code wiki / _hdl_build / nx_srcset_lib_gate.nx
nx_srcset_lib_gate.nx source
↩ module page · 408 lines · 28039 B
1// nx_srcset_lib_gate.nx -- the referee for BR14 (nx_srcset_lib, symbol bi_srcset).
2//
3// IN-PROCESS BY CONSTRUCTION. It imports the subject and the render core it is wired into, so the
4// subject is inside THIS gate's own build closure and a mutation of nx_srcset_lib.nx reaches these
5// teeth. A gate that fork/execs a deployed elf cannot be mutation-proven -- every mutant reads
6// NOT-REACHED -- so nothing here forks anything.
7//
8// ===================================================================================================
9// THE ACCEPT RULE, PRE-DECLARED BEFORE THE FIRST RUN (written 2026-08-26, before any result existed).
10// BR14 is proven by this gate IF AND ONLY IF all five hold; anything less is reported NOT PROVEN by
11// name, and the rung stays open.
12// A. GRAMMAR. Every documented descriptor form selects the candidate the HTML selection algorithm
13// selects, for a target DERIVED from the viewport and the device pixel ratio -- not from any
14// breakpoint written in this estate.
15// B. DISCRIMINATION. The three trivial wrong implementations -- always-take-the-first candidate,
16// always-take-the-last, always-take-the-largest -- each FAIL at least one tooth. A ruler that
17// cannot be distinguished from taking the first item has measured nothing.
18// C. WIRING. An <img> whose only usable URL lives in srcset / data-src / data-srcset resolves to
19// THAT URL through the real br_layout, i.e. page.bsrc_off names it. Proving the lib in isolation
20// proves a function, not a browser.
21// D. NO REGRESSION. An <img> carrying only a plain src resolves to byte-identically the range the
22// pre-BR14 code chose, checked against an INDEPENDENT instrument (nx_dom_find_attr direct).
23// E. PAINTED, NOT MERELY SELECTED. On a fixture page whose figures are lazy and responsive,
24// imgsrc_laid == decoded == painted: every laid-out <img> box decodes through the real image
25// path and leaves its own pixels in the framebuffer. This is the done-rule's SHAPE on a fixture
26// this gate controls. It is NOT the done-rule's live half (the wikipedia benchmark page over the
27// network), which needs the GUI and a network and is NOT claimed here.
28// ===================================================================================================
29import "nx_syscalls.nx"
30import "nx_gate_verdict.nx"
31import "nx_srcset_lib.nx"
32import "nx_browser_render.nx" // br_layout/br_draw_fb -- the wiring under test, in-process
33import "nx_img_to_rgb.nx"
34import "nx_png_write.nx"
35
36// Scratch lives under /tmp/<gate>/, created at SETUP: a teardown does not run when a run crashes, and
37// a gate that shares a fixture path with a production beat measures the beat, not the code.
38const SG_DIR: *u8 = "/tmp/nx_srcset_lib_gate"
39const SG_PNG: *u8 = "/tmp/nx_srcset_lib_gate/px.png"
40const SG_DIR_MODE: i64 = 493 // 0755 -- owner rwx, group/other rx
41// The fixture image is a flat block of a colour the default stylesheet cannot produce (its background
42// is white and its ink is a dark slate), so a pixel of this colour in the framebuffer can only have
43// come from the blit. A fixture whose colour the page could paint by itself is not a test.
44const SG_IMG_R: i64 = 255
45const SG_IMG_G: i64 = 0
46const SG_IMG_B: i64 = 255
47const SG_IMG_W: i64 = 24
48const SG_IMG_H: i64 = 24
49const SG_VW: i64 = 640 // the fixture viewport; every target below is DERIVED from it
50const SG_FB_W: i64 = 700
51const SG_FB_H: i64 = 900
52const SG_RGB_CH: i64 = 3
53const SG_RGBA_CH: i64 = 4
54const SG_DPR_1X: i64 = 1000
55const SG_DPR_1P5X: i64 = 1500
56const SG_DPR_2X: i64 = 2000
57const SG_DPR_3X: i64 = 3000
58
59func sg_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
60
61func sg_eq(a: i64, b: i64) -> i64 { if a == b { return 1 } return 0 }
62
63// does buf[off..off+len) equal the NUL-terminated literal, exactly and wholly?
64func sg_span_is(buf: *u8, off: i64, len: i64, lit: *u8) -> i64 {
65 if off < 0 { return 0 }
66 let n: i64 = sg_slen(lit)
67 if len != n { return 0 }
68 var i: i64 = 0
69 while i < n {
70 if (buf[off + i] as i64) != (lit[i] as i64) { return 0 }
71 i = i + 1
72 }
73 return 1
74}
75
76// run bi_srcset over a whole literal and report 1 iff the pick is exactly `want`.
77func sg_picks(list: *u8, size_px: i64, dpr: i64, want: *u8, sc: *i64, oo: *i64, ol: *i64) -> i64 {
78 let rc: i64 = bi_srcset(list, 0, sg_slen(list), size_px, dpr, sc, oo, ol)
79 if rc <= 0 { return 0 }
80 return sg_span_is(list, oo[0], ol[0], want)
81}
82
83// the verdict code alone, for the refusal teeth
84func sg_code(list: *u8, size_px: i64, dpr: i64, sc: *i64, oo: *i64, ol: *i64) -> i64 {
85 return bi_srcset(list, 0, sg_slen(list), size_px, dpr, sc, oo, ol)
86}
87
88// does the pick land on the FIRST candidate of the list? (used to discriminate against always-first)
89func sg_took_first(list: *u8, size_px: i64, dpr: i64, sc: *i64, oo: *i64, ol: *i64) -> i64 {
90 let rc: i64 = bi_srcset(list, 0, sg_slen(list), size_px, dpr, sc, oo, ol)
91 if rc <= 0 { return 0 }
92 if oo[0] == 0 { return 1 }
93 return 0
94}
95
96// resolve one <img> tag literal through bi_img_source; 1 iff it selects exactly `want`.
97func sg_src_is(tag: *u8, vw: i64, dpr: i64, want: *u8, sc: *i64, oo: *i64, ol: *i64) -> i64 {
98 let rc: i64 = bi_img_source(tag, 0, sg_slen(tag), vw, dpr, sc, oo, ol)
99 if rc == BI_SRC_NONE { return 0 }
100 return sg_span_is(tag, oo[0], ol[0], want)
101}
102
103func sg_src_code(tag: *u8, vw: i64, dpr: i64, sc: *i64, oo: *i64, ol: *i64) -> i64 {
104 return bi_img_source(tag, 0, sg_slen(tag), vw, dpr, sc, oo, ol)
105}
106
107// write the fixture PNG. Returns 1 on a file the decoder can read back -- checked, never assumed.
108func sg_make_png(wh: *i64) -> i64 {
109 sys_mkdir(SG_DIR, SG_DIR_MODE)
110 let n: i64 = SG_IMG_W * SG_IMG_H
111 let rgb: *u8 = sys_mmap(n * SG_RGB_CH + SG_RGB_CH)
112 var i: i64 = 0
113 while i < n {
114 rgb[i * SG_RGB_CH + 0] = SG_IMG_R as u8
115 rgb[i * SG_RGB_CH + 1] = SG_IMG_G as u8
116 rgb[i * SG_RGB_CH + 2] = SG_IMG_B as u8
117 i = i + 1
118 }
119 nx_png_write_rgb(SG_PNG, rgb, SG_IMG_W, SG_IMG_H)
120 let back: *u8 = nx_img_to_rgb(SG_PNG, wh)
121 if (back as i64) == 0 { return 0 }
122 if wh[0] != SG_IMG_W { return 0 }
123 if wh[1] != SG_IMG_H { return 0 }
124 return 1
125}
126
127// is the pixel at (x,y) the fixture colour? Only a blit can have put it there.
128func sg_px_is_img(px: *u8, x: i64, y: i64) -> i64 {
129 if x < 0 { return 0 }
130 if y < 0 { return 0 }
131 if x >= SG_FB_W { return 0 }
132 if y >= SG_FB_H { return 0 }
133 let o: i64 = (y * SG_FB_W + x) * SG_RGBA_CH
134 if (px[o + 0] as i64) != SG_IMG_R { return 0 }
135 if (px[o + 1] as i64) != SG_IMG_G { return 0 }
136 if (px[o + 2] as i64) != SG_IMG_B { return 0 }
137 return 1
138}
139
140// ---- FAIL REPRINT ----------------------------------------------------------------------------------
141// Every caller of this gate reads a TAIL: nx_organ_ship prints ten lines, and a gate with fifty teeth
142// therefore reports RED without showing which tooth. A truncating consumer that destroys the remedy is
143// indistinguishable from a gate that never named one, so the failing names are collected and REPRINTED
144// at the very end, where every tail reader lands.
145const SG_MAXFAIL: i64 = 16
146static sg_nfail: i64
147static sg_failv: i64 // *i64 array of name pointers, allocated on first failure
148func sg_note_fail(nm: *u8) -> i64 {
149 if sg_failv == 0 { sg_failv = sys_mmap(8 * SG_MAXFAIL) as i64 }
150 if sg_nfail < SG_MAXFAIL {
151 let a: *i64 = sg_failv as *i64
152 a[sg_nfail] = nm as i64
153 sg_nfail = sg_nfail + 1
154 }
155 return 0
156}
157func sg_check(nm: *u8, cond: i64, ctr: *i64) -> i64 {
158 let r: i64 = gv_check(nm, cond, ctr)
159 if r == 0 { sg_note_fail(nm) }
160 return r
161}
162func sg_bite(nm: *u8, bad: i64, good: i64, ctr: *i64) -> i64 {
163 let r: i64 = gv_bite(nm, bad, good, ctr)
164 if r == 0 { sg_note_fail(nm) }
165 return r
166}
167func sg_dump_fails() -> i64 {
168 gv_puts(" FAILING TEETH, reprinted here because every consumer of this gate reads a TAIL:\n" as *u8)
169 if sg_nfail == 0 { gv_puts(" none\n" as *u8) }
170 let a: *i64 = sg_failv as *i64
171 var i: i64 = 0
172 while i < sg_nfail {
173 gv_puts(" RED: " as *u8)
174 gv_puts(a[i] as *u8)
175 gv_puts("\n" as *u8)
176 i = i + 1
177 }
178 if sg_nfail >= SG_MAXFAIL { gv_puts(" (this list is a PREFIX of its own count -- more teeth failed than fit)\n" as *u8) }
179 return 0
180}
181
182func main() -> i64 {
183 let name: *u8 = "SRCSET-LIB-GATE"
184 let ctr: *i64 = gv_ctr()
185 gv_head("nx_srcset_lib -- BR14 image source selection (srcset / data-src / loading=lazy)" as *u8)
186
187 let sc: *i64 = sys_mmap(8 * BI_SCRATCH_SLOTS) as *i64
188 let oo: *i64 = sys_mmap(8) as *i64
189 let ol: *i64 = sys_mmap(8) as *i64
190
191 // ---- A. GRAMMAR: pixel-density (x) descriptors ------------------------------------------------
192 let xs: *u8 = "/a.png 1x, /b.png 2x"
193 sg_check("x-desc-at-1x-takes-the-smallest-candidate-that-covers-the-device" as *u8, sg_picks(xs, SG_VW, SG_DPR_1X, "/a.png" as *u8, sc, oo, ol), ctr)
194 sg_check("x-desc-at-2x-follows-the-device-ratio-not-the-list-order" as *u8, sg_picks(xs, SG_VW, SG_DPR_2X, "/b.png" as *u8, sc, oo, ol), ctr)
195 sg_check("x-desc-above-every-candidate-falls-back-to-the-largest-available" as *u8, sg_picks(xs, SG_VW, SG_DPR_3X, "/b.png" as *u8, sc, oo, ol), ctr)
196 let xs3: *u8 = "/a.png 1x, /b.png 1.5x, /c.png 2x"
197 sg_check("fractional-density-1.5x-parses-to-permil-and-is-selectable" as *u8, sg_picks(xs3, SG_VW, SG_DPR_1P5X, "/b.png" as *u8, sc, oo, ol), ctr)
198 let ximp: *u8 = "/a.png, /b.png 2x"
199 sg_check("a-candidate-with-no-descriptor-is-the-HTML-default-1x-not-a-drop" as *u8, sg_picks(ximp, SG_VW, SG_DPR_1X, "/a.png" as *u8, sc, oo, ol), ctr)
200 let xtie: *u8 = "/a.png 2x, /b.png 2x"
201 sg_check("ties-are-defined-first-in-document-order-wins" as *u8, sg_picks(xtie, SG_VW, SG_DPR_2X, "/a.png" as *u8, sc, oo, ol), ctr)
202 let xup: *u8 = "/a.png 1x, /b.png 2X"
203 sg_check("uppercase-descriptor-suffix-accepted-declared-divergence-from-spec-letter" as *u8, sg_picks(xup, SG_VW, SG_DPR_2X, "/b.png" as *u8, sc, oo, ol), ctr)
204
205 // ---- A. GRAMMAR: width (w) descriptors, target DERIVED from viewport x density ----------------
206 let ws: *u8 = "/w320.png 320w, /w640.png 640w, /w1280.png 1280w"
207 sg_check("w-desc-target-is-viewport-times-density-640x1x-picks-640w" as *u8, sg_picks(ws, SG_VW, SG_DPR_1X, "/w640.png" as *u8, sc, oo, ol), ctr)
208 sg_check("w-desc-same-list-at-2x-picks-1280w-because-the-TARGET-moved-not-a-breakpoint" as *u8, sg_picks(ws, SG_VW, SG_DPR_2X, "/w1280.png" as *u8, sc, oo, ol), ctr)
209 sg_check("w-desc-target-above-every-candidate-falls-back-to-the-largest" as *u8, sg_picks(ws, SG_VW * SG_DPR_3X / SG_DPR_1X, SG_DPR_1X, "/w1280.png" as *u8, sc, oo, ol), ctr)
210 sg_check("w-desc-tiny-viewport-picks-the-smallest-that-still-covers-it" as *u8, sg_picks(ws, 200, SG_DPR_1X, "/w320.png" as *u8, sc, oo, ol), ctr)
211
212 // ---- A. GRAMMAR: tokenisation ------------------------------------------------------------------
213 let comma: *u8 = "/a,b.png 1x, /c.png 2x"
214 sg_check("a-URL-containing-a-comma-is-not-split-candidates-end-at-WHITESPACE" as *u8, sg_picks(comma, SG_VW, SG_DPR_1X, "/a,b.png" as *u8, sc, oo, ol), ctr)
215 let wsy: *u8 = " /a.png 1x , /b.png 2x "
216 sg_check("runs-of-whitespace-and-commas-between-candidates-are-separators" as *u8, sg_picks(wsy, SG_VW, SG_DPR_2X, "/b.png" as *u8, sc, oo, ol), ctr)
217 let trail: *u8 = "/a.png,,, /b.png 2x"
218 sg_check("every-trailing-comma-is-trimmed-and-leaves-an-implicit-1x-candidate" as *u8, sg_picks(trail, SG_VW, SG_DPR_1X, "/a.png" as *u8, sc, oo, ol), ctr)
219 // THE CASE THAT CAUGHT THE AUTHOR OF THIS GATE OUT, pinned so it catches nobody else: with no
220 // whitespace between them, "/a.png,/b.png 2x" is ONE candidate whose URL contains a comma -- the
221 // HTML algorithm ends a URL at WHITESPACE and only then strips trailing commas. A first draft of
222 // this file asserted the opposite and the LIB was right, which is the only reason to keep the row.
223 let joined: *u8 = "/a.png,/b.png 2x"
224 sg_check("comma-joined-URLs-with-no-whitespace-are-ONE-candidate-not-two" as *u8, sg_picks(joined, SG_VW, SG_DPR_2X, "/a.png,/b.png" as *u8, sc, oo, ol), ctr)
225 let one: *u8 = "/only.png"
226 sg_check("a-single-bare-URL-is-a-valid-one-candidate-list" as *u8, sg_picks(one, SG_VW, SG_DPR_1X, "/only.png" as *u8, sc, oo, ol), ctr)
227
228 // ---- A. GRAMMAR: every malformed input REFUSES BY NAME ------------------------------------------
229 sg_check("mixed-w-and-x-descriptors-refuse-the-whole-attribute-by-name" as *u8, sg_eq(sg_code("/a.png 400w, /b.png 2x" as *u8, SG_VW, SG_DPR_1X, sc, oo, ol), BI_MIXED_DESCRIPTORS), ctr)
230 sg_check("an-implicit-1x-candidate-beside-a-w-candidate-is-also-a-mixed-list" as *u8, sg_eq(sg_code("/a.png 400w, /b.png" as *u8, SG_VW, SG_DPR_1X, sc, oo, ol), BI_MIXED_DESCRIPTORS), ctr)
231 sg_check("an-unknown-descriptor-suffix-drops-its-candidate-2y-is-not-a-descriptor" as *u8, sg_eq(sg_code("/a.png 2y" as *u8, SG_VW, SG_DPR_1X, sc, oo, ol), BI_NO_CANDIDATES), ctr)
232 sg_check("a-fractional-width-descriptor-drops-w-is-an-integer" as *u8, sg_eq(sg_code("/a.png 1.5w" as *u8, SG_VW, SG_DPR_1X, sc, oo, ol), BI_NO_CANDIDATES), ctr)
233 sg_check("a-zero-descriptor-drops-in-both-kinds" as *u8, sg_eq(sg_code("/a.png 0x" as *u8, SG_VW, SG_DPR_1X, sc, oo, ol) + sg_code("/b.png 0w" as *u8, SG_VW, SG_DPR_1X, sc, oo, ol), BI_NO_CANDIDATES + BI_NO_CANDIDATES), ctr)
234 sg_check("a-second-descriptor-token-drops-the-candidate" as *u8, sg_eq(sg_code("/a.png 100w 2x" as *u8, SG_VW, SG_DPR_1X, sc, oo, ol), BI_NO_CANDIDATES), ctr)
235 // REGRESSION GUARD for the defect this gate found on 2026-08-26: dropping a candidate must also
236 // CONSUME it. Before the fix the leftover "2x" re-entered URL collection and was selected as an
237 // image URL -- a bare descriptor served to the fetcher as if it were a picture.
238 let two: *u8 = "/a.png 100w 2x, /b.png 640w"
239 sg_check("a-bare-descriptor-left-over-from-a-dropped-candidate-is-NEVER-read-as-a-URL" as *u8, sg_picks(two, SG_VW, SG_DPR_1X, "/b.png" as *u8, sc, oo, ol), ctr)
240 sg_check("a-number-too-wide-to-scale-into-permil-drops-instead-of-wrapping" as *u8, sg_eq(sg_code("/a.png 99999999999999999999w" as *u8, SG_VW, SG_DPR_1X, sc, oo, ol), BI_NO_CANDIDATES), ctr)
241 sg_check("a-bare-dot-with-no-fraction-digits-is-not-a-number" as *u8, sg_eq(sg_code("/a.png 1.x" as *u8, SG_VW, SG_DPR_1X, sc, oo, ol), BI_NO_CANDIDATES), ctr)
242 sg_check("an-empty-attribute-refuses-and-leaves-no-usable-range-behind" as *u8, sg_eq(sg_code("" as *u8, SG_VW, SG_DPR_1X, sc, oo, ol), BI_NO_CANDIDATES) * sg_eq(oo[0], 0 - 1), ctr)
243 sg_check("a-non-positive-target-refuses-by-name-rather-than-guessing-a-viewport" as *u8, sg_eq(sg_code("/a.png 1x" as *u8, 0, SG_DPR_1X, sc, oo, ol), BI_BAD_TARGET), ctr)
244 sg_check("a-non-positive-density-refuses-by-name-too" as *u8, sg_eq(sg_code("/a.png 1x" as *u8, SG_VW, 0, sc, oo, ol), BI_BAD_TARGET), ctr)
245
246 // ---- B. DISCRIMINATION: the trivial wrong implementations must FAIL ----------------------------
247 // A box blur passes "noise reduced"; only "edge preserved" refutes it. These are that tooth for a
248 // candidate selector. Each names the exact wrong implementation it kills, so a reader can see that
249 // the greens above are not reachable by returning a fixed position in the list.
250 sg_check("anti-vacuity-ALWAYS-FIRST-is-refuted-640x2x-must-be-the-THIRD-candidate" as *u8, sg_picks(ws, SG_VW, SG_DPR_2X, "/w1280.png" as *u8, sc, oo, ol), ctr)
251 sg_check("anti-vacuity-ALWAYS-LAST-is-refuted-200x1x-must-be-the-FIRST-candidate" as *u8, sg_picks(ws, 200, SG_DPR_1X, "/w320.png" as *u8, sc, oo, ol), ctr)
252 sg_check("anti-vacuity-ALWAYS-LARGEST-is-refuted-640x1x-must-be-the-MIDDLE-candidate" as *u8, sg_picks(ws, SG_VW, SG_DPR_1X, "/w640.png" as *u8, sc, oo, ol), ctr)
253 // and the same three positions in ONE list under ONE ruler, so no tooth above can be satisfied by a
254 // per-list constant either: first, middle and last are all reachable answers for the same bytes.
255 sg_bite("neg-control-selection-tracks-the-TARGET-not-the-POSITION" as *u8, 1 - sg_took_first(ws, SG_VW, SG_DPR_2X, sc, oo, ol), 1 - sg_took_first(ws, 200, SG_DPR_1X, sc, oo, ol), ctr)
256
257 // ---- sizes: evaluated where decidable, REFUSED BY NAME where not -------------------------------
258 let szpx: *u8 = "300px"
259 sg_check("sizes-in-px-is-taken-as-the-layout-width" as *u8, sg_eq(bi_sizes_px(szpx, 0, sg_slen(szpx), SG_VW, sc), 300) * sg_eq(sc[BI_SC_SIZECODE], BI_SIZES_PX), ctr)
260 let szvw: *u8 = "50vw"
261 sg_check("sizes-in-vw-is-a-PERCENT-OF-THE-VIEWPORT-not-a-pixel-count" as *u8, sg_eq(bi_sizes_px(szvw, 0, sg_slen(szvw), 800, sc), 400) * sg_eq(sc[BI_SC_SIZECODE], BI_SIZES_VW), ctr)
262 let szmq: *u8 = "(max-width: 600px) 100vw, 50vw"
263 sg_check("a-media-condition-REFUSES-BY-NAME-and-falls-back-to-the-HTML-100vw-default" as *u8, sg_eq(bi_sizes_px(szmq, 0, sg_slen(szmq), SG_VW, sc), SG_VW) * sg_eq(sc[BI_SC_SIZECODE], BI_SIZES_UNPARSED), ctr)
264 let szjunk: *u8 = "20em"
265 sg_check("a-unit-this-lib-cannot-evaluate-refuses-rather-than-reading-the-number-alone" as *u8, sg_eq(sc[BI_SC_SIZECODE] * 0 + bi_sizes_px(szjunk, 0, sg_slen(szjunk), SG_VW, sc), SG_VW) * sg_eq(sc[BI_SC_SIZECODE], BI_SIZES_UNPARSED), ctr)
266 // and sizes actually MOVES the selection -- a sizes nobody consults is a sizes nobody honoured.
267 let sztag: *u8 = "<img sizes='320px' srcset='/w320.png 320w, /w640.png 640w, /w1280.png 1280w'>"
268 sg_check("sizes-changes-which-candidate-wins-at-the-same-viewport" as *u8, sg_src_is(sztag, SG_VW, SG_DPR_1X, "/w320.png" as *u8, sc, oo, ol), ctr)
269
270 // ---- placeholder + loading=lazy ----------------------------------------------------------------
271 let dataurl: *u8 = "data:image/gif;base64,R0lGODlhAQABAAAAACw="
272 sg_check("a-data-URI-src-is-a-PARKING-SPOT-not-a-picture" as *u8, sg_eq(bi_is_placeholder(dataurl, 0, sg_slen(dataurl)), 1), ctr)
273 let dataup: *u8 = "DATA:image/png,x"
274 sg_check("the-placeholder-test-is-case-insensitive-like-every-URL-scheme" as *u8, sg_eq(bi_is_placeholder(dataup, 0, sg_slen(dataup)), 1), ctr)
275 let realurl: *u8 = "/img/real.png"
276 sg_bite("neg-control-a-real-URL-is-NOT-a-placeholder" as *u8, bi_is_placeholder(dataurl, 0, sg_slen(dataurl)), bi_is_placeholder(realurl, 0, sg_slen(realurl)), ctr)
277 let lz: *u8 = "<img loading='lazy' src='/a.png'>"
278 let eg: *u8 = "<img loading='eager' src='/a.png'>"
279 let nolz: *u8 = "<img src='/a.png'>"
280 sg_bite("neg-control-loading-lazy-is-reported-and-loading-eager-is-not" as *u8, bi_img_lazy(lz, 0, sg_slen(lz), sc), bi_img_lazy(eg, 0, sg_slen(eg), sc), ctr)
281 sg_check("an-img-with-no-loading-attribute-is-not-lazy" as *u8, sg_eq(bi_img_lazy(nolz, 0, sg_slen(nolz), sc), 0), ctr)
282
283 // ---- bi_img_source: WHICH RULE FIRED, and in the browser's order --------------------------------
284 let t_plain: *u8 = "<img src='/img/eager.png'>"
285 let t_both: *u8 = "<img src='/img/fallback.png' srcset='/img/a.png 1x, /img/b.png 2x'>"
286 let t_lazy: *u8 = "<img loading='lazy' src='data:image/gif;base64,R0lGODlhAQABAAAAACw=' data-src='/img/lazy.png'>"
287 let t_dss: *u8 = "<img src='data:image/gif;base64,AAAA' data-srcset='/img/d1.png 1x, /img/d2.png 2x'>"
288 let t_orig: *u8 = "<img src='data:image/gif;base64,AAAA' data-original='/img/orig.png'>"
289 let t_none: *u8 = "<img alt='no source here'>"
290 let t_holdr: *u8 = "<img src='data:image/gif;base64,AAAA'>"
291 let t_title: *u8 = "<img data-original-title='a tooltip, not a picture'>"
292 sg_check("srcset-outranks-src-exactly-as-a-browser-resolves-it" as *u8, sg_src_is(t_both, SG_VW, SG_DPR_1X, "/img/a.png" as *u8, sc, oo, ol) * sg_eq(sg_src_code(t_both, SG_VW, SG_DPR_1X, sc, oo, ol), BI_SRC_SRCSET), ctr)
293 sg_check("a-placeholder-src-plus-data-src-resolves-to-the-REAL-url-THE-BR14-DEFECT" as *u8, sg_src_is(t_lazy, SG_VW, SG_DPR_1X, "/img/lazy.png" as *u8, sc, oo, ol) * sg_eq(sg_src_code(t_lazy, SG_VW, SG_DPR_1X, sc, oo, ol), BI_SRC_DATA_ATTR), ctr)
294 sg_check("data-srcset-is-selected-by-the-SAME-ruler-as-srcset" as *u8, sg_src_is(t_dss, SG_VW, SG_DPR_2X, "/img/d2.png" as *u8, sc, oo, ol) * sg_eq(sg_src_code(t_dss, SG_VW, SG_DPR_1X, sc, oo, ol), BI_SRC_DATA_SRCSET), ctr)
295 sg_check("data-original-is-honoured-as-a-lazy-loader-convention" as *u8, sg_src_is(t_orig, SG_VW, SG_DPR_1X, "/img/orig.png" as *u8, sc, oo, ol), ctr)
296 sg_check("an-element-with-no-source-at-all-reports-NONE-and-no-usable-range" as *u8, sg_eq(sg_src_code(t_none, SG_VW, SG_DPR_1X, sc, oo, ol), BI_SRC_NONE) * sg_eq(oo[0], 0 - 1), ctr)
297 sg_check("an-element-with-ONLY-a-placeholder-returns-it-unchanged-behaviour-preserved" as *u8, sg_eq(sg_src_code(t_holdr, SG_VW, SG_DPR_1X, sc, oo, ol), BI_SRC_PLACEHOLDER) * sg_span_is(t_holdr, oo[0], ol[0], "data:image/gif;base64,AAAA" as *u8), ctr)
298 sg_bite("neg-control-data-original-title-is-a-tooltip-and-must-NEVER-be-read-as-an-image-url" as *u8, sg_eq(sg_src_code(t_title, SG_VW, SG_DPR_1X, sc, oo, ol), BI_SRC_NONE), sg_eq(sg_src_code(t_orig, SG_VW, SG_DPR_1X, sc, oo, ol), BI_SRC_NONE), ctr)
299
300 // ---- D. NO REGRESSION, checked against an INDEPENDENT instrument -------------------------------
301 // The claim "the eager path is byte-identical" is not worth anything asserted. nx_dom_find_attr is
302 // the reader br_extract used BEFORE BR14; if bi_img_source returns a different range for a plain
303 // <img src>, this fails -- and it is a different code path reaching the same bytes, not a restatement.
304 let da: *i64 = sys_mmap(8) as *i64
305 let db: *i64 = sys_mmap(8) as *i64
306 let direct: i64 = nx_dom_find_attr(t_plain, 0, sg_slen(t_plain), "src\x00" as *u8, da, db)
307 let viaLib: i64 = bi_img_source(t_plain, 0, sg_slen(t_plain), SG_VW, SG_DPR_1X, sc, oo, ol)
308 sg_check("eager-path-selects-the-SAME-byte-range-the-pre-BR14-reader-selected" as *u8, sg_eq(direct, 1) * sg_eq(viaLib, BI_SRC_SRC) * sg_eq(oo[0], da[0]) * sg_eq(ol[0], db[0]), ctr)
309
310 // ---- C. WIRING: the SAME decision, taken by the REAL br_layout ---------------------------------
311 // Proving the lib alone proves a function, not a browser. This runs the shipping cascade+layout and
312 // reads page.bsrc_off -- the exact array every image consumer in the estate reads.
313 let fx: *u8 = "<html><body><div>Alpha</div><img src='/img/eager.png'><div>Beta</div><img src='/img/fallback.png' srcset='/w320.png 320w, /w640.png 640w, /w1280.png 1280w'><div>Gamma</div><img loading='lazy' src='data:image/gif;base64,AAAA' data-src='/img/lazy.png'><div>Delta</div><img loading='lazy' src='data:image/gif;base64,AAAA' data-srcset='/img/d1.png 1x, /img/d2.png 2x'></body></html>"
314 let page: *Page = sys_mmap(NX_PAGE_BYTES) as *Page
315 page.raw = fx
316 page.raw_len = sg_slen(fx)
317 page.dpr_permil = SG_DPR_1X
318 br_layout(page, SG_VW)
319 let tr: *LayoutTree = page.tree
320 var nimg: i64 = 0
321 var n_eager: i64 = 0
322 var n_640: i64 = 0
323 var n_lazyurl: i64 = 0
324 var n_d1: i64 = 0
325 var n_holder: i64 = 0
326 var n_lazyflag: i64 = 0
327 var q: i64 = 0
328 while q < tr.count {
329 if page.bsrc_off[q] != (0 - 1) {
330 nimg = nimg + 1
331 let o: i64 = page.bsrc_off[q]
332 let l: i64 = page.bsrc_len[q]
333 if sg_span_is(page.buf, o, l, "/img/eager.png" as *u8) == 1 { n_eager = n_eager + 1 }
334 if sg_span_is(page.buf, o, l, "/w640.png" as *u8) == 1 { n_640 = n_640 + 1 }
335 if sg_span_is(page.buf, o, l, "/img/lazy.png" as *u8) == 1 { n_lazyurl = n_lazyurl + 1 }
336 if sg_span_is(page.buf, o, l, "/img/d1.png" as *u8) == 1 { n_d1 = n_d1 + 1 }
337 if bi_is_placeholder(page.buf, o, l) == 1 { n_holder = n_holder + 1 }
338 if page.bsrc_lazy[q] == 1 { n_lazyflag = n_lazyflag + 1 }
339 }
340 q = q + 1
341 }
342 gv_subjects("img-boxes-the-real-br_layout-produced" as *u8, nimg, ctr)
343 sg_check("fixture-reached-the-condition-br_layout-boxed-all-four-figures" as *u8, sg_eq(nimg, 4), ctr)
344 sg_check("wired-a-plain-eager-src-survives-br_layout-unchanged" as *u8, sg_eq(n_eager, 1), ctr)
345 sg_check("wired-the-srcset-candidate-reaches-page.bsrc_off-through-br_layout" as *u8, sg_eq(n_640, 1), ctr)
346 sg_check("wired-data-src-reaches-page.bsrc_off-through-br_layout" as *u8, sg_eq(n_lazyurl, 1), ctr)
347 sg_check("wired-data-srcset-reaches-page.bsrc_off-through-br_layout" as *u8, sg_eq(n_d1, 1), ctr)
348 sg_check("wired-loading-lazy-is-recorded-per-box-for-exactly-the-two-lazy-figures" as *u8, sg_eq(n_lazyflag, 2), ctr)
349 sg_check("no-figure-is-left-holding-a-data-URI-placeholder-THIS-IS-THE-BLANK-FIGURE-DEFECT" as *u8, sg_eq(n_holder, 0) * sg_eq(nimg, 4), ctr)
350
351 // ---- E. PAINTED, NOT MERELY SELECTED -----------------------------------------------------------
352 // The done-rule's shape on a fixture this gate owns: laid == decoded == painted. Three of the four
353 // figures carry a data: URI in src, so on the pre-BR14 reader decoded would be 1 of 4 and this
354 // section fails -- which is exactly what makes it a test rather than a description.
355 let wh: *i64 = sys_mmap(16) as *i64
356 let fixture_ok: i64 = sg_make_png(wh)
357 if gv_need("a-decodable-fixture-PNG-the-codec-is-not-BR14s-subject" as *u8, fixture_ok, ctr) == 1 {
358 let ph: *u8 = "<html><body><div>One</div><img src='/tmp/nx_srcset_lib_gate/px.png'><div>Two</div><img src='data:image/gif;base64,AAAA' data-src='/tmp/nx_srcset_lib_gate/px.png'><div>Three</div><img srcset='/tmp/nx_srcset_lib_gate/px.png 1x, /tmp/nx_srcset_lib_gate/absent.png 4x'><div>Four</div><img loading='lazy' src='data:image/gif;base64,AAAA' data-srcset='/tmp/nx_srcset_lib_gate/px.png 1x'></body></html>"
359 let p2: *Page = sys_mmap(NX_PAGE_BYTES) as *Page
360 p2.raw = ph
361 p2.raw_len = sg_slen(ph)
362 p2.dpr_permil = SG_DPR_1X
363 br_layout(p2, SG_VW)
364 let t2: *LayoutTree = p2.tree
365 var laid: i64 = 0
366 var decoded: i64 = 0
367 var i2: i64 = 0
368 while i2 < t2.count {
369 if p2.bsrc_off[i2] != (0 - 1) {
370 laid = laid + 1
371 let so: i64 = p2.bsrc_off[i2]
372 let sl: i64 = p2.bsrc_len[i2]
373 let pth: *u8 = sys_mmap(sl + 1)
374 var j: i64 = 0
375 while j < sl { pth[j] = p2.buf[so + j]; j = j + 1 }
376 pth[sl] = 0 as u8
377 let w2: *i64 = sys_mmap(16) as *i64
378 let rgb2: *u8 = nx_img_to_rgb(pth, w2)
379 if (rgb2 as i64) != 0 {
380 p2.bimg[i2] = rgb2 as i64
381 p2.bimg_w[i2] = w2[0]
382 p2.bimg_h[i2] = w2[1]
383 decoded = decoded + 1
384 }
385 }
386 i2 = i2 + 1
387 }
388 let fb: *Framebuffer = sys_mmap(NX_FRAMEBUFFER_BYTES) as *Framebuffer
389 let px: *u8 = sys_mmap(SG_FB_W * SG_FB_H * SG_RGBA_CH + SG_RGBA_CH)
390 nx_framebuffer_init(fb, px, SG_FB_W, SG_FB_H)
391 br_draw_fb(fb, p2, SG_FB_W, SG_DIR, sg_slen(SG_DIR), 1)
392 var painted: i64 = 0
393 var i3: i64 = 0
394 while i3 < t2.count {
395 if p2.bimg[i3] != 0 {
396 let bx: *LayoutBox = ((t2.boxes as i64) + i3 * NX_LAYOUT_BOX_BYTES) as *LayoutBox
397 if sg_px_is_img(px, bx.x + 1, bx.y + NX_CHROME_H + 1) == 1 { painted = painted + 1 }
398 }
399 i3 = i3 + 1
400 }
401 gv_subjects("laid-out-img-boxes-on-the-paint-fixture" as *u8, laid, ctr)
402 sg_check("every-laid-out-figure-DECODES-through-the-real-image-path-laid-equals-decoded" as *u8, sg_eq(laid, 4) * sg_eq(decoded, laid), ctr)
403 sg_check("every-decoded-figure-LEAVES-ITS-OWN-PIXELS-in-the-framebuffer-decoded-equals-painted" as *u8, sg_eq(decoded, 4) * sg_eq(painted, decoded), ctr)
404 }
405
406 sg_dump_fails()
407 return gv_verdict(name, ctr, "nx_srcset_lib: srcset/data-src/loading=lazy source selection" as *u8)
408}