5 Glyphs and Metrics
dxtr edited this page 2026-10-18 16:08:49 +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.

Glyphs and metrics

Each face has one glyph slot (see Core concepts). Loading a glyph replaces what was there, and the readers on this page report on the glyph loaded last.

Loading

load-glyph face glyph-index &key flags (target :normal) → glyph-index

Loads glyph glyph-index into the face's slot at the current size, transform and variation. Returns glyph-index.

An index outside 0 to face-num-glyphs − 1 signals :invalid-glyph-index before FreeType is called:

(ft2:load-glyph face 999999)
;; error: Glyph index 999999 is out of range: DejaVu Sans has 6253 glyphs.
;;        Glyph indexes run from 0 below FACE-NUM-GLYPHS; CHAR-INDEX gives the
;;        glyph for a character.

Use load-glyph for glyph indexes that come from a shaper such as HarfBuzz.

load-char face char &key flags (target :normal) → glyph-index

Loads the glyph for char, a character or an integer code in the current charmap. Returns the glyph index, which is 0 if the face lacks the character. In that case the .notdef glyph, often a box, is what gets loaded.

Load flags

flags is a list of keywords. An unknown keyword signals a type-error that lists the valid ones.

Flag Effect
:no-scale Do not scale: metrics, advance and outline stay in font units. Implies :no-hinting and :no-bitmap. cl-ft2 reports font units for this glyph.
:no-hinting Do not hint (grid-fit) the outline.
:render Render to a bitmap right after loading, in the render mode that matches target.
:no-bitmap Ignore embedded bitmap strikes and always load the outline.
:vertical-layout Load for vertical text: glyph-advance is vertical.
:force-autohint Use FreeType's auto-hinter even when the font has its own hints.
:crop-bitmap Obsolete; ignored.
:pedantic Treat minor font errors as errors.
:ignore-global-advance-width Ignore the hhea advance for monospaced fonts. Rarely useful.
:no-recurse Do not load the components of a composite glyph. The glyph format becomes :composite.
:ignore-transform Ignore the face's transform (face-transform-matrix, face-transform-delta).
:monochrome With :render, render a 1-bit bitmap. Prefer :target :mono.
:linear-design Keep glyph-linear-advance in font units.
:sbits-only Load embedded bitmaps only, never outlines.
:no-autohint Never use the auto-hinter.
:color Load color glyphs (COLRv0 layers, CBDT/sbix bitmaps) as :bgra bitmaps.
:compute-metrics Compute metrics from the outline rather than trusting the font's.
:bitmap-metrics-only Load only the metrics of a bitmap glyph, not its pixels.
:no-svg Ignore SVG glyphs.

Hinting targets

target selects the hinting algorithm. It is stored in bits 16–19 of the load flags (FT_LOAD_TARGET_…), and cl-ft2 combines the two for you:

Target Hinting
:normal Default hinting for antialiased rendering.
:light Light, vertical-only hinting. Glyph shapes and horizontal advances stay close to the unhinted design, so it matches unhinted layout from a shaper.
:mono Strong hinting for 1-bit rendering.
:lcd Hinting for horizontal LCD subpixel rendering.
:lcd-v Hinting for vertical LCD subpixel rendering.

These keywords make up the type hinting-target; anything else is a type-error. char-bitmap and glyph-index-bitmap choose the target that suits the render mode for you (see Rendering and bitmaps).

