From af48e433712498f24f9b344c0d111e04d693e008 Mon Sep 17 00:00:00 2001 From: Sascha Brawer Date: Fri, 22 Jan 2016 14:50:17 +0100 Subject: [PATCH] [otlLib] Move building of MarkLigPos from feaLib to otlLib --- Lib/fontTools/feaLib/builder.py | 13 +--- Lib/fontTools/otlLib/builder.py | 35 ++++++++++- Lib/fontTools/otlLib/builder_test.py | 94 ++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 13 deletions(-) diff --git a/Lib/fontTools/feaLib/builder.py b/Lib/fontTools/feaLib/builder.py index e147538fc..49ebec46c 100644 --- a/Lib/fontTools/feaLib/builder.py +++ b/Lib/fontTools/feaLib/builder.py @@ -984,7 +984,6 @@ class MarkLigPosBuilder(LookupBuilder): def build(self): markClasses = self.buildMarkClasses_(self.marks) - markClassList = sorted(markClasses.keys(), key=markClasses.get) marks = {mark: (markClasses[mc], anchor) for mark, (mc, anchor) in self.marks.items()} ligs = {} @@ -992,16 +991,8 @@ class MarkLigPosBuilder(LookupBuilder): ligs[lig] = [] for c in components: ligs[lig].append({markClasses[mc]: a for mc, a in c.items()}) - - st = otTables.MarkLigPos() - st.Format = 1 - st.MarkCoverage = otl.buildCoverage(marks, self.glyphMap) - st.MarkArray = otl.buildMarkArray(marks, self.glyphMap) - st.ClassCount = max([mc for mc, _ in marks.values()]) + 1 - st.LigatureCoverage = otl.buildCoverage(ligs, self.glyphMap) - st.LigatureArray = \ - otl.buildLigatureArray(ligs, st.ClassCount, self.glyphMap) - return self.buildLookup_([st]) + subtables = otl.buildMarkLigPos(marks, ligs, self.glyphMap) + return self.buildLookup_(subtables) class MarkMarkPosBuilder(LookupBuilder): diff --git a/Lib/fontTools/otlLib/builder.py b/Lib/fontTools/otlLib/builder.py index cef57dd46..d1279d91f 100644 --- a/Lib/fontTools/otlLib/builder.py +++ b/Lib/fontTools/otlLib/builder.py @@ -211,7 +211,7 @@ def buildMarkArray(marks, glyphMap): def buildMarkBasePos(marks, bases, glyphMap): """Build a list of MarkBasePos subtables. - a1, a2, a3, a4 = buildAnchor(500, 100), ... + a1, a2, a3, a4, a5 = buildAnchor(500, 100), ... marks = {"acute": (0, a1), "grave": (0, a1), "cedilla": (1, a2)} bases = {"a": {0: a3, 1: a5}, "b": {0: a4, 1: a5}} """ @@ -232,7 +232,7 @@ def buildMarkBasePos(marks, bases, glyphMap): def buildMarkBasePosSubtable(marks, bases, glyphMap): """Build a single MarkBasePos subtable. - a1, a2, a3, a4 = buildAnchor(500, 100), ... + a1, a2, a3, a4, a5 = buildAnchor(500, 100), ... marks = {"acute": (0, a1), "grave": (0, a1), "cedilla": (1, a2)} bases = {"a": {0: a3, 1: a5}, "b": {0: a4, 1: a5}} """ @@ -246,6 +246,37 @@ def buildMarkBasePosSubtable(marks, bases, glyphMap): return self +def buildMarkLigPos(marks, ligs, glyphMap): + """Build a list of MarkLigPos subtables. + + a1, a2, a3, a4, a5 = buildAnchor(500, 100), ... + marks = {"acute": (0, a1), "grave": (0, a1), "cedilla": (1, a2)} + ligs = {"f_i": [{0: a3, 1: a5}, {0: a4, 1: a5}], "c_t": [{...}, {...}]} + """ + # TODO: Consider splitting into multiple subtables to save space, + # as with MarkBasePos, this would be a trade-off that would need + # profiling. And, depending on how typical fonts are structured, + # it might not be worth doing at all. + return [buildMarkLigPosSubtable(marks, ligs, glyphMap)] + + +def buildMarkLigPosSubtable(marks, ligs, glyphMap): + """Build a single MarkLigPos subtable. + + a1, a2, a3, a4, a5 = buildAnchor(500, 100), ... + marks = {"acute": (0, a1), "grave": (0, a1), "cedilla": (1, a2)} + ligs = {"f_i": [{0: a3, 1: a5}, {0: a4, 1: a5}], "c_t": [{...}, {...}]} + """ + self = ot.MarkLigPos() + self.Format = 1 + self.MarkCoverage = buildCoverage(marks, glyphMap) + self.MarkArray = buildMarkArray(marks, glyphMap) + self.ClassCount = max([mc for mc, _ in marks.values()]) + 1 + self.LigatureCoverage = buildCoverage(ligs, glyphMap) + self.LigatureArray = buildLigatureArray(ligs, self.ClassCount, glyphMap) + return self + + def buildMarkRecord(classID, anchor): assert isinstance(classID, int) assert isinstance(anchor, ot.Anchor) diff --git a/Lib/fontTools/otlLib/builder_test.py b/Lib/fontTools/otlLib/builder_test.py index cc8c650f1..9831c7147 100644 --- a/Lib/fontTools/otlLib/builder_test.py +++ b/Lib/fontTools/otlLib/builder_test.py @@ -632,6 +632,100 @@ class BuilderTest(unittest.TestCase): def test_buildMarkGlyphSetsDef_None(self): self.assertIsNone(builder.buildMarkGlyphSetsDef(None, self.GLYPHMAP)) + def test_buildMarkLigPosSubtable(self): + anchor = builder.buildAnchor + marks = { + "acute": (0, anchor(300, 700)), + "cedilla": (1, anchor(300, -100)), + "grave": (0, anchor(300, 700)) + } + bases = { + "f_i": [{}, {0: anchor(200, 400)}], # nothing on f; only 1 on i + "c_t": [ + {0: anchor(500, 600), 1: anchor(500, -20)}, # c + {0: anchor(1300, 800), 1: anchor(1300, -20)} # t + ] + } + table = builder.buildMarkLigPosSubtable(marks, bases, self.GLYPHMAP) + self.maxDiff = None + self.assertEqual(getXML(table.toXML), + '' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + '') + def test_buildMarkRecord(self): rec = builder.buildMarkRecord(17, builder.buildAnchor(500, -20)) self.assertEqual(getXML(rec.toXML),