[feaLib] Emit context-free chains to single substitutions

Resolves https://github.com/behdad/fonttools/issues/509
This commit is contained in:
Sascha Brawer 2016-02-04 16:45:05 +01:00
parent dba1d6666b
commit 27e23f9a95
6 changed files with 88 additions and 6 deletions

View File

@ -451,14 +451,16 @@ class ReverseChainSingleSubstStatement(Statement):
class SingleSubstStatement(Statement):
def __init__(self, location, mapping, prefix, suffix):
def __init__(self, location, mapping, prefix, suffix, forceChain):
Statement.__init__(self, location)
self.mapping, self.prefix, self.suffix = mapping, prefix, suffix
self.forceChain = forceChain
def build(self, builder):
prefix = [p.glyphSet() for p in self.prefix]
suffix = [s.glyphSet() for s in self.suffix]
builder.add_single_subst(self.location, prefix, suffix, self.mapping)
builder.add_single_subst(self.location, prefix, suffix, self.mapping,
self.forceChain)
class ScriptStatement(Statement):

View File

@ -548,13 +548,13 @@ class Builder(object):
lookup = self.get_lookup_(location, ReverseChainSingleSubstBuilder)
lookup.substitutions.append((old_prefix, old_suffix, mapping))
def add_single_subst(self, location, prefix, suffix, mapping):
def add_single_subst(self, location, prefix, suffix, mapping, forceChain):
if self.cur_feature_name_ == "aalt":
for (from_glyph, to_glyph) in mapping.items():
alts = self.aalt_alternates_.setdefault(from_glyph, set())
alts.add(to_glyph)
return
if prefix or suffix:
if prefix or suffix or forceChain:
chain = self.get_lookup_(location, ChainContextSubstBuilder)
sub = self.get_chained_lookup_(location, SingleSubstBuilder)
sub.mapping.update(mapping)

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 bug506
bug463 bug501 bug502 bug505 bug506 bug509
""".split()
def __init__(self, methodName):

View File

@ -578,7 +578,8 @@ class Parser(object):
(len(glyphs), len(replacements)), location)
return ast.SingleSubstStatement(location,
dict(zip(glyphs, replacements)),
old_prefix, old_suffix)
old_prefix, old_suffix,
forceChain=hasMarks)
# GSUB lookup type 2: Multiple substitution.
# Format: "substitute f_f_i by f f i;"

View File

@ -0,0 +1,5 @@
@LETTER_A = [A A.sc A.alt1];
feature test {
ignore sub A;
sub @LETTER_A' by a;
} test;

View File

@ -0,0 +1,74 @@
<?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=2 -->
<ChainContextSubst index="0" Format="3">
<!-- BacktrackGlyphCount=0 -->
<!-- InputGlyphCount=1 -->
<InputCoverage index="0">
<Glyph value="A"/>
</InputCoverage>
<!-- LookAheadGlyphCount=0 -->
<!-- SubstCount=0 -->
</ChainContextSubst>
<ChainContextSubst index="1" Format="3">
<!-- BacktrackGlyphCount=0 -->
<!-- InputGlyphCount=1 -->
<InputCoverage index="0">
<Glyph value="A"/>
<Glyph value="A.sc"/>
<Glyph value="A.alt1"/>
</InputCoverage>
<!-- LookAheadGlyphCount=0 -->
<!-- SubstCount=1 -->
<SubstLookupRecord index="0">
<SequenceIndex value="0"/>
<LookupListIndex value="1"/>
</SubstLookupRecord>
</ChainContextSubst>
</Lookup>
<Lookup index="1">
<!-- LookupType=1 -->
<LookupFlag value="0"/>
<!-- SubTableCount=1 -->
<SingleSubst index="0">
<Substitution in="A" out="a"/>
<Substitution in="A.alt1" out="a"/>
<Substitution in="A.sc" out="a"/>
</SingleSubst>
</Lookup>
</LookupList>
</GSUB>
</ttFont>