Skip to content

Commit 5d48ef0

Browse files
committed
skip export glyphs before generating
1 parent 56af601 commit 5d48ef0

File tree

1 file changed

+92
-32
lines changed
  • source/lib/batchGenerators/variableFontsGenerator

1 file changed

+92
-32
lines changed

source/lib/batchGenerators/variableFontsGenerator/__init__.py

Lines changed: 92 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,17 @@ def build(self):
4040
self.generatedFiles = set()
4141

4242
self.operator.loadFonts(reload=True)
43-
44-
self.makeMasterGlyphsCompatible()
43+
self.applySkipExportGlyphs()
44+
self.makeSourceGlyphsCompatible()
4545
self.decomposedMixedGlyphs()
46-
self.makeMasterKerningCompatible()
47-
self.makeMasterOnDefaultLocation()
48-
self.makeLayerMaster()
46+
self.makeSourceKerningCompatible()
47+
self.makeSourceOnDefaultLocation()
48+
self.makeLayerSource()
49+
self.makeSourcesAtAxesExtremes()
4950
if self.binaryFormat == "ttf":
50-
self.makeMasterGlyphsQuadractic()
51+
self.makeSourceGlyphsQuadractic()
5152
elif self.binaryFormat == "otf":
52-
self.makeMasterExportOptimizeCharstring()
53+
self.makeSourceExportOptimizeCharstring()
5354

5455
self.generate()
5556

@@ -62,12 +63,71 @@ def build(self):
6263
else:
6364
os.remove(path)
6465

65-
def makeMasterGlyphsCompatible(self):
66+
def applySkipExportGlyphs(self):
67+
for font in self.operator.fonts:
68+
skipExportGlyphs = set(font.lib.get("public.skipExportGlyphs", []))
69+
if skipExportGlyphs:
70+
# Decompose the listed glyphs everywhere they are used as components.
71+
for glyph in font:
72+
for component in glyph.components:
73+
if component.baseGlyph in skipExportGlyphs:
74+
glyph.decomposeComponent(component)
75+
# Remove these glyphs before the compilation run.
76+
for glyphName in skipExportGlyphs:
77+
if glyphName in font:
78+
del font[glyphName]
79+
# Prune all groups of the listed glyphs.
80+
for key, value in list(font.groups.items()):
81+
font.groups[key] = [glyphName for glyphName in value if glyphName not in skipExportGlyphs]
82+
# Prune all kerning pairs that contain any of the listed glyphs.
83+
for side1, side2 in list(font.kerning.keys()):
84+
if side1 in skipExportGlyphs or side2 in skipExportGlyphs:
85+
del font.kerning[side1, side2]
86+
87+
def makeSourcesAtAxesExtremes(self):
88+
if self.fitToExtremes:
89+
self.report.writeTitle("Add sources at axes extremes", "'")
90+
extremeLocations = []
91+
for axis in self.operator.axes:
92+
location = dict()
93+
for otherAxis in self.operator.axes:
94+
if otherAxis == axis:
95+
continue
96+
location[otherAxis.name] = otherAxis.default
97+
98+
if hasattr(axis, "values"):
99+
for value in axis.values:
100+
extremeLocations.append(dict(**location, **{axis.name: value}))
101+
else:
102+
extremeLocations.append(dict(**location, **{axis.name: axis.minimum}))
103+
extremeLocations.append(dict(**location, **{axis.name: axis.maximum}))
104+
105+
sourceLocations = [sourceDescriptor.location for sourceDescriptor in self.operator.sources]
106+
for extremeLocation in extremeLocations:
107+
if extremeLocation not in sourceLocations:
108+
109+
self.report.indent()
110+
self.report.write("Adding source at location:")
111+
self.report.indent()
112+
self.report.writeDict(extremeLocation)
113+
self.report.dedent()
114+
font = self.operator.makeInstance(extremeLocation)
115+
self.operator.addSourceDescriptor(
116+
font=font,
117+
name=f"source.{len(self.operator.sources) + 1}",
118+
familyName=font.info.familyName,
119+
styleName=font.info.styleName,
120+
location=extremeLocation
121+
)
122+
self.report.dedent()
123+
self.report.newLine()
124+
125+
def makeSourceGlyphsCompatible(self):
66126
"""
67127
Update all sources with missing glyphs.
68128
All sources must have the same glyphs.
69129
"""
70-
self.report.writeTitle("Making master glyphs compatible", "'")
130+
self.report.writeTitle("Making source glyphs compatible", "'")
71131
self.report.indent()
72132
# collect all possible glyph names
73133
glyphNames = set()
@@ -77,7 +137,7 @@ def makeMasterGlyphsCompatible(self):
77137
defaultSource = self.operator.findDefaultFont()
78138
# loop over all glyphName
79139
for glyphName in glyphNames:
80-
# first check if the default master has this glyph
140+
# first check if the default source has this glyph
81141
if glyphName not in defaultSource:
82142
# the default does not have the glyph
83143
# build a repair glyph
@@ -89,15 +149,15 @@ def makeMasterGlyphsCompatible(self):
89149
roundGeometry=self.operator.roundGeometry,
90150
clip=False
91151
)
92-
self.report.write(f"Adding missing glyph '{glyphName}' in the default master '{defaultSource.info.familyName} {defaultSource.info.styleName}'")
93-
# add the glyph to the default master
152+
self.report.write(f"Adding missing glyph '{glyphName}' in the default source '{defaultSource.info.familyName} {defaultSource.info.styleName}'")
153+
# add the glyph to the default source
94154
glyph = defaultSource.newGlyph(glyphName)
95155
result.extractGlyph(glyph, onlyGeometry=True)
96156
glyph.unicodes = list(result.unicodes)
97157

