1from fontTools.misc.textTools import bytesjoin, safeEval 2from . import DefaultTable 3import struct 4 5 6class table_V_O_R_G_(DefaultTable.DefaultTable): 7 """This table is structured so that you can treat it like a dictionary keyed by glyph name. 8 9 ``ttFont['VORG'][<glyphName>]`` will return the vertical origin for any glyph. 10 11 ``ttFont['VORG'][<glyphName>] = <value>`` will set the vertical origin for any glyph. 12 """ 13 14 def decompile(self, data, ttFont): 15 self.getGlyphName = ( 16 ttFont.getGlyphName 17 ) # for use in get/set item functions, for access by GID 18 ( 19 self.majorVersion, 20 self.minorVersion, 21 self.defaultVertOriginY, 22 self.numVertOriginYMetrics, 23 ) = struct.unpack(">HHhH", data[:8]) 24 assert ( 25 self.majorVersion <= 1 26 ), "Major version of VORG table is higher than I know how to handle" 27 data = data[8:] 28 vids = [] 29 gids = [] 30 pos = 0 31 for i in range(self.numVertOriginYMetrics): 32 gid, vOrigin = struct.unpack(">Hh", data[pos : pos + 4]) 33 pos += 4 34 gids.append(gid) 35 vids.append(vOrigin) 36 37 self.VOriginRecords = vOrig = {} 38 glyphOrder = ttFont.getGlyphOrder() 39 try: 40 names = [glyphOrder[gid] for gid in gids] 41 except IndexError: 42 getGlyphName = self.getGlyphName 43 names = map(getGlyphName, gids) 44 45 for name, vid in zip(names, vids): 46 vOrig[name] = vid 47 48 def compile(self, ttFont): 49 vorgs = list(self.VOriginRecords.values()) 50 names = list(self.VOriginRecords.keys()) 51 nameMap = ttFont.getReverseGlyphMap() 52 try: 53 gids = [nameMap[name] for name in names] 54 except KeyError: 55 nameMap = ttFont.getReverseGlyphMap(rebuild=True) 56 gids = [nameMap[name] for name in names] 57 vOriginTable = list(zip(gids, vorgs)) 58 self.numVertOriginYMetrics = len(vorgs) 59 vOriginTable.sort() # must be in ascending GID order 60 dataList = [struct.pack(">Hh", rec[0], rec[1]) for rec in vOriginTable] 61 header = struct.pack( 62 ">HHhH", 63 self.majorVersion, 64 self.minorVersion, 65 self.defaultVertOriginY, 66 self.numVertOriginYMetrics, 67 ) 68 dataList.insert(0, header) 69 data = bytesjoin(dataList) 70 return data 71 72 def toXML(self, writer, ttFont): 73 writer.simpletag("majorVersion", value=self.majorVersion) 74 writer.newline() 75 writer.simpletag("minorVersion", value=self.minorVersion) 76 writer.newline() 77 writer.simpletag("defaultVertOriginY", value=self.defaultVertOriginY) 78 writer.newline() 79 writer.simpletag("numVertOriginYMetrics", value=self.numVertOriginYMetrics) 80 writer.newline() 81 vOriginTable = [] 82 glyphNames = self.VOriginRecords.keys() 83 for glyphName in glyphNames: 84 try: 85 gid = ttFont.getGlyphID(glyphName) 86 except: 87 assert 0, ( 88 "VORG table contains a glyph name not in ttFont.getGlyphNames(): " 89 + str(glyphName) 90 ) 91 vOriginTable.append([gid, glyphName, self.VOriginRecords[glyphName]]) 92 vOriginTable.sort() 93 for entry in vOriginTable: 94 vOriginRec = VOriginRecord(entry[1], entry[2]) 95 vOriginRec.toXML(writer, ttFont) 96 97 def fromXML(self, name, attrs, content, ttFont): 98 if not hasattr(self, "VOriginRecords"): 99 self.VOriginRecords = {} 100 self.getGlyphName = ( 101 ttFont.getGlyphName 102 ) # for use in get/set item functions, for access by GID 103 if name == "VOriginRecord": 104 vOriginRec = VOriginRecord() 105 for element in content: 106 if isinstance(element, str): 107 continue 108 name, attrs, content = element 109 vOriginRec.fromXML(name, attrs, content, ttFont) 110 self.VOriginRecords[vOriginRec.glyphName] = vOriginRec.vOrigin 111 elif "value" in attrs: 112 setattr(self, name, safeEval(attrs["value"])) 113 114 def __getitem__(self, glyphSelector): 115 if isinstance(glyphSelector, int): 116 # its a gid, convert to glyph name 117 glyphSelector = self.getGlyphName(glyphSelector) 118 119 if glyphSelector not in self.VOriginRecords: 120 return self.defaultVertOriginY 121 122 return self.VOriginRecords[glyphSelector] 123 124 def __setitem__(self, glyphSelector, value): 125 if isinstance(glyphSelector, int): 126 # its a gid, convert to glyph name 127 glyphSelector = self.getGlyphName(glyphSelector) 128 129 if value != self.defaultVertOriginY: 130 self.VOriginRecords[glyphSelector] = value 131 elif glyphSelector in self.VOriginRecords: 132 del self.VOriginRecords[glyphSelector] 133 134 def __delitem__(self, glyphSelector): 135 del self.VOriginRecords[glyphSelector] 136 137 138class VOriginRecord(object): 139 def __init__(self, name=None, vOrigin=None): 140 self.glyphName = name 141 self.vOrigin = vOrigin 142 143 def toXML(self, writer, ttFont): 144 writer.begintag("VOriginRecord") 145 writer.newline() 146 writer.simpletag("glyphName", value=self.glyphName) 147 writer.newline() 148 writer.simpletag("vOrigin", value=self.vOrigin) 149 writer.newline() 150 writer.endtag("VOriginRecord") 151 writer.newline() 152 153 def fromXML(self, name, attrs, content, ttFont): 154 value = attrs["value"] 155 if name == "glyphName": 156 setattr(self, name, value) 157 else: 158 setattr(self, name, safeEval(value)) 159