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