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