From 7a86dd325e8fc107d3eba1778c4277b65cbc1f3a Mon Sep 17 00:00:00 2001 From: "Colin M. Ford" Date: Wed, 5 Apr 2023 16:35:03 -0400 Subject: [PATCH 01/13] Rewriting varLib.interpolatable to allow for sparse masters + tests --- Lib/fontTools/varLib/interpolatable.py | 347 ++++++++++++++----------- Tests/varLib/interpolatable_test.py | 25 ++ 2 files changed, 226 insertions(+), 146 deletions(-) diff --git a/Lib/fontTools/varLib/interpolatable.py b/Lib/fontTools/varLib/interpolatable.py index a2a0ff90e..1671db2b2 100644 --- a/Lib/fontTools/varLib/interpolatable.py +++ b/Lib/fontTools/varLib/interpolatable.py @@ -137,12 +137,14 @@ def min_cost_perfect_bipartite_matching(G): return best, best_cost -def test(glyphsets, glyphs=None, names=None): +def test(glyphsets, glyphs=None, names=None, ignore_missing=False): if names is None: names = glyphsets if glyphs is None: - glyphs = glyphsets[0].keys() + # `glyphs = glyphsets[0].keys()` is faster, certainly, but doesn't allow for sparse TTFs/OTFs given out of order + # ... risks the sparse master being the first one, and only processing a subset of the glyphs + glyphs = set([g for glyphset in glyphsets for g in glyphset.keys()]) hist = [] problems = OrderedDict() @@ -151,19 +153,22 @@ def test(glyphsets, glyphs=None, names=None): problems.setdefault(glyphname, []).append(problem) for glyph_name in glyphs: - # print() - # print(glyph_name) - try: + m0idx = 0 allVectors = [] allNodeTypes = [] allContourIsomorphisms = [] for glyphset, name in zip(glyphsets, names): - # print('.', end='') - if glyph_name not in glyphset: - add_problem(glyph_name, {"type": "missing", "master": name}) - continue + glyph = glyphset[glyph_name] + + if glyph is None: + if not ignore_missing: + add_problem(glyph_name, {"type": "missing", "master": name}) + allNodeTypes.append(None) + allVectors.append(None) + allContourIsomorphisms.append(None) + continue perContourPen = PerContourOrComponentPen( RecordingPen, glyphset=glyphset @@ -243,105 +248,125 @@ def test(glyphsets, glyphs=None, names=None): _rot_list([complex(*pt) for pt, bl in mirrored], i) ) - # Check each master against the first on in the list. - m0 = allNodeTypes[0] - for i, m1 in enumerate(allNodeTypes[1:]): - if len(m0) != len(m1): - add_problem( - glyph_name, - { - "type": "path_count", - "master_1": names[0], - "master_2": names[i + 1], - "value_1": len(m0), - "value_2": len(m1), - }, - ) - if m0 == m1: - continue - for pathIx, (nodes1, nodes2) in enumerate(zip(m0, m1)): - if nodes1 == nodes2: + if any(allNodeTypes): + # m0idx should be the index of the first non-None item in allNodeTypes, + # else give it the first index of the empty list, which is likely 0 + m0idx = allNodeTypes.index(next((x for x in allNodeTypes if x is not None), None)) + # m0 is the first non-None item in allNodeTypes, or the first item if all are None + m0 = allNodeTypes[m0idx] + for i, m1 in enumerate(allNodeTypes[m0idx+1:]): + if m1 is None: continue - if len(nodes1) != len(nodes2): + if len(m0) != len(m1): add_problem( glyph_name, { - "type": "node_count", - "path": pathIx, - "master_1": names[0], - "master_2": names[i + 1], - "value_1": len(nodes1), - "value_2": len(nodes2), + "type": "path_count", + "master_1": names[m0idx], + "master_2": names[m0idx + i + 1], + "value_1": len(m0), + "value_2": len(m1), }, ) + if m0 == m1: continue - for nodeIx, (n1, n2) in enumerate(zip(nodes1, nodes2)): - if n1 != n2: + for pathIx, (nodes1, nodes2) in enumerate(zip(m0, m1)): + if nodes1 == nodes2: + continue + if len(nodes1) != len(nodes2): add_problem( glyph_name, { - "type": "node_incompatibility", + "type": "node_count", "path": pathIx, - "node": nodeIx, - "master_1": names[0], - "master_2": names[i + 1], - "value_1": n1, - "value_2": n2, + "master_1": names[m0idx], + "master_2": names[m0idx + i + 1], + "value_1": len(nodes1), + "value_2": len(nodes2), }, ) continue + for nodeIx, (n1, n2) in enumerate(zip(nodes1, nodes2)): + if n1 != n2: + add_problem( + glyph_name, + { + "type": "node_incompatibility", + "path": pathIx, + "node": nodeIx, + "master_1": names[0], + "master_2": names[m0idx + i + 1], + "value_1": n1, + "value_2": n2, + }, + ) + continue - m0 = allVectors[0] - for i, m1 in enumerate(allVectors[1:]): - if len(m0) != len(m1): - # We already reported this - continue - if not m0: - continue - costs = [[_vlen(_vdiff(v0, v1)) for v1 in m1] for v0 in m0] - matching, matching_cost = min_cost_perfect_bipartite_matching(costs) - identity_matching = list(range(len(m0))) - identity_cost = sum(costs[i][i] for i in range(len(m0))) - if ( - matching != identity_matching - and matching_cost < identity_cost * 0.95 - ): - add_problem( - glyph_name, - { - "type": "contour_order", - "master_1": names[0], - "master_2": names[i + 1], - "value_1": list(range(len(m0))), - "value_2": matching, - }, - ) - break - - m0 = allContourIsomorphisms[0] - for i, m1 in enumerate(allContourIsomorphisms[1:]): - if len(m0) != len(m1): - # We already reported this - continue - if not m0: - continue - for ix, (contour0, contour1) in enumerate(zip(m0, m1)): - c0 = contour0[0] - costs = [ - v for v in (_complex_vlen(_vdiff(c0, c1)) for c1 in contour1) - ] - min_cost = min(costs) - first_cost = costs[0] - if min_cost < first_cost * 0.95: + if any(allVectors): + # m0idx should be the index of the first non-None item in allVectors, + # else give it the first index of the empty list, which is likely 0 + m0idx = allVectors.index(next((x for x in allVectors if x is not None), None)) + # m0 is the first non-None item in allVectors, or the first item if all are None + m0 = allVectors[m0idx] + for i, m1 in enumerate(allVectors[m0idx+1:]): + if m1 is None: + continue + if len(m0) != len(m1): + # We already reported this + continue + if not m0: + continue + costs = [[_vlen(_vdiff(v0, v1)) for v1 in m1] for v0 in m0] + matching, matching_cost = min_cost_perfect_bipartite_matching(costs) + identity_matching = list(range(len(m0))) + identity_cost = sum(costs[i][i] for i in range(len(m0))) + if ( + matching != identity_matching + and matching_cost < identity_cost * 0.95 + ): add_problem( glyph_name, { - "type": "wrong_start_point", - "contour": ix, - "master_1": names[0], - "master_2": names[i + 1], + "type": "contour_order", + "master_1": names[m0idx], + "master_2": names[m0idx + i + 1], + "value_1": list(range(len(m0))), + "value_2": matching, }, ) + break + + if any(allContourIsomorphisms): + # m0idx should be the index of the first non-None item in allContourIsomorphisms, + # else give it the first index of the empty list, which is likely 0 + m0idx = allContourIsomorphisms.index(next((x for x in allContourIsomorphisms if x is not None), None)) + # m0 is the first non-None item in allContourIsomorphisms, or the first item if all are None + m0 = allContourIsomorphisms[m0idx] + for i, m1 in enumerate(allContourIsomorphisms[m0idx+1:]): + if m1 is None: + continue + if len(m0) != len(m1): + # We already reported this + continue + if not m0: + continue + for ix, (contour0, contour1) in enumerate(zip(m0, m1)): + c0 = contour0[0] + costs = [ + v for v in (_complex_vlen(_vdiff(c0, c1)) for c1 in contour1) + ] + min_cost = min(costs) + first_cost = costs[0] + if min_cost < first_cost * 0.95: + add_problem( + glyph_name, + { + "type": "wrong_start_point", + "contour": ix, + "master_1": names[m0idx], + "master_2": names[m0idx + i + 1], + }, + ) except ValueError as e: add_problem( @@ -365,7 +390,17 @@ def main(args=None): help="Output report in JSON format", ) parser.add_argument( - "inputs", metavar="FILE", type=str, nargs="+", help="Input TTF/UFO files" + "--quiet", + action="store_true", + help="Only exit with code 1 or 0, no output", + ) + parser.add_argument( + "--ignore-missing", + action="store_true", + help="Will not report glyphs missing from sparse masters as errors", + ) + parser.add_argument( + "inputs", metavar="FILE", type=str, nargs="+", help="Input a single DesignSpace/Glyphs file, or multiple TTF/UFO files" ) args = parser.parse_args(args) @@ -440,70 +475,90 @@ def main(args=None): names.append(basename(filename).rsplit(".", 1)[0]) if hasattr(fonts[0], "getGlyphSet"): - glyphsets = [font.getGlyphSet() for font in fonts] + glyphsets = [dict(font.getGlyphSet().items()) for font in fonts] else: - glyphsets = fonts + glyphsets = [dict(font.items()) for font in fonts] + + if not glyphs: + glyphs = set([gn for glyphset in glyphsets for gn in glyphset.keys()]) + + for glyphset in glyphsets: + glyphSetGlyphNames = set(glyphset.keys()) + diff = glyphs - glyphSetGlyphNames + if diff: + for gn in diff: + glyphset[gn] = None - problems = test(glyphsets, glyphs=glyphs, names=names) - if args.json: - import json + problems = test(glyphsets, glyphs=glyphs, names=names, ignore_missing=args.ignore_missing) + + if not args.quiet: + if args.json: + import json - print(json.dumps(problems)) - else: - for glyph, glyph_problems in problems.items(): - print(f"Glyph {glyph} was not compatible: ") - for p in glyph_problems: - if p["type"] == "missing": - print(" Glyph was missing in master %s" % p["master"]) - if p["type"] == "open_path": - print(" Glyph has an open path in master %s" % p["master"]) - if p["type"] == "path_count": - print( - " Path count differs: %i in %s, %i in %s" - % (p["value_1"], p["master_1"], p["value_2"], p["master_2"]) - ) - if p["type"] == "node_count": - print( - " Node count differs in path %i: %i in %s, %i in %s" - % ( - p["path"], - p["value_1"], - p["master_1"], - p["value_2"], - p["master_2"], + print(json.dumps(problems)) + else: + for glyph, glyph_problems in problems.items(): + print(f"Glyph {glyph} was not compatible: ") + for p in glyph_problems: + if p["type"] == "missing": + print(" Glyph was missing in master %s" % p["master"]) + if p["type"] == "open_path": + print(" Glyph has an open path in master %s" % p["master"]) + if p["type"] == "path_count": + print( + " Path count differs: %i in %s, %i in %s" + % (p["value_1"], p["master_1"], p["value_2"], p["master_2"]) ) - ) - if p["type"] == "node_incompatibility": - print( - " Node %o incompatible in path %i: %s in %s, %s in %s" - % ( - p["node"], - p["path"], - p["value_1"], - p["master_1"], - p["value_2"], - p["master_2"], + if p["type"] == "node_count": + print( + " Node count differs in path %i: %i in %s, %i in %s" + % ( + p["path"], + p["value_1"], + p["master_1"], + p["value_2"], + p["master_2"], + ) ) - ) - if p["type"] == "contour_order": - print( - " Contour order differs: %s in %s, %s in %s" - % ( - p["value_1"], - p["master_1"], - p["value_2"], - p["master_2"], + if p["type"] == "node_incompatibility": + print( + " Node %o incompatible in path %i: %s in %s, %s in %s" + % ( + p["node"], + p["path"], + p["value_1"], + p["master_1"], + p["value_2"], + p["master_2"], + ) ) - ) - if p["type"] == "wrong_start_point": - print( - " Contour %d start point differs: %s, %s" - % ( - p["contour"], - p["master_1"], - p["master_2"], + if p["type"] == "contour_order": + print( + " Contour order differs: %s in %s, %s in %s" + % ( + p["value_1"], + p["master_1"], + p["value_2"], + p["master_2"], + ) + ) + if p["type"] == "wrong_start_point": + print( + " Contour %d start point differs: %s, %s" + % ( + p["contour"], + p["master_1"], + p["master_2"], + ) + ) + if p["type"] == "math_error": + print( + " Miscellaneous error in %s: %s" + % ( + p["master"], + p["error"], + ) ) - ) if problems: return problems diff --git a/Tests/varLib/interpolatable_test.py b/Tests/varLib/interpolatable_test.py index 9eb66ba81..96f6c8473 100644 --- a/Tests/varLib/interpolatable_test.py +++ b/Tests/varLib/interpolatable_test.py @@ -92,6 +92,31 @@ class InterpolatableTest(unittest.TestCase): otf_paths = self.get_file_list(self.tempdir, suffix) self.assertIsNone(interpolatable_main(otf_paths)) + + def test_sparse_interpolatable_ttfs(self): + suffix = ".ttf" + ttx_dir = self.get_test_input("master_ttx_interpolatable_ttf") + + self.temp_dir() + ttx_paths = self.get_file_list(ttx_dir, ".ttx", "SparseMasters-") + for path in ttx_paths: + self.compile_font(path, suffix, self.tempdir) + + ttf_paths = self.get_file_list(self.tempdir, suffix) + + # without --ignore-missing + problems = interpolatable_main(["--quiet"] + ttf_paths) + self.assertEqual(problems['a'], [{'type': 'missing', 'master': 'SparseMasters-Medium'}]) + self.assertEqual(problems['s'], [{'type': 'missing', 'master': 'SparseMasters-Medium'}]) + self.assertEqual(problems['edotabove'], [{'type': 'missing', 'master': 'SparseMasters-Medium'}]) + self.assertEqual(problems['dotabovecomb'], [{'type': 'missing', 'master': 'SparseMasters-Medium'}]) + + # normal order, with --ignore-missing + self.assertIsNone(interpolatable_main(["--ignore-missing"] + ttf_paths)) + # purposely putting the sparse master (medium) first + self.assertIsNone(interpolatable_main(["--ignore-missing"] + [ttf_paths[1]] + [ttf_paths[0]] + [ttf_paths[2]])) + # purposely putting the sparse master (medium) last + self.assertIsNone(interpolatable_main(["--ignore-missing"] + [ttf_paths[0]] + [ttf_paths[2]] + [ttf_paths[1]])) def test_interpolatable_varComposite(self): input_path = self.get_test_input( From 208c36800b09bf51fe3f820c586de62d2bbb9b60 Mon Sep 17 00:00:00 2001 From: "Colin M. Ford" Date: Wed, 5 Apr 2023 17:11:30 -0400 Subject: [PATCH 02/13] Oops, `any` could potentially block a list like `[None, [], []]`, which is not what we want --- Lib/fontTools/varLib/interpolatable.py | 185 ++++++++++++------------- 1 file changed, 91 insertions(+), 94 deletions(-) diff --git a/Lib/fontTools/varLib/interpolatable.py b/Lib/fontTools/varLib/interpolatable.py index 1671db2b2..3548b81b5 100644 --- a/Lib/fontTools/varLib/interpolatable.py +++ b/Lib/fontTools/varLib/interpolatable.py @@ -248,125 +248,122 @@ def test(glyphsets, glyphs=None, names=None, ignore_missing=False): _rot_list([complex(*pt) for pt, bl in mirrored], i) ) - if any(allNodeTypes): - # m0idx should be the index of the first non-None item in allNodeTypes, - # else give it the first index of the empty list, which is likely 0 - m0idx = allNodeTypes.index(next((x for x in allNodeTypes if x is not None), None)) - # m0 is the first non-None item in allNodeTypes, or the first item if all are None - m0 = allNodeTypes[m0idx] - for i, m1 in enumerate(allNodeTypes[m0idx+1:]): - if m1 is None: + # m0idx should be the index of the first non-None item in allNodeTypes, + # else give it the first index of the empty list, which is likely 0 + m0idx = allNodeTypes.index(next((x for x in allNodeTypes if x is not None), None)) + # m0 is the first non-None item in allNodeTypes, or the first item if all are None + m0 = allNodeTypes[m0idx] + for i, m1 in enumerate(allNodeTypes[m0idx+1:]): + if m1 is None: + continue + if len(m0) != len(m1): + add_problem( + glyph_name, + { + "type": "path_count", + "master_1": names[m0idx], + "master_2": names[m0idx + i + 1], + "value_1": len(m0), + "value_2": len(m1), + }, + ) + if m0 == m1: + continue + for pathIx, (nodes1, nodes2) in enumerate(zip(m0, m1)): + if nodes1 == nodes2: continue - if len(m0) != len(m1): + if len(nodes1) != len(nodes2): add_problem( glyph_name, { - "type": "path_count", + "type": "node_count", + "path": pathIx, "master_1": names[m0idx], "master_2": names[m0idx + i + 1], - "value_1": len(m0), - "value_2": len(m1), + "value_1": len(nodes1), + "value_2": len(nodes2), }, ) - if m0 == m1: continue - for pathIx, (nodes1, nodes2) in enumerate(zip(m0, m1)): - if nodes1 == nodes2: - continue - if len(nodes1) != len(nodes2): + for nodeIx, (n1, n2) in enumerate(zip(nodes1, nodes2)): + if n1 != n2: add_problem( glyph_name, { - "type": "node_count", + "type": "node_incompatibility", "path": pathIx, - "master_1": names[m0idx], + "node": nodeIx, + "master_1": names[0], "master_2": names[m0idx + i + 1], - "value_1": len(nodes1), - "value_2": len(nodes2), + "value_1": n1, + "value_2": n2, }, ) continue - for nodeIx, (n1, n2) in enumerate(zip(nodes1, nodes2)): - if n1 != n2: - add_problem( - glyph_name, - { - "type": "node_incompatibility", - "path": pathIx, - "node": nodeIx, - "master_1": names[0], - "master_2": names[m0idx + i + 1], - "value_1": n1, - "value_2": n2, - }, - ) - continue - if any(allVectors): - # m0idx should be the index of the first non-None item in allVectors, - # else give it the first index of the empty list, which is likely 0 - m0idx = allVectors.index(next((x for x in allVectors if x is not None), None)) - # m0 is the first non-None item in allVectors, or the first item if all are None - m0 = allVectors[m0idx] - for i, m1 in enumerate(allVectors[m0idx+1:]): - if m1 is None: - continue - if len(m0) != len(m1): - # We already reported this - continue - if not m0: - continue - costs = [[_vlen(_vdiff(v0, v1)) for v1 in m1] for v0 in m0] - matching, matching_cost = min_cost_perfect_bipartite_matching(costs) - identity_matching = list(range(len(m0))) - identity_cost = sum(costs[i][i] for i in range(len(m0))) - if ( - matching != identity_matching - and matching_cost < identity_cost * 0.95 - ): + # m0idx should be the index of the first non-None item in allVectors, + # else give it the first index of the empty list, which is likely 0 + m0idx = allVectors.index(next((x for x in allVectors if x is not None), None)) + # m0 is the first non-None item in allVectors, or the first item if all are None + m0 = allVectors[m0idx] + for i, m1 in enumerate(allVectors[m0idx+1:]): + if m1 is None: + continue + if len(m0) != len(m1): + # We already reported this + continue + if not m0: + continue + costs = [[_vlen(_vdiff(v0, v1)) for v1 in m1] for v0 in m0] + matching, matching_cost = min_cost_perfect_bipartite_matching(costs) + identity_matching = list(range(len(m0))) + identity_cost = sum(costs[i][i] for i in range(len(m0))) + if ( + matching != identity_matching + and matching_cost < identity_cost * 0.95 + ): + add_problem( + glyph_name, + { + "type": "contour_order", + "master_1": names[m0idx], + "master_2": names[m0idx + i + 1], + "value_1": list(range(len(m0))), + "value_2": matching, + }, + ) + break + + # m0idx should be the index of the first non-None item in allContourIsomorphisms, + # else give it the first index of the empty list, which is likely 0 + m0idx = allContourIsomorphisms.index(next((x for x in allContourIsomorphisms if x is not None), None)) + # m0 is the first non-None item in allContourIsomorphisms, or the first item if all are None + m0 = allContourIsomorphisms[m0idx] + for i, m1 in enumerate(allContourIsomorphisms[m0idx+1:]): + if m1 is None: + continue + if len(m0) != len(m1): + # We already reported this + continue + if not m0: + continue + for ix, (contour0, contour1) in enumerate(zip(m0, m1)): + c0 = contour0[0] + costs = [ + v for v in (_complex_vlen(_vdiff(c0, c1)) for c1 in contour1) + ] + min_cost = min(costs) + first_cost = costs[0] + if min_cost < first_cost * 0.95: add_problem( glyph_name, { - "type": "contour_order", + "type": "wrong_start_point", + "contour": ix, "master_1": names[m0idx], "master_2": names[m0idx + i + 1], - "value_1": list(range(len(m0))), - "value_2": matching, }, ) - break - - if any(allContourIsomorphisms): - # m0idx should be the index of the first non-None item in allContourIsomorphisms, - # else give it the first index of the empty list, which is likely 0 - m0idx = allContourIsomorphisms.index(next((x for x in allContourIsomorphisms if x is not None), None)) - # m0 is the first non-None item in allContourIsomorphisms, or the first item if all are None - m0 = allContourIsomorphisms[m0idx] - for i, m1 in enumerate(allContourIsomorphisms[m0idx+1:]): - if m1 is None: - continue - if len(m0) != len(m1): - # We already reported this - continue - if not m0: - continue - for ix, (contour0, contour1) in enumerate(zip(m0, m1)): - c0 = contour0[0] - costs = [ - v for v in (_complex_vlen(_vdiff(c0, c1)) for c1 in contour1) - ] - min_cost = min(costs) - first_cost = costs[0] - if min_cost < first_cost * 0.95: - add_problem( - glyph_name, - { - "type": "wrong_start_point", - "contour": ix, - "master_1": names[m0idx], - "master_2": names[m0idx + i + 1], - }, - ) except ValueError as e: add_problem( From 4a991d1d89d0a9c4897ac35152a0dac313c7c683 Mon Sep 17 00:00:00 2001 From: "Colin M. Ford" Date: Wed, 5 Apr 2023 17:12:43 -0400 Subject: [PATCH 03/13] Comment corrections --- Lib/fontTools/varLib/interpolatable.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/fontTools/varLib/interpolatable.py b/Lib/fontTools/varLib/interpolatable.py index 3548b81b5..fc7dca62a 100644 --- a/Lib/fontTools/varLib/interpolatable.py +++ b/Lib/fontTools/varLib/interpolatable.py @@ -249,7 +249,7 @@ def test(glyphsets, glyphs=None, names=None, ignore_missing=False): ) # m0idx should be the index of the first non-None item in allNodeTypes, - # else give it the first index of the empty list, which is likely 0 + # else give it the first index of None, which is likely 0 m0idx = allNodeTypes.index(next((x for x in allNodeTypes if x is not None), None)) # m0 is the first non-None item in allNodeTypes, or the first item if all are None m0 = allNodeTypes[m0idx] @@ -302,7 +302,7 @@ def test(glyphsets, glyphs=None, names=None, ignore_missing=False): continue # m0idx should be the index of the first non-None item in allVectors, - # else give it the first index of the empty list, which is likely 0 + # else give it the first index of None, which is likely 0 m0idx = allVectors.index(next((x for x in allVectors if x is not None), None)) # m0 is the first non-None item in allVectors, or the first item if all are None m0 = allVectors[m0idx] @@ -335,7 +335,7 @@ def test(glyphsets, glyphs=None, names=None, ignore_missing=False): break # m0idx should be the index of the first non-None item in allContourIsomorphisms, - # else give it the first index of the empty list, which is likely 0 + # else give it the first index of None, which is likely 0 m0idx = allContourIsomorphisms.index(next((x for x in allContourIsomorphisms if x is not None), None)) # m0 is the first non-None item in allContourIsomorphisms, or the first item if all are None m0 = allContourIsomorphisms[m0idx] From 9c1380be965585557b04d30c9acf7b2b1a9b7126 Mon Sep 17 00:00:00 2001 From: "Colin M. Ford" Date: Wed, 5 Apr 2023 18:21:17 -0400 Subject: [PATCH 04/13] Oops, UFOLib's `getGlyphSet` does not have an `items` function --- Lib/fontTools/varLib/interpolatable.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Lib/fontTools/varLib/interpolatable.py b/Lib/fontTools/varLib/interpolatable.py index fc7dca62a..bd2d3174c 100644 --- a/Lib/fontTools/varLib/interpolatable.py +++ b/Lib/fontTools/varLib/interpolatable.py @@ -471,10 +471,13 @@ def main(args=None): names.append(basename(filename).rsplit(".", 1)[0]) - if hasattr(fonts[0], "getGlyphSet"): - glyphsets = [dict(font.getGlyphSet().items()) for font in fonts] - else: - glyphsets = [dict(font.items()) for font in fonts] + glyphsets = [] + for font in fonts: + if hasattr(font, "getGlyphSet"): + glyphset = font.getGlyphSet() + else: + glyphset = font + glyphsets.append({k:glyphset[k] for k in glyphset.keys()}) if not glyphs: glyphs = set([gn for glyphset in glyphsets for gn in glyphset.keys()]) From 491bd74f4bebb1411f3fa43714eae7c49da49857 Mon Sep 17 00:00:00 2001 From: "Colin M. Ford" Date: Wed, 5 Apr 2023 18:22:21 -0400 Subject: [PATCH 05/13] Missed a `m0idx` --- Lib/fontTools/varLib/interpolatable.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/fontTools/varLib/interpolatable.py b/Lib/fontTools/varLib/interpolatable.py index bd2d3174c..4e8b96252 100644 --- a/Lib/fontTools/varLib/interpolatable.py +++ b/Lib/fontTools/varLib/interpolatable.py @@ -293,7 +293,7 @@ def test(glyphsets, glyphs=None, names=None, ignore_missing=False): "type": "node_incompatibility", "path": pathIx, "node": nodeIx, - "master_1": names[0], + "master_1": names[m0idx], "master_2": names[m0idx + i + 1], "value_1": n1, "value_2": n2, From 45d1d01f663442a69dba652c013f5e5c1b0a7031 Mon Sep 17 00:00:00 2001 From: "Colin M. Ford" Date: Wed, 5 Apr 2023 20:48:34 -0400 Subject: [PATCH 06/13] adding more tests for varlib.interpolatable --- Tests/varLib/data/InterpolateLayout.glyphs | 2402 +++++++++++++++++ Tests/varLib/data/SparseMasters.glyphs | 510 ++++ .../varLib/data/SparseMasters_ufo.designspace | 23 + .../SparseMasters-VF.ttx | 501 ++++ .../SparseMasters-Bold.ufo/fontinfo.plist | 41 + .../glyphs/_notdef.glif | 21 + .../SparseMasters-Bold.ufo/glyphs/a.glif | 32 + .../glyphs/contents.plist | 18 + .../glyphs/dotabovecomb.glif | 15 + .../SparseMasters-Bold.ufo/glyphs/e.glif | 25 + .../glyphs/edotabove.glif | 12 + .../glyphs/layerinfo.plist | 8 + .../SparseMasters-Bold.ufo/glyphs/s.glif | 24 + .../layercontents.plist | 10 + .../SparseMasters-Bold.ufo/lib.plist | 47 + .../SparseMasters-Bold.ufo/metainfo.plist | 10 + .../SparseMasters-Medium.ufo/fontinfo.plist | 41 + .../glyphs/_notdef.glif | 21 + .../glyphs/contents.plist | 10 + .../SparseMasters-Medium.ufo/glyphs/e.glif | 24 + .../glyphs/layerinfo.plist | 8 + .../layercontents.plist | 10 + .../SparseMasters-Medium.ufo/lib.plist | 27 + .../SparseMasters-Medium.ufo/metainfo.plist | 10 + .../SparseMasters-Regular.ufo/fontinfo.plist | 41 + .../glyphs/_notdef.glif | 21 + .../SparseMasters-Regular.ufo/glyphs/a.glif | 32 + .../glyphs/contents.plist | 18 + .../glyphs/dotabovecomb.glif | 15 + .../SparseMasters-Regular.ufo/glyphs/e.glif | 25 + .../glyphs/edotabove.glif | 12 + .../glyphs/layerinfo.plist | 8 + .../SparseMasters-Regular.ufo/glyphs/s.glif | 24 + .../layercontents.plist | 10 + .../SparseMasters-Regular.ufo/lib.plist | 47 + .../SparseMasters-Regular.ufo/metainfo.plist | 10 + Tests/varLib/interpolatable_test.py | 70 + variable_ttf/SparseMasters_ufo-VF.ttf | Bin 0 -> 1632 bytes 38 files changed, 4183 insertions(+) create mode 100644 Tests/varLib/data/InterpolateLayout.glyphs create mode 100644 Tests/varLib/data/SparseMasters.glyphs create mode 100644 Tests/varLib/data/SparseMasters_ufo.designspace create mode 100644 Tests/varLib/data/master_ttx_varfont_ttf/SparseMasters-VF.ttx create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/fontinfo.plist create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/_notdef.glif create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/a.glif create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/contents.plist create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/dotabovecomb.glif create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/e.glif create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/edotabove.glif create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/layerinfo.plist create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/s.glif create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/layercontents.plist create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/lib.plist create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/metainfo.plist create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/fontinfo.plist create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/_notdef.glif create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/contents.plist create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/e.glif create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/layerinfo.plist create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/layercontents.plist create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/lib.plist create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/metainfo.plist create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/fontinfo.plist create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/_notdef.glif create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/a.glif create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/contents.plist create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/dotabovecomb.glif create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/e.glif create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/edotabove.glif create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/layerinfo.plist create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/s.glif create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/layercontents.plist create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/lib.plist create mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/metainfo.plist create mode 100644 variable_ttf/SparseMasters_ufo-VF.ttf diff --git a/Tests/varLib/data/InterpolateLayout.glyphs b/Tests/varLib/data/InterpolateLayout.glyphs new file mode 100644 index 000000000..904939509 --- /dev/null +++ b/Tests/varLib/data/InterpolateLayout.glyphs @@ -0,0 +1,2402 @@ +{ +.appVersion = "895"; +customParameters = ( +{ +name = hheaAscender; +value = 984; +}, +{ +name = hheaDescender; +value = -273; +}, +{ +name = hheaLineGap; +value = 0; +}, +{ +name = panose; +value = ( +2, +11, +5, +3, +3, +4, +3, +2, +2, +4 +); +}, +{ +name = typoAscender; +value = 750; +}, +{ +name = typoDescender; +value = -250; +}, +{ +name = typoLineGap; +value = 0; +}, +{ +name = unicodeRanges; +value = ( +0, +1 +); +}, +{ +name = blueScale; +value = 0.0625; +}, +{ +name = underlinePosition; +value = -75; +}, +{ +name = vendorID; +value = ADBO; +}, +{ +name = postscriptFontName; +value = "TestFamily2-Master0"; +}, +{ +name = postscriptBlueFuzz; +value = 0; +}, +{ +name = postscriptForceBold; +value = 0; +}, +{ +name = styleMapFamilyName; +value = "Test Family 2"; +}, +{ +name = postscriptFamilyBlues; +value = ( +-12, +0, +486, +498, +518, +530, +574, +586, +638, +650, +656, +668, +712, +724 +); +}, +{ +name = postscriptFamilyOtherBlues; +value = ( +-217, +-205 +); +}, +{ +name = codePageRanges; +value = ( +1252, +1250 +); +}, +{ +name = codePageRangesUnsupportedBits; +value = ( +29 +); +}, +{ +name = winAscent; +value = 984; +}, +{ +name = winDescent; +value = 273; +}, +{ +name = weightClass; +value = 200; +}, +{ +name = glyphOrder; +value = ( +.notdef, +space, +A, +a, +d, +f, +n, +t, +f_t, +a.alt, +A.sc, +atilde, +ampersand, +circledotted, +tildecmb, +dieresiscmb, +tildebelowcmb, +dieresisbelowcmb +); +}, +{ +name = "Disable Last Change"; +value = 1; +}, +{ +name = Axes; +value = ( +{ +Name = weight; +Tag = wght; +} +); +} +); +designer = "Paul D. Hunt"; +disablesAutomaticAlignment = 1; +familyName = "Test Family 2"; +featurePrefixes = ( +{ +code = "# Do not use Glyphs to edit features.\012#\012# This Glyphs file was made from several UFOs that had different\012# features. As a result, the features are not editable in Glyphs and\012# the original features will be restored when you go back to UFOs.\012"; +name = WARNING; +} +); +fontMaster = ( +{ +alignmentZones = ( +"{722, 12}", +"{660, 12}", +"{640, 12}", +"{570, 12}", +"{510, 12}", +"{478, 12}", +"{0, -12}", +"{-222, -12}" +); +ascender = 722; +capHeight = 660; +customParameters = ( +{ +name = "UFO Filename"; +value = "master_ufo/TestFamily2-Master0.ufo"; +}, +{ +name = "Master Name"; +value = "Master 0"; +}, +{ +name = hheaAscender; +value = 984; +}, +{ +name = hheaDescender; +value = -273; +}, +{ +name = hheaLineGap; +value = 0; +}, +{ +name = panose; +value = ( +2, +11, +5, +3, +3, +4, +3, +2, +2, +4 +); +}, +{ +name = typoAscender; +value = 750; +}, +{ +name = typoDescender; +value = -250; +}, +{ +name = typoLineGap; +value = 0; +}, +{ +name = unicodeRanges; +value = ( +0, +1 +); +}, +{ +name = blueScale; +value = 0.0625; +}, +{ +name = underlinePosition; +value = -75; +}, +{ +name = vendorID; +value = ADBO; +}, +{ +name = postscriptFontName; +value = "TestFamily2-Master0"; +}, +{ +name = postscriptBlueFuzz; +value = 0; +}, +{ +name = postscriptForceBold; +value = 0; +}, +{ +name = styleMapFamilyName; +value = "Test Family 2"; +}, +{ +name = postscriptFamilyBlues; +value = ( +-12, +0, +486, +498, +518, +530, +574, +586, +638, +650, +656, +668, +712, +724 +); +}, +{ +name = postscriptFamilyOtherBlues; +value = ( +-217, +-205 +); +}, +{ +name = codePageRanges; +value = ( +1252, +1250 +); +}, +{ +name = codePageRangesUnsupportedBits; +value = ( +29 +); +}, +{ +name = winAscent; +value = 984; +}, +{ +name = winDescent; +value = 273; +}, +{ +name = weightClass; +value = 200; +} +); +descender = -222; +horizontalStems = ( +28, +40 +); +id = "8DB0CCF0-BD6F-426B-90E2-48FD021BE868"; +userData = { +com.schriftgestaltung.Glyphs.originalFeatureCode = "table head {\012 FontRevision 2.020;\012} head;\012\012\012table name {\012 nameid 9 \"Paul D. Hunt\";\012 nameid 9 1 \"Paul D. Hunt\";\012} name;\012\012\012table hhea {\012 Ascender 984;\012 Descender -273;\012 LineGap 0;\012} hhea;\012\012\012table BASE {\012 HorizAxis.BaseTagList ideo romn;\012 HorizAxis.BaseScriptList\012 latn romn -170 0,\012 grek romn -170 0,\012 cyrl romn -170 0,\012 DFLT romn -170 0;\012} BASE;\012\012\012table OS/2 {\012 Panose 2 11 3 3 3 4 3 2 2 4;\012 XHeight 478;\012 WeightClass 200;\012\012 TypoAscender 750;\012 TypoDescender -250;\012 TypoLineGap 0;\012 winAscent 984;\012 winDescent 273;\012\012 CapHeight 660;\012 WidthClass 5;\012 Vendor \"ADBO\";\012 FSType 0;\012} OS/2;\012\012\012languagesystem DFLT dflt;\012languagesystem latn dflt;\012\012# GSUB =========================================\012# Merging of GSUB is not performed. The variable\012# font will inherit the GSUB table from the\012# base master.\012\012feature c2sc {\012 sub A by A.sc; # GSUB LookupType 1\012} c2sc;\012\012feature ss01 {\012 featureNames {\012 name \"Alternate a\";\012 name 1 0 0 \"Alternate a\";};\012 sub a by a.alt;\012} ss01;\012\012feature ccmp {\012 sub ampersand by a n d; # GSUB LookupType 2\012} ccmp;\012\012feature salt {\012 sub a from [a.alt A.sc]; # GSUB LookupType 3\012} salt;\012\012feature liga {\012 sub f t by f_t; # GSUB LookupType 4\012} liga;\012\012feature calt {\012 sub a' t by a.alt; # GSUB LookupType 6\012} calt;\012\012"; +}; +verticalStems = ( +32, +48 +); +weightValue = 0; +xHeight = 478; +}, +{ +alignmentZones = ( +"{696, 12}", +"{650, 12}", +"{634, 12}", +"{580, 12}", +"{532, 12}", +"{500, 12}", +"{0, -12}", +"{-176, -12}" +); +ascender = 696; +capHeight = 650; +customParameters = ( +{ +name = "UFO Filename"; +value = "master_ufo/TestFamily2-Master1.ufo"; +}, +{ +name = "Master Name"; +value = "Master 1"; +}, +{ +name = hheaAscender; +value = 984; +}, +{ +name = hheaDescender; +value = -273; +}, +{ +name = hheaLineGap; +value = 0; +}, +{ +name = panose; +value = ( +2, +11, +5, +3, +3, +4, +3, +2, +2, +4 +); +}, +{ +name = typoAscender; +value = 750; +}, +{ +name = typoDescender; +value = -250; +}, +{ +name = typoLineGap; +value = 0; +}, +{ +name = unicodeRanges; +value = ( +0, +1 +); +}, +{ +name = blueScale; +value = 0.0625; +}, +{ +name = underlinePosition; +value = -75; +}, +{ +name = vendorID; +value = ADBO; +}, +{ +name = postscriptFontName; +value = "TestFamily2-Master1"; +}, +{ +name = postscriptBlueFuzz; +value = 0; +}, +{ +name = postscriptForceBold; +value = 0; +}, +{ +name = styleMapFamilyName; +value = "Test Family 2"; +}, +{ +name = postscriptFamilyBlues; +value = ( +-12, +0, +486, +498, +518, +530, +574, +586, +638, +650, +656, +668, +712, +724 +); +}, +{ +name = postscriptFamilyOtherBlues; +value = ( +-217, +-205 +); +}, +{ +name = codePageRanges; +value = ( +1252, +1250 +); +}, +{ +name = codePageRangesUnsupportedBits; +value = ( +29 +); +}, +{ +name = winAscent; +value = 984; +}, +{ +name = winDescent; +value = 273; +}, +{ +name = weightClass; +value = 900; +} +); +descender = -176; +horizontalStems = ( +134, +144 +); +id = "A99E50E2-B754-449B-A60B-37BA27802C99"; +userData = { +com.schriftgestaltung.Glyphs.originalFeatureCode = "table head {\012 FontRevision 2.020;\012} head;\012\012\012table name {\012 nameid 9 \"Paul D. Hunt\";\012 nameid 9 1 \"Paul D. Hunt\";\012} name;\012\012\012table hhea {\012 Ascender 984;\012 Descender -273;\012 LineGap 0;\012} hhea;\012\012\012table BASE {\012 HorizAxis.BaseTagList ideo romn;\012 HorizAxis.BaseScriptList\012 latn romn -170 0,\012 grek romn -170 0,\012 cyrl romn -170 0,\012 DFLT romn -170 0;\012} BASE;\012\012\012table OS/2 {\012 Panose 2 11 8 3 3 4 3 2 2 4;\012 XHeight 500;\012 WeightClass 900;\012\012 TypoAscender 750;\012 TypoDescender -250;\012 TypoLineGap 0;\012 winAscent 984;\012 winDescent 273;\012\012 CapHeight 660;\012 WidthClass 5;\012 Vendor \"ADBO\";\012 FSType 0;\012} OS/2;\012\012\012languagesystem DFLT dflt;\012languagesystem latn dflt;\012\012# GSUB =========================================\012# No merging of GSUB is performed. The variable\012# font will inherit the GSUB table from the\012# base master.\012\012"; +}; +verticalStems = ( +172, +176 +); +weightValue = 1000; +xHeight = 500; +} +); +glyphs = ( +{ +glyphname = .notdef; +layers = ( +{ +layerId = "8DB0CCF0-BD6F-426B-90E2-48FD021BE868"; +paths = ( +{ +closed = 1; +nodes = ( +"528 0 LINE", +"528 660 LINE", +"96 660 LINE", +"96 0 LINE" +); +}, +{ +closed = 1; +nodes = ( +"246 208 LINE", +"310 314 LINE", +"314 314 LINE", +"376 208 LINE", +"476 32 LINE", +"144 32 LINE" +); +}, +{ +closed = 1; +nodes = ( +"254 458 LINE", +"160 626 LINE", +"462 626 LINE", +"368 458 LINE", +"314 366 LINE", +"310 366 LINE" +); +}, +{ +closed = 1; +nodes = ( +"134 610 LINE", +"288 340 LINE", +"134 74 LINE" +); +}, +{ +closed = 1; +nodes = ( +"336 340 LINE", +"488 610 LINE", +"488 74 LINE" +); +} +); +vertWidth = 0; +width = 624; +}, +{ +layerId = "A99E50E2-B754-449B-A60B-37BA27802C99"; +paths = ( +{ +closed = 1; +nodes = ( +"628 0 LINE", +"628 660 LINE", +"76 660 LINE", +"76 0 LINE" +); +}, +{ +closed = 1; +nodes = ( +"314 160 LINE", +"350 256 LINE", +"354 256 LINE", +"390 160 LINE", +"416 104 LINE", +"288 104 LINE" +); +}, +{ +closed = 1; +nodes = ( +"310 520 LINE", +"292 556 LINE", +"412 556 LINE", +"394 520 LINE", +"354 424 LINE", +"350 424 LINE" +); +}, +{ +closed = 1; +nodes = ( +"188 508 LINE", +"270 340 LINE", +"188 172 LINE" +); +}, +{ +closed = 1; +nodes = ( +"434 340 LINE", +"516 508 LINE", +"516 172 LINE" +); +} +); +vertWidth = 0; +width = 704; +} +); +note = ""; +}, +{ +glyphname = space; +layers = ( +{ +layerId = "8DB0CCF0-BD6F-426B-90E2-48FD021BE868"; +vertWidth = 0; +width = 200; +}, +{ +layerId = "A99E50E2-B754-449B-A60B-37BA27802C99"; +vertWidth = 0; +width = 200; +} +); +note = ""; +unicode = 0020; +}, +{ +glyphname = A; +layers = ( +{ +layerId = "8DB0CCF0-BD6F-426B-90E2-48FD021BE868"; +paths = ( +{ +closed = 1; +nodes = ( +"42 0 LINE", +"182 396 LINE SMOOTH", +"210 476 OFFCURVE", +"234 544 OFFCURVE", +"258 626 CURVE", +"262 626 LINE", +"286 544 OFFCURVE", +"310 476 OFFCURVE", +"338 396 CURVE SMOOTH", +"476 0 LINE", +"510 0 LINE", +"274 660 LINE", +"246 660 LINE", +"10 0 LINE" +); +}, +{ +closed = 1; +nodes = ( +"405 236 LINE", +"405 264 LINE", +"112 264 LINE", +"112 236 LINE" +); +} +); +vertWidth = 0; +width = 520; +}, +{ +layerId = "A99E50E2-B754-449B-A60B-37BA27802C99"; +paths = ( +{ +closed = 1; +nodes = ( +"166 0 LINE", +"240 316 LINE SMOOTH", +"256 378 OFFCURVE", +"272 456 OFFCURVE", +"286 522 CURVE", +"290 522 LINE", +"306 457 OFFCURVE", +"322 378 OFFCURVE", +"338 316 CURVE SMOOTH", +"412 0 LINE", +"594 0 LINE", +"396 650 LINE", +"188 650 LINE", +"-10 0 LINE" +); +}, +{ +closed = 1; +nodes = ( +"450 138 LINE", +"450 271 LINE", +"132 271 LINE", +"132 138 LINE" +); +} +); +vertWidth = 0; +width = 584; +} +); +note = ""; +unicode = 0041; +}, +{ +glyphname = a; +layers = ( +{ +layerId = "8DB0CCF0-BD6F-426B-90E2-48FD021BE868"; +paths = ( +{ +closed = 1; +nodes = ( +"262 -12 OFFCURVE", +"322 24 OFFCURVE", +"372 64 CURVE", +"374 64 LINE", +"378 0 LINE", +"404 0 LINE", +"404 310 LINE SMOOTH", +"404 406 OFFCURVE", +"370 490 OFFCURVE", +"258 490 CURVE SMOOTH", +"180 490 OFFCURVE", +"114 450 OFFCURVE", +"84 428 CURVE", +"100 404 LINE", +"130 428 OFFCURVE", +"188 462 OFFCURVE", +"256 462 CURVE SMOOTH", +"356 462 OFFCURVE", +"376 376 OFFCURVE", +"374 298 CURVE", +"158 274 OFFCURVE", +"60 224 OFFCURVE", +"60 117 CURVE SMOOTH", +"60 26 OFFCURVE", +"124 -12 OFFCURVE", +"198 -12 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"142 16 OFFCURVE", +"92 44 OFFCURVE", +"92 118 CURVE SMOOTH", +"92 200 OFFCURVE", +"164 248 OFFCURVE", +"374 272 CURVE", +"374 98 LINE", +"310 44 OFFCURVE", +"258 16 OFFCURVE", +"200 16 CURVE SMOOTH" +); +} +); +vertWidth = 0; +width = 486; +}, +{ +layerId = "A99E50E2-B754-449B-A60B-37BA27802C99"; +paths = ( +{ +closed = 1; +nodes = ( +"242 -12 OFFCURVE", +"286 12 OFFCURVE", +"326 48 CURVE", +"330 48 LINE", +"342 0 LINE", +"482 0 LINE", +"482 278 LINE SMOOTH", +"482 442 OFFCURVE", +"404 512 OFFCURVE", +"274 512 CURVE SMOOTH", +"196 512 OFFCURVE", +"124 488 OFFCURVE", +"54 446 CURVE", +"114 334 LINE", +"166 362 OFFCURVE", +"204 376 OFFCURVE", +"240 376 CURVE SMOOTH", +"284 376 OFFCURVE", +"306 360 OFFCURVE", +"310 324 CURVE", +"118 304 OFFCURVE", +"38 246 OFFCURVE", +"38 142 CURVE SMOOTH", +"38 60 OFFCURVE", +"94 -12 OFFCURVE", +"188 -12 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"218 120 OFFCURVE", +"202 133 OFFCURVE", +"202 156 CURVE SMOOTH", +"202 184 OFFCURVE", +"228 210 OFFCURVE", +"310 222 CURVE", +"310 154 LINE", +"292 134 OFFCURVE", +"276 120 OFFCURVE", +"248 120 CURVE SMOOTH" +); +} +); +vertWidth = 0; +width = 536; +} +); +note = ""; +unicode = 0061; +}, +{ +glyphname = d; +layers = ( +{ +layerId = "8DB0CCF0-BD6F-426B-90E2-48FD021BE868"; +paths = ( +{ +closed = 1; +nodes = ( +"318 -12 OFFCURVE", +"372 24 OFFCURVE", +"412 64 CURVE", +"414 64 LINE", +"418 0 LINE", +"444 0 LINE", +"444 722 LINE", +"414 722 LINE", +"414 520 LINE", +"416 430 LINE", +"366 468 OFFCURVE", +"326 490 OFFCURVE", +"268 490 CURVE SMOOTH", +"152 490 OFFCURVE", +"54 392 OFFCURVE", +"54 238 CURVE SMOOTH", +"54 76 OFFCURVE", +"132 -12 OFFCURVE", +"252 -12 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"146 16 OFFCURVE", +"86 106 OFFCURVE", +"86 238 CURVE SMOOTH", +"86 362 OFFCURVE", +"164 462 OFFCURVE", +"266 462 CURVE SMOOTH", +"316 462 OFFCURVE", +"360 444 OFFCURVE", +"414 396 CURVE", +"414 100 LINE", +"360 46 OFFCURVE", +"310 16 OFFCURVE", +"254 16 CURVE SMOOTH" +); +} +); +vertWidth = 0; +width = 540; +}, +{ +layerId = "A99E50E2-B754-449B-A60B-37BA27802C99"; +paths = ( +{ +closed = 1; +nodes = ( +"284 -12 OFFCURVE", +"332 12 OFFCURVE", +"366 46 CURVE", +"370 46 LINE", +"382 0 LINE", +"522 0 LINE", +"522 696 LINE", +"350 696 LINE", +"350 534 LINE", +"356 462 LINE", +"326 492 OFFCURVE", +"294 512 OFFCURVE", +"240 512 CURVE SMOOTH", +"138 512 OFFCURVE", +"36 414 OFFCURVE", +"36 250 CURVE SMOOTH", +"36 88 OFFCURVE", +"116 -12 OFFCURVE", +"240 -12 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"240 128 OFFCURVE", +"212 162 OFFCURVE", +"212 252 CURVE SMOOTH", +"212 340 OFFCURVE", +"246 372 OFFCURVE", +"282 372 CURVE SMOOTH", +"304 372 OFFCURVE", +"330 366 OFFCURVE", +"350 348 CURVE", +"350 164 LINE", +"332 136 OFFCURVE", +"312 128 OFFCURVE", +"286 128 CURVE SMOOTH" +); +} +); +vertWidth = 0; +width = 580; +} +); +note = ""; +unicode = 0064; +}, +{ +glyphname = f; +layers = ( +{ +layerId = "8DB0CCF0-BD6F-426B-90E2-48FD021BE868"; +paths = ( +{ +closed = 1; +nodes = ( +"130 0 LINE", +"130 592 LINE SMOOTH", +"130 664 OFFCURVE", +"154 706 OFFCURVE", +"208 706 CURVE SMOOTH", +"226 706 OFFCURVE", +"246 702 OFFCURVE", +"266 692 CURVE", +"276 718 LINE", +"254 728 OFFCURVE", +"230 734 OFFCURVE", +"210 734 CURVE SMOOTH", +"142 734 OFFCURVE", +"100 690 OFFCURVE", +"100 596 CURVE SMOOTH", +"100 0 LINE" +); +}, +{ +closed = 1; +nodes = ( +"244 450 LINE", +"244 478 LINE", +"100 478 LINE", +"34 474 LINE", +"34 450 LINE" +); +} +); +vertWidth = 0; +width = 252; +}, +{ +layerId = "A99E50E2-B754-449B-A60B-37BA27802C99"; +paths = ( +{ +closed = 1; +nodes = ( +"260 0 LINE", +"260 512 LINE SMOOTH", +"260 559 OFFCURVE", +"280 574 OFFCURVE", +"312 574 CURVE SMOOTH", +"328 574 OFFCURVE", +"346 570 OFFCURVE", +"362 564 CURVE", +"392 690 LINE", +"370 698 OFFCURVE", +"332 708 OFFCURVE", +"286 708 CURVE SMOOTH", +"138 708 OFFCURVE", +"88 613 OFFCURVE", +"88 506 CURVE SMOOTH", +"88 0 LINE" +); +}, +{ +closed = 1; +nodes = ( +"344 366 LINE", +"344 500 LINE", +"98 500 LINE", +"22 494 LINE", +"22 366 LINE" +); +} +); +vertWidth = 0; +width = 360; +} +); +note = ""; +unicode = 0066; +}, +{ +glyphname = n; +layers = ( +{ +layerId = "8DB0CCF0-BD6F-426B-90E2-48FD021BE868"; +paths = ( +{ +closed = 1; +nodes = ( +"126 0 LINE", +"126 366 LINE", +"188 430 OFFCURVE", +"232 462 OFFCURVE", +"292 462 CURVE SMOOTH", +"374 462 OFFCURVE", +"408 410 OFFCURVE", +"408 304 CURVE SMOOTH", +"408 0 LINE", +"438 0 LINE", +"438 308 LINE SMOOTH", +"438 432 OFFCURVE", +"392 490 OFFCURVE", +"294 490 CURVE SMOOTH", +"228 490 OFFCURVE", +"178 452 OFFCURVE", +"128 402 CURVE", +"126 402 LINE", +"122 478 LINE", +"96 478 LINE", +"96 0 LINE" +); +} +); +vertWidth = 0; +width = 526; +}, +{ +layerId = "A99E50E2-B754-449B-A60B-37BA27802C99"; +paths = ( +{ +closed = 1; +nodes = ( +"230 0 LINE", +"230 328 LINE", +"256 352 OFFCURVE", +"274 366 OFFCURVE", +"306 366 CURVE SMOOTH", +"340 366 OFFCURVE", +"356 350 OFFCURVE", +"356 286 CURVE SMOOTH", +"356 0 LINE", +"528 0 LINE", +"528 308 LINE SMOOTH", +"528 432 OFFCURVE", +"482 512 OFFCURVE", +"372 512 CURVE SMOOTH", +"304 512 OFFCURVE", +"254 478 OFFCURVE", +"214 440 CURVE", +"210 440 LINE", +"198 500 LINE", +"58 500 LINE", +"58 0 LINE" +); +} +); +vertWidth = 0; +width = 582; +} +); +note = ""; +unicode = 006E; +}, +{ +glyphname = t; +layers = ( +{ +layerId = "8DB0CCF0-BD6F-426B-90E2-48FD021BE868"; +paths = ( +{ +closed = 1; +nodes = ( +"234 -12 OFFCURVE", +"264 -4 OFFCURVE", +"292 6 CURVE", +"282 32 LINE", +"264 24 OFFCURVE", +"238 16 OFFCURVE", +"220 16 CURVE SMOOTH", +"150 16 OFFCURVE", +"136 60 OFFCURVE", +"136 122 CURVE SMOOTH", +"136 450 LINE", +"278 450 LINE", +"278 478 LINE", +"136 478 LINE", +"136 618 LINE", +"110 618 LINE", +"106 478 LINE", +"30 474 LINE", +"30 450 LINE", +"106 450 LINE", +"106 126 LINE SMOOTH", +"106 44 OFFCURVE", +"130 -12 OFFCURVE", +"218 -12 CURVE SMOOTH" +); +} +); +vertWidth = 0; +width = 302; +}, +{ +layerId = "A99E50E2-B754-449B-A60B-37BA27802C99"; +paths = ( +{ +closed = 1; +nodes = ( +"319 -12 OFFCURVE", +"356 -2 OFFCURVE", +"382 6 CURVE", +"356 130 LINE", +"344 126 OFFCURVE", +"328 122 OFFCURVE", +"312 122 CURVE SMOOTH", +"280 122 OFFCURVE", +"252 140 OFFCURVE", +"252 195 CURVE SMOOTH", +"252 366 LINE", +"366 366 LINE", +"366 500 LINE", +"252 500 LINE", +"252 630 LINE", +"110 630 LINE", +"90 500 LINE", +"14 494 LINE", +"14 366 LINE", +"80 366 LINE", +"80 192 LINE SMOOTH", +"80 70 OFFCURVE", +"134 -12 OFFCURVE", +"264 -12 CURVE SMOOTH" +); +} +); +vertWidth = 0; +width = 400; +} +); +note = ""; +unicode = 0074; +}, +{ +glyphname = f_t; +layers = ( +{ +layerId = "8DB0CCF0-BD6F-426B-90E2-48FD021BE868"; +paths = ( +{ +closed = 1; +nodes = ( +"130 0 LINE", +"130 592 LINE SMOOTH", +"130 664 OFFCURVE", +"154 706 OFFCURVE", +"208 706 CURVE SMOOTH", +"226 706 OFFCURVE", +"246 702 OFFCURVE", +"266 692 CURVE", +"276 718 LINE", +"254 728 OFFCURVE", +"230 734 OFFCURVE", +"210 734 CURVE SMOOTH", +"142 734 OFFCURVE", +"100 690 OFFCURVE", +"100 596 CURVE SMOOTH", +"100 0 LINE" +); +}, +{ +closed = 1; +nodes = ( +"450 -12 OFFCURVE", +"480 -4 OFFCURVE", +"508 6 CURVE", +"498 32 LINE", +"480 24 OFFCURVE", +"454 16 OFFCURVE", +"436 16 CURVE SMOOTH", +"366 16 OFFCURVE", +"352 60 OFFCURVE", +"352 122 CURVE SMOOTH", +"352 450 LINE", +"494 450 LINE", +"494 478 LINE", +"352 478 LINE", +"352 618 LINE", +"326 618 LINE", +"322 478 LINE", +"100 478 LINE", +"34 474 LINE", +"34 450 LINE", +"322 450 LINE", +"322 126 LINE SMOOTH", +"322 44 OFFCURVE", +"346 -12 OFFCURVE", +"434 -12 CURVE SMOOTH" +); +} +); +vertWidth = 0; +width = 518; +}, +{ +layerId = "A99E50E2-B754-449B-A60B-37BA27802C99"; +paths = ( +{ +closed = 1; +nodes = ( +"260 0 LINE", +"260 512 LINE SMOOTH", +"260 559 OFFCURVE", +"280 574 OFFCURVE", +"312 574 CURVE SMOOTH", +"328 574 OFFCURVE", +"346 570 OFFCURVE", +"362 564 CURVE", +"392 690 LINE", +"370 698 OFFCURVE", +"332 708 OFFCURVE", +"286 708 CURVE SMOOTH", +"138 708 OFFCURVE", +"88 613 OFFCURVE", +"88 506 CURVE SMOOTH", +"88 0 LINE" +); +}, +{ +closed = 1; +nodes = ( +"643 -12 OFFCURVE", +"680 -2 OFFCURVE", +"706 6 CURVE", +"680 130 LINE", +"668 126 OFFCURVE", +"652 122 OFFCURVE", +"636 122 CURVE SMOOTH", +"604 122 OFFCURVE", +"576 140 OFFCURVE", +"576 195 CURVE", +"576 366 LINE", +"690 366 LINE", +"690 500 LINE", +"576 500 LINE", +"576 630 LINE", +"434 630 LINE", +"414 500 LINE", +"98 500 LINE", +"22 494 LINE", +"22 366 LINE", +"404 366 LINE", +"404 192 LINE SMOOTH", +"404 70 OFFCURVE", +"458 -12 OFFCURVE", +"588 -12 CURVE SMOOTH" +); +} +); +vertWidth = 0; +width = 724; +} +); +note = ""; +}, +{ +glyphname = a.alt; +layers = ( +{ +layerId = "8DB0CCF0-BD6F-426B-90E2-48FD021BE868"; +paths = ( +{ +closed = 1; +nodes = ( +"318 -12 OFFCURVE", +"372 24 OFFCURVE", +"412 64 CURVE", +"414 64 LINE", +"418 0 LINE", +"444 0 LINE", +"444 478 LINE", +"416 478 LINE", +"414 432 LINE", +"412 432 LINE", +"366 468 OFFCURVE", +"326 490 OFFCURVE", +"268 490 CURVE SMOOTH", +"152 490 OFFCURVE", +"54 392 OFFCURVE", +"54 238 CURVE SMOOTH", +"54 76 OFFCURVE", +"132 -12 OFFCURVE", +"252 -12 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"146 16 OFFCURVE", +"86 106 OFFCURVE", +"86 238 CURVE SMOOTH", +"86 362 OFFCURVE", +"164 462 OFFCURVE", +"266 462 CURVE SMOOTH", +"316 462 OFFCURVE", +"360 444 OFFCURVE", +"414 396 CURVE", +"414 100 LINE", +"360 46 OFFCURVE", +"310 16 OFFCURVE", +"254 16 CURVE SMOOTH" +); +} +); +vertWidth = 0; +width = 540; +}, +{ +layerId = "A99E50E2-B754-449B-A60B-37BA27802C99"; +paths = ( +{ +closed = 1; +nodes = ( +"284 -12 OFFCURVE", +"332 12 OFFCURVE", +"366 46 CURVE", +"370 46 LINE", +"382 0 LINE", +"522 0 LINE", +"522 500 LINE", +"388 500 LINE", +"374 450 LINE", +"370 450 LINE", +"332 494 OFFCURVE", +"292 512 OFFCURVE", +"244 512 CURVE SMOOTH", +"142 512 OFFCURVE", +"36 414 OFFCURVE", +"36 250 CURVE SMOOTH", +"36 88 OFFCURVE", +"116 -12 OFFCURVE", +"240 -12 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"240 128 OFFCURVE", +"212 162 OFFCURVE", +"212 252 CURVE SMOOTH", +"212 340 OFFCURVE", +"246 372 OFFCURVE", +"282 372 CURVE SMOOTH", +"304 372 OFFCURVE", +"330 366 OFFCURVE", +"350 348 CURVE", +"350 164 LINE", +"332 136 OFFCURVE", +"312 128 OFFCURVE", +"286 128 CURVE SMOOTH" +); +} +); +vertWidth = 0; +width = 580; +} +); +note = ""; +}, +{ +glyphname = A.sc; +layers = ( +{ +layerId = "8DB0CCF0-BD6F-426B-90E2-48FD021BE868"; +paths = ( +{ +closed = 1; +nodes = ( +"42 0 LINE", +"158 304 LINE SMOOTH", +"181 366 OFFCURVE", +"199 414 OFFCURVE", +"220 475 CURVE", +"224 475 LINE", +"245 415 OFFCURVE", +"263 367 OFFCURVE", +"286 304 CURVE SMOOTH", +"400 0 LINE", +"434 0 LINE", +"236 510 LINE", +"207 510 LINE", +"10 0 LINE" +); +}, +{ +closed = 1; +nodes = ( +"345 176 LINE", +"345 204 LINE", +"97 204 LINE", +"97 176 LINE" +); +} +); +vertWidth = 0; +width = 444; +}, +{ +layerId = "A99E50E2-B754-449B-A60B-37BA27802C99"; +paths = ( +{ +closed = 1; +nodes = ( +"164 0 LINE", +"219 244 LINE SMOOTH", +"230 292 OFFCURVE", +"241 358 OFFCURVE", +"252 409 CURVE", +"256 409 LINE", +"269 359 OFFCURVE", +"280 292 OFFCURVE", +"291 244 CURVE SMOOTH", +"346 0 LINE", +"526 0 LINE", +"361 532 LINE", +"155 532 LINE", +"-10 0 LINE" +); +}, +{ +closed = 1; +nodes = ( +"397 94 LINE", +"397 216 LINE", +"118 216 LINE", +"118 94 LINE" +); +} +); +vertWidth = 0; +width = 516; +} +); +note = ""; +}, +{ +glyphname = atilde; +layers = ( +{ +components = ( +{ +name = a; +}, +{ +name = tildecmb; +transform = "{1, 0, 0, 1, 242, 0}"; +} +); +layerId = "8DB0CCF0-BD6F-426B-90E2-48FD021BE868"; +vertWidth = 0; +width = 486; +}, +{ +components = ( +{ +name = a; +}, +{ +name = tildecmb; +transform = "{1, 0, 0, 1, 266, 0}"; +} +); +layerId = "A99E50E2-B754-449B-A60B-37BA27802C99"; +vertWidth = 0; +width = 536; +} +); +note = ""; +unicode = 00E3; +}, +{ +glyphname = ampersand; +layers = ( +{ +layerId = "8DB0CCF0-BD6F-426B-90E2-48FD021BE868"; +paths = ( +{ +closed = 1; +nodes = ( +"302 -12 OFFCURVE", +"360 28 OFFCURVE", +"410 84 CURVE SMOOTH", +"468 153 OFFCURVE", +"510 244 OFFCURVE", +"538 342 CURVE", +"508 342 LINE", +"482 248 OFFCURVE", +"444 166 OFFCURVE", +"388 102 CURVE SMOOTH", +"344 52 OFFCURVE", +"288 16 OFFCURVE", +"226 16 CURVE SMOOTH", +"142 16 OFFCURVE", +"70 76 OFFCURVE", +"70 168 CURVE SMOOTH", +"70 332 OFFCURVE", +"364 392 OFFCURVE", +"364 556 CURVE SMOOTH", +"364 622 OFFCURVE", +"328 672 OFFCURVE", +"260 672 CURVE SMOOTH", +"184 672 OFFCURVE", +"130 612 OFFCURVE", +"130 528 CURVE SMOOTH", +"130 382 OFFCURVE", +"264 196 OFFCURVE", +"392 82 CURVE SMOOTH", +"446 34 OFFCURVE", +"496 4 OFFCURVE", +"538 -12 CURVE", +"550 16 LINE", +"508 32 OFFCURVE", +"460 62 OFFCURVE", +"410 106 CURVE SMOOTH", +"290 210 OFFCURVE", +"160 392 OFFCURVE", +"160 530 CURVE SMOOTH", +"160 592 OFFCURVE", +"196 644 OFFCURVE", +"258 644 CURVE SMOOTH", +"314 644 OFFCURVE", +"334 598 OFFCURVE", +"334 554 CURVE SMOOTH", +"334 402 OFFCURVE", +"38 346 OFFCURVE", +"38 166 CURVE SMOOTH", +"38 56 OFFCURVE", +"124 -12 OFFCURVE", +"224 -12 CURVE SMOOTH" +); +} +); +vertWidth = 0; +width = 562; +}, +{ +layerId = "A99E50E2-B754-449B-A60B-37BA27802C99"; +paths = ( +{ +closed = 1; +nodes = ( +"362 -12 OFFCURVE", +"452 34 OFFCURVE", +"516 104 CURVE SMOOTH", +"590 187 OFFCURVE", +"638 276 OFFCURVE", +"668 374 CURVE", +"512 374 LINE", +"490 292 OFFCURVE", +"448 228 OFFCURVE", +"398 180 CURVE SMOOTH", +"356 142 OFFCURVE", +"310 118 OFFCURVE", +"268 118 CURVE SMOOTH", +"216 118 OFFCURVE", +"184 146 OFFCURVE", +"184 186 CURVE SMOOTH", +"184 296 OFFCURVE", +"458 332 OFFCURVE", +"458 508 CURVE SMOOTH", +"458 602 OFFCURVE", +"390 662 OFFCURVE", +"286 662 CURVE SMOOTH", +"170 662 OFFCURVE", +"98 580 OFFCURVE", +"98 486 CURVE SMOOTH", +"98 359 OFFCURVE", +"244 182 OFFCURVE", +"415 75 CURVE SMOOTH", +"485 31 OFFCURVE", +"560 0 OFFCURVE", +"630 -12 CURVE", +"670 126 LINE", +"627 131 OFFCURVE", +"573 153 OFFCURVE", +"518 183 CURVE SMOOTH", +"382 258 OFFCURVE", +"239 390 OFFCURVE", +"239 486 CURVE SMOOTH", +"239 528 OFFCURVE", +"263 550 OFFCURVE", +"290 550 CURVE SMOOTH", +"315 550 OFFCURVE", +"328 536 OFFCURVE", +"328 508 CURVE SMOOTH", +"328 386 OFFCURVE", +"22 396 OFFCURVE", +"22 176 CURVE SMOOTH", +"22 78 OFFCURVE", +"95 -12 OFFCURVE", +"246 -12 CURVE SMOOTH" +); +} +); +vertWidth = 0; +width = 690; +} +); +note = ""; +unicode = 0026; +}, +{ +glyphname = circledotted; +production = uni25CC; +layers = ( +{ +layerId = "8DB0CCF0-BD6F-426B-90E2-48FD021BE868"; +paths = ( +{ +closed = 1; +nodes = ( +"129 97 OFFCURVE", +"141 110 OFFCURVE", +"141 129 CURVE SMOOTH", +"141 150 OFFCURVE", +"128 161 OFFCURVE", +"110 161 CURVE SMOOTH", +"94 161 OFFCURVE", +"81 150 OFFCURVE", +"81 129 CURVE SMOOTH", +"81 110 OFFCURVE", +"94 97 OFFCURVE", +"110 97 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"101 207 OFFCURVE", +"114 219 OFFCURVE", +"114 239 CURVE SMOOTH", +"114 260 OFFCURVE", +"101 270 OFFCURVE", +"82 270 CURVE SMOOTH", +"67 270 OFFCURVE", +"54 260 OFFCURVE", +"54 239 CURVE SMOOTH", +"54 219 OFFCURVE", +"67 207 OFFCURVE", +"82 207 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"129 318 OFFCURVE", +"141 330 OFFCURVE", +"141 351 CURVE SMOOTH", +"141 371 OFFCURVE", +"128 382 OFFCURVE", +"110 382 CURVE SMOOTH", +"94 382 OFFCURVE", +"81 371 OFFCURVE", +"81 351 CURVE SMOOTH", +"81 330 OFFCURVE", +"94 318 OFFCURVE", +"110 318 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"207 15 OFFCURVE", +"219 27 OFFCURVE", +"219 49 CURVE SMOOTH", +"219 68 OFFCURVE", +"206 78 OFFCURVE", +"189 78 CURVE SMOOTH", +"173 78 OFFCURVE", +"160 68 OFFCURVE", +"160 49 CURVE SMOOTH", +"160 27 OFFCURVE", +"173 15 OFFCURVE", +"189 15 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"207 400 OFFCURVE", +"219 412 OFFCURVE", +"219 431 CURVE SMOOTH", +"219 453 OFFCURVE", +"206 463 OFFCURVE", +"189 463 CURVE SMOOTH", +"173 463 OFFCURVE", +"160 453 OFFCURVE", +"160 431 CURVE SMOOTH", +"160 412 OFFCURVE", +"173 400 OFFCURVE", +"189 400 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"313 -12 OFFCURVE", +"326 -1 OFFCURVE", +"326 20 CURVE SMOOTH", +"326 40 OFFCURVE", +"313 51 OFFCURVE", +"295 51 CURVE SMOOTH", +"279 51 OFFCURVE", +"266 40 OFFCURVE", +"266 20 CURVE SMOOTH", +"266 -1 OFFCURVE", +"279 -12 OFFCURVE", +"295 -12 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"313 426 OFFCURVE", +"326 438 OFFCURVE", +"326 458 CURVE SMOOTH", +"326 478 OFFCURVE", +"313 490 OFFCURVE", +"295 490 CURVE SMOOTH", +"279 490 OFFCURVE", +"266 478 OFFCURVE", +"266 458 CURVE SMOOTH", +"266 438 OFFCURVE", +"279 426 OFFCURVE", +"295 426 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"420 15 OFFCURVE", +"431 27 OFFCURVE", +"431 49 CURVE SMOOTH", +"431 68 OFFCURVE", +"418 78 OFFCURVE", +"401 78 CURVE SMOOTH", +"386 78 OFFCURVE", +"373 68 OFFCURVE", +"373 49 CURVE SMOOTH", +"373 27 OFFCURVE", +"386 15 OFFCURVE", +"401 15 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"420 399 OFFCURVE", +"431 412 OFFCURVE", +"431 431 CURVE SMOOTH", +"431 452 OFFCURVE", +"418 462 OFFCURVE", +"401 462 CURVE SMOOTH", +"386 462 OFFCURVE", +"373 452 OFFCURVE", +"373 431 CURVE SMOOTH", +"373 412 OFFCURVE", +"386 399 OFFCURVE", +"401 399 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"499 97 OFFCURVE", +"510 110 OFFCURVE", +"510 129 CURVE SMOOTH", +"510 150 OFFCURVE", +"497 161 OFFCURVE", +"480 161 CURVE SMOOTH", +"465 161 OFFCURVE", +"451 150 OFFCURVE", +"451 129 CURVE SMOOTH", +"451 110 OFFCURVE", +"465 97 OFFCURVE", +"480 97 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"526 207 OFFCURVE", +"538 219 OFFCURVE", +"538 239 CURVE SMOOTH", +"538 260 OFFCURVE", +"523 270 OFFCURVE", +"508 270 CURVE SMOOTH", +"491 270 OFFCURVE", +"478 260 OFFCURVE", +"478 239 CURVE SMOOTH", +"478 219 OFFCURVE", +"491 207 OFFCURVE", +"508 207 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"499 317 OFFCURVE", +"510 329 OFFCURVE", +"510 349 CURVE SMOOTH", +"510 369 OFFCURVE", +"497 380 OFFCURVE", +"480 380 CURVE SMOOTH", +"465 380 OFFCURVE", +"451 369 OFFCURVE", +"451 349 CURVE SMOOTH", +"451 329 OFFCURVE", +"465 317 OFFCURVE", +"480 317 CURVE SMOOTH" +); +} +); +vertWidth = 0; +width = 592; +}, +{ +layerId = "A99E50E2-B754-449B-A60B-37BA27802C99"; +paths = ( +{ +closed = 1; +nodes = ( +"131 96 OFFCURVE", +"149 112 OFFCURVE", +"149 141 CURVE SMOOTH", +"149 170 OFFCURVE", +"130 187 OFFCURVE", +"104 187 CURVE SMOOTH", +"82 187 OFFCURVE", +"61 170 OFFCURVE", +"61 141 CURVE SMOOTH", +"61 112 OFFCURVE", +"82 96 OFFCURVE", +"104 96 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"104 204 OFFCURVE", +"122 221 OFFCURVE", +"122 251 CURVE SMOOTH", +"122 279 OFFCURVE", +"102 295 OFFCURVE", +"76 295 CURVE SMOOTH", +"53 295 OFFCURVE", +"32 279 OFFCURVE", +"32 251 CURVE SMOOTH", +"32 221 OFFCURVE", +"53 204 OFFCURVE", +"76 204 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"131 313 OFFCURVE", +"149 331 OFFCURVE", +"149 360 CURVE SMOOTH", +"149 390 OFFCURVE", +"130 405 OFFCURVE", +"104 405 CURVE SMOOTH", +"82 405 OFFCURVE", +"61 390 OFFCURVE", +"61 360 CURVE SMOOTH", +"61 331 OFFCURVE", +"82 313 OFFCURVE", +"104 313 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"208 14 OFFCURVE", +"227 31 OFFCURVE", +"227 61 CURVE SMOOTH", +"227 89 OFFCURVE", +"206 105 OFFCURVE", +"182 105 CURVE SMOOTH", +"158 105 OFFCURVE", +"137 89 OFFCURVE", +"137 61 CURVE SMOOTH", +"137 31 OFFCURVE", +"158 14 OFFCURVE", +"182 14 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"208 395 OFFCURVE", +"227 412 OFFCURVE", +"227 440 CURVE SMOOTH", +"227 470 OFFCURVE", +"206 486 OFFCURVE", +"182 486 CURVE SMOOTH", +"158 486 OFFCURVE", +"137 470 OFFCURVE", +"137 440 CURVE SMOOTH", +"137 412 OFFCURVE", +"158 395 OFFCURVE", +"182 395 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"314 -13 OFFCURVE", +"332 4 OFFCURVE", +"332 34 CURVE SMOOTH", +"332 62 OFFCURVE", +"313 78 OFFCURVE", +"287 78 CURVE SMOOTH", +"264 78 OFFCURVE", +"244 62 OFFCURVE", +"244 34 CURVE SMOOTH", +"244 4 OFFCURVE", +"264 -13 OFFCURVE", +"287 -13 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"314 421 OFFCURVE", +"332 439 OFFCURVE", +"332 468 CURVE SMOOTH", +"332 496 OFFCURVE", +"313 512 OFFCURVE", +"287 512 CURVE SMOOTH", +"264 512 OFFCURVE", +"244 496 OFFCURVE", +"244 468 CURVE SMOOTH", +"244 439 OFFCURVE", +"264 421 OFFCURVE", +"287 421 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"420 14 OFFCURVE", +"438 31 OFFCURVE", +"438 61 CURVE SMOOTH", +"438 89 OFFCURVE", +"417 105 OFFCURVE", +"392 105 CURVE SMOOTH", +"369 105 OFFCURVE", +"348 89 OFFCURVE", +"348 61 CURVE SMOOTH", +"348 31 OFFCURVE", +"369 14 OFFCURVE", +"392 14 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"420 394 OFFCURVE", +"438 411 OFFCURVE", +"438 440 CURVE SMOOTH", +"438 469 OFFCURVE", +"417 486 OFFCURVE", +"392 486 CURVE SMOOTH", +"369 486 OFFCURVE", +"348 469 OFFCURVE", +"348 440 CURVE SMOOTH", +"348 411 OFFCURVE", +"369 394 OFFCURVE", +"392 394 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"498 96 OFFCURVE", +"516 112 OFFCURVE", +"516 141 CURVE SMOOTH", +"516 170 OFFCURVE", +"496 187 OFFCURVE", +"472 187 CURVE SMOOTH", +"447 187 OFFCURVE", +"426 170 OFFCURVE", +"426 141 CURVE SMOOTH", +"426 112 OFFCURVE", +"447 96 OFFCURVE", +"472 96 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"524 204 OFFCURVE", +"543 221 OFFCURVE", +"543 251 CURVE SMOOTH", +"543 279 OFFCURVE", +"522 295 OFFCURVE", +"498 295 CURVE SMOOTH", +"473 295 OFFCURVE", +"453 279 OFFCURVE", +"453 251 CURVE SMOOTH", +"453 221 OFFCURVE", +"473 204 OFFCURVE", +"498 204 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"498 313 OFFCURVE", +"516 330 OFFCURVE", +"516 359 CURVE SMOOTH", +"516 388 OFFCURVE", +"496 404 OFFCURVE", +"472 404 CURVE SMOOTH", +"447 404 OFFCURVE", +"426 388 OFFCURVE", +"426 359 CURVE SMOOTH", +"426 330 OFFCURVE", +"447 313 OFFCURVE", +"472 313 CURVE SMOOTH" +); +} +); +vertWidth = 0; +width = 574; +} +); +note = ""; +unicode = 25CC; +}, +{ +glyphname = tildecmb; +production = uni0303; +layers = ( +{ +layerId = "8DB0CCF0-BD6F-426B-90E2-48FD021BE868"; +paths = ( +{ +closed = 1; +nodes = ( +"140 580 OFFCURVE", +"156 646 OFFCURVE", +"160 702 CURVE", +"134 704 LINE", +"132 652 OFFCURVE", +"116 606 OFFCURVE", +"79 606 CURVE SMOOTH", +"20 606 OFFCURVE", +"0 706 OFFCURVE", +"-76 706 CURVE SMOOTH", +"-140 706 OFFCURVE", +"-156 641 OFFCURVE", +"-160 584 CURVE", +"-134 582 LINE", +"-132 636 OFFCURVE", +"-116 680 OFFCURVE", +"-78 680 CURVE SMOOTH", +"-20 680 OFFCURVE", +"0 580 OFFCURVE", +"77 580 CURVE SMOOTH" +); +} +); +vertWidth = 0; +width = 0; +}, +{ +layerId = "A99E50E2-B754-449B-A60B-37BA27802C99"; +paths = ( +{ +closed = 1; +nodes = ( +"144 572 OFFCURVE", +"194 617 OFFCURVE", +"196 730 CURVE", +"90 736 LINE", +"86 700 OFFCURVE", +"76 690 OFFCURVE", +"60 690 CURVE SMOOTH", +"34 690 OFFCURVE", +"-4 746 OFFCURVE", +"-64 746 CURVE SMOOTH", +"-144 746 OFFCURVE", +"-194 701 OFFCURVE", +"-196 588 CURVE", +"-90 582 LINE", +"-86 618 OFFCURVE", +"-76 628 OFFCURVE", +"-60 628 CURVE SMOOTH", +"-34 628 OFFCURVE", +"4 572 OFFCURVE", +"64 572 CURVE SMOOTH" +); +} +); +vertWidth = 0; +width = 0; +} +); +note = ""; +unicode = 0303; +}, +{ +glyphname = dieresiscmb; +production = uni0308; +layers = ( +{ +layerId = "8DB0CCF0-BD6F-426B-90E2-48FD021BE868"; +paths = ( +{ +closed = 1; +nodes = ( +"-68 602 OFFCURVE", +"-54 616 OFFCURVE", +"-54 634 CURVE SMOOTH", +"-54 652 OFFCURVE", +"-68 666 OFFCURVE", +"-86 666 CURVE SMOOTH", +"-104 666 OFFCURVE", +"-118 652 OFFCURVE", +"-118 634 CURVE SMOOTH", +"-118 616 OFFCURVE", +"-104 602 OFFCURVE", +"-86 602 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"104 602 OFFCURVE", +"118 616 OFFCURVE", +"118 634 CURVE SMOOTH", +"118 652 OFFCURVE", +"104 666 OFFCURVE", +"86 666 CURVE SMOOTH", +"68 666 OFFCURVE", +"54 652 OFFCURVE", +"54 634 CURVE SMOOTH", +"54 616 OFFCURVE", +"68 602 OFFCURVE", +"86 602 CURVE SMOOTH" +); +} +); +vertWidth = 0; +width = 0; +}, +{ +layerId = "A99E50E2-B754-449B-A60B-37BA27802C99"; +paths = ( +{ +closed = 1; +nodes = ( +"-67 562 OFFCURVE", +"-34 597 OFFCURVE", +"-34 642 CURVE SMOOTH", +"-34 687 OFFCURVE", +"-67 722 OFFCURVE", +"-114 722 CURVE SMOOTH", +"-161 722 OFFCURVE", +"-194 687 OFFCURVE", +"-194 642 CURVE SMOOTH", +"-194 597 OFFCURVE", +"-161 562 OFFCURVE", +"-114 562 CURVE SMOOTH" +); +}, +{ +closed = 1; +nodes = ( +"161 562 OFFCURVE", +"194 597 OFFCURVE", +"194 642 CURVE SMOOTH", +"194 687 OFFCURVE", +"161 722 OFFCURVE", +"114 722 CURVE SMOOTH", +"67 722 OFFCURVE", +"34 687 OFFCURVE", +"34 642 CURVE SMOOTH", +"34 597 OFFCURVE", +"67 562 OFFCURVE", +"114 562 CURVE SMOOTH" +); +} +); +vertWidth = 0; +width = 0; +} +); +note = ""; +unicode = 0308; +}, +{ +glyphname = tildebelowcmb; +production = uni0330; +layers = ( +{ +components = ( +{ +name = tildecmb; +transform = "{1, 0, 0, 1, 0, -800}"; +} +); +layerId = "8DB0CCF0-BD6F-426B-90E2-48FD021BE868"; +vertWidth = 0; +width = 0; +}, +{ +components = ( +{ +name = tildecmb; +transform = "{1, 0, 0, 1, 0, -800}"; +} +); +layerId = "A99E50E2-B754-449B-A60B-37BA27802C99"; +vertWidth = 0; +width = 0; +} +); +note = ""; +unicode = 0330; +}, +{ +glyphname = dieresisbelowcmb; +production = uni0324; +layers = ( +{ +components = ( +{ +name = dieresiscmb; +transform = "{1, 0, 0, 1, 0, -790}"; +} +); +layerId = "8DB0CCF0-BD6F-426B-90E2-48FD021BE868"; +vertWidth = 0; +width = 0; +}, +{ +components = ( +{ +name = dieresiscmb; +transform = "{1, 0, 0, 1, 0, -786}"; +} +); +layerId = "A99E50E2-B754-449B-A60B-37BA27802C99"; +vertWidth = 0; +width = 0; +} +); +note = ""; +unicode = 0324; +} +); +instances = ( +{ +customParameters = ( +{ +name = weightClass; +value = 0; +}, +{ +name = postscriptFontName; +value = "TestFamily2-ExtraLight"; +}, +{ +name = "UFO Filename"; +value = "instances/TestFamily2-ExtraLight.ufo"; +} +); +interpolationWeight = 0; +name = ExtraLight; +weightClass = Thin; +}, +{ +customParameters = ( +{ +name = postscriptFontName; +value = "TestFamily2-Light"; +}, +{ +name = "UFO Filename"; +value = "instances/TestFamily2-Light.ufo"; +} +); +name = Light; +weightClass = Thin; +}, +{ +customParameters = ( +{ +name = weightClass; +value = 368; +}, +{ +name = postscriptFontName; +value = "TestFamily2-Regular"; +}, +{ +name = "UFO Filename"; +value = "instances/TestFamily2-Regular.ufo"; +} +); +interpolationWeight = 368; +name = Regular; +weightClass = Normal; +}, +{ +customParameters = ( +{ +name = postscriptFontName; +value = "TestFamily2-Semibold"; +}, +{ +name = "UFO Filename"; +value = "instances/TestFamily2-Semibold.ufo"; +} +); +interpolationWeight = 600; +name = Semibold; +weightClass = DemiBold; +}, +{ +customParameters = ( +{ +name = weightClass; +value = 824; +}, +{ +name = postscriptFontName; +value = "TestFamily2-Bold"; +}, +{ +name = "UFO Filename"; +value = "instances/TestFamily2-Bold.ufo"; +} +); +interpolationWeight = 824; +name = Bold; +weightClass = ExtraBold; +}, +{ +customParameters = ( +{ +name = weightClass; +value = 1000; +}, +{ +name = postscriptFontName; +value = "TestFamily2-Black"; +}, +{ +name = "UFO Filename"; +value = "instances/TestFamily2-Black.ufo"; +} +); +interpolationWeight = 1000; +name = Black; +weightClass = Black; +} +); +unitsPerEm = 1000; +userData = { +com.schriftgestaltung.Glyphs.groupsNotInFeature = ( +); +}; +versionMajor = 2; +versionMinor = 20; +} diff --git a/Tests/varLib/data/SparseMasters.glyphs b/Tests/varLib/data/SparseMasters.glyphs new file mode 100644 index 000000000..0c38c139c --- /dev/null +++ b/Tests/varLib/data/SparseMasters.glyphs @@ -0,0 +1,510 @@ +{ +.appVersion = "895"; +customParameters = ( +{ +name = glyphOrder; +value = ( +.notdef, +a, +e, +edotabove, +s, +dotabovecomb +); +}, +{ +name = "Disable Last Change"; +value = 1; +} +); +disablesAutomaticAlignment = 1; +familyName = "Sparse Masters"; +fontMaster = ( +{ +ascender = 750; +capHeight = 700; +customParameters = ( +{ +name = "UFO Filename"; +value = "master_ufo/SparseMasters-Regular.ufo"; +} +); +descender = -250; +id = "CCC32AD0-E3D7-4595-BA12-BA39A95902C9"; +userData = { +com.defcon.sortDescriptor = ( +{ +ascending = ( +.notdef, +a, +e, +edotabove, +s, +dotabovecomb +); +type = glyphList; +} +); +com.typemytype.robofont.compileSettings.autohint = 1; +com.typemytype.robofont.compileSettings.checkOutlines = 0; +com.typemytype.robofont.compileSettings.createDummyDSIG = 1; +com.typemytype.robofont.compileSettings.decompose = 0; +com.typemytype.robofont.compileSettings.generateFormat = 0; +com.typemytype.robofont.compileSettings.releaseMode = 0; +com.typemytype.robofont.italicSlantOffset = 0; +com.typemytype.robofont.shouldAddPointsInSplineConversion = 1; +}; +weightValue = 350; +xHeight = 500; +}, +{ +ascender = 750; +capHeight = 700; +customParameters = ( +{ +name = "UFO Filename"; +value = "master_ufo/SparseMasters-Medium.ufo"; +}, +{ +name = "Master Name"; +value = Medium; +} +); +descender = -250; +id = "2B2F6A55-E8C4-4456-AFD7-7A9468BB18B9"; +userData = { +com.typemytype.robofont.compileSettings.autohint = 1; +com.typemytype.robofont.compileSettings.checkOutlines = 0; +com.typemytype.robofont.compileSettings.createDummyDSIG = 1; +com.typemytype.robofont.compileSettings.decompose = 0; +com.typemytype.robofont.compileSettings.generateFormat = 0; +com.typemytype.robofont.compileSettings.releaseMode = 0; +com.typemytype.robofont.italicSlantOffset = 0; +com.typemytype.robofont.shouldAddPointsInSplineConversion = 1; +}; +weightValue = 450; +xHeight = 500; +}, +{ +ascender = 750; +capHeight = 700; +customParameters = ( +{ +name = "UFO Filename"; +value = "master_ufo/SparseMasters-Bold.ufo"; +}, +{ +name = "Master Name"; +value = Bold; +} +); +descender = -250; +id = "36D5BF76-782C-4F60-A6DB-0A9BC5828108"; +userData = { +com.defcon.sortDescriptor = ( +{ +ascending = ( +.notdef, +a, +e, +edotabove, +s, +dotabovecomb +); +type = glyphList; +} +); +com.typemytype.robofont.compileSettings.autohint = 1; +com.typemytype.robofont.compileSettings.checkOutlines = 0; +com.typemytype.robofont.compileSettings.createDummyDSIG = 1; +com.typemytype.robofont.compileSettings.decompose = 0; +com.typemytype.robofont.compileSettings.generateFormat = 0; +com.typemytype.robofont.compileSettings.releaseMode = 0; +com.typemytype.robofont.italicSlantOffset = 0; +com.typemytype.robofont.shouldAddPointsInSplineConversion = 1; +}; +weightValue = 625; +xHeight = 500; +} +); +glyphs = ( +{ +glyphname = .notdef; +layers = ( +{ +layerId = "CCC32AD0-E3D7-4595-BA12-BA39A95902C9"; +paths = ( +{ +closed = 1; +nodes = ( +"450 750 LINE", +"450 -250 LINE", +"50 -250 LINE", +"50 750 LINE" +); +}, +{ +closed = 1; +nodes = ( +"400 700 LINE", +"100 700 LINE", +"100 -200 LINE", +"400 -200 LINE" +); +} +); +vertWidth = 0; +width = 500; +}, +{ +layerId = "2B2F6A55-E8C4-4456-AFD7-7A9468BB18B9"; +paths = ( +{ +closed = 1; +nodes = ( +"450 750 LINE", +"450 -250 LINE", +"50 -250 LINE", +"50 750 LINE" +); +}, +{ +closed = 1; +nodes = ( +"400 700 LINE", +"100 700 LINE", +"100 -200 LINE", +"400 -200 LINE" +); +} +); +vertWidth = 0; +width = 500; +}, +{ +layerId = "36D5BF76-782C-4F60-A6DB-0A9BC5828108"; +paths = ( +{ +closed = 1; +nodes = ( +"450 750 LINE", +"450 -250 LINE", +"50 -250 LINE", +"50 750 LINE" +); +}, +{ +closed = 1; +nodes = ( +"400 700 LINE", +"100 700 LINE", +"100 -200 LINE", +"400 -200 LINE" +); +} +); +vertWidth = 0; +width = 500; +} +); +note = .notdef; +}, +{ +glyphname = a; +layers = ( +{ +layerId = "CCC32AD0-E3D7-4595-BA12-BA39A95902C9"; +paths = ( +{ +closed = 1; +nodes = ( +"214 504 LINE", +"9 428 LINE", +"36 337 LINE", +"208 397 LINE", +"363 357 LINE", +"366 -3 LINE", +"468 -1 LINE", +"447 434 LINE" +); +}, +{ +closed = 1; +nodes = ( +"29 22 LINE", +"168 -12 LINE", +"389 71 LINE", +"383 134 LINE", +"161 74 LINE", +"86 126 LINE", +"88 172 LINE", +"382 207 LINE", +"378 263 LINE", +"26 240 LINE" +); +} +); +vertWidth = 0; +width = 600; +}, +{ +layerId = "36D5BF76-782C-4F60-A6DB-0A9BC5828108"; +paths = ( +{ +closed = 1; +nodes = ( +"214 504 LINE", +"9 428 LINE", +"36 281 LINE", +"208 341 LINE", +"304 303 LINE", +"307 -1 LINE", +"468 -1 LINE", +"447 434 LINE" +); +}, +{ +closed = 1; +nodes = ( +"29 22 LINE", +"168 -12 LINE", +"389 71 LINE", +"383 149 LINE", +"201 102 LINE", +"163 133 LINE", +"165 179 LINE", +"381 184 LINE", +"378 263 LINE", +"26 240 LINE" +); +} +); +vertWidth = 0; +width = 600; +} +); +note = a; +unicode = 0061; +}, +{ +glyphname = e; +layers = ( +{ +layerId = "CCC32AD0-E3D7-4595-BA12-BA39A95902C9"; +paths = ( +{ +closed = 1; +nodes = ( +"571 305 LINE", +"316 513 LINE", +"40 261 LINE", +"188 -18 LINE", +"526 45 LINE", +"509 129 LINE", +"229 75 LINE", +"147 263 LINE", +"317 416 LINE", +"480 292 LINE", +"125 298 LINE", +"127 228 LINE", +"576 226 LINE" +); +} +); +vertWidth = 0; +width = 600; +}, +{ +layerId = "2B2F6A55-E8C4-4456-AFD7-7A9468BB18B9"; +paths = ( +{ +closed = 1; +nodes = ( +"571 305 LINE", +"316 513 LINE", +"40 261 LINE", +"188 -18 LINE", +"526 45 LINE", +"507 157 LINE", +"264 116 LINE", +"180 264 LINE", +"318 387 LINE", +"396 297 LINE", +"125 298 LINE", +"126 203 LINE", +"576 199 LINE" +); +} +); +vertWidth = 0; +width = 600; +}, +{ +layerId = "36D5BF76-782C-4F60-A6DB-0A9BC5828108"; +paths = ( +{ +closed = 1; +nodes = ( +"596 304 LINE", +"314 548 LINE", +"9 262 LINE", +"188 -18 LINE", +"528 0 LINE", +"524 184 LINE", +"244 130 LINE", +"217 264 LINE", +"301 360 LINE", +"404 293 LINE", +"195 299 LINE", +"197 229 LINE", +"601 225 LINE" +); +} +); +vertWidth = 0; +width = 600; +} +); +note = e; +unicode = 0065; +}, +{ +glyphname = edotabove; +layers = ( +{ +components = ( +{ +name = e; +}, +{ +name = dotabovecomb; +transform = "{1, 0, 0, 1, 313, 96}"; +} +); +layerId = "CCC32AD0-E3D7-4595-BA12-BA39A95902C9"; +vertWidth = 0; +width = 600; +}, +{ +components = ( +{ +name = e; +}, +{ +name = dotabovecomb; +transform = "{1, 0, 0, 1, 307, 187}"; +} +); +layerId = "36D5BF76-782C-4F60-A6DB-0A9BC5828108"; +vertWidth = 0; +width = 600; +} +); +note = edotabove; +unicode = 0117; +}, +{ +glyphname = s; +layers = ( +{ +layerId = "CCC32AD0-E3D7-4595-BA12-BA39A95902C9"; +paths = ( +{ +closed = 1; +nodes = ( +"38 343 LINE", +"427 155 LINE", +"282 76 LINE", +"53 174 LINE", +"25 83 LINE", +"304 -13 LINE", +"582 174 LINE", +"213 366 LINE", +"326 442 LINE", +"539 376 LINE", +"559 459 LINE", +"324 530 LINE" +); +} +); +vertWidth = 0; +width = 600; +}, +{ +layerId = "36D5BF76-782C-4F60-A6DB-0A9BC5828108"; +paths = ( +{ +closed = 1; +nodes = ( +"16 398 LINE", +"347 149 LINE", +"221 119 LINE", +"26 226 LINE", +"7 79 LINE", +"284 -58 LINE", +"608 141 LINE", +"268 357 LINE", +"324 402 LINE", +"537 336 LINE", +"559 459 LINE", +"324 530 LINE" +); +} +); +vertWidth = 0; +width = 600; +} +); +note = s; +unicode = 0073; +}, +{ +glyphname = dotabovecomb; +layers = ( +{ +layerId = "CCC32AD0-E3D7-4595-BA12-BA39A95902C9"; +paths = ( +{ +closed = 1; +nodes = ( +"41 501 LINE", +"50 589 LINE", +"-21 597 LINE", +"-37 503 LINE" +); +} +); +vertWidth = 0; +width = 0; +}, +{ +layerId = "36D5BF76-782C-4F60-A6DB-0A9BC5828108"; +paths = ( +{ +closed = 1; +nodes = ( +"58 488 LINE", +"63 605 LINE", +"-29 625 LINE", +"-64 483 LINE" +); +} +); +vertWidth = 0; +width = 0; +} +); +note = dotabovecomb; +unicode = 0307; +} +); +instances = ( +); +unitsPerEm = 1000; +userData = { +com.schriftgestaltung.Glyphs.groupsNotInFeature = ( +); +}; +versionMajor = 1; +versionMinor = 0; +} diff --git a/Tests/varLib/data/SparseMasters_ufo.designspace b/Tests/varLib/data/SparseMasters_ufo.designspace new file mode 100644 index 000000000..1fd57bca9 --- /dev/null +++ b/Tests/varLib/data/SparseMasters_ufo.designspace @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tests/varLib/data/master_ttx_varfont_ttf/SparseMasters-VF.ttx b/Tests/varLib/data/master_ttx_varfont_ttf/SparseMasters-VF.ttx new file mode 100644 index 000000000..819b34416 --- /dev/null +++ b/Tests/varLib/data/master_ttx_varfont_ttf/SparseMasters-VF.ttx @@ -0,0 +1,501 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Weight + + + Sparse Masters + + + Regular + + + 0.000;NONE;SparseMasters-Regular + + + Sparse Masters Regular + + + Version 0.000 + + + SparseMasters-Regular + + + Weight + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + wght + 0x0 + 350.0 + 350.0 + 625.0 + 256 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/fontinfo.plist b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/fontinfo.plist new file mode 100644 index 000000000..cac9398db --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/fontinfo.plist @@ -0,0 +1,41 @@ + + + + + ascender + 750 + capHeight + 700 + descender + -250 + familyName + Sparse Masters + guidelines + + + postscriptBlueValues + + + postscriptFamilyBlues + + + postscriptFamilyOtherBlues + + + postscriptOtherBlues + + + postscriptStemSnapH + + + postscriptStemSnapV + + + styleName + Bold + unitsPerEm + 1000 + xHeight + 500 + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/_notdef.glif b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/_notdef.glif new file mode 100644 index 000000000..88bd5c316 --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/_notdef.glif @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + .notdef + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/a.glif b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/a.glif new file mode 100644 index 000000000..fa17a6622 --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/a.glif @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/contents.plist b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/contents.plist new file mode 100644 index 000000000..da7e7a787 --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/contents.plist @@ -0,0 +1,18 @@ + + + + + .notdef + _notdef.glif + a + a.glif + dotabovecomb + dotabovecomb.glif + e + e.glif + edotabove + edotabove.glif + s + s.glif + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/dotabovecomb.glif b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/dotabovecomb.glif new file mode 100644 index 000000000..64577cf07 --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/dotabovecomb.glif @@ -0,0 +1,15 @@ + + + + + + + + + + + + + dotabovecomb + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/e.glif b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/e.glif new file mode 100644 index 000000000..b5e3ce969 --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/e.glif @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + e + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/edotabove.glif b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/edotabove.glif new file mode 100644 index 000000000..7305f58cf --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/edotabove.glif @@ -0,0 +1,12 @@ + + + + + + + + + + edotabove + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/layerinfo.plist b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/layerinfo.plist new file mode 100644 index 000000000..5ae89c642 --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/layerinfo.plist @@ -0,0 +1,8 @@ + + + + + color + 0.9904,0.5022,0.0329,1 + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/s.glif b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/s.glif new file mode 100644 index 000000000..4fddecc4d --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/s.glif @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + s + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/layercontents.plist b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/layercontents.plist new file mode 100644 index 000000000..03e5dde58 --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/layercontents.plist @@ -0,0 +1,10 @@ + + + + + + public.default + glyphs + + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/lib.plist b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/lib.plist new file mode 100644 index 000000000..c4121f4a3 --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/lib.plist @@ -0,0 +1,47 @@ + + + + + com.defcon.sortDescriptor + + + ascending + + .notdef + a + e + edotabove + s + dotabovecomb + + type + glyphList + + + com.typemytype.robofont.compileSettings.autohint + + com.typemytype.robofont.compileSettings.checkOutlines + + com.typemytype.robofont.compileSettings.createDummyDSIG + + com.typemytype.robofont.compileSettings.decompose + + com.typemytype.robofont.compileSettings.generateFormat + 0 + com.typemytype.robofont.compileSettings.releaseMode + + com.typemytype.robofont.italicSlantOffset + 0 + com.typemytype.robofont.shouldAddPointsInSplineConversion + 1 + public.glyphOrder + + .notdef + a + e + edotabove + s + dotabovecomb + + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/metainfo.plist b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/metainfo.plist new file mode 100644 index 000000000..555d9ce4c --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/metainfo.plist @@ -0,0 +1,10 @@ + + + + + creator + com.github.fonttools.ufoLib + formatVersion + 3 + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/fontinfo.plist b/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/fontinfo.plist new file mode 100644 index 000000000..088d66ae5 --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/fontinfo.plist @@ -0,0 +1,41 @@ + + + + + ascender + 750 + capHeight + 700 + descender + -250 + familyName + Sparse Masters + guidelines + + + postscriptBlueValues + + + postscriptFamilyBlues + + + postscriptFamilyOtherBlues + + + postscriptOtherBlues + + + postscriptStemSnapH + + + postscriptStemSnapV + + + styleName + Medium + unitsPerEm + 1000 + xHeight + 500 + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/_notdef.glif b/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/_notdef.glif new file mode 100644 index 000000000..a24589a15 --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/_notdef.glif @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + +.notdef + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/contents.plist b/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/contents.plist new file mode 100644 index 000000000..456fd5ded --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/contents.plist @@ -0,0 +1,10 @@ + + + + + .notdef + _notdef.glif + e + e.glif + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/e.glif b/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/e.glif new file mode 100644 index 000000000..299e10d52 --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/e.glif @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + +e + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/layerinfo.plist b/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/layerinfo.plist new file mode 100644 index 000000000..5ae89c642 --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/layerinfo.plist @@ -0,0 +1,8 @@ + + + + + color + 0.9904,0.5022,0.0329,1 + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/layercontents.plist b/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/layercontents.plist new file mode 100644 index 000000000..03e5dde58 --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/layercontents.plist @@ -0,0 +1,10 @@ + + + + + + public.default + glyphs + + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/lib.plist b/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/lib.plist new file mode 100644 index 000000000..372a93726 --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/lib.plist @@ -0,0 +1,27 @@ + + + + + com.typemytype.robofont.compileSettings.autohint + + com.typemytype.robofont.compileSettings.checkOutlines + + com.typemytype.robofont.compileSettings.createDummyDSIG + + com.typemytype.robofont.compileSettings.decompose + + com.typemytype.robofont.compileSettings.generateFormat + 0 + com.typemytype.robofont.compileSettings.releaseMode + + com.typemytype.robofont.italicSlantOffset + 0 + com.typemytype.robofont.shouldAddPointsInSplineConversion + 1 + public.glyphOrder + + .notdef + e + + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/metainfo.plist b/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/metainfo.plist new file mode 100644 index 000000000..555d9ce4c --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/metainfo.plist @@ -0,0 +1,10 @@ + + + + + creator + com.github.fonttools.ufoLib + formatVersion + 3 + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/fontinfo.plist b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/fontinfo.plist new file mode 100644 index 000000000..47e1944b2 --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/fontinfo.plist @@ -0,0 +1,41 @@ + + + + + ascender + 750 + capHeight + 700 + descender + -250 + familyName + Sparse Masters + guidelines + + + postscriptBlueValues + + + postscriptFamilyBlues + + + postscriptFamilyOtherBlues + + + postscriptOtherBlues + + + postscriptStemSnapH + + + postscriptStemSnapV + + + styleName + Regular + unitsPerEm + 1000 + xHeight + 500 + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/_notdef.glif b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/_notdef.glif new file mode 100644 index 000000000..88bd5c316 --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/_notdef.glif @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + .notdef + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/a.glif b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/a.glif new file mode 100644 index 000000000..d152ff604 --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/a.glif @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/contents.plist b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/contents.plist new file mode 100644 index 000000000..da7e7a787 --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/contents.plist @@ -0,0 +1,18 @@ + + + + + .notdef + _notdef.glif + a + a.glif + dotabovecomb + dotabovecomb.glif + e + e.glif + edotabove + edotabove.glif + s + s.glif + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/dotabovecomb.glif b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/dotabovecomb.glif new file mode 100644 index 000000000..0ce49404b --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/dotabovecomb.glif @@ -0,0 +1,15 @@ + + + + + + + + + + + + + dotabovecomb + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/e.glif b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/e.glif new file mode 100644 index 000000000..824f54242 --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/e.glif @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + e + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/edotabove.glif b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/edotabove.glif new file mode 100644 index 000000000..b35f6b671 --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/edotabove.glif @@ -0,0 +1,12 @@ + + + + + + + + + + edotabove + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/layerinfo.plist b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/layerinfo.plist new file mode 100644 index 000000000..5ae89c642 --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/layerinfo.plist @@ -0,0 +1,8 @@ + + + + + color + 0.9904,0.5022,0.0329,1 + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/s.glif b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/s.glif new file mode 100644 index 000000000..3bd6b74b6 --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/s.glif @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + s + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/layercontents.plist b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/layercontents.plist new file mode 100644 index 000000000..03e5dde58 --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/layercontents.plist @@ -0,0 +1,10 @@ + + + + + + public.default + glyphs + + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/lib.plist b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/lib.plist new file mode 100644 index 000000000..c4121f4a3 --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/lib.plist @@ -0,0 +1,47 @@ + + + + + com.defcon.sortDescriptor + + + ascending + + .notdef + a + e + edotabove + s + dotabovecomb + + type + glyphList + + + com.typemytype.robofont.compileSettings.autohint + + com.typemytype.robofont.compileSettings.checkOutlines + + com.typemytype.robofont.compileSettings.createDummyDSIG + + com.typemytype.robofont.compileSettings.decompose + + com.typemytype.robofont.compileSettings.generateFormat + 0 + com.typemytype.robofont.compileSettings.releaseMode + + com.typemytype.robofont.italicSlantOffset + 0 + com.typemytype.robofont.shouldAddPointsInSplineConversion + 1 + public.glyphOrder + + .notdef + a + e + edotabove + s + dotabovecomb + + + diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/metainfo.plist b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/metainfo.plist new file mode 100644 index 000000000..555d9ce4c --- /dev/null +++ b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/metainfo.plist @@ -0,0 +1,10 @@ + + + + + creator + com.github.fonttools.ufoLib + formatVersion + 3 + + diff --git a/Tests/varLib/interpolatable_test.py b/Tests/varLib/interpolatable_test.py index 96f6c8473..ec33a158e 100644 --- a/Tests/varLib/interpolatable_test.py +++ b/Tests/varLib/interpolatable_test.py @@ -92,6 +92,33 @@ class InterpolatableTest(unittest.TestCase): otf_paths = self.get_file_list(self.tempdir, suffix) self.assertIsNone(interpolatable_main(otf_paths)) + + def test_interpolatable_ufo(self): + ttx_dir = self.get_test_input("master_ufo") + ufo_paths = self.get_file_list(ttx_dir, ".ufo", "TestFamily2-") + self.assertIsNone(interpolatable_main(ufo_paths)) + + def test_designspace(self): + designspace_path = self.get_test_input("InterpolateLayout.designspace") + self.assertIsNone(interpolatable_main([designspace_path])) + + def test_glyphsapp(self): + glyphsapp_path = self.get_test_input("InterpolateLayout.glyphs") + self.assertIsNone(interpolatable_main([glyphsapp_path])) + + def test_VF(self): + suffix = ".ttf" + ttx_dir = self.get_test_input("master_ttx_varfont_ttf") + + self.temp_dir() + ttx_paths = self.get_file_list(ttx_dir, ".ttx", "SparseMasters-") + for path in ttx_paths: + self.compile_font(path, suffix, self.tempdir) + + ttf_paths = self.get_file_list(self.tempdir, suffix) + + problems = interpolatable_main(["--quiet"] + ttf_paths) + self.assertIsNone(problems) def test_sparse_interpolatable_ttfs(self): suffix = ".ttf" @@ -118,6 +145,49 @@ class InterpolatableTest(unittest.TestCase): # purposely putting the sparse master (medium) last self.assertIsNone(interpolatable_main(["--ignore-missing"] + [ttf_paths[0]] + [ttf_paths[2]] + [ttf_paths[1]])) + def test_sparse_interpolatable_ufos(self): + ttx_dir = self.get_test_input("master_ufo") + ufo_paths = self.get_file_list(ttx_dir, ".ufo", "SparseMasters-") + + # without --ignore-missing + problems = interpolatable_main(["--quiet"] + ufo_paths) + self.assertEqual(problems['a'], [{'type': 'missing', 'master': 'SparseMasters-Medium'}]) + self.assertEqual(problems['s'], [{'type': 'missing', 'master': 'SparseMasters-Medium'}]) + self.assertEqual(problems['edotabove'], [{'type': 'missing', 'master': 'SparseMasters-Medium'}]) + self.assertEqual(problems['dotabovecomb'], [{'type': 'missing', 'master': 'SparseMasters-Medium'}]) + + # normal order, with --ignore-missing + self.assertIsNone(interpolatable_main(["--ignore-missing"] + ufo_paths)) + # purposely putting the sparse master (medium) first + self.assertIsNone(interpolatable_main(["--ignore-missing"] + [ufo_paths[1]] + [ufo_paths[0]] + [ufo_paths[2]])) + # purposely putting the sparse master (medium) last + self.assertIsNone(interpolatable_main(["--ignore-missing"] + [ufo_paths[0]] + [ufo_paths[2]] + [ufo_paths[1]])) + + def test_sparse_designspace(self): + designspace_path = self.get_test_input("SparseMasters_ufo.designspace") + + problems = interpolatable_main(["--quiet", designspace_path]) + self.assertEqual(problems['a'], [{'type': 'missing', 'master': 'SparseMasters-Medium'}]) + self.assertEqual(problems['s'], [{'type': 'missing', 'master': 'SparseMasters-Medium'}]) + self.assertEqual(problems['edotabove'], [{'type': 'missing', 'master': 'SparseMasters-Medium'}]) + self.assertEqual(problems['dotabovecomb'], [{'type': 'missing', 'master': 'SparseMasters-Medium'}]) + + # normal order, with --ignore-missing + self.assertIsNone(interpolatable_main(["--ignore-missing", designspace_path])) + + def test_sparse_designspace(self): + glyphsapp_path = self.get_test_input("SparseMasters.glyphs") + + problems = interpolatable_main(["--quiet", glyphsapp_path]) + self.assertEqual(problems['a'], [{'type': 'missing', 'master': 'Sparse Masters-Medium'}]) + self.assertEqual(problems['s'], [{'type': 'missing', 'master': 'Sparse Masters-Medium'}]) + self.assertEqual(problems['edotabove'], [{'type': 'missing', 'master': 'Sparse Masters-Medium'}]) + self.assertEqual(problems['dotabovecomb'], [{'type': 'missing', 'master': 'Sparse Masters-Medium'}]) + + # normal order, with --ignore-missing + self.assertIsNone(interpolatable_main(["--ignore-missing", glyphsapp_path])) + + def test_interpolatable_varComposite(self): input_path = self.get_test_input( "..", "..", "ttLib", "data", "varc-ac00-ac01.ttf" diff --git a/variable_ttf/SparseMasters_ufo-VF.ttf b/variable_ttf/SparseMasters_ufo-VF.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4a94d7ad3047e204e0f46645f447a96971dfb622 GIT binary patch literal 1632 zcmaJ>e@L8V9REDedv~wLZadGpPVESPU0T^1mw3gFJWFrVrpD>q$mKls^bDOkZ5a*H z&bCqgv5o$T6$DXGjEZOyBqWQG1pR<*FqD=xq-}{b=9q}QZ=dJhv&^99_&(3~^ZosN zzt4LR0JdNh8ro``tD;lxPi=smLR2+0J`yf4BmyL(^iI)40lA0TNj^1G=It$gqi_2bmfB;v8of~((N zBfmhZNKjy(5s%Wgn7BC6H$1XwFJ2*@CeG>Y?}&*2ZZTdt@s_^W$N)COPkk+M{-Ic3 zeEh(z9|5hCvgknn(6HftDhk-Xq`n5~u3Wi0qwa(5&>d*nb%o~|&mUVm%~{hSBXW`0 z0jZ>1^wTCx2lMWy{s$RZi)5*}J5mw{vgqR>r8A}V3fpA0Xk}w<@^!hN^4-=+SwNKi z9mis7*5mqy`Wl20({#DW8m6@gtWclIAeQ7L`Fz491Q^#zDos-^V9rvjZlRH~xht=1 z*ccCRA%i*_Vu)i%cs1QLDP4!m_sn@k+Tj}>h%4^=i6sveY@i!v+)?*hNS z#9pF%8Hv$k*r=4E_Qu^95vK6BDo^-EQ{>y+OaI{v-SHpcpi68aI6Nr;L|n)~?1U_e_1&*3#ZE31QBP zJDkB@)oYDc@n`OGio2~DYS`>_m(@cKfbU36!sevJM`ZDmUtwXI*EpXYY2Jo145WEG z^6*ZYci=%xSUh98Ft;z>)14SbBdudNj3G`nA9du1Fic)aqCC6t0(w&xJFuNu)Nd#1 z(Lkypx8DEX-Vbl^UvIfFQ~n0q=5z%;=*J<}^-u2gQT{*QKE~)_{R!U3deuD4a|rPG z?^0c^My-%&7Me5O**_d>?>`cEtuY<_eeKGN&Ev`@g;Jc_l+2ad3%PTi-bgq_VJgD> zrM=cpL7b72sW@uM7deYmXtibXg^5&-jFh~UjwCs#OlhEOR1EM1sJi*zm)bq3z!P`| zEn$qR4E&-oCN5lfO*8B2N{^3e^1JEjr0s^T``pJyCGJ7?6zfzq;y$Zlj5 Date: Wed, 5 Apr 2023 22:33:38 -0400 Subject: [PATCH 07/13] formatting with black to get lint to pass --- Lib/fontTools/varLib/interpolatable.py | 46 +++++---- Tests/varLib/interpolatable_test.py | 127 ++++++++++++++++++------- 2 files changed, 124 insertions(+), 49 deletions(-) diff --git a/Lib/fontTools/varLib/interpolatable.py b/Lib/fontTools/varLib/interpolatable.py index 4e8b96252..8ab119c5c 100644 --- a/Lib/fontTools/varLib/interpolatable.py +++ b/Lib/fontTools/varLib/interpolatable.py @@ -161,7 +161,7 @@ def test(glyphsets, glyphs=None, names=None, ignore_missing=False): for glyphset, name in zip(glyphsets, names): glyph = glyphset[glyph_name] - + if glyph is None: if not ignore_missing: add_problem(glyph_name, {"type": "missing", "master": name}) @@ -248,12 +248,14 @@ def test(glyphsets, glyphs=None, names=None, ignore_missing=False): _rot_list([complex(*pt) for pt, bl in mirrored], i) ) - # m0idx should be the index of the first non-None item in allNodeTypes, + # m0idx should be the index of the first non-None item in allNodeTypes, # else give it the first index of None, which is likely 0 - m0idx = allNodeTypes.index(next((x for x in allNodeTypes if x is not None), None)) + m0idx = allNodeTypes.index( + next((x for x in allNodeTypes if x is not None), None) + ) # m0 is the first non-None item in allNodeTypes, or the first item if all are None m0 = allNodeTypes[m0idx] - for i, m1 in enumerate(allNodeTypes[m0idx+1:]): + for i, m1 in enumerate(allNodeTypes[m0idx + 1 :]): if m1 is None: continue if len(m0) != len(m1): @@ -301,12 +303,14 @@ def test(glyphsets, glyphs=None, names=None, ignore_missing=False): ) continue - # m0idx should be the index of the first non-None item in allVectors, + # m0idx should be the index of the first non-None item in allVectors, # else give it the first index of None, which is likely 0 - m0idx = allVectors.index(next((x for x in allVectors if x is not None), None)) + m0idx = allVectors.index( + next((x for x in allVectors if x is not None), None) + ) # m0 is the first non-None item in allVectors, or the first item if all are None m0 = allVectors[m0idx] - for i, m1 in enumerate(allVectors[m0idx+1:]): + for i, m1 in enumerate(allVectors[m0idx + 1 :]): if m1 is None: continue if len(m0) != len(m1): @@ -333,13 +337,15 @@ def test(glyphsets, glyphs=None, names=None, ignore_missing=False): }, ) break - - # m0idx should be the index of the first non-None item in allContourIsomorphisms, + + # m0idx should be the index of the first non-None item in allContourIsomorphisms, # else give it the first index of None, which is likely 0 - m0idx = allContourIsomorphisms.index(next((x for x in allContourIsomorphisms if x is not None), None)) + m0idx = allContourIsomorphisms.index( + next((x for x in allContourIsomorphisms if x is not None), None) + ) # m0 is the first non-None item in allContourIsomorphisms, or the first item if all are None m0 = allContourIsomorphisms[m0idx] - for i, m1 in enumerate(allContourIsomorphisms[m0idx+1:]): + for i, m1 in enumerate(allContourIsomorphisms[m0idx + 1 :]): if m1 is None: continue if len(m0) != len(m1): @@ -397,7 +403,11 @@ def main(args=None): help="Will not report glyphs missing from sparse masters as errors", ) parser.add_argument( - "inputs", metavar="FILE", type=str, nargs="+", help="Input a single DesignSpace/Glyphs file, or multiple TTF/UFO files" + "inputs", + metavar="FILE", + type=str, + nargs="+", + help="Input a single DesignSpace/Glyphs file, or multiple TTF/UFO files", ) args = parser.parse_args(args) @@ -477,11 +487,11 @@ def main(args=None): glyphset = font.getGlyphSet() else: glyphset = font - glyphsets.append({k:glyphset[k] for k in glyphset.keys()}) - + glyphsets.append({k: glyphset[k] for k in glyphset.keys()}) + if not glyphs: glyphs = set([gn for glyphset in glyphsets for gn in glyphset.keys()]) - + for glyphset in glyphsets: glyphSetGlyphNames = set(glyphset.keys()) diff = glyphs - glyphSetGlyphNames @@ -489,8 +499,10 @@ def main(args=None): for gn in diff: glyphset[gn] = None - problems = test(glyphsets, glyphs=glyphs, names=names, ignore_missing=args.ignore_missing) - + problems = test( + glyphsets, glyphs=glyphs, names=names, ignore_missing=args.ignore_missing + ) + if not args.quiet: if args.json: import json diff --git a/Tests/varLib/interpolatable_test.py b/Tests/varLib/interpolatable_test.py index ec33a158e..a20aee10a 100644 --- a/Tests/varLib/interpolatable_test.py +++ b/Tests/varLib/interpolatable_test.py @@ -105,7 +105,7 @@ class InterpolatableTest(unittest.TestCase): def test_glyphsapp(self): glyphsapp_path = self.get_test_input("InterpolateLayout.glyphs") self.assertIsNone(interpolatable_main([glyphsapp_path])) - + def test_VF(self): suffix = ".ttf" ttx_dir = self.get_test_input("master_ttx_varfont_ttf") @@ -116,10 +116,10 @@ class InterpolatableTest(unittest.TestCase): self.compile_font(path, suffix, self.tempdir) ttf_paths = self.get_file_list(self.tempdir, suffix) - + problems = interpolatable_main(["--quiet"] + ttf_paths) self.assertIsNone(problems) - + def test_sparse_interpolatable_ttfs(self): suffix = ".ttf" ttx_dir = self.get_test_input("master_ttx_interpolatable_ttf") @@ -130,64 +130,127 @@ class InterpolatableTest(unittest.TestCase): self.compile_font(path, suffix, self.tempdir) ttf_paths = self.get_file_list(self.tempdir, suffix) - + # without --ignore-missing problems = interpolatable_main(["--quiet"] + ttf_paths) - self.assertEqual(problems['a'], [{'type': 'missing', 'master': 'SparseMasters-Medium'}]) - self.assertEqual(problems['s'], [{'type': 'missing', 'master': 'SparseMasters-Medium'}]) - self.assertEqual(problems['edotabove'], [{'type': 'missing', 'master': 'SparseMasters-Medium'}]) - self.assertEqual(problems['dotabovecomb'], [{'type': 'missing', 'master': 'SparseMasters-Medium'}]) - + self.assertEqual( + problems["a"], + [{"type": "missing", "master": "SparseMasters-Medium"}] + ) + self.assertEqual( + problems["s"], + [{"type": "missing", "master": "SparseMasters-Medium"}] + ) + self.assertEqual( + problems["edotabove"], + [{"type": "missing", "master": "SparseMasters-Medium"}], + ) + self.assertEqual( + problems["dotabovecomb"], + [{"type": "missing", "master": "SparseMasters-Medium"}], + ) + # normal order, with --ignore-missing self.assertIsNone(interpolatable_main(["--ignore-missing"] + ttf_paths)) # purposely putting the sparse master (medium) first - self.assertIsNone(interpolatable_main(["--ignore-missing"] + [ttf_paths[1]] + [ttf_paths[0]] + [ttf_paths[2]])) + self.assertIsNone( + interpolatable_main( + ["--ignore-missing"] + [ttf_paths[1]] + [ttf_paths[0]] + [ttf_paths[2]] + ) + ) # purposely putting the sparse master (medium) last - self.assertIsNone(interpolatable_main(["--ignore-missing"] + [ttf_paths[0]] + [ttf_paths[2]] + [ttf_paths[1]])) + self.assertIsNone( + interpolatable_main( + ["--ignore-missing"] + [ttf_paths[0]] + [ttf_paths[2]] + [ttf_paths[1]] + ) + ) def test_sparse_interpolatable_ufos(self): ttx_dir = self.get_test_input("master_ufo") ufo_paths = self.get_file_list(ttx_dir, ".ufo", "SparseMasters-") - + # without --ignore-missing problems = interpolatable_main(["--quiet"] + ufo_paths) - self.assertEqual(problems['a'], [{'type': 'missing', 'master': 'SparseMasters-Medium'}]) - self.assertEqual(problems['s'], [{'type': 'missing', 'master': 'SparseMasters-Medium'}]) - self.assertEqual(problems['edotabove'], [{'type': 'missing', 'master': 'SparseMasters-Medium'}]) - self.assertEqual(problems['dotabovecomb'], [{'type': 'missing', 'master': 'SparseMasters-Medium'}]) - + self.assertEqual( + problems["a"], + [{"type": "missing", "master": "SparseMasters-Medium"}] + ) + self.assertEqual( + problems["s"], + [{"type": "missing", "master": "SparseMasters-Medium"}] + ) + self.assertEqual( + problems["edotabove"], + [{"type": "missing", "master": "SparseMasters-Medium"}], + ) + self.assertEqual( + problems["dotabovecomb"], + [{"type": "missing", "master": "SparseMasters-Medium"}], + ) + # normal order, with --ignore-missing self.assertIsNone(interpolatable_main(["--ignore-missing"] + ufo_paths)) # purposely putting the sparse master (medium) first - self.assertIsNone(interpolatable_main(["--ignore-missing"] + [ufo_paths[1]] + [ufo_paths[0]] + [ufo_paths[2]])) + self.assertIsNone( + interpolatable_main( + ["--ignore-missing"] + [ufo_paths[1]] + [ufo_paths[0]] + [ufo_paths[2]] + ) + ) # purposely putting the sparse master (medium) last - self.assertIsNone(interpolatable_main(["--ignore-missing"] + [ufo_paths[0]] + [ufo_paths[2]] + [ufo_paths[1]])) + self.assertIsNone( + interpolatable_main( + ["--ignore-missing"] + [ufo_paths[0]] + [ufo_paths[2]] + [ufo_paths[1]] + ) + ) def test_sparse_designspace(self): designspace_path = self.get_test_input("SparseMasters_ufo.designspace") - + problems = interpolatable_main(["--quiet", designspace_path]) - self.assertEqual(problems['a'], [{'type': 'missing', 'master': 'SparseMasters-Medium'}]) - self.assertEqual(problems['s'], [{'type': 'missing', 'master': 'SparseMasters-Medium'}]) - self.assertEqual(problems['edotabove'], [{'type': 'missing', 'master': 'SparseMasters-Medium'}]) - self.assertEqual(problems['dotabovecomb'], [{'type': 'missing', 'master': 'SparseMasters-Medium'}]) - + self.assertEqual( + problems["a"], + [{"type": "missing", "master": "SparseMasters-Medium"}] + ) + self.assertEqual( + problems["s"], + [{"type": "missing", "master": "SparseMasters-Medium"}] + ) + self.assertEqual( + problems["edotabove"], + [{"type": "missing", "master": "SparseMasters-Medium"}], + ) + self.assertEqual( + problems["dotabovecomb"], + [{"type": "missing", "master": "SparseMasters-Medium"}], + ) + # normal order, with --ignore-missing self.assertIsNone(interpolatable_main(["--ignore-missing", designspace_path])) def test_sparse_designspace(self): glyphsapp_path = self.get_test_input("SparseMasters.glyphs") - + problems = interpolatable_main(["--quiet", glyphsapp_path]) - self.assertEqual(problems['a'], [{'type': 'missing', 'master': 'Sparse Masters-Medium'}]) - self.assertEqual(problems['s'], [{'type': 'missing', 'master': 'Sparse Masters-Medium'}]) - self.assertEqual(problems['edotabove'], [{'type': 'missing', 'master': 'Sparse Masters-Medium'}]) - self.assertEqual(problems['dotabovecomb'], [{'type': 'missing', 'master': 'Sparse Masters-Medium'}]) - + self.assertEqual( + problems["a"], + [{"type": "missing", "master": "Sparse Masters-Medium"}] + ) + self.assertEqual( + problems["s"], + [{"type": "missing", "master": "Sparse Masters-Medium"}] + ) + self.assertEqual( + problems["edotabove"], + [{"type": "missing", "master": "Sparse Masters-Medium"}], + ) + self.assertEqual( + problems["dotabovecomb"], + [{"type": "missing", "master": "Sparse Masters-Medium"}], + ) + # normal order, with --ignore-missing self.assertIsNone(interpolatable_main(["--ignore-missing", glyphsapp_path])) - def test_interpolatable_varComposite(self): input_path = self.get_test_input( "..", "..", "ttLib", "data", "varc-ac00-ac01.ttf" From 579d0dce31c9071d75f255dd8bd03a2035324f17 Mon Sep 17 00:00:00 2001 From: "Colin M. Ford" Date: Thu, 6 Apr 2023 10:08:42 -0400 Subject: [PATCH 08/13] one more try with black --- Tests/varLib/interpolatable_test.py | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/Tests/varLib/interpolatable_test.py b/Tests/varLib/interpolatable_test.py index a20aee10a..354b059a1 100644 --- a/Tests/varLib/interpolatable_test.py +++ b/Tests/varLib/interpolatable_test.py @@ -134,12 +134,10 @@ class InterpolatableTest(unittest.TestCase): # without --ignore-missing problems = interpolatable_main(["--quiet"] + ttf_paths) self.assertEqual( - problems["a"], - [{"type": "missing", "master": "SparseMasters-Medium"}] + problems["a"], [{"type": "missing", "master": "SparseMasters-Medium"}] ) self.assertEqual( - problems["s"], - [{"type": "missing", "master": "SparseMasters-Medium"}] + problems["s"], [{"type": "missing", "master": "SparseMasters-Medium"}] ) self.assertEqual( problems["edotabove"], @@ -172,12 +170,10 @@ class InterpolatableTest(unittest.TestCase): # without --ignore-missing problems = interpolatable_main(["--quiet"] + ufo_paths) self.assertEqual( - problems["a"], - [{"type": "missing", "master": "SparseMasters-Medium"}] + problems["a"], [{"type": "missing", "master": "SparseMasters-Medium"}] ) self.assertEqual( - problems["s"], - [{"type": "missing", "master": "SparseMasters-Medium"}] + problems["s"], [{"type": "missing", "master": "SparseMasters-Medium"}] ) self.assertEqual( problems["edotabove"], @@ -208,12 +204,10 @@ class InterpolatableTest(unittest.TestCase): problems = interpolatable_main(["--quiet", designspace_path]) self.assertEqual( - problems["a"], - [{"type": "missing", "master": "SparseMasters-Medium"}] + problems["a"], [{"type": "missing", "master": "SparseMasters-Medium"}] ) self.assertEqual( - problems["s"], - [{"type": "missing", "master": "SparseMasters-Medium"}] + problems["s"], [{"type": "missing", "master": "SparseMasters-Medium"}] ) self.assertEqual( problems["edotabove"], @@ -232,12 +226,10 @@ class InterpolatableTest(unittest.TestCase): problems = interpolatable_main(["--quiet", glyphsapp_path]) self.assertEqual( - problems["a"], - [{"type": "missing", "master": "Sparse Masters-Medium"}] + problems["a"], [{"type": "missing", "master": "Sparse Masters-Medium"}] ) self.assertEqual( - problems["s"], - [{"type": "missing", "master": "Sparse Masters-Medium"}] + problems["s"], [{"type": "missing", "master": "Sparse Masters-Medium"}] ) self.assertEqual( problems["edotabove"], From edc3584d5b8293a40da70a23ae3c11605c42ed10 Mon Sep 17 00:00:00 2001 From: "Colin M. Ford" Date: Thu, 6 Apr 2023 10:34:48 -0400 Subject: [PATCH 09/13] Using set comprehension Suggestion by anthrotype Co-authored-by: Cosimo Lupo --- Lib/fontTools/varLib/interpolatable.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/fontTools/varLib/interpolatable.py b/Lib/fontTools/varLib/interpolatable.py index 8ab119c5c..9e72735c2 100644 --- a/Lib/fontTools/varLib/interpolatable.py +++ b/Lib/fontTools/varLib/interpolatable.py @@ -144,7 +144,7 @@ def test(glyphsets, glyphs=None, names=None, ignore_missing=False): if glyphs is None: # `glyphs = glyphsets[0].keys()` is faster, certainly, but doesn't allow for sparse TTFs/OTFs given out of order # ... risks the sparse master being the first one, and only processing a subset of the glyphs - glyphs = set([g for glyphset in glyphsets for g in glyphset.keys()]) + glyphs = {g for glyphset in glyphsets for g in glyphset.keys()} hist = [] problems = OrderedDict() From e7c9616c48f039da24edbf8fc4021375bac39575 Mon Sep 17 00:00:00 2001 From: "Colin M. Ford" Date: Thu, 6 Apr 2023 10:44:10 -0400 Subject: [PATCH 10/13] Removing UFO cruft --- .../SparseMasters-Bold.ufo/fontinfo.plist | 21 ------------ .../glyphs/_notdef.glif | 3 -- .../SparseMasters-Bold.ufo/glyphs/a.glif | 3 -- .../glyphs/dotabovecomb.glif | 3 -- .../SparseMasters-Bold.ufo/glyphs/e.glif | 3 -- .../glyphs/edotabove.glif | 3 -- .../glyphs/layerinfo.plist | 8 ----- .../SparseMasters-Bold.ufo/glyphs/s.glif | 3 -- .../SparseMasters-Bold.ufo/lib.plist | 32 ------------------- .../SparseMasters-Medium.ufo/fontinfo.plist | 21 ------------ .../glyphs/_notdef.glif | 3 -- .../SparseMasters-Medium.ufo/glyphs/e.glif | 3 -- .../glyphs/layerinfo.plist | 8 ----- .../SparseMasters-Medium.ufo/lib.plist | 16 ---------- .../SparseMasters-Regular.ufo/fontinfo.plist | 21 ------------ .../glyphs/_notdef.glif | 3 -- .../SparseMasters-Regular.ufo/glyphs/a.glif | 3 -- .../glyphs/dotabovecomb.glif | 3 -- .../SparseMasters-Regular.ufo/glyphs/e.glif | 3 -- .../glyphs/edotabove.glif | 3 -- .../glyphs/layerinfo.plist | 8 ----- .../SparseMasters-Regular.ufo/glyphs/s.glif | 3 -- .../SparseMasters-Regular.ufo/lib.plist | 32 ------------------- 23 files changed, 209 deletions(-) delete mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/layerinfo.plist delete mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/layerinfo.plist delete mode 100644 Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/layerinfo.plist diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/fontinfo.plist b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/fontinfo.plist index cac9398db..3898ecc88 100644 --- a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/fontinfo.plist +++ b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/fontinfo.plist @@ -10,27 +10,6 @@ -250 familyName Sparse Masters - guidelines - - - postscriptBlueValues - - - postscriptFamilyBlues - - - postscriptFamilyOtherBlues - - - postscriptOtherBlues - - - postscriptStemSnapH - - - postscriptStemSnapV - - styleName Bold unitsPerEm diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/_notdef.glif b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/_notdef.glif index 88bd5c316..5d3ca4d6c 100644 --- a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/_notdef.glif +++ b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/_notdef.glif @@ -15,7 +15,4 @@ - - .notdef - diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/a.glif b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/a.glif index fa17a6622..0e038d68b 100644 --- a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/a.glif +++ b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/a.glif @@ -26,7 +26,4 @@ - - a - diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/dotabovecomb.glif b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/dotabovecomb.glif index 64577cf07..1c11088cb 100644 --- a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/dotabovecomb.glif +++ b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/dotabovecomb.glif @@ -9,7 +9,4 @@ - - dotabovecomb - diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/e.glif b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/e.glif index b5e3ce969..c78c38f49 100644 --- a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/e.glif +++ b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/e.glif @@ -19,7 +19,4 @@ - - e - diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/edotabove.glif b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/edotabove.glif index 7305f58cf..bf4819283 100644 --- a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/edotabove.glif +++ b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/edotabove.glif @@ -6,7 +6,4 @@ - - edotabove - diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/layerinfo.plist b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/layerinfo.plist deleted file mode 100644 index 5ae89c642..000000000 --- a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/layerinfo.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - color - 0.9904,0.5022,0.0329,1 - - diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/s.glif b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/s.glif index 4fddecc4d..ae47e9a9f 100644 --- a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/s.glif +++ b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/glyphs/s.glif @@ -18,7 +18,4 @@ - - s - diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/lib.plist b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/lib.plist index c4121f4a3..b0fd5eb26 100644 --- a/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/lib.plist +++ b/Tests/varLib/data/master_ufo/SparseMasters-Bold.ufo/lib.plist @@ -2,38 +2,6 @@ - com.defcon.sortDescriptor - - - ascending - - .notdef - a - e - edotabove - s - dotabovecomb - - type - glyphList - - - com.typemytype.robofont.compileSettings.autohint - - com.typemytype.robofont.compileSettings.checkOutlines - - com.typemytype.robofont.compileSettings.createDummyDSIG - - com.typemytype.robofont.compileSettings.decompose - - com.typemytype.robofont.compileSettings.generateFormat - 0 - com.typemytype.robofont.compileSettings.releaseMode - - com.typemytype.robofont.italicSlantOffset - 0 - com.typemytype.robofont.shouldAddPointsInSplineConversion - 1 public.glyphOrder .notdef diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/fontinfo.plist b/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/fontinfo.plist index 088d66ae5..a8f59388f 100644 --- a/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/fontinfo.plist +++ b/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/fontinfo.plist @@ -10,27 +10,6 @@ -250 familyName Sparse Masters - guidelines - - - postscriptBlueValues - - - postscriptFamilyBlues - - - postscriptFamilyOtherBlues - - - postscriptOtherBlues - - - postscriptStemSnapH - - - postscriptStemSnapV - - styleName Medium unitsPerEm diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/_notdef.glif b/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/_notdef.glif index a24589a15..5d3ca4d6c 100644 --- a/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/_notdef.glif +++ b/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/_notdef.glif @@ -15,7 +15,4 @@ - -.notdef - diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/e.glif b/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/e.glif index 299e10d52..bf15c1ab8 100644 --- a/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/e.glif +++ b/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/e.glif @@ -18,7 +18,4 @@ - -e - diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/layerinfo.plist b/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/layerinfo.plist deleted file mode 100644 index 5ae89c642..000000000 --- a/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/glyphs/layerinfo.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - color - 0.9904,0.5022,0.0329,1 - - diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/lib.plist b/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/lib.plist index 372a93726..3326cd653 100644 --- a/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/lib.plist +++ b/Tests/varLib/data/master_ufo/SparseMasters-Medium.ufo/lib.plist @@ -2,22 +2,6 @@ - com.typemytype.robofont.compileSettings.autohint - - com.typemytype.robofont.compileSettings.checkOutlines - - com.typemytype.robofont.compileSettings.createDummyDSIG - - com.typemytype.robofont.compileSettings.decompose - - com.typemytype.robofont.compileSettings.generateFormat - 0 - com.typemytype.robofont.compileSettings.releaseMode - - com.typemytype.robofont.italicSlantOffset - 0 - com.typemytype.robofont.shouldAddPointsInSplineConversion - 1 public.glyphOrder .notdef diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/fontinfo.plist b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/fontinfo.plist index 47e1944b2..a36990b7c 100644 --- a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/fontinfo.plist +++ b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/fontinfo.plist @@ -10,27 +10,6 @@ -250 familyName Sparse Masters - guidelines - - - postscriptBlueValues - - - postscriptFamilyBlues - - - postscriptFamilyOtherBlues - - - postscriptOtherBlues - - - postscriptStemSnapH - - - postscriptStemSnapV - - styleName Regular unitsPerEm diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/_notdef.glif b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/_notdef.glif index 88bd5c316..5d3ca4d6c 100644 --- a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/_notdef.glif +++ b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/_notdef.glif @@ -15,7 +15,4 @@ - - .notdef - diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/a.glif b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/a.glif index d152ff604..5dcc9322f 100644 --- a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/a.glif +++ b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/a.glif @@ -26,7 +26,4 @@ - - a - diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/dotabovecomb.glif b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/dotabovecomb.glif index 0ce49404b..3abb24fdc 100644 --- a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/dotabovecomb.glif +++ b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/dotabovecomb.glif @@ -9,7 +9,4 @@ - - dotabovecomb - diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/e.glif b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/e.glif index 824f54242..52fc2b3c9 100644 --- a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/e.glif +++ b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/e.glif @@ -19,7 +19,4 @@ - - e - diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/edotabove.glif b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/edotabove.glif index b35f6b671..9a6dbc56c 100644 --- a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/edotabove.glif +++ b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/edotabove.glif @@ -6,7 +6,4 @@ - - edotabove - diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/layerinfo.plist b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/layerinfo.plist deleted file mode 100644 index 5ae89c642..000000000 --- a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/layerinfo.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - color - 0.9904,0.5022,0.0329,1 - - diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/s.glif b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/s.glif index 3bd6b74b6..205b0e3da 100644 --- a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/s.glif +++ b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/glyphs/s.glif @@ -18,7 +18,4 @@ - - s - diff --git a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/lib.plist b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/lib.plist index c4121f4a3..b0fd5eb26 100644 --- a/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/lib.plist +++ b/Tests/varLib/data/master_ufo/SparseMasters-Regular.ufo/lib.plist @@ -2,38 +2,6 @@ - com.defcon.sortDescriptor - - - ascending - - .notdef - a - e - edotabove - s - dotabovecomb - - type - glyphList - - - com.typemytype.robofont.compileSettings.autohint - - com.typemytype.robofont.compileSettings.checkOutlines - - com.typemytype.robofont.compileSettings.createDummyDSIG - - com.typemytype.robofont.compileSettings.decompose - - com.typemytype.robofont.compileSettings.generateFormat - 0 - com.typemytype.robofont.compileSettings.releaseMode - - com.typemytype.robofont.italicSlantOffset - 0 - com.typemytype.robofont.shouldAddPointsInSplineConversion - 1 public.glyphOrder .notdef From c76b8f9990e6fe07c88d7b3d03feae5c3ee6f9f8 Mon Sep 17 00:00:00 2001 From: "Colin M. Ford" Date: Thu, 6 Apr 2023 10:48:00 -0400 Subject: [PATCH 11/13] Adding GlyphsLib to the requirements.txt, requested by Anthrotype --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 4e9b659b0..d8c98876a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,3 +13,4 @@ ufoLib2==0.14.0 pyobjc==9.0; sys_platform == "darwin" freetype-py==2.3.0 uharfbuzz==0.32.0 +glyphsLib==6.2.1 # this is only required to run Tests/varLib/interpolatable_test.py From ab7628b3f564d8d13f1896e85e8b07870f265cc1 Mon Sep 17 00:00:00 2001 From: "Colin M. Ford" Date: Thu, 6 Apr 2023 10:58:31 -0400 Subject: [PATCH 12/13] adding `importerskip` for glyphsapp tests --- Tests/varLib/interpolatable_test.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Tests/varLib/interpolatable_test.py b/Tests/varLib/interpolatable_test.py index 354b059a1..10b9cc30a 100644 --- a/Tests/varLib/interpolatable_test.py +++ b/Tests/varLib/interpolatable_test.py @@ -5,6 +5,7 @@ import shutil import sys import tempfile import unittest +import pytest try: import scipy @@ -103,6 +104,7 @@ class InterpolatableTest(unittest.TestCase): self.assertIsNone(interpolatable_main([designspace_path])) def test_glyphsapp(self): + pytest.importorskip("glyphsLib") glyphsapp_path = self.get_test_input("InterpolateLayout.glyphs") self.assertIsNone(interpolatable_main([glyphsapp_path])) @@ -221,7 +223,8 @@ class InterpolatableTest(unittest.TestCase): # normal order, with --ignore-missing self.assertIsNone(interpolatable_main(["--ignore-missing", designspace_path])) - def test_sparse_designspace(self): + def test_sparse_glyphsapp(self): + pytest.importorskip("glyphsLib") glyphsapp_path = self.get_test_input("SparseMasters.glyphs") problems = interpolatable_main(["--quiet", glyphsapp_path]) From 52f522525a51b74f24dfe87da9a0ebe297bbf347 Mon Sep 17 00:00:00 2001 From: "Colin M. Ford" Date: Thu, 6 Apr 2023 11:04:47 -0400 Subject: [PATCH 13/13] lastly, removing lib cruft from glyphs file --- Tests/varLib/data/SparseMasters.glyphs | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/Tests/varLib/data/SparseMasters.glyphs b/Tests/varLib/data/SparseMasters.glyphs index 0c38c139c..a9843a466 100644 --- a/Tests/varLib/data/SparseMasters.glyphs +++ b/Tests/varLib/data/SparseMasters.glyphs @@ -45,14 +45,6 @@ dotabovecomb type = glyphList; } ); -com.typemytype.robofont.compileSettings.autohint = 1; -com.typemytype.robofont.compileSettings.checkOutlines = 0; -com.typemytype.robofont.compileSettings.createDummyDSIG = 1; -com.typemytype.robofont.compileSettings.decompose = 0; -com.typemytype.robofont.compileSettings.generateFormat = 0; -com.typemytype.robofont.compileSettings.releaseMode = 0; -com.typemytype.robofont.italicSlantOffset = 0; -com.typemytype.robofont.shouldAddPointsInSplineConversion = 1; }; weightValue = 350; xHeight = 500; @@ -73,14 +65,6 @@ value = Medium; descender = -250; id = "2B2F6A55-E8C4-4456-AFD7-7A9468BB18B9"; userData = { -com.typemytype.robofont.compileSettings.autohint = 1; -com.typemytype.robofont.compileSettings.checkOutlines = 0; -com.typemytype.robofont.compileSettings.createDummyDSIG = 1; -com.typemytype.robofont.compileSettings.decompose = 0; -com.typemytype.robofont.compileSettings.generateFormat = 0; -com.typemytype.robofont.compileSettings.releaseMode = 0; -com.typemytype.robofont.italicSlantOffset = 0; -com.typemytype.robofont.shouldAddPointsInSplineConversion = 1; }; weightValue = 450; xHeight = 500; @@ -114,14 +98,6 @@ dotabovecomb type = glyphList; } ); -com.typemytype.robofont.compileSettings.autohint = 1; -com.typemytype.robofont.compileSettings.checkOutlines = 0; -com.typemytype.robofont.compileSettings.createDummyDSIG = 1; -com.typemytype.robofont.compileSettings.decompose = 0; -com.typemytype.robofont.compileSettings.generateFormat = 0; -com.typemytype.robofont.compileSettings.releaseMode = 0; -com.typemytype.robofont.italicSlantOffset = 0; -com.typemytype.robofont.shouldAddPointsInSplineConversion = 1; }; weightValue = 625; xHeight = 500;