From 2af0adde6c082d87efaee5794a126ee4b02d726f Mon Sep 17 00:00:00 2001 From: Sascha Brawer Date: Wed, 9 Dec 2015 17:14:13 +0100 Subject: [PATCH] [feaLib] Parse Mark-to-mark attachment positioning statements No output is produced yet; this will come in an upcoming change. --- Lib/fontTools/feaLib/ast.py | 11 +++++++++++ Lib/fontTools/feaLib/parser.py | 15 +++++++++++++++ Lib/fontTools/feaLib/parser_test.py | 29 +++++++++++++++++++++++++---- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/Lib/fontTools/feaLib/ast.py b/Lib/fontTools/feaLib/ast.py index c891e0213..f0e6b3512 100644 --- a/Lib/fontTools/feaLib/ast.py +++ b/Lib/fontTools/feaLib/ast.py @@ -198,6 +198,17 @@ class MarkLigPosStatement(Statement): builder.add_mark_lig_pos(self.location, self.ligatures, self.marks) +class MarkMarkPosStatement(Statement): + def __init__(self, location, baseMarks, marks): + Statement.__init__(self, location) + self.baseMarks, self.marks = baseMarks, marks + + def build(self, builder): + # TODO: Implement this. + # builder.add_mark_mark_pos(self.location, self.baseMarks, self.marks) + pass + + class MultipleSubstStatement(Statement): def __init__(self, location, glyph, replacement): Statement.__init__(self, location) diff --git a/Lib/fontTools/feaLib/parser.py b/Lib/fontTools/feaLib/parser.py index 1e4c9f6e6..90e0c32e8 100644 --- a/Lib/fontTools/feaLib/parser.py +++ b/Lib/fontTools/feaLib/parser.py @@ -286,6 +286,8 @@ class Parser(object): return self.parse_position_base_(enumerated, vertical) elif self.next_token_ == "ligature": # GPOS type 5 return self.parse_position_ligature_(enumerated, vertical) + elif self.next_token_ == "mark": # GPOS type 6 + return self.parse_position_mark_(enumerated, vertical) location = self.cur_token_location_ gc2, value2 = None, None @@ -353,6 +355,19 @@ class Parser(object): self.expect_symbol_(";") return ast.MarkLigPosStatement(location, ligatures, marks) + def parse_position_mark_(self, enumerated, vertical): + location = self.cur_token_location_ + self.expect_keyword_("mark") + if enumerated: + raise FeatureLibError( + '"enumerate" is not allowed with ' + 'mark-to-mark attachment positioning', + location) + baseMarks = self.parse_glyphclass_(accept_glyphname=True) + marks = self.parse_anchor_marks_() + self.expect_symbol_(";") + return ast.MarkMarkPosStatement(location, baseMarks, marks) + def parse_script_(self): assert self.is_cur_keyword_("script") location, script = self.cur_token_location_, self.expect_script_tag_() diff --git a/Lib/fontTools/feaLib/parser_test.py b/Lib/fontTools/feaLib/parser_test.py index f818fa70b..11f2eab1c 100644 --- a/Lib/fontTools/feaLib/parser_test.py +++ b/Lib/fontTools/feaLib/parser_test.py @@ -456,10 +456,8 @@ class ParserTest(unittest.TestCase): self.assertEqual(type(pos), ast.MarkBasePosStatement) self.assertEqual(pos.base, {"a", "e", "o", "u"}) (a1, m1), (a2, m2) = pos.marks - self.assertEqual((a1.x, a1.y), (250, 450)) - self.assertEqual(m1.name, "TOP_MARKS") - self.assertEqual((a2.x, a2.y), (210, -10)) - self.assertEqual(m2.name, "BOTTOM_MARKS") + self.assertEqual((a1.x, a1.y, m1.name), (250, 450, "TOP_MARKS")) + self.assertEqual((a2.x, a2.y, m2.name), (210, -10, "BOTTOM_MARKS")) def test_gpos_type_4_enumerated(self): self.assertRaisesRegex( @@ -510,6 +508,29 @@ class ParserTest(unittest.TestCase): " ligComponent ;" "} test;") + def test_gpos_type_6(self): + doc = self.parse( + "markClass damma @MARK_CLASS_1;" + "feature test {" + " position mark hamza mark @MARK_CLASS_1;" + "} test;") + pos = doc.statements[-1].statements[0] + self.assertEqual(type(pos), ast.MarkMarkPosStatement) + self.assertEqual(pos.baseMarks, {"hamza"}) + [(a1, m1)] = pos.marks + self.assertEqual((a1.x, a1.y, m1.name), (221, 301, "MARK_CLASS_1")) + + def test_gpos_type_6_enumerated(self): + self.assertRaisesRegex( + FeatureLibError, + '"enumerate" is not allowed with ' + 'mark-to-mark attachment positioning', + self.parse, + "markClass damma @MARK_CLASS_1;" + "feature test {" + " enum pos mark hamza mark @MARK_CLASS_1;" + "} test;") + def test_markClass(self): doc = self.parse("markClass [acute grave] @MARKS;" "feature test {"