inter/misc/glyphs-scripts/preflight.py
2019-03-30 17:03:54 -07:00

183 lines
4.8 KiB
Python

#MenuTitle: Preflight
# -*- coding: utf-8 -*-
__doc__="""
Checks for bad paths and anchors
"""
import AppKit
Glyphs.clearLog()
Glyphs.showMacroWindow()
mainRunLoop = AppKit.NSRunLoop.mainRunLoop()
_lowerCaseGlyphNames = None
def getLowerCaseGlyphNames():
global _lowerCaseGlyphNames
if _lowerCaseGlyphNames is None:
# TODO: split with regexp to allow more than one space as a separator
_lowerCaseGlyphNames = set(font.classes['Lowercase'].code.strip().split(' '))
return _lowerCaseGlyphNames
def yieldAppMain():
mainRunLoop.runMode_beforeDate_(AppKit.NSRunLoopCommonModes, AppKit.NSDate.new())
def headline(titleString):
print("\n------ %s ------" % titleString.upper())
def log(glyphName, layerName, msg):
if layerName != "":
print("[glyph] %s \t Layer %s: %s." % ( glyphName, layerName, msg ))
elif glyphName != "":
print("[glyph] %s \t - \t %s." % ( glyphName, msg ))
else:
print("[info] %s." % ( msg ))
def masterLayersIterator(font):
for g in font.glyphs:
for master in font.masters:
yield g.layers[master.id], g
yieldAppMain()
def checkForOpenPaths(font):
headline("Checking for open paths")
ok = True
for layer, g in masterLayersIterator(font):
openPathsFound = 0
for path in layer.paths:
if not path.closed:
openPathsFound += 1
if openPathsFound > 0:
ok = False
log(g.name, layer.name, "%d open path(s) found" % openPathsFound)
if ok:
print("OK")
def checkForPathDirections(font):
headline("Checking for path directions")
ok = True
for layer, g in masterLayersIterator(font):
firstPath = layer.paths[0]
if firstPath and firstPath.direction != -1:
ok = False
if len(layer.paths) > 1:
msg = "Bad path order or direction."
else:
msg = "Bad path direction."
log(g.name, layer.name, msg)
if ok:
print("OK")
def checkForPointsOutOfBounds(font):
headline("Checking for nodes out of bounds")
ok = True
for layer, g in masterLayersIterator(font):
nodesOutOfBounds = 0
anchorsOutOfBounds = []
for path in layer.paths:
for n in path.nodes:
if abs(n.x) > 32766 or abs(n.y) > 32766:
nodesOutOfBounds += 1
for a in layer.anchors:
if abs(a.x) > 32766 or abs(a.y) > 32766:
anchorsOutOfBounds.append(a.name)
if nodesOutOfBounds:
ok = False
log(g.name, layer.name, "%d node(s) out of bounds" % nodesOutOfBounds)
if anchorsOutOfBounds:
ok = False
log(g.name, layer.name, "%d anchor(s) out of bounds (%r)" % (
len(anchorsOutOfBounds),
anchorsOutOfBounds
))
if ok:
print("OK")
def checkUnicode(font):
headline("Checking Unicodes")
ok = True
listOfUnicodes = [ (g.name, g.unicode) for g in font.glyphs if g.unicode != None ]
numberOfGlyphs = len(listOfUnicodes)
# glyphsWithoutUnicodes = [ g.name for g in allGlyphs if g.unicode == None ]
# for gName in glyphsWithoutUnicodes:
# log( gName, "", "Warning: No Unicode value set" )
for i in range(numberOfGlyphs - 1):
firstGlyph = listOfUnicodes[i]
for j in range(i+1, numberOfGlyphs):
secondGlyph = listOfUnicodes[j]
if firstGlyph[1] == secondGlyph[1]:
ok = False
log(
"%s & %s" % (firstGlyph[0], secondGlyph[0]),
"-",
"Both glyphs carry same Unicode value %s" % (firstGlyph[1])
)
if ok:
print("OK")
def checkVerticalMetrics(font):
headline("Checking vertical metrics")
ascender = 0
descender = 0
capHeight = 0
lowerCase = getLowerCaseGlyphNames()
ok = True
for master in font.masters:
if ascender == 0:
ascender = master.ascender
elif ascender != master.ascender:
print('ascender varies with masters; vertical metrics must be same in all masters')
ok = False
if capHeight == 0:
capHeight = master.capHeight
elif capHeight != master.capHeight:
print('capHeight varies with masters; vertical metrics must be same in all masters')
ok = False
if descender == 0:
descender = master.descender
elif descender != master.descender:
print('descender varies with masters; vertical metrics must be same in all masters')
ok = False
for master in font.masters:
for glyph in font.glyphs:
if not glyph.export or glyph.name not in lowerCase:
continue
layer = glyph.layers[master.id]
# get ymin of current layer
ymin = layer.bounds.origin.y
if ymin < descender:
ok = False
log(glyph.name, layer.name,
'Warning: lower than descender (ymin=%r, descender=%r)' % (
ymin, descender))
if ok:
print("OK")
font = Glyphs.font
font.disableUpdateInterface()
try:
checkForOpenPaths(font)
checkForPathDirections(font)
checkForPointsOutOfBounds(font)
checkUnicode(font)
checkVerticalMetrics(font)
finally:
font.enableUpdateInterface()