font

TrueType/OTF(CFF)/WOFF/WOFF2 font parser for MoonBit

font
ttf
woff
woff2
opentype
otf
cff
moon add mizchi/font@0.7.4
Download zip
Author
Version
0.7.4
License
Apache-2.0
Last updated
15 hours ago
Downloads
22K
README

#mizchi/font

TrueType/OTF(CFF)/WOFF/WOFF2 font parser written in MoonBit.

Parses font binary data and converts glyph outlines to @svg.PathCommand (from mizchi/svg).

#Usage

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, C

#Supported Specifications

This 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.

#Font Formats

FormatNotes
TTF (TrueType)sfnt flavor 0x00010000 and 0x74727565
OTF (OpenType/CFF)sfnt flavor OTTO
WOFF1zlib decompression
WOFF2Brotli decompression with glyf/loca/hmtx transforms
TTC/OTC (Font Collections)Index-based or first-font access

#OpenType Tables

#✅ Parsed

TableDescription
headunits_per_em, indexToLocFormat
maxpnumGlyphs
hheaascent, descent, lineGap, numOfLongHorMetrics
hmtxadvanceWidth, leftSideBearing per glyph
cmapFormat 0, 4 (BMP), 6, and 12 (full Unicode)
locaShort and long formats
glyfSimple and compound glyphs
CFF Type 2 charstrings with subroutines
CFF2Variable font support with blend/vsindex
fvarAxis definitions (wght, wdth, opsz, etc.)
avarPiecewise linear axis value mapping
gvarTrueType delta interpolation with IUP
kernFormat 0 horizontal pairs
nameWindows Unicode, Unicode platform, Mac Roman
OS/2Weight/width class, PANOSE, x-height, cap-height
postItalic angle, fixed pitch, glyph names (v2.0)
vhea/vmtxVertical metrics — advance heights and top side bearings
gaspGrid-fitting and scan-conversion ranges
VORGVertical origin Y coordinates for CFF glyphs

#❌ Not Parsed

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 (fifi), stylistic alternates, and advanced kerning. Latin and CJK text renders correctly without these.

TableDescription
GSUBGlyph substitution — ligatures, contextual alternates, localized forms
GPOSGlyph positioning — pair adjustment, mark-to-base, mark-to-mark
GDEFGlyph definition — glyph classes, ligature caret positions, mark sets
BASEBaseline offsets for mixing scripts (e.g. Latin + CJK in one line)
JSTFJustification alternatives for full-justified text

🎨 Color & Emoji — Required for rendering color emoji and multi-color glyphs. Not needed for monochrome text rendering.

TableDescription
COLR/CPALColor layers with palettes (COLRv0/v1 color fonts)
SVG SVG glyph documents (SVG-in-OpenType color fonts)
CBDT/CBLCColor bitmap glyphs (Google/Android emoji)
sbixApple bitmap glyphs (Apple emoji)
EBDT/EBLCMonochrome/grayscale embedded bitmaps (legacy low-res screens)

📐 Specialized Rendering — Needed only for specific rendering scenarios.

TableDescription
MATHMath layout constants and glyph assembly — only for TeX-like math typesetting engines
cvt/fpgm/prepTrueType hinting programs — grid-fitting instructions for low-DPI rasterization. Irrelevant for SVG/vector output
hdmxPre-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.

TableDescription
morx/mortApple Advanced Typography — state-machine-based shaping

🔒 Other — Rarely needed for rendering or layout.

TableDescription
DSIGDigital signature — font authenticity verification, does not affect rendering
cvarCVT variations — hinting value adjustments in variable fonts, only relevant if hinting is executed

#CFF / CFF2 Charstring Operators

All standard operators for outline extraction are supported:

CategoryOperators
Movermoveto, hmoveto, vmoveto
Linerlineto, hlineto, vlineto
Curverrcurveto, hhcurveto, vvcurveto, hvcurveto, vhcurveto
Mixedrcurveline, rlinecurve
Flexflex, hflex, vflex, hflex1, flex1
Hinthstem, vstem, hstemhm, vstemhm, hintmask, cntrmask
Subroutinecallsubr, callgsubr, return
Arithmeticadd, sub, mul, div, neg, abs, sqrt, eq
Logicand, or, not, ifelse
Stackdup, exch, drop, index, roll, put, get
CFF2 Variationblend, vsindex
Controlendchar
Deprecatedseac, dotsection — removed from modern specs

