nx_doc_layout.nx source
↩ module page · 101 lines · 4568 B
1// nx_doc_layout.nx -- document layout: text -> 8-bit GRAYSCALE page bitmap (front half of "print real
2// documents"). Distinct from nx_text_render (that targets the OS 1bpp framebuffer). Blits scaled 8x8 glyphs
3// from nx_font8x8's font8x8_table() with margins, monospace advance, right-margin wrap, and newline.
4// Output flows into nx_urf -> Print-Job -> printer. PURE (writes a caller bitmap) -> never-brick. Sovereign.
5// genealogy_id: project-printer-management-ipp-sclass-2026-06-20 ; license_tier: ORIGINAL
6
7import "nx_font8x8.nx"
8
9// pointer to the 8-byte glyph for ch in the font8x8 table (0x20..0x7F; others -> space).
10func nx_doc_glyph(table: *u8, ch: i64) -> *u8 {
11 if ch < 32 { return table }
12 if ch > 127 { return table }
13 return ((table as i64) + (ch - 32) * 8) as *u8
14}
15
16// blit one 8x8 glyph scaled by `scale` into bm at top-left (gx,gy). set bits -> black (0x00). bounds-checked.
17func nx_doc_blit(bm: *u8, W: i64, H: i64, gx: i64, gy: i64, glyph: *u8, scale: i64) -> i64 {
18 var r: i64 = 0
19 while r < 8 {
20 let rowbits: i64 = glyph[r] as i64
21 var c: i64 = 0
22 while c < 8 {
23 if ((rowbits >> c) & 1) == 1 {
24 var dy: i64 = 0
25 while dy < scale {
26 let py: i64 = gy + r * scale + dy
27 if py >= 0 { if py < H {
28 var dx: i64 = 0
29 while dx < scale {
30 let px: i64 = gx + c * scale + dx
31 if px >= 0 { if px < W { bm[py * W + px] = 0 as u8 } }
32 dx = dx + 1
33 }
34 } }
35 dy = dy + 1
36 }
37 }
38 c = c + 1
39 }
40 r = r + 1
41 }
42 return 0
43}
44
45// Render NUL-terminated `text` into bm (caller pre-fills white 0xFF). Monospace, WORD-WRAP at the right
46// margin (whole words move to the next line; words wider than a line fall back to char-wrap), '\n' = new
47// line. Stops cleanly when the page fills, returning characters consumed so a caller can paginate (the next
48// page continues from text+consumed). This is the front half of multi-page document printing.
49func nx_doc_render(bm: *u8, W: i64, H: i64, table: *u8, text: *u8, scale: i64,
50 mleft: i64, mtop: i64, mright: i64, mbottom: i64, line_gap: i64) -> i64 {
51 let adv: i64 = 8 * scale
52 let lh: i64 = 8 * scale + line_gap
53 var x: i64 = mleft
54 var y: i64 = mtop
55 var i: i64 = 0
56 var stop: i64 = 0
57 while stop == 0 {
58 let ch: i64 = text[i] as i64
59 if ch == 0 { stop = 1 }
60 else {
61 if ch == 10 { // explicit newline
62 x = mleft
63 y = y + lh
64 i = i + 1
65 if (y + 8 * scale) > (H - mbottom) { stop = 1 }
66 } else {
67 if ch == 32 { // space: advance (collapse at line start)
68 if x > mleft { x = x + adv }
69 i = i + 1
70 } else {
71 // measure the word (run of non-space, non-newline)
72 var wl: i64 = 0
73 var k: i64 = i
74 var cont: i64 = 1
75 while cont == 1 {
76 let cc: i64 = text[k] as i64
77 if cc == 0 { cont = 0 }
78 else { if cc == 32 { cont = 0 } else { if cc == 10 { cont = 0 } else { wl = wl + 1; k = k + 1 } } }
79 }
80 // wrap the whole word to the next line if it won't fit and we're mid-line
81 if x > mleft { if (x + wl * adv) > (W - mright) { x = mleft; y = y + lh } }
82 if (y + 8 * scale) > (H - mbottom) { stop = 1 } // word moves to next page
83 else {
84 var w: i64 = 0
85 while w < wl {
86 if (x + adv) > (W - mright) { if x > mleft { x = mleft; y = y + lh } } // char-wrap (over-long word)
87 if (y + 8 * scale) > (H - mbottom) { stop = 1; w = wl }
88 else {
89 nx_doc_blit(bm, W, H, x, y, nx_doc_glyph(table, text[i] as i64), scale)
90 x = x + adv
91 i = i + 1
92 w = w + 1
93 }
94 }
95 }
96 }
97 }
98 }
99 }
100 return i
101}