[morx] Separate building from writing lookup tables

For AAT lookup format 2 (and other formats too), we need to shuffle
the data before we can estimate the encoded size. After this restructuring,
this data shuffling only needs to happen once.
This commit is contained in:
Sascha Brawer 2017-06-13 10:40:39 +02:00
parent 68dc15375b
commit bdf29b4169

View File

@ -549,6 +549,8 @@ class ValueRecord(ValueFormat):
class AATLookup(BaseConverter): class AATLookup(BaseConverter):
BIN_SEARCH_HEADER_SIZE = 10
def read(self, reader, font, tableDict): def read(self, reader, font, tableDict):
format = reader.readUShort() format = reader.readUShort()
if format == 0: if format == 0:
@ -570,14 +572,15 @@ class AATLookup(BaseConverter):
def write(self, writer, font, tableDict, value, repeatIndex=None): def write(self, writer, font, tableDict, value, repeatIndex=None):
glyphMap = font.getReverseGlyphMap() glyphMap = font.getReverseGlyphMap()
binSrchHeaderSize = 10 binSrchHeaderSize = 10
formatSizes = {6: binSrchHeaderSize + len(value) * 4 + 4}
if glyphMap.keys() == value.keys():
formatSizes[0] = len(value) * 2
# TODO: Also implement format 2, 4, and 8. # TODO: Also implement format 2, 4, and 8.
bestFormat = min(formatSizes, key=formatSizes.get) formats = list(sorted(filter(None, [
writeMethod = getattr(self, 'writeFormat%d' % bestFormat) self.buildFormat0(font, value),
writer.writeUShort(bestFormat) self.buildFormat6(font, value),
writeMethod(writer, font, value) ])))
# We use the format ID as secondary sort key to make the output
# deterministic when multiple formats have same encoded size.
_size, _format, writeMethod = formats[0]
writeMethod(writer)
@staticmethod @staticmethod
def writeBinSearchHeader(writer, numUnits, unitSize): def writeBinSearchHeader(writer, numUnits, unitSize):
@ -589,17 +592,32 @@ class AATLookup(BaseConverter):
writer.writeUShort(entrySelector) writer.writeUShort(entrySelector)
writer.writeUShort(rangeShift) writer.writeUShort(rangeShift)
def buildFormat0(self, font, value):
if font.getReverseGlyphMap().keys() != value.keys():
return None
return (len(value) * 2, 0,
lambda writer: self.writeFormat0(writer, font, value))
def writeFormat0(self, writer, font, value): def writeFormat0(self, writer, font, value):
writer.writeUShort(0)
for glyph in font.getGlyphOrder(): for glyph in font.getGlyphOrder():
writer.writeUShort(font.getGlyphID(value[glyph])) writer.writeUShort(font.getGlyphID(value[glyph]))
def writeFormat6(self, writer, font, value): def buildFormat6(self, font, value):
table = [(font.getGlyphID(key), font.getGlyphID(value)) entries = [(font.getGlyphID(key), font.getGlyphID(value))
for key, value in value.items()] + [(0xFFFF, 0xFFFF)] for key, value in value.items()]
table.sort() entries.sort()
if entries[-1][0] != 0xFFFF:
entries.append((0xFFFF, 0xFFFF))
return (self.BIN_SEARCH_HEADER_SIZE + len(entries) * 4, 6,
lambda writer:
self.writeFormat6(writer, font, value, entries))
def writeFormat6(self, writer, font, value, entries):
writer.writeUShort(6)
self.writeBinSearchHeader(writer, self.writeBinSearchHeader(writer,
numUnits=len(table), unitSize=4) numUnits=len(entries), unitSize=4)
for key, value in table: for key, value in entries:
writer.writeUShort(key) writer.writeUShort(key)
writer.writeUShort(value) writer.writeUShort(value)