#Glyph Outlines

FeatureNotes
Simple glyphs (TrueType)
Compound glyphs (TrueType)Scale, 2x2 matrix, XY offset transforms
CFF1 charstringsLocal/global subroutines
CFF2 charstringsBlend interpolation
TrueType variations (gvar)Shared tuples, IUP, delta unpacking
CFF2 variations (ItemVariationStore)Region scalars, blend deltas
Hinting / instruction executionNot needed for vector/SVG output

#cmap Formats

Formats 0, 4, 6, and 12 cover virtually all modern fonts. The unsupported formats are legacy or niche:

FormatCoverage
Format 0Mac Roman 256-char
Format 4BMP (U+0000–U+FFFF)
Format 6Trimmed table
Format 12Full Unicode (preferred when available)
Format 2CJK mixed 8/16-bit — obsolete encoding, replaced by Format 12
Format 14Unicode Variation Sequences — needed for CJK glyph variants (e.g. JP vs CN forms)

#Kerning

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:

FeatureNotes
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 kerningContext-dependent spacing adjustments

#Font Subsetting

Subsetting extracts only the glyphs you need, reducing file size for web delivery:

FeatureNotes
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 subsettingCFF charstring rewriting is complex
WOFF/WOFF2 outputOutputs raw sfnt — wrap with external compressor
Layout table subsetting (GSUB/GPOS)Requires lookup/coverage rewriting

#Text Layout

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:

FeatureNotes
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 textUnicode BiDi algorithm — needed for mixed LTR/RTL text
Vertical layoutTop-to-bottom CJK typesetting (vhea/vmtx/VORG)
Line breakingText wrapping — typically handled by the application layer

#JS Bindings (Wasm)

13 exported functions:

FunctionReturnsDescription
loadFont(data)JSON stringParse font, return metrics
getFontInfo()JSON stringGet cached font info
glyphToSvgPath(codepoint, fontSize)SVG path stringScaled glyph outline
glyphAdvance(codepoint, fontSize)DoubleScaled advance width
fontName(nameId)StringName table lookup
kernAdvance(cp1, cp2, fontSize)DoubleScaled kerning value
layoutText(text, fontSize)JSON stringGlyph positions with kerning
measureText(text, fontSize)DoubleTotal text width
fontWeightClass()IntOS/2 weight class
isFixedPitch()Int (0/1)Post table fixed-pitch flag
codepointCoverage()JSON stringAll supported codepoints
glyphIds()JSON stringAll glyph IDs (0 to numGlyphs-1)
tableSizes()JSON stringTable tag to byte size

#Development

# Download test fixtures and run tests just test # Or manually bash scripts/download-fixtures.sh moon test # Type check just check # Format code just fmt

NotoSans font files are not committed to the repository. They are downloaded from GitHub Releases on first run.

#Dependencies

#Test Fonts

fixtures/NotoSansMono-Regular.ttf is licensed under the SIL Open Font License.

#License

Apache-2.0

#
AtlasPageInfo

pub(all) struct AtlasPageInfo {
page_id : Int
width : Int
height : Int
dirty : Bool
}

#
BinaryReader

pub(all) struct BinaryReader {
data : Bytes
pos : Int
}

#
BinaryReader::at

fn BinaryReader::at(data : Bytes, pos : Int) -> BinaryReader

#
BinaryReader::new

fn BinaryReader::new(data : Bytes) -> BinaryReader

#
BinaryReader::peek_int16_at

fn BinaryReader::peek_int16_at(self : BinaryReader, offset : Int) -> Int

#
BinaryReader::peek_uint16_at

fn BinaryReader::peek_uint16_at(self : BinaryReader, offset : Int) -> Int

#
BinaryReader::peek_uint32_at

fn BinaryReader::peek_uint32_at(self : BinaryReader, offset : Int) -> Int

#
BinaryReader::position

fn BinaryReader::position(self : BinaryReader) -> Int

#
BinaryReader::read_f16dot16

fn BinaryReader::read_f16dot16(self : BinaryReader) -> Double

#
BinaryReader::read_f2dot14

fn BinaryReader::read_f2dot14(self : BinaryReader) -> Double

#
BinaryReader::read_int16

fn BinaryReader::read_int16(self : BinaryReader) -> Int

#
BinaryReader::read_int8

fn BinaryReader::read_int8(self : BinaryReader) -> Int

