code wiki / _hdl_build / nx_ttf_fontlib.nx

nx_ttf_fontlib.nx

buildroot/runtime/_hdl_build/nx_ttf_fontlib.nx

29060 B601 linesdepth 4pulls 4 transitivereach 78 importersview sourcekind librarytopic ttf
docsdependenciesstructsconstsfunctions

about

nx_ttf_fontlib.nx -- the sovereign TrueType FONT ENGINE as a LIBRARY (the browser's text renderer). Canonical home of the TTF read path first proven in the nx_ttf_raster demo (which has a main() and so cannot be imported): sfnt dir -> head/cmap/loca/glyf/hhea/hmtx(+kern), cmap format-4 (BOTH the delta path and the idRangeOffset/glyphIdArray path), glyf outline decode (flags/short/same/repeat), COMPOSITE glyphs (component offsets + F2Dot14 scale, bounded recursion), quadratic Bezier flattening, NONZERO- WINDING scan conversion with SSxSS supersampled ANTI-ALIASED coverage, a per-(char,size) COVERAGE CACHE (each glyph rasterizes once per size), REAL per-glyph advances from hmtx, pair KERNING from the 'kern' table (format 0, binary search), a mild contrast curve (stem darkening at small sizes), and an RGBA-framebuffer ALPHA-BLEND draw (nx_framebuffer px = R,G,B,A). 2026-09-02 (BR4 first half, /compare/browser rung "Real font files + shaping"): EVERY METRIC IS NOW READ FROM THE FONT, NEVER ASSUMED. The first cut hard-coded unitsPerEm=1000 and ascender=760 -- true of our own emitted nishi_sans.ttf and FALSE of every professional font (Liberation Sans, Arial, Noto: 2048), so a real face would have rasterized at HALF size with its advances halved, and nothing would have failed loudly. unitsPerEm comes from head, ascender/descender/lineGap from hhea, the cell height is DERIVED from (ascender - descender), and the browser's 1000-em advance unit is a conversion at the API edge (tf_adv_em1000), not an assumption inside the rasterizer. A negative left side bearing ('j', '_', 'w' in Liberation) is carried as the record's left margin so no ink is clipped, and ink wider than the advance ('f', 'k') widens the cell instead of being cut at the advance. Fonts proven: our own emitted web_assets/nishi_sans.ttf (96 glyphs, upem 1000) and Liberation Sans (SIL-OFL, upem 2048, 908 kern pairs, 1,076 composite glyphs). No FreeType, no GDI, no DirectWrite. license_tier: ORIGINAL

dependencies 2 imports · 5 importers

nx_syscalls.nx nx_paint_solid_rect.nx nx_ttf_fontlib.nx nx_browser_render.nx nx_browser_render_gif_t139.nx nx_cdmap_referee_lib.nx nx_font_mockup.nx nx_ttf_fontlib_gate.nx

imports: nx_syscalls.nxnx_paint_solid_rect.nx

imported by: nx_browser_render.nxnx_browser_render_gif_t139.nxnx_cdmap_referee_lib.nxnx_font_mockup.nxnx_ttf_fontlib_gate.nx

structs

none

consts

25const TF_MAGIC_32768: i64 = 32768
26const TF_MAGIC_65536: i64 = 65536
27const TF_MAGIC_16777216: i64 = 16777216
28const TF_MAGIC_2048: i64 = 2048
29const TF_F2DOT14_ONE: i64 = 16384 // 1.0 in the F2Dot14 fixed-point the glyf composite scale fields use
32const TF_H_BUF: i64 = 0
33const TF_H_GLYF: i64 = 1
34const TF_H_LOCA: i64 = 2
35const TF_H_LOCFMT: i64 = 3
36const TF_H_CMAPSUB: i64 = 4
37const TF_H_HMTX: i64 = 5
38const TF_H_NUMHM: i64 = 6
39const TF_H_CACHE: i64 = 7
40const TF_H_NSIZES: i64 = 8
41const TF_H_SIZE0: i64 = 9 // 9..9+TF_MAXSZ-1 = the pixel heights with a cache slot
42const TF_MAXSZ: i64 = 16
43const TF_H_UPEM: i64 = 25 // head.unitsPerEm -- READ, never assumed
44const TF_H_ASC: i64 = 26 // hhea.ascender (font units, positive up)
45const TF_H_DESC: i64 = 27 // hhea.descender (font units, negative)
46const TF_H_LINEGAP: i64 = 28 // hhea.lineGap
47const TF_H_KPAIRS: i64 = 29 // byte offset of the kern format-0 pair array (0 = no horizontal kern table)
48const TF_H_KN: i64 = 30 // number of kern pairs
49const TF_H_LEN: i64 = 31 // byte length of the font buffer (every table offset is checked against it)
50const TF_H_NGLYPHS: i64 = 32 // maxp.numGlyphs (bounds every gid before loca is indexed)
51const TF_HSLOTS: i64 = 40
54const TF_R_COV: i64 = 0 // coverage bytes, cw x chh, row-major; row 0 = the ASCENDER line
55const TF_R_CW: i64 = 1 // cell width px
56const TF_R_CHH: i64 = 2 // cell height px = ((asc - desc) * ph) / upem + 1
57const TF_R_ADV: i64 = 3 // advance px at this size (hmtx scaled)
58const TF_R_LM: i64 = 4 // left margin px: the cell's x0 sits this far LEFT of the pen (negative lsb)
59const TF_R_PH: i64 = 5
60const TF_REC: i64 = 8 // i64 slots per record
62const TF_ASCII_LO: i64 = 32
63const TF_ASCII_HI: i64 = 126
64const TF_ASCII_N: i64 = TF_ASCII_HI - TF_ASCII_LO + 1
65const TF_EM1000: i64 = 1000 // the browser's advance unit (font_adv_em speaks 1000-em)
66const TF_SS: i64 = 4 // supersample factor per axis (SS*SS samples per pixel)
67const TF_MAXE: i64 = 500 // flattened-edge capacity per glyph
68const TF_BEZ_STEPS: i64 = 6 // quadratic Bezier flattening steps
69const TF_COMPOSITE_DEPTH: i64 = 4 // bounded recursion for nested composites
70const TF_CONTRAST_DIV: i64 = 170 // stem-darkening curve: a += a*(255-a)/170
71const TF_KERN_SUBHDR: i64 = 14 // kern format-0 subtable header bytes before the pair array
72const TF_KERN_PAIR: i64 = 6 // left(2) right(2) value(2)
73const TF_CMAP_REC: i64 = 8 // encoding record: platform(2) encoding(2) offset(4)
74const TF_MIN_ADV_PX: i64 = 2

functions

76func tf_rd16(b: *u8, o: i64) -> i64 { return (b[o] as i64)*256 + (b[o+1] as i64) }
77func tf_rd16s(b: *u8, o: i64) -> i64 { let v: i64=tf_rd16(b,o); if v>=TF_MAGIC_32768 { return v-TF_MAGIC_65536 } return v }
78func tf_rd32(b: *u8, o: i64) -> i64 { return (b[o] as i64)*TF_MAGIC_16777216 + (b[o+1] as i64)*TF_MAGIC_65536 + (b[o+2] as i64)*256 + (b[o+3] as i64) }
79func tf_bit(f: i64, m: i64) -> i64 { if (f/m)%2 == 1 { return 1 } return 0 }
called by 1: tf_glyph_edges_x
81func tf_rd8s(b: *u8, o: i64) -> i64 { let v: i64 = b[o] as i64; if v >= 128 { return v - 256 } return v }
called by 1: tf_glyph_edges_x
83func tf_find_table(b: *u8, t0: i64, t1: i64, t2: i64, t3: i64) -> i64
called by 1: tf_load_buf calls 2: tf_rd16tf_rd32
95func tf_cmap_lookup(b: *u8, sub: i64, c: i64) -> i64
120func tf_cmap_pick4(b: *u8, cmap: i64, len: i64) -> i64
called by 1: tf_load_buf calls 2: tf_rd16tf_rd32
134func tf_edge_push(ex0: *i64, ey0: *i64, ex1: *i64, ey1: *i64, ne: i64, x0: i64, y0: i64, x1: i64, y1: i64) -> i64
called by 1: tf_glyph_edges_x
142func tf_glyph_edges_x(b: *u8, glyf: i64, loca: i64, locfmt: i64, nglyphs: i64, gid: i64,
269func tf_glyph_edges(b: *u8, glyf: i64, loca: i64, locfmt: i64, nglyphs: i64, gid: i64, ex0: *i64, ey0: *i64, ex1: *i64, ey1: *i64) -> i64
called by 2: tf_rastermain calls 1: tf_glyph_edges_x
272func tf_inside(gx: i64, gy: i64, ex0: *i64, ey0: *i64, ex1: *i64, ey1: *i64, ne: i64) -> i64
called by 1: tf_raster
296func tf_load_buf(b: *u8, len: i64) -> *i64
363func tf_load(path: *u8) -> *i64
372func tf_upem(fh: *i64) -> i64 { return fh[TF_H_UPEM] }
373func tf_asc(fh: *i64) -> i64 { return fh[TF_H_ASC] }
called by 1: main
374func tf_desc(fh: *i64) -> i64 { return fh[TF_H_DESC] }
called by 1: main
375func tf_linegap(fh: *i64) -> i64 { return fh[TF_H_LINEGAP] }
376func tf_kern_count(fh: *i64) -> i64 { return fh[TF_H_KN] }
called by 1: main
377func tf_nglyphs(fh: *i64) -> i64 { return fh[TF_H_NGLYPHS] }
called by 3: mainmainmain
379func tf_asc_px(fh: *i64, ph: i64) -> i64 { return (fh[TF_H_ASC]*ph) / fh[TF_H_UPEM] }
380func tf_desc_px(fh: *i64, ph: i64) -> i64 { return ((0 - fh[TF_H_DESC])*ph) / fh[TF_H_UPEM] }
381func tf_content_px(fh: *i64, ph: i64) -> i64 { return ((fh[TF_H_ASC] - fh[TF_H_DESC])*ph) / fh[TF_H_UPEM] }
383func tf_gid(fh: *i64, ch: i64) -> i64 { return tf_cmap_lookup(fh[TF_H_BUF] as *u8, fh[TF_H_CMAPSUB], ch) }
385func tf_adv_units_gid(fh: *i64, gid: i64) -> i64
393func tf_adv_units(fh: *i64, ch: i64) -> i64 { return tf_adv_units_gid(fh, tf_gid(fh, ch)) }
396func tf_adv_em1000(fh: *i64, ch: i64) -> i64 { return (tf_adv_units(fh, ch) * TF_EM1000) / fh[TF_H_UPEM] }
399func tf_kern_em1000(fh: *i64, a: i64, c: i64) -> i64
424func tf_glyph(fh: *i64, ch: i64, ph: i64) -> *i64
452func tf_glyph_cp(fh: *i64, cp: i64, ph: i64) -> *i64
463func tf_glyph_notdef(fh: *i64, ph: i64) -> *i64
called by 2: bpv_cellbpv_cell calls 2: sys_mmaptf_raster
470func tf_raster(fh: *i64, gid: i64, ph: i64, rec: *i64) -> i64
537func tf_draw_text(fh: *i64, fb: *Framebuffer, x: i64, y: i64, s: *u8, n: i64, ph: i64, cr: i64, cg: i64, cb: i64, cellw: i64) -> i64
called by 2: mk_para_vecmain calls 1: tf_glyph
597func tf_char_adv(fh: *i64, ch: i64, ph: i64) -> i64