3 Character Maps
dxtr edited this page 2026-10-18 16:08:49 +02:00

Character maps

A charmap maps character codes to glyph indexes. Most fonts have several, for different platforms and encodings. FreeType selects a Unicode charmap automatically when the face has one, so for most fonts char-index with a Lisp character just works.

Looking up glyphs

char-index face char → glyph index

The glyph index for char in the current charmap, or 0 (the .notdef glyph) if the face has no glyph for it. char is a character, which uses its char-code, or a non-negative integer code in the current charmap: the type character-or-code, which load-char and char-bitmap take too.

(ft2:char-index face #\A)          ; => 36
(ft2:char-index face #x4E2D)       ; => 0: DejaVu Sans has no CJK ideographs

Test for 0 to implement font fallback:

(find-if (lambda (face) (plusp (ft2:char-index face char))) fallback-faces)

glyph-index-name face glyph-index → string or nil

The glyph's PostScript name, or nil when the face has no glyph names (face-has-glyph-names-p). Names longer than 255 characters are truncated.

(ft2:glyph-index-name face 36)   ; => "A"

name-index face name → glyph index

The inverse of glyph-index-name: the index of the glyph named name, or 0 if there is none.

(ft2:name-index face "A")  ; => 36

Iterating

map-characters function face → nil

Calls function with (code glyph-index) for every character code mapped by the current charmap, in increasing order of code.

do-characters ((code glyph-index) face &optional result) &body body

The iteration-macro form of map-characters. body runs in an implicit block nil and tagbody, so return works.

;; Count the characters DejaVu Sans covers.
(let ((n 0))
  (ft2:do-characters ((code glyph) face n)
    (incf n)))
;; => 5918

;; Collect the first ten covered characters.
(let ((chars '()))
  (ft2:do-characters ((code glyph) face (nreverse chars))
    (push (code-char code) chars)
    (when (= (length chars) 10) (return (nreverse chars)))))
;; => (#\  #\! #\" #\# #\$ #\% #\& #\' #\( #\))

Charmaps

face-charmaps face → list of charmap

Every charmap in the face, in order.

(ft2:face-charmaps dejavu)
;; => (#S(CHARMAP :ENCODING :UNICODE     :PLATFORM-ID 0 :ENCODING-ID 3  :INDEX 0)
;;     #S(CHARMAP :ENCODING :UNICODE     :PLATFORM-ID 0 :ENCODING-ID 4  :INDEX 1)
;;     #S(CHARMAP :ENCODING :APPLE-ROMAN :PLATFORM-ID 1 :ENCODING-ID 0  :INDEX 2)
;;     #S(CHARMAP :ENCODING :UNICODE     :PLATFORM-ID 3 :ENCODING-ID 1  :INDEX 3)
;;     #S(CHARMAP :ENCODING :UNICODE     :PLATFORM-ID 3 :ENCODING-ID 10 :INDEX 4))

charmap is a read-only struct:

Accessor Meaning
charmap-encoding the encoding keyword (table below)
charmap-platform-id TrueType/OpenType platform ID: 0 Unicode, 1 Macintosh, 3 Windows
charmap-encoding-id platform-specific encoding ID. Windows 1 is the BMP, Windows 10 is full Unicode
charmap-index position in face-charmaps

face-charmap face → charmap or nil · setf

The current charmap. Above, FreeType chose index 4, the full-repertoire Unicode map.

Set it to select another charmap. The new value is one of:

  • an encoding keyword, which selects the face's charmap for that encoding. It fails with :invalid-argument if the face has none.
  • a charmap from face-charmaps, which selects exactly that one. Use this to choose between charmaps with the same encoding, such as Windows BMP and Windows full Unicode. A charmap from another face whose index this face does not have signals :invalid-charmap-handle.

The encoding keywords are:

Encoding keyword Meaning
:none no encoding
:unicode Unicode (UCS-4 codes)
:ms-symbol Microsoft Symbol
:sjis Shift JIS
:prc GB2312 / GBK
:big5 Big5
:wansung Korean Wansung
:johab Korean Johab
:adobe-standard, :adobe-expert, :adobe-custom, :adobe-latin-1 Type 1 / CFF encodings
:old-latin-2 obsolete
:apple-roman Mac Roman

These keywords make up the type encoding, which charmap-encoding returns; anything else given to (setf face-charmap) is a type-error.

(setf (ft2:face-charmap face) :apple-roman)
(ft2:char-index face 138)   ; => 166, the glyph for ä (code 138 in Mac Roman)
(setf (ft2:face-charmap face) :unicode)
(ft2:char-index face #\ä)   ; => 166, the same glyph

Selecting by charmap:

(setf (ft2:face-charmap face) (find 1 (ft2:face-charmaps face) :key #'ft2:charmap-encoding-id))

The charmap affects char-index, load-char, char-bitmap, map-characters and do-characters. Integer codes are interpreted in the current charmap, while a Lisp character always passes its char-code, which is a Unicode code point.