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}