(ft2:load-char face #\A :target :light)
(ft2:load-char face #\A :flags '(:no-hinting))
(ft2:load-char face #\A :flags '(:no-scale))      ; design units
(ft2:load-char face #\😀 :flags '(:color))         ; color emoji fonts

Reading the slot

These readers are generic functions of a glyph source: a face, meaning the glyph in its slot, or a glyph object, which reports the values it was loaded with.

glyph-index source → integer

The glyph's index. Note that this does not look a character up; that is char-index.

glyph-format source → keyword

:outline, :bitmap, :composite, :svg or :plotter. A scalable font loads as :outline. After rendering, or for a bitmap font, it is :bitmap.

glyph-metrics source → glyph-metrics

The glyph's metrics, in pixels, or in font units after :no-scale. Bearings are measured from the pen position to the glyph's bounding box. All accessors return reals:

Accessor Meaning
glyph-metrics-width, glyph-metrics-height size of the glyph's bounding box
glyph-metrics-hori-bearing-x horizontal layout: pen x to the box's left edge
glyph-metrics-hori-bearing-y horizontal layout: baseline to the box's top edge (up is positive)
glyph-metrics-hori-advance horizontal advance
glyph-metrics-vert-bearing-x vertical layout: pen x to the box's left edge
glyph-metrics-vert-bearing-y vertical layout: pen y to the box's top edge
glyph-metrics-vert-advance vertical advance
(setf (ft2:face-size face) 32)
(ft2:load-char face #\A)
(ft2:glyph-metrics face)
;; => #S(GLYPH-METRICS :WIDTH 22 :HEIGHT 23 :HORI-BEARING-X 0 :HORI-BEARING-Y 23
;;                     :HORI-ADVANCE 22 :VERT-BEARING-X -11 :VERT-BEARING-Y 4
;;                     :VERT-ADVANCE 32)

(ft2:load-char face #\A :flags '(:no-scale))
(ft2:glyph-metrics face)
;; => #S(GLYPH-METRICS :WIDTH 1368 :HEIGHT 1493 :HORI-BEARING-X 16 :HORI-BEARING-Y 1493
;;                     :HORI-ADVANCE 1401 :VERT-BEARING-X -684 :VERT-BEARING-Y 277
;;                     :VERT-ADVANCE 2048)

With hinting (the default), FreeType rounds the metrics to whole pixels, so they come back as integers.

glyph-advance source → x, y

The advance vector, as two values. For the slot, this is after hinting and after the transform: with a 90° rotation, the advance of l changes from 9, 0 to 0, 9.

(ft2:load-char face #\A)
(ft2:glyph-advance face)          ; => 22, 0

glyph-linear-advance source → horizontal, vertical

The unhinted advances, as two values: pixels, or font units if the glyph was loaded with :linear-design. Only meaningful for scalable faces. Use these to lay out unhinted text.

(ft2:glyph-linear-advance face)   ; => 1401/64, 32

Advances without loading

glyph-index-advance face glyph-index &key flags (target :normal) → real

The advance of a glyph without loading it into the slot, which leaves the slot alone and is much faster when you only need widths. It is horizontal unless flags contains :vertical-layout, and in pixels unless flags contains :no-scale, which gives font units. flags and target are as for load-glyph, and hinting affects the result in the same way.

(ft2:glyph-index-advance face 36)                                ; => 22
(ft2:glyph-index-advance face 36 :flags '(:no-scale))            ; => 1401
(ft2:glyph-index-advance face 36 :flags '(:vertical-layout))     ; => 32

Measuring a string's width:

(loop for ch across "Hello" sum (ft2:glyph-index-advance face (ft2:char-index face ch)))

Kerning

kerning face left-glyph right-glyph &key (mode :default) → x, y

The kerning adjustment to add to the pen between two glyphs, as two values:

Mode Result
:default grid-fitted pixels
:unfitted unrounded pixels
:unscaled font units

The modes make up the type kerning-mode.

(let ((a (ft2:char-index face #\A)) (v (ft2:char-index face #\V)))
  (list (ft2:kerning face a v)
        (ft2:kerning face a v :mode :unfitted)
        (ft2:kerning face a v :mode :unscaled)))
;; => (-2 -131/64 -131)

Faces without kerning data return 0, 0. Only the legacy TrueType kern table is read. Most modern OpenType fonts keep their kerning in the GPOS table, which only a shaper can apply. For real text, shape with HarfBuzz and render the glyph indexes and positions it produces (see Scope and limitations).

Both glyph indexes are range-checked like load-glyph's.