14.2.0

In this release, the experimental raster, vector, and GPU libraries went
through several rounds of code review and cleanup to make sure they follow the
high standards expected of HarfBuzz code. The API has also been extensively
reviewed based on experience gained from using these libraries. We consider the
code and API to be ready for stabilization, and we expect to graduate them from
experimental in the near future. If you are using or planning to use these
libraries and have any concerns about the API, it is time to raise them. Once a
library is deemed stable, we will never change the API or ABI in an
incompatible way.

- GPU library:
  * New color-glyph paint renderer, based on design by Lê Duy Quang.
    `hb_gpu_paint_t` walks a font's paint tree (COLRv0 or COLRv1) and encodes
    its layers (solid fills, linear / radial / sweep gradients, transforms,
    composite groups) into a compact blob.
    A new fragment-shader function `hb_gpu_paint()` renders the blob in
    premultiplied RGBA; monochrome glyphs are handled transparently via a
    synthesized foreground-colored layer.
    Shader sources provided in GLSL, WGSL, MSL, and HLSL.
  * Paint encoder limitations: the encoder sets `unsupported` and returns
    `NULL` when `num_ops` would exceed 32767, `push_group` nests deeper than 4,
    or the paint tree calls back through the image callback (PaintImage).
    Nested glyph clips are intersected up to 3 levels; a few composite modes
    use approximate fallbacks; `push_clip_rectangle` is silently ignored.
  * Encode entry point now returns extents and auto-clears the encoder; the
    standalone `get_extents()` is gone.
  * Gradient color stop interpolation now happens in premultiplied space per
    the OpenType COLR specification.
  * The foreground color sentinel (`is_foreground`) now correctly preserves the
    paint-tree alpha from the encoded color data instead of discarding it.
  * The hb-gpu utility gains `--draw` / `--paint` flags with per-font
    auto-detect, and `--output-file` / `-o` for headless single-frame rendering
    to a PPM image.

- Vector library:
  * New PDF output backend. Vector paint glyphs now render to PDF page content,
    producing scalable COLRv0 / COLRv1 color-glyph artwork (solid fills, linear
    / radial / sweep gradients, blend modes, PNG images with transparency) that
    can be embedded directly in PDF documents. Useful for PDF producers such as
    LibreOffice that want crisp, resolution-independent color emoji.
  * New SVG id prefix API on paint allows prefixing document references, which
    allows for embedding multiple SVGs in the same page without name clashes
    (`hb_vector_paint_set_svg_prefix`).
  * Removed glyph path dedup from vector draw and paint. Each glyph is emitted
    inline; no `<defs>` / `<use>` caching.
  * `_glyph()` functions are now thin convenience wrappers documented as
    equivalent expansions of the underlying font draw/paint API.
  * Drop glyph-source rendering of SVG-in-OT fonts.

- Raster library:
  * Drop glyph-source rendering of SVG-in-OT fonts.

- Across Draw / Paint subsystems:
  * `_reset()` methods gain matching`_clear()` companions that drop accumulated
    data while preserving user configuration. Getter companions added for
    setters across raster, vector, and gpu types.

- Various fuzzer fixes for raster, vector, and GPU libraries.

- Paint API:
  * New arbitrary-path clip: `hb_paint_push_clip_path_start` / `_end` let
    callers clip to a caller-supplied outline, not just a font glyph.
    `push_clip_path_start()` returns the draw-funcs (and matching draw data)
    for the backend’s path accumulator; the caller drives `hb_draw_*()` into
    it, then calls `push_clip_path_end()`, followed by painted ops, then
    `hb_paint_pop_clip()` to release the clip. Implemented for all paint
    backends: vector (SVG defs + clipPath + url ref), vector PDF (q / path / W
    n), raster (path rendered to an alpha mask, intersected with the current
    clip), and GPU (the path is encoded into a Slug sub-blob so the fragment
    shader clips against it the same way it clips against glyph outlines).

- Shaping:
  * Indic: categorize U+1CF5 and U+1CF6 as CS.

