1717from defcon import Font , Glyph
1818
1919
20- def check_input_file (parser , file_name ):
20+ def _check_input_file (parser , file_name ):
2121 fn = Path (file_name )
2222 if fn .suffix .lower () != '.ufo' :
2323 parser .error (f'{ fn .name } is not a UFO file' )
@@ -26,7 +26,7 @@ def check_input_file(parser, file_name):
2626 return file_name
2727
2828
29- def get_args (args = None ):
29+ def _get_args (args = None ):
3030 parser = argparse .ArgumentParser (
3131 description = __doc__ ,
3232 )
@@ -50,8 +50,8 @@ def get_args(args=None):
5050 )
5151
5252 parser .add_argument (
53- 'input_file ' ,
54- type = lambda f : check_input_file (parser , f ),
53+ 'input_ufo ' ,
54+ type = lambda f : _check_input_file (parser , f ),
5555 action = 'store' ,
5656 help = 'UFO file' ,
5757 )
@@ -173,20 +173,20 @@ def _make_agd_dict():
173173
174174def get_glyph_order (f , include_template_glyphs = False ):
175175 '''
176- Figure out the glyph order.
177- * make sure .notdef is first,
178- * respect skipExportGlyphs,
179- * include (un-filled) template glyphs if desired
176+ Figure out the glyph order of a UFO file .
177+ * make sure .notdef is first,
178+ * respect skipExportGlyphs,
179+ * include (un-filled) template glyphs if desired
180180
181181 In the case that the public.glyphOrder key does not exist, resort to
182182 unrefined sorting:
183- * encoded: by code point
184- * unencoded: following code point sorting ( deduced by glyph name)
185- * unencoded: alphabetically by name (for the rest)
183+ * encoded glyphs : by code point
184+ * unencoded glyphs : following code point sorting, deduced by glyph name
185+ * remaining unencoded glyphs : alphabetically by name (for the rest)
186186
187187 NB: defcon and RF have different ways of determining template glyphs.
188- in defcon, f.glyphOrder includes template glyphs
189- in RF, f.glyphOrder excludes them
188+ in defcon, ` f.glyphOrder` includes template glyphs
189+ in RF, ` f.glyphOrder` excludes them
190190 '''
191191
192192 glyph_order = f .glyphOrder
@@ -242,7 +242,7 @@ def get_glyph_order(f, include_template_glyphs=False):
242242 return order
243243
244244
245- def make_uni_name (cp ):
245+ def make_uni_gname (cp ):
246246 '''
247247 convert codepoint to uniXXXX (or uXXXXX) glyph name
248248 '''
@@ -253,18 +253,18 @@ def make_uni_name(cp):
253253 return uni_name
254254
255255
256- def make_uni_override (cp_list ):
256+ def _make_uni_override (cp_list ):
257257 '''
258258 comma-separated Unicode override string
259259 (or a single string if len(cp_list) == 1)
260260 '''
261- unicode_override = ',' .join ([make_uni_name (cp ) for cp in cp_list ])
261+ unicode_override = ',' .join ([make_uni_gname (cp ) for cp in cp_list ])
262262 return unicode_override
263263
264264
265- def make_unique_final_name (gname ):
265+ def _make_unique_final_name (gname ):
266266 '''
267- Since final glyph names need to be sanitized, a duplication of final glyph
267+ Since final glyph names need to be sanitized, a duplication of
268268 names is possible. This adds a 4-digit index to the glyph name.
269269
270270 If the glyph name already has a 4-digit index, the index is incremented.
@@ -282,20 +282,20 @@ def make_unique_final_name(gname):
282282 return f'{ gname_stem } { index :0>4} '
283283
284284
285- def sanitize_final_name (gname ):
285+ def sanitize_final_gname (gname ):
286286 '''
287287 The following characters are allowed in friendly- but not final names:
288- U+002A * asterisk
289- U+002B + plus sign
290- U+002D - hyphen-minus
291- U+003A : colon
292- U+005E ^ circumflex accent
293- U+007C | vertical bar
294- U+007E ~ tilde
288+ U+002A * asterisk
289+ U+002B + plus sign
290+ U+002D - hyphen-minus
291+ U+003A : colon
292+ U+005E ^ circumflex accent
293+ U+007C | vertical bar
294+ U+007E ~ tilde
295295
296296 In addition to that, final glyph names
297- * may not start with a period
298- * may not start with a digit
297+ * may not start with a period
298+ * may not start with a digit
299299
300300 see also
301301 https://adobe-type-tools.github.io/afdko/OpenTypeFeatureFileSpecification.html#2fi-glyph-name
@@ -330,12 +330,27 @@ def sanitize_final_name(gname):
330330 return gname
331331
332332
333+ def _dummy_glyph (f , gname ):
334+ '''
335+ make sure a glyph object is present -- no matter if it exists in the UFO
336+ or not.
337+ '''
338+ try :
339+ # glyph exists in the UFO
340+ glyph = f [gname ]
341+ except KeyError :
342+ # template glyph
343+ glyph = Glyph ()
344+ glyph .name = gname
345+ return glyph
346+
347+
333348class GlyphBaptism (object ):
334349 '''
335350 Simple deduction of final glyph name.
336- Not dealing with ligatures/ alternates here.
351+ (Deliberately ignoring ligatures and alternates here.)
337352
338- Either
353+ Considering either one of the following scenarios:
339354 - glyph name is in the AGD dict, makeotf associates the code point
340355 - glyph name is not in the AGD, but the glyph has attached code point(s)
341356 - glyph name implies a code point (uniXXXX or uXXXXX)
@@ -356,7 +371,7 @@ def __init__(self, gn_friendly, g=None, gn_final=None, cp_override=None):
356371 # this is the normal expectation for most glyphs
357372 if self .gn_final is None :
358373 self .assign_final_and_cp_override ()
359- self .gn_final = sanitize_final_name (self .gn_final )
374+ self .gn_final = sanitize_final_gname (self .gn_final )
360375
361376 # in other cases (alternates/ligatures), we generate the final name
362377 # outside, and use this object for data storage only.
@@ -382,7 +397,7 @@ def assign_final_and_cp_override(self):
382397 # glyph name is in AGD, but multiple code points attached;
383398 # override is needed
384399 self .gn_final = self .gn_friendly
385- self .cp_override = make_uni_override (self .glyph .unicodes )
400+ self .cp_override = _make_uni_override (self .glyph .unicodes )
386401 else :
387402 # just one codepoint
388403 expected_codepoint = agd_cp
@@ -392,7 +407,7 @@ def assign_final_and_cp_override(self):
392407 self .gn_final = agd_final
393408 else :
394409 # codepoint is different from what we expect
395- self .gn_final = make_uni_name (self .glyph .unicode )
410+ self .gn_final = make_uni_gname (self .glyph .unicode )
396411
397412 # glyph name implies Unicode value (uniXXXX or uXXXXX)
398413 elif uni_name_match :
@@ -403,8 +418,8 @@ def assign_final_and_cp_override(self):
403418 # no codepoint assigned to glyph, codepoint will be assigned
404419 # through the glyph name only
405420 # The glyph name could be uniFFFFF, which is not a legal final
406- # name, so we are sending it through make_uni_name .
407- self .gn_final = make_uni_name (cp_int )
421+ # name, so we are sending it through make_uni_gname .
422+ self .gn_final = make_uni_gname (cp_int )
408423 elif len (self .glyph .unicodes ) > 1 :
409424 # glyph name implies one code point, but multiple code points
410425 # are attached -- override needed.
@@ -415,18 +430,18 @@ def assign_final_and_cp_override(self):
415430 # The final name does not matter, because it is
416431 # overridden anyway.
417432 self .gn_final = self .gn_friendly
418- self .cp_override = make_uni_override (self .glyph .unicodes )
433+ self .cp_override = _make_uni_override (self .glyph .unicodes )
419434 else :
420435 # just one codepoint
421436 actual_codepoint = self .glyph .unicode
422437 if cp_int == actual_codepoint :
423438 # codepoint is the expected one. Name could be uniFFFFF,
424439 # which makeotf only understands as uFFFFF.
425- self .gn_final = make_uni_name (cp_int )
440+ self .gn_final = make_uni_gname (cp_int )
426441 else :
427442 # codepoint is different from what the name implies
428443 # (weird flex but OK)
429- self .gn_final = make_uni_name (self .glyph .unicode )
444+ self .gn_final = make_uni_gname (self .glyph .unicode )
430445
431446 # custom glyph name
432447 else :
@@ -436,41 +451,26 @@ def assign_final_and_cp_override(self):
436451 elif len (self .glyph .unicodes ) > 1 :
437452 # multiple code points are attached -- override needed
438453 self .gn_final = self .gn_friendly
439- self .cp_override = make_uni_override (self .glyph .unicodes )
454+ self .cp_override = _make_uni_override (self .glyph .unicodes )
440455 else :
441456 # just one codepoint, the final name will tell makeotf about it
442- self .gn_final = make_uni_name (self .glyph .unicode )
457+ self .gn_final = make_uni_gname (self .glyph .unicode )
443458
444459
445- def fill_gn_dict (gb , glyph_name_dict ):
460+ def _fill_gn_dict (gb , glyph_name_dict ):
446461 '''
447462 This slightly awkward method of adding values to a dictionary ensures that
448463 the final glyph name is unique.
449464 '''
450465 final_name = gb .gn_final
451466 while final_name in [gb .gn_final for gb in glyph_name_dict .values ()]:
452- final_name = make_unique_final_name (final_name )
467+ final_name = _make_unique_final_name (final_name )
453468 gb .gn_final = final_name
454469 glyph_name_dict [gb .gn_friendly ] = gb
455470 return glyph_name_dict
456471
457472
458- def get_glyph (f , gname ):
459- '''
460- make sure a glyph object is present -- no matter if it exists in the UFO
461- or not.
462- '''
463- try :
464- # glyph exists in the UFO
465- glyph = f [gname ]
466- except KeyError :
467- # template glyph
468- glyph = Glyph ()
469- glyph .name = gname
470- return glyph
471-
472-
473- def make_glyph_name_dict (f , glyph_order ):
473+ def _make_glyph_name_dict (f , glyph_order ):
474474 '''
475475 make a dictionary:
476476 {friendly name: gb object}
@@ -503,12 +503,12 @@ def make_glyph_name_dict(f, glyph_order):
503503 liga_glyphs = [gn for gn in glyph_order if '_' in gn ]
504504
505505 for gn in base_glyphs :
506- g = get_glyph (f , gn )
506+ g = _dummy_glyph (f , gn )
507507 gb = GlyphBaptism (g .name , g )
508- glyph_name_dict = fill_gn_dict (gb , glyph_name_dict )
508+ glyph_name_dict = _fill_gn_dict (gb , glyph_name_dict )
509509
510510 for gn in alt_glyphs :
511- g = get_glyph (f , gn )
511+ g = _dummy_glyph (f , gn )
512512 stem , suffixes = g .name .split ('.' , 1 )
513513 if stem in glyph_name_dict :
514514 final_name_stem = glyph_name_dict .get (stem ).gn_final
@@ -521,12 +521,12 @@ def make_glyph_name_dict(f, glyph_order):
521521
522522 if g .unicodes :
523523 # the alt glyph itself may have a codepoint
524- gb .cp_override = make_uni_override (g .unicodes )
524+ gb .cp_override = _make_uni_override (g .unicodes )
525525
526- glyph_name_dict = fill_gn_dict (gb , glyph_name_dict )
526+ glyph_name_dict = _fill_gn_dict (gb , glyph_name_dict )
527527
528528 for gn in liga_glyphs :
529- g = get_glyph (f , gn )
529+ g = _dummy_glyph (f , gn )
530530 liga_chunks = g .name .split ('_' )
531531 liga_chunks_final = []
532532 for chunk in liga_chunks :
@@ -542,14 +542,14 @@ def make_glyph_name_dict(f, glyph_order):
542542
543543 if g .unicodes :
544544 # some ligatures have codepoints
545- gb .cp_override = make_uni_override (g .unicodes )
545+ gb .cp_override = _make_uni_override (g .unicodes )
546546
547- glyph_name_dict = fill_gn_dict (gb , glyph_name_dict )
547+ glyph_name_dict = _fill_gn_dict (gb , glyph_name_dict )
548548
549549 return glyph_name_dict
550550
551551
552- def build_goadb (glyph_order , glyph_name_dict ):
552+ def _make_goadb_content (glyph_order , glyph_name_dict ):
553553 goadb = []
554554 for gname in glyph_order :
555555 gb = glyph_name_dict .get (gname )
@@ -560,22 +560,36 @@ def build_goadb(glyph_order, glyph_name_dict):
560560 return '\n ' .join (goadb )
561561
562562
563- def main (test_args = None ):
564- args = get_args (test_args )
565- f = Font (args .input_file )
566- glyph_order = get_glyph_order (f , args .template )
567- glyph_name_dict = make_glyph_name_dict (f , glyph_order )
568- goadb = build_goadb (glyph_order , glyph_name_dict )
569- output_path = args .output
563+ def make_goadb (input_ufo , include_template_glyphs = False ):
564+ '''
565+ Make a GOADB from an input UFO.
566+ Optionally, template glyphs can be included.
567+ '''
568+ f = Font (input_ufo )
569+ glyph_order = get_glyph_order (f , include_template_glyphs )
570+ glyph_name_dict = _make_glyph_name_dict (f , glyph_order )
571+ goadb_content = _make_goadb_content (glyph_order , glyph_name_dict )
572+ return goadb_content
570573
574+
575+ def write_goadb (goadb_content , output_path = None ):
576+ '''
577+ Write the GOADB to an output file or folder.
578+ '''
571579 if output_path and output_path .is_file ():
572580 with open (output_path , 'w' ) as blob :
573- blob .write (goadb + '\n ' )
581+ blob .write (goadb_content + '\n ' )
574582 elif output_path and output_path .is_dir ():
575583 with open (output_path / 'GlyphOrderAndAliasDB' , 'w' ) as blob :
576- blob .write (goadb + '\n ' )
584+ blob .write (goadb_content + '\n ' )
577585 else :
578- print (goadb )
586+ print (goadb_content )
587+
588+
589+ def main (test_args = None ):
590+ args = _get_args (test_args )
591+ goadb_content = make_goadb (args .input_ufo , args .template )
592+ write_goadb (goadb_content , args .output_path )
579593
580594
581595if __name__ == '__main__' :
0 commit comments