15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from __future__ import print_function, division, absolute_import 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from fontTools.misc.py23 import * 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from fontTools.ttLib import getSearchRange 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from fontTools.misc.textTools import safeEval, readHex 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from fontTools.misc.fixedTools import fixedToFloat as fi2fl, floatToFixed as fl2fi 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from . import DefaultTable 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import struct 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import warnings 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class table__k_e_r_n(DefaultTable.DefaultTable): 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch def getkern(self, format): 14c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch for subtable in self.kernTables: 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if subtable.version == format: 16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return subtable 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return None # not found 181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def decompile(self, data, ttFont): 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) version, nTables = struct.unpack(">HH", data[:4]) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) apple = False 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (len(data) >= 8) and (version == 1): 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # AAT Apple's "new" format. Hm. 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) version, nTables = struct.unpack(">LL", data[:8]) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.version = fi2fl(version, 16) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = data[8:] 27c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch apple = True 28c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch else: 29c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch self.version = version 30c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch data = data[4:] 31c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch tablesIndex = [] 32116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch self.kernTables = [] 33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch for i in range(nTables): 34116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if self.version == 1.0: 35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch # Apple 361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci length, coverage, tupleIndex = struct.unpack(">lHH", data[:8]) 37116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch version = coverage & 0xff 38116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch else: 39116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch version, length = struct.unpack(">HH", data[:4]) 40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch length = int(length) 41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if version not in kern_classes: 42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch subtable = KernTable_format_unkown(version) 43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch else: 44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch subtable = kern_classes[version]() 45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch subtable.apple = apple 46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch subtable.decompile(data[:length], ttFont) 47116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch self.kernTables.append(subtable) 48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch data = data[length:] 49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 50116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch def compile(self, ttFont): 51116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if hasattr(self, "kernTables"): 52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch nTables = len(self.kernTables) 53116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch else: 54116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch nTables = 0 55116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if self.version == 1.0: 56116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch # AAT Apple's "new" format. 57116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch data = struct.pack(">ll", fl2fi(self.version, 16), nTables) 58c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch else: 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = struct.pack(">HH", self.version, nTables) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if hasattr(self, "kernTables"): 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for subtable in self.kernTables: 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) data = data + subtable.compile(ttFont) 637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return data 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def toXML(self, writer, ttFont): 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) writer.simpletag("version", value=self.version) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) writer.newline() 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for subtable in self.kernTables: 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) subtable.toXML(writer, ttFont) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def fromXML(self, name, attrs, content, ttFont): 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if name == "version": 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.version = safeEval(attrs["value"]) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if name != "kernsubtable": 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not hasattr(self, "kernTables"): 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.kernTables = [] 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) format = safeEval(attrs["format"]) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if format not in kern_classes: 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) subtable = KernTable_format_unkown(format) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 83c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch subtable = kern_classes[format]() 84c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch self.kernTables.append(subtable) 85c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch subtable.fromXML(name, attrs, content, ttFont) 86c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 87c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 88c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochclass KernTable_format_0(object): 89c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 90c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch def decompile(self, data, ttFont): 91c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch version, length, coverage = (0,0,0) 92c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if not self.apple: 93c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch version, length, coverage = struct.unpack(">HHH", data[:6]) 94c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch data = data[6:] 95c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch else: 96c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch version, length, coverage = struct.unpack(">LHH", data[:8]) 97c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch data = data[8:] 98c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch self.version, self.coverage = int(version), int(coverage) 99c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 100c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch self.kernTable = kernTable = {} 101c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 102c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch nPairs, searchRange, entrySelector, rangeShift = struct.unpack(">HHHH", data[:8]) 103c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch data = data[8:] 104c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 105c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch for k in range(nPairs): 106c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if len(data) < 6: 107c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch # buggy kern table 108c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch data = b"" 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) left, right, value = struct.unpack(">HHh", data[:6]) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = data[6:] 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) left, right = int(left), int(right) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kernTable[(ttFont.getGlyphName(left), ttFont.getGlyphName(right))] = value 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(data): 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) warnings.warn("excess data in 'kern' subtable: %d bytes" % len(data)) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 117116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch def compile(self, ttFont): 118116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch nPairs = len(self.kernTable) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) searchRange, entrySelector, rangeShift = getSearchRange(nPairs, 6) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = struct.pack(">HHHH", nPairs, searchRange, entrySelector, rangeShift) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # yeehee! (I mean, turn names into indices) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) getGlyphID = ttFont.getGlyphID 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kernTable = sorted((getGlyphID(left), getGlyphID(right), value) for ((left,right),value) in self.kernTable.items()) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for left, right, value in kernTable: 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = data + struct.pack(">HHh", left, right, value) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return struct.pack(">HHH", self.version, len(data) + 6, self.coverage) + data 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def toXML(self, writer, ttFont): 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) writer.begintag("kernsubtable", coverage=self.coverage, format=0) 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) writer.newline() 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) items = sorted(self.kernTable.items()) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (left, right), value in items: 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) writer.simpletag("pair", [ 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ("l", left), 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ("r", right), 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ("v", value) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ]) 13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) writer.newline() 14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) writer.endtag("kernsubtable") 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) writer.newline() 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def fromXML(self, name, attrs, content, ttFont): 144c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch self.coverage = safeEval(attrs["coverage"]) 145c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch self.version = safeEval(attrs["format"]) 146c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if not hasattr(self, "kernTable"): 147c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch self.kernTable = {} 148c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch for element in content: 149c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if not isinstance(element, tuple): 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) name, attrs, content = element 152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) self.kernTable[(attrs["l"], attrs["r"])] = safeEval(attrs["v"]) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __getitem__(self, pair): 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self.kernTable[pair] 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 157c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch def __setitem__(self, pair, value): 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.kernTable[pair] = value 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 160c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch def __delitem__(self, pair): 161c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch del self.kernTable[pair] 162c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 163c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 164116680a4aac90f2aa7413d9095a592090648e557Ben Murdochclass KernTable_format_2(object): 165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 166116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch def decompile(self, data, ttFont): 167116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch self.data = data 168116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 169116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch def compile(self, ttFont): 170116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return self.data 171c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 172c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch def toXML(self, writer): 173a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch writer.begintag("kernsubtable", format=2) 174a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch writer.newline() 175c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch writer.dumphex(self.data) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) writer.endtag("kernsubtable") 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) writer.newline() 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def fromXML(self, name, attrs, content, ttFont): 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.decompile(readHex(content), ttFont) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class KernTable_format_unkown(object): 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, format): 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.format = format 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def decompile(self, data, ttFont): 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.data = data 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def compile(self, ttFont): 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self.data 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 194c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch def toXML(self, writer, ttFont): 195c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch writer.begintag("kernsubtable", format=self.format) 196c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch writer.newline() 197c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch writer.comment("unknown 'kern' subtable format") 198c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch writer.newline() 199c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch writer.dumphex(self.data) 200c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch writer.endtag("kernsubtable") 201c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch writer.newline() 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def fromXML(self, name, attrs, content, ttFont): 204 self.decompile(readHex(content), ttFont) 205 206 207 208kern_classes = {0: KernTable_format_0, 2: KernTable_format_2} 209