def _valid_designspace(self, designspace):
        """Make sure that the user-provided designspace has loaded fonts and
        that names are the same as those from the UFOs.
        """
        # TODO: (jany) really make a copy to avoid modifying the original object
        copy = designspace
        for source in copy.sources:
            if not hasattr(source, 'font') or source.font is None:
                if source.path:
                    # FIXME: (jany) consider not changing the caller's objects
                    source.font = defcon.Font(source.path)
                else:
                    dirname = os.path.dirname(designspace.path)
                    ufo_path = os.path.join(dirname, source.filename)
                    source.font = defcon.Font(ufo_path)
            if source.location is None:
                source.location = {}
            for name in ('familyName', 'styleName'):
                if getattr(source, name) != getattr(source.font.info, name):
                    self.logger.warning(
                        dedent('''\
                        The {name} is different between the UFO and the designspace source:
                            source filename: {filename}
                            source {name}: {source_name}
                            ufo {name}: {ufo_name}

                        The UFO name will be used.
                    ''').format(name=name,
                                filename=source.filename,
                                source_name=getattr(source, name),
                                ufo_name=getattr(source.font.info, name)))
                    setattr(source, name, getattr(source.font.info, name))
        return copy
Esempio n. 2
0
def test_masters_have_user_locations_string():
    """Test that stringified Axis Locations are converted.

    Some versions of Glyph store a string instead of an int.
    """
    font = to_glyphs([defcon.Font(), defcon.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)
    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. 3
0
def test_mapping_is_same_regardless_of_axes_custom_parameter():
    # https://github.com/googlefonts/glyphsLib/issues/409
    # https://github.com/googlefonts/glyphsLib/issues/411

    # First, try without the custom param
    font = to_glyphs([defcon.Font(), defcon.Font(), defcon.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)
    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)
    assert doc.axes[0].minimum == 200
    assert doc.axes[0].maximum == 700
    assert doc.axes[0].map == []
def test_designspace_source_locations(tmpdir):
    """Check that opening UFOs from their source descriptor works with both
    the filename and the path attributes.
    """
    designspace_path = os.path.join(str(tmpdir), 'test.designspace')
    light_ufo_path = os.path.join(str(tmpdir), 'light.ufo')
    bold_ufo_path = os.path.join(str(tmpdir), 'bold.ufo')

    designspace = DesignSpaceDocument()
    light_source = designspace.newSourceDescriptor()
    light_source.filename = 'light.ufo'
    designspace.addSource(light_source)
    bold_source = designspace.newSourceDescriptor()
    bold_source.path = bold_ufo_path
    designspace.addSource(bold_source)
    designspace.write(designspace_path)

    light = defcon.Font()
    light.info.ascender = 30
    light.save(light_ufo_path)

    bold = defcon.Font()
    bold.info.ascender = 40
    bold.save(bold_ufo_path)

    designspace = DesignSpaceDocument()
    designspace.read(designspace_path)

    font = to_glyphs(designspace)

    assert len(font.masters) == 2
    assert font.masters[0].ascender == 30
    assert font.masters[1].ascender == 40
Esempio n. 5
0
    def merge(self, sources, info_params=None, features_path=None):
        new_font = defcon.Font()

        for path in sources:
            source = defcon.Font(os.path.join(self.params.cwd, path))
            if new_font.info.familyName is None:
                new_font.info.__dict__ = source.info.__dict__
            for layer in source.layers:
                if not layer.name in new_font.layers:
                    new_font.newLayer(layer.name)

                for glyph in layer:
                    new_font.layers[layer.name].insertGlyph(glyph)

            new_font.kerning.update(source.kerning)
            new_font.groups.update(source.groups)

        if features_path is not None:
            try:
                with io.open(os.path.join(self.params.cwd,
                                          features_path)) as features:
                    new_font.features.text = features.read()
            except IOError:
                logger.error("File error")
            except RuntimeError as e:
                logger.error("Unknown error", e)

        if info_params is not None:
            new_font = self.set_info_params(new_font, info_params)

        return new_font
Esempio n. 6
0
    def open(self, use_hash_map):
        font_path = self.font_path

        if self.font_format == 'UFO':
            self.font_type = UFO_FONT_TYPE
            ufotools.validateLayers(font_path)
            self.defcon_font = defcon.Font(font_path)
            self.ufo_format = self.defcon_font.ufoFormatVersionTuple
            self.use_hash_map = use_hash_map
            self.ufo_font_hash_data = ufotools.UFOFontData(
                font_path,
                self.use_hash_map,
                programName=ufotools.kCheckOutlineName)
            self.ufo_font_hash_data.readHashMap()

        else:
            print("Converting to temp UFO font...")
            self.temp_ufo_path = temp_path = get_temp_dir_path('font.ufo')

            if not run_shell_command(['tx', '-ufo', font_path, temp_path]):
                raise FocusFontError('Failed to convert input font to UFO.')

            try:
                self.defcon_font = defcon.Font(temp_path)
            except UFOLibError:
                raise

            if self.font_format == 'OTF':
                self.font_type = OTF_FONT_TYPE
            elif self.font_format == 'CFF':
                self.font_type = CFF_FONT_TYPE
            else:
                self.font_type = TYPE1_FONT_TYPE

        return self.defcon_font
Esempio n. 7
0
    def render(self,
               indicesSlice=None,
               start=0,
               end=None,
               data=None,
               folder=None,
               fmt=None,
               log=True):
        if not data and self.data:
            try:
                with open(self.data, "r") as f:
                    data = json.loads(f.read())
            except FileNotFoundError:
                data = {}
        if end == None:
            end = self.length
        indices = list(range(start, end))

        if indicesSlice:
            indices = list(range(*indicesSlice.indices(self.length)))

        folder = folder if folder else self.folder
        fmt = fmt if fmt else self.fmt
        ufo_folder = folder + "/ufos"
        saving_to_font = fmt == "ufo"

        for layer in self.layers:
            # a ufo for this layer
            if saving_to_font:
                ufo_path = ufo_folder + "/" + self.name + "_" + layer + ".ufo"
                try:
                    fmt = defcon.Font(ufo_path)
                except:
                    fmt = defcon.Font()
                    fmt.save(ufo_path)
                fmt.info.familyName = self.name
                fmt.info.styleName = layer
                fmt.info.versionMajor = 1
                fmt.info.versionMinor = 0
                fmt.info.descender = 0
                fmt.info.unitsPerEm = 1000  # or self.dimensions[0] ?
                fmt.info.capHeight = self.dimensions[1]
                fmt.info.ascender = self.dimensions[1]
                fmt.info.xHeight = int(self.dimensions[1] / 2)
                fmt.save()

            for i in indices:
                frame = AnimationFrame(self, i)
                frame.data = data
                print(f"(render:layer:{layer})", frame)
                _folder = folder + "/" + layer
                frame.draw(saving=True,
                           saveTo=_folder,
                           fmt=fmt,
                           layers=[layer],
                           fill=self.fill)

            if isinstance(fmt, defcon.Font):
                fmt.save()
Esempio n. 8
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. 9
0
    def open(self, use_hash_map):
        font_path = self.font_path
        try:
            ufotools.validateLayers(font_path)
            self.defcon_font = defcon.Font(font_path)
            self.ufo_format = self.defcon_font.ufoFormatVersion
            if self.ufo_format < 2:
                self.ufo_format = 2
            self.font_type = UFO_FONT_TYPE
            self.use_hash_map = use_hash_map
            self.ufo_font_hash_data = ufotools.UFOFontData(
                font_path,
                self.use_hash_map,
                programName=ufotools.kCheckOutlineName)
            self.ufo_font_hash_data.readHashMap()

        except ufoLib.UFOLibError as e:
            if (not os.path.isdir(font_path)) \
                    and "metainfo.plist is missing" in e.message:
                # It was a file, but not a UFO font.
                # Try converting to UFO font, and try again.
                print("converting to temp UFO font...")
                self.temp_ufo_path = temp_path = font_path + ".temp.ufo"
                if os.path.exists(temp_path):
                    shutil.rmtree(temp_path)
                cmd = "tx -ufo \"%s\" \"%s\"" % (font_path, temp_path)
                subprocess.call(cmd,
                                shell=True,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.STDOUT)
                if os.path.exists(temp_path):
                    try:
                        self.defcon_font = defcon.Font(temp_path)
                    except ufoLib.UFOLibError:
                        return
                    # It must be a font file!
                    self.temp_ufo_path = temp_path
                    # figure out font type.
                    try:
                        ff = open(font_path, "rb")
                        data = ff.read(10)
                        ff.close()
                    except (IOError, OSError):
                        return
                    if data[:4] == "OTTO":  # it is an OTF font.
                        self.font_type = OPENTYPE_CFF_FONT_TYPE
                    elif (data[0] == '\1') and (data[1] == '\0'):  # CFF file
                        self.font_type = CFF_FONT_TYPE
                    elif "%" in data:
                        self.font_type = TYPE1_FONT_TYPE
                    else:
                        print('Font type is unknown: '
                              'will not be able to save changes')
            else:
                raise e
        return self.defcon_font
Esempio n. 10
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. 11
0
def DISABLED_test_check_glyphnames_max_length():
    """ Check that glyph names do not exceed max length. """
    from fontbakery.profiles.universal import com_google_fonts_check_glyphnames_max_length as check
    import defcon
    import ufo2ft

    # TTF
    test_font = defcon.Font(TEST_FILE("test.ufo"))
    test_ttf = ufo2ft.compileTTF(test_font)
    status, _ = list(check(test_ttf))[-1]
    assert status == PASS

    test_glyph = defcon.Glyph()
    test_glyph.unicode = 0x1234
    test_glyph.name = ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
    test_font.insertGlyph(test_glyph)

    test_ttf = ufo2ft.compileTTF(test_font, useProductionNames=False)
    status, _ = list(check(test_ttf))[-1]
    assert status == FAIL

    test_ttf = ufo2ft.compileTTF(test_font, useProductionNames=True)
    status, _ = list(check(test_ttf))[-1]
    assert status == PASS

    # Upgrade to post format 3.0 and roundtrip data to update TTF object.
    test_ttf["post"].formatType = 3.0
    test_file = io.BytesIO()
    test_ttf.save(test_file)
    test_ttf = TTFont(test_file)
    status, message = list(check(test_ttf))[-1]
    assert status == PASS
    assert "format 3.0" in message

    del test_font, test_ttf, test_file  # Prevent copypasta errors.

    # CFF
    test_font = defcon.Font(TEST_FILE("test.ufo"))
    test_otf = ufo2ft.compileOTF(test_font)
    status, _ = list(check(test_otf))[-1]
    assert status == PASS

    test_font.insertGlyph(test_glyph)

    test_otf = ufo2ft.compileOTF(test_font, useProductionNames=False)
    status, _ = list(check(test_otf))[-1]
    assert status == FAIL

    test_otf = ufo2ft.compileOTF(test_font, useProductionNames=True)
    status, _ = list(check(test_otf))[-1]
    assert status == PASS
Esempio n. 12
0
    def open(self, useHashMap):
        fontPath = self.fontPath
        try:
            ufoTools.validateLayers(fontPath)
            self.dFont = dFont = defcon.Font(fontPath)
            self.ufoFormat = dFont.ufoFormatVersion
            if self.ufoFormat < 2:
                self.ufoFormat = 2
            self.fontType = kUFOFontType
            self.useHashMap = useHashMap
            self.ufoFontHashData = ufoTools.UFOFontData(
                fontPath,
                self.useHashMap,
                programName=ufoTools.kCheckOutlineName)
            self.ufoFontHashData.readHashMap()

        except ufoLib.UFOLibError, e:
            if (not os.path.isdir(fontPath)
                ) and "metainfo.plist is missing" in e.message:
                # It was a file, but not a UFO font. try converting to UFO font, and try again.
                print "converting to temp UFO font..."
                self.tempUFOPath = tempPath = fontPath + ".temp.ufo"
                if os.path.exists(tempPath):
                    shutil.rmtree(tempPath)
                cmd = "tx -ufo \"%s\" \"%s\"" % (fontPath, tempPath)
                p = subprocess.Popen(cmd,
                                     shell=True,
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.STDOUT).stdout
                log = p.read()
                if os.path.exists(tempPath):
                    try:
                        self.dFont = dFont = defcon.Font(tempPath)
                    except ufoLib.UFOLibError, e:
                        return
                    # It must be a font file!
                    self.tempUFOPath = tempPath
                    # figure out font type.
                    try:
                        ff = file(fontPath, "rb")
                        data = ff.read(10)
                        ff.close()
                    except (IOError, OSError):
                        return
                    if data[:4] == "OTTO":  # it is an OTF font.
                        self.fontType = kOpenTypeCFFFontType
                    elif (data[0] == '\1') and (data[1] == '\0'):  # CFF file
                        self.fontType = kCFFFontType
                    elif "%" in data:
                        self.fontType = kType1FontType
                    else:
                        print "Font type is unknown: will not be able to save changes"
Esempio n. 13
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
Esempio n. 14
0
def test_designspace_generation_regular_different_family_names(tmpdir):
    ufo_Lt = defcon.Font()
    ufo_Lt.info.familyName = "CoolFoundry Examplary Serif Light"
    ufo_Lt.info.styleName = "Regular"
    ufo_Lt.info.openTypeOS2WeightClass = 300

    ufo_Rg = defcon.Font()
    ufo_Rg.info.familyName = "CoolFoundry Examplary Serif"
    ufo_Rg.info.styleName = "Regular"
    ufo_Rg.info.openTypeOS2WeightClass = 400

    # Different family names are not allowed
    # REVIEW: reasonable requirement?
    with pytest.raises(Exception):
        to_glyphs([ufo_Lt, ufo_Rg])
Esempio n. 15
0
def DISABLED_test_check_glyphnames_max_length():
    """ Check that glyph names do not exceed max length. """
    check = CheckTester(universal_profile,
                        "com.google.fonts/check/glyphnames_max_length")
    import defcon
    import ufo2ft

    # TTF
    test_font = defcon.Font(TEST_FILE("test.ufo"))
    ttFont = ufo2ft.compileTTF(test_font)
    assert_PASS(check(ttFont))

    test_glyph = defcon.Glyph()
    test_glyph.unicode = 0x1234
    test_glyph.name = ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
    test_font.insertGlyph(test_glyph)
    ttFont = ufo2ft.compileTTF(test_font, useProductionNames=False)
    assert_results_contain(check(ttFont), FAIL,
                           None)  # FIXME: This needs a message keyword

    ttFont = ufo2ft.compileTTF(test_font, useProductionNames=True)
    assert_PASS(check(ttFont))

    # Upgrade to post format 3.0 and roundtrip data to update TTF object.
    ttFont["post"].formatType = 3.0
    _file = io.BytesIO()
    _file.name = ttFont.reader.file.name
    ttFont.save(_file)
    ttFont = TTFont(_file)
    message = assert_PASS(check(ttFont))
    assert "format 3.0" in message

    del test_font, ttFont, _file  # Prevent copypasta errors.

    # CFF
    test_font = defcon.Font(TEST_FILE("test.ufo"))
    ttFont = ufo2ft.compileOTF(test_font)
    assert_PASS(check(ttFont))

    test_font.insertGlyph(test_glyph)
    ttFont = ufo2ft.compileOTF(test_font, useProductionNames=False)
    assert_results_contain(check(ttFont), FAIL,
                           None)  # FIXME: This needs a message keyword

    ttFont = ufo2ft.compileOTF(test_font, useProductionNames=True)
    assert_PASS(check(ttFont))
Esempio n. 16
0
def makeFamily(familyName):
    m1, m2 = defcon.Font(), defcon.Font()
    m1.info.familyName, m1.info.styleName = familyName, "Regular"
    m1.lib[GLYPHS_PREFIX + "weightValue"] = 400.0
    m2.info.familyName, m2.info.styleName = familyName, "Black"
    m2.lib[GLYPHS_PREFIX + "weightValue"] = 900.0
    instances = {
        "defaultFamilyName": familyName,
        "data": [
            {"name": "Regular", "interpolationWeight": 400.0},
            {"name": "Semibold", "interpolationWeight": 600.0},
            {"name": "Bold", "interpolationWeight": 700.0},
            {"name": "Black", "interpolationWeight": 900.0},
        ],
    }
    return [m1, m2], instances
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_only_background():
    ufo = defcon.Font()
    background = ufo.newLayer('public.background')
    a_bg = background.newGlyph('a')

    # Check that it does not crash
    font = to_glyphs([ufo])
def test_dont_copy_advance_to_the_background_unless_it_was_there(tmpdir):
    ufo = defcon.Font()
    bg = ufo.newLayer('public.background')

    fg_a = ufo.newGlyph('a')
    fg_a.width = 100
    bg_a = bg.newGlyph('a')

    fg_b = ufo.newGlyph('b')
    fg_b.width = 200
    bg_b = bg.newGlyph('b')
    bg_b.width = 300

    fg_c = ufo.newGlyph('c')
    fg_c.width = 400
    bg_c = bg.newGlyph('c')
    bg_c.width = 400

    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]:
        ufo, = to_ufos(font)

        assert ufo['a'].width == 100
        assert ufo.layers['public.background']['a'].width == 0
        assert ufo['b'].width == 200
        assert ufo.layers['public.background']['b'].width == 300
        assert ufo['c'].width == 400
        assert ufo.layers['public.background']['c'].width == 400
