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