2014-01-14 15:07:50 +08:00
|
|
|
from __future__ import print_function, division, absolute_import
|
2013-11-27 17:27:45 -05:00
|
|
|
from fontTools.misc.py23 import *
|
1999-12-17 11:57:06 +00:00
|
|
|
from fontTools.ttLib import sfnt
|
1999-12-16 21:34:53 +00:00
|
|
|
from fontTools.misc.textTools import safeEval, readHex
|
2013-11-28 18:49:30 -05:00
|
|
|
from fontTools.misc.fixedTools import fixedToFloat as fi2fl, floatToFixed as fl2fi
|
2013-11-27 17:27:45 -05:00
|
|
|
from . import DefaultTable
|
|
|
|
import struct
|
2013-07-24 18:26:49 -04:00
|
|
|
import warnings
|
1999-12-16 21:34:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
class table__k_e_r_n(DefaultTable.DefaultTable):
|
|
|
|
|
|
|
|
def getkern(self, format):
|
|
|
|
for subtable in self.kernTables:
|
|
|
|
if subtable.version == format:
|
|
|
|
return subtable
|
|
|
|
return None # not found
|
|
|
|
|
|
|
|
def decompile(self, data, ttFont):
|
|
|
|
version, nTables = struct.unpack(">HH", data[:4])
|
2012-11-10 17:58:30 +00:00
|
|
|
apple = False
|
2006-01-25 15:24:37 +00:00
|
|
|
if (len(data) >= 8) and (version == 1):
|
2012-11-10 17:58:30 +00:00
|
|
|
# AAT Apple's "new" format. Hm.
|
2006-01-25 15:24:37 +00:00
|
|
|
version, nTables = struct.unpack(">LL", data[:8])
|
2013-11-28 18:49:30 -05:00
|
|
|
self.version = fi2fl(version, 16)
|
1999-12-16 21:34:53 +00:00
|
|
|
data = data[8:]
|
2012-11-10 17:58:30 +00:00
|
|
|
apple = True
|
1999-12-16 21:34:53 +00:00
|
|
|
else:
|
|
|
|
self.version = version
|
|
|
|
data = data[4:]
|
|
|
|
tablesIndex = []
|
|
|
|
self.kernTables = []
|
|
|
|
for i in range(nTables):
|
2002-05-10 19:52:14 +00:00
|
|
|
if self.version == 1.0:
|
|
|
|
# Apple
|
|
|
|
length, coverage, tupleIndex = struct.unpack(">lHH", data[:8])
|
|
|
|
version = coverage & 0xff
|
|
|
|
else:
|
|
|
|
version, length = struct.unpack(">HH", data[:4])
|
1999-12-16 21:34:53 +00:00
|
|
|
length = int(length)
|
2013-11-27 02:33:03 -05:00
|
|
|
if version not in kern_classes:
|
2002-05-10 19:52:14 +00:00
|
|
|
subtable = KernTable_format_unkown(version)
|
1999-12-16 21:34:53 +00:00
|
|
|
else:
|
|
|
|
subtable = kern_classes[version]()
|
2012-11-10 17:58:30 +00:00
|
|
|
subtable.apple = apple
|
1999-12-16 21:34:53 +00:00
|
|
|
subtable.decompile(data[:length], ttFont)
|
|
|
|
self.kernTables.append(subtable)
|
|
|
|
data = data[length:]
|
|
|
|
|
|
|
|
def compile(self, ttFont):
|
2006-01-25 15:24:37 +00:00
|
|
|
if hasattr(self, "kernTables"):
|
|
|
|
nTables = len(self.kernTables)
|
|
|
|
else:
|
|
|
|
nTables = 0
|
1999-12-16 21:34:53 +00:00
|
|
|
if self.version == 1.0:
|
2012-11-10 17:58:30 +00:00
|
|
|
# AAT Apple's "new" format.
|
2013-11-28 18:49:30 -05:00
|
|
|
data = struct.pack(">ll", fl2fi(self.version, 16), nTables)
|
1999-12-16 21:34:53 +00:00
|
|
|
else:
|
|
|
|
data = struct.pack(">HH", self.version, nTables)
|
2006-01-25 15:24:37 +00:00
|
|
|
if hasattr(self, "kernTables"):
|
|
|
|
for subtable in self.kernTables:
|
|
|
|
data = data + subtable.compile(ttFont)
|
1999-12-16 21:34:53 +00:00
|
|
|
return data
|
|
|
|
|
|
|
|
def toXML(self, writer, ttFont):
|
|
|
|
writer.simpletag("version", value=self.version)
|
|
|
|
writer.newline()
|
|
|
|
for subtable in self.kernTables:
|
|
|
|
subtable.toXML(writer, ttFont)
|
|
|
|
|
2013-11-27 03:19:32 -05:00
|
|
|
def fromXML(self, name, attrs, content, ttFont):
|
1999-12-16 21:34:53 +00:00
|
|
|
if name == "version":
|
|
|
|
self.version = safeEval(attrs["value"])
|
|
|
|
return
|
2013-11-27 02:40:30 -05:00
|
|
|
if name != "kernsubtable":
|
1999-12-16 21:34:53 +00:00
|
|
|
return
|
|
|
|
if not hasattr(self, "kernTables"):
|
|
|
|
self.kernTables = []
|
|
|
|
format = safeEval(attrs["format"])
|
2013-11-27 02:33:03 -05:00
|
|
|
if format not in kern_classes:
|
2002-05-10 19:52:14 +00:00
|
|
|
subtable = KernTable_format_unkown(format)
|
1999-12-16 21:34:53 +00:00
|
|
|
else:
|
|
|
|
subtable = kern_classes[format]()
|
|
|
|
self.kernTables.append(subtable)
|
2013-11-27 03:19:32 -05:00
|
|
|
subtable.fromXML(name, attrs, content, ttFont)
|
1999-12-16 21:34:53 +00:00
|
|
|
|
|
|
|
|
2013-11-28 14:26:58 -05:00
|
|
|
class KernTable_format_0(object):
|
1999-12-16 21:34:53 +00:00
|
|
|
|
|
|
|
def decompile(self, data, ttFont):
|
2012-11-10 17:58:30 +00:00
|
|
|
version, length, coverage = (0,0,0)
|
|
|
|
if not self.apple:
|
|
|
|
version, length, coverage = struct.unpack(">HHH", data[:6])
|
|
|
|
data = data[6:]
|
|
|
|
else:
|
|
|
|
version, length, coverage = struct.unpack(">LHH", data[:8])
|
|
|
|
data = data[8:]
|
1999-12-16 21:34:53 +00:00
|
|
|
self.version, self.coverage = int(version), int(coverage)
|
|
|
|
|
|
|
|
self.kernTable = kernTable = {}
|
|
|
|
|
|
|
|
nPairs, searchRange, entrySelector, rangeShift = struct.unpack(">HHHH", data[:8])
|
|
|
|
data = data[8:]
|
|
|
|
|
|
|
|
for k in range(nPairs):
|
2004-09-25 10:56:15 +00:00
|
|
|
if len(data) < 6:
|
|
|
|
# buggy kern table
|
2013-11-27 22:00:49 -05:00
|
|
|
data = b""
|
2004-09-25 10:56:15 +00:00
|
|
|
break
|
1999-12-16 21:34:53 +00:00
|
|
|
left, right, value = struct.unpack(">HHh", data[:6])
|
|
|
|
data = data[6:]
|
|
|
|
left, right = int(left), int(right)
|
|
|
|
kernTable[(ttFont.getGlyphName(left), ttFont.getGlyphName(right))] = value
|
2013-07-24 18:26:49 -04:00
|
|
|
if len(data):
|
|
|
|
warnings.warn("excess data in 'kern' subtable: %d bytes" % len(data))
|
1999-12-16 21:34:53 +00:00
|
|
|
|
|
|
|
def compile(self, ttFont):
|
|
|
|
nPairs = len(self.kernTable)
|
2002-05-12 17:14:50 +00:00
|
|
|
entrySelector = sfnt.maxPowerOfTwo(nPairs)
|
1999-12-16 21:34:53 +00:00
|
|
|
searchRange = (2 ** entrySelector) * 6
|
|
|
|
rangeShift = (nPairs - (2 ** entrySelector)) * 6
|
|
|
|
data = struct.pack(">HHHH", nPairs, searchRange, entrySelector, rangeShift)
|
|
|
|
|
|
|
|
# yeehee! (I mean, turn names into indices)
|
2013-11-27 05:59:53 -05:00
|
|
|
getGlyphID = ttFont.getGlyphID
|
|
|
|
kernTable = sorted((getGlyphID(left), getGlyphID(right), value) for ((left,right),value) in self.kernTable.items())
|
1999-12-16 21:34:53 +00:00
|
|
|
for left, right, value in kernTable:
|
|
|
|
data = data + struct.pack(">HHh", left, right, value)
|
|
|
|
return struct.pack(">HHH", self.version, len(data) + 6, self.coverage) + data
|
|
|
|
|
|
|
|
def toXML(self, writer, ttFont):
|
|
|
|
writer.begintag("kernsubtable", coverage=self.coverage, format=0)
|
|
|
|
writer.newline()
|
2013-11-27 04:15:34 -05:00
|
|
|
items = sorted(self.kernTable.items())
|
1999-12-16 21:34:53 +00:00
|
|
|
for (left, right), value in items:
|
|
|
|
writer.simpletag("pair", [
|
|
|
|
("l", left),
|
|
|
|
("r", right),
|
|
|
|
("v", value)
|
|
|
|
])
|
|
|
|
writer.newline()
|
|
|
|
writer.endtag("kernsubtable")
|
|
|
|
writer.newline()
|
|
|
|
|
2013-11-27 03:19:32 -05:00
|
|
|
def fromXML(self, name, attrs, content, ttFont):
|
1999-12-16 21:34:53 +00:00
|
|
|
self.coverage = safeEval(attrs["coverage"])
|
|
|
|
self.version = safeEval(attrs["format"])
|
|
|
|
if not hasattr(self, "kernTable"):
|
|
|
|
self.kernTable = {}
|
|
|
|
for element in content:
|
2013-11-27 05:17:37 -05:00
|
|
|
if not isinstance(element, tuple):
|
1999-12-16 21:34:53 +00:00
|
|
|
continue
|
|
|
|
name, attrs, content = element
|
|
|
|
self.kernTable[(attrs["l"], attrs["r"])] = safeEval(attrs["v"])
|
|
|
|
|
|
|
|
def __getitem__(self, pair):
|
|
|
|
return self.kernTable[pair]
|
|
|
|
|
|
|
|
def __setitem__(self, pair, value):
|
|
|
|
self.kernTable[pair] = value
|
|
|
|
|
|
|
|
def __delitem__(self, pair):
|
|
|
|
del self.kernTable[pair]
|
|
|
|
|
|
|
|
|
2013-11-28 14:26:58 -05:00
|
|
|
class KernTable_format_2(object):
|
1999-12-16 21:34:53 +00:00
|
|
|
|
|
|
|
def decompile(self, data, ttFont):
|
|
|
|
self.data = data
|
|
|
|
|
2000-03-14 23:02:33 +00:00
|
|
|
def compile(self, ttFont):
|
2002-05-10 19:52:14 +00:00
|
|
|
return self.data
|
1999-12-16 21:34:53 +00:00
|
|
|
|
|
|
|
def toXML(self, writer):
|
|
|
|
writer.begintag("kernsubtable", format=2)
|
|
|
|
writer.newline()
|
|
|
|
writer.dumphex(self.data)
|
|
|
|
writer.endtag("kernsubtable")
|
|
|
|
writer.newline()
|
|
|
|
|
2013-11-27 03:19:32 -05:00
|
|
|
def fromXML(self, name, attrs, content, ttFont):
|
2002-05-10 19:52:14 +00:00
|
|
|
self.decompile(readHex(content), ttFont)
|
1999-12-16 21:34:53 +00:00
|
|
|
|
|
|
|
|
2013-11-28 14:26:58 -05:00
|
|
|
class KernTable_format_unkown(object):
|
1999-12-16 21:34:53 +00:00
|
|
|
|
2002-05-10 19:52:14 +00:00
|
|
|
def __init__(self, format):
|
|
|
|
self.format = format
|
|
|
|
|
1999-12-16 21:34:53 +00:00
|
|
|
def decompile(self, data, ttFont):
|
|
|
|
self.data = data
|
|
|
|
|
|
|
|
def compile(self, ttFont):
|
2002-05-10 19:52:14 +00:00
|
|
|
return self.data
|
1999-12-16 21:34:53 +00:00
|
|
|
|
|
|
|
def toXML(self, writer, ttFont):
|
2002-05-10 19:52:14 +00:00
|
|
|
writer.begintag("kernsubtable", format=self.format)
|
1999-12-16 21:34:53 +00:00
|
|
|
writer.newline()
|
|
|
|
writer.comment("unknown 'kern' subtable format")
|
2002-05-10 19:52:14 +00:00
|
|
|
writer.newline()
|
1999-12-16 21:34:53 +00:00
|
|
|
writer.dumphex(self.data)
|
|
|
|
writer.endtag("kernsubtable")
|
|
|
|
writer.newline()
|
|
|
|
|
2013-11-27 03:19:32 -05:00
|
|
|
def fromXML(self, name, attrs, content, ttFont):
|
2002-05-10 19:52:14 +00:00
|
|
|
self.decompile(readHex(content), ttFont)
|
1999-12-16 21:34:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2000-03-14 23:02:33 +00:00
|
|
|
kern_classes = {0: KernTable_format_0, 2: KernTable_format_2}
|