merge.py revision 2642934116cc0e3b873e37051cb57d3b29c0a9b4
145d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod# Copyright 2013 Google, Inc. All Rights Reserved.
245d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod#
347bee9cfbd47dc22895003cc94ab91f9075ca27fRoozbeh Pournader# Google Author(s): Behdad Esfahbod, Roozbeh Pournader
445d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod
545d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod"""Font merger.
645d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod"""
745d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod
8f63e80e3fc4ef5406109f1fbe2746e26927fdebfBehdad Esfahbodfrom __future__ import print_function, division
9f63e80e3fc4ef5406109f1fbe2746e26927fdebfBehdad Esfahbodfrom fontTools.misc.py23 import *
10f63e80e3fc4ef5406109f1fbe2746e26927fdebfBehdad Esfahbodfrom fontTools import ttLib, cffLib
11e219c6c76f116a38e0187b4388d99dd59eff30bcRoozbeh Pournaderfrom fontTools.ttLib.tables import otTables, _h_e_a_d
129e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbodfrom fontTools.ttLib.tables.DefaultTable import DefaultTable
13f63e80e3fc4ef5406109f1fbe2746e26927fdebfBehdad Esfahbodfrom functools import reduce
1445d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbodimport sys
15f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbodimport time
1649028b3ba7196b0389ac964f3a2db163367d24b8Behdad Esfahbodimport operator
1745d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod
1845d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod
199e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahboddef _add_method(*clazzes, **kwargs):
20c855f3ab69f31004b6aaca33ac549d384f1efc54Behdad Esfahbod	"""Returns a decorator function that adds a new method to one or
21c855f3ab69f31004b6aaca33ac549d384f1efc54Behdad Esfahbod	more classes."""
22c855f3ab69f31004b6aaca33ac549d384f1efc54Behdad Esfahbod	def wrapper(method):
23c855f3ab69f31004b6aaca33ac549d384f1efc54Behdad Esfahbod		for clazz in clazzes:
249e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod			if not kwargs.get('allowDefaultTable', False):
259e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod				assert clazz != DefaultTable, 'Oops, table class not found.'
269e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod			assert method.__name__ not in clazz.__dict__, \
27c855f3ab69f31004b6aaca33ac549d384f1efc54Behdad Esfahbod				"Oops, class '%s' has method '%s'." % (clazz.__name__,
28f63e80e3fc4ef5406109f1fbe2746e26927fdebfBehdad Esfahbod								       method.__name__)
299e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod			setattr(clazz, method.__name__, method)
30c855f3ab69f31004b6aaca33ac549d384f1efc54Behdad Esfahbod		return None
31c855f3ab69f31004b6aaca33ac549d384f1efc54Behdad Esfahbod	return wrapper
3245d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod
3347bee9cfbd47dc22895003cc94ab91f9075ca27fRoozbeh Pournader# General utility functions for merging values from different fonts
3492fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod
3549028b3ba7196b0389ac964f3a2db163367d24b8Behdad Esfahboddef equal(lst):
3649028b3ba7196b0389ac964f3a2db163367d24b8Behdad Esfahbod	t = iter(lst)
3749028b3ba7196b0389ac964f3a2db163367d24b8Behdad Esfahbod	first = next(t)
3849028b3ba7196b0389ac964f3a2db163367d24b8Behdad Esfahbod	assert all(item == first for item in t)
39e219c6c76f116a38e0187b4388d99dd59eff30bcRoozbeh Pournader	return first
4047bee9cfbd47dc22895003cc94ab91f9075ca27fRoozbeh Pournader
4147bee9cfbd47dc22895003cc94ab91f9075ca27fRoozbeh Pournaderdef first(lst):
4249028b3ba7196b0389ac964f3a2db163367d24b8Behdad Esfahbod	return next(iter(lst))
4347bee9cfbd47dc22895003cc94ab91f9075ca27fRoozbeh Pournader
44e219c6c76f116a38e0187b4388d99dd59eff30bcRoozbeh Pournaderdef recalculate(lst):
4592fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod	return NotImplemented
46e219c6c76f116a38e0187b4388d99dd59eff30bcRoozbeh Pournader
47e219c6c76f116a38e0187b4388d99dd59eff30bcRoozbeh Pournaderdef current_time(lst):
4849028b3ba7196b0389ac964f3a2db163367d24b8Behdad Esfahbod	return int(time.time() - _h_e_a_d.mac_epoch_diff)
49e219c6c76f116a38e0187b4388d99dd59eff30bcRoozbeh Pournader
50e219c6c76f116a38e0187b4388d99dd59eff30bcRoozbeh Pournaderdef bitwise_or(lst):
5149028b3ba7196b0389ac964f3a2db163367d24b8Behdad Esfahbod	return reduce(operator.or_, lst)
52e219c6c76f116a38e0187b4388d99dd59eff30bcRoozbeh Pournader
5392fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahboddef avg_int(lst):
5492fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod	lst = list(lst)
5592fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod	return sum(lst) // len(lst)
5645d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod
5792fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahboddef nonnone(func):
589e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	"""Returns a filter func that when called with a list,
599e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	only calls func on the non-None items of the list, and
609e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	only so if there's at least one non-None item in the
6192fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod	list.  Otherwise returns None."""
6265f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod
639e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	def wrapper(lst):
649e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod		items = [item for item in lst if item is not None]
659e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod		return func(items) if items else None
669e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod
679e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	return wrapper
689e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod
6992fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahboddef implemented(func):
7092fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod	"""Returns a filter func that when called with a list,
7192fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod	only calls func on the non-NotImplemented items of the list,
7292fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod	and only so if there's at least one item remaining.
7392fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod	Otherwise returns NotImplemented."""
7492fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod
7592fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod	def wrapper(lst):
7692fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod		items = [item for item in lst if item is not NotImplemented]
7792fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod		return func(items) if items else NotImplemented
7892fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod
7992fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod	return wrapper
8092fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod
819e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahboddef sumLists(lst):
829e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	l = []
839e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	for item in lst:
849e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod		l.extend(item)
859e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	return l
869e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod
879e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahboddef sumDicts(lst):
889e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	d = {}
899e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	for item in lst:
909e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod		d.update(item)
919e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	return d
92f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
9312dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahboddef mergeObjects(lst):
9412dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod	lst = [item for item in lst if item is not None and item is not NotImplemented]
9512dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod	if not lst:
9612dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod		return None # Not all can be NotImplemented
9712dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod
9812dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod	clazz = lst[0].__class__
9912dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod	assert all(type(item) == clazz for item in lst), lst
10012dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod	logic = clazz.mergeMap
10112dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod	returnTable = clazz()
10212dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod
10312dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod	allKeys = set.union(set(), *(vars(table).keys() for table in lst))
10412dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod	for key in allKeys:
10512dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod		try:
10612dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod			mergeLogic = logic[key]
10712dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod		except KeyError:
10812dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod			try:
10912dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod				mergeLogic = logic['*']
11012dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod			except KeyError:
11112dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod				raise Exception("Don't know how to merge key %s of class %s" %
11212dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod						(key, clazz.__name__))
11312dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod		if mergeLogic is NotImplemented:
11412dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod			continue
11512dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod		value = mergeLogic(getattr(table, key, NotImplemented) for table in lst)
11612dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod		if value is not NotImplemented:
11712dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod			setattr(returnTable, key, value)
11812dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod
11912dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod	return returnTable
12012dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod
12165f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod
1229e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod@_add_method(DefaultTable, allowDefaultTable=True)
1233b36f55adf2dacf187e60191b32a92703ef77abcBehdad Esfahboddef merge(self, m, tables):
1249e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	if not hasattr(self, 'mergeMap'):
1259e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod		m.log("Don't know how to merge '%s'." % self.tableTag)
12692fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod		return NotImplemented
1279e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod
12892fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod	return m.mergeObjects(self, self.mergeMap, tables)
12971294def6730c37839f03dee519b319f982587eaBehdad Esfahbod
1309e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad EsfahbodttLib.getTableClass('maxp').mergeMap = {
1319e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'*': max,
1329e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'tableTag': equal,
1339e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'tableVersion': equal,
1349e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'numGlyphs': sum,
1359e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'maxStorage': max, # FIXME: may need to be changed to sum
1369e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'maxFunctionDefs': sum,
1379e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'maxInstructionDefs': sum,
1389e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	# TODO When we correctly merge hinting data, update these values:
1399e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	# maxFunctionDefs, maxInstructionDefs, maxSizeOfInstructions
1409e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod}
1419e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod
1429e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad EsfahbodttLib.getTableClass('head').mergeMap = {
1439e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'tableTag': equal,
1449e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'tableVersion': max,
1459e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'fontRevision': max,
14692fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod	'checkSumAdjustment': lambda lst: 0, # We need *something* here
1479e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'magicNumber': equal,
1489e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'flags': first, # FIXME: replace with bit-sensitive code
1499e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'unitsPerEm': equal,
1509e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'created': current_time,
1519e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'modified': current_time,
1529e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'xMin': min,
1539e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'yMin': min,
1549e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'xMax': max,
1559e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'yMax': max,
1569e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'macStyle': first,
1579e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'lowestRecPPEM': max,
1589e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'fontDirectionHint': lambda lst: 2,
1599e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'indexToLocFormat': recalculate,
1609e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'glyphDataFormat': equal,
1619e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod}
1629e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod
1639e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad EsfahbodttLib.getTableClass('hhea').mergeMap = {
1649e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'*': equal,
1659e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'tableTag': equal,
1669e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'tableVersion': max,
1679e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'ascent': max,
1689e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'descent': min,
1699e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'lineGap': max,
1709e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'advanceWidthMax': max,
1719e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'minLeftSideBearing': min,
1729e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'minRightSideBearing': min,
1739e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'xMaxExtent': max,
1749e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'caretSlopeRise': first, # FIXME
1759e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'caretSlopeRun': first, # FIXME
1769e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'caretOffset': first, # FIXME
1779e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'numberOfHMetrics': recalculate,
1789e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod}
1799e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod
1809e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad EsfahbodttLib.getTableClass('OS/2').mergeMap = {
1819e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'*': first,
1829e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'tableTag': equal,
1839e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'version': max,
18492fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod	'xAvgCharWidth': avg_int, # Apparently fontTools doesn't recalc this
1859e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'fsType': first, # FIXME
1869e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'panose': first, # FIXME?
1879e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'ulUnicodeRange1': bitwise_or,
1889e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'ulUnicodeRange2': bitwise_or,
1899e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'ulUnicodeRange3': bitwise_or,
1909e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'ulUnicodeRange4': bitwise_or,
1919e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'fsFirstCharIndex': min,
1929e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'fsLastCharIndex': max,
1939e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'sTypoAscender': max,
1949e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'sTypoDescender': min,
1959e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'sTypoLineGap': max,
1969e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'usWinAscent': max,
1979e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'usWinDescent': max,
1989e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'ulCodePageRange1': bitwise_or,
1999e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'ulCodePageRange2': bitwise_or,
2009e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'usMaxContex': max,
2019e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	# TODO version 5
2029e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod}
2039e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod
2049e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad EsfahbodttLib.getTableClass('post').mergeMap = {
2059e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'*': first,
2069e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'tableTag': equal,
2079e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'formatType': max,
2089e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'isFixedPitch': min,
2099e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'minMemType42': max,
2109e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'maxMemType42': lambda lst: 0,
2119e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'minMemType1': max,
2129e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'maxMemType1': lambda lst: 0,
21392fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod	'mapping': implemented(sumDicts),
21492fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod	'extraNames': lambda lst: [][:],
2159e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod}
216f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
2179e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad EsfahbodttLib.getTableClass('vmtx').mergeMap = ttLib.getTableClass('hmtx').mergeMap = {
2189e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'tableTag': equal,
2199e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'metrics': sumDicts,
2209e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod}
22165f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod
2229e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad EsfahbodttLib.getTableClass('loca').mergeMap = {
22392fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod	'*': recalculate,
2249e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'tableTag': equal,
2259e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod}
2269e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod
2279e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad EsfahbodttLib.getTableClass('glyf').mergeMap = {
2289e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'tableTag': equal,
2299e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'glyphs': sumDicts,
2309e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod	'glyphOrder': sumLists,
2319e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod}
232f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
233be4ecc7c67917d95b44d16b32d8d72446162f3ddBehdad Esfahbod@_add_method(ttLib.getTableClass('glyf'))
2343b36f55adf2dacf187e60191b32a92703ef77abcBehdad Esfahboddef merge(self, m, tables):
2353b36f55adf2dacf187e60191b32a92703ef77abcBehdad Esfahbod	for table in tables:
236436503372a7a4aeb529a360e66114ce1b1b6d9ceBehdad Esfahbod		for g in table.glyphs.values():
237436503372a7a4aeb529a360e66114ce1b1b6d9ceBehdad Esfahbod			# Drop hints for now, since we don't remap
238436503372a7a4aeb529a360e66114ce1b1b6d9ceBehdad Esfahbod			# functions / CVT values.
239436503372a7a4aeb529a360e66114ce1b1b6d9ceBehdad Esfahbod			g.removeHinting()
240436503372a7a4aeb529a360e66114ce1b1b6d9ceBehdad Esfahbod			# Expand composite glyphs to load their
241436503372a7a4aeb529a360e66114ce1b1b6d9ceBehdad Esfahbod			# composite glyph names.
242436503372a7a4aeb529a360e66114ce1b1b6d9ceBehdad Esfahbod			if g.isComposite():
243436503372a7a4aeb529a360e66114ce1b1b6d9ceBehdad Esfahbod				g.expand(table)
24492fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod	return DefaultTable.merge(self, m, tables)
245f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
24692fd5665772996966aaa0709462ebae5a72d4e19Behdad EsfahbodttLib.getTableClass('prep').mergeMap = NotImplemented
24792fd5665772996966aaa0709462ebae5a72d4e19Behdad EsfahbodttLib.getTableClass('fpgm').mergeMap = NotImplemented
24892fd5665772996966aaa0709462ebae5a72d4e19Behdad EsfahbodttLib.getTableClass('cvt ').mergeMap = NotImplemented
24945d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod
250be4ecc7c67917d95b44d16b32d8d72446162f3ddBehdad Esfahbod@_add_method(ttLib.getTableClass('cmap'))
2513b36f55adf2dacf187e60191b32a92703ef77abcBehdad Esfahboddef merge(self, m, tables):
25271294def6730c37839f03dee519b319f982587eaBehdad Esfahbod	# TODO Handle format=14.
2533b36f55adf2dacf187e60191b32a92703ef77abcBehdad Esfahbod	cmapTables = [t for table in tables for t in table.tables
25471294def6730c37839f03dee519b319f982587eaBehdad Esfahbod		      if t.platformID == 3 and t.platEncID in [1, 10]]
25571294def6730c37839f03dee519b319f982587eaBehdad Esfahbod	# TODO Better handle format-4 and format-12 coexisting in same font.
25671294def6730c37839f03dee519b319f982587eaBehdad Esfahbod	# TODO Insert both a format-4 and format-12 if needed.
257be4ecc7c67917d95b44d16b32d8d72446162f3ddBehdad Esfahbod	module = ttLib.getTableModule('cmap')
25871294def6730c37839f03dee519b319f982587eaBehdad Esfahbod	assert all(t.format in [4, 12] for t in cmapTables)
25971294def6730c37839f03dee519b319f982587eaBehdad Esfahbod	format = max(t.format for t in cmapTables)
26071294def6730c37839f03dee519b319f982587eaBehdad Esfahbod	cmapTable = module.cmap_classes[format](format)
26171294def6730c37839f03dee519b319f982587eaBehdad Esfahbod	cmapTable.cmap = {}
26271294def6730c37839f03dee519b319f982587eaBehdad Esfahbod	cmapTable.platformID = 3
26371294def6730c37839f03dee519b319f982587eaBehdad Esfahbod	cmapTable.platEncID = max(t.platEncID for t in cmapTables)
26471294def6730c37839f03dee519b319f982587eaBehdad Esfahbod	cmapTable.language = 0
26571294def6730c37839f03dee519b319f982587eaBehdad Esfahbod	for table in cmapTables:
26671294def6730c37839f03dee519b319f982587eaBehdad Esfahbod		# TODO handle duplicates.
26771294def6730c37839f03dee519b319f982587eaBehdad Esfahbod		cmapTable.cmap.update(table.cmap)
26871294def6730c37839f03dee519b319f982587eaBehdad Esfahbod	self.tableVersion = 0
26971294def6730c37839f03dee519b319f982587eaBehdad Esfahbod	self.tables = [cmapTable]
27071294def6730c37839f03dee519b319f982587eaBehdad Esfahbod	self.numSubTables = len(self.tables)
27192fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod	return self
27271294def6730c37839f03dee519b319f982587eaBehdad Esfahbod
273c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod
2742642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad EsfahbodotTables.ScriptList.mergeMap = {
2752642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod	'ScriptCount': sum,
2762642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod	'ScriptRecord': sumLists,
2772642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod}
2782642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod
2792642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad EsfahbodotTables.FeatureList.mergeMap = {
2802642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod	'FeatureCount': sum,
2812642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod	'FeatureRecord': sumLists,
2822642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod}
2832642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod
2842642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad EsfahbodotTables.LookupList.mergeMap = {
2852642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod	'LookupCount': sum,
2862642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod	'Lookup': sumLists,
2872642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod}
2882642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod
28912dd547c012d4e1295a6c9c2eb48835cd57851caBehdad EsfahbodotTables.Coverage.mergeMap = {
29012dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod	'glyphs': sumLists,
29112dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod}
29212dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod
29312dd547c012d4e1295a6c9c2eb48835cd57851caBehdad EsfahbodotTables.ClassDef.mergeMap = {
29412dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod	'classDefs': sumDicts,
29512dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod}
29612dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod
29712dd547c012d4e1295a6c9c2eb48835cd57851caBehdad EsfahbodotTables.LigCaretList.mergeMap = {
29812dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod	'Coverage': mergeObjects,
29912dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod	'LigGlyphCount': sum,
30012dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod	'LigGlyph': sumLists,
30112dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod}
302c14ab48ae84ce77bbcc0942baaa18f8099edb447Behdad Esfahbod
30312dd547c012d4e1295a6c9c2eb48835cd57851caBehdad EsfahbodotTables.AttachList.mergeMap = {
30412dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod	'Coverage': mergeObjects,
30512dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod	'GlyphCount': sum,
30612dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod	'AttachPoint': sumLists,
30712dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod}
30812dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod
30912dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod# XXX Renumber MarkFilterSets of lookups
31012dd547c012d4e1295a6c9c2eb48835cd57851caBehdad EsfahbodotTables.MarkGlyphSetsDef.mergeMap = {
31112dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod	'MarkSetTableFormat': equal,
31212dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod	'MarkSetCount': sum,
31312dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod	'Coverage': sumLists,
31412dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod}
31512dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod
31612dd547c012d4e1295a6c9c2eb48835cd57851caBehdad EsfahbodotTables.GDEF.mergeMap = {
31712dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod	'*': mergeObjects,
31812dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod	'Version': max,
31912dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod}
32012dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod
3212642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad EsfahbodotTables.GSUB.mergeMap = otTables.GPOS.mergeMap = {
3222642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod	'*': mergeObjects,
32312dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod	'Version': max,
3242642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod}
3252642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod
3262642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad EsfahbodttLib.getTableClass('GDEF').mergeMap = \
3272642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad EsfahbodttLib.getTableClass('GSUB').mergeMap = \
3282642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad EsfahbodttLib.getTableClass('GPOS').mergeMap = \
3292642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad EsfahbodttLib.getTableClass('BASE').mergeMap = \
3302642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad EsfahbodttLib.getTableClass('JSTF').mergeMap = \
3312642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad EsfahbodttLib.getTableClass('MATH').mergeMap = \
3322642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod{
3332642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod	'tableTag': equal,
33412dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod	'table': mergeObjects,
33512dd547c012d4e1295a6c9c2eb48835cd57851caBehdad Esfahbod}
336f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
3372642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod
3382642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod@_add_method(otTables.Feature)
3392642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahboddef mapLookups(self, lookupMap):
3402642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod	self.LookupListIndex = [lookupMap[i] for i in self.LookupListIndex]
3412642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod
3422642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod@_add_method(otTables.FeatureList)
3432642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahboddef mapLookups(self, lookupMap):
3442642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod	for f in self.FeatureRecord:
3452642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod		if not f or not f.Feature: continue
3462642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod		f.Feature.mapLookups(lookupMap)
3472642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod
3482642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod@_add_method(otTables.DefaultLangSys,
3492642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod             otTables.LangSys)
3502642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahboddef mapFeatures(self, featureMap):
3512642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod	self.FeatureIndex = [featureMap[i] for i in self.FeatureIndex]
3522642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod	if self.ReqFeatureIndex != 65535:
3532642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod		self.ReqFeatureIndex = featureMap[self.ReqFeatureIndex]
3542642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod
3552642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod@_add_method(otTables.Script)
3562642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahboddef mapFeatures(self, featureMap):
3572642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod	if self.DefaultLangSys:
3582642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod		self.DefaultLangSys.mapFeatures(featureMap)
3592642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod	for l in self.LangSysRecord:
3602642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod		if not l or not l.LangSys: continue
3612642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod		l.LangSys.mapFeatures(featureMap)
3622642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod
3632642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod@_add_method(otTables.ScriptList)
3642642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahboddef mapFeatures(self, feature_indices):
3652642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod	for s in self.ScriptRecord:
3662642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod		if not s or not s.Script: continue
3672642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod		s.Script.mapFeatures(featureMap)
3682642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod
3692642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod
370f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbodclass Options(object):
371f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
372f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod  class UnknownOptionError(Exception):
373f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod    pass
374f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
375f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod  def __init__(self, **kwargs):
376f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
377f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod    self.set(**kwargs)
378f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
379f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod  def set(self, **kwargs):
380f63e80e3fc4ef5406109f1fbe2746e26927fdebfBehdad Esfahbod    for k,v in kwargs.items():
381f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod      if not hasattr(self, k):
382f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod        raise self.UnknownOptionError("Unknown option '%s'" % k)
383f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod      setattr(self, k, v)
384f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
385f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod  def parse_opts(self, argv, ignore_unknown=False):
386f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod    ret = []
387f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod    opts = {}
388f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod    for a in argv:
389f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod      orig_a = a
390f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod      if not a.startswith('--'):
391f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod        ret.append(a)
392f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod        continue
393f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod      a = a[2:]
394f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod      i = a.find('=')
395f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod      op = '='
396f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod      if i == -1:
397f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod        if a.startswith("no-"):
398f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod          k = a[3:]
399f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod          v = False
400f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod        else:
401f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod          k = a
402f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod          v = True
403f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod      else:
404f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod        k = a[:i]
405f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod        if k[-1] in "-+":
406f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod          op = k[-1]+'='  # Ops is '-=' or '+=' now.
407f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod          k = k[:-1]
408f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod        v = a[i+1:]
409f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod      k = k.replace('-', '_')
410f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod      if not hasattr(self, k):
411f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod        if ignore_unknown == True or k in ignore_unknown:
412f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod          ret.append(orig_a)
413f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod          continue
414f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod        else:
415f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod          raise self.UnknownOptionError("Unknown option '%s'" % a)
416f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
417f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod      ov = getattr(self, k)
418f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod      if isinstance(ov, bool):
419f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod        v = bool(v)
420f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod      elif isinstance(ov, int):
421f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod        v = int(v)
422f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod      elif isinstance(ov, list):
423f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod        vv = v.split(',')
424f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod        if vv == ['']:
425f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod          vv = []
426f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod        vv = [int(x, 0) if len(x) and x[0] in "0123456789" else x for x in vv]
427f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod        if op == '=':
428f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod          v = vv
429f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod        elif op == '+=':
430f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod          v = ov
431f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod          v.extend(vv)
432f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod        elif op == '-=':
433f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod          v = ov
434f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod          for x in vv:
435f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod            if x in v:
436f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod              v.remove(x)
437f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod        else:
438f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod          assert 0
439f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
440f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod      opts[k] = v
441f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod    self.set(**opts)
442f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
443f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod    return ret
444f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
445f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
4469e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbodclass Merger(object):
44745d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod
448f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod	def __init__(self, options=None, log=None):
449f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
450f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod		if not log:
451f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod			log = Logger()
452f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod		if not options:
453f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod			options = Options()
454f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
455f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod		self.options = options
456f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod		self.log = log
45745d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod
458f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod	def merge(self, fontfiles):
45945d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod
46045d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod		mega = ttLib.TTFont()
46145d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod
46245d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod		#
46345d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod		# Settle on a mega glyph order.
46445d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod		#
465f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod		fonts = [ttLib.TTFont(fontfile) for fontfile in fontfiles]
46645d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod		glyphOrders = [font.getGlyphOrder() for font in fonts]
46745d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod		megaGlyphOrder = self._mergeGlyphOrders(glyphOrders)
46845d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod		# Reload fonts and set new glyph names on them.
46945d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod		# TODO Is it necessary to reload font?  I think it is.  At least
47045d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod		# it's safer, in case tables were loaded to provide glyph names.
471f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod		fonts = [ttLib.TTFont(fontfile) for fontfile in fontfiles]
4723235a04ea938845d656a68c242591d37148ea353Behdad Esfahbod		for font,glyphOrder in zip(fonts, glyphOrders):
4733235a04ea938845d656a68c242591d37148ea353Behdad Esfahbod			font.setGlyphOrder(glyphOrder)
47445d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod		mega.setGlyphOrder(megaGlyphOrder)
47545d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod
4762642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod		for font in fonts:
4772642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod			self._preMerge(font)
4782642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod
479f63e80e3fc4ef5406109f1fbe2746e26927fdebfBehdad Esfahbod		allTags = reduce(set.union, (list(font.keys()) for font in fonts), set())
48045d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod		allTags.remove('GlyphOrder')
48145d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod		for tag in allTags:
482f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
48345d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod			clazz = ttLib.getTableClass(tag)
48445d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod
4852642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod			tables = [font.get(tag, NotImplemented) for font in fonts]
48692fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod			table = clazz(tag).merge(self, tables)
48792fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod			if table is not NotImplemented and table is not False:
48865f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod				mega[tag] = table
489b640f7435c3d29c57310b1a5f7d8e5b538a4c1e3Behdad Esfahbod				self.log("Merged '%s'." % tag)
49065f19d8440f5fa5d94d1f04593f16cd9f21f176bBehdad Esfahbod			else:
4919e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod				self.log("Dropped '%s'." % tag)
492b640f7435c3d29c57310b1a5f7d8e5b538a4c1e3Behdad Esfahbod			self.log.lapse("merge '%s'" % tag)
49345d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod
4942642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod		self._postMerge(mega)
4952642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod
49645d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod		return mega
49745d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod
49845d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod	def _mergeGlyphOrders(self, glyphOrders):
499c2e27fd88f54fcc081049dabce59889cdc87450eBehdad Esfahbod		"""Modifies passed-in glyphOrders to reflect new glyph names.
500c2e27fd88f54fcc081049dabce59889cdc87450eBehdad Esfahbod		Returns glyphOrder for the merged font."""
50145d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod		# Simply append font index to the glyph name for now.
502c2e27fd88f54fcc081049dabce59889cdc87450eBehdad Esfahbod		# TODO Even this simplistic numbering can result in conflicts.
503c2e27fd88f54fcc081049dabce59889cdc87450eBehdad Esfahbod		# But then again, we have to improve this soon anyway.
50445d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod		mega = []
50545d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod		for n,glyphOrder in enumerate(glyphOrders):
50645d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod			for i,glyphName in enumerate(glyphOrder):
507f63e80e3fc4ef5406109f1fbe2746e26927fdebfBehdad Esfahbod				glyphName += "#" + repr(n)
50845d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod				glyphOrder[i] = glyphName
50945d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod				mega.append(glyphName)
51045d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod		return mega
51145d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod
5126baf26ea74247a0bed5f0b52d13bc3ef1c931204Behdad Esfahbod	def mergeObjects(self, returnTable, logic, tables):
51392fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod		# Right now we don't use self at all.  Will use in the future
51492fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod		# for options and logging.
51592fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod
51692fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod		if logic is NotImplemented:
51792fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod			return NotImplemented
51892fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod
51992fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod		allKeys = set.union(set(), *(vars(table).keys() for table in tables if table is not NotImplemented))
52047bee9cfbd47dc22895003cc94ab91f9075ca27fRoozbeh Pournader		for key in allKeys:
521e219c6c76f116a38e0187b4388d99dd59eff30bcRoozbeh Pournader			try:
5226baf26ea74247a0bed5f0b52d13bc3ef1c931204Behdad Esfahbod				mergeLogic = logic[key]
523e219c6c76f116a38e0187b4388d99dd59eff30bcRoozbeh Pournader			except KeyError:
5249e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod				try:
5256baf26ea74247a0bed5f0b52d13bc3ef1c931204Behdad Esfahbod					mergeLogic = logic['*']
5269e6adb6bd6b92765f72d0a2acf871405832aa11eBehdad Esfahbod				except KeyError:
5276baf26ea74247a0bed5f0b52d13bc3ef1c931204Behdad Esfahbod					raise Exception("Don't know how to merge key %s of class %s" %
5286baf26ea74247a0bed5f0b52d13bc3ef1c931204Behdad Esfahbod							(key, returnTable.__class__.__name__))
52992fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod			if mergeLogic is NotImplemented:
530e219c6c76f116a38e0187b4388d99dd59eff30bcRoozbeh Pournader				continue
53192fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod			value = mergeLogic(getattr(table, key, NotImplemented) for table in tables)
53292fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod			if value is not NotImplemented:
53392fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod				setattr(returnTable, key, value)
53492fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod
53592fd5665772996966aaa0709462ebae5a72d4e19Behdad Esfahbod		return returnTable
53647bee9cfbd47dc22895003cc94ab91f9075ca27fRoozbeh Pournader
5372642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod	def _preMerge(self, font):
5382642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod
5392642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod		return
5402642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod		GDEF = font.get('GDEF')
5412642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod		GSUB = font.get('GSUB')
5422642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod		GPOS = font.get('GPOS')
5432642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod
5442642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod		for t in [GSUB, GPOS]:
5452642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod			if not t or not t.table.LookupList or not t.table.FeatureList: continue
5462642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod			lookupMap = dict(enumerate(t.table.LookupList.Lookup))
5472642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod			t.table.FeatureList.mapLookups(lookupMap)
5482642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod
5492642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod		# TODO FeatureParams nameIDs
5502642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod
5512642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod	def _postMerge(self, font):
5522642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod		pass
5532642934116cc0e3b873e37051cb57d3b29c0a9b4Behdad Esfahbod
554f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
555f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbodclass Logger(object):
556f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
557f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod  def __init__(self, verbose=False, xml=False, timing=False):
558f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod    self.verbose = verbose
559f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod    self.xml = xml
560f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod    self.timing = timing
561f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod    self.last_time = self.start_time = time.time()
562f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
563f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod  def parse_opts(self, argv):
564f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod    argv = argv[:]
565f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod    for v in ['verbose', 'xml', 'timing']:
566f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod      if "--"+v in argv:
567f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod        setattr(self, v, True)
568f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod        argv.remove("--"+v)
569f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod    return argv
570f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
571f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod  def __call__(self, *things):
572f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod    if not self.verbose:
573f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod      return
574f63e80e3fc4ef5406109f1fbe2746e26927fdebfBehdad Esfahbod    print(' '.join(str(x) for x in things))
575f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
576f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod  def lapse(self, *things):
577f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod    if not self.timing:
578f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod      return
579f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod    new_time = time.time()
580f63e80e3fc4ef5406109f1fbe2746e26927fdebfBehdad Esfahbod    print("Took %0.3fs to %s" %(new_time - self.last_time,
581f63e80e3fc4ef5406109f1fbe2746e26927fdebfBehdad Esfahbod                                 ' '.join(str(x) for x in things)))
582f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod    self.last_time = new_time
583f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
584f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod  def font(self, font, file=sys.stdout):
585f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod    if not self.xml:
586f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod      return
587f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod    from fontTools.misc import xmlWriter
588f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod    writer = xmlWriter.XMLWriter(file)
589f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod    font.disassembleInstructions = False  # Work around ttLib bug
590f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod    for tag in font.keys():
591f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod      writer.begintag(tag)
592f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod      writer.newline()
593f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod      font[tag].toXML(writer, font)
594f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod      writer.endtag(tag)
595f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod      writer.newline()
596f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
597f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
598f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod__all__ = [
599f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod  'Options',
600f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod  'Merger',
601f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod  'Logger',
602f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod  'main'
603f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod]
604f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
60545d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahboddef main(args):
606f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
607f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod	log = Logger()
608f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod	args = log.parse_opts(args)
609f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
610f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod	options = Options()
611f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod	args = options.parse_opts(args)
612f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
61345d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod	if len(args) < 1:
614f63e80e3fc4ef5406109f1fbe2746e26927fdebfBehdad Esfahbod		print("usage: pyftmerge font...", file=sys.stderr)
61545d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod		sys.exit(1)
616f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod
617f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod	merger = Merger(options=options, log=log)
618f2d5982826530296fd7c8f9e2d2a4dc3e070934dBehdad Esfahbod	font = merger.merge(args)
61945d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod	outfile = 'merged.ttf'
62045d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod	font.save(outfile)
621b640f7435c3d29c57310b1a5f7d8e5b538a4c1e3Behdad Esfahbod	log.lapse("compile and save font")
622b640f7435c3d29c57310b1a5f7d8e5b538a4c1e3Behdad Esfahbod
623b640f7435c3d29c57310b1a5f7d8e5b538a4c1e3Behdad Esfahbod	log.last_time = log.start_time
624b640f7435c3d29c57310b1a5f7d8e5b538a4c1e3Behdad Esfahbod	log.lapse("make one with everything(TOTAL TIME)")
62545d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod
62645d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbodif __name__ == "__main__":
62745d2f38aa51169f400062f2153a74277b9d4d04eBehdad Esfahbod	main(sys.argv[1:])
628