TrueType/OTF(CFF)/WOFF/WOFF2 font parser written in MoonBit.
Parses font binary data and converts glyph outlines to @svg.PathCommand (from mizchi/svg).
let data : Bytes = ... // TTF, OTF, WOFF, WOFF2, or TTC file bytes
let font = @font.parse_font(data).unwrap()
// Get glyph outline as SVG path commands
let cmds = font.scaled_outline('A'.to_int(), 48.0)
// Get glyph metrics
let gid = font.glyph_index('A'.to_int())
let metrics = font.glyph_metrics(gid)
// Text layout with kerning
let positions = font.layout_text("Hello", 48.0)
let width = font.measure_text("Hello", 48.0)
// Variable font with axis values
let cmds = font.char_outline_at('A'.to_int(), { "wght": 700.0 })
// Vertical text layout
let vpositions = font.layout_text_vertical("ηΈ¦ζΈγ", 48.0)
let vheight = font.measure_text_vertical("ηΈ¦ζΈγ", 48.0)
// Font subsetting (glyf-based TrueType only)
let subset = @font.subset_font(data, [0x41, 0x42, 0x43]) // A, B, CThis library covers the core OpenType tables needed for glyph rendering, metrics, variable fonts, and text layout (horizontal and vertical). Latin, CJK, and other scripts that don't require complex shaping work well out of the box.
| Format | Notes | |
|---|---|---|
| TTF (TrueType) | β | sfnt flavor 0x00010000 and 0x74727565 |
| OTF (OpenType/CFF) | β | sfnt flavor OTTO |
| WOFF1 | β | zlib decompression |
| WOFF2 | β | Brotli decompression with glyf/loca/hmtx transforms |
| TTC/OTC (Font Collections) | β | Index-based or first-font access |
| Table | Description |
|---|---|
head |
units_per_em, indexToLocFormat |
maxp |
numGlyphs |
hhea |
ascent, descent, lineGap, numOfLongHorMetrics |
hmtx |
advanceWidth, leftSideBearing per glyph |
cmap |
Format 0, 4 (BMP), 6, and 12 (full Unicode) |
loca |
Short and long formats |
glyf |
Simple and compound glyphs |
CFF |
Type 2 charstrings with subroutines |
CFF2 |
Variable font support with blend/vsindex |
fvar |
Axis definitions (wght, wdth, opsz, etc.) |
avar |
Piecewise linear axis value mapping |
gvar |
TrueType delta interpolation with IUP |
kern |
Format 0 horizontal pairs |
name |
Windows Unicode, Unicode platform, Mac Roman |
OS/2 |
Weight/width class, PANOSE, x-height, cap-height |
post |
Italic angle, fixed pitch, glyph names (v2.0) |
vhea/vmtx |
Vertical metrics β advance heights and top side bearings |
gasp |
Grid-fitting and scan-conversion ranges |
VORG |
Vertical origin Y coordinates for CFF glyphs |
The tables below are not parsed. Most of them are only needed for advanced use cases.
π€ Complex Text Shaping β Required for scripts with context-dependent glyph forms: Arabic, Hebrew, Devanagari, Thai, etc. Also needed for OpenType features like ligatures (fi β fi), stylistic alternates, and advanced kerning. Latin and CJK text renders correctly without these.
| Table | Description |
|---|---|
GSUB |
Glyph substitution β ligatures, contextual alternates, localized forms |
GPOS |
Glyph positioning β pair adjustment, mark-to-base, mark-to-mark |
GDEF |
Glyph definition β glyph classes, ligature caret positions, mark sets |
BASE |
Baseline offsets for mixing scripts (e.g. Latin + CJK in one line) |
JSTF |
Justification alternatives for full-justified text |
π¨ Color & Emoji β Required for rendering color emoji and multi-color glyphs. Not needed for monochrome text rendering.
| Table | Description |
|---|---|
COLR/CPAL |
Color layers with palettes (COLRv0/v1 color fonts) |
SVG |
SVG glyph documents (SVG-in-OpenType color fonts) |
CBDT/CBLC |
Color bitmap glyphs (Google/Android emoji) |
sbix |
Apple bitmap glyphs (Apple emoji) |
EBDT/EBLC |
Monochrome/grayscale embedded bitmaps (legacy low-res screens) |
π Specialized Rendering β Needed only for specific rendering scenarios.
| Table | Description |
|---|---|
MATH |
Math layout constants and glyph assembly β only for TeX-like math typesetting engines |
cvt/fpgm/prep |
TrueType hinting programs β grid-fitting instructions for low-DPI rasterization. Irrelevant for SVG/vector output |
hdmx |
Pre-computed device widths for specific PPEMs β legacy optimization for bitmap rendering |
π Apple AAT β Apple-proprietary layout system. Most modern fonts use OpenType (GSUB/GPOS) instead. Only found in macOS system fonts and some legacy fonts.
| Table | Description |
|---|---|
morx/mort |
Apple Advanced Typography β state-machine-based shaping |
π Other β Rarely needed for rendering or layout.
| Table | Description |
|---|---|
DSIG |
Digital signature β font authenticity verification, does not affect rendering |
cvar |
CVT variations β hinting value adjustments in variable fonts, only relevant if hinting is executed |
All standard operators for outline extraction are supported:
| Category | Operators | |
|---|---|---|
| Move | β | rmoveto, hmoveto, vmoveto |
| Line | β | rlineto, hlineto, vlineto |
| Curve | β | rrcurveto, hhcurveto, vvcurveto, hvcurveto, vhcurveto |
| Mixed | β | rcurveline, rlinecurve |
| Flex | β | flex, hflex, vflex, hflex1, flex1 |
| Hint | β | hstem, vstem, hstemhm, vstemhm, hintmask, cntrmask |
| Subroutine | β | callsubr, callgsubr, return |
| Arithmetic | β | add, sub, mul, div, neg, abs, sqrt, eq |
| Logic | β | and, or, not, ifelse |
| Stack | β | dup, exch, drop, index, roll, put, get |
| CFF2 Variation | β | blend, vsindex |
| Control | β | endchar |
| Deprecated | β | seac, dotsection β removed from modern specs |
| Feature | Notes | |
|---|---|---|
| Simple glyphs (TrueType) | β | |
| Compound glyphs (TrueType) | β | Scale, 2x2 matrix, XY offset transforms |
| CFF1 charstrings | β | Local/global subroutines |
| CFF2 charstrings | β | Blend interpolation |
| TrueType variations (gvar) | β | Shared tuples, IUP, delta unpacking |
| CFF2 variations (ItemVariationStore) | β | Region scalars, blend deltas |
| Hinting / instruction execution | β | Not needed for vector/SVG output |
Formats 0, 4, 6, and 12 cover virtually all modern fonts. The unsupported formats are legacy or niche:
| Format | Coverage | |
|---|---|---|
| Format 0 | β | Mac Roman 256-char |
| Format 4 | β | BMP (U+0000βU+FFFF) |
| Format 6 | β | Trimmed table |
| Format 12 | β | Full Unicode (preferred when available) |
| Format 2 | β | CJK mixed 8/16-bit β obsolete encoding, replaced by Format 12 |
| Format 14 | β | Unicode Variation Sequences β needed for CJK glyph variants (e.g. JP vs CN forms) |
The kern table Format 0 covers most Latin fonts. GPOS-based kerning requires the OpenType layout engine (GSUB/GPOS), which is a significantly larger scope:
| Feature | Notes | |
|---|---|---|
kern table Format 0 (flat pairs) |
β | Covers most Latin fonts |
kern table Format 1 (Apple state machine) |
β | Apple-only, rare in cross-platform fonts |
GPOS pair adjustment (PairPos) |
β | More precise than kern, used by modern fonts |
GPOS contextual kerning |
β | Context-dependent spacing adjustments |
Subsetting extracts only the glyphs you need, reducing file size for web delivery:
| Feature | Notes | |
|---|---|---|
| Glyf-based TrueType subsetting | β | |
| Compound glyph dependency resolution | β | |
| Glyph ID remapping | β | |
| cmap Format 12 rebuild | β | |
| Table copy (head, hhea, hmtx, maxp, name, OS/2, post) | β | |
| CFF/CFF2 subsetting | β | CFF charstring rewriting is complex |
| WOFF/WOFF2 output | β | Outputs raw sfnt β wrap with external compressor |
| Layout table subsetting (GSUB/GPOS) | β | Requires lookup/coverage rewriting |
Horizontal LTR text with kerning and vertical top-to-bottom text are fully supported. The unsupported features represent a full text shaping engine (like HarfBuzz), which is a separate domain:
| Feature | Notes | |
|---|---|---|
| Horizontal advance widths | β | |
Pair kerning (kern table) |
β | |
| UTF-16 surrogate pair handling | β | |
| Text width measurement | β | |
| OpenType shaping (GSUB/GPOS) | β | Full shaping engine β needed for Arabic, Devanagari, ligatures |
| Bidirectional text | β | Unicode BiDi algorithm β needed for mixed LTR/RTL text |
| Vertical layout | β | Top-to-bottom CJK typesetting (vhea/vmtx/VORG) |
| Line breaking | β | Text wrapping β typically handled by the application layer |
13 exported functions:
| Function | Returns | Description |
|---|---|---|
loadFont(data) |
JSON string | Parse font, return metrics |
getFontInfo() |
JSON string | Get cached font info |
glyphToSvgPath(codepoint, fontSize) |
SVG path string | Scaled glyph outline |
glyphAdvance(codepoint, fontSize) |
Double | Scaled advance width |
fontName(nameId) |
String | Name table lookup |
kernAdvance(cp1, cp2, fontSize) |
Double | Scaled kerning value |
layoutText(text, fontSize) |
JSON string | Glyph positions with kerning |
measureText(text, fontSize) |
Double | Total text width |
fontWeightClass() |
Int | OS/2 weight class |
isFixedPitch() |
Int (0/1) | Post table fixed-pitch flag |
codepointCoverage() |
JSON string | All supported codepoints |
glyphIds() |
JSON string | All glyph IDs (0 to numGlyphs-1) |
tableSizes() |
JSON string | Table tag to byte size |
# Download test fixtures and run tests
just test
# Or manually
bash scripts/download-fixtures.sh
moon test
# Type check
just check
# Format code
just fmtNotoSans font files are not committed to the repository. They are downloaded from GitHub Releases on first run.
- mizchi/svg β
PathCommandtype for glyph outlines - mizchi/zlib β WOFF1 decompression
- mizchi/brotli β WOFF2 decompression
fixtures/NotoSansMono-Regular.ttf is licensed under the SIL Open Font License.
Apache-2.0