diff --git a/Lib/fontTools/feaLib/builder.py b/Lib/fontTools/feaLib/builder.py index 05a15173f..9ff49b29e 100644 --- a/Lib/fontTools/feaLib/builder.py +++ b/Lib/fontTools/feaLib/builder.py @@ -714,14 +714,7 @@ class LookupBuilder(object): return {} def buildLookup_(self, subtables): - lookup = otTables.Lookup() - lookup.LookupFlag = self.lookupflag - lookup.LookupType = self.lookup_type - lookup.SubTable = subtables - lookup.SubTableCount = len(subtables) - if self.markFilterSet is not None: - lookup.MarkFilteringSet = self.markFilterSet - return lookup + return otl.buildLookup(subtables, self.lookupflag, self.markFilterSet) def buildMarkClasses_(self, marks): """{"cedilla": ("BOTTOM", ast.Anchor), ...} --> {"BOTTOM":0, "TOP":1} diff --git a/Lib/fontTools/otlLib/builder.py b/Lib/fontTools/otlLib/builder.py index 01643dcfa..2bbb45186 100644 --- a/Lib/fontTools/otlLib/builder.py +++ b/Lib/fontTools/otlLib/builder.py @@ -10,6 +10,37 @@ def buildCoverage(glyphs, glyphMap): return self +LOOKUP_FLAG_RIGHT_TO_LEFT = 0x0001 +LOOKUP_FLAG_IGNORE_BASE_GLYPHS = 0x0002 +LOOKUP_FLAG_IGNORE_LIGATURES = 0x0004 +LOOKUP_FLAG_IGNORE_MARKS = 0x0008 +LOOKUP_FLAG_USE_MARK_FILTERING_SET = 0x0010 + + +def buildLookup(subtables, flags=0, markFilterSet=None): + if not subtables: + return None + assert all(t.LookupType == subtables[0].LookupType for t in subtables), \ + ("all subtables must have the same LookupType; got %s" % + repr([t.LookupType for t in subtables])) + self = ot.Lookup() + self.LookupType = subtables[0].LookupType + self.LookupFlag = flags + self.SubTable = subtables + self.SubTableCount = len(subtables) + if markFilterSet is not None: + assert self.LookupFlag & LOOKUP_FLAG_USE_MARK_FILTERING_SET, \ + ("if markFilterSet is not None, flags must set " + "LOOKUP_FLAG_USE_MARK_FILTERING_SET; flags=0x%04x" % flags) + assert isinstance(markFilterSet, int), markFilterSet + self.MarkFilteringSet = markFilterSet + else: + assert (self.LookupFlag & LOOKUP_FLAG_USE_MARK_FILTERING_SET) == 0, \ + ("if markFilterSet is None, flags must not set " + "LOOKUP_FLAG_USE_MARK_FILTERING_SET; flags=0x%04x" % flags) + return self + + # GSUB diff --git a/Lib/fontTools/otlLib/builder_test.py b/Lib/fontTools/otlLib/builder_test.py index 3238c71a8..eb7b2eab6 100644 --- a/Lib/fontTools/otlLib/builder_test.py +++ b/Lib/fontTools/otlLib/builder_test.py @@ -14,6 +14,13 @@ class BuilderTest(unittest.TestCase): ANCHOR2 = builder.buildAnchor(22, -22) ANCHOR3 = builder.buildAnchor(33, -33) + def __init__(self, methodName): + unittest.TestCase.__init__(self, methodName) + # Python 3 renamed assertRaisesRegexp to assertRaisesRegex, + # and fires deprecation warnings if a program uses the old name. + if not hasattr(self, "assertRaisesRegex"): + self.assertRaisesRegex = self.assertRaisesRegexp + def test_buildAnchor_format1(self): anchor = builder.buildAnchor(23, 42) self.assertEqual(getXML(anchor.toXML), @@ -256,6 +263,65 @@ class BuilderTest(unittest.TestCase): ' ' '') + def test_buildLookup(self): + s1 = builder.buildSingleSubst({"one": "two"}) + s2 = builder.buildSingleSubst({"three": "four"}) + lookup = builder.buildLookup([s1, s2], flags=7) + self.assertEqual(getXML(lookup.toXML), + '' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + '') + + def test_buildLookup_badFlags(self): + s = builder.buildSingleSubst({"one": "two"}) + self.assertRaisesRegex( + AssertionError, "if markFilterSet is None, " + "flags must not set LOOKUP_FLAG_USE_MARK_FILTERING_SET; " + "flags=0x0010", + builder.buildLookup, [s], + builder.LOOKUP_FLAG_USE_MARK_FILTERING_SET, None) + self.assertRaisesRegex( + AssertionError, "if markFilterSet is not None, " + "flags must set LOOKUP_FLAG_USE_MARK_FILTERING_SET; " + "flags=0x0004", + builder.buildLookup, [s], + builder.LOOKUP_FLAG_IGNORE_LIGATURES, 777) + + def test_buildLookup_conflictingSubtableTypes(self): + s1 = builder.buildSingleSubst({"one": "two"}) + s2 = builder.buildAlternateSubst({"one": ["two", "three"]}) + self.assertRaisesRegex( + AssertionError, "all subtables must have the same LookupType", + builder.buildLookup, [s1, s2]) + + def test_buildLookup_noSubtables(self): + self.assertIsNone(builder.buildLookup([])) + self.assertIsNone(builder.buildLookup(None)) + + def test_buildLookup_markFilterSet(self): + s = builder.buildSingleSubst({"one": "two"}) + flags = (builder.LOOKUP_FLAG_RIGHT_TO_LEFT | + builder.LOOKUP_FLAG_USE_MARK_FILTERING_SET) + lookup = builder.buildLookup([s], flags, markFilterSet=999) + self.assertEqual(getXML(lookup.toXML), + '' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + '') + def test_buildMarkGlyphSetsDef(self): marksets = builder.buildMarkGlyphSetsDef( [{"acute", "grave"}, {"cedilla", "grave"}], self.GLYPHMAP)