aboutsummaryrefslogtreecommitdiff
path: root/Lib/fontTools/ttLib/tables/_h_d_m_x.py
blob: b6d56a7e70823e14d790361a844df2c6553ff35f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
from fontTools.misc import sstruct
from fontTools.misc.textTools import bytechr, byteord, strjoin
from . import DefaultTable
import array
from collections.abc import Mapping

hdmxHeaderFormat = """
	>   # big endian!
	version:	H
	numRecords:	H
	recordSize:	l
"""


class _GlyphnamedList(Mapping):
    def __init__(self, reverseGlyphOrder, data):
        self._array = data
        self._map = dict(reverseGlyphOrder)

    def __getitem__(self, k):
        return self._array[self._map[k]]

    def __len__(self):
        return len(self._map)

    def __iter__(self):
        return iter(self._map)

    def keys(self):
        return self._map.keys()


class table__h_d_m_x(DefaultTable.DefaultTable):
    def decompile(self, data, ttFont):
        numGlyphs = ttFont["maxp"].numGlyphs
        glyphOrder = ttFont.getGlyphOrder()
        dummy, data = sstruct.unpack2(hdmxHeaderFormat, data, self)
        self.hdmx = {}
        for i in range(self.numRecords):
            ppem = byteord(data[0])
            maxSize = byteord(data[1])
            widths = _GlyphnamedList(
                ttFont.getReverseGlyphMap(), array.array("B", data[2 : 2 + numGlyphs])
            )
            self.hdmx[ppem] = widths
            data = data[self.recordSize :]
        assert len(data) == 0, "too much hdmx data"

    def compile(self, ttFont):
        self.version = 0
        numGlyphs = ttFont["maxp"].numGlyphs
        glyphOrder = ttFont.getGlyphOrder()
        self.recordSize = 4 * ((2 + numGlyphs + 3) // 4)
        pad = (self.recordSize - 2 - numGlyphs) * b"\0"
        self.numRecords = len(self.hdmx)
        data = sstruct.pack(hdmxHeaderFormat, self)
        items = sorted(self.hdmx.items())
        for ppem, widths in items:
            data = data + bytechr(ppem) + bytechr(max(widths.values()))
            for glyphID in range(len(glyphOrder)):
                width = widths[glyphOrder[glyphID]]
                data = data + bytechr(width)
            data = data + pad
        return data

    def toXML(self, writer, ttFont):
        writer.begintag("hdmxData")
        writer.newline()
        ppems = sorted(self.hdmx.keys())
        records = []
        format = ""
        for ppem in ppems:
            widths = self.hdmx[ppem]
            records.append(widths)
            format = format + "%4d"
        glyphNames = ttFont.getGlyphOrder()[:]
        glyphNames.sort()
        maxNameLen = max(map(len, glyphNames))
        format = "%" + repr(maxNameLen) + "s:" + format + " ;"
        writer.write(format % (("ppem",) + tuple(ppems)))
        writer.newline()
        writer.newline()
        for glyphName in glyphNames:
            row = []
            for ppem in ppems:
                widths = self.hdmx[ppem]
                row.append(widths[glyphName])
            if ";" in glyphName:
                glyphName = "\\x3b".join(glyphName.split(";"))
            writer.write(format % ((glyphName,) + tuple(row)))
            writer.newline()
        writer.endtag("hdmxData")
        writer.newline()

    def fromXML(self, name, attrs, content, ttFont):
        if name != "hdmxData":
            return
        content = strjoin(content)
        lines = content.split(";")
        topRow = lines[0].split()
        assert topRow[0] == "ppem:", "illegal hdmx format"
        ppems = list(map(int, topRow[1:]))
        self.hdmx = hdmx = {}
        for ppem in ppems:
            hdmx[ppem] = {}
        lines = (line.split() for line in lines[1:])
        for line in lines:
            if not line:
                continue
            assert line[0][-1] == ":", "illegal hdmx format"
            glyphName = line[0][:-1]
            if "\\" in glyphName:
                from fontTools.misc.textTools import safeEval

                glyphName = safeEval('"""' + glyphName + '"""')
            line = list(map(int, line[1:]))
            assert len(line) == len(ppems), "illegal hdmx format"
            for i in range(len(ppems)):
                hdmx[ppems[i]][glyphName] = line[i]