#
BinaryReader::read_tag

fn BinaryReader::read_tag(self : BinaryReader) -> String

#
BinaryReader::read_uint16

fn BinaryReader::read_uint16(self : BinaryReader) -> Int

#
BinaryReader::read_uint32

fn BinaryReader::read_uint32(self : BinaryReader) -> Int

#
BinaryReader::read_uint8

fn BinaryReader::read_uint8(self : BinaryReader) -> Int

#
BinaryReader::seek

fn BinaryReader::seek(self : BinaryReader, pos : Int) -> Unit

#
BinaryReader::skip

fn BinaryReader::skip(self : BinaryReader, n : Int) -> Unit

#
CFFData

pub(all) struct CFFData {
charstrings : CFFIndex
global_subrs : CFFIndex
local_subrs : CFFIndex
default_width_x : Int
nominal_width_x : Int
is_cff2 : Bool
ivs : ItemVariationStore?
}

#
CFFIndex

pub(all) struct CFFIndex {
data_offset : Int
offsets : Array[Int]
}

#
FontFormat

pub enum FontFormat {
TrueType
OpenType
Woff1
Woff2
TrueTypeCollection
Unknown
} derive(Eq)

impl Show for FontFormat

#
FontKey

pub(all) struct FontKey {
family : String
weight : Int
italic : Bool
}

impl Show for FontKey

#
GaspRange

pub(all) struct GaspRange {
max_ppem : Int
behavior : Int
}

#
Glyph

pub(all) struct Glyph {
glyph_id : Int
metrics : GlyphMetrics
outline : Array[
PathCommand
]
}

#
GlyphAtlas

pub struct GlyphAtlas {
cache : GlyphCache
width : Int
height : Int
pixels : Array[Int]
dirty : Bool
last_used_generation : Int
}

#
GlyphAtlas::deserialize

fn GlyphAtlas::deserialize(data : Array[Int]) -> GlyphAtlas?

Deserialize a GlyphAtlas from a flat Int array.

#
GlyphAtlas::get_cache

fn GlyphAtlas::get_cache(self : GlyphAtlas) -> GlyphCache

#
GlyphAtlas::get_pixels

fn GlyphAtlas::get_pixels(self : GlyphAtlas) -> Array[Int]

#
GlyphAtlas::new

fn GlyphAtlas::new(width : Int, height : Int, page_id : Int) -> GlyphAtlas

#
GlyphAtlas::rasterize_glyph

fn GlyphAtlas::rasterize_glyph(self : GlyphAtlas, font : TTFont, codepoint : Int, size_px : Double) -> GlyphCacheEntry?

Rasterize a single glyph and place it into the atlas.

#
GlyphAtlas::serialize

fn GlyphAtlas::serialize(self : GlyphAtlas) -> Array[Int]

Serialize a GlyphAtlas to a flat Int array for persistent caching.

#
GlyphBBox

pub(all) struct GlyphBBox {
x_min : Int
y_min : Int
x_max : Int
y_max : Int
}

#
GlyphBitmap

pub struct GlyphBitmap {
width : Int
height : Int
pixels : Array[Int]
}

Rasterized glyph pixel data (RGBA8 flat array: [r,g,b,a, r,g,b,a, ...]).
impl Show for GlyphBitmap

#
GlyphCache

pub struct GlyphCache {
entries : Map[Int, GlyphCacheEntry]
next_x : Double
next_y : Double
row_height : Double
atlas_width : Double
atlas_height : Double
atlas_page_id : Int
}

#
GlyphCache::allocate

fn GlyphCache::allocate(self : GlyphCache, glyph_id : Int, width : Double, height : Double) -> GlyphCacheEntry?

Allocate space in the atlas for a glyph. Returns the cache entry, or None if the atlas is full.

#
GlyphCache::clear

fn GlyphCache::clear(self : GlyphCache) -> Unit

#
GlyphCache::entry_count

fn GlyphCache::entry_count(self : GlyphCache) -> Int

#
GlyphCache::get

fn GlyphCache::get(self : GlyphCache, glyph_id : Int) -> GlyphCacheEntry?

#
GlyphCache::new

fn GlyphCache::new(atlas_width : Double, atlas_height : Double, atlas_page_id : Int) -> GlyphCache

#
GlyphCacheEntry

pub(all) struct GlyphCacheEntry {
glyph_id : Int
atlas_x : Double
atlas_y : Double
atlas_w : Double
atlas_h : Double
atlas_page_id : Int
}

