• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""
2Merge OpenType Layout tables (GDEF / GPOS / GSUB).
3"""
4from __future__ import print_function, division, absolute_import
5from fontTools.misc.py23 import *
6from fontTools.misc.fixedTools import otRound
7from fontTools.misc import classifyTools
8from fontTools.ttLib.tables import otTables as ot
9from fontTools.ttLib.tables import otBase as otBase
10from fontTools.ttLib.tables.DefaultTable import DefaultTable
11from fontTools.varLib import builder, models, varStore
12from fontTools.varLib.models import nonNone, allNone, allEqual, allEqualTo
13from fontTools.varLib.varStore import VarStoreInstancer
14from functools import reduce
15
16
17class Merger(object):
18
19	def __init__(self, font=None):
20		self.font = font
21
22	@classmethod
23	def merger(celf, clazzes, attrs=(None,)):
24		assert celf != Merger, 'Subclass Merger instead.'
25		if 'mergers' not in celf.__dict__:
26			celf.mergers = {}
27		if type(clazzes) == type:
28			clazzes = (clazzes,)
29		if type(attrs) == str:
30			attrs = (attrs,)
31		def wrapper(method):
32			assert method.__name__ == 'merge'
33			done = []
34			for clazz in clazzes:
35				if clazz in done: continue # Support multiple names of a clazz
36				done.append(clazz)
37				mergers = celf.mergers.setdefault(clazz, {})
38				for attr in attrs:
39					assert attr not in mergers, \
40						"Oops, class '%s' has merge function for '%s' defined already." % (clazz.__name__, attr)
41					mergers[attr] = method
42			return None
43		return wrapper
44
45	@classmethod
46	def mergersFor(celf, thing, _default={}):
47		typ = type(thing)
48
49		for celf in celf.mro():
50
51			mergers = getattr(celf, 'mergers', None)
52			if mergers is None:
53				break;
54
55			m = celf.mergers.get(typ, None)
56			if m is not None:
57				return m
58
59		return _default
60
61	def mergeObjects(self, out, lst, exclude=()):
62		keys = sorted(vars(out).keys())
63		assert all(keys == sorted(vars(v).keys()) for v in lst), \
64			(keys, [sorted(vars(v).keys()) for v in lst])
65		mergers = self.mergersFor(out)
66		defaultMerger = mergers.get('*', self.__class__.mergeThings)
67		try:
68			for key in keys:
69				if key in exclude: continue
70				value = getattr(out, key)
71				values = [getattr(table, key) for table in lst]
72				mergerFunc = mergers.get(key, defaultMerger)
73				mergerFunc(self, value, values)
74		except Exception as e:
75			e.args = e.args + ('.'+key,)
76			raise
77
78	def mergeLists(self, out, lst):
79		assert allEqualTo(out, lst, len), (len(out), [len(v) for v in lst])
80		for i,(value,values) in enumerate(zip(out, zip(*lst))):
81			try:
82				self.mergeThings(value, values)
83			except Exception as e:
84				e.args = e.args + ('[%d]' % i,)
85				raise
86
87	def mergeThings(self, out, lst):
88		try:
89			assert allEqualTo(out, lst, type), (out, lst)
90			mergerFunc = self.mergersFor(out).get(None, None)
91			if mergerFunc is not None:
92				mergerFunc(self, out, lst)
93			elif hasattr(out, '__dict__'):
94				self.mergeObjects(out, lst)
95			elif isinstance(out, list):
96				self.mergeLists(out, lst)
97			else:
98				assert allEqualTo(out, lst), (out, lst)
99		except Exception as e:
100			e.args = e.args + (type(out).__name__,)
101			raise
102
103	def mergeTables(self, font, master_ttfs, tableTags):
104
105		for tag in tableTags:
106			if tag not in font: continue
107			self.mergeThings(font[tag], [m[tag] if tag in m else None
108						     for m in master_ttfs])
109
110#
111# Aligning merger
112#
113class AligningMerger(Merger):
114	pass
115
116@AligningMerger.merger(ot.GDEF, "GlyphClassDef")
117def merge(merger, self, lst):
118	if self is None:
119		assert allNone(lst), (lst)
120		return
121
122	self.classDefs = {}
123	# We only care about the .classDefs
124	self = self.classDefs
125	lst = [l.classDefs for l in lst]
126
127	allKeys = set()
128	allKeys.update(*[l.keys() for l in lst])
129	for k in allKeys:
130		allValues = nonNone(l.get(k) for l in lst)
131		assert allEqual(allValues), allValues
132		if not allValues:
133			self[k] = None
134		else:
135			self[k] = allValues[0]
136
137def _SinglePosUpgradeToFormat2(self):
138	if self.Format == 2: return self
139
140	ret = ot.SinglePos()
141	ret.Format = 2
142	ret.Coverage = self.Coverage
143	ret.ValueFormat = self.ValueFormat
144	ret.Value = [self.Value for g in ret.Coverage.glyphs]
145	ret.ValueCount = len(ret.Value)
146
147	return ret
148
149def _merge_GlyphOrders(font, lst, values_lst=None, default=None):
150	"""Takes font and list of glyph lists (must be sorted by glyph id), and returns
151	two things:
152	- Combined glyph list,
153	- If values_lst is None, return input glyph lists, but padded with None when a glyph
154	  was missing in a list.  Otherwise, return values_lst list-of-list, padded with None
155	  to match combined glyph lists.
156	"""
157	if values_lst is None:
158		dict_sets = [set(l) for l in lst]
159	else:
160		dict_sets = [{g:v for g,v in zip(l,vs)} for l,vs in zip(lst,values_lst)]
161	combined = set()
162	combined.update(*dict_sets)
163
164	sortKey = font.getReverseGlyphMap().__getitem__
165	order = sorted(combined, key=sortKey)
166	# Make sure all input glyphsets were in proper order
167	assert all(sorted(vs, key=sortKey) == vs for vs in lst)
168	del combined
169
170	paddedValues = None
171	if values_lst is None:
172		padded = [[glyph if glyph in dict_set else default
173			   for glyph in order]
174			  for dict_set in dict_sets]
175	else:
176		assert len(lst) == len(values_lst)
177		padded = [[dict_set[glyph] if glyph in dict_set else default
178			   for glyph in order]
179			  for dict_set in dict_sets]
180	return order, padded
181
182def _Lookup_SinglePos_get_effective_value(subtables, glyph):
183	for self in subtables:
184		if self is None or \
185		   type(self) != ot.SinglePos or \
186		   self.Coverage is None or \
187		   glyph not in self.Coverage.glyphs:
188			continue
189		if self.Format == 1:
190			return self.Value
191		elif self.Format == 2:
192			return self.Value[self.Coverage.glyphs.index(glyph)]
193		else:
194			assert 0
195	return None
196
197def _Lookup_PairPos_get_effective_value_pair(subtables, firstGlyph, secondGlyph):
198	for self in subtables:
199		if self is None or \
200		   type(self) != ot.PairPos or \
201		   self.Coverage is None or \
202		   firstGlyph not in self.Coverage.glyphs:
203			continue
204		if self.Format == 1:
205			ps = self.PairSet[self.Coverage.glyphs.index(firstGlyph)]
206			pvr = ps.PairValueRecord
207			for rec in pvr: # TODO Speed up
208				if rec.SecondGlyph == secondGlyph:
209					return rec
210			continue
211		elif self.Format == 2:
212			klass1 = self.ClassDef1.classDefs.get(firstGlyph, 0)
213			klass2 = self.ClassDef2.classDefs.get(secondGlyph, 0)
214			return self.Class1Record[klass1].Class2Record[klass2]
215		else:
216			assert 0
217	return None
218
219@AligningMerger.merger(ot.SinglePos)
220def merge(merger, self, lst):
221	self.ValueFormat = valueFormat = reduce(int.__or__, [l.ValueFormat for l in lst], 0)
222	assert len(lst) == 1 or (valueFormat & ~0xF == 0), valueFormat
223
224	# If all have same coverage table and all are format 1,
225	coverageGlyphs = self.Coverage.glyphs
226	if all(v.Format == 1 for v in lst) and all(coverageGlyphs == v.Coverage.glyphs for v in lst):
227		self.Value = otBase.ValueRecord(valueFormat)
228		merger.mergeThings(self.Value, [v.Value for v in lst])
229		self.ValueFormat = self.Value.getFormat()
230		return
231
232	# Upgrade everything to Format=2
233	self.Format = 2
234	lst = [_SinglePosUpgradeToFormat2(v) for v in lst]
235
236	# Align them
237	glyphs, padded = _merge_GlyphOrders(merger.font,
238					    [v.Coverage.glyphs for v in lst],
239					    [v.Value for v in lst])
240
241	self.Coverage.glyphs = glyphs
242	self.Value = [otBase.ValueRecord(valueFormat) for g in glyphs]
243	self.ValueCount = len(self.Value)
244
245	for i,values in enumerate(padded):
246		for j,glyph in enumerate(glyphs):
247			if values[j] is not None: continue
248			# Fill in value from other subtables
249			# Note!!! This *might* result in behavior change if ValueFormat2-zeroedness
250			# is different between used subtable and current subtable!
251			# TODO(behdad) Check and warn if that happens?
252			v = _Lookup_SinglePos_get_effective_value(merger.lookup_subtables[i], glyph)
253			if v is None:
254				v = otBase.ValueRecord(valueFormat)
255			values[j] = v
256
257	merger.mergeLists(self.Value, padded)
258
259	# Merge everything else; though, there shouldn't be anything else. :)
260	merger.mergeObjects(self, lst,
261			    exclude=('Format', 'Coverage', 'Value', 'ValueCount'))
262	self.ValueFormat = reduce(int.__or__, [v.getFormat() for v in self.Value], 0)
263
264@AligningMerger.merger(ot.PairSet)
265def merge(merger, self, lst):
266	# Align them
267	glyphs, padded = _merge_GlyphOrders(merger.font,
268				[[v.SecondGlyph for v in vs.PairValueRecord] for vs in lst],
269				[vs.PairValueRecord for vs in lst])
270
271	self.PairValueRecord = pvrs = []
272	for glyph in glyphs:
273		pvr = ot.PairValueRecord()
274		pvr.SecondGlyph = glyph
275		pvr.Value1 = otBase.ValueRecord(merger.valueFormat1) if merger.valueFormat1 else None
276		pvr.Value2 = otBase.ValueRecord(merger.valueFormat2) if merger.valueFormat2 else None
277		pvrs.append(pvr)
278	self.PairValueCount = len(self.PairValueRecord)
279
280	for i,values in enumerate(padded):
281		for j,glyph in enumerate(glyphs):
282			# Fill in value from other subtables
283			v = ot.PairValueRecord()
284			v.SecondGlyph = glyph
285			if values[j] is not None:
286				vpair = values[j]
287			else:
288				vpair = _Lookup_PairPos_get_effective_value_pair(merger.lookup_subtables[i], self._firstGlyph, glyph)
289			if vpair is None:
290				v1, v2 = None, None
291			else:
292				v1, v2 = vpair.Value1, vpair.Value2
293			v.Value1 = otBase.ValueRecord(merger.valueFormat1, src=v1) if merger.valueFormat1 else None
294			v.Value2 = otBase.ValueRecord(merger.valueFormat2, src=v2) if merger.valueFormat2 else None
295			values[j] = v
296	del self._firstGlyph
297
298	merger.mergeLists(self.PairValueRecord, padded)
299
300def _PairPosFormat1_merge(self, lst, merger):
301	assert allEqual([l.ValueFormat2 == 0 for l in lst if l.PairSet]), "Report bug against fonttools."
302
303	# Merge everything else; makes sure Format is the same.
304	merger.mergeObjects(self, lst,
305			    exclude=('Coverage',
306				     'PairSet', 'PairSetCount',
307				     'ValueFormat1', 'ValueFormat2'))
308
309	empty = ot.PairSet()
310	empty.PairValueRecord = []
311	empty.PairValueCount = 0
312
313	# Align them
314	glyphs, padded = _merge_GlyphOrders(merger.font,
315					    [v.Coverage.glyphs for v in lst],
316					    [v.PairSet for v in lst],
317					    default=empty)
318
319	self.Coverage.glyphs = glyphs
320	self.PairSet = [ot.PairSet() for g in glyphs]
321	self.PairSetCount = len(self.PairSet)
322	for glyph, ps in zip(glyphs, self.PairSet):
323		ps._firstGlyph = glyph
324
325	merger.mergeLists(self.PairSet, padded)
326
327def _ClassDef_invert(self, allGlyphs=None):
328
329	if isinstance(self, dict):
330		classDefs = self
331	else:
332		classDefs = self.classDefs if self and self.classDefs else {}
333	m = max(classDefs.values()) if classDefs else 0
334
335	ret = []
336	for _ in range(m + 1):
337		ret.append(set())
338
339	for k,v in classDefs.items():
340		ret[v].add(k)
341
342	# Class-0 is special.  It's "everything else".
343	if allGlyphs is None:
344		ret[0] = None
345	else:
346		# Limit all classes to glyphs in allGlyphs.
347		# Collect anything without a non-zero class into class=zero.
348		ret[0] = class0 = set(allGlyphs)
349		for s in ret[1:]:
350			s.intersection_update(class0)
351			class0.difference_update(s)
352
353	return ret
354
355def _ClassDef_merge_classify(lst, allGlyphses=None):
356	self = ot.ClassDef()
357	self.classDefs = classDefs = {}
358	allGlyphsesWasNone = allGlyphses is None
359	if allGlyphsesWasNone:
360		allGlyphses = [None] * len(lst)
361
362	classifier = classifyTools.Classifier()
363	for classDef,allGlyphs in zip(lst, allGlyphses):
364		sets = _ClassDef_invert(classDef, allGlyphs)
365		if allGlyphs is None:
366			sets = sets[1:]
367		classifier.update(sets)
368	classes = classifier.getClasses()
369
370	if allGlyphsesWasNone:
371		classes.insert(0, set())
372
373	for i,classSet in enumerate(classes):
374		if i == 0:
375			continue
376		for g in classSet:
377			classDefs[g] = i
378
379	return self, classes
380
381# It's stupid that we need to do this here.  Just need to, to match test
382# expecatation results, since ttx prints out format of ClassDef (and Coverage)
383# even though it should not.
384def _ClassDef_calculate_Format(self, font):
385	fmt = 2
386	ranges = self._getClassRanges(font)
387	if ranges:
388		startGlyph = ranges[0][1]
389		endGlyph = ranges[-1][3]
390		glyphCount = endGlyph - startGlyph + 1
391		if len(ranges) * 3 >= glyphCount + 1:
392			# Format 1 is more compact
393			fmt = 1
394	self.Format = fmt
395
396def _PairPosFormat2_align_matrices(self, lst, font, transparent=False):
397
398	matrices = [l.Class1Record for l in lst]
399
400	# Align first classes
401	self.ClassDef1, classes = _ClassDef_merge_classify([l.ClassDef1 for l in lst], [l.Coverage.glyphs for l in lst])
402	_ClassDef_calculate_Format(self.ClassDef1, font)
403	self.Class1Count = len(classes)
404	new_matrices = []
405	for l,matrix in zip(lst, matrices):
406		nullRow = None
407		coverage = set(l.Coverage.glyphs)
408		classDef1 = l.ClassDef1.classDefs
409		class1Records = []
410		for classSet in classes:
411			exemplarGlyph = next(iter(classSet))
412			if exemplarGlyph not in coverage:
413				# Follow-up to e6125b353e1f54a0280ded5434b8e40d042de69f,
414				# Fixes https://github.com/googlei18n/fontmake/issues/470
415				# Again, revert 8d441779e5afc664960d848f62c7acdbfc71d7b9
416				# when merger becomes selfless.
417				nullRow = None
418				if nullRow is None:
419					nullRow = ot.Class1Record()
420					class2records = nullRow.Class2Record = []
421					# TODO: When merger becomes selfless, revert e6125b353e1f54a0280ded5434b8e40d042de69f
422					for _ in range(l.Class2Count):
423						if transparent:
424							rec2 = None
425						else:
426							rec2 = ot.Class2Record()
427							rec2.Value1 = otBase.ValueRecord(self.ValueFormat1) if self.ValueFormat1 else None
428							rec2.Value2 = otBase.ValueRecord(self.ValueFormat2) if self.ValueFormat2 else None
429						class2records.append(rec2)
430				rec1 = nullRow
431			else:
432				klass = classDef1.get(exemplarGlyph, 0)
433				rec1 = matrix[klass] # TODO handle out-of-range?
434			class1Records.append(rec1)
435		new_matrices.append(class1Records)
436	matrices = new_matrices
437	del new_matrices
438
439	# Align second classes
440	self.ClassDef2, classes = _ClassDef_merge_classify([l.ClassDef2 for l in lst])
441	_ClassDef_calculate_Format(self.ClassDef2, font)
442	self.Class2Count = len(classes)
443	new_matrices = []
444	for l,matrix in zip(lst, matrices):
445		classDef2 = l.ClassDef2.classDefs
446		class1Records = []
447		for rec1old in matrix:
448			oldClass2Records = rec1old.Class2Record
449			rec1new = ot.Class1Record()
450			class2Records = rec1new.Class2Record = []
451			for classSet in classes:
452				if not classSet: # class=0
453					rec2 = oldClass2Records[0]
454				else:
455					exemplarGlyph = next(iter(classSet))
456					klass = classDef2.get(exemplarGlyph, 0)
457					rec2 = oldClass2Records[klass]
458				class2Records.append(rec2)
459			class1Records.append(rec1new)
460		new_matrices.append(class1Records)
461	matrices = new_matrices
462	del new_matrices
463
464	return matrices
465
466def _PairPosFormat2_merge(self, lst, merger):
467	assert allEqual([l.ValueFormat2 == 0 for l in lst if l.Class1Record]), "Report bug against fonttools."
468
469	merger.mergeObjects(self, lst,
470			    exclude=('Coverage',
471				     'ClassDef1', 'Class1Count',
472				     'ClassDef2', 'Class2Count',
473				     'Class1Record',
474				     'ValueFormat1', 'ValueFormat2'))
475
476	# Align coverages
477	glyphs, _ = _merge_GlyphOrders(merger.font,
478				       [v.Coverage.glyphs for v in lst])
479	self.Coverage.glyphs = glyphs
480
481	# Currently, if the coverage of PairPosFormat2 subtables are different,
482	# we do NOT bother walking down the subtable list when filling in new
483	# rows for alignment.  As such, this is only correct if current subtable
484	# is the last subtable in the lookup.  Ensure that.
485	#
486	# Note that our canonicalization process merges trailing PairPosFormat2's,
487	# so in reality this is rare.
488	for l,subtables in zip(lst,merger.lookup_subtables):
489		if l.Coverage.glyphs != glyphs:
490			assert l == subtables[-1]
491
492	matrices = _PairPosFormat2_align_matrices(self, lst, merger.font)
493
494	self.Class1Record = list(matrices[0]) # TODO move merger to be selfless
495	merger.mergeLists(self.Class1Record, matrices)
496
497@AligningMerger.merger(ot.PairPos)
498def merge(merger, self, lst):
499	merger.valueFormat1 = self.ValueFormat1 = reduce(int.__or__, [l.ValueFormat1 for l in lst], 0)
500	merger.valueFormat2 = self.ValueFormat2 = reduce(int.__or__, [l.ValueFormat2 for l in lst], 0)
501
502	if self.Format == 1:
503		_PairPosFormat1_merge(self, lst, merger)
504	elif self.Format == 2:
505		_PairPosFormat2_merge(self, lst, merger)
506	else:
507		assert False
508
509	del merger.valueFormat1, merger.valueFormat2
510
511	# Now examine the list of value records, and update to the union of format values,
512	# as merge might have created new values.
513	vf1 = 0
514	vf2 = 0
515	if self.Format == 1:
516		for pairSet in self.PairSet:
517			for pairValueRecord in pairSet.PairValueRecord:
518				pv1 = pairValueRecord.Value1
519				if pv1 is not None:
520					vf1 |= pv1.getFormat()
521				pv2 = pairValueRecord.Value2
522				if pv2 is not None:
523					vf2 |= pv2.getFormat()
524	elif self.Format == 2:
525		for class1Record in self.Class1Record:
526			for class2Record in class1Record.Class2Record:
527				pv1 = class2Record.Value1
528				if pv1 is not None:
529					vf1 |= pv1.getFormat()
530				pv2 = class2Record.Value2
531				if pv2 is not None:
532					vf2 |= pv2.getFormat()
533	self.ValueFormat1 = vf1
534	self.ValueFormat2 = vf2
535
536def _MarkBasePosFormat1_merge(self, lst, merger, Mark='Mark', Base='Base'):
537	self.ClassCount = max(l.ClassCount for l in lst)
538
539	MarkCoverageGlyphs, MarkRecords = \
540		_merge_GlyphOrders(merger.font,
541				   [getattr(l, Mark+'Coverage').glyphs for l in lst],
542				   [getattr(l, Mark+'Array').MarkRecord for l in lst])
543	getattr(self, Mark+'Coverage').glyphs = MarkCoverageGlyphs
544
545	BaseCoverageGlyphs, BaseRecords = \
546		_merge_GlyphOrders(merger.font,
547				   [getattr(l, Base+'Coverage').glyphs for l in lst],
548				   [getattr(getattr(l, Base+'Array'), Base+'Record') for l in lst])
549	getattr(self, Base+'Coverage').glyphs = BaseCoverageGlyphs
550
551	# MarkArray
552	records = []
553	for g,glyphRecords in zip(MarkCoverageGlyphs, zip(*MarkRecords)):
554		allClasses = [r.Class for r in glyphRecords if r is not None]
555
556		# TODO Right now we require that all marks have same class in
557		# all masters that cover them.  This is not required.
558		#
559		# We can relax that by just requiring that all marks that have
560		# the same class in a master, have the same class in every other
561		# master.  Indeed, if, say, a sparse master only covers one mark,
562		# that mark probably will get class 0, which would possibly be
563		# different from its class in other masters.
564		#
565		# We can even go further and reclassify marks to support any
566		# input.  But, since, it's unlikely that two marks being both,
567		# say, "top" in one master, and one being "top" and other being
568		# "top-right" in another master, we shouldn't do that, as any
569		# failures in that case will probably signify mistakes in the
570		# input masters.
571
572		assert allEqual(allClasses), allClasses
573		if not allClasses:
574			rec = None
575		else:
576			rec = ot.MarkRecord()
577			rec.Class = allClasses[0]
578			allAnchors = [None if r is None else r.MarkAnchor for r in glyphRecords]
579			if allNone(allAnchors):
580				anchor = None
581			else:
582				anchor = ot.Anchor()
583				anchor.Format = 1
584				merger.mergeThings(anchor, allAnchors)
585			rec.MarkAnchor = anchor
586		records.append(rec)
587	array = ot.MarkArray()
588	array.MarkRecord = records
589	array.MarkCount = len(records)
590	setattr(self, Mark+"Array", array)
591
592	# BaseArray
593	records = []
594	for g,glyphRecords in zip(BaseCoverageGlyphs, zip(*BaseRecords)):
595		if allNone(glyphRecords):
596			rec = None
597		else:
598			rec = getattr(ot, Base+'Record')()
599			anchors = []
600			setattr(rec, Base+'Anchor', anchors)
601			glyphAnchors = [[] if r is None else getattr(r, Base+'Anchor')
602					for r in glyphRecords]
603			for l in glyphAnchors:
604				l.extend([None] * (self.ClassCount - len(l)))
605			for allAnchors in zip(*glyphAnchors):
606				if allNone(allAnchors):
607					anchor = None
608				else:
609					anchor = ot.Anchor()
610					anchor.Format = 1
611					merger.mergeThings(anchor, allAnchors)
612				anchors.append(anchor)
613		records.append(rec)
614	array = getattr(ot, Base+'Array')()
615	setattr(array, Base+'Record', records)
616	setattr(array, Base+'Count', len(records))
617	setattr(self, Base+'Array', array)
618
619@AligningMerger.merger(ot.MarkBasePos)
620def merge(merger, self, lst):
621	assert allEqualTo(self.Format, (l.Format for l in lst))
622	if self.Format == 1:
623		_MarkBasePosFormat1_merge(self, lst, merger)
624	else:
625		assert False
626
627@AligningMerger.merger(ot.MarkMarkPos)
628def merge(merger, self, lst):
629	assert allEqualTo(self.Format, (l.Format for l in lst))
630	if self.Format == 1:
631		_MarkBasePosFormat1_merge(self, lst, merger, 'Mark1', 'Mark2')
632	else:
633		assert False
634
635
636def _PairSet_flatten(lst, font):
637	self = ot.PairSet()
638	self.Coverage = ot.Coverage()
639	self.Coverage.Format = 1
640
641	# Align them
642	glyphs, padded = _merge_GlyphOrders(font,
643				[[v.SecondGlyph for v in vs.PairValueRecord] for vs in lst],
644				[vs.PairValueRecord for vs in lst])
645
646	self.Coverage.glyphs = glyphs
647	self.PairValueRecord = pvrs = []
648	for values in zip(*padded):
649		for v in values:
650			if v is not None:
651				pvrs.append(v)
652				break
653		else:
654			assert False
655	self.PairValueCount = len(self.PairValueRecord)
656
657	return self
658
659def _Lookup_PairPosFormat1_subtables_flatten(lst, font):
660	assert allEqual([l.ValueFormat2 == 0 for l in lst if l.PairSet]), "Report bug against fonttools."
661
662	self = ot.PairPos()
663	self.Format = 1
664	self.Coverage = ot.Coverage()
665	self.Coverage.Format = 1
666	self.ValueFormat1 = reduce(int.__or__, [l.ValueFormat1 for l in lst], 0)
667	self.ValueFormat2 = reduce(int.__or__, [l.ValueFormat2 for l in lst], 0)
668
669	# Align them
670	glyphs, padded = _merge_GlyphOrders(font,
671					    [v.Coverage.glyphs for v in lst],
672					    [v.PairSet for v in lst])
673
674	self.Coverage.glyphs = glyphs
675	self.PairSet = [_PairSet_flatten([v for v in values if v is not None], font)
676		        for values in zip(*padded)]
677	self.PairSetCount = len(self.PairSet)
678	return self
679
680def _Lookup_PairPosFormat2_subtables_flatten(lst, font):
681	assert allEqual([l.ValueFormat2 == 0 for l in lst if l.Class1Record]), "Report bug against fonttools."
682
683	self = ot.PairPos()
684	self.Format = 2
685	self.Coverage = ot.Coverage()
686	self.Coverage.Format = 1
687	self.ValueFormat1 = reduce(int.__or__, [l.ValueFormat1 for l in lst], 0)
688	self.ValueFormat2 = reduce(int.__or__, [l.ValueFormat2 for l in lst], 0)
689
690	# Align them
691	glyphs, _ = _merge_GlyphOrders(font,
692				       [v.Coverage.glyphs for v in lst])
693	self.Coverage.glyphs = glyphs
694
695	matrices = _PairPosFormat2_align_matrices(self, lst, font, transparent=True)
696
697	matrix = self.Class1Record = []
698	for rows in zip(*matrices):
699		row = ot.Class1Record()
700		matrix.append(row)
701		row.Class2Record = []
702		row = row.Class2Record
703		for cols in zip(*list(r.Class2Record for r in rows)):
704			col = next(iter(c for c in cols if c is not None))
705			row.append(col)
706
707	return self
708
709def _Lookup_PairPos_subtables_canonicalize(lst, font):
710	"""Merge multiple Format1 subtables at the beginning of lst,
711	and merge multiple consecutive Format2 subtables that have the same
712	Class2 (ie. were split because of offset overflows).  Returns new list."""
713	lst = list(lst)
714
715	l = len(lst)
716	i = 0
717	while i < l and lst[i].Format == 1:
718		i += 1
719	lst[:i] = [_Lookup_PairPosFormat1_subtables_flatten(lst[:i], font)]
720
721	l = len(lst)
722	i = l
723	while i > 0 and lst[i - 1].Format == 2:
724		i -= 1
725	lst[i:] = [_Lookup_PairPosFormat2_subtables_flatten(lst[i:], font)]
726
727	return lst
728
729@AligningMerger.merger(ot.Lookup)
730def merge(merger, self, lst):
731	subtables = merger.lookup_subtables = [l.SubTable for l in lst]
732
733	# Remove Extension subtables
734	for l,sts in list(zip(lst,subtables))+[(self,self.SubTable)]:
735		if not sts:
736			continue
737		if sts[0].__class__.__name__.startswith('Extension'):
738			assert allEqual([st.__class__ for st in sts])
739			assert allEqual([st.ExtensionLookupType for st in sts])
740			l.LookupType = sts[0].ExtensionLookupType
741			new_sts = [st.ExtSubTable for st in sts]
742			del sts[:]
743			sts.extend(new_sts)
744
745	isPairPos = self.SubTable and isinstance(self.SubTable[0], ot.PairPos)
746
747	if isPairPos:
748
749		# AFDKO and feaLib sometimes generate two Format1 subtables instead of one.
750		# Merge those before continuing.
751		# https://github.com/fonttools/fonttools/issues/719
752		self.SubTable = _Lookup_PairPos_subtables_canonicalize(self.SubTable, merger.font)
753		subtables = merger.lookup_subtables = [_Lookup_PairPos_subtables_canonicalize(st, merger.font) for st in subtables]
754
755	merger.mergeLists(self.SubTable, subtables)
756	self.SubTableCount = len(self.SubTable)
757
758	if isPairPos:
759		# If format-1 subtable created during canonicalization is empty, remove it.
760		assert len(self.SubTable) >= 1 and self.SubTable[0].Format == 1
761		if not self.SubTable[0].Coverage.glyphs:
762			self.SubTable.pop(0)
763			self.SubTableCount -= 1
764
765		# If format-2 subtable created during canonicalization is empty, remove it.
766		assert len(self.SubTable) >= 1 and self.SubTable[-1].Format == 2
767		if not self.SubTable[-1].Coverage.glyphs:
768			self.SubTable.pop(-1)
769			self.SubTableCount -= 1
770
771	merger.mergeObjects(self, lst, exclude=['SubTable', 'SubTableCount'])
772
773	del merger.lookup_subtables
774
775
776#
777# InstancerMerger
778#
779
780class InstancerMerger(AligningMerger):
781	"""A merger that takes multiple master fonts, and instantiates
782	an instance."""
783
784	def __init__(self, font, model, location):
785		Merger.__init__(self, font)
786		self.model = model
787		self.location = location
788		self.scalars = model.getScalars(location)
789
790@InstancerMerger.merger(ot.CaretValue)
791def merge(merger, self, lst):
792	assert self.Format == 1
793	Coords = [a.Coordinate for a in lst]
794	model = merger.model
795	scalars = merger.scalars
796	self.Coordinate = otRound(model.interpolateFromMastersAndScalars(Coords, scalars))
797
798@InstancerMerger.merger(ot.Anchor)
799def merge(merger, self, lst):
800	assert self.Format == 1
801	XCoords = [a.XCoordinate for a in lst]
802	YCoords = [a.YCoordinate for a in lst]
803	model = merger.model
804	scalars = merger.scalars
805	self.XCoordinate = otRound(model.interpolateFromMastersAndScalars(XCoords, scalars))
806	self.YCoordinate = otRound(model.interpolateFromMastersAndScalars(YCoords, scalars))
807
808@InstancerMerger.merger(otBase.ValueRecord)
809def merge(merger, self, lst):
810	model = merger.model
811	scalars = merger.scalars
812	# TODO Handle differing valueformats
813	for name, tableName in [('XAdvance','XAdvDevice'),
814				('YAdvance','YAdvDevice'),
815				('XPlacement','XPlaDevice'),
816				('YPlacement','YPlaDevice')]:
817
818		assert not hasattr(self, tableName)
819
820		if hasattr(self, name):
821			values = [getattr(a, name, 0) for a in lst]
822			value = otRound(model.interpolateFromMastersAndScalars(values, scalars))
823			setattr(self, name, value)
824
825
826#
827# MutatorMerger
828#
829
830class MutatorMerger(AligningMerger):
831	"""A merger that takes a variable font, and instantiates
832	an instance.  While there's no "merging" to be done per se,
833	the operation can benefit from many operations that the
834	aligning merger does."""
835
836	def __init__(self, font, location):
837		Merger.__init__(self, font)
838		self.location = location
839
840		store = None
841		if 'GDEF' in font:
842			gdef = font['GDEF'].table
843			if gdef.Version >= 0x00010003:
844				store = gdef.VarStore
845
846		self.instancer = VarStoreInstancer(store, font['fvar'].axes, location)
847
848@MutatorMerger.merger(ot.CaretValue)
849def merge(merger, self, lst):
850
851	# Hack till we become selfless.
852	self.__dict__ = lst[0].__dict__.copy()
853
854	if self.Format != 3:
855		return
856
857	instancer = merger.instancer
858	dev = self.DeviceTable
859	del self.DeviceTable
860	if dev:
861		assert dev.DeltaFormat == 0x8000
862		varidx = (dev.StartSize << 16) + dev.EndSize
863		delta = otRound(instancer[varidx])
864		self.Coordinate  += delta
865
866	self.Format = 1
867
868@MutatorMerger.merger(ot.Anchor)
869def merge(merger, self, lst):
870
871	# Hack till we become selfless.
872	self.__dict__ = lst[0].__dict__.copy()
873
874	if self.Format != 3:
875		return
876
877	instancer = merger.instancer
878	for v in "XY":
879		tableName = v+'DeviceTable'
880		if not hasattr(self, tableName):
881			continue
882		dev = getattr(self, tableName)
883		delattr(self, tableName)
884		if dev is None:
885			continue
886
887		assert dev.DeltaFormat == 0x8000
888		varidx = (dev.StartSize << 16) + dev.EndSize
889		delta = otRound(instancer[varidx])
890
891		attr = v+'Coordinate'
892		setattr(self, attr, getattr(self, attr) + delta)
893
894	self.Format = 1
895
896@MutatorMerger.merger(otBase.ValueRecord)
897def merge(merger, self, lst):
898
899	# Hack till we become selfless.
900	self.__dict__ = lst[0].__dict__.copy()
901
902	instancer = merger.instancer
903	# TODO Handle differing valueformats
904	for name, tableName in [('XAdvance','XAdvDevice'),
905				('YAdvance','YAdvDevice'),
906				('XPlacement','XPlaDevice'),
907				('YPlacement','YPlaDevice')]:
908
909		if not hasattr(self, tableName):
910			continue
911		dev = getattr(self, tableName)
912		delattr(self, tableName)
913		if dev is None:
914			continue
915
916		assert dev.DeltaFormat == 0x8000
917		varidx = (dev.StartSize << 16) + dev.EndSize
918		delta = otRound(instancer[varidx])
919
920		setattr(self, name, getattr(self, name) + delta)
921
922
923#
924# VariationMerger
925#
926
927class VariationMerger(AligningMerger):
928	"""A merger that takes multiple master fonts, and builds a
929	variable font."""
930
931	def __init__(self, model, axisTags, font):
932		Merger.__init__(self, font)
933		self.store_builder = varStore.OnlineVarStoreBuilder(axisTags)
934		self.setModel(model)
935
936	def setModel(self, model):
937		self.model = model
938		self.store_builder.setModel(model)
939
940	def mergeThings(self, out, lst):
941		masterModel = None
942		if None in lst:
943			if allNone(lst):
944				assert out is None, (out, lst)
945				return
946			masterModel = self.model
947			model, lst = masterModel.getSubModel(lst)
948			self.setModel(model)
949
950		super(VariationMerger, self).mergeThings(out, lst)
951
952		if masterModel:
953			self.setModel(masterModel)
954
955
956def buildVarDevTable(store_builder, master_values):
957	if allEqual(master_values):
958		return master_values[0], None
959	base, varIdx = store_builder.storeMasters(master_values)
960	return base, builder.buildVarDevTable(varIdx)
961
962@VariationMerger.merger(ot.CaretValue)
963def merge(merger, self, lst):
964	assert self.Format == 1
965	self.Coordinate, DeviceTable = buildVarDevTable(merger.store_builder, [a.Coordinate for a in lst])
966	if DeviceTable:
967		self.Format = 3
968		self.DeviceTable = DeviceTable
969
970@VariationMerger.merger(ot.Anchor)
971def merge(merger, self, lst):
972	assert self.Format == 1
973	self.XCoordinate, XDeviceTable = buildVarDevTable(merger.store_builder, [a.XCoordinate for a in lst])
974	self.YCoordinate, YDeviceTable = buildVarDevTable(merger.store_builder, [a.YCoordinate for a in lst])
975	if XDeviceTable or YDeviceTable:
976		self.Format = 3
977		self.XDeviceTable = XDeviceTable
978		self.YDeviceTable = YDeviceTable
979
980@VariationMerger.merger(otBase.ValueRecord)
981def merge(merger, self, lst):
982	for name, tableName in [('XAdvance','XAdvDevice'),
983				('YAdvance','YAdvDevice'),
984				('XPlacement','XPlaDevice'),
985				('YPlacement','YPlaDevice')]:
986
987		if hasattr(self, name):
988			value, deviceTable = buildVarDevTable(merger.store_builder,
989							      [getattr(a, name, 0) for a in lst])
990			setattr(self, name, value)
991			if deviceTable:
992				setattr(self, tableName, deviceTable)
993