code wiki / (root) / nx_layout_default_display.nx

nx_layout_default_display.nx source

↩ module page · 245 lines · 11528 B

1// nx_layout_default_display.nx -- map an HTML element tag name to 2// its CSS default display kind (BLOCK / INLINE / INLINE_BLOCK). 3// Phase 3 third primitive of NISHI_BROWSER_ROADMAP. 4// 5// Per W3C HTML spec ยง 15 (default rendering / user-agent stylesheet) 6// and CSS Display Module Level 3, every HTML element has a default 7// `display` value the user-agent stylesheet sets. This primitive 8// returns that value for the subset of tags andelinwest.com + the 9// IDE require. 10// 11// The eventual nx_layout_from_dom primitive (queued) walks a parsed 12// DOM tree and calls this to assign LayoutBox.kind. Author-supplied 13// CSS can override via the cascade (Phase 2's nx_css_apply, then a 14// Phase 3b `display` property resolver). 15// 16// Subset (most common HTML5 elements): 17// BLOCK: html body div p h1 h2 h3 h4 h5 h6 header footer main 18// section article nav aside ul ol li dl dt dd table thead 19// tbody tfoot tr blockquote pre figure figcaption form 20// fieldset hr address 21// INLINE_BLOCK: img button input textarea select 22// INLINE: span a em strong b i u code small mark sub sup label 23// (and any tag not in the above two lists) 24// TEXT: handled separately by caller from text-node detection 25// 26// What it does NOT handle yet (Phase 3b improvements): 27// - SVG / MathML namespace switches 28// - <table> internal display values (table / table-row / table-cell) 29// - <script> / <style> / <head> / <title> default-hidden treatment 30// (these have `display: none` semantically; caller filters) 31// - HTML5 custom elements (no default; caller's UA stylesheet) 32// - Case-insensitive tag matching for HTML quirks mode (HTML5 33// parser lowercases tags; until nx_html_tokenizer normalizes, 34// callers pre-lowercase if needed) 35// 36// Per cardinal feedback-honest-perf-verdict-no-aspirational-claims: 37// every tag IS exhaustively listed in this header. 38// 39// genealogy_id: w3c_html5_user_agent_stylesheet_default_rendering + 40// w3c_css_display_module_level_3 41// lineage_id: nishi_browser_layout_default_display_v1 42// 43// nx_safety_envelope: 44// intended_use: "HTML tag -> default CSS display kind" 45// sil_target: SIL1 46// evidence: [W3C_HTML5_canonical_basis, 47// sealed_display_kind_enum, 48// pure_function_table_lookup] 49// verdict: NOT_YET_EVALUATED 50 51import "nx_syscalls.nx" 52import "nx_layout_box.nx" 53 54// ---- helpers ---- 55 56// Lowercase ASCII single byte (A..Z -> a..z); leave others unchanged. 57func _disp_lc(c: i64) -> i64 { 58 if c >= 65 { // 'A' 59 if c <= 90 { return c + 32 } 60 } 61 return c 62} 63 64// Byte-equal compare a candidate tag (src[off..off+len]) against an 65// inline-listed literal byte sequence m0..m(N-1), case-insensitive 66// over the candidate. Helpers for each N keep the API small and 67// dodge variadic complexity. 68 69func _disp_eq2(src: *u8, off: i64, len: i64, 70 m0: i64, m1: i64) -> i64 { 71 if len != 2 { return 0 } 72 let c0: i64 = _disp_lc((src[off] as i64) & 255) 73 let c1: i64 = _disp_lc((src[off + 1] as i64) & 255) 74 if c0 != m0 { return 0 } 75 if c1 != m1 { return 0 } 76 return 1 77} 78 79func _disp_eq3(src: *u8, off: i64, len: i64, 80 m0: i64, m1: i64, m2: i64) -> i64 { 81 if len != 3 { return 0 } 82 let c0: i64 = _disp_lc((src[off] as i64) & 255) 83 let c1: i64 = _disp_lc((src[off + 1] as i64) & 255) 84 let c2: i64 = _disp_lc((src[off + 2] as i64) & 255) 85 if c0 != m0 { return 0 } 86 if c1 != m1 { return 0 } 87 if c2 != m2 { return 0 } 88 return 1 89} 90 91func _disp_eq4(src: *u8, off: i64, len: i64, 92 m0: i64, m1: i64, m2: i64, m3: i64) -> i64 { 93 if len != 4 { return 0 } 94 let c0: i64 = _disp_lc((src[off] as i64) & 255) 95 let c1: i64 = _disp_lc((src[off + 1] as i64) & 255) 96 let c2: i64 = _disp_lc((src[off + 2] as i64) & 255) 97 let c3: i64 = _disp_lc((src[off + 3] as i64) & 255) 98 if c0 != m0 { return 0 } 99 if c1 != m1 { return 0 } 100 if c2 != m2 { return 0 } 101 if c3 != m3 { return 0 } 102 return 1 103} 104 105func _disp_eq5(src: *u8, off: i64, len: i64, 106 m0: i64, m1: i64, m2: i64, m3: i64, m4: i64) -> i64 { 107 if len != 5 { return 0 } 108 let c0: i64 = _disp_lc((src[off] as i64) & 255) 109 let c1: i64 = _disp_lc((src[off + 1] as i64) & 255) 110 let c2: i64 = _disp_lc((src[off + 2] as i64) & 255) 111 let c3: i64 = _disp_lc((src[off + 3] as i64) & 255) 112 let c4: i64 = _disp_lc((src[off + 4] as i64) & 255) 113 if c0 != m0 { return 0 } 114 if c1 != m1 { return 0 } 115 if c2 != m2 { return 0 } 116 if c3 != m3 { return 0 } 117 if c4 != m4 { return 0 } 118 return 1 119} 120 121func _disp_eq6(src: *u8, off: i64, len: i64, 122 m0: i64, m1: i64, m2: i64, m3: i64, m4: i64, m5: i64) -> i64 { 123 if len != 6 { return 0 } 124 let c0: i64 = _disp_lc((src[off] as i64) & 255) 125 let c1: i64 = _disp_lc((src[off + 1] as i64) & 255) 126 let c2: i64 = _disp_lc((src[off + 2] as i64) & 255) 127 let c3: i64 = _disp_lc((src[off + 3] as i64) & 255) 128 let c4: i64 = _disp_lc((src[off + 4] as i64) & 255) 129 let c5: i64 = _disp_lc((src[off + 5] as i64) & 255) 130 if c0 != m0 { return 0 } 131 if c1 != m1 { return 0 } 132 if c2 != m2 { return 0 } 133 if c3 != m3 { return 0 } 134 if c4 != m4 { return 0 } 135 if c5 != m5 { return 0 } 136 return 1 137} 138 139func _disp_eq7(src: *u8, off: i64, len: i64, 140 m0: i64, m1: i64, m2: i64, m3: i64, m4: i64, m5: i64, m6: i64) -> i64 { 141 if len != 7 { return 0 } 142 let c0: i64 = _disp_lc((src[off] as i64) & 255) 143 let c1: i64 = _disp_lc((src[off + 1] as i64) & 255) 144 let c2: i64 = _disp_lc((src[off + 2] as i64) & 255) 145 let c3: i64 = _disp_lc((src[off + 3] as i64) & 255) 146 let c4: i64 = _disp_lc((src[off + 4] as i64) & 255) 147 let c5: i64 = _disp_lc((src[off + 5] as i64) & 255) 148 let c6: i64 = _disp_lc((src[off + 6] as i64) & 255) 149 if c0 != m0 { return 0 } 150 if c1 != m1 { return 0 } 151 if c2 != m2 { return 0 } 152 if c3 != m3 { return 0 } 153 if c4 != m4 { return 0 } 154 if c5 != m5 { return 0 } 155 if c6 != m6 { return 0 } 156 return 1 157} 158 159// Single-char tag check (h1..h6, p, b, i, u, a). Returns 1 if the 160// candidate is exactly the single byte `m`. 161func _disp_eq1(src: *u8, off: i64, len: i64, m: i64) -> i64 { 162 if len != 1 { return 0 } 163 let c: i64 = _disp_lc((src[off] as i64) & 255) 164 if c != m { return 0 } 165 return 1 166} 167 168// h1..h6 family: two chars, first is 'h', second is '1'..'6'. 169func _disp_is_h_family(src: *u8, off: i64, len: i64) -> i64 { 170 if len != 2 { return 0 } 171 let c0: i64 = _disp_lc((src[off] as i64) & 255) 172 let c1: i64 = (src[off + 1] as i64) & 255 173 if c0 != 104 { return 0 } // 'h' 174 if c1 < 49 { return 0 } // '1' 175 if c1 > 54 { return 0 } // '6' 176 return 1 177} 178 179// ---- public API ---- 180 181// Return the LayoutBox kind for the given tag name. Falls back to 182// INLINE for unknown tags (matches the HTML5 user-agent default -- 183// any unrecognized element is inline unless its CSS overrides). 184func nx_layout_default_display(src: *u8, tag_off: i64, tag_len: i64) -> i64 { 185 if tag_len <= 0 { return NX_LAYOUT_BOX_INLINE } 186 187 // Single-char block: p 188 if _disp_eq1(src, tag_off, tag_len, 112) == 1 { return NX_LAYOUT_BOX_BLOCK } // p 189 190 // h1..h6 family. 191 if _disp_is_h_family(src, tag_off, tag_len) == 1 { return NX_LAYOUT_BOX_BLOCK } 192 193 // 2-char blocks: hr, ul, ol, li, dl, dt, dd, tr 194 if _disp_eq2(src, tag_off, tag_len, 104, 114) == 1 { return NX_LAYOUT_BOX_BLOCK } // hr 195 if _disp_eq2(src, tag_off, tag_len, 117, 108) == 1 { return NX_LAYOUT_BOX_BLOCK } // ul 196 if _disp_eq2(src, tag_off, tag_len, 111, 108) == 1 { return NX_LAYOUT_BOX_BLOCK } // ol 197 if _disp_eq2(src, tag_off, tag_len, 108, 105) == 1 { return NX_LAYOUT_BOX_BLOCK } // li 198 if _disp_eq2(src, tag_off, tag_len, 100, 108) == 1 { return NX_LAYOUT_BOX_BLOCK } // dl 199 if _disp_eq2(src, tag_off, tag_len, 100, 116) == 1 { return NX_LAYOUT_BOX_BLOCK } // dt 200 if _disp_eq2(src, tag_off, tag_len, 100, 100) == 1 { return NX_LAYOUT_BOX_BLOCK } // dd 201 if _disp_eq2(src, tag_off, tag_len, 116, 114) == 1 { return NX_LAYOUT_BOX_BLOCK } // tr 202 if _disp_eq2(src, tag_off, tag_len, 116, 100) == 1 { return NX_LAYOUT_BOX_BLOCK } // td (table-cell: a block container, NOT inline -- else its block children flatten out) 203 if _disp_eq2(src, tag_off, tag_len, 116, 104) == 1 { return NX_LAYOUT_BOX_BLOCK } // th (table-cell) 204 205 // 3-char blocks: div, nav, pre 206 if _disp_eq3(src, tag_off, tag_len, 100, 105, 118) == 1 { return NX_LAYOUT_BOX_BLOCK } // div 207 if _disp_eq3(src, tag_off, tag_len, 110, 97, 118) == 1 { return NX_LAYOUT_BOX_BLOCK } // nav 208 if _disp_eq3(src, tag_off, tag_len, 112, 114, 101) == 1 { return NX_LAYOUT_BOX_BLOCK } // pre 209 210 // 3-char inline-block: img 211 if _disp_eq3(src, tag_off, tag_len, 105, 109, 103) == 1 { return NX_LAYOUT_BOX_INLINE_BLOCK } // img 212 213 // 4-char blocks: body, html, main, form, aside (5), table, thead/tbody/tfoot 214 if _disp_eq4(src, tag_off, tag_len, 98, 111, 100, 121) == 1 { return NX_LAYOUT_BOX_BLOCK } // body 215 if _disp_eq4(src, tag_off, tag_len, 104, 116, 109, 108) == 1 { return NX_LAYOUT_BOX_BLOCK } // html 216 if _disp_eq4(src, tag_off, tag_len, 109, 97, 105, 110) == 1 { return NX_LAYOUT_BOX_BLOCK } // main 217 if _disp_eq4(src, tag_off, tag_len, 102, 111, 114, 109) == 1 { return NX_LAYOUT_BOX_BLOCK } // form 218 219 // 5-char blocks: aside, table, tbody/thead/tfoot 220 if _disp_eq5(src, tag_off, tag_len, 97, 115, 105, 100, 101) == 1 { return NX_LAYOUT_BOX_BLOCK } // aside 221 if _disp_eq5(src, tag_off, tag_len, 116, 97, 98, 108, 101) == 1 { return NX_LAYOUT_BOX_BLOCK } // table 222 if _disp_eq5(src, tag_off, tag_len, 116, 98, 111, 100, 121) == 1 { return NX_LAYOUT_BOX_BLOCK } // tbody 223 if _disp_eq5(src, tag_off, tag_len, 116, 104, 101, 97, 100) == 1 { return NX_LAYOUT_BOX_BLOCK } // thead 224 if _disp_eq5(src, tag_off, tag_len, 116, 102, 111, 111, 116) == 1 { return NX_LAYOUT_BOX_BLOCK } // tfoot 225 226 // 5-char inline-block: input 227 if _disp_eq5(src, tag_off, tag_len, 105, 110, 112, 117, 116) == 1 { return NX_LAYOUT_BOX_INLINE_BLOCK } // input 228 229 // 6-char blocks: header, footer, figure, fieldset (8), address (7) 230 if _disp_eq6(src, tag_off, tag_len, 104, 101, 97, 100, 101, 114) == 1 { return NX_LAYOUT_BOX_BLOCK } // header 231 if _disp_eq6(src, tag_off, tag_len, 102, 111, 111, 116, 101, 114) == 1 { return NX_LAYOUT_BOX_BLOCK } // footer 232 if _disp_eq6(src, tag_off, tag_len, 102, 105, 103, 117, 114, 101) == 1 { return NX_LAYOUT_BOX_BLOCK } // figure 233 if _disp_eq6(src, tag_off, tag_len, 98, 117, 116, 116, 111, 110) == 1 { return NX_LAYOUT_BOX_INLINE_BLOCK } // button 234 if _disp_eq6(src, tag_off, tag_len, 115, 101, 108, 101, 99, 116) == 1 { return NX_LAYOUT_BOX_INLINE_BLOCK } // select 235 236 // 7-char blocks: article, section, address 237 if _disp_eq7(src, tag_off, tag_len, 97, 114, 116, 105, 99, 108, 101) == 1 { return NX_LAYOUT_BOX_BLOCK } // article 238 if _disp_eq7(src, tag_off, tag_len, 115, 101, 99, 116, 105, 111, 110) == 1 { return NX_LAYOUT_BOX_BLOCK } // section 239 if _disp_eq7(src, tag_off, tag_len, 97, 100, 100, 114, 101, 115, 115) == 1 { return NX_LAYOUT_BOX_BLOCK } // address 240 241 // Everything else (span, a, em, strong, b, i, u, code, small, 242 // mark, sub, sup, label, img-when-Phase3b, etc.) defaults to 243 // INLINE per the HTML5 user-agent stylesheet. 244 return NX_LAYOUT_BOX_INLINE 245}