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}