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