6 FFI Layer
dxtr edited this page 2026-10-19 18:47:30 +02:00

FFI layer

cl-harfbuzz/ffi is a direct transcription, on cl-ffi, of the part of the HarfBuzz C API that cl-harfbuzz uses. Names are the C names in Lisp spelling: hb_buffer_add_codepoints → hb-buffer-add-codepoints, hb_glyph_info_t → hb-glyph-info.

It does no error checking, no lifetime tracking and no conversion beyond cl-ffi's own (enums and bitfields become keywords). Use it for HarfBuzz features the idiomatic layer does not wrap, and see the HarfBuzz API reference for the semantics.

Connecting the layers

Function Returns
hb:face-handle face the hb_face_t*
hb:font-handle font the hb_font_t*
hb:buffer-handle buffer the hb_buffer_t*

The pointers are owned by the Lisp objects and valid until they are destroyed. If you keep a pointer beyond that, take your own reference with hb-face-reference (for fonts and buffers, bind hb_font_reference or hb_buffer_reference yourself) and release it with the matching hb-*-destroy.

;; Read the raw glyph infos of a shaped buffer without copying into structs.
(hb:with-buffer (buffer)
  (hb:buffer-add-text buffer "office")
  (hb:guess-buffer-properties buffer)
  (hb:shape font buffer)
  (cl-ffi:with-foreign-object (n :uint)
    (let ((infos (cl-harfbuzz/ffi:hb-buffer-get-glyph-infos (hb:buffer-handle buffer) n)))
      (loop for i below (cl-ffi:mem-ref n :uint)
            collect (cl-ffi:foreign-slot-value
                     (cl-ffi:mem-aptr infos '(:struct cl-harfbuzz/ffi:hb-glyph-info) i)
                     '(:struct cl-harfbuzz/ffi:hb-glyph-info) 'cl-harfbuzz/ffi:codepoint)))))
;; => (82 5044 70 72)

The library

libharfbuzz is the cl-ffi foreign library, loaded when the system loads:

Platform Tried in order
Linux and other Unix libharfbuzz.so.0, libharfbuzz.so
macOS libharfbuzz.0.dylib, libharfbuzz.dylib
Windows native/windows-x64/harfbuzz.dll by full path, then harfbuzz.dll by name

To bind more functions, use cl-ffi:defcfun in your own package; they resolve against the loaded library. hb_ft_* functions are only in builds with FreeType support (the Debian package and the bundled DLL both have it).

Types

Type C type Notes
hb-bool hb_bool_t :int; 0 is false
hb-codepoint hb_codepoint_t :uint32; a character or, after shaping, a glyph
hb-position hb_position_t :int32, in scale units
hb-mask hb_mask_t :uint32
hb-tag hb_tag_t :uint32, four bytes big-endian
hb-color hb_color_t :uint32, B G R A from the most significant byte
hb-ot-name-id hb_ot_name_id_t :uint

Enums (keywords): hb-memory-mode (:duplicate :readonly :writable :readonly-may-make-writable), hb-direction (:invalid :ltr :rtl :ttb :btt), hb-buffer-content-type (:invalid :unicode :glyphs), hb-buffer-cluster-level (:monotone-graphemes :monotone-characters :characters), hb-paint-extend (:pad :repeat :reflect), hb-paint-composite-mode (:clear … :hsl-luminosity), hb-ot-name-id-predefined (the standard name IDs of hb_ot_name_id_predefined_t, :copyright for 0 … :variations-ps-prefix for 25), hb-ot-metrics-tag (hb_ot_metrics_tag_t, :horizontal-ascender … :underline-offset, each the tag HarfBuzz gives the metric).

Bitfields (lists of keywords): hb-buffer-flags, hb-glyph-flags, hb-ot-var-axis-flags (:hidden).

Scripts (hb_script_t) and languages (hb_language_t) are passed as integers and pointers; convert with hb-script-from-string or hb-script-from-iso15924-tag, hb-language-from-string, hb-language-to-string.

Structs

Struct Slots
hb-glyph-info codepoint mask cluster var1 var2
hb-glyph-position x-advance y-advance x-offset y-offset var
hb-feature tag value start end
hb-variation tag value
hb-glyph-extents x-bearing y-bearing width height
hb-font-extents ascender descender line-gap reserved
hb-ot-name-entry name-id var language
hb-ot-color-layer glyph color-index
hb-ot-var-axis-info axis-index tag name-id flags min-value default-value max-value reserved
hb-color-stop offset is-foreground color

Slot names are exported symbols of cl-harfbuzz/ffi. Use them as (:struct cl-harfbuzz/ffi:hb-glyph-info).

Functions

Area Functions
version, shapers hb-version, hb-version-string, hb-shape-list-shapers
tags, scripts, languages hb-tag-from-string, hb-script-from-string, hb-script-from-iso15924-tag, hb-script-get-horizontal-direction, hb-language-from-string, hb-language-to-string, hb-language-get-default
blobs hb-blob-create, hb-blob-create-from-file-or-fail, hb-blob-destroy, hb-blob-get-data, hb-blob-get-length
faces hb-face-count, hb-face-create, hb-face-reference, hb-face-destroy, hb-face-get-index, hb-face-get-upem, hb-face-get-glyph-count, hb-face-get-table-tags, hb-face-reference-table
fonts hb-font-create, hb-font-destroy, hb-font-get-face, hb-font-get-scale, hb-font-set-scale, hb-font-get-ppem, hb-font-set-ppem, hb-font-get-ptem, hb-font-set-ptem, hb-font-get-nominal-glyph, hb-font-get-glyph-h-advance, hb-font-get-glyph-v-advance, hb-font-get-glyph-extents, hb-font-get-glyph-name, hb-font-get-glyph-from-name, hb-font-get-h-extents, hb-font-get-v-extents
variations hb-font-set-variations, hb-font-get-var-coords-design, hb-font-get-var-coords-normalized, hb-font-set-var-named-instance, hb-font-get-var-named-instance, hb-ot-var-has-data, hb-ot-var-get-axis-count, hb-ot-var-get-axis-infos, hb-ot-var-get-named-instance-count, hb-ot-var-named-instance-get-design-coords, hb-ot-var-named-instance-get-subfamily-name-id, hb-ot-var-named-instance-get-postscript-name-id
buffers hb-buffer-create, hb-buffer-destroy, hb-buffer-reset, hb-buffer-clear-contents, hb-buffer-allocation-successful, hb-buffer-add-codepoints, hb-buffer-get-length, hb-buffer-get-content-type, hb-buffer-get/set-direction, hb-buffer-get/set-script, hb-buffer-get/set-language, hb-buffer-get/set-cluster-level, hb-buffer-get/set-flags, hb-buffer-guess-segment-properties, hb-buffer-get-glyph-infos, hb-buffer-get-glyph-positions
shaping hb-shape, hb-feature-from-string, hb-feature-to-string
drawing hb-draw-funcs-create, hb-draw-funcs-destroy, hb-draw-funcs-set-move-to-func, -line-to-func, -quadratic-to-func, -cubic-to-func, -close-path-func, hb-font-draw-glyph
painting hb-paint-funcs-create, hb-paint-funcs-destroy, hb-paint-funcs-set-push-transform-func, -pop-transform-func, -push-clip-glyph-func, -push-clip-rectangle-func, -pop-clip-func, -color-func, -image-func, -linear-gradient-func, -radial-gradient-func, -sweep-gradient-func, -push-group-func, -pop-group-func, -color-glyph-func, hb-font-paint-glyph, hb-color-line-get-color-stops, hb-color-line-get-extend
OpenType names, metrics, layout hb-ot-name-list-names, hb-ot-name-get-utf8, hb-ot-metrics-get-position, hb-ot-layout-table-get-script-tags, hb-ot-layout-table-get-feature-tags
OpenType color hb-ot-color-has-palettes, hb-ot-color-palette-get-count, hb-ot-color-palette-get-colors, hb-ot-color-has-layers, hb-ot-color-glyph-get-layers, hb-ot-color-has-paint, hb-ot-color-glyph-has-paint, hb-ot-color-has-svg, hb-ot-color-glyph-reference-svg, hb-ot-color-has-png, hb-ot-color-glyph-reference-png
FreeType (hb-ft) hb-ft-font-create-referenced, hb-ft-font-changed

get/set means both hb-…-get-… and hb-…-set-…; a leading - continues the prefix of the row's first name.

Things to know

  • Array queries follow HarfBuzz's "start offset, count in/out, array out" convention; call once with a null array to learn the total.
  • Blobs returned by hb-face-reference-table, hb-ot-color-glyph-reference-svg/png must be released with hb-blob-destroy.
  • Callbacks (draw, paint) must not unwind through HarfBuzz frames: catch errors inside them. cl-harfbuzz defines its callbacks once, statically, and passes each call's results out through a special variable bound around the call.
  • Buffer flags set through the FFI are not checked against the known flags.
  • Metrics: hb-ot-metrics-get-position takes its metric as an hb-ot-metrics-tag keyword, such as :x-height, or the tag as an integer.