def test_custom_stylemap_style_name():
    ufo = defcon.Font()
    ufo.info.styleMapStyleName = 'bold'  # Not "regular"

    font = to_glyphs([ufo], minimize_ufo_diffs=True)
    ufo, = to_ufos(font)

    assert ufo.info.styleMapStyleName == 'bold'
Example #2
0
def test_custom_stylemap_style_name(ufo_module):
    ufo = ufo_module.Font()
    ufo.info.styleMapStyleName = "bold"  # Not "regular"

    font = to_glyphs([ufo], minimize_ufo_diffs=True)
    (ufo,) = to_ufos(font)

    assert ufo.info.styleMapStyleName == "bold"
Example #3
0
def test_comments_in_classes(ufo_module):
    filename = os.path.join(os.path.dirname(__file__),
                            "../data/CommentedClass.glyphs")
    font = classes.GSFont(filename)
    (ufo, ) = to_ufos(font)
    assert ufo.features.text == dedent("""\
            @Test = [ A
            # B
            ];
""")
def test_guidelines():
    ufo = defcon.Font()
    a = ufo.newGlyph('a')
    for obj in [ufo, a]:
        # Complete guideline
        obj.appendGuideline(
            dict(x=10,
                 y=20,
                 angle=30,
                 name="lc",
                 color="1,0,0,1",
                 identifier="lc1"))
        # Don't crash if a guideline misses information
        obj.appendGuideline({'x': 10})
        obj.appendGuideline({'y': 20})
        obj.appendGuideline({})

    font = to_glyphs([ufo])

    for gobj in [font.masters[0], font.glyphs['a'].layers[0]]:
        assert len(gobj.guides) == 4

        angled, vertical, horizontal, empty = gobj.guides

        assert angled.position.x == 10
        assert angled.position.y == 20
        assert angled.angle == 330
        assert angled.name == "lc [1,0,0,1] [#lc1]"

        assert vertical.position.x == 10
        assert vertical.angle == 90

        assert horizontal.position.y == 20
        assert horizontal.angle == 0

    ufo, = to_ufos(font)

    for obj in [ufo, ufo['a']]:
        angled, vertical, horizontal, empty = obj.guidelines

        assert angled.x == 10
        assert angled.y == 20
        assert angled.angle == 30
        assert angled.name == 'lc'
        assert angled.color == '1,0,0,1'
        assert angled.identifier == 'lc1'

        assert vertical.x == 10
        assert vertical.y is None
        assert vertical.angle is None

        assert horizontal.x is None
        assert horizontal.y == 20
        assert horizontal.angle is None
Example #5
0
def test_guidelines(ufo_module):
    ufo = ufo_module.Font()
    a = ufo.newGlyph("a")
    for obj in [ufo, a]:
        # Complete guideline
        obj.appendGuideline(
            dict(x=10,
                 y=20,
                 angle=30,
                 name="lc",
                 color="1,0,0,1",
                 identifier="lc1"))
        # Don't crash if a guideline misses information
        obj.appendGuideline({"x": 10})
        obj.appendGuideline({"y": 20})

    font = to_glyphs([ufo])

    for gobj in [font.masters[0], font.glyphs["a"].layers[0]]:
        assert len(gobj.guides) == 3

        angled, vertical, horizontal = gobj.guides

        assert angled.position.x == 10
        assert angled.position.y == 20
        assert angled.angle == 30
        assert angled.name == "lc [1,0,0,1] [#lc1]"

        assert vertical.position.x == 10
        assert vertical.angle == 90

        assert horizontal.position.y == 20
        assert horizontal.angle == 0

    (ufo, ) = to_ufos(font)

    for obj in [ufo, ufo["a"]]:
        angled, vertical, horizontal = obj.guidelines

        assert angled.x == 10
        assert angled.y == 20
        assert angled.angle == 30
        assert angled.name == "lc"
        assert angled.color == "1,0,0,1"
        assert angled.identifier == "lc1"

        assert vertical.x == 10
        assert vertical.y is None
        assert vertical.angle is None

        assert horizontal.x is None
        assert horizontal.y == 20
        assert horizontal.angle is None