#
GlyphMetrics

pub(all) struct GlyphMetrics {
advance_width : Int
left_side_bearing : Int
bbox : GlyphBBox
}

#
GlyphPosition

pub(all) struct GlyphPosition {
codepoint : Int
glyph_id : Int
x_offset : Double
y_offset : Double
x_advance : Double
}

#
GlyphQuad

pub(all) struct GlyphQuad {
glyph_id : Int
atlas_x : Double
atlas_y : Double
atlas_w : Double
atlas_h : Double
dst_x : Double
dst_y : Double
dst_w : Double
dst_h : Double
}

impl Show for GlyphQuad

#
GvarData

pub(all) struct GvarData {
axis_count : Int
shared_tuples : Array[Array[Double]]
gvar_offset : Int
glyph_var_data_offset : Int
glyph_offsets : Array[Int]
}

#
ItemVariationData

pub(all) struct ItemVariationData {
region_indices : Array[Int]
delta_sets : Array[Array[Int]]
}

#
ItemVariationStore

pub(all) struct ItemVariationStore {
regions : Array[VarRegion]
data : Array[ItemVariationData]
}

#
OS2Table

pub(all) struct OS2Table {
version : Int
us_weight_class : Int
us_width_class : Int
fs_type : Int
panose : FixedArray[Int]
ul_unicode_range1 : Int
ul_unicode_range2 : Int
ul_unicode_range3 : Int
ul_unicode_range4 : Int
fs_selection : Int
s_typo_ascender : Int
s_typo_descender : Int
s_typo_line_gap : Int
us_win_ascent : Int
us_win_descent : Int
sx_height : Int
s_cap_height : Int
}

#
PostTable

pub(all) struct PostTable {
italic_angle : Double
underline_position : Int
underline_thickness : Int
is_fixed_pitch : Bool
glyph_names : Array[String]
}

#
TTFont

pub(all) struct TTFont {
units_per_em : Int
index_to_loc_format : Int
num_glyphs : Int
ascent : Int
descent : Int
line_gap : Int
num_h_metrics : Int
glyf_offset : Int
data : Bytes
cmap : Map[Int, Int]
loca : Array[Int]
advance_widths : Array[Int]
left_side_bearings : Array[Int]
cff : CFFData?
gvar : GvarData?
var_axes : Array[VarAxis]
kern_pairs : Map[Int, Int]
avar_segments : Array[Array[(Double, Double)]]
name_records : Map[Int, String]
os2 : OS2Table?
post : PostTable?
vertical : VerticalMetrics?
gasp : Array[GaspRange]
vorg : VorgData?
}

#
TTFont::cap_height

fn TTFont::cap_height(self : TTFont) -> Int

Get cap-height from OS/2 table

#
TTFont::char_outline

fn TTFont::char_outline(self : TTFont, codepoint : Int) -> Array[
PathCommand
]

#
TTFont::char_outline_at

fn TTFont::char_outline_at(self : TTFont, codepoint : Int, axis_values : Map[String, Double]) -> Array[
PathCommand
]

#
TTFont::codepoint_coverage

fn TTFont::codepoint_coverage(self : TTFont) -> Array[Int]

Get all codepoints covered by the font's cmap

#
TTFont::font_name

fn TTFont::font_name(self : TTFont, name_id : Int) -> String?

Get font name by nameID (1=family, 2=subfamily, 4=full name, 6=postscript name)

#
TTFont::get_glyph

fn TTFont::get_glyph(self : TTFont, codepoint : Int) -> Glyph

#
TTFont::glyph_ids

fn TTFont::glyph_ids(self : TTFont) -> Array[Int]

Get all glyph IDs in the font (0 to num_glyphs-1)

#
TTFont::glyph_index

fn TTFont::glyph_index(self : TTFont, codepoint : Int) -> Int

#
TTFont::glyph_metrics

fn TTFont::glyph_metrics(self : TTFont, glyph_id : Int) -> GlyphMetrics

#
TTFont::glyph_metrics_at

fn TTFont::glyph_metrics_at(self : TTFont, glyph_id : Int, axis_values : Map[String, Double]) -> GlyphMetrics

Get glyph metrics with variable font interpolation. For glyf+gvar fonts, advance width is interpolated via phantom points. For CFF2 fonts, bbox is computed from the variable outline (advance uses static value).

