Created by: gwideman, Jul 9, 2013 9:21 pm
Revised by: gwideman, Nov 5, 2013 4:02 pm (28 revisions)

Introduction

This article captures some notes on font vertical metrics, with particular attention to how the space between rows of text is specified.
My original quest was to adjust my Windows console (Cmd.exe, powershell or what-have-you) environment for better readability, by introducing more whitespace (er, blackspace?) between lines of text. This was motivated by impending sessions with python command-line operations, iPython and so on.
To my chagrin, not only do cmd.exe and powershell lack a straightforward setting to adjust line spacing, but so did every other shell-replacement product I could find.
So, I thought, why not just select a favored monospace console font, and hack its definition so as to specify more overall height, while maintaining the existing height dedicated to the visible part of the character?

Plan of attack

I decided to work with TrueType font Consolas, which I liked the best out of fonts available in cmd.exe and powershell. I expected to be able to load the font into a tool, which would reveal whatever vertical adjustments were available for fiddling, and I could fiddle my way to a solution. It turns out to be a little more complicated.

Initial fiddling with tools

  • FontForge: I installed FontForge on my Linux machine. I opened a copy of the consolas font file (consola.ttf), and tried some adjusting, interleaved with copying the edited file back to Windows, and trying it in cmd.exe. This process was disrupted by automatic changes that FontForge would make that I hadn't asked for and didn't know how to control. It's possible that if I was more familiar with FontForge I'd have been able to master this. Instead I decided to try a Windows-hosted commercial tool.
    • One specific problem with FontForge is that it shows the various vertical metric parameters in either relative or absolute form (checkbox to select which). It was not clear at the time whether this reflected alternative underlying font data, or simply calculation convenience in the FontForge UI. It turns out to be the latter, but this added considerable confusion in the early going.
  • FontCreator: The free version seemed to show an orderly and comprehensible display of the relevant parameters, and overall I liked the UI. It turns out that the demo version won't save results of work. So I sprang for the paid "home" version to be able to proceed.
    • See later notes for problems with FontCreator's automatic behavior, later overcome with an update.

TrueType font vertical parameters

A TrueType file contains a number of parameters relating to vertical metrics.
TrueType table
Param set
Origin [1]
Parameter name
Description
Font rendering role



UPM

"font geometry Units per Em", typically 2048 or 1000. Establishes the font geometry coordinate space scaling. When painting text, an application will specify how large an Em is in screen units. The font-rendering service will then draw the font geometry (which is internally in units 1/2048 or 1/1000 of that) accordingly.
OS/2
usWin
Windows ancient






Ascent
Top extent of font
  • Some application software uses this as the top clipping boundary.
  • Some application software uses Ascent+Descent as default line-to-line spacing



Descent
Bottom extent of font
  • Some application software uses this as the bottom clipping boundary.
OS/2
sTypo
Windows newer






Ascender
Top of ascenders
Varies



Descender
Bottom of descenders
Varies



LineGap
Vague
Varies
hhea
hhea
Apple






ascent
Top of ascenders
Varies



descent
Bottom of descenders
Varies



lineGap
Vague
Varies
[Note 1] I think it's safe to assume that Windows software uses only the Windows metrics, and Mac software uses only the hhea metrics. However, since it's up to the application software to interpret these values (particularly the distance between rows), software which is cross-platform might try to be extra clever and use all of the parameters in some way.

Interpretation issues

It would have been helpful if the standards bodies provided authoritative definitions for what all these variables mean, with application developers following those definitions. However, that is not what's happened.
The vertical metrics parameters in the font file are used by application software when it renders text to the screen to determine how to position lines of text relative to boundaries above and below, and one line of text relative to the line above or below. So though an application calls OS routines to render a string of text (character, or string up to an entire line), it is the application that determines the vertical positioning of that text, and hence the space between lines of text.
Application developers have had to experiment to get the line-spacing appearance they want, based on how font designers have set these vertical metric values. In turn, font designers have presumably adjusted these values in order to get desirable line-spacing results from common software.
This has not converged, and continues to generate discussion to this day as to how these values should be interpreted, particularly to get consistent results cross-platform.

Some interpretations examined

The sections below list some online posts which seem to be referenced frequently.

Vertical metrics landmarks

As a basis for diagramming the different interpretations, I have used a consistent background graphic for each one.
vertfontmetrics-00-base.png

