Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

font-patcher: Do not maximize heavy brackets in Mono #1232

Merged
merged 4 commits into from
May 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bin/scripts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Note: Usually you need to call the scripts in this directory while actually bein
* `generate-font-image-previews.sh`: Generates the preview images for `nerdfonts.com` (i.e. gh-pages) [3]
* `generate-glyph-info-from-set.py`: Generate the `i_xxx.sh` file from a glyph source (font) file, if the glyphs are named correctly [4]
* `generate-original-source.py`: Generate `original-source.otf` from single glyph svgs. [5]
* `generate-sample-set.sh`: Generate one patched font file from each source font (for manual checks) [4]
* `generate-webfonts.sh`: Generate woff and woff2 font files from the SymbolsOnly font (for the gh-pages) [1]
* `get-font-names-from-json.sh`: Helper to setup the CI font matrix from `data/fonts.json` [1]
* `gotta-patch-em-all-font-patcher!.sh`: Patch one or more fonts 'complete' with and without `mono` and with and without `windows compat` [1]
Expand Down
101 changes: 101 additions & 0 deletions bin/scripts/generate-sample-set.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#!/usr/bin/env bash
# Nerd Fonts Version: 3.0.0
# Script Version: 1.0.0
# Create one sample of each font

set -e

# Get script directory to set source and target dirs relative to it
sd="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"

outputdir="${sd}/../../temp"
unpatched="${sd}/../../src/unpatched-fonts"

function get_config_patch_flags {
local dir=$1
unset config_patch_flags
if [ -f "${unpatched}/${dir}/config.cfg" ]; then
source "${unpatched}/${dir}/config.cfg"
return
fi
dir=$(dirname "$dir")
if [ -f "${unpatched}/${dir}/config.cfg" ]; then
source "${unpatched}/${dir}/config.cfg"
return
fi
dir=$(dirname "$dir")
if [ -f "${unpatched}/${dir}/config.cfg" ]; then
source "${unpatched}/${dir}/config.cfg"
return
fi
}

font_files=( \
'3270/Regular/3270-Regular.ttf' \
'Agave/Agave-Regular.ttf' \
'AnonymousPro/Regular/Anonymous Pro.ttf' \
'Arimo/Regular/Arimo-Regular.ttf' \
'AurulentSansMono/AurulentSansMono-Regular.otf' \
'BigBlueTerminal/BigBlue_TerminalPlus.ttf' \
'BitstreamVeraSansMono/Regular/VeraMono.ttf' \
'CascadiaCode/Regular/CascadiaCode-Regular-vtt.ttf' \
'CodeNewRoman/Regular/Code New Roman-Regular.otf' \
'ComicShannsMono/ComicShannsMono-Regular.otf' \
'Cousine/Regular/Cousine-Regular.ttf' \
'DaddyTimeMono/DaddyTimeMono.otf' \
'DejaVuSansMono/Regular/DejaVuSansMono.ttf' \
'DroidSansMono/Droid Sans Mono for Powerline.otf' \
'FantasqueSansMono/Regular/FantasqueSansMono-Regular.ttf' \
'FiraCode/Regular/FiraCode-Regular.ttf' \
'FiraMono/Regular/FiraMono-Regular.otf' \
'Gohu/14/gohufont-14.ttf' \
'Go-Mono/Regular/Go-Mono.ttf' \
'Hack/Regular/Hack-Regular.ttf' \
'Hasklig/Regular/Hasklig-Regular.otf' \
'HeavyData/heavy_data.ttf' \
'Hermit/Regular/Hermit-Regular.otf' \
'iA-Writer/Mono/Regular/iAWriterMonoS-Regular.ttf' \
'IBMPlexMono/Mono/IBMPlexMono-Regular.ttf' \
'Inconsolata/Inconsolata-Regular.ttf' \
'InconsolataGo/Regular/InconsolataGo-Regular.ttf' \
'InconsolataLGC/Regular/Inconsolata-LGC.ttf' \
'Iosevka/Regular/iosevka-regular.ttf' \
'IosevkaTerm/Regular/iosevka-term-regular.ttf' \
'JetBrainsMono/Ligatures/Regular/JetBrainsMono-Regular.ttf' \
'Lekton/Regular/Lekton-Regular.ttf' \
'LiberationMono/LiberationMono-Regular.ttf' \
'Lilex/Regular/Lilex-Regular.ttf' \
'Meslo/M/Regular/Meslo LG M Regular for Powerline.ttf' \
'Monofur/Regular/Monofur for Powerline.ttf' \
'Monoid/Regular/Monoid-Regular.ttf' \
'Mononoki/Regular/mononoki-Regular.ttf' \
'MPlus/M_Plus_1_code/MPLUS1Code-Regular.ttf' \
'NerdFontsSymbolsOnly/NerdFontsSymbolsNerdFontBlank.sfd' \
'Noto/Sans-Mono/NotoSansMono-Regular.ttf' \
'OpenDyslexic/Regular/OpenDyslexic-Regular.otf' \
'Overpass/Mono/Regular/overpass-mono-regular.otf' \
'ProFont/profontiix/ProFontIIx.ttf' \
'ProggyClean/Regular/ProggyClean.ttf' \
'RobotoMono/Regular/RobotoMono-Regular.ttf' \
'ShareTechMono/ShareTechMono-Regular.ttf' \
'SourceCodePro/Regular/SourceCodePro-Regular.ttf' \
'SpaceMono/Regular/SpaceMono-Regular.ttf' \
'Terminus/Regular/TerminusTTF-4.49.2.ttf' \
'Tinos/Regular/Tinos-Regular.ttf' \
'Ubuntu/Regular/Ubuntu-R.ttf' \
'UbuntuMono/Regular/UbuntuMono-R.ttf' \
'VictorMono/Regular/VictorMono-Regular.ttf' \
)

