Fix for #2293: allow more than one lookahead glyph/class in contextual positioning with "value at end" (#2294)
* add test that fails for #2293 * fixing #2293: rewrite of contextual positioning logic, ensure len(suffix) > 1 yields the correct result; checking more edge cases and raising errors inspired by makeotf * test error cases * only check when we actually have a value * catch one more case that makeotf errors on and we didn't
This commit is contained in:
parent
d601951eab
commit
9825ab0977
@ -473,14 +473,38 @@ class Parser(object):
|
|||||||
assert lookups == []
|
assert lookups == []
|
||||||
return ([], prefix, [None] * len(prefix), values, [], hasMarks)
|
return ([], prefix, [None] * len(prefix), values, [], hasMarks)
|
||||||
else:
|
else:
|
||||||
assert not any(values[: len(prefix)]), values
|
if any(values[: len(prefix)]):
|
||||||
format1 = values[len(prefix) :][: len(glyphs)]
|
raise FeatureLibError(
|
||||||
format2 = values[(len(prefix) + len(glyphs)) :][: len(suffix)]
|
"Positioning cannot be applied in the bactrack glyph sequence, "
|
||||||
values = (
|
"before the marked glyph sequence.",
|
||||||
format2
|
self.cur_token_location_
|
||||||
if format2 and isinstance(format2[0], self.ast.ValueRecord)
|
)
|
||||||
else format1
|
marked_values = values[len(prefix) : len(prefix) + len(glyphs)]
|
||||||
)
|
if any(marked_values):
|
||||||
|
if any(values[len(prefix) + len(glyphs) :]):
|
||||||
|
raise FeatureLibError(
|
||||||
|
"Positioning values are allowed only in the marked glyph "
|
||||||
|
"sequence, or after the final glyph node when only one glyph "
|
||||||
|
"node is marked.",
|
||||||
|
self.cur_token_location_
|
||||||
|
)
|
||||||
|
values = marked_values
|
||||||
|
elif values and values[-1]:
|
||||||
|
if len(glyphs) > 1 or any(values[:-1]):
|
||||||
|
raise FeatureLibError(
|
||||||
|
"Positioning values are allowed only in the marked glyph "
|
||||||
|
"sequence, or after the final glyph node when only one glyph "
|
||||||
|
"node is marked.",
|
||||||
|
self.cur_token_location_
|
||||||
|
)
|
||||||
|
values = values[-1:]
|
||||||
|
elif any(values):
|
||||||
|
raise FeatureLibError(
|
||||||
|
"Positioning values are allowed only in the marked glyph "
|
||||||
|
"sequence, or after the final glyph node when only one glyph "
|
||||||
|
"node is marked.",
|
||||||
|
self.cur_token_location_
|
||||||
|
)
|
||||||
return (prefix, glyphs, lookups, values, suffix, hasMarks)
|
return (prefix, glyphs, lookups, values, suffix, hasMarks)
|
||||||
|
|
||||||
def parse_chain_context_(self):
|
def parse_chain_context_(self):
|
||||||
|
@ -870,6 +870,41 @@ class ParserTest(unittest.TestCase):
|
|||||||
self.assertEqual(glyphstr(pos.prefix), "[A B]")
|
self.assertEqual(glyphstr(pos.prefix), "[A B]")
|
||||||
self.assertEqual(glyphstr(pos.suffix), "comma")
|
self.assertEqual(glyphstr(pos.suffix), "comma")
|
||||||
|
|
||||||
|
def test_gpos_type_1_chained_special_kern_format_valuerecord_format_b_bug2293(self):
|
||||||
|
# https://github.com/fonttools/fonttools/issues/2293
|
||||||
|
doc = self.parse("feature kern {pos [A B] [T Y]' comma a <0 0 0 0>;} kern;")
|
||||||
|
pos = doc.statements[0].statements[0]
|
||||||
|
self.assertIsInstance(pos, ast.SinglePosStatement)
|
||||||
|
[(glyphs, value)] = pos.pos
|
||||||
|
self.assertEqual(glyphstr([glyphs]), "[T Y]")
|
||||||
|
self.assertEqual(value.asFea(), "<0 0 0 0>")
|
||||||
|
self.assertEqual(glyphstr(pos.prefix), "[A B]")
|
||||||
|
self.assertEqual(glyphstr(pos.suffix), "comma a")
|
||||||
|
|
||||||
|
def test_gpos_type_1_chained_exception1(self):
|
||||||
|
with self.assertRaisesRegex(FeatureLibError, "Positioning values are allowed"):
|
||||||
|
doc = self.parse("feature kern {"
|
||||||
|
" pos [A B]' [T Y]' comma a <0 0 0 0>;"
|
||||||
|
"} kern;")
|
||||||
|
|
||||||
|
def test_gpos_type_1_chained_exception2(self):
|
||||||
|
with self.assertRaisesRegex(FeatureLibError, "Positioning values are allowed"):
|
||||||
|
doc = self.parse("feature kern {"
|
||||||
|
" pos [A B]' <0 0 0 0> [T Y]' comma a <0 0 0 0>;"
|
||||||
|
"} kern;")
|
||||||
|
|
||||||
|
def test_gpos_type_1_chained_exception3(self):
|
||||||
|
with self.assertRaisesRegex(FeatureLibError, "Positioning cannot be applied"):
|
||||||
|
doc = self.parse("feature kern {"
|
||||||
|
" pos [A B] <0 0 0 0> [T Y]' comma a <0 0 0 0>;"
|
||||||
|
"} kern;")
|
||||||
|
|
||||||
|
def test_gpos_type_1_chained_exception4(self):
|
||||||
|
with self.assertRaisesRegex(FeatureLibError, "Positioning values are allowed"):
|
||||||
|
doc = self.parse("feature kern {"
|
||||||
|
" pos a' b c 123 d;"
|
||||||
|
"} kern;")
|
||||||
|
|
||||||
def test_gpos_type_2_format_a(self):
|
def test_gpos_type_2_format_a(self):
|
||||||
doc = self.parse("feature kern {"
|
doc = self.parse("feature kern {"
|
||||||
" pos [T V] -60 [a b c] <1 2 3 4>;"
|
" pos [T V] -60 [a b c] <1 2 3 4>;"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user