merge.py revision c14ab48ae84ce77bbcc0942baaa18f8099edb447
145d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod# Copyright 2013 Google, Inc. All Rights Reserved. 245d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod# 345d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod# Google Author(s): Behdad Esfahbod 445d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 545d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod"""Font merger. 645d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod""" 745d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 845d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbodimport sys 9f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbodimport time 1045d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 1145d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbodimport fontTools 1245d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbodfrom fontTools import misc, ttLib, cffLib 13c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbodfrom fontTools.ttLib.tables import otTables 1445d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 1545d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahboddef _add_method(*clazzes): 16c855f3ab69f31004b6aaca33ac549d384f1efc54Behdad Esfahbod """Returns a decorator function that adds a new method to one or 17c855f3ab69f31004b6aaca33ac549d384f1efc54Behdad Esfahbod more classes.""" 18c855f3ab69f31004b6aaca33ac549d384f1efc54Behdad Esfahbod def wrapper(method): 19c855f3ab69f31004b6aaca33ac549d384f1efc54Behdad Esfahbod for clazz in clazzes: 20c855f3ab69f31004b6aaca33ac549d384f1efc54Behdad Esfahbod assert clazz.__name__ != 'DefaultTable', 'Oops, table class not found.' 21c855f3ab69f31004b6aaca33ac549d384f1efc54Behdad Esfahbod assert not hasattr(clazz, method.func_name), \ 22c855f3ab69f31004b6aaca33ac549d384f1efc54Behdad Esfahbod "Oops, class '%s' has method '%s'." % (clazz.__name__, 23c855f3ab69f31004b6aaca33ac549d384f1efc54Behdad Esfahbod method.func_name) 24c855f3ab69f31004b6aaca33ac549d384f1efc54Behdad Esfahbod setattr(clazz, method.func_name, method) 25c855f3ab69f31004b6aaca33ac549d384f1efc54Behdad Esfahbod return None 26c855f3ab69f31004b6aaca33ac549d384f1efc54Behdad Esfahbod return wrapper 2745d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 2845d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 29be4ecc7c67917d95b44d16b32d8d72446162f3ddBehdad Esfahbod@_add_method(ttLib.getTableClass('maxp')) 300bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahboddef merge(self, m): 3145d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod # TODO When we correctly merge hinting data, update these values: 3245d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod # maxFunctionDefs, maxInstructionDefs, maxSizeOfInstructions 3345d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod # TODO Assumes that all tables have format 1.0; safe assumption. 340bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod for key in set(sum((vars(table).keys() for table in m.tables), [])): 353235a04ea938845d656a68c242591d37148ea353Behdad Esfahbod setattr(self, key, max(getattr(table, key) for table in m.tables)) 3665f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod return True 3765f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod 38be4ecc7c67917d95b44d16b32d8d72446162f3ddBehdad Esfahbod@_add_method(ttLib.getTableClass('head')) 390bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahboddef merge(self, m): 40f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod # TODO Check that unitsPerEm are the same. 41f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod # TODO Use bitwise ops for flags, macStyle, fontDirectionHint 42f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod minMembers = ['xMin', 'yMin'] 43f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod # Negate some members 44f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod for key in minMembers: 450bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod for table in m.tables: 46f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod setattr(table, key, -getattr(table, key)) 47f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod # Get max over members 480bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod for key in set(sum((vars(table).keys() for table in m.tables), [])): 490bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod setattr(self, key, max(getattr(table, key) for table in m.tables)) 50f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod # Negate them back 51f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod for key in minMembers: 520bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod for table in m.tables: 53f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod setattr(table, key, -getattr(table, key)) 54f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod setattr(self, key, -getattr(self, key)) 55f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod return True 56f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 57be4ecc7c67917d95b44d16b32d8d72446162f3ddBehdad Esfahbod@_add_method(ttLib.getTableClass('hhea')) 580bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahboddef merge(self, m): 5965f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod # TODO Check that ascent, descent, slope, etc are the same. 6065f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod minMembers = ['descent', 'minLeftSideBearing', 'minRightSideBearing'] 6165f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod # Negate some members 6265f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod for key in minMembers: 630bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod for table in m.tables: 6465f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod setattr(table, key, -getattr(table, key)) 6565f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod # Get max over members 660bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod for key in set(sum((vars(table).keys() for table in m.tables), [])): 670bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod setattr(self, key, max(getattr(table, key) for table in m.tables)) 6865f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod # Negate them back 6965f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod for key in minMembers: 700bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod for table in m.tables: 7165f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod setattr(table, key, -getattr(table, key)) 7265f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod setattr(self, key, -getattr(self, key)) 7365f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod return True 7465f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod 75be4ecc7c67917d95b44d16b32d8d72446162f3ddBehdad Esfahbod@_add_method(ttLib.getTableClass('OS/2')) 760bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahboddef merge(self, m): 7771294def6730c37839f03dee519b319f982587eaBehdad Esfahbod # TODO Check that weight/width/subscript/superscript/etc are the same. 7871294def6730c37839f03dee519b319f982587eaBehdad Esfahbod # TODO Bitwise ops for UnicodeRange/CodePageRange. 7971294def6730c37839f03dee519b319f982587eaBehdad Esfahbod # TODO Pretty much all fields generated here have bogus values. 8071294def6730c37839f03dee519b319f982587eaBehdad Esfahbod # Get max over members 810bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod for key in set(sum((vars(table).keys() for table in m.tables), [])): 820bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod setattr(self, key, max(getattr(table, key) for table in m.tables)) 8371294def6730c37839f03dee519b319f982587eaBehdad Esfahbod return True 8471294def6730c37839f03dee519b319f982587eaBehdad Esfahbod 85be4ecc7c67917d95b44d16b32d8d72446162f3ddBehdad Esfahbod@_add_method(ttLib.getTableClass('post')) 860bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahboddef merge(self, m): 87f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod # TODO Check that italicAngle, underlinePosition, underlineThickness are the same. 88f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod minMembers = ['underlinePosition', 'minMemType42', 'minMemType1'] 89f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod # Negate some members 90f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod for key in minMembers: 910bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod for table in m.tables: 92f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod setattr(table, key, -getattr(table, key)) 93f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod # Get max over members 940bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod keys = set(sum((vars(table).keys() for table in m.tables), [])) 95f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if 'mapping' in keys: 96f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod keys.remove('mapping') 97f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod keys.remove('extraNames') 98f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod for key in keys: 990bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod setattr(self, key, max(getattr(table, key) for table in m.tables)) 100f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod # Negate them back 101f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod for key in minMembers: 1020bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod for table in m.tables: 103f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod setattr(table, key, -getattr(table, key)) 104f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod setattr(self, key, -getattr(self, key)) 105f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod self.mapping = {} 1060bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod for table in m.tables: 107f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if hasattr(table, 'mapping'): 108f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod self.mapping.update(table.mapping) 109f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod self.extraNames = [] 110f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod return True 111f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 112be4ecc7c67917d95b44d16b32d8d72446162f3ddBehdad Esfahbod@_add_method(ttLib.getTableClass('vmtx'), 113be4ecc7c67917d95b44d16b32d8d72446162f3ddBehdad Esfahbod ttLib.getTableClass('hmtx')) 1140bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahboddef merge(self, m): 11565f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod self.metrics = {} 1160bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod for table in m.tables: 11765f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod self.metrics.update(table.metrics) 11865f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod return True 11965f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod 120be4ecc7c67917d95b44d16b32d8d72446162f3ddBehdad Esfahbod@_add_method(ttLib.getTableClass('loca')) 1210bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahboddef merge(self, m): 122f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod return True # Will be computed automatically 123f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 124be4ecc7c67917d95b44d16b32d8d72446162f3ddBehdad Esfahbod@_add_method(ttLib.getTableClass('glyf')) 1250bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahboddef merge(self, m): 126f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod self.glyphs = {} 1270bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod for table in m.tables: 128f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod self.glyphs.update(table.glyphs) 129f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod # TODO Drop hints? 130f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod return True 131f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 132be4ecc7c67917d95b44d16b32d8d72446162f3ddBehdad Esfahbod@_add_method(ttLib.getTableClass('prep'), 133be4ecc7c67917d95b44d16b32d8d72446162f3ddBehdad Esfahbod ttLib.getTableClass('fpgm'), 134be4ecc7c67917d95b44d16b32d8d72446162f3ddBehdad Esfahbod ttLib.getTableClass('cvt ')) 1350bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahboddef merge(self, m): 13665f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod return False # Will be computed automatically 13745d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 138be4ecc7c67917d95b44d16b32d8d72446162f3ddBehdad Esfahbod@_add_method(ttLib.getTableClass('cmap')) 1390bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahboddef merge(self, m): 14071294def6730c37839f03dee519b319f982587eaBehdad Esfahbod # TODO Handle format=14. 1410bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod cmapTables = [t for table in m.tables for t in table.tables 14271294def6730c37839f03dee519b319f982587eaBehdad Esfahbod if t.platformID == 3 and t.platEncID in [1, 10]] 14371294def6730c37839f03dee519b319f982587eaBehdad Esfahbod # TODO Better handle format-4 and format-12 coexisting in same font. 14471294def6730c37839f03dee519b319f982587eaBehdad Esfahbod # TODO Insert both a format-4 and format-12 if needed. 145be4ecc7c67917d95b44d16b32d8d72446162f3ddBehdad Esfahbod module = ttLib.getTableModule('cmap') 14671294def6730c37839f03dee519b319f982587eaBehdad Esfahbod assert all(t.format in [4, 12] for t in cmapTables) 14771294def6730c37839f03dee519b319f982587eaBehdad Esfahbod format = max(t.format for t in cmapTables) 14871294def6730c37839f03dee519b319f982587eaBehdad Esfahbod cmapTable = module.cmap_classes[format](format) 14971294def6730c37839f03dee519b319f982587eaBehdad Esfahbod cmapTable.cmap = {} 15071294def6730c37839f03dee519b319f982587eaBehdad Esfahbod cmapTable.platformID = 3 15171294def6730c37839f03dee519b319f982587eaBehdad Esfahbod cmapTable.platEncID = max(t.platEncID for t in cmapTables) 15271294def6730c37839f03dee519b319f982587eaBehdad Esfahbod cmapTable.language = 0 15371294def6730c37839f03dee519b319f982587eaBehdad Esfahbod for table in cmapTables: 15471294def6730c37839f03dee519b319f982587eaBehdad Esfahbod # TODO handle duplicates. 15571294def6730c37839f03dee519b319f982587eaBehdad Esfahbod cmapTable.cmap.update(table.cmap) 15671294def6730c37839f03dee519b319f982587eaBehdad Esfahbod self.tableVersion = 0 15771294def6730c37839f03dee519b319f982587eaBehdad Esfahbod self.tables = [cmapTable] 15871294def6730c37839f03dee519b319f982587eaBehdad Esfahbod self.numSubTables = len(self.tables) 15971294def6730c37839f03dee519b319f982587eaBehdad Esfahbod return True 16071294def6730c37839f03dee519b319f982587eaBehdad Esfahbod 161c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod@_add_method(ttLib.getTableClass('GDEF')) 162c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahboddef merge(self, m): 163c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod self.table = otTables.GDEF() 164c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod self.table.Version = 1.0 165c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod 166c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod if any(t.table.LigCaretList for t in m.tables): 167c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod glyphs = [] 168c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod ligGlyphs = [] 169c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod for table in m.tables: 170c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod if table.table.LigCaretList: 171c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod glyphs.extend(table.table.LigCaretList.Coverage.glyphs) 172c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod ligGlyphs.extend(table.table.LigCaretList.LigGlyph) 173c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod coverage = otTables.Coverage() 174c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod coverage.glyphs = glyphs 175c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod ligCaretList = otTables.LigCaretList() 176c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod ligCaretList.Coverage = coverage 177c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod ligCaretList.LigGlyph = ligGlyphs 178c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod ligCaretList.GlyphCount = len(ligGlyphs) 179c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod self.table.LigCaretList = ligCaretList 180c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod else: 181c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod self.table.LigCaretList = None 182c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod 183c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod if any(t.table.MarkAttachClassDef for t in m.tables): 184c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod classDefs = {} 185c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod for table in m.tables: 186c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod if table.table.MarkAttachClassDef: 187c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod classDefs.update(table.table.MarkAttachClassDef.classDefs) 188c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod self.table.MarkAttachClassDef = otTables.MarkAttachClassDef() 189c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod self.table.MarkAttachClassDef.classDefs = classDefs 190c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod else: 191c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod self.table.MarkAttachClassDef = None 192c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod 193c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod if any(t.table.GlyphClassDef for t in m.tables): 194c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod classDefs = {} 195c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod for table in m.tables: 196c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod if table.table.GlyphClassDef: 197c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod classDefs.update(table.table.GlyphClassDef.classDefs) 198c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod self.table.GlyphClassDef = otTables.GlyphClassDef() 199c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod self.table.GlyphClassDef.classDefs = classDefs 200c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod else: 201c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod self.table.GlyphClassDef = None 202c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod 203c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod if any(t.table.AttachList for t in m.tables): 204c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod glyphs = [] 205c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod attachPoints = [] 206c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod for table in m.tables: 207c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod if table.table.AttachList: 208c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod glyphs.extend(table.table.AttachList.Coverage.glyphs) 209c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod attachPoints.extend(table.table.AttachList.AttachPoint) 210c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod coverage = otTables.Coverage() 211c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod coverage.glyphs = glyphs 212c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod attachList = otTables.AttachList() 213c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod attachList.Coverage = coverage 214c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod attachList.AttachPoint = attachPoints 215c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod attachList.GlyphCount = len(attachPoints) 216c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod self.table.AttachList = attachList 217c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod else: 218c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod self.table.AttachList = None 219c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod 220c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod return True 221c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod 222f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 223f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbodclass Options(object): 224f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 225f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod class UnknownOptionError(Exception): 226f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod pass 227f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 228f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod _drop_tables_default = ['fpgm', 'prep', 'cvt ', 'gasp'] 229f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod drop_tables = _drop_tables_default 230f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 231f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod def __init__(self, **kwargs): 232f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 233f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod self.set(**kwargs) 234f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 235f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod def set(self, **kwargs): 236f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod for k,v in kwargs.iteritems(): 237f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if not hasattr(self, k): 238f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod raise self.UnknownOptionError("Unknown option '%s'" % k) 239f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod setattr(self, k, v) 240f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 241f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod def parse_opts(self, argv, ignore_unknown=False): 242f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod ret = [] 243f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod opts = {} 244f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod for a in argv: 245f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod orig_a = a 246f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if not a.startswith('--'): 247f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod ret.append(a) 248f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod continue 249f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod a = a[2:] 250f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod i = a.find('=') 251f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod op = '=' 252f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if i == -1: 253f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if a.startswith("no-"): 254f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod k = a[3:] 255f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod v = False 256f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod else: 257f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod k = a 258f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod v = True 259f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod else: 260f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod k = a[:i] 261f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if k[-1] in "-+": 262f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod op = k[-1]+'=' # Ops is '-=' or '+=' now. 263f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod k = k[:-1] 264f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod v = a[i+1:] 265f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod k = k.replace('-', '_') 266f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if not hasattr(self, k): 267f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if ignore_unknown == True or k in ignore_unknown: 268f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod ret.append(orig_a) 269f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod continue 270f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod else: 271f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod raise self.UnknownOptionError("Unknown option '%s'" % a) 272f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 273f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod ov = getattr(self, k) 274f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if isinstance(ov, bool): 275f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod v = bool(v) 276f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod elif isinstance(ov, int): 277f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod v = int(v) 278f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod elif isinstance(ov, list): 279f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod vv = v.split(',') 280f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if vv == ['']: 281f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod vv = [] 282f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod vv = [int(x, 0) if len(x) and x[0] in "0123456789" else x for x in vv] 283f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if op == '=': 284f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod v = vv 285f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod elif op == '+=': 286f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod v = ov 287f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod v.extend(vv) 288f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod elif op == '-=': 289f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod v = ov 290f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod for x in vv: 291f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if x in v: 292f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod v.remove(x) 293f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod else: 294f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod assert 0 295f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 296f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod opts[k] = v 297f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod self.set(**opts) 298f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 299f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod return ret 300f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 301f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 30245d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbodclass Merger: 30345d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 304f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod def __init__(self, options=None, log=None): 305f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 306f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if not log: 307f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod log = Logger() 308f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if not options: 309f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod options = Options() 310f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 311f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod self.options = options 312f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod self.log = log 31345d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 314f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod def merge(self, fontfiles): 31545d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 31645d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod mega = ttLib.TTFont() 31745d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 31845d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod # 31945d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod # Settle on a mega glyph order. 32045d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod # 321f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod fonts = [ttLib.TTFont(fontfile) for fontfile in fontfiles] 32245d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod glyphOrders = [font.getGlyphOrder() for font in fonts] 32345d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod megaGlyphOrder = self._mergeGlyphOrders(glyphOrders) 32445d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod # Reload fonts and set new glyph names on them. 32545d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod # TODO Is it necessary to reload font? I think it is. At least 32645d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod # it's safer, in case tables were loaded to provide glyph names. 327f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod fonts = [ttLib.TTFont(fontfile) for fontfile in fontfiles] 3283235a04ea938845d656a68c242591d37148ea353Behdad Esfahbod for font,glyphOrder in zip(fonts, glyphOrders): 3293235a04ea938845d656a68c242591d37148ea353Behdad Esfahbod font.setGlyphOrder(glyphOrder) 33045d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod mega.setGlyphOrder(megaGlyphOrder) 33145d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 332c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod allTags = reduce(set.union, (font.keys() for font in fonts), set()) 33345d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod allTags.remove('GlyphOrder') 33445d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod for tag in allTags: 335f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 336f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if tag in self.options.drop_tables: 337b640f7435c3d29c57310b1a5f7d8e5b538a4c1e3Behdad Esfahbod self.log("Dropping '%s'." % tag) 338f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod continue 339f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 34045d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod clazz = ttLib.getTableClass(tag) 34145d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 34245d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod if not hasattr(clazz, 'merge'): 343b640f7435c3d29c57310b1a5f7d8e5b538a4c1e3Behdad Esfahbod self.log("Don't know how to merge '%s', dropped." % tag) 34445d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod continue 34545d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 34645d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod # TODO For now assume all fonts have the same tables. 3470bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod self.tables = [font[tag] for font in fonts] 34845d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod table = clazz(tag) 3490bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod if table.merge (self): 35065f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod mega[tag] = table 351b640f7435c3d29c57310b1a5f7d8e5b538a4c1e3Behdad Esfahbod self.log("Merged '%s'." % tag) 35265f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod else: 353b640f7435c3d29c57310b1a5f7d8e5b538a4c1e3Behdad Esfahbod self.log("Dropped '%s'. No need to merge explicitly." % tag) 354b640f7435c3d29c57310b1a5f7d8e5b538a4c1e3Behdad Esfahbod self.log.lapse("merge '%s'" % tag) 3550bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod del self.tables 35645d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 35745d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod return mega 35845d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 35945d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod def _mergeGlyphOrders(self, glyphOrders): 36045d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod """Modifies passed-in glyphOrders to reflect new glyph names.""" 36145d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod # Simply append font index to the glyph name for now. 36245d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod mega = [] 36345d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod for n,glyphOrder in enumerate(glyphOrders): 36445d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod for i,glyphName in enumerate(glyphOrder): 36545d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod glyphName += "#" + `n` 36645d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod glyphOrder[i] = glyphName 36745d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod mega.append(glyphName) 36845d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod return mega 36945d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 370f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 371f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbodclass Logger(object): 372f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 373f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod def __init__(self, verbose=False, xml=False, timing=False): 374f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod self.verbose = verbose 375f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod self.xml = xml 376f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod self.timing = timing 377f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod self.last_time = self.start_time = time.time() 378f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 379f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod def parse_opts(self, argv): 380f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod argv = argv[:] 381f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod for v in ['verbose', 'xml', 'timing']: 382f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if "--"+v in argv: 383f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod setattr(self, v, True) 384f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod argv.remove("--"+v) 385f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod return argv 386f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 387f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod def __call__(self, *things): 388f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if not self.verbose: 389f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod return 390f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod print ' '.join(str(x) for x in things) 391f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 392f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod def lapse(self, *things): 393f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if not self.timing: 394f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod return 395f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod new_time = time.time() 396f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod print "Took %0.3fs to %s" %(new_time - self.last_time, 397f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod ' '.join(str(x) for x in things)) 398f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod self.last_time = new_time 399f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 400f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod def font(self, font, file=sys.stdout): 401f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if not self.xml: 402f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod return 403f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod from fontTools.misc import xmlWriter 404f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod writer = xmlWriter.XMLWriter(file) 405f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod font.disassembleInstructions = False # Work around ttLib bug 406f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod for tag in font.keys(): 407f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod writer.begintag(tag) 408f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod writer.newline() 409f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod font[tag].toXML(writer, font) 410f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod writer.endtag(tag) 411f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod writer.newline() 412f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 413f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 414f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod__all__ = [ 415f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 'Options', 416f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 'Merger', 417f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 'Logger', 418f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 'main' 419f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod] 420f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 42145d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahboddef main(args): 422f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 423f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod log = Logger() 424f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod args = log.parse_opts(args) 425f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 426f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod options = Options() 427f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod args = options.parse_opts(args) 428f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 42945d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod if len(args) < 1: 43045d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod print >>sys.stderr, "usage: pyftmerge font..." 43145d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod sys.exit(1) 432f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 433f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod merger = Merger(options=options, log=log) 434f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod font = merger.merge(args) 43545d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod outfile = 'merged.ttf' 43645d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod font.save(outfile) 437b640f7435c3d29c57310b1a5f7d8e5b538a4c1e3Behdad Esfahbod log.lapse("compile and save font") 438b640f7435c3d29c57310b1a5f7d8e5b538a4c1e3Behdad Esfahbod 439b640f7435c3d29c57310b1a5f7d8e5b538a4c1e3Behdad Esfahbod log.last_time = log.start_time 440b640f7435c3d29c57310b1a5f7d8e5b538a4c1e3Behdad Esfahbod log.lapse("make one with everything(TOTAL TIME)") 44145d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 44245d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbodif __name__ == "__main__": 44345d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod main(sys.argv[1:]) 444