Exemple #1
0
def run(args):
	options = Options(args)

	# Set the current dir to the design space dir, so that relative paths in
	# the design space file will work.
	dsDir,dsFile = os.path.split(os.path.abspath(options.dsPath))
	os.chdir(dsDir)
	options.dsPath = dsFile
	
	dsPath, newInstancesList = readDesignSpaceFile(options)
	if not dsPath:
		return


	version = 2
	if len(newInstancesList) == 1:
		logMsg.log( "Building 1 instance..")
	else:
		logMsg.log("Building %s instances.." % (len(newInstancesList)))
	mutatorMathBuild(documentPath=dsPath, outputUFOFormatVersion=version, roundGeometry=(not options.allowDecimalCoords))
	if (dsPath != options.dsPath) and os.path.exists(dsPath):
		os.remove(dsPath)

	logMsg.log("Built %s instances.." % (len(newInstancesList)))
	if options.doAutoHint or options.doOverlapRemoval:
		logMsg.log( "Applying post-processing")
		# Apply autohint and checkoutlines, if requested.
		for instancePath in newInstancesList:
			# make new instance font.
			updateInstance(options, instancePath)

	if not options.doOverlapRemoval: # checkOutlinesUFO does ufoTools.validateLayers()
		for instancePath in newInstancesList:
			# make sure that that there are no old glyphs left in the processed glyphs folder.
			ufoTools.validateLayers(instancePath)
    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
Exemple #3
0
def run(args):
    options = Options(args)

    # Set the current dir to the design space dir, so that relative paths in
    # the design space file will work.
    dsDir, dsFile = os.path.split(os.path.abspath(options.dsPath))
    os.chdir(dsDir)
    options.dsPath = dsFile

    dsPath, newInstancesList = readDesignSpaceFile(options)
    if not dsPath:
        return

    version = 2
    if len(newInstancesList) == 1:
        logMsg.log("Building 1 instance...")
    else:
        logMsg.log("Building %s instances..." % (len(newInstancesList)))
    mutatorMathBuild(documentPath=dsPath,
                     outputUFOFormatVersion=version,
                     roundGeometry=(not options.allowDecimalCoords))
    if (dsPath != options.dsPath) and os.path.exists(dsPath):
        os.remove(dsPath)

    logMsg.log("Built %s instances." % (len(newInstancesList)))
    # Remove glyph.lib and font.lib (except for "public.glyphOrder")
    for instancePath in newInstancesList:
        postProcessInstance(instancePath, options)

    if options.doNormalize and haveUfONormalizer:
        logMsg.log("Applying UFO normalization...")
        for instancePath in newInstancesList:
            ufonormalizer.normalizeUFO(instancePath,
                                       outputPath=None,
                                       onlyModified=True,
                                       writeModTimes=False)

    if options.doAutoHint or options.doOverlapRemoval:
        logMsg.log("Applying post-processing...")
        # Apply autohint and checkoutlines, if requested.
        for instancePath in newInstancesList:
            # make new instance font.
            updateInstance(options, instancePath)

    if not options.doOverlapRemoval:  # checkOutlinesUFO does ufoTools.validateLayers()
        for instancePath in newInstancesList:
            # make sure that that there are no old glyphs left in the processed glyphs folder.
            ufoTools.validateLayers(instancePath)

    if options.doOverlapRemoval or options.doAutoHint:  # The defcon library renames glyphs. Need to fix them again.
        for instancePath in newInstancesList:
            if haveUfONormalizer and options.doNormalize:
                ufonormalizer.normalizeUFO(instancePath,
                                           outputPath=None,
                                           onlyModified=False,
                                           writeModTimes=False)
    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"
