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
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 }]
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
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
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
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()
def test_default_master_roundtrips(): """This test comes from a common scenario while using glyphsLib to go back and forth several times with "minimize diffs" in both directions. In the end we get UFOs that have information as below, and there was a bug that turned "Regular" into "Normal" and changed the default axis value. """ thin = defcon.Font() thin.info.familyName = "CustomFont" thin.info.styleName = "Thin" thin.lib["com.schriftgestaltung.customParameter.GSFont.Axes"] = [ {"Name": "Weight", "Tag": "wght"} ] regular = defcon.Font() regular.info.familyName = "CustomFont" regular.info.styleName = "Regular" regular.lib["com.schriftgestaltung.customParameter.GSFont.Axes"] = [ {"Name": "Weight", "Tag": "wght"} ] ds = designspaceLib.DesignSpaceDocument() weight = ds.newAxisDescriptor() weight.tag = "wght" weight.name = "Weight" weight.minimum = 300 weight.maximum = 700 weight.default = 400 weight.map = [(300, 58), (400, 85), (700, 145)] ds.addAxis(weight) thinSource = ds.newSourceDescriptor() thinSource.font = thin thinSource.location = {"Weight": 58} thinSource.familyName = "CustomFont" thinSource.styleName = "Thin" ds.addSource(thinSource) regularSource = ds.newSourceDescriptor() regularSource.font = regular regularSource.location = {"Weight": 85} regularSource.familyName = "CustomFont" regularSource.styleName = "Regular" regularSource.copyFeatures = True regularSource.copyGroups = True regularSource.copyInfo = True regularSource.copyLib = True ds.addSource(regularSource) font = to_glyphs(ds, minimize_ufo_diffs=True) doc = to_designspace(font, minimize_glyphs_diffs=True) reg = doc.sources[1] assert reg.styleName == "Regular" assert reg.font.info.styleName == "Regular" assert reg.copyFeatures is True assert reg.copyGroups is True assert reg.copyInfo is True assert reg.copyLib is True
def 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
def test_masters_have_user_locations(): """Test the new axis definition with custom parameters. See https://github.com/googlei18n/glyphsLib/issues/280. For tests about the previous system with weight/width/custom, see `tests/builder/interpolation_test.py`. """ # Get a font with two masters font = to_glyphs([defcon.Font(), defcon.Font()]) font.customParameters['Axes'] = [{ 'Tag': 'opsz', 'Name': 'Optical', }] # There is only one axis, so the design location is stored in the weight font.masters[0].weightValue = 0 # The user location is stored as a custom parameter font.masters[0].customParameters['Axis Location'] = [{ 'Axis': 'Optical', 'Location': 13, }] font.masters[1].weightValue = 1000 font.masters[1].customParameters['Axis Location'] = [{ 'Axis': 'Optical', 'Location': 100, }] doc = to_designspace(font) assert len(doc.axes) == 1 assert doc.axes[0].map == [ (13, 0), (100, 1000), ] assert len(doc.sources) == 2 assert doc.sources[0].location == {'Optical': 0} assert doc.sources[1].location == {'Optical': 1000} font = to_glyphs(doc) assert font.customParameters['Axes'] == [{ 'Tag': 'opsz', 'Name': 'Optical', }] assert font.masters[0].weightValue == 0 assert font.masters[0].customParameters['Axis Location'] == [{ 'Axis': 'Optical', 'Location': 13, }] assert font.masters[1].weightValue == 1000 assert font.masters[1].customParameters['Axis Location'] == [{ 'Axis': 'Optical', 'Location': 100, }]
def 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
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"
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_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])
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))
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
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
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)
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
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()
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)
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"
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")
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)
def test_only_background(): ufo = defcon.Font() background = ufo.newLayer("public.background") background.newGlyph("a") # Check that it does not crash to_glyphs([ufo])
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)
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)