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",
    }
Esempio n. 2
0
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 == []
Esempio n. 3
0
    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
Esempio n. 4
0
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)
Esempio n. 5
0
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)
Esempio n. 6
0
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)
Esempio n. 9
0
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
    }]
Esempio n. 10
0
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
Esempio n. 11
0
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'
Esempio n. 14
0
    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
Esempio n. 16
0
    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)
Esempio n. 18
0
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)
Esempio n. 19
0
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
Esempio n. 20
0
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]",
            }
Esempio n. 21
0
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
Esempio n. 22
0
    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)
Esempio n. 23
0
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
Esempio n. 24
0
    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
Esempio n. 25
0
 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)
Esempio n. 26
0
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
Esempio n. 27
0
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"
Esempio n. 28
0
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"
Esempio n. 29
0
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,
    }]
Esempio n. 30
0
 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)