Example #6
0
def doit(args):
    logger = args.logger
    logger.log("Creating UFO objects from GlyphsApp file", "I")
    with open(args.glyphsfont, 'r', encoding='utf-8') as gfile:
        gfont = glyphsLib.parser.load(gfile)
    ufos = glyphsLib.to_ufos(gfont,
                             include_instances=False,
                             family_name=None,
                             propagate_anchors=False,
                             generate_GDEF=False)

    # Extract directory name for use with restores
    (glyphsdir, filen) = os.path.split(args.glyphsfont)

    keylists = {
        "librestorekeys": [
            "org.sil.pysilfontparams", "org.sil.altLineMetrics",
            "org.sil.lcg.toneLetters", "org.sil.lcg.transforms",
            "public.glyphOrder", "public.postscriptNames",
            "com.schriftgestaltung.disablesLastChange",
            "com.schriftgestaltung.disablesAutomaticAlignment"
        ],
        "libdeletekeys":
        ("UFOFormat", "com.schriftgestaltung.blueFuzz",
         "com.schriftgestaltung.blueScale", "com.schriftgestaltung.blueShift",
         "com.schriftgestaltung.customParameter.GSFont.note",
         "com.schriftgestaltung.customParameter.GSFont.Axes",
         "com.schriftgestaltung.customParameter.GSFontMaster.Master Name",
         "org.sil.glyphsappversion"),
        "libdeleteempty": ("com.schriftgestaltung.DisplayStrings", ),
        "inforestorekeys": [
            "openTypeHeadCreated", "openTypeNamePreferredFamilyName",
            "openTypeNamePreferredSubfamilyName", "openTypeNameUniqueID",
            "openTypeOS2WeightClass", "openTypeOS2WidthClass",
            "postscriptFontName", "postscriptFullName", "styleMapFamilyName",
            "styleMapStyleName", "note"
        ],
        "integerkeys": ("openTypeOS2WeightClass", "openTypeOS2WidthClass"),
        "infodeleteempty": ("openTypeOS2Selection", )
    }

    if args.restore:  # Extra kesys to restore.  Add to both lists, since should never be duplicated names
        keylist = args.restore.split(",")
        keylists["librestorekeys"] += keylist
        keylists["inforestorekeys"].append(keylist)

    loglists = []
    for ufo in ufos:
        loglists.append(process_ufo(ufo, keylists, glyphsdir, args))
    for loglist in loglists:
        for logitem in loglist:
            logger.log(logitem[0], logitem[1])
def test_DisplayStrings_ufo_lib():
    font = classes.GSFont()
    font.masters.append(classes.GSFontMaster())
    font.masters.append(classes.GSFontMaster())
    font.DisplayStrings = ""

    ufo1, ufo2 = to_ufos(font)
    assert FONT_CUSTOM_PARAM_PREFIX + "DisplayStrings" not in ufo1.lib
    assert FONT_CUSTOM_PARAM_PREFIX + "DisplayStrings" not in ufo2.lib

    font = to_glyphs([ufo1, ufo2])
    assert font.DisplayStrings == ""

    # ---
    font.DisplayStrings = "a"

    ufo1, ufo2 = to_ufos(font)
    assert ufo1.lib[FONT_CUSTOM_PARAM_PREFIX + "DisplayStrings"] == "a"
    assert ufo2.lib[FONT_CUSTOM_PARAM_PREFIX + "DisplayStrings"] == "a"

    font = to_glyphs([ufo1, ufo2])
    assert font.DisplayStrings == "a"
Example #8
0
def test_roundtrip_existing_GDEF(tmpdir, ufo_with_GDEF):
    """Test that an existing GDEF table in UFO is preserved unchanged and
    no extra GDEF table is generated upon roundtripping to UFO when
    `generate_GDEF` is False.
    """
    ufo, gdef, ufo_module = ufo_with_GDEF
    font = to_glyphs([ufo])
    filename = os.path.join(str(tmpdir), "font.glyphs")
    font.save(filename)
    font = classes.GSFont(filename)
    (rtufo, ) = to_ufos(font, generate_GDEF=False, ufo_module=ufo_module)

    assert rtufo.features.text == gdef
Example #9
0
def test_roundtrip_disabled_feature():
    font = to_glyphs([defcon.Font()])
    feature = classes.GSFeature(name="ccmp")
    feature.code = dedent(
        """\
        sub a by a.ss03;
        sub b by b.ss03;
        sub c by c.ss03;
    """
    )
    feature.disabled = True
    font.features.append(feature)

    ufo, = to_ufos(font)
    assert ufo.features.text == dedent(
        """\
        feature ccmp {
        # disabled
        #sub a by a.ss03;
        #sub b by b.ss03;
        #sub c by c.ss03;
        } ccmp;
    """
    )

    font_r = to_glyphs([ufo])
    assert len(font_r.features) == 1
    feature_r = font_r.features[0]
    assert feature_r.name == "ccmp"
    assert feature_r.code == feature.code
    assert feature_r.disabled is True

    font_rr = to_glyphs(to_ufos(font_r))
    assert len(font_rr.features) == 1
    feature_rr = font_rr.features[0]
    assert feature_rr.name == "ccmp"
    assert feature_rr.code == feature.code
    assert feature_rr.disabled is True
