1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
|
#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()
|