Esempio n. 20
0
def test_dont_copy_advance_to_the_background_unless_it_was_there(tmpdir):
    ufo = defcon.Font()
    bg = ufo.newLayer("public.background")

    fg_a = ufo.newGlyph("a")
    fg_a.width = 100
    bg.newGlyph("a")

    fg_b = ufo.newGlyph("b")
    fg_b.width = 200
    bg_b = bg.newGlyph("b")
    bg_b.width = 300

    fg_c = ufo.newGlyph("c")
    fg_c.width = 400
    bg_c = bg.newGlyph("c")
    bg_c.width = 400

    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]:
        ufo, = to_ufos(font)

        assert ufo["a"].width == 100
        assert ufo.layers["public.background"]["a"].width == 0
        assert ufo["b"].width == 200
        assert ufo.layers["public.background"]["b"].width == 300
        assert ufo["c"].width == 400
        assert ufo.layers["public.background"]["c"].width == 400
Esempio n. 21
0
 def test_no_width_class(self):
     ufo = defcon.Font()
     # no explicit widthClass set, instance name doesn't matter
     doc, data = makeInstanceDescriptor("Normal")
     set_width_class(ufo, doc, data)
     # the default OS/2 width class is set
     self.assertEqual(ufo.info.openTypeOS2WidthClass, 5)
