[gpu] Assign curves to bands using quantized bounds (#6132)

The fragment shader picks one horizontal and one vertical band from
the fragment position and walks only that band's curve list, so a
curve must be listed in every band its bounding box reaches into.

The encoder computed those bounding boxes from the unquantized
control points, but the shader only ever sees the coordinates after
they are rounded to quarter font units.  When rounding pushed a
curve's extreme across a band boundary, the curve was left out of the
band it now reached into.  Fragments landing in that sliver never saw
the curve, so their winding number was off by one and the pixel came
out empty in the middle of a filled area -- a thin black line through
the glyph, appearing and disappearing as the font size moves the
pixel grid.

The rounding error is at most an eighth of a font unit, so this is
invisible for an integer-coordinate glyph rendered at its own upem.
It gets easy to hit when the coordinates are fractional: CFF glyphs
after cu2qu, or any font whose hb_font_t scale is not its upem.  With
hb_font_set_scale(font, 163, 163), as in issue #6131, more than half
of the glyphs of util/gpu/default-font.ttf had at least one band the
shader could reach but that did not list the curve.

Compute the bounds (and the is_horizontal/is_vertical tests) from the
quantized control points instead, and widen the band range by 1/1024
of a band so that the double arithmetic here cannot disagree with the
shader's float32 band index right at a boundary.

Verified with a CPU port of _hb_gpu_slug_single: comparing the banded
lookup against a walk over every curve of the glyph, at sizes 39, 47
and 107 with scale 163, default-font.ttf had 27 wrong pixels before
and none after.  Encoded atlas size grows by 0.12%.

Adds test_encode_band_membership, which checks the invariant directly
on the encoded blob and fails before this change.

Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2 files changed
tree: 8e7cc5c97425297fc80633458bfa5c5cc8e880ad
  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. AVAR2-INSTANCING.md
  15. BUILD.md
  16. CMakeLists.txt
  17. CODE_OF_AI_CONDUCT.md
  18. CONFIG.md
  19. COPYING
  20. harfbuzz.doap
  21. HarfBuzz.png
  22. meson.build
  23. meson_options.txt
  24. NEWS
  25. README.md
  26. README.mingw.md
  27. README.python.md
  28. RELEASING.md
  29. replace-enum-strings.cmake
  30. SECURITY.md
  31. TESTING.md
  32. THANKS
  33. 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, Flutter, 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