def __init__(self, filename=None):
     """Load a variable font from the given filename."""
     self.masters = {}
     self.designspace = None
     self.master_order = []
     if filename.endswith(".glyphs"):
         f = GSFont(filename)
         self.designspace = UFOBuilder(f).designspace
         self.masters = {
             master.name: _load_gsfont(master)
             for master in f.masters
         }
         self.master_order = [master.name for master in f.masters]
     elif filename.endswith(".designspace"):
         self.designspace = DesignSpaceDocument.fromfile(filename)
         self.designspace.loadSourceFonts(load_ufo)
         self.masters = {
             source.styleName: source.font
             for source in self.designspace.sources
         }
         self.master_order = [
             source.styleName for source in self.designspace.sources
         ]
     if self.designspace:
         self._make_model()
Exemple #2
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
    def test_master_with_light_weight_but_thin_name(self):
        font = generate_minimal_font()
        master = font.masters[0]
        name = "Thin"  # In Glyphs.app, show "Thin" in the sidebar
        weight = "Light"  # In Glyphs.app, have the light "n" icon
        width = None  # No data => should be equivalent to Regular
        custom_name = "Thin"
        master.set_all_name_components(name, weight, width, custom_name)
        assert master.name == "Thin"
        assert master.weight == "Light"

        ufo, = to_ufos(font)
        font_rt = to_glyphs([ufo])
        master_rt = font_rt.masters[0]

        assert master_rt.name == "Thin"
        assert master_rt.weight == "Light"

        tmpdir = tempfile.mkdtemp()
        try:
            filename = os.path.join(tmpdir, "test.glyphs")
            font_rt.save(filename)
            font_rt_written = GSFont(filename)

            master_rt_written = font_rt_written.masters[0]

            assert master_rt_written.name == "Thin"
            assert master_rt_written.weight == "Light"
        finally:
            shutil.rmtree(tmpdir)
 def setUp(self):
     self.font = GSFont()
     self.font.masters.append(GSFontMaster())
     self.font.glyphs.append(GSGlyph("a"))
     self.font.glyphs.append(GSGlyph("c"))
     self.font.glyphs.append(GSGlyph("f"))
     self.ufo = Font()
     self.ufo.newGlyph("a")
     self.ufo.newGlyph("c")
     self.ufo.newGlyph("f")
Exemple #5
0
 def setUp(self):
     self.font = GSFont()
     self.font.masters.append(GSFontMaster())
     self.font.glyphs.append(GSGlyph('a'))
     self.font.glyphs.append(GSGlyph('c'))
     self.font.glyphs.append(GSGlyph('f'))
     self.ufo = Font()
     self.ufo.newGlyph('a')
     self.ufo.newGlyph('c')
     self.ufo.newGlyph('f')
Exemple #6
0
def test_custom_parameter_vfo_old_name():
    """Tests get_regular_master when 'Variation Font Origin' custom parameter name
    is used with master set to 'Regular Text'.  This custom parameter name is not
    used in current releases of the Glyphs editor / glyphs source file specification."""
    source_path = os.path.join("tests", "data", "CustomParameterVFO.glyphs")
    font = GSFont(source_path)

    # mock up source for this test with a source file from another test
    del font.customParameters["Variable Font Origin"]
    font.customParameters["Variation Font Origin"] = "Regular Text"
    assert font.customParameters["Variable Font Origin"] is None
    # start tests
    test_name = font.customParameters["Variation Font Origin"]
    matched = False
    for master in font.masters:
        if master.name == test_name:
            matched = True
    assert matched is True
    default_master = get_regular_master(font)
    assert default_master.name == "Regular Text"
