def test_designspace_generation_bracket_roundtrip_psnames(datadir, ufo_module): with open(str(datadir.join("PSNames.glyphs"))) as f: font = glyphsLib.load(f) designspace: DesignSpaceDocument = to_designspace(font, ufo_module=ufo_module) assert designspace.findDefault().font.lib["public.postscriptNames"] == { "a-cy": "uni0430", "a-cy.BRACKET.18": "uni0430.BRACKET.18", "a-cy.alt": "uni0430.alt", } font_rt = to_glyphs(designspace) designspace_rt = to_designspace(font_rt, ufo_module=ufo_module) assert designspace_rt.findDefault().font.lib["public.postscriptNames"] == { "a-cy": "uni0430", "a-cy.BRACKET.18": "uni0430.BRACKET.18", "a-cy.alt": "uni0430.alt", } font_rt2 = to_glyphs(designspace_rt) designspace_rt2 = to_designspace(font_rt2, ufo_module=ufo_module) assert designspace_rt2.findDefault().font.lib["public.postscriptNames"] == { "a-cy": "uni0430", "a-cy.BRACKET.18": "uni0430.BRACKET.18", "a-cy.alt": "uni0430.alt", }
def test_mapping_is_same_regardless_of_axes_custom_parameter(ufo_module): # https://github.com/googlefonts/glyphsLib/issues/409 # https://github.com/googlefonts/glyphsLib/issues/411 # First, try without the custom param font = to_glyphs([ufo_module.Font(), ufo_module.Font(), ufo_module.Font()]) font.masters[0].name = "ExtraLight" font.masters[0].weightValue = 200 font.masters[1].name = "Regular" font.masters[1].weightValue = 400 font.masters[2].name = "Bold" font.masters[2].weightValue = 700 doc = to_designspace(font, ufo_module=ufo_module) assert doc.axes[0].minimum == 200 assert doc.axes[0].maximum == 700 assert doc.axes[0].map == [] # Now with the custom parameter. Should produce the same results font.customParameters["Axes"] = [{"Name": "Weight", "Tag": "wght"}] doc = to_designspace(font, ufo_module=ufo_module) assert doc.axes[0].minimum == 200 assert doc.axes[0].maximum == 700 assert doc.axes[0].map == []
def test_instance_filtering_by_family_name(self): # See https://github.com/googlefonts/fontmake/issues/257 path = os.path.join(os.path.dirname(__file__), "..", "data", "MontserratStrippedDown.glyphs") font = GSFont(path) # By default (no special parameter), all instances are exported designspace_all = to_designspace(font) assert len(designspace_all.instances) == 18 # If we specify that we want the same familyName as the masters, # we only get instances that have that same family name, and the # masters are copied as-is. (basically a subset of the previous doc) designspace_no_alternates = to_designspace(font, family_name="Montserrat") assert len(designspace_no_alternates.instances) == 9 # If we specify the alternate family name, we only get the instances # that have that family name, and the masters are renamed to have the # given family name. designspace_alternates = to_designspace( font, family_name="Montserrat Alternates") assert designspace_alternates.sources[ 0].familyName == "Montserrat Alternates" assert (designspace_alternates.sources[0].font.info.familyName == "Montserrat Alternates") assert len(designspace_alternates.instances) == 9
def test_background_component_decompose_missing(datadir): font = glyphsLib.GSFont(str(datadir.join("Recursion.glyphs"))) layer = font.glyphs["B"].layers[ "DB4D7D04-C02D-48DE-811E-03AA03052DD2"].background layer.components.append(GSComponent("xxx")) with pytest.raises(MissingComponentError): to_designspace(font)
def test_designspace_generation_bracket_unbalanced_brackets(datadir): with open(str(datadir.join("BracketTestFont.glyphs"))) as f: font = glyphsLib.load(f) # Delete the "Other [600]" layer to unbalance bracket layers. del font.glyphs["x"].layers["C5C3CA59-C2D0-46F6-B5D3-86541DE36ACB"] with pytest.raises(ValueError) as excinfo: to_designspace(font) assert "bracket layer(s) missing" in str(excinfo) # Delete the other [600] layers to rebalance. del font.glyphs["x"].layers["E729A72D-C6FF-4DDD-ADA1-BB5B6FD7E3DD"] del font.glyphs["x"].layers["F5778F4C-2B04-4030-9D7D-09E3C951C089"] del font.glyphs["x"].layers["24328DA8-2CE1-4D0A-9C91-214ED36F6393"] assert to_designspace(font)
def test_axis_with_no_mapping_does_not_error_in_roundtrip(ufo_module): """Tests that a custom axis without a mapping and without sources on its extremes does not generate an error during roundtrip. Also tests that during a to_glyphs, to_designspace roundtrip the min and max axis information is not lost. """ doc = designspaceLib.DesignSpaceDocument() # Add a "Regular" source regular = doc.newSourceDescriptor() regular.font = ufo_module.Font() regular.location = {"Style": 0} doc.addSource(regular) axis = doc.newAxisDescriptor() axis.tag = "styl" axis.name = "Style" doc.addAxis(axis) # This axis spans a range of 0 to 1 but only has a source at {"Style": 0} # and no explicit mapping. The point of this test is to see if the min and # max are still the same after round tripping. doc.axes[0].minimum = 0 doc.axes[0].maximum = 1 doc.axes[0].default = 0 doc.axes[0].map = [] doc2 = deepcopy(doc) font = to_glyphs(doc2) doc_rt = to_designspace(font) assert doc_rt.axes[0].serialize() == doc.axes[0].serialize()
def test_designspace_name(self): doc = to_designspace( makeFont([ makeMaster("Regular", weight=100), makeMaster("Bold", weight=190), ], [], "Family Name")) # no shared base style name, only write the family name self.assertEqual(doc.filename, "FamilyName.designspace") doc = to_designspace( makeFont([ makeMaster("Italic", weight=100), makeMaster("Bold Italic", weight=190), ], [], "Family Name")) # 'Italic' is the base style; append to designspace name self.assertEqual(doc.filename, "FamilyName-Italic.designspace")
def test_twoAxes(self): # In NotoSansArabic-MM.glyphs, the regular width only contains # parameters for the weight axis. For the width axis, glyphsLib # should use 100 as default value (just like Glyphs.app does). familyName = "DesignspaceTest TwoAxes" masters = [ makeMaster("Regular", weight=90), makeMaster("Black", weight=190), makeMaster("Thin", weight=26), makeMaster("ExtraCond", weight=90, width=70), makeMaster("ExtraCond Black", weight=190, width=70), makeMaster("ExtraCond Thin", weight=26, width=70), ] instances = [ makeInstance("Thin", weight=("Thin", 100, 26)), makeInstance("Regular", weight=("Regular", 400, 90)), makeInstance("Semibold", weight=("SemiBold", 600, 128)), makeInstance("Black", weight=("Black", 900, 190)), makeInstance("ExtraCondensed Thin", weight=("Thin", 100, 26), width=("Extra Condensed", 2, 70)), makeInstance("ExtraCondensed", weight=("Regular", 400, 90), width=("Extra Condensed", 2, 70)), makeInstance("ExtraCondensed Black", weight=("Black", 900, 190), width=("Extra Condensed", 2, 70)), ] font = makeFont(masters, instances, familyName) doc = to_designspace(font, instance_dir='out') self.expect_designspace(doc, "DesignspaceTestTwoAxes.designspace") self.expect_designspace_roundtrip(doc)
def test_masters_have_user_locations_string(ufo_module): """Test that stringified Axis Locations are converted. Some versions of Glyph store a string instead of an int. """ font = to_glyphs([ufo_module.Font(), ufo_module.Font()]) font.customParameters["Axes"] = [{"Tag": "opsz", "Name": "Optical"}] font.masters[0].weightValue = 0 font.masters[0].customParameters["Axis Location"] = [{ "Axis": "Optical", "Location": 13 }] font.masters[1].weightValue = 1000 font.masters[1].customParameters["Axis Location"] = [{ "Axis": "Optical", "Location": "100" }] doc = to_designspace(font, ufo_module=ufo_module) assert doc.axes[0].map == [(13, 0), (100, 1000)] font = to_glyphs(doc) assert font.masters[0].customParameters["Axis Location"] == [{ "Axis": "Optical", "Location": 13 }] assert font.masters[1].customParameters["Axis Location"] == [{ "Axis": "Optical", "Location": 100 }]
def test_designspace_generation_bracket_composite_glyph(datadir): with open(str(datadir.join("BracketTestFont2.glyphs"))) as f: font = glyphsLib.load(f) g = font.glyphs["B"] for layer in g.layers: assert layer.components[0].name == "A" designspace = to_designspace(font) for source in designspace.sources: ufo = source.font assert "B.BRACKET.600" in ufo assert ufo["B"].components[0].baseGlyph == "A" assert ufo["B.BRACKET.600"].components[0].baseGlyph == "A.BRACKET.600" font_rt = to_glyphs(designspace) assert "B" in font_rt.glyphs g2 = font_rt.glyphs["B"] for layer in g2.layers: assert layer.components[0].name == "A" assert "B.BRACKET.600" not in font_rt.glyphs
def test_warn_diff_between_designspace_and_ufos(caplog, ufo_module): ufo = ufo_module.Font() ufo.info.familyName = "UFO Family Name" ufo.info.styleName = "UFO Style Name" # ufo.info.styleMapFamilyName = 'UFO Stylemap Family Name' # ufo.info.styleMapStyleName = 'bold' doc = DesignSpaceDocument() source = doc.newSourceDescriptor() source.font = ufo source.familyName = "DS Family Name" source.styleName = "DS Style Name" doc.addSource(source) font = to_glyphs(doc, minimize_ufo_diffs=True) assert any(record.levelname == "WARNING" for record in caplog.records) assert ( "The familyName is different between the UFO and the designspace source" in caplog.text) assert ( "The styleName is different between the UFO and the designspace source" in caplog.text) doc = to_designspace(font, ufo_module=ufo_module) source = doc.sources[0] # The UFO info will prevail assert ufo.info.familyName == "UFO Family Name" assert ufo.info.styleName == "UFO Style Name" assert source.font.info.familyName == "UFO Family Name" assert source.font.info.styleName == "UFO Style Name"
def test_custom_featureWriters_in_designpace_lib(tmpdir, ufo_module): """Test that we can roundtrip custom user-defined ufo2ft featureWriters settings that are stored in the designspace lib or GSFont.userData. """ font = classes.GSFont() font.masters.append(classes.GSFontMaster()) kern = classes.GSFeature(name="kern", code="pos a b 100;") font.features.append(kern) customFeatureWriters = list(DEFAULT_FEATURE_WRITERS) + [{ "class": "MyCustomWriter", "module": "myCustomWriter" }] font.userData[UFO2FT_FEATURE_WRITERS_KEY] = customFeatureWriters designspace = to_designspace(font, ufo_module=ufo_module) path = str(tmpdir / "test.designspace") designspace.write(path) for source in designspace.sources: source.font.save(str(tmpdir / source.filename)) designspace2 = DesignSpaceDocument.fromfile(path) assert UFO2FT_FEATURE_WRITERS_KEY in designspace2.lib assert designspace2.lib[UFO2FT_FEATURE_WRITERS_KEY] == customFeatureWriters font2 = to_glyphs(designspace2, ufo_module=ufo_module) assert len(font2.userData) == 1 assert font2.userData[UFO2FT_FEATURE_WRITERS_KEY] == customFeatureWriters
def test_warn_diff_between_designspace_and_ufos(caplog): ufo = defcon.Font() ufo.info.familyName = 'UFO Family Name' ufo.info.styleName = 'UFO Style Name' # ufo.info.styleMapFamilyName = 'UFO Stylemap Family Name' # ufo.info.styleMapStyleName = 'bold' doc = DesignSpaceDocument() source = doc.newSourceDescriptor() source.font = ufo source.familyName = 'DS Family Name' source.styleName = 'DS Style Name' doc.addSource(source) font = to_glyphs(doc, minimize_ufo_diffs=True) assert any(record.levelname == 'WARNING' for record in caplog.records) assert 'The familyName is different between the UFO and the designspace source' in caplog.text assert 'The styleName is different between the UFO and the designspace source' in caplog.text doc = to_designspace(font) source = doc.sources[0] # The UFO info will prevail assert ufo.info.familyName == 'UFO Family Name' assert ufo.info.styleName == 'UFO Style Name' assert source.font.info.familyName == 'UFO Family Name' assert source.font.info.styleName == 'UFO Style Name'
def test_BraceTestFont_no_editor_state(self): filename = os.path.join(os.path.dirname(__file__), "../data/BraceTestFont.glyphs") with open(filename) as f: font = glyphsLib.load(f) designspace = glyphsLib.to_designspace(font) for source in designspace.sources: assert source.font.lib[ glyphsLib.builder.constants.FONT_CUSTOM_PARAM_PREFIX + "DisplayStrings"] == ["a", "b"] designspace = glyphsLib.to_designspace(font, store_editor_state=False) for source in designspace.sources: assert (glyphsLib.builder.constants.FONT_CUSTOM_PARAM_PREFIX + "DisplayStrings" not in source.font.lib)
def test_default_featureWriters_in_designspace_lib(tmpdir, ufo_module): """Test that the glyphsLib custom featureWriters settings (with mode="append") are exported to the designspace lib whenever a GSFont contains a manual 'kern' feature. And that they are not imported back to GSFont.userData if they are the same as the default value. """ font = classes.GSFont() font.masters.append(classes.GSFontMaster()) kern = classes.GSFeature(name="kern", code="pos a b 100;") font.features.append(kern) designspace = to_designspace(font, ufo_module=ufo_module) path = str(tmpdir / "test.designspace") designspace.write(path) for source in designspace.sources: source.font.save(str(tmpdir / source.filename)) designspace2 = DesignSpaceDocument.fromfile(path) assert UFO2FT_FEATURE_WRITERS_KEY in designspace2.lib assert designspace2.lib[ UFO2FT_FEATURE_WRITERS_KEY] == DEFAULT_FEATURE_WRITERS font2 = to_glyphs(designspace2, ufo_module=ufo_module) assert not len(font2.userData) assert len([f for f in font2.features if f.name == "kern"]) == 1
def test_inactive_from_exports(self): # Glyphs.app recognizes exports=0 as a flag for inactive instances. # https://github.com/googlefonts/glyphsLib/issues/129 masters, instances = makeFamily() for inst in instances: if inst.name != "Semibold": inst.exports = False font = makeFont(masters, instances, "DesignspaceTest Inactive") doc = to_designspace(font, instance_dir="out") self.expect_designspace(doc, "DesignspaceTestInactive.designspace") self.expect_designspace_roundtrip(doc) # Although inactive instances are not exported by default, # all instances are exported when intending to roundtrip Glyphs->Glyphs doc = to_designspace(font, minimize_glyphs_diffs=True) self.assertEqual(4, len(doc.instances))
def test_apply_instance_data(tmpdir, instance_names): font = glyphsLib.GSFont(TESTFILE_PATH) instance_dir = "instances" designspace = glyphsLib.to_designspace(font, instance_dir=instance_dir) path = str(tmpdir / (font.familyName + '.designspace')) write_designspace_and_UFOs(designspace, path) builder = DesignSpaceDocumentReader(designspace.path, ufoVersion=3) if instance_names is None: # generate all instances builder.process() include_filenames = None else: # generate only selected instances for name in instance_names: builder.readInstance(("stylename", name)) # make relative filenames from paths returned by MutatorMath include_filenames = {os.path.relpath(instance_path, str(tmpdir)) for instance_path in builder.results.values()} ufos = apply_instance_data(designspace.path, include_filenames=include_filenames) for filename in include_filenames or (): assert os.path.isdir(str(tmpdir / filename)) assert len(ufos) == len(builder.results) assert isinstance(ufos[0], defcon.Font)
def test_background_component_decompose(datadir): font = glyphsLib.GSFont(str(datadir.join("Recursion.glyphs"))) ds = to_designspace(font) for source in ds.sources: for layer in source.font.layers: for glyph in layer: if layer.name == "Apr 27 20, 17:59" and glyph.name == "B": continue assert not glyph.components ufo_rg = ds.sources[0].font assert ufo_rg.layers["public.background"]["A"].contours == ufo_rg[ "B"].contours assert (ufo_rg.layers["Apr 27 20, 17:57.background"]["A"].contours == ufo_rg["B"].contours) assert ufo_rg.layers["public.background"]["B"].contours == ufo_rg[ "A"].contours assert len(ufo_rg.layers["Apr 27 20, 17:59.background"]["B"].contours) == 2 assert ufo_rg.layers["Apr 27 20, 17:59"]["B"].components ufo_bd = ds.sources[1].font assert ufo_bd.layers["public.background"]["A"].contours == ufo_bd[ "B"].contours assert (ufo_bd.layers["Apr 27 20, 17:57.background"]["A"].contours == ufo_bd["B"].contours) assert ufo_bd.layers["public.background"]["B"].contours == ufo_bd[ "A"].contours assert (ufo_bd.layers["Apr 27 20, 17:59.background"]["B"].contours == ufo_bd["A"].contours)
def test_designspace_generation_reverse_bracket_roundtrip(datadir): with open(str(datadir.join("BracketTestFont2.glyphs"))) as f: font = glyphsLib.load(f) g = font.glyphs["D"] assert {"Regular ]600]", "Bold ]600]"}.intersection(l.name for l in g.layers) designspace = to_designspace(font) assert designspace.rules[1].name == "BRACKET.400.600" assert designspace.rules[1].conditionSets == [[ dict(name="Weight", minimum=400, maximum=600) ]] assert designspace.rules[1].subs == [("D", "D.REV_BRACKET.600")] for source in designspace.sources: ufo = source.font assert "D.REV_BRACKET.600" in ufo font_rt = to_glyphs(designspace) assert "D" in font_rt.glyphs g2 = font_rt.glyphs["D"] assert {"Regular ]600]", "Bold ]600]"}.intersection(l.name for l in g2.layers) assert "D.REV_BRACKET.600" not in font_rt.glyphs
def test_designspace_generation_bracket_no_export_glyph(datadir): with open(str(datadir.join("BracketTestFont2.glyphs"))) as f: font = glyphsLib.load(f) font.glyphs["E"].export = False designspace = to_designspace(font, write_skipexportglyphs=True) assert "E" in designspace.lib.get("public.skipExportGlyphs") for source in designspace.sources: assert "E.REV_BRACKET.570" not in source.font assert "E.BRACKET.630" not in source.font for rule in designspace.rules: assert "E" not in {g for g in itertools.chain(*rule.subs)} font_rt = to_glyphs(designspace) assert "E" in font_rt.glyphs assert {l.name for l in font_rt.glyphs["E"].layers} == { "Regular", "Regular [630]", "Bold", "Bold ]570]", }
def test_designspace_generation_brace_layers(datadir): with open(str(datadir.join("BraceTestFont.glyphs"))) as f: font = glyphsLib.load(f) designspace = to_designspace(font) axes_order = [(a.name, a.minimum, a.default, a.maximum, a.map) for a in designspace.axes] assert axes_order == [ ("Width", 75, 100, 100, [(75, 50.0), (100, 100.0)]), ("Weight", 100, 100, 700, [(100, 100.0), (700, 1000.0)]), ] source_order = [(s.filename, s.layerName, s.name) for s in designspace.sources] assert source_order == [ ("NewFont-Light.ufo", None, "New Font Light"), ("NewFont-Light.ufo", "{75}", "New Font Light {75}"), ("NewFont-Bold.ufo", None, "New Font Bold"), ("NewFont-Bold.ufo", "{75}", "New Font Bold {75}"), ("NewFont-Bold.ufo", "Test2 {90, 500}", "New Font Bold Test2 {90, 500}"), ("NewFont-Bold.ufo", "Test1 {90, 600}", "New Font Bold Test1 {90, 600}"), ("NewFont-CondensedLight.ufo", None, "New Font Condensed Light"), ("NewFont-CondensedBold.ufo", None, "New Font Condensed Bold"), ] # Check that all sources have a font object attached and sources with the same # filename have the same font object attached. masters = {} for source in designspace.sources: assert source.font if source.filename in masters: assert masters[source.filename] is source.font masters[source.filename] = source.font
def test_variationFontOrigin(self): # Glyphs 2.4.1 introduced a custom parameter “Variation Font Origin” # to specify which master should be considered the origin. # https://glyphsapp.com/blog/glyphs-2-4-1-released masters = [ makeMaster("Thin", weight=26), makeMaster("Regular", weight=100), makeMaster("Medium", weight=111), makeMaster("Black", weight=190), ] instances = [ makeInstance("Black", weight=("Black", 900, 190)), makeInstance("Medium", weight=("Medium", 444, 111)), makeInstance("Regular", weight=("Regular", 400, 100)), makeInstance("Thin", weight=("Thin", 100, 26)), ] font = makeFont(masters, instances, "Family") font.customParameters["Variation Font Origin"] = "Medium" designspace = to_designspace(font, instance_dir="out") path = self.write_to_tmp_path(designspace, "varfontorig.designspace") doc = etree.parse(path) medium = doc.find('sources/source[@stylename="Medium"]') self.assertEqual(medium.find("lib").attrib["copy"], "1") weightAxis = doc.find('axes/axis[@tag="wght"]') self.assertEqual(weightAxis.attrib["default"], "444") self.expect_designspace_roundtrip(designspace)
def test_designspace_generation_bracket_roundtrip(datadir): with open(str(datadir.join("BracketTestFont.glyphs"))) as f: font = glyphsLib.load(f) designspace = to_designspace(font) assert designspace.rules[0].name == "BRACKET.300.600" assert designspace.rules[0].conditionSets == [[ dict(name="Weight", minimum=300, maximum=600) ]] assert designspace.rules[0].subs == [("x", "x.BRACKET.300")] assert designspace.rules[1].name == "BRACKET.300.1000" assert designspace.rules[1].conditionSets == [[ dict(name="Weight", minimum=300, maximum=1000) ]] assert designspace.rules[1].subs == [("a", "a.BRACKET.300")] assert designspace.rules[2].name == "BRACKET.600.1000" assert designspace.rules[2].conditionSets == [[ dict(name="Weight", minimum=600, maximum=1000) ]] assert designspace.rules[2].subs == [("x", "x.BRACKET.600")] for source in designspace.sources: assert "[300]" not in source.font.layers assert "Something [300]" not in source.font.layers assert "[600]" not in source.font.layers assert "Other [600]" not in source.font.layers g1 = source.font["x.BRACKET.300"] assert not g1.unicodes g2 = source.font["x.BRACKET.600"] assert not g2.unicodes font_rt = to_glyphs(designspace) assert "x" in font_rt.glyphs g1 = font_rt.glyphs["x"] assert len(g1.layers) == 12 and {l.name for l in g1.layers} == { "[300]", "[600]", "Bold", "Condensed Bold", "Condensed Light", "Light", "Other [600]", "Something [300]", } g2 = font_rt.glyphs["a"] assert len(g2.layers) == 8 and {l.name for l in g2.layers} == { "[300]", "Bold", "Condensed Bold", "Condensed Light", "Light", } assert "a.BRACKET.300" not in font_rt.glyphs assert "x.BRACKET.300" not in font_rt.glyphs assert "x.BRACKET.600" not in font_rt.glyphs
def build_master_ufos( self, glyphs_path, designspace_path=None, master_dir=None, instance_dir=None, family_name=None, mti_source=None, write_skipexportglyphs=True, ): """Build UFOs and MutatorMath designspace from Glyphs source.""" import glyphsLib if master_dir is None: master_dir = self._output_dir("ufo") if not os.path.isdir(master_dir): os.mkdir(master_dir) if instance_dir is None: instance_dir = self._output_dir("ufo", is_instance=True) if not os.path.isdir(instance_dir): os.mkdir(instance_dir) font = glyphsLib.GSFont(glyphs_path) if designspace_path is not None: designspace_dir = os.path.dirname(designspace_path) else: designspace_dir = master_dir # glyphsLib.to_designspace expects instance_dir to be relative instance_dir = os.path.relpath(instance_dir, designspace_dir) designspace = glyphsLib.to_designspace( font, family_name=family_name, instance_dir=instance_dir, write_skipexportglyphs=write_skipexportglyphs, ) masters = {} # multiple sources can have the same font/filename (but different layer), # we want to save a font only once for source in designspace.sources: if source.filename in masters: assert source.font is masters[source.filename] continue ufo_path = os.path.join(master_dir, source.filename) # no need to also set the relative 'filename' attribute as that # will be auto-updated on writing the designspace document source.path = ufo_path source.font.save(ufo_path) masters[source.filename] = source.font if designspace_path is None: designspace_path = os.path.join(master_dir, designspace.filename) designspace.write(designspace_path) if mti_source: self.add_mti_features_to_master_ufos(mti_source, masters.values()) return designspace_path
def test_familyName(self): masters, _ = makeFamily() customFamily = makeInstance("Regular", weight=("Bold", 600, 151)) customFamily.customParameters["familyName"] = "Custom Family" instances = [makeInstance("Regular", weight=("Regular", 400, 90)), customFamily] font = makeFont(masters, instances, "DesignspaceTest FamilyName") doc = to_designspace(font, instance_dir="out") self.expect_designspace(doc, "DesignspaceTestFamilyName.designspace") self.expect_designspace_roundtrip(doc)
def test_default_master_roundtrips(): """This test comes from a common scenario while using glyphsLib to go back and forth several times with "minimize diffs" in both directions. In the end we get UFOs that have information as below, and there was a bug that turned "Regular" into "Normal" and changed the default axis value. """ thin = defcon.Font() thin.info.familyName = "CustomFont" thin.info.styleName = "Thin" thin.lib["com.schriftgestaltung.customParameter.GSFont.Axes"] = [ {"Name": "Weight", "Tag": "wght"} ] regular = defcon.Font() regular.info.familyName = "CustomFont" regular.info.styleName = "Regular" regular.lib["com.schriftgestaltung.customParameter.GSFont.Axes"] = [ {"Name": "Weight", "Tag": "wght"} ] ds = designspaceLib.DesignSpaceDocument() weight = ds.newAxisDescriptor() weight.tag = "wght" weight.name = "Weight" weight.minimum = 300 weight.maximum = 700 weight.default = 400 weight.map = [(300, 58), (400, 85), (700, 145)] ds.addAxis(weight) thinSource = ds.newSourceDescriptor() thinSource.font = thin thinSource.location = {"Weight": 58} thinSource.familyName = "CustomFont" thinSource.styleName = "Thin" ds.addSource(thinSource) regularSource = ds.newSourceDescriptor() regularSource.font = regular regularSource.location = {"Weight": 85} regularSource.familyName = "CustomFont" regularSource.styleName = "Regular" regularSource.copyFeatures = True regularSource.copyGroups = True regularSource.copyInfo = True regularSource.copyLib = True ds.addSource(regularSource) font = to_glyphs(ds, minimize_ufo_diffs=True) doc = to_designspace(font, minimize_glyphs_diffs=True) reg = doc.sources[1] assert reg.styleName == "Regular" assert reg.font.info.styleName == "Regular" assert reg.copyFeatures is True assert reg.copyGroups is True assert reg.copyInfo is True assert reg.copyLib is True
def test_ufo_filename_custom_param_plus_legacy(): """Test that new-style UFO_FILENAME_CUSTOM_PARAM overrides legacy (UFO_FILENAME_KEY|FULL_FILENAME_KEY).""" font = glyphsLib.GSFont(os.path.join(DATA, "UFOFilenameTest.glyphs")) font.masters[0].customParameters[UFO_FILENAME_CUSTOM_PARAM] = "aaa.ufo" font.instances[0].customParameters[UFO_FILENAME_CUSTOM_PARAM] = "bbb.ufo" ds = glyphsLib.to_designspace(font, minimize_glyphs_diffs=True) assert ds.sources[0].filename == "aaa.ufo" assert ds.instances[0].filename == "bbb.ufo"
def test_ufo_filename_custom_param_instance_empty(): font = glyphsLib.GSFont(os.path.join(DATA, "UFOFilenameTest.glyphs")) font.masters[0].customParameters[UFO_FILENAME_CUSTOM_PARAM] = "aaa.ufo" del font.instances[0].customParameters[UFO_FILENAME_CUSTOM_PARAM] del font.instances[0].customParameters[FULL_FILENAME_KEY] ds = glyphsLib.to_designspace(font, minimize_glyphs_diffs=True) assert ds.sources[0].filename == "aaa.ufo" # Instance filename should be whatever the default is. assert ds.instances[0].filename == "instance_ufos/NewFont-Regular.ufo"
def test_masters_have_user_locations(): """Test the new axis definition with custom parameters. See https://github.com/googlei18n/glyphsLib/issues/280. For tests about the previous system with weight/width/custom, see `tests/builder/interpolation_test.py`. """ # Get a font with two masters font = to_glyphs([defcon.Font(), defcon.Font()]) font.customParameters['Axes'] = [{ 'Tag': 'opsz', 'Name': 'Optical', }] # There is only one axis, so the design location is stored in the weight font.masters[0].weightValue = 0 # The user location is stored as a custom parameter font.masters[0].customParameters['Axis Location'] = [{ 'Axis': 'Optical', 'Location': 13, }] font.masters[1].weightValue = 1000 font.masters[1].customParameters['Axis Location'] = [{ 'Axis': 'Optical', 'Location': 100, }] doc = to_designspace(font) assert len(doc.axes) == 1 assert doc.axes[0].map == [ (13, 0), (100, 1000), ] assert len(doc.sources) == 2 assert doc.sources[0].location == {'Optical': 0} assert doc.sources[1].location == {'Optical': 1000} font = to_glyphs(doc) assert font.customParameters['Axes'] == [{ 'Tag': 'opsz', 'Name': 'Optical', }] assert font.masters[0].weightValue == 0 assert font.masters[0].customParameters['Axis Location'] == [{ 'Axis': 'Optical', 'Location': 13, }] assert font.masters[1].weightValue == 1000 assert font.masters[1].customParameters['Axis Location'] == [{ 'Axis': 'Optical', 'Location': 100, }]
def test_instanceOrder(self): # The generated *.designspace file should place instances # in the same order as they appear in the original source. # https://github.com/googlefonts/glyphsLib/issues/113 masters, _ = makeFamily() instances = [ makeInstance("Black", weight=("Black", 900, 190)), makeInstance("Regular", weight=("Regular", 400, 90)), makeInstance("Bold", weight=("Bold", 700, 151), is_bold=True), ] font = makeFont(masters, instances, "DesignspaceTest InstanceOrder") doc = to_designspace(font, instance_dir="out") self.expect_designspace(doc, "DesignspaceTestInstanceOrder.designspace") self.expect_designspace_roundtrip(doc)