code wiki / _hdl_build / nx_inline_vec_measure_gate.nx
nx_inline_vec_measure_gate.nx source
↩ module page · 372 lines · 23167 B
1// nx_inline_vec_measure_gate.nx -- PROOF (re-runnable) of the S21 F3 root fix: when the renderer paints
2// with the proportional VECTOR font, layout must reserve the SAME widths (font_adv_em sums), not the wider
3// bitmap widths -- the drift put visible gaps around every styled inline span/link (Wikipedia links, the
4// /experiential intro labels). T1/T2 prove exactness in both modes; T3 proves inline CONTIGUITY (the next
5// run starts where the previous ended -- the gap is structurally gone); T4 is the can-fail control (vec
6// widths genuinely differ from bitmap for this text, so T1 isn't vacuous). license_tier: ORIGINAL
7// expect_exit: 0
8import "nx_syscalls.nx"
9import "nx_browser_render.nx"
10import "nx_gate_verdict.nx" // D001: inherit the ONE judge so the EXIT CODE carries the verdict
11
12func gv_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 gv_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 gv_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
15
16func gv_box(t: *LayoutTree, i: i64) -> *LayoutBox {
17 return (t.boxes as *u8 + (i as nx_size) * (NX_LAYOUT_BOX_BYTES as nx_size)) as *LayoutBox
18}
19func gv_has(src: *u8, off: i64, len: i64, m: *u8) -> i64 {
20 let ml: i64 = gv_slen(m)
21 if ml == 0 { return 0 }
22 var i: i64 = 0
23 while i + ml <= len {
24 var k: i64 = 0
25 var ok: i64 = 1
26 while k < ml { if (src[off+i+k]&0xff) != (m[k]&0xff) { ok = 0; k = ml } else { k = k + 1 } }
27 if ok == 1 { return 1 }
28 i = i + 1
29 }
30 return 0
31}
32// layout the fixture; find the text box containing `marker`; return ptr (0 if absent)
33func gv_find(page: *Page, marker: *u8) -> *LayoutBox {
34 let t: *LayoutTree = page.tree
35 var i: i64 = 0
36 while i < t.count {
37 let b: *LayoutBox = gv_box(t, i)
38 if b.text_len > 0 { if gv_has(page.buf, b.text_off, b.text_len, marker) == 1 { return b } }
39 i = i + 1
40 }
41 return 0 as *LayoutBox
42}
43func gv_layout(html: *u8, vec: i64) -> *Page {
44 let page: *Page = sys_mmap(NX_PAGE_BYTES) as *Page
45 page.raw = html
46 page.raw_len = gv_slen(html)
47 page.dark_mode = 0
48 nx_layout_set_vec_measure(vec)
49 br_layout(page, 1024)
50 return page
51}
52
53func main() -> i64 {
54 gv_w("=== nx_inline_vec_measure_gate -- layout reserves what the vector paint draws (S21 F3) ===\n" as *u8)
55 // D001 MIGRATION (2026-08-25): teeth lifted to gv_check so declared == executed BY CONSTRUCTION
56 // and the exit code carries the verdict. This gate rolled its own `fails` counter and sys_exit, so
57 // /api/gate_run could not read its outcome and it recorded no harness.jrnl frame -- flake and
58 // erosion were invisible for it. nx_gate_dry_apply correctly REFUSED an automatic map (this is the
59 // fails==0 family; a direct operand map would have INVERTED it GREEN->RED), so the teeth are lifted
60 // BY HAND, one gv_check each, with the measured values still printed before every verdict.
61 let ctr: *i64 = sys_mmap(16) as *i64
62 ctr[0] = 0
63 ctr[1] = 0
64 // one line, three runs: "alpha " <b>beta</b> " gamma" -- the <b> span is the styled inline
65 let html: *u8 = "<html><body><p>alpha <b>beta</b> gamma</p></body></html>\x00" as *u8
66
67 // T1: vec mode -- the "beta" box width == the exact font_adv_em sum at the inherited fs (16)
68 let pv: *Page = gv_layout(html, 1)
69 let bv: *LayoutBox = gv_find(pv, "beta\x00" as *u8)
70 var want: i64 = 0
71 let bs: *u8 = "beta\x00" as *u8
72 var i: i64 = 0
73 while bs[i] != (0 as u8) { want = want + (font_adv_em((bs[i] as i64) & 255) * 16) / 1000; i = i + 1 }
74 gv_w(" T1 vec-measure beta w=" as *u8)
75 if (bv as i64) != 0 { gv_n(bv.w) } else { gv_w("(missing)" as *u8) }
76 gv_w(" want=" as *u8); gv_n(want)
77 var t1: i64 = 0
78 if (bv as i64) != 0 { if bv.w == want { t1 = 1 } }
79 gv_check("T1-vec-measure-is-the-exact-font_adv_em-sum" as *u8, t1, ctr)
80
81 // T2: bitmap mode (default OFF) -- width == font8x8 measured width x scale (byte-unchanged legacy)
82 let pb: *Page = gv_layout(html, 0)
83 let bb: *LayoutBox = gv_find(pb, "beta\x00" as *u8)
84 let ftab: *u8 = font8x8_table()
85 let wantb: i64 = font8x8_text_w(ftab, bs, 0, 4) * 1
86 gv_w(" T2 bitmap-measure beta w=" as *u8)
87 if (bb as i64) != 0 { gv_n(bb.w) } else { gv_w("(missing)" as *u8) }
88 gv_w(" want=" as *u8); gv_n(wantb)
89 var t2: i64 = 0
90 if (bb as i64) != 0 { if bb.w == wantb { t2 = 1 } }
91 gv_check("T2-neg-control-explicit-bitmap-choice-BEATS-br_layout-default" as *u8, t2, ctr)
92
93 // T3: CONTIGUITY in vec mode -- " gamma" starts exactly at beta.x + beta.w (no phantom gap)
94 let gv2: *LayoutBox = gv_find(pv, "gamma\x00" as *u8)
95 gv_w(" T3 contiguity: beta.x+w=" as *u8)
96 var t3: i64 = 0
97 if (bv as i64) != 0 { if (gv2 as i64) != 0 {
98 gv_n(bv.x + bv.w); gv_w(" gamma.x=" as *u8); gv_n(gv2.x)
99 if gv2.x == bv.x + bv.w { t3 = 1 }
100 } }
101 gv_check("T3-inline-contiguity-next-run-starts-where-last-ended" as *u8, t3, ctr)
102
103 // T4 CAN-FAIL control: vec and bitmap widths genuinely DIFFER for this run (else T1 proves nothing)
104 gv_w(" T4 modes differ: vec=" as *u8); gv_n(want); gv_w(" bitmap=" as *u8); gv_n(wantb)
105 var t4: i64 = 0
106 if want != wantb { t4 = 1 }
107 gv_check("T4-neg-control-vec-and-bitmap-widths-genuinely-differ" as *u8, t4, ctr)
108
109 // T5 (2026-08-25) FOLD-BEFORE-LAYOUT: an entity-bearing run must be measured at its DECODED
110 // length, not its raw one. "café" is 11 raw bytes and 4 decoded; before the fold pass
111 // layout measured 11 and paint drew 4. The box must now be found by its FOLDED text and its
112 // width must equal the vector sum over "cafe" -- i.e. measure and paint agree on what the
113 // text IS, which is the precondition for agreeing on how wide it is.
114 let ehtml: *u8 = "<html><body><p>café</p></body></html>\x00" as *u8
115 let pe: *Page = gv_layout(ehtml, 1)
116 let be: *LayoutBox = gv_find(pe, "cafe\x00" as *u8)
117 var wante: i64 = 0
118 let es: *u8 = "cafe\x00" as *u8
119 var ei: i64 = 0
120 while es[ei] != (0 as u8) { wante = wante + (font_adv_em((es[ei] as i64) & 255) * 16) / 1000; ei = ei + 1 }
121 gv_w(" T5 folded-entity run w=" as *u8)
122 if (be as i64) != 0 { gv_n(be.w) } else { gv_w("(missing: still raw)" as *u8) }
123 gv_w(" want=" as *u8); gv_n(wante)
124 var t5: i64 = 0
125 if (be as i64) != 0 { if be.w == wante { t5 = 1 } }
126 gv_check("T5-layout-measured-the-DECODED-text-paint-draws" as *u8, t5, ctr)
127
128 // T6 CAN-FAIL control for T5. An earlier draft compared two LITERALS (11 != 4), which can never
129 // fail -- a vacuous tooth inside a gate whose whole purpose is catching vacuity. This reads
130 // MEASURED state instead: after fold-before-layout the box text_len must be the DECODED length
131 // (4 = "cafe"), not the raw one (11 = "café"). If the fold pass ever stops running this
132 // tooth goes RED on its own, which is what a control is for.
133 gv_w(" T6 measured text_len=" as *u8)
134 var t6: i64 = 0
135 if (be as i64) != 0 {
136 gv_n(be.text_len); gv_w(" want=4 (raw would be 11)" as *u8)
137 if be.text_len == 4 { t6 = 1 }
138 } else { gv_w("(box missing)" as *u8) }
139 gv_check("T6-neg-control-fold-pass-really-ran-text_len-is-decoded" as *u8, t6, ctr)
140
141 // T7/T8 (2026-09-02, BR4 first half): a REAL FACE's advances flow through the ONE ruler. A synthetic
142 // 1000-em table (no font file needed, so this proves the HOOK on any host) is set via font_set_face;
143 // layout must then reserve exactly the table's widths PLUS the pair kern, and clearing the face must
144 // restore the stroke widths -- so the tooth can fail in both directions.
145 let fadv: *i64 = sys_mmap(8*FS_FACE_CPS) as *i64 // BR30: advance tables are indexed by CODEPOINT
146 let fkern: *i64 = sys_mmap(8*256*256) as *i64
147 var fi: i64 = 0
148 while fi < FS_FACE_CPS { fadv[fi] = 0; fi = fi + 1 }
149 fi = 0
150 while fi < 256*256 { fkern[fi] = 0; fi = fi + 1 }
151 fadv[98] = 600; fadv[101] = 500; fadv[116] = 300; fadv[97] = 550 // b e t a (1000-em)
152 fkern[98*256 + 101] = 0 - 100 // the 'be' pair pulls 100/1000 em closer
153 font_set_face(fadv, fkern)
154 let pf: *Page = gv_layout(html, 1)
155 let bf: *LayoutBox = gv_find(pf, "beta\x00" as *u8)
156 let wantf: i64 = (600*16)/1000 + (500*16)/1000 + (300*16)/1000 + (550*16)/1000 + ((0 - 100)*16)/1000
157 gv_w(" T7 face-measure beta w=" as *u8)
158 if (bf as i64) != 0 { gv_n(bf.w) } else { gv_w("(missing)" as *u8) }
159 gv_w(" want=" as *u8); gv_n(wantf); gv_w(" (table advances + 'be' kern)" as *u8)
160 var t7: i64 = 0
161 if (bf as i64) != 0 { if bf.w == wantf { t7 = 1 } }
162 gv_check("T7-layout-reserves-the-REAL-FACE-advances-plus-pair-kern-through-font_adv_em" as *u8, t7, ctr)
163 // T9/T10 (BR27): a run inside <b> resolves to the BOLD face slot through the ONE resolver
164 // (nx_layout_face_for_box, font-weight:bold from the UA sheet) and layout reserves the bold table's
165 // widths; with no bold face registered the run falls back to slot 0 (never to the stroke font).
166 let badv: *i64 = sys_mmap(8*FS_FACE_CPS) as *i64
167 let bkern: *i64 = sys_mmap(8*256*256) as *i64
168 var bi: i64 = 0
169 while bi < FS_FACE_CPS { badv[bi] = 0; bi = bi + 1 }
170 bi = 0
171 while bi < 256*256 { bkern[bi] = 0; bi = bi + 1 }
172 badv[98] = 700; badv[101] = 600; badv[116] = 400; badv[97] = 650 // the BOLD face is wider than the regular table above
173 font_face_register(1, badv, bkern)
174 let pbold: *Page = gv_layout(html, 1)
175 let bbold: *LayoutBox = gv_find(pbold, "beta\x00" as *u8)
176 let wantbold: i64 = (700*16)/1000 + (600*16)/1000 + (400*16)/1000 + (650*16)/1000
177 gv_w(" T9 <b>beta</b> with a bold face registered w=" as *u8)
178 if (bbold as i64) != 0 { gv_n(bbold.w) } else { gv_w("(missing)" as *u8) }
179 gv_w(" want=" as *u8); gv_n(wantbold); gv_w(" (bold table; regular would be " as *u8); gv_n(wantf); gv_w(")" as *u8)
180 var t9: i64 = 0
181 if (bbold as i64) != 0 { if bbold.w == wantbold { t9 = 1 } }
182 gv_check("T9-a-run-inside-b-is-measured-with-the-BOLD-face-slot-via-the-ONE-resolver" as *u8, t9, ctr)
183 // the resolver itself, asked directly for the beta box, must say slot 1 (bold, upright, sans)
184 var t9b: i64 = 0
185 if (bbold as i64) != 0 {
186 let tb: *LayoutTree = pbold.tree
187 var bidx: i64 = 0 - 1
188 var q: i64 = 0
189 while q < tb.count { if (gv_box(tb, q) as i64) == (bbold as i64) { bidx = q; q = tb.count } q = q + 1 }
190 if bidx >= 0 {
191 let par: i64 = bbold.parent_idx
192 let slot: i64 = nx_layout_face_for_box(pbold.buf, pbold.computed, pbold.ncomp, tb, par)
193 gv_w(" T9b resolver slot for the <b> parent=" as *u8); gv_n(slot); gv_w(" (want 1 = bold)" as *u8)
194 if slot == 1 { t9b = 1 }
195 }
196 }
197 gv_check("T9b-the-resolver-names-slot-1-bold-for-the-b-element" as *u8, t9b, ctr)
198 // T11-T13 (2026-09-02, seen on the wikipedia render: the author rule returning headings to normal
199 // weight was not honoured). Author CSS must beat the UA sheet's b{font-weight:bold}: T11 a single
200 // selector (control: proves the author path works at all), T12 a COMMA-SEPARATED selector list,
201 // T13 a class-descendant selector -- each measured through the real layout with the bold slot live.
202 let h11: *u8 = "<html><head><style>b { font-weight: normal }</style></head><body><p>alpha <b>beta</b> gamma</p></body></html>\x00" as *u8
203 let p11: *Page = gv_layout(h11, 1)
204 let b11: *LayoutBox = gv_find(p11, "beta\x00" as *u8)
205 gv_w(" T11 author b{font-weight:normal} beats UA bold: w=" as *u8)
206 if (b11 as i64) != 0 { gv_n(b11.w) } else { gv_w("(missing)" as *u8) }
207 gv_w(" want=" as *u8); gv_n(wantf); gv_w(" (regular; bold would be " as *u8); gv_n(wantbold); gv_w(")" as *u8)
208 var t11: i64 = 0
209 if (b11 as i64) != 0 { if b11.w == wantf { t11 = 1 } }
210 gv_check("T11-control-author-font-weight-normal-beats-the-UA-bold-single-selector" as *u8, t11, ctr)
211 let h12: *u8 = "<html><head><style>i, b { font-weight: normal }</style></head><body><p>alpha <b>beta</b> gamma</p></body></html>\x00" as *u8
212 let p12: *Page = gv_layout(h12, 1)
213 let b12: *LayoutBox = gv_find(p12, "beta\x00" as *u8)
214 gv_w(" T12 comma-list selector 'i, b' applies to b: w=" as *u8)
215 if (b12 as i64) != 0 { gv_n(b12.w) } else { gv_w("(missing)" as *u8) }
216 gv_w(" want=" as *u8); gv_n(wantf)
217 var t12: i64 = 0
218 if (b12 as i64) != 0 { if b12.w == wantf { t12 = 1 } }
219 gv_check("T12-a-comma-separated-selector-list-applies-to-every-member" as *u8, t12, ctr)
220 let h13: *u8 = "<html><head><style>.x b { font-weight: normal }</style></head><body><div class=\"x\"><p>alpha <b>beta</b> gamma</p></div></body></html>\x00" as *u8
221 let p13: *Page = gv_layout(h13, 1)
222 let b13: *LayoutBox = gv_find(p13, "beta\x00" as *u8)
223 gv_w(" T13 class-descendant selector '.x b': w=" as *u8)
224 if (b13 as i64) != 0 { gv_n(b13.w) } else { gv_w("(missing)" as *u8) }
225 gv_w(" want=" as *u8); gv_n(wantf)
226 var t13: i64 = 0
227 if (b13 as i64) != 0 { if b13.w == wantf { t13 = 1 } }
228 gv_check("T13-a-class-descendant-selector-reaches-the-nested-b" as *u8, t13, ctr)
229 // T14/T15: the EXACT wikipedia shape that painted bold. Its stylesheet says
230 // .mw-heading,h1,h2{font-weight:bold} then .mw-heading1,h1{font-size:188%;font-weight:normal}
231 // -- class-first comma lists with NO space after the comma, the later rule winning on equal specificity.
232 let h14: *u8 = "<html><head><style>.zz,b{font-weight:normal}</style></head><body><p>alpha <b>beta</b> gamma</p></body></html>\x00" as *u8
233 let p14: *Page = gv_layout(h14, 1)
234 let b14: *LayoutBox = gv_find(p14, "beta\x00" as *u8)
235 gv_w(" T14 class-first no-space list '.zz,b': w=" as *u8)
236 if (b14 as i64) != 0 { gv_n(b14.w) } else { gv_w("(missing)" as *u8) }
237 gv_w(" want=" as *u8); gv_n(wantf)
238 var t14: i64 = 0
239 if (b14 as i64) != 0 { if b14.w == wantf { t14 = 1 } }
240 gv_check("T14-a-class-first-comma-list-without-spaces-applies-to-the-type-member" as *u8, t14, ctr)
241 let h15: *u8 = "<html><head><style>.mw-heading,b,i{font-weight:bold}.mw-heading1,b{font-weight:normal}</style></head><body><p>alpha <b>beta</b> gamma</p></body></html>\x00" as *u8
242 let p15: *Page = gv_layout(h15, 1)
243 let b15: *LayoutBox = gv_find(p15, "beta\x00" as *u8)
244 gv_w(" T15 wikipedia pair (bold list, then normal list, equal specificity, later wins): w=" as *u8)
245 if (b15 as i64) != 0 { gv_n(b15.w) } else { gv_w("(missing)" as *u8) }
246 gv_w(" want=" as *u8); gv_n(wantf)
247 var t15: i64 = 0
248 if (b15 as i64) != 0 { if b15.w == wantf { t15 = 1 } }
249 gv_check("T15-the-later-equal-specificity-list-rule-wins-the-exact-wikipedia-heading-pair" as *u8, t15, ctr)
250 // T16/T17 discriminate the T15 mechanism: does a class member of a comma list leak its specificity onto
251 // the type members of the same list? T16: type-only list first, class-first list later (both b = 0,0,1)
252 // -> later wins. T17: class-first list FIRST, then a bare b -> b must still win as the later equal rule.
253 let h16: *u8 = "<html><head><style>b,i{font-weight:bold}.zz,b{font-weight:normal}</style></head><body><p>alpha <b>beta</b> gamma</p></body></html>\x00" as *u8
254 let p16: *Page = gv_layout(h16, 1)
255 let b16: *LayoutBox = gv_find(p16, "beta\x00" as *u8)
256 gv_w(" T16 'b,i{bold}' then '.zz,b{normal}': w=" as *u8)
257 if (b16 as i64) != 0 { gv_n(b16.w) } else { gv_w("(missing)" as *u8) }
258 gv_w(" want=" as *u8); gv_n(wantf)
259 var t16: i64 = 0
260 if (b16 as i64) != 0 { if b16.w == wantf { t16 = 1 } }
261 gv_check("T16-type-list-then-class-first-list-the-later-b-member-wins" as *u8, t16, ctr)
262 let h17: *u8 = "<html><head><style>.zz,b{font-weight:bold}b{font-weight:normal}</style></head><body><p>alpha <b>beta</b> gamma</p></body></html>\x00" as *u8
263 let p17: *Page = gv_layout(h17, 1)
264 let b17: *LayoutBox = gv_find(p17, "beta\x00" as *u8)
265 gv_w(" T17 '.zz,b{bold}' then 'b{normal}': w=" as *u8)
266 if (b17 as i64) != 0 { gv_n(b17.w) } else { gv_w("(missing)" as *u8) }
267 gv_w(" want=" as *u8); gv_n(wantf)
268 var t17: i64 = 0
269 if (b17 as i64) != 0 { if b17.w == wantf { t17 = 1 } }
270 gv_check("T17-a-class-member-must-not-leak-its-specificity-onto-the-type-member-of-its-list" as *u8, t17, ctr)
271 // T10 neg-control: the same fixture with ONLY the regular face registered measures the regular table
272 font_set_face(0 as *i64, 0 as *i64)
273 font_set_face(fadv, fkern)
274 let preg: *Page = gv_layout(html, 1)
275 let breg: *LayoutBox = gv_find(preg, "beta\x00" as *u8)
276 gv_w(" T10 <b>beta</b> with no bold face registered w=" as *u8)
277 if (breg as i64) != 0 { gv_n(breg.w) } else { gv_w("(missing)" as *u8) }
278 gv_w(" want=" as *u8); gv_n(wantf); gv_w(" (falls back to slot 0)" as *u8)
279 var t10: i64 = 0
280 if (breg as i64) != 0 { if breg.w == wantf { if wantf != wantbold { t10 = 1 } } }
281 gv_check("T10-neg-control-no-bold-slot-falls-back-to-the-regular-face-not-the-stroke-font" as *u8, t10, ctr)
282 // T18/T19 (BR30, 2026-09-02): a face measures CODEPOINTS. 'caf' + U+00E9: with the face COVERING U+00E9
283 // the pre-pass keeps its UTF-8 bytes (text_len 5) and layout reserves the table advance for U+00E9;
284 // with U+00E9 UNCOVERED the pre-pass folds it to 'e' (text_len 4) and reserves e's advance instead --
285 // and the two widths differ, so the tooth can fail in both directions.
286 fadv[99] = 500; fadv[102] = 300; fadv[233] = 650 // c f e-acute (1000-em)
287 font_set_face(fadv, fkern)
288 // the fixture is CONSTRUCTED byte by byte: a high-byte escape inside a string literal is not a lexer
289 // contract (measured 2026-09-02: the escaped literal desynced the lexer and the errors surfaced in the
290 // auto-appended nx_crash.nx, i.e. the file AFTER the one that broke)
291 let html18: *u8 = sys_mmap(32)
292 let h18a: *u8 = "<p>caf" as *u8
293 var h18i: i64 = 0
294 while h18i < 6 { html18[h18i] = h18a[h18i]; h18i = h18i + 1 }
295 html18[6] = 195 as u8; html18[7] = 169 as u8 // U+00E9 as UTF-8
296 let h18b: *u8 = "</p>" as *u8
297 h18i = 0
298 while h18i < 4 { html18[8 + h18i] = h18b[h18i]; h18i = h18i + 1 }
299 html18[12] = 0 as u8
300 let p18: *Page = gv_layout(html18, 1)
301 let b18: *LayoutBox = gv_find(p18, "caf\x00" as *u8)
302 let want18: i64 = (500*16)/1000 + (550*16)/1000 + (300*16)/1000 + (650*16)/1000
303 gv_w(" T18 caf+U+00E9 (covered) w=" as *u8)
304 if (b18 as i64) != 0 { gv_n(b18.w); gv_w(" text_len=" as *u8); gv_n(b18.text_len) } else { gv_w("(missing)" as *u8) }
305 gv_w(" want=" as *u8); gv_n(want18); gv_w(" text_len want=5 (UTF-8 kept)" as *u8)
306 var t18: i64 = 0
307 if (b18 as i64) != 0 { if b18.w == want18 { if b18.text_len == 5 { t18 = 1 } } }
308 gv_check("T18-a-covered-non-ASCII-codepoint-keeps-its-UTF8-bytes-and-layout-reserves-the-face-advance" as *u8, t18, ctr)
309 fadv[233] = 0
310 font_set_face(fadv, fkern)
311 let p19: *Page = gv_layout(html18, 1)
312 let b19: *LayoutBox = gv_find(p19, "caf\x00" as *u8)
313 let want19: i64 = (500*16)/1000 + (550*16)/1000 + (300*16)/1000 + (500*16)/1000 // e-acute folded to e
314 gv_w(" T19 caf+U+00E9 (UNCOVERED) w=" as *u8)
315 if (b19 as i64) != 0 { gv_n(b19.w); gv_w(" text_len=" as *u8); gv_n(b19.text_len) } else { gv_w("(missing)" as *u8) }
316 gv_w(" want=" as *u8); gv_n(want19); gv_w(" text_len want=4 (folded to e)" as *u8)
317 var t19: i64 = 0
318 if (b19 as i64) != 0 { if b19.w == want19 { if b19.text_len == 4 { if want19 != want18 { t19 = 1 } } } }
319 gv_check("T19-neg-control-an-UNCOVERED-codepoint-folds-to-ASCII-before-layout-and-the-widths-differ" as *u8, t19, ctr)
320 // T20/T21 (BR39, 2026-09-02): a codepoint BEYOND the face table (U+65E5, CJK) is covered by the notdef
321 // box when slot 0 carries the notdef advance -- the run keeps its bytes (text_len 4) and reserves that
322 // advance; with slot 0 empty the pre-pass folds it away (text_len 1) and only the a remains.
323 fadv[0] = 500
324 font_set_face(fadv, fkern)
325 let html20: *u8 = sys_mmap(32)
326 let h20a: *u8 = "<p>a" as *u8
327 var h20i: i64 = 0
328 while h20i < 4 { html20[h20i] = h20a[h20i]; h20i = h20i + 1 }
329 html20[4] = 230 as u8; html20[5] = 151 as u8; html20[6] = 165 as u8 // U+65E5 as UTF-8
330 let h20b: *u8 = "</p>" as *u8
331 h20i = 0
332 while h20i < 4 { html20[7 + h20i] = h20b[h20i]; h20i = h20i + 1 }
333 html20[11] = 0 as u8
334 let p20: *Page = gv_layout(html20, 1)
335 let b20: *LayoutBox = gv_find(p20, "a\x00" as *u8)
336 let want20: i64 = (550*16)/1000 + (500*16)/1000
337 gv_w(" T20 a+U+65E5 (beyond the table, notdef adv 500) w=" as *u8)
338 if (b20 as i64) != 0 { gv_n(b20.w); gv_w(" text_len=" as *u8); gv_n(b20.text_len) } else { gv_w("(missing)" as *u8) }
339 gv_w(" want=" as *u8); gv_n(want20); gv_w(" text_len want=4 (bytes kept)" as *u8)
340 var t20: i64 = 0
341 if (b20 as i64) != 0 { if b20.w == want20 { if b20.text_len == 4 { t20 = 1 } } }
342 gv_check("T20-a-codepoint-beyond-the-face-table-keeps-its-bytes-and-reserves-the-notdef-advance" as *u8, t20, ctr)
343 fadv[0] = 0
344 font_set_face(fadv, fkern)
345 let p21: *Page = gv_layout(html20, 1)
346 let b21: *LayoutBox = gv_find(p21, "a\x00" as *u8)
347 let want21: i64 = (550*16)/1000
348 gv_w(" T21 same run with NO notdef advance w=" as *u8)
349 if (b21 as i64) != 0 { gv_n(b21.w); gv_w(" text_len=" as *u8); gv_n(b21.text_len) } else { gv_w("(missing)" as *u8) }
350 gv_w(" want=" as *u8); gv_n(want21); gv_w(" text_len want=1 (folded away)" as *u8)
351 var t21: i64 = 0
352 if (b21 as i64) != 0 { if b21.w == want21 { if b21.text_len == 1 { if want21 != want20 { t21 = 1 } } } }
353 gv_check("T21-neg-control-without-a-notdef-advance-the-beyond-table-codepoint-folds-away" as *u8, t21, ctr)
354 fadv[99] = 0; fadv[102] = 0 // restore the T7 table shape
355 font_set_face(0 as *i64, 0 as *i64)
356 let pg: *Page = gv_layout(html, 1)
357 let bg2: *LayoutBox = gv_find(pg, "beta\x00" as *u8)
358 gv_w(" T8 after clearing the face beta w=" as *u8)
359 if (bg2 as i64) != 0 { gv_n(bg2.w) } else { gv_w("(missing)" as *u8) }
360 gv_w(" stroke want=" as *u8); gv_n(want); gv_w(" face want=" as *u8); gv_n(wantf)
361 var t8: i64 = 0
362 if (bg2 as i64) != 0 { if bg2.w == want { if want != wantf { t8 = 1 } } }
363 gv_check("T8-neg-control-clearing-the-face-restores-stroke-widths-and-the-two-differ" as *u8, t8, ctr)
364
365 nx_layout_set_vec_measure(0)
366 nx_layout_clear_vec_measure_pin() // release the pin so a later default applies again
367 // NOTE deliberately does NOT recite the teeth or their counts -- each gv_check states itself, and
368 // a note that enumerates them silently lies the moment a tooth is added.
369 let rc: i64 = gv_verdict("INLINE-VEC-MEASURE" as *u8, ctr, "layout reserves and breaks on the same advances paint draws" as *u8)
370 sys_exit(rc)
371 return rc
372}