Esempio n. 22
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
Esempio n. 23
0
def prepSparseMaster(dirToPrep):

    # for path in walk dirToPrep:
    for dirName, subdirList, fileList in os.walk(dirToPrep):
        for dir in subdirList:
            if ".ufo" in dir and "SubSource" in dir:
                sparseUfoPath = dirName + "/" + dir
                print(sparseUfoPath)

                # remove unneeded files
                try:
                    os.remove(sparseUfoPath + '/groups.plist')
                except FileNotFoundError:
                    pass
                try:
                    os.remove(sparseUfoPath + '/kerning.plist')
                except FileNotFoundError:
                    pass
                try:
                    os.remove(sparseUfoPath + '/features.fea')
                except FileNotFoundError:
                    pass

                # tag UFO as sparse master
                font = defcon.Font(sparseUfoPath)
                font.lib["com.github.googlei18n.ufo2ft.featureWriters"] = []
                font.save()
Esempio n. 24
0
    def test_width_class(self):
        ufo = defcon.Font()
        doc, data = makeInstanceDescriptor("Condensed",
                                           width=("Condensed", 3, 80))

        set_width_class(ufo, doc, data)
        self.assertEqual(ufo.info.openTypeOS2WidthClass, 3)
Esempio n. 25
0
    def test_single_input_no_output(self, test_paths):
        ufo_path = test_paths[0]

        self.run_main(ufo_path)

        font = defcon.Font(str(ufo_path))
        assert font.lib[CURVE_TYPE_LIB_KEY] == "quadratic"
