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&eacute;" 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&eacute;</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&eacute;"). 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}