- Changed API
  * GPU library:
    - `hb_gpu_draw_glyph()` now returns `void` (was `hb_bool_t`). Use
      `hb_gpu_draw_glyph_or_fail()` if you need the success status.
    - `hb_gpu_paint_glyph()` now returns `void` (was `hb_bool_t`) and
      internally synthesizes a foreground-colored layer for non-color glyphs
      via `hb_font_paint_glyph()`, so every glyph with an outline produces
      output. Use `hb_gpu_paint_glyph_or_fail()` (which delegates to
      `hb_font_paint_glyph_or_fail()`) if you need to distinguish color vs
      synthesized paint. Encoder-level limits (unsupported ops, group-stack
      overflow) no longer fail paint_glyph; they surface from
      `hb_gpu_paint_encode()` returning `NULL`.
    - `hb_gpu_draw_encode()` now takes an `extents` out-parameter and
      auto-clears the encoder on return.
    - `hb_gpu_draw_darken()` renamed to `hb_gpu_stem_darken()`.

  * Vector library:
    - `hb_vector_svg_set_precision()` and its paint counterpart renamed to
      `hb_vector_draw_set_precision()` / `hb_vector_paint_set_precision()`
      (SVG-specific naming is inaccurate with the PDF backend added).
    - `hb_vector_draw_glyph()` / `hb_vector_paint_glyph()` now return `void`
      (were `hb_bool_t`). Paint additionally gains a draw fallback for
      non-color glyphs. Use the matching `_or_fail()` variants for the
      `hb_bool_t` return.

  * Raster library:
    - `hb_raster_draw_glyph()` / `hb_raster_paint_glyph()` now return `void`
      (were `hb_bool_t`). Paint additionally gains a draw fallback for
      non-color glyphs. Use the matching `_or_fail()` variants for the
      `hb_bool_t` return.

  * General:
    - Many read-only getters gained const on their object argument.
    - Six public draw / paint funcs getters across raster, vector, and gpu now
      take a const-pointer to the relevant context instance instead of being
      singletons:
        hb_raster_draw_get_funcs (const hb_raster_draw_t *)`
        hb_raster_paint_get_funcs (const hb_raster_paint_t *)
        hb_vector_draw_get_funcs (const hb_vector_draw_t *)
        hb_vector_paint_get_funcs (const hb_vector_paint_t *)
        hb_gpu_draw_get_funcs (const hb_gpu_draw_t *)
        hb_gpu_paint_get_funcs (const hb_gpu_paint_t *)
      This is what lets vector_paint dispatch to SVG- vs PDF- flavored
      callbacks transparently when called from outside code; the others
      currently use the instance for symmetry only.

- New API
  * Draw:
    +HB_DRAW_LINE_CAP_BUTT
    +HB_DRAW_LINE_CAP_ROUND
    +HB_DRAW_LINE_CAP_SQUARE
    +hb_draw_line_cap_t
    +hb_draw_line()
    +hb_draw_rectangle()
    +hb_draw_circle()

  * Paint:
    +hb_paint_push_clip_path_start_func_t
    +hb_paint_push_clip_path_end_func_t
    +hb_paint_sweep_gradient_tile_func_t
    +hb_paint_push_group_for_func_t
    +hb_paint_push_group_for()
    +hb_paint_funcs_set_push_group_for_func()
    +hb_paint_reduce_linear_anchors()
    +hb_paint_normalize_color_line()
    +hb_paint_sweep_gradient_tiles()
    +hb_paint_push_clip_path_start()
    +hb_paint_push_clip_path_end()
    +hb_paint_funcs_set_push_clip_path_start_func()
    +hb_paint_funcs_set_push_clip_path_end_func()

  * GPU library:
    +HB_GPU_SHADER_STAGE_VERTEX
    +HB_GPU_SHADER_STAGE_FRAGMENT
    +HB_GPU_SHADER_LANG_INVALID
    +hb_gpu_shader_stage_t
    +hb_gpu_paint_t
    +hb_gpu_paint_create_or_fail()
    +hb_gpu_paint_reference()
    +hb_gpu_paint_destroy()
    +hb_gpu_paint_set_user_data()
    +hb_gpu_paint_get_user_data()
    +hb_gpu_paint_get_funcs()
    +hb_gpu_paint_set_palette()
    +hb_gpu_paint_get_palette()
    +hb_gpu_paint_set_custom_palette_color()
    +hb_gpu_paint_clear_custom_palette_colors()
    +hb_gpu_paint_set_scale()
    +hb_gpu_paint_get_scale()
    +hb_gpu_paint_glyph()
    +hb_gpu_paint_encode()
    +hb_gpu_paint_clear()
    +hb_gpu_paint_reset()
    +hb_gpu_paint_recycle_blob()
    +hb_gpu_paint_shader_source()
    +hb_gpu_paint_glyph_or_fail()
    +hb_gpu_shader_source()
    +hb_gpu_draw_shader_source()
    +hb_gpu_draw_clear()
    +hb_gpu_draw_get_scale()
    +hb_gpu_draw_glyph_or_fail()

  * Raster library:
    +hb_raster_draw_clear()
    +hb_raster_draw_glyph_or_fail()
    +hb_raster_paint_clear()
    +hb_raster_paint_glyph_or_fail()
    +hb_raster_paint_set_palette()
    +hb_raster_paint_get_palette()
    +hb_raster_paint_get_foreground()
    +hb_raster_paint_set_background()
    +hb_raster_paint_get_background()

  * Vector library:
    +HB_VECTOR_FORMAT_PDF
    +hb_vector_draw_clear()
    +hb_vector_draw_get_precision()
    +hb_vector_draw_get_format()
    +hb_vector_draw_glyph_or_fail()
    +hb_vector_draw_new_path()
    +hb_vector_draw_set_foreground()
    +hb_vector_draw_get_foreground()
    +hb_vector_draw_set_background()
    +hb_vector_draw_get_background()
    +hb_vector_paint_clear()
    +hb_vector_paint_get_precision()
    +hb_vector_paint_get_format()
    +hb_vector_paint_get_foreground()
    +hb_vector_paint_set_background()
    +hb_vector_paint_get_background()
    +hb_vector_paint_get_palette()
    +hb_vector_paint_glyph_or_fail()
    +hb_vector_paint_set_svg_prefix()
    +hb_vector_paint_get_svg_prefix()

- Removed API
  * GPU library:
    -hb_gpu_shader_fragment_source()   (replaced by hb_gpu_shader_source(stage))
    -hb_gpu_shader_vertex_source()     (replaced by hb_gpu_shader_source(stage))
    -hb_gpu_draw_get_extents()         (extents are now an out-parameter of hb_gpu_draw_encode())

  * Vector library:
    -hb_vector_draw_set_flat()
    -hb_vector_draw_get_flat()
    -hb_vector_paint_set_flat()
    -hb_vector_paint_get_flat()
14.2.0
16 files changed
tree: 20dfbf1ee5c28916fad25b2c11d5ecc1aeb1918c
  1. .ci/
  2. .github/
  3. docs/
  4. perf/
  5. src/
  6. subprojects/
  7. test/
  8. util/
  9. .clang-format
  10. .codecov.yml
  11. .editorconfig
  12. AGENTS.md
  13. AUTHORS
  14. BUILD.md
  15. CMakeLists.txt
  16. CODE_OF_AI_CONDUCT.md
  17. CONFIG.md
  18. COPYING
  19. harfbuzz.doap
  20. HarfBuzz.png
  21. meson.build
  22. meson_options.txt
  23. NEWS
  24. README.md
  25. README.mingw.md
  26. README.python.md
  27. RELEASING.md
  28. replace-enum-strings.cmake
  29. SECURITY.md
  30. TESTING.md
  31. THANKS
  32. xkcd.png
README.md

HarfBuzz

Linux CI Status macoOS CI Status Windows CI Status OSS-Fuzz Status Coverity Scan Build Status Packaging status OpenSSF Scorecard

HarfBuzz started as a text shaping engine but has grown into a full font platform — the ffmpeg of text shaping. It primarily supports OpenType, but also Apple Advanced Typography.

HarfBuzz shapes the majority of text on modern screens.

HarfBuzz is optimized for robustness, correctness, and performance — in that order. Achieve all.

Try it live at harfbuzz-world.cc — an interactive playground for shaping, subsetting, rasterization, vector output, and GPU rendering, all running in your browser.

Here is a quick map of its components:

Core libraries

LibraryDescription
libharfbuzzText shaping, draw API, paint API. Highly configurable (see CONFIG.md). Optional integration backends compiled in: hb-ft (FreeType), hb-coretext (macOS), hb-uniscribe (Windows), hb-directwrite (Windows), hb-gdi (Windows), hb-glib, hb-graphite2.
libharfbuzz-subsetFont subsetting and variable-font instancing.

Auxiliary libraries

LibraryDescription
libharfbuzz-icuICU Unicode integration.
libharfbuzz-cairoCairo rendering integration.
libharfbuzz-gobjectGObject/GI bindings.

Experimental libraries

LibraryDescription
libharfbuzz-rasterGlyph rasterization to bitmaps, including color fonts. Uses hb-draw and hb-paint.
libharfbuzz-vectorGlyph output to vector formats (currently SVG), including color fonts. Uses hb-draw and hb-paint.
libharfbuzz-gpuEncodes glyph outlines for GPU rasterization (Slug algorithm). Provides shader sources in GLSL, WGSL, MSL, and HLSL. Live demo.

Notable missing feature: font hinting (including autohinting) is not implemented. For hinted rasterization, use FreeType or Skrifa.

For simplified builds, amalgamated sources are available: harfbuzz.cc (just libharfbuzz), harfbuzz-subset.cc (just libharfbuzz-subset), or harfbuzz-world.cc (everything, driven by a custom hb-features.h). For a live in-browser playground plus a worked example of the world.cc single-file build, see harfbuzz-world.cc.

Command-line tools

ToolDescription
hb-shapeShape text and display glyph output.
hb-viewRender shaped text to an image.
hb-subsetSubset and optimize fonts.
hb-infoDisplay font metadata.
hb-rasterRender glyphs to bitmap images.
hb-vectorRender glyphs to vector formats (SVG).
hb-gpuInteractive GPU text rendering.

The canonical source tree and bug trackers are available on github. Both development and user support discussion around HarfBuzz happen on github as well.

For license information, see COPYING.

API stability

The API that comes with hb.h will not change incompatibly. Other, peripheral, headers are more likely to go through minor modifications, but again, we do our best to never change API in an incompatible way. We will never break the ABI.

The API and ABI are stable even across major version number jumps. In fact, current HarfBuzz is API/ABI compatible all the way back to the 0.9.x series. If one day we need to break the API/ABI, that would be called a new library.

As such, we bump the major version number only when we add major new features, the minor version when there is new API, and the micro version when there are bug fixes.

Documentation

For user manual as well as API documentation, check: https://harfbuzz.github.io

Download

Tarball releases and Win32/Win64 binary bundles are available on the github releases page.

Development

For build information, see BUILD.md.

For custom configurations, see CONFIG.md.

For testing and profiling, see TESTING.md.

For using with Python, see README.python.md. There is also uharfbuzz.

For cross-compiling to Windows from Linux or macOS, see README.mingw.md.

To report bugs or submit patches please use github issues and pull-requests.

Developer documents

To get a better idea of where HarfBuzz stands in the text rendering stack you may want to read State of Text Rendering 2024. Here are a few presentation slides about HarfBuzz over the years:

More presentations and papers are available on behdad's website. In particular, the following studies are relevant to HarfBuzz development:

Name

HarfBuzz /hærfˈbɒːz/

From Persian حرف (Harf: letter) and باز (Buzz: open). Transliteration of the Persian calque for OpenType.

As a noun: The Open Source text shaping engine.

As an adjective: Insincerely talkative; glib. A nod to the GNOME project where HarfBuzz originates from.

The logo shows حرف‌باز in the IranNastaliq font, on a Damascus steel background.

Background: Originally there was this font format called TrueType. People and companies started calling their type engines all things ending in Type: FreeType, CoolType, ClearType, etc. And then came OpenType, which is the successor of TrueType. So, for my OpenType implementation, I decided to stick with the concept but use the Persian translation. Which is fitting given that Persian is written in the Arabic script, and OpenType is an extension of TrueType that adds support for complex script rendering, and HarfBuzz is an implementation of OpenType text shaping.

Users

HarfBuzz is used in Android, Chrome, ChromeOS, Firefox, GNOME, GTK+, KDE, Qt, LibreOffice, OpenJDK, XeTeX, Adobe Photoshop, Illustrator, InDesign, Microsoft Edge, Amazon Kindle, PlayStation, Godot Engine, Unreal Engine, Figma, Canva, QuarkXPress, Scribus, smart TVs, car displays, and many other places.

Distribution

Packaging status