#
TTFont::glyph_name

fn TTFont::glyph_name(self : TTFont, glyph_id : Int) -> String

Get glyph name from post table

#
TTFont::glyph_outline

fn TTFont::glyph_outline(self : TTFont, glyph_id : Int) -> Array[
PathCommand
]

#
TTFont::glyph_outline_at

fn TTFont::glyph_outline_at(self : TTFont, glyph_id : Int, axis_values : Map[String, Double]) -> Array[
PathCommand
]

#
TTFont::is_fixed_pitch

fn TTFont::is_fixed_pitch(self : TTFont) -> Bool

Check if font is fixed-pitch from post table

#
TTFont::italic_angle

fn TTFont::italic_angle(self : TTFont) -> Double

Get italic angle from post table

#
TTFont::kern_pair

fn TTFont::kern_pair(self : TTFont, left_gid : Int, right_gid : Int) -> Int

Get kerning value for a pair of glyph IDs

#
TTFont::layout_text

fn TTFont::layout_text(self : TTFont, text : String, font_size : Double) -> Array[GlyphPosition]

Layout text into positioned glyphs with kerning

#
TTFont::layout_text_vertical

fn TTFont::layout_text_vertical(self : TTFont, text : String, font_size : Double) -> Array[GlyphPosition]

Layout text vertically (top-to-bottom) into positioned glyphs

#
TTFont::measure_text

fn TTFont::measure_text(self : TTFont, text : String, font_size : Double) -> Double

Measure total text width

#
TTFont::measure_text_vertical

fn TTFont::measure_text_vertical(self : TTFont, text : String, font_size : Double) -> Double

Measure total text height for vertical layout

#
TTFont::scaled_outline

fn TTFont::scaled_outline(self : TTFont, codepoint : Int, font_size : Double) -> Array[
PathCommand
]

#
TTFont::vert_origin_y

fn TTFont::vert_origin_y(self : TTFont, glyph_id : Int) -> Int

Get vertical origin Y for a glyph (design units)

#
TTFont::weight_class

fn TTFont::weight_class(self : TTFont) -> Int

Get weight class from OS/2 table (400=Regular, 700=Bold)

#
TTFont::x_height

fn TTFont::x_height(self : TTFont) -> Int

Get x-height from OS/2 table

#
TableInfo

pub(all) struct TableInfo {
tag : String
offset : Int
length : Int
}

#
TextMetrics

pub(all) struct TextMetrics {
width : Double
height : Double
baseline : Double
}

impl Show for TextMetrics

#
TextRenderer

pub struct TextRenderer {
pages : Array[GlyphAtlas]
font : TTFont
pipeline_id : Int
atlas_size : Int
base_page_id : Int
max_pages : Int
generation : Int
}

#
TextRenderer::clear

fn TextRenderer::clear(self : TextRenderer) -> Unit

#
TextRenderer::ensure_glyph

fn TextRenderer::ensure_glyph(self : TextRenderer, codepoint : Int, size_px : Double) -> (Int, GlyphCacheEntry)?

Ensure a glyph is rasterized and cached. Returns the page index and cache entry. Used by GPU renderers to build draw commands.

#
TextRenderer::flush_dirty_pages

fn TextRenderer::flush_dirty_pages(self : TextRenderer) -> Array[AtlasPageInfo]

#
TextRenderer::get_atlas

fn TextRenderer::get_atlas(self : TextRenderer) -> GlyphAtlas

#
TextRenderer::get_page

fn TextRenderer::get_page(self : TextRenderer, index : Int) -> GlyphAtlas

#
TextRenderer::get_page_id

fn TextRenderer::get_page_id(self : TextRenderer) -> Int

#
TextRenderer::get_page_ids

fn TextRenderer::get_page_ids(self : TextRenderer) -> Array[Int]

#
TextRenderer::glyph_count

fn TextRenderer::glyph_count(self : TextRenderer) -> Int

#
TextRenderer::load_cache

fn TextRenderer::load_cache(self : TextRenderer, pages_data : Array[Array[Int]]) -> Int

Restore atlas pages from serialized data. Returns number of pages loaded.

#
TextRenderer::measure

fn TextRenderer::measure(self : TextRenderer, text : String, size_px : Double) -> TextMetrics

#
TextRenderer::new

fn TextRenderer::new(font : TTFont, atlas_size : Int, base_page_id : Int, pipeline_id : Int) -> TextRenderer

