• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2013 Google, Inc. All Rights Reserved.
2#
3# Google Author(s): Behdad Esfahbod, Roozbeh Pournader
4
5from fontTools.ttLib.tables.DefaultTable import DefaultTable
6import logging
7
8
9log = logging.getLogger("fontTools.merge")
10
11
12def add_method(*clazzes, **kwargs):
13	"""Returns a decorator function that adds a new method to one or
14	more classes."""
15	allowDefault = kwargs.get('allowDefaultTable', False)
16	def wrapper(method):
17		done = []
18		for clazz in clazzes:
19			if clazz in done: continue # Support multiple names of a clazz
20			done.append(clazz)
21			assert allowDefault or clazz != DefaultTable, 'Oops, table class not found.'
22			assert method.__name__ not in clazz.__dict__, \
23				"Oops, class '%s' has method '%s'." % (clazz.__name__, method.__name__)
24			setattr(clazz, method.__name__, method)
25		return None
26	return wrapper
27
28def mergeObjects(lst):
29	lst = [item for item in lst if item is not NotImplemented]
30	if not lst:
31		return NotImplemented
32	lst = [item for item in lst if item is not None]
33	if not lst:
34		return None
35
36	clazz = lst[0].__class__
37	assert all(type(item) == clazz for item in lst), lst
38
39	logic = clazz.mergeMap
40	returnTable = clazz()
41	returnDict = {}
42
43	allKeys = set.union(set(), *(vars(table).keys() for table in lst))
44	for key in allKeys:
45		try:
46			mergeLogic = logic[key]
47		except KeyError:
48			try:
49				mergeLogic = logic['*']
50			except KeyError:
51				raise Exception("Don't know how to merge key %s of class %s" %
52						(key, clazz.__name__))
53		if mergeLogic is NotImplemented:
54			continue
55		value = mergeLogic(getattr(table, key, NotImplemented) for table in lst)
56		if value is not NotImplemented:
57			returnDict[key] = value
58
59	returnTable.__dict__ = returnDict
60
61	return returnTable
62
63@add_method(DefaultTable, allowDefaultTable=True)
64def merge(self, m, tables):
65	if not hasattr(self, 'mergeMap'):
66		log.info("Don't know how to merge '%s'.", self.tableTag)
67		return NotImplemented
68
69	logic = self.mergeMap
70
71	if isinstance(logic, dict):
72		return m.mergeObjects(self, self.mergeMap, tables)
73	else:
74		return logic(tables)
75
76
77