_h_m_t_x.py revision 4c2f1b6a2c2e4d85d4987606795097d592b1586a
19be387c94ff8199f8031b7f11f06c52cce5ccf6djvrimport sys
27842e56b97ce677b83bdab09cda48bc2d89ac75aJustimport DefaultTable
3035bc7da2318f0dcacecba2e1e24c0a4bf3cf80cBehdad Esfahbodimport array
47842e56b97ce677b83bdab09cda48bc2d89ac75aJustfrom fontTools import ttLib
57842e56b97ce677b83bdab09cda48bc2d89ac75aJustfrom fontTools.misc.textTools import safeEval
6d3d7250fc3147b6333e365e5be4ff29aa92ee506pabsimport warnings
77842e56b97ce677b83bdab09cda48bc2d89ac75aJust
87842e56b97ce677b83bdab09cda48bc2d89ac75aJust
97842e56b97ce677b83bdab09cda48bc2d89ac75aJustclass table__h_m_t_x(DefaultTable.DefaultTable):
107842e56b97ce677b83bdab09cda48bc2d89ac75aJust
117842e56b97ce677b83bdab09cda48bc2d89ac75aJust	headerTag = 'hhea'
127842e56b97ce677b83bdab09cda48bc2d89ac75aJust	advanceName = 'width'
137842e56b97ce677b83bdab09cda48bc2d89ac75aJust	sideBearingName = 'lsb'
147842e56b97ce677b83bdab09cda48bc2d89ac75aJust	numberOfMetricsName = 'numberOfHMetrics'
157842e56b97ce677b83bdab09cda48bc2d89ac75aJust
167842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def decompile(self, data, ttFont):
17035bc7da2318f0dcacecba2e1e24c0a4bf3cf80cBehdad Esfahbod		numGlyphs = ttFont['maxp'].numGlyphs
187842e56b97ce677b83bdab09cda48bc2d89ac75aJust		numberOfMetrics = int(getattr(ttFont[self.headerTag], self.numberOfMetricsName))
19035bc7da2318f0dcacecba2e1e24c0a4bf3cf80cBehdad Esfahbod		if numberOfMetrics > numGlyphs:
20035bc7da2318f0dcacecba2e1e24c0a4bf3cf80cBehdad Esfahbod			numberOfMetrics = numGlyphs # We warn later.
21035bc7da2318f0dcacecba2e1e24c0a4bf3cf80cBehdad Esfahbod		# Note: advanceWidth is unsigned, but we read/write as signed.
22035bc7da2318f0dcacecba2e1e24c0a4bf3cf80cBehdad Esfahbod		metrics = array.array("h", data[:4 * numberOfMetrics])
239be387c94ff8199f8031b7f11f06c52cce5ccf6djvr		if sys.byteorder <> "big":
24035bc7da2318f0dcacecba2e1e24c0a4bf3cf80cBehdad Esfahbod			metrics.byteswap()
257842e56b97ce677b83bdab09cda48bc2d89ac75aJust		data = data[4 * numberOfMetrics:]
26035bc7da2318f0dcacecba2e1e24c0a4bf3cf80cBehdad Esfahbod		numberOfSideBearings = numGlyphs - numberOfMetrics
27035bc7da2318f0dcacecba2e1e24c0a4bf3cf80cBehdad Esfahbod		sideBearings = array.array("h", data[:2 * numberOfSideBearings])
28035bc7da2318f0dcacecba2e1e24c0a4bf3cf80cBehdad Esfahbod		data = data[2 * numberOfSideBearings:]
29035bc7da2318f0dcacecba2e1e24c0a4bf3cf80cBehdad Esfahbod
30035bc7da2318f0dcacecba2e1e24c0a4bf3cf80cBehdad Esfahbod		if sys.byteorder <> "big":
31035bc7da2318f0dcacecba2e1e24c0a4bf3cf80cBehdad Esfahbod			sideBearings.byteswap()
327842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if data:
33731e4377e13b91d906d78f6e1e8c7ca2097c71e8Just			sys.stderr.write("too much data for hmtx/vmtx table\n")
347842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.metrics = {}
35035bc7da2318f0dcacecba2e1e24c0a4bf3cf80cBehdad Esfahbod		for i in range(numberOfMetrics):
367842e56b97ce677b83bdab09cda48bc2d89ac75aJust			glyphName = ttFont.getGlyphName(i)
37035bc7da2318f0dcacecba2e1e24c0a4bf3cf80cBehdad Esfahbod			self.metrics[glyphName] = list(metrics[i*2:i*2+2])
38035bc7da2318f0dcacecba2e1e24c0a4bf3cf80cBehdad Esfahbod		lastAdvance = metrics[-2]
39035bc7da2318f0dcacecba2e1e24c0a4bf3cf80cBehdad Esfahbod		for i in range(numberOfSideBearings):
40035bc7da2318f0dcacecba2e1e24c0a4bf3cf80cBehdad Esfahbod			glyphName = ttFont.getGlyphName(i + numberOfMetrics)
41035bc7da2318f0dcacecba2e1e24c0a4bf3cf80cBehdad Esfahbod			self.metrics[glyphName] = [lastAdvance, sideBearings[i]]
427842e56b97ce677b83bdab09cda48bc2d89ac75aJust
437842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def compile(self, ttFont):
447842e56b97ce677b83bdab09cda48bc2d89ac75aJust		metrics = []
457842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for glyphName in ttFont.getGlyphOrder():
467842e56b97ce677b83bdab09cda48bc2d89ac75aJust			metrics.append(self.metrics[glyphName])
477842e56b97ce677b83bdab09cda48bc2d89ac75aJust		lastAdvance = metrics[-1][0]
487842e56b97ce677b83bdab09cda48bc2d89ac75aJust		lastIndex = len(metrics)
497842e56b97ce677b83bdab09cda48bc2d89ac75aJust		while metrics[lastIndex-2][0] == lastAdvance:
50035bc7da2318f0dcacecba2e1e24c0a4bf3cf80cBehdad Esfahbod			lastIndex -= 1
511288f8ad41b183ccdc3a8657b751ce53e03953a7jvr			if lastIndex <= 1:
52ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr				# all advances are equal
531288f8ad41b183ccdc3a8657b751ce53e03953a7jvr				lastIndex = 1
54ca4c45681ef2ea9290c6845f8bf61dff281fc5c4jvr				break
557842e56b97ce677b83bdab09cda48bc2d89ac75aJust		additionalMetrics = metrics[lastIndex:]
56035bc7da2318f0dcacecba2e1e24c0a4bf3cf80cBehdad Esfahbod		additionalMetrics = [sb for advance, sb in additionalMetrics]
577842e56b97ce677b83bdab09cda48bc2d89ac75aJust		metrics = metrics[:lastIndex]
587842e56b97ce677b83bdab09cda48bc2d89ac75aJust		setattr(ttFont[self.headerTag], self.numberOfMetricsName, len(metrics))
597842e56b97ce677b83bdab09cda48bc2d89ac75aJust
604c2f1b6a2c2e4d85d4987606795097d592b1586aBehdad Esfahbod		allMetrics = []
614c2f1b6a2c2e4d85d4987606795097d592b1586aBehdad Esfahbod		for item in metrics:
624c2f1b6a2c2e4d85d4987606795097d592b1586aBehdad Esfahbod			allMetrics.extend(item)
634c2f1b6a2c2e4d85d4987606795097d592b1586aBehdad Esfahbod		allMetrics = array.array("h", allMetrics)
649be387c94ff8199f8031b7f11f06c52cce5ccf6djvr		if sys.byteorder <> "big":
654c2f1b6a2c2e4d85d4987606795097d592b1586aBehdad Esfahbod			allMetrics.byteswap()
664c2f1b6a2c2e4d85d4987606795097d592b1586aBehdad Esfahbod		data = allMetrics.tostring()
677842e56b97ce677b83bdab09cda48bc2d89ac75aJust
68035bc7da2318f0dcacecba2e1e24c0a4bf3cf80cBehdad Esfahbod		additionalMetrics = array.array("h", additionalMetrics)
699be387c94ff8199f8031b7f11f06c52cce5ccf6djvr		if sys.byteorder <> "big":
70035bc7da2318f0dcacecba2e1e24c0a4bf3cf80cBehdad Esfahbod			additionalMetrics.byteswap()
717842e56b97ce677b83bdab09cda48bc2d89ac75aJust		data = data + additionalMetrics.tostring()
727842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return data
737842e56b97ce677b83bdab09cda48bc2d89ac75aJust
747842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def toXML(self, writer, ttFont):
757842e56b97ce677b83bdab09cda48bc2d89ac75aJust		names = self.metrics.keys()
767842e56b97ce677b83bdab09cda48bc2d89ac75aJust		names.sort()
777842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for glyphName in names:
787842e56b97ce677b83bdab09cda48bc2d89ac75aJust			advance, sb = self.metrics[glyphName]
797842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.simpletag("mtx", [
807842e56b97ce677b83bdab09cda48bc2d89ac75aJust					("name", glyphName),
817842e56b97ce677b83bdab09cda48bc2d89ac75aJust					(self.advanceName, advance),
827842e56b97ce677b83bdab09cda48bc2d89ac75aJust					(self.sideBearingName, sb),
837842e56b97ce677b83bdab09cda48bc2d89ac75aJust					])
847842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.newline()
857842e56b97ce677b83bdab09cda48bc2d89ac75aJust
867842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def fromXML(self, (name, attrs, content), ttFont):
877842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if not hasattr(self, "metrics"):
887842e56b97ce677b83bdab09cda48bc2d89ac75aJust			self.metrics = {}
897842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if name == "mtx":
907842e56b97ce677b83bdab09cda48bc2d89ac75aJust			self.metrics[attrs["name"]] = [safeEval(attrs[self.advanceName]),
917842e56b97ce677b83bdab09cda48bc2d89ac75aJust					safeEval(attrs[self.sideBearingName])]
927842e56b97ce677b83bdab09cda48bc2d89ac75aJust
937842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def __getitem__(self, glyphName):
947842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return self.metrics[glyphName]
957842e56b97ce677b83bdab09cda48bc2d89ac75aJust
967842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def __setitem__(self, glyphName, (advance, sb)):
977842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.metrics[glyphName] = advance, sb
987842e56b97ce677b83bdab09cda48bc2d89ac75aJust
99