[varLib.interpolatable] Support CFF2 input font
Fixes https://github.com/fonttools/fonttools/issues/3666
This commit is contained in:
parent
885d7c1ecb
commit
b5373bf5d2
@ -752,11 +752,11 @@ def main(args=None):
|
|||||||
|
|
||||||
elif args.inputs[0].endswith(".ttf") or args.inputs[0].endswith(".otf"):
|
elif args.inputs[0].endswith(".ttf") or args.inputs[0].endswith(".otf"):
|
||||||
from fontTools.ttLib import TTFont
|
from fontTools.ttLib import TTFont
|
||||||
|
|
||||||
# Is variable font?
|
# Is variable font?
|
||||||
|
|
||||||
font = TTFont(args.inputs[0])
|
font = TTFont(args.inputs[0])
|
||||||
upem = font["head"].unitsPerEm
|
upem = font["head"].unitsPerEm
|
||||||
if "gvar" in font:
|
|
||||||
|
|
||||||
fvar = font["fvar"]
|
fvar = font["fvar"]
|
||||||
axisMapping = {}
|
axisMapping = {}
|
||||||
@ -780,12 +780,14 @@ def main(args=None):
|
|||||||
location, fvarMapping
|
location, fvarMapping
|
||||||
)
|
)
|
||||||
|
|
||||||
gvar = font["gvar"]
|
|
||||||
glyf = font["glyf"]
|
|
||||||
# Gather all glyphs at their "master" locations
|
# Gather all glyphs at their "master" locations
|
||||||
ttGlyphSets = {}
|
ttGlyphSets = {}
|
||||||
glyphsets = defaultdict(dict)
|
glyphsets = defaultdict(dict)
|
||||||
|
|
||||||
|
if "gvar" in font:
|
||||||
|
gvar = font["gvar"]
|
||||||
|
glyf = font["glyf"]
|
||||||
|
|
||||||
if glyphs is None:
|
if glyphs is None:
|
||||||
glyphs = sorted(gvar.variations.keys())
|
glyphs = sorted(gvar.variations.keys())
|
||||||
for glyphname in glyphs:
|
for glyphname in glyphs:
|
||||||
@ -806,6 +808,60 @@ def main(args=None):
|
|||||||
glyphname, glyphsets[locTuple], ttGlyphSets[locTuple], glyf
|
glyphname, glyphsets[locTuple], ttGlyphSets[locTuple], glyf
|
||||||
)
|
)
|
||||||
|
|
||||||
|
elif "CFF2" in font:
|
||||||
|
fvarAxes = font["fvar"].axes
|
||||||
|
cff2 = font["CFF2"].cff.topDictIndex[0]
|
||||||
|
charstrings = cff2.CharStrings
|
||||||
|
|
||||||
|
if glyphs is None:
|
||||||
|
glyphs = sorted(charstrings.keys())
|
||||||
|
for glyphname in glyphs:
|
||||||
|
cs = charstrings[glyphname]
|
||||||
|
private = cs.private
|
||||||
|
|
||||||
|
# Extract vsindex for the glyph
|
||||||
|
vsindices = {getattr(private, "vsindex", 0)}
|
||||||
|
vsindex = getattr(private, "vsindex", 0)
|
||||||
|
last_op = 0
|
||||||
|
# The spec says vsindex can only appear once and must be the first
|
||||||
|
# operator in the charstring, but we support multiple.
|
||||||
|
# https://github.com/harfbuzz/boring-expansion-spec/issues/158
|
||||||
|
for op in enumerate(cs.program):
|
||||||
|
if op == "blend":
|
||||||
|
vsindices.add(vsindex)
|
||||||
|
elif op == "vsindex":
|
||||||
|
assert isinstance(last_op, int)
|
||||||
|
vsindex = last_op
|
||||||
|
last_op = op
|
||||||
|
|
||||||
|
if not hasattr(private, "vstore"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
varStore = private.vstore.otVarStore
|
||||||
|
for vsindex in vsindices:
|
||||||
|
varData = varStore.VarData[vsindex]
|
||||||
|
for regionIndex in varData.VarRegionIndex:
|
||||||
|
region = varStore.VarRegionList.Region[regionIndex]
|
||||||
|
|
||||||
|
locDict = {}
|
||||||
|
loc = []
|
||||||
|
for axisIndex, axis in enumerate(region.VarRegionAxis):
|
||||||
|
tag = fvarAxes[axisIndex].axisTag
|
||||||
|
val = axis.PeakCoord
|
||||||
|
locDict[tag] = val
|
||||||
|
loc.append((tag, val))
|
||||||
|
|
||||||
|
locTuple = tuple(loc)
|
||||||
|
if locTuple not in ttGlyphSets:
|
||||||
|
ttGlyphSets[locTuple] = font.getGlyphSet(
|
||||||
|
location=locDict,
|
||||||
|
normalized=True,
|
||||||
|
recalcBounds=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
glyphset = glyphsets[locTuple]
|
||||||
|
glyphset[glyphname] = ttGlyphSets[locTuple][glyphname]
|
||||||
|
|
||||||
names = ["''"]
|
names = ["''"]
|
||||||
fonts = [font.getGlyphSet()]
|
fonts = [font.getGlyphSet()]
|
||||||
locations = [{}]
|
locations = [{}]
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -94,6 +94,33 @@ class InterpolatableTest(unittest.TestCase):
|
|||||||
otf_paths = self.get_file_list(self.tempdir, suffix)
|
otf_paths = self.get_file_list(self.tempdir, suffix)
|
||||||
self.assertIsNone(interpolatable_main(otf_paths))
|
self.assertIsNone(interpolatable_main(otf_paths))
|
||||||
|
|
||||||
|
def test_interpolatable_cff2(self):
|
||||||
|
suffix = ".otf"
|
||||||
|
ttx_dir = self.get_test_input("variable_ttx_interpolatable_cff2")
|
||||||
|
ttx_path = os.path.abspath(os.path.join(ttx_dir, "interpolatable-test.ttx"))
|
||||||
|
|
||||||
|
self.temp_dir()
|
||||||
|
self.compile_font(ttx_path, suffix, self.tempdir)
|
||||||
|
|
||||||
|
otf_path = self.get_file_list(self.tempdir, suffix)[0]
|
||||||
|
|
||||||
|
problems = interpolatable_main([otf_path])
|
||||||
|
print(problems)
|
||||||
|
self.assertEqual(
|
||||||
|
problems["uni0408"],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"type": "underweight",
|
||||||
|
"contour": 0,
|
||||||
|
"master_1": "'wght=200.0 opsz=20.0'",
|
||||||
|
"master_2": "'wght=200.0 opsz=60.0'",
|
||||||
|
"master_1_idx": 2,
|
||||||
|
"master_2_idx": 3,
|
||||||
|
"tolerance": 0.9184032411892079,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def test_interpolatable_ufo(self):
|
def test_interpolatable_ufo(self):
|
||||||
ttx_dir = self.get_test_input("master_ufo")
|
ttx_dir = self.get_test_input("master_ufo")
|
||||||
ufo_paths = self.get_file_list(ttx_dir, ".ufo", "TestFamily2-")
|
ufo_paths = self.get_file_list(ttx_dir, ".ufo", "TestFamily2-")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user