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 == []
|
||||
return ([], prefix, [None] * len(prefix), values, [], hasMarks)
|
||||
else:
|
||||
assert not any(values[: len(prefix)]), values
|
||||
format1 = values[len(prefix) :][: len(glyphs)]
|
||||
format2 = values[(len(prefix) + len(glyphs)) :][: len(suffix)]
|
||||
values = (
|
||||
format2
|
||||
if format2 and isinstance(format2[0], self.ast.ValueRecord)
|
||||
else format1
|
||||
)
|
||||
if any(values[: len(prefix)]):
|
||||
raise FeatureLibError(
|
||||
"Positioning cannot be applied in the bactrack glyph sequence, "
|
||||
"before the marked glyph sequence.",
|
||||
self.cur_token_location_
|
||||
)
|
||||
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)
|
||||
|
||||
def parse_chain_context_(self):
|
||||
|
@ -870,6 +870,41 @@ class ParserTest(unittest.TestCase):
|
||||
self.assertEqual(glyphstr(pos.prefix), "[A B]")
|
||||
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):
|
||||
doc = self.parse("feature kern {"
|
||||
" pos [T V] -60 [a b c] <1 2 3 4>;"
|
||||
|
Loading…
x
Reference in New Issue
Block a user