Exemple #5
0
def run(args):
	options = Options(args)

	# Set the current dir to the design space dir, so that relative paths in
	# the design space file will work.
	dsDir,dsFile = os.path.split(os.path.abspath(options.dsPath))
	os.chdir(dsDir)
	options.dsPath = dsFile

	dsPath, newInstancesList = readDesignSpaceFile(options)
	if not dsPath:
		return

	version = 2
	if len(newInstancesList) == 1:
		logMsg.log("Building 1 instance...")
	else:
		logMsg.log("Building %s instances..." % (len(newInstancesList)))
	mutatorMathBuild(documentPath=dsPath, outputUFOFormatVersion=version, roundGeometry=(not options.allowDecimalCoords))
	if (dsPath != options.dsPath) and os.path.exists(dsPath):
		os.remove(dsPath)

	logMsg.log("Built %s instances." % (len(newInstancesList)))

	# Remove glyph.lib and font.lib (except for "public.glyphOrder")
	for instancePath in newInstancesList:
		clearCustomLibs(instancePath)

	if options.doNormalize:
		logMsg.log("Applying UFO normalization...")
		for instancePath in newInstancesList:
			if haveUfONormalizer:
				ufonormalizerLib.normalizeUFO(instancePath, outputPath=None, onlyModified=True)

	if options.doAutoHint or options.doOverlapRemoval:
		logMsg.log("Applying post-processing...")
		# Apply autohint and checkoutlines, if requested.
		for instancePath in newInstancesList:
			# make new instance font.
			updateInstance(options, instancePath)

	if not options.doOverlapRemoval: # checkOutlinesUFO does ufoTools.validateLayers()
		for instancePath in newInstancesList:
			# make sure that that there are no old glyphs left in the processed glyphs folder.
			ufoTools.validateLayers(instancePath)

	if options.doOverlapRemoval or options.doAutoHint: # The defcon library renames glyphs. Need to fix them again.
		for instancePath in newInstancesList:
			if haveUfONormalizer and options.doNormalize:
				ufonormalizerLib.normalizeUFO(instancePath, outputPath=None, onlyModified=False)
	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"
Exemple #7
0
def run(args):
    options = Options(args)

    # Set the current dir to the design space dir, so that relative paths in
    # the design space file will work.
    dsDir, dsFile = os.path.split(os.path.abspath(options.dsPath))
    os.chdir(dsDir)
    options.dsPath = dsFile

    dsPath, newInstancesList = readDesignSpaceFile(options)
    if not dsPath:
        return

    version = 2
    if len(newInstancesList) == 1:
        logMsg.log("Building 1 instance..")
    else:
        logMsg.log("Building %s instances.." % (len(newInstancesList)))
    mutatorMathBuild(documentPath=dsPath,
                     outputUFOFormatVersion=version,
                     roundGeometry=(not options.allowDecimalCoords))
    if (dsPath != options.dsPath) and os.path.exists(dsPath):
        os.remove(dsPath)

    logMsg.log("Built %s instances.." % (len(newInstancesList)))
    if options.doAutoHint or options.doOverlapRemoval:
        logMsg.log("Applying post-processing")
        # Apply autohint and checkoutlines, if requested.
        for instancePath in newInstancesList:
            # make new instance font.
            updateInstance(options, instancePath)

    if not options.doOverlapRemoval:  # checkOutlinesUFO does ufoTools.validateLayers()
        for instancePath in newInstancesList:
            # make sure that that there are no old glyphs left in the processed glyphs folder.
            ufoTools.validateLayers(instancePath)