Example #10
0
def test_info(fields, tmpdir, ufo_module):
    ufo = ufo_module.Font()

    for field in fields:
        setattr(ufo.info, field.name, field.test_value)

    font = to_glyphs([ufo], minimize_ufo_diffs=True)
    filename = os.path.join(str(tmpdir), "font.glyphs")
    font.save(filename)
    font = classes.GSFont(filename)
    (ufo, ) = to_ufos(font, ufo_module=ufo_module)

    for field in fields:
        assert getattr(ufo.info, field.name) == field.test_value
Example #11
0
def test_different_features_in_different_UFOS(tmpdir):
    # If the input UFOs have different features, Glyphs cannot model the
    # differences easily.
    #
    # TODO: (jany) A complex solution would be to put all the features that we
    # find across all the UFOS into the GSFont's features, and then add custom
    # parameters "Replace Features" and "Remove features" to the GSFontMasters
    # of the UFOs that didn't have the feature originally.
    #
    # What is done now: if feature files differ between the input UFOs, the
    # original text of each UFO's feature is stored in userData, and a single
    # GSFeaturePrefix is created just to warn the user that features were not
    # imported because of differences.
    ufo1 = defcon.Font()
    ufo1.features.text = dedent(
        """\
        include('../family.fea');
    """
    )
    ufo2 = defcon.Font()
    ufo2.features.text = dedent(
        """\
        include('../family.fea');

        feature ss03 {
            sub c by c.ss03;
        } ss03;
    """
    )

    font = to_glyphs([ufo1, ufo2], minimize_ufo_diffs=True)
    filename = os.path.join(str(tmpdir), "font.glyphs")
    font.save(filename)
    font = classes.GSFont(filename)
    ufo1rt, ufo2rt = to_ufos(font)

    assert len(font.features) == 0
    assert len(font.featurePrefixes) == 1
    assert font.featurePrefixes[0].code == dedent(
        """\
        # Do not use Glyphs to edit features.
        #
        # This Glyphs file was made from several UFOs that had different
        # features. As a result, the features are not editable in Glyphs and
        # the original features will be restored when you go back to UFOs.
    """
    )

    assert ufo1rt.features.text == ufo1.features.text
    assert ufo2rt.features.text == ufo2.features.text
def test_info(fields, tmpdir):
    ufo = defcon.Font()

    for field in fields:
        setattr(ufo.info, field.name, field.test_value)

    font = to_glyphs([ufo], minimize_ufo_diffs=True)
    filename = os.path.join(str(tmpdir), 'font.glyphs')
    font.save(filename)
    font = classes.GSFont(filename)
    ufo, = to_ufos(font)

    for field in fields:
        assert getattr(ufo.info, field.name) == field.test_value
Example #13
0
def test_custom_default_layer_name(ufo_module):
    ufo1 = ufo_module.Font()
    ufo2 = ufo_module.Font()
    if hasattr(ufo1, "renameLayer") and callable(ufo1.renameLayer):
        ufo1.renameLayer("public.default", "custom default")
        ufo2.renameLayer("public.default", "other default")
    else:
        ufo1.layers.defaultLayer.name = "custom default"
        ufo2.layers.defaultLayer.name = "other default"

    font = to_glyphs([ufo1, ufo2])
    (ufo1, ufo2) = to_ufos(font)

    assert ufo1.layers.defaultLayer.name == "custom default"
    assert ufo2.layers.defaultLayer.name == "other default"
Example #14
0
    def test_ufo2ft_filter_roundtrip(self):
        ufo_filters = [
            {"name": "propagateAnchors", "pre": True, "include": ["a", "b", "c"]}
        ]
        glyphs_filter = "propagateAnchors;include:a,b,c"

        self.master.customParameters["PreFilter"] = glyphs_filter
        self.set_custom_params()
        self.assertEqual(self.ufo.lib[UFO2FT_FILTERS_KEY], ufo_filters)

        font_rt = glyphsLib.to_glyphs([self.ufo])
        self.assertEqual(
            font_rt.masters[0].customParameters["PreFilter"], glyphs_filter
        )
        ufo_rt = glyphsLib.to_ufos(font_rt)[0]
        self.assertEqual(ufo_rt.lib[UFO2FT_FILTERS_KEY], ufo_filters)
