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