code wiki / _hdl_build / nx_lineheight_gate.nx
nx_lineheight_gate.nx source
↩ module page · 109 lines · 5929 B
1// nx_lineheight_gate.nx -- PROOF (re-runnable) of CSS line-height (the S21 height-axis remainder):
2// unitless multiplier, px form, the `font` shorthand's /N part, inheritance-with-recompute, and
3// layout==paint resolver parity -- all through the REAL br_layout on inline fixtures.
4// T1 line-height:2 @fs16 -> single-line text box h == 32 (control: 17)
5// T2 font:15px/1.55 ... -> text box h == 23 (15*1550/1000, integer)
6// T3 line-height:30px -> h == 30 (fixed px, fs-independent)
7// T4 inherit+recompute -> body{line-height:1.5} p{font-size:20px} -> p line h == 30 (1.5x20, NOT 24)
8// T5 paint parity -> br_comp_lineheight_px == the layout-observed height on T2's page
9// T6 CAN-FAIL control -> no decl -> h == 17 (legacy exact; T1's delta is load-bearing)
10// license_tier: ORIGINAL expect_exit: 0
11import "nx_syscalls.nx"
12import "nx_browser_render.nx"
13
14func lg_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
15func lg_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 }
16func lg_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
17func lg_box(t: *LayoutTree, i: i64) -> *LayoutBox {
18 return (t.boxes as *u8 + (i as nx_size) * (NX_LAYOUT_BOX_BYTES as nx_size)) as *LayoutBox
19}
20func lg_has(src: *u8, off: i64, len: i64, m: *u8) -> i64 {
21 let ml: i64 = lg_slen(m)
22 if ml == 0 { return 0 }
23 var i: i64 = 0
24 while i + ml <= len {
25 var k: i64 = 0
26 var ok: i64 = 1
27 while k < ml { if (src[off+i+k]&0xff) != (m[k]&0xff) { ok = 0; k = ml } else { k = k + 1 } }
28 if ok == 1 { return 1 }
29 i = i + 1
30 }
31 return 0
32}
33func lg_layout(html: *u8) -> *Page {
34 let page: *Page = sys_mmap(NX_PAGE_BYTES) as *Page
35 page.raw = html
36 page.raw_len = lg_slen(html)
37 page.dark_mode = 0
38 br_layout(page, 1024)
39 return page
40}
41func lg_find(page: *Page, marker: *u8) -> *LayoutBox {
42 let t: *LayoutTree = page.tree
43 var i: i64 = 0
44 while i < t.count {
45 let b: *LayoutBox = lg_box(t, i)
46 if b.text_len > 0 { if lg_has(page.buf, b.text_off, b.text_len, marker) == 1 { return b } }
47 i = i + 1
48 }
49 return 0 as *LayoutBox
50}
51
52func main() -> i64 {
53 lg_w("=== nx_lineheight_gate -- CSS line-height shapes layout AND paint identically (S21 height axis) ===\n" as *u8)
54 var fails: i64 = 0
55
56 // T1: unitless multiplier vs control
57 let p1: *Page = lg_layout("<html><head><style>body{line-height:2}</style></head><body><p>alphabeta</p></body></html>\x00" as *u8)
58 let b1: *LayoutBox = lg_find(p1, "alphabeta\x00" as *u8)
59 lg_w(" T1 line-height:2 @fs16 h=" as *u8)
60 var t1: i64 = 0
61 if (b1 as i64) != 0 { lg_n(b1.h); lg_w(" (want 32)" as *u8); if b1.h == 32 { t1 = 1 } }
62 if t1 == 1 { lg_w(" PASS\n" as *u8) } else { fails=fails+1; lg_w(" FAIL\n" as *u8) }
63
64 // T2: the font shorthand's /N
65 let p2: *Page = lg_layout("<html><head><style>body{font:15px/1.55 sans-serif}</style></head><body><p>alphabeta</p></body></html>\x00" as *u8)
66 let b2: *LayoutBox = lg_find(p2, "alphabeta\x00" as *u8)
67 lg_w(" T2 font:15px/1.55 h=" as *u8)
68 var t2: i64 = 0
69 if (b2 as i64) != 0 { lg_n(b2.h); lg_w(" (want 23)" as *u8); if b2.h == 23 { t2 = 1 } }
70 if t2 == 1 { lg_w(" PASS\n" as *u8) } else { fails=fails+1; lg_w(" FAIL\n" as *u8) }
71
72 // T3: fixed px form
73 let p3: *Page = lg_layout("<html><head><style>p{line-height:30px}</style></head><body><p>alphabeta</p></body></html>\x00" as *u8)
74 let b3: *LayoutBox = lg_find(p3, "alphabeta\x00" as *u8)
75 lg_w(" T3 line-height:30px h=" as *u8)
76 var t3: i64 = 0
77 if (b3 as i64) != 0 { lg_n(b3.h); lg_w(" (want 30)" as *u8); if b3.h == 30 { t3 = 1 } }
78 if t3 == 1 { lg_w(" PASS\n" as *u8) } else { fails=fails+1; lg_w(" FAIL\n" as *u8) }
79
80 // T4: unitless INHERITS AS THE NUMBER -> recomputes against the descendant's own font-size
81 let p4: *Page = lg_layout("<html><head><style>body{line-height:1.5}p{font-size:20px}</style></head><body><p>alphabeta</p></body></html>\x00" as *u8)
82 let b4: *LayoutBox = lg_find(p4, "alphabeta\x00" as *u8)
83 lg_w(" T4 body lh:1.5 + p fs:20 h=" as *u8)
84 var t4: i64 = 0
85 if (b4 as i64) != 0 { lg_n(b4.h); lg_w(" (want 30 = 1.5x20, NOT 1.5x16=24)" as *u8); if b4.h == 30 { t4 = 1 } }
86 if t4 == 1 { lg_w(" PASS\n" as *u8) } else { fails=fails+1; lg_w(" FAIL\n" as *u8) }
87
88 // T5: the PAINT resolver returns the same value layout used (measure==paint)
89 lg_w(" T5 paint resolver on T2 page lh=" as *u8)
90 var t5: i64 = 0
91 if (b2 as i64) != 0 {
92 let plh: i64 = br_comp_lineheight_px(p2.buf, p2.computed, p2.ncomp, p2.tree, b2.parent_idx, 15)
93 lg_n(plh); lg_w(" (want 23)" as *u8)
94 if plh == 23 { t5 = 1 }
95 }
96 if t5 == 1 { lg_w(" PASS\n" as *u8) } else { fails=fails+1; lg_w(" FAIL\n" as *u8) }
97
98 // T6 CAN-FAIL control: no declaration anywhere -> the legacy 17px line box, exactly
99 let p6: *Page = lg_layout("<html><body><p>alphabeta</p></body></html>\x00" as *u8)
100 let b6: *LayoutBox = lg_find(p6, "alphabeta\x00" as *u8)
101 lg_w(" T6 control (no decl) h=" as *u8)
102 var t6: i64 = 0
103 if (b6 as i64) != 0 { lg_n(b6.h); lg_w(" (want 17)" as *u8); if b6.h == 17 { t6 = 1 } }
104 if t6 == 1 { lg_w(" PASS (legacy exact -> T1/T2 deltas are load-bearing)\n" as *u8) } else { fails=fails+1; lg_w(" FAIL\n" as *u8) }
105
106 if fails == 0 { lg_w("NX-LINEHEIGHT GREEN -- unitless/px/font-shorthand line-height, inherited-with-recompute, layout==paint\n" as *u8); sys_exit(0); return 0 }
107 lg_w("NX-LINEHEIGHT RED fails=" as *u8); lg_n(fails); lg_w("\n" as *u8)
108 sys_exit(1); return 1
109}