merge.py revision c2e27fd88f54fcc081049dabce59889cdc87450e
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) 129c2e27fd88f54fcc081049dabce59889cdc87450eBehdad Esfahbod # Drop hints for now, since we don't remap functions / CVT values. 130c2e27fd88f54fcc081049dabce59889cdc87450eBehdad Esfahbod for g in self.glyphs.values(): 131c2e27fd88f54fcc081049dabce59889cdc87450eBehdad Esfahbod g.removeHinting() 132f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod return True 133f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 134be4ecc7c67917d95b44d16b32d8d72446162f3ddBehdad Esfahbod@_add_method(ttLib.getTableClass('prep'), 135be4ecc7c67917d95b44d16b32d8d72446162f3ddBehdad Esfahbod ttLib.getTableClass('fpgm'), 136be4ecc7c67917d95b44d16b32d8d72446162f3ddBehdad Esfahbod ttLib.getTableClass('cvt ')) 1370bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahboddef merge(self, m): 13865f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod return False # Will be computed automatically 13945d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 140be4ecc7c67917d95b44d16b32d8d72446162f3ddBehdad Esfahbod@_add_method(ttLib.getTableClass('cmap')) 1410bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahboddef merge(self, m): 14271294def6730c37839f03dee519b319f982587eaBehdad Esfahbod # TODO Handle format=14. 1430bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod cmapTables = [t for table in m.tables for t in table.tables 14471294def6730c37839f03dee519b319f982587eaBehdad Esfahbod if t.platformID == 3 and t.platEncID in [1, 10]] 14571294def6730c37839f03dee519b319f982587eaBehdad Esfahbod # TODO Better handle format-4 and format-12 coexisting in same font. 14671294def6730c37839f03dee519b319f982587eaBehdad Esfahbod # TODO Insert both a format-4 and format-12 if needed. 147be4ecc7c67917d95b44d16b32d8d72446162f3ddBehdad Esfahbod module = ttLib.getTableModule('cmap') 14871294def6730c37839f03dee519b319f982587eaBehdad Esfahbod assert all(t.format in [4, 12] for t in cmapTables) 14971294def6730c37839f03dee519b319f982587eaBehdad Esfahbod format = max(t.format for t in cmapTables) 15071294def6730c37839f03dee519b319f982587eaBehdad Esfahbod cmapTable = module.cmap_classes[format](format) 15171294def6730c37839f03dee519b319f982587eaBehdad Esfahbod cmapTable.cmap = {} 15271294def6730c37839f03dee519b319f982587eaBehdad Esfahbod cmapTable.platformID = 3 15371294def6730c37839f03dee519b319f982587eaBehdad Esfahbod cmapTable.platEncID = max(t.platEncID for t in cmapTables) 15471294def6730c37839f03dee519b319f982587eaBehdad Esfahbod cmapTable.language = 0 15571294def6730c37839f03dee519b319f982587eaBehdad Esfahbod for table in cmapTables: 15671294def6730c37839f03dee519b319f982587eaBehdad Esfahbod # TODO handle duplicates. 15771294def6730c37839f03dee519b319f982587eaBehdad Esfahbod cmapTable.cmap.update(table.cmap) 15871294def6730c37839f03dee519b319f982587eaBehdad Esfahbod self.tableVersion = 0 15971294def6730c37839f03dee519b319f982587eaBehdad Esfahbod self.tables = [cmapTable] 16071294def6730c37839f03dee519b319f982587eaBehdad Esfahbod self.numSubTables = len(self.tables) 16171294def6730c37839f03dee519b319f982587eaBehdad Esfahbod return True 16271294def6730c37839f03dee519b319f982587eaBehdad Esfahbod 163c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod@_add_method(ttLib.getTableClass('GDEF')) 164c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahboddef merge(self, m): 165c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod self.table = otTables.GDEF() 166c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod self.table.Version = 1.0 167c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod 168c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod if any(t.table.LigCaretList for t in m.tables): 169c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod glyphs = [] 170c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod ligGlyphs = [] 171c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod for table in m.tables: 172c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod if table.table.LigCaretList: 173c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod glyphs.extend(table.table.LigCaretList.Coverage.glyphs) 174c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod ligGlyphs.extend(table.table.LigCaretList.LigGlyph) 175c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod coverage = otTables.Coverage() 176c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod coverage.glyphs = glyphs 177c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod ligCaretList = otTables.LigCaretList() 178c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod ligCaretList.Coverage = coverage 179c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod ligCaretList.LigGlyph = ligGlyphs 180c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod ligCaretList.GlyphCount = len(ligGlyphs) 181c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod self.table.LigCaretList = ligCaretList 182c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod else: 183c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod self.table.LigCaretList = None 184c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod 185c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod if any(t.table.MarkAttachClassDef for t in m.tables): 186c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod classDefs = {} 187c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod for table in m.tables: 188c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod if table.table.MarkAttachClassDef: 189c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod classDefs.update(table.table.MarkAttachClassDef.classDefs) 190c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod self.table.MarkAttachClassDef = otTables.MarkAttachClassDef() 191c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod self.table.MarkAttachClassDef.classDefs = classDefs 192c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod else: 193c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod self.table.MarkAttachClassDef = None 194c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod 195c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod if any(t.table.GlyphClassDef for t in m.tables): 196c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod classDefs = {} 197c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod for table in m.tables: 198c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod if table.table.GlyphClassDef: 199c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod classDefs.update(table.table.GlyphClassDef.classDefs) 200c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod self.table.GlyphClassDef = otTables.GlyphClassDef() 201c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod self.table.GlyphClassDef.classDefs = classDefs 202c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod else: 203c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod self.table.GlyphClassDef = None 204c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod 205c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod if any(t.table.AttachList for t in m.tables): 206c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod glyphs = [] 207c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod attachPoints = [] 208c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod for table in m.tables: 209c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod if table.table.AttachList: 210c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod glyphs.extend(table.table.AttachList.Coverage.glyphs) 211c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod attachPoints.extend(table.table.AttachList.AttachPoint) 212c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod coverage = otTables.Coverage() 213c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod coverage.glyphs = glyphs 214c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod attachList = otTables.AttachList() 215c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod attachList.Coverage = coverage 216c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod attachList.AttachPoint = attachPoints 217c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod attachList.GlyphCount = len(attachPoints) 218c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod self.table.AttachList = attachList 219c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod else: 220c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod self.table.AttachList = None 221c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod 222c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod return True 223c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod 224f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 225f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbodclass Options(object): 226f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 227f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod class UnknownOptionError(Exception): 228f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod pass 229f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 230f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod _drop_tables_default = ['fpgm', 'prep', 'cvt ', 'gasp'] 231f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod drop_tables = _drop_tables_default 232f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 233f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod def __init__(self, **kwargs): 234f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 235f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod self.set(**kwargs) 236f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 237f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod def set(self, **kwargs): 238f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod for k,v in kwargs.iteritems(): 239f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if not hasattr(self, k): 240f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod raise self.UnknownOptionError("Unknown option '%s'" % k) 241f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod setattr(self, k, v) 242f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 243f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod def parse_opts(self, argv, ignore_unknown=False): 244f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod ret = [] 245f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod opts = {} 246f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod for a in argv: 247f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod orig_a = a 248f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if not a.startswith('--'): 249f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod ret.append(a) 250f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod continue 251f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod a = a[2:] 252f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod i = a.find('=') 253f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod op = '=' 254f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if i == -1: 255f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if a.startswith("no-"): 256f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod k = a[3:] 257f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod v = False 258f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod else: 259f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod k = a 260f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod v = True 261f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod else: 262f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod k = a[:i] 263f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if k[-1] in "-+": 264f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod op = k[-1]+'=' # Ops is '-=' or '+=' now. 265f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod k = k[:-1] 266f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod v = a[i+1:] 267f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod k = k.replace('-', '_') 268f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if not hasattr(self, k): 269f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if ignore_unknown == True or k in ignore_unknown: 270f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod ret.append(orig_a) 271f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod continue 272f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod else: 273f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod raise self.UnknownOptionError("Unknown option '%s'" % a) 274f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 275f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod ov = getattr(self, k) 276f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if isinstance(ov, bool): 277f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod v = bool(v) 278f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod elif isinstance(ov, int): 279f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod v = int(v) 280f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod elif isinstance(ov, list): 281f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod vv = v.split(',') 282f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if vv == ['']: 283f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod vv = [] 284f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod vv = [int(x, 0) if len(x) and x[0] in "0123456789" else x for x in vv] 285f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if op == '=': 286f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod v = vv 287f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod elif op == '+=': 288f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod v = ov 289f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod v.extend(vv) 290f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod elif op == '-=': 291f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod v = ov 292f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod for x in vv: 293f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if x in v: 294f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod v.remove(x) 295f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod else: 296f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod assert 0 297f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 298f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod opts[k] = v 299f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod self.set(**opts) 300f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 301f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod return ret 302f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 303f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 30445d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbodclass Merger: 30545d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 306f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod def __init__(self, options=None, log=None): 307f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 308f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if not log: 309f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod log = Logger() 310f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if not options: 311f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod options = Options() 312f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 313f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod self.options = options 314f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod self.log = log 31545d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 316f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod def merge(self, fontfiles): 31745d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 31845d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod mega = ttLib.TTFont() 31945d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 32045d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod # 32145d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod # Settle on a mega glyph order. 32245d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod # 323f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod fonts = [ttLib.TTFont(fontfile) for fontfile in fontfiles] 32445d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod glyphOrders = [font.getGlyphOrder() for font in fonts] 32545d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod megaGlyphOrder = self._mergeGlyphOrders(glyphOrders) 32645d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod # Reload fonts and set new glyph names on them. 32745d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod # TODO Is it necessary to reload font? I think it is. At least 32845d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod # it's safer, in case tables were loaded to provide glyph names. 329f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod fonts = [ttLib.TTFont(fontfile) for fontfile in fontfiles] 3303235a04ea938845d656a68c242591d37148ea353Behdad Esfahbod for font,glyphOrder in zip(fonts, glyphOrders): 3313235a04ea938845d656a68c242591d37148ea353Behdad Esfahbod font.setGlyphOrder(glyphOrder) 33245d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod mega.setGlyphOrder(megaGlyphOrder) 33345d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 334c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod allTags = reduce(set.union, (font.keys() for font in fonts), set()) 33545d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod allTags.remove('GlyphOrder') 33645d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod for tag in allTags: 337f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 338f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if tag in self.options.drop_tables: 339b640f7435c3d29c57310b1a5f7d8e5b538a4c1e3Behdad Esfahbod self.log("Dropping '%s'." % tag) 340f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod continue 341f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 34245d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod clazz = ttLib.getTableClass(tag) 34345d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 34445d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod if not hasattr(clazz, 'merge'): 345b640f7435c3d29c57310b1a5f7d8e5b538a4c1e3Behdad Esfahbod self.log("Don't know how to merge '%s', dropped." % tag) 34645d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod continue 34745d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 34845d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod # TODO For now assume all fonts have the same tables. 3490bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod self.tables = [font[tag] for font in fonts] 35045d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod table = clazz(tag) 3510bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod if table.merge (self): 35265f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod mega[tag] = table 353b640f7435c3d29c57310b1a5f7d8e5b538a4c1e3Behdad Esfahbod self.log("Merged '%s'." % tag) 35465f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod else: 355b640f7435c3d29c57310b1a5f7d8e5b538a4c1e3Behdad Esfahbod self.log("Dropped '%s'. No need to merge explicitly." % tag) 356b640f7435c3d29c57310b1a5f7d8e5b538a4c1e3Behdad Esfahbod self.log.lapse("merge '%s'" % tag) 3570bf4f561da7972ab90f6bee87fa30923e201adf5Behdad Esfahbod del self.tables 35845d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 35945d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod return mega 36045d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 36145d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod def _mergeGlyphOrders(self, glyphOrders): 362c2e27fd88f54fcc081049dabce59889cdc87450eBehdad Esfahbod """Modifies passed-in glyphOrders to reflect new glyph names. 363c2e27fd88f54fcc081049dabce59889cdc87450eBehdad Esfahbod Returns glyphOrder for the merged font.""" 36445d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod # Simply append font index to the glyph name for now. 365c2e27fd88f54fcc081049dabce59889cdc87450eBehdad Esfahbod # TODO Even this simplistic numbering can result in conflicts. 366c2e27fd88f54fcc081049dabce59889cdc87450eBehdad Esfahbod # But then again, we have to improve this soon anyway. 36745d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod mega = [] 36845d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod for n,glyphOrder in enumerate(glyphOrders): 36945d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod for i,glyphName in enumerate(glyphOrder): 37045d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod glyphName += "#" + `n` 37145d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod glyphOrder[i] = glyphName 37245d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod mega.append(glyphName) 37345d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod return mega 37445d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 375f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 376f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbodclass Logger(object): 377f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 378f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod def __init__(self, verbose=False, xml=False, timing=False): 379f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod self.verbose = verbose 380f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod self.xml = xml 381f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod self.timing = timing 382f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod self.last_time = self.start_time = time.time() 383f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 384f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod def parse_opts(self, argv): 385f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod argv = argv[:] 386f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod for v in ['verbose', 'xml', 'timing']: 387f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if "--"+v in argv: 388f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod setattr(self, v, True) 389f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod argv.remove("--"+v) 390f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod return argv 391f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 392f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod def __call__(self, *things): 393f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if not self.verbose: 394f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod return 395f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod print ' '.join(str(x) for x in things) 396f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 397f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod def lapse(self, *things): 398f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if not self.timing: 399f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod return 400f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod new_time = time.time() 401f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod print "Took %0.3fs to %s" %(new_time - self.last_time, 402f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod ' '.join(str(x) for x in things)) 403f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod self.last_time = new_time 404f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 405f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod def font(self, font, file=sys.stdout): 406f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod if not self.xml: 407f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod return 408f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod from fontTools.misc import xmlWriter 409f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod writer = xmlWriter.XMLWriter(file) 410f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod font.disassembleInstructions = False # Work around ttLib bug 411f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod for tag in font.keys(): 412f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod writer.begintag(tag) 413f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod writer.newline() 414f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod font[tag].toXML(writer, font) 415f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod writer.endtag(tag) 416f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod writer.newline() 417f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 418f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 419f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod__all__ = [ 420f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 'Options', 421f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 'Merger', 422f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 'Logger', 423f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 'main' 424f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod] 425f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 42645d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahboddef main(args): 427f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 428f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod log = Logger() 429f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod args = log.parse_opts(args) 430f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 431f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod options = Options() 432f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod args = options.parse_opts(args) 433f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 43445d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod if len(args) < 1: 43545d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod print >>sys.stderr, "usage: pyftmerge font..." 43645d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod sys.exit(1) 437f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod 438f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod merger = Merger(options=options, log=log) 439f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod font = merger.merge(args) 44045d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod outfile = 'merged.ttf' 44145d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod font.save(outfile) 442b640f7435c3d29c57310b1a5f7d8e5b538a4c1e3Behdad Esfahbod log.lapse("compile and save font") 443b640f7435c3d29c57310b1a5f7d8e5b538a4c1e3Behdad Esfahbod 444b640f7435c3d29c57310b1a5f7d8e5b538a4c1e3Behdad Esfahbod log.last_time = log.start_time 445b640f7435c3d29c57310b1a5f7d8e5b538a4c1e3Behdad Esfahbod log.lapse("make one with everything(TOTAL TIME)") 44645d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod 44745d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbodif __name__ == "__main__": 44845d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod main(sys.argv[1:]) 449