code wiki / _hdl_build / nx_font_baseline_census.nx
nx_font_baseline_census.nx source
↩ module page · 160 lines · 8651 B
1// nx_font_baseline_census.nx -- the PROFESSIONAL-CONSISTENCY benchmark for the pioneer font: how much do the
2// letters BOUNCE off the baseline? Amateur type has a wandering baseline; professional type is dead-flat (round
3// letters overshoot by a small CONSTANT). Renders an all-x-height word ("consensus" -- no ascenders/descenders,
4// so every glyph's bottom IS the baseline) in OUR font and Chrome's Arial; segments letters by white-column
5// gaps; measures each letter's bottom row; reports the STANDARD DEVIATION of the bottoms, normalized by letter
6// height (permille) -> the bounce. Lower = more professional. LIAR-KILL: a synthetic ALIGNED row of bars must
7// read ~0 bounce and a deliberately BOUNCY row must read high -- else the metric is broken. license_tier:
8// ORIGINAL expect_exit: 0
9import "nx_img_bytes_to_rgb.nx"
10const K_MAGIC_2126: i64 = 2126
11const K_MAGIC_7152: i64 = 7152
12const K_MAGIC_10000: i64 = 10000
13
14func fb_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
15func fb_num(v: i64) -> i64 { let b: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)} 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 }
16func fb_lum(rgb: *u8, o: i64) -> i64 { return (K_MAGIC_2126*(rgb[o] as i64)+K_MAGIC_7152*(rgb[o+1] as i64)+722*(rgb[o+2] as i64))/K_MAGIC_10000 }
17func fb_isqrt(n: i64) -> i64 { if n<=0 { return 0 } var x: i64=n; var y: i64=(x+1)/2; while y<x { x=y; y=(x+n/x)/2 } return x }
18
19// segment the ink into letters (by white-column gaps) and measure the STD of letter-bottoms / letter-height,
20// in permille. out[0]=bounce_permille out[1]=nletters out[2]=mean_height_px. Returns 0 ok, -1 fail.
21func fb_measure(rgb: *u8, w: i64, h: i64, out: *i64) -> i64 {
22 // per-column: does it have ink, and what is its bottom-most ink row / top-most
23 let colink: *i64 = sys_mmap(8*(w+4)) as *i64
24 let colbot: *i64 = sys_mmap(8*(w+4)) as *i64
25 let coltop: *i64 = sys_mmap(8*(w+4)) as *i64
26 var x: i64=0
27 while x<w {
28 var has: i64=0; var bot: i64=0-1; var top: i64=h
29 var y: i64=0
30 while y<h { if fb_lum(rgb,(y*w+x)*3) < 128 { has=1; if y>bot { bot=y }; if y<top { top=y } } y=y+1 }
31 colink[x]=has; colbot[x]=bot; coltop[x]=top
32 x=x+1
33 }
34 // walk columns; a letter = a run of ink columns; a gap of >=4 white columns ends a letter
35 let bots: *i64 = sys_mmap(8*256) as *i64
36 let hts: *i64 = sys_mmap(8*256) as *i64
37 var nl: i64=0
38 var inrun: i64=0
39 var runbot: i64=0-1
40 var runtop: i64=h
41 var gap: i64=0
42 x=0
43 while x<w {
44 if colink[x]==1 {
45 if inrun==0 { inrun=1; runbot=0-1; runtop=h }
46 if colbot[x]>runbot { runbot=colbot[x] }
47 if coltop[x]<runtop { runtop=coltop[x] }
48 gap=0
49 } else {
50 if inrun==1 {
51 gap=gap+1
52 if gap>=4 { // letter ended
53 if nl<256 { bots[nl]=runbot; hts[nl]=runbot-runtop; nl=nl+1 }
54 inrun=0
55 }
56 }
57 }
58 x=x+1
59 }
60 if inrun==1 { if nl<256 { bots[nl]=runbot; hts[nl]=runbot-runtop; nl=nl+1 } }
61 out[1]=nl
62 if nl<3 { out[0]=0; out[2]=0; return 0-1 }
63 // mean bottom + mean height
64 var sb: i64=0; var sh: i64=0
65 var i: i64=0
66 while i<nl { sb=sb+bots[i]; sh=sh+hts[i]; i=i+1 }
67 let mb: i64=sb/nl
68 let mh: i64=sh/nl
69 out[2]=mh
70 // variance of bottoms
71 var vs: i64=0
72 i=0
73 while i<nl { let dd: i64=bots[i]-mb; vs=vs+dd*dd; i=i+1 }
74 let sd: i64=fb_isqrt(vs/nl)
75 if mh<=0 { out[0]=0; return 0 }
76 out[0]=(sd*1000)/mh // bounce = baseline-STD / letter-height, permille
77 return 0
78}
79func fb_load(path: *u8, wh: *i64) -> *u8 {
80 let lp: *i64=sys_mmap(16) as *i64; lp[0]=0-1
81 let raw: *u8=sys_read_file(path, lp)
82 if lp[0]<=0 { return 0 as *u8 }
83 return nx_img_bytes_to_rgb(raw, lp[0], wh)
84}
85// synthetic row of N bars; jitter=max baseline wobble px (0=aligned). Into rgb (white bg).
86func fb_make_bars(rgb: *u8, w: i64, h: i64, n: i64, jitter: i64) -> i64 {
87 var i: i64=0
88 while i<w*h*3 { rgb[i]=255 as u8; i=i+1 }
89 let bw: i64=40
90 let step: i64=w/n
91 var k: i64=0
92 while k<n {
93 let x0: i64=k*step+20
94 var jb: i64=0
95 if jitter>0 { jb=(k*37)%jitter } // deterministic pseudo-wobble
96 let ytop: i64=60
97 let ybot: i64=h-40-jb
98 var yy: i64=ytop
99 while yy<ybot { var xx: i64=x0; while xx<x0+bw { let o: i64=(yy*w+xx)*3; rgb[o]=20 as u8; rgb[o+1]=20 as u8; rgb[o+2]=43 as u8; xx=xx+1 } yy=yy+1 }
100 k=k+1
101 }
102 return 0
103}
104
105func main() -> i64 {
106 fb_puts("=== nx_font_baseline_census -- baseline BOUNCE (professional consistency) vs Chrome ===\n" as *u8)
107 let W: i64=1000
108 let H: i64=300
109 let rgb: *u8=sys_mmap(W*H*3+64)
110 let sa: *i64=sys_mmap(32) as *i64
111 let sb2: *i64=sys_mmap(32) as *i64
112 // LIAR-KILL: aligned bars vs bouncy bars
113 fb_make_bars(rgb, W, H, 9, 0)
114 fb_measure(rgb, W, H, sa)
115 fb_make_bars(rgb, W, H, 9, 60)
116 fb_measure(rgb, W, H, sb2)
117 fb_puts(" synthetic ALIGNED bars bounce=" as *u8); fb_num(sa[0]); fb_puts(" permille BOUNCY bars bounce=" as *u8); fb_num(sb2[0]); fb_puts(" permille\n" as *u8)
118 var metric_ok: i64=0
119 if sb2[0] > sa[0]+40 { metric_ok=1 }
120 if metric_ok==0 { fb_puts(" LIAR-KILL FIRED: metric can't tell aligned from bouncy -> INVALID\nNX-FONT-BASELINE: BROKEN\n" as *u8); sys_exit(1); return 1 }
121 fb_puts(" metric liar-kill: PASS (bouncy reads >aligned+40 -> the metric measures baseline bounce)\n" as *u8)
122
123 let owh: *i64=sys_mmap(16) as *i64
124 let cwh: *i64=sys_mmap(16) as *i64
125 let orgb: *u8=fb_load("knowledge/status/typeq_base_ours.png\x00" as *u8, owh)
126 let crgb: *u8=fb_load("knowledge/status/typeq_base_chrome.png\x00" as *u8, cwh)
127 let so: *i64=sys_mmap(32) as *i64
128 let sc: *i64=sys_mmap(32) as *i64
129 so[0]=0-1; sc[0]=0-1
130 if orgb!=(0 as *u8) { fb_measure(orgb, owh[0], owh[1], so) }
131 if crgb!=(0 as *u8) { fb_measure(crgb, cwh[0], cwh[1], sc) }
132 fb_puts(" ours bounce=" as *u8); fb_num(so[0]); fb_puts(" permille (letters=" as *u8); fb_num(so[1]); fb_puts(", h=" as *u8); fb_num(so[2]); fb_puts("px)\n" as *u8)
133 fb_puts(" chrome bounce=" as *u8); fb_num(sc[0]); fb_puts(" permille (letters=" as *u8); fb_num(sc[1]); fb_puts(", h=" as *u8); fb_num(sc[2]); fb_puts("px)\n" as *u8)
134
135 var pass: i64=0; var ttl: i64=0
136 ttl=ttl+1; if metric_ok==1 { pass=pass+1 }
137 ttl=ttl+1; fb_puts(" C2 both words segmented (>=7 letters each): " as *u8); if so[1]>=7 { if sc[1]>=7 { pass=pass+1; fb_puts("PASS\n" as *u8) } else { fb_puts("FAIL\n" as *u8) } } else { fb_puts("FAIL\n" as *u8) }
138 if so[0]>=0 { if sc[0]>=0 {
139 fb_puts(" >>> our baseline bounce " as *u8); fb_num(so[0]); fb_puts(" vs Chrome " as *u8); fb_num(sc[0]); fb_puts(" permille -- " as *u8)
140 if so[0] <= sc[0]+15 { fb_puts("PROFESSIONAL-FLAT (within ~15permille of Chrome), MEASURED\n" as *u8) }
141 else { fb_puts("still BOUNCY vs Chrome (gap " as *u8); fb_num(so[0]-sc[0]); fb_puts(") -- normalize more round-letter overshoots\n" as *u8) }
142 } }
143 // benchmark log line (composed by nx_font_pioneer_benchmark)
144 let lg: *u8 = sys_mmap(128)
145 var lo: i64 = 0
146 let pfx: *u8 = "FONT-BASELINE ours=\x00" as *u8
147 while pfx[lo] != (0 as u8) { lg[lo]=pfx[lo]; lo=lo+1 }
148 var mv: i64 = so[0]; if mv<0 { mv=0 }
149 let t2: *u8 = sys_mmap(24); var k2: i64=0; if mv==0 { t2[0]=48 as u8; k2=1 } while mv>0 { t2[k2]=(48+(mv%10)) as u8; mv=mv/10; k2=k2+1 } var z: i64=0; while z<k2 { lg[lo]=t2[k2-1-z]; lo=lo+1; z=z+1 }
150 let sfx: *u8 = " chrome=\x00" as *u8; var si: i64=0; while sfx[si]!=(0 as u8) { lg[lo]=sfx[si]; lo=lo+1; si=si+1 }
151 var cv: i64 = sc[0]; if cv<0 { cv=0 }
152 let t3: *u8 = sys_mmap(24); var k3: i64=0; if cv==0 { t3[0]=48 as u8; k3=1 } while cv>0 { t3[k3]=(48+(cv%10)) as u8; cv=cv/10; k3=k3+1 } z=0; while z<k3 { lg[lo]=t3[k3-1-z]; lo=lo+1; z=z+1 }
153 lg[lo]=10 as u8; lo=lo+1
154 let bfd: i64 = sys_openat_wr("knowledge/status/font_baseline.log\x00" as *u8, 0x1a4)
155 if bfd > 0 { sys_write(bfd, lg, lo); sys_close(bfd) }
156
157 fb_puts("FONT-BASELINE-CENSUS-GATE passed " as *u8); fb_num(pass); fb_puts("/" as *u8); fb_num(ttl)
158 if pass==ttl { fb_puts(" verdict=GREEN (baseline consistency MEASURED, liar-killed)\n" as *u8); sys_exit(0); return 0 }
159 fb_puts(" verdict=RED\n" as *u8); sys_exit(1); return 1
160}