#
TextRenderer::new_with_options

fn TextRenderer::new_with_options(font : TTFont, atlas_size : Int, base_page_id : Int, pipeline_id : Int, max_pages : Int) -> TextRenderer

#
TextRenderer::page_count

fn TextRenderer::page_count(self : TextRenderer) -> Int

#
TextRenderer::serialize_cache

fn TextRenderer::serialize_cache(self : TextRenderer) -> Array[Array[Int]]

Serialize all pages of a TextRenderer.

#
TextRun

pub(all) struct TextRun {
text : String
style : TextStyle
}

impl Show for TextRun

#
TextStyle

pub(all) struct TextStyle {
font : FontKey
size_px : Double
line_height : Double
letter_spacing : Double
}

impl Show for TextStyle

#
VarAxis

pub(all) struct VarAxis {
tag : String
min_value : Double
default_value : Double
max_value : Double
}

#
VarRegion

pub(all) struct VarRegion {
axes : Array[VarRegionAxis]
}

#
VarRegionAxis

pub(all) struct VarRegionAxis {
start_coord : Double
peak_coord : Double
end_coord : Double
}

#
VerticalMetrics

pub(all) struct VerticalMetrics {
v_ascent : Int
v_descent : Int
advance_heights : Array[Int]
top_side_bearings : Array[Int]
}

#
VorgData

pub(all) struct VorgData {
default_vert_origin_y : Int
vert_origins : Map[Int, Int]
}

#
analyze_tables

fn analyze_tables(data : Bytes) -> Array[TableInfo]?

Analyze sfnt table directory without full parsing

#
blit_to_atlas

fn blit_to_atlas(atlas_pixels : Array[Int], atlas_width : Int, src : GlyphBitmap, dst_x : Int, dst_y : Int) -> Unit

Copy a GlyphBitmap into a larger pixel array at the given position.

#
bytes_slice

fn bytes_slice(data : Bytes, offset : Int, length : Int) -> Bytes

Copy a slice of Bytes

#
calc_table_checksum

fn calc_table_checksum(data : Bytes) -> Int

Calculate table checksum per OpenType spec

#
compute_path_bbox

fn compute_path_bbox(cmds : Array[
PathCommand
]) -> GlyphBBox

Compute bounding box from path commands. Calculates exact bounds including cubic/quadratic bezier curve extrema.

#
default_text_style

fn default_text_style(family : String, size_px : Double) -> TextStyle

#
detect_font_format

fn detect_font_format(data : Bytes) -> FontFormat

#
log2_floor

fn log2_floor(n : Int) -> Int

Floor of log2(n), minimum 0

#
make_glyph_cache_key

fn make_glyph_cache_key(glyph_id : Int, size_px : Double) -> Int

Create a composite cache key from glyph_id and size_px. Quantizes size to 0.1px precision (supports sizes 0-4095px, glyph IDs 0-524287).

#
new_text_run

fn new_text_run(text : String, style : TextStyle) -> TextRun

#
outline_bbox

fn outline_bbox(commands : Array[
PathCommand
]) -> (Double, Double, Double, Double)

Compute bounding box from outline path commands.

#
pad4

fn pad4(n : Int) -> Int

Round up to next multiple of 4

#
parse_avar

fn parse_avar(reader : BinaryReader, offset : Int, axis_count : Int) -> Array[Array[(Double, Double)]]

Parse avar table: returns per-axis segment maps

#
parse_cmap

fn parse_cmap(reader : BinaryReader, offset : Int) -> Map[Int, Int]

Parse cmap table: returns Map[codepoint -> glyph_id] Prefers Format 12 (full Unicode) over Format 4 (BMP only)

#
parse_font

fn parse_font(data : Bytes) -> TTFont?

Parse a font from raw bytes, auto-detecting format (TTF, OTF, or WOFF1)

#
parse_font_at

fn parse_font_at(data : Bytes, index : Int) -> TTFont?

Parse a single font from a TTC/OTC collection by index

#
parse_font_collection

fn parse_font_collection(data : Bytes) -> Array[TTFont]?

Parse a TTC/OTC font collection, returning all fonts

#
parse_fvar

fn parse_fvar(reader : BinaryReader, offset : Int) -> Array[VarAxis]

Parse fvar table: returns array of variation axes

#
parse_gasp

fn parse_gasp(reader : BinaryReader, offset : Int) -> Array[GaspRange]

