head, hhea, post: three small tables
Last updated 2026-11-02
On this page
head, hhea and post hold a dozen fields each, and their names do not look as tidy as OS/2. But they decide how fine the grid is, how tall a line is, how far italic leans and where the underline sits. They are covered together because they are usually read together.
head: global settings
| Field | Meaning |
|---|---|
unitsPerEm |
The scale of font units. Usually 1000 (CFF) or 2048 (TrueType); valid range 16–16384 |
xMin / yMin / xMax / yMax |
Overall bounding box of all outlines |
macStyle |
Bits: 0 bold, 1 italic, 2 underline, 3 outline, 4 shadow, 5 condensed, 6 extended |
fontRevision |
Numeric revision (unrelated to the version string in name) |
indexToLocFormat |
Whether loca uses short or long offsets |
magicNumber |
Fixed 0x5F0F3CF5, used to confirm this really is a font |
created / modified |
Timestamps, seconds since 1904 |
unitsPerEm is the first key to reading any metrics drawing: every coordinate in the font is counted in these units, not pixels. At 16px, one unit in a font with unitsPerEm = 2048 is 16 / 2048 of a pixel.
macStyle and OS/2's fsSelection say the same things in two dialects: the old Mac way and the Windows way. Read fsSelection first and keep macStyle as a fallback.
hhea: the horizontal baseline trio
| Field | Meaning |
|---|---|
ascender |
Typographic ascent (positive) |
descender |
Typographic descent (usually negative) |
lineGap |
Suggested extra gap between lines |
advanceWidthMax |
Widest advance in the font |
numberOfHMetrics |
Entries in hmtx; the rest repeat the last one |
caretSlopeRise / Run |
Caret angle, used to draw a slanted insertion bar in italics |
Many renderers treat ascender + |descender| + lineGap as "the font's own line height". But OS/2 carries two more sets (sTypo* and usWin*) — which one counts depends on bit 7 of fsSelection. Different line heights on macOS and Windows usually come from exactly that choice.
post: italics and underlines
| Field | Meaning |
|---|---|
italicAngle |
Slope in degrees, counter-clockwise positive; a forward-leaning italic is negative (often −12) |
underlinePosition |
Distance from baseline to the top of the underline; negative means below the baseline |
underlineThickness |
How thick the underline is |
isFixedPitch |
Whether the font is monospaced |
| Glyph names | Only in version 2.0 — names such as A or uni4E2D |
italicAngle is often used as circumstantial evidence for "is this a real italic": true italics almost always write a non-zero angle, while a slanted upright might write 0 or something arbitrary. It cannot be the only test, but combined with fsSelection it beats reading the name.
Three sign conventions not to flip
This is where metrics drawings most often go wrong:
| Value | Actual direction |
|---|---|
hhea.descender |
Negative (below baseline) |
OS/2.sTypoDescender |
Negative |
OS/2.usWinDescent |
Positive — it is "how far down", not a coordinate |
post.underlinePosition |
Negative (below baseline) |
post.italicAngle |
Negative = leaning right |
This site normalises all of these into one "y up is negative" font coordinate system in shared/src/fonts/metrics.ts; components never flip them again. Mixing the two conventions flips or mirrors the whole drawing.
What these three do not cover
- Whether a character exists:
cmap; - How many glyphs:
maxp; - Weight and x-height:
OS/2.
Further reading
- OpenType spec: the
head,hheaandpostsections - Apple TrueType Reference Manual: the original
head/postdefinitions