• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from fontTools.misc import sstruct
2from fontTools.misc.textTools import bytechr, byteord, strjoin
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
14
15class _GlyphnamedList(Mapping):
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
32
33class table__h_d_m_x(DefaultTable.DefaultTable):
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(
43                ttFont.getReverseGlyphMap(), array.array("B", data[2 : 2 + numGlyphs])
44            )
45            self.hdmx[ppem] = widths
46            data = data[self.recordSize :]
47        assert len(data) == 0, "too much hdmx data"
48
49    def compile(self, ttFont):
50        self.version = 0
51        numGlyphs = ttFont["maxp"].numGlyphs
52        glyphOrder = ttFont.getGlyphOrder()
53        self.recordSize = 4 * ((2 + numGlyphs + 3) // 4)
54        pad = (self.recordSize - 2 - numGlyphs) * b"\0"
55        self.numRecords = len(self.hdmx)
56        data = sstruct.pack(hdmxHeaderFormat, self)
57        items = sorted(self.hdmx.items())
58        for ppem, widths in items:
59            data = data + bytechr(ppem) + bytechr(max(widths.values()))
60            for glyphID in range(len(glyphOrder)):
61                width = widths[glyphOrder[glyphID]]
62                data = data + bytechr(width)
63            data = data + pad
64        return data
65
66    def toXML(self, writer, ttFont):
67        writer.begintag("hdmxData")
68        writer.newline()
69        ppems = sorted(self.hdmx.keys())
70        records = []
71        format = ""
72        for ppem in ppems:
73            widths = self.hdmx[ppem]
74            records.append(widths)
75            format = format + "%4d"
76        glyphNames = ttFont.getGlyphOrder()[:]
77        glyphNames.sort()
78        maxNameLen = max(map(len, glyphNames))
79        format = "%" + repr(maxNameLen) + "s:" + format + " ;"
80        writer.write(format % (("ppem",) + tuple(ppems)))
81        writer.newline()
82        writer.newline()
83        for glyphName in glyphNames:
84            row = []
85            for ppem in ppems:
86                widths = self.hdmx[ppem]
87                row.append(widths[glyphName])
88            if ";" in glyphName:
89                glyphName = "\\x3b".join(glyphName.split(";"))
90            writer.write(format % ((glyphName,) + tuple(row)))
91            writer.newline()
92        writer.endtag("hdmxData")
93        writer.newline()
94
95    def fromXML(self, name, attrs, content, ttFont):
96        if name != "hdmxData":
97            return
98        content = strjoin(content)
99        lines = content.split(";")
100        topRow = lines[0].split()
101        assert topRow[0] == "ppem:", "illegal hdmx format"
102        ppems = list(map(int, topRow[1:]))
103        self.hdmx = hdmx = {}
104        for ppem in ppems:
105            hdmx[ppem] = {}
106        lines = (line.split() for line in lines[1:])
107        for line in lines:
108            if not line:
109                continue
110            assert line[0][-1] == ":", "illegal hdmx format"
111            glyphName = line[0][:-1]
112            if "\\" in glyphName:
113                from fontTools.misc.textTools import safeEval
114
115                glyphName = safeEval('"""' + glyphName + '"""')
116            line = list(map(int, line[1:]))
117            assert len(line) == len(ppems), "illegal hdmx format"
118            for i in range(len(ppems)):
119                hdmx[ppems[i]][glyphName] = line[i]
120