blob: b8e60d398bc7f3fb516b5b83a7f9fc87a3cb1b17 [file] [log] [blame]
from __future__ import print_function, division, absolute_import
from fontTools.misc.py23 import *
from fontTools.ttLib import sfnt
from fontTools.misc.textTools import safeEval, readHex
from fontTools.misc.fixedTools import fixedToFloat as fi2fl, floatToFixed as fl2fi
from . import DefaultTable
import struct
import warnings
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])
apple = False
if (len(data) >= 8) and (version == 1):
# AAT Apple's "new" format. Hm.
version, nTables = struct.unpack(">LL", data[:8])
self.version = fi2fl(version, 16)
data = data[8:]
apple = True
else:
self.version = version
data = data[4:]
tablesIndex = []
self.kernTables = []
for i in range(nTables):
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])
length = int(length)
if version not in kern_classes:
subtable = KernTable_format_unkown(version)
else:
subtable = kern_classes[version]()
subtable.apple = apple
subtable.decompile(data[:length], ttFont)
self.kernTables.append(subtable)
data = data[length:]
def compile(self, ttFont):
if hasattr(self, "kernTables"):
nTables = len(self.kernTables)
else:
nTables = 0
if self.version == 1.0:
# AAT Apple's "new" format.
data = struct.pack(">ll", fl2fi(self.version, 16), nTables)
else:
data = struct.pack(">HH", self.version, nTables)
if hasattr(self, "kernTables"):
for subtable in self.kernTables:
data = data + subtable.compile(ttFont)
return data
def toXML(self, writer, ttFont):
writer.simpletag("version", value=self.version)
writer.newline()
for subtable in self.kernTables:
subtable.toXML(writer, ttFont)
def fromXML(self, name, attrs, content, ttFont):
if name == "version":
self.version = safeEval(attrs["value"])
return
if name != "kernsubtable":
return
if not hasattr(self, "kernTables"):
self.kernTables = []
format = safeEval(attrs["format"])
if format not in kern_classes:
subtable = KernTable_format_unkown(format)
else:
subtable = kern_classes[format]()
self.kernTables.append(subtable)
subtable.fromXML(name, attrs, content, ttFont)
class KernTable_format_0(object):
def decompile(self, data, ttFont):
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:]
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):
if len(data) < 6:
# buggy kern table
data = b""
break
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
if len(data):
warnings.warn("excess data in 'kern' subtable: %d bytes" % len(data))
def compile(self, ttFont):
nPairs = len(self.kernTable)
entrySelector = sfnt.maxPowerOfTwo(nPairs)
searchRange = (2 ** entrySelector) * 6
rangeShift = max(0, (nPairs - (2 ** entrySelector)) * 6)
data = struct.pack(">HHHH", nPairs, searchRange, entrySelector, rangeShift)
# yeehee! (I mean, turn names into indices)
getGlyphID = ttFont.getGlyphID
kernTable = sorted((getGlyphID(left), getGlyphID(right), value) for ((left,right),value) in self.kernTable.items())
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()
items = sorted(self.kernTable.items())
for (left, right), value in items:
writer.simpletag("pair", [
("l", left),
("r", right),
("v", value)
])
writer.newline()
writer.endtag("kernsubtable")
writer.newline()
def fromXML(self, name, attrs, content, ttFont):
self.coverage = safeEval(attrs["coverage"])
self.version = safeEval(attrs["format"])
if not hasattr(self, "kernTable"):
self.kernTable = {}
for element in content:
if not isinstance(element, tuple):
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]
class KernTable_format_2(object):
def decompile(self, data, ttFont):
self.data = data
def compile(self, ttFont):
return self.data
def toXML(self, writer):
writer.begintag("kernsubtable", format=2)
writer.newline()
writer.dumphex(self.data)
writer.endtag("kernsubtable")
writer.newline()
def fromXML(self, name, attrs, content, ttFont):
self.decompile(readHex(content), ttFont)
class KernTable_format_unkown(object):
def __init__(self, format):
self.format = format
def decompile(self, data, ttFont):
self.data = data
def compile(self, ttFont):
return self.data
def toXML(self, writer, ttFont):
writer.begintag("kernsubtable", format=self.format)
writer.newline()
writer.comment("unknown 'kern' subtable format")
writer.newline()
writer.dumphex(self.data)
writer.endtag("kernsubtable")
writer.newline()
def fromXML(self, name, attrs, content, ttFont):
self.decompile(readHex(content), ttFont)
kern_classes = {0: KernTable_format_0, 2: KernTable_format_2}