code wiki / _hdl_build / nx_font_advdiff.nx

nx_font_advdiff.nx source

↩ module page · 102 lines · 4696 B

1// nx_font_advdiff.nx -- FONT-METRICS DRIFT instrument (operator 2026-07-28: "use free fonts as 2// another benchmark -- make sure the browser isn't held back by something dumb like that"). 3// Reads a real TTF's cmap(format 4) + hmtx and prints, for ASCII 32..126, the font's advance in 4// 1000/em units next to OUR font_adv_em(ch), plus the drift. Wrap points come from summed advances, 5// so per-char drift vs Arial (Chrome's default sans; metrics == Liberation Sans, SIL-OFL) IS the 6// structural-exactness gap of every line break. usage: nx_font_advdiff <path.ttf> 7import "nx_syscalls.nx" 8import "nx_font.nx" 9const K_MAGIC_65536: i64 = 65536 10 11func w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 12func n2(v: i64) -> i64 { let b: *u8=sys_mmap(28); var m: i64=v; if m<0{w("-" as *u8);m=0-m} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 } 13func u16(p: *u8, o: i64) -> i64 { return ((p[o]&0xff)*256) + (p[o+1]&0xff) } 14func u32(p: *u8, o: i64) -> i64 { return (u16(p,o)*K_MAGIC_65536) + u16(p,o+2) } 15func tag_is(p: *u8, o: i64, a: i64, b: i64, c: i64, d: i64) -> i64 { 16 if (p[o]&0xff)==a { if (p[o+1]&0xff)==b { if (p[o+2]&0xff)==c { if (p[o+3]&0xff)==d { return 1 } } } } 17 return 0 18} 19 20func main(argc: i64, argv: *i64) -> i64 { 21 if argc < 2 { w("usage: nx_font_advdiff <path.ttf>\n" as *u8); sys_exit(2); return 2 } 22 let lp: *i64 = sys_mmap(16) as *i64 23 let f: *u8 = sys_read_file(argv[1] as *u8, lp) 24 if (f as i64) == 0 { w("cannot read ttf\n" as *u8); sys_exit(3); return 3 } 25 let ntab: i64 = u16(f, 4) 26 var head_o: i64 = 0 - 1 27 var hhea_o: i64 = 0 - 1 28 var hmtx_o: i64 = 0 - 1 29 var cmap_o: i64 = 0 - 1 30 var ti: i64 = 0 31 while ti < ntab { 32 let ro: i64 = 12 + ti*16 33 if tag_is(f,ro,104,101,97,100)==1 { head_o = u32(f,ro+8) } // head 34 if tag_is(f,ro,104,104,101,97)==1 { hhea_o = u32(f,ro+8) } // hhea 35 if tag_is(f,ro,104,109,116,120)==1 { hmtx_o = u32(f,ro+8) } // hmtx 36 if tag_is(f,ro,99,109,97,112)==1 { cmap_o = u32(f,ro+8) } // cmap 37 ti = ti + 1 38 } 39 if head_o < 0 { w("no head\n" as *u8); sys_exit(4); return 4 } 40 if hmtx_o < 0 { w("no hmtx\n" as *u8); sys_exit(4); return 4 } 41 if cmap_o < 0 { w("no cmap\n" as *u8); sys_exit(4); return 4 } 42 let upem: i64 = u16(f, head_o + 18) 43 let numh: i64 = u16(f, hhea_o + 34) 44 // cmap: pick a format-4 subtable (prefer windows 3/1; accept any format-4) 45 let ncm: i64 = u16(f, cmap_o + 2) 46 var sub4: i64 = 0 - 1 47 var ci: i64 = 0 48 while ci < ncm { 49 let er: i64 = cmap_o + 4 + ci*8 50 let so: i64 = cmap_o + u32(f, er+4) 51 if u16(f, so) == 4 { if sub4 < 0 { sub4 = so } if u16(f,er)==3 { if u16(f,er+2)==1 { sub4 = so } } } 52 ci = ci + 1 53 } 54 if sub4 < 0 { w("no cmap4\n" as *u8); sys_exit(5); return 5 } 55 let segx2: i64 = u16(f, sub4 + 6) 56 let endo: i64 = sub4 + 14 57 let starto: i64 = endo + segx2 + 2 58 let deltao: i64 = starto + segx2 59 let rangeo: i64 = deltao + segx2 60 w("ch ttf1000 ours drift (upem=" as *u8); n2(upem); w(" numh=" as *u8); n2(numh); w(")\n" as *u8) 61 var sumabs: i64 = 0 62 var cnt: i64 = 0 63 var big: i64 = 0 64 var ch: i64 = 32 65 while ch <= 126 { 66 // find segment 67 var g: i64 = 0 68 var si: i64 = 0 69 var go: i64 = 1 70 while go == 1 { 71 if si*2 >= segx2 { go = 0 } 72 else { 73 if u16(f, endo + si*2) >= ch { 74 if u16(f, starto + si*2) <= ch { 75 let ro2: i64 = u16(f, rangeo + si*2) 76 if ro2 == 0 { g = (ch + u16(f, deltao + si*2)) % K_MAGIC_65536 } 77 else { g = u16(f, rangeo + si*2 + ro2 + (ch - u16(f, starto + si*2))*2) } 78 } 79 go = 0 80 } else { si = si + 1 } 81 } 82 } 83 var gm: i64 = g 84 if gm >= numh { gm = numh - 1 } 85 let adv: i64 = u16(f, hmtx_o + gm*4) 86 let a1000: i64 = (adv * 1000) / upem 87 let ours: i64 = font_adv_em(ch) 88 let d: i64 = a1000 - ours 89 var ad: i64 = d 90 if ad < 0 { ad = 0 - ad } 91 sumabs = sumabs + ad 92 cnt = cnt + 1 93 if ad > 50 { big = big + 1 } 94 n2(ch); w(" " as *u8); n2(a1000); w(" " as *u8); n2(ours); w(" " as *u8); n2(d); w("\n" as *u8) 95 ch = ch + 1 96 } 97 w("SUMMARY meanabs=" as *u8); n2(sumabs / cnt) 98 w(" chars_drift_gt50=" as *u8); n2(big) 99 w("/" as *u8); n2(cnt); w("\n" as *u8) 100 sys_exit(0) 101 return 0 102}