Step 17b: Pretext — DOM-free text layout with otfm font measurement
Pure SX text layout library with one IO boundary (text-measure perform). Knuth-Plass optimal line breaking, Liang's hyphenation, position calculation. Library (lib/text-layout.sx): - break-lines: Knuth-Plass DP over word widths - break-lines-greedy: simple word-wrap for comparison - hyphenate-word: Liang's trie algorithm - position-line/position-lines: running x/y sums - measure-text: single perform (text-measure IO) Server font measurement (otfm): - Reads OpenType cmap + hmtx tables from .ttf files - DejaVu Serif/Sans bundled in shared/static/fonts/ - _cek_io_resolver hook: perform works inside aser/eval_expr - JIT VM suspension inline resolution for IO in compiled code ~font component (shared/sx/templates/font.sx): - Works like ~tw: emits @font-face CSS via cssx scope - Sets font-family on parent via spread - Deduplicates font declarations Infrastructure fixes: - stdin load command: per-expression error handling (was aborting on first error) - cek_run IO hook: _cek_io_resolver in sx_types.ml - JIT VmSuspended: inline IO resolution when resolver installed - ListRef handling in IO resolver (perform creates ListRef, not List) Demo page at /sx/(applications.(pretext)): - Hero: justified paragraph with otfm-measured proportional widths - Greedy vs Knuth-Plass side-by-side comparison - Badness scoring visualization - Hyphenation syllable decomposition 25 new tests (spec/tests/test-text-layout.sx), 3201/3201 passing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
BIN
shared/static/fonts/DejaVuSans.ttf
Normal file
BIN
shared/static/fonts/DejaVuSans.ttf
Normal file
Binary file not shown.
BIN
shared/static/fonts/DejaVuSerif.ttf
Normal file
BIN
shared/static/fonts/DejaVuSerif.ttf
Normal file
Binary file not shown.
41
shared/sx/templates/font.sx
Normal file
41
shared/sx/templates/font.sx
Normal file
@@ -0,0 +1,41 @@
|
||||
;; ~font — web font component
|
||||
;;
|
||||
;; Works like ~tw: emits @font-face CSS into the cssx scope,
|
||||
;; sets font-family on the parent element via spread.
|
||||
;;
|
||||
;; Usage:
|
||||
;; (div (~font :family "Pretext Serif" :src "/static/fonts/DejaVuSerif.ttf")
|
||||
;; "This text uses DejaVu Serif")
|
||||
;;
|
||||
;; (p (~font :family "Pretext Serif") ;; reuse already-declared font
|
||||
;; "No :src needed after first declaration")
|
||||
|
||||
;; Track which font families have already emitted @font-face rules
|
||||
(define *font-declared* (dict))
|
||||
|
||||
(defcomp
|
||||
~font
|
||||
(&key family src weight style format)
|
||||
(let
|
||||
((fam (or family "serif"))
|
||||
(wt (or weight "normal"))
|
||||
(st (or style "normal"))
|
||||
(fmt (or format "truetype")))
|
||||
(when
|
||||
(and src (not (has-key? *font-declared* fam)))
|
||||
(dict-set! *font-declared* fam true)
|
||||
(collect!
|
||||
"cssx"
|
||||
(str
|
||||
"@font-face{font-family:'"
|
||||
fam
|
||||
"';src:url('"
|
||||
src
|
||||
"') format('"
|
||||
fmt
|
||||
"');font-weight:"
|
||||
wt
|
||||
";font-style:"
|
||||
st
|
||||
";}")))
|
||||
(make-spread {:style (str "font-family:'" fam "',serif;")})))
|
||||
Reference in New Issue
Block a user