code wiki / _hdl_build / nx_browser_find_gate.nx
nx_browser_find_gate.nx source
↩ module page · 131 lines · 7042 B
1// nx_browser_find_gate.nx -- gate for FIND-IN-PAGE (the Ctrl+F feature every browser has; UX census had
2// it as an ADMITTED gap -- this flips it, with EVIDENCE). Proves on the real bench page through the real
3// core: (T1) the term "wizards" is FOUND with the right match count; (T2) the first-match page-y is
4// returned (scroll-to target) and really is the paragraph's y; (T3) with the find active the render shows
5// HIGHLIGHT pixels (#FFE066) under the match; (T4) with no find active there are ZERO highlight pixels;
6// (T5) NEG: an absent term matches 0 and highlights NOTHING (the highlighter cannot false-fire);
7// (T6) case-insensitive ("WIZARDS" == "wizards"); (T7) EVIDENCE CLIP recorded: page -> find+highlight ->
8// scrolled-to-match, browser-playable APNG (knowledge/status/usersim_find_clip.png).
9// expect_exit: 0 license_tier: ORIGINAL
10import "nx_browser_render.nx"
11import "nx_apng_write.nx"
12import "nx_gate_verdict.nx"
13
14func fg_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 fg_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 }
16
17const FG_W: i64 = 500
18const FG_H: i64 = 400
19
20// render into a fresh RGBA buffer at scroll sy; returns pixels
21func fg_frame(page: *Page, sy: i64) -> *u8 {
22 let fb: *Framebuffer = sys_mmap(NX_FRAMEBUFFER_BYTES) as *Framebuffer
23 let px: *u8 = sys_mmap(FG_W*FG_H*4 + 64)
24 nx_framebuffer_init(fb, px, FG_W, FG_H)
25 br_draw_fb_at(fb, page, FG_W, "usersim://find\x00" as *u8, 14, 1, sy)
26 return px
27}
28// count highlight-yellow pixels (255,224,102)
29func fg_hl(px: *u8) -> i64 {
30 var cnt: i64 = 0
31 var i: i64 = 0
32 while i < FG_W*FG_H {
33 if (px[i*4] as i64)==255 { if (px[i*4+1] as i64)==224 { if (px[i*4+2] as i64)==102 { cnt=cnt+1 } } }
34 i = i + 1
35 }
36 return cnt
37}
38func fg_rgb(px: *u8, rgb: *u8) -> i64 {
39 var p: i64 = 0
40 while p < FG_W*FG_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 }
41 return 0
42}
43
44func main() -> i64 {
45 fg_puts("FIND-IN-PAGE gate: search -> highlight -> scroll-to-match, on the real core, with clip evidence\n" as *u8)
46 let lp: *i64 = sys_mmap(16) as *i64
47 let html: *u8 = sys_read_file("knowledge/status/ocr_bench_page.html\x00" as *u8, lp)
48 if lp[0] <= 0 { fg_puts("find_gate: no bench page\n" as *u8); sys_exit(1); return 1 }
49 let page: *Page = sys_mmap(NX_PAGE_BYTES) as *Page
50 page.raw = html
51 page.raw_len = lp[0]
52 br_layout(page, FG_W)
53 if page.ok != 1 { fg_puts("find_gate: layout failed\n" as *u8); sys_exit(1); return 1 }
54
55 var pass: i64=0
56 var ttl: i64=0
57
58 // T1: find "wizards" (appears once in the pangram paragraph)
59 let yb: *i64 = sys_mmap(16) as *i64
60 let m1: i64 = br_find(page, "wizards\x00" as *u8, 7, yb)
61 ttl=ttl+1; fg_puts(" T1 find 'wizards': matches=" as *u8); fg_num(m1); fg_puts(" (expect 1): " as *u8)
62 if m1==1 { pass=pass+1; fg_puts("PASS\n" as *u8) } else { fg_puts("FAIL\n" as *u8) }
63
64 // T2: first-match y is a real content y (below the h1, above page_h)
65 ttl=ttl+1; fg_puts(" T2 scroll-to target y=" as *u8); fg_num(yb[0]); fg_puts(" (0 < y < page_h " as *u8); fg_num(page.page_h); fg_puts("): " as *u8)
66 if yb[0] > 0 { if yb[0] < page.page_h { pass=pass+1; fg_puts("PASS\n" as *u8) } else { fg_puts("FAIL\n" as *u8) } } else { fg_puts("FAIL\n" as *u8) }
67
68 // T3: highlight pixels present while the find is active
69 let pxa: *u8 = fg_frame(page, 0)
70 let hla: i64 = fg_hl(pxa)
71 ttl=ttl+1; fg_puts(" T3 highlight pixels with find active (got " as *u8); fg_num(hla); fg_puts(" > 100): " as *u8)
72 if hla > 100 { pass=pass+1; fg_puts("PASS\n" as *u8) } else { fg_puts("FAIL\n" as *u8) }
73
74 // T4: clearing the find removes ALL highlight
75 page.find_ptr = 0
76 page.find_len = 0
77 let pxb: *u8 = fg_frame(page, 0)
78 let hlb: i64 = fg_hl(pxb)
79 ttl=ttl+1; fg_puts(" T4 zero highlight pixels with find cleared (got " as *u8); fg_num(hlb); fg_puts("): " as *u8)
80 if hlb == 0 { pass=pass+1; fg_puts("PASS\n" as *u8) } else { fg_puts("FAIL\n" as *u8) }
81
82 // T5 NEG: absent term -> 0 matches, no highlight
83 let m2: i64 = br_find(page, "zzqx\x00" as *u8, 4, yb)
84 let pxn: *u8 = fg_frame(page, 0)
85 let hln: i64 = fg_hl(pxn)
86 ttl=ttl+1; fg_puts(" T5 NEG absent term: matches=" as *u8); fg_num(m2); fg_puts(" highlight=" as *u8); fg_num(hln); fg_puts(": " as *u8)
87 if m2==0 { if hln==0 { pass=pass+1; fg_puts("PASS\n" as *u8) } else { fg_puts("FAIL\n" as *u8) } } else { fg_puts("FAIL\n" as *u8) }
88
89 // T6: case-insensitive
90 let m3: i64 = br_find(page, "WIZARDS\x00" as *u8, 7, yb)
91 ttl=ttl+1; fg_puts(" T6 case-insensitive 'WIZARDS': matches=" as *u8); fg_num(m3); fg_puts(": " as *u8)
92 if m3==1 { pass=pass+1; fg_puts("PASS\n" as *u8) } else { fg_puts("FAIL\n" as *u8) }
93
94 // T7: EVIDENCE CLIP -- plain page, find+highlight, scrolled-to-match
95 let st: *ApngState = sys_mmap(NX_APNG_STATE_BYTES) as *ApngState
96 apng_open(st, "knowledge/status/usersim_find_clip.png\x00" as *u8, FG_W, FG_H, 3, 2, 3)
97 let rgb: *u8 = sys_mmap(FG_W*FG_H*3 + 64)
98 page.find_ptr = 0
99 page.find_len = 0
100 let f1: *u8 = fg_frame(page, 0)
101 fg_rgb(f1, rgb)
102 apng_frame(st, rgb) // frame 1: the page
103 br_find(page, "wizards\x00" as *u8, 7, yb)
104 let f2: *u8 = fg_frame(page, 0)
105 fg_rgb(f2, rgb)
106 apng_frame(st, rgb) // frame 2: highlighted
107 var sy: i64 = yb[0] - 60
108 if sy < 0 { sy = 0 }
109 let f3: *u8 = fg_frame(page, sy)
110 fg_rgb(f3, rgb)
111 apng_frame(st, rgb) // frame 3: scrolled to the match
112 apng_close(st)
113 let cl: *i64 = sys_mmap(16) as *i64
114 cl[0]=0-1
115 let cb: *u8 = sys_read_file("knowledge/status/usersim_find_clip.png\x00" as *u8, cl)
116 ttl=ttl+1; fg_puts(" T7 evidence clip recorded + animated (" as *u8); fg_num(cl[0]); fg_puts("B): " as *u8)
117 var clip_ok: i64 = 0
118 if cl[0] > 50000 { if (cb[37] as i64)==97 { if (cb[38] as i64)==99 { clip_ok=1 } } }
119 if clip_ok==1 { pass=pass+1; fg_puts("PASS\n" as *u8) } else { fg_puts("FAIL\n" as *u8) }
120
121 fg_puts("BROWSER-FIND-GATE passed " as *u8); fg_num(pass); fg_puts("/" as *u8); fg_num(ttl)
122 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
123 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
124 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
125 let ctr__dry: *i64 = gv_ctr()
126 ctr__dry[0] = pass
127 ctr__dry[1] = ttl
128 let rc__dry: i64 = gv_verdict("BROWSER-FIND-GATE" as *u8, ctr__dry, "find-in-page works; watch knowledge/status/usersim_find_clip.png)" as *u8)
129 sys_exit(rc__dry)
130 return rc__dry
131}