code wiki / _hdl_build / nx_browser_darkmode_gate.nx
nx_browser_darkmode_gate.nx source
↩ module page · 138 lines · 7364 B
1// nx_browser_darkmode_gate.nx -- DARK MODE (the "OLED look" the operator framed the visual push around),
2// a UX-census ADMIT flipped by BUILD + evidence. Renders the SAME bench page through the real core in LIGHT
3// (dark_mode=0) and DARK (dark_mode=1); proves: (T1) the light page is majority-LIGHT; (T2) the dark page is
4// majority-DARK -- the theme actually FLIPPED (CAN-FAIL control: if the flag did nothing the two renders would
5// be identical and this fails); (T3) dark page still has LIGHT TEXT ink (readable, not an all-black void);
6// (T4) the browser chrome went dark too (coherent, not a light bar on a dark page); (T5) evidence PNGs written
7// (light + dark + a side-by-side) for the eyeball. license_tier: ORIGINAL expect_exit: 0
8import "nx_browser_render.nx"
9import "nx_gate_verdict.nx"
10
11func dm_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
12func dm_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 }
13
14const DM_W: i64 = 900
15
16func dm_render(html: *u8, hlen: i64, dark: i64, hout: *i64) -> *u8 {
17 let page: *Page = sys_mmap(NX_PAGE_BYTES) as *Page
18 page.raw = html
19 page.raw_len = hlen
20 page.dark_mode = dark // set BEFORE br_layout (it picks the default CSS)
21 br_layout(page, DM_W/2)
22 page.vec_headings = 1
23 var H: i64 = (page.page_h + NX_CHROME_H + 40) * 2
24 if H > 1400 { H = 1400 }
25 let fb: *Framebuffer = sys_mmap(NX_FRAMEBUFFER_BYTES) as *Framebuffer
26 let px: *u8 = sys_mmap(DM_W*H*4 + 64)
27 nx_framebuffer_init(fb, px, DM_W, H)
28 var url: *u8 = "nishi://reader\x00" as *u8
29 if dark == 1 { url = "nishi://reader (dark)\x00" as *u8 }
30 br_draw_fb(fb, page, DM_W/2, url, 21, 2)
31 hout[0] = H
32 return px
33}
34// count pixels darker than lum L and lighter than lum L, in the PAGE area (below the chrome)
35func dm_counts(px: *u8, W: i64, H: i64, out: *i64) -> i64 {
36 var dark: i64=0
37 var light: i64=0
38 var lightink: i64=0
39 let y0: i64 = NX_CHROME_H*2 + 4
40 var y: i64=y0
41 while y<H {
42 var x: i64=0
43 while x<W {
44 let o: i64=(y*W+x)*4
45 let lum: i64=(2126*(px[o] as i64)+7152*(px[o+1] as i64)+722*(px[o+2] as i64))/10000
46 if lum < 60 { dark=dark+1 }
47 if lum > 200 { light=light+1 }
48 if lum > 150 { if lum < 245 { lightink=lightink+1 } } // light-gray text ink (not pure white)
49 x=x+1
50 }
51 y=y+1
52 }
53 out[0]=dark; out[1]=light; out[2]=lightink
54 return 0
55}
56func dm_rgb_write(px: *u8, W: i64, H: i64, path: *u8) -> i64 {
57 let rgb: *u8 = sys_mmap(W*H*3+64)
58 var p: i64=0
59 while p<W*H { rgb[p*3]=px[p*4]; rgb[p*3+1]=px[p*4+1]; rgb[p*3+2]=px[p*4+2]; p=p+1 }
60 nx_png_write_rgb(path, rgb, W, H)
61 return 0
62}
63// chrome-bar mean luminance (top strip) -- proves the chrome darkened too
64func dm_chrome_lum(px: *u8, W: i64) -> i64 {
65 var s: i64=0
66 var n: i64=0
67 var y: i64=2
68 while y<NX_CHROME_H*2-2 { var x: i64=0; while x<W { let o: i64=(y*W+x)*4; s=s+(2126*(px[o] as i64)+7152*(px[o+1] as i64)+722*(px[o+2] as i64))/10000; n=n+1; x=x+8 } y=y+2 }
69 if n>0 { return s/n } else { return 0 }
70}
71
72func main() -> i64 {
73 dm_puts("DARK MODE gate: the OLED reader theme through the real core, with a can-fail control\n" as *u8)
74 let lp: *i64 = sys_mmap(16) as *i64
75 let html: *u8 = sys_read_file("knowledge/status/ocr_bench_page.html\x00" as *u8, lp)
76 if lp[0] <= 0 { dm_puts("darkmode: no bench page\n" as *u8); sys_exit(1); return 1 }
77
78 let hl: *i64 = sys_mmap(16) as *i64
79 let hd: *i64 = sys_mmap(16) as *i64
80 let lpx: *u8 = dm_render(html, lp[0], 0, hl)
81 let dpx: *u8 = dm_render(html, lp[0], 1, hd)
82 let lc: *i64 = sys_mmap(32) as *i64
83 let dc: *i64 = sys_mmap(32) as *i64
84 dm_counts(lpx, DM_W, hl[0], lc)
85 dm_counts(dpx, DM_W, hd[0], dc)
86 dm_puts(" light page: dark-px=" as *u8); dm_num(lc[0]); dm_puts(" light-px=" as *u8); dm_num(lc[1]); dm_puts("\n" as *u8)
87 dm_puts(" dark page: dark-px=" as *u8); dm_num(dc[0]); dm_puts(" light-px=" as *u8); dm_num(dc[1]); dm_puts(" light-ink=" as *u8); dm_num(dc[2]); dm_puts("\n" as *u8)
88 let lchrome: i64 = dm_chrome_lum(lpx, DM_W)
89 let dchrome: i64 = dm_chrome_lum(dpx, DM_W)
90 dm_puts(" chrome-bar mean lum: light=" as *u8); dm_num(lchrome); dm_puts(" dark=" as *u8); dm_num(dchrome); dm_puts("\n" as *u8)
91
92 var pass: i64=0
93 var ttl: i64=0
94 ttl=ttl+1; dm_puts(" T1 light page is majority-LIGHT (light>dark): " as *u8); if lc[1] > lc[0]*4 { pass=pass+1; dm_puts("PASS\n" as *u8) } else { dm_puts("FAIL\n" as *u8) }
95 ttl=ttl+1; dm_puts(" T2 dark page is majority-DARK (theme FLIPPED, can-fail): " as *u8); if dc[0] > dc[1]*4 { pass=pass+1; dm_puts("PASS\n" as *u8) } else { dm_puts("FAIL\n" as *u8) }
96 ttl=ttl+1; dm_puts(" T3 dark page has LIGHT TEXT ink (readable, not a void): " as *u8); if dc[2] > 2000 { pass=pass+1; dm_puts("PASS\n" as *u8) } else { dm_puts("FAIL\n" as *u8) }
97 ttl=ttl+1; dm_puts(" T4 chrome went dark too (dark bar << light bar lum): " as *u8); if dchrome < 90 { if lchrome > 180 { pass=pass+1; dm_puts("PASS\n" as *u8) } else { dm_puts("FAIL\n" as *u8) } } else { dm_puts("FAIL\n" as *u8) }
98
99 dm_rgb_write(lpx, DM_W, hl[0], "knowledge/status/darkmode_light.png\x00" as *u8)
100 dm_rgb_write(dpx, DM_W, hd[0], "knowledge/status/darkmode_dark.png\x00" as *u8)
101 // side-by-side (light left, dark right) into one PNG
102 var CH: i64 = hl[0]
103 if hd[0] < CH { CH = hd[0] }
104 let cw: i64 = DM_W*2 + 20
105 let comp: *u8 = sys_mmap(cw*CH*3 + 64)
106 var q: i64=0
107 while q<cw*CH*3 { comp[q]=30 as u8; q=q+1 }
108 var yy: i64=0
109 while yy<CH {
110 var xx: i64=0
111 while xx<DM_W {
112 let lo: i64=(yy*DM_W+xx)*4
113 let co: i64=(yy*cw+xx)*3
114 comp[co]=lpx[lo]; comp[co+1]=lpx[lo+1]; comp[co+2]=lpx[lo+2]
115 let ro: i64=(yy*cw+(xx+DM_W+20))*3
116 comp[ro]=dpx[lo]; comp[ro+1]=dpx[lo+1]; comp[ro+2]=dpx[lo+2]
117 xx=xx+1
118 }
119 yy=yy+1
120 }
121 nx_png_write_rgb("knowledge/status/darkmode_compare.png\x00" as *u8, comp, cw, CH)
122 let clp: *i64 = sys_mmap(16) as *i64
123 clp[0]=0-1
124 let cb: *u8 = sys_read_file("knowledge/status/darkmode_compare.png\x00" as *u8, clp)
125 ttl=ttl+1; dm_puts(" T5 evidence PNGs written (light+dark+compare " as *u8); dm_num(clp[0]); dm_puts("B): " as *u8)
126 if clp[0] > 5000 { pass=pass+1; dm_puts("PASS\n" as *u8) } else { dm_puts("FAIL\n" as *u8) }
127
128 dm_puts("BROWSER-DARKMODE-GATE passed " as *u8); dm_num(pass); dm_puts("/" as *u8); dm_num(ttl)
129 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
130 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
131 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
132 let ctr__dry: *i64 = gv_ctr()
133 ctr__dry[0] = pass
134 ctr__dry[1] = ttl
135 let rc__dry: i64 = gv_verdict("BROWSER-DARKMODE-GATE" as *u8, ctr__dry, "dark mode works; see knowledge/status/darkmode_compare.png)" as *u8)
136 sys_exit(rc__dry)
137 return rc__dry
138}