if [ ! -d "${outputdir}" ]; then
mkdir -p "${outputdir}"
fi

for f in "${font_files[@]}"; do
echo
echo ">>------------------------[ $f ]------------------------>>"
dir=$(dirname "${f}")
get_config_patch_flags "${dir}"
echo ">> config.cfg: ${config_patch_flags}"
fontforge ../../font-patcher --powerline --debug 2 -out "${outputdir}" $config_patch_flags ${NERDFONTS} "${unpatched}/${f}" 2>/dev/null || true
done
1 change: 1 addition & 0 deletions bin/scripts/gotta-patch-em-all-font-patcher!.sh
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ function patch_font {

# source the font config file if exists:
# fetches for example config_patch_flags
unset config_patch_flags
if [ -f "$config_dir/config.cfg" ]
then
# shellcheck source=/dev/null
Expand Down
45 changes: 29 additions & 16 deletions font-patcher
Original file line number Diff line number Diff line change
Expand Up @@ -803,14 +803,16 @@ class font_patcher:
box_enabled = False # Cowardly not scaling existing glyphs, although the code would allow this

# Stretch 'xz' or 'pa' (preserve aspect ratio)
# Supported params: overlap | careful | xy-ratio | dont_copy
# Supported params: overlap | careful | xy-ratio | dont_copy | ypadding
# Overlap value is used horizontally but vertically limited to 0.01
# Careful does not overwrite/modify existing glyphs
# The xy-ratio limits the x-scale for a given y-scale to make the ratio <= this value (to prevent over-wide glyphs)
# '1' means occupu 1 cell (default for 'xy')
# '2' means occupy 2 cells (default for 'pa')
# '!' means do the 'pa' scaling even with non mono fonts (else it just scales down, never up)
# Dont_copy does not overwrite existing glyphs but rescales the preexisting ones
#
# Be careful, stretch may not change within a ScaleRule!

SYM_ATTR_DEFAULT = {
'default': {'align': 'c', 'valign': 'c', 'stretch': 'pa', 'params': {}}
Expand Down Expand Up @@ -887,7 +889,7 @@ class font_patcher:
0xf0de: {'align': 'c', 'valign': '', 'stretch': 'pa', 'params': {}}
}
SYM_ATTR_HEAVYBRACKETS = {
'default': {'align': 'c', 'valign': 'c', 'stretch': 'pa', 'params': {'careful': True}}
'default': {'align': 'c', 'valign': 'c', 'stretch': 'pa1!', 'params': {'ypadding': 0.3, 'careful': True}}
}
SYM_ATTR_BOX = {
'default': {'align': 'c', 'valign': 'c', 'stretch': 'xy', 'params': {'overlap': 0.02, 'dont_copy': box_keep}},
Expand Down Expand Up @@ -984,6 +986,10 @@ class font_patcher:
range(0xf221, 0xf22d + 1), # gender or so
range(0xf255, 0xf25b + 1), # hand symbols
]}
HEAVY_SCALE_LIST = {'ScaleGlyph': 0x2771, # widest bracket, horizontally
'GlyphsToScale': [
(0x276c, 0x2771) # all
]}
OCTI_SCALE_LIST = {'ScaleGroups': [
[*range(0xf03d, 0xf040 + 1), 0xf019, 0xf030, 0xf04a, 0xf050, 0xf071, 0xf08c ], # arrows
[0xF0E7, # Smily and ...
Expand Down Expand Up @@ -1021,7 +1027,7 @@ class font_patcher:
# Symbol font ranges
self.patch_set = [
{'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': 0x276C, 'SymEnd': 0x2771, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_HEAVYBRACKETS},
{'Enabled': True, 'Name': "Heavy Angle Brackets", 'Filename': "extraglyphs.sfd", 'Exact': True, 'SymStart': 0x276C, 'SymEnd': 0x2771, 'SrcStart': None, 'ScaleRules': HEAVY_SCALE_LIST, 'Attributes': SYM_ATTR_HEAVYBRACKETS},
{'Enabled': box_enabled, 'Name': "Box Drawing", 'Filename': "extraglyphs.sfd", 'Exact': True, 'SymStart': 0x2500, 'SymEnd': 0x259F, 'SrcStart': None, 'ScaleRules': BOX_SCALE_LIST, 'Attributes': SYM_ATTR_BOX},
{'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},
Expand Down Expand Up @@ -1138,7 +1144,7 @@ class font_patcher:

# 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, 'ypadding': 0}

if metrics == Metric.HHEA:
self.font_dim['ymin'] = self.sourceFont.hhea_descent - half_gap(self.sourceFont.hhea_linegap, False)
Expand Down Expand Up @@ -1246,7 +1252,7 @@ class font_patcher:

# font_dim['height'] represents total line height, keep our symbols sized based upon font's em
# Use the font_dim['height'] only for explicit 'y' scaling (not 'pa')
target_height = self.font_dim['height']
target_height = self.font_dim['height'] * (1.0 - self.font_dim['ypadding'])
scale_ratio_y = target_height / sym_dim['height']

if 'pa' in stretch:
Expand Down Expand Up @@ -1330,6 +1336,9 @@ class font_patcher:
# if currentSourceFontGlyph != 0xe7bd:
# continue

ypadding = sym_attr['params'].get('ypadding')
self.font_dim['ypadding'] = ypadding or 0.0

if not self.args.quiet:
if self.args.progressbars:
update_progress(round(float(index + 1) / glyphSetLength, 2))
Expand All @@ -1352,14 +1361,15 @@ class font_patcher:
if currentSourceFontGlyph in self.sourceFont:
self.sourceFont[currentSourceFontGlyph].removePosSub("*")

stretch = sym_attr['stretch']
dont_copy = sym_attr['params'].get('dont_copy')

if dont_copy:
# Just prepare scaling of existing glyphs
glyph_scale_data = self.get_glyph_scale(sym_glyph.encoding, scaleRules, self.sourceFont, currentSourceFontGlyph) if scaleRules is not None else None
glyph_scale_data = self.get_glyph_scale(sym_glyph.encoding, scaleRules, stretch, self.sourceFont, currentSourceFontGlyph) if scaleRules is not None else None
else:
# This will destroy any content currently in currentSourceFontGlyph, so do it first
glyph_scale_data = self.get_glyph_scale(sym_glyph.encoding, scaleRules, symbolFont, currentSourceFontGlyph) if scaleRules is not None else None
glyph_scale_data = self.get_glyph_scale(sym_glyph.encoding, scaleRules, stretch, symbolFont, currentSourceFontGlyph) if scaleRules is not None else None

# Select and copy symbol from its encoding point
# We need to do this select after the careful check, this way we don't
Expand All @@ -1378,15 +1388,18 @@ class font_patcher:
if glyph_scale_data is not None:
if glyph_scale_data[1] is not None:
sym_dim = glyph_scale_data[1] # Use combined bounding box
(scale_ratio_x, scale_ratio_y) = self.get_scale_factors(sym_dim, sym_attr['stretch'])
(scale_ratio_x, scale_ratio_y) = self.get_scale_factors(sym_dim, stretch)
else:
# This is roughly alike get_scale_factors(glyph_scale_data[1], 'pa')
# Except we do not have glyph_scale_data[1] always...
(scale_ratio_x, scale_ratio_y) = (glyph_scale_data[0], glyph_scale_data[0])
else:
(scale_ratio_x, scale_ratio_y) = self.get_scale_factors(sym_dim, sym_attr['stretch'])
(scale_ratio_x, scale_ratio_y) = self.get_scale_factors(sym_dim, stretch)

overlap = sym_attr['params'].get('overlap')
if overlap and ypadding:
logger.critical("Conflicting params: overlap and ypadding")
sys.exit(1)
if overlap:
scale_ratio_x *= 1.0 + (self.font_dim['width'] / (sym_dim['width'] * scale_ratio_x)) * overlap
y_overlap = min(0.01, overlap) # never aggressive vertical overlap
Expand Down Expand Up @@ -1436,7 +1449,7 @@ class font_patcher:
x_align_distance += (self.font_dim['width'] / 2) - (sym_dim['width'] / 2)
elif sym_attr['align'] == 'r':
# Right align
x_align_distance += self.font_dim['width'] * self.get_target_width(sym_attr['stretch']) - sym_dim['width']
x_align_distance += self.font_dim['width'] * self.get_target_width(stretch) - sym_dim['width']
# If symbol glyph is wider than target font cell, just left-align
x_align_distance = max(self.font_dim['xmin'] - sym_dim['xmin'], x_align_distance)

Expand All @@ -1449,7 +1462,7 @@ class font_patcher:
x_align_distance -= overlap_width / 2
elif sym_attr['align'] == 'r':
# Check and correct overlap; it can go wrong if we have a xy-ratio limit
target_xmax = (self.font_dim['xmin'] + self.font_dim['width']) * self.get_target_width(sym_attr['stretch'])
target_xmax = (self.font_dim['xmin'] + self.font_dim['width']) * self.get_target_width(stretch)
target_xmax += overlap_width
glyph_xmax = sym_dim['xmax'] + x_align_distance
correction = target_xmax - glyph_xmax
Expand Down Expand Up @@ -1545,7 +1558,7 @@ class font_patcher:
except:
pass

def prepareScaleRules(self, scaleRules, symbolFont, destGlyph):
def prepareScaleRules(self, scaleRules, stretch, symbolFont, destGlyph):
""" Prepare raw ScaleRules data for use """
# The scaleRules is/will be a dict with these (possible) entries:
# 'ScaleGroups': List of ((lists of glyph codes) or (ranges of glyph codes)) that shall be scaled
Expand Down Expand Up @@ -1579,7 +1592,7 @@ class font_patcher:
scaleRules['ScaleGroups'] = []
for group in scaleRules['ScaleGroups']:
sym_dim = get_multiglyph_boundingBox([ symbolFont[g] if g in symbolFont else None for g in group ], destGlyph)
scale = self.get_scale_factors(sym_dim, 'pa')[0]
scale = self.get_scale_factors(sym_dim, stretch)[0]
scaleRules['scales'].append(scale)
scaleRules['bbdims'].append(sym_dim)

Expand All @@ -1598,21 +1611,21 @@ class font_patcher:
else:
group_list.append(i)
sym_dim = get_glyph_dimensions(symbolFont[scaleRules['ScaleGlyph']])
scale = self.get_scale_factors(sym_dim, 'pa')[0]
scale = self.get_scale_factors(sym_dim, stretch)[0]
scaleRules['ScaleGroups'].append(group_list)
scaleRules['scales'].append(scale)
if plus:
scaleRules['bbdims'].append(sym_dim)
else:
scaleRules['bbdims'].append(None) # The 'old' style keeps just the scale, not the positioning

def get_glyph_scale(self, symbol_unicode, scaleRules, symbolFont, dest_unicode):
def get_glyph_scale(self, symbol_unicode, scaleRules, stretch, symbolFont, dest_unicode):
""" Determines whether or not to use scaled glyphs for glyph in passed symbol_unicode """
# Potentially destorys the contents of self.sourceFont[dest_unicode]
if not 'scales' in scaleRules:
if not dest_unicode in self.sourceFont:
self.sourceFont.createChar(dest_unicode)
self.prepareScaleRules(scaleRules, symbolFont, self.sourceFont[dest_unicode])
self.prepareScaleRules(scaleRules, stretch, symbolFont, self.sourceFont[dest_unicode])
for glyph_list, scale, box in zip(scaleRules['ScaleGroups'], scaleRules['scales'], scaleRules['bbdims']):
for e in glyph_list:
if isinstance(e, range):
Expand Down