Skip to content

Commit 576baa3

Browse files
committed
wip
1 parent ed9aebe commit 576baa3

1 file changed

Lines changed: 83 additions & 94 deletions

File tree

sources/scripts/fix_fonts.py

Lines changed: 83 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -26,28 +26,14 @@
2626

2727

2828
def 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

5339
def 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

324279
def 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+
471457
def 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

Comments
 (0)