Description of landmarks

The graphic and table describe several landmarks. Baseline, ascender and descender and widely recognized terms, while the limits and boundaries are less so. These landmarks pertain most directly to European character sets, less so to Arabic and Asian characters. (Hence fonts that contain characters from two or more of these groups have special challenges.)
Sticking with European-based character sets, one confounding factor is that some of the landmarks may be thought of as "visual reference lines" with respect to which typographic features are positioned (a feature could stretch beyond the line for visual purposes), whereas software may need boundaries at which it is safe to clip.
Feature
Description
Base
or baseline. This is the line which characters "sit upon". Characters with rounded bottoms may overlap the line slightly to look visually aligned with flat-bottom characters
Ascender
Top of characters like "b" and lower-case "L". There is a separate Cap Height, which in most (but not all) fonts is lower than the ascender height
Descender
Bottom of characters like "p" which hang below the baseline. Characters with rounded bottoms ("g", "y") may dip slightly lower
High and Low limits
I am using these values to refer to the limits of "ink" (including adornments like accents).
High and Low Boundaries (and Gaps)
I am using these terms to indicate where the default gap between lines is accounted for. The other landmarks are important for the font-rendering service (ie: not the application per se), while the high and low boundaries would be used by the application to determine vertical line positioning of one line relative to the previous line.
For the most part, it doesn't matter how the total "gap" is distributed between the top and bottom boundaries. However, it does come in to play when positioning an initial or final row of text below or above neighboring graphics or whitespace.
I present the online references in chronological order.
NOTE: Feel free to open two browser windows to the current page if you wish to compare different interpretations side-by-side.

Typophile forum discussion "En/em dash"

2004-09-05. See John Hudson comments about Ascender and Descender values etc
My distillation
Set
Ascent/der, Descent/der
Gap
Comment
UPM



usWin
  • Some apps use WinAscent + WinDescent to determine default linespacing and clipping zone
  • ... incorrect, since WinAscent and WinDescent were not intended to be used for this purpose. But the error is so entrenched and widespread
NA

sTypo
  • TypoAscender + TypoDescender = UPM
  • TypoAscender + TypoDescender + TypoLineGap = WinAscent + WinDescent
?

hhea
  • hheaAscender = WinAscent ; hheaDescender = WinDescent
0


vertfontmetrics-01-hudson-orig.png
Notes:
  • I have shown UPM some arbitrary amount larger than measured Ascender...Descender, and Typo values agreeing with that.

Typophile: John Hudson. Setting Cross-Platform Vertical Metrics

John Hudson article. Post date says 2005-06-14, but "final update" says 2003-06-07. The year 2003 may be a typo.

Original recommendation:

Set
Ascent/der, Descent/der
Gap
Comment
UPM
[Note 1]


usWin
WinAscent + WinDescent = UPM * 1.2 to 1.25
NA

sTypo
  • TypoAsc+TypoDesc = UPM [Note 2]
  • TypoAscender + TypoDescender + TypoLineGap = WinAscent + WinDescent
?

hhea
hheaAscender = TypoAscender; hheaDescender = TypoDescender
hheaLineGap = TypoLineGap

Note 1: Example uses a UPM that is only slightly greater than ascender+descender, so this scheme apparently doesn't think UPM should include accents above capital letters, for example.
Note 2: Article says: If measured ascender+descender < UPM, then distribute excess UPM to TypoAscender and TypoDescender equally. I have shown that in the figure.
vertfontmetrics-02-hudson-xplat-orig.png

Update final recommendations

The main difference is in recommendation for hhea values for cross-platform compatibility.
Set
Ascent/der, Descent/der
Gap
Comment
UPM
[Note 1, as in original recommendation]


usWin
WinAscent + WinDescent = UPM * 1.2 to 1.25
NA
Sums equal
sTypo
  • TypoAsc+TypoDesc = UPM [Note 2, as in original recommendation]
  • TypoAscender + TypoDescender + TypoLineGap = WinAscent + WinDescent
?
Sums equal
hhea
hheaAscender = usWinAscent; hheaDescender = usWinDescent
hheaLineGap = 0
Sums equal
x
vertfontmetrics-03-hudson-xplat-update.png

Karsten Lucke Font Metrics