def test_glyph_color():
    ufo = defcon.Font()
    a = ufo.newGlyph('a')
    a.markColor = GLYPHS_COLORS[3]
    b = ufo.newGlyph('b')
    b.markColor = '{:.3f},{:.3f},0,1'.format(4.0 / 255, 128.0 / 255)

    font = to_glyphs([ufo])

    assert font.glyphs['a'].color == 3
    assert font.glyphs['b'].color == [4, 128, 0, 255]

    ufo, = to_ufos(font)

    assert ufo['a'].markColor == GLYPHS_COLORS[3]
    assert ufo['b'].markColor == b.markColor
Example #16
0
def test_master_user_location_goes_into_os2_classes():
    font = to_glyphs([defcon.Font(), defcon.Font()])
    font.customParameters['Axes'] = [
        {
            'Tag': 'wght',
            'Name': 'Weight',
        },
        {
            'Tag': 'wdth',
            'Name': 'Width',
        },
    ]
    font.masters[0].weightValue = 0
    font.masters[0].widthValue = 1000
    # This master will be Light Expanded
    # as per https://docs.microsoft.com/en-gb/typography/opentype/spec/os2#uswidthclass
    font.masters[0].customParameters['Axis Location'] = [
        {
            'Axis': 'Weight',
            'Location': 300,
        },
        {
            'Axis': 'Width',
            'Location': 125,
        },
    ]
    font.masters[1].weightValue = 1000
    font.masters[1].widthValue = 0
    # This master is Black Ultra-condensed but not quite
    font.masters[1].customParameters['Axis Location'] = [
        {
            'Axis': 'Weight',
            'Location': 920,  # instead of 900
        },
        {
            'Axis': 'Width',
            'Location': 55,  # instead of 50
        },
    ]

    light, black = to_ufos(font)

    assert light.info.openTypeOS2WeightClass == 300
    assert light.info.openTypeOS2WidthClass == 7

    assert black.info.openTypeOS2WeightClass == 920
    assert black.info.openTypeOS2WidthClass == 1
Example #17
0
def test_master_user_location_goes_into_os2_classes(ufo_module):
    font = to_glyphs([ufo_module.Font(), ufo_module.Font()])
    font.customParameters["Axes"] = [
        {
            "Tag": "wght",
            "Name": "Weight"
        },
        {
            "Tag": "wdth",
            "Name": "Width"
        },
    ]
    font.masters[0].weightValue = 0
    font.masters[0].widthValue = 1000
    # This master will be Light Expanded
    # as per https://docs.microsoft.com/en-gb/typography/opentype/spec/os2#uswidthclass
    font.masters[0].customParameters["Axis Location"] = [
        {
            "Axis": "Weight",
            "Location": 300
        },
        {
            "Axis": "Width",
            "Location": 125
        },
    ]
    font.masters[1].weightValue = 1000
    font.masters[1].widthValue = 0
    # This master is Black Ultra-condensed but not quite
    font.masters[1].customParameters["Axis Location"] = [
        {
            "Axis": "Weight",
            "Location": 920
        },  # instead of 900
        {
            "Axis": "Width",
            "Location": 55
        },  # instead of 50
    ]

    light, black = to_ufos(font)

    assert light.info.openTypeOS2WeightClass == 300
    assert light.info.openTypeOS2WidthClass == 7

    assert black.info.openTypeOS2WeightClass == 920
    assert black.info.openTypeOS2WidthClass == 1
def test_ufo_lib_equivalent_to_font_master_user_data():
    ufo1 = defcon.Font()
    ufo1.lib['ufoLibKey1'] = 'ufoLibValue1'
    ufo2 = defcon.Font()
    ufo2.lib['ufoLibKey2'] = 'ufoLibValue2'

    font = to_glyphs([ufo1, ufo2])

    assert font.masters[0].userData['ufoLibKey1'] == 'ufoLibValue1'
    assert font.masters[1].userData['ufoLibKey2'] == 'ufoLibValue2'

    ufo1, ufo2 = to_ufos(font)

    assert ufo1.lib['ufoLibKey1'] == 'ufoLibValue1'
    assert ufo2.lib['ufoLibKey2'] == 'ufoLibValue2'
    assert 'ufoLibKey2' not in ufo1.lib
    assert 'ufoLibKey1' not in ufo2.lib
def test_double_unicodes(tmpdir):
    ufo = defcon.Font()
    z = ufo.newGlyph('z')
    z.unicodes = [0x005A, 0x007A]

    font = to_glyphs([ufo])
    path = os.path.join(str(tmpdir), 'test.glyphs')
    font.save(path)
    saved_font = classes.GSFont(path)

    for font in [font, saved_font]:
        assert font.glyphs['z'].unicode == "005A"
        assert font.glyphs['z'].unicodes == ["005A", "007A"]

        ufo, = to_ufos(font)

        assert ufo['z'].unicodes == [0x005A, 0x007A]
