_h_m_t_x.py revision 3de0e58f294263cd5d0b18aab95e267e8abc2689
1import sys
2import DefaultTable
3import numpy
4from fontTools import ttLib
5from fontTools.misc.textTools import safeEval
6import warnings
7
8
9class table__h_m_t_x(DefaultTable.DefaultTable):
10
11	headerTag = 'hhea'
12	advanceName = 'width'
13	sideBearingName = 'lsb'
14	numberOfMetricsName = 'numberOfHMetrics'
15
16	def decompile(self, data, ttFont):
17		numberOfMetrics = int(getattr(ttFont[self.headerTag], self.numberOfMetricsName))
18		metrics = numpy.fromstring(data[:4 * numberOfMetrics],
19				numpy.int16)
20		if sys.byteorder <> "big":
21			metrics = metrics.byteswap()
22		metrics.shape = (numberOfMetrics, 2)
23		data = data[4 * numberOfMetrics:]
24		numberOfSideBearings = ttFont['maxp'].numGlyphs - numberOfMetrics
25		numberOfSideBearings = int(numberOfSideBearings)
26		if numberOfSideBearings:
27			assert numberOfSideBearings > 0, "bad hmtx/vmtx table"
28			lastAdvance = metrics[-1][0]
29			advances = numpy.array([lastAdvance] * numberOfSideBearings,
30					numpy.int16)
31			sideBearings = numpy.fromstring(data[:2 * numberOfSideBearings],
32					numpy.int16)
33			if sys.byteorder <> "big":
34				sideBearings = sideBearings.byteswap()
35			data = data[2 * numberOfSideBearings:]
36			if len(advances) and len(sideBearings):
37				additionalMetrics = numpy.array([advances, sideBearings], numpy.int16)
38				metrics = numpy.concatenate((metrics, numpy.transpose(additionalMetrics)))
39			else:
40				warnings.warn('Unable to include additional metrics')
41		if data:
42			sys.stderr.write("too much data for hmtx/vmtx table\n")
43		metrics = metrics.tolist()
44		self.metrics = {}
45		for i in range(len(metrics)):
46			glyphName = ttFont.getGlyphName(i)
47			self.metrics[glyphName] = metrics[i]
48
49	def compile(self, ttFont):
50		metrics = []
51		for glyphName in ttFont.getGlyphOrder():
52			metrics.append(self.metrics[glyphName])
53		lastAdvance = metrics[-1][0]
54		lastIndex = len(metrics)
55		while metrics[lastIndex-2][0] == lastAdvance:
56			lastIndex = lastIndex - 1
57			if lastIndex <= 1:
58				# all advances are equal
59				lastIndex = 1
60				break
61		additionalMetrics = metrics[lastIndex:]
62		additionalMetrics = map(lambda (advance, sb): sb, additionalMetrics)
63		metrics = metrics[:lastIndex]
64		setattr(ttFont[self.headerTag], self.numberOfMetricsName, len(metrics))
65
66		metrics = numpy.array(metrics, numpy.int16)
67		if sys.byteorder <> "big":
68			metrics = metrics.byteswap()
69		data = metrics.tostring()
70
71		additionalMetrics = numpy.array(additionalMetrics, numpy.int16)
72		if sys.byteorder <> "big":
73			additionalMetrics = additionalMetrics.byteswap()
74		data = data + additionalMetrics.tostring()
75		return data
76
77	def toXML(self, writer, ttFont):
78		names = self.metrics.keys()
79		names.sort()
80		for glyphName in names:
81			advance, sb = self.metrics[glyphName]
82			writer.simpletag("mtx", [
83					("name", glyphName),
84					(self.advanceName, advance),
85					(self.sideBearingName, sb),
86					])
87			writer.newline()
88
89	def fromXML(self, (name, attrs, content), ttFont):
90		if not hasattr(self, "metrics"):
91			self.metrics = {}
92		if name == "mtx":
93			self.metrics[attrs["name"]] = [safeEval(attrs[self.advanceName]),
94					safeEval(attrs[self.sideBearingName])]
95
96	def __getitem__(self, glyphName):
97		return self.metrics[glyphName]
98
99	def __setitem__(self, glyphName, (advance, sb)):
100		self.metrics[glyphName] = advance, sb
101
102