1 from __future__ import print_function, division, absolute_import 2 from fontTools.misc.py23 import * 3 from fontTools.ttLib import getSearchRange 4 from fontTools.misc.textTools import safeEval, readHex 5 from fontTools.misc.fixedTools import fixedToFloat as fi2fl, floatToFixed as fl2fi 6 from . import DefaultTable 7 import struct 8 import warnings 9 10 11 class table__k_e_r_n(DefaultTable.DefaultTable): 12 13 def getkern(self, format): 14 for subtable in self.kernTables: 15 if subtable.version == format: 16 return subtable 17 return None # not found 18 19 def decompile(self, data, ttFont): 20 version, nTables = struct.unpack(">HH", data[:4]) 21 apple = False 22 if (len(data) >= 8) and (version == 1): 23 # AAT Apple's "new" format. Hm. 24 version, nTables = struct.unpack(">LL", data[:8]) 25 self.version = fi2fl(version, 16) 26 data = data[8:] 27 apple = True 28 else: 29 self.version = version 30 data = data[4:] 31 tablesIndex = [] 32 self.kernTables = [] 33 for i in range(nTables): 34 if self.version == 1.0: 35 # Apple 36 length, coverage, tupleIndex = struct.unpack(">lHH", data[:8]) 37 version = coverage & 0xff 38 else: 39 version, length = struct.unpack(">HH", data[:4]) 40 length = int(length) 41 if version not in kern_classes: 42 subtable = KernTable_format_unkown(version) 43 else: 44 subtable = kern_classes[version]() 45 subtable.apple = apple 46 subtable.decompile(data[:length], ttFont) 47 self.kernTables.append(subtable) 48 data = data[length:] 49 50 def compile(self, ttFont): 51 if hasattr(self, "kernTables"): 52 nTables = len(self.kernTables) 53 else: 54 nTables = 0 55 if self.version == 1.0: 56 # AAT Apple's "new" format. 57 data = struct.pack(">ll", fl2fi(self.version, 16), nTables) 58 else: 59 data = struct.pack(">HH", self.version, nTables) 60 if hasattr(self, "kernTables"): 61 for subtable in self.kernTables: 62 data = data + subtable.compile(ttFont) 63 return data 64 65 def toXML(self, writer, ttFont): 66 writer.simpletag("version", value=self.version) 67 writer.newline() 68 for subtable in self.kernTables: 69 subtable.toXML(writer, ttFont) 70 71 def fromXML(self, name, attrs, content, ttFont): 72 if name == "version": 73 self.version = safeEval(attrs["value"]) 74 return 75 if name != "kernsubtable": 76 return 77 if not hasattr(self, "kernTables"): 78 self.kernTables = [] 79 format = safeEval(attrs["format"]) 80 if format not in kern_classes: 81 subtable = KernTable_format_unkown(format) 82 else: 83 subtable = kern_classes[format]() 84 self.kernTables.append(subtable) 85 subtable.fromXML(name, attrs, content, ttFont) 86 87 88 class KernTable_format_0(object): 89 90 def decompile(self, data, ttFont): 91 version, length, coverage = (0,0,0) 92 if not self.apple: 93 version, length, coverage = struct.unpack(">HHH", data[:6]) 94 data = data[6:] 95 else: 96 version, length, coverage = struct.unpack(">LHH", data[:8]) 97 data = data[8:] 98 self.version, self.coverage = int(version), int(coverage) 99 100 self.kernTable = kernTable = {} 101 102 nPairs, searchRange, entrySelector, rangeShift = struct.unpack(">HHHH", data[:8]) 103 data = data[8:] 104 105 for k in range(nPairs): 106 if len(data) < 6: 107 # buggy kern table 108 data = b"" 109 break 110 left, right, value = struct.unpack(">HHh", data[:6]) 111 data = data[6:] 112 left, right = int(left), int(right) 113 kernTable[(ttFont.getGlyphName(left), ttFont.getGlyphName(right))] = value 114 if len(data): 115 warnings.warn("excess data in 'kern' subtable: %d bytes" % len(data)) 116 117 def compile(self, ttFont): 118 nPairs = len(self.kernTable) 119 searchRange, entrySelector, rangeShift = getSearchRange(nPairs, 6) 120 data = struct.pack(">HHHH", nPairs, searchRange, entrySelector, rangeShift) 121 122 # yeehee! (I mean, turn names into indices) 123 getGlyphID = ttFont.getGlyphID 124 kernTable = sorted((getGlyphID(left), getGlyphID(right), value) for ((left,right),value) in self.kernTable.items()) 125 for left, right, value in kernTable: 126 data = data + struct.pack(">HHh", left, right, value) 127 return struct.pack(">HHH", self.version, len(data) + 6, self.coverage) + data 128 129 def toXML(self, writer, ttFont): 130 writer.begintag("kernsubtable", coverage=self.coverage, format=0) 131 writer.newline() 132 items = sorted(self.kernTable.items()) 133 for (left, right), value in items: 134 writer.simpletag("pair", [ 135 ("l", left), 136 ("r", right), 137 ("v", value) 138 ]) 139 writer.newline() 140 writer.endtag("kernsubtable") 141 writer.newline() 142 143 def fromXML(self, name, attrs, content, ttFont): 144 self.coverage = safeEval(attrs["coverage"]) 145 self.version = safeEval(attrs["format"]) 146 if not hasattr(self, "kernTable"): 147 self.kernTable = {} 148 for element in content: 149 if not isinstance(element, tuple): 150 continue 151 name, attrs, content = element 152 self.kernTable[(attrs["l"], attrs["r"])] = safeEval(attrs["v"]) 153 154 def __getitem__(self, pair): 155 return self.kernTable[pair] 156 157 def __setitem__(self, pair, value): 158 self.kernTable[pair] = value 159 160 def __delitem__(self, pair): 161 del self.kernTable[pair] 162 163 164 class KernTable_format_2(object): 165 166 def decompile(self, data, ttFont): 167 self.data = data 168 169 def compile(self, ttFont): 170 return self.data 171 172 def toXML(self, writer): 173 writer.begintag("kernsubtable", format=2) 174 writer.newline() 175 writer.dumphex(self.data) 176 writer.endtag("kernsubtable") 177 writer.newline() 178 179 def fromXML(self, name, attrs, content, ttFont): 180 self.decompile(readHex(content), ttFont) 181 182 183 class KernTable_format_unkown(object): 184 185 def __init__(self, format): 186 self.format = format 187 188 def decompile(self, data, ttFont): 189 self.data = data 190 191 def compile(self, ttFont): 192 return self.data 193 194 def toXML(self, writer, ttFont): 195 writer.begintag("kernsubtable", format=self.format) 196 writer.newline() 197 writer.comment("unknown 'kern' subtable format") 198 writer.newline() 199 writer.dumphex(self.data) 200 writer.endtag("kernsubtable") 201 writer.newline() 202 203 def fromXML(self, name, attrs, content, ttFont): 204 self.decompile(readHex(content), ttFont) 205 206 207 208 kern_classes = {0: KernTable_format_0, 2: KernTable_format_2} 209