5 Scope and Limitations
dxtr edited this page 2026-10-19 18:45:57 +02:00

Scope and limitations

What HarfBuzz does, and what it leaves to others

HarfBuzz shapes one run: text of one direction, one script, one language, in one font. A text stack needs several other steps around it:

Step Who does it
splitting text into paragraphs, resolving bidi levels, reordering runs per line (UAX #9) cl-icu (bidi-runs)
splitting runs by script (UAX #24) cl-icu (script-runs)
choosing a font per run (fallback) your code, or cl-textrender
shaping each run cl-harfbuzz
finding line break opportunities (UAX #14), grapheme boundaries for carets (UAX #29) cl-icu
choosing line breaks, justification, alignment, tabs your code, or cl-textrender
rasterizing glyphs (hinting, anti-aliasing, LCD, SDF) cl-ft2
rendering outlines or color paint on the GPU (MSDF, Slug) your engine, from glyph-outline / glyph-paint
normalization, case mapping cl-icu

cl-textrender ties these together: layout on cl-icu and plain cl-harfbuzz, with an optional cl-ft2 raster backend.

Not covered by cl-harfbuzz

These HarfBuzz APIs have no idiomatic wrapper. Most are reachable through the C API with your own cl-ffi definitions alongside cl-harfbuzz/ffi.

  • Subsetting (hb-subset). It is a separate library (libharfbuzz-subset).
  • Custom font functions (hb_font_funcs_t): supplying your own glyph lookup and metrics, and sub-fonts (hb_font_create_sub_font).
  • HarfBuzz's own Unicode functions and AAT APIs (hb_aat_*); AAT shaping (morx, kerx, trak) is still applied by the ot shaper.
  • Fine-grained OpenType layout queries: lookups, language systems, glyph classes, ligature carets (hb_ot_layout_get_ligature_carets), GDEF, BASE and MATH table APIs, feature names (hb_ot_layout_feature_get_name_ids).
  • Synthetic bold and slant (hb_font_set_synthetic_bold, hb_font_set_synthetic_slant), and hb-ft load flags (hb_ft_font_set_load_flags).
  • Choosing a shaper list (hb_shape_full), shape plans, and buffer serialization / message callbacks for debugging.
  • WOFF/WOFF2 input: HarfBuzz itself cannot read them. make-face recognises and reports them.

Design limits

  • Positions are in the font's units, not in a separate float space. For pixels, use an ft2-font, set font-scale, or scale the results yourself.
  • shaped-glyph is a copy. Each call to buffer-glyphs allocates a fresh vector of structs. For code that shapes again and again, read the glyphs one at a time with buffer-glyph, which allocates nothing: shaping into a reused buffer then allocates nothing at all.
  • No finalizers. Objects are released explicitly or by with- macros.
  • Text is passed as code points, so clusters are character indexes into Lisp strings. There is no UTF-8 or UTF-16 cluster mode.