code wiki / (root) / nx_kp_break.nx

nx_kp_break.nx

buildroot/runtime/nx_kp_break.nx

17384 B379 linesdepth 3pulls 3 transitivereach 0 importersview sourcekind tool
docsdependenciesstructsconstsfunctions

about

nx_kp_break.nx -- KNUTH-PLASS OPTIMAL LINE BREAKING, integer-exact. WHY: every browser, and almost every renderer, breaks lines FIRST-FIT -- it fills the current line until the next word does not fit, then breaks, and never reconsiders. That is a greedy choice made with no knowledge of the rest of the paragraph, and it is why justified text on the web has rivers of white and books do not. Knuth and Plass (1981, the TeX line breaker) instead model the paragraph as BOXES (words), GLUE (spaces that can stretch and shrink) and PENALTIES (places a break is discouraged or encouraged), then choose the set of breakpoints that minimises TOTAL badness over the WHOLE paragraph by dynamic programming. Accepting a slightly worse line early to avoid a terrible line later is a trade a greedy algorithm cannot make. This is the piece CSS cannot reach. `hyphens:auto` and `text-align:justify` only make the browser's greedy result less ugly; they do not change the algorithm. Owning the line breaker is what makes a Nishi reading surface typographically book-grade rather than screen-grade. INTEGER-EXACT: badness is TeX's 100*r^3 evaluated in fixed point, so a paragraph lays out identically on every host. Widths are in milli-units (one character = 1000) which keeps the arithmetic exact without float. nx_kp_break fit <cols> <text> -- optimal layout, one line per output line nx_kp_break compare <cols> <text> -- Knuth-Plass vs greedy first-fit, with the measured difference nx_kp_break selftest -- the gate license_tier: ORIGINAL

dependencies 2 imports · 0 importers

nx_gate_verdict.nx nx_syscalls.nx nx_kp_break.nx

imports: nx_gate_verdict.nxnx_syscalls.nx

imported by: nobody (leaf or entry point)

call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown

main kp_puts sys_write sys_exit kp_seq kp_selftest gv_head gv_puts sys_write ↻ gv_ctr sys_mmap nxa_die sys_write ↻ sys_exit ↻ nxa_lock_take nxa_lock_addr sys_write ↻ nxa_lock_give nxa_lock_addr ↻ nxa_report_overrun sys_write ↻ nxa_dump_printable sys_write ↻ nxa_dump_sizes sys_write ↻ sys_mmap ↻ kp_words kp_optimal kp_ratio kp_badness kp_backtrack sys_mmap ↻ kp_greedy kp_ratio ↻ kp_badness ↻ kp_worst kp_ratio ↻ kp_badness ↻ kp_puts ↻ kp_num

structs

none

consts

24const KP_MAGIC_4000: i64 = 4000
25const KP_MAGIC_100000: i64 = 100000
27const KP_UNIT: i64 = 1000 // one character cell
28const KP_SP_NAT: i64 = 1000 // interword space: natural width
29const KP_SP_STRETCH: i64 = 500 // ... may stretch by half a space
30const KP_SP_SHRINK: i64 = 333 // ... may shrink by a third (TeX's plain.tex proportions)
31const KP_MAX_WORDS: i64 = 512
32const KP_INF: i64 = 1000000000 // "this line cannot be set" -- never a real cost
33const KP_BAD_CAP: i64 = 10000 // TeX treats anything past this as equally awful
34const KP_R_SCALE: i64 = 1000
35const KP_BAD_K: i64 = 100 // badness = 100 * r^3
36const KP_R_CUBE_DIV: i64 = 1000000000 // (r/1000)^3 == r^3 / 1e9
37const KP_LINE_PENALTY: i64 = 10 // a small per-line cost, so an equal-badness layout prefers fewer lines
234const KP_TEST_TEXT: *u8 = "In olden times when wishing still helped one there lived a king whose daughters were all beautiful but the youngest was so beautiful that the sun itself which has seen so much was astonished whenever it shone in her face"

functions

39func kp_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
40func kp_num(v: i64) -> i64
called by 2: kp_selftestmain calls 2: sys_writesys_mmap
50func kp_atoi(s: *u8) -> i64
called by 1: main
55func kp_seq(a: *u8, b: *u8) -> i64
called by 1: main
62func kp_words(text: *u8, wstart: *i64, wlen: *i64, wid: *i64) -> i64
called by 2: kp_selftestmain
84func kp_badness(r: i64) -> i64
97func kp_ratio(wid: *i64, i: i64, j: i64, target: i64, last: i64) -> i64
118func kp_optimal(wid: *i64, n: i64, target: i64, prev: *i64, best: *i64) -> i64
called by 2: kp_selftestmain calls 2: kp_ratiokp_badness
145func kp_greedy(wid: *i64, n: i64, target: i64, brk: *i64) -> i64
called by 2: kp_selftestmain calls 2: kp_ratiokp_badness
181func kp_backtrack(prev: *i64, n: i64, brk: *i64) -> i64
called by 2: kp_selftestmain calls 1: sys_mmap
195func kp_print_lines(text: *u8, wstart: *i64, wlen: *i64, brk: *i64, lines: i64) -> i64
called by 2: kp_selftestmain calls 2: kp_putssys_write
216func kp_worst(wid: *i64, n: i64, target: i64, brk: *i64, lines: i64) -> i64
called by 2: kp_selftestmain calls 2: kp_ratiokp_badness
236func kp_selftest() -> i64
324func main(argc: i64, argv: *i64) -> i64