Example #20
0
def test_double_unicodes(tmpdir, ufo_module):
    ufo = ufo_module.Font()
    z = ufo.newGlyph("z")
    z.unicodes = [0x005A, 0x007A]

    font = to_glyphs([ufo])
    path = os.path.join(str(tmpdir), "test.glyphs")
    font.save(path)
    saved_font = classes.GSFont(path)

    for font in [font, saved_font]:
        assert font.glyphs["z"].unicode == "005A"
        assert font.glyphs["z"].unicodes == ["005A", "007A"]

        (ufo, ) = to_ufos(font)

        assert ufo["z"].unicodes == [0x005A, 0x007A]
def test_ufo_lib_equivalent_to_font_master_user_data(ufo_module):
    ufo1 = ufo_module.Font()
    ufo1.lib["ufoLibKey1"] = "ufoLibValue1"
    ufo2 = ufo_module.Font()
    ufo2.lib["ufoLibKey2"] = "ufoLibValue2"

    font = to_glyphs([ufo1, ufo2])

    assert font.masters[0].userData["ufoLibKey1"] == "ufoLibValue1"
    assert font.masters[1].userData["ufoLibKey2"] == "ufoLibValue2"

    ufo1, ufo2 = to_ufos(font)

    assert ufo1.lib["ufoLibKey1"] == "ufoLibValue1"
    assert ufo2.lib["ufoLibKey2"] == "ufoLibValue2"
    assert "ufoLibKey2" not in ufo1.lib
    assert "ufoLibKey1" not in ufo2.lib
Example #22
0
def test_glyph_color(ufo_module):
    ufo = ufo_module.Font()
    a = ufo.newGlyph("a")
    a.markColor = GLYPHS_COLORS[3]
    b = ufo.newGlyph("b")
    b.markColor = "{:.3f},{:.3f},0,1".format(4.0 / 255, 128.0 / 255)

    font = to_glyphs([ufo])

    rt_a_color = font.glyphs["a"].color
    assert rt_a_color == 3 and type(rt_a_color) is int
    rt_b_color = font.glyphs["b"].color
    assert rt_b_color == [4, 128, 0, 255] and all(type(x) is int for x in rt_b_color)

    (ufo,) = to_ufos(font)

    assert ufo["a"].markColor == GLYPHS_COLORS[3]
    assert ufo["b"].markColor == b.markColor
def test_layer_lib_into_master_user_data(ufo_module):
    ufo1 = ufo_module.Font()
    ufo1.layers["public.default"].lib["layerLibKey1"] = "ufo1 layerLibValue1"
    layer = ufo1.newLayer("sketches")
    layer.lib["layerLibKey2"] = "ufo1 layerLibValue2"
    # layers won't roundtrip if they contain no glyph, except for the default
    layer.newGlyph("bob")
    ufo2 = ufo_module.Font()
    ufo2.layers["public.default"].lib["layerLibKey1"] = "ufo2 layerLibValue1"
    layer = ufo2.newLayer("sketches")
    layer.lib["layerLibKey2"] = "ufo2 layerLibValue2"
    layer.newGlyph("bob")

    font = to_glyphs([ufo1, ufo2])

    default_layer_key = GLYPHLIB_PREFIX + "layerLib.public.default"
    sketches_layer_key = GLYPHLIB_PREFIX + "layerLib.sketches"
    assert default_layer_key not in font.userData
    assert sketches_layer_key not in font.userData
    assert font.masters[0].userData[default_layer_key] == {
        "layerLibKey1": "ufo1 layerLibValue1"
    }
    assert font.masters[0].userData[sketches_layer_key] == {
        "layerLibKey2": "ufo1 layerLibValue2"
    }
    assert font.masters[1].userData[default_layer_key] == {
        "layerLibKey1": "ufo2 layerLibValue1"
    }
    assert font.masters[1].userData[sketches_layer_key] == {
        "layerLibKey2": "ufo2 layerLibValue2"
    }

    (ufo1, ufo2) = to_ufos(font)

    assert ufo1.layers["public.default"].lib[
        "layerLibKey1"] == "ufo1 layerLibValue1"
    assert "layerLibKey1" not in ufo1.layers["sketches"].lib
    assert ufo1.layers["sketches"].lib["layerLibKey2"] == "ufo1 layerLibValue2"
    assert "layerLibKey2" not in ufo1.layers["public.default"].lib
    assert ufo2.layers["public.default"].lib[
        "layerLibKey1"] == "ufo2 layerLibValue1"
    assert "layerLibKey1" not in ufo2.layers["sketches"].lib
    assert ufo2.layers["sketches"].lib["layerLibKey2"] == "ufo2 layerLibValue2"
    assert "layerLibKey2" not in ufo2.layers["public.default"].lib
