• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from fontTools.misc.py23 import bytechr, byteord, strjoin
2from fontTools.misc import sstruct
3from . import DefaultTable
4import array
5from collections.abc import Mapping
6
7hdmxHeaderFormat = """
8	>   # big endian!
9	version:	H
10	numRecords:	H
11	recordSize:	l
12"""
13
14class _GlyphnamedList(Mapping):
15
16	def __init__(self, reverseGlyphOrder, data):
17		self._array = data
18		self._map = dict(reverseGlyphOrder)
19
20	def __getitem__(self, k):
21		return self._array[self._map[k]]
22
23	def __len__(self):
24		return len(self._map)
25
26	def __iter__(self):
27		return iter(self._map)
28
29	def keys(self):
30		return self._map.keys()
31
32class table__h_d_m_x(DefaultTable.DefaultTable):
33
34	def decompile(self, data, ttFont):
35		numGlyphs = ttFont['maxp'].numGlyphs
36		glyphOrder = ttFont.getGlyphOrder()
37		dummy, data = sstruct.unpack2(hdmxHeaderFormat, data, self)
38		self.hdmx = {}
39		for i in range(self.numRecords):
40			ppem = byteord(data[0])
41			maxSize = byteord(data[1])
42			widths = _GlyphnamedList(ttFont.getReverseGlyphMap(), array.array("B", data[2:2+numGlyphs]))
43			self.hdmx[ppem] = widths
44			data = data[self.recordSize:]
45		assert len(data) == 0, "too much hdmx data"
46
47	def compile(self, ttFont):
48		self.version = 0
49		numGlyphs = ttFont['maxp'].numGlyphs
50		glyphOrder = ttFont.getGlyphOrder()
51		self.recordSize = 4 * ((2 + numGlyphs + 3) // 4)
52		pad = (self.recordSize - 2 - numGlyphs) * b"\0"
53		self.numRecords = len(self.hdmx)
54		data = sstruct.pack(hdmxHeaderFormat, self)
55		items = sorted(self.hdmx.items())
56		for ppem, widths in items:
57			data = data + bytechr(ppem) + bytechr(max(widths.values()))
58			for glyphID in range(len(glyphOrder)):
59				width = widths[glyphOrder[glyphID]]
60				data = data + bytechr(width)
61			data = data + pad
62		return data
63
64	def toXML(self, writer, ttFont):
65		writer.begintag("hdmxData")
66		writer.newline()
67		ppems = sorted(self.hdmx.keys())
68		records = []
69		format = ""
70		for ppem in ppems:
71			widths = self.hdmx[ppem]
72			records.append(widths)
73			format = format + "%4d"
74		glyphNames = ttFont.getGlyphOrder()[:]
75		glyphNames.sort()
76		maxNameLen = max(map(len, glyphNames))
77		format = "%" + repr(maxNameLen) + 's:' + format + ' ;'
78		writer.write(format % (("ppem",) + tuple(ppems)))
79		writer.newline()
80		writer.newline()
81		for glyphName in glyphNames:
82			row = []
83			for ppem in ppems:
84				widths = self.hdmx[ppem]
85				row.append(widths[glyphName])
86			if ";" in glyphName:
87				glyphName = "\\x3b".join(glyphName.split(";"))
88			writer.write(format % ((glyphName,) + tuple(row)))
89			writer.newline()
90		writer.endtag("hdmxData")
91		writer.newline()
92
93	def fromXML(self, name, attrs, content, ttFont):
94		if name != "hdmxData":
95			return
96		content = strjoin(content)
97		lines = content.split(";")
98		topRow = lines[0].split()
99		assert topRow[0] == "ppem:", "illegal hdmx format"
100		ppems = list(map(int, topRow[1:]))
101		self.hdmx = hdmx = {}
102		for ppem in ppems:
103			hdmx[ppem] = {}
104		lines = (line.split() for line in lines[1:])
105		for line in lines:
106			if not line:
107				continue
108			assert line[0][-1] == ":", "illegal hdmx format"
109			glyphName = line[0][:-1]
110			if "\\" in glyphName:
111				from fontTools.misc.textTools import safeEval
112				glyphName = safeEval('"""' + glyphName + '"""')
113			line = list(map(int, line[1:]))
114			assert len(line) == len(ppems), "illegal hdmx format"
115			for i in range(len(ppems)):
116				hdmx[ppems[i]][glyphName] = line[i]
117