code wiki / _hdl_build / nx_rawtext_layout_gate.nx

nx_rawtext_layout_gate.nx source

↩ module page · 67 lines · 3994 B

1// nx_rawtext_layout_gate.nx -- PROOF (re-runnable) of the google-blank root fix: a bare `<` inside a 2// <script>/<style> body (e.g. JS `a<b`, `if (x<y)`) must NOT eat the closing tag and suppress the rest of 3// the page. Before the fix, layout_from_dom relied on a `suppress` counter and let the tokenizer parse 4// `<b` as a start tag whose attribute-skip consumed `</script>` -> script never closed -> all following 5// visible text dropped (google.com rendered blank while laying out 3378px). Fix = layout_from_dom now 6// consumes raw-text bodies via the HTML5 scanner, like the 3 other tokenizer consumers already did. 7// Each test lays out an inline fixture through the REAL br_layout and asserts the post-script text renders. 8// license_tier: ORIGINAL expect_exit: 0 9import "nx_syscalls.nx" 10import "nx_browser_render.nx" 11 12func rt_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 13func rt_n(v: i64) -> i64 { let t: *u8=sys_mmap(24); var m: i64=v; if m<0{sys_write(1,"-" as *u8,1);m=0-m} 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} let b: *u8=sys_mmap(24); var j: i64=0; while j<k{b[j]=t[k-1-j];j=j+1} sys_write(1,b,k); return 0 } 14func rt_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 15func rt_box(t: *LayoutTree, i: i64) -> *LayoutBox { 16 return (t.boxes as *u8 + (i as nx_size) * (NX_LAYOUT_BOX_BYTES as nx_size)) as *LayoutBox 17} 18func rt_has(src: *u8, off: i64, len: i64, m: *u8) -> i64 { 19 let ml: i64 = rt_slen(m) 20 if ml == 0 { return 0 } 21 var i: i64 = 0 22 while i + ml <= len { 23 var k: i64 = 0 24 var ok: i64 = 1 25 while k < ml { if (src[off+i+k]&0xff) != (m[k]&0xff) { ok = 0; k = ml } else { k = k + 1 } } 26 if ok == 1 { return 1 } 27 i = i + 1 28 } 29 return 0 30} 31// does the laid-out page contain a TEXT box holding `marker`? 32func rt_renders(html: *u8, marker: *u8) -> i64 { 33 let page: *Page = sys_mmap(NX_PAGE_BYTES) as *Page 34 page.raw = html 35 page.raw_len = rt_slen(html) 36 page.dark_mode = 0 37 br_layout(page, 1024) 38 let t: *LayoutTree = page.tree 39 var i: i64 = 0 40 while i < t.count { 41 let b: *LayoutBox = rt_box(t, i) 42 if b.kind == NX_LAYOUT_BOX_TEXT { if b.text_len > 0 { 43 if rt_has(page.buf, b.text_off, b.text_len, marker) == 1 { return 1 } 44 } } 45 i = i + 1 46 } 47 return 0 48} 49func rt_case(html: *u8, marker: *u8, label: *u8) -> i64 { 50 rt_w(" " as *u8); rt_w(label); rt_w(": " as *u8) 51 if rt_renders(html, marker) == 1 { rt_w("PASS (post-script text renders)\n" as *u8); return 0 } 52 rt_w("FAIL (text suppressed -- script closer eaten)\n" as *u8) 53 return 1 54} 55 56func main() -> i64 { 57 rt_w("=== nx_rawtext_layout_gate -- bare < in script body must not blank the page (google-blank root) ===\n" as *u8) 58 var fails: i64 = 0 59 fails = fails + rt_case("<html><body><script>a<b</script><p>SEEONE</p></body></html>\x00" as *u8, "SEEONE\x00" as *u8, "T1 a<b in body script" as *u8) 60 fails = fails + rt_case("<html><head><script nonce=\"q\">if (x<y) z=1;</script></head><body><p>SEETWO</p></body></html>\x00" as *u8, "SEETWO\x00" as *u8, "T2 x<y in head script w/ nonce" as *u8) 61 fails = fails + rt_case("<html><body><style>a{width:1<2}</style><p>SEETHREE</p></body></html>\x00" as *u8, "SEETHREE\x00" as *u8, "T3 < in style body" as *u8) 62 fails = fails + rt_case("<html><body><script>var a=1;</script><p>SEEFOUR</p></body></html>\x00" as *u8, "SEEFOUR\x00" as *u8, "T4 CONTROL clean script (no regression)" as *u8) 63 fails = fails + rt_case("<html><body><p>SEEFIVE</p><script>x<y<z</script></body></html>\x00" as *u8, "SEEFIVE\x00" as *u8, "T5 text before a broken script" as *u8) 64 if fails == 0 { rt_w("NX-RAWTEXT-LAYOUT GREEN -- raw-text bodies consumed; a bare < cannot blank the page\n" as *u8); sys_exit(0); return 0 } 65 rt_w("NX-RAWTEXT-LAYOUT RED fails=" as *u8); rt_n(fails); rt_w("\n" as *u8) 66 sys_exit(1); return 1 67}