Example #24
0
def test_roundtrip_feature_prefix_with_only_a_comment(ufo_module):
    font = to_glyphs([ufo_module.Font()])
    prefix = classes.GSFeaturePrefix(name="include")
    # Contents: just a comment
    prefix.code = "#include(../family.fea)"
    font.featurePrefixes.append(prefix)

    (ufo, ) = to_ufos(font, ufo_module=ufo_module)

    assert ufo.features.text == dedent("""\
        # Prefix: include
        #include(../family.fea)
    """)

    font_r = to_glyphs([ufo])
    assert len(font_r.featurePrefixes) == 1
    prefix_r = font_r.featurePrefixes[0]
    assert prefix_r.name == "include"
    assert prefix_r.code == "#include(../family.fea)"
Example #25
0
def test_roundtrip_empty_feature(ufo_module):
    # https://github.com/googlefonts/glyphsLib/issues/562
    font = to_glyphs([ufo_module.Font()])
    feature = classes.GSFeature(name="dlig")
    feature.code = ""
    font.features.append(feature)

    (ufo, ) = to_ufos(font, ufo_module=ufo_module)
    assert ufo.features.text == dedent("""\
        feature dlig {

        } dlig;
    """)

    font_r = to_glyphs([ufo])
    assert len(font_r.features) == 1
    feature_r = font_r.features[0]
    assert feature_r.name == "dlig"
    assert feature_r.code == ""
Example #26
0
    def test_ufo2ft_filter_roundtrip(self):
        ufo_filters = [
            {"name": "propagateAnchors", "pre": True, "include": ["a", "b", "c"]}
        ]
        glyphs_filter = "propagateAnchors;include:a,b,c"

        # Test the one-way conversion of (Pre)Filters into ufo2ft filters. See the
        # docstring for FilterParamHandler.
        self.master.customParameters["PreFilter"] = glyphs_filter
        self.set_custom_params()
        self.assertEqual(self.ufo.lib[UFO2FT_FILTERS_KEY], ufo_filters)

        # Test the round-tripping of ufo2ft filters from UFO -> Glyphs master -> UFO.
        # See the docstring for FilterParamHandler.
        font_rt = glyphsLib.to_glyphs([self.ufo])
        self.assertNotIn("PreFilter", font_rt.masters[0].customParameters)
        self.assertEqual(font_rt.masters[0].userData[UFO2FT_FILTERS_KEY], ufo_filters)
        ufo_rt = glyphsLib.to_ufos(font_rt)[0]
        self.assertEqual(ufo_rt.lib[UFO2FT_FILTERS_KEY], ufo_filters)
def test_node_user_data_into_glif_lib():
    font = classes.GSFont()
    master = classes.GSFontMaster()
    master.id = "M1"
    font.masters.append(master)
    glyph = classes.GSGlyph("a")
    layer = classes.GSLayer()
    layer.layerId = "M1"
    layer.associatedMasterId = "M1"
    glyph.layers.append(layer)
    font.glyphs.append(glyph)
    path = classes.GSPath()
    layer.paths.append(path)
    node1 = classes.GSNode()
    node1.userData["nodeUserDataKey1"] = "nodeUserDataValue1"
    node1.name = "node1"
    node2 = classes.GSNode()
    node2.userData["nodeUserDataKey2"] = "nodeUserDataValue2"
    node2.name = "node2"
    path.nodes.append(classes.GSNode())
    path.nodes.append(node1)
    path.nodes.append(classes.GSNode())
    path.nodes.append(classes.GSNode())
    path.nodes.append(node2)

    (ufo, ) = to_ufos(font, minimize_glyphs_diffs=True)

    assert ufo["a"].lib[GLYPHLIB_PREFIX + "nodeUserData.0.1"] == {
        "nodeUserDataKey1": "nodeUserDataValue1"
    }
    assert ufo["a"][0][2].name == "node1"
    assert ufo["a"].lib[GLYPHLIB_PREFIX + "nodeUserData.0.4"] == {
        "nodeUserDataKey2": "nodeUserDataValue2"
    }
    assert ufo["a"][0][0].name == "node2"

    font = to_glyphs([ufo])

    path = font.glyphs["a"].layers["M1"].paths[0]
    assert path.nodes[1].userData["nodeUserDataKey1"] == "nodeUserDataValue1"
    assert path.nodes[1].name == "node1"
    assert path.nodes[4].userData["nodeUserDataKey2"] == "nodeUserDataValue2"
    assert path.nodes[4].name == "node2"
