From 2798bf6d1f481125bb5e3643b910fc71d763d7d2 Mon Sep 17 00:00:00 2001 From: Cosimo Lupo Date: Thu, 19 Jul 2018 17:50:43 +0100 Subject: [PATCH 1/3] otTables: print subtable type when can't split in fixSubTableOverFlows --- Lib/fontTools/ttLib/tables/otTables.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Lib/fontTools/ttLib/tables/otTables.py b/Lib/fontTools/ttLib/tables/otTables.py index d00c23361..7017ed7d6 100644 --- a/Lib/fontTools/ttLib/tables/otTables.py +++ b/Lib/fontTools/ttLib/tables/otTables.py @@ -1347,6 +1347,11 @@ def fixSubTableOverFlows(ttf, overflowRecord): try: splitFunc = splitTable[overflowRecord.tableType][subTableType] except KeyError: + log.error( + "Don't know how to split %s lookup type %s", + overflowRecord.tableType, + subTableType, + ) return ok ok = splitFunc(subtable, newSubTable, overflowRecord) From 6e8e431dee54df08dff75d0d1b5c5818a7e8dbc6 Mon Sep 17 00:00:00 2001 From: Cosimo Lupo Date: Thu, 19 Jul 2018 17:52:00 +0100 Subject: [PATCH 2/3] otTables: try to fix MarkBasePos subtable overflows Fixes https://github.com/googlei18n/fontmake/issues/450 --- Lib/fontTools/ttLib/tables/otTables.py | 63 +++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/Lib/fontTools/ttLib/tables/otTables.py b/Lib/fontTools/ttLib/tables/otTables.py index 7017ed7d6..2e7b06ca2 100644 --- a/Lib/fontTools/ttLib/tables/otTables.py +++ b/Lib/fontTools/ttLib/tables/otTables.py @@ -1281,6 +1281,67 @@ def splitPairPos(oldSubTable, newSubTable, overflowRecord): return ok +def splitMarkBasePos(oldSubTable, newSubTable, overflowRecord): + # split half of the mark classes to the new subtable + classCount = oldSubTable.ClassCount + if classCount < 2: + # oh well, not much left to split... + return False + + oldClassCount = classCount // 2 + newClassCount = classCount - oldClassCount + + oldMarkCoverage, oldMarkRecords = [], [] + newMarkCoverage, newMarkRecords = [], [] + for glyphName, markRecord in zip( + oldSubTable.MarkCoverage.glyphs, + oldSubTable.MarkArray.MarkRecord + ): + if markRecord.Class < oldClassCount: + oldMarkCoverage.append(glyphName) + oldMarkRecords.append(markRecord) + else: + newMarkCoverage.append(glyphName) + newMarkRecords.append(markRecord) + + oldBaseRecords, newBaseRecords = [], [] + for rec in oldSubTable.BaseArray.BaseRecord: + oldBaseRecord, newBaseRecord = rec.__class__(), rec.__class__() + oldBaseRecord.BaseAnchor = rec.BaseAnchor[:oldClassCount] + newBaseRecord.BaseAnchor = rec.BaseAnchor[oldClassCount:] + oldBaseRecords.append(oldBaseRecord) + newBaseRecords.append(newBaseRecord) + + newSubTable.Format = oldSubTable.Format + + oldSubTable.MarkCoverage.glyphs = oldMarkCoverage + newSubTable.MarkCoverage = oldSubTable.MarkCoverage.__class__() + newSubTable.MarkCoverage.Format = oldSubTable.MarkCoverage.Format + newSubTable.MarkCoverage.glyphs = newMarkCoverage + + # share the same BaseCoverage in both halves + newSubTable.BaseCoverage = oldSubTable.BaseCoverage + + oldSubTable.ClassCount = oldClassCount + newSubTable.ClassCount = newClassCount + + oldSubTable.MarkArray.MarkRecord = oldMarkRecords + newSubTable.MarkArray = oldSubTable.MarkArray.__class__() + newSubTable.MarkArray.MarkRecord = newMarkRecords + + oldSubTable.MarkArray.MarkCount = len(oldMarkRecords) + newSubTable.MarkArray.MarkCount = len(newMarkRecords) + + oldSubTable.BaseArray.BaseRecord = oldBaseRecords + newSubTable.BaseArray = oldSubTable.BaseArray.__class__() + newSubTable.BaseArray.BaseRecord = newBaseRecords + + oldSubTable.BaseArray.BaseCount = len(oldBaseRecords) + newSubTable.BaseArray.BaseCount = len(newBaseRecords) + + return True + + splitTable = { 'GSUB': { # 1: splitSingleSubst, # 2: splitMultipleSubst, @@ -1295,7 +1356,7 @@ splitTable = { 'GSUB': { # 1: splitSinglePos, 2: splitPairPos, # 3: splitCursivePos, -# 4: splitMarkBasePos, + 4: splitMarkBasePos, # 5: splitMarkLigPos, # 6: splitMarkMarkPos, # 7: splitContextPos, From 0df51c58e006b034ea75c3ca0c140997a84fa328 Mon Sep 17 00:00:00 2001 From: Cosimo Lupo Date: Thu, 19 Jul 2018 17:56:35 +0100 Subject: [PATCH 3/3] otTables_test: add unit test for splitMarkBasePos --- Tests/ttLib/tables/otTables_test.py | 44 +++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/Tests/ttLib/tables/otTables_test.py b/Tests/ttLib/tables/otTables_test.py index e02b22f8d..6fc4c3264 100644 --- a/Tests/ttLib/tables/otTables_test.py +++ b/Tests/ttLib/tables/otTables_test.py @@ -485,6 +485,50 @@ class InsertionMorphActionTest(unittest.TestCase): self.assertEqual(hexStr(writer.getAllData()), "1234fc4300090007") +def test_splitMarkBasePos(): + from fontTools.otlLib.builder import buildAnchor, buildMarkBasePosSubtable + + marks = { + "acutecomb": (0, buildAnchor(0, 600)), + "gravecomb": (0, buildAnchor(0, 590)), + "cedillacomb": (1, buildAnchor(0, 0)), + } + bases = { + "a": { + 0: buildAnchor(350, 500), + 1: None, + }, + "c": { + 0: buildAnchor(300, 700), + 1: buildAnchor(300, 0), + }, + } + glyphOrder = ["a", "c", "acutecomb", "gravecomb", "cedillacomb"] + glyphMap = {g: i for i, g in enumerate(glyphOrder)} + + oldSubTable = buildMarkBasePosSubtable(marks, bases, glyphMap) + oldSubTable.MarkCoverage.Format = oldSubTable.BaseCoverage.Format = 1 + newSubTable = otTables.MarkBasePos() + + ok = otTables.splitMarkBasePos(oldSubTable, newSubTable, overflowRecord=None) + + assert ok + assert oldSubTable.Format == newSubTable.Format + assert oldSubTable.MarkCoverage.glyphs == [ + "acutecomb", "gravecomb" + ] + assert newSubTable.MarkCoverage.glyphs == ["cedillacomb"] + assert newSubTable.MarkCoverage.Format == 1 + assert oldSubTable.BaseCoverage.glyphs == newSubTable.BaseCoverage.glyphs + assert newSubTable.BaseCoverage.Format == 1 + assert oldSubTable.ClassCount == newSubTable.ClassCount == 1 + assert oldSubTable.MarkArray.MarkCount == 2 + assert newSubTable.MarkArray.MarkCount == 1 + assert oldSubTable.BaseArray.BaseCount == newSubTable.BaseArray.BaseCount + assert newSubTable.BaseArray.BaseRecord[0].BaseAnchor[0] is None + assert newSubTable.BaseArray.BaseRecord[1].BaseAnchor[0] == buildAnchor(300, 0) + + if __name__ == "__main__": import sys sys.exit(unittest.main())