6 Fonts and Metrics
dxtr edited this page 2026-10-18 16:07:14 +02:00
This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Fonts and metrics

A font is a face at a scale and variation. Shaping, outlines, paint and all metrics take a font, and report in the font's units.

Making fonts

make-font face → font

A new font for face at a scale of the face's units per EM, so it reports font units. ppem and point size are unset (0). For a variable face the font starts at the default coordinates.

with-font (var face) &body body

Binds var to (make-font face) and destroys it on exit.

destroy-font font (generic)

Releases the font, and the face font-face returns. Destroying an already destroyed font does nothing. For an ft2-font it also unregisters the font from its cl-ft2 face.

font-live-p font → boolean

font-face font → face

The face the font was made from, for face queries such as face-units-per-em or face-name:

(hb:face-units-per-em (hb:font-face font))                   ; => 2048
(hb:face-name (hb:font-face font) :font-family)      ; => "DejaVu Sans"

It is a face object of its own, not the one passed to make-font, and it belongs to the font: it stays usable as long as the font does, even after the face passed to make-font has been destroyed, and destroy-font releases it, so do not destroy it yourself. For an ft2-font it is the face HarfBuzz made from the cl-ft2 face (in font units, like any face). It may be shared between threads, like the font. Signals harfbuzz-error if the font has been destroyed.

font-handle font → foreign pointer

The raw hb_font_t* for cl-harfbuzz/ffi; valid until destroy-font.

#<CL-HARFBUZZ:FONT scale 2048x2048 {12042D5233}>
#<CL-HARFBUZZ/FT2:FT2-FONT scale 2048x2048 {1202FEE723}>   ; 32 px × 64
#<CL-HARFBUZZ:FONT destroyed {1204705033}>

Scale

font-scale font → x, y — setf-able

The number of scale units per EM, horizontally and vertically, as two values. Default: face-units-per-em for both. Set it from a signed 32-bit integer (both axes) or a list (x y) of them:

(setf (hb:font-scale font) 1024)          ; half of DejaVu's 2048
(hb:font-scale font)                      ; => 1024, 1024
(hb:shape-text font "AV")                 ; x-advances 636, 701 instead of 1270, 1401
(setf (hb:font-scale font) '(2048 1024))  ; stretch horizontally

Everything the font reports scales with it, rounded to integers by HarfBuzz. A common choice is pixels × 64, which gives 26.6 fixed point you then divide by 64 yourself; with an ft2-font that division is done for you. A negative scale mirrors the axis.

Do not set the scale of an ft2-font: it follows the cl-ft2 face's size, and is overwritten whenever the face changes. Set ft2:face-size instead.

font-ppem font → x, y — setf-able

Pixels per EM, two values; 0 means unset. Used for hinting (when the font is hinted, which plain fonts are not) and for choosing a bitmap strike (color emoji in CBDT/sbix, glyph-png). Set from an unsigned 32-bit integer or a list (x y) of them.

font-point-size font → real — setf-able

Point size, 0 if unset. Used for the AAT trak (tracking) table. HarfBuzz does not set the opsz axis from the point size, so set that axis yourself (see Font variations). Set from a non-negative real.

(setf (hb:font-ppem font) 16 (hb:font-point-size font) 12)
(hb:font-ppem font)  ; => 16, 16
(hb:font-point-size font)  ; => 12

Glyph lookup

font-char-glyph font char → glyph or nil

The glyph the font's cmap maps char (a character or a code point integer) to, without shaping, or nil if the font has none. Glyphs are numbered as HarfBuzz numbers them, non-negative integers below 2³², the type glyph-index, which every function that reads a glyph takes.

(hb:font-char-glyph font #\A)        ; => 36
(hb:font-char-glyph font #x1F600)    ; => 5857   (DejaVu has a monochrome 😀)
(hb:font-char-glyph font #\U+E000)   ; => NIL

Use it to test coverage (font fallback), or to find a glyph to pass to glyph-outline. For text, shape instead: font-char-glyph ignores ligatures, contextual forms, variation selectors and normalization.

font-glyph-name font glyph → string or nil

font-glyph-from-name font name → glyph or nil

Glyph names from the post or CFF table.

(hb:font-glyph-name font 36)         ; => "A"
(hb:font-glyph-from-name font "A")   ; => 36
(hb:font-glyph-name font 99999)      ; => NIL

Glyph metrics

font-glyph-advance font glyph &key vertical → number

The glyph's horizontal advance, or vertical advance if vertical is true, before any shaping (no kerning). Vertical advances are negative (y up, text runs down).

(hb:font-glyph-advance font 36)              ; => 1401
(hb:font-glyph-advance font 36 :vertical t)  ; => -2384

font-glyph-extents font glyph → xmin, ymin, xmax, ymax or nil

The ink bounding box as four values, relative to the glyph origin, y up: the same form as cl-ft2:glyph-control-box. nil if the font has no extents for the glyph. A blank glyph such as space returns four zeros. With a mirrored (negative) scale the box is mirrored but still runs from min to max.

(hb:font-glyph-extents font 36)   ; => 16, 0, 1384, 1493   (A stands on the baseline)

Font-wide metrics

font-extents font &key vertical → ascender, descender, line-gap

Line metrics for horizontal layout (from OS/2 typo metrics if the font says to use them, else hhea), or vertical layout (vhea) if vertical is true. The descender is usually negative. The default line height is ascender - descender + line-gap.

(hb:font-extents font)              ; => 1901, -483, 0
(hb:font-extents font :vertical t)  ; => 0, 0, 0   (DejaVu has no vhea)

font-metric font metric → number or nil

One OpenType metric from OS/2, hhea, vhea or post, with variations applied (MVAR), or nil if the font does not define it.

Metric keyword Meaning
:horizontal-ascender, :horizontal-descender, :horizontal-line-gap typographic line metrics
:horizontal-clipping-ascent, :horizontal-clipping-descent usWinAscent / usWinDescent: the box beyond which renderers may clip
:vertical-ascender, :vertical-descender, :vertical-line-gap vertical line metrics
:horizontal-caret-rise, :horizontal-caret-run, :horizontal-caret-offset caret slope (rise/run) and offset, for italic carets
:vertical-caret-rise, :vertical-caret-run, :vertical-caret-offset the same for vertical text
:x-height, :cap-height from OS/2 version 2+
:subscript-em-x-size, :subscript-em-y-size, :subscript-em-x-offset, :subscript-em-y-offset synthetic subscript size and position
:superscript-em-x-size, :superscript-em-y-size, :superscript-em-x-offset, :superscript-em-y-offset synthetic superscript size and position
:strikeout-size, :strikeout-offset strike-through thickness and position
:underline-size, :underline-offset underline thickness and position (negative = below baseline)
(hb:font-metric font :underline-offset)   ; => -40
(hb:font-metric font :x-height)           ; => NIL   (DejaVu's OS/2 table is version 1)

These keywords make up the type metric; an unknown one signals a type-error listing the valid ones.

Other font functions