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}