Example #28
0
def test_roundtrip_feature_prefix_with_only_a_comment():
    font = to_glyphs([defcon.Font()])
    prefix = classes.GSFeaturePrefix(name="include")
    # Contents: just a comment
    prefix.code = "#include(../family.fea)"
    font.featurePrefixes.append(prefix)

    ufo, = to_ufos(font)

    assert ufo.features.text == dedent('''\
        # Prefix: include
        #include(../family.fea)
    ''')

    font_r = to_glyphs([ufo])
    assert len(font_r.featurePrefixes) == 1
    prefix_r = font_r.featurePrefixes[0]
    assert prefix_r.name == 'include'
    assert prefix_r.code == "#include(../family.fea)"
Example #29
0
def test_open_contour(ufo_module):
    ufo = ufo_module.Font()
    a = ufo.newGlyph("a")
    pen = a.getPen()
    pen.moveTo((10, 20))
    pen.lineTo((30, 40))
    pen.endPath()

    font = to_glyphs([ufo])

    path = font.glyphs["a"].layers[0].paths[0]
    assert not path.closed
    assert len(path.nodes) == 2
    assert path.nodes[0].type == classes.LINE

    (ufo_rt, ) = to_ufos(font)

    assert [(p.segmentType, p.x, p.y) for p in a[0]
            ] == [(p.segmentType, p.x, p.y) for p in ufo_rt["a"][0]]
def test_lib_data_types(tmpdir, ufo_module):
    # Test the roundtrip of a few basic types both at the top level and in a
    # nested object.
    data = OrderedDict({
        "boolean": True,
        "smooth": False,
        "integer": 1,
        "float": 0.5,
        "array": [],
        "dict": {},
    })
    ufo = ufo_module.Font()
    a = ufo.newGlyph("a")
    for key, value in data.items():
        a.lib[key] = value
        a.lib["nestedDict"] = dict(data)
        a.lib["nestedArray"] = list(data.values())
        a.lib["crazyNesting"] = [{"a": [{"b": [dict(data)]}]}]

    font = to_glyphs([ufo])

    # FIXME: This test will stop working if the font is written and read back,
    # because the file format of Glyphs does not make a difference between
    # `True` (bool) and `1` (int).
    # filename = os.path.join(str(tmpdir), 'font.glyphs')
    # font.save(filename)
    # font = classes.GSFont(filename)

    (ufo, ) = to_ufos(font)

    for index, (key, value) in enumerate(data.items()):
        assert value == ufo["a"].lib[key]
        assert value == ufo["a"].lib["nestedDict"][key]
        assert value == ufo["a"].lib["nestedArray"][index]
        assert value == ufo["a"].lib["crazyNesting"][0]["a"][0]["b"][0][key]
        assert type(value) is type(ufo["a"].lib[key])  # noqa: E721
        assert type(value) is type(
            ufo["a"].lib["nestedDict"][key])  # noqa: E721
        assert type(value) is type(
            ufo["a"].lib["nestedArray"][index])  # noqa: E721
        assert type(value) is type(  # noqa: E721
            ufo["a"].lib["crazyNesting"][0]["a"][0]["b"][0][key])
