1from __future__ import print_function, division, absolute_import 2from fontTools.misc.py23 import * 3from fontTools.misc import sstruct 4from fontTools.misc.textTools import safeEval 5from . import DefaultTable 6 7GMAPFormat = """ 8 > # big endian 9 tableVersionMajor: H 10 tableVersionMinor: H 11 flags: H 12 recordsCount: H 13 recordsOffset: H 14 fontNameLength: H 15""" 16# psFontName is a byte string which follows the record above. This is zero padded 17# to the beginning of the records array. The recordsOffsst is 32 bit aligned. 18 19GMAPRecordFormat1 = """ 20 > # big endian 21 UV: L 22 cid: H 23 gid: H 24 ggid: H 25 name: 32s 26""" 27 28 29 30class GMAPRecord(object): 31 def __init__(self, uv = 0, cid = 0, gid = 0, ggid = 0, name = ""): 32 self.UV = uv 33 self.cid = cid 34 self.gid = gid 35 self.ggid = ggid 36 self.name = name 37 38 def toXML(self, writer, ttFont): 39 writer.begintag("GMAPRecord") 40 writer.newline() 41 writer.simpletag("UV", value=self.UV) 42 writer.newline() 43 writer.simpletag("cid", value=self.cid) 44 writer.newline() 45 writer.simpletag("gid", value=self.gid) 46 writer.newline() 47 writer.simpletag("glyphletGid", value=self.gid) 48 writer.newline() 49 writer.simpletag("GlyphletName", value=self.name) 50 writer.newline() 51 writer.endtag("GMAPRecord") 52 writer.newline() 53 54 55 def fromXML(self, name, attrs, content, ttFont): 56 value = attrs["value"] 57 if name == "GlyphletName": 58 self.name = value 59 else: 60 setattr(self, name, safeEval(value)) 61 62 63 def compile(self, ttFont): 64 if self.UV is None: 65 self.UV = 0 66 nameLen = len(self.name) 67 if nameLen < 32: 68 self.name = self.name + "\0"*(32 - nameLen) 69 data = sstruct.pack(GMAPRecordFormat1, self) 70 return data 71 72 def __repr__(self): 73 return "GMAPRecord[ UV: " + str(self.UV) + ", cid: " + str(self.cid) + ", gid: " + str(self.gid) + ", ggid: " + str(self.ggid) + ", Glyphlet Name: " + str(self.name) + " ]" 74 75 76class table_G_M_A_P_(DefaultTable.DefaultTable): 77 78 dependencies = [] 79 80 def decompile(self, data, ttFont): 81 dummy, newData = sstruct.unpack2(GMAPFormat, data, self) 82 self.psFontName = tostr(newData[:self.fontNameLength]) 83 assert (self.recordsOffset % 4) == 0, "GMAP error: recordsOffset is not 32 bit aligned." 84 newData = data[self.recordsOffset:] 85 self.gmapRecords = [] 86 for i in range (self.recordsCount): 87 gmapRecord, newData = sstruct.unpack2(GMAPRecordFormat1, newData, GMAPRecord()) 88 gmapRecord.name = gmapRecord.name.strip('\0') 89 self.gmapRecords.append(gmapRecord) 90 91 92 def compile(self, ttFont): 93 self.recordsCount = len(self.gmapRecords) 94 self.fontNameLength = len(self.psFontName) 95 self.recordsOffset = 4 *(((self.fontNameLength + 12) + 3) // 4) 96 data = sstruct.pack(GMAPFormat, self) 97 data = data + tobytes(self.psFontName) 98 data = data + b"\0" * (self.recordsOffset - len(data)) 99 for record in self.gmapRecords: 100 data = data + record.compile(ttFont) 101 return data 102 103 104 def toXML(self, writer, ttFont): 105 writer.comment("Most of this table will be recalculated by the compiler") 106 writer.newline() 107 formatstring, names, fixes = sstruct.getformat(GMAPFormat) 108 for name in names: 109 value = getattr(self, name) 110 writer.simpletag(name, value=value) 111 writer.newline() 112 writer.simpletag("PSFontName", value=self.psFontName) 113 writer.newline() 114 for gmapRecord in self.gmapRecords: 115 gmapRecord.toXML(writer, ttFont) 116 117 def fromXML(self, name, attrs, content, ttFont): 118 if name == "GMAPRecord": 119 if not hasattr(self, "gmapRecords"): 120 self.gmapRecords = [] 121 gmapRecord = GMAPRecord() 122 self.gmapRecords.append(gmapRecord) 123 for element in content: 124 if isinstance(element, basestring): 125 continue 126 name, attrs, content = element 127 gmapRecord.fromXML(name, attrs, content, ttFont) 128 else: 129 value = attrs["value"] 130 if name == "PSFontName": 131 self.psFontName = value 132 else: 133 setattr(self, name, safeEval(value)) 134