code wiki / (root) / nx_pagerender_lib.nx

nx_pagerender_lib.nx source

↩ module page · 174 lines · 7033 B

1// nx_pagerender_lib.nx -- RENDER ONE PUBLISHED PAGE THROUGH THE SOVEREIGN PAINT SUBSTRATE, as a LIB. 2// 3// WHY A LIB. The render proof lived inside nx_browser_render_own_test, which has a main() and therefore 4// cannot be imported. A sweep over every published board would have had to FORK that binary per page -- 5// a boundary the mutation harness is blind across, and a second copy of the assertions waiting to drift 6// from the first. One ruler, two callers: the single-page CLI and the whole-fleet sweep now prove the 7// SAME code, so they cannot disagree about what "rendered" means. 8// 9// WHAT IT ACTUALLY PROVES, stated so it is not mistaken for more: HTML on disk -> nx_html_to_text -> 10// the 5x7 bitmap font -> an RGBA framebuffer, asserted NON-BLANK, with the ASCII raster written out as 11// VISIBLE evidence rather than a boolean. It does NOT run the full CSS-cascade box layout; that is a 12// different rung and claiming it here would be the overclaim this substrate exists to avoid. 13// license_tier: ORIGINAL 14import "nx_syscalls.nx" 15import "nx_html_to_text.nx" 16import "nx_css_color_decode.nx" 17import "nx_paint_solid_rect.nx" 18import "nx_paint_text.nx" 19import "nx_paint_fb_ascii_dump.nx" 20import "nx_gate_verdict.nx" 21 22// outcome codes -- the ORIGINAL numbers from nx_browser_render_own_test, unchanged so nothing keying 23// on them breaks (rule 19: add, never renumber). 24const PR_OK: i64 = 0 25const PR_SKIP_ABSENT: i64 = 10 26const PR_SKIP_TINY: i64 = 11 27const PR_FAIL_TEXT: i64 = 20 28const PR_FAIL_MARKER: i64 = 21 29const PR_FAIL_LINE: i64 = 30 30const PR_FAIL_BLANK: i64 = 40 31const PR_FAIL_DUMP: i64 = 41 32 33// the fixture floor and the paint geometry, named rather than inline. 34const PR_MIN_HTML: i64 = 64 // below this a "page" is an error stub, not a document 35const PR_MIN_TEXT: i64 = 16 36const PR_MIN_LINE: i64 = 4 37const PR_MIN_LIT: i64 = 16 // a real glyph row lights dozens; 16 is the floor for NON-BLANK 38const PR_FB_W: i64 = 480 // 80 cols x 6px 39const PR_FB_H: i64 = 128 // 16 rows x 8px 40const PR_LINE_MAX: i64 = 76 // chars of the first non-empty line that fit the framebuffer 41const PR_RGBA: i64 = 4 42const PR_LIT_THRESHOLD: i64 = 128 // a subpixel counts as lit above half range 43const PR_NL: i64 = 10 44const PR_SPACE: i64 = 32 45 46// stats slots -- an i64 array so a caller reports NUMBERS, never just a verdict. 47const PR_ST_SLOTS: i64 = 8 48const PR_ST_HTML: i64 = 0 49const PR_ST_TEXT: i64 = 1 50const PR_ST_PAINTED: i64 = 2 51const PR_ST_LIT: i64 = 3 52const PR_ST_TOTALPX: i64 = 4 53const PR_ST_RASTER: i64 = 5 54const PR_ST_MARKED: i64 = 6 // 1 = the marker was CHECKED, 0 = deliberately skipped 55const PR_WORD: i64 = 8 56 57func pr_stats() -> *i64 { 58 let s: *i64 = sys_mmap(PR_ST_SLOTS * PR_WORD) as *i64 59 var i: i64 = 0 60 while i < PR_ST_SLOTS { s[i] = 0; i = i + 1 } 61 return s 62} 63 64func pr_contains(hay: *u8, hay_len: i64, needle: *u8) -> i64 { 65 var nlen: i64 = 0 66 while needle[nlen] != (0 as u8) { nlen = nlen + 1 } 67 if nlen == 0 { return 1 } 68 var i: i64 = 0 69 while i + nlen <= hay_len { 70 var j: i64 = 0 71 var ok: i64 = 1 72 while j < nlen { 73 if hay[i + j] != needle[j] { ok = 0; j = nlen } 74 j = j + 1 75 } 76 if ok == 1 { return 1 } 77 i = i + 1 78 } 79 return 0 80} 81 82// a marker of "-" means DELIBERATELY NOT CHECKED, and that choice is recorded in stats so a skipped 83// check is VISIBLE in the caller's output. A silently-skipped assertion is how a suite reports 84// coverage it does not have. 85func pr_marker_is_skip(m: *u8) -> i64 { 86 if m[0] != (45 as u8) { return 0 } 87 if m[1] != (0 as u8) { return 0 } 88 return 1 89} 90 91// THE RENDER. html_path -> text -> painted framebuffer -> ascii raster at out_path. 92// out_path of "-" writes no raster (the sweep does not want 84 files); the render still runs in full. 93func pr_render(html_path: *u8, marker: *u8, out_path: *u8, st: *i64) -> i64 { 94 let lenp: *i64 = sys_mmap(16) as *i64 95 let html: *u8 = sys_read_file(html_path, lenp) 96 if (html as i64) == 0 { return PR_SKIP_ABSENT } 97 let html_len: i64 = lenp[0] 98 st[PR_ST_HTML] = html_len 99 if html_len < PR_MIN_HTML { return PR_SKIP_TINY } 100 101 // NO GUESSED CAP: extracted text can never exceed the markup it came from, so the buffer is 102 // DERIVED from html_len and truncation is impossible by construction. A fixed 65536 here silently 103 // dropped 7,008 bytes of a 153,102-byte page on 2026-08-26 and nothing announced it. 104 let text_cap: i64 = html_len + 1 105 let text: *u8 = sys_mmap(text_cap) 106 let text_len: i64 = nx_html_to_text(html, html_len, text, text_cap) 107 st[PR_ST_TEXT] = text_len 108 if text_len < PR_MIN_TEXT { return PR_FAIL_TEXT } 109 110 if pr_marker_is_skip(marker) == 1 { st[PR_ST_MARKED] = 0 } 111 else { 112 st[PR_ST_MARKED] = 1 113 if pr_contains(text, text_len, marker) != 1 { return PR_FAIL_MARKER } 114 } 115 116 let fb_raw: *u8 = sys_mmap(NX_FRAMEBUFFER_BYTES) 117 let fb: *Framebuffer = fb_raw as *Framebuffer 118 let pixels: *u8 = sys_mmap(PR_FB_W * PR_FB_H * PR_RGBA) 119 nx_framebuffer_init(fb, pixels, PR_FB_W, PR_FB_H) 120 nx_framebuffer_clear(fb) 121 122 let line: *u8 = sys_mmap(PR_LINE_MAX + 8) 123 var li: i64 = 0 124 var ti: i64 = 0 125 while ti < text_len { 126 let c: i64 = text[ti] & 0xff 127 if c == PR_NL { if li > 0 { ti = text_len } } 128 if ti < text_len { 129 if c >= PR_SPACE { if li < PR_LINE_MAX { line[li] = c as u8; li = li + 1 } } 130 ti = ti + 1 131 } 132 } 133 st[PR_ST_PAINTED] = li 134 if li < PR_MIN_LINE { return PR_FAIL_LINE } 135 line[li] = 0 as u8 136 137 let white: *CssColor = (sys_mmap(NX_CSS_COLOR_BYTES)) as *CssColor 138 white.r = 255; white.g = 255; white.b = 255; white.a = 255 139 nx_paint_text(fb, 4, 4, line, li, white) 140 141 var lit: i64 = 0 142 var pi: i64 = 0 143 let total_px: i64 = PR_FB_W * PR_FB_H 144 while pi < total_px { 145 if (pixels[pi * PR_RGBA] & 0xff) > PR_LIT_THRESHOLD { lit = lit + 1 } 146 pi = pi + 1 147 } 148 st[PR_ST_LIT] = lit 149 st[PR_ST_TOTALPX] = total_px 150 if lit < PR_MIN_LIT { return PR_FAIL_BLANK } 151 152 let dump_cap: i64 = (PR_FB_W + 1) * PR_FB_H 153 let dump: *u8 = sys_mmap(dump_cap) 154 let dn: i64 = nx_paint_fb_ascii_dump(fb, dump, dump_cap) 155 st[PR_ST_RASTER] = dn 156 if dn <= 0 { return PR_FAIL_DUMP } 157 if pr_marker_is_skip(out_path) == 0 { 158 let ofd: i64 = sys_openat_wr(out_path, GV_MODE_644) 159 if ofd > 0 { sys_write(ofd, dump, dn); sys_close(ofd) } 160 } 161 return PR_OK 162} 163 164func pr_code_name(c: i64) -> *u8 { 165 if c == PR_OK { return "PASS" as *u8 } 166 if c == PR_SKIP_ABSENT { return "SKIP-absent" as *u8 } 167 if c == PR_SKIP_TINY { return "SKIP-tiny" as *u8 } 168 if c == PR_FAIL_TEXT { return "FAIL-no-text" as *u8 } 169 if c == PR_FAIL_MARKER { return "FAIL-marker" as *u8 } 170 if c == PR_FAIL_LINE { return "FAIL-short-line" as *u8 } 171 if c == PR_FAIL_BLANK { return "FAIL-blank-framebuffer" as *u8 } 172 if c == PR_FAIL_DUMP { return "FAIL-no-raster" as *u8 } 173 return "UNKNOWN" as *u8 174}