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