98158
sourceGlyphs = []
99-
# fill all masters with missing glyphs
100-
# and collect all glyphs from all masters
159+
# fill all sources with missing glyphs
160+
# and collect all glyphs from all sources
101161
# to send them to optimize contour data
102162
for sourceDescriptor in self.operator.sources:
103163
sourceFont = self.operator.fonts[sourceDescriptor.name]
@@ -114,7 +174,7 @@ def makeMasterGlyphsCompatible(self):
114174
clip=False
115175
)
116176
self.report.write(f"Adding missing glyph '{glyphName}' in the source '{sourceFont.info.familyName} {sourceFont.info.styleName}'")
117-
# add the glyph to the master
177+
# add the glyph to the source
118178
glyph = sourceFont.newGlyph(glyphName)
119179
result.extractGlyph(glyph, onlyGeometry=True)
120180
glyph.unicodes = list(result.unicodes)
@@ -165,7 +225,7 @@ def makeGlyphOutlinesCompatible(self, glyphs):
165225
if types == pointTypes:
166226
continue
167227
# add missing off curves
168-
self.report.write(f"Adding missing offcurves in contour {contourIndex} for glyph '{glyph.name}' in master '{font.info.familyName} {font.info.styleName}'")
228+
self.report.write(f"Adding missing offcurves in contour {contourIndex} for glyph '{glyph.name}' in source '{font.info.familyName} {font.info.styleName}'")
169229
contour = glyph[contourIndex]
170230
pen = CompatibleContourPointPen(pointTypes)
171231
contour.drawPoints(pen)
@@ -185,7 +245,7 @@ def decomposedMixedGlyphs(self):
185245
if len(glyph) and len(glyph.components):
186246
# found, loop over all components and decompose
187247
for component in glyph.components:
188-
# get the master font
248+
# get the source font
189249
base = fontSource[component.baseGlyph]
190250
# get the decompose pen
191251
decomposePointPen = DecomposePointPen(glyph.layer, glyph.getPointPen(), component.transformation)
@@ -197,29 +257,29 @@ def decomposedMixedGlyphs(self):
197257
component.drawPoints(decomposePointPen)
198258
# remove all components
199259
glyph.clearComponents()
200-
self.report.write(f"Decomposing glyph '{glyph.name}' in master '{fontSource.info.familyName} {fontSource.info.styleName}'")
260+
self.report.write(f"Decomposing glyph '{glyph.name}' in source '{fontSource.info.familyName} {fontSource.info.styleName}'")
201261
self.report.dedent()
202262
self.report.newLine()
203263

204-
def makeMasterGlyphsQuadractic(self):
264+
def makeSourceGlyphsQuadractic(self):
205265
"""
206-
Optimize and convert all master ufo to quad curves.
266+
Optimize and convert all source ufo to quad curves.
207267
"""
208-
# use cu2qu to optimize all masters
268+
# use cu2qu to optimize all sources
209269
fonts_to_quadratic(self.operator.fonts.values())
210270

211-
def makeMasterExportOptimizeCharstring(self):
271+
def makeSourceExportOptimizeCharstring(self):
212272
for name, font in self.operator.fonts.items():
213273
font.lib["com.typemytype.robofont.optimizeCharstring"] = False
214274

215-
def makeMasterKerningCompatible(self):
275+
def makeSourceKerningCompatible(self):
216276
"""
217277
Optimize kerning data.
218-
All masters must have the same kering pairs.
278+
All sources must have the same kering pairs.
219279
Build repair mutators for missing kering pairs
220280
and generate the kerning value within the design space.
221281
"""
222-
self.report.writeTitle("Making master kerning compatible", "'")
282+
self.report.writeTitle("Making source kerning compatible", "'")
223283
self.report.indent()
224284
# collect all kerning pairs
225285
allPairs = set()
@@ -234,7 +294,7 @@ def makeMasterKerningCompatible(self):
234294
kerningCache = dict()
235295
# loop over all pairs
236296
for pair in allPairs:
237-
# loop over all masters
297+
# loop over all sources
238298
for sourceDescriptor in self.operator.sources:
239299
sourceFont = self.operator.fonts[sourceDescriptor.name]
240300
missingPairs = []
@@ -263,7 +323,7 @@ def makeMasterKerningCompatible(self):
263323
self.report.dedent()
264324
self.report.newLine()
265325

266-
def makeMasterOnDefaultLocation(self):
326+
def makeSourceOnDefaultLocation(self):
267327
"""
268328
create default location
269329
which is on the crossing of all axis
@@ -275,19 +335,19 @@ def makeMasterOnDefaultLocation(self):
275335
# found the default location
276336
# do nothing
277337
return
278-
self.report.writeTitle("Setting a master on the default", "'")
338+
self.report.writeTitle("Setting a source on the default", "'")
279339
self.report.indent()
280-
# there is no master at the default location
281-
# change the defaults of each axis so it fits with a given master
340+
# there is no source at the default location
341+
# change the defaults of each axis so it fits with a given source
282342
for axis in self.operator.axes:
283343
axis.default = axis.map_backward(defaultLocation[axis.name])
284344
self.report.writeDict(defaultLocation)
285345
self.report.dedent()
286346
self.report.newLine()
287347

288-
def makeLayerMaster(self):
348+
def makeLayerSource(self):
289349
"""
290-
If there is a layer name in a source description add it as seperate master in the source description.
350+
If there is a layer name in a source description add it as seperate source in the source description.
291351
"""
292352
for sourceDescriptor in self.operator.sources:
293353
if sourceDescriptor.layerName is not None:

0 commit comments

Comments
 (0)