code wiki / _hdl_build / nx_css_boxmodel_gate.nx
nx_css_boxmodel_gate.nx source
↩ module page · 143 lines · 7816 B
1// nx_css_boxmodel_gate.nx -- PROOF (re-runnable) of the S21 height-axis rung: `padding`/`margin`
2// SHORTHANDS and the `font` shorthand's font-size now shape layout. Real pages set the box model almost
3// entirely through shorthands, which the longhand-only lookups ignored -> we rendered ~40% denser than
4// Chrome. Every test runs the REAL br_layout on an inline fixture and asserts EXACT geometry:
5// T1 padding:8px 12px -> the padded block grows 16px taller AND its text indents 12px
6// T2 margin:10px 0 30px -> vertical rhythm between two paragraphs == 17+10+30 = 57px
7// T3 margin:2em 0 (fs 20) -> em resolves against the INHERITED font-size (40px)
8// T4 font:15px/1.55 ... -> BOTH resolvers (layout inherited + paint br_comp_fontsize_inh) read 15
9// T5 longhand priority -> padding:8px 12px + padding-top:1px -> top is 1 (longhand wins)
10// T6 CAN-FAIL control -> the same fixtures WITHOUT shorthands do NOT move (the deltas are real)
11// license_tier: ORIGINAL expect_exit: 0
12import "nx_syscalls.nx"
13import "nx_browser_render.nx"
14
15func bm_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
16func bm_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 }
17func bm_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
18func bm_box(t: *LayoutTree, i: i64) -> *LayoutBox {
19 return (t.boxes as *u8 + (i as nx_size) * (NX_LAYOUT_BOX_BYTES as nx_size)) as *LayoutBox
20}
21func bm_has(src: *u8, off: i64, len: i64, m: *u8) -> i64 {
22 let ml: i64 = bm_slen(m)
23 if ml == 0 { return 0 }
24 var i: i64 = 0
25 while i + ml <= len {
26 var k: i64 = 0
27 var ok: i64 = 1
28 while k < ml { if (src[off+i+k]&0xff) != (m[k]&0xff) { ok = 0; k = ml } else { k = k + 1 } }
29 if ok == 1 { return 1 }
30 i = i + 1
31 }
32 return 0
33}
34func bm_layout(html: *u8) -> *Page {
35 let page: *Page = sys_mmap(NX_PAGE_BYTES) as *Page
36 page.raw = html
37 page.raw_len = bm_slen(html)
38 page.dark_mode = 0
39 br_layout(page, 1024)
40 return page
41}
42// find the TEXT box containing marker; return it (0 if absent)
43func bm_find(page: *Page, marker: *u8) -> *LayoutBox {
44 let t: *LayoutTree = page.tree
45 var i: i64 = 0
46 while i < t.count {
47 let b: *LayoutBox = bm_box(t, i)
48 if b.text_len > 0 { if bm_has(page.buf, b.text_off, b.text_len, marker) == 1 { return b } }
49 i = i + 1
50 }
51 return 0 as *LayoutBox
52}
53// find the text box's PARENT block
54func bm_parent(page: *Page, marker: *u8) -> *LayoutBox {
55 let tb: *LayoutBox = bm_find(page, marker)
56 if (tb as i64) == 0 { return 0 as *LayoutBox }
57 if tb.parent_idx < 0 { return 0 as *LayoutBox }
58 return bm_box(page.tree, tb.parent_idx)
59}
60
61func main() -> i64 {
62 bm_w("=== nx_css_boxmodel_gate -- padding/margin/font SHORTHANDS shape layout (S21 height axis) ===\n" as *u8)
63 var fails: i64 = 0
64
65 // T1: padding shorthand -- div grows 2x8=16 taller than the control; text indents 12
66 let p1: *Page = bm_layout("<html><head><style>div{padding:8px 12px}</style></head><body><div>alphabeta</div></body></html>\x00" as *u8)
67 let c1: *Page = bm_layout("<html><body><div>alphabeta</div></body></html>\x00" as *u8)
68 let b1: *LayoutBox = bm_parent(p1, "alphabeta\x00" as *u8)
69 let k1: *LayoutBox = bm_parent(c1, "alphabeta\x00" as *u8)
70 let t1t: *LayoutBox = bm_find(p1, "alphabeta\x00" as *u8)
71 let k1t: *LayoutBox = bm_find(c1, "alphabeta\x00" as *u8)
72 bm_w(" T1 padding:8px 12px h=" as *u8)
73 var t1ok: i64 = 0
74 if (b1 as i64) != 0 { if (k1 as i64) != 0 {
75 bm_n(b1.h); bm_w(" (ctl " as *u8); bm_n(k1.h); bm_w(") text-x=" as *u8); bm_n(t1t.x); bm_w(" (ctl " as *u8); bm_n(k1t.x); bm_w(")" as *u8)
76 if b1.h == k1.h + 16 { if t1t.x == k1t.x + 12 { t1ok = 1 } }
77 } }
78 if t1ok == 1 { bm_w(" PASS\n" as *u8) } else { fails=fails+1; bm_w(" FAIL\n" as *u8) }
79
80 // T2: margin shorthand vertical rhythm: y(second) - y(first) == 17 + 10 + 30 = 57
81 let p2: *Page = bm_layout("<html><head><style>p{margin:10px 0 30px}</style></head><body><p>first</p><p>second</p></body></html>\x00" as *u8)
82 let a2: *LayoutBox = bm_find(p2, "first\x00" as *u8)
83 let b2: *LayoutBox = bm_find(p2, "second\x00" as *u8)
84 bm_w(" T2 margin:10px 0 30px dy=" as *u8)
85 var t2ok: i64 = 0
86 if (a2 as i64) != 0 { if (b2 as i64) != 0 {
87 bm_n(b2.y - a2.y); bm_w(" (want 57)" as *u8)
88 if b2.y - a2.y == 57 { t2ok = 1 }
89 } }
90 if t2ok == 1 { bm_w(" PASS\n" as *u8) } else { fails=fails+1; bm_w(" FAIL\n" as *u8) }
91
92 // T3: em margins resolve against the INHERITED font-size (body 20px -> 2em = 40)
93 let p3: *Page = bm_layout("<html><head><style>body{font-size:20px}p{margin:2em 0}</style></head><body><p>first</p><p>second</p></body></html>\x00" as *u8)
94 let a3: *LayoutBox = bm_find(p3, "first\x00" as *u8)
95 let b3: *LayoutBox = bm_find(p3, "second\x00" as *u8)
96 bm_w(" T3 margin:2em 0 @fs20 dy=" as *u8)
97 var t3ok: i64 = 0
98 if (a3 as i64) != 0 { if (b3 as i64) != 0 {
99 let want3: i64 = a3.h + 40 + 40
100 bm_n(b3.y - a3.y); bm_w(" (want " as *u8); bm_n(want3); bm_w(")" as *u8)
101 if b3.y - a3.y == want3 { t3ok = 1 }
102 } }
103 if t3ok == 1 { bm_w(" PASS\n" as *u8) } else { fails=fails+1; bm_w(" FAIL\n" as *u8) }
104
105 // T4: font shorthand -- the paint resolver reads 15 through the inherited walk
106 let p4: *Page = bm_layout("<html><head><style>body{font:15px/1.55 sans-serif}</style></head><body><p>alphabeta</p></body></html>\x00" as *u8)
107 let t4b: *LayoutBox = bm_find(p4, "alphabeta\x00" as *u8)
108 bm_w(" T4 font:15px/1.55 paint-fs=" as *u8)
109 var t4ok: i64 = 0
110 if (t4b as i64) != 0 {
111 let fs4: i64 = br_comp_fontsize_inh(p4.buf, p4.computed, p4.ncomp, p4.tree, t4b.parent_idx, 16)
112 bm_n(fs4); bm_w(" (want 15)" as *u8)
113 if fs4 == 15 { t4ok = 1 }
114 }
115 if t4ok == 1 { bm_w(" PASS\n" as *u8) } else { fails=fails+1; bm_w(" FAIL\n" as *u8) }
116
117 // T5: longhand wins over the shorthand for its side; other sides keep the shorthand
118 let p5: *Page = bm_layout("<html><head><style>div{padding:8px 12px;padding-top:1px}</style></head><body><div>alphabeta</div></body></html>\x00" as *u8)
119 let b5: *LayoutBox = bm_parent(p5, "alphabeta\x00" as *u8)
120 bm_w(" T5 shorthand+longhand-top h=" as *u8)
121 var t5ok: i64 = 0
122 if (b5 as i64) != 0 { if (k1 as i64) != 0 {
123 bm_n(b5.h); bm_w(" (want ctl+1+8=" as *u8); bm_n(k1.h + 9); bm_w(")" as *u8)
124 if b5.h == k1.h + 9 { t5ok = 1 }
125 } }
126 if t5ok == 1 { bm_w(" PASS\n" as *u8) } else { fails=fails+1; bm_w(" FAIL\n" as *u8) }
127
128 // T6 CAN-FAIL control: no-shorthand rhythm is the bare line height (the T2 delta is load-bearing)
129 let p6: *Page = bm_layout("<html><body><p>first</p><p>second</p></body></html>\x00" as *u8)
130 let a6: *LayoutBox = bm_find(p6, "first\x00" as *u8)
131 let b6: *LayoutBox = bm_find(p6, "second\x00" as *u8)
132 bm_w(" T6 control (no shorthand) dy=" as *u8)
133 var t6ok: i64 = 0
134 if (a6 as i64) != 0 { if (b6 as i64) != 0 {
135 bm_n(b6.y - a6.y)
136 if b6.y - a6.y < 57 { t6ok = 1 }
137 } }
138 if t6ok == 1 { bm_w(" PASS (differs from T2 -> the shorthand moved real geometry)\n" as *u8) } else { fails=fails+1; bm_w(" FAIL (vacuous)\n" as *u8) }
139
140 if fails == 0 { bm_w("NX-CSS-BOXMODEL GREEN -- shorthands shape layout; longhand priority + em inheritance + paint parity hold\n" as *u8); sys_exit(0); return 0 }
141 bm_w("NX-CSS-BOXMODEL RED fails=" as *u8); bm_n(fails); bm_w("\n" as *u8)
142 sys_exit(1); return 1
143}