nx_paint_walk_layout_text_test.nx source
↩ module page · 140 lines · 5446 B
1// nx_paint_walk_layout_text_test.nx -- smoke for the integrated
2// background + TEXT-box rendering walk. Pairs with
3// nx_paint_walk_layout_test (background-only) which still passes
4// because new text rendering is gated on opt-in via
5// nx_paint_ctx_set_text.
6//
7// Fixture: 1-box tree with a single TEXT box at (3, 2) carrying
8// the byte "1". The walk should rasterize the '1' glyph into the
9// framebuffer at that position.
10
11import "nx_syscalls.nx"
12import "nx_css_tokenize.nx"
13import "nx_css_apply.nx"
14import "nx_css_color_decode.nx"
15import "nx_layout_box.nx"
16import "nx_paint_solid_rect.nx"
17import "nx_paint_text.nx"
18import "nx_font_bitmap_5x7.nx"
19import "nx_paint_walk_layout.nx"
20
21func _put_byte(buf: *u8, i: i64, v: i64) -> i64 {
22 buf[i] = v as u8
23 return 0
24}
25
26func main() -> i64 {
27 // Source buffer hosting (a) the text body "1" at offset 0, and
28 // (b) the paint-table's "background-color" property name at
29 // offset 16 (so the table init writes don't clobber the text
30 // body). We give the paint table its OWN 64-byte buffer to
31 // keep concerns clean.
32 let text_src: *u8 = (sys_mmap(32)) as *u8
33 _put_byte(text_src, 0, 49) // '1'
34
35 // Paint table.
36 let table_buf: *u8 = (sys_mmap(64)) as *u8
37 let table: *PaintPropTable = (sys_mmap(NX_PAINT_PROP_TABLE_BYTES as nx_size)) as *PaintPropTable
38 nx_paint_prop_table_init(table, table_buf)
39
40 // Cascade is empty (no background, no styles).
41 let computed: *CssComputedDecl = (sys_mmap(NX_CSS_COMPUTED_DECL_BYTES as nx_size)) as *CssComputedDecl
42 let n_computed: i64 = 0
43
44 // Build 1-box LayoutTree.
45 let max_boxes: i64 = 4
46 let boxes: *LayoutBox = (sys_mmap((max_boxes * NX_LAYOUT_BOX_BYTES) as nx_size)) as *LayoutBox
47 let tree: *LayoutTree = (sys_mmap(NX_LAYOUT_TREE_BYTES as nx_size)) as *LayoutTree
48 nx_layout_tree_init(tree, boxes, max_boxes)
49 let text_idx: i64 = nx_layout_box_append(tree, NX_LAYOUT_BOX_TEXT, 0)
50
51 // Manually position the text box at (3, 2). Set text body to the
52 // byte at offset 0 of text_src, length 1.
53 let tb: *LayoutBox = boxes
54 tb.x = 3
55 tb.y = 2
56 tb.w = 6
57 tb.h = 7
58 nx_layout_box_set_text(tree, text_idx, 0, 1)
59
60 // Framebuffer.
61 let fb_pixels: *u8 = (sys_mmap((32 * 16 * 4) as nx_size)) as *u8
62 let fb: *Framebuffer = (sys_mmap(NX_FRAMEBUFFER_BYTES as nx_size)) as *Framebuffer
63 nx_framebuffer_init(fb, fb_pixels, 32, 16)
64 nx_framebuffer_clear(fb)
65
66 // PaintCtx + opt-in text rendering with BLACK foreground.
67 let ctx: *PaintCtx = (sys_mmap(NX_PAINT_CTX_BYTES as nx_size)) as *PaintCtx
68 // Cascade-source buffer can be the same as text_src (no cascade
69 // decls exist so byte equality isn't exercised).
70 nx_paint_ctx_init(ctx, fb, tree, computed, n_computed, text_src, table)
71
72 let black: *CssColor = (sys_mmap(NX_CSS_COLOR_BYTES as nx_size)) as *CssColor
73 black.r = 0
74 black.g = 0
75 black.b = 0
76 black.a = 255
77
78 nx_paint_ctx_set_text(ctx, text_src, black)
79
80 // Walk: should paint the '1' glyph.
81 let total: i64 = nx_paint_walk_layout(ctx, text_idx)
82
83 // '1' glyph pixel count (per the font row patterns):
84 // row 0 ..#.. 1 pixel
85 // row 1 .##.. 2 pixels
86 // row 2 ..#.. 1 pixel
87 // row 3 ..#.. 1 pixel
88 // row 4 ..#.. 1 pixel
89 // row 5 ..#.. 1 pixel
90 // row 6 .###. 3 pixels
91 // Total = 10 pixels.
92 if total != 10 { return 1 }
93
94 let probe: *CssColor = (sys_mmap(NX_CSS_COLOR_BYTES as nx_size)) as *CssColor
95
96 // Text painted at (3, 2). '1' has its center stroke at col 2
97 // (relative to cell), so the center column should be at x = 5
98 // (= 3 base + 2 col offset). Row 0..6 span y = 2..8.
99
100 // Center stroke is lit at every row.
101 nx_framebuffer_get_pixel(fb, 5, 2, probe)
102 if probe.r != 0 { return 10 } // black foreground; r,g,b all 0
103 if probe.g != 0 { return 11 }
104 if probe.b != 0 { return 12 }
105 if probe.a != 255 { return 13 } // opaque
106
107 // Row 1 has the .##.. pattern: col 1 also lit, plus center col 2.
108 // (x = 3+1 = 4, y = 2+1 = 3) should be lit.
109 nx_framebuffer_get_pixel(fb, 4, 3, probe)
110 if probe.a != 255 { return 20 }
111
112 // Row 6 (bottom): .###. pattern. cols 1, 2, 3 lit. (x = 4, 5, 6 at y = 8).
113 nx_framebuffer_get_pixel(fb, 4, 8, probe)
114 if probe.a != 255 { return 30 }
115 nx_framebuffer_get_pixel(fb, 6, 8, probe)
116 if probe.a != 255 { return 31 }
117
118 // Pixel that should NOT be lit: col 0 (x = 3) at row 0 (y = 2)
119 // (..#.. -> col 0 is 0, so x = 3 is unlit).
120 nx_framebuffer_get_pixel(fb, 3, 2, probe)
121 if probe.a != 0 { return 40 } // untouched -> transparent zero
122
123 // Pixel below the glyph (y = 10) is untouched.
124 nx_framebuffer_get_pixel(fb, 5, 10, probe)
125 if probe.a != 0 { return 50 }
126
127 // ---- Verify text rendering is OFF by default (without
128 // nx_paint_ctx_set_text). Reset everything. ----
129 nx_framebuffer_clear(fb)
130 let ctx2: *PaintCtx = (sys_mmap(NX_PAINT_CTX_BYTES as nx_size)) as *PaintCtx
131 nx_paint_ctx_init(ctx2, fb, tree, computed, n_computed, text_src, table)
132 // Do NOT call nx_paint_ctx_set_text -- text rendering should
133 // remain disabled.
134 let total2: i64 = nx_paint_walk_layout(ctx2, text_idx)
135 if total2 != 0 { return 60 } // no background-color, no text -> 0 pixels
136 nx_framebuffer_get_pixel(fb, 5, 2, probe)
137 if probe.a != 0 { return 61 }
138
139 return 0
140}