Exemple #7
0
def test_custom_parameter_vfo_not_set():
    """Tests default behavior of get_regular_master when Variable Font Origin custom
    parameter is not set"""
    source_path = os.path.join("tests", "data", "CustomParameterVFO.glyphs")
    font = GSFont(source_path)

    # mock up source for this test with a source file from another test
    del font.customParameters["Variable Font Origin"]
    del font.customParameters["Variation Font Origin"]
    assert font.customParameters["Variable Font Origin"] is None
    assert font.customParameters["Variation Font Origin"] is None
    default_master = get_regular_master(font)
    assert default_master.name == "Regular Text"
Exemple #8
0
def test_custom_parameter_vfo_current():
    """Tests get_regular_master when 'Variable Font Origin' custom parameter name
    is used with master set to 'Regular Text'.  This is the current default
    custom parameter name in the Glyphs editor / glyphs source file specification."""
    source_path = os.path.join("tests", "data", "CustomParameterVFO.glyphs")
    font = GSFont(source_path)
    assert font.customParameters["Variation Font Origin"] is None
    test_id = font.customParameters["Variable Font Origin"]
    assert test_id == "ACC63F3E-1323-486A-94AF-B18797A154CE"
    matched = False
    for master in font.masters:
        if master.id == test_id:
            assert master.name == "Regular Text"
            matched = True
    assert matched is True
    default_master = get_regular_master(font)
    assert default_master.name == "Regular Text"
Exemple #9
0
def test_single_master_default_weight_400(ufo_module):
    font = GSFont()
    master = GSFontMaster()
    master.weightValue = 400
    font.masters.append(master)

    doc = to_designspace(font, ufo_module=ufo_module)

    assert len(doc.axes) == 1
    assert doc.axes[0].name == "Weight"
    assert doc.axes[0].minimum == 400
    assert doc.axes[0].default == 400
    assert doc.axes[0].maximum == 400
    assert len(doc.sources) == 1
    assert doc.sources[0].location["Weight"] == 400

    font2 = to_glyphs(doc)

    assert len(font2.masters) == 1
    assert font2.masters[0].weightValue == 400
def replace_prefixes(repl_map, features_text, glyph_names=None):
    """Replace all '# Prefix: NAME' sections in features.

    Args:
        repl_map: Dict[str, str]: dictionary keyed by prefix name containing
            feature code snippets to be replaced.
        features_text: str: feature text to be parsed.
        glyph_names: Optional[Sequence[str]]: list of valid glyph names, used
            by feaLib Parser to distinguish glyph name tokens containing '-' from
            glyph ranges such as 'a-z'.

    Returns:
        str: new feature text with replaced prefix paragraphs.
    """
    from glyphsLib.classes import GSFont

    temp_font = GSFont()
    _to_glyphs_features(temp_font, features_text, glyph_names=glyph_names)

    for prefix in temp_font.featurePrefixes:
        if prefix.name in repl_map:
            prefix.code = repl_map[prefix.name]

    return _to_ufo_features(temp_font)
Exemple #11
0
def build_masters(
    filename,
    master_dir,
    designspace_instance_dir=None,
    designspace_path=None,
    family_name=None,
    propagate_anchors=True,
    minimize_glyphs_diffs=False,
    normalize_ufos=False,
    create_background_layers=False,
    generate_GDEF=True,
    store_editor_state=True,
    write_skipexportglyphs=False,
):
    """Write and return UFOs from the masters and the designspace defined in a
    .glyphs file.

    Args:
        master_dir: Directory where masters are written.
        designspace_instance_dir: If provided, a designspace document will be
            written alongside the master UFOs though no instances will be built.
        family_name: If provided, the master UFOs will be given this name and
            only instances with this name will be included in the designspace.

    Returns:
        A named tuple of master UFOs (`ufos`) and the path to the designspace
        file (`designspace_path`).
    """

    font = GSFont(filename)

    if not os.path.isdir(master_dir):
        os.mkdir(master_dir)

    if designspace_instance_dir is None:
        instance_dir = None
    else:
        instance_dir = os.path.relpath(designspace_instance_dir, master_dir)

    designspace = to_designspace(
        font,
        family_name=family_name,
        propagate_anchors=propagate_anchors,
        instance_dir=instance_dir,
        minimize_glyphs_diffs=minimize_glyphs_diffs,
        generate_GDEF=generate_GDEF,
        store_editor_state=store_editor_state,
        write_skipexportglyphs=write_skipexportglyphs,
    )

    # Only write full masters to disk. This assumes that layer sources are always part
    # of another full master source, which must always be the case in a .glyphs file.
    ufos = {}
    for source in designspace.sources:
        if source.filename in ufos:
            assert source.font is ufos[source.filename]
            continue

        if create_background_layers:
            ufo_create_background_layer_for_all_glyphs(source.font)

        ufo_path = os.path.join(master_dir, source.filename)
        clean_ufo(ufo_path)
        source.font.save(ufo_path)

        if normalize_ufos:
            import ufonormalizer

            ufonormalizer.normalizeUFO(ufo_path, writeModTimes=False)

        ufos[source.filename] = source.font

    if not designspace_path:
        designspace_path = os.path.join(master_dir, designspace.filename)
    designspace.write(designspace_path)

    return Masters(ufos, designspace_path)
