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