2626
2727
2828def fix_font_revision (font ):
29- """Fix font revision to exact value (32.05000 instead of 32.04999)"""
30- version_str = font ['name' ].getName (5 , 3 , 1 , 0x409 ).toUnicode ()
31- # Extract version like "Version 32.5.0; ttfautohint (v1.8.3)"
32- if 'Version' in version_str :
33- # Split on semicolon to remove ttfautohint suffix
34- version_main = version_str .split (';' )[0 ].replace ('Version' , '' ).strip ()
35- version_parts = version_main .split ('.' )
36- if len (version_parts ) >= 3 :
37- major = int (version_parts [0 ])
38- minor = int (version_parts [1 ])
39- patch = int (version_parts [2 ].split ()[0 ] if ' ' in version_parts [2 ] else version_parts [2 ])
40-
41- # Calculate exact revision
42- # Google Fonts preferred format is often Major.Minor as a float
43- # For 32.5.0, this should be 32.500
44- revision = major + (minor / 10 ) + (patch / 1000 ) # Simplified, might need adjustment
45- # Try to match what fontbakery expects, which is usually Major.Minor
46- revision = float (f"{ major } .{ minor } { patch } " )
47- font ['head' ].fontRevision = revision
48- print (f" ✓ Fixed font revision: { revision } " )
49- return True
50- return False
29+ """Fix font revision and nameID5 to exact value (Version 32.5.0)."""
30+ target_version = "Version 32.5.0"
31+ font ['head' ].fontRevision = 32.5
32+ name_table = font ['name' ]
33+ name_table .setName (target_version , 5 , 3 , 1 , 0x409 )
34+ name_table .setName (target_version , 5 , 1 , 0 , 0 )
35+ print (" ✓ Fixed font revision: 32.5" )
36+ return True
5137
5238
5339def fix_windows_metrics (font ):
@@ -236,17 +222,26 @@ def fix_font_names(font):
236222 is_bold = font ['OS/2' ].usWeightClass >= 700
237223 is_italic = bool (font ['head' ].macStyle & 2 ) or (font ['OS/2' ].fsSelection & 1 )
238224
239- family_name = "Iosevka Charon"
240-
241- # Determine style name
242- if is_bold and is_italic :
243- style_name = "Bold Italic"
244- elif is_bold :
245- style_name = "Bold"
246- elif is_italic :
247- style_name = "Italic"
248- else :
249- style_name = "Regular"
225+ existing_family = name_table .getName (1 , 3 , 1 , 0x409 )
226+ family_hint = existing_family .toUnicode () if existing_family else ""
227+ existing_style = name_table .getName (2 , 3 , 1 , 0x409 )
228+ style_hint = existing_style .toUnicode () if existing_style else ""
229+ is_mono = "Mono" in family_hint or "Mono" in font .reader .file .name
230+ family_name = "Iosevka Charon Mono" if is_mono else "Iosevka Charon"
231+
232+ weight_map = {
233+ 100 : "Thin" ,
234+ 200 : "ExtraLight" ,
235+ 300 : "Light" ,
236+ 400 : "Regular" ,
237+ 500 : "Medium" ,
238+ 600 : "SemiBold" ,
239+ 700 : "Bold" ,
240+ 800 : "ExtraBold" ,
241+ 900 : "Heavy" ,
242+ }
243+ style_base = weight_map .get (font ["OS/2" ].usWeightClass , style_hint .strip () or "Regular" )
244+ style_name = f"{ style_base } Italic" if is_italic else style_base
250245
251246 # Full name should be "Family Style"
252247 full_name = f"{ family_name } { style_name } "
@@ -262,63 +257,23 @@ def fix_font_names(font):
262257
263258 changed = False
264259
265- # Name IDs to check/fix
266- # 1: Family Name
267- # 2: Subfamily Name
268- # 4: Full Name
269- # 6: Postscript Name
270- # 16: Typographic Family Name
271- # 17: Typographic Subfamily Name
272-
273- # Collect existing names to check for ID 16/17 necessity
274- has_id16 = any (r .nameID == 16 for r in name_table .names )
275- has_id17 = any (r .nameID == 17 for r in name_table .names )
276-
277- # For Regular/Bold/Italic/Bold Italic, we don't strictly need ID 16/17 if ID 1/2 are correct,
278- # but having them consistent is good.
279-
280- records_to_add = []
281-
282- for record in name_table .names :
283- # Check all platforms for Name ID 6 (Postscript Name)
284- if record .nameID == 6 :
285- if record .toUnicode () != ps_name :
286- if record .platformID == 3 : # Windows
287- record .string = ps_name .encode ('utf-16-be' )
288- else : # Mac or other
289- record .string = ps_name .encode ('ascii' )
290- changed = True
291-
292- # For other IDs, check Windows platform
293- elif record .platformID == 3 and record .platEncID == 1 and record .langID == 0x409 :
294- if record .nameID == 1 :
295- if record .toUnicode () != family_name :
296- record .string = family_name .encode ('utf-16-be' )
297- changed = True
298- elif record .nameID == 2 :
299- if record .toUnicode () != style_name :
300- record .string = style_name .encode ('utf-16-be' )
301- changed = True
302- elif record .nameID == 4 :
303- if record .toUnicode () != full_name :
304- record .string = full_name .encode ('utf-16-be' )
305- changed = True
306- elif record .nameID == 16 :
307- if record .toUnicode () == family_name :
308- records_to_add .append (record ) # Reuse this list for removal
309- changed = True
310- elif record .nameID == 17 :
311- if record .toUnicode () == style_name :
312- records_to_add .append (record ) # Reuse this list for removal
313- changed = True
314-
315- for record in records_to_add :
316- if record in name_table .names :
317- name_table .names .remove (record )
318-
319- if changed :
320- print (f" ✓ Fixed font names: { full_name } " )
321- return changed
260+ name_table .setName (family_name , 1 , 3 , 1 , 0x409 )
261+ name_table .setName (style_name , 2 , 3 , 1 , 0x409 )
262+ name_table .setName (full_name , 4 , 3 , 1 , 0x409 )
263+ name_table .setName (ps_name , 6 , 3 , 1 , 0x409 )
264+ name_table .setName (family_name , 16 , 3 , 1 , 0x409 )
265+ name_table .setName (style_name , 17 , 3 , 1 , 0x409 )
266+
267+ # Mirror to Mac platform
268+ name_table .setName (family_name , 1 , 1 , 0 , 0 )
269+ name_table .setName (style_name , 2 , 1 , 0 , 0 )
270+ name_table .setName (full_name , 4 , 1 , 0 , 0 )
271+ name_table .setName (ps_name , 6 , 1 , 0 , 0 )
272+ name_table .setName (family_name , 16 , 1 , 0 , 0 )
273+ name_table .setName (style_name , 17 , 1 , 0 , 0 )
274+
275+ print (f" ✓ Fixed font names: { full_name } " )
276+ return True
322277
323278
324279def fix_dotted_circle (font ):
@@ -360,9 +315,9 @@ def add_fallback_mark_anchors(font):
360315 if not unicodedata .combining (chr (cp )):
361316 base_glyphs .append (name )
362317
363- mark_class_count = len ( mark_glyphs )
364- # Anchor every mark at its origin.
365- mark_anchors = {name : (idx , buildAnchor (0 , 0 )) for idx , ( name , _ ) in enumerate ( mark_glyphs ) }
318+ # Use a single fallback mark class to keep the lookup compact.
319+ mark_class_index = 0
320+ mark_anchors = {name : (mark_class_index , buildAnchor (0 , 0 )) for name , _ in mark_glyphs }
366321
367322 glyf = font ['glyf' ]
368323 hmtx = font ['hmtx' ]
@@ -377,7 +332,7 @@ def add_fallback_mark_anchors(font):
377332 x = advance // 2
378333 y = glyph .yMax if hasattr (glyph , "yMax" ) and glyph .yMax is not None else font ['hhea' ].ascender
379334 anchor = buildAnchor (x , y )
380- base_anchors [base ] = {idx : anchor for idx in range ( mark_class_count ) }
335+ base_anchors [base ] = {mark_class_index : anchor }
381336
382337 if not base_anchors :
383338 return False
@@ -468,6 +423,37 @@ def set_name(name_id, value):
468423 return changed
469424
470425
426+ def fix_style_bits (font ):
427+ """Ensure fsSelection and macStyle reflect bold/italic status correctly."""
428+ os2 = font ['OS/2' ]
429+ head = font ['head' ]
430+ name_table = font ['name' ]
431+ style_entry = name_table .getName (2 , 3 , 1 , 0x409 )
432+ style_str = style_entry .toUnicode () if style_entry else ""
433+ base_style = style_str .replace (" Italic" , "" ).strip ()
434+ is_italic = "Italic" in style_str
435+ is_bold = base_style == "Bold"
436+ is_regular = base_style == "Regular"
437+
438+ fs_sel = os2 .fsSelection
439+ # Clear bold/italic/regular bits first
440+ fs_sel &= ~ (1 << 0 ) # ITALIC
441+ fs_sel &= ~ (1 << 5 ) # BOLD
442+ fs_sel &= ~ (1 << 6 ) # REGULAR
443+
444+ if is_italic :
445+ fs_sel |= (1 << 0 )
446+ if is_bold :
447+ fs_sel |= (1 << 5 )
448+ if is_regular :
449+ fs_sel |= (1 << 6 )
450+
451+ os2 .fsSelection = fs_sel
452+
453+ head .macStyle = (1 if is_bold else 0 ) | (2 if is_italic else 0 )
454+ return True
455+
456+
471457def post_process_font (font_path , output_path = None ):
472458 """Apply all post-processing fixes to a font"""
473459 if output_path is None :
@@ -517,6 +503,9 @@ def post_process_font(font_path, output_path=None):
517503 if fix_license_entries (font ):
518504 fixes_applied .append ("license_entries" )
519505
506+ if fix_style_bits (font ):
507+ fixes_applied .append ("style_bits" )
508+
520509 if add_fallback_mark_anchors (font ):
521510 fixes_applied .append ("fallback_mark_anchors" )
522511
0 commit comments