mirror of
https://github.com/ryanoasis/nerd-fonts.git
synced 2024-09-19 09:51:48 +02:00
font-patcher: Rewrite font height calculation
[why] The initial font-patcher used the WIN font metrics to determine the cell height. What has been found was forced into HHEA metrics but without observing the USE_TYPO_METRICS flag. That has been changed to use the TYPO metric instead of the WIN metric when the font wants that. For that the gap value becomes important. This is the current code. It still has problems to detect the correct cell height. A more rigorous approach seem to be needed. [how] The baseline to baseline distance is what we need as 'cell height', to fill it completely with the powerline glyphs. This is a little bit complicated and not really specified, each font rendering application or engine can handle the font metrics differently. But there are some common approaches. So we try to come up with the correct and congruent height, comparing different metrics and issuing a warning on problematic fonts. Afterwards we make all metrics equal (even if they were not before), because our goal is clear now and we impose it onto all platforms. [note] Useful resources: * https://glyphsapp.com/learn/vertical-metrics * https://github.com/source-foundry/font-line Fixes: #1056 Signed-off-by: Fini Jastrow <ulf.fini.jastrow@desy.de>
This commit is contained in:
parent
ce6c161281
commit
04c682fd9c
1 changed files with 79 additions and 31 deletions
110
font-patcher
110
font-patcher
|
@ -6,7 +6,7 @@
|
|||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
# Change the script version when you edit this script:
|
||||
script_version = "3.4.5"
|
||||
script_version = "3.5.0"
|
||||
|
||||
version = "2.3.0"
|
||||
projectName = "Nerd Fonts"
|
||||
|
@ -271,8 +271,8 @@ class font_patcher:
|
|||
self.assert_monospace()
|
||||
self.remove_ligatures()
|
||||
self.setup_patch_set()
|
||||
self.improve_line_dimensions()
|
||||
self.get_sourcefont_dimensions()
|
||||
self.improve_line_dimensions()
|
||||
self.sourceFont.encoding = 'UnicodeFull' # Update the font encoding to ensure that the Unicode glyphs are available
|
||||
self.onlybitmaps = self.sourceFont.onlybitmaps # Fetch this property before adding outlines. NOTE self.onlybitmaps initialized and never used
|
||||
|
||||
|
@ -907,6 +907,7 @@ class font_patcher:
|
|||
# center more evenly.
|
||||
if self.args.adjustLineHeight:
|
||||
if (self.sourceFont.os2_winascent + self.sourceFont.os2_windescent) % 2 != 0:
|
||||
# All three are equal before due to get_sourcefont_dimensions()
|
||||
self.sourceFont.hhea_ascent += 1
|
||||
self.sourceFont.os2_typoascent += 1
|
||||
self.sourceFont.os2_winascent += 1
|
||||
|
@ -924,18 +925,56 @@ class font_patcher:
|
|||
self.essential.add(self.sourceFont[r[0]].unicode)
|
||||
|
||||
def get_sourcefont_dimensions(self):
|
||||
# Initial font dimensions
|
||||
self.font_dim = {
|
||||
'xmin' : 0,
|
||||
'ymin' : -self.sourceFont.os2_windescent,
|
||||
'xmax' : 0,
|
||||
'ymax' : self.sourceFont.os2_winascent,
|
||||
'width' : 0,
|
||||
'height': 0,
|
||||
}
|
||||
if self.sourceFont.os2_use_typo_metrics:
|
||||
self.font_dim['ymin'] = self.sourceFont.os2_typodescent
|
||||
self.font_dim['ymax'] = self.sourceFont.os2_typoascent
|
||||
""" This gets the font dimensions (cell width and height), and makes them equal on all platforms """
|
||||
# Step 1
|
||||
# There are three ways to discribe the baseline to baseline distance
|
||||
# (a.k.a. line spacing) of a font. That is all a kuddelmuddel
|
||||
# and we try to sort this out here
|
||||
# See also https://glyphsapp.com/learn/vertical-metrics
|
||||
# See also https://github.com/source-foundry/font-line
|
||||
hhea_height = self.sourceFont.hhea_ascent - self.sourceFont.hhea_descent
|
||||
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
|
||||
|
||||
# We use either TYPO (1) or WIN (2) and compare with HHEA
|
||||
# and use HHEA (0) if the fonts seems broken
|
||||
our_btb = typo_btb if use_typo else win_btb
|
||||
if our_btb == hhea_btb:
|
||||
metrics = 1 if use_typo else 2 # conforming font
|
||||
elif abs(our_btb - hhea_btb) / our_btb < 0.03:
|
||||
print("{}: Font vertical metrics slightly off ({:.1f}%)".format(projectName, (our_btb - hhea_btb) / our_btb * 100.0))
|
||||
metrics = 1 if use_typo else 2
|
||||
else:
|
||||
# Try the other metric
|
||||
our_btb = typo_btb if not use_typo else win_btb
|
||||
if our_btb == hhea_btb:
|
||||
print("{}: Font vertical metrics probably wrong USE TYPO METRICS, assume opposite (i.e. {})".format(projectName, not use_typo))
|
||||
use_typo = not use_typo
|
||||
self.sourceFont.os2_use_typo_metrics = 1 if use_typo else 0
|
||||
metrics = 1 if use_typo else 2
|
||||
else:
|
||||
print("{}: WARNING Font vertical metrics inconsistent ({:.1f}%), using HHEA".format(projectName, (our_btb - hhea_btb) / our_btb * 100.0))
|
||||
our_btb = hhea_btb
|
||||
metrics = 0
|
||||
|
||||
# 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}
|
||||
|
||||
if metrics == 0:
|
||||
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)
|
||||
elif metrics == 1:
|
||||
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)
|
||||
else:
|
||||
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)
|
||||
|
||||
# Calculate font height
|
||||
self.font_dim['height'] = -self.font_dim['ymin'] + self.font_dim['ymax']
|
||||
|
@ -950,26 +989,21 @@ class font_patcher:
|
|||
'width' : self.sourceFont.em,
|
||||
'height': self.sourceFont.descent + self.sourceFont.ascent,
|
||||
}
|
||||
elif self.font_dim['height'] < 0:
|
||||
sys.exit("{}: Can not detect sane font height".format(projectName))
|
||||
|
||||
# Line gap add extra space on the bottom of the line which
|
||||
# doesn't allow the powerline glyphs to fill the entire line.
|
||||
# Put half of the gap into the 'cell', each top and bottom
|
||||
gap = max(self.sourceFont.hhea_linegap, self.sourceFont.os2_typolinegap) # TODO probably wrong
|
||||
if self.sourceFont.os2_use_typo_metrics:
|
||||
gap = self.sourceFont.os2_typolinegap
|
||||
self.sourceFont.hhea_linegap = 0
|
||||
# Make all metrics equal
|
||||
self.sourceFont.os2_typolinegap = 0
|
||||
if gap > 0:
|
||||
gap_top = int(gap / 2)
|
||||
gap_bottom = gap - gap_top
|
||||
print("Redistributing line gap of {} ({} top and {} bottom)".format(gap, gap_top, gap_bottom))
|
||||
self.font_dim['ymin'] -= gap_bottom
|
||||
self.font_dim['ymax'] += gap_top
|
||||
self.font_dim['height'] = -self.font_dim['ymin'] + self.font_dim['ymax']
|
||||
self.sourceFont.os2_typoascent = self.sourceFont.os2_typoascent + gap_top
|
||||
self.sourceFont.os2_typodescent = self.sourceFont.os2_typodescent - gap_bottom
|
||||
# TODO Check what to do with win and hhea values
|
||||
self.sourceFont.os2_typoascent = self.font_dim['ymax']
|
||||
self.sourceFont.os2_typodescent = self.font_dim['ymin']
|
||||
self.sourceFont.os2_winascent = self.sourceFont.os2_typoascent
|
||||
self.sourceFont.os2_windescent = -self.sourceFont.os2_typodescent
|
||||
self.sourceFont.hhea_ascent = self.sourceFont.os2_typoascent
|
||||
self.sourceFont.hhea_descent = self.sourceFont.os2_typodescent
|
||||
self.sourceFont.hhea_linegap = self.sourceFont.os2_typolinegap
|
||||
self.sourceFont.os2_use_typo_metrics = 1
|
||||
|
||||
# Step 2
|
||||
# Find the biggest char width and advance width
|
||||
# 0x00-0x17f is the Latin Extended-A range
|
||||
warned = self.args.quiet or self.args.nonmono # Do not warn if quiet or proportional target
|
||||
|
@ -1379,6 +1413,20 @@ class font_patcher:
|
|||
return None
|
||||
|
||||
|
||||
def half_gap(gap, top):
|
||||
""" Divides integer value into two new integers """
|
||||
# Line gap add extra space on the bottom of the line which
|
||||
# doesn't allow the powerline glyphs to fill the entire line.
|
||||
# Put half of the gap into the 'cell', each top and bottom
|
||||
if gap <= 0:
|
||||
return 0
|
||||
gap_top = int(gap / 2)
|
||||
gap_bottom = gap - gap_top
|
||||
if top:
|
||||
print("Redistributing line gap of {} ({} top and {} bottom)".format(gap, gap_top, gap_bottom))
|
||||
return gap_top
|
||||
return gap_bottom
|
||||
|
||||
def replace_font_name(font_name, replacement_dict):
|
||||
""" Replaces all keys with vals from replacement_dict in font_name. """
|
||||
for key, val in replacement_dict.items():
|
||||
|
|
Loading…
Reference in a new issue