Parse gasp table: returns array of GaspRange records

#
parse_head

fn parse_head(reader : BinaryReader, offset : Int) -> (Int, Int)

Parse head table: returns (units_per_em, index_to_loc_format)

#
parse_hhea

fn parse_hhea(reader : BinaryReader, offset : Int) -> (Int, Int, Int, Int)

Parse hhea table: returns (ascent, descent, line_gap, num_h_metrics)

#
parse_hmtx

fn parse_hmtx(reader : BinaryReader, offset : Int, num_glyphs : Int, num_h_metrics : Int) -> (Array[Int], Array[Int])

Parse hmtx table: returns (advance_widths, left_side_bearings)

#
parse_kern

fn parse_kern(reader : BinaryReader, offset : Int) -> Map[Int, Int]

Parse kern table (format 0, horizontal only): returns Map[key -> value] Key = (left_gid << 16) | right_gid

#
parse_loca

fn parse_loca(reader : BinaryReader, offset : Int, num_glyphs : Int, format : Int) -> Array[Int]

Parse loca table: returns array of glyph offsets into glyf table

#
parse_maxp

fn parse_maxp(reader : BinaryReader, offset : Int) -> Int

Parse maxp table: returns num_glyphs

#
parse_name

fn parse_name(reader : BinaryReader, offset : Int) -> Map[Int, String]

Parse name table: returns Map[nameID -> string] Prefers platformID=3/encodingID=1 (Windows Unicode BMP, UTF-16BE)

#
parse_os2

fn parse_os2(reader : BinaryReader, offset : Int) -> OS2Table

Parse OS/2 table

#
parse_post

fn parse_post(reader : BinaryReader, offset : Int, num_glyphs : Int) -> PostTable

Parse post table

#
parse_ttf

fn parse_ttf(data : Bytes) -> TTFont?

Parse a TrueType/OpenType font from raw bytes

#
parse_vhea

fn parse_vhea(reader : BinaryReader, offset : Int) -> (Int, Int, Int)

Parse vhea table: returns (v_ascent, v_descent, num_v_metrics)

#
parse_vmtx

fn parse_vmtx(reader : BinaryReader, offset : Int, num_glyphs : Int, num_v_metrics : Int) -> (Array[Int], Array[Int])

Parse vmtx table: returns (advance_heights, top_side_bearings)

#
parse_vorg

fn parse_vorg(reader : BinaryReader, offset : Int) -> VorgData

Parse VORG table: returns VorgData with default origin and per-glyph overrides

#
parse_woff1

fn parse_woff1(data : Bytes) -> TTFont?

Parse a WOFF1 font, decompress tables, rebuild sfnt, and delegate to parse_ttf

#
parse_woff2

fn parse_woff2(data : Bytes) -> TTFont?

Parse a WOFF2 font, decompress tables, reconstruct transforms, and delegate to parse_ttf

#
path_commands_to_svg_d

fn path_commands_to_svg_d(commands : Array[
PathCommand
]) -> String

Convert font outline PathCommands to SVG path d attribute string.

#
rasterize_glyph

fn rasterize_glyph(font : TTFont, codepoint : Int, size_px : Double) -> GlyphBitmap?

Rasterize a glyph outline to a pixel bitmap using SVG rendering. Returns None for glyphs with no outline (e.g., space).

#
rebuild_sfnt

fn rebuild_sfnt(flavor : Int, tables : Array[(String, Bytes)]) -> Bytes

Rebuild an sfnt (TrueType/OpenType) binary from individual table data. Produces: Offset Table (12 bytes) + Table Records (16 bytes x n) + Table Data (4-byte aligned)

#
scale_commands

fn scale_commands(commands : Array[
PathCommand
], scale : Double, flip_y : Bool) -> Array[
PathCommand
]

#
subset_font

fn subset_font(data : Bytes, codepoints : Array[Int]) -> Bytes?

Subset a TrueType font to include only the given codepoints. Returns a new sfnt binary containing only the required glyphs. Only supports glyf-based TrueType fonts (not CFF/CFF2).

#
write_be16

fn write_be16(out : Array[Byte], offset : Int, value : Int) -> Unit

Write a big-endian uint16 into Array[Byte]

#
write_be32

fn write_be32(out : Array[Byte], offset : Int, value : Int) -> Unit

Write a big-endian uint32 into Array[Byte]