Example #31
0
def doit(args):
    logger = args.logger
    logger.log("Creating UFO objects from GlyphsApp file", "I")
    with open(args.glyphsfont, 'r', encoding='utf-8') as gfile:
        gfont = glyphsLib.parser.load(gfile)
    ufos = glyphsLib.to_ufos(gfont, include_instances=False, family_name=None, propagate_anchors=False)

    # Extract directory name for use with backups
    (glyphsdir, filen) = os.path.split(args.glyphsfont)

    librestorekeys = ("org.sil.pysilfontparams", "org.sil.altLineMetrics", "org.sil.lcg.toneLetters",
                   "org.sil.lcg.transforms", "public.glyphOrder", "public.postscriptNames")
    libdeletekeys = ("UFOFormat", "com.schriftgestaltung.blueFuzz", "com.schriftgestaltung.blueScale",
                     "com.schriftgestaltung.blueShift")
    libdeleteempty = ("com.schriftgestaltung.DisplayStrings",)

    inforestorekeys = ("openTypeHeadCreated", "openTypeNamePreferredFamilyName", "openTypeNamePreferredSubfamilyName",
                       "openTypeNameUniqueID", "openTypeOS2WeightClass", "openTypeOS2WidthClass", "postscriptFontName",
                       "postscriptFullName", "styleMapFamilyName", "styleMapStyleName")
    integerkeys = ("openTypeOS2WeightClass", "openTypeOS2WidthClass")
    infodeleteempty = ("openTypeOS2Selection",)
    infodeletekeys = ("openTypeOS2Type",)

    for ufo in ufos:
        sn = ufo.info.styleName                              # )
        sn = sn.replace("Italic Italic", "Italic")           # ) Temp fixes due to glyphLib incorrectly
        sn = sn.replace("Italic Bold Italic", "Bold Italic") # ) forming styleName
        ufo.info.styleName = sn                              # )
        fontname = ufo.info.familyName.replace(" ", "") + "-" + ufo.info.styleName.replace(" ", "")

        # Fixes to the data
        if not args.nofixes:
            logger.log("Fixing data in " + fontname, "P")
            # lib.plist processing
            logger.log("Checking lib.plist", "P")

            # Process UFO.lib if present
            if "UFO.lib" in ufo.lib:
                logger.log("UFOlib found in lib.plist for " + fontname + ". Values will be copied to root", "P")
                ul = ufo.lib["UFO.lib"]
                # Copy fields from UFO.lib to root
                for key in ul:
                    if key in librestorekeys:
                        continue # They will be restored later
                    if key in libdeleteempty:
                        if ul[key] == "" or ul[key] == []:
                            logger.log("Emtpy field ignored: " + key, "I")
                            continue
                    if key in libdeletekeys:
                        logger.log(key + " ignored", "I")
                        continue
                    if key in ufo.lib:
                        current = ufo.lib[key]
                        logmess = " updated from UFO.lib. "
                    else:
                        current = None
                        logmess = " copied from UFO.lib. "
                    new = ul[key]
                    if current == new:
                        continue
                    else:
                        ufo.lib[key] = new
                        logchange(logger, logmess, key, current, new)
                del ufo.lib["UFO.lib"]
                logger.log("UFO.lib field deleted", "I")

            # Restore values from original UFOs, assuming nameed as <fontname>.ufo in same directory as input .gylphs file

            ufodir = os.path.join(glyphsdir,fontname+".ufo")
            try:
                origlibplist = silfont.ufo.Uplist(font=None, dirn=ufodir, filen="lib.plist")
            except Exception as e:
                logger.log("Unable to open lib.plist in " + ufodir + "; values will not be restored", "E")
                origlibplist = None

            if origlibplist is not None:
                for key in librestorekeys:
                    if key in origlibplist:
                        new = origlibplist.getval(key)
                        current = None if key not in ufo.lib else ufo.lib[key]
                        if current == new:
                            continue
                        else:
                            ufo.lib[key] = new
                            logchange(logger, " restored from backup ufo. ", key, current, new)

            # Delete unneeded keys

            for key in libdeletekeys:
                if key in ufo.lib:
                    current = ufo.lib[key]
                    del ufo.lib[key]
                    logchange(logger, " deleted. ", key, current, None)

            for key in libdeleteempty:
                if key in ufo.lib and (ufo.lib[key] == "" or ufo.lib[key] == []):
                    del ufo.lib[key]
                    logchange(logger, " empty field deleted. ", key, current, None)

            ufo.lib["org.sil.glyphsappversion"] = gfont.appVersion

            # fontinfo.plist processing

            logger.log("Checking fontinfo.plist", "P")

            try:
                origfontinfo = silfont.ufo.Uplist(font=None, dirn=ufodir, filen="fontinfo.plist")
            except Exception as e:
                logger.log("Unable to open fontinfo.plist in " + ufodir + "; values will not be restored", "E")
                origfontinfo = None

            if origfontinfo is not None:
                for key in inforestorekeys:
                    if key in origfontinfo:
                        new = origfontinfo.getval(key)
                        if key in integerkeys: new = int(new)
                        current = None if not hasattr(ufo.info, key) else  getattr(ufo.info, key)
                        if current == new:
                            continue
                        else:
                            setattr(ufo.info, key, new)
                            logchange(logger, " restored from backup ufo. ", key, current, new)

            # Delete unneeded keys
            for key in infodeletekeys:
                if hasattr(ufo.info, key):
                    current = getattr(ufo.info, key)
                    setattr(ufo.info, key, None)
                    logchange(logger, " deleted. ", key, current, None)

            for key in infodeleteempty:
                if hasattr(ufo.info, key) and getattr(ufo.info, key) == "":
                    setattr(ufo.info, key, None)
                    logchange(logger, " empty field deleted. ", key, current, None)
        # Write ufo out
        logger.log("Writing out " + fontname, "P")
        glyphsLib.write_ufo(ufo, args.masterdir)