def run(args):
	
	options = getOptions()
	fontPath = os.path.abspath(options.filePath)
	dFont = None
	fontFile = FontFile(fontPath)
	dFont = fontFile.open(options.allowChanges) # We allow use of a hash map to skip glyphs only if fixing glyphs
	if options.clearHashMap:
		fontFile.clearHashMap()
		return
			
	if dFont == None:
		print "Could not open  file: %s." % (fontPath)
		return
			
	glyphCount = len(dFont)
	changed = 0
	glyphList = filterGlyphList(options, dFont.keys(), options.filePath)
	if not glyphList:
		raise focusFontError("Error: selected glyph list is empty for font <%s>." % options.filePath)

	if not options.writeToDefaultLayer:
		try:
			processedLayer = dFont.layers[kProcessedGlyphsLayerName]
		except KeyError:
			processedLayer = dFont.newLayer(kProcessedGlyphsLayerName)
	else:
		processedLayer = None
		fontFile.saveToDefaultLayer = 1
	fontChanged = 0
	lastHadMsg = 0
	seenGlyphCount = 0
	processedGlyphCount = 0
	glyphList.sort()
	for glyphName in glyphList:
		changed = 0
		seenGlyphCount +=1
		msg = []

		# fontFile.checkSkipGlyph updates the hash map for the glyph, so we call it even when
		# the  '-all' option is used.
		skip = fontFile.checkSkipGlyph(glyphName, options.checkAll)
		#Note: this will delete glyphs from the processed layer, if the glyph hash has changed.
		if skip:
			continue
		processedGlyphCount += 1

		dGlyph = dFont[glyphName]
		if dGlyph.components:
			dGlyph.decomposeAllComponents()
		newGlyph = booleanOperations.booleanGlyph.BooleanGlyph(dGlyph)
		glyphDigest = None
		for test in options.testList:
			if test != None:
				newGlyph, glyphDigest, changed, msg = test(newGlyph, glyphDigest, changed, msg, options)

		if len(msg) == 0:
			if lastHadMsg:
				print
			print ".",
			lastHadMsg = 0
		else:
			print os.linesep + glyphName, " ".join(msg),
			if changed and options.allowChanges:
				fontChanged = 1
			lastHadMsg = 1
		if changed and options.allowChanges:
			originalContours = list(dGlyph)
			fontFile.updateHashEntry(glyphName, changed)
			if options.writeToDefaultLayer:
				fixedGlyph = dGlyph
				fixedGlyph.clearContours()
			else:
				processedLayer.newGlyph(glyphName) # will replace any pre-existing glyph 
				fixedGlyph = processedLayer[glyphName]
				fixedGlyph.width = dGlyph.width
				fixedGlyph.height = dGlyph.height
				fixedGlyph.unicodes = dGlyph.unicodes
			pointPen = fixedGlyph.getPointPen()
			newGlyph.drawPoints(pointPen)
			if options.allowDecimalCoords:
				for contour in fixedGlyph:
					for point in contour:
						point.x = round(point.x, 3)
						point.y = round(point.y, 3)
			else:
				for contour in fixedGlyph:
					for point in contour:
						point.x = int(round(point.x))
						point.y = int(round(point.y))
			restoreContourOrder(fixedGlyph, originalContours)
		sys.stdout.flush() # Needed when the script is called from another script with Popen().
	# update layer plist: the hash check call may have deleted processed layer glyphs because the default layer glyph is newer.

	# At this point, we may have deleted glyphs  in the processed layer.writer.getGlyphSet()
	# will fail unless we update the contents.plist file to match.
	if options.allowChanges:
		ufoTools.validateLayers(fontPath, False)

	if not fontChanged:
		print
		fontFile.close() # Even if the program didn't change any glyphs, we should still save updates to the src glyph hash file.
	else:
		print
		fontFile.save()
		
	if processedGlyphCount != seenGlyphCount:
		print "Skipped %s of %s glyphs." % (seenGlyphCount - processedGlyphCount, seenGlyphCount)
	print "Done with font"
	return
