diff --git a/Lib/fontTools/ttLib/tables/otConverters.py b/Lib/fontTools/ttLib/tables/otConverters.py index a9bc578c9..8f96af77b 100644 --- a/Lib/fontTools/ttLib/tables/otConverters.py +++ b/Lib/fontTools/ttLib/tables/otConverters.py @@ -571,11 +571,12 @@ class AATLookup(BaseConverter): def write(self, writer, font, tableDict, value, repeatIndex=None): glyphMap = font.getReverseGlyphMap() - # TODO: Also implement format 4 and 8. + # TODO: Also implement format 4. formats = list(sorted(filter(None, [ self.buildFormat0(font, value), self.buildFormat2(font, value), self.buildFormat6(font, value), + self.buildFormat8(font, value), ]))) # We use the format ID as secondary sort key to make the output # deterministic when multiple formats have same encoded size. @@ -651,6 +652,24 @@ class AATLookup(BaseConverter): writer.writeUShort(key) writer.writeUShort(value) + def buildFormat8(self, font, values): + mapping = list(sorted([(font.getGlyphID(glyph), val) + for glyph, val in values.items()])) + minGlyphID, maxGlyphID = mapping[0][0], mapping[-1][0] + if len(mapping) != maxGlyphID - minGlyphID + 1: + return None + encodedValueSize = 2 + return (4 + len(mapping) * (2 + encodedValueSize), 8, + lambda writer: self.writeFormat8(writer, font, mapping)) + + def writeFormat8(self, writer, font, mapping): + firstGlyphID = mapping[0][0] + writer.writeUShort(8) + writer.writeUShort(firstGlyphID) + writer.writeUShort(len(mapping)) + for _, value in mapping: + writer.writeUShort(font.getGlyphID(value)) + def readFormat0(self, reader, numGlyphs): data = reader.readUShortArray(numGlyphs) return {k:v for (k,v) in enumerate(data)} diff --git a/Tests/ttLib/tables/otConverters_test.py b/Tests/ttLib/tables/otConverters_test.py index 2640966c8..c7796d7c2 100644 --- a/Tests/ttLib/tables/otConverters_test.py +++ b/Tests/ttLib/tables/otConverters_test.py @@ -307,6 +307,24 @@ class AATLookupTest(unittest.TestCase): "FFFF FFFF " # entries[4]= )) + def test_writeFormat8(self): + writer = OTTableWriter() + font = FakeFont(".notdef A B C D E F G H".split()) + self.converter.write(writer, font, {}, { + "B": "B", + "C": "A", + "D": "B", + "E": "C", + "F": "B", + "G": "A", + }) + self.assertEqual(writer.getData(), deHexStr( + "0008 " # format=8 + "0002 " # firstGlyph=B + "0006 " # glyphCount=6 + "0002 0001 0002 0003 0002 0001" # valueArray=[B, A, B, C, B, A] + )) + def test_xmlRead(self): value = self.converter.xmlRead({}, [ ("Substitution", {"in": "A", "out": "A.alt"}, []),