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