def run(args):

    options = getOptions(args)
    fontPath = os.path.abspath(options.filePath)
    dFont = None
    fontFile = FontFile(fontPath)
    dFont = fontFile.open(
        options.allowChanges
    )  # We allow use of a hash map to skip glyphs only if fixing glyphs
    if options.clearHashMap:
        fontFile.clearHashMap()
        return

    if dFont == None:
        print "Could not open  file: %s." % (fontPath)
        return

    glyphCount = len(dFont)
    changed = 0
    glyphList = filterGlyphList(options, dFont.keys(), options.filePath)
    if not glyphList:
        raise focusFontError(
            "Error: selected glyph list is empty for font <%s>." %
            options.filePath)

    if not options.writeToDefaultLayer:
        try:
            processedLayer = dFont.layers[kProcessedGlyphsLayerName]
        except KeyError:
            processedLayer = dFont.newLayer(kProcessedGlyphsLayerName)
    else:
        processedLayer = None
        fontFile.saveToDefaultLayer = 1
    fontChanged = 0
    lastHadMsg = 0
    seenGlyphCount = 0
    processedGlyphCount = 0
    glyphList.sort()
    for glyphName in glyphList:
        changed = 0
        seenGlyphCount += 1
        msg = []

        # fontFile.checkSkipGlyph updates the hash map for the glyph, so we call it even when
        # the  '-all' option is used.
        skip = fontFile.checkSkipGlyph(glyphName, options.checkAll)
        #Note: this will delete glyphs from the processed layer, if the glyph hash has changed.
        if skip:
            continue
        processedGlyphCount += 1

        dGlyph = dFont[glyphName]
        if dGlyph.components:
            dGlyph.decomposeAllComponents()
        newGlyph = booleanOperations.booleanGlyph.BooleanGlyph(dGlyph)
        glyphDigest = None
        for test in options.testList:
            if test != None:
                newGlyph, glyphDigest, changed, msg = test(
                    newGlyph, glyphDigest, changed, msg, options)

        if not options.quietMode:
            if len(msg) == 0:
                if lastHadMsg:
                    print
                print ".",
                lastHadMsg = 0
            else:
                print os.linesep + glyphName, " ".join(msg),
                lastHadMsg = 1
        if changed and options.allowChanges:
            fontChanged = 1
            originalContours = list(dGlyph)
            fontFile.updateHashEntry(glyphName, changed)
            if options.writeToDefaultLayer:
                fixedGlyph = dGlyph
                fixedGlyph.clearContours()
            else:
                processedLayer.newGlyph(
                    glyphName)  # will replace any pre-existing glyph
                fixedGlyph = processedLayer[glyphName]
                fixedGlyph.width = dGlyph.width
                fixedGlyph.height = dGlyph.height
                fixedGlyph.unicodes = dGlyph.unicodes
            pointPen = fixedGlyph.getPointPen()
            newGlyph.drawPoints(pointPen)
            if options.allowDecimalCoords:
                for contour in fixedGlyph:
                    for point in contour:
                        point.x = round(point.x, 3)
                        point.y = round(point.y, 3)
            else:
                for contour in fixedGlyph:
                    for point in contour:
                        point.x = int(round(point.x))
                        point.y = int(round(point.y))
            restoreContourOrder(fixedGlyph, originalContours)
        sys.stdout.flush(
        )  # Needed when the script is called from another script with Popen().
    # update layer plist: the hash check call may have deleted processed layer glyphs because the default layer glyph is newer.

    # At this point, we may have deleted glyphs  in the processed layer.writer.getGlyphSet()
    # will fail unless we update the contents.plist file to match.
    if options.allowChanges:
        ufoTools.validateLayers(fontPath, False)

    if not fontChanged:
        print
        fontFile.close(
        )  # Even if the program didn't change any glyphs, we should still save updates to the src glyph hash file.
    else:
        print
        fontFile.save()

    if processedGlyphCount != seenGlyphCount:
        print "Skipped %s of %s glyphs." % (
            seenGlyphCount - processedGlyphCount, seenGlyphCount)
    print "Done with font"
    return