http://www.kltf.de/downloads/FontMetrics-kltf.pdf
v1.0.7. Not sure of date, but references John Hudson quoting Read Roberts
See PDF diagram for details of Lucke's interpretation of the parameters and their totals. The UI displayed is likely FontLab, and thus this article introduces an additional set of parameters: "Key dimensions" which are not TrueType parameters, but from which FontLab calculates the TrueType parameters. Here is my interpretation of Lucke:
vertfontmetrics-04-lucke.png
Notes:
  • Lucke places all of the gap at the bottom of the font region, so in the graphic top boundary is the same as Hi Lim.
  • Lucke draws UPM as equal to measured Ascender+Descender. Lucke's diagram shows no separate Lo Lim, so Lo Lim = Desc.

Typophile selfbuildtype Vertical Metrics Calculator

2010-06-10 This post introduces an Excel spreadsheet which is intended to implement the thinking described by John Hudson in "Setting Cross-Platform Vertical Metrics", including separate calculations for the original and updated thinking.

Spreadsheet "Hudson original"

Set
Ascent/der, Descent/der
Gap
Comment
UPM
Example shows UPM = Hi Lim to Low Lim [Note 1]


usWin
WinAscent + WinDescent = UPM * Linespace Factor (Example:1.25)
NA
Sums equal
sTypo
  • TypoAscender+TypoDescender = UPM [Note 2]
  • TypoAscender + TypoDescender + TypoLineGap = WinAscent + WinDescent
?
Sums equal
hhea
hheaAscender = TypoAscender; hheaDescender = TypoDescender
hheaLineGap = TypoLineGap
Sums equal
Note 1: Although not specified in a formula, the example values show UPM = 2048 = Hi Lim + Lo Lim. This is the most extreme interpretation of UPM. Or to put it another way, this model expects all character features to be drawn within UPM, which results in the smallest characters, relative to the other interpretations discussed on this page.
Note 2: To the extent that UPM exceeds measured ascender+descender, the spreadsheet distributes the excess to TypeAscender and TypoDescender equally, per Hudson. However, since the spreadsheet is using an extreme interpretation of UPM, this scheme has a larger "excess UPM". The excess UPM at the top is apt to be substantially larger than at the bottom, so it would seem sensible to allocate more of the excess to TypoAscender than to TypeDescender. Instead, this scheme splits the UPM excess equally to the two Typo variables, resulting in TypoAscender relative short, TypoDescender relatively long.
vertfontmetrics-05-selfbuildtype-hudson-orig.png
Comments
As described in Notes 1 and 2, the extreme interpretation of UPM would results in small characters and a peculiar distribution of "excess UPM" to Typo Ascender and Descender (and thus to hhea values).

Spreadsheet "Hudson update"

The main difference here is the revision of the hhea parameters to agree with usWin instead of sType values.
Set
Ascent/der, Descent/der
Gap
Comment
UPM
Example shows UPM = Hi Lim to Low Lim [Note 1, as in original]


usWin
WinAscent + WinDescent = UPM * Linespace Factor (Example:1.25)
NA
Sums equal
sTypo
  • TypoAscender+TypoDescender = UPM [Note 2]
  • TypoAscender + TypoDescender + TypoLineGap = WinAscent + WinDescent
?
Sums equal
hhea
hheaAscender = usWinAscent; hheaDescender = usWinDescent
hheaLineGap = 0
Sums equal
vertfontmetrics-06-selfbuildtype-hudson-update.png
Comments
While settling on the same cross-platform compromise (hhea = usWin values) as Hudson and Lucke, this scheme retains, from the earlier spreadsheet, the same extreme interpretation of UPM and thus peculiar distribution of "excess UPM".

Examples

Some dimensions from example fonts. Each is the "regular" version of the font.


Measured
Win
Typo
hhea

