| from __future__ import print_function, division, absolute_import |
| from fontTools.misc.py23 import * |
| from fontTools.misc import sstruct |
| from . import DefaultTable |
| import array |
| |
| hdmxHeaderFormat = """ |
| > # big endian! |
| version: H |
| numRecords: H |
| recordSize: l |
| """ |
| |
| try: |
| from collections.abc import Mapping |
| except: |
| from UserDict import DictMixin as Mapping |
| |
| 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] |