chore: change batteries

This commit is contained in:
github-actions 2023-02-15 01:39:45 +00:00
parent 5aff489af5
commit 5006509e0a
2 changed files with 96 additions and 32 deletions

View file

@ -6,7 +6,7 @@
from __future__ import absolute_import, print_function, unicode_literals from __future__ import absolute_import, print_function, unicode_literals
# Change the script version when you edit this script: # Change the script version when you edit this script:
script_version = "3.5.2" script_version = "3.5.8"
version = "2.3.3" version = "2.3.3"
projectName = "Nerd Fonts" projectName = "Nerd Fonts"
@ -21,6 +21,7 @@ from argparse import RawTextHelpFormatter
import errno import errno
import subprocess import subprocess
import json import json
from enum import Enum
try: try:
import configparser import configparser
except ImportError: except ImportError:
@ -194,6 +195,14 @@ def panose_check_to_text(value, panose = False):
return "Panose says \"monospaced\"" return "Panose says \"monospaced\""
return "Panose is invalid" + (" ({})".format(list(panose)) if panose else "") return "Panose is invalid" + (" ({})".format(list(panose)) if panose else "")
def panose_proportion_to_text(value):
""" Interpret a Panose proportion value (4th value) for family 2 (latin text) """
proportion = {
0: "Any", 1: "No Fit", 2: "Old Style", 3: "Modern", 4: "Even Width",
5: "Extended", 6: "Condensed", 7: "Very Extended", 8: "Very Condensed",
9: "Monospaced" }
return proportion.get(value, "??? {}".format(value))
def is_monospaced(font): def is_monospaced(font):
""" Check if a font is probably monospaced """ """ Check if a font is probably monospaced """
# Some fonts lie (or have not any Panose flag set), spot check monospaced: # Some fonts lie (or have not any Panose flag set), spot check monospaced:
@ -222,6 +231,20 @@ def is_monospaced(font):
# We believe our own check more then Panose ;-D # We believe our own check more then Panose ;-D
return (width_mono, None if width_mono else glyph) return (width_mono, None if width_mono else glyph)
def force_panose_monospaced(font):
""" Forces the Panose flag to monospaced if they are unset or halfway ok already """
# For some Windows applications (e.g. 'cmd'), they seem to honour the Panose table
# https://forum.high-logic.com/postedfiles/Panose.pdf
panose = list(font.os2_panose)
if panose[0] == 0: # 0 (1st value) = family kind; 0 = any (default)
panose[0] = 2 # make kind latin text and display
print(" Setting Panose 'Family Kind' to 'Latin Text and Display' (was 'Any')")
font.os2_panose = tuple(panose)
if panose[0] == 2 and panose[3] != 9:
print(" Setting Panose 'Proportion' to 'Monospaced' (was '{}')".format(panose_proportion_to_text(panose[3])))
panose[3] = 9 # 3 (4th value) = proportion; 9 = monospaced
font.os2_panose = tuple(panose)
def get_advance_width(font, extended, minimum): def get_advance_width(font, extended, minimum):
""" Get the maximum/minimum advance width in the extended(?) range """ """ Get the maximum/minimum advance width in the extended(?) range """
width = 0 width = 0
@ -248,6 +271,17 @@ def report_advance_widths(font):
get_advance_width(font, True, True), get_advance_width(font, False, True), get_advance_width(font, True, True), get_advance_width(font, False, True),
get_advance_width(font, False, False), get_advance_width(font, True, False)) get_advance_width(font, False, False), get_advance_width(font, True, False))
def get_btb_metrics(font):
""" Get the baseline to baseline distance for all three metrics """
hhea_height = font.hhea_ascent - font.hhea_descent
typo_height = font.os2_typoascent - font.os2_typodescent
win_height = font.os2_winascent + font.os2_windescent
win_gap = max(0, font.hhea_linegap - win_height + hhea_height)
hhea_btb = hhea_height + font.hhea_linegap
typo_btb = typo_height + font.os2_typolinegap
win_btb = win_height + win_gap
return (hhea_btb, typo_btb, win_btb, win_gap)
class font_patcher: class font_patcher:
def __init__(self, args): def __init__(self, args):
@ -267,7 +301,7 @@ class font_patcher:
self.setup_version() self.setup_version()
self.get_essential_references() self.get_essential_references()
self.setup_name_backup(font) self.setup_name_backup(font)
if self.args.single: if not self.args.nonmono:
self.assert_monospace() self.assert_monospace()
self.remove_ligatures() self.remove_ligatures()
self.setup_patch_set() self.setup_patch_set()
@ -280,13 +314,6 @@ class font_patcher:
# Force width to be equal on all glyphs to ensure the font is considered monospaced on Windows. # Force width to be equal on all glyphs to ensure the font is considered monospaced on Windows.
# This needs to be done on all characters, as some information seems to be lost from the original font file. # This needs to be done on all characters, as some information seems to be lost from the original font file.
self.set_sourcefont_glyph_widths() self.set_sourcefont_glyph_widths()
# For some Windows applications (e.g. 'cmd') that is not enough. But they seem to honour the Panose table
# https://forum.high-logic.com/postedfiles/Panose.pdf
panose = list(self.sourceFont.os2_panose)
if panose[0] == 0 or panose[0] == 2: # 0 (1st value) = family kind; 0 = any (default); 2 = latin text and display
panose[0] = 2 # Assert kind
panose[3] = 9 # 3 (4th value) = propotion; 9 = monospaced
self.sourceFont.os2_panose = tuple(panose)
# For very wide (almost square or wider) fonts we do not want to generate 2 cell wide Powerline glyphs # For very wide (almost square or wider) fonts we do not want to generate 2 cell wide Powerline glyphs
if self.font_dim['height'] * 1.8 < self.font_dim['width'] * 2: if self.font_dim['height'] * 1.8 < self.font_dim['width'] * 2:
@ -693,12 +720,14 @@ class font_patcher:
print(" {} and {}".format( print(" {} and {}".format(
report_advance_widths(self.sourceFont), report_advance_widths(self.sourceFont),
panose_check_to_text(panose_mono, self.sourceFont.os2_panose))) panose_check_to_text(panose_mono, self.sourceFont.os2_panose)))
if not width_mono: if self.args.single and not width_mono:
print(" Warning: Sourcefont is not monospaced - forcing to monospace not advisable, results might be useless") print(" Warning: Sourcefont is not monospaced - forcing to monospace not advisable, results might be useless")
if offending_char is not None: if offending_char is not None:
print(" Offending char: 0x{:X}".format(offending_char)) print(" Offending char: 0x{:X}".format(offending_char))
if self.args.single <= 1: if self.args.single <= 1:
sys.exit(projectName + ": Font will not be patched! Give --mono (or -s, or --use-single-width-glyphs) twice to force patching") sys.exit(projectName + ": Font will not be patched! Give --mono (or -s, or --use-single-width-glyphs) twice to force patching")
if width_mono:
force_panose_monospaced(self.sourceFont)
def setup_patch_set(self): def setup_patch_set(self):
@ -779,6 +808,9 @@ class font_patcher:
0xf0dd: {'align': 'c', 'valign': '', 'stretch': 'pa', 'params': {}}, 0xf0dd: {'align': 'c', 'valign': '', 'stretch': 'pa', 'params': {}},
0xf0de: {'align': 'c', 'valign': '', 'stretch': 'pa', 'params': {}} 0xf0de: {'align': 'c', 'valign': '', 'stretch': 'pa', 'params': {}}
} }
SYM_ATTR_HEAVYBRACKETS = {
'default': {'align': 'c', 'valign': 'c', 'stretch': 'pa', 'params': {'careful': True}}
}
CUSTOM_ATTR = { CUSTOM_ATTR = {
# 'pa' == preserve aspect ratio # 'pa' == preserve aspect ratio
@ -877,7 +909,8 @@ class font_patcher:
# Define the character ranges # Define the character ranges
# Symbol font ranges # Symbol font ranges
self.patch_set = [ self.patch_set = [
{'Enabled': True, 'Name': "Seti-UI + Custom", 'Filename': "original-source.otf", 'Exact': False, 'SymStart': 0xE4FA, 'SymEnd': 0xE5AA, 'SrcStart': 0xE5FA, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT}, {'Enabled': True, 'Name': "Seti-UI + Custom", 'Filename': "original-source.otf", 'Exact': False, 'SymStart': 0xE4FA, 'SymEnd': 0xE5FF, 'SrcStart': 0xE5FA, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT},
{'Enabled': True, 'Name': "Heavy Angle Brackets", 'Filename': "extraglyphs.sfd", 'Exact': True, 'SymStart': 0x0000, 'SymEnd': 0x0000, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_HEAVYBRACKETS},
{'Enabled': True, 'Name': "Devicons", 'Filename': "devicons.ttf", 'Exact': False, 'SymStart': 0xE600, 'SymEnd': 0xE6C5, 'SrcStart': 0xE700, 'ScaleRules': DEVI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, {'Enabled': True, 'Name': "Devicons", 'Filename': "devicons.ttf", 'Exact': False, 'SymStart': 0xE600, 'SymEnd': 0xE6C5, 'SrcStart': 0xE700, 'ScaleRules': DEVI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT},
{'Enabled': self.args.powerline, 'Name': "Powerline Symbols", 'Filename': "powerline-symbols/PowerlineSymbols.otf", 'Exact': True, 'SymStart': 0xE0A0, 'SymEnd': 0xE0A2, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_POWERLINE}, {'Enabled': self.args.powerline, 'Name': "Powerline Symbols", 'Filename': "powerline-symbols/PowerlineSymbols.otf", 'Exact': True, 'SymStart': 0xE0A0, 'SymEnd': 0xE0A2, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_POWERLINE},
{'Enabled': self.args.powerline, 'Name': "Powerline Symbols", 'Filename': "powerline-symbols/PowerlineSymbols.otf", 'Exact': True, 'SymStart': 0xE0B0, 'SymEnd': 0xE0B3, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_POWERLINE}, {'Enabled': self.args.powerline, 'Name': "Powerline Symbols", 'Filename': "powerline-symbols/PowerlineSymbols.otf", 'Exact': True, 'SymStart': 0xE0B0, 'SymEnd': 0xE0B3, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_POWERLINE},
@ -961,39 +994,37 @@ class font_patcher:
# and we try to sort this out here # and we try to sort this out here
# See also https://glyphsapp.com/learn/vertical-metrics # See also https://glyphsapp.com/learn/vertical-metrics
# See also https://github.com/source-foundry/font-line # See also https://github.com/source-foundry/font-line
hhea_height = self.sourceFont.hhea_ascent - self.sourceFont.hhea_descent (hhea_btb, typo_btb, win_btb, win_gap) = get_btb_metrics(self.sourceFont)
typo_height = self.sourceFont.os2_typoascent - self.sourceFont.os2_typodescent
win_height = self.sourceFont.os2_winascent + self.sourceFont.os2_windescent
win_gap = max(0, self.sourceFont.hhea_linegap - win_height + hhea_height)
hhea_btb = hhea_height + self.sourceFont.hhea_linegap
typo_btb = typo_height + self.sourceFont.os2_typolinegap
win_btb = win_height + win_gap
use_typo = self.sourceFont.os2_use_typo_metrics != 0 use_typo = self.sourceFont.os2_use_typo_metrics != 0
Metric = Enum('Metric', ['HHEA', 'TYPO', 'WIN'])
# We use either TYPO (1) or WIN (2) and compare with HHEA # We use either TYPO (1) or WIN (2) and compare with HHEA
# and use HHEA (0) if the fonts seems broken # and use HHEA (0) if the fonts seems broken - no WIN, see #1056
our_btb = typo_btb if use_typo else win_btb our_btb = typo_btb if use_typo else win_btb
if our_btb == hhea_btb: if our_btb == hhea_btb:
metrics = 1 if use_typo else 2 # conforming font metrics = Metric.TYPO if use_typo else Metric.WIN # conforming font
else: else:
# We trust the WIN metric more, see experiments in #1056 # We trust the WIN metric more, see experiments in #1056
print("{}: WARNING Font vertical metrics inconsistent (HHEA {} / TYPO {} / WIN {}), using WIN".format(projectName, hhea_btb, typo_btb, win_btb)) print("{}: WARNING Font vertical metrics inconsistent (HHEA {} / TYPO {} / WIN {}), using WIN".format(projectName, hhea_btb, typo_btb, win_btb))
our_btb = win_btb our_btb = win_btb
metrics = 1 metrics = Metric.WIN
# print("FINI hhea {} typo {} win {} use {} {} {}".format(hhea_btb, typo_btb, win_btb, use_typo, our_btb != hhea_btb, self.sourceFont.fontname)) # print("FINI hhea {} typo {} win {} use {} {} {}".format(hhea_btb, typo_btb, win_btb, use_typo, our_btb != hhea_btb, self.sourceFont.fontname))
self.font_dim = {'xmin': 0, 'ymin': 0, 'xmax': 0, 'ymax': 0, 'width' : 0, 'height': 0} self.font_dim = {'xmin': 0, 'ymin': 0, 'xmax': 0, 'ymax': 0, 'width' : 0, 'height': 0}
if metrics == 0: if metrics == Metric.HHEA:
self.font_dim['ymin'] = self.sourceFont.hhea_descent + half_gap(self.sourceFont.hhea_linegap, False) self.font_dim['ymin'] = self.sourceFont.hhea_descent - half_gap(self.sourceFont.hhea_linegap, False)
self.font_dim['ymax'] = self.sourceFont.hhea_ascent + half_gap(self.sourceFont.hhea_linegap, True) self.font_dim['ymax'] = self.sourceFont.hhea_ascent + half_gap(self.sourceFont.hhea_linegap, True)
elif metrics == 1: elif metrics == Metric.TYPO:
self.font_dim['ymin'] = self.sourceFont.os2_typodescent + half_gap(self.sourceFont.os2_typolinegap, False) self.font_dim['ymin'] = self.sourceFont.os2_typodescent - half_gap(self.sourceFont.os2_typolinegap, False)
self.font_dim['ymax'] = self.sourceFont.os2_typoascent + half_gap(self.sourceFont.os2_typolinegap, True) self.font_dim['ymax'] = self.sourceFont.os2_typoascent + half_gap(self.sourceFont.os2_typolinegap, True)
else: elif metrics == Metric.WIN:
self.font_dim['ymin'] = -self.sourceFont.os2_windescent + half_gap(win_gap, False) self.font_dim['ymin'] = -self.sourceFont.os2_windescent - half_gap(win_gap, False)
self.font_dim['ymax'] = self.sourceFont.os2_winascent + half_gap(win_gap, True) self.font_dim['ymax'] = self.sourceFont.os2_winascent + half_gap(win_gap, True)
else:
pass # Will fail the metrics check some line later
# Calculate font height # Calculate font height
self.font_dim['height'] = -self.font_dim['ymin'] + self.font_dim['ymax'] self.font_dim['height'] = -self.font_dim['ymin'] + self.font_dim['ymax']
@ -1021,6 +1052,9 @@ class font_patcher:
self.sourceFont.hhea_descent = self.sourceFont.os2_typodescent self.sourceFont.hhea_descent = self.sourceFont.os2_typodescent
self.sourceFont.hhea_linegap = self.sourceFont.os2_typolinegap self.sourceFont.hhea_linegap = self.sourceFont.os2_typolinegap
self.sourceFont.os2_use_typo_metrics = 1 self.sourceFont.os2_use_typo_metrics = 1
(check_hhea_btb, check_typo_btb, check_win_btb, _) = get_btb_metrics(self.sourceFont)
if check_hhea_btb != check_typo_btb or check_typo_btb != check_win_btb or check_win_btb != our_btb:
sys.exit("{}: Error in baseline to baseline code detected".format(projectName))
# Step 2 # Step 2
# Find the biggest char width and advance width # Find the biggest char width and advance width
@ -1093,7 +1127,6 @@ class font_patcher:
""" Copies symbol glyphs into self.sourceFont """ """ Copies symbol glyphs into self.sourceFont """
progressText = '' progressText = ''
careful = False careful = False
glyphSetLength = 0
sourceFontCounter = 0 sourceFontCounter = 0
if self.args.careful: if self.args.careful:
@ -1114,14 +1147,12 @@ class font_patcher:
glyphSetLength = len(symbolFontSelection) glyphSetLength = len(symbolFontSelection)
if not self.args.quiet: if not self.args.quiet:
sys.stdout.write("Adding " + str(max(1, glyphSetLength)) + " Glyphs from " + setName + " Set \n") sys.stdout.write("Adding {} Glyphs from {} Set\n".format(glyphSetLength, setName))
currentSourceFontGlyph = -1 # initialize for the exactEncoding case currentSourceFontGlyph = -1 # initialize for the exactEncoding case
width_warning = False width_warning = False
for index, sym_glyph in enumerate(symbolFontSelection): for index, sym_glyph in enumerate(symbolFontSelection):
index = max(1, index)
sym_attr = attributes.get(sym_glyph.unicode) sym_attr = attributes.get(sym_glyph.unicode)
if sym_attr is None: if sym_attr is None:
sym_attr = attributes['default'] sym_attr = attributes['default']
@ -1571,6 +1602,34 @@ def check_fontforge_min_version():
sys.stderr.write("{}: Please use at least version: {}\n".format(projectName, minimumVersion)) sys.stderr.write("{}: Please use at least version: {}\n".format(projectName, minimumVersion))
sys.exit(1) sys.exit(1)
def check_version_with_git(version):
""" Upgraded the version to the current git tag version (starting with 'v') """
git = subprocess.run("git describe --tags",
cwd=os.path.dirname(__file__),
shell=True,
stdout=subprocess.PIPE, stderr=subprocess.DEVNULL
).stdout.decode('utf-8')
if len(git) == 0:
return False
tag = git.strip()
if len(tag) == 0 or not tag.startswith('v'):
return False
tag = tag[1:]
r = re.search('(.*?)(-[0-9]+)-g[0-9a-fA-F]+$', tag)
if r:
tag = r.group(1)
patchlevel = r.group(2)
else:
patchlevel = ""
# Inspired by Phaxmohdem's versiontuple https://stackoverflow.com/a/28568003
versiontuple = lambda v: tuple( p.zfill(8) for p in v.split(".") )
if versiontuple(tag) > versiontuple(version):
return tag + patchlevel
if versiontuple(tag) == versiontuple(version) and len(patchlevel) > 0:
return tag + patchlevel
return False
def setup_arguments(): def setup_arguments():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description=( description=(
@ -1699,7 +1758,12 @@ def setup_arguments():
def main(): def main():
print("{} Patcher v{} ({}) executing".format(projectName, version, script_version)) global version
git_version = check_version_with_git(version)
print("{} Patcher v{} ({}) (ff {}) executing".format(
projectName, git_version if git_version else version, script_version, fontforge.version()))
if git_version:
version = git_version
check_fontforge_min_version() check_fontforge_min_version()
args = setup_arguments() args = setup_arguments()
patcher = font_patcher(args) patcher = font_patcher(args)

BIN
src/glyphs/extraglyphs.sfd Normal file

Binary file not shown.