[feaLib] Emit chains to LigatureSubst even without backtrack or lookahead

https://github.com/behdad/fonttools/issues/506
This commit is contained in:
Sascha Brawer 2016-02-04 15:31:29 +01:00
parent ea4a4e34b3
commit dba1d6666b
6 changed files with 86 additions and 13 deletions

View File

@ -326,17 +326,19 @@ class LigatureCaretByPosStatement(Statement):
class LigatureSubstStatement(Statement):
def __init__(self, location, prefix, glyphs, suffix, replacement):
def __init__(self, location, prefix, glyphs, suffix, replacement,
forceChain):
Statement.__init__(self, location)
self.prefix, self.glyphs, self.suffix = (prefix, glyphs, suffix)
self.replacement = replacement
self.replacement, self.forceChain = replacement, forceChain
def build(self, builder):
prefix = [p.glyphSet() for p in self.prefix]
glyphs = [g.glyphSet() for g in self.glyphs]
suffix = [s.glyphSet() for s in self.suffix]
builder.add_ligature_subst(
self.location, prefix, glyphs, suffix, self.replacement)
self.location, prefix, glyphs, suffix, self.replacement,
self.forceChain)
class LookupFlagStatement(Statement):

View File

@ -512,8 +512,8 @@ class Builder(object):
self.aalt_features_.append((location, featureName))
def add_ligature_subst(self, location,
prefix, glyphs, suffix, replacement):
if prefix or suffix:
prefix, glyphs, suffix, replacement, forceChain):
if prefix or suffix or forceChain:
chain = self.get_lookup_(location, ChainContextSubstBuilder)
lookup = self.get_chained_lookup_(location, LigatureSubstBuilder)
chain.substitutions.append((prefix, glyphs, suffix, [lookup]))

View File

@ -52,7 +52,7 @@ class BuilderTest(unittest.TestCase):
spec5f_ii_1
spec5h1 spec6b_ii spec6d2 spec6e spec6f spec6h_ii spec6h_iii_1 spec8a
spec9b spec9c1 spec9c2 spec9c3
bug463 bug501 bug502 bug505
bug463 bug501 bug502 bug505 bug506
""".split()
def __init__(self, methodName):

View File

@ -241,12 +241,13 @@ class Parser(object):
def parse_glyph_pattern_(self, vertical):
prefix, glyphs, lookups, values, suffix = ([], [], [], [], [])
hasMarks = False
while self.next_token_ not in {"by", "from", ";"}:
gc = self.parse_glyphclass_(accept_glyphname=True)
marked = False
if self.next_token_ == "'":
self.expect_symbol_("'")
marked = True
hasMarks = marked = True
if marked:
glyphs.append(gc)
elif glyphs:
@ -277,18 +278,18 @@ class Parser(object):
if not glyphs and not suffix: # eg., "sub f f i by"
assert lookups == []
return ([], prefix, [None] * len(prefix), values, [])
return ([], prefix, [None] * len(prefix), values, [], hasMarks)
else:
assert not any(values[:len(prefix)]), values
values = values[len(prefix):][:len(glyphs)]
return (prefix, glyphs, lookups, values, suffix)
return (prefix, glyphs, lookups, values, suffix, hasMarks)
def parse_ignore_(self):
assert self.is_cur_keyword_("ignore")
location = self.cur_token_location_
self.advance_lexer_()
if self.cur_token_ in ["substitute", "sub"]:
prefix, glyphs, lookups, values, suffix = \
prefix, glyphs, lookups, values, suffix, hasMarks = \
self.parse_glyph_pattern_(vertical=False)
self.expect_symbol_(";")
if any(lookups):
@ -423,7 +424,7 @@ class Parser(object):
return self.parse_position_mark_(enumerated, vertical)
location = self.cur_token_location_
prefix, glyphs, lookups, values, suffix = \
prefix, glyphs, lookups, values, suffix, hasMarks = \
self.parse_glyph_pattern_(vertical)
self.expect_symbol_(";")
@ -518,7 +519,7 @@ class Parser(object):
assert self.cur_token_ in {"substitute", "sub", "reversesub", "rsub"}
location = self.cur_token_location_
reverse = self.cur_token_ in {"reversesub", "rsub"}
old_prefix, old, lookups, values, old_suffix = \
old_prefix, old, lookups, values, old_suffix, hasMarks = \
self.parse_glyph_pattern_(vertical=False)
if any(values):
raise FeatureLibError(
@ -597,7 +598,7 @@ class Parser(object):
num_lookups == 0):
return ast.LigatureSubstStatement(
location, old_prefix, old, old_suffix,
list(new[0].glyphSet())[0])
list(new[0].glyphSet())[0], forceChain=hasMarks)
# GSUB lookup type 8: Reverse chaining substitution.
if reverse:

View File

@ -0,0 +1,4 @@
# https://github.com/behdad/fonttools/issues/506
feature test {
sub f' i' by f_i;
} test;

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<ttFont sfntVersion="true" ttLibVersion="3.0">
<GSUB>
<Version value="1.0"/>
<ScriptList>
<!-- ScriptCount=1 -->
<ScriptRecord index="0">
<ScriptTag value="DFLT"/>
<Script>
<DefaultLangSys>
<ReqFeatureIndex value="65535"/>
<!-- FeatureCount=1 -->
<FeatureIndex index="0" value="0"/>
</DefaultLangSys>
<!-- LangSysCount=0 -->
</Script>
</ScriptRecord>
</ScriptList>
<FeatureList>
<!-- FeatureCount=1 -->
<FeatureRecord index="0">
<FeatureTag value="test"/>
<Feature>
<!-- LookupCount=1 -->
<LookupListIndex index="0" value="0"/>
</Feature>
</FeatureRecord>
</FeatureList>
<LookupList>
<!-- LookupCount=2 -->
<Lookup index="0">
<!-- LookupType=6 -->
<LookupFlag value="0"/>
<!-- SubTableCount=1 -->
<ChainContextSubst index="0" Format="3">
<!-- BacktrackGlyphCount=0 -->
<!-- InputGlyphCount=2 -->
<InputCoverage index="0">
<Glyph value="f"/>
</InputCoverage>
<InputCoverage index="1">
<Glyph value="i"/>
</InputCoverage>
<!-- LookAheadGlyphCount=0 -->
<!-- SubstCount=1 -->
<SubstLookupRecord index="0">
<SequenceIndex value="0"/>
<LookupListIndex value="1"/>
</SubstLookupRecord>
</ChainContextSubst>
</Lookup>
<Lookup index="1">
<!-- LookupType=4 -->
<LookupFlag value="0"/>
<!-- SubTableCount=1 -->
<LigatureSubst index="0">
<LigatureSet glyph="f">
<Ligature components="i" glyph="f_i"/>
</LigatureSet>
</LigatureSubst>
</Lookup>
</LookupList>
</GSUB>
</ttFont>