Merge pull request #3559 from fonttools/reuse-chain-multi-subst
[feaLib] try reuse existing inline chained multiple subst lookups when possible
This commit is contained in:
commit
4b030d2db8
@ -1286,10 +1286,7 @@ class Builder(object):
|
|||||||
self, location, prefix, glyph, suffix, replacements, forceChain=False
|
self, location, prefix, glyph, suffix, replacements, forceChain=False
|
||||||
):
|
):
|
||||||
if prefix or suffix or forceChain:
|
if prefix or suffix or forceChain:
|
||||||
chain = self.get_lookup_(location, ChainContextSubstBuilder)
|
self.add_multi_subst_chained_(location, prefix, glyph, suffix, replacements)
|
||||||
sub = self.get_chained_lookup_(location, MultipleSubstBuilder)
|
|
||||||
sub.mapping[glyph] = replacements
|
|
||||||
chain.rules.append(ChainContextualRule(prefix, [{glyph}], suffix, [sub]))
|
|
||||||
return
|
return
|
||||||
lookup = self.get_lookup_(location, MultipleSubstBuilder)
|
lookup = self.get_lookup_(location, MultipleSubstBuilder)
|
||||||
if glyph in lookup.mapping:
|
if glyph in lookup.mapping:
|
||||||
@ -1369,7 +1366,7 @@ class Builder(object):
|
|||||||
# https://github.com/fonttools/fonttools/issues/512
|
# https://github.com/fonttools/fonttools/issues/512
|
||||||
# https://github.com/fonttools/fonttools/issues/2150
|
# https://github.com/fonttools/fonttools/issues/2150
|
||||||
chain = self.get_lookup_(location, ChainContextSubstBuilder)
|
chain = self.get_lookup_(location, ChainContextSubstBuilder)
|
||||||
sub = chain.find_chainable_single_subst(mapping)
|
sub = chain.find_chainable_subst(mapping, SingleSubstBuilder)
|
||||||
if sub is None:
|
if sub is None:
|
||||||
sub = self.get_chained_lookup_(location, SingleSubstBuilder)
|
sub = self.get_chained_lookup_(location, SingleSubstBuilder)
|
||||||
sub.mapping.update(mapping)
|
sub.mapping.update(mapping)
|
||||||
@ -1377,6 +1374,19 @@ class Builder(object):
|
|||||||
ChainContextualRule(prefix, [list(mapping.keys())], suffix, [sub])
|
ChainContextualRule(prefix, [list(mapping.keys())], suffix, [sub])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def add_multi_subst_chained_(self, location, prefix, glyph, suffix, replacements):
|
||||||
|
if not all(prefix) or not all(suffix):
|
||||||
|
raise FeatureLibError(
|
||||||
|
"Empty glyph class in contextual substitution", location
|
||||||
|
)
|
||||||
|
# https://github.com/fonttools/fonttools/issues/3551
|
||||||
|
chain = self.get_lookup_(location, ChainContextSubstBuilder)
|
||||||
|
sub = chain.find_chainable_subst({glyph: replacements}, MultipleSubstBuilder)
|
||||||
|
if sub is None:
|
||||||
|
sub = self.get_chained_lookup_(location, MultipleSubstBuilder)
|
||||||
|
sub.mapping[glyph] = replacements
|
||||||
|
chain.rules.append(ChainContextualRule(prefix, [{glyph}], suffix, [sub]))
|
||||||
|
|
||||||
# GSUB 8
|
# GSUB 8
|
||||||
def add_reverse_chain_single_subst(self, location, old_prefix, old_suffix, mapping):
|
def add_reverse_chain_single_subst(self, location, old_prefix, old_suffix, mapping):
|
||||||
if not mapping:
|
if not mapping:
|
||||||
|
@ -544,6 +544,10 @@ class ChainContextualBuilder(LookupBuilder):
|
|||||||
f"{classRuleAttr}Count",
|
f"{classRuleAttr}Count",
|
||||||
getattr(setForThisRule, f"{classRuleAttr}Count") + 1,
|
getattr(setForThisRule, f"{classRuleAttr}Count") + 1,
|
||||||
)
|
)
|
||||||
|
for i, classSet in enumerate(classSets):
|
||||||
|
if not getattr(classSet, classRuleAttr):
|
||||||
|
# class sets can be null so replace nop sets with None
|
||||||
|
classSets[i] = None
|
||||||
setattr(st, self.ruleSetAttr_(format=2, chaining=chaining), classSets)
|
setattr(st, self.ruleSetAttr_(format=2, chaining=chaining), classSets)
|
||||||
setattr(
|
setattr(
|
||||||
st, self.ruleSetAttr_(format=2, chaining=chaining) + "Count", len(classSets)
|
st, self.ruleSetAttr_(format=2, chaining=chaining) + "Count", len(classSets)
|
||||||
@ -781,14 +785,14 @@ class ChainContextSubstBuilder(ChainContextualBuilder):
|
|||||||
)
|
)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def find_chainable_single_subst(self, mapping):
|
def find_chainable_subst(self, mapping, builder_class):
|
||||||
"""Helper for add_single_subst_chained_()"""
|
"""Helper for add_{single,multi}_subst_chained_()"""
|
||||||
res = None
|
res = None
|
||||||
for rule in self.rules[::-1]:
|
for rule in self.rules[::-1]:
|
||||||
if rule.is_subtable_break:
|
if rule.is_subtable_break:
|
||||||
return res
|
return res
|
||||||
for sub in rule.lookups:
|
for sub in rule.lookups:
|
||||||
if isinstance(sub, SingleSubstBuilder) and not any(
|
if isinstance(sub, builder_class) and not any(
|
||||||
g in mapping and mapping[g] != sub.mapping[g] for g in sub.mapping
|
g in mapping and mapping[g] != sub.mapping[g] for g in sub.mapping
|
||||||
):
|
):
|
||||||
res = sub
|
res = sub
|
||||||
|
@ -48,6 +48,7 @@ def makeTTFont():
|
|||||||
grave acute dieresis macron circumflex cedilla umlaut ogonek caron
|
grave acute dieresis macron circumflex cedilla umlaut ogonek caron
|
||||||
damma hamza sukun kasratan lam_meem_jeem noon.final noon.initial
|
damma hamza sukun kasratan lam_meem_jeem noon.final noon.initial
|
||||||
by feature lookup sub table uni0327 uni0328 e.fina
|
by feature lookup sub table uni0327 uni0328 e.fina
|
||||||
|
idotbelow idotless iogonek acutecomb brevecomb ogonekcomb dotbelowcomb
|
||||||
""".split()
|
""".split()
|
||||||
glyphs.extend("cid{:05d}".format(cid) for cid in range(800, 1001 + 1))
|
glyphs.extend("cid{:05d}".format(cid) for cid in range(800, 1001 + 1))
|
||||||
font = TTFont()
|
font = TTFont()
|
||||||
@ -82,6 +83,7 @@ class BuilderTest(unittest.TestCase):
|
|||||||
GSUB_5_formats delete_glyph STAT_test STAT_test_elidedFallbackNameID
|
GSUB_5_formats delete_glyph STAT_test STAT_test_elidedFallbackNameID
|
||||||
variable_scalar_valuerecord variable_scalar_anchor variable_conditionset
|
variable_scalar_valuerecord variable_scalar_anchor variable_conditionset
|
||||||
variable_mark_anchor duplicate_lookup_reference
|
variable_mark_anchor duplicate_lookup_reference
|
||||||
|
contextual_inline_multi_sub_format_2
|
||||||
""".split()
|
""".split()
|
||||||
|
|
||||||
VARFONT_AXES = [
|
VARFONT_AXES = [
|
||||||
|
17
Tests/feaLib/data/contextual_inline_multi_sub_format_2.fea
Normal file
17
Tests/feaLib/data/contextual_inline_multi_sub_format_2.fea
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# reduced from the ccmp feature in Oswald
|
||||||
|
feature ccmp {
|
||||||
|
lookup ccmp_Other_1 {
|
||||||
|
@CombiningTopAccents = [acutecomb brevecomb];
|
||||||
|
@CombiningNonTopAccents = [dotbelowcomb ogonekcomb];
|
||||||
|
lookupflag UseMarkFilteringSet @CombiningTopAccents;
|
||||||
|
# we should only generate two lookups; one contextual and one multiple sub,
|
||||||
|
# containing 'sub idotbelow by idotless dotbelowcomb' and
|
||||||
|
# 'sub iogonek by idotless ogonekcomb'
|
||||||
|
sub idotbelow' @CombiningTopAccents by idotless dotbelowcomb;
|
||||||
|
sub iogonek' @CombiningTopAccents by idotless ogonekcomb;
|
||||||
|
sub idotbelow' @CombiningNonTopAccents @CombiningTopAccents by idotless dotbelowcomb;
|
||||||
|
sub iogonek' @CombiningNonTopAccents @CombiningTopAccents by idotless ogonekcomb;
|
||||||
|
} ccmp_Other_1;
|
||||||
|
} ccmp;
|
||||||
|
|
||||||
|
|
135
Tests/feaLib/data/contextual_inline_multi_sub_format_2.ttx
Normal file
135
Tests/feaLib/data/contextual_inline_multi_sub_format_2.ttx
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.53">
|
||||||
|
|
||||||
|
<GDEF>
|
||||||
|
<Version value="0x00010002"/>
|
||||||
|
<MarkGlyphSetsDef>
|
||||||
|
<MarkSetTableFormat value="1"/>
|
||||||
|
<!-- MarkSetCount=1 -->
|
||||||
|
<Coverage index="0">
|
||||||
|
<Glyph value="acutecomb"/>
|
||||||
|
<Glyph value="brevecomb"/>
|
||||||
|
</Coverage>
|
||||||
|
</MarkGlyphSetsDef>
|
||||||
|
</GDEF>
|
||||||
|
|
||||||
|
<GSUB>
|
||||||
|
<Version value="0x00010000"/>
|
||||||
|
<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="ccmp"/>
|
||||||
|
<Feature>
|
||||||
|
<!-- LookupCount=1 -->
|
||||||
|
<LookupListIndex index="0" value="0"/>
|
||||||
|
</Feature>
|
||||||
|
</FeatureRecord>
|
||||||
|
</FeatureList>
|
||||||
|
<LookupList>
|
||||||
|
<!-- LookupCount=2 -->
|
||||||
|
<Lookup index="0">
|
||||||
|
<LookupType value="6"/>
|
||||||
|
<LookupFlag value="16"/><!-- useMarkFilteringSet -->
|
||||||
|
<!-- SubTableCount=1 -->
|
||||||
|
<ChainContextSubst index="0" Format="2">
|
||||||
|
<Coverage>
|
||||||
|
<Glyph value="idotbelow"/>
|
||||||
|
<Glyph value="iogonek"/>
|
||||||
|
</Coverage>
|
||||||
|
<BacktrackClassDef>
|
||||||
|
</BacktrackClassDef>
|
||||||
|
<InputClassDef>
|
||||||
|
<ClassDef glyph="idotbelow" class="1"/>
|
||||||
|
<ClassDef glyph="iogonek" class="2"/>
|
||||||
|
</InputClassDef>
|
||||||
|
<LookAheadClassDef>
|
||||||
|
<ClassDef glyph="acutecomb" class="1"/>
|
||||||
|
<ClassDef glyph="brevecomb" class="1"/>
|
||||||
|
<ClassDef glyph="dotbelowcomb" class="2"/>
|
||||||
|
<ClassDef glyph="ogonekcomb" class="2"/>
|
||||||
|
</LookAheadClassDef>
|
||||||
|
<!-- ChainSubClassSetCount=3 -->
|
||||||
|
<ChainSubClassSet index="0" empty="1"/>
|
||||||
|
<ChainSubClassSet index="1">
|
||||||
|
<!-- ChainSubClassRuleCount=2 -->
|
||||||
|
<ChainSubClassRule index="0">
|
||||||
|
<!-- BacktrackGlyphCount=0 -->
|
||||||
|
<!-- InputGlyphCount=1 -->
|
||||||
|
<!-- LookAheadGlyphCount=1 -->
|
||||||
|
<LookAhead index="0" value="1"/>
|
||||||
|
<!-- SubstCount=1 -->
|
||||||
|
<SubstLookupRecord index="0">
|
||||||
|
<SequenceIndex value="0"/>
|
||||||
|
<LookupListIndex value="1"/>
|
||||||
|
</SubstLookupRecord>
|
||||||
|
</ChainSubClassRule>
|
||||||
|
<ChainSubClassRule index="1">
|
||||||
|
<!-- BacktrackGlyphCount=0 -->
|
||||||
|
<!-- InputGlyphCount=1 -->
|
||||||
|
<!-- LookAheadGlyphCount=2 -->
|
||||||
|
<LookAhead index="0" value="2"/>
|
||||||
|
<LookAhead index="1" value="1"/>
|
||||||
|
<!-- SubstCount=1 -->
|
||||||
|
<SubstLookupRecord index="0">
|
||||||
|
<SequenceIndex value="0"/>
|
||||||
|
<LookupListIndex value="1"/>
|
||||||
|
</SubstLookupRecord>
|
||||||
|
</ChainSubClassRule>
|
||||||
|
</ChainSubClassSet>
|
||||||
|
<ChainSubClassSet index="2">
|
||||||
|
<!-- ChainSubClassRuleCount=2 -->
|
||||||
|
<ChainSubClassRule index="0">
|
||||||
|
<!-- BacktrackGlyphCount=0 -->
|
||||||
|
<!-- InputGlyphCount=1 -->
|
||||||
|
<!-- LookAheadGlyphCount=1 -->
|
||||||
|
<LookAhead index="0" value="1"/>
|
||||||
|
<!-- SubstCount=1 -->
|
||||||
|
<SubstLookupRecord index="0">
|
||||||
|
<SequenceIndex value="0"/>
|
||||||
|
<LookupListIndex value="1"/>
|
||||||
|
</SubstLookupRecord>
|
||||||
|
</ChainSubClassRule>
|
||||||
|
<ChainSubClassRule index="1">
|
||||||
|
<!-- BacktrackGlyphCount=0 -->
|
||||||
|
<!-- InputGlyphCount=1 -->
|
||||||
|
<!-- LookAheadGlyphCount=2 -->
|
||||||
|
<LookAhead index="0" value="2"/>
|
||||||
|
<LookAhead index="1" value="1"/>
|
||||||
|
<!-- SubstCount=1 -->
|
||||||
|
<SubstLookupRecord index="0">
|
||||||
|
<SequenceIndex value="0"/>
|
||||||
|
<LookupListIndex value="1"/>
|
||||||
|
</SubstLookupRecord>
|
||||||
|
</ChainSubClassRule>
|
||||||
|
</ChainSubClassSet>
|
||||||
|
</ChainContextSubst>
|
||||||
|
<MarkFilteringSet value="0"/>
|
||||||
|
</Lookup>
|
||||||
|
<Lookup index="1">
|
||||||
|
<LookupType value="2"/>
|
||||||
|
<LookupFlag value="16"/><!-- useMarkFilteringSet -->
|
||||||
|
<!-- SubTableCount=1 -->
|
||||||
|
<MultipleSubst index="0">
|
||||||
|
<Substitution in="idotbelow" out="idotless,dotbelowcomb"/>
|
||||||
|
<Substitution in="iogonek" out="idotless,ogonekcomb"/>
|
||||||
|
</MultipleSubst>
|
||||||
|
<MarkFilteringSet value="0"/>
|
||||||
|
</Lookup>
|
||||||
|
</LookupList>
|
||||||
|
</GSUB>
|
||||||
|
|
||||||
|
</ttFont>
|
Loading…
x
Reference in New Issue
Block a user