1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
|
"""GSUBUnparser: Convert binary GSUB lookups to fontFeatures objects."""
from .GTableUnparser import GTableUnparser
import fontFeatures
# These are silly little functions which help to document the intent
def glyph(x):
"""Wraps a glyph name in an array, to document the fact that it occupies a slot."""
assert isinstance(x, str)
return [x]
def singleglyph(x):
"""Wraps a glyph name in two arrays, to document the fact that it is the only occupant of a slot."""
return [glyph(x)]
class GSUBUnparser(GTableUnparser):
"""Unparse a GSUB table into a fontFeatures object. See :py:class:`fontFeatures.ttLib.GTableUnparser`."""
_table = "GSUB"
lookupTypes = {
1: "SingleSubstitution",
2: "MultipleSubstitution",
3: "AlternateSubstitution",
4: "LigatureSubstitution",
5: "Contextual",
6: "ChainedContextual",
7: "Extension",
8: "ReverseContextualSubstitution",
}
_attrs = {
"lookup": "SubstLookupRecord",
"format1_ruleset": "SubRuleSet",
"format1_rule": "SubRule",
"format2_classset": "SubClassSet",
"format2_rule": "SubClassRule",
"chain_format1_ruleset": "ChainSubRuleSet",
"chain_format1_rule": "ChainSubRule",
"chain_format2_classset": "ChainSubClassSet",
"chain_format2_rule": "ChainSubClassRule",
}
def isChaining(self, lookupType):
"""Returns true if the given lookup type is a chaining lookup."""
return lookupType >= 5
def unparseReverseContextualSubstitution(self, lookup):
"""Turn a GPOS8 (reverse contextual substitution) subtable into a fontFeatures Routine."""
b = fontFeatures.Routine(
name=self.getname("ReverseContextualSubstitution" + self.gensym())
)
self._fix_flags(b, lookup)
for sub in lookup.SubTable:
prefix = []
outputs = []
suffix = []
if hasattr(sub, "BacktrackCoverage"):
for coverage in reversed(sub.BacktrackCoverage):
prefix.append(coverage.glyphs)
if hasattr(sub, "LookAheadCoverage"):
for i, coverage in enumerate(sub.LookAheadCoverage):
suffix.append(coverage.glyphs)
outputs = [sub.Substitute]
inputs = [sub.Coverage.glyphs]
b.addRule(
fontFeatures.Substitution(
inputs,
outputs,
prefix,
suffix,
flags=lookup.LookupFlag,
reverse=True,
)
)
return b, []
def unparseLigatureSubstitution(self, lookup):
"""Turn a GPOS4 (ligature substitution) subtable into a fontFeatures Routine."""
b = fontFeatures.Routine(
name=self.getname("LigatureSubstitution" + self.gensym())
)
self._fix_flags(b, lookup)
for sub in lookup.SubTable:
for first, ligatures in sub.ligatures.items():
for lig in ligatures:
substarray = [glyph(first)]
for x in lig.Component:
substarray.append(glyph(x))
b.addRule(
fontFeatures.Substitution(
substarray,
singleglyph(lig.LigGlyph),
address=self.currentLookup,
flags=lookup.LookupFlag,
)
)
return b, []
def unparseMultipleSubstitution(self, lookup):
"""Turn a GPOS2 (multiple substitution) subtable into a fontFeatures Routine."""
b = fontFeatures.Routine(
name=self.getname("MultipleSubstitution" + self.gensym())
)
self._fix_flags(b, lookup)
for sub in lookup.SubTable:
for in_glyph, out_glyphs in sub.mapping.items():
b.addRule(
fontFeatures.Substitution(
singleglyph(in_glyph),
[glyph(x) for x in out_glyphs],
address=self.currentLookup,
flags=lookup.LookupFlag,
)
)
return b, []
def unparseAlternateSubstitution(self, lookup):
"""Turn a GPOS3 (alternate substitution) subtable into a fontFeatures Routine."""
b = fontFeatures.Routine(
name=self.getname("AlternateSubstitution" + self.gensym())
)
self._fix_flags(b, lookup)
for sub in lookup.SubTable:
for in_glyph, out_glyphs in sub.alternates.items():
b.addRule(
fontFeatures.Substitution(
singleglyph(in_glyph),
[out_glyphs],
address=self.currentLookup,
flags=lookup.LookupFlag,
force_alt=True,
)
)
return b, []
def unparseSingleSubstitution(self, lookup):
"""Turn a GPOS1 (single substitution) subtable into a fontFeatures Routine."""
b = fontFeatures.Routine(
name=self.getname("SingleSubstitution" + self.gensym())
)
self._fix_flags(b, lookup)
for sub in lookup.SubTable:
for k, v in sub.mapping.items():
b.addRule(
fontFeatures.Substitution(
[[k]],
[[v]],
address=self.currentLookup,
flags=lookup.LookupFlag,
)
)
return b, []
|