Exemple #12
0
 def setUp(self):
     self.ufo = Font()
     self.font = GSFont()
     self.master = GSFontMaster()
     self.font.masters.insert(0, self.master)
     self.builder = UFOBuilder(self.font)
Exemple #13
0
def makeFont(masters, instances, familyName):
    font = GSFont()
    font.familyName = familyName
    font.masters = masters
    font.instances = instances
    return font
Exemple #14
0
def test_wheres_ma_axis2(datadir):
    font2 = GSFont(datadir.join("AxesWdthWght.glyphs"))
    doc2 = to_designspace(font2)
    assert [a.tag for a in doc2.axes] == ["wdth", "wght"]
Exemple #15
0
def test_wheres_ma_axis(datadir):
    font1 = GSFont(datadir.join("AxesWdth.glyphs"))
    doc1 = to_designspace(font1)
    assert [a.tag for a in doc1.axes] == ["wdth"]
Exemple #16
0
def build_masters(
    filename,
    master_dir,
    designspace_instance_dir=None,
    designspace_path=None,
    family_name=None,
    propagate_anchors=True,
    minimize_glyphs_diffs=False,
    normalize_ufos=False,
    create_background_layers=False,
    generate_GDEF=True,
):
    """Write and return UFOs from the masters and the designspace defined in a
    .glyphs file.

    Args:
        master_dir: Directory where masters are written.
        designspace_instance_dir: If provided, a designspace document will be
            written alongside the master UFOs though no instances will be built.
        family_name: If provided, the master UFOs will be given this name and
            only instances with this name will be included in the designspace.

    Returns:
        A named tuple of master UFOs (`ufos`) and the path to the designspace
        file (`designspace_path`).
    """

    font = GSFont(filename)

    if not os.path.isdir(master_dir):
        os.mkdir(master_dir)

    if designspace_instance_dir is None:
        instance_dir = None
    else:
        instance_dir = os.path.relpath(designspace_instance_dir, master_dir)

    designspace = to_designspace(
        font,
        family_name=family_name,
        propagate_anchors=propagate_anchors,
        instance_dir=instance_dir,
        minimize_glyphs_diffs=minimize_glyphs_diffs,
        generate_GDEF=generate_GDEF,
    )

    ufos = []
    for source in designspace.sources:
        ufos.append(source.font)

        if create_background_layers:
            ufo_create_background_layer_for_all_glyphs(source.font)

        ufo_path = os.path.join(master_dir, source.filename)
        clean_ufo(ufo_path)
        source.font.save(ufo_path)

        if normalize_ufos:
            import ufonormalizer

            ufonormalizer.normalizeUFO(ufo_path, writeModTimes=False)

    if not designspace_path:
        designspace_path = os.path.join(master_dir, designspace.filename)
    designspace.write(designspace_path)

    return Masters(ufos, designspace_path)