Font
UPM
Top A
Top A hat
Top b
Bot p
Topb - Botp
Top
Ahat -Botp
Asc ent
Desc ent
Tot
Asc' der
Desc' der
Gap
Tot
Asc' der
Desc' der
Gap
Tot
Comments
Arial.ttf
2048
1466
1836
1466
-407
1873
2243
1854
-434
2288
1491
-431
307
2229
1854
-434
67
2355
???
Tahoma
2048
1488
2028
1555
-412
1967
2440
2049
-423
2472
1566
-423
59
2048
2049
-423
0
2472
hhea matches Win
Calibri
2048
1300
1688
1393
-363
1756
2051
1950
-550
2500
1536
-512
452
2500
1536
-512
452
2500
hhea matches Typo; totals match; (Hudson original)
Segoe UI
2048
1434
1897
1517
-470
1987
2367
2210
-514
2724
1491
-431
269
2191
2210
514
0
2724
hhea matches Win
Georgia
2048
1439
1867
1547
-444
1991
2311
1878
-449
2327
1549
-444
198
2191
1878
-449
0
2327
hhea matches Win
Consolas
2048
1308
1660
1414
-410
1824
2070
1884
-514
2398
1521
-527
350
2398
1521
-527
350
2398
hhea matches Typo;
totals match; Asc+Desc=UPM;
(Hudson original)
Adobe Garamond Pro
1000
674
841
714
-260
974
1101
917
-354
1271
725
-275
200
1200
725
-275
200
1200
hhea matches Typo
Of these fonts, none completely matches Hudson's update recommendations.
  • Several have hhea parameters matching usWin parameters, with hheaLineGap = 0
  • A couple have all three totals matching
  • A couple have hhea parameters matching Typo parameters, as in Hudson original recommendations

Applied to Consolas

After all that, how to modify Consolas to prompt cmd.exe (and powershell) to give us larger gaps between lines?
My goal was to add something like 10% to 20% additional line spacing. So with default line spacing at ~2400, the example here shows how to add 20%, (about 500 units), distributed equally above and below baseline. I will stick with the scheme in which hhea matches Typo.


Measured
Win
Typo
hhea

Font
UPM
Top A
Top A hat
Top b
Bot p
Topb - Botp
Top
Ahat -Botp
Asc ent
Desc ent
Tot
Asc' der
Desc' der
Gap
Tot
Asc' der
Desc' der
Gap
Tot
Comments
Consolas
2048
1308
1660
1414
-410
1824
2070
1884
-514
2398
1521
-527
350
2398
1521
-527
350
2398
hhea matches Typo; totals match; Asc+Desc=UPM;(Hudson original)
Consolas +20% line spacing
2048
"
"
"
"
"
"
2134
-764
2898
1521
-527
850
2898
1521
-527
850
2898

Samples

The following screenshots are from cmd.exe.
No modification: Consolas 14pt:
vertfontmetrics-10-testdoc-consreg-0pct-14pt.png
ConsolasGW 18pt:
vertfontmetrics-11-testdoc-consgw-20pct-18pt.png

Note:

It appears that cmd.exe scales the total font height (probably usWinAscent+usWinDescent) to the point size selected in the font dialog. So to get approximately equivalent character sizes, I selected 14pt when using the system Consolas font, and 18pt when using the ConsolasGW modified font.

Wrinkles

Minor problem with FontCreator

During testing, my sequence was to use FontCreator to make an edit to a copy of consola.ttf, then export and install this modified font. However, the newly exported font would not appear as a choice in cmd.exe, and further, would appear in Windows' Fonts folder with Asian characters in its icon. So FontCreator was changing something that made Windows believe this was an Asian font. This Microsoft article provided part of the answer: Necessary criteria for fonts to be available in a command window
Note the additional criteria for Asian fonts. Since Consolas would presumably not meet those criteria, if Windows thought the new font was Asian that would prevent it appearing as a choice in cmd.exe.
To get further, I obtained Python Font Tools and used it to convert to XML an original copy of consola.ttf, and a copy which I'd loaded and saved with FontCreator. I then used a text diff tool to see if I could spot a salient difference. I found that FontCreator was producing new values for a field which corresponds to FontCreator's "Code Page Character Ranges" settings, adding several ranges not flagged in consola.ttf. I pursued this in a forum post, which resulted in a bug fix.

Problem replacing installed font

When trying successive versions of font modifications, I initially found it difficult to uninstall (from Windows Fonts) an installed font as Windows would report the font in use. Googling for solutions to this problem I was discouraged by many reports of the gymnastics that some users had to perform in this situation.
However, in my case, I discovered that many applications keep fonts in use that they aren't actually using in any open documents. This is perhaps because they have loaded the font so that it can appear on a font menu and so forth. So I discovered that my test fonts could be uninstalled or replaced if I closed all open apps. I gradually learned which apps were safe to leave open during font replacement.

Other References


Microsoft Typography Specifications http://www.microsoft.com/typography/SpecificationsOverview.mspx
TrueType Reference Manual https://developer.apple.com/fonts/TTRefMan/