def run(args=None):
    options = get_options(args)
    font_path = os.path.abspath(options.file_path)
    font_file = FontFile(font_path)
    defcon_font = font_file.open(options.allow_changes)
    # We allow use of a hash map to skip glyphs only if fixing glyphs
    if options.clear_hash_map:
        font_file.clear_hash_map()
        return

    if defcon_font is None:
        print("Could not open  file: %s." % font_path)
        return

    if not options.glyph_list:
        glyph_list = list(defcon_font.keys())
    else:
        if not defcon_font.glyphOrder:
            raise FocusFontError(
                "Error: public.glyphOrder is empty or missing "
                "from lib.plist file of %s" %
                os.path.abspath(options.file_path))
        else:
            glyph_list = filter_glyph_list(options.glyph_list,
                                           defcon_font.glyphOrder,
                                           options.file_path)
    if not glyph_list:
        raise FocusFontError(
            "Error: selected glyph list is empty for font <%s>." %
            options.file_path)

    if not options.write_to_default_layer:
        try:
            processed_layer = defcon_font.layers[PROCD_GLYPHS_LAYER_NAME]
        except KeyError:
            processed_layer = defcon_font.newLayer(PROCD_GLYPHS_LAYER_NAME)
    else:
        processed_layer = None
        font_file.save_to_default_layer = True
    font_changed = False
    last_had_msg = False
    seen_glyph_count = 0
    processed_glyph_count = 0
    for glyph_name in sorted(glyph_list):
        changed = False
        seen_glyph_count += 1
        msg = []

        if glyph_name not in defcon_font:
            continue

        # font_file.check_skip_glyph updates the hash map for the glyph,
        # so we call it even when the  '-all' option is used.
        skip = font_file.check_skip_glyph(glyph_name, options.check_all)
        # Note: this will delete glyphs from the processed layer,
        #       if the glyph hash has changed.
        if skip:
            continue
        processed_glyph_count += 1

        defcon_glyph = defcon_font[glyph_name]
        if defcon_glyph.components:
            defcon_glyph.decomposeAllComponents()
        new_glyph = booleanOperations.booleanGlyph.BooleanGlyph(defcon_glyph)
        if len(new_glyph) == 0:
            # Complain about empty glyph only if it is not a space glyph.
            if not RE_SPACE_PATTERN.search(glyph_name):
                msg = ["has no contours"]
            else:
                msg = []
        else:
            for test in options.test_list:
                if test is not None:
                    new_glyph, changed, msg = \
                        test(new_glyph, changed, msg, options)

        if not options.quiet_mode:
            if len(msg) == 0:
                if last_had_msg:
                    print()
                print(".", end=' ')
                last_had_msg = False
            else:
                print(os.linesep + glyph_name, " ".join(msg), end=' ')
                last_had_msg = True
        if changed and options.allow_changes:
            font_changed = True
            original_contours = list(defcon_glyph)
            font_file.update_hash_entry(glyph_name, changed)
            if options.write_to_default_layer:
                fixed_glyph = defcon_glyph
                fixed_glyph.clearContours()
            else:
                # this will replace any pre-existing glyph:
                processed_layer.newGlyph(glyph_name)
                fixed_glyph = processed_layer[glyph_name]
                fixed_glyph.width = defcon_glyph.width
                fixed_glyph.height = defcon_glyph.height
                fixed_glyph.unicodes = defcon_glyph.unicodes
            point_pen = fixed_glyph.getPointPen()
            new_glyph.drawPoints(point_pen)
            if options.allow_decimal_coords:
                for contour in fixed_glyph:
                    for point in contour:
                        point.x = round(point.x, 3)
                        point.y = round(point.y, 3)
            else:
                for contour in fixed_glyph:
                    for point in contour:
                        point.x = int(round(point.x))
                        point.y = int(round(point.y))
            restore_contour_order(fixed_glyph, original_contours)
        # The following is needed when the script is called from another
        # script with Popen():
        sys.stdout.flush()
    # update layer plist: the hash check call may have deleted processed layer
    # glyphs because the default layer glyph is newer.

    # At this point, we may have deleted glyphs in the
    # processed layer.writer.getGlyphSet()
    # will fail unless we update the contents.plist file to match.
    if options.allow_changes:
        ufoTools.validateLayers(font_path, False)

    if not font_changed:
        # Even if the program didn't change any glyphs,
        # we should still save updates to the src glyph hash file.
        print()
        font_file.close()
    else:
        print()
        font_file.save()

    if processed_glyph_count != seen_glyph_count:
        print("Skipped %s of %s glyphs." %
              (seen_glyph_count - processed_glyph_count, seen_glyph_count))
    print("Done with font")
    return