Esempio n. 26
0
def test_groups_remain_at_top(tmpdir):
    ufo = defcon.Font()
    ufo.newGlyph("zero")
    ufo.newGlyph("zero.alt")
    fea_example = dedent(
        """\
        @FIG_DFLT = [zero];
        @FIG_ALT = [zero.alt];

        lookup pnum_text {
            sub @FIG_DFLT by @FIG_ALT;
        } pnum_text;

        feature pnum {
            lookup pnum_text;
        } pnum;
        """
    )
    ufo.features.text = fea_example

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

    fea_rt = rtufo.features.text
    assert fea_rt.index("@FIG_DFLT") < fea_rt.index("lookup") < fea_rt.index("feature")
Esempio n. 27
0
    def test_explicit_default_weight(self):
        ufo = defcon.Font()
        doc, data = makeInstanceDescriptor("Regular", weight=("Regular", None, 100))

        set_weight_class(ufo, doc, data)
        # the default OS/2 weight class is set
        self.assertEqual(ufo.info.openTypeOS2WeightClass, 400)
Esempio n. 28
0
def test_only_background():
    ufo = defcon.Font()
    background = ufo.newLayer("public.background")
    background.newGlyph("a")

    # Check that it does not crash
    to_glyphs([ufo])
Esempio n. 29
0
def main():

    glyph_set = SourceGlyphSet(
        script=mongolian,
        font=defcon.Font(source_ufo_path),
        implied_script_codes=[Common.code, mongolian.code],
        validate_glyph_availability=False,
    )

    builder = glyph_set.otl_code_builder()

    for name in mongolian.characters.keys():
        try:
            name = glyph_set[name]
        except GlyphNotInSourceFontError:
            continue
        builder.shaped_glyph_names.update([name])

    builder.build_with_writer(stateless.writer)

    # feaLib’s include() following somehow fails.
    inlined_otl_path = otl_dir / "stateless.fea"
    include_statement_pattern = re.compile(r"include\((.+)\);\n")
    with inlined_otl_path.open("w") as inlined_otl:
        with otl_path.open() as main_otl:
            for line in main_otl:
                if match := include_statement_pattern.fullmatch(line):
                    included_otl_path = otl_path.parent / match.group(1)
                    inlined_otl.write(included_otl_path.read_text())
                else:
                    inlined_otl.write(line)
Esempio n. 30
0
    def test_explicit_default_width(self):
        ufo = defcon.Font()
        doc, data = makeInstanceDescriptor("Regular", width=("Medium (normal)", 5, 100))

        set_width_class(ufo, doc, data)
        # the default OS/2 width class is set
        self.assertEqual(ufo.info.openTypeOS2WidthClass, 5)