@@ -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