def test_setStartPoint(self): font = Font(getTestFontPath()) contour = font["B"][0] start = [(point.segmentType, point.x, point.y) for point in contour] contour.setStartPoint(6) self.assertTrue(contour.dirty) contour.setStartPoint(6) end = [(point.segmentType, point.x, point.y) for point in contour] self.assertEqual(start, end) contour = font["A"][0] start = [(point.segmentType, point.x, point.y) for point in contour] contour.setStartPoint(2) contour.setStartPoint(2) end = [(point.segmentType, point.x, point.y) for point in contour] self.assertEqual(start, end) contour = font["B"][0] start = [(point.segmentType, point.x, point.y) for point in contour] contour.setStartPoint(3) contour.setStartPoint(9) end = [(point.segmentType, point.x, point.y) for point in contour] self.assertEqual(start, end)
def test_save_ufoz(self): path = getTestFontPath() tmpdir = tempfile.mkdtemp() dest = os.path.join(tmpdir, "TestFont.ufoz") font = Font(path) try: self.assertFalse(os.path.exists(dest)) self.assertEqual(font.path, path) font.save(dest, structure="zip") self.assertTrue(os.path.exists(dest)) self.assertTrue(zipfile.is_zipfile(dest)) self.assertEqual(font.path, dest) self.assertEqual(font.ufoFileStructure, UFOFileStructure.ZIP) fileNames = sorted([ fs.path.basename(m.path) for m in UFOReader(dest).fs.glob("glyphs/*.glif") ]) self.assertEqual(fileNames, ["A_.glif", "B_.glif", "C_.glif"]) finally: font.close() shutil.rmtree(tmpdir)
def test_read(self): path = getTestFontPath() font = Font(path) fileNames = [ "com.typesupply.defcon.test.directory/file 1.txt", "com.typesupply.defcon.test.directory/sub directory/file 2.txt", "com.typesupply.defcon.test.file" ] for i, fileName in enumerate(sorted(font.data.fileNames)): if True in [j.startswith(".") for j in fileName.split(os.sep)]: continue self.assertEqual(fileName, fileNames[i]) self.assertEqual( font.data["com.typesupply.defcon.test.directory/file 1.txt"], b"This is file 1.") self.assertEqual( font.data[ "com.typesupply.defcon.test.directory/sub directory/file 2.txt"], b"This is file 2.") self.assertEqual(font.data["com.typesupply.defcon.test.file"], b"This is a top level test file.")
def test_testForExternalChanges_change_default_layer(self): for ufo in (u"TestExternalEditing.ufo", u"TestExternalEditing.ufoz"): path = getTestFontPath(ufo) path = makeTestFontCopy(path) fileSystem = openTestFontAsFileSystem(path) fs.copy.copy_dir(fileSystem, "glyphs", fileSystem, "glyphs.test") contents = [("foo", "glyphs"), ("test", "glyphs.test")] with fileSystem.open(u"layercontents.plist", "wb") as f: dump(contents, f) closeTestFontAsFileSystem(fileSystem, path) with Font(path) as font: fileSystem = openTestFontAsFileSystem(path) contents = [("foo", "glyphs.test"), ("test", "glyphs")] with fileSystem.open(u"layercontents.plist", "wb") as f: dump(contents, f) closeTestFontAsFileSystem(fileSystem, path) with UFOReader(path) as reader: self.assertEqual(font.layers.testForExternalChanges(reader), {"deleted": [], "added": [], "modified": {}, "defaultLayer": True, "order": False}) tearDownTestFontCopy(font.path)
def get_family_name(self): """Ensure that all source files have the same family name""" names = set() for fp in self.config["sources"]: if fp.endswith("glyphs"): src = glyphsLib.GSFont(fp) names.add(src.familyName) elif fp.endswith("ufo"): src = Font(fp) names.add(src.info.familyName) elif fp.endswith("designspace"): ds = designspaceLib.DesignSpaceDocument.fromfile( self.config["sources"][0]) names.add(ds.sources[0].familyName) else: raise ValueError(f"{fp} not a supported source file!") if len(names) > 1: raise ValueError( f"Inconsistent family names in sources {names}. Set familyName in config instead" ) return list(names)[0]
def test_delitem_glyph_not_dirty(self): for ufo in (u"TestExternalEditing.ufo", u"TestExternalEditing.ufoz"): path = getTestFontPath(ufo) path = makeTestFontCopy(path) font = Font(path) font["A"] # glyph = font["A"] fileSystem = openTestFontAsFileSystem(path) glyphPath = fs.path.join("glyphs", "A_.glif") fileSystem.remove(glyphPath) contentsPath = fs.path.join("glyphs", "contents.plist") with fileSystem.open(contentsPath, "rb") as f: plist = load(f) del plist["A"] with fileSystem.open(contentsPath, "wb") as f: dump(plist, f) closeTestFontAsFileSystem(fileSystem, path) r = font.testForExternalChanges() self.assertEqual(r["deletedGlyphs"], ["A"]) del font["A"] font.save() self.assertFalse(os.path.exists(glyphPath)) tearDownTestFontCopy(font.path)
def doTask(fonts): totalFonts = len(fonts) print "%d fonts found\n" % totalFonts i = 0 for font in fonts: i += 1 folderPath, fontFileName = os.path.split( os.path.realpath(font) ) # path to the folder where the font is contained and the font's file name styleName = os.path.basename( folderPath) # name of the folder where the font is contained # Change current directory to the folder where the font is contained os.chdir(folderPath) print '*******************************' print 'Kerning for %s...(%d/%d)' % (styleName, i, totalFonts) ufoFont = Font(fontFileName) WriteFeaturesKernFDK.KernDataClass(ufoFont, folderPath, minKern, writeTrimmed, writeSubtables)
def test_reloadGroups(self): path = getTestFontPath(u"TestExternalEditing.ufo") font = Font(path) groups = font.groups path = os.path.join(font.path, "groups.plist") f = open(path, "r") t = f.read() f.close() t = t.replace("<key>TestGroup</key>", "<key>XXX</key>") f = open(path, "w") f.write(t) f.close() self.assertEqual(list(groups.keys()), ["TestGroup"]) font.reloadGroups() self.assertEqual(list(groups.keys()), ["XXX"]) t = t.replace("<key>XXX</key>", "<key>TestGroup</key>") f = open(path, "w") f.write(t) f.close()
def test_reloadKerning(self): path = getTestFontPath(u"TestExternalEditing.ufo") font = Font(path) kerning = font.kerning path = os.path.join(font.path, "kerning.plist") f = open(path, "r") t = f.read() f.close() t = t.replace("<integer>-100</integer>", "<integer>-101</integer>") f = open(path, "w") f.write(t) f.close() self.assertEqual(list(kerning.items()), [(("A", "A"), -100)]) font.reloadKerning() self.assertEqual(list(kerning.items()), [(("A", "A"), -101)]) t = t.replace("<integer>-101</integer>", "<integer>-100</integer>") f = open(path, "w") f.write(t) f.close()
def test_bottomMargin_set(self): font = Font(getTestFontPath()) glyph = font["A"] glyph.bottomMargin = 100 self.assertEqual(glyph.bottomMargin, 100) self.assertEqual(glyph.height, 600) self.assertEqual(glyph.verticalOrigin, 500) self.assertTrue(glyph.dirty) # now glyph.verticalOrigin is defined glyph.bottomMargin = 50 self.assertEqual(glyph.bottomMargin, 50) self.assertEqual(glyph.height, 550) self.assertEqual(glyph.verticalOrigin, 500) self.assertTrue(glyph.dirty) # empty glyph glyph = font.newGlyph("D") glyph.dirty = False glyph.bottomMargin = 10 self.assertIsNone(glyph.bottomMargin) self.assertEqual(glyph.height, 0) self.assertIsNone(glyph.verticalOrigin) self.assertFalse(glyph.dirty)
def _determine_which_masters_to_generate(self, ds_path, master_list): """'ds_path' is the path to a designspace file. Returns a list of integers representing the indexes of the temp masters to generate. """ # Make a set of the glyphsets of all the masters while collecting each # glyphset. Glyph order is ignored. all_gsets = set() each_gset = [] for master in master_list: master_path = master.attrib['filename'] ufo_path = os.path.join(os.path.dirname(ds_path), master_path) gset = set(Font(ufo_path).keys()) all_gsets.update(gset) each_gset.append(gset) master_indexes = [] for i, gset in enumerate(each_gset): if gset != all_gsets: master_indexes.append(i) return master_indexes
def test_reloadInfo(self): path = getTestFontPath(u"TestExternalEditing.ufo") font = Font(path) info = font.info path = os.path.join(font.path, "fontinfo.plist") f = open(path, "r") t = f.read() f.close() t = t.replace("<integer>750</integer>", "<integer>751</integer>") f = open(path, "w") f.write(t) f.close() self.assertEqual(info.ascender, 750) font.reloadInfo() self.assertEqual(info.ascender, 751) t = t.replace("<integer>751</integer>", "<integer>750</integer>") f = open(path, "w") f.write(t) f.close()
def test_skip_empty_feature(self): ufo = Font() glyph = ufo.newGlyph('a') glyph.appendAnchor( glyph.anchorClass(anchorDict={ 'name': 'top', 'x': 100, 'y': 200 })) glyph = ufo.newGlyph('acutecomb') glyph.appendAnchor( glyph.anchorClass(anchorDict={ 'name': '_top', 'x': 100, 'y': 200 })) writer = MarkFeatureWriter(ufo) fea = writer.write() self.assertIn("feature mark", fea) self.assertNotIn("feature mkmk", fea)
def buildStatic( self, ufo, # input UFO as filename string or defcon.Font object outputFilename, # output filename string cff=True, # true = makes CFF outlines. false = makes TTF outlines. **kwargs, # passed along to ufo2ft.compile*() ): if isinstance(ufo, str): ufo = Font(ufo) # update version to actual, real version. Must come after any call to setFontInfo. updateFontVersion(ufo, dummy=False, isVF=False) # decompose some glyphs glyphNamesToDecompose = set() for g in ufo: directives = findGlyphDirectives(g.note) if 'decompose' in directives or (g.components and not composedGlyphIsTrivial(g)): glyphNamesToDecompose.add(g.name) self._decompose([ufo], glyphNamesToDecompose) compilerOptions = dict( useProductionNames=True, inplace=True, # avoid extra copy removeOverlaps=True, overlapsBackend='pathops', # use Skia's pathops ) log.info("compiling %s -> %s (%s)", _LazyFontName(ufo), outputFilename, "OTF/CFF-2" if cff else "TTF") if cff: font = ufo2ft.compileOTF(ufo, **compilerOptions) else: # ttf font = ufo2ft.compileTTF(ufo, **compilerOptions) log.debug("writing %s", outputFilename) font.save(outputFilename)
def test_clear(self): font = Font(getTestFontPath()) glyph = font["A"] contour = glyph[0] anchor = glyph.anchors[0] glyph.clear() self.assertEqual(len(glyph), 0) self.assertEqual(len(glyph.anchors), 0) glyph = font["C"] component = glyph.components[0] glyph.clear() self.assertEqual(len(glyph.components), 0) glyph = font.layers["Layer 1"]["A"] guideline = glyph.guidelines[0] glyph.clear() self.assertEqual(len(glyph.guidelines), 0) self.assertEqual((contour.getParent(), component.getParent(), anchor.getParent(), guideline.getParent()), (None, None, None, None)) self.assertEqual((contour.dispatcher, component.dispatcher, anchor.dispatcher, guideline.dispatcher), (None, None, None, None))
def test__cleanupMissingGlyphs(self): groups = { "public.kern1.A": ["A", "Aacute", "Abreve", "Acircumflex"], "public.kern2.B": ["B", "D", "E", "F"], } ufo = Font() for glyphs in groups.values(): for glyph in glyphs: ufo.newGlyph(glyph) ufo.groups.update(groups) del ufo["Abreve"] del ufo["D"] writer = KernFeatureWriter() writer.set_context(ufo) self.assertEquals(writer.context.groups, groups) writer._cleanupMissingGlyphs() self.assertEquals( writer.context.groups, { "public.kern1.A": ["A", "Aacute", "Acircumflex"], "public.kern2.B": ["B", "E", "F"] })
def test_add_classes(self): ufo = Font() glyph = ufo.newGlyph('grave') glyph.appendAnchor( glyph.anchorClass(anchorDict={ 'name': '_top', 'x': 100, 'y': 200 })) glyph = ufo.newGlyph('cedilla') glyph.appendAnchor( glyph.anchorClass(anchorDict={ 'name': '_bottom', 'x': 100, 'y': 0 })) lines = [] writer = PrebuiltMarkFeatureWriter(ufo) writer._addClasses(lines, doMark=True, doMkmk=True) self.assertEqual( '\n'.join(lines).strip(), 'markClass cedilla <anchor 100 0> @MC_bottom;\n\n' 'markClass grave <anchor 100 200> @MC_top;')
def test_only_write_one(self): ufo = Font() ufo.newGlyph('a').appendAnchor({'name': 'top', 'x': 100, 'y': 200}) ufo.newGlyph('acutecomb').appendAnchor({ 'name': '_top', 'x': 100, 'y': 200 }) glyph = ufo.newGlyph('tildecomb') glyph.appendAnchor({'name': '_top', 'x': 100, 'y': 200}) glyph.appendAnchor({'name': 'top', 'x': 100, 'y': 300}) writer = MarkFeatureWriter() # by default both mark + mkmk are built fea = writer.write(ufo) self.assertIn("feature mark", fea) self.assertIn("feature mkmk", fea) writer = MarkFeatureWriter(features=["mkmk"]) # only builds "mkmk" fea = writer.write(ufo) self.assertNotIn("feature mark", fea) self.assertIn("feature mkmk", fea)
def test_testForExternalChanges_change_default_layer(self): path = getTestFontPath("TestExternalEditing.ufo") path = makeTestFontCopy(path) shutil.copytree(os.path.join(path, "glyphs"), os.path.join(path, "glyphs.test")) contents = [("foo", "glyphs"), ("test", "glyphs.test")] with open(os.path.join(path, "layercontents.plist"), "wb") as f: dump(contents, f) font = Font(path) contents = [("test", "glyphs"), ("foo", "glyphs.test")] contents.reverse() with open(os.path.join(path, "layercontents.plist"), "wb") as f: dump(contents, f) reader = UFOReader(path) self.assertEqual( font.layers.testForExternalChanges(reader), { "deleted": [], "added": [], "modified": {}, "defaultLayer": True, "order": False }) tearDownTestFontCopy(font.path)
def doTask(fonts, startpath): totalFonts = len(fonts) print "%d fonts found\n" % totalFonts i = 0 for font in fonts: i += 1 folderPath, fontFileName = os.path.split(os.path.realpath(font)) styleName = os.path.basename(folderPath) # Change current directory to the folder where the font is contained os.chdir(folderPath) exportMessage = 'Exporting mark files for %s...(%d/%d)' % ( styleName, i, totalFonts) print '*' * len(exportMessage) print exportMessage ufoFont = Font(fontFileName) WriteFeaturesMarkFDK.MarkDataClass(ufoFont, folderPath, trimCasingTags, genMkmkFeature, writeClassesFile, indianScriptsFormat) # go back to the start os.chdir(startpath)
def test_decomposeComponent(self): font = Font() font.newGlyph("baseGlyph") baseGlyph = font["baseGlyph"] pointPen = baseGlyph.getPointPen() pointPen.beginPath(identifier="contour1") pointPen.addPoint((0, 0), "move", identifier="point1") pointPen.addPoint((0, 100), "line") pointPen.addPoint((100, 100), "line") pointPen.addPoint((100, 0), "line") pointPen.addPoint((0, 0), "line") pointPen.endPath() font.newGlyph("referenceGlyph") referenceGlyph = font["referenceGlyph"] pointPen = referenceGlyph.getPointPen() pointPen.addComponent("baseGlyph", (1, 0, 0, 1, 0, 0)) self.assertEqual(len(referenceGlyph.components), 1) self.assertEqual(len(referenceGlyph), 0) referenceGlyph.decomposeAllComponents() self.assertEqual(len(referenceGlyph.components), 0) self.assertEqual(len(referenceGlyph), 1) self.assertEqual(referenceGlyph[0].identifier, "contour1") self.assertEqual(referenceGlyph[0][0].identifier, "point1") pointPen.addComponent("baseGlyph", (1, 0, 0, 1, 100, 100)) self.assertEqual(len(referenceGlyph.components), 1) self.assertEqual(len(referenceGlyph), 1) component = referenceGlyph.components[0] referenceGlyph.decomposeComponent(component) self.assertEqual(len(referenceGlyph.components), 0) self.assertEqual(len(referenceGlyph), 2) self.assertEqual(referenceGlyph[0].identifier, "contour1") self.assertEqual(referenceGlyph[0][0].identifier, "point1") referenceGlyph[1].identifier referenceGlyph[1][0].identifier
def test_save_as(self): path = getTestFontPath() font = Font(path) saveAsPath = getTestFontCopyPath(path) font.save(saveAsPath) dataDirectory = os.path.join(saveAsPath, "data") self.assertTrue(os.path.exists(dataDirectory)) self.assertTrue( os.path.exists( os.path.join( dataDirectory, os.path.join("com.typesupply.defcon.test.directory", "file 1.txt")))) self.assertTrue( os.path.exists( os.path.join( dataDirectory, os.path.join("com.typesupply.defcon.test.directory", "sub directory", "file 2.txt")))) self.assertTrue( os.path.exists( os.path.join(dataDirectory, "com.typesupply.defcon.test.file"))) tearDownTestFontCopy(saveAsPath)
def test_topMargin_set(self): from defcon.test.testTools import getTestFontPath from defcon.objects.font import Font font = Font(getTestFontPath()) glyph = font["A"] glyph.topMargin = 100 self.assertEqual(glyph.topMargin, 100) self.assertEqual(glyph.height, 800) self.assertEqual(glyph.verticalOrigin, 800) self.assertTrue(glyph.dirty) # now glyph.verticalOrigin is defined glyph.topMargin = 50 self.assertEqual(glyph.topMargin, 50) self.assertEqual(glyph.height, 750) self.assertEqual(glyph.verticalOrigin, 750) self.assertTrue(glyph.dirty) # empty glyph glyph = font.newGlyph("D") glyph.dirty = False glyph.topMargin = 10 self.assertIsNone(glyph.topMargin) self.assertEqual(glyph.height, 0) self.assertIsNone(glyph.verticalOrigin) self.assertFalse(glyph.dirty)
def test_reloadGlyphs(self): path = getTestFontPath(u"TestExternalEditing.ufo") font = Font(path) glyph = font["A"] path = os.path.join(font.path, "glyphs", "A_.glif") f = open(path, "r") t = f.read() f.close() t = t.replace('<advance width="700"/>', '<advance width="701"/>') f = open(path, "w") f.write(t) f.close() self.assertEqual(glyph.width, 700) self.assertEqual(len(glyph), 2) font.reloadGlyphs(["A"]) self.assertEqual(glyph.width, 701) self.assertEqual(len(glyph), 2) t = t.replace('<advance width="701"/>', '<advance width="700"/>') f = open(path, "w") f.write(t) f.close()
def test_reloadLib(self): path = getTestFontPath(u"TestExternalEditing.ufo") font = Font(path) lib = font.lib path = os.path.join(font.path, "lib.plist") f = open(path, "r") t = f.read() f.close() t = t.replace("<key>org.robofab.glyphOrder</key>", "<key>org.robofab.glyphOrder.XXX</key>") f = open(path, "w") f.write(t) f.close() self.assertEqual(list(lib.keys()), ["org.robofab.glyphOrder"]) font.reloadLib() self.assertEqual(list(lib.keys()), ["org.robofab.glyphOrder.XXX"]) t = t.replace("<key>org.robofab.glyphOrder.XXX</key>", "<key>org.robofab.glyphOrder</key>") f = open(path, "w") f.write(t) f.close()
def doTask(fonts): totalFonts = len(fonts) print "%d fonts found\n" % totalFonts i = 0 for font in fonts: i += 1 folderPath, fontFileName = os.path.split( os.path.realpath(font) ) # path to the folder where the font is contained and the font's file name styleName = os.path.basename( folderPath) # name of the folder where the font is contained # Change current directory to the folder where the font is contained os.chdir(folderPath) print '*******************************' print 'Exporting mark files for %s...(%d/%d)' % (styleName, i, totalFonts) ufoFont = Font(fontFileName) WriteFeaturesMarkFDK.MarkDataClass(ufoFont, folderPath, trimCasingTags, genMkmkFeature, writeClassesFile, indianScriptsFormat)
def test_beginSelfLayerSetNotificationObservation(self): font = Font() self.assertTrue(font.dispatcher.hasObserver( font, "LayerSet.Changed", font.layers)) self.assertTrue(font.dispatcher.hasObserver( font, "LayerSet.LayerAdded", font.layers)) self.assertTrue(font.dispatcher.hasObserver( font, "LayerSet.LayerWillBeDeleted", font.layers)) font.layers.removeObserver( observer=self, notification="LayerSet.Changed") font.layers.removeObserver( observer=self, notification="LayerSet.LayerAdded") font.layers.removeObserver( observer=self, notification="LayerSet.LayerWillBeDeleted") font.layers.endSelfNotificationObservation() font.beginSelfLayerSetNotificationObservation() self.assertTrue(font.dispatcher.hasObserver( font, "LayerSet.Changed", font.layers)) self.assertTrue(font.dispatcher.hasObserver( font, "LayerSet.LayerAdded", font.layers)) self.assertTrue(font.dispatcher.hasObserver( font, "LayerSet.LayerWillBeDeleted", font.layers))
def main(): argparser = ArgumentParser( description= 'Generate info on name, unicodes and color mark for all glyphs') argparser.add_argument( '-ucd', dest='ucdFile', metavar='<file>', type=str, help='UnicodeData.txt file from http://www.unicode.org/') argparser.add_argument('fontPaths', metavar='<ufofile>', type=str, nargs='+', help='UFO fonts to update') args = argparser.parse_args() fontPaths = [] for fontPath in args.fontPaths: fontPath = fontPath.rstrip('/ ') if 'regular' or 'Regular' in fontPath: fontPaths = [fontPath] + fontPaths else: fontPaths.append(fontPath) fonts = [Font(fontPath) for fontPath in args.fontPaths] ucd = {} if args.ucdFile: ucd = parseUnicodeDataFile(args.ucdFile) glyphs = [] # contains final glyph data printed as JSON visitedGlyphNames = set() for font in fonts: glyphorder = font.lib['public.glyphOrder'] for name in glyphorder: if name in visitedGlyphNames: continue if name not in font: print( "warning: %r in public.glyphOrder but doesn't exist in font" % name, file=sys.stderr) continue g = font[name] # color color = None if 'public.markColor' in g.lib: rgba = [ float(c.strip()) for c in g.lib['public.markColor'].strip().split(',') ] color = rgbaToCSSColor(*rgba) # mtime mtime = None if 'com.schriftgestaltung.Glyphs.lastChange' in g.lib: datetimestr = g.lib['com.schriftgestaltung.Glyphs.lastChange'] mtime = localDateTimeToUTCStr(datetimestr) # name[, unicode[, unicodeName[, color]]] glyph = None ucs = g.unicodes if len(ucs): for uc in ucs: ucName = unicodeName(ucd.get(uc)) if not ucName and uc >= 0xE000 and uc <= 0xF8FF: ucName = '[private use %04X]' % uc if color: glyph = [name, uc, ucName, mtime, color] elif mtime: glyph = [name, uc, ucName, mtime] elif ucName: glyph = [name, uc, ucName] else: glyph = [name, uc] else: if color: glyph = [name, None, None, mtime, color] elif mtime: glyph = [name, None, None, mtime] else: glyph = [name] glyphs.append(glyph) visitedGlyphNames.add(name) print('{"glyphs":[') prefix = ' ' for g in glyphs: print(prefix + json.dumps(g)) if prefix == ' ': prefix = ', ' print(']}')
def getTestUFO(): dirname = os.path.dirname(__file__) return Font(os.path.join(dirname, 'data', 'TestFont.ufo'))
def setUp(self): self.ufo = Font()