summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/mkiv
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2020-03-05 00:48:46 +0000
committerKarl Berry <karl@freefriends.org>2020-03-05 00:48:46 +0000
commitf210bce174e1f2f05305ab03e88e120a1cbfc4da (patch)
tree5c4e2ad096b5c745e859516ac3196fa0864292d5 /Master/texmf-dist/tex/context/base/mkiv
parent35fd641a3546acc0c62e0aa7f134888e36da30d4 (diff)
context (from cont-tmf.zip of Feb 17 16:00, size 116339406)
git-svn-id: svn://tug.org/texlive/trunk@54086 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkiv')
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/anch-bar.mkiv4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/anch-pgr.lua10
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/anch-pgr.mkiv6
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/anch-pos.lua217
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/anch-pos.mkiv10
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/anch-snc.lua25
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/attr-col.lua2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/attr-ini.lua12
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/attr-ini.mkiv78
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/attr-lay.lua1
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/back-exp.lua131
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/back-exp.mkiv7
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/back-ini.lua162
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/back-ini.mkiv133
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/back-ini.mkxl81
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/back-lua.lua354
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/back-lua.mkxl18
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/back-mps.lua205
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/back-mps.mkxl18
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/back-out.lua259
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/back-out.mkxl23
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/back-pdf.lua31
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/back-pdf.mkiv493
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/back-pdf.mkxl156
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/back-pdp.lua228
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/back-res.lua167
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/back-res.mkiv32
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/back-trf.lua164
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/back-trf.mkiv79
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/bibl-tra.lua4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/buff-imp-default.mkiv12
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/buff-imp-xml.lua8
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/buff-ini.lua48
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/buff-ini.mkiv11
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/buff-ver.lua3
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/buff-ver.mkiv218
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/buff-ver.mkxl1005
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/catc-sym.mkiv14
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/char-def.lua4010
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/char-emj.lua375
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/char-fio.lua6
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/char-ini.lua32
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/char-tex.lua1
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/chem-str.lua11
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/cldf-bas.lua32
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/cldf-ini.lua116
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/cldf-int.lua391
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/colo-ini.lua85
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/colo-ini.mkiv297
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/colo-ini.mkxl1407
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/cont-cs.mkxl21
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/cont-de.mkxl21
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/cont-en.mkxl21
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/cont-fil.mkiv269
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/cont-fr.mkxl21
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/cont-gb.mkxl21
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/cont-it.mkxl21
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/cont-log.mkiv75
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/cont-new.mkiv4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/cont-nl.mkxl21
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/cont-pe.mkxl22
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/cont-ro.mkxl21
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/cont-run.lua5
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/context-error.lmx2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/context-lmtx-error.pdfbin0 -> 4171 bytes
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/context-lmtx-error.tex8
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/context-todo.tex58
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/context.mkiv89
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/context.mkxl619
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/core-con.lua20
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/core-con.mkiv53
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/core-def.mkiv3
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/core-env.mkiv122
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/core-lmt.mkxl (renamed from Master/texmf-dist/tex/context/base/mkiv/core-lmt.mkiv)11
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/core-sys.lua4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/core-sys.mkiv12
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/core-uti.lua10
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/data-aux.lua18
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/data-bin.lua11
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/data-con.lua55
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/data-crl.lua2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/data-env.lua6
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/data-exp.lua8
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/data-fil.lua83
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/data-ini.lua4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/data-lst.lua37
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/data-lua.lua19
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/data-met.lua56
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/data-out.lua9
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/data-pre.lua22
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/data-res.lua647
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/data-sch.lua27
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/data-tex.lua64
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/data-tmp.lua318
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/data-tre.lua407
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/data-use.lua111
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/data-vir.lua40
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/data-zip.lua141
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/driv-ini.lua134
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/driv-ini.mkiv15
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/driv-ini.mkxl20
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/driv-shp.lua1328
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/driv-shp.mkxl18
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/export-example.css52
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/file-job.lua20
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/file-lib.lua41
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/file-mod.lua17
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-age.lua13
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-agl.lua15
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-aux.lua4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-cff.lua340
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-con.lua53
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-ctx.lua579
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-def.lua10
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-dsp.lua225
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-emp.mklx256
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-emp.mkvi33
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-enc.lua2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-fbk.lua3
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-fea.mkvi13
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-fil.mklx422
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-fil.mkvi20
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-imp-dimensions.lua43
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-imp-properties.lua1
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-imp-quality.lua188
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-imp-spacekerns.lua258
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-ini.lua4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-ini.mklx2563
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-ini.mkvi477
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-lib.mkvi41
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-mat.mklx500
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-mis.lua57
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-mps.lua41
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-nod.lua8
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-ocl.lua251
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-off.lua230
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-ogr.lua670
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-one.lua42
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-onr.lua5
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-osd.lua1015
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-ota.lua2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-otc.lua18
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-otj.lua6
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-otl.lua7
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-oto.lua19
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-otr.lua195
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-ots.lua127
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-ott.lua85
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-oup.lua46
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-pre.mkiv10
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-prv.lua6
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-run.mkiv2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-shp.lua150
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-sol.lua3
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-sty.mklx458
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-sty.mkvi11
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-sym.mklx245
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-sym.mkvi31
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-syn.lua12
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-tfm.lua504
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-tpk.lua1304
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-tra.mkiv2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/font-ttf.lua10
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/grph-bmp.lua96
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/grph-chk.lua277
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/grph-con.lua47
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/grph-fil.lua28
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/grph-img.lua738
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/grph-inc.lua124
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/grph-inc.mkiv109
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/grph-mem.lua168
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/grph-rul.lua257
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/grph-trf.mkiv58
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/hand-ini.mkiv7
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/hand-ini.mkxl111
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/java-ini.lua7
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/l-file.lua20
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/l-gzip.lua198
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/l-io.lua2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/l-lpeg.lua2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/l-lua.lua12
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/l-macro.lua2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/l-md5.lua28
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/l-os.lua15
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/l-pdfview.lua4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/l-sandbox.lua24
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/l-string.lua12
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/l-table.lua149
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/l-unicode.lua84
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lang-hyp.lua2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lang-ini.mkiv40
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lang-ini.mkxl730
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lang-lab.mkiv47
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lang-lab.mkxl390
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lang-rep.lua6
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lang-txt.lua143
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/libs-imp-curl.lua296
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/libs-imp-ghostscript.lua111
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/libs-imp-graphicsmagick.lua77
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/libs-imp-mujs.lua126
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/libs-imp-mujs.mkxl121
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/libs-imp-mysql.lua220
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/libs-imp-postgress.lua200
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/libs-imp-sqlite.lua187
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/libs-imp-zint.lua161
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/libs-imp-zint.mkxl64
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/libs-ini.lua196
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/libs-ini.mkxl31
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lpdf-ano.lua268
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lpdf-col.lua87
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lpdf-emb.lua2224
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lpdf-eng.lua96
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lpdf-epa.lua22
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lpdf-epd.lua1313
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lpdf-fld.lua91
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lpdf-fmt.lua172
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lpdf-fnt.lua2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lpdf-grp.lua11
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lpdf-img.lua1340
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lpdf-ini.lua128
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lpdf-lmt.lua2762
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lpdf-mis.lua25
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lpdf-nod.lua4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lpdf-pde.lua317
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lpdf-swf.lua6
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lpdf-tag.lua206
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lpdf-u3d.lua6
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lpdf-wid.lua350
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/luat-bwc.lua44
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/luat-cnf.lua59
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/luat-cod.lua29
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/luat-env.lua13
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/luat-fio.lua2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/luat-fmt.lua327
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/luat-ini.lua6
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/luat-ini.mkiv114
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/luat-lib.mkiv23
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/luat-mac.lua89
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/luat-run.lua88
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/luat-sto.lua2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lxml-css.lua145
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lxml-ini.lua2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lxml-ini.mkiv15
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lxml-lpt.lua45
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lxml-tab.lua34
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/lxml-tex.lua36
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/m-fonts-plugins.mkiv1
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/m-gnuplot.mkxl97
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/math-act.lua7
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/math-ali.mkiv88
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/math-ext.lua1
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/math-ini.lua2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/math-ini.mkiv30
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/math-noa.lua212
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/math-stc.mkvi159
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/math-tag.lua36
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/math-vfu.lua7
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/meta-blb.lua6
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/meta-fig.mkiv7
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/meta-fnt.lua4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/meta-imp-dum.mkiv131
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/meta-imp-gamesymbols.mkxl349
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/meta-imp-symbols.mkxl99
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/meta-imp-tab.mkiv6
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/meta-imp-threesix.mkxl253
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/meta-imp-txt.mkiv4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/meta-ini.mkiv109
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/meta-ini.mkxl1465
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/meta-mac.mkxl66
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/meta-pag.mkiv42
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/meta-pag.mkxl26
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/meta-pdf.lua9
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/meta-tex.mkiv86
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mlib-cnt.lua2021
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mlib-ctx.lua20
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mlib-ctx.mkiv66
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mlib-ctx.mkxl31
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mlib-int.lua387
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mlib-lmp.lua215
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mlib-lmt.lua63
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mlib-lua.lua663
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mlib-mat.lua137
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mlib-pdf.lua119
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mlib-pdf.mkiv41
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mlib-pdf.mkxl171
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mlib-pps.lua227
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mlib-run.lua570
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mlib-scn.lua777
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mlib-svg.lua3118
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mtx-context-copy.tex10
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mtx-context-listing.tex8
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mtx-context-markdown.tex92
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mult-aux.mkiv603
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mult-aux.mkxl1170
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mult-chk.mkiv2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mult-def.lua84
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mult-def.mkiv6
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mult-fun.lua28
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mult-ini.mkiv60
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mult-low.lua22
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mult-mes.lua4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mult-mps.lua11
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mult-prm.lua127
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mult-sys.mkiv55
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/node-aux.lua372
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/node-bck.lua2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/node-cmp.lua232
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/node-dir.lua146
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/node-fin.lua222
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/node-fnt.lua15
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/node-ini.lua319
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/node-ini.mkiv6
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/node-ltp.lua1840
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/node-met.lua246
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/node-mig.lua28
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/node-nut.lua349
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/node-par.lua2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/node-pro.lua5
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/node-ref.lua248
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/node-res.lua72
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/node-rul.lua111
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/node-rul.mkiv6
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/node-scn.lua2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/node-syn.lua29
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/node-tra.lua8
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/pack-bck.mkvi7
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/pack-box.mkiv16
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/pack-com.mkiv84
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/pack-lyr.mkiv85
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/pack-lyr.mkxl794
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/pack-mrl.mkiv64
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/pack-obj.mkiv20
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/pack-ori.lua70
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/pack-ori.mkxl88
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/pack-rul.lua2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/pack-rul.mkiv207
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/pack-rul.mkxl3089
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-box.mkvi4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-col.mkiv3
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-cst.lua39
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-cst.mkiv29
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-ffl.mkiv64
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-flt.lua45
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-flt.mkiv8
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-imp.mkiv29
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-ini.lua32
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-ini.mkiv33
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-inj.mkvi2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-lay.mkiv72
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-lin.lua2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-lin.mkvi37
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-mix.lua74
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-mix.mkiv29
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-mul.mkiv15
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-not.mkiv26
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-one.mkiv76
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-otr.mkvi4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-pcl.mkiv34
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-run.lua35
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-run.mkiv10
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-sid.mkiv38
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-str.lua98
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-txt.mklx969
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/page-txt.mkvi52
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/phys-dim.mkiv4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/publ-imp-apa.mkvi10
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/publ-imp-aps.mkvi6
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/publ-imp-chicago.lua560
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/publ-imp-chicago.mkvi1686
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/publ-imp-cite.mkvi6
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/publ-ini.lua80
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/publ-ini.mkiv5
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/publ-tra.lua2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/regi-ini.lua35
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/regi-ini.mkiv4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/scrn-bar.mkvi4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/scrn-but.mkvi4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/scrn-wid.lua2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/scrn-wid.mkvi5
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/scrp-ini.lua17
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/spac-ali.lua18
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/spac-ali.mkiv50
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/spac-chr.lua7
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/spac-flr.mkiv6
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/spac-hor.mkiv31
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/spac-par.mkiv2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/spac-prf.lua4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/spac-ver.lua120
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/spac-ver.mkiv229
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/spac-ver.mkxl2605
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/status-files.pdfbin26606 -> 26753 bytes
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/status-lua.pdfbin265935 -> 269549 bytes
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/strc-bkm.lua13
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/strc-blk.lua10
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/strc-con.mkvi3
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/strc-def.mkiv146
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/strc-doc.lua29
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/strc-flt.mkvi278
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/strc-itm.lua4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/strc-itm.mklx1882
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/strc-itm.mkvi196
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/strc-lnt.mkvi7
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/strc-lst.mkvi6
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/strc-mar.lua78
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/strc-not.mkvi24
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/strc-pag.lua37
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/strc-ref.lua49
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/strc-ref.mkvi20
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/strc-reg.lua154
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/strc-reg.mkiv104
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/strc-ren.mkiv24
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/strc-sec.mkiv84
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/strc-tag.lua8
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/strc-tag.mkiv16
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/strc-tnt.mkiv120
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/supp-box.lua223
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/supp-box.mkiv527
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/supp-box.mkxl2952
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/supp-mat.mkiv4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/supp-ran.lua22
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/symb-emj.lua1
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/symb-ini.lua7
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/syst-aux.lua57
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/syst-aux.mkiv1602
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/syst-aux.mkxl6587
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/syst-con.lua8
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/syst-con.mkiv105
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/syst-con.mkxl93
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/syst-ini.mkiv160
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/syst-ini.mkxl1111
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/syst-lua.lua242
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/syst-lua.mkiv122
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/syst-lua.mkxl100
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/syst-mes.mkiv6
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/tabl-frm.mkiv52
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/tabl-ltb.mkiv57
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/tabl-ntb.mkiv245
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/tabl-ntb.mkxl2202
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/tabl-tab.mkiv11
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/tabl-tbl.mkiv222
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/tabl-tbl.mkxl3022
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/tabl-tsp.mkiv4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/tabl-xtb.lua34
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/tabl-xtb.mkvi11
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/toks-ini.lua120
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/toks-scn.lua26
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/trac-ctx.lua14
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/trac-deb.lua290
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/trac-exp.lua2
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/trac-inf.lua127
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/trac-lmx.lua3
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/trac-log.lua81
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/trac-set.lua11
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/trac-tex.mkiv31
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/trac-vis.lua68
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/type-ini.lua11
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/type-ini.mklx618
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/type-ini.mkvi47
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/type-set.mkiv12
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-bld.lua67
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-brk.lua14
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-cap.lua8
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-chr.lua22
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-chr.mkiv4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-del.mkiv15
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-dha.lua3
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-drp.lua422
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-drp.mkiv20
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-dua.lua7
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-dub.lua5
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-duc.lua5
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-fln.lua72
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-fln.mkiv4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-inj.mkiv4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-itc.lua93
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-krn.lua13
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-lin.lua5
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-mar.lua17
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-ovl.lua24
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-pag.lua143
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-par.mkiv3
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-scr.mkiv24
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-sus.lua1
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-tal.lua23
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-tal.mkiv34
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/typo-wrp.lua4
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/util-deb.lua10
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/util-dim.lua14
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/util-jsn.lua486
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/util-lib.lua55
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/util-lua.lua14
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/util-pck.lua11
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/util-sac.lua85
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/util-sbx.lua81
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/util-sci.lua90
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/util-seq.lua14
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/util-sha.lua248
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/util-soc-imp-copas.lua10
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/util-sql-imp-ffi.lua5
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/util-sql-imp-sqlite.lua1
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/util-sql.lua49
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/util-sta.lua9
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/util-str.lua106
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/util-tab.lua257
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/util-tpl.lua68
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/util-zip.lua563
506 files changed, 86944 insertions, 15528 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkiv/anch-bar.mkiv b/Master/texmf-dist/tex/context/base/mkiv/anch-bar.mkiv
index f8581da325b..49e9e29461b 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/anch-bar.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/anch-bar.mkiv
@@ -102,7 +102,7 @@
\edef\m_level{\sidebarparameter\c!level}%
\ifx\m_level\empty
\ifnum\c_anch_sidebars_level=\plusone
- \ifdim\scratchdimen=\zeropoint
+ \ifzeropt\scratchdimen
\advance\d_anch_sidebars_distance\scratchdistance\relax
\else
\d_anch_sidebars_distance\scratchdimen
@@ -112,7 +112,7 @@
\fi
\else
\ifnum\m_level=\plusone
- \ifdim\scratchdimen=\zeropoint
+ \ifzeropt\scratchdimen
\advance\d_anch_sidebars_distance\scratchdistance\relax
\else
\d_anch_sidebars_distance\scratchdimen
diff --git a/Master/texmf-dist/tex/context/base/mkiv/anch-pgr.lua b/Master/texmf-dist/tex/context/base/mkiv/anch-pgr.lua
index 14afa3967ae..be9e28c08dc 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/anch-pgr.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/anch-pgr.lua
@@ -25,6 +25,8 @@ local jobpositions = job.positions
local formatters = string.formatters
local setmetatableindex = table.setmetatableindex
+local enableaction = nodes.tasks.enableaction
+
local commands = commands
local context = context
@@ -76,6 +78,7 @@ local getdepth = nuts.getdepth
local nodecodes = nodes.nodecodes
local localpar_code = nodecodes.localpar
+local start_of_par = nuts.start_of_par
local insert_before = nuts.insert_before
local insert_after = nuts.insert_after
@@ -85,6 +88,7 @@ local unsetvalue = attributes.unsetvalue
local jobpositions = job.positions
local getpos = jobpositions.getpos
+local getfree = jobpositions.getfree
local data = { }
local realpage = 1
@@ -161,7 +165,7 @@ local function flush(head,f,l,a,parent,depth)
ln = new_hlist(setlink(new_rule(65536,65536*4,0),new_kern(-65536),ln))
rn = new_hlist(setlink(new_rule(65536,0,65536*4),new_kern(-65536),rn))
end
- if getid(f) == localpar_code and getsubtype(f) == 0 then -- we need to clean this mess
+ if getid(f) == localpar_code and start_of_par(f) then -- we need to clean this mess
insert_after(head,f,ln)
else
head, f = insert_before(head,f,ln)
@@ -193,7 +197,7 @@ local function registerbackground(name)
}
texsetattribute(a_textbackground,n)
if not enabled then
- nodes.tasks.enableaction("contributers", "nodes.handlers.textbackgrounds")
+ enableaction("contributers", "nodes.handlers.textbackgrounds")
enabled = true
end
else
@@ -1130,7 +1134,7 @@ local function fetchmultipar(n,anchor,page)
local k = data.bpos.k
if k ~= 3 then
-- to be checked: no need in txt mode
- freemultipar(pagedata,jobpositions.free[page])
+ freemultipar(pagedata,getfree(page))
end
local nofmultipars = #pagedata
if trace_shapes then
diff --git a/Master/texmf-dist/tex/context/base/mkiv/anch-pgr.mkiv b/Master/texmf-dist/tex/context/base/mkiv/anch-pgr.mkiv
index 7fa378cd14f..f2195818ab8 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/anch-pgr.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/anch-pgr.mkiv
@@ -70,7 +70,7 @@
{\anch_positions_trace_action_yes
\the\everyinsertpositionaction
\the\everypositionaction
- \csname\??positionaction\currentpositionaction\endcsname
+ \begincsname\??positionaction\currentpositionaction\endcsname
\anch_positions_cleanup_action}%
\smashedbox\scratchbox % smashing is really needed else we get problems with too big overlays
\endgroup}
@@ -367,7 +367,7 @@
\obeyMPboxorigin % do we also set the size ? when needed this must be done in mp ... might change
\def\anch_positions_meta_graphic_direct{\anch_positions_meta_graphic_nested{#3}}% takes two extra arguments
\setbox\b_anch_positions_graphic\hbox % \hpack
- {\ignorespaces\csname#1#2\endcsname\removelastspace}%
+ {\ignorespaces\begincsname#1#2\endcsname\removelastspace}%
\smashbox\b_anch_positions_graphic
\box\b_anch_positions_graphic
\endgroup}
@@ -377,7 +377,7 @@
\setupMPvariables[#2][#1,#3]%
\edef\currentmpvariableclass{#2}%
\anch_positions_meta_graphic_prepare
- \csname\??positiongraphic#2\endcsname
+ \begincsname\??positiongraphic#2\endcsname
\endgroup}%
\def\startMPpositionmethod#1#2\stopMPpositionmethod
diff --git a/Master/texmf-dist/tex/context/base/mkiv/anch-pos.lua b/Master/texmf-dist/tex/context/base/mkiv/anch-pos.lua
index a0d2eee2c8e..2788c9d1a55 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/anch-pos.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/anch-pos.lua
@@ -24,10 +24,9 @@ more efficient.</p>
-- we need virtual table accessors as well as have tag/id accessors ... we don't
-- save much here (at least not now)
-local tostring, next, rawget, rawset, setmetatable, tonumber = tostring, next, rawget, rawset, setmetatable, tonumber
+local tostring, next, setmetatable, tonumber = tostring, next, setmetatable, tonumber
local sort = table.sort
local format, gmatch = string.format, string.gmatch
-local rawget = rawget
local lpegmatch = lpeg.match
local insert, remove = table.insert, table.remove
local allocate = utilities.storage.allocate
@@ -54,8 +53,6 @@ local texget = tex.get
local texsp = tex.sp
----- texsp = string.todimen -- because we cache this is much faster but no rounding
-local pdf = pdf -- h and v are variables
-
local setmetatableindex = table.setmetatableindex
local setmetatablenewindex = table.setmetatablenewindex
@@ -71,7 +68,7 @@ local getwhd = nuts.getwhd
local hlist_code = nodes.nodecodes.hlist
local find_tail = nuts.tail
-local hpack = nuts.hpack
+----- hpack = nuts.hpack
local new_latelua = nuts.pool.latelua
@@ -123,17 +120,17 @@ local f_region = formatters["region:%s"]
local f_tag_three = formatters["%s:%s:%s"]
local f_tag_two = formatters["%s:%s"]
-jobpositions.used = false
-
local nofregular = 0
local nofspecial = 0
local splitter = lpeg.splitat(":",true)
+local pagedata = { }
+local columndata = setmetatableindex("table") -- per page
+local freedata = setmetatableindex("table") -- per page
+
local function initializer()
tobesaved = jobpositions.tobesaved
collected = jobpositions.collected
- local pagedata = { }
- local freedata = setmetatableindex("table")
for tag, data in next, collected do
local prefix, rest = lpegmatch(splitter,tag)
if prefix == "p" then
@@ -145,6 +142,8 @@ local function initializer()
nofspecial = nofspecial + 1
local t = freedata[data.p or 0]
t[#t+1] = data
+ elseif prefix == "columnarea" then
+ columndata[data.p or 0][data.c or 0] = data
end
setmetatable(data,default)
end
@@ -173,101 +172,23 @@ local function initializer()
end
end
end
- jobpositions.page = pagedata
- jobpositions.free = freedata
- jobpositions.used = next(collected)
+ jobpositions.pagedata = pagedata
end
--- -- we can gain a little when we group positions but then we still have to
--- -- deal with regions and cells so we either end up with lots of extra small
--- -- tables pointing to them and/or assembling/disassembling so in the end
--- -- it makes no sense to do it (now) and still have such a mix
---
--- local splitter = lpeg.splitat(":",true)
---
--- local function setpos(t,k,v)
--- local class, tag = lpegmatch(splitter,k)
--- if tag then
--- local c = rawget(t,class)
--- if c then
--- c[tonumber(tag) or tag] = v
--- else
--- rawset(t,class,{ [tonumber(tag) or tag] = v })
--- end
--- else
--- t.default[tonumber(k) or k] = v
--- end
--- end
---
--- local function getpos(t,k)
--- local class, tag = lpegmatch(splitter,k)
--- if tag then
--- local c = rawget(t,class)
--- if c then
--- return c[tonumber(tag) or tag]
--- end
--- else
--- return c.default[tonumber(k) or k]
--- end
--- end
---
--- tobesaved.default = tobesaved.default or { }
--- setmetatablenewindex(tobesaved,setpos)
--- setmetatableindex (tobesaved,getpos)
---
--- local function initializer()
--- tobesaved = jobpositions.tobesaved
--- collected = jobpositions.collected
---
--- tobesaved.default = tobesaved.default or { }
--- collected.default = collected.default or { }
---
--- setmetatablenewindex(tobesaved,setpos)
--- setmetatableindex (collected,getpos)
--- setmetatableindex (tobesaved,getpos)
---
--- for class, list in next, collected do
--- for tag, data in next, list do
--- setmetatable(data,default)
--- nofregular = nofregular + 1
--- end
--- end
---
--- local pagedata = collected.page or { }
--- local freedata = setmetatableindex("table")
---
--- for tag, data in next, collected.free or { } do
--- local t = freedata[data.p or 0]
--- t[#t+1] = data
--- end
---
--- local pages = structures.pages.collected
--- if pages then
--- local last = nil
--- for p=1,#pages do
--- local data = pagedata[p]
--- local free = freedata[p]
--- if free then
--- sort(free,function(a,b) return b.y < a.y end) -- order matters !
--- end
--- if data then
--- last = data
--- last.free = free
--- elseif last then
--- local t = setmetatableindex({ free = free, p = p },last)
--- if not pagedata[p] then
--- pagedata[p] = t
--- end
--- end
--- end
--- end
--- jobpositions.page = pagedata
--- jobpositions.free = freedata
--- jobpositions.used = next(collected)
--- end
+function jobpositions.used()
+ return next(collected) -- we can safe it
+end
+
+function jobpositions.getfree(page)
+ return freedata[page]
+end
+
+-- we can gain a little when we group positions but then we still have to
+-- deal with regions and cells so we either end up with lots of extra small
+-- tables pointing to them and/or assembling/disassembling so in the end
+-- it makes no sense to do it (now) and still have such a mix
--
--- function jobpositions.getcollected(class,tag) if tag then return collected[class..tag] else return collected[class] end end
--- function jobpositions.gettobesaved(class,tag) if tag then return tobesaved[class..tag] else return tobesaved[class] end end
+-- proof of concept code removed ... see archive
local function finalizer()
-- We make the (possible extensive) shape lists sparse working
@@ -334,14 +255,18 @@ local getpos, gethpos, getvpos
function jobpositions.registerhandlers(t)
getpos = t and t.getpos or function() return 0, 0 end
- gethpos = t and t.gethpos or function() return 0 end
- getvpos = t and t.getvpos or function() return 0 end
+ getrpos = t and t.getrpos or function() return 0, 0, 0 end
+ gethpos = t and t.gethpos or function() return 0 end
+ getvpos = t and t.getvpos or function() return 0 end
end
function jobpositions.getpos () return getpos () end
+function jobpositions.getrpos() return getrpos() end
function jobpositions.gethpos() return gethpos() end
function jobpositions.getvpos() return getvpos() end
+-------- jobpositions.getcolumn() return column end
+
jobpositions.registerhandlers()
local function setall(name,p,x,y,w,h,d,extra)
@@ -401,7 +326,8 @@ end
-- use that one instead of a table (so, a 3rd / 4th argument: key, e.g. "x")
local function set(name,index,value) -- ,key
- local data = enhance(tobesaved[value or index])
+ -- officially there should have been a settobesaved
+ local data = enhance(value or {})
if value then
container = tobesaved[name]
if not container then
@@ -420,7 +346,7 @@ local function setspec(specification)
local name = specification.name
local index = specification.index
local value = specification.value
- local data = enhance(tobesaved[value or index])
+ local data = enhance(value or {})
if value then
container = tobesaved[name]
if not container then
@@ -553,7 +479,7 @@ jobpositions.e_region = e_region
local lastregion
-local function setregionbox(n,tag,k,lo,ro,to,bo) -- kind
+local function setregionbox(n,tag,k,lo,ro,to,bo,column) -- kind
if not tag or tag == "" then
nofregions = nofregions + 1
tag = f_region(nofregions)
@@ -572,6 +498,7 @@ local function setregionbox(n,tag,k,lo,ro,to,bo) -- kind
ro = ro ~= 0 and ro or nil,
to = to ~= 0 and to or nil,
bo = bo ~= 0 and bo or nil,
+ c = column or nil,
}
lastregion = tag
return tag, box
@@ -615,6 +542,13 @@ function jobpositions.gettobesaved(name,tag)
end
end
+function jobpositions.settobesaved(name,tag,data)
+ local t = tobesaved[name]
+ if t and tag and data then
+ t[tag] = data
+ end
+end
+
local nofparagraphs = 0
scanners.parpos = function()
@@ -803,12 +737,22 @@ function jobpositions.replace(id,p,x,y,w,h,d)
collected[id] = { p = p, x = x, y = y, w = w, h = h, d = d } -- c g
end
-function jobpositions.page(id)
+local function getpage(id)
local jpi = collected[id]
return jpi and jpi.p
end
-function jobpositions.region(id)
+local function getcolumn(id)
+ local jpi = collected[id]
+ return jpi and jpi.c or false
+end
+
+local function getparagraph(id)
+ local jpi = collected[id]
+ return jpi and jpi.n
+end
+
+local function getregion(id)
local jpi = collected[id]
if jpi then
local r = jpi.r
@@ -823,20 +767,15 @@ function jobpositions.region(id)
return false
end
-function jobpositions.column(id)
- local jpi = collected[id]
- return jpi and jpi.c or false
-end
-
-function jobpositions.paragraph(id)
- local jpi = collected[id]
- return jpi and jpi.n
-end
+jobpositions.page = getpage
+jobpositions.column = getcolumn
+jobpositions.paragraph = getparagraph
+jobpositions.region = getregion
-jobpositions.p = jobpositions.page
-jobpositions.r = jobpositions.region
-jobpositions.c = jobpositions.column
-jobpositions.n = jobpositions.paragraph
+jobpositions.p = getpage -- not used, kind of obsolete
+jobpositions.c = getcolumn -- idem
+jobpositions.n = getparagraph -- idem
+jobpositions.r = getregion -- idem
function jobpositions.x(id)
local jpi = collected[id]
@@ -1030,8 +969,24 @@ local function onsamepage(list,page)
return page
end
+local function columnofpos(realpage,xposition)
+ local p = columndata[realpage]
+ if p then
+ for i=1,#p do
+ local c = p[i]
+ local x = c.x or 0
+ local w = c.w or 0
+ if xposition >= x and xposition <= (x + w) then
+ return i
+ end
+ end
+ end
+ return 1
+end
+
jobpositions.overlapping = overlapping
jobpositions.onsamepage = onsamepage
+jobpositions.columnofpos = columnofpos
-- interface
@@ -1287,7 +1242,7 @@ scanners.MPposset = function() -- name (special helper, used in backgrounds)
local b = f_b_tag(name)
local e = f_e_tag(name)
local w = f_w_tag(name)
- local p = f_p_tag(jobpositions.n(b))
+ local p = f_p_tag(getparagraph(b))
MPpos(b) context(",") MPpos(e) context(",") MPpos(w) context(",") MPpos(p) context(",") MPpardata(p)
end
@@ -1387,6 +1342,10 @@ scanners.doifelsepositionsonthispage = function() -- list
doifelse(onsamepage(scanstring(),tostring(texgetcount("realpageno"))))
end
+-- scanners.columnofpos = function()
+-- context(columnofpos(scaninteger(),scandimen())
+-- end
+
scanners.doifelsepositionsused = function()
doifelse(next(collected))
end
@@ -1403,6 +1362,11 @@ scanners.markregionboxtagged = function() -- box tag
markregionbox(scaninteger(),scanstring())
end
+scanners.markregionboxtaggedn = function() -- box tag n
+ markregionbox(scaninteger(),scanstring(),nil,
+ nil,nil,nil,nil,nil,scaninteger())
+end
+
scanners.setregionboxtagged = function() -- box tag
setregionbox(scaninteger(),scanstring())
end
@@ -1441,3 +1405,12 @@ statistics.register("positions", function()
return nil
end
end)
+
+-- We support the low level positional commands too:
+
+local newsavepos = nodes.pool.savepos
+local implement = interfaces.implement
+
+implement { name = "savepos", actions = function() context(newsavepos()) end }
+implement { name = "lastxpos", actions = function() context(gethpos()) end }
+implement { name = "lastypos", actions = function() context(getvpos()) end }
diff --git a/Master/texmf-dist/tex/context/base/mkiv/anch-pos.mkiv b/Master/texmf-dist/tex/context/base/mkiv/anch-pos.mkiv
index fbebb5f173b..2762a53c65c 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/anch-pos.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/anch-pos.mkiv
@@ -279,9 +279,9 @@
% beware we need to pass \somethingexpanded or { }
-\unexpanded\def\anch_mark_column_box#1%
+\unexpanded\def\anch_mark_column_box#1#2% box n
{\global\advance\c_anch_column\plusone
- \clf_markregionboxtagged#1{columnarea:\the\c_anch_column}} % extra height
+ \clf_markregionboxtaggedn#1{columnarea:\the\c_anch_column}#2\relax} % extra height
\unexpanded\def\anch_mark_region_box
{\iftrialtypesetting
@@ -497,4 +497,10 @@
\let\doifpositionsusedelse\doifelsepositionsused
+%D Moved here:
+
+\unexpanded\def\savepos {\clf_savepos}
+\unexpanded\def\lastxpos{\numexpr\clf_lastxpos\relax}
+\unexpanded\def\lastypos{\numexpr\clf_lastypos\relax}
+
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/anch-snc.lua b/Master/texmf-dist/tex/context/base/mkiv/anch-snc.lua
index 8006f3bd674..ee13adca39d 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/anch-snc.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/anch-snc.lua
@@ -7,18 +7,14 @@ if not modules then modules = { } end modules ['anch-snc'] = {
}
-function mp.xxOverlayRegion()
- local r = tokens.getters.macro("m_overlay_region")
- mp.quoted('"'.. r .. '"')
--- mp.print('"'.. r .. '"')
-end
-
-- use factors as in mlib-int.lua
local tonumber, next, setmetatable = tonumber, next, setmetatable
local concat, sort, remove, copy = table.concat, table.sort, table.remove, table.copy
local match, find = string.match, string.find
-local lpegmatch = lpeg.match
+local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns
+
+local P, Cc = lpeg.P, lpeg.Cc
local setmetatableindex = table.setmetatableindex
@@ -28,11 +24,10 @@ local mpnumeric = mp.numeric
local mppoints = mp.points
local texgetdimen = tex.getdimen
-local p_number = lpeg.patterns.cardinal/tonumber
-local p_space = lpeg.patterns.whitespace^0
-local p_tag = lpeg.P("syncpos:") * p_number * lpeg.P(":") * p_number
-local p_option = p_number -- for now
- * ((lpeg.P(",") * p_space * lpeg.P("reset") * lpeg.Cc(true)) + lpeg.Cc(false))
+local p_number = patterns.cardinal/tonumber
+local p_space = patterns.whitespace^0
+local p_tag = P("syncpos:") * p_number * P(":") * p_number
+local p_option = p_number * ((P(",") * p_space * P("reset") * Cc(true)) + Cc(false)) -- for now
local list = { }
local colors = setmetatableindex("table")
@@ -269,3 +264,9 @@ function mp.sync_get_y() mpnumeric((list.page.y or 0)*factor) end
function mp.sync_get_w() mpnumeric((list.page.w or 0)*factor) end
function mp.sync_get_h() mpnumeric((list.page.h or 0)*factor) end
function mp.sync_get_d() mpnumeric((list.page.d or 0)*factor) end
+
+-- function mp.xxOverlayRegion()
+-- local r = tokens.getters.macro("m_overlay_region")
+-- mp.quoted('"'.. r .. '"')
+-- end
+
diff --git a/Master/texmf-dist/tex/context/base/mkiv/attr-col.lua b/Master/texmf-dist/tex/context/base/mkiv/attr-col.lua
index 5ea72c7e3b3..15590dccceb 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/attr-col.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/attr-col.lua
@@ -549,7 +549,7 @@ local function extender(transparencies,key)
end
local function reviver(data,n)
- if transparencies.supported then
+ if n and transparencies.supported then
local v = values[n]
local d
if not v then
diff --git a/Master/texmf-dist/tex/context/base/mkiv/attr-ini.lua b/Master/texmf-dist/tex/context/base/mkiv/attr-ini.lua
index dd971afc149..6145fa08d08 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/attr-ini.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/attr-ini.lua
@@ -7,6 +7,7 @@ if not modules then modules = { } end modules ['attr-ini'] = {
}
local next, type = next, type
+local osexit = os.exit
--[[ldx--
<p>We start with a registration system for atributes so that we can use the
@@ -34,6 +35,8 @@ attributes.states = attributes.states or { }
attributes.handlers = attributes.handlers or { }
attributes.unsetvalue = -0x7FFFFFFF
+local currentfont = font.current
+
local names = attributes.names
local numbers = attributes.numbers
local list = attributes.list
@@ -74,7 +77,7 @@ function attributes.private(name) -- at the lua end (hidden from user)
sharedstorage.attributes_last_private = last
else
report_attribute("no more room for private attributes")
- os.exit()
+ osexit()
end
number = last
numbers[name], names[number], list[number] = number, name, { }
@@ -91,7 +94,7 @@ function attributes.public(name) -- at the lua end (hidden from user)
sharedstorage.attributes_last_public = last
else
report_attribute("no more room for public attributes")
- os.exit()
+ osexit()
end
number = last
numbers[name], names[number], list[number] = number, name, { }
@@ -146,7 +149,7 @@ function attributes.save(name)
end
store[name] = {
attr = t,
- font = font.current(),
+ font = currentfont(),
}
end
@@ -163,7 +166,8 @@ function attributes.restore(name)
end
if font then
-- tex.font = font
- context.getvalue(fonts.hashes.csnames[font]) -- we don't have a direct way yet (will discuss it with taco)
+ -- context.getvalue(fonts.hashes.csnames[font])
+ currentfont(font)
end
end
-- store[name] = nil
diff --git a/Master/texmf-dist/tex/context/base/mkiv/attr-ini.mkiv b/Master/texmf-dist/tex/context/base/mkiv/attr-ini.mkiv
index 3792b1c6370..49a1126b9a6 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/attr-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/attr-ini.mkiv
@@ -57,31 +57,60 @@
\def\attr_basics_define {\attr_basics_define_indeed\s!public}
\def\attr_basics_define_system{\attr_basics_define_indeed\s!private}
- % here public means 'visible' so it's not to be confused with 'public' at the lua end
+% todo: define global !
+
+% here public means 'visible' so it's not to be confused with 'public' at the lua end
+
+% \def\attr_basics_define_indeed#1[#2][#3]%
+% {\ifcsname\??attributecount#2\endcsname\else
+% \scratchcounter\clf_defineattribute{#2}{#1}\relax
+% %\writestatus\m!system{defining #1 attribute #2 with number \number\scratchcounter}%
+% \expandafter\attributedef\csname\??attributecount#2\endcsname\scratchcounter
+% \expandafter\newconstant \csname\??attributeid#2\endcsname
+% \csname\??attributeid#2\endcsname\scratchcounter
+% % some attributes are always global
+% \doifelseinset\s!global{#3}%
+% {\etoksapp\t_attr_list_global{\csname\??attributecount#2\endcsname\attributeunsetvalue}}%
+% {\etoksapp\t_attr_list_local {\csname\??attributecount#2\endcsname\attributeunsetvalue}}%
+% \doifinset\s!nomath{#3}%
+% {\etoksapp\t_attr_list_nomath{\csname\??attributecount#2\endcsname\attributeunsetvalue}}%
+% \doifinset\s!public{#3}%
+% {\expandafter\let\csname#2\s!attribute\expandafter\endcsname\csname\??attributeid#2\endcsname}%
+% \doifinset\s!pickup{#3}%
+% {\expandafter\newconstant\csname\??attributepickup#2\endcsname
+% \csname\??attributepickup#2\endcsname\attributeunsetvalue
+% \etoksapp\t_attr_list_pickup{\csname\??attributecount#2\endcsname\csname\??attributepickup#2\endcsname}%
+% \ifcsname#2\s!attribute\endcsname
+% \expandafter\edef\csname\s!pickup#2\s!attribute\endcsname
+% {\csname\??attributepickup#2\endcsname\csname\??attributecount#2\endcsname}%
+% \expandafter\edef\csname\s!forget#2\s!attribute\endcsname
+% {\csname\??attributepickup#2\endcsname\attributeunsetvalue}%
+% \fi}%
+% \fi}
\def\attr_basics_define_indeed#1[#2][#3]%
{\ifcsname\??attributecount#2\endcsname\else
\scratchcounter\clf_defineattribute{#2}{#1}\relax
%\writestatus\m!system{defining #1 attribute #2 with number \number\scratchcounter}%
- \expandafter\attributedef\csname\??attributecount#2\endcsname\scratchcounter
- \expandafter\newconstant \csname\??attributeid#2\endcsname
- \csname\??attributeid#2\endcsname\scratchcounter
+ \global\expandafter\attributedef\csname\??attributecount#2\endcsname\scratchcounter
+ \global\expandafter\newconstant \csname\??attributeid#2\endcsname
+ \global\csname\??attributeid#2\endcsname\scratchcounter
% some attributes are always global
\doifelseinset\s!global{#3}%
- {\etoksapp\t_attr_list_global{\csname\??attributecount#2\endcsname\attributeunsetvalue}}%
- {\etoksapp\t_attr_list_local {\csname\??attributecount#2\endcsname\attributeunsetvalue}}%
+ {\xtoksapp\t_attr_list_global{\csname\??attributecount#2\endcsname\attributeunsetvalue}}%
+ {\xtoksapp\t_attr_list_local {\csname\??attributecount#2\endcsname\attributeunsetvalue}}%
\doifinset\s!nomath{#3}%
- {\etoksapp\t_attr_list_nomath{\csname\??attributecount#2\endcsname\attributeunsetvalue}}%
+ {\xtoksapp\t_attr_list_nomath{\csname\??attributecount#2\endcsname\attributeunsetvalue}}%
\doifinset\s!public{#3}%
- {\expandafter\let\csname#2\s!attribute\expandafter\endcsname\csname\??attributeid#2\endcsname}%
+ {\expandafter\glet\csname#2\s!attribute\expandafter\endcsname\csname\??attributeid#2\endcsname}%
\doifinset\s!pickup{#3}%
- {\expandafter\newconstant\csname\??attributepickup#2\endcsname
- \csname\??attributepickup#2\endcsname\attributeunsetvalue
- \etoksapp\t_attr_list_pickup{\csname\??attributecount#2\endcsname\csname\??attributepickup#2\endcsname}%
+ {\global\expandafter\newconstant\csname\??attributepickup#2\endcsname
+ \global\csname\??attributepickup#2\endcsname\attributeunsetvalue
+ \xtoksapp\t_attr_list_pickup{\csname\??attributecount#2\endcsname\csname\??attributepickup#2\endcsname}%
\ifcsname#2\s!attribute\endcsname
- \expandafter\edef\csname\s!pickup#2\s!attribute\endcsname
+ \expandafter\xdef\csname\s!pickup#2\s!attribute\endcsname
{\csname\??attributepickup#2\endcsname\csname\??attributecount#2\endcsname}%
- \expandafter\edef\csname\s!forget#2\s!attribute\endcsname
+ \expandafter\xdef\csname\s!forget#2\s!attribute\endcsname
{\csname\??attributepickup#2\endcsname\attributeunsetvalue}%
\fi}%
\fi}
@@ -95,9 +124,13 @@
% \unexpanded\def\pickupattributelater#1%
% {\csname\??attributepickup#1\endcsname\csname\??attributecount#1\endcsname}
+% \unexpanded\def\newattribute#1%
+% {\attr_basics_define_indeed\s!public[\csstring#1][]%
+% \expandafter\let\expandafter#1\csname\??attributeid\csstring#1\endcsname}
+
\unexpanded\def\newattribute#1%
{\attr_basics_define_indeed\s!public[\csstring#1][]%
- \expandafter\let\expandafter#1\csname\??attributeid\csstring#1\endcsname}
+ \expandafter\glet\expandafter#1\csname\??attributeid\csstring#1\endcsname}
% expandable so we can \edef them for speed
@@ -108,8 +141,13 @@
\let\dompattribute\gobbletwoarguments
-\unexpanded\def\resetglobalattributes{\the\t_attr_list_global\attribute\zerocount\zerocount}
-\unexpanded\def\resetlocalattributes {\the\t_attr_list_local \attribute\zerocount\zerocount}
+\ifcase\contextlmtxmode
+ \unexpanded\def\resetglobalattributes{\the\t_attr_list_global\attribute\zerocount\zerocount}
+ \unexpanded\def\resetlocalattributes {\the\t_attr_list_local \attribute\zerocount\zerocount}
+\else
+ \unexpanded\def\resetglobalattributes{\the\t_attr_list_global\glyphdatafield \zerocount}
+ \unexpanded\def\resetlocalattributes {\the\t_attr_list_local \glyphdatafield \zerocount}
+\fi
\let\resetallattributes\resetlocalattributes
@@ -147,12 +185,18 @@
\unexpanded\def\showattributes{\clf_showattributes}
+%D Todo:
+
+% \appendtoks
+% \clf_cleanupattributes
+% \to \everyafterpagebreak
+
\protect \endinput
% for the luatex list:
%
% \attributedef\zeroattribute=0
-% \attributedef\someatriubute=999
+% \attributedef\someattribute=999
%
% \directlua {
% local createtoken = newtoken.create
diff --git a/Master/texmf-dist/tex/context/base/mkiv/attr-lay.lua b/Master/texmf-dist/tex/context/base/mkiv/attr-lay.lua
index ff9d1c38fd3..28f6e92765c 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/attr-lay.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/attr-lay.lua
@@ -201,6 +201,7 @@ function viewerlayers.start(name)
else
texsetattribute(a_viewerlayer,a)
end
+ -- or macro
texsettokenlist("currentviewerlayertoks",name)
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/back-exp.lua b/Master/texmf-dist/tex/context/base/mkiv/back-exp.lua
index f5035d3cfab..00c939b999b 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/back-exp.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/back-exp.lua
@@ -34,7 +34,7 @@ if not modules then modules = { } end modules ['back-exp'] = {
-- check setting __i__
local next, type, tonumber = next, type, tonumber
-local sub, gsub = string.sub, string.gsub
+local sub, gsub, match = string.sub, string.gsub, string.match
local validstring = string.valid
local lpegmatch = lpeg.match
local utfchar, utfvalues, utflen = utf.char, utf.values, utf.len
@@ -46,7 +46,7 @@ local replacetemplate = utilities.templates.replace
local trace_export = false trackers.register ("export.trace", function(v) trace_export = v end)
local trace_spacing = false trackers.register ("export.trace.spacing", function(v) trace_spacing = v end)
-local trace_detail = false trackers.register ("export.trace.detail", function(v) trace_detail = v end)
+local trace_details = false trackers.register ("export.trace.details", function(v) trace_details = v end)
local less_state = false directives.register("export.lessstate", function(v) less_state = v end)
local show_comment = true directives.register("export.comment", function(v) show_comment = v end)
@@ -305,7 +305,7 @@ document,
%namespace%div.document {
font-size : %size% !important ;
max-width : %width% !important ;
- text-width : %align% !important ;
+ text-align : %align% !important ;
hyphens : %hyphens% !important ;
}]]
@@ -334,7 +334,7 @@ local styletemplate = [[
namespace = contextns,
-- cssnamespaceurl = usecssnamespace and cssnamespaceurl or cssnamespacenop,
cssnamespaceurl = cssnamespaceurl,
- }) }
+ },false,true) }
--
local bodyfont = finetuning.bodyfont
local width = finetuning.width
@@ -438,7 +438,7 @@ local imagetemplate = [[
namespace = contextns,
-- cssnamespaceurl = usecssnamespace and cssnamespaceurl or "",
cssnamespaceurl = cssnamespaceurl,
- }) }
+ },false,true) }
for element, details in sortedhash(usedimages) do
for detail, data in sortedhash(details) do
local name = data.name
@@ -1234,28 +1234,38 @@ do
local ndata = #data
local roottg = root.tg
if roottg == "msubsup" then
+ -- kind of tricky: we have a diufferent order in display mode
local nucleus, superscript, subscript
- for i=1,ndata do
- local di = data[i]
- if not di then
- -- weird
- elseif di.content then
- -- text
- elseif not nucleus then
- nucleus = i
- elseif not superscript then
- superscript = i
- elseif not subscript then
- subscript = i
- else
- -- error
+ if ndata > 3 then
+ -- error
+ else
+ for i=1,ndata do
+ local di = data[i]
+ if not di then
+ -- weird
+ elseif di.content then
+ -- text
+ else
+ local s = specifications[di.fulltag]
+ if s.subscript then
+ subscript = i
+ elseif s.superscript then
+ superscript = i
+ else
+ nucleus = i
+ end
+ end
+ end
+ if superscript or subscript then
+ -- we probably always have 3 anyway ... needs checking
+ local nuc = nucleus and data[nucleus]
+ local sub = subscript and data[subscript]
+ local sup = superscript and data[superscript]
+ local n = 0 -- play safe
+ if nuc then n = n + 1 ; data[n] = nuc end
+ if sub then n = n + 1 ; data[n] = sub end
+ if sup then n = n + 1 ; data[n] = sup end
end
- end
- if superscript and subscript then
- local sup, sub = data[superscript], data[subscript]
- data[superscript], data[subscript] = sub, sup
- -- sub.__o__, sup.__o__ = subscript, superscript
- sub.__i__, sup.__i__ = superscript, subscript
end
-- elseif roottg == "msup" or roottg == "msub" then
-- -- m$^2$
@@ -1982,6 +1992,10 @@ do
end
end
+ function structurestags.gettablecell(fulltag)
+ return tabledata[fulltag]
+ end
+
function extras.tablecell(di,element,n,fulltag)
local hash = tabledata[fulltag]
if hash then
@@ -2017,6 +2031,10 @@ do
end
end
+ function structurestags.gettabulatecell(fulltag)
+ return tabulatedata[fulltag]
+ end
+
function extras.tabulate(di,element,n,fulltag)
local data = di.data
for i=1,#data do
@@ -2086,6 +2104,29 @@ do
end
+do
+
+ local usedparagraphs = { }
+
+ function structurestags.setparagraph(align)
+ if align ~= "" then
+ usedparagraphs[locatedtag("paragraph")] = {
+ dataset = dataset,
+ tag = tag,
+ align = align,
+ }
+ end
+ end
+
+ function extras.paragraph(di,element,n,fulltag)
+ local hash = usedparagraphs[fulltag]
+ if hash then
+ setattribute(di,"align",hash.align)
+ end
+ end
+
+end
+
-- flusher
do
@@ -2659,16 +2700,16 @@ local function push(fulltag,depth)
end
local treedata = tree.data
local t = { -- maybe we can use the tag table
- tg = tg,
- fulltag = fulltag,
- detail = detail,
- n = n, -- already a number
- element = element,
- nature = nature,
- data = { },
- attribute = currentattribute,
- parnumber = currentparagraph,
- record = record, -- we can consider storing properties
+ tg = tg,
+ fulltag = fulltag,
+ detail = detail,
+ n = n, -- already a number
+ element = element,
+ nature = nature,
+ data = { },
+ attribute = currentattribute,
+ parnumber = currentparagraph,
+ record = record, -- we can consider storing properties
}
treedata[#treedata+1] = t
currentdepth = currentdepth + 1
@@ -2701,9 +2742,9 @@ local function pop()
currentdepth = currentdepth - 1
if trace_export then
if top then
- report_export("%w</%s>",currentdepth,tree.tg)
+ report_export("%w</%s>",currentdepth,match(top,"[^>]+"))
else
- report_export("</%s>",tree.tg)
+ report_export("</BAD>")
end
end
else
@@ -2906,6 +2947,8 @@ local collectresults do -- too many locals otherwise
local getkern = nuts.getkern
local getwidth = nuts.getwidth
+ local start_of_par = nuts.start_of_par
+
local nexthlist = nuts.traversers.hlist
local nextnode = nuts.traversers.node
@@ -2947,7 +2990,7 @@ local collectresults do -- too many locals otherwise
local maybewrong
local pid
for n, id, subtype in nextnode, head do
- if trace_detail then
+ if trace_details then
showdetail(n,id,subtype)
end
if id == glyph_code then
@@ -3280,7 +3323,7 @@ local collectresults do -- too many locals otherwise
last = nil
currentparagraph = nil
end
- elseif not localparagraph and id == localpar_code and subtype == 0 then
+ elseif not localparagraph and id == localpar_code and start_of_par(n) then
localparagraph = getattr(n,a_taggedpar)
end
p = n
@@ -3444,7 +3487,7 @@ local htmltemplate = [[
namespace = contextns,
-- cssnamespaceurl = usecssnamespace and cssnamespaceurl or "",
cssnamespaceurl = cssnamespaceurl,
- }) }
+ },false,true) }
for element, details in sortedhash(used) do
if namespaces[element] then
-- skip math
@@ -3921,7 +3964,7 @@ local htmltemplate = [[
end
- local examplefilename = resolvers.find_file("export-example.css")
+ local examplefilename = resolvers.findfile("export-example.css")
if examplefilename then
local data = io.loaddata(examplefilename)
if not data or data == "" then
@@ -4250,3 +4293,9 @@ implement {
actions = structurestags.setpublication,
arguments = "2 strings"
}
+
+implement {
+ name = "settagparagraph",
+ actions = structurestags.setparagraph,
+ arguments = "string"
+}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/back-exp.mkiv b/Master/texmf-dist/tex/context/base/mkiv/back-exp.mkiv
index 03dbe709a97..3e8469b145e 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/back-exp.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/back-exp.mkiv
@@ -262,6 +262,13 @@
\fi}%
\to \everyenableelements
+\appendtoks
+ \unexpanded\def\dotagparagraph#1%
+ {\iftrialtypesetting\else
+ \clf_settagparagraph{#1}\relax
+ \fi}%
+\to \everyenableelements
+
% The action: \setupbackend[export=yes] % or filename
% maybe xhtml css settings will move to setupexport
diff --git a/Master/texmf-dist/tex/context/base/mkiv/back-ini.lua b/Master/texmf-dist/tex/context/base/mkiv/back-ini.lua
index b7af1529b71..b0af61edcd8 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/back-ini.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/back-ini.lua
@@ -8,31 +8,21 @@ if not modules then modules = { } end modules ['back-ini'] = {
local next, type = next, type
local format = string.format
-local sind, cosd, abs = math.sind, math.cosd, math.abs
-local insert, remove = table.insert, table.remove
-local unpack = unpack
backends = backends or { }
local backends = backends
-local trace_backend = false trackers.register("backend.initializers", function(v) trace_finalizers = v end)
+local context = context
+local trace = false trackers.register("backend", function(v) trace = v end)
local report = logs.reporter("backend")
-local report_backend = logs.reporter("backend","initializing")
local allocate = utilities.storage.allocate
local setmetatableindex = table.setmetatableindex
local setaction = nodes.tasks.setaction
-local scanners = tokens.scanners
-local scannumber = scanners.number
-local scankeyword = scanners.keyword
-local scancount = scanners.count
-local scanstring = scanners.string
-
-local scanners = interfaces.scanners
-
local implement = interfaces.implement
+local variables = interfaces.variables
local texset = tex.set
@@ -76,7 +66,7 @@ local lmtx_mode = nil
local function lmtxmode()
if lmtx_mode == nil then
- lmtx_mode = ((tonumber(CONTEXTLMTXMODE) or 0) > 0) and drivers and drivers.lmtxversion
+ lmtx_mode = CONTEXTLMTXMODE > 0 and drivers and drivers.lmtxversion
end
return lmtx_mode
end
@@ -87,11 +77,11 @@ function backends.install(what)
if type(what) == "string" then
local backend = backends[what]
if backend then
- if trace_backend then
+ if trace then
if backend.comment then
- report_backend("initializing backend %a, %a",what,backend.comment)
+ report("initializing backend %a, %a",what,backend.comment)
else
- report_backend("initializing backend %a",what)
+ report("initializing backend %a",what)
end
end
backends.current = what
@@ -101,8 +91,8 @@ function backends.install(what)
setmetatableindex(plugin, default)
setmetatableindex(target, plugin)
end
- elseif trace_backend then
- report_backend("no backend named %a",what)
+ elseif trace then
+ report("no backend named %a",what)
end
end
end
@@ -139,7 +129,7 @@ interfaces.implement {
name = "setrealspaces",
arguments = "string",
actions = function(v)
- setaction("shipouts","nodes.handlers.accessibility",v == interfaces.variables.yes)
+ setaction("shipouts","nodes.handlers.accessibility",v == variables.yes)
end
}
@@ -192,125 +182,31 @@ implement {
end
}
--- could also be codeinjections
-
-function backends.noflatelua()
- return status.late_callbacks or 0
-end
-
---
-
-local stack = { }
-local restore = true -- false
-local nodepool = nodes.pool
-local savenode = nodepool.save
-local restorenode = nodepool.restore
-local setmatrixnode = nodepool.setmatrix
+local page_x_origin = 0
+local page_y_origin = 0
-updaters.register("backend.update",function()
- savenode = nodepool.save
- restorenode = nodepool.restore
- setmatrixnode = nodepool.setmatrix
-end)
-
-local function stopsomething()
- local top = remove(stack)
- if top == false then
- -- not wrapped
- elseif top == true then
- context(restorenode())
- elseif top then
- context(setmatrixnode(unpack(top))) -- not really needed anymore
- context(restorenode())
- else
- -- nesting error
- end
-end
-
-local function startrotation()
- local a = scannumber()
- if a == 0 then
- insert(stack,false)
- else
- local s, c = sind(a), cosd(a)
- if abs(s) < 0.000001 then
- s = 0 -- otherwise funny -0.00000
- end
- if abs(c) < 0.000001 then
- c = 0 -- otherwise funny -0.00000
- end
- context(savenode())
- context(setmatrixnode(c,s,-s,c))
- insert(stack,restore and { c, -s, s, c } or true)
- end
+function codeinjections.setpageorigin(x,y)
+ page_x_origin = x
+ page_y_origin = y
end
-implement { name = "startrotation", actions = startrotation }
-implement { name = "stoprotation", actions = stopsomething }
-
-local function startscaling() -- at the tex end we use sx and sy instead of rx and ry
- local rx, ry = 1, 1
- while true do
- if scankeyword("rx") then
- rx = scannumber()
- elseif scankeyword("ry") then
- ry = scannumber()
- -- elseif scankeyword("revert") then
- -- local top = stack[#stack]
- -- if top then
- -- rx = top[1]
- -- ry = top[4]
- -- else
- -- rx = 1
- -- ry = 1
- -- end
- else
- break
- end
- end
- if rx == 1 and ry == 1 then
- insert(stack,false)
- else
- if rx == 0 then
- rx = 0.0001
- end
- if ry == 0 then
- ry = 0.0001
- end
- context(savenode())
- context(setmatrixnode(rx,0,0,ry))
- insert(stack,restore and { 1/rx, 0, 0, 1/ry } or true)
- end
+function codeinjections.getpageorigin()
+ local x = page_x_origin
+ local y = page_y_origin
+ page_x_origin = 0
+ page_y_origin = 0
+ return x, y, (x ~= 0 or y ~= 0)
end
-implement { name = "startscaling", actions = startscaling }
-implement { name = "stopscaling", actions = stopsomething }
-
-local function startmatrix() -- rx sx sy ry -- tx, ty
- local rx, sx, sy, ry = 1, 0, 0, 1
- while true do
- if scankeyword("rx") then rx = scannumber()
- elseif scankeyword("ry") then ry = scannumber()
- elseif scankeyword("sx") then sx = scannumber()
- elseif scankeyword("sy") then sy = scannumber()
- else break end
- end
- if rx == 1 and sx == 0 and sy == 0 and ry == 1 then
- insert(stack,false)
- else
- context(savenode())
- context(setmatrixnode(rx,sx,sy,ry))
- insert(stack,store and { -rx, -sx, -sy, -ry } or true)
- end
-end
+implement {
+ name = "setpageorigin",
+ arguments = { "dimension", "dimension" },
+ actions = codeinjections.setpageorigin,
+}
-implement { name = "startmatrix", actions = startmatrix }
-implement { name = "stopmatrix", actions = stopsomething }
+-- could also be codeinjections
-local function startmirroring()
- context(setmatrixnode(-1,0,0,1))
+function backends.noflatelua()
+ return status.late_callbacks or 0
end
-
-implement { name = "startmirroring", actions = startmirroring }
-implement { name = "stopmirroring", actions = startmirroring } -- not: stopsomething
diff --git a/Master/texmf-dist/tex/context/base/mkiv/back-ini.mkiv b/Master/texmf-dist/tex/context/base/mkiv/back-ini.mkiv
index 8729403f848..43fe48ee0a9 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/back-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/back-ini.mkiv
@@ -11,35 +11,12 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-%D Most will go away here as it is replaced by \LUA\ calls to
-%D backend functions.
-
\writestatus{loading}{ConTeXt Backend Macros / Initialization}
-%D The exact page model depends on the backend so we just define some
-%D variables that are used. A helper at the \LUA\ end will synchronize
-%D with the internal variables. We store these in the format.
-
-% \newdimen\backendpageheight
-% \newdimen\backendpagewidth
-% \newdimen\backendinchoffset \backendinchoffset=1in
-
-%D Now we load the \LUA\ code:
-
\registerctxluafile{back-ini}{}
-\registerctxluafile{back-res}{}
-
-\doifelsefileexists{back-out.mkiv}{\loadmarkfile{back-out}}{}
-
-%D We currently have a curious mix between tex and lua backend handling but
-%D eventually most will move to \LUA.
\unprotect
-\ifdefined\everybackendshipout \else \newtoks\everybackendshipout \fi
-\ifdefined\everylastbackendshipout \else \newtoks\everylastbackendshipout \fi
-\ifdefined\everybackendlastinshipout \else \newtoks\everybackendlastinshipout \fi % e.g. finalize via latelua
-
%D Right from the start \CONTEXT\ had a backend system based on runtime pluggable
%D code. As most backend issues involved specials and since postprocessors had not
%D that much in common, we ended up with a system where we could switch backend as
@@ -52,104 +29,31 @@
%D At this moment \DVI\ is no longer used for advanced document output and we
%D therefore dropped support for this format. Future versions might support more
%D backends again, but this has a low priority.
-%D
-%D Not everything here makes sense and the content of this file will definitely
-%D change (or even go away).
-
-% rotation
-
-\unexpanded\def\dostartrotation#1%
- {\forcecolorhack
- \clf_startrotation#1\relax} % todo: implement without Q q
-
-\unexpanded\def\dostoprotation
- {\clf_stoprotation
- \forcecolorhack}
-
-% scaling
-
-\unexpanded\def\dostartscaling#1#2%
- {\forcecolorhack
- \clf_startscaling rx #1 ry #2\relax}
-
-\unexpanded\def\dostopscaling
- {\clf_stopscaling
- \forcecolorhack}
-
-% mirroring
-
-\unexpanded\def\dostartmirroring
- {\clf_startmirroring}
-
-\unexpanded\def\dostopmirroring
- {\clf_stopmirroring}
-
-% transform
-
-\unexpanded\def\dotransformnextbox#1#2#3#4#5#6%
- {\dowithnextbox{\dodotransformnextbox{#1}{#2}{#3}{#4}{#5}{#6}}}
-\unexpanded\def\dodotransformnextbox#1#2#3#4#5#6%
- {\hpack
- {\kern #5\onebasepoint
- \raise#6\onebasepoint
- \hpack
- {\clf_startmatrix rx #1 sx #2 sy #3 ry #4\relax
- \box\nextbox
- \clf_stopmatrix}}}
+\outputmode\plusone
+\let\outputmode\relax
+\newcount\outputmode
+\outputmode\plusone
+\let\normaloutputmode\outputmode
-%D \macros
-%D {back_ovalbox}
-%D
-%D When we look at the implementation, this is a complicated one. There are seven
-%D arguments.
-%D
-%D \starttyping
-%D \back_ovalbox {w} {h} {d} {linewidth} {radius} {stroke} {fill} {variant}
-%D \stoptyping
-%D
-%D This command has to return a \type {\vbox} which can be used to lay over another
-%D one (with text). The radius is in degrees, the stroke and fill are~\type {1}
-%D (true) of~\type {0} (false).
-
-\let\back_ovalbox \gobbleeightarguments
-
-%D \macros
-%D {dostartclipping,dostopclipping}
-%D
-%D Clipping is implemented in such a way that an arbitrary code can be fed.
-%D
-%D \starttyping
-%D \dostartclipping {pathname} {width} {height}
-%D \dostopclipping
-%D \stoptyping
+%D The exact page model depends on the backend so we just define some variables that
+%D are used. A helper at the \LUA\ end will synchronize with the internal variables.
+%D We store these in the format.
-\let \dostartclipping \gobblethreearguments
-\let \dostopclipping \donothing
-
-%D \macros
-%D {jobsuffix}
-%D
-%D By default, \TEX\ produces \DVI\ files which can be converted to other filetypes.
-%D Sometimes it is handy to know what the target file will be. In other driver
-%D modules we wil set \type {\jobsuffix} to \type {pdf}.
+\ifdefined\everybackendshipout \else \newtoks\everybackendshipout \fi
+\ifdefined\everylastbackendshipout \else \newtoks\everylastbackendshipout \fi
+\ifdefined\everybackendlastinshipout \else \newtoks\everybackendlastinshipout \fi
-%D Backend configuration:
+%D In \MKIV\ there is just one backend, \PDF, plus an additional export. We never
+%D came to seperate them, but \LMTX\ might do that.
\installcorenamespace{backend}
\installsetuponlycommandhandler \??backend {backend}
-\let\jobsuffix\empty
-
-\unexpanded\def\back_job_set_suffix#1% % checking could happen in mode
- {\ifx\jobsuffix\empty\else\resetsystemmode\jobsuffix\fi
- \edef\jobsuffix{#1}%
- \ifx\jobsuffix\empty\else\setsystemmode \jobsuffix\fi}
-
-\back_job_set_suffix{pdf} % default
-
-% \setupbackend[space=yes] % replace spacing in (pdf) file
+%D \starttyping
+%D \setupbackend[space=yes]
+%D \stoptyping
\appendtoks
\clf_setrealspaces{\backendparameter\c!space}%
@@ -161,8 +65,7 @@
\fi
\to \everysetupbackend
-%D For older styles:
-
-\let\setupoutput\gobbleoneoptional
+\unexpanded\def\setupoutput[#1]%
+ {\clf_enabledriver{#1}}
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/back-ini.mkxl b/Master/texmf-dist/tex/context/base/mkiv/back-ini.mkxl
new file mode 100644
index 00000000000..4e2fa351ef0
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/back-ini.mkxl
@@ -0,0 +1,81 @@
+%D \module
+%D [ file=back-ini,
+%D version=2009.04.15,
+%D title=\CONTEXT\ Backend Macros,
+%D subtitle=Initialization,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Backend Macros / Initialization}
+
+\registerctxluafile{back-ini}{}
+
+\unprotect
+
+%D Right from the start \CONTEXT\ had a backend system based on runtime pluggable
+%D code. As most backend issues involved specials and since postprocessors had not
+%D that much in common, we ended up with a system where we could switch backend as
+%D well as output code for multiple backends at the same time.
+%D
+%D Because \LUATEX\ has the backend built in, and since some backend issues have
+%D been moved to the frontend I decided to provide new backend code for \MKIV,
+%D starting with what was actually used.
+%D
+%D At this moment \DVI\ is no longer used for advanced document output and we
+%D therefore dropped support for this format. Future versions might support more
+%D backends again, but this has a low priority.
+
+%D The exact page model depends on the backend so we just define some variables that
+%D are used. A helper at the \LUA\ end will synchronize with the internal variables.
+%D We store these in the format.
+
+\ifdefined\everybackendshipout \else \newtoks\everybackendshipout \fi
+\ifdefined\everylastbackendshipout \else \newtoks\everylastbackendshipout \fi
+\ifdefined\everybackendlastinshipout \else \newtoks\everybackendlastinshipout \fi
+
+\installcorenamespace{backend}
+
+\installsetuponlycommandhandler \??backend {backend}
+
+%D \starttyping
+%D \setupbackend[space=yes]
+%D \stoptyping
+
+\appendtoks
+ \clf_setrealspaces{\backendparameter\c!space}%
+\to \everysetupbackend
+
+\appendtoks
+ \ifdefined\clf_resetmapfile
+ \clf_resetmapfile
+ \fi
+\to \everysetupbackend
+
+%D For the moment this is an experiment (defauls is pdf, but we also
+%D have lua, json and mps).
+%D
+%D \starttyping
+%D % \setupoutput[lua]
+%D % \setupoutput[json]
+%D % \setupoutput[mps]
+%D % \setupoutput[none] % for testing only
+%D % \setupoutput[empty] % for testing only
+%D
+%D \starttext
+%D \dorecurse{1000}{
+%D {\tf \red \samplefile{tufte}} \par
+%D {\bf \green \samplefile {ward}} \par
+%D {\sl \blue \samplefile{davis}} \par
+%D }
+%D \stoptext
+%D \stoptyping
+
+\unexpanded\def\setupoutput[#1]%
+ {\clf_enabledriver{#1}}
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/back-lua.lua b/Master/texmf-dist/tex/context/base/mkiv/back-lua.lua
new file mode 100644
index 00000000000..4e95d37e3fb
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/back-lua.lua
@@ -0,0 +1,354 @@
+if not modules then modules = { } end modules ['back-lua'] = {
+ version = 1.001,
+ comment = "companion to lpdf-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- we can remap fonts
+
+local fontproperties = fonts.hashes.properties
+local fontparameters = fonts.hashes.parameters
+local fontshapes = fonts.hashes.shapes
+
+local starttiming = statistics.starttiming
+local stoptiming = statistics.stoptiming
+
+local bpfactor = number.dimenfactors.bp
+local texgetbox = tex.getbox
+
+local rulecodes = nodes.rulecodes
+local normalrule_code = rulecodes.normal
+----- boxrule_code = rulecodes.box
+----- imagerule_code = rulecodes.image
+----- emptyrule_code = rulecodes.empty
+----- userrule_code = rulecodes.user
+----- overrule_code = rulecodes.over
+----- underrule_code = rulecodes.under
+----- fractionrule_code = rulecodes.fraction
+----- radicalrule_code = rulecodes.radical
+local outlinerule_code = rulecodes.outline
+
+-- todo : per instance
+
+local pages = { }
+local fonts = { }
+local names = { }
+local mapping = { }
+local used = { }
+local shapes = { }
+local glyphs = { }
+local buffer = { }
+local b = 0
+local converter = nil
+
+local compact = false -- true
+local shapestoo = true
+
+local x, y, d, f, c, w, h, t, r, o
+
+local function reset()
+ buffer = { }
+ b = 0
+ t = nil
+ x = nil
+ y = nil
+ d = nil
+ f = nil
+ c = nil
+ w = nil
+ h = nil
+ r = nil
+ o = nil
+end
+
+local function result()
+ -- todo: we're now still in the pdf backend but need different codeinjections
+ local codeinjections = backends.pdf.codeinjections
+ local getvariable = codeinjections.getidentityvariable or function() end
+ local jobname = environment.jobname or tex.jobname or "unknown"
+ return {
+ metadata = {
+ unit = "bp",
+ jobname = jobname,
+ title = getvariable("title") or jobname,
+ subject = getvariable("subject"),
+ author = getvariable("author"),
+ keywords = getvariable("keywords"),
+ time = os.date("%Y-%m-%d %H:%M"),
+ engine = environment.luatexengine .. " " .. environment.luatexversion,
+ context = environment.version,
+ },
+ fonts = fonts,
+ pages = pages,
+ shapes = shapes,
+ }
+end
+
+-- actions
+
+local function outputfilename(driver)
+ return tex.jobname .. "-output.lua"
+end
+
+local function save() -- might become a driver function that already is plugged into stopactions
+ local filename = outputfilename()
+ drivers.report("saving result in %a",filename)
+ starttiming(drivers)
+ local data = result()
+ if data then
+ io.savedata(filename,table.serialize(data))
+ end
+ stoptiming(drivers)
+end
+
+local function prepare(driver)
+ converter = drivers.converters.lmtx
+ luatex.registerstopactions(1,function()
+ save()
+ end)
+end
+
+local function initialize(driver,details)
+ reset()
+end
+
+local function finalize(driver,details)
+ local n = details.pagenumber
+ local b = details.boundingbox
+ pages[n] = {
+ number = n,
+ content = buffer,
+ boundingbox = {
+ b[1] * bpfactor,
+ b[2] * bpfactor,
+ b[3] * bpfactor,
+ b[4] * bpfactor,
+ },
+ }
+end
+
+local function wrapup(driver)
+end
+
+local function cleanup(driver)
+ reset()
+end
+
+local function convert(driver,boxnumber,pagenumber)
+ converter(driver,texgetbox(boxnumber),"page",pagenumber)
+end
+
+-- flushers
+
+local function updatefontstate(id)
+ if not mapping[id] then
+ local fn = #fonts + 1
+ mapping[id] = fn
+ local properties = fontproperties[id]
+ local parameters = fontparameters[id]
+ local filename = file.basename(properties.filename)
+ local fontname = properties.fullname or properties.fontname
+ if shapestoo then
+ if not names[fontname] then
+ local sn = #shapes+1
+ names[fontname] = sn
+ shapes[sn] = { }
+ glyphs[sn] = fontshapes[id].glyphs
+ end
+ end
+ fonts[fn] = {
+ filename = filename,
+ name = fontname,
+ size = parameters.size * bpfactor,
+ shapes = shapestoo and names[fontname] or nil,
+ }
+ end
+end
+
+local function flushcharacter(current, pos_h, pos_v, pos_r, font, char)
+ local fnt = mapping[font]
+ b = b + 1
+ buffer[b] = {
+ t = "glyph" ~= t and "glyph" or nil,
+ f = font ~= f and fnt or nil,
+ c = char ~= c and char or nil,
+ x = pos_h ~= x and (pos_h * bpfactor) or nil,
+ y = pos_v ~= y and (pos_v * bpfactor) or nil,
+ d = pos_r ~= d and (pos_r == 1 and "r2l" or "l2r") or nil,
+ }
+ t = "glyph"
+ f = font
+ c = char
+ x = pos_h
+ y = pos_v
+ d = pos_r
+ if shapestoo then
+ -- can be sped up if needed
+ local sn = fonts[fnt].shapes
+ local shp = shapes[sn]
+ if not shp[char] then
+ shp[char] = glyphs[sn][char]
+ end
+ end
+end
+
+local function rule(pos_h, pos_v, pos_r, size_h, size_v, rule_s, rule_o)
+ b = b + 1
+ buffer[b] = {
+ t = "rule" ~= t and "rule" or nil,
+ r = rule_s ~= r and rule_s or nil,
+ o = rule_s == "outline" and rule_o ~= o and (rule_o * bpfactor) or nil,
+ w = size_h ~= w and (size_h * bpfactor) or nil,
+ h = size_v ~= h and (size_v * bpfactor) or nil,
+ x = pos_h ~= x and (pos_h * bpfactor) or nil,
+ y = pos_v ~= y and (pos_v * bpfactor) or nil,
+ d = pos_r ~= d and (pos_r == 1 and "r2l" or "l2r") or nil,
+ }
+ t = "rule"
+ w = size_h
+ h = size_v
+ x = pos_h
+ y = pos_v
+ d = pos_r
+end
+
+local function flushrule(current, pos_h, pos_v, pos_r, size_h, size_v, subtype)
+ local rule_s, rule_o
+ if subtype == normalrule_code then
+ rule_s = "normal"
+ elseif subtype == outlinerule_code then
+ rule_s = "outline"
+ rule_o = getdata(current)
+ else
+ return
+ end
+ return rule(pos_h, pos_v, pos_r, size_h, size_v, rule_s, rule_o)
+end
+
+local function flushsimplerule(current, pos_h, pos_v, pos_r, size_h, size_v)
+ return rule(pos_h, pos_v, pos_r, size_h, size_v, "normal", nil)
+end
+
+-- file stuff too
+-- todo: default flushers
+-- also color (via hash)
+
+-- installer
+
+drivers.install {
+ name = "lua",
+ actions = {
+ prepare = prepare,
+ initialize = initialize,
+ finalize = finalize,
+ wrapup = wrapup,
+ cleanup = cleanup,
+ convert = convert,
+ outputfilename = outputfilename,
+ },
+ flushers = {
+ updatefontstate = updatefontstate,
+ character = flushcharacter,
+ rule = flushrule,
+ }
+}
+
+-- actions
+
+local function outputfilename(driver)
+ return tex.jobname .. "-output.json"
+end
+
+local function save() -- might become a driver function that already is plugged into stopactions
+ local filename = outputfilename()
+ drivers.report("saving result in %a",filename)
+ starttiming(drivers)
+ local data = result()
+ if data then
+ if not utilities.json then
+ require("util-jsn")
+ end
+ io.savedata(filename,utilities.json.tostring(data,not compact))
+ end
+ stoptiming(drivers)
+end
+
+local function prepare(driver)
+ converter = drivers.converters.lmtx
+ luatex.registerstopactions(1,function()
+ save()
+ end)
+end
+
+-- installer
+
+drivers.install {
+ name = "json",
+ actions = {
+ prepare = prepare,
+ initialize = initialize,
+ finalize = finalize,
+ wrapup = wrapup,
+ cleanup = cleanup,
+ convert = convert,
+ outputfilename = outputfilename,
+ },
+ flushers = {
+ updatefontstate = updatefontstate,
+ character = flushcharacter,
+ rule = flushrule,
+ }
+}
+
+-- actions
+
+local function outputfilename(driver)
+ return tex.jobname .. "-output.js"
+end
+
+local function save() -- might become a driver function that already is plugged into stopactions
+ local filename = outputfilename()
+ drivers.report("saving result in %a",filename)
+ starttiming(drivers)
+ local data = result()
+ if data then
+ if not utilities.json then
+ require("util-jsn")
+ end
+ io.savedata(filename,
+ "const JSON_CONTEXT = JSON.parse ( `" ..
+ utilities.json.tostring(data,not compact) ..
+ "` ) ;\n"
+ )
+ end
+ stoptiming(drivers)
+end
+
+local function prepare(driver)
+ converter = drivers.converters.lmtx
+ luatex.registerstopactions(1,function()
+ save()
+ end)
+end
+
+-- installer
+
+drivers.install {
+ name = "js",
+ actions = {
+ prepare = prepare,
+ initialize = initialize,
+ finalize = finalize,
+ wrapup = wrapup,
+ cleanup = cleanup,
+ convert = convert,
+ outputfilename = outputfilename,
+ },
+ flushers = {
+ updatefontstate = updatefontstate,
+ character = flushcharacter,
+ rule = flushrule,
+ }
+}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/back-lua.mkxl b/Master/texmf-dist/tex/context/base/mkiv/back-lua.mkxl
new file mode 100644
index 00000000000..82ba8f9f196
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/back-lua.mkxl
@@ -0,0 +1,18 @@
+%D \module
+%D [ file=back-lua,
+%D version=2018.07.26,
+%D title=\CONTEXT\ Backend Macros,
+%D subtitle=\LUA,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\ifcase\contextlmtxmode \else
+ \registerctxluafile{back-lua}{optimize}
+\fi
+
+\endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/back-mps.lua b/Master/texmf-dist/tex/context/base/mkiv/back-mps.lua
new file mode 100644
index 00000000000..96c850ed63e
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/back-mps.lua
@@ -0,0 +1,205 @@
+if not modules then modules = { } end modules ['back-mps'] = {
+ version = 1.001,
+ comment = "companion to lpdf-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local fontproperties = fonts.hashes.properties
+local fontparameters = fonts.hashes.parameters
+
+local starttiming = statistics.starttiming
+local stoptiming = statistics.stoptiming
+
+local bpfactor = number.dimenfactors.bp
+local texgetbox = tex.getbox
+local formatters = string.formatters
+
+local rulecodes = nodes.rulecodes
+local normalrule_code = rulecodes.normal
+----- boxrule_code = rulecodes.box
+----- imagerule_code = rulecodes.image
+----- emptyrule_code = rulecodes.empty
+----- userrule_code = rulecodes.user
+----- overrule_code = rulecodes.over
+----- underrule_code = rulecodes.under
+----- fractionrule_code = rulecodes.fraction
+----- radicalrule_code = rulecodes.radical
+local outlinerule_code = rulecodes.outline
+
+local fonts = { }
+local pages = { }
+local buffer = { }
+local b = 0
+local converter = nil
+
+local function reset()
+ buffer = { }
+ b = 0
+end
+
+local f_font = formatters[ "\\definefont[%s][file:%s*none @ %sbp]\n" ]
+
+local f_glyph = formatters[ [[draw textext.drt("\%s\char%i\relax") shifted (%N,%N);]] ]
+local f_rule = formatters[ [[fill unitsquare xscaled %N yscaled %N shifted (%N,%N);]] ]
+local f_outline = formatters[ [[draw unitsquare xscaled %N yscaled %N shifted (%N,%N);]] ]
+
+-- actions
+
+local function outputfilename(driver)
+ return tex.jobname .. "-output.tex"
+end
+
+local function save() -- might become a driver function that already is plugged into stopactions
+ starttiming(drivers)
+ if #pages > 0 then
+ local filename = outputfilename()
+ drivers.report("saving result in %a",filename)
+ reset()
+ b = b + 1
+ buffer[b] = "\\starttext\n"
+ for k, v in table.sortedhash(fonts) do
+ b = b + 1
+ buffer[b] = f_font(v.name,v.filename,v.size)
+ end
+ for i=1,#pages do
+ b = b + 1
+ buffer[b] = pages[i]
+ end
+ b = b + 1
+ buffer[b] = "\\stoptext\n"
+ io.savedata(filename,table.concat(buffer,"",1,b))
+ end
+ stoptiming(drivers)
+end
+
+local function prepare(driver)
+ converter = drivers.converters.lmtx
+ luatex.registerstopactions(1,function()
+ save()
+ end)
+end
+
+local function initialize(driver,details)
+ reset()
+ b = b + 1
+ buffer[b] = "\n\\startMPpage"
+end
+
+local function finalize(driver,details)
+ b = b + 1
+ buffer[b] = "\\stopMPpage\n"
+ pages[details.pagenumber] = table.concat(buffer,"\n",1,b)
+end
+
+local function wrapup(driver)
+end
+
+local function cleanup(driver)
+ reset()
+end
+
+local function convert(driver,boxnumber,pagenumber)
+ converter(driver,texgetbox(boxnumber),"page",pagenumber)
+end
+
+-- flushers
+
+local last
+
+local function updatefontstate(id)
+ if fonts[id] then
+ last = fonts[id].name
+ else
+ last = "MPSfont" .. converters.Characters(id)
+ fonts[id] = {
+ filename = file.basename(fontproperties[id].filename),
+ size = fontparameters[id].size * bpfactor,
+ name = last,
+ }
+ end
+end
+
+local function flushcharacter(current, pos_h, pos_v, pod_r, font, char)
+ b = b + 1
+ buffer[b] = f_glyph(last,char,pos_h*bpfactor,pos_v*bpfactor)
+end
+
+local function flushrule(current, pos_h, pos_v, pod_r, size_h, size_v, subtype)
+ if subtype == normalrule_code then
+ b = b + 1
+ buffer[b] = f_rule(size_h*bpfactor,size_v*bpfactor,pos_h*bpfactor,pos_v*bpfactor)
+ elseif subtype == outlinerule_code then
+ b = b + 1
+ buffer[b] = f_outline(size_h*bpfactor,size_v*bpfactor,pos_h*bpfactor,pos_v*bpfactor)
+ end
+end
+
+local function flushsimplerule(current, pos_h, pos_v, pod_r, size_h, size_v)
+ b = b + 1
+ buffer[b] = f_rule(size_h*bpfactor,size_v*bpfactor,pos_h*bpfactor,pos_v*bpfactor)
+end
+
+-- installer
+
+drivers.install {
+ name = "mps",
+ actions = {
+ prepare = prepare,
+ initialize = initialize,
+ finalize = finalize,
+ wrapup = wrapup,
+ cleanup = cleanup,
+ convert = convert,
+ outputfilename = outputfilename,
+ },
+ flushers = {
+ updatefontstate = updatefontstate,
+ character = flushcharacter,
+ rule = flushrule,
+ simplerule = flushsimplerule,
+ }
+}
+
+-- extras
+
+-- if not mp then
+-- return
+-- end
+--
+-- local mpprint = mp.print
+-- local formatters = string.formatters
+--
+-- local f_glyph = formatters[ [[draw textext.drt("\setfontid%i\relax\char%i\relax") shifted (%N,%N);]] ]
+-- local f_rule = formatters[ [[fill unitsquare xscaled %N yscaled %N shifted (%N,%N);]] ]
+--
+-- local current = nil
+-- local size = 0
+--
+-- function mp.place_buffermake(box)
+-- drivers.convert("mps",box)
+-- current = drivers.action("mps","fetch")
+-- size = #current
+-- end
+--
+-- function mp.place_buffersize()
+-- mpprint(size)
+-- end
+--
+-- function mp.place_bufferslot(i)
+-- if i > 0 and i <= size then
+-- local b = buffer[i]
+-- local t = b[1]
+-- if t == "glyph" then
+-- mpprint(f_glyph(b[2],b[3],b[4]*bpfactor,b[5]*bpfactor))
+-- elseif t == "rule" then
+-- mpprint(f_rule(b[2]*bpfactor,b[3]*bpfactor,b[4]*bpfactor,b[5]*bpfactor))
+-- end
+-- end
+-- end
+--
+-- function mp.place_bufferwipe()
+-- current = nil
+-- size = 0
+-- end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/back-mps.mkxl b/Master/texmf-dist/tex/context/base/mkiv/back-mps.mkxl
new file mode 100644
index 00000000000..0a6640614aa
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/back-mps.mkxl
@@ -0,0 +1,18 @@
+%D \module
+%D [ file=back-mps,
+%D version=2018.07.26,
+%D title=\CONTEXT\ Backend Macros,
+%D subtitle=\METAPOST,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\ifcase\contextlmtxmode \else
+ \registerctxluafile{back-mps}{optimize}
+\fi
+
+\endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/back-out.lua b/Master/texmf-dist/tex/context/base/mkiv/back-out.lua
new file mode 100644
index 00000000000..5ea5aa048ac
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/back-out.lua
@@ -0,0 +1,259 @@
+if not modules then modules = { } end modules ['back-out'] = {
+ version = 1.001,
+ comment = "companion to back-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local type = type
+local loadstring = loadstring
+
+local context = context
+
+-- tokens.scanners.....
+
+local get = token.get_index
+local scaninteger = token.scan_int
+local scanstring = token.scan_string
+local scankeyword = token.scan_keyword
+local scantokenlist = token.scan_tokenlist
+----- scancode = token.scan_code
+
+local tokentostring = token.to_string
+
+local logwriter = logs.writer
+local openfile = io.open
+local flushio = io.flush
+
+local nuts = nodes.nuts
+local tonode = nuts.tonode
+local copynode = nuts.copy
+local nodepool = nuts.pool
+
+local getdata = nuts.getdata
+
+local whatsit_code = nodes.nodecodes.whatsit
+
+local whatsitcodes = nodes.whatsitcodes
+
+local literalvalues = nodes.literalvalues
+local originliteral_code = literalvalues.origin
+local pageliteral_code = literalvalues.page
+local directliteral_code = literalvalues.direct
+local rawliteral_code = literalvalues.raw
+
+local nodeproperties = nodes.properties.data
+
+local channels = { }
+
+local register = nodepool.register
+local newnut = nuts.new
+
+local opennode = register(newnut(whatsit_code,whatsitcodes.open))
+local writenode = register(newnut(whatsit_code,whatsitcodes.write))
+local closenode = register(newnut(whatsit_code,whatsitcodes.close))
+local lateluanode = register(newnut(whatsit_code,whatsitcodes.latelua))
+local literalnode = register(newnut(whatsit_code,whatsitcodes.literal))
+local savenode = register(newnut(whatsit_code,whatsitcodes.save))
+local restorenode = register(newnut(whatsit_code,whatsitcodes.restore))
+local setmatrixnode = register(newnut(whatsit_code,whatsitcodes.setmatrix))
+
+local tomatrix = drivers.helpers.tomatrix
+
+local immediately = false -- not watertight
+
+local open_command, write_command, close_command
+
+backends = backends or { }
+
+local function openout()
+ local channel = scaninteger()
+ scankeyword("=") -- hack
+ local filename = scanstring()
+ if not immediately then
+ local n = copynode(opennode)
+ nodeproperties[n] = { channel = channel, filename = filename } -- action = "open"
+ return context(tonode(n))
+ elseif not channels[channel] then
+ local handle = openfile(filename,"wb") or false
+ if handle then
+ channels[channel] = handle
+ else
+ -- error
+ end
+ end
+ immediately = false
+end
+
+function backends.openout(n)
+ local p = nodeproperties[n]
+ if p then
+ local handle = openfile(p.filename,"wb") or false
+ if handle then
+ channels[p.channel] = handle
+ else
+ -- error
+ end
+ end
+end
+
+local function write()
+ local channel = scaninteger()
+ if not immediately then
+ local t = scantokenlist()
+ local n = copynode(writenode)
+ nodeproperties[n] = { channel = channel, data = t } -- action = "write"
+ return context(tonode(n))
+ else
+ local content = scanstring()
+ local handle = channels[channel]
+ if handle then
+ handle:write(content,"\n")
+ else
+ logwriter(content,"\n")
+ end
+ end
+ immediately = false
+end
+
+function backends.writeout(n)
+ local p = nodeproperties[n]
+ if p then
+ local handle = channels[p.channel]
+ local content = tokentostring(p.data)
+ if handle then
+ handle:write(content,"\n")
+ else
+ logwriter(content,"\n")
+ end
+ end
+end
+
+local function closeout()
+ local channel = scaninteger()
+ if not immediately then
+ local n = copynode(closenode)
+ nodeproperties[n] = { channel = channel } -- action = "close"
+ return context(tonode(n))
+ else
+ local handle = channels[channel]
+ if handle then
+ handle:close()
+ channels[channel] = false
+ flushio()
+ else
+ -- error
+ end
+ end
+ immediately = false
+end
+
+function backends.closeout(n)
+ local p = nodeproperties[n]
+ if p then
+ local channel = p.channel
+ local handle = channels[channel]
+ if handle then
+ handle:close()
+ channels[channel] = false
+ flushio()
+ else
+ -- error
+ end
+ end
+end
+
+local function immediate()
+ immediately = true
+end
+
+local noflatelua = 0
+
+local function latelua()
+ local node = copynode(lateluanode)
+ local name = "latelua"
+ if scankeyword("name") then
+ name = scanstring()
+ end
+ local data = scantokenlist()
+ nodeproperties[node] = { name = name, data = data }
+ return context(tonode(node))
+end
+
+function backends.latelua(current,pos_h,pos_v) -- todo: pass pos_h and pos_v (more efficient in lmtx)
+ local p = nodeproperties[current]
+ if p then
+ data = p.data
+ else
+ data = getdata(current)
+ end
+ noflatelua = noflatelua + 1
+ local kind = type(data)
+ if kind == "table" then
+ data.action(data.specification or data)
+ elseif kind == "function" then
+ data()
+ else
+ if kind ~= "string" then
+ data = tokentostring(data)
+ end
+ if #data ~= "" then
+ local code = loadstring(data)
+ if code then
+ code()
+ end
+ end
+ end
+end
+
+function backends.noflatelua()
+ return noflatelua
+end
+
+function nodepool.originliteral(str) local t = copynode(literalnode) nodeproperties[t] = { data = str, mode = originliteral_code } return t end
+function nodepool.pageliteral (str) local t = copynode(literalnode) nodeproperties[t] = { data = str, mode = pageliteral_code } return t end
+function nodepool.directliteral(str) local t = copynode(literalnode) nodeproperties[t] = { data = str, mode = directliteral_code } return t end
+function nodepool.rawliteral (str) local t = copynode(literalnode) nodeproperties[t] = { data = str, mode = rawliteral_code } return t end
+
+local pdfliterals = {
+ [originliteral_code] = originliteral_code, [literalvalues[originliteral_code]] = originliteral_code,
+ [pageliteral_code] = pageliteral_code, [literalvalues[pageliteral_code]] = pageliteral_code,
+ [directliteral_code] = directliteral_code, [literalvalues[directliteral_code]] = directliteral_code,
+ [rawliteral_code] = rawliteral_code, [literalvalues[rawliteral_code]] = rawliteral_code,
+}
+
+function nodepool.literal(mode,str)
+ local t = copynode(literalnode)
+ if str then
+ nodeproperties[t] = { data = str, mode = pdfliterals[mode] or pageliteral_code }
+ else
+ nodeproperties[t] = { data = mode, mode = pageliteral_code }
+ end
+ return t
+end
+
+function nodepool.save()
+ return copynode(savenode)
+end
+
+function nodepool.restore()
+ return copynode(restorenode)
+end
+
+function nodepool.setmatrix(rx,sx,sy,ry,tx,ty)
+ local t = copynode(setmatrixnode)
+ nodeproperties[t] = { matrix = tomatrix(rx,sx,sy,ry,tx,ty) }
+ return t
+end
+
+interfaces.implement { name = "immediate", actions = immediate, public = true, protected = true }
+interfaces.implement { name = "openout", actions = openout, public = true, protected = true }
+interfaces.implement { name = "write", actions = write, public = true, protected = true }
+interfaces.implement { name = "closeout", actions = closeout, public = true, protected = true }
+interfaces.implement { name = "latelua", actions = latelua, public = true, protected = true }
+interfaces.implement { name = "special", actions = scanstring, public = true, protected = true }
+
+open_command = get(token.create("openout"))
+write_command = get(token.create("write"))
+close_command = get(token.create("closeout"))
diff --git a/Master/texmf-dist/tex/context/base/mkiv/back-out.mkxl b/Master/texmf-dist/tex/context/base/mkiv/back-out.mkxl
new file mode 100644
index 00000000000..26548a0a496
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/back-out.mkxl
@@ -0,0 +1,23 @@
+%D \module
+%D [ file=back-out,
+%D version=2019.02.08,
+%D title=\CONTEXT\ Backend Macros,
+%D subtitle=Output,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\registerctxluafile{back-out}{}
+
+\let\normalimmediate\immediate
+\let\normalopenout \openout
+\let\normalwrite \write
+\let\normalcloseout \closeout
+\let\normallatelua \latelua
+\let\normalspecial \special
+
+\endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/back-pdf.lua b/Master/texmf-dist/tex/context/base/mkiv/back-pdf.lua
index 8886967e0c5..5f845fdcd97 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/back-pdf.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/back-pdf.lua
@@ -10,17 +10,38 @@ if not modules then modules = { } end modules ['back-pdf'] = {
-- the way we manage resources, info, etc. Users should use the \type {lpdf}
-- interface instead. If needed I will provide replacement functionality.
+local setmetatableindex = table.setmetatableindex
+
interfaces.implement {
name = "setpdfcompression",
arguments = { "integer", "integer" },
actions = lpdf.setcompression,
}
-if CONTEXTLMTXMODE == 0 then
- updaters.apply("backend.update.pdf")
- updaters.apply("backend.update.lpdf")
- updaters.apply("backend.update.tex")
- updaters.apply("backend.update")
+do
+
+ local dummy = function() end
+ local report = logs.reporter("backend")
+
+ local function unavailable(t,k)
+ report("calling unavailable pdf.%s function",k)
+ t[k] = dummy
+ return dummy
+ end
+
+ updaters.register("backend.update",function()
+ --
+ -- For now we keep this for tikz. If really needed some more can be made
+ -- accessible but it has to happen in a controlled way then, for instance
+ -- by first loading or enabling some compatibility layer so that we can
+ -- trace possible interferences.
+ --
+ pdf = {
+ immediateobj = pdf.immediateobj
+ }
+ setmetatableindex(pdf,unavailable)
+ end)
+
end
backends.install("pdf")
diff --git a/Master/texmf-dist/tex/context/base/mkiv/back-pdf.mkiv b/Master/texmf-dist/tex/context/base/mkiv/back-pdf.mkiv
index 9e88ab19399..ec1c641e690 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/back-pdf.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/back-pdf.mkiv
@@ -11,12 +11,15 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-%D The less there is here, the better.
+%D The less there is here, the better. After a decade it is time to remove the \type
+%D {\pdf*} ones completely. For the moment I keep them commented but even that will
+%D go away.
\writestatus{loading}{ConTeXt Backend Macros / PDF}
\registerctxluafile{lpdf-ini}{optimize}
\registerctxluafile{lpdf-nod}{}
+\registerctxluafile{lpdf-eng}{optimize}
\registerctxluafile{lpdf-col}{}
\registerctxluafile{lpdf-xmp}{}
\registerctxluafile{lpdf-ano}{}
@@ -32,21 +35,10 @@
\registerctxluafile{lpdf-tag}{}
\registerctxluafile{lpdf-fmt}{}
\registerctxluafile{lpdf-pde}{}
-
-\ifcase\contextlmtxmode\else
- \registerctxluafile{lpdf-img}{optimize}
-\fi
-
\registerctxluafile{lpdf-epa}{}
-
-\ifcase\contextlmtxmode\else
- \registerctxluafile{lpdf-emb}{optimize}
-\fi
-
-\registerctxluafile{back-pdp}{}
-
\registerctxluafile{lpdf-fnt}{}
+\registerctxluafile{back-pdp}{}
\registerctxluafile{back-pdf}{} % some code will move to lpdf-*
\loadmarkfile{back-u3d} % this will become a module
@@ -57,184 +49,51 @@
%D We will minimize the number of calls to \PDF\ specific primitives and delegate
%D all management and injection of code to the backend.
%D
-%D Here we initialize some internal quantities. We also protect them.
-
-\ifdefined\outputmode
- \outputmode\plusone
- \let\outputmode\relax
- \newcount\outputmode
- \outputmode\plusone
- \let\normaloutputmode\outputmode
-\fi
-
%D Because we do a lot in \LUA\ and don't want interferences, we nil most of the
%D \PDFTEX\ primitives. Of course one can always use the \type {\pdfvariable},
%D \type {\pdfextension} and \type {\pdffeedback} primitives but it will probably
%D have bad side effects.
-%D For the moment we put these here as they are pdf related but they might move to
-%D a better place. We overload the primitives with our own but use a bit of indirection
-%D for the purpose of tracing.
-
-\unexpanded\def\saveboxresource {\clf_saveboxresource}
-\unexpanded\def\lastsavedboxresourceindex {\numexpr\clf_lastsavedboxresourceindex\relax}
-\unexpanded\def\useboxresource {\clf_useboxresource}
-
-\unexpanded\def\saveimageresource {\clf_saveimageresource}
-\unexpanded\def\lastsavedimageresourceindex{\numexpr\clf_lastsavedimageresourceindex\relax}
-\unexpanded\def\lastsavedimageresourcepages{\numexpr\clf_lastsavedimageresourcepages\relax}
-\unexpanded\def\useimageresource {\clf_useimageresource}
-
-\unexpanded\def\savepos {\clf_savepos}
- \def\lastxpos {\clf_lastxpos}
- \def\lastypos {\clf_lastypos}
-
-\unexpanded\def\pdfextension {\clf_pdfextension}
- \def\pdffeedback {\clf_pdffeedback}
-
-%D These are no-ops and don't even intercept what comes next. Maybe some day
-%D I'll write a parser that maps onto \CONTEXT.
-
-\unexpanded\def\unsupportedpdfprimitive#1%
- {\writestatus{fatal error}{the primitive \string#1\space is not supported}%
- \directlua{os.exit()}}
-
-\unexpanded\def\pdfcolorstack {\unsupportedpdfprimitive\pdfcolorstack}
-\unexpanded\def\pdfcolorstackinit{\unsupportedpdfprimitive\pdfcolorstackinit}
-% pdfannot
-\unexpanded\def\pdfstartlink {\unsupportedpdfprimitive\pdfstartlink}
-\unexpanded\def\pdfendlink {\unsupportedpdfprimitive\pdfendlink}
-\unexpanded\def\pdfoutline {\unsupportedpdfprimitive\pdfoutline}
-% pdfdest
-\unexpanded\def\pdfthread {\unsupportedpdfprimitive\pdfthread}
-\unexpanded\def\pdfstartthread {\unsupportedpdfprimitive\pdfstartthread}
-\unexpanded\def\pdfendthread {\unsupportedpdfprimitive\pdfendthread}
-\unexpanded\def\pdffontattr {\unsupportedpdfprimitive\pdffontattr}
-\unexpanded\def\pdfglyphtounicode{\unsupportedpdfprimitive\pdfglyphtounicode}
-
-\unexpanded\def\pdfannot {\clf_pdfannot}
-\unexpanded\def\pdfdest {\clf_pdfdest}
-
-%D Here we do intercept (silently) what gets passed. One should use the \CONTEXT\
-%D interfaces instead.
-
-\let\pdfcatalog \relax \newtoks\pdfcatalog
-\let\pdfinfo \relax \newtoks\pdfinfo
-\let\pdfnames \relax \newtoks\pdfnames
-\let\pdftrailer \relax \newtoks\pdftrailer
-\let\pdfpageresources \relax \newtoks\pdfpageresources
-\let\pdfpageattr \relax \newtoks\pdfpageattr
-\let\pdfpagesattr \relax \newtoks\pdfpagesattr
-\let\pdfxformattr \relax \newtoks\pdfxformattr
-\let\pdfxformresources\relax \newtoks\pdfxformresources
-
-%D We use the \LUA\ interface (which then permits more control over possible pdf/x
-%D extensions).
-
-\let\pdfcompresslevel \relax \newcount\pdfcompresslevel
-\let\pdfobjcompresslevel\relax \newcount\pdfobjcompresslevel
-
-%D But we still provide:
+\unexpanded\def\pdfextension{\clf_pdfextension}
+ \def\pdffeedback {\clf_pdffeedback}
+
+%D For the moment we keep this for tikz but hopefully it will at some point use
+%D the proper ones. Consider them obsolete:
+
+\unexpanded\def\pdfliteral {\clf_pdfliteral}
+\unexpanded\def\pdfobj {\clf_pdfobj}%
+\unexpanded\def\pdflastobj {\numexpr\clf_pdflastobj\relax}
+\unexpanded\def\pdfrefobj {\clf_pdfrefobj }
+
+\unexpanded\def\pdfrestore {\clf_restore}
+\unexpanded\def\pdfsave {\clf_save}
+\unexpanded\def\pdfsetmatrix{\clf_setmatrix}
+
+ \let\pdfxform \saveboxresource
+ \let\pdflastxform \lastsavedboxresourceindex
+ \let\pdfrefxform \useboxresource
+
+%D Here are quick and dirty compression flippers, mostly used when testing something
+%D as one can best stick to the defaults that also adapt to specific standards.
\unexpanded\def\nopdfcompression {\clf_setpdfcompression\zerocount\zerocount}
\unexpanded\def\onlypdfobjectcompression{\clf_setpdfcompression\zerocount\plusthree}
\unexpanded\def\maximumpdfcompression {\clf_setpdfcompression\plusnine \plusnine }
\unexpanded\def\normalpdfcompression {\clf_setpdfcompression\plusthree\plusthree}
-%D These might even become no-ops as we don't need them in \CONTEXT:
-
-\unexpanded\def\pdfmapfile#1{} % obsolete
-\unexpanded\def\pdfmapline#1{} % obsolete
-
-%D We don't support these directives, at least not this way. If they are needed
-%D by third party modules we can provide some interface.
-
-%pdfcreationdate
-\let\pdfdecimaldigits \relax \newcount\pdfdecimaldigits
-\let\pdfdestmargin \relax \newdimen\pdfdestmargin
-% pdffontname
-% pdffontobjnum
-\let\pdffontsize \relax \newcount\pdffontsize
-\let\pdfgamma \relax \newcount\pdfgamma
-\let\pdfgentounicode \relax \newcount\pdfgentounicode
-\let\pdfhorigin \relax \newcount\pdfhorigin
-\let\pdfignoreunknownimages \relax \newcount\pdfignoreunknownimages
-\let\pdfimageaddfilename \relax \newcount\pdfimageaddfilename
-\let\pdfimageapplygamma \relax \newcount\pdfimageapplygamma
-\let\pdfimagegamma \relax \newcount\pdfimagegamma
-\let\pdfimagehicolor \relax \newcount\pdfimagehicolor
-\let\pdfimageresolution \relax \newcount\pdfimageresolution
-\let\pdfincludechars \relax \newtoks \pdfincludechars
-\let\pdfinclusioncopyfonts \relax \newcount\pdfinclusioncopyfonts
-\let\pdfinclusionerrorlevel \relax \newcount\pdfinclusionerrorlevel
-\let\pdfinfoomitdate \relax \newcount\pdfinfoomitdate
-% pdflastannot
-% pdflastlink
-\let\pdflinkmargin \relax \newdimen\pdflinkmargin
-\let\pdfmajorversion \relax \newcount\pdfmajorversion
-\let\pdfminorversion \relax \newcount\pdfminorversion
-\let\pdfpagebox \relax \newcount\pdfpagebox
-% pdfpageref
-\let\pdfpkfixeddpi \relax \newcount\pdfpkfixeddpi
-\let\pdfpkmode \relax \newtoks \pdfpkmode
-\let\pdfpkresolution \relax \newcount\pdfpkresolution
-% pdfretval
-\let\pdfsuppressoptionalinfo \relax \newcount\pdfsuppressoptionalinfo
-\let\pdfsuppressptexinfo \relax \newcount\pdfsuppressptexinfo
-% pdftexrevision
-% pdftexversion
-\let\pdfthreadmargin \relax \newdimen\pdfthreadmargin
-\let\pdftrailerid \relax \newtoks \pdftrailerid
-\let\pdfuniqueresname \relax \newcount\pdfuniqueresname
-\let\pdfvorigin \relax \newcount\pdfvorigin
-\let\pdfxformmargin \relax \newdimen\pdfxformmargin
-% \pdfxformname
-
-%D These are still accepted but are normally not needed.
-
-\let\pdfxform \saveboxresource
-\let\pdfximage \saveimageresource
-
-\let\pdflastxform \lastsavedboxresourceindex
-\let\pdflastximage \lastsavedimageresourceindex
-
-\let\pdfrefxform \useboxresource
-\let\pdfrefximage \useimageresource
-
-\let\pdflastximagepages \lastsavedimageresourcepages
-
-\let\pdfsavepos \savepos
-\let\pdflastxpos \lastxpos
-\let\pdflastypos \lastypos
-
-%D For the moment we keep these as they are but they will become \LUA\ calls
-%D eventually, after which we will nil the three \type {\pdf} interface primitives.
-
-\normalprotected\def\pdfliteral {\clf_pdfliteral}%
-
-\normalprotected\def\pdfobj {\clf_pdfobj}%
-\normalprotected\def\pdflastobj {\numexpr\clf_pdflastobj\relax}%
-
-\normalprotected\def\pdfrefobj {\pdfextension refobj }
-\normalprotected\def\pdfrestore {\clf_restore}
-\normalprotected\def\pdfsave {\clf_save}
-\normalprotected\def\pdfsetmatrix{\clf_setmatrix}
-
-%D This one can be consulted by users although the suffix is also a system mode.
-
-\back_job_set_suffix{pdf}
-
%D PDF/X (maybe combine the two lua calls)
\setupbackend
[xmpfile=]
\appendtoks
- \doifsomething{\backendparameter{xmpfile}}
- {\clf_setxmpfile{\backendparameter{xmpfile}}}%
+ \edef\p_file{\backendparameter{xmpfile}}%
+ \ifx\p_file\empty\else
+ \clf_setxmpfile{\p_file}%
+ \fi
\to \everysetupbackend
-% \doifsomething{\backendparameter\c!format} .. at the lua end
+%D This will change:
\appendtoks
\clf_setformat
@@ -247,281 +106,35 @@
\relax
\to \everysetupbackend
-%D For the moment we keep these.
+%D These are the only official methods to add stuff to the resources. If more is
+%D needed for third party low level code, it can be added.
-%newtoks \pdfbackendeveryximage
-\newtoks \pdfbackendeveryxform
+\unexpanded\def\pdfbackendsetcatalog #1#2{\clf_lpdf_addtocatalog{#1}{#2}}
+\unexpanded\def\pdfbackendsetinfo #1#2{\clf_lpdf_addtoinfo{#1}{#2}}
+\unexpanded\def\pdfbackendsetname #1#2{\clf_lpdf_addtonames{#1}{#2}}
-%D These are the only official methods to add stuff to the resources.
+\unexpanded\def\pdfbackendsetpageattribute #1#2{\clf_lpdf_addtopageattributes{#1}{#2}}
+\unexpanded\def\pdfbackendsetpagesattribute#1#2{\clf_lpdf_addtopagesattributes{#1}{#2}}
+\unexpanded\def\pdfbackendsetpageresource #1#2{\clf_lpdf_addtopageresources{#1}{#2}}
-\unexpanded\def\pdfbackendsetcatalog #1#2{\clf_lpdf_addtocatalog {#1}{#2}}
-\unexpanded\def\pdfbackendsetinfo #1#2{\clf_lpdf_addtoinfo {#1}{#2}}
-\unexpanded\def\pdfbackendsetname #1#2{\clf_lpdf_addtonames {#1}{#2}}
-
-\unexpanded\def\pdfbackendsetpageattribute #1#2{\clf_lpdf_addtopageattributes {#1}{#2}}
-\unexpanded\def\pdfbackendsetpagesattribute#1#2{\clf_lpdf_addtopagesattributes {#1}{#2}}
-\unexpanded\def\pdfbackendsetpageresource #1#2{\clf_lpdf_addtopageresources {#1}{#2}}
-
-\unexpanded\def\pdfbackendsetextgstate #1#2{\clf_lpdf_adddocumentextgstate {#1}{#2}}
+\unexpanded\def\pdfbackendsetextgstate #1#2{\clf_lpdf_adddocumentextgstate{#1}{#2}}
\unexpanded\def\pdfbackendsetcolorspace #1#2{\clf_lpdf_adddocumentcolorspace{#1}{#2}}
-\unexpanded\def\pdfbackendsetpattern #1#2{\clf_lpdf_adddocumentpattern {#1}{#2}}
-\unexpanded\def\pdfbackendsetshade #1#2{\clf_lpdf_adddocumentshade {#1}{#2}}
+\unexpanded\def\pdfbackendsetpattern #1#2{\clf_lpdf_adddocumentpattern{#1}{#2}}
+\unexpanded\def\pdfbackendsetshade #1#2{\clf_lpdf_adddocumentshade{#1}{#2}}
\def\pdfbackendcurrentresources {\clf_lpdf_collectedresources}
\def\pdfcolor #1{\clf_lpdf_color\numexpr\thecolorattribute{#1}\relax}
- \let\PDFcolor\pdfcolor
-
-% clipping
-\unexpanded\def\dostartclipping#1#2#3% we can move this to lua and only set a box here
- {\forcecolorhack
- \edef\width {\tobigpoints#2}%
- \edef\height{\tobigpoints#3}%
- \meta_grab_clip_path{#1}\width\height{%
- 0 0 m %
- \width\space 0 l %
- \width\space \height\space l %
- 0 \height\space l%
- }%
- \pdfliteral{q 0 w \MPclippath\space W n}}
+%D This is a temporary hack mthat will be removed, improved or somehow can become
+%D default.
-\unexpanded\def\dostopclipping
- {\pdfliteral{Q}}
-
-%D Temporary hack, will be removed or improved or default.
-
-% attr {/Group << /S /Transparency /I false /K true >>}
-
-%def\TransparencyHack{\ctxlua{backends.codeinjections.addtransparencygroup()}}
\def\TransparencyHack{\setupcolors[\c!pagecolormodel=\v!auto]}
-% Still here:
-
-%D \macros
-%D {back_ovalbox}
+%D Just in case one needs this \unknown:
%D
-%D Drawing frames with round corners is inherited from the main module. For drawing
-%D ovals we use quite raw \PDF\ code. The next implementation does not differ that
-%D much from the one implemented in the \POSTSCRIPT\ driver. This code is somewhat
-%D obsolete as we now have metapost embedded.
-
-\unexpanded\def\back_ovalbox#1#2#3#4#5#6#7#8%
- {\forcecolorhack
- \bgroup
- \edef\stroke{\tobigpoints\dimexpr#4\relax\space}%
- \edef\radius{\tobigpoints\dimexpr#5\relax\space}%
- \scratchdimen\dimexpr#4/\plustwo\relax
- \edef\xmin {\tobigpoints \scratchdimen \space}%
- \edef\xmax {\tobigpoints\dimexpr #1-\scratchdimen\relax\space}%
- \edef\ymax {\tobigpoints\dimexpr #2-\scratchdimen\relax\space}%
- \edef\ymin {\tobigpoints\dimexpr-#3+\scratchdimen\relax\space}%
- \advance\scratchdimen by #5\relax
- \edef\xxmin{\tobigpoints \scratchdimen \space}%
- \edef\xxmax{\tobigpoints\dimexpr #1-\scratchdimen\relax\space}%
- \edef\yymax{\tobigpoints\dimexpr #2-\scratchdimen\relax\space}%
- \edef\yymin{\tobigpoints\dimexpr-#3+\scratchdimen\relax\space}%
- %
- \edef\dostroke{\number#6}%
- \edef\dofill {\number#7}%
- \scratchcounter#8\relax
- \setbox\scratchbox\naturalhpack
- {\ifnum\dostroke\dofill>\zerocount
- \pdfliteral
- {q
- \stroke w
- \ifcase\scratchcounter
- \xxmin \ymin m
- \xxmax \ymin l
- \xmax \ymin \xmax \yymin y
- \xmax \yymax l
- \xmax \ymax \xxmax \ymax y
- \xxmin \ymax l
- \xmin \ymax \xmin \yymax y
- \xmin \yymin l
- \xmin \ymin \xxmin \ymin y
- h
- \or % 1
- \xxmin \ymin m
- \xxmax \ymin l
- \xmax \ymin \xmax \yymin y
- \xmax \ymax l
- \xmin \ymax l
- \xmin \yymin l
- \xmin \ymin \xxmin \ymin y
- h
- \or % 2
- \xxmin \ymin m
- \xmax \ymin l
- \xmax \ymax l
- \xxmin \ymax l
- \xmin \ymax \xmin \yymax y
- \xmin \yymin l
- \xmin \ymin \xxmin \ymin y
- h
- \or % 3
- \xmin \ymin m
- \xmax \ymin l
- \xmax \yymax l
- \xmax \ymax \xxmax \ymax y
- \xxmin \ymax l
- \xmin \ymax \xmin \yymax y
- \xmin \ymin l
- h
- \or % 4
- \xmin \ymin m
- \xxmax \ymin l
- \xmax \ymin \xmax \yymin y
- \xmax \yymax l
- \xmax \ymax \xxmax \ymax y
- \xmin \ymax l
- \xmin \ymin l
- h
- \or % 5
- \xmin \ymin m
- \xmax \ymin l
- \xmax \yymax l
- \xmax \ymax \xxmax \ymax y
- \xmin \ymax l
- \xmin \ymin l
- h
- \or % 6
- \xmin \ymin m
- \xxmax \ymin l
- \xmax \ymin \xmax \yymin y
- \xmax \ymax l
- \xmin \ymax l
- \xmin \ymin l
- h
- \or % 7
- \xxmin \ymin m
- \xmax \ymin l
- \xmax \ymax l
- \xmin \ymax l
- \xmin \yymin l
- \xmin \ymin \xxmin \ymin y
- h
- \or % 8
- \xmin \ymin m
- \xmax \ymin l
- \xmax \ymax l
- \xxmin \ymax l
- \xmin \ymax \xmin \yymax y
- \xmin \ymin l
- h
- \or % 9 top open
- \xmin \ymax m
- \xmin \yymin l
- \xmin \ymin \xxmin \ymin y
- \xxmax \ymin l
- \xmax \ymin \xmax \yymin y
- \xmax \ymax l
- \or % 10 right open
- \xmax \ymax m
- \xxmin \ymax l
- \xmin \ymax \xmin \yymax y
- \xmin \yymin l
- \xmin \ymin \xxmin \ymin y
- \xmax \ymin l
- \or % 11 bottom open
- \xmax \ymin m
- \xmax \yymax l
- \xmax \ymax \xxmax \ymax y
- \xxmin \ymax l
- \xmin \ymax \xmin \yymax y
- \xmin \ymin l
- \or % 12 left open
- \xmin \ymax m
- \xxmax \ymax l
- \xmax \ymax \xmax \yymax y
- \xmax \yymin l
- \xmax \ymin \xxmax \ymin y
- \xmin \ymin l
- \or % 13
- \xmin \ymax m
- \xxmax \ymax l
- \xmax \ymax \xmax \yymax y
- \xmax \ymin l
- \or % 14
- \xmax \ymax m
- \xmax \yymin l
- \xmax \ymin \xxmax \ymin y
- \xmin \ymin l
- \or % 15
- \xmax \ymin m
- \xxmin \ymin l
- \xmin \ymin \xmin \yymin y
- \xmin \ymax l
- \or % 16
- \xmin \ymin m
- \xmin \yymax l
- \xmin \ymax \xxmin \ymax y
- \xmax \ymax l
- \or % 17
- \xxmax \ymax m
- \xmax \ymax \xmax \yymax y
- \or % 18
- \xmax \yymin m
- \xmax \ymin \xxmax \ymin y
- \or % 19
- \xxmin \ymin m
- \xmin \ymin \xmin \yymin y
- \or % 20
- \xmin \yymax m
- \xmin \ymax \xxmin \ymax y
- \or % 21
- \xxmax \ymax m
- \xmax \ymax \xmax \yymax y
- \xmin \yymax m
- \xmin \ymax \xxmin \ymax y
- \or % 22
- \xxmax \ymax m
- \xmax \ymax \xmax \yymax y
- \xmax \yymin m
- \xmax \ymin \xxmax \ymin y
- \or % 23
- \xmax \yymin m
- \xmax \ymin \xxmax \ymin y
- \xxmin \ymin m
- \xmin \ymin \xmin \yymin y
- \or % 24
- \xxmin \ymin m
- \xmin \ymin \xmin \yymin y
- \xmin \yymax m
- \xmin \ymax \xxmin \ymax y
- \or % 25
- \xxmax \ymax m
- \xmax \ymax \xmax \yymax y
- \xmax \yymin m
- \xmax \ymin \xxmax \ymin y
- \xxmin \ymin m
- \xmin \ymin \xmin \yymin y
- \xmin \yymax m
- \xmin \ymax \xxmin \ymax y
- \or % 26
- \xmax \yymin m
- \xmax \ymin \xxmax \ymin y
- \xmin \yymax m
- \xmin \ymax \xxmin \ymax y
- \or % 27
- \xxmax \ymax m
- \xmax \ymax \xmax \yymax y
- \xxmin \ymin m
- \xmin \ymin \xmin \yymin y
- \or % 28
- \fi
- \ifnum\scratchcounter>\pluseight
- S
- \else
- \ifnum\dostroke=\plusone S \fi
- \ifnum\dofill =\plusone f \fi
- \fi
- Q}%
- \fi}%
- \wd\scratchbox#1%
- \ht\scratchbox#2%
- \dp\scratchbox#3%
- \box\scratchbox
- \egroup}
+%D \starttyping
+%D text \pdfbackendactualtext{Meier}{Müller} text
+%D \stoptyping
\unexpanded\def\pdfbackendactualtext#1#2% not interfaced
{\clf_startactualtext{#2}%
@@ -530,8 +143,12 @@
\let\pdfactualtext\pdfbackendactualtext
-% \starttext
-% text \pdfbackendactualtext{Meier}{Müller} text
-% \stoptext
+%D Bah, this is also needed for tikz:
+
+\ifdefined\pdfsavepos\else
+ \let\pdfsavepos \savepos
+ \let\pdflastxpos\lastxpos
+ \let\pdflastypos\lastypos
+\fi
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/back-pdf.mkxl b/Master/texmf-dist/tex/context/base/mkiv/back-pdf.mkxl
new file mode 100644
index 00000000000..ab65458c576
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/back-pdf.mkxl
@@ -0,0 +1,156 @@
+%D \module
+%D [ file=back-pdf,
+%D version=2009.04.15,
+%D title=\CONTEXT\ Backend Macros,
+%D subtitle=\PDF,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D The less there is here, the better. After a decade it is time to remove the \type
+%D {\pdf*} ones completely. For the moment I keep them commented but even that will
+%D go away.
+
+\writestatus{loading}{ConTeXt Backend Macros / PDF}
+
+\registerctxluafile{lpdf-ini}{optimize}
+\registerctxluafile{lpdf-lmt}{optimize}
+
+\registerctxluafile{lpdf-col}{}
+\registerctxluafile{lpdf-xmp}{}
+\registerctxluafile{lpdf-ano}{}
+\registerctxluafile{lpdf-res}{}
+\registerctxluafile{lpdf-mis}{}
+\registerctxluafile{lpdf-ren}{}
+\registerctxluafile{lpdf-grp}{}
+\registerctxluafile{lpdf-wid}{}
+\registerctxluafile{lpdf-fld}{}
+\registerctxluafile{lpdf-mov}{}
+\registerctxluafile{lpdf-u3d}{} % this will become a module
+\registerctxluafile{lpdf-swf}{} % this will become a module
+\registerctxluafile{lpdf-tag}{}
+\registerctxluafile{lpdf-fmt}{}
+\registerctxluafile{lpdf-pde}{}
+\registerctxluafile{lpdf-img}{optimize}
+\registerctxluafile{lpdf-epa}{}
+\registerctxluafile{lpdf-emb}{optimize}
+\registerctxluafile{lpdf-fnt}{}
+
+\registerctxluafile{back-pdp}{}
+\registerctxluafile{back-pdf}{} % some code will move to lpdf-*
+
+\loadmarkfile{back-u3d} % this will become a module
+\loadmarkfile{back-swf} % this will become a module
+
+\unprotect
+
+%D We will minimize the number of calls to \PDF\ specific primitives and delegate
+%D all management and injection of code to the backend.
+%D
+%D Because we do a lot in \LUA\ and don't want interferences, we nil most of the
+%D \PDFTEX\ primitives. Of course one can always use the \type {\pdfvariable},
+%D \type {\pdfextension} and \type {\pdffeedback} primitives but it will probably
+%D have bad side effects.
+
+\unexpanded\def\pdfextension{\clf_pdfextension}
+ \def\pdffeedback {\clf_pdffeedback}
+
+%D For the moment we keep this for tikz but hopefully it will at some point use
+%D the proper ones. Consider them obsolete:
+
+\unexpanded\def\pdfliteral {\clf_pdfliteral}
+\unexpanded\def\pdfobj {\clf_pdfobj}%
+\unexpanded\def\pdflastobj {\numexpr\clf_pdflastobj\relax}
+\unexpanded\def\pdfrefobj {\clf_pdfrefobj }
+
+\unexpanded\def\pdfrestore {\clf_restore}
+\unexpanded\def\pdfsave {\clf_save}
+\unexpanded\def\pdfsetmatrix{\clf_setmatrix}
+
+ \let\pdfxform \saveboxresource
+ \let\pdflastxform \lastsavedboxresourceindex
+ \let\pdfrefxform \useboxresource
+
+%D Here are quick and dirty compression flippers, mostly used when testing something
+%D as one can best stick to the defaults that also adapt to specific standards.
+
+\unexpanded\def\nopdfcompression {\clf_setpdfcompression\zerocount\zerocount}
+\unexpanded\def\onlypdfobjectcompression{\clf_setpdfcompression\zerocount\plusthree}
+\unexpanded\def\maximumpdfcompression {\clf_setpdfcompression\plusnine \plusnine }
+\unexpanded\def\normalpdfcompression {\clf_setpdfcompression\plusthree\plusthree}
+
+%D PDF/X (maybe combine the two lua calls)
+
+\setupbackend
+ [xmpfile=]
+
+\appendtoks
+ \edef\p_file{\backendparameter{xmpfile}}%
+ \ifx\p_file\empty\else
+ \clf_setxmpfile{\p_file}%
+ \fi
+\to \everysetupbackend
+
+%D This will change:
+
+\appendtoks
+ \clf_setformat
+ format {\backendparameter\c!format}%
+ level {\backendparameter\c!level}%
+ option {\backendparameter\c!option}%
+ profile {\backendparameter\c!profile}%
+ intent {\backendparameter\c!intent}%
+ file {\backendparameter\c!file}%
+ \relax
+\to \everysetupbackend
+
+%D These are the only official methods to add stuff to the resources. If more is
+%D needed for third party low level code, it can be added.
+
+\unexpanded\def\pdfbackendsetcatalog #1#2{\clf_lpdf_addtocatalog{#1}{#2}}
+\unexpanded\def\pdfbackendsetinfo #1#2{\clf_lpdf_addtoinfo{#1}{#2}}
+\unexpanded\def\pdfbackendsetname #1#2{\clf_lpdf_addtonames{#1}{#2}}
+
+\unexpanded\def\pdfbackendsetpageattribute #1#2{\clf_lpdf_addtopageattributes{#1}{#2}}
+\unexpanded\def\pdfbackendsetpagesattribute#1#2{\clf_lpdf_addtopagesattributes{#1}{#2}}
+\unexpanded\def\pdfbackendsetpageresource #1#2{\clf_lpdf_addtopageresources{#1}{#2}}
+
+\unexpanded\def\pdfbackendsetextgstate #1#2{\clf_lpdf_adddocumentextgstate{#1}{#2}}
+\unexpanded\def\pdfbackendsetcolorspace #1#2{\clf_lpdf_adddocumentcolorspace{#1}{#2}}
+\unexpanded\def\pdfbackendsetpattern #1#2{\clf_lpdf_adddocumentpattern{#1}{#2}}
+\unexpanded\def\pdfbackendsetshade #1#2{\clf_lpdf_adddocumentshade{#1}{#2}}
+
+ \def\pdfbackendcurrentresources {\clf_lpdf_collectedresources}
+ \def\pdfcolor #1{\clf_lpdf_color\numexpr\thecolorattribute{#1}\relax}
+
+%D This is a temporary hack mthat will be removed, improved or somehow can become
+%D default.
+
+\def\TransparencyHack{\setupcolors[\c!pagecolormodel=\v!auto]}
+
+%D Just in case one needs this \unknown:
+%D
+%D \starttyping
+%D text \pdfbackendactualtext{Meier}{Müller} text
+%D \stoptyping
+
+\unexpanded\def\pdfbackendactualtext#1#2% not interfaced
+ {\clf_startactualtext{#2}%
+ #1%
+ \clf_stopactualtext}
+
+\let\pdfactualtext\pdfbackendactualtext
+
+%D Bah, this is also needed for tikz:
+
+\ifdefined\pdfsavepos\else
+ \let\pdfsavepos \savepos
+ \let\pdflastxpos\lastxpos
+ \let\pdflastypos\lastypos
+\fi
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/back-pdp.lua b/Master/texmf-dist/tex/context/base/mkiv/back-pdp.lua
index 7363cfcae4d..6111cf469b2 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/back-pdp.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/back-pdp.lua
@@ -9,7 +9,8 @@ if not modules then modules = { } end modules ['back-pdp'] = {
-- This is temporary ... awaiting a better test .. basically we can
-- always use this: pdf primitives.
-local context = context
+local context = context
+local lpdf = lpdf
local lpdfreserveobject = lpdf.reserveobject
local lpdfcompresslevel = lpdf.compresslevel
@@ -17,22 +18,17 @@ local lpdfobj = lpdf.obj
local lpdfpagereference = lpdf.pagereference
local lpdfxformname = lpdf.xformname
-local jobpositions = job.positions
-local gethpos = jobpositions.gethpos
-local getvpos = jobpositions.getvpos
-
local tokenscanners = tokens.scanners
local scanword = tokenscanners.word
local scankeyword = tokenscanners.keyword
local scanstring = tokenscanners.string
local scaninteger = tokenscanners.integer
-local scandimension = tokenscanners.dimension
+local scanwhd = tokenscanners.whd
-local trace = false trackers.register("commands", function(v) trace = v end)
-local report = logs.reporter("command")
+local trace = false trackers.register("backend", function(v) trace = v end)
+local report = logs.reporter("backend")
local nodepool = nodes.pool
-local newsavepos = nodepool.savepos
local newliteral = nodepool.literal
local newsave = nodepool.save
local newrestore = nodepool.restore
@@ -42,183 +38,12 @@ local implement = interfaces.implement
local constants = interfaces.constants
local variables = interfaces.variables
--- helper
-
-local function scanwhd()
- local width, height, depth
- while true do
- if scankeyword("width") then
- width = scandimension()
- elseif scankeyword("height") then
- height = scandimension()
- elseif scankeyword("depth") then
- depth = scandimension()
- else
- break
- end
- end
- if width or height or depth then
- return width or 0, height or 0, depth or 0
- else
- -- we inherit
- end
-end
-
--- positions
-
-local function savepos()
- context(newsavepos())
-end
-
-local function lastxpos()
- context(gethpos())
-end
-
-local function lastypos()
- context(getvpos())
-end
-
-implement { name = "savepos", actions = savepos }
-implement { name = "lastxpos", actions = lastxpos }
-implement { name = "lastypos", actions = lastypos }
-
-- literals
local function pdfliteral()
context(newliteral(scanword() or "origin",scanstring()))
end
-implement { name = "pdfliteral", actions = pdfliteral }
-
--- box resources
-
-local boxresources = tex.boxresources
-local savebox = boxresources.save
-local usebox = boxresources.use
-
-local lastindex = 0
-
-local function saveboxresource()
- local immediate = true
- local kind = scankeyword("type") and scaninteger() or 0
- local attributes = scankeyword("attr") and scanstring() or nil
- local resources = scankeyword("resources") and scanstring() or nil
- local margin = scankeyword("margin") and scandimension() or 0 -- register
- local boxnumber = scaninteger()
- --
- lastindex = savebox(boxnumber,attributes,resources,immediate,kind,margin)
- if trace then
- report("\\saveboxresource: index %i",lastindex)
- end
-end
-
-local function lastsavedboxresourceindex()
- if trace then
- report("\\lastsaveboxresource: index %i",lastindex)
- end
- context("%i",lastindex)
-end
-
-local function useboxresource()
- local width, height, depth = scanwhd()
- local index = scaninteger()
- local node = usebox(index,width,height,depth)
- if trace then
- report("\\useboxresource: index %i",index)
- end
- context(node)
-end
-
-implement { name = "saveboxresource", actions = saveboxresource }
-implement { name = "lastsavedboxresourceindex", actions = lastsavedboxresourceindex }
-implement { name = "useboxresource", actions = useboxresource }
-
--- image resources (messy: will move)
-
-local imageresources = { }
-local lastindex = 0
-local lastpages = 1
-
-local function saveimageresource()
- local width, height, depth = scanwhd()
- local page = 1
- local immediate = true
- local margin = 0 -- or dimension
- local attributes = scankeyword("attr") and scanstring() or nil
- if scankeyword("named") then
- scanstring() -- ignored
- elseif scankeyword("page") then
- page = scaninteger()
- end
- local userpassword = scankeyword("userpassword") and scanstring() or nil
- local ownerpassword = scankeyword("ownerpassword") and scanstring() or nil
- local visiblefilename = scankeyword("visiblefilename") and scanstring() or nil
- local colorspace = scankeyword("colorspace") and scaninteger() or nil
- local pagebox = scanword() or nil
- local filename = scanstring()
--- pcall
- context.getfiguredimensions( { filename }, {
- [constants.userpassword] = userpassword,
- [constants.ownerpassword] = ownerpassword,
- [constants.page] = page or 1,
- [constants.size] = pagebox,
- })
- context.relax()
- lastindex = lastindex + 1
- lastpages = 1
- imageresources[lastindex] = {
- filename = filename,
- page = page or 1,
- size = pagebox,
- width = width,
- height = height,
- depth = depth,
- attr = attributes,
- -- margin = margin,
- }
-end
-
-local function lastsavedimageresourceindex()
- context("%i",lastindex or 0)
-end
-
-local function lastsavedimageresourcepages()
- context("%i",lastpages or 0) -- todo
-end
-
-local function useimageresource()
- local width, height, depth = scanwhd()
- if scankeyword("keepopen") then
- -- ignored
- end
- local index = scaninteger()
- local l = imageresources[index]
- if l then
- if not (width or height or depth) then
- width = l.width
- height = l.height
- depth = l.depth
- end
--- pcall
- context.externalfigure( { l.filename }, {
- [constants.userpassword] = l.userpassword,
- [constants.ownerpassword] = l.ownerpassword,
- [constants.width] = width and (width .. "sp") or nil,
- [constants.height] = height and (height .. "sp") or nil,
- [constants.page] = l.page or 1,
- [constants.size] = pagebox,
- })
- context.relax()
- else
- print("no image resource",index)
- end
-end
-
-implement { name = "saveimageresource", actions = saveimageresource }
-implement { name = "lastsavedimageresourceindex", actions = lastsavedimageresourceindex }
-implement { name = "lastsavedimageresourcepages", actions = lastsavedimageresourcepages }
-implement { name = "useimageresource", actions = useimageresource }
-
-- objects
local lastobjnum = 0
@@ -233,16 +58,20 @@ local function pdfobj()
local immediate = true
local objnum = scankeyword("useobjnum") and scaninteger() or lpdfreserveobject()
local uncompress = scankeyword("uncompressed") or lpdfcompresslevel() == 0
- local streamobject = scankeyword("stream") and true or false
- local attributes = scankeyword("attr") and scanstring()
+ local streamobject = scankeyword("stream")
+ local attributes = scankeyword("attr") and scanstring() or nil
local fileobject = scankeyword("file")
local content = scanstring()
- local object = {
+ local object = streamobject and {
+ type = "stream",
+ objnum = objnum,
immediate = immediate,
attr = attributes,
- objnum = objnum,
- type = streamobject and "stream" or nil,
compresslevel = uncompress and 0 or nil,
+ } or {
+ type = "raw",
+ objnum = objnum,
+ immediate = immediate,
}
if fileobject then
object.filename = content
@@ -271,10 +100,6 @@ local function pdfrefobj()
end
end
-implement { name = "pdfobj", actions = pdfobj }
-implement { name = "pdflastobj", actions = pdflastobj }
-implement { name = "pdfrefobj", actions = pdfrefobj }
-
-- annotations
local lastobjnum = 0
@@ -306,8 +131,6 @@ local function pdfannot()
end
end
-implement { name = "pdfannot", actions = pdfannot }
-
local function pdfdest()
local name = false
local zoom = false
@@ -345,11 +168,8 @@ local function pdfdest()
context(backends.nodeinjections.destination(width or 0,height or 0,depth or 0,{ name or "" },view or "fit"))
end
-implement { name = "pdfdest", actions = pdfdest }
-
-- management
-
local function pdfsave()
context(newsave())
end
@@ -362,7 +182,6 @@ local function pdfsetmatrix()
context(newsetmatrix(scanstring()))
end
-
-- extras
local function pdfpageref()
@@ -400,8 +219,6 @@ local function pdfextension()
end
end
-implement { name = "pdfextension", actions = pdfextension }
-
-- feedbacks: colorstackinit creationdate fontname fontobjnum fontsize lastannot
-- lastlink lastobj pageref retval revision version xformname
@@ -423,8 +240,6 @@ local function pdffeedback()
end
end
-implement { name = "pdffeedback", actions = pdffeedback }
-
-- variables: (integers:) compresslevel decimaldigits gamma gentounicode
-- ignoreunknownimages imageaddfilename imageapplygamma imagegamma imagehicolor
-- imageresolution inclusioncopyfonts inclusionerrorlevel majorversion minorversion
@@ -450,4 +265,17 @@ implement { name = "pdffeedback", actions = pdffeedback }
-- end
-- end
---------- { name = "pdfvariable", actions = pdfvariable }
+-- kept:
+
+implement { name = "pdfextension", actions = pdfextension }
+implement { name = "pdffeedback", actions = pdffeedback }
+--------- { name = "pdfvariable", actions = pdfvariable }
+
+-- for the moment (tikz)
+
+implement { name = "pdfliteral", actions = pdfliteral }
+implement { name = "pdfobj", actions = pdfobj }
+implement { name = "pdflastobj", actions = pdflastobj }
+implement { name = "pdfrefobj", actions = pdfrefobj }
+--------- { name = "pdfannot", actions = pdfannot }
+--------- { name = "pdfdest", actions = pdfdest }
diff --git a/Master/texmf-dist/tex/context/base/mkiv/back-res.lua b/Master/texmf-dist/tex/context/base/mkiv/back-res.lua
index be92c74a6db..2ca4a5ac8b0 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/back-res.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/back-res.lua
@@ -1,15 +1,32 @@
if not modules then modules = { } end modules ['back-res'] = {
version = 1.001,
- comment = "companion to lpdf-ini.mkiv",
+ comment = "companion to back-ini.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
}
--- A box resource has an index. This happens to be an object number
--- due to the pdf backend but in fact it's an abstraction. This is why
--- we have explicit fetchers. The internal number (as in \Fm123) is yet
--- another number.
+local context = context
+
+local trace = false trackers.register("backend", function(v) trace = v end)
+local report = logs.reporter("backend")
+
+local scanners = tokens.scanners
+local scankeyword = scanners.keyword
+local scaninteger = scanners.integer
+local scanstring = scanners.string
+local scandimension = scanners.dimension
+local scanword = scanners.word
+local scanwhd = scanners.whd
+
+local scanners = interfaces.scanners
+local implement = interfaces.implement
+local constants = interfaces.constants
+local variables = interfaces.variables
+
+-- A box resource has an index. This happens to be an object number due to the pdf
+-- backend but in fact it's an abstraction. This is why we have explicit fetchers.
+-- The internal number (as in \Fm123) is yet another number.
local tex_saveboxresource = tex.saveboxresource
local tex_useboxresource = tex.useboxresource
@@ -23,13 +40,20 @@ updaters.register("backend.update",function()
tex_getboxresourcedimensions = tex.getboxresourcedimensions
end)
-tex.boxresources = {
- save = function(...) return tex_saveboxresource(...) end,
- use = function(...) return tex_useboxresource(...) end,
- getbox = function(...) return tex_getboxresourcebox(...) end,
- getdimensions = function(...) return tex_getboxresourcedimensions(...) end,
+local savebox = function(...) return tex_saveboxresource(...) end
+local usebox = function(...) return tex_useboxresource(...) end
+local getbox = function(...) return tex_getboxresourcebox(...) end
+local getwhd = function(...) return tex_getboxresourcedimensions(...) end
+
+local boxresources = {
+ save = savebox,
+ use = usebox,
+ getbox = getbox,
+ getdimensions = getwhd,
}
+tex.boxresources = boxresources
+
-- local tex_saveimageresource = tex.saveimageresource
-- local tex_useimageresource = tex.useimageresource
--
@@ -42,3 +66,126 @@ tex.boxresources = {
-- save = function(...) return tex_saveimageresource(...) end,
-- use = function(...) return tex_useimageresource(...) end,
-- }
+
+local lastindex = 0
+
+local function saveboxresource()
+ local immediate = true
+ local kind = scankeyword("type") and scaninteger() or 0
+ local attributes = scankeyword("attr") and scanstring() or nil
+ local resources = scankeyword("resources") and scanstring() or nil
+ local margin = scankeyword("margin") and scandimension() or 0 -- register
+ local boxnumber = scaninteger()
+ --
+ lastindex = savebox(boxnumber,attributes,resources,immediate,kind,margin)
+ if trace then
+ report("\\saveboxresource: index %i",lastindex)
+ end
+end
+
+local function lastsavedboxresourceindex()
+ if trace then
+ report("\\lastsaveboxresource: index %i",lastindex)
+ end
+ context("%i",lastindex)
+end
+
+local function useboxresource()
+ local width, height, depth = scanwhd()
+ local index = scaninteger()
+ local node = usebox(index,width,height,depth)
+ if trace then
+ report("\\useboxresource: index %i",index)
+ end
+ context(node)
+end
+
+implement { name = "saveboxresource", actions = saveboxresource }
+implement { name = "lastsavedboxresourceindex", actions = lastsavedboxresourceindex }
+implement { name = "useboxresource", actions = useboxresource }
+
+-- image resources
+
+local imageresources = { }
+local lastindex = 0
+local lastpages = 1
+
+local function saveimageresource()
+ local width, height, depth = scanwhd()
+ local page = 1
+ local immediate = true
+ local margin = 0 -- or dimension
+ local attributes = scankeyword("attr") and scanstring() or nil
+ if scankeyword("named") then
+ scanstring() -- ignored
+ elseif scankeyword("page") then
+ page = scaninteger()
+ end
+ local userpassword = scankeyword("userpassword") and scanstring() or nil
+ local ownerpassword = scankeyword("ownerpassword") and scanstring() or nil
+ local visiblefilename = scankeyword("visiblefilename") and scanstring() or nil
+ local colorspace = scankeyword("colorspace") and scaninteger() or nil
+ local pagebox = scanword() or nil
+ local filename = scanstring()
+-- pcall
+ context.getfiguredimensions( { filename }, {
+ [constants.userpassword] = userpassword,
+ [constants.ownerpassword] = ownerpassword,
+ [constants.page] = page or 1,
+ [constants.size] = pagebox,
+ })
+ context.relax()
+ lastindex = lastindex + 1
+ lastpages = 1
+ imageresources[lastindex] = {
+ filename = filename,
+ page = page or 1,
+ size = pagebox,
+ width = width,
+ height = height,
+ depth = depth,
+ attr = attributes,
+ -- margin = margin,
+ }
+end
+
+local function lastsavedimageresourceindex()
+ context("%i",lastindex or 0)
+end
+
+local function lastsavedimageresourcepages()
+ context("%i",lastpages or 0) -- todo
+end
+
+local function useimageresource()
+ local width, height, depth = scanwhd()
+ if scankeyword("keepopen") then
+ -- ignored
+ end
+ local index = scaninteger()
+ local l = imageresources[index]
+ if l then
+ if not (width or height or depth) then
+ width = l.width
+ height = l.height
+ depth = l.depth
+ end
+ -- pcall / we could use a dedicated call instead:
+ context.externalfigure( { l.filename }, {
+ [constants.userpassword] = l.userpassword,
+ [constants.ownerpassword] = l.ownerpassword,
+ [constants.width] = width and (width .. "sp") or nil,
+ [constants.height] = height and (height .. "sp") or nil,
+ [constants.page] = l.page or 1,
+ [constants.size] = pagebox,
+ })
+ context.relax()
+ else
+ report("no valid image resource %a",index)
+ end
+end
+
+implement { name = "saveimageresource", actions = saveimageresource }
+implement { name = "lastsavedimageresourceindex", actions = lastsavedimageresourceindex }
+implement { name = "lastsavedimageresourcepages", actions = lastsavedimageresourcepages }
+implement { name = "useimageresource", actions = useimageresource }
diff --git a/Master/texmf-dist/tex/context/base/mkiv/back-res.mkiv b/Master/texmf-dist/tex/context/base/mkiv/back-res.mkiv
new file mode 100644
index 00000000000..fd7b208c949
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/back-res.mkiv
@@ -0,0 +1,32 @@
+%D \module
+%D [ file=back-res,
+%D version=2019.05.23, % 2009.04.15,
+%D title=\CONTEXT\ Backend Macros,
+%D subtitle=Resources,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Backend Macros / Resources}
+
+\registerctxluafile{back-res}{}
+
+\unprotect
+
+%D We overload the primitives with our own but use a bit of indirection for the
+%D purpose of tracing. Some of these are needes for packages like tikz.
+
+\unexpanded\def\saveboxresource {\clf_saveboxresource}
+\unexpanded\def\lastsavedboxresourceindex {\numexpr\clf_lastsavedboxresourceindex\relax}
+\unexpanded\def\useboxresource {\clf_useboxresource}
+
+\unexpanded\def\saveimageresource {\clf_saveimageresource}
+\unexpanded\def\lastsavedimageresourceindex{\numexpr\clf_lastsavedimageresourceindex\relax}
+\unexpanded\def\lastsavedimageresourcepages{\numexpr\clf_lastsavedimageresourcepages\relax}
+\unexpanded\def\useimageresource {\clf_useimageresource}
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/back-trf.lua b/Master/texmf-dist/tex/context/base/mkiv/back-trf.lua
new file mode 100644
index 00000000000..1586bc440f4
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/back-trf.lua
@@ -0,0 +1,164 @@
+if not modules then modules = { } end modules ['back-trf'] = {
+ version = 1.001,
+ comment = "companion to back-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local sind, cosd, abs = math.sind, math.cosd, math.abs
+local insert, remove = table.insert, table.remove
+local unpack = unpack
+
+local context = context
+
+local formatters = string.formatters
+
+local scanners = tokens.scanners
+local scankeyword = scanners.keyword
+local scaninteger = scanners.integer
+local scannumber = scanners.number
+local scanstring = scanners.string
+
+local implement = interfaces.implement
+
+local nodepool = nodes.pool
+local savenode = nodepool.save
+local restorenode = nodepool.restore
+local setmatrixnode = nodepool.setmatrix
+local literalnode = nodepool.literal -- has to become some nodeinjection
+
+local stack = { }
+local restore = true -- false
+
+updaters.register("backend.update",function()
+ savenode = nodepool.save
+ restorenode = nodepool.restore
+ setmatrixnode = nodepool.setmatrix
+ literalnode = nodepool.literal -- has to become some nodeinjection
+end)
+
+local function stopsomething()
+ local top = remove(stack)
+ if top == false then
+ -- not wrapped
+ elseif top == true then
+ context(restorenode())
+ elseif top then
+ context(setmatrixnode(unpack(top))) -- not really needed anymore
+ context(restorenode())
+ else
+ -- nesting error
+ end
+end
+
+local function startrotation()
+ local a = scannumber()
+ if a == 0 then
+ insert(stack,false)
+ else
+ local s, c = sind(a), cosd(a)
+ if abs(s) < 0.000001 then
+ s = 0 -- otherwise funny -0.00000
+ end
+ if abs(c) < 0.000001 then
+ c = 0 -- otherwise funny -0.00000
+ end
+ context(savenode())
+ context(setmatrixnode(c,s,-s,c))
+ insert(stack,restore and { c, -s, s, c } or true)
+ end
+end
+
+implement { name = "startrotation", actions = startrotation }
+implement { name = "stoprotation", actions = stopsomething }
+
+local function startscaling() -- at the tex end we use sx and sy instead of rx and ry
+ local rx, ry = 1, 1
+ while true do
+ if scankeyword("rx") then
+ rx = scannumber()
+ elseif scankeyword("ry") then
+ ry = scannumber()
+ -- elseif scankeyword("revert") then
+ -- local top = stack[#stack]
+ -- if top then
+ -- rx = top[1]
+ -- ry = top[4]
+ -- else
+ -- rx = 1
+ -- ry = 1
+ -- end
+ else
+ break
+ end
+ end
+ if rx == 1 and ry == 1 then
+ insert(stack,false)
+ else
+ if rx == 0 then
+ rx = 0.0001
+ end
+ if ry == 0 then
+ ry = 0.0001
+ end
+ context(savenode())
+ context(setmatrixnode(rx,0,0,ry))
+ insert(stack,restore and { 1/rx, 0, 0, 1/ry } or true)
+ end
+end
+
+implement { name = "startscaling", actions = startscaling }
+implement { name = "stopscaling", actions = stopsomething }
+
+local function startmatrix() -- rx sx sy ry -- tx, ty
+ local rx, sx, sy, ry = 1, 0, 0, 1
+ while true do
+ if scankeyword("rx") then rx = scannumber()
+ elseif scankeyword("ry") then ry = scannumber()
+ elseif scankeyword("sx") then sx = scannumber()
+ elseif scankeyword("sy") then sy = scannumber()
+ else break end
+ end
+ if rx == 1 and sx == 0 and sy == 0 and ry == 1 then
+ insert(stack,false)
+ else
+ context(savenode())
+ context(setmatrixnode(rx,sx,sy,ry))
+ insert(stack,store and { -rx, -sx, -sy, -ry } or true)
+ end
+end
+
+implement { name = "startmatrix", actions = startmatrix }
+implement { name = "stopmatrix", actions = stopsomething }
+
+local function startmirroring()
+ context(setmatrixnode(-1,0,0,1))
+end
+
+implement { name = "startmirroring", actions = startmirroring }
+implement { name = "stopmirroring", actions = startmirroring } -- not: stopsomething
+
+-- this could also run on top of pack-rul ... todo
+
+-- local function startclipping()
+-- -- context(savenode())
+-- context(literalnode("origin",formatters["q 0 w %s W n"](scanstring())))
+-- end
+--
+-- local function stopclipping()
+-- -- context(restorenode())
+-- context(literalnode("Q"))
+-- end
+
+local function startclipping()
+ context(savenode())
+ context(literalnode("origin",formatters["0 w %s W n"](scanstring())))
+end
+
+local function stopclipping()
+ context(restorenode())
+end
+
+implement { name = "startclipping", actions = startclipping }
+implement { name = "stopclipping", actions = stopclipping }
diff --git a/Master/texmf-dist/tex/context/base/mkiv/back-trf.mkiv b/Master/texmf-dist/tex/context/base/mkiv/back-trf.mkiv
new file mode 100644
index 00000000000..3d8477a8214
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/back-trf.mkiv
@@ -0,0 +1,79 @@
+%D \module
+%D [ file=back-trf,
+%D version=2019.02.08, % 2009.04.15,
+%D title=\CONTEXT\ Backend Macros,
+%D subtitle=Transformations,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\unprotect
+
+\registerctxluafile{back-trf}{}
+
+% rotation
+
+\unexpanded\def\dostartrotation#1%
+ {\forcecolorhack
+ \clf_startrotation#1\relax} % todo: implement without Q q
+
+\unexpanded\def\dostoprotation
+ {\clf_stoprotation
+ \forcecolorhack}
+
+% scaling
+
+\unexpanded\def\dostartscaling#1#2%
+ {\forcecolorhack
+ \clf_startscaling rx #1 ry #2\relax}
+
+\unexpanded\def\dostopscaling
+ {\clf_stopscaling
+ \forcecolorhack}
+
+% mirroring
+
+\unexpanded\def\dostartmirroring
+ {\clf_startmirroring}
+
+\unexpanded\def\dostopmirroring
+ {\clf_stopmirroring}
+
+% transform
+
+\unexpanded\def\dotransformnextbox#1#2#3#4#5#6%
+ {\dowithnextbox{\dodotransformnextbox{#1}{#2}{#3}{#4}{#5}{#6}}}
+
+\unexpanded\def\dodotransformnextbox#1#2#3#4#5#6%
+ {\hpack
+ {\kern #5\onebasepoint
+ \raise#6\onebasepoint
+ \hpack
+ {\clf_startmatrix rx #1 sx #2 sy #3 ry #4\relax
+ \box\nextbox
+ \clf_stopmatrix}}}
+
+%D \macros
+%D {dostartclipping,dostopclipping}
+%D
+%D Clipping is implemented in such a way that an arbitrary code can be fed.
+%D
+%D \starttyping
+%D \dostartclipping {pathname} {width} {height}
+%D \dostopclipping
+%D \stoptyping
+
+\unexpanded\def\dostartclipping#1#2#3% we can move this to lua and only set a box here
+ {\forcecolorhack
+ \meta_grab_clip_path{#1}{#2}{#3}%
+ \clf_startclipping{\MPclippath}%
+ \glet\MPclippath\empty}
+
+\unexpanded\def\dostopclipping
+ {\clf_stopclipping}
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/bibl-tra.lua b/Master/texmf-dist/tex/context/base/mkiv/bibl-tra.lua
index 76171cb7f21..d6fb7c6c7ed 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/bibl-tra.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/bibl-tra.lua
@@ -68,7 +68,7 @@ local runners = {
name = "bibtex",
method = "execute",
program = "bibtex",
- template = [["%filename%"]],
+ template = "%filename%",
checkers = {
filename = "readable",
}
@@ -77,7 +77,7 @@ local runners = {
name = "mlbibtex",
method = "execute",
program = "mlbibcontext",
- template = [["%filename%"]],
+ template = "%filename%",
checkers = {
filename = "readable",
}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/buff-imp-default.mkiv b/Master/texmf-dist/tex/context/base/mkiv/buff-imp-default.mkiv
index 4da4ff0df20..1a125a07324 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/buff-imp-default.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/buff-imp-default.mkiv
@@ -15,11 +15,13 @@
\unprotect
-\setupstartstop
- [DefaultSnippet]
- [\c!before={\typingparameter\c!before},
- \c!after={\typingparameter\c!after},
- \c!style={\typingparameter\c!style}]
+% Happens elsewhere:
+%
+% \setupstartstop
+% [DefaultSnippet]
+% [\c!before={\typingparameter\c!before},
+% \c!after={\typingparameter\c!after},
+% \c!style={\typingparameter\c!style}]
% Name
% NamePrimitive
diff --git a/Master/texmf-dist/tex/context/base/mkiv/buff-imp-xml.lua b/Master/texmf-dist/tex/context/base/mkiv/buff-imp-xml.lua
index 0c48ed3b090..b7fa85818a0 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/buff-imp-xml.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/buff-imp-xml.lua
@@ -41,7 +41,9 @@ local handler = visualizers.newhandler {
}
local comment = P("--")
-local name = (patterns.letter + patterns.digit + S('_-.'))^1
+local alsoname = patterns.utf8two + patterns.utf8three + patterns.utf8four
+----- alsoname = R("\128\255") -- basically any encoding without checking (fast)
+local name = (patterns.letter + patterns.digit + S('_-.') + alsoname)^1
local entity = P("&") * (1-P(";"))^1 * P(";")
local openbegin = P("<")
local openend = P("</")
@@ -57,11 +59,11 @@ local closecdata = P("]]>")
local grammar = visualizers.newgrammar("default", { "visualizer",
sstring =
makepattern(handler,"string",patterns.dquote)
- * (V("whitespace") + makepattern(handler,"default",1-patterns.dquote))^0
+ * (V("whitespace") + makepattern(handler,"default",(1-patterns.dquote)^0))
* makepattern(handler,"string",patterns.dquote),
dstring =
makepattern(handler,"string",patterns.squote)
- * (V("whitespace") + makepattern(handler,"default",1-patterns.squote))^0
+ * (V("whitespace") + makepattern(handler,"default",(1-patterns.squote)^0))
* makepattern(handler,"string",patterns.squote),
entity =
makepattern(handler,"entity",entity),
diff --git a/Master/texmf-dist/tex/context/base/mkiv/buff-ini.lua b/Master/texmf-dist/tex/context/base/mkiv/buff-ini.lua
index ecb5d9dd054..5b5c4786756 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/buff-ini.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/buff-ini.lua
@@ -36,6 +36,7 @@ local scanstring = scanners.string
local scaninteger = scanners.integer
local scanboolean = scanners.boolean
local scancode = scanners.code
+local scantokencode = scanners.tokencode
----- scantoken = scanners.token
local getters = tokens.getters
@@ -357,6 +358,23 @@ local split = table.setmetatableindex(function(t,k)
return v
end)
+local tochar = {
+ [ 0] = "\\",
+ [ 1] = "{",
+ [ 2] = "}",
+ [ 3] = "$",
+ [ 4] = "&",
+ [ 5] = "\n",
+ [ 6] = "#",
+ [ 7] = "^",
+ [ 8] = "_",
+ [10] = " ",
+ [14] = "%",
+}
+
+local experiment = false
+local experiment = scantokencode and true
+
function tokens.pickup(start,stop)
local stoplist = split[stop] -- totable(stop)
local stoplength = #stoplist
@@ -367,7 +385,8 @@ function tokens.pickup(start,stop)
local list = { }
local size = 0
local depth = 0
--- local done = 32
+-- local done = 32
+ local scancode = experiment and scantokencode or scancode
while true do -- or use depth
local char = scancode()
if char then
@@ -418,15 +437,37 @@ function tokens.pickup(start,stop)
local t = gettoken()
if t then
-- we're skipping leading stuff, like obeyedlines and relaxes
+ if experiment and size > 0 then
+ -- we're probably in a macro
+ local char = tochar[token.get_command(t)] -- could also be char(token.get_mode(t))
+ if char then
+ size = size + 1 ; list[size] = char
+ else
+ local csname = token.get_csname(t)
+ if csname == stop then
+ stoplength = 0
+ break
+ else
+ size = size + 1 ; list[size] = "\\"
+ size = size + 1 ; list[size] = csname
+ size = size + 1 ; list[size] = " "
+ end
+ end
+ else
+ -- ignore and hope for the best
+ end
else
break
end
end
end
local start = 1
- local stop = size-stoplength-1
+ local stop = size - stoplength - 1
-- not good enough: only empty lines, but even then we miss the leading
-- for verbatim
+ --
+ -- the next is not yet adapted to the new scanner ... we don't need lpeg here
+ --
for i=start,stop do
local li = list[i]
if lpegmatch(blackspace,li) then
@@ -445,6 +486,7 @@ function tokens.pickup(start,stop)
break
end
end
+ --
if start <= stop then
return concat(list,"",start,stop)
else
@@ -512,7 +554,7 @@ local runner = sandbox.registerrunner {
name = "run buffer",
program = "context",
method = "execute",
- template = "--purgeall " .. (jit and "--jit" or "") .. " %filename%",
+ template = jit and "--purgeall --jit %filename%" or "--purgeall %filename%",
reporter = report_typeset,
checkers = {
filename = "readable",
diff --git a/Master/texmf-dist/tex/context/base/mkiv/buff-ini.mkiv b/Master/texmf-dist/tex/context/base/mkiv/buff-ini.mkiv
index 145f0f39245..8e71c9865ad 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/buff-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/buff-ini.mkiv
@@ -132,7 +132,7 @@
\unexpanded\def\buff_stop#1%
{\endgroup % (3 & 4 & 5 & 6)
- \csname#1\endcsname}
+ \begincsname#1\endcsname}
% \installctxfunction\dopickupbuffer{commands.dopickupbuffer}
@@ -185,6 +185,15 @@
{\processcommalist[#1]\buff_get_stored_indeed}%
\namedbufferparameter\empty\c!after\relax}
+% \installcommalistprocessorcommand \buff_get_stored_list \empty \buff_get_stored_indeed
+%
+% \unexpanded\def\buff_get[#1]% [name]
+% {\namedbufferparameter\empty\c!before\relax
+% \doifelsenothing{#1}
+% {\buff_get_stored_indeed\empty}
+% {\buff_get_stored_list[#1]}%
+% \namedbufferparameter\empty\c!after\relax}
+
\unexpanded\def\buff_get_stored#1#2%
{\namedbufferparameter{#1}\c!before\relax
\buff_get_stored_indeed{#2}%
diff --git a/Master/texmf-dist/tex/context/base/mkiv/buff-ver.lua b/Master/texmf-dist/tex/context/base/mkiv/buff-ver.lua
index 969a28055e2..ad06dceeca3 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/buff-ver.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/buff-ver.lua
@@ -127,7 +127,8 @@ local signal = "\000"
visualizers.signal = signal
visualizers.signalpattern = P(signal)
-local functions = { __index = {
+local functions = {
+ __index = {
emptyline = f_emptyline,
newline = f_newline,
default = f_default,
diff --git a/Master/texmf-dist/tex/context/base/mkiv/buff-ver.mkiv b/Master/texmf-dist/tex/context/base/mkiv/buff-ver.mkiv
index 7cf829b746c..75ee992e41b 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/buff-ver.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/buff-ver.mkiv
@@ -140,8 +140,7 @@
%D \macros
%D {definetype,setuptype}
%D
-%D Specific inline verbatim commands can be defined with the
-%D following command.
+%D Specific inline verbatim commands can be defined with the following command.
\installcorenamespace{type}
@@ -158,9 +157,8 @@
%D \macros
%D {definetyping,setuptyping}
%D
-%D For most users the standard \type{\start}||\type{\stop}||pair
-%D will suffice, but for documentation purposes the next
-%D definition command can be of use:
+%D For most users the standard \type {\start}||\type {\stop}||pair will suffice, but
+%D for documentation purposes the next definition command can be of use:
%D
%D \starttyping
%D \definetyping[extratyping][margin=3em]
@@ -198,31 +196,27 @@
\let\doifvisualizerelse\doifelsevisualizer
-%D Verbatim command are very sensitive to argument processing,
-%D which is a direct result of the \CATCODES\ being fixed at
-%D reading time.
+%D Verbatim command are very sensitive to argument processing, which is a direct
+%D result of the \CATCODES\ being fixed at reading time.
%D
-%D Typesetting inline verbatim can be accomplished by
-%D \type{\type}, which in this sentence was typeset by saying
-%D just \type{\type{\type}}, which in turn was typeset by
-%D \unknown. Using the normal grouping characters \type{{}} is
-%D the most natural way of using this command.
+%D Typesetting inline verbatim can be accomplished by \type {\type}, which in this
+%D sentence was typeset by saying just \type {\type {\type}}, which in turn was
+%D typeset by \unknown. Using the normal grouping characters \type {{}} is the most
+%D natural way of using this command.
%D
-%D A second, more or less redundant, alternative is delimiting
-%D the argument with an own character. This method was
-%D implemented in the context of a publication in the \MAPS,
-%D where this way of delimiting is recognized by \LATEX\ users.
+%D A second, more or less redundant, alternative is delimiting the argument with an
+%D own character. This method was implemented in the context of a publication in the
+%D \MAPS, where this way of delimiting is recognized by \LATEX\ users.
+%D
+%D The third, more original alternative, is the one using \type {<<} and \type {>>}
+%D as delimiters. This alternative can be used in situations where slanted
+%D typeseting is needed.
%D
-%D The third, more original alternative, is the one using
-%D \type{<<} and \type{>>} as delimiters. This alternative can
-%D be used in situations where slanted typeseting is needed.
-
%D \macros
%D {type}
%D
-%D We define \type{\type} as a protected command. This command
-%D has several invocations: grouped, wirt boundary characters,
-%D and with font switches.
+%D We define \type {\type} as a protected command. This command has several
+%D invocations: grouped, wirt boundary characters, and with font switches.
%D
%D \starttyping
%D normal: \par \type{xx<<..xx..<<xx <<xx>> >>..>>xx} \par \type<<....>> \par \type<<..<<xx>>..>> \par
@@ -234,17 +228,14 @@
%D none: \par \type{xx<<..xx..<<xx <<xx>> >>..>>xx} \par \type<<....>> \par \type<<..<<xx>>..>> \par
%D \stoptyping
%D
-%D When writing the manual to \CONTEXT\ and documenting this
-%D source we needed to typeset \type{<<} and \type{>>}. Because
-%D we wanted to do this in the natural way, we've adapted the
-%D original definition a bit. This implementation went through
-%D several live cycles. The final implementation looks a bit
-%D further and treats the lone \type{<<} and \type{>>} a bit
-%D different. The \type {\null} prevents ligatures, which
-%D unfortunately turn up in Lucida fonts.
+%D When writing the manual to \CONTEXT\ and documenting this source we needed to
+%D typeset \type {<<} and \type {>>}. Because we wanted to do this in the natural
+%D way, we've adapted the original definition a bit. This implementation went
+%D through several live cycles. The final implementation looks a bit further and
+%D treats the lone \type {<<} and \type {>>} a bit different. The \type {\null}
+%D prevents ligatures, which unfortunately turn up in Lucida fonts.
%D
-%D The following lines show what happens when we set
-%D \type {option=commands}.
+%D The following lines show what happens when we set \type {option=commands}.
%D
%D \startbuffer
%D \starttyping
@@ -261,9 +252,8 @@
%D
%D \typebuffer
-% Beware, the command is supposed to do something like \framed and not
-% manipulate content i.e. it gets no argument but something b/egrouped
-% instead:
+% Beware, the command is supposed to do something like \framed and not manipulate
+% content i.e. it gets no argument but something b/egrouped instead:
\def\buff_verbatim_left_of_type
{\typeparameter\c!left
@@ -286,10 +276,6 @@
{\setupcurrenttype[#1]%
\buff_verbatim_type_nop}
-\def\buff_verbatim_type_nop
- {\buff_verbatim_left_of_type
- \futurelet\next\buff_verbatim_type_one}
-
\def\buff_verbatim_typ#1%
{\dontleavehmode
\bgroup
@@ -298,6 +284,10 @@
\let\specialobeyedspace\specialstretchedspace
\doifelsenextoptionalcs\buff_verbatim_type_yes\buff_verbatim_type_nop}
+\def\buff_verbatim_type_nop
+ {\buff_verbatim_left_of_type
+ \futurelet\next\buff_verbatim_type_one}
+
\def\buff_verbatim_type_one
{\ifx\next\bgroup
\expandafter\buff_verbatim_type_a
@@ -379,12 +369,11 @@
%D \macros
%D {obeyhyphens,obeybreakpoints}
%D
-%D Although it's not clear from the macros, one character
-%D trait of this macros, which are build on top of the support
-%D module, is that they don't hyphenate. We therefore offer
-%D the alternative \type{\typ}. The current implementation
-%D works all right, but a decent hyphenation support of
-%D \type{\tt} text will be implemented soon.
+%D Although it's not clear from the macros, one character trait of this macros,
+%D which are build on top of the support module, is that they don't hyphenate. We
+%D therefore offer the alternative \type{\typ}. The current implementation works all
+%D right, but a decent hyphenation support of \type{\tt} text will be implemented
+%D soon.
\unexpanded\def\specialfixedspace {\kern\interwordspace\relax}
\unexpanded\def\specialobeyedspace {\hskip\interwordspace\relax} % better than spaceskip
@@ -418,13 +407,11 @@
%D \macros
%D {tex,arg,mat,dis,astype}
%D
-%D Sometimes, for instance when we pass verbatim text as an
-%D argument, the fixed \CATCODES\ interfere with our wishes. An
-%D experimental implementation of character by character
-%D processing of verbatim text did overcome this limitation,
-%D but we've decided not to use that slow and sometimes
-%D troublesome solution. Instead we stick to some 'old'
-%D \CONTEXT\ macros for typesetting typical \TEX\ characters.
+%D Sometimes, for instance when we pass verbatim text as an argument, the fixed
+%D \CATCODES\ interfere with our wishes. An experimental implementation of character
+%D by character processing of verbatim text did overcome this limitation, but we've
+%D decided not to use that slow and sometimes troublesome solution. Instead we stick
+%D to some 'old' \CONTEXT\ macros for typesetting typical \TEX\ characters.
\def\lesscharacter {<} % obsolete
\def\morecharacter {>} % obsolete
@@ -502,12 +489,25 @@
\buff_verbatim_setup_keep_together
\normalexpanded{\buff_verbatim_type_block{\e!start\currenttyping}{\e!stop\currenttyping}}}
+% \def\buff_verbatim_typing_start_yes[#1]%
+% {\typingparameter\c!before
+% \startpacked[\v!blank]%
+% \doifelseassignment{#1}
+% {\setupcurrenttyping[#1]}
+% {\doif\v!continue{#1}{\lettypingparameter\c!continue\v!yes}}%
+% \buff_verbatim_setup_line_numbering
+% \buff_verbatim_initialize_typing_one
+% \buff_verbatim_setup_keep_together
+% \normalexpanded{\buff_verbatim_type_block{\e!start\currenttyping}{\e!stop\currenttyping}}}
+
\def\buff_verbatim_typing_start_yes[#1]%
{\typingparameter\c!before
\startpacked[\v!blank]%
- \doifelseassignment{#1}
- {\setupcurrenttyping[#1]}
- {\doif\v!continue{#1}{\lettypingparameter\c!continue\v!yes}}%
+ \ifcondition\validassignment{#1}%
+ \setupcurrenttyping[#1]%
+ \else
+ \doif\v!continue{#1}{\lettypingparameter\c!continue\v!yes}%
+ \fi
\buff_verbatim_setup_line_numbering
\buff_verbatim_initialize_typing_one
\buff_verbatim_setup_keep_together
@@ -549,8 +549,8 @@
\endgroup
\dorechecknextindentation}
-%D Line numbering for files is combined with filtering, while
-%D display verbatim has the ability to continue.
+%D Line numbering for files is combined with filtering, while display verbatim has
+%D the ability to continue.
%D
%D \starttyping
%D \typefile[numbering=file,start=10,stop=12]{test.tex}
@@ -596,10 +596,9 @@
%D \macros
%D {typefile}
%D
-%D Typesetting files verbatim (for the moment) only supports
-%D colorization of \TEX\ sources as valid option. The other
-%D setup values are inherited from display verbatim.
-%D The implementation of \type{\typefile} is straightforward:
+%D Typesetting files verbatim (for the moment) only supports colorization of \TEX\
+%D sources as valid option. The other setup values are inherited from display
+%D verbatim. The implementation of \type {\typefile} is straightforward:
% [category] [settings] {name} % for historic reasons, all filenames are {}
@@ -610,20 +609,39 @@
\setuevalue{\e!type\currenttyping\v!file}{\typefile[\currenttyping]}%
\to \everydefinetyping
+% \def\buff_verbatim_type_file[#1][#2]#3%
+% {\begingroup
+% \ifsecondargument
+% \setuptyping[#1][#2]%
+% \buff_verbatim_type_file_checked{#1}{#3}%
+% \else\iffirstargument
+% \doifelseassignment{#1}
+% {\setuptyping[\v!file][#1]%
+% \buff_verbatim_type_file_checked\v!file{#3}}
+% {\buff_verbatim_type_file_checked{#1}{#3}}%
+% \else
+% \buff_verbatim_type_file_checked\v!file{#3}%
+% \fi\fi
+% \endgroup}
+
\def\buff_verbatim_type_file[#1][#2]#3%
{\begingroup
\ifsecondargument
\setuptyping[#1][#2]%
\buff_verbatim_type_file_checked{#1}{#3}%
\else\iffirstargument
- \doifelseassignment{#1}
- {\setuptyping[\v!file][#1]
- \buff_verbatim_type_file_checked\v!file{#3}}
- {\buff_verbatim_type_file_checked{#1}{#3}}%
+ \ifcondition\validassignment{#1}%
+ \setuptyping[\v!file][#1]%
+ \buff_verbatim_type_file_checked\v!file{#3}%
+ \else
+ \buff_verbatim_type_file_checked{#1}{#3}%
+ \fi
\else
\buff_verbatim_type_file_checked\v!file{#3}%
\fi\fi
- \endgroup}
+ \useindentnextparameter\typingparameter % needs checking
+ \endgroup
+ \dorechecknextindentation} % needs checking
\def\buff_verbatim_type_file_checked#1#2%
{\doifelsetypingfile{#2}
@@ -721,10 +739,9 @@
\unexpanded\def\verbatim#1{\detokenize{#1}}
-%D The setups for display verbatim and file verbatim are
-%D shared. One can adapt the extra defined typing environments,
-%D but they also default to the values below. Watch the
-%D alternative escape character.
+%D The setups for display verbatim and file verbatim are shared. One can adapt the
+%D extra defined typing environments, but they also default to the values below.
+%D Watch the alternative escape character.
% \tttf gives problems with {\tx \type...}
% \tt\tf does not adapt to e.g. \bf
@@ -806,19 +823,36 @@
\setuevalue{\e!type\currenttyping\v!buffer}{\buff_verbatim_type_buffer_class{\currenttyping}}%
\to \everydefinetyping
+% \unexpanded\def\buff_verbatim_type_buffer[#1][#2]%
+% {\ifsecondargument
+% \setupcurrenttyping[#2]%
+% \processcommalist[#1]{\buff_verbatim_type_buffer_indeed\currenttyping}% [name] [settings]
+% \else\iffirstargument
+% \doifelseassignment{#1}
+% {\setupcurrenttyping[#1]%
+% \buff_verbatim_type_buffer_indeed\currenttyping\empty}% [settings]
+% {\processcommalist[#1]{\buff_verbatim_type_buffer_indeed\currenttyping}}% [name]
+% \else
+% \buff_verbatim_type_buffer_indeed\currenttyping\empty% []
+% \fi\fi
+% \endgroup}
+
\unexpanded\def\buff_verbatim_type_buffer[#1][#2]%
{\ifsecondargument
\setupcurrenttyping[#2]%
\processcommalist[#1]{\buff_verbatim_type_buffer_indeed\currenttyping}% [name] [settings]
\else\iffirstargument
- \doifelseassignment{#1}
- {\setupcurrenttyping[#1]%
- \buff_verbatim_type_buffer_indeed\currenttyping\empty}% [settings]
- {\processcommalist[#1]{\buff_verbatim_type_buffer_indeed\currenttyping}}% [name]
+ \ifcondition\validassignment{#1}%
+ \setupcurrenttyping[#1]%
+ \buff_verbatim_type_buffer_indeed\currenttyping\empty% [settings]
+ \else
+ \processcommalist[#1]{\buff_verbatim_type_buffer_indeed\currenttyping}% [name]
+ \fi
\else
\buff_verbatim_type_buffer_indeed\currenttyping\empty% []
\fi\fi
- \endgroup}
+ \endgroup
+ \dorechecknextindentation}
\unexpanded\def\buff_verbatim_type_buffer_class#1%
{\begingroup
@@ -857,7 +891,8 @@
\endofverbatimlines
\dostoptagged
\stoppacked
- \typingparameter\c!after}
+ \typingparameter\c!after
+ \dorechecknextindentation}
\unexpanded\def\typeinlinebuffer
{\dontleavehmode
@@ -891,16 +926,33 @@
{\writestatus{nota bene}{\string\processbuffer\space is obsolete}%
\dodoubleempty\buff_verbatim_process}
+% \def\buff_verbatim_process[#1][#2]%
+% {\begingroup
+% \ifsecondargument
+% \setuptyping[\v!buffer][#2]%
+% \processcommalist[#1]{\buff_verbatim_process_indeed\v!buffer}% [name] [settings]
+% \else\iffirstargument
+% \doifelseassignment{#1}
+% {\setuptyping[\v!buffer][#1]%
+% \buff_verbatim_process_indeed\v!buffer\empty}% [settings]
+% {\processcommalist[#1]{\buff_verbatim_process_indeed\v!buffer}}% [name]
+% \else
+% \buff_verbatim_process_indeed\v!buffer\empty% []
+% \fi\fi
+% \endgroup}
+
\def\buff_verbatim_process[#1][#2]%
{\begingroup
\ifsecondargument
\setuptyping[\v!buffer][#2]%
\processcommalist[#1]{\buff_verbatim_process_indeed\v!buffer}% [name] [settings]
\else\iffirstargument
- \doifelseassignment{#1}
- {\setuptyping[\v!buffer][#1]%
- \buff_verbatim_process_indeed\v!buffer\empty}% [settings]
- {\processcommalist[#1]{\buff_verbatim_process_indeed\v!buffer}}% [name]
+ \ifcondition\validassignment{#1}%
+ \setuptyping[\v!buffer][#1]%
+ \buff_verbatim_process_indeed\v!buffer\empty% [settings]
+ \else
+ \processcommalist[#1]{\buff_verbatim_process_indeed\v!buffer}% [name]
+ \fi
\else
\buff_verbatim_process_indeed\v!buffer\empty% []
\fi\fi
@@ -949,7 +1001,7 @@
\else
\blank[\typingparameter\c!blank]%
\fi
- \dostarttagged\t!verbatimlines\empty}
+ \dostarttagged\t!verbatimlines\empty}
% hooks:
diff --git a/Master/texmf-dist/tex/context/base/mkiv/buff-ver.mkxl b/Master/texmf-dist/tex/context/base/mkiv/buff-ver.mkxl
new file mode 100644
index 00000000000..dec4dfb4a02
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/buff-ver.mkxl
@@ -0,0 +1,1005 @@
+%D \module
+%D [ file=buff-ver, % was core-ver
+%D version=2000.05.09,
+%D title=\CONTEXT\ Buffer Macros,
+%D subtitle=Verbatim,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% check after-first and before-last breaks
+
+\writestatus{loading}{ConTeXt Buffer Macros / Verbatim}
+
+\registerctxluafile{buff-ver}{}
+
+\unprotect
+
+\startcontextdefinitioncode
+
+\definesystemattribute[verbatimline][public]
+
+\appendtoksonce
+ \attribute\verbatimlineattribute\attributeunsetvalue
+\to \everyforgetall
+
+%D Initializations.
+
+\installcorenamespace{typinglines}
+\installcorenamespace{typingspace}
+\installcorenamespace{typingblank} % needs checking ... used?
+
+\newtoks\everyinitializeverbatim
+
+\appendtoks
+ \the\everyresettypesetting
+ \resetfontfeature
+ \resetcharacterspacing
+\to \everyinitializeverbatim
+
+\unexpanded\def\setverbatimspaceskip % to be checked: must happen after font switch
+ {\spaceskip\fontcharwd\font`x\relax
+ \xspaceskip\spaceskip}
+
+\setvalue{\??typinglines\v!no }{\buff_verbatim_ignore_hyphens}
+\setvalue{\??typinglines\v!normal }{\buff_verbatim_ignore_hyphens}
+\setvalue{\??typinglines\v!yes }{\buff_verbatim_obey_breakpoints}
+\setvalue{\??typinglines\v!hyphenated}{\buff_verbatim_obey_hyphens}
+
+\setvalue{\??typingspace\v!on }{\let\obeyedspace\specialcontrolspace}
+\setvalue{\??typingspace\v!stretch }{\let\obeyedspace\specialstretchedspace}
+\setvalue{\??typingspace\v!normal }{}
+\setvalue{\??typingspace\v!fixed }{\let\obeyedspace\specialfixedspace}
+
+\setvalue{\??typingblank\v!standard }{\s_spac_whitespace_parskip}
+\setvalue{\??typingblank\v!small }{\smallskipamount}
+\setvalue{\??typingblank\v!medium }{\medskipamount}
+\setvalue{\??typingblank\v!big }{\bigskipamount}
+\setvalue{\??typingblank\v!halfline }{.5\baselineskip}
+\setvalue{\??typingblank\v!line }{\baselineskip}
+\setvalue{\??typingblank\v!none }{\zeropoint}
+
+\unexpanded\def\buff_verbatim_obey_hyphens
+ {}
+
+\unexpanded\def\buff_verbatim_obey_breakpoints
+ {\language\minusone % tricky as this affects the pagebuilder
+ \veryraggedright}
+
+\unexpanded\def\buff_verbatim_ignore_hyphens
+ {\language\minusone} % tricky as this affects the pagebuilder
+
+\def\buff_verbatim_initialize_type_one
+ {\let\obeylines\ignorelines
+ \edef\p_buff_option{\typeparameter\c!option}%
+ \ifx\p_buff_option\v!none
+ \usetypestyleandcolor\c!style\c!color
+ \orelse\ifx\p_buff_option\empty
+ \usetypestyleandcolor\c!style\c!color
+ \else
+ \usetypestyleparameter\c!style % no color
+ \fi
+ \setcatcodetable\vrbcatcodes}
+
+\def\buff_verbatim_initialize_type_two
+ {\spaceskip.5\emwidth\relax
+ \let\obeyedspace\specialobeyedspace
+ \let\controlspace\specialcontrolspace
+ \edef\p_buff_lines{\typeparameter\c!lines}%
+ \begincsname\??typinglines\p_buff_lines\endcsname
+ \edef\p_buff_space{\typeparameter\c!space}%
+ \begincsname\??typingspace\p_buff_space\endcsname
+ \relax\the\everyinitializeverbatim\relax}
+
+\unexpanded\def\doinitializeverbatim % for use elsewhere .. temp hack (see lxml-ini)
+ {\buff_verbatim_initialize_type_one
+ \buff_verbatim_initialize_type_two}
+
+\let\buff_verbatim_set_line_margin\relax
+
+\def\buff_verbatim_set_line_margin_indeed
+ {\hskip\doifelseoddpage{\typingparameter\c!oddmargin}{\typingparameter\c!evenmargin}\relax}
+
+\def\buff_verbatim_initialize_typing_one
+ {\usebodyfontparameter\typingparameter
+ \scratchskip\typingparameter\c!oddmargin\relax
+ \ifzeropt\scratchskip \else
+ \let\buff_verbatim_set_line_margin\buff_verbatim_set_line_margin_indeed
+ \fi
+ \scratchskip\typingparameter\c!evenmargin\relax
+ \ifzeropt\scratchskip \else
+ \let\buff_verbatim_set_line_margin\buff_verbatim_set_line_margin_indeed
+ \fi
+ \ifx\buff_verbatim_set_line_margin\relax
+ \doadaptleftskip{\typingparameter\c!margin}%
+ \fi
+ \edef\p_buff_option{\typingparameter\c!option}%
+ \ifx\p_buff_option\v!none
+ \usetypingstyleandcolor\c!style\c!color
+ \orelse\ifx\p_buff_option\empty
+ \usetypingstyleandcolor\c!style\c!color
+ \else
+ \usetypingstyleparameter\c!style % no color !
+ \fi
+ \usealignparameter\typingparameter}
+
+\def\buff_verbatim_initialize_typing_two
+ {\spaceskip.5\emwidth\relax
+ \let\obeyedspace\specialobeyedspace
+ \let\controlspace\specialcontrolspace
+ \edef\p_buff_lines{\typingparameter\c!lines}%
+ \begincsname\??typinglines\p_buff_lines\endcsname
+ \edef\p_buff_space{\typingparameter\c!space}%
+ \begincsname\??typingspace\p_buff_space\endcsname
+ \relax\the\everyinitializeverbatim\relax}
+
+%D \macros
+%D {definetype,setuptype}
+%D
+%D Specific inline verbatim commands can be defined with the following command.
+
+\installcorenamespace{type}
+
+\installcommandhandler \??type {type} \??type
+
+\appendtoks
+ \setuevalue{\currenttype}{\buff_verbatim_type{\currenttype}}%
+\to \everydefinetype
+
+\appendtoks
+ \buff_verbatim_initialize_visualizer{\typeparameter\c!option}%
+\to \everysetuptype
+
+%D \macros
+%D {definetyping,setuptyping}
+%D
+%D For most users the standard \type {\start}||\type {\stop}||pair will suffice, but
+%D for documentation purposes the next definition command can be of use:
+%D
+%D \starttyping
+%D \definetyping[extratyping][margin=3em]
+%D
+%D \startextratyping
+%D these extra ones are indented by 1 em
+%D \stopextratyping
+%D \stoptyping
+%D
+%D The definitions default to the standard typing values.
+
+\installcorenamespace{typing}
+
+\installcommandhandler \??typing {typing} \??typing
+
+\appendtoks
+ \setuevalue{\e!start\currenttyping}{\buff_verbatim_typing_start{\currenttyping}}%
+ \setuevalue{\e!stop \currenttyping}{\buff_verbatim_typing_stop {\currenttyping}}%
+ \ifx\currenttypingparent\empty
+ \normalexpanded{\definelinenumbering[\currenttyping]}%
+ \else
+ \normalexpanded{\definelinenumbering[\currenttyping][\currenttypingparent]}%
+ \fi
+\to \everydefinetyping
+
+\appendtoks
+ \buff_verbatim_initialize_visualizer{\typingparameter\c!option}% we can check at the tex end
+\to \everysetuptyping
+
+\def\buff_verbatim_initialize_visualizer#1%
+ {\ifproductionrun\clf_loadvisualizer{#1}\fi}
+
+\unexpanded\def\doifelsevisualizer#1%
+ {\clf_doifelsevisualizer{#1}}
+
+\let\doifvisualizerelse\doifelsevisualizer
+
+%D Verbatim command are very sensitive to argument processing, which is a direct
+%D result of the \CATCODES\ being fixed at reading time.
+%D
+%D Typesetting inline verbatim can be accomplished by \type {\type}, which in this
+%D sentence was typeset by saying just \type {\type {\type}}, which in turn was
+%D typeset by \unknown. Using the normal grouping characters \type {{}} is the most
+%D natural way of using this command.
+%D
+%D A second, more or less redundant, alternative is delimiting the argument with an
+%D own character. This method was implemented in the context of a publication in the
+%D \MAPS, where this way of delimiting is recognized by \LATEX\ users.
+%D
+%D The third, more original alternative, is the one using \type {<<} and \type {>>}
+%D as delimiters. This alternative can be used in situations where slanted
+%D typeseting is needed.
+%D
+%D \macros
+%D {type}
+%D
+%D We define \type {\type} as a protected command. This command has several
+%D invocations: grouped, wirt boundary characters, and with font switches.
+%D
+%D \starttyping
+%D normal: \par \type{xx<<..xx..<<xx <<xx>> >>..>>xx} \par \type<<....>> \par \type<<..<<xx>>..>> \par
+%D normal: \par \type{xx<..xx..<xx <slanted> >..>xx} \par \type{<....>} \par \type{<..<xx>..>}
+%D \setuptype[option=slanted]
+%D slanted: \par \type{xx<<..sl..<<xx <<sl>> xx>>..sl..>>xx} \par \type<<..xx..>> \par \type<<..<<sl>>..>> \par
+%D slanted: \par \type{xx<<..sl..<xx <sl> xx>..sl..>>xx} \par \type<<..xx..>> \par \type<<..<sl>..>> \par
+%D \setuptype[option=none]
+%D none: \par \type{xx<<..xx..<<xx <<xx>> >>..>>xx} \par \type<<....>> \par \type<<..<<xx>>..>> \par
+%D \stoptyping
+%D
+%D When writing the manual to \CONTEXT\ and documenting this source we needed to
+%D typeset \type {<<} and \type {>>}. Because we wanted to do this in the natural
+%D way, we've adapted the original definition a bit. This implementation went
+%D through several live cycles. The final implementation looks a bit further and
+%D treats the lone \type {<<} and \type {>>} a bit different. The \type {\null}
+%D prevents ligatures, which unfortunately turn up in Lucida fonts.
+%D
+%D The following lines show what happens when we set \type {option=commands}.
+%D
+%D \startbuffer
+%D \starttyping
+%D test//test test/BTEX \footnote{test test test}/ETEX test
+%D test//test test/BTEX \footnote{test test test}/ETEX test
+%D test test test/BTEX \bf(nota bene)/ETEX test
+%D test test test /BTEX \bf(nota bene)/ETEX test
+%D \stoptyping
+%D \stopbuffer
+%D
+%D % \bgroup\setuptyping[option=commands]\getbuffer\egroup
+%D
+%D this was keyed in as:
+%D
+%D \typebuffer
+
+% Beware, the command is supposed to do something like \framed and not manipulate
+% content i.e. it gets no argument but something b/egrouped instead:
+
+\def\buff_verbatim_left_of_type
+ {\typeparameter\c!left
+ \typeparameter\c!command\bgroup}
+
+\def\buff_verbatim_right_of_type
+ {\egroup
+ \typeparameter\c!right}
+
+\unexpanded\def\type{\buff_verbatim_type\empty}
+\unexpanded\def\typ {\buff_verbatim_typ \empty}
+
+\unexpanded\def\buff_verbatim_type#1%
+ {\dontleavehmode
+ \bgroup
+ \edef\currenttype{#1}%
+ \doifelsenextoptionalcs\buff_verbatim_type_yes\buff_verbatim_type_nop}
+
+\def\buff_verbatim_type_yes[#1]%
+ {\setupcurrenttype[#1]%
+ \buff_verbatim_type_nop}
+
+\def\buff_verbatim_typ#1%
+ {\dontleavehmode
+ \bgroup
+ \edef\currenttype{#1}%
+ \lettypeparameter\c!lines\v!hyphenated
+ \let\specialobeyedspace\specialstretchedspace
+ \doifelsenextoptionalcs\buff_verbatim_type_yes\buff_verbatim_type_nop}
+
+\def\buff_verbatim_type_nop
+ {\buff_verbatim_left_of_type
+ \futureexpand\bgroup\buff_verbatim_type_a\buff_verbatim_type_one}
+
+\def\buff_verbatim_type_one
+ {\catcode`<=\othercatcode % old precaution
+ \catcode`>=\othercatcode % old precaution
+ \futureexpandis<\buff_verbatim_type_b\buff_verbatim_type_c}
+
+\def\buff_verbatim_type_three
+ {\if\next<%
+ \expandafter\buff_verbatim_type_b
+ \else
+ \expandafter\buff_verbatim_type_c
+ \fi}
+
+\def\buff_verbatim_type_a
+ {\buff_verbatim_initialize_type_one
+ \setcatcodetable\tpacatcodes
+ \buff_verbatim_type_normal}
+
+\def\buff_verbatim_type_b#1%
+ {\buff_verbatim_initialize_type_one
+ \setcatcodetable\tpbcatcodes
+ \buff_verbatim_type_nested}
+
+\def\buff_verbatim_type_c#1%
+ {\buff_verbatim_initialize_type_one
+ \setcatcodetable\vrbcatcodes
+ \def\next##1#1{\buff_verbatim_type_normal{##1}}%
+ \next}
+
+\def\buff_verbatim_type_normal#1%
+ {\buff_verbatim_initialize_type_two
+ \dostarttaggedchained\t!verbatim\currenttype\??type
+ \clf_type
+ data {\detokenize{#1}}%
+ tab {\typeparameter\c!tab}%
+ method {\p_buff_option}%
+ compact {\typeparameter\c!compact}% % none | all | last (all needed in tabulate etc for manuals)
+ escape {\typeparameter\c!escape}% % new but rather useless imo (escaping in general is not used much)
+ % nature {inline}% is default
+ \relax
+ \dostoptagged
+ \buff_verbatim_right_of_type
+ \egroup}
+
+\def\buff_verbatim_type_nested#1%
+ {\buff_verbatim_initialize_type_two
+ \dostarttaggedchained\t!verbatim\currenttype\??type
+ \clf_type
+ data {\detokenize{#1}}%
+ tab {\typeparameter\c!tab}%
+ method {\p_buff_option}% % extra visualizer (maybe: nested,\typeparameter\c!option)
+ escape {\typeparameter\c!escape}% % new but rather useless imo (escaping in general is not used much)
+ % nature {inline}% is default
+ method {nested}%
+ \relax
+ \dostoptagged
+ \buff_verbatim_right_of_type
+ \egroup
+ \gobbleoneargument} % grab last >
+
+%D The \type {compact} option can come in handy in the case of inline argument passing
+%D
+%D \starttyping
+%D \definetype[TeXcodeA][option=TEX]
+%D \definetype[TeXcodeB][option=TEX,compact=all]
+%D \definetype[TeXcodeC][option=TEX,compact=absolute]
+%D
+%D \def\argA#1{\TeXcodeA{{#1}}}
+%D \def\argB#1{\TeXcodeB{{#1}}}
+%D \def\argC#1{\TeXcodeC{{#1}}}
+%D \stoptyping
+
+%D \macros
+%D {obeyhyphens,obeybreakpoints}
+%D
+%D Although it's not clear from the macros, one character trait of this macros,
+%D which are build on top of the support module, is that they don't hyphenate. We
+%D therefore offer the alternative \type{\typ}. The current implementation works all
+%D right, but a decent hyphenation support of \type{\tt} text will be implemented
+%D soon.
+
+\unexpanded\def\specialfixedspace {\kern\interwordspace\relax}
+\unexpanded\def\specialobeyedspace {\hskip\interwordspace\relax} % better than spaceskip
+\unexpanded\def\specialstretchedspace {\hskip.5\interwordspace\s!plus.125\interwordspace\relax} % \interwordstretch can be zero
+\unexpanded\def\specialcontrolspace {\normalcontrolspace\allowbreak} % uses fallback
+
+\unexpanded\def\explicitfixedspace {\asciispacechar}
+\unexpanded\def\explicitobeyedspace {\asciispacechar\allowbreak}
+\unexpanded\def\explicitstretchedspace{\asciispacechar\hskip\zeropoint\s!plus.125\interwordspace\relax}%
+\unexpanded\def\explicitcontrolspace {\optionalcontrolspace\allowbreak} % uses asciispace
+
+\appendtoks
+ \unexpanded\def\obeyedspace{\hskip\zeropoint\asciispacechar\hskip\zeropoint}%
+\to \everyenableelements
+
+\unexpanded\def\obeyhyphens
+ {\let\obeyedspace \specialobeyedspace % maybe \specialstretchedspace
+ \let\controlspace\specialcontrolspace
+ \spaceskip.25\emwidth\relax} % hm a bit of stretch !
+
+\unexpanded\def\obeybreakpoints
+ {\ignorehyphens
+ \veryraggedright}
+
+\unexpanded\def\ignorehyphens
+ {\language\minusone % extra bonus, the \null should do the job too
+ \let\obeyedspace \specialobeyedspace
+ \let\controlspace\specialcontrolspace
+ \spaceskip.5\emwidth\relax}
+
+%D \macros
+%D {tex,arg,mat,dis,astype}
+%D
+%D Sometimes, for instance when we pass verbatim text as an argument, the fixed
+%D \CATCODES\ interfere with our wishes. An experimental implementation of character
+%D by character processing of verbatim text did overcome this limitation, but we've
+%D decided not to use that slow and sometimes troublesome solution. Instead we stick
+%D to some 'old' \CONTEXT\ macros for typesetting typical \TEX\ characters.
+
+\def\lesscharacter {<} % obsolete
+\def\morecharacter {>} % obsolete
+
+\let\texescape \textbackslash
+\let\leftargument \textbraceleft
+\let\rightargument \textbraceright
+\let\inlinemathmarker \textdollar
+\def\displaymathmarker{\textdollar\textdollar}
+
+\def\buff_verbatim_special_type#1#2#% # gobbles spaces
+ {\dontleavehmode\bgroup
+ \buff_verbatim_initialize_type_one
+ \catcode\leftbraceasciicode \begingroupcatcode
+ \catcode\rightbraceasciicode\endgroupcatcode
+ #1%
+ \bgroup % else wrong font for #2
+ \aftergroup#2%
+ \aftergroup\egroup
+ \let\nexttoken}
+
+\unexpanded\def\tex{\buff_verbatim_special_type\texescape \relax}
+\unexpanded\def\arg{\buff_verbatim_special_type\leftargument \rightargument}
+\unexpanded\def\mat{\buff_verbatim_special_type\inlinemathmarker \inlinemathmarker}
+\unexpanded\def\dis{\buff_verbatim_special_type\displaymathmarker\displaymathmarker}
+
+\let\normaltexttex\tex
+\let\normaltextarg\arg
+\let\normaltextmat\mat
+\let\normaltextdis\dis
+
+\unexpanded\def\astype
+ {\dontleavehmode
+ \bgroup\usetypestyleandcolor\c!style\c!color\let\nexttoken}
+
+\unexpanded\def\asciistr#1% used in some old styles
+ {\dontleavehmode\begingroup
+ \dostarttagged\t!verbatim\empty
+ \usetypestyleandcolor\c!style\c!color\detokenize{#1}%
+ \dostoptagged
+ \endgroup}
+
+%D The basic display verbatim commands are defined in an indirect way. As we
+%D will see, they are a specific case of a more general mechanism.
+
+\let\beginofverbatimlines\relax % hooks
+\let\endofverbatimlines \relax % hooks
+
+\unexpanded\def\buff_verbatim_typing_start#1% tricky non standard lookahead
+ {\begingroup
+ \edef\currenttyping{#1}%
+ \obeylines
+ \futureexpandis[\buff_verbatim_typing_start_yes\buff_verbatim_typing_start_nop}
+
+\unexpanded\def\buff_verbatim_setup_keep_together
+ {\edef\p_keeptogether{\typingparameter\c!keeptogether}%
+ \ifx\p_keeptogether\v!yes
+ \settrue \c_buff_optimize_linebreaks
+ \else
+ \setfalse\c_buff_optimize_linebreaks
+ \fi}
+
+\def\buff_verbatim_typing_start_nop
+ {\typingparameter\c!before
+ \startpacked[\v!blank]%
+ \buff_verbatim_setup_line_numbering
+ \buff_verbatim_initialize_typing_one
+ \buff_verbatim_setup_keep_together
+ \normalexpanded{\buff_verbatim_type_block{\e!start\currenttyping}{\e!stop\currenttyping}}}
+
+\def\buff_verbatim_typing_start_yes[#1]%
+ {\typingparameter\c!before
+ \startpacked[\v!blank]%
+ \ifcondition\validassignment{#1}%
+ \setupcurrenttyping[#1]%
+ \else
+ \doif\v!continue{#1}{\lettypingparameter\c!continue\v!yes}%
+ \fi
+ \buff_verbatim_setup_line_numbering
+ \buff_verbatim_initialize_typing_one
+ \buff_verbatim_setup_keep_together
+ \normalexpanded{\buff_verbatim_type_block{\e!start\currenttyping}{\e!stop\currenttyping}}}
+
+\unexpanded\def\buff_verbatim_type_block#1#2%
+ {\edef\p_strip{\typingparameter\c!strip}%
+ \normalexpanded{\buff_pickup
+ {_typing_}%
+ {#1}%
+ {#2}%
+ {}%
+ {\buff_verbatim_type_block_verbatim_indeed{#1}{#2}}%
+ \ifx\p_strip\v!no\zerocount\else\plusone\fi}}
+
+\unexpanded\def\buff_verbatim_type_block_verbatim_indeed#1#2%
+ {\buff_verbatim_initialize_typing_two
+ \dostarttaggedchained\t!verbatimblock\currenttyping\??typing
+ \beginofverbatimlines
+ \dostarttagged\t!verbatimlines\empty
+ \clf_typebuffer
+ name {_typing_}%
+ strip {\typingparameter\c!strip}%
+ range {\typingparameter\c!range}%
+ tab {\typingparameter\c!tab}%
+ method {\p_buff_option}%
+ escape {\typingparameter\c!escape}%
+ nature {display}%
+ \relax
+ \dostoptagged
+ \endofverbatimlines
+ \dostoptagged
+ \begincsname#2\endcsname}
+
+\unexpanded\def\buff_verbatim_typing_stop#1% hm, currenttyping
+ {\stoppacked
+ \typingparameter\c!after
+ \useindentnextparameter\typingparameter
+ \endgroup
+ \dorechecknextindentation}
+
+%D Line numbering for files is combined with filtering, while display verbatim has
+%D the ability to continue.
+%D
+%D \starttyping
+%D \typefile[numbering=file,start=10,stop=12]{test.tex}
+%D
+%D \definetyping[code][numbering=line]
+%D
+%D \starttext
+%D \startcode
+%D ...
+%D ...
+%D \stopcode
+%D
+%D \startcode[start=continue]
+%D ...
+%D ...
+%D \stopcode
+%D
+%D \startcode[start=10]
+%D ...
+%D \stopcode
+%D \stoptyping
+
+%D Ranges:
+%D
+%D \starttyping
+%D % label:start:one
+%D
+%D \def\MyMacro
+%D {just an example}
+%D
+%D % label:stop:one
+%D
+%D \starttext
+%D
+%D % \typefile[file][range={3,6}] {whatever.tex}
+%D % \typefile[file][range={3,+2}]{whatever.tex}
+%D
+%D \typefile[file][range={label:start:one,label:stop:one}]{whatever.tex}
+%D
+%D \stoptext
+%D \stoptyping
+
+%D \macros
+%D {typefile}
+%D
+%D Typesetting files verbatim (for the moment) only supports colorization of \TEX\
+%D sources as valid option. The other setup values are inherited from display
+%D verbatim. The implementation of \type {\typefile} is straightforward:
+
+% [category] [settings] {name} % for historic reasons, all filenames are {}
+
+\unexpanded\def\typefile
+ {\dodoubleempty\buff_verbatim_type_file}
+
+\appendtoks
+ \setuevalue{\e!type\currenttyping\v!file}{\typefile[\currenttyping]}%
+\to \everydefinetyping
+
+\def\buff_verbatim_type_file[#1][#2]#3%
+ {\begingroup
+ \ifsecondargument
+ \setuptyping[#1][#2]%
+ \buff_verbatim_type_file_checked{#1}{#3}%
+ \orelse\iffirstargument
+ \ifcondition\validassignment{#1}%
+ \setuptyping[\v!file][#1]%
+ \buff_verbatim_type_file_checked\v!file{#3}%
+ \else
+ \buff_verbatim_type_file_checked{#1}{#3}%
+ \fi
+ \else
+ \buff_verbatim_type_file_checked\v!file{#3}%
+ \fi
+ \useindentnextparameter\typingparameter % needs checking
+ \endgroup
+ \dorechecknextindentation} % needs checking
+
+\def\buff_verbatim_type_file_checked#1#2%
+ {\doifelsetypingfile{#2}
+ {\buff_verbatim_type_file_indeed{#1}\askedtypingfile}
+ {\showmessage\m!verbatims1{#2}}}
+
+\unexpanded\def\doifelsetypingfile#1%
+ {\edef\askedtypingfile{\locfilename{#1}}%
+ \ifx\askedtypingfile\empty
+ \edef\askedtypingfile{\locfilename{#1.tex}}% downward compatible
+ \fi
+ \ifx\askedtypingfile\empty
+ \expandafter\secondoftwoarguments
+ \else
+ \expandafter\firstoftwoarguments
+ \fi}
+
+\let\doiftypingfileelse\doifelsetypingfile
+
+\def\buff_verbatim_type_file_indeed#1#2% category name
+ {\edef\currenttyping{#1}%
+ \typingparameter\c!before
+ \startpacked[\v!blank]
+ \buff_verbatim_setup_line_numbering
+ \buff_verbatim_initialize_typing_one
+ \buff_verbatim_initialize_typing_two
+ \dostarttaggedchained\t!verbatimblock\currenttyping\??typing
+ \beginofverbatimlines
+ \dostarttagged\t!verbatimlines\empty
+ \clf_typefile
+ name {#2}%
+ strip {\typingparameter\c!strip}%
+ range {\typingparameter\c!range}%
+ regime {\currentregime}%
+ tab {\typingparameter\c!tab}%
+ method {\p_buff_option}%
+ nature {display}%
+ \relax
+ \dostoptagged
+ \endofverbatimlines
+ \dostoptagged
+ \stoppacked
+ \typingparameter\c!after}
+
+%D Line numbering:
+
+\newconditional\verbatimnumberinglines
+
+\def\beginofverbatimlinenumbering
+ {\startlinenumbering
+ [\currenttyping]%
+ [\c!continue=\typingparameter\c!continue,
+ \c!method=\v!type,
+ \c!start=\typingparameter\c!start,
+ \c!stop=\typingparameter\c!stop, % ?
+ \c!step=\typingparameter\c!step]}
+
+\def\endofverbatimlinenumbering
+ {\stoplinenumbering}
+
+\def\buff_verbatim_setup_line_numbering
+ {\ifdefined\startlinenumbering
+ \edef\currenttypingnumbering{\typingparameter\c!numbering}%
+ \ifx\currenttypingnumbering\v!file
+ \setuplinenumbering[\currenttyping][\c!method=\v!file]%
+ \settrue\verbatimnumberinglines
+ \orelse\ifx\currenttypingnumbering\v!line
+ \settrue\verbatimnumberinglines
+ \else
+ \setfalse\verbatimnumberinglines
+ \fi
+ \ifconditional\verbatimnumberinglines
+ \let\beginofverbatimlines\beginofverbatimlinenumbering
+ \let\endofverbatimlines \endofverbatimlinenumbering
+ \fi
+ \fi}
+
+%D \macros
+%D {filename}
+%D
+%D Typesetting filenames in monospaced fonts is possible with
+%D
+%D \starttyping
+%D \filename{here/there/filename.suffix}
+%D \stoptyping
+%D
+%D The definition is not that spectacular.
+
+\unexpanded\def\filename#1{{\tttf\hyphenatedfilename{#1}}}
+
+%D \macros
+%D {verbatim}
+%d
+%D And a bonus macro, an unexpanded detokenize:
+
+\unexpanded\def\verbatim#1{\detokenize{#1}}
+
+%D The setups for display verbatim and file verbatim are shared. One can adapt the
+%D extra defined typing environments, but they also default to the values below.
+%D Watch the alternative escape character.
+
+% \tttf gives problems with {\tx \type...}
+% \tt\tf does not adapt to e.g. \bf
+
+\setuptyping
+ [\c!before=\blank,
+ \c!after=\blank,
+ %\c!keeptogether=yes, % this will become default (when tested enough)
+ %\c!bodyfont=,
+ %\c!color=,
+ \c!space=\v!off,
+ \c!lines=\v!no,
+ \c!page=\v!no,
+ \c!tab=\v!yes, % what is this: \s!ascii ?
+ \c!option=\v!none,
+ \c!text=\v!no,
+ \c!style=\tt,
+ \c!indentnext=\v!yes,
+ \c!margin=\zeropoint,
+ \c!evenmargin=\zeropoint,
+ \c!oddmargin=\zeropoint,
+ \c!blank=\v!line,
+ %\c!escape=, % yes | no | {START,STOP} | default when yes: {BTEX,ETEX}
+ \c!numbering=\v!no,
+ %\c!range=,
+ \c!start=1,
+ %\c!stop=,
+ \c!step=1,
+ %\c!continue=,
+ \c!strip=\v!no] % auto or number
+
+\definetyping[\v!typing]
+
+% the \zeropoint forces the number to the margin but also works ok in text
+
+\setuplinenumbering[\v!typing][\c!location=\v!left,\c!width=\zeropoint]
+
+\setuptyping [\v!file] [\s!parent=\??typing \v!typing] % we don't want \start..\stop overload
+\setuplinenumbering[\v!file] [\s!parent=\??linenumbering\v!typing]
+
+\setuptyping [\v!buffer][\s!parent=\??typing \v!file] % we don't want \start..\stop overload
+\setuplinenumbering[\v!buffer][\s!parent=\??linenumbering\v!file]
+
+%D The setups for inline verbatim default to:
+
+\setuptype
+ [\c!space=\v!off,
+ \c!lines=\v!no,
+ %\c!color=,
+ \c!style=\tt,
+ %\c!option=\v!normal,
+ \c!page=\v!no,
+ \c!tab=\v!yes,
+ \c!compact=\v!all]
+
+%D Buffers
+
+% [name] [settings] | [name] | [settings]
+
+% \unexpanded\def\typebuffer
+% {\dodoubleempty\buff_verbatim_type_buffer}
+
+\unexpanded\def\typebuffer
+ {\begingroup
+ \let\currenttyping\v!buffer
+ \dodoubleempty\buff_verbatim_type_buffer}
+
+\unexpanded\def\buff_verbatim_type_defined_buffer
+ {\dotripleempty\buff_verbatim_type_defined_buffer_indeed}
+
+\unexpanded\def\typedefinedbuffer[#1]%
+ {\buff_verbatim_type_defined_buffer[\v!buffer][\thedefinedbuffer{#1}]}%
+
+\appendtoks
+ \setuevalue{\e!type\currentbuffer}{\buff_verbatim_type_defined_buffer[\v!buffer][\currentdefinedbuffer]}%
+\to \everydefinebuffer
+
+\appendtoks % \e!buffer
+ \setuevalue{\e!type\currenttyping\v!buffer}{\buff_verbatim_type_buffer_class{\currenttyping}}%
+\to \everydefinetyping
+
+\unexpanded\def\buff_verbatim_type_buffer[#1][#2]%
+ {\ifsecondargument
+ \setupcurrenttyping[#2]%
+ \processcommalist[#1]{\buff_verbatim_type_buffer_indeed\currenttyping}% [name] [settings]
+ \orelse\iffirstargument
+ \ifcondition\validassignment{#1}%
+ \setupcurrenttyping[#1]%
+ \buff_verbatim_type_buffer_indeed\currenttyping\empty% [settings]
+ \else
+ \processcommalist[#1]{\buff_verbatim_type_buffer_indeed\currenttyping}% [name]
+ \fi
+ \else
+ \buff_verbatim_type_buffer_indeed\currenttyping\empty% []
+ \fi
+ \endgroup
+ \dorechecknextindentation}
+
+\unexpanded\def\buff_verbatim_type_buffer_class#1%
+ {\begingroup
+ \edef\currenttyping{#1}%
+ \dodoubleempty\buff_verbatim_type_buffer}
+
+\unexpanded\def\buff_verbatim_type_defined_buffer_indeed[#1][#2][#3]% category name settings
+ {\begingroup
+ \ifthirdargument
+ \setuptyping[#1][#3]%
+ \fi
+ \buff_verbatim_type_buffer_indeed{#1}{#2}%
+ \endgroup}
+
+\unexpanded\def\buff_verbatim_type_buffer_indeed#1#2% category name
+ {\edef\currenttyping{#1}%
+ \typingparameter\c!before
+ \startpacked[\v!blank]
+ \buff_verbatim_setup_line_numbering
+ \buff_verbatim_initialize_typing_one
+ \buff_verbatim_initialize_typing_two
+ \dostarttaggedchained\t!verbatimblock{#1}\??typing
+ \beginofverbatimlines
+ \dostarttagged\t!verbatimlines\empty
+ \clf_typebuffer
+ name {#2}%
+ strip {\typingparameter\c!strip}%
+ range {\typingparameter\c!range}%
+ regime {\currentregime}%
+ tab {\typingparameter\c!tab}%
+ method {\p_buff_option}%
+ escape {\typingparameter\c!escape}%
+ nature {display}%
+ \relax
+ \dostoptagged
+ \endofverbatimlines
+ \dostoptagged
+ \stoppacked
+ \typingparameter\c!after
+ \dorechecknextindentation}
+
+\unexpanded\def\typeinlinebuffer
+ {\dontleavehmode
+ \begingroup
+ \let\buff_verbatim_type_buffer_indeed\buff_verbatim_type_buffer_indeed_inline
+ \let\setupcurrenttyping\setupcurrenttype % a terrible hack but it saves code
+ \let\currenttype\empty
+ \dodoubleempty\buff_verbatim_type_buffer}
+
+\unexpanded\def\buff_verbatim_type_buffer_indeed_inline#1#2% category name
+ {\edef\currenttype{#1}%
+ \buff_verbatim_initialize_type_one
+ \dostarttaggedchained\t!verbatim\currenttype\??type
+ \clf_typebuffer
+ name {#2}%
+ strip {\v!yes}%
+ regime {\currentregime}%
+ method {\p_buff_option}%
+ nature {inline}% is default anyway
+ \relax
+ \dostoptagged}
+
+% get : before/after of buffer
+% typing : before/after of typing
+% process : no before/after (special case anyway)
+
+% the next one is obsolete (bad name and used nowhere) so if it stays
+% the name will change
+
+\unexpanded\def\processbuffer
+ {\writestatus{nota bene}{\string\processbuffer\space is obsolete}%
+ \dodoubleempty\buff_verbatim_process}
+
+\def\buff_verbatim_process[#1][#2]%
+ {\begingroup
+ \ifsecondargument
+ \setuptyping[\v!buffer][#2]%
+ \processcommalist[#1]{\buff_verbatim_process_indeed\v!buffer}% [name] [settings]
+ \orelse\iffirstargument
+ \ifcondition\validassignment{#1}%
+ \setuptyping[\v!buffer][#1]%
+ \buff_verbatim_process_indeed\v!buffer\empty% [settings]
+ \else
+ \processcommalist[#1]{\buff_verbatim_process_indeed\v!buffer}% [name]
+ \fi
+ \else
+ \buff_verbatim_process_indeed\v!buffer\empty% []
+ \fi
+ \endgroup}
+
+\def\buff_verbatim_process_indeed#1#2%
+ {\edef\currenttyping{#1}%
+ \clf_processbuffer
+ name {#2}%
+ strip {\typingparameter\c!strip}%
+ tab {\typingparameter\c!tab}%
+ % method {\p_buff_option}%
+ nature {direct}%
+ \relax}
+
+% so far for obsolete
+
+% line numbering, keep broken lines together
+
+\newcount\nofverbatimlines
+
+\unexpanded\def\buff_verbatim_begin_of_line
+ {\ifconditional\verbatimnumberinglines
+ \global\advance\nofverbatimlines\plusone
+ \attribute\verbatimlineattribute\nofverbatimlines
+ \fi
+ \noindent
+ \buff_verbatim_set_line_margin
+ \the\everyline % maybe also after starttagged
+ \strut % after starttagged, else break !
+ \dostarttagged\t!verbatimline\empty
+ }
+
+\unexpanded\def\buff_verbatim_end_of_line
+ {\dostoptagged
+ \obeyedline % still needed?
+ \par
+ \ifconditional\verbatimnumberinglines
+ \attribute\verbatimlineattribute\attributeunsetvalue
+ \fi}
+
+\unexpanded\def\buff_verbatim_empty_line
+ {\dostoptagged
+ \ifconditional\verbatimnumberinglines
+ \par\strut\par % this will be an option where we use a signal instead of a strut
+ \else
+ \blank[\typingparameter\c!blank]%
+ \fi
+ \dostarttagged\t!verbatimlines\empty}
+
+% hooks:
+
+\newcount \c_buff_verbatim_noflines
+\newcount \c_buff_verbatim_current
+\newconditional\c_buff_optimize_linebreaks
+
+ \def\doverbatimspace {\obeyedspace}
+
+\unexpanded\def\doinlineverbatimstart {}
+\unexpanded\def\doinlineverbatimstop {}
+\unexpanded\def\doinlineverbatimbeginline {}
+\unexpanded\def\doinlineverbatimnewline {\obeyedspace}
+\unexpanded\def\doinlineverbatimemptyline {\obeyedspace}
+
+\unexpanded\def\dodisplayverbatimstart {\advance\c_buff_verbatim_current\plusone
+ \buff_verbatim_begin_of_line}
+\unexpanded\def\dodisplayverbatimstop {\buff_verbatim_end_of_line}
+\unexpanded\def\dodisplayverbatimbeginline{\advance\c_buff_verbatim_current\plusone
+ \buff_verbatim_begin_of_line}
+\unexpanded\def\dodisplayverbatimnewline {\buff_verbatim_end_of_line
+ \par
+ \ifconditional\c_buff_optimize_linebreaks
+ \buff_verbatim_inject_breaks
+ \fi}
+\unexpanded\def\dodisplayverbatimemptyline{\buff_verbatim_empty_line}
+
+\unexpanded\def\buff_verbatim_inject_breaks
+ {\ifnum\c_buff_verbatim_current=\plusone
+ \nobreak
+ \orelse\ifnum\c_buff_verbatim_noflines=\plusthree
+ \nobreak
+ \orelse\ifnum\c_buff_verbatim_current=\numexpr\c_buff_verbatim_noflines-\plusone\relax
+ \nobreak
+ \fi}
+
+\unexpanded\def\dodisplayverbatiminitialize#1%
+ {\forgetparindent % maybe more
+ \c_buff_verbatim_noflines#1\relax
+ \c_buff_verbatim_current\zerocount}
+
+\loadmarkfile{buff-imp-default} % preloaded as otherwise spurious spaces inline due to loading
+\loadmarkfile{buff-imp-nested} % preloaded as otherwise spurious spaces inline due to loading
+\loadmarkfile{buff-imp-escaped} % for completeness
+
+%D To be considered:
+
+% \installcorenamespace{visualizer}
+%
+% \installcommandhandler \??visualizer {visualizer} \??visualizer
+%
+% \appendtoks
+% \setuevalue{\currentvisualizer}{\buff_verbatim_visualize{\currentvisualizer}}%
+% \to \everydefinevisualizer
+%
+% \unexpanded\def\buff_verbatim_visualize#1%
+% {\bgroup
+% \def\currentvisualizer{#1}%
+% \usevisualizerstyleandcolor\c!style\c!color
+% \let\next}
+
+\appendtoks
+ %def\type#1{\letterbackslash\checkedstrippedcsname#1}% or maybe detokenize
+ \def\type#1{\detokenize\expandafter{\csstring#1}}% or maybe detokenize
+ \def\tex #1{\letterbackslash#1}%
+\to \everysimplifycommands
+
+\stopcontextdefinitioncode
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/catc-sym.mkiv b/Master/texmf-dist/tex/context/base/mkiv/catc-sym.mkiv
index ae12532720d..5cda010fe38 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/catc-sym.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/catc-sym.mkiv
@@ -55,6 +55,20 @@
.egroup
+\bgroup
+
+\catcode`_=\lettercatcode
+
+%xdef\_n_u_l_{\expandafter\string\Uchar1} % nul(l)
+%xdef\_s_o_h_{\expandafter\string\Uchar1} % start of header ^^^^0001
+\xdef\_s_t_x_{\expandafter\string\Uchar2} % start of text ^^^^0002
+\xdef\_e_t_x_{\expandafter\string\Uchar3} % end of text ^^^^0003
+\xdef\_e_o_t_{\expandafter\string\Uchar4} % end of transmission ^^^^0004
+%xdef\_e_n_q_{\expandafter\string\Uchar5} % enquiry
+%xdef\_a_c_k_{\expandafter\string\Uchar6} % aknowledgement
+
+\egroup
+
%D \macros
%D {uncatcodespecials,setnaturalcatcodes,setnormalcatcodes,
%D uncatcodecharacters,uncatcodeallcharacters,
diff --git a/Master/texmf-dist/tex/context/base/mkiv/char-def.lua b/Master/texmf-dist/tex/context/base/mkiv/char-def.lua
index c17400a7942..953d33f4a0e 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/char-def.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/char-def.lua
@@ -26,6 +26,11 @@ local variants_emoji={
[0xFE0F]="emoji style",
}
+local variants_forms={
+ [0xFE00]="corner-justified form",
+ [0xFE01]="centered form",
+}
+
characters = characters or { }
characters.data={
@@ -22001,7 +22006,7 @@ characters.data={
category="mn",
description="BENGALI SIGN CANDRABINDU",
direction="nsm",
- indic="o",
+ indic="m",
indicorder="ap",
linebreak="cm",
unicodeslot=0x981,
@@ -22469,7 +22474,7 @@ characters.data={
category="mc",
description="BENGALI VOWEL SIGN II",
direction="l",
- indic="d",
+ indic="o",
indicmark="r",
indicorder="ap",
linebreak="cm",
@@ -22525,7 +22530,7 @@ characters.data={
description="BENGALI VOWEL SIGN E",
direction="l",
indic="d",
- indicmark="r",
+ indicmark="l",
indicorder="bh",
linebreak="cm",
unicodeslot=0x9C7,
@@ -22536,7 +22541,7 @@ characters.data={
description="BENGALI VOWEL SIGN AI",
direction="l",
indic="d",
- indicmark="r",
+ indicmark="l",
indicorder="bh",
linebreak="cm",
unicodeslot=0x9C8,
@@ -22546,7 +22551,8 @@ characters.data={
category="mc",
description="BENGALI VOWEL SIGN O",
direction="l",
- indic="s",
+ indic="d",
+ indicmark="s",
linebreak="cm",
specials={ "char", 0x9C7, 0x9BE },
unicodeslot=0x9CB,
@@ -22556,7 +22562,8 @@ characters.data={
category="mc",
description="BENGALI VOWEL SIGN AU",
direction="l",
- indic="s",
+ indic="d",
+ indicmark="s",
linebreak="cm",
specials={ "char", 0x9C7, 0x9D7 },
unicodeslot=0x9CC,
@@ -22756,6 +22763,7 @@ characters.data={
description="BENGALI LETTER RA WITH MIDDLE DIAGONAL",
direction="l",
indic="o",
+ indicclass="ra",
indicorder="as",
linebreak="al",
shcode=0x9B0,
@@ -23648,6 +23656,7 @@ characters.data={
description="GUJARATI SIGN ANUSVARA",
direction="nsm",
indic="o",
+ indicmark="t",
linebreak="cm",
unicodeslot=0xA82,
},
@@ -24016,6 +24025,7 @@ characters.data={
description="GUJARATI LETTER YA",
direction="l",
indic="c",
+ indicorder="ap",
linebreak="al",
unicodeslot=0xAAF,
},
@@ -24972,7 +24982,7 @@ characters.data={
description="ORIYA VOWEL SIGN AI",
direction="l",
indic="d",
- indicmark="l",
+ indicmark="s",
linebreak="cm",
specials={ "char", 0xB47, 0xB56 },
unicodeslot=0xB48,
@@ -26389,7 +26399,7 @@ characters.data={
description="TELUGU VOWEL SIGN AI",
direction="nsm",
indic="d",
- indicmark="t",
+ indicmark="s",
linebreak="cm",
specials={ "char", 0xC46, 0xC56 },
unicodeslot=0xC48,
@@ -26593,6 +26603,13 @@ characters.data={
linebreak="nu",
unicodeslot=0xC6F,
},
+ [0xC77]={
+ category="po",
+ description="TELUGU SIGN SIDDHAM",
+ direction="l",
+ linebreak="bb",
+ unicodeslot=0xC77,
+ },
[0xC78]={
category="no",
description="TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR",
@@ -27134,7 +27151,7 @@ characters.data={
description="KANNADA VOWEL SIGN II",
direction="l",
indic="d",
- indicmark="r",
+ indicmark="s",
linebreak="cm",
specials={ "char", 0xCBF, 0xCD5 },
unicodeslot=0xCC0,
@@ -27194,7 +27211,7 @@ characters.data={
description="KANNADA VOWEL SIGN EE",
direction="l",
indic="d",
- indicmark="r",
+ indicmark="s",
linebreak="cm",
specials={ "char", 0xCC6, 0xCD5 },
unicodeslot=0xCC7,
@@ -27204,7 +27221,7 @@ characters.data={
description="KANNADA VOWEL SIGN AI",
direction="l",
indic="d",
- indicmark="r",
+ indicmark="s",
linebreak="cm",
specials={ "char", 0xCC6, 0xCD6 },
unicodeslot=0xCC8,
@@ -27214,7 +27231,7 @@ characters.data={
description="KANNADA VOWEL SIGN O",
direction="l",
indic="d",
- indicmark="r",
+ indicmark="s",
linebreak="cm",
specials={ "char", 0xCC6, 0xCC2 },
unicodeslot=0xCCA,
@@ -27224,7 +27241,7 @@ characters.data={
description="KANNADA VOWEL SIGN OO",
direction="l",
indic="d",
- indicmark="r",
+ indicmark="s",
linebreak="cm",
specials={ "char", 0xCCA, 0xCD5 },
unicodeslot=0xCCB,
@@ -27244,7 +27261,7 @@ characters.data={
combining=0x9,
description="KANNADA SIGN VIRAMA",
direction="nsm",
- indic="s",
+ indic="o",
indicclass="halant",
linebreak="cm",
unicodeslot=0xCCD,
@@ -27253,7 +27270,8 @@ characters.data={
category="mc",
description="KANNADA LENGTH MARK",
direction="l",
- indic="o",
+ indic="d",
+ indicmark="r",
indicorder="as",
linebreak="cm",
unicodeslot=0xCD5,
@@ -27262,7 +27280,8 @@ characters.data={
category="mc",
description="KANNADA AI LENGTH MARK",
direction="l",
- indic="o",
+ indic="d",
+ indicmark="b",
indicorder="as",
linebreak="cm",
unicodeslot=0xCD6,
@@ -28017,7 +28036,7 @@ characters.data={
combining=0x9,
description="MALAYALAM SIGN VIRAMA",
direction="nsm",
- indic="s",
+ indic="o",
indicclass="halant",
linebreak="cm",
synonyms={ "malayalam chandrakkala", "malayalam vowel half-u" },
@@ -29741,6 +29760,13 @@ characters.data={
linebreak="sa",
unicodeslot=0xE84,
},
+ [0xE86]={
+ category="lo",
+ description="LAO LETTER PALI GHA",
+ direction="l",
+ linebreak="sa",
+ unicodeslot=0xE86,
+ },
[0xE87]={
category="lo",
description="LAO LETTER NGO",
@@ -29755,6 +29781,13 @@ characters.data={
linebreak="sa",
unicodeslot=0xE88,
},
+ [0xE89]={
+ category="lo",
+ description="LAO LETTER PALI CHA",
+ direction="l",
+ linebreak="sa",
+ unicodeslot=0xE89,
+ },
[0xE8A]={
category="lo",
description="LAO LETTER SO TAM",
@@ -29762,6 +29795,13 @@ characters.data={
linebreak="sa",
unicodeslot=0xE8A,
},
+ [0xE8C]={
+ category="lo",
+ description="LAO LETTER PALI JHA",
+ direction="l",
+ linebreak="sa",
+ unicodeslot=0xE8C,
+ },
[0xE8D]={
category="lo",
description="LAO LETTER NYO",
@@ -29769,6 +29809,48 @@ characters.data={
linebreak="sa",
unicodeslot=0xE8D,
},
+ [0xE8E]={
+ category="lo",
+ description="LAO LETTER PALI NYA",
+ direction="l",
+ linebreak="sa",
+ unicodeslot=0xE8E,
+ },
+ [0xE8F]={
+ category="lo",
+ description="LAO LETTER PALI TTA",
+ direction="l",
+ linebreak="sa",
+ unicodeslot=0xE8F,
+ },
+ [0xE90]={
+ category="lo",
+ description="LAO LETTER PALI TTHA",
+ direction="l",
+ linebreak="sa",
+ unicodeslot=0xE90,
+ },
+ [0xE91]={
+ category="lo",
+ description="LAO LETTER PALI DDA",
+ direction="l",
+ linebreak="sa",
+ unicodeslot=0xE91,
+ },
+ [0xE92]={
+ category="lo",
+ description="LAO LETTER PALI DDHA",
+ direction="l",
+ linebreak="sa",
+ unicodeslot=0xE92,
+ },
+ [0xE93]={
+ category="lo",
+ description="LAO LETTER PALI NNA",
+ direction="l",
+ linebreak="sa",
+ unicodeslot=0xE93,
+ },
[0xE94]={
category="lo",
description="LAO LETTER DO",
@@ -29797,6 +29879,13 @@ characters.data={
linebreak="sa",
unicodeslot=0xE97,
},
+ [0xE98]={
+ category="lo",
+ description="LAO LETTER PALI DHA",
+ direction="l",
+ linebreak="sa",
+ unicodeslot=0xE98,
+ },
[0xE99]={
category="lo",
description="LAO LETTER NO",
@@ -29846,6 +29935,13 @@ characters.data={
linebreak="sa",
unicodeslot=0xE9F,
},
+ [0xEA0]={
+ category="lo",
+ description="LAO LETTER PALI BHA",
+ direction="l",
+ linebreak="sa",
+ unicodeslot=0xEA0,
+ },
[0xEA1]={
category="lo",
description="LAO LETTER MO",
@@ -29881,6 +29977,20 @@ characters.data={
linebreak="sa",
unicodeslot=0xEA7,
},
+ [0xEA8]={
+ category="lo",
+ description="LAO LETTER SANSKRIT SHA",
+ direction="l",
+ linebreak="sa",
+ unicodeslot=0xEA8,
+ },
+ [0xEA9]={
+ category="lo",
+ description="LAO LETTER SANSKRIT SSA",
+ direction="l",
+ linebreak="sa",
+ unicodeslot=0xEA9,
+ },
[0xEAA]={
category="lo",
description="LAO LETTER SO SUNG",
@@ -29895,6 +30005,13 @@ characters.data={
linebreak="sa",
unicodeslot=0xEAB,
},
+ [0xEAC]={
+ category="lo",
+ description="LAO LETTER PALI LLA",
+ direction="l",
+ linebreak="sa",
+ unicodeslot=0xEAC,
+ },
[0xEAD]={
category="lo",
description="LAO LETTER O",
@@ -29989,6 +30106,14 @@ characters.data={
linebreak="sa",
unicodeslot=0xEB9,
},
+ [0xEBA]={
+ category="mn",
+ combining=0x9,
+ description="LAO SIGN PALI VIRAMA",
+ direction="nsm",
+ linebreak="sa",
+ unicodeslot=0xEBA,
+ },
[0xEBB]={
category="mn",
description="LAO VOWEL SIGN MAI KON",
@@ -53570,14 +53695,14 @@ characters.data={
category="mc",
description="VEDIC SIGN ARDHAVISARGA",
direction="l",
- linebreak="cm",
+ linebreak="al",
unicodeslot=0x1CF2,
},
[0x1CF3]={
category="mc",
description="VEDIC SIGN ROTATED ARDHAVISARGA",
direction="l",
- linebreak="cm",
+ linebreak="al",
unicodeslot=0x1CF3,
},
[0x1CF4]={
@@ -53625,6 +53750,13 @@ characters.data={
linebreak="cm",
unicodeslot=0x1CF9,
},
+ [0x1CFA]={
+ category="lo",
+ description="VEDIC SIGN DOUBLE ANUSVARA ANTARGOMUKHA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1CFA,
+ },
[0x1D00]={
category="ll",
description="LATIN LETTER SMALL CAPITAL A",
@@ -85787,6 +85919,13 @@ characters.data={
linebreak="al",
unicodeslot=0x2BC8,
},
+ [0x2BC9]={
+ category="so",
+ description="NEPTUNE FORM TWO",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x2BC9,
+ },
[0x2BCA]={
category="so",
description="TOP HALF BLACK CIRCLE",
@@ -86159,6 +86298,13 @@ characters.data={
mirror=0x221F,
unicodeslot=0x2BFE,
},
+ [0x2BFF]={
+ category="so",
+ description="HELLSCHREIBER PAUSE SYMBOL",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x2BFF,
+ },
[0x2C00]={
category="lu",
description="GLAGOLITIC CAPITAL LETTER AZU",
@@ -90247,6 +90393,13 @@ characters.data={
linebreak="ba",
unicodeslot=0x2E4E,
},
+ [0x2E4F]={
+ category="po",
+ description="CORNISH VERSE DIVIDER",
+ direction="on",
+ linebreak="ba",
+ unicodeslot=0x2E4F,
+ },
[0x2E80]={
category="so",
cjkwd="w",
@@ -93210,6 +93363,7 @@ characters.data={
direction="on",
linebreak="cl",
unicodeslot=0x3001,
+ variants=variants_forms,
},
[0x3002]={
adobename="ideographicperiod",
@@ -93219,6 +93373,7 @@ characters.data={
direction="on",
linebreak="cl",
unicodeslot=0x3002,
+ variants=variants_forms,
},
[0x3003]={
adobename="dittomark",
@@ -100600,6 +100755,15 @@ characters.data={
specials={ "circle", 0x30F2 },
unicodeslot=0x32FE,
},
+ [0x32FF]={
+ category="so",
+ cjkwd="w",
+ description="SQUARE ERA NAME REIWA",
+ direction="l",
+ linebreak="id",
+ specials={ "square", 0x4EE4, 0x548C },
+ unicodeslot=0x32FF,
+ },
[0x3300]={
adobename="apaatosquare",
category="so",
@@ -118280,6 +118444,83 @@ characters.data={
linebreak="al",
unicodeslot=0xA7B9,
},
+ [0xA7BA]={
+ category="lu",
+ description="LATIN CAPITAL LETTER GLOTTAL A",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0xA7BA,
+ },
+ [0xA7BB]={
+ category="ll",
+ description="LATIN SMALL LETTER GLOTTAL A",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0xA7BB,
+ },
+ [0xA7BC]={
+ category="lu",
+ description="LATIN CAPITAL LETTER GLOTTAL I",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0xA7BC,
+ },
+ [0xA7BD]={
+ category="ll",
+ description="LATIN SMALL LETTER GLOTTAL I",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0xA7BD,
+ },
+ [0xA7BE]={
+ category="lu",
+ description="LATIN CAPITAL LETTER GLOTTAL U",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0xA7BE,
+ },
+ [0xA7BF]={
+ category="ll",
+ description="LATIN SMALL LETTER GLOTTAL U",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0xA7BF,
+ },
+ [0xA7C2]={
+ category="lu",
+ description="LATIN CAPITAL LETTER ANGLICANA W",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0xA7C2,
+ },
+ [0xA7C3]={
+ category="ll",
+ description="LATIN SMALL LETTER ANGLICANA W",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0xA7C3,
+ },
+ [0xA7C4]={
+ category="lu",
+ description="LATIN CAPITAL LETTER C WITH PALATAL HOOK",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0xA7C4,
+ },
+ [0xA7C5]={
+ category="lu",
+ description="LATIN CAPITAL LETTER S WITH HOOK",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0xA7C5,
+ },
+ [0xA7C6]={
+ category="lu",
+ description="LATIN CAPITAL LETTER Z WITH PALATAL HOOK",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0xA7C6,
+ },
[0xA7F7]={
category="lo",
description="LATIN EPIGRAPHIC LETTER SIDEWAYS I",
@@ -119926,7 +120167,7 @@ characters.data={
combining=0xE6,
description="COMBINING DEVANAGARI LETTER VI",
direction="nsm",
- indic="m",
+ indic="o",
indicmark="t",
linebreak="cm",
unicodeslot=0xA8F0,
@@ -121301,7 +121542,7 @@ characters.data={
[0xA9BD]={
category="mc",
description="JAVANESE CONSONANT SIGN KERET",
- direction="l",
+ direction="nsm",
linebreak="cm",
unicodeslot=0xA9BD,
},
@@ -123911,6 +124152,20 @@ characters.data={
linebreak="al",
unicodeslot=0xAB65,
},
+ [0xAB66]={
+ category="ll",
+ description="LATIN SMALL LETTER DZ DIGRAPH WITH RETROFLEX HOOK",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0xAB66,
+ },
+ [0xAB67]={
+ category="ll",
+ description="LATIN SMALL LETTER TS DIGRAPH WITH RETROFLEX HOOK",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0xAB67,
+ },
[0xAB70]={
category="ll",
description="CHEROKEE SMALL LETTER A",
@@ -137206,6 +137461,7 @@ characters.data={
linebreak="ex",
specials={ "wide", 0x21 },
unicodeslot=0xFF01,
+ variants=variants_forms,
},
[0xFF02]={
adobename="quotedblmonospace",
@@ -137320,6 +137576,7 @@ characters.data={
linebreak="cl",
specials={ "wide", 0x2C },
unicodeslot=0xFF0C,
+ variants=variants_forms,
},
[0xFF0D]={
adobename="hyphenmonospace",
@@ -137340,6 +137597,7 @@ characters.data={
linebreak="cl",
specials={ "wide", 0x2E },
unicodeslot=0xFF0E,
+ variants=variants_forms,
},
[0xFF0F]={
adobename="slashmonospace",
@@ -137463,6 +137721,7 @@ characters.data={
linebreak="ns",
specials={ "wide", 0x3A },
unicodeslot=0xFF1A,
+ variants=variants_forms,
},
[0xFF1B]={
adobename="semicolonmonospace",
@@ -137473,6 +137732,7 @@ characters.data={
linebreak="ns",
specials={ "wide", 0x3B },
unicodeslot=0xFF1B,
+ variants=variants_forms,
},
[0xFF1C]={
adobename="lessmonospace",
@@ -137517,6 +137777,7 @@ characters.data={
linebreak="ex",
specials={ "wide", 0x3F },
unicodeslot=0xFF1F,
+ variants=variants_forms,
},
[0xFF20]={
adobename="atmonospace",
@@ -156690,6 +156951,167 @@ characters.data={
linebreak="al",
unicodeslot=0x10F59,
},
+ [0x10FE0]={
+ category="lo",
+ description="ELYMAIC LETTER ALEPH",
+ direction="r",
+ linebreak="al",
+ unicodeslot=0x10FE0,
+ },
+ [0x10FE1]={
+ category="lo",
+ description="ELYMAIC LETTER BETH",
+ direction="r",
+ linebreak="al",
+ unicodeslot=0x10FE1,
+ },
+ [0x10FE2]={
+ category="lo",
+ description="ELYMAIC LETTER GIMEL",
+ direction="r",
+ linebreak="al",
+ unicodeslot=0x10FE2,
+ },
+ [0x10FE3]={
+ category="lo",
+ description="ELYMAIC LETTER DALETH",
+ direction="r",
+ linebreak="al",
+ unicodeslot=0x10FE3,
+ },
+ [0x10FE4]={
+ category="lo",
+ description="ELYMAIC LETTER HE",
+ direction="r",
+ linebreak="al",
+ unicodeslot=0x10FE4,
+ },
+ [0x10FE5]={
+ category="lo",
+ description="ELYMAIC LETTER WAW",
+ direction="r",
+ linebreak="al",
+ unicodeslot=0x10FE5,
+ },
+ [0x10FE6]={
+ category="lo",
+ description="ELYMAIC LETTER ZAYIN",
+ direction="r",
+ linebreak="al",
+ unicodeslot=0x10FE6,
+ },
+ [0x10FE7]={
+ category="lo",
+ description="ELYMAIC LETTER HETH",
+ direction="r",
+ linebreak="al",
+ unicodeslot=0x10FE7,
+ },
+ [0x10FE8]={
+ category="lo",
+ description="ELYMAIC LETTER TETH",
+ direction="r",
+ linebreak="al",
+ unicodeslot=0x10FE8,
+ },
+ [0x10FE9]={
+ category="lo",
+ description="ELYMAIC LETTER YODH",
+ direction="r",
+ linebreak="al",
+ unicodeslot=0x10FE9,
+ },
+ [0x10FEA]={
+ category="lo",
+ description="ELYMAIC LETTER KAPH",
+ direction="r",
+ linebreak="al",
+ unicodeslot=0x10FEA,
+ },
+ [0x10FEB]={
+ category="lo",
+ description="ELYMAIC LETTER LAMEDH",
+ direction="r",
+ linebreak="al",
+ unicodeslot=0x10FEB,
+ },
+ [0x10FEC]={
+ category="lo",
+ description="ELYMAIC LETTER MEM",
+ direction="r",
+ linebreak="al",
+ unicodeslot=0x10FEC,
+ },
+ [0x10FED]={
+ category="lo",
+ description="ELYMAIC LETTER NUN",
+ direction="r",
+ linebreak="al",
+ unicodeslot=0x10FED,
+ },
+ [0x10FEE]={
+ category="lo",
+ description="ELYMAIC LETTER SAMEKH",
+ direction="r",
+ linebreak="al",
+ unicodeslot=0x10FEE,
+ },
+ [0x10FEF]={
+ category="lo",
+ description="ELYMAIC LETTER AYIN",
+ direction="r",
+ linebreak="al",
+ unicodeslot=0x10FEF,
+ },
+ [0x10FF0]={
+ category="lo",
+ description="ELYMAIC LETTER PE",
+ direction="r",
+ linebreak="al",
+ unicodeslot=0x10FF0,
+ },
+ [0x10FF1]={
+ category="lo",
+ description="ELYMAIC LETTER SADHE",
+ direction="r",
+ linebreak="al",
+ unicodeslot=0x10FF1,
+ },
+ [0x10FF2]={
+ category="lo",
+ description="ELYMAIC LETTER QOPH",
+ direction="r",
+ linebreak="al",
+ unicodeslot=0x10FF2,
+ },
+ [0x10FF3]={
+ category="lo",
+ description="ELYMAIC LETTER RESH",
+ direction="r",
+ linebreak="al",
+ unicodeslot=0x10FF3,
+ },
+ [0x10FF4]={
+ category="lo",
+ description="ELYMAIC LETTER SHIN",
+ direction="r",
+ linebreak="al",
+ unicodeslot=0x10FF4,
+ },
+ [0x10FF5]={
+ category="lo",
+ description="ELYMAIC LETTER TAW",
+ direction="r",
+ linebreak="al",
+ unicodeslot=0x10FF5,
+ },
+ [0x10FF6]={
+ category="lo",
+ description="ELYMAIC LIGATURE ZAYIN-YODH",
+ direction="r",
+ linebreak="al",
+ unicodeslot=0x10FF6,
+ },
[0x11000]={
category="mc",
description="BRAHMI SIGN CANDRABINDU",
@@ -162207,6 +162629,13 @@ characters.data={
linebreak="cm",
unicodeslot=0x1145E,
},
+ [0x1145F]={
+ category="lo",
+ description="NEWA LETTER VEDIC ANUSVARA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1145F,
+ },
[0x11480]={
category="lo",
description="TIRHUTA ANJI",
@@ -164473,6 +164902,13 @@ characters.data={
linebreak="cm",
unicodeslot=0x116B7,
},
+ [0x116B8]={
+ category="lo",
+ description="TAKRI LETTER ARCHAIC KHA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x116B8,
+ },
[0x116C0]={
category="nd",
description="TAKRI DIGIT ZERO",
@@ -165960,6 +166396,462 @@ characters.data={
linebreak="al",
unicodeslot=0x118FF,
},
+ [0x119A0]={
+ category="lo",
+ description="NANDINAGARI LETTER A",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119A0,
+ },
+ [0x119A1]={
+ category="lo",
+ description="NANDINAGARI LETTER AA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119A1,
+ },
+ [0x119A2]={
+ category="lo",
+ description="NANDINAGARI LETTER I",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119A2,
+ },
+ [0x119A3]={
+ category="lo",
+ description="NANDINAGARI LETTER II",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119A3,
+ },
+ [0x119A4]={
+ category="lo",
+ description="NANDINAGARI LETTER U",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119A4,
+ },
+ [0x119A5]={
+ category="lo",
+ description="NANDINAGARI LETTER UU",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119A5,
+ },
+ [0x119A6]={
+ category="lo",
+ description="NANDINAGARI LETTER VOCALIC R",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119A6,
+ },
+ [0x119A7]={
+ category="lo",
+ description="NANDINAGARI LETTER VOCALIC RR",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119A7,
+ },
+ [0x119AA]={
+ category="lo",
+ description="NANDINAGARI LETTER E",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119AA,
+ },
+ [0x119AB]={
+ category="lo",
+ description="NANDINAGARI LETTER AI",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119AB,
+ },
+ [0x119AC]={
+ category="lo",
+ description="NANDINAGARI LETTER O",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119AC,
+ },
+ [0x119AD]={
+ category="lo",
+ description="NANDINAGARI LETTER AU",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119AD,
+ },
+ [0x119AE]={
+ category="lo",
+ description="NANDINAGARI LETTER KA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119AE,
+ },
+ [0x119AF]={
+ category="lo",
+ description="NANDINAGARI LETTER KHA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119AF,
+ },
+ [0x119B0]={
+ category="lo",
+ description="NANDINAGARI LETTER GA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119B0,
+ },
+ [0x119B1]={
+ category="lo",
+ description="NANDINAGARI LETTER GHA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119B1,
+ },
+ [0x119B2]={
+ category="lo",
+ description="NANDINAGARI LETTER NGA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119B2,
+ },
+ [0x119B3]={
+ category="lo",
+ description="NANDINAGARI LETTER CA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119B3,
+ },
+ [0x119B4]={
+ category="lo",
+ description="NANDINAGARI LETTER CHA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119B4,
+ },
+ [0x119B5]={
+ category="lo",
+ description="NANDINAGARI LETTER JA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119B5,
+ },
+ [0x119B6]={
+ category="lo",
+ description="NANDINAGARI LETTER JHA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119B6,
+ },
+ [0x119B7]={
+ category="lo",
+ description="NANDINAGARI LETTER NYA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119B7,
+ },
+ [0x119B8]={
+ category="lo",
+ description="NANDINAGARI LETTER TTA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119B8,
+ },
+ [0x119B9]={
+ category="lo",
+ description="NANDINAGARI LETTER TTHA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119B9,
+ },
+ [0x119BA]={
+ category="lo",
+ description="NANDINAGARI LETTER DDA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119BA,
+ },
+ [0x119BB]={
+ category="lo",
+ description="NANDINAGARI LETTER DDHA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119BB,
+ },
+ [0x119BC]={
+ category="lo",
+ description="NANDINAGARI LETTER NNA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119BC,
+ },
+ [0x119BD]={
+ category="lo",
+ description="NANDINAGARI LETTER TA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119BD,
+ },
+ [0x119BE]={
+ category="lo",
+ description="NANDINAGARI LETTER THA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119BE,
+ },
+ [0x119BF]={
+ category="lo",
+ description="NANDINAGARI LETTER DA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119BF,
+ },
+ [0x119C0]={
+ category="lo",
+ description="NANDINAGARI LETTER DHA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119C0,
+ },
+ [0x119C1]={
+ category="lo",
+ description="NANDINAGARI LETTER NA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119C1,
+ },
+ [0x119C2]={
+ category="lo",
+ description="NANDINAGARI LETTER PA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119C2,
+ },
+ [0x119C3]={
+ category="lo",
+ description="NANDINAGARI LETTER PHA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119C3,
+ },
+ [0x119C4]={
+ category="lo",
+ description="NANDINAGARI LETTER BA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119C4,
+ },
+ [0x119C5]={
+ category="lo",
+ description="NANDINAGARI LETTER BHA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119C5,
+ },
+ [0x119C6]={
+ category="lo",
+ description="NANDINAGARI LETTER MA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119C6,
+ },
+ [0x119C7]={
+ category="lo",
+ description="NANDINAGARI LETTER YA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119C7,
+ },
+ [0x119C8]={
+ category="lo",
+ description="NANDINAGARI LETTER RA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119C8,
+ },
+ [0x119C9]={
+ category="lo",
+ description="NANDINAGARI LETTER LA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119C9,
+ },
+ [0x119CA]={
+ category="lo",
+ description="NANDINAGARI LETTER VA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119CA,
+ },
+ [0x119CB]={
+ category="lo",
+ description="NANDINAGARI LETTER SHA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119CB,
+ },
+ [0x119CC]={
+ category="lo",
+ description="NANDINAGARI LETTER SSA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119CC,
+ },
+ [0x119CD]={
+ category="lo",
+ description="NANDINAGARI LETTER SA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119CD,
+ },
+ [0x119CE]={
+ category="lo",
+ description="NANDINAGARI LETTER HA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119CE,
+ },
+ [0x119CF]={
+ category="lo",
+ description="NANDINAGARI LETTER LLA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119CF,
+ },
+ [0x119D0]={
+ category="lo",
+ description="NANDINAGARI LETTER RRA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119D0,
+ },
+ [0x119D1]={
+ category="mc",
+ description="NANDINAGARI VOWEL SIGN AA",
+ direction="l",
+ linebreak="cm",
+ unicodeslot=0x119D1,
+ },
+ [0x119D2]={
+ category="mc",
+ description="NANDINAGARI VOWEL SIGN I",
+ direction="l",
+ linebreak="cm",
+ unicodeslot=0x119D2,
+ },
+ [0x119D3]={
+ category="mc",
+ description="NANDINAGARI VOWEL SIGN II",
+ direction="l",
+ linebreak="cm",
+ unicodeslot=0x119D3,
+ },
+ [0x119D4]={
+ category="mn",
+ description="NANDINAGARI VOWEL SIGN U",
+ direction="nsm",
+ linebreak="cm",
+ unicodeslot=0x119D4,
+ },
+ [0x119D5]={
+ category="mn",
+ description="NANDINAGARI VOWEL SIGN UU",
+ direction="nsm",
+ linebreak="cm",
+ unicodeslot=0x119D5,
+ },
+ [0x119D6]={
+ category="mn",
+ description="NANDINAGARI VOWEL SIGN VOCALIC R",
+ direction="nsm",
+ linebreak="cm",
+ unicodeslot=0x119D6,
+ },
+ [0x119D7]={
+ category="mn",
+ description="NANDINAGARI VOWEL SIGN VOCALIC RR",
+ direction="nsm",
+ linebreak="cm",
+ unicodeslot=0x119D7,
+ },
+ [0x119DA]={
+ category="mn",
+ description="NANDINAGARI VOWEL SIGN E",
+ direction="nsm",
+ linebreak="cm",
+ unicodeslot=0x119DA,
+ },
+ [0x119DB]={
+ category="mn",
+ description="NANDINAGARI VOWEL SIGN AI",
+ direction="nsm",
+ linebreak="cm",
+ unicodeslot=0x119DB,
+ },
+ [0x119DC]={
+ category="mc",
+ description="NANDINAGARI VOWEL SIGN O",
+ direction="l",
+ linebreak="cm",
+ unicodeslot=0x119DC,
+ },
+ [0x119DD]={
+ category="mc",
+ description="NANDINAGARI VOWEL SIGN AU",
+ direction="l",
+ linebreak="cm",
+ unicodeslot=0x119DD,
+ },
+ [0x119DE]={
+ category="mc",
+ description="NANDINAGARI SIGN ANUSVARA",
+ direction="l",
+ linebreak="cm",
+ unicodeslot=0x119DE,
+ },
+ [0x119DF]={
+ category="mc",
+ description="NANDINAGARI SIGN VISARGA",
+ direction="l",
+ linebreak="cm",
+ unicodeslot=0x119DF,
+ },
+ [0x119E0]={
+ category="mn",
+ combining=0x9,
+ description="NANDINAGARI SIGN VIRAMA",
+ direction="nsm",
+ linebreak="cm",
+ unicodeslot=0x119E0,
+ },
+ [0x119E1]={
+ category="lo",
+ description="NANDINAGARI SIGN AVAGRAHA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119E1,
+ },
+ [0x119E2]={
+ category="po",
+ description="NANDINAGARI SIGN SIDDHAM",
+ direction="l",
+ linebreak="bb",
+ unicodeslot=0x119E2,
+ },
+ [0x119E3]={
+ category="lo",
+ description="NANDINAGARI HEADSTROKE",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x119E3,
+ },
+ [0x119E4]={
+ category="mc",
+ description="NANDINAGARI VOWEL SIGN PRISHTHAMATRA E",
+ direction="l",
+ linebreak="cm",
+ unicodeslot=0x119E4,
+ },
[0x11A00]={
category="lo",
description="ZANABAZAR SQUARE LETTER A",
@@ -166830,6 +167722,20 @@ characters.data={
linebreak="al",
unicodeslot=0x11A83,
},
+ [0x11A84]={
+ category="lo",
+ description="SOYOMBO SIGN JIHVAMULIYA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x11A84,
+ },
+ [0x11A85]={
+ category="lo",
+ description="SOYOMBO SIGN UPADHMANIYA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x11A85,
+ },
[0x11A86]={
category="lo",
description="SOYOMBO CLUSTER-INITIAL LETTER RA",
@@ -169734,6 +170640,363 @@ characters.data={
linebreak="al",
unicodeslot=0x11EF8,
},
+ [0x11FC0]={
+ category="no",
+ description="TAMIL FRACTION ONE THREE-HUNDRED-AND-TWENTIETH",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x11FC0,
+ },
+ [0x11FC1]={
+ category="no",
+ description="TAMIL FRACTION ONE ONE-HUNDRED-AND-SIXTIETH",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x11FC1,
+ },
+ [0x11FC2]={
+ category="no",
+ description="TAMIL FRACTION ONE EIGHTIETH",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x11FC2,
+ },
+ [0x11FC3]={
+ category="no",
+ description="TAMIL FRACTION ONE SIXTY-FOURTH",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x11FC3,
+ },
+ [0x11FC4]={
+ category="no",
+ description="TAMIL FRACTION ONE FORTIETH",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x11FC4,
+ },
+ [0x11FC5]={
+ category="no",
+ description="TAMIL FRACTION ONE THIRTY-SECOND",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x11FC5,
+ },
+ [0x11FC6]={
+ category="no",
+ description="TAMIL FRACTION THREE EIGHTIETHS",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x11FC6,
+ },
+ [0x11FC7]={
+ category="no",
+ description="TAMIL FRACTION THREE SIXTY-FOURTHS",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x11FC7,
+ },
+ [0x11FC8]={
+ category="no",
+ description="TAMIL FRACTION ONE TWENTIETH",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x11FC8,
+ },
+ [0x11FC9]={
+ category="no",
+ description="TAMIL FRACTION ONE SIXTEENTH-1",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x11FC9,
+ },
+ [0x11FCA]={
+ category="no",
+ description="TAMIL FRACTION ONE SIXTEENTH-2",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x11FCA,
+ },
+ [0x11FCB]={
+ category="no",
+ description="TAMIL FRACTION ONE TENTH",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x11FCB,
+ },
+ [0x11FCC]={
+ category="no",
+ description="TAMIL FRACTION ONE EIGHTH",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x11FCC,
+ },
+ [0x11FCD]={
+ category="no",
+ description="TAMIL FRACTION THREE TWENTIETHS",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x11FCD,
+ },
+ [0x11FCE]={
+ category="no",
+ description="TAMIL FRACTION THREE SIXTEENTHS",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x11FCE,
+ },
+ [0x11FCF]={
+ category="no",
+ description="TAMIL FRACTION ONE FIFTH",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x11FCF,
+ },
+ [0x11FD0]={
+ category="no",
+ description="TAMIL FRACTION ONE QUARTER",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x11FD0,
+ },
+ [0x11FD1]={
+ category="no",
+ description="TAMIL FRACTION ONE HALF-1",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x11FD1,
+ },
+ [0x11FD2]={
+ category="no",
+ description="TAMIL FRACTION ONE HALF-2",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x11FD2,
+ },
+ [0x11FD3]={
+ category="no",
+ description="TAMIL FRACTION THREE QUARTERS",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x11FD3,
+ },
+ [0x11FD4]={
+ category="no",
+ description="TAMIL FRACTION DOWNSCALING FACTOR KIIZH",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x11FD4,
+ },
+ [0x11FD5]={
+ category="so",
+ description="TAMIL SIGN NEL",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x11FD5,
+ },
+ [0x11FD6]={
+ category="so",
+ description="TAMIL SIGN CEVITU",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x11FD6,
+ },
+ [0x11FD7]={
+ category="so",
+ description="TAMIL SIGN AAZHAAKKU",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x11FD7,
+ },
+ [0x11FD8]={
+ category="so",
+ description="TAMIL SIGN UZHAKKU",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x11FD8,
+ },
+ [0x11FD9]={
+ category="so",
+ description="TAMIL SIGN MUUVUZHAKKU",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x11FD9,
+ },
+ [0x11FDA]={
+ category="so",
+ description="TAMIL SIGN KURUNI",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x11FDA,
+ },
+ [0x11FDB]={
+ category="so",
+ description="TAMIL SIGN PATHAKKU",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x11FDB,
+ },
+ [0x11FDC]={
+ category="so",
+ description="TAMIL SIGN MUKKURUNI",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x11FDC,
+ },
+ [0x11FDD]={
+ category="sc",
+ description="TAMIL SIGN KAACU",
+ direction="et",
+ linebreak="po",
+ unicodeslot=0x11FDD,
+ },
+ [0x11FDE]={
+ category="sc",
+ description="TAMIL SIGN PANAM",
+ direction="et",
+ linebreak="po",
+ unicodeslot=0x11FDE,
+ },
+ [0x11FDF]={
+ category="sc",
+ description="TAMIL SIGN PON",
+ direction="et",
+ linebreak="po",
+ unicodeslot=0x11FDF,
+ },
+ [0x11FE0]={
+ category="sc",
+ description="TAMIL SIGN VARAAKAN",
+ direction="et",
+ linebreak="po",
+ unicodeslot=0x11FE0,
+ },
+ [0x11FE1]={
+ category="so",
+ description="TAMIL SIGN PAARAM",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x11FE1,
+ },
+ [0x11FE2]={
+ category="so",
+ description="TAMIL SIGN KUZHI",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x11FE2,
+ },
+ [0x11FE3]={
+ category="so",
+ description="TAMIL SIGN VELI",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x11FE3,
+ },
+ [0x11FE4]={
+ category="so",
+ description="TAMIL WET CULTIVATION SIGN",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x11FE4,
+ },
+ [0x11FE5]={
+ category="so",
+ description="TAMIL DRY CULTIVATION SIGN",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x11FE5,
+ },
+ [0x11FE6]={
+ category="so",
+ description="TAMIL LAND SIGN",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x11FE6,
+ },
+ [0x11FE7]={
+ category="so",
+ description="TAMIL SALT PAN SIGN",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x11FE7,
+ },
+ [0x11FE8]={
+ category="so",
+ description="TAMIL TRADITIONAL CREDIT SIGN",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x11FE8,
+ },
+ [0x11FE9]={
+ category="so",
+ description="TAMIL TRADITIONAL NUMBER SIGN",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x11FE9,
+ },
+ [0x11FEA]={
+ category="so",
+ description="TAMIL CURRENT SIGN",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x11FEA,
+ },
+ [0x11FEB]={
+ category="so",
+ description="TAMIL AND ODD SIGN",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x11FEB,
+ },
+ [0x11FEC]={
+ category="so",
+ description="TAMIL SPENT SIGN",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x11FEC,
+ },
+ [0x11FED]={
+ category="so",
+ description="TAMIL TOTAL SIGN",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x11FED,
+ },
+ [0x11FEE]={
+ category="so",
+ description="TAMIL IN POSSESSION SIGN",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x11FEE,
+ },
+ [0x11FEF]={
+ category="so",
+ description="TAMIL STARTING FROM SIGN",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x11FEF,
+ },
+ [0x11FF0]={
+ category="so",
+ description="TAMIL SIGN MUTHALIYA",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x11FF0,
+ },
+ [0x11FF1]={
+ category="so",
+ description="TAMIL SIGN VAKAIYARAA",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x11FF1,
+ },
+ [0x11FFF]={
+ category="po",
+ description="TAMIL PUNCTUATION END OF TEXT",
+ direction="l",
+ linebreak="ba",
+ unicodeslot=0x11FFF,
+ },
[0x12000]={
category="lo",
description="CUNEIFORM SIGN A",
@@ -185871,6 +187134,69 @@ characters.data={
linebreak="al",
unicodeslot=0x1342E,
},
+ [0x13430]={
+ category="cf",
+ description="EGYPTIAN HIEROGLYPH VERTICAL JOINER",
+ direction="l",
+ linebreak="gl",
+ unicodeslot=0x13430,
+ },
+ [0x13431]={
+ category="cf",
+ description="EGYPTIAN HIEROGLYPH HORIZONTAL JOINER",
+ direction="l",
+ linebreak="gl",
+ unicodeslot=0x13431,
+ },
+ [0x13432]={
+ category="cf",
+ description="EGYPTIAN HIEROGLYPH INSERT AT TOP START",
+ direction="l",
+ linebreak="gl",
+ unicodeslot=0x13432,
+ },
+ [0x13433]={
+ category="cf",
+ description="EGYPTIAN HIEROGLYPH INSERT AT BOTTOM START",
+ direction="l",
+ linebreak="gl",
+ unicodeslot=0x13433,
+ },
+ [0x13434]={
+ category="cf",
+ description="EGYPTIAN HIEROGLYPH INSERT AT TOP END",
+ direction="l",
+ linebreak="gl",
+ unicodeslot=0x13434,
+ },
+ [0x13435]={
+ category="cf",
+ description="EGYPTIAN HIEROGLYPH INSERT AT BOTTOM END",
+ direction="l",
+ linebreak="gl",
+ unicodeslot=0x13435,
+ },
+ [0x13436]={
+ category="cf",
+ description="EGYPTIAN HIEROGLYPH OVERLAY MIDDLE",
+ direction="l",
+ linebreak="gl",
+ unicodeslot=0x13436,
+ },
+ [0x13437]={
+ category="cf",
+ description="EGYPTIAN HIEROGLYPH BEGIN SEGMENT",
+ direction="l",
+ linebreak="op",
+ unicodeslot=0x13437,
+ },
+ [0x13438]={
+ category="cf",
+ description="EGYPTIAN HIEROGLYPH END SEGMENT",
+ direction="l",
+ linebreak="cl",
+ unicodeslot=0x13438,
+ },
[0x14400]={
category="lo",
description="ANATOLIAN HIEROGLYPH A001",
@@ -196509,6 +197835,55 @@ characters.data={
linebreak="al",
unicodeslot=0x16F44,
},
+ [0x16F45]={
+ category="lo",
+ description="MIAO LETTER BRI",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x16F45,
+ },
+ [0x16F46]={
+ category="lo",
+ description="MIAO LETTER SYI",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x16F46,
+ },
+ [0x16F47]={
+ category="lo",
+ description="MIAO LETTER DZYI",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x16F47,
+ },
+ [0x16F48]={
+ category="lo",
+ description="MIAO LETTER TE",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x16F48,
+ },
+ [0x16F49]={
+ category="lo",
+ description="MIAO LETTER TSE",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x16F49,
+ },
+ [0x16F4A]={
+ category="lo",
+ description="MIAO LETTER RTE",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x16F4A,
+ },
+ [0x16F4F]={
+ category="mn",
+ description="MIAO SIGN CONSONANT MODIFIER BAR",
+ direction="nsm",
+ linebreak="cm",
+ unicodeslot=0x16F4F,
+ },
[0x16F50]={
category="lo",
description="MIAO LETTER NASALIZATION",
@@ -196838,6 +198213,69 @@ characters.data={
linebreak="cm",
unicodeslot=0x16F7E,
},
+ [0x16F7F]={
+ category="mc",
+ description="MIAO VOWEL SIGN UOG",
+ direction="l",
+ linebreak="cm",
+ unicodeslot=0x16F7F,
+ },
+ [0x16F80]={
+ category="mc",
+ description="MIAO VOWEL SIGN YUI",
+ direction="l",
+ linebreak="cm",
+ unicodeslot=0x16F80,
+ },
+ [0x16F81]={
+ category="mc",
+ description="MIAO VOWEL SIGN OG",
+ direction="l",
+ linebreak="cm",
+ unicodeslot=0x16F81,
+ },
+ [0x16F82]={
+ category="mc",
+ description="MIAO VOWEL SIGN OER",
+ direction="l",
+ linebreak="cm",
+ unicodeslot=0x16F82,
+ },
+ [0x16F83]={
+ category="mc",
+ description="MIAO VOWEL SIGN VW",
+ direction="l",
+ linebreak="cm",
+ unicodeslot=0x16F83,
+ },
+ [0x16F84]={
+ category="mc",
+ description="MIAO VOWEL SIGN IG",
+ direction="l",
+ linebreak="cm",
+ unicodeslot=0x16F84,
+ },
+ [0x16F85]={
+ category="mc",
+ description="MIAO VOWEL SIGN EA",
+ direction="l",
+ linebreak="cm",
+ unicodeslot=0x16F85,
+ },
+ [0x16F86]={
+ category="mc",
+ description="MIAO VOWEL SIGN IONG",
+ direction="l",
+ linebreak="cm",
+ unicodeslot=0x16F86,
+ },
+ [0x16F87]={
+ category="mc",
+ description="MIAO VOWEL SIGN UI",
+ direction="l",
+ linebreak="cm",
+ unicodeslot=0x16F87,
+ },
[0x16F8F]={
category="mn",
description="MIAO TONE RIGHT",
@@ -196973,6 +198411,22 @@ characters.data={
linebreak="ns",
unicodeslot=0x16FE1,
},
+ [0x16FE2]={
+ category="po",
+ cjkwd="w",
+ description="OLD CHINESE HOOK MARK",
+ direction="on",
+ linebreak="ns",
+ unicodeslot=0x16FE2,
+ },
+ [0x16FE3]={
+ category="lm",
+ cjkwd="w",
+ description="OLD CHINESE ITERATION MARK",
+ direction="l",
+ linebreak="ns",
+ unicodeslot=0x16FE3,
+ },
[0x18800]={
category="lo",
cjkwd="w",
@@ -205309,6 +206763,62 @@ characters.data={
linebreak="id",
unicodeslot=0x1B11E,
},
+ [0x1B150]={
+ category="lo",
+ cjkwd="w",
+ description="HIRAGANA LETTER SMALL WI",
+ direction="l",
+ linebreak="cj",
+ unicodeslot=0x1B150,
+ },
+ [0x1B151]={
+ category="lo",
+ cjkwd="w",
+ description="HIRAGANA LETTER SMALL WE",
+ direction="l",
+ linebreak="cj",
+ unicodeslot=0x1B151,
+ },
+ [0x1B152]={
+ category="lo",
+ cjkwd="w",
+ description="HIRAGANA LETTER SMALL WO",
+ direction="l",
+ linebreak="cj",
+ unicodeslot=0x1B152,
+ },
+ [0x1B164]={
+ category="lo",
+ cjkwd="w",
+ description="KATAKANA LETTER SMALL WI",
+ direction="l",
+ linebreak="cj",
+ unicodeslot=0x1B164,
+ },
+ [0x1B165]={
+ category="lo",
+ cjkwd="w",
+ description="KATAKANA LETTER SMALL WE",
+ direction="l",
+ linebreak="cj",
+ unicodeslot=0x1B165,
+ },
+ [0x1B166]={
+ category="lo",
+ cjkwd="w",
+ description="KATAKANA LETTER SMALL WO",
+ direction="l",
+ linebreak="cj",
+ unicodeslot=0x1B166,
+ },
+ [0x1B167]={
+ category="lo",
+ cjkwd="w",
+ description="KATAKANA LETTER SMALL N",
+ direction="l",
+ linebreak="cj",
+ unicodeslot=0x1B167,
+ },
[0x1B170]={
category="lo",
cjkwd="w",
@@ -228068,6 +229578,927 @@ characters.data={
linebreak="cm",
unicodeslot=0x1E02A,
},
+ [0x1E100]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER MA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E100,
+ },
+ [0x1E101]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER TSA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E101,
+ },
+ [0x1E102]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER NTA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E102,
+ },
+ [0x1E103]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER TA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E103,
+ },
+ [0x1E104]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER HA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E104,
+ },
+ [0x1E105]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER NA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E105,
+ },
+ [0x1E106]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER XA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E106,
+ },
+ [0x1E107]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER NKA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E107,
+ },
+ [0x1E108]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER CA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E108,
+ },
+ [0x1E109]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER LA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E109,
+ },
+ [0x1E10A]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER SA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E10A,
+ },
+ [0x1E10B]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER ZA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E10B,
+ },
+ [0x1E10C]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER NCA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E10C,
+ },
+ [0x1E10D]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER NTSA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E10D,
+ },
+ [0x1E10E]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER KA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E10E,
+ },
+ [0x1E10F]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER DA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E10F,
+ },
+ [0x1E110]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER NYA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E110,
+ },
+ [0x1E111]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER NRA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E111,
+ },
+ [0x1E112]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER VA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E112,
+ },
+ [0x1E113]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER NTXA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E113,
+ },
+ [0x1E114]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER TXA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E114,
+ },
+ [0x1E115]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER FA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E115,
+ },
+ [0x1E116]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER RA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E116,
+ },
+ [0x1E117]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER QA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E117,
+ },
+ [0x1E118]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER YA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E118,
+ },
+ [0x1E119]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER NQA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E119,
+ },
+ [0x1E11A]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER PA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E11A,
+ },
+ [0x1E11B]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER XYA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E11B,
+ },
+ [0x1E11C]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER NPA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E11C,
+ },
+ [0x1E11D]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER DLA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E11D,
+ },
+ [0x1E11E]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER NPLA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E11E,
+ },
+ [0x1E11F]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER HAH",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E11F,
+ },
+ [0x1E120]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER MLA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E120,
+ },
+ [0x1E121]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER PLA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E121,
+ },
+ [0x1E122]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER GA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E122,
+ },
+ [0x1E123]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER RRA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E123,
+ },
+ [0x1E124]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER A",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E124,
+ },
+ [0x1E125]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER AA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E125,
+ },
+ [0x1E126]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER I",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E126,
+ },
+ [0x1E127]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER U",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E127,
+ },
+ [0x1E128]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER O",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E128,
+ },
+ [0x1E129]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER OO",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E129,
+ },
+ [0x1E12A]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER E",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E12A,
+ },
+ [0x1E12B]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER EE",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E12B,
+ },
+ [0x1E12C]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LETTER W",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E12C,
+ },
+ [0x1E130]={
+ category="mn",
+ combining=0xE6,
+ description="NYIAKENG PUACHUE HMONG TONE-B",
+ direction="nsm",
+ linebreak="cm",
+ unicodeslot=0x1E130,
+ },
+ [0x1E131]={
+ category="mn",
+ combining=0xE6,
+ description="NYIAKENG PUACHUE HMONG TONE-M",
+ direction="nsm",
+ linebreak="cm",
+ unicodeslot=0x1E131,
+ },
+ [0x1E132]={
+ category="mn",
+ combining=0xE6,
+ description="NYIAKENG PUACHUE HMONG TONE-J",
+ direction="nsm",
+ linebreak="cm",
+ unicodeslot=0x1E132,
+ },
+ [0x1E133]={
+ category="mn",
+ combining=0xE6,
+ description="NYIAKENG PUACHUE HMONG TONE-V",
+ direction="nsm",
+ linebreak="cm",
+ unicodeslot=0x1E133,
+ },
+ [0x1E134]={
+ category="mn",
+ combining=0xE6,
+ description="NYIAKENG PUACHUE HMONG TONE-S",
+ direction="nsm",
+ linebreak="cm",
+ unicodeslot=0x1E134,
+ },
+ [0x1E135]={
+ category="mn",
+ combining=0xE6,
+ description="NYIAKENG PUACHUE HMONG TONE-G",
+ direction="nsm",
+ linebreak="cm",
+ unicodeslot=0x1E135,
+ },
+ [0x1E136]={
+ category="mn",
+ combining=0xE6,
+ description="NYIAKENG PUACHUE HMONG TONE-D",
+ direction="nsm",
+ linebreak="cm",
+ unicodeslot=0x1E136,
+ },
+ [0x1E137]={
+ category="lm",
+ description="NYIAKENG PUACHUE HMONG SIGN FOR PERSON",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E137,
+ },
+ [0x1E138]={
+ category="lm",
+ description="NYIAKENG PUACHUE HMONG SIGN FOR THING",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E138,
+ },
+ [0x1E139]={
+ category="lm",
+ description="NYIAKENG PUACHUE HMONG SIGN FOR LOCATION",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E139,
+ },
+ [0x1E13A]={
+ category="lm",
+ description="NYIAKENG PUACHUE HMONG SIGN FOR ANIMAL",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E13A,
+ },
+ [0x1E13B]={
+ category="lm",
+ description="NYIAKENG PUACHUE HMONG SIGN FOR INVERTEBRATE",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E13B,
+ },
+ [0x1E13C]={
+ category="lm",
+ description="NYIAKENG PUACHUE HMONG SIGN XW XW",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E13C,
+ },
+ [0x1E13D]={
+ category="lm",
+ description="NYIAKENG PUACHUE HMONG SYLLABLE LENGTHENER",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E13D,
+ },
+ [0x1E140]={
+ category="nd",
+ description="NYIAKENG PUACHUE HMONG DIGIT ZERO",
+ direction="l",
+ linebreak="nu",
+ unicodeslot=0x1E140,
+ },
+ [0x1E141]={
+ category="nd",
+ description="NYIAKENG PUACHUE HMONG DIGIT ONE",
+ direction="l",
+ linebreak="nu",
+ unicodeslot=0x1E141,
+ },
+ [0x1E142]={
+ category="nd",
+ description="NYIAKENG PUACHUE HMONG DIGIT TWO",
+ direction="l",
+ linebreak="nu",
+ unicodeslot=0x1E142,
+ },
+ [0x1E143]={
+ category="nd",
+ description="NYIAKENG PUACHUE HMONG DIGIT THREE",
+ direction="l",
+ linebreak="nu",
+ unicodeslot=0x1E143,
+ },
+ [0x1E144]={
+ category="nd",
+ description="NYIAKENG PUACHUE HMONG DIGIT FOUR",
+ direction="l",
+ linebreak="nu",
+ unicodeslot=0x1E144,
+ },
+ [0x1E145]={
+ category="nd",
+ description="NYIAKENG PUACHUE HMONG DIGIT FIVE",
+ direction="l",
+ linebreak="nu",
+ unicodeslot=0x1E145,
+ },
+ [0x1E146]={
+ category="nd",
+ description="NYIAKENG PUACHUE HMONG DIGIT SIX",
+ direction="l",
+ linebreak="nu",
+ unicodeslot=0x1E146,
+ },
+ [0x1E147]={
+ category="nd",
+ description="NYIAKENG PUACHUE HMONG DIGIT SEVEN",
+ direction="l",
+ linebreak="nu",
+ unicodeslot=0x1E147,
+ },
+ [0x1E148]={
+ category="nd",
+ description="NYIAKENG PUACHUE HMONG DIGIT EIGHT",
+ direction="l",
+ linebreak="nu",
+ unicodeslot=0x1E148,
+ },
+ [0x1E149]={
+ category="nd",
+ description="NYIAKENG PUACHUE HMONG DIGIT NINE",
+ direction="l",
+ linebreak="nu",
+ unicodeslot=0x1E149,
+ },
+ [0x1E14E]={
+ category="lo",
+ description="NYIAKENG PUACHUE HMONG LOGOGRAM NYAJ",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E14E,
+ },
+ [0x1E14F]={
+ category="so",
+ description="NYIAKENG PUACHUE HMONG CIRCLED CA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E14F,
+ },
+ [0x1E2C0]={
+ category="lo",
+ description="WANCHO LETTER AA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2C0,
+ },
+ [0x1E2C1]={
+ category="lo",
+ description="WANCHO LETTER A",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2C1,
+ },
+ [0x1E2C2]={
+ category="lo",
+ description="WANCHO LETTER BA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2C2,
+ },
+ [0x1E2C3]={
+ category="lo",
+ description="WANCHO LETTER CA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2C3,
+ },
+ [0x1E2C4]={
+ category="lo",
+ description="WANCHO LETTER DA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2C4,
+ },
+ [0x1E2C5]={
+ category="lo",
+ description="WANCHO LETTER GA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2C5,
+ },
+ [0x1E2C6]={
+ category="lo",
+ description="WANCHO LETTER YA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2C6,
+ },
+ [0x1E2C7]={
+ category="lo",
+ description="WANCHO LETTER PHA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2C7,
+ },
+ [0x1E2C8]={
+ category="lo",
+ description="WANCHO LETTER LA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2C8,
+ },
+ [0x1E2C9]={
+ category="lo",
+ description="WANCHO LETTER NA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2C9,
+ },
+ [0x1E2CA]={
+ category="lo",
+ description="WANCHO LETTER PA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2CA,
+ },
+ [0x1E2CB]={
+ category="lo",
+ description="WANCHO LETTER TA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2CB,
+ },
+ [0x1E2CC]={
+ category="lo",
+ description="WANCHO LETTER THA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2CC,
+ },
+ [0x1E2CD]={
+ category="lo",
+ description="WANCHO LETTER FA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2CD,
+ },
+ [0x1E2CE]={
+ category="lo",
+ description="WANCHO LETTER SA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2CE,
+ },
+ [0x1E2CF]={
+ category="lo",
+ description="WANCHO LETTER SHA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2CF,
+ },
+ [0x1E2D0]={
+ category="lo",
+ description="WANCHO LETTER JA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2D0,
+ },
+ [0x1E2D1]={
+ category="lo",
+ description="WANCHO LETTER ZA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2D1,
+ },
+ [0x1E2D2]={
+ category="lo",
+ description="WANCHO LETTER WA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2D2,
+ },
+ [0x1E2D3]={
+ category="lo",
+ description="WANCHO LETTER VA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2D3,
+ },
+ [0x1E2D4]={
+ category="lo",
+ description="WANCHO LETTER KA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2D4,
+ },
+ [0x1E2D5]={
+ category="lo",
+ description="WANCHO LETTER O",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2D5,
+ },
+ [0x1E2D6]={
+ category="lo",
+ description="WANCHO LETTER AU",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2D6,
+ },
+ [0x1E2D7]={
+ category="lo",
+ description="WANCHO LETTER RA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2D7,
+ },
+ [0x1E2D8]={
+ category="lo",
+ description="WANCHO LETTER MA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2D8,
+ },
+ [0x1E2D9]={
+ category="lo",
+ description="WANCHO LETTER KHA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2D9,
+ },
+ [0x1E2DA]={
+ category="lo",
+ description="WANCHO LETTER HA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2DA,
+ },
+ [0x1E2DB]={
+ category="lo",
+ description="WANCHO LETTER E",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2DB,
+ },
+ [0x1E2DC]={
+ category="lo",
+ description="WANCHO LETTER I",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2DC,
+ },
+ [0x1E2DD]={
+ category="lo",
+ description="WANCHO LETTER NGA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2DD,
+ },
+ [0x1E2DE]={
+ category="lo",
+ description="WANCHO LETTER U",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2DE,
+ },
+ [0x1E2DF]={
+ category="lo",
+ description="WANCHO LETTER LLHA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2DF,
+ },
+ [0x1E2E0]={
+ category="lo",
+ description="WANCHO LETTER TSA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2E0,
+ },
+ [0x1E2E1]={
+ category="lo",
+ description="WANCHO LETTER TRA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2E1,
+ },
+ [0x1E2E2]={
+ category="lo",
+ description="WANCHO LETTER ONG",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2E2,
+ },
+ [0x1E2E3]={
+ category="lo",
+ description="WANCHO LETTER AANG",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2E3,
+ },
+ [0x1E2E4]={
+ category="lo",
+ description="WANCHO LETTER ANG",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2E4,
+ },
+ [0x1E2E5]={
+ category="lo",
+ description="WANCHO LETTER ING",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2E5,
+ },
+ [0x1E2E6]={
+ category="lo",
+ description="WANCHO LETTER ON",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2E6,
+ },
+ [0x1E2E7]={
+ category="lo",
+ description="WANCHO LETTER EN",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2E7,
+ },
+ [0x1E2E8]={
+ category="lo",
+ description="WANCHO LETTER AAN",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2E8,
+ },
+ [0x1E2E9]={
+ category="lo",
+ description="WANCHO LETTER NYA",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2E9,
+ },
+ [0x1E2EA]={
+ category="lo",
+ description="WANCHO LETTER UEN",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2EA,
+ },
+ [0x1E2EB]={
+ category="lo",
+ description="WANCHO LETTER YIH",
+ direction="l",
+ linebreak="al",
+ unicodeslot=0x1E2EB,
+ },
+ [0x1E2EC]={
+ category="mn",
+ combining=0xE6,
+ description="WANCHO TONE TUP",
+ direction="nsm",
+ linebreak="cm",
+ unicodeslot=0x1E2EC,
+ },
+ [0x1E2ED]={
+ category="mn",
+ combining=0xE6,
+ description="WANCHO TONE TUPNI",
+ direction="nsm",
+ linebreak="cm",
+ unicodeslot=0x1E2ED,
+ },
+ [0x1E2EE]={
+ category="mn",
+ combining=0xE6,
+ description="WANCHO TONE KOI",
+ direction="nsm",
+ linebreak="cm",
+ unicodeslot=0x1E2EE,
+ },
+ [0x1E2EF]={
+ category="mn",
+ combining=0xE6,
+ description="WANCHO TONE KOINI",
+ direction="nsm",
+ linebreak="cm",
+ unicodeslot=0x1E2EF,
+ },
+ [0x1E2F0]={
+ category="nd",
+ description="WANCHO DIGIT ZERO",
+ direction="l",
+ linebreak="nu",
+ unicodeslot=0x1E2F0,
+ },
+ [0x1E2F1]={
+ category="nd",
+ description="WANCHO DIGIT ONE",
+ direction="l",
+ linebreak="nu",
+ unicodeslot=0x1E2F1,
+ },
+ [0x1E2F2]={
+ category="nd",
+ description="WANCHO DIGIT TWO",
+ direction="l",
+ linebreak="nu",
+ unicodeslot=0x1E2F2,
+ },
+ [0x1E2F3]={
+ category="nd",
+ description="WANCHO DIGIT THREE",
+ direction="l",
+ linebreak="nu",
+ unicodeslot=0x1E2F3,
+ },
+ [0x1E2F4]={
+ category="nd",
+ description="WANCHO DIGIT FOUR",
+ direction="l",
+ linebreak="nu",
+ unicodeslot=0x1E2F4,
+ },
+ [0x1E2F5]={
+ category="nd",
+ description="WANCHO DIGIT FIVE",
+ direction="l",
+ linebreak="nu",
+ unicodeslot=0x1E2F5,
+ },
+ [0x1E2F6]={
+ category="nd",
+ description="WANCHO DIGIT SIX",
+ direction="l",
+ linebreak="nu",
+ unicodeslot=0x1E2F6,
+ },
+ [0x1E2F7]={
+ category="nd",
+ description="WANCHO DIGIT SEVEN",
+ direction="l",
+ linebreak="nu",
+ unicodeslot=0x1E2F7,
+ },
+ [0x1E2F8]={
+ category="nd",
+ description="WANCHO DIGIT EIGHT",
+ direction="l",
+ linebreak="nu",
+ unicodeslot=0x1E2F8,
+ },
+ [0x1E2F9]={
+ category="nd",
+ description="WANCHO DIGIT NINE",
+ direction="l",
+ linebreak="nu",
+ unicodeslot=0x1E2F9,
+ },
+ [0x1E2FF]={
+ category="sc",
+ description="WANCHO NGUN SIGN",
+ direction="et",
+ linebreak="pr",
+ unicodeslot=0x1E2FF,
+ },
[0x1E800]={
category="lo",
description="MENDE KIKAKUI SYLLABLE M001 KI",
@@ -230166,6 +232597,14 @@ characters.data={
linebreak="cm",
unicodeslot=0x1E94A,
},
+ [0x1E94B]={
+ arabic="t",
+ category="lm",
+ description="ADLAM NASALIZATION MARK",
+ direction="r",
+ linebreak="al",
+ unicodeslot=0x1E94B,
+ },
[0x1E950]={
category="nd",
description="ADLAM DIGIT ZERO",
@@ -230726,6 +233165,433 @@ characters.data={
linebreak="al",
unicodeslot=0x1ECB4,
},
+ [0x1ED01]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER ONE",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED01,
+ },
+ [0x1ED02]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER TWO",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED02,
+ },
+ [0x1ED03]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER THREE",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED03,
+ },
+ [0x1ED04]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER FOUR",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED04,
+ },
+ [0x1ED05]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER FIVE",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED05,
+ },
+ [0x1ED06]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER SIX",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED06,
+ },
+ [0x1ED07]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER SEVEN",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED07,
+ },
+ [0x1ED08]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER EIGHT",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED08,
+ },
+ [0x1ED09]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER NINE",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED09,
+ },
+ [0x1ED0A]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER TEN",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED0A,
+ },
+ [0x1ED0B]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER TWENTY",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED0B,
+ },
+ [0x1ED0C]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER THIRTY",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED0C,
+ },
+ [0x1ED0D]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER FORTY",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED0D,
+ },
+ [0x1ED0E]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER FIFTY",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED0E,
+ },
+ [0x1ED0F]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER SIXTY",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED0F,
+ },
+ [0x1ED10]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER SEVENTY",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED10,
+ },
+ [0x1ED11]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER EIGHTY",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED11,
+ },
+ [0x1ED12]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER NINETY",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED12,
+ },
+ [0x1ED13]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER ONE HUNDRED",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED13,
+ },
+ [0x1ED14]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER TWO HUNDRED",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED14,
+ },
+ [0x1ED15]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER THREE HUNDRED",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED15,
+ },
+ [0x1ED16]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER FOUR HUNDRED",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED16,
+ },
+ [0x1ED17]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER FIVE HUNDRED",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED17,
+ },
+ [0x1ED18]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER SIX HUNDRED",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED18,
+ },
+ [0x1ED19]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER SEVEN HUNDRED",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED19,
+ },
+ [0x1ED1A]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER EIGHT HUNDRED",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED1A,
+ },
+ [0x1ED1B]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER NINE HUNDRED",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED1B,
+ },
+ [0x1ED1C]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER ONE THOUSAND",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED1C,
+ },
+ [0x1ED1D]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER TWO THOUSAND",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED1D,
+ },
+ [0x1ED1E]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER THREE THOUSAND",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED1E,
+ },
+ [0x1ED1F]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER FOUR THOUSAND",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED1F,
+ },
+ [0x1ED20]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER FIVE THOUSAND",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED20,
+ },
+ [0x1ED21]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER SIX THOUSAND",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED21,
+ },
+ [0x1ED22]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER SEVEN THOUSAND",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED22,
+ },
+ [0x1ED23]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER EIGHT THOUSAND",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED23,
+ },
+ [0x1ED24]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER NINE THOUSAND",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED24,
+ },
+ [0x1ED25]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER TEN THOUSAND",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED25,
+ },
+ [0x1ED26]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER TWENTY THOUSAND",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED26,
+ },
+ [0x1ED27]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER THIRTY THOUSAND",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED27,
+ },
+ [0x1ED28]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER FORTY THOUSAND",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED28,
+ },
+ [0x1ED29]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER FIFTY THOUSAND",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED29,
+ },
+ [0x1ED2A]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER SIXTY THOUSAND",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED2A,
+ },
+ [0x1ED2B]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER SEVENTY THOUSAND",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED2B,
+ },
+ [0x1ED2C]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER EIGHTY THOUSAND",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED2C,
+ },
+ [0x1ED2D]={
+ category="no",
+ description="OTTOMAN SIYAQ NUMBER NINETY THOUSAND",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED2D,
+ },
+ [0x1ED2E]={
+ category="so",
+ description="OTTOMAN SIYAQ MARRATAN",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED2E,
+ },
+ [0x1ED2F]={
+ category="no",
+ description="OTTOMAN SIYAQ ALTERNATE NUMBER TWO",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED2F,
+ },
+ [0x1ED30]={
+ category="no",
+ description="OTTOMAN SIYAQ ALTERNATE NUMBER THREE",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED30,
+ },
+ [0x1ED31]={
+ category="no",
+ description="OTTOMAN SIYAQ ALTERNATE NUMBER FOUR",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED31,
+ },
+ [0x1ED32]={
+ category="no",
+ description="OTTOMAN SIYAQ ALTERNATE NUMBER FIVE",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED32,
+ },
+ [0x1ED33]={
+ category="no",
+ description="OTTOMAN SIYAQ ALTERNATE NUMBER SIX",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED33,
+ },
+ [0x1ED34]={
+ category="no",
+ description="OTTOMAN SIYAQ ALTERNATE NUMBER SEVEN",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED34,
+ },
+ [0x1ED35]={
+ category="no",
+ description="OTTOMAN SIYAQ ALTERNATE NUMBER EIGHT",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED35,
+ },
+ [0x1ED36]={
+ category="no",
+ description="OTTOMAN SIYAQ ALTERNATE NUMBER NINE",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED36,
+ },
+ [0x1ED37]={
+ category="no",
+ description="OTTOMAN SIYAQ ALTERNATE NUMBER TEN",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED37,
+ },
+ [0x1ED38]={
+ category="no",
+ description="OTTOMAN SIYAQ ALTERNATE NUMBER FOUR HUNDRED",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED38,
+ },
+ [0x1ED39]={
+ category="no",
+ description="OTTOMAN SIYAQ ALTERNATE NUMBER SIX HUNDRED",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED39,
+ },
+ [0x1ED3A]={
+ category="no",
+ description="OTTOMAN SIYAQ ALTERNATE NUMBER TWO THOUSAND",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED3A,
+ },
+ [0x1ED3B]={
+ category="no",
+ description="OTTOMAN SIYAQ ALTERNATE NUMBER TEN THOUSAND",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED3B,
+ },
+ [0x1ED3C]={
+ category="no",
+ description="OTTOMAN SIYAQ FRACTION ONE HALF",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED3C,
+ },
+ [0x1ED3D]={
+ category="no",
+ description="OTTOMAN SIYAQ FRACTION ONE SIXTH",
+ direction="al",
+ linebreak="al",
+ unicodeslot=0x1ED3D,
+ },
[0x1EE00]={
category="lo",
comment="check math properties",
@@ -234508,6 +237374,14 @@ characters.data={
synonyms={ "marque deposee" },
unicodeslot=0x1F16B,
},
+ [0x1F16C]={
+ category="so",
+ description="RAISED MR SIGN",
+ direction="on",
+ linebreak="al",
+ specials={ "super", 0x4D, 0x52 },
+ unicodeslot=0x1F16C,
+ },
[0x1F170]={
category="so",
cjkwd="a",
@@ -238661,7 +241535,7 @@ characters.data={
cjkwd="w",
description="FAMILY",
direction="on",
- linebreak="id",
+ linebreak="eb",
unicodeslot=0x1F46A,
},
[0x1F46B]={
@@ -238669,7 +241543,7 @@ characters.data={
cjkwd="w",
description="MAN AND WOMAN HOLDING HANDS",
direction="on",
- linebreak="id",
+ linebreak="eb",
unicodeslot=0x1F46B,
},
[0x1F46C]={
@@ -238677,7 +241551,7 @@ characters.data={
cjkwd="w",
description="TWO MEN HOLDING HANDS",
direction="on",
- linebreak="id",
+ linebreak="eb",
unicodeslot=0x1F46C,
},
[0x1F46D]={
@@ -238685,7 +241559,7 @@ characters.data={
cjkwd="w",
description="TWO WOMEN HOLDING HANDS",
direction="on",
- linebreak="id",
+ linebreak="eb",
unicodeslot=0x1F46D,
},
[0x1F46E]={
@@ -238701,7 +241575,7 @@ characters.data={
cjkwd="w",
description="WOMAN WITH BUNNY EARS",
direction="on",
- linebreak="id",
+ linebreak="eb",
unicodeslot=0x1F46F,
},
[0x1F470]={
@@ -238958,7 +241832,7 @@ characters.data={
cjkwd="w",
description="KISS",
direction="on",
- linebreak="id",
+ linebreak="eb",
unicodeslot=0x1F48F,
},
[0x1F490]={
@@ -238974,7 +241848,7 @@ characters.data={
cjkwd="w",
description="COUPLE WITH HEART",
direction="on",
- linebreak="id",
+ linebreak="eb",
unicodeslot=0x1F491,
},
[0x1F492]={
@@ -243446,6 +246320,14 @@ characters.data={
linebreak="id",
unicodeslot=0x1F6D4,
},
+ [0x1F6D5]={
+ category="so",
+ cjkwd="w",
+ description="HINDU TEMPLE",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F6D5,
+ },
[0x1F6E0]={
category="so",
description="HAMMER AND WRENCH",
@@ -243624,6 +246506,14 @@ characters.data={
linebreak="id",
unicodeslot=0x1F6F9,
},
+ [0x1F6FA]={
+ category="so",
+ cjkwd="w",
+ description="AUTO RICKSHAW",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F6FA,
+ },
[0x1F700]={
category="so",
description="ALCHEMICAL SYMBOL FOR QUINTESSENCE",
@@ -245060,6 +247950,102 @@ characters.data={
linebreak="id",
unicodeslot=0x1F7D8,
},
+ [0x1F7E0]={
+ category="so",
+ cjkwd="w",
+ description="LARGE ORANGE CIRCLE",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F7E0,
+ },
+ [0x1F7E1]={
+ category="so",
+ cjkwd="w",
+ description="LARGE YELLOW CIRCLE",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F7E1,
+ },
+ [0x1F7E2]={
+ category="so",
+ cjkwd="w",
+ description="LARGE GREEN CIRCLE",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F7E2,
+ },
+ [0x1F7E3]={
+ category="so",
+ cjkwd="w",
+ description="LARGE PURPLE CIRCLE",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F7E3,
+ },
+ [0x1F7E4]={
+ category="so",
+ cjkwd="w",
+ description="LARGE BROWN CIRCLE",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F7E4,
+ },
+ [0x1F7E5]={
+ category="so",
+ cjkwd="w",
+ description="LARGE RED SQUARE",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F7E5,
+ },
+ [0x1F7E6]={
+ category="so",
+ cjkwd="w",
+ description="LARGE BLUE SQUARE",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F7E6,
+ },
+ [0x1F7E7]={
+ category="so",
+ cjkwd="w",
+ description="LARGE ORANGE SQUARE",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F7E7,
+ },
+ [0x1F7E8]={
+ category="so",
+ cjkwd="w",
+ description="LARGE YELLOW SQUARE",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F7E8,
+ },
+ [0x1F7E9]={
+ category="so",
+ cjkwd="w",
+ description="LARGE GREEN SQUARE",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F7E9,
+ },
+ [0x1F7EA]={
+ category="so",
+ cjkwd="w",
+ description="LARGE PURPLE SQUARE",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F7EA,
+ },
+ [0x1F7EB]={
+ category="so",
+ cjkwd="w",
+ description="LARGE BROWN SQUARE",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F7EB,
+ },
[0x1F800]={
category="so",
description="LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD",
@@ -246180,6 +249166,30 @@ characters.data={
linebreak="al",
unicodeslot=0x1F90B,
},
+ [0x1F90D]={
+ category="so",
+ cjkwd="w",
+ description="WHITE HEART",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F90D,
+ },
+ [0x1F90E]={
+ category="so",
+ cjkwd="w",
+ description="BROWN HEART",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F90E,
+ },
+ [0x1F90F]={
+ category="so",
+ cjkwd="w",
+ description="PINCHING HAND",
+ direction="on",
+ linebreak="eb",
+ unicodeslot=0x1F90F,
+ },
[0x1F910]={
category="so",
cjkwd="w",
@@ -246289,7 +249299,7 @@ characters.data={
cjkwd="w",
description="HANDSHAKE",
direction="on",
- linebreak="id",
+ linebreak="eb",
unicodeslot=0x1F91D,
},
[0x1F91E]={
@@ -246540,7 +249550,7 @@ characters.data={
cjkwd="w",
description="WRESTLERS",
direction="on",
- linebreak="id",
+ linebreak="eb",
unicodeslot=0x1F93C,
},
[0x1F93D]={
@@ -246559,6 +249569,14 @@ characters.data={
linebreak="eb",
unicodeslot=0x1F93E,
},
+ [0x1F93F]={
+ category="so",
+ cjkwd="w",
+ description="DIVING MASK",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F93F,
+ },
[0x1F940]={
category="so",
cjkwd="w",
@@ -246955,6 +249973,14 @@ characters.data={
linebreak="id",
unicodeslot=0x1F970,
},
+ [0x1F971]={
+ category="so",
+ cjkwd="w",
+ description="YAWNING FACE",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F971,
+ },
[0x1F973]={
category="so",
cjkwd="w",
@@ -246995,6 +250021,14 @@ characters.data={
linebreak="id",
unicodeslot=0x1F97A,
},
+ [0x1F97B]={
+ category="so",
+ cjkwd="w",
+ description="SARI",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F97B,
+ },
[0x1F97C]={
category="so",
cjkwd="w",
@@ -247308,6 +250342,70 @@ characters.data={
linebreak="id",
unicodeslot=0x1F9A2,
},
+ [0x1F9A5]={
+ category="so",
+ cjkwd="w",
+ description="SLOTH",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F9A5,
+ },
+ [0x1F9A6]={
+ category="so",
+ cjkwd="w",
+ description="OTTER",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F9A6,
+ },
+ [0x1F9A7]={
+ category="so",
+ cjkwd="w",
+ description="ORANGUTAN",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F9A7,
+ },
+ [0x1F9A8]={
+ category="so",
+ cjkwd="w",
+ description="SKUNK",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F9A8,
+ },
+ [0x1F9A9]={
+ category="so",
+ cjkwd="w",
+ description="FLAMINGO",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F9A9,
+ },
+ [0x1F9AA]={
+ category="so",
+ cjkwd="w",
+ description="OYSTER",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F9AA,
+ },
+ [0x1F9AE]={
+ category="so",
+ cjkwd="w",
+ description="GUIDE DOG",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F9AE,
+ },
+ [0x1F9AF]={
+ category="so",
+ cjkwd="w",
+ description="PROBING CANE",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F9AF,
+ },
[0x1F9B0]={
category="so",
cjkwd="w",
@@ -247388,6 +250486,54 @@ characters.data={
linebreak="eb",
unicodeslot=0x1F9B9,
},
+ [0x1F9BA]={
+ category="so",
+ cjkwd="w",
+ description="SAFETY VEST",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F9BA,
+ },
+ [0x1F9BB]={
+ category="so",
+ cjkwd="w",
+ description="EAR WITH HEARING AID",
+ direction="on",
+ linebreak="eb",
+ unicodeslot=0x1F9BB,
+ },
+ [0x1F9BC]={
+ category="so",
+ cjkwd="w",
+ description="MOTORIZED WHEELCHAIR",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F9BC,
+ },
+ [0x1F9BD]={
+ category="so",
+ cjkwd="w",
+ description="MANUAL WHEELCHAIR",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F9BD,
+ },
+ [0x1F9BE]={
+ category="so",
+ cjkwd="w",
+ description="MECHANICAL ARM",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F9BE,
+ },
+ [0x1F9BF]={
+ category="so",
+ cjkwd="w",
+ description="MECHANICAL LEG",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F9BF,
+ },
[0x1F9C0]={
category="so",
cjkwd="w",
@@ -247412,6 +250558,94 @@ characters.data={
linebreak="id",
unicodeslot=0x1F9C2,
},
+ [0x1F9C3]={
+ category="so",
+ cjkwd="w",
+ description="BEVERAGE BOX",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F9C3,
+ },
+ [0x1F9C4]={
+ category="so",
+ cjkwd="w",
+ description="GARLIC",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F9C4,
+ },
+ [0x1F9C5]={
+ category="so",
+ cjkwd="w",
+ description="ONION",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F9C5,
+ },
+ [0x1F9C6]={
+ category="so",
+ cjkwd="w",
+ description="FALAFEL",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F9C6,
+ },
+ [0x1F9C7]={
+ category="so",
+ cjkwd="w",
+ description="WAFFLE",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F9C7,
+ },
+ [0x1F9C8]={
+ category="so",
+ cjkwd="w",
+ description="BUTTER",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F9C8,
+ },
+ [0x1F9C9]={
+ category="so",
+ cjkwd="w",
+ description="MATE DRINK",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F9C9,
+ },
+ [0x1F9CA]={
+ category="so",
+ cjkwd="w",
+ description="ICE CUBE",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1F9CA,
+ },
+ [0x1F9CD]={
+ category="so",
+ cjkwd="w",
+ description="STANDING PERSON",
+ direction="on",
+ linebreak="eb",
+ unicodeslot=0x1F9CD,
+ },
+ [0x1F9CE]={
+ category="so",
+ cjkwd="w",
+ description="KNEELING PERSON",
+ direction="on",
+ linebreak="eb",
+ unicodeslot=0x1F9CE,
+ },
+ [0x1F9CF]={
+ category="so",
+ cjkwd="w",
+ description="DEAF PERSON",
+ direction="on",
+ linebreak="eb",
+ unicodeslot=0x1F9CF,
+ },
[0x1F9D0]={
category="so",
cjkwd="w",
@@ -247796,6 +251030,594 @@ characters.data={
linebreak="id",
unicodeslot=0x1F9FF,
},
+ [0x1FA00]={
+ category="so",
+ description="NEUTRAL CHESS KING",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA00,
+ },
+ [0x1FA01]={
+ category="so",
+ description="NEUTRAL CHESS QUEEN",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA01,
+ },
+ [0x1FA02]={
+ category="so",
+ description="NEUTRAL CHESS ROOK",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA02,
+ },
+ [0x1FA03]={
+ category="so",
+ description="NEUTRAL CHESS BISHOP",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA03,
+ },
+ [0x1FA04]={
+ category="so",
+ description="NEUTRAL CHESS KNIGHT",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA04,
+ },
+ [0x1FA05]={
+ category="so",
+ description="NEUTRAL CHESS PAWN",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA05,
+ },
+ [0x1FA06]={
+ category="so",
+ description="WHITE CHESS KNIGHT ROTATED FORTY-FIVE DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA06,
+ },
+ [0x1FA07]={
+ category="so",
+ description="BLACK CHESS KNIGHT ROTATED FORTY-FIVE DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA07,
+ },
+ [0x1FA08]={
+ category="so",
+ description="NEUTRAL CHESS KNIGHT ROTATED FORTY-FIVE DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA08,
+ },
+ [0x1FA09]={
+ category="so",
+ description="WHITE CHESS KING ROTATED NINETY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA09,
+ },
+ [0x1FA0A]={
+ category="so",
+ description="WHITE CHESS QUEEN ROTATED NINETY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA0A,
+ },
+ [0x1FA0B]={
+ category="so",
+ description="WHITE CHESS ROOK ROTATED NINETY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA0B,
+ },
+ [0x1FA0C]={
+ category="so",
+ description="WHITE CHESS BISHOP ROTATED NINETY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA0C,
+ },
+ [0x1FA0D]={
+ category="so",
+ description="WHITE CHESS KNIGHT ROTATED NINETY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA0D,
+ },
+ [0x1FA0E]={
+ category="so",
+ description="WHITE CHESS PAWN ROTATED NINETY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA0E,
+ },
+ [0x1FA0F]={
+ category="so",
+ description="BLACK CHESS KING ROTATED NINETY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA0F,
+ },
+ [0x1FA10]={
+ category="so",
+ description="BLACK CHESS QUEEN ROTATED NINETY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA10,
+ },
+ [0x1FA11]={
+ category="so",
+ description="BLACK CHESS ROOK ROTATED NINETY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA11,
+ },
+ [0x1FA12]={
+ category="so",
+ description="BLACK CHESS BISHOP ROTATED NINETY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA12,
+ },
+ [0x1FA13]={
+ category="so",
+ description="BLACK CHESS KNIGHT ROTATED NINETY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA13,
+ },
+ [0x1FA14]={
+ category="so",
+ description="BLACK CHESS PAWN ROTATED NINETY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA14,
+ },
+ [0x1FA15]={
+ category="so",
+ description="NEUTRAL CHESS KING ROTATED NINETY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA15,
+ },
+ [0x1FA16]={
+ category="so",
+ description="NEUTRAL CHESS QUEEN ROTATED NINETY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA16,
+ },
+ [0x1FA17]={
+ category="so",
+ description="NEUTRAL CHESS ROOK ROTATED NINETY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA17,
+ },
+ [0x1FA18]={
+ category="so",
+ description="NEUTRAL CHESS BISHOP ROTATED NINETY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA18,
+ },
+ [0x1FA19]={
+ category="so",
+ description="NEUTRAL CHESS KNIGHT ROTATED NINETY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA19,
+ },
+ [0x1FA1A]={
+ category="so",
+ description="NEUTRAL CHESS PAWN ROTATED NINETY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA1A,
+ },
+ [0x1FA1B]={
+ category="so",
+ description="WHITE CHESS KNIGHT ROTATED ONE HUNDRED THIRTY-FIVE DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA1B,
+ },
+ [0x1FA1C]={
+ category="so",
+ description="BLACK CHESS KNIGHT ROTATED ONE HUNDRED THIRTY-FIVE DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA1C,
+ },
+ [0x1FA1D]={
+ category="so",
+ description="NEUTRAL CHESS KNIGHT ROTATED ONE HUNDRED THIRTY-FIVE DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA1D,
+ },
+ [0x1FA1E]={
+ category="so",
+ description="WHITE CHESS TURNED KING",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA1E,
+ },
+ [0x1FA1F]={
+ category="so",
+ description="WHITE CHESS TURNED QUEEN",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA1F,
+ },
+ [0x1FA20]={
+ category="so",
+ description="WHITE CHESS TURNED ROOK",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA20,
+ },
+ [0x1FA21]={
+ category="so",
+ description="WHITE CHESS TURNED BISHOP",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA21,
+ },
+ [0x1FA22]={
+ category="so",
+ description="WHITE CHESS TURNED KNIGHT",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA22,
+ },
+ [0x1FA23]={
+ category="so",
+ description="WHITE CHESS TURNED PAWN",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA23,
+ },
+ [0x1FA24]={
+ category="so",
+ description="BLACK CHESS TURNED KING",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA24,
+ },
+ [0x1FA25]={
+ category="so",
+ description="BLACK CHESS TURNED QUEEN",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA25,
+ },
+ [0x1FA26]={
+ category="so",
+ description="BLACK CHESS TURNED ROOK",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA26,
+ },
+ [0x1FA27]={
+ category="so",
+ description="BLACK CHESS TURNED BISHOP",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA27,
+ },
+ [0x1FA28]={
+ category="so",
+ description="BLACK CHESS TURNED KNIGHT",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA28,
+ },
+ [0x1FA29]={
+ category="so",
+ description="BLACK CHESS TURNED PAWN",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA29,
+ },
+ [0x1FA2A]={
+ category="so",
+ description="NEUTRAL CHESS TURNED KING",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA2A,
+ },
+ [0x1FA2B]={
+ category="so",
+ description="NEUTRAL CHESS TURNED QUEEN",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA2B,
+ },
+ [0x1FA2C]={
+ category="so",
+ description="NEUTRAL CHESS TURNED ROOK",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA2C,
+ },
+ [0x1FA2D]={
+ category="so",
+ description="NEUTRAL CHESS TURNED BISHOP",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA2D,
+ },
+ [0x1FA2E]={
+ category="so",
+ description="NEUTRAL CHESS TURNED KNIGHT",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA2E,
+ },
+ [0x1FA2F]={
+ category="so",
+ description="NEUTRAL CHESS TURNED PAWN",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA2F,
+ },
+ [0x1FA30]={
+ category="so",
+ description="WHITE CHESS KNIGHT ROTATED TWO HUNDRED TWENTY-FIVE DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA30,
+ },
+ [0x1FA31]={
+ category="so",
+ description="BLACK CHESS KNIGHT ROTATED TWO HUNDRED TWENTY-FIVE DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA31,
+ },
+ [0x1FA32]={
+ category="so",
+ description="NEUTRAL CHESS KNIGHT ROTATED TWO HUNDRED TWENTY-FIVE DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA32,
+ },
+ [0x1FA33]={
+ category="so",
+ description="WHITE CHESS KING ROTATED TWO HUNDRED SEVENTY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA33,
+ },
+ [0x1FA34]={
+ category="so",
+ description="WHITE CHESS QUEEN ROTATED TWO HUNDRED SEVENTY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA34,
+ },
+ [0x1FA35]={
+ category="so",
+ description="WHITE CHESS ROOK ROTATED TWO HUNDRED SEVENTY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA35,
+ },
+ [0x1FA36]={
+ category="so",
+ description="WHITE CHESS BISHOP ROTATED TWO HUNDRED SEVENTY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA36,
+ },
+ [0x1FA37]={
+ category="so",
+ description="WHITE CHESS KNIGHT ROTATED TWO HUNDRED SEVENTY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA37,
+ },
+ [0x1FA38]={
+ category="so",
+ description="WHITE CHESS PAWN ROTATED TWO HUNDRED SEVENTY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA38,
+ },
+ [0x1FA39]={
+ category="so",
+ description="BLACK CHESS KING ROTATED TWO HUNDRED SEVENTY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA39,
+ },
+ [0x1FA3A]={
+ category="so",
+ description="BLACK CHESS QUEEN ROTATED TWO HUNDRED SEVENTY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA3A,
+ },
+ [0x1FA3B]={
+ category="so",
+ description="BLACK CHESS ROOK ROTATED TWO HUNDRED SEVENTY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA3B,
+ },
+ [0x1FA3C]={
+ category="so",
+ description="BLACK CHESS BISHOP ROTATED TWO HUNDRED SEVENTY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA3C,
+ },
+ [0x1FA3D]={
+ category="so",
+ description="BLACK CHESS KNIGHT ROTATED TWO HUNDRED SEVENTY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA3D,
+ },
+ [0x1FA3E]={
+ category="so",
+ description="BLACK CHESS PAWN ROTATED TWO HUNDRED SEVENTY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA3E,
+ },
+ [0x1FA3F]={
+ category="so",
+ description="NEUTRAL CHESS KING ROTATED TWO HUNDRED SEVENTY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA3F,
+ },
+ [0x1FA40]={
+ category="so",
+ description="NEUTRAL CHESS QUEEN ROTATED TWO HUNDRED SEVENTY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA40,
+ },
+ [0x1FA41]={
+ category="so",
+ description="NEUTRAL CHESS ROOK ROTATED TWO HUNDRED SEVENTY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA41,
+ },
+ [0x1FA42]={
+ category="so",
+ description="NEUTRAL CHESS BISHOP ROTATED TWO HUNDRED SEVENTY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA42,
+ },
+ [0x1FA43]={
+ category="so",
+ description="NEUTRAL CHESS KNIGHT ROTATED TWO HUNDRED SEVENTY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA43,
+ },
+ [0x1FA44]={
+ category="so",
+ description="NEUTRAL CHESS PAWN ROTATED TWO HUNDRED SEVENTY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA44,
+ },
+ [0x1FA45]={
+ category="so",
+ description="WHITE CHESS KNIGHT ROTATED THREE HUNDRED FIFTEEN DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA45,
+ },
+ [0x1FA46]={
+ category="so",
+ description="BLACK CHESS KNIGHT ROTATED THREE HUNDRED FIFTEEN DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA46,
+ },
+ [0x1FA47]={
+ category="so",
+ description="NEUTRAL CHESS KNIGHT ROTATED THREE HUNDRED FIFTEEN DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA47,
+ },
+ [0x1FA48]={
+ category="so",
+ description="WHITE CHESS EQUIHOPPER",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA48,
+ },
+ [0x1FA49]={
+ category="so",
+ description="BLACK CHESS EQUIHOPPER",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA49,
+ },
+ [0x1FA4A]={
+ category="so",
+ description="NEUTRAL CHESS EQUIHOPPER",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA4A,
+ },
+ [0x1FA4B]={
+ category="so",
+ description="WHITE CHESS EQUIHOPPER ROTATED NINETY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA4B,
+ },
+ [0x1FA4C]={
+ category="so",
+ description="BLACK CHESS EQUIHOPPER ROTATED NINETY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA4C,
+ },
+ [0x1FA4D]={
+ category="so",
+ description="NEUTRAL CHESS EQUIHOPPER ROTATED NINETY DEGREES",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA4D,
+ },
+ [0x1FA4E]={
+ category="so",
+ description="WHITE CHESS KNIGHT-QUEEN",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA4E,
+ },
+ [0x1FA4F]={
+ category="so",
+ description="WHITE CHESS KNIGHT-ROOK",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA4F,
+ },
+ [0x1FA50]={
+ category="so",
+ description="WHITE CHESS KNIGHT-BISHOP",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA50,
+ },
+ [0x1FA51]={
+ category="so",
+ description="BLACK CHESS KNIGHT-QUEEN",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA51,
+ },
+ [0x1FA52]={
+ category="so",
+ description="BLACK CHESS KNIGHT-ROOK",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA52,
+ },
+ [0x1FA53]={
+ category="so",
+ description="BLACK CHESS KNIGHT-BISHOP",
+ direction="on",
+ linebreak="al",
+ unicodeslot=0x1FA53,
+ },
[0x1FA60]={
category="so",
description="XIANGQI RED GENERAL",
@@ -247894,6 +251716,134 @@ characters.data={
linebreak="id",
unicodeslot=0x1FA6D,
},
+ [0x1FA70]={
+ category="so",
+ cjkwd="w",
+ description="BALLET SHOES",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1FA70,
+ },
+ [0x1FA71]={
+ category="so",
+ cjkwd="w",
+ description="ONE-PIECE SWIMSUIT",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1FA71,
+ },
+ [0x1FA72]={
+ category="so",
+ cjkwd="w",
+ description="BRIEFS",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1FA72,
+ },
+ [0x1FA73]={
+ category="so",
+ cjkwd="w",
+ description="SHORTS",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1FA73,
+ },
+ [0x1FA78]={
+ category="so",
+ cjkwd="w",
+ description="DROP OF BLOOD",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1FA78,
+ },
+ [0x1FA79]={
+ category="so",
+ cjkwd="w",
+ description="ADHESIVE BANDAGE",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1FA79,
+ },
+ [0x1FA7A]={
+ category="so",
+ cjkwd="w",
+ description="STETHOSCOPE",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1FA7A,
+ },
+ [0x1FA80]={
+ category="so",
+ cjkwd="w",
+ description="YO-YO",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1FA80,
+ },
+ [0x1FA81]={
+ category="so",
+ cjkwd="w",
+ description="KITE",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1FA81,
+ },
+ [0x1FA82]={
+ category="so",
+ cjkwd="w",
+ description="PARACHUTE",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1FA82,
+ },
+ [0x1FA90]={
+ category="so",
+ cjkwd="w",
+ description="RINGED PLANET",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1FA90,
+ },
+ [0x1FA91]={
+ category="so",
+ cjkwd="w",
+ description="CHAIR",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1FA91,
+ },
+ [0x1FA92]={
+ category="so",
+ cjkwd="w",
+ description="RAZOR",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1FA92,
+ },
+ [0x1FA93]={
+ category="so",
+ cjkwd="w",
+ description="AXE",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1FA93,
+ },
+ [0x1FA94]={
+ category="so",
+ cjkwd="w",
+ description="DIYA LAMP",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1FA94,
+ },
+ [0x1FA95]={
+ category="so",
+ cjkwd="w",
+ description="BANJO",
+ direction="on",
+ linebreak="id",
+ unicodeslot=0x1FA95,
+ },
[0x2F800]={
category="lo",
cjkwd="w",
diff --git a/Master/texmf-dist/tex/context/base/mkiv/char-emj.lua b/Master/texmf-dist/tex/context/base/mkiv/char-emj.lua
index b00e9ebf809..e6c059174b7 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/char-emj.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/char-emj.lua
@@ -16,6 +16,7 @@ return {
["a button (blood type)"]={ 0x1F170, 0xFE0F },
["ab button (blood type)"]={ 0x1F18E },
["abacus"]={ 0x1F9EE },
+ ["accordion"]={ 0x1FA97 },
["adhesive bandage"]={ 0x1FA79 },
["admission tickets"]={ 0x1F39F, 0xFE0F },
["aerial tramway"]={ 0x1F6A1 },
@@ -29,6 +30,7 @@ return {
["ambulance"]={ 0x1F691 },
["american football"]={ 0x1F3C8 },
["amphora"]={ 0x1F3FA },
+ ["anatomical heart"]={ 0x1FAC0 },
["anchor"]={ 0x2693 },
["anger symbol"]={ 0x1F4A2 },
["angry face"]={ 0x1F620 },
@@ -40,8 +42,20 @@ return {
["aquarius"]={ 0x2652 },
["aries"]={ 0x2648 },
["articulated lorry"]={ 0x1F69B },
+ ["artist"]={ 0x1F9D1, 0x200D, 0x1F3A8 },
["artist palette"]={ 0x1F3A8 },
+ ["artist: dark skin tone"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x1F3A8 },
+ ["artist: light skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F3A8 },
+ ["artist: medium skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F3A8 },
+ ["artist: medium-dark skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F3A8 },
+ ["artist: medium-light skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F3A8 },
["astonished face"]={ 0x1F632 },
+ ["astronaut"]={ 0x1F9D1, 0x200D, 0x1F680 },
+ ["astronaut: dark skin tone"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x1F680 },
+ ["astronaut: light skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F680 },
+ ["astronaut: medium skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F680 },
+ ["astronaut: medium-dark skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F680 },
+ ["astronaut: medium-light skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F680 },
["atm sign"]={ 0x1F3E7 },
["atom symbol"]={ 0x269B, 0xFE0F },
["auto rickshaw"]={ 0x1F6FA },
@@ -115,9 +129,12 @@ return {
["beaming face with smiling eyes"]={ 0x1F601 },
["bear"]={ 0x1F43B },
["beating heart"]={ 0x1F493 },
+ ["beaver"]={ 0x1F9AB },
["bed"]={ 0x1F6CF, 0xFE0F },
["beer mug"]={ 0x1F37A },
+ ["beetle"]={ 0x1FAB2 },
["bell"]={ 0x1F514 },
+ ["bell pepper"]={ 0x1FAD1 },
["bell with slash"]={ 0x1F515 },
["bellhop bell"]={ 0x1F6CE, 0xFE0F },
["bento box"]={ 0x1F371 },
@@ -128,6 +145,8 @@ return {
["biohazard"]={ 0x2623, 0xFE0F },
["bird"]={ 0x1F426 },
["birthday cake"]={ 0x1F382 },
+ ["bison"]={ 0x1F9AC },
+ ["black cat"]={ 0x1F408, 0x200D, 0x2B1B },
["black circle"]={ 0x26AB },
["black flag"]={ 0x1F3F4 },
["black heart"]={ 0x1F5A4 },
@@ -143,12 +162,14 @@ return {
["blue circle"]={ 0x1F535 },
["blue heart"]={ 0x1F499 },
["blue square"]={ 0x1F7E6 },
+ ["blueberries"]={ 0x1FAD0 },
["boar"]={ 0x1F417 },
["bomb"]={ 0x1F4A3 },
["bone"]={ 0x1F9B4 },
["bookmark"]={ 0x1F516 },
["bookmark tabs"]={ 0x1F4D1 },
["books"]={ 0x1F4DA },
+ ["boomerang"]={ 0x1FA83 },
["bottle with popping cork"]={ 0x1F37E },
["bouquet"]={ 0x1F490 },
["bow and arrow"]={ 0x1F3F9 },
@@ -170,14 +191,9 @@ return {
["breast-feeding: medium-dark skin tone"]={ 0x1F931, 0x1F3FE },
["breast-feeding: medium-light skin tone"]={ 0x1F931, 0x1F3FC },
["brick"]={ 0x1F9F1 },
- ["bride with veil"]={ 0x1F470 },
- ["bride with veil: dark skin tone"]={ 0x1F470, 0x1F3FF },
- ["bride with veil: light skin tone"]={ 0x1F470, 0x1F3FB },
- ["bride with veil: medium skin tone"]={ 0x1F470, 0x1F3FD },
- ["bride with veil: medium-dark skin tone"]={ 0x1F470, 0x1F3FE },
- ["bride with veil: medium-light skin tone"]={ 0x1F470, 0x1F3FC },
["bridge at night"]={ 0x1F309 },
["briefcase"]={ 0x1F4BC },
+ ["briefs"]={ 0x1FA72 },
["bright button"]={ 0x1F506 },
["broccoli"]={ 0x1F966 },
["broken heart"]={ 0x1F494 },
@@ -185,6 +201,8 @@ return {
["brown circle"]={ 0x1F7E4 },
["brown heart"]={ 0x1F90E },
["brown square"]={ 0x1F7EB },
+ ["bubble tea"]={ 0x1F9CB },
+ ["bucket"]={ 0x1FAA3 },
["bug"]={ 0x1F41B },
["building construction"]={ 0x1F3D7, 0xFE0F },
["bullet train"]={ 0x1F685 },
@@ -218,6 +236,7 @@ return {
["card index dividers"]={ 0x1F5C2, 0xFE0F },
["carousel horse"]={ 0x1F3A0 },
["carp streamer"]={ 0x1F38F },
+ ["carpentry saw"]={ 0x1FA9A },
["carrot"]={ 0x1F955 },
["castle"]={ 0x1F3F0 },
["cat"]={ 0x1F408 },
@@ -284,9 +303,11 @@ return {
["club suit"]={ 0x2663, 0xFE0F },
["clutch bag"]={ 0x1F45D },
["coat"]={ 0x1F9E5 },
+ ["cockroach"]={ 0x1FAB3 },
["cocktail glass"]={ 0x1F378 },
["coconut"]={ 0x1F965 },
["coffin"]={ 0x26B0, 0xFE0F },
+ ["coin"]={ 0x1FA99 },
["cold face"]={ 0x1F976 },
["collision"]={ 0x1F4A5 },
["comet"]={ 0x2604, 0xFE0F },
@@ -305,6 +326,12 @@ return {
["construction worker: medium-light skin tone"]={ 0x1F477, 0x1F3FC },
["control knobs"]={ 0x1F39B, 0xFE0F },
["convenience store"]={ 0x1F3EA },
+ ["cook"]={ 0x1F9D1, 0x200D, 0x1F373 },
+ ["cook: dark skin tone"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x1F373 },
+ ["cook: light skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F373 },
+ ["cook: medium skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F373 },
+ ["cook: medium-dark skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F373 },
+ ["cook: medium-light skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F373 },
["cooked rice"]={ 0x1F35A },
["cookie"]={ 0x1F36A },
["cooking"]={ 0x1F373 },
@@ -392,12 +419,14 @@ return {
["dim button"]={ 0x1F505 },
["direct hit"]={ 0x1F3AF },
["disappointed face"]={ 0x1F61E },
+ ["disguised face"]={ 0x1F978 },
+ ["divide"]={ 0x2797 },
["diving mask"]={ 0x1F93F },
- ["division sign"]={ 0x2797 },
["diya lamp"]={ 0x1FA94 },
["dizzy"]={ 0x1F4AB },
["dizzy face"]={ 0x1F635 },
["dna"]={ 0x1F9EC },
+ ["dodo"]={ 0x1F9A4 },
["dog"]={ 0x1F415 },
["dog face"]={ 0x1F436 },
["dollar banknote"]={ 0x1F4B5 },
@@ -447,6 +476,7 @@ return {
["eject button"]={ 0x23CF, 0xFE0F },
["electric plug"]={ 0x1F50C },
["elephant"]={ 0x1F418 },
+ ["elevator"]={ 0x1F6D7 },
["eleven o’clock"]={ 0x1F55A },
["eleven-thirty"]={ 0x1F566 },
["elf"]={ 0x1F9DD },
@@ -486,6 +516,12 @@ return {
["face with tongue"]={ 0x1F61B },
["face without mouth"]={ 0x1F636 },
["factory"]={ 0x1F3ED },
+ ["factory worker"]={ 0x1F9D1, 0x200D, 0x1F3ED },
+ ["factory worker: dark skin tone"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x1F3ED },
+ ["factory worker: light skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F3ED },
+ ["factory worker: medium skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F3ED },
+ ["factory worker: medium-dark skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F3ED },
+ ["factory worker: medium-light skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F3ED },
["fairy"]={ 0x1F9DA },
["fairy: dark skin tone"]={ 0x1F9DA, 0x1F3FF },
["fairy: light skin tone"]={ 0x1F9DA, 0x1F3FB },
@@ -520,12 +556,19 @@ return {
["family: woman, woman, girl"]={ 0x1F469, 0x200D, 0x1F469, 0x200D, 0x1F467 },
["family: woman, woman, girl, boy"]={ 0x1F469, 0x200D, 0x1F469, 0x200D, 0x1F467, 0x200D, 0x1F466 },
["family: woman, woman, girl, girl"]={ 0x1F469, 0x200D, 0x1F469, 0x200D, 0x1F467, 0x200D, 0x1F467 },
+ ["farmer"]={ 0x1F9D1, 0x200D, 0x1F33E },
+ ["farmer: dark skin tone"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x1F33E },
+ ["farmer: light skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F33E },
+ ["farmer: medium skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F33E },
+ ["farmer: medium-dark skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F33E },
+ ["farmer: medium-light skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F33E },
["fast down button"]={ 0x23EC },
["fast reverse button"]={ 0x23EA },
["fast up button"]={ 0x23EB },
["fast-forward button"]={ 0x23E9 },
["fax machine"]={ 0x1F4E0 },
["fearful face"]={ 0x1F628 },
+ ["feather"]={ 0x1FAB6 },
["female sign"]={ 0x2640, 0xFE0F },
["ferris wheel"]={ 0x1F3A1 },
["ferry"]={ 0x26F4, 0xFE0F },
@@ -538,6 +581,12 @@ return {
["fire engine"]={ 0x1F692 },
["fire extinguisher"]={ 0x1F9EF },
["firecracker"]={ 0x1F9E8 },
+ ["firefighter"]={ 0x1F9D1, 0x200D, 0x1F692 },
+ ["firefighter: dark skin tone"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x1F692 },
+ ["firefighter: light skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F692 },
+ ["firefighter: medium skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F692 },
+ ["firefighter: medium-dark skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F692 },
+ ["firefighter: medium-light skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F692 },
["fireworks"]={ 0x1F386 },
["first quarter moon"]={ 0x1F313 },
["first quarter moon face"]={ 0x1F31B },
@@ -684,7 +733,6 @@ return {
["flag: lithuania"]={ 0x1F1F1, 0x1F1F9 },
["flag: luxembourg"]={ 0x1F1F1, 0x1F1FA },
["flag: macao sar china"]={ 0x1F1F2, 0x1F1F4 },
- ["flag: macedonia"]={ 0x1F1F2, 0x1F1F0 },
["flag: madagascar"]={ 0x1F1F2, 0x1F1EC },
["flag: malawi"]={ 0x1F1F2, 0x1F1FC },
["flag: malaysia"]={ 0x1F1F2, 0x1F1FE },
@@ -718,6 +766,7 @@ return {
["flag: niue"]={ 0x1F1F3, 0x1F1FA },
["flag: norfolk island"]={ 0x1F1F3, 0x1F1EB },
["flag: north korea"]={ 0x1F1F0, 0x1F1F5 },
+ ["flag: north macedonia"]={ 0x1F1F2, 0x1F1F0 },
["flag: northern mariana islands"]={ 0x1F1F2, 0x1F1F5 },
["flag: norway"]={ 0x1F1F3, 0x1F1F4 },
["flag: oman"]={ 0x1F1F4, 0x1F1F2 },
@@ -811,6 +860,7 @@ return {
["flamingo"]={ 0x1F9A9 },
["flashlight"]={ 0x1F526 },
["flat shoe"]={ 0x1F97F },
+ ["flatbread"]={ 0x1FAD3 },
["fleur-de-lis"]={ 0x269C, 0xFE0F },
["flexed biceps"]={ 0x1F4AA },
["flexed biceps: dark skin tone"]={ 0x1F4AA, 0x1F3FF },
@@ -821,6 +871,7 @@ return {
["floppy disk"]={ 0x1F4BE },
["flower playing cards"]={ 0x1F3B4 },
["flushed face"]={ 0x1F633 },
+ ["fly"]={ 0x1FAB0 },
["flying disc"]={ 0x1F94F },
["flying saucer"]={ 0x1F6F8 },
["fog"]={ 0x1F32B, 0xFE0F },
@@ -831,6 +882,7 @@ return {
["folded hands: medium skin tone"]={ 0x1F64F, 0x1F3FD },
["folded hands: medium-dark skin tone"]={ 0x1F64F, 0x1F3FE },
["folded hands: medium-light skin tone"]={ 0x1F64F, 0x1F3FC },
+ ["fondue"]={ 0x1FAD5 },
["foot"]={ 0x1F9B6 },
["foot: dark skin tone"]={ 0x1F9B6, 0x1F3FF },
["foot: light skin tone"]={ 0x1F9B6, 0x1F3FB },
@@ -926,6 +978,13 @@ return {
["handshake"]={ 0x1F91D },
["hatching chick"]={ 0x1F423 },
["headphone"]={ 0x1F3A7 },
+ ["headstone"]={ 0x1FAA6 },
+ ["health worker"]={ 0x1F9D1, 0x200D, 0x2695, 0xFE0F },
+ ["health worker: dark skin tone"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x2695, 0xFE0F },
+ ["health worker: light skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x2695, 0xFE0F },
+ ["health worker: medium skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x2695, 0xFE0F },
+ ["health worker: medium-dark skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x2695, 0xFE0F },
+ ["health worker: medium-light skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x2695, 0xFE0F },
["hear-no-evil monkey"]={ 0x1F649 },
["heart decoration"]={ 0x1F49F },
["heart exclamation"]={ 0x2763, 0xFE0F },
@@ -947,6 +1006,7 @@ return {
["hollow red circle"]={ 0x2B55 },
["honey pot"]={ 0x1F36F },
["honeybee"]={ 0x1F41D },
+ ["hook"]={ 0x1FA9D },
["horizontal traffic light"]={ 0x1F6A5 },
["horse"]={ 0x1F40E },
["horse face"]={ 0x1F434 },
@@ -971,8 +1031,9 @@ return {
["hugging face"]={ 0x1F917 },
["hundred points"]={ 0x1F4AF },
["hushed face"]={ 0x1F62F },
+ ["hut"]={ 0x1F6D6 },
+ ["ice"]={ 0x1F9CA },
["ice cream"]={ 0x1F368 },
- ["ice cube"]={ 0x1F9CA },
["ice hockey"]={ 0x1F3D2 },
["ice skate"]={ 0x26F8, 0xFE0F },
["id button"]={ 0x1F194 },
@@ -1016,6 +1077,12 @@ return {
["jeans"]={ 0x1F456 },
["joker"]={ 0x1F0CF },
["joystick"]={ 0x1F579, 0xFE0F },
+ ["judge"]={ 0x1F9D1, 0x200D, 0x2696, 0xFE0F },
+ ["judge: dark skin tone"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x2696, 0xFE0F },
+ ["judge: light skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x2696, 0xFE0F },
+ ["judge: medium skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x2696, 0xFE0F },
+ ["judge: medium-dark skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x2696, 0xFE0F },
+ ["judge: medium-light skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x2696, 0xFE0F },
["kaaba"]={ 0x1F54B },
["kangaroo"]={ 0x1F998 },
["key"]={ 0x1F511 },
@@ -1047,12 +1114,14 @@ return {
["kitchen knife"]={ 0x1F52A },
["kite"]={ 0x1FA81 },
["kiwi fruit"]={ 0x1F95D },
+ ["knot"]={ 0x1FAA2 },
["koala"]={ 0x1F428 },
["lab coat"]={ 0x1F97C },
["label"]={ 0x1F3F7, 0xFE0F },
["lacrosse"]={ 0x1F94D },
+ ["ladder"]={ 0x1FA9C },
["lady beetle"]={ 0x1F41E },
- ["laptop computer"]={ 0x1F4BB },
+ ["laptop"]={ 0x1F4BB },
["large blue diamond"]={ 0x1F537 },
["large orange diamond"]={ 0x1F536 },
["last quarter moon"]={ 0x1F317 },
@@ -1099,6 +1168,7 @@ return {
["locked with pen"]={ 0x1F50F },
["locomotive"]={ 0x1F682 },
["lollipop"]={ 0x1F36D },
+ ["long drum"]={ 0x1FA98 },
["lotion bottle"]={ 0x1F9F4 },
["loudly crying face"]={ 0x1F62D },
["loudspeaker"]={ 0x1F4E2 },
@@ -1111,6 +1181,7 @@ return {
["love-you gesture: medium-dark skin tone"]={ 0x1F91F, 0x1F3FE },
["love-you gesture: medium-light skin tone"]={ 0x1F91F, 0x1F3FC },
["luggage"]={ 0x1F9F3 },
+ ["lungs"]={ 0x1FAC1 },
["lying face"]={ 0x1F925 },
["mage"]={ 0x1F9D9 },
["mage: dark skin tone"]={ 0x1F9D9, 0x1F3FF },
@@ -1118,11 +1189,13 @@ return {
["mage: medium skin tone"]={ 0x1F9D9, 0x1F3FD },
["mage: medium-dark skin tone"]={ 0x1F9D9, 0x1F3FE },
["mage: medium-light skin tone"]={ 0x1F9D9, 0x1F3FC },
+ ["magic wand"]={ 0x1FA84 },
["magnet"]={ 0x1F9F2 },
["magnifying glass tilted left"]={ 0x1F50D },
["magnifying glass tilted right"]={ 0x1F50E },
["mahjong red dragon"]={ 0x1F004 },
["male sign"]={ 0x2642, 0xFE0F },
+ ["mammoth"]={ 0x1F9A3 },
["man"]={ 0x1F468 },
["man artist"]={ 0x1F468, 0x200D, 0x1F3A8 },
["man artist: dark skin tone"]={ 0x1F468, 0x1F3FF, 0x200D, 0x1F3A8 },
@@ -1220,6 +1293,12 @@ return {
["man farmer: medium skin tone"]={ 0x1F468, 0x1F3FD, 0x200D, 0x1F33E },
["man farmer: medium-dark skin tone"]={ 0x1F468, 0x1F3FE, 0x200D, 0x1F33E },
["man farmer: medium-light skin tone"]={ 0x1F468, 0x1F3FC, 0x200D, 0x1F33E },
+ ["man feeding baby"]={ 0x1F468, 0x200D, 0x1F37C },
+ ["man feeding baby: dark skin tone"]={ 0x1F468, 0x1F3FF, 0x200D, 0x1F37C },
+ ["man feeding baby: light skin tone"]={ 0x1F468, 0x1F3FB, 0x200D, 0x1F37C },
+ ["man feeding baby: medium skin tone"]={ 0x1F468, 0x1F3FD, 0x200D, 0x1F37C },
+ ["man feeding baby: medium-dark skin tone"]={ 0x1F468, 0x1F3FE, 0x200D, 0x1F37C },
+ ["man feeding baby: medium-light skin tone"]={ 0x1F468, 0x1F3FC, 0x200D, 0x1F37C },
["man firefighter"]={ 0x1F468, 0x200D, 0x1F692 },
["man firefighter: dark skin tone"]={ 0x1F468, 0x1F3FF, 0x200D, 0x1F692 },
["man firefighter: light skin tone"]={ 0x1F468, 0x1F3FB, 0x200D, 0x1F692 },
@@ -1299,18 +1378,12 @@ return {
["man in steamy room: medium skin tone"]={ 0x1F9D6, 0x1F3FD, 0x200D, 0x2642, 0xFE0F },
["man in steamy room: medium-dark skin tone"]={ 0x1F9D6, 0x1F3FE, 0x200D, 0x2642, 0xFE0F },
["man in steamy room: medium-light skin tone"]={ 0x1F9D6, 0x1F3FC, 0x200D, 0x2642, 0xFE0F },
- ["man in suit levitating"]={ 0x1F574, 0xFE0F },
- ["man in suit levitating: dark skin tone"]={ 0x1F574, 0x1F3FF },
- ["man in suit levitating: light skin tone"]={ 0x1F574, 0x1F3FB },
- ["man in suit levitating: medium skin tone"]={ 0x1F574, 0x1F3FD },
- ["man in suit levitating: medium-dark skin tone"]={ 0x1F574, 0x1F3FE },
- ["man in suit levitating: medium-light skin tone"]={ 0x1F574, 0x1F3FC },
- ["man in tuxedo"]={ 0x1F935 },
- ["man in tuxedo: dark skin tone"]={ 0x1F935, 0x1F3FF },
- ["man in tuxedo: light skin tone"]={ 0x1F935, 0x1F3FB },
- ["man in tuxedo: medium skin tone"]={ 0x1F935, 0x1F3FD },
- ["man in tuxedo: medium-dark skin tone"]={ 0x1F935, 0x1F3FE },
- ["man in tuxedo: medium-light skin tone"]={ 0x1F935, 0x1F3FC },
+ ["man in tuxedo"]={ 0x1F935, 0x200D, 0x2642, 0xFE0F },
+ ["man in tuxedo: dark skin tone"]={ 0x1F935, 0x1F3FF, 0x200D, 0x2642, 0xFE0F },
+ ["man in tuxedo: light skin tone"]={ 0x1F935, 0x1F3FB, 0x200D, 0x2642, 0xFE0F },
+ ["man in tuxedo: medium skin tone"]={ 0x1F935, 0x1F3FD, 0x200D, 0x2642, 0xFE0F },
+ ["man in tuxedo: medium-dark skin tone"]={ 0x1F935, 0x1F3FE, 0x200D, 0x2642, 0xFE0F },
+ ["man in tuxedo: medium-light skin tone"]={ 0x1F935, 0x1F3FC, 0x200D, 0x2642, 0xFE0F },
["man judge"]={ 0x1F468, 0x200D, 0x2696, 0xFE0F },
["man judge: dark skin tone"]={ 0x1F468, 0x1F3FF, 0x200D, 0x2696, 0xFE0F },
["man judge: light skin tone"]={ 0x1F468, 0x1F3FB, 0x200D, 0x2696, 0xFE0F },
@@ -1497,18 +1570,18 @@ return {
["man wearing turban: medium skin tone"]={ 0x1F473, 0x1F3FD, 0x200D, 0x2642, 0xFE0F },
["man wearing turban: medium-dark skin tone"]={ 0x1F473, 0x1F3FE, 0x200D, 0x2642, 0xFE0F },
["man wearing turban: medium-light skin tone"]={ 0x1F473, 0x1F3FC, 0x200D, 0x2642, 0xFE0F },
- ["man with chinese cap"]={ 0x1F472 },
- ["man with chinese cap: dark skin tone"]={ 0x1F472, 0x1F3FF },
- ["man with chinese cap: light skin tone"]={ 0x1F472, 0x1F3FB },
- ["man with chinese cap: medium skin tone"]={ 0x1F472, 0x1F3FD },
- ["man with chinese cap: medium-dark skin tone"]={ 0x1F472, 0x1F3FE },
- ["man with chinese cap: medium-light skin tone"]={ 0x1F472, 0x1F3FC },
- ["man with probing cane"]={ 0x1F468, 0x200D, 0x1F9AF },
- ["man with probing cane: dark skin tone"]={ 0x1F468, 0x1F3FF, 0x200D, 0x1F9AF },
- ["man with probing cane: light skin tone"]={ 0x1F468, 0x1F3FB, 0x200D, 0x1F9AF },
- ["man with probing cane: medium skin tone"]={ 0x1F468, 0x1F3FD, 0x200D, 0x1F9AF },
- ["man with probing cane: medium-dark skin tone"]={ 0x1F468, 0x1F3FE, 0x200D, 0x1F9AF },
- ["man with probing cane: medium-light skin tone"]={ 0x1F468, 0x1F3FC, 0x200D, 0x1F9AF },
+ ["man with veil"]={ 0x1F470, 0x200D, 0x2642, 0xFE0F },
+ ["man with veil: dark skin tone"]={ 0x1F470, 0x1F3FF, 0x200D, 0x2642, 0xFE0F },
+ ["man with veil: light skin tone"]={ 0x1F470, 0x1F3FB, 0x200D, 0x2642, 0xFE0F },
+ ["man with veil: medium skin tone"]={ 0x1F470, 0x1F3FD, 0x200D, 0x2642, 0xFE0F },
+ ["man with veil: medium-dark skin tone"]={ 0x1F470, 0x1F3FE, 0x200D, 0x2642, 0xFE0F },
+ ["man with veil: medium-light skin tone"]={ 0x1F470, 0x1F3FC, 0x200D, 0x2642, 0xFE0F },
+ ["man with white cane"]={ 0x1F468, 0x200D, 0x1F9AF },
+ ["man with white cane: dark skin tone"]={ 0x1F468, 0x1F3FF, 0x200D, 0x1F9AF },
+ ["man with white cane: light skin tone"]={ 0x1F468, 0x1F3FB, 0x200D, 0x1F9AF },
+ ["man with white cane: medium skin tone"]={ 0x1F468, 0x1F3FD, 0x200D, 0x1F9AF },
+ ["man with white cane: medium-dark skin tone"]={ 0x1F468, 0x1F3FE, 0x200D, 0x1F9AF },
+ ["man with white cane: medium-light skin tone"]={ 0x1F468, 0x1F3FC, 0x200D, 0x1F9AF },
["man zombie"]={ 0x1F9DF, 0x200D, 0x2642, 0xFE0F },
["man: bald"]={ 0x1F468, 0x200D, 0x1F9B2 },
["man: beard"]={ 0x1F9D4 },
@@ -1560,6 +1633,12 @@ return {
["martial arts uniform"]={ 0x1F94B },
["mate"]={ 0x1F9C9 },
["meat on bone"]={ 0x1F356 },
+ ["mechanic"]={ 0x1F9D1, 0x200D, 0x1F527 },
+ ["mechanic: dark skin tone"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x1F527 },
+ ["mechanic: light skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F527 },
+ ["mechanic: medium skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F527 },
+ ["mechanic: medium-dark skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F527 },
+ ["mechanic: medium-light skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F527 },
["mechanical arm"]={ 0x1F9BE },
["mechanical leg"]={ 0x1F9BF },
["medical symbol"]={ 0x2695, 0xFE0F },
@@ -1573,15 +1652,25 @@ return {
["men holding hands: dark skin tone, medium-dark skin tone"]={ 0x1F468, 0x1F3FF, 0x200D, 0x1F91D, 0x200D, 0x1F468, 0x1F3FE },
["men holding hands: dark skin tone, medium-light skin tone"]={ 0x1F468, 0x1F3FF, 0x200D, 0x1F91D, 0x200D, 0x1F468, 0x1F3FC },
["men holding hands: light skin tone"]={ 0x1F46C, 0x1F3FB },
+ ["men holding hands: light skin tone, dark skin tone"]={ 0x1F468, 0x1F3FB, 0x200D, 0x1F91D, 0x200D, 0x1F468, 0x1F3FF },
+ ["men holding hands: light skin tone, medium skin tone"]={ 0x1F468, 0x1F3FB, 0x200D, 0x1F91D, 0x200D, 0x1F468, 0x1F3FD },
+ ["men holding hands: light skin tone, medium-dark skin tone"]={ 0x1F468, 0x1F3FB, 0x200D, 0x1F91D, 0x200D, 0x1F468, 0x1F3FE },
+ ["men holding hands: light skin tone, medium-light skin tone"]={ 0x1F468, 0x1F3FB, 0x200D, 0x1F91D, 0x200D, 0x1F468, 0x1F3FC },
["men holding hands: medium skin tone"]={ 0x1F46C, 0x1F3FD },
+ ["men holding hands: medium skin tone, dark skin tone"]={ 0x1F468, 0x1F3FD, 0x200D, 0x1F91D, 0x200D, 0x1F468, 0x1F3FF },
["men holding hands: medium skin tone, light skin tone"]={ 0x1F468, 0x1F3FD, 0x200D, 0x1F91D, 0x200D, 0x1F468, 0x1F3FB },
+ ["men holding hands: medium skin tone, medium-dark skin tone"]={ 0x1F468, 0x1F3FD, 0x200D, 0x1F91D, 0x200D, 0x1F468, 0x1F3FE },
["men holding hands: medium skin tone, medium-light skin tone"]={ 0x1F468, 0x1F3FD, 0x200D, 0x1F91D, 0x200D, 0x1F468, 0x1F3FC },
["men holding hands: medium-dark skin tone"]={ 0x1F46C, 0x1F3FE },
+ ["men holding hands: medium-dark skin tone, dark skin tone"]={ 0x1F468, 0x1F3FE, 0x200D, 0x1F91D, 0x200D, 0x1F468, 0x1F3FF },
["men holding hands: medium-dark skin tone, light skin tone"]={ 0x1F468, 0x1F3FE, 0x200D, 0x1F91D, 0x200D, 0x1F468, 0x1F3FB },
["men holding hands: medium-dark skin tone, medium skin tone"]={ 0x1F468, 0x1F3FE, 0x200D, 0x1F91D, 0x200D, 0x1F468, 0x1F3FD },
["men holding hands: medium-dark skin tone, medium-light skin tone"]={ 0x1F468, 0x1F3FE, 0x200D, 0x1F91D, 0x200D, 0x1F468, 0x1F3FC },
["men holding hands: medium-light skin tone"]={ 0x1F46C, 0x1F3FC },
+ ["men holding hands: medium-light skin tone, dark skin tone"]={ 0x1F468, 0x1F3FC, 0x200D, 0x1F91D, 0x200D, 0x1F468, 0x1F3FF },
["men holding hands: medium-light skin tone, light skin tone"]={ 0x1F468, 0x1F3FC, 0x200D, 0x1F91D, 0x200D, 0x1F468, 0x1F3FB },
+ ["men holding hands: medium-light skin tone, medium skin tone"]={ 0x1F468, 0x1F3FC, 0x200D, 0x1F91D, 0x200D, 0x1F468, 0x1F3FD },
+ ["men holding hands: medium-light skin tone, medium-dark skin tone"]={ 0x1F468, 0x1F3FC, 0x200D, 0x1F91D, 0x200D, 0x1F468, 0x1F3FE },
["men with bunny ears"]={ 0x1F46F, 0x200D, 0x2642, 0xFE0F },
["men wrestling"]={ 0x1F93C, 0x200D, 0x2642, 0xFE0F },
["menorah"]={ 0x1F54E },
@@ -1614,10 +1703,12 @@ return {
["middle finger: medium skin tone"]={ 0x1F595, 0x1F3FD },
["middle finger: medium-dark skin tone"]={ 0x1F595, 0x1F3FE },
["middle finger: medium-light skin tone"]={ 0x1F595, 0x1F3FC },
+ ["military helmet"]={ 0x1FA96 },
["military medal"]={ 0x1F396, 0xFE0F },
["milky way"]={ 0x1F30C },
["minibus"]={ 0x1F690 },
- ["minus sign"]={ 0x2796 },
+ ["minus"]={ 0x2796 },
+ ["mirror"]={ 0x1FA9E },
["moai"]={ 0x1F5FF },
["mobile phone"]={ 0x1F4F1 },
["mobile phone off"]={ 0x1F4F4 },
@@ -1643,6 +1734,7 @@ return {
["mountain railway"]={ 0x1F69E },
["mouse"]={ 0x1F401 },
["mouse face"]={ 0x1F42D },
+ ["mouse trap"]={ 0x1FAA4 },
["mouth"]={ 0x1F444 },
["movie camera"]={ 0x1F3A5 },
["mrs. claus"]={ 0x1F936 },
@@ -1651,13 +1743,19 @@ return {
["mrs. claus: medium skin tone"]={ 0x1F936, 0x1F3FD },
["mrs. claus: medium-dark skin tone"]={ 0x1F936, 0x1F3FE },
["mrs. claus: medium-light skin tone"]={ 0x1F936, 0x1F3FC },
- ["multiplication sign"]={ 0x2716, 0xFE0F },
+ ["multiply"]={ 0x2716, 0xFE0F },
["mushroom"]={ 0x1F344 },
["musical keyboard"]={ 0x1F3B9 },
["musical note"]={ 0x1F3B5 },
["musical notes"]={ 0x1F3B6 },
["musical score"]={ 0x1F3BC },
["muted speaker"]={ 0x1F507 },
+ ["mx claus"]={ 0x1F9D1, 0x200D, 0x1F384 },
+ ["mx claus: dark skin tone"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x1F384 },
+ ["mx claus: light skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F384 },
+ ["mx claus: medium skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F384 },
+ ["mx claus: medium-dark skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F384 },
+ ["mx claus: medium-light skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F384 },
["nail polish"]={ 0x1F485 },
["nail polish: dark skin tone"]={ 0x1F485, 0x1F3FF },
["nail polish: light skin tone"]={ 0x1F485, 0x1F3FB },
@@ -1670,6 +1768,7 @@ return {
["nazar amulet"]={ 0x1F9FF },
["necktie"]={ 0x1F454 },
["nerd face"]={ 0x1F913 },
+ ["nesting dolls"]={ 0x1FA86 },
["neutral face"]={ 0x1F610 },
["new button"]={ 0x1F195 },
["new moon"]={ 0x1F311 },
@@ -1680,6 +1779,12 @@ return {
["night with stars"]={ 0x1F303 },
["nine o’clock"]={ 0x1F558 },
["nine-thirty"]={ 0x1F564 },
+ ["ninja"]={ 0x1F977 },
+ ["ninja: dark skin tone"]={ 0x1F977, 0x1F3FF },
+ ["ninja: light skin tone"]={ 0x1F977, 0x1F3FB },
+ ["ninja: medium skin tone"]={ 0x1F977, 0x1F3FD },
+ ["ninja: medium-dark skin tone"]={ 0x1F977, 0x1F3FE },
+ ["ninja: medium-light skin tone"]={ 0x1F977, 0x1F3FC },
["no bicycles"]={ 0x1F6B3 },
["no entry"]={ 0x26D4 },
["no littering"]={ 0x1F6AF },
@@ -1701,6 +1806,12 @@ return {
["octopus"]={ 0x1F419 },
["oden"]={ 0x1F362 },
["office building"]={ 0x1F3E2 },
+ ["office worker"]={ 0x1F9D1, 0x200D, 0x1F4BC },
+ ["office worker: dark skin tone"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x1F4BC },
+ ["office worker: light skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F4BC },
+ ["office worker: medium skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F4BC },
+ ["office worker: medium-dark skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F4BC },
+ ["office worker: medium-light skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F4BC },
["ogre"]={ 0x1F479 },
["oil drum"]={ 0x1F6E2, 0xFE0F },
["ok button"]={ 0x1F197 },
@@ -1729,6 +1840,7 @@ return {
["older person: medium skin tone"]={ 0x1F9D3, 0x1F3FD },
["older person: medium-dark skin tone"]={ 0x1F9D3, 0x1F3FE },
["older person: medium-light skin tone"]={ 0x1F9D3, 0x1F3FC },
+ ["olive"]={ 0x1FAD2 },
["om"]={ 0x1F549, 0xFE0F },
["on! arrow"]={ 0x1F51B },
["oncoming automobile"]={ 0x1F698 },
@@ -1809,15 +1921,26 @@ return {
["people holding hands: dark skin tone, medium-dark skin tone"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x1F91D, 0x200D, 0x1F9D1, 0x1F3FE },
["people holding hands: dark skin tone, medium-light skin tone"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x1F91D, 0x200D, 0x1F9D1, 0x1F3FC },
["people holding hands: light skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F91D, 0x200D, 0x1F9D1, 0x1F3FB },
+ ["people holding hands: light skin tone, dark skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F91D, 0x200D, 0x1F9D1, 0x1F3FF },
+ ["people holding hands: light skin tone, medium skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F91D, 0x200D, 0x1F9D1, 0x1F3FD },
+ ["people holding hands: light skin tone, medium-dark skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F91D, 0x200D, 0x1F9D1, 0x1F3FE },
+ ["people holding hands: light skin tone, medium-light skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F91D, 0x200D, 0x1F9D1, 0x1F3FC },
["people holding hands: medium skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F91D, 0x200D, 0x1F9D1, 0x1F3FD },
+ ["people holding hands: medium skin tone, dark skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F91D, 0x200D, 0x1F9D1, 0x1F3FF },
["people holding hands: medium skin tone, light skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F91D, 0x200D, 0x1F9D1, 0x1F3FB },
+ ["people holding hands: medium skin tone, medium-dark skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F91D, 0x200D, 0x1F9D1, 0x1F3FE },
["people holding hands: medium skin tone, medium-light skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F91D, 0x200D, 0x1F9D1, 0x1F3FC },
["people holding hands: medium-dark skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F91D, 0x200D, 0x1F9D1, 0x1F3FE },
+ ["people holding hands: medium-dark skin tone, dark skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F91D, 0x200D, 0x1F9D1, 0x1F3FF },
["people holding hands: medium-dark skin tone, light skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F91D, 0x200D, 0x1F9D1, 0x1F3FB },
["people holding hands: medium-dark skin tone, medium skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F91D, 0x200D, 0x1F9D1, 0x1F3FD },
["people holding hands: medium-dark skin tone, medium-light skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F91D, 0x200D, 0x1F9D1, 0x1F3FC },
["people holding hands: medium-light skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F91D, 0x200D, 0x1F9D1, 0x1F3FC },
+ ["people holding hands: medium-light skin tone, dark skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F91D, 0x200D, 0x1F9D1, 0x1F3FF },
["people holding hands: medium-light skin tone, light skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F91D, 0x200D, 0x1F9D1, 0x1F3FB },
+ ["people holding hands: medium-light skin tone, medium skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F91D, 0x200D, 0x1F9D1, 0x1F3FD },
+ ["people holding hands: medium-light skin tone, medium-dark skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F91D, 0x200D, 0x1F9D1, 0x1F3FE },
+ ["people hugging"]={ 0x1FAC2 },
["people with bunny ears"]={ 0x1F46F },
["people wrestling"]={ 0x1F93C },
["performing arts"]={ 0x1F3AD },
@@ -1859,6 +1982,12 @@ return {
["person facepalming: medium skin tone"]={ 0x1F926, 0x1F3FD },
["person facepalming: medium-dark skin tone"]={ 0x1F926, 0x1F3FE },
["person facepalming: medium-light skin tone"]={ 0x1F926, 0x1F3FC },
+ ["person feeding baby"]={ 0x1F9D1, 0x200D, 0x1F37C },
+ ["person feeding baby: dark skin tone"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x1F37C },
+ ["person feeding baby: light skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F37C },
+ ["person feeding baby: medium skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F37C },
+ ["person feeding baby: medium-dark skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F37C },
+ ["person feeding baby: medium-light skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F37C },
["person fencing"]={ 0x1F93A },
["person frowning"]={ 0x1F64D },
["person frowning: dark skin tone"]={ 0x1F64D, 0x1F3FF },
@@ -1908,12 +2037,36 @@ return {
["person in lotus position: medium skin tone"]={ 0x1F9D8, 0x1F3FD },
["person in lotus position: medium-dark skin tone"]={ 0x1F9D8, 0x1F3FE },
["person in lotus position: medium-light skin tone"]={ 0x1F9D8, 0x1F3FC },
+ ["person in manual wheelchair"]={ 0x1F9D1, 0x200D, 0x1F9BD },
+ ["person in manual wheelchair: dark skin tone"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x1F9BD },
+ ["person in manual wheelchair: light skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F9BD },
+ ["person in manual wheelchair: medium skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F9BD },
+ ["person in manual wheelchair: medium-dark skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F9BD },
+ ["person in manual wheelchair: medium-light skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F9BD },
+ ["person in motorized wheelchair"]={ 0x1F9D1, 0x200D, 0x1F9BC },
+ ["person in motorized wheelchair: dark skin tone"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x1F9BC },
+ ["person in motorized wheelchair: light skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F9BC },
+ ["person in motorized wheelchair: medium skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F9BC },
+ ["person in motorized wheelchair: medium-dark skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F9BC },
+ ["person in motorized wheelchair: medium-light skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F9BC },
["person in steamy room"]={ 0x1F9D6 },
["person in steamy room: dark skin tone"]={ 0x1F9D6, 0x1F3FF },
["person in steamy room: light skin tone"]={ 0x1F9D6, 0x1F3FB },
["person in steamy room: medium skin tone"]={ 0x1F9D6, 0x1F3FD },
["person in steamy room: medium-dark skin tone"]={ 0x1F9D6, 0x1F3FE },
["person in steamy room: medium-light skin tone"]={ 0x1F9D6, 0x1F3FC },
+ ["person in suit levitating"]={ 0x1F574, 0xFE0F },
+ ["person in suit levitating: dark skin tone"]={ 0x1F574, 0x1F3FF },
+ ["person in suit levitating: light skin tone"]={ 0x1F574, 0x1F3FB },
+ ["person in suit levitating: medium skin tone"]={ 0x1F574, 0x1F3FD },
+ ["person in suit levitating: medium-dark skin tone"]={ 0x1F574, 0x1F3FE },
+ ["person in suit levitating: medium-light skin tone"]={ 0x1F574, 0x1F3FC },
+ ["person in tuxedo"]={ 0x1F935 },
+ ["person in tuxedo: dark skin tone"]={ 0x1F935, 0x1F3FF },
+ ["person in tuxedo: light skin tone"]={ 0x1F935, 0x1F3FB },
+ ["person in tuxedo: medium skin tone"]={ 0x1F935, 0x1F3FD },
+ ["person in tuxedo: medium-dark skin tone"]={ 0x1F935, 0x1F3FE },
+ ["person in tuxedo: medium-light skin tone"]={ 0x1F935, 0x1F3FC },
["person juggling"]={ 0x1F939 },
["person juggling: dark skin tone"]={ 0x1F939, 0x1F3FF },
["person juggling: light skin tone"]={ 0x1F939, 0x1F3FB },
@@ -2022,25 +2175,80 @@ return {
["person wearing turban: medium skin tone"]={ 0x1F473, 0x1F3FD },
["person wearing turban: medium-dark skin tone"]={ 0x1F473, 0x1F3FE },
["person wearing turban: medium-light skin tone"]={ 0x1F473, 0x1F3FC },
+ ["person with skullcap"]={ 0x1F472 },
+ ["person with skullcap: dark skin tone"]={ 0x1F472, 0x1F3FF },
+ ["person with skullcap: light skin tone"]={ 0x1F472, 0x1F3FB },
+ ["person with skullcap: medium skin tone"]={ 0x1F472, 0x1F3FD },
+ ["person with skullcap: medium-dark skin tone"]={ 0x1F472, 0x1F3FE },
+ ["person with skullcap: medium-light skin tone"]={ 0x1F472, 0x1F3FC },
+ ["person with veil"]={ 0x1F470 },
+ ["person with veil: dark skin tone"]={ 0x1F470, 0x1F3FF },
+ ["person with veil: light skin tone"]={ 0x1F470, 0x1F3FB },
+ ["person with veil: medium skin tone"]={ 0x1F470, 0x1F3FD },
+ ["person with veil: medium-dark skin tone"]={ 0x1F470, 0x1F3FE },
+ ["person with veil: medium-light skin tone"]={ 0x1F470, 0x1F3FC },
+ ["person with white cane"]={ 0x1F9D1, 0x200D, 0x1F9AF },
+ ["person with white cane: dark skin tone"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x1F9AF },
+ ["person with white cane: light skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F9AF },
+ ["person with white cane: medium skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F9AF },
+ ["person with white cane: medium-dark skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F9AF },
+ ["person with white cane: medium-light skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F9AF },
+ ["person: bald"]={ 0x1F9D1, 0x200D, 0x1F9B2 },
["person: blond hair"]={ 0x1F471 },
+ ["person: curly hair"]={ 0x1F9D1, 0x200D, 0x1F9B1 },
["person: dark skin tone"]={ 0x1F9D1, 0x1F3FF },
+ ["person: dark skin tone, bald"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x1F9B2 },
["person: dark skin tone, blond hair"]={ 0x1F471, 0x1F3FF },
+ ["person: dark skin tone, curly hair"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x1F9B1 },
+ ["person: dark skin tone, red hair"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x1F9B0 },
+ ["person: dark skin tone, white hair"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x1F9B3 },
["person: light skin tone"]={ 0x1F9D1, 0x1F3FB },
+ ["person: light skin tone, bald"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F9B2 },
["person: light skin tone, blond hair"]={ 0x1F471, 0x1F3FB },
+ ["person: light skin tone, curly hair"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F9B1 },
+ ["person: light skin tone, red hair"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F9B0 },
+ ["person: light skin tone, white hair"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F9B3 },
["person: medium skin tone"]={ 0x1F9D1, 0x1F3FD },
+ ["person: medium skin tone, bald"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F9B2 },
["person: medium skin tone, blond hair"]={ 0x1F471, 0x1F3FD },
+ ["person: medium skin tone, curly hair"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F9B1 },
+ ["person: medium skin tone, red hair"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F9B0 },
+ ["person: medium skin tone, white hair"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F9B3 },
["person: medium-dark skin tone"]={ 0x1F9D1, 0x1F3FE },
+ ["person: medium-dark skin tone, bald"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F9B2 },
["person: medium-dark skin tone, blond hair"]={ 0x1F471, 0x1F3FE },
+ ["person: medium-dark skin tone, curly hair"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F9B1 },
+ ["person: medium-dark skin tone, red hair"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F9B0 },
+ ["person: medium-dark skin tone, white hair"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F9B3 },
["person: medium-light skin tone"]={ 0x1F9D1, 0x1F3FC },
+ ["person: medium-light skin tone, bald"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F9B2 },
["person: medium-light skin tone, blond hair"]={ 0x1F471, 0x1F3FC },
+ ["person: medium-light skin tone, curly hair"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F9B1 },
+ ["person: medium-light skin tone, red hair"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F9B0 },
+ ["person: medium-light skin tone, white hair"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F9B3 },
+ ["person: red hair"]={ 0x1F9D1, 0x200D, 0x1F9B0 },
+ ["person: white hair"]={ 0x1F9D1, 0x200D, 0x1F9B3 },
["petri dish"]={ 0x1F9EB },
["pick"]={ 0x26CF, 0xFE0F },
+ ["pickup truck"]={ 0x1F6FB },
["pie"]={ 0x1F967 },
["pig"]={ 0x1F416 },
["pig face"]={ 0x1F437 },
["pig nose"]={ 0x1F43D },
["pile of poo"]={ 0x1F4A9 },
["pill"]={ 0x1F48A },
+ ["pilot"]={ 0x1F9D1, 0x200D, 0x2708, 0xFE0F },
+ ["pilot: dark skin tone"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x2708, 0xFE0F },
+ ["pilot: light skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x2708, 0xFE0F },
+ ["pilot: medium skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x2708, 0xFE0F },
+ ["pilot: medium-dark skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x2708, 0xFE0F },
+ ["pilot: medium-light skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x2708, 0xFE0F },
+ ["pinched fingers"]={ 0x1F90C },
+ ["pinched fingers: dark skin tone"]={ 0x1F90C, 0x1F3FF },
+ ["pinched fingers: light skin tone"]={ 0x1F90C, 0x1F3FB },
+ ["pinched fingers: medium skin tone"]={ 0x1F90C, 0x1F3FD },
+ ["pinched fingers: medium-dark skin tone"]={ 0x1F90C, 0x1F3FE },
+ ["pinched fingers: medium-light skin tone"]={ 0x1F90C, 0x1F3FC },
["pinching hand"]={ 0x1F90F },
["pinching hand: dark skin tone"]={ 0x1F90F, 0x1F3FF },
["pinching hand: light skin tone"]={ 0x1F90F, 0x1F3FB },
@@ -2054,11 +2262,15 @@ return {
["pisces"]={ 0x2653 },
["pistol"]={ 0x1F52B },
["pizza"]={ 0x1F355 },
+ ["piñata"]={ 0x1FA85 },
+ ["placard"]={ 0x1FAA7 },
["place of worship"]={ 0x1F6D0 },
["play button"]={ 0x25B6, 0xFE0F },
["play or pause button"]={ 0x23EF, 0xFE0F },
["pleading face"]={ 0x1F97A },
- ["plus sign"]={ 0x2795 },
+ ["plunger"]={ 0x1FAA0 },
+ ["plus"]={ 0x2795 },
+ ["polar bear"]={ 0x1F43B, 0x200D, 0x2744, 0xFE0F },
["police car"]={ 0x1F693 },
["police car light"]={ 0x1F6A8 },
["police officer"]={ 0x1F46E },
@@ -2076,6 +2288,7 @@ return {
["pot of food"]={ 0x1F372 },
["potable water"]={ 0x1F6B0 },
["potato"]={ 0x1F954 },
+ ["potted plant"]={ 0x1FAB4 },
["poultry leg"]={ 0x1F357 },
["pound banknote"]={ 0x1F4B7 },
["pouting cat"]={ 0x1F63E },
@@ -2101,7 +2314,6 @@ return {
["princess: medium-dark skin tone"]={ 0x1F478, 0x1F3FE },
["princess: medium-light skin tone"]={ 0x1F478, 0x1F3FC },
["printer"]={ 0x1F5A8, 0xFE0F },
- ["probing cane"]={ 0x1F9AF },
["prohibited"]={ 0x1F6AB },
["purple circle"]={ 0x1F7E3 },
["purple heart"]={ 0x1F49C },
@@ -2187,10 +2399,12 @@ return {
["ringed planet"]={ 0x1FA90 },
["roasted sweet potato"]={ 0x1F360 },
["robot"]={ 0x1F916 },
+ ["rock"]={ 0x1FAA8 },
["rocket"]={ 0x1F680 },
["roll of paper"]={ 0x1F9FB },
["rolled-up newspaper"]={ 0x1F5DE, 0xFE0F },
["roller coaster"]={ 0x1F3A2 },
+ ["roller skate"]={ 0x1F6FC },
["rolling on the floor laughing"]={ 0x1F923 },
["rooster"]={ 0x1F413 },
["rose"]={ 0x1F339 },
@@ -2220,10 +2434,18 @@ return {
["saxophone"]={ 0x1F3B7 },
["scarf"]={ 0x1F9E3 },
["school"]={ 0x1F3EB },
+ ["scientist"]={ 0x1F9D1, 0x200D, 0x1F52C },
+ ["scientist: dark skin tone"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x1F52C },
+ ["scientist: light skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F52C },
+ ["scientist: medium skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F52C },
+ ["scientist: medium-dark skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F52C },
+ ["scientist: medium-light skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F52C },
["scissors"]={ 0x2702, 0xFE0F },
["scorpio"]={ 0x264F },
["scorpion"]={ 0x1F982 },
+ ["screwdriver"]={ 0x1FA9B },
["scroll"]={ 0x1F4DC },
+ ["seal"]={ 0x1F9AD },
["seat"]={ 0x1F4BA },
["see-no-evil monkey"]={ 0x1F648 },
["seedling"]={ 0x1F331 },
@@ -2236,6 +2458,7 @@ return {
["service dog"]={ 0x1F415, 0x200D, 0x1F9BA },
["seven o’clock"]={ 0x1F556 },
["seven-thirty"]={ 0x1F562 },
+ ["sewing needle"]={ 0x1FAA1 },
["shallow pan of food"]={ 0x1F958 },
["shamrock"]={ 0x2618, 0xFE0F },
["shark"]={ 0x1F988 },
@@ -2259,6 +2482,12 @@ return {
["sign of the horns: medium skin tone"]={ 0x1F918, 0x1F3FD },
["sign of the horns: medium-dark skin tone"]={ 0x1F918, 0x1F3FE },
["sign of the horns: medium-light skin tone"]={ 0x1F918, 0x1F3FC },
+ ["singer"]={ 0x1F9D1, 0x200D, 0x1F3A4 },
+ ["singer: dark skin tone"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x1F3A4 },
+ ["singer: light skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F3A4 },
+ ["singer: medium skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F3A4 },
+ ["singer: medium-dark skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F3A4 },
+ ["singer: medium-light skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F3A4 },
["six o’clock"]={ 0x1F555 },
["six-thirty"]={ 0x1F561 },
["skateboard"]={ 0x1F6F9 },
@@ -2285,6 +2514,7 @@ return {
["smiling face with horns"]={ 0x1F608 },
["smiling face with smiling eyes"]={ 0x1F60A },
["smiling face with sunglasses"]={ 0x1F60E },
+ ["smiling face with tear"]={ 0x1F972 },
["smirking face"]={ 0x1F60F },
["snail"]={ 0x1F40C },
["snake"]={ 0x1F40D },
@@ -2345,6 +2575,12 @@ return {
["stopwatch"]={ 0x23F1, 0xFE0F },
["straight ruler"]={ 0x1F4CF },
["strawberry"]={ 0x1F353 },
+ ["student"]={ 0x1F9D1, 0x200D, 0x1F393 },
+ ["student: dark skin tone"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x1F393 },
+ ["student: light skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F393 },
+ ["student: medium skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F393 },
+ ["student: medium-dark skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F393 },
+ ["student: medium-light skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F393 },
["studio microphone"]={ 0x1F399, 0xFE0F },
["stuffed flatbread"]={ 0x1F959 },
["sun"]={ 0x2600, 0xFE0F },
@@ -2374,19 +2610,32 @@ return {
["suspension railway"]={ 0x1F69F },
["swan"]={ 0x1F9A2 },
["sweat droplets"]={ 0x1F4A6 },
- ["swim brief"]={ 0x1FA72 },
["synagogue"]={ 0x1F54D },
["syringe"]={ 0x1F489 },
["t-rex"]={ 0x1F996 },
["t-shirt"]={ 0x1F455 },
["taco"]={ 0x1F32E },
["takeout box"]={ 0x1F961 },
+ ["tamale"]={ 0x1FAD4 },
["tanabata tree"]={ 0x1F38B },
["tangerine"]={ 0x1F34A },
["taurus"]={ 0x2649 },
["taxi"]={ 0x1F695 },
+ ["teacher"]={ 0x1F9D1, 0x200D, 0x1F3EB },
+ ["teacher: dark skin tone"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x1F3EB },
+ ["teacher: light skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F3EB },
+ ["teacher: medium skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F3EB },
+ ["teacher: medium-dark skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F3EB },
+ ["teacher: medium-light skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F3EB },
["teacup without handle"]={ 0x1F375 },
+ ["teapot"]={ 0x1FAD6 },
["tear-off calendar"]={ 0x1F4C6 },
+ ["technologist"]={ 0x1F9D1, 0x200D, 0x1F4BB },
+ ["technologist: dark skin tone"]={ 0x1F9D1, 0x1F3FF, 0x200D, 0x1F4BB },
+ ["technologist: light skin tone"]={ 0x1F9D1, 0x1F3FB, 0x200D, 0x1F4BB },
+ ["technologist: medium skin tone"]={ 0x1F9D1, 0x1F3FD, 0x200D, 0x1F4BB },
+ ["technologist: medium-dark skin tone"]={ 0x1F9D1, 0x1F3FE, 0x200D, 0x1F4BB },
+ ["technologist: medium-light skin tone"]={ 0x1F9D1, 0x1F3FC, 0x200D, 0x1F4BB },
["teddy bear"]={ 0x1F9F8 },
["telephone"]={ 0x260E, 0xFE0F },
["telephone receiver"]={ 0x1F4DE },
@@ -2399,6 +2648,7 @@ return {
["test tube"]={ 0x1F9EA },
["thermometer"]={ 0x1F321, 0xFE0F },
["thinking face"]={ 0x1F914 },
+ ["thong sandal"]={ 0x1FA74 },
["thought balloon"]={ 0x1F4AD },
["thread"]={ 0x1F9F5 },
["three o’clock"]={ 0x1F552 },
@@ -2426,6 +2676,7 @@ return {
["tongue"]={ 0x1F445 },
["toolbox"]={ 0x1F9F0 },
["tooth"]={ 0x1F9B7 },
+ ["toothbrush"]={ 0x1FAA5 },
["top arrow"]={ 0x1F51D },
["top hat"]={ 0x1F3A9 },
["tornado"]={ 0x1F32A, 0xFE0F },
@@ -2435,6 +2686,8 @@ return {
["train"]={ 0x1F686 },
["tram"]={ 0x1F68A },
["tram car"]={ 0x1F68B },
+ ["transgender flag"]={ 0x1F3F3, 0xFE0F, 0x200D, 0x26A7, 0xFE0F },
+ ["transgender symbol"]={ 0x26A7, 0xFE0F },
["triangular flag"]={ 0x1F6A9 },
["triangular ruler"]={ 0x1F4D0 },
["trident emblem"]={ 0x1F531 },
@@ -2519,6 +2772,7 @@ return {
["whale"]={ 0x1F40B },
["wheel of dharma"]={ 0x2638, 0xFE0F },
["wheelchair symbol"]={ 0x267F },
+ ["white cane"]={ 0x1F9AF },
["white circle"]={ 0x26AA },
["white exclamation mark"]={ 0x2755 },
["white flag"]={ 0x1F3F3, 0xFE0F },
@@ -2533,6 +2787,7 @@ return {
["wilted flower"]={ 0x1F940 },
["wind chime"]={ 0x1F390 },
["wind face"]={ 0x1F32C, 0xFE0F },
+ ["window"]={ 0x1FA9F },
["wine glass"]={ 0x1F377 },
["winking face"]={ 0x1F609 },
["winking face with tongue"]={ 0x1F61C },
@@ -2660,6 +2915,12 @@ return {
["woman farmer: medium skin tone"]={ 0x1F469, 0x1F3FD, 0x200D, 0x1F33E },
["woman farmer: medium-dark skin tone"]={ 0x1F469, 0x1F3FE, 0x200D, 0x1F33E },
["woman farmer: medium-light skin tone"]={ 0x1F469, 0x1F3FC, 0x200D, 0x1F33E },
+ ["woman feeding baby"]={ 0x1F469, 0x200D, 0x1F37C },
+ ["woman feeding baby: dark skin tone"]={ 0x1F469, 0x1F3FF, 0x200D, 0x1F37C },
+ ["woman feeding baby: light skin tone"]={ 0x1F469, 0x1F3FB, 0x200D, 0x1F37C },
+ ["woman feeding baby: medium skin tone"]={ 0x1F469, 0x1F3FD, 0x200D, 0x1F37C },
+ ["woman feeding baby: medium-dark skin tone"]={ 0x1F469, 0x1F3FE, 0x200D, 0x1F37C },
+ ["woman feeding baby: medium-light skin tone"]={ 0x1F469, 0x1F3FC, 0x200D, 0x1F37C },
["woman firefighter"]={ 0x1F469, 0x200D, 0x1F692 },
["woman firefighter: dark skin tone"]={ 0x1F469, 0x1F3FF, 0x200D, 0x1F692 },
["woman firefighter: light skin tone"]={ 0x1F469, 0x1F3FB, 0x200D, 0x1F692 },
@@ -2739,6 +3000,12 @@ return {
["woman in steamy room: medium skin tone"]={ 0x1F9D6, 0x1F3FD, 0x200D, 0x2640, 0xFE0F },
["woman in steamy room: medium-dark skin tone"]={ 0x1F9D6, 0x1F3FE, 0x200D, 0x2640, 0xFE0F },
["woman in steamy room: medium-light skin tone"]={ 0x1F9D6, 0x1F3FC, 0x200D, 0x2640, 0xFE0F },
+ ["woman in tuxedo"]={ 0x1F935, 0x200D, 0x2640, 0xFE0F },
+ ["woman in tuxedo: dark skin tone"]={ 0x1F935, 0x1F3FF, 0x200D, 0x2640, 0xFE0F },
+ ["woman in tuxedo: light skin tone"]={ 0x1F935, 0x1F3FB, 0x200D, 0x2640, 0xFE0F },
+ ["woman in tuxedo: medium skin tone"]={ 0x1F935, 0x1F3FD, 0x200D, 0x2640, 0xFE0F },
+ ["woman in tuxedo: medium-dark skin tone"]={ 0x1F935, 0x1F3FE, 0x200D, 0x2640, 0xFE0F },
+ ["woman in tuxedo: medium-light skin tone"]={ 0x1F935, 0x1F3FC, 0x200D, 0x2640, 0xFE0F },
["woman judge"]={ 0x1F469, 0x200D, 0x2696, 0xFE0F },
["woman judge: dark skin tone"]={ 0x1F469, 0x1F3FF, 0x200D, 0x2696, 0xFE0F },
["woman judge: light skin tone"]={ 0x1F469, 0x1F3FB, 0x200D, 0x2696, 0xFE0F },
@@ -2931,12 +3198,18 @@ return {
["woman with headscarf: medium skin tone"]={ 0x1F9D5, 0x1F3FD },
["woman with headscarf: medium-dark skin tone"]={ 0x1F9D5, 0x1F3FE },
["woman with headscarf: medium-light skin tone"]={ 0x1F9D5, 0x1F3FC },
- ["woman with probing cane"]={ 0x1F469, 0x200D, 0x1F9AF },
- ["woman with probing cane: dark skin tone"]={ 0x1F469, 0x1F3FF, 0x200D, 0x1F9AF },
- ["woman with probing cane: light skin tone"]={ 0x1F469, 0x1F3FB, 0x200D, 0x1F9AF },
- ["woman with probing cane: medium skin tone"]={ 0x1F469, 0x1F3FD, 0x200D, 0x1F9AF },
- ["woman with probing cane: medium-dark skin tone"]={ 0x1F469, 0x1F3FE, 0x200D, 0x1F9AF },
- ["woman with probing cane: medium-light skin tone"]={ 0x1F469, 0x1F3FC, 0x200D, 0x1F9AF },
+ ["woman with veil"]={ 0x1F470, 0x200D, 0x2640, 0xFE0F },
+ ["woman with veil: dark skin tone"]={ 0x1F470, 0x1F3FF, 0x200D, 0x2640, 0xFE0F },
+ ["woman with veil: light skin tone"]={ 0x1F470, 0x1F3FB, 0x200D, 0x2640, 0xFE0F },
+ ["woman with veil: medium skin tone"]={ 0x1F470, 0x1F3FD, 0x200D, 0x2640, 0xFE0F },
+ ["woman with veil: medium-dark skin tone"]={ 0x1F470, 0x1F3FE, 0x200D, 0x2640, 0xFE0F },
+ ["woman with veil: medium-light skin tone"]={ 0x1F470, 0x1F3FC, 0x200D, 0x2640, 0xFE0F },
+ ["woman with white cane"]={ 0x1F469, 0x200D, 0x1F9AF },
+ ["woman with white cane: dark skin tone"]={ 0x1F469, 0x1F3FF, 0x200D, 0x1F9AF },
+ ["woman with white cane: light skin tone"]={ 0x1F469, 0x1F3FB, 0x200D, 0x1F9AF },
+ ["woman with white cane: medium skin tone"]={ 0x1F469, 0x1F3FD, 0x200D, 0x1F9AF },
+ ["woman with white cane: medium-dark skin tone"]={ 0x1F469, 0x1F3FE, 0x200D, 0x1F9AF },
+ ["woman with white cane: medium-light skin tone"]={ 0x1F469, 0x1F3FC, 0x200D, 0x1F9AF },
["woman zombie"]={ 0x1F9DF, 0x200D, 0x2640, 0xFE0F },
["woman: bald"]={ 0x1F469, 0x200D, 0x1F9B2 },
["woman: blond hair"]={ 0x1F471, 0x200D, 0x2640, 0xFE0F },
@@ -2984,20 +3257,32 @@ return {
["women holding hands: dark skin tone, medium-dark skin tone"]={ 0x1F469, 0x1F3FF, 0x200D, 0x1F91D, 0x200D, 0x1F469, 0x1F3FE },
["women holding hands: dark skin tone, medium-light skin tone"]={ 0x1F469, 0x1F3FF, 0x200D, 0x1F91D, 0x200D, 0x1F469, 0x1F3FC },
["women holding hands: light skin tone"]={ 0x1F46D, 0x1F3FB },
+ ["women holding hands: light skin tone, dark skin tone"]={ 0x1F469, 0x1F3FB, 0x200D, 0x1F91D, 0x200D, 0x1F469, 0x1F3FF },
+ ["women holding hands: light skin tone, medium skin tone"]={ 0x1F469, 0x1F3FB, 0x200D, 0x1F91D, 0x200D, 0x1F469, 0x1F3FD },
+ ["women holding hands: light skin tone, medium-dark skin tone"]={ 0x1F469, 0x1F3FB, 0x200D, 0x1F91D, 0x200D, 0x1F469, 0x1F3FE },
+ ["women holding hands: light skin tone, medium-light skin tone"]={ 0x1F469, 0x1F3FB, 0x200D, 0x1F91D, 0x200D, 0x1F469, 0x1F3FC },
["women holding hands: medium skin tone"]={ 0x1F46D, 0x1F3FD },
+ ["women holding hands: medium skin tone, dark skin tone"]={ 0x1F469, 0x1F3FD, 0x200D, 0x1F91D, 0x200D, 0x1F469, 0x1F3FF },
["women holding hands: medium skin tone, light skin tone"]={ 0x1F469, 0x1F3FD, 0x200D, 0x1F91D, 0x200D, 0x1F469, 0x1F3FB },
+ ["women holding hands: medium skin tone, medium-dark skin tone"]={ 0x1F469, 0x1F3FD, 0x200D, 0x1F91D, 0x200D, 0x1F469, 0x1F3FE },
["women holding hands: medium skin tone, medium-light skin tone"]={ 0x1F469, 0x1F3FD, 0x200D, 0x1F91D, 0x200D, 0x1F469, 0x1F3FC },
["women holding hands: medium-dark skin tone"]={ 0x1F46D, 0x1F3FE },
+ ["women holding hands: medium-dark skin tone, dark skin tone"]={ 0x1F469, 0x1F3FE, 0x200D, 0x1F91D, 0x200D, 0x1F469, 0x1F3FF },
["women holding hands: medium-dark skin tone, light skin tone"]={ 0x1F469, 0x1F3FE, 0x200D, 0x1F91D, 0x200D, 0x1F469, 0x1F3FB },
["women holding hands: medium-dark skin tone, medium skin tone"]={ 0x1F469, 0x1F3FE, 0x200D, 0x1F91D, 0x200D, 0x1F469, 0x1F3FD },
["women holding hands: medium-dark skin tone, medium-light skin tone"]={ 0x1F469, 0x1F3FE, 0x200D, 0x1F91D, 0x200D, 0x1F469, 0x1F3FC },
["women holding hands: medium-light skin tone"]={ 0x1F46D, 0x1F3FC },
+ ["women holding hands: medium-light skin tone, dark skin tone"]={ 0x1F469, 0x1F3FC, 0x200D, 0x1F91D, 0x200D, 0x1F469, 0x1F3FF },
["women holding hands: medium-light skin tone, light skin tone"]={ 0x1F469, 0x1F3FC, 0x200D, 0x1F91D, 0x200D, 0x1F469, 0x1F3FB },
+ ["women holding hands: medium-light skin tone, medium skin tone"]={ 0x1F469, 0x1F3FC, 0x200D, 0x1F91D, 0x200D, 0x1F469, 0x1F3FD },
+ ["women holding hands: medium-light skin tone, medium-dark skin tone"]={ 0x1F469, 0x1F3FC, 0x200D, 0x1F91D, 0x200D, 0x1F469, 0x1F3FE },
["women with bunny ears"]={ 0x1F46F, 0x200D, 0x2640, 0xFE0F },
["women wrestling"]={ 0x1F93C, 0x200D, 0x2640, 0xFE0F },
["women’s room"]={ 0x1F6BA },
+ ["wood"]={ 0x1FAB5 },
["woozy face"]={ 0x1F974 },
["world map"]={ 0x1F5FA, 0xFE0F },
+ ["worm"]={ 0x1FAB1 },
["worried face"]={ 0x1F61F },
["wrapped gift"]={ 0x1F381 },
["wrench"]={ 0x1F527 },
diff --git a/Master/texmf-dist/tex/context/base/mkiv/char-fio.lua b/Master/texmf-dist/tex/context/base/mkiv/char-fio.lua
index 9939bf04143..b1f652eedb0 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/char-fio.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/char-fio.lua
@@ -92,7 +92,11 @@ directives.register("filters.utf.reorder", function(v) configure("characters.f
directives.register("filters.utf.collapse", function(v) configure("characters.filters.utf.collapse", v) end)
directives.register("filters.utf.decompose", function(v) configure("characters.filters.utf.decompose",v) end)
-utffilters.setskippable { "mkiv", "mkvi", "mkix", "mkxi" }
+utffilters.setskippable {
+ "mkiv", "mkvi",
+ "mkix", "mkxi",
+ "mkxl", "mklx",
+}
interfaces.implement {
name = "enableutf",
diff --git a/Master/texmf-dist/tex/context/base/mkiv/char-ini.lua b/Master/texmf-dist/tex/context/base/mkiv/char-ini.lua
index fb9d9f126e4..1d202c8d42d 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/char-ini.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/char-ini.lua
@@ -192,6 +192,7 @@ insert(characters.ranges,{
end,
})
+
local blocks = allocate {
["adlam"] = { first = 0x1E900, last = 0x1E95F, description = "Adlam" },
["aegeannumbers"] = { first = 0x10100, last = 0x1013F, description = "Aegean Numbers" },
@@ -297,12 +298,14 @@ local blocks = allocate {
-- ["digitsthai"] = { first = 0x00E50, last = 0x00E59, math = true },
-- ["digitstibetan"] = { first = 0x00F20, last = 0x00F29, math = true },
["dingbats"] = { first = 0x02700, last = 0x027BF, description = "Dingbats" },
- ["dogra"] = { first = 0x11800, last = 0x1184F, description = "Dogra" },
+ ["dogra"] = { first = 0x11800, last = 0x1184F, description = "Dogra" },
["dominotiles"] = { first = 0x1F030, last = 0x1F09F, description = "Domino Tiles" },
["duployan"] = { first = 0x1BC00, last = 0x1BC9F, description = "Duployan" },
["earlydynasticcuneiform"] = { first = 0x12480, last = 0x1254F, description = "Early Dynastic Cuneiform" },
+ ["egyptianhieroglyphformatcontrols"] = { first = 0x13430, last = 0x1343F, description = "Egyptian Hieroglyph Format Controls" },
["egyptianhieroglyphs"] = { first = 0x13000, last = 0x1342F, description = "Egyptian Hieroglyphs" },
["elbasan"] = { first = 0x10500, last = 0x1052F, description = "Elbasan" },
+ ["elymaic"] = { first = 0x10FE0, last = 0x10FFF, description = "Elymaic" },
["emoticons"] = { first = 0x1F600, last = 0x1F64F, description = "Emoticons" },
["enclosedalphanumerics"] = { first = 0x02460, last = 0x024FF, description = "Enclosed Alphanumerics" },
["enclosedalphanumericsupplement"] = { first = 0x1F100, last = 0x1F1FF, description = "Enclosed Alphanumeric Supplement" },
@@ -316,7 +319,7 @@ local blocks = allocate {
["geometricshapes"] = { first = 0x025A0, last = 0x025FF, math = true, description = "Geometric Shapes" },
["geometricshapesextended"] = { first = 0x1F780, last = 0x1F7FF, description = "Geometric Shapes Extended" },
["georgian"] = { first = 0x010A0, last = 0x010FF, otf="geor", description = "Georgian" },
- ["georgianextended"] = { first = 0x01C90, last = 0x01CBF, description = "Georgian Extended" },
+ ["georgianextended"] = { first = 0x01C90, last = 0x01CBF, description = "Georgian Extended" },
["georgiansupplement"] = { first = 0x02D00, last = 0x02D2F, otf="geor", description = "Georgian Supplement" },
["glagolitic"] = { first = 0x02C00, last = 0x02C5F, otf="glag", description = "Glagolitic" },
["glagoliticsupplement"] = { first = 0x1E000, last = 0x1E02F, description = "Glagolitic Supplement" },
@@ -325,7 +328,7 @@ local blocks = allocate {
["greekandcoptic"] = { first = 0x00370, last = 0x003FF, otf="grek", description = "Greek and Coptic" },
["greekextended"] = { first = 0x01F00, last = 0x01FFF, otf="grek", description = "Greek Extended" },
["gujarati"] = { first = 0x00A80, last = 0x00AFF, otf="gujr", description = "Gujarati" },
- ["gunjalagondi"] = { first = 0x11D60, last = 0x11DAF, description = "Gunjala Gondi" },
+ ["gunjalagondi"] = { first = 0x11D60, last = 0x11DAF, description = "Gunjala Gondi" },
["gurmukhi"] = { first = 0x00A00, last = 0x00A7F, otf="guru", description = "Gurmukhi" },
["halfwidthandfullwidthforms"] = { first = 0x0FF00, last = 0x0FFEF, description = "Halfwidth and Fullwidth Forms" },
["hangulcompatibilityjamo"] = { first = 0x03130, last = 0x0318F, otf="jamo", description = "Hangul Compatibility Jamo" },
@@ -333,7 +336,7 @@ local blocks = allocate {
["hanguljamoextendeda"] = { first = 0x0A960, last = 0x0A97F, description = "Hangul Jamo Extended-A" },
["hanguljamoextendedb"] = { first = 0x0D7B0, last = 0x0D7FF, description = "Hangul Jamo Extended-B" },
["hangulsyllables"] = { first = 0x0AC00, last = 0x0D7AF, otf="hang", description = "Hangul Syllables" },
- ["hanifirohingya"] = { first = 0x10D00, last = 0x10D3F, description = "Hanifi Rohingya" },
+ ["hanifirohingya"] = { first = 0x10D00, last = 0x10D3F, description = "Hanifi Rohingya" },
["hanunoo"] = { first = 0x01720, last = 0x0173F, otf="hano", description = "Hanunoo" },
["hatran"] = { first = 0x108E0, last = 0x108FF, description = "Hatran" },
["hebrew"] = { first = 0x00590, last = 0x005FF, otf="hebr", description = "Hebrew" },
@@ -343,7 +346,7 @@ local blocks = allocate {
["ideographicdescriptioncharacters"] = { first = 0x02FF0, last = 0x02FFF, description = "Ideographic Description Characters" },
["ideographicsymbolsandpunctuation"] = { first = 0x16FE0, last = 0x16FFF, description = "Ideographic Symbols and Punctuation" },
["imperialaramaic"] = { first = 0x10840, last = 0x1085F, description = "Imperial Aramaic" },
- ["indicsiyaqnumbers"] = { first = 0x1EC70, last = 0x1ECBF, description = "Indic Siyaq Numbers" },
+ ["indicsiyaqnumbers"] = { first = 0x1EC70, last = 0x1ECBF, description = "Indic Siyaq Numbers" },
["inscriptionalpahlavi"] = { first = 0x10B60, last = 0x10B7F, description = "Inscriptional Pahlavi" },
["inscriptionalparthian"] = { first = 0x10B40, last = 0x10B5F, description = "Inscriptional Parthian" },
["ipaextensions"] = { first = 0x00250, last = 0x002AF, description = "IPA Extensions" },
@@ -402,7 +405,7 @@ local blocks = allocate {
["lydian"] = { first = 0x10920, last = 0x1093F, description = "Lydian" },
["mahajani"] = { first = 0x11150, last = 0x1117F, description = "Mahajani" },
["mahjongtiles"] = { first = 0x1F000, last = 0x1F02F, description = "Mahjong Tiles" },
- ["makasar"] = { first = 0x11EE0, last = 0x11EFF, description = "Makasar" },
+ ["makasar"] = { first = 0x11EE0, last = 0x11EFF, description = "Makasar" },
["malayalam"] = { first = 0x00D00, last = 0x00D7F, otf="mlym", description = "Malayalam" },
["mandaic"] = { first = 0x00840, last = 0x0085F, otf="mand", description = "Mandaic" },
["manichaean"] = { first = 0x10AC0, last = 0x10AFF, description = "Manichaean" },
@@ -410,8 +413,8 @@ local blocks = allocate {
["masaramgondi"] = { first = 0x11D00, last = 0x11D5F, description = "Masaram Gondi" },
["mathematicalalphanumericsymbols"] = { first = 0x1D400, last = 0x1D7FF, math = true, description = "Mathematical Alphanumeric Symbols" },
["mathematicaloperators"] = { first = 0x02200, last = 0x022FF, math = true, description = "Mathematical Operators" },
- ["mayannumerals"] = { first = 0x1D2E0, last = 0x1D2FF, description = "Mayan Numerals" },
- ["medefaidrin"] = { first = 0x16E40, last = 0x16E9F, description = "Medefaidrin" },
+ ["mayannumerals"] = { first = 0x1D2E0, last = 0x1D2FF, description = "Mayan Numerals" },
+ ["medefaidrin"] = { first = 0x16E40, last = 0x16E9F, description = "Medefaidrin" },
["meeteimayek"] = { first = 0x0ABC0, last = 0x0ABFF, description = "Meetei Mayek" },
["meeteimayekextensions"] = { first = 0x0AAE0, last = 0x0AAFF, description = "Meetei Mayek Extensions" },
["mendekikakui"] = { first = 0x1E800, last = 0x1E8DF, description = "Mende Kikakui" },
@@ -435,11 +438,13 @@ local blocks = allocate {
["myanmarextendeda"] = { first = 0x0AA60, last = 0x0AA7F, description = "Myanmar Extended-A" },
["myanmarextendedb"] = { first = 0x0A9E0, last = 0x0A9FF, description = "Myanmar Extended-B" },
["nabataean"] = { first = 0x10880, last = 0x108AF, description = "Nabataean" },
+ ["nandinagari"] = { first = 0x119A0, last = 0x119FF, description = "Nandinagari" },
["newa"] = { first = 0x11400, last = 0x1147F, description = "Newa" },
["newtailue"] = { first = 0x01980, last = 0x019DF, description = "New Tai Lue" },
["nko"] = { first = 0x007C0, last = 0x007FF, otf="nko", description = "NKo" },
["numberforms"] = { first = 0x02150, last = 0x0218F, description = "Number Forms" },
["nushu"] = { first = 0x1B170, last = 0x1B2FF, description = "Nushu" },
+ ["nyiakengpuachuehmong"] = { first = 0x1E100, last = 0x1E14F, description = "Nyiakeng Puachue Hmong" },
["ogham"] = { first = 0x01680, last = 0x0169F, otf="ogam", description = "Ogham" },
["olchiki"] = { first = 0x01C50, last = 0x01C7F, description = "Ol Chiki" },
["oldhungarian"] = { first = 0x10C80, last = 0x10CFF, description = "Old Hungarian" },
@@ -447,7 +452,7 @@ local blocks = allocate {
["oldnortharabian"] = { first = 0x10A80, last = 0x10A9F, description = "Old North Arabian" },
["oldpermic"] = { first = 0x10350, last = 0x1037F, description = "Old Permic" },
["oldpersian"] = { first = 0x103A0, last = 0x103DF, otf="xpeo", description = "Old Persian" },
- ["oldsogdian"] = { first = 0x10F00, last = 0x10F2F, description = "Old Sogdian" },
+ ["oldsogdian"] = { first = 0x10F00, last = 0x10F2F, description = "Old Sogdian" },
["oldsoutharabian"] = { first = 0x10A60, last = 0x10A7F, description = "Old South Arabian" },
["oldturkic"] = { first = 0x10C00, last = 0x10C4F, description = "Old Turkic" },
["opticalcharacterrecognition"] = { first = 0x02440, last = 0x0245F, description = "Optical Character Recognition" },
@@ -455,6 +460,7 @@ local blocks = allocate {
["ornamentaldingbats"] = { first = 0x1F650, last = 0x1F67F, description = "Ornamental Dingbats" },
["osage"] = { first = 0x104B0, last = 0x104FF, description = "Osage" },
["osmanya"] = { first = 0x10480, last = 0x104AF, otf="osma", description = "Osmanya" },
+ ["ottomansiyaqnumbers"] = { first = 0x1ED00, last = 0x1ED4F, description = "Ottoman Siyaq Numbers" },
["pahawhhmong"] = { first = 0x16B00, last = 0x16B8F, description = "Pahawh Hmong" },
["palmyrene"] = { first = 0x10860, last = 0x1087F, description = "Palmyrene" },
["paucinhau"] = { first = 0x11AC0, last = 0x11AFF, description = "Pau Cin Hau" },
@@ -478,7 +484,8 @@ local blocks = allocate {
["sinhala"] = { first = 0x00D80, last = 0x00DFF, otf="sinh", description = "Sinhala" },
["sinhalaarchaicnumbers"] = { first = 0x111E0, last = 0x111FF, description = "Sinhala Archaic Numbers" },
["smallformvariants"] = { first = 0x0FE50, last = 0x0FE6F, description = "Small Form Variants" },
- ["sogdian"] = { first = 0x10F30, last = 0x10F6F, description = "Sogdian" },
+ ["smallkanaextension"] = { first = 0x1B130, last = 0x1B16F, description = "Small Kana Extension" },
+ ["sogdian"] = { first = 0x10F30, last = 0x10F6F, description = "Sogdian" },
["sorasompeng"] = { first = 0x110D0, last = 0x110FF, description = "Sora Sompeng" },
["soyombo"] = { first = 0x11A50, last = 0x11AAF, description = "Soyombo" },
["spacingmodifierletters"] = { first = 0x002B0, last = 0x002FF, description = "Spacing Modifier Letters" },
@@ -496,6 +503,7 @@ local blocks = allocate {
["supplementaryprivateuseareab"] = { first = 0x100000,last = 0x10FFFF, description = "Supplementary Private Use Area-B" },
["suttonsignwriting"] = { first = 0x1D800, last = 0x1DAAF, description = "Sutton SignWriting" },
["sylotinagri"] = { first = 0x0A800, last = 0x0A82F, otf="sylo", description = "Syloti Nagri" },
+ ["symbolsandpictographsextendeda"] = { first = 0x1FA70, last = 0x1FAFF, description = "Symbols and Pictographs Extended-A" },
["syriac"] = { first = 0x00700, last = 0x0074F, otf="syrc", description = "Syriac" },
["syriacsupplement"] = { first = 0x00860, last = 0x0086F, description = "Syriac Supplement" },
["tagalog"] = { first = 0x01700, last = 0x0171F, otf="tglg", description = "Tagalog" },
@@ -507,6 +515,7 @@ local blocks = allocate {
["taixuanjingsymbols"] = { first = 0x1D300, last = 0x1D35F, description = "Tai Xuan Jing Symbols" },
["takri"] = { first = 0x11680, last = 0x116CF, description = "Takri" },
["tamil"] = { first = 0x00B80, last = 0x00BFF, otf="taml", description = "Tamil" },
+ ["tamilsupplement"] = { first = 0x11FC0, last = 0x11FFF, description = "Tamil Supplement" },
["tangut"] = { first = 0x17000, last = 0x187FF, description = "Tangut" },
["tangutcomponents"] = { first = 0x18800, last = 0x18AFF, description = "Tangut Components" },
["telugu"] = { first = 0x00C00, last = 0x00C7F, otf="telu", description = "Telugu" },
@@ -544,6 +553,7 @@ local blocks = allocate {
["variationselectorssupplement"] = { first = 0xE0100, last = 0xE01EF, description = "Variation Selectors Supplement" },
["vedicextensions"] = { first = 0x01CD0, last = 0x01CFF, description = "Vedic Extensions" },
["verticalforms"] = { first = 0x0FE10, last = 0x0FE1F, description = "Vertical Forms" },
+ ["wancho"] = { first = 0x1E2C0, last = 0x1E2FF, description = "Wancho" },
["warangciti"] = { first = 0x118A0, last = 0x118FF, description = "Warang Citi" },
["yijinghexagramsymbols"] = { first = 0x04DC0, last = 0x04DFF, otf="yi", description = "Yijing Hexagram Symbols" },
["yiradicals"] = { first = 0x0A490, last = 0x0A4CF, otf="yi", description = "Yi Radicals" },
@@ -1516,7 +1526,7 @@ do
)^1)
local function load()
- local name = resolvers.find_file("char-emj.lua")
+ local name = resolvers.findfile("char-emj.lua")
local data = name and name ~= "" and dofile(name) or { }
local hash = { }
for d, c in next, data do
diff --git a/Master/texmf-dist/tex/context/base/mkiv/char-tex.lua b/Master/texmf-dist/tex/context/base/mkiv/char-tex.lua
index bbaf11875d0..b361a9a0776 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/char-tex.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/char-tex.lua
@@ -692,7 +692,6 @@ if not csletters then
else
mark(csletters)
-
end
lpegpatterns.csletter = utfchartabletopattern(csletters)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/chem-str.lua b/Master/texmf-dist/tex/context/base/mkiv/chem-str.lua
index 9f0738fc516..1316769cac5 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/chem-str.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/chem-str.lua
@@ -69,7 +69,8 @@ local chemistry = chemistry
chemistry.instance = "chemistry"
chemistry.format = "metafun"
chemistry.method = "double"
-chemistry.structures = 0
+
+local nofstructures = 0
local common_keys = {
b = "line",
@@ -739,7 +740,7 @@ function chemistry.start(settings)
return
end
--
- chemistry.structures = chemistry.structures + 1
+ nofstructures = nofstructures + 1
--
rotation = tonumber(rotation) or 0
--
@@ -749,7 +750,7 @@ function chemistry.start(settings)
report_chemistry("%s scale %a, rotation %a, width %s, height %s, left %s, right %s, top %s, bottom %s","used",scale,rotation,width,height,left,right,top,bottom)
end
metacode[#metacode+1] = f_start_structure(
- chemistry.structures,
+ nofstructures,
left, right, top, bottom,
rotation, topoints(unit), bondlength, scale, topoints(offset),
tostring(settings.axis == v_on), topoints(rulethickness), axiscolor
@@ -788,8 +789,8 @@ function chemistry.component(spec,text,rulethickness,rulecolor)
end
statistics.register("chemical formulas", function()
- if chemistry.structures > 0 then
- return format("%s chemical structure formulas",chemistry.structures) -- no timing needed, part of metapost
+ if nofstructures > 0 then
+ return format("%s chemical structure formulas",nofstructures) -- no timing needed, part of metapost
end
end)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/cldf-bas.lua b/Master/texmf-dist/tex/context/base/mkiv/cldf-bas.lua
index f55132a0612..9e789a72fe8 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/cldf-bas.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/cldf-bas.lua
@@ -193,34 +193,12 @@ context.registers = {
newchar = function(name,u) context([[\chardef\%s=%s\relax]],name,u) end,
}
-do
-
- if CONTEXTLMTXMODE > 1 then
-
- function context.latelua(f)
- -- table check moved elsewhere
- local latelua = new_latelua(f)
- setattrlist(latelua,true) -- will become an option
- ctx_flushnode(latelua,true)
- end
-
- else
-
- function context.latelua(f)
- if type(f) == "table" then
- local action = f.action
- local specification = f.specification or f
- f = function() action(specification) end
- end
- local latelua = new_latelua(f)
- setattrlist(latelua,true) -- will become an option
- ctx_flushnode(latelua,true)
- end
-
- end
-
+function context.latelua(f)
+ -- table check moved elsewhere
+ local latelua = new_latelua(f)
+ setattrlist(latelua,true) -- will become an option
+ ctx_flushnode(latelua,true)
end
--- yes or no
do
diff --git a/Master/texmf-dist/tex/context/base/mkiv/cldf-ini.lua b/Master/texmf-dist/tex/context/base/mkiv/cldf-ini.lua
index 15ebc9d9595..e22de5a5b80 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/cldf-ini.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/cldf-ini.lua
@@ -124,8 +124,8 @@ local scannerdefmode = true
local maxflushnodeindex = 0x10FFFF - 1
-- tokenflushmode = false
--- scannerdefmode = false
-- nodeflushmode = false
+-- scannerdefmode = false
-- In earlier experiments a function tables was referred to as lua.calls and the
-- primitive \luafunctions was \luacall and we used our own implementation of
@@ -137,7 +137,7 @@ function context.trialtypesetting()
return texgetcount(trialtypesettingstate) ~= 0
end
-local knownfunctions = lua.get_functions_table(true)
+local knownfunctions = (lua.getfunctionstable or lua.get_functions_table)(true)
local showstackusage = false
trackers.register("context.stack",function(v) showstackusage = v end)
@@ -326,6 +326,39 @@ end
setmetatablecall(knownfunctions,function(t,n) return knownfunctions[n](n) end)
+-- some protection
+
+do
+
+ local stub = { }
+ local done = false
+ local message = function()
+ -- one time message
+ if not done then
+ report_cld("")
+ report_cld("use : slot = context.functions.register(f)")
+ report_cld("and : context.functions.unregister(slot)")
+ report_cld("")
+ done = true
+ end
+ end
+
+ setmetatable(stub, {
+ __index = message,
+ __newindex = message,
+ })
+
+ function lua.getfunctionstable()
+ message()
+ return stub
+ end
+
+ lua.get_functions_table = lua.getfunctionstable
+
+end
+
+-- so far
+
-- The next hack is a convenient way to define scanners at the Lua end and
-- get them available at the TeX end. There is some dirty magic needed to
-- prevent overload during format loading.
@@ -713,9 +746,15 @@ local s_cldl_argument_e = "}"
-- local s_cldl_argument_b = "{"
-- local s_cldl_argument_f = "{ "
-local t_cldl_luafunction = createtoken("luafunctioncall")
+local t_cldl_luafunction = newtoken("luafunctioncall",0)
local lua_expandable_call_token_code = token.command_id and token.command_id("lua_expandable_call")
+local sortedhashindeed = false
+
+directives.register("context.sorthash",function(v)
+ sortedhashindeed = v and table.sortedhash or nil
+end)
+
local function writer(parent,command,...) -- already optimized before call
if type(command) == "string" then -- for now
@@ -766,20 +805,39 @@ local function writer(parent,command,...) -- already optimized before call
local tn = #ti
if tn == 0 then
local done = false
- for k, v in next, ti do
- if done then
- if v == "" then
- flush(currentcatcodes,",",k,'=')
+ if sortedhashindeed then
+ for k, v in sortedhashindeed(ti) do
+ if done then
+ if v == "" then
+ flush(currentcatcodes,",",k,'=')
+ else
+ flush(currentcatcodes,",",k,"={",v,"}")
+ end
else
- flush(currentcatcodes,",",k,"={",v,"}")
+ if v == "" then
+ flush(currentcatcodes,"[",k,"=")
+ else
+ flush(currentcatcodes,"[",k,"={",v,"}")
+ end
+ done = true
end
- else
- if v == "" then
- flush(currentcatcodes,"[",k,"=")
+ end
+ else
+ for k, v in next, ti do
+ if done then
+ if v == "" then
+ flush(currentcatcodes,",",k,'=')
+ else
+ flush(currentcatcodes,",",k,"={",v,"}")
+ end
else
- flush(currentcatcodes,"[",k,"={",v,"}")
+ if v == "" then
+ flush(currentcatcodes,"[",k,"=")
+ else
+ flush(currentcatcodes,"[",k,"={",v,"}")
+ end
+ done = true
end
- done = true
end
end
if done then
@@ -792,11 +850,11 @@ local function writer(parent,command,...) -- already optimized before call
if type(tj) == "function" then
tj = storefunction(tj)
if tokenflushmode then
- if newtoken then
+ -- if newtoken then
flush(currentcatcodes,"[",newtoken(tj,lua_expandable_call_token_code),"]")
- else
- flush(currentcatcodes,"[",t_cldl_luafunction,tj,"]")
- end
+ -- else
+ -- flush(currentcatcodes,"[",t_cldl_luafunction,tj,"]")
+ -- end
else
flush(currentcatcodes,s_cldl_option_b,tj,s_cldl_option_e)
end
@@ -810,11 +868,11 @@ local function writer(parent,command,...) -- already optimized before call
if type(tj) == "function" then
tj = storefunction(tj)
if tokenflushmode then
- if newtoken then
+ -- if newtoken then
flush(currentcatcodes,"[",newtoken(tj,lua_expandable_call_token_code),j == tn and "]" or ",")
- else
- flush(currentcatcodes,"[",t_cldl_luafunction,tj,j == tn and "]" or ",")
- end
+ -- else
+ -- flush(currentcatcodes,"[",t_cldl_luafunction,tj,j == tn and "]" or ",")
+ -- end
else
flush(currentcatcodes,s_cldl_option_s,tj,j == tn and "]" or ",")
end
@@ -831,11 +889,11 @@ local function writer(parent,command,...) -- already optimized before call
-- todo: ctx|prt|texcatcodes
ti = storefunction(ti)
if tokenflushmode then
- if newtoken then
+ -- if newtoken then
flush(currentcatcodes,"{",newtoken(ti,lua_expandable_call_token_code),"}")
- else
- flush(currentcatcodes,"{",t_cldl_luafunction,ti,"}")
- end
+ -- else
+ -- flush(currentcatcodes,"{",t_cldl_luafunction,ti,"}")
+ -- end
else
flush(currentcatcodes,s_cldl_argument_f,ti,s_cldl_argument_e)
end
@@ -1060,11 +1118,11 @@ local caller = function(parent,f,a,...)
-- ignored: a ...
f = storefunction(f)
if tokenflushmode then
- if newtoken then
+ -- if newtoken then
flush(currentcatcodes,"{",newtoken(f,lua_expandable_call_token_code),"}")
- else
- flush(currentcatcodes,"{",t_cldl_luafunction,f,"}")
- end
+ -- else
+ -- flush(currentcatcodes,"{",t_cldl_luafunction,f,"}")
+ -- end
else
flush(currentcatcodes,s_cldl_argument_b,f,s_cldl_argument_e) -- todo: ctx|prt|texcatcodes
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/cldf-int.lua b/Master/texmf-dist/tex/context/base/mkiv/cldf-int.lua
index 52cfea8d0ae..86420f422b1 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/cldf-int.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/cldf-int.lua
@@ -11,8 +11,9 @@ if not modules then modules = { } end modules ['cldf-int'] = {
-- needs checking
-- todo: multilingual
-local format, insert, remove, concat = string.format, table.insert, table.remove, table.concat
-local unpack = unpack or table.unpack
+local format, byte = string.format, string.byte
+local insert, remove, concat = table.insert, table.remove, table.concat
+local unpack, type = unpack or table.unpack, type
local catcodenumbers = catcodes.numbers
@@ -24,140 +25,291 @@ local contextsprint = context.sprint
local trace_define = false trackers.register("context.define", function(v) trace_define = v end)
-interfaces = interfaces or { }
+interfaces = interfaces or { }
+local implement = interfaces.implement
+local estart = interfaces.elements.start
+local estop = interfaces.elements.stop
-_clmh_ = utilities.parsers.settings_to_hash
-_clma_ = utilities.parsers.settings_to_array
+if CONTEXTLMTXMODE > 0 then
-local starters, stoppers, macros, stack = { }, { }, { }, { }
+ local scanners = tokens.scanners
+ local shortcuts = tokens.shortcuts
-local checkers = {
- [0] = "",
- "\\dosingleempty",
- "\\dodoubleempty",
- "\\dotripleempty",
- "\\doquadrupleempty",
- "\\doquintupleempty",
- "\\dosixtupleempty",
-}
+ local scanpeek = scanners.peek
+ local scankey = scanners.key
+ local scanvalue = scanners.value
+ local scanskip = scanners.skip
-function _clmm_(name,...)
- macros[name](...)
-end
+ local open = byte('[')
+ local close = byte(']')
+ local equal = byte('=')
+ local comma = byte(',')
-function _clmb_(name,...)
- local sn = stack[name]
- insert(sn,{...})
- starters[name](...)
-end
-
-function _clme_(name)
- local sn = stack[name]
- local sv = remove(sn)
- if sv then
- stoppers[name](unpack(sv))
- else
- -- nesting error
+ function scanhash(scanners)
+ if scanpeek() == open then
+ local data = { }
+ scanskip()
+ while true do
+ local c = scanpeek()
+ if c == comma then
+ scanskip()
+ elseif c == close then
+ scanskip()
+ break
+ else
+ local key = scankey(equal)
+ if key then
+ if scanpeek() == equal then
+ scanskip()
+ if scanners then
+ local scanner = scanners[key]
+ if scanner then
+ data[key] = scanner()
+ else
+ data[key] = scanvalue(comma,close) or ""
+ end
+ else
+ data[key] = scanvalue(comma,close) or ""
+ end
+ else
+ break
+ end
+ else
+ break
+ end
+ end
+ end
+ return data
+ end
end
-end
-_clmn_ = tonumber
+ function scanarray()
+ if scanpeek() == open then
+ local data = { }
+ local d = 0
+ scanskip()
+ while true do
+ local c = scanpeek()
+ if c == comma then
+ scanskip()
+ elseif c == close then
+ scanskip()
+ break
+ else
+ local v = scanvalue(comma,close) or ""
+ d = d + 1
+ data[d] = v
+ end
+ end
+ return data
+ end
+ end
-local estart = interfaces.elements.start
-local estop = interfaces.elements.stop
+ shortcuts.scanhash = scanhash
+ shortcuts.scanarray = scanarray
--- this is a bit old definition ... needs to be modernized
+ scanners.hash = scanhash
+ scanners.array = scanarray
-function interfaces.definecommand(name,specification) -- name is optional
- if type(name) == "table" then
- specification = name
- name = specification.name
+ local function remap(arguments)
+ -- backward compatibility
+ if type(arguments) == "table" then
+ for i=1,#arguments do
+ local a = arguments[i]
+ if type(a) == "table" then
+ local t = a[2]
+ arguments[i] = t == "list" and "array" or t
+ end
+ end
+ return arguments
+ end
end
- if name and specification then
- local arguments = specification.arguments
- local na = (arguments and #arguments) or 0
- local environment = specification.environment
- if na == 0 then
+
+ function interfaces.definecommand(name,specification) -- name is optional
+ if type(name) == "table" then
+ specification = name
+ name = specification.name
+ end
+ if name and specification then
+ local environment = specification.environment
+ local arguments = remap(specification.arguments)
if environment then
- contextsprint(ctxcatcodes,"\\setuvalue{",estart,name,"}{\\ctxlua{_clmb_('",name,"')}}")
- contextsprint(ctxcatcodes,"\\setuvalue{",estop, name,"}{\\ctxlua{_clme_('",name,"')}}")
+ local starter = specification.starter
+ local stopper = specification.stopper
+ if starter and stopper then
+ implement {
+ name = estart .. name,
+ arguments = arguments,
+ public = true,
+ protected = true,
+ actions = starter,
+ }
+ implement {
+ name = estop .. name,
+ public = true,
+ protected = true,
+ actions = stopper,
+ }
+ else
+ -- message
+ end
end
if not environment or environment == "both" then
- contextsprint(ctxcatcodes,"\\setuvalue{", name,"}{\\ctxlua{_clmm_('",name,"')}}")
- end
- else
- -- we could flush immediate but tracing is bad then
- stack[name] = { }
- local opt = 0
- local done = false
- local snippets = { } -- we can reuse it
- local mkivdo = "\\mkivdo" .. name -- maybe clddo
- snippets[#snippets+1] = "\\def"
- snippets[#snippets+1] = mkivdo
- for i=1,na do
- local a = arguments[i]
- local variant = a[1]
- if variant == "option" then
- snippets[#snippets+1] = "[#"
- snippets[#snippets+1] = i
- snippets[#snippets+1] = "]"
- if not done then
- opt = opt + 1
- end
+ local macro = specification.macro
+ if macro then
+ implement {
+ name = name,
+ arguments = arguments,
+ public = true,
+ protected = true,
+ actions = macro,
+ }
else
- done = true -- no more optional checking after this
- snippets[#snippets+1] = "#"
- snippets[#snippets+1] = i
+ -- message
end
end
- if environment then
- snippets[#snippets+1] = "{\\ctxlua{_clmb_('"
- snippets[#snippets+1] = name
- snippets[#snippets+1] = "'"
+ else
+ -- message
+ end
+ end
+
+
+else
+
+ _clmh_ = utilities.parsers.settings_to_hash
+ _clma_ = utilities.parsers.settings_to_array
+
+ local starters, stoppers, macros, stack = { }, { }, { }, { }
+
+ local checkers = {
+ [0] = "",
+ "\\dosingleempty",
+ "\\dodoubleempty",
+ "\\dotripleempty",
+ "\\doquadrupleempty",
+ "\\doquintupleempty",
+ "\\dosixtupleempty",
+ }
+
+ function _clmm_(name,...)
+ macros[name](...)
+ end
+
+ function _clmb_(name,...)
+ local sn = stack[name]
+ insert(sn,{...})
+ starters[name](...)
+ end
+
+ function _clme_(name)
+ local sn = stack[name]
+ local sv = remove(sn)
+ if sv then
+ stoppers[name](unpack(sv))
+ else
+ -- nesting error
+ end
+ end
+
+ _clmn_ = tonumber
+
+ local estart = interfaces.elements.start
+ local estop = interfaces.elements.stop
+
+ -- this is a bit old definition ... needs to be modernized
+
+ function interfaces.definecommand(name,specification) -- name is optional
+ if type(name) == "table" then
+ specification = name
+ name = specification.name
+ end
+ if name and specification then
+ local arguments = specification.arguments
+ local na = (arguments and #arguments) or 0
+ local environment = specification.environment
+ if na == 0 then
+ if environment then
+ contextsprint(ctxcatcodes,"\\setuvalue{",estart,name,"}{\\ctxlua{_clmb_('",name,"')}}")
+ contextsprint(ctxcatcodes,"\\setuvalue{",estop, name,"}{\\ctxlua{_clme_('",name,"')}}")
+ end
+ if not environment or environment == "both" then
+ contextsprint(ctxcatcodes,"\\setuvalue{", name,"}{\\ctxlua{_clmm_('",name,"')}}")
+ end
else
- snippets[#snippets+1] = "{\\ctxlua{_clmm_('"
- snippets[#snippets+1] = name
- snippets[#snippets+1] = "'"
- end
- for i=1,na do
- local a = arguments[i]
- local variant = a[2]
- if variant == "list" then
- snippets[#snippets+1] = ",_clma_([[#"
- snippets[#snippets+1] = i
- snippets[#snippets+1] = "]])"
- elseif variant == "hash" then
- snippets[#snippets+1] = ",_clmh_([[#"
- snippets[#snippets+1] = i
- snippets[#snippets+1] = "]])"
- elseif variant == "number" then
- snippets[#snippets+1] = ",_clmn_([[#"
- snippets[#snippets+1] = i
- snippets[#snippets+1] = "]])"
+ -- we could flush immediate but tracing is bad then
+ stack[name] = { }
+ local opt = 0
+ local done = false
+ local snippets = { } -- we can reuse it
+ local mkivdo = "\\mkivdo" .. name -- maybe clddo
+ snippets[#snippets+1] = "\\def"
+ snippets[#snippets+1] = mkivdo
+ for i=1,na do
+ local a = arguments[i]
+ local variant = a[1]
+ if variant == "option" then
+ snippets[#snippets+1] = "[#"
+ snippets[#snippets+1] = i
+ snippets[#snippets+1] = "]"
+ if not done then
+ opt = opt + 1
+ end
+ else
+ done = true -- no more optional checking after this
+ snippets[#snippets+1] = "#"
+ snippets[#snippets+1] = i
+ end
+ end
+ if environment then
+ snippets[#snippets+1] = "{\\ctxlua{_clmb_('"
+ snippets[#snippets+1] = name
+ snippets[#snippets+1] = "'"
else
- snippets[#snippets+1] = ",[[#"
- snippets[#snippets+1] = i
- snippets[#snippets+1] = "]]"
+ snippets[#snippets+1] = "{\\ctxlua{_clmm_('"
+ snippets[#snippets+1] = name
+ snippets[#snippets+1] = "'"
+ end
+ for i=1,na do
+ local a = arguments[i]
+ local variant = a[2]
+ if variant == "list" then
+ snippets[#snippets+1] = ",_clma_([==[#"
+ snippets[#snippets+1] = i
+ snippets[#snippets+1] = "]==])"
+ elseif variant == "hash" then
+ snippets[#snippets+1] = ",_clmh_([==[#"
+ snippets[#snippets+1] = i
+ snippets[#snippets+1] = "]==])"
+ elseif variant == "number" then
+ snippets[#snippets+1] = ",_clmn_([==[#"
+ snippets[#snippets+1] = i
+ snippets[#snippets+1] = "]==])"
+ else
+ snippets[#snippets+1] = ",[==[#"
+ snippets[#snippets+1] = i
+ snippets[#snippets+1] = "]==]"
+ end
+ end
+ snippets[#snippets+1] = ")}}"
+ contextsprint(ctxcatcodes,unpack(snippets))
+ if environment then
+ -- needs checking
+ contextsprint(ctxcatcodes,"\\setuvalue{",estart,name,"}{",checkers[opt],mkivdo,"}")
+ contextsprint(ctxcatcodes,"\\setuvalue{",estop, name,"}{\\ctxlua{_clme_('",name,"')}}")
+ end
+ if not environment or environment == "both" then
+ contextsprint(ctxcatcodes,"\\setuvalue{", name,"}{",checkers[opt],mkivdo,"}")
end
end
- snippets[#snippets+1] = ")}}"
- contextsprint(ctxcatcodes,unpack(snippets))
if environment then
- -- needs checking
- contextsprint(ctxcatcodes,"\\setuvalue{",estart,name,"}{",checkers[opt],mkivdo,"}")
- contextsprint(ctxcatcodes,"\\setuvalue{",estop, name,"}{\\ctxlua{_clme_('",name,"')}}")
- end
- if not environment or environment == "both" then
- contextsprint(ctxcatcodes,"\\setuvalue{", name,"}{",checkers[opt],mkivdo,"}")
+ starters[name] = specification.starter
+ stoppers[name] = specification.stopper
+ else
+ macros[name] = specification.macro
end
end
- if environment then
- starters[name] = specification.starter
- stoppers[name] = specification.stopper
- else
- macros[name] = specification.macro
- end
end
+
end
function interfaces.tolist(t)
@@ -223,3 +375,20 @@ end
-- \stopluacode
--
-- more: \startmore[1] one \startmore[2] two \stopmore one \stopmore
+--
+-- More modern (no need for option or content):
+--
+-- \startluacode
+-- interfaces.definecommand {
+-- name = "test",
+-- arguments = {
+-- "array", -- or list
+-- "hash",
+-- "string",
+-- "number",
+-- },
+-- macro = test,
+-- }
+-- \stopluacode
+--
+
diff --git a/Master/texmf-dist/tex/context/base/mkiv/colo-ini.lua b/Master/texmf-dist/tex/context/base/mkiv/colo-ini.lua
index 3c8d23abc09..6b3f515b90e 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/colo-ini.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/colo-ini.lua
@@ -109,6 +109,8 @@ colors.pushset = pushset
colors.popset = popset
colors.setlist = setlist
+-- todo: set at the lua end
+
local ctx_colordefagc = context.colordefagc
local ctx_colordefagt = context.colordefagt
local ctx_colordefalc = context.colordefalc
@@ -508,6 +510,59 @@ local function defineprocesscolor(name,str,global,freeze) -- still inconsistent
colorset[name] = true-- maybe we can store more
end
+-- You cannot overload a local color so one then has to use some prefix, like
+-- mp:red. Kind of protection.
+
+local function defineprocesscolordirect(settings)
+ if settings then
+ local name = settings.name
+ if name then
+ local r = settings.r
+ local g = settings.g
+ local b = settings.b
+ if r or g or b then
+ -- we can consider a combined rgb cmyk s definition
+ register_color(name,'rgb', r or 0, g or 0, b or 0)
+ else
+ local c = settings.c
+ local m = settings.m
+ local y = settings.y
+ local k = settings.k
+ if c or m or y or k then
+ register_color(name,'cmyk',c or 0, m or 0, y or 0, k or 0)
+ else
+ local h = settings.h
+ local s = settings.s
+ local v = settings.v
+ if v then
+ r, g, b = colors.hsvtorgb(h or 0, s or 1, v or 1) -- maybe later native
+ register_color(name,'rgb',r,g,b)
+ else
+ local x = settings.x or h
+ if x then
+ r, g, b = lpegmatch(hexpattern,x) -- can be inlined
+ if r and g and b then
+ register_color(name,'rgb',r,g,b)
+ else
+ register_color(name,'gray',r or 0)
+ end
+ else
+ register_color(name,'gray',s or 0)
+ end
+ end
+ end
+ end
+ local a = settings.a
+ local t = settings.t
+ if a and t then
+ transparencies.register(name,transparent[a] or a or 1,t or 1)
+ end
+ colorset[name] = true-- maybe we can store more
+ valid[name] = true
+ end
+ end
+end
+
local function isblack(ca) -- maybe commands
local cv = ca > 0 and colorvalues[ca]
return (cv and cv[2] == 0) or false
@@ -519,7 +574,6 @@ colors.isblack = isblack
-- if c and c > 1 then -- 1 is black
-- local v = attributes.colors.values[c]
-
local function definespotcolor(name,parent,str,global)
if parent == "" or find(parent,"=",1,true) then
colors.registerspotcolor(name, parent) -- does that work? no attr
@@ -657,6 +711,8 @@ colors.defineprocesscolor = defineprocesscolor
colors.definespotcolor = definespotcolor
colors.definemultitonecolor = definemultitonecolor
+colors.defineprocesscolordirect = defineprocesscolordirect -- test for mp
+
-- will move to mlib-col as colors in mp are somewhat messy due to the fact
-- that we cannot cast .. so we really need to use (s,s,s) for gray in order
-- to be able to map onto 'color'
@@ -734,10 +790,13 @@ local function namedcolorattributes(name)
elseif color == true then
color = paletnamespace .. prefix .. name
end
- elseif valid[name] then
- color = name
else
- return space, l_color.black
+ color = valid[name]
+ if not color then
+ return space, l_color.black
+ elseif color == true then
+ color = name
+ end
end
color = counts[color]
if color then
@@ -773,7 +832,6 @@ colors.mpoptions = mpoptions
-- mpprint(mpnamedcolor(str))
-- end
-
-- local function formatcolor(ca,separator)
-- local cv = colorvalues[ca]
-- if cv then
@@ -953,6 +1011,12 @@ local function complement(one,fraction,i)
return otf
end
+colors.helpers = {
+ inbetween = inbetween,
+ justone = justone,
+ complement = complement,
+}
+
defineintermediatecolor = function(name,fraction,c_one,c_two,a_one,a_two,specs,global,freeze)
fraction = tonumber(fraction) or 1
local one, two = colorvalues[c_one], colorvalues[c_two] -- beware, it uses the globals
@@ -1014,6 +1078,7 @@ colors.defineintermediatecolor = defineintermediatecolor
-- for the moment downward compatible
local patterns = {
+ CONTEXTLMTXMODE > 0 and "colo-imp-%s.mkxl" or "",
"colo-imp-%s.mkiv",
"colo-imp-%s.tex",
-- obsolete:
@@ -1022,13 +1087,7 @@ local patterns = {
}
local function action(name,foundname)
- -- could be one command
- context.startreadingfile()
- context.startcolorset { name }
- context.input(foundname)
- context.showmessage("colors",4,name)
- context.stopcolorset()
- context.stopreadingfile()
+ context.loadfoundcolorsetfile(name,foundname)
end
local function failure(name)
@@ -1037,7 +1096,7 @@ local function failure(name)
end
local function usecolors(name)
- commands.uselibrary {
+ resolvers.uselibrary {
category = "color definition",
name = name,
patterns = patterns,
diff --git a/Master/texmf-dist/tex/context/base/mkiv/colo-ini.mkiv b/Master/texmf-dist/tex/context/base/mkiv/colo-ini.mkiv
index 7079322f7a2..c489635deca 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/colo-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/colo-ini.mkiv
@@ -37,16 +37,15 @@
\unprotect
-%D In \MKIV\ we have independent color, colorspace and transparency
-%D but I'm still not sure if I keep it that way as it's probably more
-%D efficient to combine them (less attributes and finalizing). If
-%D it becomes a bottleneck we can set up a more complex system
-%D with one shared attribute for colorspace, color and transparency.
+%D In \MKIV\ we have independent color, colorspace and transparency but I'm still
+%D not sure if I keep it that way as it's probably more efficient to combine them
+%D (less attributes and finalizing). If it becomes a bottleneck we can set up a more
+%D complex system with one shared attribute for colorspace, color and transparency.
%D
-%D When typesetting for paper, we prefer using the \CMYK\ color space,
-%D but for on||screen viewing we prefer \RGB\ (the previous
-%D implementation supported only this scheme). Independant of such
-%D specifications, we support some automatic conversions:
+%D When typesetting for paper, we prefer using the \CMYK\ color space, but for
+%D on||screen viewing we prefer \RGB\ (the previous implementation supported only
+%D this scheme). Independant of such specifications, we support some automatic
+%D conversions:
%D
%D \startitemize[packed]
%D \item convert all colors to \RGB
@@ -108,11 +107,18 @@
\unexpanded\def\definetransparency {\dodoubleargument\colo_basics_define_transpancy}
\unexpanded\def\defineglobaltransparency{\dodoubleargument\colo_basics_define_transpancy_global}
+\unexpanded\def\loadfoundcolorsetfile#1#2% name foundname / not a user command
+ {\startreadingfile
+ \startcolorset[#1]%
+ \input{#2}%
+ \stopcolorset
+ \showmessage\m!colors4{#1}%
+ \stopreadingfile}
+
%D \macros
%D {startcolor,stopcolor,color,graycolor}
%D
-%D The local and global commands are here just for compatibility
-%D with \MKII.
+%D The local and global commands are here just for compatibility with \MKII.
%D
%D \showsetup{startcolor}
%D
@@ -131,42 +137,6 @@
\unexpanded\def\switchtocolor[#1]{\begincsname#1\endcsname}
-% \unexpanded\def\color [#1]{\bgroup
-% \def\g_color{\colo_helpers_activate{#1}}%
-% \afterassignment\g_color
-% \let\nexttoken}
-%
-% \unexpanded\def\graycolor [#1]{\bgroup
-% \def\g_color{\colo_helpers_set_model\s!gray\colo_helpers_activate{#1}}%
-% \afterassignment\g_color
-% \let\nexttoken}
-%
-% \unexpanded\def\startcolor [#1]{\begingroup
-% \colo_helpers_activate{#1}}
-%
-% \unexpanded\def\stopcolor {\endgroup}
-%
-% \unexpanded\def\colored [#1]{\bgroup
-% \def\g_color{\colo_basics_defined_and_activated{#1}}%
-% \afterassignment\g_color
-% \let\nexttoken}
-%
-% \unexpanded\def\fastcolored[#1]#2{\begingroup % is this command still needed?
-% \colo_basics_defined_and_activated{#1}%
-% #2%
-% \endgroup}
-%
-% \unexpanded\def\directcolored[#1]{\colo_basics_defined_and_activated{#1}}
-%
-% \unexpanded\def\fastcolor [#1]#2{\begingroup % is this command still needed?
-% \colo_helpers_activate{#1}%
-% #2%
-% \endgroup}
-%
-% \unexpanded\def\directcolor [#1]{\colo_helpers_activate{#1}}
-%
-% \afterassignment was a left-over artifact
-
% transparency
\unexpanded\def\transparent[#1]%
@@ -259,7 +229,7 @@
\unexpanded\def\directcolored[#1]%
{\colo_basics_defined_and_activated{#1}}
-\unexpanded\def\fastcolor [#1]#2%
+\unexpanded\def\fastcolor[#1]#2%
{\begingroup % is this command still needed?
\edef\currentcolorname{#1}%
\ifx\currentcolorprefix\empty
@@ -310,11 +280,11 @@
%D
%D \showsetup{usecolors}
%D
-%D Some default colors are specified in \type {colo-imp-rgb},
-%D which is loaded into the format by default.
+%D Some default colors are specified in \type {colo-imp-rgb}, which is loaded into
+%D the format by default.
%D
-%D Some demo palets and groups are defined in \type {colo-imp-dem}
-%D which can be loaded with:
+%D Some demo palets and groups are defined in \type {colo-imp-dem} which can be
+%D loaded with:
%D
%D \starttyping
%D \usecolors[dem]
@@ -407,33 +377,27 @@
{\attribute\colorattribute \c_colo_saved_attribute_color
\attribute\transparencyattribute\c_colo_saved_attribute_transparency}
-%D In this documentation we will not go into too much details
-%D on palets. Curious users can find more information on this
-%D topic in \from[use of color].
+%D In this documentation we will not go into too much details on palets. Curious
+%D users can find more information on this topic in \from[use of color].
%D
-%D At the moment we implemented color in \CONTEXT\ color
-%D printing was not yet on the desktop. In spite of this lack our
-%D graphics designer made colorfull illustrations. When printed
-%D on a black and white printer, distinctive colors can come
-%D out equally gray. We therefore decided to use only colors
-%D that were distinctive in colors as well as in black and
-%D white print.
+%D At the moment we implemented color in \CONTEXT\ color printing was not yet on the
+%D desktop. In spite of this lack our graphics designer made colorfull
+%D illustrations. When printed on a black and white printer, distinctive colors can
+%D come out equally gray. We therefore decided to use only colors that were
+%D distinctive in colors as well as in black and white print.
%D
-%D Although none of the graphic packages we used supported
-%D logical colors and global color redefition, we build this
-%D support into \CONTEXT. This enabled us to experiment and
-%D also prepared us for the future.
+%D Although none of the graphic packages we used supported logical colors and global
+%D color redefition, we build this support into \CONTEXT. This enabled us to
+%D experiment and also prepared us for the future.
%D \macros
%D {definepalet}
%D
-%D Colors are grouped in palets. The colors in such a palet can
-%D have colorful names, but best is to use names that specify
-%D their use, like {\em important} or {\em danger}. As a sort
-%D of example \CONTEXT\ has some palets predefined,
-%D like:\footnote{At the time I wrote the palet support, I was
-%D reading 'A hort history of time' of S.~Hawkins, so that's
-%D why we stuck to quarks.}
+%D Colors are grouped in palets. The colors in such a palet can have colorful names,
+%D but best is to use names that specify their use, like {\em important} or {\em
+%D danger}. As a sort of example \CONTEXT\ has some palets predefined,
+%D like:\footnote{At the time I wrote the palet support, I was reading 'A hort
+%D history of time' of S.~Hawkins, so that's why we stuck to quarks.}
%D
%D \starttyping
%D \definepalet
@@ -460,8 +424,8 @@
%D \getbuffer[palet]
%D \stoplinecorrection
%D
-%D This bar shows both the color and gray alternatives of the
-%D palet components (not visible in black and white print).
+%D This bar shows both the color and gray alternatives of the palet components (not
+%D visible in black and white print).
%D
%D When needed, one can copy a palet by saying:
%D
@@ -469,8 +433,8 @@
%D \definepalet [TEXcolorpretty] [colorpretty]
%D \stoptyping
%D
-%D This saves us some typing in for instance the modules that
-%D deal with pretty verbatim typesetting.
+%D This saves us some typing in for instance the modules that deal with pretty
+%D verbatim typesetting.
\installcorenamespace{paletlist}
\installcorenamespace{paletsize}
@@ -485,7 +449,7 @@
\def\colo_palet_prepare#1%
{\edef\colo_palet_name{#1}%
\ifcsname\??paletlist\colo_palet_name\endcsname
- \csname\??paletsize#1\endcsname\zerocount
+ \csname\??paletsize\colo_palet_name\endcsname\zerocount
\else
\colo_palet_allocate\colo_palet_name
\fi
@@ -527,14 +491,25 @@
\expandafter\colo_palets_define_a
\fi}
+% \unexpanded\def\colo_palets_define_a[#1][#2][#3]%
+% {\colo_palet_prepare{#1}%
+% \doifelseassignment{#2}
+% {\setevalue{\??colorpaletspecification#1}{#2}%
+% \processcommalist[#2]{\colo_palets_define_one{#1}}}
+% {\ifcsname\??colorpaletspecification#2\endcsname
+% \normalexpanded{\colo_palets_define[#1][\lastnamedcs]}%
+% \fi}}
+
\unexpanded\def\colo_palets_define_a[#1][#2][#3]%
{\colo_palet_prepare{#1}%
- \doifelseassignment{#2}
- {\setevalue{\??colorpaletspecification#1}{#2}%
- \processcommalist[#2]{\colo_palets_define_one{#1}}}
- {\ifcsname\??colorpaletspecification#2\endcsname
- \normalexpanded{\colo_palets_define[#1][\lastnamedcs]}%
- \fi}}
+ \ifcondition\validassignment{#2}%
+ \setevalue{\??colorpaletspecification#1}{#2}%
+ \processcommalist[#2]{\colo_palets_define_one{#1}}%
+ \else
+ \ifcsname\??colorpaletspecification#2\endcsname
+ \normalexpanded{\colo_palets_define[#1][\lastnamedcs]}%
+ \fi
+ \fi}
\unexpanded\def\colo_palets_define_b[#1][#2][#3]%
{\colo_palet_prepare{#1}%
@@ -542,10 +517,17 @@
\colo_palet_extend{#2}%
\colo_palets_define_assign{#1}{#2}{#3}}
+% \def\colo_palets_define_one#1#2% get rid of { }
+% {\doifelseassignment{#2} % catch empty entries
+% {\colo_palets_define_two{#1}[#2]}
+% {\colo_palets_define_three{#1}{#2}}}
+
\def\colo_palets_define_one#1#2% get rid of { }
- {\doifelseassignment{#2} % catch empty entries
- {\colo_palets_define_two{#1}[#2]}
- {\colo_palets_define_three{#1}{#2}}}
+ {\ifcondition\validassignment{#2}% catch empty entries
+ \colo_palets_define_two{#1}[#2]%
+ \else
+ \colo_palets_define_three{#1}{#2}%
+ \fi}
\def\colo_palets_define_two#1[#2=#3]%
{\colo_palet_extend{#2}%
@@ -556,8 +538,7 @@
\processcommacommand[\lastnamedcs]{\colo_palets_define_one{#1}}%
\fi}
-%D Instead of refering to colors, one can also directly specify
-%D a color:
+%D Instead of refering to colors, one can also directly specify a color:
%D
%D \starttyping
%D \definepalet[test][xx=green]
@@ -567,8 +548,8 @@
%D \macros
%D {setuppalet}
%D
-%D Colors are taken from the current palet, if defined.
-%D Setting the current palet is done by:
+%D Colors are taken from the current palet, if defined. Setting the current palet is
+%D done by:
%D
%D \showsetup{setuppalet}
@@ -660,8 +641,8 @@
%D \macros
%D {showcolor}
%D
-%D But let's not forget that we also have the more traditional
-%D non||related colors. These show up after:
+%D But let's not forget that we also have the more traditional non||related colors.
+%D These show up after:
%D
%D \starttyping
%D \showcolor [name]
@@ -673,8 +654,8 @@
\fetchruntimecommand \showcolor \f!colo_run
-%D It would make sense to put the following code in \type
-%D {colo-mps}, but it it rather low level.
+%D It would make sense to put the following code in \type {colo-mps}, but it it
+%D rather low level.
%D \macros
%D {negatecolorcomponent,negatedcolorcomponent}
@@ -705,8 +686,8 @@
%D \macros
%D {MPcolor}
%D
-%D A very special macro is \type{\MPcolor}. This one can be
-%D used to pass a \CONTEXT\ color to \METAPOST.
+%D A very special macro is \type{\MPcolor}. This one can be used to pass a \CONTEXT\
+%D color to \METAPOST.
%D
%D \starttyping
%D \MPcolor{my own red}
@@ -715,15 +696,13 @@
%D This macro returns \METAPOST\ code that represents the
%D color.
%D
-%D For the moment we keep the next downward compatibility
-%D switch, i.e.\ expanded colors. However, predefined colors
-%D and palets are no longer expanded (which is what I wanted
-%D in the first place).
+%D For the moment we keep the next downward compatibility switch, i.e.\ expanded
+%D colors. However, predefined colors and palets are no longer expanded (which is
+%D what I wanted in the first place).
%D
-%D In \MKIV\ we don't support color separation as we might now
-%D assume that printing houses have the right programs to do
-%D it themselves. If it's ever needed in \MKIV\ It is relatively
-%D easy to support it in the backend code.
+%D In \MKIV\ we don't support color separation as we might now assume that printing
+%D houses have the right programs to do it themselves. If it's ever needed in \MKIV\
+%D It is relatively easy to support it in the backend code.
% todo: palets in definecolor
% todo: {\red xx} vs \red{xx}
@@ -773,12 +752,12 @@
\fi
\fi}
-% Currently in mkiv transparency is implemented independent of color. This costs
-% a bit more processing time but gives the possibility to apply transparency
-% independently in the future. Is this useful? If not we may as well combine them
-% again in the future. By coupling we are downward compatible. When we decouple we
-% need to do more tricky housekeeping (e.g. persist color independent transparencies
-% when color bound ones are nil.
+%D Currently in mkiv transparency is implemented independent of color. This costs a
+%D bit more processing time but gives the possibility to apply transparency
+%D independently in the future. Is this useful? If not we may as well combine them
+%D again in the future. By coupling we are downward compatible. When we decouple we
+%D need to do more tricky housekeeping (e.g. persist color independent
+%D transparencies when color bound ones are nil.
% Since we couple definitions, we could stick to one test. Todo. Same for mpcolor.
@@ -804,21 +783,21 @@
\def\colo_helpers_fast_activate_yes#1%
{\ifcsname\??colorsetter\currentcolorprefix#1\endcsname
\lastnamedcs
- \csname\??transparencysetter\currentcolorprefix#1\endcsname
+ \begincsname\??transparencysetter\currentcolorprefix#1\endcsname
\else\ifcsname\??colorsetter#1\endcsname
\lastnamedcs
- \csname\??transparencysetter#1\endcsname
+ \begincsname\??transparencysetter#1\endcsname
\fi\fi}
\def\colo_helpers_fast_activate_nop#1%
{\ifcsname\??colorsetter#1\endcsname
\lastnamedcs
- \csname\??transparencysetter#1\endcsname
+ \begincsname\??transparencysetter#1\endcsname
\fi}
\def\colo_helpers_activate_dummy
- {\csname\??colorsetter \v_colo_dummy_name\endcsname
- \csname\??transparencysetter\v_colo_dummy_name\endcsname}
+ {\begincsname\??colorsetter \v_colo_dummy_name\endcsname
+ \begincsname\??transparencysetter\v_colo_dummy_name\endcsname}
\let\dofastcoloractivation\colo_helpers_fast_activate
@@ -835,16 +814,16 @@
\def\colo_helpers_activate_yes
{\ifcsname\??colorsetter\currentcolorprefix\currentcolorname\endcsname
\lastnamedcs
- \csname\??transparencysetter\currentcolorprefix\currentcolorname\endcsname
+ \begincsname\??transparencysetter\currentcolorprefix\currentcolorname\endcsname
\else\ifcsname\??colorsetter\currentcolorname\endcsname
\lastnamedcs
- \csname\??transparencysetter\currentcolorname\endcsname
+ \begincsname\??transparencysetter\currentcolorname\endcsname
\fi\fi}
\def\colo_helpers_activate_nop
{\ifcsname\??colorsetter\currentcolorname\endcsname
\lastnamedcs
- \csname\??transparencysetter\currentcolorname\endcsname
+ \begincsname\??transparencysetter\currentcolorname\endcsname
\fi}
\def\colo_helpers_activate_yes_only
@@ -870,10 +849,10 @@
{\let\currentcolorname\currentcolorparameter % maybe only when success
\ifcsname\??colorsetter\currentcolorprefix\currentcolorparameter\endcsname
\lastnamedcs
- \csname\??transparencysetter\currentcolorprefix\currentcolorparameter\endcsname
+ \begincsname\??transparencysetter\currentcolorprefix\currentcolorparameter\endcsname
\else\ifcsname\??colorsetter\currentcolorparameter\endcsname
\lastnamedcs
- \csname\??transparencysetter\currentcolorparameter\endcsname
+ \begincsname\??transparencysetter\currentcolorparameter\endcsname
\fi\fi}
\let\dosetcolorattribute\dousecolorhashparameter % for a while
@@ -888,7 +867,7 @@
% \let\colo_basics_synchronize\gobbleoneargument % used in mp interface
% \let\colo_basics_inherit \gobbletwoarguments % used in mp interface
-\def\colo_basics_allocate#1%
+\def\colo_basics_allocate#1% todo: use a chardef instead
{\expandafter\newcount\csname\??colornumber#1\endcsname
\clf_synccolorcount{#1}\c_syst_last_allocated_count}
@@ -971,10 +950,9 @@
\unexpanded\setvalue{#1}{\colo_helpers_activate{#1}}%
\fi}
-% Spotcolors used setxvalue but that messes up currentcolor
-% and probably no global is needed either but they are global
-% at the lua end (true argument) so we keep that if only because
-% spot colors often are a document wide property
+%D Spotcolors used setxvalue but that messes up currentcolor and probably no global
+%D is needed either but they are global at the lua end (true argument) so we keep
+%D that if only because spot colors often are a document wide property
\def\colo_basics_define_spot[#1][#2][#3]%
{\clf_definespotcolorglobal{#1}{#2}{#3}%
@@ -1026,8 +1004,8 @@
%
% \definecolor[one][two]
%
-% only color one is actually defined and two is not seen at the
-% \LUA\ end. This means that this doesn't work:
+% Only color one is actually defined and two is not seen at the \LUA\ end. This
+% means that this doesn't work:
%
% \definecolor[ColorA][red]
% \definecolor[ColorB][.5(ColorA)]
@@ -1111,9 +1089,8 @@
%D \macros
%D {doifcolorelse, doifcolor}
%D
-%D Switching to a color is done by means of the following
-%D command. Later on we will explain the use of palets. We
-%D define ourselves a color conditional first.
+%D Switching to a color is done by means of the following command. Later on we will
+%D explain the use of palets. We define ourselves a color conditional first.
\def\doifelsecolor#1%
{\ifcsname\??colorattribute\currentcolorprefix#1\endcsname
@@ -1138,13 +1115,11 @@
%D \macros
%D {startregistercolor,stopregistercolor,permitcolormode}
%D
-%D If you only want to register a color, the switch \type
-%D {\ifpermitcolormode} can be used. That way the nested
-%D colors know where to go back to.
+%D If you only want to register a color, the switch \type {\ifpermitcolormode} can
+%D be used. That way the nested colors know where to go back to.
%D
-%D We use these macros for implementing text colors
-%D (actually, the first application was in foreground
-%D colors).
+%D We use these macros for implementing text colors (actually, the first application
+%D was in foreground colors).
%D
%D \starttyping
%D \starttextcolor[red]
@@ -1233,16 +1208,28 @@
\fi
\to \everysetupcolors
+% \def\colo_palets_define_set#1#2#3%
+% {\doifelseassignment{#3}% \definepalet[test][xx={y=.4}]
+% {\colo_palets_define_assign}%
+% {\ifcsname\??colorsetter#3\endcsname
+% % \definepalet[test][xx=green]
+% \expandafter\colo_palets_define_inherit
+% \else
+% % not entered when making format
+% \expandafter\colo_palets_define_undefine
+% \fi}%
+% {#1}{#2}{#3}}
+
\def\colo_palets_define_set#1#2#3%
- {\doifelseassignment{#3}% \definepalet[test][xx={y=.4}]
- {\colo_palets_define_assign}%
- {\ifcsname\??colorsetter#3\endcsname
- % \definepalet[test][xx=green]
- \expandafter\colo_palets_define_inherit
- \else
- % not entered when making format
- \expandafter\colo_palets_define_undefine
- \fi}%
+ {\ifcondition\validassignment{#3}% \definepalet[test][xx={y=.4}]
+ \expandafter\colo_palets_define_assign
+ \else\ifcsname\??colorsetter#3\endcsname
+ % \definepalet[test][xx=green]
+ \doubleexpandafter\colo_palets_define_inherit
+ \else
+ % not entered when making format
+ \doubleexpandafter\colo_palets_define_undefine
+ \fi\fi
{#1}{#2}{#3}}
\def\colo_palets_define_inherit#1#2#3%
@@ -1298,8 +1285,8 @@
%D \macros
%D {colorvalue, grayvalue}
%D
-%D We can typeset the color components using \type{\colorvalue} and
-%D \type{\grayvalue}. The commands:
+%D We can typeset the color components using \type {\colorvalue} and \type
+%D {\grayvalue}. The commands:
%D
%D \startbuffer
%D color value of SomeKindOfRed: \colorvalue{SomeKindOfRed} \crlf
@@ -1376,8 +1363,8 @@
%D \macros
%D {forcecolorhack}
%D
-%D We can out this in front of (for instance) a special and so force color
-%D to be applied (only glyphs, rules and leaders are handled).
+%D We can out this in front of (for instance) a special and so force color to be
+%D applied (only glyphs, rules and leaders are handled).
%D
%D \startbuffer
%D \framed
@@ -1438,10 +1425,10 @@
\definecolor[trace:g][g=.75,t=.5,a=1]
\definecolor[trace:b][b=.75,t=.5,a=1]
%definecolor[trace:c][c=.75,t=.5,a=1]
-\definecolor[trace:c][g=.75,b=.75,t=.5,a=1]
%definecolor[trace:m][m=.75,t=.5,a=1]
-\definecolor[trace:m][r=.75,b=.75,t=.5,a=1]
%definecolor[trace:y][y=.75,t=.5,a=1]
+\definecolor[trace:c][g=.75,b=.75,t=.5,a=1]
+\definecolor[trace:m][r=.75,b=.75,t=.5,a=1]
\definecolor[trace:y][r=.75,g=.75,t=.5,a=1]
\definecolor[trace:s][s=.75,t=.5,a=1]
\definecolor[trace:d][s=.25,t=.5,a=1]
@@ -1452,11 +1439,11 @@
\definecolor[trace:dg][g=.75,t=.75,a=1]
\definecolor[trace:db][b=.75,t=.75,a=1]
%definecolor[trace:dc][c=.75,t=.75,a=1]
-\definecolor[trace:dc][g=.75,b=.75,t=.75,a=1]
%definecolor[trace:dm][m=.75,t=.75,a=1]
-\definecolor[trace:dm][r=.75,b=.75,t=.75,a=1]
%definecolor[trace:dy][y=.75,t=.75,a=1]
-\definecolor[trace:y][r=.75,g=.75,t=.75,a=1]
+\definecolor[trace:dc][g=.75,b=.75,t=.75,a=1]
+\definecolor[trace:dm][r=.75,b=.75,t=.75,a=1]
+\definecolor[trace:dy][r=.75,g=.75,t=.75,a=1]
\definecolor[trace:ds][s=.75,t=.75,a=1]
\definecolor[trace:dd][s=.25,t=.75,a=1]
\definecolor[trace:do][r=1,g=.6,b=.1,t=.75,a=1]
diff --git a/Master/texmf-dist/tex/context/base/mkiv/colo-ini.mkxl b/Master/texmf-dist/tex/context/base/mkiv/colo-ini.mkxl
new file mode 100644
index 00000000000..e821fb7e282
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/colo-ini.mkxl
@@ -0,0 +1,1407 @@
+%D \module
+%D [ file=colo-ini,
+%D version=2007.08.08,
+%D title=\CONTEXT\ Color Macros,
+%D subtitle=Initialization,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D We need to clean this up further but first we have to make sure that mkiv
+%D code works ok.
+
+\writestatus{loading}{ConTeXt Color Macros / Initialization}
+
+%D Todo: move color space in color attribute (last two bits)
+
+%D This module implements color. Since \MKII\ and \MKIV\ use a completely
+%D different approach, this module only implements a few generic mechanisms.
+
+\installcorenamespace{color}
+\installcorenamespace{colorattribute}
+\installcorenamespace{transparencyattribute}
+\installcorenamespace{colorsetter}
+\installcorenamespace{transparencysetter}
+\installcorenamespace{colorpaletspecification}
+\installcorenamespace{colorpalet}
+\installcorenamespace{colorstack}
+\installcorenamespace{colorconversions}
+\installcorenamespace{colornumber}
+
+\registerctxluafile{colo-ini}{}
+\registerctxluafile{colo-icc}{}
+
+\unprotect
+
+%D In \MKIV\ we have independent color, colorspace and transparency but I'm still
+%D not sure if I keep it that way as it's probably more efficient to combine them
+%D (less attributes and finalizing). If it becomes a bottleneck we can set up a more
+%D complex system with one shared attribute for colorspace, color and transparency.
+%D
+%D When typesetting for paper, we prefer using the \CMYK\ color space, but for
+%D on||screen viewing we prefer \RGB\ (the previous implementation supported only
+%D this scheme). Independant of such specifications, we support some automatic
+%D conversions:
+%D
+%D \startitemize[packed]
+%D \item convert all colors to \RGB
+%D \item convert all colors to \CMYK
+%D \item convert all colors to gray scales
+%D \stopitemize
+%D
+%D These options are communicated by means of:
+
+\newconditional\c_colo_rgb_supported
+\newconditional\c_colo_cmyk_supported
+\newconditional\c_colo_spot_supported % backend driven
+\newconditional\c_colo_convert_gray \settrue\c_colo_convert_gray
+\newconditional\c_colo_enabled
+\newconditional\c_colo_expanded
+
+\let\m_colo_weight_gray\v!yes
+
+\let\currentcolormodel \empty
+\let\currentcolorname \empty
+\let\currentcolorpalet \empty
+\let\currentcolorprefix\empty % \currentcolorpalet:
+
+%D \macros
+%D {definecolor,defineglobalcolor,definenamedcolor,definespotcolor,definemultitonecolor,
+%D definetransparency}
+%D
+%D \starttyping
+%D \definecolor [blue] [c=1,m=.38,y=0,k=.64] % pantone pms 2965 uncoated m
+%D \definecolor [yellow] [c=0,m=.28,y=1,k=.06] % pantone pms 124 uncoated m
+%D
+%D \definespotcolor [blue-100] [blue] [p=1]
+%D \definespotcolor [yellow-100] [yellow] [p=1]
+%D
+%D \definemultitonecolor [pdftoolscolor] [blue=.12,yellow=.28] [c=.1,m=.1,y=.3,k=.1]
+%D
+%D \defineprocesscolor[myred][r=.5]
+%D \defineprocesscolor[myredish][red][a=1,t=.5]
+%D
+%D \blackrule[color=myred,width=\hsize,height=1cm] \par
+%D \blackrule[color=myredish,width=\hsize,height=1cm]
+%D
+%D \useexternalfigure[demofig][mill.png][object=no]
+%D
+%D \startcombination[4*1]
+%D {\externalfigure[demofig]} {no color}
+%D {\externalfigure[demofig][color=pdftoolscolor]} {indexed duotone}
+%D {\externalfigure[demofig][color=blue-100]} {spot color}
+%D {\externalfigure[demofig][color=yellow-100]} {spot color}
+%D \stopcombination
+%D \stoptyping
+
+\unexpanded\def\definecolor {\dodoubleargument\colo_basics_define}
+\unexpanded\def\defineglobalcolor {\dodoubleargument\colo_basics_define_global}
+\unexpanded\def\defineprocesscolor {\dotripleargument\colo_basics_define_process}
+\unexpanded\def\definenamedcolor {\dodoubleargument\colo_basics_define_named}
+\unexpanded\def\definespotcolor {\dotripleargument\colo_basics_define_spot}
+\unexpanded\def\definemultitonecolor {\doquadrupleempty\colo_basics_define_multitone}
+\unexpanded\def\definetransparency {\dodoubleargument\colo_basics_define_transpancy}
+\unexpanded\def\defineglobaltransparency{\dodoubleargument\colo_basics_define_transpancy_global}
+
+\unexpanded\def\loadfoundcolorsetfile#1#2% name foundname / not a user command
+ {\startreadingfile
+ \startcolorset[#1]%
+ \input{#2}%
+ \stopcolorset
+ \showmessage\m!colors4{#1}%
+ \stopreadingfile}
+
+%D \macros
+%D {startcolor,stopcolor,color,graycolor}
+%D
+%D The local and global commands are here just for compatibility with \MKII.
+%D
+%D \showsetup{startcolor}
+%D
+%D The simple color commands are:
+%D
+%D \showsetup{color}
+%D \showsetup{graycolor}
+
+%D We expect sane behaviour in \MKIV\ so we don't used grouped command any
+%D longer.
+
+% \testfeatureonce{100000}{\color[red]{}} % 1.046 => 0.541
+
+\let\g_color\empty
+\let\g_style\empty
+
+\unexpanded\def\switchtocolor[#1]{\begincsname#1\endcsname}
+
+% transparency
+
+\unexpanded\def\transparent[#1]%
+ {\bgroup
+ \edef\currenttransparencyname{#1}%
+ % the \relax catches a non existent csname
+ \ifx\currenttransparencyname\v!reset
+ \attribute\transparencyattribute\attributeunsetvalue
+ \else
+ \begincsname\??transparencysetter\currenttransparencyname\endcsname\relax
+ \fi
+ \let\nexttoken}
+
+\unexpanded\def\starttransparent[#1]%$
+ {\begingroup
+ \edef\currenttransparencyname{#1}%
+ \ifx\currenttransparencyname\v!reset
+ \attribute\transparencyattribute\attributeunsetvalue
+ \else
+ \begincsname\??transparencysetter\currenttransparencyname\endcsname\relax
+ \fi}
+
+\unexpanded\def\stoptransparent
+ {\endgroup}
+
+% color
+
+\unexpanded\def\coloronly[#1]%
+ {\bgroup
+ \edef\currentcolorname{#1}%
+ \ifx\currentcolorprefix\empty
+ \colo_helpers_activate_nop_only
+ \else
+ \colo_helpers_activate_yes_only
+ \fi
+ \let\nexttoken}
+
+\unexpanded\def\startcoloronly[#1]%$
+ {\begingroup
+ \edef\currentcolorname{#1}%
+ \ifx\currentcolorprefix\empty
+ \colo_helpers_activate_nop_only
+ \else
+ \colo_helpers_activate_yes_only
+ \fi}
+
+\unexpanded\def\stopcoloronly
+ {\endgroup}
+
+% color + transparency
+
+\unexpanded\def\color[#1]%
+ {\bgroup
+ \edef\currentcolorname{#1}%
+ \ifx\currentcolorprefix\empty
+ \colo_helpers_activate_nop
+ \else
+ \colo_helpers_activate_yes
+ \fi
+ \let\nexttoken}
+
+\unexpanded\def\graycolor[#1]%
+ {\bgroup
+ \colo_helpers_set_model\s!gray\colo_helpers_activate{#1}%
+ \let\nexttoken}
+
+\unexpanded\def\startcolor[#1]%$
+ {\begingroup
+ \edef\currentcolorname{#1}%
+ \ifx\currentcolorprefix\empty
+ \colo_helpers_activate_nop
+ \else
+ \colo_helpers_activate_yes
+ \fi}
+
+\unexpanded\def\stopcolor
+ {\endgroup}
+
+\unexpanded\def\colored[#1]%
+ {\bgroup
+ \colo_basics_defined_and_activated{#1}%
+ \let\nexttoken}
+
+\unexpanded\def\fastcolored[#1]#2%
+ {\begingroup % is this command still needed?
+ \colo_basics_defined_and_activated{#1}%
+ #2%
+ \endgroup}
+
+\unexpanded\def\directcolored[#1]%
+ {\colo_basics_defined_and_activated{#1}}
+
+\unexpanded\def\fastcolor [#1]#2%
+ {\begingroup % is this command still needed?
+ \edef\currentcolorname{#1}%
+ \ifx\currentcolorprefix\empty
+ \colo_helpers_activate_nop
+ \else
+ \colo_helpers_activate_yes
+ \fi
+ #2%
+ \endgroup}
+
+\unexpanded\def\directcolor[#1]%
+ {\edef\currentcolorname{#1}%
+ \ifx\currentcolorprefix\empty
+ \colo_helpers_activate_nop
+ \else
+ \colo_helpers_activate_yes
+ \fi}
+
+%D The following command is obsolete:
+
+\unexpanded\def\startcolorpage {\startcolor[\ifx\maintextcolor\empty\defaulttextcolor\else\maintextcolor\fi]}
+\unexpanded\def\stopcolorpage {\stopcolor}
+
+\unexpanded\def\getcolorattributevalue#1#2% obsolete, use \thecolorattribute instead ...
+ {\begingroup
+ \colo_helpers_activate{#1}%
+ \normalexpanded{\endgroup\edef\noexpand#2%
+ {\ifnum\attribute\colorattribute=\attributeunsetvalue\else\number\attribute\colorattribute\fi}}}
+
+\let\grey\graycolor % these macros are only used in tracing
+
+%D \macros
+%D {startcurrentcolor,stopcurrentcolor}
+
+\unexpanded\def\startcurrentcolor{\startcolor[\outercolorname]}
+\unexpanded\def\stopcurrentcolor {\stopcolor}
+
+%D \macros
+%D {setupcolor}
+%D
+%D Color definitions can be grouped in files with the name:
+%D
+%D \starttyping
+%D colo-imp-tag.tex
+%D \stoptyping
+%D
+%D Loading such a file is done by:
+%D
+%D \showsetup{usecolors}
+%D
+%D Some default colors are specified in \type {colo-imp-rgb}, which is loaded into
+%D the format by default.
+%D
+%D Some demo palets and groups are defined in \type {colo-imp-dem} which can be
+%D loaded with:
+%D
+%D \starttyping
+%D \usecolors[dem]
+%D \stoptyping
+
+\unexpanded\def\startcolorset[#1]{\clf_startcolorset{#1}}
+\unexpanded\def\stopcolorset {\clf_stopcolorset}
+\unexpanded\def\usecolors [#1]{\clf_usecolors{#1}}
+
+\let\setupcolor\usecolors
+
+\installsetuponlycommandhandler \??color {colors}
+
+\let\colo_helpers_show_message\gobblethreearguments
+
+% \newtoks\everysetupcolors
+
+\let\v_colo_freeze_state\s!false
+
+\setvalue{\??colorconversions\v!yes}%
+ {\settrue \c_colo_convert_gray}
+
+\setvalue{\??colorconversions\v!always}%
+ {\settrue \c_colo_convert_gray
+ \setfalse\c_colo_rgb_supported
+ \setfalse\c_colo_cmyk_supported}
+
+\appendtoks
+ %
+ \doifelse{\directcolorsparameter\c!spot }\v!yes \settrue \setfalse\c_colo_spot_supported
+ \doifelse{\directcolorsparameter\c!expansion}\v!yes \settrue \setfalse\c_colo_expanded
+ \doifelse{\directcolorsparameter\c!rgb }\v!yes \settrue \setfalse\c_colo_rgb_supported
+ \doifelse{\directcolorsparameter\c!cmyk }\v!yes \settrue \setfalse\c_colo_cmyk_supported
+ \doifelse{\directcolorsparameter\c!state }\v!start\settrue \setfalse\c_colo_enabled
+ %
+ \edef\m_colo_weight_gray{\directcolorsparameter\c!factor}%
+ %
+ \ifconditional\c_colo_expanded
+ \let\v_colo_freeze_state\s!true
+ \else
+ \let\v_colo_freeze_state\s!false
+ \fi
+ %
+ \setfalse\c_colo_convert_gray
+ \begincsname\??colorconversions\directcolorsparameter\c!conversion\endcsname
+ % too often:
+ \ifconditional\c_colo_rgb_supported \colo_helpers_show_message\m!colors{10}\v!rgb \fi
+ \ifconditional\c_colo_cmyk_supported\colo_helpers_show_message\m!colors{10}\v!cmyk\fi
+ \colo_helpers_set_current_model
+ \ifproductionrun
+ \edef\p_pagecolormodel{\directcolorsparameter\c!pagecolormodel}%
+ \clf_setpagecolormodel{\ifx\p_pagecolormodel\v!auto\currentcolormodel\else\p_pagecolormodel\fi}%
+ \fi
+\to \everysetupcolors
+
+\appendtoks
+ \setupcolors[\c!state=\v!start]%
+ \clf_enablecolor % this can as well happen when
+ \clf_enabletransparency % the handler is defined in lua
+ \let\colo_helpers_show_message\showmessage
+\to \everyjob
+
+%D We provide stacking independent of grouping.
+
+\newcount\c_colo_nesting
+
+\unexpanded\def\pushcolor[#1]%
+ {\global\advance\c_colo_nesting\plusone
+ \expandafter\edef\csname\??colorstack\number\c_colo_nesting\endcsname
+ {\attribute\colormodelattribute \the\attribute\colormodelattribute
+ \attribute\colorattribute \the\attribute\colorattribute
+ \attribute\transparencyattribute\the\attribute\transparencyattribute
+ \relax}% stack
+ \colo_helpers_activate{#1}}
+
+\unexpanded\def\popcolor
+ {\csname\??colorstack\number\c_colo_nesting\endcsname
+ \global\advance\c_colo_nesting\minusone}
+
+% a simple one: assumes grouping
+
+\newcount\c_colo_saved_attribute_color
+\newcount\c_colo_saved_attribute_transparency
+
+\unexpanded\def\savecolor
+ {\c_colo_saved_attribute_color \attribute\colorattribute
+ \c_colo_saved_attribute_transparency\attribute\transparencyattribute}
+
+\unexpanded\def\restorecolor
+ {\attribute\colorattribute \c_colo_saved_attribute_color
+ \attribute\transparencyattribute\c_colo_saved_attribute_transparency}
+
+%D In this documentation we will not go into too much details on palets. Curious
+%D users can find more information on this topic in \from[use of color].
+%D
+%D At the moment we implemented color in \CONTEXT\ color printing was not yet on the
+%D desktop. In spite of this lack our graphics designer made colorfull
+%D illustrations. When printed on a black and white printer, distinctive colors can
+%D come out equally gray. We therefore decided to use only colors that were
+%D distinctive in colors as well as in black and white print.
+%D
+%D Although none of the graphic packages we used supported logical colors and global
+%D color redefition, we build this support into \CONTEXT. This enabled us to
+%D experiment and also prepared us for the future.
+
+%D \macros
+%D {definepalet}
+%D
+%D Colors are grouped in palets. The colors in such a palet can have colorful names,
+%D but best is to use names that specify their use, like {\em important} or {\em
+%D danger}. As a sort of example \CONTEXT\ has some palets predefined,
+%D like:\footnote{At the time I wrote the palet support, I was reading 'A hort
+%D history of time' of S.~Hawkins, so that's why we stuck to quarks.}
+%D
+%D \starttyping
+%D \definepalet
+%D [alfa]
+%D [ top=rood:7,
+%D bottom=groen:6,
+%D up=blauw:5,
+%D down=cyaan:4,
+%D strange=magenta:3,
+%D charm=geel:2]
+%D \stoptyping
+%D
+%D It's formal definition is:
+%D
+%D \showsetup{definepalet}
+%D
+%D Visualized, such a palet looks like:
+%D
+%D \startbuffer[palet]
+%D \showpalet [alfa] [horizontal,name,number,value]
+%D \stopbuffer
+%D
+%D \startlinecorrection
+%D \getbuffer[palet]
+%D \stoplinecorrection
+%D
+%D This bar shows both the color and gray alternatives of the palet components (not
+%D visible in black and white print).
+%D
+%D When needed, one can copy a palet by saying:
+%D
+%D \starttyping
+%D \definepalet [TEXcolorpretty] [colorpretty]
+%D \stoptyping
+%D
+%D This saves us some typing in for instance the modules that deal with pretty
+%D verbatim typesetting.
+
+\installcorenamespace{paletlist}
+\installcorenamespace{paletsize}
+
+\let\m_colo_palet\relax
+\let\c_colo_palet\relax
+
+\def\colo_palet_allocate#1%
+ {\expandafter\let \csname\??paletlist#1\endcsname\empty
+ \expandafter\newcount\csname\??paletsize#1\endcsname}
+
+\def\colo_palet_prepare#1%
+ {\edef\colo_palet_name{#1}%
+ \ifcsname\??paletlist\colo_palet_name\endcsname
+ \csname\??paletsize\colo_palet_name\endcsname\zerocount
+ \else
+ \colo_palet_allocate\colo_palet_name
+ \fi
+ \edef\m_colo_palet{\begincsname\??paletlist\colo_palet_name\endcsname}%
+ \expandafter\let\expandafter\c_colo_palet\csname\??paletsize\colo_palet_name\endcsname}
+
+\def\colo_palet_extend#1%
+ {\addtocommalist{#1}\m_colo_palet
+ \expandafter\let\csname\??paletlist\colo_palet_name\endcsname\m_colo_palet
+ \advance\c_colo_palet\plusone}
+
+\unexpanded\def\doifelsecolorpalet#1%
+ {\ifcsname\??paletlist#1\endcsname
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\let\paletlist\empty
+\let\paletsize\!!zerocount
+
+\unexpanded\def\getpaletlist[#1]%
+ {\edef\paletlist{\begincsname\??paletlist#1\endcsname}}
+
+\unexpanded\def\getpaletsize[#1]%
+ {\ifcsname\??paletsize#1\endcsname
+ \edef\paletsize{\the\lastnamedcs}%
+ \else
+ \let\paletsize\!!zerocount
+ \fi}
+
+\unexpanded\def\definepalet
+ {\dotripleempty\colo_palets_define}
+
+\def\colo_palets_define
+ {\ifthirdargument
+ \expandafter\colo_palets_define_b
+ \else
+ \expandafter\colo_palets_define_a
+ \fi}
+
+\unexpanded\def\colo_palets_define_a[#1][#2][#3]%
+ {\colo_palet_prepare{#1}%
+ \ifcondition\validassignment{#2}%
+ \setevalue{\??colorpaletspecification#1}{#2}%
+ \processcommalist[#2]{\colo_palets_define_one{#1}}%
+ \orelse\ifcsname\??colorpaletspecification#2\endcsname
+ \normalexpanded{\colo_palets_define[#1][\lastnamedcs]}%
+ \fi}
+
+\unexpanded\def\colo_palets_define_b[#1][#2][#3]%
+ {\colo_palet_prepare{#1}%
+ \setevalue{\??colorpaletspecification#1}{#2}%
+ \colo_palet_extend{#2}%
+ \colo_palets_define_assign{#1}{#2}{#3}}
+
+\def\colo_palets_define_one#1#2% get rid of { }
+ {\ifcondition\validassignment{#2}% catch empty entries
+ \colo_palets_define_two{#1}[#2]%
+ \else
+ \colo_palets_define_three{#1}{#2}%
+ \fi}
+
+\def\colo_palets_define_two#1[#2=#3]%
+ {\colo_palet_extend{#2}%
+ \colo_palets_define_set{#1}{#2}{#3}}%
+
+\def\colo_palets_define_three#1#2%
+ {\ifcsname\??colorpaletspecification#2\endcsname
+ \processcommacommand[\lastnamedcs]{\colo_palets_define_one{#1}}%
+ \fi}
+
+%D Instead of refering to colors, one can also directly specify a color:
+%D
+%D \starttyping
+%D \definepalet[test][xx=green]
+%D \definepalet[test][xx={y=.4}]
+%D \stoptyping
+
+%D \macros
+%D {setuppalet}
+%D
+%D Colors are taken from the current palet, if defined. Setting the current palet is
+%D done by:
+%D
+%D \showsetup{setuppalet}
+
+\newtoks\everysetuppalet
+
+\unexpanded\def\setuppalet
+ {\dosingleempty\colo_palets_setup}
+
+% \newtoks\t_colo_prefix % used in mp interface
+
+\def\colo_palets_setup[#1]%
+ {\edef\currentcolorpalet{#1}%
+ \ifx\currentcolorpalet\empty
+ % seems to be a reset
+ \let\currentcolorprefix\empty
+ %\t_colo_prefix\emptytoks
+ \orelse\ifcsname\??paletlist\currentcolorpalet\endcsname
+ \edef\currentcolorprefix{#1:}%
+ %\t_colo_prefix\expandafter{\currentcolorprefix}%
+ \else
+ \colo_helpers_show_message\m!colors7\currentcolorpalet
+ \let\currentcolorpalet\empty
+ \let\currentcolorprefix\empty
+ %\t_colo_prefix\emptytoks
+ \fi
+ \the\everysetuppalet
+ \colo_helpers_initialize_maintextcolor}
+
+%D \macros
+%D {showpalet}
+%D
+%D The previous visualization was typeset with:
+%D
+%D \typebuffer[palet]
+%D
+%D This commands is defined as:
+%D
+%D \showsetup{showpalet}
+
+\fetchruntimecommand \showpalet \f!colo_run
+
+%D \macros
+%D {showcolorcomponents}
+%D
+%D \starttyping
+%D \showcolorcomponents[color-1,color-2]
+%D \stoptyping
+
+\fetchruntimecommand \showcolorcomponents \f!colo_run
+
+%D \macros
+%D {comparepalet}
+%D
+%D There are some more testing macros available:
+%D
+%D \startbuffer
+%D \comparepalet [alfa]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D shows the palet colors against a background:
+%D
+%D \startlinecorrection
+%D \getbuffer
+%D \stoplinecorrection
+%D
+%D The formal definition is:
+%D
+%D \showsetup{comparepalet}
+
+\fetchruntimecommand \comparepalet \f!colo_run
+
+%D \macros
+%D {showcolor}
+%D
+%D But let's not forget that we also have the more traditional non||related colors.
+%D These show up after:
+%D
+%D \starttyping
+%D \showcolor [name]
+%D \stoptyping
+%D
+%D Where \type{name} for instance can be \type{rgb}.
+%D
+%D \showsetup{showcolor}
+
+\fetchruntimecommand \showcolor \f!colo_run
+
+%D It would make sense to put the following code in \type {colo-mps}, but it it
+%D rather low level.
+
+%D \macros
+%D {negatecolorcomponent,negatedcolorcomponent}
+%D
+%D These speak for themselves. See \type {colo-ext} for usage.
+
+\unexpanded\def\negatecolorcomponent#1% #1 = \macro
+ {\edef#1{\clf_negatecolorcomponent{#1}}}
+
+\def\negatedcolorcomponent#1%
+ {\clf_negatecolorcomponent{#1}}
+
+%D \macros
+%D {MPcolor}
+%D
+%D A very special macro is \type{\MPcolor}. This one can be used to pass a \CONTEXT\
+%D color to \METAPOST.
+%D
+%D \starttyping
+%D \MPcolor{my own red}
+%D \stoptyping
+%D
+%D This macro returns \METAPOST\ code that represents the
+%D color.
+%D
+%D For the moment we keep the next downward compatibility switch, i.e.\ expanded
+%D colors. However, predefined colors and palets are no longer expanded (which is
+%D what I wanted in the first place).
+%D
+%D In \MKIV\ we don't support color separation as we might now assume that printing
+%D houses have the right programs to do it themselves. If it's ever needed in \MKIV\
+%D It is relatively easy to support it in the backend code.
+
+% todo: palets in definecolor
+% todo: {\red xx} vs \red{xx}
+
+% \def\mptexcolor#1{"\dogetattributeid\s!color \somecolorattribute{#1} A"}
+%
+% \startMPpage
+% fill fullcircle scaled 10cm ;
+% fill fullcircle scaled 5cm withprescript \mptexcolor{red} withpostscript \mptexcolor{black} ;
+% fill fullcircle scaled 3cm ;
+% draw btex test etex withprescript \mptexcolor{blue} ;
+% \stopMPpage
+
+\unexpanded\def\setcolormodel[#1]% % beware, \setupcolors will overload this, so this one is
+ {\colo_helpers_set_model{#1}} % only for local usage
+
+\def\colo_helpers_set_model#1% direct
+ {\edef\currentcolormodel{#1}%
+ \clf_setcolormodel{\currentcolormodel}{\m_colo_weight_gray}} % sets attribute at lua end
+
+\colo_helpers_set_model\s!all
+
+\def\colo_helpers_set_current_model
+ {\ifconditional\c_colo_enabled
+ \ifconditional\c_colo_rgb_supported
+ \ifconditional\c_colo_cmyk_supported
+ \colo_helpers_set_model\s!all
+ \else
+ \colo_helpers_set_model\s!rgb
+ \fi
+ \else
+ \ifconditional\c_colo_cmyk_supported
+ \colo_helpers_set_model\s!cmyk
+ \else
+ \ifconditional\c_colo_convert_gray
+ \colo_helpers_set_model\s!gray
+ \else
+ \colo_helpers_set_model\s!none
+ \fi
+ \fi
+ \fi
+ \else
+ \ifconditional\c_colo_convert_gray
+ \colo_helpers_set_model\s!gray
+ \else
+ \colo_helpers_set_model\s!none
+ \fi
+ \fi}
+
+%D Currently in mkiv transparency is implemented independent of color. This costs a
+%D bit more processing time but gives the possibility to apply transparency
+%D independently in the future. Is this useful? If not we may as well combine them
+%D again in the future. By coupling we are downward compatible. When we decouple we
+%D need to do more tricky housekeeping (e.g. persist color independent
+%D transparencies when color bound ones are nil.
+
+% Since we couple definitions, we could stick to one test. Todo. Same for mpcolor.
+
+\def\v_colo_dummy_name{c_o_l_o_r}
+
+\letvalue{\??colorattribute \v_colo_dummy_name}\empty
+\letvalue{\??transparencyattribute\v_colo_dummy_name}\empty
+\letvalue{\??colorsetter \v_colo_dummy_name}\empty
+\letvalue{\??transparencysetter \v_colo_dummy_name}\empty
+
+\letvalue{\??colorsetter -}\empty % used?
+\letvalue{\??transparencysetter-}\empty % used?
+
+% new: expandable (see tbl)
+
+\def\colo_helpers_fast_activate
+ {\ifx\currentcolorprefix\empty
+ \expandafter\colo_helpers_fast_activate_nop
+ \else
+ \expandafter\colo_helpers_fast_activate_yes
+ \fi}
+
+\def\colo_helpers_fast_activate_yes#1%
+ {\ifcsname\??colorsetter\currentcolorprefix#1\endcsname
+ \lastnamedcs
+ \begincsname\??transparencysetter\currentcolorprefix#1\endcsname
+ \orelse\ifcsname\??colorsetter#1\endcsname
+ \lastnamedcs
+ \begincsname\??transparencysetter#1\endcsname
+ \fi}
+
+\def\colo_helpers_fast_activate_nop#1%
+ {\ifcsname\??colorsetter#1\endcsname
+ \lastnamedcs
+ \begincsname\??transparencysetter#1\endcsname
+ \fi}
+
+\def\colo_helpers_activate_dummy
+ {\begincsname\??colorsetter \v_colo_dummy_name\endcsname
+ \begincsname\??transparencysetter\v_colo_dummy_name\endcsname}
+
+\let\dofastcoloractivation\colo_helpers_fast_activate
+
+% so far
+
+\def\colo_helpers_activate#1% two-step is not that much faster but less tracing
+ {\edef\currentcolorname{#1}%
+ \ifx\currentcolorprefix\empty
+ \expandafter\colo_helpers_activate_nop
+ \else
+ \expandafter\colo_helpers_activate_yes
+ \fi}
+
+\def\colo_helpers_activate_yes
+ {\ifcsname\??colorsetter\currentcolorprefix\currentcolorname\endcsname
+ \lastnamedcs
+ \begincsname\??transparencysetter\currentcolorprefix\currentcolorname\endcsname
+ \orelse\ifcsname\??colorsetter\currentcolorname\endcsname
+ \lastnamedcs
+ \begincsname\??transparencysetter\currentcolorname\endcsname
+ \fi}
+
+\def\colo_helpers_activate_nop
+ {\ifcsname\??colorsetter\currentcolorname\endcsname
+ \lastnamedcs
+ \begincsname\??transparencysetter\currentcolorname\endcsname
+ \fi}
+
+\def\colo_helpers_activate_yes_only
+ {\ifcsname\??colorsetter\currentcolorprefix\currentcolorname\endcsname
+ \lastnamedcs
+ \orelse\ifcsname\??colorsetter\currentcolorname\endcsname
+ \lastnamedcs
+ \fi}
+
+\def\colo_helpers_activate_nop_only
+ {\ifcsname\??colorsetter\currentcolorname\endcsname
+ \lastnamedcs
+ \fi}
+
+\let\dousecolorparameter\colo_helpers_activate
+
+\unexpanded\def\dousecolorhashparameter#1#2%
+ {\ifcsname#1#2\endcsname
+ \expandafter\dousecolorparameter\csname#1#2\endcsname
+ \fi}
+
+\unexpanded\def\dousecurrentcolorparameter
+ {\let\currentcolorname\currentcolorparameter % maybe only when success
+ \ifcsname\??colorsetter\currentcolorprefix\currentcolorparameter\endcsname
+ \lastnamedcs
+ \begincsname\??transparencysetter\currentcolorprefix\currentcolorparameter\endcsname
+ \orelse\ifcsname\??colorsetter\currentcolorparameter\endcsname
+ \lastnamedcs
+ \begincsname\??transparencysetter\currentcolorparameter\endcsname
+ \fi}
+
+\let\dosetcolorattribute\dousecolorhashparameter % for a while
+
+\unexpanded\def\deactivatecolor % sort of public but a bad name
+ {\let\currentcolorname\s!black
+ \attribute\colorattribute\attributeunsetvalue
+ \attribute\transparencyattribute\attributeunsetvalue}
+
+% todo: check if color is overloading a non-color command
+
+% \let\colo_basics_synchronize\gobbleoneargument % used in mp interface
+% \let\colo_basics_inherit \gobbletwoarguments % used in mp interface
+
+\def\colo_basics_allocate#1%
+ {\expandafter\newcount\csname\??colornumber#1\endcsname
+ \clf_synccolorcount{#1}\c_syst_last_allocated_count}
+
+\def\colo_basics_synchronize#1%
+ {\ifcsname\??colornumber#1\endcsname\else
+ \colo_basics_allocate{#1}%
+ \fi
+ \clf_synccolor{#1}%
+ %\csname\??colornumber#1\endcsname\csname\??colorattribute#1\endcsname
+ \lastnamedcs\csname\??colorattribute#1\endcsname}
+
+\let\colo_basics_inherit\clf_synccolorclone
+
+\newcount\c_colo_protection
+
+\unexpanded\def\startprotectedcolors
+ {\advance\c_colo_protection\plusone}
+
+\unexpanded\def\stopprotectedcolors
+ {\advance\c_colo_protection\minusone}
+
+\def\colo_basics_define[#1][#2]%
+ {\edef\m_colo_old{#1}%
+ \edef\m_colo_new{#2}%
+ \ifx\m_colo_old\m_colo_new
+ % maybe a warning
+ \else
+ \clf_defineprocesscolorlocal{#1}{#2}\v_colo_freeze_state\relax
+ \colo_basics_synchronize{#1}%
+ \ifcase\c_colo_protection
+ \unexpanded\setvalue{#1}{\colo_helpers_activate{#1}}%
+ \fi
+ \fi}
+
+\def\colo_basics_define_global[#1][#2]%
+ {\edef\m_colo_old{#1}%
+ \edef\m_colo_new{#2}%
+ \ifx\m_colo_old\m_colo_new
+ % maybe a warning
+ \else
+ \clf_defineprocesscolorglobal{#1}{#2}\v_colo_freeze_state\relax
+ \colo_basics_synchronize{#1}%
+ \ifcase\c_colo_protection
+ \unexpanded\setgvalue{#1}{\colo_helpers_activate{#1}}%
+ \fi
+ \fi}
+
+\let\colo_basics_define_named\colo_basics_define
+
+\def\dodefinefastcolor[#1][#2]% still not fast but ok (might change)
+ {\clf_defineprocesscolorlocal{#1}{#2}\v_colo_freeze_state\relax
+ \colo_basics_synchronize{#1}%
+ \ifcase\c_colo_protection
+ \unexpanded\setvalue{#1}{\colo_helpers_activate{#1}}%
+ \fi}
+
+\def\colo_basics_defined_and_activated#1%
+ {\clf_defineprocesscolordummy{#1}% we could pass dummy here too
+ \colo_basics_synchronize{\v_colo_dummy_name}%
+ \colo_helpers_activate_dummy}
+
+\def\colo_basics_define_process
+ {\ifthirdargument
+ \expandafter\colo_basics_define_process_yes
+ \else
+ \expandafter\colo_basics_define_process_nop
+ \fi}
+
+\def\colo_basics_define_process_yes[#1][#2][#3]%
+ {\clf_defineprocesscolorlocal{#1}{\processcolorcomponents{#2},#3}\v_colo_freeze_state\relax
+ \colo_basics_synchronize{#1}%
+ \ifcase\c_colo_protection
+ \unexpanded\setvalue{#1}{\colo_helpers_activate{#1}}%
+ \fi}
+
+\def\colo_basics_define_process_nop[#1][#2][#3]%
+ {\clf_defineprocesscolorlocal{#1}{#2}\v_colo_freeze_state\relax
+ \colo_basics_synchronize{#1}%
+ \ifcase\c_colo_protection
+ \unexpanded\setvalue{#1}{\colo_helpers_activate{#1}}%
+ \fi}
+
+%D Spotcolors used setxvalue but that messes up currentcolor and probably no global
+%D is needed either but they are global at the lua end (true argument) so we keep
+%D that if only because spot colors often are a document wide property
+
+\def\colo_basics_define_spot[#1][#2][#3]%
+ {\clf_definespotcolorglobal{#1}{#2}{#3}%
+ \colo_basics_synchronize{#1}%
+ \ifcase\c_colo_protection
+ \unexpanded\setgvalue{#1}{\colo_helpers_activate{#1}}%
+ \fi}
+
+\def\colo_basics_define_multitone[#1][#2][#3][#4]%
+ {\clf_definemultitonecolorglobal{#1}{#2}{#3}{#4}%
+ \colo_basics_synchronize{#1}%
+ \ifcase\c_colo_protection
+ \unexpanded\setgvalue{#1}{\colo_helpers_activate{#1}}%
+ \fi}
+
+%D Transparencies (only):
+
+\def\colo_basics_define_transpancy[#1][#2]%
+ {\clf_definetransparency{#1}{#2}}
+
+\def\colo_basics_define_transpancy_global[#1][#2]%
+ {\clf_definetransparencyglobal{#1}{#2}}
+
+% A goodie that replaces the startMPcolor hackery
+
+% \definecolor[red-t] [r=1,t=0.5,a=1]
+% \definecolor[green-t][g=1,t=0.5,a=1]
+%
+% \defineintermediatecolor[mycolora][0.5,red,green]
+% \defineintermediatecolor[mycolorb][0.5,red-t,green-t]
+%
+% \definecolor[mycolorc][.5(blue,red)]
+% \definecolor[mycolord][.5(blue)]
+% \definecolor[mycolord][-.5(blue,red)] % complement
+% \definecolor[mycolord][-(blue)] % complement
+%
+% \enabledirectives[colors.pgf]
+% \definecolor[mycolorx][magenta!50!yellow]
+%
+% \starttext
+% test {\mycolora OEPS} test
+% test {\mycolorb OEPS} test
+% test {\mycolorc OEPS} test
+% test {\mycolord OEPS} test
+% test {\mycolorx OEPS} test
+% \stoptext
+%
+% Beware: if we say:
+%
+% \definecolor[one][two]
+%
+% Only color one is actually defined and two is not seen at the \LUA\ end. This
+% means that this doesn't work:
+%
+% \definecolor[ColorA][red]
+% \definecolor[ColorB][.5(ColorA)]
+% \definecolor[ColorC][.5(ColorB,white)]
+%
+% But this does work:
+%
+% \definecolor[ColorA][1.0(red)]
+% \definecolor[ColorB][0.5(ColorA)]
+% \definecolor[ColorC][0.5(ColorB,white)]
+%
+% because the fractional definition results in a new definition.
+
+\unexpanded\def\defineintermediatecolor
+ {\dotripleempty\colo_basics_define_intermediate}
+
+\def\colo_basics_define_intermediate[#1][#2][#3]% \dotripleempty adds {} inside []
+ {\colo_basics_define_intermediate_indeed[#1][#2][#3]}
+
+\def\colo_basics_define_intermediate_indeed[#1][#2,#3,#4][#5]%
+ {\clf_defineintermediatecolor % not global
+ {#1}%
+ {#2}%
+ \rawcolorattribute{#3} %
+ \rawcolorattribute{#4} %
+ \rawtransparencyattribute{#3} %
+ \rawtransparencyattribute{#4} %
+ {#5}%
+ \v_colo_freeze_state
+ \relax
+ \colo_basics_synchronize{#1}%
+ \unexpanded\setvalue{#1}{\colo_helpers_activate{#1}}}
+
+%D Here is a more efficient helper for pgf:
+%D
+%D \starttyping
+%D \startluacode
+%D function commands.pgfxcolorspec(ca) -- {}{}{colorspace}{list}
+%D local cv = attributes.colors.values[ca]
+%D if cv then
+%D local model = cv[1]
+%D if model == 2 then
+%D context("{}{}{gray}{%1.3f}",cv[2])
+%D elseif model == 3 then
+%D context("{}{}{rgb}{%1.3f,%1.3f,%1.3f}",cv[3],cv[4],cv[5])
+%D elseif model == 4 then
+%D context("{}{}{cmyk}{%1.3f,%1.3f,%1.3f,%1.3f}",cv[6],cv[7],cv[8],cv[9])
+%D else
+%D context("{}{}{gray}{%1.3f}",cv[2])
+%D end
+%D else
+%D context("{}{}{gray}{0}")
+%D end
+%D end
+%D \stopluacode
+%D
+%D \def\pgfutil@registercolor#1%
+%D {\setevalue{\string\color@#1}{\noexpand\xcolor@\ctxcommand{pgfxcolorspec(\thecolorattribute{#1})}}}
+%D
+%D \definecolor [darkblue] [r=0,g=0,b=0.5]
+%D
+%D \starttikzpicture
+%D \fill [blue] (0,0) circle(1);
+%D \fill [darkblue] (0,0) circle(1);
+%D \stoptikzpicture
+%D \stoptyping
+%D
+%D \stopmode
+
+\def\pgf@context@registercolor#1{\setevalue{\string\color@#1}{\noexpand\xcolor@{}{}\clf_pgfxcolorspec\zerocount\thecolorattribute{#1}}}
+\def\pgf@context@registergray #1{\setevalue{\string\color@#1}{\noexpand\xcolor@{}{}\clf_pgfxcolorspec\plustwo \thecolorattribute{#1}}}
+\def\pgf@context@registerrgb #1{\setevalue{\string\color@#1}{\noexpand\xcolor@{}{}\clf_pgfxcolorspec\plusthree\thecolorattribute{#1}}}
+\def\pgf@context@registercmyk #1{\setevalue{\string\color@#1}{\noexpand\xcolor@{}{}\clf_pgfxcolorspec\plusfour \thecolorattribute{#1}}}
+
+%D \starttyping
+%D \ifdefined\pgf@context@registercolor
+%D \let\pgfutil@registercolor\pgf@context@registercolor
+%D \fi
+%D \stoptyping
+
+%D \macros
+%D {doifcolorelse, doifcolor}
+%D
+%D Switching to a color is done by means of the following command. Later on we will
+%D explain the use of palets. We define ourselves a color conditional first.
+
+\def\doifelsecolor#1%
+ {\ifcsname\??colorattribute\currentcolorprefix#1\endcsname
+ \expandafter\firstoftwoarguments
+ \orelse\ifcsname\??colorattribute#1\endcsname
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\let\doifcolorelse\doifelsecolor
+
+\def\doifcolor#1%
+ {\ifcsname\??colorattribute\currentcolorprefix#1\endcsname
+ \expandafter\firstofoneargument
+ \orelse\ifcsname\??colorattribute#1\endcsname
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+%D \macros
+%D {startregistercolor,stopregistercolor,permitcolormode}
+%D
+%D If you only want to register a color, the switch \type {\ifpermitcolormode} can
+%D be used. That way the nested colors know where to go back to.
+%D
+%D We use these macros for implementing text colors (actually, the first application
+%D was in foreground colors).
+%D
+%D \starttyping
+%D \starttextcolor[red]
+%D \dorecurse{10}{\input tufte \color[green]{oeps} \par}
+%D \stoptextcolor
+%D \stoptyping
+%D
+%D This is more efficient than the alternative:
+%D
+%D \starttyping
+%D \setupbackgrounds[text][foregroundcolor=red]
+%D \startregistercolor[red]
+%D \dorecurse{10}{\input tufte \color[green]{oeps} \par}
+%D \stopregistercolor
+%D \stoptyping
+
+\let\maintextcolor \empty
+\def\defaulttextcolor {black}
+\def\s!themaintextcolor{themaintextcolor}
+
+\unexpanded\def\inheritmaintextcolor
+ {\ifx\maintextcolor\empty\else\colo_helpers_activate\maintextcolor\fi}
+
+\unexpanded\def\onlyinheritmaintextcolor
+ {\ifx\maintextcolor\empty
+ \deactivatecolor
+ \else
+ \colo_helpers_activate\maintextcolor
+ \fi}
+
+\appendtoks
+ \deactivatecolor % public?
+ \inheritmaintextcolor
+\to \everybeforeoutput
+
+\def\colo_helpers_switch_to_maintextcolor#1%
+ {\let\maintextcolor\s!themaintextcolor
+ \definecolor[\maintextcolor][#1]% can be fast one
+ \colo_helpers_activate\maintextcolor
+ \clf_registermaintextcolor\thecolorattribute\maintextcolor\relax}
+
+\unexpanded\def\starttextcolor[#1]%
+ {\doifsomething{#1}
+ {\colo_helpers_switch_to_maintextcolor{#1}}}
+
+\let\stoptextcolor\relax
+
+\let\p_colo_textcolor\empty
+
+\def\colo_helpers_initialize_maintextcolor
+ {\edef\p_colo_textcolor{\directcolorsparameter\c!textcolor}%
+ \ifx\p_colo_textcolor\empty
+ \colo_helpers_switch_to_maintextcolor\defaulttextcolor
+ \else
+ \colo_helpers_switch_to_maintextcolor\p_colo_textcolor
+ \fi}
+
+\appendtoks \colo_helpers_initialize_maintextcolor \to \everyjob
+\appendtoks \colo_helpers_initialize_maintextcolor \to \everysetupcolors
+
+\letvalue{\??colorsetter }\empty \letvalue{\??colorattribute }\!!zerocount
+\letvalue{\??transparencysetter}\empty \letvalue{\??transparencyattribute}\!!zerocount
+
+\def\colo_helpers_inherited_direct_cs#1{\ifcsname\??colorsetter #1\endcsname\lastnamedcs\fi}
+\def\colo_helpers_inherited_direct_ca#1{\ifcsname\??colorattribute #1\endcsname\lastnamedcs\else\!!zerocount\fi}
+\def\colo_helpers_inherited_direct_ts#1{\ifcsname\??transparencysetter #1\endcsname\lastnamedcs\fi}
+\def\colo_helpers_inherited_direct_ta#1{\ifcsname\??transparencyattribute#1\endcsname\lastnamedcs\else\!!zerocount\fi}
+
+% %def\colo_helpers_inherited_palet_cs#1#2{\csname\??colorsetter \ifcsname\??colorsetter \??colorpalet#1:#2\endcsname\??colorpalet#1:#2\fi\endcsname}
+% %def\colo_helpers_inherited_palet_ca#1#2{\csname\??colorattribute \ifcsname\??colorattribute \??colorpalet#1:#2\endcsname\??colorpalet#1:#2\fi\endcsname}
+% %def\colo_helpers_inherited_palet_ts#1#2{\csname\??transparencysetter \ifcsname\??transparencysetter \??colorpalet#1:#2\endcsname\??colorpalet#1:#2\fi\endcsname}
+% %def\colo_helpers_inherited_palet_ta#1#2{\csname\??transparencyattribute\ifcsname\??transparencyattribute\??colorpalet#1:#2\endcsname\??colorpalet#1:#2\fi\endcsname}
+%
+% \def\colo_helpers_inherited_palet_cs#1#2{\ifcsname\??colorsetter \??colorpalet#1:#2\endcsname\lastnamedcs\fi}
+% \def\colo_helpers_inherited_palet_ca#1#2{\ifcsname\??colorattribute \??colorpalet#1:#2\endcsname\lastnamedcs\else\!!zerocount\fi}
+% \def\colo_helpers_inherited_palet_ts#1#2{\ifcsname\??transparencysetter \??colorpalet#1:#2\endcsname\lastnamedcs}
+% \def\colo_helpers_inherited_palet_ta#1#2{\ifcsname\??transparencyattribute\??colorpalet#1:#2\endcsname\lastnamedcs\else\!!zerocount\fi}
+
+\let\colo_helpers_set_value\setvalue
+
+\appendtoks
+ \ifconditional\c_colo_expanded
+ \let\colo_helpers_set_value\setevalue
+ \else
+ \let\colo_helpers_set_value\setvalue
+ \fi
+\to \everysetupcolors
+
+\def\colo_palets_define_set#1#2#3%
+ {\ifcondition\validassignment{#3}% \definepalet[test][xx={y=.4}]
+ \expandafter\colo_palets_define_assign
+ \orelse\ifcsname\??colorsetter#3\endcsname
+ % \definepalet[test][xx=green]
+ \expandafter\colo_palets_define_inherit
+ \else
+ % not entered when making format
+ \expandafter\colo_palets_define_undefine
+ \fi
+ {#1}{#2}{#3}}
+
+\def\colo_palets_define_inherit#1#2#3%
+ {\colo_basics_inherit{#1:#2}{#3}%
+ \colo_helpers_set_value{\??colorsetter #1:#2}{\colo_helpers_inherited_direct_cs{#3}}%
+ \colo_helpers_set_value{\??colorattribute #1:#2}{\colo_helpers_inherited_direct_ca{#3}}%
+ \colo_helpers_set_value{\??transparencysetter #1:#2}{\colo_helpers_inherited_direct_ts{#3}}%
+ \colo_helpers_set_value{\??transparencyattribute#1:#2}{\colo_helpers_inherited_direct_ta{#3}}}
+
+\def\colo_palets_define_undefine#1#2#3%
+ {\localundefine{\??colorsetter #1:#2}%
+ \localundefine{\??colorattribute #1:#2}%
+ \localundefine{\??transparencysetter #1:#2}%
+ \localundefine{\??transparencyattribute#1:#2}}
+
+\def\colo_palets_define_assign#1#2#3%
+ {\definecolor[\??colorpalet#1:#2][#3]%
+ \colo_helpers_set_value{\??colorsetter #1:#2}{\colo_helpers_inherited_direct_cs{\??colorpalet#1:#2}}%
+ \colo_helpers_set_value{\??colorattribute #1:#2}{\colo_helpers_inherited_direct_ca{\??colorpalet#1:#2}}%
+ \colo_helpers_set_value{\??transparencysetter #1:#2}{\colo_helpers_inherited_direct_ts{\??colorpalet#1:#2}}%
+ \colo_helpers_set_value{\??transparencyattribute#1:#2}{\colo_helpers_inherited_direct_ta{\??colorpalet#1:#2}}}
+
+\setvalue{\??colorattribute currentcolor}{\the\attribute\colorattribute} % for mpcolor
+\setvalue{\??transparencyattribute currentcolor}{\the\attribute\transparencyattribute} % for mpcolor
+
+%def\colo_helpers_inherited_current_ca#1{\csname\??colorattribute \ifcsname\??colorattribute \currentcolorprefix#1\endcsname\currentcolorprefix#1\else\ifcsname\??colorattribute #1\endcsname#1\fi\fi\endcsname}
+%def\colo_helpers_inherited_current_cs#1{\csname\??colorsetter \ifcsname\??colorsetter \currentcolorprefix#1\endcsname\currentcolorprefix#1\else\ifcsname\??colorsetter #1\endcsname#1\fi\fi\endcsname}
+%def\colo_helpers_inherited_current_ta#1{\csname\??transparencyattribute\ifcsname\??transparencyattribute\currentcolorprefix#1\endcsname\currentcolorprefix#1\else\ifcsname\??transparencyattribute#1\endcsname#1\fi\fi\endcsname}
+%def\colo_helpers_inherited_current_ts#1{\csname\??transparencysetter \ifcsname\??transparencysetter \currentcolorprefix#1\endcsname\currentcolorprefix#1\else\ifcsname\??transparencysetter #1\endcsname#1\fi\fi\endcsname}
+
+\def\colo_helpers_inherited_current_ca#1{\ifcsname\??colorattribute \currentcolorprefix#1\endcsname\lastnamedcs\else\ifcsname\??colorattribute #1\endcsname\lastnamedcs\else\!!zerocount\fi\fi}
+\def\colo_helpers_inherited_current_cs#1{\ifcsname\??colorsetter \currentcolorprefix#1\endcsname\lastnamedcs\else\ifcsname\??colorsetter #1\endcsname\lastnamedcs\else\fi\fi}
+\def\colo_helpers_inherited_current_ta#1{\ifcsname\??transparencyattribute\currentcolorprefix#1\endcsname\lastnamedcs\else\ifcsname\??transparencyattribute#1\endcsname\lastnamedcs\else\!!zerocount\fi\fi}
+\def\colo_helpers_inherited_current_ts#1{\ifcsname\??transparencysetter \currentcolorprefix#1\endcsname\lastnamedcs\else\ifcsname\??transparencysetter #1\endcsname\lastnamedcs\else\fi\fi}
+
+%D Low level defs:
+
+\unexpanded\def\colordefalc#1#2{\setevalue{\??colorattribute #1}{#2}\setvalue {\??colorsetter #1}{\attribute\colorattribute #2 }}
+\unexpanded\def\colordefagc#1#2{\setxvalue{\??colorattribute #1}{#2}\setgvalue{\??colorsetter #1}{\attribute\colorattribute #2 }} % was not g
+\unexpanded\def\colordefalt#1#2{\setevalue{\??transparencyattribute#1}{#2}\setvalue {\??transparencysetter#1}{\attribute\transparencyattribute#2 }}
+\unexpanded\def\colordefagt#1#2{\setxvalue{\??transparencyattribute#1}{#2}\setgvalue{\??transparencysetter#1}{\attribute\transparencyattribute#2 }}
+
+\unexpanded\def\colordefflc#1#2{\setvalue {\??colorattribute #1}{\colo_helpers_inherited_current_ca{#2}}\setvalue {\??colorsetter #1}{\colo_helpers_inherited_current_cs{#2}}}
+\unexpanded\def\colordeffgc#1#2{\setgvalue{\??colorattribute #1}{\colo_helpers_inherited_current_ca{#2}}\setvalue {\??colorsetter #1}{\colo_helpers_inherited_current_cs{#2}}}
+\unexpanded\def\colordefflt#1#2{\setvalue {\??transparencyattribute#1}{\colo_helpers_inherited_current_ta{#2}}\setvalue {\??transparencysetter#1}{\colo_helpers_inherited_current_ts{#2}}}
+\unexpanded\def\colordeffgt#1#2{\setgvalue{\??transparencyattribute#1}{\colo_helpers_inherited_current_ta{#2}}\setgvalue{\??transparencysetter#1}{\colo_helpers_inherited_current_ts{#2}}}
+
+\unexpanded\def\colordefrlc #1{\localundefine {\??colorattribute #1}\localundefine {\??colorsetter #1}}
+\unexpanded\def\colordefrgc #1{\globalundefine{\??colorattribute #1}\globalundefine{\??colorsetter #1}}
+\unexpanded\def\colordefrlt #1{\localundefine {\??transparencyattribute#1}\localundefine {\??transparencysetter#1}}
+\unexpanded\def\colordefrgt #1{\globalundefine{\??transparencyattribute#1}\globalundefine{\??transparencysetter#1}}
+
+%D \macros
+%D {colorvalue, grayvalue}
+%D
+%D We can typeset the color components using \type {\colorvalue} and \type
+%D {\grayvalue}. The commands:
+%D
+%D \startbuffer
+%D color value of SomeKindOfRed: \colorvalue{SomeKindOfRed} \crlf
+%D gray value of SomeKindOfRed: \grayvalue{SomeKindOfRed}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D show us:
+%D
+%D \startexample
+%D \getbuffer
+%D \stopexample
+
+\let\currentcolorname\s!black % todo
+\let\outercolorname \s!black % todo
+
+\let\colorformatseparator\space
+
+\def\MPcolor#1%
+ {\clf_mpcolor
+ \attribute\colormodelattribute
+ \colo_helpers_inherited_current_ca{#1} %
+ \colo_helpers_inherited_current_ta{#1} }
+
+\def\MPcoloronly#1%
+ {\clf_mpcolor
+ \attribute\colormodelattribute
+ \colo_helpers_inherited_current_ca{#1} %
+ \zerocount}
+
+\def\MPtransparency#1%
+ {\clf_mpcolor
+ \zerocount
+ \zerocount
+ \colo_helpers_inherited_current_ta{#1} }
+
+\def\MPoptions#1%
+ {\clf_mpoptions
+ \attribute\colormodelattribute
+ \colo_helpers_inherited_current_ca{#1} %
+ \colo_helpers_inherited_current_ta{#1} }
+
+\def\thecolormodelattribute {\the\attribute\colormodelattribute}
+
+%def\thecolorattribute #1{\number\csname\??colorattribute \ifcsname\??colorattribute \currentcolorprefix#1\endcsname\currentcolorprefix#1\else\ifcsname\??colorattribute #1\endcsname#1\fi\fi\endcsname}
+%def\thetransparencyattribute#1{\number\csname\??transparencyattribute\ifcsname\??transparencyattribute\currentcolorprefix#1\endcsname\currentcolorprefix#1\else\ifcsname\??transparencyattribute#1\endcsname#1\fi\fi\endcsname}
+
+\def\rawcolorattribute #1{\ifcsname\??colorattribute \currentcolorprefix#1\endcsname\lastnamedcs\orelse\ifcsname\??colorattribute #1\endcsname\lastnamedcs\else\zerocount\fi}
+\def\rawtransparencyattribute#1{\ifcsname\??transparencyattribute\currentcolorprefix#1\endcsname\lastnamedcs\orelse\ifcsname\??transparencyattribute#1\endcsname\lastnamedcs\else\zerocount\fi}
+
+\def\thecolorattribute #1{\number\ifcsname\??colorattribute \currentcolorprefix#1\endcsname\lastnamedcs\orelse\ifcsname\??colorattribute #1\endcsname\lastnamedcs\else\zerocount\fi}
+\def\thetransparencyattribute#1{\number\ifcsname\??transparencyattribute\currentcolorprefix#1\endcsname\lastnamedcs\orelse\ifcsname\??transparencyattribute#1\endcsname\lastnamedcs\else\zerocount\fi}
+\def\internalspotcolorname #1{\clf_spotcolorname \thecolorattribute{#1} }
+\def\internalspotcolorparent #1{\clf_spotcolorparent\thecolorattribute{#1} }
+\def\internalspotcolorsize #1{\clf_spotcolorvalue \thecolorattribute{#1} }
+
+\def\colorcomponents #1{\clf_colorcomponents \thecolorattribute {#1} }
+\def\transparencycomponents #1{\clf_transparencycomponents\thetransparencyattribute{#1} }
+\def\processcolorcomponents #1{\clf_processcolorcomponents\thecolorattribute {#1} }
+
+\def\colorvalue #1{\clf_formatcolor\thecolorattribute{#1}{\colorformatseparator}}
+\def\grayvalue #1{\clf_formatgray \thecolorattribute{#1}{\colorformatseparator}}
+
+\def\doifelseblack #1{\clf_doifelseblack\thecolorattribute{#1} }
+\def\doifelsedrawingblack {\clf_doifelsedrawingblack}
+
+\let\doifblackelse \doifelseblack
+\let\doifdrawingblackelse \doifelsedrawingblack
+
+\let\doifblackelse \doifelseblack
+\let\doifdrawingblackelse\doifelsedrawingblack
+
+%D \macros
+%D {forcecolorhack}
+%D
+%D We can out this in front of (for instance) a special and so force color to be
+%D applied (only glyphs, rules and leaders are handled).
+%D
+%D \startbuffer
+%D \framed
+%D [background=color,backgroundcolor=yellow,framecolor=red,corner=round]
+%D {test}
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+% ignores in attribute handler
+%
+% \def\forcecolorhack{\vrule\s!width\zeropoint\s!height\zeropoint\s!depth\zeropoint}
+
+% \normal added else fails in metafun manual (leaders do a hard scan)
+
+\unexpanded\def\forcecolorhack{\leaders\hrule\hskip\zeropoint\relax} % relax is needed !
+
+%D We default to the colors defined in \type {colo-imp-rgb} and
+%D support both \RGB\ and \CMYK\ output. Transparencies are defined
+%D here:
+
+\definecolor[black][s=0]
+\definecolor[white][s=1]
+
+\definetransparency [none] [0]
+\definetransparency [normal] [1]
+\definetransparency [multiply] [2]
+\definetransparency [screen] [3]
+\definetransparency [overlay] [4]
+\definetransparency [softlight] [5]
+\definetransparency [hardlight] [6]
+\definetransparency [colordodge] [7]
+\definetransparency [colorburn] [8]
+\definetransparency [darken] [9]
+\definetransparency [lighten] [10]
+\definetransparency [difference] [11]
+\definetransparency [exclusion] [12]
+\definetransparency [hue] [13]
+\definetransparency [saturation] [14]
+\definetransparency [color] [15]
+\definetransparency [luminosity] [16]
+
+%D Some common ones:
+
+\definecolor[trace:0][s=.4]
+\definecolor[trace:1][r=.6]
+\definecolor[trace:2][g=.6]
+\definecolor[trace:3][b=.6]
+\definecolor[trace:4][r=.6,g=.6]
+\definecolor[trace:5][r=.6,b=.6]
+\definecolor[trace:6][g=.6,b=.6]
+\definecolor[trace:7][r=.8,g=.4]
+\definecolor[trace:8][r=.8,b=.4]
+\definecolor[trace:9][g=.4,b=.8]
+
+\definecolor[trace:w][s=1]
+\definecolor[trace:r][r=.75,t=.5,a=1]
+\definecolor[trace:g][g=.75,t=.5,a=1]
+\definecolor[trace:b][b=.75,t=.5,a=1]
+%definecolor[trace:c][c=.75,t=.5,a=1]
+%definecolor[trace:m][m=.75,t=.5,a=1]
+%definecolor[trace:y][y=.75,t=.5,a=1]
+\definecolor[trace:c][g=.75,b=.75,t=.5,a=1]
+\definecolor[trace:m][r=.75,b=.75,t=.5,a=1]
+\definecolor[trace:y][r=.75,g=.75,t=.5,a=1]
+\definecolor[trace:s][s=.75,t=.5,a=1]
+\definecolor[trace:d][s=.25,t=.5,a=1]
+\definecolor[trace:o][r=1,g=.6,b=.1,t=.5,a=1]
+
+\definecolor[trace:dw][s=1]
+\definecolor[trace:dr][r=.75,t=.75,a=1]
+\definecolor[trace:dg][g=.75,t=.75,a=1]
+\definecolor[trace:db][b=.75,t=.75,a=1]
+%definecolor[trace:dc][c=.75,t=.75,a=1]
+%definecolor[trace:dm][m=.75,t=.75,a=1]
+%definecolor[trace:dy][y=.75,t=.75,a=1]
+\definecolor[trace:dc][g=.75,b=.75,t=.75,a=1]
+\definecolor[trace:dm][r=.75,b=.75,t=.75,a=1]
+\definecolor[trace:dy][r=.75,g=.75,t=.75,a=1]
+\definecolor[trace:ds][s=.75,t=.75,a=1]
+\definecolor[trace:dd][s=.25,t=.75,a=1]
+\definecolor[trace:do][r=1,g=.6,b=.1,t=.75,a=1]
+
+\setupcolors
+ [\c!state=\v!stop, % color will be enabled later on
+ \c!conversion=\v!yes,
+ \c!rgb=\v!yes,
+ \c!cmyk=\v!yes,
+ \c!spot=\v!yes,
+ \c!pagecolormodel=\v!none,
+ \c!expansion=\v!no,
+ \c!textcolor=,
+ \c!factor=\v!yes]
+
+\setupcolor
+ [\v!rgb]
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/cont-cs.mkxl b/Master/texmf-dist/tex/context/base/mkiv/cont-cs.mkxl
new file mode 100644
index 00000000000..8e5ae567cc4
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/cont-cs.mkxl
@@ -0,0 +1,21 @@
+%D \module
+%D [ file=cont-cs,
+%D version=1998.12.02,
+%D title=\CONTEXT,
+%D subtitle=\CONTEXT\ Czech Format Generation,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\catcode`\{=1 \catcode`\}=2
+
+\def\defaultinterface {czech}
+\def\defaultlanguagetag{cs}
+
+\input context.mkxl
+
+\endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/cont-de.mkxl b/Master/texmf-dist/tex/context/base/mkiv/cont-de.mkxl
new file mode 100644
index 00000000000..579cc88c3c3
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/cont-de.mkxl
@@ -0,0 +1,21 @@
+%D \module
+%D [ file=cont-de,
+%D version=1997.08.19,
+%D title=\CONTEXT,
+%D subtitle=\CONTEXT\ German Format Generation,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\catcode`\{=1 \catcode`\}=2
+
+\def\defaultinterface {german}
+\def\defaultlanguagetag{de}
+
+\input context.mkxl
+
+\endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/cont-en.mkxl b/Master/texmf-dist/tex/context/base/mkiv/cont-en.mkxl
new file mode 100644
index 00000000000..bfb17ffb3c2
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/cont-en.mkxl
@@ -0,0 +1,21 @@
+%D \module
+%D [ file=cont-en,
+%D version=1997.08.19,
+%D title=\CONTEXT,
+%D subtitle=\CONTEXT\ English Format Generation,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\catcode`\{=1 \catcode`\}=2
+
+\def\defaultinterface {english}
+\def\defaultlanguagetag{en}
+
+\input context.mkxl
+
+\endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/cont-fil.mkiv b/Master/texmf-dist/tex/context/base/mkiv/cont-fil.mkiv
index 9257e2e1ed6..aa7d9ddb314 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/cont-fil.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/cont-fil.mkiv
@@ -16,137 +16,142 @@
\writestatus{loading}{ConTeXt File Synonyms}
-\definefilesynonym [chemics] [chemic]
-
-\definefilesynonym [unit] [units]
-
-\definefilesynonym [pstric] [pstricks]
-\definefilesynonym [pstrick] [pstricks]
-
-\definefilesynonym [finance] [financ]
-
-\definefilesynonym [dir-make] [dir-01]
-\definefilesynonym [dir-identify] [dir-05]
-
-\definefilesynonym [int-load] [set-11]
-\definefilesynonym [int-make] [set-12]
-
- \definefilesynonym [fig-base] [fig-00]
- \definefilesynonym [fig-make] [fig-01]
- \definefilesynonym [fig-fake] [fig-02]
- \definefilesynonym [fig-missing] [fig-06]
-
-\definefilesynonym [exi-interface] [exi-21]
-
- \definefilesynonym [res-make] [res-01]
- \definefilesynonym [res-base] [res-04]
- \definefilesynonym [res-crop] [res-07]
- \definefilesynonym [res-trace] [res-08]
- \definefilesynonym [res-log] [res-09]
- \definefilesynonym [res-identify] [res-12]
-
- \definefilesynonym [med-show] [res-50]
-
-\definefilesynonym [pre-general] [pre-00]
-\definefilesynonym [pre-01] [present-original]
-\definefilesynonym [pre-original] [present-original]
-\definefilesynonym [pre-02] [present-green]
-\definefilesynonym [pre-green] [present-green]
-\definefilesynonym [pre-03] [present-funny]
-\definefilesynonym [pre-funny] [present-funny]
-\definefilesynonym [pre-04] [present-colorful]
-\definefilesynonym [pre-colorful] [present-colorful]
-\definefilesynonym [pre-05] [present-fuzzy]
-\definefilesynonym [pre-fuzzy] [present-fuzzy]
-\definefilesynonym [pre-polish] [pre-06]
-\definefilesynonym [pre-spider] [pre-07]
-\definefilesynonym [pre-wonder] [pre-08]
-\definefilesynonym [pre-09] [present-windows]
-\definefilesynonym [pre-windows] [present-windows]
-\definefilesynonym [pre-10] [present-grow]
-\definefilesynonym [pre-grow] [present-grow]
-\definefilesynonym [pre-11] [present-stack]
-\definefilesynonym [pre-stack] [present-stack]
-\definefilesynonym [pre-arrows] [pre-12]
-\definefilesynonym [pre-writing] [pre-13]
-\definefilesynonym [pre-split] [present-split]
-\definefilesynonym [pre-14] [present-split]
-\definefilesynonym [pre-balls] [present-balls]
-\definefilesynonym [pre-15] [present-balls]
-\definefilesynonym [pre-knot] [pre-16]
-\definefilesynonym [pre-17] [present-weird]
-\definefilesynonym [pre-weird] [present-weird]
-\definefilesynonym [pre-shade] [pre-18]
-\definefilesynonym [pre-organic] [pre-19]
-\definefilesynonym [pre-speckle] [pre-20]
-\definefilesynonym [pre-zoom] [pre-21]
-\definefilesynonym [pre-cycle] [pre-22]
-\definefilesynonym [pre-super] [pre-23]
-%definefilesynonym [pre-more] [pre-24]
-%definefilesynonym [pre-more] [pre-25]
-\definefilesynonym [pre-more] [pre-26]
-%definefilesynonym [pre-more] [pre-27]
-%definefilesynonym [pre-more] [pre-28]
-%definefilesynonym [pre-more] [pre-29]
-%definefilesynonym [pre-more] [pre-30]
-\definefilesynonym [pre-41] [present-tiles]
-\definefilesynonym [pre-60] [present-stepwise]
-\definefilesynonym [pre-stepwise] [present-stepwise]
-\definefilesynonym [pre-61] [present-stepper]
-\definefilesynonym [pre-stepper] [present-stepper]
-\definefilesynonym [pre-62] [present-overlap]
-\definefilesynonym [pre-69] [present-wobbling]
-\definefilesynonym [pre-punk] [present-punk]
-\definefilesynonym [pre-70] [present-punk]
-\definefilesynonym [pre-random] [present-random]
-\definefilesynonym [pre-71] [present-random]
-
-\definefilesynonym [abr-01] [abbreviations-pseudocaps]
-\definefilesynonym [abr-02] [abbreviations-smallcaps]
-\definefilesynonym [abr-03] [abbreviations-words]
-\definefilesynonym [abr-04] [abbreviations-mixed]
-
-\definefilesynonym [art-01] [article-basic]
-\definefilesynonym [article] [article-basic]
-\definefilesynonym [mag-01] [magazine-basic]
-\definefilesynonym [magazine] [magazine-basic]
-\definefilesynonym [mod-01] [module-basic]
-\definefilesynonym [module] [module-basic]
-
-\definefilesynonym [map-10] [maps] % for a while
-
-\definefilesynonym [mml] [mathml]
-\definefilesynonym [cml] [chemml]
-
-\definefilesynonym [letter] [cor-01]
-\definefilesynonym [memo] [cor-02]
-\definefilesynonym [resume] [cor-03]
-
-\definefilesynonym [fnt-10] [fonts-complete]
-\definefilesynonym [fnt-11] [fonts-system]
-\definefilesynonym [fnt-20] [fonts-steps]
-\definefilesynonym [fnt-21] [fonts-steps]
-\definefilesynonym [fnt-22] [fonts-engines]
-\definefilesynonym [fnt-23] [fonts-shapes]
-\definefilesynonym [fnt-24] [fonts-cjk]
-\definefilesynonym [fnt-25] [math-characters]
-\definefilesynonym [fnt-28] [fonts-goodies]
-\definefilesynonym [fnt-29] [fonts-shapes]
-\definefilesynonym [fnt-31] [fonts-coverage]
-\definefilesynonym [fnt-33] [math-coverage]
-
-\definefilesynonym [mat-10] [math-characters]
-\definefilesynonym [mat-11] [math-characters]
-\definefilesynonym [mat-12] [math-parameters]
-\definefilesynonym [mat-20] [math-parameters]
-
-\definefilesynonym [syn-01] [syntax]
-
-\definefilesynonym [reg-01] [regimes-list]
-
-\definefilesynonym [set-11] [setups-basics]
-\definefilesynonym [set-12] [setups-overview]
-%definefilesynonym [set-13] [setups-proofing]
-%definefilesynonym [set-15] [setups-generate]
+\definefilesynonym [chemics] [chemic]
+
+\definefilesynonym [unit] [units]
+
+\definefilesynonym [pstric] [pstricks]
+\definefilesynonym [pstrick] [pstricks]
+
+\definefilesynonym [finance] [financ]
+
+\definefilesynonym [dir-make] [dir-01]
+\definefilesynonym [dir-identify] [dir-05]
+
+\definefilesynonym [int-load] [set-11]
+\definefilesynonym [int-make] [set-12]
+
+ \definefilesynonym [fig-base] [fig-00]
+ \definefilesynonym [fig-make] [fig-01]
+ \definefilesynonym [fig-fake] [fig-02]
+ \definefilesynonym [fig-missing] [fig-06]
+
+ \definefilesynonym [exi-interface] [exi-21]
+
+ \definefilesynonym [res-make] [res-01]
+ \definefilesynonym [res-base] [res-04]
+ \definefilesynonym [res-crop] [res-07]
+ \definefilesynonym [res-trace] [res-08]
+ \definefilesynonym [res-log] [res-09]
+ \definefilesynonym [res-identify] [res-12]
+
+ \definefilesynonym [med-show] [res-50]
+
+\definefilesynonym [pre-general] [pre-00]
+\definefilesynonym [pre-01] [present-original]
+\definefilesynonym [pre-original] [present-original]
+\definefilesynonym [pre-02] [present-green]
+\definefilesynonym [pre-green] [present-green]
+\definefilesynonym [pre-03] [present-funny]
+\definefilesynonym [pre-funny] [present-funny]
+\definefilesynonym [pre-04] [present-colorful]
+\definefilesynonym [pre-colorful] [present-colorful]
+\definefilesynonym [pre-05] [present-fuzzy]
+\definefilesynonym [pre-fuzzy] [present-fuzzy]
+\definefilesynonym [pre-polish] [pre-06]
+\definefilesynonym [pre-spider] [pre-07]
+\definefilesynonym [pre-wonder] [pre-08]
+\definefilesynonym [pre-09] [present-windows]
+\definefilesynonym [pre-windows] [present-windows]
+\definefilesynonym [pre-10] [present-grow]
+\definefilesynonym [pre-grow] [present-grow]
+\definefilesynonym [pre-11] [present-stack]
+\definefilesynonym [pre-stack] [present-stack]
+\definefilesynonym [pre-arrows] [pre-12]
+\definefilesynonym [pre-writing] [pre-13]
+\definefilesynonym [pre-split] [present-split]
+\definefilesynonym [pre-14] [present-split]
+\definefilesynonym [pre-balls] [present-balls]
+\definefilesynonym [pre-15] [present-balls]
+\definefilesynonym [pre-knot] [pre-16]
+\definefilesynonym [pre-17] [present-weird]
+\definefilesynonym [pre-weird] [present-weird]
+\definefilesynonym [pre-shade] [pre-18]
+\definefilesynonym [pre-organic] [pre-19]
+\definefilesynonym [pre-speckle] [pre-20]
+\definefilesynonym [pre-zoom] [pre-21]
+\definefilesynonym [pre-cycle] [pre-22]
+\definefilesynonym [pre-super] [pre-23]
+%definefilesynonym [pre-more] [pre-24]
+%definefilesynonym [pre-more] [pre-25]
+\definefilesynonym [pre-more] [pre-26]
+%definefilesynonym [pre-more] [pre-27]
+%definefilesynonym [pre-more] [pre-28]
+%definefilesynonym [pre-more] [pre-29]
+%definefilesynonym [pre-more] [pre-30]
+\definefilesynonym [pre-41] [present-tiles]
+\definefilesynonym [pre-60] [present-stepwise]
+\definefilesynonym [pre-stepwise] [present-stepwise]
+\definefilesynonym [pre-61] [present-stepper]
+\definefilesynonym [pre-stepper] [present-stepper]
+\definefilesynonym [pre-62] [present-overlap]
+\definefilesynonym [pre-69] [present-wobbling]
+\definefilesynonym [pre-punk] [present-punk]
+\definefilesynonym [pre-70] [present-punk]
+\definefilesynonym [pre-random] [present-random]
+\definefilesynonym [pre-71] [present-random]
+
+\definefilesynonym [abr-01] [abbreviations-pseudocaps]
+\definefilesynonym [abr-02] [abbreviations-smallcaps]
+\definefilesynonym [abr-03] [abbreviations-words]
+\definefilesynonym [abr-04] [abbreviations-mixed]
+
+\definefilesynonym [art-01] [article-basic]
+\definefilesynonym [article] [article-basic]
+\definefilesynonym [mag-01] [magazine-basic]
+\definefilesynonym [magazine] [magazine-basic]
+\definefilesynonym [mod-01] [module-basic]
+\definefilesynonym [module] [module-basic]
+
+\definefilesynonym [map-10] [maps] % for a while
+
+\definefilesynonym [mml] [mathml]
+\definefilesynonym [cml] [chemml]
+
+\definefilesynonym [letter] [cor-01]
+\definefilesynonym [memo] [cor-02]
+\definefilesynonym [resume] [cor-03]
+
+\definefilesynonym [fnt-10] [fonts-complete]
+\definefilesynonym [fnt-11] [fonts-system]
+\definefilesynonym [fnt-20] [fonts-steps]
+\definefilesynonym [fnt-21] [fonts-steps]
+\definefilesynonym [fnt-22] [fonts-engines]
+\definefilesynonym [fnt-23] [fonts-shapes]
+\definefilesynonym [fnt-24] [fonts-cjk]
+\definefilesynonym [fnt-25] [math-characters]
+\definefilesynonym [fnt-28] [fonts-goodies]
+\definefilesynonym [fnt-29] [fonts-shapes]
+\definefilesynonym [fnt-31] [fonts-coverage]
+\definefilesynonym [fnt-33] [math-coverage]
+
+\definefilesynonym [mat-10] [math-characters]
+\definefilesynonym [mat-11] [math-characters]
+\definefilesynonym [mat-12] [math-parameters]
+\definefilesynonym [mat-20] [math-parameters]
+
+\definefilesynonym [syn-01] [syntax]
+
+\definefilesynonym [reg-01] [regimes-list]
+
+\definefilesynonym [set-11] [setups-basics]
+\definefilesynonym [set-12] [setups-overview]
+%definefilesynonym [set-13] [setups-proofing]
+%definefilesynonym [set-15] [setups-generate]
+
+\ifcase\contextlmtxmode \else
+ \definefilesynonym [ecmascript] [libs-imp-mujs]
+ \definefilesynonym [zint] [libs-imp-zint]
+\fi
\endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/cont-fr.mkxl b/Master/texmf-dist/tex/context/base/mkiv/cont-fr.mkxl
new file mode 100644
index 00000000000..bedae536b66
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/cont-fr.mkxl
@@ -0,0 +1,21 @@
+%D \module
+%D [ file=cont-de,
+%D version=1997.08.19,
+%D title=\CONTEXT,
+%D subtitle=\CONTEXT\ French Format Generation,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\catcode`\{=1 \catcode`\}=2
+
+\def\defaultinterface {french}
+\def\defaultlanguagetag{fr}
+
+\input context.mkxl
+
+\endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/cont-gb.mkxl b/Master/texmf-dist/tex/context/base/mkiv/cont-gb.mkxl
new file mode 100644
index 00000000000..464b237da87
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/cont-gb.mkxl
@@ -0,0 +1,21 @@
+%D \module
+%D [ file=cont-uk,
+%D version=1997.08.19,
+%D title=\CONTEXT,
+%D subtitle=\CONTEXT\ English Format Generation,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\catcode`\{=1 \catcode`\}=2
+
+\def\defaultinterface {english}
+\def\defaultlanguagetag{gb}
+
+\input context.mkxl
+
+\endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/cont-it.mkxl b/Master/texmf-dist/tex/context/base/mkiv/cont-it.mkxl
new file mode 100644
index 00000000000..1702a872fa4
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/cont-it.mkxl
@@ -0,0 +1,21 @@
+%D \module
+%D [ file=cont-it,
+%D version=1997.08.19,
+%D title=\CONTEXT,
+%D subtitle=\CONTEXT\ Italian Format Generation,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\catcode`\{=1 \catcode`\}=2
+
+\def\defaultinterface {italian}
+\def\defaultlanguagetag{it}
+
+\input context.mkxl
+
+\endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/cont-log.mkiv b/Master/texmf-dist/tex/context/base/mkiv/cont-log.mkiv
index f9fc6a8f765..75d87eb81d9 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/cont-log.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/cont-log.mkiv
@@ -52,7 +52,7 @@
\begingroup
\setbox\scratchbox\hbox{L}%
\scratchdimen\ht\scratchbox
- \setbox\scratchbox\hbox{\txx A}%
+ \setbox\scratchbox\hbox{\doresetattribute{case}\txx A}%
L\kern-.55\wd\scratchbox
\raise\scratchdimen\hbox{\lower\ht\scratchbox\copy\scratchbox}%
\kern-.2\wd\scratchbox\TeX
@@ -198,14 +198,14 @@
%D Some placeholders:
-\unexpanded\def\eTeX {\mathematics{\varepsilon}-\TeX}
-\unexpanded\def\pdfTeX {pdf\wordboundary\TeX}
-\unexpanded\def\pdfeTeX {pdfe-\wordboundary\TeX}
-\unexpanded\def\luaTeX {lua\wordboundary\TeX}
-\unexpanded\def\Lua {Lua}
-\unexpanded\def\luajitTeX{luajit\wordboundary\TeX}
-\unexpanded\def\metaTeX {meta\wordboundary\TeX}
-%unexpanded\def\XeTeX {X\lower.5\exheight\hbox{\kern-.15\emwidth\mirror{E}}\kern-.1667\emwidth\TeX}
+\unexpanded\def\eTeX {\mathematics{\varepsilon}-\TeX}
+\unexpanded\def\pdfTeX {pdf\wordboundary\TeX}
+\unexpanded\def\pdfeTeX {pdfe-\wordboundary\TeX}
+\unexpanded\def\luaTeX {lua\wordboundary\TeX}
+\unexpanded\def\Lua {Lua}
+\unexpanded\def\luajitTeX {lua\wordboundary jit\wordboundary\TeX}
+\unexpanded\def\luametaTeX{lua\wordboundary meta\wordboundary\TeX}
+%unexpanded\def\XeTeX {X\lower.5\exheight\hbox{\kern-.15\emwidth\mirror{E}}\kern-.1667\emwidth\TeX}
% Adapted from a patch by Mojca:
@@ -229,13 +229,15 @@
\fi}%
\kern-.1667\emwidth\TeX}
-\let\ETEX \eTeX
-\let\PDFTEX \pdfTeX
-\let\PDFETEX \pdfeTeX
-\let\LUATEX \luaTeX
-\let\LUAJITTEX\luajitTeX
-\let\LuaTeX \luaTeX
-\let\XETEX \XeTeX
+\let\ETEX \eTeX
+\let\PDFTEX \pdfTeX
+\let\PDFETEX \pdfeTeX
+\let\LUATEX \luaTeX
+\let\LUAJITTEX \luajitTeX
+\let\LuaTeX \luaTeX
+\let\LuaMetaTeX\luametaTeX
+\let\LUAMETATEX\luametaTeX
+\let\XETEX \XeTeX
\unexpanded\def\LuaTeX
{\dontleavehmode
@@ -273,28 +275,33 @@
\let\LUATEX \LuaTeX
\let\LUAJITTEX\LuajitTeX
-\unexpanded\def\MKII{MkII}
-\unexpanded\def\MKIV{MkIV}
-\unexpanded\def\MKVI{MkVI}
-\unexpanded\def\MKIX{MkIX}
-\unexpanded\def\MKXI{MkXI}
+\unexpanded\def\MKII{MkII} % MarkTwo
+\unexpanded\def\MKIV{MkIV} % MarkFour : MKIV
+\unexpanded\def\MKVI{MkVI} % MarkSix : MKIV
+\unexpanded\def\MKXL{MkXL} % MarkFourty : LMTX
+\unexpanded\def\MKLX{MkLX} % MarkSixty : LMTX
+\unexpanded\def\MKIX{MkIX} % : MKIV / LMTX
+\unexpanded\def\MKXI{MkXI} % : MKIV / LMTX
-\unexpanded\def\MPII{MpII}
-\unexpanded\def\MPIV{MpIV}
-\unexpanded\def\MPVI{MpVI}
+\unexpanded\def\MPII{MpII} % MarkTwo
+\unexpanded\def\MPIV{MpIV} % MarkFour : MetaFun
+\unexpanded\def\MPVI{MpVI} % MarkSix : MetaFun
+\unexpanded\def\MPXL{MpXL} % MarkFourty : LuaMetaFun
+\unexpanded\def\MPLX{MpLX} % MarkSixty : LuaMetaFun
-\unexpanded\def\LMTX{lmtx}
+\unexpanded\def\LMTX{lmtx} % for LuaMetaTeX
\appendtoks
- \def\ConTeXt {ConTeXt}%
- \def\MetaPost {MetaPost}%
- \def\MetaFont {MetaFont}%
- \def\MetaFun {MetaFun}%
- \def\TeX {TeX}%
- \def\TeXsuffix{TeX}%
- \def\TeXprefix{TeX}%
- \def\LuaTeX {LuaTeX}%
- \def\LuajitTeX{LuajitTeX}%
+ \def\ConTeXt {ConTeXt}%
+ \def\MetaPost {MetaPost}%
+ \def\MetaFont {MetaFont}%
+ \def\MetaFun {MetaFun}%
+ \def\TeX {TeX}%
+ \def\TeXsuffix {TeX}%
+ \def\TeXprefix {TeX}%
+ \def\LuaTeX {LuaTeX}%
+ \def\LuajitTeX {LuajitTeX}%
+ \def\LuaMetaTeX{LuaMetaTeX}%
\let\wordboundary\empty
\to \everysimplifycommands
diff --git a/Master/texmf-dist/tex/context/base/mkiv/cont-new.mkiv b/Master/texmf-dist/tex/context/base/mkiv/cont-new.mkiv
index f7581465258..97d5d207165 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/cont-new.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/cont-new.mkiv
@@ -11,7 +11,9 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\newcontextversion{2019.03.21 21:39}
+% \normalend % uncomment this to get the real base runtime
+
+\newcontextversion{2020.02.17 12:06}
%D This file is loaded at runtime, thereby providing an excellent place for
%D hacks, patches, extensions and new features.
diff --git a/Master/texmf-dist/tex/context/base/mkiv/cont-nl.mkxl b/Master/texmf-dist/tex/context/base/mkiv/cont-nl.mkxl
new file mode 100644
index 00000000000..1f00e7e892f
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/cont-nl.mkxl
@@ -0,0 +1,21 @@
+%D \module
+%D [ file=cont-nl,
+%D version=1997.08.19,
+%D title=\CONTEXT,
+%D subtitle=\CONTEXT\ Dutch Format Generation,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\catcode`\{=1 \catcode`\}=2
+
+\def\defaultinterface {dutch}
+\def\defaultlanguagetag{nl}
+
+\input context.mkxl
+
+\endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/cont-pe.mkxl b/Master/texmf-dist/tex/context/base/mkiv/cont-pe.mkxl
new file mode 100644
index 00000000000..82bf7372195
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/cont-pe.mkxl
@@ -0,0 +1,22 @@
+%D \module
+%D [ file=cont-en,
+%D version=1997.08.19,
+%D title=\CONTEXT,
+%D subtitle=\CONTEXT\ English Format Generation,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\catcode`\{=1 \catcode`\}=2
+
+\def\defaultinterface {persian}
+\def\messageinterface {english}
+\def\defaultlanguagetag{pe}
+
+\input context.mkxl
+
+\endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/cont-ro.mkxl b/Master/texmf-dist/tex/context/base/mkiv/cont-ro.mkxl
new file mode 100644
index 00000000000..6d636c7dc87
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/cont-ro.mkxl
@@ -0,0 +1,21 @@
+%D \module
+%D [ file=cont-ro,
+%D version=2000.01.09,
+%D title=\CONTEXT,
+%D subtitle=\CONTEXT\ Romanian Format Generation,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\catcode`\{=1 \catcode`\}=2
+
+\def\defaultinterface {romanian}
+\def\defaultlanguagetag{ro}
+
+\input context.mkxl
+
+\endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/cont-run.lua b/Master/texmf-dist/tex/context/base/mkiv/cont-run.lua
index 2634654fe77..9a2b3db965c 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/cont-run.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/cont-run.lua
@@ -166,10 +166,7 @@ if sandboxing then
-- We block some potential escapes from protection.
- context [[
- \let\primitive \relax
- \let\normalprimitive\relax
- ]]
+ context [[\let\primitive\relax\let\normalprimitive\relax]]
debug = {
traceback = traceback,
diff --git a/Master/texmf-dist/tex/context/base/mkiv/context-error.lmx b/Master/texmf-dist/tex/context/base/mkiv/context-error.lmx
index b82b552f88f..d1a758b050a 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/context-error.lmx
+++ b/Master/texmf-dist/tex/context/base/mkiv/context-error.lmx
@@ -46,7 +46,7 @@
</table>
<br/>
<pre>
- <?lua pv('errorcontext')?>
+<?lua pv('errorcontext')?>
</pre>
</div></div>
<div id="bottom"><div id="bottom-one"><div id="bottom-two">
diff --git a/Master/texmf-dist/tex/context/base/mkiv/context-lmtx-error.pdf b/Master/texmf-dist/tex/context/base/mkiv/context-lmtx-error.pdf
new file mode 100644
index 00000000000..0455781a396
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/context-lmtx-error.pdf
Binary files differ
diff --git a/Master/texmf-dist/tex/context/base/mkiv/context-lmtx-error.tex b/Master/texmf-dist/tex/context/base/mkiv/context-lmtx-error.tex
new file mode 100644
index 00000000000..25020cb59fb
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/context-lmtx-error.tex
@@ -0,0 +1,8 @@
+\startTEXpage[offset=overlay,toffset=.5pt,boffset=.5pt,background=color,backgroundcolor=gray]
+ \definedfont[LMTypewriterVarWd-Regular]%
+ \darkred e%
+ \darkgreen r%
+ \darkblue r%
+ \darkyellow o%
+ \darkgray r%
+\stopTEXpage
diff --git a/Master/texmf-dist/tex/context/base/mkiv/context-todo.tex b/Master/texmf-dist/tex/context/base/mkiv/context-todo.tex
index a356d596423..6aa5bca08a8 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/context-todo.tex
+++ b/Master/texmf-dist/tex/context/base/mkiv/context-todo.tex
@@ -70,16 +70,18 @@
draw d withcolor "ColorTwo" withpen pencircle scaled (o - 5) ;
draw l withcolor white withpen pencircle scaled (o / 5) ;
draw l withcolor "ColorTwo" withpen pencircle scaled (o /10) ;
- draw thelabel.ulft(t xsized .5PaperWidth,lrcorner Page shifted - (PaperWidth/20,-PaperWidth/40)) ;
+ draw thelabel.ulft((t xsized .5PaperWidth),lrcorner Page shifted - (PaperWidth/20,-PaperWidth/40)) ;
StopPage ;
\stopMPpage
-
\startsubject[title={Introduction}]
-There is not really a long term roadmap for development. One reason is that there is already
-a lot available. When we started with \LUATEX, the \CONTEXT\ code was mostly rewritten,
-and that process is more of less finished. Of course there is always work left.
+There is not really a long term roadmap for development. One reason is that there
+is already a lot available. When we started with \LUATEX, the \CONTEXT\ code was
+mostly rewritten from \MKII\ to \MKIV, and that process is more of less finished.
+Of course there is always work left. We have moved on to \LUAMETATEX\ and \LMTX\
+as follow up on \MKIV. Deep down some things might (and will) change but the user
+interface will stay the same (as usual).
This file is not a complete overview of our plans but users can at least get an
idea of what we're working on and what is coming. Feel free to submit
@@ -93,35 +95,32 @@ Hasselt NL
\stopsubject
-\startsubject[title={On the agenda for \LUATEX}]
+\startsubject[title={On the agenda for \LUAMETATEX}]
+
+The agenda for \LUATEX\ is basically empty as this program is (supposed to be)
+frozen, but for \LUAMETATEX\ we can still consider improvements. In fact, there
+are quite some changes between the engines already (internally). Items that
+concern \LUATEX\ have been removed from the agenda but some improvements in
+\LUAMETATEX\ might trickle back.
\startitemize
\startitem
- cleanup passive nodes
- \stopitem
- \startitem
- optimize some callback resolution (more direct)
+ cleanup passive nodes in the par builder
\stopitem
\startitem
- add \type {--output-filename} for \PDF\ filename
+ optimize some callback resolution (more direct) but there is not that
+ much to gain there
\stopitem
\startitem
- more consistent \type {lang_variables} and \type {tex_language} in \type
- {texlang.w} and also store the \type {*mins}
+ remove local par in head of line when done with linebreak and maybe also
+ ensure leftskip and rightskip
\stopitem
\startitem
- remove local par in head of line when done with linebreak
+ only return nil in lua helpers when we expect multiple calls in in one
+ line
\stopitem
\startitem
- check why leftskip doesn't always inherit attributes (maybe dir notes don't have them)
- (also check redundant \type {delete_attribute_ref} after \type {new_glue})
- \stopitem
- \startitem
- only return nil when we expect multiple calls in in one line
- \stopitem
- \startitem
- pdf injection in virtual characters (currently qQ interferes with font switch
- flushing) so a pdf page hack is needed
+ experiment a bit more with the new protrusion code
\stopitem
\stopitemize
@@ -140,7 +139,7 @@ Hasselt NL
add flag to font for math engine
\stopitem
\startitem
- get rid of components
+ get rid of components in glyph nodes
\stopitem
\startitem
play with box attributes
@@ -150,15 +149,24 @@ Hasselt NL
styles, properties)
\stopitem
\startitem
+ freeze actions and tasks (by name or function), maybe a register
+ function that does that so no one can overload built-in features
+ \startitem
redo some of the spacing (adapt to improvements in engine)
\stopitem
\startitem
- reorganize position data (more subtables)
+ more node and code injections
+ \stopitem
+ \startitem
+ maybe reorganize position data (more subtables)
\stopitem
\startitem
use \type {\matheqnogapstep}, \type {\Ustack}, \type {\mathscriptsmode},
\type {\mathdisplayskipmode} and other new math primitives
\stopitem
+ \startitem
+ cleanup some lua helpers (io.exists vs lfs.isfile)
+ \stopitem
\stopitemize
\stopsubject
diff --git a/Master/texmf-dist/tex/context/base/mkiv/context.mkiv b/Master/texmf-dist/tex/context/base/mkiv/context.mkiv
index 4059a29759b..9cdb78c47e7 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/context.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/context.mkiv
@@ -18,31 +18,34 @@
% 0.2 sec : format dumped
% 0.2 sec : char-def/char-ini (no bytecode)
%
-% So a format still saves some 1.5 seconds (with luajjitex) startup and
-% on network shares cq. when no files are cached by the os it's of course
-% much worse. A zero run is .27 sec with luajittex.
+%D So a format still saves some 1.5 seconds (with luajjitex) startup and on network
+%D shares cq. when no files are cached by the os it's of course much worse. A zero
+%D run is .27 sec with luajittex. In luametatex it's faster anyway (2.4 sec).
-% http://build.contextgarden.net/waterfall?tag=c/luatex
+%D The real minimal startup time can be measured by uncommenting \type {\normalend}
+%D in the \type {cont-new.mkiv} file. When we subtract .250 for \LUA\ initialization
+%D from 0.300 runtime and also subtract some 0.030 for the resolver, we get about
+%D 0.020 for format loading which is pretty fast. We're talking \LUAMETATEX\ here.
-% Welcome to context, pronounced as kontekst (rather dutch) and not as
-% conτεχt.
+% http://build.contextgarden.net/waterfall?tag=c/lua(meta)tex
+
+%D Welcome to context, pronounced as kontekst (rather dutch) and not as conτεχt.
\catcode`\{=1 \catcode`\}=2 \catcode`\#=6
-%D From the next string (which is set by the script that assembles the
-%D distribution) later on we will calculate a number that can be used
-%D by use modules to identify the feature level. Starting with version
-%D 2004.8.30 the low level interface is english. Watch out and adapt
-%D your styles an modules.
+%D From the next string (which is set by the script that assembles the distribution)
+%D later on we will calculate a number that can be used by use modules to identify
+%D the feature level. Starting with version 2004.8.30 the low level interface is
+%D english. Watch out and adapt your styles an modules.
% \everypar{\writestatus{!!!!}{some spurious input in line \the\inputlineno}\wait}
-%D The order of loading will change when all modules have been cleaned
-%D up and the dependencies are more consistent. beware, the version number
-%D has to match \type {YYYY.MM.DD HH:MM} format.
+%D The order of loading will change when all modules have been cleaned up and the
+%D dependencies are more consistent. Beware, the version number has to match \type
+%D {YYYY.MM.DD HH:MM} format.
\edef\contextformat {\jobname}
-\edef\contextversion{2019.03.21 21:39}
+\edef\contextversion{2020.02.17 12:06}
\edef\contextkind {beta}
%D Kind of special:
@@ -61,31 +64,30 @@
\ifx\normalinput\undefined \let\normalinput\input \fi
-\def\loadcorefile#1{\normalinput#1\relax}
-\def\loadmarkfile#1{\normalinput#1.\mksuffix\relax}
-\def\loadmkiifile#1{}
-\def\loadmkivfile#1{\normalinput#1.mkiv\relax}
-\def\loadmkvifile#1{\normalinput#1.mkvi\relax}
+\def\loadmarkfile#1{\normalinput{#1.\mksuffix}}
+\def\loadmkivfile#1{\normalinput{#1.mkiv}}
+\def\loadmkvifile#1{\normalinput{#1.mkvi}}
+%def\loadmkilfile#1{\normalinput{#1.mkil}}
+%def\loadmklifile#1{\normalinput{#1.mkli}}
-%D First we load the system modules. These implement a lot of
-%D manipulation macros. We start with setting up some basic \TEX\
-%D machinery.
+%D First we load the system modules. These implement a lot of manipulation macros.
+%D We start with setting up some basic \TEX\ machinery.
\loadmarkfile{syst-ini}
+%D We just quit if new functionality is expected.
+
+\ifnum\luatexversion<110 % also change message
+ \writestatus{!!!!}{Your luatex binary is too old, you need at least version 1.10!}
+ \expandafter\end
+\fi
+
%D Some checking (more primitives are now defined):
\ifdefined\defaultinterface \else \def\defaultinterface {english} \fi
%ifdefined\messageinterface \else \let\messageinterface \defaultinterface \fi
\ifdefined\defaultlanguagetag \else \def\defaultlanguagetag{en} \fi
-%D We just quit if new functionality is expected.
-
-\ifnum\luatexversion<109 % also change message
- \writestatus{!!!!}{Your luatex binary is too old, you need at least version 1.09!}
- \expandafter\end
-\fi
-
%D There is only this way to pass the version info to \LUA\ (currently). Hm, we could
%D now put it into the environment.
@@ -116,8 +118,8 @@
% \tracecatcodetables
-% From here on we have \unexpanded being \normalprotected, as we already had
-% \unexpanded long before etex came around.
+%D From here on we have \unexpanded being \normalprotected, as we already had
+%D \type {\unexpanded} long before etex came around.
\loadmarkfile{luat-ini}
\loadmarkfile{toks-scn}
@@ -135,13 +137,11 @@
\loadmkvifile{file-res}
\loadmkvifile{file-lib}
-\doifelsefileexists{core-lmt.mkiv} {\loadmarkfile{core-lmt}} {}
-
-% needs more checking for clashes:
-%
-% no need to register, just execute once, slightly faster
-%
-% \doifelsefileexists{l-macro-imp-codes.lua}{\registerctxluafile{l-macro-imp-codes}{}}{}
+%D This needs more checking for clashes:
+%D
+%D \starttyping
+%D \doifelsefileexists{l-macro-imp-codes.lua}{\registerctxluafile{l-macro-imp-codes}{}}{}
+%D \stoptyping
\loadmarkfile{supp-dir}
@@ -154,7 +154,6 @@
\loadmarkfile{mult-aux}
\loadmarkfile{mult-def}
\loadmarkfile{mult-chk}
-%loadmarkfile{mult-aux} % moved up
\loadmkvifile{mult-dim}
\loadmarkfile{cldf-int} % interface
@@ -182,9 +181,11 @@
\loadmarkfile{node-mig}
%loadmarkfile{node-pag}
-\loadmarkfile{driv-ini}
+\loadmarkfile{driv-ini} % lmtx
\loadmarkfile{back-ini}
+\loadmarkfile{back-res}
+\loadmarkfile{back-trf}
\loadmarkfile{attr-col}
\loadmarkfile{attr-lay}
@@ -523,6 +524,7 @@
\loadmkvifile{strc-not}
\loadmkvifile{strc-lnt}
+\loadmkivfile{strc-tnt}
\loadmkivfile{strc-usr}
\loadmarkfile{pack-com}
@@ -580,8 +582,7 @@
% now we hook in backend code (needs checking)
\loadmarkfile{back-exp}
-
-\loadmarkfile{back-pdf} % actually, this one should load the next three using document.arguments.backend
+\loadmarkfile{back-pdf}
\loadmarkfile{mlib-pdf}
\loadmarkfile{mlib-pps}
@@ -598,8 +599,6 @@
\loadmarkfile{cont-run} % the main runner (used in cont-yes.mkiv)
-\doifelsefileexists{driv-shp.mkiv} {\loadmarkfile{driv-shp}} {}
-
\setupcurrentlanguage[\defaultlanguagetag]
\prependtoks
diff --git a/Master/texmf-dist/tex/context/base/mkiv/context.mkxl b/Master/texmf-dist/tex/context/base/mkiv/context.mkxl
new file mode 100644
index 00000000000..5cb85c4cd32
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/context.mkxl
@@ -0,0 +1,619 @@
+%D \module
+%D [ file=context,
+%D version=2019.07.24, % 2008.28.10, % 1995.10.10,
+%D title=\CONTEXT,
+%D subtitle=\CONTEXT\ Format Generation,
+%D author=Hans Hagen, % ɦɑns ɦɑˈχən
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% http://build.contextgarden.net/waterfall?tag=c/lua(meta)tex
+
+%D Welcome to context, pronounced as kontekst (rather dutch) and not as conτεχt.
+
+\catcode`\{=1 \catcode`\}=2 \catcode`\#=6
+
+%D From the next string (which is set by the script that assembles the distribution)
+%D later on we will calculate a number that can be used by use modules to identify
+%D the feature level. Starting with version 2004.8.30 the low level interface is
+%D english. Watch out and adapt your styles an modules.
+
+% \everypar{\writestatus{!!!!}{some spurious input in line \the\inputlineno}\wait}
+
+%D The order of loading will change when all modules have been cleaned up and the
+%D dependencies are more consistent. Beware, the version number has to match \type
+%D {YYYY.MM.DD HH:MM} format.
+
+\edef\contextformat {\jobname}
+\edef\contextversion{2020.02.17 12:06}
+\edef\contextkind {beta}
+
+%D Kind of special:
+
+\chardef\contextlmtxmode\directlua{tex.print(CONTEXTLMTXMODE or 0)}\relax
+
+%D For those who want to use this:
+
+\let\fmtname \contextformat
+\let\fmtversion\contextversion
+
+%D Loading:
+
+\edef\mksuffix {mkiv}
+\edef\contextmark{MKIV}
+
+\ifx\normalinput\undefined \let\normalinput\input \fi
+
+\def\loadmarkfile#1{\normalinput{#1.\mksuffix}}
+\def\loadmkivfile#1{\normalinput{#1.mkiv}}
+\def\loadmkvifile#1{\normalinput{#1.mkvi}}
+\def\loadmkxlfile#1{\normalinput{#1.mkxl}}
+\def\loadmklxfile#1{\normalinput{#1.mklx}}
+
+%D First we load the system modules. These implement a lot of manipulation macros.
+%D We start with setting up some basic \TEX\ machinery.
+
+\loadmkxlfile{syst-ini} % LMTX
+
+%D We just quit if new functionality is expected.
+
+\ifnum\luatexversion<200 % also change message
+ \writestatus{!!!!}{Your luametatex binary is too old, you need at least version 2.00!}
+ \expandafter\end
+\fi
+
+%D Some checking (more primitives are now defined):
+
+\ifdefined\defaultinterface \else \def\defaultinterface {english} \fi
+%ifdefined\messageinterface \else \let\messageinterface \defaultinterface \fi
+\ifdefined\defaultlanguagetag \else \def\defaultlanguagetag{en} \fi
+
+%D There is only this way to pass the version info to \LUA\ (currently). Hm, we could
+%D now put it into the environment.
+
+\newtoks\contextversiontoks \contextversiontoks\expandafter{\contextversion}
+\newtoks\contextkindtoks \contextkindtoks \expandafter{\contextkind}
+
+% \normaleverypar{\wait} % uncomment for test of funny injections
+
+%D Now the more fundamental code gets defined.
+
+\loadmarkfile{norm-ctx}
+\loadmarkfile{syst-pln}
+\loadmarkfile{syst-mes}
+
+\loadmarkfile{luat-cod}
+\loadmarkfile{luat-bas}
+\loadmarkfile{luat-lib}
+\loadmarkfile{luat-soc}
+
+\loadmarkfile{catc-ini}
+\loadmarkfile{catc-act}
+\loadmarkfile{catc-def}
+\loadmarkfile{catc-ctx}
+\loadmarkfile{catc-sym}
+
+\loadmarkfile{toks-ini}
+\loadmarkfile{cldf-ini}
+
+% \tracecatcodetables
+
+%D From here on we have \unexpanded being \normalprotected, as we already had
+%D \type {\unexpanded} long before etex came around.
+
+\loadmarkfile{luat-ini}
+\loadmarkfile{toks-scn}
+
+\loadmkxlfile{syst-aux} % LMTX
+\loadmkxlfile{syst-lua} % LMTX
+\loadmkxlfile{syst-con} % LMTX
+
+\loadmarkfile{syst-fnt}
+\loadmarkfile{syst-rtp}
+
+\loadmarkfile{luat-usr}
+
+\loadmkvifile{file-ini}
+\loadmkvifile{file-res}
+\loadmkvifile{file-lib}
+
+\loadmkxlfile{core-lmt} % LMTX
+
+%D This needs more checking for clashes:
+%D
+%D \starttyping
+%D \doifelsefileexists{l-macro-imp-codes.lua}{\registerctxluafile{l-macro-imp-codes}{}}{}
+%D \stoptyping
+
+\loadmarkfile{supp-dir}
+
+\loadmarkfile{char-utf} % generic code (i.e. not much tex) ... could become unic-ini
+\loadmarkfile{char-ini} % tex / context specific
+\loadmarkfile{char-act} % even more specific
+
+\loadmarkfile{mult-ini}
+\loadmarkfile{mult-sys}
+\loadmkxlfile{mult-aux} % LMTX
+\loadmarkfile{mult-def}
+\loadmarkfile{mult-chk}
+\loadmkvifile{mult-dim}
+
+\loadmarkfile{cldf-int} % interface
+
+\loadmarkfile{trac-ctx} % maybe move up
+
+% \loadmarkfile{luat-ini}
+
+\loadmarkfile{toks-tra}
+\loadmarkfile{toks-aux}
+%loadmarkfile{toks-map} % obsolete, never used
+
+\loadmarkfile{attr-ini}
+
+\loadmarkfile{core-ini}
+\loadmarkfile{core-env}
+
+\loadmarkfile{layo-ini}
+
+\loadmarkfile{node-ini}
+
+\loadmarkfile{cldf-bas} % basics / depends on nodes
+
+\loadmkivfile{node-fin}
+\loadmarkfile{node-mig}
+%loadmarkfile{node-pag}
+
+\loadmkxlfile{driv-ini} % LMTX
+
+\loadmkxlfile{back-ini} % LMTX
+\loadmarkfile{back-res}
+\loadmarkfile{back-trf}
+\loadmkxlfile{back-out} % LMTX
+
+\loadmarkfile{attr-col}
+\loadmarkfile{attr-lay}
+\loadmarkfile{attr-neg}
+\loadmarkfile{attr-eff}
+\loadmarkfile{attr-mkr}
+
+\loadmarkfile{trac-tex}
+\loadmarkfile{trac-deb} % will move up
+
+%loadmarkfile{blob-ini} % not to be used, we only use a helper
+
+\loadmkxlfile{supp-box} % LMTX
+
+\loadmarkfile{supp-ran}
+\loadmarkfile{supp-mat}
+
+\loadmarkfile{core-uti}
+\loadmkvifile{file-job}
+
+\loadmarkfile{anch-pos}
+
+\loadmarkfile{typo-ini}
+\loadmarkfile{typo-lin}
+\loadmarkfile{typo-bld} % par builders
+
+\loadmarkfile{typo-inj}
+
+\loadmkvifile{file-syn}
+\loadmkvifile{file-mod}
+
+\loadmarkfile{core-sys}
+\loadmarkfile{core-con}
+
+\loadmarkfile{cont-fil}
+
+\loadmarkfile{regi-ini}
+\loadmarkfile{enco-ini}
+\loadmkxlfile{hand-ini}
+
+\loadmkxlfile{lang-ini} % LMTX
+\loadmarkfile{lang-hyp} % also loads dis
+\loadmkxlfile{lang-lab} % LMTX
+
+\loadmarkfile{unic-ini}
+
+% \loadmarkfile{core-uti}
+\loadmarkfile{core-two}
+\loadmarkfile{core-dat}
+
+\loadmkxlfile{colo-ini} % LMTX
+\loadmarkfile{colo-grp} % optional
+\loadmarkfile{colo-ext}
+
+\loadmarkfile{node-bck} % overloads anch-pgr (experimental and undocumented)
+
+\loadmarkfile{pack-cut}
+
+\loadmarkfile{lang-mis}
+\loadmarkfile{lang-url}
+\loadmarkfile{lang-def}
+
+% \loadmkvifile{file-job} % why so late?
+
+\loadmarkfile{symb-ini} % brrr depends on fonts
+
+\loadmarkfile{sort-ini}
+
+\loadmkvifile{pack-mis}
+\loadmkxlfile{pack-ori} % LMTX
+\loadmkxlfile{pack-rul} % LMTX
+\loadmarkfile{pack-mrl}
+\loadmkvifile{pack-bck}
+\loadmarkfile{pack-fen}
+
+\loadmarkfile{lxml-ini}
+\loadmarkfile{lxml-sor}
+
+\loadmkvifile{typo-prc}
+
+% \loadmarkfile{anch-pos}
+
+\loadmkvifile{strc-ini}
+\loadmarkfile{strc-tag}
+\loadmarkfile{strc-doc}
+\loadmarkfile{strc-num}
+\loadmarkfile{strc-mar}
+\loadmarkfile{strc-sbe}
+\loadmkvifile{strc-lst}
+\loadmarkfile{strc-sec}
+\loadmarkfile{strc-pag} % hm, depends on core-num
+\loadmarkfile{strc-ren}
+\loadmarkfile{strc-xml}
+\loadmarkfile{strc-def} % might happen later
+\loadmkvifile{strc-ref}
+%loadmarkfile{strc-reg}
+\loadmkvifile{strc-lev} % experiment
+
+\loadmarkfile{spac-hor}
+\loadmarkfile{spac-ali}
+\loadmarkfile{spac-flr}
+\loadmkxlfile{spac-ver} % LMTX beware, hooks into strc-sec
+\loadmarkfile{spac-lin}
+\loadmarkfile{spac-pag}
+\loadmarkfile{spac-par}
+\loadmarkfile{spac-def}
+\loadmkvifile{spac-prf}
+\loadmarkfile{spac-grd}
+
+%loadmarkfile{anch-pos}
+
+\loadmkvifile{scrn-ini}
+\loadmkvifile{scrn-ref}
+
+\loadmarkfile{pack-obj}
+
+\loadmklxfile{strc-itm} % LMTX
+
+\loadmkvifile{strc-con}
+\loadmkvifile{strc-des}
+\loadmkvifile{strc-enu}
+
+\loadmarkfile{strc-ind}
+\loadmarkfile{strc-lab}
+\loadmarkfile{strc-syn}
+
+% \loadmarkfile{core-sys}
+
+\loadmarkfile{page-var}
+\loadmkvifile{page-otr}
+\loadmarkfile{page-ini}
+\loadmarkfile{page-ins}
+\loadmarkfile{page-fac}
+\loadmarkfile{page-brk}
+\loadmarkfile{page-col}
+\loadmarkfile{page-inf}
+\loadmarkfile{page-flt}
+\loadmarkfile{page-bck}
+\loadmarkfile{page-not}
+\loadmarkfile{page-one}
+\loadmarkfile{page-lay}
+\loadmkvifile{page-box}
+\loadmklxfile{page-txt} % LMTX
+\loadmarkfile{page-sid} % when
+
+\loadmkvifile{strc-flt}
+
+\loadmarkfile{page-pst}
+\loadmkvifile{page-mbk}
+%loadmarkfile{page-mul} % \usecolumns[old-multicolumns]
+\loadmarkfile{page-mix}
+\loadmarkfile{page-smp}
+%loadmarkfile{page-set} % \usecolumns[old-columnsets]
+\loadmarkfile{page-cst}
+\loadmarkfile{page-pcl} % new
+\loadmkxlfile{pack-lyr} % LMTX
+\loadmarkfile{pack-pos}
+\loadmkvifile{page-mak}
+
+\loadmarkfile{strc-reg} % uses mixed columns
+
+\loadmkvifile{page-lin}
+\loadmarkfile{page-par}
+\loadmarkfile{typo-pag}
+\loadmarkfile{typo-mar}
+\loadmarkfile{typo-itm}
+
+\loadmarkfile{buff-ini}
+\loadmkxlfile{buff-ver} % LMTX
+\loadmkvifile{buff-par}
+
+\loadmarkfile{buff-imp-tex} % optional as also runtime if not loaded
+\loadmarkfile{buff-imp-mp} % optional as also runtime if not loaded
+\loadmarkfile{buff-imp-lua} % optional as also runtime if not loaded
+\loadmarkfile{buff-imp-xml} % optional as also runtime if not loaded
+
+\loadmarkfile{buff-imp-parsed-xml} % optional
+%loadmarkfile{buff-imp-parsed-lua} % optional
+
+\loadmarkfile{strc-blk}
+
+\loadmarkfile{page-imp}
+\loadmkvifile{page-sel} % optional
+\loadmkvifile{page-inj} % optional
+
+\loadmkvifile{scrn-pag}
+\loadmkvifile{scrn-wid}
+\loadmkvifile{scrn-but}
+\loadmkvifile{scrn-bar}
+
+\loadmarkfile{page-com} % optional (after scrn-pag)
+
+\loadmarkfile{strc-bkm} % bookmarks
+
+\loadmarkfile{java-ini}
+
+\loadmkvifile{scrn-fld}
+\loadmkvifile{scrn-hlp}
+
+\loadmarkfile{char-enc} % will move up
+
+\loadmkvifile{font-lib} % way too late but after language
+\loadmklxfile{font-fil} % LMTX
+\loadmkvifile{font-var}
+\loadmkvifile{font-fea}
+\loadmklxfile{font-mat} % LMTX
+\loadmklxfile{font-ini} % LMTX
+\loadmklxfile{font-sym} % LMTX
+\loadmklxfile{font-sty} % LMTX
+\loadmkvifile{font-set}
+\loadmklxfile{font-emp} % LMTX
+\loadmarkfile{font-pre}
+\loadmarkfile{font-unk}
+\loadmarkfile{font-tra}
+\loadmarkfile{font-chk}
+\loadmarkfile{font-uni}
+\loadmkvifile{font-col}
+\loadmkvifile{font-gds}
+\loadmkvifile{font-aux}
+\loadmkvifile{font-sel}
+
+\loadmarkfile{typo-tal}
+\loadmarkfile{typo-par} % par builders (uses fonts)
+
+\loadmarkfile{tabl-com}
+\loadmarkfile{tabl-pln}
+
+\loadmarkfile{tabl-tab} % thrd-tab stripped and merged
+
+\loadmkxlfile{tabl-tbl} % LMTX
+\loadmkxlfile{tabl-ntb} % LMTX
+\loadmarkfile{tabl-nte}
+\loadmarkfile{tabl-ltb}
+\loadmarkfile{tabl-frm}
+\loadmarkfile{tabl-tsp}
+\loadmkvifile{tabl-xtb}
+\loadmarkfile{tabl-mis}
+
+\loadmarkfile{typo-lan}
+
+\loadmarkfile{lxml-css}
+
+\loadmarkfile{spac-chr} % depends on fonts
+
+\loadmarkfile{blob-ini} % not to be used, we only use a helper
+
+\loadmarkfile{trac-vis}
+\loadmarkfile{trac-jus}
+
+\loadmarkfile{typo-cln}
+\loadmarkfile{typo-wrp}
+\loadmarkfile{typo-spa}
+\loadmarkfile{typo-krn}
+\loadmkvifile{typo-itc}
+\loadmarkfile{typo-dir}
+\loadmarkfile{typo-brk}
+\loadmarkfile{typo-cap}
+\loadmarkfile{typo-dig}
+\loadmarkfile{typo-rep}
+\loadmkvifile{typo-txt}
+\loadmarkfile{typo-drp}
+\loadmarkfile{typo-fln}
+\loadmarkfile{typo-sus}
+\loadmarkfile{typo-lig}
+\loadmarkfile{typo-chr}
+\loadmarkfile{typo-rub}
+\loadmkivfile{typo-fkr}
+\loadmkivfile{typo-pnc}
+
+\loadmklxfile{type-ini} % LMTX
+\loadmarkfile{type-set}
+
+\loadmarkfile{scrp-ini}
+
+\loadmarkfile{symb-emj}
+
+\loadmarkfile{lang-wrd} % can be optional (discussion with mm sideeffect)
+\loadmarkfile{lang-rep} % can be optional (bt 2013 side effect)
+
+\loadmarkfile{prop-ini} % only for downward compatibility
+
+\loadmkxlfile{mlib-ctx} % LMTX % messy order
+
+\loadmkxlfile{meta-ini} % LMTX
+\loadmarkfile{meta-tex}
+\loadmarkfile{meta-fun}
+\loadmkxlfile{meta-pag}
+\loadmarkfile{meta-grd}
+\loadmarkfile{meta-fnt}
+\loadmarkfile{meta-nod}
+\loadmarkfile{meta-lua}
+\loadmkxlfile{meta-mac} % LMTX
+
+\loadmarkfile{page-mrk} % depends on mp
+
+\loadmarkfile{page-flw}
+\loadmarkfile{page-spr}
+\loadmarkfile{page-plg}
+\loadmarkfile{page-str}
+
+\loadmarkfile{anch-pgr} % can be moved up (nicer for dependencies)
+\loadmkvifile{anch-bck}
+\loadmarkfile{anch-tab} % overloads tabl-tbl
+\loadmarkfile{anch-bar}
+%loadmarkfile{anch-snc} % when needed this one will be redone
+
+\loadmarkfile{math-ini} % way after font-pre !
+\loadmarkfile{math-pln}
+\loadmarkfile{math-for}
+\loadmarkfile{math-def} % also saves some meanings
+\loadmarkfile{math-ali}
+%loadmarkfile{math-arr}
+\loadmkvifile{math-stc}
+\loadmarkfile{math-frc}
+\loadmarkfile{math-mis}
+\loadmarkfile{math-scr}
+\loadmarkfile{math-int}
+\loadmarkfile{math-del}
+\loadmarkfile{math-fen}
+\loadmkvifile{math-acc}
+\loadmkvifile{math-rad}
+\loadmarkfile{math-inl}
+\loadmarkfile{math-dis}
+%loadmarkfile{math-lan}
+
+%loadmarkfile{phys-dim} % moved to after typo-scr
+
+\loadmarkfile{strc-mat}
+
+\loadmarkfile{chem-ini}
+\loadmarkfile{chem-str}
+
+\loadmarkfile{typo-scr}
+\loadmarkfile{phys-dim}
+
+\loadmarkfile{node-rul} % beware, defined \underbar so after math
+\loadmkvifile{font-sol} % font solutions
+
+\loadmkvifile{strc-not}
+\loadmkvifile{strc-lnt}
+\loadmkivfile{strc-tnt}
+\loadmkivfile{strc-usr}
+
+\loadmarkfile{pack-com}
+\loadmarkfile{typo-del}
+
+\loadmarkfile{grph-trf}
+\loadmarkfile{grph-inc}
+\loadmarkfile{grph-fig}
+\loadmarkfile{grph-raw}
+\loadmarkfile{grph-rul}
+\loadmarkfile{grph-pat}
+
+\loadmarkfile{pack-box}
+\loadmarkfile{pack-bar}
+\loadmarkfile{page-app}
+\loadmarkfile{meta-fig}
+
+\loadmarkfile{page-ffl}
+
+\loadmarkfile{lang-spa} % will become obsolete
+
+\loadmarkfile{typo-ovl} % fuzzy project (tracing) code
+
+% old bibtex support: (will be m-oldbibtex.mkiv)
+
+% \loadmarkfile{bibl-bib}
+% \loadmarkfile{bibl-tra}
+
+% new bibtex support:
+
+\loadmarkfile{publ-ini}
+\loadmarkfile{publ-tra}
+\loadmarkfile{publ-xml}
+\loadmarkfile{publ-old}
+
+%loadmarkfile{x-xtag} % no longer preloaded
+
+\loadmarkfile{meta-xml}
+
+\loadmarkfile{cont-log}
+
+% \loadmarkfile{task-ini}
+
+\loadmarkfile{cldf-ver} % verbatim, this can come late
+\loadmarkfile{cldf-com} % commands, this can come late
+
+\loadmarkfile{core-ctx} % this order might change but we need to check depedencies / move to another namespace
+
+\loadmarkfile{core-def}
+
+%usemodule[x][res-04] % xml resource libraries
+%usemodule[x][res-08] % rlx runtime conversion
+%usemodule[x][res-12] % rli external indentification
+
+% now we hook in backend code (needs checking)
+
+\loadmkxlfile{driv-shp} % LMTX
+
+\loadmarkfile{back-exp}
+\loadmkxlfile{back-pdf} % LMTX
+\loadmkxlfile{back-mps} % LMTX
+\loadmkxlfile{back-lua} % LMTX
+
+\loadmkxlfile{mlib-pdf} % LMTX
+\loadmarkfile{mlib-pps}
+\loadmarkfile{meta-pdf}
+\loadmarkfile{meta-blb}
+\loadmarkfile{grph-epd}
+
+\loadmarkfile{math-inc} % an experiment
+\loadmarkfile{publ-inc} % an experiment
+
+\loadmarkfile{task-ini}
+
+\loadmarkfile{syst-cmp} % compatibility stuff moved here
+
+\loadmkxlfile{libs-ini}
+
+\loadmarkfile{cont-run} % the main runner (used in cont-yes.mkiv)
+
+\setupcurrentlanguage[\defaultlanguagetag]
+
+\prependtoks
+ \ctxlua{statistics.starttiming(statistics)}%
+\to \everyjob
+
+\appendtoks
+ \ctxlua{statistics.stoptiming(statistics)}%
+\to \everyjob
+
+% \appendtoks
+% \ctxlua{job.prepare()}%
+% \to \everyjob
+
+% \appendtoks
+% \enabletrackers[*]%
+% \to \everyjob
+
+\appendtoks
+ \ctxlua{statistics.savefmtstatus("\jobname","\contextversion","context.mkxl","\contextkind","\contextbanner")}% can become automatic
+\to \everydump
+
+\errorstopmode \dump \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/core-con.lua b/Master/texmf-dist/tex/context/base/mkiv/core-con.lua
index 3829efc9c82..4f6090ef5b5 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/core-con.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/core-con.lua
@@ -311,11 +311,15 @@ local function textime()
return tonumber(osdate("%H")) * 60 + tonumber(osdate("%M"))
end
-function converters.year () return osdate("%Y") end
-function converters.month () return osdate("%m") end
-function converters.hour () return osdate("%H") end
-function converters.minute() return osdate("%M") end
-function converters.second() return osdate("%S") end
+-- For consistenty we need to add day here but that conflicts with the current
+-- serializer so then best is to have none from now on:
+
+-- function converters.year () return osdate("%Y") end
+-- function converters.month () return osdate("%m") end -- always two digits
+-- function converters.day () return osdate("%d") end -- conflicts
+-- function converters.hour () return osdate("%H") end
+-- function converters.minute() return osdate("%M") end
+-- function converters.second() return osdate("%S") end
converters.weekday = weekday
converters.isleapyear = isleapyear
@@ -329,6 +333,7 @@ implement { name = "nofdays", actions = { nofdays, context }, arguments = { "i
implement { name = "year", actions = { osdate, context }, arguments = "'%Y'" }
implement { name = "month", actions = { osdate, context }, arguments = "'%m'" }
+implement { name = "day", actions = { osdate, context }, arguments = "'%d'" }
implement { name = "hour", actions = { osdate, context }, arguments = "'%H'" }
implement { name = "minute", actions = { osdate, context }, arguments = "'%M'" }
implement { name = "second", actions = { osdate, context }, arguments = "'%S'" }
@@ -1675,3 +1680,8 @@ implement {
}
}
+local function field(n) return context(osdate("*t")[n]) end
+
+implement { name = "actualday", public = true, actions = function() field("day") end }
+implement { name = "actualmonth", public = true, actions = function() field("month") end }
+implement { name = "actualyear", public = true, actions = function() field("year") end }
diff --git a/Master/texmf-dist/tex/context/base/mkiv/core-con.mkiv b/Master/texmf-dist/tex/context/base/mkiv/core-con.mkiv
index 303fb12910f..b73280d00f1 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/core-con.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/core-con.mkiv
@@ -186,9 +186,9 @@
%D \macros
%D {normaltime,normalyear,normalmonth,normalday}
%D
-%D The last part of this module is dedicated to converting dates. Because we
-%D want to use as meaningful commands as possible, and because \TEX\ already
-%D uses up some of those, we save the original meanings.
+%D The last part of this module is dedicated to converting dates. Because we want to
+%D use as meaningful commands as possible, and because \TEX\ already uses up some of
+%D those, we save the original meanings.
% \savenormalmeaning\time
% \savenormalmeaning\year
@@ -274,8 +274,8 @@
%D \getbuffer
%D \stoplines
%D
-%D The macro \type {\getdayoftheweek} can be used to calculate the number
-%D \type {\normalweekday}.
+%D The macro \type {\getdayoftheweek} can be used to calculate the number \type
+%D {\normalweekday}.
%D \macros
%D {doifleapyearelse,
@@ -363,8 +363,8 @@
%D
%D \typebuffer
%D
-%D The date is specified by one character keys. When no date is given, we
-%D get the current date.
+%D The date is specified by one character keys. When no date is given, we get the
+%D current date.
%D
%D \startlines
%D \getbuffer
@@ -425,26 +425,25 @@
\unexpanded\def\date
{\dodoubleempty\syst_converters_date}
-\def\syst_converters_date[#1][#2]%
+\def\syst_converters_date[#1][#2]% sets the date !
{\dontleavehmode
- \begingroup
- \scratchcounterone \normalyear
- \scratchcountertwo \normalmonth
- \scratchcounterthree\normalday
\iffirstargument
- \letdummyparameter\c!y\empty
- \letdummyparameter\c!m\empty
- \letdummyparameter\c!d\empty
+ \begingroup
+ \letdummyparameter\c!d\normalday
+ \letdummyparameter\c!m\normalmonth
+ \letdummyparameter\c!y\normalyear
\getdummyparameters[#1]%
- \edef\temp{\dummyparameter\c!y}\ifx\temp\empty\else\scratchcounterone \temp\fi
- \edef\temp{\dummyparameter\c!m}\ifx\temp\empty\else\scratchcountertwo \temp\fi
- \edef\temp{\dummyparameter\c!d}\ifx\temp\empty\else\scratchcounterthree\temp\fi
- \relax
+ \normalexpanded
+ {\endgroup
+ \normalday \number\directdummyparameter\c!d\relax
+ \normalmonth\number\directdummyparameter\c!m\relax
+ \normalyear \number\directdummyparameter\c!y\relax}%
\fi
+ \begingroup
\the\everycurrentdate
\clf_currentdate
{#2}{\currentdatespecification}{\labellanguage}%
- \scratchcounterone\scratchcountertwo\scratchcounterthree
+ \normalyear\normalmonth\normalday
\endgroup}
\def\rawdate[#1]% expandable and no labels
@@ -535,10 +534,10 @@
\installcorenamespace {conversionarguments}
\installcorenamespace {conversionwords}
-%D It might be better to move more to lua as we also need conversion there
-%D and doublicating logic doesn't make things cleaner. It means that all
-%D conversions will get a language argument too. However, we permit definitions
-%D at the \TEX\ end so we have to provide some hybrid method.
+%D It might be better to move more to \LUA\ as we also need conversion there and
+%D doublicating logic doesn't make things cleaner. It means that all conversions
+%D will get a language argument too. However, we permit definitions at the \TEX\ end
+%D so we have to provide some hybrid method.
% checkedconversion(method,n,language)
@@ -561,9 +560,9 @@
\def\syst_converters_checked_conversion#1#2%
{\clf_checkedconversion{#1}\numexpr#2\relax}
-%D If a conversion is just a font switch then we need to make sure that the
-%D number is indeed ends up as number in the input, so we need to handle the
-%D second argument.
+%D If a conversion is just a font switch then we need to make sure that the number
+%D is indeed ends up as number in the input, so we need to handle the second
+%D argument.
\def\convertnumber#1#2% expandable
{\csname\??conversionarguments
diff --git a/Master/texmf-dist/tex/context/base/mkiv/core-def.mkiv b/Master/texmf-dist/tex/context/base/mkiv/core-def.mkiv
index 95f7f2577d0..d10527d7bc7 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/core-def.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/core-def.mkiv
@@ -107,6 +107,9 @@
\initializenewlinechar
\calculatecurrenttime
\syst_files_load
+ % for the moment here (before doc env)
+ \setupoutput[pdf]%
+ %
\clf_setdocumentcommandline
\clf_setdocumentctxfile
\clf_setdocumentfilenames
diff --git a/Master/texmf-dist/tex/context/base/mkiv/core-env.mkiv b/Master/texmf-dist/tex/context/base/mkiv/core-env.mkiv
index 758ee126d1a..09de435e7c0 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/core-env.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/core-env.mkiv
@@ -17,6 +17,8 @@
\unprotect
+\def\wildcardsymbol{*}
+
%D Modes:
%D
%D \starttyping
@@ -35,12 +37,11 @@
%D
%D system modes have a * as prefix
%D
-%D Sometimes, we want to prevent a mode for being set. Think
-%D of situations where a style enables a mode, but an outer
-%D level style does not want that. Preventing can be
-%D considered a permanent disabling on forehand.
+%D Sometimes, we want to prevent a mode for being set. Think of situations where a
+%D style enables a mode, but an outer level style does not want that. Preventing can
+%D be considered a permanent disabling on forehand.
-\def\systemmodeprefix{*}
+\let\systemmodeprefix\wildcardsymbol
% we will have \installcorenamespace{mode} but need some hackery at the lua end then
@@ -129,26 +130,18 @@
\unexpanded\def\globalenablemode {\let\syst_mode_prefix\global\unprotect\syst_modes_enable }
\unexpanded\def\globaldisablemode{\let\syst_mode_prefix\global\unprotect\syst_modes_disable}
-\def\syst_modes_prevent[#1]{\protect\rawprocesscommacommand[#1]\syst_modes_prevent_indeed\let\syst_mode_prefix\relax}
-\def\syst_modes_enable [#1]{\protect\rawprocesscommacommand[#1]\syst_modes_enable_indeed \let\syst_mode_prefix\relax}
-\def\syst_modes_disable[#1]{\protect\rawprocesscommacommand[#1]\syst_modes_disable_indeed\let\syst_mode_prefix\relax}
+% \def\syst_modes_prevent[#1]{\protect\rawprocesscommacommand[#1]\syst_modes_prevent_indeed\let\syst_mode_prefix\relax}
+% \def\syst_modes_enable [#1]{\protect\rawprocesscommacommand[#1]\syst_modes_enable_indeed \let\syst_mode_prefix\relax}
+% \def\syst_modes_disable[#1]{\protect\rawprocesscommacommand[#1]\syst_modes_disable_indeed\let\syst_mode_prefix\relax}
+
+\def\syst_modes_prevent[#1]{\protect\fastprocesscommacommand[#1]\syst_modes_prevent_indeed\let\syst_mode_prefix\relax}
+\def\syst_modes_enable [#1]{\protect\fastprocesscommacommand[#1]\syst_modes_enable_indeed \let\syst_mode_prefix\relax}
+\def\syst_modes_disable[#1]{\protect\fastprocesscommacommand[#1]\syst_modes_disable_indeed\let\syst_mode_prefix\relax}
\def\syst_modes_prevent_indeed#1%
{\ifcsname\??mode#1\endcsname\else\syst_modes_new{#1}\fi
\syst_mode_prefix\lastnamedcs\preventedmode}
-% \def\syst_modes_enable_indeed#1% we can speed it up by moving the new outside
-% {\ifcsname\??mode#1\endcsname\else\syst_modes_new{#1}\fi
-% \ifnum\csname\??mode#1\endcsname=\preventedmode \else
-% \syst_mode_prefix\lastnamedcs\enabledmode
-% \fi}
-%
-% \def\syst_modes_disable_indeed#1%
-% {\ifcsname\??mode#1\endcsname\else\syst_modes_new{#1}\fi
-% \ifnum\csname\??mode#1\endcsname=\preventedmode \else
-% \syst_mode_prefix\lastnamedcs\disabledmode
-% \fi}
-
\def\syst_modes_enable_indeed#1% we can speed it up by moving the new outside
{\ifcsname\??mode#1\endcsname\else\syst_modes_new{#1}\fi
\ifnum\lastnamedcs=\preventedmode\else
@@ -174,19 +167,8 @@
\def\syst_modes_define[#1][#2]%
{\protect
\edef\m_modes_asked{#2}%
- \rawprocesscommacommand[#1]\syst_modes_define_indeed}
-
-% \def\syst_modes_define_indeed#1%
-% {\ifcsname\??mode#1\endcsname
-% % already set
-% \else
-% \syst_modes_new{#1}
-% \fi
-% \ifx\m_modes_asked\v!keep
-% % not changes, disabled when undefined
-% \else
-% \csname\??mode#1\endcsname\ifx\m_modes_asked\v!yes\enabledmode\else\disabledmode\fi
-% \fi}
+ % \rawprocesscommacommand[#1]\syst_modes_define_indeed}
+ \fastprocesscommacommand[#1]\syst_modes_define_indeed}
\def\syst_modes_define_indeed#1%
{\ifcsname\??mode#1\endcsname
@@ -230,7 +212,8 @@
\def\syst_modes_check_nop#1#2#3%
{\let\syst_modes_check_step\syst_modes_check_indeed
- \rawprocesscommacommand[#3]\syst_modes_check_step
+ % \rawprocesscommacommand[#3]\syst_modes_check_step
+ \fastprocesscommacommand[#3]\syst_modes_check_step
\ifx\syst_modes_check_step\gobbleoneargument
\expandafter#1%
\else
@@ -277,7 +260,7 @@
\def\syst_modes_check_all_lr#1#2#3%
{\let\syst_modes_check_all_step\syst_modes_check_all_indeed
- \rawprocesscommacommand[#3]\syst_modes_check_all_step
+ \fastprocesscommacommand[#3]\syst_modes_check_all_step
\ifx\syst_modes_check_all_step\gobbleoneargument
\expandafter#2%
\else
@@ -286,7 +269,7 @@
\def\syst_modes_check_all_ss#1#2[#3]%
{\let\syst_modes_check_all_step\syst_modes_check_all_indeed
- \rawprocesscommacommand[#3]\syst_modes_check_all_step
+ \fastprocesscommacommand[#3]\syst_modes_check_all_step
\ifx\syst_modes_check_all_step\gobbleoneargument
\expandafter#2%
\else
@@ -319,28 +302,6 @@
%D Pushing/popping:
-% \unexpanded\def\pushmode[#1]%
-% {\ifcsname\??mode#1\endcsname\else\syst_modes_new{#1}\fi
-% \expandafter\edef\csname\??modestack#1\endcsname{\number\csname\??mode#1\endcsname}%
-% \expandafter\pushmacro\csname\??modestack#1\endcsname}
-%
-% \unexpanded\def\popmode[#1]%
-% {\ifcsname\??modestack#1\endcsname
-% \expandafter\popmacro\csname\??modestack#1\endcsname
-% \csname\??mode#1\endcsname\csname\??modestack#1\endcsname\relax
-% \fi}
-%
-% \def\pushsystemmode#1%
-% {\ifcsname\??mode\systemmodeprefix#1\endcsname\else\syst_modes_new{\systemmodeprefix#1}\fi
-% \expandafter\edef\csname\??modestack\systemmodeprefix#1\endcsname{\number\csname\??mode\systemmodeprefix#1\endcsname}%
-% \expandafter\pushmacro\csname\??modestack\systemmodeprefix#1\endcsname}
-%
-% \def\popsystemmode#1%
-% {\ifcsname\??modestack\systemmodeprefix#1\endcsname
-% \expandafter\popmacro\csname\??modestack\systemmodeprefix#1\endcsname
-% \csname\??mode\systemmodeprefix#1\endcsname\csname\??modestack\systemmodeprefix#1\endcsname\relax
-% \fi}
-
\unexpanded\def\pushmode[#1]%
{\ifcsname\??mode#1\endcsname\else\syst_modes_new{#1}\fi
\expandafter\edef\csname\??modestack#1\expandafter\endcsname\expandafter{\number\lastnamedcs}%
@@ -450,14 +411,6 @@
\unexpanded\def\startsetups{} % to please dep checker
\unexpanded\def\stopsetups {} % to please dep checker
-% \expanded % will become obsolete
-% {\def\expandafter\noexpand\csname\e!start\v!setups\endcsname
-% {\begingroup\noexpand\doifnextoptionalcselse
-% {\noexpand\dostartsetupsA\expandafter\noexpand\csname\e!stop\v!setups\endcsname}
-% {\noexpand\dostartsetupsB\expandafter\noexpand\csname\e!stop\v!setups\endcsname}}}
-%
-% \letvalue{\e!stop\v!setups}\relax
-
\unexpanded\def\setups{\doifelsenextbgroup\syst_setups_a\syst_setups_b} % {..} or [..]
\unexpanded\def\setup {\doifelsenextbgroup\syst_setups \syst_setups_c} % {..} or [..]
@@ -499,9 +452,6 @@
\expandafter\syst_setups_process_local
\fi}
-% \def\syst_setups_process_local
-% {\expandafter\processcommalist\expandafter[\m_syst_setups_asked]\syst_setups}
-
% setups=S1
% setups=lua(S2)
% setups=S3
@@ -666,9 +616,9 @@
\def\luasetup#1{\ctxlua{\syst_setups{#1}}}
-% % % %
+%D System setups:
-\def\systemsetupsprefix{*}
+\let\systemsetupsprefix\wildcardsymbol
\def\systemsetups#1{\syst_setups{\systemsetupsprefix#1}}
@@ -679,19 +629,9 @@
\dodoglobal\undefinevalue{\??setup:#1}%
\fi}
-% \unexpanded\def\resetsetups[#1]% see x-fo for usage
-% {\dodoglobal\expandafter\let\csname\??setup
-% \ifgridsnapping\ifcsname\??setup\v!grid:#1\endcsname\v!grid\fi
-% :#1\endcsname\undefined}
-
\unexpanded\def\copysetups
{\dodoubleargument\syst_setups_copy}
-% \def\syst_setups_copy[#1][#2]%
-% {\ifcsname\??setup:#2\endcsname
-% \expandafter\let\csname\??setup:#1\expandafter\endcsname\csname\??setup:#2\endcsname
-% \fi}
-
\def\syst_setups_copy[#1][#2]%
{\ifcsname\??setup:#2\endcsname
\expandafter\let\csname\??setup:#1\expandafter\endcsname\lastnamedcs
@@ -723,27 +663,20 @@
{\dotripleargument\syst_variables_set[\globalgetrawparameters]}
\def\syst_variables_set[#1][#2][#3]% tricky, test on s-pre-60
- {\errorisfataltrue
- \doifelse{#2}\currentvariableclass
+ {\doifelse{#2}\currentvariableclass
{#1[\??variables#2:][#3]}%
{\pushmacro\currentvariableclass
\def\currentvariableclass{#2}%
\getvariable{#2}\s!reset
#1[\??variables#2:][#3]%
\getvariable{#2}\s!set
- \popmacro\currentvariableclass}%
- \errorisfatalfalse}
+ \popmacro\currentvariableclass}}
\unexpanded\def\setvariable #1#2#3{\expandafter\def \csname\??variables#1:#2\endcsname{#3}}
\unexpanded\def\setevariable#1#2#3{\expandafter\edef\csname\??variables#1:#2\endcsname{#3}}
\unexpanded\def\setgvariable#1#2#3{\expandafter\gdef\csname\??variables#1:#2\endcsname{#3}}
\unexpanded\def\setxvariable#1#2#3{\expandafter\xdef\csname\??variables#1:#2\endcsname{#3}}
-% \def\getvariable#1#2%
-% {\csname
-% \ifcsname\??variables#1:#2\endcsname\??variables#1:#2\else\s!empty\fi
-% \endcsname}
-
\def\getvariable#1#2%
{\begincsname\??variables#1:#2\endcsname}
@@ -767,7 +700,6 @@
\def\syst_variables_check_value#1#2#3%
{\ifcsname\??variables#1:#2\endcsname
- %\edef\m_syst_variables_temp{\csname\??variables#1:#2\endcsname}%
\edef\m_syst_variables_temp{\lastnamedcs}%
\ifx\m_syst_variables_temp\empty
\expandafter\def\csname\??variables#1:#2\endcsname{#3}%
@@ -804,13 +736,12 @@
\expandafter\firstofoneargument
\fi}
-%D A few more (we could use a public test variable so that we only need
-%D to expand once, assuming expandable variables):
+%D A few more (we could use a public test variable so that we only need to expand
+%D once, assuming expandable variables):
\letvalue{\??variables:}\empty
\unexpanded\def\doifelseemptyvariable#1#2%
- %{\edef\m_syst_string_one{\csname\??variables\ifcsname\??variables#1:#2\endcsname#1:#2\else:\fi\endcsname}%
{\edef\m_syst_string_one{\begincsname\??variables#1:#2\endcsname}%
\ifx\m_syst_string_one\empty
\expandafter\firstoftwoarguments
@@ -821,7 +752,6 @@
\let\doifemptyvariableelse\doifelseemptyvariable
\unexpanded\def\doifemptyvariable#1#2%
- %{\edef\m_syst_string_one{\csname\??variables\ifcsname\??variables#1:#2\endcsname#1:#2\else:\fi\endcsname}%
{\edef\m_syst_string_one{\begincsname\??variables#1:#2\endcsname}%
\ifx\m_syst_string_one\empty
\expandafter\firstofoneargument
@@ -830,7 +760,6 @@
\fi}
\unexpanded\def\doifnotemptyvariable#1#2%
- %{\edef\m_syst_string_one{\csname\??variables\ifcsname\??variables#1:#2\endcsname#1:#2\else:\fi\endcsname}%
{\edef\m_syst_string_one{\begincsname\??variables#1:#2\endcsname}%
\ifx\m_syst_string_one\empty
\expandafter\gobbleoneargument
@@ -839,7 +768,6 @@
\fi}
\def\getvariabledefault#1#2% #3% can be command
- %{\executeifdefined{\??variables#1:#2}}% {#3}
{\ifcsname\??variables#1:#2\endcsname
\expandafter\expandafter\expandafter\lastnamedcs\expandafter\gobbleoneargument
\else
diff --git a/Master/texmf-dist/tex/context/base/mkiv/core-lmt.mkiv b/Master/texmf-dist/tex/context/base/mkiv/core-lmt.mkxl
index eda66796918..75a791a50d9 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/core-lmt.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/core-lmt.mkxl
@@ -1,6 +1,6 @@
%D \module
%D [ file=core-lmt,
-%D version=2010.08.2,
+%D version=2018.08.2,
%D title=\CONTEXT\ System Macros,
%D subtitle=Primitives,
%D author=Hans Hagen,
@@ -11,13 +11,12 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\ifcase\contextlmtxmode\expandafter\endinput\fi
-
\writestatus{loading}{ConTeXt System Macros / Primitives}
-\ifdefined\textdir \else
- \registerctxluafile{core-lmt}{}
-\fi
+%D This is offered temporarily because in the end we don't expect u sers to use the
+%D low level direction directives directly.
+
+\registerctxluafile{core-lmt}{}
\unprotect
diff --git a/Master/texmf-dist/tex/context/base/mkiv/core-sys.lua b/Master/texmf-dist/tex/context/base/mkiv/core-sys.lua
index 4078ab8a8a9..7e9648fb845 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/core-sys.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/core-sys.lua
@@ -53,6 +53,10 @@ function environment.initializefilenames()
environment.filename = filename
environment.suffix = suffix
+ -- if tex then
+ -- tex.jobname = jobfilename
+ -- end
+
report_files("jobname %a, input %a, result %a",jobfilename,inputfilename,outputfilename)
function environment.initializefilenames() end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/core-sys.mkiv b/Master/texmf-dist/tex/context/base/mkiv/core-sys.mkiv
index 4d99d8647b0..7a04df8408f 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/core-sys.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/core-sys.mkiv
@@ -78,18 +78,6 @@
\fi
\to \everysetupsystem
-\let\m_system_job_suffix\s!unknown
-
-\appendtoks
- \resetsystemmode{suffix-\m_system_job_suffix}%
- \edef\m_system_job_suffix{\jobsuffix}%
- \setsystemmode{suffix-\m_system_job_suffix}%
-\to \everysetupsystem
-
-% \appendtoks
-% \ctxcommand{updatefilenames("\jobame","\inputfilename","\outputfilename")}%
-% \to \everysetupsystem
-
\newconditional\prerollrun % when true it means that we have a forced number of runs
% Some mechanisms (see x-res-01) use either \jobfilename or
diff --git a/Master/texmf-dist/tex/context/base/mkiv/core-uti.lua b/Master/texmf-dist/tex/context/base/mkiv/core-uti.lua
index cd867db1bce..50c7bc9dc6a 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/core-uti.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/core-uti.lua
@@ -269,6 +269,16 @@ end
local function load(filename)
if lfs.isfile(filename) then
+
+ local function dofile(filename)
+ local result = loadstring(io.loaddata(filename))
+ if result then
+ return result()
+ else
+ return nil
+ end
+ end
+
local okay, data = pcall(dofile,filename)
if okay and type(data) == "table" then
local jobversion = job.version
diff --git a/Master/texmf-dist/tex/context/base/mkiv/data-aux.lua b/Master/texmf-dist/tex/context/base/mkiv/data-aux.lua
index c57f16d2c57..028794e51aa 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/data-aux.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/data-aux.lua
@@ -8,29 +8,33 @@ if not modules then modules = { } end modules ['data-aux'] = {
local find = string.find
local type, next = type, next
+local addsuffix, removesuffix = file.addsuffix, file.removesuffix
+local loaddata, savedata = io.loaddata, io.savedata
local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end)
local resolvers = resolvers
+local cleanpath = resolvers.cleanpath
+local findfiles = resolvers.findfiles
local report_scripts = logs.reporter("resolvers","scripts")
function resolvers.updatescript(oldname,newname) -- oldname -> own.name, not per se a suffix
-- local scriptpath = "scripts/context/lua"
local scriptpath = "context/lua"
- newname = file.addsuffix(newname,"lua")
- local oldscript = resolvers.cleanpath(oldname)
+ local oldscript = cleanpath(oldname)
+ local newname = addsuffix(newname,"lua")
+ local newscripts = findfiles(newname) or { }
if trace_locating then
report_scripts("to be replaced old script %a", oldscript)
end
- local newscripts = resolvers.findfiles(newname) or { }
if #newscripts == 0 then
if trace_locating then
report_scripts("unable to locate new script")
end
else
for i=1,#newscripts do
- local newscript = resolvers.cleanpath(newscripts[i])
+ local newscript = cleanpath(newscripts[i])
if trace_locating then
report_scripts("checking new script %a", newscript)
end
@@ -42,17 +46,17 @@ function resolvers.updatescript(oldname,newname) -- oldname -> own.name, not per
if trace_locating then
report_scripts("new script should come from %a",scriptpath)
end
- elseif not (find(oldscript,file.removesuffix(newname).."$") or find(oldscript,newname.."$")) then
+ elseif not (find(oldscript,removesuffix(newname).."$") or find(oldscript,newname.."$")) then
if trace_locating then
report_scripts("invalid new script name")
end
else
- local newdata = io.loaddata(newscript)
+ local newdata = loaddata(newscript)
if newdata then
if trace_locating then
report_scripts("old script content replaced by new content: %s",oldscript)
end
- io.savedata(oldscript,newdata)
+ savedata(oldscript,newdata)
break
elseif trace_locating then
report_scripts("unable to load new script")
diff --git a/Master/texmf-dist/tex/context/base/mkiv/data-bin.lua b/Master/texmf-dist/tex/context/base/mkiv/data-bin.lua
index 1d1e8b74959..2bac901ea47 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/data-bin.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/data-bin.lua
@@ -6,22 +6,25 @@ if not modules then modules = { } end modules ['data-bin'] = {
license = "see context related readme files"
}
-local resolvers = resolvers
+local resolvers = resolvers
local methodhandler = resolvers.methodhandler
+local notfound = resolvers.loaders.notfound
function resolvers.findbinfile(filename,filetype)
return methodhandler('finders',filename,filetype)
end
-function resolvers.openbinfile(filename)
+local function openbinfile(filename)
return methodhandler('loaders',filename) -- a bit weird: load
end
+resolvers.openbinfile = openbinfile
+
function resolvers.loadbinfile(filename,filetype)
local fname = methodhandler('finders',filename,filetype)
if fname and fname ~= "" then
- return resolvers.openbinfile(fname) -- a bit weird: open
+ return openbinfile(fname) -- a bit weird: open
else
- return resolvers.loaders.notfound()
+ return notfound()
end
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/data-con.lua b/Master/texmf-dist/tex/context/base/mkiv/data-con.lua
index c79fca7c5c1..ec2251b3534 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/data-con.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/data-con.lua
@@ -6,6 +6,7 @@ if not modules then modules = { } end modules ['data-con'] = {
license = "see context related readme files"
}
+local setmetatable = setmetatable
local format, lower, gsub = string.format, string.lower, string.gsub
local trace_cache = false trackers.register("resolvers.cache", function(v) trace_cache = v end)
@@ -13,21 +14,28 @@ local trace_containers = false trackers.register("resolvers.containers", functi
local trace_storage = false trackers.register("resolvers.storage", function(v) trace_storage = v end)
--[[ldx--
-<p>Once we found ourselves defining similar cache constructs
-several times, containers were introduced. Containers are used
-to collect tables in memory and reuse them when possible based
-on (unique) hashes (to be provided by the calling function).</p>
+<p>Once we found ourselves defining similar cache constructs several times,
+containers were introduced. Containers are used to collect tables in memory and
+reuse them when possible based on (unique) hashes (to be provided by the calling
+function).</p>
-<p>Caching to disk is disabled by default. Version numbers are
-stored in the saved table which makes it possible to change the
-table structures without bothering about the disk cache.</p>
+<p>Caching to disk is disabled by default. Version numbers are stored in the
+saved table which makes it possible to change the table structures without
+bothering about the disk cache.</p>
-<p>Examples of usage can be found in the font related code.</p>
+<p>Examples of usage can be found in the font related code. This code is not
+ideal but we need it in generic too so we compromise.</p>
--ldx]]--
-containers = containers or { }
-local containers = containers
-containers.usecache = true
+containers = containers or { }
+local containers = containers
+containers.usecache = true
+
+local getwritablepath = caches.getwritablepath
+local getreadablepaths = caches.getreadablepaths
+local cacheiswritable = caches.is_writable
+local loaddatafromcache = caches.loaddata
+local savedataincache = caches.savedata
local report_containers = logs.reporter("resolvers","containers")
@@ -36,11 +44,11 @@ local allocated = { }
local mt = {
__index = function(t,k)
if k == "writable" then
- local writable = caches.getwritablepath(t.category,t.subcategory) or { "." }
+ local writable = getwritablepath(t.category,t.subcategory) or { "." }
t.writable = writable
return writable
elseif k == "readables" then
- local readables = caches.getreadablepaths(t.category,t.subcategory) or { "." }
+ local readables = getreadablepaths(t.category,t.subcategory) or { "." }
t.readables = readables
return readables
end
@@ -64,8 +72,8 @@ function containers.define(category, subcategory, version, enabled)
enabled = enabled,
version = version or math.pi, -- after all, this is TeX
trace = false,
- -- writable = caches.getwritablepath and caches.getwritablepath (category,subcategory) or { "." },
- -- readables = caches.getreadablepaths and caches.getreadablepaths(category,subcategory) or { "." },
+ -- writable = getwritablepath and getwritablepath (category,subcategory) or { "." },
+ -- readables = getreadablepaths and getreadablepaths(category,subcategory) or { "." },
}
setmetatable(s,mt)
c[subcategory] = s
@@ -75,7 +83,7 @@ function containers.define(category, subcategory, version, enabled)
end
function containers.is_usable(container,name)
- return container.enabled and caches and caches.is_writable(container.writable, name)
+ return container.enabled and caches and cacheiswritable(container.writable, name)
end
function containers.is_valid(container,name)
@@ -91,7 +99,7 @@ function containers.read(container,name)
local storage = container.storage
local stored = storage[name]
if not stored and container.enabled and caches and containers.usecache then
- stored = caches.loaddata(container.readables,name,container.writable)
+ stored = loaddatafromcache(container.readables,name,container.writable)
if stored and stored.cache_version == container.version then
if trace_cache or trace_containers then
report_containers("action %a, category %a, name %a","load",container.subcategory,name)
@@ -108,17 +116,20 @@ function containers.read(container,name)
return stored
end
-function containers.write(container, name, data)
+function containers.write(container, name, data, fast)
if data then
data.cache_version = container.version
if container.enabled and caches then
- local unique, shared = data.unique, data.shared
- data.unique, data.shared = nil, nil
- caches.savedata(container.writable, name, data)
+ local unique = data.unique
+ local shared = data.shared
+ data.unique = nil
+ data.shared = nil
+ savedataincache(container.writable, name, data, fast)
if trace_cache or trace_containers then
report_containers("action %a, category %a, name %a","save",container.subcategory,name)
end
- data.unique, data.shared = unique, shared
+ data.unique = unique
+ data.shared = shared
end
if trace_cache or trace_containers then
report_containers("action %a, category %a, name %a","store",container.subcategory,name)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/data-crl.lua b/Master/texmf-dist/tex/context/base/mkiv/data-crl.lua
index dec9972f186..bdc5cf5308e 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/data-crl.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/data-crl.lua
@@ -26,7 +26,7 @@ local runner = sandbox.registerrunner {
name = "curl resolver",
method = "execute",
program = "curl",
- template = "--silent --insecure --create-dirs --output %cachename% %original%",
+ template = '--silent --insecure --create-dirs --output "%cachename%" "%original%"',
checkers = {
cachename = "cache",
original = "url",
diff --git a/Master/texmf-dist/tex/context/base/mkiv/data-env.lua b/Master/texmf-dist/tex/context/base/mkiv/data-env.lua
index 1b31caab65c..53f0c27cc27 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/data-env.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/data-env.lua
@@ -7,7 +7,7 @@ if not modules then modules = { } end modules ['data-env'] = {
}
local lower, gsub = string.lower, string.gsub
-local next = next
+local next, rawget = next, rawget
local resolvers = resolvers
@@ -94,13 +94,13 @@ local relations = allocate { -- todo: handlers also here
mp = {
names = { "mp" },
variable = 'MPINPUTS',
- suffixes = { 'mp', 'mpvi', 'mpiv', 'mpii' },
+ suffixes = { 'mp', 'mpvi', 'mpiv', 'mpxl', 'mpii' },
usertype = true,
},
tex = {
names = { "tex" },
variable = 'TEXINPUTS',
- suffixes = { "tex", "mkvi", "mkiv", "mkii", "cld", "lfg", "xml" }, -- known suffixes have less lookups
+ suffixes = { "tex", "mkiv", "mkvi", "mkxl", "mklx", "mkii", "cld", "lfg", "xml" }, -- known suffixes have less lookups
usertype = true,
},
icc = {
diff --git a/Master/texmf-dist/tex/context/base/mkiv/data-exp.lua b/Master/texmf-dist/tex/context/base/mkiv/data-exp.lua
index ce7f952228b..98c2f6839f9 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/data-exp.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/data-exp.lua
@@ -198,7 +198,7 @@ local function expandedhome()
return usedhomedir
end
-local dohome = ((P("~")+P("$HOME")+P("%HOME%"))/expandedhome)^0
+local dohome = ((P("~") + P("$HOME") + P("%HOME%")) / expandedhome)^0
local cleanup = Cs(donegation * dohome * doslashes)
resolvers.cleanpath = function(str)
@@ -423,7 +423,7 @@ local function scan(files,remap,spec,path,n,m,r,onlyone,tolerant)
return files, remap, n, m, r
end
-function resolvers.scanfiles(path,branch,usecache,onlyonce,tolerant)
+local function scanfiles(path,branch,usecache,onlyonce,tolerant)
local realpath = resolveprefix(path)
if usecache then
local content = fullcache[realpath]
@@ -480,8 +480,10 @@ function resolvers.scanfiles(path,branch,usecache,onlyonce,tolerant)
return content
end
+resolvers.scanfiles = scanfiles
+
function resolvers.simplescanfiles(path,branch,usecache)
- return resolvers.scanfiles(path,branch,usecache,true,true) -- onlyonce
+ return scanfiles(path,branch,usecache,true,true) -- onlyonce
end
function resolvers.scandata()
diff --git a/Master/texmf-dist/tex/context/base/mkiv/data-fil.lua b/Master/texmf-dist/tex/context/base/mkiv/data-fil.lua
index b699fc9e38f..bbcc954b2ea 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/data-fil.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/data-fil.lua
@@ -6,48 +6,57 @@ if not modules then modules = { } end modules ['data-fil'] = {
license = "see context related readme files"
}
+local ioopen = io.open
+local isdir = lfs.isdir
+
local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end)
local report_files = logs.reporter("resolvers","files")
-local resolvers = resolvers
-local resolveprefix = resolvers.resolve
+local resolvers = resolvers
+local resolveprefix = resolvers.resolve
+local findfile = resolvers.findfile
+local scanfiles = resolvers.scanfiles
+local registerfilehash = resolvers.registerfilehash
+local appendhash = resolvers.appendhash
-local finders, openers, loaders, savers = resolvers.finders, resolvers.openers, resolvers.loaders, resolvers.savers
-local locators, hashers, generators, concatinators = resolvers.locators, resolvers.hashers, resolvers.generators, resolvers.concatinators
+local loadcachecontent = caches.loadcontent
-local checkgarbage = utilities.garbagecollector and utilities.garbagecollector.check
+local checkgarbage = utilities.garbagecollector and utilities.garbagecollector.check
-function locators.file(specification)
+function resolvers.locators.file(specification)
local filename = specification.filename
local realname = resolveprefix(filename) -- no shortcut
- if realname and realname ~= '' and lfs.isdir(realname) then
+ if realname and realname ~= '' and isdir(realname) then
if trace_locating then
report_files("file locator %a found as %a",filename,realname)
end
- resolvers.appendhash('file',filename,true) -- cache
+ appendhash('file',filename,true) -- cache
elseif trace_locating then
report_files("file locator %a not found",filename)
end
end
-function hashers.file(specification)
+function resolvers.hashers.file(specification)
local pathname = specification.filename
- local content = caches.loadcontent(pathname,'files')
- resolvers.registerfilehash(pathname,content,content==nil)
+ local content = loadcachecontent(pathname,'files')
+ registerfilehash(pathname,content,content==nil)
end
-function generators.file(specification)
+function resolvers.generators.file(specification)
local pathname = specification.filename
- local content = resolvers.scanfiles(pathname,false,true) -- scan once
- resolvers.registerfilehash(pathname,content,true)
+ local content = scanfiles(pathname,false,true) -- scan once
+ registerfilehash(pathname,content,true)
end
-concatinators.file = file.join
+resolvers.concatinators.file = file.join
+
+local finders = resolvers.finders
+local notfound = finders.notfound
function finders.file(specification,filetype)
local filename = specification.filename
- local foundname = resolvers.findfile(filename,filetype)
+ local foundname = findfile(filename,filetype)
if foundname and foundname ~= "" then
if trace_locating then
report_files("file finder: %a found",filename)
@@ -57,42 +66,64 @@ function finders.file(specification,filetype)
if trace_locating then
report_files("file finder: %a not found",filename)
end
- return finders.notfound()
+ return notfound()
end
end
-- The default textopener will be overloaded later on.
-function openers.helpers.textopener(tag,filename,f)
+local openers = resolvers.openers
+local notfound = openers.notfound
+local overloaded = false
+
+local function textopener(tag,filename,f)
return {
- reader = function() return f:read () end,
- close = function() logs.show_close(filename) return f:close() end,
+ reader = function() return f:read () end,
+ close = function() return f:close() end,
}
end
+function openers.helpers.textopener(...)
+ return textopener(...)
+end
+
+function openers.helpers.settextopener(opener)
+ if overloaded then
+ report_files("file opener: %s overloaded","already")
+ else
+ if trace_locating then
+ report_files("file opener: %s overloaded","once")
+ end
+ overloaded = true
+ textopener = opener
+ end
+end
+
function openers.file(specification,filetype)
local filename = specification.filename
if filename and filename ~= "" then
- local f = io.open(filename,"r")
+ local f = ioopen(filename,"r")
if f then
if trace_locating then
report_files("file opener: %a opened",filename)
end
- return openers.helpers.textopener("file",filename,f)
+ return textopener("file",filename,f)
end
end
if trace_locating then
report_files("file opener: %a not found",filename)
end
- return openers.notfound()
+ return notfound()
end
+local loaders = resolvers.loaders
+local notfound = loaders.notfound
+
function loaders.file(specification,filetype)
local filename = specification.filename
if filename and filename ~= "" then
- local f = io.open(filename,"rb")
+ local f = ioopen(filename,"rb")
if f then
- logs.show_load(filename)
if trace_locating then
report_files("file loader: %a loaded",filename)
end
@@ -109,5 +140,5 @@ function loaders.file(specification,filetype)
if trace_locating then
report_files("file loader: %a not found",filename)
end
- return loaders.notfound()
+ return notfound()
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/data-ini.lua b/Master/texmf-dist/tex/context/base/mkiv/data-ini.lua
index 09357368ca9..0fe70b5f11a 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/data-ini.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/data-ini.lua
@@ -10,11 +10,11 @@ local next, type, getmetatable, rawset = next, type, getmetatable, rawset
local gsub, find, gmatch, char = string.gsub, string.find, string.gmatch, string.char
local filedirname, filebasename, filejoin = file.dirname, file.basename, file.join
local ostype, osname, osuname, ossetenv, osgetenv = os.type, os.name, os.uname, os.setenv, os.getenv
+local sortedpairs = table.sortedpairs
local P, S, R, C, Cs, Cc, lpegmatch = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cs, lpeg.Cc, lpeg.match
local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end)
-local trace_detail = false trackers.register("resolvers.details", function(v) trace_detail = v end)
local trace_expansions = false trackers.register("resolvers.expansions", function(v) trace_expansions = v end)
local report_initialization = logs.reporter("resolvers","initialization")
@@ -333,7 +333,7 @@ if ostype == "unix" then
rawset(t,k,v)
end
local colon = P(":")
- for k, v in table.sortedpairs(prefixes) do
+ for k, v in sortedpairs(prefixes) do
if p then
p = P(k) + p
else
diff --git a/Master/texmf-dist/tex/context/base/mkiv/data-lst.lua b/Master/texmf-dist/tex/context/base/mkiv/data-lst.lua
index f061393e5a3..f349409e41a 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/data-lst.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/data-lst.lua
@@ -9,19 +9,26 @@ if not modules then modules = { } end modules ['data-lst'] = {
-- used in mtxrun, can be loaded later .. todo
local type = type
-local concat, sortedhash = table.concat,table.sortedhash
+local sortedhash = table.sortedhash
+local isdir = lfs.isdir
-local resolvers = resolvers
-local listers = resolvers.listers or { }
-resolvers.listers = listers
+local resolvers = resolvers
+local listers = resolvers.listers or { }
+resolvers.listers = listers
-local resolveprefix = resolvers.resolve
+local resolveprefix = resolvers.resolve
+local configurationfiles = resolvers.configurationfiles
+local expandedpathfromlist = resolvers.expandedpathfromlist
+local splitpath = resolvers.splitpath
+local knownvariables = resolvers.knownvariables
-local report_lists = logs.reporter("resolvers","lists")
-local report_resolved = logs.reporter("system","resolved")
+local report_lists = logs.reporter("resolvers","lists")
+local report_resolved = logs.reporter("system","resolved")
local function tabstr(str)
- if type(str) == 'table' then
+ if not str then
+ return "unset"
+ elseif type(str) == 'table' then
return concat(str," | ")
else
return str
@@ -32,23 +39,23 @@ function listers.variables(pattern)
local result = resolvers.knownvariables(pattern)
for key, value in sortedhash(result) do
report_lists(key)
- report_lists(" env: %s",tabstr(value.environment or "unset"))
- report_lists(" var: %s",tabstr(value.variable or "unset"))
- report_lists(" exp: %s",tabstr(value.expansion or "unset"))
- report_lists(" res: %s",tabstr(value.resolved or "unset"))
+ report_lists(" env: %s",tabstr(value.environment))
+ report_lists(" var: %s",tabstr(value.variable))
+ report_lists(" exp: %s",tabstr(value.expansion))
+ report_lists(" res: %s",tabstr(value.resolved))
end
end
function listers.configurations()
- local configurations = resolvers.configurationfiles()
+ local configurations = configurationfiles()
for i=1,#configurations do
report_resolved("file : %s",resolveprefix(configurations[i]))
end
report_resolved("")
- local list = resolvers.expandedpathfromlist(resolvers.splitpath(resolvers.luacnfspec))
+ local list = expandedpathfromlist(splitpath(resolvers.luacnfspec))
for i=1,#list do
local li = resolveprefix(list[i])
- if lfs.isdir(li) then
+ if isdir(li) then
report_resolved("path - %s",li)
else
report_resolved("path + %s",li)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/data-lua.lua b/Master/texmf-dist/tex/context/base/mkiv/data-lua.lua
index 3022ae55037..03d899e846b 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/data-lua.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/data-lua.lua
@@ -10,8 +10,7 @@ if not modules then modules = { } end modules ['data-lua'] = {
local package, lpeg = package, lpeg
-local gsub = string.gsub
-local concat = table.concat
+local loadfile = loadfile
local addsuffix = file.addsuffix
local P, S, Cs, lpegmatch = lpeg.P, lpeg.S, lpeg.Cs, lpeg.match
@@ -25,6 +24,8 @@ local methods = helpers.methods or { }
local resolvers = resolvers
local resolveprefix = resolvers.resolve
+local expandedpaths = resolvers.expandedpathlistfromvariable
+local findfile = resolvers.findfile
helpers.report = logs.reporter("resolvers","libraries")
@@ -50,9 +51,9 @@ function helpers.cleanpath(path) -- hm, don't we have a helper for this?
return resolveprefix(lpegmatch(pattern,path))
end
-local loadedaslib = helpers.loadedaslib
-local registerpath = helpers.registerpath
-local lualibfile = helpers.lualibfile
+local loadedaslib = helpers.loadedaslib
+local registerpath = helpers.registerpath
+local lualibfile = helpers.lualibfile
local luaformatpaths
local libformatpaths
@@ -61,7 +62,7 @@ local function getluaformatpaths()
if not luaformatpaths then
luaformatpaths = { }
for i=1,#luaformats do
- registerpath("lua format","lua",luaformatpaths,resolvers.expandedpathlistfromvariable(luaformats[i]))
+ registerpath("lua format","lua",luaformatpaths,expandedpaths(luaformats[i]))
end
end
return luaformatpaths
@@ -71,7 +72,7 @@ local function getlibformatpaths()
if not libformatpaths then
libformatpaths = { }
for i=1,#libformats do
- registerpath("lib format","lib",libformatpaths,resolvers.expandedpathlistfromvariable(libformats[i]))
+ registerpath("lib format","lib",libformatpaths,expandedpaths(libformats[i]))
end
end
return libformatpaths
@@ -81,8 +82,8 @@ local function loadedbyformat(name,rawname,suffixes,islib,what)
local trace = helpers.trace
local report = helpers.report
for i=1,#suffixes do -- so we use findfile and not a lookup loop
- local format = suffixes[i]
- local resolved = resolvers.findfile(name,format) or ""
+ local format = suffixes[i]
+ local resolved = findfile(name,format) or ""
if trace then
report("%s format, identifying %a using format %a",what,name,format)
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/data-met.lua b/Master/texmf-dist/tex/context/base/mkiv/data-met.lua
index bb892957733..8004ad2cdac 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/data-met.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/data-met.lua
@@ -6,9 +6,12 @@ if not modules then modules = { } end modules ['data-met'] = {
license = "see context related readme files"
}
-local find, format = string.find, string.format
-local sequenced = table.sequenced
+local type = type
+local find = string.find
local addurlscheme, urlhashed = url.addscheme, url.hashed
+local collapsepath, joinfile = file.collapsepath, file.join
+
+local report_methods = logs.reporter("resolvers","methods")
local trace_locating = false
local trace_methods = false
@@ -16,31 +19,38 @@ local trace_methods = false
trackers.register("resolvers.locating", function(v) trace_methods = v end)
trackers.register("resolvers.methods", function(v) trace_methods = v end)
---~ trace_methods = true
-
-local report_methods = logs.reporter("resolvers","methods")
-
-local allocate = utilities.storage.allocate
-
-local resolvers = resolvers
+local allocate = utilities.storage.allocate
+local resolvers = resolvers
local registered = { }
local function splitmethod(filename) -- todo: filetype in specification
if not filename then
- return { scheme = "unknown", original = filename }
+ return {
+ scheme = "unknown",
+ original = filename,
+ }
end
if type(filename) == "table" then
return filename -- already split
end
- filename = file.collapsepath(filename,".") -- hm, we should keep ./ in some cases
-
+ filename = collapsepath(filename,".") -- hm, we should keep ./ in some cases
if not find(filename,"://",1,true) then
- return { scheme = "file", path = filename, original = filename, filename = filename }
+ return {
+ scheme = "file",
+ path = filename,
+ original = filename,
+ filename = filename,
+ }
end
- local specification = url.hashed(filename)
+ local specification = urlhashed(filename)
if not specification.scheme or specification.scheme == "" then
- return { scheme = "file", path = filename, original = filename, filename = filename }
+ return {
+ scheme = "file",
+ path = filename,
+ original = filename,
+ filename = filename,
+ }
else
return specification
end
@@ -53,7 +63,7 @@ end
-- if type(filename) == "table" then
-- return filename -- already split
-- end
--- return url.hashed(filename)
+-- return urlhashed(filename)
-- end
resolvers.splitmethod = splitmethod -- bad name but ok
@@ -64,11 +74,12 @@ resolvers.splitmethod = splitmethod -- bad name but ok
local function methodhandler(what,first,...) -- filename can be nil or false
local method = registered[what]
if method then
- local how, namespace = method.how, method.namespace
+ local how = method.how
+ local namespace = method.namespace
if how == "uri" or how == "url" then
local specification = splitmethod(first)
- local scheme = specification.scheme
- local resolver = namespace and namespace[scheme]
+ local scheme = specification.scheme
+ local resolver = namespace and namespace[scheme]
if resolver then
if trace_methods then
report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,scheme,first)
@@ -112,7 +123,10 @@ end
resolvers.methodhandler = methodhandler
function resolvers.registermethod(name,namespace,how)
- registered[name] = { how = how or "tag", namespace = namespace }
+ registered[name] = {
+ how = how or "tag",
+ namespace = namespace
+ }
namespace["byscheme"] = function(scheme,filename,...)
if scheme == "file" then
return methodhandler(name,filename,...)
@@ -122,7 +136,7 @@ function resolvers.registermethod(name,namespace,how)
end
end
-local concatinators = allocate { notfound = file.join } -- concatinate paths
+local concatinators = allocate { notfound = joinfile } -- concatinate paths
local locators = allocate { notfound = function() end } -- locate databases
local hashers = allocate { notfound = function() end } -- load databases
local generators = allocate { notfound = function() end } -- generate databases
diff --git a/Master/texmf-dist/tex/context/base/mkiv/data-out.lua b/Master/texmf-dist/tex/context/base/mkiv/data-out.lua
index 11304c2ced3..6cd02a22e2e 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/data-out.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/data-out.lua
@@ -6,13 +6,12 @@ if not modules then modules = { } end modules ['data-out'] = {
license = "see context related readme files"
}
-local allocate = utilities.storage.allocate
-local resolvers = resolvers
+local allocate = utilities.storage.allocate
+local resolvers = resolvers
local registermethod = resolvers.registermethod
-local savers = allocate { helpers = { } }
-
-resolvers.savers = savers
+local savers = allocate { helpers = { } }
+resolvers.savers = savers
registermethod("savers", savers, "uri")
diff --git a/Master/texmf-dist/tex/context/base/mkiv/data-pre.lua b/Master/texmf-dist/tex/context/base/mkiv/data-pre.lua
index 5e3020b7065..f7df8b91870 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/data-pre.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/data-pre.lua
@@ -25,6 +25,8 @@ if not modules then modules = { } end modules ['data-pre'] = {
-- version : operating system version
-- release : operating system release
+local insert, remove = table.insert, table.remove
+
local resolvers = resolvers
local prefixes = resolvers.prefixes
@@ -121,8 +123,10 @@ prefixes.path = prefixes.pathname
-- This one assumes that inputstack is set (used in the tex loader). It is a momentary resolve
-- as the top of the input stack changes.
+local inputstack = { }
+local stackpath = resolvers.stackpath
+
local function toppath()
- local inputstack = resolvers.inputstack -- dependency, actually the code should move but it's
if not inputstack then -- more convenient to keep it here
return "."
end
@@ -139,7 +143,7 @@ end
-- stucture.
local function jobpath()
- local path = resolvers.stackpath()
+ local path = stackpath()
if not path or path == "" then
return "."
else
@@ -147,8 +151,18 @@ local function jobpath()
end
end
-resolvers.toppath = toppath
-resolvers.jobpath = jobpath
+local function pushinputname(name)
+ insert(inputstack,name)
+end
+
+local function popinputname(name)
+ return remove(inputstack)
+end
+
+resolvers.toppath = toppath
+resolvers.jobpath = jobpath
+resolvers.pushinputname = pushinputname
+resolvers.popinputname = popinputname
-- This hook sit into the resolver:
diff --git a/Master/texmf-dist/tex/context/base/mkiv/data-res.lua b/Master/texmf-dist/tex/context/base/mkiv/data-res.lua
index 0c2735fc274..8afc09b9792 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/data-res.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/data-res.lua
@@ -10,7 +10,9 @@ if not modules then modules = { } end modules ['data-res'] = {
local gsub, find, lower, upper, match, gmatch = string.gsub, string.find, string.lower, string.upper, string.match, string.gmatch
local concat, insert, remove = table.concat, table.insert, table.remove
-local next, type, rawget = next, type, rawget
+local next, type, rawget, loadfile = next, type, rawget, loadfile
+local mergedtable = table.merged
+
local os = os
local P, S, R, C, Cc, Cs, Ct, Carg = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Carg
@@ -30,6 +32,8 @@ local is_qualified_path = file.is_qualified_path
local allocate = utilities.storage.allocate
local settings_to_array = utilities.parsers.settings_to_array
+local urlhasscheme = url.hasscheme
+
local getcurrentdir = lfs.currentdir
local isfile = lfs.isfile
local isdir = lfs.isdir
@@ -38,7 +42,7 @@ local setmetatableindex = table.setmetatableindex
local luasuffixes = utilities.lua.suffixes
local trace_locating = false trackers .register("resolvers.locating", function(v) trace_locating = v end)
-local trace_detail = false trackers .register("resolvers.details", function(v) trace_detail = v end)
+local trace_details = false trackers .register("resolvers.details", function(v) trace_details = v end)
local trace_expansions = false trackers .register("resolvers.expansions", function(v) trace_expansions = v end)
local trace_paths = false trackers .register("resolvers.paths", function(v) trace_paths = v end)
local resolve_otherwise = true directives.register("resolvers.otherwise", function(v) resolve_otherwise = v end)
@@ -63,11 +67,19 @@ local ostype, osname, osenv, ossetenv, osgetenv = os.type, os.name, os.env, os.s
resolvers.cacheversion = "1.100"
resolvers.configbanner = ""
resolvers.homedir = environment.homedir
-resolvers.criticalvars = allocate { "SELFAUTOLOC", "SELFAUTODIR", "SELFAUTOPARENT", "TEXMFCNF", "TEXMF", "TEXOS" }
resolvers.luacnfname = "texmfcnf.lua"
resolvers.luacnffallback = "contextcnf.lua"
resolvers.luacnfstate = "unknown"
+local criticalvars = {
+ "SELFAUTOLOC",
+ "SELFAUTODIR",
+ "SELFAUTOPARENT",
+ "TEXMFCNF",
+ "TEXMF",
+ "TEXOS",
+}
+
-- The web2c tex binaries as well as kpse have built in paths for the configuration
-- files and there can be a depressing truckload of them. This is actually the weak
-- spot of a distribution. So we don't want:
@@ -145,14 +157,27 @@ local suffixmap = resolvers.suffixmap
resolvers.defaultsuffixes = { "tex" } -- "mkiv", "cld" -- too tricky
-local instance = nil -- the current one (fast access)
+local instance = nil -- the current one (fast access)
+
+-- forward declarations
+
+local variable
+local expansion
+local setenv
+local getenv
+
+-- done
+
+local formatofsuffix = resolvers.formatofsuffix
+local splitpath = resolvers.splitpath
+local splitmethod = resolvers.splitmethod
-- An instance has an environment (coming from the outside, kept raw), variables
-- (coming from the configuration file), and expansions (variables with nested
-- variables replaced). One can push something into the outer environment and
-- its internal copy, but only the later one will be the raw unprefixed variant.
-function resolvers.setenv(key,value,raw)
+setenv = function(key,value,raw)
if instance then
-- this one will be consulted first when we stay inside
-- the current environment (prefixes are not resolved here)
@@ -167,7 +192,7 @@ end
-- Beware we don't want empty here as this one can be called early on
-- and therefore we use rawget.
-local function getenv(key)
+getenv = function(key)
local value = rawget(instance.environment,key)
if value and value ~= "" then
return value
@@ -178,115 +203,121 @@ local function getenv(key)
end
resolvers.getenv = getenv
-resolvers.env = getenv
+resolvers.setenv = setenv
-- We are going to use some metatable trickery where we backtrack from
-- expansion to variable to environment.
-local function resolvevariable(k)
- return instance.expansions[k]
-end
-
local dollarstripper = lpeg.stripper("$")
local inhibitstripper = P("!")^0 * Cs(P(1)^0)
-local somevariable = P("$") / ""
-local somekey = C(R("az","AZ","09","__","--")^1)
-local somethingelse = P(";") * ((1-S("!{}/\\"))^1 * P(";") / "")
- + P(";") * (P(";") / "")
- + P(1)
-local variableexpander = Cs( (somevariable * (somekey/resolvevariable) + somethingelse)^1 )
+local expandedvariable, resolvedvariable do
-local cleaner = P("\\") / "/" + P(";") * S("!{}/\\")^0 * P(";")^1 / ";"
-local variablecleaner = Cs((cleaner + P(1))^0)
+ local function resolveinstancevariable(k)
+ return instance.expansions[k]
+ end
-local somevariable = R("az","AZ","09","__","--")^1 / resolvevariable
-local variable = (P("$")/"") * (somevariable + (P("{")/"") * somevariable * (P("}")/""))
-local variableresolver = Cs((variable + P(1))^0)
+ local p_variable = P("$") / ""
+ local p_key = C(R("az","AZ","09","__","--")^1)
+ local p_whatever = P(";") * ((1-S("!{}/\\"))^1 * P(";") / "")
+ + P(";") * (P(";") / "")
+ + P(1)
+ local variableexpander = Cs( (p_variable * (p_key/resolveinstancevariable) + p_whatever)^1 )
-local function expandedvariable(var)
- return lpegmatch(variableexpander,var) or var
-end
+ local p_cleaner = P("\\") / "/" + P(";") * S("!{}/\\")^0 * P(";")^1 / ";"
+ local variablecleaner = Cs((p_cleaner + P(1))^0)
-function resolvers.reset()
+ local p_variable = R("az","AZ","09","__","--")^1 / resolveinstancevariable
+ local p_variable = (P("$")/"") * (p_variable + (P("{")/"") * p_variable * (P("}")/""))
+ local variableresolver = Cs((p_variable + P(1))^0)
- -- normally we only need one instance but for special cases we can (re)load one so
- -- we stick to this model.
+ expandedvariable = function(var)
+ return lpegmatch(variableexpander,var) or var
+ end
- if trace_locating then
- report_resolving("creating instance")
- end
-
- local environment = { }
- local variables = { }
- local expansions = { }
- local order = { }
-
- instance = {
- environment = environment,
- variables = variables,
- expansions = expansions,
- order = order,
- files = { },
- setups = { },
- found = { },
- foundintrees = { },
- hashes = { },
- hashed = { },
- pathlists = false,-- delayed
- specification = { },
- lists = { },
- data = { }, -- only for loading
- fakepaths = { },
- remember = true,
- diskcache = true,
- renewcache = false,
- renewtree = false,
- loaderror = false,
- savelists = true,
- pattern = nil, -- lists
- force_suffixes = true,
- pathstack = { },
- }
-
- setmetatableindex(variables,function(t,k)
- local v
- for i=1,#order do
- v = order[i][k]
- if v ~= nil then
- t[k] = v
- return v
+ function resolvers.reset()
+
+ -- normally we only need one instance but for special cases we can (re)load one so
+ -- we stick to this model.
+
+ if trace_locating then
+ report_resolving("creating instance")
+ end
+
+ local environment = { }
+ local variables = { }
+ local expansions = { }
+ local order = { }
+
+ instance = {
+ environment = environment,
+ variables = variables,
+ expansions = expansions,
+ order = order,
+ files = { },
+ setups = { },
+ found = { },
+ foundintrees = { },
+ hashes = { },
+ hashed = { },
+ pathlists = false,-- delayed
+ specification = { },
+ lists = { },
+ data = { }, -- only for loading
+ fakepaths = { },
+ remember = true,
+ diskcache = true,
+ renewcache = false,
+ renewtree = false,
+ loaderror = false,
+ savelists = true,
+ pattern = nil, -- lists
+ force_suffixes = true,
+ pathstack = { },
+ }
+
+ setmetatableindex(variables,function(t,k)
+ local v
+ for i=1,#order do
+ v = order[i][k]
+ if v ~= nil then
+ t[k] = v
+ return v
+ end
end
- end
- if v == nil then
- v = ""
- end
- t[k] = v
- return v
- end)
+ if v == nil then
+ v = ""
+ end
+ t[k] = v
+ return v
+ end)
- setmetatableindex(environment, function(t,k)
- local v = osgetenv(k)
- if v == nil then
- v = variables[k]
- end
- if v ~= nil then
- v = checkedvariable(v) or ""
- end
- v = resolvers.repath(v) -- for taco who has a : separated osfontdir
- t[k] = v
- return v
- end)
+ local repath = resolvers.repath
- setmetatableindex(expansions, function(t,k)
- local v = environment[k]
- if type(v) == "string" then
- v = lpegmatch(variableresolver,v)
- v = lpegmatch(variablecleaner,v)
- end
- t[k] = v
- return v
- end)
+ setmetatableindex(environment, function(t,k)
+ local v = osgetenv(k)
+ if v == nil then
+ v = variables[k]
+ end
+ if v ~= nil then
+ v = checkedvariable(v) or ""
+ end
+ v = repath(v) -- for taco who has a : separated osfontdir
+ t[k] = v
+ return v
+ end)
+
+ setmetatableindex(expansions, function(t,k)
+ local v = environment[k]
+ if type(v) == "string" then
+ v = lpegmatch(variableresolver,v)
+ v = lpegmatch(variablecleaner,v)
+ end
+ t[k] = v
+ return v
+ end)
+
+ end
end
@@ -305,40 +336,44 @@ local function reset_caches()
instance.pathlists = false
end
-local slash = P("/")
+local makepathexpression do
-local pathexpressionpattern = Cs ( -- create lpeg instead (2013/2014)
- Cc("^") * (
- Cc("%") * S(".-")
- + slash^2 * P(-1) / "/.*"
- -- + slash^2 / "/.-/"
- -- + slash^2 / "/[^/]*/*" -- too general
- + slash^2 / "/"
- + (1-slash) * P(-1) * Cc("/")
- + P(1)
- )^1 * Cc("$") -- yes or no $
-)
+ local slash = P("/")
-local cache = { }
+ local pathexpressionpattern = Cs ( -- create lpeg instead (2013/2014)
+ Cc("^") * (
+ Cc("%") * S(".-")
+ + slash^2 * P(-1) / "/.*"
+ -- + slash^2 / "/.-/"
+ -- + slash^2 / "/[^/]*/*" -- too general
+ + slash^2 / "/"
+ + (1-slash) * P(-1) * Cc("/")
+ + P(1)
+ )^1 * Cc("$") -- yes or no $
+ )
-local function makepathexpression(str)
- if str == "." then
- return "^%./$"
- else
- local c = cache[str]
- if not c then
- c = lpegmatch(pathexpressionpattern,str)
- cache[str] = c
+ local cache = { }
+
+ makepathexpression = function(str)
+ if str == "." then
+ return "^%./$"
+ else
+ local c = cache[str]
+ if not c then
+ c = lpegmatch(pathexpressionpattern,str)
+ cache[str] = c
+ end
+ return c
end
- return c
end
+
end
local function reportcriticalvariables(cnfspec)
if trace_locating then
- for i=1,#resolvers.criticalvars do
- local k = resolvers.criticalvars[i]
- local v = resolvers.getenv(k) or "unknown" -- this one will not resolve !
+ for i=1,#criticalvars do
+ local k = criticalvars[i]
+ local v = getenv(k) or "unknown" -- this one will not resolve !
report_resolving("variable %a set to %a",k,v)
end
report_resolving()
@@ -361,7 +396,7 @@ local function identify_configuration_files()
resolvers.luacnfstate = "environment"
end
reportcriticalvariables(cnfspec)
- local cnfpaths = expandedpathfromlist(resolvers.splitpath(cnfspec))
+ local cnfpaths = expandedpathfromlist(splitpath(cnfspec))
local function locatecnf(luacnfname,kind)
for i=1,#cnfpaths do
@@ -398,6 +433,8 @@ end
local function load_configuration_files()
local specification = instance.specification
+ local setups = instance.setups
+ local order = instance.order
if #specification > 0 then
local luacnfname = resolvers.luacnfname
for i=1,#specification do
@@ -407,7 +444,6 @@ local function load_configuration_files()
local realname = resolveprefix(filename) -- no shortcut
local blob = loadfile(realname)
if blob then
- local setups = instance.setups
local data = blob()
local parent = data and data.parent
if parent then
@@ -418,7 +454,7 @@ local function load_configuration_files()
local parentdata = blob()
if parentdata then
report_resolving("loading configuration file %a",filename)
- data = table.merged(parentdata,data)
+ data = mergedtable(parentdata,data)
end
end
end
@@ -454,7 +490,7 @@ local function load_configuration_files()
-- we push the value into the main environment (osenv) so
-- that it takes precedence over the default one and therefore
-- also over following definitions
- resolvers.setenv("TEXMFCNF",cnfspec) -- resolves prefixes
+ setenv("TEXMFCNF",cnfspec) -- resolves prefixes
-- we now identify and load the specified configuration files
instance.specification = { }
identify_configuration_files()
@@ -476,7 +512,7 @@ local function load_configuration_files()
elseif trace_locating then
report_resolving("skipping configuration file %a (no valid format)",filename)
end
- instance.order[#instance.order+1] = instance.setups[pathname]
+ order[#order+1] = setups[pathname]
if instance.loaderror then
break
end
@@ -486,6 +522,13 @@ local function load_configuration_files()
end
end
+-- forward declarations:
+
+local expandedpathlist
+local unexpandedpathlist
+
+-- done
+
function resolvers.configurationfiles()
return instance.specification or { }
end
@@ -507,7 +550,7 @@ end
local function locate_file_databases()
-- todo: cache:// and tree:// (runtime)
- local texmfpaths = resolvers.expandedpathlist("TEXMF")
+ local texmfpaths = expandedpathlist("TEXMF")
if #texmfpaths > 0 then
for i=1,#texmfpaths do
local path = collapsepath(texmfpaths[i])
@@ -516,7 +559,7 @@ local function locate_file_databases()
if stripped ~= "" then
local runtime = stripped == path
path = cleanpath(path)
- local spec = resolvers.splitmethod(stripped)
+ local spec = splitmethod(stripped)
if runtime and (spec.noscheme or spec.scheme == "file") then
stripped = "tree:///" .. stripped
elseif spec.scheme == "cache" or spec.scheme == "file" then
@@ -552,11 +595,13 @@ local function generate_file_databases()
end
local function save_file_databases() -- will become cachers
- for i=1,#instance.hashes do
- local hash = instance.hashes[i]
+ local hashes = instance.hashes
+ local files = instance.files
+ for i=1,#hashes do
+ local hash = hashes[i]
local cachename = hash.name
if hash.cache then
- local content = instance.files[cachename]
+ local content = files[cachename]
caches.collapsecontent(content)
if trace_locating then
report_resolving("saving tree %a",cachename)
@@ -569,8 +614,9 @@ local function save_file_databases() -- will become cachers
end
function resolvers.renew(hashname)
+ local files = instance.files
if hashname and hashname ~= "" then
- local expanded = resolvers.expansion(hashname) or ""
+ local expanded = expansion(hashname) or ""
if expanded ~= "" then
if trace_locating then
report_resolving("identifying tree %a from %a",expanded,hashname)
@@ -588,7 +634,7 @@ function resolvers.renew(hashname)
end
methodhandler('generators',hashname)
-- could be shared
- local content = instance.files[hashname]
+ local content = files[hashname]
caches.collapsecontent(content)
if trace_locating then
report_resolving("saving tree %a",hashname)
@@ -618,35 +664,43 @@ local function load_databases()
end
function resolvers.appendhash(type,name,cache)
- -- safeguard ... tricky as it's actually a bug when seen twice
- if not instance.hashed[name] then
+ local hashed = instance.hashed
+ local hashes = instance.hashes
+ if hashed[name] then
+ -- safeguard ... tricky as it's actually a bug when seen twice
+ else
if trace_locating then
report_resolving("hash %a appended",name)
end
- insert(instance.hashes, { type = type, name = name, cache = cache } )
- instance.hashed[name] = cache
+ insert(hashes, { type = type, name = name, cache = cache } )
+ hashed[name] = cache
end
end
function resolvers.prependhash(type,name,cache)
- -- safeguard ... tricky as it's actually a bug when seen twice
- if not instance.hashed[name] then
+ local hashed = instance.hashed
+ local hashes = instance.hashes
+ if hashed[name] then
+ -- safeguard ... tricky as it's actually a bug when seen twice
+ else
if trace_locating then
report_resolving("hash %a prepended",name)
end
- insert(instance.hashes, 1, { type = type, name = name, cache = cache } )
- instance.hashed[name] = cache
+ insert(hashes, 1, { type = type, name = name, cache = cache } )
+ hashed[name] = cache
end
end
function resolvers.extendtexmfvariable(specification) -- crap, we could better prepend the hash
- local t = resolvers.splitpath(getenv("TEXMF")) -- okay?
- insert(t,1,specification)
- local newspec = concat(t,",") -- not ;
- if instance.environment["TEXMF"] then
- instance.environment["TEXMF"] = newspec
- elseif instance.variables["TEXMF"] then
- instance.variables["TEXMF"] = newspec
+ local environment = instance.environment
+ local variables = instance.variables
+ local texmftrees = splitpath(getenv("TEXMF")) -- okay?
+ insert(texmftrees,1,specification)
+ texmftrees = concat(texmftrees,",") -- not ;
+ if environment["TEXMF"] then
+ environment["TEXMF"] = texmftrees
+ elseif variables["TEXMF"] then
+ variables["TEXMF"] = texmftrees
else
-- weird
end
@@ -654,8 +708,8 @@ function resolvers.extendtexmfvariable(specification) -- crap, we could better p
end
function resolvers.splitexpansions()
- local ie = instance.expansions
- for k,v in next, ie do
+ local expansions = instance.expansions
+ for k, v in next, expansions do
local t, tn, h, p = { }, 0, { }, splitconfigurationpath(v)
for kk=1,#p do
local vv = p[kk]
@@ -665,10 +719,10 @@ function resolvers.splitexpansions()
h[vv] = true
end
end
- if #t > 1 then
- ie[k] = t
+ if tn > 1 then
+ expansions[k] = t
else
- ie[k] = t[1]
+ expansions[k] = t[1]
end
end
end
@@ -682,26 +736,31 @@ function resolvers.datastate()
return caches.contentstate()
end
-function resolvers.variable(name)
+variable = function(name)
+ local variables = instance.variables
local name = name and lpegmatch(dollarstripper,name)
- local result = name and instance.variables[name]
+ local result = name and variables[name]
return result ~= nil and result or ""
end
-function resolvers.expansion(name)
+expansion = function(name)
+ local expansions = instance.expansions
local name = name and lpegmatch(dollarstripper,name)
- local result = name and instance.expansions[name]
+ local result = name and expansions[name]
return result ~= nil and result or ""
end
-function resolvers.unexpandedpathlist(str)
- local pth = resolvers.variable(str)
- local lst = resolvers.splitpath(pth)
+resolvers.variable = variable
+resolvers.expansion = expansion
+
+unexpandedpathlist = function(str)
+ local pth = variable(str)
+ local lst = splitpath(pth)
return expandedpathfromlist(lst)
end
function resolvers.unexpandedpath(str)
- return joinpath(resolvers.unexpandedpathlist(str))
+ return joinpath(unexpandedpathlist(str))
end
function resolvers.pushpath(name)
@@ -736,8 +795,8 @@ end
local done = { }
function resolvers.resetextrapaths()
- local ep = instance.extra_paths
- if not ep then
+ local extra_paths = instance.extra_paths
+ if not extra_paths then
done = { }
instance.extra_paths = { }
elseif #ep > 0 then
@@ -760,8 +819,8 @@ function resolvers.registerextrapath(paths,subpaths)
end
local paths = settings_to_array(paths)
local subpaths = settings_to_array(subpaths)
- local ep = instance.extra_paths or { }
- local oldn = #ep
+ local extra_paths = instance.extra_paths or { }
+ local oldn = #extra_paths
local newn = oldn
local nofpaths = #paths
local nofsubpaths = #subpaths
@@ -774,7 +833,7 @@ function resolvers.registerextrapath(paths,subpaths)
local ps = p .. "/" .. s
if not done[ps] then
newn = newn + 1
- ep[newn] = cleanpath(ps)
+ extra_paths[newn] = cleanpath(ps)
done[ps] = true
end
end
@@ -784,7 +843,7 @@ function resolvers.registerextrapath(paths,subpaths)
local p = paths[i]
if not done[p] then
newn = newn + 1
- ep[newn] = cleanpath(p)
+ extra_paths[newn] = cleanpath(p)
done[p] = true
end
end
@@ -793,17 +852,17 @@ function resolvers.registerextrapath(paths,subpaths)
for i=1,oldn do
for j=1,nofsubpaths do
local s = subpaths[j]
- local ps = ep[i] .. "/" .. s
+ local ps = extra_paths[i] .. "/" .. s
if not done[ps] then
newn = newn + 1
- ep[newn] = cleanpath(ps)
+ extra_paths[newn] = cleanpath(ps)
done[ps] = true
end
end
end
end
if newn > 0 then
- instance.extra_paths = ep -- register paths
+ instance.extra_paths = extra_paths -- register paths
end
if newn ~= oldn then
reset_caches()
@@ -812,8 +871,9 @@ end
function resolvers.pushextrapath(path)
local paths = settings_to_array(path)
- if instance.extra_stack then
- insert(instance.extra_stack,1,paths)
+ local extra_stack = instance.extra_stack
+ if extra_stack then
+ insert(extra_stack,1,paths)
else
instance.extra_stack = { paths }
end
@@ -821,9 +881,10 @@ function resolvers.pushextrapath(path)
end
function resolvers.popextrapath()
- if instance.extra_stack then
+ local extra_stack = instance.extra_stack
+ if extra_stack then
reset_caches()
- return remove(instance.extra_stack,1)
+ return remove(extra_stack,1)
end
end
@@ -856,17 +917,17 @@ local function made_list(instance,list,extra_too)
end
end
if extra_too then
+ local extra_stack = instance.extra_stack
+ local extra_paths = instance.extra_paths
-- first the stacked paths
- local es = instance.extra_stack
- if es and #es > 0 then
- for k=1,#es do
- add(es[k])
+ if extra_stack and #extra_stack > 0 then
+ for k=1,#extra_stack do
+ add(extra_stack[k])
end
end
-- then the extra paths
- local ep = instance.extra_paths
- if ep and #ep > 0 then
- add(ep)
+ if extra_paths and #extra_paths > 0 then
+ add(extra_paths)
end
end
-- last the formal paths
@@ -874,21 +935,7 @@ local function made_list(instance,list,extra_too)
return new
end
-function resolvers.cleanpathlist(str)
- local t = resolvers.expandedpathlist(str)
- if t then
- for i=1,#t do
- t[i] = collapsepath(cleanpath(t[i]))
- end
- end
- return t
-end
-
-function resolvers.expandpath(str)
- return joinpath(resolvers.expandedpathlist(str))
-end
-
-function resolvers.expandedpathlist(str,extra_too)
+expandedpathlist = function(str,extra_too)
if not str then
return { }
elseif instance.savelists then -- hm, what if two cases, with and without extra_too
@@ -896,45 +943,65 @@ function resolvers.expandedpathlist(str,extra_too)
local lists = instance.lists
local lst = lists[str]
if not lst then
- local l = made_list(instance,resolvers.splitpath(resolvers.expansion(str)),extra_too)
+ local l = made_list(instance,splitpath(expansion(str)),extra_too)
lst = expandedpathfromlist(l)
lists[str] = lst
end
return lst
else
- local lst = resolvers.splitpath(resolvers.expansion(str))
+ local lst = splitpath(expansion(str))
return made_list(instance,expandedpathfromlist(lst),extra_too)
end
end
-function resolvers.expandedpathlistfromvariable(str) -- brrr / could also have cleaner ^!! /$ //
+resolvers.expandedpathlist = expandedpathlist
+resolvers.unexpandedpathlist = unexpandedpathlist
+
+function resolvers.cleanpathlist(str)
+ local t = expandedpathlist(str)
+ if t then
+ for i=1,#t do
+ t[i] = collapsepath(cleanpath(t[i]))
+ end
+ end
+ return t
+end
+
+function resolvers.expandpath(str)
+ return joinpath(expandedpathlist(str))
+end
+
+local function expandedpathlistfromvariable(str) -- brrr / could also have cleaner ^!! /$ //
str = lpegmatch(dollarstripper,str)
local tmp = resolvers.variableofformatorsuffix(str)
- return resolvers.expandedpathlist(tmp ~= "" and tmp or str)
+ return expandedpathlist(tmp ~= "" and tmp or str)
end
function resolvers.expandpathfromvariable(str)
- return joinpath(resolvers.expandedpathlistfromvariable(str))
+ return joinpath(expandedpathlistfromvariable(str))
end
+resolvers.expandedpathlistfromvariable = expandedpathlistfromvariable
+
function resolvers.cleanedpathlist(v) -- can be cached if needed
- local t = resolvers.expandedpathlist(v)
+ local t = expandedpathlist(v)
for i=1,#t do
- t[i] = resolvers.resolve(resolvers.cleanpath(t[i]))
+ t[i] = resolveprefix(cleanpath(t[i]))
end
return t
end
function resolvers.expandbraces(str) -- output variable and brace expansion of STRING
- local pth = expandedpathfromlist(resolvers.splitpath(str))
+ local pth = expandedpathfromlist(splitpath(str))
return joinpath(pth)
end
function resolvers.registerfilehash(name,content,someerror)
+ local files = instance.files
if content then
- instance.files[name] = content
+ files[name] = content
else
- instance.files[name] = { }
+ files[name] = { }
if somerror == true then -- can be unset
instance.loaderror = someerror
end
@@ -956,8 +1023,8 @@ function resolvers.renewcache()
end
local function isreadable(name)
- local readable = isfile(name) -- not file.is_readable(name) asit can be a dir
- if trace_detail then
+ local readable = isfile(name) -- not file.is_readable(name) as it can be a dir
+ if trace_details then
if readable then
report_resolving("file %a is readable",name)
else
@@ -977,7 +1044,7 @@ local function collect_files(names) -- potential files .. sort of too much when
local variant = hash.type
local search = filejoin(root,path,name) -- funny no concatinator
local result = methodhandler('concatinators',variant,root,path,name)
- if trace_detail then
+ if trace_details then
report_resolving("match: variant %a, search %a, result %a",variant,search,result)
end
noffiles = noffiles + 1
@@ -986,7 +1053,7 @@ local function collect_files(names) -- potential files .. sort of too much when
end
for k=1,#names do
local filename = names[k]
- if trace_detail then
+ if trace_details then
report_resolving("checking name %a",filename)
end
local basename = filebasename(filename)
@@ -998,12 +1065,13 @@ local function collect_files(names) -- potential files .. sort of too much when
pathname = "/" .. pathname .. "$"
end
local hashes = instance.hashes
+ local files = instance.files
for h=1,#hashes do
local hash = hashes[h]
local hashname = hash.name
- local content = hashname and instance.files[hashname]
+ local content = hashname and files[hashname]
if content then
- if trace_detail then
+ if trace_details then
report_resolving("deep checking %a, base %a, pattern %a",hashname,basename,pathname)
end
local path, name = lookup(content,basename)
@@ -1089,7 +1157,6 @@ local function find_analyze(filename,askedformat,allresults)
if askedformat == "" then
if filesuffix == "" or not suffixmap[filesuffix] then
local defaultsuffixes = resolvers.defaultsuffixes
- local formatofsuffix = resolvers.formatofsuffix
for i=1,#defaultsuffixes do
local forcedname = filename .. '.' .. defaultsuffixes[i]
wantedfiles[#wantedfiles+1] = forcedname
@@ -1099,7 +1166,7 @@ local function find_analyze(filename,askedformat,allresults)
end
end
else
- filetype = resolvers.formatofsuffix(filename)
+ filetype = formatofsuffix(filename)
if trace_locating then
report_resolving("using suffix based filetype %a",filetype)
end
@@ -1123,7 +1190,7 @@ end
local function find_direct(filename,allresults)
if not dangerous[askedformat] and isreadable(filename) then
- if trace_detail then
+ if trace_details then
report_resolving("file %a found directly",filename)
end
return "direct", { filename }
@@ -1150,12 +1217,12 @@ local function find_qualified(filename,allresults,askedformat,alsostripped) -- t
report_resolving("checking qualified name %a", filename)
end
if isreadable(filename) then
- if trace_detail then
+ if trace_details then
report_resolving("qualified file %a found", filename)
end
return "qualified", { filename }
end
- if trace_detail then
+ if trace_details then
report_resolving("locating qualified file %a", filename)
end
local forcedname, suffix = "", suffixonly(filename)
@@ -1163,11 +1230,11 @@ local function find_qualified(filename,allresults,askedformat,alsostripped) -- t
local format_suffixes = askedformat == "" and resolvers.defaultsuffixes or suffixes[askedformat]
if format_suffixes then
for i=1,#format_suffixes do
- local s = format_suffixes[i]
- forcedname = filename .. "." .. s
+ local suffix = format_suffixes[i]
+ forcedname = filename .. "." .. suffix
if isreadable(forcedname) then
if trace_locating then
- report_resolving("no suffix, forcing format filetype %a", s)
+ report_resolving("no suffix, forcing format filetype %a", suffix)
end
return "qualified", { forcedname }
end
@@ -1182,7 +1249,7 @@ local function find_qualified(filename,allresults,askedformat,alsostripped) -- t
local savedformat = askedformat
local format = savedformat or ""
if format == "" then
- askedformat = resolvers.formatofsuffix(suffix)
+ askedformat = formatofsuffix(suffix)
end
if not format then
askedformat = "othertextfiles" -- kind of everything, maybe all
@@ -1231,7 +1298,7 @@ end
local function check_subpath(fname)
if isreadable(fname) then
- if trace_detail then
+ if trace_details then
report_resolving("found %a by deep scanning",fname)
end
return fname
@@ -1244,7 +1311,7 @@ end
local function makepathlist(list,filetype)
local typespec = resolvers.variableofformat(filetype)
- local pathlist = resolvers.expandedpathlist(typespec,filetype and usertypes[filetype]) -- only extra path with user files
+ local pathlist = expandedpathlist(typespec,filetype and usertypes[filetype]) -- only extra path with user files
local entry = { }
if pathlist and #pathlist > 0 then
for k=1,#pathlist do
@@ -1255,7 +1322,7 @@ local function makepathlist(list,filetype)
local expression = makepathexpression(pathname)
local barename = gsub(pathname,"/+$","")
barename = resolveprefix(barename)
- local scheme = url.hasscheme(barename)
+ local scheme = urlhasscheme(barename)
local schemename = gsub(barename,"%.%*$",'') -- after scheme
-- local prescanned = path ~= pathname -- ^!!
-- local resursive = find(pathname,'//$')
@@ -1300,7 +1367,7 @@ local function find_intree(filename,filetype,wantedfiles,allresults)
dirlist[i] = filedirname(filelist[i][3]) .. "/" -- was [2] .. gamble
end
end
- if trace_detail then
+ if trace_details then
report_resolving("checking filename %a in tree",filename)
end
for k=1,#pathlist do
@@ -1312,7 +1379,7 @@ local function find_intree(filename,filetype,wantedfiles,allresults)
if filelist then -- database
-- compare list entries with permitted pattern -- /xx /xx//
local expression = entry.expression
- if trace_detail then
+ if trace_details then
report_resolving("using pattern %a for path %a",expression,pathname)
end
for k=1,#filelist do
@@ -1325,16 +1392,16 @@ local function find_intree(filename,filetype,wantedfiles,allresults)
result[#result+1] = resolveprefix(fl[3]) -- no shortcut
done = true
if allresults then
- if trace_detail then
+ if trace_details then
report_resolving("match to %a in hash for file %a and path %a, continue scanning",expression,f,d)
end
else
- if trace_detail then
+ if trace_details then
report_resolving("match to %a in hash for file %a and path %a, quit scanning",expression,f,d)
end
break
end
- elseif trace_detail then
+ elseif trace_details then
report_resolving("no match to %a in hash for file %a and path %a",expression,f,d)
end
end
@@ -1355,9 +1422,8 @@ local function find_intree(filename,filetype,wantedfiles,allresults)
-- that are not hashed (like sources on my machine) .. so, this is slightly
-- out of order but at least fast (and we seldom end up here, only when a file
-- is not already found
--- inspect(entry)
if not done and not entry.prescanned then
- if trace_detail then
+ if trace_details then
report_resolving("quick root scan for %a",pname)
end
for k=1,#wantedfiles do
@@ -1373,7 +1439,7 @@ local function find_intree(filename,filetype,wantedfiles,allresults)
end
if not done and entry.recursive then -- maybe also when allresults
-- collect files in path (and cache the result)
- if trace_detail then
+ if trace_details then
report_resolving("scanning filesystem for %a",pname)
end
local files = resolvers.simplescanfiles(pname,false,true)
@@ -1446,7 +1512,7 @@ local function find_intree(filename,filetype,wantedfiles,allresults)
end
local function find_onpath(filename,filetype,wantedfiles,allresults)
- if trace_detail then
+ if trace_details then
report_resolving("checking filename %a, filetype %a, wanted files %a",filename,filetype,concat(wantedfiles," | "))
end
local result = { }
@@ -1481,10 +1547,8 @@ collect_instance_files = function(filename,askedformat,allresults) -- uses neste
return { }
end
askedformat = askedformat or ""
- filename = collapsepath(filename,".")
-
- filename = gsub(filename,"^%./",getcurrentdir().."/") -- we will merge dir.expandname and collapse some day
-
+ filename = collapsepath(filename,".")
+ filename = gsub(filename,"^%./",getcurrentdir().."/") -- we will merge dir.expandname and collapse some day
if allresults then
-- no need for caching, only used for tracing
local filetype, wantedfiles = find_analyze(filename,askedformat)
@@ -1496,7 +1560,9 @@ collect_instance_files = function(filename,askedformat,allresults) -- uses neste
{ find_onpath (filename,filetype,wantedfiles,true) },
{ find_otherwise(filename,filetype,wantedfiles,true) },
}
- local result, status, done = { }, { }, { }
+ local result = { }
+ local status = { }
+ local done = { }
for k, r in next, results do
local method, list = r[1], r[2]
if method and list then
@@ -1510,7 +1576,7 @@ collect_instance_files = function(filename,askedformat,allresults) -- uses neste
end
end
end
- if trace_detail then
+ if trace_details then
report_resolving("lookup status: %s",table.serialize(status,filename))
end
return result, status
@@ -1571,6 +1637,9 @@ local function findfiles(filename,filetype,allresults)
if not filename or filename == "" then
return { }
end
+ if allresults == nil then
+ allresults = true
+ end
local result, status = collect_instance_files(filename,filetype or "",allresults)
if not result or #result == 0 then
local lowered = lower(filename)
@@ -1581,32 +1650,29 @@ local function findfiles(filename,filetype,allresults)
return result or { }, status
end
-function resolvers.findfiles(filename,filetype)
- if not filename or filename == "" then
- -- weird ... why called then
- return ""
- else
- return findfiles(filename,filetype,true)
- end
-end
-
-function resolvers.findfile(filename,filetype)
+local function findfile(filename,filetype)
if not filename or filename == "" then
- -- weird ... why called then
return ""
else
return findfiles(filename,filetype,false)[1] or ""
end
end
+resolvers.findfiles = findfiles
+resolvers.findfile = findfile
+
+resolvers.find_file = findfile -- obsolete
+resolvers.find_files = findfiles -- obsolete
+
function resolvers.findpath(filename,filetype)
return filedirname(findfiles(filename,filetype,false)[1] or "")
end
local function findgivenfiles(filename,allresults)
+ local hashes = instance.hashes
+ local files = instance.files
local base = filebasename(filename)
local result = { }
- local hashes = instance.hashes
--
local function okay(hash,path,name)
local found = methodhandler('concatinators',hash.type,hash.name,path,name)
@@ -1618,7 +1684,7 @@ local function findgivenfiles(filename,allresults)
--
for k=1,#hashes do
local hash = hashes[k]
- local content = instance.files[hash.name]
+ local content = files[hash.name]
if content then
local path, name = lookup(content,base)
if not path then
@@ -1661,15 +1727,16 @@ end
-- why bother
local function findwildcardfiles(filename,allresults,result)
+ local files = instance.files
+ local hashes = instance.hashes
+ --
local result = result or { }
local base = filebasename(filename)
local dirn = filedirname(filename)
local path = lower(lpegmatch(makewildcard,dirn) or dirn)
local name = lower(lpegmatch(makewildcard,base) or base)
- local files = instance.files
--
if find(name,"*",1,true) then
- local hashes = instance.hashes
local function okay(found,path,base,hashname,hashtype)
if find(found,path) then
local full = methodhandler('concatinators',hashtype,hashname,found,base)
@@ -1710,7 +1777,6 @@ local function findwildcardfiles(filename,allresults,result)
end
end
--
- local hashes = instance.hashes
for k=1,#hashes do
local hash = hashes[k]
local hashname = hash.name
@@ -1746,18 +1812,30 @@ function resolvers.findwildcardfile(filename)
return findwildcardfiles(filename,false)[1] or ""
end
--- main user functions
+do
-function resolvers.automount()
- -- implemented later
-end
+ local starttiming = statistics.starttiming
+ local stoptiming = statistics.stoptiming
+ local elapsedtime = statistics.elapsedtime
+
+ function resolvers.starttiming()
+ starttiming(instance)
+ end
+
+ function resolvers.stoptiming()
+ stoptiming(instance)
+ end
+
+ function resolvers.loadtime()
+ return elapsedtime(instance)
+ end
-function resolvers.starttiming()
- statistics.starttiming(instance)
end
-function resolvers.stoptiming()
- statistics.stoptiming(instance)
+-- main user functions
+
+function resolvers.automount()
+ -- implemented later (maybe a one-time setter like textopener)
end
function resolvers.load(option)
@@ -1773,10 +1851,6 @@ function resolvers.load(option)
return files and next(files) and true
end
-function resolvers.loadtime()
- return statistics.elapsedtime(instance)
-end
-
local function report(str)
if trace_locating then
report_resolving(str) -- has already verbose
@@ -1807,13 +1881,11 @@ function resolvers.dowithfilesandreport(command, files, ...) -- will move
end
end
--- obsolete
-
-- resolvers.varvalue = resolvers.variable -- output the value of variable $STRING.
--- resolvers.expandvar = resolvers.expansion -- output variable expansion of STRING.
+-- resolvers.expandvar = expansion -- output variable expansion of STRING.
function resolvers.showpath(str) -- output search path for file type NAME
- return joinpath(resolvers.expandedpathlist(resolvers.formatofvariable(str)))
+ return joinpath(expandedpathlist(resolvers.formatofvariable(str)))
end
function resolvers.registerfile(files, name, path)
@@ -1829,7 +1901,7 @@ function resolvers.registerfile(files, name, path)
end
function resolvers.dowithpath(name,func)
- local pathlist = resolvers.expandedpathlist(name)
+ local pathlist = expandedpathlist(name)
for i=1,#pathlist do
func("^"..cleanpath(pathlist[i]))
end
@@ -1840,12 +1912,12 @@ function resolvers.dowithvariable(name,func)
end
function resolvers.locateformat(name)
- local engine = environment.ownmain or "luatex"
- local barename = removesuffix(name)
+ local engine = environment.ownmain or "luatex"
+ local barename = removesuffix(file.basename(name))
local fullname = addsuffix(barename,"fmt")
- local fmtname = caches.getfirstreadablefile(fullname,"formats",engine) or ""
+ local fmtname = caches.getfirstreadablefile(fullname,"formats",engine) or ""
if fmtname == "" then
- fmtname = resolvers.findfile(fullname)
+ fmtname = findfile(fullname)
fmtname = cleanpath(fmtname)
end
if fmtname ~= "" then
@@ -1854,18 +1926,18 @@ function resolvers.locateformat(name)
local lucname = addsuffix(barename,luasuffixes.luc)
local luiname = addsuffix(barename,luasuffixes.lui)
if isfile(luiname) then
- return barename, luiname
+ return fmtname, luiname
elseif isfile(lucname) then
- return barename, lucname
+ return fmtname, lucname
elseif isfile(luaname) then
- return barename, luaname
+ return fmtname, luaname
end
end
return nil, nil
end
function resolvers.booleanvariable(str,default)
- local b = resolvers.expansion(str)
+ local b = expansion(str)
if b == "" then
return default
else
@@ -1876,6 +1948,7 @@ end
function resolvers.dowithfilesintree(pattern,handle,before,after) -- will move, can be a nice iterator instead
local hashes = instance.hashes
+ local files = instance.files
for i=1,#hashes do
local hash = hashes[i]
local blobtype = hash.type
@@ -1887,7 +1960,7 @@ function resolvers.dowithfilesintree(pattern,handle,before,after) -- will move,
if before then
before(blobtype,blobpath,pattern)
end
- for path, name in filtered(instance.files[blobpath],pattern) do
+ for path, name in filtered(files[blobpath],pattern) do
if type(path) == "string" then
checked = checked + 1
if handle(blobtype,blobpath,path,name) then
@@ -1909,12 +1982,6 @@ function resolvers.dowithfilesintree(pattern,handle,before,after) -- will move,
end
end
-local obsolete = resolvers.obsolete or { }
-resolvers.obsolete = obsolete
-
-resolvers.find_file = resolvers.findfile obsolete.find_file = resolvers.findfile
-resolvers.find_files = resolvers.findfiles obsolete.find_files = resolvers.findfiles
-
-- moved here
function resolvers.knownvariables(pattern)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/data-sch.lua b/Master/texmf-dist/tex/context/base/mkiv/data-sch.lua
index 2e880e99740..d869520ba28 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/data-sch.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/data-sch.lua
@@ -6,9 +6,14 @@ if not modules then modules = { } end modules ['data-sch'] = {
license = "see context related readme files"
}
+-- this one will be redone / localized
+
local load, tonumber = load, tonumber
-local gsub, concat, format = string.gsub, table.concat, string.format
+local gsub, format = string.gsub, string.format
+local sortedhash, concat = table.sortedhash, table.concat
local finders, openers, loaders = resolvers.finders, resolvers.openers, resolvers.loaders
+local addsuffix, suffix, splitbase = file.addsuffix, file.suffix, file.splitbase
+local md5hex = md5.hex
local trace_schemes = false trackers.register("resolvers.schemes",function(v) trace_schemes = v end)
local report_schemes = logs.reporter("resolvers","schemes")
@@ -39,7 +44,7 @@ end
-- end
function cleaners.strip(specification) -- keep suffixes
- local path, name = file.splitbase(specification.original)
+ local path, name = splitbase(specification.original)
if path == "" then
return (gsub(name,"[^%a%d%.]+","-"))
else
@@ -48,7 +53,7 @@ function cleaners.strip(specification) -- keep suffixes
end
function cleaners.md5(specification)
- return file.addsuffix(md5.hex(specification.original),file.suffix(specification.path))
+ return addsuffix(md5hex(specification.original),suffix(specification.path))
end
local cleaner = cleaners.strip
@@ -72,7 +77,7 @@ local runner = sandbox.registerrunner {
name = "curl resolver",
method = "execute",
program = "curl",
- template = "--silent --insecure --create-dirs --output %cachename% %original%",
+ template = '--silent --insecure --create-dirs --output "%cachename%" "%original%"',
checkers = {
cachename = "cache",
original = "url",
@@ -149,10 +154,10 @@ schemes.install = install
local function http_handler(specification,cachename)
local tempname = cachename .. ".tmp"
- local f = io.open(tempname,"wb")
+ local handle = io.open(tempname,"wb")
local status, message = http.request {
url = specification.original,
- sink = ltn12.sink.file(f)
+ sink = ltn12.sink.file(handle)
}
if not status then
os.remove(tempname)
@@ -169,13 +174,13 @@ install('ftp')
statistics.register("scheme handling time", function()
local l, r, nl, nr = { }, { }, 0, 0
- for k, v in table.sortedhash(loaded) do
+ for k, v in sortedhash(loaded) do
if v > 0 then
nl = nl + 1
l[nl] = k .. ":" .. v
end
end
- for k, v in table.sortedhash(reused) do
+ for k, v in sortedhash(reused) do
if v > 0 then
nr = nr + 1
r[nr] = k .. ":" .. v
@@ -183,10 +188,10 @@ statistics.register("scheme handling time", function()
end
local n = nl + nr
if n > 0 then
- l = nl > 0 and concat(l) or "none"
- r = nr > 0 and concat(r) or "none"
+ if nl == 0 then l = { "none" } end
+ if nr == 0 then r = { "none" } end
return format("%s seconds, %s processed, threshold %s seconds, loaded: %s, reused: %s",
- statistics.elapsedtime(schemes), n, threshold, l, r)
+ statistics.elapsedtime(schemes), n, threshold, concat(l," "), concat(l," "))
else
return nil
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/data-tex.lua b/Master/texmf-dist/tex/context/base/mkiv/data-tex.lua
index 8f978a204f3..e7c4941cae7 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/data-tex.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/data-tex.lua
@@ -6,20 +6,25 @@ if not modules then modules = { } end modules ['data-tex'] = {
license = "see context related readme files"
}
+local tostring, tonumber, type = tostring, tonumber, type
local char, find = string.char, string.find
-local insert, remove = table.insert, table.remove
local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end)
local report_tex = logs.reporter("resolvers","tex")
-local resolvers = resolvers
local sequencers = utilities.sequencers
-local methodhandler = resolvers.methodhandler
-local splitlines = string.splitlines
local utffiletype = utf.filetype
local setmetatableindex = table.setmetatableindex
+local loaddata = io.loaddata
+----- readall = io.readall
+
+local resolvers = resolvers
+local methodhandler = resolvers.methodhandler
+local loadbinfile = resolvers.loadbinfile
+local pushinputname = resolvers.pushinputname
+local popinputname = resolvers.popinputname
-- local fileprocessor = nil
-- local lineprocessor = nil
@@ -36,8 +41,9 @@ local textlineactions = sequencers.new {
results = "str",
}
-local helpers = resolvers.openers.helpers
-local appendgroup = sequencers.appendgroup
+local helpers = resolvers.openers.helpers
+local appendgroup = sequencers.appendgroup
+local appendaction = sequencers.appendaction
helpers.textfileactions = textfileactions
helpers.textlineactions = textlineactions
@@ -53,10 +59,6 @@ appendgroup(textlineactions,"after" ) -- user
local ctrl_d = char( 4) -- unix
local ctrl_z = char(26) -- windows
-resolvers.inputstack = resolvers.inputstack or { }
-
-local inputstack = resolvers.inputstack
-
----------------------------------------
local lpegmatch = lpeg.match
@@ -84,18 +86,25 @@ end
-----------------------------------------
-function helpers.textopener(tag,filename,filehandle,coding)
+local wideutfcoding = {
+ ["utf-16-be"] = utf.utf16_to_utf8_be_t,
+ ["utf-16-le"] = utf.utf16_to_utf8_le_t,
+ ["utf-32-be"] = utf.utf32_to_utf8_be_t,
+ ["utf-32-le"] = utf.utf32_to_utf8_le_t,
+}
+
+local function textopener(tag,filename,filehandle,coding)
local lines
local t_filehandle = type(filehandle)
if not filehandle then
- lines = io.loaddata(filename)
+ lines = loaddata(filename)
elseif t_filehandle == "string" then
lines = filehandle
elseif t_filehandle == "table" then
lines = filehandle
else
- lines = filehandle:read("*a") -- io.readall(filehandle) ... but never that large files anyway
- -- lines = io.readall(filehandle)
+ lines = filehandle:read("*a") -- readall(filehandle) ... but never that large files anyway
+ -- lines = readall(filehandle)
filehandle:close()
end
if type(lines) == "string" then
@@ -103,14 +112,9 @@ function helpers.textopener(tag,filename,filehandle,coding)
if trace_locating then
report_tex("%a opener: %a opened using method %a",tag,filename,coding)
end
- if coding == "utf-16-be" then
- lines = utf.utf16_to_utf8_be_t(lines)
- elseif coding == "utf-16-le" then
- lines = utf.utf16_to_utf8_le_t(lines)
- elseif coding == "utf-32-be" then
- lines = utf.utf32_to_utf8_be_t(lines)
- elseif coding == "utf-32-le" then
- lines = utf.utf32_to_utf8_le_t(lines)
+ local wideutf = wideutfcoding[coding]
+ if wideutf then
+ lines = wideutf(lines)
else -- utf8 or unknown (could be a mkvi file)
local runner = textfileactions.runner
if runner then
@@ -125,19 +129,17 @@ function helpers.textopener(tag,filename,filehandle,coding)
if lines[noflines] == "" then -- maybe some special check is needed
lines[noflines] = nil
end
- logs.show_open(filename)
- insert(inputstack,filename)
+ pushinputname(filename)
local currentline, noflines = 0, noflines
local t = {
filename = filename,
noflines = noflines,
-- currentline = 0,
close = function()
+ local usedname = popinputname() -- should match filename
if trace_locating then
report_tex("%a closer: %a closed",tag,filename)
end
- logs.show_close(filename)
- remove(inputstack)
t = nil
end,
reader = function(self)
@@ -176,6 +178,8 @@ function helpers.textopener(tag,filename,filehandle,coding)
return t
end
+helpers.settextopener(textopener) -- can only be done once
+
function resolvers.findtexfile(filename,filetype)
return methodhandler('finders',filename,filetype)
end
@@ -191,7 +195,7 @@ end
function resolvers.loadtexfile(filename,filetype)
-- todo: optionally apply filters
- local ok, data, size = resolvers.loadbinfile(filename, filetype)
+ local ok, data, size = loadbinfile(filename, filetype)
return data or ""
end
@@ -202,14 +206,14 @@ local function installhandler(namespace,what,where,func)
where, func = "after", where
end
if where == "before" or where == "after" then
- sequencers.appendaction(namespace,where,func)
+ appendaction(namespace,where,func)
else
report_tex("installing input %a handlers in %a is not possible",what,tostring(where))
end
end
-function resolvers.installinputlinehandler(...) installhandler(helpers.textlineactions,"line",...) end
-function resolvers.installinputfilehandler(...) installhandler(helpers.textfileactions,"file",...) end
+function resolvers.installinputlinehandler(...) installhandler(textlineactions,"line",...) end
+function resolvers.installinputfilehandler(...) installhandler(textfileactions,"file",...) end
-- local basename = file.basename
-- resolvers.installinputlinehandler(function(str,filename,linenumber,noflines)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/data-tmp.lua b/Master/texmf-dist/tex/context/base/mkiv/data-tmp.lua
index d25a6b2f972..9b0117c1562 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/data-tmp.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/data-tmp.lua
@@ -7,28 +7,32 @@ if not modules then modules = { } end modules ['data-tmp'] = {
}
--[[ldx--
-<p>This module deals with caching data. It sets up the paths and
-implements loaders and savers for tables. Best is to set the
-following variable. When not set, the usual paths will be
-checked. Personally I prefer the (users) temporary path.</p>
+<p>This module deals with caching data. It sets up the paths and implements
+loaders and savers for tables. Best is to set the following variable. When not
+set, the usual paths will be checked. Personally I prefer the (users) temporary
+path.</p>
</code>
TEXMFCACHE=$TMP;$TEMP;$TMPDIR;$TEMPDIR;$HOME;$TEXMFVAR;$VARTEXMF;.
</code>
-<p>Currently we do no locking when we write files. This is no real
-problem because most caching involves fonts and the chance of them
-being written at the same time is small. We also need to extend
-luatools with a recache feature.</p>
+<p>Currently we do no locking when we write files. This is no real problem
+because most caching involves fonts and the chance of them being written at the
+same time is small. We also need to extend luatools with a recache feature.</p>
--ldx]]--
-local format, lower, gsub, concat = string.format, string.lower, string.gsub, table.concat
------ serialize, serializetofile = table.serialize, table.tofile -- overloaded so no local
-local concat = table.concat
-local mkdirs, isdir, isfile = dir.mkdirs, lfs.isdir, lfs.isfile
-local addsuffix, is_writable, is_readable = file.addsuffix, file.is_writable, file.is_readable
-local formatters = string.formatters
local next, type = next, type
+local pcall, loadfile, collectgarbage = pcall, loadfile, collectgarbage
+local format, lower, gsub = string.format, string.lower, string.gsub
+local concat, serialize, fastserialize, serializetofile = table.concat, table.serialize, table.fastserialize, table.tofile
+local mkdirs, expanddirname, isdir, isfile = dir.mkdirs, dir.expandname, lfs.isdir, lfs.isfile
+local is_writable, is_readable = file.is_writable, file.is_readable
+local collapsepath, joinfile, addsuffix, dirname = file.collapsepath, file.join, file.addsuffix, file.dirname
+local savedata = file.savedata
+local formatters = string.formatters
+local osexit, osdate, osuuid = os.exit, os.date, os.uuid
+local removefile = os.remove
+local md5hex = md5.hex
local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end)
local trace_cache = false trackers.register("resolvers.cache", function(v) trace_cache = v end)
@@ -36,44 +40,80 @@ local trace_cache = false trackers.register("resolvers.cache", function(v
local report_caches = logs.reporter("resolvers","caches")
local report_resolvers = logs.reporter("resolvers","caching")
-local resolvers = resolvers
-local cleanpath = resolvers.cleanpath
+local resolvers = resolvers
+local cleanpath = resolvers.cleanpath
+local resolvepath = resolvers.resolve
+
+local luautilities = utilities.lua
-- intermezzo
-local directive_cleanup = false directives.register("system.compile.cleanup", function(v) directive_cleanup = v end)
-local directive_strip = false directives.register("system.compile.strip", function(v) directive_strip = v end)
+do
+
+ local directive_cleanup = false directives.register("system.compile.cleanup", function(v) directive_cleanup = v end)
+ local directive_strip = false directives.register("system.compile.strip", function(v) directive_strip = v end)
-local compile = utilities.lua.compile
+ local compilelua = luautilities.compile
+
+ function luautilities.compile(luafile,lucfile,cleanup,strip)
+ if cleanup == nil then cleanup = directive_cleanup end
+ if strip == nil then strip = directive_strip end
+ return compilelua(luafile,lucfile,cleanup,strip)
+ end
-function utilities.lua.compile(luafile,lucfile,cleanup,strip)
- if cleanup == nil then cleanup = directive_cleanup end
- if strip == nil then strip = directive_strip end
- return compile(luafile,lucfile,cleanup,strip)
end
-- end of intermezzo
-caches = caches or { }
-local caches = caches
+caches = caches or { }
+local caches = caches
+local writable = nil
+local readables = { }
+local usedreadables = { }
-local luasuffixes = utilities.lua.suffixes
+local compilelua = luautilities.compile
+local luasuffixes = luautilities.suffixes
-caches.base = caches.base or "luatex-cache"
-caches.more = caches.more or "context"
-caches.direct = false -- true is faster but may need huge amounts of memory
-caches.tree = false
-caches.force = true
-caches.ask = false
-caches.relocate = false
-caches.defaults = { "TMPDIR", "TEMPDIR", "TMP", "TEMP", "HOME", "HOMEPATH" }
+caches.base = caches.base or "luatex-cache" -- can be local
+caches.more = caches.more or "context" -- can be local
+caches.defaults = { "TMPDIR", "TEMPDIR", "TMP", "TEMP", "HOME", "HOMEPATH" }
-directives.register("system.caches.fast",function(v) caches.fast = true end)
+local direct_cache = false -- true is faster but may need huge amounts of memory
+local fast_cache = false
+local cache_tree = false
-local writable, readables, usedreadables = nil, { }, { }
+directives.register("system.caches.direct",function(v) direct_cache = true end)
+directives.register("system.caches.fast", function(v) fast_cache = true end)
-- we could use a metatable for writable and readable but not yet
+local function configfiles()
+ return concat(resolvers.configurationfiles(),";")
+end
+
+local function hashed(tree)
+ tree = gsub(tree,"[\\/]+$","")
+ tree = lower(tree)
+ local hash = md5hex(tree)
+ if trace_cache or trace_locating then
+ report_caches("hashing tree %a, hash %a",tree,hash)
+ end
+ return hash
+end
+
+local function treehash()
+ local tree = configfiles()
+ if not tree or tree == "" then
+ return false
+ else
+ return hashed(tree)
+ end
+end
+
+caches.hashed = hashed
+caches.treehash = treehash
+caches.configfiles = configfiles
+
local function identify()
-- Combining the loops makes it messy. First we check the format cache path
-- and when the last component is not present we try to create it.
@@ -82,9 +122,9 @@ local function identify()
for k=1,#texmfcaches do
local cachepath = texmfcaches[k]
if cachepath ~= "" then
- cachepath = resolvers.resolve(cachepath)
- cachepath = resolvers.cleanpath(cachepath)
- cachepath = file.collapsepath(cachepath)
+ cachepath = resolvepath(cachepath)
+ cachepath = cleanpath(cachepath)
+ cachepath = collapsepath(cachepath)
local valid = isdir(cachepath)
if valid then
if is_readable(cachepath) then
@@ -93,16 +133,14 @@ local function identify()
writable = cachepath
end
end
- elseif not writable and caches.force then
- local cacheparent = file.dirname(cachepath)
- if is_writable(cacheparent) and true then -- we go on anyway (needed for mojca's kind of paths)
- if not caches.ask or io.ask(format("\nShould I create the cache path %s?",cachepath), "no", { "yes", "no" }) == "yes" then
- mkdirs(cachepath)
- if isdir(cachepath) and is_writable(cachepath) then
- report_caches("path %a created",cachepath)
- writable = cachepath
- readables[#readables+1] = cachepath
- end
+ elseif not writable then
+ local cacheparent = dirname(cachepath)
+ if is_writable(cacheparent) then -- we go on anyway (needed for mojca's kind of paths)
+ mkdirs(cachepath)
+ if isdir(cachepath) and is_writable(cachepath) then
+ report_caches("path %a created",cachepath)
+ writable = cachepath
+ readables[#readables+1] = cachepath
end
end
end
@@ -117,8 +155,8 @@ local function identify()
local cachepath = texmfcaches[k]
cachepath = resolvers.expansion(cachepath) -- was getenv
if cachepath ~= "" then
- cachepath = resolvers.resolve(cachepath)
- cachepath = resolvers.cleanpath(cachepath)
+ cachepath = resolvepath(cachepath)
+ cachepath = cleanpath(cachepath)
local valid = isdir(cachepath)
if valid and is_readable(cachepath) then
if not writable and is_writable(cachepath) then
@@ -134,25 +172,27 @@ local function identify()
-- quit.
if not writable then
report_caches("fatal error: there is no valid writable cache path defined")
- os.exit()
+ osexit()
elseif #readables == 0 then
report_caches("fatal error: there is no valid readable cache path defined")
- os.exit()
+ osexit()
end
-- why here
- writable = dir.expandname(resolvers.cleanpath(writable)) -- just in case
- -- moved here
- local base, more, tree = caches.base, caches.more, caches.tree or caches.treehash() -- we have only one writable tree
+ writable = expanddirname(cleanpath(writable)) -- just in case
+ -- moved here ( we have only one writable tree)
+ local base = caches.base
+ local more = caches.more
+ local tree = cache_tree or treehash() -- we have only one writable tree
if tree then
- caches.tree = tree
+ cache_tree = tree
writable = mkdirs(writable,base,more,tree)
for i=1,#readables do
- readables[i] = file.join(readables[i],base,more,tree)
+ readables[i] = joinfile(readables[i],base,more,tree)
end
else
writable = mkdirs(writable,base,more)
for i=1,#readables do
- readables[i] = file.join(readables[i],base,more)
+ readables[i] = joinfile(readables[i],base,more)
end
end
-- end
@@ -192,30 +232,8 @@ function caches.usedpaths(separator)
end
end
-function caches.configfiles()
- return concat(resolvers.configurationfiles(),";")
-end
-
-function caches.hashed(tree)
- tree = gsub(tree,"[\\/]+$","")
- tree = lower(tree)
- local hash = md5.hex(tree)
- if trace_cache or trace_locating then
- report_caches("hashing tree %a, hash %a",tree,hash)
- end
- return hash
-end
-
-function caches.treehash()
- local tree = caches.configfiles()
- if not tree or tree == "" then
- return false
- else
- return caches.hashed(tree)
- end
-end
-
-local r_cache, w_cache = { }, { } -- normally w in in r but who cares
+local r_cache = { }
+local w_cache = { }
local function getreadablepaths(...)
local tags = { ... }
@@ -226,7 +244,7 @@ local function getreadablepaths(...)
if #tags > 0 then
done = { }
for i=1,#readables do
- done[i] = file.join(readables[i],...)
+ done[i] = joinfile(readables[i],...)
end
else
done = readables
@@ -252,31 +270,21 @@ local function getwritablepath(...)
return done
end
-caches.getreadablepaths = getreadablepaths
-caches.getwritablepath = getwritablepath
-
--- this can be tricky as we can have a pre-generated format while at the same time
--- use e.g. a home path where we have updated file databases and so maybe we need
--- to check first if we do have a writable one
-
--- function caches.getfirstreadablefile(filename,...)
--- local rd = getreadablepaths(...)
--- for i=1,#rd do
--- local path = rd[i]
--- local fullname = file.join(path,filename)
--- if is_readable(fullname) then
--- usedreadables[i] = true
--- return fullname, path
--- end
--- end
--- return caches.setfirstwritablefile(filename,...)
--- end
+local function setfirstwritablefile(filename,...)
+ local wr = getwritablepath(...)
+ local fullname = joinfile(wr,filename)
+ return fullname, wr
+end
--- next time we have an issue, we can test this instead:
+local function setluanames(path,name)
+ return
+ format("%s/%s.%s",path,name,luasuffixes.tma),
+ format("%s/%s.%s",path,name,luasuffixes.tmc)
+end
-function caches.getfirstreadablefile(filename,...)
+local function getfirstreadablefile(filename,...)
-- check if we have already written once
- local fullname, path = caches.setfirstwritablefile(filename,...)
+ local fullname, path = setfirstwritablefile(filename,...)
if is_readable(fullname) then
return fullname, path -- , true
end
@@ -284,7 +292,7 @@ function caches.getfirstreadablefile(filename,...)
local rd = getreadablepaths(...)
for i=1,#rd do
local path = rd[i]
- local fullname = file.join(path,filename)
+ local fullname = joinfile(path,filename)
if is_readable(fullname) then
usedreadables[i] = true
return fullname, path -- , false
@@ -294,21 +302,19 @@ function caches.getfirstreadablefile(filename,...)
return fullname, path -- , true
end
-function caches.setfirstwritablefile(filename,...)
- local wr = getwritablepath(...)
- local fullname = file.join(wr,filename)
- return fullname, wr
-end
+caches.getreadablepaths = getreadablepaths
+caches.getwritablepath = getwritablepath
+caches.setfirstwritablefile = setfirstwritablefile
+caches.getfirstreadablefile = getfirstreadablefile
+caches.setluanames = setluanames
-function caches.define(category,subcategory) -- not used
- return function()
- return getwritablepath(category,subcategory)
- end
-end
-
-function caches.setluanames(path,name)
- return format("%s/%s.%s",path,name,luasuffixes.tma), format("%s/%s.%s",path,name,luasuffixes.tmc)
-end
+-- -- not used:
+--
+-- function caches.define(category,subcategory)
+-- return function()
+-- return getwritablepath(category,subcategory)
+-- end
+-- end
-- This works best if the first writable is the first readable too. In practice
-- we can have these situations for file databases:
@@ -325,22 +331,23 @@ function caches.loaddata(readables,name,writable)
for i=1,#readables do
local path = readables[i]
local loader = false
- local tmaname, tmcname = caches.setluanames(path,name)
+ local state = false
+ local tmaname, tmcname = setluanames(path,name)
if isfile(tmcname) then
- loader = loadfile(tmcname)
+ state, loader = pcall(loadfile,tmcname)
end
if not loader and isfile(tmaname) then
-- can be different paths when we read a file database from disk
- local tmacrap, tmcname = caches.setluanames(writable,name)
+ local tmacrap, tmcname = setluanames(writable,name)
if isfile(tmcname) then
- loader = loadfile(tmcname)
+ state, loader = pcall(loadfile,tmcname)
end
- utilities.lua.compile(tmaname,tmcname)
+ compilelua(tmaname,tmcname)
if isfile(tmcname) then
- loader = loadfile(tmcname)
+ state, loader = pcall(loadfile,tmcname)
end
if not loader then
- loader = loadfile(tmaname)
+ state, loader = pcall(loadfile,tmaname)
end
end
if loader then
@@ -353,27 +360,23 @@ function caches.loaddata(readables,name,writable)
end
function caches.is_writable(filepath,filename)
- local tmaname, tmcname = caches.setluanames(filepath,filename)
+ local tmaname, tmcname = setluanames(filepath,filename)
return is_writable(tmaname)
end
-local saveoptions = { compact = true }
-
--- add some point we will only use the internal bytecode compiler and
--- then we can flag success in the tma so that it can trigger a compile
--- if the other engine
+local saveoptions = { compact = true, accurate = not JITSUPPORTED }
-function caches.savedata(filepath,filename,data,raw)
- local tmaname, tmcname = caches.setluanames(filepath,filename)
- data.cache_uuid = os.uuid()
- if caches.fast then
- file.savedata(tmaname,table.fastserialize(data,true))
- elseif caches.direct then
- file.savedata(tmaname,table.serialize(data,true,saveoptions))
+function caches.savedata(filepath,filename,data,fast)
+ local tmaname, tmcname = setluanames(filepath,filename)
+ data.cache_uuid = osuuid()
+ if fast or fast_cache then
+ savedata(tmaname,fastserialize(data,true))
+ elseif direct_cache then
+ savedata(tmaname,serialize(data,true,saveoptions))
else
- table.tofile(tmaname,data,true,saveoptions)
+ serializetofile(tmaname,data,true,saveoptions)
end
- utilities.lua.compile(tmaname,tmcname)
+ compilelua(tmaname,tmcname)
end
-- moved from data-res:
@@ -386,11 +389,14 @@ end
function caches.loadcontent(cachename,dataname,filename)
if not filename then
- local name = caches.hashed(cachename)
- local full, path = caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees")
- filename = file.join(path,name)
+ local name = hashed(cachename)
+ local full, path = getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees")
+ filename = joinfile(path,name)
+ end
+ local state, blob = pcall(loadfile,addsuffix(filename,luasuffixes.luc))
+ if not blob then
+ state, blob = pcall(loadfile,addsuffix(filename,luasuffixes.lua))
end
- local blob = loadfile(addsuffix(filename,luasuffixes.luc)) or loadfile(addsuffix(filename,luasuffixes.lua))
if blob then
local data = blob()
if data and data.content then
@@ -425,9 +431,9 @@ end
function caches.savecontent(cachename,dataname,content,filename)
if not filename then
- local name = caches.hashed(cachename)
- local full, path = caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees")
- filename = file.join(path,name) -- is full
+ local name = hashed(cachename)
+ local full, path = setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees")
+ filename = joinfile(path,name) -- is full
end
local luaname = addsuffix(filename,luasuffixes.lua)
local lucname = addsuffix(filename,luasuffixes.luc)
@@ -438,17 +444,17 @@ function caches.savecontent(cachename,dataname,content,filename)
type = dataname,
root = cachename,
version = resolvers.cacheversion,
- date = os.date("%Y-%m-%d"),
- time = os.date("%H:%M:%S"),
+ date = osdate("%Y-%m-%d"),
+ time = osdate("%H:%M:%S"),
content = content,
- uuid = os.uuid(),
+ uuid = osuuid(),
}
- local ok = io.savedata(luaname,table.serialize(data,true))
+ local ok = savedata(luaname,serialize(data,true))
if ok then
if trace_locating then
report_resolvers("category %a, cachename %a saved in %a",dataname,cachename,luaname)
end
- if utilities.lua.compile(luaname,lucname) then
+ if compilelua(luaname,lucname) then
if trace_locating then
report_resolvers("%a compiled to %a",dataname,lucname)
end
@@ -457,7 +463,7 @@ function caches.savecontent(cachename,dataname,content,filename)
if trace_locating then
report_resolvers("compiling failed for %a, deleting file %a",dataname,lucname)
end
- os.remove(lucname)
+ removefile(lucname)
end
elseif trace_locating then
report_resolvers("unable to save %a in %a (access error)",dataname,luaname)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/data-tre.lua b/Master/texmf-dist/tex/context/base/mkiv/data-tre.lua
index c4d43e3eb20..8958dfbea9c 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/data-tre.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/data-tre.lua
@@ -6,6 +6,10 @@ if not modules then modules = { } end modules ['data-tre'] = {
license = "see context related readme files"
}
+-- A tree search is rather dumb ... there is some basic caching of searched trees
+-- but nothing is cached over runs ... it's also a wildcard one so we cannot use
+-- the normal scanner.
+
-- tree://e:/temporary/mb-mp/**/drawing.jpg
-- tree://e:/temporary/mb-mp/**/Drawing.jpg
-- tree://t:./**/tufte.tex
@@ -19,8 +23,9 @@ if not modules then modules = { } end modules ['data-tre'] = {
-- dirlist://///storage-2/resources/mb-mp/**/drawing.jpg
-- dirlist://e:/**/drawing.jpg
+local type = type
local find, gsub, lower = string.find, string.gsub, string.lower
-local basename, dirname, joinname = file.basename, file.dirname, file .join
+local basename, dirname, joinname = file.basename, file.dirname, file.join
local globdir, isdir, isfile = dir.glob, lfs.isdir, lfs.isfile
local P, lpegmatch = lpeg.P, lpeg.match
@@ -28,83 +33,119 @@ local trace_locating = false trackers.register("resolvers.locating", function(v
local report_trees = logs.reporter("resolvers","trees")
-local resolvers = resolvers
-local resolveprefix = resolvers.resolve
-local notfound = resolvers.finders.notfound
-local lookup = resolvers.get_from_content
+local resolvers = resolvers
+local finders = resolvers.finders
+local openers = resolvers.openers
+local loaders = resolvers.loaders
+local locators = resolvers.locators
+local hashers = resolvers.hashers
+local generators = resolvers.generators
--- A tree search is rather dumb ... there is some basic caching of searched trees
--- but nothing is cached over runs ... it's also a wildcard one so we cannot use
--- the normal scanner.
+do
-local collectors = { }
-local found = { }
-
-function resolvers.finders.tree(specification) -- to be adapted to new formats
- local spec = specification.filename
- local okay = found[spec]
- if okay == nil then
- if spec ~= "" then
- local path = dirname(spec)
- local name = basename(spec)
- if path == "" then
- path = "."
- end
- local names = collectors[path]
- if not names then
- local pattern = find(path,"/%*+$") and path or (path .. "/*")
- names = globdir(pattern)
- collectors[path] = names
- end
- local pattern = "/" .. gsub(name,"([%.%-%+])", "%%%1") .. "$"
- for i=1,#names do
- local fullname = names[i]
- if find(fullname,pattern) then
- found[spec] = fullname
- return fullname
+ local collectors = { }
+ local found = { }
+ local notfound = finders.notfound
+
+ function finders.tree(specification) -- to be adapted to new formats
+ local spec = specification.filename
+ local okay = found[spec]
+ if okay == nil then
+ if spec ~= "" then
+ local path = dirname(spec)
+ local name = basename(spec)
+ if path == "" then
+ path = "."
end
- end
- -- let's be nice:
- local pattern = lower(pattern)
- for i=1,#names do
- local fullname = lower(names[i])
- if find(fullname,pattern) then
- if isfile(fullname) then
+ local names = collectors[path]
+ if not names then
+ local pattern = find(path,"/%*+$") and path or (path .. "/*")
+ names = globdir(pattern)
+ collectors[path] = names
+ end
+ local pattern = "/" .. gsub(name,"([%.%-%+])", "%%%1") .. "$"
+ for i=1,#names do
+ local fullname = names[i]
+ if find(fullname,pattern) then
found[spec] = fullname
return fullname
- else
- -- no os name mapping
- break
+ end
+ end
+ -- let's be nice:
+ local pattern = lower(pattern)
+ for i=1,#names do
+ local fullname = lower(names[i])
+ if find(fullname,pattern) then
+ if isfile(fullname) then
+ found[spec] = fullname
+ return fullname
+ else
+ -- no os name mapping
+ break
+ end
end
end
end
+ okay = notfound() -- false
+ found[spec] = okay
end
- okay = notfound() -- false
- found[spec] = okay
+ return okay
end
- return okay
+
end
-function resolvers.locators.tree(specification)
- local name = specification.filename
- local realname = resolveprefix(name) -- no shortcut
- if realname and realname ~= '' and isdir(realname) then
- if trace_locating then
- report_trees("locator %a found",realname)
+do
+
+ local resolveprefix = resolvers.resolve
+ local appendhash = resolvers.appendhash
+
+ local function dolocate(specification)
+ local name = specification.filename
+ local realname = resolveprefix(name) -- no shortcut
+ if realname and realname ~= '' and isdir(realname) then
+ if trace_locating then
+ report_trees("locator %a found",realname)
+ end
+ appendhash('tree',name,false) -- don't cache
+ elseif trace_locating then
+ report_trees("locator %a not found",name)
end
- resolvers.appendhash('tree',name,false) -- don't cache
- elseif trace_locating then
- report_trees("locator %a not found",name)
end
+
+ locators.tree = dolocate
+ locators.dirlist = dolocate
+ locators.dirfile = dolocate
+
end
-function resolvers.hashers.tree(specification)
- local name = specification.filename
- if trace_locating then
- report_trees("analyzing %a",name)
+
+do
+
+ local filegenerator = generators.file
+
+ generators.dirlist = filegenerator
+ generators.dirfile = filegenerator
+
+end
+
+do
+
+ local filegenerator = generators.file
+ local methodhandler = resolvers.methodhandler
+
+ local function dohash(specification)
+ local name = specification.filename
+ if trace_locating then
+ report_trees("analyzing %a",name)
+ end
+ methodhandler("hashers",name)
+ filegenerator(specification)
end
- resolvers.methodhandler("hashers",name)
- resolvers.generators.file(specification)
+
+ hashers.tree = dohash
+ hashers.dirlist = dohash
+ hashers.dirfile = dohash
+
end
-- This is a variation on tree lookups but this time we do cache in the given
@@ -112,121 +153,181 @@ end
-- for instance trees with 50K xml files plus a similar amount of resources to
-- deal and we don't want too much overhead.
-local collectors = { }
-local splitter = lpeg.splitat("/**/")
-local stripper = lpeg.replacer { [P("/") * P("*")^1 * P(-1)] = "" }
-
-table.setmetatableindex(collectors, function(t,k)
- local rootname = lpegmatch(stripper,k)
- local dataname = joinname(rootname,"dirlist")
- local content = caches.loadcontent(dataname,"files",dataname)
- if not content then
- -- path branch usecache onlyonce tolerant
- content = resolvers.scanfiles(rootname,nil,nil,false,true) -- so we accept crap
- caches.savecontent(dataname,"files",content,dataname)
- end
- t[k] = content
- return content
-end)
+local resolve do
+ local collectors = { }
+ local splitter = lpeg.splitat("/**/")
+ local stripper = lpeg.replacer { [P("/") * P("*")^1 * P(-1)] = "" }
+
+ local loadcontent = caches.loadcontent
+ local savecontent = caches.savecontent
+
+ local notfound = finders.notfound
+
+ local scanfiles = resolvers.scanfiles
+ local lookup = resolvers.get_from_content
+
+ table.setmetatableindex(collectors, function(t,k)
+ local rootname = lpegmatch(stripper,k)
+ local dataname = joinname(rootname,"dirlist")
+ local content = loadcontent(dataname,"files",dataname)
+ if not content then
+ -- path branch usecache onlyonce tolerant
+ content = scanfiles(rootname,nil,nil,false,true) -- so we accept crap
+ savecontent(dataname,"files",content,dataname)
+ end
+ t[k] = content
+ return content
+ end)
-local function checked(root,p,n)
- if p then
- if type(p) == "table" then
- for i=1,#p do
- local fullname = joinname(root,p[i],n)
+ local function checked(root,p,n)
+ if p then
+ if type(p) == "table" then
+ for i=1,#p do
+ local fullname = joinname(root,p[i],n)
+ if isfile(fullname) then -- safeguard
+ return fullname
+ end
+ end
+ else
+ local fullname = joinname(root,p,n)
if isfile(fullname) then -- safeguard
return fullname
end
end
- else
- local fullname = joinname(root,p,n)
- if isfile(fullname) then -- safeguard
- return fullname
- end
end
+ return notfound()
end
- return notfound()
-end
--- no funny characters in path but in filename permitted .. sigh
-
-local function resolve(specification) -- can be called directly too
- local filename = specification.filename
- -- inspect(specification)
- if filename ~= "" then
- local root, rest = lpegmatch(splitter,filename)
- if root and rest then
- local path, name = dirname(rest), basename(rest)
- if name ~= rest then
- local content = collectors[root]
- local p, n = lookup(content,name)
- if not p then
- return notfound()
- end
- local pattern = ".*/" .. path .. "$"
- local istable = type(p) == "table"
- if istable then
- for i=1,#p do
- local pi = p[i]
- if pi == path or find(pi,pattern) then
- local fullname = joinname(root,pi,n)
- if isfile(fullname) then -- safeguard
- return fullname
+ -- no funny characters in path but in filename permitted .. sigh
+
+ resolve = function(specification) -- can be called directly too
+ local filename = specification.filename
+ -- inspect(specification)
+ if filename ~= "" then
+ local root, rest = lpegmatch(splitter,filename)
+ if root and rest then
+ local path, name = dirname(rest), basename(rest)
+ if name ~= rest then
+ local content = collectors[root]
+ local p, n = lookup(content,name)
+ if not p then
+ return notfound()
+ end
+ local pattern = ".*/" .. path .. "$"
+ local istable = type(p) == "table"
+ if istable then
+ for i=1,#p do
+ local pi = p[i]
+ if pi == path or find(pi,pattern) then
+ local fullname = joinname(root,pi,n)
+ if isfile(fullname) then -- safeguard
+ return fullname
+ end
end
end
+ elseif p == path or find(p,pattern) then
+ local fullname = joinname(root,p,n)
+ if isfile(fullname) then -- safeguard
+ return fullname
+ end
end
- elseif p == path or find(p,pattern) then
- local fullname = joinname(root,p,n)
- if isfile(fullname) then -- safeguard
- return fullname
+ local queries = specification.queries
+ if queries and queries.option == "fileonly" then
+ return checked(root,p,n)
+ else
+ return notfound()
end
end
- local queries = specification.queries
- if queries and queries.option == "fileonly" then
- return checked(root,p,n)
- else
- return notfound()
- end
+ end
+ local path = dirname(filename)
+ local name = basename(filename)
+ local root = lpegmatch(stripper,path)
+ local content = collectors[path]
+ local p, n = lookup(content,name)
+ if p then
+ return checked(root,p,n)
end
end
- local path, name = dirname(filename), basename(filename)
- local root = lpegmatch(stripper,path)
- local content = collectors[path]
- local p, n = lookup(content,name)
- if p then
- return checked(root,p,n)
- end
+ return notfound()
end
- return notfound()
-end
-resolvers.finders .dirlist = resolve
-resolvers.locators .dirlist = resolvers.locators .tree
-resolvers.hashers .dirlist = resolvers.hashers .tree
-resolvers.generators.dirlist = resolvers.generators.file
-resolvers.openers .dirlist = resolvers.openers .file
-resolvers.loaders .dirlist = resolvers.loaders .file
-
-function resolvers.finders.dirfile(specification)
- local queries = specification.queries
- if queries then
- queries.option = "fileonly"
- else
- specification.queries = { option = "fileonly" }
+ finders.dirlist = resolve
+
+ function finders.dirfile(specification)
+ local queries = specification.queries
+ if queries then
+ queries.option = "fileonly"
+ else
+ specification.queries = { option = "fileonly" }
+ end
+ return resolve(specification)
end
- return resolve(specification)
+
end
-resolvers.locators .dirfile = resolvers.locators .dirlist
-resolvers.hashers .dirfile = resolvers.hashers .dirlist
-resolvers.generators.dirfile = resolvers.generators.dirlist
-resolvers.openers .dirfile = resolvers.openers .dirlist
-resolvers.loaders .dirfile = resolvers.loaders .dirlist
+do
+
+ local fileopener = openers.file
+ local fileloader = loaders.file
+
+ openers.dirlist = fileopener
+ loaders.dirlist = fileloader
--- local locate = collectors[ [[E:\temporary\mb-mp]] ]
--- local locate = collectors( [[\\storage-2\resources\mb-mp]] )
+ openers.dirfile = fileopener
+ loaders.dirfile = fileloader
+
+end
-- print(resolvers.findtexfile("tree://e:/temporary/mb-mp/**/VB_wmf_03_vw_01d_ant.jpg"))
-- print(resolvers.findtexfile("tree://t:/**/tufte.tex"))
-- print(resolvers.findtexfile("dirlist://e:/temporary/mb-mp/**/VB_wmf_03_vw_01d_ant.jpg"))
+
+
+do
+
+ local hashfile = "dirhash.lua"
+ local kind = "HASH256"
+ local version = 1.0
+
+ local loadtable = table.load
+ local savetable = table.save
+ local loaddata = io.loaddata
+
+ function resolvers.dirstatus(patterns)
+ local t = type(patterns)
+ if t == "string" then
+ patterns = { patterns }
+ elseif t ~= "table" then
+ return false
+ end
+ local status = loadtable(hashfile)
+ if not status or status.version ~= version or status.kind ~= kind then
+ status = {
+ version = 1.0,
+ kind = kind,
+ hashes = { },
+ }
+ end
+ local hashes = status.hashes
+ local changed = { }
+ local action = sha2[kind]
+ local update = { }
+ for i=1,#patterns do
+ local pattern = patterns[i]
+ local files = globdir(pattern)
+ for i=1,#files do
+ local name = files[i]
+ local hash = action(loaddata(name))
+ if hashes[name] ~= hash then
+ changed[#changed+1] = name
+ end
+ update[name] = hash
+ end
+ end
+ status.hashes = update
+ savetable(hashfile,status)
+ return #changed > 0 and changed or false
+ end
+
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/data-use.lua b/Master/texmf-dist/tex/context/base/mkiv/data-use.lua
index 5985a2eac24..7df416b65c9 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/data-use.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/data-use.lua
@@ -6,48 +6,60 @@ if not modules then modules = { } end modules ['data-use'] = {
license = "see context related readme files"
}
-local format, lower, gsub, find = string.format, string.lower, string.gsub, string.find
+local format = string.format
local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end)
local report_mounts = logs.reporter("resolvers","mounts")
local resolvers = resolvers
+local findfile = resolvers.findfile
--- we will make a better format, maybe something xml or just text or lua
-
-resolvers.automounted = resolvers.automounted or { }
-
-function resolvers.automount(usecache)
- local mountpaths = resolvers.cleanpathlist(resolvers.expansion('TEXMFMOUNT'))
- if (not mountpaths or #mountpaths == 0) and usecache then
- mountpaths = caches.getreadablepaths("mount")
- end
- if mountpaths and #mountpaths > 0 then
- resolvers.starttiming()
- for k=1,#mountpaths do
- local root = mountpaths[k]
- local f = io.open(root.."/url.tmi")
- if f then
- for line in f:lines() do
- if line then
- if find(line,"^[%%#%-]") then -- or %W
- -- skip
- elseif find(line,"^zip://") then
- if trace_locating then
- report_mounts("mounting %a",line)
- end
- table.insert(resolvers.automounted,line)
- resolvers.usezipfile(line)
- end
- end
- end
- f:close()
- end
- end
- resolvers.stoptiming()
- end
-end
+-- -- This should mount a zip file so that we can run from zip files but I never went
+-- -- on with it. It's really old code, from right when we started with luatex and
+-- -- mkiv. Nowadays I'd use a lua specification file instead of a line based url.tmi,
+-- -- file so just to be modern I patched it but it's untested. This is a normally a
+-- -- startup-only feature.
+--
+-- do
+--
+-- local mounted = { }
+--
+-- function resolvers.automount(usecache)
+-- local mountpaths = resolvers.cleanpathlist(resolvers.expansion('TEXMFMOUNT'))
+-- if (not mountpaths or #mountpaths == 0) and usecache then
+-- mountpaths = caches.getreadablepaths("mount")
+-- end
+-- if mountpaths and #mountpaths > 0 then
+-- resolvers.starttiming()
+-- for k=1,#mountpaths do
+-- local root = mountpaths[k]
+-- local list = table.load("automount.lua")
+-- if list then
+-- local archives = list.archives
+-- if archives then
+-- for i=1,#archives do
+-- local archive = archives[i]
+-- local already = false
+-- for i=1,#mounted do
+-- if archive == mounted[i] then
+-- already = true
+-- break
+-- end
+-- end
+-- if not already then
+-- mounted[#mounted+1] = archive
+-- resolvers.usezipfile(archive)
+-- end
+-- end
+-- end
+-- end
+-- end
+-- resolvers.stoptiming()
+-- end
+-- end
+--
+-- end
-- status info
@@ -61,11 +73,13 @@ function statistics.savefmtstatus(texname,formatbanner,sourcefile,kind,banner) -
if formatbanner and enginebanner and sourcefile then
local luvname = file.replacesuffix(texname,"luv") -- utilities.lua.suffixes.luv
local luvdata = {
- enginebanner = enginebanner,
- formatbanner = formatbanner,
- sourcehash = md5.hex(io.loaddata(resolvers.findfile(sourcefile)) or "unknown"),
- sourcefile = sourcefile,
- luaversion = LUAVERSION,
+ enginebanner = enginebanner,
+ formatbanner = formatbanner,
+ sourcehash = md5.hex(io.loaddata(findfile(sourcefile)) or "unknown"),
+ sourcefile = sourcefile,
+ luaversion = LUAVERSION,
+ formatid = LUATEXFORMATID,
+ functionality = LUATEXFUNCTIONALITY,
}
io.savedata(luvname,table.serialize(luvdata,true))
lua.registerfinalizer(function()
@@ -90,7 +104,7 @@ function statistics.checkfmtstatus(texname)
if lfs.isfile(luvname) then
local luv = dofile(luvname)
if luv and luv.sourcefile then
- local sourcehash = md5.hex(io.loaddata(resolvers.findfile(luv.sourcefile)) or "unknown")
+ local sourcehash = md5.hex(io.loaddata(findfile(luv.sourcefile)) or "unknown")
local luvbanner = luv.enginebanner or "?"
if luvbanner ~= enginebanner then
return format("engine mismatch (luv: %s <> bin: %s)",luvbanner,enginebanner)
@@ -100,8 +114,19 @@ function statistics.checkfmtstatus(texname)
return format("source mismatch (luv: %s <> bin: %s)",luvhash,sourcehash)
end
local luvluaversion = luv.luaversion or 0
- if luvluaversion ~= LUAVERSION then
- return format("lua mismatch (luv: %s <> bin: %s)",luvluaversion,LUAVERSION)
+ local engluaversion = LUAVERSION or 0
+ if luvluaversion ~= engluaversion then
+ return format("lua mismatch (luv: %s <> bin: %s)",luvluaversion,engluaversion)
+ end
+ local luvfunctionality = luv.functionality or 0
+ local engfunctionality = status.development_id or 0
+ if luvfunctionality ~= engfunctionality then
+ return format("functionality mismatch (luv: %s <> bin: %s)",luvfunctionality,engfunctionality)
+ end
+ local luvformatid = luv.formatid or 0
+ local engformatid = status.format_id or 0
+ if luvformatid ~= engformatid then
+ return format("formatid mismatch (luv: %s <> bin: %s)",luvformatid,engformatid)
end
else
return "invalid status file"
diff --git a/Master/texmf-dist/tex/context/base/mkiv/data-vir.lua b/Master/texmf-dist/tex/context/base/mkiv/data-vir.lua
index 7e25c822d07..4b19ee53720 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/data-vir.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/data-vir.lua
@@ -6,7 +6,8 @@ if not modules then modules = { } end modules ['data-vir'] = {
license = "see context related readme files"
}
-local formatters, validstrings = string.formatters, string.valid
+local type = type
+local formatters = string.formatters
local trace_virtual = false
local report_virtual = logs.reporter("resolvers","virtual")
@@ -15,17 +16,20 @@ trackers.register("resolvers.locating", function(v) trace_virtual = v end)
trackers.register("resolvers.virtual", function(v) trace_virtual = v end)
local resolvers = resolvers
+local savers = resolvers.savers
-local finders, openers, loaders, savers = resolvers.finders, resolvers.openers, resolvers.loaders, resolvers.savers
+local data = { }
+local n = 0 -- hm, number can be query
+local f_virtual_n = formatters["virtual://%s.%s"]
+local f_virtual_y = formatters["virtual://%s-%s.%s"]
-local data = { }
-local n = 0 -- hm, number can be query
-local f_virtual = formatters["virtual://%s.%s"]
-
-function savers.virtual(specification,content)
+function savers.virtual(specification,content,suffix)
n = n + 1 -- one number for all namespaces
- local path = specification.path
- local filename = f_virtual(path ~= "" and path or "virtualfile",n)
+ local path = type(specification) == "table" and specification.path or specification
+ if type(path) ~= "string" or path == "" then
+ path = "virtualfile"
+ end
+ local filename = suffix and f_virtual_y(path,n,suffix) or f_virtual_n(path,n)
if trace_virtual then
report_virtual("saver: file %a saved",filename)
end
@@ -33,6 +37,9 @@ function savers.virtual(specification,content)
return filename
end
+local finders = resolvers.finders
+local notfound = finders.notfound
+
function finders.virtual(specification)
local original = specification.original
local d = data[original]
@@ -45,10 +52,14 @@ function finders.virtual(specification)
if trace_virtual then
report_virtual("finder: unknown file %a",original)
end
- return finders.notfound()
+ return notfound()
end
end
+local openers = resolvers.openers
+local notfound = openers.notfound
+local textopener = openers.helpers.textopener
+
function openers.virtual(specification)
local original = specification.original
local d = data[original]
@@ -59,15 +70,18 @@ function openers.virtual(specification)
data[original] = nil -- when we comment this we can have error messages
-- With utf-8 we signal that no regime is to be applied!
-- characters.showstring(d)
- return openers.helpers.textopener("virtual",original,d,"utf-8")
+ return textopener("virtual",original,d,"utf-8")
else
if trace_virtual then
report_virtual("opener: file %a not found",original)
end
- return openers.notfound()
+ return notfound()
end
end
+local loaders = resolvers.loaders
+local notfound = loaders.notfound
+
function loaders.virtual(specification)
local original = specification.original
local d = data[original]
@@ -81,5 +95,5 @@ function loaders.virtual(specification)
if trace_virtual then
report_virtual("loader: file %a not loaded",original)
end
- return loaders.notfound()
+ return notfound()
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/data-zip.lua b/Master/texmf-dist/tex/context/base/mkiv/data-zip.lua
index 388ae0c1053..8d914b842de 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/data-zip.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/data-zip.lua
@@ -26,7 +26,16 @@ zip:///texmf-mine.zip?tree=/tex/texmf-projects
</typing>
--ldx]]--
-local resolvers = resolvers
+local resolvers = resolvers
+local findfile = resolvers.findfile
+local registerfile = resolvers.registerfile
+local splitmethod = resolvers.splitmethod
+local prependhash = resolvers.prependhash
+local starttiming = resolvers.starttiming
+local extendtexmf = resolvers.extendtexmfvariable
+local stoptiming = resolvers.stoptiming
+
+local urlquery = url.query
zip = zip or { }
local zip = zip
@@ -50,8 +59,10 @@ if zipfiles then
validfile = zipfiles.found
wholefile = zipfiles.unzip
+ local listzip = zipfiles.list
+
traversezip = function(zfile)
- return ipairs(zipfiles.list(zfile))
+ return ipairs(listzip(zfile))
end
local streams = utilities.streams
@@ -120,13 +131,13 @@ local function validzip(str) -- todo: use url splitter
end
end
-function zip.openarchive(name)
+local function openarchive(name)
if not name or name == "" then
return nil
else
local arch = archives[name]
if not arch then
- local full = resolvers.findfile(name) or ""
+ local full = findfile(name) or ""
arch = full ~= "" and openzip(full) or false
archives[name] = arch
end
@@ -134,16 +145,19 @@ function zip.openarchive(name)
end
end
-function zip.closearchive(name)
+local function closearchive(name)
if not name or (name == "" and archives[name]) then
closezip(archives[name])
archives[name] = nil
end
end
+zip.openarchive = openarchive
+zip.closearchive = closearchive
+
function resolvers.locators.zip(specification)
local archive = specification.filename
- local zipfile = archive and archive ~= "" and zip.openarchive(archive) -- tricky, could be in to be initialized tree
+ local zipfile = archive and archive ~= "" and openarchive(archive) -- tricky, could be in to be initialized tree
if trace_locating then
if zipfile then
report_zip("locator: archive %a found",archive)
@@ -153,14 +167,6 @@ function resolvers.locators.zip(specification)
end
end
-function resolvers.hashers.zip(specification)
- local archive = specification.filename
- if trace_locating then
- report_zip("loading file %a",archive)
- end
- resolvers.usezipfile(specification.original)
-end
-
function resolvers.concatinators.zip(zipfile,path,name) -- ok ?
if not path or path == "" then
return format('%s?name=%s',zipfile,name)
@@ -169,14 +175,17 @@ function resolvers.concatinators.zip(zipfile,path,name) -- ok ?
end
end
-function resolvers.finders.zip(specification)
+local finders = resolvers.finders
+local notfound = finders.notfound
+
+function finders.zip(specification)
local original = specification.original
- local archive = specification.filename
+ local archive = specification.filename
if archive then
- local query = url.query(specification.query)
+ local query = urlquery(specification.query)
local queryname = query.name
if queryname then
- local zfile = zip.openarchive(archive)
+ local zfile = openarchive(archive)
if zfile then
if trace_locating then
report_zip("finder: archive %a found",archive)
@@ -197,17 +206,21 @@ function resolvers.finders.zip(specification)
if trace_locating then
report_zip("finder: %a not found",original)
end
- return resolvers.finders.notfound()
+ return notfound()
end
-function resolvers.openers.zip(specification)
+local openers = resolvers.openers
+local notfound = openers.notfound
+local textopener = openers.helpers.textopener
+
+function openers.zip(specification)
local original = specification.original
- local archive = specification.filename
+ local archive = specification.filename
if archive then
- local query = url.query(specification.query)
+ local query = urlquery(specification.query)
local queryname = query.name
if queryname then
- local zfile = zip.openarchive(archive)
+ local zfile = openarchive(archive)
if zfile then
if trace_locating then
report_zip("opener; archive %a opened",archive)
@@ -217,7 +230,7 @@ function resolvers.openers.zip(specification)
if trace_locating then
report_zip("opener: file %a found",queryname)
end
- return resolvers.openers.helpers.textopener('zip',original,handle)
+ return textopener('zip',original,handle)
elseif trace_locating then
report_zip("opener: file %a not found",queryname)
end
@@ -229,24 +242,26 @@ function resolvers.openers.zip(specification)
if trace_locating then
report_zip("opener: %a not found",original)
end
- return resolvers.openers.notfound()
+ return notfound()
end
-function resolvers.loaders.zip(specification)
+local loaders = resolvers.loaders
+local notfound = loaders.notfound
+
+function loaders.zip(specification)
local original = specification.original
- local archive = specification.filename
+ local archive = specification.filename
if archive then
- local query = url.query(specification.query)
+ local query = urlquery(specification.query)
local queryname = query.name
if queryname then
- local zfile = zip.openarchive(archive)
+ local zfile = openarchive(archive)
if zfile then
if trace_locating then
report_zip("loader: archive %a opened",archive)
end
local data = wholefile(zfile,queryname)
if data then
- logs.show_load(original)
if trace_locating then
report_zip("loader; file %a loaded",original)
end
@@ -262,52 +277,28 @@ function resolvers.loaders.zip(specification)
if trace_locating then
report_zip("loader: %a not found",original)
end
- return resolvers.openers.notfound()
+ return notfound()
end
-- zip:///somefile.zip
-- zip:///somefile.zip?tree=texmf-local -> mount
-function resolvers.usezipfile(archive)
- local specification = resolvers.splitmethod(archive) -- to be sure
- local archive = specification.filename
- if archive and not registeredfiles[archive] then
- local z = zip.openarchive(archive)
- if z then
- local tree = url.query(specification.query).tree or ""
- if trace_locating then
- report_zip("registering: archive %a",archive)
- end
- resolvers.starttiming()
- resolvers.prependhash('zip',archive)
- resolvers.extendtexmfvariable(archive) -- resets hashes too
- registeredfiles[archive] = z
- resolvers.registerfilehash(archive,resolvers.registerzipfile(z,tree))
- resolvers.stoptiming()
- elseif trace_locating then
- report_zip("registering: unknown archive %a",archive)
- end
- elseif trace_locating then
- report_zip("registering: archive %a not found",archive)
- end
-end
-
-function resolvers.registerzipfile(z,tree)
+local function registerzipfile(z,tree)
local names = { }
local files = { } -- somewhat overkill .. todo
local remap = { } -- somewhat overkill .. todo
local n = 0
local filter = tree == "" and "^(.+)/(.-)$" or format("^%s/(.+)/(.-)$",tree)
- local register = resolvers.registerfile
if trace_locating then
report_zip("registering: using filter %a",filter)
end
+ starttiming()
for i in traversezip(z) do
local filename = i.filename
local path, name = match(filename,filter)
if not path then
n = n + 1
- register(names,filename,"")
+ registerfile(names,filename,"")
local usedname = lower(filename)
files[usedname] = ""
if usedname ~= filename then
@@ -325,6 +316,7 @@ function resolvers.registerzipfile(z,tree)
-- directory
end
end
+ stoptiming()
report_zip("registering: %s files registered",n)
return {
-- metadata = { },
@@ -332,3 +324,36 @@ function resolvers.registerzipfile(z,tree)
remap = remap,
}
end
+
+local function usezipfile(archive)
+ local specification = splitmethod(archive) -- to be sure
+ local archive = specification.filename
+ if archive and not registeredfiles[archive] then
+ local z = openarchive(archive)
+ if z then
+ local tree = urlquery(specification.query).tree or ""
+ if trace_locating then
+ report_zip("registering: archive %a",archive)
+ end
+ prependhash('zip',archive)
+ extendtexmf(archive) -- resets hashes too
+ registeredfiles[archive] = z
+ registerfilehash(archive,registerzipfile(z,tree))
+ elseif trace_locating then
+ report_zip("registering: unknown archive %a",archive)
+ end
+ elseif trace_locating then
+ report_zip("registering: archive %a not found",archive)
+ end
+end
+
+resolvers.usezipfile = usezipfile
+resolvers.registerzipfile = registerzipfile
+
+function resolvers.hashers.zip(specification)
+ local archive = specification.filename
+ if trace_locating then
+ report_zip("loading file %a",archive)
+ end
+ usezipfile(specification.original)
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/driv-ini.lua b/Master/texmf-dist/tex/context/base/mkiv/driv-ini.lua
index e16327f27d7..316613b2167 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/driv-ini.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/driv-ini.lua
@@ -19,19 +19,33 @@ local report = logs.reporter("drivers")
local instances = { }
local helpers = { }
+local converters = { }
local prepared = { }
local wrappedup = { }
+local cleanedup = { }
local currentdriver = "default"
+local currentinstance = nil
+
+local shipout = tex.shipout
+local texgetbox = tex.getbox
+local texgetcount = tex.getcount
+
+function converters.engine(driver,boxnumber,mode,number,specification)
+ return shipout(boxnumber)
+end
local prepare = nil
local convert = nil
local wrapup = nil
+local cleanup = nil
local outputfilename = nil
drivers = drivers or {
instances = instances,
helpers = helpers,
+ converters = converters,
lmtxversion = 0.10,
+ report = report,
}
local dummy = function() end
@@ -42,6 +56,7 @@ local defaulthandlers = {
finalize = dummy,
updatefontstate = dummy,
wrapup = dummy,
+ cleanup = dummy,
convert = dummy,
outputfilename = dummy,
}
@@ -62,45 +77,74 @@ function drivers.install(specification)
report("no flushers for driver %a",name)
return
end
- setmetatableindex(actions,defaulthandlers)
+ -- report("driver %a is installed",name)
+ setmetatableindex(actions, defaulthandlers)
+ setmetatableindex(flushers, function() return dummy end)
instances[name] = specification
end
function drivers.convert(boxnumber)
- callbacks.functions.start_page_number()
- starttiming(drivers)
- convert(boxnumber)
- stoptiming(drivers)
- callbacks.functions.stop_page_number()
+ if currentinstance then
+ callbacks.functions.start_page_number()
+ starttiming(drivers)
+ convert(currentinstance,boxnumber,texgetcount("realpageno"))
+ stoptiming(drivers)
+ callbacks.functions.stop_page_number()
+ end
end
function drivers.outputfilename()
- return outputfilename()
+ if currentinstance then
+ return outputfilename(currentinstance)
+ end
end
-
luatex.wrapup(function()
- if not wrappedup[currentdriver] then
+ if currentinstance and wrapup and not wrappedup[currentdriver] then
starttiming(drivers)
- wrapup()
+ wrapup(currentinstance)
stoptiming(drivers)
wrappedup[currentdriver] = true
+ cleanedup[currentdriver] = true
end
end)
-function drivers.enable(name)
- currentdriver = name or "default"
- local actions = instances[currentdriver].actions
- prepare = actions.prepare
- wrapup = actions.wrapup
- convert = actions.convert
- outputfilename = actions.outputfilename
- --
- if prepare and not prepared[currentdriver] then
+luatex.cleanup(function()
+ if currentinstance and cleanup and not cleanedup[currentdriver] then
starttiming(drivers)
- prepare()
+ cleanup(currentinstance)
stoptiming(drivers)
- prepared[currentdriver] = true
+ wrappedup[currentdriver] = true
+ cleanedup[currentdriver] = true
+ end
+end)
+
+function drivers.enable(name)
+ if name ~= currentdriver then
+ if currentinstance then
+ starttiming(drivers)
+ cleanup(currentinstance)
+ stoptiming(drivers)
+ end
+ currentdriver = name or "default"
+ currentinstance = instances[currentdriver]
+ if currentinstance then
+ local actions = currentinstance.actions
+ prepare = actions.prepare
+ wrapup = actions.wrapup
+ cleanup = actions.cleanup
+ convert = actions.convert
+ outputfilename = actions.outputfilename
+ --
+ if prepare and not prepared[currentdriver] then
+ starttiming(drivers)
+ prepare(currentinstance)
+ stoptiming(drivers)
+ prepared[currentdriver] = true
+ end
+ else
+ report("bad driver")
+ end
end
end
@@ -129,8 +173,8 @@ do
drivers.install {
name = "default",
actions = {
- convert = tex.shipout,
- outputfilename = function()
+ convert = drivers.converters.engine,
+ outputfilename = function(driver)
if not filename then
filename = addsuffix(tex.jobname,"pdf")
end
@@ -144,6 +188,41 @@ do
end
+-- No driver:
+
+do
+
+ drivers.install {
+ name = "none",
+ actions = { },
+ flushers = { },
+ }
+
+end
+
+do
+
+ local function prepare(driver)
+ converter = drivers.converters.lmtx
+ end
+
+ local function convert(driver,boxnumber,pagenumber)
+ converter(driver,texgetbox(boxnumber),"page",pagenumber)
+ end
+
+ drivers.install {
+ name = "empty",
+ actions = {
+ prepare = prepare,
+ convert = convert,
+ },
+ flushers = { },
+ }
+
+end
+
+--
+
setmetatableindex(instances,function() return instances.default end)
-- for now:
@@ -153,13 +232,8 @@ drivers.enable("default")
-- helpers
local s_matrix_0 = "1 0 0 1"
-local f_matrix_2 = formatters["%.6F 0 0 %.6F"]
-local f_matrix_4 = formatters["%.6F %.6F %.6F %.6F"]
-
-directives.register("pdf.stripzeros",function()
- f_matrix_2 = formatters["%.6N 0 0 %.6N"]
- f_matrix_4 = formatters["%.6N %.6N %.6N %.6N"]
-end)
+local f_matrix_2 = formatters["%.6N 0 0 %.6N"]
+local f_matrix_4 = formatters["%.6N %.6N %.6N %.6N"]
function helpers.tomatrix(rx,sx,sy,ry,tx,ty) -- todo: tx ty
if type(rx) == "string" then
diff --git a/Master/texmf-dist/tex/context/base/mkiv/driv-ini.mkiv b/Master/texmf-dist/tex/context/base/mkiv/driv-ini.mkiv
index 95b6c88a7b4..96e7460a3c1 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/driv-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/driv-ini.mkiv
@@ -13,13 +13,18 @@
\writestatus{loading}{ConTeXt Driver Macros / Initialization}
+%D Around the \CONTEXT\ 2018 meeting I had a preliminary backend written in \LUA\ as
+%D alternative for the hard coded variant (we're talking of the font embedding and
+%D page stream output, the part we still used). Therefore there is a pluggable
+%D output driver. But \unknown\ I decided not to waste time on supporting both
+%D \LUATEX\ and the new kid \LUAMETATEX, also because in practice \LUATEX\ would be
+%D used as benchmark, using the more traditional approach. So, the code in the
+%D driver modules is mostly a kind of simple placeholder now and although I could
+%D simplify it ther eis no real reason for it. It is no problem to getit all working
+%D well in normal \LUATEX, it's just that we don't need it there.
+
\registerctxluafile{driv-ini}{}
\unprotect
-\def\page_shipout_box#1%
- {\clf_shipoutpage#1\relax
- \setbox#1\emptybox
- \global\deadcycles\zerocount}
-
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/driv-ini.mkxl b/Master/texmf-dist/tex/context/base/mkiv/driv-ini.mkxl
new file mode 100644
index 00000000000..9f489a2a1a6
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/driv-ini.mkxl
@@ -0,0 +1,20 @@
+%D \module
+%D [ file=driv-ini,
+%D version=2018.07.26,
+%D title=\CONTEXT\ Driver Macros,
+%D subtitle=Initialization,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Driver Macros / Initialization}
+
+\registerctxluafile{driv-ini}{}
+
+\unprotect
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/driv-shp.lua b/Master/texmf-dist/tex/context/base/mkiv/driv-shp.lua
new file mode 100644
index 00000000000..a4e36105d09
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/driv-shp.lua
@@ -0,0 +1,1328 @@
+if not modules then modules = { } end modules ['driv-shp'] = {
+ version = 1.001,
+ comment = "companion to driv-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local type, next = type, next
+local round = math.round
+
+local setmetatableindex = table.setmetatableindex
+local formatters = string.formatters
+local concat = table.concat
+local keys = table.keys
+local sortedhash = table.sortedhash
+local splitstring = string.split
+local idiv = number.idiv
+local extract = bit32.extract
+local nuts = nodes.nuts
+
+local tonut = nodes.tonut
+local tonode = nodes.tonode
+
+local getdirection = nuts.getdirection
+local getlist = nuts.getlist
+local getoffsets = nuts.getoffsets
+local getorientation = nuts.getorientation
+local getfield = nuts.getfield
+local getwhd = nuts.getwhd
+local getkern = nuts.getkern
+local getheight = nuts.getheight
+local getdepth = nuts.getdepth
+----- getwidth = nuts.getwidth
+local getnext = nuts.getnext
+local getsubtype = nuts.getsubtype
+local getid = nuts.getid
+local getleader = nuts.getleader
+----- getglue = nuts.getglue
+local getshift = nuts.getshift
+local getdata = nuts.getdata
+----- getexpansion = nuts.getexpansion
+local getreplace = nuts.getreplace
+local setreplace = nuts.setreplace
+local getfont = nuts.getfont
+
+local setdirection = nuts.setdirection
+local setfield = nuts.setfield
+local setlink = nuts.setlink
+
+local isglyph = nuts.isglyph
+local findtail = nuts.tail
+local nextdir = nuts.traversers.dir
+local nextnode = nuts.traversers.node
+
+local rangedimensions = node.direct.rangedimensions -- nuts ?
+local effectiveglue = nuts.effective_glue
+local start_of_par = nuts.start_of_par
+local dirdimensions = nuts.dirdimensions
+
+local texget = tex.get
+
+local fonthashes = fonts.hashes
+local fontdata = fonthashes.identifiers
+local characters = fonthashes.characters
+local parameters = fonthashes.parameters
+
+local nodecodes = nodes.nodecodes
+local whatsitcodes = nodes.whatsitcodes
+local leadercodes = nodes.leadercodes
+local gluecodes = nodes.gluecodes
+local dircodes = nodes.dircodes
+local dirvalues = nodes.dirvalues
+local subtypes = nodes.subtypes
+
+local normaldir_code <const> = dircodes.normal
+
+local lefttoright_code <const> = dirvalues.lefttoright
+local righttoleft_code <const> = dirvalues.righttoleft
+
+local glyph_code <const> = nodecodes.glyph
+local kern_code <const> = nodecodes.kern
+local glue_code <const> = nodecodes.glue
+local hlist_code <const> = nodecodes.hlist
+local vlist_code <const> = nodecodes.vlist
+local dir_code <const> = nodecodes.dir
+local disc_code <const> = nodecodes.disc
+local math_code <const> = nodecodes.math
+local rule_code <const> = nodecodes.rule
+local marginkern_code <const> = nodecodes.marginkern
+local whatsit_code <const> = nodecodes.whatsit
+----- penalty_code <const> = nodecodes.penalty
+----- boundary_code <const> = nodecodes.boundary
+
+local leaders_code <const> = leadercodes.leaders
+local cleaders_code <const> = leadercodes.cleaders
+local xleaders_code <const> = leadercodes.xleaders
+local gleaders_code <const> = leadercodes.gleaders
+
+local spaceskip_code <const> = gluecodes.spaceskip
+
+local saveposwhatsit_code <const> = whatsitcodes.savepos
+local userdefinedwhatsit_code <const> = whatsitcodes.userdefined
+local openwhatsit_code <const> = whatsitcodes.open
+local writewhatsit_code <const> = whatsitcodes.write
+local closewhatsit_code <const> = whatsitcodes.close
+local lateluawhatsit_code <const> = whatsitcodes.latelua
+local literalwhatsit_code <const> = whatsitcodes.literal
+local setmatrixwhatsit_code <const> = whatsitcodes.setmatrix
+local savewhatsit_code <const> = whatsitcodes.save
+local restorewhatsit_code <const> = whatsitcodes.restore
+
+local getpagedimensions getpagedimensions = function()
+ getpagedimensions = backends.codeinjections.getpagedimensions
+ return getpagedimensions()
+end
+
+local drivers = drivers
+local instances = drivers.instances
+
+local report = logs.reporter("drivers")
+
+---------------------------------------------------------------------------------------
+
+local lastfont = nil
+local fontcharacters = nil
+
+local magicconstants = tex.magicconstants
+local trueinch = magicconstants.trueinch
+local maxdimen = magicconstants.maxdimen
+local running = magicconstants.running
+
+local pos_h = 0
+local pos_v = 0
+local pos_r = lefttoright_code
+local shippingmode = "none"
+
+local abs_max_v = 0
+local abs_max_h = 0
+
+local shipbox_h = 0
+local shipbox_v = 0
+local page_size_h = 0
+local page_size_v = 0
+----- page_h_origin = 0 -- trueinch
+----- page_v_origin = 0 -- trueinch
+
+local initialize
+local finalize
+local updatefontstate
+local pushorientation
+local poporientation
+local flushcharacter
+local flushfontchar
+local flushrule
+local flushliteral
+local flushsetmatrix
+local flushsave
+local flushrestore
+local flushspecial
+----- flushimage
+
+-- make local
+
+function drivers.getpos () return round(pos_h), round(pos_v) end
+function drivers.getrpos() return round(pos_h), round(pos_v), pos_r end
+function drivers.gethpos() return round(pos_h) end
+function drivers.getvpos() return round(pos_v) end
+
+-- characters
+
+local flush_character
+
+local stack = setmetatableindex("table")
+local level = 0
+local nesting = 0
+local main = 0
+
+-- experiment (smaller page stream but might be fragile)
+
+local tospace = false directives.register("backends.spaces", function(v) tospace = v end)
+
+-- todo: cache streams
+
+local function flush_vf_packet(pos_h,pos_v,pos_r,font,char,data,factor,vfcommands)
+
+ if nesting > 100 then
+ return
+ elseif nesting == 0 then
+ main = font
+ end
+
+ nesting = nesting + 1
+
+ local saved_h = pos_h
+ local saved_v = pos_v
+ local saved_r = pos_r
+ pos_r = lefttoright_code
+
+ local data = fontdata[font]
+ local fnt = font
+ local fonts = data.fonts
+ local siz = (data.parameters.factor or 1)/65536
+
+ local function flushchar(font,char,fnt,chr,f,e)
+ if fnt then
+ local nest = char ~= chr or font ~= fnt
+ if fnt == 0 then
+ fnt = main
+ end
+ return flush_character(false,fnt,chr,factor,nest,pos_h,pos_v,pos_r,f,e)
+ else
+ return 0
+ end
+ end
+
+ -- we assume resolved fonts: id mandate but maybe also size
+
+ for i=1,#vfcommands do
+ local packet = vfcommands[i]
+ local command = packet[1]
+ if command == "char" then
+ local chr = packet[2]
+ local f = packet[3]
+ local e = packet[4]
+ pos_h = pos_h + flushchar(font,char,fnt,chr,f,e)
+ elseif command == "slot" then
+ local index = packet[2]
+ local chr = packet[3]
+ local f = packet[4]
+ local e = packet[5]
+ if index == 0 then
+ pos_h = pos_h + flushchar(font,char,font,chr,f,e)
+ else
+ local okay = fonts and fonts[index]
+ if okay then
+ local fnt = okay.id
+ if fnt then
+ pos_h = pos_h + flushchar(font,char,fnt,chr,f,e)
+ end
+ else
+ -- safeguard, we assume the font itself (often index 1)
+ pos_h = pos_h + flushchar(font,char,font,chr,f,e)
+ end
+ end
+ elseif command == "use" then
+ local index = packet[2]
+ if index then
+ local fnt
+ if index == 0 then
+ fnt = font
+ else
+ local okay = fonts and fonts[index]
+ if okay then
+ fnt = okay.id
+ end
+ end
+ if fnt then
+ -- not efficient but ok for now as experiment
+ local d = characters[fnt]
+ if d then
+ for i=3,#packet do
+ local chr = packet[i]
+ local dat = d[chr]
+ if dat then
+ flushfontchar(fnt,chr,dat)
+ end
+ end
+ end
+ end
+ end
+ elseif command == "right" then
+ local h = packet[2] -- * siz
+ if factor ~= 0 and h ~= 0 then
+ h = h + h * factor / 1000 -- expansion
+ end
+ pos_h = pos_h + h
+ elseif command == "down" then
+ local v = packet[2] -- * siz
+ pos_v = pos_v - v
+ elseif command == "push" then
+ level = level + 1
+ local s = stack[level]
+ s[1] = pos_h
+ s[2] = pos_v
+ elseif command == "pop" then
+ if level > 0 then
+ local s = stack[level]
+ pos_h = s[1]
+ pos_v = s[2]
+ level = level - 1
+ end
+ elseif command == "pdf" then
+ flushliteral(false,pos_h,pos_v,packet[2],packet[3])
+ elseif command == "rule" then
+ local size_v = packet[2]
+ local size_h = packet[3]
+ if factor ~= 0 and size_h > 0 then
+ size_h = size_h + size_h * factor / 1000
+ end
+ if size_h > 0 and size_v > 0 then
+ flushsimplerule(pos_h,pos_v,pos_r,size_h,size_v)
+ pos_h = pos_h + size_h
+ end
+ elseif command == "font" then
+ local index = packet[2]
+ local okay = fonts and fonts[index]
+ if okay then
+ fnt = okay.id or fnt -- or maybe just return
+ end
+ elseif command == "lua" then
+ local code = packet[2]
+ if type(code) ~= "function" then
+ code = loadstring(code)
+ end
+ if type(code) == "function" then
+ code(font,char,pos_h,pos_v)
+ end
+ elseif command == "node" then
+ hlist_out(packet[2])
+ elseif command == "image" then
+ -- doesn't work because intercepted by engine so we use a different
+ -- mechanism (for now)
+ local image = packet[2]
+ -- to do
+ elseif command == "pdfmode" then
+ -- doesn't happen
+ -- elseif command == "special" then
+ -- -- not supported
+ -- elseif command == "nop" then
+ -- -- nothing to do|
+ -- elseif command == "scale" then
+ -- -- not supported
+ end
+ end
+
+ pos_h = saved_h
+ pos_v = saved_v
+ pos_r = saved_r
+
+ nesting = nesting - 1
+end
+
+local onetimemessage -- could be defined later (todo: make plug for this)
+
+flush_character = function(current,font,char,factor,vfcommands,pos_h,pos_v,pos_r,f,e)
+
+ if font ~= lastfont then
+ lastfont = font
+ fontcharacters = characters[font]
+ updatefontstate(font)
+ end
+
+ local data = fontcharacters[char]
+ if not data then
+ if char > 0 then
+ if not onetimemessage then
+ onetimemessage = fonts.loggers.onetimemessage
+ end
+ onetimemessage(font,char,"missing")
+ end
+ return 0, 0, 0
+ end
+
+ local width, height, depth, naturalwidth
+ if current then
+ naturalwidth, height, depth, factor = getwhd(current,true)
+ if factor == 0 then
+ width = naturalwidth
+ else
+ -- width = (1.0 + factor/1000000.0) * naturalwidth
+ width = naturalwidth + naturalwidth * factor/1000000.0
+ -- width = naturalwidth + naturalwidth * 0.000001 * factor
+ end
+ else
+ width = data.width or 0
+ height = data.height or 0
+ depth = data.depth or 0
+ naturalwidth = width
+ if not factor then
+ factor = 0
+ end
+ end
+
+ if pos_r == righttoleft_code then
+ pos_h = pos_h - width
+ end
+ if vfcommands then
+ vfcommands = data.commands
+ end
+ if vfcommands then
+ flush_vf_packet(pos_h,pos_v,pos_r,font,char,data,factor,vfcommands) -- also f ?
+ else
+ -- kind of messy that we do orientation here and offsets elsewhere
+ local orientation = data.orientation
+ if orientation and (orientation == 1 or orientation == 3) then
+ local x = data.xoffset
+ local y = data.yoffset
+ if x then
+ pos_h = pos_h + x
+ end
+ if y then
+ pos_v = pos_v + y
+ end
+ pushorientation(orientation,pos_h,pos_v)
+ flushcharacter(current,pos_h,pos_v,pos_r,font,char,data,f,e,factor) -- ,naturalwidth,width)
+ poporientation(orientation,pos_h,pos_v)
+ else
+ flushcharacter(current,pos_h,pos_v,pos_r,font,char,data,f,e,factor) -- ,naturalwidth,width)
+ end
+ end
+ return width, height, depth
+end
+
+-- end of characters
+
+local function reset_state()
+ pos_h = 0
+ pos_v = 0
+ pos_r = lefttoright_code
+ shipbox_h = 0
+ shipbox_v = 0
+ shippingmode = "none"
+ page_size_h = 0
+ page_size_v = 0
+ -- page_h_origin = 0 -- trueinch
+ -- page_v_origin = 0 -- trueinch
+end
+
+-- local function dirstackentry(t,k)
+-- local v = {
+-- cur_h = 0,
+-- cur_v = 0,
+-- ref_h = 0,
+-- ref_v = 0,
+-- }
+-- t[k] = v
+-- return v
+-- end
+
+----- dirstack = { }
+local dirstack = setmetatableindex(dirstackentry)
+
+local function reset_dir_stack()
+ -- dirstack = setmetatableindex(dirstackentry)
+ dirstack = { }
+end
+
+local function flushlatelua(current,h,v)
+ return backends.latelua(current,h,v)
+end
+
+local function flushwriteout(current)
+ if not doing_leaders then
+ backends.writeout(current)
+ end
+end
+
+local function flushopenout(current)
+ if not doing_leaders then
+ backends.openout(current)
+ end
+end
+
+local function flushcloseout(current)
+ if not doing_leaders then
+ backends.closeout(current)
+ end
+end
+
+local hlist_out, vlist_out do
+
+ local function applyanchor(orientation,x,y,width,height,depth,woffset,hoffset,doffset,xoffset,yoffset)
+ local ot = extract(orientation, 0,4)
+ local ay = extract(orientation, 4,4)
+ local ax = extract(orientation, 8,4)
+ local of = extract(orientation,12,4)
+ if ot == 4 then
+ ot, ay = 0, 1
+ elseif ot == 5 then
+ ot, ay = 0, 2
+ end
+ if ot == 0 or ot == 2 then
+ if ax == 1 then x = x - width
+ elseif ax == 2 then x = x + width
+ elseif ax == 3 then x = x - width/2
+ elseif ax == 4 then x = x + width/2
+ end
+ if ot == 2 then
+ doffset, hoffset = hoffset, doffset
+ end
+ if ay == 1 then y = y - doffset
+ elseif ay == 2 then y = y + hoffset
+ elseif ay == 3 then y = y + (doffset + hoffset)/2 - doffset
+ end
+ elseif ot == 1 or ot == 3 then
+ if ay == 1 then y = y - height
+ elseif ay == 2 then y = y + height
+ elseif ay == 3 then y = y - height/2
+ end
+ if ot == 1 then
+ doffset, hoffset = hoffset, doffset
+ end
+ if ax == 1 then x = x - width
+ elseif ax == 2 then x = x + width
+ elseif ax == 3 then x = x - width/2
+ elseif ax == 4 then x = x + width/2
+ elseif ax == 5 then x = x - hoffset
+ elseif ax == 6 then x = x + doffset
+ end
+ end
+ return ot, x + xoffset, y - yoffset
+ end
+
+ -- to be checked: begin- or enddir kan nil zijn, weird
+
+ -- local function calculate_width_to_enddir(this_box,begindir) -- can be a helper
+ -- local dir_nest = 1
+ -- local enddir = begindir
+ -- for current, subtype in nextdir, getnext(begindir) do
+ -- if subtype == normaldir_code then -- todo
+ -- dir_nest = dir_nest + 1
+ -- else
+ -- dir_nest = dir_nest - 1
+ -- end
+ -- if dir_nest == 0 then -- does the type matter
+ -- enddir = current
+ -- local width = rangedimensions(this_box,begindir,enddir)
+ -- return enddir, width
+ -- end
+ -- end
+ -- if enddir == begindir then
+ -- local width = rangedimensions(this_box,begindir) -- ,enddir)
+ -- return enddir, width
+ -- end
+ -- return enddir, 0
+ -- end
+
+ -- check frequencies of nodes
+
+ hlist_out = function(this_box,current)
+ local outer_doing_leaders = false
+
+ local ref_h = pos_h
+ local ref_v = pos_v
+ local ref_r = pos_r
+ pos_r = getdirection(this_box)
+ local boxwidth,
+ boxheight,
+ boxdepth = getwhd(this_box)
+
+ local cur_h = 0
+ local cur_v = 0
+
+ if not current then
+ current = getlist(this_box)
+ end
+
+ -- we can encounter localpar, boundary and penalty nodes but a special
+ -- iterator over content nodes won't save much
+
+ for current, id, subtype in nextnode, current do
+ if id == glyph_code then
+ local char, font = isglyph(current)
+ local x_offset, y_offset = getoffsets(current)
+ if x_offset ~= 0 or y_offset ~= 0 then
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - (cur_h + x_offset)
+ else
+ pos_h = ref_h + (cur_h + x_offset)
+ end
+ pos_v = ref_v - (cur_v - y_offset)
+ -- synced
+ end
+ -- local wd, ht, dp = flush_character(current,font,char,false,true,pos_h,pos_v,pos_r)
+ local wd = flush_character(current,font,char,false,true,pos_h,pos_v,pos_r)
+ cur_h = cur_h + wd
+ elseif id == glue_code then
+ local gluewidth = effectiveglue(current,this_box)
+ if gluewidth ~= 0 then
+ if subtype >= leaders_code then
+ local leader = getleader(current)
+ if leader then
+ local width, height, depth = getwhd(leader)
+ if getid(leader) == rule_code then
+ if gluewidth > 0 then
+ if height == running then
+ height = boxheight
+ end
+ if depth == running then
+ depth = boxdepth
+ end
+ local total = height + depth
+ if total > 0 then
+ if pos_r == righttoleft_code then
+ pos_h = pos_h - gluewidth
+ end
+ pos_v = pos_v - depth
+ flushrule(leader,pos_h,pos_v,pos_r,gluewidth,total,getsubtype(leader))
+ end
+ cur_h = cur_h + gluewidth
+ end
+ elseif width > 0 and gluewidth > 0 then
+ local boxdir = getdirection(leader) or lefttoright_code
+ gluewidth = gluewidth + 10
+ local edge = cur_h + gluewidth
+ local lx = 0
+ if subtype == gleaders_code then
+ local save_h = cur_h
+ if pos_r == righttoleft_code then
+ cur_h = ref_h - shipbox_h - cur_h
+ cur_h = width * (cur_h / width)
+ cur_h = ref_h - shipbox_h - cur_h
+ else
+ cur_h = cur_h + ref_h - shipbox_h
+ cur_h = width * (cur_h / width)
+ cur_h = cur_h - ref_h - shipbox_h
+ end
+ if cur_h < save_h then
+ cur_h = cur_h + width
+ end
+ elseif subtype == leaders_code then
+ local save_h = cur_h
+ cur_h = width * (cur_h / width)
+ if cur_h < save_h then
+ cur_h = cur_h + width
+ end
+ else
+ lq = gluewidth / width
+ lr = gluewidth % width
+ if subtype == cleaders_code then
+ cur_h = cur_h + lr / 2
+ else
+ lx = lr / (lq + 1)
+ cur_h = cur_h + (lr - (lq - 1) * lx) / 2
+ end
+ end
+ local shift = getshift(leader)
+ while cur_h + width <= edge do
+ local basepoint_h = 0
+ -- local basepoint_v = shift
+ if boxdir ~= pos_r then
+ basepoint_h = boxwidth
+ end
+ -- synch_pos_with_cur(ref_h,ref_v,cur_h + basepoint_h,shift)
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - (cur_h + basepoint_h)
+ else
+ pos_h = ref_h + (cur_h + basepoint_h)
+ end
+ pos_v = ref_v - shift
+ -- synced
+ outer_doing_leaders = doing_leaders
+ doing_leaders = true
+ if getid(leader) == vlist_code then
+ vlist_out(leader)
+ else
+ hlist_out(leader)
+ end
+ doing_leaders = outer_doing_leaders
+ cur_h = cur_h + width + lx
+ end
+ cur_h = edge - 10
+ else
+ cur_h = cur_h + gluewidth
+ end
+ else
+ cur_h = cur_h + gluewidth
+ end
+ else
+ if tospace and subtype == spaceskip_code then
+ -- todo: flush_space
+ flush_character(false,getfont(current),32,false,true,pos_h,pos_v,pos_r)
+ end
+ cur_h = cur_h + gluewidth
+ end
+ end
+ elseif id == hlist_code or id == vlist_code then
+ local boxdir = getdirection(current) or lefttoright_code
+ local width, height, depth = getwhd(current)
+ local list = getlist(current)
+ if list then
+ local shift, orientation = getshift(current)
+ if not orientation then
+ local basepoint_h = boxdir ~= pos_r and width or 0
+ -- local basepoint_v = shift
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - (cur_h + basepoint_h)
+ else
+ pos_h = ref_h + (cur_h + basepoint_h)
+ end
+ pos_v = ref_v - shift
+ -- synced
+ if id == vlist_code then
+ vlist_out(current,list)
+ else
+ hlist_out(current,list)
+ end
+ elseif orientation == 0x1000 then
+ local orientation, xoffset, yoffset = getorientation(current)
+ local basepoint_h = boxdir ~= pos_r and width or 0
+ -- local basepoint_v = shift
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - (cur_h + basepoint_h + xoffset)
+ else
+ pos_h = ref_h + (cur_h + basepoint_h + xoffset)
+ end
+ pos_v = ref_v - (shift - yoffset)
+ -- synced
+ if id == vlist_code then
+ vlist_out(current,list)
+ else
+ hlist_out(current,list)
+ end
+ else
+ local orientation, xoffset, yoffset, woffset, hoffset, doffset = getorientation(current)
+ local orientation, basepoint_h, basepoint_v = applyanchor(orientation,0,shift,width,height,depth,woffset,hoffset,doffset,xoffset,yoffset)
+ if orientation == 1 then
+ basepoint_h = basepoint_h + doffset
+ if boxdir == pos_r then
+ basepoint_v = basepoint_v - height
+ end
+ elseif orientation == 2 then
+ if boxdir == pos_r then
+ basepoint_h = basepoint_h + width
+ end
+ elseif orientation == 3 then
+ basepoint_h = basepoint_h + hoffset
+ if boxdir ~= pos_r then
+ basepoint_v = basepoint_v - height
+ end
+ end
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - (cur_h + basepoint_h)
+ else
+ pos_h = ref_h + (cur_h + basepoint_h)
+ end
+ pos_v = ref_v - (cur_v + basepoint_v)
+ -- synced
+ pushorientation(orientation,pos_h,pos_v,pos_r)
+ if id == vlist_code then
+ vlist_out(current,list)
+ else
+ hlist_out(current,list)
+ end
+ poporientation(orientation,pos_h,pos_v,pos_r)
+ end
+ end
+ cur_h = cur_h + width
+ elseif id == disc_code then
+ local replace, tail = getreplace(current)
+ if replace and subtype ~= select_disc then
+ -- we could flatten .. no gain
+ setlink(tail,getnext(current))
+ setlink(current,replace)
+ setreplace(current)
+ end
+ elseif id == kern_code then
+ local kern, factor = getkern(current,true)
+ if kern ~= 0 then
+ if factor and factor ~= 0 then
+ cur_h = cur_h + (1.0 + factor/1000000.0) * kern
+ else
+ cur_h = cur_h + kern
+ end
+ end
+ elseif id == rule_code then
+ local width, height, depth = getwhd(current)
+ if width > 0 then
+ if height == running then
+ height = boxheight
+ end
+ if depth == running then
+ depth = boxdepth
+ end
+ local total = height + depth
+ if total > 0 then
+ local xoffset, yoffset, left, right = getoffsets(current) -- top bottom
+ if left ~= 0 then
+ pos_v = pos_v + left
+ total = total - left
+ end
+ if right ~= 0 then
+ depth = depth - right
+ total = total - right
+ end
+ if pos_r == righttoleft_code then
+ pos_h = pos_h - width
+ xoffset = - xoffset
+ end
+ pos_v = pos_v - depth
+ flushrule(current,pos_h + xoffset,pos_v + yoffset,pos_r,width,total,subtype)
+ end
+ cur_h = cur_h + width
+ end
+ elseif id == math_code then
+ -- local kern = getkern(current)
+ -- if kern ~= 0 then
+ -- cur_h = cur_h + kern
+ -- else
+ cur_h = cur_h + effectiveglue(current,this_box)
+ -- end
+ elseif id == dir_code then
+ -- We normally have proper begin-end pairs. A begin without end is (silently) handled
+ -- and an end without a begin will be (silently) skipped we only need to move forward
+ -- so we then have a faster calculation.
+ local dir, cancel = getdirection(current)
+ if cancel then
+ local ds = dirstack[current]
+ if ds then
+ ref_h = ds.ref_h
+ ref_v = ds.ref_v
+ cur_h = ds.cur_h
+ cur_v = ds.cur_v
+ else
+ -- pardir
+ end
+ pos_r = dir
+ else
+ local width, enddir = dirdimensions(this_box,current)
+ local new_h = cur_h + width
+ if dir ~= pos_r then
+ cur_h = new_h
+ end
+ if enddir ~= current then
+ dirstack[enddir] = {
+ cur_h = new_h,
+ cur_v = cur_v,
+ ref_h = ref_h,
+ ref_v = ref_v,
+ }
+ setdirection(enddir,pos_r)
+ end
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - cur_h
+ else
+ pos_h = ref_h + cur_h
+ end
+ pos_v = ref_v - cur_v
+ -- synced
+ ref_h = pos_h
+ ref_v = pos_v
+ cur_h = 0
+ cur_v = 0
+ pos_r = dir
+ goto synced
+ end
+ elseif id == whatsit_code then
+ if subtype == literalwhatsit_code then
+ flushliteral(current,pos_h,pos_v)
+ elseif subtype == lateluawhatsit_code then
+ flushlatelua(current,pos_h,pos_v)
+ elseif subtype == setmatrixwhatsit_code then
+ flushsetmatrix(current,pos_h,pos_v)
+ elseif subtype == savewhatsit_code then
+ flushsave(current,pos_h,pos_v)
+ elseif subtype == restorewhatsit_code then
+ flushrestore(current,pos_h,pos_v)
+ elseif subtype == saveposwhatsit_code then
+ last_position_x = pos_h
+ last_position_y = pos_v
+ elseif subtype == writewhatsit_code then
+ flushwriteout(current)
+ elseif subtype == closewhatsit_code then
+ flushcloseout(current)
+ elseif subtype == openwhatsit_code then
+ flushopenout(current)
+ end
+ elseif id == marginkern_code then
+ cur_h = cur_h + getkern(current)
+ -- elseif id == localpar_code and start_of_par(current) then
+ -- local pardir = getdirection(current) or lefttoright_code
+ -- if pardir == righttoleft_code then
+ -- end
+ -- end
+ end
+ -- There is no gain in skipping over this when we have zero progression
+ -- and such.
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - cur_h
+ else
+ pos_h = ref_h + cur_h
+ end
+ pos_v = ref_v - cur_v
+ ::synced::
+ end
+ pos_h = ref_h
+ pos_v = ref_v
+ pos_r = ref_r
+ end
+
+ vlist_out = function(this_box,current)
+ local outer_doing_leaders = false
+
+ local ref_h = pos_h
+ local ref_v = pos_v
+ local ref_r = pos_r
+ pos_r = getdirection(this_box)
+
+ local boxwidth,
+ boxheight,
+ boxdepth = getwhd(this_box)
+
+ local cur_h = 0
+ local cur_v = - boxheight
+
+ local top_edge = cur_v
+
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - cur_h
+ else
+ pos_h = ref_h + cur_h
+ end
+ pos_v = ref_v - cur_v
+ -- synced
+
+ if not current then
+ current = getlist(this_box)
+ end
+
+ -- while current do
+ -- local id = getid(current)
+ for current, id, subtype in nextnode, current do
+ if id == glue_code then
+ local glueheight = effectiveglue(current,this_box)
+ if glueheight ~= 0 then
+ if subtype >= leaders_code then
+ local leader = getleader(current)
+ if leader then
+ local width, height, depth = getwhd(leader)
+ local total = height + depth
+ if getid(leader) == rule_code then
+ depth = 0 -- hm
+ if total > 0 then
+ if width == running then
+ width = boxwidth
+ end
+ if width > 0 then
+ if pos_r == righttoleft_code then
+ cur_h = cur_h - width
+ end
+ flushrule(leader,pos_h,pos_v - total,pos_r,width,total,getsubtype(leader))
+ end
+ cur_v = cur_v + total
+ end
+ elseif total > 0 and glueheight > 0 then
+ glueheight = glueheight + 10
+ local edge = cur_v + glueheight
+ local ly = 0
+ if subtype == gleaders_code then
+ save_v = cur_v
+ cur_v = ref_v - shipbox_v - cur_v
+ cur_v = total * (cur_v / total)
+ cur_v = ref_v - shipbox_v - cur_v
+ if cur_v < save_v then
+ cur_v = cur_v + total
+ end
+ elseif subtype == leaders_code then -- aleader
+ save_v = cur_v
+ cur_v = top_edge + total * ((cur_v - top_edge) / total)
+ if cur_v < save_v then
+ cur_v = cur_v + total
+ end
+ else
+ lq = glueheight / total
+ lr = glueheight % total
+ if subtype == cleaders_code then
+ cur_v = cur_v + lr / 2
+ else
+ ly = lr / (lq + 1)
+ cur_v = cur_v + (lr - (lq - 1) * ly) / 2
+ end
+ end
+ local shift = getshift(leader)
+ while cur_v + total <= edge do -- todo: <= edge - total
+ -- synch_pos_with_cur(ref_h, ref_v, getshift(leader), cur_v + height)
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - shift
+ else
+ pos_h = ref_h + shift
+ end
+ pos_v = ref_v - (cur_v + height)
+ -- synced
+ outer_doing_leaders = doing_leaders
+ doing_leaders = true
+ if getid(leader) == vlist_code then
+ vlist_out(leader)
+ else
+ hlist_out(leader)
+ end
+ doing_leaders = outer_doing_leaders
+ cur_v = cur_v + total + ly
+ end
+ cur_v = edge - 10
+ else
+ cur_v = cur_v + glueheight
+ end
+ end
+ else
+ cur_v = cur_v + glueheight
+ end
+ end
+ elseif id == hlist_code or id == vlist_code then
+ local boxdir = getdirection(current) or lefttoright_code
+ local width, height, depth = getwhd(current)
+ local list = getlist(current)
+ if list then
+ local shift, orientation = getshift(current)
+ if not orientation then
+ -- local basepoint_h = shift
+ -- local basepoint_v = height
+ if boxdir ~= pos_r then
+ shift = shift + width
+ end
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - shift
+ else
+ pos_h = ref_h + shift
+ end
+ pos_v = ref_v - (cur_v + height)
+ -- synced
+ if id == vlist_code then
+ vlist_out(current,list)
+ else
+ hlist_out(current,list)
+ end
+ elseif orientation == 0x1000 then
+ local orientation, xoffset, yoffset = getorientation(current)
+ -- local basepoint_h = shift
+ -- local basepoint_v = height
+ if boxdir ~= pos_r then
+ shift = shift + width
+ end
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - (shift + xoffset)
+ else
+ pos_h = ref_h + (shift + xoffset)
+ end
+ pos_v = ref_v - (cur_v + height - yoffset)
+ -- synced
+ if id == vlist_code then
+ vlist_out(current,list)
+ else
+ hlist_out(current,list)
+ end
+ else
+ local orientation, xoffset, yoffset, woffset, hoffset, doffset = getorientation(current)
+ local orientation, basepoint_h, basepoint_v = applyanchor(orientation,shift,height,width,height,depth,woffset,hoffset,doffset,xoffset,yoffset)
+ if orientation == 1 then
+ basepoint_h = basepoint_h + width - height
+ basepoint_v = basepoint_v - height
+ elseif orientation == 2 then
+ basepoint_h = basepoint_h + width
+ basepoint_v = basepoint_v + depth - height
+ elseif orientation == 3 then -- weird
+ basepoint_h = basepoint_h + height
+ end
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - basepoint_h
+ else
+ pos_h = ref_h + basepoint_h
+ end
+ pos_v = ref_v - (cur_v + basepoint_v)
+ -- synced
+ pushorientation(orientation,pos_h,pos_v,pos_r)
+ if id == vlist_code then
+ vlist_out(current,list)
+ else
+ hlist_out(current,list)
+ end
+ poporientation(orientation,pos_h,pos_v,pos_r)
+ end
+ end
+ cur_v = cur_v + height + depth
+ elseif id == kern_code then
+ cur_v = cur_v + getkern(current)
+ elseif id == rule_code then
+ local width, height, depth = getwhd(current)
+ local total = height + depth
+ if total > 0 then
+ if width == running then
+ width = boxwidth
+ end
+ if width > 0 then
+ local xoffset, yoffset, left, right = getoffsets(current)
+ if left ~= 0 then
+ width = width - left
+ xoffset = left
+ end
+ if right ~= 0 then
+ width = width - right
+ end
+ if pos_r == righttoleft_code then
+ xoffset = - xoffset - width
+ end
+ flushrule(current,pos_h + xoffset,pos_v - total - yoffset,pos_r,width,total,subtype)
+ end
+ cur_v = cur_v + total
+ end
+ elseif id == whatsit_code then
+ if subtype == literalwhatsit_code then
+ flushliteral(current,pos_h,pos_v)
+ elseif subtype == lateluawhatsit_code then
+ flushlatelua(current,pos_h,pos_v)
+ elseif subtype == setmatrixwhatsit_code then
+ flushsetmatrix(current,pos_h,pos_v)
+ elseif subtype == savewhatsit_code then
+ flushsave(current,pos_h,pos_v)
+ elseif subtype == restorewhatsit_code then
+ flushrestore(current,pos_h,pos_v)
+ elseif subtype == saveposwhatsit_code then
+ last_position_x = pos_h
+ last_position_y = pos_v
+ elseif subtype == writewhatsit_code then
+ flushwriteout(current)
+ elseif subtype == closewhatsit_code then
+ flushcloseout(current)
+ elseif subtype == openwhatsit_code then
+ flushopenout(current)
+ end
+ end
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - cur_h
+ else
+ pos_h = ref_h + cur_h
+ end
+ pos_v = ref_v - cur_v
+ ::synced::
+ end
+ pos_h = ref_h
+ pos_v = ref_v
+ pos_r = ref_r
+ end
+
+end
+
+function drivers.converters.lmtx(driver,box,smode,objnum,specification)
+
+ if not driver then
+ report("error in converter, no driver")
+ return
+ end
+
+ if box then
+ box = tonut(box)
+ else
+ report("error in converter, no box")
+ return
+ end
+
+ local actions = driver.actions
+ local flushers = driver.flushers
+
+ initialize = actions.initialize
+ finalize = actions.finalize
+
+ updatefontstate = flushers.updatefontstate
+
+ pushorientation = flushers.pushorientation
+ poporientation = flushers.poporientation
+
+ flushcharacter = flushers.character
+ flushfontchar = flushers.fontchar
+ flushrule = flushers.rule
+ flushsimplerule = flushers.simplerule
+ flushspecial = flushers.special
+ flushliteral = flushers.literal
+ flushsetmatrix = flushers.setmatrix
+ flushsave = flushers.save
+ flushrestore = flushers.restore
+ -- flushimage = flushers.image
+
+ reset_dir_stack()
+ reset_state()
+
+ shippingmode = smode
+
+ local details = nil -- must be outside labels
+
+ local width, height, depth = getwhd(box)
+
+ local total = height + depth
+
+ ----- v_offset_par = 0
+ ----- h_offset_par = 0
+
+ local max_v = total -- + v_offset_par
+ local max_h = width -- + h_offset_par
+
+ if height > maxdimen or depth > maxdimen or width > maxdimen then
+ goto DONE
+ end
+
+ if max_v > maxdimen then
+ goto DONE
+ elseif max_v > abs_max_v then
+ abs_max_v = max_v
+ end
+
+ if max_h > maxdimen then
+ goto DONE
+ elseif max_h > abs_max_h then
+ abs_max_h = max_h
+ end
+
+ if shippingmode == "page" then
+
+ -- We have zero offsets in ConTeXt.
+
+ local pagewidth, pageheight = getpagedimensions()
+
+ -- local h_offset_par = texget("hoffset")
+ -- local v_offset_par = texget("voffset")
+
+ -- page_h_origin = trueinch
+ -- page_v_origin = trueinch
+
+ pos_r = lefttoright_code
+
+ if pagewidth > 0 then
+ page_size_h = pagewidth
+ else
+ page_size_h = width
+ end
+
+ if page_size_h == 0 then
+ page_size_h = width
+ end
+
+ if pageheight > 0 then
+ page_size_v = pageheight
+ else
+ page_size_v = total
+ end
+
+ if page_size_v == 0 then
+ page_size_v = total
+ end
+
+ local refpoint_h = 0 -- + page_h_origin + h_offset_par
+ local refpoint_v = page_size_v -- - page_v_origin - v_offset_par
+
+ pos_h = refpoint_h
+ pos_v = refpoint_v - height
+ -- synced
+
+ else
+
+ -- page_h_origin = 0
+ -- page_v_origin = 0
+ page_size_h = width
+ page_size_v = total
+ pos_r = getdirection(box)
+ pos_v = depth
+ pos_h = pos_r == righttoleft_code and width or 0
+
+ end
+
+ shipbox_ref_h = pos_h
+ shipbox_ref_v = pos_v
+
+ details = {
+ shippingmode = smode, -- target
+ boundingbox = { 0, 0, page_size_h, page_size_v },
+ objectnumber = smode ~= "page" and objnum or nil,
+ pagenumber = smode == "page" and objnum or nil,
+ specification = specification,
+ }
+
+ initialize(driver,details)
+
+ lastfont = nil -- this forces a sync each page / object
+
+ if getid(box) == vlist_code then
+ vlist_out(box)
+ else
+ hlist_out(box)
+ end
+
+ ::DONE::
+
+ finalize(driver,details)
+
+ shippingmode = "none"
+end
+
+-- This will move to back-out.lua eventually.
+
+do
+
+ ----- sortedhash = table.sortedhash
+
+ ----- tonut = nodes.tonut
+ local properties = nodes.properties.data
+ local flush = texio.write_nl
+
+ local periods = utilities.strings.newrepeater(".")
+
+ local function showdetails(n,l)
+ local p = properties[tonut(n)]
+ if p then
+ local done = false
+ for k, v in sortedhash(p) do
+ if done then
+ flush("\n")
+ else
+ done = true
+ end
+ flush(periods[l+1] .. " " .. k .. " = " .. tostring(v))
+ end
+ end
+ end
+
+ local whatsittracers = {
+ latelua = showdetails,
+ literal = showdetails,
+ }
+
+ callback.register("show_whatsit",function(n,l)
+ local s = nodes.whatsitcodes[n.subtype]
+ texio.write(" [" .. s .. "]")
+ local w = whatsittracers[s]
+ if w then
+ w(n,l)
+ end
+ end)
+
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/driv-shp.mkxl b/Master/texmf-dist/tex/context/base/mkiv/driv-shp.mkxl
new file mode 100644
index 00000000000..68b62c72a72
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/driv-shp.mkxl
@@ -0,0 +1,18 @@
+%D \module
+%D [ file=driv-shp,
+%D version=2018.07.26,
+%D title=\CONTEXT\ Driver Macros,
+%D subtitle=Shipout,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\registerctxluafile{driv-shp}{optimize}
+
+\unprotect
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/export-example.css b/Master/texmf-dist/tex/context/base/mkiv/export-example.css
index c39f0bec637..19a2a071e88 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/export-example.css
+++ b/Master/texmf-dist/tex/context/base/mkiv/export-example.css
@@ -78,13 +78,13 @@ context|div.document {
font-family : "DejaVu Serif", "Lucida Bright", serif ;
font-size : 12pt ;
/* line-height : 14.4pt; */
- line-height : 2.8ex;
+ line-height : 2.8ex;
max-width : 50em ;
padding : 1em ;
- /* text-align : justify ; */
- text-align : justify ;
- /* hyphens : manual ; */
- /* text-justify : inter-word ; */
+ /* text-align : justify ; */
+ text-align : justify ;
+ /* hyphens : manual ; */
+ /* text-justify : inter-word ; */
}
document>metadata,
@@ -124,7 +124,7 @@ context|div.document context|div.metadata context|div.metavariable.metaname-titl
font-family : "DejaVu Serif", "Lucida Bright", serif ;
font-weight : bold ;
font-size : 3em ;
- text-align : left ;
+ text-align : left ;
margin-bottom : 2ex ;
}
@@ -183,7 +183,7 @@ context|div.section {
sectioncaption,
context|div.sectioncaption {
display : block ;
- text-align : left ;
+ text-align : left ;
page-break-after : avoid ;
margin-top : 3ex ;
margin-bottom : 2ex ;
@@ -343,7 +343,7 @@ context|div.section.summary context|div.sectioncaption context|div.sectiontitle
border-bottom-style : solid ;
border-color : rgb(50%,50%,100%) ;
border-width : .15em;
- text-align : left ;
+ text-align : left ;
}
section[detail="subsummary"]>sectioncaption>sectiontitle,
@@ -355,7 +355,7 @@ context|div.section.subsummary context|div.sectioncaption context|div.sectiontit
border-color : rgb(50%,50%,100%) ;
border-bottom-style : dotted ;
border-width : .15em ;
- text-align : left ;
+ text-align : left ;
}
/* itemgroup : display */
@@ -367,13 +367,13 @@ context|div.section.subsummary context|div.sectioncaption context|div.sectiontit
/* suffix : '.' ; */
@counter-style lower-greek { /* css 3 */
- type : non-repeating ;
- glyphs : 'α' 'β' 'γ' 'δ' 'ε' 'ζ' 'η' 'θ' 'ι' 'κ' 'λ' 'μ' 'ν' 'ξ' 'ο' 'π' 'ρ' 'σ' 'τ' 'υ' 'φ' 'χ' 'ψ' 'ω' ;
+ type : non-repeating ;
+ glyphs : 'α' 'β' 'γ' 'δ' 'ε' 'ζ' 'η' 'θ' 'ι' 'κ' 'λ' 'μ' 'ν' 'ξ' 'ο' 'π' 'ρ' 'σ' 'τ' 'υ' 'φ' 'χ' 'ψ' 'ω' ;
}
@counter-style upper-greek { /* css 3 */
- type : non-repeating ;
- glyphs : 'Α' 'B' 'Γ' 'Δ' 'Ε' 'Ζ' 'Η' 'Θ' 'Ι' 'Κ' 'Λ' 'Μ' 'Ν' 'Ξ' 'Ο' 'Π' 'Ρ' 'Σ' 'Τ' 'Υ' 'Φ' 'Χ' 'Ψ' 'Ω' ;
+ type : non-repeating ;
+ glyphs : 'Α' 'B' 'Γ' 'Δ' 'Ε' 'Ζ' 'Η' 'Θ' 'Ι' 'Κ' 'Λ' 'Μ' 'Ν' 'Ξ' 'Ο' 'Π' 'Ρ' 'Σ' 'Τ' 'Υ' 'Φ' 'Χ' 'Ψ' 'Ω' ;
}
itemgroup,
@@ -428,11 +428,11 @@ context|div.description {
descriptiontag,
context|div.descriptiontag {
display : inline ;
- float : left ;
- clear : left ;
+ float : left ;
+ clear : left ;
margin-right : 1em ;
- text-align : left ;
- font-weight : bold ;
+ text-align : left ;
+ font-weight : bold ;
}
descriptioncontent,
@@ -537,8 +537,8 @@ context|div.registerlocation:after {
content : "\25B6\00A0\00A0" ;
color : rgb(40%,40%,40%) ;
font-size : x-small ;
- line-height : 0 ;
- padding-top : 0.5ex ;
+ line-height : 0 ;
+ padding-top : 0.5ex ;
vertical-align : top ;
}
@@ -814,22 +814,22 @@ context|div.delimitedblock.quote:after {
delimited,
context|div.delimited {
- display : inline
+ display : inline
}
delimitedcontent,
context|div.delimitedcontent {
- display : inline
+ display : inline
}
delimitedsymbol,
context|div.delimitedsymbol {
- display : inline
+ display : inline
}
delimitedblock,
context|div.delimitedblock {
- display : block
+ display : block
}
subsentence:before,
@@ -841,17 +841,17 @@ context|div.subsentence:after {
subsentence,
context|div.subsentence {
- display : inline
+ display : inline
}
subsentencecontent,
context|div.subsentencecontent {
- display : inline
+ display : inline
}
subsentencesymbol,
context|div.subsentencesymbol {
- display : inline
+ display : inline
}
/* label : mixed */
diff --git a/Master/texmf-dist/tex/context/base/mkiv/file-job.lua b/Master/texmf-dist/tex/context/base/mkiv/file-job.lua
index 486aee63a72..407c3c15da1 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/file-job.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/file-job.lua
@@ -46,7 +46,7 @@ local dirname = file.dirname
local is_qualified_path = file.is_qualified_path
local cleanpath = resolvers.cleanpath
-local inputstack = resolvers.inputstack
+local toppath = resolvers.toppath
local resolveprefix = resolvers.resolve
local hasscheme = url.hasscheme
@@ -172,8 +172,8 @@ implement {
-- moved from tex to lua:
-local texpatterns = { "%s.mkvi", "%s.mkiv", "%s.tex" }
-local luapatterns = { "%s" .. utilities.lua.suffixes.luc, "%s.lua" }
+local texpatterns = { "%s.mkvi", "%s.mkiv", "%s.mklx", "%s.mkxl", "%s.tex" }
+local luapatterns = { "%s" .. utilities.lua.suffixes.luc, "%s.lua", "%s.lmt" }
local cldpatterns = { "%s.cld" }
local xmlpatterns = { "%s.xml" }
@@ -326,6 +326,8 @@ end
local suffixes = {
mkvi = usetexfile,
mkiv = usetexfile,
+ mklx = usetexfile,
+ mkxl = usetexfile,
tex = usetexfile,
luc = useluafile,
lua = useluafile,
@@ -789,7 +791,7 @@ end
local function autoname(name)
if name == "*" then
- name = nameonly(inputstack[#inputstack] or name)
+ name = nameonly(toppath() or name)
end
return name
end
@@ -1114,11 +1116,11 @@ function document.setfilenames()
end
end
-implement { name = "setdocumentcommandline", actions = document.setcommandline, onlyonce = true }
-implement { name = "setdocumentmodes", actions = document.setmodes, onlyonce = true }
-implement { name = "setdocumentmodules", actions = document.setmodules, onlyonce = true }
-implement { name = "setdocumentenvironments", actions = document.setenvironments, onlyonce = true }
-implement { name = "setdocumentfilenames", actions = document.setfilenames, onlyonce = true }
+implement { name = "setdocumentcommandline", actions = document.setcommandline, onlyonce = true }
+implement { name = "setdocumentmodes", actions = document.setmodes, onlyonce = true }
+implement { name = "setdocumentmodules", actions = document.setmodules, onlyonce = true }
+implement { name = "setdocumentenvironments", actions = document.setenvironments, onlyonce = true }
+implement { name = "setdocumentfilenames", actions = document.setfilenames, onlyonce = true }
do
diff --git a/Master/texmf-dist/tex/context/base/mkiv/file-lib.lua b/Master/texmf-dist/tex/context/base/mkiv/file-lib.lua
index 62cf938ba4d..9b0679e250d 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/file-lib.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/file-lib.lua
@@ -61,13 +61,18 @@ function resolvers.uselibrary(specification) -- todo: reporter
if not foundname then
-- pattern based search
for i=1,#patterns do
- local wanted = format(patterns[i],barename)
- foundname = found(wanted)
- if trace_libraries then
- report_library("checking %a as %a: %s",filename,wanted,foundname or "not found")
- end
- if foundname then
- break
+ local pattern = patterns[i]
+ if pattern and pattern ~= "" then
+ local wanted = format(pattern,barename)
+ foundname = found(wanted)
+ if trace_libraries then
+ report_library("checking %a as %a: %s",filename,wanted,foundname or "not found")
+ end
+ if foundname then
+ break
+ end
+ else
+ -- can be a bogus path (coming from a test)
end
end
end
@@ -89,4 +94,24 @@ function resolvers.uselibrary(specification) -- todo: reporter
end
end
-commands.uselibrary = resolvers.uselibrary -- for the moment
+-- We keep these in the commands namespace even if it's not that logical
+-- but this way we are compatible.
+
+function commands.loadlibrary(name,foundname,nointerference)
+ if not foundname then
+ foundname = name
+ end
+ if foundname and foundname ~= "" then
+ if nointerference then
+ context.startnointerference()
+ end
+ context.startreadingfile()
+ context.input(foundname)
+ context.stopreadingfile()
+ if nointerference then
+ context.stopnointerference()
+ end
+ end
+end
+
+commands.uselibrary = resolvers.uselibrary
diff --git a/Master/texmf-dist/tex/context/base/mkiv/file-mod.lua b/Master/texmf-dist/tex/context/base/mkiv/file-mod.lua
index 81320f96eff..10a18717865 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/file-mod.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/file-mod.lua
@@ -36,7 +36,7 @@ local iterator = utilities.parsers.iterator
-- modules can have a specific suffix or can specify one
-local prefixes = {
+local prefixes = {
"m", -- module, extends functionality
"p", -- private code
"s", -- styles
@@ -47,13 +47,24 @@ local prefixes = {
-- the order might change and how about cld
-local suffixes = {
- "mkvi", -- proprocessed mkiv files
+local suffixes = CONTEXTLMTXMODE > 0 and
+{
+ "mklx", -- preprocessed mkiv lmtx files
+ "mkxl", -- mkiv lmtx files
+ "mkvi", -- preprocessed mkiv files
"mkiv", -- mkiv files
"tex", -- normally source code files
"cld", -- context lua documents (often stand alone)
"lua", -- lua files
}
+ or
+{
+ "mkvi",
+ "mkiv",
+ "tex",
+ "cld",
+ "lua",
+}
local modstatus = { }
local missing = false
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-age.lua b/Master/texmf-dist/tex/context/base/mkiv/font-age.lua
index b20a57538e2..1545c1c8d3c 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-age.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-age.lua
@@ -12,6 +12,9 @@ if context then
os.exit()
end
+-- There is no need for a special script to generate this list as it's seldom
+-- changes: inspect(fonts.encodings.agl.unicodes) will do.
+
return {
["A"]=65,
["AE"]=198,
@@ -1603,6 +1606,7 @@ return {
["eightideographicparen"]=12839,
["eightinferior"]=8328,
["eightmonospace"]=65304,
+ ["eightoldstyle"]=56,
["eightparen"]=9339,
["eightperiod"]=9359,
["eightpersian"]=1784,
@@ -1760,6 +1764,7 @@ return {
["fiveideographicparen"]=12836,
["fiveinferior"]=8325,
["fivemonospace"]=65301,
+ ["fiveoldstyle"]=53,
["fiveparen"]=9336,
["fiveperiod"]=9356,
["fivepersian"]=1781,
@@ -1788,6 +1793,7 @@ return {
["fourinferior"]=8324,
["fourmonospace"]=65300,
["fournumeratorbengali"]=2551,
+ ["fouroldstyle"]=52,
["fourparen"]=9335,
["fourperiod"]=9355,
["fourpersian"]=1780,
@@ -2616,6 +2622,7 @@ return {
["nineideographicparen"]=12840,
["nineinferior"]=8329,
["ninemonospace"]=65305,
+ ["nineoldstyle"]=57,
["nineparen"]=9340,
["nineperiod"]=9360,
["ninepersian"]=1785,
@@ -2782,6 +2789,7 @@ return {
["oneinferior"]=8321,
["onemonospace"]=65297,
["onenumeratorbengali"]=2548,
+ ["oneoldstyle"]=49,
["oneparen"]=9332,
["oneperiod"]=9352,
["onepersian"]=1777,
@@ -3298,6 +3306,7 @@ return {
["sevenideographicparen"]=12838,
["seveninferior"]=8327,
["sevenmonospace"]=65303,
+ ["sevenoldstyle"]=55,
["sevenparen"]=9338,
["sevenperiod"]=9358,
["sevenpersian"]=1783,
@@ -3394,6 +3403,7 @@ return {
["sixideographicparen"]=12837,
["sixinferior"]=8326,
["sixmonospace"]=65302,
+ ["sixoldstyle"]=54,
["sixparen"]=9337,
["sixperiod"]=9357,
["sixpersian"]=1782,
@@ -3602,6 +3612,7 @@ return {
["threeinferior"]=8323,
["threemonospace"]=65299,
["threenumeratorbengali"]=2550,
+ ["threeoldstyle"]=51,
["threeparen"]=9334,
["threeperiod"]=9354,
["threepersian"]=1779,
@@ -3722,6 +3733,7 @@ return {
["twoinferior"]=8322,
["twomonospace"]=65298,
["twonumeratorbengali"]=2549,
+ ["twooldstyle"]=50,
["twoparen"]=9333,
["twoperiod"]=9353,
["twopersian"]=1778,
@@ -4088,6 +4100,7 @@ return {
["zerohackarabic"]=1632,
["zeroinferior"]=8320,
["zeromonospace"]=65296,
+ ["zerooldstyle"]=48,
["zeropersian"]=1776,
["zerosuperior"]=8304,
["zerothai"]=3664,
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-agl.lua b/Master/texmf-dist/tex/context/base/mkiv/font-agl.lua
index 49b85421f1c..19912b94478 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-agl.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-agl.lua
@@ -395,7 +395,7 @@ local synonyms = allocate {
zeroarabic = 0x0660,
}
-local extras = allocate { -- private extensions
+local extras = allocate { -- private extensions
Dcroat = 0x0110,
Delta = 0x2206,
Euro = 0x20AC,
@@ -635,6 +635,17 @@ local extras = allocate { -- private extensions
theta1 = 0x03D1,
twodotenleader = 0x2025,
+ zerooldstyle = 0x0030,
+ oneoldstyle = 0x0031,
+ twooldstyle = 0x0032,
+ threeoldstyle = 0x0033,
+ fouroldstyle = 0x0034,
+ fiveoldstyle = 0x0035,
+ sixoldstyle = 0x0036,
+ sevenoldstyle = 0x0037,
+ eightoldstyle = 0x0038,
+ nineoldstyle = 0x0039,
+
dotlessj = 0x0237,
}
@@ -653,7 +664,7 @@ if names then
mark(unicodes)
mark(ctxcodes)
-else
+elseif characters then
names = allocate { } -- filled from char-def.lua
unicodes = allocate { }
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-aux.lua b/Master/texmf-dist/tex/context/base/mkiv/font-aux.lua
index 4ac6278cbcf..0e4d7add3f0 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-aux.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-aux.lua
@@ -240,3 +240,7 @@ function fonts.getmultiple(tfmdata,k,kind)
return 0
end
end
+
+function fonts.getindices(tfmdata)
+ return getindices(tfmdata)
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-cff.lua b/Master/texmf-dist/tex/context/base/mkiv/font-cff.lua
index 46deedb5f93..72b0a038f17 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-cff.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-cff.lua
@@ -27,7 +27,7 @@ if not modules then modules = { } end modules ['font-cff'] = {
-- the other hand, we can now feed back cff2 stuff.
local next, type, tonumber, rawget = next, type, tonumber, rawget
-local byte, char, gmatch = string.byte, string.char, string.gmatch
+local byte, char, gmatch, sub = string.byte, string.char, string.gmatch, string.sub
local concat, remove, unpack = table.concat, table.remove, table.unpack
local floor, abs, round, ceil, min, max = math.floor, math.abs, math.round, math.ceil, math.min, math.max
local P, C, R, S, C, Cs, Ct = lpeg.P, lpeg.C, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpeg.Ct
@@ -145,6 +145,38 @@ local defaultstrings = { [0] = -- taken from ff
"Black", "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold",
}
+local standardnames = { [0] = -- needed for seac
+ false, false, false, false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, false, false,
+ "space", "exclam", "quotedbl", "numbersign", "dollar", "percent",
+ "ampersand", "quoteright", "parenleft", "parenright", "asterisk", "plus",
+ "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four",
+ "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less",
+ "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H",
+ "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W",
+ "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum",
+ "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
+ "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y",
+ "z", "braceleft", "bar", "braceright", "asciitilde", false, false, false,
+ false, false, false, false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, false, "exclamdown",
+ "cent", "sterling", "fraction", "yen", "florin", "section", "currency",
+ "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft",
+ "guilsinglright", "fi", "fl", false, "endash", "dagger", "daggerdbl",
+ "periodcentered", false, "paragraph", "bullet", "quotesinglbase",
+ "quotedblbase", "quotedblright", "guillemotright", "ellipsis", "perthousand",
+ false, "questiondown", false, "grave", "acute", "circumflex", "tilde",
+ "macron", "breve", "dotaccent", "dieresis", false, "ring", "cedilla", false,
+ "hungarumlaut", "ogonek", "caron", "emdash", false, false, false, false,
+ false, false, false, false, false, false, false, false, false, false, false,
+ false, "AE", false, "ordfeminine", false, false, false, false, "Lslash",
+ "Oslash", "OE", "ordmasculine", false, false, false, false, false, "ae",
+ false, false, false, "dotlessi", false, false, "lslash", "oslash", "oe",
+ "germandbls", false, false, false, false
+}
+
local cffreaders = {
readbyte,
readushort,
@@ -152,6 +184,15 @@ local cffreaders = {
readulong,
}
+directives.register("fonts.streamreader",function()
+ cffreaders = {
+ readbyte,
+ readushort,
+ readuint,
+ readulong,
+ }
+end)
+
-- The header contains information about its own size.
local function readheader(f)
@@ -655,6 +696,7 @@ do
local x = 0
local y = 0
local width = false
+ local lsb = 0
local r = 0
local stems = 0
local globalbias = 0
@@ -678,6 +720,9 @@ do
local factors = false
local axis = false
local vsindex = 0
+ local justpass = false
+ local seacs = { }
+ local procidx = nil
local function showstate(where)
report("%w%-10s : [%s] n=%i",depth*2,where,concat(stack," ",1,top),top)
@@ -1012,43 +1057,6 @@ do
top = 0
end
--- local function xxcurveto(swap)
--- local last = top % 4 ~= 0 and stack[top]
--- if last then
--- top = top - 1
--- end
--- for i=1,top,4 do
--- local ax, ay, bx, by
--- if swap then
--- ax = x + stack[i]
--- ay = y
--- bx = ax + stack[i+1]
--- by = ay + stack[i+2]
--- y = by + stack[i+3]
--- if last and i+3 == top then
--- x = bx + last
--- else
--- x = bx
--- end
--- swap = false
--- else
--- ax = x
--- ay = y + stack[i]
--- bx = ax + stack[i+1]
--- by = ay + stack[i+2]
--- x = bx + stack[i+3]
--- if last and i+3 == top then
--- y = by + last
--- else
--- y = by
--- end
--- swap = true
--- end
--- xycurveto(ax,ay,bx,by,x,y)
--- end
--- top = 0
--- end
-
local function xxcurveto(swap)
local last = top % 4 ~= 0 and stack[top]
if last then
@@ -1086,7 +1094,6 @@ do
top = 0
end
-
local function hvcurveto()
if trace_charstrings then
showstate("hvcurveto")
@@ -1302,7 +1309,7 @@ do
end
local function divide()
- if version == 1 then
+ if version == "cff" then
local d = stack[top]
top = top - 1
stack[top] = stack[top] / d
@@ -1310,7 +1317,7 @@ do
end
local function closepath()
- if version == 1 then
+ if version == "cff" then
if trace_charstrings then
showstate("closepath")
end
@@ -1319,65 +1326,90 @@ do
end
local function hsbw()
- if version == 1 then
+ if version == "cff" then
if trace_charstrings then
showstate("hsbw")
end
- -- lsb = stack[top-1]
+ lsb = stack[top-1] or 0
width = stack[top]
end
top = 0
end
- local function seac()
- if version == 1 then
+ local function sbw()
+ if version == "cff" then
if trace_charstrings then
- showstate("seac")
+ showstate("sbw")
end
+ lsb = stack[top-3]
+ width = stack[top-1]
end
top = 0
end
- local function sbw()
- if version == 1 then
+ -- asb adx ady bchar achar seac (accented characters)
+
+ local function seac()
+ if version == "cff" then
if trace_charstrings then
- showstate("sbw")
+ showstate("seac")
end
- width = stack[top-1]
end
top = 0
end
- -- these are probably used for special cases i.e. call out to postscript
+ -- These are probably used for special cases i.e. call out to the
+ -- postscript interpreter (p 61 of the spec as well as chapter 8).
+ --
+ -- This needs checking (I have to ask Taco next time we meet.)
+
+ local popped = 3
+ local hints = 3
+
+ -- arg1 ... argn n othersubr# <callothersubr> (on postscript stack)
local function callothersubr()
- if version == 1 then
- -- we don't support this (ok, we could mimick these othersubs)
+ if version == "cff" then
if trace_charstrings then
- showstate("callothersubr (unsupported)")
+ showstate("callothersubr")
+ end
+ if stack[top] == hints then
+ popped = stack[top-2]
+ else
+ popped = 3
+ end
+ local t = stack[top-1]
+ if t then
+ top = top - (t + 2)
+ if top < 0 then
+ top = 0
+ end
+ else
+ top = 0
end
+ else
+ top = 0
end
- top = 0
end
+ -- <pop> number (from postscript stack)
+
local function pop()
- if version == 1 then
- -- we don't support this
+ if version == "cff" then
if trace_charstrings then
- showstate("pop (unsupported)")
+ showstate("pop")
end
top = top + 1
- stack[top] = 0 -- a dummy
+ stack[top] = popped
else
top = 0
end
end
local function setcurrentpoint()
- if version == 1 then
- -- we don't support this
+ if version == "cff" then
if trace_charstrings then
- showstate("pop (unsupported)")
+ showstate("setcurrentpoint (unsupported)")
end
x = x + stack[top-1]
y = y + stack[top]
@@ -1527,6 +1559,41 @@ do
hvcurveto, -- 31
}
+ local reverse = { [0] =
+ "unsupported",
+ "getstem",
+ "unsupported",
+ "getstem",
+ "vmoveto",
+ "rlineto",
+ "hlineto",
+ "vlineto",
+ "rrcurveto",
+ "unsupported",
+ "unsupported",
+ "unsupported",
+ "unsupported",
+ "hsbw",
+ "unsupported",
+ "setvsindex",
+ "blend",
+ "unsupported",
+ "getstem",
+ "getmask",
+ "getmask",
+ "rmoveto",
+ "hmoveto",
+ "getstem",
+ "rcurveline",
+ "rlinecurve",
+ "vvcurveto",
+ "hhcurveto",
+ "unsupported",
+ "unsupported",
+ "vhcurveto",
+ "hvcurveto",
+ }
+
local subactions = {
-- cff 1
[000] = dotsection,
@@ -1578,6 +1645,7 @@ do
for i=1132,2048 do
t[i] = char(28,band(rshift(i,8),0xFF),band(i,0xFF))
end
+ -- we could inline some ...
setmetatableindex(encode,function(t,k)
-- 16.16-bit signed fixed value
local r = round(k)
@@ -1663,7 +1731,7 @@ do
local function call(scope,list,bias) -- ,process)
depth = depth + 1
if top == 0 then
- showstate(formatters["unknown %s call"](scope))
+ showstate(formatters["unknown %s call %s, case %s"](scope,"?",1))
top = 0
else
local index = stack[top] + bias
@@ -1675,7 +1743,7 @@ do
if tab then
process(tab)
else
- showstate(formatters["unknown %s call %i"](scope,index))
+ showstate(formatters["unknown %s call %s, case %s"](scope,index,2))
top = 0
end
end
@@ -1684,8 +1752,6 @@ do
-- precompiling and reuse is much slower than redoing the calls
- local justpass = false
-
-- local function decode(str)
-- local a, b, c, d, e = byte(str,1,5)
-- if a == 28 then
@@ -1796,13 +1862,24 @@ do
i = i + 1
local t = tab[i]
if justpass then
- if t >= 34 or t <= 37 then -- flexes
+ if t >= 34 and t <= 37 then -- flexes
for i=1,top do
r = r + 1 ; result[r] = encode[stack[i]]
end
r = r + 1 ; result[r] = chars[12]
r = r + 1 ; result[r] = chars[t]
top = 0
+ elseif t == 6 then
+ seacs[procidx] = {
+ asb = stack[1],
+ adx = stack[2],
+ ady = stack[3],
+ base = stack[4],
+ accent = stack[5],
+ width = width,
+ lsb = lsb,
+ }
+ top = 0
else
local a = subactions[t]
if a then
@@ -1834,46 +1911,56 @@ do
-- cff 1: (when cff2 strip them)
elseif t == 1 or t == 3 or t == 18 or operation == 23 then
p_getstem() -- at the start
-if true then
- if top > 0 then
- for i=1,top do
- r = r + 1 ; result[r] = encode[stack[i]]
+ if true then
+ if top > 0 then
+ for i=1,top do
+ r = r + 1 ; result[r] = encode[stack[i]]
+ end
+ top = 0
end
+ r = r + 1 ; result[r] = chars[t]
+ else
top = 0
end
- r = r + 1 ; result[r] = chars[t]
-else
- top = 0
-end
i = i + 1
-- cff 1: (when cff2 strip them)
elseif t == 19 or t == 20 then
local s = p_getmask() or 0 -- after the stems
-if true then
- if top > 0 then
- for i=1,top do
- r = r + 1 ; result[r] = encode[stack[i]]
+ if true then
+ if top > 0 then
+ for i=1,top do
+ r = r + 1 ; result[r] = encode[stack[i]]
+ end
+ top = 0
end
+ r = r + 1 ; result[r] = chars[t]
+ for j=1,s do
+ i = i + 1
+ r = r + 1 ; result[r] = chars[tab[i]]
+ end
+ else
+ i = i + s
top = 0
end
- r = r + 1 ; result[r] = chars[t]
- for j=1,s do
- i = i + 1
- r = r + 1 ; result[r] = chars[tab[i]]
- end
-else
- i = i + s
- top = 0
-end
i = i + 1
-- cff 1: closepath
elseif t == 9 then
top = 0
i = i + 1
elseif t == 13 then
- local s = hsbw() or 0
- i = i + s + 1
+ hsbw()
+ if version == "cff" then
+ -- we do a moveto over lsb
+ r = r + 1 ; result[r] = encode[lsb]
+ r = r + 1 ; result[r] = chars[22]
+ else
+ -- lsb is supposed to be zero
+ end
+ i = i + 1
else
+ if trace_charstrings then
+ showstate(reverse[t] or "<action>")
+ end
if top > 0 then
for i=1,top do
r = r + 1 ; result[r] = encode[stack[i]]
@@ -1894,7 +1981,7 @@ end
end
else
if trace_charstrings then
- showvalue("<action>",t)
+ showstate(reverse[t] or "<action>")
end
top = 0
i = i + 1
@@ -1941,24 +2028,19 @@ end
-- end
-- end
- local function setbias(globals,locals)
--- if version == 1 then -- charstring version, not cff
--- return
--- 0,
--- 0
--- return
--- 1,
--- 1
--- else
+ local function setbias(globals,locals,nobias)
+ if nobias then
+ return 0, 0
+ else
local g = #globals
local l = #locals
return
((g < 1240 and 107) or (g < 33900 and 1131) or 32768) + 1,
((l < 1240 and 107) or (l < 33900 and 1131) or 32768) + 1
--- end
+ end
end
- local function processshape(tab,index)
+ local function processshape(tab,index,hack)
if not tab then
glyphs[index] = {
@@ -1974,10 +2056,13 @@ end
x = 0
y = 0
width = false
+ lsb = 0
r = 0
top = 0
stems = 0
result = { } -- we could reuse it when only boundingbox calculations are needed
+ popped = 3
+ procidx = index
xmin = 0
xmax = 0
@@ -1995,6 +2080,10 @@ end
process(tab)
+ if hack then
+ return x, y
+ end
+
local boundingbox = {
round(xmin),
round(ymin),
@@ -2059,6 +2148,8 @@ end
axis = false
regions = data.regions
justpass = streams == true
+ popped = 3
+ seacs = { }
if regions then
regions = { regions } -- needs checking
axis = data.factors or false
@@ -2073,6 +2164,8 @@ end
locals = false
globals = false
strings = false
+ popped = 3
+ seacs = { }
end
local function setwidths(private)
@@ -2086,7 +2179,7 @@ end
return privatedata.nominalwidthx or 0, privatedata.defaultwidthx or 0
end
- parsecharstrings = function(fontdata,data,glphs,doshapes,tversion,streams)
+ parsecharstrings = function(fontdata,data,glphs,doshapes,tversion,streams,nobias)
local dictionary = data.dictionaries[1]
local charstrings = dictionary.charstrings
@@ -2100,14 +2193,42 @@ end
vsindex = dictionary.vsindex or 0
glyphs = glphs or { }
- globalbias, localbias = setbias(globals,locals)
+ globalbias, localbias = setbias(globals,locals,nobias)
nominalwidth, defaultwidth = setwidths(dictionary.private)
if charstrings then
startparsing(fontdata,data,streams)
for index=1,#charstrings do
processshape(charstrings[index],index-1)
--- charstrings[index] = nil -- free memory (what if used more often?)
+ end
+ if justpass and next(seacs) then
+ -- old type 1 stuff ... seacs
+ local charset = data.dictionaries[1].charset
+ if charset then
+ local lookup = table.swapped(charset)
+ for index, v in next, seacs do
+ local bindex = lookup[standardnames[v.base]]
+ local aindex = lookup[standardnames[v.accent]]
+ local bglyph = bindex and glyphs[bindex]
+ local aglyph = aindex and glyphs[aindex]
+ if bglyph and aglyph then
+ -- this is a real ugly hack but we seldom enter this branch (e.g. old lbr)
+ local jp = justpass
+ justpass = false
+ local x, y = processshape(charstrings[bindex+1],bindex,true)
+ justpass = jp
+ --
+ local base = bglyph.stream
+ local accent = aglyph.stream
+ local moveto = encode[-x-v.asb+v.adx] .. chars[22]
+ .. encode[-y +v.ady] .. chars[ 4]
+ -- prune an endchar
+ base = sub(base,1,#base-1)
+ -- combine them
+ glyphs[index].stream = base .. moveto .. accent
+ end
+ end
+ end
end
stopparsing(fontdata,data)
else
@@ -2127,9 +2248,10 @@ end
vsindex = dictionary.vsindex or 0
glyphs = glphs or { }
- justpass = streams == true
+ justpass = streams == true
+ seacs = { }
- globalbias, localbias = setbias(globals,locals)
+ globalbias, localbias = setbias(globals,locals,nobias)
nominalwidth, defaultwidth = setwidths(dictionary.private)
processshape(tab,index-1)
@@ -2428,8 +2550,8 @@ function readers.cff(f,fontdata,specification)
if private then
local data = private.data
if type(data) == "table" then
- cffinfo.defaultwidth = data.defaultwidth or cffinfo.defaultwidth
- cffinfo.nominalwidth = data.nominalwidth or cffinfo.nominalwidth
+ cffinfo.defaultwidth = data.defaultwidthx or cffinfo.defaultwidth
+ cffinfo.nominalwidth = data.nominalwidthx or cffinfo.nominalwidth
cffinfo.bluevalues = data.bluevalues
cffinfo.otherblues = data.otherblues
cffinfo.familyblues = data.familyblues
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-con.lua b/Master/texmf-dist/tex/context/base/mkiv/font-con.lua
index 93ce9f5da47..1bb63aa5192 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-con.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-con.lua
@@ -40,7 +40,6 @@ local setmetatableindex = table.setmetatableindex
-- will be directives
constructors.dontembed = allocate()
-constructors.autocleanup = true
constructors.namemode = "fullpath" -- will be a function
constructors.version = 1.01
@@ -51,6 +50,8 @@ constructors.cacheintex = true -- so we see the original table in fonts.fon
constructors.addtounicode = true
+constructors.fixprotrusion = true
+
-- This might become an interface:
local designsizes = allocate()
@@ -134,21 +135,10 @@ make this profitable and the <l n='lua'/> based variant was just faster. A days
wasted day but an experience richer.</p>
--ldx]]--
--- we can get rid of the tfm instance when we have fast access to the
--- scaled character dimensions at the tex end, e.g. a fontobject.width
--- actually we already have some of that now as virtual keys in glyphs
---
--- flushing the kern and ligature tables from memory saves a lot (only
--- base mode) but it complicates vf building where the new characters
--- demand this data .. solution: functions that access them
-
function constructors.cleanuptable(tfmdata)
- if constructors.autocleanup and tfmdata.properties.virtualized then
- for k, v in next, tfmdata.characters do
- if v.commands then v.commands = nil end
- -- if v.kerns then v.kerns = nil end
- end
- end
+ -- This no longer makes sense because the addition of font.getcopy and its
+ -- possible usage in generic implicates that we need to return the whole
+ -- lot now.
end
-- experimental, sharing kerns (unscaled and scaled) saves memory
@@ -444,9 +434,10 @@ function constructors.scale(tfmdata,specification)
-- boundarychar = 65536, -- there is now a string 'right_boundary'
-- false_boundarychar = 65536, -- produces invalid tfm in luatex
--
- targetproperties.language = properties.language or "dflt" -- inherited
- targetproperties.script = properties.script or "dflt" -- inherited
- targetproperties.mode = properties.mode or "base" -- inherited
+ targetproperties.language = properties.language or "dflt" -- inherited
+ targetproperties.script = properties.script or "dflt" -- inherited
+ targetproperties.mode = properties.mode or "base" -- inherited
+ targetproperties.method = properties.method
--
local askedscaledpoints = scaledpoints
local scaledpoints, delta = constructors.calculatescale(tfmdata,scaledpoints,nil,specification) -- no shortcut, dan be redefined
@@ -465,6 +456,7 @@ function constructors.scale(tfmdata,specification)
target.size = scaledpoints
--
target.encodingbytes = properties.encodingbytes or 1
+ target.subfont = properties.subfont
target.embedding = properties.embedding or "subset"
target.tounicode = 1
target.cidinfo = properties.cidinfo
@@ -595,10 +587,12 @@ function constructors.scale(tfmdata,specification)
targetparameters.descender = delta * descender
end
--
--- inspect(targetparameters)
constructors.enhanceparameters(targetparameters) -- official copies for us, now virtual
--
- local protrusionfactor = (targetquad ~= 0 and 1000/targetquad) or 0
+ -- I need to fix this in luatex ... get rid of quad there so that we can omit this here.
+ --
+ local protrusionfactor = constructors.fixprotrusion and ((targetquad ~= 0 and 1000/targetquad) or 1) or 1
+ --
local scaledwidth = defaultwidth * hdelta
local scaledheight = defaultheight * vdelta
local scaleddepth = defaultdepth * vdelta
@@ -983,15 +977,15 @@ function constructors.finalize(tfmdata)
end
--
if not parameters.slantfactor then
- parameters.slantfactor = tfmdata.slant or 0
+ parameters.slantfactor = (tfmdata.slant or 0)/1000
end
--
if not parameters.extendfactor then
- parameters.extendfactor = tfmdata.extend or 0
+ parameters.extendfactor = (tfmdata.extend or 1000)/1000
end
--
if not parameters.squeezefactor then
- parameters.squeezefactor = tfmdata.squeeze or 0
+ parameters.squeezefactor = (tfmdata.squeeze or 1000)/1000
end
--
local designsize = parameters.designsize
@@ -1027,13 +1021,14 @@ function constructors.finalize(tfmdata)
properties.virtualized = tfmdata.type == "virtual"
end
--
- properties.fontname = tfmdata.fontname
- properties.filename = tfmdata.filename
- properties.fullname = tfmdata.fullname
- properties.name = tfmdata.name
- properties.psname = tfmdata.psname
+ properties.fontname = properties.fontname or tfmdata.fontname
+ properties.filename = properties.filename or tfmdata.filename
+ properties.fullname = properties.fullname or tfmdata.fullname
+ properties.name = properties.name or tfmdata.name
+ properties.psname = properties.psname or tfmdata.psname
--
properties.encodingbytes = tfmdata.encodingbytes or 1
+ properties.subfont = tfmdata.subfont or nil
properties.embedding = tfmdata.embedding or "subset"
properties.tounicode = tfmdata.tounicode or 1
properties.cidinfo = tfmdata.cidinfo or nil
@@ -1067,6 +1062,7 @@ function constructors.finalize(tfmdata)
tfmdata.psname = nil
--
tfmdata.encodingbytes = nil
+ tfmdata.subfont = nil
tfmdata.embedding = nil
tfmdata.tounicode = nil
tfmdata.cidinfo = nil
@@ -1143,6 +1139,7 @@ hashmethods.normal = function(list)
m = m + 1
t[m] = k .. '=' .. tostring(v)
end
+ sort(t)
s[n] = k .. '={' .. concat(t,",") .. "}"
else
s[n] = k .. '=' .. tostring(v)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-ctx.lua b/Master/texmf-dist/tex/context/base/mkiv/font-ctx.lua
index 6847a2b8d30..bf14dd309b1 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-ctx.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-ctx.lua
@@ -87,8 +87,6 @@ local getprop = nuts.getprop
local setprop = nuts.setprop
local setsubtype = nuts.setsubtype
-local texgetattribute = tex.getattribute
-local texsetattribute = tex.setattribute
local texgetdimen = tex.getdimen
local texsetcount = tex.setcount
local texget = tex.get
@@ -170,10 +168,34 @@ addformatter(formatters,"font:features",[["'"..sequenced(%s," ",true).."'"]],{ s
constructors.resolvevirtualtoo = true -- context specific (due to resolver)
+if CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 then
+ constructors.fixprotrusion = false
+end
+
constructors.sharefonts = true -- experimental
constructors.nofsharedhashes = 0
constructors.nofsharedvectors = 0
constructors.noffontsloaded = 0
+constructors.autocleanup = true
+
+-- we can get rid of the tfm instance when we have fast access to the
+-- scaled character dimensions at the tex end, e.g. a fontobject.width
+-- actually we already have some of that now as virtual keys in glyphs
+--
+-- flushing the kern and ligature tables from memory saves a lot (only
+-- base mode) but it complicates vf building where the new characters
+-- demand this data .. solution: functions that access them
+
+-- font.getcopy = font.getfont -- we always want the table that context uses
+
+function constructors.cleanuptable(tfmdata)
+ if constructors.autocleanup and tfmdata.properties.virtualized then
+ for k, v in next, tfmdata.characters do
+ if v.commands then v.commands = nil end
+ -- if v.kerns then v.kerns = nil end
+ end
+ end
+end
do
@@ -181,7 +203,7 @@ do
local hashes = { }
local nofinstances = 0
- local instances = table.setmetatableindex(function(t,k)
+ local instances = setmetatableindex(function(t,k)
nofinstances = nofinstances + 1
t[k] = nofinstances
return nofinstances
@@ -572,6 +594,21 @@ end
-- \definefontfeature[demo][a={b,c}]
-- \definefontfeature[demo][a={b=12,c={34,35}}]
+local h = setmetatableindex(function(t,k)
+ local v = "," .. k .. ","
+ t[k] = v
+ return v
+end)
+
+-- local function removefromhash(hash,key)
+-- local pattern = h[key]
+-- for k in next, hash do
+-- if k ~= key and find(h[k],pattern) then -- if find(k,",") and ...
+-- hash[k] = nil
+-- end
+-- end
+-- end
+
local function presetcontext(name,parent,features) -- will go to con and shared
if features == "" and find(parent,"=",1,true) then
features = parent
@@ -637,14 +674,23 @@ local function presetcontext(name,parent,features) -- will go to con and shared
-- if v then t[k] = v end
t[k] = v
end
- -- needed for dynamic features
- -- maybe number should always be renewed as we can redefine features
- local number = setups[name] and setups[name].number or 0 -- hm, numbers[name]
+ -- the number is needed for dynamic features; maybe number should always be
+ -- renewed as we can redefine features ... i need a test
+ local number = setups[name] and setups[name].number or 0
if number == 0 then
number = #numbers + 1
numbers[number] = name
end
+ --
t.number = number
+ -- there is the special case of combined features as we have in math but maybe
+ -- this has to change some day ... otherwise we mess up dynamics (ok, we could
+ -- impose a limit there: no combined features)
+ --
+ -- done elsewhere (!)
+ --
+ -- removefromhash(setups,name) -- can have changed (like foo,extramath)
+ --
setups[name] = t
return number, t
end
@@ -841,23 +887,6 @@ specifiers.definecontext = definecontext
-- we extend the hasher:
--- constructors.hashmethods.virtual = function(list)
--- local s = { }
--- local n = 0
--- for k, v in next, list do
--- n = n + 1
--- s[n] = k -- no checking on k
--- end
--- if n > 0 then
--- sort(s)
--- for i=1,n do
--- local k = s[i]
--- s[i] = k .. '=' .. tostring(list[k])
--- end
--- return concat(s,"+")
--- end
--- end
-
constructors.hashmethods.virtual = function(list)
local s = { }
local n = 0
@@ -878,6 +907,54 @@ constructors.hashmethods.virtual = function(list)
end
end
+if not JITSUPPORTED then
+
+ constructors.hashmethods.normal = function(list)
+ local s = { }
+ local n = 0
+ for k, v in next, list do
+ if not k then
+ -- no need to add to hash
+ elseif k == "number" or k == "features" then
+ -- no need to add to hash (maybe we need a skip list)
+ else
+ n = n + 1
+ if type(v) == "table" then
+ -- table.sequenced
+ local t = { }
+ local m = 0
+ for k, v in next, v do
+ m = m + 1
+ t[m] = format("%q=%q",k,v)
+ end
+ sort(t)
+ s[n] = format("%q={%s}",k,concat(t,","))
+ else
+ s[n] = format("%q=%q",k,v)
+ end
+ end
+ end
+ if n > 0 then
+ sort(s)
+ return concat(s,"+")
+ end
+ end
+
+ constructors.hashmethods.virtual = function(list)
+ local s = { }
+ local n = 0
+ for k, v in next, list do
+ n = n + 1
+ s[n] = format("%q=%q",k,v)
+ end
+ if n > 0 then
+ sort(s)
+ return concat(s,"+")
+ end
+ end
+
+end
+
-- end of redefine
-- local withcache = { } -- concat might be less efficient than nested tables
@@ -915,14 +992,37 @@ end
-- return fastcopy(setups[features] or (presetcontext(features,"","") and setups[features]))
-- end
+-- local function splitcontext(features) -- presetcontext creates dummy here
+-- local sf = setups[features]
+-- if not sf then
+-- local n -- number
+-- if find(features,",") then
+-- -- let's assume a combination which is not yet defined but just specified (as in math)
+-- n, sf = presetcontext(features,features,"")
+-- else
+-- -- we've run into an unknown feature and or a direct spec so we create a dummy
+-- n, sf = presetcontext(features,"","")
+-- end
+-- end
+-- return fastcopy(sf)
+-- end
+
local function splitcontext(features) -- presetcontext creates dummy here
- local sf = setups[features]
- if not sf then
- local n -- number
- if find(features,",",a,true) then
- -- let's assume a combination which is not yet defined but just specified (as in math)
- n, sf = presetcontext(features,features,"")
- else
+ local n, sf
+ if find(features,",") then
+ --
+ -- from elsewhere (!)
+ --
+ -- this will become:
+ --
+ -- if find(features,"^reset," then
+ setups[features] = nil
+ -- end
+ -- let's assume a combination which is not yet defined but just specified (as in math)
+ n, sf = presetcontext(features,features,"")
+ else
+ sf = setups[features]
+ if not sf then
-- we've run into an unknown feature and or a direct spec so we create a dummy
n, sf = presetcontext(features,"","")
end
@@ -1129,199 +1229,17 @@ do -- else too many locals
end
end
- local n = 0
-
- -- we can also move rscale to here (more consistent)
- -- the argument list will become a table
-
local function nice_cs(cs)
return (gsub(cs,".->", ""))
end
- -- function commands.definefont_two(global,cs,str,size,inheritancemode,classfeatures,fontfeatures,classfallbacks,fontfallbacks,
- -- mathsize,textsize,relativeid,classgoodies,goodies,classdesignsize,fontdesignsize,scaledfontmode)
-
--- scanners.definefont_two = function()
-
--- local global = scanboolean() -- \ifx\fontclass\empty\s!false\else\s!true\fi
--- local cs = scanstring () -- {#csname}%
--- local str = scanstring () -- \somefontfile
--- local size = scaninteger() -- \d_font_scaled_font_size
--- local inheritancemode = scaninteger() -- \c_font_feature_inheritance_mode
--- local classfeatures = scanstring () -- \m_font_class_features
--- local fontfeatures = scanstring () -- \m_font_features
--- local classfallbacks = scanstring () -- \m_font_class_fallbacks
--- local fontfallbacks = scanstring () -- \m_font_fallbacks
--- local mathsize = scaninteger() -- \fontface
--- local textsize = scaninteger() -- \d_font_scaled_text_face
--- local relativeid = scaninteger() -- \relativefontid
--- local classgoodies = scanstring () -- \m_font_class_goodies
--- local goodies = scanstring () -- \m_font_goodies
--- local classdesignsize = scanstring () -- \m_font_class_designsize
--- local fontdesignsize = scanstring () -- \m_font_designsize
--- local scaledfontmode = scaninteger() -- \scaledfontmode
-
--- if trace_defining then
--- report_defining("start stage two: %s, size %s, features %a & %a",str,size,classfeatures,fontfeatures)
--- end
--- -- name is now resolved and size is scaled cf sa/mo
--- local lookup, name, sub, method, detail = getspecification(str or "")
--- -- new (todo: inheritancemode)
--- local designsize = fontdesignsize ~= "" and fontdesignsize or classdesignsize or ""
--- local designname = designsizefilename(name,designsize,size)
--- if designname and designname ~= "" then
--- if trace_defining or trace_designsize then
--- report_defining("remapping name %a, specification %a, size %a, designsize %a",name,designsize,size,designname)
--- end
--- -- we don't catch detail here
--- local o_lookup, o_name, o_sub, o_method, o_detail = getspecification(designname)
--- if o_lookup and o_lookup ~= "" then lookup = o_lookup end
--- if o_method and o_method ~= "" then method = o_method end
--- if o_detail and o_detail ~= "" then detail = o_detail end
--- name = o_name
--- sub = o_sub
--- end
--- -- so far
--- -- some settings can have been overloaded
--- if lookup and lookup ~= "" then
--- specification.lookup = lookup
--- end
--- if relativeid and relativeid ~= "" then -- experimental hook
--- local id = tonumber(relativeid) or 0
--- specification.relativeid = id > 0 and id
--- end
--- --
--- specification.name = name
--- specification.size = size
--- specification.sub = (sub and sub ~= "" and sub) or specification.sub
--- specification.mathsize = mathsize
--- specification.textsize = textsize
--- specification.goodies = goodies
--- specification.cs = cs
--- specification.global = global
--- specification.scalemode = scaledfontmode -- context specific
--- if detail and detail ~= "" then
--- specification.method = method or "*"
--- specification.detail = detail
--- elseif specification.detail and specification.detail ~= "" then
--- -- already set
--- elseif inheritancemode == 0 then
--- -- nothing
--- elseif inheritancemode == 1 then
--- -- fontonly
--- if fontfeatures and fontfeatures ~= "" then
--- specification.method = "*"
--- specification.detail = fontfeatures
--- end
--- if fontfallbacks and fontfallbacks ~= "" then
--- specification.fallbacks = fontfallbacks
--- end
--- elseif inheritancemode == 2 then
--- -- classonly
--- if classfeatures and classfeatures ~= "" then
--- specification.method = "*"
--- specification.detail = classfeatures
--- end
--- if classfallbacks and classfallbacks ~= "" then
--- specification.fallbacks = classfallbacks
--- end
--- elseif inheritancemode == 3 then
--- -- fontfirst
--- if fontfeatures and fontfeatures ~= "" then
--- specification.method = "*"
--- specification.detail = fontfeatures
--- elseif classfeatures and classfeatures ~= "" then
--- specification.method = "*"
--- specification.detail = classfeatures
--- end
--- if fontfallbacks and fontfallbacks ~= "" then
--- specification.fallbacks = fontfallbacks
--- elseif classfallbacks and classfallbacks ~= "" then
--- specification.fallbacks = classfallbacks
--- end
--- elseif inheritancemode == 4 then
--- -- classfirst
--- if classfeatures and classfeatures ~= "" then
--- specification.method = "*"
--- specification.detail = classfeatures
--- elseif fontfeatures and fontfeatures ~= "" then
--- specification.method = "*"
--- specification.detail = fontfeatures
--- end
--- if classfallbacks and classfallbacks ~= "" then
--- specification.fallbacks = classfallbacks
--- elseif fontfallbacks and fontfallbacks ~= "" then
--- specification.fallbacks = fontfallbacks
--- end
--- end
--- local tfmdata = definers.read(specification,size) -- id not yet known (size in spec?)
--- --
--- local lastfontid = 0
--- if not tfmdata then
--- report_defining("unable to define %a as %a",name,nice_cs(cs))
--- lastfontid = -1
--- texsetcount("scaledfontsize",0)
--- -- ctx_letvaluerelax(cs) -- otherwise the current definition takes the previous one
--- elseif type(tfmdata) == "number" then
--- if trace_defining then
--- report_defining("reusing %s, id %a, target %a, features %a / %a, fallbacks %a / %a, goodies %a / %a, designsize %a / %a",
--- name,tfmdata,nice_cs(cs),classfeatures,fontfeatures,classfallbacks,fontfallbacks,classgoodies,goodies,classdesignsize,fontdesignsize)
--- end
--- csnames[tfmdata] = specification.cs
--- texdefinefont(global,cs,tfmdata)
--- -- resolved (when designsize is used):
--- local size = fontdata[tfmdata].parameters.size or 0
--- -- ctx_setsomefontsize(size .. "sp")
--- setmacro("somefontsize",size.."sp")
--- texsetcount("scaledfontsize",size)
--- lastfontid = tfmdata
--- else
--- -- setting the extra characters will move elsewhere
--- local characters = tfmdata.characters
--- local parameters = tfmdata.parameters
--- -- we use char0 as signal; cf the spec pdf can handle this (no char in slot)
--- characters[0] = nil
--- -- characters[0x00A0] = { width = parameters.space }
--- -- characters[0x2007] = { width = characters[0x0030] and characters[0x0030].width or parameters.space } -- figure
--- -- characters[0x2008] = { width = characters[0x002E] and characters[0x002E].width or parameters.space } -- period
--- --
--- local id = definefont(tfmdata)
--- csnames[id] = specification.cs
--- tfmdata.properties.id = id
--- definers.register(tfmdata,id) -- to be sure, normally already done
--- texdefinefont(global,cs,id)
--- constructors.cleanuptable(tfmdata)
--- constructors.finalize(tfmdata)
--- if trace_defining then
--- report_defining("defining %a, id %a, target %a, features %a / %a, fallbacks %a / %a",
--- name,id,nice_cs(cs),classfeatures,fontfeatures,classfallbacks,fontfallbacks)
--- end
--- -- resolved (when designsize is used):
--- local size = tfmdata.parameters.size or 655360
--- setmacro("somefontsize",size.."sp")
--- -- ctx_setsomefontsize(size .. "sp")
--- texsetcount("scaledfontsize",size)
--- lastfontid = id
--- end
--- if trace_defining then
--- report_defining("memory usage after: %s",statistics.memused())
--- report_defining("stop stage two")
--- end
--- --
--- texsetcount("global","lastfontid",lastfontid)
--- specifiers[lastfontid] = { str, size }
--- if not mathsize then
--- -- forget about it
--- elseif mathsize == 0 then
--- lastmathids[1] = lastfontid
--- else
--- lastmathids[mathsize] = lastfontid
--- end
--- --
--- stoptiming(fonts)
--- end
+ local n = 0
+ local busy = false
+ local combinefeatures = false
- local busy = false
+ directives.register("fonts.features.combine",function(v)
+ combinefeatures = v
+ end)
scanners.definefont_two = function()
local global = scanboolean() -- \ifx\fontclass\empty\s!false\else\s!true\fi
@@ -1343,7 +1261,7 @@ do -- else too many locals
local scaledfontmode = scaninteger() -- \scaledfontmode
if trace_defining then
- report_defining("start stage two: %s, size %s, features %a & %a",str,size,classfeatures,fontfeatures)
+ report_defining("start stage two: %s, size %s, features %a & %a, mode %a",str,size,classfeatures,fontfeatures,inheritancemode)
end
-- name is now resolved and size is scaled cf sa/mo
local lookup, name, sub, method, detail = getspecification(str or "")
@@ -1408,12 +1326,26 @@ do -- else too many locals
end
elseif inheritancemode == 3 then
-- fontfirst
- if fontfeatures and fontfeatures ~= "" then
- specification.method = "*"
- specification.detail = fontfeatures
- elseif classfeatures and classfeatures ~= "" then
- specification.method = "*"
- specification.detail = classfeatures
+ if combinefeatures then
+ if classfeatures and classfeatures ~= "" then
+ specification.method = "*"
+ if fontfeatures and fontfeatures ~= "" and fontfeatures ~= classfeatures then
+ specification.detail = classfeatures .. "," .. fontfeatures
+ else
+ specification.detail = classfeatures
+ end
+ elseif fontfeatures and fontfeatures ~= "" then
+ specification.method = "*"
+ specification.detail = fontfeatures
+ end
+ else
+ if fontfeatures and fontfeatures ~= "" then
+ specification.method = "*"
+ specification.detail = fontfeatures
+ elseif classfeatures and classfeatures ~= "" then
+ specification.method = "*"
+ specification.detail = classfeatures
+ end
end
if fontfallbacks and fontfallbacks ~= "" then
specification.fallbacks = fontfallbacks
@@ -1422,12 +1354,26 @@ do -- else too many locals
end
elseif inheritancemode == 4 then
-- classfirst
- if classfeatures and classfeatures ~= "" then
- specification.method = "*"
- specification.detail = classfeatures
- elseif fontfeatures and fontfeatures ~= "" then
- specification.method = "*"
- specification.detail = fontfeatures
+ if combinefeatures then
+ if fontfeatures and fontfeatures ~= "" then
+ specification.method = "*"
+ if classfeatures and classfeatures ~= "" and classfeatures ~= fontfeatures then
+ specification.detail = fontfeatures .. "," .. classfeatures
+ else
+ specification.detail = fontfeatures
+ end
+ elseif classfeatures and classfeatures ~= "" then
+ specification.method = "*"
+ specification.detail = classfeatures
+ end
+ else
+ if classfeatures and classfeatures ~= "" then
+ specification.method = "*"
+ specification.detail = classfeatures
+ elseif fontfeatures and fontfeatures ~= "" then
+ specification.method = "*"
+ specification.detail = fontfeatures
+ end
end
if classfallbacks and classfallbacks ~= "" then
specification.fallbacks = classfallbacks
@@ -1583,7 +1529,7 @@ do -- else too many locals
--
- function definers.define(specification)
+ local function define(specification)
--
local name = specification.name
if not name or name == "" then
@@ -1631,6 +1577,7 @@ do -- else too many locals
texdefinefont(specification.global,cs,tfmdata)
csnames[tfmdata] = cs
end
+ stoptiming(fonts)
return tfmdata, fontdata[tfmdata]
else
local id = definefont(tfmdata)
@@ -1642,12 +1589,14 @@ do -- else too many locals
end
constructors.cleanuptable(tfmdata)
constructors.finalize(tfmdata)
+ stoptiming(fonts)
return id, tfmdata
end
- stoptiming(fonts)
end
end
+ definers.define = define
+
-- local id, cs = fonts.definers.internal { }
-- local id, cs = fonts.definers.internal { number = 2 }
-- local id, cs = fonts.definers.internal { name = "dejavusans" }
@@ -1674,7 +1623,7 @@ do -- else too many locals
else
specification.cs = cs
end
- id = definers.define {
+ id = define {
name = name,
size = size,
cs = cs,
@@ -1686,13 +1635,25 @@ do -- else too many locals
return id, csnames[id]
end
+ local read
+
+ if CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 then -- maybe always
+ read = function(name,size)
+ return (define { name = name, size = size } or 0)
+ end
+ else
+ read = definers.read
+ end
+
+ callbacks.register('define_font', read, "definition of fonts (tfmdata preparation)")
+
-- here
local infofont = 0
function fonts.infofont()
if infofont == 0 then
- infofont = definers.define { name = "dejavusansmono", size = texsp("6pt") }
+ infofont = define { name = "dejavusansmono", size = texsp("6pt") }
end
return infofont
end
@@ -2380,7 +2341,7 @@ if environment.initex then
statistics.register("font processing", function()
local l = { }
for what, handler in table.sortedpairs(handlers) do
- local features = handler.features
+ local features = handler and handler.features
if features then
l[#l+1] = format("[%s (base initializers: %s) (base processors: %s) (base manipulators: %s) (node initializers: %s) (node processors: %s) (node manipulators: %s)]",
what,
@@ -2429,6 +2390,26 @@ to scale virtual characters.</p>
do
+ -- can become luat-tex.lua
+
+ local texsetglyphdata = tex.setglyphdata
+ local texgetglyphdata = tex.getglyphdata
+
+ if not texsetglyphdata then
+
+ local texsetattribute = tex.setattribute
+ local texgetattribute = tex.getattribute
+
+ texsetglyphdata = function(n) return texsetattribute(0,n) end
+ texgetglyphdata = function() return texgetattribute(0) end
+
+ tex.setglyphdata = texsetglyphdata
+ tex.getglyphdata = texgetglyphdata
+
+ end
+
+ -- till here
+
local setmacro = tokens.setters.macro
function constructors.currentfonthasfeature(n)
@@ -2452,6 +2433,63 @@ do
local f_strip = formatters["%0.2fpt"] -- normally this value is changed only once
local stripper = lpeg.patterns.stripzeros
+ local cache = { }
+
+ local hows = {
+ ["+"] = "add",
+ ["-"] = "subtract",
+ ["="] = "replace",
+ }
+
+ local function setfeature(how,parent,name,font) -- 0/1 test temporary for testing
+ if not how or how == 0 then
+ if trace_features and texgetglyphdata() ~= 0 then
+ report_cummulative("font %!font:name!, reset",fontdata[font or true])
+ end
+ texsetglyphdata(0)
+ elseif how == true or how == 1 then
+ local hash = "feature > " .. parent
+ local done = cache[hash]
+ if trace_features and done then
+ report_cummulative("font %!font:name!, revive %a : %!font:features!",fontdata[font or true],parent,setups[numbers[done]])
+ end
+ texsetglyphdata(done or 0)
+ else
+ local full = parent .. how .. name
+ local hash = "feature > " .. full
+ local done = cache[hash]
+ if not done then
+ local n = setups[full]
+ if n then
+ -- already defined
+ else
+ n = mergecontextfeatures(parent,name,how,full)
+ end
+ done = registercontextfeature(hash,full,how)
+ cache[hash] = done
+ if trace_features then
+ report_cummulative("font %!font:name!, %s %a : %!font:features!",fontdata[font or true],hows[how],full,setups[numbers[done]])
+ end
+ end
+ texsetglyphdata(done)
+ end
+ end
+
+ local function resetfeature()
+ if trace_features and texgetglyphdata() ~= 0 then
+ report_cummulative("font %!font:name!, reset",fontdata[true])
+ end
+ texsetglyphdata(0)
+ end
+
+ local function setfontfeature(tag)
+ texsetglyphdata(contextnumber(tag))
+ end
+
+ local function resetfontfeature()
+ texsetglyphdata(0)
+ end
+
implement {
name = "nbfs",
arguments = "dimen",
@@ -2469,13 +2507,13 @@ do
implement {
name = "setfontfeature",
arguments = "string",
- actions = function(tag) texsetattribute(0,contextnumber(tag)) end
+ actions = setfontfeature,
}
implement {
name = "resetfontfeature",
- arguments = { 0, 0 },
- actions = texsetattribute,
+ -- arguments = { 0, 0 },
+ actions = resetfontfeature,
}
implement {
@@ -2504,62 +2542,12 @@ do
actions = function(name) ctx_doif(contextnumber(name) == 0) end,
}
-
implement {
name = "adaptfontfeature",
arguments = "2 strings",
actions = adaptcontext
}
- local cache = { }
-
- local hows = {
- ["+"] = "add",
- ["-"] = "subtract",
- ["="] = "replace",
- }
-
- local function setfeature(how,parent,name,font) -- 0/1 test temporary for testing
- if not how or how == 0 then
- if trace_features and texgetattribute(0) ~= 0 then
- report_cummulative("font %!font:name!, reset",fontdata[font or true])
- end
- texsetattribute(0,0)
- elseif how == true or how == 1 then
- local hash = "feature > " .. parent
- local done = cache[hash]
- if trace_features and done then
- report_cummulative("font %!font:name!, revive %a : %!font:features!",fontdata[font or true],parent,setups[numbers[done]])
- end
- texsetattribute(0,done or 0)
- else
- local full = parent .. how .. name
- local hash = "feature > " .. full
- local done = cache[hash]
- if not done then
- local n = setups[full]
- if n then
- -- already defined
- else
- n = mergecontextfeatures(parent,name,how,full)
- end
- done = registercontextfeature(hash,full,how)
- cache[hash] = done
- if trace_features then
- report_cummulative("font %!font:name!, %s %a : %!font:features!",fontdata[font or true],hows[how],full,setups[numbers[done]])
- end
- end
- texsetattribute(0,done)
- end
- end
-
- local function resetfeature()
- if trace_features and texgetattribute(0) ~= 0 then
- report_cummulative("font %!font:name!, reset",fontdata[true])
- end
- texsetattribute(0,0)
- end
-
local function registerlanguagefeatures()
local specifications = languages.data.specifications
for i=1,#specifications do
@@ -3184,9 +3172,9 @@ end
do
- local family_font = node.family_font
- local new_glyph = nodes.pool.glyph
- local fontproperties = fonts.hashes.properties
+ local getfontoffamily = font.getfontoffamily
+ local new_glyph = nodes.pool.glyph
+ local fontproperties = fonts.hashes.properties
local function getprivateslot(id,name)
if not name then
@@ -3255,7 +3243,7 @@ do
name = "getprivatemathchar",
arguments = "string",
actions = function(name)
- local p = getprivateslot(family_font(0),name)
+ local p = getprivateslot(getfontoffamily(0),name)
if p then
context(utfchar(p))
end
@@ -3381,3 +3369,8 @@ function fonts.helpers.collectanchors(tfmdata)
return anchors
end
+
+if CONTEXTLMTXMODE > 0 then
+ fonts.constructors.addtounicode = false
+ fonts.constructors.autocleanup = false
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-def.lua b/Master/texmf-dist/tex/context/base/mkiv/font-def.lua
index f3d0f818718..e287bf79ce5 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-def.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-def.lua
@@ -45,7 +45,6 @@ specifiers.variants = variants
definers.methods = definers.methods or { }
local internalized = allocate() -- internal tex numbers (private)
-local lastdefined = nil -- we don't want this one to end up in s-tra-02
local loadedfonts = constructors.loadedfonts
local designsizes = constructors.designsizes
@@ -455,10 +454,6 @@ not gain much. By the way, passing id's back to in the callback was
introduced later in the development.</p>
--ldx]]--
-function definers.current() -- or maybe current
- return lastdefined
-end
-
function definers.registered(hash)
local id = internalized[hash]
return id, id and fontdata[id]
@@ -511,7 +506,6 @@ function definers.read(specification,size,id) -- id can be optional, name can al
end
end
end
- lastdefined = tfmdata or id -- todo ! ! ! ! !
if not tfmdata then -- or id?
report_defining( "unknown font %a, loading aborted",specification.name)
elseif trace_defining and type(tfmdata) == "table" then
@@ -533,4 +527,6 @@ end
<p>We overload the <l n='tfm'/> reader.</p>
--ldx]]--
-callbacks.register('define_font', definers.read, "definition of fonts (tfmdata preparation)")
+if not context then
+ callbacks.register('define_font', definers.read, "definition of fonts (tfmdata preparation)")
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-dsp.lua b/Master/texmf-dist/tex/context/base/mkiv/font-dsp.lua
index f8bf6f2c872..3058be37b9a 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-dsp.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-dsp.lua
@@ -1473,6 +1473,123 @@ end
-- ValueFormat1 applies to the ValueRecord of the first glyph in each pair. ValueRecords for all first glyphs must use ValueFormat1. If ValueFormat1 is set to zero (0), the corresponding glyph has no ValueRecord and, therefore, should not be repositioned.
-- ValueFormat2 applies to the ValueRecord of the second glyph in each pair. ValueRecords for all second glyphs must use ValueFormat2. If ValueFormat2 is set to null, then the second glyph of the pair is the “next” glyph for which a lookup should be performed.
+-- local simple = {
+-- [true] = { [true] = { true, true }, [false] = { true } },
+-- [false] = { [true] = { false, true }, [false] = { false } },
+-- }
+
+-- function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
+-- local tableoffset = lookupoffset + offset
+-- setposition(f,tableoffset)
+-- local subtype = readushort(f)
+-- local getdelta = fontdata.temporary.getdelta
+-- if subtype == 1 then
+-- local coverage = readushort(f)
+-- local format1 = readushort(f)
+-- local format2 = readushort(f)
+-- local sets = readarray(f)
+-- sets = readpairsets(f,tableoffset,sets,format1,format2,mainoffset,getdelta)
+-- coverage = readcoverage(f,tableoffset + coverage)
+-- local shared = { } -- partial sparse, when set also needs to be handled in the packer
+-- for index, newindex in next, coverage do
+-- local set = sets[newindex+1]
+-- local hash = { }
+-- for i=1,#set do
+-- local value = set[i]
+-- if value then
+-- local other = value[1]
+-- if shared then
+-- local s = shared[value]
+-- if s == nil then
+-- local first = value[2]
+-- local second = value[3]
+-- if first or second then
+-- s = { first, second or nil } -- needs checking
+-- else
+-- s = false
+-- end
+-- shared[value] = s
+-- end
+-- hash[other] = s or nil
+-- else
+-- local first = value[2]
+-- local second = value[3]
+-- if first or second then
+-- hash[other] = { first, second or nil } -- needs checking
+-- else
+-- hash[other] = nil -- what if set, maybe warning
+-- end
+-- end
+-- end
+-- end
+-- coverage[index] = hash
+-- end
+-- return {
+-- shared = shared and true or nil,
+-- format = "pair",
+-- coverage = coverage,
+-- }
+-- elseif subtype == 2 then
+-- local coverage = readushort(f)
+-- local format1 = readushort(f)
+-- local format2 = readushort(f)
+-- local classdef1 = readushort(f)
+-- local classdef2 = readushort(f)
+-- local nofclasses1 = readushort(f) -- incl class 0
+-- local nofclasses2 = readushort(f) -- incl class 0
+-- local classlist = readpairclasssets(f,nofclasses1,nofclasses2,format1,format2,tableoffset,getdelta)
+-- coverage = readcoverage(f,tableoffset+coverage)
+-- classdef1 = readclassdef(f,tableoffset+classdef1,coverage)
+-- classdef2 = readclassdef(f,tableoffset+classdef2,nofglyphs)
+-- local usedcoverage = { }
+-- local shared = { } -- partial sparse, when set also needs to be handled in the packer
+-- for g1, c1 in next, classdef1 do
+-- if coverage[g1] then
+-- local l1 = classlist[c1]
+-- if l1 then
+-- local hash = { }
+-- for paired, class in next, classdef2 do
+-- local offsets = l1[class]
+-- if offsets then
+-- local first = offsets[1]
+-- local second = offsets[2]
+-- if first or second then
+-- if shared then
+-- local s1 = shared[first]
+-- if s1 == nil then
+-- s1 = { }
+-- shared[first] = s1
+-- end
+-- local s2 = s1[second]
+-- if s2 == nil then
+-- s2 = { first, second or nil }
+-- s1[second] = s2
+-- end
+-- hash[paired] = s2
+-- else
+-- hash[paired] = { first, second or nil }
+-- end
+-- else
+-- -- upto the next lookup for this combination
+-- end
+-- end
+-- end
+-- usedcoverage[g1] = hash
+-- end
+-- end
+-- end
+-- return {
+-- shared = shared and true or nil,
+-- format = "pair",
+-- coverage = usedcoverage,
+-- }
+-- elseif subtype == 3 then
+-- report("yet unsupported subtype %a in %a positioning",subtype,"pair")
+-- else
+-- report("unsupported subtype %a in %a positioning",subtype,"pair")
+-- end
+-- end
+
function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
local tableoffset = lookupoffset + offset
setposition(f,tableoffset)
@@ -1485,25 +1602,32 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly
local sets = readarray(f)
sets = readpairsets(f,tableoffset,sets,format1,format2,mainoffset,getdelta)
coverage = readcoverage(f,tableoffset + coverage)
+ local shared = { } -- partial sparse, when set also needs to be handled in the packer
for index, newindex in next, coverage do
local set = sets[newindex+1]
local hash = { }
for i=1,#set do
local value = set[i]
if value then
- local other = value[1]
- local first = value[2]
- local second = value[3]
- if first or second then
- hash[other] = { first, second or nil } -- needs checking
- else
- hash[other] = nil -- what if set, maybe warning
+ local other = value[1]
+ local share = shared[value]
+ if share == nil then
+ local first = value[2]
+ local second = value[3]
+ if first or second then
+ share = { first, second or nil } -- needs checking
+ else
+ share = false
+ end
+ shared[value] = share
end
+ hash[other] = share or nil -- really overload ?
end
end
coverage[index] = hash
end
return {
+ shared = shared and true or nil,
format = "pair",
coverage = coverage,
}
@@ -1520,6 +1644,7 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly
classdef1 = readclassdef(f,tableoffset+classdef1,coverage)
classdef2 = readclassdef(f,tableoffset+classdef2,nofglyphs)
local usedcoverage = { }
+ local shared = { } -- partial sparse, when set also needs to be handled in the packer
for g1, c1 in next, classdef1 do
if coverage[g1] then
local l1 = classlist[c1]
@@ -1531,9 +1656,17 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly
local first = offsets[1]
local second = offsets[2]
if first or second then
- hash[paired] = { first, second or nil }
- else
- -- upto the next lookup for this combination
+ local s1 = shared[first]
+ if s1 == nil then
+ s1 = { }
+ shared[first] = s1
+ end
+ local s2 = s1[second]
+ if s2 == nil then
+ s2 = { first, second or nil }
+ s1[second] = s2
+ end
+ hash[paired] = s2
end
end
end
@@ -1542,6 +1675,7 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly
end
end
return {
+ shared = shared and true or nil,
format = "pair",
coverage = usedcoverage,
}
@@ -3025,6 +3159,14 @@ function readers.cpal(f,fontdata,specification)
end
end
+local compress = gzip and gzip.compress
+local compressed = compress and gzip.compressed
+
+-- At some point I will delay loading and only store the offsets (in context lmtx
+-- only).
+
+-- compressed = false
+
function readers.svg(f,fontdata,specification)
local tableoffset = gotodatatable(f,fontdata,"svg",specification.glyphs)
if tableoffset then
@@ -3050,10 +3192,14 @@ function readers.svg(f,fontdata,specification)
for i=1,nofentries do
local entry = entries[i]
setposition(f,entry.offset)
+ local data = readstring(f,entry.length)
+ if compressed and not compressed(data) then
+ data = compress(data)
+ end
entries[i] = {
first = entry.first,
last = entry.last,
- data = readstring(f,entry.length)
+ data = data
}
end
fontdata.svgshapes = entries
@@ -3091,7 +3237,8 @@ function readers.sbix(f,fontdata,specification)
return b.ppem < a.ppem
end
end)
- local glyphs = { }
+ local glyphs = { }
+ local delayed = CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 or fonts.handlers.typethree
for i=1,nofstrikes do
local strike = strikes[i]
local strikeppem = strike.ppem
@@ -3108,13 +3255,28 @@ function readers.sbix(f,fontdata,specification)
local datasize = nextoffset - glyphoffset
if datasize > 0 then
setposition(f,strikeoffset + glyphoffset)
+ local x = readshort(f)
+ local y = readshort(f)
+ local tag = readtag(f) -- or just skip, we never needed it till now
+ local size = datasize - 8
+ local data = nil
+ local offset = nil
+ if delayed then
+ offset = getposition(f)
+ data = nil
+ else
+ data = readstring(f,size)
+ size = nil
+ end
shapes[i] = {
- x = readshort(f),
- y = readshort(f),
- tag = readtag(f), -- maybe for tracing
- data = readstring(f,datasize-8),
- ppem = strikeppem, -- not used, for tracing
- ppi = strikeppi, -- not used, for tracing
+ x = x,
+ y = y,
+ o = offset,
+ s = size,
+ data = data,
+ -- tag = tag, -- maybe for tracing
+ -- ppem = strikeppem, -- not used, for tracing
+ -- ppi = strikeppi, -- not used, for tracing
}
done = done + 1
if done == nofglyphs then
@@ -3316,32 +3478,48 @@ do
local default = { width = 0, height = 0 }
local glyphs = fontdata.glyphs
+ local delayed = CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 or fonts.handlers.typethree
for index, subtable in sortedhash(shapes) do
if type(subtable) == "table" then
local data = nil
+ local size = nil
local metrics = default
local format = subtable.format
local offset = subtable.offsets[index]
setposition(f,offset)
if format == 17 then
metrics = getsmallmetrics(f)
- data = readstring(f,readulong(f))
+ size = true
elseif format == 18 then
metrics = getbigmetrics(f)
- data = readstring(f,readulong(f))
+ size = true
elseif format == 19 then
metrics = subtable.metrics
- data = readstring(f,readulong(f))
+ size = true
else
-- forget about it
end
+ if size then
+ size = readulong(f)
+ if delayed then
+ offset = getposition(f)
+ data = nil
+ else
+ offset = nil
+ data = readstring(f,size)
+ size = nil
+ end
+ else
+ offset = nil
+ end
local x = metrics.width
local y = metrics.height
shapes[index] = {
- -- maybe some metrics
x = x,
y = y,
+ o = offset,
+ s = size,
data = data,
}
-- I'll look into this in more details when needed
@@ -3352,12 +3530,11 @@ do
local height = width * y/x
glyph.boundingbox = { 0, 0, width, height }
end
-
else
shapes[index] = {
x = 0,
y = 0,
- data = "",
+ data = "", -- or just nil
}
end
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-emp.mklx b/Master/texmf-dist/tex/context/base/mkiv/font-emp.mklx
new file mode 100644
index 00000000000..2bd6f3cf9c2
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-emp.mklx
@@ -0,0 +1,256 @@
+%D \module
+%D [ file=font-emp,
+%D version=20120106, % (moved from font-ini)
+%D title=\CONTEXT\ Font Macros,
+%D subtitle=Emphasis,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Font Macros / Emphasis}
+
+\unprotect
+
+%D \macros
+%D {em,emphasistypeface,emphasisboldface}
+%D
+%D The next macro started as a copy of Donald Arseneau's \type {\em} (\TUGNEWS\
+%D Vol.~3, no.~1, 1994). His implementation was a bit more sophisticated version of
+%D the standard \LATEX\ one. We further enhanced the macro, so now it also adapts
+%D itself to boldface mode. Because we favor {\sl slanted} type over {\it italic},
+%D we made the emphasis adaptable, for instance:
+%D
+%D \starttyping
+%D \def\emphasistypeface {\it}
+%D \def\emphasisboldface {\bi}
+%D \stoptyping
+%D
+%D But we prefer:
+%D
+%D \starttyping
+%D \unexpanded\def\emphasistypeface{\sl}
+%D \unexpanded\def\emphasisboldface{\bs}
+%D \stoptyping
+%D
+%D or even better:
+
+\let\m_font_emphasized_typeface\empty
+
+\def\font_emphasis_checked_typeface#slanted#italic%
+ {\edef\m_font_emphasized_typeface{\font_bodyfontvariable\s!em}%
+ \ifx\m_font_emphasized_typeface\v!slanted
+ #slanted%
+ \orelse\ifx\m_font_emphasized_typeface\v!italic
+ #italic%
+ \orelse\ifx\m_font_emphasized_typeface\empty
+ #slanted%
+ \else
+ \csname\m_font_emphasized_typeface\endcsname
+ \fi}
+
+\unexpanded\def\emphasistypeface{\font_emphasis_checked_typeface\sl\it}
+\unexpanded\def\emphasisboldface{\font_emphasis_checked_typeface\bs\bi}
+
+\unexpanded\def\normalboldface % public
+ {\relax
+ \ifx\fontalternative\s!it\bi\orelse
+ \ifx\fontalternative\s!sl\bs\else
+ \bf\fi}
+
+\unexpanded\def\normalitalicface % public
+ {\relax
+ \ifx\fontalternative\s!tf\it\orelse
+ \ifx\fontalternative\s!bf\bi\else
+ \tf\fi}
+
+\unexpanded\def\normalslantedface % public
+ {\relax \ifx\fontalternative\s!tf\sl
+ \orelse\ifx\fontalternative\s!bf\bs
+ \else \tf\fi}
+
+\unexpanded\def\normaltypeface % public
+ {\relax
+ \ifx\fontalternative\s!bi \it \orelse
+ \ifx\fontalternative\s!bs \sl \else
+ \tf \fi}
+
+\unexpanded\def\swaptypeface % public
+ {\relax
+ \ifx\fontalternative\s!it \tf \orelse
+ \ifx\fontalternative\s!sl \tf \orelse
+ \ifx\fontalternative\s!bf \emphasisboldface \orelse
+ \ifx\fontalternative\s!bs \bf \orelse
+ \ifx\fontalternative\s!bi \bf \else
+ \emphasistypeface \fi}
+
+\let\typeface \normaltypeface % public
+\let\boldface \normalboldface % public
+\let\slantedface\normalslantedface % public
+\let\italicface \normalitalicface % public
+\let\swapface \swaptypeface % public
+
+%D To be set with the default body font environment: \type
+%D {em} being \type {slanted} or \type {italic}.
+
+% maybe a \csname...\fontalternative\endcsname
+
+\newconditional\c_font_emphasis_needed
+
+\unexpanded\def\em
+ {\relax
+ \ifdim\slantperpoint>\zeropoint
+ \settrue\c_font_emphasis_needed
+ \else
+ \setfalse\c_font_emphasis_needed
+ \fi
+ \font_emphasis_set_emphasis_boldface % new
+ \ifx\fontalternative\s!it
+ \unexpanded\def\emphasistypeface{\it}\tf
+ \orelse\ifx\fontalternative\s!sl
+ \unexpanded\def\emphasistypeface{\sl}\tf
+ \orelse\ifx\fontalternative\s!bf
+ \emphasisboldface
+ \orelse\ifx\fontalternative\s!bs
+ \unexpanded\def\emphasisboldface{\bs}\bf
+ \orelse\ifx\fontalternative\s!bi
+ \unexpanded\def\emphasisboldface{\bi}\bf
+ \else
+ \emphasistypeface
+ \fi
+ \ifconditional\c_font_emphasis_needed\else
+ \expandafter\aftergroup
+ \fi
+ \emphasiscorrection}
+
+%D The next feature was not present in previous versions. It
+%D takes care of \type {\em \bf ...} situations.
+
+\let\font_emphasis_saved_emphasis_boldface\relax
+
+\def\font_emphasis_set_emphasis_boldface
+ {\let\font_emphasis_saved_emphasis_boldface\bf
+ \let\font_emphasis_set_emphasis_boldface\relax
+ \let\bf\font_emphasis_bold_bold}
+
+\unexpanded\def\font_emphasis_bold_bold
+ {%\relax
+ \let\bf\relax % new
+ \ifx\fontalternative\s!it
+ \bi
+ \orelse\ifx\fontalternative\s!sl
+ \bs
+ \else
+ \font_emphasis_saved_emphasis_boldface
+ \fi
+ \let\bf\font_emphasis_saved_emphasis_boldface}
+
+%D Donald's (adapted) macros take the next character into account when placing
+%D italic correction. As a bonus we also look for something that looks like a dash,
+%D in which case we don't correct.
+
+\let\italiccorrection=\/ % tex primitive
+
+\def\emphasiscorrection % public, not in raw alignment groups, else omit problem
+ {\ifhmode\ifnum\currentgrouptype=\aligngroupcode\else
+ \expandafter\expandafter\expandafter\font_emphasis_look
+ \fi\fi}
+
+\def\font_emphasis_look
+ {\begingroup
+ \futurelet\nexttoken\font_emphasis_test}
+
+\def\font_emphasis_test
+ {\ifcat\noexpand\nexttoken,% we can do better in luatex ... some day ...
+ \expandafter\font_emphasis_a
+ \else
+ \expandafter\font_emphasis_b
+ \fi}
+
+\def\font_emphasis_a
+ {\futurelet\nexttoken\font_emphasis_correction}
+
+\def\font_emphasis_correction
+ {\setbox\scratchbox\hbox{\nexttoken}% tricky as next can be a macro
+ \ifzeropt\ht\scratchbox % probably a space
+ \expandafter\font_emphasis_b
+ \orelse\ifdim\ht\scratchbox<.3\exheight
+ \expandafter\expandafter\expandafter\endgroup
+ \else
+ \expandafter\expandafter\expandafter\font_emphasis_b
+ \fi}
+
+\def\font_emphasis_b
+ {\scratchskip\lastskip
+ \ifzeropt\scratchskip
+ \italiccorrection\relax
+ \else
+ \unskip\italiccorrection\hskip\scratchskip
+ \fi
+ \endgroup}
+
+%D We end with some examples which show the behavior when some punctuation is met.
+%D We also show how the mechanism adapts itself to bold, italic and slanted typing.
+%D
+%D \startbuffer
+%D test {test}test \par
+%D test {\sl test}test \par
+%D test {\em test}test \par
+%D test {\em test}--test \par
+%D
+%D test {test}, test \par
+%D test {\em test}, test \par
+%D
+%D test {\em test {\em test {\em test} test} test} test \par
+%D test {\bf test {\em test {\em test} test} test} test \par
+%D test {\sl test {\em test {\em test} test} test} test \par
+%D test {\it test {\em test {\em test} test} test} test \par
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D We get:
+%D
+%D \startpacked
+%D \getbuffer
+%D \stoppacked
+
+%D \macros
+%D {emphbf,emphit,emphsl,emphtf}
+%D
+%D The next emphasis alternatives are for \THANH. They adapt their style as good as
+%D possible. These macros are obsolete in \MKIV.
+
+% \unexpanded\def\emphbf{\groupedcommand{\bf\def\emphit{\bi}\def\emphsl{\bs}}{}}
+% \unexpanded\def\emphit{\groupedcommand{\it\def\emphbf{\bi}\def\emphsl{\sl}}{}}
+% \unexpanded\def\emphsl{\groupedcommand{\sl\def\emphbf{\bs}\def\emphit{\it}}{}}
+% \unexpanded\def\emphtf{\groupedcommand{\tf\def\emphbf{\bf}\def\emphit{\it}\def\emphsl{\sl}}{}}
+% \unexpanded\def\emph {\groupedcommand{\em}{}}
+
+\unexpanded\def\font_emphasis_bf{\bf\def\emphit{\bi}\def\emphsl{\bs}}
+\unexpanded\def\font_emphasis_it{\it\def\emphbf{\bi}\def\emphsl{\sl}}
+\unexpanded\def\font_emphasis_sl{\sl\def\emphbf{\bs}\def\emphit{\it}}
+\unexpanded\def\font_emphasis_tf{\tf\def\emphbf{\bf}\def\emphit{\it}\def\emphsl{\sl}}
+
+\unexpanded\def\emphbf{\triggergroupedcommandcs\font_emphasis_bf}
+\unexpanded\def\emphit{\triggergroupedcommandcs\font_emphasis_it}
+\unexpanded\def\emphsl{\triggergroupedcommandcs\font_emphasis_sl}
+\unexpanded\def\emphtf{\triggergroupedcommandcs\font_emphasis_tf}
+\unexpanded\def\emph {\triggergroupedcommandcs\em}
+
+\unexpanded\def\emphasized{\bgroup\em\let\nexttoken}
+
+%D \startbuffer
+%D TEXT {\emphbf text \emphit text \emphtf text \emphsl text} TEXT
+%D TEXT \emphbf{text \emphit{text} \emphtf{text} \emphsl{text}} TEXT
+%D \stopbuffer
+%D
+%D \typebuffer
+%D \startlines
+%D \getbuffer
+%D \stoplines
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-emp.mkvi b/Master/texmf-dist/tex/context/base/mkiv/font-emp.mkvi
index b5c09d4c265..38305abeff4 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-emp.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-emp.mkvi
@@ -18,13 +18,11 @@
%D \macros
%D {em,emphasistypeface,emphasisboldface}
%D
-%D The next macro started as a copy of Donald Arseneau's
-%D \type{\em} (\TUGNEWS\ Vol.~3, no.~1, 1994). His
-%D implementation was a bit more sophisticated version of the
-%D standard \LATEX\ one. We further enhanced the macro, so now
-%D it also adapts itself to boldface mode. Because we favor
-%D {\sl slanted} type over {\it italic}, we made the emphasis
-%D adaptable, for instance:
+%D The next macro started as a copy of Donald Arseneau's \type {\em} (\TUGNEWS\
+%D Vol.~3, no.~1, 1994). His implementation was a bit more sophisticated version of
+%D the standard \LATEX\ one. We further enhanced the macro, so now it also adapts
+%D itself to boldface mode. Because we favor {\sl slanted} type over {\it italic},
+%D we made the emphasis adaptable, for instance:
%D
%D \starttyping
%D \def\emphasistypeface {\it}
@@ -148,10 +146,9 @@
\fi\fi
\let\bf\font_emphasis_saved_emphasis_boldface}
-%D Donald's (adapted) macros take the next character into
-%D account when placing italic correction. As a bonus we also
-%D look for something that looks like a dash, in which case we
-%D don't correct.
+%D Donald's (adapted) macros take the next character into account when placing
+%D italic correction. As a bonus we also look for something that looks like a dash,
+%D in which case we don't correct.
\let\italiccorrection=\/ % tex primitive
@@ -176,7 +173,7 @@
\def\font_emphasis_correction
{\setbox\scratchbox\hbox{\nexttoken}% tricky as next can be a macro
- \ifdim\ht\scratchbox=\zeropoint % probably a space
+ \ifzeropt\ht\scratchbox % probably a space
\expandafter\font_emphasis_b
\else\ifdim\ht\scratchbox<.3\exheight
\expandafter\expandafter\expandafter\endgroup
@@ -186,16 +183,15 @@
\def\font_emphasis_b
{\scratchskip\lastskip
- \ifdim\scratchskip=\zeropoint\relax % == \ifzeropt\scratchskip
+ \ifzeropt\scratchskip
\italiccorrection\relax
\else
\unskip\italiccorrection\hskip\scratchskip
\fi
\endgroup}
-%D We end with some examples which show the behavior when
-%D some punctuation is met. We also show how the mechanism
-%D adapts itself to bold, italic and slanted typing.
+%D We end with some examples which show the behavior when some punctuation is met.
+%D We also show how the mechanism adapts itself to bold, italic and slanted typing.
%D
%D \startbuffer
%D test {test}test \par
@@ -223,9 +219,8 @@
%D \macros
%D {emphbf,emphit,emphsl,emphtf}
%D
-%D The next emphasis alternatives are for \THANH. They adapt
-%D their style as good as possible. These macros are obsolete
-%D in \MKIV.
+%D The next emphasis alternatives are for \THANH. They adapt their style as good as
+%D possible. These macros are obsolete in \MKIV.
% \unexpanded\def\emphbf{\groupedcommand{\bf\def\emphit{\bi}\def\emphsl{\bs}}{}}
% \unexpanded\def\emphit{\groupedcommand{\it\def\emphbf{\bi}\def\emphsl{\sl}}{}}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-enc.lua b/Master/texmf-dist/tex/context/base/mkiv/font-enc.lua
index f448685a69a..608539c59ad 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-enc.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-enc.lua
@@ -8,7 +8,7 @@ if not modules then modules = { } end modules ['font-enc'] = {
-- this module is obsolete
-local next = next
+local next, rawget = next, rawget
local match, gmatch, gsub = string.match, string.gmatch, string.gsub
local setmetatableindex = table.setmetatableindex
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-fbk.lua b/Master/texmf-dist/tex/context/base/mkiv/font-fbk.lua
index 122e43ddc71..b6c9a430ddf 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-fbk.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-fbk.lua
@@ -189,6 +189,7 @@ local function composecharacters(tfmdata)
chr_t,
}
end
+t.depth = a_ury
elseif c_ury > a_lly then -- messy test
local dy
if compose then
@@ -219,6 +220,7 @@ local function composecharacters(tfmdata)
else
dy = - deltaxheight + extraxheight
end
+t.height = a_ury-dy
local right = rightcommand[dx+dd]
local down = downcommand[dy]
if trace_visualize then
@@ -245,6 +247,7 @@ local function composecharacters(tfmdata)
chr_t,
}
end
+t.height = a_ury
end
end
else
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-fea.mkvi b/Master/texmf-dist/tex/context/base/mkiv/font-fea.mkvi
index 4a5356090e9..3737632fe2e 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-fea.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-fea.mkvi
@@ -137,11 +137,14 @@
\def\font_basics_features_list[#name][#separator]% todo: arg voor type
{\clf_featurelist{#name}{\detokenize{#separator}}}
-\attribute\zerocount\zerocount % first in list, so fast match
-
-\prependtoks
- \attribute\zerocount\attributeunsetvalue % new per 2017-08-30
-\to \t_attr_list_local
+\ifcase\contextlmtxmode
+ \attribute\zerocount\zerocount
+ \def\font_dynamic_value{\attribute\zerocount}
+\else
+ \attribute\zerocount\attributeunsetvalue
+ \glyphdatafield\zerocount
+ \let\font_dynamic_value\glyphdatafield
+\fi
% beware: these are global features on top of existing font features
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-fil.mklx b/Master/texmf-dist/tex/context/base/mkiv/font-fil.mklx
new file mode 100644
index 00000000000..6cc25db1036
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-fil.mklx
@@ -0,0 +1,422 @@
+%D \module
+%D [ file=font-fil,
+%D version=2011.01.13, % (copied fron font-ini)
+%D title=\CONTEXT\ Font Macros,
+%D subtitle=Classes and Files,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Font Macros / Classes and Files}
+
+\unprotect
+
+%D Personally I think that using \TEX\ macro packages is complicated by the way
+%D fonts are handled. Apart from the many encodings, we also deal with different
+%D naming schemes. Confronted with this problem, I decided to change the definitions
+%D into:
+%D
+%D \starttyping
+%D \definebodyfont [12pt] [rm] [tf=Times-Roman at 12pt]
+%D \stoptyping
+%D
+%D combined with for instance:
+%D
+%D \starttyping
+%D \definefontsynonym [Times-Roman] [tir]
+%D \stoptyping
+
+% \definetypeface[palatino][rm][serif][palatino,allbold][default]
+%
+% \startfontclass[palatino]
+% \definefontsynonym [Serif] [SerifBold]
+% \definefontsynonym [SerifItalic] [SerifBoldItalic]
+% \definefontsynonym [SerifSlanted] [SerifBoldSlanted]
+% \definefontsynonym [SerifCaps] [SerifBold]
+% \stopfontclass
+%
+% \setupbodyfont[palatino]
+
+\unexpanded\def\startfontclass
+ {\dosingleempty\font_basics_start_font_class}
+
+\def\font_basics_start_font_class[#class]%
+ {\push_macro_fontclass
+ \doifelse{#class}\v!each
+ {\let\fontclass\empty}
+ {\doifsomething{#class}{\def\fontclass{#class}}}}
+
+\unexpanded\def\stopfontclass
+ {\pop_macro_fontclass}
+
+\def\classfont#class#name{#class#name} % \definefont[whatever][\classfont{xx}{yy} at 10pt]
+
+%D \macros
+%D {definefontsynonym, doifelsefontsynonym,
+%D expandfontsynonym, truefontname, truefontdata}
+%D
+%D While looking for fonts, fontsynonyms are used for accessing
+%D the files!
+%D
+%D \starttyping
+%D \definefontsynonym[Serif][Lucida-Bright]
+%D \definefontsynonym[Lucida-Bright][lbr][encoding=texnansi]
+%D \stoptyping
+
+\installcorenamespace {fontfile} % file synonyms
+
+\let\m_font_name\empty
+\let\m_font_file\empty
+
+\def \defaultfontfile{\truefontname{Normal}} % was cmtt10, but that one is gone
+\edef\nullfontname {\fontname\nullfont}
+
+\unexpanded\def\definefontsynonym[#name]#crap[#file]%
+ {\edef\m_font_name{#name}%
+ \edef\m_font_file{#file}%
+ \ifx\fontclass\empty
+ \expandafter\font_basics_define_font_synonym_nop
+ \else
+ \expandafter\font_basics_define_font_synonym_yes
+ \fi}
+
+\unexpanded\def\font_basics_define_font_synonym_nop
+ {\expandafter\let\csname\??fontfile\m_font_name\endcsname\m_font_file
+ \doifelsenextoptionalcs\font_basics_define_font_synonym_nop_opt\font_basics_define_font_synonym_nop_nil}
+
+\unexpanded\def\font_basics_define_font_synonym_yes
+ {\expandafter\let\csname\??fontfile\fontclass\m_font_name\endcsname\m_font_file
+ \doifelsenextoptionalcs\font_basics_define_font_synonym_yes_opt\font_basics_define_font_synonym_yes_nil}
+
+\unexpanded\def\edefinefontsynonym[#name]#crap[#file]%
+ {\edef\m_font_name{#name}%
+ \edef\m_font_file{#file}%
+ \ifx\fontclass\empty
+ \expandafter\font_basics_define_font_synonym_nop_expanded
+ \else
+ \expandafter\font_basics_define_font_synonym_yes_expanded
+ \fi}
+
+\unexpanded\def\font_basics_define_font_synonym_nop_expanded#crap[#spec]%
+ {\expandafter\let\csname\??fontfile\m_font_name\endcsname\m_font_file
+ \normalexpanded{\font_basics_define_font_synonym_nop_opt[#1]}}
+
+\unexpanded\def\font_basics_define_font_synonym_yes_expanded#crap[#spec]%
+ {\expandafter\let\csname\??fontfile\fontclass\m_font_name\endcsname\m_font_file
+ \normalexpanded{\font_basics_define_font_synonym_yes_opt[#spec]}}
+
+\unexpanded\def\font_basics_define_font_synonym_nop_opt[#specification]%
+ {\let\p_features \undefined
+ \let\p_fallbacks \undefined
+ \let\p_goodies \undefined
+ \let\p_designsize\undefined
+ \expandafter\font_basics_get_font_parameter_nop#specification,]=,}
+
+\unexpanded\def\font_basics_define_font_synonym_yes_opt[#specification]%
+ {\let\p_features \undefined
+ \let\p_fallbacks \undefined
+ \let\p_goodies \undefined
+ \let\p_designsize\undefined
+ \expandafter\font_basics_get_font_parameter_yes#specification,]=,}
+
+% todo: check if we can use \edef but then we need to protect \mathsizesuffix .. in fact that
+% can be default then: \let\mathsizesuffix\relax .. i need to play with it first
+
+\def\font_basics_get_font_parameter_nop#key=#value,%
+ {\if]#key%
+ \font_basics_get_font_parameter_nop_finish
+ \else
+ \expandafter\normaldef\csname p_#key\endcsname{#value}% % no edef as we need to keep \mathsizesuffix
+ \expandafter\font_basics_get_font_parameter_nop
+ \fi}
+
+\def\font_basics_get_font_parameter_yes#key=#value,%
+ {\if]#key%
+ \font_basics_get_font_parameter_yes_finish
+ \else
+ \expandafter\normaldef\csname p_#key\endcsname{#value}% % no edef as we need to keep \mathsizesuffix
+ \expandafter\font_basics_get_font_parameter_yes
+ \fi}
+
+% helpers, some day these will be toks and counts
+
+% \def\fntsetdefname {\glet\somefontname\defaultfontfile}
+% \def\fntsetsomename{\gdef\somefontname} % takes argument
+% \def\fntsetnopsize {\let\somefontsize\empty}
+% \def\fntsetsomesize{\def\somefontsize} % takes argument
+
+% happens later, else mkvi parsing gets into troubles
+
+% end of helpers
+
+% we could collect them in one macro (but no expansion)
+
+\def\font_basics_define_font_synonym_nop_nil
+ {\expandafter\let\csname\??fontfile\m_font_name\s!features \endcsname\undefined
+ \expandafter\let\csname\??fontfile\m_font_name\s!fallbacks \endcsname\undefined
+ \expandafter\let\csname\??fontfile\m_font_name\s!goodies \endcsname\undefined
+ \expandafter\let\csname\??fontfile\m_font_name\s!designsize\endcsname\undefined}
+
+\def\font_basics_define_font_synonym_yes_nil
+ {\expandafter\glet\csname\??fontfile\fontclass\m_font_name\s!features \endcsname\undefined
+ \expandafter\glet\csname\??fontfile\fontclass\m_font_name\s!fallbacks \endcsname\undefined
+ \expandafter\glet\csname\??fontfile\fontclass\m_font_name\s!goodies \endcsname\undefined
+ \expandafter\glet\csname\??fontfile\fontclass\m_font_name\s!designsize\endcsname\undefined}
+
+\def\font_basics_get_font_parameter_nop_finish
+ {\expandafter\let\csname\??fontfile\m_font_name\s!features \endcsname\p_features
+ \expandafter\let\csname\??fontfile\m_font_name\s!fallbacks \endcsname\p_fallbacks
+ \expandafter\let\csname\??fontfile\m_font_name\s!goodies \endcsname\p_goodies
+ \expandafter\let\csname\??fontfile\m_font_name\s!designsize\endcsname\p_designsize}
+
+\def\font_basics_get_font_parameter_yes_finish
+ {\expandafter\glet\csname\??fontfile\fontclass\m_font_name\s!features \endcsname\p_features
+ \expandafter\glet\csname\??fontfile\fontclass\m_font_name\s!fallbacks \endcsname\p_fallbacks
+ \expandafter\glet\csname\??fontfile\fontclass\m_font_name\s!goodies \endcsname\p_goodies
+ \expandafter\glet\csname\??fontfile\fontclass\m_font_name\s!designsize\endcsname\p_designsize}
+
+%\definefontsynonym [KopFont] [\fontclassname{officina}{SerifBold}]
+%
+%\defineclassfontsynonym [KopFont] [officina] [SerifBold]
+
+\unexpanded\def\defineclassfontsynonym
+ {\dotripleargument\font_basics_define_class_font_synonym}
+
+%\definefontsynonym[#tag][\fontclassname{#class}{#fileortag}]}
+
+\def\font_basics_define_class_font_synonym[#tag][#class][#fileortag]% needs testing
+ {\expandafter\normaldef\csname\??fontfile\fontclass#tag\endcsname{\fontclassname{#class}{#fileortag}}%
+ \font_basics_define_font_synonym_yes_nil}
+
+\let\definefontfile\definefontsynonym % dedicated to Taco Hoekwater
+
+\unexpanded\def\setupfontsynonym
+ {\dodoubleempty\dosetupfontsynonym}
+
+\def\dosetupfontsynonym[#name][#settings]% not yet supported, will do when needed
+ {}
+
+% todo: replace * by ... less messy with features
+
+\def\truefontname#name%
+ {\expandafter\font_helpers_true_fontname#name*\empty*\relax}
+
+\def\font_helpers_true_fontname#name*#first#rest*#crap\relax
+ {\ifcsname\??fontfile\fontclass#name\endcsname
+ \ifx#first\empty
+ %\expandafter\truefontname\csname\??fontfile\fontclass#name\endcsname
+ \expandafter\truefontname\lastnamedcs
+ \else
+ %\expandafter\font_helpers_true_fontname_check\csname\??fontfile\fontclass#name\endcsname*#first#rest%
+ \expandafter\font_helpers_true_fontname_check\lastnamedcs*#first#rest%
+ \fi
+ \orelse\ifcsname\??fontfile\defaultfontclass#name\endcsname
+ \ifx#first\empty
+ %\expandafter\truefontname\csname\??fontfile\defaultfontclass#name\endcsname
+ \expandafter\truefontname\lastnamedcs
+ \else
+ %\expandafter\font_helpers_true_fontname_check\csname\??fontfile\defaultfontclass#name\endcsname*#first#rest%
+ \expandafter\font_helpers_true_fontname_check\lastnamedcs*#first#rest%
+ \fi
+ \orelse\ifcsname\??fontfile#name\endcsname
+ \ifx#first\empty
+ %\expandafter\truefontname\csname\??fontfile#name\endcsname
+ \expandafter\truefontname\lastnamedcs
+ \else
+ %\expandafter\font_helpers_true_fontname_check\csname\??fontfile#name\endcsname*#first#rest%
+ \expandafter\font_helpers_true_fontname_check\lastnamedcs*#first#rest%
+ \fi
+ \else
+ #name\ifx#first\empty\else*#first#rest\fi
+ \fi}
+
+\def\font_helpers_true_fontname_check#name%
+ {\expandafter\font_helpers_true_fontname_check_indeed#name*\relax}
+
+\def\font_helpers_true_fontname_check_indeed#name*#crap\relax
+ {\ifcsname\??fontfile\fontclass#name\endcsname
+ %\expandafter\font_helpers_true_fontname_check\csname\??fontfile\fontclass#name\endcsname
+ \expandafter\font_helpers_true_fontname_check\lastnamedcs
+ \orelse\ifcsname\??fontfile\defaultfontclass#name\endcsname
+ %\expandafter\font_helpers_true_fontname_check\csname\??fontfile\defaultfontclass#name\endcsname
+ \expandafter\font_helpers_true_fontname_check\lastnamedcs
+ \orelse\ifcsname\??fontfile#name\endcsname
+ %\expandafter\font_helpers_true_fontname_check\csname\??fontfile#name\endcsname
+ \expandafter\font_helpers_true_fontname_check\lastnamedcs
+ \else
+ #name%
+ \fi}
+
+% ok when the last lookup is not stripped .. we need to be able to define synonyms for symbols
+%
+% \def\truefontname#name%
+% %{\normalexpanded{\noexpand\font_helpers_true_fontname{\clf_truefontname{#name}}}}
+% {\expandafter\expandafter\expandafter\font_helpers_true_fontname\expandafter\expandafter\expandafter{\clf_truefontname{#name}}}
+%
+% \def\font_helpers_true_fontname#name%
+% {\ifcsname\??fontfile\fontclass#name\endcsname
+% \expandafter\font_helpers_true_fontname\expandafter{\lastnamedcs}%
+% \orelse\ifcsname\??fontfile\defaultfontclass#name\endcsname
+% \expandafter\font_helpers_true_fontname\expandafter{\lastnamedcs}%
+% \orelse\ifcsname\??fontfile#name\endcsname
+% \expandafter\font_helpers_true_fontname\expandafter{\lastnamedcs}%
+% \else
+% % \clf_truefontname{#name}%
+% #name% so the last one can have features !
+% \fi}
+
+\def\expandfontsynonym#command#name% one level expansion
+ {\ifcsname\??fontfile\fontclass#name\endcsname
+ %\expandafter\normaldef\expandafter#command\expandafter{\csname\??fontfile\fontclass#name\endcsname}%
+ \expandafter\normaldef\expandafter#command\expandafter{\lastnamedcs}%
+ \orelse\ifcsname\??fontfile\defaultfontclass#2\endcsname
+ %\expandafter\normaldef\expandafter#command\expandafter{\csname\??fontfile\defaultfontclass#name\endcsname}%
+ \expandafter\normaldef\expandafter#command\expandafter{\lastnamedcs}%
+ \fi}
+
+\def\doifelsefontsynonym#name%
+ {\ifcsname\??fontfile\fontclass#name\endcsname
+ \expandafter\firstoftwoarguments
+ \orelse\ifcsname\??fontfile\defaultfontclass#name\endcsname
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\let\doiffontsynonymelse\doifelsefontsynonym
+
+%D \macros
+%D {tracedfontname}
+%D
+%D A goody:
+
+\def\tracedfontname#name%
+ {#name\ifcsname\??fontfile\fontclass#name\endcsname
+ %\expandafter\tracedfontname\csname\??fontfile\fontclass#name\endcsname
+ \expandafter\tracedfontname\lastnamedcs
+ \orelse\ifcsname\??fontfile#name\endcsname
+ %\expandafter\tracedfontname\csname\??fontfile#name\endcsname
+ \expandafter\tracedfontname\lastnamedcs
+ \fi}
+
+%D \macros
+%D {fontclass, defaultfontclass}
+%D
+%D The fontclass model was introduced a while after we implement the basic font
+%D model and at that time we still defaulted to no model at all. Nowadays we default
+%D to the \type {modern} fontclass.
+
+\let\fontclass \empty
+\let\defaultfontclass\empty
+
+\def\fontclassname#class#name% tricky ... no lastnamedcs here due to nesting
+ {\ifcsname\??fontfile#class#name\endcsname
+ \fontclassname{#class}{\csname\??fontfile#class#name\endcsname}%
+ \orelse\ifcsname\??fontfile#name\endcsname
+ \fontclassname{#class}{\csname\??fontfile#name\endcsname}%
+ \else
+ #2%
+ \fi}
+
+\installmacrostack\fontclass
+
+%D Files or names can have properties and these need to be consulted at some point.
+%D They can inherit them.
+
+% Why these expanded and rscale not ... maybe not worth the trouble (delayed
+% expansion actually would be better i.e. macros in feature specs). Test
+% without pre-expansion.
+
+\def\font_helpers_update_font_class_parameters
+ {\edef\m_font_class_direction {\begincsname\??fontclass\fontclass\fontstyle\s!direction \endcsname}%
+ \edef\m_font_class_features {\begincsname\??fontclass\fontclass\fontstyle\s!features \endcsname}%
+ \edef\m_font_class_fallbacks {\begincsname\??fontclass\fontclass\fontstyle\s!fallbacks \endcsname}%
+ \edef\m_font_class_goodies {\begincsname\??fontclass\fontclass\fontstyle\s!goodies \endcsname}%
+ \edef\m_font_class_designsize{\begincsname\??fontclass\fontclass\fontstyle\s!designsize\endcsname}}
+
+% resolve
+
+\def\font_helpers_set_features_yes#name%
+ {\ifcsname\??fontfile\fontclass#name\s!features\endcsname \edef\m_font_features{\lastnamedcs}\orelse % class + symbolic_name
+ \ifcsname\??fontfile #name\s!features\endcsname \edef\m_font_features{\lastnamedcs}\orelse % symbolic_name
+ \ifcsname\??fontfile\fontclass#name\endcsname \expandafter\font_helpers_set_features_yes\lastnamedcs \orelse % class + parent_name
+ \ifcsname\??fontfile #name\endcsname \expandafter\font_helpers_set_features_yes\lastnamedcs \else % parent_name
+ \let\m_font_features\empty\fi}
+
+\def\font_helpers_set_fallbacks_yes#name%
+ {\ifcsname\??fontfile\fontclass#name\s!fallbacks\endcsname \edef\m_font_fallbacks{\lastnamedcs}\orelse
+ \ifcsname\??fontfile #name\s!fallbacks\endcsname \edef\m_font_fallbacks{\lastnamedcs}\orelse
+ \ifcsname\??fontfile\fontclass#name\endcsname \expandafter\font_helpers_set_fallbacks_yes\lastnamedcs \orelse
+ \ifcsname\??fontfile #name\endcsname \expandafter\font_helpers_set_fallbacks_yes\lastnamedcs \else
+ \let\m_font_fallbacks\empty\fi}
+
+\def\font_helpers_set_goodies_yes#name%
+ {\ifcsname\??fontfile\fontclass#name\s!goodies \endcsname \edef\m_font_goodies{\lastnamedcs}\orelse
+ \ifcsname\??fontfile #name\s!goodies \endcsname \edef\m_font_goodies{\lastnamedcs}\orelse
+ \ifcsname\??fontfile\fontclass#name\endcsname \expandafter\font_helpers_set_goodies_yes\lastnamedcs \orelse
+ \ifcsname\??fontfile #name\endcsname \expandafter\font_helpers_set_goodies_yes\lastnamedcs \else
+ \let\m_font_goodies\empty\fi}
+
+\def\font_helpers_set_designsize_yes#name%
+ {\ifcsname\??fontfile\fontclass#name\s!designsize\endcsname \edef\m_font_designsize{\lastnamedcs}\orelse
+ \ifcsname\??fontfile #name\s!designsize\endcsname \edef\m_font_designsize{\lastnamedcs}\orelse
+ \ifcsname\??fontfile\fontclass#name\endcsname \expandafter\font_helpers_set_designsize_yes\lastnamedcs \orelse
+ \ifcsname\??fontfile #name\endcsname \expandafter\font_helpers_set_designsize_yes\lastnamedcs \else
+ \let\m_font_designsize\empty\fi}
+
+\def\font_helpers_set_features_nop#name%
+ {\ifcsname\??fontfile#name\s!features\endcsname \edef\m_font_features{\lastnamedcs}\orelse
+ \ifcsname\??fontfile#name\endcsname \expandafter\font_helpers_set_features_nop\lastnamedcs \else
+ \let\m_font_features\empty\fi}
+
+\def\font_helpers_set_fallbacks_nop#name%
+ {\ifcsname\??fontfile#name\s!fallbacks\endcsname \edef\m_font_fallbacks{\lastnamedcs}\orelse
+ \ifcsname\??fontfile#name\endcsname \expandafter\font_helpers_set_fallbacks_nop\lastnamedcs \else
+ \let\m_font_fallbacks\empty\fi}
+
+\def\font_helpers_set_goodies_nop#name%
+ {\ifcsname\??fontfile#name\s!goodies\endcsname \edef\m_font_goodies{\lastnamedcs}\orelse
+ \ifcsname\??fontfile#name\endcsname \expandafter\font_helpers_set_goodies_nop\lastnamedcs \else
+ \let\m_font_goodies\empty\fi}
+
+\def\font_helpers_set_designsize_nop#name%
+ {\ifcsname\??fontfile#name\s!designsize\endcsname \edef\m_font_designsize{\lastnamedcs}\orelse
+ \ifcsname\??fontfile#name\endcsname \expandafter\font_helpers_set_designsize_nop\lastnamedcs \else
+ \let\m_font_designsize\empty\fi}
+
+\def\font_helpers_update_font_parameters_yes
+ {\font_helpers_set_features_yes \somefontname
+ \font_helpers_set_fallbacks_yes \somefontname
+ \font_helpers_set_goodies_yes \somefontname
+ \font_helpers_set_designsize_yes\somefontname}
+
+\def\font_helpers_update_font_parameters_nop
+ {\font_helpers_set_features_nop \somefontname
+ \font_helpers_set_fallbacks_nop \somefontname
+ \font_helpers_set_goodies_nop \somefontname
+ \font_helpers_set_designsize_nop\somefontname}
+
+\def\font_helpers_update_font_parameters
+ {\ifx\fontclass\empty\font_helpers_update_font_parameters_nop\else\font_helpers_update_font_parameters_yes\fi}
+
+\installcorenamespace{fontclass}
+
+% we can pack them (don't use \setxvalue!)
+
+\unexpanded\def\savefontclassparameters#style#rscale#features#fallbacks#goodies#designsize#direction%
+ {\letgvalue{\??fontclass\fontclass#style\s!rscale }#rscale%
+ \letgvalue{\??fontclass\fontclass#style\s!features }#features%
+ \letgvalue{\??fontclass\fontclass#style\s!fallbacks }#fallbacks%
+ \letgvalue{\??fontclass\fontclass#style\s!goodies }#goodies%
+ \letgvalue{\??fontclass\fontclass#style\s!designsize}#designsize%
+ \letgvalue{\??fontclass\fontclass#style\s!direction }#direction}% math
+
+% bonus
+
+\let\currentfontinstancespec\clf_currentfontinstancespec % expandable
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-fil.mkvi b/Master/texmf-dist/tex/context/base/mkiv/font-fil.mkvi
index ae83ef4c4f4..8622e733f3d 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-fil.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-fil.mkvi
@@ -15,11 +15,10 @@
\unprotect
-%D Personally I think that using \TEX\ macro packages is
-%D complicated by the way fonts are handled. Apart from the
-%D many encodings, we also deal with different naming schemes.
-%D Confronted with this problem, I decided to change the
-%D definitions into:
+%D Personally I think that using \TEX\ macro packages is complicated by the way
+%D fonts are handled. Apart from the many encodings, we also deal with different
+%D naming schemes. Confronted with this problem, I decided to change the definitions
+%D into:
%D
%D \starttyping
%D \definebodyfont [12pt] [rm] [tf=Times-Roman at 12pt]
@@ -307,10 +306,9 @@
%D \macros
%D {fontclass, defaultfontclass}
%D
-%D The fontclass model was introduced a while after we implement
-%D the basic font model and at that time we still defaulted to
-%D no model at all. Nowadays we default to the \type {modern}
-%D fontclass.
+%D The fontclass model was introduced a while after we implement the basic font
+%D model and at that time we still defaulted to no model at all. Nowadays we default
+%D to the \type {modern} fontclass.
\let\fontclass \empty
\let\defaultfontclass\empty
@@ -326,8 +324,8 @@
\installmacrostack\fontclass
-%D Files or names can have properties and these need to be consulted
-%D at some point. They can inherit them.
+%D Files or names can have properties and these need to be consulted at some point.
+%D They can inherit them.
% Why these expanded and rscale not ... maybe not worth the trouble (delayed
% expansion actually would be better i.e. macros in feature specs). Test
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-imp-dimensions.lua b/Master/texmf-dist/tex/context/base/mkiv/font-imp-dimensions.lua
index a7125625da7..24891a2cdf3 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-imp-dimensions.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-imp-dimensions.lua
@@ -48,13 +48,42 @@ local function initialize(tfmdata,key,value)
elseif value == "mono" then
newwidth = emwidth
else
+ -- there are fonts out there with no x_height ...
local spec = settings_to_array(value)
- newwidth = tonumber(spec[1])
- newheight = tonumber(spec[2])
- newdepth = tonumber(spec[3])
- if newwidth then newwidth = newwidth * emwidth end
- if newheight then newheight = newheight * exheight end
- if newdepth then newdepth = newdepth * exheight end
+ newwidth = spec[1]
+ newheight = spec[2]
+ newdepth = spec[3]
+ local quad = parameters.quad or 0
+ local ascender = parameters.ascender or 0
+ local descender = parameters.descender or 0
+ if newwidth == "max" then
+ newwidth = quad
+ else
+ newwidth = tonumber(newwidth)
+ if newwidth then
+ newwidth = newwidth * emwidth
+ end
+ end
+ if newheight == "max" then
+ newheight = ascender
+ else
+ newheight = tonumber(newheight)
+ if newheight then
+ newheight = newheight * exheight
+ end
+ end
+ if newdepth == "max" then
+ newdepth = descender
+ else
+ newdepth = tonumber(newdepth)
+ if newdepth then
+ newdepth = newdepth * exheight
+ end
+ end
+ if parameters.x_heigth == 0 then
+ -- maybe a fourth parameter
+ parameters.x_heigth = (ascender + descender) / 2
+ end
end
if newwidth or newheight or newdepth then
for unicode, character in next, characters do
@@ -107,7 +136,7 @@ end
registerotffeature {
name = "realdimensions",
- description = "accept negative dimenions",
+ description = "accept negative dimensions",
initializers = {
base = initialize,
node = initialize,
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-imp-properties.lua b/Master/texmf-dist/tex/context/base/mkiv/font-imp-properties.lua
index 5805235b780..21b55aeb2b0 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-imp-properties.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-imp-properties.lua
@@ -35,7 +35,6 @@ local constructors = fonts.constructors
local getprivate = constructors.getprivate
local allocate = utilities.storage.allocate
-local family_font = node.family_font
local setmetatableindex = table.setmetatableindex
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-imp-quality.lua b/Master/texmf-dist/tex/context/base/mkiv/font-imp-quality.lua
index 01f0afe6309..053a2562f9b 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-imp-quality.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-imp-quality.lua
@@ -9,8 +9,6 @@ if not modules then modules = { } end modules ['font-imp-quality'] = {
if not context then return end
local next, type, tonumber = next, type, tonumber
-local byte = string.byte
-local insert = table.insert
local fonts = fonts
local utilities = utilities
@@ -65,26 +63,63 @@ local vectors = expansions.vectors or allocate()
expansions.classes = classes
expansions.vectors = vectors
--- beware, pdftex itself uses percentages * 10
---
--- todo: get rid of byte() here
-
-classes.preset = { stretch = 2, shrink = 2, step = .5, factor = 1 }
+classes.preset = {
+ stretch = 2,
+ shrink = 2,
+ step = .5,
+ factor = 1,
+}
classes['quality'] = {
- stretch = 2, shrink = 2, step = .5, vector = 'default', factor = 1
+ stretch = 2,
+ shrink = 2,
+ step = .5,
+ vector = 'default',
+ factor = 1,
}
vectors['default'] = {
- [byte('A')] = 0.5, [byte('B')] = 0.7, [byte('C')] = 0.7, [byte('D')] = 0.5, [byte('E')] = 0.7,
- [byte('F')] = 0.7, [byte('G')] = 0.5, [byte('H')] = 0.7, [byte('K')] = 0.7, [byte('M')] = 0.7,
- [byte('N')] = 0.7, [byte('O')] = 0.5, [byte('P')] = 0.7, [byte('Q')] = 0.5, [byte('R')] = 0.7,
- [byte('S')] = 0.7, [byte('U')] = 0.7, [byte('W')] = 0.7, [byte('Z')] = 0.7,
- [byte('a')] = 0.7, [byte('b')] = 0.7, [byte('c')] = 0.7, [byte('d')] = 0.7, [byte('e')] = 0.7,
- [byte('g')] = 0.7, [byte('h')] = 0.7, [byte('k')] = 0.7, [byte('m')] = 0.7, [byte('n')] = 0.7,
- [byte('o')] = 0.7, [byte('p')] = 0.7, [byte('q')] = 0.7, [byte('s')] = 0.7, [byte('u')] = 0.7,
- [byte('w')] = 0.7, [byte('z')] = 0.7,
- [byte('2')] = 0.7, [byte('3')] = 0.7, [byte('6')] = 0.7, [byte('8')] = 0.7, [byte('9')] = 0.7,
+ [0x0041] = 0.5, -- A
+ [0x0042] = 0.7, -- B
+ [0x0043] = 0.7, -- C
+ [0x0044] = 0.5, -- D
+ [0x0045] = 0.7, -- E
+ [0x0046] = 0.7, -- F
+ [0x0047] = 0.5, -- G
+ [0x0048] = 0.7, -- H
+ [0x004B] = 0.7, -- K
+ [0x004D] = 0.7, -- M
+ [0x004E] = 0.7, -- N
+ [0x004F] = 0.5, -- O
+ [0x0050] = 0.7, -- P
+ [0x0051] = 0.5, -- Q
+ [0x0052] = 0.7, -- R
+ [0x0053] = 0.7, -- S
+ [0x0055] = 0.7, -- U
+ [0x0057] = 0.7, -- W
+ [0x005A] = 0.7, -- Z
+ [0x0061] = 0.7, -- a
+ [0x0062] = 0.7, -- b
+ [0x0063] = 0.7, -- c
+ [0x0064] = 0.7, -- d
+ [0x0065] = 0.7, -- e
+ [0x0067] = 0.7, -- g
+ [0x0068] = 0.7, -- h
+ [0x006B] = 0.7, -- k
+ [0x006D] = 0.7, -- m
+ [0x006E] = 0.7, -- n
+ [0x006F] = 0.7, -- o
+ [0x0070] = 0.7, -- p
+ [0x0071] = 0.7, -- q
+ [0x0073] = 0.7, -- s
+ [0x0075] = 0.7, -- u
+ [0x0077] = 0.7, -- w
+ [0x007A] = 0.7, -- z
+ [0x0032] = 0.7, -- 2
+ [0x0033] = 0.7, -- 3
+ [0x0036] = 0.7, -- 6
+ [0x0038] = 0.7, -- 8
+ [0x0039] = 0.7, -- 9
}
vectors['quality'] = vectors['default'] -- metatable ?
@@ -153,15 +188,11 @@ registerafmfeature(specification)
fonts.goodies.register("expansions", function(...) return fonts.goodies.report("expansions", trace_expansion, ...) end)
-if context then
-
- implement {
- name = "setupfontexpansion",
- arguments = "2 strings",
- actions = function(class,settings) getparameters(classes,class,'preset',settings) end
- }
-
-end
+implement {
+ name = "setupfontexpansion",
+ arguments = "2 strings",
+ actions = function(class,settings) getparameters(classes,class,'preset',settings) end
+}
-- -- -- -- -- --
-- protrusion
@@ -178,21 +209,17 @@ local vectors = protrusions.vectors
-- the values need to be revisioned
-classes.preset = { factor = 1, left = 1, right = 1 }
-
-classes['pure'] = {
- vector = 'pure', factor = 1
-}
-classes['punctuation'] = {
- vector = 'punctuation', factor = 1
-}
-classes['alpha'] = {
- vector = 'alpha', factor = 1
-}
-classes['quality'] = {
- vector = 'quality', factor = 1
+classes.preset = {
+ factor = 1,
+ left = 1,
+ right = 1,
}
+classes['pure'] = { vector = 'pure', factor = 1 }
+classes['punctuation'] = { vector = 'punctuation', factor = 1 }
+classes['alpha'] = { vector = 'alpha', factor = 1 }
+classes['quality'] = { vector = 'quality', factor = 1 }
+
vectors['pure'] = {
[0x002C] = { 0, 1 }, -- comma
@@ -254,24 +281,24 @@ vectors['punctuation'] = {
vectors['alpha'] = {
- [byte("A")] = { .05, .05 },
- [byte("F")] = { 0, .05 },
- [byte("J")] = { .05, 0 },
- [byte("K")] = { 0, .05 },
- [byte("L")] = { 0, .05 },
- [byte("T")] = { .05, .05 },
- [byte("V")] = { .05, .05 },
- [byte("W")] = { .05, .05 },
- [byte("X")] = { .05, .05 },
- [byte("Y")] = { .05, .05 },
-
- [byte("k")] = { 0, .05 },
- [byte("r")] = { 0, .05 },
- [byte("t")] = { 0, .05 },
- [byte("v")] = { .05, .05 },
- [byte("w")] = { .05, .05 },
- [byte("x")] = { .05, .05 },
- [byte("y")] = { .05, .05 },
+ [0x0041] = { .05, .05 }, -- A
+ [0x0046] = { 0, .05 }, -- F
+ [0x004A] = { .05, 0 }, -- J
+ [0x004B] = { 0, .05 }, -- K
+ [0x004C] = { 0, .05 }, -- L
+ [0x0054] = { .05, .05 }, -- T
+ [0x0056] = { .05, .05 }, -- V
+ [0x0057] = { .05, .05 }, -- W
+ [0x0058] = { .05, .05 }, -- X
+ [0x0059] = { .05, .05 }, -- Y
+
+ [0x006B] = { 0, .05 }, -- k
+ [0x0072] = { 0, .05 }, -- r
+ [0x0074] = { 0, .05 }, -- t
+ [0x0076] = { .05, .05 }, -- v
+ [0x0077] = { .05, .05 }, -- w
+ [0x0078] = { .05, .05 }, -- x
+ [0x0079] = { .05, .05 }, -- y
}
@@ -305,7 +332,9 @@ vectors['quality'] = table.merged(
-- \definefontfeature[whocares][default][mode=node,protrusion=2,opbd=yes,script=latn,featurefile=texgyrepagella-regularxx.fea]
classes['double'] = { -- for testing opbd
- factor = 2, left = 1, right = 1,
+ factor = 2,
+ left = 1,
+ right = 1,
}
local function map_opbd_onto_protrusion(tfmdata,value,opbd)
@@ -438,8 +467,7 @@ local function initialize(tfmdata,value)
report_protrusions("setting class %a, vector %a, factor %a, left %a, right %a",
value,class.vector,factor,left,right)
end
- local data = characters.data
- local emwidth = tfmdata.parameters.quad
+ local data = characters.data
local lfactor = left * factor
local rfactor = right * factor
if trace_protrusion then
@@ -516,12 +544,40 @@ registerafmfeature(specification)
fonts.goodies.register("protrusions", function(...) return fonts.goodies.report("protrusions", trace_protrusion, ...) end)
-if context then
+implement {
+ name = "setupfontprotrusion",
+ arguments = "2 strings",
+ actions = function(class,settings) getparameters(classes,class,'preset',settings) end
+}
+
+local function initialize(tfmdata,value)
+ local properties = tfmdata.properties
+ local parameters = tfmdata.parameters
+ if properties then
+ value = tonumber(value)
+ if value then
+ if value < 0 then
+ value = 0
+ elseif value > 10 then
+ report_expansions("threshold for %a @ %p limited to 10 pct",properties.fontname,parameters.size)
+ value = 10
+ end
+ if value > 5 then
+ report_expansions("threshold for %a @ %p exceeds 5 pct",properties.fontname,parameters.size)
+ end
+ end
+ properties.threshold = value or nil -- nil enforces default
+ end
+end
- implement {
- name = "setupfontprotrusion",
- arguments = "2 strings",
- actions = function(class,settings) getparameters(classes,class,'preset',settings) end
+local specification = {
+ name = "threshold",
+ description = "threshold for quality features",
+ initializers = {
+ base = initialize,
+ node = initialize,
}
+}
-end
+registerotffeature(specification)
+registerafmfeature(specification)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-imp-spacekerns.lua b/Master/texmf-dist/tex/context/base/mkiv/font-imp-spacekerns.lua
new file mode 100644
index 00000000000..0e2b0f9b0ae
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-imp-spacekerns.lua
@@ -0,0 +1,258 @@
+if not modules then modules = { } end modules ['font-imp-spacekerns'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv and hand-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+if not context then return end
+
+-- This is an experiment. See font-ots.lua for original implementation.
+
+local type, next = type, next
+local insert, setmetatableindex = table.insert, table.setmetatableindex
+
+local fonts = fonts
+local otf = fonts.handlers.otf
+local fontdata = fonts.hashes.identifiers
+local fontfeatures = fonts.hashes.features
+local otffeatures = fonts.constructors.features.otf
+local registerotffeature = otffeatures.register
+local handlers = otf.handlers
+local setspacekerns = nodes.injections.setspacekerns
+
+function handlers.trigger_space_kerns(head,dataset,sequence,initialrl,font,attr)
+ local features = fontfeatures[font]
+ local enabled = features and features.spacekern
+ if enabled then
+ setspacekerns(font,sequence) -- called quite often, each glyphrun
+ end
+ return head, enabled
+end
+
+local function hasspacekerns(data)
+ local resources = data.resources
+ local sequences = resources.sequences
+ local validgpos = resources.features.gpos
+ if validgpos and sequences then
+ for i=1,#sequences do
+ local sequence = sequences[i]
+ local steps = sequence.steps
+ if steps then -- and sequence.features[tag] then
+ local kind = sequence.type
+ if kind == "gpos_pair" then -- or kind == "gpos_single" then
+ for i=1,#steps do
+ local step = steps[i]
+ local coverage = step.coverage
+ local rules = step.rules
+ -- if rules then
+ -- -- not now: analyze (simple) rules
+ -- elseif not coverage then
+ -- -- nothing to do
+ -- elseif kind == "gpos_single" then
+ -- -- maybe a message that we ignore
+ -- elseif kind == "gpos_pair" then
+ if coverage and not rules then
+ local format = step.format
+ if format == "move" or format == "kern" then
+ local kerns = coverage[32]
+ if kerns then
+ return true
+ end
+ for k, v in next, coverage do
+ if v[32] then
+ return true
+ end
+ end
+ elseif format == "pair" then
+ local kerns = coverage[32]
+ if kerns then
+ for k, v in next, kerns do
+ local one = v[1]
+ if one and one ~= true then
+ return true
+ end
+ end
+ end
+ for k, v in next, coverage do
+ local kern = v[32]
+ if kern then
+ local one = kern[1]
+ if one and one ~= true then
+ return true
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ return false
+end
+
+otf.readers.registerextender {
+ name = "spacekerns",
+ action = function(data)
+ data.properties.hasspacekerns = hasspacekerns(data)
+ end
+}
+
+local function newdata(t,k)
+ local v = {
+ left = { },
+ right = { },
+ last = 0,
+ feat = nil,
+ }
+ t[k] = v
+ return v
+end
+
+local function spaceinitializer(tfmdata,value) -- attr
+ local resources = tfmdata.resources
+ local spacekerns = resources and resources.spacekerns
+ if value and spacekerns == nil then
+ local rawdata = tfmdata.shared and tfmdata.shared.rawdata
+ local properties = rawdata.properties
+ if properties and properties.hasspacekerns then
+ local sequences = resources.sequences
+ local validgpos = resources.features.gpos
+ if validgpos and sequences then
+ local data = setmetatableindex(newdata)
+ for i=1,#sequences do
+ local sequence = sequences[i]
+ local steps = sequence.steps
+ if steps then
+ -- we don't support space kerns in other features
+ -- local kern = sequence.features[tag]
+ -- if kern then
+ for tag, kern in next, sequence.features do
+
+ local d = data[tag]
+ local left = d.left
+ local right = d.right
+ local last = d.last
+ local feat = d.feat
+
+ local kind = sequence.type
+ if kind == "gpos_pair" then -- or kind == "gpos_single" then
+ if feat then
+ for script, languages in next, kern do
+ local f = feat[script]
+ if f then
+ for l in next, languages do
+ f[l] = true
+ end
+ else
+ feat[script] = languages
+ end
+ end
+ else
+ feat = kern
+ d.feat = feat
+ end
+ for i=1,#steps do
+ local step = steps[i]
+ local coverage = step.coverage
+ local rules = step.rules
+ -- if rules then
+ -- -- not now: analyze (simple) rules
+ -- elseif not coverage then
+ -- -- nothing to do
+ -- elseif kind == "gpos_single" then
+ -- -- makes no sense in TeX
+ -- elseif kind == "gpos_pair" then
+ if coverage and not rules then
+ local format = step.format
+ if format == "move" or format == "kern" then
+ local kerns = coverage[32]
+ if kerns then
+ for k, v in next, kerns do
+ right[k] = v
+ end
+ end
+ for k, v in next, coverage do
+ local kern = v[32]
+ if kern then
+ left[k] = kern
+ end
+ end
+ elseif format == "pair" then
+ local kerns = coverage[32]
+ if kerns then
+ for k, v in next, kerns do
+ local one = v[1]
+ if one and one ~= true then
+ right[k] = one[3]
+ end
+ end
+ end
+ for k, v in next, coverage do
+ local kern = v[32]
+ if kern then
+ local one = kern[1]
+ if one and one ~= true then
+ left[k] = one[3]
+ end
+ end
+ end
+ end
+ end
+ end
+ last = i
+ end
+d.last = last
+ end
+ end
+ end
+
+ for tag, d in next, data do
+ local left = d.left
+ local right = d.right
+ left = next(left) and left or false
+ right = next(right) and right or false
+ if left or right then
+
+ local last = d.last
+ local feat = d.feat
+
+ if last > 0 then
+ local triggersequence = {
+ -- no steps, see (!!)
+ features = { [tag] = feat or { dflt = { dflt = true, } } },
+ flags = noflags,
+ name = "trigger_space_kerns",
+ order = { tag },
+ type = "trigger_space_kerns",
+ left = left,
+ right = right,
+ }
+ insert(sequences,last,triggersequence)
+ d.last = d.last + 1
+ spacekerns = true
+ end
+ end
+
+ end
+ end
+ end
+ if not spacekerns then
+ spacekerns = false
+ end
+ resources.spacekerns = spacekerns
+ end
+ return spacekerns
+end
+
+registerotffeature {
+ name = "spacekern",
+ description = "space kern injection",
+ default = true,
+ initializers = {
+ node = spaceinitializer,
+ },
+}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-ini.lua b/Master/texmf-dist/tex/context/base/mkiv/font-ini.lua
index 462e30bf909..8bab6d90295 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-ini.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-ini.lua
@@ -52,3 +52,7 @@ fonts.privateoffsets = {
mathbase = 0xFF000, -- used for hidden (virtual math)
keepnames = false, -- when set to true names are always kept (not for context)
}
+
+if node and not tex.getfontoffamily then
+ tex.getfontoffamily = node.family_font -- we moved this
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-ini.mklx b/Master/texmf-dist/tex/context/base/mkiv/font-ini.mklx
new file mode 100644
index 00000000000..4b112322dc3
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-ini.mklx
@@ -0,0 +1,2563 @@
+%D \module
+%D [ file=font-ini,
+%D version=1998.09.11, % (second)
+%D version=2001.02.20, % (third)
+%D title=\CONTEXT\ Font Macros,
+%D subtitle=Initialization,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% todo: < 3 pt => 3pt
+% todo: check where more class usage
+% todo: split font-nam (style/alternative/size)
+% todo: split font-dim (scales etc)
+% todo: reconsider defaultfontclass
+%
+
+%D Watch out: as we define inside macros in sometimes special ways,
+%D an occasional \type {\normaldef} is used in order to please the
+%D \MKVI\ parser.
+
+%D Beware, we use a special set of parameters here:
+%D
+%D \starttabulate[|l|l|]
+%D \NC system variable (fixed) \NC \type {\s!text} \NC \NR
+%D \NC system variable (fixed) \NC \type {\s!script} \NC \NR
+%D \NC system variable (fixed) \NC \type {\s!scriptscript} \NC \NR
+%D \NC system variable (fixed) \NC \type {\s!x} \NC \NR
+%D \NC system variable (fixed) \NC \type {\s!xx} \NC \NR
+%D \NC variable (value) \NC \type {\v!big} \NC \NR
+%D \NC variable (value) \NC \type {\v!small} \NC \NR
+%D \NC constant (regular key) \NC \type {\c!interlinespace} \NC \NR
+%D \NC constant (regular key) \NC \type {\c!em} \NC \NR
+%D \stoptabulate
+%D
+%D The math related ones are similar to the ones used in \TEX\ itself,
+%D the size related ones show up as keywords in the user interface
+%D when switching sizes, and the two constants are used in key|/|value
+%D situations.
+
+%D We should consider design sizes ... maybe kick 'm out which removes
+%D the size code and simplifies things considerably. After all, there
+%D will be no latin modern math in sizes.
+
+\writestatus{loading}{ConTeXt Font Macros / Initialization}
+
+%D Documentation is somewhat messy as it contains bits and pieces of
+%D previous versions.
+
+\unprotect
+
+%D There are several ways to specify a font. Three of them are pure \TEX\ ones, the
+%D fourth one is new:
+%D
+%D \starttyping
+%D \font\name=cmr12
+%D \font\name=cmr12 at 10pt
+%D \font\name=cmr12 scaled 2
+%D \font\name=cmr12 sa 1.440
+%D \stoptyping
+%D
+%D The non||\TEX\ alternative \type{sa} stands for {\em scaled at}. This means as
+%D much as: scale the bodyfontsize with this factor. The scaled option is not that
+%D useful as one needs to know the design size.
+%D
+%D Because \type {sa} (scaled at) and \type {mo} (mapped on) are not low level \TEX\
+%D supported alternatives, we have to test for it ourselves. In doing so, we need an
+%D auxiliary \DIMENSION. We cannot use \type{\scratchdimen} because font loading can
+%D happen at any moment due to postponed loading. We could instead have used dirty
+%D grouping tricks, but this one works too.
+
+% \enableexperiments[fonts.autorscale]
+%
+% \starttypescript[mscore]
+% \definetypeface [mscore] [rm] [serif] [mscoretimes] [default]
+% \definetypeface [mscore] [ss] [sans] [mscorearial] [default] [rscale=auto] % 0.860]
+% \definetypeface [mscore] [tt] [mono] [mscorecourier] [default] [rscale=auto] % 1.065]
+% \definetypeface [mscore] [mm] [math] [times] [default] [rscale=auto] % 1.020]
+% \stoptypescript
+%
+% \starttext
+% \setupbodyfont[mscore,12pt]
+% \startTEXpage
+% test \ss test \tt test
+% \stopTEXpage
+% \stoptext
+
+% \definetypeface[one][rm][serif][computer-roman][default]
+% \definetypeface[two][rm][serif][computer-roman][default][rscale=.9]
+%
+% {\one \bf test \two test}
+% {\one \bf test \pushcurrentfont \two \popcurrentfont test}
+
+%D \macros
+%D {rm,ss,tt,hw,cg}
+%D
+%D Fonts are defined in separate files. When we define a font, we distinguish
+%D between several styles. In most cases we will use:
+%D
+%D \startlinecorrection
+%D \starttable[|l||]
+%D \HL
+%D \NC roman regular serif \NC \type{\rm} \NC\FR
+%D \NC sansserif sans support \NC \type{\ss} \NC\MR
+%D \NC type teletype mono \NC \type{\tt} \NC\LR
+%D \HL
+%D \stoptable
+%D \stoplinecorrection
+%D
+%D The number of styles is not limited to these three. When using Lucida Bright we
+%D can for instance also define:
+%D
+%D \startlinecorrection
+%D \starttable[|l||]
+%D \HL
+%D \NC handwritten \NC \type{\hw} \NC\FR
+%D \NC calligraphic \NC \type{\cg} \NC\LR
+%D \HL
+%D \stoptable
+%D \stoplinecorrection
+%D
+%D Within such a font set (\type{cmr}) and style (\type{\rm}) we can define a number
+%D of text font alternatives:
+%D
+%D \startlinecorrection
+%D \starttable[|l||]
+%D \HL
+%D \NC typeface \NC \type{\tf} \NC\FR
+%D \NC boldface \NC \type{\bf} \NC\MR
+%D \NC slanted \NC \type{\sl} \NC\MR
+%D \NC italic \NC \type{\it} \NC\MR
+%D \NC boldslanted \NC \type{\bs} \NC\MR
+%D \NC bolditalic \NC \type{\bi} \NC\MR
+%D \NC smallcaps \NC \type{\sc} \NC\LR
+%D \HL
+%D \stoptable
+%D \stoplinecorrection
+%D
+%D Internally fonts are stored as combination of size, style
+%D and alternative, e.g. \type{12pt}+\type{\ss}+\type{\bf}. Users are not confronted
+%D with sizes, but use the style or style+alternative to activate them.
+%D
+%D During the definition of a bodyfont one can also declare the available larger
+%D alternatives:
+%D
+%D \starttyping
+%D \tf \tfa \tfb \tfc ...
+%D \bf \bfa \bfb \bfc ...
+%D \sl \sla \slb \slc ...
+%D \stoptyping
+%D
+%D The smaller ones are automatically supplied and derived from
+%D the the bodyfont environment.
+%D
+%D \starttyping
+%D \tfx \tfxx
+%D \bfx \bfxx
+%D \slx \slxx
+%D \stoptyping
+%D
+%D There are only two smaller alternatives per style. The larger alternatives on the
+%D other hand have no limitations.
+%D
+%D These larger alternatives are mostly used in chapter and section titles or on
+%D title pages. When one switches to a larger alternative, the bold an other ones
+%D automatically adapt themselves:
+%D
+%D \startbuffer
+%D \tfd Hi \bf there\sl, here \tfb I \bf am
+%D \stopbuffer
+%D
+%S \startnarrower
+%D \typebuffer
+%S \stopnarrower
+%D
+%D therefore becomes:
+%D
+%D \startexample
+%D \getbuffer
+%D \stopexample
+%D
+%D Maybe this mechanism isn't always as logic, but as said before, we tried to make
+%D it as intuitive as possible.
+%D
+%D So a specific kind of glyph can be characterized by:
+%D
+%D \startnarrower
+%D family (cmr) + bodyfont (12pt) + style (rm) + alternative (bf) + size (a)
+%D \stopnarrower
+%D
+%D The last component (the size) is optional.
+%D
+%D We introduced \type {\tf} as command to call for the current normally sized
+%D typeface. This commands results in roman, sans serif, teletype or whatever style
+%D is in charge. Such rather massive switches of style sometimes take more
+%D processing time than comfortable. Of course there is a workaround for this: we
+%D can call fonts directly by means of commands like:
+%D
+%D \starttyping
+%D \rmtf \sssl \tttf \rmbsa
+%D \stoptyping
+%D
+%D One should realize that this fast calls have limitations, they lack for instance
+%D automatic super- and subscript support.
+%D
+%D This leaves us two more commands: \type {\tx} and \type {\txx}. These activate a
+%D smaller and even more smaller font than the current one and adapt themselves to
+%D the current alternative, so when \type {\bf} is active, \type {\tx} gives a
+%D smaller boldface, which in turn can be called directly by \type {\bfx}.
+%D
+%D These two smaller alternatives are specified by the bodyfont environment and
+%D therefore not necessarily have similar sizes as \type {\scriptsize} and \type
+%D {\scriptscriptsize}. The main reason for this incompatibility (which can easily
+%D be undone) lays in the fact that we often want a bit bigger characters than in
+%D math mode. In \CONTEXT\ for instance the \type {\tx} and \type {\txx} commands
+%D are used for surrogate \cap {smallcaps} which support both nesting and
+%D alternatives, like in {\bf \cap {a \cap {small} world}}, which was typeset by
+%D
+%D \starttyping
+%D \bf\cap{a \cap{small} world}
+%D \stoptyping
+%D
+%D And compare $\rm \scriptstyle THIS$ with the slightly larger \cap {THIS}:
+%D \ruledhbox {$\rm \scriptstyle scriptstyle: THIS$} or \ruledhbox {\cap {x style:
+%D THIS}} makes a big difference.
+%D
+%D The \type {x..d} sizes should be used grouped. If you don't group them, i.e. call
+%D them in a row, \CONTEXT\ will not be able to sort out your intention (\type {x}
+%D inside \type {d} inside \type {x}. etc.). The following table demonstrates this:
+%D
+%D \def\FontState{\setstrut\ruledhbox{\strut Hello}}
+%D
+%D \starttabulate[|||||]
+%D \HL
+%D \NC \rlap{\quad\bf grouped} \NC \NC \type {\tx} \NC \type {\txx} \NC \NR
+%D \HL
+%D \NC \type{\tfx} \NC \tfx \FontState \NC \tfx \tx \FontState \NC \tfx \txx \FontState \NC \NR
+%D \NC \type{\tfxx} \NC \tfxx \FontState \NC \tfxx\tx \FontState \NC \tfxx\txx \FontState \NC \NR
+%D \NC \type{\tf} \NC \tf \FontState \NC \tf \tx \FontState \NC \tf \txx \FontState \NC \NR
+%D \NC \type{\tfa} \NC \tfa \FontState \NC \tfa \tx \FontState \NC \tfa \txx \FontState \NC \NR
+%D \NC \type{\tfb} \NC \tfb \FontState \NC \tfb \tx \FontState \NC \tfb \txx \FontState \NC \NR
+%D \NC \type{\tfc} \NC \tfc \FontState \NC \tfc \tx \FontState \NC \tfc \txx \FontState \NC \NR
+%D \NC \type{\tfd} \NC \tfd \FontState \NC \tfd \tx \FontState \NC \tfd \txx \FontState \NC \NR
+%D \NC \type{\tfx} \NC \tfx \FontState \NC \tfx \tx \FontState \NC \tfx \txx \FontState \NC \NR
+%D \NC \type{\tfxx} \NC \tfxx \FontState \NC \tfxx\tx \FontState \NC \tfxx\txx \FontState \NC \NR
+%D \HL
+%D \stoptabulate
+%D
+%D \blank
+%D
+%D \starttabulate[|||||]
+%D \HL
+%D \NC \rlap{\quad\bf stacked} \NC \NC \type {\tx} \NC \type {\txx} \NC \NR
+%D \HL
+%D \NC \type{\tfx}
+%D \NC \tfx \FontState
+%D \NC \tfx \tx \FontState
+%D \NC \tfx \txx \FontState
+%D \NC \NR
+%D \NC \type{\tfxx}
+%D \NC \tfx\tfxx \FontState
+%D \NC \tfx\tfxx \tx \FontState
+%D \NC \tfx\tfxx \txx \FontState
+%D \NC \NR
+%D \NC \type{\tf}
+%D \NC \tfx\tfxx\tf \FontState
+%D \NC \tfx\tfxx\tf \tx \FontState
+%D \NC \tfx\tfxx\tf \txx \FontState
+%D \NC \NR
+%D \NC \type{\tfa}
+%D \NC \tfx\tfxx\tf\tfa \FontState
+%D \NC \tfx\tfxx\tf\tfa \tx \FontState
+%D \NC \tfx\tfxx\tf\tfa \txx \FontState
+%D \NC \NR
+%D \NC \type{\tfb}
+%D \NC \tfx\tfxx\tf\tfa\tfb \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb \tx \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb \txx \FontState
+%D \NC \NR
+%D \NC \type{\tfc}
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc \tx \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc \txx \FontState
+%D \NC \NR
+%D \NC \type{\tfd}
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfd \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfd \tx \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfd \txx \FontState
+%D \NC \NR
+%D \NC \type{\tfx}
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc\tfx \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc\tfx \tx \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc\tfx \txx \FontState
+%D \NC \NR
+%D \NC \type{\tfxx}
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc\tfx\tfxx \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc\tfx\tfxx \tx \FontState
+%D \NC \tfx\tfxx\tf\tfa\tfb\tfc\tfx\tfxx \txx \FontState
+%D \NC \NR
+%D \HL
+%D \stoptabulate
+
+\fontslantperpoint \nullfont 0\scaledpoint
+\fontinterwordspace \nullfont 256377\scaledpoint
+\fontinterwordstretch\nullfont 128188\scaledpoint
+\fontinterwordshrink \nullfont 85459\scaledpoint
+\fontexheight \nullfont 338952\scaledpoint
+\fontemwidth \nullfont 786432\scaledpoint
+\fontextraspace \nullfont 85459\scaledpoint
+
+\appendtoks
+ \fontslantperpoint \nullfont 0\scaledpoint
+ \fontinterwordspace \nullfont 256377\scaledpoint
+ \fontinterwordstretch\nullfont 128188\scaledpoint
+ \fontinterwordshrink \nullfont 85459\scaledpoint
+ \fontexheight \nullfont 338952\scaledpoint
+ \fontemwidth \nullfont 786432\scaledpoint
+ \fontextraspace \nullfont 85459\scaledpoint
+\to \everyjob
+
+%D Tracing
+
+\newtoks\t_font_tracers_definitions
+
+\unexpanded\def\tracefontdefinitions
+ {\the\t_font_tracers_definitions}
+
+%D Some housekeeping macros:
+
+\unexpanded\def\setfontparameters
+ {\setfalse\c_font_synchronize
+ \the\everybodyfont
+ \settrue\c_font_synchronize}
+
+\let\savedfont\empty
+
+\installmacrostack\savedfont
+
+\unexpanded\def\savefont
+ {\edef\savedfont{\the\font}% gives \csname
+ \push_macro_savedfont}
+
+\unexpanded\def\restorefont
+ {\pop_macro_savedfont
+ \savedfont}
+
+\unexpanded\def\pushcurrentfont
+ {\edef\popcurrentfont
+ {\def\noexpand\fontbody {\fontbody}%
+ \def\noexpand\fontstyle {\fontstyle}%
+ \def\noexpand\fontalternative{\fontalternative}%
+ \def\noexpand\fontsize {\fontsize}%
+ \font_helpers_check_big_math_synchronization
+ \font_helpers_synchronize_font}}
+
+%D \macros{definedfont}
+
+\let\thedefinedfont\relax % not to be confused with \everydefinefont
+
+\unexpanded\def\definedfont
+ {\doifelsenextoptionalcs\font_basics_defined_font_yes\font_basics_defined_font_nop}
+
+\def\font_basics_defined_font_yes[#specification]%
+ {\c_font_feature_inheritance_mode\c_font_feature_inheritance_fontonly
+ \font_basics_define_font_without_parameters{thedefinedfont}{#specification}%
+ \thedefinedfont
+ \the\everydefinedfont}
+
+\def\font_basics_defined_font_nop
+ {\c_font_feature_inheritance_mode\c_font_feature_inheritance_fontonly
+ \thedefinedfont
+ \the\everydefinedfont}
+
+%D \macros{startfont}
+
+\unexpanded\def\startfont{\begingroup\definedfont}
+\unexpanded\def\stopfont {\endgroup}
+
+%D \macros
+%D {everybodyfont,everyglobalbodyfont}
+%D
+%D Every change in bodyfont size has conseqences for the baseline distance and skips
+%D between paragraphs. These are initialized in other modules. Here we only provide
+%D the hooks that garantees their handling.
+%D
+%D At the system level one can initialize thing like:
+%D
+%D \starttyping
+%D \appendtoks \setupspacing \to \everybodyfont
+%D \stoptyping
+
+%D \macros
+%D {globalbodyfontsize,localbodyfontsize,bodyfontsize}
+%D
+%D Here we have to distinguish between the global (overal) bodyfont size and the
+%D local (sometimes in the textflow) size. We store these dimensions in two
+%D \DIMENSION\ registers. These registers are not to be misused in calculations.
+
+\ifdefined\globalbodyfontsize\else \newdimen\globalbodyfontsize \fi \globalbodyfontsize=12pt
+\ifdefined\localbodyfontsize \else \newdimen\localbodyfontsize \fi \localbodyfontsize =\globalbodyfontsize
+\ifdefined\bodyfontsize \else \newdimen\bodyfontsize \fi \bodyfontsize =\globalbodyfontsize
+
+%D When we assign for instance 12pt to a \DIMENSION\ register the \type {\the}'d
+%D value comes out as 12.0pt, which is often not the way users specify the bodyfont
+%D size. Therefore we use normalized values. They are cached to save overhead in
+%D \LUA\ calls.
+
+\installcorenamespace{fontnormalizedbody}
+
+\def\normalizebodyfontsize#macro#body%
+ {\expandafter\let\expandafter#macro\csname\??fontnormalizedbody\number\dimexpr#body\endcsname
+ \ifx#macro\relax
+ \normalizebodyfontsize_indeed#macro{#body}%
+ \fi}
+
+\def\normalizebodyfontsize_indeed#macro#body%
+ {\edef#macro{\clf_nbfs\dimexpr#body\relax}%
+ \expandafter\glet\csname\??fontnormalizedbody\number\dimexpr#body\endcsname#macro}
+
+\def\thenormalizedbodyfontsize#body%
+ {\clf_nbfs\dimexpr#body\relax}
+
+\edef\normalizedglobalbodyfontsize{\thenormalizedbodyfontsize\bodyfontsize}
+\edef\normalizedlocalbodyfontsize {\thenormalizedbodyfontsize\bodyfontsize}
+\edef\normalizedbodyfontsize {\thenormalizedbodyfontsize\bodyfontsize}
+
+%D \macros
+%D {mapfontsize}
+%D
+%D For special purposes, like in math, you may want to use slightly different sizes
+%D than the ones given. This happens for instance with the Math Times fonts. Mapped
+%D font sizes can be specified by using the \type {mo} key instead of \type {sa} in
+%D font definitions.
+%D
+%D \startbuffer
+%D \mapfontsize[10pt][11pt]
+%D \mapfontsize[11pt][12pt]
+%D \mapfontsize[12pt][13pt]
+%D
+%D \definefont[test][Serif]\test TEST \par
+%D \definefont[test][Serif sa 5]\test TEST \par
+%D \definefont[test][Serif mo 5]\test TEST \par
+%D \definefont[test][Serif sa d]\test TEST \par
+%D \definefont[test][Serif at 60pt]\test TEST \par
+%D \definefont[test][Serif scaled 6000]\test TEST \par
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startpacked
+%D \getbuffer
+%D \stoppacked
+
+\installcorenamespace{mappedfontsize}
+
+\unexpanded\def\mapfontsize
+ {\dodoubleargument\font_basics_map_fontsize}
+
+\def\font_basics_map_fontsize[#from][#to]%
+ {\setvalue{\??mappedfontsize\the\dimexpr#from\relax}{#to}}
+
+\def\font_basics_set_mapped_fontsize#from%
+ {\ifcsname\??mappedfontsize\the\dimexpr#from\relax\endcsname
+ \lastnamedcs\else#from%
+ \fi}
+
+\installcorenamespace{fontbodyknown}
+\installcorenamespace{fontclassyes} % fontclass
+\installcorenamespace{fontclassnop} % nofontclass
+
+\def\font_helpers_process_relative_size_list#command% could be a toks
+ {#command\v!big
+ #command\v!small}
+
+\let\v_font_size_relative \plusone
+\def\v_font_size_absolute {\fontbody}
+
+\let\v_font_rscale_default\!!plusone
+\let\p_font_rscale \v_font_rscale_default
+
+\def\font_helpers_check_relative_font_id % can be plugged in later
+ {\let\p_font_rscale\minusone
+ \let\p_font_rscale\v_font_rscale_default}
+
+\def\font_helpers_check_relative_font_size#style%
+ {\edef\p_font_rscale
+ {\ifcsname\??fontclass\fontclass#style\s!rscale\endcsname
+ \lastnamedcs
+ \orelse\ifcsname\??fontclass\defaultfontclass#style\s!rscale\endcsname % brr
+ \lastnamedcs
+ \else
+ \v_font_rscale_default
+ \fi}%
+ % move elsewhere
+ \ifx\p_font_rscale\v!auto
+ \let\p_font_rscale\plusone
+ \font_helpers_check_relative_font_id
+ \else
+ \let\relativefontid\minusone
+ \fi}
+
+\def\font_rscale_xx#style%
+ {\ifcsname\??fontclass\fontclass#style\s!rscale\endcsname
+ \lastnamedcs
+ \else
+ \v_font_rscale_default
+ \fi}
+
+\def\font_rscale_mm
+ {\ifcsname\??fontclass\fontclass\s!mm\s!rscale\endcsname
+ \lastnamedcs
+ \else
+ \v_font_rscale_default
+ \fi}
+
+\def\font_helpers_register_fontbody#body%
+ {\expandafter\let\csname\??fontbodyknown#body\endcsname\empty}
+
+%D \macros
+%D {definefontstyle,definefontsize,definefontalternative}
+%D
+%D When setting of switching the overall style we can use the short identifier like
+%D rm and ss, but when defined we can also use more verbose names like roman or
+%D sansserif. Such names are defined by:
+%D
+%D \starttyping
+%D \definefontstyle [serif,rm] [rm]
+%D \definefontstyle [sansserif,ss] [ss]
+%D \stoptyping
+
+\installcorenamespace{fontstyle} % full style prefix (roman etc)
+\installcorenamespace{fontshortstyle} % short style prefix (rm etc)
+
+\installcorenamespace{fontstyleknown}
+\installcorenamespace{fontalternativeknown}
+\installcorenamespace{fontsizeknown}
+
+\newtoks\t_font_style_commands
+\newtoks\t_font_size_commands
+\newtoks\t_font_alternative_commands
+
+\setnewmacro\m_font_style_command \gobbleoneargument
+\setnewmacro\m_font_size_command \gobbleoneargument
+\setnewmacro\m_font_alternative_command\gobbleoneargument
+
+\def\font_helpers_process_style_list #command{\def\m_font_style_command {#command}\the\t_font_style_commands}
+\def\font_helpers_process_size_list #command{\def\m_font_size_command {#command}\the\t_font_size_commands}
+\def\font_helpers_process_alternative_list#command{\def\m_font_alternative_command{#command}\the\t_font_alternative_commands}
+
+\def\font_helpers_register_style #style{\expandafter\let\csname\??fontstyleknown #style\endcsname\empty}
+\def\font_helpers_register_size #size{\expandafter\let\csname\??fontsizeknown #size\endcsname\empty}
+\def\font_helpers_register_alternative#alternative{\expandafter\let\csname\??fontalternativeknown#alternative\endcsname\empty}
+
+\unexpanded\def\definefontstyle
+ {\dodoubleargument\font_basics_define_fontstyle}
+
+\def\font_basics_define_fontstyle[#commands][#style]% style: rm ss tt ...
+ {\ifcsname\??fontstyleknown#style\endcsname \else % can be delayed till used (cg, hw)
+ \font_helpers_register_style{#style}%
+ \toksapp\t_font_style_commands{\m_font_style_command{#style}}%
+ \fi
+ \processcommalist[#commands]{\font_basics_define_fontstyle_indeed{#style}}}
+
+\def\font_basics_define_fontstyle_indeed#style#command%
+ {\setvalue{\??fontshortstyle#command}{#style}%
+ \setvalue{\??fontstyle #command}{\csname#style\endcsname}}
+
+\unexpanded\def\definefontsize[#size]%
+ {\ifcsname\??fontsizeknown#size\endcsname \else
+ \font_helpers_register_size{#size}%
+ \toksapp\t_font_size_commands{\m_font_size_command{#size}}%
+ \fi
+ \font_helpers_check_fontname_combinations}
+
+\unexpanded\def\definefontalternative[#alternative]%
+ {\ifcsname\??fontalternativeknown#alternative\endcsname \else
+ \font_helpers_register_alternative{#alternative}%
+ \toksapp\t_font_alternative_commands{\m_font_alternative_command{#alternative}}%
+ \fi
+ \font_helpers_check_fontname_combinations}
+
+\unexpanded\def\font_helpers_check_fontname_combinations % we need to split math and text here ... todo (math only has mr and mb)
+ {\font_helpers_process_style_list\font_helpers_check_fontname_combinations_s}
+
+\def\font_helpers_check_fontname_combinations_s#style%
+ {\font_helpers_process_alternative_list{\font_helpers_check_fontname_combinations_indeed_s_a{#style}}}
+
+\def\font_helpers_check_fontname_combinations_indeed_s_a#style#alternative%
+ {\font_helpers_process_size_list{\font_basics_check_fontname_combination{#style}{#alternative}}}
+
+\definefontstyle [\s!mm] [\s!mm]
+\definefontstyle [\s!rm] [\s!rm]
+\definefontstyle [\s!ss] [\s!ss]
+\definefontstyle [\s!tt] [\s!tt]
+
+%D We define all the font switching commands globally. After all they are part of
+%D the formal font interface once defined. The size can be empty (so checking is
+%D needed as \type {\bf} is already defined).
+%D
+%D The \type {\normal..} variants are available as extras for cases where the \type
+%D {..} is overloaded.
+
+\newmacro\m_font_mm
+
+\def\font_basics_check_fontname_combination#style% alternative size
+ {\edef\m_font_mm{#style}%
+ \ifx\m_font_mm\s!mm % prevents \max and alike (re)defs
+ \expandafter\font_basics_check_math_bodyfont
+ \else
+ \expandafter\font_basics_check_text_bodyfont
+ \fi{#style}} % no \m_font_mm, not expanded later on
+
+\def\font_basics_check_math_bodyfont#style#alternative#size%
+ {}
+
+\def\font_basics_check_text_bodyfont_step#whatever#body% size can be empty (checking needed as \bf is already defined)
+ {\ifcsname#whatever\endcsname\else
+ \setugvalue{#whatever}{#body}%
+ \fi}
+
+\def\font_basics_check_text_bodyfont#style#alternative#size% size can be empty (checking needed as \bf is already defined)
+ {\font_basics_check_text_bodyfont_step{#style#size}{\font_helpers_set_current_font_style_size{#style}{#size}}% \rma
+ \font_basics_check_text_bodyfont_step{#alternative#size}{\font_helpers_set_current_font_alternative_size{#alternative}{#size}}% \sla
+ \font_basics_check_text_bodyfont_step{#style#alternative#size}{\font_helpers_set_current_font_style_alternative_size{#style}{#alternative}{#size}}% \rmsla
+ \font_basics_check_text_bodyfont_step{#style}{\font_helpers_set_current_font_style{#style}}% \rm
+ \font_basics_check_text_bodyfont_step{#alternative}{\font_helpers_set_current_font_alternative{#alternative}}% \sl
+ \font_basics_check_text_bodyfont_step{#style\s!x }{\font_helpers_set_current_font_x_style_alternative{#style}}% \rmx
+ \font_basics_check_text_bodyfont_step{#style\s!xx}{\font_helpers_set_current_font_xx_style_alternative{#style}}% \rmxx
+ \font_basics_check_text_bodyfont_step{#alternative\s!x }{\font_helpers_set_current_font_x_alternative{#alternative}}% \slx
+ \font_basics_check_text_bodyfont_step{#alternative\s!xx}{\font_helpers_set_current_font_xx_alternative{#alternative}}% \slxx
+ \font_basics_check_text_bodyfont_step{#style#alternative}{\font_helpers_set_current_font_style_alternative{#style}{#alternative}}}% \rmsl
+
+%D Scaling macros:
+%D
+%D This system is somewhat complicated by two (possible conflicting) demands:
+%D
+%D \startitemize
+%D \item We support wildcards like \type {sa *} which will adapt to the current
+%D size. This is also the default specification.
+%D \item We support named scales like \type {sa d}; beware: \type {x} and \type {xx}
+%D are valid scales but they are not alway the same as the ones used in for
+%D instance \type {\bfx} because there the sized come from the bodyfont
+%D environment. In the future there maybe a switch that also honors the
+%D environment in named scales.
+%D \stopitemize
+%D
+%D Keep in mind that the smaller sizes are just for text super and subscripts while
+%D larger sizes can be used in titles where for instance math follows the size.
+
+% b:x{\definedfont[SerifBold sa b]x}{\bfb x $x^x$}\par
+% 1:x{\definedfont[SerifBold sa 1]x}{\bf x $x^x$}\par
+% x:x{\definedfont[SerifBold sa x]x}{\bfx x $x^x$}\par
+% xx:x{\definedfont[SerifBold sa xx]x}{\bfxx x $x^x$}\par
+%
+% *:x{\definedfont[Serif sa *]x}\par
+% 1:x{\definedfont[Serif sa 1]x}\par
+% 2:x{\definedfont[Serif sa 2]x}\par
+% 3:x{\definedfont[Serif sa 3]x}\par
+% 4:x{\definedfont[Serif sa 4]x}\par
+% 5:x{\definedfont[Serif sa 5]x}\par
+
+\def\safontscale{\number\dimexpr\v_font_size_absolute\relax}
+\def\mofontscale{\number\dimexpr\font_basics_set_mapped_fontsize\v_font_size_absolute\relax}
+
+\let\somefontname\s!unknown
+\let\somefontspec\s!unknown
+\let\somefontsize\zerocount
+
+\newcount\scaledfontmode % also used at the lua end
+\newcount\scaledfontsize % also used at the lua end
+\newcount\lastfontid % also used at the lua end / tex end
+\newtoks \everydefinefont
+
+\let\relativefontid\minusone % todo, not yet used
+
+\let\c_font_feature_inheritance_fontnone \zerocount % none
+\let\c_font_feature_inheritance_fontonly \plusone % fontonly
+\let\c_font_feature_inheritance_classonly \plustwo % classonly
+\let\c_font_feature_inheritance_fontfirst \plusthree % fontfirst
+\let\c_font_feature_inheritance_classfirst\plusfour % classfirst
+
+\let\c_font_feature_inheritance_default \c_font_feature_inheritance_fontfirst
+
+\setnewconstant\c_font_feature_inheritance_mode \c_font_feature_inheritance_default
+
+\newdimen \d_font_scaled_text_face
+\newdimen \d_font_scaled_font_size
+\newconditional\c_font_body_scale
+\newfraction \f_font_body_scale
+
+\unexpanded\def\font_helpers_low_level_define#specification#csname%
+ {% we can now set more at the lua end
+ \glet\somefontname\defaultfontfile
+ \let\somefontsize\empty
+ \clf_definefont_one{\detokenize\expandafter{\normalexpanded{#specification}}}% the escapestring catches at \somedimen
+ % sets \scaledfontmode and \somefontname and \somefontsize
+ \ifcase\fontface\relax
+ % \let\v_font_size_absolute\textface % fontbody
+ \or
+ \let\v_font_size_absolute\textface
+ \or
+ \let\v_font_size_absolute\scriptface
+ \or
+ \let\v_font_size_absolute\scriptscriptface
+ \or
+ \let\v_font_size_absolute\xtextface
+ \or
+ \let\v_font_size_absolute\xxtextface
+ \fi
+ %
+ \ifcase\scaledfontmode\relax
+ % none, avoid the designsize if possible
+ \d_font_scaled_font_size-\plusthousand\scaledpoint
+ \or
+ % at
+ \d_font_scaled_font_size\somefontsize
+ \or
+ % sa
+ \d_font_scaled_font_size\v_font_size_absolute\relax
+ \d_font_scaled_font_size\currentfontbodysize\d_font_scaled_font_size % uses \somefontsize set by lua
+ \or
+ % mo
+ \d_font_scaled_font_size\font_basics_set_mapped_fontsize\v_font_size_absolute
+ \d_font_scaled_font_size\currentfontbodysize\d_font_scaled_font_size
+ \or
+ % scaled, don't use this one as it's unpredictable
+ \d_font_scaled_font_size-\somefontsize\scaledpoint
+ \else % ht cp
+ % experiment, yet undocumented
+ \d_font_scaled_font_size\somefontsize
+ \fi
+ \relax
+ \d_font_scaled_font_size\v_font_size_relative\d_font_scaled_font_size
+ \ifconditional\c_font_auto_size
+ \font_helpers_check_body_scale\fontsize
+ \ifconditional\c_font_body_scale
+ \d_font_scaled_font_size\f_font_body_scale\d_font_scaled_font_size
+ \d_font_scaled_text_face\f_font_body_scale\dimexpr\textface\relax
+ \else
+ \d_font_scaled_font_size\f_font_body_scale
+ \d_font_scaled_text_face\textface
+ \fi
+ \else
+ \d_font_scaled_text_face\textface
+ \fi
+ \edef\somefontspec{at \number\d_font_scaled_font_size sp}%
+ \edef\somefontfile{\truefontname\somefontname}%
+ \ifx\somefontfile\s!unknown
+ \edef\somefontfile{\defaultfontfile}%
+ \fi
+ \font_helpers_update_font_parameters
+ \font_helpers_update_font_class_parameters
+ %\writestatus{fonts}{low level define: #csname/\somefontfile/\number\d_font_scaled_font_size/\fontface/\number\d_font_scaled_text_face}%
+ \clf_definefont_two
+ \ifx\fontclass\empty\s!false\else\s!true\fi
+ {#csname}%
+ {\somefontfile}%
+ \d_font_scaled_font_size
+ \c_font_feature_inheritance_mode
+ {\m_font_class_features}%
+ {\m_font_features}%
+ {\m_font_class_fallbacks}%
+ {\m_font_fallbacks}%
+ \fontface
+ \d_font_scaled_text_face
+ \relativefontid
+ {\m_font_class_goodies}%
+ {\m_font_goodies}%
+ {\m_font_class_designsize}%
+ {\m_font_designsize}%
+ \scaledfontmode
+ \relax
+ \ifcase\scaledfontsize
+ %\scaledfontsize\plusone
+ \let\somefontspec\empty
+ \let\lastrawfontcall\relax
+ \expandafter\let\csname#csname\endcsname\relax
+ \else
+ \edef\somefontspec{at \number\scaledfontsize sp}% we need the resolved designsize (for fallbacks)
+ \expandafter\let\expandafter\lastrawfontcall\csname#csname\endcsname
+ \the\everydefinefont
+ \fi
+ \c_font_feature_inheritance_mode\c_font_feature_inheritance_default}
+
+\def\font_helpers_check_body_scale#fontsize% gets character (x xx a etc)
+ {\ifcsname\??fontenvironments\fontclass\fontbody#fontsize\endcsname
+ \expandafter\let\expandafter\f_font_body_scale\lastnamedcs
+ \setfalse\c_font_body_scale % !
+ \orelse\ifcsname\??fontenvironments\fontclass\s!default#fontsize\endcsname
+ \expandafter\let\expandafter\f_font_body_scale\lastnamedcs
+ \settrue\c_font_body_scale
+ \orelse\ifcsname\??fontenvironments\fontbody#fontsize\endcsname
+ \expandafter\let\expandafter\f_font_body_scale\lastnamedcs
+ \setfalse\c_font_body_scale % !
+ \orelse\ifcsname\??fontenvironments\s!default#fontsize\endcsname
+ \expandafter\let\expandafter\f_font_body_scale\lastnamedcs
+ \settrue\c_font_body_scale
+ \orelse\ifcsname\??fontenvironments\fontclass\s!default\s!text\endcsname
+ \expandafter\let\expandafter\f_font_body_scale\lastnamedcs
+ \settrue\c_font_body_scale
+ \orelse\ifcsname\??fontenvironments\s!default\s!text\endcsname
+ \expandafter\let\expandafter\f_font_body_scale\lastnamedcs
+ \settrue\c_font_body_scale
+ \else
+ \let\f_font_body_scale\plusone
+ \settrue\c_font_body_scale
+ \fi}
+
+%D The following macros are used at the \LUA\ end. Watch the \type {\normal}
+%D hackery: this makes the mkvi parser happy.
+
+% \normaldef\fntsetdefname {\glet\somefontname\defaultfontfile} % do before calling
+% \normaldef\fntsetnopsize {\let\somefontsize\empty} % do before calling
+% \normaldef\fntsetsomename{\normalgdef\somefontname} % takes argument
+% \normaldef\fntsetsomesize{\normaldef\somefontsize} % takes argument
+
+\newif\ifskipfontcharacteristics \skipfontcharacteristicstrue
+
+\tracingfonts\plussix % <id: name @ size>
+
+%D When fontclasses are used, we define the font global, since namespaces are
+%D used. Otherwise we parse the specs each time.
+
+\let\fontfile\s!unknown
+
+%D Relatively new:
+
+\installcorenamespace{fonts}
+\installcorenamespace{fontslanguage}
+
+\installsetuponlycommandhandler \??fonts {fonts}
+
+\newconstant\c_fonts_auto_language
+
+\letvalue{\??fontslanguage\v!auto}\plusone % experimental
+%letvalue{\??fontslanguage\v!yes }\plustwo % less efficient, for experiments
+
+\appendtoks
+ \c_fonts_auto_language
+ \ifcsname\??fontslanguage\fontsparameter\c!language\endcsname
+ \lastnamedcs
+ \else
+ \zerocount
+ \fi
+\to \everysetupfonts
+
+\appendtoks
+ \ifcase\c_fonts_auto_language
+ % nothing
+ \or
+ \addfflanguage
+ % \or
+ % font
+ \fi
+\to \everylanguage
+
+% \setupfonts
+% [\c!language=\v!auto]
+
+%D \macros
+%D {everyfont,everyfontswitch}
+
+\ifdefined\everyfont \else \newtoks\everyfont \fi
+\ifdefined\everyfontswitch \else \newtoks\everyfontswitch \fi
+
+\def\setfontcharacteristics{\the\everyfont}
+
+% \appendtoks
+% \ifcase\c_fonts_auto_language
+% % nothing
+% \or
+% % auto
+% \or
+% \addfflanguage
+% \fi
+% \to \everyfont
+
+%D \macros
+%D {definefont}
+%D
+%D We also accept \type{sa a}||\type{sa d} as specification.
+%D
+%D Before we implement the main definition macro, we first show one for local use:
+%D
+%D \starttyping
+%D \definefont[Some][LucidaBright at 100pt] \Some some
+%D \definefont[More][LucidaBright scaled 3000] \More more
+%D \definefont[Nice][LucidaBright mo 2] \Nice nice
+%D \definefont[Text][LucidaBright sa 5.4] \Text last
+%D \stoptyping
+%D
+%D The implementation looks as follows:
+
+\unexpanded\def\definefont % [name][spec][1.6 | line=10pt | setup_id]
+ {\dotripleempty\font_basics_define_font}
+
+\def\font_basics_define_font
+ {\ifthirdargument
+ \expandafter\font_basics_define_font_a
+ \else
+ \expandafter\font_basics_define_font_b
+ \fi}
+
+\def\font_basics_define_font_a[#name][#specification][#settings]% [name][spec][1.6 | line=10pt | setup_id]
+ {\doifelsesetups{#settings}%
+ {\setuvalue{#name}{\font_basics_define_font_with_setups {#name}{#specification}{#settings}}}
+ {\setuvalue{#name}{\font_basics_define_font_with_parameters{#name}{#specification}{#settings}}}}
+
+\def\font_basics_define_font_b[#name][#specification][#dummy]%
+ {\setuvalue{#name}{\font_basics_define_font_without_parameters{#name}{#specification}}}
+
+\def\font_basics_define_font_with_parameters#name#specification#settings%
+ {\font_basics_define_font_without_parameters{#name}{#specification}%
+ \setuplocalinterlinespace[#settings]%
+ \setupspacing\relax} % is this really needed ?
+
+\def\font_basics_define_font_with_setups#name#specification#settings%
+ {\font_basics_define_font_without_parameters{#name}{#specification}%
+ \setups[#settings]}
+
+%D Beware, in the frozen variants no settings are supported yet, but that might happen
+%D some day.
+
+\unexpanded\def\definefrozenfont
+ {\dotripleempty\font_basics_define_frozen_font}
+
+% \def\font_basics_define_frozen_font[#name][#specification][#settings]%
+% {\begingroup
+% \font_basics_define_font[#name][#specification][#settings]%
+% \csname#name\endcsname
+% \expandafter\expandafter\expandafter\endgroup\expandafter\let\csname#name\endcsname\lastrawfontcall}
+
+\def\font_basics_define_frozen_font[#name][#specification][#settings]%
+ {\begingroup
+ \font_basics_define_font[#name][#specification][#settings]%
+ \csname#name\endcsname
+ \glet\lastglobalrawfontcall\lastrawfontcall
+ \endgroup
+ \expandafter\let\csname#name\endcsname\lastglobalrawfontcall}
+
+%D The instance namespace protection makes the switch local so that we can redefine a
+%D logical name and/or change the size in between.
+
+% todo: now mathsize twice in name (so it can go here)
+% todo: check when mathsize is needed
+
+\ifdefined\??fontinstanceready \else \installcorenamespace{fontinstanceready} \fi
+\ifdefined\??fontinstancebasic \else \installcorenamespace{fontinstancebasic} \fi
+\ifdefined\??fontinstanceclass \else \installcorenamespace{fontinstanceclass} \fi
+
+\newconditional\c_font_auto_size \settrue\c_font_auto_size
+
+\let\lastfontidentifier\empty
+
+\def\v_font_identifier_basic{\??fontinstancebasic \lastfontidentifier-\fontsize-\fontface}
+\def\v_font_identifier_class{\??fontinstanceclass\fontclass-\lastfontidentifier-\fontsize-\fontface}
+
+\let\v_font_identifier_basic_saved\v_font_identifier_basic
+\let\v_font_identifier_class_saved\v_font_identifier_class
+
+% \def\v_font_identifier_class{\??fontinstanceclass\fontclass-\lastfontidentifier-\fontstyle-\fontsize} % no \fontface
+
+\def\font_basics_define_font_without_parameters#identifier#2%
+ {\c_font_feature_inheritance_mode\c_font_feature_inheritance_fontonly
+ \edef\lastfontidentifier{#identifier}%
+ \let\v_font_size_relative\v_font_rscale_default
+ \let\v_font_size_absolute\fontbody
+ \font_helpers_low_level_define{#2}\v_font_identifier_basic
+ \csname\v_font_identifier_basic\endcsname
+ \setfalse\c_font_auto_size
+ \setfontcharacteristics
+ \the\everyfontswitch
+ \let\v_font_identifier_basic\v_font_identifier_basic_saved}
+
+\unexpanded\def\font_helpers_trigger#identifier% make a traced variant
+ {\edef\lastfontidentifier{#identifier}%
+ \ifcsname\v_font_identifier_class\endcsname
+ % \writestatus{fonts}{trigger: reusing \v_font_identifier_class}%
+ \expandafter\font_helpers_trigger_reuse
+ \else
+ % \writestatus{fonts}{trigger: defining \v_font_identifier_class}%
+ \expandafter\font_helpers_trigger_define
+ \fi}
+
+\def\font_helpers_trigger_define#relative#absolute#specification%
+ {\def\v_font_size_relative{#relative}%
+ \def\v_font_size_absolute{#absolute}%
+ \font_helpers_low_level_define{#specification}\v_font_identifier_class
+ \csname\v_font_identifier_class\endcsname
+ \setfalse\c_font_auto_size
+ \ifskipfontcharacteristics \else
+ \setfontcharacteristics
+ \the\everyfontswitch
+ \fi
+ \let\v_font_identifier_class\v_font_identifier_class_saved}
+
+\def\font_helpers_trigger_reuse#relative#absolute#specification%
+ {\csname\v_font_identifier_class\endcsname
+ \setfalse\c_font_auto_size
+ \ifskipfontcharacteristics \else
+ \setfontcharacteristics
+ \the\everyfontswitch
+ \fi
+ \let\v_font_identifier_class\v_font_identifier_class_saved}
+
+%D \macros
+%D {currentfontbodyscale}
+%D
+%D Sometimes we need to have access to the font scale including the \type {a}||\type
+%D {d} sizes. The next macro returns the current scaling factor. Take a look at
+%D \type {cont-log.tex} for an example of its use.
+
+\installcorenamespace{fontenvironments}
+
+\def\currentfontbodysize % gets number (the normal sa 1 etc)
+ {\ifcsname\??fontenvironments\fontclass\s!default\somefontsize\endcsname
+ \lastnamedcs
+ \orelse\ifcsname\??fontenvironments\s!default\somefontsize\endcsname
+ \lastnamedcs
+ \else
+ \somefontsize
+ \fi}
+
+\def\currentfontbodyscale % gets character (x xx a etc)
+ {\csname\??fontenvironments
+ \ifcsname\??fontenvironments\fontclass\s!default\fontsize\endcsname\fontclass\s!default\fontsize\orelse
+ \ifcsname\??fontenvironments \s!default\fontsize\endcsname \s!default\fontsize\orelse
+ \ifcsname\??fontenvironments\fontclass\s!default\s!text \endcsname\fontclass\s!default\s!text \orelse
+ \ifcsname\??fontenvironments \s!default\s!text \endcsname \s!default\s!text \else
+ \s!default \fi
+ \endcsname}
+
+\def\font_currentfontbodyscale % gets character (x xx a etc)
+ {\ifcsname\??fontenvironments\fontclass\s!default\fontsize\endcsname\lastnamedcs\orelse
+ \ifcsname\??fontenvironments \s!default\fontsize\endcsname\lastnamedcs\orelse
+ \ifcsname\??fontenvironments\fontclass\s!default\s!text \endcsname\lastnamedcs\orelse
+ \ifcsname\??fontenvironments \s!default\s!text \endcsname\lastnamedcs\else
+ \csname\??fontenvironments \s!default \endcsname \fi}
+
+\def\currentfontscale % used in default definition
+ {\csname\??fontenvironments
+ \ifcsname\??fontenvironments\fontclass\s!default\xfontsize\endcsname\fontclass\s!default\fontsize\orelse
+ \ifcsname\??fontenvironments \s!default\xfontsize\endcsname \s!default\fontsize\orelse
+ \ifcsname\??fontenvironments\fontclass\s!default\s!text \endcsname\fontclass\s!default\s!text \orelse
+ \ifcsname\??fontenvironments \s!default\s!text \endcsname \s!default\s!text \else
+ \s!default \fi
+ \endcsname}
+
+\def\font_currentfontscale % used in default definition
+ {\ifcsname\??fontenvironments\fontclass\s!default\xfontsize\endcsname\lastnamedcs\orelse
+ \ifcsname\??fontenvironments \s!default\xfontsize\endcsname\lastnamedcs\orelse
+ \ifcsname\??fontenvironments\fontclass\s!default\s!text \endcsname\lastnamedcs\orelse
+ \ifcsname\??fontenvironments \s!default\s!text \endcsname\lastnamedcs\else
+ \csname\??fontenvironments \s!default \endcsname \fi}
+
+\setvalue{\??fontenvironments\s!default}{1}
+
+%D In the following macros we use \type {\currentxfontsize} to hold the current
+%D x||size of the font. This enables us to support for instance \type {\sl} inside a
+%D \type {\tx} switch.
+
+\newconstant\currentxfontsize
+
+\def\xfontsize{\ifcase\currentxfontsize\fontsize\or\s!x\else\s!xx\fi}
+
+%D Now we enter the area of font switching. The switching mechanism has to take care
+%D of several situations, like:
+%D
+%D \startitemize[packed]
+%D \item changing the overal document fonts (including margins, headers and footers)
+%D \item changing local fonts (only the running text)
+%D \item smaller and even more smaller alternatives (super- and subscripts)
+%D \stopitemize
+%D
+%D \TEX\ offers a powerfull family mechanism for super- and subscripts in math mode.
+%D In text mode however, we don't use families for the smaller alternatives, and
+%D therefore have to take care of it otherwise.
+%D
+%D \macros
+%D {definebodyfontenvironment,setupbodyfontenvironment}
+%D
+%D The relationship between the several sizes of a font, is
+%D defined by:
+%D
+%D \showsetup{definebodyfontenvironment}
+%D
+%D Later on we will see how these parameters are used, so for the moment we stick
+%D with an example:
+%D
+%D \starttyping
+%D \definebodyfontenvironment
+%D [12pt]
+%D [ text=12pt,
+%D script=9pt,
+%D scriptscript=7pt,
+%D x=10pt,
+%D xx=8pt,
+%D big=12pt,
+%D small=10pt]
+%D \stoptyping
+%D
+%D The first argument specifies the bodyfont size to which the settings apply. All
+%D second parameters are specified in dimensions and tell us more about related
+%D sizes.
+%D
+%D Afterwards, one can change values with
+%D
+%D \showsetup{setupbodyfontenvironment}
+%D
+%D When instead of a size the keyword \type{unknown} is
+%D passed, fractions (relations) are used instead of fixed
+%D sizes.
+
+%D {\bf Remark:} We need to cover the following cases, otherwise users can get
+%D confused:
+%D
+%D \starttyping
+%D \setupbodyfont[23pt]
+%D
+%D \definebodyfontenvironment[23pt]
+%D \setupbodyfont[23pt]
+%D
+%D \definebodyfontenvironment[23pt]
+%D \definebodyfont[23pt][rm,ss,tt][default]
+%D \setupbodyfont[23pt]
+%D \stoptyping
+%D
+%D Beware: while some font defs can be global, the bodyfont environment checks
+%D local. This means that multiple local checks resulting in definitions are not
+%D that efficient. So, apart from an occasional switch, one should define an
+%D environment at the outer level.
+
+% \definebodyfontenvironment[33pt]
+% \definebodyfontenvironment[dejavu][default][1=.5]
+% \definebodyfontenvironment[dejavu][default][x=1.2]
+% \definebodyfontenvironment[dejavu][default][a=5]
+% \definebodyfontenvironment[dejavu][33pt][x=100pt]
+
+% the lookup order is:
+%
+% [class] [dimension] [parameters]
+% [class] [default] [parameters] % factors
+% [dimension] [parameters]
+% [default] [parameters] % factors
+%
+% with defaults providing factors
+
+% todo: class:size
+% todo: make assignments global
+
+\letvalue\??fontenvironments\empty % so we default to empty
+
+\def\bodyfontvariable#parameter%
+ {\csname\??fontenvironments
+ \ifcsname\??fontenvironments\fontclass\normalizedbodyfontsize#parameter\endcsname\fontclass\normalizedbodyfontsize#parameter\orelse
+ \ifcsname\??fontenvironments\fontclass #parameter\endcsname\fontclass #parameter\orelse
+ \ifcsname\??fontenvironments \normalizedbodyfontsize#parameter\endcsname \normalizedbodyfontsize#parameter\orelse
+ \ifcsname\??fontenvironments\s!default #parameter\endcsname\s!default #parameter\fi
+ \endcsname}
+
+\def\font_bodyfontvariable#parameter%
+ {\ifcsname\??fontenvironments\fontclass\normalizedbodyfontsize#parameter\endcsname\lastnamedcs\orelse
+ \ifcsname\??fontenvironments\fontclass #parameter\endcsname\lastnamedcs\orelse
+ \ifcsname\??fontenvironments \normalizedbodyfontsize#parameter\endcsname\lastnamedcs\orelse
+ \ifcsname\??fontenvironments\s!default #parameter\endcsname\lastnamedcs\fi}
+
+\def\bodyfontsizevariable#size#parameter%
+ {\csname\??fontenvironments
+ \ifcsname\??fontenvironments\fontclass#size#parameter\endcsname\fontclass#size#parameter\orelse
+ \ifcsname\??fontenvironments\fontclass #parameter\endcsname\fontclass #parameter\orelse
+ \ifcsname\??fontenvironments #size#parameter\endcsname #size#parameter\orelse
+ \ifcsname\??fontenvironments\s!default #parameter\endcsname\s!default #parameter\fi
+ \endcsname}
+
+\def\font_bodyfontsizevariable#size#parameter%
+ {\ifcsname\??fontenvironments\fontclass#size#parameter\endcsname\lastnamedcs\orelse
+ \ifcsname\??fontenvironments\fontclass #parameter\endcsname\lastnamedcs\orelse
+ \ifcsname\??fontenvironments #size#parameter\endcsname\lastnamedcs\orelse
+ \ifcsname\??fontenvironments\s!default #parameter\endcsname\lastnamedcs\fi}
+
+\def\bodyfontinterlinespace{\bodyfontvariable\c!interlinespace} % used elsewhere
+
+\def\bodyfontdimension#class#size#parameter#body%
+ {\the\dimexpr
+ \ifcsname\??fontenvironments #class#size#parameter\endcsname \lastnamedcs \orelse
+ \ifcsname\??fontenvironments#class\s!default#parameter\endcsname \lastnamedcs\dimexpr#body\relax\orelse % factor
+ \ifcsname\??fontenvironments #size#parameter\endcsname \lastnamedcs \else
+ \lastnamedcs\dimexpr#body\relax\fi % factor
+ \relax}
+
+\unexpanded\def\definebodyfontenvironment
+ {\dotripleempty\font_basics_define_body_font_environment}
+
+\let\setupbodyfontenvironment\definebodyfontenvironment
+
+\installcorenamespace{fontenvironmentknown}
+
+\def\font_helpers_register_environment#class#body%
+ {\expandafter\let\csname\??fontenvironmentknown#class#body\endcsname\empty}
+
+\newmacro\m_font_body
+\newmacro\m_font_body_normalized
+
+\def\font_basics_define_body_font_environment
+ {\ifthirdargument
+ \singleexpandafter\font_basics_define_body_font_environment_class
+ \orelse\ifsecondargument
+ \expandafter\font_basics_define_body_font_environment_empty
+ \else
+ \expandafter\font_basics_define_body_font_environment_unset
+ \fi}
+
+%D First we handle the class specific case. Beware: you can change values before
+%D a bodyfont is loaded but changing them afterwards can be sort of tricky as
+%D values are not consulted afterwards.
+
+\def\processbodyfontenvironmentlist#1% no \unexpanded as then we cannot use it in alignments
+ {\clf_processbodyfontsizes{\strippedcsname#1}}
+
+\def\bodyfontenvironmentlist
+ {\clf_getbodyfontsizes}
+
+\def\font_basics_define_body_font_environment_class[#class][#body][#settings]%
+ {\edef\m_font_body{#body}%
+ \ifx\m_font_body\s!default
+ % these are the last resort within a class
+ \getrawparameters[\??fontenvironments#class\s!default][#settings]%
+ \else
+ \normalizebodyfontsize\m_font_body_normalized\m_font_body
+ \font_basics_define_body_font_environment_size[#class][\m_font_body_normalized][#settings]%
+ \clf_registerbodyfontsize{\m_font_body_normalized}%
+ \fi}
+
+%D The empty case uses the same code but needs to ignore the current class settings
+%D (just to be sure, as it's not really needed).
+
+\def\font_basics_define_body_font_environment_empty[#body][#settings][#dummy]%
+ {\push_macro_fontclass
+ \let\fontclass\empty
+ \font_basics_define_body_font_environment_class[][#body][#settings]%
+ \pop_macro_fontclass}
+
+\def\font_basics_define_body_font_environment_unset[#body][#dummya][#dummyb]%
+ {\push_macro_fontclass
+ \let\fontclass\empty
+ \font_basics_define_body_font_environment_class[][#body][]%
+ \pop_macro_fontclass}
+
+%D We don't check too soon as we can refer to later definitions.
+
+\newconditional\c_font_defining_environment_state % controls messages
+
+\def\font_basics_define_body_font_environment_size[#class][#normalizedbody][#settings]% normalized body
+ {\getrawparameters[\??fontenvironments#class#normalizedbody][#settings]%
+ \ifcsname\??fontenvironmentknown#class#normalizedbody\endcsname
+ % environment and size already defined
+ \orelse\ifproductionrun
+ \push_macro_fontclass
+ \edef\fontclass{#class}%
+ \font_helpers_register_environment{#class}{#normalizedbody}%
+ \settrue\c_font_defining_environment_state
+ \font_helpers_define_unknown_font{#normalizedbody}% current class
+ \setfalse\c_font_defining_environment_state
+ \pop_macro_fontclass
+ \fi
+ \font_helpers_register_fontbody{#normalizedbody}}
+
+%D Checking
+
+\def\font_helpers_check_bodyfont_environment#normalizedbody#body%
+ {\ifcsname\??fontenvironmentknown\fontclass#normalizedbody\endcsname
+ % already defined
+ \else
+ \font_helpers_check_bodyfont_environment_indeed{#normalizedbody}{#body}%
+ \fi}
+
+\def\font_helpers_check_bodyfont_environment_indeed#normalizedbody#body%
+ {\font_helpers_register_environment\fontclass{#normalizedbody}%
+ \ifcsname\??fontbodyknown#normalizedbody\endcsname
+ \else
+ \font_helpers_define_unknown_font{#normalizedbody}%
+ \fi}
+
+%D We default all parameters to the main bodyfont size, so the next setup is valid
+%D too:
+%D
+%D \starttyping
+%D \definebodyfontenvironment[24pt]
+%D \stoptyping
+%D
+%D All parameters can be redefined when needed, so one doesnot have to stick to the
+%D default ones.
+
+%D \macros
+%D {definebodyfont}
+%D
+%D The next step in defining a bodyfont involves the actual font files, which can be
+%D recognized by their extension \type {tfm}. Installing those file is often beyond
+%D the scope of the user and up to the system administrator.
+%D
+%D \showsetup{definebodyfont}
+%D
+%D This commands takes three arguments: a (series of) bodyfont size(s), the style
+%D group to which the definitions belong, and an alternative, as specified by the
+%D \TEX\ (math) families, extended with~a, b~\unknown.
+%D
+%D We show two examples, that show all the alternative scaling options. The \type
+%D {\tfa} alternatives can be extended with \type {\bfa}, \type {\slb}, etc. or even
+%D \type {e} and higher alternatives. The magic scaled values are derived from plain
+%D \TEX's \type {\magstep}:
+%D
+%D \starttyping
+%D \definebodyfont [12pt] [rm]
+%D [tf=cmr12,
+%D bf=cmbx12,
+%D it=cmti12,
+%D sl=cmsl12,
+%D bi=cmbxti10 at 12pt,
+%D bs=cmbxsl10 at 12pt,
+%D tfa=cmr12 scaled 1.200,
+%D tfb=cmr12 scaled 1.440,
+%D tfc=cmr12 scaled 1.728,
+%D tfd=cmr12 scaled 2.074,
+%D sc=cmcsc10 at 12pt]
+%D
+%D \definebodyfont [12pt,11pt,10pt,9pt,8pt] [rm]
+%D [tf=lbr sa 1,
+%D bf=lbd sa 1,
+%D it=lbi sa 1,
+%D sl=lbsl sa 1,
+%D bi=lbdi sa 1,
+%D bs=lbdi sa 1,
+%D tfa=lbr sa 1.200,
+%D tfb=lbr sa 1.440,
+%D tfc=lbr sa 1.728,
+%D tfd=lbr sa 2.074,
+%D sc=lbr sa 0.833]
+%D \stoptyping
+%D
+%D The second example shows that we can define more sizes at once. The main
+%D difference between these examples is that the Computer Modern Roman come in many
+%D design sizes. This means that there we cannot define them in bulk using \type
+%D {sa}. Instead of \type {rm} (roman) one can define \type {ss} (sans serif), \type
+%D {tt} (teletype), \type {hw} (hand written), \type {cg} (calygraphic) and whatever
+%D styles.
+%D
+%D The first argument may be a comma separated list. This, combined with
+%D specifications using \type{sa} can save a lot of typing. Although all arguments
+%D should be specified, we treat the second argument as optional.
+%D
+%D Defining a bodyfont involves two actions: defining the specific style related
+%D alternatives, like \type {\rma}, \type {\bfa} and \type {\rmsla}, and storing the
+%D definitions of their bodyfont size related fonts. The first step is bodyfont
+%D independant but executed every time. This permits user definitions like \type
+%D {\tfw} or \type {\bfq} for real large alternatives.
+%D
+%D If we move design size info to the lfg file (after all only lm has design sizes)
+%D we can get rid of much code .. 2012 or so.
+
+\installcorenamespace{fontdefinitions}
+
+% [class] [name] [rm,ss] [settings]
+% [class] [10pt,11pt] [rm,ss] [settings]
+% [class] [10pt,11pt] [rm,ss] [name]
+
+% [class] [name] [settings] == [name] [rm] [settings]
+% [class] [10pt,11pt] [settings] == [name] [rm] [settings]
+% [class] [10pt,11pt] [name] == [10pt,11pt] [rm] [name]
+
+\unexpanded\def\definebodyfont
+ {\doquadrupleempty\font_basics_define_body_font}
+
+\def\font_basics_define_body_font[#1][#2][#3][#4]%
+ {\iffourthargument
+ \processcommacommand[#1]{\font_basics_define_body_font_class_given[#2][#3][#4]}%
+ \else
+ \font_basics_define_body_font_class_known[#1][#2][#3]%
+ \fi}
+
+\def\font_basics_define_body_font_class_given[#1][#2][#3]#4%
+ {\push_macro_fontclass
+ \doifelse{#4}\s!default
+ {\let\fontclass\empty}
+ {\def\fontclass{#4}}%
+ \definebodyfont[#1][#2][#3]%
+ \pop_macro_fontclass}
+
+\def\font_basics_define_body_font_class_known
+ {\ifthirdargument
+ \singleexpandafter\font_basics_define_body_font_a
+ \orelse\ifsecondargument
+ \expandafter\font_basics_define_body_font_b
+ \else
+ \expandafter\font_basics_define_body_font_c
+ \fi}
+
+\unexpanded\def\font_basics_define_body_font_b[#whatever][#specification][#dummy]% body|identifier defs|identifier
+ {\font_basics_define_body_font_a[#whatever][\s!rm][#specification]}
+
+\unexpanded\def\font_basics_define_body_font_c[#whatever][#dummya][#dummyb]% body|identifier
+ {\font_basics_define_body_font_a[#whatever][\s!rm][]}
+
+\unexpanded\def\font_basics_define_body_font_a[#whatever]%
+ {\doifelsenumber{#whatever}%
+ \font_basics_define_body_font_body
+ \font_basics_define_body_font_name
+ [#whatever]}
+
+\unexpanded\def\font_basics_define_body_font_body[#body][#style][#specification]%
+ {\ifcondition\validassignment{#specification}%
+ \expandafter\font_basics_define_body_font_body_assignment
+ \else
+ \expandafter\font_basics_define_body_font_body_identifier
+ \fi
+ [#body][#style][#specification]}%
+
+\unexpanded\def\font_basics_define_body_font_name[#name][#style][#specification]%
+ {\ifcondition\validassignment{#specification}%
+ \expandafter\font_basics_define_body_font_name_assignment
+ \else
+ \expandafter\font_basics_define_body_font_name_identifier
+ \fi
+ [#name][#style][#specification]}%
+
+\unexpanded\def\font_basics_define_body_font_body_assignment[#bodylist][#stylelist][#assignments]%
+ {\processcommalist[#bodylist]{\font_basics_define_body_font_body_assignment_a{#stylelist}{#assignments}}}
+
+\unexpanded\def\font_basics_define_body_font_body_assignment_a#stylelist#assignments#body%
+ {\normalizebodyfontsize\m_font_asked_body{#body}%
+ % normally we define quite a lot in advance, i.e global defs
+ \font_helpers_check_bodyfont_environment\m_font_asked_body\m_font_asked_body % !!
+ \processcommalist[#stylelist]{\font_basics_define_body_font_body_assignment_b{#assignments}}}
+
+\unexpanded\def\font_basics_define_body_font_body_assignment_b#assignments#style%
+ {\edef\m_font_asked_style{#style}%
+ \processcommalist[#assignments]\font_basics_define_body_font_defs}
+
+\unexpanded\def\font_basics_define_body_font_defs
+ {\ifx\fontclass\empty
+ \expandafter\font_basics_define_body_font_defs_nop
+ \else
+ \expandafter\font_basics_define_body_font_defs_yes
+ \fi}
+
+\unexpanded\def\font_basics_define_body_font_defs_yes_normal#assignment%
+ {\ifx\m_font_asked_style\s!mm
+ \expandafter\font_basics_define_body_font_yes_mm
+ \else
+ \expandafter\font_basics_define_body_font_yes_xx
+ \fi[#assignment]}
+
+\unexpanded\def\font_basics_define_body_font_defs_nop_normal#assignment%
+ {\ifx\m_font_asked_style\s!mm
+ \expandafter\font_basics_define_body_font_nop_mm
+ \else
+ \expandafter\font_basics_define_body_font_nop_xx
+ \fi[#assignment]}
+
+\unexpanded\def\font_basics_define_body_font_defs_yes_traced#assignment%
+ {\writestatus\m!fonts{[\fontclass] [\m_font_asked_body] [\m_font_asked_style] [#assignment]}%
+ \ifx\m_font_asked_style\s!mm
+ \expandafter\font_basics_define_body_font_yes_mm
+ \else
+ \expandafter\font_basics_define_body_font_yes_xx
+ \fi[#assignment]}
+
+\unexpanded\def\font_basics_define_body_font_defs_nop_traced#assignment%
+ {\writestatus\m!fonts{[\fontclass] [\m_font_asked_body] [\m_font_asked_style] [#assignment]}%
+ \ifx\m_font_asked_style\s!mm
+ \expandafter\font_basics_define_body_font_nop_mm
+ \else
+ \expandafter\font_basics_define_body_font_nop_xx
+ \fi[#assignment]}
+
+\let\font_basics_define_body_font_defs_yes\font_basics_define_body_font_defs_yes_normal
+\let\font_basics_define_body_font_defs_nop\font_basics_define_body_font_defs_nop_normal
+
+\appendtoks
+ \let\font_basics_define_body_font_defs_yes\font_basics_define_body_font_defs_yes_traced
+ \let\font_basics_define_body_font_defs_nop\font_basics_define_body_font_defs_nop_traced
+\to \t_font_tracers_definitions
+
+%D We split into two characters (first part of spec) and the rest: the first two are
+%D the style and the rest is a size, although in practice one will seldom define the
+%D size directly. We might even drop that as it gives faster code.
+
+\unexpanded\def\font_basics_define_body_font_nop_xx[#one#two#rest=#value]% local
+ {\ifcsname\m_font_asked_style#one#two#rest\endcsname\else\font_basics_check_fontname_combination\m_font_asked_style{#one#two}{#rest}\fi
+ \expandafter\let\csname\??fontinstanceclass\m_font_asked_body-\m_font_asked_style-#one#two-#rest-0\endcsname\undefined
+ \unexpanded\expandafter\normaledef\csname\??fontinstanceready\m_font_asked_body-\m_font_asked_style-#one#two-#rest-0\endcsname
+ {\font_helpers_trigger{\m_font_asked_body-\m_font_asked_style-#one#two#rest}{\noexpand\font_rscale_xx{\m_font_asked_style}}{\m_font_asked_body}{\normalunexpanded{#value}}}%
+ \expandafter\let\csname\??fontinstanceclass\m_font_asked_body-\m_font_asked_style-#one#two-#rest-4\endcsname\undefined
+ \unexpanded\expandafter\normaledef\csname\??fontinstanceready\m_font_asked_body-\m_font_asked_style-#one#two-#rest-4\endcsname
+ {\font_helpers_trigger{\m_font_asked_body-\m_font_asked_style-#one#two#rest}{\noexpand\font_rscale_xx{\m_font_asked_style}}{\m_font_asked_body}{\normalunexpanded{#value}}}%
+ \expandafter\let\csname\??fontinstanceclass\m_font_asked_body-\m_font_asked_style-#one#two-#rest-5\endcsname\undefined
+ \unexpanded\expandafter\normaledef\csname\??fontinstanceready\m_font_asked_body-\m_font_asked_style-#one#two-#rest-5\endcsname
+ {\font_helpers_trigger{\m_font_asked_body-\m_font_asked_style-#one#two#rest}{\noexpand\font_rscale_xx{\m_font_asked_style}}{\m_font_asked_body}{\normalunexpanded{#value}}}%
+ }
+
+\unexpanded\def\font_basics_define_body_font_yes_xx[#one#two#rest=#value]% global
+ {\ifcsname\m_font_asked_style#one#two#rest\endcsname\else\font_basics_check_fontname_combination\m_font_asked_style{#one#two}{#rest}\fi
+ \expandafter\glet\csname\??fontinstanceclass\fontclass-\m_font_asked_body-\m_font_asked_style-#one#two-#rest-1\endcsname\undefined
+ \unexpanded\expandafter\normalxdef\csname\??fontinstanceready\fontclass-\m_font_asked_body-\m_font_asked_style-#one#two-#rest-0\endcsname
+ {\font_helpers_trigger{\m_font_asked_body-\m_font_asked_style-#one#two#rest-0}{\number\p_font_rscale}{\m_font_asked_body}{\normalunexpanded{#value}}}%
+ \expandafter\glet\csname\??fontinstanceclass\fontclass-\m_font_asked_body-\m_font_asked_style-#one#two-#rest-2\endcsname\undefined
+ \unexpanded\expandafter\normalxdef\csname\??fontinstanceready\fontclass-\m_font_asked_body-\m_font_asked_style-#one#two-#rest-4\endcsname
+ {\font_helpers_trigger{\m_font_asked_body-\m_font_asked_style-#one#two#rest-4}{\number\p_font_rscale}{\m_font_asked_body}{\normalunexpanded{#value}}}%
+ \expandafter\glet\csname\??fontinstanceclass\fontclass-\m_font_asked_body-\m_font_asked_style-#one#two-#rest-3\endcsname\undefined
+ \unexpanded\expandafter\normalxdef\csname\??fontinstanceready\fontclass-\m_font_asked_body-\m_font_asked_style-#one#two-#rest-5\endcsname
+ {\font_helpers_trigger{\m_font_asked_body-\m_font_asked_style-#one#two#rest-5}{\number\p_font_rscale}{\m_font_asked_body}{\normalunexpanded{#value}}}%
+ }
+
+% \writestatus{fonts}{define \m_asked_style\space yes: {\expandafter\meaning\csname\fontclass\m_font_asked_body\m_font_asked_style#one#two#rest\endcsname}
+
+%D Here the rest concerns rl or lr so in this case it is not a size specifier but
+%D a directional one.
+
+\unexpanded\def\font_basics_define_body_font_nop_mm[#one#two#rest=#value]% local
+ {%\ifcsname\s!mm\endcsname\else\font_basics_check_fontname_combination\s!mm{#one#two}{#rest}\fi
+ \expandafter\let\csname\??fontinstanceclass\m_font_asked_body-\s!mm-#one#two#rest-1\endcsname\undefined
+ % \expandafter\let\csname\??fontinstanceclass\m_font_asked_body-\s!mm-#one#two#rest-2\endcsname\undefined
+ % \expandafter\let\csname\??fontinstanceclass\m_font_asked_body-\s!mm-#one#two#rest-3\endcsname\undefined
+ \unexpanded\expandafter\normaledef\csname\??fontinstanceready\m_font_asked_body-\s!mm-#one#two#rest\endcsname
+ {\font_helpers_trigger{\m_font_asked_body-\s!mm-#one#two#rest}{\noexpand\font_rscale_mm}{\m_font_asked_body}{\normalunexpanded{#value}}}%
+ }
+
+% \writestatus{fonts}{define \m_asked_style\space nop: \expandafter\meaning\csname\m_font_asked_body\m_font_asked_style#one#two#rest\endcsname}%
+
+\unexpanded\def\font_basics_define_body_font_yes_mm[#one#two#rest=#value]% global
+ {%\ifcsname\s!mm\endcsname\else\font_basics_check_fontname_combination\s!mm{#one#two}{#rest}\fi
+ \expandafter\glet\csname\??fontinstanceclass\fontclass-\m_font_asked_body-\s!mm-#one#two#rest-1\endcsname\undefined
+ % \expandafter\glet\csname\??fontinstanceclass\fontclass-\m_font_asked_body-\s!mm-#one#two#rest-2\endcsname\undefined
+ % \expandafter\glet\csname\??fontinstanceclass\fontclass-\m_font_asked_body-\s!mm-#one#two#rest-3\endcsname\undefined
+ \unexpanded\expandafter\normalxdef\csname\??fontinstanceready\fontclass-\m_font_asked_body-\s!mm-#one#two#rest\endcsname
+ {\font_helpers_trigger{\m_font_asked_body-\s!mm-#one#two#rest}{\number\p_font_rscale}{\m_font_asked_body}{\normalunexpanded{#value}}}%
+ }
+
+% \writestatus{fonts}{define \m_asked_style\space yes: \expandafter\meaning\csname\fontclass\m_font_asked_body\m_font_asked_style#one#two#rest\endcsname}%
+
+\unexpanded\def\font_basics_define_body_font_body_identifier[#bodylist][#stylelist][#name]%
+ {\processcommalist[#bodylist]{\font_basics_define_body_font_body_identifier_a{#stylelist}{#name}}}
+
+\unexpanded\def\font_basics_define_body_font_body_identifier_a#stylelist#name#body%
+ {\normalizebodyfontsize\m_font_asked_body{#body}%
+ \font_helpers_check_bodyfont_environment\m_font_asked_body\m_font_asked_body % !!
+ \processcommalist[#stylelist]{\font_basics_define_body_font_body_identifier_b{#name}}}
+
+\unexpanded\def\font_basics_define_body_font_body_identifier_b#name#style%
+ {\edef\m_font_asked_style{#style}%
+ %\writestatus\m!fonts{[\fontclass] [\m_font_asked_body] [\m_font_asked_style] => [#name]}%
+ \csname\??fontdefinitions#name:\m_font_asked_style\endcsname} % no checking
+
+\unexpanded\def\font_basics_define_body_font_name_assignment[#name][#stylelist][#assignments]%
+ {\processcommalist[#stylelist]{\font_basics_define_body_font_name_assignment_a{#name}{#assignments}}}
+
+\unexpanded\def\font_basics_define_body_font_name_assignment_a#name#assignments#style%
+ {%\writestatus\m!fonts{[#name:#style] => [#assignments]}%
+ \setevalue{\??fontdefinitions#name:#style}{\font_basics_define_body_font_default{#assignments}}}
+
+\unexpanded\def\font_basics_define_body_font_name_identifier[#name][#stylelist][#identifier]%
+ {\processcommalist[#stylelist]{\font_basics_define_body_font_name_identifier_a{#name}{#identifier}}}
+
+\unexpanded\def\font_basics_define_body_font_name_identifier_a#name#identifier#style%
+ {%\writestatus\m!fonts{[#name:#style] => [##identifier:#style]}%
+ \ifcsname\??fontdefinitions#name:#style\endcsname
+ \expandafter\let\csname\??fontdefinitions#name:#style\expandafter\endcsname\csname\??fontdefinitions#identifier:#style\endcsname
+ \else
+ \expandafter\def\csname\??fontdefinitions#name:#style\endcsname{\csname\??fontdefinitions#identifier:#style\endcsname}%
+ \fi}
+
+%D The unknown:
+
+\newconditional\c_font_defining_unknown
+\newconditional\c_font_defining_state
+
+\unexpanded\def\font_helpers_define_unknown_font#body% one level only
+ {\font_helpers_register_fontbody{#body}% prevents loop, can go
+ \setfalse\c_font_defining_state
+ \font_helpers_process_relative_size_list{\font_helpers_define_unknown_check_sizes{#body}}%
+ \ifconditional\c_font_defining_state
+ \setfalse\c_font_defining_state
+ \font_helpers_process_style_list{\font_helpers_define_unknown_check_definitions{#body}}%
+ \ifconditional\c_font_defining_state
+ \ifconditional\c_font_defining_environment_state\else
+ %\showmessage\m!fonts{14}{#body}% main
+ \clf_registerunknownbodysize{#body}%
+ \fi
+ \setfalse\c_font_defining_state
+ \font_helpers_register_fontbody{#body}%
+ % needed ?
+ \ifconditional\c_font_defining_unknown
+ \else
+ \settrue\c_font_defining_unknown
+ \font_helpers_process_relative_size_list{\font_helpers_define_unknown_check_relatives{#body}}%
+ \setfalse\c_font_defining_unknown
+ \fi
+ \fi
+ \fi}
+
+\def\font_helpers_define_unknown_check_sizes#body#relativesize%
+ {\ifcsname\??fontenvironments\s!default#relativesize\endcsname % fontclass ?
+ \expandafter\normalizebodyfontsize\csname\??fontenvironments#body#relativesize\endcsname{\csname\??fontenvironments\s!default#relativesize\endcsname\dimexpr#body\relax}%
+ \settrue\c_font_defining_state
+ \fi}
+
+\def\font_helpers_define_unknown_check_definitions#body#style%
+ {\ifcsname\??fontdefinitions\s!default:#style\endcsname
+ \edef\m_font_asked_body{#body}%
+ \edef\m_font_asked_style{#style}%
+ \lastnamedcs
+ \settrue\c_font_defining_state
+ \fi}
+
+% \def\font_helpers_define_unknown_check_relatives#body#relativesize%
+% {\ifcsname\??fontbodyknown\csname\??fontenvironments#body#relativesize\endcsname\endcsname \else
+% % how \lastnamedcs here
+% \expandafter\font_helpers_define_unknown_font\csname\??fontenvironments#body#relativesize\endcsname
+% \settrue\c_font_defining_state
+% \fi}
+
+\def\font_helpers_define_unknown_check_relatives#body#relativesize%
+ {\ifcsname\??fontbodyknown\csname\??fontenvironments#body#relativesize\endcsname\endcsname \else
+ \expandafter\font_helpers_define_unknown_font\csname\??fontenvironments#body#relativesize\endcsname
+ \settrue\c_font_defining_state
+ \fi}
+
+\unexpanded\def\font_basics_define_body_font_default#assignments%
+ {\font_helpers_check_relative_font_size\m_font_asked_style % still needed here?
+ \ifcsname\m_font_asked_style\endcsname\else
+ \normalexpanded{\definefontstyle[\m_font_asked_style][\m_font_asked_style]}%
+ \fi
+ \processcommalist[#assignments]\font_basics_define_body_font_defs
+ \let\p_font_rscale\v_font_rscale_default}
+
+%D These macros show that quite some definitions take place. Fonts are not loaded
+%D yet! This means that at format generation time, no font files are present.
+
+\unexpanded\def\font_basics_switch_points#body%
+ {\ifcsname\??fontbodyknown#body\endcsname \else
+ % we need to check the relative sizes for this body
+ \font_helpers_define_unknown_font{#body}%
+ \fi%
+ \ifcsname\??fontbodyknown#body\endcsname % always true now
+ \font_basics_complete_switch{#body}%
+ \localbodyfontsize#body\relax
+ \normalizebodyfontsize\normalizedbodyfontsize\localbodyfontsize
+ \font_helpers_check_bodyfont_environment\normalizedbodyfontsize\normalizedbodyfontsize % !!
+ \else
+ \showmessage\m!fonts4{#body}%
+ \fi}
+
+\unexpanded\def\font_basics_switch_style#style%
+ {\ifcsname\??fontstyle#style\endcsname
+ \lastnamedcs
+ \edef\fontstyle{#style}%
+ \ifmmode\mr\fi % in order to be compatible with \rm in math mode
+ % \the\everybodyfont % cleaner, in setting size as well as style
+ \else
+ \showmessage\m!fonts5{#style}%
+ \fi}
+
+%D Here comes the main font switching macros. These macros handle changes in size as
+%D well as returning to the global bodyfont size.
+
+\ifdefined\font_preloads_at_definition \else \let\font_preloads_at_definition\relax \fi
+
+\def\font_helpers_set_font#method#specification%
+ {\edef\m_font_specification{#specification}%
+ \ifx\m_font_specification\empty \else
+ \ifx\m_font_specification\v!global % we can have all kind of presets
+ \restoreglobalbodyfont
+ \else
+ \processcommacommand[\m_font_specification]{\font_helpers_set_font_check_size}%
+ \processcommacommand[\m_font_specification]{\font_helpers_set_font_set_font{#method}}%
+ \ifproductionrun
+ \font_preloads_at_definition
+ \font_basics_switch_points\normalizedbodyfontsize
+ \font_basics_switch_style\fontstyle
+ \ifx\defaultfontclass\empty
+ \let\defaultfontclass\fontclass
+ \fi
+ \fi
+ \fi
+ \currentxfontsize\zerocount
+ \fi}
+
+\def\font_helpers_set_font_check_size#option%
+ {\doifelsenumber{#option}{\font_helpers_check_bodyfont_environment{#option}{#option}}\donothing}
+
+\def\font_helpers_set_font_set_font#method#option% method=1: set, method=2: switch
+ {\doifsomething{#option}{\font_helpers_set_font_set_font_option{#method}{#option}}}
+
+\def\font_helpers_set_font_set_font_option#method#option%
+ {\doifelsenumber{#option}%
+ \font_helpers_set_font_set_font_option_body
+ \font_helpers_set_font_set_font_option_keyword
+ {#method}{#option}{#option}}
+
+\newmacro\m_font_keyword
+
+\unexpanded\def\font_helpers_set_font_set_font_option_keyword#method#keyword#message%
+ {\edef\m_font_keyword{#keyword}%
+ \ifcsname\??fontenvironments\normalizedbodyfontsize\m_font_keyword\endcsname
+ \edef\m_font_step{\font_bodyfontvariable\m_font_keyword}%
+ \normalexpanded{\font_helpers_set_font_set_font_option_body{#method}{\m_font_step}{#message}}%
+ \orelse\ifx\m_font_keyword\v!reset
+ \let\fontstyle\empty % new 31/7/2006
+ \let\fontsize \empty
+ \orelse\ifcsname\??fontstyle\m_font_keyword\endcsname
+ \let\fontstyle\m_font_keyword
+ \else
+ \setcurrentfontclass\m_font_keyword
+ \ifcase#method\relax
+ \let\globalfontclass\globalfontclass % -)
+ \else
+ \let\globalfontclass\fontclass
+ \fi
+ \font_helpers_set_fontstyle_of_fontclass
+ \fi}
+
+\def\font_helpers_set_fontstyle_of_fontclass % will be overloaded later
+ {\let\fontstyle\s!rm}
+
+\unexpanded\def\font_helpers_set_font_set_font_option_body#method#body#message%
+ {\normalizebodyfontsize\normalizedsetfont{#body}% redundant for some calls
+ \ifcsname\??fontbodyknown\normalizedsetfont\endcsname \else
+ \font_helpers_define_unknown_font\normalizedsetfont
+ \fi
+ \ifcsname\??fontbodyknown\normalizedsetfont\endcsname
+ \localbodyfontsize\normalizedsetfont
+ \let\normalizedbodyfontsize\normalizedsetfont
+ \else
+ \showmessage\m!fonts4{#message}%
+ %\font_helpers_set_font_set_font_option_body_fallbacks{#method}{#body}%
+ \fi}
+
+% we need to check the fontclass
+
+\def\registerfontclass#class%
+ {\letgvalue{\??fontclassyes#class}\v!yes} % global ?
+
+\def\setcurrentfontclass#class%
+ {\ifcsname\??fontclassyes#class\endcsname
+ \edef\fontclass{#class}%
+ \orelse\ifcsname\??fontclassnop#class\endcsname
+ % already tried
+ \else % too messy: \ifcase\currentgrouplevel % (unpredictable)
+ \trycurrentfontclass{#class}%
+ \fi}
+
+\ifdefined\trycurrentfontclass \else
+
+ \unexpanded\def\trycurrentfontclass#typeface%
+ {\letvalueempty{\??fontclassnop#typeface}}
+
+\fi
+
+\let\defaultfontstyle \s!rm
+\let\defaultfontalternative\s!tf
+\let\defaultfontsize \empty
+\let\defaultfontface \!!zerocount
+
+%D So far for synchronisation. (We can inline the following macros.)
+
+\unexpanded\def\setcurrentfont#body#style#alternative#size% not used
+ {\edef\fontbody {#body}%
+ \edef\fontstyle {#style}%
+ \edef\fontalternative{#alternative}%
+ \edef\fontsize {#size}%
+ \font_helpers_check_big_math_synchronization
+ \font_helpers_synchronize_font}
+
+\unexpanded\def\setcurrentfontbody#body% % not used
+ {\edef\fontbody{#body}%
+ \font_helpers_synchronize_font}
+
+% For Taco: optional fall backs:
+
+\ifdefined\font_typescripts_inherit_check \else
+ \let\font_typescripts_inherit_check\gobbleoneargument % implemented in type-ini
+\fi
+
+\unexpanded\def\font_helpers_set_current_font_style#style%
+ {\edef\fontstyle{#style}%
+ \font_typescripts_inherit_check\fontstyle
+ \ifmmode\mr\fi % otherwise \rm not downward compatible ... not adapted yet
+ \font_helpers_synchronize_font}
+
+\unexpanded\def\font_helpers_set_current_xsize_alternative#xsize#alternative%
+ {\edef\fontface{#xsize}%
+ \edef\fontalternative{#alternative}%
+ \font_helpers_synchronize_font}
+
+\unexpanded\def\font_helpers_set_current_font_alternative#alternative%
+ {\edef\fontalternative{#alternative}%
+ \font_helpers_synchronize_font}
+
+\unexpanded\def\font_helpers_set_current_font_size#size%
+ {\edef\fontsize{#size}%
+ \font_helpers_check_big_math_synchronization % double? better in everymath?
+ \font_helpers_synchronize_font}
+
+\unexpanded\def\font_helpers_set_current_font_style_alternative#style#alternative% \rmsl
+ {\edef\fontstyle {#style}%
+ \edef\fontalternative{#alternative}%
+ \font_helpers_synchronize_font}
+
+\unexpanded\def\font_helpers_set_current_font_style_size#style#size% \rma
+ {\edef\fontstyle{#style}%
+ \edef\fontsize {#size}%
+ \font_helpers_check_big_math_synchronization % double? better in everymath?
+ \font_helpers_synchronize_font}
+
+\unexpanded\def\font_helpers_set_current_font_alternative_size#alternative#size% \sla
+ {\edef\fontalternative{#alternative}%
+ \edef\fontsize {#size}%
+ \font_helpers_check_big_math_synchronization % double? better in everymath?
+ \font_helpers_synchronize_font}
+
+\unexpanded\def\font_helpers_set_current_font_style_alternative_size#style#alternative#size% \rmsla
+ {\edef\fontstyle {#style}%
+ \edef\fontalternative{#alternative}%
+ \edef\fontsize {#size}%
+ \font_helpers_check_big_math_synchronization % double? better in everymath?
+ \font_helpers_synchronize_font}
+
+\unexpanded\def\font_helpers_synchronize_font % we can have dups i.e. no need to let fontstrategy
+ {\ifx\fontclass\empty
+ \applyfontstrategies
+ \else
+ \applyfontclassstrategies
+ \fi
+ \setfalse\c_font_auto_size
+ \ifskipfontcharacteristics
+ \setfontcharacteristics
+ \the\everyfontswitch
+ \fi}
+
+%D This is the resolver for special cases (sizes) and in practice it is not called
+%D that often so further optimization makes no sense.
+
+\def\font_helpers_check_strategy_class_a % --- --- --- --- % pt tt bf a
+ {\ifcsname\??fontinstanceready\fontclass-\fontbody-\fontstyle-\fontalternative-\fontsize-\fontface\endcsname
+ \setfalse\c_font_auto_size
+ \lastnamedcs
+ \else
+ \expandafter\font_helpers_check_strategy_class_b
+ \fi}
+
+\def\font_helpers_check_strategy_class_b % --- --- --- def % pt tt bf
+ {\ifcsname\??fontinstanceready\fontclass-\fontbody-\fontstyle-\fontalternative-\defaultfontsize-\fontface\endcsname
+ \settrue\c_font_auto_size
+ \lastnamedcs
+ \else
+ \expandafter\font_helpers_check_strategy_class_c
+ \fi}
+
+\def\font_helpers_check_strategy_class_c % --- --- def --- % pt tt tf a
+ {\ifcsname\??fontinstanceready\fontclass-\fontbody-\fontstyle-\defaultfontalternative-\fontsize-\fontface\endcsname
+ \settrue\c_font_auto_size
+ \lastnamedcs
+ \else
+ \expandafter\font_helpers_check_strategy_class_d
+ \fi}
+
+\def\font_helpers_check_strategy_class_d % --- --- def def % pt tt tf
+ {\ifcsname\??fontinstanceready\fontclass-\fontbody-\fontstyle-\defaultfontalternative-\defaultfontsize-\fontface\endcsname
+ \settrue\c_font_auto_size
+ \lastnamedcs
+ \else
+ \expandafter\font_helpers_check_strategy_class_e
+ \fi}
+
+\def\font_helpers_check_strategy_class_e % --- def def def % pt rm tf
+ {\ifcsname\??fontinstanceready\fontclass-\fontbody-\defaultfontstyle-\defaultfontalternative-\defaultfontsize-\fontface\endcsname
+ \setfalse\c_font_auto_size
+ \lastnamedcs
+ \else
+ \expandafter\font_helpers_check_strategy_class_f
+ \fi}
+
+\def\font_helpers_check_strategy_class_f % def def def def % rm tf
+ {\ifcsname\??fontinstanceready\fontclass-\defaultfontbody-\defaultfontstyle-\defaultfontalternative-\defaultfontsize-\fontface\endcsname
+ \settrue\c_font_auto_size
+ \lastnamedcs
+ \else
+ \expandafter\font_helpers_check_strategy_a
+ \fi}
+
+% no class
+
+\def\font_helpers_check_strategy_a % --- --- --- --- % pt tt bf a
+ {\ifcsname\??fontinstanceready\fontbody-\fontstyle-\fontalternative-\fontsize-\fontface\endcsname
+ \setfalse\c_font_auto_size
+ \lastnamedcs
+ \else
+ \expandafter\font_helpers_check_strategy_b
+ \fi}
+
+\def\font_helpers_check_strategy_b % --- --- --- --- % pt tt bf a
+ {\ifcsname\??fontinstanceready\fontbody-\fontstyle-\fontalternative-\defaultfontsize-\fontface\endcsname
+ \settrue\c_font_auto_size
+ \lastnamedcs
+ \else
+ \expandafter\font_helpers_check_strategy_c
+ \fi}
+
+\def\font_helpers_check_strategy_c % --- --- --- --- % pt tt bf a
+ {\ifcsname\??fontinstanceready\fontbody-\fontstyle-\defaultfontalternative-\fontsize-\fontface\endcsname
+ \settrue\c_font_auto_size
+ \lastnamedcs
+ \else
+ \expandafter\font_helpers_check_strategy_d
+ \fi}
+
+\def\font_helpers_check_strategy_d % --- --- --- --- % pt tt bf a
+ {\ifcsname\??fontinstanceready\fontbody-\fontstyle-\defaultfontalternative-\defaultfontsize-\fontface\endcsname
+ \settrue\c_font_auto_size
+ \lastnamedcs
+ \else
+ \expandafter\font_helpers_check_strategy_e
+ \fi}
+
+\def\font_helpers_check_strategy_e % --- --- --- --- % pt tt bf a
+ {\ifcsname\??fontinstanceready\fontbody-\defaultfontstyle-\defaultfontalternative-\defaultfontsize-\fontface\endcsname
+ \setfalse\c_font_auto_size
+ \lastnamedcs
+ \else
+ \expandafter\font_helpers_check_strategy_f
+ \fi}
+
+\def\font_helpers_check_strategy_f % --- --- --- --- % pt tt bf a
+ {\ifcsname\??fontinstanceready\defaultfontbody-\defaultfontstyle-\defaultfontalternative-\defaultfontsize-\fontface\endcsname
+ \settrue\c_font_auto_size
+ \lastnamedcs
+ \fi}
+
+\let\applyfontstrategies \font_helpers_check_strategy_a
+\let\applyfontclassstrategies\font_helpers_check_strategy_class_a
+
+%D Let's synchronize:
+
+\newconditional\c_font_synchronize \settrue\c_font_synchronize
+
+\prependtoks
+ \ifconditional\c_font_synchronize
+ \font_helpers_synchronize_math
+ \font_helpers_synchronize_font % problem: syncs last font
+ \fi
+\to \everybodyfont
+
+%D Setting the normal sizes as well as the x and xx smaller sizes is accomplished by
+%D the next set of macros. When in math mode, the commands \type {\tx} and \type
+%D {\txx} are just a switch to the script and double script styles, but in text mode
+%D the values defined by the bodyfontenvironment are used. Here we also set \type
+%D {\currentxfontsize}.
+
+\def\font_helpers_set_current_font_xxx_alternative#alternative#xsize#scriptstyle%
+ {\ifmmode
+ #scriptstyle%
+ \else
+ \font_helpers_set_current_xsize_alternative{#xsize}{#alternative}%
+ \fi}
+
+\def\font_helpers_reset_x_fontsize
+ {\ifcase\currentxfontsize\else
+ \currentxfontsize\zerocount
+ % also \sx and \sxx ?
+ \let\tx \normaltx
+ \let\txx\normaltxx
+ \fi}
+
+\let\font_helpers_check_nested_x_fontsize\relax
+
+\def\font_helpers_set_current_font_x_alternative#alternative%
+ {\font_helpers_check_nested_x_fontsize
+ \font_helpers_set_current_font_xxx_alternative{#alternative}{4}\scriptstyle
+ \currentxfontsize\plusone
+ \let\tx\txx}
+
+\def\font_helpers_set_current_font_xx_alternative#alternative%
+ {\font_helpers_check_nested_x_fontsize
+ \font_helpers_set_current_font_xxx_alternative{#alternative}{5}\scriptscriptstyle
+ \currentxfontsize\plustwo
+ \let\tx\empty
+ \let\txx\empty}
+
+%D This alterative is not really needed, but for old time's sake we keep it there.
+%D We can speed it up when needed.
+
+\def\font_helpers_set_current_font_x_style_alternative #alternative{\csname#alternative\endcsname\tx}
+\def\font_helpers_set_current_font_xx_style_alternative#alternative{\csname#alternative\endcsname\txx}
+
+%D These macros also show us that when we call for \type {\tx}, this macro is
+%D redefined to be \type {\txx}. Therefore calls like:
+%D
+%D \startbuffer
+%D {small \tx is \tx beautiful}
+%D {small \tx is \txx beautiful}
+%D {small \txx is \tx beautiful}
+%D {small \txx is \txx beautiful}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D result in:
+%D
+%D \startlines
+%D \getbuffer
+%D \stoplines
+%D
+%D Setting the main size involves the style list and therefore takes a bit more
+%D time. Keep in mind that the fontsize is represented by a character or empty.
+
+\installcorenamespace{fontscalex}
+\installcorenamespace{fontscalexx}
+
+\newconditional\c_font_inherit_scale
+
+\def\font_scale_inherit#1%
+ {\begingroup
+ \scratchcounterone\fontid\font\relax
+ \currentxfontsize\plusone
+ \normalexpanded{\definedfont[\clf_specifiedfont\scratchcounterone\font_currentfontscale\relax]}%
+ \scratchcountertwo\fontid\font\relax
+ \currentxfontsize\plustwo
+ \normalexpanded{\definedfont[\clf_specifiedfont\scratchcounterone\font_currentfontscale\relax]}%
+ \scratchcounterthree\fontid\font\relax
+ % parent -> x -> xx
+ % parent -> xx
+ \global\expandafter\chardef\csname\??fontscalex \number\scratchcounterone\endcsname\scratchcountertwo
+ \global\expandafter\chardef\csname\??fontscalexx\number\scratchcounterone\endcsname\scratchcounterthree
+ \global\expandafter\chardef\csname\??fontscalex \number\scratchcountertwo\endcsname\scratchcounterthree
+ \global\expandafter\chardef\csname\??fontscalexx\number\scratchcountertwo\endcsname\scratchcounterthree
+ \endgroup
+ \setfontid\csname#1\number\fontid\font\endcsname}
+
+\def\font_scale_inherit_x
+ {\ifcsname\??fontscalex\number\fontid\font\endcsname
+ \setfontid\lastnamedcs
+ \else
+ \font_scale_inherit\??fontscalex
+ \fi
+ \ifskipfontcharacteristics
+ \setfontcharacteristics
+ \the\everyfontswitch
+ \fi}
+
+\def\font_scale_inherit_xx
+ {\ifcsname\??fontscalexx\number\fontid\font\endcsname
+ \setfontid\lastnamedcs
+ \else
+ \font_scale_inherit\??fontscalexx
+ \fi
+ \ifskipfontcharacteristics
+ \setfontcharacteristics
+ \the\everyfontswitch
+ \fi}
+
+\def\font_scale_defined_x
+ {\let\fontface\!!plusfour
+ \let\fontalternative\fontalternative
+ \font_helpers_synchronize_font}
+
+\def\font_scale_defined_xx
+ {\let\fontface\!!plusfive
+ \let\fontalternative\fontalternative
+ \font_helpers_synchronize_font}
+
+\unexpanded\def\tx
+ {\currentxfontsize\plusone
+ \ifmmode
+ \scriptstyle
+ \else\ifconditional\c_font_inherit_scale
+ \font_scale_inherit_x
+ \else
+ \font_scale_defined_x
+ \fi\fi
+ \let\tx\txx}
+
+\unexpanded\def\txx
+ {\currentxfontsize\plustwo
+ \ifmmode
+ \scriptscriptstyle
+ \else\ifconditional\c_font_inherit_scale
+ \font_scale_inherit_xx
+ \else
+ \font_scale_defined_xx
+ \fi\fi
+ \let\tx \empty
+ \let\txx\empty}
+
+\unexpanded\def\sx
+ {\currentxfontsize\plusone
+ \ifmmode
+ \scriptstyle
+ \else
+ \font_scale_inherit_x
+ \fi
+ \let\tx\txx
+ \let\sx\sxx}
+
+\unexpanded\def\sxx
+ {\currentxfontsize\plustwo
+ \ifmmode
+ \scriptscriptstyle
+ \else
+ \font_scale_inherit_xx
+ \fi
+ \let\tx \empty
+ \let\txx\empty
+ \let\sx \empty
+ \let\sxx\empty}
+
+\unexpanded\def\useinheritxsizes{\settrue \c_font_inherit_scale} % not yet public, playground for WS and me
+\unexpanded\def\usedefinedxsizes{\setfalse\c_font_inherit_scale} % not yet public, playground for WS and me
+
+\let\normaltx \tx
+\let\normaltxx\txx
+
+\let\normalsx \sx
+\let\normalsxx\sxx
+
+%D When asking for a complete font switch, for instance from 10 to 12~points, the
+%D next macro does the job. First we normalize the size, next we define the current
+%D range of text, script and scriptscript sizes, then we set the text fonts and the
+%D math families and finally we activate the default typeface and also set the font
+%D specific parameters assigned to \type {\everybodyfont}.
+
+\def\textface {\currentbodyfontdimension\s!text }
+\def\scriptface {\currentbodyfontdimension\s!script }
+\def\scriptscriptface{\currentbodyfontdimension\s!scriptscript}
+\def\xtextface {\currentbodyfontdimension\s!x }
+\def\xxtextface {\currentbodyfontdimension\s!xx }
+
+\installcorenamespace{fontbodyfaces}
+
+\unexpanded\def\font_basics_complete_switch#size%
+ {\bodyfontsize#size\relax
+ \normalizebodyfontsize\normalizedbodyfontsize\bodyfontsize
+ \expandafter\let\expandafter\font_basics_set_faces\csname\??fontbodyfaces\fontbody\endcsname
+ \ifx\font_basics_set_faces\relax
+ \font_basics_set_faces_preset
+ \fi
+ \font_basics_set_faces}
+
+\def\font_basics_set_faces_preset
+ {\edef\font_basics_set_faces{% 0.2 sec on 10K \tfa
+ \noexpand\edef\noexpand\textface {\currentbodyfontdimension\s!text }%
+ \noexpand\edef\noexpand\scriptface {\currentbodyfontdimension\s!script }%
+ \noexpand\edef\noexpand\scriptscriptface{\currentbodyfontdimension\s!scriptscript}%
+ \noexpand\edef\noexpand\xtextface {\currentbodyfontdimension\s!x }%
+ \noexpand\edef\noexpand\xxtextface {\currentbodyfontdimension\s!xx }%
+ }%
+ \expandafter\glet\csname\??fontbodyfaces\fontbody\endcsname\font_basics_set_faces}
+
+\def\currentbodyfontdimension#parameter% there can be factors here
+ {\the\dimexpr
+ \ifcsname\??fontenvironments\fontclass\normalizedbodyfontsize#parameter\endcsname
+ \lastnamedcs
+ \orelse\ifcsname\??fontenvironments\fontclass\s!default#parameter\endcsname
+ \lastnamedcs
+ \dimexpr\normalizedbodyfontsize\relax
+ \orelse\ifcsname\??fontenvironments\normalizedbodyfontsize#parameter\endcsname
+ \lastnamedcs
+ \else
+ \csname\??fontenvironments\s!default#parameter\endcsname
+ \dimexpr\normalizedbodyfontsize\relax
+ \fi
+ \relax}
+
+%D \macros
+%D {setupbodyfont,switchtobodyfont}
+%D
+%D The next two macros are user ones. With \type {\setupbodyfont} one can set the
+%D document bodyfont size, font family, style and/or options defined in files, for
+%D example:
+%D
+%D \starttyping
+%D \setupbodyfont[modern,12pt,roman]
+%D \stoptyping
+%D
+%D This command affects the document as a whole: text, headers and footers. The
+%D second macro however affects only the text:
+%D
+%D \starttyping
+%D \switchtobodyfont[10pt]
+%D \stoptyping
+%D
+%D So we've got:
+%D
+%D \showsetup{setupbodyfont}
+%D \showsetup{switchtobodyfont}
+%D
+%D Both macros look alike. The second one also has to take all kind of keywords into
+%D account.
+
+\ifx\saveinterlinespace \undefined \let\saveinterlinespace \relax \fi
+\ifx\restoreinterlinespace\undefined \let\restoreinterlinespace\relax \fi
+
+% \newtoks \everysetupbodyfont
+% \newtoks \everyswitchtobodyfont
+
+\unexpanded\def\setupbodyfont
+ {\doifelsenextoptionalcs\font_basics_setupbodyfont_yes\font_basics_setupbodyfont_nop}
+
+\def\font_basics_setupbodyfont_nop
+ {\restoreglobalbodyfont
+ \saveinterlinespace}
+
+\def\font_basics_setupbodyfont_yes[#specification]%
+ {\doifsomething{#specification}
+ {\font_helpers_set_font\plusone{#specification}%
+ \globalbodyfontsize\localbodyfontsize
+ \normalizebodyfontsize\normalizedglobalbodyfontsize\globalbodyfontsize
+ \let\globalfontstyle\fontstyle
+ \ifproductionrun
+ \the\everybodyfont
+ \the\everyglobalbodyfont
+ \saveinterlinespace
+ \fi
+ \the\everysetupbodyfont}}
+
+\unexpanded\def\font_basics_switchtobodyfont#specification%
+ {\edef\m_font_step{\font_bodyfontvariable{#specification}}%
+ \ifx\m_font_step\empty
+ \font_helpers_set_font\zerocount{#specification}%
+ \else
+ \font_helpers_switch_bodyfont_step % so we have a fast [small] switch
+ \fi
+ \the\everybodyfont
+ \the\everyswitchtobodyfont}
+
+\unexpanded\def\switchtobodyfont[#specification]% could become an ifx
+ {\doifsomething{#specification}{\font_basics_switchtobodyfont{#specification}}}
+
+\unexpanded\def\usebodyfontparameter#1%
+ {\edef\m_font_bodyfont_asked{#1\c!bodyfont}%
+ \ifx\m_font_bodyfont_asked\empty\else
+ \font_basics_switchtobodyfont\m_font_bodyfont_asked
+ \fi}
+
+\def\font_helpers_switch_bodyfont_step
+ {\font_basics_switch_points\m_font_step
+ \font_basics_switch_style \fontstyle}
+
+%D The following alternative is meant for math||to||text switching and will be
+%D optimized.
+
+\unexpanded\def\fastswitchtobodyfont#name%
+ {\ifcsname\??fontenvironments\normalizedbodyfontsize#name\endcsname
+ %\edef\futurebodyfontsize{\csname\??fontenvironments\normalizedbodyfontsize#name\endcsname}%
+ \edef\futurebodyfontsize{\lastnamedcs}%
+ \ifcsname\??fontbodyknown\futurebodyfontsize\endcsname
+ \font_basics_complete_switch\futurebodyfontsize
+ \localbodyfontsize\futurebodyfontsize\relax
+ \fi
+ \fi
+ \csname\??fontstyle\fontstyle\endcsname
+ \the\everybodyfont}
+
+%D \starttyping
+%D $\cases{& \ccaron}$ $x=\hbox{\ccaron $x=\hbox{\ccaron}$}$
+%D \stoptyping
+
+%D \macros
+%D {usebodyfont}
+%D
+%D This looks nicer then a switch in the preamble
+%D
+%D \starttyping
+%D \usebodyfont[pagella,10pt]
+%D \usebodyfont[termes,10pt]
+%D \usebodyfont[dejavu,10pt]
+%D
+%D \setupbodyfont[dejavu]
+%D
+%D \starttext
+%D test
+%D \stoptext
+%D \stoptyping
+
+\unexpanded\def\usebodyfont[#1]%
+ {\ifx\fontclass\empty
+ \setupbodyfont[#1]%
+ \else
+ \switchtobodyfont[#1]%
+ \fullrestoreglobalbodyfont
+ \fi}
+
+\unexpanded\def\showbodyfontstate
+ {\dontleavehmode
+ \start
+ \infofont
+ [fontclass: \fontclass,\space
+ fontbody: \fontbody ,\space
+ fontface: \fontface ,\space
+ fontsize: \fontsize ]%
+ \stop}
+
+%D Handy for manuals:
+
+%D The \type {\tochar} commmand takes a specification:
+%D
+%D \starttabulate[|l|l|l|]
+%D \NC e \NC entity \NC e:eacute \NC \NR
+%D \NC x \NC hexadecimal unicode \NC x:013D \NC \NR
+%D \NC d \NC decimal unicode \NC d:123 \NC \NR
+%D \NC s \NC hexadecimal index (slot) \NC s:210D \NC \NR
+%D \NC i \NC decimal index \NC i:456 \NC \NR
+%D \NC n \NC name \NC n:eight \NC \NR
+%D \NC c \NC name \NC c:x \NC \NR
+%D \NC u \NC unicode descriptions \NC u:dog \NC \NR
+%D \NC a \NC all (also descriptions) \NC a:rewind \NC \NR
+%D \stoptabulate
+%D
+%D This is an expandable command!
+
+\unexpanded\def\fontchar #character{\clf_fontchar{#character}}
+\unexpanded\def\fontcharbyindex #index{\clf_fontcharbyindex#index\relax}
+ \def\tochar #specifications{\clf_tochar{#specifications}} % expanded (also used in edef)
+
+%D The next auxilliary macro is an alternative to \type {\fontname}.
+
+\def\purefontname#font{\clf_purefontname{\fontname#font}}
+
+%D \macros
+%D {switchstyleonly}
+%D
+%D For switching a style but keeping the alternative, there
+%D is:
+%D
+%D \starttyping
+%D {\bf text \switchstyleonly\ss text}
+%D {\bf text \switchstyleonly[ss]text}
+%D {\sl text \switchstyleonly[sansserif]text}
+%D \stoptyping
+
+\unexpanded\def\switchstyleonly
+ {\doifelsenextoptionalcs\font_basics_switch_style_only_opt\font_basics_switch_style_only_arg}
+
+\def\font_basics_switch_style_only_arg#name% stupid version
+ {\font_helpers_set_current_font_style{\csname\??fontshortstyle\checkedstrippedcsname#name\endcsname}%
+ \the\everybodyfont} % needed ?
+
+\def\font_basics_switch_style_only_opt[#name]% todo : check
+ {\font_helpers_set_current_font_style{\csname\??fontshortstyle#name\endcsname}%
+ \the\everybodyfont} % needed ?
+
+%D \macros
+%D {definebodyfontswitch}
+%D
+%D \PLAIN\ \TEX\ defines some macro's like \type {\tenpoint} to switch to a specific
+%D bodyfontsize. Just for the sake of compatibility we can define them like:
+%D
+%D \starttyping
+%D \definebodyfontswitch [twelvepoint] [12pt]
+%D \stoptyping
+%D
+%D We don't support language specific synonyms here.
+
+\unexpanded\def\definebodyfontswitch
+ {\dodoubleargument\font_basics_define_bodyfont_switch}
+
+\def\font_basics_define_bodyfont_switch[#command][#specification]% no longer a commalist (not useful)
+ {\setvalue{#command}{\switchtobodyfont[#specification]}}%
+
+%D \macros
+%D {setsmallbodyfont,setmainbodyfont,setbigbodyfont}
+%D
+%D When we're typesetting at for instance 10pt, we can call for the \type {small} as
+%D well as the \type {big} alternative, related to this main size, using \type
+%D {\switchtobodyfont[small]}. The three alternatives can be activated by the next
+%D three system calls and are defined by the bodyfontenvironment.
+
+\newmacro\m_font_step
+
+\def\font_helpers_set_bodyfont_step#step%
+ {\edef\m_font_step{\font_bodyfontvariable{#step}}% not always \cs
+ \font_basics_switch_points\m_font_step
+ \font_basics_switch_style \fontstyle}
+
+\unexpanded\def\setsmallbodyfont{\font_helpers_set_bodyfont_step\v!small\the\everybodyfont}
+\unexpanded\def\setbigbodyfont {\font_helpers_set_bodyfont_step\v!big \the\everybodyfont}
+
+\unexpanded\def\setmainbodyfont
+ {\font_basics_switch_points\normalizedbodyfontsize
+ \font_basics_switch_style\fontstyle
+ \the\everybodyfont
+ \the\everyglobalbodyfont
+ \saveinterlinespace}
+
+%D \macros
+%D {restoreglobalbodyfont}
+%D
+%D Users can set whatever font available while typesetting text. Pagenumbers,
+%D footers, headers etc. however must be typeset in the main bodyfont and style of
+%D the document. Returning to the global state can be done with the next macro:
+%D
+%D This macro has to be called when entering the pagebody handling routine as well
+%D as the footnote insert routine. Users can access this feature |<|for instance
+%D when one wants to typeset tables and alike in the main bodyfont and style while
+%D the running text is temporary set to a smaller one|>| by saying \type
+%D {\switchtobodyfont [global]}.
+
+\let\globalfontstyle\s!rm
+
+\unexpanded\def\fullrestoreglobalbodyfont
+ {\let\fontsize\defaultfontsize
+ \let\fontbody\defaultfontbody
+ \let\fontface\defaultfontface
+ \currentxfontsize\zerocount
+ \let\fontclass\globalfontclass
+ \font_basics_switch_points\normalizedglobalbodyfontsize
+ \font_basics_switch_style\globalfontstyle
+ \redoconvertfont % just in case a pagebreak occurs
+ \tf
+ \the\everybodyfont
+ \the\everyglobalbodyfont
+ \saveinterlinespace}
+
+\unexpanded\def\partialrestoreglobalbodyfont
+ {\let\fontsize\defaultfontsize
+ \let\fontbody\defaultfontbody
+ \let\fontface\defaultfontface
+ \currentxfontsize\zerocount
+ \redoconvertfont
+ \tf
+ \the\everybodyfont % indeed needed
+ \the\everyglobalbodyfont % indeed needed
+ \saveinterlinespace}
+
+\unexpanded\def\restoreglobalbodyfont % ook style etc
+ {\ifx\fontclass\globalfontclass
+ \ifx\fontstyle\globalfontstyle
+ \ifx\normalizedbodyfontsize\normalizedglobalbodyfontsize
+ \partialrestoreglobalbodyfont
+ \else
+ \fullrestoreglobalbodyfont
+ \fi
+ \else
+ \fullrestoreglobalbodyfont
+ \fi
+ \else
+ \fullrestoreglobalbodyfont
+ \fi}
+
+% in case of troubles: \let\restorebodyfont\fullrestoreglobalbodyfont
+
+%D Here are some fast variants that can be used in cases where no font system is
+%D needed and where fonts are frozen:
+%D
+%D \starttyping
+%D \definefont [TestA][Serif at 10pt]
+%D \predefinefont[TestB][Serif at 20pt]
+%D
+%D \testfeatureonce{1000}{{\TestA}} % .312
+%D \testfeatureonce{1000}{{\TestB}} % < .016
+%D \testfeatureonce{1000}{{\definedfont[Serif at 30pt]}} % .312
+%D \testfeatureonce{1000}{{\predefinedfont[Serif at 40pt]}} % < .016
+%D \stoptyping
+
+\installcorenamespace{predefinedfont}
+
+\unexpanded\def\predefinefont[#1]#2[#3]% global !
+ {\setugvalue{#1}{\font_basics_predefine{#1}{#3}}}
+
+\unexpanded\def\predefinedfont[#1]% global !
+ {\ifcsname\??predefinedfont#1\endcsname
+ \lastnamedcs
+ \else
+ \font_basics_predefined{#1}%
+ \fi}
+
+\unexpanded\def\font_basics_predefine#1#2%
+ {\font_basics_defined_font_yes[#2]%
+ \expandafter\glet\csname#1\expandafter\endcsname\csname\v_font_identifier_basic\endcsname}
+
+\unexpanded\def\font_basics_predefined#1%
+ {\font_basics_predefine{\??predefinedfont#1}{#1}}
+
+%D Handy helper:
+
+\unexpanded\def\savedefinedfont[#1]%
+ {\bgroup
+ \definedfont[#1]%
+ \xdef\saveddefinedfontid {\number\fontid\font}%
+ \xdef\saveddefinedfontname{\fontname\font}%
+ \egroup}
+
+\def\saveddefinedfontid {\number\fontid\font}
+\def\saveddefinedfontname{\fontname\font}
+
+%D Ugly helper:
+
+\unexpanded\def\saverunningstyleandcolor
+ {\unexpanded\edef\restorerunningstyleandcolor
+ {\setfontid \number\fontid\font
+ \attribute\colormodelattribute \the\attribute\colormodelattribute
+ \attribute\colorattribute \the\attribute\colorattribute
+ \attribute\transparencyattribute\the\attribute\transparencyattribute
+ \relax}}
+
+\let\restorerunningstyleandcolor\relax
+
+%D Handy for defining additional glyphs:
+
+\let\getprivateglyphslot\clf_getprivateglyphslot % kind of private macro
+
+\let\getprivatechar \clf_getprivatechar % gives back a utf !
+\let\getprivatemathchar \clf_getprivatemathchar % gives back a utf !
+\let\getprivateslot \clf_getprivateslot % companion to fonts.helpers.addprivate
+
+% \unexpanded\def\getprivatemathchar#1%
+% {\begingroup\the\textfont\zerocount\getprivatechar{#1}\endgroup}
+
+\def\privatechar % the text variant gets expanded to utf
+ {\ifmmode
+ \expandafter\getprivatemathchar
+ \else
+ \expandafter\getprivatechar
+ \fi}
+
+%D Some fonts can have color specifiers:
+%D
+%D \starttyping
+%D \definefontfeature[seguiemj-cl][default][colr=yes,ccmp=yes,dist=yes]
+%D \definefontsynonym[emoji][seguiemj*seguiemj-cl]
+%D
+%D \definecolor[emoji-red] [r=.4]
+%D \definecolor[emoji-gray][s=1,t=.5,a=1]
+%D
+%D %definefontcolorpalette [emoji-r] [emoji-red,emoji-gray,textcolor] % bad
+%D \definefontcolorpalette [emoji-r] [emoji-red,emoji-gray] % okay
+%D
+%D \definefontfeature[seguiemj-r][ccmp=yes,dist=yes,colr=emoji-r]
+%D
+%D \definefont[MyEmojiR][seguiemj*seguiemj-r @ 100pt]
+%D
+%D \startTEXpage[offset=10pt]
+%D \MyEmojiR\resolvedemoji{triangular ruler}
+%D \stopTEXpage
+%D \stoptyping
+
+\unexpanded\def\definefontcolorpalette
+ {\dodoubleargument\font_define_color_palette}
+
+\def\font_define_color_palette[#1][#2]%
+ {\clf_definefontcolorpalette{#1}{#2}}
+
+%D \macros
+%D {addfontpath}
+%D
+%D A way to add a path at runtime (no need to generate database):
+
+\unexpanded\def\usefontpath[#1]%
+ {\clf_addfontpath{#1}}
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-ini.mkvi b/Master/texmf-dist/tex/context/base/mkiv/font-ini.mkvi
index dd8a5f14834..99e7117a38e 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-ini.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-ini.mkvi
@@ -53,8 +53,8 @@
\unprotect
-%D There are several ways to specify a font. Three of them are
-%D pure \TeX\ ones, the fourth one is new:
+%D There are several ways to specify a font. Three of them are pure \TEX\ ones, the
+%D fourth one is new:
%D
%D \starttyping
%D \font\name=cmr12
@@ -63,18 +63,15 @@
%D \font\name=cmr12 sa 1.440
%D \stoptyping
%D
-%D The non||\TEX\ alternative \type{sa} stands for {\em scaled
-%D at}. This means as much as: scale the bodyfontsize with this
-%D factor. The scaled option is not that useful as one needs to
-%D know the design size.
+%D The non||\TEX\ alternative \type{sa} stands for {\em scaled at}. This means as
+%D much as: scale the bodyfontsize with this factor. The scaled option is not that
+%D useful as one needs to know the design size.
%D
-%D Because \type {sa} (scaled at) and \type {mo} (mapped on)
-%D are not low level \TEX\ supported alternatives, we have to
-%D test for it ourselves. In doing so, we need an auxiliary
-%D \DIMENSION. We cannot use \type{\scratchdimen} because font
-%D loading can happen at any moment due to postponed loading.
-%D We could instead have used dirty grouping tricks, but this
-%D one works too.
+%D Because \type {sa} (scaled at) and \type {mo} (mapped on) are not low level \TEX\
+%D supported alternatives, we have to test for it ourselves. In doing so, we need an
+%D auxiliary \DIMENSION. We cannot use \type{\scratchdimen} because font loading can
+%D happen at any moment due to postponed loading. We could instead have used dirty
+%D grouping tricks, but this one works too.
% \enableexperiments[fonts.autorscale]
%
@@ -101,9 +98,8 @@
%D \macros
%D {rm,ss,tt,hw,cg}
%D
-%D Fonts are defined in separate files. When we define a font,
-%D we distinguish between several styles. In most cases we will
-%D use:
+%D Fonts are defined in separate files. When we define a font, we distinguish
+%D between several styles. In most cases we will use:
%D
%D \startlinecorrection
%D \starttable[|l||]
@@ -115,8 +111,8 @@
%D \stoptable
%D \stoplinecorrection
%D
-%D The number of styles is not limited to these three. When
-%D using Lucida Bright we can for instance also define:
+%D The number of styles is not limited to these three. When using Lucida Bright we
+%D can for instance also define:
%D
%D \startlinecorrection
%D \starttable[|l||]
@@ -127,8 +123,8 @@
%D \stoptable
%D \stoplinecorrection
%D
-%D Within such a font set (\type{cmr}) and style (\type{\rm})
-%D we can define a number of text font alternatives:
+%D Within such a font set (\type{cmr}) and style (\type{\rm}) we can define a number
+%D of text font alternatives:
%D
%D \startlinecorrection
%D \starttable[|l||]
@@ -145,12 +141,11 @@
%D \stoplinecorrection
%D
%D Internally fonts are stored as combination of size, style
-%D and alternative, e.g. \type{12pt}+\type{\ss}+\type{\bf}.
-%D Users are not confronted with sizes, but use the style or
-%D style+alternative to activate them.
+%D and alternative, e.g. \type{12pt}+\type{\ss}+\type{\bf}. Users are not confronted
+%D with sizes, but use the style or style+alternative to activate them.
%D
-%D During the definition of a bodyfont one can also declare the
-%D available larger alternatives:
+%D During the definition of a bodyfont one can also declare the available larger
+%D alternatives:
%D
%D \starttyping
%D \tf \tfa \tfb \tfc ...
@@ -167,13 +162,12 @@
%D \slx \slxx
%D \stoptyping
%D
-%D There are only two smaller alternatives per style. The
-%D larger alternatives on the other hand have no limitations.
+%D There are only two smaller alternatives per style. The larger alternatives on the
+%D other hand have no limitations.
%D
-%D These larger alternatives are mostly used in chapter and
-%D section titles or on title pages. When one switches to a
-%D larger alternative, the bold an other ones automatically
-%D adapt themselves:
+%D These larger alternatives are mostly used in chapter and section titles or on
+%D title pages. When one switches to a larger alternative, the bold an other ones
+%D automatically adapt themselves:
%D
%D \startbuffer
%D \tfd Hi \bf there\sl, here \tfb I \bf am
@@ -189,8 +183,8 @@
%D \getbuffer
%D \stopexample
%D
-%D Maybe this mechanism isn't always as logic, but as said
-%D before, we tried to make it as intuitive as possible.
+%D Maybe this mechanism isn't always as logic, but as said before, we tried to make
+%D it as intuitive as possible.
%D
%D So a specific kind of glyph can be characterized by:
%D
@@ -200,52 +194,43 @@
%D
%D The last component (the size) is optional.
%D
-%D We introduced \type{\tf} as command to call for the current
-%D normally sized typeface. This commands results in roman,
-%D sans serif, teletype or whatever style is in charge. Such
-%D rather massive switches of style sometimes take more
-%D processing time than comfortable. Of course there is a
-%D workaround for this: we can call fonts directly by means of
-%D commands like:
+%D We introduced \type {\tf} as command to call for the current normally sized
+%D typeface. This commands results in roman, sans serif, teletype or whatever style
+%D is in charge. Such rather massive switches of style sometimes take more
+%D processing time than comfortable. Of course there is a workaround for this: we
+%D can call fonts directly by means of commands like:
%D
%D \starttyping
%D \rmtf \sssl \tttf \rmbsa
%D \stoptyping
%D
-%D One should realize that this fast calls have limitations,
-%D they lack for instance automatic super- and subscript
-%D support.
-%D
-%D This leaves us two more commands: \type{\tx} and
-%D \type{\txx}. These activate a smaller and even more smaller
-%D font than the current one and adapt themselves to the
-%D current alternative, so when \type{\bf} is active,
-%D \type{\tx} gives a smaller boldface, which in turn can be
-%D called directly by \type{\bfx}.
-%D
-%D These two smaller alternatives are specified by the bodyfont
-%D environment and therefore not necessarily have similar sizes
-%D as \type{\scriptsize} and \type{\scriptscriptsize}. The main
-%D reason for this incompatibility (which can easily be undone)
-%D lays in the fact that we often want a bit bigger characters
-%D than in math mode. In \CONTEXT\ for instance the \type{\tx}
-%D and \type{\txx} commands are used for surrogate
-%D \cap{smallcaps} which support both nesting and alternatives,
-%D like in {\bf\cap{a \cap{small} world}}, which was typeset by
+%D One should realize that this fast calls have limitations, they lack for instance
+%D automatic super- and subscript support.
+%D
+%D This leaves us two more commands: \type {\tx} and \type {\txx}. These activate a
+%D smaller and even more smaller font than the current one and adapt themselves to
+%D the current alternative, so when \type {\bf} is active, \type {\tx} gives a
+%D smaller boldface, which in turn can be called directly by \type {\bfx}.
+%D
+%D These two smaller alternatives are specified by the bodyfont environment and
+%D therefore not necessarily have similar sizes as \type {\scriptsize} and \type
+%D {\scriptscriptsize}. The main reason for this incompatibility (which can easily
+%D be undone) lays in the fact that we often want a bit bigger characters than in
+%D math mode. In \CONTEXT\ for instance the \type {\tx} and \type {\txx} commands
+%D are used for surrogate \cap {smallcaps} which support both nesting and
+%D alternatives, like in {\bf \cap {a \cap {small} world}}, which was typeset by
%D
%D \starttyping
%D \bf\cap{a \cap{small} world}
%D \stoptyping
%D
-%D And compare $\rm \scriptstyle THIS$ with the slightly larger
-%D \cap{THIS}: \ruledhbox{$\rm \scriptstyle scriptstyle: THIS$}
-%D or \ruledhbox{\cap{x style: THIS}} makes a big difference.
+%D And compare $\rm \scriptstyle THIS$ with the slightly larger \cap {THIS}:
+%D \ruledhbox {$\rm \scriptstyle scriptstyle: THIS$} or \ruledhbox {\cap {x style:
+%D THIS}} makes a big difference.
%D
-%D The \type{x..d} sizes should be used grouped. If you
-%D don't group them, i.e. call them in a row, \CONTEXT\ will
-%D not be able to sort out your intention (\type {x} inside
-%D \type {d} inside \type {x}. etc.). The following table
-%D demonstrates this:
+%D The \type {x..d} sizes should be used grouped. If you don't group them, i.e. call
+%D them in a row, \CONTEXT\ will not be able to sort out your intention (\type {x}
+%D inside \type {d} inside \type {x}. etc.). The following table demonstrates this:
%D
%D \def\FontState{\setstrut\ruledhbox{\strut Hello}}
%D
@@ -327,6 +312,16 @@
\fontemwidth \nullfont 786432\scaledpoint
\fontextraspace \nullfont 85459\scaledpoint
+\appendtoks
+ \fontslantperpoint \nullfont 0\scaledpoint
+ \fontinterwordspace \nullfont 256377\scaledpoint
+ \fontinterwordstretch\nullfont 128188\scaledpoint
+ \fontinterwordshrink \nullfont 85459\scaledpoint
+ \fontexheight \nullfont 338952\scaledpoint
+ \fontemwidth \nullfont 786432\scaledpoint
+ \fontextraspace \nullfont 85459\scaledpoint
+\to \everyjob
+
%D Tracing
\newtoks\t_font_tracers_definitions
@@ -388,10 +383,9 @@
%D \macros
%D {everybodyfont,everyglobalbodyfont}
%D
-%D Every change in bodyfont size has conseqences for the baseline
-%D distance and skips between paragraphs. These are initialized
-%D in other modules. Here we only provide the hooks that
-%D garantees their handling.
+%D Every change in bodyfont size has conseqences for the baseline distance and skips
+%D between paragraphs. These are initialized in other modules. Here we only provide
+%D the hooks that garantees their handling.
%D
%D At the system level one can initialize thing like:
%D
@@ -401,20 +395,19 @@
%D \macros
%D {globalbodyfontsize,localbodyfontsize,bodyfontsize}
-
-%D Here we have to distinguish between the global (overal) bodyfont
-%D size and the local (sometimes in the textflow) size. We store
-%D these dimensions in two \DIMENSION\ registers. These registers are
-%D not to be misused in calculations.
+%D
+%D Here we have to distinguish between the global (overal) bodyfont size and the
+%D local (sometimes in the textflow) size. We store these dimensions in two
+%D \DIMENSION\ registers. These registers are not to be misused in calculations.
\ifdefined\globalbodyfontsize\else \newdimen\globalbodyfontsize \fi \globalbodyfontsize=12pt
\ifdefined\localbodyfontsize \else \newdimen\localbodyfontsize \fi \localbodyfontsize =\globalbodyfontsize
\ifdefined\bodyfontsize \else \newdimen\bodyfontsize \fi \bodyfontsize =\globalbodyfontsize
-%D When we assign for instance 12pt to a \DIMENSION\ register the \type
-%D {\the}'d value comes out as 12.0pt, which is often not the way users
-%D specify the bodyfont size. Therefore we use normalized values. They
-%D are cached to save overhead in \LUA\ calls.
+%D When we assign for instance 12pt to a \DIMENSION\ register the \type {\the}'d
+%D value comes out as 12.0pt, which is often not the way users specify the bodyfont
+%D size. Therefore we use normalized values. They are cached to save overhead in
+%D \LUA\ calls.
% \setnewconstant\fontdigits\plustwo % from now on always 2
@@ -455,11 +448,10 @@
%D \macros
%D {mapfontsize}
%D
-%D For special purposes, like in math, you may want to use
-%D slightly different sizes than the ones given. This happens
-%D for instance with the Math Times fonts. Mapped font sizes
-%D can be specified by using the \type {mo} key instead of
-%D \type {sa} in font definitions.
+%D For special purposes, like in math, you may want to use slightly different sizes
+%D than the ones given. This happens for instance with the Math Times fonts. Mapped
+%D font sizes can be specified by using the \type {mo} key instead of \type {sa} in
+%D font definitions.
%D
%D \startbuffer
%D \mapfontsize[10pt][11pt]
@@ -548,10 +540,9 @@
%D \macros
%D {definefontstyle,definefontsize,definefontalternative}
%D
-%D When setting of switching the overall style we can use the
-%D short identifier like rm and ss, but when defined we can
-%D also use more verbose names like roman or sansserif. Such
-%D names are defined by:
+%D When setting of switching the overall style we can use the short identifier like
+%D rm and ss, but when defined we can also use more verbose names like roman or
+%D sansserif. Such names are defined by:
%D
%D \starttyping
%D \definefontstyle [serif,rm] [rm]
@@ -623,12 +614,12 @@
\definefontstyle [\s!ss] [\s!ss]
\definefontstyle [\s!tt] [\s!tt]
-%D We define all the font switching commands globally. After all they are part
-%D of the formal font interface once defined. The size can be empty (so
-%D checking is needed as \type {\bf} is already defined)
-
-%D The \type {\normal..} variants are available as extras for cases where
-%D the \type {..} is overloaded.
+%D We define all the font switching commands globally. After all they are part of
+%D the formal font interface once defined. The size can be empty (so checking is
+%D needed as \type {\bf} is already defined).
+%D
+%D The \type {\normal..} variants are available as extras for cases where the \type
+%D {..} is overloaded.
\newmacro\m_font_mm
@@ -714,23 +705,20 @@
%D Scaling macros:
%D
-%D This system is somewhat complicated by two (possible conflicting)
-%D demands:
+%D This system is somewhat complicated by two (possible conflicting) demands:
%D
%D \startitemize
-%D \item We support wildcards like \type {sa *} which will adapt
-%D to the current size. This is also the default specification.
-%D \item We support named scales like \type {sa d}; beware: \type
-%D {x} and \type {xx} are valid scales but they are not alway
-%D the same as the ones used in for instance \type {\bfx} because
-%D there the sized come from the bodyfont environment. In the
-%D future there maybe a switch that also honors the environment
-%D in named scales.
+%D \item We support wildcards like \type {sa *} which will adapt to the current
+%D size. This is also the default specification.
+%D \item We support named scales like \type {sa d}; beware: \type {x} and \type {xx}
+%D are valid scales but they are not alway the same as the ones used in for
+%D instance \type {\bfx} because there the sized come from the bodyfont
+%D environment. In the future there maybe a switch that also honors the
+%D environment in named scales.
%D \stopitemize
%D
-%D Keep in mind that the smaller sizes are just for text super and
-%D subscripts while larger sizes can be used in titles where for
-%D instance math follows the size.
+%D Keep in mind that the smaller sizes are just for text super and subscripts while
+%D larger sizes can be used in titles where for instance math follows the size.
% b:x{\definedfont[SerifBold sa b]x}{\bfb x $x^x$}\par
% 1:x{\definedfont[SerifBold sa 1]x}{\bf x $x^x$}\par
@@ -983,8 +971,7 @@
%D
%D We also accept \type{sa a}||\type{sa d} as specification.
%D
-%D Before we implement the main definition macro, we first show
-%D one for local use:
+%D Before we implement the main definition macro, we first show one for local use:
%D
%D \starttyping
%D \definefont[Some][LucidaBright at 100pt] \Some some
@@ -1110,9 +1097,8 @@
%D \macros
%D {currentfontbodyscale}
%D
-%D Sometimes we need to have access to the font scale
-%D including the \type{a}||\type{d} sizes. The next macro
-%D returns the current scaling factor. Take a look at
+%D Sometimes we need to have access to the font scale including the \type {a}||\type
+%D {d} sizes. The next macro returns the current scaling factor. Take a look at
%D \type {cont-log.tex} for an example of its use.
\installcorenamespace{fontenvironments}
@@ -1182,30 +1168,27 @@
\setvalue{\??fontenvironments\s!default}{1}
-%D In the following macros we use \type{\currentxfontsize} to
-%D hold the current x||size of the font. This enables us to
-%D support for instance \type{\sl} inside a \type{\tx} switch.
+%D In the following macros we use \type {\currentxfontsize} to hold the current
+%D x||size of the font. This enables us to support for instance \type {\sl} inside a
+%D \type {\tx} switch.
\newconstant\currentxfontsize
\def\xfontsize{\ifcase\currentxfontsize\fontsize\or\s!x\else\s!xx\fi}
-%D Now we enter the area of font switching. The switching
-%D mechanism has to take care of several situations, like:
+%D Now we enter the area of font switching. The switching mechanism has to take care
+%D of several situations, like:
%D
%D \startitemize[packed]
-%D \item changing the overal document fonts (including margins,
-%D headers and footers)
-%D \item changing local fonts (only the running text)
-%D \item smaller and even more smaller alternatives (super-
-%D and subscripts)
+%D \item changing the overal document fonts (including margins, headers and footers)
+%D \item changing local fonts (only the running text)
+%D \item smaller and even more smaller alternatives (super- and subscripts)
%D \stopitemize
%D
-%D \TEX\ offers a powerfull family mechanism for super- and
-%D subscripts in math mode. In text mode however, we don't use
-%D families for the smaller alternatives, and therefore have
-%D to take care of it otherwise.
-
+%D \TEX\ offers a powerfull family mechanism for super- and subscripts in math mode.
+%D In text mode however, we don't use families for the smaller alternatives, and
+%D therefore have to take care of it otherwise.
+%D
%D \macros
%D {definebodyfontenvironment,setupbodyfontenvironment}
%D
@@ -1214,8 +1197,8 @@
%D
%D \showsetup{definebodyfontenvironment}
%D
-%D Later on we will see how these parameters are used, so for
-%D the moment we stick with an example:
+%D Later on we will see how these parameters are used, so for the moment we stick
+%D with an example:
%D
%D \starttyping
%D \definebodyfontenvironment
@@ -1229,9 +1212,9 @@
%D small=10pt]
%D \stoptyping
%D
-%D The first argument specifies the bodyfont size to which the
-%D settings apply. All second parameters are specified in
-%D dimensions and tell us more about related sizes.
+%D The first argument specifies the bodyfont size to which the settings apply. All
+%D second parameters are specified in dimensions and tell us more about related
+%D sizes.
%D
%D Afterwards, one can change values with
%D
@@ -1241,8 +1224,8 @@
%D passed, fractions (relations) are used instead of fixed
%D sizes.
-%D {\bf Remark:} We need to cover the following cases, otherwise users can
-%D get confused:
+%D {\bf Remark:} We need to cover the following cases, otherwise users can get
+%D confused:
%D
%D \starttyping
%D \setupbodyfont[23pt]
@@ -1255,10 +1238,9 @@
%D \setupbodyfont[23pt]
%D \stoptyping
%D
-%D Beware: while some font defs can be global, the bodyfont
-%D environment checks local. This means that multiple local
-%D checks resulting in definitions are not that efficient.
-%D So, apart from an occasional switch, one should define an
+%D Beware: while some font defs can be global, the bodyfont environment checks
+%D local. This means that multiple local checks resulting in definitions are not
+%D that efficient. So, apart from an occasional switch, one should define an
%D environment at the outer level.
% \definebodyfontenvironment[33pt]
@@ -1373,8 +1355,8 @@
\clf_registerbodyfontsize{\m_font_body_normalized}%
\fi}
-%D The empty case uses the same code but needs to ignore the current class
-%D settings (just to be sure, as it's not really needed).
+%D The empty case uses the same code but needs to ignore the current class settings
+%D (just to be sure, as it's not really needed).
\def\font_basics_define_body_font_environment_empty[#body][#settings][#dummy]%
{\push_macro_fontclass
@@ -1423,36 +1405,33 @@
\font_helpers_define_unknown_font{#normalizedbody}%
\fi}
-%D We default all parameters to the main bodyfont size, so the next
-%D setup is valid too:
+%D We default all parameters to the main bodyfont size, so the next setup is valid
+%D too:
%D
%D \starttyping
%D \definebodyfontenvironment[24pt]
%D \stoptyping
%D
-%D All parameters can be redefined when needed, so one doesnot have to
-%D stick to the default ones.
+%D All parameters can be redefined when needed, so one doesnot have to stick to the
+%D default ones.
%D \macros
%D {definebodyfont}
%D
-%D The next step in defining a bodyfont involves the actual font
-%D files, which can be recognized by their extension
-%D \type{tfm}. Installing those file is often beyond the
-%D scope of the user and up to the system administrator.
+%D The next step in defining a bodyfont involves the actual font files, which can be
+%D recognized by their extension \type {tfm}. Installing those file is often beyond
+%D the scope of the user and up to the system administrator.
%D
%D \showsetup{definebodyfont}
%D
-%D This commands takes three arguments: a (series of) bodyfont
-%D size(s), the style group to which the definitions belong,
-%D and an alternative, as specified by the \TEX\ (math) families,
-%D extended with~a, b~\unknown.
+%D This commands takes three arguments: a (series of) bodyfont size(s), the style
+%D group to which the definitions belong, and an alternative, as specified by the
+%D \TEX\ (math) families, extended with~a, b~\unknown.
%D
-%D We show two examples, that show all the alternative
-%D scaling options. The \type{\tfa} alternatives can be
-%D extended with \type{\bfa}, \type{\slb}, etc. or even
-%D \type{e} and higher alternatives. The magic scaled
-%D values are derived from plain \TEX's \type {\magstep}:
+%D We show two examples, that show all the alternative scaling options. The \type
+%D {\tfa} alternatives can be extended with \type {\bfa}, \type {\slb}, etc. or even
+%D \type {e} and higher alternatives. The magic scaled values are derived from plain
+%D \TEX's \type {\magstep}:
%D
%D \starttyping
%D \definebodyfont [12pt] [rm]
@@ -1482,29 +1461,25 @@
%D sc=lbr sa 0.833]
%D \stoptyping
%D
-%D The second example shows that we can define more sizes at
-%D once. The main difference between these examples is that the
-%D Computer Modern Roman come in many design sizes. This means
-%D that there we cannot define them in bulk using \type{sa}.
-%D Instead of \type{rm} (roman) one can define \type{ss} (sans
-%D serif), \type{tt} (teletype), \type{hw} (hand written),
-%D \type{cg} (calygraphic) and whatever styles.
-%D
-%D The first argument may be a comma separated list. This,
-%D combined with specifications using \type{sa} can save a lot
-%D of typing. Although all arguments should be specified, we
-%D treat the second argument as optional.
-%D
-%D Defining a bodyfont involves two actions: defining the
-%D specific style related alternatives, like \type{\rma},
-%D \type{\bfa} and \type{\rmsla}, and storing the definitions
-%D of their bodyfont size related fonts. The first step is
-%D bodyfont independant but executed every time. This permits
-%D user definitions like \type{\tfw} or \type{\bfq} for real
-%D large alternatives.
-
-%D If we move design size info to the lfg file (after all only lm
-%D has design sizes) we can get rid of much code .. 2012 or so.
+%D The second example shows that we can define more sizes at once. The main
+%D difference between these examples is that the Computer Modern Roman come in many
+%D design sizes. This means that there we cannot define them in bulk using \type
+%D {sa}. Instead of \type {rm} (roman) one can define \type {ss} (sans serif), \type
+%D {tt} (teletype), \type {hw} (hand written), \type {cg} (calygraphic) and whatever
+%D styles.
+%D
+%D The first argument may be a comma separated list. This, combined with
+%D specifications using \type{sa} can save a lot of typing. Although all arguments
+%D should be specified, we treat the second argument as optional.
+%D
+%D Defining a bodyfont involves two actions: defining the specific style related
+%D alternatives, like \type {\rma}, \type {\bfa} and \type {\rmsla}, and storing the
+%D definitions of their bodyfont size related fonts. The first step is bodyfont
+%D independant but executed every time. This permits user definitions like \type
+%D {\tfw} or \type {\bfq} for real large alternatives.
+%D
+%D If we move design size info to the lfg file (after all only lm has design sizes)
+%D we can get rid of much code .. 2012 or so.
\installcorenamespace{fontdefinitions}
@@ -1555,17 +1530,33 @@
\font_basics_define_body_font_name
[#whatever]}
+% \unexpanded\def\font_basics_define_body_font_body[#body][#style][#specification]%
+% {\doifelseassignment{#specification}
+% \font_basics_define_body_font_body_assignment
+% \font_basics_define_body_font_body_identifier
+% [#body][#style][#specification]}%
+
\unexpanded\def\font_basics_define_body_font_body[#body][#style][#specification]%
- {\doifelseassignment{#specification}
- \font_basics_define_body_font_body_assignment
- \font_basics_define_body_font_body_identifier
- [#body][#style][#specification]}%
+ {\ifcondition\validassignment{#specification}%
+ \expandafter\font_basics_define_body_font_body_assignment
+ \else
+ \expandafter\font_basics_define_body_font_body_identifier
+ \fi
+ [#body][#style][#specification]}%
+
+% \unexpanded\def\font_basics_define_body_font_name[#name][#style][#specification]%
+% {\doifelseassignment{#specification}
+% \font_basics_define_body_font_name_assignment
+% \font_basics_define_body_font_name_identifier
+% [#name][#style][#specification]}%
\unexpanded\def\font_basics_define_body_font_name[#name][#style][#specification]%
- {\doifelseassignment{#specification}
- \font_basics_define_body_font_name_assignment
- \font_basics_define_body_font_name_identifier
- [#name][#style][#specification]}%
+ {\ifcondition\validassignment{#specification}%
+ \expandafter\font_basics_define_body_font_name_assignment
+ \else
+ \expandafter\font_basics_define_body_font_name_identifier
+ \fi
+ [#name][#style][#specification]}%
\unexpanded\def\font_basics_define_body_font_body_assignment[#bodylist][#stylelist][#assignments]%
{\processcommalist[#bodylist]{\font_basics_define_body_font_body_assignment_a{#stylelist}{#assignments}}}
@@ -1625,9 +1616,9 @@
\let\font_basics_define_body_font_defs_nop\font_basics_define_body_font_defs_nop_traced
\to \t_font_tracers_definitions
-% We split into two characters (first part of spec) and the rest: the first two are the style and
-% the rest is a size, although in practice one will seldom define the size directly. We might even
-% drop that as it gives faster code.
+%D We split into two characters (first part of spec) and the rest: the first two are
+%D the style and the rest is a size, although in practice one will seldom define the
+%D size directly. We might even drop that as it gives faster code.
\unexpanded\def\font_basics_define_body_font_nop_xx[#one#two#rest=#value]% local
{\ifcsname\m_font_asked_style#one#two#rest\endcsname\else\font_basics_check_fontname_combination\m_font_asked_style{#one#two}{#rest}\fi
@@ -1818,9 +1809,8 @@
\showmessage\m!fonts5{#style}%
\fi}
-%D Here comes the main font switching macros. These macros
-%D handle changes in size as well as returning to the global
-%D bodyfont size.
+%D Here comes the main font switching macros. These macros handle changes in size as
+%D well as returning to the global bodyfont size.
\ifdefined\font_preloads_at_definition \else \let\font_preloads_at_definition\relax \fi
@@ -1996,8 +1986,8 @@
\the\everyfontswitch
\fi}
-%D This is the resolver for special cases (sizes) and in practice it is not called that often
-%D so further optimization makes no sense.
+%D This is the resolver for special cases (sizes) and in practice it is not called
+%D that often so further optimization makes no sense.
\def\font_helpers_check_strategy_class_a % --- --- --- --- % pt tt bf a
{\ifcsname\??fontinstanceready\fontclass-\fontbody-\fontstyle-\fontalternative-\fontsize-\fontface\endcsname
@@ -2109,12 +2099,11 @@
\fi
\to \everybodyfont
-%D Setting the normal sizes as well as the x and xx smaller
-%D sizes is accomplished by the next set of macros. When in
-%D math mode, the commands \type{\tx} and \type{\txx} are
-%D just a switch to the script and double script styles, but
-%D in text mode the values defined by the bodyfontenvironment are
-%D used. Here we also set \type{\currentxfontsize}.
+%D Setting the normal sizes as well as the x and xx smaller sizes is accomplished by
+%D the next set of macros. When in math mode, the commands \type {\tx} and \type
+%D {\txx} are just a switch to the script and double script styles, but in text mode
+%D the values defined by the bodyfontenvironment are used. Here we also set \type
+%D {\currentxfontsize}.
\def\font_helpers_set_current_font_xxx_alternative#alternative#xsize#scriptstyle%
{\ifmmode
@@ -2155,15 +2144,14 @@
\let\tx\empty
\let\txx\empty}
-% This alterative is not really needed, but for old time's sake
-% we keep it there. We can speed it up when needed.
+%D This alterative is not really needed, but for old time's sake we keep it there.
+%D We can speed it up when needed.
\def\font_helpers_set_current_font_x_style_alternative #alternative{\csname#alternative\endcsname\tx}
\def\font_helpers_set_current_font_xx_style_alternative#alternative{\csname#alternative\endcsname\txx}
-%D These macros also show us that when we call for \type{\tx},
-%D this macro is redefined to be \type{\txx}. Therefore calls
-%D like:
+%D These macros also show us that when we call for \type {\tx}, this macro is
+%D redefined to be \type {\txx}. Therefore calls like:
%D
%D \startbuffer
%D {small \tx is \tx beautiful}
@@ -2180,9 +2168,8 @@
%D \getbuffer
%D \stoplines
%D
-%D Setting the main size involves the style list and therefore
-%D takes a bit more time. Keep in mind that the fontsize is
-%D represented by a character or empty.
+%D Setting the main size involves the style list and therefore takes a bit more
+%D time. Keep in mind that the fontsize is represented by a character or empty.
% \unexpanded\def\tx {\font_helpers_set_current_font_x_alternative \fontalternative}
% \unexpanded\def\txx{\font_helpers_set_current_font_xx_alternative\fontalternative}
@@ -2317,13 +2304,11 @@
\let\normalsx \sx
\let\normalsxx\sxx
-%D When asking for a complete font switch, for instance from 10
-%D to 12~points, the next macro does the job. First we
-%D normalize the size, next we define the current range of
-%D text, script and scriptscript sizes, then we set the text
-%D fonts and the math families and finally we activate the
-%D default typeface and also set the font specific parameters
-%D assigned to \type{\everybodyfont}
+%D When asking for a complete font switch, for instance from 10 to 12~points, the
+%D next macro does the job. First we normalize the size, next we define the current
+%D range of text, script and scriptscript sizes, then we set the text fonts and the
+%D math families and finally we activate the default typeface and also set the font
+%D specific parameters assigned to \type {\everybodyfont}.
\def\textface {\currentbodyfontdimension\s!text }
\def\scriptface {\currentbodyfontdimension\s!script }
@@ -2390,16 +2375,16 @@
%D \macros
%D {setupbodyfont,switchtobodyfont}
%D
-%D The next two macros are user ones. With \type{\setupbodyfont}
-%D one can set the document bodyfont size, font family, style
-%D and/or options defined in files, for example:
+%D The next two macros are user ones. With \type {\setupbodyfont} one can set the
+%D document bodyfont size, font family, style and/or options defined in files, for
+%D example:
%D
%D \starttyping
%D \setupbodyfont[modern,12pt,roman]
%D \stoptyping
%D
-%D This command affects the document as a whole: text, headers
-%D and footers. The second macro however affects only the text:
+%D This command affects the document as a whole: text, headers and footers. The
+%D second macro however affects only the text:
%D
%D \starttyping
%D \switchtobodyfont[10pt]
@@ -2410,8 +2395,8 @@
%D \showsetup{setupbodyfont}
%D \showsetup{switchtobodyfont}
%D
-%D Both macros look alike. The second one also has to take
-%D all kind of keywords into account.
+%D Both macros look alike. The second one also has to take all kind of keywords into
+%D account.
\ifx\saveinterlinespace \undefined \let\saveinterlinespace \relax \fi
\ifx\restoreinterlinespace\undefined \let\restoreinterlinespace\relax \fi
@@ -2462,8 +2447,8 @@
{\font_basics_switch_points\m_font_step
\font_basics_switch_style \fontstyle}
-%D The following alternative is meant for math||to||text
-%D switching and will be optimized.
+%D The following alternative is meant for math||to||text switching and will be
+%D optimized.
\unexpanded\def\fastswitchtobodyfont#name%
{\ifcsname\??fontenvironments\normalizedbodyfontsize#name\endcsname
@@ -2582,9 +2567,8 @@
%D \macros
%D {definebodyfontswitch}
%D
-%D \PLAIN\ \TEX\ defines some macro's like \type{\tenpoint}
-%D to switch to a specific bodyfontsize. Just for the sake of
-%D compatibility we can define them like:
+%D \PLAIN\ \TEX\ defines some macro's like \type {\tenpoint} to switch to a specific
+%D bodyfontsize. Just for the sake of compatibility we can define them like:
%D
%D \starttyping
%D \definebodyfontswitch [twelvepoint] [12pt]
@@ -2601,11 +2585,10 @@
%D \macros
%D {setsmallbodyfont,setmainbodyfont,setbigbodyfont}
%D
-%D When we're typesetting at for instance 10pt, we can call for
-%D the \type{small} as well as the \type{big} alternative,
-%D related to this main size, using \type{\switchtobodyfont[small]}.
-%D The three alternatives can be activated by the next three
-%D system calls and are defined by the bodyfontenvironment.
+%D When we're typesetting at for instance 10pt, we can call for the \type {small} as
+%D well as the \type {big} alternative, related to this main size, using \type
+%D {\switchtobodyfont[small]}. The three alternatives can be activated by the next
+%D three system calls and are defined by the bodyfontenvironment.
\newmacro\m_font_step
@@ -2627,17 +2610,15 @@
%D \macros
%D {restoreglobalbodyfont}
%D
-%D Users can set whatever font available while typesetting text.
-%D Pagenumbers, footers, headers etc. however must be typeset
-%D in the main bodyfont and style of the document. Returning to
-%D the global state can be done with the next macro:
+%D Users can set whatever font available while typesetting text. Pagenumbers,
+%D footers, headers etc. however must be typeset in the main bodyfont and style of
+%D the document. Returning to the global state can be done with the next macro:
%D
-%D This macro has to be called when entering the pagebody
-%D handling routine as well as the footnote insert routine.
-%D Users can access this feature |<|for instance when one wants
-%D to typeset tables and alike in the main bodyfont and style
-%D while the running text is temporary set to a smaller one|>|
-%D by saying \type{\switchtobodyfont[global]}.
+%D This macro has to be called when entering the pagebody handling routine as well
+%D as the footnote insert routine. Users can access this feature |<|for instance
+%D when one wants to typeset tables and alike in the main bodyfont and style while
+%D the running text is temporary set to a smaller one|>| by saying \type
+%D {\switchtobodyfont [global]}.
\let\globalfontstyle\s!rm
@@ -2683,8 +2664,8 @@
% in case of troubles: \let\restorebodyfont\fullrestoreglobalbodyfont
-%D Here are some fast variants that can be used in cases where no font
-%D system is needed and where fonts are frozen:
+%D Here are some fast variants that can be used in cases where no font system is
+%D needed and where fonts are frozen:
%D
%D \starttyping
%D \definefont [TestA][Serif at 10pt]
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-lib.mkvi b/Master/texmf-dist/tex/context/base/mkiv/font-lib.mkvi
index 081ae0f388c..8953c9b320b 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-lib.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-lib.mkvi
@@ -28,7 +28,6 @@
% helpers
-
\registerctxluafile{font-otr}{optimize} % opentype fontloader
\registerctxluafile{font-web}{} % opentype fontloader
\registerctxluafile{font-cff}{optimize} % quadratic outlines
@@ -50,8 +49,19 @@
\registerctxluafile{font-otc}{}
\registerctxluafile{font-oth}{}
\registerctxluafile{font-osd}{}
-% \doifelsefileexists{font-osm.lua}{\registerctxluafile{font-osm}{}}{}
-\registerctxluafile{font-ocl}{}
+%registerctxluafile{font-osm}{}
+
+\ifcase\contextlmtxmode
+ \ifnum\luatexversion>111
+ \doifelsefileexists{font-ocm.lua}
+ {\registerctxluafile{font-ocm}{}} % mkiv new
+ {\registerctxluafile{font-ocl}{}}
+ \else
+ \registerctxluafile{font-ocl}{} % generic (will become luatex-fonts-ocl)
+ \fi
+\else
+ \registerctxluafile{font-ogr}{} % lmtx
+\fi
% we use otf code for type one
@@ -61,12 +71,8 @@
% tfm
-\doifelsefileexists {font-tpk.lua} {
- \registerctxluafile{font-tpk}{optimize}
- \registerctxluafile{font-tfm}{}
-} {
- \registerctxluafile{font-tfm}{}
-}
+\registerctxluafile{font-tpk}{optimize}
+\registerctxluafile{font-tfm}{}
% name database
@@ -111,6 +117,7 @@
\registerctxluafile{font-imp-quality}{}
\registerctxluafile{font-imp-italics}{}
\registerctxluafile{font-imp-dimensions}{}
+\registerctxluafile{font-imp-spacekerns}{}
\doifelsefileexists{font-imp-scripts.lua} {
\registerctxluafile{font-imp-scripts}{}
@@ -153,5 +160,21 @@
\def\cleanfontname #1{\clf_cleanfontname{#1}}
\unexpanded\def\setfontofid #1{\clf_setfontofid\numexpr#1\relax}
+% this is an ugly hack needed for postponed inclusion stuff ... don't try
+% to understand this ... these are kind of old mkiv solutions
+
+\unexpanded\def\typethreefont#1{\setfontid#1\relax}
+\unexpanded\def\typethreechar#1{\char#1\hskip-\fontcharwd\font#1\relax}
+\unexpanded\def\typethreelast#1{\char#1\relax}
+\unexpanded\def\typethreecode#1{\pdfliteral direct {#1}}
+
+\newtoks\typethreetoks
+\let \typethreemacro\empty
+
+\typethreetoks {%
+ \setbox\zerocount\hpack{\typethreemacro}%
+ \setbox\zerocount\hpack{\raise\dp\zerocount\box\zerocount}%
+}
+
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-mat.mklx b/Master/texmf-dist/tex/context/base/mkiv/font-mat.mklx
new file mode 100644
index 00000000000..d08a2ce879f
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-mat.mklx
@@ -0,0 +1,500 @@
+%D \module
+%D [ file=font-mat,
+%D version=2011.01.13, % (copied fron font-ini)
+%D title=\CONTEXT\ Font Macros,
+%D subtitle=Math,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Font Macros / Math}
+
+\unprotect
+
+%D Be nice:
+
+\ifdefined\??fontinstanceready \else \installcorenamespace{fontinstanceready} \fi
+\ifdefined\??fontinstancebasic \else \installcorenamespace{fontinstancebasic} \fi
+\ifdefined\??fontinstanceclass \else \installcorenamespace{fontinstanceclass} \fi
+
+%D The order 3 2 1 of siuze matters: needed for math-fbk relative size storage!
+
+%D \macros
+%D {textonly}
+%D
+%D Traditionally math has a big impact on font definitions, mainly because we need
+%D to define alphabet variants using families and fonts. This means that one can
+%D easily get 10 fonts loaded per math size. In \MKIV\ we use a different approach:
+%D one family which has either a virtual font made of traditional fonts, or an
+%D \OPENTYPE\ font that has it all.
+%D
+%D We currently use only one math family but in the future we might consider using a
+%D second one for bold math. For the moment we keep the \MKII\ method of using a
+%D token register for definitions but we already dropped the text and symbols ones
+%D since they now live in the same family.
+
+\newtoks \t_font_math_strategies
+\newconditional\c_font_synchronize_math_fonts \settrue\c_font_synchronize_math_fonts
+
+\unexpanded\def\font_helpers_synchronize_math % math stuff in mmode
+ {\ifconditional\c_font_synchronize_math_fonts\the\t_font_math_strategies\fi}
+
+\unexpanded\def\textonly{\setfalse\c_font_synchronize_math_fonts} % document this
+
+%D The main math font definer. We have removed some optimized code simply because we
+%D now always have a fontclass. We could check for fontclass being default or empty
+%D and save a few tests but it does not help us when no math is defined.
+%D
+%D Because we want to keep mr=.. and mb=... settings (read: not break downward
+%D compatibility by enforcing mrlr etc) we need a bit more code that optimal.
+
+% todo: \c_font_fam_mr
+
+\let\c_font_fam_mr \zerocount % math regular
+\let\c_font_fam_mr_lr\plusone % math regular l2r
+\let\c_font_fam_mr_rl\plustwo % math regular r2l
+
+\let\c_font_fam_mb \plusthree % math bold
+\let\c_font_fam_mb_lr\plusfour % math bold l2r
+\let\c_font_fam_mb_rl\plusfive % math bold r2l
+
+\definesystemattribute[mathfamily][public]
+
+\newconditional\c_font_bidirectional_mathstrategy % can be default, not that much overhead: \settrue\c_font_bidirectional_mathstrategy
+\newconditional\c_font_complete_bold_mathstrategy \settrue\c_font_complete_bold_mathstrategy
+
+\def\mathtextsuffix {-text}
+\def\mathscriptsuffix {-script}
+\def\mathscriptscriptsuffix{-scriptscript}
+
+\def\mathsizesuffix{\ifcase\fontface\or\mathtextsuffix\or\mathscriptsuffix\or\mathscriptscriptsuffix\fi}
+
+%D Beware: truefontname also does a fallback on defaultfontclass so there
+%D can be some interference here, which is why we use a different method
+%D for bold.
+
+\def\font_helpers_set_math_family_a
+ {\ifcsname\??fontinstanceready\fontclass -\fontbody-\s!mm-\fontfamily-\fontsize\endcsname \setfalse\c_font_auto_size
+ \lastnamedcs \orelse
+ \ifcsname\??fontinstanceready\fontclass -\fontbody-\s!mm-\fontfamily \endcsname \settrue \c_font_auto_size
+ \lastnamedcs \else
+ \font_helpers_set_math_family_b
+ \fi}
+
+\def\font_helpers_set_math_family_b
+ {\ifcsname\??fontinstanceready\defaultfontclass-\fontbody-\s!mm-\fontfamily-\fontsize\endcsname \setfalse\c_font_auto_size
+ \lastnamedcs \orelse
+ \ifcsname\??fontinstanceready\defaultfontclass-\fontbody-\s!mm-\fontfamily \endcsname \settrue \c_font_auto_size
+ \lastnamedcs \else
+ \font_helpers_set_math_family_c
+ \fi}
+
+\def\font_helpers_set_math_family_c
+ {\ifcsname\??fontinstanceready \fontbody-\s!mm-\fontfamily-\fontsize\endcsname \setfalse\c_font_auto_size
+ \lastnamedcs \orelse
+ \ifcsname\??fontinstanceready \fontbody-\s!mm-\fontfamily \endcsname \settrue \c_font_auto_size
+ \lastnamedcs \else
+ \settrue \c_font_auto_size
+ \fi}
+
+\let\mathsizesuffix\empty
+
+\def\font_helpers_set_math_family_indeed#mrtag#family% \fontface etc are also used later on
+ {\let\savedfontbody\fontbody
+ \let\fontfamily#family%
+ % the order is important as we depend on known id's when completing fonts
+ % enabling is needed when we have fallbacks which spoils the families
+ \let\mathsizesuffix\mathscriptscriptsuffix\let\fontface\!!plusthree
+ \font_helpers_set_math_family_a\scriptscriptfont#mrtag\font % defines
+ \font_helpers_set_math_family_a\scriptscriptfont#mrtag\font % enables
+ \let\mathsizesuffix\mathscriptsuffix \let\fontface\!!plustwo
+ \font_helpers_set_math_family_a\scriptfont #mrtag\font % defines
+ \font_helpers_set_math_family_a\scriptfont #mrtag\font % enables
+ \let\mathsizesuffix\mathtextsuffix \let\fontface\!!plusone
+ \font_helpers_set_math_family_a\textfont #mrtag\font % defines
+ \font_helpers_set_math_family_a\textfont #mrtag\font % enables
+ \let\mathsizesuffix\empty \let\fontface\!!zerocount
+ \let\fontbody\savedfontbody
+ \setfalse\c_font_auto_size}
+
+\def\font_helpers_set_math_family_bold_a#font#mbfam#mrfam%
+ {\ifcsname\??fontinstanceready\fontclass-\fontbody-\s!mm-\fontfamily-\fontsize\endcsname \setfalse\c_font_auto_size
+ \lastnamedcs #font#mbfam\font \orelse
+ \ifcsname\??fontinstanceready\fontclass-\fontbody-\s!mm-\fontfamily \endcsname \settrue \c_font_auto_size
+ \lastnamedcs #font#mbfam\font \else
+ #font#mbfam#font#mrfam%
+ \fi}
+
+\def\font_helpers_set_math_family_bold_indeed#mbfam#familytag#mrfam% \c_font_fam_mb \s!mb \c_font_fam_mr
+ {\let\savedfontclass\defaultfontclass
+ \let\defaultfontclass\fontclass % else truefontname falls back on the wrong one
+ \let\savedfontbody\fontbody
+ \let\fontfamily#familytag%
+ \let\mathsizesuffix\mathscriptscriptsuffix\let\fontface\!!plusthree
+ \font_helpers_set_math_family_bold_a\scriptscriptfont#mbfam#mrfam% defines
+ \font_helpers_set_math_family_bold_a\scriptscriptfont#mbfam#mrfam% enables
+ \let\mathsizesuffix\mathscriptsuffix \let\fontface\!!plustwo
+ \font_helpers_set_math_family_bold_a\scriptfont #mbfam#mrfam% defines
+ \font_helpers_set_math_family_bold_a\scriptfont #mbfam#mrfam% enables
+ \let\mathsizesuffix\mathtextsuffix \let\fontface\!!plusone
+ \font_helpers_set_math_family_bold_a\textfont #mbfam#mrfam% defines
+ \font_helpers_set_math_family_bold_a\textfont #mbfam#mrfam% enables
+ \let\mathsizesuffix\empty \let\fontface\!!zerocount
+ \let\fontbody\savedfontbody
+ \let\defaultfontclass\savedfontclass
+ \setfalse\c_font_auto_size}
+
+% optimized: math fonts are never changed (10K \bfa $x$: 3.2 => 2.5 (baseline 1.0))
+%
+% sort of tricky: we cannot reset in \everybeforedefinetypeface as we don't know
+% all sizes so we postpone the optimization to the first starttext
+%
+% pitfall: we should reset 'm when a fontclass name is reused
+
+\newconditional\optimizemathfontdefinitions \settrue\optimizemathfontdefinitions
+
+\def\font_helpers_set_math_family#mrfam#familytag%
+ {\ifconditional\optimizemathfontdefinitions
+ \ifcsname\??fontinstanceclass\fontclass-\fontbody-\s!mm-#familytag-\fontsize-1\endcsname
+ % \writestatus{fonts}{math: reusing \fontclass\fontbody\s!mm#familytag\fontsize1}%
+ \font_helpers_preset_math_family_indeed#mrfam#familytag%
+ \else
+ % \writestatus{fonts}{math: defining \fontclass\fontbody\s!mm#familytag\fontsize1}%
+ \font_helpers_set_math_family_indeed#mrfam#familytag%
+ \fi
+ \else
+ \font_helpers_set_math_family_indeed#mrfam#familytag%
+ \fi}
+
+\def\font_helpers_set_math_family_bold#mbfam#familytag#mrfam%
+ {\ifconditional\optimizemathfontdefinitions
+ %\ifcsname\??fontinstanceclass\fontclass-\textface-\s!mm-#familytag-\fontsize-1\endcsname
+ \ifcsname\??fontinstanceclass\fontclass-\fontbody-\s!mm-#familytag-\fontsize-1\endcsname
+ \font_helpers_preset_math_family_indeed#mbfam#familytag%
+ \else
+ \font_helpers_set_math_family_bold_indeed#mbfam#familytag#mrfam%
+ \fi
+ \else
+ \font_helpers_set_math_family_bold_indeed#mbfam#familytag#mrfam%
+ \fi}
+
+%D It can happen that we use a bodyfont with no math in which case we have a problem
+%D with setting the global bodyfont size in the page builder. For instance in:
+%D
+%D \starttext
+%D \definetypeface[test][rm][serif][pagella][default]
+%D \setupbodyfont[test]
+%D test
+%D \stoptext
+%D
+%D This is why we need the check. At the cost of some extra checking we gain a
+%D little in restoring global states and, what's more important, we get rid of large
+%D math parameter push/pop in tracingall when not needed.
+
+\def\font_helpers_preset_math_family_indeed#fam#familytag%
+ {\expandafter\let\expandafter\v_font_math_one\csname\??fontinstanceclass\fontclass-\fontbody-\s!mm-#familytag-\fontsize-1\endcsname
+ \ifx\v_font_math_one\relax
+ \font_helpers_preset_math_family_warning
+ \orelse\ifnum\fontid\textfont#fam=\fontid\v_font_math_one\else
+ \font_helpers_preset_math_family_indeed_changed#fam#familytag%
+ \fi}
+
+\def\font_helpers_preset_math_family_warning
+ {\writestatus{fonts}{math: unset for global bodyfont \fontclass\space at \fontbody}}
+
+\def\font_helpers_preset_math_family_indeed_changed#fam#familytag%
+ {\scriptscriptfont#fam\csname\??fontinstanceclass\fontclass-\fontbody-\s!mm-#familytag-\fontsize-3\endcsname
+ \scriptfont #fam\csname\??fontinstanceclass\fontclass-\fontbody-\s!mm-#familytag-\fontsize-2\endcsname
+ \textfont #fam\v_font_math_one}
+
+\let\font_helpers_reset_fontclass_math_families\gobbleoneargument
+
+%D It would be nice if characters could be defined in a neutral way (say fam 255)
+%D and be mapped to a real family during noad list construction. However, this
+%D changes tex in critical places so for the moment we simulate this using
+%D manipulation.
+%D
+%D For tracing purposes we use three families but in l2r mode 1 and 2 are copies of
+%D 0 while in rl mode 0 is a copy of 1. There is no real overhead involved in this.
+%D This also permits different font definitions for normal and mixed.
+
+\let\m_font_class_direction\empty
+\let\m_font_class_features \empty
+\let\m_font_class_fallbacks\empty
+\let\m_font_class_goodies \empty
+
+\let\m_font_direction\empty
+\let\m_font_features \empty
+\let\m_font_fallbacks\empty
+\let\m_font_goodies \empty
+
+\appendtoks % can be analyzed once
+ % why here ..
+ %\edef\m_font_class_direction{\ifcsname\??fontclass\fontclass\s!mm\s!direction\endcsname\csname\??fontclass\fontclass\s!mm\s!direction\endcsname\fi}%
+ \edef\m_font_class_direction{\begincsname\??fontclass\fontclass\s!mm\s!direction\endcsname}%
+ % ...
+ \ifx\m_font_class_direction\v!both
+ \settrue\c_font_bidirectional_mathstrategy
+ \else
+ \setfalse\c_font_bidirectional_mathstrategy
+ \fi
+\to \t_font_math_strategies
+
+\def\font_helpers_bidirectional_mathstrategy_yes
+ {\font_helpers_set_math_family\c_font_fam_mr_lr\s!mrlr
+ \font_helpers_set_math_family\c_font_fam_mr_rl\s!mrrl
+ \ifnum\fontid\textfont\c_font_fam_mr=\fontid\textfont\c_font_fam_mr_lr\else
+ \font_helpers_bidirectional_mathstrategy_yes_changed
+ \fi}
+
+\def\font_helpers_bidirectional_mathstrategy_yes_changed
+ {\textfont \c_font_fam_mr\textfont \c_font_fam_mr_lr
+ \scriptfont \c_font_fam_mr\scriptfont \c_font_fam_mr_lr
+ \scriptscriptfont\c_font_fam_mr\scriptscriptfont\c_font_fam_mr_lr}
+
+\def\font_helpers_bidirectional_mathstrategy_nop
+ {\font_helpers_set_math_family\c_font_fam_mr\s!mr
+ \ifnum\fontid\textfont\c_font_fam_mr_rl=\fontid\textfont\c_font_fam_mr\else
+ \font_helpers_bidirectional_mathstrategy_nop_changed
+ \fi}
+
+\def\font_helpers_bidirectional_mathstrategy_nop_changed
+ {\textfont \c_font_fam_mr_lr\textfont \c_font_fam_mr
+ \scriptfont \c_font_fam_mr_lr\scriptfont \c_font_fam_mr
+ \scriptscriptfont\c_font_fam_mr_lr\scriptscriptfont\c_font_fam_mr
+ \textfont \c_font_fam_mr_rl\textfont \c_font_fam_mr
+ \scriptfont \c_font_fam_mr_rl\scriptfont \c_font_fam_mr
+ \scriptscriptfont\c_font_fam_mr_rl\scriptscriptfont\c_font_fam_mr}
+
+\appendtoks
+ \ifconditional\c_font_bidirectional_mathstrategy
+ \font_helpers_bidirectional_mathstrategy_yes
+ \else
+ \font_helpers_bidirectional_mathstrategy_nop
+ \fi
+\to \t_font_math_strategies
+
+\def\font_helpers_complete_bold_mathstrategy_yes_bidi
+ {\font_helpers_set_math_family_bold\c_font_fam_mb_lr\s!mblr\c_font_fam_mr_lr
+ \font_helpers_set_math_family_bold\c_font_fam_mb_rl\s!mbrl\c_font_fam_mr_rl
+ \ifnum\fontid\textfont\c_font_fam_mb=\fontid\textfont\c_font_fam_mb_lr\else
+ \font_helpers_complete_bold_mathstrategy_yes_bidi_changed
+ \fi}
+
+\def\font_helpers_complete_bold_mathstrategy_yes_bidi_changed
+ {\textfont \c_font_fam_mb\textfont \c_font_fam_mb_lr
+ \scriptfont \c_font_fam_mb\scriptfont \c_font_fam_mb_lr
+ \scriptscriptfont\c_font_fam_mb\scriptscriptfont\c_font_fam_mb_lr}
+
+\def\font_helpers_complete_bold_mathstrategy_yes
+ {\font_helpers_set_math_family_bold\c_font_fam_mb\s!mb\c_font_fam_mr\relax
+ \ifnum\fontid\textfont\c_font_fam_mb_rl=\fontid\textfont\c_font_fam_mb\else
+ \font_helpers_complete_bold_mathstrategy_yes_changed
+ \fi}
+
+\def\font_helpers_complete_bold_mathstrategy_yes_changed
+ {\textfont \c_font_fam_mb_rl\textfont \c_font_fam_mb
+ \scriptfont \c_font_fam_mb_rl\scriptfont \c_font_fam_mb
+ \scriptscriptfont\c_font_fam_mb_rl\scriptscriptfont\c_font_fam_mb
+ \textfont \c_font_fam_mb_lr\textfont \c_font_fam_mb
+ \scriptfont \c_font_fam_mb_lr\scriptfont \c_font_fam_mb
+ \scriptscriptfont\c_font_fam_mb_lr\scriptscriptfont\c_font_fam_mb}
+
+\def\font_helpers_complete_bold_mathstrategy_nop
+ {\ifnum\fontid\textfont\c_font_fam_mb=\fontid\textfont\c_font_fam_mr\else
+ \font_helpers_complete_bold_mathstrategy_nop_changed
+ \fi}
+
+\def\font_helpers_complete_bold_mathstrategy_nop_changed
+ {\textfont \c_font_fam_mb \textfont \c_font_fam_mr
+ \scriptfont \c_font_fam_mb \scriptfont \c_font_fam_mr
+ \scriptscriptfont\c_font_fam_mb \scriptscriptfont\c_font_fam_mr
+ \textfont \c_font_fam_mb_lr\textfont \c_font_fam_mr_lr
+ \scriptfont \c_font_fam_mb_lr\scriptfont \c_font_fam_mr_lr
+ \scriptscriptfont\c_font_fam_mb_lr\scriptscriptfont\c_font_fam_mr_lr
+ \textfont \c_font_fam_mb_rl\textfont \c_font_fam_mr_rl
+ \scriptfont \c_font_fam_mb_rl\scriptfont \c_font_fam_mr_rl
+ \scriptscriptfont\c_font_fam_mb_rl\scriptscriptfont\c_font_fam_mr_rl}
+
+\def\font_helpers_apply_complete_bold_mathstrategy
+ {\ifconditional\c_font_complete_bold_mathstrategy
+ \ifconditional\c_font_bidirectional_mathstrategy
+ \font_helpers_complete_bold_mathstrategy_yes_bidi
+ \else
+ \font_helpers_complete_bold_mathstrategy_yes
+ \fi
+ \else
+ \font_helpers_complete_bold_mathstrategy_nop
+ \fi}
+
+\appendtoks
+ \font_helpers_apply_complete_bold_mathstrategy
+\to \t_font_math_strategies
+
+\ifdefined\defaultmathfamily \else
+ \setnewconstant\defaultmathfamily\zerocount
+\fi
+
+\appendtoks
+ \fam\defaultmathfamily % all characters and symbols are in this family
+\to \everymathematics
+
+\unexpanded\def\font_helpers_synchronize_math_family_mr
+ {\attribute\mathfamilyattribute\ifconditional\c_font_bidirectional_mathstrategy
+ \ifconditional\c_math_right_to_left
+ \plustwo
+ \else
+ \plusone
+ \fi
+ \else
+ \zerocount
+ \fi}
+
+\unexpanded\def\font_helpers_synchronize_math_family_mb
+ {\attribute\mathfamilyattribute\ifconditional\c_font_bidirectional_mathstrategy
+ \ifconditional\c_math_right_to_left
+ \ifconditional\c_font_pseudo_bold_math_state\pluseight\else\plusfive\fi
+ \else
+ \ifconditional\c_font_pseudo_bold_math_state\plusseven\else\plusfour\fi
+ \fi
+ \else
+ \ifconditional\c_font_pseudo_bold_math_state\plussix\else\plusthree\fi
+ \fi}
+
+\installcorenamespace{fontmathsynchronizer}
+\installcorenamespace{fontmathstoredstrategy}
+
+\letvalue{\??fontmathsynchronizer\s!tf }\font_helpers_synchronize_math_family_mr
+\letvalue{\??fontmathsynchronizer\s!sl }\font_helpers_synchronize_math_family_mr
+\letvalue{\??fontmathsynchronizer\s!it }\font_helpers_synchronize_math_family_mr
+\letvalue{\??fontmathsynchronizer\s!bf }\font_helpers_synchronize_math_family_mb
+\letvalue{\??fontmathsynchronizer\s!bs }\font_helpers_synchronize_math_family_mb
+\letvalue{\??fontmathsynchronizer\s!bi }\font_helpers_synchronize_math_family_mb
+\letvalue{\??fontmathsynchronizer\empty}\font_helpers_synchronize_math_family_mr
+
+% \def\font_helpers_synchronize_math_family
+% {\csname\??fontmathsynchronizer\ifcsname\??fontmathsynchronizer\fontalternative\endcsname\fontalternative\fi\endcsname}
+
+\def\font_helpers_synchronize_math_family
+ {\ifcsname\??fontmathsynchronizer\fontalternative\endcsname
+ \lastnamedcs
+ \else
+ \font_helpers_synchronize_math_family_mr
+ \fi}
+
+\ifdefined \fontid % we need to keep this test for a while
+ \appendtoks
+ \ifnum\fontid\textfont\zerocount=\fontid\textfont\plusthree
+ \letvalue{\??fontmathstoredstrategy\fontclass}\font_helpers_set_math_partial_bold_strategy
+ \else
+ \letvalue{\??fontmathstoredstrategy\fontclass}\font_helpers_set_math_full_bold_strategy
+ \fi
+ \to \t_font_math_strategies
+\else
+ \appendtoks
+ \edef\currentmathfontmr{\fontname\textfont\zerocount}%
+ \edef\currentmathfontmb{\fontname\textfont\plusthree}%
+ \ifx\currentmathfontmr\currentmathfontmb
+ \letvalue{\??fontmathstoredstrategy\fontclass}\font_helpers_set_math_partial_bold_strategy
+ \else
+ \letvalue{\??fontmathstoredstrategy\fontclass}\font_helpers_set_math_full_bold_strategy
+ \fi
+ \to \t_font_math_strategies
+\fi
+
+%def\font_helpers_synchronize_math_bold_strategy{\csname\??fontmathstoredstrategy\fontclass\endcsname}
+\def\font_helpers_synchronize_math_bold_strategy{\begincsname\??fontmathstoredstrategy\fontclass\endcsname}
+
+\newconditional\c_font_pseudo_bold_math_state
+
+\def\font_helpers_set_math_partial_bold_strategy{\settrue \c_font_pseudo_bold_math_state}
+\def\font_helpers_set_math_full_bold_strategy {\setfalse\c_font_pseudo_bold_math_state}
+
+\appendtoks
+ \font_helpers_synchronize_math_bold_strategy
+\to \everymathematics
+
+%D Bold is somewhat special as we might want both full-bold-math mixed regular-math,
+%D as well as automatic adaption to outer bold (in titles and inline text bold) so
+%D we will need explicit switches as well as an automatic one. (We will use lucida
+%D as an example.)
+
+\ifdefined\mathdefault \else \let\mathdefault\relax \fi
+
+\newconditional\c_math_bold
+
+\unexpanded\def\mr % math regular
+ {\ifmmode
+ \font_helpers_synchronize_math_family_mr
+ \else
+ \font_helpers_set_current_font_alternative\s!mr
+ \fi
+ \mathdefault
+ \setfalse\c_math_bold}
+
+\unexpanded\def\mb % math bold
+ {\ifmmode
+ \font_helpers_synchronize_math_family_mb
+ \else
+ \font_helpers_set_current_font_alternative\s!mb
+ \fi
+ \mathdefault
+ \settrue\c_math_bold}
+
+\appendtoks
+ \font_helpers_synchronize_math_family % auto bold
+\to \everymathematics
+
+\appendtoks
+ \ifconditional\c_math_bold\mb\fi
+\to \everymathematics
+
+%D \macros
+%D {bigmath,nobigmath}
+%D
+%D We can inhibit this slow||downer with:
+
+% these can best be combined
+
+% 0=never 1=everymath 2=always
+
+\setnewconstant\synchronizebigmathflag\plusone
+
+\appendtoks
+ \ifcase\synchronizebigmathflag
+ % never
+ \or
+ \synchronizebigmath
+ \or
+ % always
+ \fi
+\to \everymathematics
+
+\unexpanded\def\nobigmath {\synchronizebigmathflag\zerocount}
+\unexpanded\def\autobigmath{\synchronizebigmathflag\plusone\synchronizebigmath}
+\unexpanded\def\bigmath {\synchronizebigmathflag\plustwo\synchronizebigmath}
+
+\let\bigmathfontsize\empty
+
+\unexpanded\def\synchronizebigmath
+ {\ifx\bigmathfontsize\fontsize
+ % already in sync
+ \else
+ \let\bigmathfontsize\fontsize
+ \font_helpers_synchronize_math
+ \fi}
+
+\unexpanded\def\font_helpers_check_big_math_synchronization
+ {\ifcase\synchronizebigmathflag
+ % never
+ \or
+ \ifmmode \synchronizebigmath \fi
+ \or
+ \synchronizebigmath
+ \fi}
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-mis.lua b/Master/texmf-dist/tex/context/base/mkiv/font-mis.lua
index c75b9298454..fe972114f47 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-mis.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-mis.lua
@@ -21,38 +21,41 @@ local readers = otf.readers
if readers then
- otf.version = otf.version or 3.107
+ otf.version = otf.version or 3.111
otf.cache = otf.cache or containers.define("fonts", "otl", otf.version, true)
function fonts.helpers.getfeatures(name,save)
local filename = resolvers.findfile(name) or ""
if filename ~= "" then
--- local name = file.removesuffix(file.basename(filename))
--- local cleanname = containers.cleanname(name)
--- local data = containers.read(otf.cache,cleanname)
--- if data then
--- readers.unpack(data)
--- else
--- data = readers.loadfont(filename) -- we can do a more minimal load
--- -- if data and save then
--- -- -- keep this in sync with font-otl
--- -- readers.compact(data)
--- -- readers.rehash(data,"unicodes")
--- -- readers.addunicodetable(data)
--- -- readers.extend(data)
--- -- readers.pack(data)
--- -- -- till here
--- -- containers.write(otf.cache,cleanname,data)
--- -- end
--- end
--- if not data then
--- data = readers.loadfont(filename) -- we can do a more minimal load
--- end
--- if data then
--- readers.unpack(data)
--- end
-local data = otf.load(filename)
- return data and data.resources and data.resources.features
+ -- local name = file.removesuffix(file.basename(filename))
+ -- local cleanname = containers.cleanname(name)
+ -- local data = containers.read(otf.cache,cleanname)
+ -- if data then
+ -- readers.unpack(data)
+ -- else
+ -- data = readers.loadfont(filename) -- we can do a more minimal load
+ -- -- if data and save then
+ -- -- -- keep this in sync with font-otl
+ -- -- readers.compact(data)
+ -- -- readers.rehash(data,"unicodes")
+ -- -- readers.addunicodetable(data)
+ -- -- readers.extend(data)
+ -- -- readers.pack(data)
+ -- -- -- till here
+ -- -- containers.write(otf.cache,cleanname,data)
+ -- -- end
+ -- end
+ -- if not data then
+ -- data = readers.loadfont(filename) -- we can do a more minimal load
+ -- end
+ -- if data then
+ -- readers.unpack(data)
+ -- end
+ local data = otf.load(filename)
+ local resources = data and data.resources
+ if resources then
+ return data.resources.features, data.resources.foundtables, data
+ end
end
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-mps.lua b/Master/texmf-dist/tex/context/base/mkiv/font-mps.lua
index 89583595826..8bfe23b892b 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-mps.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-mps.lua
@@ -22,9 +22,9 @@ fonts = fonts or { }
local metapost = fonts.metapost or { }
fonts.metapost = metapost
-local f_moveto = formatters["(%.6F,%.6F)"]
-local f_lineto = formatters["--(%.6F,%.6F)"]
-local f_curveto = formatters["..controls(%.6F,%.6F)and(%.6F,%.6F)..(%.6F,%.6F)"]
+local f_moveto = formatters["(%N,%N)"]
+local f_lineto = formatters["--(%N,%N)"]
+local f_curveto = formatters["..controls(%N,%N)and(%N,%N)..(%N,%N)"]
local s_cycle = "--cycle"
local f_nofill = formatters["nofill %s;"]
@@ -33,19 +33,8 @@ local f_dofill = formatters["fill %s;"]
local f_draw_trace = formatters["drawpathonly %s;"]
local f_draw = formatters["draw %s;"]
-local f_boundingbox = formatters["((%.6F,%.6F)--(%.6F,%.6F)--(%.6F,%.6F)--(%.6F,%.6F)--cycle)"]
-local f_vertical = formatters["((%.6F,%.6F)--(%.6F,%.6F))"]
-
-directives.register("metapost.stripzeros", function()
-
- f_moveto = formatters["(%.6N,%.6N)"]
- f_lineto = formatters["--(%.6N,%.6N)"]
- f_curveto = formatters["..controls(%.6N,%.6N)and(%.6N,%.6N)..(%.6N,%.6N)"]
-
- f_boundingbox = formatters["((%.6N,%.6N)--(%.6N,%.6N)--(%.6N,%.6N)--(%.6N,%.6N)--cycle)"]
- f_vertical = formatters["((%.6N,%.6N)--(%.6N,%.6N))"]
-
-end)
+local f_boundingbox = formatters["((%N,%N)--(%N,%N)--(%N,%N)--(%N,%N)--cycle)"]
+local f_vertical = formatters["((%N,%N)--(%N,%N))"]
function metapost.boundingbox(d,factor)
local bounds = d.boundingbox
@@ -279,7 +268,7 @@ local getnext = nuts.getnext
local getid = nuts.getid
local getlist = nuts.getlist
local getsubtype = nuts.getsubtype
-local getfield = nuts.getfield
+local getreplace = nuts.getreplace
local getbox = nuts.getbox
local getwhd = nuts.getwhd
local getkern = nuts.getkern
@@ -297,19 +286,13 @@ local parameters = fonts.hashes.parameters
local shapes = fonts.hashes.shapes
local topaths = metapost.paths
-local f_code = formatters["mfun_do_outline_text_flush(%q,%i,%.6F,%.6F,%q)(%,t);"]
-local f_rule = formatters["mfun_do_outline_rule_flush(%q,%.6F,%.6F,%.6F,%.6F);"]
-local f_bounds = formatters["checkbounds(%.6F,%.6F,%.6F,%.6F);"]
+local f_code = formatters["mfun_do_outline_text_flush(%q,%i,%N,%N,%q)(%,t);"]
+local f_rule = formatters["mfun_do_outline_rule_flush(%q,%N,%N,%N,%N);"]
+local f_bounds = formatters["checkbounds(%N,%N,%N,%N);"]
local s_nothing = "(origin scaled 10)"
-directives.register("metapost.stripzeros", function()
- f_code = formatters["mfun_do_outline_text_flush(%q,%i,%.6N,%.6N,%q)(%,t);"]
- f_rule = formatters["mfun_do_outline_rule_flush(%q,%.6N,%.6N,%.6N,%.6N);"]
- f_bounds = formatters["checkbounds(%.6N,%.6N,%.6N,%.6N);"]
-end)
-
-local sc = 10
-local fc = number.dimenfactors.bp * sc / 10
+local sc = 10
+local fc = number.dimenfactors.bp * sc / sc
-- todo: make the next more efficient:
@@ -372,7 +355,7 @@ function fonts.metapost.boxtomp(n,kind)
result[#result+1] = code
dx = dx + width
elseif id == disc_code then
- local replace = getfield(current,"replace")
+ local replace = getreplace(current)
if replace then
dx = dx + horizontal(parent,replace,xoffset+dx,yoffset)
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-nod.lua b/Master/texmf-dist/tex/context/base/mkiv/font-nod.lua
index a0eb88a252c..8c0f6e441a7 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-nod.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-nod.lua
@@ -56,7 +56,6 @@ local kern_code = nodecodes.kern
local dir_code = nodecodes.dir
local localpar_code = nodecodes.localpar
-local getfield = nuts.getfield
local getnext = nuts.getnext
local getprev = nuts.getprev
local getid = nuts.getid
@@ -64,6 +63,7 @@ local getfont = nuts.getfont
local getsubtype = nuts.getsubtype
local getlist = nuts.getlist
local getdisc = nuts.getdisc
+local getreplace = nuts.getreplace
local isglyph = nuts.isglyph
local getkern = nuts.getkern
local getdirection = nuts.getdirection
@@ -77,6 +77,7 @@ local copy_node_list = nuts.copy_list
local hpack_node_list = nuts.hpack
local flush_node_list = nuts.flush_list
local protect_glyphs = nuts.protect_glyphs
+local start_of_par = nuts.start_of_par
local nextnode = nuts.traversers.node
local nextglyph = nuts.traversers.glyph
@@ -395,7 +396,7 @@ function step_tracers.codes(i,command,space)
local char, id = isglyph(c)
if char then
showchar(char,id)
- elseif id == dir_code or (id == localpar_code and getsubtype(c) == 0) then
+ elseif id == dir_code or (id == localpar_code and start_of_par(c)) then
context("[%s]",getdirection(c) or "?")
elseif id == disc_code then
local pre, post, replace = getdisc(c)
@@ -519,7 +520,8 @@ local function toutf(list,result,nofresult,stopcriterium,nostrip)
result[nofresult] = f_badcode(c)
end
elseif id == disc_code then
- result, nofresult = toutf(getfield(n,"replace"),result,nofresult,false,true) -- needed?
+ local replace = getreplace(n)
+ result, nofresult = toutf(replace,result,nofresult,false,true) -- needed?
elseif id == hlist_code or id == vlist_code then
-- if nofresult > 0 and result[nofresult] ~= " " then
-- nofresult = nofresult + 1
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-ocl.lua b/Master/texmf-dist/tex/context/base/mkiv/font-ocl.lua
index 0976cdb21c0..eef221e4686 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-ocl.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-ocl.lua
@@ -8,9 +8,14 @@ if not modules then modules = { } end modules ['font-ocl'] = {
-- todo : user list of colors
+if CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 then
+ return
+end
+
local tostring, tonumber, next = tostring, tonumber, next
local round, max = math.round, math.round
-local sortedkeys, sortedhash = table.sortedkeys, table.sortedhash
+local gsub, find = string.gsub, string.find
+local sortedkeys, sortedhash, concat = table.sortedkeys, table.sortedhash, table.concat
local setmetatableindex = table.setmetatableindex
local formatters = string.formatters
@@ -24,6 +29,7 @@ local leftcommand = helpers.commands.left
local downcommand = helpers.commands.down
local otf = fonts.handlers.otf
+local otfregister = otf.features.register
local f_color = formatters["%.3f %.3f %.3f rg"]
local f_gray = formatters["%.3f g"]
@@ -150,7 +156,7 @@ local pop = { "pdf", "page", "Q" }
-- -- only shows the first glyph in acrobat and nothing more. No problem with other
-- -- renderers.
--
--- local function initialize(tfmdata,kind,value) -- hm, always value
+-- local function initializeoverlay(tfmdata,kind,value) -- hm, always value
-- if value then
-- local resources = tfmdata.resources
-- local palettes = resources.colorpalettes
@@ -193,11 +199,11 @@ local pop = { "pdf", "page", "Q" }
-- local goback = w ~= 0 and leftcommand[w] or nil -- needs checking: are widths the same
-- local t = {
-- start,
--- not u and actualb or { "pdf", "page", (getactualtext(tounicode(u))) }
+-- not u and actualb or { "pdf", "page", (getactualtext(tounicode(u))) },
+-- push,
-- }
--- local n = 2
+-- local n = 3
-- local l = nil
--- n = n + 1 t[n] = push
-- for i=1,s do
-- local entry = colorlist[i]
-- local v = colorvalues[entry.class] or default
@@ -220,11 +226,8 @@ local pop = { "pdf", "page", "Q" }
-- end
-- end
-- end
---
--- -- Here we have no color change in BT .. ET and more q Q pairs but even then acrobat
--- -- fails displaying the overlays correctly. Other renderers do it right.
-local function initialize(tfmdata,kind,value)
+local function initializeoverlay(tfmdata,kind,value)
if value then
local resources = tfmdata.resources
local palettes = resources.colorpalettes
@@ -271,54 +274,40 @@ local function initialize(tfmdata,kind,value)
local s = #colorlist
local goback = w ~= 0 and leftcommand[w] or nil -- needs checking: are widths the same
local t = {
- start, -- really needed
- not u and actualb or { "pdf", "page", (getactualtext(tounicode(u))) }
+ not u and actualb or { "pdf", "page", (getactualtext(tounicode(u))) },
+ push,
}
local n = 2
local l = nil
- local f = false
for i=1,s do
local entry = colorlist[i]
local v = colorvalues[entry.class] or default
if v and l ~= v then
- if f then
- n = n + 1 t[n] = pop
- end
- n = n + 1 t[n] = push
- f = true
n = n + 1 t[n] = v
l = v
- else
- if f then
- n = n + 1 t[n] = pop
- end
- f = false
- l = nil
end
n = n + 1 t[n] = charcommand[entry.slot]
if s > 1 and i < s and goback then
n = n + 1 t[n] = goback
end
end
- if f then
- n = n + 1 t[n] = pop
- end
+ n = n + 1 t[n] = pop
n = n + 1 t[n] = actuale
- -- n = n + 1 t[n] = stop -- not needed
character.commands = t
end
end
end
+ return true
end
end
end
-fonts.handlers.otf.features.register {
+otfregister {
name = "colr",
description = "color glyphs",
manipulators = {
- base = initialize,
- node = initialize,
+ base = initializeoverlay,
+ node = initializeoverlay,
}
}
@@ -330,39 +319,19 @@ do
local hashed = { }
local cache = { }
- if epdf then
-
- local openpdf = epdf.openMemStream
-
- function otf.storepdfdata(pdf)
- local done = hashed[pdf]
- if not done then
- nofstreams = nofstreams + 1
- local o, n = openpdf(pdf,#pdf,f_name(nofstreams))
- cache[n] = o -- we need to keep in mem
- done = f_used(n)
- hashed[pdf] = done
- end
- return done
+ local openpdf = pdfe.new
+ ----- prefix = "data:application/pdf,"
+
+ function otf.storepdfdata(pdf)
+ local done = hashed[pdf]
+ if not done then
+ nofstreams = nofstreams + 1
+ local f = f_name(nofstreams)
+ local n = openpdf(pdf,#pdf,f)
+ done = f_used(n)
+ hashed[pdf] = done
end
-
- else
-
- local openpdf = pdfe.new
- ----- prefix = "data:application/pdf,"
-
- function otf.storepdfdata(pdf)
- local done = hashed[pdf]
- if not done then
- nofstreams = nofstreams + 1
- local f = f_name(nofstreams)
- local n = openpdf(pdf,#pdf,f)
- done = f_used(n)
- hashed[pdf] = done
- end
- return done
- end
-
+ return done
end
end
@@ -394,7 +363,6 @@ local function pdftovirtual(tfmdata,pdfshapes,kind) -- kind = png|svg
local actuale = { "pdf", "page", e } -- saves tables
--
local vfimage = lpdf and lpdf.vfimage or function(wd,ht,dp,data,name)
- -- needed for generic (if used there at all)
local name = storepdfdata(data)
return { "image", { filename = name, width = wd, height = ht, depth = dp } }
end
@@ -402,19 +370,25 @@ local function pdftovirtual(tfmdata,pdfshapes,kind) -- kind = png|svg
for unicode, character in sortedhash(characters) do -- sort is nicer for svg
local index = character.index
if index then
- local pdf = pdfshapes[index]
- local typ = type(pdf)
- local data = nil
- local dx = nil
- local dy = nil
+ local pdf = pdfshapes[index]
+ local typ = type(pdf)
+ local data = nil
+ local dx = nil
+ local dy = nil
+ local scale = 1
if typ == "table" then
- data = pdf.data
- dx = pdf.dx or 0
- dy = pdf.dy or 0
+ data = pdf.data
+ dx = pdf.x or pdf.dx or 0
+ dy = pdf.y or pdf.dy or 0
+ scale = pdf.scale or 1
elseif typ == "string" then
data = pdf
dx = 0
dy = 0
+ elseif typ == "number" then
+ data = pdf
+ dx = 0
+ dy = 0
end
if data then
-- We can delay storage by a lua function in commands: but then we need to
@@ -424,12 +398,20 @@ local function pdftovirtual(tfmdata,pdfshapes,kind) -- kind = png|svg
local wd = character.width or 0
local ht = character.height or 0
local dp = character.depth or 0
- -- The down and right will change too (we can move that elsewhere).
+ -- The down and right will change too (we can move that elsewhere). We have
+ -- a different treatment in lmtx but the next kind of works. These images are
+ -- a mess anyway as in svg the bbox can be messed up absent). A png image
+ -- needs the x/y. I might normalize this once we move to lmtx exlusively.
character.commands = {
not unicode and actualb or { "pdf", "page", (getactualtext(unicode)) },
- downcommand[dp + dy * hfactor],
- rightcommand[dx * hfactor],
- vfimage(wd,ht,dp,data,name),
+ -- lmtx (when we deal with depth in vfimage, currently disabled):
+ -- downcommand [dy * hfactor],
+ -- rightcommand[dx * hfactor],
+ -- vfimage(wd,ht,dp,data,name),
+ -- mkiv
+ downcommand [dp + dy * hfactor],
+ rightcommand[ dx * hfactor],
+ vfimage(scale*wd,ht,dp,data,pdfshapes.filename or ""),
actuale,
}
character[kind] = true
@@ -456,6 +438,8 @@ do
local xmlfirst = xml.first
function otfsvg.filterglyph(entry,index)
+ -- we only support decompression in lmtx, so one needs to wipe the
+ -- cache when invalid xml is reported
local svg = xmlconvert(entry.data)
local root = svg and xmlfirst(svg,"/svg[@id='glyph"..index.."']")
local data = root and tostring(root)
@@ -475,7 +459,7 @@ do
name = "otfsvg",
program = "inkscape",
method = "pipeto",
- template = "--shell > temp-otf-svg-shape.log",
+ template = "--export-area-drawing --shell > temp-otf-svg-shape.log",
reporter = report_svg,
}
@@ -484,20 +468,31 @@ do
-- poor mans variant for generic:
--
runner = function()
- return io.open("inkscape --shell > temp-otf-svg-shape.log","w")
+ return io.popen("inkscape --export-area-drawing --shell > temp-otf-svg-shape.log","w")
end
end
- function otfsvg.topdf(svgshapes)
+ -- There are svg out there with bad viewBox specifications where shapes lay outside that area,
+ -- but trying to correct that didn't work out well enough so I discarded that code. BTW, we
+ -- decouple the inskape run and the loading run because inkscape is working in the background
+ -- in the files so we need to have unique files.
+ --
+ -- Because a generic setup can be flawed we need to catch bad inkscape runs which add a bit of
+ -- ugly overhead. Bah.
+
+ function otfsvg.topdf(svgshapes,tfmdata)
local pdfshapes = { }
local inkscape = runner()
if inkscape then
- local nofshapes = #svgshapes
- local f_svgfile = formatters["temp-otf-svg-shape-%i.svg"]
- local f_pdffile = formatters["temp-otf-svg-shape-%i.pdf"]
- local f_convert = formatters["%s --export-pdf=%s\n"]
- local filterglyph = otfsvg.filterglyph
- local nofdone = 0
+ -- local indices = fonts.getindices(tfmdata)
+ local descriptions = tfmdata.descriptions
+ local nofshapes = #svgshapes
+ local f_svgfile = formatters["temp-otf-svg-shape-%i.svg"]
+ local f_pdffile = formatters["temp-otf-svg-shape-%i.pdf"]
+ local f_convert = formatters["%s --export-pdf=%s\n"]
+ local filterglyph = otfsvg.filterglyph
+ local nofdone = 0
+ local processed = { }
report_svg("processing %i svg containers",nofshapes)
statistics.starttiming()
for i=1,nofshapes do
@@ -509,24 +504,55 @@ do
local pdffile = f_pdffile(index)
savedata(svgfile,data)
inkscape:write(f_convert(svgfile,pdffile))
- pdfshapes[index] = true
+ processed[index] = true
nofdone = nofdone + 1
- if nofdone % 100 == 0 then
- report_svg("%i shapes processed",nofdone)
+ if nofdone % 25 == 0 then
+ report_svg("%i shapes submitted",nofdone)
end
end
end
end
+ if nofdone % 25 ~= 0 then
+ report_svg("%i shapes submitted",nofdone)
+ end
+ report_svg("processing can be going on for a while")
inkscape:write("quit\n")
inkscape:close()
report_svg("processing %i pdf results",nofshapes)
- for index in next, pdfshapes do
+ for index in next, processed do
local svgfile = f_svgfile(index)
local pdffile = f_pdffile(index)
- pdfshapes[index] = loaddata(pdffile)
+ -- local fntdata = descriptions[indices[index]]
+ -- local bounds = fntdata and fntdata.boundingbox
+ local pdfdata = loaddata(pdffile)
+ if pdfdata and pdfdata ~= "" then
+ pdfshapes[index] = {
+ data = pdfdata,
+ -- x = bounds and bounds[1] or 0,
+ -- y = bounds and bounds[2] or 0,
+ }
+ end
remove(svgfile)
remove(pdffile)
end
+ local characters = tfmdata.characters
+ for k, v in next, characters do
+ local d = descriptions[k]
+ local i = d.index
+ if i then
+ local p = pdfshapes[i]
+ if p then
+ local w = d.width
+ local l = d.boundingbox[1]
+ local r = d.boundingbox[3]
+ p.scale = (r - l) / w
+ p.x = l
+ end
+ end
+ end
+ if not next(pdfshapes) then
+ report_svg("there are no converted shapes, fix your setup")
+ end
statistics.stoptiming()
if statistics.elapsedseconds then
report_svg("svg conversion time %s",statistics.elapsedseconds() or "-")
@@ -547,20 +573,23 @@ local function initializesvg(tfmdata,kind,value) -- hm, always value
end
local pdffile = containers.read(otf.pdfcache,hash)
local pdfshapes = pdffile and pdffile.pdfshapes
- if not pdfshapes or pdffile.timestamp ~= timestamp then
+ if not pdfshapes or pdffile.timestamp ~= timestamp or not next(pdfshapes) then
+ -- the next test tries to catch errors in generic usage but of course can result
+ -- in running again and again
local svgfile = containers.read(otf.svgcache,hash)
local svgshapes = svgfile and svgfile.svgshapes
- pdfshapes = svgshapes and otfsvg.topdf(svgshapes) or { }
+ pdfshapes = svgshapes and otfsvg.topdf(svgshapes,tfmdata,otf.pdfcache.writable,hash) or { }
containers.write(otf.pdfcache, hash, {
pdfshapes = pdfshapes,
timestamp = timestamp,
})
end
pdftovirtual(tfmdata,pdfshapes,"svg")
+ return true
end
end
-fonts.handlers.otf.features.register {
+otfregister {
name = "svg",
description = "svg glyphs",
manipulators = {
@@ -668,10 +697,11 @@ local function initializepng(tfmdata,kind,value) -- hm, always value
end
--
pdftovirtual(tfmdata,pdfshapes,"png")
+ return true
end
end
-fonts.handlers.otf.features.register {
+otfregister {
name = "sbix",
description = "sbix glyphs",
manipulators = {
@@ -680,7 +710,7 @@ fonts.handlers.otf.features.register {
}
}
-fonts.handlers.otf.features.register {
+otfregister {
name = "cblc",
description = "cblc glyphs",
manipulators = {
@@ -688,3 +718,36 @@ fonts.handlers.otf.features.register {
node = initializepng,
}
}
+
+if context then
+
+ -- untested in generic and might clash with other color trickery
+ -- anyway so let's stick to context only
+
+ local function initializecolor(tfmdata,kind,value)
+ if value == "auto" then
+ return
+ initializeoverlay(tfmdata,kind,value) or
+ initializesvg(tfmdata,kind,value) or
+ initializepng(tfmdata,kind,value)
+ elseif value == "overlay" then
+ return initializeoverlay(tfmdata,kind,value)
+ elseif value == "svg" then
+ return initializesvg(tfmdata,kind,value)
+ elseif value == "png" or value == "bitmap" then
+ return initializepng(tfmdata,kind,value)
+ else
+ -- forget about it
+ end
+ end
+
+ otfregister {
+ name = "color",
+ description = "color glyphs",
+ manipulators = {
+ base = initializecolor,
+ node = initializecolor,
+ }
+ }
+
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-off.lua b/Master/texmf-dist/tex/context/base/mkiv/font-off.lua
deleted file mode 100644
index 7e509c2c3d7..00000000000
--- a/Master/texmf-dist/tex/context/base/mkiv/font-off.lua
+++ /dev/null
@@ -1,230 +0,0 @@
-if not modules then modules = { } end modules ['font-off'] = {
- version = 1.001,
- comment = "companion to font-ini.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-local tonumber = tonumber
-local lower = string.lower
-local round = math.round
-local setmetatableindex = table.setmetatableindex
-
-local fontloader = fontloader
------ font_to_table = fontloader.to_table
-local open_font = fontloader.open
------ get_font_info = fontloader.info
-local close_font = fontloader.close
------ font_fields = fontloader.fields
-
--- table={
--- ["familyname"]="TeXGyrePagella",
--- ["fontname"]="TeXGyrePagella-Regular",
--- ["fullname"]="TeXGyrePagella-Regular",
--- ["italicangle"]=0,
--- ["names"]={
--- {
--- ["lang"]="English (US)",
--- ["names"]={
--- ["copyright"]="Copyright 2006, 2009 for TeX Gyre extensions by B. Jackowski and J.M. Nowacki (on behalf of TeX users groups). This work is released under the GUST Font License -- see http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt for details.",
--- ["family"]="TeXGyrePagella",
--- ["fullname"]="TeXGyrePagella-Regular",
--- ["postscriptname"]="TeXGyrePagella-Regular",
--- ["preffamilyname"]="TeX Gyre Pagella",
--- ["subfamily"]="Regular",
--- ["trademark"]="Please refer to the Copyright section for the font trademark attribution notices.",
--- ["uniqueid"]="2.004;UKWN;TeXGyrePagella-Regular",
--- ["version"]="Version 2.004;PS 2.004;hotconv 1.0.49;makeotf.lib2.0.14853",
--- },
--- },
--- },
--- ["pfminfo"]={
--- ["avgwidth"]=528,
--- ["codepages"]={ 536871315, 0 },
--- ["firstchar"]=32,
--- ["fstype"]=12,
--- ["hhead_ascent"]=1098,
--- ["hhead_descent"]=-283,
--- ["hheadascent_add"]=0,
--- ["hheaddescent_add"]=0,
--- ["hheadset"]=1,
--- ["lastchar"]=64260,
--- ["linegap"]=0,
--- ["os2_breakchar"]=32,
--- ["os2_capheight"]=692,
--- ["os2_defaultchar"]=0,
--- ["os2_family_class"]=0,
--- ["os2_strikeypos"]=269,
--- ["os2_strikeysize"]=50,
--- ["os2_subxoff"]=0,
--- ["os2_subxsize"]=650,
--- ["os2_subyoff"]=75,
--- ["os2_subysize"]=600,
--- ["os2_supxoff"]=0,
--- ["os2_supxsize"]=650,
--- ["os2_supyoff"]=350,
--- ["os2_supysize"]=600,
--- ["os2_typoascent"]=726,
--- ["os2_typodescent"]=-274,
--- ["os2_typolinegap"]=200,
--- ["os2_vendor"]="UKWN",
--- ["os2_winascent"]=1098,
--- ["os2_windescent"]=283,
--- ["os2_xheight"]=449,
--- ["panose"]={
--- ["armstyle"]="Any",
--- ["contrast"]="Any",
--- ["familytype"]="Any",
--- ["letterform"]="Any",
--- ["midline"]="Any",
--- ["proportion"]="Any",
--- ["serifstyle"]="Any",
--- ["strokevariation"]="Any",
--- ["weight"]="Book",
--- ["xheight"]="Any",
--- },
--- ["panose_set"]=1,
--- ["pfmfamily"]=81,
--- ["pfmset"]=1,
--- ["subsuper_set"]=1,
--- ["typoascent_add"]=0,
--- ["typodescent_add"]=0,
--- ["unicoderanges"]={ 536871047, 0, 0, 0 },
--- ["vheadset"]=0,
--- ["vlinegap"]=0,
--- ["weight"]=400,
--- ["width"]=5,
--- ["winascent_add"]=0,
--- ["windescent_add"]=0,
--- },
--- ["units_per_em"]=1000,
--- ["version"]="2.004;PS 2.004;hotconv 1.0.49;makeotf.lib2.0.14853",
--- ["weight"]="Book",
--- }
-
--- We had this as temporary solution because we needed a bit more info but in the
--- meantime it got an interesting side effect: currently luatex delays loading of e.g.
--- glyphs so here we first load and then discard which is a waste. In the past it did
--- free memory because a full load was done. One of these things that goes unnoticed.
---
--- local function get_full_info(...) -- check with taco what we get / could get
--- local ff = open_font(...)
--- if ff then
--- local d = ff -- and font_to_table(ff)
--- d.glyphs, d.subfonts, d.gpos, d.gsub, d.lookups = nil, nil, nil, nil, nil
--- close_font(ff)
--- return d
--- else
--- return nil, "error in loading font"
--- end
--- end
-
--- Phillip suggested this faster variant but it's still a hack as fontloader.info should
--- return these keys/values (and maybe some more) but at least we close the loader which
--- might save some memory in the end.
-
--- local function get_full_info(name)
--- local ff = open_font(name)
--- if ff then
--- local fields = table.tohash(font_fields(ff),true) -- isn't that one stable
--- local d = {
--- names = fields.names and ff.names,
--- familyname = fields.familyname and ff.familyname,
--- fullname = fields.fullname and ff.fullname,
--- fontname = fields.fontname and ff.fontname,
--- weight = fields.weight and ff.weight,
--- italicangle = fields.italicangle and ff.italicangle,
--- units = fields.units_per_em and ff.units_per_em,
--- designsize = fields.design_size and ff.design_size,
--- minsize = fields.design_range_bottom and ff.design_range_bottom,
--- maxsize = fields.design_range_top and ff.design_range_top,
--- italicangle = fields.italicangle and ff.italicangle,
--- pfmweight = pfminfo and pfminfo.weight or 400,
--- pfmwidth = pfminfo and pfminfo.width or 5,
--- }
--- -- setmetatableindex(d,function(t,k)
--- -- report_names("warning, trying to access field %a in font table of %a",k,name)
--- -- end)
--- close_font(ff)
--- return d
--- else
--- return nil, "error in loading font"
--- end
--- end
-
--- more efficient:
-
-local fields = nil
-
-local function check_names(names)
- if names then
- for i=1,#names do
- local name = names[i]
- if lower(name.lang) == "english (us)" then -- lower added
- return name.names
- end
- end
- end
-end
-
-local function get_full_info(name)
- local ff = open_font(name)
- if ff then
- -- unfortunately luatex aborts when a field is not available but we just make
- -- sure that we only access a few known ones
- local pfminfo = ff.pfminfo or { }
- local names = check_names(ff.names) or { }
- local weight = names.weight or ff.weight
- local width = names.width -- no: ff.width
- local d = {
- fontname = ff.fontname,
- fullname = names.fullname or ff.fullname,
- family = names.family,
- subfamily = names.subfamily,
- familyname = names.preffamilyname or names.family or ff.familyname,
- subfamilyname = names.prefmodifiers or names.subfamily,
- weight = weight and lower(weight),
- width = width and lower(width),
- italicangle = round(1000*(tonumber(ff.italicangle) or 0))/1000 or 0,
- units = ff.units_per_em,
- designsize = ff.design_size,
- minsize = ff.design_range_bottom,
- maxsize = ff.design_range_top,
- pfmweight = pfminfo.weight or 400,
- pfmwidth = pfminfo.width or 5,
- monospaced = pfminfo.panose and pfminfo.panose.proportion == "Monospaced",
- }
- close_font(ff)
- return d
- else
- return nil, "error in loading font"
- end
-end
-
--- As we have lazy loading anyway, this one still is full and with less code than
--- the previous one. But this depends on the garbage collector to kick in and in the
--- current version that somehow happens not that often (on my machine I end up with
--- some 3 GB extra before that happens).
-
--- local function get_full_info(...)
--- local ff = open_font(...)
--- if ff then
--- local d = { } -- ff is userdata so [1] or # fails on it
--- setmetatableindex(d,ff)
--- return d -- garbage collection will do the close_font(ff)
--- else
--- return nil, "error in loading font"
--- end
--- end
-
-fonts = fonts or { }
-local handlers = fonts.handlers or { }
-fonts.handlers = handlers
-local otf = handlers.otf or { }
-handlers.otf = otf
-local readers = otf.readers or { }
-otf.readers = readers
-
-fontloader.fullinfo = get_full_info
-readers.getinfo = readers.getinfo or get_full_info
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-ogr.lua b/Master/texmf-dist/tex/context/base/mkiv/font-ogr.lua
new file mode 100644
index 00000000000..b45728c6cc1
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-ogr.lua
@@ -0,0 +1,670 @@
+if not modules then modules = { } end modules ['font-ogr'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- Here we deal with graphic variants and for now also color support ends up here
+-- but that might change. It's lmtx only code.
+
+if not context then
+ return
+elseif CONTEXTLMTXMODE == 0 then
+ return
+end
+
+local tostring, tonumber, next, type = tostring, tonumber, next, type
+local round, max, mod, div = math.round, math.max, math.mod, math.div
+local find = string.find
+local concat, setmetatableindex, sortedhash = table.concat, table.setmetatableindex, table.sortedhash
+local utfbyte = utf.byte
+local formatters = string.formatters
+local settings_to_hash_strict, settings_to_array = utilities.parsers.settings_to_hash_strict, utilities.parsers.settings_to_array
+
+local otf = fonts.handlers.otf
+local otfregister = otf.features.register
+otf.svgenabled = true
+otf.pngenabled = true
+
+-- Just to remind me ... rewritten around the time this was posted on YT which
+-- was also around the 2019 ctx meeting:
+--
+-- Gavin Harrison - "Threatening War" by The Pineapple Thief
+-- https://www.youtube.com/watch?v=ENF9wth4kwM
+
+-- todo: svg color plugin
+-- todo: get rid of double cm in svg (tricky as also elsewhere)
+-- todo: png offsets (depth)
+-- todo: maybe collapse indices so that we have less files (harder to debug)
+-- todo: manage (read: assign) font id's in lua so we know in advance
+
+-- what here and what in backend ...
+
+do
+
+ -- This is a prelude to something better but I'm still experimenting.
+
+ local dropins = { }
+ fonts.dropins = dropins
+ local droppedin = 0
+ local identifiers = fonts.hashes.identifiers
+
+ function dropins.nextid()
+ droppedin = droppedin - 1
+ return droppedin
+ end
+
+ -- todo: pass specification table instead
+
+ function dropins.provide(method,t_tfmdata,indexdata,...)
+ local droppedin = dropins.nextid()
+ local t_characters = t_tfmdata.characters
+ local t_descriptions = t_tfmdata.descriptions
+ local t_properties = t_tfmdata.properties
+ local d_tfmdata = setmetatableindex({ },t_tfmdata)
+ local d_properties = setmetatableindex({ },t_properties)
+ d_tfmdata.properties = d_properties
+ local d_characters = { } -- setmetatableindex({ },t_characters) -- hm, index vs unicode
+ local d_descriptions = { } -- setmetatableindex({ },t_descriptions) -- hm, index vs unicode
+ d_tfmdata.characters = d_characters
+ d_tfmdata.descriptions = d_descriptions
+ d_properties.instance = - droppedin -- will become an extra element in the hash
+ t_properties.virtualized = true
+ identifiers[droppedin] = d_tfmdata
+ local fonts = t_tfmdata.fonts or { }
+ t_tfmdata.fonts = fonts
+ d_properties.format = "type3"
+ d_properties.method = method
+ d_properties.indexdata = { indexdata, ... } -- can take quite some memory
+ local slot = #fonts + 1
+ fonts[slot] = { id = droppedin }
+ return slot, droppedin, d_tfmdata, d_properties
+ end
+
+ function dropins.clone(method,tfmdata,shapes,...) -- by index
+ if method and shapes then
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local droppedin, tfmdrop, dropchars, dropdescs, colrshapes
+ local idx = 255
+ local slot = 0
+ for k, v in next, characters do
+ local index = v.index
+ if index then
+ local description = descriptions[k]
+ if description then
+ local shape = shapes[index]
+ if shape then
+ if idx >= 255 then
+ idx = 1
+ colrshapes = setmetatableindex({ },shapes)
+ slot, droppedin, tfmdrop = dropins.provide(method,tfmdata,colrshapes)
+ dropchars = tfmdrop.characters
+ dropdescs = tfmdrop.descriptions
+ else
+ idx = idx + 1
+ end
+ colrshapes[idx] = shape -- so not: description
+ -- todo: prepend
+ v.commands = { { "slot", slot, idx } }
+ -- hack to prevent that type 3 also gets 'use' flags .. todo
+ local c = { commands = false, index = idx, dropin = tfmdrop }
+ local d = { } -- { index = idx, dropin = tfmdrop }
+ setmetatableindex(c,v)
+ setmetatableindex(d,description)
+ dropchars[idx] = c
+ dropdescs[idx] = d -- not needed
+ end
+ end
+ end
+ end
+ else
+ -- error
+ end
+ end
+
+ function dropins.swap(method,tfmdata,shapes,...) -- by unicode
+ if method and shapes then
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local droppedin, tfmdrop, dropchars, dropdescs, colrshapes
+ local idx = 255
+ local slot = 0
+ -- we can have a variant where shaped are by unicode and not by index
+ for k, v in next, characters do
+ local description = descriptions[k]
+ if description then
+ local shape = shapes[k]
+ if shape then
+ if idx >= 255 then
+ idx = 1
+ colrshapes = setmetatableindex({ },shapes)
+ slot, droppedin, tfmdrop = dropins.provide(method,tfmdata,colrshapes)
+ dropchars = tfmdrop.characters
+ dropdescs = tfmdrop.descriptions
+ else
+ idx = idx + 1
+ end
+ colrshapes[idx] = shape -- so not: description
+ -- todo: prepend
+ v.commands = { { "slot", slot, idx } }
+ -- hack to prevent that type 3 also gets 'use' flags .. todo
+ local c = { commands = false, index = idx, dropin = tfmdrop }
+ local d = { } -- index = idx, dropin = tfmdrop }
+ setmetatableindex(c,v)
+ setmetatableindex(d,description)
+ dropchars[idx] = c
+ dropdescs[idx] = d -- not needed
+ end
+ end
+ end
+ else
+ -- error
+ end
+ end
+
+end
+
+do -- this will move to its own module
+
+ local dropins = fonts.dropins
+
+ local shapes = setmetatableindex(function(t,k)
+ local v = {
+ glyphs = { },
+ parameters = {
+ units = 1000
+ },
+ }
+ t[k] = v
+ return v
+ end)
+
+ function dropins.registerglyphs(parameters)
+ local category = parameters.name
+ local target = shapes[category].parameters
+ for k, v in next, parameters do
+ if k ~= "glyphs" then
+ target[k] = v
+ end
+ end
+ end
+
+ function dropins.registerglyph(parameters)
+ local category = parameters.category
+ local unicode = parameters.unicode
+ local private = parameters.private
+ local unichar = parameters.unichar
+ if private then
+ unicode = fonts.helpers.newprivateslot(private)
+ elseif type(unichar) == "string" then
+ unicode = utfbyte(unichar)
+ else
+ local unitype = type(unicode)
+ if unitype == "string" then
+ local uninumber = tonumber(unicode)
+ if uninumber then
+ unicode = round(uninumber)
+ else
+ unicode = utfbyte(unicode)
+ end
+ elseif unitype == "number" then
+ unicode = round(unicode)
+ end
+ end
+ if unicode then
+ parameters.unicode = unicode
+ -- print(category,unicode)
+ shapes[category].glyphs[unicode] = parameters
+ else
+ -- error
+ end
+ end
+
+ -- local function hascolorspec(t)
+ -- if (t.color or "") ~= "" then
+ -- return true
+ -- elseif (t.fillcolor or "") ~= "" then
+ -- return true
+ -- elseif (t.drawcolor or "") ~= "" then
+ -- return true
+ -- elseif (t.linecolor or "") ~= "" then
+ -- return true
+ -- else
+ -- return false
+ -- end
+ -- end
+
+ local function hascolorspec(t)
+ for k, v in next, t do
+ if find(k,"color") then
+ return true
+ end
+ end
+ return false
+ end
+
+ local function initializemps(tfmdata,kind,value)
+ if value then
+ local specification = settings_to_hash_strict(value)
+ if not specification or not next(specification) then
+ specification = { category = value }
+ end
+ -- todo: multiple categories but then maybe also different
+ -- clones because of the units .. for now we assume the same
+ -- units
+ local category = specification.category
+ if category and category ~= "" then
+ local categories = settings_to_array(category)
+ local usedshapes = nil
+ local index = 0
+ local spread = tonumber(specification.spread or 0)
+ local hascolor = hascolorspec(specification)
+ specification.spread = spread -- now a number
+ for i=1,#categories do
+ local category = categories[i]
+ local mpsshapes = shapes[category]
+ if mpsshapes then
+ local properties = tfmdata.properties
+ local parameters = tfmdata.parameters
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local mpsparameters = mpsshapes.parameters
+ local units = mpsparameters.units or 1000
+ local defaultwidth = mpsparameters.width or 0
+ local defaultheight = mpsparameters.height or 0
+ local defaultdepth = mpsparameters.depth or 0
+ local usecolor = mpsparameters.usecolor
+ local spread = spread * units
+ local defaultcode = mpsparameters.code or ""
+ local scale = parameters.size / units
+ if hascolor then
+ -- the graphic has color
+ usecolor = false
+ else
+ -- do whatever is specified
+ end
+ usedshapes = usedshapes or {
+ instance = "simplefun",
+ units = units,
+ usecolor = usecolor,
+ specification = specification,
+ shapes = mpsshapes,
+ }
+ -- todo: deal with extensibles and more properties
+ for unicode, shape in sortedhash(mpsshapes.glyphs) do
+ -- local oldc = characters[unicode]
+ -- if oldc then
+ index = index + 1 -- todo: somehow we end up with 2 as first entry after 0
+ local wd = shape.width or defaultwidth
+ local ht = shape.height or defaultheight
+ local dp = shape.depth or defaultdepth
+ local newc = {
+ index = index, -- into usedshapes
+ width = scale * (wd + spread),
+ height = scale * ht,
+ depth = scale * dp,
+ unicode = unicode,
+ }
+ --
+ characters [unicode] = newc
+ descriptions[unicode] = newc
+ --
+ usedshapes[unicode] = shape.code or defaultcode
+ -- end
+ end
+ end
+ end
+ if usedshapes then
+ -- todo: different font when units and usecolor changes, maybe move into loop
+ -- above
+ dropins.swap("mps",tfmdata,usedshapes)
+ end
+ end
+ end
+ end
+
+ -- This kicks in quite late, after features have been checked. So if needed
+ -- substitutions need to be defined with force.
+
+ otfregister {
+ name = "metapost",
+ description = "metapost glyphs",
+ manipulators = {
+ base = initializemps,
+ node = initializemps,
+ }
+ }
+
+end
+
+-- This sits here for historcal reasons so for now we keep it here.
+
+local startactualtext = nil
+local stopactualtext = nil
+
+function otf.getactualtext(s)
+ if not startactualtext then
+ startactualtext = backends.codeinjections.startunicodetoactualtextdirect
+ stopactualtext = backends.codeinjections.stopunicodetoactualtextdirect
+ end
+ return startactualtext(s), stopactualtext()
+end
+
+-- This is also somewhat specific.
+
+local sharedpalettes do
+
+ sharedpalettes = { }
+
+ local colors = attributes.list[attributes.private('color')] or { }
+ local transparencies = attributes.list[attributes.private('transparency')] or { }
+
+ function otf.registerpalette(name,values)
+ sharedpalettes[name] = values
+ local color = lpdf.color
+ local transparency = lpdf.transparency
+ local register = colors.register
+ for i=1,#values do
+ local v = values[i]
+ if v == "textcolor" then
+ values[i] = false
+ else
+ local c = nil
+ local t = nil
+ if type(v) == "table" then
+ c = register(name,"rgb",
+ max(round((v.r or 0)*255),255)/255,
+ max(round((v.g or 0)*255),255)/255,
+ max(round((v.b or 0)*255),255)/255
+ )
+ else
+ c = colors[v]
+ t = transparencies[v]
+ end
+ if c and t then
+ values[i] = color(1,c) .. " " .. transparency(t)
+ elseif c then
+ values[i] = color(1,c)
+ elseif t then
+ values[i] = color(1,t)
+ end
+ end
+ end
+ end
+
+end
+
+local initializeoverlay do
+
+ -- we should use the proper interface instead but for now:
+
+ local colors = attributes.colors
+ local rgbtocmyk = colors.rgbtocmyk
+
+ local f_cmyk = formatters["%.3N %.3f %.3N %.3N k"]
+ local f_rgb = formatters["%.3N %.3f %.3N rg"]
+ local f_gray = formatters["%.3N g"]
+
+ local function convert(t,k)
+ local v = { }
+ local m = colors.model
+ for i=1,#k do
+ local p = k[i]
+ local r, g, b = p[1]/255, p[2]/255, p[3]/255
+ if r == g and g == b then
+ p = f_gray(r)
+ elseif m == "cmyk" then
+ p = f_cmyk(rgbtocmyk(r,g,b))
+ else
+ p = f_rgb(r,g,b)
+ end
+ v[i] = p
+ end
+ t[k] = v
+ return v
+ end
+
+ initializeoverlay = function(tfmdata,kind,value) -- we really need the id ... todo
+ if value then
+ local resources = tfmdata.resources
+ local palettes = resources.colorpalettes
+ if palettes then
+ --
+ local converted = resources.converted
+ if not converted then
+ converted = setmetatableindex(convert)
+ resources.converted = converted
+ end
+ local colorvalues = sharedpalettes[value]
+ local default = false -- so the text color (bad for icon overloads)
+ if colorvalues then
+ default = colorvalues[#colorvalues]
+ else
+ colorvalues = converted[palettes[tonumber(value) or 1] or palettes[1]] or { }
+ end
+ local classes = #colorvalues
+ if classes == 0 then
+ return
+ end
+ --
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local droppedin, tfmdrop, dropchars, dropdescs, colrshapes
+ local idx = 255
+ local slot = 0
+ --
+ -- todo: delay
+ --
+ for k, v in next, characters do
+ local index = v.index
+ if index then
+ local description = descriptions[k]
+ if description then
+ local colorlist = description.colors
+ if colorlist then
+ if idx >= 255 then
+ idx = 1
+ colrshapes = { }
+ slot, droppedin, tfmdrop = fonts.dropins.provide("color",tfmdata,colrshapes,colorvalues)
+ dropchars = tfmdrop.characters
+ dropdescs = tfmdrop.descriptions
+ else
+ idx = idx + 1
+ end
+ --
+ colrshapes[idx] = description
+ -- todo: use extender
+ local u = { "use", 0 }
+ for i=1,#colorlist do
+ u[i+2] = colorlist[i].slot
+ end
+ v.commands = { u, { "slot", slot, idx } }
+ -- hack to prevent that type 3 also gets 'use' flags .. todo
+ local c = { commands = false, index = idx, dropin = tfmdata }
+ local d = { } -- index = idx, dropin = tfmdrop
+ setmetatableindex(c,v)
+ setmetatableindex(d,description)
+ dropchars[idx] = c
+ dropdescs[idx] = d -- not needed
+ end
+ end
+ end
+ end
+ return true
+ end
+ end
+ end
+
+ fonts.handlers.otf.features.register {
+ name = "colr",
+ description = "color glyphs",
+ manipulators = {
+ base = initializeoverlay,
+ node = initializeoverlay,
+ }
+ }
+
+end
+
+local initializesvg do
+
+ local report_svg = logs.reporter("fonts","svg")
+
+ local cached = true -- maybe always false (after i've optimized the lot)
+
+ directives.register("fonts.svg.cached", function(v) cached = v end)
+
+ initializesvg = function(tfmdata,kind,value) -- hm, always value
+ if value then
+ local properties = tfmdata.properties
+ local svg = properties.svg
+ local hash = svg and svg.hash
+ local timestamp = svg and svg.timestamp
+ if not hash then
+ return
+ end
+ local shapes = nil
+ local method = nil
+ local enforce = attributes.colors.model == "cmyk"
+ if cached and not enforce then
+ -- we need a different hash than for mkiv, so we append:
+ local pdfhash = hash .. "-svg"
+ local pdffile = containers.read(otf.pdfcache,pdfhash)
+ local pdfshapes = pdffile and pdffile.pdfshapes
+ local pdftarget = file.join(otf.pdfcache.writable,file.addsuffix(pdfhash,"pdf"))
+ if not pdfshapes or pdffile.timestamp ~= timestamp or not next(pdfshapes) or not lfs.isfile(pdftarget) then
+ local svgfile = containers.read(otf.svgcache,hash)
+ local svgshapes = svgfile and svgfile.svgshapes
+ pdfshapes = svgshapes and metapost.svgshapestopdf(svgshapes,pdftarget,report_svg,tfmdata.parameters.units) or { }
+ -- look at ocl: we should store scale and x and y
+ containers.write(otf.pdfcache, pdfhash, {
+ pdfshapes = pdfshapes,
+ timestamp = timestamp,
+ })
+ end
+ shapes = pdfshapes
+ method = "pdf"
+ else
+ local mpsfile = containers.read(otf.mpscache,hash)
+ local mpsshapes = mpsfile and mpsfile.mpsshapes
+ if not mpsshapes or mpsfile.timestamp ~= timestamp or not next(mpsshapes) then
+ local svgfile = containers.read(otf.svgcache,hash)
+ local svgshapes = svgfile and svgfile.svgshapes
+ -- still suboptimal
+ mpsshapes = svgshapes and metapost.svgshapestomp(svgshapes,report_svg,tfmdata.parameters.units) or { }
+ if enforce then
+ -- cheap conversion, no black component generation
+ mpsshapes.preamble = "interim svgforcecmyk := 1;"
+ end
+ containers.write(otf.mpscache, hash, {
+ mpsshapes = mpsshapes,
+ timestamp = timestamp,
+ })
+ end
+ shapes = mpsshapes
+ method = "mps"
+ end
+ if shapes then
+ shapes.fixdepth = value == "fixdepth"
+ fonts.dropins.clone(method,tfmdata,shapes)
+ end
+ return true
+ end
+ end
+
+ otfregister {
+ name = "svg",
+ description = "svg glyphs",
+ manipulators = {
+ base = initializesvg,
+ node = initializesvg,
+ }
+ }
+
+end
+
+local initializepng do
+
+ -- If this is really critical we can also use a pdf file as cache but I don't expect
+ -- png fonts to remain used.
+
+ local colors = attributes.colors
+
+ local report_png = logs.reporter("fonts","png conversion")
+
+ initializepng = function(tfmdata,kind,value) -- hm, always value
+ if value then
+ local properties = tfmdata.properties
+ local png = properties.png
+ local hash = png and png.hash
+ local timestamp = png and png.timestamp
+ if not hash then
+ return
+ end
+ local pngfile = containers.read(otf.pngcache,hash)
+ local pngshapes = pngfile and pngfile.pngshapes
+ if pngshapes then
+ if colors.model == "cmyk" then
+ pngshapes.enforcecmyk = true
+ end
+ fonts.dropins.clone("png",tfmdata,pngshapes)
+ end
+ return true
+ end
+ end
+
+ otfregister {
+ name = "sbix",
+ description = "sbix glyphs",
+ manipulators = {
+ base = initializepng,
+ node = initializepng,
+ }
+ }
+
+ otfregister {
+ name = "cblc",
+ description = "cblc glyphs",
+ manipulators = {
+ base = initializepng,
+ node = initializepng,
+ }
+ }
+
+end
+
+do
+
+ -- I need to check jpeg and such but will do that when I run into
+ -- it.
+
+ local function initializecolor(tfmdata,kind,value)
+ if value == "auto" then
+ return
+ initializeoverlay(tfmdata,kind,value) or
+ initializesvg(tfmdata,kind,value) or
+ initializepng(tfmdata,kind,value)
+ elseif value == "overlay" then
+ return initializeoverlay(tfmdata,kind,value)
+ elseif value == "svg" then
+ return initializesvg(tfmdata,kind,value)
+ elseif value == "png" or value == "bitmap" then
+ return initializepng(tfmdata,kind,value)
+ else
+ -- forget about it
+ end
+ end
+
+ otfregister {
+ name = "color",
+ description = "color glyphs",
+ manipulators = {
+ base = initializecolor,
+ node = initializecolor,
+ }
+ }
+
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-one.lua b/Master/texmf-dist/tex/context/base/mkiv/font-one.lua
index 9b296cac551..5387516b4d5 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-one.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-one.lua
@@ -483,8 +483,9 @@ local function copytotfm(data)
local filename = constructors.checkedfilename(resources)
local fontname = metadata.fontname or metadata.fullname
local fullname = metadata.fullname or metadata.fontname
- local endash = 0x0020 -- space
+ local endash = 0x2013
local emdash = 0x2014
+ local space = 0x0020 -- space
local spacer = "space"
local spaceunits = 500
--
@@ -496,28 +497,33 @@ local function copytotfm(data)
parameters.italicangle = italicangle
parameters.charwidth = charwidth
parameters.charxheight = charxheight
- -- same as otf
+ -- nearly the same as otf, catches
+ local d_endash = descriptions[endash]
+ local d_emdash = descriptions[emdash]
+ local d_space = descriptions[space]
+ if not d_space or d_space == 0 then
+ d_space = d_endash
+ end
+ if d_space then
+ spaceunits, spacer = d_space.width or 0, "space"
+ end
if properties.monospaced then
- if descriptions[endash] then
- spaceunits, spacer = descriptions[endash].width, "space"
- end
- if not spaceunits and descriptions[emdash] then
- spaceunits, spacer = descriptions[emdash].width, "emdash"
- end
- if not spaceunits and charwidth then
- spaceunits, spacer = charwidth, "charwidth"
+ if spaceunits == 0 and d_emdash then
+ spaceunits, spacer = d_emdash.width or 0, "emdash"
end
else
- if descriptions[endash] then
- spaceunits, spacer = descriptions[endash].width, "space"
- end
- if not spaceunits and charwidth then
- spaceunits, spacer = charwidth, "charwidth"
+ if spaceunits == 0 and d_endash then
+ spaceunits, spacer = d_emdash.width or 0, "endash"
end
end
- spaceunits = tonumber(spaceunits)
- if spaceunits < 200 then
- -- todo: warning
+ if spaceunits == 0 and charwidth then
+ spaceunits, spacer = charwidth or 0, "charwidth"
+ end
+ if spaceunits == 0 then
+ spaceunits = tonumber(spaceunits) or 500
+ end
+ if spaceunits == 0 then
+ spaceunits = 500
end
--
parameters.slant = 0
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-onr.lua b/Master/texmf-dist/tex/context/base/mkiv/font-onr.lua
index 8523d8729ab..fc6bead5889 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-onr.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-onr.lua
@@ -21,7 +21,7 @@ add features.</p>
local fonts, logs, trackers, resolvers = fonts, logs, trackers, resolvers
-local next, type, tonumber, rawget, rawset = next, type, tonumber, rawget, rawset
+local next, type, tonumber, rawset = next, type, tonumber, rawset
local match, lower, gsub, strip, find = string.match, string.lower, string.gsub, string.strip, string.find
local char, byte, sub = string.char, string.byte, string.sub
local abs = math.abs
@@ -235,7 +235,6 @@ do
binary = decrypt(binary,55665,4)
local names = { }
-
local encoding = lpegmatch(p_filterencoding,ascii)
local metadata = lpegmatch(p_filtermetadata,ascii,1,{})
local glyphs = { }
@@ -255,7 +254,7 @@ do
},
}
-- only cff 1 in type 1 fonts
- fonts.handlers.otf.readers.parsecharstrings(false,data,glyphs,true,"cff",streams)
+ fonts.handlers.otf.readers.parsecharstrings(false,data,glyphs,true,"cff",streams,true)
else
lpegmatch(p_filternames,binary,1,filename)
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-osd.lua b/Master/texmf-dist/tex/context/base/mkiv/font-osd.lua
index f51ae7bf71b..b97ac9c6f57 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-osd.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-osd.lua
@@ -81,7 +81,7 @@ if not modules then modules = { } end modules ['font-osd'] = { -- script devanag
-- malayalam, oriya, tamil and tolugu but not all are checked. Also, some of the
-- code below might need to be adapted to the extra scripts.
-local insert, imerge, copy = table.insert, table.imerge, table.copy
+local insert, imerge, copy, tohash = table.insert, table.imerge, table.copy, table.tohash
local next, type = next, type
local report = logs.reporter("otf","devanagari")
@@ -114,7 +114,7 @@ local setchar = nuts.setchar
local getprop = nuts.getprop
local setprop = nuts.setprop
-local ischar = nuts.is_char
+local ischar = nuts.ischar
local insert_node_after = nuts.insert_after
local copy_node = nuts.copy
@@ -143,6 +143,7 @@ local s_half = states.half
local s_pref = states.pref
local s_blwf = states.blwf
local s_pstf = states.pstf
+local s_init = states.init
local replace_all_nbsp = nil
@@ -209,10 +210,10 @@ if not indicgroups and characters then
local indicorders = {
bp = { }, -- before_postscript
ap = { }, -- after_postscript
- bs = { }, -- before_half
- as = { }, -- after_half
- bh = { }, -- before_subscript
- ah = { }, -- after_subscript
+ bs = { }, -- before_subscript
+ as = { }, -- after_subscript
+ bh = { }, -- before_half
+ ah = { }, -- after_half
bm = { }, -- before_main
am = { }, -- after_main
}
@@ -324,17 +325,11 @@ local zw_char = { -- both_joiners_true
}
local dflt_true = {
- dflt = true
+ dflt = true,
}
-local two_defaults = {
- dev2 = dflt_true,
-}
-
-local one_defaults = {
- dev2 = dflt_true,
- deva = dflt_true,
-}
+local two_defaults = { }
+local one_defaults = { }
local false_flags = { false, false, false, false }
@@ -367,7 +362,7 @@ local sequence_reorder_reph = {
}
local sequence_reorder_pre_base_reordering_consonants = {
- features = { dv03 = two_defaults },
+ features = { dv03 = one_defaults },
flags = false_flags,
name = "dv03_reorder_pre_base_reordering_consonants",
order = { "dv03" },
@@ -399,34 +394,20 @@ local sequence_remove_joiners = {
-- as it might depends on the font. Not that it's a bottleneck.
local basic_shaping_forms = {
- -- init = true, -- new
- -- abvs = true, -- new
akhn = true,
blwf = true,
- -- calt = true, -- new
cjct = true,
half = true,
- -- haln = true, -- new
nukt = true,
pref = true,
- -- pres = true, -- new
pstf = true,
- -- psts = true, -- new
rkrf = true,
rphf = true,
vatu = true,
+ locl = true,
}
local valid = {
- -- akhn = true, -- malayalam
- -- rphf = true,
- -- pref = true,
- -- half = true,
- -- blwf = true,
- -- pstf = true,
- -- pres = true, -- malayalam
- -- blws = true, -- malayalam
- -- psts = true, -- malayalam
abvs = true,
akhn = true,
blwf = true,
@@ -448,6 +429,7 @@ local valid = {
psts = true,
haln = true,
calt = true,
+ locl = true,
}
local scripts = { }
@@ -462,7 +444,7 @@ for i=1,nofscripts do
local two = scripts_two[i]
scripts[one] = true
scripts[two] = true
- two_defaults[one] = dflt_true
+ two_defaults[two] = dflt_true
one_defaults[one] = dflt_true
one_defaults[two] = dflt_true
end
@@ -483,28 +465,75 @@ local function initializedevanagi(tfmdata)
local sequences = resources.sequences
local sharedfeatures = tfmdata.shared.features
--
- local lastmatch = 0
- for s=1,#sequences do -- classify chars
+ gsubfeatures["dv01"] = two_defaults -- reorder matras
+ gsubfeatures["dv02"] = two_defaults -- reorder reph
+ gsubfeatures["dv03"] = one_defaults -- reorder pre base reordering consonants
+ gsubfeatures["dv04"] = one_defaults -- remove joiners
+ --
+ local reorder_pre_base_reordering_consonants = copy(sequence_reorder_pre_base_reordering_consonants)
+ local reorder_reph = copy(sequence_reorder_reph)
+ local reorder_matras = copy(sequence_reorder_matras)
+ local remove_joiners = copy(sequence_remove_joiners)
+
+ local lastmatch = 0
+ for s=1,#sequences do -- classify chars and make sure basic_shaping_forms come first
local features = sequences[s].features
if features then
for k, v in next, features do
+ if k == "locl" then
+ local steps = sequences[s].steps
+ local nofsteps = sequences[s].nofsteps
+ for i=1,nofsteps do
+ local step = steps[i]
+ local coverage = step.coverage
+ if coverage then
+ for k, v in next, pre_mark do
+ local locl = coverage[k]
+ if locl then
+ if #locl > 0 then --contextchain; KE: is this right?
+ for j=1,#locl do
+ local ck = locl[j]
+ local f = ck[4]
+ local chainlookups = ck[6]
+ if chainlookups then
+ local chainlookup = chainlookups[f]
+ for j=1,#chainlookup do
+ local chainstep = chainlookup[j]
+ local steps = chainstep.steps
+ local nofsteps = chainstep.nofsteps
+ for i=1,nofsteps do
+ local step = steps[i]
+ local coverage = step.coverage
+ if coverage then
+ locl = coverage[k]
+ end
+ end
+ end
+ end
+ end
+ end
+ if locl then
+ reorder_matras.steps[1].coverage[locl] = true
+ end
+ end
+ end
+ end
+ end
+ end
if basic_shaping_forms[k] then
- lastmatch = s
+ lastmatch = lastmatch + 1
+ if s ~= lastmatch then
+ table.insert(sequences, lastmatch, table.remove(sequences, s))
+ end
end
end
end
end
local insertindex = lastmatch + 1
--
- gsubfeatures["dv01"] = two_defaults -- reorder matras
- gsubfeatures["dv02"] = two_defaults -- reorder reph
- gsubfeatures["dv03"] = two_defaults -- reorder pre base reordering consonants
- gsubfeatures["dv04"] = one_defaults -- remove joiners
- --
- local reorder_pre_base_reordering_consonants = copy(sequence_reorder_pre_base_reordering_consonants)
- local reorder_reph = copy(sequence_reorder_reph)
- local reorder_matras = copy(sequence_reorder_matras)
- local remove_joiners = copy(sequence_remove_joiners)
+ if tfmdata.properties.language then
+ dflt_true[tfmdata.properties.language] = true
+ end
--
insert(sequences,insertindex,reorder_pre_base_reordering_consonants)
insert(sequences,insertindex,reorder_reph)
@@ -512,6 +541,8 @@ local function initializedevanagi(tfmdata)
insert(sequences,insertindex,remove_joiners)
--
local blwfcache = { }
+ local vatucache = { }
+ local pstfcache = { }
local seqsubset = { }
local rephstep = {
coverage = { } -- will be adapted each work
@@ -520,6 +551,8 @@ local function initializedevanagi(tfmdata)
reph = false,
vattu = false,
blwfcache = blwfcache,
+ vatucache = vatucache,
+ pstfcache = pstfcache,
seqsubset = seqsubset,
reorderreph = rephstep,
@@ -539,41 +572,148 @@ local function initializedevanagi(tfmdata)
local features = sequence.features
local has_rphf = features.rphf
local has_blwf = features.blwf
- if has_rphf and has_rphf.deva then
+ local has_vatu = features.vatu
+ local has_pstf = features.pstf
+ if has_rphf and has_rphf[script] then
devanagari.reph = true
- elseif has_blwf and has_blwf.deva then
+ elseif (has_blwf and has_blwf[script] ) or (has_vatu and has_vatu[script] ) then
devanagari.vattu = true
for i=1,nofsteps do
local step = steps[i]
local coverage = step.coverage
if coverage then
for k, v in next, coverage do
- if not blwfcache[k] then
- blwfcache[k] = v
+ for h, w in next, halant do
+ if v[h] then
+ if not blwfcache[k] then
+ blwfcache[k] = v
+ end
+ end
+ if has_vatu and has_vatu[script] and not vatucache[k] then
+ vatucache[k] = v
+ end
+ end
+ end
+ end
+ end
+ elseif has_pstf and has_pstf[script] then
+ for i=1,nofsteps do
+ local step = steps[i]
+ local coverage = step.coverage
+ if coverage then
+ for k, v in next, coverage do
+ if not pstfcache[k] then
+ pstfcache[k] = v
+ end
+ end
+ for k, v in next, ra do
+ local r = coverage[k]
+ if r then
+ local found = false
+ if #r > 0 then -- contextchain; KE: is this right?
+ for j=1,#r do
+ local ck = r[j]
+ local f = ck[4]
+ local chainlookups = ck[6]
+ if chainlookups and chainlookups[f] then --KE: why is check for chainlookups[f] necessacy???
+ local chainlookup = chainlookups[f]
+ for j=1,#chainlookup do
+ local chainstep = chainlookup[j]
+ local steps = chainstep.steps
+ local nofsteps = chainstep.nofsteps
+ for i=1,nofsteps do
+ local step = steps[i]
+ local coverage = step.coverage
+ if coverage then
+ local h = coverage[k]
+ if h then
+ for k, v in next, h do
+ found = v and v.ligature
+ if found then
+ pre_base_reordering_consonants[found] = true
+ break
+ end
+ end
+ if found then
+ break
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ else
+ for k, v in next, r do
+ found = v and v.ligature
+ if found then
+ pre_base_reordering_consonants[found] = true
+ break
+ end
+ end
+ end
+ if found then
+ break
+ end
end
end
end
end
end
for kind, spec in next, features do
- -- if spec.dev2 and valid[kind] then
if valid[kind] and valid_two(spec)then
for i=1,nofsteps do
local step = steps[i]
local coverage = step.coverage
if coverage then
- local reph = false
+ local reph, rephbase = false, false
if kind == "rphf" then
-- rphf acts on consonant + halant
for k, v in next, ra do
local r = coverage[k]
if r then
+ rephbase = k
local h = false
- for k, v in next, halant do
- local h = r[k]
- if h then
- reph = h.ligature or false
- break
+ if #r > 0 then --contextchain; KE: is this right?
+ for j=1,#r do
+ local ck = r[j]
+ local f = ck[4]
+ local chainlookups = ck[6]
+ if chainlookups then
+ local chainlookup = chainlookups[f]
+ for j=1,#chainlookup do
+ local chainstep = chainlookup[j]
+ local steps = chainstep.steps
+ local nofsteps = chainstep.nofsteps
+ for i=1,nofsteps do
+ local step = steps[i]
+ local coverage = step.coverage
+ if coverage then
+ local r = coverage[k]
+ if r then
+ for k, v in next, halant do
+ local h = r[k]
+ if h then
+ reph = h.ligature or false
+ break
+ end
+ end
+ if h then
+ break
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ else
+ for k, v in next, halant do
+ local h = r[k]
+ if h then
+ reph = h.ligature or false
+ break
+ end
end
end
if reph then
@@ -582,7 +722,7 @@ local function initializedevanagi(tfmdata)
end
end
end
- seqsubset[#seqsubset+1] = { kind, coverage, reph }
+ seqsubset[#seqsubset+1] = { kind, coverage, reph, rephbase }
end
end
end
@@ -597,11 +737,46 @@ local function initializedevanagi(tfmdata)
local h = coverage[k]
if h then
local found = false
- for k, v in next, h do
- found = v and v.ligature
- if found then
- pre_base_reordering_consonants[k] = found
- break
+ if #h > 0 then -- contextchain; KE: is this right?
+ for j=1,#h do
+ local ck = h[j]
+ local f = ck[4]
+ local chainlookups = ck[6]
+ if chainlookups then
+ local chainlookup = chainlookups[f]
+ for j=1,#chainlookup do
+ local chainstep = chainlookup[j]
+ local steps = chainstep.steps
+ local nofsteps = chainstep.nofsteps
+ for i=1,nofsteps do
+ local step = steps[i]
+ local coverage = step.coverage
+ if coverage then
+ local h = coverage[k]
+ if h then
+ for k, v in next, h do
+ found = v and v.ligature
+ if found then
+ pre_base_reordering_consonants[found] = true
+ break
+ end
+ end
+ if found then
+ break
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ else
+ for k, v in next, h do
+ found = v and v.ligature
+ if found then
+ pre_base_reordering_consonants[found] = true
+ break
+ end
end
end
if found then
@@ -615,45 +790,17 @@ local function initializedevanagi(tfmdata)
end
end
--
- -- needs checking: this might be needed per instance ?
- --
- if script == "deva" then
- sharedfeatures["dv04"] = true -- dv04_remove_joiners
- elseif script == "dev2" then
+ if two_defaults[script] then
sharedfeatures["dv01"] = true -- dv01_reorder_matras
sharedfeatures["dv02"] = true -- dv02_reorder_reph
sharedfeatures["dv03"] = true -- dv03_reorder_pre_base_reordering_consonants
sharedfeatures["dv04"] = true -- dv04_remove_joiners
- elseif script == "mlym" then
- sharedfeatures["pstf"] = true
- elseif script == "mlm2" then
- sharedfeatures["pstf"] = true
- sharedfeatures["pref"] = true
+ elseif one_defaults[script] then
sharedfeatures["dv03"] = true -- dv03_reorder_pre_base_reordering_consonants
- gsubfeatures ["dv03"] = two_defaults -- reorder pre base reordering consonants
- insert(sequences,insertindex,sequence_reorder_pre_base_reordering_consonants)
- -- elseif script == "beng" then
- -- elseif script == "bng2" then
- -- elseif script == "gujr" then
- -- elseif script == "gjr2" then
- -- elseif script == "guru" then
- -- elseif script == "gur2" then
- -- elseif script == "knda" then
- -- elseif script == "knd2" then
- elseif script == "taml" then
sharedfeatures["dv04"] = true -- dv04_remove_joiners
-sharedfeatures["pstf"] = true
- elseif script == "tml2" then
--- sharedfeatures["pstf"] = true
--- sharedfeatures["pref"] = true
--- sharedfeatures["dv01"] = true -- dv01_reorder_matras
--- sharedfeatures["dv02"] = true -- dv02_reorder_reph
--- sharedfeatures["dv03"] = true -- dv03_reorder_pre_base_reordering_consonants
--- sharedfeatures["dv04"] = true -- dv04_remove_joiners
- -- elseif script == "telu" then
- -- elseif script == "tel2" then
- else
- report("todo: enable the right features for script %a",script)
+ end
+ if script == "mlym" or script == "taml" then
+ devanagari.left_matra_before_base = true
end
end
end
@@ -695,6 +842,8 @@ local function initialize_one(font,attr) -- we need a proper hook into the datas
reph = false,
vattu = false,
blwfcache = { },
+ vatucache = { },
+ pstfcache = { },
}
datasets.devanagari = devanagaridata
local resources = tfmdata.resources
@@ -707,31 +856,97 @@ local function initialize_one(font,attr) -- we need a proper hook into the datas
if kind == "rphf" then
-- deva
devanagaridata.reph = true
- elseif kind == "blwf" then
+ elseif kind == "blwf" or kind == "vatu" then
-- deva
devanagaridata.vattu = true
-- dev2
devanagaridata.blwfcache = devanagari.blwfcache
+ devanagaridata.vatucache = devanagari.vatucache
+ devanagaridata.pstfcache = devanagari.pstfcache
end
end
end
end
- return devanagaridata.reph, devanagaridata.vattu, devanagaridata.blwfcache
+ return devanagaridata.reph, devanagaridata.vattu, devanagaridata.blwfcache, devanagaridata.vatucache, devanagaridata.pstfcache
end
+local function contextchain(contexts, n)
+ local char = getchar(n)
+ for k=1,#contexts do
+ local ck = contexts[k]
+ local seq = ck[3]
+ local f = ck[4]
+ local l = ck[5]
+ if (l - f) == 1 and seq[f+1][char] then
+ local ok = true
+ local c = n
+ for i=l+1,#seq do
+ c = getnext(c)
+ if not c or not seq[i][ischar(c)] then
+ ok = false
+ break
+ end
+ end
+ if ok then
+ c = getprev(n)
+ for i=1,f-1 do
+ c = getprev(c)
+ if not c or not seq[f-i][ischar(c)] then
+ ok = false
+ end
+ end
+ end
+ if ok then
+ return true
+ end
+ end
+ end
+ return false
+end
+
+local function order_matras(c)
+ local cn = getnext(c)
+ local char = getchar(cn)
+ while dependent_vowel[char] do
+ local next = getnext(cn)
+ local cc = c
+ local cchar = getchar(cc)
+ while cc ~= cn do
+ if (above_mark[char] and (below_mark[cchar] or post_mark[cchar])) or (below_mark[char] and (post_mark[cchar])) then
+ local prev, next = getboth(cn)
+ if next then
+ setprev(next,prev)
+ end
+ -- todo: setlink
+ setnext(prev,next)
+ setnext(getprev(cc),cn)
+ setprev(cn,getprev(cc))
+ setnext(cn,cc)
+ setprev(cc,cn)
+ break
+ end
+ cc = getnext(cc)
+ cchar = getchar(cc)
+ end
+ cn = next
+ char = getchar(cn)
+ end
+end
+
local function reorder_one(head,start,stop,font,attr,nbspaces)
- local reph, vattu, blwfcache = initialize_one(font,attr) -- todo: a hash[font]
+ local reph, vattu, blwfcache, vatucache, pstfcache = initialize_one(font,attr) -- todo: a hash[font]
- local current = start
- local n = getnext(start)
- local base = nil
- local firstcons = nil
- local lastcons = nil
- local basefound = false
+ local devanagari = fontdata[font].resources.devanagari
+ local current = start
+ local n = getnext(start)
+ local base = nil
+ local firstcons = nil
+ local lastcons = nil
+ local basefound = false
if reph and ra[getchar(start)] and halant[getchar(n)] then
-- if syllable starts with Ra + H and script has 'Reph' then exclude Reph
@@ -814,8 +1029,11 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
if not base then
base = current
elseif blwfcache[char] then
- -- consonant has below-base (or post-base) form
+ -- consonant has below-base form
setprop(current,a_state,s_blwf)
+ elseif pstfcache[char] then
+ -- consonant has post-base form
+ setprop(current,a_state,s_pstf)
else
base = current
end
@@ -894,16 +1112,14 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
current = next
end
- if base ~= stop and getprop(base,a_state) then
+ if base ~= stop and getprop(base,a_state) then -- a_state can also be init
local next = getnext(base)
if halant[getchar(next)] and not (next ~= stop and getchar(getnext(next)) == c_zwj) then
setprop(base,a_state,unsetvalue)
end
end
- -- ToDo: split two- or three-part matras into their parts. Then, move the left 'matra' part to the beginning of the syllable.
- -- Not necessary for Devanagari. However it is necessay for other scripts, such as Tamil (e.g. TAMIL VOWEL SIGN O - 0BCA)
-
+ -- split two- or three-part matras into their parts. Then, move the left 'matra' part to the beginning of the syllable.
-- classify consonants and 'matra' parts as pre-base, above-base (Reph), below-base or post-base, and group elements of the syllable (consonants and 'matras') according to this classification
local current, allreordered, moved = start, false, { [base] = true }
@@ -929,6 +1145,17 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
n = getnext(n)
ch = getchar(n)
end
+
+ local tpm = twopart_mark[ch]
+ while tpm do
+ local extra = copy_node(n)
+ copyinjection(extra,n)
+ ch = tpm[1]
+ setchar(n,ch)
+ setchar(extra,tpm[2])
+ head = insert_node_after(head,current,extra)
+ tpm = twopart_mark[ch]
+ end
while c ~= stop and dependent_vowel[ch] do
c = n
n = getnext(n)
@@ -947,15 +1174,51 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
end
end
end
- local bp = getprev(firstcons)
- local cn = getnext(current)
+ local bp = getprev(firstcons)
+ local cn = getnext(current)
local last = getnext(c)
while cn ~= last do
-- move pre-base matras...
if pre_mark[getchar(cn)] then
- if bp then
- setnext(bp,cn)
+ if devanagari.left_matra_before_base then
+ local prev, next = getboth(cn)
+ setlink(prev,next)
+ if cn == stop then
+ stop = getprev(cn)
+ end
+ if base == start then
+ if head == start then
+ head = cn
+ end
+ start = cn
+ end
+ setlink(getprev(base),cn)
+ setlink(cn,base)
+ -- setlink(getprev(base),cn,base) -- maybe
+ cn = next
+ else
+ if bp then
+ setnext(bp,cn)
+ end
+ local prev, next = getboth(cn)
+ if next then
+ setprev(next,prev)
+ end
+ setnext(prev,next)
+ if cn == stop then
+ stop = prev
+ end
+ setprev(cn,bp)
+ setlink(cn,firstcons)
+ if firstcons == start then
+ if head == start then
+ head = cn
+ end
+ start = cn
+ end
+ cn = next
end
+ elseif current ~= base and dependent_vowel[getchar(cn)] then
local prev, next = getboth(cn)
if next then
setprev(next,prev)
@@ -964,17 +1227,19 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
if cn == stop then
stop = prev
end
- setprev(cn,bp)
- setlink(cn,firstcons)
- if firstcons == start then
- if head == start then
- head = cn
- end
- start = cn
+ setlink(b,cn,getnext(b))
+ order_matras(cn)
+ cn = next
+ elseif current == base and dependent_vowel[getchar(cn)] then
+ local cnn = getnext(cn)
+ order_matras(cn)
+ cn = cnn
+ while cn ~= last and dependent_vowel[getchar(cn)] do
+ cn = getnext(cn)
end
- break
+ else
+ cn = getnext(cn)
end
- cn = getnext(cn)
end
allreordered = c == stop
current = getnext(c)
@@ -1020,7 +1285,7 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
local cp = getprev(current)
local cnsn = getnext(cns)
setlink(cp,n)
- setlink(cns,current)
+ setlink(cns,current) -- cns ?
setlink(c,cnsn)
if c == stop then
stop = cp
@@ -1036,6 +1301,13 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
if halant[getchar(next)] then
cns = next
end
+ if not vatucache[char] then
+ next = getnext(cns)
+ while dependent_vowel[getchar(next)] do
+ cns = next
+ next = getnext(cns)
+ end
+ end
elseif char == c_nbsp then
nbspaces = nbspaces + 1
cns = current
@@ -1043,6 +1315,13 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
if halant[getchar(next)] then
cns = next
end
+ if not vatucache[char] then
+ next = getnext(cns)
+ while dependent_vowel[getchar(next)] do
+ cns = next
+ next = getnext(cns)
+ end
+ end
end
end
current = getnext(current)
@@ -1051,6 +1330,9 @@ local function reorder_one(head,start,stop,font,attr,nbspaces)
if getchar(base) == c_nbsp then
nbspaces = nbspaces - 1
+ if base == stop then
+ stop = getprev(stop)
+ end
head = remove_node(head,base)
flush_node(base)
end
@@ -1075,7 +1357,7 @@ function handlers.devanagari_reorder_matras(head,start) -- no leak
local char = ischar(current,startfont)
local next = getnext(current)
if char and getprop(current,a_syllabe) == startattr then
- if halant[char] and not getprop(current,a_state) then
+ if halant[char] then -- a_state can also be init
if next then
local char = ischar(next,startfont)
if char and zw_char[char] and getprop(next,a_syllabe) == startattr then
@@ -1091,6 +1373,18 @@ function handlers.devanagari_reorder_matras(head,start) -- no leak
-- setlink(current,start,next) -- maybe
start = startnext
break
+ -- elseif consonant[char] and ( not getprop(current,a_state) or getprop(current,a_state) == s_init) then
+ -- startnext = getnext(start)
+ -- head = remove_node(head,start)
+ -- if current == head then
+ -- setlink(start,current)
+ -- head = start
+ -- else
+ -- setlink(getprev(current),start)
+ -- setlink(start,current)
+ -- end
+ -- start = startnext
+ -- break
end
else
break
@@ -1109,6 +1403,8 @@ end
-- In Devanagari reph has reordering position 'before postscript' and dev2 only
-- follows step 2, 4, and 6.
+local rephbase = { }
+
function handlers.devanagari_reorder_reph(head,start)
local current = getnext(start)
local startnext = nil
@@ -1120,6 +1416,12 @@ function handlers.devanagari_reorder_reph(head,start)
--
-- If reph should be positioned after post-base consonant forms, proceed to step 5.
--
+ local char = ischar(start,startfont)
+ local rephbase = rephbase[startfont][char]
+ if char and after_subscript[rephbase] then
+ goto step_5
+ end
+ --
::step_2::
--
-- If the reph repositioning class is not after post-base: target position is after
@@ -1130,39 +1432,64 @@ function handlers.devanagari_reorder_reph(head,start)
-- fixed in shaping engine, there was no case where reph position will be found on
-- this step.
--
- while current do
- local char = ischar(current,startfont)
- if char and getprop(current,a_syllabe) == startattr then
- if halant[char] and not getprop(current,a_state) then
- local next = getnext(current)
- if next then
- local nextchar = ischar(next,startfont)
- if nextchar and zw_char[nextchar] and getprop(next,a_syllabe) == startattr then
- current = next
- next = getnext(current)
+ if char and not after_postscript[rephbase] then
+ while current do
+ local char = ischar(current,startfont)
+ if char and getprop(current,a_syllabe) == startattr then
+ if halant[char] then
+ local next = getnext(current)
+ if next then
+ local nextchar = ischar(next,startfont)
+ if nextchar and zw_char[nextchar] and getprop(next,a_syllabe) == startattr then
+ current = next
+ next = getnext(current)
+ end
end
+ startnext = getnext(start)
+ head = remove_node(head,start)
+ setlink(start,next)
+ setlink(current,start)
+ -- setlink(current,start,next) -- maybe
+ start = startnext
+ startattr = getprop(start,a_syllabe)
+ break
end
- startnext = getnext(start)
- head = remove_node(head,start)
- setlink(start,next)
- setlink(current,start)
- -- setlink(current,start,next) -- maybe
- start = startnext
- startattr = getprop(start,a_syllabe)
+ current = getnext(current)
+ else
break
end
- current = getnext(current)
- else
- break
end
end
+ --
::step_3::
--
- -- If reph should be repositioned after the main consonant: from the first consonant
+ -- If reph should be repositioned after the main consonant: find the first consonant
-- not ligated with main, or find the first consonant that is not a potential
-- pre-base reordering Ra.
--
- -- Kai: todo
+ if not startnext then
+ if char and after_main[rephbase] then
+ current = getnext(start)
+ while current do
+ local char = ischar(current,startfont)
+ if char and getprop(current,a_syllabe) == startattr then
+ if consonant[char] and not getprop(current,a_state) == s_pref then
+ startnext = getnext(start)
+ head = remove_node(head,start)
+ setlink(current,start)
+ setlink(start,getnext(current))
+ -- setlink(current,start,getnext(current)) -- maybe
+ start = startnext
+ startattr = getprop(start,a_syllabe)
+ break
+ end
+ current = getnext(current)
+ else
+ break
+ end
+ end
+ end
+ end
--
::step_4::
--
@@ -1171,23 +1498,37 @@ function handlers.devanagari_reorder_reph(head,start)
-- position should be before the first matra, syllable modifier sign or vedic sign.
--
if not startnext then
- current = getnext(start)
- while current do
- local char = ischar(current,startfont)
- if char and getprop(current,a_syllabe) == startattr then
- if getprop(current,a_state) == s_pstf then -- post-base
- startnext = getnext(start)
- head = remove_node(head,start)
- setlink(getprev(current),start)
- setlink(start,current)
- -- setlink(getprev(current),start,current) -- maybe
- start = startnext
- startattr = getprop(start,a_syllabe)
+ if char and before_postscript[rephbase] then
+ current = getnext(start)
+ local c = nil
+ while current do
+ local char = ischar(current,startfont)
+ if char and getprop(current,a_syllabe) == startattr then
+ if getprop(current,a_state) == s_pstf then -- post-base
+ startnext = getnext(start)
+ head = remove_node(head,start)
+ setlink(getprev(current),start)
+ setlink(start,current)
+ -- setlink(getprev(current),start,current) -- maybe
+ start = startnext
+ startattr = getprop(start,a_syllabe)
+ break
+ elseif not c and ( vowel_modifier[char] or stress_tone_mark[char] ) then
+ c = current
+ end
+ current = getnext(current)
+ else
+ if c then
+ startnext = getnext(start)
+ head = remove_node(head,start)
+ setlink(getprev(c),start)
+ setlink(start,c)
+ -- setlink(getprev(c),start,c) -- maybe
+ start = startnext
+ startattr = getprop(start,a_syllabe)
+ end
break
end
- current = getnext(current)
- else
- break
end
end
end
@@ -1206,7 +1547,10 @@ function handlers.devanagari_reorder_reph(head,start)
while current do
local char = ischar(current,startfont)
if char and getprop(current,a_syllabe) == startattr then
- if not c and mark_above_below_post[char] and not after_subscript[char] then
+ local state = getprop(current,a_state)
+ if before_subscript[rephbase] and (state == s_blwf or state == s_pstf) then
+ c = current
+ elseif after_subscript[rephbase] and (state == s_pstf) then
c = current
end
current = getnext(current)
@@ -1271,67 +1615,82 @@ end
-- return head, start, done
-- end
+local reordered_pre_base_reordering_consonants = { } -- shared ? not reset ?
+
function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
- local current = start
- local startnext = nil
- local startprev = nil
+ if reordered_pre_base_reordering_consonants[start] then
+ return head, start, true
+ end
+ local current = start -- we could cache attributes here
local startfont = getfont(start)
local startattr = getprop(start,a_syllabe)
- -- can be fast for loop + caching state
while current do
local char = ischar(current,startfont)
+ local next = getnext(current)
if char and getprop(current,a_syllabe) == startattr then
- local next = getnext(current)
- if halant[char] and not getprop(current,a_state) then
+ if halant[char] then -- a_state can also be init
if next then
- local nextchar = ischar(next,startfont)
- if nextchar and getprop(next,a_syllabe) == startattr then
- if nextchar == c_zwnj or nextchar == c_zwj then
- current = next
- next = getnext(current)
- end
+ local char = ischar(next,startfont)
+ if char and zw_char[char] and getprop(next,a_syllabe) == startattr then
+ current = next
+ next = getnext(current)
end
end
- startnext = getnext(start)
- removenode(start,start)
+ -- can be optimzied
+ local startnext = getnext(start)
+ head = remove_node(head,start)
setlink(start,next)
setlink(current,start)
-- setlink(current,start,next) -- maybe
+ reordered_pre_base_reordering_consonants[start] = true
start = startnext
- break
+ return head, start, true
+ -- elseif consonant[char] and ( not getprop(current,a_state) or getprop(current,a_state) == s_init) then
+ -- startnext = getnext(start)
+ -- head = remove_node(head,start)
+ -- if current == head then
+ -- setlink(start,current)
+ -- head = start
+ -- else
+ -- setlink(getprev(current),start)
+ -- setlink(start,current)
+ -- end
+ -- start = startnext
+ -- break
end
- current = next
else
break
end
+ current = next
end
- if not startnext then
- current = getnext(start)
- startattr = getprop(start,a_syllabe)
- while current do
- local char = ischar(current,startfont)
- if char and getprop(current,a_syllabe) == startattr then
- if not consonant[char] and getprop(current,a_state) then -- main
- startnext = getnext(start)
- removenode(start,start)
- setlink(getprev(current),start)
- setlink(start,current)
- -- setlink(getprev(current),start,current) -- maybe
- start = startnext
- break
- end
- current = getnext(current)
+
+ local startattr = getprop(start,a_syllabe)
+ local current = getprev(start)
+ while current and getprop(current,a_syllabe) == startattr do
+ local char = ischar(current)
+ if ( not dependent_vowel[char] and not getprop(current,a_state) or getprop(current,a_state) == s_init) then
+ startnext = getnext(start)
+ head = remove_node(head,start)
+ if current == head then
+ setlink(start,current)
+ head = start
else
- break
+ setlink(getprev(current),start)
+ setlink(start,current)
end
+ reordered_pre_base_reordering_consonants[start] = true
+ start = startnext
+ break
end
+ current = getprev(current)
end
+
return head, start, true
end
function handlers.devanagari_remove_joiners(head,start,kind,lookupname,replacement)
local stop = getnext(start)
- local font = getfont(start) -- hm
+ local font = getfont(start)
local last = start
while stop do
local char = ischar(stop,font)
@@ -1372,15 +1731,15 @@ end
-- of the actions
local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pass over (determine stop in sweep)
-
local seqsubset, reorderreph = initialize_two(font,attr)
- local reph = false -- was nil ... probably went unnoticed because never assigned
local halfpos = nil
local basepos = nil
local subpos = nil
local postpos = nil
- local locl = { }
+
+ reorderreph.coverage = { }
+ rephbase[font] = { }
for i=1,#seqsubset do
@@ -1390,17 +1749,17 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
local kind = subset[1]
local lookupcache = subset[2]
if kind == "rphf" then
- reph = subset[3]
+ reorderreph.coverage[subset[3]] = true -- neat
+ rephbase[font][subset[3]] = subset[4]
local current = start
local last = getnext(stop)
while current ~= last do
if current ~= stop then
- local c = locl[current] or getchar(current)
+ local c = getchar(current)
local found = lookupcache[c]
if found then
local next = getnext(current)
- local n = locl[next] or getchar(next)
- if found[n] then --above-base: rphf Consonant + Halant
+ if found[getchar(next)] or contextchain(found, next) then --above-base: rphf Consonant + Halant
local afternext = next ~= stop and getnext(next)
if afternext and zw_char[getchar(afternext)] then -- ZWJ and ZWNJ prevent creation of reph
current = afternext -- getnext(next)
@@ -1420,15 +1779,16 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
local last = getnext(stop)
while current ~= last do
if current ~= stop then
- local c = locl[current] or getchar(current)
+ local c = getchar(current)
local found = lookupcache[c]
if found then -- pre-base: pref Halant + Consonant
local next = getnext(current)
- local n = locl[next] or getchar(next)
- if found[n] then
- setprop(current,a_state,s_pref)
- setprop(next,a_state,s_pref)
- current = next
+ if found[getchar(next)] or contextchain(found, next) then
+ if (not getprop(current,a_state) and not getprop(next,a_state)) then --KE: a_state can also be init...
+ setprop(current,a_state,s_pref)
+ setprop(next,a_state,s_pref)
+ current = next
+ end
end
end
end
@@ -1439,15 +1799,14 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
local last = getnext(stop)
while current ~= last do
if current ~= stop then
- local c = locl[current] or getchar(current)
+ local c = getchar(current)
local found = lookupcache[c]
if found then
local next = getnext(current)
- local n = locl[next] or getchar(next)
- if found[n] then
+ if found[getchar(next)] or contextchain(found, next) then
if next ~= stop and getchar(getnext(next)) == c_zwnj then -- zwnj prevent creation of half
current = next
- else
+ elseif (not getprop(current,a_state)) then --KE: a_state can also be init...
setprop(current,a_state,s_half)
if not halfpos then
halfpos = current
@@ -1459,21 +1818,22 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
end
current = getnext(current)
end
- elseif kind == "blwf" then -- below-base: blwf / Halant + Consonant
+ elseif kind == "blwf" or kind == "vatu" then -- below-base: blwf / Halant + Consonant
local current = start
local last = getnext(stop)
while current ~= last do
if current ~= stop then
- local c = locl[current] or getchar(current)
+ local c = getchar(current)
local found = lookupcache[c]
if found then
local next = getnext(current)
- local n = locl[next] or getchar(next)
- if found[n] then
- setprop(current,a_state,s_blwf)
- setprop(next,a_state,s_blwf)
- current = next
- subpos = current
+ if found[getchar(next)] or contextchain(found, next) then
+ if (not getprop(current,a_state) and not getprop(next,a_state)) then --KE: a_state can also be init...
+ setprop(current,a_state,s_blwf)
+ setprop(next,a_state,s_blwf)
+ current = next
+ subpos = current
+ end
end
end
end
@@ -1484,16 +1844,17 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
local last = getnext(stop)
while current ~= last do
if current ~= stop then
- local c = locl[current] or getchar(current)
+ local c = getchar(current)
local found = lookupcache[c]
if found then
local next = getnext(current)
- local n = locl[next] or getchar(next)
- if found[n] then
- setprop(current,a_state,s_pstf)
- setprop(next,a_state,s_pstf)
- current = next
- postpos = current
+ if found[getchar(next)] or contextchain(found, next) then
+ if (not getprop(current,a_state) and not getprop(next,a_state)) then --KE: a_state can also be init...
+ setprop(current,a_state,s_pstf)
+ setprop(next,a_state,s_pstf)
+ current = next
+ postpos = current
+ end
end
end
end
@@ -1502,12 +1863,6 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
end
end
- -- this one changes per word ...
-
- reorderreph.coverage = { [reph] = true } -- neat
-
- -- end of weird
-
local current, base, firstcons = start, nil, nil
if getprop(start,a_state) == s_rphf then
@@ -1573,7 +1928,7 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
end
-- check whether consonant has below-base or post-base form or is pre-base reordering Ra
local a = getprop(current,a_state)
- if not (a == s_pref or a == s_blwf or a == s_pstf) then
+ if not (a == s_blwf or a == s_pstf or (a ~= s_rphf and a ~= s_blwf and ra[getchar(current)])) then
base = current
end
end
@@ -1591,7 +1946,7 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
end
return head, stop, nbspaces
else
- if getprop(base,a_state) then
+ if getprop(base,a_state) then -- a_state can also be init
setprop(base,a_state,unsetvalue)
end
basepos = base
@@ -1608,24 +1963,27 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
-- Matra characters are classified and reordered by which consonant in a conjunct they have affinity for
- local moved = { }
+ local moved = { }
local current = start
- local last = getnext(stop)
+ local last = getnext(stop)
while current ~= last do
- local char, target, cn = locl[current] or getchar(current), nil, getnext(current)
+ local char = getchar(current)
+ local target = nil
+ local cn = getnext(current)
-- not so efficient (needed for malayalam)
local tpm = twopart_mark[char]
- if tpm then
+ while tpm do
local extra = copy_node(current)
copyinjection(extra,current)
char = tpm[1]
setchar(current,char)
setchar(extra,tpm[2])
head = insert_node_after(head,current,extra)
+ tpm = twopart_mark[char]
end
--
if not moved[current] and dependent_vowel[char] then
- if pre_mark[char] then -- Before first half form in the syllable
+ if pre_mark[char] then -- or: if before_main or before_half
moved[current] = true
-- can be helper to remove one node
local prev, next = getboth(current)
@@ -1633,17 +1991,47 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
if current == stop then
stop = getprev(current)
end
- if halfpos == start then
+
+ local pos
+ if before_main[char] then
+ pos = basepos
+ -- basepos = current -- is this correct?
+ else
+ -- must be before_half
+ pos = halfpos
+ -- halfpos = current -- is this correct?
+ end
+
+ local ppos = getprev(pos) -- necessary?
+ while ppos and getprop(ppos,a_syllabe) == getprop(pos,a_syllabe) do
+ if getprop(ppos,a_state) == s_pref then
+ pos = ppos
+ end
+ ppos = getprev(ppos)
+ end
+
+ local ppos = getprev(pos) -- necessary?
+ while ppos and getprop(ppos,a_syllabe) == getprop(pos,a_syllabe) and halant[ischar(ppos)] do
+ ppos = getprev(ppos)
+ if ppos and getprop(ppos,a_syllabe) == getprop(pos,a_syllabe) and consonant[ischar(ppos)] then
+ pos = ppos
+ ppos = getprev(ppos)
+ else
+ break
+ end
+ end
+
+ if pos == start then
if head == start then
head = current
end
start = current
end
- setlink(getprev(halfpos),current)
- setlink(current,halfpos)
- -- setlink(getprev(halfpos),current,halfpos) -- maybe
- halfpos = current
- elseif above_mark[char] then -- After main consonant
+ setlink(getprev(pos),current)
+ setlink(current,pos)
+ -- setlink(getprev(pos),current,pos) -- maybe
+ elseif above_mark[char] then
+ -- after main consonant
target = basepos
if subpos == basepos then
subpos = current
@@ -1652,13 +2040,25 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
postpos = current
end
basepos = current
- elseif below_mark[char] then -- After subjoined consonants
+ elseif below_mark[char] then
+ -- after subjoined consonants
target = subpos
if postpos == subpos then
postpos = current
end
subpos = current
- elseif post_mark[char] then -- After post-form consonant
+ elseif post_mark[char] then
+ -- after post-form consonant
+ local n = getnext(postpos) -- nukta and vedic sign come first - is that right? and also halant+ra
+ while n do
+ local v = ischar(n,font)
+ if nukta[v] or stress_tone_mark[v] or vowel_modifier[v] then
+ postpos = n
+ else
+ break
+ end
+ n = getnext(n)
+ end
target = postpos
postpos = current
end
@@ -1679,9 +2079,44 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pas
current = cn
end
+ -- reorder halant+Ra
+
+ local current = getnext(start)
+ local last = getnext(stop)
+ while current ~= last do
+ local char = getchar(current)
+ local cn = getnext(current)
+ if halant[char] and ra[ischar(cn)] and getprop(cn,a_state) ~= s_rphf and getprop(cn,a_state) ~= s_blwf then
+ if after_main[ischar(cn)] then
+ local prev = getprev(current)
+ local next = getnext(cn)
+ local bpn = getnext(basepos)
+ while bpn and dependent_vowel[ischar(bpn)] do
+ basepos = bpn
+ bpn = getnext(bpn)
+ end
+ if basepos ~= prev then
+ setlink(prev,next)
+ setlink(cn, getnext(basepos))
+ setlink(basepos, current)
+ if cn == stop then
+ stop = prev
+ end
+ cn = next
+ end
+ end
+ -- after_postscript
+ -- after_subscript
+ -- before_postscript
+ -- before_subscript
+ end
+ current = cn
+ end
+
-- Reorder marks to canonical order: Adjacent nukta and halant or nukta and vedic sign are always repositioned if necessary, so that the nukta is first.
- local current, c = start, nil
+ local current = start
+ local c = nil
while current ~= stop do
local char = getchar(current)
if halant[char] or stress_tone_mark[char] then
@@ -1810,7 +2245,25 @@ local function analyze_next_chars_one(c,font,variant) -- skip one dependent vowe
if not v then
return c
end
- if dependent_vowel[v] then
+ local already_pre_mark -- = false
+ local already_above_mark -- = false
+ local already_below_mark -- = false
+ local already_post_mark -- = false
+ while dependent_vowel[v] do
+ local vowels = twopart_mark[v] or { v }
+ for k, v in next, vowels do
+ if pre_mark[v] and not already_pre_mark then
+ already_pre_mark = true
+ elseif above_mark[v] and not already_above_mark then
+ already_above_mark = true
+ elseif below_mark[v] and not already_below_mark then
+ already_below_mark = true
+ elseif post_mark[v] and not already_post_mark then
+ already_post_mark = true
+ else
+ return c
+ end
+ end
c = getnext(c)
n = getnext(c)
if not n then
@@ -1982,7 +2435,25 @@ local function analyze_next_chars_two(c,font)
else
-- c = ms_matra(c)
-- same as one
- if dependent_vowel[v] then
+ local already_pre_mark -- = false
+ local already_above_mark -- = false
+ local already_below_mark -- = false
+ local already_post_mark -- = false
+ while dependent_vowel[v] do
+ local vowels = twopart_mark[v] or { v }
+ for k, v in next, vowels do
+ if pre_mark[v] and not already_pre_mark then
+ already_pre_mark = true
+ elseif above_mark[v] and not already_above_mark then
+ already_above_mark = true
+ elseif below_mark[v] and not already_below_mark then
+ already_below_mark = true
+ elseif post_mark[v] and not already_post_mark then
+ already_post_mark = true
+ else
+ return c
+ end
+ end
c = n
n = getnext(c)
if not n then
@@ -2054,6 +2525,7 @@ local function method_one(head,font,attr)
local start = true
local done = false
local nbspaces = 0
+ local syllabe = 0
while current do
local char = ischar(current,font)
if char then
@@ -2203,6 +2675,15 @@ local function method_one(head,font,attr)
end
end
if syllablestart ~= syllableend then
+ if syllableend then
+ syllabe = syllabe + 1
+ local c = syllablestart
+ local n = getnext(syllableend)
+ while c ~= n do
+ setprop(c,a_syllabe,syllabe)
+ c = getnext(c)
+ end
+ end
head, current, nbspaces = reorder_one(head,syllablestart,syllableend,font,attr,nbspaces)
current = getnext(current)
end
@@ -2244,6 +2725,21 @@ local function method_one(head,font,attr)
head = replace_all_nbsp(head)
end
+ current = head
+ local n = 0
+ while current do
+ local char = ischar(current,font)
+ if char then
+ if n == 0 and not getprop(current,a_state) then
+ setprop(current,a_state,s_init)
+ end
+ n = n + 1
+ else
+ n = 0
+ end
+ current = getnext(current)
+ end
+
return head, done
end
@@ -2324,7 +2820,7 @@ local function method_two(head,font,attr)
end
if not syllableend and show_syntax_errors then
local char = ischar(current,font)
- if char and not getprop(current,a_state) then
+ if char and not getprop(current,a_state) then -- a_state can also be init
local mark = mark_four[char]
if mark then
head, current = inject_syntax_error(head,current,char)
@@ -2339,6 +2835,21 @@ local function method_two(head,font,attr)
head = replace_all_nbsp(head)
end
+ current = head
+ local n = 0
+ while current do
+ local char = ischar(current,font)
+ if char then
+ if n == 0 and not getprop(current,a_state) then -- a_state can also be init
+ setprop(current,a_state,s_init)
+ end
+ n = n + 1
+ else
+ n = 0
+ end
+ current = getnext(current)
+ end
+
return head, done
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-ota.lua b/Master/texmf-dist/tex/context/base/mkiv/font-ota.lua
index 76c267a8176..3d217b3f4d0 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-ota.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-ota.lua
@@ -39,7 +39,7 @@ local getprop = nuts.getprop
local setprop = nuts.setprop
local getsubtype = nuts.getsubtype
local getchar = nuts.getchar
-local ischar = nuts.is_char
+local ischar = nuts.ischar
local end_of_math = nuts.end_of_math
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-otc.lua b/Master/texmf-dist/tex/context/base/mkiv/font-otc.lua
index a774a81c2c9..2643d022a57 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-otc.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-otc.lua
@@ -22,9 +22,10 @@ local otf = fonts.handlers.otf
local registerotffeature = otf.features.register
local setmetatableindex = table.setmetatableindex
-local checkmerge = fonts.helpers.checkmerge
-local checkflags = fonts.helpers.checkflags
-local checksteps = fonts.helpers.checksteps
+local fonthelpers = fonts.helpers
+local checkmerge = fonthelpers.checkmerge
+local checkflags = fonthelpers.checkflags
+local checksteps = fonthelpers.checksteps
local normalized = {
substitution = "substitution",
@@ -167,6 +168,7 @@ local function addfeature(data,feature,specifications)
local done = 0
local skip = 0
local aglunicodes = false
+ local privateslot = fonthelpers.privateslot
local specifications = validspecification(specifications,feature)
if not specifications then
@@ -196,6 +198,13 @@ local function addfeature(data,feature,specifications)
return u
end
end
+ if privateslot then
+ u = privateslot(code) -- no creation !
+ if u then
+ -- unicodes[code] = u
+ return u
+ end
+ end
local u = lpegmatch(p,code)
if u then
-- unicodes[code] = u
@@ -229,7 +238,7 @@ local function addfeature(data,feature,specifications)
replacement = replacement[1]
end
replacement = tounicode(replacement)
- if replacement and descriptions[replacement] then
+ if replacement and (nocheck or descriptions[replacement]) then
cover(coverage,unicode,replacement)
done = done + 1
else
@@ -620,7 +629,6 @@ local function addfeature(data,feature,specifications)
local featuretype = normalized[specification.type or "substitution"] or "substitution"
local featureflags = specification.flags or noflags
local nocheck = specification.nocheck
- local futuresteps = specification.futuresteps
local featureorder = specification.order or { feature }
local featurechain = (featuretype == "chainsubstitution" or featuretype == "chainposition") and 1 or 0
local nofsteps = 0
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-otj.lua b/Master/texmf-dist/tex/context/base/mkiv/font-otj.lua
index bb30389357c..2e7878d3dfd 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-otj.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-otj.lua
@@ -90,7 +90,7 @@ local getboth = nuts.getboth
local getdisc = nuts.getdisc
local setdisc = nuts.setdisc
local setoffsets = nuts.setoffsets
-local ischar = nuts.is_char
+local ischar = nuts.ischar
local getkern = nuts.getkern
local setkern = nuts.setkern
local setlink = nuts.setlink
@@ -836,8 +836,8 @@ local function inject_positions_only(head,where)
if replace then
-- error, we expect an empty one
else
---KE setfield(next,"replace",fontkern(rightkern)) -- maybe also leftkern
- replace = fontkern(rightkern) -- maybe also leftkern --KE
+ -- KE setfield(next,"replace",fontkern(rightkern)) -- maybe also leftkern
+ replace = fontkern(rightkern) -- maybe also leftkern
done = true --KE
end
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-otl.lua b/Master/texmf-dist/tex/context/base/mkiv/font-otl.lua
index 6e0939e76bd..aff4cc8c8d9 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-otl.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-otl.lua
@@ -52,11 +52,12 @@ local report_otf = logs.reporter("fonts","otf loading")
local fonts = fonts
local otf = fonts.handlers.otf
-otf.version = 3.107 -- beware: also sync font-mis.lua and in mtx-fonts
+otf.version = 3.111 -- beware: also sync font-mis.lua and in mtx-fonts
otf.cache = containers.define("fonts", "otl", otf.version, true)
otf.svgcache = containers.define("fonts", "svg", otf.version, true)
otf.pngcache = containers.define("fonts", "png", otf.version, true)
otf.pdfcache = containers.define("fonts", "pdf", otf.version, true)
+otf.mpscache = containers.define("fonts", "mps", otf.version, true)
otf.svgenabled = false
otf.pngenabled = false
@@ -491,6 +492,7 @@ local function copytotfm(data,cache_id)
parameters.ascender = abs(metadata.ascender or 0)
parameters.descender = abs(metadata.descender or 0)
parameters.units = units
+ parameters.vheight = metadata.defaultvheight
--
properties.space = spacer
properties.encodingbytes = 2
@@ -532,6 +534,9 @@ local converters = {
}
}
+-- We can get differences between daylight saving etc ... but it makes no sense to
+-- mess with trickery .. so be it when you use a different binary.
+
local function checkconversion(specification)
local filename = specification.filename
local converter = converters[lower(file.suffix(filename))]
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-oto.lua b/Master/texmf-dist/tex/context/base/mkiv/font-oto.lua
index 6f6d89d434a..6f5f2fb418f 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-oto.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-oto.lua
@@ -9,16 +9,15 @@ if not modules then modules = { } end modules ['font-oto'] = { -- original tex
local concat, unpack = table.concat, table.unpack
local insert, remove = table.insert, table.remove
local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip
-local type, next, tonumber, tostring, rawget = type, next, tonumber, tostring, rawget
-
-local trace_baseinit = false trackers.register("otf.baseinit", function(v) trace_baseinit = v end)
-local trace_singles = false trackers.register("otf.singles", function(v) trace_singles = v end)
-local trace_multiples = false trackers.register("otf.multiples", function(v) trace_multiples = v end)
-local trace_alternatives = false trackers.register("otf.alternatives", function(v) trace_alternatives = v end)
-local trace_ligatures = false trackers.register("otf.ligatures", function(v) trace_ligatures = v end)
------ trace_ligatures_detail = false trackers.register("otf.ligatures.detail", function(v) trace_ligatures_detail = v end)
-local trace_kerns = false trackers.register("otf.kerns", function(v) trace_kerns = v end)
-local trace_preparing = false trackers.register("otf.preparing", function(v) trace_preparing = v end)
+local type, next, tonumber, tostring = type, next, tonumber, tostring
+
+local trace_baseinit = false trackers.register("otf.baseinit", function(v) trace_baseinit = v end)
+local trace_singles = false trackers.register("otf.singles", function(v) trace_singles = v end)
+local trace_multiples = false trackers.register("otf.multiples", function(v) trace_multiples = v end)
+local trace_alternatives = false trackers.register("otf.alternatives", function(v) trace_alternatives = v end)
+local trace_ligatures = false trackers.register("otf.ligatures", function(v) trace_ligatures = v end)
+local trace_kerns = false trackers.register("otf.kerns", function(v) trace_kerns = v end)
+local trace_preparing = false trackers.register("otf.preparing", function(v) trace_preparing = v end)
local report_prepare = logs.reporter("fonts","otf prepare")
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-otr.lua b/Master/texmf-dist/tex/context/base/mkiv/font-otr.lua
index e851c315704..e726053202f 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-otr.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-otr.lua
@@ -65,7 +65,7 @@ if not modules then modules = { } end modules ['font-otr'] = {
-- require("char-ini")
-- end
-local next, type, tonumber = next, type, tonumber
+local next, type, tonumber, rawget = next, type, tonumber, rawget
local byte, lower, char, gsub = string.byte, string.lower, string.char, string.gsub
local fullstrip = string.fullstrip
local floor, round = math.floor, math.round
@@ -73,56 +73,54 @@ local P, R, S, C, Cs, Cc, Ct, Carg, Cmt = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.C
local lpegmatch = lpeg.match
local rshift = bit32.rshift
-local setmetatableindex = table.setmetatableindex
-local sortedkeys = table.sortedkeys
-local sortedhash = table.sortedhash
-local stripstring = string.nospaces
-local utf16_to_utf8_be = utf.utf16_to_utf8_be
-
-local report = logs.reporter("otf reader")
-
-local trace_cmap = false -- only for checking issues
-local trace_cmap_detail = false -- only for checking issues
-
--- local trace_cmap = true
--- local trace_cmap_detail = true
-
-fonts = fonts or { }
-local handlers = fonts.handlers or { }
-fonts.handlers = handlers
-local otf = handlers.otf or { }
-handlers.otf = otf
-local readers = otf.readers or { }
-otf.readers = readers
-
------ streamreader = utilities.streams -- faster on big files (not true any longer)
-local streamreader = utilities.files -- faster on identify (also uses less memory)
-local streamwriter = utilities.files
-
-readers.streamreader = streamreader
-readers.streamwriter = streamwriter
-
-local openfile = streamreader.open
-local closefile = streamreader.close
------ skipbytes = streamreader.skip
-local setposition = streamreader.setposition
-local skipshort = streamreader.skipshort
-local readbytes = streamreader.readbytes
-local readstring = streamreader.readstring
-local readbyte = streamreader.readcardinal1 -- 8-bit unsigned integer
-local readushort = streamreader.readcardinal2 -- 16-bit unsigned integer
-local readuint = streamreader.readcardinal3 -- 24-bit unsigned integer
-local readulong = streamreader.readcardinal4 -- 32-bit unsigned integer
------ readchar = streamreader.readinteger1 -- 8-bit signed integer
-local readshort = streamreader.readinteger2 -- 16-bit signed integer
-local readlong = streamreader.readinteger4 -- 32-bit unsigned integer
-local readfixed = streamreader.readfixed4
-local read2dot14 = streamreader.read2dot14 -- 16-bit signed fixed number with the low 14 bits of fraction (2.14) (F2DOT14)
-local readfword = readshort -- 16-bit signed integer that describes a quantity in FUnits
-local readufword = readushort -- 16-bit unsigned integer that describes a quantity in FUnits
-local readoffset = readushort
-local readcardinaltable = streamreader.readcardinaltable
-local readintegertable = streamreader.readintegertable
+local setmetatableindex = table.setmetatableindex
+local sortedkeys = table.sortedkeys
+local sortedhash = table.sortedhash
+local stripstring = string.nospaces
+local utf16_to_utf8_be = utf.utf16_to_utf8_be
+
+local report = logs.reporter("otf reader")
+local report_cmap = logs.reporter("otf reader","cmap")
+
+local trace_cmap = false trackers.register("otf.cmap", function(v) trace_cmap = v end)
+local trace_cmap_details = false trackers.register("otf.cmap.details", function(v) trace_cmap_details = v end)
+
+fonts = fonts or { }
+local handlers = fonts.handlers or { }
+fonts.handlers = handlers
+local otf = handlers.otf or { }
+handlers.otf = otf
+local readers = otf.readers or { }
+otf.readers = readers
+
+----- streamreader = utilities.streams -- faster on big files (not true any longer)
+local streamreader = utilities.files -- faster on identify (also uses less memory)
+local streamwriter = utilities.files
+
+readers.streamreader = streamreader
+readers.streamwriter = streamwriter
+
+local openfile = streamreader.open
+local closefile = streamreader.close
+----- skipbytes = streamreader.skip
+local setposition = streamreader.setposition
+local skipshort = streamreader.skipshort
+local readbytes = streamreader.readbytes
+local readstring = streamreader.readstring
+local readbyte = streamreader.readcardinal1 -- 8-bit unsigned integer
+local readushort = streamreader.readcardinal2 -- 16-bit unsigned integer
+local readuint = streamreader.readcardinal3 -- 24-bit unsigned integer
+local readulong = streamreader.readcardinal4 -- 32-bit unsigned integer
+----- readchar = streamreader.readinteger1 -- 8-bit signed integer
+local readshort = streamreader.readinteger2 -- 16-bit signed integer
+local readlong = streamreader.readinteger4 -- 32-bit unsigned integer
+local readfixed = streamreader.readfixed4
+local read2dot14 = streamreader.read2dot14 -- 16-bit signed fixed number with the low 14 bits of fraction (2.14) (F2DOT14)
+local readfword = readshort -- 16-bit signed integer that describes a quantity in FUnits
+local readufword = readushort -- 16-bit unsigned integer that describes a quantity in FUnits
+local readoffset = readushort
+local readcardinaltable = streamreader.readcardinaltable
+local readintegertable = streamreader.readintegertable
function streamreader.readtag(f)
return lower(stripstring(readstring(f,4)))
@@ -1213,18 +1211,18 @@ readers.vmtx = function(f,fontdata,specification)
local glyphs = fontdata.glyphs
local nofglyphs = fontdata.nofglyphs
local vheight = 0
- local vdefault = verticalheader.ascender + verticalheader.descender
+ local vdefault = verticalheader.ascender - verticalheader.descender
local topsidebearing = 0
for i=0,nofmetrics-1 do
local glyph = glyphs[i]
- vheight = readshort(f)
+ vheight = readushort(f)
topsidebearing = readshort(f)
if vheight ~= 0 and vheight ~= vdefault then
glyph.vheight = vheight
end
- -- if topsidebearing ~= 0 then
- -- glyph.tsb = topsidebearing
- -- end
+ if topsidebearing ~= 0 then
+ glyph.tsb = topsidebearing
+ end
end
-- The next can happen in for instance a monospace font or in a cjk font
-- with fixed heights.
@@ -1233,9 +1231,6 @@ readers.vmtx = function(f,fontdata,specification)
if vheight ~= 0 and vheight ~= vdefault then
glyph.vheight = vheight
end
- -- if topsidebearing ~= 0 then
- -- glyph.tsb = topsidebearing
- -- end
end
end
end
@@ -1320,32 +1315,23 @@ local formatreaders = { }
local duplicatestoo = true
local sequence = {
+ -- these is some provision against redundant loading
{ 3, 1, 4 },
{ 3, 10, 12 },
{ 0, 3, 4 },
+ { 0, 3, 12 },
{ 0, 1, 4 },
- -- { 0, 4, 12 },
+ { 0, 1, 12 }, -- for some old mac fonts
{ 0, 0, 6 },
{ 3, 0, 6 },
+ { 3, 0, 4 }, -- for (likely) old crap
-- variants
{ 0, 5, 14 },
-- last resort ranges
-{ 0, 4, 12 },
+ { 0, 4, 12 },
{ 3, 10, 13 },
}
--- local sequence = {
--- { 0, 1, 4 },
--- { 0, 4, 12 },
--- { 0, 3, 4 },
--- { 3, 1, 4 },
--- { 3, 10, 12 },
--- { 0, 0, 6 },
--- { 3, 0, 6 },
--- -- variants
--- { 0, 5, 14 },
--- }
-
local supported = { }
for i=1,#sequence do
@@ -1398,7 +1384,7 @@ formatreaders[4] = function(f,fontdata,offset)
elseif offset == 0xFFFF then
-- bad encoding
elseif offset == 0 then
- if trace_cmap_detail then
+ if trace_cmap_details then
report("format 4.%i segment %2i from %C upto %C at index %H",1,segment,startchar,endchar,(startchar + delta) % 65536)
end
for unicode=startchar,endchar do
@@ -1431,8 +1417,8 @@ formatreaders[4] = function(f,fontdata,offset)
end
else
local shift = (segment-nofsegments+offset/2) - startchar
- if trace_cmap_detail then
- report("format 4.%i segment %2i from %C upto %C at index %H",0,segment,startchar,endchar,(startchar + delta) % 65536)
+ if trace_cmap_details then
+ report_cmap("format 4.%i segment %2i from %C upto %C at index %H",0,segment,startchar,endchar,(startchar + delta) % 65536)
end
for unicode=startchar,endchar do
local slot = shift + unicode
@@ -1481,8 +1467,8 @@ formatreaders[6] = function(f,fontdata,offset)
local count = readushort(f)
local stop = start+count-1
local nofdone = 0
- if trace_cmap_detail then
- report("format 6 from %C to %C",2,start,stop)
+ if trace_cmap_details then
+ report_cmap("format 6 from %C to %C",2,start,stop)
end
for unicode=start,stop do
local index = readushort(f)
@@ -1518,8 +1504,8 @@ formatreaders[12] = function(f,fontdata,offset)
local first = readulong(f)
local last = readulong(f)
local index = readulong(f)
- if trace_cmap_detail then
- report("format 12 from %C to %C starts at index %i",first,last,index)
+ if trace_cmap_details then
+ report_cmap("format 12 from %C to %C starts at index %i",first,last,index)
end
for unicode=first,last do
local glyph = glyphs[index]
@@ -1562,8 +1548,8 @@ formatreaders[13] = function(f,fontdata,offset)
local last = readulong(f)
local index = readulong(f)
if first < privateoffset then
- if trace_cmap_detail then
- report("format 13 from %C to %C get index %i",first,last,index)
+ if trace_cmap_details then
+ report_cmap("format 13 from %C to %C get index %i",first,last,index)
end
local glyph = glyphs[index]
local unicode = glyph.unicode
@@ -1649,27 +1635,46 @@ formatreaders[14] = function(f,fontdata,offset)
end
local function checkcmap(f,fontdata,records,platform,encoding,format)
- local data = records[platform]
- if not data then
+ local pdata = records[platform]
+ if not pdata then
+ if trace_cmap_details then
+ report_cmap("skipped, %s, p=%i e=%i f=%i","no platform",platform,encoding,format)
+ end
return 0
end
- data = data[encoding]
- if not data then
+ local edata = pdata[encoding]
+ if not edata then
+ if trace_cmap_details then
+ report_cmap("skipped, %s, p=%i e=%i f=%i","no encoding",platform,encoding,format)
+ end
return 0
end
- data = data[format]
- if not data then
+ local fdata = edata[format]
+ if not fdata then
+ if trace_cmap_details then
+ report_cmap("skipped, %s, p=%i e=%i f=%i","no format",platform,encoding,format)
+ end
+ return 0
+ elseif type(fdata) ~= "number" then
+ if trace_cmap_details then
+ report_cmap("skipped, %s, p=%i e=%i f=%i","already done",platform,encoding,format)
+ end
return 0
end
+ edata[format] = true -- done
local reader = formatreaders[format]
if not reader then
+ if trace_cmap_details then
+ report_cmap("skipped, %s, p=%i e=%i f=%i","unsupported format",platform,encoding,format)
+ end
return 0
end
- local p = platforms[platform]
- local e = encodings[p]
- local n = reader(f,fontdata,data) or 0
- if trace_cmap then
- report("cmap checked: platform %i (%s), encoding %i (%s), format %i, new unicodes %i",platform,p,encoding,e and e[encoding] or "?",format,n)
+ local n = reader(f,fontdata,fdata) or 0
+ if trace_cmap_details or trace_cmap then
+ local p = platforms[platform]
+ local e = encodings[p]
+ report_cmap("checked, platform %i (%s), encoding %i (%s), format %i, new unicodes %i",
+ platform,p,encoding,e and e[encoding] or "?",format,n)
end
return n
end
@@ -1904,6 +1909,7 @@ local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo,inst
local postscript = fontdata.postscript or { }
local fontheader = fontdata.fontheader or { }
local cffinfo = fontdata.cffinfo or { }
+ local verticalheader = fontdata.verticalheader or { }
local filename = fontdata.filename
local weight = getname(fontdata,"weight") or (cffinfo and cffinfo.weight) or (metrics and metrics.weight)
local width = getname(fontdata,"width") or (cffinfo and cffinfo.width ) or (metrics and metrics.width )
@@ -1973,6 +1979,7 @@ local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo,inst
platformnames = platformnames or nil,
instancenames = instancenames or nil,
tableoffsets = fontdata.tableoffsets,
+ defaultvheight = (verticalheader.ascender or 0) - (verticalheader.descender or 0)
}
if metricstoo then
local keys = {
@@ -2073,9 +2080,7 @@ end
local function readtable(tag,f,fontdata,specification,...)
local reader = readers[tag]
if reader then
- -- local t = os.clock()
reader(f,fontdata,specification,...)
- -- report("reading table %a took %0.4f seconds",tag,os.clock()-t)
end
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-ots.lua b/Master/texmf-dist/tex/context/base/mkiv/font-ots.lua
index b9f719a5fd8..c4f89c156be 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-ots.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-ots.lua
@@ -177,7 +177,6 @@ registertracker("otf.sample.silent", "otf.steps=silent","otf.substitutions","otf
local nuts = nodes.nuts
-local getfield = nuts.getfield
local getnext = nuts.getnext
local setnext = nuts.setnext
local getprev = nuts.getprev
@@ -185,8 +184,6 @@ local setprev = nuts.setprev
local getboth = nuts.getboth
local setboth = nuts.setboth
local getid = nuts.getid
-local getattr = nuts.getattr
-local setattr = nuts.setattr
local getprop = nuts.getprop
local setprop = nuts.setprop
local getsubtype = nuts.getsubtype
@@ -195,12 +192,16 @@ local getchar = nuts.getchar
local setchar = nuts.setchar
local getdisc = nuts.getdisc
local setdisc = nuts.setdisc
+local getreplace = nuts.getreplace
local setlink = nuts.setlink
local getcomponents = nuts.getcomponents -- the original one, not yet node-aux
local setcomponents = nuts.setcomponents -- the original one, not yet node-aux
local getwidth = nuts.getwidth
+local getattr = nuts.getattr
+
+local getglyphdata = nuts.getglyphdata
-local ischar = nuts.is_char
+local ischar = nuts.ischar
local isglyph = nuts.isglyph
local usesfont = nuts.uses_font
@@ -212,6 +213,7 @@ local find_node_tail = nuts.tail
local flush_node_list = nuts.flush_list
local flush_node = nuts.flush_node
local end_of_math = nuts.end_of_math
+local start_of_par = nuts.start_of_par
local setmetatable = setmetatable
local setmetatableindex = table.setmetatableindex
@@ -2089,7 +2091,7 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck)
if keepdisc then
keepdisc = false
lookaheaddisc = current
- local replace = getfield(current,"replace")
+ local replace = getreplace(current)
if not replace then
sweepoverflow = true
sweepnode = current
@@ -2166,7 +2168,7 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck)
lookaheaddisc = current
end
-- we assume a simple text only replace (we could use nuts.count)
- local replace = getfield(current,"replace")
+ local replace = getreplace(current)
while replace and i < s do
if getid(replace) == glyph_code then
i = i + 1
@@ -2212,7 +2214,7 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck)
backtrackdisc = current
end
-- we assume a simple text only replace (we could use nuts.count)
- local replace = getfield(current,"replace")
+ local replace = getreplace(current)
while replace and i > 1 do
if getid(replace) == glyph_code then
i = i - 1
@@ -3177,7 +3179,7 @@ local function testrun(disc,t_run,c_run,...)
end
local pre, post, replace, pretail, posttail, replacetail = getdisc(disc,true)
local renewed = false
- if (post or replace) and prev then
+ if (post or replace) then -- and prev then -- hm, we can start with a disc
if post then
setlink(posttail,next)
else
@@ -3291,7 +3293,7 @@ end
-- discretionaries (maybe we need to tag those some day). So, at least for now, we don't
-- have the following test in the sub runs:
--
--- -- local a = getattr(start,0)
+-- -- local a = getglyhpdata(start)
-- -- if a then
-- -- a = (a == attr) and (not attribute or getprop(start,a_state) == attribute)
-- -- else
@@ -3301,7 +3303,7 @@ end
--
-- but use this instead:
--
--- -- local a = getattr(start,0)
+-- -- local a = getglyphdata(start)
-- -- if not a or (a == attr) then
--
-- and even that one is probably not needed. However, we can handle interesting
@@ -3327,7 +3329,7 @@ local function c_run_single(head,font,attr,lookupcache,step,dataset,sequence,rlm
if char then
local a -- happens often so no assignment is faster
if attr then
- a = getattr(start,0)
+ a = getglyphdata(start)
end
if not a or (a == attr) then
local lookupmatch = lookupcache[char]
@@ -3367,7 +3369,7 @@ local function t_run_single(start,stop,font,attr,lookupcache)
if char then
local a -- happens often so no assignment is faster
if attr then
- a = getattr(start,0)
+ a = getglyphdata(start)
end
local startnext = getnext(start)
if not a or (a == attr) then
@@ -3385,7 +3387,7 @@ local function t_run_single(start,stop,font,attr,lookupcache)
-- how about post ... we can probably merge this into the while
while getid(s) == disc_code do
ss = getnext(s)
- s = getfield(s,"replace")
+ s = getreplace(s)
if not s then
s = ss
ss = nil
@@ -3412,12 +3414,13 @@ local function t_run_single(start,stop,font,attr,lookupcache)
end
while getid(s) == disc_code do
ss = getnext(s)
- s = getfield(s,"replace")
+ s = getreplace(s)
if not s then
s = ss
ss = nil
end
end
+lookupmatch = lg
else
break
end
@@ -3451,7 +3454,7 @@ end
local function k_run_single(sub,injection,last,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler)
local a -- happens often so no assignment is faster
if attr then
- a = getattr(sub,0)
+ a = getglyphdata(sub)
end
if not a or (a == attr) then
for n in nextnode, sub do -- only gpos
@@ -3487,7 +3490,7 @@ local function c_run_multiple(head,font,attr,steps,nofsteps,dataset,sequence,rlm
if char then
local a -- happens often so no assignment is faster
if attr then
- a = getattr(start,0)
+ a = getglyphdata(start)
end
if not a or (a == attr) then
for i=1,nofsteps do
@@ -3535,7 +3538,7 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps)
if char then
local a -- happens often so no assignment is faster
if attr then
- a = getattr(start,0)
+ a = getglyphdata(start)
end
local startnext = getnext(start)
if not a or (a == attr) then
@@ -3554,7 +3557,7 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps)
end
while getid(s) == disc_code do
ss = getnext(s)
- s = getfield(s,"replace")
+ s = getreplace(s)
if not s then
s = ss
ss = nil
@@ -3581,12 +3584,13 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps)
end
while getid(s) == disc_code do
ss = getnext(s)
- s = getfield(s,"replace")
+ s = getreplace(s)
if not s then
s = ss
ss = nil
end
end
+lookupmatch = lg
else
break
end
@@ -3616,7 +3620,7 @@ end
local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler)
local a -- happens often so no assignment is faster
if attr then
- a = getattr(sub,0)
+ a = getglyphdata(sub)
end
if not a or (a == attr) then
for n in nextnode, sub do -- only gpos
@@ -3709,7 +3713,7 @@ do
-- reference:
--
- -- local a = attr and getattr(start,0)
+ -- local a = attr and getglyphdata(start)
-- if a then
-- a = (a == attr) and (not attribute or getprop(start,a_state) == attribute)
-- else
@@ -3720,7 +3724,7 @@ do
--
-- local a -- happens often so no assignment is faster
-- if attr then
- -- if getattr(start,0) == attr and (not attribute or getprop(start,a_state) == attribute) then
+ -- if getglyphdata(start) == attr and (not attribute or getprop(start,a_state) == attribute) then
-- a = true
-- end
-- elseif not attribute or getprop(start,a_state) == attribute then
@@ -3801,7 +3805,7 @@ do
local initialrl = 0
- if getid(head) == localpar_code and getsubtype(head) == 0 then
+ if getid(head) == localpar_code and start_of_par(head) then
initialrl = pardirstate(head)
elseif direction == 1 or direction == "TRT" then
initialrl = -1
@@ -3860,7 +3864,7 @@ do
if m then
local a -- happens often so no assignment is faster
if attr then
- a = getattr(start,0)
+ a = getglyphdata(start)
end
if not a or (a == attr) then
for i=m[1],m[2] do
@@ -3907,7 +3911,7 @@ do
if lookupmatch then
local a -- happens often so no assignment is faster
if attr then
- if getattr(start,0) == attr and (not attribute or getprop(start,a_state) == attribute) then
+ if getglyphdata(start) == attr and (not attribute or getprop(start,a_state) == attribute) then
a = true
end
elseif not attribute or getprop(start,a_state) == attribute then
@@ -3955,7 +3959,7 @@ do
elseif id == dir_code then
topstack, rlmode = txtdirstate(start,dirstack,topstack,rlparmode)
start = getnext(start)
- -- elseif id == localpar_code then
+ -- elseif id == localpar_code and start_of_par(start) then
-- rlparmode, rlmode = pardirstate(start)
-- start = getnext(start)
else
@@ -3974,7 +3978,7 @@ do
if m then
local a -- happens often so no assignment is faster
if attr then
- if getattr(start,0) == attr and (not attribute or getprop(start,a_state) == attribute) then
+ if getglyphdata(start) == attr and (not attribute or getprop(start,a_state) == attribute) then
a = true
end
elseif not attribute or getprop(start,a_state) == attribute then
@@ -4039,7 +4043,7 @@ do
elseif id == dir_code then
topstack, rlmode = txtdirstate(start,dirstack,topstack,rlparmode)
start = getnext(start)
- -- elseif id == localpar_code then
+ -- elseif id == localpar_code and start_of_par(start) then
-- rlparmode, rlmode = pardirstate(start)
-- start = getnext(start)
else
@@ -4150,7 +4154,7 @@ do
elseif id == dir_code then
topstack, rlmode = txtdirstate(start,dirstack,topstack,rlparmode)
start = getnext(start)
- -- elseif id == localpar_code then
+ -- elseif id == localpar_code and start_of_par(start) then
-- rlparmode, rlmode = pardirstate(start)
-- start = getnext(start)
else
@@ -4231,9 +4235,26 @@ registerotffeature {
}
}
+-- Moved here (up) a bit. This doesn't really belong in generic so it will
+-- move to a context module some day.
+
+local function markinitializer(tfmdata,value)
+ local properties = tfmdata.properties
+ properties.checkmarks = value
+end
+
+registerotffeature {
+ name = "checkmarks",
+ description = "check mark widths",
+ default = true,
+ initializers = {
+ node = markinitializer,
+ },
+}
+
-- This can be used for extra handlers, but should be used with care! We implement one
-- here but some more can be found in the osd (script devanagary) file. Now watch out:
--- when a handlers has steps, it is called as the other ones, but when we have no steps,
+-- when a handler has steps, it is called as the other ones, but when we have no steps,
-- we use a different call:
--
-- function(head,dataset,sequence,initialrl,font,attr)
@@ -4244,22 +4265,28 @@ registerotffeature {
otf.handlers = handlers
+if context then
+ return
+else
+ -- todo: move the following code someplace else
+end
+
local setspacekerns = nodes.injections.setspacekerns if not setspacekerns then os.exit() end
-local tag = "kern" -- maybe some day a merge
+local tag = "kern"
-if fontfeatures then
+-- if fontfeatures then
- function handlers.trigger_space_kerns(head,dataset,sequence,initialrl,font,attr)
- local features = fontfeatures[font]
- local enabled = features and features.spacekern and features[tag]
- if enabled then
- setspacekerns(font,sequence)
- end
- return head, enabled
- end
+-- function handlers.trigger_space_kerns(head,dataset,sequence,initialrl,font,attr)
+-- local features = fontfeatures[font]
+-- local enabled = features and features.spacekern and features[tag]
+-- if enabled then
+-- setspacekerns(font,sequence)
+-- end
+-- return head, enabled
+-- end
-else -- generic (no hashes)
+-- else -- generic (no hashes)
function handlers.trigger_space_kerns(head,dataset,sequence,initialrl,font,attr)
local shared = fontdata[font].shared
@@ -4271,7 +4298,7 @@ else -- generic (no hashes)
return head, enabled
end
-end
+-- end
-- There are fonts out there that change the space but we don't do that kind of
-- things in TeX.
@@ -4389,7 +4416,7 @@ local function spaceinitializer(tfmdata,value) -- attr
if rules then
-- not now: analyze (simple) rules
elseif not coverage then
- -- nothng to do
+ -- nothing to do
elseif kind == "gpos_single" then
-- makes no sense in TeX
elseif kind == "gpos_pair" then
@@ -4473,17 +4500,3 @@ registerotffeature {
node = spaceinitializer,
},
}
-
-local function markinitializer(tfmdata,value)
- local properties = tfmdata.properties
- properties.checkmarks = value
-end
-
-registerotffeature {
- name = "checkmarks",
- description = "check mark widths",
- default = true,
- initializers = {
- node = markinitializer,
- },
-}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-ott.lua b/Master/texmf-dist/tex/context/base/mkiv/font-ott.lua
index 10420f6eeb1..c9e467f2253 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-ott.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-ott.lua
@@ -27,14 +27,19 @@ local statistics = otf.statistics or { }
otf.statistics = statistics
local scripts = allocate {
+ ["adlm"] = "adlam",
+ ["aghb"] = "caucasian albanian",
+ ["ahom"] = "ahom",
["arab"] = "arabic",
["armi"] = "imperial aramaic",
["armn"] = "armenian",
["avst"] = "avestan",
["bali"] = "balinese",
["bamu"] = "bamum",
+ ["bass"] = "bassa vah",
["batk"] = "batak",
["beng"] = "bengali",
+ ["bhks"] = "bhaiksuki",
["bng2"] = "bengali variant 2",
["bopo"] = "bopomofo",
["brah"] = "brahmi",
@@ -50,23 +55,33 @@ local scripts = allocate {
["copt"] = "coptic",
["cprt"] = "cypriot syllabary",
["cyrl"] = "cyrillic",
- ["deva"] = "devanagari",
["dev2"] = "devanagari variant 2",
+ ["deva"] = "devanagari",
+ ["dogr"] = "dogra",
["dsrt"] = "deseret",
+ ["dupl"] = "duployan",
["egyp"] = "egyptian heiroglyphs",
+ ["elba"] = "elbasan",
["ethi"] = "ethiopic",
["geor"] = "georgian",
+ ["gjr2"] = "gujarati variant 2",
["glag"] = "glagolitic",
+ ["gong"] = "gunjala gondi",
+ ["gonm"] = "masaram gondi",
["goth"] = "gothic",
+ ["gran"] = "grantha",
["grek"] = "greek",
["gujr"] = "gujarati",
- ["gjr2"] = "gujarati variant 2",
- ["guru"] = "gurmukhi",
["gur2"] = "gurmukhi variant 2",
+ ["guru"] = "gurmukhi",
["hang"] = "hangul",
["hani"] = "cjk ideographic",
["hano"] = "hanunoo",
+ ["hatr"] = "hatran",
["hebr"] = "hebrew",
+ ["hluw"] = "anatolian hieroglyphs",
+ ["hmng"] = "pahawh hmong",
+ ["hung"] = "old hungarian",
["ital"] = "old italic",
["jamo"] = "hangul jamo",
["java"] = "javanese",
@@ -74,49 +89,77 @@ local scripts = allocate {
["kana"] = "hiragana and katakana",
["khar"] = "kharosthi",
["khmr"] = "khmer",
- ["knda"] = "kannada",
+ ["khoj"] = "khojki",
["knd2"] = "kannada variant 2",
+ ["knda"] = "kannada",
["kthi"] = "kaithi",
["lana"] = "tai tham",
["lao" ] = "lao",
["latn"] = "latin",
["lepc"] = "lepcha",
["limb"] = "limbu",
+ ["lina"] = "linear a",
["linb"] = "linear b",
["lisu"] = "lisu",
["lyci"] = "lycian",
["lydi"] = "lydian",
+ ["mahj"] = "mahajani",
+ ["maka"] = "makasar",
["mand"] = "mandaic and mandaean",
+ ["mani"] = "manichaean",
+ ["marc"] = "marchen",
["math"] = "mathematical alphanumeric symbols",
+ ["medf"] = "medefaidrin",
+ ["mend"] = "mende kikakui",
["merc"] = "meroitic cursive",
["mero"] = "meroitic hieroglyphs",
- ["mlym"] = "malayalam",
["mlm2"] = "malayalam variant 2",
+ ["mlym"] = "malayalam",
+ ["modi"] = "modi",
["mong"] = "mongolian",
+ ["mroo"] = "mro",
["mtei"] = "meitei Mayek",
+ ["mult"] = "multani",
["musc"] = "musical symbols",
["mym2"] = "myanmar variant 2",
["mymr"] = "myanmar",
+ ["narb"] = "old north arabian",
+ ["nbat"] = "nabataean",
+ ["newa"] = "newa",
["nko" ] = 'n"ko',
+ ["nshu"] = "nüshu",
["ogam"] = "ogham",
["olck"] = "ol chiki",
["orkh"] = "old turkic and orkhon runic",
- ["orya"] = "oriya",
["ory2"] = "odia variant 2",
+ ["orya"] = "oriya",
+ ["osge"] = "osage",
["osma"] = "osmanya",
+ ["palm"] = "palmyrene",
+ ["pauc"] = "pau cin hau",
+ ["perm"] = "old permic",
["phag"] = "phags-pa",
["phli"] = "inscriptional pahlavi",
+ ["phlp"] = "psalter pahlavi",
["phnx"] = "phoenician",
+ ["plrd"] = "miao",
["prti"] = "inscriptional parthian",
["rjng"] = "rejang",
+ ["rohg"] = "hanifi rohingya",
["runr"] = "runic",
["samr"] = "samaritan",
["sarb"] = "old south arabian",
["saur"] = "saurashtra",
+ ["sgnw"] = "sign writing",
["shaw"] = "shavian",
["shrd"] = "sharada",
+ ["sidd"] = "siddham",
+ ["sind"] = "khudawadi",
["sinh"] = "sinhala",
+ ["sogd"] = "sogdian",
+ ["sogo"] = "old sogdian",
["sora"] = "sora sompeng",
+ ["soyo"] = "soyombo",
["sund"] = "sundanese",
["sylo"] = "syloti nagri",
["syrc"] = "syriac",
@@ -125,20 +168,24 @@ local scripts = allocate {
["tale"] = "tai le",
["talu"] = "tai lu",
["taml"] = "tamil",
+ ["tang"] = "tangut",
["tavt"] = "tai viet",
- ["telu"] = "telugu",
["tel2"] = "telugu variant 2",
+ ["telu"] = "telugu",
["tfng"] = "tifinagh",
["tglg"] = "tagalog",
["thaa"] = "thaana",
["thai"] = "thai",
["tibt"] = "tibetan",
+ ["tirh"] = "tirhuta",
["tml2"] = "tamil variant 2",
["ugar"] = "ugaritic cuneiform",
["vai" ] = "vai",
+ ["wara"] = "warang citi",
["xpeo"] = "old persian cuneiform",
["xsux"] = "sumero-akkadian cuneiform",
["yi" ] = "yi",
+ ["zanb"] = "zanabazar square",
}
local languages = allocate {
@@ -208,12 +255,15 @@ local languages = allocate {
["brm" ] = "burmese",
["brx" ] = "bodo",
["bsh" ] = "bashkir",
+ ["bsk" ] = "burushaski",
["bti" ] = "beti",
["bts" ] = "batak simalungun",
["bug" ] = "bugis",
+ ["byv" ] = "medumba",
["cak" ] = "kaqchikel",
["cat" ] = "catalan",
["cbk" ] = "zamboanga chavacano",
+ ["cchn"] = "chinantec",
["ceb" ] = "cebuano",
["cgg" ] = "chiga",
["cha" ] = "chamorro",
@@ -228,6 +278,8 @@ local languages = allocate {
["chr" ] = "cherokee",
["chu" ] = "chuvash",
["chy" ] = "cheyenne",
+ ["cja" ] = "western cham",
+ ["cjm" ] = "eastern cham",
["cmr" ] = "comorian",
["cop" ] = "coptic",
["cor" ] = "cornish",
@@ -283,6 +335,7 @@ local languages = allocate {
["fin" ] = "finnish",
["fji" ] = "fijian",
["fle" ] = "dutch (flemish)",
+ ["fmp" ] = "fe’fe’",
["fne" ] = "forest nenets",
["fon" ] = "fon",
["fos" ] = "faroese",
@@ -361,6 +414,7 @@ local languages = allocate {
["jan" ] = "japanese",
["jav" ] = "javanese",
["jbo" ] = "lojban",
+ ["jct" ] = "krymchak",
["jii" ] = "yiddish",
["jud" ] = "ladino",
["jul" ] = "jula",
@@ -397,6 +451,7 @@ local languages = allocate {
["kmn" ] = "kumaoni",
["kmo" ] = "komo",
["kms" ] = "komso",
+ ["kmz" ] = "khorasani turkic",
["knr" ] = "kanuri",
["kod" ] = "kodagu",
["koh" ] = "korean old hangul",
@@ -473,6 +528,7 @@ local languages = allocate {
["mar" ] = "marathi",
["maw" ] = "marwari",
["mbn" ] = "mbundu",
+ ["mbo" ] = "mbo",
["mch" ] = "manchu",
["mcr" ] = "moose cree",
["mde" ] = "mende",
@@ -489,6 +545,7 @@ local languages = allocate {
["mle" ] = "male",
["mlg" ] = "malagasy",
["mln" ] = "malinke",
+ ["mlr" ] = "malayalam reformed",
["mly" ] = "malay",
["mnd" ] = "mandinka",
["mng" ] = "mongolian",
@@ -542,6 +599,7 @@ local languages = allocate {
["nto" ] = "esperanto",
["nym" ] = "nyamwezi",
["nyn" ] = "norwegian nynorsk",
+ ["nza" ] = "mbembe tigon",
["oci" ] = "occitan",
["ocr" ] = "oji-cree",
["ojb" ] = "ojibway",
@@ -605,6 +663,7 @@ local languages = allocate {
["say" ] = "sayisi",
["scn" ] = "sicilian",
["sco" ] = "scots",
+ ["scs" ] = "north slavey",
["sek" ] = "sekota",
["sel" ] = "selkup",
["sga" ] = "old irish",
@@ -649,6 +708,9 @@ local languages = allocate {
["sxu" ] = "upper saxon",
["syl" ] = "sylheti",
["syr" ] = "syriac",
+ ["syre"] = "estrangela syriac",
+ ["syrj"] = "western syriac",
+ ["syrn"] = "eastern syriac",
["szl" ] = "silesian",
["tab" ] = "tabasaran",
["taj" ] = "tajiki",
@@ -680,6 +742,7 @@ local languages = allocate {
["tsj" ] = "tshangla",
["tua" ] = "turoyo aramaic",
["tul" ] = "tulu",
+ ["tum" ] = "tulu",
["tuv" ] = "tuvin",
["tvl" ] = "tuvalu",
["twi" ] = "twi",
@@ -705,6 +768,7 @@ local languages = allocate {
["wel" ] = "welsh",
["wlf" ] = "wolof",
["wln" ] = "walloon",
+ ["wtm" ] = "mewati",
["xbd" ] = "lü",
["xhs" ] = "xhosa",
["xjb" ] = "minjangbal",
@@ -730,6 +794,7 @@ local languages = allocate {
["zza" ] = "zazaki",
}
+
local features = allocate {
["aalt"] = "access all alternates",
["abvf"] = "above-base forms",
@@ -869,6 +934,7 @@ local features = allocate {
["vkna"] = "vertical kana alternates",
["vkrn"] = "vertical kerning",
["vpal"] = "proportional alternate vertical metrics",
+ ["vrtr"] = "vertical alternates for rotation",
["vrt2"] = "vertical rotation",
["zero"] = "slashed zero",
@@ -879,8 +945,9 @@ local features = allocate {
["cv.."] = "character variant ..",
["js.."] = "justification ..",
- ["dv.."] = "devanagari ..",
- ["ml.."] = "malayalam ..",
+ ["dv.."] = "devanagari ..", -- for internal use
+ ["ml.."] = "malayalam ..", -- for internal use
+
}
local baselines = allocate {
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-oup.lua b/Master/texmf-dist/tex/context/base/mkiv/font-oup.lua
index d1faadbf712..0e7e25808ca 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-oup.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-oup.lua
@@ -720,6 +720,10 @@ local function checklookups(fontdata,missing,nofmissing)
end
end
+local firstprivate = fonts.privateoffsets and fonts.privateoffsets.textbase or 0xF0000
+local puafirst = 0xE000
+local pualast = 0xF8FF
+
local function unifymissing(fontdata)
if not fonts.mappings then
require("font-map")
@@ -730,20 +734,22 @@ local function unifymissing(fontdata)
resources.unicodes = unicodes
for unicode, d in next, fontdata.descriptions do
if unicode < privateoffset then
- local name = d.name
- if name then
- unicodes[name] = unicode
+ if unicode >= puafirst and unicode <= pualast then
+ -- report_unicodes("resolving private unicode %U",unicode)
+ else
+ local name = d.name
+ if name then
+ unicodes[name] = unicode
+ end
end
+ else
+ -- report_unicodes("resolving private unicode %U",unicode)
end
end
fonts.mappings.addtounicode(fontdata,fontdata.filename,checklookups)
resources.unicodes = nil
end
-local firstprivate = fonts.privateoffsets and fonts.privateoffsets.textbase or 0xF0000
-local puafirst = 0xE000
-local pualast = 0xF8FF
-
local function unifyglyphs(fontdata,usenames)
local private = fontdata.private or privateoffset
local glyphs = fontdata.glyphs
@@ -1573,16 +1579,34 @@ function readers.pack(data)
if kind == "gpos_pair" then
local c = step.coverage
if c then
- if step.format == "pair" then
+ if step.format ~= "pair" then
+ for g1, d1 in next, c do
+ c[g1] = pack_normal(d1)
+ end
+ elseif step.shared then
+ -- This branch results from classes. We already share at the reader end. Maybe
+ -- the sharing should be moved there altogether but it becomes kind of messy
+ -- then. Here we're still wasting time because in the second pass we serialize
+ -- and hash. So we compromise. We could merge the two passes ...
+ local shared = { }
for g1, d1 in next, c do
for g2, d2 in next, d1 do
- local f = d2[1] if f and f ~= true then d2[1] = pack_indexed(f) end
- local s = d2[2] if s and s ~= true then d2[2] = pack_indexed(s) end
+ if not shared[d2] then
+ local f = d2[1] if f and f ~= true then d2[1] = pack_indexed(f) end
+ local s = d2[2] if s and s ~= true then d2[2] = pack_indexed(s) end
+ shared[d2] = true
+ end
end
end
+ if pass == 2 then
+ step.shared = nil -- weird, so dups
+ end
else
for g1, d1 in next, c do
- c[g1] = pack_normal(d1)
+ for g2, d2 in next, d1 do
+ local f = d2[1] if f and f ~= true then d2[1] = pack_indexed(f) end
+ local s = d2[2] if s and s ~= true then d2[2] = pack_indexed(s) end
+ end
end
end
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-pre.mkiv b/Master/texmf-dist/tex/context/base/mkiv/font-pre.mkiv
index c1c24b8544f..721c4c6ebcb 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-pre.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-pre.mkiv
@@ -497,14 +497,18 @@
[boldened]
[boldened-30]
-%D Emoji:
+%D Emoji etc:
\definefontfeature[bandw:overlay][ccmp=yes,dist=yes]
\definefontfeature[color:overlay][ccmp=yes,dist=yes,colr=yes]
%definefontfeature[bandw:svg] [ccmp=yes,dist=yes]
\definefontfeature[color:svg] [ccmp=yes,dist=yes,svg=yes]
%definefontfeature[bandw:bitmap] [ccmp=yes,dist=yes,sbix=yes]
-\definefontfeature[color:bitmap] [ccmp=yes,dist=yes,sbix=yes]
+\definefontfeature[color:bitmap] [ccmp=yes,dist=yes,sbix=yes] % also cblc
+
+% Plus an automatic one:
+
+\definefontfeature[color] [ccmp=yes,dist=yes,color=auto]
%D We define some colors that are used in tracing (for instance \OPENTYPE\
%D features). We cannot yet inherit because no colors are predefined.
@@ -755,6 +759,8 @@
\definealternativestyle [italicface] [\italicface] []
\definealternativestyle [swapface] [\swapface] []
+\definealternativestyle [emphasize] [\em] [\em] % new
+
% For Alan:
\definealternativestyle
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-prv.lua b/Master/texmf-dist/tex/context/base/mkiv/font-prv.lua
index 20c06d2e54e..c3323ca743e 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-prv.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-prv.lua
@@ -6,7 +6,7 @@ if not modules then modules = { } end modules ['font-prv'] = {
license = "see context related readme files"
}
-local type = type
+local type, rawget = type, rawget
local formatters = string.formatters
local fonts = fonts
@@ -76,3 +76,7 @@ end
function helpers.privateslot(name)
return rawget(sharedprivates,name)
end
+
+function helpers.newprivateslot(name)
+ return sharedprivates[name]
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-run.mkiv b/Master/texmf-dist/tex/context/base/mkiv/font-run.mkiv
index 610f2e62c95..2f6cd32df9f 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-run.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-run.mkiv
@@ -158,7 +158,7 @@
{\vss
\hpack to \scratchdimenone
{\dummy
- \ifdim\interwordspace=\zeropoint
+ \ifzeropt\interwordspace
\setbox##1\hpack
{\raise.5\dp##1\hpack
{\lower.5\ht##1\copy##1}}%
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-shp.lua b/Master/texmf-dist/tex/context/base/mkiv/font-shp.lua
index d5c194c858e..3d2e5b7c902 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-shp.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-shp.lua
@@ -17,12 +17,16 @@ local pfb = fonts.handlers.pfb
local hashes = fonts.hashes
local identifiers = hashes.identifiers
-local version = 0.007
+local version = 0.009
local shapescache = containers.define("fonts", "shapes", version, true)
local streamscache = containers.define("fonts", "streams", version, true)
-- shapes (can be come a separate file at some point)
+local compact_streams = false
+
+directives.register("fonts.streams.compact", function(v) compact_streams = v end)
+
local function packoutlines(data,makesequence)
local subfonts = data.subfonts
if subfonts then
@@ -40,26 +44,27 @@ local function packoutlines(data,makesequence)
return
end
if makesequence then
--- for index=1,#glyphs do
- for index=0,#glyphs-1 do
+ for index=0,#glyphs do
local glyph = glyphs[index]
- local segments = glyph.segments
- if segments then
- local sequence = { }
- local nofsequence = 0
- for i=1,#segments do
- local segment = segments[i]
- local nofsegment = #segment
- -- why last first ... needs documenting
- nofsequence = nofsequence + 1
- sequence[nofsequence] = segment[nofsegment]
- for i=1,nofsegment-1 do
+ if glyph then
+ local segments = glyph.segments
+ if segments then
+ local sequence = { }
+ local nofsequence = 0
+ for i=1,#segments do
+ local segment = segments[i]
+ local nofsegment = #segment
+ -- why last first ... needs documenting
nofsequence = nofsequence + 1
- sequence[nofsequence] = segment[i]
+ sequence[nofsequence] = segment[nofsegment]
+ for i=1,nofsegment-1 do
+ nofsequence = nofsequence + 1
+ sequence[nofsequence] = segment[i]
+ end
end
+ glyph.sequence = sequence
+ glyph.segments = nil
end
- glyph.sequence = sequence
- glyph.segments = nil
end
end
else
@@ -67,32 +72,36 @@ local function packoutlines(data,makesequence)
local common = { }
local reverse = { }
local last = 0
--- for index=1,#glyphs do
- for index=0,#glyphs-1 do
- local segments = glyphs[index].segments
- if segments then
- for i=1,#segments do
- local h = concat(segments[i]," ")
- hash[h] = (hash[h] or 0) + 1
+ for index=0,#glyphs do
+ local glyph = glyphs[index]
+ if glyph then
+ local segments = glyph.segments
+ if segments then
+ for i=1,#segments do
+ local h = concat(segments[i]," ")
+ hash[h] = (hash[h] or 0) + 1
+ end
end
end
end
--- for index=1,#glyphs do
- for index=0,#glyphs-1 do
- local segments = glyphs[index].segments
- if segments then
- for i=1,#segments do
- local segment = segments[i]
- local h = concat(segment," ")
- if hash[h] > 1 then -- minimal one shared in order to hash
- local idx = reverse[h]
- if not idx then
- last = last + 1
- reverse[h] = last
- common[last] = segment
- idx = last
+ for index=0,#glyphs do
+ local glyph = glyphs[index]
+ if glyph then
+ local segments = glyph.segments
+ if segments then
+ for i=1,#segments do
+ local segment = segments[i]
+ local h = concat(segment," ")
+ if hash[h] > 1 then -- minimal one shared in order to hash
+ local idx = reverse[h]
+ if not idx then
+ last = last + 1
+ reverse[h] = last
+ common[last] = segment
+ idx = last
+ end
+ segments[i] = idx
end
- segments[i] = idx
end
end
end
@@ -119,14 +128,16 @@ local function unpackoutlines(data)
if not glyphs then
return
end
--- for index=1,#glyphs do
- for index=0,#glyphs-1 do
- local segments = glyphs[index].segments
- if segments then
- for i=1,#segments do
- local c = common[segments[i]]
- if c then
- segments[i] = c
+ for index=0,#glyphs do
+ local glyph = glyphs[index]
+ if glyph then
+ local segments = glyph.segments
+ if segments then
+ for i=1,#segments do
+ local c = common[segments[i]]
+ if c then
+ segments[i] = c
+ end
end
end
end
@@ -202,6 +213,11 @@ local function loadoutlines(cache,filename,sub,instance)
return data
end
+local function cachethem(cache,hash,data)
+ containers.write(cache,hash,data,compact_streams) -- arg 4 aka fast
+ return containers.read(cache,hash) -- frees old mem
+end
+
local function loadstreams(cache,filename,sub,instance)
local base = file.basename(filename)
local name = file.removesuffix(base)
@@ -210,7 +226,7 @@ local function loadstreams(cache,filename,sub,instance)
local size = attr and attr.size or 0
local time = attr and attr.modification or 0
local sub = tonumber(sub)
- if size > 0 and (kind == "otf" or kind == "ttf" or kind == "tcc") then
+ if size > 0 and (kind == "otf" or kind == "ttf" or kind == "ttc") then
local hash = makehash(filename,sub,instance)
data = containers.read(cache,hash)
if not data or data.time ~= time or data.size ~= size then
@@ -219,8 +235,13 @@ local function loadstreams(cache,filename,sub,instance)
local glyphs = data.glyphs
local streams = { }
if glyphs then
- for i=0,#glyphs-1 do
- streams[i] = glyphs[i].stream or ""
+ for i=0,#glyphs do
+ local glyph = glyphs[i]
+ if glyph then
+ streams[i] = glyph.stream or ""
+ else
+ streams[i] = ""
+ end
end
end
data.streams = streams
@@ -228,8 +249,7 @@ local function loadstreams(cache,filename,sub,instance)
data.size = size
data.format = data.format or (kind == "otf" and "opentype") or "truetype"
data.time = time
- containers.write(cache,hash,data)
- data = containers.read(cache,hash) -- frees old mem
+ data = cachethem(cache,hash,data)
end
end
elseif size > 0 and (kind == "pfb") then
@@ -283,8 +303,7 @@ local function loadstreams(cache,filename,sub,instance)
weight = metadata.weight,
},
}
- containers.write(cache,hash,data)
- data = containers.read(cache,hash) -- frees old mem
+ data = cachethem(cache,hash,data)
end
end
else
@@ -333,8 +352,11 @@ end
local function loadstreamdata(fontdata)
local properties = fontdata.properties
+ local shared = fontdata.shared
+ local rawdata = shared and shared.rawdata
+ local metadata = rawdata and rawdata.metadata
local filename = properties.filename
- local subindex = fontdata.subindex
+ local subindex = metadata and metadata.subfontindex
local instance = properties.instance
local hash = makehash(filename,subindex,instance)
local loaded = loadedstreams[hash]
@@ -348,26 +370,18 @@ end
hashes.streams = table.setmetatableindex(function(t,k)
local f = identifiers[k]
if f then
- return loadstreamdata(f,true)
+ return loadstreamdata(f)
end
end)
otf.loadoutlinedata = loadoutlinedata -- not public
otf.loadstreamdata = loadstreamdata -- not public
otf.loadshapes = loadshapes
-otf.getstreamhash = getstreamhash -- not public, might move to other namespace
+otf.getstreamhash = getstreamhash -- not public, might move to other namespace
--- experimental code, for me only ... unsupported (todo: use %N)
-
-local f_c = formatters["%F %F %F %F %F %F c"]
-local f_l = formatters["%F %F l"]
-local f_m = formatters["%F %F m"]
-
-directives.register("pdf.stripzeros",function()
- f_c = formatters["%N %N %N %N %N %N c"]
- f_l = formatters["%N %N l"]
- f_m = formatters["%N %N m"]
-end)
+local f_c = formatters["%.6N %.6N %.6N %.6N %.6N %.6N c"]
+local f_l = formatters["%.6N %.6N l"]
+local f_m = formatters["%.6N %.6N m"]
local function segmentstopdf(segments,factor,bt,et)
local t = { }
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-sol.lua b/Master/texmf-dist/tex/context/base/mkiv/font-sol.lua
index 002f9df131f..2017afcb225 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-sol.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-sol.lua
@@ -82,6 +82,7 @@ local hpack_nodes = nuts.hpack
local insert_node_before = nuts.insert_before
local insert_node_after = nuts.insert_after
local protect_glyphs = nuts.protect_glyphs
+local start_of_par = nuts.start_of_par
local nextnode = nuts.traversers.next
local nexthlist = nuts.traversers.hlist
@@ -434,7 +435,7 @@ function splitters.split(head) -- best also pass the direction
end
local direction, pop = getdirection(current)
r2l = not pop and direction == righttoleft
- elseif id == localpar_code and getsubtype(current) == 0 then
+ elseif id == localpar_code and start_of_par(current) then
if start then
flush() -- very unlikely as this starts a paragraph
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-sty.mklx b/Master/texmf-dist/tex/context/base/mkiv/font-sty.mklx
new file mode 100644
index 00000000000..81884333bb1
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-sty.mklx
@@ -0,0 +1,458 @@
+%D \module
+%D [ file=font-sty,
+%D version=2011.01.13, % (copied fron font-ini)
+%D title=\CONTEXT\ Font Macros,
+%D subtitle=Styles,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Font Macros / Styles}
+
+\unprotect
+
+%D \macros
+%D {definealternativestyle}
+%D
+%D In the main modules we are going to implement lots of parameterized commands and
+%D one of these parameters will concern the font to use. To suit consistent use of
+%D fonts we here implement a mechanism for defining the keywords that present a
+%D particular style or alternative.
+%D
+%D \starttyping
+%D \definealternativestyle [keywords] [\style] [\nostyle]
+%D \stoptyping
+%D
+%D The first command is used in the normal textflow, while the second command takes
+%D care of headings and alike. Consider the next two definitions:
+%D
+%D \starttyping
+%D \definealternativestyle [bold] [\bf] []
+%D \definealternativestyle [cap] [\cap] [\cap]
+%D \stoptyping
+%D
+%D A change \type {\bf} in a heading which is to be set in \type {\tfd} does not look
+%D that well, so therefore we leave the second argument of \type
+%D {\definealternativestyle} empty. When we capatalize characters using the pseudo
+%D small cap command \type {\cap}, we want this to take effect in both text and
+%D headings, which is accomplished by assigning both arguments.
+
+\installcorenamespace{alternativestyles} % settings
+\installcorenamespace{alternativestyle} % instances
+
+\installsetuponlycommandhandler \??alternativestyles {alternativestyles}
+
+\setnewconstant \c_font_current_alternative_style_index \plusone
+
+\unexpanded\def\definealternativestyle
+ {\dotripleempty\font_basics_define_alternative_style}
+
+\def\font_basics_define_alternative_style[#commands][#variantone][#varianttwo]%
+ {\processcommalist[#commands]{\font_basics_define_alternative_style_indeed{#variantone}{#varianttwo}}}
+
+\let\definestyle\definealternativestyle % later redefined
+
+\newconstant\c_fonts_basics_alternative_style_method
+
+\def\font_basics_define_alternative_style_indeed#variantone#varianttwo#command%
+ {\setuvalue{\??alternativestyle#command}{\font_helpers_apply_alternative_style{#variantone}{#varianttwo}}%
+ \ifcsname#command\endcsname
+ % no redefinition
+ \orelse\ifnum\c_fonts_basics_alternative_style_method=\plusone
+ \ifthirdargument
+ \setuevalue{#command}{\triggergroupedcommandcs\begincsname\??alternativestyle#command\endcsname}%
+ \else
+ \setuvalue{#command}{\triggergroupedcommand{#variantone}}%
+ \fi
+ \else
+ \setuvalue{#command}{\triggergroupedcommand{#variantone}}%
+ \fi}
+
+\def\font_helpers_apply_alternative_style
+ {\ifcase\c_font_current_alternative_style_index
+ \expandafter\gobbletwoarguments
+ \or
+ \expandafter\firstoftwoarguments
+ \or
+ \expandafter\secondoftwoarguments
+ \else
+ \expandafter\firstoftwoarguments
+ \fi}
+
+\def\applyalternativestyle#name% public
+ {\begincsname\??alternativestyle#name\endcsname}
+
+\appendtoks
+ \doifelse{\alternativestylesparameter\c!method}\v!auto
+ {\c_fonts_basics_alternative_style_method\plusone}%
+ {\c_fonts_basics_alternative_style_method\zerocount}%
+\to \everysetupalternativestyles
+
+%D Maybe too generic, but probably ok is the following. (Maybe one day we will use a
+%D dedicated grouped command for styles.)
+
+% \appendtoks
+% \let\groupedcommand\thirdofthreearguments
+% \to \everysimplifycommands
+
+%D This command also defines the keyword as command. This means that the example
+%D definition of \type {bold} we gave before, results in a command \type {\bold}
+%D which can be used as:
+%D
+%D \startbuffer
+%D He's a \bold{bold} man with a {\bold head}.
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D or
+%D
+%D \startexample
+%D \definealternativestyle[bold][\bf][]\getbuffer
+%D \stopexample
+%D
+%D Such definitions are of course unwanted for \type {\cap} because this would
+%D result in an endless recursive call. Therefore we check on the existance of both
+%D the command and the substitution. The latter is needed because for instance \type
+%D {\type} is an entirely diferent command. That command handles verbatim, while the
+%D style command would just switch to teletype font. This is just an example of a
+%D tricky naming coincidence.
+%D
+%D \macros
+%D {doconvertfont,noconvertfont,
+%D dontconvertfont,redoconvertfont}
+%D
+%D After having defined such keywords, we can call for them by using
+%D
+%D \starttyping
+%D \doconvertfont{keyword}{text}
+%D \stoptyping
+%D
+%D We deliberately pass an argument. This enables us to assign converters that
+%D handle one argument, like \type {\cap}.
+%D
+%D By default the first specification is used to set the style, exept when we say
+%D \type {\dontconvertfont}, after which the second specification is used. We can
+%D also directly call for \type {\noconvertfont}. In nested calls, we can restore
+%D the conversion by saying \type {\redoconvertfont}.
+%D
+%D These commands are not grouped! Grouping is most probably done by the calling
+%D macro's and would lead to unnecessary overhead.
+
+\let\m_current_convert_font \empty
+\let\m_current_convert_font_dt\empty
+
+\unexpanded\def\doconvertfont#specification% takes second argument / this command is obsolete
+ {\edef\m_current_convert_font{#specification}%
+ \ifx\m_current_convert_font\empty
+ %\expandafter\firstofoneargument
+ \else
+ \expandafter\font_helpers_do_convert_font
+ \fi}
+
+\def\font_helpers_do_convert_font
+ {\edef\m_current_convert_font_dt{\detokenize\expandafter{\m_current_convert_font}}%
+ \ifcsname\??alternativestyle\m_current_convert_font_dt\endcsname
+ \expandafter\lastnamedcs
+ \orelse\ifcsname\m_current_convert_font_dt\endcsname
+ \expandafter\lastnamedcs
+ \else
+ \expandafter\m_current_convert_font
+ \fi}
+
+%D Low level switches (downward compatible, but we keep them as one can use them in
+%D styles):
+%D
+%D \starttyping
+%D \usemodule[abr-02]
+%D \setuphead[chapter][style=\bfb]
+%D \setupfooter[style=\dontconvertfont\bf]
+%D \chapter{This is \TEX}
+%D \stoptyping
+
+\unexpanded\def\dontconvertfont{\c_font_current_alternative_style_index\plustwo} % needs checking in usage
+\unexpanded\def\redoconvertfont{\c_font_current_alternative_style_index\plusone} % needs checking in usage
+
+%D The new one:
+
+\setfalse\fontattributeisset
+
+\unexpanded\def\dousestyleparameter#value%
+ {\edef\currentstyleparameter{#value}%
+ \ifx\currentstyleparameter\empty\else
+ \expandafter\dousecurrentstyleparameter
+ \fi}
+
+\unexpanded\def\dousestylehashparameter#hash#parameter%
+ {\ifcsname#hash#parameter\endcsname
+ \expandafter\dousestyleparameter\lastnamedcs
+ \fi}
+
+\unexpanded\def\dousecurrentstyleparameter % empty check outside here
+ {\edef\detokenizedstyleparameter{\detokenize\expandafter{\currentstyleparameter}}%
+ \settrue\fontattributeisset % reset is done elsewhere
+ \ifcsname\??alternativestyle\detokenizedstyleparameter\endcsname
+ \lastnamedcs
+ \orelse\ifcsname\detokenizedstyleparameter\endcsname
+ \lastnamedcs
+ \else
+ \currentstyleparameter
+ \fi}
+
+\let\dosetfontattribute\dousestylehashparameter % for a while
+
+%D New commands (not yet interfaced):
+%D
+%D \startbuffer
+%D \definestyle[one][style=bold,color=darkblue]
+%D
+%D test \one{test} test
+%D test \style[one]{test} test
+%D test \style[color=red]{test} test
+%D test \style[Serif at 20pt]{test} test
+%D \stopbuffer
+%D
+%D \typebuffer \startlines \getbuffer \stoplines
+
+% definitions .. no tagging here
+
+\installcorenamespace{style}
+\installcorenamespace{stylecheck}
+\installcorenamespace{stylehack}
+
+\installcommandhandler \??style {style} \??style
+
+\setupstyle
+ [%\c!style=,
+ %\c!color=,
+ \c!method=\v!command]
+
+\appendtoks
+ \letvalue{\??stylecheck\currentstyle}\relax
+ \edef\p_method{\styleparameter\c!method}%
+ \ifx\p_method\v!command
+ \setuevalue{\e!start\currentstyle}{\font_styles_apply_start{\currentstyle}}%
+ \setuevalue{\e!stop \currentstyle}{\font_styles_apply_stop}%
+ \setuevalue {\currentstyle}{\font_styles_apply_grouped{\currentstyle}}% no longer groupedcommand here
+ \fi
+\to \everydefinestyle
+
+\unexpanded\def\font_styles_apply_start#name%
+ {\begingroup
+ \font_styles_use_defined{#name}}
+
+\unexpanded\def\font_styles_apply_stop
+ {\endgroup}
+
+\unexpanded\def\font_styles_apply_grouped#name% assumes that the next is { or \bgroup
+ {\bgroup
+ \def\g_style{\font_styles_use_defined{#name}}%
+ \afterassignment\g_style
+ \let\nexttoken}
+
+\unexpanded\def\font_styles_use_defined#name%
+ {\edef\currentstyle{#name}%
+ \usestylestyleandcolor\c!style\c!color}
+
+\unexpanded\def\font_styles_use_generic#specification%
+ {\let\currentstyle\s!unknown % reasonable generic tag
+ \letstyleparameter\c!style\empty
+ \letstyleparameter\c!color\empty
+ \setupcurrentstyle[#specification]%
+ \usestylestyleandcolor\c!style\c!color}
+
+% commands
+
+\installcorenamespace{styleargument}
+
+\unexpanded\def\style[#name]% as this is can be a switch we use groupedcommand
+ {\csname\??styleargument
+ \ifcsname\??stylecheck#name\endcsname
+ 2% defined as style
+ \orelse\ifcsname\??stylehack#name\endcsname
+ 4% defined as command
+ \orelse\ifcsname#name\endcsname
+ 1% defined as command
+ \else
+ 3% specification
+ \fi
+ \endcsname{#name}}
+
+% \setvalue{\??styleargument1}#name%
+% {\groupedcommand{\begincsname#name\endcsname}{}}
+
+\setvalue{\??styleargument1}#name%
+ {\expandafter\triggergroupedcommandcs\begincsname#name\endcsname}
+
+% \setvalue{\??styleargument2}#name%
+% {\groupedcommand{\font_styles_use_defined{#name}}{}} % or {\font_styles_apply_grouped{#name}}
+
+\setvalue{\??styleargument2}#name%
+ {\triggergroupedcommand{\font_styles_use_defined{#name}}} % or {\font_styles_apply_grouped{#name}}
+
+\setvalue{\??styleargument3}#specification%
+ {\doifelseassignment{#specification}\font_styles_assignment\font_styles_direct{#specification}}
+
+\setvalue{\??styleargument4}#name%
+ {\expandafter\triggergroupedcommandcs\begincsname\??stylehack#name\endcsname}
+
+\setvalue{\??stylehack\s!math}% dirty trick
+ {\groupedcommand\normalstartimath\normalstopimath}
+
+% \def\font_styles_assignment#specification{\groupedcommand{\font_styles_use_generic{#specification}}{}}
+% \def\font_styles_direct #specification{\groupedcommand{\definedfont[#specification]}{}}
+
+\def\font_styles_assignment#specification{\triggergroupedcommand{\font_styles_use_generic{#specification}}}
+\def\font_styles_direct #specification{\triggergroupedcommand{\definedfont[#specification]}}
+
+% environments
+
+\installcorenamespace{styleenvironment}
+
+\unexpanded\def\startstyle[#name]%
+ {\begingroup
+ \csname\??styleenvironment
+ \ifcsname\??stylecheck#name\endcsname
+ 2% defined as style
+ \orelse\ifcsname#name\endcsname
+ 1% defined as command
+ \else
+ 3% specification
+ \fi
+ \endcsname{#name}}
+
+\unexpanded\def\stopstyle
+ {\endgroup
+ \autoinsertnextspace} % will be configurable, maybe also in \definestartstop
+
+\setvalue{\??styleenvironment1}#name%
+ {\csname#name\endcsname}
+
+\setvalue{\??styleenvironment2}#name%
+ {\font_styles_use_defined{#name}}
+
+\setvalue{\??styleenvironment3}#specification%
+ {\doifelseassignment{#specification}\font_styles_start_assignment\font_styles_start_direct{#specification}}
+
+\def\font_styles_start_assignment#specification{\font_styles_use_generic{#specification}}
+\def\font_styles_start_direct #specification{\definedfont[#specification]\relax}
+
+%D Still experimental (might even go away).
+
+% \definestylecollection[mine]
+
+% \definestyleinstance[mine][default][sorry]
+% \definestyleinstance[mine][tt][bs][ttbs:\rm\sl]
+% \definestyleinstance[mine][tt][bf][ttbf:\rm\sl]
+% \definestyleinstance[mine][bf][\sl]
+% \definestyleinstance[mine][sl][\tt]
+
+% {\bf test \mine test \sl test \mine test \bs oeps \mine oeps {\tt test \mine \bf test}}
+
+\installcorenamespace{stylecollection}
+
+\unexpanded\def\definestylecollection
+ {\dosingleargument\font_styles_define_style_collection}
+
+\def\font_styles_define_style_collection[#name]%
+ {\iffirstargument
+ \setuvalue{#name}{\styleinstance[#name]}%
+ \def\font_styles_define_style_collection_a#style%
+ {\def\font_styles_define_style_collection_b#alternative{\undefinevalue{\??stylecollection#name:#style:#alternative}}%
+ \font_helpers_process_alternative_list\font_styles_define_style_collection_b
+ \font_styles_define_style_collection_b\s!default}%
+ \font_helpers_process_style_list\font_styles_define_style_collection_a
+ \font_styles_define_style_collection_a\s!default
+ \fi}
+
+\let\font_styles_define_style_collection_a\relax
+\let\font_styles_define_style_collection_b\relax
+
+\unexpanded\def\definestyleinstance
+ {\doquadrupleargument\font_styles_define_style_instance}
+
+\def\font_styles_define_style_instance[#instance][#2][#3][#4]% [name] [rm|ss|tt|..] [sl|bf|...] [whatever]
+ {\iffirstargument
+ \ifcsname#instance\endcsname\else\font_styles_define_style_collection[#instance]\fi
+ \fi
+ \iffourthargument
+ \setvalue{\??stylecollection#instance:#2:#3}{#4}%
+ \orelse\ifthirdargument
+ \setvalue{\??stylecollection#instance::#2}{#3}%
+ \orelse\ifsecondargument
+ \letvalueempty{\??stylecollection#instance::#2}%
+ \fi}
+
+% \unexpanded\def\styleinstance[#instance]% will be made faster
+% {%\begingroup\normalexpanded{\noexpand\infofont[#1:\fontstyle:\fontalternative]}\endgroup
+% \executeifdefined{\??stylecollection#instance:\fontstyle:\fontalternative}%
+% {\executeifdefined{\??stylecollection#instance:\fontstyle:\s!default}%
+% {\executeifdefined{\??stylecollection#instance::\fontalternative}
+% {\getvalue {\??stylecollection#instance::\s!default}}}}}
+
+\unexpanded\def\styleinstance[#instance]% maybe \lastnamedcs here too
+ {\csname\??stylecollection#instance:%
+ \ifcsname\??stylecollection#instance:\fontstyle:\fontalternative\endcsname
+ \fontstyle:\fontalternative
+ \orelse\ifcsname\??stylecollection#instance:\fontstyle:\s!default\endcsname
+ \fontstyle:\s!default
+ \orelse\ifcsname\??stylecollection#instance::\fontalternative\endcsname
+ :\fontalternative
+ \else
+ :\s!default
+ \fi
+ \endcsname}
+
+%D Variant selectors
+%D
+%D \starttyping
+%D \mathematics {\vsone{\utfchar{0x2229}}}
+%D \mathematics {\utfchar{0x2229}\vsone{}}
+%D \stoptyping
+
+\unexpanded\edef\vsone#character{#character\normalUchar"FE00 } % used
+\unexpanded\edef\vstwo#character{#character\normalUchar"FE01 } % not used but handy for testing
+
+%D For historic reasons we keep the following around but they are no longer that
+%D relevant for \MKIV.
+
+\unexpanded\def\doattributes#1#2#3#4%
+ {\begingroup % geen \bgroup, anders in mathmode lege \hbox
+ \dousestylehashparameter{#1}{#2}%
+ \dousecolorhashparameter{#1}{#3}%
+ #4%
+ \endgroup}
+
+\unexpanded\def\dostartattributes#1#2#3%
+ {\begingroup % geen \bgroup, anders in mathmode lege \hbox
+ \dousestylehashparameter{#1}{#2}%
+ \dousecolorhashparameter{#1}{#3}}
+
+\let\dostopattributes\endgroup
+
+%D New but it needs to be supported explicitly (as in natural tables).
+
+\newconditional\c_font_styles_math
+
+\unexpanded\def\font_styles_math_reset
+ {\setfalse\c_font_styles_math}
+
+\unexpanded\def\font_styles_math_start
+ {\ifconditional\c_font_styles_math
+ \startimath
+ \fi
+ \relax}
+
+\unexpanded\def\font_styles_math_stop
+ {\relax
+ \ifconditional\c_font_styles_math
+ \stopimath
+ \fi}
+
+\definealternativestyle[\v!math][\settrue\c_font_styles_math]
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-sty.mkvi b/Master/texmf-dist/tex/context/base/mkiv/font-sty.mkvi
index 8200aa95748..a24194355e2 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-sty.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-sty.mkvi
@@ -222,6 +222,7 @@
\installcorenamespace{style}
\installcorenamespace{stylecheck}
+\installcorenamespace{stylehack}
\installcommandhandler \??style {style} \??style
@@ -272,11 +273,13 @@
{\csname\??styleargument
\ifcsname\??stylecheck#name\endcsname
2% defined as style
+ \else\ifcsname\??stylehack#name\endcsname
+ 4% defined as command
\else\ifcsname#name\endcsname
1% defined as command
\else
3% specification
- \fi\fi
+ \fi\fi\fi
\endcsname{#name}}
% \setvalue{\??styleargument1}#name%
@@ -294,6 +297,12 @@
\setvalue{\??styleargument3}#specification%
{\doifelseassignment{#specification}\font_styles_assignment\font_styles_direct{#specification}}
+\setvalue{\??styleargument4}#name%
+ {\expandafter\triggergroupedcommandcs\begincsname\??stylehack#name\endcsname}
+
+\setvalue{\??stylehack\s!math}% dirty trick
+ {\groupedcommand\normalstartimath\normalstopimath}
+
% \def\font_styles_assignment#specification{\groupedcommand{\font_styles_use_generic{#specification}}{}}
% \def\font_styles_direct #specification{\groupedcommand{\definedfont[#specification]}{}}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-sym.mklx b/Master/texmf-dist/tex/context/base/mkiv/font-sym.mklx
new file mode 100644
index 00000000000..33f8a62da7b
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-sym.mklx
@@ -0,0 +1,245 @@
+%D \module
+%D [ file=font-mat,
+%D version=2011.01.13, % (copied fron font-ini)
+%D title=\CONTEXT\ Font Macros,
+%D subtitle=Symbolic Access,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Font Macros / Symbolic Access}
+
+\unprotect
+
+%D \macros
+%D {getglyph, symbolicfont}
+%D
+%D Individual glyphs can be accessed by using
+%D
+%D \starttyping
+%D \getglyph{fontname}{character}
+%D \stoptyping
+%D
+%D This macro is used in for instance the symbol modules and as one can see, it does
+%D obey the small and even smaller sizes. The \type {\symbolicfont} macro can be
+%D used to switch to a font named \type {fontname} (see \type {cont-log} and \type
+%D {symb-eur} for examples of symbolic definitions.
+
+\def\v_font_string_a
+ {\ifx\fontstyle\s!rm \s!Serif \orelse
+ \ifx\fontstyle\s!ss \s!Sans \orelse
+ \ifx\fontstyle\s!tt \s!Mono \else
+ \s!Serif \fi}
+
+\def\v_font_string_b
+ {\ifx\fontstyle\s!rm \s!Regular \orelse
+ \ifx\fontstyle\s!ss \s!Support \orelse
+ \ifx\fontstyle\s!tt \s!Type \else
+ \s!Serif \fi}
+
+\def\v_font_string_c
+ {\ifx\fontalternative\s!bf \s!Bold \orelse
+ \ifx\fontalternative\s!sl \s!Slanted \orelse
+ \ifx\fontalternative\s!it \s!Italic \orelse
+ \ifx\fontalternative\s!bs \s!BoldSlanted \orelse
+ \ifx\fontalternative\s!bi \s!BoldItalic \fi}
+
+\let\v_font_string_d\s!Serif % default fontstyle (will be redefined in type-ini)
+
+\definefontsynonym
+ [CurrentFont]
+ [\noexpand\v_font_string_a\noexpand\v_font_string_c]
+
+% potential generalization:
+%
+% \letvalue{\??fontfile:t:\s!rm}\s!Serif
+% \letvalue{\??fontfile:t:\s!ss}\s!Sans
+% \letvalue{\??fontfile:t:\s!tt}\s!Mono
+%
+% \letvalue{\??fontfile:a:\s!rm}\s!Regular
+% \letvalue{\??fontfile:a:\s!ss}\s!Support
+% \letvalue{\??fontfile:a:\s!tt}\s!Type
+%
+% \letvalue{\??fontfile:s:\s!bf}\s!Bold
+% \letvalue{\??fontfile:s:\s!sl}\s!Slanted
+% \letvalue{\??fontfile:s:\s!it}\s!Italic
+% \letvalue{\??fontfile:s:\s!bs}\s!BoldSlanted
+% \letvalue{\??fontfile:s:\s!bi}\s!BoldItalic
+%
+% \def\v_font_string_a{\executeifdefined{\??fontfile:t:\fontstyle}\s!Serif}
+% \def\v_font_string_a{\executeifdefined{\??fontfile:t:\fontstyle}\s!Serif}
+% \def\v_font_string_b{\executeifdefined{\??fontfile:a:\fontstyle}\s!Serif}
+% \def\v_font_string_c{\executeifdefined{\??fontfile:s:\fontstyle}\empty}
+% \def\v_font_string_d{\executeifdefined{\??fontfile:t:\csname\??typescriptdefaultstyles\fontclass\endcsname}\s!Serif}
+
+%D \macros
+%D {fontstylesuffix}
+%D
+%D The next macro is used to map non latin fontnames on fonts. See \type
+%D {font-uni} for an example of its use.
+
+\def\fontstylesuffix% why the \s!Regular ? see \getglyph
+ {\ifx\fontalternative\s!tf \s!Regular \orelse
+ \ifx\fontalternative\s!bf \s!Bold \orelse
+ \ifx\fontalternative\s!sl \s!Slanted \orelse
+ \ifx\fontalternative\s!it \s!Italic \orelse
+ \ifx\fontalternative\s!bs \s!BoldSlanted \orelse
+ \ifx\fontalternative\s!bi \s!BoldItalic \orelse
+ \ifx\fontalternative\s!sc \s!Caps \else
+ \s!Regular \fi}
+
+\def\glyphfontfile#base% appends
+ {#base%
+ \ifcsname\??fontfile#base\v_font_string_a\v_font_string_c\endcsname
+ \v_font_string_a\v_font_string_c
+ \orelse\ifcsname\??fontfile#base\v_font_string_b\v_font_string_c\endcsname
+ \v_font_string_b\v_font_string_c
+ \orelse\ifcsname\??fontfile#base\v_font_string_a\endcsname
+ \v_font_string_a
+ \orelse\ifcsname\??fontfile#base\v_font_string_b\endcsname
+ \v_font_string_b
+ \orelse\ifcsname\??fontfile#base\v_font_string_c\endcsname
+ \v_font_string_c
+ \fi}
+
+%D The next macro can be used to make decisions based on the shape:
+
+\def\doifelseitalic#yes#nop%
+ {\ifx\fontalternative\s!sl#yes\orelse
+ \ifx\fontalternative\s!it#yes\orelse
+ \ifx\fontalternative\s!bs#yes\orelse
+ \ifx\fontalternative\s!bi#yes\else#nop\fi}
+
+\let\doifitalicelse\doifelseitalic
+
+%D For an example of usage of the following command, see \type {cont-log.tex}.
+%D
+%D \starttyping
+%D \def\symbolicfont#specification{\definedfont[\glyphfontfile{#specification} sa *]}
+%D \stoptyping
+%D
+%D Since we know what scaling it to be applied, we can implement a much faster
+%D alternative:
+
+\installcorenamespace{symbolfont}
+
+\let\thedefinedfont\relax
+
+\def\setscaledstyledsymbolicfont#1#2#3% quite a slowdown, glyphfontfile
+ {\edef\askedsymbolfont{\truefontname{\glyphfontfile{#3}} at \the\dimexpr#2\dimexpr\currentfontbodyscale\dimexpr#1}%
+ \ifcsname\??symbolfont\askedsymbolfont\endcsname
+ \lastnamedcs
+ \else
+ \font_basics_define_symbolic_font
+ \fi}
+
+\def\setscaleddirectsymbolicfont#1#2#3% quite a slowdown, glyphfontfile
+ {\edef\askedsymbolfont{\truefontname{#3} at \the\dimexpr#2\dimexpr\currentfontbodyscale\dimexpr#1}%
+ \ifcsname\??symbolfont\askedsymbolfont\endcsname
+ \lastnamedcs
+ \else
+ \font_basics_define_symbolic_font
+ \fi}
+
+\def\setstyledsymbolicfont#fontname% quite a slowdown, glyphfontfile
+ {\edef\askedsymbolfont{\truefontname{\glyphfontfile{#fontname}} at \the\dimexpr\currentfontbodyscale\dimexpr\fontbody}%
+ \ifcsname\??symbolfont\askedsymbolfont\endcsname
+ \lastnamedcs
+ \else
+ \font_basics_define_symbolic_font
+ \fi}
+
+\def\setdirectsymbolicfont#fontname%
+ {\edef\askedsymbolfont{\truefontname{#fontname} at \the\dimexpr\currentfontbodyscale\dimexpr\fontbody}%
+ \ifcsname\??symbolfont\askedsymbolfont\endcsname
+ \lastnamedcs
+ \else
+ \font_basics_define_symbolic_font
+ \fi}
+
+\def\font_basics_define_symbolic_font
+ {\definefont[currentsymbolfont][\askedsymbolfont]%
+ \currentsymbolfont
+ \expandafter\glet\csname\??symbolfont\askedsymbolfont\endcsname\lastrawfontcall}
+
+\unexpanded\def\getnamedglyphstyled#fontname#character{{\setstyledsymbolicfont{#fontname}\clf_fontchar{#character}}}
+\unexpanded\def\getnamedglyphdirect#fontname#character{{\setdirectsymbolicfont{#fontname}\clf_fontchar{#character}}}
+\unexpanded\def\getglyphstyled #fontname#character{{\setstyledsymbolicfont{#fontname}\doifelsenumber{#character}\char\donothing#character}}
+\unexpanded\def\getglyphdirect #fontname#character{{\setdirectsymbolicfont{#fontname}\doifelsenumber{#character}\char\donothing#character}}
+\unexpanded\def\resolvedglyphstyled#fontname#character{{\setstyledsymbolicfont{#fontname}\clf_tochar{#character}}}
+\unexpanded\def\resolvedglyphdirect#fontname#character{{\setdirectsymbolicfont{#fontname}\clf_tochar{#character}}}
+
+% this one is wrong:
+
+\unexpanded\def\getscaledglyph#scale#name#content%
+ {{\setscaledstyledsymbolicfont\fontbody{#scale}{#name}\doifelsenumber{#content}\char\donothing#content}}
+
+\let\getglyph \getglyphstyled % old
+\let\getrawglyph \getglyphdirect % old
+\let\symbolicsizedfont\setscaledstyledsymbolicfont % old
+\let\symbolicfont \setstyledsymbolicfont % old
+
+\unexpanded\def\symbolicscaledfont{\setsscaledstyledsymbolicfont\fontbody}
+\unexpanded\def\symbolicscaledfont{\setscaledstyledsymbolicfont\fontbody}
+
+%D The last implementation of \type {\getglyph} permits definitions like:
+%D
+%D \starttyping
+%D \definefontsynonym [EuroSans] [eurose]
+%D \definefontsynonym [EuroSansBold] [euroseb]
+%D \definefontsynonym [EuroSansItalic] [eurosei]
+%D \definefontsynonym [EuroSansSlanted] [eurosei]
+%D \definefontsynonym [EuroSansBoldItalic] [eurosebi]
+%D \definefontsynonym [EuroSansBoldSlanted] [eurosebi]
+%D
+%D \definesymbol [euro] [\getglyph{Euro}{\char160}]
+%D
+%D \def\euro{\symbol[euro]}
+%D \stoptyping
+%D
+%D These definitions guarantee that the next calls work okay:
+%D
+%D \starttyping
+%D \ss \tf\euro \bf\euro \sla\euro \itd\euro \bs\euro \bic\euro
+%D \stoptyping
+%D
+%D The shape as well as the size is adapted to the current environment.
+
+%D \macros
+%D {setfont}
+%D
+%D Every now and then we want to define a font directly, for instance when we
+%D typeset title pages. The next macro saves some typing:
+
+\unexpanded\def\setfont% geen \font_helpers_set_font mogelijk
+ {\afterassignment\font_basics_set_font\font\nextfont=}
+
+\def\font_basics_set_font
+ {\nextfont\setupinterlinespace}% hm, we need to use \setuplocalinterlinespace
+
+%D One can call this macro as:
+%D
+%D \starttyping
+%D \setfont cmr10 at 60pt
+%D \stoptyping
+%D
+%D After which the font is active and the baselines and struts are set.
+
+%D \macros{doiffontcharelse}
+
+\unexpanded\def\doifelsefontchar#specification#unicode% this could be a direct lua call
+ {\begingroup
+ \font_basics_define_font_without_parameters{thedefinedfont}{#specification}%
+ \iffontchar\font#unicode\relax
+ \endgroup\expandafter\firstoftwoarguments
+ \else
+ \endgroup\expandafter\secondoftwoarguments
+ \fi}
+
+\let\doiffontcharelse\doifelsefontchar
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-sym.mkvi b/Master/texmf-dist/tex/context/base/mkiv/font-sym.mkvi
index 3ff85fb4a84..b6479535b3a 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-sym.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-sym.mkvi
@@ -24,12 +24,10 @@
%D \getglyph{fontname}{character}
%D \stoptyping
%D
-%D This macro is used in for instance the symbol modules and
-%D as one can see, it does obey the small and even smaller
-%D sizes. The \type {\symbolicfont} macro can be used to
-%D switch to a font named \type {fontname} (see \type
-%D {cont-log} and \type {symb-eur} for examples of symbolic
-%D definitions.
+%D This macro is used in for instance the symbol modules and as one can see, it does
+%D obey the small and even smaller sizes. The \type {\symbolicfont} macro can be
+%D used to switch to a font named \type {fontname} (see \type {cont-log} and \type
+%D {symb-eur} for examples of symbolic definitions.
\def\v_font_string_a
{\ifx\fontstyle\s!rm \s!Serif \else
@@ -118,15 +116,14 @@
\let\doifitalicelse\doifelseitalic
-%D For an example of usage of the following command,
-%D see \type {cont-log.tex}.
+%D For an example of usage of the following command, see \type {cont-log.tex}.
%D
%D \starttyping
%D \def\symbolicfont#specification{\definedfont[\glyphfontfile{#specification} sa *]}
%D \stoptyping
%D
-%D Since we know what scaling it to be applied, we can
-%D implement a much faster alternative:
+%D Since we know what scaling it to be applied, we can implement a much faster
+%D alternative:
\installcorenamespace{symbolfont}
@@ -189,8 +186,7 @@
\unexpanded\def\symbolicscaledfont{\setsscaledstyledsymbolicfont\fontbody}
\unexpanded\def\symbolicscaledfont{\setscaledstyledsymbolicfont\fontbody}
-%D The last implementation of \type {\getglyph} permits
-%D definitions like:
+%D The last implementation of \type {\getglyph} permits definitions like:
%D
%D \starttyping
%D \definefontsynonym [EuroSans] [eurose]
@@ -211,15 +207,13 @@
%D \ss \tf\euro \bf\euro \sla\euro \itd\euro \bs\euro \bic\euro
%D \stoptyping
%D
-%D The shape as well as the size is adapted to the current
-%D environment.
+%D The shape as well as the size is adapted to the current environment.
%D \macros
%D {setfont}
%D
-%D Every now and then we want to define a font directly, for
-%D instance when we typeset title pages. The next macro saves
-%D some typing:
+%D Every now and then we want to define a font directly, for instance when we
+%D typeset title pages. The next macro saves some typing:
\unexpanded\def\setfont% geen \font_helpers_set_font mogelijk
{\afterassignment\font_basics_set_font\font\nextfont=}
@@ -233,8 +227,7 @@
%D \setfont cmr10 at 60pt
%D \stoptyping
%D
-%D After which the font is active and the baselines and
-%D struts are set.
+%D After which the font is active and the baselines and struts are set.
%D \macros{doiffontcharelse}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-syn.lua b/Master/texmf-dist/tex/context/base/mkiv/font-syn.lua
index 18c25fbfd97..1d5e1803243 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-syn.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-syn.lua
@@ -26,6 +26,7 @@ local formatters, topattern = string.formatters, string.topattern
local round = math.round
local P, R, S, C, Cc, Ct, Cs = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cc, lpeg.Ct, lpeg.Cs
local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns
+local isfile, modificationtime = lfs.isfile, lfs.modification
local allocate = utilities.storage.allocate
local sparse = utilities.storage.sparse
@@ -46,9 +47,6 @@ local findfile = resolvers.findfile
local cleanpath = resolvers.cleanpath
local resolveprefix = resolvers.resolve
------ fontloader = fontloader -- still needed for pfb (now)
------ get_font_info = fontloader.info
-
local settings_to_hash = utilities.parsers.settings_to_hash_tolerant
local trace_names = false trackers.register("fonts.names", function(v) trace_names = v end)
@@ -468,11 +466,11 @@ function names.getpaths(trace)
if name == "" then
-- after all, fontconfig is a unix thing
name = filejoin("/etc",confname)
- if not lfs.isfile(name) then
+ if not isfile(name) then
name = "" -- force quit
end
end
- if name ~= "" and lfs.isfile(name) then
+ if name ~= "" and isfile(name) then
if trace_names then
report_names("%s fontconfig file %a","loading",name)
end
@@ -485,7 +483,7 @@ function names.getpaths(trace)
incname = filejoin(path,incname)
end
end
- if lfs.isfile(incname) then
+ if isfile(incname) then
if trace_names then
report_names("%s fontconfig file %a","merging included",incname)
end
@@ -1099,7 +1097,7 @@ local function analyzefiles(olddata)
end
-- needs checking with ttc / ttx : date not updated ?
local result = nil
- local modification = lfs.attributes(completename,"modification")
+ local modification = modificationtime(completename)
if olddata and modification and modification > 0 then
local oldindex = oldindices[storedname] -- index into specifications
if oldindex then
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-tfm.lua b/Master/texmf-dist/tex/context/base/mkiv/font-tfm.lua
index 6e4f8698052..e2f0d22f2a8 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-tfm.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-tfm.lua
@@ -6,6 +6,8 @@ if not modules then modules = { } end modules ['font-tfm'] = {
license = "see context related readme files"
}
+if not context then return end -- use luatex-fonts-tfm.lua instead
+
local next, type = next, type
local match, format = string.match, string.format
local concat, sortedhash = table.concat, table.sortedhash
@@ -118,266 +120,216 @@ local depth = { } -- table.setmetatableindex("number")
--
-- So "czechdqcheat=yes" is then a valid feature. And yes, it's a cheat.
-local read_from_tfm, check_tfm do
-
- local tfmreaders = context and tfm.readers
- local loadtfmvf = tfmreaders and tfmreaders.loadtfmvf
- local loadtfm = font.read_tfm
- local loadvf = font.read_vf
+local loadtfmvf = tfm.readers.loadtfmvf
- directives.register("fonts.tfm.builtin",function(v)
- loadtfmvf = tfmreaders and tfmreaders.loadtfmvf
- if v and loadtfm then
- loadtfmvf = false
+local function read_from_tfm(specification)
+ local filename = specification.filename
+ local size = specification.size
+ depth[filename] = (depth[filename] or 0) + 1
+ if trace_defining then
+ report_defining("loading tfm file %a at size %s",filename,size)
+ end
+ local tfmdata = loadtfmvf(filename,size)
+ if tfmdata then
+
+ local features = specification.features and specification.features.normal or { }
+ local features = constructors.checkedfeatures("tfm",features)
+ specification.features.normal = features
+
+ -- If reencode returns a new table, we assume that we're doing something
+ -- special. An 'auto' reencode picks up its vector from the pfb file.
+
+ if lpdf and lpdf.getmapentry and not features.reencode then
+ -- This can happen multiple times but not that often so we don't
+ -- optimize this.
+ local encoding, pfbfile, encfile = lpdf.getmapentry(filename)
+ if encoding and pfbfile then
+ features.reencode = encfile
+ features.pfbfile = pfbfile
+ end
end
- end)
- read_from_tfm = function(specification)
- local filename = specification.filename
- local size = specification.size
- depth[filename] = (depth[filename] or 0) + 1
- if trace_defining then
- report_defining("loading tfm file %a at size %s",filename,size)
+ local newtfmdata = (depth[filename] == 1) and tfm.reencode(tfmdata,specification)
+ if newtfmdata then
+ tfmdata = newtfmdata
end
- local tfmdata -- not cached, fast enough
- if loadtfmvf then
- tfmdata = loadtfmvf(filename,size)
- else
- tfmdata = loadtfm(filename,size)
- end
- if tfmdata then
-
- local features = specification.features and specification.features.normal or { }
- local features = constructors.checkedfeatures("tfm",features)
- specification.features.normal = features
- -- If reencode returns a new table, we assume that we're doing something
- -- special. An 'auto' reencode picks up its vector from the pfb file.
-
- local newtfmdata = (depth[filename] == 1) and tfm.reencode(tfmdata,specification)
- if newtfmdata then
- tfmdata = newtfmdata
+ local resources = tfmdata.resources or { }
+ local properties = tfmdata.properties or { }
+ local parameters = tfmdata.parameters or { }
+ local shared = tfmdata.shared or { }
+ --
+ shared.features = features
+ shared.resources = resources
+ --
+ properties.name = tfmdata.name -- todo: fallback
+ properties.fontname = tfmdata.fontname -- todo: fallback
+ properties.psname = tfmdata.psname -- todo: fallback
+ properties.fullname = tfmdata.fullname -- todo: fallback
+ properties.filename = specification.filename -- todo: fallback
+ properties.format = tfmdata.format or fonts.formats.tfm -- better than nothing
+ properties.usedbitmap = tfmdata.usedbitmap
+ --
+if lpdf and lpdf.getmapentry and newtfmdata then
+ properties.filename = features.pfbfile
+end
+ --
+ tfmdata.properties = properties
+ tfmdata.resources = resources
+ tfmdata.parameters = parameters
+ tfmdata.shared = shared
+ --
+ shared.rawdata = { resources = resources }
+ shared.features = features
+ --
+ -- The next branch is only entered when we have a proper encoded file i.e.
+ -- unicodes and such. It really nakes no sense to do feature juggling when
+ -- we have no names and unicodes.
+ --
+ if newtfmdata then
+ --
+ -- Some opentype processing assumes these to be present:
+ --
+ if not resources.marks then
+ resources.marks = { }
+ end
+ if not resources.sequences then
+ resources.sequences = { }
+ end
+ if not resources.features then
+ resources.features = {
+ gsub = { },
+ gpos = { },
+ }
+ end
+ if not tfmdata.changed then
+ tfmdata.changed = { }
+ end
+ if not tfmdata.descriptions then
+ tfmdata.descriptions = tfmdata.characters
end
-
- local resources = tfmdata.resources or { }
- local properties = tfmdata.properties or { }
- local parameters = tfmdata.parameters or { }
- local shared = tfmdata.shared or { }
--
- shared.features = features
- shared.resources = resources
+ -- It might be handy to have this:
--
- properties.name = tfmdata.name -- todo: fallback
- properties.fontname = tfmdata.fontname -- todo: fallback
- properties.psname = tfmdata.psname -- todo: fallback
- properties.fullname = tfmdata.fullname -- todo: fallback
- properties.filename = specification.filename -- todo: fallback
- properties.format = tfmdata.format or fonts.formats.tfm -- better than nothing
- properties.usedbitmap = tfmdata.usedbitmap
+ otf.readers.addunicodetable(tfmdata)
--
- tfmdata.properties = properties
- tfmdata.resources = resources
- tfmdata.parameters = parameters
- tfmdata.shared = shared
+ -- We make a pseudo opentype font, e.g. kerns and ligatures etc:
--
- shared.rawdata = { resources = resources }
- shared.features = features
+ tfmenhancers.apply(tfmdata,filename)
--
- -- The next branch is only entered when we have a proper encoded file i.e.
- -- unicodes and such. It really nakes no sense to do feature juggling when
- -- we have no names and unicodes.
+ -- Now user stuff can kick in.
--
- if newtfmdata then
- --
- -- Some opentype processing assumes these to be present:
- --
- if not resources.marks then
- resources.marks = { }
- end
- if not resources.sequences then
- resources.sequences = { }
- end
- if not resources.features then
- resources.features = {
- gsub = { },
- gpos = { },
- }
- end
- if not tfmdata.changed then
- tfmdata.changed = { }
- end
- if not tfmdata.descriptions then
- tfmdata.descriptions = tfmdata.characters
- end
- --
- -- It might be handy to have this:
- --
- otf.readers.addunicodetable(tfmdata)
- --
- -- We make a pseudo opentype font, e.g. kerns and ligatures etc:
- --
- tfmenhancers.apply(tfmdata,filename)
- --
- -- Now user stuff can kick in.
- --
- constructors.applymanipulators("tfm",tfmdata,features,trace_features,report_tfm)
- --
- -- As that can also mess with names and such, we are now ready for finalizing
- -- the unicode information. This is a different order that for instance type one
- -- (afm) files. First we try to deduce unicodes from already present information.
- --
- otf.readers.unifymissing(tfmdata)
- --
- -- Next we fill in the gaps, based on names from teh agl. Probably not much will
- -- happen here.
- --
- fonts.mappings.addtounicode(tfmdata,filename)
- --
- -- The tounicode data is passed to the backend that constructs the vectors for us.
- --
- tfmdata.tounicode = 1
- local tounicode = fonts.mappings.tounicode
- for unicode, v in next, tfmdata.characters do
- local u = v.unicode
- if u then
- v.tounicode = tounicode(u)
- end
- end
- --
- -- However, when we use a bitmap font those vectors can't be constructed because
- -- that information is not carried with those fonts (there is no name info, nor
- -- proper index info, nor unicodes at that end). So, we provide it ourselves.
- --
- if tfmdata.usedbitmap then
- tfm.addtounicode(tfmdata)
- end
- end
+ constructors.applymanipulators("tfm",tfmdata,features,trace_features,report_tfm)
--
- shared.processes = next(features) and tfm.setfeatures(tfmdata,features) or nil
+ -- As that can also mess with names and such, we are now ready for finalizing
+ -- the unicode information. This is a different order that for instance type one
+ -- (afm) files. First we try to deduce unicodes from already present information.
--
- if size < 0 then
- size = idiv(65536 * -size,100)
- end
- parameters.factor = 1 -- already scaled
- parameters.units = 1000 -- just in case
- parameters.size = size
- parameters.slant = parameters.slant or parameters[1] or 0
- parameters.space = parameters.space or parameters[2] or 0
- parameters.space_stretch = parameters.space_stretch or parameters[3] or 0
- parameters.space_shrink = parameters.space_shrink or parameters[4] or 0
- parameters.x_height = parameters.x_height or parameters[5] or 0
- parameters.quad = parameters.quad or parameters[6] or 0
- parameters.extra_space = parameters.extra_space or parameters[7] or 0
+ otf.readers.unifymissing(tfmdata)
--
- constructors.enhanceparameters(parameters) -- official copies for us
+ -- Next we fill in the gaps, based on names from teh agl. Probably not much will
+ -- happen here.
--
- properties.private = properties.private or tfmdata.private or privateoffset
+ fonts.mappings.addtounicode(tfmdata,filename)
--
- if newtfmdata then
- --
- -- We do nothing as we assume flat tfm files. It would become real messy
- -- otherwise and I don't have something for testing on my system anyway.
- --
- elseif loadtfmvf then
- -- already loaded
- local fonts = tfmdata.fonts
- if fonts then
- for i=1,#fonts do
- local font = fonts[i]
- local id = font.id
- if not id then
- local name = font.name
- local size = font.size
- if name and size then
- local data, id = constructors.readanddefine(name,size)
- if id then
- font.id = id
- font.name = nil
- font.size = nil
- end
- end
- end
- end
- end
- elseif constructors.resolvevirtualtoo then
- fonts.loggers.register(tfmdata,file.suffix(filename),specification) -- strange, why here
- local vfname = findbinfile(specification.name, 'ovf')
- if vfname and vfname ~= "" then
- local vfdata = loadvf(vfname,size)
- if vfdata then
- local chars = tfmdata.characters
- for k,v in next, vfdata.characters do
- chars[k].commands = v.commands
- end
- properties.virtualized = true
- tfmdata.fonts = vfdata.fonts
- tfmdata.type = "virtual" -- else nested calls with cummulative scaling
- local fontlist = vfdata.fonts
- local name = file.nameonly(filename)
- for i=1,#fontlist do
- local n = fontlist[i].name
- local s = fontlist[i].size
- local d = depth[filename]
- s = constructors.scaled(s,vfdata.designsize)
- if d > tfm.maxnestingdepth then
- report_defining("too deeply nested virtual font %a with size %a, max nesting depth %s",n,s,tfm.maxnestingdepth)
- fontlist[i] = { id = 0 }
- elseif (d > 1) and (s > tfm.maxnestingsize) then
- report_defining("virtual font %a exceeds size %s",n,s)
- fontlist[i] = { id = 0 }
- else
- local t, id = constructors.readanddefine(n,s)
- fontlist[i] = { id = id }
- end
- end
- end
+ -- The tounicode data is passed to the backend that constructs the vectors for us.
+ --
+ tfmdata.tounicode = 1
+ local tounicode = fonts.mappings.tounicode
+ for unicode, v in next, tfmdata.characters do
+ local u = v.unicode
+ if u then
+ v.tounicode = tounicode(u)
end
end
--
- -- This is for old times sake (and context specific) so we comment it. It has
- -- to do with encoding prefixes (a context naming that was later adopted by
- -- the lm/gyre project)
- --
- -- if not features.encoding then
- -- local encoding, filename = match(properties.filename,"^(.-)%-(.*)$")
- -- if filename and encoding and encodings.known and encodings.known[encoding] then
- -- features.encoding = encoding
- -- end
- -- end
- --
- -- Some afterthoughts:
+ -- However, when we use a bitmap font those vectors can't be constructed because
+ -- that information is not carried with those fonts (there is no name info, nor
+ -- proper index info, nor unicodes at that end). So, we provide it ourselves.
--
- properties.haskerns = true
- properties.hasligatures = true
- properties.hasitalics = true
- resources.unicodes = { }
- resources.lookuptags = { }
+ if tfmdata.usedbitmap then
+ tfm.addtounicode(tfmdata)
+ end
+ end
+ --
+ shared.processes = next(features) and tfm.setfeatures(tfmdata,features) or nil
+ --
+ if size < 0 then
+ size = idiv(65536 * -size,100)
+ end
+
+ parameters.factor = 1 -- already scaled
+ parameters.units = 1000 -- just in case
+ parameters.size = size
+ parameters.slant = parameters.slant or parameters[1] or 0
+ parameters.space = parameters.space or parameters[2] or 0
+ parameters.space_stretch = parameters.space_stretch or parameters[3] or 0
+ parameters.space_shrink = parameters.space_shrink or parameters[4] or 0
+ parameters.x_height = parameters.x_height or parameters[5] or 0
+ parameters.quad = parameters.quad or parameters[6] or 0
+ parameters.extra_space = parameters.extra_space or parameters[7] or 0
+ --
+ constructors.enhanceparameters(parameters) -- official copies for us
+ --
+ properties.private = properties.private or tfmdata.private or privateoffset
+ --
+ if newtfmdata then
--
- depth[filename] = depth[filename] - 1
+ -- We do nothing as we assume flat tfm files. It would become real messy
+ -- otherwise and I don't have something for testing on my system anyway.
--
- return tfmdata
else
- depth[filename] = depth[filename] - 1
+ -- already loaded
+ local fonts = tfmdata.fonts
+ if fonts then
+ for i=1,#fonts do
+ local font = fonts[i]
+ local id = font.id
+ if not id then
+ local name = font.name
+ local size = font.size
+ if name and size then
+ local data, id = constructors.readanddefine(name,size)
+ if id then
+ font.id = id
+ font.name = nil
+ font.size = nil
+ end
+ end
+ end
+ end
+ end
end
+ --
+ properties.haskerns = true
+ properties.hasligatures = true
+ properties.hasitalics = true
+ resources.unicodes = { }
+ resources.lookuptags = { }
+ --
+ depth[filename] = depth[filename] - 1
+ --
+ return tfmdata
+ else
+ depth[filename] = depth[filename] - 1
end
+end
- check_tfm = function(specification,fullname) -- we could split up like afm/otf
- local foundname = findbinfile(fullname, 'tfm') or ""
- if foundname == "" then
- foundname = findbinfile(fullname, 'ofm') or "" -- not needed in context
- end
- if foundname == "" then
- foundname = fonts.names.getfilename(fullname,"tfm") or ""
- end
- if foundname ~= "" then
- specification.filename = foundname
- specification.format = "ofm"
- return read_from_tfm(specification)
- elseif trace_defining then
- report_defining("loading tfm with name %a fails",specification.name)
- end
+local function check_tfm(specification,fullname) -- we could split up like afm/otf
+ local foundname = findbinfile(fullname, 'tfm') or ""
+ if foundname == "" then
+ foundname = findbinfile(fullname, 'ofm') or "" -- not needed in context
+ end
+ if foundname == "" then
+ foundname = fonts.names.getfilename(fullname,"tfm") or ""
+ end
+ if foundname ~= "" then
+ specification.filename = foundname
+ specification.format = "ofm"
+ return read_from_tfm(specification)
+ elseif trace_defining then
+ report_defining("loading tfm with name %a fails",specification.name)
end
-
end
readers.check_tfm = check_tfm
@@ -437,7 +389,7 @@ do
return
end
- local pfbfile = outfiles[tfmfile]
+ local pfbfile = pfbfile or outfiles[tfmfile]
if pfbfile == nil then
if bitmap then
@@ -458,7 +410,6 @@ do
local encoding = false
local vector = false
-
if type(pfbfile) == "string" then
local pfb = constructors.handlers.pfb
if pfb and pfb.loadvector then
@@ -490,17 +441,18 @@ do
local indices = { }
local parentfont = { "font", 1 }
local private = tfmdata.privateoffset or constructors.privateoffset
- local reported = encdone[tfmfile][encfile]
-
+ local reported = encdone[tfmfile][encfile] -- bah, encdone for tfm or pfb ?
-- create characters table
+ -- vector : pfbindex -> name
+ -- encoding : tfmindex -> name
+
local backmap = vector and table.swapped(vector)
local done = { } -- prevent duplicate
-
- for index, name in sortedhash(encoding) do -- predictable order
- local unicode = unicoding[name]
- local original = originals[index]
+ for tfmindex, name in sortedhash(encoding) do -- predictable order
+ local original = originals[tfmindex]
if original then
+ local unicode = unicoding[name]
if unicode then
original.unicode = unicode
else
@@ -511,17 +463,17 @@ do
end
end
characters[unicode] = original
- indices[index] = unicode
+ indices[tfmindex] = unicode
original.name = name -- so one can lookup weird names
if backmap then
- original.index = backmap[name]
+ original.index = backmap[name] -- the pfb index
else -- probably bitmap
- original.commands = { parentfont, charcommand[index] } -- or "slot"
- original.oindex = index
+ original.commands = { parentfont, charcommand[tfmindex] } -- or "slot"
+ original.oindex = tfmindex
end
done[name] = true
elseif not done[name] then
- report_tfm("bad index %a in font %a with name %a",index,tfmfile,name)
+ report_tfm("bad index %a in font %a with name %a",tfmindex,tfmfile,name)
end
end
@@ -575,68 +527,6 @@ do
end
--- This code adds a ToUnicode vector for bitmap fonts. We don't bother about
--- ranges because we have small fonts. it works ok with acrobat but fails with
--- the other viewers (they get confused by the bitmaps I guess).
-
-do
-
- local template = [[
-/CIDInit /ProcSet findresource begin
- 12 dict begin
- begincmap
- /CIDSystemInfo << /Registry (TeX) /Ordering (bitmap-%s) /Supplement 0 >> def
- /CMapName /TeX-bitmap-%s def
- /CMapType 2 def
- 1 begincodespacerange
- <00> <FF>
- endcodespacerange
- %s beginbfchar
-%s
- endbfchar
- endcmap
-CMapName currentdict /CMap defineresource pop end
-end
-end
-]]
-
- local flushstreamobject = lpdf and lpdf.flushstreamobject -- context
- local setfontattributes = lpdf and lpdf.setfontattributes -- context
-
- if not flushstreamobject then
- flushstreamobject = function(data)
- return pdf.obj { immediate = true, type = "stream", string = data } -- generic
- end
- end
-
- if not setfontattributes then
- setfontattributes = function(id,data)
- return pdf.setfontattributes(id,data) -- generic
- end
- end
-
- function tfm.addtounicode(tfmdata)
- local id = tfmdata.usedbitmap
- local map = { }
- local char = { } -- no need for range, hardly used
- for k, v in next, tfmdata.characters do
- local index = v.oindex
- local tounicode = v.tounicode
- if index and tounicode then
- map[index] = tounicode
- end
- end
- for k, v in sortedhash(map) do
- char[#char+1] = format("<%02X> <%s>",k,v)
- end
- char = concat(char,"\n")
- local stream = format(template,id,id,#char,char)
- local reference = flushstreamobject(stream,nil,true)
- setfontattributes(id,format("/ToUnicode %i 0 R",reference))
- end
-
-end
-
-- Now we implement the regular features handlers. We need to convert the
-- tfm specific structures to opentype structures. In basemode they are
-- converted back so that is a bit of a waste but it's fast enough.
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-tpk.lua b/Master/texmf-dist/tex/context/base/mkiv/font-tpk.lua
new file mode 100644
index 00000000000..05ecdd45ce1
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-tpk.lua
@@ -0,0 +1,1304 @@
+ if not modules then modules = { } end modules ['font-tpk'] = {
+ version = 1.001,
+ comment = "companion to font-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- The bitmap loader is more or less derived from the luatex version (taco)
+-- which is derived from pdftex (thanh) who uses code from dvips (thomas)
+-- adapted by piet ... etc. The tfm and vf readers are also derived from
+-- luatex. All do things a bit more luaish and errors are of course mine.
+
+local next = next
+local extract, band, lshift, rshift = bit32.extract, bit32.band, bit32.lshift, bit32.rshift
+local idiv = number.idiv
+local char = string.char
+local concat, insert, remove, copy = table.concat, table.insert, table.remove, table.copy
+local tobitstring = number.tobitstring
+local formatters = string.formatters
+local round = math.round
+
+local streams = utilities.streams
+local openstream = streams.open
+local streamsize = streams.size
+local readcardinal1 = streams.readcardinal1
+local readcardinal2 = streams.readcardinal2
+local readcardinal3 = streams.readcardinal3
+local readcardinal4 = streams.readcardinal4
+local readinteger1 = streams.readinteger1
+local readinteger2 = streams.readinteger2
+local readinteger3 = streams.readinteger3
+local readinteger4 = streams.readinteger4
+local readbyte = streams.readbyte
+local readbytes = streams.readbytes
+local readstring = streams.readstring
+local skipbytes = streams.skipbytes
+local getposition = streams.getposition
+local setposition = streams.setposition
+
+if not fonts then fonts = { handlers = { tfm = { } } } end
+
+local handlers = fonts.handlers
+local tfm = handlers.tfm or { }
+handlers.tfm = tfm
+local readers = tfm.readers or { }
+tfm.readers = readers
+
+tfm.version = 1.005
+tfm.cache = containers.define("fonts", "tfm", tfm.version, true)
+
+-- Performance is no real issue here so I didn't optimize too much. After
+-- all, these files are small and we mostly use opentype or type1 fonts.
+
+do
+
+ local function readbitmap(glyph,s,flagbyte)
+
+ local inputbyte = 0
+ local bitweight = 0
+ local dynf = 0
+ local remainder = 0
+ local realfunc = nil
+ local repeatcount = 0
+
+ local function getnyb() -- can be inlined
+ if bitweight == 0 then
+ bitweight = 16
+ inputbyte = readbyte(s)
+ return extract(inputbyte,4,4)
+ else
+ bitweight = 0
+ return band(inputbyte,15)
+ end
+ end
+
+ local function getbit() -- can be inlined
+ bitweight = rshift(bitweight,1)
+ if bitweight == 0 then -- actually we can check for 1
+ inputbyte = readbyte(s)
+ bitweight = 128
+ end
+ return band(inputbyte,bitweight)
+ end
+
+ local function pkpackednum()
+ local i = getnyb(s)
+ if i == 0 then
+ repeat
+ j = getnyb()
+ i = i + 1
+ until (j ~= 0)
+ if i > 3 then
+ return handlehuge(i,j)
+ else
+ for i=1,i do
+ j = j * 16 + getnyb()
+ end
+ return j - 15 + (13 - dynf) * 16 + dynf
+ end
+ elseif i <= dynf then
+ return i
+ elseif i < 14 then
+ return (i - dynf - 1) * 16 + getnyb() + dynf + 1
+ elseif i == 14 then
+ repeatcount = pkpackednum()
+ else
+ repeatcount = 1
+ end
+ return realfunc()
+ end
+
+ local function rest()
+ if remainder < 0 then
+ remainder = -remainder
+ return 0
+ elseif remainder > 4000 then
+ remainder = 4000 - remainder
+ return 4000
+ elseif remainder > 0 then
+ local i = remainder
+ remainder = 0
+ realfunc = pkpackednum
+ return i
+ else
+ -- error = "pk issue that shouldn't happen"
+ return 0
+ end
+ end
+
+ local function handlehuge(i,j)
+ while i ~= 0 do
+ j = lshift(j,4) + getnyb()
+ -- j = extract(j,8,4) + getnyb()
+ i = i - 1
+ end
+ remainder = j - 15 + (13 - dynf) * 16 + dynf
+ realfunc = rest
+ return rest()
+ end
+
+ local gpower = { [0] =
+ 0, 1, 3, 7, 15, 31, 63, 127,
+ 255, 511, 1023, 2047, 4095, 8191, 16383, 32767,
+ 65535
+ }
+
+ local raster = { }
+ local r = 0
+ glyph.stream = raster
+
+ local xsize = glyph.xsize
+ local ysize = glyph.ysize
+ local word = 0
+ local wordweight = 0
+ local wordwidth = idiv(xsize + 15,16)
+ local rowsleft = 0
+ local turnon = band(flagbyte,8) == 8 and true or false
+ local hbit = 0
+ local count = 0
+ --
+ realfunc = pkpackednum
+ dynf = idiv(flagbyte,16)
+ --
+ if dynf == 14 then
+ bitweight = 0
+ for i=1,ysize do
+ word = 0
+ wordweight = 32768
+ for j=1,xsize do
+ if getbit() ~= 0 then
+ word = word + wordweight
+ end
+ wordweight = rshift(wordweight,1)
+ if wordweight == 0 then
+ r = r + 1
+ raster[r] = word
+ word = 0
+ wordweight = 32768
+ end
+ end
+ if wordweight ~= 32768 then
+ r = r + 1
+ raster[r] = word
+ end
+ end
+ else
+ rowsleft = ysize
+ hbit = xsize
+ repeatcount = 0
+ wordweight = 16
+ word = 0
+ bitweight = 0
+ while rowsleft > 0 do
+ count = realfunc()
+ while count ~= 0 do
+ if count < wordweight and count < hbit then
+ if turnon then
+ word = word + gpower[wordweight] - gpower[wordweight - count]
+ end
+ hbit = hbit - count
+ wordweight = wordweight - count
+ count = 0
+ elseif count >= hbit and hbit <= wordweight then
+ if turnon then
+ word = word + gpower[wordweight] - gpower[wordweight - hbit]
+ end
+ r = r + 1
+ raster[r] = word
+ for i=1,repeatcount*wordwidth do
+ r = r + 1
+ raster[r] = raster[r - wordwidth]
+ end
+ rowsleft = rowsleft - repeatcount - 1
+ repeatcount = 0
+ word = 0
+ wordweight = 16
+ count = count - hbit
+ hbit = xsize
+ else
+ if turnon then
+ word = word + gpower[wordweight]
+ end
+ r = r + 1
+ raster[r] = word
+ word = 0
+ count = count - wordweight
+ hbit = hbit - wordweight
+ wordweight = 16
+ end
+ end
+ turnon = not turnon
+ end
+ if rowsleft ~= 0 or hbit ~= xsize then
+ print("ERROR",rowsleft,hbit,xsize)
+ -- error = "error while unpacking, more bits than required"
+ end
+ end
+
+ end
+
+ function readers.showpk(glyph)
+ local xsize = glyph.xsize
+ local ysize = glyph.ysize
+ local stream = glyph.stream
+ local result = { }
+ local rr = { }
+ local r = 0
+ local s = 0
+ local cw = idiv(xsize+ 7, 8)
+ local rw = idiv(xsize+15,16)
+ local extra = 2 * rw == cw
+ local b
+ for y=1,ysize do
+ r = 0
+ for x=1,rw-1 do
+ s = s + 1 ; b = stream[s]
+ r = r + 1 ; rr[r] = tobitstring(b,16,16)
+ end
+ s = s + 1 ; b = stream[s]
+ if extra then
+ r = r + 1 ; rr[r] = tobitstring(b,16,16)
+ else
+ r = r + 1 ; rr[r] = tobitstring(extract(b,8+(8-cw),cw),cw,cw)
+ end
+ result[y] = concat(rr)
+ end
+ return concat(result,"\n")
+ end
+
+ local template = formatters [ [[
+%.3N 0 %i %i %i %i d1
+q
+%i 0 0 %i %i %i cm
+BI
+ /W %i
+ /H %i
+ /IM true
+ /BPC 1
+ /D [1 0]
+ID %t
+EI
+Q]] ]
+
+ function readers.pktopdf(glyph,data,factor)
+ local width = data.width * factor
+ local xsize = glyph.xsize or 0
+ local ysize = glyph.ysize or 0
+ local xoffset = glyph.xoffset or 0
+ local yoffset = glyph.yoffset or 0
+ local stream = glyph.stream
+
+ local dpi = 1
+ local newdpi = 1
+
+ local xdpi = dpi * xsize / newdpi
+ local ydpi = dpi * ysize / newdpi
+
+ local llx = - xoffset
+ local lly = yoffset - ysize + 1
+ local urx = llx + xsize + 1
+ local ury = lly + ysize
+
+ local result = { }
+ local r = 0
+ local s = 0
+ local cw = idiv(xsize+ 7, 8)
+ local rw = idiv(xsize+15,16)
+ local extra = 2 * rw == cw
+ local b
+ for y=1,ysize do
+ for x=1,rw-1 do
+ s = s + 1 ; b = stream[s]
+ r = r + 1 ; result[r] = char(extract(b,8,8),extract(b,0,8))
+ end
+ s = s + 1 ; b = stream[s]
+ if extra then
+ r = r + 1 ; result[r] = char(extract(b,8,8),extract(b,0,8))
+ else
+ r = r + 1 ; result[r] = char(extract(b,8,8))
+ end
+ end
+ return template(width,llx,lly,urx,ury,xdpi,ydpi,llx,lly,xsize,ysize,result), width
+ end
+
+ function readers.loadpk(filename)
+ local s = openstream(filename)
+ local preamble = readcardinal1(s)
+ local version = readcardinal1(s)
+ local comment = readstring(s,readcardinal1(s))
+ local designsize = readcardinal4(s)
+ local checksum = readcardinal4(s)
+ local hppp = readcardinal4(s)
+ local vppp = readcardinal4(s)
+ if preamble ~= 247 or version ~= 89 or not vppp then
+ return { error = "invalid preamble" }
+ end
+ local glyphs = { }
+ local data = {
+ designsize = designsize,
+ comment = comment,
+ hppp = hppp,
+ vppp = vppp,
+ glyphs = glyphs,
+ }
+ while true do
+ local flagbyte = readcardinal1(s)
+ if flagbyte < 240 then
+ local c = band(flagbyte,7)
+ local length, index, width, pixels, xsize, ysize, xoffset, yoffset
+ if c >= 0 and c <= 3 then
+ length = band(flagbyte,7) * 256 + readcardinal1(s) - 3
+ index = readcardinal1(s)
+ width = readinteger3(s)
+ pixels = readcardinal1(s)
+ xsize = readcardinal1(s)
+ ysize = readcardinal1(s)
+ xoffset = readcardinal1(s)
+ yoffset = readcardinal1(s)
+ if xoffset > 127 then
+ xoffset = xoffset - 256
+ end
+ if yoffset > 127 then
+ yoffset = yoffset - 256
+ end
+ elseif c >= 4 and c <= 6 then
+ length = band(flagbyte,3) * 65536 + readcardinal1(s) * 256 + readcardinal1(s) - 4
+ index = readcardinal1(s)
+ width = readinteger3(s)
+ pixels = readcardinal2(s)
+ xsize = readcardinal2(s)
+ ysize = readcardinal2(s)
+ xoffset = readcardinal2(s)
+ yoffset = readcardinal2(s)
+ else -- 7
+ length = readcardinal4(s) - 9
+ index = readcardinal4(s)
+ width = readinteger4(s)
+ pixels = readcardinal4(s)
+ readcardinal4(s)
+ xsize = readcardinal4(s)
+ ysize = readcardinal4(s)
+ xoffset = readcardinal4(s)
+ yoffset = readcardinal4(s)
+ end
+ local glyph = {
+ index = index,
+ width = width,
+ pixels = pixels,
+ xsize = xsize,
+ ysize = ysize,
+ xoffset = xoffset,
+ yoffset = yoffset,
+ }
+ if length <= 0 then
+ data.error = "bad packet"
+ return data
+ end
+ readbitmap(glyph,s,flagbyte)
+ glyphs[index] = glyph
+ elseif flagbyte == 240 then
+ -- k[1] x[k]
+ skipbytes(s,readcardinal1(s))
+ elseif flagbyte == 241 then
+ -- k[2] x[k]
+ skipbytes(s,readcardinal2(s)*2)
+ elseif flagbyte == 242 then
+ -- k[3] x[k]
+ skipbytes(s,readcardinal3(s)*3)
+ elseif flagbyte == 243 then
+ -- k[4] x[k]
+ skipbytes(s,readcardinal4(s)*4) -- readinteger4
+ elseif flagbyte == 244 then
+ -- y[4]
+ skipbytes(s,4)
+ elseif flagbyte == 245 then
+ break
+ elseif flagbyte == 246 then
+ -- nop
+ else
+ data.error = "unknown pk command"
+ break
+ end
+ end
+ return data
+ end
+
+end
+
+do
+
+ local leftboundary = -1
+ local rightboundary = -2
+ local boundarychar = 65536
+
+ function readers.loadtfm(filename)
+ local data
+ --
+ local function someerror(m)
+ if not data then
+ data = { }
+ end
+ data.error = m or "fatal error"
+ return data
+ end
+ --
+ local s = openstream(filename)
+ if not s then
+ return someerror()
+ end
+ --
+ local wide = false
+ local header = 0
+ local max = 0
+ local size = streamsize(s)
+ local glyphs = table.setmetatableindex(function(t,k)
+ local v = {
+ -- we default because boundary chars have no dimension s
+ width = 0,
+ height = 0,
+ depth = 0,
+ italic = 0,
+ }
+ t[k] = v
+ return v
+ end)
+ local parameters = { }
+ local direction = 0
+ --
+ local lf, lh, bc, ec, nw, nh, nd, ni, nl, nk, ne, np
+ --
+ lf = readcardinal2(s)
+ if lf ~= 0 then
+ header = 6
+ max = 255
+ wide = false
+ lh = readcardinal2(s)
+ bc = readcardinal2(s)
+ ec = readcardinal2(s)
+ nw = readcardinal2(s)
+ nh = readcardinal2(s)
+ nd = readcardinal2(s)
+ ni = readcardinal2(s)
+ nl = readcardinal2(s)
+ nk = readcardinal2(s)
+ ne = readcardinal2(s)
+ np = readcardinal2(s)
+ else
+ header = 14
+ max = 65535
+ wide = readcardinal4(s) == 0
+ if not wide then
+ return someerror("invalid format")
+ end
+ lf = readcardinal4(s)
+ lh = readcardinal4(s)
+ bc = readcardinal4(s)
+ ec = readcardinal4(s)
+ nw = readcardinal4(s)
+ nh = readcardinal4(s)
+ nd = readcardinal4(s)
+ ni = readcardinal4(s)
+ nl = readcardinal4(s)
+ nk = readcardinal4(s)
+ ne = readcardinal4(s)
+ np = readcardinal4(s)
+ direction = readcardinal4(s)
+ end
+ if (bc > ec + 1) or (ec > max) then
+ return someerror("file is too small")
+ end
+ if bc > max then
+ bc, ec = 1, 0
+ end
+ local nlw = (wide and 2 or 1) * nl
+ local neew = (wide and 2 or 1) * ne
+ local ncw = (wide and 2 or 1) * (ec - bc + 1)
+ if lf ~= (header + lh + ncw + nw + nh + nd + ni + nlw + nk + neew + np) then
+ return someerror("file is too small")
+ end
+ if nw == 0 or nh == 0 or nd == 0 or ni == 0 then
+ return someerror("no glyphs")
+ end
+ if lf * 4 > size then
+ return someerror("file is too small")
+ end
+ local slh = lh
+ if lh < 2 then
+ return someerror("file is too small")
+ end
+ local checksum = readcardinal4(s)
+ local designsize = readcardinal2(s)
+ designsize = designsize * 256 + readcardinal1(s)
+ designsize = designsize * 16 + rshift(readcardinal1(s),4)
+ if designsize < 0xFFFF then
+ return someerror("weird designsize")
+ end
+ --
+ local alpha = 16
+ local z = designsize
+ while z >= 040000000 do
+ z = rshift(z,1)
+ alpha = alpha + alpha
+ end
+ local beta = idiv(256,alpha)
+ alpha = alpha * z
+ --
+ local function readscaled()
+ local a, b, c, d = readbytes(s,4)
+ local n = idiv(rshift(rshift(d*z,8)+c*z,8)+b*z,beta)
+ if a == 0 then
+ return n
+ elseif a == 255 then
+ return n - alpha
+ else
+ return 0
+ end
+ end
+ --
+ local function readunscaled()
+ local a, b, c, d = readbytes(s,4)
+ if a > 127 then
+ a = a - 256
+ end
+ return a * 0xFFFFF + b * 0xFFF + c * 0xF + rshift(d,4)
+ end
+ --
+ while lh > 2 do -- can be one-liner
+ skipbytes(s,4)
+ lh = lh - 1
+ end
+ local saved = getposition(s)
+ setposition(s,(header + slh + ncw) * 4 + 1)
+ local widths = { } for i=0,nw-1 do widths [i] = readscaled() end
+ local heights = { } for i=0,nh-1 do heights[i] = readscaled() end
+ local depths = { } for i=0,nd-1 do depths [i] = readscaled() end
+ local italics = { } for i=0,ni-1 do italics[i] = readscaled() end
+ if widths[0] ~= 0 or heights[0] ~= 0 or depths[0] ~= 0 then
+ return someerror("invalid dimensions")
+ end
+ --
+ local blabel = nl
+ local bchar = boundarychar
+ --
+ local ligatures = { }
+ if nl > 0 then
+ for i=0,nl-1 do
+ local a, b, c, d = readbytes(s,4)
+ ligatures[i] = {
+ skip = a,
+ nxt = b,
+ op = c,
+ rem = d,
+ }
+ if a > 128 then
+ if 256 * c + d >= nl then
+ return someerror("invalid ligature table")
+ end
+ if a == 255 and i == 0 then
+ bchar = b
+ end
+ else
+ if c < 128 then
+ -- whatever
+ elseif 256 * (c - 128) + d >= nk then
+ return someerror("invalid ligature table")
+ end
+ if (a < 128) and (i - 0 + a + 1 >= nl) then
+ return someerror("invalid ligature table")
+ end
+ end
+ if a == 255 then
+ blabel = 256 * c + d
+ end
+ end
+ end
+ local allkerns = { }
+ for i=0,nk-1 do
+ allkerns[i] = readscaled()
+ end
+ local extensibles = { }
+ for i=0,ne-1 do
+ extensibles[i] = wide and {
+ top = readcardinal2(s),
+ bot = readcardinal2(s),
+ mid = readcardinal2(s),
+ rep = readcardinal2(s),
+ } or {
+ top = readcardinal1(s),
+ bot = readcardinal1(s),
+ mid = readcardinal1(s),
+ rep = readcardinal1(s),
+ }
+ end
+ for i=1,np do
+ if i == 1 then
+ parameters[i] = readunscaled()
+ else
+ parameters[i] = readscaled()
+ end
+ end
+ for i=1,7 do
+ if not parameters[i] then
+ parameters[i] = 0
+ end
+ end
+ --
+ setposition(s,saved)
+ local extras = false
+ if blabel ~= nl then
+ local k = blabel
+ while true do
+ local l = ligatures[k]
+ local skip = l.skip
+ if skip <= 128 then
+ -- if l.op >= 128 then
+ -- extras = true -- kern
+ -- else
+ extras = true -- ligature
+ -- end
+ end
+ if skip == 0 then
+ k = k + 1
+ else
+ if skip >= 128 then
+ break
+ end
+ k = k + skip + 1
+ end
+ end
+ end
+ if extras then
+ local ligas = { }
+ local kerns = { }
+ local k = blabel
+ while true do
+ local l = ligatures[k]
+ local skip = l.skip
+ if skip <= 128 then
+ local nxt = l.nxt
+ local op = l.op
+ local rem = l.rem
+ if op >= 128 then
+ kerns[nxt] = allkerns[256 * (op - 128) + rem]
+ else
+ ligas[nxt] = { type = op * 2 + 1, char = rem }
+ end
+ end
+ if skip == 0 then
+ k = k + 1
+ else
+ if skip >= 128 then
+ break;
+ end
+ k = k + skip + 1
+ end
+ end
+ if next(kerns) then
+ local glyph = glyphs[leftboundary]
+ glyph.kerns = kerns
+ glyph.remainder = 0
+ end
+ if next(ligas) then
+ local glyph = glyphs[leftboundary]
+ glyph.ligatures = ligas
+ glyph.remainder = 0
+ end
+ end
+ for i=bc,ec do
+ local glyph, width, height, depth, italic, tag, remainder
+ if wide then
+ width = readcardinal2(s)
+ height = readcardinal1(s)
+ depth = readcardinal1(s)
+ italic = readcardinal1(s)
+ tag = readcardinal1(s)
+ remainder = readcardinal2(s)
+ else
+ width = readcardinal1(s)
+ height = readcardinal1(s)
+ depth = extract(height,0,4)
+ height = extract(height,4,4)
+ italic = readcardinal1(s)
+ tag = extract(italic,0,2)
+ italic = extract(italic,2,6)
+ remainder = readcardinal1(s)
+ end
+ if width == 0 then
+ -- nothing
+ else
+ if width >= nw or height >= nh or depth >= nd or italic >= ni then
+ return someerror("invalid dimension index")
+ end
+ local extensible, nextinsize
+ if tag == 0 then
+ -- nothing special
+ else
+ local r = remainder
+ if tag == 1 then
+ if r >= nl then
+ return someerror("invalid ligature index")
+ end
+ elseif tag == 2 then
+ if r < bc or r > ec then
+ return someerror("invalid chain index")
+ end
+ while r < i do
+ local g = glyphs[r]
+ if g.tag ~= list_tag then
+ break
+ end
+ r = g.remainder
+ end
+ if r == i then
+ return someerror("cycles in chain")
+ end
+ nextinsize = r
+ elseif tag == 3 then
+ if r >= ne then
+ return someerror("bad extensible")
+ end
+ extensible = extensibles[r] -- remainder ?
+ remainder = 0
+ end
+ end
+ glyphs[i] = {
+ width = widths [width],
+ height = heights[height],
+ depth = depths [depth],
+ italic = italics[italic],
+ tag = tag,
+ -- index = i,
+ remainder = remainder,
+ extensible = extensible,
+ next = nextinsize,
+ }
+ end
+ end
+ for i=bc,ec do
+ local glyph = glyphs[i]
+ if glyph.tag == 1 then
+ -- ligature
+ local k = glyph.remainder
+ local l = ligatures[k]
+ if l.skip > 128 then
+ k = 256 * l.op + l.rem
+ end
+ local ligas = { }
+ local kerns = { }
+ while true do
+ local l = ligatures[k]
+ local skip = l.skip
+ if skip <= 128 then
+ local nxt = l.nxt
+ local op = l.op
+ local rem = l.rem
+ if op >= 128 then
+ local kern = allkerns[256 * (op - 128) + rem]
+ if nxt == bchar then
+ kerns[rightboundary] = kern
+ end
+ kerns[nxt] = kern
+ else
+ local ligature = { type = op * 2 + 1, char = rem }
+ if nxt == bchar then
+ ligas[rightboundary] = ligature
+ end
+ ligas[nxt] = ligature -- shared
+ end
+ end
+ if skip == 0 then
+ k = k + 1
+ else
+ if skip >= 128 then
+ break
+ end
+ k = k + skip + 1
+ end
+ end
+ if next(kerns)then
+ glyph.kerns = kerns
+ glyph.remainder = 0
+ end
+ if next(ligas) then
+ glyph.ligatures = ligas
+ glyph.remainder = 0
+ end
+ end
+ end
+ --
+ if bchar ~= boundarychar then
+ glyphs[rightboundary] = copy(glyphs[bchar])
+ end
+ --
+ -- for k, v in next, glyphs do
+ -- v.tag = nil
+ -- v.remainder = nil
+ -- end
+ --
+ return {
+ name = file.nameonly(filename),
+ fontarea = file.pathpart(filename),
+ glyphs = glyphs,
+ parameters = parameters,
+ designsize = designsize,
+ size = designsize,
+ direction = direction,
+ -- checksum = checksum,
+ -- embedding = "unknown",
+ -- encodingbytes = 0,
+ -- extend = 1000,
+ -- slant = 0,
+ -- squeeze = 0,
+ -- format = "unknown",
+ -- identity = "unknown",
+ -- mode = 0,
+ -- streamprovider = 0,
+ -- tounicode = 0,
+ -- type = "unknown",
+ -- units_per_em = 0,
+ -- used = false,
+ -- width = 0,
+ -- writingmode = "unknown",
+ }
+ end
+
+end
+
+do
+
+ local push = { "push" }
+ local push = { "pop" }
+
+ local w, x, y, z, f
+ local stack
+ local s, result, r
+ local alpha, beta, z
+
+ local function scaled1()
+ local a = readbytes(s,1)
+ if a == 0 then
+ return 0
+ elseif a == 255 then
+ return - alpha
+ else
+ return 0 -- error
+ end
+ end
+
+ local function scaled2()
+ local a, b = readbytes(s,2)
+ local sw = idiv(b*z,beta)
+ if a == 0 then
+ return sw
+ elseif a == 255 then
+ return sw - alpha
+ else
+ return 0 -- error
+ end
+ end
+
+ local function scaled3()
+ local a, b, c = readbytes(s,3)
+ local sw = idiv(rshift(c*z,8)+b*z,beta)
+ if a == 0 then
+ return sw
+ elseif a == 255 then
+ return sw - alpha
+ else
+ return 0 -- error
+ end
+ end
+
+ local function scaled4()
+ local a, b, c, d = readbytes(s,4)
+ local sw = idiv( rshift(rshift(d*z,8)+(c*z),8)+b*z,beta)
+ if a == 0 then
+ return sw
+ elseif a == 255 then
+ return sw - alpha
+ else
+ return 0 -- error
+ end
+ end
+
+ local function dummy()
+ end
+
+ local actions = {
+
+ [128] = function() r = r + 1 result[r] = { "slot", f or 1, readcardinal1(s) } p = p + 1 end,
+ [129] = function() r = r + 1 result[r] = { "slot", f or 1, readcardinal2(s) } p = p + 2 end,
+ [130] = function() r = r + 1 result[r] = { "slot", f or 1, readcardinal3(s) } p = p + 3 end,
+ [131] = function() r = r + 1 result[r] = { "slot", f or 1, readcardinal4(s) } p = p + 4 end,
+
+ [132] = function()
+ r = r + 1
+ result[r] = { "rule", scaled4(), scaled4() }
+ p = p + 8
+ end,
+
+ [133] = function()
+ r = r + 1 result[r] = push
+ r = r + 1 result[r] = { "slot", f or 1, readcardinal1(s) }
+ r = r + 1 result[r] = pop
+ p = p + 1
+ end,
+ [134] = function()
+ r = r + 1 result[r] = push
+ r = r + 1 result[r] = { "slot", f or 1, readcardinal2(s) }
+ r = r + 1 result[r] = pop
+ p = p + 2
+ end,
+ [135] = function()
+ r = r + 1 result[r] = push
+ r = r + 1 result[r] = { "slot", f or 1, readcardinal2(s) }
+ r = r + 1 result[r] = pop
+ p = p + 3
+ end,
+ [136] = function()
+ r = r + 1 result[r] = push
+ r = r + 1 result[r] = { "slot", f or 1, readcardinal4(s) }
+ r = r + 1 result[r] = pop
+ p = p + 4
+ end,
+
+ [137] = function()
+ r = r + 1 result[r] = push
+ r = r + 1 result[r] = { "rule", scaled4(), scaled4() }
+ r = r + 1 result[r] = pop
+ p = p + 8
+ end,
+
+ [138] = dummy, -- nop
+ [139] = dummy, -- bop
+ [140] = dummy, -- eop
+
+ [141] = function()
+ insert(stack, { w, x, y, z })
+ r = r + 1
+ result[r] = push
+ end,
+ [142] = function()
+ local t = remove(stack)
+ if t then
+ w, x, y, z = t[1], t[2], t[3], t[4]
+ r = r + 1
+ result[r] = pop
+ end
+ end,
+
+ [143] = function() r = r + 1 result[r] = { "right", scaled1() } p = p + 1 end,
+ [144] = function() r = r + 1 result[r] = { "right", scaled2() } p = p + 2 end,
+ [145] = function() r = r + 1 result[r] = { "right", scaled3() } p = p + 3 end,
+ [146] = function() r = r + 1 result[r] = { "right", scaled4() } p = p + 4 end,
+
+ [148] = function() w = scaled1() r = r + 1 result[r] = { "right", w } p = p + 1 end,
+ [149] = function() w = scaled2() r = r + 1 result[r] = { "right", w } p = p + 2 end,
+ [150] = function() w = scaled3() r = r + 1 result[r] = { "right", w } p = p + 3 end,
+ [151] = function() w = scaled4() r = r + 1 result[r] = { "right", w } p = p + 4 end,
+
+ [153] = function() x = scaled1() r = r + 1 result[r] = { "right", x } p = p + 1 end,
+ [154] = function() x = scaled2() r = r + 1 result[r] = { "right", x } p = p + 2 end,
+ [155] = function() x = scaled3() r = r + 1 result[r] = { "right", x } p = p + 3 end,
+ [156] = function() x = scaled4() r = r + 1 result[r] = { "right", x } p = p + 4 end,
+
+ [157] = function() r = r + 1 result[r] = { "down", scaled1() } p = p + 1 end,
+ [158] = function() r = r + 1 result[r] = { "down", scaled2() } p = p + 2 end,
+ [159] = function() r = r + 1 result[r] = { "down", scaled3() } p = p + 3 end,
+ [160] = function() r = r + 1 result[r] = { "down", scaled4() } p = p + 4 end,
+
+ [162] = function() y = scaled1() r = r + 1 result[r] = { "down", y } p = p + 1 end,
+ [163] = function() y = scaled2() r = r + 1 result[r] = { "down", y } p = p + 2 end,
+ [164] = function() y = scaled3() r = r + 1 result[r] = { "down", y } p = p + 3 end,
+ [165] = function() y = scaled3() r = r + 1 result[r] = { "down", y } p = p + 4 end,
+
+ [167] = function() z = scaled1() r = r + 1 ; result[r] = { "down", z } p = p + 4 end,
+ [168] = function() z = scaled2() r = r + 1 ; result[r] = { "down", z } p = p + 4 end,
+ [169] = function() z = scaled3() r = r + 1 ; result[r] = { "down", z } p = p + 4 end,
+ [170] = function() z = scaled4() r = r + 1 ; result[r] = { "down", z } p = p + 4 end,
+
+ [147] = function() r = r + 1 result[r] = { "right", w } end,
+ [152] = function() r = r + 1 result[r] = { "right", x } end,
+ [161] = function() r = r + 1 result[r] = { "down", y } end,
+ [166] = function() r = r + 1 result[r] = { "down", z } end,
+
+ [235] = function() f = readcardinal1(s) p = p + 1 end,
+ [236] = function() f = readcardinal2(s) p = p + 3 end,
+ [237] = function() f = readcardinal3(s) p = p + 3 end,
+ [238] = function() f = readcardinal4(s) p = p + 4 end,
+
+ [239] = function() local n = readcardinal1(s) r = r + 1 result[r] = { "special", readstring(s,n) } p = p + 1 + n end,
+ [240] = function() local n = readcardinal2(s) r = r + 1 result[r] = { "special", readstring(s,n) } p = p + 2 + n end,
+ [241] = function() local n = readcardinal3(s) r = r + 1 result[r] = { "special", readstring(s,n) } p = p + 3 + n end,
+ [242] = function() local n = readcardinal4(s) r = r + 1 result[r] = { "special", readstring(s,n) } p = p + 4 + n end,
+
+ [250] = function() local n = readcardinal1(s) r = r + 1 result[r] = { "pdf", readstring(s,n) } p = p + 1 + n end,
+ [251] = function() local n = readcardinal2(s) r = r + 1 result[r] = { "pdf", readstring(s,n) } p = p + 2 + n end,
+ [252] = function() local n = readcardinal3(s) r = r + 1 result[r] = { "pdf", readstring(s,n) } p = p + 3 + n end,
+ [253] = function() local n = readcardinal4(s) r = r + 1 result[r] = { "pdf", readstring(s,n) } p = p + 4 + n end,
+
+ }
+
+ table.setmetatableindex(actions,function(t,cmd)
+ local v
+ if cmd >= 0 and cmd <= 127 then
+ v = function()
+ if f == 0 then
+ f = 1
+ end
+ r = r + 1 ; result[r] = { "slot", f, cmd }
+ end
+ elseif cmd >= 171 and cmd <= 234 then
+ cmd = cmd - 170
+ v = function()
+ r = r + 1 ; result[r] = { "font", cmd }
+ end
+ else
+ v = dummy
+ end
+ t[cmd] = v
+ return v
+ end)
+
+ function readers.loadvf(filename,data)
+ --
+ local function someerror(m)
+ if not data then
+ data = { }
+ end
+ data.error = m or "fatal error"
+ return data
+ end
+ --
+ s = openstream(filename)
+ if not s then
+ return someerror()
+ end
+ --
+ local cmd = readcardinal1(s)
+ if cmd ~= 247 then
+ return someerror("bad preamble")
+ end
+ cmd = readcardinal1(s)
+ if cmd ~= 202 then
+ return someerror("bad version")
+ end
+ local header = readstring(s,readcardinal1(s))
+ local checksum = readcardinal4(s)
+ local designsize = idiv(readcardinal4(s),16)
+ local fonts = data and data.fonts or { }
+ local glyphs = data and data.glyphs or { }
+ --
+ alpha = 16
+ z = designsize
+ while z >= 040000000 do
+ z = rshift(z,1)
+ alpha = alpha + alpha
+ end
+ beta = idiv(256,alpha)
+ alpha = alpha * z
+ --
+ cmd = readcardinal1(s)
+ while true do
+ local n
+ if cmd == 243 then
+ n = readcardinal1(s) + 1
+ elseif cmd == 244 then
+ n = readcardinal2(s) + 1
+ elseif cmd == 245 then
+ n = readcardinal3(s) + 1
+ elseif cmd == 246 then
+ n = readcardinal4(s) + 1
+ else
+ break
+ end
+ local checksum = skipbytes(s,4)
+ local size = scaled4()
+ local designsize = idiv(readcardinal4(s),16)
+ local pathlen = readcardinal1(s)
+ local namelen = readcardinal1(s)
+ local path = readstring(s,pathlen)
+ local name = readstring(s,namelen)
+ fonts[n] = { path = path, name = name, size = size }
+ cmd = readcardinal1(s)
+ end
+ local index = 0
+ while cmd and cmd <= 242 do
+ local width = 0
+ local length = 0
+ local checksum = 0
+ if cmd == 242 then
+ length = readcardinal4(s)
+ checksum = readcardinal4(s)
+ width = readcardinal4(s)
+ else
+ length = cmd
+ checksum = readcardinal1(s)
+ width = readcardinal3(s)
+ end
+ w, x, y, z, f = 0, 0, 0, 0, false
+ stack, result, r, p = { }, { }, 0, 0
+ while p < length do
+ local cmd = readcardinal1(s)
+ p = p + 1
+ actions[cmd]()
+ end
+ local glyph = glyphs[index]
+ if glyph then
+ glyph.width = width
+ glyph.commands = result
+ else
+ glyphs[index] = {
+ width = width,
+ commands = result,
+ }
+ end
+ index = index + 1
+ if #stack > 0 then
+ -- error: more pushes than pops
+ end
+ if packet_length ~= 0 then
+ -- error: invalid packet length
+ end
+ cmd = readcardinal1(s)
+ end
+ if readcardinal1(s) ~= 248 then
+ -- error: no post
+ end
+ s, result, r = nil, nil, nil
+ if data then
+ data.glyphs = data.glyphs or glyphs
+ data.fonts = data.fonts or fonts
+ return data
+ else
+ return {
+ name = file.nameonly(filename),
+ fontarea = file.pathpart(filename),
+ glyphs = glyphs,
+ designsize = designsize,
+ header = header,
+ fonts = fonts,
+ }
+ end
+ end
+
+ -- the replacement loader (not sparse):
+
+ function readers.loadtfmvf(tfmname,size)
+ local vfname = file.addsuffix(file.nameonly(tfmfile),"vf")
+ local tfmfile = tfmname
+ local vffile = resolvers.findbinfile(vfname,"ovf")
+ if tfmfile and tfmfile ~= "" then
+ if size < 0 then
+ size = idiv(65536 * -size,100)
+ end
+ local data = readers.loadtfm(tfmfile)
+ if data.error then
+ return data
+ end
+ if vffile and vffile ~= "" then
+ data = readers.loadvf(vffile,data)
+ if data.error then
+ return data
+ end
+ end
+ local designsize = data.designsize
+ local glyphs = data.glyphs
+ local parameters = data.parameters
+ local fonts = data.fonts
+ if size ~= designsize then
+ local factor = size / designsize
+ for index, glyph in next, glyphs do
+ if next(glyph) then
+ glyph.width = round(factor*glyph.width)
+ glyph.height = round(factor*glyph.height)
+ glyph.depth = round(factor*glyph.depth)
+ local italic = glyph.italic
+ if italic == 0 then
+ glyph.italic = nil
+ else
+ glyph.italic = round(factor*glyph.italic)
+ end
+ --
+ local kerns = glyph.kerns
+ if kerns then
+ for index, kern in next, kerns do
+ kerns[index] = round(factor*kern)
+ end
+ end
+ --
+ local commands = glyph.commands
+ if commands then
+ for i=1,#commands do
+ local c = commands[i]
+ local t = c[1]
+ if t == "down" or t == "right" then
+ c[2] = round(factor*c[2])
+ elseif t == "rule" then
+ c[2] = round(factor*c[2])
+ c[3] = round(factor*c[3])
+ end
+ end
+ end
+ else
+ glyphs[index] = nil
+ end
+ end
+ for i=2,30 do
+ local p = parameters[i]
+ if p then
+ parameters[i] = round(factor*p)
+ else
+ break
+ end
+ end
+ if fonts then
+ for k, v in next, fonts do
+ v.size = round(factor*v.size)
+ end
+ end
+ else
+ for index, glyph in next, glyphs do
+ if next(glyph) then
+ if glyph.italic == 0 then
+ glyph.italic = nil
+ end
+ else
+ glyphs[index] = nil
+ end
+ end
+ end
+ --
+ parameters.slant = parameters[1]
+ parameters.space = parameters[2]
+ parameters.space_stretch = parameters[3]
+ parameters.space_shrink = parameters[4]
+ parameters.x_height = parameters[5]
+ parameters.quad = parameters[6]
+ parameters.extra_space = parameters[7]
+ --
+ for i=1,7 do
+ parameters[i] = nil -- so no danger for async
+ end
+ --
+ data.characters = glyphs
+ data.glyphs = nil
+ data.size = size
+ -- we assume type1 for now ... maybe the format should be unknown
+ data.filename = tfmfile -- file.replacesuffix(tfmfile,"pfb")
+ data.format = "unknown"
+ --
+ return data
+ end
+ end
+
+end
+
+-- inspect(readers.loadtfmvf(resolvers.findfile("mi-iwonari.tfm")))
+-- inspect(readers.loadtfm(resolvers.findfile("texnansi-palatinonova-regular.tfm")))
+-- inspect(readers.loadtfm(resolvers.findfile("cmex10.tfm")))
+-- inspect(readers.loadtfm(resolvers.findfile("cmr10.tfm")))
+-- local t = readers.loadtfmvf("texnansi-lte50019.tfm")
+-- inspect(t)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-tra.mkiv b/Master/texmf-dist/tex/context/base/mkiv/font-tra.mkiv
index 205ca5ca02d..89a50c5aeb2 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-tra.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-tra.mkiv
@@ -126,7 +126,7 @@
{\otfstepspace
\doif{#3}{mark}{\underbar}{U+\hexnumber{#2}}:%
\setbox\scratchbox\hbox{\ctxlua{nodes.tracers.fontchar(#1,#2)}}%
- \ifdim\wd\scratchbox=\zeropoint
+ \ifzeropt\wd\scratchbox
\scratchwidth.125\onepoint
\scratchdistance\dimexpr(\emwidth/2-\scratchwidth)\relax
\kern\scratchdistance
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-ttf.lua b/Master/texmf-dist/tex/context/base/mkiv/font-ttf.lua
index d2fe0917c53..651ede17e21 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/font-ttf.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/font-ttf.lua
@@ -733,7 +733,15 @@ local function repackpoints(glyphs,shapes)
currentx = px
currenty = py
if lastflag == fl then
- nofflags = nofflags + 1
+ if nofflags == 255 then
+ -- This happens in koeieletters!
+ lastflag = lastflag + 0x08
+ r = r + 1 result[r] = char(lastflag,nofflags-1)
+ nofflags = 1
+ lastflag = fl
+ else
+ nofflags = nofflags + 1
+ end
else -- if > 255
if nofflags == 1 then
-- r = r + 1 result[r] = char(lastflag)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/grph-bmp.lua b/Master/texmf-dist/tex/context/base/mkiv/grph-bmp.lua
new file mode 100644
index 00000000000..e10b01aa4b6
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/grph-bmp.lua
@@ -0,0 +1,96 @@
+if not modules then modules = { } end modules ['grph-bmp'] = {
+ version = 1.001,
+ comment = "companion to grph-inc.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local random = math.random
+local context = context
+
+local report_bitmap = logs.reporter("graphics","bitmap")
+
+local bitmaps = { }
+graphics.bitmaps = bitmaps
+
+local wrapimage = images.wrap
+
+function bitmaps.new(xsize,ysize,colorspace,colordepth,mask,index)
+ if not xsize or not ysize or xsize == 0 or ysize == 0 then
+ report_bitmap("provide 'xsize' and 'ysize' larger than zero")
+ return
+ end
+ if not colorspace then
+ report_bitmap("provide 'colorspace' (1, 2, 3, 'gray', 'rgb', 'cmyk'")
+ return
+ end
+ if not colordepth then
+ report_bitmap("provide 'colordepth' (1, 2)")
+ return
+ end
+ return graphics.identifiers.bitmap {
+ colorspace = colorspace,
+ colordepth = colordepth,
+ xsize = xsize,
+ ysize = ysize,
+ mask = mask and true or nil,
+ index = index and true or nil,
+ }
+end
+
+-- function backends.codeinjections.bitmap(bitmap)
+-- return lpdf.injectors.bitmap(bitmap)
+-- end
+
+local function flush(bitmap)
+ local specification = backends.codeinjections.bitmap(bitmap)
+ if specification then
+ return wrapimage(specification)
+ end
+end
+
+bitmaps.flush = flush
+
+function bitmaps.tocontext(bitmap,width,height)
+ local bmp = flush(bitmap)
+ if bmp then
+ if type(width) == "number" then
+ width = width .. "sp"
+ end
+ if type(height) == "number" then
+ height = height .. "sp"
+ end
+ if width or height then
+ context.scale (
+ {
+ width = width,
+ height = height,
+ },
+ bmp
+ )
+ else
+ context(bmp)
+ end
+ end
+end
+
+local function placeholder(nx,ny)
+
+ local nx = nx or 8
+ local ny = ny or nx
+ local bitmap = bitmaps.new(nx,ny,"gray",1)
+ local data = bitmap.data
+
+ for i=1,ny do
+ local d = data[i]
+ for j=1,nx do
+ d[j] = random(100,199)
+ end
+ end
+
+ return lpdf.injectors.bitmap(bitmap)
+
+end
+
+bitmaps.placeholder = placeholder
diff --git a/Master/texmf-dist/tex/context/base/mkiv/grph-chk.lua b/Master/texmf-dist/tex/context/base/mkiv/grph-chk.lua
new file mode 100644
index 00000000000..ed78b856c60
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/grph-chk.lua
@@ -0,0 +1,277 @@
+if not modules then modules = { } end modules ['grph-inc'] = {
+ version = 1.001,
+ comment = "companion to grph-inc.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local xpcall, pcall = xpcall, pcall
+
+local bpfactor = number.dimenfactors.bp
+
+local report = logs.reporter("graphics")
+local report_inclusion = logs.reporter("graphics","inclusion")
+local report_bitmap = logs.reporter("graphics","bitmap")
+local report_pdf = logs.reporter("graphics","pdf")
+
+local trace_pdf = false trackers.register("graphics.pdf", function(v) trace_pdf = v end)
+
+local checkers = figures.checkers
+local genericchecker = checkers.generic
+
+local placeholder = graphics.bitmaps.placeholder
+
+-- This is an experiment. The following method uses Lua to handle the embedding
+-- using the epdf library. This feature will be used when we make the transition
+-- from the pre 1.10 epdf library (using an unsuported low level poppler api) to a
+-- new (lightweight, small and statically compiled) library. More on that later.
+--
+-- The method implemented below has the same performance as the hard coded inclusion
+-- but opens up some possibilities (like merging fonts) that I will look into some
+-- day.
+
+function checkers.pdf(data)
+ local request = data.request
+ local used = data.used
+ if request and used and not request.scanimage then
+ local image = lpdf.epdf.image
+ local openpdf = image.open
+ local closepdf = image.close
+ local querypdf = image.query
+ local copypage = image.copy
+ local pdfdoc = nil
+ local filename = nil
+ request.scanimage = function(t)
+ if pdfdoc then
+ if trace_pdf then
+ report_pdf("scan image %a",filename)
+ end
+ if not filename then
+ filename = pdfdoc.filename
+ end
+ else
+ filename = t.filename
+ if trace_pdf then
+ report_pdf("open and scan image %a",filename)
+ end
+ pdfdoc = openpdf(filename,request.userpassword,request.ownerpassword)
+ end
+ if pdfdoc then
+ --
+ local info = querypdf(pdfdoc,request.page,request.size)
+ if info then
+ local bbox = info and info.boundingbox or { 0, 0, 0, 0 }
+ local height = bbox[4] - bbox[2]
+ local width = bbox[3] - bbox[1]
+ local rotation = info.rotation or 0
+ if rotation == 90 then
+ rotation, height, width = 3, width, height
+ elseif rotation == 180 then
+ rotation = 2
+ elseif rotation == 270 then
+ rotation, height, width = 1, width, height
+ elseif rotation == 1 or rotation == 3 then
+ height, width = width, height
+ else
+ rotation = 0
+ end
+ return {
+ filename = filename,
+ -- page = 1,
+ pages = pdfdoc.nofpages,
+ width = width,
+ height = height,
+ depth = 0,
+ colordepth = 0,
+ xres = 0,
+ yres = 0,
+ xsize = width,
+ ysize = height,
+ rotation = rotation,
+ pdfdoc = pdfdoc,
+ }
+ end
+ end
+ end
+ request.copyimage = function(t)
+ if not pdfdoc then
+ pdfdoc = t.pdfdoc
+ end
+ if pdfdoc then
+ local page = request.page
+ local copied = pdfdoc.nofcopied or 0
+ if not pdfdoc.copied[page] then
+ pdfdoc.copied[page] = true
+ copied = copied + 1
+ end
+ pdfdoc.nofcopied = copied
+ if trace_pdf then
+ report_pdf("copy page %i from image %a, %i pages copied",page,filename,copied)
+ end
+ local result = copypage(pdfdoc,page,nil,request.compact,request.width,request.height,request.attr)
+ if pdfdoc.nofcopied >= pdfdoc.nofpages then
+ if trace_pdf then
+ report_pdf("closing image %a, %i pages copied",filename,copied)
+ end
+ closepdf(pdfdoc)
+ pdfdoc = nil
+ t.pdfdoc = nil
+ end
+ return result
+ else
+ -- message, should not happen as we always first scan so that reopens
+ end
+ end
+ end
+ return genericchecker(data)
+end
+
+local function wrappedidentify(identify,filename)
+ local wrapup = function() report_inclusion("fatal error reading %a",filename) end
+ local _, result = xpcall(identify,wrapup,filename)
+ if result then
+ local xsize = result.xsize or 0
+ local ysize = result.ysize or 0
+ local xres = result.xres or 0
+ local yres = result.yres or 0
+ if xres == 0 or yres == 0 then
+ xres = 300
+ yres = 300
+ end
+ result.xsize = xsize
+ result.ysize = ysize
+ result.xres = xres
+ result.yres = yres
+ result.width = result.width or ((72/xres) * xsize / bpfactor)
+ result.height = result.height or ((72/yres) * ysize / bpfactor)
+ result.depth = result.depth or 0
+ result.filename = filename
+ result.colordepth = result.colordepth or 0
+ result.colorspace = result.colorspace or 0
+ result.rotation = result.rotation or 0
+ result.orientation = result.orientation or 0
+ result.transform = result.transform or 0
+ return result
+ else
+ return { error = "fatal error" }
+ end
+end
+
+function checkers.jpg(data)
+ local request = data.request
+ local used = data.used
+ if request and used and not request.scanimage then
+ local identify = graphics.identify
+ local inject = lpdf.injectors.jpg
+ local found = false
+ request.scanimage = function(t)
+ local result = wrappedidentify(identify,t.filename)
+ found = not result.error
+ return {
+ filename = result.filename,
+ width = result.width,
+ height = result.height,
+ depth = result.depth,
+ colordepth = result.colordepth,
+ xres = result.xres,
+ yres = result.yres,
+ xsize = result.xsize,
+ ysize = result.ysize,
+ colorspace = result.colorspace,
+ rotation = result.rotation,
+ orientation = result.orientation,
+ transform = result.transform,
+ }
+ end
+ request.copyimage = function(t)
+ if found then
+ found = false
+ return inject(t)
+ end
+ end
+ end
+ return genericchecker(data)
+end
+
+function checkers.jp2(data) -- idem as jpg
+ local request = data.request
+ local used = data.used
+ if request and used and not request.scanimage then
+ local identify = graphics.identify
+ local inject = lpdf.injectors.jp2
+ local found = false
+ request.scanimage = function(t)
+ local result = wrappedidentify(identify,t.filename)
+ found = not result.error
+ return {
+ filename = result.filename,
+ width = result.width,
+ height = result.height,
+ depth = result.depth,
+ colordepth = result.colordepth,
+ xres = result.xres,
+ yres = result.yres,
+ xsize = result.xsize,
+ ysize = result.ysize,
+ rotation = result.rotation,
+ colorspace = result.colorspace,
+ orientation = result.orientation,
+ transform = result.transform,
+ }
+ end
+ request.copyimage = function(t)
+ if found then
+ found = false
+ return inject(t)
+ end
+ end
+ end
+ return genericchecker(data)
+end
+
+function checkers.png(data) -- same as jpg (for now)
+ local request = data.request
+ local used = data.used
+ if request and used and not request.scanimage then
+ local identify = graphics.identify
+ local inject = lpdf.injectors.png -- currently pdf specific
+ local found = false
+ request.scanimage = function(t)
+ local result = wrappedidentify(identify,t.filename)
+ found = not result.error
+ return {
+ filename = result.filename,
+ width = result.width,
+ height = result.height,
+ depth = result.depth,
+ colordepth = result.colordepth,
+ xres = result.xres,
+ yres = result.yres,
+ xsize = result.xsize,
+ ysize = result.ysize,
+ rotation = result.rotation,
+ colorspace = result.colorspace,
+ tables = result.tables,
+ interlace = result.interlace,
+ filter = result.filter,
+ orientation = result.orientation,
+ transform = result.transform,
+ }
+ end
+ request.copyimage = function(t)
+ t.colorref = used.colorref -- this is a bit of a hack
+ if found then
+ found = false
+ local ok, result = pcall(inject,t)
+ if ok then
+ return result
+ else
+ report_inclusion("bad bitmap image")
+ return placeholder()
+ end
+ end
+ end
+ end
+ return genericchecker(data)
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/grph-con.lua b/Master/texmf-dist/tex/context/base/mkiv/grph-con.lua
index f106e1036c5..c3c711b0c72 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/grph-con.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/grph-con.lua
@@ -12,6 +12,7 @@ local tonumber = tonumber
local longtostring = string.longtostring
local formatters = string.formatters
local expandfilename = dir.expandname
+local isfile = lfs.isfile
local settings_to_array = utilities.parsers.settings_to_array
local settings_to_hash = utilities.parsers.settings_to_hash
@@ -68,9 +69,9 @@ do -- eps | ps
-dPDFSETTINGS=/%presets%
-dEPSCrop
-dCompatibilityLevel=%level%
- -sOutputFile="%newname%"
+ -sOutputFile=%newname%
%colorspace%
- "%oldname%"
+ %oldname%
-c quit
]],
checkers = {
@@ -121,7 +122,7 @@ do -- eps | ps
local presets = resolutions[resolution or "high"] or resolutions.high
local level = codeinjections.getformatoption("pdf_level") or "1.3"
local tmpname = oldname
- if not tmpname or tmpname == "" or not lfs.isfile(tmpname) then
+ if not tmpname or tmpname == "" or not isfile(tmpname) then
return
end
if cleanups.ai then
@@ -197,9 +198,9 @@ do -- svg
name = "svg to something",
program = "inkscape",
template = longtostring [[
- "%oldname%"
+ %oldname%
--export-dpi=%resolution%
- --export-%format%="%newname%"
+ --export-%format%=%newname%
]],
checkers = {
oldname = "readable",
@@ -289,7 +290,7 @@ do -- png | jpg | profiles
local pngconverters = converters.png
local function profiles()
- if not lfs.isfile(rgbprofile) then
+ if not isfile(rgbprofile) then
local found = resolvers.findfile(rgbprofile)
if found and found ~= "" then
rgbprofile = found
@@ -297,7 +298,7 @@ do -- png | jpg | profiles
report_figures("unknown profile %a",rgbprofile)
end
end
- if not lfs.isfile(cmykprofile) then
+ if not isfile(cmykprofile) then
local found = resolvers.findfile(cmykprofile)
if found and found ~= "" then
cmykprofile = found
@@ -324,7 +325,7 @@ do -- png | jpg | profiles
local pngtocmykpdf = sandbox.registerrunner {
name = "png to cmyk pdf",
program = "gm",
- template = [[convert -compress Zip -strip +profile "*" -profile "%rgbprofile%" -profile "%cmykprofile%" -sampling-factor 1x1 "%oldname%" "%newname%"]],
+ template = [[convert -compress Zip -strip +profile "*" -profile %rgbprofile% -profile %cmykprofile% -sampling-factor 1x1 %oldname% %newname%]],
checkers = checkers,
defaults = defaults,
}
@@ -332,7 +333,7 @@ do -- png | jpg | profiles
local jpgtocmykpdf = sandbox.registerrunner {
name = "jpg to cmyk pdf",
program = "gm",
- template = [[convert -compress JPEG -strip +profile "*" -profile "%rgbprofile%" -profile "%cmykprofile%" -sampling-factor 1x1 "%oldname%" "%newname%"]],
+ template = [[convert -compress JPEG -strip +profile "*" -profile %rgbprofile% -profile %cmykprofile% -sampling-factor 1x1 %oldname% %newname%]],
checkers = checkers,
defaults = defaults,
}
@@ -340,7 +341,7 @@ do -- png | jpg | profiles
local pngtograypdf = sandbox.registerrunner {
name = "png to gray pdf",
program = "gm",
- template = [[convert -colorspace gray -compress Zip -sampling-factor 1x1 "%oldname%" "%newname%"]],
+ template = [[convert -colorspace gray -compress Zip -sampling-factor 1x1 %oldname% %newname%]],
checkers = checkers,
defaults = defaults,
}
@@ -348,7 +349,7 @@ do -- png | jpg | profiles
local jpgtograypdf = sandbox.registerrunner {
name = "jpg to gray pdf",
program = "gm",
- template = [[convert -colorspace gray -compress Zip -sampling-factor 1x1 "%oldname%" "%newname%"]],
+ template = [[convert -colorspace gray -compress Zip -sampling-factor 1x1 %oldname% %newname%]],
checkers = checkers,
defaults = defaults,
}
@@ -401,7 +402,7 @@ do -- png | jpg | profiles
local recolorpng = sandbox.registerrunner {
name = "recolor png",
program = "gm",
- template = [[convert -recolor "%color%" "%oldname%" "%newname%"]],
+ template = [[convert -recolor %color% %oldname% %newname%]],
checkers = checkers,
defaults = defaults,
}
@@ -420,3 +421,25 @@ do -- png | jpg | profiles
end
end
+
+if CONTEXTLMTXMODE > 0 then
+
+ -- This might also work ok in mkiv but is yet untested. Anyway, it's experimental as we
+ -- go through TeX which is is inefficient. I'll improve the buffer trick.
+
+ local function remap(specification)
+ local fullname = specification.fullname
+ if fullname then
+ local only = file.nameonly(fullname)
+ local name = formatters["svg-%s-inclusion"](only)
+ local code = formatters["\\includesvgfile[%s]\\resetbuffer[%s]"](fullname,name)
+ buffers.assign(name,code)
+ specification.format = "buffer"
+ specification.fullname = name
+ end
+ return specification
+ end
+
+ figures.remappers.svg = { mp = remap }
+
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/grph-fil.lua b/Master/texmf-dist/tex/context/base/mkiv/grph-fil.lua
index 540356c46cf..b3980783038 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/grph-fil.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/grph-fil.lua
@@ -45,7 +45,7 @@ job.register('job.files.collected', tobesaved, initializer)
local runner = sandbox.registerrunner {
name = "hashed context run",
program = "context",
- template = [[%options% "%filename%"]],
+ template = [[%options% %filename%]],
checkers = {
options = "string",
filename = "readable",
@@ -57,10 +57,32 @@ function jobfiles.run(name,action)
local oldchecksum = collected[usedname]
local newchecksum = checksum(usedname)
local resultfile = replacesuffix(usedname,resultsuffix)
- if jobfiles.forcerun or not oldchecksum or oldchecksum ~= newchecksum or not isfile(resultfile) then
+ local tobedone = false
+ if jobfiles.forcerun then
+ tobedone = true
if trace_run then
- report_run("processing file, changes in %a, processing forced",name)
+ report_run("processing file, changes in %a, %s",name,"processing forced")
end
+ end
+ if not tobedone and not oldchecksum then
+ tobedone = true
+ if trace_run then
+ report_run("processing file, changes in %a, %s",name,"no checksum yet")
+ end
+ end
+ if not tobedone and oldchecksum ~= newchecksum then
+ tobedone = true
+ if trace_run then
+ report_run("processing file, changes in %a, %s",name,"checksum mismatch")
+ end
+ end
+ if not tobedone and not isfile(resultfile) then
+ tobedone = true
+ if trace_run then
+ report_run("processing file, changes in %a, %s",name,"no result file")
+ end
+ end
+ if tobedone then
local ta = type(action)
if ta == "function" then
action(name)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/grph-img.lua b/Master/texmf-dist/tex/context/base/mkiv/grph-img.lua
new file mode 100644
index 00000000000..4b4bee1fc08
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/grph-img.lua
@@ -0,0 +1,738 @@
+ if not modules then modules = { } end modules ['grph-img'] = {
+ version = 1.001,
+ comment = "companion to grph-inc.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- The jpg identification and inclusion code is based on the code in \LUATEX\ but as we
+-- use \LUA\ we can do it a bit cleaner. We can also use some helpers for reading from
+-- file. We could make it even more lean and mean. When all works out ok I will clean
+-- up this code a bit as we can divert more from luatex.
+
+local lower, strip = string.lower, string.strip
+local round = math.round
+local concat = table.concat
+local suffixonly = file.suffix
+
+local newreader = io.newreader
+local setmetatableindex = table.setmetatableindex
+local setmetatablecall = table.setmetatablecall
+
+local graphics = graphics or { }
+local identifiers = { }
+graphics.identifiers = identifiers
+
+do
+
+ local colorspaces = {
+ [1] = 1, -- gray
+ [3] = 2, -- rgb
+ [4] = 3, -- cmyk
+ }
+
+ local tags = {
+ [0xC0] = { name = "SOF0", }, -- baseline DCT
+ [0xC1] = { name = "SOF1", }, -- extended sequential DCT
+ [0xC2] = { name = "SOF2", }, -- progressive DCT
+ [0xC3] = { name = "SOF3", supported = false }, -- lossless (sequential)
+
+ [0xC5] = { name = "SOF5", supported = false }, -- differential sequential DCT
+ [0xC6] = { name = "SOF6", supported = false }, -- differential progressive DCT
+ [0xC7] = { name = "SOF7", supported = false }, -- differential lossless (sequential)
+
+ [0xC8] = { name = "JPG", }, -- reserved for JPEG extensions
+ [0xC9] = { name = "SOF9", }, -- extended sequential DCT
+ [0xCA] = { name = "SOF10", supported = false }, -- progressive DCT
+ [0xCB] = { name = "SOF11", supported = false }, -- lossless (sequential)
+
+ [0xCD] = { name = "SOF13", supported = false }, -- differential sequential DCT
+ [0xCE] = { name = "SOF14", supported = false }, -- differential progressive DCT
+ [0xCF] = { name = "SOF15", supported = false }, -- differential lossless (sequential)
+
+ [0xC4] = { name = "DHT" }, -- define Huffman table(s)
+
+ [0xCC] = { name = "DAC" }, -- define arithmetic conditioning table
+
+ [0xD0] = { name = "RST0", zerolength = true }, -- restart
+ [0xD1] = { name = "RST1", zerolength = true }, -- restart
+ [0xD2] = { name = "RST2", zerolength = true }, -- restart
+ [0xD3] = { name = "RST3", zerolength = true }, -- restart
+ [0xD4] = { name = "RST4", zerolength = true }, -- restart
+ [0xD5] = { name = "RST5", zerolength = true }, -- restart
+ [0xD6] = { name = "RST6", zerolength = true }, -- restart
+ [0xD7] = { name = "RST7", zerolength = true }, -- restart
+
+ [0xD8] = { name = "SOI", zerolength = true }, -- start of image
+ [0xD9] = { name = "EOI", zerolength = true }, -- end of image
+ [0xDA] = { name = "SOS" }, -- start of scan
+ [0xDB] = { name = "DQT" }, -- define quantization tables
+ [0xDC] = { name = "DNL" }, -- define number of lines
+ [0xDD] = { name = "DRI" }, -- define restart interval
+ [0xDE] = { name = "DHP" }, -- define hierarchical progression
+ [0xDF] = { name = "EXP" }, -- expand reference image(s)
+
+ [0xE0] = { name = "APP0" }, -- application marker, used for JFIF
+ [0xE1] = { name = "APP1" }, -- application marker
+ [0xE2] = { name = "APP2" }, -- application marker
+ [0xE3] = { name = "APP3" }, -- application marker
+ [0xE4] = { name = "APP4" }, -- application marker
+ [0xE5] = { name = "APP5" }, -- application marker
+ [0xE6] = { name = "APP6" }, -- application marker
+ [0xE7] = { name = "APP7" }, -- application marker
+ [0xE8] = { name = "APP8" }, -- application marker
+ [0xE9] = { name = "APP9" }, -- application marker
+ [0xEA] = { name = "APP10" }, -- application marker
+ [0xEB] = { name = "APP11" }, -- application marker
+ [0xEC] = { name = "APP12" }, -- application marker
+ [0xED] = { name = "APP13" }, -- application marker
+ [0xEE] = { name = "APP14" }, -- application marker, used by Adobe
+ [0xEF] = { name = "APP15" }, -- application marker
+
+ [0xF0] = { name = "JPG0" }, -- reserved for JPEG extensions
+ [0xFD] = { name = "JPG13" }, -- reserved for JPEG extensions
+ [0xFE] = { name = "COM" }, -- comment
+
+ [0x01] = { name = "TEM", zerolength = true }, -- temporary use
+ }
+
+ -- More can be found in http://www.exif.org/Exif2-2.PDF but basically we have
+ -- good old tiff tags here.
+
+ local function read_APP1_Exif(f, xres, yres, orientation) -- untested
+ local position = false
+ local littleendian = false
+ -- endian II|MM
+ while true do
+ position = f:getposition()
+ local b = f:readbyte()
+ if b == 0 then
+ -- next one
+ elseif b == 0x4D and f:readbyte() == 0x4D then -- M
+ -- big endian
+ break
+ elseif b == 0x49 and f:readbyte() == 0x49 then -- I
+ -- little endian
+ littleendian = true
+ break
+ else
+ -- warning "bad exif data"
+ return xres, yres, orientation
+ end
+ end
+ -- version
+ local version = littleendian and f:readcardinal2le() or f:readcardinal2()
+ if version ~= 42 then
+ return xres, yres, orientation
+ end
+ -- offset to records
+ local offset = littleendian and f:readcardinal4le() or f:readcardinal4()
+ if not offset then
+ return xres, yres, orientation
+ end
+ f:setposition(position + offset)
+ local entries = littleendian and f:readcardinal2le() or f:readcardinal2()
+ if not entries or entries == 0 then
+ return xres, yres, orientation
+ end
+ local x_res, y_res, x_res_ms, y_res_ms, x_temp, y_temp
+ local res_unit, res_unit_ms
+ for i=1,entries do
+ local tag = littleendian and f:readcardinal2le() or f:readcardinal2()
+ local kind = littleendian and f:readcardinal2le() or f:readcardinal2()
+ local size = littleendian and f:readcardinal4le() or f:readcardinal4()
+ local value = 0
+ local num = 0
+ local den = 0
+ if kind == 1 or kind == 7 then -- byte | undefined
+ value = f:readbyte()
+ f:skip(3)
+ elseif kind == 3 or kind == 8 then -- (un)signed short
+ value = littleendian and f:readcardinal2le() or f:readcardinal2()
+ f:skip(2)
+ elseif kind == 4 or kind == 9 then -- (un)signed long
+ value = littleendian and f:readcardinal4le() or f:readcardinal4()
+ elseif kind == 5 or kind == 10 then -- (s)rational
+ local offset = littleendian and f:readcardinal4le() or f:readcardinal4()
+ local saved = f:getposition()
+ f:setposition(position+offset)
+ num = littleendian and f:readcardinal4le() or f:readcardinal4()
+ den = littleendian and f:readcardinal4le() or f:readcardinal4()
+ f:setposition(saved)
+ else -- 2 -- ascii
+ f:skip(4)
+ end
+ if tag == 274 then -- orientation
+ orientation = value
+ elseif tag == 282 then -- x resolution
+ if den ~= 0 then
+ x_res = num/den
+ end
+ elseif tag == 283 then -- y resolution
+ if den ~= 0 then
+ y_res = num/den
+ end
+ elseif tag == 296 then -- resolution unit
+ if value == 2 then
+ res_unit = 1
+ elseif value == 3 then
+ res_unit = 2.54
+ end
+ elseif tag == 0x5110 then -- pixel unit
+ res_unit_ms = value == 1
+ elseif tag == 0x5111 then -- x pixels per unit
+ x_res_ms = value
+ elseif tag == 0x5112 then -- y pixels per unit
+ y_res_ms = value
+ end
+ end
+ if x_res and y_res and res_unit and res_unit > 0 then
+ x_temp = round(x_res * res_unit)
+ y_temp = round(y_res * res_unit)
+ elseif x_res_ms and y_res_ms and res_unit_ms then
+ x_temp = round(x_res_ms * 0.0254) -- in meters
+ y_temp = round(y_res_ms * 0.0254) -- in meters
+ end
+ if x_temp and a_temp and x_temp > 0 and y_temp > 0 then
+ if (x_temp ~= x_res or y_temp ~= y_res) and x_res ~= 0 and y_res ~= 0 then
+ -- exif resolution differs from already found resolution
+ elseif x_temp == 1 or y_temp == 1 then
+ -- exif resolution is kind of weird
+ else
+ return x_temp, y_temp, orientation
+ end
+ end
+ return round(xres), round(yres), orientation
+ end
+
+ function identifiers.jpg(filename,method)
+ local specification = {
+ filename = filename,
+ filetype = "jpg",
+ }
+ if not filename or filename == "" then
+ specification.error = "invalid filename"
+ return specification -- error
+ end
+ local f = newreader(filename,method)
+ if not f then
+ specification.error = "unable to open file"
+ return specification -- error
+ end
+ specification.xres = 0
+ specification.yres = 0
+ specification.orientation = 1
+ specification.totalpages = 1
+ specification.pagenum = 1
+ specification.length = 0
+ local banner = f:readcardinal2()
+ if banner ~= 0xFFD8 then
+ specification.error = "no jpeg file"
+ return specification -- error
+ end
+ local xres = 0
+ local yres = 0
+ local orientation = 1
+ local okay = false
+ local filesize = f:getsize() -- seek end
+ -- local majorversion = pdfmajorversion and pdfmajorversion() or 1
+ -- local minorversion = pdfminorversion and pdfminorversion() or 7
+ while f:getposition() < filesize do
+ local b = f:readbyte()
+ if not b then
+ break
+ elseif b ~= 0xFF then
+ if not okay then
+ -- or check for size
+ specification.error = "incomplete file"
+ end
+ break
+ end
+ local category = f:readbyte()
+ local position = f:getposition()
+ local length = 0
+ local tagdata = tags[category]
+ if not tagdata then
+ specification.error = "invalid tag"
+ break
+ elseif tagdata.supported == false then
+ specification.error = "unsupported " .. tagdata.comment
+ break
+ end
+ local name = tagdata.name
+ if name == "SOF0" or name == "SOF1" or name == "SOF2" then
+ --
+ -- It makes no sense to support pdf < 1.3 so we now just omit this
+ -- test. There is no need to polute the code with useless tests.
+ --
+ -- if majorversion == 1 and minorversion <= 2 then
+ -- specification.error = "no progressive DCT in PDF <= 1.2"
+ -- break
+ -- end
+ length = f:readcardinal2()
+ specification.colordepth = f:readcardinal()
+ specification.ysize = f:readcardinal2()
+ specification.xsize = f:readcardinal2()
+ specification.colorspace = colorspaces[f:readcardinal()]
+ if not specification.colorspace then
+ specification.error = "unsupported color space"
+ break
+ end
+ okay = true
+ elseif name == "APP0" then
+ length = f:readcardinal2()
+ if length > 6 then
+ local format = f:readstring(5)
+ if format == "JFIF\000" then
+ f:skip(2)
+ units = f:readcardinal()
+ xres = f:readcardinal2()
+ yres = f:readcardinal2()
+ if units == 1 then
+ -- pixels per inch
+ if xres == 1 or yres == 1 then
+ -- warning
+ end
+ elseif units == 2 then
+ -- pixels per cm */
+ xres = xres * 2.54
+ yres = yres * 2.54
+ else
+ xres = 0
+ yres = 0
+ end
+ end
+ end
+ elseif name == "APP1" then
+ length = f:readcardinal2()
+ if length > 7 then
+ local format = f:readstring(5)
+ if format == "Exif\000" then
+ xres, yres, orientation = read_APP1_Exif(f,xres,yres,orientation)
+ end
+ end
+ elseif not tagdata.zerolength then
+ length = f:readcardinal2()
+ end
+ if length > 0 then
+ f:setposition(position+length)
+ end
+ end
+ f:close()
+ if not okay then
+ specification.error = specification.error or "invalid file"
+ elseif not specification.error then
+ if xres == 0 and yres ~= 0 then
+ xres = yres
+ end
+ if yres == 0 and xres ~= 0 then
+ yres = xres
+ end
+ end
+ specification.xres = xres
+ specification.yres = yres
+ specification.orientation = orientation
+ specification.length = filesize
+ return specification
+ end
+
+end
+
+do
+
+ local function read_boxhdr(specification,f)
+ local size = f:readcardinal4()
+ local kind = f:readstring(4)
+ if kind then
+ kind = strip(lower(kind))
+ else
+ kind = ""
+ end
+ if size == 1 then
+ size = f:readcardinal4() * 0xFFFF0000 + f:readcardinal4()
+ end
+ if size == 0 and kind ~= "jp2c" then -- move this
+ specification.error = "invalid size"
+ end
+ return kind, size
+ end
+
+ local function scan_ihdr(specification,f)
+ specification.ysize = f:readcardinal4()
+ specification.xsize = f:readcardinal4()
+ f:skip(2) -- nc
+ specification.colordepth = f:readcardinal() + 1
+ f:skip(3) -- c unkc ipr
+ end
+
+ local function scan_resc_resd(specification,f)
+ local vr_n = f:readcardinal2()
+ local vr_d = f:readcardinal2()
+ local hr_n = f:readcardinal2()
+ local hr_d = f:readcardinal2()
+ local vr_e = f:readcardinal()
+ local hr_e = f:readcardinal()
+ specification.xres = math.round((hr_n / hr_d) * math.exp(hr_e * math.log(10.0)) * 0.0254)
+ specification.yres = math.round((vr_n / vr_d) * math.exp(vr_e * math.log(10.0)) * 0.0254)
+ end
+
+ local function scan_res(specification,f,last)
+ local pos = f:getposition()
+ while true do
+ local kind, size = read_boxhdr(specification,f)
+ pos = pos + size
+ if kind == "resc" then
+ if specification.xres == 0 and specification.yres == 0 then
+ scan_resc_resd(specification,f)
+ if f:getposition() ~= pos then
+ specification.error = "invalid resc"
+ return
+ end
+ end
+ elseif tpos == "resd" then
+ scan_resc_resd(specification,f)
+ if f:getposition() ~= pos then
+ specification.error = "invalid resd"
+ return
+ end
+ elseif pos > last then
+ specification.error = "invalid res"
+ return
+ elseif pos == last then
+ break
+ end
+ if specification.error then
+ break
+ end
+ f:setposition(pos)
+ end
+ end
+
+ local function scan_jp2h(specification,f,last)
+ local okay = false
+ local pos = f:getposition()
+ while true do
+ local kind, size = read_boxhdr(specification,f)
+ pos = pos + size
+ if kind == "ihdr" then
+ scan_ihdr(specification,f)
+ if f:getposition() ~= pos then
+ specification.error = "invalid ihdr"
+ return false
+ end
+ okay = true
+ elseif kind == "res" then
+ scan_res(specification,f,pos)
+ elseif pos > last then
+ specification.error = "invalid jp2h"
+ return false
+ elseif pos == last then
+ break
+ end
+ if specification.error then
+ break
+ end
+ f:setposition(pos)
+ end
+ return okay
+ end
+
+ function identifiers.jp2(filename,method)
+ local specification = {
+ filename = filename,
+ filetype = "jp2",
+ }
+ if not filename or filename == "" then
+ specification.error = "invalid filename"
+ return specification -- error
+ end
+ local f = newreader(filename,method)
+ if not f then
+ specification.error = "unable to open file"
+ return specification -- error
+ end
+ specification.xres = 0
+ specification.yres = 0
+ specification.orientation = 1
+ specification.totalpages = 1
+ specification.pagenum = 1
+ specification.length = 0
+ local xres = 0
+ local yres = 0
+ local orientation = 1
+ local okay = false
+ local filesize = f:getsize() -- seek end
+ --
+ local pos = 0
+ -- signature
+ local kind, size = read_boxhdr(specification,f)
+ pos = pos + size
+ f:setposition(pos)
+ -- filetype
+ local kind, size = read_boxhdr(specification,f)
+ if kind ~= "ftyp" then
+ specification.error = "missing ftyp box"
+ return specification
+ end
+ pos = pos + size
+ f:setposition(pos)
+ while not okay do
+ local kind, size = read_boxhdr(specification,f)
+ pos = pos + size
+ if kind == "jp2h" then
+ okay = scan_jp2h(specification,f,pos)
+ elseif kind == "jp2c" and not okay then
+ specification.error = "no ihdr box found"
+ return specification
+ end
+ f:setposition(pos)
+ end
+ --
+ f:close()
+ if not okay then
+ specification.error = "invalid file"
+ elseif not specification.error then
+ if xres == 0 and yres ~= 0 then
+ xres = yres
+ end
+ if yres == 0 and xres ~= 0 then
+ yres = xres
+ end
+ end
+ specification.xres = xres
+ specification.yres = yres
+ specification.orientation = orientation
+ specification.length = filesize
+ return specification
+ end
+
+end
+
+do
+
+ -- 0 = gray "image b"
+ -- 2 = rgb "image c"
+ -- 3 = palette "image c" + "image i"
+ -- 4 = gray + alpha "image b"
+ -- 6 = rgb + alpha "image c"
+
+ -- for i=1,length/3 do
+ -- palette[i] = f:readstring3)
+ -- end
+
+ local function grab(t,f,once)
+ if once then
+ for i=1,#t do
+ local l = t[i]
+ f:setposition(l.offset)
+ t[i] = f:readstring(l.length)
+ end
+ local data = concat(t)
+ -- t wiped in caller
+ return data
+ else
+ local data = { }
+ for i=1,#t do
+ local l = t[i]
+ f:setposition(l.offset)
+ data[i] = f:readstring(l.length)
+ end
+ return concat(data)
+ end
+ end
+
+ function identifiers.png(filename,method)
+ local specification = {
+ filename = filename,
+ filetype = "png",
+ }
+ if not filename or filename == "" then
+ specification.error = "invalid filename"
+ return specification -- error
+ end
+ local f = newreader(filename,method)
+ if not f then
+ specification.error = "unable to open file"
+ return specification -- error
+ end
+ specification.xres = 0
+ specification.yres = 0
+ specification.orientation = 1
+ specification.totalpages = 1
+ specification.pagenum = 1
+ specification.offset = 0
+ specification.length = 0
+ local filesize = f:getsize() -- seek end
+ local tables = { }
+ local banner = f:readstring(8)
+ if banner ~= "\137PNG\013\010\026\010" then
+ specification.error = "no png file"
+ return specification -- error
+ end
+ while true do
+ local position = f:getposition()
+ if position >= filesize then
+ break
+ end
+ local length = f:readcardinal4()
+ if not length then
+ break
+ end
+ local kind = f:readstring(4)
+ if kind then
+ kind = lower(kind)
+ else
+ break
+ end
+ if kind == "ihdr" then -- metadata
+ specification.xsize = f:readcardinal4()
+ specification.ysize = f:readcardinal4()
+ specification.colordepth = f:readcardinal()
+ specification.colorspace = f:readcardinal()
+ specification.compression = f:readcardinal()
+ specification.filter = f:readcardinal()
+ specification.interlace = f:readcardinal()
+ tables[kind] = true
+ elseif kind == "iend" then
+ tables[kind] = true
+ break
+ elseif kind == "phys" then
+ local x = f:readcardinal4()
+ local y = f:readcardinal4()
+ local u = f:readcardinal()
+ if u == 1 then -- meters
+ -- x = round(0.0254 * x)
+ -- y = round(0.0254 * y)
+ end
+ specification.xres = x
+ specification.yres = y
+ tables[kind] = true
+ elseif kind == "idat" or kind == "plte" or kind == "gama" or kind == "trns" then
+ local t = tables[kind]
+ if not t then
+ t = setmetatablecall(grab)
+ tables[kind] = t
+ end
+ t[#t+1] = {
+ offset = f:getposition(),
+ length = length,
+ }
+ else
+ tables[kind] = true
+ end
+ f:setposition(position+length+12) -- #size #kind #crc
+ end
+ f:close()
+ specification.tables = tables
+ return specification
+ end
+
+end
+
+do
+
+ local function gray(t,k)
+ local v = 0
+ t[k] = v
+ return v
+ end
+
+ local function rgb(t,k)
+ local v = { 0, 0, 0 }
+ t[k] = v
+ return v
+ end
+
+ local function cmyk(t,k)
+ local v = { 0, 0, 0, 0 }
+ t[k] = v
+ return v
+ end
+
+ function identifiers.bitmap(specification)
+ local xsize = specification.xsize or 0
+ local ysize = specification.ysize or 0
+ local width = specification.width or xsize * 65536
+ local height = specification.height or ysize * 65536
+ local colordepth = specification.colordepth or 1 -- 1 .. 2
+ local colorspace = specification.colorspace or 1 -- 1 .. 3
+ local pixel = false
+ local data = specification.data
+ local mask = specification.mask
+ local index = specification.index
+ if colorspace == 1 or colorspace == "gray" then
+ pixel = gray
+ colorspace = 1
+ elseif colorspace == 2 or colorspace == "rgb" then
+ pixel = rgb
+ colorspace = 2
+ elseif colorspace == 3 or colorspace == "cmyk" then
+ pixel = cmyk
+ colorspace = 3
+ else
+ return
+ end
+ if colordepth == 8 then
+ colordepth = 1
+ elseif colordepth == 16 then
+ colordepth = 2
+ end
+ if colordepth > 1 then
+ -- not yet
+ return
+ end
+ if data then
+ -- assume correct data
+ else
+ data = { }
+ for i=1,ysize do
+ data[i] = setmetatableindex(pixel)
+ end
+ end
+ if mask == true then
+ mask = { }
+ for i=1,ysize do
+ mask[i] = setmetatableindex(gray)
+ end
+ end
+ if index then
+ index = setmetatableindex(pixel)
+ end
+ local specification = {
+ xsize = xsize,
+ ysize = ysize,
+ width = width,
+ height = height,
+ colordepth = colordepth,
+ colorspace = colorspace,
+ data = data,
+ mask = mask,
+ index = index,
+ }
+ return specification
+ end
+
+end
+
+function graphics.identify(filename,filetype)
+ local identify = filetype and identifiers[filetype]
+ if identify then
+ return identify(filename)
+ end
+ local identify = identifiers[suffixonly(filename)]
+ if identify then
+ identify = identify(filename)
+ else
+ identify = {
+ filename = filename,
+ filetype = filetype,
+ error = "identification failed",
+ }
+ end
+ -- inspect(identify)
+ return identify
+end
+
+-- inspect(identifiers.jpg("t:/sources/hacker.jpg"))
+-- inspect(identifiers.png("t:/sources/mill.png"))
diff --git a/Master/texmf-dist/tex/context/base/mkiv/grph-inc.lua b/Master/texmf-dist/tex/context/base/mkiv/grph-inc.lua
index 0856e0de9bb..8032f3c240f 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/grph-inc.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/grph-inc.lua
@@ -55,6 +55,7 @@ local todimen = string.todimen
local collapsepath = file.collapsepath
local formatters = string.formatters
local odd = math.odd
+local isfile, isdir, modificationtime = lfs.isfile, lfs.isdir, lfs.modification
local P, R, S, Cc, C, Cs, Ct, lpegmatch = lpeg.P, lpeg.R, lpeg.S, lpeg.Cc, lpeg.C, lpeg.Cs, lpeg.Ct, lpeg.match
@@ -157,36 +158,11 @@ function checkimage(figure)
end
end
---- begin of mapping / this will become graphics & code|nodeinjections but not this year
+-- This is a bit of abstraction. Fro a while we will follow the luatex image
+-- model.
-local __img__ = type(img) == "table" and img or { }
-images.__img__ =__img__
-
-local imgnew = __img__.new
-local imgscan = __img__.scan
-local imgcopy = __img__.copy
-local imgwrap = __img__.node
-local imgembed = __img__.immediatewrite
-
-if imgnew then
- -- catch (actually we should be less picky in img)
- local __img__new__ = imgnew
- imgnew = function(t)
- t.kind = nil
- return __img__new__(t)
- end
-end
-
-updaters.register("backend.update.img",function()
- local img = images.__img__
- imgnew = img.new
- imgscan = img.scan
- imgcopy = img.copy
- imgwrap = img.wrap
- imgembed = img.embed
-end)
-
-local imagekeys = { -- only relevant ones
+local imagekeys = {
+ -- only relevant ones (permitted in luatex)
"width", "height", "depth", "bbox",
"colordepth", "colorspace",
"filename", "filepath", "visiblefilename",
@@ -214,28 +190,26 @@ images.keys = imagekeys
images.types = imagetypes
images.sizes = imagesizes
--- new interface
-
local function createimage(specification)
- return imgnew(specification)
+ return backends.codeinjections.newimage(specification)
end
local function copyimage(specification)
- return imgcopy(specification)
+ return backends.codeinjections.copyimage(specification)
end
local function scanimage(specification)
- return imgscan(specification)
+ return backends.codeinjections.scanimage(specification)
end
local function embedimage(specification)
-- write the image to file
- return imgembed(specification)
+ return backends.codeinjections.embedimage(specification)
end
local function wrapimage(specification)
-- create an image rule
- return imgwrap(specification)
+ return backends.codeinjections.wrapimage(specification)
end
images.create = createimage
@@ -244,20 +218,20 @@ images.copy = copyimage
images.wrap = wrapimage
images.embed = embedimage
--- now we reimplement img:
-
-img = {
- new = createimage,
- scan = scanimage,
- copy = copyimage,
- node = wrapimage,
- write = function(specification) context(wrapimage(specification)) end,
- immediatewrite = embedimage,
- immediatewriteobject = function() end, -- not upported, experimental anyway
- boxes = function() return sortedkeys(imagesizes) end,
- fields = function() return imagekeys end,
- types = function() return { unpack(imagetypes,0,#imagetypes) } end,
-}
+-- If really needed we can provide:
+--
+-- img = {
+-- new = createimage,
+-- scan = scanimage,
+-- copy = copyimage,
+-- node = wrapimage,
+-- write = function(specification) context(wrapimage(specification)) end,
+-- immediatewrite = embedimage,
+-- immediatewriteobject = function() end, -- not upported, experimental anyway
+-- boxes = function() return sortedkeys(imagesizes) end,
+-- fields = function() return imagekeys end,
+-- types = function() return { unpack(imagetypes,0,#imagetypes) } end,
+-- }
-- end of copies / mapping
@@ -325,6 +299,7 @@ local figures_resources = allocate() figures.resources = figures_resources
local existers = allocate() figures.existers = existers
local checkers = allocate() figures.checkers = checkers
local includers = allocate() figures.includers = includers
+local remappers = allocate() figures.remappers = remappers
local converters = allocate() figures.converters = converters
local identifiers = allocate() figures.identifiers = identifiers
local programs = allocate() figures.programs = programs
@@ -351,7 +326,7 @@ local figures_order = allocate {
local figures_formats = allocate { -- magic and order will move here
["pdf"] = { list = { "pdf" } },
- ["mps"] = { patterns = { "mps", "%d+" } },
+ ["mps"] = { patterns = { "^mps$", "^%d+$" } }, -- we need to anchor
["jpg"] = { list = { "jpg", "jpeg" } },
["png"] = { list = { "png" } },
["jp2"] = { list = { "jp2" } },
@@ -806,24 +781,32 @@ local function register(askedname,specification)
arguments or ""
)
end
- -- quick hack
- local converter = (newformat ~= format or resolution or arguments) and converters[format]
+ -- begin of quick hack
+ local remapper = remappers[format]
+ if remapper then
+ remapper = remapper[conversion]
+ if remapper then
+ specification = remapper(specification) or specification
+ format = specification.format
+ newformat = format
+ conversion = nil
+ end
+ end
+ -- end of quick hack
+ local converter = (not remapper) and (newformat ~= format or resolution or arguments) and converters[format]
if converter then
- if converter[newformat] then
- converter = converter[newformat]
+ local okay = converter[newformat]
+ if okay then
+ converter = okay
else
newformat = defaultformat
- if converter[newformat] then
- converter = converter[newformat]
- else
- converter = nil
- newformat = defaultformat
- end
+ converter = converter[newformat]
end
elseif trace_conversion then
report_inclusion("no converter for %a to %a",format,newformat)
end
if converter then
+ -- todo: make this a function
--
-- todo: outline as helper function
--
@@ -850,7 +833,7 @@ local function register(askedname,specification)
if subpath and subpath ~= "" and subpath ~= "." then
newpath = newpath .. "/" .. subpath
end
- if not lfs.isdir(newpath) then
+ if not isdir(newpath) then
dir.makedirs(newpath)
if not file.is_writable(newpath) then
if trace_conversion then
@@ -888,8 +871,8 @@ local function register(askedname,specification)
local newname = file.join(newpath,newbase)
oldname = collapsepath(oldname)
newname = collapsepath(newname)
- local oldtime = lfs.attributes(oldname,'modification') or 0
- local newtime = lfs.attributes(newname,'modification') or 0
+ local oldtime = modificationtime(oldname) or 0
+ local newtime = modificationtime(newname) or 0
if newtime == 0 or oldtime > newtime then
if trace_conversion then
report_inclusion("converting %a (%a) from %a to %a",askedname,oldname,format,newformat)
@@ -918,7 +901,7 @@ local function register(askedname,specification)
format = suffix
end
end
-specification.format = format
+ specification.format = format
elseif io.exists(oldname) then
report_inclusion("file %a is bugged",oldname)
if format and imagetypes[format] then
@@ -1021,7 +1004,7 @@ local function locate(request) -- name, format, cache
end
else
local foundname = resolvers.findbinfile(askedname)
- if not foundname or not lfs.isfile(foundname) then -- foundname can be dummy
+ if not foundname or not isfile(foundname) then -- foundname can be dummy
if trace_figures then
report_inclusion("unknown url %a",askedname)
end
@@ -1408,7 +1391,7 @@ function existers.generic(askedname,resolve)
local result
if hasscheme(askedname) then
result = resolvers.findbinfile(askedname)
- elseif lfs.isfile(askedname) then
+ elseif isfile(askedname) then
result = askedname
elseif resolve then
result = resolvers.findbinfile(askedname)
@@ -1452,6 +1435,7 @@ local transforms = setmetatableindex (
local function checktransform(figure,forced)
if auto_transform then
+
local orientation = (forced ~= "" and forced ~= v_auto and forced) or figure.orientation or 0
local transform = transforms["orientation-"..orientation]
figure.transform = transform
@@ -1536,6 +1520,11 @@ function checkers.generic(data)
-- tricky as img doesn't allow it
f.attr = figure.attr
end
+ if dr.cmyk == v_yes then
+ f.enforcecmyk = true
+ elseif dr.cmyk == v_auto and attributes.colors.model == "cmyk" then
+ f.enforcecmyk = true
+ end
figure = f
end
local f, d = codeinjections.setfigurealternative(data,figure)
@@ -2086,6 +2075,7 @@ implement {
{ "conversion" },
{ "resolution" },
{ "color" },
+ { "cmyk" },
{ "arguments" },
{ "repeat" },
{ "transform" },
diff --git a/Master/texmf-dist/tex/context/base/mkiv/grph-inc.mkiv b/Master/texmf-dist/tex/context/base/mkiv/grph-inc.mkiv
index 20e7c11a61b..578bad1d067 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/grph-inc.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/grph-inc.mkiv
@@ -20,11 +20,10 @@
\writestatus{loading}{ConTeXt Graphic Macros / Figure Inclusion}
-\ifcase\contextlmtxmode
- \registerctxluafile{grph-inc}{}
-\else
- \registerctxluafile{grph-img}{}
- \registerctxluafile{grph-inc}{}
+\registerctxluafile{grph-img}{}
+\registerctxluafile{grph-inc}{}
+
+\ifcase\contextlmtxmode \else
\registerctxluafile{grph-bmp}{}
\registerctxluafile{grph-chk}{}
\fi
@@ -116,6 +115,7 @@
\c!userpassword =,
\c!ownerpassword =,
\c!compact =,
+ \c!cmyk =,
]
%D Defining figures.
@@ -197,19 +197,39 @@
% label file settings
% label file parent
+% \def\grph_include_use[#1][#2][#3][#4]%
+% {\doifelsenothing{#1}
+% {\doifsomething{#2}
+% {\doifelseassignment{#3}
+% {\grph_include_use_indeed{#2}{#2}{#3}{#4}}
+% {\grph_include_use_indeed{#2}{#2}\empty{#4}}}}
+% {\doifelsenothing{#2}
+% {\doifelseassignment{#3}
+% {\grph_include_use_indeed{#1}{#1}\empty{#3}}
+% {\grph_include_use_indeed{#1}{#1}{#3}{#4}}}
+% {\doifelseassignment{#3}
+% {\grph_include_use_indeed{#1}{#2}\empty{#3}}
+% {\grph_include_use_indeed{#1}{#2}{#3}{#4}}}}}
+
\def\grph_include_use[#1][#2][#3][#4]%
{\doifelsenothing{#1}
{\doifsomething{#2}
- {\doifelseassignment{#3}
- {\grph_include_use_indeed{#2}{#2}{#3}{#4}}
- {\grph_include_use_indeed{#2}{#2}\empty{#4}}}}
+ {\ifcondition\validassignment{#3}%
+ \grph_include_use_indeed{#2}{#2}{#3}{#4}%
+ \else
+ \grph_include_use_indeed{#2}{#2}\empty{#4}%
+ \fi}}%
{\doifelsenothing{#2}
- {\doifelseassignment{#3}
- {\grph_include_use_indeed{#1}{#1}\empty{#3}}
- {\grph_include_use_indeed{#1}{#1}{#3}{#4}}}
- {\doifelseassignment{#3}
- {\grph_include_use_indeed{#1}{#2}\empty{#3}}
- {\grph_include_use_indeed{#1}{#2}{#3}{#4}}}}}
+ {\ifcondition\validassignment{#3}%
+ \grph_include_use_indeed{#1}{#1}\empty{#3}%
+ \else
+ \grph_include_use_indeed{#1}{#1}{#3}{#4}%
+ \fi}
+ {\ifcondition\validassignment{#3}%
+ \grph_include_use_indeed{#1}{#2}\empty{#3}
+ \else
+ \grph_include_use_indeed{#1}{#2}{#3}{#4}%
+ \fi}}}
\def\grph_include_use_indeed#1#2#3#4%
{\dodoglobal\setvalue{\??externalfigureinstance#1}{\grph_include_setup{#2}{#3}{#4}}%
@@ -221,8 +241,9 @@
{\dotripleempty\grph_include_figure}
\def\grph_include_figure[#1][#2][#3]%
- {\docheckassignment{#2}%
- \ifassignment
+% {\docheckassignment{#2}%
+% \ifassignment
+ {\ifcondition\validassignment{#2}%
\grph_include_place[#1][][#2]%
\else
\grph_include_place[#1][#2][#3]%
@@ -301,8 +322,9 @@
%
\edef\p_grph_include_label{#1}%
\let\p_grph_include_name\p_grph_include_label
- \docheckassignment{#2}%
- \ifassignment
+ % \docheckassignment{#2}%
+ % \ifassignment
+ \ifcondition\validassignment{#2}%
% [label] [settings]
\let\p_grph_include_parent\p_grph_include_label
\grph_include_place_inherit
@@ -346,6 +368,7 @@
conversion {\externalfigureparameter\c!conversion}%
resolution {\externalfigureparameter\c!resolution}%
color {\externalfigureparameter\c!color}% unprocessed raw key
+ cmyk {\externalfigureparameter\c!cmyk}% kind of special
arguments {\externalfigureparameter\c!arguments}% used for converters
repeat {\externalfigureparameter\c!repeat}%
transform {\externalfigureparameter\c!transform}%
@@ -353,10 +376,10 @@
userpassword {\externalfigureparameter\c!userpassword}%
ownerpassword{\externalfigureparameter\c!ownerpassword}%
\ifx\p_width\empty \else
- width \dimexpr\p_width\relax
+ width \dimexpr\p_width\relax
\fi
\ifx\p_height\empty \else
- height \dimexpr\p_height\relax
+ height \dimexpr\p_height\relax
\fi
}%\relax
\clf_figure_identify
@@ -485,29 +508,6 @@
\c!height =\externalfigureparameter\c!height,
\c!lines =\externalfigureparameter\c!lines]
-% % this will become:
-%
-% \unexpanded\def\doscalefigure % used at lua end
-% {\global\setbox\foundexternalfigure\vbox\bgroup
-% \bgroup
-% \let\currentscale\currentexternalfigure
-% \let\scaleparameter\externalfigureparameter
-% \dowithnextboxcs\grph_scale_finish\hbox{\dowithfigure{\box\foundexternalfigure}}%
-% \egroup}
-%
-% % or even better:
-%
-% \def\grph_scale_inherited#1%
-% {\bgroup
-% \expandafter\let\expandafter\currentscale \csname current#1\endcsname
-% \expandafter\let\expandafter\scaleparameter\csname #1parameter\endcsname
-% \dowithnextboxcs\grph_scale_finish\hbox}
-%
-% \unexpanded\def\doscalefigure % used at lua end
-% {\global\setbox\foundexternalfigure\vbox\bgroup
-% \grph_scale_inherited{externalfigure}{\dowithfigure{\box\foundexternalfigure}}%
-% \egroup}
-
%D You can register additional suffixes with the following command:
%D
%D \starttyping
@@ -904,6 +904,25 @@
\unexpanded\def\overlayfigure#1%
{\externalfigure[#1][\c!width=\d_overlay_width,\c!height=\d_overlay_height]}
+% Experimental (will become cleaner):
+
+\ifcase\contextlmtxmode \else
+
+ \unexpanded\def\includesvgfile {\dontleavehmode\begingroup\dodoubleempty\grph_include_svg_file}
+ \unexpanded\def\includesvgbuffer{\dontleavehmode\begingroup\dodoubleempty\grph_include_svg_buffer}
+
+ \def\grph_include_svg_file[#1][#2]%
+ {\getdummyparameters[\c!offset=\zeropoint,#2]%
+ \clf_includesvgfile{#1}\dimexpr\dummyparameter\c!offset\relax
+ \endgroup}
+
+ \def\grph_include_svg_buffer[#1][#2]%
+ {\getdummyparameters[\c!offset=\zeropoint,#2]%
+ \clf_includesvgbuffer{#1}\dimexpr\dummyparameter\c!offset\relax
+ \endgroup}
+
+\fi
+
% Bonus:
\useexternalfigure
@@ -961,6 +980,10 @@
\unexpanded\def\inlinefigure[#1]{\dontleavehmode\sbox{\externalfigure[#1][\v!inline]}}
+%D Needs to be done global:
+
+\definelayer[epdfcontent]
+
\protect \endinput
%D Moved here because this already old code is nowhere documents (so I need to check
diff --git a/Master/texmf-dist/tex/context/base/mkiv/grph-mem.lua b/Master/texmf-dist/tex/context/base/mkiv/grph-mem.lua
index ff35483505a..bde21682693 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/grph-mem.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/grph-mem.lua
@@ -21,142 +21,74 @@ local report = logs.reporter("memstream")
local trace = false trackers.register ("graphics.memstreams", function(v) trace = v end)
local data = { }
-if pdfe then
-
- local function setmemstream(name,stream,once)
- if once and data[name] then
- if trace then
- report("not overloading %a",name) --
- end
- return data[name]
- end
- local kind = figures.guessfromstring(stream)
- local identifier = false
- if kind == "pdf" then
- identifier = pdfe.new(stream,#stream,name)
- if not identifier then
- report("no valid pdf stream %a",name)
- elseif trace then
- report("setting %a with identifier %a",name,identifier)
- end
- else
- identifier = "m_k_i_v_memstream_" .. name .. "." .. kind
- io.savedata(identifier,stream)
- end
- if not identifier then
- identifier = "invalid-memstream"
- end
- data[name] = identifier
- return identifier
- end
-
- resolvers.setmemstream = setmemstream
-
- function resolvers.finders.memstream(specification)
- local name = specification.path
- local identifier = data[name]
- if identifier then
- if trace then
- report("reusing %a with identifier %a",name,identifier)
- end
- return identifier
- end
- local stream = io.loaddata(name)
- if stream and stream ~= "" then
- return setmemstream(name,stream)
- end
+local function setmemstream(name,stream,once)
+ if once and data[name] then
if trace then
- report("no valid memstream %a",name)
+ report("not overloading %a",name) --
end
- return resolvers.finders.notfound()
+ return data[name]
end
-
- local flush = { }
-
- function resolvers.resetmemstream(name,afterpage)
- if afterpage then
- flush[#flush+1] = name
- end
- end
-
- luatex.registerpageactions(function()
- if #flush > 0 then
- for i=1,#flush do
- local identifier = data[name]
- if identifier then
- os.remove(identifier)
- data[name] = nil
- end
- end
- flush = { }
- end
- end)
-
-else
-
- local opened = { }
-
- local function setmemstream(name,stream,once)
- if once and data[name] then
- if trace then
- report("not overloading %a",name) --
- end
- return data[name]
- end
- local memstream, identifier = epdf.openMemStream(stream,#stream,name)
+ local kind = figures.guessfromstring(stream)
+ local identifier = false
+ if kind == "pdf" then
+ identifier = pdfe.new(stream,#stream,name)
if not identifier then
- report("no valid stream %a",name)
- identifier = "invalid-memstream"
+ report("no valid pdf stream %a",name)
elseif trace then
report("setting %a with identifier %a",name,identifier)
end
- data [name] = identifier
- opened[name] = memstream
- return identifier
+ else
+ identifier = "m_k_i_v_memstream_" .. name .. "." .. kind
+ io.savedata(identifier,stream)
end
+ if not identifier then
+ identifier = "invalid-memstream"
+ end
+ data[name] = identifier
+ return identifier
+end
- resolvers.setmemstream = setmemstream
+resolvers.setmemstream = setmemstream
- function resolvers.finders.memstream(specification)
- local name = specification.path
- local identifier = data[name]
- if identifier then
- if trace then
- report("reusing %a with identifier %a",name,identifier)
- end
- return identifier
- end
- local stream = io.loaddata(name)
- if not stream or stream == "" then
- if trace then
- report("no valid file %a",name)
- end
- return resolvers.finders.notfound()
- else
- return setmemstream(name,stream)
+function resolvers.finders.memstream(specification)
+ local name = specification.path
+ local identifier = data[name]
+ if identifier then
+ if trace then
+ report("reusing %a with identifier %a",name,identifier)
end
+ return identifier
+ end
+ local stream = io.loaddata(name)
+ if stream and stream ~= "" then
+ return setmemstream(name,stream)
end
+ if trace then
+ report("no valid memstream %a",name)
+ end
+ return resolvers.finders.notfound()
+end
- local flush = { }
+local flush = { }
- function resolvers.resetmemstream(name,afterpage)
- if afterpage then
- flush[#flush+1] = name
- else
- opened[name] = nil
- end
+function resolvers.resetmemstream(name,afterpage)
+ if afterpage then
+ flush[#flush+1] = name
end
+end
- luatex.registerpageactions(function()
- if #flush > 0 then
- for i=1,#flush do
- opened[flush[i]] = nil -- we keep of course data[name] because of reuse
+luatex.registerpageactions(function()
+ if #flush > 0 then
+ for i=1,#flush do
+ local identifier = data[name]
+ if identifier then
+ os.remove(identifier)
+ data[name] = nil
end
- flush = { }
end
- end)
-
-end
+ flush = { }
+ end
+end)
figures.identifiers.list[#figures.identifiers.list+1] = function(specification)
local name = specification.request.name
diff --git a/Master/texmf-dist/tex/context/base/mkiv/grph-rul.lua b/Master/texmf-dist/tex/context/base/mkiv/grph-rul.lua
index 08edade1fe4..5067b0165ee 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/grph-rul.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/grph-rul.lua
@@ -7,6 +7,7 @@ if not modules then modules = { } end modules ['grph-rul'] = {
}
local tonumber, next, type = tonumber, next, type
+local concat = table.concat
local attributes = attributes
local nodes = nodes
@@ -15,6 +16,7 @@ local context = context
local bpfactor = number.dimenfactors.bp
local nuts = nodes.nuts
+local nodepool = nuts.pool
local userrule = nuts.rules.userrule
local outlinerule = nuts.pool.outlinerule
local ruleactions = nuts.rules.ruleactions
@@ -24,6 +26,8 @@ local setattr = nuts.setattr
local tonode = nuts.tonode
local getattribute = tex.getattribute
+local getwhd = nuts.getwhd
+local setwhd = nuts.setwhd
local lefttoright_code = nodes.dirvalues.lefttoright
@@ -143,25 +147,188 @@ end
do
- -- maybe %.6F
+ -- This is the old oval method that we keep it for compatibility reasons. Of
+ -- course one can use mp instead. It could be improved but at the cost of more
+ -- code than I'm willing to add for something hardly used.
- local f_rectangle = formatters["%.6F w %.6F %.6F %.6F %.6F re %s"]
- local f_baselined = formatters["%.6F w %.6F %.6F %.6F %.6F re s %.6F %.6F m %.6F %.6F l s"]
- local f_dashlined = formatters["%.6F w %.6F %.6F %.6F %.6F re s [%.6F %.6F] 2 d %.6F %.6F m %.6F %.6F l s"]
- local f_radtangle = formatters[
- [[%.6F w %.6F %.6F m
-%.6F %.6F l %.6F %.6F %.6F %.6F y
-%.6F %.6F l %.6F %.6F %.6F %.6F y
-%.6F %.6F l %.6F %.6F %.6F %.6F y
-%.6F %.6F l %.6F %.6F %.6F %.6F y
-h %s]]
- ]
+ local function round(p,kind)
+ local method = tonumber(p.corner) or 0
+ if method < 0 or method > 27 then
+ method = 0
+ end
+ local width = p.width or 0
+ local height = p.height or 0
+ local depth = p.depth or 0
+ local total = height + depth
+ local radius = p.radius or 655360
+ local line = p.line or 65536
+ local how = (method > 8 or kind ~= "fill") and "S" or "f"
+ local half = line / 2
+ local xmin = half * bpfactor
+ local xmax = ( width - half) * bpfactor
+ local ymax = ( height - half) * bpfactor
+ local ymin = (-depth + half) * bpfactor
+ local full = ( radius + half)
+ local xxmin = full * bpfactor
+ local xxmax = ( width - full) * bpfactor
+ local yymax = ( height - full) * bpfactor
+ local yymin = (-depth + full) * bpfactor
+ line = line * bpfactor
+ if xxmin <= xxmax and yymin <= yymax then
+ local list = nil
+ if method == 0 then
+ list = {
+ "q", line, "w", xxmin, ymin, "m", xxmax, ymin, "l", xmax, ymin, xmax, yymin, "y",
+ xmax, yymax, "l", xmax, ymax, xxmax, ymax, "y", xxmin, ymax, "l", xmin, ymax,
+ xmin, yymax, "y", xmin, yymin, "l", xmin, ymin, xxmin, ymin, "y", "h", how, "Q",
+ }
+ elseif method == 1 then
+ list = {
+ "q", line, "w", xxmin, ymin, "m", xxmax, ymin, "l", xmax, ymin, xmax, yymin, "y",
+ xmax, ymax, "l", xmin, ymax, "l", xmin, yymin, "l", xmin, ymin, xxmin, ymin, "y",
+ "h", how, "Q",
+ }
+ elseif method == 2 then
+ list = {
+ "q", line, "w", xxmin, ymin, "m", xmax, ymin, "l", xmax, ymax, "l", xxmin, ymax,
+ "l", xmin, ymax, xmin, yymax, "y", xmin, yymin, "l", xmin, ymin, xxmin, ymin,
+ "y", "h", how, "Q",
+ }
+ elseif method == 3 then
+ list = {
+ "q", line, "w", xmin, ymin, "m", xmax, ymin, "l", xmax, yymax, "l", xmax, ymax,
+ xxmax, ymax, "y", xxmin, ymax, "l", xmin, ymax, xmin, yymax, "y", xmin, ymin,
+ "l", "h", how, "Q",
+ }
+
+ elseif method == 4 then
+ list = {
+ "q", line, "w", xmin, ymin, "m", xxmax, ymin, "l", xmax, ymin, xmax, yymin, "y",
+ xmax, yymax, "l", xmax, ymax, xxmax, ymax, "y", xmin, ymax, "l", xmin, ymin, "l",
+ "h", how, "Q",
+ }
+ elseif method == 5 then
+ list = {
+ "q", line, "w", xmin, ymin, "m", xmax, ymin, "l", xmax, yymax, "l", xmax, ymax,
+ xxmax, ymax, "y", xmin, ymax, "l", xmin, ymin, "l", "h", how, "Q",
+ }
+ elseif method == 6 then
+ list = {
+ "q", line, "w", xmin, ymin, "m", xxmax, ymin, "l", xmax, ymin, xmax, yymin, "y",
+ xmax, ymax, "l", xmin, ymax, "l", xmin, ymin, "l", "h", how, "Q",
+ }
+ elseif method == 7 then
+ list = {
+ "q", line, "w", xxmin, ymin, "m", xmax, ymin, "l", xmax, ymax, "l", xmin, ymax,
+ "l", xmin, yymin, "l", xmin, ymin, xxmin, ymin, "y", "h", how, "Q",
+ }
+ elseif method == 8 then
+ list = {
+ "q", line, "w", xmin, ymin, "m", xmax, ymin, "l", xmax, ymax, "l", xxmin, ymax,
+ "l", xmin, ymax, xmin, yymax, "y", xmin, ymin, "l", "h", how, "Q",
+ }
+ elseif method == 9 then
+ list = {
+ "q", line, "w", xmin, ymax, "m", xmin, yymin, "l", xmin, ymin, xxmin, ymin, "y",
+ xxmax, ymin, "l", xmax, ymin, xmax, yymin, "y", xmax, ymax, "l", how, "Q",
+ }
+ elseif method == 10 then
+ list = {
+ "q", line, "w", xmax, ymax, "m", xxmin, ymax, "l", xmin, ymax, xmin, yymax, "y",
+ xmin, yymin, "l", xmin, ymin, xxmin, ymin, "y", xmax, ymin, "l", how, "Q",
+ }
+ elseif method == 11 then
+ list = {
+ "q", line, "w", xmax, ymin, "m", xmax, yymax, "l", xmax, ymax, xxmax, ymax, "y",
+ xxmin, ymax, "l", xmin, ymax, xmin, yymax, "y", xmin, ymin, "l", how, "Q",
+ }
+ elseif method == 12 then
+ list = {
+ "q", line, "w", xmin, ymax, "m", xxmax, ymax, "l", xmax, ymax, xmax, yymax, "y",
+ xmax, yymin, "l", xmax, ymin, xxmax, ymin, "y", xmin, ymin, "l", how, "Q",
+ }
+ elseif method == 13 then
+ list = {
+ "q", line, "w", xmin, ymax, "m", xxmax, ymax, "l", xmax, ymax, xmax, yymax, "y",
+ xmax, ymin, "l", how, "Q",
+ }
+ elseif method == 14 then
+ list = {
+ "q", line, "w", xmax, ymax, "m", xmax, yymin, "l", xmax, ymin, xxmax, ymin, "y",
+ xmin, ymin, "l", how, "Q",
+ }
+ elseif method == 15 then
+ list = {
+ "q", line, "w", xmax, ymin, "m", xxmin, ymin, "l", xmin, ymin, xmin, yymin, "y",
+ xmin, ymax, "l", how, "Q",
+ }
+ elseif method == 16 then
+ list = {
+ "q", line, "w", xmin, ymin, "m", xmin, yymax, "l", xmin, ymax, xxmin, ymax, "y",
+ xmax, ymax, "l", how, "Q",
+ }
+ elseif method == 17 then
+ list = {
+ "q", line, "w", xxmax, ymax, "m", xmax, ymax, xmax, yymax, "y", how, "Q",
+ }
+ elseif method == 18 then
+ list = {
+ "q", line, "w", xmax, yymin, "m", xmax, ymin, xxmax, ymin, "y", how, "Q",
+ }
+ elseif method == 19 then
+ list = {
+ "q", line, "w", xxmin, ymin, "m", xmin, ymin, xmin, yymin, "y", how, "Q",
+ }
+ elseif method == 20 then
+ list = {
+ "q", line, "w", xmin, yymax, "m", xmin, ymax, xxmin, ymax, "y", how, "Q",
+ }
+ elseif method == 21 then
+ list = {
+ "q", line, "w", xxmax, ymax, "m", xmax, ymax, xmax, yymax, "y", xmin, yymax, "m",
+ xmin, ymax, xxmin, ymax, "y", how, "Q",
+ }
+ elseif method == 22 then
+ list = {
+ "q", line, "w", xxmax, ymax, "m", xmax, ymax, xmax, yymax, "y", xmax, yymin, "m",
+ xmax, ymin, xxmax, ymin, "y", how, "Q",
+ }
+ elseif method == 23 then
+ list = {
+ "q", line, "w", xmax, yymin, "m", xmax, ymin, xxmax, ymin, "y", xxmin, ymin, "m",
+ xmin, ymin, xmin, yymin, "y", how, "Q",
+ }
+ elseif method == 24 then
+ list = {
+ "q", line, "w", xxmin, ymin, "m", xmin, ymin, xmin, yymin, "y", xmin, yymax, "m",
+ xmin, ymax, xxmin, ymax, "y", how, "Q",
+ }
+ elseif method == 25 then
+ list = {
+ "q", line, "w", xxmax, ymax, "m", xmax, ymax, xmax, yymax, "y", xmax, yymin, "m",
+ xmax, ymin, xxmax, ymin, "y", xxmin, ymin, "m", xmin, ymin, xmin, yymin, "y",
+ xmin, yymax, "m", xmin, ymax, xxmin, ymax, "y", how, "Q",
+ }
+ elseif method == 26 then
+ list = {
+ "q", line, "w", xmax, yymin, "m", xmax, ymin, xxmax, ymin, "y", xmin, yymax, "m",
+ xmin, ymax, xxmin, ymax, "y", how, "Q",
+ }
+
+ elseif method == 27 then
+ list = {
+ "q", line, "w", xxmax, ymax, "m", xmax, ymax, xmax, yymax, "y", xxmin, ymin, "m",
+ xmin, ymin, xmin, yymin, "y", how, "Q",
+ }
+ end
+ pdfprint("direct",concat(list," "))
+ end
+ end
- directives.register("metapost.stripzeros",function() -- confusing name but ok
- f_rectangle = formatters["%.6N w %.6N %.6N %.6N %.6N re %s"]
- f_baselined = formatters["%.6N w %.6N %.6N %.6N %.6N re s %.6N %.6N m %.6N %.6N l s"]
- f_dashlined = formatters["%.6N w %.6N %.6N %.6N %.6N re s [%.6N %.6N] 2 d %.6N %.6N m %.6N %.6N l s"]
- f_radtangle = formatters[
+ local f_rectangle = formatters["%.6N w %.6N %.6N %.6N %.6N re %s"]
+ local f_baselined = formatters["%.6N w %.6N %.6N %.6N %.6N re s %.6N %.6N m %.6N %.6N l s"]
+ local f_dashlined = formatters["%.6N w %.6N %.6N %.6N %.6N re s [%.6N %.6N] 2 d %.6N %.6N m %.6N %.6N l s"]
+ local f_radtangle = formatters[
[[%.6N w %.6N %.6N m
%.6N %.6N l %.6N %.6N %.6N %.6N y
%.6N %.6N l %.6N %.6N %.6N %.6N y
@@ -169,33 +336,34 @@ h %s]]
%.6N %.6N l %.6N %.6N %.6N %.6N y
h %s]]
]
- end)
ruleactions.fill = function(p,h,v,i,n)
- local l = (p.line or 65536)*bpfactor
- local r = p and (p.radius or 0)*bpfactor or 0
- local w = h * bpfactor
- local h = v * bpfactor
- local m = nil
- local t = i == "fill" and "f" or "s"
- local o = l / 2
- if r > 0 then
- w = w - o
- h = h - o
- m = f_radtangle(l, r,o, w-r,o, w,o,w,r, w,h-r, w,h,w-r,h, r,h, o,h,o,h-r, o,r, o,o,r,o, t)
+ if p.corner then
+ return round(p,i)
else
- w = w - l
- h = h - l
- m = f_rectangle(l,o,o,w,h,t)
+ local l = (p.line or 65536)*bpfactor
+ local r = p and (p.radius or 0)*bpfactor or 0
+ local w = h * bpfactor
+ local h = v * bpfactor
+ local m = nil
+ local t = i == "fill" and "f" or "s"
+ local o = l / 2
+ if r > 0 then
+ w = w - o
+ h = h - o
+ m = f_radtangle(l, r,o, w-r,o, w,o,w,r, w,h-r, w,h,w-r,h, r,h, o,h,o,h-r, o,r, o,o,r,o, t)
+ else
+ w = w - l
+ h = h - l
+ m = f_rectangle(l,o,o,w,h,t)
+ end
+ pdfprint("direct",m)
end
- pdfprint("direct",m)
end
ruleactions.draw = ruleactions.fill
ruleactions.stroke = ruleactions.fill
- local getwhd = nodes.nuts.getwhd
-
ruleactions.box = function(p,h,v,i,n)
local w, h, d = getwhd(n)
local line = p.line or 65536
@@ -231,22 +399,17 @@ interfaces.implement {
{ "type", "string" },
{ "data", "string" },
{ "name", "string" },
+ { "radius", "dimension" },
+ { "corner", "string" },
} } ,
actions = function(t)
- -- no nuts !
local rule = userrule(t)
- local ma = getattribute(a_colormodel) or 1
- local ca = getattribute(a_color)
- local ta = getattribute(a_transparency)
- setattrlist(rule,true)
if t.type == "mp" then
- t.ma = ma
- t.ca = ca
- t.ta = ta
+ t.ma = getattribute(a_colormodel) or 1
+ t.ca = getattribute(a_color)
+ t.ta = getattribute(a_transparency)
else
- setattr(rule,a_colormodel,ma)
- setattr(rule,a_color,ca)
- setattr(rule,a_transparency,ta)
+ setattrlist(rule,true)
end
context(tonode(rule)) -- will become context.nodes.flush
end
@@ -306,5 +469,3 @@ interfaces.implement {
context(tonode(rule))
end
}
-
-
diff --git a/Master/texmf-dist/tex/context/base/mkiv/grph-trf.mkiv b/Master/texmf-dist/tex/context/base/mkiv/grph-trf.mkiv
index 35e812b3edb..f9218036c33 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/grph-trf.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/grph-trf.mkiv
@@ -139,7 +139,7 @@
%
\d_grph_scale_dp\dp\nextbox
\ifx\p_depth\v!no \ifzeropt\d_grph_scale_dp \else
- \setbox\nextbox\hpack{\raise\d_grph_scale_dp\box\nextbox}% new
+ \setbox\nextbox\naturalhpack{\raise\d_grph_scale_dp\box\nextbox}% new
\d_grph_scale_dp\dp\nextbox
\fi \fi
\d_grph_scale_wd\wd\nextbox
@@ -168,7 +168,7 @@
% {\d_grph_scale_wd\finalscaleboxxscale\d_grph_scale_wd
% \d_grph_scale_ht\finalscaleboxyscale\d_grph_scale_ht
% \d_grph_scale_dp\finalscaleboxyscale\d_grph_scale_dp
-% \setbox\nextbox\hpack
+% \setbox\nextbox\naturalhpack
% {\dostartscaling \finalscaleboxxscale \finalscaleboxyscale
% \smashedbox\nextbox
% \dostopscaling}%
@@ -195,7 +195,7 @@
\fi}
\def\grph_scale_apply_yes
- {\setbox\nextbox\hpack
+ {\setbox\nextbox\naturalhpack
{\dostartscaling \finalscaleboxxscale \finalscaleboxyscale
\smashedbox\nextbox
\dostopscaling}%
@@ -567,13 +567,13 @@
{\ifx\p_equalwidth\empty \else
\scratchdimen\p_equalwidth\relax
\ifdim\d_grph_scale_wd<\scratchdimen
- \setbox\nextbox\hpack to \scratchdimen{\hss\box\nextbox\hss}%
+ \setbox\nextbox\naturalhpack to \scratchdimen{\hss\box\nextbox\hss}%
\fi
\fi
\ifx\p_equalheight\empty \else
\scratchdimen\p_equalheight\relax
\ifdim\d_grph_scale_ht<\scratchdimen
- \setbox\nextbox\vpack to \scratchdimen{\vss\box\nextbox\vss}%
+ \setbox\nextbox\naturalvpack to \scratchdimen{\vss\box\nextbox\vss}%
\fi
\fi}
@@ -603,8 +603,18 @@
\edef\p_sy{#2}%
\dowithnextboxcs\grph_scale_fast_sx_xy_finish\hbox}
+% \def\grph_scale_fast_sx_xy_finish
+% {\grph_scale_check_sx_sy
+% \grph_scale_calculations_nop
+% \grph_scale_apply
+% \box\nextbox
+% \egroup}
+
\def\grph_scale_fast_sx_xy_finish
{\grph_scale_check_sx_sy
+ \d_grph_scale_wd\wd\nextbox
+ \d_grph_scale_ht\ht\nextbox
+ \d_grph_scale_dp\dp\nextbox
\grph_scale_calculations_nop
\grph_scale_apply
\box\nextbox
@@ -677,7 +687,7 @@
\scratchheight\clippingparameter\c!sy\scratchheight
\advance\scratchyoffset \ht\nextbox
\fi
- \setbox\nextbox\hpack
+ \setbox\nextbox\naturalhpack
{\advance\scratchxoffset -\clippingparameter\c!leftoffset \relax
\advance\scratchyoffset -\clippingparameter\c!bottomoffset\relax
\hskip-\scratchxoffset
@@ -686,13 +696,13 @@
\wd\nextbox\zeropoint
\ht\nextbox\zeropoint
\dp\nextbox\zeropoint
- \setbox\nextbox\hpack
+ \setbox\nextbox\naturalhpack
{\advance\scratchwidth \dimexpr\clippingparameter\c!leftoffset +\clippingparameter\c!rightoffset\relax
\advance\scratchheight\dimexpr\clippingparameter\c!bottomoffset+\clippingparameter\c!topoffset \relax
\dostartclipping{\clippingparameter\c!mp}\scratchwidth\scratchheight
\box\nextbox
\dostopclipping}%
- \setbox\nextbox\hpack
+ \setbox\nextbox\naturalhpack
{\hskip-\clippingparameter\c!leftoffset
\lower \clippingparameter\c!bottomoffset
\box\nextbox}%
@@ -750,7 +760,11 @@
{\scratchdimen\wd\nextbox
% better use an hbox (if no \forgetall, leftskip etc may creep in)
%\setbox\nextbox\vbox{\forgetall\dostartmirroring\hskip-\wd\nextbox\box\nextbox\dostopmirroring}%
- \setbox\nextbox\hpack{\dostartmirroring\hskip-\wd\nextbox\box\nextbox\dostopmirroring}%
+ \setbox\nextbox\naturalhpack
+ {\dostartmirroring
+ \hskip-\wd\nextbox
+ \box\nextbox
+ \dostopmirroring}%
\wd\nextbox\scratchdimen
\box\nextbox
\egroup}
@@ -898,7 +912,7 @@
\egroup}
\def\grph_rotate_finish_indeed
- {\hpack\bgroup
+ {\naturalhpack\bgroup
\ifx\p_rotation_rotation\empty
\grph_rotate_finish_nop
\else
@@ -910,10 +924,10 @@
{\boxcursor\box\nextbox}
\setvalue{\??rotatepreset\v!left}%
- {\edef\p_rotation_rotation{\doifelseoddpage{90}{270}}}
+ {\edef\p_rotation_rotation{90}}
\setvalue{\??rotatepreset\v!right}%
- {\edef\p_rotation_rotation{\doifelseoddpage{270}{90}}}
+ {\edef\p_rotation_rotation{270}}
\setvalue{\??rotatepreset\v!inner}%
{\signalrightpage
@@ -924,25 +938,23 @@
\doifelserightpage{\def\p_rotation_rotation{90}}{\def\p_rotation_rotation{270}}}
\setvalue{\??rotatepreset\v!default}%
- {\edef\p_rotation_rotation{\realnumber{\p_rotation_rotation}}}% get rid of leading zeros and spaces
+ {}
\def\grph_rotate_finish_yes
- {\csname\??rotatepreset
- \ifcsname\??rotatepreset\p_rotation_rotation\endcsname\p_rotation_rotation\else\v!default\fi
- \endcsname
- \setbox\nextbox\vpack{\box\nextbox}% not really needed
+ {\begincsname\??rotatepreset\p_rotation_rotation\endcsname
+ \setbox\nextbox\naturalvpack{\box\nextbox}% not really needed
\dontcomplain
\ifconditional\c_grph_rotate_center
\d_grph_rotate_saved_width \wd\nextbox
\d_grph_rotate_saved_height\ht\nextbox
\d_grph_rotate_saved_depth \dp\nextbox
- \setbox\nextbox\vpack{\vskip.5\ht\nextbox\hskip-.5\wd\nextbox\box\nextbox}%
+ \setbox\nextbox\naturalvpack{\vskip.5\ht\nextbox\hskip-.5\wd\nextbox\box\nextbox}%
\smashbox\nextbox
\fi
\d_grph_rotate_width \wd\nextbox
\d_grph_rotate_height\ht\nextbox
\d_grph_rotate_depth \dp\nextbox
- \setbox\nextbox\vpack{\hpack{\raise\dp\nextbox\box\nextbox}}%
+ \setbox\nextbox\naturalvpack{\naturalhpack{\raise\dp\nextbox\box\nextbox}}%
\d_grph_rotate_used_height \ht\nextbox
% much of the next happens in lua (all the sin and cos) so we can do that in
% one go if needed
@@ -973,7 +985,7 @@
\fi\fi
\fi
\ifconditional\c_grph_rotate_center
- \setbox\nextbox\vpack{\vskip-.5\d_grph_rotate_saved_height\hskip.5\d_grph_rotate_saved_height\box\nextbox}%
+ \setbox\nextbox\naturalvpack{\vskip-.5\d_grph_rotate_saved_height\hskip.5\d_grph_rotate_saved_height\box\nextbox}%
\wd\nextbox\d_grph_rotate_saved_width
\ht\nextbox\d_grph_rotate_saved_height
\dp\nextbox\d_grph_rotate_saved_depth
@@ -1039,9 +1051,9 @@
\fi}
\def\grph_rotate_apply
- {\setbox\nextbox\vpack to \d_grph_rotate_y_size
+ {\setbox\nextbox\naturalvpack to \d_grph_rotate_y_size
{\vfill
- \hpack to \d_grph_rotate_x_size
+ \naturalhpack to \d_grph_rotate_x_size
{\dostartrotation\p_rotation_rotation
\wd\nextbox\zeropoint
\ht\nextbox\zeropoint
@@ -1049,7 +1061,7 @@
\dostoprotation
\hfill}%
\kern\d_grph_rotate_y_position}%
- \setbox\nextbox\hpack
+ \setbox\nextbox\naturalhpack
{\kern\dimexpr\d_grph_rotate_x_position+\d_grph_rotate_x_offset\relax
\lower\d_grph_rotate_y_offset\box\nextbox}}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/hand-ini.mkiv b/Master/texmf-dist/tex/context/base/mkiv/hand-ini.mkiv
index f678a88da40..dc6d1b19829 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/hand-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/hand-ini.mkiv
@@ -60,11 +60,12 @@
\def\font_expansion_enable {\normaladjustspacing\plusthree}
\def\font_expansion_enable_k{\normaladjustspacing\plustwo}
-\def\font_expansion_enable_n{\normaladjustspacing\plusone}
+%def\font_expansion_enable_n{\normaladjustspacing\plusone}
\def\font_expansion_disable {\normaladjustspacing\zerocount}
-\def\font_protruding_enable {\normalprotrudechars\plustwo }
-\def\font_protruding_disable{\normalprotrudechars\zerocount}
+\def\font_protruding_enable_b{\normalprotrudechars\plusthree} % also deal with r2l (experimental lmtx)
+\def\font_protruding_enable {\normalprotrudechars\plustwo }
+\def\font_protruding_disable {\normalprotrudechars\zerocount}
\appendtoks \font_expansion_disable \to \everyforgetall % Here or not here?
\appendtoks \font_protruding_disable \to \everyforgetall % Here or not here?
diff --git a/Master/texmf-dist/tex/context/base/mkiv/hand-ini.mkxl b/Master/texmf-dist/tex/context/base/mkiv/hand-ini.mkxl
new file mode 100644
index 00000000000..ca6922dddeb
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/hand-ini.mkxl
@@ -0,0 +1,111 @@
+%D \module
+%D [ file=hand-ini,
+%D version=2008.02.12,
+%D title=\CONTEXT\ Handling Macros,
+%D subtitle=Initialization,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D Handling is implemented differently in \MKIV. Maybe I'll cook up
+%D some compatibility hack.
+
+% \definefontfeature[demo][default][mode=node,expansion=quality]
+% \definefontfeature[demo][default][mode=node,protrusion=pure]
+
+% experimental setup:
+%
+% \showframe \setupalign[hanging] \enabletrackers[fonts.protrusion]
+%
+% \definefontfeature[default] [default][mode=node,script=latn]
+% %definefontfeature[whatever][default][mode=node,lfbd=yes,rtbd=yes,script=latn]
+% \definefontfeature[whatever][default][mode=node,protrusion=quality]
+% \definefontfeature[whocares][default][mode=node,protrusion=yes,opbd=yes,script=latn] % left|right|yes
+%
+% \definedfont[fxlbi.otf*default] \input tufte 0123456789 \par \dorecurse{15}{1 2 3 4 5 6 7 8 9 0 } \par
+% \definedfont[fxlbi.otf*whatever] \input tufte 0123456789 \par \dorecurse{15}{1 2 3 4 5 6 7 8 9 0 } \par
+% \definedfont[fxlbi.otf*whocares] \input tufte 0123456789 \par \dorecurse{15}{1 2 3 4 5 6 7 8 9 0 } \par
+%
+% %definefontfeature[whocares][default][mode=node,protrusion=2,opbd=yes,script=latn,featurefile=texgyrepagella-regularxx.fea]
+% \definefontfeature[whocares][default][mode=node,protrusion=2,opbd=yes,script=latn]
+%
+% \definedfont[texgyrepagella-regularxx.otf*whocares] \input tufte
+
+\unprotect
+
+%D New stuff.
+
+\unexpanded\def\setupfontexpansion {\dodoubleargument\font_expansion_setup }
+\unexpanded\def\setupfontprotrusion{\dodoubleargument\font_protrusion_setup}
+
+\def\font_expansion_setup [#1][#2]{\clf_setupfontexpansion {#1}{#2}}
+\def\font_protrusion_setup[#1][#2]{\clf_setupfontprotrusion{#1}{#2}}
+
+% \setupfontprotrusion[quality-upright][vector=quality]
+% \setupfontprotrusion[quality-slanted][vector=quality,right=1.5]
+
+\let\adjustspacing\relax \newcount\adjustspacing % a little bit protection
+\let\protrudechars\relax \newcount\protrudechars % a little bit protection
+
+% at some point we can introduce extreme expansion, i.e. \normaladjustspacing\plustwo
+
+% 0 = disabled
+% 1 = notused (thesis)
+% 2 = glyph + kern
+% 3 = glyph only
+
+\def\font_expansion_enable {\normaladjustspacing\plusthree}
+\def\font_expansion_enable_k{\normaladjustspacing\plustwo}
+%def\font_expansion_enable_n{\normaladjustspacing\plusone}
+\def\font_expansion_disable {\normaladjustspacing\zerocount}
+
+\def\font_protruding_enable_b{\normalprotrudechars\plusthree} % also deal with r2l (experimental lmtx)
+\def\font_protruding_enable {\normalprotrudechars\plustwo }
+\def\font_protruding_disable {\normalprotrudechars\zerocount}
+
+\appendtoks \font_expansion_disable \to \everyforgetall % Here or not here?
+\appendtoks \font_protruding_disable \to \everyforgetall % Here or not here?
+
+% \def\fonthandlingerror{\writestatus\m!fonts{font handling is replaced by features in mkiv}}
+%
+% \let\fonthandling\empty
+%
+% \unexpanded\def\startfonthandling #1{\fonthandlingerror\fonthandlingerror\gobbleuntil\stopfonthandling} % can't happen
+% \unexpanded\def\definefonthandling {\dotripleempty\dodefinefonthandling}
+% \unexpanded\def\setupfonthandling {\dodoubleempty\dosetupfonthandling }
+% \def\dodefinefonthandling[#1][#2][#3]{\fonthandlingerror}
+% \def\dosetupfonthandling [#1][#2]{\fonthandlingerror}
+% \def\usehandling [#1]{\fonthandlingerror}
+
+\installcorenamespace{expansion}
+
+\installcommandhandler \??expansion {expansion} \??expansion
+
+\appendtoks
+ \setuevalue{\??expansion:\currentexpansion}%
+ {\adjustspacingstep \expansionparameter\c!step\relax
+ \adjustspacingstretch\expansionparameter\c!stretch\relax
+ \adjustspacingshrink \expansionparameter\c!shrink\relax}%
+\to \everydefineexpansion
+
+\defineexpansion
+ [\c!step=1,
+ \c!stretch=40,
+ \c!shrink=20]
+
+% \defineexpansion
+% [myexpansion]
+% [\c!stretch=50,
+% \c!shrink=20]
+
+\unexpanded\def\setexpansion
+ {\dosingleempty\font_expansion_set}
+
+\unexpanded\def\font_expansion_set[#1]%
+ {\begincsname\??expansion:#1\endcsname}
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/java-ini.lua b/Master/texmf-dist/tex/context/base/mkiv/java-ini.lua
index b41b065e89d..ebe51d15ee8 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/java-ini.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/java-ini.lua
@@ -199,6 +199,7 @@ function javascripts.flushpreambles()
end
local patterns = {
+ CONTEXTLMTXMODE > 0 and "java-imp-%s.mkxl" or "",
"java-imp-%s.mkiv",
"java-imp-%s.tex",
-- obsolete:
@@ -207,12 +208,8 @@ local patterns = {
}
local function action(name,foundname)
- context.startnointerference()
- context.startreadingfile()
- context.input(foundname)
+ commands.loadlibrary(name,foundname,true)
status_javascripts("loaded: library %a",name)
- context.stopreadingfile()
- context.stopnointerference()
end
local function failure(name)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/l-file.lua b/Master/texmf-dist/tex/context/base/mkiv/l-file.lua
index 1b039a43866..d0af94f09d4 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/l-file.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/l-file.lua
@@ -76,17 +76,27 @@ local P, R, S, C, Cs, Cp, Cc, Ct = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpeg
local attributes = lfs.attributes
function lfs.isdir(name)
- return attributes(name,"mode") == "directory"
+ if name then
+ return attributes(name,"mode") == "directory"
+ end
end
function lfs.isfile(name)
- local a = attributes(name,"mode")
- return a == "file" or a == "link" or nil
+ if name then
+ local a = attributes(name,"mode")
+ return a == "file" or a == "link" or nil
+ end
end
function lfs.isfound(name)
- local a = attributes(name,"mode")
- return (a == "file" or a == "link") and name or nil
+ if name then
+ local a = attributes(name,"mode")
+ return (a == "file" or a == "link") and name or nil
+ end
+end
+
+function lfs.modification(name)
+ return name and attributes(name,"modification") or nil
end
if sandbox then
diff --git a/Master/texmf-dist/tex/context/base/mkiv/l-gzip.lua b/Master/texmf-dist/tex/context/base/mkiv/l-gzip.lua
index 5100e47222c..f141b5ebbbe 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/l-gzip.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/l-gzip.lua
@@ -5,50 +5,176 @@ if not modules then modules = { } end modules ['l-gzip'] = {
license = "see context related readme files"
}
-if not gzip then
+-- We only have a few official methods here:
+--
+-- local decompressed = gzip.load (filename)
+-- local resultsize = gzip.save (filename,compresslevel)
+-- local compressed = gzip.compress (str,compresslevel)
+-- local decompressed = gzip.decompress (str)
+-- local iscompressed = gzip.compressed (str)
+-- local suffix, okay = gzip.suffix (filename)
+--
+-- In LuaMetaTeX we have only xzip which implements a very few methods:
+--
+-- compress (str,level,method,window,memory,strategy)
+-- decompress (str,window)
+-- adler32 (str,checksum)
+-- crc32 (str,checksum)
+--
+-- Special window values are:
+--
+-- flate : - 15
+-- zlib : 15
+-- gzip : 15 | 16
+-- auto : 15 | 32
- -- no fallback yet
-
- return
+gzip = gzip or { } -- so in luatex we keep the old ones too
+if not zlib then
+ zlib = xzip -- in luametatex we shadow the old one
+elseif not xzip then
+ xzip = zlib
end
-local suffix, suffixes = file.suffix, file.suffixes
-
-function gzip.load(filename)
- local f = io.open(filename,"rb")
- if not f then
- -- invalid file
- elseif suffix(filename) == "gz" then
- f:close()
- local g = gzip.open(filename,"rb")
- if g then
- local str = g:read("*all")
- g:close()
- return str
+if zlib then
+
+ local suffix = file.suffix
+ local suffixes = file.suffixes
+ local find = string.find
+ local openfile = io.open
+
+ local gzipwindow = 15 + 16 -- +16: gzip, +32: gzip|zlib
+ local gziplevel = 3
+ local identifier = "^\x1F\x8B\x08"
+
+ local compress = zlib.compress
+ local decompress = zlib.decompress
+
+ function gzip.load(filename)
+ local f = openfile(filename,"rb")
+ if not f then
+ -- invalid file
+ else
+ local data = f:read("*all")
+ f:close()
+ if data and data ~= "" then
+ if suffix(filename) == "gz" then
+ data = decompress(data,gzipwindow)
+ end
+ return data
+ end
end
- else
- local str = f:read("*all")
- f:close()
- return str
end
-end
-function gzip.save(filename,data)
- if suffix(filename) ~= "gz" then
- filename = filename .. ".gz"
+ function gzip.save(filename,data,level)
+ if suffix(filename) ~= "gz" then
+ filename = filename .. ".gz"
+ end
+ local f = openfile(filename,"wb")
+ if f then
+ data = compress(data or "",level or gziplevel,nil,gzipwindow)
+ f:write(data)
+ f:close()
+ return #data
+ end
end
- local f = io.open(filename,"wb")
- if f then
- local s = zlib.compress(data or "",9,nil,15+16)
- f:write(s)
- f:close()
- return #s
+
+ function gzip.suffix(filename)
+ local suffix, extra = suffixes(filename)
+ local gzipped = extra == "gz"
+ return suffix, gzipped
+ end
+
+ function gzip.compressed(s)
+ return s and find(s,identifier)
+ end
+
+ function gzip.compress(s,level)
+ if s and not find(s,identifier) then -- the find check might go away
+ if not level then
+ level = gziplevel
+ elseif level <= 0 then
+ return s
+ elseif level > 9 then
+ level = 9
+ end
+ return compress(s,level or gziplevel,nil,gzipwindow) or s
+ end
+ end
+
+ function gzip.decompress(s)
+ if s and find(s,identifier) then
+ return decompress(s,gzipwindow)
+ else
+ return s
+ end
end
-end
-function gzip.suffix(filename)
- local suffix, extra = suffixes(filename)
- local gzipped = extra == "gz"
- return suffix, gzipped
end
+
+-- In luametatex we can use this one but it doesn't look like there wil be stream
+-- support so for now we still use zlib (the performance difference is not that
+-- spectacular in our usage.
+
+-- if flate then
+--
+-- local type = type
+-- local find = string.find
+--
+-- local compress = flate.gz_compress
+-- local decompress = flate.gz_decompress
+--
+-- local absmax = 128*1024*1024
+-- local initial = 64*1024
+-- local identifier = "^\x1F\x8B\x08"
+--
+-- function gzip.compressed(s)
+-- return s and find(s,identifier)
+-- end
+--
+-- function gzip.compress(s,level)
+-- if s and not find(s,identifier) then -- the find check might go away
+-- if not level then
+-- level = 3
+-- elseif level <= 0 then
+-- return s
+-- elseif level > 9 then
+-- level = 9
+-- end
+-- return compress(s,level) or s
+-- end
+-- end
+--
+-- function gzip.decompress(s,size,iterate)
+-- if s and find(s,identifier) then
+-- if type(size) ~= "number" then
+-- size = initial
+-- end
+-- if size > absmax then
+-- size = absmax
+-- end
+-- if type(iterate) == "number" then
+-- max = size * iterate
+-- elseif iterate == nil or iterate == true then
+-- iterate = true
+-- max = absmax
+-- end
+-- if max > absmax then
+-- max = absmax
+-- end
+-- while true do
+-- local d = decompress(s,size)
+-- if d then
+-- return d
+-- end
+-- size = 2 * size
+-- if not iterate or size > max then
+-- return false
+-- end
+-- end
+-- else
+-- return s
+-- end
+-- end
+--
+-- end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/l-io.lua b/Master/texmf-dist/tex/context/base/mkiv/l-io.lua
index fa3ad3c4cda..a955262a31e 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/l-io.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/l-io.lua
@@ -13,7 +13,7 @@ local concat = table.concat
----- floor = math.floor
local type = type
-if string.find(os.getenv("PATH"),";",1,true) then
+if string.find(os.getenv("PATH") or "",";",1,true) then
io.fileseparator, io.pathseparator = "\\", ";"
else
io.fileseparator, io.pathseparator = "/" , ":"
diff --git a/Master/texmf-dist/tex/context/base/mkiv/l-lpeg.lua b/Master/texmf-dist/tex/context/base/mkiv/l-lpeg.lua
index 51bc1d3df30..7979a40fb94 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/l-lpeg.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/l-lpeg.lua
@@ -295,7 +295,7 @@ patterns.longtostring = Cs(whitespace^0/"" * ((patterns.quoted + nonwhitespace^
-- return P { P(pattern) + 1 * V(1) }
-- end
-function anywhere(pattern) -- faster
+local function anywhere(pattern) -- faster
return (1-P(pattern))^0 * P(pattern)
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/l-lua.lua b/Master/texmf-dist/tex/context/base/mkiv/l-lua.lua
index 5570e83dc8d..f411230d4aa 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/l-lua.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/l-lua.lua
@@ -35,6 +35,12 @@ if LUAVERSION < 5.2 and jit then
LUAVERSION = 5.2
end
+-- this is lmtx only:
+
+-- if lua and lua.openfile then
+-- io.open = lua.openfile
+-- end
+
-- lpeg
if not lpeg then
@@ -212,7 +218,7 @@ FFISUPPORTED = type(ffi) == "table" and ffi.os ~= "" and ffi.arch ~= "" and ffi.
if not FFISUPPORTED then
- -- Maybe we should check for LUATEXENGINE but that's also a bti tricky as we still
+ -- Maybe we should check for LUATEXENGINE but that's also a bit tricky as we still
-- can have a weird ffi library laying around. Checking for presence of 'jit' is
-- also not robust. So for now we hope for the best.
@@ -253,3 +259,7 @@ if LUAVERSION > 5.3 then
-- collectgarbage("collect")
-- collectgarbage("generational") -- crashes on unix
end
+
+if status and os.setenv then
+ os.setenv("engine",string.lower(status.luatex_engine or "unknown"))
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/l-macro.lua b/Master/texmf-dist/tex/context/base/mkiv/l-macro.lua
index 24a3d07bc23..98cf20d05cb 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/l-macro.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/l-macro.lua
@@ -273,7 +273,7 @@ macros.loaded = loaded
function required(name,trace)
local filename = file.addsuffix(name,"lua")
- local fullname = resolvers and resolvers.find_file(filename) or filename
+ local fullname = resolvers and resolvers.findfile(filename) or filename
if not fullname or fullname == "" then
return false
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/l-md5.lua b/Master/texmf-dist/tex/context/base/mkiv/l-md5.lua
index 6758fa44441..9e3f7672d6b 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/l-md5.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/l-md5.lua
@@ -20,6 +20,8 @@ end
local md5, file = md5, file
local gsub = string.gsub
+local modification, isfile, touch = lfs.modification, lfs.isfile, lfs.touch
+local loaddata, savedata = io.loaddata, io.savedata
-- local gsub, format, byte = string.gsub, string.format, string.byte
--
@@ -55,10 +57,12 @@ do
end
+local md5HEX = md5.HEX
+
function file.needsupdating(oldname,newname,threshold) -- size modification access change
- local oldtime = lfs.attributes(oldname,"modification")
+ local oldtime = modification(oldname)
if oldtime then
- local newtime = lfs.attributes(newname,"modification")
+ local newtime = modification(newname)
if not newtime then
return true -- no new file, so no updating needed
elseif newtime >= oldtime then
@@ -76,34 +80,36 @@ end
file.needs_updating = file.needsupdating
function file.syncmtimes(oldname,newname)
- local oldtime = lfs.attributes(oldname,"modification")
- if oldtime and lfs.isfile(newname) then
- lfs.touch(newname,oldtime,oldtime)
+ local oldtime = modification(oldname)
+ if oldtime and isfile(newname) then
+ touch(newname,oldtime,oldtime)
end
end
-function file.checksum(name)
+local function checksum(name)
if md5 then
- local data = io.loaddata(name)
+ local data = loaddata(name)
if data then
- return md5.HEX(data)
+ return md5HEX(data)
end
end
return nil
end
+file.checksum = checksum
+
function file.loadchecksum(name)
if md5 then
- local data = io.loaddata(name .. ".md5")
+ local data = loaddata(name .. ".md5")
return data and (gsub(data,"%s",""))
end
return nil
end
function file.savechecksum(name,checksum)
- if not checksum then checksum = file.checksum(name) end
+ if not checksum then checksum = checksum(name) end
if checksum then
- io.savedata(name .. ".md5",checksum)
+ savedata(name .. ".md5",checksum)
return checksum
end
return nil
diff --git a/Master/texmf-dist/tex/context/base/mkiv/l-os.lua b/Master/texmf-dist/tex/context/base/mkiv/l-os.lua
index 15408565c34..64c7de567c4 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/l-os.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/l-os.lua
@@ -30,7 +30,7 @@ local date, time = os.date, os.time
local find, format, gsub, upper, gmatch = string.find, string.format, string.gsub, string.upper, string.gmatch
local concat = table.concat
local random, ceil, randomseed = math.random, math.ceil, math.randomseed
-local rawget, rawset, type, getmetatable, setmetatable, tonumber, tostring = rawget, rawset, type, getmetatable, setmetatable, tonumber, tostring
+local type, setmetatable, tonumber, tostring = type, setmetatable, tonumber, tostring
-- This check needs to happen real early on. Todo: we can pick it up from the commandline
-- if we pass --binpath= (which is useful anyway)
@@ -227,7 +227,10 @@ local launchers = {
}
function os.launch(str)
- execute(format(launchers[os.name] or launchers.unix,str))
+ local command = format(launchers[os.name] or launchers.unix,str)
+ -- todo: pcall
+-- print(command)
+ execute(command)
end
local gettimeofday = os.gettimeofday or os.clock
@@ -634,6 +637,14 @@ function os.validdate(year,month,day)
return year, month, day
end
+function os.date(fmt,...)
+ if not fmt then
+ -- otherwise differences between unix, mingw and msvc
+ fmt = "%Y-%m-%d %H:%M"
+ end
+ return date(fmt,...)
+end
+
local osexit = os.exit
local exitcode = nil
diff --git a/Master/texmf-dist/tex/context/base/mkiv/l-pdfview.lua b/Master/texmf-dist/tex/context/base/mkiv/l-pdfview.lua
index d2add91886e..dc3888df59f 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/l-pdfview.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/l-pdfview.lua
@@ -28,8 +28,6 @@ local allcalls -- a table with templates that close all open pdf documents
local runner -- runner function
local expander -- filename cleanup function
--- maybe spawn/execute spec in calls
-
if os.type == "windows" then
-- os.setenv("path",os.getenv("path") .. ";" .. "c:/data/system/pdf-xchange")
@@ -164,7 +162,7 @@ function pdfview.close(...)
for i=1,#t do
local name = expander(fullname(t[i]))
if io.exists(name) then
- replace(closecall,{ filename = name })
+ runner(closecall,{ filename = name })
end
end
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/l-sandbox.lua b/Master/texmf-dist/tex/context/base/mkiv/l-sandbox.lua
index c2e1753d3ab..276e54937b7 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/l-sandbox.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/l-sandbox.lua
@@ -281,20 +281,24 @@ end
loadfile = register(loadfile,"loadfile")
+if supported("lua") then
+ lua.openfile = register(lua.openfile,"lua.openfile")
+end
+
if supported("io") then
- io.open = register(io.open, "io.open")
- io.popen = register(io.popen, "io.popen") -- needs checking
- io.lines = register(io.lines, "io.lines")
- io.output = register(io.output, "io.output")
- io.input = register(io.input, "io.input")
+ io.open = register(io.open, "io.open")
+ io.popen = register(io.popen, "io.popen") -- needs checking
+ io.lines = register(io.lines, "io.lines")
+ io.output = register(io.output,"io.output")
+ io.input = register(io.input, "io.input")
end
if supported("os") then
- os.execute = register(os.execute, "os.execute")
- os.spawn = register(os.spawn, "os.spawn")
- os.exec = register(os.exec, "os.exec")
- os.rename = register(os.rename, "os.rename")
- os.remove = register(os.remove, "os.remove")
+ os.execute = register(os.execute,"os.execute")
+ os.spawn = register(os.spawn, "os.spawn")
+ os.exec = register(os.exec, "os.exec")
+ os.rename = register(os.rename, "os.rename")
+ os.remove = register(os.remove, "os.remove")
end
if supported("lfs") then
diff --git a/Master/texmf-dist/tex/context/base/mkiv/l-string.lua b/Master/texmf-dist/tex/context/base/mkiv/l-string.lua
index 8ae8d8d1d76..1dee85e2894 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/l-string.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/l-string.lua
@@ -155,11 +155,13 @@ end
--- needs checking
local anything = patterns.anything
-local allescapes = Cc("%") * S(".-+%?()[]*") -- also {} and ^$ ?
-local someescapes = Cc("%") * S(".-+%()[]") -- also {} and ^$ ?
-local matchescapes = Cc(".") * S("*?") -- wildcard and single match
+local moreescapes = Cc("%") * S(".-+%?()[]*$^{}")
+local allescapes = Cc("%") * S(".-+%?()[]*") -- also {} and ^$ ?
+local someescapes = Cc("%") * S(".-+%()[]") -- also {} and ^$ ?
+local matchescapes = Cc(".") * S("*?") -- wildcard and single match
-local pattern_a = Cs ( ( allescapes + anything )^0 )
+local pattern_m = Cs ( ( moreescapes + anything )^0 )
+local pattern_a = Cs ( ( allescapes + anything )^0 )
local pattern_b = Cs ( ( someescapes + matchescapes + anything )^0 )
local pattern_c = Cs ( Cc("^") * ( someescapes + matchescapes + anything )^0 * Cc("$") )
@@ -170,6 +172,8 @@ end
function string.topattern(str,lowercase,strict)
if str == "" or type(str) ~= "string" then
return ".*"
+ elseif strict == "all" then
+ str = lpegmatch(pattern_m,str)
elseif strict then
str = lpegmatch(pattern_c,str)
else
diff --git a/Master/texmf-dist/tex/context/base/mkiv/l-table.lua b/Master/texmf-dist/tex/context/base/mkiv/l-table.lua
index 192347b0619..c20bd4733c4 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/l-table.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/l-table.lua
@@ -6,7 +6,7 @@ if not modules then modules = { } end modules ['l-table'] = {
license = "see context related readme files"
}
-local type, next, tostring, tonumber, select = type, next, tostring, tonumber, select
+local type, next, tostring, tonumber, select, rawget = type, next, tostring, tonumber, select, rawget
local table, string = table, string
local concat, sort = table.concat, table.sort
local format, lower, dump = string.format, string.lower, string.dump
@@ -287,6 +287,37 @@ local function sortedhash(t,cmp)
return nothing
end
+-- local function iterate(t,i)
+-- local i = i + 1
+-- if i <= t.n then
+-- local k = t[i]
+-- return i, k, t.t[k]
+-- end
+-- end
+--
+-- local function indexedhash(t,cmp)
+-- if t then
+-- local s
+-- if cmp then
+-- -- it would be nice if the sort function would accept a third argument (or nicer, an optional first)
+-- s = sortedhashkeys(t,function(a,b) return cmp(t,a,b) end)
+-- else
+-- s = sortedkeys(t) -- the robust one
+-- end
+-- local m = #s
+-- if m == 1 then
+-- return next, t
+-- elseif m > 0 then
+-- s.n = m
+-- s.t = t
+-- return iterate, s, 0
+-- end
+-- end
+-- return nothing
+-- end
+--
+-- -- for i, k, v in indexedhash(t) do print(k,v,s) end
+
table.sortedhash = sortedhash
table.sortedpairs = sortedhash -- obsolete
@@ -494,84 +525,15 @@ function table.fromhash(t)
return hsh
end
-local noquotes, hexify, handle, compact, inline, functions, metacheck
+local noquotes, hexify, handle, compact, inline, functions, metacheck, accurate
local reserved = table.tohash { -- intercept a language inconvenience: no reserved words as key
'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for', 'function', 'if',
'in', 'local', 'nil', 'not', 'or', 'repeat', 'return', 'then', 'true', 'until', 'while',
- 'NaN', 'goto',
+ 'NaN', 'goto', 'const',
}
--- local function is_simple_table(t)
--- if #t > 0 then
--- local n = 0
--- for _,v in next, t do
--- n = n + 1
--- end
--- if n == #t then
--- local tt, nt = { }, 0
--- for i=1,#t do
--- local v = t[i]
--- local tv = type(v)
--- if tv == "number" then
--- nt = nt + 1
--- if hexify then
--- tt[nt] = format("0x%X",v)
--- else
--- tt[nt] = tostring(v) -- tostring not needed
--- end
--- elseif tv == "string" then
--- nt = nt + 1
--- tt[nt] = format("%q",v)
--- elseif tv == "boolean" then
--- nt = nt + 1
--- tt[nt] = v and "true" or "false"
--- else
--- return nil
--- end
--- end
--- return tt
--- end
--- end
--- return nil
--- end
-
--- local function is_simple_table(t)
--- local nt = #t
--- if nt > 0 then
--- local n = 0
--- for _,v in next, t do
--- n = n + 1
--- -- if type(v) == "table" then
--- -- return nil
--- -- end
--- end
--- if n == nt then
--- local tt = { }
--- for i=1,nt do
--- local v = t[i]
--- local tv = type(v)
--- if tv == "number" then
--- if hexify then
--- tt[i] = format("0x%X",v)
--- else
--- tt[i] = tostring(v) -- tostring not needed
--- end
--- elseif tv == "string" then
--- tt[i] = format("%q",v)
--- elseif tv == "boolean" then
--- tt[i] = v and "true" or "false"
--- else
--- return nil
--- end
--- end
--- return tt
--- end
--- end
--- return nil
--- end
-
-local function is_simple_table(t,hexify) -- also used in util-tab so maybe public
+local function is_simple_table(t,hexify,accurate) -- also used in util-tab so maybe public
local nt = #t
if nt > 0 then
local n = 0
@@ -592,6 +554,8 @@ local function is_simple_table(t,hexify) -- also used in util-tab so maybe publi
-- tt[i] = v -- not needed tostring(v)
if hexify then
tt[i] = format("0x%X",v)
+ elseif accurate then
+ tt[i] = format("%q",v)
else
tt[i] = v -- not needed tostring(v)
end
@@ -613,6 +577,8 @@ local function is_simple_table(t,hexify) -- also used in util-tab so maybe publi
-- tt[i+1] = v -- not needed tostring(v)
if hexify then
tt[i+1] = format("0x%X",v)
+ elseif accurate then
+ tt[i+1] = format("%q",v)
else
tt[i+1] = v -- not needed tostring(v)
end
@@ -707,6 +673,8 @@ local function do_serialize(root,name,depth,level,indexed)
if tv == "number" then
if hexify then
handle(format("%s 0x%X,",depth,v))
+ elseif accurate then
+ handle(format("%s %q,",depth,v))
else
handle(format("%s %s,",depth,v)) -- %.99g
end
@@ -716,7 +684,7 @@ local function do_serialize(root,name,depth,level,indexed)
if next(v) == nil then
handle(format("%s {},",depth))
elseif inline then -- and #t > 0
- local st = is_simple_table(v,hexify)
+ local st = is_simple_table(v,hexify,accurate)
if st then
handle(format("%s { %s },",depth,concat(st,", ")))
else
@@ -744,12 +712,16 @@ local function do_serialize(root,name,depth,level,indexed)
if tk == "number" then
if hexify then
handle(format("%s [0x%X]=0x%X,",depth,k,v))
+ elseif accurate then
+ handle(format("%s [%s]=%q,",depth,k,v))
else
handle(format("%s [%s]=%s,",depth,k,v)) -- %.99g
end
elseif tk == "boolean" then
if hexify then
handle(format("%s [%s]=0x%X,",depth,k and "true" or "false",v))
+ elseif accurate then
+ handle(format("%s [%s]=%q,",depth,k and "true" or "false",v))
else
handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) -- %.99g
end
@@ -758,12 +730,16 @@ local function do_serialize(root,name,depth,level,indexed)
elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
if hexify then
handle(format("%s %s=0x%X,",depth,k,v))
+ elseif accurate then
+ handle(format("%s %s=%q,",depth,k,v))
else
handle(format("%s %s=%s,",depth,k,v)) -- %.99g
end
else
if hexify then
handle(format("%s [%q]=0x%X,",depth,k,v))
+ elseif accurate then
+ handle(format("%s [%q]=%q,",depth,k,v))
else
handle(format("%s [%q]=%s,",depth,k,v)) -- %.99g
end
@@ -772,6 +748,8 @@ local function do_serialize(root,name,depth,level,indexed)
if tk == "number" then
if hexify then
handle(format("%s [0x%X]=%q,",depth,k,v))
+ elseif accurate then
+ handle(format("%s [%q]=%q,",depth,k,v))
else
handle(format("%s [%s]=%q,",depth,k,v))
end
@@ -789,6 +767,8 @@ local function do_serialize(root,name,depth,level,indexed)
if tk == "number" then
if hexify then
handle(format("%s [0x%X]={},",depth,k))
+ elseif accurate then
+ handle(format("%s [%q]={},",depth,k))
else
handle(format("%s [%s]={},",depth,k))
end
@@ -802,11 +782,13 @@ local function do_serialize(root,name,depth,level,indexed)
handle(format("%s [%q]={},",depth,k))
end
elseif inline then
- local st = is_simple_table(v,hexify)
+ local st = is_simple_table(v,hexify,accurate)
if st then
if tk == "number" then
if hexify then
handle(format("%s [0x%X]={ %s },",depth,k,concat(st,", ")))
+ elseif accurate then
+ handle(format("%s [%q]={ %s },",depth,k,concat(st,", ")))
else
handle(format("%s [%s]={ %s },",depth,k,concat(st,", ")))
end
@@ -829,6 +811,8 @@ local function do_serialize(root,name,depth,level,indexed)
if tk == "number" then
if hexify then
handle(format("%s [0x%X]=%s,",depth,k,v and "true" or "false"))
+ elseif accurate then
+ handle(format("%s [%q]=%s,",depth,k,v and "true" or "false"))
else
handle(format("%s [%s]=%s,",depth,k,v and "true" or "false"))
end
@@ -850,6 +834,8 @@ local function do_serialize(root,name,depth,level,indexed)
if tk == "number" then
if hexify then
handle(format("%s [0x%X]=load(%q),",depth,k,f))
+ elseif accurate then
+ handle(format("%s [%q]=load(%q),",depth,k,f))
else
handle(format("%s [%s]=load(%q),",depth,k,f))
end
@@ -868,6 +854,8 @@ local function do_serialize(root,name,depth,level,indexed)
if tk == "number" then
if hexify then
handle(format("%s [0x%X]=%q,",depth,k,tostring(v)))
+ elseif accurate then
+ handle(format("%s [%q]=%q,",depth,k,tostring(v)))
else
handle(format("%s [%s]=%q,",depth,k,tostring(v)))
end
@@ -896,6 +884,7 @@ local function serialize(_handle,root,name,specification) -- handle wins
if type(specification) == "table" then
noquotes = specification.noquotes
hexify = specification.hexify
+ accurate = specification.accurate
handle = _handle or specification.handle or print
functions = specification.functions
compact = specification.compact
@@ -1261,10 +1250,12 @@ function table.reverse(t) -- check with 5.3 ?
end
end
+-- This one is for really simple cases where need a hash from a table.
+
local function sequenced(t,sep,simple)
if not t then
return ""
- elseif type(t) == "string" then
+ elseif type(t) ~= "table" then
return t -- handy fallback
end
local n = #t
@@ -1305,7 +1296,11 @@ local function sequenced(t,sep,simple)
end
end
end
- return concat(s,sep or " | ")
+ if sep == true then
+ return "{ " .. concat(s,", ") .. " }"
+ else
+ return concat(s,sep or " | ")
+ end
end
table.sequenced = sequenced
diff --git a/Master/texmf-dist/tex/context/base/mkiv/l-unicode.lua b/Master/texmf-dist/tex/context/base/mkiv/l-unicode.lua
index 13e0a3fa1c1..c57aaf33ebc 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/l-unicode.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/l-unicode.lua
@@ -1081,56 +1081,62 @@ function utf.utf32_to_utf8_t(t,endian)
return endian and utf32_to_utf8_be_t(t) or utf32_to_utf8_le_t(t) or t
end
-local function little(b)
- if b < 0x10000 then
- return char(b%256,rshift(b,8))
- else
- b = b - 0x10000
- local b1 = rshift(b,10) + 0xD800
- local b2 = b%1024 + 0xDC00
- return char(b1%256,rshift(b1,8),b2%256,rshift(b2,8))
+if bit32 then
+
+ local rshift = bit32.rshift
+
+ local function little(b)
+ if b < 0x10000 then
+ return char(b%256,rshift(b,8))
+ else
+ b = b - 0x10000
+ local b1 = rshift(b,10) + 0xD800
+ local b2 = b%1024 + 0xDC00
+ return char(b1%256,rshift(b1,8),b2%256,rshift(b2,8))
+ end
end
-end
-local function big(b)
- if b < 0x10000 then
- return char(rshift(b,8),b%256)
- else
- b = b - 0x10000
- local b1 = rshift(b,10) + 0xD800
- local b2 = b%1024 + 0xDC00
- return char(rshift(b1,8),b1%256,rshift(b2,8),b2%256)
+ local function big(b)
+ if b < 0x10000 then
+ return char(rshift(b,8),b%256)
+ else
+ b = b - 0x10000
+ local b1 = rshift(b,10) + 0xD800
+ local b2 = b%1024 + 0xDC00
+ return char(rshift(b1,8),b1%256,rshift(b2,8),b2%256)
+ end
end
-end
-local l_remap = Cs((p_utf8byte/little+P(1)/"")^0)
-local b_remap = Cs((p_utf8byte/big +P(1)/"")^0)
+ local l_remap = Cs((p_utf8byte/little+P(1)/"")^0)
+ local b_remap = Cs((p_utf8byte/big +P(1)/"")^0)
-local function utf8_to_utf16_be(str,nobom)
- if nobom then
- return lpegmatch(b_remap,str)
- else
- return char(254,255) .. lpegmatch(b_remap,str)
+ local function utf8_to_utf16_be(str,nobom)
+ if nobom then
+ return lpegmatch(b_remap,str)
+ else
+ return char(254,255) .. lpegmatch(b_remap,str)
+ end
end
-end
-local function utf8_to_utf16_le(str,nobom)
- if nobom then
- return lpegmatch(l_remap,str)
- else
- return char(255,254) .. lpegmatch(l_remap,str)
+ local function utf8_to_utf16_le(str,nobom)
+ if nobom then
+ return lpegmatch(l_remap,str)
+ else
+ return char(255,254) .. lpegmatch(l_remap,str)
+ end
end
-end
-utf.utf8_to_utf16_be = utf8_to_utf16_be
-utf.utf8_to_utf16_le = utf8_to_utf16_le
+ utf.utf8_to_utf16_be = utf8_to_utf16_be
+ utf.utf8_to_utf16_le = utf8_to_utf16_le
-function utf.utf8_to_utf16(str,littleendian,nobom)
- if littleendian then
- return utf8_to_utf16_le(str,nobom)
- else
- return utf8_to_utf16_be(str,nobom)
+ function utf.utf8_to_utf16(str,littleendian,nobom)
+ if littleendian then
+ return utf8_to_utf16_le(str,nobom)
+ else
+ return utf8_to_utf16_be(str,nobom)
+ end
end
+
end
local pattern = Cs (
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lang-hyp.lua b/Master/texmf-dist/tex/context/base/mkiv/lang-hyp.lua
index 92b400d4f53..93457c7a22c 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lang-hyp.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/lang-hyp.lua
@@ -74,7 +74,7 @@ if not modules then modules = { } end modules ['lang-hyp'] = {
-- ins : when hyphenationbounds 2 or 3
-- adjust : when hyphenationbounds 2 or 3
-local type, rawset, tonumber, next = type, rawset, tonumber, next
+local type, rawget, rawset, tonumber, next = type, rawget, rawset, tonumber, next
local P, R, S, Cg, Cf, Ct, Cc, C, Carg, Cs = lpeg.P, lpeg.R, lpeg.S, lpeg.Cg, lpeg.Cf, lpeg.Ct, lpeg.Cc, lpeg.C, lpeg.Carg, lpeg.Cs
local lpegmatch = lpeg.match
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lang-ini.mkiv b/Master/texmf-dist/tex/context/base/mkiv/lang-ini.mkiv
index 296cf7f1c86..f9d7e0f510f 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lang-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/lang-ini.mkiv
@@ -195,19 +195,35 @@
\unexpanded\def\installlanguage
{\dodoubleargument\lang_basics_install}
+% \def\lang_basics_install[#1][#2]%
+% {\doifelseassignment{#2}
+% {\doifelselanguage{#1}
+% {\getparameters[\??language#1][#2]}
+% {\setvalue{\??languagelinked#1}{#1}%
+% \lang_basics_install_indeed{#1}{#1}%
+% \getparameters[\??language#1][\c!state=\v!start,#2]}%
+% \edef\currentsetuplanguage{#1}%
+% \clf_definelanguage{#1}{\specificlanguageparameter{#1}\s!default}%
+% \the\everysetuplanguage}
+% {\setvalue{\??languagelinked#1}{#2}%
+% \clf_setlanguagesynonym{#1}{#2}%
+% \lang_basics_install_indeed{#1}{#2}}}
+
\def\lang_basics_install[#1][#2]%
- {\doifelseassignment{#2}
- {\doifelselanguage{#1}
- {\getparameters[\??language#1][#2]}
- {\setvalue{\??languagelinked#1}{#1}%
- \lang_basics_install_indeed{#1}{#1}%
- \getparameters[\??language#1][\c!state=\v!start,#2]}%
- \edef\currentsetuplanguage{#1}%
- \clf_definelanguage{#1}{\specificlanguageparameter{#1}\s!default}%
- \the\everysetuplanguage}
- {\setvalue{\??languagelinked#1}{#2}%
- \clf_setlanguagesynonym{#1}{#2}%
- \lang_basics_install_indeed{#1}{#2}}}
+ {\ifcondition\validassignment{#2}%
+ \doifelselanguage{#1}
+ {\getparameters[\??language#1][#2]}
+ {\setvalue{\??languagelinked#1}{#1}%
+ \lang_basics_install_indeed{#1}{#1}%
+ \getparameters[\??language#1][\c!state=\v!start,#2]}%
+ \edef\currentsetuplanguage{#1}%
+ \clf_definelanguage{#1}{\specificlanguageparameter{#1}\s!default}%
+ \the\everysetuplanguage
+ \else
+ \setvalue{\??languagelinked#1}{#2}%
+ \clf_setlanguagesynonym{#1}{#2}%
+ \lang_basics_install_indeed{#1}{#2}%
+ \fi}
\def\lang_basics_install_indeed#1#2%
{\ifcsname#1\endcsname\else\setuvalue{#1}{\lang_basics_set_current[#2]}\fi}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lang-ini.mkxl b/Master/texmf-dist/tex/context/base/mkiv/lang-ini.mkxl
new file mode 100644
index 00000000000..8bcba01d8d0
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/lang-ini.mkxl
@@ -0,0 +1,730 @@
+%D \module
+%D [ file=lang-ini,
+%D version=1996.01.25,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Initialization,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This module needs a further cleanup (real split between ii/iv).
+
+% \cldcontext{languages.numbers[tex.count.mainlanguagenumber]}
+
+%D This module implements multi||language support of \CONTEXT, which should not be
+%D confused with the multi||lingual interface. This support will be extended when
+%D needed. Properties of languages are defined in \TEX\ files as well as \LUA\
+%D files.
+
+\writestatus{loading}{ConTeXt Language Macros / Initialization}
+
+\registerctxluafile{lang-ini}{}
+\registerctxluafile{lang-def}{}
+\registerctxluafile{lang-cnt}{}
+
+\unprotect
+
+\ifdefined\nonfrenchspacing\else \let\nonfrenchspacing\relax \fi
+\ifdefined\frenchspacing \else \let\frenchspacing \relax \fi
+
+%D When loading hyphenation patterns, \TEX\ assign a number to each loaded table,
+%D starting with~0. Switching to a specific table is done by assigning the relevant
+%D number to the predefined \COUNTER\ \type {\language}. However, in \MKIV\ a lot
+%D of management is delegated to \LUA.
+
+%D We keep track of the last loaded patterns by means of a pseudo \COUNTER. This
+%D just one of those situations in which we don't want to spent a real one. Language
+%D zero has no patterns, first of all because I like to start numbering at one. It
+%D may come in handy for special purposes as well.
+
+\normallanguage\zerocount \def\loadedlanguage{1}
+
+%D \macros
+%D {currentlanguage, setupcurrentlanguage}
+%D
+%D Instead of numbers,we are going to use symbolic names for the languages. The
+%D current langage is saved in the macro \type {\currentlanguage}. The setup macro
+%D is mainly used for cosmetic purposes.
+%D
+%D \starttyping
+%D \dorecurse{3}
+%D {\language[nl]
+%D \startmode[*en] english \stopmode
+%D \startmode[*nl] dutch \stopmode
+%D \language[en]
+%D \startmode[*en] english \stopmode
+%D \startmode[*nl] dutch \stopmode}
+%D \stoptyping
+
+\let\currentlanguage \empty
+\let\currentmainlanguage\empty
+
+%D \macros
+%D {defaultlanguage,languageparameter,specificlanguageparameter}
+%D
+%D We don't use the commandhandler here (yet) because we have a rather special
+%D fallback mechanism so quite some compatibility testing is needed.
+
+\installcorenamespace{language}
+\installcorenamespace{languagelinked}
+
+\def\currentusedlanguage{\currentlanguage}
+
+\def\defaultlanguage#1%
+ {\ifcsname\??language#1\s!default\endcsname
+ \expandafter\defaultlanguage\lastnamedcs
+ \else
+ #1%
+ \fi}
+
+\def\languageparameter#1%
+ {\ifcsname\??language\currentlanguage#1\endcsname
+ \lastnamedcs
+ \orelse\ifcsname\??language\currentlanguage\s!default\endcsname
+ \expandafter\specificlanguageparameter\lastnamedcs{#1}%
+ \orelse\ifcsname\??language\s!default#1\endcsname
+ \lastnamedcs
+ \fi}
+
+\def\specificlanguageparameter#1#2%
+ {\ifcsname\??language#1#2\endcsname
+ \lastnamedcs
+ \orelse\ifcsname\??language#1\s!default\endcsname
+ \expandafter\specificlanguageparameter\lastnamedcs{#2}%
+ \orelse\ifcsname\??language\s!default#2\endcsname
+ \lastnamedcs
+ \fi}
+
+\def\mainlanguageparameter#1%
+ {\ifcsname\??language\currentmainlanguage#1\endcsname
+ \lastnamedcs
+ \orelse\ifcsname\??language\currentmainlanguage\s!default\endcsname
+ \expandafter\specificlanguageparameter\lastnamedcs{#1}%
+ \orelse\ifcsname\??language\s!default#1\endcsname
+ \lastnamedcs
+ \fi}
+
+\let\usedlanguageparameter\languageparameter
+
+\def\askedlanguageparameter#1% assumes \currentusedlanguage being set
+ {\ifcsname\??language\currentusedlanguage#1\endcsname
+ \lastnamedcs
+ \orelse\ifcsname\??language\currentusedlanguage\s!default\endcsname
+ \expandafter\specificlanguageparameter\lastnamedcs{#1}%
+ \orelse\ifcsname\??language\s!default#1\endcsname
+ \lastnamedcs
+ \fi}
+
+\unexpanded\def\setusedlanguage#1%
+ {\edef\currentusedlanguage{\reallanguagetag{#1}}%
+ \ifx\currentusedlanguage\empty
+ \let\currentusedlanguage \currentlanguage
+ \let\usedlanguageparameter\languageparameter
+ \orelse\ifx\currentusedlanguage\v!global
+ \let\currentusedlanguage \currentmainlanguage
+ \let\usedlanguageparameter\mainlanguageparameter
+ \orelse\ifx\currentusedlanguage\v!local
+ \let\currentusedlanguage \currentlanguage
+ \let\usedlanguageparameter\languageparameter
+ \else
+ \let\usedlanguageparameter\askedlanguageparameter
+ \fi}
+
+\unexpanded\def\setupcurrentlanguage[#1]%
+ {\setcurrentlanguage\currentmainlanguage{#1}}
+
+\unexpanded\def\setcurrentlanguage#1#2% sets modes: **id (currentmain) *id (current)
+ {\edef\xaskedlanguage{#1}% otherwise clash with \askedlanguage
+ \ifx\xaskedlanguage\empty \else
+ \ifx\currentmainlanguage\empty\else\resetsystemmode{\systemmodeprefix\currentmainlanguage}\fi
+ \let\currentmainlanguage\xaskedlanguage
+ \setsystemmode{\systemmodeprefix\currentmainlanguage}%
+ \fi
+ \edef\xaskedlanguage{#2}%
+ \ifx\xaskedlanguage\empty \else
+ \ifx\currentlanguage\empty\else\resetsystemmode\currentlanguage\fi
+ \let\currentlanguage\xaskedlanguage
+ \setsystemmode\currentlanguage
+ \fi}
+
+%D The internal macros will be defined later.
+
+%D \macros
+%D {installlanguage}
+%D
+%D Hyphenation patterns can only be loaded when the format file is prepared. The
+%D next macro takes care of this loading. A language is specified with
+%D
+%D \showsetup{installlanguage}
+%D
+%D When \type {state} equals \type {start}, both patterns and additional hyphenation
+%D specifications are loaded. These files are seached for in the patterns path
+%D have names like \type {lang-nl.lua}.
+%D
+%D The \type {spacing} variable specifies how the spaces after punctuation has to be
+%D handled. English is by tradition more tolerant to inter||sentence spacing than
+%D other languages.
+%D
+%D This macro also defines \type {\identifier} as a shortcut switch to the language.
+%D Furthermore the command defined as being language specific, are executed. With
+%D \type {default} we can default to another language (patterns) at format
+%D generation time. Patterns are loaded at runtime.
+
+\newtoks \everysetuplanguage
+
+\def\installedlanguages{\clf_installedlanguages}
+
+\unexpanded\def\doifelselanguage#1%
+ {\ifcsname\??language#1\c!state\endcsname
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\let\doiflanguageelse\doifelselanguage
+
+\def\reallanguagetag#1%
+ {\ifcsname\??languagelinked#1\endcsname\lastnamedcs\else#1\fi}
+
+% \language[#1] gave unwanted side effect of loading language specifics
+
+\unexpanded\def\installlanguage
+ {\dodoubleargument\lang_basics_install}
+
+% \def\lang_basics_install[#1][#2]%
+% {\doifelseassignment{#2}
+% {\doifelselanguage{#1}
+% {\getparameters[\??language#1][#2]}
+% {\setvalue{\??languagelinked#1}{#1}%
+% \lang_basics_install_indeed{#1}{#1}%
+% \getparameters[\??language#1][\c!state=\v!start,#2]}%
+% \edef\currentsetuplanguage{#1}%
+% \clf_definelanguage{#1}{\specificlanguageparameter{#1}\s!default}%
+% \the\everysetuplanguage}
+% {\setvalue{\??languagelinked#1}{#2}%
+% \clf_setlanguagesynonym{#1}{#2}%
+% \lang_basics_install_indeed{#1}{#2}}}
+
+\def\lang_basics_install[#1][#2]%
+ {\ifcondition\validassignment{#2}%
+ \doifelselanguage{#1}
+ {\getparameters[\??language#1][#2]}
+ {\setvalue{\??languagelinked#1}{#1}%
+ \lang_basics_install_indeed{#1}{#1}%
+ \getparameters[\??language#1][\c!state=\v!start,#2]}%
+ \edef\currentsetuplanguage{#1}%
+ \clf_definelanguage{#1}{\specificlanguageparameter{#1}\s!default}%
+ \the\everysetuplanguage
+ \else
+ \setvalue{\??languagelinked#1}{#2}%
+ \clf_setlanguagesynonym{#1}{#2}%
+ \lang_basics_install_indeed{#1}{#2}%
+ \fi}
+
+\def\lang_basics_install_indeed#1#2%
+ {\ifcsname#1\endcsname\else\setuvalue{#1}{\lang_basics_set_current[#2]}\fi}
+
+%D When the second argument is a language identifier, a synonym is created. This
+%D feature is present because we used dutch mnemonics in the dutch version, but
+%D nowadays conform a standard.
+
+\unexpanded\def\doifelsepatterns#1%
+ {\begingroup % will change
+ \lang_basics_set_current[#1]%
+ \ifnum\normallanguage>\zerocount
+ \endgroup\expandafter\firstoftwoarguments
+ \else
+ \endgroup\expandafter\secondoftwoarguments
+ \fi}
+
+\let\doifpatternselse\doifelsepatterns
+
+%D \macros
+%D {setuplanguage}
+%D
+%D Quick and dirty, but useful:
+%D
+%D \showsetup{setuplanguage}
+%D
+%D Beware, this command can only be used when a language is installed.
+
+\unexpanded\def\setuplanguage
+ {\dodoubleempty\lang_basics_setup}
+
+\ifdefined\lang_basics_synchronize \else
+ \let\lang_basics_synchronize\relax % be nice for setups till we have one
+\fi
+
+\installmacrostack\currentlanguage
+
+\def\lang_basics_setup[#1][#2]%
+ {\ifsecondargument
+ \push_macro_currentlanguage % can be default
+ \edef\currentsetuplanguage{\reallanguagetag{#1}}%
+ \getparameters[\??language\currentsetuplanguage][#2]%
+ \the\everysetuplanguage
+ \pop_macro_currentlanguage
+ %\doif\currentsetuplanguage\currentlanguage we can have influenced inheritance (default)
+ \else
+ \let\currentsetuplanguage\currentlanguage
+ \getparameters[\??language\currentsetuplanguage][#1]%
+ \the\everysetuplanguage
+ \fi
+ \lang_basics_synchronize}
+
+\appendtoks
+ \clf_unloadlanguage{\currentsetuplanguage}%
+\to \everysetuplanguage
+
+\setuplanguage
+ [\s!default]
+ [\s!patterns=,
+ \s!lefthyphenmin=2,
+ \s!righthyphenmin=2,
+ \s!lefthyphenchar=-1,
+ \s!righthyphenchar=45,
+ % used in compound i.e. interfaced with c! and can be anything so no numbers
+ \c!lefthyphen=,
+ \c!righthyphen=-,
+ \c!hyphen=-,
+ \c!spacing=\v!packed,
+ \c!compoundhyphen=\compoundhyphen,
+ \c!rightcompoundhyphen=\compoundhyphen,
+ \c!leftcompoundhyphen=,
+ \c!midsentence=---,
+ \c!leftsentence=---,
+ \c!rightsentence=---,
+ \c!leftsubsentence=---,
+ \c!rightsubsentence=---,
+ \c!leftquote=\upperleftsinglesixquote,
+ \c!rightquote=\upperrightsingleninequote,
+ \c!leftquotation=\upperleftdoublesixquote,
+ \c!rightquotation=\upperrightdoubleninequote,
+ \c!leftspeech=\languageparameter\c!leftquotation,
+ \c!middlespeech=,
+ \c!rightspeech=\languageparameter\c!rightquotation,
+ \c!limittext=\unknown,
+ \c!time={h,:,m},
+ \c!date={\v!year,\ ,\v!month,\ ,\v!day},
+ \c!text=Ag,
+ \s!font=] % \v!auto : experimental !
+
+% to be tested:
+%
+% \setuplanguage
+% [\s!default]
+% [\c!righthyphenchar="AD]
+
+%D The values \type {leftsentence} and \type {rightsentence} can be (and are) used
+%D to implement automatic subsentence boundary glyphs, like in {\fr |<|french
+%D guillemots|>|} or {\de |<|german guillemots|>|} or {\nl |<|dutch dashes|>|} like
+%D situations. Furthermore \type {leftquotation} and \type {leftquote} come into
+%D view \quotation {when we quote} or \quote {quote} something.
+
+%D \macros
+%D {currentdatespecification, currenttimespecification}
+%D
+%D Just to make things easy we can ask for the current date specification by saying:
+
+\def\currentdatespecification{\languageparameter\c!date}
+\def\currenttimespecification{\languageparameter\c!time}
+
+%D Carefull reading of these macros shows that it's legal to say
+%D
+%D \starttyping
+%D \installlanguage [du] [de]
+%D \stoptyping
+
+%D \macros
+%D {language,mainlanguage}
+%D
+%D Switching to another language (actually another hyphenation pattern) is done
+%D with:
+%D
+%D \starttyping
+%D \language[identifier]
+%D \stoptyping
+%D
+%D or with \type {\identifier}. Just to be compatible with \PLAIN\ \TEX, we still
+%D support the original meaning, so
+%D
+%D \starttyping
+%D \language=1
+%D \stoptyping
+%D
+%D is a valid operation, where the relation between number and language depends on
+%D the order in installing languages.
+%D
+%D \showsetup{language}
+%D \showsetup{mainlanguage}
+%D
+%D Both commands take a predefined language identifier as argument. We can use \type
+%D {\mainlanguage[identifier]} for setting the (indeed) main language. This is the
+%D language used for translating labels like {\em figure} and {\em table}. The main
+%D language defaults to the current language.
+
+\newtoks \everylanguage
+
+\installcorenamespace{languagenumbers}
+
+\appendtoks
+ % we need to reassign the number because new patterns can be defined later on
+ % so let's hope not that many \setups happen during a run
+ \expandafter\glet\csname\??languagenumbers\currentlanguage\endcsname\undefined
+\to \everysetuplanguage
+
+\def\lang_basics_synchronize_yes
+ {\zerocount % see below
+ \global\expandafter\chardef\csname\??languagenumbers\currentlanguage\endcsname
+ \clf_languagenumber
+ {\currentlanguage}%
+ {\defaultlanguage\currentlanguage}%
+ {\languageparameter\s!patterns}%
+ {\languageparameter\c!factor}%
+ \relax
+ \normallanguage\csname\??languagenumbers\currentlanguage\endcsname}
+
+\let\lang_basics_synchronize_nop\zerocount % not loaded anyway
+
+\letvalue{\??languagenumbers}\lang_basics_synchronize_nop % initime
+
+\appendtoks
+ \letvalue{\??languagenumbers}\lang_basics_synchronize_yes % runtime
+\to \everydump
+
+\def\lang_basics_synchronize
+ {\normallanguage\csname\??languagenumbers
+ \ifcsname\??languagenumbers\currentlanguage\endcsname
+ \currentlanguage
+ \fi
+ \endcsname
+ \relax
+ \the\everylanguage
+ \relax}
+
+\newcount\hyphenstate
+\newcount\hyphenminoffset
+
+\unexpanded\def\lesshyphens
+ {\advance\hyphenminoffset\plusone
+ \lang_basics_synchronize_min_max}
+
+\unexpanded\def\morehyphens
+ {\ifcase\hyphenminoffset \else
+ \advance\hyphenminoffset\minusone
+ \fi
+ \lang_basics_synchronize_min_max}
+
+\unexpanded\def\nohyphens % nicer for url's
+ {\ifx\dohyphens\relax
+ \unexpanded\edef\dohyphens
+ {\hyphenminoffset\the\hyphenminoffset\relax
+ \lang_basics_synchronize_min_max}%
+ \fi
+ \hyphenminoffset\plusthousand
+ \lang_basics_synchronize_min_max}
+
+\let\dohyphens\relax
+
+\unexpanded\def\lang_basics_synchronize_min_max % maybe store this at the lua end
+ {% these values are stored along with glyph nodes
+ \lefthyphenmin \numexpr0\languageparameter\s!lefthyphenmin +\hyphenminoffset\relax
+ \righthyphenmin\numexpr0\languageparameter\s!righthyphenmin+\hyphenminoffset\relax
+ \hyphenationmin\numexpr0\languageparameter\s!hyphenmin\relax
+ % these values are stored with the language (global!)
+ \prehyphenchar \languageparameter\s!righthyphenchar\relax
+ \posthyphenchar\languageparameter\s!lefthyphenchar \relax}
+
+\appendtoks
+ \lang_basics_synchronize_min_max
+\to \everylanguage
+
+\unexpanded\def\unhyphenated
+ {\groupedcommand{\lefthyphenmin\maxdimen}\donothing}
+
+% \appendtoks
+% \setups[\languageparameter\c!setups]%
+% \to \everylanguage
+
+%D You can setup the default language to reset settings.
+
+\appendtoks
+ \edef\currentlanguagesetups{\languageparameter\c!setups}%
+ \ifx\currentlanguagesetups\empty \else
+ \setups[\currentlanguagesetups]%
+ \fi
+\to \everylanguage
+
+% new
+
+\appendtoks
+ \usebidiparameter\languageparameter
+\to \everylanguage
+
+% this will move to core-spa !
+
+\appendtoks
+ \edef\p_spacing{\languageparameter\c!spacing}%
+ \ifx\p_spacing\v!broad
+ \nonfrenchspacing
+ \else
+ \frenchspacing
+ \fi
+\to \everylanguage
+
+% \mainlanguage[nl] \setuplanguage[nl][lefthyphen=,righthyphen=?]
+%
+% \dorecurse{100}{dit is toch wel een heel\normalhyphendiscretionary lang\normalhyphendiscretionary woord \recurselevel\ }
+% \dorecurse{100}{dit is toch wel een heellangwoord \recurselevel\ }
+
+% new experimental feature
+
+\unexpanded\def\setuplanguages
+ {\setuplanguage[\s!default]}
+
+% \setuplanguages[\s!font=\v!auto]
+% \setuplanguage[\s!default][\s!font=\v!auto]
+% \setuplanguage[nl][\s!font=\v!auto]
+
+\appendtoks
+ \edef\p_language_font{\languageparameter\s!font}%
+ \ifx\p_language_font\empty
+ \orelse\ifx\p_language_font\v!auto
+ \doaddfeature\currentlanguage
+ \else
+ \doaddfeature\p_language_font
+ \fi
+\to \everylanguage
+
+%D Fast switcher
+
+\def\lang_basics_switch_asked
+ {\ifcsname\??languagelinked\askedlanguage\endcsname
+ \edef\askedlanguage{\lastnamedcs}%
+ \ifx\currentlanguage\askedlanguage \else
+ \setcurrentlanguage\currentmainlanguage\askedlanguage
+ \lang_basics_synchronize
+ \fi
+ \fi}
+
+\unexpanded\def\uselanguageparameter#1%
+ {\edef\askedlanguage{#1\c!language}%
+ \ifx\askedlanguage\empty\else\lang_basics_switch_asked\fi}
+
+\unexpanded\def\douselanguageparameter#1% fast setter
+ {\edef\askedlanguage{#1}%
+ \ifx\askedlanguage\empty\else\lang_basics_switch_asked\fi}
+
+\unexpanded\def\lang_basics_set_current[#1]%
+ {\edef\askedlanguage{#1}%
+ \ifx\askedlanguage\empty\else\lang_basics_switch_asked\fi}
+
+\unexpanded\def\language
+ {\doifelsenextoptionalcs\lang_basics_set_current\normallanguage}
+
+\let\setlanguage\language % we make these synonyms
+
+\let\patterns\gobbleoneargument
+
+\newcount\mainlanguagenumber
+
+%D Beware: you might need to use \type {\dontleavehmode} outside and|/|or \type {\par}
+%D inside the group!
+
+\unexpanded\def\startlanguage
+ {\begingroup\language}
+
+\let\stoplanguage\endgroup
+
+\unexpanded\def\mainlanguage[#1]%
+ {\edef\askedlanguage{#1}%
+ \ifx\askedlanguage\empty
+ \orelse\ifcsname\??languagelinked\askedlanguage\endcsname
+ %\edef\askedlanguage{\csname\??languagelinked\askedlanguage\endcsname}%
+ \edef\askedlanguage{\lastnamedcs}%
+ \ifx\currentlanguage\askedlanguage
+ \ifx\currentmainlanguage\askedlanguage \else
+ \setcurrentlanguage\askedlanguage\askedlanguage
+ \lang_basics_synchronize
+ \fi
+ \else
+ \setcurrentlanguage\askedlanguage\askedlanguage
+ \lang_basics_synchronize
+ \fi
+ \fi
+ \mainlanguagenumber\normallanguage}
+
+\appendtoks
+ \normallanguage\mainlanguagenumber
+\to \everybeforepagebody
+
+%D Used at all?
+
+\def\splitsequence#1#2%
+ {\doifelse{#1}\v!no{#2}{\doifelse{#1}\v!yes{\languageparameter\c!limittext}{#1}}}
+
+\def\splitsymbol#1%
+ {\splitsequence{#1}{\languageparameter\c!limittext}}
+
+%D Just like with subsentence boundary symbols, quotes placement depends on the
+%D current language, therefore we show the defaults here.
+%D
+%D \def\ShowLanguageValues [#1] [#2] #3 #4
+%D {\blank
+%D \startlinecorrection
+%D \vbox\bgroup
+%D \language[#1]
+%D \midaligned{\bf#2 subsentence symbol and quotes}
+%D \framed[width=\hsize,frame=off,topframe=on,bottomframe=on,offset=.5ex]
+%D {\hfil\quotation{#3 #4}\hfil\quote{#2}\hfil
+%D \startsubsentence\startsubsentence#3\stopsubsentence#4\stopsubsentence\hfil}
+%D \egroup
+%D \stoplinecorrection
+%D \blank}
+%D
+%D \ShowLanguageValues [af] [afrikaans] afrikaanse ...
+%D \ShowLanguageValues [ca] [catalan] catalan ...
+%D \ShowLanguageValues [cs] [czech] tjechisch tex
+%D \ShowLanguageValues [cs] [slovak] slowaakse ...
+%D \ShowLanguageValues [da] [danish] deense ...
+%D \ShowLanguageValues [de] [german] duitse degelijkheid
+%D \ShowLanguageValues [en] [english] engelse humor
+%D \ShowLanguageValues [et] [estonian] ...
+%D \ShowLanguageValues [fi] [finnish] finse ...
+%D \ShowLanguageValues [fr] [french] franse slag
+%D \ShowLanguageValues [it] [italian] italiaanse ...
+%D \ShowLanguageValues [la] [latin] latijnse missen
+%D \ShowLanguageValues [nl] [dutch] nederlandse zuinigheid
+%D \ShowLanguageValues [nb] [bokmal] noorse zalm
+%D \ShowLanguageValues [nn] [nnynorsk] noorse zalm
+%D \ShowLanguageValues [pl] [polish] poolse vlag
+%D \ShowLanguageValues [pt] [portuguese] portugese ...
+%D \ShowLanguageValues [es] [spanish] spaans benauwd
+%D \ShowLanguageValues [sv] [swedish] zweedse ...
+%D \ShowLanguageValues [tr] [turkish] turks fruit
+
+%D We support a lot of languages. These are specified and loaded in separate files,
+%D according to their roots. Here we only take care of (postponed) setting of the
+%D current language.
+%D
+%D \unprotect
+%D \placetable{The germanic languages (\type{lang-ger})}
+%D \starttable[||||]
+%D \HL
+%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
+%D \HL
+%D \NC \s!nl \NC dutch \NC germanic \NC\FR
+%D \NC \s!en \NC english \NC germanic \NC\MR
+%D \NC \s!de \NC german \NC germanic \NC\MR
+%D \NC \s!da \NC danish \NC germanic \NC\MR
+%D \NC \s!sv \NC swedish \NC germanic \NC\MR
+%D \NC \s!af \NC afrikaans \NC germanic \NC\MR
+%D \NC \s!nb \NC bokmal \NC germanic \NC\LR
+%D \NC \s!nn \NC nynorsk \NC germanic \NC\LR
+%D \HL
+%D \stoptable
+%D \protect
+%D
+%D \unprotect
+%D \placetable{The italic languages (\type{lang-ita})}
+%D \starttable[||||]
+%D \HL
+%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
+%D \HL
+%D \NC \s!fr \NC french \NC italic \NC\FR
+%D \NC \s!ca \NC catalan \NC italic \NC\MR
+%D \NC \s!es \NC spanish \NC italic \NC\MR
+%D \NC \s!it \NC italian \NC italic \NC\MR
+%D \NC \s!la \NC latin \NC italic \NC\MR
+%D \NC \s!pt \NC portuguese \NC italic \NC\LR
+%D \HL
+%D \stoptable
+%D \protect
+%D
+%D \unprotect
+%D \placetable{The slavic languages (\type{lang-sla})}
+%D \starttable[||||]
+%D \HL
+%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
+%D \HL
+%D \NC \s!pl \NC polish \NC slavic \NC\FR
+%D \NC \s!cs \NC czech \NC slavic \NC\MR
+%D \NC \s!sk \NC slavik \NC slavic \NC\LR
+%D \HL
+%D \stoptable
+%D \protect
+%D \unprotect
+%D
+%D \placetable{The altaic languages (\type{lang-alt})}
+%D \starttable[||||]
+%D \HL
+%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
+%D \HL
+%D \NC \s!tr \NC turkish \NC altaic \NC\SR
+%D \HL
+%D \stoptable
+%D
+%D \placetable{The uralic languages (\type{lang-ura})}
+%D \starttable[||||]
+%D \HL
+%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
+%D \HL
+%D \NC \s!fi \NC finnish \NC uralic \NC\SR
+%D \HL
+%D \stoptable
+%D \protect
+
+\unexpanded\def\nopatterns{\normallanguage\minusone}
+
+%D We default to the language belonging to the interface. This is one of the few
+%D places outside the interface modules where \type {\startinterface} is used.
+
+\setupcurrentlanguage[\s!en]
+
+\unexpanded\def\initializemainlanguage
+ {\mainlanguage[\currentlanguage]%
+ \showmessage\m!languages9\currentlanguage}
+
+%D New:
+
+\let\stopexceptions\relax
+
+\unexpanded\def\startexceptions
+ {\dosingleempty\lang_basics_start_exceptions}
+
+\def\lang_basics_start_exceptions[#1]#2\stopexceptions % multilingual or not?
+ {\begingroup
+ \edef\askedlanguage{\reallanguagetag{#1}}%
+ \ifx\askedlanguage\empty
+ \let\askedlanguage\currentlanguage
+ \fi
+ \clf_setlanguageexceptions{\askedlanguage}{#2}%
+ \endgroup}
+
+\unexpanded\def\hyphenation
+ {\clf_setlanguageexceptions{\currentlanguage}}
+
+%D For the moment here:
+
+\uchyph 1 % also treat uppercase
+\exhyphenchar 45 % to permit breaking at explicit hyphens
+
+%D New:
+
+\unexpanded\def\traceddiscretionary#1#2#3%
+ {\dontleavehmode
+ \discretionary{\darkred#1}{\darkgreen#2}{\darkblue#3}}
+
+\unexpanded\def\samplediscretionary
+ {\traceddiscretionary
+ {pre\clf_currentprehyphenchar}%
+ {\clf_currentposthyphenchar post}%
+ {replace}}
+
+% todo: make this configurable
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lang-lab.mkiv b/Master/texmf-dist/tex/context/base/mkiv/lang-lab.mkiv
index 9d73d96e589..1ae2d4c741c 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lang-lab.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/lang-lab.mkiv
@@ -24,26 +24,23 @@
\def\sixperemspace{\normalUchar"2006}
\fi
-%D In this module we deal with language dependant labels and
-%D prefixes, like in {\em Figure~12} and {\em Chapter 1}. In
-%D this file we set the default values. Users can easily
-%D overrule these.
+%D In this module we deal with language dependant labels and prefixes, like in {\em
+%D Figure~12} and {\em Chapter 1}. In this file we set the default values. Users can
+%D easily overrule these.
%D
-%D This module is dedicated to the grandfather of Tobias
-%D Burnus, who's extensive languages oriented library helped us
-%D a lot in finding the right translations. All those labels
-%D are collected in files that reflect their common ancestor.
+%D This module is dedicated to the grandfather of Tobias Burnus, who's extensive
+%D languages oriented library helped us a lot in finding the right translations. All
+%D those labels are collected in files that reflect their common ancestor.
%D
-%D Not all languages can be satisfied with the labeling
-%D mechanism as provided here. Chinese for instance put a label
-%D in front as well as after a part number. This is why the
-%D current implementation of labels supports two labels too.
+%D Not all languages can be satisfied with the labeling mechanism as provided here.
+%D Chinese for instance put a label in front as well as after a part number. This is
+%D why the current implementation of labels supports two labels too.
%D \macros
%D {setupheadtext, setuplabeltext}
%D
-%D First we present some macros that deal with what we will
-%D call head and label texts. Such texts are defines by:
+%D First we present some macros that deal with what we will call head and label
+%D texts. Such texts are defines by:
%D
%D \showsetup{setupheadtext}
%D \showsetup{setuplabeltext}
@@ -165,8 +162,8 @@
%D \macros
%D {presetheadtext,presetlabeltext}
%D
-%D These macros enable us to automatically define head and label
-%D texts without replacing predefined ones. They are internal macros.
+%D These macros enable us to automatically define head and label texts without
+%D replacing predefined ones. They are internal macros.
\appendtoks \let\labellanguage\currentlanguage \to \everycurrentdate
@@ -301,9 +298,8 @@
%D \macros
%D {translate}
%D
-%D Sometimes macros contain language specific words that are to
-%D be typeset. Such macros can be made (more) language
-%D independant by using:
+%D Sometimes macros contain language specific words that are to be typeset. Such
+%D macros can be made (more) language independant by using:
%D
%D \showsetup{translate}
%D
@@ -313,8 +309,7 @@
%D \translate[en=something,nl=iets]
%D \stoptyping
%D
-%D which expands to {\em something} or {\em iets}, depending on
-%D de current language.
+%D which expands to {\em something} or {\em iets}, depending on de current language.
\installcorenamespace{translation}
@@ -331,8 +326,8 @@
[translation #1]%
\fi\fi}
-%D When used without argument, the last defined values are
-%D used. This enables repetitive use like
+%D When used without argument, the last defined values are used. This enables
+%D repetitive use like
%D
%D \starttyping
%D \en \translate\ means \nl \translate
@@ -341,8 +336,8 @@
%D \macros
%D {assigntranslation}
%D
-%D This macro is a system macro, and can be used to assign a
-%D translation to a macro. Its form is:
+%D This macro is a system macro, and can be used to assign a translation to a macro.
+%D Its form is:
%D
%D \starttyping
%D \assigntranslation[en=something,nl=iets]\to\command
@@ -350,7 +345,7 @@
\unexpanded\def\assigntranslation[#1]\to#2% bad, this \to
{\getparameters[\??translation][#1]%
- \edef#2{\csname\??translation\currentlanguage\endcsname}}
+ \edef#2{\begincsname\??translation\currentlanguage\endcsname}}
%D \macros
%D {commalistsentence}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lang-lab.mkxl b/Master/texmf-dist/tex/context/base/mkiv/lang-lab.mkxl
new file mode 100644
index 00000000000..a527224e9dc
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/lang-lab.mkxl
@@ -0,0 +1,390 @@
+%D \module
+%D [ file=lang-lab,
+%D version=1997.08.27,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Labels,
+%D author=Hans Hagen / Tobias Burnus,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Language Macros / Labels}
+
+\registerctxluafile{lang-lab}{}
+\registerctxluafile{lang-txt}{}
+
+\unprotect
+
+%D Left-overs:
+
+\ifdefined\sixperemspace \else
+ \def\sixperemspace{\normalUchar"2006}
+\fi
+
+%D In this module we deal with language dependant labels and prefixes, like in {\em
+%D Figure~12} and {\em Chapter 1}. In this file we set the default values. Users can
+%D easily overrule these.
+%D
+%D This module is dedicated to the grandfather of Tobias Burnus, who's extensive
+%D languages oriented library helped us a lot in finding the right translations. All
+%D those labels are collected in files that reflect their common ancestor.
+%D
+%D Not all languages can be satisfied with the labeling mechanism as provided here.
+%D Chinese for instance put a label in front as well as after a part number. This is
+%D why the current implementation of labels supports two labels too.
+
+%D \macros
+%D {setupheadtext, setuplabeltext}
+%D
+%D First we present some macros that deal with what we will call head and label
+%D texts. Such texts are defines by:
+%D
+%D \showsetup{setupheadtext}
+%D \showsetup{setuplabeltext}
+%D
+%D A regular \CONTEXT\ stores some 1500 labels at most.
+%D
+%D These commands accept all kind of inputs:
+%D
+%D \starttyping
+%D \setuplabeltext [language] [labellabel=text]
+%D \setuplabeltext [language] [labellabel=text,labellabel=text,...]
+%D \setuplabeltext [labellabel=text]
+%D \setuplabeltext [labellabel=text,labellabel=text,...]
+%D \stoptyping
+%D
+%D The last two cases concern the current language.
+
+\installcorenamespace{label}
+
+\let\currentlabelcategory\empty
+
+\unexpanded\def\definelabelclass
+ {\dodoubleempty\lang_labels_define_class}
+
+\def\lang_labels_define_class[#1][#2]%
+ {\normalexpanded
+ {\lang_labels_define_class_indeed
+ {#1}%
+ {\ifsecondargument#2\else\zerocount\fi}%
+ \expandafter\noexpand\csname dogetupsome#1text\endcsname
+ \expandafter\noexpand\csname #1language\endcsname
+ \expandafter\noexpand\csname dodogetupsome#1text\endcsname
+ \expandafter\noexpand\csname left#1text\endcsname
+ \expandafter\noexpand\csname right#1text\endcsname
+ \expandafter\noexpand\csname #1texts\endcsname
+ \expandafter\noexpand\csname #1text\endcsname}}
+
+% hm, not interfaced
+
+\let\thetextprefix\empty
+
+\unexpanded\def\lang_labels_define_class_indeed#1#2#3#4#5#6#7#8#9%
+ {\setuvalue{setup#1text}{\protecttextprefixes#2\def\currenttextprefixclass{#1}\dodoubleempty\lang_labels_text_prefix_setup}%
+ \setuvalue{preset#1text}{\protecttextprefixes1\def\currenttextprefixclass{#1}\dodoubleempty\lang_labels_text_prefix_setup}%
+ \setuvalue{copy#1text}{\protecttextprefixes1\def\currenttextprefixclass{#1}\dodoubleempty\lang_labels_text_prefix_copy}%
+ \setuvalue{start#1text}{\protecttextprefixes1\def\currenttextprefixclass{#1}\dotripleempty\lang_labels_text_prefix_start[#1]}%
+ \letvalue{stop#1text}\relax
+ \def#4{\reallanguagetag{\defaultlanguage\currentmainlanguage}}%
+ \ifnum#2=\plustwo % used for math and tags
+ \def#3{#5#4}%
+ \def#5##1##2% ##1=language
+ {\ifcsname\??label\currentlabelcategory#1:##1:##2\endcsname
+ \lastnamedcs
+ \orelse\ifcsname\??label#1:##1:##2\endcsname
+ \lastnamedcs
+ % \orelse\ifcsname\??language#4\s!default\endcsname
+ % \expandafter#5\csname\??language#4\s!default\endcsname{##2}%
+ \orelse\ifcsname\??language##1\s!default\endcsname
+ %\expandafter#5\csname\??language##1\s!default\endcsname{##2}%
+ \expandafter#5\lastnamedcs{##2}%
+ \orelse\ifcsname\??label\currentlabelcategory#1:##2\endcsname
+ \lastnamedcs
+ \orelse\ifcsname\??label#1:##2\endcsname
+ \lastnamedcs
+ \orelse\ifcsname\??label\currentlabelcategory#1:\s!en:##2\endcsname
+ \lastnamedcs
+ \orelse\ifcsname\??label#1:\s!en:##2\endcsname
+ \lastnamedcs
+ \else
+ ##2%
+ \fi}%
+ \let#6\gobbleoneargument
+ \let#7\gobbleoneargument
+ \let#8\gobbletwoarguments
+ \let#9#3%
+ \else
+ \unexpanded\def#3{#5#4}%
+ \unexpanded\def#5##1##2%
+ {\ifcsname\??label#1:##1:##2\endcsname
+ %\expandafter\let\expandafter\thetextprefix\csname\??label#1:##1:##2\endcsname
+ \expandafter\let\expandafter\thetextprefix\lastnamedcs
+ \orelse\ifcsname\??language#4\s!default\endcsname
+ %\expandafter#5\csname\??language#4\s!default\endcsname{##2}%
+ \expandafter#5\lastnamedcs{##2}%
+ \orelse\ifcsname\??label#1:##2\endcsname
+ %\expandafter\let\expandafter\thetextprefix\csname\??label#1:##2\endcsname
+ \expandafter\let\expandafter\thetextprefix\lastnamedcs
+ \orelse\ifcsname\??label#1:\s!en:##2\endcsname
+ %\expandafter\let\expandafter\thetextprefix\csname\??label#1:\s!en:##2\endcsname
+ \expandafter\let\expandafter\thetextprefix\lastnamedcs
+ \else
+ \let\thetextprefix\dummytextprefix
+ \fi}%
+ \unexpanded\def#6##1{#3{##1}\expandafter\flushleftlabelclass \thetextprefix}%
+ \unexpanded\def#7##1{#3{##1}\expandafter\flushrightlabelclass\thetextprefix}%
+ \unexpanded\def#8##1{#3{##1}\expandafter\flushbothlabelclass \thetextprefix}% #2
+ \unexpanded\def#9##1{#3{##1}\expandafter\flushleftlabelclass \thetextprefix}%
+ \fi
+ \appendtoks
+ \let#6\firstofoneargument % to be checked
+ \let#7\firstofoneargument % to be checked
+ \let#8\firstofoneargument % to be checked
+ \let#9\firstofoneargument % to be checked
+ \to \everysimplifycommands}
+
+\let\flushleftlabelclass \firstoftwoarguments
+\let\flushrightlabelclass\secondoftwoarguments
+\def\flushbothlabelclass #1#2#3{#1#3#2}
+\def\dummytextprefix {\empty\empty}
+
+%D \macros
+%D {headtext, labeltext, leftlabeltext, rightlabeltext, labeltexts}
+%D
+%D Once defined, head and label texts can be called upon using:
+%D
+%D \showsetup{headtext}
+%D \showsetup{labeltext}
+%D
+%D \macros
+%D {presetheadtext,presetlabeltext}
+%D
+%D These macros enable us to automatically define head and label texts without
+%D replacing predefined ones. They are internal macros.
+
+\appendtoks \let\labellanguage\currentlanguage \to \everycurrentdate
+
+\newconstant\protecttextprefixes
+
+\let\currenttextprefixtag \s!unknown
+\let\currenttextprefixclass\s!unknown
+
+\def\lang_labels_text_prefix_start[#1][#2][#3]% class language name
+ {\ifthirdargument
+ \edef\currenttextprefixtag{\reallanguagetag{#2}}%
+ \edef\currenttextprefixname{#3}%
+ \else
+ \edef\currenttextprefixtag{\reallanguagetag\currentmainlanguage}%
+ \edef\currenttextprefixname{#2}%
+ \fi
+ \grabuntil{stop#1text}\lang_labels_text_prefix_start_indeed}
+
+\def\lang_labels_text_prefix_start_indeed#1% text (not special checking done here yet, only for long texts anyway)
+ {\expandafter\edef\csname\??label\currenttextprefixclass:\currenttextprefixtag:\currenttextprefixname\endcsname%
+ {{\clf_strip{#1}}\empty}}
+
+\def\lang_labels_text_prefix_setup[#1][#2]%
+ {\ifsecondargument
+ \edef\currenttextprefixtag{\reallanguagetag{#1}}%
+ \processcommalist[#2]\lang_labels_text_prefix_setup_indeed
+ \else
+ \edef\currenttextprefixtag{\reallanguagetag\currentmainlanguage}%
+ \processcommalist[#1]\lang_labels_text_prefix_setup_indeed
+ \fi}
+
+\def\lang_labels_text_prefix_setup_indeed#1%
+ {\lang_labels_text_prefix_assign[#1]}
+
+\def\lang_labels_text_prefix_assign[#1=#2]%
+ {\lang_labels_text_prefix_assign_indeed{#1}[#2,,]}
+
+\def\lang_labels_text_prefix_assign_indeed#1%
+ {\ifcase\protecttextprefixes
+ % no checking
+ \expandafter\lang_labels_text_prefix_assign_yes
+ \or
+ % checking
+ \ifcsname\??label\currenttextprefixclass:\currenttextprefixtag:#1\endcsname
+ \expandafter\expandafter\expandafter\lang_labels_text_prefix_assign_nop
+ \else
+ \expandafter\expandafter\expandafter\lang_labels_text_prefix_assign_yes
+ \fi
+ \or
+ % simple assignment (a bit overkill but it fits in the whole)
+ \expandafter\lang_labels_text_prefix_assign_dumb
+ \fi{#1}}
+
+\let\m_lang_labels_left \empty
+\let\m_lang_labels_right\empty
+
+% \def\lang_labels_text_prefix_assign_yes#1[#2,#3,#4]%
+% {\def\m_lang_labels_left {#2}% no longer an edef ... else \Word undefined expansion issues
+% \def\m_lang_labels_right{#3}% no longer an edef ... else \Word undefined expansion issues
+% \ifx\m_lang_labels_right\empty
+% \ifx\m_lang_labels_left\empty
+% \expandafter\def\csname\??label\currenttextprefixclass:\currenttextprefixtag:#1\endcsname{\empty\empty}%
+% \else
+% \expandafter\def\csname\??label\currenttextprefixclass:\currenttextprefixtag:#1\endcsname{{#2}\empty}%
+% \fi
+% \else
+% \expandafter\def\csname\??label\currenttextprefixclass:\currenttextprefixtag:#1\endcsname{{#2}{#3}}%
+% \fi}
+%
+% how we love obscure efficicency ...
+
+\def\lang_labels_text_prefix_assign_yes#1[#2,#3,#4]%
+ {\def\m_lang_labels_left {#2}% no longer an edef ... else \Word undefined expansion issues
+ \def\m_lang_labels_right{#3}% no longer an edef ... else \Word undefined expansion issues
+ \expandafter\def\csname\??label\currenttextprefixclass:\currenttextprefixtag:#1%
+ \ifx\m_lang_labels_right\empty
+ \ifx\m_lang_labels_left\empty
+ \endcsname{\empty\empty}%
+ \else
+ \endcsname{{#2}\empty}%
+ \fi
+ \else
+ \endcsname{{#2}{#3}}%
+ \fi}
+
+\def\lang_labels_text_prefix_assign_nop#1[#2]%
+ {}
+
+\def\lang_labels_text_prefix_assign_dumb#1[#2,#3]%
+ {\expandafter\def\csname\??label\currenttextprefixclass:\currenttextprefixtag:#1\endcsname{#2}}
+
+\unexpanded\def\setlabeltextpair#1#2#3#4#5% a fast one for usage at the Lua end
+ {%\writestatus{!!!!}{#1:\reallanguagetag{#2}:#3}%
+ \expandafter\def\csname\??label#1:\reallanguagetag{#2}:#3\endcsname{{#4}{#5}}} % class tag key left right
+
+\def\lang_labels_text_prefix_copy[#1][#2]%
+ {\ifsecondargument
+ \edef\currenttextprefixtag{\reallanguagetag{#1}}%
+ \processcommalist[#2]\lang_labels_text_prefix_copy_indeed
+ \else
+ \edef\currenttextprefixtag{\reallanguagetag\currentmainlanguage}%
+ \processcommalist[#1]\lang_labels_text_prefix_copy_indeed
+ \fi}
+
+\def\lang_labels_text_prefix_copy_indeed#1%
+ {\lang_labels_text_prefix_copy_pair[#1]}
+
+\def\lang_labels_text_prefix_copy_pair[#1=#2]%
+ {\lang_labels_text_prefix_copy_pair_indeed{#1}[#2,,]}
+
+% \def\lang_labels_text_prefix_copy_pair_indeed#1[#2,#3]%
+% {\expandafter\let
+% \csname\??label\currenttextprefixclass:\currenttextprefixtag:#1\expandafter\endcsname
+% \csname\??label\currenttextprefixclass:\currenttextprefixtag:#2\endcsname}
+%
+% this delays the aliasing so that we can switch maillanguage in between
+
+\def\lang_labels_text_prefix_copy_pair_indeed#1[#2,#3]%
+ {\expandafter\edef\csname\??label\currenttextprefixclass:#1\endcsname
+ {{\noexpand\csname\??label\currenttextprefixclass:\noexpand\reallanguagetag\noexpand\currentmainlanguage:#2\endcsname}{}}}
+
+\definelabelclass [head] [0] % titles
+\definelabelclass [label] [0] % texts
+\definelabelclass [mathlabel] [0] % functions
+\definelabelclass [taglabel] [2] % tags
+
+\clf_definelabels{head}{titles}\s!true\relax
+\clf_definelabels{label}{texts}\s!true\relax
+\clf_definelabels{mathlabel}{functions}\s!false\relax
+\clf_definelabels{taglabel}{tags}\s!false\relax
+
+%D \macros
+%D {translate}
+%D
+%D Sometimes macros contain language specific words that are to be typeset. Such
+%D macros can be made (more) language independant by using:
+%D
+%D \showsetup{translate}
+%D
+%D like for instance:
+%D
+%D \starttyping
+%D \translate[en=something,nl=iets]
+%D \stoptyping
+%D
+%D which expands to {\em something} or {\em iets}, depending on de current language.
+
+\installcorenamespace{translation}
+
+\unexpanded\def\translate
+ {\dosingleempty\lang_translate}
+
+\def\lang_translate[#1]%
+ {\getparameters[\??translation][#1]%
+ \ifcsname\??translation\currentlanguage\endcsname
+ \lastnamedcs
+ \orelse\ifcsname\??translation\s!en\endcsname
+ \lastnamedcs
+ \else
+ [translation #1]%
+ \fi}
+
+%D When used without argument, the last defined values are used. This enables
+%D repetitive use like
+%D
+%D \starttyping
+%D \en \translate\ means \nl \translate
+%D \stoptyping
+
+%D \macros
+%D {assigntranslation}
+%D
+%D This macro is a system macro, and can be used to assign a translation to a macro.
+%D Its form is:
+%D
+%D \starttyping
+%D \assigntranslation[en=something,nl=iets]\to\command
+%D \stoptyping
+
+\unexpanded\def\assigntranslation[#1]\to#2% bad, this \to
+ {\getparameters[\??translation][#1]%
+ \edef#2{\begincsname\??translation\currentlanguage\endcsname}}
+
+%D \macros
+%D {commalistsentence}
+%D
+%D Redone in \LUA:
+%D
+%D \startbuffer
+%D \commalistsentence[aap,noot,mies]
+%D \commalistsentence[aap,noot]
+%D \commalistsentence[aap]
+%D \commalistsentence[a,b,c]
+%D \commalistsentence[a,b,c][{ \& },{ and }]
+%D \commalistsentence[a,b,c][+,-]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlines
+%D \getbuffer
+%D \stoplines
+
+\unexpanded\def\commalistsentence
+ {\dodoubleempty\typo_helpers_concat_comma_list}
+
+\def\typo_helpers_concat_comma_list[#1][#2]%
+ {\clf_concatcommalist
+ text {#1}%
+ separators {#2}%
+ separator {\detokenize\expandafter{\normalexpanded{\labeltext{and-1}}}}%
+ last {\detokenize\expandafter{\normalexpanded{\labeltext{and-2}}}}%
+ \relax}
+
+\setuplabeltext [\s!nl] [and-1={{, }}, and-2={{ en }}] % 1, 2 en 3
+\setuplabeltext [\s!en] [and-1={{, }}, and-2={{, }}] % 1, 2, 3
+\setuplabeltext [\s!de] [and-1={{, }}, and-2={{ und }}] % 1, 2 und 3
+\setuplabeltext [\s!hr] [and-1={{, }}, and-2={{ i }}] % 1, 2 i 3
+
+%D Goodie (handy at \LUA\ end):
+
+\unexpanded\def\LABELTEXT#1{\WORD{\labeltext{#1}}} % only for simple cases!
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lang-rep.lua b/Master/texmf-dist/tex/context/base/mkiv/lang-rep.lua
index 93509d82a3e..d0f6f6d5f24 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lang-rep.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/lang-rep.lua
@@ -34,8 +34,8 @@ local splitter = Ct((
local stripper = P("{") * Cs((1-P(-2))^0) * P("}") * P(-1)
-local trace_replacements = false trackers.register("languages.replacements", function(v) trace_replacements = v end)
-local trace_detail = false trackers.register("languages.replacements.detail", function(v) trace_detail = v end)
+local trace_replacements = false trackers.register("languages.replacements", function(v) trace_replacements = v end)
+local trace_details = false trackers.register("languages.replacements.details", function(v) trace_details = v end)
local report_replacement = logs.reporter("languages","replacements")
@@ -179,7 +179,7 @@ local function hit(a,head)
else
local final = newroot.final
if final then
- if trace_detail then
+ if trace_details then
report_replacement("hitting word %a, replacement %a",final.word,final.replacement)
end
lastrun = current
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lang-txt.lua b/Master/texmf-dist/tex/context/base/mkiv/lang-txt.lua
index d287f7e6d6c..f89795e3972 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lang-txt.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/lang-txt.lua
@@ -36,6 +36,7 @@ if not modules then modules = { } end modules ['lang-txt'] = {
-- kr Korean Jeong Dalyoung
-- la Latin ...
-- lt Lithuanian Marius Aleknevičius
+-- mk Macedonian Jakub Loula, Tomáš Hála (2019), Stojan Trajanovski
-- nb Norwegian Hans Fredrik Nordhaug, ...
-- nn Norwegian Hans Fredrik Nordhaug, ...
-- nl Dutch Hans Hagen
@@ -44,7 +45,7 @@ if not modules then modules = { } end modules ['lang-txt'] = {
-- pt Portuguese Pedro F. M. Mendonça
-- ro Romanian Dan Seracu, ...
-- ru Russian Olga Briginets, Alexander Bokovoy, Victor Figurnov, ...
--- sk Slovak ...
+-- sk Slovak Tomáš Hála (2012)
-- sl Slovenian Mojca Miklavec
-- sv Swedish ...
-- tk Turkish Tobias Burnus
@@ -64,6 +65,8 @@ local languages = languages
languages.data = languages.data or utilities.storage.allocate { }
local data = languages.data
+local hairspace = utf.char(0x200A)
+
data.labels={
["btx"]={
["In"]={
@@ -71,6 +74,7 @@ data.labels={
["en"]="In",
["es"]="En",
["fr"]="Dans",
+ ["mk"]="во",
["pe"]="در",
},
},
@@ -79,6 +83,7 @@ data.labels={
["de"]="Numer",
["en"]="Number",
["fr"]="Numéro",
+ ["mk"]="Број",
["nl"]="Nummer",
["pe"]="شماره",
},
@@ -88,6 +93,7 @@ data.labels={
["de"]="Band",
["en"]="Volume",
["et"]="Köide",
+ ["mk"]="Том",
["nl"]="Deel",
["pe"]="جلد",
},
@@ -100,6 +106,7 @@ data.labels={
["et"]="ja",
["fr"]="et",
["it"]="e",
+ ["mk"]="и",
["nl"]="en",
["pe"]="و",
},
@@ -112,6 +119,7 @@ data.labels={
["et"]="väljaanne",
["fr"]="édition",
["it"]="edizione",
+ ["mk"]="издание",
["nl"]="editie",
["pe"]="ویرایش",
},
@@ -123,6 +131,7 @@ data.labels={
["et"]="toimetaja",
["fr"]="éditeur",
["it"]="a cura di",
+ ["mk"]="уредник",
["pe"]="ویراستار",
},
},
@@ -134,6 +143,8 @@ data.labels={
["et"]="toimetajad",
["fr"]="éditeurs",
["it"]="a cura di",
+ ["mk"]="уредници",
+
},
},
["in"]={
@@ -141,6 +152,7 @@ data.labels={
["en"]="in",
["es"]="en",
["fr"]="dans",
+ ["mk"]="во",
["pe"]="در",
},
},
@@ -152,6 +164,7 @@ data.labels={
["et"]="magistritöö",
["fr"]="Thèse de master (DEA, DESS, master)",
["it"]="Tesi di laurea",
+ ["mk"]="Магистерска дисертација",
["nl"]="Masterproef",
["pe"]="پایان‌نامه کارشناسی ارشد",
},
@@ -161,6 +174,7 @@ data.labels={
["de"]="Numer",
["en"]="number",
["fr"]="numéro",
+ ["mk"]="број",
["nl"]="nummer",
["pe"]="شماره",
},
@@ -170,6 +184,7 @@ data.labels={
["de"]="von",
["en"]="of",
["fr"]="de",
+ ["mk"]="од",
["nl"]="van",
},
},
@@ -177,12 +192,14 @@ data.labels={
["labels"]={
["en"]="et al.",
["et"]="jt",
+ ["mk"]="и др.",
},
},
["p"]={
["labels"]={
["de"]="S.",
["en"]="p.",
+ ["mk"]="стр.",
["et"]="lk",
["pe"]="ص",
},
@@ -192,6 +209,7 @@ data.labels={
["de"]="Seiten",
["en"]="pages",
["et"]="leheküljed",
+ ["mk"]="страници",
["nl"]="paginas",
["pe"]="صفحات",
},
@@ -204,6 +222,7 @@ data.labels={
["et"]="Patent",
["fr"]="Brevet",
["it"]="Brevetto",
+ ["mk"]="Патент",
["nl"]="Octrooi",
},
},
@@ -215,6 +234,7 @@ data.labels={
["et"]="doktoritöö",
["fr"]="Thèse de doctorat",
["it"]="Tesi di dottorato",
+ ["mk"]="Докторска дисертација",
["nl"]="Proefschrift",
["pe"]="رساله دکتری",
},
@@ -224,6 +244,7 @@ data.labels={
["de"]="S.",
["en"]="pp.",
["et"]="lk-d",
+ ["mk"]="стр.",
["pe"]="صص",
},
},
@@ -235,6 +256,7 @@ data.labels={
["et"]="tehniline raport",
["fr"]="Rapport technique",
["it"]="Relazione tecnica",
+ ["mk"]="Технички извештај",
["nl"]="Technisch rapport",
["pe"]="گزارش فنی",
},
@@ -244,6 +266,7 @@ data.labels={
["de"]="Band",
["en"]="volume",
["et"]="köide",
+ ["mk"]="том",
["nl"]="deel",
["pe"]="جلد",
},
@@ -256,6 +279,7 @@ data.labels={
["et"]="koos",
["fr"]="avec",
["it"]="con",
+ ["mk"]="со",
["nl"]="met",
},
},
@@ -265,6 +289,7 @@ data.labels={
["labels"]={
["cz"]="P",
["en"]="Pr",
+ ["mk"]="P",
["sk"]="P",
},
},
@@ -274,6 +299,7 @@ data.labels={
["en"]="arccos",
["es"]="arc\\sixperemspace cos",
["hr"]="arc\\sixperemspace cos",
+ ["mk"]="arccos",
["pl"]="arc\\sixperemspace cos",
["sk"]="arccos",
},
@@ -284,6 +310,7 @@ data.labels={
["en"]="arccosh",
["es"]="arc\\sixperemspace cosh",
["hr"]="arc\\sixperemspace cosh",
+ ["mk"]="arccosh",
["pl"]="arc\\sixperemspace cosh",
["sk"]="arccosh",
},
@@ -294,6 +321,7 @@ data.labels={
["en"]="arccot",
["es"]="arc\\sixperemspace cot",
["hr"]="arc\\sixperemspace ctg",
+ ["mk"]="arccotg",
["pl"]="arc\\sixperemspace ctg",
["sk"]="arccotg",
},
@@ -304,6 +332,7 @@ data.labels={
["en"]="arcsin",
["es"]="arc\\sixperemspace sen",
["hr"]="arc\\sixperemspace sin",
+ ["mk"]="arcsin",
["pl"]="arc\\sixperemspace sin",
["sk"]="arcsin",
},
@@ -314,6 +343,7 @@ data.labels={
["en"]="arcsinh",
["es"]="arc\\sixperemspace senh",
["hr"]="arc\\sixperemspace sinh",
+ ["mk"]="arcsinh",
["pl"]="arc\\sixperemspace sinh",
["sk"]="arcsinh",
},
@@ -324,6 +354,7 @@ data.labels={
["en"]="arctan",
["es"]="arc\\sixperemspace tan",
["hr"]="arc\\sixperemspace tg",
+ ["mk"]="arctg",
["pl"]="arc\\sixperemspace tg",
["sk"]="arctg",
},
@@ -334,8 +365,9 @@ data.labels={
["en"]="arctanh",
["es"]="arc\\sixperemspace tanh",
["hr"]="arc\\sixperemspace tgh",
+ ["mk"]="arctgh",
["pl"]="arc\\sixperemspace tgh",
- ["sk"]="arctg",
+ ["sk"]="arctgh",
},
},
["arg"]={
@@ -343,6 +375,7 @@ data.labels={
["cz"]="arg",
["en"]="arg",
["es"]="arg",
+ ["mk"]="arg",
["sk"]="arg",
},
},
@@ -351,6 +384,7 @@ data.labels={
["cz"]="cos",
["en"]="cos",
["es"]="cos",
+ ["mk"]="cos",
["sk"]="cos",
},
},
@@ -359,6 +393,7 @@ data.labels={
["cz"]="cosh",
["en"]="cosh",
["es"]="cosh",
+ ["mk"]="cosh",
["sk"]="cosh",
},
},
@@ -368,6 +403,7 @@ data.labels={
["en"]="cot",
["es"]="cot",
["hr"]="ctg",
+ ["mk"]="ctg",
["pl"]="ctg",
["sk"]="cotg",
},
@@ -377,6 +413,7 @@ data.labels={
["cz"]="cotgh",
["en"]="coth",
["es"]="coth",
+ ["mk"]="ctgh",
["sk"]="cotgh",
},
},
@@ -385,6 +422,7 @@ data.labels={
["cz"]="cosec",
["en"]="csc",
["es"]="csc",
+ ["mk"]="cosec",
["sk"]="cosec",
},
},
@@ -394,6 +432,7 @@ data.labels={
["en"]="cot",
["es"]="cot",
["hr"]="ctg",
+ ["mk"]="ctg",
["pl"]="ctg",
["sk"]="cotg",
},
@@ -403,6 +442,7 @@ data.labels={
["cz"]="deg",
["en"]="deg",
["es"]="gr",
+ ["mk"]="deg",
["sk"]="deg",
},
},
@@ -424,6 +464,7 @@ data.labels={
["cz"]="dim",
["en"]="dim",
["es"]="dim",
+ ["mk"]="dim",
["sk"]="dim",
},
},
@@ -441,6 +482,7 @@ data.labels={
["en"]="gcd",
["es"]="mcd",
["hr"]="nzd",
+ ["mk"]="НЗД",
["nl"]="ggd",
["sk"]="NSD",
},
@@ -458,6 +500,7 @@ data.labels={
["cz"]="inf",
["en"]="inf",
["es"]="inf",
+ ["mk"]="inf",
["sk"]="inf",
},
},
@@ -483,6 +526,7 @@ data.labels={
["en"]="lcm",
["es"]="MCM",
["hr"]="nzv",
+ ["mk"]="НЗС",
["nl"]="kgv",
["sk"]="NSN",
},
@@ -492,6 +536,7 @@ data.labels={
["cz"]="log",
["en"]="lg",
["es"]="log",
+ ["mk"]="lg",
["sk"]="log",
},
},
@@ -500,6 +545,7 @@ data.labels={
["cz"]="lim",
["en"]="lim",
["es"]="lím",
+ ["mk"]="lim",
["sk"]="lim",
},
},
@@ -508,6 +554,7 @@ data.labels={
["cz"]="lim\\sixperemspace inf",
["en"]="lim\\sixperemspace inf",
["es"]="lím\\sixperemspace inf",
+ ["mk"]="lim\\sixperemspace inf",
["sk"]="lim\\sixperemspace inf",
},
},
@@ -516,6 +563,7 @@ data.labels={
["cz"]="lim\\sixperemspace sup",
["en"]="lim\\sixperemspace sup",
["es"]="lím\\sixperemspace sup",
+ ["mk"]="lim\\sixperemspace sup",
["sk"]="lim\\sixperemspace sup",
},
},
@@ -524,6 +572,7 @@ data.labels={
["cz"]="ln",
["en"]="ln",
["es"]="ln",
+ ["mk"]="ln",
["sk"]="ln",
},
},
@@ -532,6 +581,7 @@ data.labels={
["cz"]="log",
["en"]="log",
["es"]="log",
+ ["mk"]="log",
["sk"]="log",
},
},
@@ -540,6 +590,7 @@ data.labels={
["cz"]="max",
["en"]="max",
["es"]="máx",
+ ["mk"]="max",
["sk"]="max",
},
},
@@ -556,6 +607,7 @@ data.labels={
["cz"]="min",
["en"]="min",
["es"]="mín",
+ ["mk"]="min",
["sk"]="min",
},
},
@@ -564,6 +616,7 @@ data.labels={
["cz"]="mod",
["en"]="mod",
["es"]="mod",
+ ["mk"]="mod",
["sk"]="mod",
},
},
@@ -580,6 +633,7 @@ data.labels={
["cz"]="sec",
["en"]="sec",
["es"]="sec",
+ ["mk"]="sec",
["sk"]="sec",
},
},
@@ -588,6 +642,7 @@ data.labels={
["cz"]="sin",
["en"]="sin",
["es"]="sen",
+ ["mk"]="sin",
["sk"]="sin",
},
},
@@ -596,6 +651,7 @@ data.labels={
["cz"]="sinh",
["en"]="sinh",
["es"]="senh",
+ ["mk"]="sinh",
["sk"]="sinh",
},
},
@@ -604,6 +660,7 @@ data.labels={
["cz"]="sup",
["en"]="sup",
["es"]="sup",
+ ["mk"]="sup",
["sk"]="sup",
},
},
@@ -613,6 +670,7 @@ data.labels={
["en"]="tan",
["es"]="tan",
["hr"]="tg",
+ ["mk"]="tg",
["pl"]="tg",
["sk"]="tg",
},
@@ -622,11 +680,24 @@ data.labels={
["cz"]="tgh",
["en"]="tanh",
["es"]="tanh",
+ ["mk"]="tgh",
["sk"]="tgh",
},
},
},
["texts"]={
+ ["following:singular"]={
+ ["labels"]={
+ ["en"]="f.",
+ ["fr"]=hairspace .. "sq",
+ },
+ },
+ ["following:plural"]={
+ ["labels"]={
+ ["en"]="ff.",
+ ["fr"]=hairspace .. "sqq",
+ },
+ },
["and"]={
["labels"]={
["af"]="",
@@ -645,6 +716,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="",
+ ["mk"]=" и ",
["nb"]="",
["nl"]=" en ",
["nn"]="",
@@ -685,6 +757,7 @@ data.labels={
["kr"]="부록",
["la"]="",
["lt"]="",
+ ["mk"]="Додаток ",
["nb"]="Tillegg ",
["nl"]="",
["nn"]="Tillegg ",
@@ -727,6 +800,7 @@ data.labels={
["la"]="Aprilis",
["lt"]="balandžio",
["nb"]="april",
+ ["mk"]="април",
["nl"]="april",
["nn"]="april",
["pe"]="آوریل",
@@ -767,6 +841,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="apr",
+ ["mk"]="апр.",
["nb"]="april",
["nl"]="",
["nn"]="april",
@@ -802,6 +877,7 @@ data.labels={
["it"]="a pagina ",
["la"]="",
["lt"]="puslapyje ",
+ ["mk"]="на страница ",
["nb"]="på side ",
["nl"]="op pagina ",
["nn"]="på side ",
@@ -844,6 +920,7 @@ data.labels={
["kr"]="8",
["la"]="Augustus",
["lt"]="rugpjūčio",
+ ["mk"]="август",
["nb"]="august",
["nl"]="augustus",
["nn"]="august",
@@ -885,6 +962,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="aug",
+ ["mk"]="авг.",
["nb"]="aug.",
["nl"]="",
["nn"]="aug.",
@@ -924,6 +1002,7 @@ data.labels={
["kr"]={ "제", "장" },
["la"]="",
["lt"]="",
+ ["mk"]="Глава ",
["nb"]="",
["nl"]="",
["nn"]="",
@@ -959,6 +1038,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="",
+ ["mk"]=" (продолжение)",
["nb"]="",
["nl"]=" (vervolgd)",
["nn"]="",
@@ -981,6 +1061,7 @@ data.labels={
["en"]="day",
["et"]="päev",
["kr"]="일",
+ ["mk"]="ден",
["nl"]="dag",
["pe"]="روز",
},
@@ -1010,6 +1091,7 @@ data.labels={
["la"]="December",
["lt"]="gruodžio",
["nb"]="desember",
+ ["mk"]="декември",
["nl"]="december",
["nn"]="desember",
["pe"]="دسامبر",
@@ -1050,6 +1132,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="dec",
+ ["mk"]="дек.",
["nb"]="des.",
["nl"]="",
["nn"]="des.",
@@ -1090,6 +1173,7 @@ data.labels={
["kr"]="2",
["la"]="Februarius",
["lt"]="vasario",
+ ["mk"]="февруари",
["nb"]="februar",
["nl"]="februari",
["nn"]="februar",
@@ -1131,6 +1215,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="feb",
+ ["mk"]="фев.",
["nb"]="feb.",
["nl"]="",
["nn"]="feb.",
@@ -1169,6 +1254,7 @@ data.labels={
["kr"]="그림 ",
["la"]="Imago ",
["lt"]={ "", " pav." },
+ ["mk"]="Слика ",
["nb"]="Figur ",
["nl"]="Figuur ",
["nn"]="Figur ",
@@ -1190,6 +1276,7 @@ data.labels={
["labels"]={
["en"]="on a following page",
["et"]="järgmisel leheküljel",
+ ["mk"]="на следната страница",
["nl"]="op een volgende bladzijde",
["pe"]="در صفحات آینده",
},
@@ -1216,6 +1303,7 @@ data.labels={
["kr"]="금요일",
["la"]="Dies Veneris",
["lt"]="penktadienis",
+ ["mk"]="петок",
["nb"]="fredag",
["nl"]="vrijdag",
["nn"]="fredag",
@@ -1254,6 +1342,7 @@ data.labels={
["ja"]="イラスト",
["la"]="Typus ",
["lt"]="Graphic ",
+ ["mk"]="График ",
["nb"]="Bilde ",
["nl"]="Grafiek ",
["nn"]="Bilete ",
@@ -1291,6 +1380,7 @@ data.labels={
["kr"]="그러므로",
["la"]="",
["lt"]="kaip parodyta aukščiau",
+ ["mk"]="како што е прикажано погоре",
["nb"]="som vist over",
["nl"]="hierboven",
["nn"]="som vist over",
@@ -1328,6 +1418,7 @@ data.labels={
["kr"]="이후로",
["la"]="",
["lt"]="kaip parodyta žemiau",
+ ["mk"]="како што е прикажано подолу",
["nb"]="som vist under",
["nl"]="hieronder",
["nn"]="som vist under",
@@ -1367,6 +1458,7 @@ data.labels={
["kr"]="간주곡",
["la"]="Intermissum ",
["lt"]="Intermezzo ",
+ ["mk"]="Дигресија ",
["nb"]="Intermesso ",
["nl"]="Intermezzo ",
["nn"]="Intermesso ",
@@ -1407,6 +1499,7 @@ data.labels={
["kr"]="1",
["la"]="Ianuarius",
["lt"]="sausio",
+ ["mk"]="јануари",
["nb"]="januar",
["nl"]="januari",
["nn"]="januar",
@@ -1448,6 +1541,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="jan",
+ ["mk"]="jан.",
["nb"]="jan.",
["nl"]="",
["nn"]="jan.",
@@ -1489,6 +1583,7 @@ data.labels={
["kr"]="7",
["la"]="Iulius",
["lt"]="liepos",
+ ["mk"]="јули",
["nb"]="juli",
["nl"]="juli",
["nn"]="juli",
@@ -1530,6 +1625,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="jul",
+ ["mk"]="јул.",
["nb"]="juli",
["nl"]="",
["nn"]="juli",
@@ -1570,6 +1666,7 @@ data.labels={
["kr"]="6",
["la"]="Iunius",
["lt"]="birželio",
+ ["mk"]="јуни",
["nb"]="juni",
["nl"]="juni",
["nn"]="juni",
@@ -1611,6 +1708,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="jun",
+ ["mk"]="јун.",
["nb"]="juni",
["nl"]="",
["nn"]="juni",
@@ -1649,6 +1747,7 @@ data.labels={
["kr"]="행",
["la"]="versus ",
["lt"]="line ",
+ ["mk"]="линија ",
["nb"]="linje ",
["nl"]="regel ",
["nn"]="linje ",
@@ -1688,6 +1787,7 @@ data.labels={
["kr"]="행",
["la"]="versus ",
["lt"]="lines ",
+ ["mk"]="линии ",
["nb"]="linjer ",
["nl"]="regels ",
["nn"]="linjer ",
@@ -1728,6 +1828,7 @@ data.labels={
["kr"]="3",
["la"]="Martius",
["lt"]="kovo",
+ ["mk"]="март",
["nb"]="mars",
["nl"]="maart",
["nn"]="mars",
@@ -1769,6 +1870,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="mar",
+ ["mk"]="мар.",
["nb"]="mars",
["nl"]="",
["nn"]="mars",
@@ -1810,6 +1912,7 @@ data.labels={
["kr"]="5",
["la"]="Maius",
["lt"]="gegužės",
+ ["mk"]="мај",
["nb"]="mai",
["nl"]="mei",
["nn"]="mai",
@@ -1851,6 +1954,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="may",
+ ["mk"]="мај",
["nb"]="mai",
["nl"]="",
["nn"]="mai",
@@ -1889,6 +1993,7 @@ data.labels={
["kr"]="월요일",
["la"]="Dies Lunae",
["lt"]="pirmadienis",
+ ["mk"]="понеделник",
["nb"]="mandag",
["nl"]="maandag",
["nn"]="måndag",
@@ -1911,6 +2016,7 @@ data.labels={
["en"]="month",
["et"]="kuu",
["kr"]="월",
+ ["mk"]="месец",
["nl"]="maand",
["pe"]="ماه",
},
@@ -1939,6 +2045,7 @@ data.labels={
["kr"]="11",
["la"]="November",
["lt"]="lapkričio",
+ ["mk"]="ноември",
["nb"]="november",
["nl"]="november",
["nn"]="november",
@@ -1980,6 +2087,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="nov",
+ ["mk"]="ноем.",
["nb"]="nov.",
["nl"]="",
["nn"]="nov.",
@@ -2019,6 +2127,7 @@ data.labels={
["kr"]="10",
["la"]="October",
["lt"]="spalio",
+ ["mk"]="октомври",
["nb"]="oktober",
["nl"]="oktober",
["nn"]="oktober",
@@ -2060,6 +2169,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="oct",
+ ["mk"]="окт.",
["nb"]="okt.",
["nl"]="",
["nn"]="okt.",
@@ -2096,6 +2206,7 @@ data.labels={
["kr"]="쪽",
["la"]="",
["lt"]="puslapis ",
+ ["mk"]="страница ",
["nb"]="side ",
["nl"]="pagina ",
["nn"]="side ",
@@ -2135,7 +2246,8 @@ data.labels={
["kr"]={ "제", "부" },
["la"]="Pars ",
["lt"]={ "", " dalis" },
- ["nb"]="Del",
+ ["mk"]="Дел ",
+ ["nb"]="Del ",
["nl"]="Deel ",
["nn"]="Del",
["pe"]="قسمت ",
@@ -2156,6 +2268,7 @@ data.labels={
["labels"]={
["en"]="on a preceding page",
["et"]="eelmisel lehel",
+ ["mk"]="на претходната страница",
["nl"]="op een voorgaande bladzijde",
["pe"]="در صفحات گذشته",
},
@@ -2182,6 +2295,7 @@ data.labels={
["kr"]="토요일",
["la"]="Dies Saturni",
["lt"]="šeštadienis",
+ ["mk"]="сабота",
["nb"]="lørdag",
["nl"]="zaterdag",
["nn"]="laurdag",
@@ -2223,6 +2337,7 @@ data.labels={
["la"]="",
["lt"]="",
["nb"]="",
+ ["mk"]="Поглавје ",
["nl"]="",
["nn"]="",
["pe"]="بخش ",
@@ -2259,6 +2374,7 @@ data.labels={
["kr"]="",
["la"]="",
["lt"]="žiūrėti ",
+ ["mk"]="види ",
["nb"]="se ",
["nl"]="zie ",
["nn"]="sjå ",
@@ -2300,6 +2416,7 @@ data.labels={
["kr"]="9",
["la"]="September",
["lt"]="rugsėjo",
+ ["mk"]="септември",
["nb"]="september",
["nl"]="september",
["nn"]="september",
@@ -2341,6 +2458,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="sep",
+ ["mk"]="септ.",
["nb"]="sep.",
["nl"]="",
["nn"]="sep.",
@@ -2379,6 +2497,7 @@ data.labels={
["ja"]="",
["la"]="",
["lt"]="",
+ ["mk"]="Подпоглавје ",
["nb"]="",
["nl"]="",
["nn"]="",
@@ -2418,6 +2537,7 @@ data.labels={
["ja"]="",
["la"]="",
["lt"]="",
+ ["mk"]="Подподпоглавје ",
["nb"]="",
["nl"]="",
["nn"]="",
@@ -2457,6 +2577,7 @@ data.labels={
["ja"]="",
["la"]="",
["lt"]="",
+ ["mk"]="Подподподпоглавје ",
["nb"]="",
["nl"]="",
["nn"]="",
@@ -2496,6 +2617,7 @@ data.labels={
["kr"]="일요일",
["la"]="Dies Solis",
["lt"]="sekmadienis",
+ ["mk"]="недела",
["nb"]="søndag",
["nl"]="zondag",
["nn"]="sundag",
@@ -2535,6 +2657,7 @@ data.labels={
["kr"]="표 ",
["la"]="Tabula ",
["lt"]={ "", " lentelė." },
+ ["mk"]="Табела ",
["nb"]="Tabell ",
["nl"]="Tabel ",
["nn"]="Tabell ",
@@ -2574,6 +2697,7 @@ data.labels={
["kr"]="목요일",
["la"]="Dies Iovis",
["lt"]="ketvirtadienis",
+ ["mk"]="четврток",
["nb"]="torsdag",
["nl"]="donderdag",
["nn"]="torsdag",
@@ -2613,6 +2737,7 @@ data.labels={
["kr"]="화요일",
["la"]="Dies Martis",
["lt"]="antradienis",
+ ["mk"]="вторник",
["nb"]="tirsdag",
["nl"]="dinsdag",
["nn"]="tysdag",
@@ -2652,6 +2777,7 @@ data.labels={
["kr"]="수요일",
["la"]="Dies Mercuri",
["lt"]="trečiadienis",
+ ["mk"]="среда",
["nb"]="onsdag",
["nl"]="woensdag",
["nn"]="onsdag",
@@ -2674,6 +2800,7 @@ data.labels={
["en"]="year",
["et"]="aasta",
["kr"]="년",
+ ["mk"]="година",
["nl"]="jaar",
["pe"]="سال",
},
@@ -2702,6 +2829,7 @@ data.labels={
["kr"]="약어",
["la"]="Notae",
["lt"]="Santrumpos",
+ ["mk"]="Скратеници",
["nb"]="Forkortelser",
["nl"]="Afkortingen",
["nn"]="Forkortingar",
@@ -2741,6 +2869,7 @@ data.labels={
["kr"]="목차",
["la"]="Quod in libro continetur",
["lt"]="Turinys",
+ ["mk"]="Содржина",
["nb"]="Innhold",
["nl"]="Inhoud",
["nn"]="Innhald",
@@ -2780,6 +2909,7 @@ data.labels={
["kr"]="그림 ",
["la"]="Imagines",
["lt"]="Iliustracijos",
+ ["mk"]="Листа на слики",
["nb"]="Figurer",
["nl"]="Figuren",
["nn"]="Figurar",
@@ -2819,6 +2949,7 @@ data.labels={
["kr"]="그래픽 ",
["la"]="Typi",
["lt"]="Graphics",
+ ["mk"]="Листа на графици",
["nb"]="Bilde",
["nl"]="Grafieken",
["nn"]="Bilete",
@@ -2858,6 +2989,7 @@ data.labels={
["kr"]="찾아보기",
["la"]="Indices",
["lt"]="Rodyklė",
+ ["mk"]="Индекс",
["nb"]="Register",
["nl"]="Index",
["nn"]="Register",
@@ -2897,6 +3029,7 @@ data.labels={
["kr"]="간주곡",
["la"]="Intermissa",
["lt"]="Intermezzos",
+ ["mk"]="Листа на дигресии",
["nb"]="Intermesso",
["nl"]="Intermezzo's",
["nn"]="Intermesso",
@@ -2935,6 +3068,7 @@ data.labels={
["kr"]="이성",
["la"]="Typi negotiales",
["lt"]="Logos",
+ ["mk"]="Логоа",
["nb"]="Logoer",
["nl"]="Logo's",
["nn"]="Logoar",
@@ -2971,6 +3105,7 @@ data.labels={
["kr"]="참고문헌",
["la"]="",
["lt"]="Literatūra",
+ ["mk"]="Литература",
["nb"]="",
["nl"]="Literatuur",
["nn"]="",
@@ -3010,6 +3145,7 @@ data.labels={
["kr"]="표 ",
["la"]="Tabulae",
["lt"]="Lentelės",
+ ["mk"]="Листа на табели",
["nb"]="Tabeller",
["nl"]="Tabellen",
["nn"]="Tabellar",
@@ -3049,6 +3185,7 @@ data.labels={
["kr"]="측정단위",
["la"]="Modi",
["lt"]="Units",
+ ["mk"]="Единици",
["nb"]="Enheter",
["nl"]="Eenheden",
["nn"]="Einingar",
diff --git a/Master/texmf-dist/tex/context/base/mkiv/libs-imp-curl.lua b/Master/texmf-dist/tex/context/base/mkiv/libs-imp-curl.lua
new file mode 100644
index 00000000000..b307397948c
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/libs-imp-curl.lua
@@ -0,0 +1,296 @@
+if not modules then modules = { } end modules ['libs-imp-curl'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkxl",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- c:/data/develop/tex-context/tex/texmf-win64/bin/lib/luametatex/lua/copies/curl/libcurl.dll
+
+local libname = "curl"
+local libfile = "libcurl"
+
+local curllib = resolvers.libraries.validoptional(libname)
+
+if not curllib then return end
+
+-- We're good, so we continue.
+
+local next, type = next, type
+local lower, gsub = string.lower, string.gsub
+
+local mapping = {
+ ["acceptencoding"] = 102,
+ ["accepttimeoutms"] = 212,
+ ["addressscope"] = 171,
+ ["append"] = 50,
+ ["autoreferer"] = 58,
+ ["buffersize"] = 98,
+ ["cainfo"] = 65,
+ ["capath"] = 97,
+ ["certinfo"] = 172,
+ -- ["chunkbgnfunction"] = 198,
+ ["chunkdata"] = 201,
+ -- ["chunkendfunction"] = 199,
+ ["closepolicy"] = 72,
+ ["closesocketdata"] = 209,
+ -- ["closesocketfunction"] = 208,
+ ["connectonly"] = 141,
+ ["connecttimeout"] = 78,
+ ["connecttimeoutms"] = 156,
+ -- ["convfromnetworkfunction"] = 142,
+ -- ["convfromutf8function"] = 144,
+ -- ["convtonetworkfunction"] = 143,
+ ["cookie"] = 22,
+ ["cookiefile"] = 31,
+ ["cookiejar"] = 82,
+ ["cookielist"] = 135,
+ ["cookiesessionv"] = 96,
+ ["copypostfields"] = 165,
+ ["crlf"] = 27,
+ ["crlfile"] = 169,
+ ["customrequest"] = 36,
+ ["debugdata"] = 95,
+ -- ["debugfunction"] = 94,
+ ["dirlistonly"] = 48,
+ ["dnscachetimeout"] = 92,
+ ["dnsinterface"] = 221,
+ ["dnslocalip4"] = 222,
+ ["dnslocalip6"] = 223,
+ ["dnsservers"] = 211,
+ ["dnsuseglobalcache"] = 91,
+ ["egdsocket"] = 77,
+ ["errorbuffer"] = 10,
+ ["expect100timeoutms"] = 227,
+ ["failonerror"] = 45,
+ ["file"] = 1,
+ ["filetime"] = 69,
+ ["fnmatchdata"] = 202,
+ -- ["fnmatchfunction"] = 200,
+ ["followlocation"] = 52,
+ ["forbidreuse"] = 75,
+ ["freshconnect"] = 74,
+ ["ftpaccount"] = 134,
+ ["ftpalternativetouser"] = 147,
+ ["ftpcreatemissingdirs"] = 110,
+ ["ftpfilemethod"] = 138,
+ ["ftpresponsetimeout"] = 112,
+ ["ftpskippasvip"] = 137,
+ ["ftpsslccc"] = 154,
+ ["ftpuseeprt"] = 106,
+ ["ftpuseepsv"] = 85,
+ ["ftpusepret"] = 188,
+ ["ftpport"] = 17,
+ ["ftpsslauth"] = 129,
+ ["gssapidelegation"] = 210,
+ ["header"] = 42,
+ ["headerdata"] = 29,
+ -- ["headerfunction"] = 79,
+ ["http200aliases"] = 104,
+ ["httpcontentdecoding"] = 158,
+ ["httptransferdecoding"] = 157,
+ ["httpversion"] = 84,
+ ["httpauth"] = 107,
+ ["httpget"] = 80,
+ ["httpheader"] = 23,
+ ["httppost"] = 24,
+ ["httpproxytunnel"] = 61,
+ ["ignorecontentlength"] = 136,
+ ["infile"] = 9,
+ ["infilesize"] = 14,
+ ["infilesizelarge"] = 115,
+ ["interface"] = 62,
+ ["interleavedata"] = 195,
+ -- ["interleavefunction"] = 196,
+ ["ioctldata"] = 131,
+ -- ["ioctlfunction"] = 130,
+ ["ipresolve"] = 113,
+ ["issuercert"] = 170,
+ ["keypasswd"] = 26,
+ ["krblevel"] = 63,
+ ["localport"] = 139,
+ ["localportrange"] = 140,
+ ["loginoptions"] = 224,
+ ["lowspeedlimit"] = 19,
+ ["lowspeedtime"] = 20,
+ ["mailauth"] = 217,
+ ["mailfrom"] = 186,
+ ["mailrcpt"] = 187,
+ ["maxrecvspeedlarge"] = 146,
+ ["maxsendspeedlarge"] = 145,
+ ["maxconnects"] = 71,
+ ["maxfilesize"] = 114,
+ ["maxfilesizelarge"] = 117,
+ ["maxredirs"] = 68,
+ ["netrc"] = 51,
+ ["netrcfile"] = 118,
+ ["newdirectoryperms"] = 160,
+ ["newfileperms"] = 159,
+ ["nobody"] = 44,
+ ["noprogress"] = 43,
+ ["noproxy"] = 177,
+ ["nosignal"] = 99,
+ ["opensocketdata"] = 164,
+ -- ["opensocketfunction"] = 163,
+ ["password"] = 174,
+ ["port"] = 3,
+ ["post"] = 47,
+ -- ["postfields"] = 15,
+ -- ["postfieldsize"] = 60,
+ -- ["postfieldsizelarge"] = 120,
+ ["postquote"] = 39,
+ ["postredir"] = 161,
+ ["prequote"] = 93,
+ ["private"] = 103,
+ ["progressdata"] = 57,
+ -- ["progressfunction"] = 56,
+ ["protocols"] = 181,
+ ["proxy"] = 4,
+ ["proxytransfermode"] = 166,
+ ["proxyauth"] = 111,
+ ["proxypassword"] = 176,
+ ["proxyport"] = 59,
+ ["proxytype"] = 101,
+ ["proxyusername"] = 175,
+ ["proxyuserpwd"] = 6,
+ ["put"] = 54,
+ ["quote"] = 28,
+ ["randomfile"] = 76,
+ ["range"] = 7,
+ ["readdata"] = 9,
+ -- ["readfunction"] = 12,
+ ["redirprotocols"] = 182,
+ ["referer"] = 16,
+ ["resolve"] = 203,
+ ["resumefrom"] = 21,
+ ["resumefromlarge"] = 116,
+ ["rtspclientcseq"] = 193,
+ ["rtsprequest"] = 189,
+ ["rtspservercseq"] = 194,
+ ["rtspsessionid"] = 190,
+ ["rtspstreamuri"] = 191,
+ ["rtsptransport"] = 192,
+ ["rtspheader"] = 23,
+ ["saslir"] = 218,
+ ["seekdata"] = 168,
+ -- ["seekfunction"] = 167,
+ ["serverresponsetimeout"] = 112,
+ ["share"] = 100,
+ ["sockoptdata"] = 149,
+ -- ["sockoptfunction"] = 148,
+ ["socks5gssapinec"] = 180,
+ ["socks5gssapiservice"] = 179,
+ ["sshauthtypes"] = 151,
+ ["sshhostpublickeymd5"] = 162,
+ ["sshkeydata"] = 185,
+ -- ["sshkeyfunction"] = 184,
+ ["sshknownhosts"] = 183,
+ ["sshprivatekeyfile"] = 153,
+ ["sshpublickeyfile"] = 152,
+ ["sslcipherlist"] = 83,
+ ["sslctxdata"] = 109,
+ -- ["sslctxfunction"] = 108,
+ ["sslenablealpn"] = 226,
+ ["sslenablenpn"] = 225,
+ ["ssloptions"] = 216,
+ ["sslsessionidcache"] = 150,
+ ["sslverifyhost"] = 81,
+ ["sslverifypeer"] = 64,
+ ["sslcert"] = 25,
+ ["sslcerttype"] = 86,
+ ["sslengine"] = 89,
+ ["sslenginedefault"] = 90,
+ ["sslkey"] = 87,
+ ["sslkeytype"] = 88,
+ ["sslversion"] = 32,
+ ["stderr"] = 37,
+ ["tcpkeepalive"] = 213,
+ ["tcpkeepidle"] = 214,
+ ["tcpkeepintvl"] = 215,
+ ["tcpnodelay"] = 121,
+ ["telnetoptions"] = 70,
+ ["tftpblksize"] = 178,
+ ["timecondition"] = 33,
+ ["timeout"] = 13,
+ ["timeoutms"] = 155,
+ ["timevalue"] = 34,
+ ["tlsauthpassword"] = 205,
+ ["tlsauthtype"] = 206,
+ ["tlsauthusername"] = 204,
+ ["transferencoding"] = 207,
+ ["transfertext"] = 53,
+ ["unrestrictedauth"] = 105,
+ ["upload"] = 46,
+ ["url"] = 2,
+ ["usessl"] = 119,
+ ["useragent"] = 18,
+ ["username"] = 173,
+ ["userpwd"] = 5,
+ ["verbose"] = 41,
+ ["wildcardmatch"] = 197,
+ ["writedata"] = 1,
+ -- ["writefunction"] = 11,
+ ["writeheader"] = 29,
+ ["writeinfo"] = 40,
+ ["xferinfodata"] = 57,
+ -- ["xferinfofunction"] = 219,
+ ["xoauth2bearer"] = 220,
+}
+
+table.setmetatableindex(mapping,function(t,k)
+ local s = gsub(lower(k),"[^a-z0-9]","")
+ local v = rawget(t,s) or false
+ t[k] = v
+ return v
+end)
+
+local curl_fetch = curllib.fetch
+local curl_escape = curllib.escape
+local curl_unescape = curllib.unescape
+local curl_getversion = curllib.getversion
+
+local report = logs.reporter(libname)
+
+local function okay()
+ if resolvers.libraries.optionalloaded(libname,libfile) then
+ okay = function() return true end
+ else
+ okay = function() return false end
+ end
+ return okay()
+end
+
+local function fetch(options)
+ if okay() then
+ local t = type(options)
+ if t == "table" then
+ local o = { }
+ for name, value in next, options do
+ local index = mapping[name]
+ if index then
+ o[index] = value
+ end
+ end
+ return curl_fetch(o)
+ elseif t == "string" then
+ return curl_fetch { [mapping.url] = options }
+ else
+ report("invalid argument")
+ end
+ end
+end
+
+local curl = {
+ getversion = function () return okay() and curl_getversion() end,
+ escape = function (s) return okay() and curl_escape (s) end,
+ unescape = function (s) return okay() and curl_unescape (s) end,
+ fetch = fetch,
+}
+
+-- inspect(curl.fetch("http://www.pragma-ade.com/index.html"))
+-- inspect(curl.fetch { url = "http://www.pragma-ade.com/index.html" })
+
+package.loaded[libname] = curl
+
+return curl
diff --git a/Master/texmf-dist/tex/context/base/mkiv/libs-imp-ghostscript.lua b/Master/texmf-dist/tex/context/base/mkiv/libs-imp-ghostscript.lua
new file mode 100644
index 00000000000..b129a58c143
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/libs-imp-ghostscript.lua
@@ -0,0 +1,111 @@
+if not modules then modules = { } end modules ['libs-imp-ghostscript'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkxl",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+}
+
+local libname = "ghostscript"
+local libfile = "gsdll64" -- what on unix?
+
+local gslib = resolvers.libraries.validoptional(libname)
+
+if not gslib then return end
+
+local function okay()
+ if resolvers.libraries.optionalloaded(libname,libfile) then
+ okay = function() return true end
+ else
+ okay = function() return false end
+ end
+ return okay()
+end
+
+local insert = table.insert
+local formatters = string.formatters
+
+local ghostscript = utilities.ghostscript or { }
+utilities.ghostscript = ghostscript
+
+local gs_execute = gslib.execute
+local nofruns = 0
+local report = logs.reporter(libname)
+
+function ghostscript.convert(specification)
+ if okay() then
+ --
+ nofruns = nofruns + 1
+ statistics.starttiming(ghostscript)
+ --
+ local inputname = specification.inputname
+ if not inputname or inputname == "" then
+ report("invalid run %s, no inputname specified",nofruns)
+ statistics.stoptiming(ghostscript)
+ return false
+ end
+ local outputname = specification.outputname
+ if not outputname or outputname == "" then
+ outputname = file.replacesuffix(inputname,"pdf")
+ end
+ --
+ if not lfs.isfile(inputname) then
+ report("invalid run %s, input file %a is not found",nofruns,inputname)
+ statistics.stoptiming(ghostscript)
+ return false
+ end
+ --
+ local device = specification.device
+ if not device or device == "" then
+ device = "pdfwrite"
+ end
+ --
+ local code = specification.code
+ if not code or code == "" then
+ code = ".setpdfwrite"
+ end
+ --
+ local options = specification.options or { }
+ --
+ insert(options,"-dNOPAUSE")
+ insert(options,"-dBATCH")
+ insert(options,"-dSAFER")
+ insert(options,formatters["-sDEVICE=%s"](device))
+ insert(options,formatters["-sOutputFile=%s"](outputname))
+ insert(options,"-c")
+ insert(options,code)
+ insert(options,"-f")
+ insert(options,inputname)
+ --
+ report("run %s, input file %a, outputfile %a",nofruns,inputname,outputname)
+ report("")
+ local done = gslib_execute(options)
+ report("")
+ --
+ statistics.stoptiming(ghostscript)
+ if done then
+ return outputname
+ else
+ report("run %s quit with errors",nofruns)
+ return false
+ end
+ end
+end
+
+function ghostscript.statistics(report)
+ local runtime = statistics.elapsedtime(ghostscript)
+ if report then
+ report("nofruns %s, runtime %s",nofruns,runtime)
+ else
+ return {
+ runtime = runtime,
+ nofruns = nofruns,
+ }
+ end
+end
+
+-- for i=1,100 do
+-- ghostscript.convert { inputname = "temp.eps" }
+-- ghostscript.convert { inputname = "t:/escrito/tiger.eps" }
+-- end
+-- ghostscript.statistics(true)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/libs-imp-graphicsmagick.lua b/Master/texmf-dist/tex/context/base/mkiv/libs-imp-graphicsmagick.lua
new file mode 100644
index 00000000000..6f5d1d967fd
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/libs-imp-graphicsmagick.lua
@@ -0,0 +1,77 @@
+if not modules then modules = { } end modules ['libs-imp-graphicsmagick'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkxl",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+}
+
+local libname = "graphicsmagick"
+local libfile = { "CORE_RL_magick_", "CORE_RL_wand_" }
+
+local gmlib = resolvers.libraries.validoptional(libname)
+
+if not gmlib then return end
+
+local function okay()
+ if resolvers.libraries.optionalloaded(libname,libfile) then
+ okay = function() return true end
+ else
+ okay = function() return false end
+ end
+ return okay()
+end
+
+local graphicsmagick = utilities.graphicsmagick or { }
+utilities.graphicsmagick = graphicsmagick
+utilities.graphicmagick = graphicsmagick
+
+local gm_execute = gmlib.execute
+local nofruns = 0
+local report = logs.reporter(libname)
+
+function graphicsmagick.convert(specification)
+ if okay() then
+ --
+ nofruns = nofruns + 1
+ statistics.starttiming(graphicsmagick)
+ --
+ local inputname = specification.inputname
+ if not inputname or inputname == "" then
+ report("invalid run %s, no inputname specified",nofruns)
+ statistics.stoptiming(graphicsmagick)
+ return false
+ end
+ local outputname = specification.outputname
+ if not outputname or outputname == "" then
+ outputname = file.replacesuffix(inputname,"pdf")
+ end
+ --
+ if not lfs.isfile(inputname) then
+ report("invalid run %s, input file %a is not found",nofruns,inputname)
+ statistics.stoptiming(graphicsmagick)
+ return false
+ end
+ --
+ report("run %s, input file %a, outputfile %a",nofruns,inputname,outputname)
+ --
+ gm_execute { inputfile = inputname, outputfile = outputname }
+ --
+ statistics.stoptiming(graphicsmagick)
+ end
+end
+
+function graphicsmagick.statistics(report)
+ local runtime = statistics.elapsedtime(graphicsmagick)
+ if report then
+ report("nofruns %s, runtime %s",nofruns,runtime)
+ else
+ return {
+ runtime = runtime,
+ nofruns = nofruns,
+ }
+ end
+end
+
+-- graphicsmagick.convert { inputname = "t:/sources/hacker.jpg", outputname = "e:/tmp/hacker.png" }
+-- graphicsmagick.statistics(true)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/libs-imp-mujs.lua b/Master/texmf-dist/tex/context/base/mkiv/libs-imp-mujs.lua
new file mode 100644
index 00000000000..264c8e53126
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/libs-imp-mujs.lua
@@ -0,0 +1,126 @@
+if not modules then modules = { } end modules ['libs-imp-mujs'] = {
+ version = 1.001,
+ comment = "companion to luat-imp-mujs.mkxl",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- This is an experiment. When a new user knows \JAVASCRIPT\ it can be a
+-- stepping stone to using \LUA.
+
+-- local ecmascript = optional.mujs.initialize("libmujs")
+-- local execute = optional.mujs.execute
+
+local libname = "mujs"
+local libfile = "libmujs"
+
+if package.loaded[libname] then
+ return package.loaded[libname]
+end
+
+local mujslib = resolvers.libraries.validoptional(libname)
+
+if not mujslib then
+ return
+end
+
+local files = { }
+local openfile = io.open
+local findfile = resolvers.findfile
+
+local mujs_execute = mujslib.execute
+local mujs_dofile = mujslib.dofile
+local mujs_reset = mujslib.reset
+
+local function okay()
+ if resolvers.libraries.optionalloaded(libname,libfile) then
+ mujs_execute(
+ "var catcodes = { " ..
+ "'tex': " .. tex.texcatcodes .. "," ..
+ "'ctx': " .. tex.ctxcatcodes .. "," ..
+ "'prt': " .. tex.prtcatcodes .. "," ..
+ "'vrb': " .. tex.vrbcatcodes .. "," ..
+ "};"
+ )
+ okay = function() return true end
+ else
+ okay = function() return false end
+ end
+ return okay()
+end
+
+mujslib.setfindfile(findfile)
+
+mujslib.setopenfile(function(name)
+ local full = findfile(name)
+ if full then
+ local f = openfile(full,"rb")
+ if f then
+ for i=1,100 do
+ if not files[i] then
+ files[i] = f
+ return i
+ end
+ end
+ end
+ end
+end)
+
+mujslib.setclosefile(function(id)
+ local f = files[id]
+ if f then
+ f:close()
+ files[id] = false
+ end
+end)
+
+mujslib.setreadfile(function(id,how)
+ local f = files[id]
+ if f then
+ return (f:read(how or "*l"))
+ end
+end)
+
+mujslib.setseekfile(function(id,whence,offset)
+ local f = files[id]
+ if f then
+ return (f:seek(whence,offset))
+ end
+end)
+
+local reporters = {
+ console = logs.reporter("mujs","console"),
+ report = logs.reporter("mujs","report"),
+}
+
+mujslib.setconsole(function(category,name)
+ reporters[category](name)
+end)
+
+local mujs = {
+ ["execute"] = function(c,s) if okay() then mujs_execute(c,s) end end,
+ ["dofile"] = function(n) if okay() then mujs_dofile(n) end end,
+ ["reset"] = function(n) if okay() then mujs_reset(n) end end,
+}
+
+package.loaded[libname] = mujs
+
+optional.loaded.mujs = mujs
+
+interfaces.implement {
+ name = "ecmacode",
+ actions = mujs.execute,
+ arguments = "string",
+ public = true,
+}
+
+interfaces.implement {
+ name = "ecmafile",
+ actions = mujs.dofile,
+ arguments = "string",
+ public = true,
+ protected = true,
+}
+
+return mujs
diff --git a/Master/texmf-dist/tex/context/base/mkiv/libs-imp-mujs.mkxl b/Master/texmf-dist/tex/context/base/mkiv/libs-imp-mujs.mkxl
new file mode 100644
index 00000000000..0f278dff5b2
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/libs-imp-mujs.mkxl
@@ -0,0 +1,121 @@
+%D \module
+%D [ file=libs-imp-mujs,
+%D version=2020.02.08,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=MuJS interpreter,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D Just an experiment:
+%D
+%D \starttyping
+%D http://mujs.com
+%D \stoptyping
+
+\ifdefined\ecmacode
+ \expandafter \endinput
+\fi
+
+\registerctxluafile{libs-imp-mujs}{}
+
+\unprotect
+
+% todo: environment
+
+\let\stopecmacode\relax
+
+\normalprotected\def\startecmacode % \stopecmacode
+ {\begingroup
+ \obeylualines
+ \obeyluatokens
+ \luat_start_ecma_code_indeed}
+
+\def\luat_start_ecma_code_indeed#1\stopecmacode
+ {\normalexpanded{\endgroup\noexpand\ecmacode{#1}}}
+
+\protect
+
+\continueifinputfile{libs-imp-mujs.mkxl}
+
+\usemodule[article-basic,abbreviations-logos]
+
+\starttext
+
+\startbuffer
+\startluacode
+ local mujs = require("libs-imp-mujs")
+
+ mujs.execute [[
+ var MyMax = 1000;
+ ]]
+
+ mujs.execute [[
+ console("Example One!");
+ texsprint("\\startpacked");
+ for (var i = 1; i <= MyMax; i = i + 1) {
+ texprint(
+ "This is a buildbot compilation challenge for Mojca: "
+ .concat(Math.sqrt(i/MyMax))
+ .concat("!\\par")
+ );
+ }
+ texsprint("\\stoppacked");
+ ]]
+
+ -- mujs.execute [[
+ -- something very bad: an error
+ -- ]]
+\stopluacode
+
+\startecmacode
+ console("Example Two!");
+ for (var i = 1; i <= MyMax; i = i + 1) {
+ texsprint(
+ "And an opportunity for Alan to attract highschool students to \\TeX: "
+ .concat(i)
+ .concat("! ")
+ );
+ }
+\stopecmacode
+
+\ecmacode {
+ console("Example Three!");
+ texprint("And otherwise a way to prototype \\JAVASCRIPT\\ code in \\PDF.")
+}
+
+\startecmacode
+ var f = File("libs-imp-mujs.mkxl","r");
+ console(f);
+ // var l = f.read(400);
+ var l = f.read("*a");
+ console(l);
+ f.close();
+\stopecmacode
+
+\startecmacode
+ console("Example Four!");
+ texsprint("\\startMPcode "
+ .concat(' fill fullcircle scaled 6cm withcolor "darkred";')
+ .concat(' fill fullcircle scaled 4cm withcolor "darkgreen";')
+ .concat(' fill fullcircle scaled 2cm withcolor "darkblue";')
+ .concat("\\stopMPcode ")
+ );
+\stopecmacode
+
+\startluacode
+ context.startMPcode()
+ context('fill fullcircle scaled 6cm withcolor "middlecyan";')
+ context('fill fullcircle scaled 4cm withcolor "middlemagenta";')
+ context('fill fullcircle scaled 2cm withcolor "middleyellow";')
+ context.stopMPcode()
+\stopluacode
+\stopbuffer
+
+\typebuffer \page \getbuffer
+
+\stoptext
diff --git a/Master/texmf-dist/tex/context/base/mkiv/libs-imp-mysql.lua b/Master/texmf-dist/tex/context/base/mkiv/libs-imp-mysql.lua
new file mode 100644
index 00000000000..3e938a6de48
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/libs-imp-mysql.lua
@@ -0,0 +1,220 @@
+if not modules then modules = { } end modules ['libs-imp-mysql'] = {
+ version = 1.001,
+ comment = "companion to util-sql.lua",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- c:/data/develop/tex-context/tex/texmf-win64/bin/lib/luametatex/lua/copies/mysql/libmysql.dll
+
+local libname = "mysql"
+local libfile = "libmysql"
+
+local mysqllib = resolvers.libraries.validoptional(libname)
+
+if not mysqllib then return end
+
+local function okay()
+ if resolvers.libraries.optionalloaded(libname,libfile) then
+ okay = function() return true end
+ else
+ okay = function() return false end
+ end
+ return okay()
+end
+
+local lpegmatch = lpeg.match
+local setmetatable = setmetatable
+
+local sql = utilities.sql or require("util-sql")
+local report = logs.reporter(libname)
+
+local trace_sql = false trackers.register("sql.trace", function(v) trace_sql = v end)
+local trace_queries = false trackers.register("sql.queries",function(v) trace_queries = v end)
+
+local mysql_open = mysqllib.open
+local mysql_close = mysqllib.close
+local mysql_execute = mysqllib.execute
+local mysql_getmessage = mysqllib.getmessage
+
+local helpers = sql.helpers
+local methods = sql.methods
+local validspecification = helpers.validspecification
+local preparetemplate = helpers.preparetemplate
+local querysplitter = helpers.querysplitter
+local cache = { }
+local timeout -- = 3600 -- to be tested
+
+local function connect(specification)
+ local db = mysql_open(
+ specification.database or "",
+ specification.username or "",
+ specification.password or "",
+ specification.host or "",
+ specification.port
+ )
+ if db and timeout then
+ mysql_execute(db,formatters["SET SESSION connect_timeout=%s ;"](timeout))
+ end
+ return db
+end
+
+local function execute_once(specification,retry)
+ if okay() then
+ if trace_sql then
+ report("executing mysql")
+ end
+ if not validspecification(specification) then
+ report("error in specification")
+ end
+ local query = preparetemplate(specification)
+ if not query then
+ report("error in preparation")
+ return
+ else
+ query = lpegmatch(querysplitter,query)
+ end
+ local base = specification.database -- or specification.presets and specification.presets.database
+ if not base then
+ report("no database specified")
+ return
+ end
+ local result = { }
+ local keys = { }
+ local id = specification.id
+ local db = nil
+ if id then
+ local session = cache[id]
+ if session then
+ db = session.db
+ else
+ db = connect(specification)
+ if not db then
+ report("no session database specified")
+ else
+ cache[id] = {
+ specification = specification,
+ db = db,
+ }
+ end
+ end
+ else
+ db = connect(specification)
+ end
+ if not db then
+ report("no database opened")
+ else
+ local converter = specification.converter
+ local nofrows = 0
+ local callback = nil
+ if converter then
+ local convert = converter.mysql
+ callback = function(nofcolumns,values,fields)
+ nofrows = nofrows + 1
+ result[nofrows] = convert(values)
+ end
+ else
+ callback = function(nofcolumns,values,fields)
+ local column = { }
+ for i=1,nofcolumns do
+ local field
+ if fields then
+ field = fields[i]
+ keys[i] = field
+ else
+ field = keys[i]
+ end
+ if field then
+ column[field] = values[i]
+ end
+ end
+ nofrows = nofrows + 1
+ result[nofrows] = column
+ end
+ end
+ for i=1,#query do
+ local okay = mysql_execute(db,query[i],callback)
+ if not okay then
+ if id and retry and i == 1 then
+ report("error: %s, retrying to connect",mysql_getmessage(db))
+ mysql_close(db)
+ cache[id] = nil
+ return execute_once(specification,false)
+ else
+ report("error: %s",mysql_getmessage(db))
+ end
+ end
+ end
+ end
+ if db and not id then
+ mysql_close(db)
+ end
+ -- bonus
+ local one = result[1]
+ if one then
+ setmetatable(result,{ __index = one } )
+ end
+ --
+ return result, keys
+ else
+ report("error: ","no library loaded")
+ end
+end
+
+local function execute(specification)
+ return execute_once(specification,true)
+end
+
+-- Here we build the dataset stepwise so we don't use the data hack that
+-- is used in the client variant.
+
+local wraptemplate = [[
+local converters = utilities.sql.converters
+local deserialize = utilities.sql.deserialize
+
+local tostring = tostring
+local tonumber = tonumber
+local booleanstring = string.booleanstring
+
+%s
+
+return function(cells)
+ -- %s (not needed)
+ -- %s (not needed)
+ return {
+ %s
+ }
+end
+]]
+
+-- return function(result)
+-- if not result then
+-- return { }
+-- end
+-- local nofrows = #result
+-- if nofrows == 0 then
+-- return { }
+-- end
+-- local target = { } -- no %s needed here
+-- for i=1,nofrows do
+-- target[%s] = {
+-- %s
+-- }
+-- end
+-- return result
+-- end
+
+local celltemplate = "cells[%s]"
+
+methods.mysql = {
+ execute = execute,
+ usesfiles = false,
+ wraptemplate = wraptemplate,
+ celltemplate = celltemplate,
+}
+
+package.loaded["util-sql-imp-ffi"] = methods.mysql
+package.loaded["util-sql-imp-mysql"] = methods.mysql
+package.loaded["util-sql-imp-library"] = methods.mysql
+package.loaded[libname] = methods.mysql
diff --git a/Master/texmf-dist/tex/context/base/mkiv/libs-imp-postgress.lua b/Master/texmf-dist/tex/context/base/mkiv/libs-imp-postgress.lua
new file mode 100644
index 00000000000..629079b01a5
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/libs-imp-postgress.lua
@@ -0,0 +1,200 @@
+if not modules then modules = { } end modules ['libs-imp-postgress'] = {
+ version = 1.001,
+ comment = "companion to util-sql.lua",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- Not yet untested !
+
+-- c:/data/develop/tex-context/tex/texmf-win64/bin/lib/luametatex/lua/copies/postgress/libpq.dll
+
+-- we can now share the code between mysql, postgress, sqlite ... todo
+
+local libname = "postgress"
+local libfile = "libpq"
+
+local postgresslib = resolvers.libraries.validoptional(libname)
+
+if not postgresslib then return end
+
+local function okay()
+ if resolvers.libraries.optionalloaded(libname,libfile) then
+ okay = function() return true end
+ else
+ okay = function() return false end
+ end
+ return okay()
+end
+
+local lpegmatch = lpeg.match
+local setmetatable = setmetatable
+
+local sql = utilities.sql or require("util-sql")
+local report = logs.reporter(libname)
+
+local trace_sql = false trackers.register("sql.trace", function(v) trace_sql = v end)
+local trace_queries = false trackers.register("sql.queries",function(v) trace_queries = v end)
+
+local postgress_open = postgresslib.open
+local postgress_close = postgresslib.close
+local postgress_execute = postgresslib.execute
+local postgress_getmessage = postgresslib.getmessage
+
+local helpers = sql.helpers
+local methods = sql.methods
+local validspecification = helpers.validspecification
+local preparetemplate = helpers.preparetemplate
+local querysplitter = helpers.querysplitter -- not needed
+local cache = { }
+
+local function connect(specification)
+ return postgress_open(
+ specification.database or "",
+ specification.username or "",
+ specification.password or "",
+ specification.host or "",
+ specification.port
+ )
+end
+
+local function execute_once(specification,retry)
+ if okay() then
+ if trace_sql then
+ report("executing postgress")
+ end
+ if not validspecification(specification) then
+ report("error in specification")
+ end
+ local query = preparetemplate(specification)
+ if not query then
+ report("error in preparation")
+ return
+ else
+ query = lpegmatch(querysplitter,query) -- not needed
+ end
+ local base = specification.database -- or specification.presets and specification.presets.database
+ if not base then
+ report("no database specified")
+ return
+ end
+ local result = { }
+ local keys = { }
+ local id = specification.id
+ local db = nil
+ if id then
+ local session = cache[id]
+ if session then
+ db = session.db
+ else
+ db = connect(specification)
+ if not db then
+ report("no session database specified")
+ else
+ cache[id] = {
+ specification = specification,
+ db = db,
+ }
+ end
+ end
+ else
+ db = connect(specification)
+ end
+ if not db then
+ report("no database opened")
+ else
+ local converter = specification.converter
+ local nofrows = 0
+ local callback = nil
+ if converter then
+ local convert = converter.postgress
+ callback = function(nofcolumns,values,fields)
+ nofrows = nofrows + 1
+ result[nofrows] = convert(values)
+ end
+ else
+ callback = function(nofcolumns,values,fields)
+ local column = { }
+ for i=1,nofcolumns do
+ local field
+ if fields then
+ field = fields[i]
+ keys[i] = field
+ else
+ field = keys[i]
+ end
+ if field then
+ column[field] = values[i]
+ end
+ end
+ nofrows = nofrows + 1
+ result[nofrows] = column
+ end
+ end
+ for i=1,#query do
+ local okay = postgress_execute(db,query[i],callback)
+ if not okay then
+ if id and retry and i == 1 then
+ report("error: %s, retrying to connect",postgress_getmessage(db))
+ postgress_close(db)
+ cache[id] = nil
+ return execute_once(specification,false)
+ else
+ report("error: %s",postgress_getmessage(db))
+ end
+ end
+ end
+ end
+ if db and not id then
+ postgress_close(db)
+ end
+ -- bonus
+ local one = result[1]
+ if one then
+ setmetatable(result,{ __index = one } )
+ end
+ --
+ return result, keys
+ else
+ report("error: ","no library loaded")
+ end
+end
+
+local function execute(specification)
+ return execute_once(specification,true)
+end
+
+-- Here we build the dataset stepwise so we don't use the data hack that
+-- is used in the client variant.
+
+local wraptemplate = [[
+local converters = utilities.sql.converters
+local deserialize = utilities.sql.deserialize
+
+local tostring = tostring
+local tonumber = tonumber
+local booleanstring = string.booleanstring
+
+%s
+
+return function(cells)
+ -- %s (not needed)
+ -- %s (not needed)
+ return {
+ %s
+ }
+end
+]]
+
+local celltemplate = "cells[%s]"
+
+methods.postgress = {
+ execute = execute,
+ usesfiles = false,
+ wraptemplate = wraptemplate,
+ celltemplate = celltemplate,
+}
+
+package.loaded["util-sql-imp-postgress"] = methods.postgress
+package.loaded[libname] = methods.postgress
diff --git a/Master/texmf-dist/tex/context/base/mkiv/libs-imp-sqlite.lua b/Master/texmf-dist/tex/context/base/mkiv/libs-imp-sqlite.lua
new file mode 100644
index 00000000000..5d38986f347
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/libs-imp-sqlite.lua
@@ -0,0 +1,187 @@
+if not modules then modules = { } end modules ['libs-imp-sqlite'] = {
+ version = 1.001,
+ comment = "companion to util-sql.lua",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- c:/data/develop/tex-context/tex/texmf-win64/bin/lib/luametatex/lua/copies/sqlite/sqlite3.dll
+
+local libname = "sqlite"
+local libfile = "sqlite3"
+
+local sqlitelib = resolvers.libraries.validoptional(libname)
+
+if not sqlitelib then return end
+
+local function okay()
+ if resolvers.libraries.optionalloaded(libname,libfile) then
+ okay = function() return true end
+ else
+ okay = function() return false end
+ end
+ return okay()
+end
+
+local next, tonumber = next, tonumber
+local setmetatable = setmetatable
+local formatters = string.formatters
+
+local sql = utilities.sql or require("util-sql")
+local report = logs.reporter(libname)
+
+local trace_sql = false trackers.register("sql.trace", function(v) trace_sql = v end)
+local trace_queries = false trackers.register("sql.queries",function(v) trace_queries = v end)
+
+local sqlite_open = sqlitelib.open
+local sqlite_close = sqlitelib.close
+local sqlite_execute = sqlitelib.execute
+local sqlite_getmessage = sqlitelib.getmessage
+
+local helpers = sql.helpers
+local methods = sql.methods
+local validspecification = helpers.validspecification
+local preparetemplate = helpers.preparetemplate
+local cache = { }
+
+-- synchronous journal_mode locking_mode 1000 logger inserts
+--
+-- normal normal normal 6.8
+-- off off normal 0.1
+-- normal off normal 2.1
+-- normal persist normal 5.8
+-- normal truncate normal 4.2
+-- normal truncate exclusive 4.1
+
+local f_preamble = formatters[ [[
+ATTACH `%s` AS `%s` ;
+PRAGMA `%s`.synchronous = normal ;
+]] ]
+
+local function execute(specification)
+ if okay() then
+ if trace_sql then
+ report("executing sqlite")
+ end
+ if not validspecification(specification) then
+ report("error in specification")
+ end
+ local query = preparetemplate(specification)
+ if not query then
+ report("error in preparation")
+ return
+ end
+ local base = specification.database -- or specification.presets and specification.presets.database
+ if not base then
+ report("no database specified")
+ return
+ end
+ local filename = file.addsuffix(base,"db")
+ local result = { }
+ local keys = { }
+ local id = specification.id
+ local db = nil
+ local preamble = nil
+ if id then
+ local session = cache[id]
+ if session then
+ db = session.db
+ else
+ db = sqlite_open(filename)
+ preamble = f_preamble(filename,base,base)
+ if not db then
+ report("no session database specified")
+ else
+ cache[id] = {
+ name = filename,
+ db = db,
+ }
+ end
+ end
+ else
+ db = open_db(filename)
+ preamble = f_preamble(filename,base,base)
+ end
+ if not db then
+ report("no database opened")
+ else
+ local converter = specification.converter
+ local nofrows = 0
+ local callback = nil
+ if preamble then
+ query = preamble .. query -- only needed in open
+ end
+ if converter then
+ local convert = converter.sqlite
+ callback = function(nofcolumns,values,fields)
+ nofrows = nofrows + 1
+ result[nofrows] = convert(values)
+ end
+ else
+ callback = function(nofcolumns,values,fields)
+ local column = { }
+ for i=1,nofcolumns do
+ local field
+ if fields then
+ field = fields[i]
+ keys[i] = field
+ else
+ field = keys[i]
+ end
+ if field then
+ column[field] = values[i]
+ end
+ end
+ nofrows = nofrows + 1
+ result[nofrows] = column
+ end
+ end
+ local okay = sqlite_execute(db,query,callback)
+ if not okay then
+ report("error: %s",sqlite_getmessage(db))
+ -- elseif converter then
+ -- result = converter.sqlite(result)
+ end
+ end
+ if db and not id then
+ sqlite_close(db)
+ end
+ return result, keys
+ else
+ report("error: ","no library loaded")
+ end
+end
+
+local wraptemplate = [[
+local converters = utilities.sql.converters
+local deserialize = utilities.sql.deserialize
+
+local tostring = tostring
+local tonumber = tonumber
+local booleanstring = string.booleanstring
+
+%s
+
+return function(cells)
+ -- %s (not needed)
+ -- %s (not needed)
+ return {
+ %s
+ }
+end
+]]
+
+local celltemplate = "cells[%s]"
+
+methods.sqlite = {
+ execute = execute,
+ usesfiles = false,
+ wraptemplate = wraptemplate,
+ celltemplate = celltemplate,
+}
+
+package.loaded["util-sql-imp-sqlite"] = methods.sqlite
+package.loaded[libname] = methods.sqlite
+
+return methods.sqlite
diff --git a/Master/texmf-dist/tex/context/base/mkiv/libs-imp-zint.lua b/Master/texmf-dist/tex/context/base/mkiv/libs-imp-zint.lua
new file mode 100644
index 00000000000..2c346ae7d5f
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/libs-imp-zint.lua
@@ -0,0 +1,161 @@
+if not modules then modules = { } end modules ['libs-imp-ghostscript'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkxl",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+}
+
+local libname = "zint"
+local libfile = "libzint" -- what on unix?
+-- local libfile = "/usr/local/lib/libzint.so"
+
+local zintlib = resolvers.libraries.validoptional(libname)
+
+if not zintlib then return end
+
+local function okay()
+ if resolvers.libraries.optionalloaded(libname,libfile) then
+ okay = function() return true end
+ else
+ okay = function() return false end
+ end
+ return okay()
+end
+
+local zint = utilities.zint or { }
+utilities.zint = zint
+
+local zintlib_execute = zintlib.execute
+
+local next, type, unpack = next, type, unpack
+local lower, gsub = string.lower, string.gsub
+
+local mapping = {
+ ["code 11"] = 1, ["pharma one-track"] = 51, ["aztec code"] = 92,
+ ["standard 2of5"] = 2, ["pzn"] = 52, ["daft code"] = 93,
+ ["interleaved 2of5"] = 3, ["pharma two-track"] = 53, ["micro qr code"] = 97,
+ ["iata 2of5"] = 4, ["pdf417"] = 55, ["hibc code 128"] = 98,
+ ["data logic"] = 6, ["pdf417 trunc"] = 56, ["hibc code 39"] = 99,
+ ["industrial 2of5"] = 7, ["maxicode"] = 57, ["hibc data matrix"] = 102,
+ ["code 39"] = 8, ["qr code"] = 58, ["hibc qr code"] = 104,
+ ["extended code 39"] = 9, ["code 128-b"] = 60, ["hibc pdf417"] = 106,
+ ["ean"] = 13, ["ap standard customer"] = 63, ["hibc micropdf417"] = 108,
+ ["ean + check"] = 14, ["ap reply paid"] = 66, ["hibc codablock-f"] = 110,
+ ["gs1-128"] = 16, ["ap routing"] = 67, ["hibc aztec code"] = 112,
+ ["codabar"] = 18, ["ap redirection"] = 68, ["dotcode"] = 115,
+ ["code 128"] = 20, ["isbn"] = 69, ["han xin code"] = 116,
+ ["leitcode"] = 21, ["rm4scc"] = 70, ["rm mailmark"] = 121,
+ ["identcode"] = 22, ["data matrix"] = 71, ["aztec runes"] = 128,
+ ["code 16k"] = 23, ["ean-14"] = 72, ["code 32"] = 129,
+ ["code 49"] = 24, ["vin (north america)"] = 73, ["comp ean"] = 130,
+ ["code 93"] = 25, ["codablock-f"] = 74, ["comp gs1-128"] = 131,
+ ["flattermarken"] = 28, ["nve-18"] = 75, ["comp databar omni"] = 132,
+ ["gs1 databar omni"] = 29, ["japanese post"] = 76, ["comp databar ltd"] = 133,
+ ["gs1 databar ltd"] = 30, ["korea post"] = 77, ["comp databar expom"] = 134,
+ ["gs1 databar expom"] = 31, ["gs1 databar stack"] = 79, ["comp upc-a"] = 135,
+ ["telepen alpha"] = 32, ["gs1 databar stack omni"] = 80, ["comp upc-e"] = 136,
+ ["upc-a"] = 34, ["gs1 databar eso"] = 81, ["comp databar stack"] = 137,
+ ["upc-a + check"] = 35, ["planet"] = 82, ["comp databar stack omni"] = 138,
+ ["upc-e"] = 37, ["micropdf"] = 84, ["comp databar eso"] = 139,
+ ["upc-e + check"] = 38, ["usps onecode"] = 85, ["channel code"] = 140,
+ ["postnet"] = 40, ["uk plessey"] = 86, ["code one"] = 141,
+ ["msi plessey"] = 47, ["telepen numeric"] = 87, ["grid matrix"] = 142,
+ ["fim"] = 49, ["itf-14"] = 89, ["upnqr"] = 143,
+ ["logmars"] = 50, ["kix code"] = 90, ["rmqr"] = 145,
+}
+
+table.setmetatableindex(mapping,function(t,k)
+ local s = gsub(lower(k),"[^a-z0-9]","")
+ local v = rawget(t,s) or false
+ t[k] = v
+ return v
+end)
+
+local report = logs.reporter("zint")
+local context = context
+local shown = false
+
+----- f_rectangle = string.formatters["%sofill unitsquare xysized (%N,%N) shifted (%N,%N);"]
+
+local function execute(specification)
+ if okay() then
+ local code = specification.code
+ local text = specification.text
+ if code then
+ local id = mapping[code]
+ if id then
+ specification.code = id
+ local result = zintlib_execute(specification)
+ if result then
+ -- not that fast but if needed we can speed it up
+ context.startMPcode()
+ local rectangles = result.rectangles
+ local hexagons = result.hexagons
+ local circles = result.circles
+ local strings = result.strings
+ if rectangles then
+ local n = #rectangles
+ for i=1,n do
+ local r = rectangles[i]
+ context("%sofill unitsquare xysized (%N,%N) shifted (%N,%N);",
+ i == n and "d" or "n",r[3],r[4],r[1],r[2])
+ -- rectangles[i] = f_rectangle(i == n and "d" or "n",r[3],r[4],r[1],r[2])
+ end
+ -- context("% t",rectangles)
+ end
+ if hexagons then
+ local n = #hexagons
+ for i=1,#hexagons do
+ context("%sofill (%N,%N)--(%N,%N)--(%N,%N)--(%N,%N)--(%N,%N)--(%N,%N)--cycle;",
+ i == n and "d" or "n",unpack(hexagons[i]))
+ end
+ end
+ if circles then
+ local n = #circles
+ for i=1,#circles do
+ local c = circles[i]
+ context("%sofill unitcircle scaled %N shifted (%N,%N);",
+ i == n and "d" or "n",c[3],c[1],c[2])
+ end
+ end
+ if strings then
+ -- We set the font at the encapsulating level.
+ for i=1,#strings do
+ local s = strings[i]
+ context('draw textext("%s") scaled (%N/10) shifted (%N,%N);',
+ s[4],s[3],s[1],s[2])
+ end
+ end
+ context.stopMPcode()
+ end
+ else
+ report("unknown barcode alternative %a",code)
+ if not shown then
+ report("")
+ report("valid barcode alternatives:")
+ report("")
+ local list = table.sortedkeys(mapping)
+ for i=1,#list do
+ report(" %s", list[i])
+ end
+ report("")
+ shown = true
+ end
+ end
+ end
+ end
+end
+
+optional.loaded.zint = { execute = execute }
+
+interfaces.implement {
+ name = "zint",
+ actions = execute,
+ arguments = {
+ {
+ { "code" },
+ { "text" },
+ }
+ }
+}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/libs-imp-zint.mkxl b/Master/texmf-dist/tex/context/base/mkiv/libs-imp-zint.mkxl
new file mode 100644
index 00000000000..72ce8157efe
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/libs-imp-zint.mkxl
@@ -0,0 +1,64 @@
+%D \module
+%D [ file=m-zint,
+%D version=2010.12.07,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=Zint Barcode Generator,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D Using \type {zint} seems to be the easiest way to generate
+%D (PDF417) barcodes so therefore we now have this module. There
+%D are proper (also windows) binaries at:
+%D
+%D \starttyping
+%D http://www.zint.org.uk
+%D \stoptyping
+%D
+%D There is a bit more code than needed as we want to be able to
+%D feed names.
+
+\registerctxluafile{libs-imp-zint}{}
+
+\unprotect
+
+\definefont[usedzintfont][dejavusansmono at 10bp]
+
+\unexpanded\def\barcode[#1]% [alternative=,text=]
+ {\bgroup
+ \usedzintfont
+ \getdummyparameters
+ [\c!alternative=,\c!text=,#1]%
+ \scale
+ [#1]%
+ {\clf_zint
+ code {\dummyparameter\c!alternative}
+ text {\dummyparameter\c!text}
+ \relax}
+ \egroup}
+
+\protect
+
+\continueifinputfile{libs-imp-zint.mkxl}
+
+\starttext
+
+% \dorecurse{1000}{
+ \startTEXpage
+ \barcode[alternative=PDF417,text={Hans Hagen}]%
+ \blank
+ \barcode[alternative=PDF417,text={Ton Otten}]%
+ \blank
+ \barcode[alternative=ISBN,text=9789490688011]%
+ \blank
+ \barcode[alternative=isbn,text=9789490688011,width=3cm]%
+ \stopTEXpage
+% }
+
+\stoptext
+
+
diff --git a/Master/texmf-dist/tex/context/base/mkiv/libs-ini.lua b/Master/texmf-dist/tex/context/base/mkiv/libs-ini.lua
new file mode 100644
index 00000000000..2bac3201d28
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/libs-ini.lua
@@ -0,0 +1,196 @@
+if not modules then modules = { } end modules ['libs-ini'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- This is a loader for optional libraries in luametatex with context lmtx. It's
+-- kind of experimental. We also use a different locator than in mkiv because we
+-- don't support loading lua libraries and swiglibs any more. Of course one can
+-- try the regular lua loaders but we just assume that a user then knows what (s)he
+-- is doing.
+
+local type, unpack = type, unpack
+
+-- here we implement the resolver
+
+local type = type
+
+local nameonly = file.nameonly
+local joinfile = file.join
+local addsuffix = file.addsuffix
+local qualifiedpath = file.is_qualified_path
+
+local isfile = lfs.isfile
+
+local findfile = resolvers.findfile
+local expandpaths = resolvers.expandedpathlistfromvariable
+
+local report = logs.reporter("resolvers","libraries")
+local trace = false
+
+trackers.register("resolvers.lib", function(v) trace = v end)
+
+local function findlib(required) -- todo: cache
+ local suffix = os.libsuffix or "so"
+ if not qualifiedpath(required) then
+ local list = directives.value("system.librarynames" )
+ local only = nameonly(required)
+ if type(list) == "table" then
+ list = list[only]
+ if type(list) ~= "table" then
+ list = { only }
+ end
+ else
+ list = { only }
+ end
+ if trace then
+ report("using lookup list for library %a: % | t",only,list)
+ end
+ for i=1,#list do
+ local name = list[i]
+ local found = findfile(name,"lib")
+ if not found then
+ found = findfile(addsuffix(name,suffix),"lib")
+ end
+ if found then
+ if trace then
+ report("library %a resolved via %a path to %a",name,"tds lib",found)
+ end
+ return found
+ end
+ end
+ if expandpaths then
+ local list = expandpaths("PATH")
+ local base = addsuffix(only,suffix)
+ for i=1,#list do
+ local full = joinfile(list[i],base)
+ local found = isfile(full) and full
+ if found then
+ if trace then
+ report("library %a resolved via %a path to %a",name,"system",found)
+ end
+ return found
+ end
+ end
+ end
+ elseif isfile(addsuffix(required,suffix)) then
+ if trace then
+ report("library with qualified name %a %sfound",required,"")
+ end
+ return required
+ else
+ if trace then
+ report("library with qualified name %a %sfound",required,"not ")
+ end
+ end
+ return false
+end
+
+local foundlibraries = table.setmetatableindex(function(t,k)
+ local v = findlib(k)
+ t[k] = v
+ return v
+end)
+
+function resolvers.findlib(required)
+ return foundlibraries[required]
+end
+
+-- here we implement the loader
+
+local libraries = { }
+resolvers.libraries = libraries
+
+local report = logs.reporter("optional")
+
+if optional then optional.loaded = { } end
+
+function libraries.validoptional(name)
+ local thelib = optional and optional[name]
+ if not thelib then
+ -- forget about it, no message here
+ elseif thelib.initialize then
+ return thelib
+ else
+ report("invalid optional library %a",libname)
+ end
+end
+
+function libraries.optionalloaded(name,libnames)
+ local thelib = optional and optional[name]
+ if not thelib then
+ report("no optional %a library found",name)
+ else
+ local thelib_initialize = thelib.initialize
+ if not thelib_initialize then
+ report("invalid optional library %a",name)
+ else
+ if type(libnames) == "string" then
+ libnames = { libnames }
+ end
+ if type(libnames) == "table" then
+ for i=1,#libnames do
+ local libname = libnames[i]
+ local filename = foundlibraries[libname]
+ if filename then
+ libnames[i] = filename
+ else
+ report("unable to locate library %a",libname)
+ return
+ end
+ end
+ local initialized = thelib_initialize(unpack(libnames))
+ if initialized then
+ report("using library '% + t'",libnames)
+ else
+ report("unable to initialize library '% + t'",libnames)
+ end
+ return initialized
+ end
+ end
+ end
+end
+
+if FFISUPPORTED and ffi and ffi.load then
+
+ local ffiload = ffi.load
+
+ function ffi.load(name)
+ local full = name and foundlibraries[name]
+ if full then
+ return ffiload(full)
+ else
+ return ffiload(name)
+ end
+ end
+
+end
+
+-- local patterns = {
+-- "libs-imp-%s.mkxl",
+-- "libs-imp-%s.mklx",
+-- }
+--
+-- local function action(name,foundname)
+-- -- could be one command
+-- context.startreadingfile()
+-- context.input(foundname)
+-- context.stopreadingfile()
+-- end
+--
+-- interfaces.implement {
+-- name = "uselibrary",
+-- arguments = "string"
+-- actions = function(name)
+-- resolvers.uselibrary {
+-- category = "color definition",
+-- name = name,
+-- patterns = patterns,
+-- action = action,
+-- onlyonce = true,
+-- }
+-- end
+-- }
diff --git a/Master/texmf-dist/tex/context/base/mkiv/libs-ini.mkxl b/Master/texmf-dist/tex/context/base/mkiv/libs-ini.mkxl
new file mode 100644
index 00000000000..18163beed12
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/libs-ini.mkxl
@@ -0,0 +1,31 @@
+%D \module
+%D [ file=libs-ini,
+%D version=2020.01.02,
+%D title=\CONTEXT\ Lua Macros,
+%D subtitle=Libraries,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\registerctxluafile{libs-ini}{}
+
+\registerctxluafile{libs-imp-curl}{}
+\registerctxluafile{libs-imp-ghostscript}{}
+\registerctxluafile{libs-imp-graphicsmagick}{}
+
+% These are loaded on demand:
+
+% \registerctxluafile{libs-imp-mysql}{}
+% \registerctxluafile{libs-imp-sqlite}{}
+% \registerctxluafile{libs-imp-postgress}{}
+
+\unprotect
+
+% \unexpanded\def\uselibrary[#1]%
+% {\clf_uselibrary{#1}}
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lpdf-ano.lua b/Master/texmf-dist/tex/context/base/mkiv/lpdf-ano.lua
index 49bf973c9f8..c04ada15156 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lpdf-ano.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/lpdf-ano.lua
@@ -18,7 +18,7 @@ local rep, format, find = string.rep, string.format, string.find
local min = math.min
local lpegmatch = lpeg.match
local formatters = string.formatters
-local sortedkeys = table.sortedkeys
+local sortedkeys, concat = table.sortedkeys, table.concat
local backends, lpdf = backends, lpdf
@@ -93,7 +93,7 @@ local pdfrectangle = lpdf.rectangle
-- todo: 3dview
-local pdf_annot = pdfconstant("Annot")
+----- pdf_annot = pdfconstant("Annot")
local pdf_uri = pdfconstant("URI")
local pdf_gotor = pdfconstant("GoToR")
local pdf_goto = pdfconstant("GoTo")
@@ -133,6 +133,99 @@ local function checkautoprefixes(destinations)
end
end
+local maxslice = 32 -- could be made configureable ... 64 is also ok
+
+local function pdfmakenametree(list,apply)
+ if not next(list) then
+ return
+ end
+ local slices = { }
+ local sorted = sortedkeys(list)
+ local size = #sorted
+ local maxslice = maxslice
+ if size <= 1.5*maxslice then
+ maxslice = size
+ end
+ for i=1,size,maxslice do
+ local amount = min(i+maxslice-1,size)
+ local names = pdfarray { }
+ local n = 0
+ for j=i,amount do
+ local name = sorted[j]
+ local target = list[name]
+ n = n + 1 ; names[n] = tostring(name)
+ n = n + 1 ; names[n] = apply and apply(target) or target
+ end
+ local first = sorted[i]
+ local last = sorted[amount]
+ local limits = pdfarray {
+ first,
+ last,
+ }
+ local d = pdfdictionary {
+ Names = names,
+ Limits = limits,
+ }
+ slices[#slices+1] = {
+ reference = pdfreference(pdfflushobject(d)),
+ limits = limits,
+ }
+ end
+ local function collectkids(slices,first,last)
+ local f = slices[first]
+ local l = slices[last]
+ if f and l then
+ local k = pdfarray()
+ local n = 0
+ local d = pdfdictionary {
+ Kids = k,
+ Limits = pdfarray {
+ f.limits[1],
+ l.limits[2],
+ },
+ }
+ for i=first,last do
+ n = n + 1 ; k[n] = slices[i].reference
+ end
+ return d
+ end
+ end
+ if #slices == 1 then
+ return slices[1].reference
+ else
+ while true do
+ local size = #slices
+ if size > maxslice then
+ local temp = { }
+ local n = 0
+ for i=1,size,maxslice do
+ local kids = collectkids(slices,i,min(i+maxslice-1,size))
+ if kids then
+ n = n + 1
+ temp[n] = {
+ reference = pdfreference(pdfflushobject(kids)),
+ limits = kids.Limits,
+ }
+ else
+ -- error
+ end
+ end
+ slices = temp
+ else
+ local kids = collectkids(slices,1,size)
+ if kids then
+ return pdfreference(pdfflushobject(kids))
+ else
+ -- error
+ return
+ end
+ end
+ end
+ end
+end
+
+lpdf.makenametree = pdfmakenametree
+
-- Bah, I hate this kind of features .. anyway, as we have delayed resolving we
-- only support a document-wide setup and it has to be set before the first one
-- is used. Also, we default to a non-intrusive gray and the outline is kept
@@ -237,8 +330,6 @@ end
lpdf.registerdestination = pdfregisterdestination
-local maxslice = 32 -- could be made configureable ... 64 is also ok
-
logs.registerfinalactions(function()
if log_destinations and next(destinations) then
local report = logs.startfilelogging("references","used destinations")
@@ -252,98 +343,10 @@ logs.registerfinalactions(function()
end
end)
-local function pdfnametree(destinations)
- local slices = { }
- checkautoprefixes(destinations)
- if not next(destinations) then
- return
- end
- local sorted = sortedkeys(destinations)
- local size = #sorted
-
- if size <= 1.5*maxslice then
- maxslice = size
- end
-
- for i=1,size,maxslice do
- local amount = min(i+maxslice-1,size)
- local names = pdfarray { }
- local n = 0
- for j=i,amount do
- local destination = sorted[j]
- local pagenumber = destinations[destination]
- n = n + 1 ; names[n] = tostring(destination) -- tostring is a safeguard
- n = n + 1 ; names[n] = pdfreference(pagenumber)
- end
- local first = sorted[i]
- local last = sorted[amount]
- local limits = pdfarray {
- first,
- last,
- }
- local d = pdfdictionary {
- Names = names,
- Limits = limits,
- }
- slices[#slices+1] = {
- reference = pdfreference(pdfflushobject(d)),
- limits = limits,
- }
- end
- local function collectkids(slices,first,last)
- local f = slices[first]
- local l = slices[last]
- if f and l then
- local k = pdfarray()
- local n = 0
- local d = pdfdictionary {
- Kids = k,
- Limits = pdfarray {
- f.limits[1],
- l.limits[2],
- },
- }
- for i=first,last do
- n = n + 1 ; k[n] = slices[i].reference
- end
- return d
- end
- end
- if #slices == 1 then
- return slices[1].reference
- else
- while true do
- if #slices > maxslice then
- local temp = { }
- local size = #slices
- for i=1,size,maxslice do
- local kids = collectkids(slices,i,min(i+maxslice-1,size))
- if kids then
- temp[#temp+1] = {
- reference = pdfreference(pdfflushobject(kids)),
- limits = kids.Limits,
- }
- else
- -- error
- end
- end
- slices = temp
- else
- local kids = collectkids(slices,1,#slices)
- if kids then
- return pdfreference(pdfflushobject(kids))
- else
- -- error
- return
- end
- end
- end
- end
-end
-
local function pdfdestinationspecification()
if next(destinations) then -- safeguard
- local r = pdfnametree(destinations)
+ checkautoprefixes(destinations)
+ local r = pdfmakenametree(destinations,pdfreference)
if r then
pdfaddtonames("Dests",r)
end
@@ -353,7 +356,6 @@ local function pdfdestinationspecification()
end
end
-lpdf.nametree = pdfnametree
lpdf.destinationspecification = pdfdestinationspecification
lpdf.registerdocumentfinalizer(pdfdestinationspecification,"collect destinations")
@@ -362,25 +364,14 @@ lpdf.registerdocumentfinalizer(pdfdestinationspecification,"collect destinations
local destinations = { }
-local f_xyz = formatters["<< /D [ %i 0 R /XYZ %.6F %.6F null ] >>"]
+local f_xyz = formatters["<< /D [ %i 0 R /XYZ %.6N %.6N null ] >>"]
local f_fit = formatters["<< /D [ %i 0 R /Fit ] >>"]
local f_fitb = formatters["<< /D [ %i 0 R /FitB ] >>"]
-local f_fith = formatters["<< /D [ %i 0 R /FitH %.6F ] >>"]
-local f_fitv = formatters["<< /D [ %i 0 R /FitV %.6F ] >>"]
-local f_fitbh = formatters["<< /D [ %i 0 R /FitBH %.6F ] >>"]
-local f_fitbv = formatters["<< /D [ %i 0 R /FitBV %.6F ] >>"]
-local f_fitr = formatters["<< /D [ %i 0 R /FitR %.6F %.6F %.6F %.6F ] >>"]
-
-directives.register("pdf.stripzeros",function()
- f_xyz = formatters["<< /D [ %i 0 R /XYZ %.6N %.6N null ] >>"]
- f_fit = formatters["<< /D [ %i 0 R /Fit ] >>"]
- f_fitb = formatters["<< /D [ %i 0 R /FitB ] >>"]
- f_fith = formatters["<< /D [ %i 0 R /FitH %.6N ] >>"]
- f_fitv = formatters["<< /D [ %i 0 R /FitV %.6N ] >>"]
- f_fitbh = formatters["<< /D [ %i 0 R /FitBH %.6N ] >>"]
- f_fitbv = formatters["<< /D [ %i 0 R /FitBV %.6N ] >>"]
- f_fitr = formatters["<< /D [ %i 0 R /FitR %.6N %.6N %.6N %.6N ] >>"]
-end)
+local f_fith = formatters["<< /D [ %i 0 R /FitH %.6N ] >>"]
+local f_fitv = formatters["<< /D [ %i 0 R /FitV %.6N ] >>"]
+local f_fitbh = formatters["<< /D [ %i 0 R /FitBH %.6N ] >>"]
+local f_fitbv = formatters["<< /D [ %i 0 R /FitBV %.6N ] >>"]
+local f_fitr = formatters["<< /D [ %i 0 R /FitR %.6N %.6N %.6N %.6N ] >>"]
local v_standard = variables.standard
local v_frame = variables.frame
@@ -634,9 +625,9 @@ local function pdffilelink(filename,destination,page,actions)
destination = pdfarray { (page or 1) - 1, pdf_fit }
end
return pdfdictionary {
- S = pdf_gotor, -- can also be pdf_launch
- F = filename,
- D = destination or defaultdestination,
+ S = pdf_gotor, -- can also be pdf_launch
+ F = filename,
+ D = destination or defaultdestination,
NewWindow = actions.newwindow and true or nil,
}
end
@@ -758,11 +749,8 @@ local nofused = 0
local nofspecial = 0
local share = true
-local f_annot = formatters["<< /Type /Annot %s /Rect [ %0.6F %0.6F %0.6F %0.6F ] >>"]
-
-directives.register("pdf.stripzeros",function()
- f_annot = formatters["<< /Type /Annot %s /Rect [ %0.6N %0.6N %0.6N %0.6N ] >>"]
-end)
+local f_annot = formatters["<< /Type /Annot %s /Rect [ %.6N %.6N %.6N %.6N ] >>"]
+local f_quadp = formatters["<< /Type /Annot %s /QuadPoints [ %s ] /Rect [ %.6N %.6N %.6N %.6N ] >>"]
directives.register("references.sharelinks", function(v)
share = v
@@ -777,10 +765,41 @@ setmetatableindex(hashed,function(t,k)
return v
end)
-local function finishreference(specification) -- %0.2f looks okay enough (no scaling anyway)
- local annot = hashed[f_annot(specification.prerolled,pdfrectangle(specification.width,specification.height,specification.depth))]
+local function toquadpoints(paths)
+ local t, n = { }, 0
+ for i=1,#paths do
+ local path = paths[i]
+ local size = #path
+ for j=1,size do
+ local p = path[j]
+ n = n + 1 ; t[n] = p[1]
+ n = n + 1 ; t[n] = p[2]
+ end
+ local m = size % 4
+ if m > 0 then
+ local p = path[size]
+ for j=size+1,m do
+ n = n + 1 ; t[n] = p[1]
+ n = n + 1 ; t[n] = p[2]
+ end
+ end
+ end
+ return concat(t," ")
+end
+
+local function finishreference(specification)
+ local prerolled = specification.prerolled
+ local quadpoints = specification.mesh
+ local llx, lly,
+ urx, ury = pdfrectangle(specification.width,specification.height,specification.depth)
+ local specifier = nil
+ if quadpoints and #quadpoints > 0 then
+ specifier = f_quadp(prerolled,toquadpoints(quadpoints),llx,lly,urx,ury)
+ else
+ specifier = f_annot(prerolled,llx,lly,urx,ury)
+ end
nofused = nofused + 1
- return pdfregisterannotation(annot)
+ return pdfregisterannotation(hashed[specifier])
end
local function finishannotation(specification)
@@ -799,7 +818,7 @@ local function finishannotation(specification)
return pdfregisterannotation(objref)
end
-function nodeinjections.reference(width,height,depth,prerolled)
+function nodeinjections.reference(width,height,depth,prerolled,mesh)
if prerolled then
if trace_references then
report_references("link: width %p, height %p, depth %p, prerolled %a",width,height,depth,prerolled)
@@ -810,6 +829,7 @@ function nodeinjections.reference(width,height,depth,prerolled)
height = height,
depth = depth,
prerolled = prerolled,
+ mesh = mesh,
}
end
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lpdf-col.lua b/Master/texmf-dist/tex/context/base/mkiv/lpdf-col.lua
index 9ba64abba75..c586300e55b 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lpdf-col.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/lpdf-col.lua
@@ -6,6 +6,8 @@ if not modules then modules = { } end modules ['lpdf-col'] = {
license = "see context related readme files"
}
+-- slants also page ?
+
local type, next, tostring, tonumber = type, next, tostring, tonumber
local char, byte, format, gsub, rep, gmatch = string.char, string.byte, string.format, string.gsub, string.rep, string.gmatch
local settings_to_array, settings_to_numbers = utilities.parsers.settings_to_array, utilities.parsers.settings_to_numbers
@@ -58,25 +60,18 @@ local setmetatableindex = table.setmetatableindex
local c_transparency = pdfconstant("Transparency")
-local f_gray = formatters["%.3F g %.3F G"]
-local f_rgb = formatters["%.3F %.3F %.3F rg %.3F %.3F %.3F RG"]
-local f_cmyk = formatters["%.3F %.3F %.3F %.3F k %.3F %.3F %.3F %.3F K"]
+local f_gray = formatters["%.3N g %.3N G"]
+local f_rgb = formatters["%.3N %.3N %.3N rg %.3N %.3N %.3N RG"]
+local f_cmyk = formatters["%.3N %.3N %.3N %.3N k %.3N %.3N %.3N %.3N K"]
local f_spot = formatters["/%s cs /%s CS %s SCN %s scn"]
local f_tr = formatters["Tr%s"]
-local f_cm = formatters["q %.6F %.6F %.6F %.6F %.6F %.6F cm"]
-local f_effect = formatters["%s Tc %s w %s Tr"] -- %.3F ?
+local f_cm = formatters["q %.6N %.6N %.6N %.6N %.6N %.6N cm"]
+local f_effect = formatters["%s Tc %s w %s Tr"] -- %.6N ?
local f_tr_gs = formatters["/Tr%s gs"]
-local f_num_1 = tostring
-local f_num_2 = formatters["%s %s"]
-local f_num_3 = formatters["%s %s %s"]
-local f_num_4 = formatters["%s %s %s %s"]
-
-directives.register("pdf.stripzeros",function()
- f_gray = formatters["%.3N g %.3N G"]
- f_rgb = formatters["%.3N %.3N %.3N rg %.3N %.3N %.3N RG"]
- f_cmyk = formatters["%.3N %.3N %.3N %.3N k %.3N %.3N %.3N %.3N K"]
- f_cm = formatters["q %.6N %.6N %.6N %.6N %.6N %.6N cm"]
-end)
+local f_num_1 = formatters["%.3N %.3N"]
+local f_num_2 = formatters["%.3N %.3N"]
+local f_num_3 = formatters["%.3N %.3N %.3N"]
+local f_num_4 = formatters["%.3N %.3N %.3N %.3N"]
local report_color = logs.reporter("colors","backend")
@@ -733,43 +728,39 @@ do
local pdfcolor = lpdf.color
local pdftransparency = lpdf.transparency
- local f_slant = formatters["q 1 0 %.6F 1 0 0 cm"]
-
- directives.register("pdf.stripzeros",function()
- f_slant = formatters["q 1 0 %.6N 1 0 0 cm"]
- end)
+ local f_slant = formatters["q 1 0 %N 1 0 0 cm"]
-- local fillcolors = {
- -- red = { "pdf", "origin", "1 0 0 rg" },
- -- green = { "pdf", "origin", "0 1 0 rg" },
- -- blue = { "pdf", "origin", "0 0 1 rg" },
- -- gray = { "pdf", "origin", ".5 g" },
- -- black = { "pdf", "origin", "0 g" },
- -- palered = { "pdf", "origin", "1 .75 .75 rg" },
- -- palegreen = { "pdf", "origin", ".75 1 .75 rg" },
- -- paleblue = { "pdf", "origin", ".75 .75 1 rg" },
- -- palegray = { "pdf", "origin", ".75 g" },
+ -- red = { "pdf", "page", "1 0 0 rg" },
+ -- green = { "pdf", "page", "0 1 0 rg" },
+ -- blue = { "pdf", "page", "0 0 1 rg" },
+ -- gray = { "pdf", "page", ".5 g" },
+ -- black = { "pdf", "page", "0 g" },
+ -- palered = { "pdf", "page", "1 .75 .75 rg" },
+ -- palegreen = { "pdf", "page", ".75 1 .75 rg" },
+ -- paleblue = { "pdf", "page", ".75 .75 1 rg" },
+ -- palegray = { "pdf", "page", ".75 g" },
-- }
--
-- local strokecolors = {
- -- red = { "pdf", "origin", "1 0 0 RG" },
- -- green = { "pdf", "origin", "0 1 0 RG" },
- -- blue = { "pdf", "origin", "0 0 1 RG" },
- -- gray = { "pdf", "origin", ".5 G" },
- -- black = { "pdf", "origin", "0 G" },
- -- palered = { "pdf", "origin", "1 .75 .75 RG" },
- -- palegreen = { "pdf", "origin", ".75 1 .75 RG" },
- -- paleblue = { "pdf", "origin", ".75 .75 1 RG" },
- -- palegray = { "pdf", "origin", ".75 G" },
+ -- red = { "pdf", "page", "1 0 0 RG" },
+ -- green = { "pdf", "page", "0 1 0 RG" },
+ -- blue = { "pdf", "page", "0 0 1 RG" },
+ -- gray = { "pdf", "page", ".5 G" },
+ -- black = { "pdf", "page", "0 G" },
+ -- palered = { "pdf", "page", "1 .75 .75 RG" },
+ -- palegreen = { "pdf", "page", ".75 1 .75 RG" },
+ -- paleblue = { "pdf", "page", ".75 .75 1 RG" },
+ -- palegray = { "pdf", "page", ".75 G" },
-- }
--
-- backends.pdf.tables.vfspecials = allocate { -- todo: distinguish between glyph and rule color
--
- -- red = { "pdf", "origin", "1 0 0 rg 1 0 0 RG" },
- -- green = { "pdf", "origin", "0 1 0 rg 0 1 0 RG" },
- -- blue = { "pdf", "origin", "0 0 1 rg 0 0 1 RG" },
- -- gray = { "pdf", "origin", ".75 g .75 G" },
- -- black = { "pdf", "origin", "0 g 0 G" },
+ -- red = { "pdf", "page", "1 0 0 rg 1 0 0 RG" },
+ -- green = { "pdf", "page", "0 1 0 rg 0 1 0 RG" },
+ -- blue = { "pdf", "page", "0 0 1 rg 0 0 1 RG" },
+ -- gray = { "pdf", "page", ".75 g .75 G" },
+ -- black = { "pdf", "page", "0 g 0 G" },
--
-- -- rulecolors = fillcolors,
-- -- fillcolors = fillcolors,
@@ -792,7 +783,7 @@ do
local c_cache = setmetatableindex(function(t,m)
local v = setmetatableindex(function(t,c)
- local p = { "pdf", "origin", "q " .. pdfcolor(m,c) }
+ local p = { "pdf", "page", "q " .. pdfcolor(m,c) }
t[c] = p
return p
end)
@@ -806,7 +797,7 @@ do
local p = pdftransparency(transparency)
local v = setmetatableindex(function(t,colormodel)
local v = setmetatableindex(function(t,color)
- local v = { "pdf", "origin", "q " .. pdfcolor(colormodel,color) .. " " .. p }
+ local v = { "pdf", "page", "q " .. pdfcolor(colormodel,color) .. " " .. p }
t[color] = v
return v
end)
@@ -830,8 +821,8 @@ do
backends.pdf.tables.vfspecials = allocate { -- todo: distinguish between glyph and rule color
startcolor = startcolor,
- -- stopcolor = { "pdf", "origin", "0 g 0 G Q" },
- stopcolor = { "pdf", "origin", "Q" },
+ -- stopcolor = { "pdf", "page", "0 g 0 G Q" },
+ stopcolor = { "pdf", "page", "Q" },
startslant = startslant,
stopslant = { "pdf", "origin", "Q" },
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lpdf-emb.lua b/Master/texmf-dist/tex/context/base/mkiv/lpdf-emb.lua
new file mode 100644
index 00000000000..4ffcfd8a846
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/lpdf-emb.lua
@@ -0,0 +1,2224 @@
+if not modules then modules = { } end modules ['lpdf-ini'] = {
+ version = 1.001,
+ comment = "companion to lpdf-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- vkgoeswild: Pink Floyd - Shine on You Crazy Diamond - piano cover (around that
+-- time I redid the code, a reminder so to say)
+
+-- At some point I wanted to have access to the shapes so that we could use them in
+-- metapost. So, after looking at the cff and ttf specifications, I decided to write
+-- parsers. At somepoint we needed a cff parser anyway in order to calculate the
+-- dimensions. Then variable fonts came around and a option was added to recreate
+-- streams of operators and a logical next step was to do all inclusion that way. It
+-- was only then that I found out that some of the juggling also happens in the the
+-- backend, but spread over places, so I could have saved myself some time
+-- deciphering the specifications. Anyway, here we go.
+--
+-- Color fonts are a bit messy. Catching issues with older fonts will break new ones
+-- so I don't think that it's wise to build in too many catches (like for fonts with
+-- zero boundingboxes, weird dimensions, transformations that in a next version are
+-- fixed, etc.). Better is then to wait till something gets fixed. If a spec doesn't
+-- tell me how to deal with it ... I'll happily wait till it does. After all we're
+-- not in a hurry as these fonts are mostly meant for the web or special purposes
+-- with manual tweaking in desk top publishing applications. Keep in mind that Emoji
+-- can have funny dimensions (e.g. to be consistent within a font, so no tight ones).
+
+-- When we have moved to lmtx I will document a bit more. Till then it's experimental
+-- and subjected to change.
+
+local next, type, unpack, rawget = next, type, unpack, rawget
+local char, byte, gsub, sub, match, rep, gmatch = string.char, string.byte, string.gsub, string.sub, string.match, string.rep, string.gmatch
+local formatters = string.formatters
+local format = string.format
+local concat, sortedhash, sort = table.concat, table.sortedhash, table.sort
+local utfchar = utf.char
+local random, round, max, abs, ceiling = math.random, math.round, math.max, math.abs, math.ceiling
+local extract, lshift, rshift, band, bor = bit32.extract, bit32.lshift, bit32.rshift, bit32.band, bit32.bor
+local idiv = number.idiv
+local setmetatableindex = table.setmetatableindex
+
+local pdfnull = lpdf.null
+local pdfdictionary = lpdf.dictionary
+local pdfarray = lpdf.array
+local pdfconstant = lpdf.constant
+local pdfstring = lpdf.string
+local pdfreference = lpdf.reference
+local pdfreserveobject = lpdf.reserveobject
+local pdfflushobject = lpdf.flushobject
+local pdfflushstreamobject = lpdf.flushstreamobject
+
+local report_fonts = logs.reporter("backend","fonts")
+
+local trace_fonts = false
+local trace_details = false
+
+local dimenfactors = number.dimenfactors
+local bpfactor = dimenfactors.bp
+local ptfactor = dimenfactors.pt
+
+trackers.register("backend.pdf.fonts",function(v) trace_fonts = v end)
+
+local readers = fonts.handlers.otf.readers
+local getinfo = readers.getinfo
+
+local setposition = utilities.files.setposition
+local readstring = utilities.files.readstring
+local openfile = utilities.files.open
+local closefile = utilities.files.close
+
+
+-- needs checking: signed vs unsigned
+
+local tocardinal1 = char
+
+local function tocardinal2(n)
+ return char(extract(n,8,8),extract(n,0,8))
+end
+
+local function tocardinal3(n)
+ return char(extract(n,16,8),extract(n,8,8),extract(n,0,8))
+end
+
+local function tocardinal4(n)
+ return char(extract(n,24,8),extract(n,16,8),extract(n,8,8),extract(n,0,8))
+end
+
+local function tointeger2(n)
+ return char(extract(n,8,8),extract(n,0,8))
+end
+
+local function tointeger3(n)
+ return char(extract(n,16,8),extract(n,8,8),extract(n,0,8))
+end
+
+local function tointeger4(n)
+ return char(extract(n,24,8),extract(n,16,8),extract(n,8,8),extract(n,0,8))
+end
+
+local function tocardinal8(n)
+ local l = idiv(n,0x100000000)
+ local r = n % 0x100000000
+ return char(extract(l,24,8),extract(l,16,8),extract(l,8,8),extract(l,0,8),
+ extract(r,24,8),extract(r,16,8),extract(r,8,8),extract(r,0,8))
+end
+
+-- A couple of shared helpers.
+
+local tounicodedictionary, widtharray, collectindices, subsetname, includecidset, forcecidset, tocidsetdictionary
+
+do
+
+ -- Because we supply tounicodes ourselves we only use bfchar mappings (as in the
+ -- backend). In fact, we can now no longer pass the tounicodes to the frontend but
+ -- pick them up from the descriptions.
+
+ local f_mapping_2 = formatters["<%02X> <%s>"]
+ local f_mapping_4 = formatters["<%04X> <%s>"]
+
+ local tounicode = fonts.mappings.tounicode
+
+local tounicode_template = [[
+%%!PS-Adobe-3.0 Resource-CMap
+%%%%DocumentNeededResources: ProcSet (CIDInit)
+%%%%IncludeResource: ProcSet (CIDInit)
+%%%%BeginResource: CMap (TeX-%s-0)
+%%%%Title: (TeX-%s-0 TeX %s 0)|
+%%%%Version: 1.000
+%%%%EndComments
+/CIDInit /ProcSet findresource begin
+ 12 dict begin
+ begincmap
+ /CIDSystemInfo
+ << /Registry (TeX) /Ordering (%s) /Supplement 0 >>
+ def
+ /CMapName
+ /TeX-Identity-%s
+ def
+ /CMapType
+ 2
+ def
+ 1 begincodespacerange
+ <%s> <%s>
+ endcodespacerange
+ %i beginbfchar
+%s
+ endbfchar
+ endcmap
+ CMapName currentdict /CMap defineresource pop
+ end
+end
+%%%%EndResource
+%%%%EOF]]
+
+ tounicodedictionary = function(details,indices,maxindex,name,wide)
+ local mapping = { }
+ local length = 0
+ if maxindex > 0 then
+ local f_mapping = wide and f_mapping_4 or f_mapping_2
+ for index=1,maxindex do
+ local data = indices[index]
+ if data then
+ length = length + 1
+ local unicode = data.unicode
+ if unicode then
+ unicode = tounicode(unicode)
+ else
+ unicode = "FFFD"
+ end
+ mapping[length] = f_mapping(index,unicode)
+ end
+ end
+ end
+ local name = gsub(name,"%+","-") -- like luatex does
+ local first = wide and "0000" or "00"
+ local last = wide and "FFFF" or "FF"
+ local blob = format(tounicode_template,name,name,name,name,name,first,last,length,concat(mapping,"\n"))
+ return blob
+ end
+
+ widtharray = function(details,indices,maxindex,units)
+ local widths = pdfarray()
+ local length = 0
+ local factor = 10000 / units
+ if maxindex > 0 then
+ local lastindex = -1
+ local sublist = nil
+ for index=1,maxindex do
+ local data = indices[index]
+ if data then
+ local width = data.width -- hm, is inaccurate for cff, so take from elsewhere
+ if width then
+ -- width = round(width * 10000 / units) / 10
+ width = round(width * factor) / 10
+ else
+ width = 0
+ end
+ if index == lastindex + 1 then
+ sublist[#sublist+1] = width
+ else
+ if sublist then
+ length = length + 1
+ widths[length] = sublist
+ end
+ sublist = pdfarray { width }
+ length = length + 1
+ widths[length] = index
+ end
+ lastindex = index
+ end
+ end
+ length = length + 1
+ widths[length] = sublist
+ end
+ return widths
+ end
+
+ collectindices = function(descriptions,indices)
+ local minindex = 0xFFFF
+ local maxindex = 0
+ local reverse = { }
+ -- todo: already at definition time trigger copying streams
+ -- and add extra indices ... first i need a good example of
+ -- a clash
+ -- for unicode, data in next, descriptions do
+ -- local i = data.index or unicode
+ -- if reverse[i] then
+ -- print("CLASH")
+ -- else
+ -- reverse[i] = data
+ -- end
+ -- end
+ for unicode, data in next, descriptions do
+ reverse[data.index or unicode] = data
+ end
+ for index in next, indices do
+ if index > maxindex then
+ maxindex = index
+ end
+ if index < minindex then
+ minindex = index
+ end
+ indices[index] = reverse[index]
+ end
+ if minindex > maxindex then
+ minindex = maxindex
+ end
+ return indices, minindex, maxindex
+ end
+
+ includecidset = false
+ forcecidset = false -- for private testing only
+
+ directives.register("backend.pdf.forcecidset",function(v)
+ forcecidset = v
+ end)
+
+ tocidsetdictionary = function(indices,min,max)
+ if includecidset or forcecidset then
+ local b = { }
+ local m = idiv(max+7,8)
+ for i=0,max do
+ b[i] = 0
+ end
+ b[0] = bor(b[0],lshift(1,7)) -- force notdef into the file
+ for i=min,max do
+ if indices[i] then
+ local bi = idiv(i,8)
+ local ni = i % 8
+ b[bi] = bor(b[bi],lshift(1,7-ni))
+ end
+ end
+ b = char(unpack(b,0,#b))
+ return pdfreference(pdfflushstreamobject(b))
+ end
+ end
+
+ -- Actually we can use the same as we only embed once.
+
+ -- subsetname = function(name)
+ -- return "CONTEXT" .. name
+ -- end
+
+ local prefixes = { } -- todo: set fixed one
+
+ subsetname = function(name)
+ local prefix
+ while true do
+ prefix = utfchar(random(65,90),random(65,90),random(65,90),random(65,90),random(65,90),random(65,90))
+ if not prefixes[prefix] then
+ prefixes[prefix] = true
+ break
+ end
+ end
+ return prefix .. "+" .. name
+ end
+
+end
+
+-- Map file mess.
+
+local loadmapfile, loadmapline, getmapentry do
+
+ -- We only need to pick up the filename and optionally the enc file
+ -- as we only use them for old school virtual math fonts. We might as
+ -- we drop this completely.
+
+ local find, match, splitlines = string.find, string.match, string.splitlines
+
+
+ local mappings = { }
+
+ loadmapline = function(n)
+ if trace_fonts then
+ report_fonts("mapline: %s",n)
+ end
+ local name, fullname, encfile, pfbfile = match(n,"(%S+)%s+(%S+).-<(.-%.enc).-<(.-%.pfb)")
+ if name then
+ mappings[name] = { fullname, encfile, pfbfile }
+ end
+ end
+
+ loadmapfile = function(n)
+ local okay, data = resolvers.loadbinfile(n,"map")
+ if okay and data then
+ data = splitlines(data)
+ for i=1,#data do
+ local d = data[i]
+ if d ~= "" and not find(d,"^[#%%]") then
+ loadmapline(d)
+ end
+ end
+ end
+ end
+
+ getmapentry = function(n)
+ local n = file.nameonly(n)
+ local m = mappings[n]
+ if m then
+ local encfile = m[2]
+ local encoding = fonts.encodings.load(encfile)
+ if not encoding then
+ return
+ end
+ local pfbfile = resolvers.findfile(m[3],"pfb")
+ if not pfbfile or pfbfile == "" then
+ return
+ end
+ return encoding, pfbfile, encfile
+ end
+ end
+
+ lpdf.getmapentry = getmapentry
+
+end
+
+-- The three writers: opentype, truetype and type1.
+
+local mainwriters = { }
+
+do
+
+ -- advh = os2.ascender - os2.descender
+ -- tsb = default_advh - os2.ascender
+
+ -- truetype has the following tables:
+
+ -- head : mandate
+ -- hhea : mandate
+ -- vhea : mandate
+ -- hmtx : mandate
+ -- maxp : mandate
+ -- glyf : mandate
+ -- loca : mandate
+ --
+ -- cvt : if needed (but we flatten)
+ -- fpgm : if needed (but we flatten)
+ -- prep : if needed (but we flatten)
+ -- PCLT : if needed (but we flatten)
+ --
+ -- name : not needed for T2: backend does that
+ -- post : not needed for T2: backend does that
+ -- OS/2 : not needed for T2: backend does that
+ -- cmap : not needed for T2: backend does that
+
+ local streams = utilities.streams
+ local openstring = streams.openstring
+ local readcardinal2 = streams.readcardinal2
+ ----- readcardinal4 = streams.readcardinal4
+
+ local otfreaders = fonts.handlers.otf.readers
+
+ local function readcardinal4(f) -- this needs to be sorted out
+ local a = readcardinal2(f)
+ local b = readcardinal2(f)
+ if a and b then
+ return a * 0x10000 + b
+ end
+ end
+
+ -- -- --
+
+ local tablereaders = { }
+ local tablewriters = { }
+ local tablecreators = { }
+ local tableloaders = { }
+
+ local openfontfile, closefontfile, makefontfile, makemetadata do
+
+ local details = {
+ details = true,
+ platformnames = true,
+ platformextras = true,
+ }
+
+ -- .022 sec on luatex manual, neglectable:
+
+ -- local function checksum(data)
+ -- local s = openstring(data)
+ -- local n = 0
+ -- local d = #data
+ -- while true do
+ -- local c = readcardinal4(s)
+ -- if c then
+ -- n = (n + c) % 0x100000000
+ -- else
+ -- break
+ -- end
+ -- end
+ -- return n
+ -- end
+
+ local function checksum(data)
+ local s = openstring(data)
+ local n = 0
+ local d = #data
+ while true do
+ local a = readcardinal2(s)
+ local b = readcardinal2(s)
+ if b then
+ n = (n + a * 0x10000 + b) % 0x100000000
+ else
+ break
+ end
+ end
+ return n
+ end
+
+ openfontfile = function(details)
+ return {
+ offset = 0,
+ order = { },
+ used = { },
+ details = details,
+ streams = details.streams,
+ }
+ end
+
+ closefontfile = function(fontfile)
+ for k, v in next, fontfile do
+ fontfile[k] = nil -- so it can be collected asap
+ end
+ end
+
+ local metakeys = {
+ "uniqueid", "version",
+ "copyright", "license", "licenseurl",
+ "manufacturer", "vendorurl",
+ "family", "subfamily",
+ "typographicfamily", "typographicsubfamily",
+ "fullname", "postscriptname",
+ }
+
+ local template = [[
+<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
+ <x:xmpmeta xmlns:x="adobe:ns:meta/">
+ <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+ <rdf:Description rdf:about="" xmlns:pdfx="http://ns.adobe.com/pdfx/1.3/">
+
+%s
+
+ </rdf:Description>
+ </rdf:RDF>
+ </x:xmpmeta>
+<?xpacket end="w"?>]]
+
+ makemetadata = function(fontfile)
+ local names = fontfile.streams.names
+ local list = { }
+ local f_name = formatters["<pdfx:%s>%s</pdfx:%s>"]
+ for i=1,#metakeys do
+ local m = metakeys[i]
+ local n = names[m]
+ if n then
+ list[#list+1] = f_name(m,n,m)
+ end
+ end
+ return format(template,concat(list,"\n"))
+ end
+
+ makefontfile = function(fontfile)
+ local order = fontfile.order
+ local used = fontfile.used
+ local count = 0
+ for i=1,#order do
+ local tag = order[i]
+ local data = fontfile[tag]
+ if data and #data > 0 then
+ count = count + 1
+ else
+ fontfile[tag] = false
+ end
+ end
+ local offset = 12 + (count * 16)
+ local headof = 0
+ local list = {
+ "" -- placeholder
+ }
+ local i = 1
+ local k = 0
+ while i <= count do
+ i = lshift(i,1)
+ k = k + 1
+ end
+ local searchrange = lshift(i,3)
+ local entryselector = k - 1
+ local rangeshift = lshift(count,4) - lshift(i,3)
+ local index = {
+ tocardinal4(0x00010000), -- tables.version
+ tocardinal2(count),
+ tocardinal2(searchrange),
+ tocardinal2(entryselector),
+ tocardinal2(rangeshift),
+ }
+ --
+ local ni = #index
+ local nl = #list
+ for i=1,#order do
+ local tag = order[i]
+ local data = fontfile[tag]
+ if data then
+ local csum = checksum(data)
+ local dlength = #data
+ local length = idiv(dlength+3,4) * 4
+ local padding = length - dlength
+ nl = nl + 1 ; list[nl] = data
+ for i=1,padding do
+ nl = nl + 1 ; list[nl] = "\0"
+ end
+ if #tag == 3 then
+ tag = tag .. " "
+ end
+ ni = ni + 1 ; index[ni] = tag -- must be 4 chars
+ ni = ni + 1 ; index[ni] = tocardinal4(csum)
+ ni = ni + 1 ; index[ni] = tocardinal4(offset)
+ ni = ni + 1 ; index[ni] = tocardinal4(dlength)
+ used[i] = offset -- not used
+ if tag == "head" then
+ headof = offset
+ end
+ offset = offset + length
+ end
+ end
+ list[1] = concat(index)
+ local off = #list[1] + headof + 1 + 8
+ list = concat(list)
+ local csum = (0xB1B0AFBA - checksum(list)) % 0x100000000
+ list = sub(list,1,off-1) .. tocardinal4(csum) .. sub(list,off+4,#list)
+ return list
+ end
+
+ local function register(fontfile,name)
+ local u = fontfile.used
+ local o = fontfile.order
+ if not u[name] then
+ o[#o+1] = name
+ u[name] = true
+ end
+ end
+
+ local function create(fontfile,name)
+ local t = { }
+ fontfile[name] = t
+ return t
+ end
+
+ local function write(fontfile,name)
+ local t = fontfile[name]
+ if not t then
+ return
+ end
+ register(fontfile,name)
+ if type(t) == "table" then
+ if t[0] then
+ fontfile[name] = concat(t,"",0,#t)
+ elseif #t > 0 then
+ fontfile[name] = concat(t)
+ else
+ fontfile[name] = false
+ end
+ end
+ end
+
+ tablewriters.head = function(fontfile)
+ register(fontfile,"head")
+ local t = fontfile.streams.fontheader
+ fontfile.head = concat {
+ tocardinal4(t.version),
+ tocardinal4(t.fontversionnumber),
+ tocardinal4(t.checksum),
+ tocardinal4(t.magic),
+ tocardinal2(t.flags),
+ tocardinal2(t.units),
+ tocardinal8(t.created),
+ tocardinal8(t.modified),
+ tocardinal2(t.xmin),
+ tocardinal2(t.ymin),
+ tocardinal2(t.xmax),
+ tocardinal2(t.ymax),
+ tocardinal2(t.macstyle),
+ tocardinal2(t.smallpixels),
+ tocardinal2(t.directionhint),
+ tocardinal2(t.indextolocformat),
+ tocardinal2(t.glyphformat),
+ }
+ end
+
+ tablewriters.hhea = function(fontfile)
+ register(fontfile,"hhea")
+ local t = fontfile.streams.horizontalheader
+ local n = t and fontfile.nofglyphs or 0
+ fontfile.hhea = concat {
+ tocardinal4(t.version),
+ tocardinal2(t.ascender),
+ tocardinal2(t.descender),
+ tocardinal2(t.linegap),
+ tocardinal2(t.maxadvancewidth),
+ tocardinal2(t.minleftsidebearing),
+ tocardinal2(t.minrightsidebearing),
+ tocardinal2(t.maxextent),
+ tocardinal2(t.caretsloperise),
+ tocardinal2(t.caretsloperun),
+ tocardinal2(t.caretoffset),
+ tocardinal2(t.reserved_1),
+ tocardinal2(t.reserved_2),
+ tocardinal2(t.reserved_3),
+ tocardinal2(t.reserved_4),
+ tocardinal2(t.metricdataformat),
+ tocardinal2(n) -- t.nofmetrics
+ }
+ end
+
+ tablewriters.vhea = function(fontfile)
+ local t = fontfile.streams.verticalheader
+ local n = t and fontfile.nofglyphs or 0
+ register(fontfile,"vhea")
+ fontfile.vhea = concat {
+ tocardinal4(t.version),
+ tocardinal2(t.ascender),
+ tocardinal2(t.descender),
+ tocardinal2(t.linegap),
+ tocardinal2(t.maxadvanceheight),
+ tocardinal2(t.mintopsidebearing),
+ tocardinal2(t.minbottomsidebearing),
+ tocardinal2(t.maxextent),
+ tocardinal2(t.caretsloperise),
+ tocardinal2(t.caretsloperun),
+ tocardinal2(t.caretoffset),
+ tocardinal2(t.reserved_1),
+ tocardinal2(t.reserved_2),
+ tocardinal2(t.reserved_3),
+ tocardinal2(t.reserved_4),
+ tocardinal2(t.metricdataformat),
+ tocardinal2(n) -- t.nofmetrics
+ }
+ end
+
+ tablewriters.maxp = function(fontfile)
+ register(fontfile,"maxp")
+ local t = fontfile.streams.maximumprofile
+ local n = fontfile.nofglyphs
+ -- if fontfile.streams.cffinfo then
+ -- error
+ -- end
+ fontfile.maxp = concat {
+ tocardinal4(0x00010000),
+ tocardinal2(n),
+ tocardinal2(t.points),
+ tocardinal2(t.contours),
+ tocardinal2(t.compositepoints),
+ tocardinal2(t.compositecontours),
+ tocardinal2(t.zones),
+ tocardinal2(t.twilightpoints),
+ tocardinal2(t.storage),
+ tocardinal2(t.functiondefs),
+ tocardinal2(t.instructiondefs),
+ tocardinal2(t.stackelements),
+ tocardinal2(t.sizeofinstructions),
+ tocardinal2(t.componentelements),
+ tocardinal2(t.componentdepth),
+ }
+ end
+
+ tablecreators.loca = function(fontfile) return create(fontfile,"loca") end
+ tablewriters .loca = function(fontfile) return write (fontfile,"loca") end
+
+ tablecreators.glyf = function(fontfile) return create(fontfile,"glyf") end
+ tablewriters .glyf = function(fontfile) return write (fontfile,"glyf") end
+
+ tablecreators.hmtx = function(fontfile) return create(fontfile,"hmtx") end
+ tablewriters .hmtx = function(fontfile) return write (fontfile,"hmtx") end
+
+ tablecreators.vmtx = function(fontfile) return create(fontfile,"vmtx") end
+ tablewriters .vmtx = function(fontfile) return write (fontfile,"vmtx") end
+
+ tableloaders .cmap = function(fontfile) return read (fontfile,"cmap") end
+ tablewriters .cmap = function(fontfile) return write (fontfile,"cmap") end
+
+ tableloaders .name = function(fontfile) return read (fontfile,"name") end
+ tablewriters .name = function(fontfile) return write (fontfile,"name") end
+
+ tableloaders .post = function(fontfile) return read (fontfile,"post") end
+ tablewriters .post = function(fontfile) return write (fontfile,"post") end
+
+ end
+
+ mainwriters["truetype"] = function(details)
+ --
+ local fontfile = openfontfile(details)
+ local basefontname = details.basefontname
+ local streams = details.streams
+ local blobs = streams.streams
+ local fontheader = streams.fontheader
+ local horizontalheader = streams.horizontalheader
+ local verticalheader = streams.verticalheader
+ local maximumprofile = streams.maximumprofile
+ local names = streams.names
+ local descriptions = details.rawdata.descriptions
+ local metadata = details.rawdata.metadata
+ local indices = details.indices
+ local metabbox = { fontheader.xmin, fontheader.ymin, fontheader.xmax, fontheader.ymax }
+ local indices,
+ minindex,
+ maxindex = collectindices(descriptions,indices)
+ local glyphstreams = tablecreators.glyf(fontfile)
+ local locations = tablecreators.loca(fontfile)
+ local horizontals = tablecreators.hmtx(fontfile)
+ local verticals = tablecreators.vmtx(fontfile)
+ --
+ local zero2 = tocardinal2(0)
+ local zero4 = tocardinal4(0)
+ --
+ local horizontal = horizontalheader.nofmetrics > 0
+ local vertical = verticalheader.nofmetrics > 0
+ --
+ local streamoffset = 0
+ local lastoffset = zero4
+ local g, h, v = 0, 0, 0
+ --
+ -- todo: locate notdef
+ --
+ if minindex > 0 then
+ local blob = blobs[0]
+ if blob and #blob > 0 then
+ locations[0] = lastoffset
+ g = g + 1 ; glyphstreams[g] = blob
+ h = h + 1 ; horizontals [h] = zero4
+ if vertical then
+ v = v + 1 ; verticals[v] = zero4
+ end
+ streamoffset = streamoffset + #blob
+ lastoffset = tocardinal4(streamoffset)
+ else
+ report_fonts("missing .notdef in font %a",basefontname)
+ end
+ -- todo: use a rep for h/v
+ for index=1,minindex-1 do
+ locations[index] = lastoffset
+ h = h + 1 ; horizontals[h] = zero4
+ if vertical then
+ v = v + 1 ; verticals[v] = zero4
+ end
+ end
+ end
+ for index=minindex,maxindex do
+ locations[index] = lastoffset
+ local data = indices[index]
+ if data then
+ local blob = blobs[index] -- we assume padding
+ if blob and #blob > 0 then
+ g = g + 1 ; glyphstreams[g] = blob
+ h = h + 1 ; horizontals [h] = tocardinal2(data.width or 0)
+ h = h + 1 ; horizontals [h] = tocardinal2(data.boundingbox[1])
+ if vertical then
+ v = v + 1 ; verticals[v] = tocardinal2(data.height or 0)
+ v = v + 1 ; verticals[v] = tocardinal2(data.boundingbox[3])
+ end
+ streamoffset = streamoffset + #blob
+ lastoffset = tocardinal4(streamoffset)
+ else
+ h = h + 1 ; horizontals[h] = zero4
+ if vertical then
+ v = v + 1 ; verticals[v] = zero4
+ end
+ report_fonts("missing blob for index %i in font %a",index,basefontname)
+ end
+ else
+ h = h + 1 ; horizontals[h] = zero4
+ if vertical then
+ v = v + 1 ; verticals[v] = zero4
+ end
+ end
+ end
+ locations[maxindex+1] = lastoffset -- cf spec
+ --
+ local nofglyphs = maxindex + 1 -- include zero
+ --
+ fontheader.checksum = 0
+ fontheader.indextolocformat = 1
+ maximumprofile.nofglyphs = nofglyphs
+ --
+ fontfile.format = "tff"
+ fontfile.basefontname = basefontname
+ fontfile.nofglyphs = nofglyphs
+ --
+ tablewriters.head(fontfile)
+ tablewriters.hhea(fontfile)
+ if vertical then
+ tablewriters.vhea(fontfile)
+ end
+ tablewriters.maxp(fontfile)
+
+ tablewriters.loca(fontfile)
+ tablewriters.glyf(fontfile)
+
+ tablewriters.hmtx(fontfile)
+ if vertical then
+ tablewriters.vmtx(fontfile)
+ end
+ --
+ local fontdata = makefontfile(fontfile)
+ local fontmeta = makemetadata(fontfile)
+ --
+ fontfile = closefontfile(fontfile)
+ --
+ local units = metadata.units
+ local basefont = pdfconstant(basefontname)
+ local widths = widtharray(details,indices,maxindex,units)
+ local object = details.objectnumber
+ local tounicode = tounicodedictionary(details,indices,maxindex,basefontname,true)
+ local tocidset = tocidsetdictionary(indices,minindex,maxindex)
+ local metabbox = metadata.boundingbox or { 0, 0, 0, 0 }
+ local fontbbox = pdfarray { unpack(metabbox) }
+ local ascender = metadata.ascender
+ local descender = metadata.descender
+ local capheight = metadata.capheight or fontbbox[4]
+ local stemv = metadata.weightclass
+ local italicangle = metadata.italicangle
+ local xheight = metadata.xheight or fontbbox[4]
+ --
+ if stemv then
+ stemv = (stemv/65)^2 + 50
+ end
+ --
+ local function scale(n)
+ if n then
+ return round((n) * 10000 / units) / 10
+ else
+ return 0
+ end
+ end
+ --
+ local reserved = pdfreserveobject()
+ local child = pdfdictionary {
+ Type = pdfconstant("Font"),
+ Subtype = pdfconstant("CIDFontType2"),
+ BaseFont = basefont,
+ FontDescriptor = pdfreference(reserved),
+ W = pdfreference(pdfflushobject(widths)),
+ CIDToGIDMap = pdfconstant("Identity"),
+ CIDSystemInfo = pdfdictionary {
+ Registry = pdfstring("Adobe"),
+ Ordering = pdfstring("Identity"),
+ Supplement = 0,
+ }
+ }
+ local descendants = pdfarray {
+ pdfreference(pdfflushobject(child)),
+ }
+ local descriptor = pdfdictionary {
+ Type = pdfconstant("FontDescriptor"),
+ FontName = basefont,
+ Flags = 4,
+ FontBBox = fontbbox,
+ Ascent = scale(ascender),
+ Descent = scale(descender),
+ ItalicAngle = round(italicangle or 0),
+ CapHeight = scale(capheight),
+ StemV = scale(stemv),
+ XHeight = scale(xheight),
+ FontFile2 = pdfreference(pdfflushstreamobject(fontdata)),
+ CIDSet = tocidset,
+ Metadata = fontmeta and pdfreference(pdfflushstreamobject(fontmeta)) or nil,
+ }
+ local parent = pdfdictionary {
+ Type = pdfconstant("Font"),
+ Subtype = pdfconstant("Type0"),
+ Encoding = pdfconstant(details.properties.writingmode == "vertical" and "Identity-V" or "Identity-H"),
+ BaseFont = basefont,
+ DescendantFonts = descendants,
+ ToUnicode = pdfreference(pdfflushstreamobject(tounicode)),
+ }
+ pdfflushobject(reserved,descriptor)
+ pdfflushobject(object,parent)
+ --
+ -- if trace_details then
+ -- local name = "temp.ttf"
+ -- report_fonts("saving %a",name)
+ -- io.savedata(name,fontdata)
+ -- inspect(fonts.handlers.otf.readers.loadfont(name))
+ -- end
+ --
+ end
+
+ do
+ -- todo : cff2
+
+ local details = {
+ details = true,
+ platformnames = true,
+ platformextras = true,
+ }
+
+ tablecreators.cff = function(fontfile)
+ fontfile.charstrings = { }
+ fontfile.charmappings = { }
+ fontfile.cffstrings = { }
+ fontfile.cffhash = { }
+ return fontfile.charstrings , fontfile.charmappings
+ end
+
+ local todictnumber, todictreal, todictinteger, todictoffset do
+
+ local maxnum = 0x7FFFFFFF
+ local minnum = - 0x7FFFFFFF - 1
+ local epsilon = 1.0e-5
+
+ local int2tag = "\28"
+ local int4tag = "\29"
+ local realtag = "\30"
+
+ todictinteger = function(n)
+ if not n then
+ return char(band(139,0xFF))
+ elseif n >= -107 and n <= 107 then
+ return char(band(n + 139,0xFF))
+ elseif n >= 108 and n <= 1131 then
+ n = 0xF700 + n - 108
+ return char(band(rshift(n,8),0xFF),band(n,0xFF))
+ elseif n >= -1131 and n <= -108 then
+ n = 0xFB00 - n - 108
+ return char(band(rshift(n,8),0xFF),band(n,0xFF))
+ elseif n >= -32768 and n <= 32767 then
+ -- return int2tag .. tointeger2(n)
+ return char(28,extract(n,8,8),extract(n,0,8))
+ else
+ -- return int4tag .. tointeger4(n)
+ return char(29,extract(n,24,8),extract(n,16,8),extract(n,8,8),extract(n,0,8))
+ end
+ end
+
+ -- -- not called that often
+ --
+ -- local encoder = readers.cffencoder
+ --
+ -- todictinteger = function(n)
+ -- if not n then
+ -- return encoder[0]
+ -- elseif n >= -1131 and n <= 1131 then
+ -- return encoder[n]
+ -- elseif n >= -32768 and n <= 32767 then
+ -- -- return int2tag .. tointeger2(n)
+ -- return char(28,extract(n,8,8),extract(n,0,8))
+ -- else
+ -- -- return int4tag .. tointeger4(n)
+ -- return char(29,extract(n,24,8),extract(n,16,8),extract(n,8,8),extract(n,0,8))
+ -- end
+ -- end
+
+ todictoffset = function(n)
+ return int4tag .. tointeger4(n)
+ end
+
+ local e = false
+ local z = byte("0")
+ local dp = 10
+ local ep = 11
+ local em = 12
+ local mn = 14
+ local es = 15
+
+ local fg = formatters["%g"]
+
+ todictreal = function(v)
+ local s = fg(v)
+ local t = { [0] = realtag }
+ local n = 0
+ for s in gmatch(s,".") do
+ if s == "e" or s == "E" then
+ e = true
+ elseif s == "+" then
+ -- skip
+ elseif s == "-" then
+ n = n + 1
+ if e then
+ t[n] = em
+ e = false
+ else
+ t[n] = mn
+ end
+ else
+ if e then
+ n = n + 1
+ t[n] = ep
+ e = false
+ end
+ n = n + 1
+ if s == "." then
+ t[n] = dp
+ else
+ t[n] = byte(s) - z
+ end
+ end
+ end
+ n = n + 1
+ t[n] = es
+ if (n % 2) ~= 0 then
+ n = n + 1
+ t[n] = es
+ end
+ local j = 0
+ for i=1,n,2 do
+ j = j + 1
+ t[j] = char(t[i]*0x10+t[i+1])
+ end
+ t = concat(t,"",0,j)
+ return t
+ end
+
+ todictnumber = function(n)
+ if not n or n == 0 then
+ return todictinteger(0)
+ elseif (n > maxnum or n < minnum or (abs(n - round(n)) > epsilon)) then
+ return todictreal(n)
+ else
+ return todictinteger(n)
+ end
+ end
+
+ end
+
+ local todictkey = char
+
+ local function todictstring(fontfile,value)
+ if not value then
+ value = ""
+ end
+ local s = fontfile.cffstrings
+ local h = fontfile.cffhash
+ local n = h[value]
+ if not n then
+ n = #s + 1
+ s[n] = value
+ h[value] = n
+ end
+ return todictinteger(390+n)
+ end
+
+ local function todictboolean(b)
+ return todictinteger(b and 1 or 0)
+ end
+
+ local function todictdeltas(t)
+ local r = { }
+ for i=1,#t do
+ r[i] = todictnumber(t[i]-(t[i-1] or 0))
+ end
+ return concat(r)
+ end
+
+ local function todictarray(t)
+ local r = { }
+ for i=1,#t do
+ r[i] = todictnumber(t[i])
+ end
+ return concat(r)
+ end
+
+ local function writestring(target,source,offset,what)
+ target[#target+1] = source
+ -- report_fonts("string : %-11s %06i # %05i",what,offset,#source)
+ return offset + #source
+ end
+
+ local function writetable(target,source,offset,what)
+ source = concat(source)
+ target[#target+1] = source
+ -- report_fonts("table : %-11s %06i # %05i",what,offset,#source)
+ return offset + #source
+ end
+
+ local function writeindex(target,source,offset,what)
+ local n = #source
+ local t = #target
+ t = t + 1 ; target[t] = tocardinal2(n)
+ if n > 0 then
+ local data = concat(source)
+ local size = #data -- assume the worst
+ local offsetsize, tocardinal
+ if size < 0xFF then
+ offsetsize, tocardinal = 1, tocardinal1
+ elseif size < 0xFFFF then
+ offsetsize, tocardinal = 2, tocardinal2
+ elseif size < 0xFFFFFF then
+ offsetsize, tocardinal = 3, tocardinal3
+ elseif size < 0xFFFFFFFF then
+ offsetsize, tocardinal = 4, tocardinal4
+ end
+ -- report_fonts("index : %-11s %06i # %05i (%i entries with offset size %i)",what,offset,#data,n,offsetsize)
+ offset = offset + 2 + 1 + (n + 1) * offsetsize + size
+ -- bytes per offset
+ t = t + 1 ; target[t] = tocardinal1(offsetsize)
+ -- list of offsets (one larger for length calculation)
+ local offset = 1 -- mandate
+ t = t + 1 ; target[t] = tocardinal(offset)
+ for i=1,n do
+ offset = offset + #source[i]
+ t = t + 1 ; target[t] = tocardinal(offset)
+ end
+ t = t + 1 ; target[t] = data
+ else
+ -- report_fonts("index : %-11s %06i # %05i (no entries)",what,offset,0)
+ offset = offset + 2
+ end
+ -- print("offset",offset,#concat(target))
+ return offset
+ end
+
+ tablewriters.cff = function(fontfile)
+ --
+ local streams = fontfile.streams
+ local cffinfo = streams.cffinfo or { }
+ local names = streams.names or { }
+ local fontheader = streams.fontheader or { }
+ local basefontname = fontfile.basefontname
+ --
+ local offset = 0
+ local dictof = 0
+ local target = { }
+ --
+ local charstrings = fontfile.charstrings
+ local nofglyphs = #charstrings + 1
+ local fontmatrix = { 0.001, 0, 0, 0.001, 0, 0 } -- todo
+ local fontbbox = fontfile.fontbbox
+ local defaultwidth = cffinfo.defaultwidth or 0
+ local nominalwidth = cffinfo.nominalwidth or 0
+ local bluevalues = cffinfo.bluevalues
+ local otherblues = cffinfo.otherblues
+ local familyblues = cffinfo.familyblues
+ local familyotherblues = cffinfo.familyotherblues
+ local bluescale = cffinfo.bluescale
+ local blueshift = cffinfo.blueshift
+ local bluefuzz = cffinfo.bluefuzz
+ local stdhw = cffinfo.stdhw
+ local stdvw = cffinfo.stdvw
+ --
+ if defaultwidth == 0 then defaultwidth = nil end
+ if nomimalwidth == 0 then nominalwidth = nil end
+ if bluevalues then bluevalues = todictarray(bluevalues) end
+ if otherblues then otherblues = todictarray(otherblues) end
+ if familyblues then familyblues = todictarray(familyblues) end
+ if familyotherblues then familyotherblues = todictarray(familyotherblues) end
+ if bluescale then bluescale = todictnumber(bluescale) end
+ if blueshift then blueshift = todictnumber(blueshift) end
+ if bluefuzz then bluefuzz = todictnumber(bluefuzz) end
+ if stdhw then stdhw = todictdeltas(stdhw) end
+ if stdvw then stdvw = todictdeltas(stdvw) end
+ --
+ local fontversion = todictstring(fontfile,fontheader.fontversion or "uknown version")
+ local familyname = todictstring(fontfile,cffinfo.familyname or names.family or basefontname)
+ local fullname = todictstring(fontfile,cffinfo.fullname or basefontname)
+ local weight = todictstring(fontfile,cffinfo.weight or "Normal")
+ local fontbbox = todictarray(fontbbox)
+ local strokewidth = todictnumber(cffinfo.strokewidth)
+ local monospaced = todictboolean(cffinfo.monospaced)
+ local italicangle = todictnumber(cffinfo.italicangle)
+ local underlineposition = todictnumber(cffinfo.underlineposition)
+ local underlinethickness = todictnumber(cffinfo.underlinethickness)
+ local charstringtype = todictnumber(2)
+ local fontmatrix = todictarray(fontmatrix)
+ local ros = todictstring(fontfile,"Adobe") -- registry
+ .. todictstring(fontfile,"Identity") -- identity
+ .. todictnumber(0) -- supplement
+ local cidcount = todictnumber(fontfile.nofglyphs)
+ local fontname = todictstring(fontfile,basefontname)
+ local fdarrayoffset = todictoffset(0)
+ local fdselectoffset = todictoffset(0)
+ local charstringoffset = todictoffset(0)
+ local charsetoffset = todictoffset(0)
+ local privateoffset = todictoffset(0)
+ --
+ local defaultwidthx = todictnumber(defaultwidth)
+ local nominalwidthx = todictnumber(nominalwidth)
+ local private = ""
+ .. (defaultwidthx and (defaultwidthx .. todictkey(20)) or "")
+ .. (nominalwidthx and (nominalwidthx .. todictkey(21)) or "")
+ .. (bluevalues and (bluevalues .. todictkey(6)) or "")
+ .. (otherblues and (otherblues .. todictkey(7)) or "")
+ .. (familyblues and (familyblues .. todictkey(8)) or "")
+ .. (familyotherblues and (familyotherblues .. todictkey(9)) or "")
+ .. (bluescale and (bluescale .. todictkey(12,9)) or "")
+ .. (blueshift and (blueshift .. todictkey(12,10)) or "")
+ .. (bluefuzz and (bluefuzz .. todictkey(12,11)) or "")
+ .. (stdhw and (stdhw .. todictkey(12,12)) or "")
+ .. (stdvw and (stdvw .. todictkey(12,13)) or "")
+ local privatesize = todictnumber(#private)
+ local privatespec = privatesize .. privateoffset
+ --
+ -- header (fixed @ 1)
+ --
+ local header =
+ tocardinal1(1) -- major
+ .. tocardinal1(0) -- minor
+ .. tocardinal1(4) -- header size
+ .. tocardinal1(4) -- offset size
+ --
+ offset = writestring(target,header,offset,"header")
+ --
+ -- name index (fixed @ 2) (has to be sorted)
+ --
+ local names = {
+ basefontname,
+ }
+ --
+ offset = writeindex(target,names,offset,"names")
+ --
+ -- topdict index (fixed @ 3)
+ --
+ local topvars =
+ charstringoffset .. todictkey(17)
+ .. charsetoffset .. todictkey(15)
+ .. fdarrayoffset .. todictkey(12,36)
+ .. fdselectoffset .. todictkey(12,37)
+ .. privatespec .. todictkey(18)
+ --
+ local topdict = {
+ ros .. todictkey(12,30) -- first
+ .. cidcount .. todictkey(12,34)
+ .. familyname .. todictkey( 3)
+ .. fullname .. todictkey( 2)
+ .. weight .. todictkey( 4)
+ .. fontbbox .. todictkey( 5)
+ .. monospaced .. todictkey(12, 1)
+ .. italicangle .. todictkey(12, 2)
+ .. underlineposition .. todictkey(12, 3)
+ .. underlinethickness .. todictkey(12, 4)
+ .. charstringtype .. todictkey(12, 6)
+ .. fontmatrix .. todictkey(12, 7)
+ .. strokewidth .. todictkey(12, 8)
+ .. topvars
+ }
+ --
+ offset = writeindex(target,topdict,offset,"topdict")
+ dictof = #target
+ --
+ -- string index (fixed @ 4)
+ --
+ offset = writeindex(target,fontfile.cffstrings,offset,"strings")
+ --
+ -- global subroutine index (fixed @ 5)
+ --
+ offset = writeindex(target,{},offset,"globals")
+ --
+ -- Encoding (cff1)
+ --
+ -- offset = writeindex(target,{},offset,"encoding")
+ --
+ -- Charsets
+ --
+ charsetoffset = todictoffset(offset)
+ offset = writetable(target,fontfile.charmappings,offset,"charsets")
+ --
+ -- fdselect
+ --
+ local fdselect =
+ tocardinal1(3) -- format
+ .. tocardinal2(1) -- n of ranges
+ -- entry 1
+ .. tocardinal2(0) -- first gid
+ .. tocardinal1(0) -- fd index
+ -- entry 2
+-- .. tocardinal2(fontfile.sparsemax-1) -- sentinel
+ .. tocardinal2(fontfile.sparsemax) -- sentinel
+ --
+ fdselectoffset = todictoffset(offset)
+ offset = writestring(target,fdselect,offset,"fdselect")
+ --
+ -- charstrings
+ --
+ charstringoffset = todictoffset(offset)
+ offset = writeindex(target,charstrings,offset,"charstrings")
+ --
+ -- font dict
+ --
+ -- offset = writeindex(target,{},offset,"fontdict")
+ --
+ -- private
+ --
+ privateoffset = todictoffset(offset)
+ privatespec = privatesize .. privateoffset
+ offset = writestring(target,private,offset,"private")
+ --
+ local fdarray = {
+ fontname .. todictkey(12,38)
+ .. privatespec .. todictkey(18)
+ }
+ fdarrayoffset = todictoffset(offset)
+ offset = writeindex(target,fdarray,offset,"fdarray")
+ --
+ topdict = target[dictof]
+ topdict = sub(topdict,1,#topdict-#topvars)
+ topvars =
+ charstringoffset .. todictkey(17)
+ .. charsetoffset .. todictkey(15)
+ .. fdarrayoffset .. todictkey(12,36)
+ .. fdselectoffset .. todictkey(12,37)
+ .. privatespec .. todictkey(18)
+ target[dictof] = topdict .. topvars
+ --
+ target = concat(target)
+ -- if trace_details then
+ -- local name = "temp.cff"
+ -- report_fonts("saving %a",name)
+ -- io.savedata(name,target)
+ -- inspect(fonts.handlers.otf.readers.cffcheck(name))
+ -- end
+ return target
+ end
+
+ end
+
+ -- todo: check widths (missing a decimal)
+
+ mainwriters["opentype"] = function(details)
+ --
+ local fontfile = openfontfile(details)
+ local basefontname = details.basefontname
+ local streams = details.streams
+ local blobs = streams.streams
+ local fontheader = streams.fontheader
+ local maximumprofile = streams.maximumprofile
+ local names = streams.names
+ local descriptions = details.rawdata.descriptions
+ local metadata = details.rawdata.metadata
+ local indices = details.indices
+ local metabbox = { fontheader.xmin, fontheader.ymin, fontheader.xmax, fontheader.ymax }
+ local correction = 1
+
+ -- (*) We share code with type1 and when we have old school tfm with
+ -- pfb but without descriptions we're kind of toast.
+
+ if not descriptions or not next(descriptions) then
+ -- This is good enough, we only need indices and widths.
+ descriptions = details.fontdata.characters
+ -- This is a hack, we have no basepoints.
+ correction = details.fontdata.parameters.size / 1000
+ -- And this needs checking.
+ correction = correction * bpfactor / ptfactor
+ metadata = { }
+ end
+
+ --
+
+ local indices,
+ minindex,
+ maxindex = collectindices(descriptions,indices)
+ local streamoffset = 0
+ local glyphstreams,
+ charmappings = tablecreators.cff(fontfile)
+ --
+ local zero2 = tocardinal2(0)
+ local zero4 = tocardinal4(0)
+ --
+ -- we need to locate notdef (or store its unicode someplace)
+ --
+ local blob = blobs[0] or "\14"
+ local sparsemax = 1
+ local lastoffset = zero4
+ glyphstreams[sparsemax] = blob
+ charmappings[sparsemax] = tocardinal1(0) -- format 0
+ streamoffset = streamoffset + #blob
+ lastoffset = tocardinal4(streamoffset)
+ if minindex == 0 then
+ minindex = 1
+ end
+ for index=minindex,maxindex do
+ if indices[index] then
+ local blob = blobs[index] or "\14"
+ sparsemax = sparsemax + 1
+ glyphstreams[sparsemax] = blob
+ charmappings[sparsemax] = tocardinal2(index)
+ streamoffset = streamoffset + #blob
+ lastoffset = tocardinal4(streamoffset)
+ end
+ end
+ --
+ fontfile.nofglyphs = maxindex + 1
+ fontfile.sparsemax = sparsemax
+ fontfile.format = "cff"
+ fontfile.basefontname = basefontname
+ fontfile.fontbbox = metabbox
+ --
+ local fontdata = tablewriters.cff(fontfile)
+ local fontmeta = makemetadata(fontfile)
+ --
+ fontfile = closefontfile(fontfile)
+ --
+ local units = fontheader.units or metadata.units
+
+ local basefont = pdfconstant(basefontname)
+ local widths = widtharray(details,indices,maxindex,units * correction)
+ local object = details.objectnumber
+ local tounicode = tounicodedictionary(details,indices,maxindex,basefontname,true)
+ local tocidset = tocidsetdictionary(indices,minindex,maxindex)
+ local fontbbox = pdfarray { unpack(metabbox) }
+ local ascender = metadata.ascender or 0
+ local descender = metadata.descender or 0
+ local capheight = metadata.capheight or fontbbox[4]
+ local stemv = metadata.weightclass
+ local italicangle = metadata.italicangle
+ local xheight = metadata.xheight or fontbbox[4]
+ if stemv then
+ stemv = (stemv/65)^2 + 50
+ else
+-- stemv = 2
+ end
+ --
+ local function scale(n)
+ if n then
+ return round((n) * 10000 / units) / 10
+ else
+ return 0
+ end
+ end
+ --
+ local reserved = pdfreserveobject()
+ local child = pdfdictionary {
+ Type = pdfconstant("Font"),
+ Subtype = pdfconstant("CIDFontType0"),
+ BaseFont = basefont,
+ FontDescriptor = pdfreference(reserved),
+ W = pdfreference(pdfflushobject(widths)),
+ CIDSystemInfo = pdfdictionary {
+ Registry = pdfstring("Adobe"),
+ Ordering = pdfstring("Identity"),
+ Supplement = 0,
+ }
+ }
+ local descendants = pdfarray {
+ pdfreference(pdfflushobject(child)),
+ }
+ local fontstream = pdfdictionary {
+ Subtype = pdfconstant("CIDFontType0C"),
+ }
+ local descriptor = pdfdictionary {
+ Type = pdfconstant("FontDescriptor"),
+ FontName = basefont,
+ Flags = 4,
+ FontBBox = fontbbox,
+ Ascent = scale(ascender),
+ Descent = scale(descender),
+ ItalicAngle = round(italicangle or 0),
+ CapHeight = scale(capheight),
+ StemV = scale(stemv),
+ XHeight = scale(xheight),
+ CIDSet = tocidset,
+ FontFile3 = pdfreference(pdfflushstreamobject(fontdata,fontstream())),
+ Metadata = fontmeta and pdfreference(pdfflushstreamobject(fontmeta)) or nil,
+ }
+ local parent = pdfdictionary {
+ Type = pdfconstant("Font"),
+ Subtype = pdfconstant("Type0"),
+ Encoding = pdfconstant(details.properties.writingmode == "vertical" and "Identity-V" or "Identity-H"),
+ BaseFont = basefont,
+ DescendantFonts = descendants,
+ ToUnicode = pdfreference(pdfflushstreamobject(tounicode)),
+ }
+ pdfflushobject(reserved,descriptor)
+ pdfflushobject(object,parent)
+ end
+
+ mainwriters["type1"] = function(details)
+ -- We abuse the cff includer which is ok but for special cases like
+ -- tfm -> pfb we don't have the right descriptions and scale so this
+ -- is why we cheat elsewhere. Maybe I should just drop that kind of
+ -- support and assume afm files to be present. See (*) above.
+ local s = details.streams
+ local m = details.rawdata.metadata
+ if m then
+ local h = s.horizontalheader
+ local c = s.cffinfo
+ local n = s.names
+ h.ascender = m.ascender or h.ascender
+ h.descender = m.descender or h.descender
+ n.copyright = m.copyright or n.copyright
+ n.family = m.familyname or n.familyname
+ n.fullname = m.fullname or n.fullname
+ n.fontname = m.fontname or n.fontname
+ n.subfamily = m.subfamilyname or n.subfamilyname
+ n.version = m.version or n.version
+ setmetatableindex(h,m)
+ setmetatableindex(c,m)
+ setmetatableindex(n,m)
+ end
+ mainwriters["opentype"](details)
+ end
+
+ do
+
+ -- The methods might become plugins.
+
+ local methods = { }
+
+ local pdfimage = lpdf.epdf.image
+ local openpdf = pdfimage.open
+ local closepdf = pdfimage.close
+ local copypage = pdfimage.copy
+
+ local embedimage = images.embed
+
+ local f_glyph = formatters["G%d"]
+ local f_char = formatters["BT /V%d 1 Tf [<%04X>] TJ ET"]
+ local f_width = formatters["%.6N 0 d0"]
+ local f_index = formatters["I%d"]
+ local f_image_xy = formatters["%.6N 0 d0 1 0 0 1 %.6N %.6N cm /%s Do"]
+ local f_image_c = formatters["/%s Do"]
+ local f_image_c_xy = formatters["%.6N 0 0 %.6N %.6N %.6N cm /%s Do"]
+ local f_image_w = formatters["%.6N 0 d0 %s"]
+ local f_image_d = formatters["%.6N 0 d0 1 0 0 1 0 %.6N cm /%s Do"]
+ local f_stream = formatters["%.6N 0 d0 %s"]
+ local f_stream_c = formatters["%.6N 0 0 0 0 0 d1 %s"]
+ local f_stream_d = formatters["%.6N 0 d0 1 0 0 1 0 %.6N cm %s"]
+
+ -- A type 3 font has at most 256 characters and Acrobat also wants a zero slot
+ -- to be filled. We can share a mandate zero slot character. We also need to
+ -- make sure that we use bytes as index in the page stream as well as in the
+ -- tounicode vector.
+
+ local c_notdef = nil
+ local r_notdef = nil
+ local w_notdef = nil
+ local fontbbox = nil
+
+ -- pk inclusion (not really tested but not really used either)
+
+ function methods.pk(filename)
+ local pkfullname = resolvers.findpk(basedfontname,resolution)
+ if not pkfullname or pkfullname == "" then
+ return
+ end
+ local readers = fonts.handlers.tfm.readers
+ local result = readers.loadpk(pkfullname)
+ local convert = readers.pktopdf
+ if not result or result.error then
+ return
+ end
+ local resolution = 600
+ local widthfactor = resolution / 72
+ local scalefactor = 72 / resolution / 10
+ local factor = widthfactor / 65536
+ local function pktopdf(glyph,data)
+ return convert(glyph,data,factor) -- return pdfcode, width
+ end
+ return result.glyphs, scalefactor, pktopdf, false, false
+ end
+
+ -- pdf inclusion
+
+ local used = setmetatableindex("table")
+
+ function methods.pdf(filename,details)
+ local properties = details.properties
+ local pdfshapes = properties.indexdata[1]
+ local pdfdoc = openpdf(pdfshapes.filename)
+ local xforms = pdfdictionary()
+ local nofglyphs = 0
+ if pdfdoc then
+ local scale = 10 * details.parameters.size/details.parameters.designsize
+ local units = details.parameters.units
+ local factor = units * bpfactor / scale
+ local fixdepth = pdfshapes.fixdepth
+ local useddoc = used[pdfdoc]
+ local function pdftopdf(glyph,data)
+ local width = (data.width or 0) * factor
+ local image = useddoc[glyph]
+ local reference = nil
+ if not image then
+ image = embedimage(copypage(pdfdoc,glyph))
+ nofglyphs = nofglyphs + 1
+ local name = f_glyph(nofglyphs)
+ local stream = nil
+ if fixdepth then
+ local depth = data.depth or 0
+ local height = data.height or 0
+ if depth ~= 0 or height ~= 0 then
+ local d = data.dropin.descriptions[data.index]
+ local b = d.boundingbox
+ local l = b[1]
+ local r = b[3]
+ local w = r - l
+ local scale = w / d.width
+ local x = l
+ local y = - b[4] - b[2] - d.depth
+ local scale = w / (image.width * bpfactor)
+ stream = f_image_c_xy(scale,scale,x,y,name)
+ else
+ stream = f_image_c(name)
+ end
+ else
+ stream = f_image_c(name)
+ end
+ useddoc[glyph] = image
+ image.embedded_name = name
+ image.embedded_stream = stream
+ image.embedded_reference = pdfreference(image.objnum)
+ end
+ xforms[image.embedded_name] = image.embedded_reference
+ return f_image_w(width,image.embedded_stream), width
+ end
+ local function closepdf()
+ -- closepdf(pdfdoc)
+ end
+ local function getresources()
+ return pdfdictionary { XObject = xforms }
+ end
+ return pdfshapes, 1/units, pdftopdf, closepdf, getresources
+ end
+ end
+
+ -- mps inclusion
+
+ local decompress = gzip.decompress
+ local metapost = metapost
+ local simplemprun = metapost.simple
+ local setparameterset = metapost.setparameterset
+
+ function methods.mps(filename,details)
+ local properties = details.properties
+ local parameters = details.parameters
+ local mpshapes = properties.indexdata[1] -- indexdata will change
+ if mpshapes then
+ local scale = 10 * parameters.size/parameters.designsize
+ local units = mpshapes.units or parameters.units
+ local factor = units * bpfactor / scale
+ local fixdepth = mpshapes.fixdepth
+ local usecolor = mpshapes.usecolor
+ local specification = mpshapes.specification
+ local shapedefinitions = mpshapes.shapes
+ local instance = mpshapes.instance
+ --
+ simplemprun(instance,"begingroup;",true,true)
+ setparameterset("mpsfont",specification)
+ if shapedefinitions then
+ local preamble = shapedefinitions.parameters.preamble
+ if preamble then
+ simplemprun(instance,preamble,true,true)
+ end
+ end
+ --
+ local function mpstopdf(mp,data)
+ local width = data.width
+ if decompress then
+ mp = decompress(mp)
+ end
+ local pdf = simplemprun(instance,mp,true) -- can be sped up, minifun
+ local width = width * factor
+ if usecolor then
+ return f_stream_c(width,pdf), width
+ elseif fixdepth then
+ local depth = data.depth or 0
+ local height = data.height or 0
+ if depth ~= 0 or height ~= 0 then
+ return f_stream_d(width,(-height-depth)*factor,pdf), width
+ end
+ end
+ return f_stream(width,pdf), width
+ end
+ --
+ local function resetmps()
+ setparameterset("mpsfont")
+ simplemprun(instance,"endgroup;",true,true)
+ end
+ --
+ local function getresources()
+ return lpdf.collectedresources {
+ serialize = false,
+ }
+ end
+ --
+ return mpshapes, 1/units, mpstopdf, resetmps, getresources
+ end
+ end
+
+ -- png inclusion
+
+ -- With d1 the image mask is used when given and obeys color. So it is needed for pure bw
+ -- bitmap fonts, so here we really need d0.
+ --
+ -- Acrobat X pro only seems to see the image mask but other viewers are doing it ok. Acrobat
+ -- reader crashes. We really need to add a notdef!
+
+ local files = utilities.files
+ local openfile = files.open
+ local closefile = files.close
+ local setposition = files.setposition
+ local readstring = files.readstring
+
+ function methods.png(filename,details)
+ local properties = details.properties
+ local pngshapes = properties.indexdata[1]
+ if pngshapes then
+ local parameters = details.parameters
+ local png = properties.png
+ local hash = png.hash
+ local xforms = pdfdictionary()
+ local nofglyphs = 0
+ local scale = 10 * parameters.size/parameters.designsize
+ local factor = bpfactor / scale
+ -- local units = parameters.units -- / 1000
+ local units = 1000
+ local filehandle = openfile(details.filename,true)
+ local function pngtopdf(glyph,data)
+ -- local info = graphics.identifiers.png(glyph.data,"string")
+ local offset = glyph.o
+ local size = glyph.s
+ local pdfdata = nil
+ if offset and size then
+ setposition(filehandle,offset)
+ local blob = readstring(filehandle,size)
+ local info = graphics.identifiers.png(blob,"string")
+ info.enforcecmyk = pngshapes.enforcecmyk
+ local image = lpdf.injectors.png(info,"string")
+ local width = (data.width or 0) * factor
+ if image then
+ embedimage(image)
+ nofglyphs = nofglyphs + 1
+ local xoffset = (glyph.x or 0) / units
+ local yoffset = (glyph.y or 0) / units
+ local name = f_glyph(nofglyphs)
+ xforms[name] = pdfreference(image.objnum)
+ pdfdata = f_image_xy(width,xoffset,yoffset,name)
+ end
+ end
+ return pdfdata or f_stream(width), width
+ end
+ local function closepng()
+ if filehandle then
+ closefile(filehandle)
+ end
+ pngshapes = nil
+ end
+ local function getresources()
+ return pdfdictionary { XObject = xforms }
+ end
+ return pngshapes, 1, pngtopdf, closepng, getresources
+ end
+ end
+
+ function methods.color(filename,details)
+ local colrshapes = details.properties.indexdata[1]
+ local colrvalues = details.properties.indexdata[2]
+ local usedfonts = { }
+ local function colrtopdf(description,data)
+ -- descriptions by index
+ local colorlist = description.colors
+ if colorlist then
+ local dropdata = data.dropin
+ local dropid = dropdata.properties.id
+ local dropunits = dropdata.parameters.units -- shared
+ local descriptions = dropdata.descriptions
+ usedfonts[dropid] = dropid
+ local w = description.width or 0
+ local s = #colorlist
+ local l = nil
+ local t = { f_width(w) }
+ local n = 1
+ local d = colrvalues[#colrvalues]
+ for i=1,s do
+ local entry = colorlist[i]
+ local v = colrvalues[entry.class] or d
+ if v and l ~= v then
+ n = n + 1 ; t[n] = v
+ l = v
+ end
+ local e = descriptions[entry.slot]
+ if e then
+ n = n + 1 ; t[n] = f_char(dropid,e.index)
+ end
+ end
+ return concat(t," "), w / dropunits
+ end
+ end
+ local function getresources()
+ return lpdf.collectedresources {
+ serialize = false,
+ fonts = usedfonts,
+ fontprefix = "V",
+ }
+ end
+ return colrshapes, 1, colrtopdf, false, getresources
+ end
+
+ mainwriters["type3"] = function(details)
+ local properties = details.properties
+ local basefontname = details.basefontname or properties.name
+ local askedmethod = properties.method or "pk"
+ local method = methods[askedmethod] or methods.pk
+ if not method then
+ return
+ end
+ local glyphs, scalefactor, glyphtopdf, reset, getresources = method(basedfontname,details)
+ if not glyphs then
+ return
+ end
+ local parameters = details.parameters
+ local object = details.objectnumber
+ local factor = parameters.factor -- normally 1
+ local fontmatrix = pdfarray { scalefactor, 0, 0, scalefactor, 0, 0 }
+ local indices,
+ minindex,
+ maxindex = collectindices(details.fontdata.characters,details.indices)
+ local widths = pdfarray()
+ local differences = pdfarray()
+ local charprocs = pdfdictionary()
+ local basefont = pdfconstant(basefontname)
+ local d = 0
+ local w = 0
+ local forcenotdef = minindex > 0
+ local lastindex = -0xFF
+ if forcenotdef then
+ widths[0] = 0
+ minindex = 0
+ lastindex = 0
+ d = 2
+ if not c_notdef then
+ w_notdef = 0
+ c_notdef = pdfconstant(".notdef")
+ r_notdef = pdfreference(pdfflushstreamobject("0 0 d0"))
+ end
+ differences[1] = w_notdef
+ differences[2] = c_notdef
+ charprocs[".notdef"] = r_notdef
+ end
+
+ for i=1,maxindex-minindex+1 do
+ widths[i] = 0
+ end
+
+ for index, data in sortedhash(indices) do
+ local name = f_index(index)
+ local glyph = glyphs[index]
+ if glyph then
+ local stream, width = glyphtopdf(glyph,data)
+ if stream then
+ if index - 1 ~= lastindex then
+ d = d + 1 differences[d] = index
+ end
+ lastindex = index
+ d = d + 1 differences[d] = pdfconstant(name)
+ charprocs[name] = pdfreference(pdfflushstreamobject(stream))
+ widths[index-minindex+1] = width
+ end
+ else
+ report_fonts("missing glyph %i in type3 font %a",index,basefontname)
+ end
+ end
+ if not fontbbox then
+ -- The specification permits zero values and these are actually also more
+ -- robust as then there are no assumptions and no accuracy is needed.
+ fontbbox = pdfarray { 0, 0, 0, 0 }
+ end
+ local encoding = pdfdictionary {
+ Type = pdfconstant("Encoding"),
+ Differences = differences,
+ }
+ local tounicode = tounicodedictionary(details,indices,maxindex,basefontname,false)
+ local resources = getresources and getresources()
+ if not resources or not next(resources) then
+ -- resources = lpdf.procset(true)
+ resources = nil
+ end
+ local descriptor = pdfdictionary {
+ -- most is optional in type3
+ Type = pdfconstant("FontDescriptor"),
+ FontName = basefont,
+ Flags = 4,
+ ItalicAngle = 0,
+ }
+ local parent = pdfdictionary {
+ Type = pdfconstant("Font"),
+ Subtype = pdfconstant("Type3"),
+ Name = basefont,
+ FontBBox = fontbbox,
+ FontMatrix = fontmatrix,
+ CharProcs = pdfreference(pdfflushobject(charprocs)),
+ Encoding = pdfreference(pdfflushobject(encoding)),
+ FirstChar = minindex,
+ LastChar = maxindex,
+ Widths = pdfreference(pdfflushobject(widths)),
+ FontDescriptor = pdfreference(pdfflushobject(descriptor)),
+ Resources = resources,
+ ToUnicode = tounicode and pdfreference(pdfflushstreamobject(tounicode)),
+ }
+ pdfflushobject(object,parent)
+ if reset then
+ reset()
+ end
+ end
+
+ end
+
+end
+
+-- writingmode
+
+local usedfonts = fonts.hashes.identifiers -- for now
+local noffonts = 0
+
+-- The main injector.
+
+-- here we need to test for sharing otherwise we reserve too many
+-- objects
+
+local getstreamhash = fonts.handlers.otf.getstreamhash
+local loadstreamdata = fonts.handlers.otf.loadstreamdata
+
+-- we can actually now number upwards (so not use fontid in /F)
+
+local objects = setmetatableindex(function(t,k)
+ local v
+ if type(k) == "number" then
+ local h = getstreamhash(k)
+ v = rawget(t,h)
+ if not v then
+ v = pdfreserveobject()
+ t[h] = v
+ end
+ if trace_fonts then
+ report_fonts("font id %i bound to hash %s and object %i",k,h,v)
+ end
+ else
+ -- no problem as it can be svg only
+ -- report_fonts("fatal error, hash %s asked but not used",k,h,v)
+ v = pdfreserveobject()
+ t[k] = v
+ end
+ return v
+end)
+
+local n = 0
+
+local names = setmetatableindex(function(t,k)
+ local v
+ if type(k) == "number" then
+ local h = getstreamhash(k)
+ v = rawget(t,h)
+ if not v then
+ n = n + 1
+ v = n
+ t[h] = v
+ end
+ if trace_fonts then
+ report_fonts("font id %i bound to hash %s and name %i",k,h,n)
+ end
+ end
+ t[k] = v
+ return v
+end)
+
+function lpdf.flushfonts()
+
+ local mainfonts = { }
+
+ statistics.starttiming(objects)
+
+ for fontid, used in sortedhash(lpdf.usedcharacters) do
+
+ -- for a bitmap we need a different hash unless we stick to a fixed high
+ -- resolution which makes much sense
+
+ local hash = getstreamhash(fontid)
+ if hash then
+ local parent = mainfonts[hash]
+ if not parent then
+ local fontdata = usedfonts[fontid]
+ local rawdata = fontdata.shared and fontdata.shared.rawdata
+ local resources = fontdata.resources
+ local properties = fontdata.properties -- writingmode and type3
+ local parameters = fontdata.parameters -- used in type3
+ if not rawdata then
+ -- we have a virtual font that loaded directly ... at some point i will
+ -- sort this out (in readanddefine we need to do a bit more) .. the problem
+ -- is that we have a hybrid font then
+ for xfontid, xfontdata in next, fonts.hashes.identifiers do
+ if fontid ~= xfontid then
+ local xhash = getstreamhash(xfontid)
+ if hash == xhash then
+ rawdata = xfontdata.shared and xfontdata.shared.rawdata
+ if rawdata then
+ resources = xfontdata.resources
+ properties = xfontdata.properties
+ parameters = xfontdata.parameters
+ break
+ end
+ end
+ end
+ end
+ end
+ if rawdata then
+ parent = {
+ hash = hash,
+ fontdata = fontdata,
+ filename = resources.filename or properties.filename or "unset",
+ indices = { },
+ rawdata = rawdata,
+ properties = properties, -- we assume consistency
+ parameters = parameters, -- we assume consistency
+ streams = { },
+ objectnumber = objects[hash],
+ basefontname = subsetname(properties.psname or properties.name or "unset"),
+ name = names[hash],
+ }
+ mainfonts[hash] = parent
+ noffonts = noffonts + 1
+ end
+ end
+ if parent then
+ local indices = parent.indices
+ for k in next, used do
+ indices[k] = true
+ end
+ end
+ end
+ end
+
+ -- this is no not yet ok for tfm / type 1 .. we need to move the nested blobs ourside the loop
+
+ for hash, details in sortedhash(mainfonts) do
+ local filename = details.filename
+ if next(details.indices) then
+ if trace_fonts then
+ report_fonts("embedding %a hashed as %a",filename,hash)
+ end
+ local properties = details.properties
+ local bitmap = properties.usedbitmap
+ local method = properties.method -- will be pk | pdf | svg | ...
+ if bitmap or method then
+ local format = "type3"
+ local writer = mainwriters[format]
+ if writer then
+ if trace_fonts then
+ report_fonts("using main writer %a",format)
+ end
+ writer(details)
+ end
+ else
+ local format = properties.format
+ local writer = mainwriters[format]
+ if not writer then
+ -- This will move to the tpk module where we will also deal
+ -- with bitmaps then.
+ local encoding, pfbfile, encfile = getmapentry(filename)
+ if trace_fonts then
+ report_fonts("file %a resolved to encoding %a and file %a",filename,encoding,pfbfile)
+ end
+ if encoding and pfbfile then
+ filename = pfbfile
+ format = "type1"
+ --
+ -- another (temp) hack
+ local size = details.fontdata.parameters.size
+ local factor = details.fontdata.parameters.factor
+ local descriptions = { }
+ local characters = details.fontdata.characters
+ --
+ local names, _, _, metadata = fonts.constructors.handlers.pfb.loadvector(pfbfile)
+ local reverse = table.swapped(names)
+ local vector = encoding.vector
+ local indices = details.indices
+ local remapped = { }
+ local factor = bpfactor * size / 65536
+ for k, v in next, indices do
+ local name = vector[k]
+ local index = reverse[name] or 0
+ local width = factor * (characters[k].width or 0)
+ descriptions[k] = {
+ width = width,
+ index = index,
+ name = name,
+ }
+ remapped[index] = true
+ end
+ details.indices = remapped
+ --
+ details.rawdata.descriptions = descriptions
+ details.filename = filename
+ details.rawdata.metadata = { }
+ --
+ properties.filename = filename
+ properties.format = format
+ writer = mainwriters[format]
+ end
+ end
+ if not writer then
+ local pfbfile = file.replacesuffix(filename,"pfb")
+ if encoding and pfbfile then
+ filename = pfbfile
+ format = "type1"
+ --
+ -- another (temp) hack
+ local size = details.fontdata.parameters.size
+ local factor = details.fontdata.parameters.factor
+ local descriptions = { }
+ local characters = details.fontdata.characters
+ --
+ local names, _, _, metadata = fonts.constructors.handlers.pfb.loadvector(pfbfile)
+ local reverse = table.swapped(names)
+ local vector = encoding.vector
+ local indices = details.indices
+ local remapped = { }
+ local factor = bpfactor * size / 65536
+ for k, v in next, indices do
+ local name = vector[k]
+ local index = reverse[name] or 0
+ local width = factor * (characters[k].width or 0)
+ descriptions[k] = {
+ width = width,
+ index = index,
+ name = name,
+ }
+ remapped[index] = true
+ end
+ details.indices = remapped
+ --
+ details.rawdata.descriptions = descriptions
+ details.filename = filename
+ details.rawdata.metadata = { }
+ --
+ properties.filename = filename
+ properties.format = format
+ writer = mainwriters[format]
+ end
+ end
+ if writer then
+ if trace_fonts then
+ report_fonts("using main writer %a",format)
+ end
+ -- better move this test to the writers .. cleaner
+ local streams = loadstreamdata(details.fontdata)
+ if streams and streams.fontheader and streams.names then
+ details.streams = streams
+ writer(details)
+ details.streams = { }
+ elseif trace_fonts then
+ -- can be ok for e.g. emoji
+ report_fonts("no streams in %a",filename)
+ end
+ -- free some memory
+ else -- if trace_fonts then
+ report_fonts("no %a writer for %a",format,filename)
+ end
+ end
+ else -- not problem for svg ...
+ -- report_fonts("no indices for %a",filename)
+ end
+ if trace_fonts then
+ report_fonts("embedded indices: % t",table.sortedkeys(details.indices))
+ end
+ mainfonts[details.hash] = false -- done
+ end
+
+ statistics.stoptiming(objects)
+
+end
+
+statistics.register("font embedding time",function()
+ if noffonts > 0 then
+ return format("%s seconds, %s fonts", statistics.elapsedtime(objects),noffonts)
+ end
+end)
+
+-- this is temporary
+
+local done = false
+
+updaters.register("backend.update.pdf",function()
+ if not done then
+ function pdf.getfontobjnum (k) return objects[k] end
+ function pdf.getfontname (k) return names [k] end
+ function pdf.includechar () end -- maybe, when we need it
+ function pdf.includefont () end -- maybe, when we need it
+ function pdf.includecharlist () end -- maybe, when we need it
+ function pdf.setomitcidset (v) includecidset = not toboolean(v) end
+ function pdf.setomitcharset () end -- we don't need that in lmtx
+ function pdf.setsuppressoptionalinfo() end -- we don't need that in lmtx
+ function pdf.mapfile (n) loadmapfile(n) end
+ function pdf.mapline (n) loadmapline(n) end
+ -- this will change
+ lpdf.registerdocumentfinalizer(lpdf.flushfonts,1,"wrapping up fonts")
+ done = true
+ end
+end)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lpdf-eng.lua b/Master/texmf-dist/tex/context/base/mkiv/lpdf-eng.lua
new file mode 100644
index 00000000000..21c7e66e999
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/lpdf-eng.lua
@@ -0,0 +1,96 @@
+if not modules then modules = { } end modules ['lpdf-eng'] = {
+ version = 1.001,
+ comment = "companion to lpdf-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- Here we plug in the regular luatex image handler. The low level module itself
+-- is hidden from the user.
+
+local codeinjections = backends.pdf.codeinjections
+local imgnew = img.new
+
+function codeinjections.newimage(specification)
+ if type(specification) == "table" then
+ specification.kind = nil
+ end
+ return imgnew(specification)
+end
+
+codeinjections.copyimage = img.copy
+codeinjections.scanimage = img.scan
+codeinjections.embedimage = img.immediatewrite
+codeinjections.wrapimage = img.node
+
+-- We cannot nil the img table because the backend code explicitly accesses the
+-- new field when dealing with virtual characters. I should patch luatex for that
+-- and maybe I will. So no:
+--
+-- img = nil
+--
+-- We keep the low level img.new function but make the rest kind of unseen. At some
+-- point the other ones will be gone and one has to use the images.* wrappers.
+
+local unpack = unpack
+local sortedkeys = table.sortedkeys
+local context = context
+
+img = table.setmetatableindex (
+ {
+ new = images.create,
+ },
+ {
+ -- new = images.create,
+ scan = images.scan,
+ copy = images.copy,
+ node = images.wrap,
+ write = function(specification) context(images.wrap(specification)) end,
+ immediatewrite = images.embed,
+ immediatewriteobject = function() end, -- not upported, experimental anyway
+ boxes = function() return sortedkeys(images.sizes) end,
+ fields = function() return images.keys end,
+ types = function() return { unpack(images.types,0,#images.types) } end,
+ }
+)
+
+--
+
+do
+
+ local function prepare(driver)
+ if not environment.initex then
+ -- install new functions in pdf namespace
+ updaters.apply("backend.update.pdf")
+ -- install new functions in lpdf namespace
+ updaters.apply("backend.update.lpdf")
+ -- adapt existing shortcuts to lpdf namespace
+ updaters.apply("backend.update.tex")
+ -- adapt existing shortcuts to tex namespace
+ updaters.apply("backend.update")
+ --
+ end
+ end
+
+ local function outputfilename(driver)
+ if not filename then
+ filename = addsuffix(tex.jobname,"pdf")
+ end
+ return filename
+ end
+
+ drivers.install {
+ name = "pdf",
+ flushers = {
+ -- nothing here
+ },
+ actions = {
+ convert = drivers.converters.engine,
+ outputfilename = outputfilename,
+ prepare = prepare,
+ },
+ }
+
+end
+
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lpdf-epa.lua b/Master/texmf-dist/tex/context/base/mkiv/lpdf-epa.lua
index 570d738817f..45000aebc75 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lpdf-epa.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/lpdf-epa.lua
@@ -31,7 +31,6 @@ local report_field = logs.reporter("backend","field")
local report_outline = logs.reporter("backend","outline")
local lpdf = lpdf
-local epdf = epdf
local backends = backends
local context = context
@@ -73,7 +72,7 @@ local maxdimen = 0x3FFFFFFF -- 2^30-1
local bpfactor = number.dimenfactors.bp
-local layerspec = { -- predefining saves time
+local layerspec = {
"epdfcontent"
}
@@ -144,11 +143,18 @@ end
local layerused = false
+-- local function initializelayer(height,width)
+-- if not layerused then
+-- context.definelayer(layerspec, { height = height .. "bp", width = width .. "bp" })
+-- layerused = true
+-- end
+-- end
+
local function initializelayer(height,width)
- if not layerused then
- context.definelayer(layerspec, { height = height .. "bp", width = width .. "bp" })
+-- if not layerused then
+ context.setuplayer(layerspec, { height = height .. "bp", width = width .. "bp" })
layerused = true
- end
+-- end
end
function codeinjections.flushmergelayer()
@@ -295,6 +301,12 @@ function codeinjections.mergereferences(specification)
if annotation.Subtype == "Link" then
local a = annotation.A
if not a then
+ local d = annotation.Dest
+ if d then
+ annotation.A = { S = "GoTo", D = d } -- no need for a dict
+ end
+ end
+ if not a then
report_link("missing link annotation")
else
local x, y, w, h = getdimensions(annotation,llx,lly,xscale,yscale,width,height,report_link)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lpdf-epd.lua b/Master/texmf-dist/tex/context/base/mkiv/lpdf-epd.lua
deleted file mode 100644
index 86aa6f29445..00000000000
--- a/Master/texmf-dist/tex/context/base/mkiv/lpdf-epd.lua
+++ /dev/null
@@ -1,1313 +0,0 @@
-if not modules then modules = { } end modules ['lpdf-epd'] = {
- version = 1.001,
- comment = "companion to lpdf-epa.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
--- This is an experimental layer around the epdf library. The reason for this layer is that
--- I want to be independent of the library (which implements a selection of what a file
--- provides) and also because I want an interface closer to Lua's table model while the API
--- stays close to the original xpdf library. Of course, after prototyping a solution, we can
--- optimize it using the low level epdf accessors. However, not all are accessible (this will
--- be fixed).
---
--- It will be handy when we have a __length and __next that can trigger the resolve till then
--- we will provide .n as #; maybe in Lua 5.3 or later.
---
--- As there can be references to the parent we cannot expand a tree. I played with some
--- expansion variants but it does not pay off; adding extra checks is not worth the trouble.
---
--- The document stays open. In order to free memory one has to explicitly unload the loaded
--- document.
---
--- We have much more checking then needed in the prepare functions because occasionally
--- we run into bugs in poppler or the epdf interface. It took us a while to realize that
--- there was a long standing gc issue the on long runs with including many pages could
--- crash the analyzer.
---
--- Normally a value is fetched by key, as in foo.Title but as it can be in pdfdoc encoding
--- a safer bet is foo("Title") which will return a decoded string (or the original if it
--- already was unicode).
-
-local setmetatable, rawset, rawget, type, next = setmetatable, rawset, rawget, type, next
-local tostring, tonumber, unpack = tostring, tonumber, unpack
-local lower, match, char, byte, find = string.lower, string.match, string.char, string.byte, string.find
-local abs = math.abs
-local concat = table.concat
-local toutf, toeight, utfchar = string.toutf, utf.toeight, utf.char
-local setmetatableindex = table.setmetatableindex
-
-local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns
-local P, C, S, R, Ct, Cc, V, Carg, Cs, Cf, Cg = lpeg.P, lpeg.C, lpeg.S, lpeg.R, lpeg.Ct, lpeg.Cc, lpeg.V, lpeg.Carg, lpeg.Cs, lpeg.Cf, lpeg.Cg
-
-local epdf = epdf
- lpdf = lpdf or { }
-local lpdf = lpdf
-local lpdf_epdf = { }
-lpdf.epdf = lpdf_epdf
-
--- local getDict, getArray, getReal, getNum, getString, getBool, getName, getRef, getRefNum
--- local getType, getTypeName
--- local dictGetLength, dictGetVal, dictGetValNF, dictGetKey
--- local arrayGetLength, arrayGetNF, arrayGet
--- local streamReset, streamGetDict, streamGetChar
-
--- We use as little as possible and also not an object interface. After all, we
--- don't know how the library (and its api) evolves so we better can be prepared
--- for wrappers.
-
-local registry = debug.getregistry()
-
-local object = registry["epdf.Object"]
-local dictionary = registry["epdf.Dict"]
-local array = registry["epdf.Array"]
-local xref = registry["epdf.XRef"]
-local catalog = registry["epdf.Catalog"]
-local pdfdoc = registry["epdf.PDFDoc"]
-
-if not (object and dictionary and array and xref and catalog and pdfdoc) then
- logs.report("fatal error","invalid pdf inclusion library (%s)",1)
- os.exit()
-end
-
-local openPDF = epdf.open
-
-local getMajorVersion = pdfdoc.getPDFMajorVersion
-local getMinorVersion = pdfdoc.getPDFMinorVersion
-local getXRef = pdfdoc.getXRef
-local getRawCatalog = pdfdoc.getCatalog
-
-if not (openPDF and getMajorVersion and getMinorVersion and getXRef and getRawCatalog) then
- logs.report("fatal error","invalid pdf inclusion library (%s)",2)
- os.exit()
-end
-
-local getDict = object.getDict
-local getArray = object.getArray
-local getReal = object.getReal
-local getInt = object.getInt
-local getString = object.getString
-local getBool = object.getBool
-local getName = object.getName
-local getRef = object.getRef
-local getRefNum = object.getRefNum
-
-local getType = object.getType
-
-if not (getDict and getArray and getReal and getInt and getString and getBool and getName and getRef and getRefNum and getType) then
- logs.report("fatal error","invalid pdf inclusion library (%s)",3)
- os.exit()
-end
-
-local streamReset = object.streamReset
-local streamGetDict = object.streamGetDict
-local streamGetChar = object.streamGetChar
-local streamGetAll = object.streamGetAll
-
-if not (streamReset and streamGetDict and streamGetChar) then
- logs.report("fatal error","invalid pdf inclusion library (%s)",3)
- os.exit()
-end
-
-local dictGetLength = dictionary.getLength
-local dictGetVal = dictionary.getVal
-local dictGetValNF = dictionary.getValNF
-local dictGetKey = dictionary.getKey
-
-if not (dictGetLength and dictGetVal and dictGetValNF and dictGetKey) then
- logs.report("fatal error","invalid pdf inclusion library (%s)",4)
- os.exit()
-end
-
-local arrayGetLength = array.getLength
-local arrayGetNF = array.getNF
-local arrayGet = array.get
-
-if not (arrayGetLength and arrayGetNF and arrayGet) then
- logs.report("fatal error","invalid pdf inclusion library (%s)",5)
- os.exit()
-end
-
--- these are kind of weird as they can't be accessed by (root) object
-
-local getNumPages = catalog.getNumPages
-local getPageRef = catalog.getPageRef
-
-local fetch = xref.fetch
-local getCatalog = xref.getCatalog
-local getDocInfo = xref.getDocInfo
-
-if not (getNumPages and getPageRef and fetch and getCatalog and getDocInfo) then
- logs.report("fatal error","invalid pdf inclusion library (%s)",6)
- os.exit()
-end
-
--- we're done with library shortcuts
-
-local typenames = { [0] =
- "boolean",
- "integer",
- "real",
- "string",
- "name",
- "null",
- "array",
- "dictionary",
- "stream",
- "ref",
- "cmd",
- "error",
- "eof",
- "none",
- "integer64",
-}
-
-local typenumbers = table.swapped(typenames)
-
-local null_object_code = typenumbers.null
-local ref_object_code = typenumbers.ref
-
-local report_epdf = logs.reporter("epdf")
-
-local function fatal_error(...)
- report_epdf(...)
- report_epdf("aborting job in order to avoid crash")
- os.exit()
-end
-
--- epdf is the built-in library
-
-function epdf.type(o)
- local t = lower(match(tostring(o),"[^ :]+"))
- return t or "?"
-end
-
-local checked_access
-
--- dictionaries (can be optimized: ... resolve and redefine when all locals set)
-
-local frompdfdoc = lpdf.frompdfdoc
-
-local get_flagged
-
-if lpdf.dictionary then
-
- local pdfdictionary = lpdf.dictionary
- local pdfarray = lpdf.array
- local pdfconstant = lpdf.constant
- local pdfstring = lpdf.string
- local pdfunicode = lpdf.unicode
-
- get_flagged = function(t,f,k)
- local tk = t[k] -- triggers resolve
- local fk = f[k]
- if not fk then
- return tk
- elseif fk == "name" then
- return pdfconstant(tk)
- elseif fk == "array" then
- return pdfarray(tk)
- elseif fk == "dictionary" then
- return pdfarray(tk)
- elseif fk == "rawtext" then
- return pdfstring(tk)
- elseif fk == "unicode" then
- return pdfunicode(tk)
- else
- return tk
- end
- end
-
-else
-
- get_flagged = function(t,f,k)
- local tk = t[k] -- triggers resolve
- local fk = f[k]
- if not fk then
- return tk
- elseif fk == "rawtext" then
- return frompdfdoc(tk)
- else
- return tk
- end
- end
-
-end
-
-local function prepare(document,d,t,n,k,mt,flags)
- for i=1,n do
- local v = dictGetVal(d,i)
- if v then
- local r = dictGetValNF(d,i)
- local kind = getType(v)
- if kind == null_object_code then
- -- ignore
- elseif kind then
- local key = dictGetKey(d,i)
- if r and getType(r) == ref_object_code then
- local objnum = getRefNum(r)
- local cached = document.__cache__[objnum]
- if not cached then
- cached = checked_access[kind](v,document,objnum,mt)
- if cached then
- document.__cache__[objnum] = cached
- document.__xrefs__[cached] = objnum
- end
- end
- t[key] = cached
- else
- local v, flag = checked_access[kind](v,document)
- t[key] = v
- if flag and flags then
- flags[key] = flag -- flags
- end
- end
- else
- report_epdf("warning: nil value for key %a in dictionary",key)
- end
- else
- fatal_error("error: invalid value at index %a in dictionary of %a",i,document.filename)
- end
- end
- if mt then
- setmetatable(t,mt)
- else
- getmetatable(t).__index = nil
- end
- return t[k]
-end
-
--- local function prepare(document,d,t,n,k,mt,flags)
--- for i=1,n do
--- local v = dictGetValNF(d,i)
--- if v then
--- local key = dictGetKey(d,i)
--- local kind = getType(v)
--- if kind == ref_object_code then
--- local objnum = getRefNum(v)
--- local cached = document.__cache__[objnum]
--- if not cached then
--- local v = dictGetVal(d,i)
--- local kind = getType(v)
--- cached = checked_access[kind](v,document,objnum,mt)
--- if cached then
--- document.__cache__[objnum] = cached
--- document.__xrefs__[cached] = objnum
--- end
--- end
--- t[key] = cached
--- else
--- local v, flag = checked_access[kind](v,document)
--- t[key] = v
--- if flag and flags then
--- flags[key] = flag -- flags
--- end
--- end
--- end
--- end
--- if mt then
--- setmetatable(t,mt)
--- else
--- getmetatable(t).__index = nil
--- end
--- return t[k]
--- end
-
-local function some_dictionary(d,document)
- local n = d and dictGetLength(d) or 0
- if n > 0 then
- local t = { }
- local f = { }
- setmetatable(t, {
- __index = function(t,k)
- return prepare(document,d,t,n,k,_,_,f)
- end,
- __call = function(t,k)
- return get_flagged(t,f,k)
- end,
- -- __kind = function(k)
- -- return f[k] or type(t[k])
- -- end,
- } )
- return t, "dictionary"
- end
-end
-
-local function get_dictionary(object,document,r,mt)
- local d = getDict(object)
- local n = d and dictGetLength(d) or 0
- if n > 0 then
- local t = { }
- local f = { }
- setmetatable(t, {
- __index = function(t,k)
- return prepare(document,d,t,n,k,mt,f)
- end,
- __call = function(t,k)
- return get_flagged(t,f,k)
- end,
- -- __kind = function(k)
- -- return f[k] or type(t[k])
- -- end,
- } )
- return t, "dictionary"
- end
-end
-
--- arrays (can be optimized: ... resolve and redefine when all locals set)
-
-local function prepare(document,a,t,n,k)
- for i=1,n do
- local v = arrayGet(a,i)
- if v then
- local kind = getType(v)
- if kind == null_object_code then
- -- ignore
- elseif kind then
- local r = arrayGetNF(a,i)
- if r and getType(r) == ref_object_code then
- local objnum = getRefNum(r)
- local cached = document.__cache__[objnum]
- if not cached then
- cached = checked_access[kind](v,document,objnum)
- document.__cache__[objnum] = cached
- document.__xrefs__[cached] = objnum
- end
- t[i] = cached
- else
- t[i] = checked_access[kind](v,document)
- end
- else
- report_epdf("warning: nil value for index %a in array",i)
- end
- else
- fatal_error("error: invalid value at index %a in array of %a",i,document.filename)
- end
- end
- local m = getmetatable(t)
- if m then
- m.__index = nil
- m.__len = nil
- end
- if k then
- return t[k]
- end
-end
-
--- local function prepare(document,a,t,n,k)
--- for i=1,n do
--- local v = arrayGetNF(a,i)
--- if v then
--- local kind = getType(v)
--- if kind == ref_object_code then
--- local objnum = getRefNum(v)
--- local cached = document.__cache__[objnum]
--- if not cached then
--- local v = arrayGet(a,i)
--- local kind = getType(v)
--- cached = checked_access[kind](v,document,objnum)
--- document.__cache__[objnum] = cached
--- document.__xrefs__[cached] = objnum
--- end
--- t[i] = cached
--- else
--- t[i] = checked_access[kind](v,document)
--- end
--- end
--- end
--- local m = getmetatable(t)
--- if m then
--- m.__index = nil
--- m.__len = nil
--- end
--- if k then
--- return t[k]
--- end
--- end
-
-local function some_array(a,document)
- local n = a and arrayGetLength(a) or 0
- if n > 0 then
- local t = { n = n }
- setmetatable(t, {
- __index = function(t,k)
- return prepare(document,a,t,n,k,_,_,f)
- end,
- __len = function(t)
- prepare(document,a,t,n,_,_,f)
- return n
- end,
- __call = function(t,k)
- return get_flagged(t,f,k)
- end,
- -- __kind = function(k)
- -- return f[k] or type(t[k])
- -- end,
- } )
- return t, "array"
- end
-end
-
-local function get_array(object,document)
- local a = getArray(object)
- local n = a and arrayGetLength(a) or 0
- if n > 0 then
- local t = { n = n }
- local f = { }
- setmetatable(t, {
- __index = function(t,k)
- return prepare(document,a,t,n,k,_,_,f)
- end,
- __len = function(t)
- prepare(document,a,t,n,_,_,f)
- return n
- end,
- __call = function(t,k)
- return get_flagged(t,f,k)
- end,
- -- __kind = function(k)
- -- return f[k] or type(t[k])
- -- end,
- } )
- return t, "array"
- end
-end
-
--- todo: collect chunks
-
--- local function streamaccess(s,_,what)
--- if not what or what == "all" or what == "*all" then
--- local t, n = { }, 0
--- streamReset(s)
--- while true do
--- local c = streamGetChar(s)
--- if c < 0 then
--- break
--- else
--- n = n + 1
--- t[n] = char(c)
--- end
--- end
--- return concat(t,"",1,n)
--- end
--- end
-
-local function getstream(s)
- streamReset(s)
- if streamGetAll then
- return streamGetAll(s)
- else
- local t, b, n = { }, { }, 0
- while true do
- local c = streamGetChar(s)
- if c < 0 then
- break
- else
- n = n + 1
- b[n] = c
- end
- if n == 2000 then
- t[#t+1] = char(unpack(b,1,n))
- n = 1
- end
- end
- t[#t+1] = char(unpack(b,1,n))
- return concat(t)
- end
-end
-
-local function streamaccess(s,_,what)
- if not what or what == "all" or what == "*all" then
- return getstream(s)
- end
-end
-
-local function get_stream(d,document)
- if d then
- streamReset(d)
- local s = some_dictionary(streamGetDict(d),document)
- getmetatable(s).__call = function(...) return streamaccess(d,...) end
- return s
- end
-end
-
--- We need to convert the string from utf16 although there is no way to
--- check if we have a regular string starting with a bom. So, we have
--- na dilemma here: a pdf doc encoded string can be invalid utf.
-
--- <hex encoded> : implicit 0 appended if odd
--- (byte encoded) : \( \) \\ escaped
---
--- <FE><FF> : utf16be
---
--- \r \r \t \b \f \( \) \\ \NNN and \<newline> : append next line
---
--- the getString function gives back bytes so we don't need to worry about
--- the hex aspect.
-
-local u_pattern = lpeg.patterns.utfbom_16_be * lpeg.patterns.utf16_to_utf8_be
------ b_pattern = lpeg.patterns.hextobytes
-
-local function get_string(v)
- -- the toutf function only converts a utf16 string and leaves the original
- -- untouched otherwise; one might want to apply lpdf.frompdfdoc to a
- -- non-unicode string
- local s = getString(v)
- if not s or s == "" then
- return ""
- end
- local u = lpegmatch(u_pattern,s)
- if u then
- return u, "unicode"
- end
- -- this is too tricky and fails on e.g. reload of url www.pragma-ade.com)
- -- local b = lpegmatch(b_pattern,s)
- -- if b then
- -- return b, "rawtext"
- -- end
- return s, "rawtext"
-end
-
-local function get_name(v)
- return getName(v), "name"
-end
-
-local function get_null()
- return nil
-end
-
--- we have dual access: by typenumber and by typename
-
-local function invalidaccess(k,document)
- local fullname = type(document) == "table" and document.fullname
- if fullname then
- fatal_error("error, asking for key %a in checker of %a",k,fullname)
- else
- fatal_error("error, asking for key %a in checker",k)
- end
-end
-
-checked_access = setmetatableindex(function(t,k)
- return function(v,document)
- invalidaccess(k,document)
- end
-end)
-
-checked_access[typenumbers.boolean] = getBool
-checked_access[typenumbers.integer] = getInt
-checked_access[typenumbers.real] = getReal
-checked_access[typenumbers.string] = get_string -- getString
-checked_access[typenumbers.name] = get_name
-checked_access[typenumbers.null] = get_null
-checked_access[typenumbers.array] = get_array -- d,document,r
-checked_access[typenumbers.dictionary] = get_dictionary -- d,document,r
-checked_access[typenumbers.stream] = get_stream
-checked_access[typenumbers.ref] = getRef
-
-for i=0,#typenames do
- local checker = checked_access[i]
- if not checker then
- checker = function()
- return function(v,document)
- invalidaccess(i,document)
- end
- end
- checked_access[i] = checker
- end
- checked_access[typenames[i]] = checker
-end
-
-local function getnames(document,n,target) -- direct
- if n then
- local Names = n.Names
- if Names then
- if not target then
- target = { }
- end
- for i=1,Names.n,2 do
- target[Names[i]] = Names[i+1]
- end
- else
- local Kids = n.Kids
- if Kids then
- for i=1,Kids.n do
- target = getnames(document,Kids[i],target)
- end
- end
- end
- return target
- end
-end
-
-local function getkids(document,n,target) -- direct
- if n then
- local Kids = n.Kids
- if Kids then
- for i=1,Kids.n do
- target = getkids(document,Kids[i],target)
- end
- elseif target then
- target[#target+1] = n
- else
- target = { n }
- end
- return target
- end
-end
-
--- /OCProperties <<
--- /OCGs [ 15 0 R 17 0 R 19 0 R 21 0 R 23 0 R 25 0 R 27 0 R ]
--- /D <<
--- /Order [ 15 0 R 17 0 R 19 0 R 21 0 R 23 0 R 25 0 R 27 0 R ]
--- /ON [ 15 0 R 17 0 R 19 0 R 21 0 R 23 0 R 25 0 R 27 0 R ]
--- /OFF [ ]
--- >>
--- >>
-
-local function getlayers(document)
- local properties = document.Catalog.OCProperties
- if properties then
- local layers = properties.OCGs
- if layers then
- local t = { }
- local n = layers.n
- for i=1,n do
- local layer = layers[i]
- t[i] = layer.Name
- end
- t.n = n
- return t
- end
- end
-end
-
-local function getstructure(document)
- -- this might become a tree
- return document.Catalog.StructTreeRoot
-end
-
--- This is the only messy helper. We can't access the root as any object (it seems)
--- so we need a few low level acessors. It's anyway sort of simple enough to deal
--- with but it won't win a beauty contest.
-
-local function getpages(document,Catalog)
- local __data__ = document.__data__
- local __xrefs__ = document.__xrefs__
- local __cache__ = document.__cache__
- local __xref__ = document.__xref__
- --
- local rawcatalog = getRawCatalog(__data__)
- local nofpages = getNumPages(rawcatalog)
- --
- local majorversion = getMajorVersion(__data__)
- local minorversion = getMinorVersion(__data__)
- --
- local pages = { }
- local metatable = { __index = Catalog.Pages } -- somewhat empty
- --
- for pagenumber=1,nofpages do
- local pagereference = getPageRef(rawcatalog,pagenumber).num
- local pageobject = fetch(__xref__,pagereference,0)
- local pagedata = get_dictionary(pageobject,document,pagereference,metatable)
- if pagedata then
- -- rawset(pagedata,"number",pagenumber)
- pagedata.number = pagenumber
- pagedata.object = pageobject
- pages[pagenumber] = pagedata
- __xrefs__[pagedata] = pagereference
- __cache__[pagereference] = pagedata
- else
- report_epdf("missing pagedata at slot %i",i)
- end
- end
- --
- pages.n = nofpages
- --
- document.pages = pages
- document.majorversion = majorversion
- document.minorversion = minorversion
- --
- return pages
-end
-
-local function resolve(document,k)
- local entry = nil
- local Catalog = document.Catalog
- local Names = Catalog.Names
- if k == "pages" then
- entry = getpages(document,Catalog)
- elseif k == "destinations" then
- entry = getnames(document,Names and Names.Dests)
- elseif k == "javascripts" then
- entry = getnames(document,Names and Names.JS)
- elseif k == "widgets" then
- entry = getnames(document,Names and Names.AcroForm)
- elseif k == "embeddedfiles" then
- entry = getnames(document,Names and Names.EmbeddedFiles)
- elseif k == "layers" then
- entry = getlayers(document)
- elseif k == "structure" then
- entry = getstructure(document)
- end
- document[k] = entry
- return entry
-end
-
-local loaded = { }
-
-function lpdf_epdf.load(filename)
- local document = loaded[filename]
- if not document then
- statistics.starttiming(lpdf_epdf)
- local __data__ = openPDF(filename) -- maybe resolvers.find_file
- if __data__ then
- local __xref__ = getXRef(__data__)
- document = {
- filename = filename,
- __cache__ = { },
- __xrefs__ = { },
- __fonts__ = { },
- __data__ = __data__,
- __xref__ = __xref__
- }
- document.Catalog = some_dictionary(getDict(getCatalog(__xref__)),document)
- document.Info = some_dictionary(getDict(getDocInfo(__xref__)),document)
- setmetatableindex(document,resolve)
- --
- document.nofpages = getNumPages(getRawCatalog(__data__))
- else
- document = false
- end
- loaded[filename] = document
- loaded[document] = document
- statistics.stoptiming(lpdf_epdf)
- -- print(statistics.elapsedtime(lpdf_epdf))
- end
- return document or nil
-end
-
-function lpdf_epdf.unload(filename)
- local document = loaded[filename]
- if document then
- loaded[document] = nil
- loaded[filename] = nil
- end
-end
-
--- for k, v in next, expand(t) do
-
-local function expand(t)
- if type(t) == "table" then
- local dummy = t.dummy
- end
- return t
-end
-
--- for k, v in expanded(t) do
-
-local function expanded(t)
- if type(t) == "table" then
- local dummy = t.dummy
- end
- return next, t
-end
-
-lpdf_epdf.expand = expand
-lpdf_epdf.expanded = expanded
-
--- we could resolve the text stream in one pass if we directly handle the
--- font but why should we complicate things
-
-local hexdigit = R("09","AF")
-local numchar = ( P("\\") * ( (R("09")^3/tonumber) + C(1) ) ) + C(1)
-local number = lpegpatterns.number / tonumber
-local spaces = lpegpatterns.whitespace^1
-local optspaces = lpegpatterns.whitespace^0
-local keyword = P("/") * C(R("AZ","az","09")^1)
-local operator = C((R("AZ","az")+P("'")+P('"'))^1)
-
-local grammar = P { "start",
- start = (keyword + number + V("dictionary") + V("unicode") + V("string") + V("unicode")+ V("array") + spaces)^1,
- -- keyvalue = (keyword * spaces * V("start") + spaces)^1,
- keyvalue = optspaces * Cf(Ct("") * Cg(keyword * optspaces * V("start") * optspaces)^1,rawset),
- array = P("[") * Ct(V("start")^1) * P("]"),
- dictionary = P("<<") * V("keyvalue") * P(">>"),
- unicode = P("<") * Ct(Cc("hex") * C((1-P(">"))^1)) * P(">"),
- string = P("(") * Ct(Cc("dec") * C((V("string")+numchar)^1)) * P(")"), -- untested
-}
-
-local operation = Ct(grammar^1 * operator)
-local parser = Ct((operation + P(1))^1)
-
--- beginbfrange : <start> <stop> <firstcode>
--- <start> <stop> [ <firstsequence> <firstsequence> <firstsequence> ]
--- beginbfchar : <code> <newcodes>
-
-local fromsixteen = lpdf.fromsixteen -- maybe inline the lpeg ... but not worth it
-
-local function f_bfchar(t,a,b)
- t[tonumber(a,16)] = fromsixteen(b)
-end
-
-local function f_bfrange_1(t,a,b,c)
- print("todo 1",a,b,c)
- -- c is string
- -- todo t[tonumber(a,16)] = fromsixteen(b)
-end
-
-local function f_bfrange_2(t,a,b,c)
- print("todo 2",a,b,c)
- -- c is table
- -- todo t[tonumber(a,16)] = fromsixteen(b)
-end
-
-local optionals = spaces^0
-local hexstring = optionals * P("<") * C((1-P(">"))^1) * P(">")
-local bfchar = Carg(1) * hexstring * hexstring / f_bfchar
-local bfrange = Carg(1) * hexstring * hexstring * hexstring / f_bfrange_1
- + Carg(1) * hexstring * hexstring * optionals * P("[") * Ct(hexstring^1) * optionals * P("]") / f_bfrange_2
-local fromunicode = (
- P("beginbfchar" ) * bfchar ^1 * optionals * P("endbfchar" ) +
- P("beginbfrange") * bfrange^1 * optionals * P("endbfrange") +
- spaces +
- P(1)
-)^1 * Carg(1)
-
-local function analyzefonts(document,resources) -- unfinished, see mtx-pdf for better code
- local fonts = document.__fonts__
- if resources then
- local fontlist = resources.Font
- if fontlist then
- for id, data in expanded(fontlist) do
- if not fonts[id] then
- -- a quick hack ... I will look into it more detail if I find a real
- -- -application for it
- local tounicode = data.ToUnicode()
- if tounicode then
- tounicode = lpegmatch(fromunicode,tounicode,1,{})
- end
- fonts[id] = {
- tounicode = type(tounicode) == "table" and tounicode or { }
- }
- setmetatableindex(fonts[id],"self")
- end
- end
- end
- end
- return fonts
-end
-
-local more = 0
-local unic = nil -- cheaper than passing each time as Carg(1)
-
-local p_hex_to_utf = C(4) / function(s) -- needs checking !
- local now = tonumber(s,16)
- if more > 0 then
- now = (more-0xD800)*0x400 + (now-0xDC00) + 0x10000 -- the 0x10000 smells wrong
- more = 0
- return unic[now] or utfchar(now)
- elseif now >= 0xD800 and now <= 0xDBFF then
- more = now
- -- return ""
- else
- return unic[now] or utfchar(now)
- end
-end
-
-local p_dec_to_utf = C(1) / function(s) -- needs checking !
- local now = byte(s)
- return unic[now] or utfchar(now)
-end
-
-local p_hex_to_utf = P(true) / function() more = 0 end * Cs(p_hex_to_utf^1)
-local p_dec_to_utf = P(true) / function() more = 0 end * Cs(p_dec_to_utf^1)
-
-function lpdf_epdf.getpagecontent(document,pagenumber)
-
- local page = document.pages[pagenumber]
-
- if not page then
- return
- end
-
- local fonts = analyzefonts(document,page.Resources)
-
- local content = page.Contents() or ""
- local list = lpegmatch(parser,content)
- local font = nil
- -- local unic = nil
-
- for i=1,#list do
- local entry = list[i]
- local size = #entry
- local operator = entry[size]
- if operator == "Tf" then
- font = fonts[entry[1]]
- unic = font.tounicode
- elseif operator == "TJ" then -- { array, TJ }
- local list = entry[1]
- for i=1,#list do
- local li = list[i]
- if type(li) == "table" then
- if li[1] == "hex" then
- list[i] = lpegmatch(p_hex_to_utf,li[2])
- else
- list[i] = lpegmatch(p_dec_to_utf,li[2])
- end
- else
- -- kern
- end
- end
- elseif operator == "Tj" or operator == "'" or operator == '"' then -- { string, Tj } { string, ' } { n, m, string, " }
- local list = entry[size-1]
- if list[1] == "hex" then
- list[2] = lpegmatch(p_hex_to_utf,li[2])
- else
- list[2] = lpegmatch(p_dec_to_utf,li[2])
- end
- end
- end
-
- unic = nil -- can be collected
-
- return list
-
-end
-
--- This is also an experiment. When I really need it I can improve it, for instance
--- with proper position calculating. It might be usefull for some search or so.
-
-local softhyphen = utfchar(0xAD) .. "$"
-local linefactor = 1.3
-
-function lpdf_epdf.contenttotext(document,list) -- maybe signal fonts
- local last_y = 0
- local last_f = 0
- local text = { }
- local last = 0
-
- for i=1,#list do
- local entry = list[i]
- local size = #entry
- local operator = entry[size]
- if operator == "Tf" then
- last_f = entry[2]
- elseif operator == "TJ" then
- local list = entry[1]
- for i=1,#list do
- local li = list[i]
- if type(li) == "string" then
- last = last + 1
- text[last] = li
- elseif li < -50 then
- last = last + 1
- text[last] = " "
- end
- end
- line = concat(list)
- elseif operator == "Tj" then
- last = last + 1
- text[last] = entry[size-1]
- elseif operator == "cm" or operator == "Tm" then
- local ty = entry[6]
- local dy = abs(last_y - ty)
- if dy > linefactor*last_f then
- if last > 0 then
- if find(text[last],softhyphen,1,true) then
- -- ignore
- else
- last = last + 1
- text[last] = "\n"
- end
- end
- end
- last_y = ty
- end
- end
-
- return concat(text)
-end
-
-function lpdf_epdf.getstructure(document,list) -- just a test
- local depth = 0
- for i=1,#list do
- local entry = list[i]
- local size = #entry
- local operator = entry[size]
- if operator == "BDC" then
- report_epdf("%w%s : %s",depth,entry[1] or "?",entry[2].MCID or "?")
- depth = depth + 1
- elseif operator == "EMC" then
- depth = depth - 1
- elseif operator == "TJ" then
- local list = entry[1]
- for i=1,#list do
- local li = list[i]
- if type(li) == "string" then
- report_epdf("%w > %s",depth,li)
- elseif li < -50 then
- report_epdf("%w >",depth,li)
- end
- end
- elseif operator == "Tj" then
- report_epdf("%w > %s",depth,entry[size-1])
- end
- end
-end
-
--- document.Catalog.StructTreeRoot.ParentTree.Nums[2][1].A.P[1])
-
--- helpers
-
--- function lpdf_epdf.getdestinationpage(document,name)
--- local destination = document.__data__:findDest(name)
--- return destination and destination.number
--- end
-
--- This is experimental code that we need for testing the transition from
--- poppler to a new lightweight library. Don't rely on this code to remain
--- as it is now. Interesting is that performance of this variant is the same
--- as the natural page includer.
-
-if img then do
-
- local copydictionary = nil
- local copyarray = nil
-
- local ref_object_code = typenumbers.ref
- local boolean_object_code = typenumbers.boolean
- local integer_object_code = typenumbers.integer
- local real_object_code = typenumbers.real
- local string_object_code = typenumbers.string
- local name_object_code = typenumbers.name
- local null_object_code = typenumbers.null
- local array_object_code = typenumbers.array
- local dictionary_object_code = typenumbers.dictionary
- local stream_object_code = typenumbers.stream
- local cmd_object_code = typenumbers.cmd
-
- local pdfreserveobject = lpdf.reserveobject
- local pdfflushobject = lpdf.flushobject
- local pdfflushstreamobject = lpdf.flushstreamobject
- local pdfreference = lpdf.reference
- local pdfconstant = lpdf.constant
- local pdfarray = lpdf.array
- local pdfdictionary = lpdf.dictionary
- local pdfunicode = lpdf.unicode
- local pdfstring = lpdf.string
- local pdfnull = lpdf.null
-
- local report = logs.reporter("backend","xobjects")
-
- local factor = 65536 / (7200/7227) -- 1/number.dimenfactors.bp
-
- local createimage = images.create
-
- local function scaledbbox(b)
- return { b[1]*factor, b[2]*factor, b[3]*factor, b[4]*factor }
- end
-
- local function copyobject(xref,copied,kind,r,v)
- if kind == null_object_code then
- return pdfnull()
- elseif r and getType(r) == ref_object_code then
- local objnum = getRefNum(r)
- local r = copied[objnum]
- if r then
- -- report("%s object %i is reused",kind,objnum)
- else
- local o
- r = pdfreserveobject()
- copied[objnum] = r
- if kind == array_object_code then
- local a = copyarray(xref,copied,fetch(xref,objnum,0))
- pdfflushobject(r,tostring(a))
- elseif kind == dictionary_object_code then
- local d = copydictionary(xref,copied,fetch(xref,objnum,0))
- pdfflushobject(r,tostring(d))
- elseif kind == stream_object_code then
- local f = fetch(xref,objnum,0)
- local d = copydictionary(xref,copied,false,streamGetDict(f))
- local s = getstream(f)
- --
- d.Filter = nil
- d.Length = nil
- d.DecodeParms = nil
- d.DL = nil
- --
- pdfflushstreamobject(s,d,true,r)
- else
- report("reference not done: %s", kind)
- end
- end
- return pdfreference(r)
- elseif kind == array_object_code then
- return copyarray(xref,copied,v)
- elseif kind == dictionary_object_code then
- return copydictionary(xref,copied,v)
- elseif kind == integer_object_code then
- return getInt(v)
- elseif kind == real_object_code then
- return getReal(v)
- elseif kind == name_object_code then
- return pdfconstant(getName(v))
- elseif kind == string_object_code then
- local s = getString(v)
- if not s or s == "" then
- return ""
- end
- local u = lpegmatch(u_pattern,s)
- if u then
- return pdfunicode(s)
- end
- return pdfstring(s)
- elseif kind == boolean_object_code then
- return getBool(v)
- elseif kind == stream_object_code then
- -- hm ...
- return getStream(v)
- else
- report("object not done: %s", kind)
- end
- end
-
- copyarray = function (xref,copied,object)
- local a = getArray(object)
- local n = a and arrayGetLength(a) or 0
- if n > 0 then
- local target = pdfarray()
- for i=1,n do
- local v = arrayGet(a,i)
- if v then
- local kind = getType(v)
- local r = arrayGetNF(a,i)
- target[i] = copyobject(xref,copied,kind,r,v)
- end
- end
- return target
- end
- end
-
- copydictionary = function (xref,copied,object,d)
- local d = d or getDict(object)
- local n = d and dictGetLength(d) or 0
- if n > 0 then
- local target = pdfdictionary()
- for i=1,n do
- local v = dictGetVal(d,i)
- if v then
- local kind = getType(v)
- local key = dictGetKey(d,i)
- local r = dictGetValNF(d,i)
- target[key] = copyobject(xref,copied,kind,r,v)
- end
- end
- return target
- end
- end
-
- local function copy_resources(pdfdoc,xref,copied,pagedata)
- local object = pagedata.object
- if object then
- local d = getDict(object)
- local n = d and dictGetLength(d) or 0
- for i=1,n do
- local k = dictGetKey(d,i)
- if v and k == "Resources" then
- local v = dictGetVal(d,i)
- local kind = getType(v)
- local r = dictGetValNF(d,i)
- return copyobject(xref,copied,kind,r,v)
- end
- end
- end
- end
-
- local function openpdf(filename)
- local pdfdoc = lpdf_epdf.load(filename)
- if pdfdoc then
- pdfdoc.__copied__ = pdfdoc.__copied__ or { }
- pdfdoc.filename = filename
- return pdfdoc
- end
- end
-
- local function closepdf(pdfdoc)
- if pdfdoc then
- lpdf_epdf.unload(pdfdoc.filename)
- end
- end
-
- local function querypdf(pdfdoc,pagenumber)
- if pdfdoc then
- if not pagenumber then
- pagenumber = 1
- end
- local root = pdfdoc.Catalog
- local page = pdfdoc.pages[pagenumber]
- if page then
- local mediabox = page.MediaBox or { 0, 0, 0, 0 }
- local cropbox = page.CropBox or mediabox
- return {
- filename = pdfdoc.filename,
- pagenumber = pagenumber,
- nofpages = pdfdoc.nofpages,
- boundingbox = scaledbbox(cropbox),
- cropbox = cropbox,
- mediabox = mediabox,
- bleedbox = page.BleedBox or cropbox,
- trimbox = page.TrimBox or cropbox,
- artbox = page.ArtBox or cropbox,
- }
- end
- end
- end
-
- local function copypage(pdfdoc,pagenumber,attributes)
- if pdfdoc then
- local root = pdfdoc.Catalog
- local page = pdfdoc.pages[pagenumber or 1]
- local pageinfo = querypdf(pdfdoc,pagenumber)
- local contents = page.Contents
- local xref = pdfdoc.__xref__
- local copied = pdfdoc.__copied__
- --
- local xobject = pdfdictionary {
- Type = pdfconstant("XObject"),
- Subtype = pdfconstant("Form"),
- -- image attributes
- FormType = 1,
- BBox = pageinfo.cropbox,
- -- Metadata = copy(xref,copied,root,"Metadata"),
- -- Group = copy(xref,copied,page,"Group"),
- -- LastModified = copy(xref,copied,page,"LastModified"),
- -- Metadata = copy(xref,copied,page,"Metadata"),
- -- PieceInfo = copy(xref,copied,page,"PieceInfo"),
- Resources = copy_resources(pdfdoc,xref,copied,page),
- -- SeparationInfo = copy(xref,copied,page,"SeparationInfo"),
- }
- if attributes then
- for k, v in next, expand(attributes) do
- page[k] = v -- maybe nested
- end
- end
- return createimage {
- bbox = pageinfo.boundingbox,
- stream = contents(),
- attr = xobject(),
- }
- end
- end
-
- -- todo: codeinjections
-
- lpdf_epdf.image = {
- open = openpdf,
- close = closepdf,
- query = querypdf,
- copy = copypage,
- }
-
-end end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lpdf-fld.lua b/Master/texmf-dist/tex/context/base/mkiv/lpdf-fld.lua
index 983be508f2c..e5a95fdab7c 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lpdf-fld.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/lpdf-fld.lua
@@ -6,6 +6,8 @@ if not modules then modules = { } end modules ['lpdf-fld'] = {
license = "see context related readme files"
}
+-- TURN OFF: preferences -> forms -> highlight -> etc
+
-- The problem with widgets is that so far each version of acrobat has some
-- rendering problem. I tried to keep up with this but it makes no sense to do so as
-- one cannot rely on the viewer not changing. Especially Btn fields are tricky as
@@ -87,6 +89,7 @@ local pdfflushobject = lpdf.flushobject
local pdfshareobjectreference = lpdf.shareobjectreference
local pdfshareobject = lpdf.shareobject
local pdfreserveobject = lpdf.reserveobject
+local pdfpagereference = lpdf.pagereference
local pdfaction = lpdf.action
local pdfmajorversion = lpdf.majorversion
@@ -911,8 +914,11 @@ end
local collected = pdfarray()
local forceencoding = false
+-- todo : check #opt
+
local function finishfields()
local sometext = forceencoding
+ local somefont = next(usedfonts)
for name, field in sortedhash(fields) do
local kids = field.kids
if kids then
@@ -943,15 +949,33 @@ local function finishfields()
Fields = pdfreference(pdfflushobject(collected)),
CO = fieldsetlist(calculationset),
}
- if sometext then
+ if sometext or somefont then
checkpdfdocencoding()
- usedfonts.tttf = fontnames.tt.tf
- acroform.DA = "/tttf 12 Tf 0 g"
+ if sometext then
+ usedfonts.tttf = fontnames.tt.tf
+ acroform.DA = "/tttf 12 Tf 0 g"
+ end
acroform.DR = pdfdictionary {
Font = registerfonts(),
Encoding = pdfdocencodingcapsule,
}
end
+ -- maybe:
+ -- if sometext then
+ -- checkpdfdocencoding()
+ -- if sometext then
+ -- usedfonts.tttf = fontnames.tt.tf
+ -- acroform.DA = "/tttf 12 Tf 0 g"
+ -- end
+ -- acroform.DR = pdfdictionary {
+ -- Font = registerfonts(),
+ -- Encoding = pdfdocencodingcapsule,
+ -- }
+ -- elseif somefont then
+ -- acroform.DR = pdfdictionary {
+ -- Font = registerfonts(),
+ -- }
+ -- end
lpdf.addtocatalog("AcroForm",pdfreference(pdfflushobject(acroform)))
end
end
@@ -1350,6 +1374,65 @@ local function makeradioparent(field,specification)
save_parent(field,specification,d,true)
end
+-- local function makeradiochild(name,specification)
+-- local field = clones[name]
+-- local parent = nil
+-- local pname = nil
+-- if field then
+-- pname = field.parent
+-- field = radios[pname]
+-- parent = fields[pname]
+-- if not parent.pobj then
+-- if trace_fields then
+-- report_fields("forcing parent radio %a",parent.name)
+-- end
+-- makeradioparent(parent,parent)
+-- end
+-- else
+-- field = radios[name]
+-- if not field then
+-- report_fields("there is some problem with field %a",name)
+-- return nil
+-- end
+-- pname = field.parent
+-- parent = fields[pname]
+-- if not parent.pobj then
+-- if trace_fields then
+-- report_fields("using parent radio %a",name)
+-- end
+-- makeradioparent(parent,parent)
+-- end
+-- end
+-- if trace_fields then
+-- report_fields("using child radio %a with values %a and default %a",name,field.values,field.default)
+-- end
+-- local fontsymbol = specification.fontsymbol
+-- -- fontsymbol = "circle"
+-- local d = pdfdictionary {
+-- Subtype = pdf_widget,
+-- Parent = pdfreference(parent.pobj),
+-- F = fieldplus(specification),
+-- OC = fieldlayer(specification),
+-- AA = fieldactions(specification),
+-- H = pdf_n,
+-- -- H = pdf_p,
+-- -- P = pdfpagereference(true),
+-- }
+-- if fontsymbol and fontsymbol ~= "" then
+-- specification.fontsymbol = todingbat(fontsymbol)
+-- specification.fontstyle = "symbol"
+-- specification.fontalternative = "dingbats"
+-- d.DA = fieldsurrounding(specification)
+-- d.MK = fieldrendering(specification)
+-- return save_kid(parent,specification,d) -- todo: what if no value
+-- else
+-- local appearance, default, value = fieldstates_radio(field,name,fields[pname])
+-- d.AP = appearance
+-- d.AS = default -- /Whatever
+-- return save_kid(parent,specification,d,value)
+-- end
+-- end
+
local function makeradiochild(name,specification)
local field, parent = clones[name], nil
if field then
@@ -1398,6 +1481,8 @@ local function makeradiochild(name,specification)
local appearance, default, value = fieldstates_radio(field,name,fields[field.parent])
d.AP = appearance
d.AS = default -- /Whatever
+-- d.MK = pdfdictionary { BC = pdfarray {0}, BG = pdfarray { 1 } }
+d.BS = pdfdictionary { S = pdfconstant("I"), W = 1 }
return save_kid(parent,specification,d,value)
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lpdf-fmt.lua b/Master/texmf-dist/tex/context/base/mkiv/lpdf-fmt.lua
index 25a72fa49bc..388db0be3d9 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lpdf-fmt.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/lpdf-fmt.lua
@@ -81,10 +81,13 @@ local prefixes = {
cmyk = "DefaultCMYK",
}
-local formatspecification, formatname = nil, nil
+local formatspecification = nil
+local formatname = nil
-- * correspondent document wide flags (write once) needed for permission tests
+-- defaults as mt
+
local formats = utilities.storage.allocate {
version = {
external_icc_profiles = 1.4, -- 'p' in name; URL reference of output intent
@@ -95,6 +98,7 @@ local formats = utilities.storage.allocate {
optional_content = 1.5,
transparency = 1.4,
object_compression = 1.5,
+ attachments = 1.7,
},
default = {
pdf_version = 1.7, -- todo: block tex primitive
@@ -113,10 +117,11 @@ local formats = utilities.storage.allocate {
open_prepress_interface = true, -- unknown
optional_content = true, -- todo: block at lua level
transparency = true, -- todo: block at lua level
- jbig2_compression = true, -- todo: block at lua level
- jpeg2000_compression = true, -- todo: block at lua level
+ jbig2_compression = true, -- todo: block at lua level (dropped anyway)
+ jpeg2000_compression = true, -- todo: block at lua level (dropped anyway)
include_cidsets = true,
include_charsets = true,
+ attachments = true,
inject_metadata = function()
-- nothing
end
@@ -133,6 +138,7 @@ local formats = utilities.storage.allocate {
internal_icc_profiles = true,
include_cidsets = true,
include_charsets = true,
+ attachments = false,
inject_metadata = function()
addtoinfo("GTS_PDFXVersion","PDF/X-1a:2001")
injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfxid='http://www.npes.org/pdfx/ns/id/'><pdfxid:GTS_PDFXVersion>PDF/X-1a:2001</pdfxid:GTS_PDFXVersion></rdf:Description>",false)
@@ -149,6 +155,7 @@ local formats = utilities.storage.allocate {
internal_icc_profiles = true,
include_cidsets = true,
include_charsets = true,
+ attachments = false,
inject_metadata = function()
addtoinfo("GTS_PDFXVersion","PDF/X-1a:2003")
injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfxid='http://www.npes.org/pdfx/ns/id/'><pdfxid:GTS_PDFXVersion>PDF/X-1a:2003</pdfxid:GTS_PDFXVersion></rdf:Description>",false)
@@ -169,6 +176,7 @@ local formats = utilities.storage.allocate {
include_intents = true,
include_cidsets = true,
include_charsets = true,
+ attachments = false,
inject_metadata = function()
addtoinfo("GTS_PDFXVersion","PDF/X-3:2002")
end
@@ -189,6 +197,7 @@ local formats = utilities.storage.allocate {
jbig2_compression = true,
include_cidsets = true,
include_charsets = true,
+ attachments = false,
inject_metadata = function()
addtoinfo("GTS_PDFXVersion","PDF/X-3:2003")
end
@@ -213,6 +222,7 @@ local formats = utilities.storage.allocate {
object_compression = true,
include_cidsets = true,
include_charsets = true,
+ attachments = false,
inject_metadata = function()
injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfxid='http://www.npes.org/pdfx/ns/id/'><pdfxid:GTS_PDFXVersion>PDF/X-4</pdfxid:GTS_PDFXVersion></rdf:Description>",false)
insertxmpinfo("xml://rdf:Description/xmpMM:InstanceID","<xmpMM:VersionID>1</xmpMM:VersionID>",false)
@@ -240,6 +250,7 @@ local formats = utilities.storage.allocate {
object_compression = true,
include_cidsets = true,
include_charsets = true,
+ attachments = false,
inject_metadata = function()
injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfxid='http://www.npes.org/pdfx/ns/id/'><pdfxid:GTS_PDFXVersion>PDF/X-4p</pdfxid:GTS_PDFXVersion></rdf:Description>",false)
insertxmpinfo("xml://rdf:Description/xmpMM:InstanceID","<xmpMM:VersionID>1</xmpMM:VersionID>",false)
@@ -267,6 +278,7 @@ local formats = utilities.storage.allocate {
object_compression = true,
include_cidsets = true,
include_charsets = true,
+ attachments = false,
inject_metadata = function()
-- todo
end
@@ -293,6 +305,7 @@ local formats = utilities.storage.allocate {
object_compression = true,
include_cidsets = true,
include_charsets = true,
+ attachments = false,
inject_metadata = function()
-- todo
end
@@ -318,6 +331,7 @@ local formats = utilities.storage.allocate {
object_compression = true,
include_cidsets = true,
include_charsets = true,
+ attachments = false,
inject_metadata = function()
-- todo
end
@@ -334,11 +348,12 @@ local formats = utilities.storage.allocate {
calibrated_rgb_colors = true, -- unknown
cielab_colors = true, -- unknown
include_intents = true,
- forms = true, -- NEW; forms are allowed (with limitations); no JS, other restrictions are unknown (TODO)
- tagging = true, -- NEW; the only difference to PDF/A-1b
+ forms = true, -- new: forms are allowed (with limitations); no JS, other restrictions are unknown (TODO)
+ tagging = true, -- new: the only difference to PDF/A-1b
internal_icc_profiles = true,
include_cidsets = true,
include_charsets = true,
+ attachments = false,
inject_metadata = function()
injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfaid='http://www.aiim.org/pdfa/ns/id/'><pdfaid:part>1</pdfaid:part><pdfaid:conformance>A</pdfaid:conformance></rdf:Description>",false)
end
@@ -359,11 +374,14 @@ local formats = utilities.storage.allocate {
internal_icc_profiles = true,
include_cidsets = true,
include_charsets = true,
+ attachments = false,
inject_metadata = function()
injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfaid='http://www.aiim.org/pdfa/ns/id/'><pdfaid:part>1</pdfaid:part><pdfaid:conformance>B</pdfaid:conformance></rdf:Description>",false)
end
},
- ["pdf/a-2a"] = { -- untested; only PDF/A Attachments are allowed
+ -- Only PDF/A Attachments are allowed but we don't check the attachments
+ -- for any quality: they are just blobs.
+ ["pdf/a-2a"] = {
pdf_version = 1.7,
format_name = "pdf/a-2a",
xmp_file = "lpdf-pda.xml",
@@ -378,17 +396,74 @@ local formats = utilities.storage.allocate {
forms = true,
tagging = true,
internal_icc_profiles = true,
- transparency = true, -- NEW
+ transparency = true, -- new
jbig2_compression = true,
- jpeg2000_compression = true, -- NEW
- object_compression = true,
+ jpeg2000_compression = true, -- new
+ object_compression = true, -- new
include_cidsets = false,
include_charsets = false,
+ attachments = true, -- new
inject_metadata = function()
injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfaid='http://www.aiim.org/pdfa/ns/id/'><pdfaid:part>2</pdfaid:part><pdfaid:conformance>A</pdfaid:conformance></rdf:Description>",false)
end
},
- ["pdf/a-3a"] = { -- untested; NEW: any type of attachment is allowed
+ ["pdf/a-2b"] = {
+ pdf_version = 1.7,
+ format_name = "pdf/a-2b",
+ xmp_file = "lpdf-pda.xml",
+ gts_flag = "GTS_PDFA1",
+ gray_scale = true,
+ cmyk_colors = true,
+ rgb_colors = true,
+ spot_colors = true,
+ calibrated_rgb_colors = true, -- unknown
+ cielab_colors = true, -- unknown
+ include_intents = true,
+ forms = true,
+ tagging = false,
+ internal_icc_profiles = true,
+ transparency = true,
+ jbig2_compression = true,
+ jpeg2000_compression = true,
+ object_compression = true,
+ include_cidsets = false,
+ include_charsets = false,
+ attachments = true,
+ inject_metadata = function()
+ injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfaid='http://www.aiim.org/pdfa/ns/id/'><pdfaid:part>2</pdfaid:part><pdfaid:conformance>B</pdfaid:conformance></rdf:Description>",false)
+ end
+ },
+ -- This is like the b variant, but it requires Unicode mapping of fonts
+ -- which we do anyway.
+ ["pdf/a-2u"] = {
+ pdf_version = 1.7,
+ format_name = "pdf/a-2u",
+ xmp_file = "lpdf-pda.xml",
+ gts_flag = "GTS_PDFA1",
+ gray_scale = true,
+ cmyk_colors = true,
+ rgb_colors = true,
+ spot_colors = true,
+ calibrated_rgb_colors = true, -- unknown
+ cielab_colors = true, -- unknown
+ include_intents = true,
+ forms = true,
+ tagging = false,
+ internal_icc_profiles = true,
+ transparency = true,
+ jbig2_compression = true,
+ jpeg2000_compression = true,
+ object_compression = true,
+ include_cidsets = false,
+ include_charsets = false,
+ attachments = true,
+ inject_metadata = function()
+ injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfaid='http://www.aiim.org/pdfa/ns/id/'><pdfaid:part>2</pdfaid:part><pdfaid:conformance>U</pdfaid:conformance></rdf:Description>",false)
+ end
+ },
+ -- Any type of attachment is allowed but we don't check the quality
+ -- of them.
+ ["pdf/a-3a"] = {
pdf_version = 1.7,
format_name = "pdf/a-3a",
xmp_file = "lpdf-pda.xml",
@@ -409,10 +484,63 @@ local formats = utilities.storage.allocate {
object_compression = true,
include_cidsets = false,
include_charsets = false,
+ attachments = true,
inject_metadata = function()
injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfaid='http://www.aiim.org/pdfa/ns/id/'><pdfaid:part>3</pdfaid:part><pdfaid:conformance>A</pdfaid:conformance></rdf:Description>",false)
end
},
+ ["pdf/a-3b"] = {
+ pdf_version = 1.7,
+ format_name = "pdf/a-3b",
+ xmp_file = "lpdf-pda.xml",
+ gts_flag = "GTS_PDFA1",
+ gray_scale = true,
+ cmyk_colors = true,
+ rgb_colors = true,
+ spot_colors = true,
+ calibrated_rgb_colors = true, -- unknown
+ cielab_colors = true, -- unknown
+ include_intents = true,
+ forms = true,
+ tagging = false,
+ internal_icc_profiles = true,
+ transparency = true,
+ jbig2_compression = true,
+ jpeg2000_compression = true,
+ object_compression = true,
+ include_cidsets = false,
+ include_charsets = false,
+ attachments = true,
+ inject_metadata = function()
+ injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfaid='http://www.aiim.org/pdfa/ns/id/'><pdfaid:part>3</pdfaid:part><pdfaid:conformance>B</pdfaid:conformance></rdf:Description>",false)
+ end
+ },
+ ["pdf/a-3u"] = {
+ pdf_version = 1.7,
+ format_name = "pdf/a-3u",
+ xmp_file = "lpdf-pda.xml",
+ gts_flag = "GTS_PDFA1",
+ gray_scale = true,
+ cmyk_colors = true,
+ rgb_colors = true,
+ spot_colors = true,
+ calibrated_rgb_colors = true, -- unknown
+ cielab_colors = true, -- unknown
+ include_intents = true,
+ forms = true,
+ tagging = false,
+ internal_icc_profiles = true,
+ transparency = true,
+ jbig2_compression = true,
+ jpeg2000_compression = true,
+ object_compression = true,
+ include_cidsets = false,
+ include_charsets = false,
+ attachments = true,
+ inject_metadata = function()
+ injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfaid='http://www.aiim.org/pdfa/ns/id/'><pdfaid:part>3</pdfaid:part><pdfaid:conformance>U</pdfaid:conformance></rdf:Description>",false)
+ end
+ },
["pdf/ua-1"] = { -- based on PDF/A-3a, but no 'gts_flag'
pdf_version = 1.7,
format_name = "pdf/ua-1",
@@ -433,6 +561,7 @@ local formats = utilities.storage.allocate {
object_compression = true,
include_cidsets = true,
include_charsets = true, --- really ?
+ attachments = true,
inject_metadata = function()
injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfaid='http://www.aiim.org/pdfa/ns/id/'><pdfaid:part>3</pdfaid:part><pdfaid:conformance>A</pdfaid:conformance></rdf:Description>",false)
injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfuaid='http://www.aiim.org/pdfua/ns/id/'><pdfuaid:part>1</pdfuaid:part></rdf:Description>",false)
@@ -626,10 +755,16 @@ local function handledefaultprofile(s,spec) -- specification
end
end
-local loadedintents, intents = { }, pdfarray()
+local loadedintents = { }
+local intents = pdfarray()
local function handleoutputintent(s,spec)
- local name, url, filename, id, outputcondition, info = s.info or s.filename or "", s.url or "", s.filename or "", s.id or "", s.outputcondition or "", s.info or ""
+ local url = s.url or ""
+ local filename = s.filename or ""
+ local name = s.info or filename
+ local id = s.id or ""
+ local outputcondition = s.outputcondition or ""
+ local info = s.info or ""
if name == "" or id == "" then
report_backend("error in output intent specification: %s",serialize(s,false))
elseif not loadedintents[name] then
@@ -771,8 +906,13 @@ function codeinjections.setformat(s)
-- cid sets can always omitted now, but those validators still complain so let's
-- for a while keep it (for luigi):
--
- lpdf.setomitcidset (formatspecification.include_cidsets == false and 1 or 0)
- lpdf.setomitcharset(formatspecification.include_charsets == false and 1 or 0)
+ lpdf.setomitcidset (formatspecification.include_cidsets == false and 1 or 0) -- why a number
+ lpdf.setomitcharset(formatspecification.include_charsets == false and 1 or 0) -- why a number
+ --
+ -- maybe block by pdf version
+ --
+ codeinjections.settaggingsupport(formatspecification.tagging)
+ codeinjections.setattachmentsupport(formatspecification.attachments)
--
-- context.setupcolors { -- not this way
-- cmyk = spec.cmyk_colors and variables.yes or variables.no,
@@ -847,6 +987,10 @@ function codeinjections.getformatoption(key)
return formatspecification and formatspecification[key]
end
+-- function codeinjections.getformatspecification()
+-- return formatspecification
+-- end
+
function codeinjections.supportedformats()
local t = { }
for k, v in sortedhash(formats.data) do
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lpdf-fnt.lua b/Master/texmf-dist/tex/context/base/mkiv/lpdf-fnt.lua
index 1caa2f93c98..6729578a269 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lpdf-fnt.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/lpdf-fnt.lua
@@ -9,7 +9,7 @@ if not modules then modules = { } end modules ['lpdf-fnt'] = {
-- This is experimental code.
local match, gmatch = string.match, string.gmatch
-local tonumber = tonumber
+local tonumber, rawget = tonumber, rawget
local pdfreserveobject = lpdf.reserveobject
local pdfincludechar = lpdf.includechar
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lpdf-grp.lua b/Master/texmf-dist/tex/context/base/mkiv/lpdf-grp.lua
index 49cc7687111..e827419a6ce 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lpdf-grp.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/lpdf-grp.lua
@@ -262,14 +262,9 @@ end
-- experimental (q Q is not really needed)
-local f_pattern = formatters["q /Pattern cs /%s scn 0 0 %.6F %.6F re f Q"]
-
-directives.register("pdf.stripzeros",function()
- f_pattern = formatters["q /Pattern cs /%s scn 0 0 %.6N %.6N re f Q"]
-end)
-
-local saveboxresource = tex.boxresources.save
-local nofpatterns = 0
+local saveboxresource = tex.boxresources.save
+local nofpatterns = 0
+local f_pattern = formatters["q /Pattern cs /%s scn 0 0 %.6N %.6N re f Q"]
function lpdf.registerpattern(specification)
nofpatterns = nofpatterns + 1
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lpdf-img.lua b/Master/texmf-dist/tex/context/base/mkiv/lpdf-img.lua
new file mode 100644
index 00000000000..17305a1cfa6
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/lpdf-img.lua
@@ -0,0 +1,1340 @@
+if not modules then modules = { } end modules ['lpdf-img'] = {
+ version = 1.001,
+ comment = "companion to lpdf-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- This started as an experiment but has potential for some (cached) optimizations.
+-- At some point we can also use it for fonts. For small images performance is ok
+-- with pure lua but for bigger images we can use some helpers. Normally in a
+-- typesetting workflow non-interlaced images are used. One should convert
+-- interlaced images to more efficient non-interlaced ones (ok, we can cache
+-- them if needed).
+--
+-- The \LUA\ code is slightly optimized so we could have done with less lines if
+-- we wanted but best gain a little. The idea is that we collect striped (in stages)
+-- so that we can play with substitutions.
+
+local type = type
+local concat, move = table.concat, table.move
+local ceil, min = math.ceil, math.min
+local char, byte, find, gmatch = string.char, string.byte, string.find, string.gmatch
+local idiv = number.idiv
+local band, rshift = bit32.band, bit32.rshift
+
+local loaddata = io.loaddata
+local setmetatableindex = table.setmetatableindex
+local formatters = string.formatters
+
+local streams = utilities.streams
+local openstring = streams.openstring
+local readstring = streams.readstring
+local readbytetable = streams.readbytetable
+
+local newreader = io.newreader
+
+local tobytetable = string.bytetable
+
+local lpdf = lpdf or { }
+local pdfdictionary = lpdf.dictionary
+local pdfarray = lpdf.array
+local pdfconstant = lpdf.constant
+local pdfstring = lpdf.string
+local pdfflushstreamobject = lpdf.flushstreamobject
+local pdfreference = lpdf.reference
+local pdfverbose = lpdf.verbose
+
+local pdfmajorversion = lpdf.majorversion
+local pdfminorversion = lpdf.minorversion
+
+local createimage = images.create
+
+local zlibcompress = (xzip or zlib).compress
+local zlibdecompress = (xzip or zlib).decompress
+
+local trace = false
+
+local report_jpg = logs.reporter("graphics","jpg")
+local report_jp2 = logs.reporter("graphics","jp2")
+local report_png = logs.reporter("graphics","png")
+
+trackers.register("graphics.backend", function(v) trace = v end)
+
+local injectors = { }
+lpdf.injectors = injectors
+
+-- todo: load from a virtual file
+
+local function loadcontent(filename,method)
+ return method == "string" and filename or loaddata(filename)
+end
+
+local function newcontent(filename,method)
+ return newreader(filename,method)
+end
+
+--
+
+local chars = setmetatableindex(function(t,k) -- share this one
+ local v = (k <= 0 and "\000") or (k >= 255 and "\255") or char(k)
+ t[k] = v
+ return v
+end)
+
+do
+
+ function injectors.jpg(specification,method)
+ if specification.error then
+ return
+ end
+ local filename = specification.filename
+ if not filename then
+ return
+ end
+ local colorspace = specification.colorspace or jpg_gray
+ local decodearray = nil
+ ----- procset = colorspace == 0 and "image b" or "image c"
+ if colorspace == 1 then
+ colorspace = "DeviceGray"
+ elseif colorspace == 2 then
+ colorspace = "DeviceRGB"
+ elseif colorspace == 3 then
+ colorspace = "DeviceCMYK"
+ decodearray = pdfarray { 1, 0, 1, 0, 1, 0, 1, 0 }
+ end
+ -- todo: set filename
+ local xsize = specification.xsize
+ local ysize = specification.ysize
+ local colordepth = specification.colordepth
+ local content = loadcontent(filename,method)
+ local xobject = pdfdictionary {
+ Type = pdfconstant("XObject"),
+ Subtype = pdfconstant("Image"),
+ -- BBox = pdfarray { 0, 0, xsize, ysize },
+ Width = xsize,
+ Height = ysize,
+ BitsPerComponent = colordepth,
+ Filter = pdfconstant("DCTDecode"),
+ ColorSpace = pdfconstant(colorspace),
+ Decode = decodearray,
+ Length = #content, -- specification.length
+ } + specification.attr
+ if trace then
+ report_jpg("%s: width %i, height %i, colordepth %i, size %i",filename,xsize,ysize,colordepth,#content)
+ end
+ return createimage {
+ bbox = { 0, 0, specification.width/xsize, specification.height/ysize }, -- mandate
+ transform = specification.transform,
+ nolength = true,
+ nobbox = true,
+ notype = true,
+ stream = content,
+ attr = xobject(),
+ }
+ end
+
+end
+
+do
+
+ function injectors.jp2(specification,method)
+ if specification.error then
+ return
+ end
+ local filename = specification.filename
+ if not filename then
+ return
+ end
+ -- todo: set filename
+ local xsize = specification.xsize
+ local ysize = specification.ysize
+ local content = loadcontent(filename,method)
+ local xobject = pdfdictionary {
+ Type = pdfconstant("XObject"),
+ Subtype = pdfconstant("Image"),
+ BBox = pdfarray { 0, 0, xsize, ysize },
+ Width = xsize,
+ Height = ysize,
+ Filter = pdfconstant("JPXDecode"),
+ Length = #content, -- specification.length
+ } + specification.attr
+ if trace then
+ report_jp2("%s: width %i, height %i, size %i",filename,xsize,ysize,#content)
+ end
+ return createimage {
+ bbox = { 0, 0, specification.width/xsize, specification.height/ysize }, -- mandate
+ transform = specification.transform,
+ nolength = true,
+ nobbox = true,
+ notype = true,
+ stream = content,
+ attr = xobject(),
+ }
+ end
+
+end
+
+do
+
+ -- We don't like interlaced files. You can deinterlace them beforehand because otherwise
+ -- each run you add runtime. Actually, even masked images can best be converted to PDF
+ -- beforehand.
+
+ -- The amount of code is larger that I like and looks somewhat redundant but we sort of
+ -- optimize a few combinations that happen often.
+
+ local pngapplyfilter = pngdecode.applyfilter
+ local pngsplitmask = pngdecode.splitmask
+ local pnginterlace = pngdecode.interlace
+ local pngexpand = pngdecode.expand
+ local pngtocmyk = pngdecode.tocmyk
+
+ local filtermask, decodemask, decodestrip, transpose, expand, tocmyk
+
+ local newindex = lua.newindex
+ local newtable = lua.newtable
+
+ local function newoutput(size)
+ if newindex then
+ return newindex(size,0)
+ end
+ local t = newtable and newtable(size,0) or { }
+ for i=1,size do
+ t[i] = 0
+ end
+ return t
+ end
+
+ local function convert(t)
+ if type(t) == "table" then
+ for i=1,#t do
+ local ti = t[i]
+ if ti ~= "" then -- soon gone
+ t[i] = chars[ti]
+ end
+ end
+ return concat(t)
+ else
+ return t
+ end
+ end
+
+ local function zero(t,k)
+ return 0
+ end
+
+ local function applyfilter(t,xsize,ysize,bpp)
+ local len = xsize * bpp + 1
+ local n = 1
+ local m = len - 1
+ for i=1,ysize do
+ local filter = t[n]
+ t[n] = ""
+ if filter == 0 then
+ elseif filter == 1 then
+ for j=n+bpp+1,n+m do
+ t[j] = (t[j] + t[j-bpp]) % 256
+ end
+ elseif filter == 2 then
+ for j=n+1,n+m do
+ t[j] = (t[j] + t[j-len]) % 256
+ end
+ elseif filter == 3 then
+ for j=n+1,n+bpp do
+ t[j] = (t[j] + idiv(t[j-len],2)) % 256
+ end
+ for j=n+bpp+1,n+m do
+ t[j] = (t[j] + idiv(t[j-bpp] + t[j-len],2)) % 256
+ end
+ elseif filter == 4 then
+ for j=n+1,n+bpp do
+ local p = j - len
+ local b = t[p]
+ if b > 0 then
+ t[j] = (t[j] + b) % 256
+ end
+ end
+ for j=n+bpp+1,n+m do
+ local p = j - len
+ local a = t[j-bpp]
+ local b = t[p]
+ local c = t[p-bpp]
+ local pa = b - c
+ local pb = a - c
+ local pc = pa + pb
+ if pa < 0 then pa = - pa end
+ if pb < 0 then pb = - pb end
+ if pc < 0 then pc = - pc end
+ t[j] = (t[j] + ((pa <= pb and pa <= pc and a) or (pb <= pc and b) or c)) % 256
+ end
+ end
+ n = n + len
+ end
+ return t
+ end
+
+ local filtermask_l = function (content,xsize,ysize,colordepth,colorspace,hasfilter)
+ local mask = { }
+ local bytes = colordepth == 16 and 2 or 1
+ local bpp = colorspace == "DeviceRGB" and 3 or 1
+ local length = #content
+ local size = ysize * xsize * ((bpp+1)*bytes + (hasfilter and 1 or 0))
+ local n = 1
+ local l = 1
+ if bytes == 2 then
+ if bpp == 1 then
+ for i=1,ysize do
+ if hasfilter then
+ content[n] = "" ; n = n + 1
+ end
+ for j=1,xsize do
+ content[n] = chars[content[n]] ; n = n + 1
+ content[n] = chars[content[n]] ; n = n + 1
+ mask[l] = chars[content[n]] ; l = l + 1
+ content[n] = "" ; n = n + 1
+ mask[l] = chars[content[n]] ; l = l + 1
+ content[n] = "" ; n = n + 1
+ end
+ end
+ elseif bpp == 3 then
+ for i=1,ysize do
+ if hasfilter then
+ content[n] = "" ; n = n + 1
+ end
+ for j=1,xsize do
+ content[n] = chars[content[n]] ; n = n + 1
+ content[n] = chars[content[n]] ; n = n + 1
+ content[n] = chars[content[n]] ; n = n + 1
+ content[n] = chars[content[n]] ; n = n + 1
+ content[n] = chars[content[n]] ; n = n + 1
+ content[n] = chars[content[n]] ; n = n + 1
+ mask[l] = chars[content[n]] ; l = l + 1
+ content[n] = "" ; n = n + 1
+ mask[l] = chars[content[n]] ; l = l + 1
+ content[n] = "" ; n = n + 1
+ end
+ end
+ else
+ return "", ""
+ end
+ else
+ if bpp == 1 then
+ for i=1,ysize do
+ if hasfilter then
+ content[n] = "" ; n = n + 1
+ end
+ for j=1,xsize do
+ content[n] = chars[content[n]] ; n = n + 1
+ mask[l] = chars[content[n]] ; l = l + 1
+ content[n] = "" ; n = n + 1
+ end
+ end
+ elseif bpp == 3 then
+ for i=1,ysize do
+ if hasfilter then
+ content[n] = "" ; n = n + 1
+ end
+ for j=1,xsize do
+ content[n] = chars[content[n]] ; n = n + 1
+ content[n] = chars[content[n]] ; n = n + 1
+ content[n] = chars[content[n]] ; n = n + 1
+ mask[l] = chars[content[n]] ; l = l + 1
+ content[n] = "" ; n = n + 1
+ end
+ end
+ else
+ return "", ""
+ end
+ end
+ return concat(content), concat(mask)
+ end
+
+ local decodemask_l = function(content,xsize,ysize,colordepth,colorspace)
+ local bytes = colordepth == 16 and 2 or 1
+ local bpp = colorspace == "DeviceRGB" and 3 or 1
+ local slice = bytes*(bpp+1)
+ local length = #content
+ local size = ysize * xsize * ((bpp+1)*bytes + 1) -- assume filter
+ content = openstring(content)
+ content = readbytetable(content,length)
+ setmetatableindex(content,zero)
+ applyfilter(content,xsize,ysize,slice)
+ content, mask = filtermask(content,xsize,ysize,colordepth,colorspace,true)
+ return content, mask
+ end
+
+ local filtermask_c = function(content,xsize,ysize,colordepth,colorspace)
+ local bytes = colordepth == 16 and 2 or 1
+ local bpp = colorspace == "DeviceRGB" and 3 or 1
+ return pngsplitmask(content,xsize,ysize,bpp,bytes)
+ end
+
+ local decodemask_c = function(content,xsize,ysize,colordepth,colorspace)
+ local mask = true
+ local filter = false
+ local bytes = colordepth == 16 and 2 or 1
+ local bpp = colorspace == "DeviceRGB" and 3 or 1
+ local slice = bytes * (bpp + 1) -- always a mask
+ content = pngapplyfilter(content,xsize,ysize,slice)
+ return pngsplitmask(content,xsize,ysize,bpp,bytes,mask,filter)
+ end
+
+ local function decodestrip_l(s,nx,ny,slice)
+ local input = readbytetable(s,ny*(nx*slice+1))
+ setmetatableindex(input,zero)
+ applyfilter(input,nx,ny,slice)
+ return input, true
+ end
+
+ local function decodestrip_c(s,nx,ny,slice)
+ local input = readstring(s,ny*(nx*slice+1))
+ input = pngapplyfilter(input,nx,ny,slice)
+ return input, false
+ end
+
+ local xstart = { 0, 4, 0, 2, 0, 1, 0 }
+ local ystart = { 0, 0, 4, 0, 2, 0, 1 }
+ local xstep = { 8, 8, 4, 4, 2, 2, 1 }
+ local ystep = { 8, 8, 8, 4, 4, 2, 2 }
+
+ local xblock = { 8, 4, 4, 2, 2, 1, 1 }
+ local yblock = { 8, 8, 4, 4, 2, 2, 1 }
+
+ local function transpose_l(xsize,ysize,slice,pass,input,output,filter)
+ local xstart = xstart[pass]
+ local xstep = xstep[pass]
+ local ystart = ystart[pass]
+ local ystep = ystep[pass]
+ local nx = idiv(xsize + xstep - xstart - 1,xstep)
+ local ny = idiv(ysize + ystep - ystart - 1,ystep)
+ local offset = filter and 1 or 0
+ local xstep = xstep * slice
+ local xstart = xstart * slice
+ local xsize = xsize * slice
+ local target = ystart * xsize + xstart + 1
+ local ystep = ystep * xsize
+ local start = 1
+ local plus = nx * xstep
+ local step = plus - xstep
+ if not output then
+ output = newoutput(xsize*(parts or slice)*ysize)
+ end
+ if slice == 1 then
+ for j=0,ny-1 do
+ start = start + offset
+ local target = target + j * ystep
+ for target=target,target+step,xstep do
+ output[target] = input[start]
+ start = start + slice
+ end
+ end
+ elseif slice == 2 then
+ for j=0,ny-1 do
+ start = start + offset
+ local target = target + j * ystep
+ for target=target,target+step,xstep do
+ output[target] = input[start]
+ output[target+1] = input[start+1]
+ start = start + slice
+ end
+ end
+ elseif slice == 3 then
+ for j=0,ny-1 do
+ start = start + offset
+ local target = target + j * ystep
+ for target=target,target+step,xstep do
+ output[target] = input[start]
+ output[target+1] = input[start+1]
+ output[target+2] = input[start+2]
+ start = start + slice
+ end
+ end
+ elseif slice == 4 then
+ for j=0,ny-1 do
+ start = start + offset
+ local target = target + j * ystep
+ for target=target,target+step,xstep do
+ output[target] = input[start]
+ output[target+1] = input[start+1]
+ output[target+2] = input[start+2]
+ output[target+3] = input[start+3]
+ start = start + slice
+ end
+ end
+ else
+ local delta = slice - 1
+ for j=0,ny-1 do
+ start = start + offset
+ local target = target + j * ystep
+ for target=target,target+step,xstep do
+ move(input,start,start+delta,target,output)
+ start = start + slice
+ end
+ end
+ end
+ return output;
+ end
+
+ local transpose_c = pnginterlace
+
+ -- print(band(rshift(v,4),0x03),extract(v,4,2))
+ -- print(band(rshift(v,6),0x03),extract(v,6,2))
+
+ local function expand_l(t,xsize,ysize,parts,run,factor,filter)
+ local size = ysize * xsize + 1 -- a bit of overshoot, needs testing, probably a few bytes us ok
+ local xline = filter and (run+1) or run
+ local f = filter and 1 or 0
+ local l = xline - 1
+ local n = 1
+ local o = newoutput(size)
+ local k = 0
+ if factor then
+ if parts == 4 then
+ for i=1,ysize do
+ for j=n+f,n+l do
+ local v = t[j]
+ if v == 0 then
+ k = k + 2
+ else
+ k = k + 1 ; o[k] = extract4(v,4) * 0x11
+ k = k + 1 ; o[k] = extract4(v,0) * 0x11
+ end
+ end
+ k = i * xsize
+ n = n + xline
+ end
+ elseif parts == 2 then
+ for i=1,ysize do
+ for j=n+f,n+l do
+ local v = t[j]
+ if v == 0 then
+ k = k + 4
+ else
+ k = k + 1 ; o[k] = extract2(v,6) * 0x55
+ k = k + 1 ; o[k] = extract2(v,4) * 0x55
+ k = k + 1 ; o[k] = extract2(v,2) * 0x55
+ k = k + 1 ; o[k] = extract2(v,0) * 0x55
+ end
+ end
+ k = i * xsize
+ n = n + xline
+ end
+ else
+ for i=1,ysize do
+ for j=n+f,n+l do
+ local v = t[j]
+ if v == 0 then
+ k = k + 8
+ else
+ k = k + 1 ; if band(v,0x80) ~= 0 then o[k] = 0xFF end -- o[k] = extract1(v,7) * 0xFF
+ k = k + 1 ; if band(v,0x40) ~= 0 then o[k] = 0xFF end -- o[k] = extract1(v,6) * 0xFF
+ k = k + 1 ; if band(v,0x20) ~= 0 then o[k] = 0xFF end -- o[k] = extract1(v,5) * 0xFF
+ k = k + 1 ; if band(v,0x10) ~= 0 then o[k] = 0xFF end -- o[k] = extract1(v,4) * 0xFF
+ k = k + 1 ; if band(v,0x08) ~= 0 then o[k] = 0xFF end -- o[k] = extract1(v,3) * 0xFF
+ k = k + 1 ; if band(v,0x04) ~= 0 then o[k] = 0xFF end -- o[k] = extract1(v,2) * 0xFF
+ k = k + 1 ; if band(v,0x02) ~= 0 then o[k] = 0xFF end -- o[k] = extract1(v,1) * 0xFF
+ k = k + 1 ; if band(v,0x01) ~= 0 then o[k] = 0xFF end -- o[k] = extract1(v,0) * 0xFF
+ end
+ end
+ k = i * xsize
+ n = n + xline
+ end
+ end
+ else
+ if parts == 4 then
+ for i=1,ysize do
+ for j=n+f,n+l do
+ local v = t[j]
+ if v == 0 then
+ k = k + 2
+ else
+ k = k + 1 ; o[k] = extract4(v,4)
+ k = k + 1 ; o[k] = extract4(v,0)
+ end
+ end
+ k = i * xsize
+ n = n + xline
+ end
+ elseif parts == 2 then
+ for i=1,ysize do
+ for j=n+f,n+l do
+ local v = t[j]
+ if v == 0 then
+ k = k + 4
+ else
+ k = k + 1 ; o[k] = extract2(v,6)
+ k = k + 1 ; o[k] = extract2(v,4)
+ k = k + 1 ; o[k] = extract2(v,2)
+ k = k + 1 ; o[k] = extract2(v,0)
+ end
+ end
+ k = i * xsize
+ n = n + xline
+ end
+ else
+ for i=1,ysize do
+ for j=n+f,n+l do
+ local v = t[j]
+ if v == 0 then
+ k = k + 8
+ else
+ k = k + 1 ; if band(v,0x80) ~= 0 then o[k] = 1 end -- o[k] = extract1(v,7)
+ k = k + 1 ; if band(v,0x40) ~= 0 then o[k] = 1 end -- o[k] = extract1(v,6)
+ k = k + 1 ; if band(v,0x20) ~= 0 then o[k] = 1 end -- o[k] = extract1(v,5)
+ k = k + 1 ; if band(v,0x10) ~= 0 then o[k] = 1 end -- o[k] = extract1(v,4)
+ k = k + 1 ; if band(v,0x08) ~= 0 then o[k] = 1 end -- o[k] = extract1(v,3)
+ k = k + 1 ; if band(v,0x04) ~= 0 then o[k] = 1 end -- o[k] = extract1(v,2)
+ k = k + 1 ; if band(v,0x02) ~= 0 then o[k] = 1 end -- o[k] = extract1(v,1)
+ k = k + 1 ; if band(v,0x01) ~= 0 then o[k] = 1 end -- o[k] = extract1(v,0)
+ end
+ end
+ k = i * xsize
+ n = n + xline
+ end
+ end
+ end
+ for i=size,xsize * ysize +1,-1 do
+ o[i] = nil
+ end
+ return o, false
+ end
+
+ local expand_c = pngexpand
+
+ local function analyze(colordepth,colorspace,palette,mask)
+ -- return bytes, parts, factor
+ if palette then
+ if colordepth == 16 then
+ return 2, false, false
+ elseif colordepth == 8 then
+ return 1, false, false
+ elseif colordepth == 4 then
+ return 1, 4, false
+ elseif colordepth == 2 then
+ return 1, 2, false
+ elseif colordepth == 1 then
+ return 1, 1, false
+ end
+ elseif colorspace == "DeviceGray" then
+ if colordepth == 16 then
+ return mask and 4 or 2, false, false
+ elseif colordepth == 8 then
+ return mask and 2 or 1, false, false
+ elseif colordepth == 4 then
+ return 1, 4, true
+ elseif colordepth == 2 then
+ return 1, 2, true
+ elseif colordepth == 1 then
+ return 1, 1, true
+ end
+ else
+ if colordepth == 16 then
+ return mask and 8 or 6, false, false
+ elseif colordepth == 8 then
+ return mask and 4 or 3, false, false
+ elseif colordepth == 4 then
+ return 3, 4, true
+ elseif colordepth == 2 then
+ return 3, 2, true
+ elseif colordepth == 1 then
+ return 3, 1, true
+ end
+ end
+ return false, false, false
+ end
+
+ -- 1 6 4 6 2 6 4 6
+ -- 7 7 7 7 7 7 7 7
+ -- 5 6 5 6 5 6 5 6
+ -- 7 7 7 7 7 7 7 7
+ -- 3 6 4 6 3 6 4 6
+ -- 7 7 7 7 7 7 7 7
+ -- 5 6 5 6 5 6 5 6
+ -- 7 7 7 7 7 7 7 7
+
+ local function deinterlace(content,xsize,ysize,colordepth,colorspace,palette,mask)
+ local slice, parts, factor = analyze(colordepth,colorspace,palette,mask)
+ if slice then
+ content = openstring(zlibdecompress(content))
+ local filter = false
+ local output = false
+ for pass=1,7 do
+ local xstart = xstart[pass]
+ local xstep = xstep[pass]
+ local ystart = ystart[pass]
+ local ystep = ystep[pass]
+ local nx = idiv(xsize + xstep - xstart - 1,xstep)
+ local ny = idiv(ysize + ystep - ystart - 1,ystep)
+ if nx > 0 and ny > 0 then
+ local input, filter
+ if parts then
+ local nxx = ceil(nx*parts/8)
+ input, filter = decodestrip(content,nxx,ny,slice)
+ input, filter = expand(input,nx,ny,parts,nxx,factor,filter)
+ else
+ input, filter = decodestrip(content,nx,ny,slice)
+ end
+ output = transpose(xsize,ysize,slice,pass,input,output,filter)
+ end
+ -- if pass == 3 then
+ -- break -- still looks ok, could be nice for a preroll
+ -- end
+ end
+ return output, parts and 8 or false
+ end
+ end
+
+ -- 1 (palette used), 2 (color used), and 4 (alpha channel used)
+
+ -- paeth:
+ --
+ -- p = a + b - c
+ -- pa = abs(p - a) => a + b - c - a => b - c
+ -- pb = abs(p - b) => a + b - c - b => a - c
+ -- pc = abs(p - c) => a + b - c - c => a + b - c - c => a - c + b - c => pa + pb
+
+ local function full(t,k) local v = "\xFF" t[k] = v return v end
+
+ local function expandvector(transparent)
+ local s = openstring(transparent)
+ local n = #transparent
+ local r = { }
+ for i=0,n-1 do
+ r[i] = readstring(s,1) -- readchar
+ end
+ setmetatableindex(r,full)
+ return r
+ end
+
+ local function createmask_l(content,palette,transparent,xsize,ysize,colordepth,colorspace)
+ if palette then
+ local r = expandvector(transparent)
+ local size = xsize*ysize
+ local len = ceil(xsize*colordepth/8) + 1
+ local o = newoutput(xsize*ysize)
+ local u = setmetatableindex(zero)
+ content = zlibdecompress(content)
+ content = openstring(content)
+ for i=0,ysize-1 do
+ local t = readbytetable(content,len)
+ local k = i * xsize
+ local filter = t[1]
+ if filter == 0 then
+ elseif filter == 1 then
+ for j=3,len do
+ t[j] = (t[j] + t[j-1]) % 256
+ end
+ elseif filter == 2 then
+ for j=2,len do
+ t[j] = (t[j] + u[j]) % 256
+ end
+ elseif filter == 3 then
+ local j = 2
+ t[j] = (t[j] + idiv(u[j],2)) % 256
+ for j=3,len do
+ t[j] = (t[j] + idiv(t[j-1] + u[j],2)) % 256
+ end
+ elseif filter == 4 then
+ local j = 2
+ local p = j - len
+ local b = t[p]
+ if b < 0 then
+ b = - b
+ end
+ if b > 0 then
+ t[j] = (t[j] + b) % 256
+ end
+ for j=3,len do
+ local p = j - len
+ local a = t[j-1]
+ local b = t[p]
+ local c = t[p-1]
+ local pa = b - c
+ local pb = a - c
+ local pc = pa + pb
+ if pa < 0 then pa = - pa end
+ if pb < 0 then pb = - pb end
+ if pc < 0 then pc = - pc end
+ t[j] = (t[j] + ((pa <= pb and pa <= pc and a) or (pb <= pc and b) or c)) % 256
+ end
+ end
+ if colordepth == 8 then
+ for j=2,len do
+ local v = t[j]
+ k = k + 1 ; o[k] = r[v]
+ end
+ elseif colordepth == 4 then
+ for j=2,len do
+ local v = t[j]
+ k = k + 1 ; o[k] = r[extract4(v,4)]
+ k = k + 1 ; o[k] = r[extract4(v,0)]
+ end
+ elseif colordepth == 2 then
+ for j=2,len do
+ local v = t[j]
+ k = k + 1 ; o[k] = r[extract2(v,6)]
+ k = k + 1 ; o[k] = r[extract2(v,4)]
+ k = k + 1 ; o[k] = r[extract2(v,2)]
+ k = k + 1 ; o[k] = r[extract2(v,0)]
+ end
+ else
+ for j=2,len do
+ local v = t[j]
+ k = k + 1 ; o[k] = r[extract1(v,7)]
+ k = k + 1 ; o[k] = r[extract1(v,6)]
+ k = k + 1 ; o[k] = r[extract1(v,5)]
+ k = k + 1 ; o[k] = r[extract1(v,4)]
+ k = k + 1 ; o[k] = r[extract1(v,3)]
+ k = k + 1 ; o[k] = r[extract1(v,2)]
+ k = k + 1 ; o[k] = r[extract1(v,1)]
+ k = k + 1 ; o[k] = r[extract1(v,0)]
+ end
+ end
+ u = t
+ end
+ return concat(o,"",1,size)
+ end
+ end
+
+ local function createmask_c(content,palette,transparent,xsize,ysize,colordepth,colorspace)
+ if palette then
+ local r = expandvector(transparent)
+ local size = xsize*ysize
+ local len = ceil(xsize*colordepth/8)
+ local o = newoutput(size)
+ content = zlibdecompress(content)
+ content = pngapplyfilter(content,len,ysize,1) -- nostrip (saves copy)
+ content = openstring(content)
+ for i=0,ysize-1 do
+ local t = readbytetable(content,len)
+ local k = i * xsize
+ if colordepth == 8 then
+ for j=1,len do
+ local v = t[j]
+ k = k + 1 ; o[k] = r[v]
+ end
+ elseif colordepth == 4 then
+ for j=1,len do
+ local v = t[j]
+ k = k + 1 ; o[k] = r[extract4(v,4)]
+ k = k + 1 ; o[k] = r[extract4(v,0)]
+ end
+ elseif colordepth == 2 then
+ for j=1,len do
+ local v = t[j]
+ k = k + 1 ; o[k] = r[extract2(v,6)]
+ k = k + 1 ; o[k] = r[extract2(v,4)]
+ k = k + 1 ; o[k] = r[extract2(v,2)]
+ k = k + 1 ; o[k] = r[extract2(v,0)]
+ end
+ else
+ for j=1,len do
+ local v = t[j]
+ k = k + 1 ; o[k] = r[extract1(v,7)]
+ k = k + 1 ; o[k] = r[extract1(v,6)]
+ k = k + 1 ; o[k] = r[extract1(v,5)]
+ k = k + 1 ; o[k] = r[extract1(v,4)]
+ k = k + 1 ; o[k] = r[extract1(v,3)]
+ k = k + 1 ; o[k] = r[extract1(v,2)]
+ k = k + 1 ; o[k] = r[extract1(v,1)]
+ k = k + 1 ; o[k] = r[extract1(v,0)]
+ end
+ end
+ end
+ return concat(o,"",1,size)
+ end
+ end
+
+ local function tocmyk_l(content,colordepth)
+ local l = #content
+ local t = { }
+ local n = 0
+ if colordepth == 8 then
+ for i=1,l,3 do
+ local r, g, b = byte(content,i,i+2)
+ n = n + 1 ; t[n] = char(255-r,255-g,255-b,0) -- a tad faster than chars[...]
+ end
+ else
+ for i=1,l,6 do
+ local r1, r2, g1, g2, b1, b2 = byte(content,i,i+5)
+ n = n + 1 ; t[n] = char(255-r1,255-r2,255-g1,255-g2,255-b1,255-b2,0,0)
+ end
+ end
+ return concat(t)
+ end
+
+ local tocmyk_c = pngtocmyk or tocmyk_l
+
+ local function converttocmyk(content,colorspace,colordepth)
+ if colorspace == "DeviceRGB" and colordepth == 8 or colordepth == 16 then
+ local done = tocmyk(content,colordepth)
+ if done then
+ content = done
+ colorspace = "DeviceCMYK"
+ end
+ end
+ return content, colorspace
+ end
+
+ local function switch(v)
+ if v then
+ filtermask = filtermask_l
+ decodemask = decodemask_l
+ decodestrip = decodestrip_l
+ transpose = transpose_l
+ expand = expand_l
+ createmask = createmask_l
+ tocmyk = tocmyk_l
+ else
+ filtermask = filtermask_c
+ decodemask = decodemask_c
+ decodestrip = decodestrip_c
+ transpose = transpose_c
+ expand = expand_c
+ createmask = createmask_c
+ tocmyk = tocmyk_c
+ end
+ end
+
+ if pngapplyfilter then
+ switch(false)
+ directives.register("graphics.png.purelua",switch)
+ else
+ switch(true)
+ end
+
+ local alwaysdecode = false -- trucky with palettes
+ local compresslevel = 3
+
+ directives.register("graphics.png.recompress", function(v)
+ alwaysdecode = v
+ end)
+
+ directives.register("graphics.png.compresslevel", function(v)
+ v = tonumber(v)
+ if compresslevel >= 0 or compresslevel <= 9 then
+ compresslevel = v
+ end
+ end)
+
+ function injectors.png(specification,method) -- todo: method in specification
+ if specification.error then
+ return
+ end
+ local filename = specification.filename
+ if not filename then
+ return
+ end
+ local colorspace = specification.colorspace
+ if not colorspace then
+ return
+ end
+ local interlace = specification.interlace or 0
+ if interlace == 1 then
+ interlace = true
+ elseif interlace == 0 then
+ interlace = false
+ else
+ report_png("unknown interlacing %i",interlace)
+ return
+ end
+ local tables = specification.tables
+ if not tables then
+ return
+ end
+ local idat = tables.idat
+ if not idat then
+ return
+ end
+ local pngfile = newcontent(filename,method)
+ if not pngfile then
+ return
+ end
+ local content = idat(pngfile,true)
+ tables.idat = false
+ --
+ -- if tables.gama then
+ -- report_png("ignoring gamma correction")
+ -- end
+ --
+ local xsize = specification.xsize
+ local ysize = specification.ysize
+ local colordepth = specification.colordepth or 8
+ local mask = false
+ local transparent = false
+ local palette = false
+ local enforcecmyk = specification.enforcecmyk
+ local colors = 1
+ if colorspace == 0 then -- gray | image b
+ colorspace = "DeviceGray"
+ transparent = true
+ elseif colorspace == 2 then -- rgb | image c
+ colorspace = "DeviceRGB"
+ colors = 3
+ transparent = true
+ elseif colorspace == 3 then -- palette | image c+i
+ colorspace = "DeviceRGB"
+ palette = true
+ transparent = true
+ elseif colorspace == 4 then -- gray | alpha | image b
+ colorspace = "DeviceGray"
+ mask = true
+ elseif colorspace == 6 then -- rgb | alpha | image c
+ colorspace = "DeviceRGB"
+ colors = 3
+ mask = true
+ else
+ report_png("unknown colorspace %i",colorspace)
+ return
+ end
+ --
+ if transparent then
+ local trns = tables.trns
+ if trns then
+ transparent = trns(pngfile,true)
+ if transparent == "" then
+ transparent = false
+ end
+ tables.trns = false
+ else
+ transparent = false
+ end
+ end
+ --
+ local decode = alwaysdecode -- tricky, might go away
+ local filter = pdfconstant("FlateDecode")
+ local major = pdfmajorversion()
+ local minor = pdfminorversion()
+ if major > 1 then
+ -- we're okay
+ elseif minor < 5 and colordepth == 16 then
+ report_png("16 bit colordepth not supported in pdf < 1.5")
+ return
+ elseif minor < 4 and (mask or transparent) then
+ report_png("alpha channels not supported in pdf < 1.4")
+ return
+ elseif minor < 2 then
+ report_png("you'd better use a version > 1.2")
+ return
+ -- decode = true
+ end
+ --
+ -- todo: compresslevel (or delegate)
+ --
+ if palette then
+ local plte = tables.plte
+ if plte then
+ palette = plte(pngfile,true)
+ if palette == "" then
+ palette = false
+ end
+ tables.plte = false
+ else
+ palette = false
+ end
+ end
+ --
+ if interlace then
+ local r, p = deinterlace(content,xsize,ysize,colordepth,colorspace,palette,mask)
+ if not r then
+ return
+ end
+ if p then
+ colordepth = p
+ end
+ if mask then
+ if not (colordepth == 8 or colordepth == 16) then
+ report_png("mask can't be split from the image")
+ return
+ end -- get rid of bpp:
+ content, mask = filtermask(r,xsize,ysize,colordepth,colorspace,false)
+ else
+ content = convert(r) -- can be in deinterlace if needed
+ end
+ if enforcecmyk then
+ content, colorspace = converttocmyk(content,colorspace,colordepth)
+ end
+ if compresslevel > 0 then
+ content = zlibcompress(content,compresslevel)
+ else
+ filter = nil
+ end
+ decode = true
+ elseif mask then
+ if not (colordepth == 8 or colordepth == 16) then
+ report_png("mask can't be split from the image")
+ return
+ end
+ content = zlibdecompress(content)
+ content, mask = decodemask(content,xsize,ysize,colordepth,colorspace)
+ if enforcecmyk and not palette then
+ content, colorspace = converttocmyk(content,colorspace,colordepth)
+ end
+ if compresslevel > 0 then
+ content = zlibcompress(content,compresslevel)
+ else
+ filter = nil
+ end
+ decode = true -- we don't copy the filter byte
+ elseif transparent then
+ -- in test suite
+ -- how about decode/recompress here
+ if palette then
+ mask = createmask(content,palette,transparent,xsize,ysize,colordepth,colorspace)
+ else
+ pallette = false
+ end
+ elseif decode or (enforcecmyk and not palette) then
+ -- this one needs checking
+ local bytes = analyze(colordepth,colorspace)
+ if bytes then
+ content = zlibdecompress(content)
+ content = decodestrip(openstring(content),xsize,ysize,bytes)
+ if enforcecmyk and not palette then
+ content, colorspace = converttocmyk(content,colorspace,colordepth)
+ end
+ if compresslevel > 0 then
+ content = zlibcompress(content,compresslevel)
+ else
+ filter = nil
+ end
+ else
+ return
+ end
+ decode = true -- due to enforcecmyk
+ else
+ -- print("PASS ON")
+ end
+ if palette then
+ local colorspace = "DeviceRGB"
+ local nofbytes = 3
+ if enforcecmyk then
+ palette = converttocmyk(palette,colorspace,8)
+ colorspace = "DeviceCMYK"
+ nofbytes = 4
+ end
+ palette = pdfarray {
+ pdfconstant("Indexed"),
+ pdfconstant(colorspace),
+ idiv(#palette,nofbytes),
+ pdfreference(pdfflushstreamobject(palette)),
+ }
+ end
+ pngfile:close()
+ local xobject = pdfdictionary {
+ Type = pdfconstant("XObject"),
+ Subtype = pdfconstant("Image"),
+ -- BBox = pdfarray { 0, 0, xsize, ysize },
+ Width = xsize,
+ Height = ysize,
+ BitsPerComponent = colordepth,
+ Filter = filter,
+ ColorSpace = palette or pdfconstant(colorspace),
+ Length = #content,
+ } + specification.attr
+ if mask then
+ local d = pdfdictionary {
+ Type = pdfconstant("XObject"),
+ Subtype = pdfconstant("Image"),
+ Width = xsize,
+ Height = ysize,
+ BitsPerComponent = palette and 8 or colordepth,
+ ColorSpace = pdfconstant("DeviceGray"),
+ }
+ xobject.SMask = pdfreference(pdfflushstreamobject(mask,d()))
+ end
+ if not decode then
+ xobject.DecodeParms = pdfdictionary {
+ Colors = colors,
+ Columns = xsize,
+ BitsPerComponent = colordepth,
+ Predictor = 15,
+ }
+ end
+ if trace then
+ report_png("%s: width %i, height %i, colordepth %i, size %i, palette %l, mask %l, transparent %l, decode %l",filename,xsize,ysize,colordepth,#content,palette,mask,transparent,decode)
+ end
+ if specification.colorref then
+ xobject.ColorSpace = pdfreference(specification.colorref)
+ end
+ local width = specification.width or xsize * 65536
+ local height = specification.height or ysize * 65536
+ return createimage {
+ bbox = { 0, 0, width/xsize, height/ysize }, -- mandate
+ transform = specification.transform,
+ nolength = true,
+ nobbox = true,
+ notype = true,
+ stream = content,
+ attr = xobject(),
+ }
+ end
+
+end
+
+do
+
+ local function pack(specification,what)
+ local t = { }
+ local n = 0
+ local s = specification.colorspace
+ local d = specification.data
+ local x = specification.xsize
+ local y = specification.ysize
+ if what == "mask" then
+ d = specification.mask
+ s = 1
+ elseif what == "indexed" then
+ s = 1
+ elseif what == "index" then
+ d = specification.index
+ s = - s
+ end
+ if s > 0 then
+ if s == 1 then
+ for i=1,y do
+ local r = d[i]
+ for j=1,x do
+ n = n + 1 ; t[n] = chars[r[j]]
+ end
+ end
+ elseif s == 2 then
+ for i=1,y do
+ local r = d[i]
+ for j=1,x do
+ local c = r[j]
+ n = n + 1 ; t[n] = chars[c[1]]
+ n = n + 1 ; t[n] = chars[c[2]]
+ n = n + 1 ; t[n] = chars[c[3]]
+ -- n = n + 1 ; t[n] = char(c[1],c[2],c[3]) -- test this
+ end
+ end
+ elseif s == 3 then
+ for i=1,y do
+ local r = d[i]
+ for j=1,x do
+ local c = r[j]
+ n = n + 1 ; t[n] = chars[c[1]]
+ n = n + 1 ; t[n] = chars[c[2]]
+ n = n + 1 ; t[n] = chars[c[3]]
+ n = n + 1 ; t[n] = chars[c[4]]
+ -- n = n + 1 ; t[n] = char(c[1],c[2],c[3],c[4]) -- test this
+ end
+ end
+ end
+ return concat(t)
+ else
+ local z = d[0] and 0 or 1
+ if s == -1 then
+ local f = formatters["%02X"]
+ for i=z,#d do
+ n = n + 1 ; t[n] = f(d[i])
+ end
+ elseif s == -2 then
+ local f = formatters["%02X%02X%02X"]
+ for i=z,#d do
+ local c = d[i]
+ n = n + 1 ; t[n] = f(c[1],c[2],c[3])
+ end
+ elseif s == -3 then
+ local f = formatters["%02X%02X%02X%02X"]
+ for i=z,#d do
+ local c = d[i]
+ n = n + 1 ; t[n] = f(c[1],c[2],c[3],c[4])
+ end
+ end
+ return "<" .. concat(t," ") .. ">"
+ end
+ return ""
+ end
+
+ function injectors.bitmap(specification)
+ local data = specification.data
+ if not data then
+ return
+ end
+ local xsize = specification.xsize or 0
+ local ysize = specification.ysize or 0
+ if xsize == 0 or ysize == 0 then
+ return
+ end
+ local colorspace = specification.colorspace or 1
+ if colorspace == 1 then
+ colorspace = "DeviceGray"
+ elseif colorspace == 2 then
+ colorspace = "DeviceRGB"
+ elseif colorspace == 3 then
+ colorspace = "DeviceCMYK"
+ end
+ local colordepth = (specification.colordepth or 2) == 16 or 8
+ local index = specification.index
+ local content = pack(specification,index and "indexed" or "data")
+ local mask = specification.mask
+ local colorspace = pdfconstant(colorspace)
+ if index then
+ colorspace = pdfarray {
+ pdfconstant("Indexed"),
+ colorspace,
+ #index + (index[0] and 0 or -1), -- upper index
+ pdfverbose(pack(specification,"index"))
+ }
+ end
+ local xobject = pdfdictionary {
+ Type = pdfconstant("XObject"),
+ Subtype = pdfconstant("Image"),
+ BBox = pdfarray { 0, 0, xsize, ysize },
+ Width = xsize,
+ Height = ysize,
+ BitsPerComponent = colordepth,
+ ColorSpace = colorspace,
+ Length = #content, -- specification.length
+ }
+ if mask then
+ local d = pdfdictionary {
+ Type = pdfconstant("XObject"),
+ Subtype = pdfconstant("Image"),
+ Width = xsize,
+ Height = ysize,
+ BitsPerComponent = colordepth,
+ ColorSpace = pdfconstant("DeviceGray"),
+ }
+ xobject.SMask = pdfreference(pdfflushstreamobject(pack(specification,"mask"),d()))
+ end
+ return createimage {
+ bbox = { 0, 0, specification.width/xsize, specification.height/ysize }, -- mandate
+ -- nolength = true,
+ nobbox = true,
+ notype = true,
+ stream = content,
+ attr = xobject(),
+ }
+ end
+
+ backends.pdf.codeinjections.bitmap = injectors.bitmap
+
+end
+
+-- local function validcompression(data)
+-- local d = utilities.streams.openstring(data)
+-- local b1 = utilities.streams.readbyte(d)
+-- local b2 = utilities.streams.readbyte(d)
+-- print(b1,b2)
+-- if (b1 * 256 + b2) % 31 ~= 0 then
+-- return false, "no zlib compressed file"
+-- end
+-- local method = band(b1,15)
+-- if method ~= 8 then
+-- return false, "method 8 expected"
+-- end
+-- local detail = band(rshift(b1,4),15)
+-- if detail > 7 then
+-- return false, "window 32 expected"
+-- end
+-- local preset = band(rshift(b2,5),1)
+-- if preset ~= 0 then
+-- return false, "unexpected preset dictionary"
+-- end
+-- return true
+-- end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lpdf-ini.lua b/Master/texmf-dist/tex/context/base/mkiv/lpdf-ini.lua
index ec837449f7e..2163e874852 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lpdf-ini.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/lpdf-ini.lua
@@ -12,12 +12,13 @@ local setmetatable, getmetatable, type, next, tostring, tonumber, rawset = setme
local char, byte, format, gsub, concat, match, sub, gmatch = string.char, string.byte, string.format, string.gsub, table.concat, string.match, string.sub, string.gmatch
local utfchar, utfbyte, utfvalues = utf.char, utf.byte, utf.values
local sind, cosd, max, min = math.sind, math.cosd, math.max, math.min
-local sort = table.sort
+local sort, sortedhash = table.sort, table.sortedhash
local P, C, R, S, Cc, Cs, V = lpeg.P, lpeg.C, lpeg.R, lpeg.S, lpeg.Cc, lpeg.Cs, lpeg.V
local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns
local formatters = string.formatters
local isboolean = string.is_boolean
local rshift = bit32.rshift
+local osdate, ostime = os.date, os.time
local report_objects = logs.reporter("backend","objects")
local report_finalizing = logs.reporter("backend","finalizing")
@@ -57,7 +58,7 @@ lpdf.flags = lpdf.flags or { } -- will be filled later
local trace_finalizers = false trackers.register("backend.finalizers", function(v) trace_finalizers = v end)
local trace_resources = false trackers.register("backend.resources", function(v) trace_resources = v end)
local trace_objects = false trackers.register("backend.objects", function(v) trace_objects = v end)
-local trace_detail = false trackers.register("backend.detail", function(v) trace_detail = v end)
+local trace_details = false trackers.register("backend.details", function(v) trace_details = v end)
do
@@ -169,23 +170,25 @@ end
local pdfgetpagereference
updaters.register("backend.update.lpdf",function()
- pdfreserveobject = pdf.reserveobj
- pdfimmediateobject = pdf.immediateobj
- pdfdeferredobject = pdf.obj
- pdfreferenceobject = pdf.refobj
+ pdfreserveobject = pdf.reserveobj
+ pdfimmediateobject = pdf.immediateobj
+ pdfdeferredobject = pdf.obj
+ pdfreferenceobject = pdf.refobj
- pdfgetpagereference = pdf.getpageref
+ pdfgetpagereference = pdf.getpageref
- pdfsetpageresources = pdf.setpageresources
- pdfsetpageattributes = pdf.setpageattributes
- pdfsetpagesattributes = pdf.setpagesattributes
+ pdfsetpageresources = pdf.setpageresources
+ pdfsetpageattributes = pdf.setpageattributes
+ pdfsetpagesattributes = pdf.setpagesattributes
end)
local jobpositions = job.positions
local getpos = jobpositions.getpos
+local getrpos = jobpositions.getrpos
jobpositions.registerhandlers {
getpos = pdf.getpos,
+ -- getrpos = pdf.getrpos,
gethpos = pdf.gethpos,
getvpos = pdf.getvpos,
}
@@ -204,8 +207,6 @@ do
return pdfprint(...)
end
- pdfbackend.codeinjections.print = lpdf.print -- will go
-
-- local function transform(llx,lly,urx,ury,rx,sx,sy,ry)
-- local x1 = llx * rx + lly * sy
-- local y1 = llx * sx + lly * ry
@@ -236,7 +237,7 @@ do
-- funny values for tx and ty
function lpdf.rectangle(width,height,depth,offset)
- local tx, ty = getpos()
+ local tx, ty = getpos() -- pdfgetpos, maybe some day use dir here
if offset then
tx = tx - offset
ty = ty + offset
@@ -866,18 +867,21 @@ end
local nofpages = 0
-function lpdf.pagereference(n)
+local texgetcount = tex.getcount
+
+function lpdf.pagereference(n,complete) -- true | false | nil | n [true,false]
if nofpages == 0 then
nofpages = structures.pages.nofpages
if nofpages == 0 then
nofpages = 1
end
end
- if n > nofpages then
- return pdfgetpagereference(nofpages) -- or 1, could be configureable
- else
- return pdfgetpagereference(n)
+ if n == true or not n then
+ complete = n
+ n = texgetcount("realpageno")
end
+ local r = n > nofpages and pdfgetpagereference(nofpages) or pdfgetpagereference(n)
+ return complete and pdfreference(r) or r
end
function lpdf.nofpages()
@@ -907,7 +911,7 @@ function lpdf.flushobject(name,data)
local named = names[name]
if named then
if not trace_objects then
- elseif trace_detail then
+ elseif trace_details then
report_objects("flushing data to reserved object with name %a, data: %S",name,data)
else
report_objects("flushing data to reserved object with name %a",name)
@@ -915,7 +919,7 @@ function lpdf.flushobject(name,data)
return pdfimmediateobject(named,tostring(data))
else
if not trace_objects then
- elseif trace_detail then
+ elseif trace_details then
report_objects("flushing data to reserved object with number %s, data: %S",name,data)
else
report_objects("flushing data to reserved object with number %s",name)
@@ -923,7 +927,7 @@ function lpdf.flushobject(name,data)
return pdfimmediateobject(name,tostring(data))
end
else
- if trace_objects and trace_detail then
+ if trace_objects and trace_details then
report_objects("flushing data: %S",name)
end
return pdfimmediateobject(tostring(name))
@@ -1249,32 +1253,47 @@ do
-- todo: share them
-- todo: force when not yet set
+ local f_font = formatters["%s%d"]
+
function lpdf.collectedresources(options)
local ExtGState = d_extgstates and next(d_extgstates ) and p_extgstates
local ColorSpace = d_colorspaces and next(d_colorspaces) and p_colorspaces
local Pattern = d_patterns and next(d_patterns ) and p_patterns
local Shading = d_shades and next(d_shades ) and p_shades
+ local Font
if options and options.patterns == false then
Pattern = nil
end
- if ExtGState or ColorSpace or Pattern or Shading then
+ local fonts = options and options.fonts
+ if fonts and next(fonts) then
+ local pdfgetfontobjnumber = lpdf.getfontobjnumber
+ if pdfgetfontobjnumber then
+ local prefix = options.fontprefix or "F"
+ Font = pdfdictionary { }
+ for k, v in sortedhash(fonts) do
+ Font[f_font(prefix,v)] = pdfreference(pdfgetfontobjnumber(k))
+ end
+ end
+ end
+ if ExtGState or ColorSpace or Pattern or Shading or Font then
local collected = pdfdictionary {
ExtGState = ExtGState,
ColorSpace = ColorSpace,
Pattern = Pattern,
Shading = Shading,
+ Font = Font,
}
if options and options.serialize == false then
return collected
else
return collected()
end
+ elseif options and options.notempty then
+ return nil
+ elseif options and options.serialize == false then
+ return pdfdictionary { }
else
- if options and options.serialize == false then
- return pdfdictionary { }
- else
- return ""
- end
+ return ""
end
end
@@ -1383,8 +1402,13 @@ do
lpdf.settime(tonumber(resolvers.variable("start_time")) or tonumber(resolvers.variable("SOURCE_DATE_EPOCH"))) -- bah
function lpdf.pdftimestamp(str)
- local Y, M, D, h, m, s, Zs, Zh, Zm = match(str,"^(%d%d%d%d)%-(%d%d)%-(%d%d)T(%d%d):(%d%d):(%d%d)([%+%-])(%d%d):(%d%d)$")
- return Y and format("D:%s%s%s%s%s%s%s%s'%s'",Y,M,D,h,m,s,Zs,Zh,Zm)
+ local t = type(str)
+ if t == "string" then
+ local Y, M, D, h, m, s, Zs, Zh, Zm = match(str,"^(%d%d%d%d)%-(%d%d)%-(%d%d)T(%d%d):(%d%d):(%d%d)([%+%-])(%d%d):(%d%d)$")
+ return Y and format("D:%s%s%s%s%s%s%s%s'%s'",Y,M,D,h,m,s,Zs,Zh,Zm)
+ else
+ return osdate("D:%Y%m%d%H%M%S",t == "number" and str or ostime()) -- maybe "!D..." : universal time
+ end
end
function lpdf.id(date)
@@ -1478,41 +1502,23 @@ end
do
- local f_actual_text_one = formatters["BT /Span << /ActualText <feff%04x> >> BDC %s EMC ET"]
- local f_actual_text_two = formatters["BT /Span << /ActualText <feff%04x%04x> >> BDC %s EMC ET"]
- local f_actual_text_one_b = formatters["BT /Span << /ActualText <feff%04x> >> BDC"]
- local f_actual_text_two_b = formatters["BT /Span << /ActualText <feff%04x%04x> >> BDC"]
- local f_actual_text_b = formatters["BT /Span << /ActualText <feff%s> >> BDC"]
- local s_actual_text_e = "EMC ET"
- local f_actual_text_b_not = formatters["/Span << /ActualText <feff%s> >> BDC"]
- local f_actual_text_one_b_not = formatters["/Span << /ActualText <feff%04x> >> BDC"]
- local f_actual_text_two_b_not = formatters["/Span << /ActualText <feff%04x%04x> >> BDC"]
- local s_actual_text_e_not = "EMC"
- local f_actual_text = formatters["/Span <</ActualText %s >> BDC"]
+ local f_actual_text_p = formatters["BT /Span << /ActualText <feff%s> >> BDC %s EMC ET"]
+ local f_actual_text_b = formatters["BT /Span << /ActualText <feff%s> >> BDC"]
+ local s_actual_text_e = "EMC ET"
+ local f_actual_text_b_not = formatters["/Span << /ActualText <feff%s> >> BDC"]
+ local s_actual_text_e_not = "EMC"
+ local f_actual_text = formatters["/Span <</ActualText %s >> BDC"]
local context = context
local pdfdirect = nodes.pool.directliteral -- we can use nuts.write deep down
-
- -- todo: use tounicode from the font mapper
-
- -- floor(unicode/1024) => rshift(unicode,10) -- better for 5.3
+ local tounicode = fonts.mappings.tounicode
function codeinjections.unicodetoactualtext(unicode,pdfcode)
- if unicode < 0x10000 then
- return f_actual_text_one(unicode,pdfcode)
- else
- return f_actual_text_two(rshift(unicode,10)+0xD800,unicode%1024+0xDC00,pdfcode)
- end
+ return f_actual_text_p(type(unicode) == "string" and unicode or tounicode(unicode),pdfcode)
end
function codeinjections.startunicodetoactualtext(unicode)
- if type(unicode) == "string" then
- return f_actual_text_b(unicode)
- elseif unicode < 0x10000 then
- return f_actual_text_one_b(unicode)
- else
- return f_actual_text_two_b(rshift(unicode,10)+0xD800,unicode%1024+0xDC00)
- end
+ return f_actual_text_b(type(unicode) == "string" and unicode or tounicode(unicode))
end
function codeinjections.stopunicodetoactualtext()
@@ -1520,13 +1526,7 @@ do
end
function codeinjections.startunicodetoactualtextdirect(unicode)
- if type(unicode) == "string" then
- return f_actual_text_b_not(unicode)
- elseif unicode < 0x10000 then
- return f_actual_text_one_b_not(unicode)
- else
- return f_actual_text_two_b_not(rshift(unicode,10)+0xD800,unicode%1024+0xDC00)
- end
+ return f_actual_text_b_not(type(unicode) == "string" and unicode or tounicode(unicode))
end
function codeinjections.stopunicodetoactualtextdirect()
@@ -1689,5 +1689,3 @@ end
if environment.arguments.nocompression then
lpdf.setcompression(0,0,true)
end
-
-
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lpdf-lmt.lua b/Master/texmf-dist/tex/context/base/mkiv/lpdf-lmt.lua
new file mode 100644
index 00000000000..0ad0c4e5ec0
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/lpdf-lmt.lua
@@ -0,0 +1,2762 @@
+if not modules then modules = { } end modules ['lpdf-lmt'] = {
+ version = 1.001,
+ comment = "companion to lpdf-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- The code below was originally in back-lpd.lua but it makes more sense in
+-- this namespace. I will rename variables.
+--
+-- There is no way that a lua based backend can compete with the original one
+-- for relative simple text runs. And we're talking seconds here on say 500
+-- pages with paragraphs alternativng between three fonts and colors. But such
+-- documents are rare so in practice we are quite okay, especially because in
+-- ConTeXt we can gain quite a bit elsewhere. So, when we loose 30% on such
+-- simple documents, we break even on for instance the manual, and gain 30% on
+-- Thomas's turture test (also for other reasons). But .. who knows what magic
+-- I can cook up in due time.
+
+-- If you consider this complex, watch:
+--
+-- https://www.youtube.com/watch?v=6H-cAzfB2qo
+--
+-- or in distractionmode:
+--
+-- https://www.youtube.com/watch?v=TYuTE_1jvvE
+-- https://www.youtube.com/watch?v=nnicGKX3lvM
+--
+-- For the moment we have to support the built in backend as well as the alternative. So
+-- the next interface is suboptimal and will change at some time. At that moment I will
+-- also optimize and extend.
+
+local type, next, unpack, tonumber = type, next, unpack, tonumber
+local char, rep, find = string.char, string.rep, string.find
+local formatters, splitupstring = string.formatters, string.splitup
+local band, extract = bit32.band, bit32.extract
+local concat, sortedhash = table.concat, table.sortedhash
+local setmetatableindex = table.setmetatableindex
+local loaddata = io.loaddata
+
+local bpfactor <const> = number.dimenfactors.bp
+
+local md5HEX = md5.HEX
+local osuuid = os.uuid
+local zlibcompress = (xzip or zlib).compress
+
+local nuts = nodes.nuts
+local tonut = nodes.tonut
+
+local getdata = nuts.getdata
+local getsubtype = nuts.getsubtype
+local getwhd = nuts.getwhd
+local flushlist = nuts.flush_list
+
+local pdfincludeimage = lpdf.includeimage
+local pdfgetfontname = lpdf.getfontname
+local pdfgetfontobjnumber = lpdf.getfontobjnumber
+
+local pdfreserveobject = lpdf.reserveobject
+local pdfpagereference = lpdf.pagereference
+local pdfflushobject = lpdf.flushobject
+local pdfreference = lpdf.reference
+local pdfdictionary = lpdf.dictionary
+local pdfarray = lpdf.array
+local pdfconstant = lpdf.constant
+local pdfflushstreamobject = lpdf.flushstreamobject
+local pdfliteral = lpdf.literal -- not to be confused with a whatsit!
+
+local pdf_pages = pdfconstant("Pages")
+local pdf_page = pdfconstant("Page")
+local pdf_xobject = pdfconstant("XObject")
+local pdf_form = pdfconstant("Form")
+
+local fonthashes = fonts.hashes
+local characters = fonthashes.characters
+local descriptions = fonthashes.descriptions
+local parameters = fonthashes.parameters
+local properties = fonthashes.properties
+
+local report = logs.reporter("backend")
+
+-- used variables
+
+local pdf_h, pdf_v
+local need_tm, need_tf, cur_tmrx, cur_factor, cur_f, cur_e
+local need_width, need_mode, done_width, done_mode
+local mode
+local f_pdf_cur, f_pdf, fs_cur, fs, f_cur
+local tj_delta, cw
+local usedfonts, usedxforms, usedximages, usedxgroups
+local getxformname, getximagename
+local boundingbox, shippingmode, objectnumber
+local tmrx, tmry, tmsx, tmsy, tmtx, tmty
+local cmrx, cmry, cmsx, cmsy, cmtx, cmty
+
+local function usefont(t,k) -- a bit redundant hash
+ local v = pdfgetfontname(k)
+ t[k] = v
+ return v
+end
+
+local function reset_variables(specification)
+ pdf_h, pdf_v = 0, 0
+ cmrx, cmry = 1, 1
+ cmsx, cmsy = 0, 0
+ cmtx, cmty = 0, 0
+ tmrx, tmry = 1, 1
+ tmsx, tmsy = 0, 0
+ tmtx, tmty = 0, 0
+ need_tm = false
+ need_tf = false
+ need_width = 0
+ need_mode = 0
+ done_width = false
+ done_mode = false
+ mode = "page"
+ shippingmode = specification.shippingmode
+ objectnumber = specification.objectnumber
+ cur_tmrx = 0
+ f_cur = 0
+ f_pdf_cur = 0 -- nullfont
+ f_pdf = 0 -- nullfont
+ fs_cur = 0
+ fs = 0
+ tj_delta = 0
+ cur_factor = 0
+ cur_f = false
+ cur_e = false
+ cw = 0
+ usedfonts = setmetatableindex(usefont)
+ usedxforms = { }
+ usedximages = { }
+ -- usedxgroups = { }
+ boundingbox = specification.boundingbox
+end
+
+-- buffer
+
+local buffer = { }
+local b = 0
+
+local function reset_buffer()
+ b = 0
+end
+
+-- fonts
+
+local fontcharacters
+local fontdescriptions
+local fontparameters
+local fontproperties
+local usedcharacters = setmetatableindex("table")
+local pdfcharacters
+
+local horizontalmode = true
+----- widefontmode = true
+local scalefactor = 1
+local threshold = 655360
+local tjfactor <const> = 100 / 65536
+
+lpdf.usedcharacters = usedcharacters
+
+local function updatefontstate(font)
+ fontcharacters = characters[font]
+ fontdescriptions = descriptions[font]
+ fontparameters = parameters[font]
+ fontproperties = properties[font]
+ local size = fontparameters.size -- or bad news
+ local designsize = fontparameters.designsize or size
+ pdfcharacters = usedcharacters[font]
+ horizontalmode = fontparameters.writingmode ~= "vertical"
+ -- widefontmode = fontproperties.encodingbytes == 2
+ scalefactor = (designsize/size) * tjfactor
+ local fthreshold = fontproperties.threshold
+ threshold = (fthreshold and (size * fthreshold / 100)) or 655360
+end
+
+-- helpers
+
+local f_cm = formatters["%.6N %.6N %.6N %.6N %.6N %.6N cm"]
+local f_tm = formatters["%.6N %.6N %.6N %.6N %.6N %.6N Tm"]
+
+local saved_text_pos_v = 0
+local saved_text_pos_h = 0
+
+local function begin_text()
+ saved_text_pos_h = pdf_h
+ saved_text_pos_v = pdf_v
+ b = b + 1 ; buffer[b] = "BT"
+ need_tf = true
+ need_width = 0
+ need_mode = 0
+ mode = "text"
+end
+
+local function end_text()
+ if done_width then
+ b = b + 1 ; buffer[b] = "0 w"
+ done_width = false
+ end
+ if done_mode then
+ b = b + 1 ; buffer[b] = "0 Tr"
+ done_mode = false
+ end
+ b = b + 1 ; buffer[b] = "ET"
+ pdf_h = saved_text_pos_h
+ pdf_v = saved_text_pos_v
+ mode = "page"
+end
+
+local saved_chararray_pos_h
+local saved_chararray_pos_v
+
+local saved_b = 0
+
+local function begin_chararray()
+ saved_chararray_pos_h = pdf_h
+ saved_chararray_pos_v = pdf_v
+ cw = horizontalmode and saved_chararray_pos_h or - saved_chararray_pos_v
+ tj_delta = 0
+ saved_b = b
+ b = b + 1 ; buffer[b] = " ["
+ mode = "chararray"
+end
+
+local function end_chararray()
+ b = b + 1 ; buffer[b] = "] TJ"
+ buffer[saved_b] = concat(buffer,"",saved_b,b)
+ b = saved_b
+ pdf_h = saved_chararray_pos_h
+ pdf_v = saved_chararray_pos_v
+ mode = "text"
+end
+
+local function begin_charmode()
+ b = b + 1 ; buffer[b] = "<"
+ mode = "char"
+end
+
+local function end_charmode()
+ b = b + 1 ; buffer[b] = ">"
+ mode = "chararray"
+end
+
+local function calc_pdfpos(h,v)
+ -- mostly char
+ if mode == "page" then
+ cmtx = h - pdf_h
+ cmty = v - pdf_v
+ return h ~= pdf_h or v ~= pdf_v
+ elseif mode == "text" then
+ tmtx = h - saved_text_pos_h
+ tmty = v - saved_text_pos_v
+ return h ~= pdf_h or v ~= pdf_v
+ elseif horizontalmode then
+ tmty = v - saved_text_pos_v
+ tj_delta = cw - h
+ return tj_delta ~= 0 or v ~= pdf_v
+ else
+ tmtx = h - saved_text_pos_h
+ tj_delta = cw + v
+ return tj_delta ~= 0 or h ~= pdf_h
+ end
+end
+
+local function pdf_set_pos(h,v)
+ local move = calc_pdfpos(h,v)
+ if move then
+ b = b + 1 ; buffer[b] = f_cm(cmrx, cmsx, cmsy, cmry, cmtx*bpfactor, cmty*bpfactor)
+ pdf_h = pdf_h + cmtx
+ pdf_v = pdf_v + cmty
+ end
+end
+
+local function pdf_reset_pos()
+ if mode == "page" then
+ cmtx = - pdf_h
+ cmty = - pdf_v
+ if pdf_h == 0 and pdf_v == 0 then
+ return
+ end
+ elseif mode == "text" then
+ tmtx = - saved_text_pos_h
+ tmty = - saved_text_pos_v
+ if pdf_h == 0 and pdf_v == 0 then
+ return
+ end
+ elseif horizontalmode then
+ tmty = - saved_text_pos_v
+ tj_delta = cw
+ if tj_delta == 0 and pdf_v == 0 then
+ return
+ end
+ else
+ tmtx = - saved_text_pos_h
+ tj_delta = cw
+ if tj_delta == 0 and pdf_h == 0 then
+ return
+ end
+ end
+ b = b + 1 ; buffer[b] = f_cm(cmrx, cmsx, cmsy, cmry, cmtx*bpfactor, cmty*bpfactor)
+ pdf_h = pdf_h + cmtx
+ pdf_v = pdf_v + cmty
+end
+
+local function pdf_set_pos_temp(h,v)
+ local move = calc_pdfpos(h,v)
+ if move then
+ b = b + 1 ; buffer[b] = f_cm(cmrx, cmsx, cmsy, cmry, cmtx*bpfactor, cmty*bpfactor)
+ end
+end
+
+-- these dummy returns makes using them a bit faster
+
+local function pdf_end_string_nl()
+ if mode == "char" then
+ end_charmode()
+ return end_chararray()
+ elseif mode == "chararray" then
+ return end_chararray()
+ end
+end
+
+local function pdf_goto_textmode()
+ if mode == "page" then
+ pdf_reset_pos()
+ return begin_text()
+ elseif mode ~= "text" then
+ if mode == "char" then
+ end_charmode()
+ return end_chararray()
+ else -- if mode == "chararray" then
+ return end_chararray()
+ end
+ end
+end
+
+local function pdf_goto_pagemode()
+ if mode ~= "page" then
+ if mode == "char" then
+ end_charmode()
+ end_chararray()
+ return end_text()
+ elseif mode == "chararray" then
+ end_chararray()
+ return end_text()
+ elseif mode == "text" then
+ return end_text()
+ end
+ end
+end
+
+local function pdf_goto_fontmode()
+ if mode == "char" then
+ end_charmode()
+ end_chararray()
+ end_text()
+ elseif mode == "chararray" then
+ end_chararray()
+ end_text()
+ elseif mode == "text" then
+ end_text()
+ end
+ pdf_reset_pos()
+ mode = "page"
+end
+
+-- characters
+
+local flushcharacter do
+
+ local round = math.round
+
+ -- across pages ... todo: clean up because we don't need to pass the font
+ -- as fontparameters already has checked / set it we can also have a variable
+ -- for it so
+
+ local naturalwidth = nil
+
+ local naturalwidths = setmetatableindex(function(t,font)
+ local d = descriptions[font]
+ local c = characters[font]
+ local f = parameters[font].hfactor
+ local v = setmetatableindex(function(t,char)
+ local e = d and d[char]
+ local w = 0
+ if e then
+ w = e.width
+ if w then
+ w = w * f
+ end
+ end
+ e = c[char]
+ if e then
+ w = e.width or 0
+ end
+ t[char] = w
+ return w
+ end)
+ t[font] = v
+ return v
+ end)
+
+ local function setup_fontparameters(font,factor,f,e)
+ local slant = fontparameters.slantfactor or 0
+ local extend = fontparameters.extendfactor or 1
+ local squeeze = fontparameters.squeezefactor or 1
+ local expand = 1 + factor / 1000000
+ local format = fontproperties.format
+ if e then
+ extend = extend * e
+ end
+ tmrx = expand * extend
+ tmsy = slant
+ tmry = squeeze
+ need_width = fontparameters.width or 0
+ need_mode = fontparameters.mode or 0
+ f_cur = font
+ f_pdf = usedfonts[font] -- cache
+ cur_factor = factor
+ cur_f = f
+ cur_e = e
+ tj_delta = 0
+ fs = fontparameters.size * bpfactor
+ if f then
+ fs = fs * f
+ end
+ -- kind of special:
+ if format == "opentype" or format == "type1" then
+ fs = fs * 1000 / fontparameters.units -- can we avoid this ?
+ end
+ --
+ naturalwidth = naturalwidths[font]
+ end
+
+ -- This only saves a little on hz because there we switch a lot of
+ -- instances.
+
+ -- local lastslant, lastextend, lastsqueeze, lastformat, lastsize, lastwidth, lastmode, lastused, lastfont
+
+ -- local function setup_fontparameters(font,factor,f,e)
+ -- if font ~= lastfont then
+ -- lastslant = fontparameters.slantfactor or 0
+ -- lastextend = fontparameters.extendfactor or 1
+ -- lastsqueeze = fontparameters.squeezefactor or 1
+ -- lastformat = fontproperties.format
+ -- lastsize = fontparameters.size * bpfactor
+ -- if format == "opentype" or format == "type1" then
+ -- lastsize = lastsize * 1000 / fontparameters.units -- can we avoid this ?
+ -- end
+ -- lastwidth = fontparameters.width
+ -- lastmode = fontparameters.mode
+ -- lastused = usedfonts[font] -- cache
+ -- lastfont = font
+ -- end
+ -- local expand = 1 + factor / 1000000
+ -- if e then
+ -- tmrx = expand * lastextend * e
+ -- else
+ -- tmrx = expand * lastextend
+ -- end
+ -- tmsy = lastslant
+ -- tmry = lastsqueeze
+ -- need_width = lastwidth
+ -- need_mode = lastmode
+ -- f_cur = lastfont
+ -- f_pdf = lastused
+ -- cur_factor = factor
+ -- cur_f = f
+ -- cur_e = e
+ -- tj_delta = 0
+ -- if f then
+ -- fs = lastsize * f
+ -- else
+ -- fs = lastsize
+ -- end
+ -- end
+
+ local f_width = formatters["%.6N w"]
+ local f_mode = formatters["%i Tr"] -- can be hash
+ local f_font = formatters["/F%i %.6N Tf"] -- can be hash
+
+ local s_width <const> = "0 w"
+ local s_mode <const> = "0 Tr"
+
+ local function set_font()
+ -- if need_width and need_width ~= 0 then
+ if need_width ~= 0 then
+ b = b + 1 ; buffer[b] = f_width(bpfactor * need_width / 1000)
+ done_width = true
+ elseif done_width then
+ b = b + 1 ; buffer[b] = s_width
+ done_width = false
+ end
+ -- if need_mode and need_mode ~= 0 then
+ if need_mode ~= 0 then
+ b = b + 1 ; buffer[b] = f_mode(need_mode)
+ done_mode = true
+ elseif done_mode then
+ b = b + 1 ; buffer[b] = s_mode
+ done_mode = false
+ end
+ b = b + 1 ; buffer[b] = f_font(f_pdf,fs)
+ f_pdf_cur = f_pdf
+ fs_cur = fs
+ need_tf = false
+ need_tm = true
+ end
+
+ local function set_textmatrix(h,v)
+ local move = calc_pdfpos(h,v)
+ if need_tm or move then
+ b = b + 1 ; buffer[b] = f_tm(tmrx, tmsx, tmsy, tmry, tmtx*bpfactor, tmty*bpfactor)
+ pdf_h = saved_text_pos_h + tmtx
+ pdf_v = saved_text_pos_v + tmty
+ need_tm = false
+ end
+ cur_tmrx = tmrx
+ end
+
+ local f_hex_4 = formatters["%04X"]
+ local f_hex_2 = formatters["%02X"]
+
+ local h_hex_4 = setmetatableindex(function(t,k) -- we already have this somewhere
+ if k < 256 then -- maybe 512
+ -- not sparse in this range
+ for i=0,255 do
+ t[i] = f_hex_4(i)
+ end
+ return t[k]
+ else
+ local v = f_hex_4(k)
+ t[k] = v
+ return v
+ end
+ end)
+ local h_hex_2 = setmetatableindex(function(t,k) -- we already have this somewhere
+ local v = k < 256 and f_hex_2(k) or "00"
+ t[k] = v
+ return v
+ end)
+
+ local trace_threshold = false trackers.register("backends.pdf.threshold", function(v) trace_threshold = v end)
+
+ flushcharacter = function(current,pos_h,pos_v,pos_r,font,char,data,f,e,factor) -- ,naturalwidth,width)
+ if need_tf or font ~= f_cur or f_pdf ~= f_pdf_cur or fs ~= fs_cur or mode == "page" then
+ pdf_goto_textmode()
+ setup_fontparameters(font,factor,f,e)
+ set_font()
+ elseif cur_tmrx ~= tmrx or cur_factor ~= factor or cur_f ~= f or cur_e ~= e then
+ setup_fontparameters(font,factor,f,e)
+ need_tm = true
+ end
+ local move = calc_pdfpos(pos_h,pos_v)
+
+ -- if trace_threshold then
+ -- report(
+ -- "font %i, char %C, factor %i, naturalwidth %p, move %l, tm %l, hpos %p, delta %p, threshold %p, cw %p",
+ -- font,char,factor,naturalwidth[char],move,need_tm,pos_h,tj_delta,threshold,cw
+ -- )
+ -- end
+
+ if move or need_tm then
+ if not need_tm then
+ if horizontalmode then
+ if (saved_text_pos_v + tmty) ~= pdf_v then
+ need_tm = true
+ elseif tj_delta >= threshold or tj_delta <= -threshold then
+ need_tm = true
+ end
+ else
+ if (saved_text_pos_h + tmtx) ~= pdf_h then
+ need_tm = true
+ elseif tj_delta >= threshold or tj_delta <= -threshold then
+ need_tm = true
+ end
+ end
+ end
+ if need_tm then
+ pdf_goto_textmode()
+ set_textmatrix(pos_h,pos_v)
+ begin_chararray()
+ move = calc_pdfpos(pos_h,pos_v)
+ end
+ if move then
+ local d = tj_delta * scalefactor
+ if d <= -0.5 or d >= 0.5 then
+ if mode == "char" then
+ end_charmode()
+ end
+ b = b + 1 ; buffer[b] = round(d) -- or f_skip(d)
+ end
+ cw = cw - tj_delta
+ end
+ end
+
+ if mode == "chararray" then
+ begin_charmode()
+ end
+
+ -- cw = cw + naturalwidth
+ -- cw = cw + width
+ cw = cw + naturalwidth[char]
+
+ local index = data.index or char
+
+ b = b + 1 ; buffer[b] = font > 0 and h_hex_4[index] or h_hex_2[index]
+
+ if not pdfcharacters[index] then
+ pdfcharacters[index] = true
+ end
+
+ end
+
+ flushfontchar = function(font,char,data)
+ local dummy = usedfonts[font]
+ local index = data.index or char
+ if not pdfcharacters[index] then
+ pdfcharacters[index] = true
+ end
+ return dummy
+ end
+
+end
+
+-- literals
+
+local flushliteral do
+
+ local nodeproperties <const> = nodes.properties.data
+ local literalvalues <const> = nodes.literalvalues
+
+ local originliteral_code <const> = literalvalues.origin
+ local pageliteral_code <const> = literalvalues.page
+ local alwaysliteral_code <const> = literalvalues.always
+ local rawliteral_code <const> = literalvalues.raw
+ local textliteral_code <const> = literalvalues.text
+ local fontliteral_code <const> = literalvalues.font
+
+ flushliteral = function(current,pos_h,pos_v,mode,str)
+ if mode then
+ if not str then
+ mode, str = originliteral_code, mode
+ elseif mode == "mode" then
+ mode = literalvalues[str]
+ if mode == originliteral_code then
+ pdf_goto_pagemode()
+ pdf_set_pos(pos_h,pos_v)
+ elseif mode == pageliteral_code then
+ pdf_goto_pagemode()
+ elseif mode == textliteral_code then
+ pdf_goto_textmode()
+ elseif mode == fontliteral_code then
+ pdf_goto_fontmode()
+ elseif mode == alwaysliteral_code then
+ pdf_end_string_nl()
+ need_tm = true
+ elseif mode == rawliteral_code then
+ pdf_end_string_nl()
+ end
+ return
+ else
+ mode = literalvalues[mode]
+ end
+ else
+ local p = nodeproperties[current]
+ if p then
+ str = p.data
+ mode = p.mode
+ else
+ str, mode = getdata(current)
+ end
+ end
+ if str and str ~= "" then
+ if mode == originliteral_code then
+ pdf_goto_pagemode()
+ pdf_set_pos(pos_h,pos_v)
+ elseif mode == pageliteral_code then
+ pdf_goto_pagemode()
+ elseif mode == textliteral_code then
+ pdf_goto_textmode()
+ elseif mode == fontliteral_code then
+ pdf_goto_fontmode()
+ elseif mode == alwaysliteral_code then
+ pdf_end_string_nl()
+ need_tm = true
+ elseif mode == rawliteral_code then
+ pdf_end_string_nl()
+ else
+ report("check literal")
+ pdf_goto_pagemode()
+ pdf_set_pos(pos_h,pos_v)
+ end
+ b = b + 1 ; buffer[b] = str
+ end
+ end
+
+ updaters.register("backend.update.pdf",function()
+ function pdf.print(mode,str)
+ if str then
+ mode = literalvalues[mode]
+ else
+ mode, str = originliteral_code, mode
+ end
+ if str and str ~= "" then
+ if mode == originliteral_code then
+ pdf_goto_pagemode()
+ -- pdf_set_pos(pdf_h,pdf_v)
+ elseif mode == pageliteral_code then
+ pdf_goto_pagemode()
+ elseif mode == textliteral_code then
+ pdf_goto_textmode()
+ elseif mode == fontliteral_code then
+ pdf_goto_fontmode()
+ elseif mode == alwaysliteral_code then
+ pdf_end_string_nl()
+ need_tm = true
+ elseif mode == rawliteral_code then
+ pdf_end_string_nl()
+ else
+ pdf_goto_pagemode()
+ -- pdf_set_pos(pdf_h,pdf_v)
+ end
+ b = b + 1 ; buffer[b] = str
+ end
+ end
+ end)
+
+end
+
+-- grouping & orientation
+
+local flushsave, flushrestore, flushsetmatrix do
+
+ local matrices = { }
+ local positions = { }
+ local nofpositions = 0
+ local nofmatrices = 0
+
+ local f_matrix = formatters["%s 0 0 cm"]
+
+ flushsave = function(current,pos_h,pos_v)
+ nofpositions = nofpositions + 1
+ positions[nofpositions] = { pos_h, pos_v, nofmatrices }
+ pdf_goto_pagemode()
+ pdf_set_pos(pos_h,pos_v)
+ b = b + 1 ; buffer[b] = "q"
+ end
+
+ flushrestore = function(current,pos_h,pos_v)
+ if nofpositions < 1 then
+ return
+ end
+ local t = positions[nofpositions]
+ -- local h = pos_h - t[1]
+ -- local v = pos_v - t[2]
+ if shippingmode == "page" then
+ nofmatrices = t[3]
+ end
+ pdf_goto_pagemode()
+ pdf_set_pos(pos_h,pos_v)
+ b = b + 1 ; buffer[b] = "Q"
+ nofpositions = nofpositions - 1
+ end
+
+ local function pdf_set_matrix(str,pos_h,pos_v)
+ if shippingmode == "page" then
+ local rx, sx, sy, ry = splitupstring(str," ")
+ if rx and ry and sx and ry then
+ rx, sx, sy, ry = tonumber(rx), tonumber(sx), tonumber(sy), tonumber(ry)
+ local tx = pos_h * (1 - rx) - pos_v * sy
+ local ty = pos_v * (1 - ry) - pos_h * sx
+ if nofmatrices > 1 then
+ local t = matrices[nofmatrices]
+ local r_x, s_x, s_y, r_y, te, tf = t[1], t[2], t[3], t[4], t[5], t[6]
+ rx, sx = rx * r_x + sx * s_y, rx * s_x + sx * r_y
+ sy, ry = sy * r_x + ry * s_y, sy * s_x + ry * r_y
+ tx, ty = tx * r_x + ty * s_y, tx * s_x + ty * r_y
+ end
+ nofmatrices = nofmatrices + 1
+ matrices[nofmatrices] = { rx, sx, sy, ry, tx, ty }
+ end
+ end
+ end
+
+ local nodeproperties = nodes.properties.data
+
+ flushsetmatrix = function(current,pos_h,pos_v)
+ local str
+ if type(current) == "string" then
+ str = current
+ else
+ local p = nodeproperties[current]
+ if p then
+ str = p.matrix
+ else
+ str = getdata(current) -- for the moment
+ end
+ end
+ if str and str ~= "" then
+ pdf_set_matrix(str,pos_h,pos_v)
+ pdf_goto_pagemode()
+ pdf_set_pos(pos_h,pos_v)
+ b = b + 1 ; buffer[b] = f_matrix(str)
+ end
+ end
+
+ do
+
+ local function hasmatrix()
+ return nofmatrices > 0
+ end
+
+ local function getmatrix()
+ if nofmatrices > 0 then
+ return unpack(matrices[nofmatrices])
+ else
+ return 1, 0, 0, 1, 0, 0
+ end
+ end
+
+ updaters.register("backend.update.pdf",function()
+ pdf.hasmatrix = hasmatrix
+ pdf.getmatrix = getmatrix
+ end)
+
+ end
+
+ pushorientation = function(orientation,pos_h,pos_v,pos_r)
+ pdf_goto_pagemode()
+ pdf_set_pos(pos_h,pos_v)
+ b = b + 1 ; buffer[b] = "q"
+ if orientation == 1 then
+ b = b + 1 ; buffer[b] = "0 -1 1 0 0 0 cm" -- 90
+ elseif orientation == 2 then
+ b = b + 1 ; buffer[b] = "-1 0 0 -1 0 0 cm" -- 180
+ elseif orientation == 3 then
+ b = b + 1 ; buffer[b] = "0 1 -1 0 0 0 cm" -- 270
+ end
+ end
+
+ poporientation = function(orientation,pos_h,pos_v,pos_r)
+ pdf_goto_pagemode()
+ pdf_set_pos(pos_h,pos_v)
+ b = b + 1 ; buffer[b] = "Q"
+ end
+
+ -- pushorientation = function(orientation,pos_h,pos_v,pos_r)
+ -- flushsave(false,pos_h,pos_v)
+ -- if orientation == 1 then
+ -- flushsetmatrix("0 -1 1 0",pos_h,pos_v)
+ -- elseif orientation == 2 then
+ -- flushsetmatrix("-1 0 0 -1",pos_h,pos_v)
+ -- elseif orientation == 3 then
+ -- flushsetmatrix("0 1 -1 0",pos_h,pos_v)
+ -- end
+ -- end
+
+ -- poporientation = function(orientation,pos_h,pos_v,pos_r)
+ -- flushrestore(false,pos_h,pos_v)
+ -- end
+
+end
+
+-- rules
+
+local flushedxforms = { } -- actually box resources but can also be direct
+local localconverter = nil -- will be set
+
+local flushrule, flushsimplerule, flushimage, flushgroup do
+
+ local rulecodes = nodes.rulecodes
+ local newrule = nodes.pool.rule
+
+ local setprop = nuts.setprop
+ local getprop = nuts.getprop
+
+ local normalrule_code <const> = rulecodes.normal
+ local boxrule_code <const> = rulecodes.box
+ local imagerule_code <const> = rulecodes.image
+ local emptyrule_code <const> = rulecodes.empty
+ local userrule_code <const> = rulecodes.user
+ local overrule_code <const> = rulecodes.over
+ local underrule_code <const> = rulecodes.under
+ local fractionrule_code <const> = rulecodes.fraction
+ local radicalrule_code <const> = rulecodes.radical
+ local outlinerule_code <const> = rulecodes.outline
+
+ local rule_callback = callbacks.functions.process_rule
+
+ local f_fm = formatters["/Fm%d Do"]
+ local f_im = formatters["/Im%d Do"]
+ local f_gr = formatters["/Gp%d Do"]
+
+ local s_b <const> = "q"
+ local s_e <const> = "Q"
+
+ local f_v = formatters["[] 0 d 0 J %.6N w 0 0 m %.6N 0 l S"]
+ local f_h = formatters["[] 0 d 0 J %.6N w 0 0 m 0 %.6N l S"]
+
+ local f_f = formatters["0 0 %.6N %.6N re f"]
+ local f_o = formatters["[] 0 d 0 J 0 0 %.6N %.6N re S"]
+ local f_w = formatters["[] 0 d 0 J %.6N w 0 0 %.6N %.6N re S"]
+
+ -- Historically the index is an object which is kind of bad.
+
+ local boxresources, n = { }, 0
+
+ getxformname = function(index)
+ local l = boxresources[index]
+ if l then
+ return l.name
+ else
+ report("no box resource %S",index)
+ end
+ end
+
+ updaters.register("backend.update.pdf",function()
+ pdf.getxformname = getxformname
+ end)
+
+ local function saveboxresource(box,attributes,resources,immediate,kind,margin)
+ n = n + 1
+ local immediate = true
+ local margin = margin or 0 -- or dimension
+ local objnum = pdfreserveobject()
+ local list = tonut(type(box) == "number" and tex.takebox(box) or box)
+ --
+ local width, height, depth = getwhd(list)
+ --
+ local l = {
+ width = width,
+ height = height,
+ depth = depth,
+ margin = margin,
+ attributes = attributes,
+ resources = resources,
+ list = nil,
+ type = kind,
+ name = n,
+ index = objnum,
+ objnum = objnum,
+ }
+ boxresources[objnum] = l
+ if immediate then
+ localconverter(list,"xform",objnum,l)
+ flushedxforms[objnum] = { true , objnum }
+ flushlist(list)
+ else
+ l.list = list
+ end
+ return objnum
+ end
+
+ local function useboxresource(index,wd,ht,dp)
+ local l = boxresources[index]
+ if l then
+ if wd or ht or dp then
+ wd, ht, dp = wd or 0, ht or 0, dp or 0
+ else
+ wd, ht, dp = l.width, l.height, l.depth
+ end
+ local rule = newrule(wd,ht,dp) -- newboxrule
+ rule.subtype = boxrule_code
+ setprop(tonut(rule),"index",index)
+ return rule, wd, ht, dp
+ else
+ report("no box resource %S",index)
+ end
+ end
+
+ local function getboxresourcedimensions(index)
+ local l = boxresources[index]
+ if l then
+ return l.width, l.height, l.depth, l.margin
+ else
+ report("no box resource %S",index)
+ end
+ end
+
+ local function getboxresourcebox(index)
+ local l = boxresources[index]
+ if l then
+ return l.list
+ end
+ end
+
+ updaters.register("backend.update.tex",function()
+ tex.saveboxresource = saveboxresource
+ tex.useboxresource = useboxresource
+ tex.getboxresourcedimensions = getboxresourcedimensions
+ tex.getboxresourcebox = getboxresourcebox
+ end)
+
+ -- a bit of a mess: index is now objnum but that has to change to a proper index
+ -- ... an engine inheritance
+
+ local function flushpdfxform(current,pos_h,pos_v,pos_r,size_h,size_v)
+ -- object properties
+ local objnum = getprop(current,"index")
+ local name = getxformname(objnum)
+ local info = flushedxforms[objnum]
+ local r = boxresources[objnum]
+ if not info then
+ info = { false , objnum }
+ flushedxforms[objnum] = info
+ end
+ local wd, ht, dp = getboxresourcedimensions(objnum)
+ -- or: wd, ht, dp = r.width, r.height, r.depth
+ -- sanity check
+ local htdp = ht + dp
+ if wd == 0 or size_h == 0 or htdp == 0 or size_v == 0 then
+ return
+ end
+ -- calculate scale
+ local rx, ry = 1, 1
+ if wd ~= size_h or htdp ~= size_v then
+ rx = size_h / wd
+ ry = size_v / htdp
+ end
+ -- flush the reference
+ usedxforms[objnum] = true
+ pdf_goto_pagemode()
+ calc_pdfpos(pos_h,pos_v)
+ tx = cmtx * bpfactor
+ ty = cmty * bpfactor
+ b = b + 1 ; buffer[b] = s_b
+ b = b + 1 ; buffer[b] = f_cm(rx,0,0,ry,tx,ty)
+ b = b + 1 ; buffer[b] = f_fm(name)
+ b = b + 1 ; buffer[b] = s_e
+ end
+
+ -- place image also used in vf but we can use a different one if we need it
+
+ local imagetypes = images.types -- pdf png jpg jp2 jbig2 stream memstream
+ local img_none = imagetypes.none
+ local img_pdf = imagetypes.pdf
+ local img_stream = imagetypes.stream
+ local img_memstream = imagetypes.memstream
+
+ local one_bp <const> = 65536 * bpfactor
+
+ local imageresources, n = { }, 0
+
+ getximagename = function(index)
+ local l = imageresources[index]
+ if l then
+ return l.name
+ else
+ report("no image resource %S",index)
+ end
+ end
+
+ updaters.register("backend.update.pdf",function()
+ pdf.getximagename = getximagename
+ end)
+
+ -- Groups are flushed immediately but we can decide to make them into a
+ -- specific whatsit ... but not now. We could hash them if needed when
+ -- we use lot sof them in mp ... but not now.
+
+ usedxgroups = { }
+ local groups = 0
+ local group = nil
+
+ flushgroup = function(content,bbox)
+ if not group then
+ group = pdfdictionary {
+ Type = pdfconstant("Group"),
+ S = pdfconstant("Transparency"),
+ }
+ end
+ local wrapper = pdfdictionary {
+ Type = pdf_xobject,
+ Subtype = pdf_form,
+ FormType = 1,
+ Group = group,
+ BBox = pdfarray(bbox),
+ Resources = lpdf.collectedresources { serialize = false },
+ }
+ local objnum = pdfflushstreamobject(content,wrapper,false)
+ groups = groups + 1
+ usedxgroups[groups] = objnum
+ return f_gr(groups)
+ end
+
+ lpdf.flushgroup = flushgroup -- todo: access via driver in mlib-pps
+
+ -- end of experiment
+
+ local function flushpdfximage(current,pos_h,pos_v,pos_r,size_h,size_v)
+
+ local width,
+ height,
+ depth = getwhd(current)
+ local total = height + depth
+ local transform = getprop(current,"transform") or 0 -- we never set it ... so just use rotation then
+ local index = getprop(current,"index") or 0
+ local kind,
+ xorigin,
+ yorigin,
+ xsize,
+ ysize,
+ rotation, -- transform / orientation / rotation : it's a mess (i need to redo this)
+ objnum,
+ groupref = pdfincludeimage(index) -- needs to be sorted out, bad name (no longer mixed anyway)
+
+ if not kind then
+ report("invalid image %S",index)
+ return
+ end
+
+ local rx, sx, sy, ry, tx, ty = 1, 0, 0, 1, 0, 0
+
+ -- tricky: xsize and ysize swapped
+
+ if kind == img_pdf or kind == img_stream or kind == img_memstream then
+ rx, ry, tx, ty = 1/xsize, 1/ysize, xorigin/xsize, yorigin/ysize
+ else
+ -- if kind == img_png then
+ -- -- if groupref > 0 and img_page_group_val == 0 then
+ -- -- img_page_group_val = groupref
+ -- -- end
+ -- end
+ rx, ry = bpfactor, bpfactor
+ end
+
+ if band(transform,7) > 3 then
+ -- mirror
+ rx, tx = -rx, -tx
+ end
+ local t = band(transform + rotation,3)
+ if t == 0 then
+ -- nothing
+ elseif t == 1 then
+ -- rotation over 90 degrees (counterclockwise)
+ rx, sx, sy, ry, tx, ty = 0, rx, -ry, 0, -ty, tx
+ elseif t == 2 then
+ -- rotation over 180 degrees (counterclockwise)
+ rx, ry, tx, ty = -rx, -ry, -tx, -ty
+ elseif t == 3 then
+ -- rotation over 270 degrees (counterclockwise)
+ rx, sx, sy, ry, tx, ty = 0, -rx, ry, 0, ty, -tx
+ end
+
+ rx = rx * width
+ sx = sx * total
+ sy = sy * width
+ ry = ry * total
+ tx = pos_h - tx * width
+ ty = pos_v - ty * total
+
+ local t = transform + rotation
+
+ if band(transform,7) > 3 then
+ t = t + 1
+ end
+
+ t = band(t,3)
+
+ if t == 0 then
+ -- no transform
+ elseif t == 1 then
+ -- rotation over 90 degrees (counterclockwise)
+ tx = tx + width
+ elseif t == 2 then
+ -- rotation over 180 degrees (counterclockwise)
+ tx = tx + width
+ ty = ty + total
+ elseif t == 3 then
+ -- rotation over 270 degrees (counterclockwise)
+ ty = ty + total
+ end
+
+ -- a flaw in original, can go:
+ --
+ -- if img_page_group_val == 0 then
+ -- img_page_group_val = group_ref
+ -- end
+
+ usedximages[index] = objnum -- hm
+
+ pdf_goto_pagemode()
+
+ calc_pdfpos(tx,ty)
+
+ tx = cmtx * bpfactor
+ ty = cmty * bpfactor
+
+ b = b + 1 ; buffer[b] = s_b
+ b = b + 1 ; buffer[b] = f_cm(rx,sx,sy,ry,tx,ty)
+ b = b + 1 ; buffer[b] = f_im(index)
+ b = b + 1 ; buffer[b] = s_e
+ end
+
+ flushimage = function(index,width,height,depth,pos_h,pos_v)
+
+ -- used in vf characters
+
+ local total = height + depth
+ local kind,
+ xorigin, yorigin,
+ xsize, ysize,
+ rotation,
+ objnum,
+ groupref = pdfincludeimage(index)
+
+ local rx = width / xsize
+ local sx = 0
+ local sy = 0
+ local ry = total / ysize
+ local tx = pos_h
+ -- to be sorted out
+ -- local ty = pos_v - depth
+ local ty = pos_v -- we assume that depth is dealt with in the caller (for now)
+
+ usedximages[index] = objnum
+
+ pdf_goto_pagemode()
+
+ calc_pdfpos(tx,ty)
+
+ tx = cmtx * bpfactor
+ ty = cmty * bpfactor
+
+ b = b + 1 ; buffer[b] = s_b
+ b = b + 1 ; buffer[b] = f_cm(rx,sx,sy,ry,tx,ty)
+ b = b + 1 ; buffer[b] = f_im(index)
+ b = b + 1 ; buffer[b] = s_e
+ end
+
+ -- For the moment we need this hack because the engine checks the 'image'
+ -- command in virtual fonts (so we use lua instead).
+
+ flushrule = function(current,pos_h,pos_v,pos_r,size_h,size_v,subtype)
+
+ if subtype == emptyrule_code then
+ return
+ elseif subtype == boxrule_code then
+ return flushpdfxform(current,pos_h,pos_v,pos_r,size_h,size_v)
+ elseif subtype == imagerule_code then
+ return flushpdfximage(current,pos_h,pos_v,pos_r,size_h,size_v)
+ end
+ if subtype == userrule_code or subtype >= overrule_code and subtype <= radicalrule_code then
+ pdf_goto_pagemode()
+ b = b + 1 ; buffer[b] = s_b
+ pdf_set_pos_temp(pos_h,pos_v)
+ rule_callback(current,size_h,size_v,pos_r) -- so we pass direction
+ b = b + 1 ; buffer[b] = s_e
+ return
+ end
+
+ pdf_goto_pagemode()
+
+ -- local saved_b = b
+
+ b = b + 1 ; buffer[b] = s_b
+
+ local dim_h = size_h * bpfactor
+ local dim_v = size_v * bpfactor
+ local rule
+
+ if dim_v <= one_bp then
+ pdf_set_pos_temp(pos_h,pos_v + 0.5 * size_v)
+ rule = f_v(dim_v,dim_h)
+ elseif dim_h <= one_bp then
+ pdf_set_pos_temp(pos_h + 0.5 * size_h,pos_v)
+ rule = f_h(dim_h,dim_v)
+ else
+ pdf_set_pos_temp(pos_h,pos_v)
+ if subtype == outlinerule_code then
+ local linewidth = getdata(current)
+ if linewidth > 0 then
+ rule = f_w(linewidth * bpfactor,dim_h,dim_v)
+ else
+ rule = f_o(dim_h,dim_v)
+ end
+ else
+ rule = f_f(dim_h,dim_v)
+ end
+ end
+
+ b = b + 1 ; buffer[b] = rule
+ b = b + 1 ; buffer[b] = s_e
+
+ -- buffer[saved_b] = concat(buffer," ",saved_b,b)
+ -- b = saved_b
+
+ end
+
+ flushsimplerule = function(pos_h,pos_v,pos_r,size_h,size_v)
+ pdf_goto_pagemode()
+
+ b = b + 1 ; buffer[b] = s_b
+
+ local dim_h = size_h * bpfactor
+ local dim_v = size_v * bpfactor
+ local rule
+
+ if dim_v <= one_bp then
+ pdf_set_pos_temp(pos_h,pos_v + 0.5 * size_v)
+ rule = f_v(dim_v,dim_h)
+ elseif dim_h <= one_bp then
+ pdf_set_pos_temp(pos_h + 0.5 * size_h,pos_v)
+ rule = f_h(dim_h,dim_v)
+ else
+ pdf_set_pos_temp(pos_h,pos_v)
+ rule = f_f(dim_h,dim_v)
+ end
+
+ b = b + 1 ; buffer[b] = rule
+ b = b + 1 ; buffer[b] = s_e
+ end
+
+end
+
+--- basics
+
+local wrapup, registerpage do
+
+ local pages = { }
+ local maxkids = 10
+ local nofpages = 0
+ local pagetag = "unset"
+
+ registerpage = function(object)
+ nofpages = nofpages + 1
+ local objnum = pdfpagereference(nofpages)
+ pages[nofpages] = {
+ page = nofpages, -- original number, only for diagnostics
+ objnum = objnum,
+ object = object,
+ tag = pagetag,
+ }
+ end
+
+ function lpdf.setpagetag(tag)
+ pagetag = tag or "unset"
+ end
+
+ function lpdf.getnofpages()
+ return nofpages
+ end
+
+ function lpdf.getpagetags()
+ local list = { }
+ for i=1,nofpages do
+ list[i] = pages[i].tag
+ end
+ return list
+ end
+
+ function lpdf.setpageorder(mapping)
+ -- mapping can be a hash so:
+ local list = table.sortedkeys(mapping)
+ local n = #list
+ if n == nofpages then
+ local done = { }
+ local hash = { }
+ for i=1,n do
+ local order = mapping[list[i]]
+ if hash[order] then
+ report("invalid page order, duplicate entry %i",order)
+ return
+ elseif order < 1 or order > nofpages then
+ report("invalid page order, no page %i",order)
+ return
+ else
+ done[i] = pages[order]
+ hash[order] = true
+ end
+ end
+ pages = done
+ else
+ report("invalid page order, %i entries expected",nofpages)
+ end
+ end
+
+ -- We can have this, but then via codeinjections etc. Later.
+
+ -- function structures.pages.swapthem()
+ -- local n = lpdf.getnofpages()
+ -- local t = { }
+ -- for i=1,n do
+ -- t[i] = i
+ -- end
+ -- for i=2,math.odd(n) and n or (n-1),2 do
+ -- t[i] = i+1
+ -- t[i+1] = i
+ -- end
+ -- lpdf.setpageorder(t)
+ -- end
+
+ wrapup = function(driver)
+
+ -- hook (to reshuffle pages)
+ local pagetree = { }
+ local parent = nil
+ local minimum = 0
+ local maximum = 0
+ local current = 0
+ if #pages > 1.5 * maxkids then
+ repeat
+ local plist, pnode
+ if current == 0 then
+ plist, minimum = pages, 1
+ elseif current == 1 then
+ plist, minimum = pagetree, 1
+ else
+ plist, minimum = pagetree, maximum + 1
+ end
+ maximum = #plist
+ if maximum > minimum then
+ local kids
+ for i=minimum,maximum do
+ local p = plist[i]
+ if not pnode or #kids == maxkids then
+ kids = pdfarray()
+ parent = pdfreserveobject()
+ pnode = pdfdictionary {
+ objnum = parent,
+ Type = pdf_pages,
+ Kids = kids,
+ Count = 0,
+ }
+ pagetree[#pagetree+1] = pnode
+ end
+ kids[#kids+1] = pdfreference(p.objnum)
+ pnode.Count = pnode.Count + (p.Count or 1)
+ p.Parent = pdfreference(parent)
+ end
+ end
+ current = current + 1
+ until maximum == minimum
+ -- flush page tree
+ for i=1,#pagetree do
+ local entry = pagetree[i]
+ local objnum = entry.objnum
+ entry.objnum = nil
+ pdfflushobject(objnum,entry)
+ end
+ else
+ -- ugly
+ local kids = pdfarray()
+ local list = pdfdictionary {
+ Type = pdf_pages,
+ Kids = kids,
+ Count = nofpages,
+ }
+ parent = pdfreserveobject()
+ for i=1,nofpages do
+ local page = pages[i]
+ kids[#kids+1] = pdfreference(page.objnum)
+ page.Parent = pdfreference(parent)
+ end
+ pdfflushobject(parent,list)
+ end
+ for i=1,nofpages do
+ local page = pages[i]
+ local object = page.object
+ object.Parent = page.Parent
+ pdfflushobject(page.objnum,object)
+ end
+ lpdf.addtocatalog("Pages",pdfreference(parent))
+
+ end
+
+end
+
+pdf_h, pdf_v = 0, 0
+
+local function initialize(driver,details)
+ reset_variables(details)
+ reset_buffer()
+end
+
+-- This will all move and be merged and become less messy.
+
+-- todo: more clever resource management: a bit tricky as we can inject
+-- stuff in the page stream
+
+local compact = false
+
+do
+
+ -- This is more a convenience feature and it might even be not entirely robust.
+ -- It removes redundant color directives which makes the page stream look a bit
+ -- nicer (also when figuring out issues). I might add more here but there is
+ -- some additional overhead involved so runtime can be impacted.
+
+ local P, R, S, Cs, lpegmatch = lpeg.P, lpeg.R, lpeg.S, lpeg.Cs, lpeg.match
+
+ local p_ds = (R("09") + S(" ."))^1
+ ----- p_nl = S("\n\r")^1
+ local p_nl = S("\n")^1
+ local p_eg = P("Q")
+
+ local p_cl = p_ds * (P("rg") + P("g") + P("k")) * p_ds * (P("RG") + P("G") + P("K"))
+ ----- p_cl = (p_ds * (P("rg") + P("g") + P("k") + P("RG") + P("G") + P("K")))^1
+ local p_tr = P("/Tr") * p_ds * P("gs")
+
+ local p_no_cl = (p_cl * p_nl) / ""
+ local p_no_tr = (p_tr * p_nl) / ""
+ local p_no_nl = 1 - p_nl
+
+ local p_do_cl = p_cl * p_nl
+ local p_do_tr = p_tr * p_nl
+
+ local p_do_eg = p_eg * p_nl
+
+ local pattern = Cs( (
+ (p_no_cl + p_no_tr)^0 * p_do_eg -- transparencies and colors before Q
+ + p_no_tr * p_no_cl * p_do_tr * p_do_cl -- transparencies and colors before others
+ + p_no_cl * p_do_cl -- successive colors
+ + p_no_tr * p_do_tr -- successive transparencies
+ + p_no_nl^1
+ + 1
+ )^1 )
+
+ local oldsize = 0
+ local newsize = 0
+
+ directives.register("pdf.compact", function(v)
+ compact = v and function(s)
+ oldsize = oldsize + #s
+ s = lpegmatch(pattern,s) or s
+ newsize = newsize + #s
+ return s
+ end
+ end)
+
+ statistics.register("pdf pagestream",function()
+ if oldsize ~= newsize then
+ return string.format("old size: %i, new size %i",oldsize,newsize)
+ end
+ end)
+
+
+end
+
+local flushdeferred -- defined later
+
+local level = 0
+
+local finalize do
+
+ local f_font = formatters["F%d"]
+
+ local f_form = formatters["Fm%d"]
+ local f_group = formatters["Gp%d"]
+ local f_image = formatters["Im%d"]
+
+ finalize = function(driver,details)
+
+ level = level + 1
+
+ pdf_goto_pagemode() -- for now
+
+ local objnum = details.objnum
+ local specification = details.specification
+
+ local content = concat(buffer,"\n",1,b)
+
+ if compact then
+ content = compact(content)
+ end
+
+ local fonts = nil
+ local xforms = nil
+
+ if next(usedfonts) then
+ fonts = pdfdictionary { }
+ for k, v in next, usedfonts do
+ fonts[f_font(v)] = pdfreference(pdfgetfontobjnumber(k)) -- we can overload for testing
+ end
+ end
+
+ -- messy: use real indexes for both ... so we need to change some in the
+ -- full luatex part
+
+ if next(usedxforms) or next(usedximages) or next(usedxgroups) then
+ xforms = pdfdictionary { }
+ for k in sortedhash(usedxforms) do
+ -- xforms[f_form(k)] = pdfreference(k)
+ xforms[f_form(getxformname(k))] = pdfreference(k)
+ end
+ for k, v in sortedhash(usedximages) do
+ xforms[f_image(k)] = pdfreference(v)
+ end
+ for k, v in sortedhash(usedxgroups) do
+ xforms[f_group(k)] = pdfreference(v)
+ end
+ end
+
+ reset_buffer()
+
+ -- finish_pdfpage_callback(shippingmode == "page")
+
+ if shippingmode == "page" then
+
+ local pageproperties = lpdf.getpageproperties()
+
+ local pageresources = pageproperties.pageresources
+ local pageattributes = pageproperties.pageattributes
+ local pagesattributes = pageproperties.pagesattributes
+
+ pageresources.Font = fonts
+ pageresources.XObject = xforms
+ pageresources.ProcSet = lpdf.procset()
+
+ local xorigin, yorigin, relocated = backends.codeinjections.getpageorigin() -- for now here
+
+ local bbox = pdfarray {
+ (boundingbox[1] + xorigin) * bpfactor,
+ (boundingbox[2] + yorigin) * bpfactor,
+ (boundingbox[3] + xorigin) * bpfactor,
+ (boundingbox[4] + yorigin) * bpfactor,
+ }
+
+ if relocated then
+ content = formatters["1 0 0 1 %.6N %.6N cm\n%s"](bbox[1],bbox[2],content)
+ end
+
+ local contentsobj = pdfflushstreamobject(content,false,false)
+
+ pageattributes.Type = pdf_page
+ pageattributes.Contents = pdfreference(contentsobj)
+ pageattributes.Resources = pageresources
+ -- pageattributes.Resources = pdfreference(pdfflushobject(pageresources))
+ pageattributes.MediaBox = bbox
+ pageattributes.Parent = nil -- precalculate
+ pageattributes.Group = nil -- todo
+
+ -- resources can be indirect
+
+ registerpage(pageattributes)
+
+ lpdf.finalizepage(true)
+
+ if relocated then
+ if pageattributes.TrimBox then pageattributes.TrimBox = box end
+ if pageattributes.CropBox then pageattributes.CropBox = box end
+ if pageattributes.BleedBox then pageattributes.BleedBox = box end
+ end
+
+ else
+
+ local xformtype = specification.type or 0
+ local margin = specification.margin or 0
+ local attributes = specification.attributes or ""
+ local resources = specification.resources or ""
+
+ local wrapper = nil
+
+ if xformtype == 0 then
+ wrapper = pdfdictionary {
+ Type = pdf_xobject,
+ Subtype = pdf_form,
+ FormType = 1,
+ BBox = nil,
+ Matrix = nil,
+ Resources = nil,
+ }
+ else
+ wrapper = pdfdictionary {
+ BBox = nil,
+ Matrix = nil,
+ Resources = nil,
+ }
+ end
+ if xformtype == 0 or xformtype == 1 or xformtype == 3 then
+ wrapper.BBox = pdfarray {
+ -margin * bpfactor,
+ -margin * bpfactor,
+ (boundingbox[3] + margin) * bpfactor,
+ (boundingbox[4] + margin) * bpfactor,
+ }
+ end
+ if xformtype == 0 or xformtype == 2 or xformtype == 3 then
+ wrapper.Matrix = pdfarray { 1, 0, 0, 1, 0, 0 }
+ end
+
+ -- todo: additional = resources
+
+ local boxresources = lpdf.collectedresources { serialize = false }
+ boxresources.Font = fonts
+ boxresources.XObject = xforms
+
+ -- todo: maybe share them
+ -- wrapper.Resources = pdfreference(pdfflushobject(boxresources))
+
+ if resources ~= "" then
+ boxresources = boxresources + resources
+ end
+ if attributes ~= "" then
+ wrapper = wrapper + attributes
+ end
+
+ wrapper.Resources = next(boxresources) and boxresources or nil
+ wrapper.ProcSet = lpdf.procset()
+
+ -- pdfflushstreamobject(content,wrapper,false,objectnumber)
+ pdfflushstreamobject(content,wrapper,false,specification.objnum)
+
+ end
+
+ for objnum in sortedhash(usedxforms) do
+ local f = flushedxforms[objnum]
+ if f[1] == false then
+ f[1] = true
+ local objnum = f[2] -- specification.objnum
+ local specification = boxresources[objnum]
+ local list = specification.list
+ localconverter(list,"xform",f[2],specification)
+ end
+ end
+
+ pdf_h, pdf_v = 0, 0
+
+ if level == 1 then
+ flushdeferred()
+ end
+ level = level - 1
+
+ end
+
+end
+
+updaters.register("backend.update.pdf",function()
+ job.positions.registerhandlers {
+ getpos = drivers.getpos,
+ getrpos = drivers.getrpos,
+ gethpos = drivers.gethpos,
+ getvpos = drivers.getvpos,
+ }
+end)
+
+updaters.register("backend.update",function()
+ local saveboxresource = tex.boxresources.save
+ --
+ -- also in lpdf-res .. brrr .. needs fixing
+ --
+ backends.codeinjections.registerboxresource = function(n,offset)
+ local r = saveboxresource(n,nil,nil,false,0,offset or 0)
+ return r
+ end
+end)
+
+-- now comes the pdf file handling
+
+local objects = { }
+local streams = { } -- maybe just parallel to objects (no holes)
+local nofobjects = 0
+local offset = 0
+local f = false
+local flush = false
+local threshold = 40 -- also #("/Filter /FlateDecode") (compression threshold)
+local objectstream = true
+local compress = true
+local cache = false
+local info = ""
+local catalog = ""
+local lastdeferred = false
+local majorversion = 1
+local minorversion = 7
+local trailerid = true
+
+directives.register("backend.pdf.threshold",function(v)
+ if v then
+ threshold = tonumber(v) or 40
+ else
+ threshold = -1000
+ end
+end)
+
+local f_object = formatters["%i 0 obj\010%s\010endobj\010"]
+local f_stream_n_u = formatters["%i 0 obj\010<< /Length %i >>\010stream\010%s\010endstream\010endobj\010"]
+local f_stream_n_c = formatters["%i 0 obj\010<< /Filter /FlateDecode /Length %i >>\010stream\010%s\010endstream\010endobj\010"]
+local f_stream_d_u = formatters["%i 0 obj\010<< %s /Length %i >>\010stream\010%s\010endstream\010endobj\010"]
+local f_stream_d_c = formatters["%i 0 obj\010<< %s /Filter /FlateDecode /Length %i >>\010stream\010%s\010endstream\010endobj\010"]
+local f_stream_d_r = formatters["%i 0 obj\010<< %s >>\010stream\010%s\010endstream\010endobj\010"]
+
+----- f_object_b = formatters["%i 0 obj\010"]
+local f_stream_b_n_u = formatters["%i 0 obj\010<< /Length %i >>\010stream\010"]
+local f_stream_b_n_c = formatters["%i 0 obj\010<< /Filter /FlateDecode /Length %i >>\010stream\010"]
+local f_stream_b_d_u = formatters["%i 0 obj\010<< %s /Length %i >>\010stream\010"]
+local f_stream_b_d_c = formatters["%i 0 obj\010<< %s /Filter /FlateDecode /Length %i >>\010stream\010"]
+local f_stream_b_d_r = formatters["%i 0 obj\010<< %s >>\010stream\010"]
+
+----- s_object_e <const> = "\010endobj\010"
+local s_stream_e <const> = "\010endstream\010endobj\010"
+
+do
+
+ local function setinfo() end -- we get it
+ local function setcatalog() end -- we get it
+
+ local function settrailerid(v)
+ trailerid = v or false
+ end
+
+ local function setmajorversion(v) majorversion = tonumber(v) or majorversion end
+ local function setminorversion(v) minorversion = tonumber(v) or minorversion end
+
+ local function getmajorversion(v) return majorversion end
+ local function getminorversion(v) return minorversion end
+
+ local function setcompresslevel (v) compress = v and v ~= 0 and true or false end
+ local function setobjcompresslevel(v) objectstream = v and v ~= 0 and true or false end
+
+ local function getcompresslevel (v) return compress and 3 or 0 end
+ local function getobjcompresslevel(v) return objectstream and 1 or 0 end
+
+ local function setpageresources () end -- needs to be sorted out
+ local function setpageattributes () end
+ local function setpagesattributes() end
+
+ updaters.register("backend.update.pdf",function()
+ pdf.setinfo = setinfo
+ pdf.setcatalog = setcatalog
+ pdf.settrailerid = settrailerid
+ pdf.setmajorversion = setmajorversion
+ pdf.setminorversion = setminorversion
+ pdf.getmajorversion = getmajorversion
+ pdf.getminorversion = getminorversion
+ pdf.setcompresslevel = setcompresslevel
+ pdf.setobjcompresslevel = setobjcompresslevel
+ pdf.getcompresslevel = getcompresslevel
+ pdf.getobjcompresslevel = getobjcompresslevel
+ pdf.setpageresources = setpageresources
+ pdf.setpageattributes = setpageattributes
+ pdf.setpagesattributes = setpagesattributes
+ end)
+
+end
+
+local addtocache, flushcache, cache do
+
+ local data, d = { }, 0
+ local list, l = { }, 0
+ local coffset = 0
+ local indices = { }
+
+ local maxsize <const> = 32 * 1024 -- uncompressed
+ local maxcount <const> = 0xFF
+
+ addtocache = function(n,str)
+ local size = #str
+ if size == 0 then
+ -- todo: message
+ return
+ end
+ if coffset + size > maxsize or d == maxcount then
+ flushcache()
+ end
+ if d == 0 then
+ nofobjects = nofobjects + 1
+ objects[nofobjects] = false
+ streams[nofobjects] = indices
+ cache = nofobjects
+ end
+ objects[n] = - cache
+ indices[n] = d
+ d = d + 1
+ -- can have a comment n 0 obj as in luatex
+ data[d] = str
+ l = l + 1 ; list[l] = n
+ l = l + 1 ; list[l] = coffset
+ coffset = coffset + size + 1
+ end
+
+ local p_ObjStm = pdfconstant("ObjStm")
+
+ flushcache = function() -- references cannot be stored
+ if l > 0 then
+ list = concat(list," ")
+ data[0] = list
+ data = concat(data,"\010",0,d)
+ local strobj = pdfdictionary {
+ Type = p_ObjStm,
+ N = d,
+ First = #list + 1,
+ }
+ objects[cache] = offset
+ local b = nil
+ local e = s_stream_e
+ if compress then
+ local comp = zlibcompress(data,3)
+ if comp and #comp < #data then
+ data = comp
+ b = f_stream_b_d_c(cache,strobj(),#data)
+ else
+ b = f_stream_b_d_u(cache,strobj(),#data)
+ end
+ else
+ b = f_stream_b_d_u(cache,strobj(),#data)
+ end
+ flush(f,b)
+ flush(f,data)
+ flush(f,e)
+ offset = offset + #b + #data + #e
+ data, d = { }, 0
+ list, l = { }, 0
+ coffset = 0
+ indices = { }
+ end
+ end
+
+end
+
+local function pdfreserveobj()
+ nofobjects = nofobjects + 1
+ objects[nofobjects] = false
+ return nofobjects
+end
+
+local pages = table.setmetatableindex(function(t,k)
+ local v = pdfreserveobj()
+ t[k] = v
+ return v
+end)
+
+local function getpageref(n)
+ return pages[n]
+end
+
+local function refobj()
+ -- not needed, as we have auto-delay
+end
+
+local function flushnormalobj(data,n)
+ if not n then
+ nofobjects = nofobjects + 1
+ n = nofobjects
+ end
+ data = f_object(n,data)
+ if level == 0 then
+ objects[n] = offset
+ offset = offset + #data
+ flush(f,data)
+ else
+ if not lastdeferred then
+ lastdeferred = n
+ elseif n < lastdeferred then
+ lastdeferred = n
+ end
+ objects[n] = data
+ end
+ return n
+end
+
+local function flushstreamobj(data,n,dict,comp,nolength)
+ if not data then
+ report("no data for %S",dict)
+ return
+ end
+ if not n then
+ nofobjects = nofobjects + 1
+ n = nofobjects
+ end
+ local size = #data
+ if level == 0 then
+ local b = nil
+ local e = s_stream_e
+ if nolength then
+ b = f_stream_b_d_r(n,dict)
+ elseif comp ~= false and compress and size > threshold then
+ local compdata = zlibcompress(data,3)
+ if compdata then
+ local compsize = #compdata
+ if compsize > size - threshold then
+ b = dict and f_stream_b_d_u(n,dict,size) or f_stream_b_n_u(n,size)
+ else
+ data = compdata
+ b = dict and f_stream_b_d_c(n,dict,compsize) or f_stream_b_n_c(n,compsize)
+ end
+ else
+ b = dict and f_stream_b_d_u(n,dict,size) or f_stream_b_n_u(n,size)
+ end
+ else
+ b = dict and f_stream_b_d_u(n,dict,size) or f_stream_b_n_u(n,size)
+ end
+ flush(f,b)
+ flush(f,data)
+ flush(f,e)
+ objects[n] = offset
+ offset = offset + #b + #data + #e
+ else
+ if nolength then
+ data = f_stream_d_r(n,dict,data)
+ elseif comp ~= false and compress and size > threshold then
+ local compdata = zlibcompress(data,3)
+ if compdata then
+ local compsize = #compdata
+ if compsize > size - threshold then
+ data = dict and f_stream_d_u(n,dict,size,data) or f_stream_n_u(n,size,data)
+ else
+ data = dict and f_stream_d_c(n,dict,compsize,compdata) or f_stream_n_c(n,compsize,compdata)
+ end
+ else
+ data = dict and f_stream_d_u(n,dict,size,data) or f_stream_n_u(n,size,data)
+ end
+ else
+ data = dict and f_stream_d_u(n,dict,size,data) or f_stream_n_u(n,size,data)
+ end
+ if not lastdeferred then
+ lastdeferred = n
+ elseif n < lastdeferred then
+ lastdeferred = n
+ end
+ objects[n] = data
+ end
+ return n
+end
+
+flushdeferred = function() -- was forward defined
+ if lastdeferred then
+ for n=lastdeferred,nofobjects do
+ local o = objects[n]
+ if type(o) == "string" then
+ objects[n] = offset
+ offset = offset + #o
+ flush(f,o)
+ end
+ end
+ lastdeferred = false
+ end
+end
+
+-- n = pdf.obj([n,] objtext)
+-- n = pdf.obj([n,] "file", filename)
+-- n = pdf.obj([n,] "stream", streamtext [, attrtext])
+-- n = pdf.obj([n,] "streamfile", filename [, attrtext])
+--
+-- n = pdf.obj {
+-- type = <string>, -- raw|stream
+-- immediate = <boolean>,
+-- objnum = <number>,
+-- attr = <string>,
+-- compresslevel = <number>,
+-- objcompression = <boolean>,
+-- file = <string>,
+-- string = <string>,
+-- nolength = <boolean>,
+-- }
+
+local function obj(a,b,c,d)
+ local kind --, immediate
+ local objnum, data, attr, filename
+ local compresslevel, objcompression, nolength
+ local argtype = type(a)
+ if argtype == "table" then
+ kind = a.type -- raw | stream
+ -- immediate = a.immediate
+ objnum = a.objnum
+ attr = a.attr
+ compresslevel = a.compresslevel
+ objcompression = a.objcompression
+ filename = a.file
+ data = a.string or a.stream or ""
+ nolength = a.nolength
+ if kind == "stream" then
+ if filename then
+ data = loaddata(filename) or ""
+ end
+ elseif kind == "raw"then
+ if filename then
+ data = loaddata(filename) or ""
+ end
+ elseif kind == "file"then
+ kind = "raw"
+ data = filename and loaddata(filename) or ""
+ elseif kind == "streamfile" then
+ kind = "stream"
+ data = filename and loaddata(filename) or ""
+ end
+ else
+ if argtype == "number" then
+ objnum = a
+ a, b, c = b, c, d
+ else
+ nofobjects = nofobjects + 1
+ objnum = nofobjects
+ end
+ if b then
+ if a == "stream" then
+ kind = "stream"
+ data = b
+ elseif a == "file" then
+ -- kind = "raw"
+ data = loaddata(b)
+ elseif a == "streamfile" then
+ kind = "stream"
+ data = loaddata(b)
+ else
+ data = "" -- invalid object
+ end
+ attr = c
+ else
+ -- kind = "raw"
+ data = a
+ end
+ end
+ if not objnum then
+ nofobjects = nofobjects + 1
+ objnum = nofobjects
+ end
+ -- todo: immediate
+ if kind == "stream" then
+ flushstreamobj(data,objnum,attr,compresslevel and compresslevel > 0 or nil,nolength)
+ elseif objectstream and objcompression ~= false then
+ addtocache(objnum,data)
+ else
+ flushnormalobj(data,objnum)
+ end
+ return objnum
+end
+
+updaters.register("backend.update.pdf",function()
+ pdf.reserveobj = pdfreserveobj
+ pdf.getpageref = getpageref
+ pdf.refobj = refobj
+ pdf.flushstreamobj = flushstreamobj
+ pdf.flushnormalobj = flushnormalobj
+ pdf.obj = obj
+ pdf.immediateobj = obj
+end)
+
+-- In lua 5.4 the methods are now moved one metalevel deeper so we need to get them
+-- from mt.__index instead. (I did get that at first.) It makes for a slightly (imo)
+-- nicer interface but no real gain in speed as we don't flush that often.
+
+local openfile, closefile do
+
+ -- I used to do <space><lf> but then figured out that when I open and save a file in a mode
+ -- that removes trailing spaces, the xref becomes invalid. The problem was then that a
+ -- reconstruction of the file by a viewer gives weird effects probably because percent symbols
+ -- gets interpreted then. Thanks to Ross Moore for noticing this side effect!
+
+ local f_used = formatters["%010i 00000 n\013\010"]
+ local f_link = formatters["%010i 00000 f\013\010"]
+ local f_first = formatters["%010i 65535 f\013\010"]
+
+ local f_pdf = formatters["%%PDF-%i.%i\010"]
+ local f_xref = formatters["xref\0100 %i\010"]
+ local f_trailer_id = formatters["trailer\010<< %s /ID [ <%s> <%s> ] >>\010startxref\010%i\010%%%%EOF"]
+ local f_trailer_no = formatters["trailer\010<< %s >>\010startxref\010%i\010%%%%EOF"]
+ local f_startxref = formatters["startxref\010%i\010%%%%EOF"]
+
+ local inmemory = false
+ local close = false
+
+ openfile = function(filename)
+ if inmemory then
+ local n = 0
+ f = { }
+ flush = function(f,s)
+ n = n + 1 f[n] = s
+ end
+ close = function(f)
+ f = concat(f)
+ io.savedata(filename,f)
+ f = false
+ end
+ -- local n = 0
+ -- f = {
+ -- write = function(self,s)
+ -- n = n + 1 f[n] = s
+ -- end,
+ -- close = function(self)
+ -- f = concat(f)
+ -- io.savedata(filename,f)
+ -- f = false
+ -- end,
+ -- }
+ else
+ f = io.open(filename,"wb")
+ if not f then
+ -- message
+ os.exit()
+ end
+ -- f:setvbuf("full",64*1024)
+ local m = getmetatable(f)
+ flush = m.write or m.__index.write
+ close = m.close or m.__index.close
+ end
+ local v = f_pdf(majorversion,minorversion)
+ -- local b = "%\xCC\xD5\xC1\xD4\xC5\xD8\xD0\xC4\xC6\010" -- LUATEXPDF (+128)
+ local b = "%\xC3\xCF\xCE\xD4\xC5\xD8\xD4\xD0\xC4\xC6\010" -- CONTEXTPDF (+128)
+ flush(f,v)
+ flush(f,b)
+ offset = #v + #b
+ end
+
+ closefile = function(abort)
+ if abort then
+ f:close()
+ f = io.open(abort,"wb")
+ if f then
+ local name = resolvers.findfile("context-lmtx-error.pdf")
+ if name then
+ local data = io.loaddata(name)
+ if data then
+ f:write(data)
+ f:close()
+ return
+ end
+ end
+ f:close()
+ removefile(abort)
+ end
+ else
+ local xrefoffset = offset
+ local lastfree = 0
+ local noffree = 0
+ local catalog = lpdf.getcatalog()
+ local info = lpdf.getinfo()
+ if trailerid == true then
+ trailerid = md5HEX(osuuid())
+ elseif trailerid and #trailerid > 32 then
+ trailerid = md5HEX(trailerid)
+ else
+ trailerid = false
+ end
+ if objectstream then
+ flushdeferred()
+ flushcache()
+ --
+ xrefoffset = offset
+ --
+ nofobjects = nofobjects + 1
+ objects[nofobjects] = offset -- + 1
+ --
+ -- combine these three in one doesn't really give less code so
+ -- we go for the efficient ones
+ --
+ local nofbytes = 4
+ local c1, c2, c3, c4
+ if offset <= 0xFFFF then
+ nofbytes = 2
+ for i=1,nofobjects do
+ local o = objects[i]
+ if not o then
+ noffree = noffree + 1
+ else
+ local strm = o < 0
+ if strm then
+ o = -o
+ end
+ c1 = extract(o,8,8)
+ c2 = extract(o,0,8)
+ if strm then
+ objects[i] = char(2,c1,c2,streams[o][i])
+ else
+ objects[i] = char(1,c1,c2,0)
+ end
+ end
+ end
+ if noffree > 0 then
+ for i=nofobjects,1,-1 do
+ local o = objects[i]
+ if not o then
+ local f1 = extract(lastfree,8,8)
+ local f2 = extract(lastfree,0,8)
+ objects[i] = char(0,f1,f2,0)
+ lastfree = i
+ end
+ end
+ end
+ elseif offset <= 0xFFFFFF then
+ nofbytes = 3
+ for i=1,nofobjects do
+ local o = objects[i]
+ if not o then
+ noffree = noffree + 1
+ else
+ local strm = o < 0
+ if strm then
+ o = -o
+ end
+ c1 = extract(o,16,8)
+ c2 = extract(o, 8,8)
+ c3 = extract(o, 0,8)
+ if strm then
+ objects[i] = char(2,c1,c2,c3,streams[o][i])
+ else
+ objects[i] = char(1,c1,c2,c3,0)
+ end
+ end
+ end
+ if noffree > 0 then
+ for i=nofobjects,1,-1 do
+ local o = objects[i]
+ if not o then
+ local f1 = extract(lastfree,16,8)
+ local f2 = extract(lastfree, 8,8)
+ local f3 = extract(lastfree, 0,8)
+ objects[i] = char(0,f1,f2,f3,0)
+ lastfree = i
+ end
+ end
+ end
+ else
+ nofbytes = 4
+ for i=1,nofobjects do
+ local o = objects[i]
+ if not o then
+ noffree = noffree + 1
+ else
+ local strm = o < 0
+ if strm then
+ o = -o
+ end
+ c1 = extract(o,24,8)
+ c2 = extract(o,16,8)
+ c3 = extract(o, 8,8)
+ c4 = extract(o, 0,8)
+ if strm then
+ objects[i] = char(2,c1,c2,c3,c4,streams[o][i])
+ else
+ objects[i] = char(1,c1,c2,c3,c4,0)
+ end
+ end
+ end
+ if noffree > 0 then
+ for i=nofobjects,1,-1 do
+ local o = objects[i]
+ if not o then
+ local f1 = extract(lastfree,24,8)
+ local f2 = extract(lastfree,16,8)
+ local f3 = extract(lastfree, 8,8)
+ local f4 = extract(lastfree, 0,8)
+ objects[i] = char(0,f1,f2,f3,f4,0)
+ lastfree = i
+ end
+ end
+ end
+ end
+ objects[0] = rep("\0",1+nofbytes+1)
+ local data = concat(objects,"",0,nofobjects)
+ local xref = pdfdictionary {
+ Type = pdfconstant("XRef"),
+ Size = nofobjects + 1,
+ W = pdfarray { 1, nofbytes, 1 },
+ Root = catalog,
+ Info = info,
+ ID = trailerid and pdfarray { pdfliteral(trailerid,true), pdfliteral(trailerid,true) } or nil,
+ }
+ if compress then
+ local comp = zlibcompress(data,3)
+ if comp then
+ data = comp
+ flush(f,f_stream_b_d_c(nofobjects,xref(),#data))
+ else
+ flush(f,f_stream_b_d_u(nofobjects,xref(),#data))
+ end
+ else
+ flush(f,f_stream_b_d_u(nofobjects,xref(),#data))
+ end
+ flush(f,data)
+ flush(f,s_stream_e)
+ flush(f,f_startxref(xrefoffset))
+ else
+ flushdeferred()
+ xrefoffset = offset
+ flush(f,f_xref(nofobjects+1))
+ local trailer = pdfdictionary {
+ Size = nofobjects+1,
+ Root = catalog,
+ Info = info,
+ }
+ for i=1,nofobjects do
+ local o = objects[i]
+ if o then
+ objects[i] = f_used(o)
+ end
+ end
+ for i=nofobjects,1,-1 do
+ local o = objects[i]
+ if not o then
+ objects[i] = f_link(lastfree)
+ lastfree = i
+ end
+ end
+ objects[0] = f_first(lastfree)
+ flush(f,concat(objects,"",0,nofobjects))
+ trailer.Size = nofobjects + 1
+ if trailerid then
+ flush(f,f_trailer_id(trailer(),trailerid,trailerid,xrefoffset))
+ else
+ flush(f,f_trailer_no(trailer(),xrefoffset))
+ end
+ end
+ f:close()
+ end
+ io.flush()
+ closefile = function() end
+ end
+
+end
+
+-- For the moment we overload it here, although back-fil.lua eventually will
+-- be merged with back-pdf as it's pdf specific, or maybe back-imp-pdf or so.
+
+updaters.register("backend.update.pdf",function()
+
+ -- We overload img but at some point it will even go away, so we just
+ -- reimplement what we need in context. This will change completely i.e.
+ -- we will drop the low level interface!
+
+ local codeinjections = backends.pdf.codeinjections
+
+ local imagetypes = images.types -- pdf png jpg jp2 jbig2 stream memstream
+ local img_none = imagetypes.none
+
+ local rulecodes = nodes.rulecodes
+
+ local setprop = nodes.nuts.setprop
+
+ local report_images = logs.reporter("backend","images")
+
+ local lastindex = 0
+ local indices = { }
+
+ local bpfactor <const> = number.dimenfactors.bp
+ local imagerule_code <const> = rulecodes.image
+
+ function codeinjections.newimage(specification)
+ return specification
+ end
+
+ function codeinjections.copyimage(original)
+ return setmetatableindex(original)
+ end
+
+ function codeinjections.scanimgage(specification)
+ return specification
+ end
+
+ local function embedimage(specification)
+ if specification then
+ lastindex = lastindex + 1
+ index = lastindex
+ specification.index = index
+ local xobject = pdfdictionary { }
+ if not specification.notype then
+ xobject.Type = pdf_xobject
+ xobject.Subtype = pdf_form
+ xobject.FormType = 1
+ end
+ local bbox = specification.bbox
+ if bbox and not specification.nobbox then
+ xobject.BBox = pdfarray {
+ bbox[1] * bpfactor,
+ bbox[2] * bpfactor,
+ bbox[3] * bpfactor,
+ bbox[4] * bpfactor,
+ }
+ end
+ xobject = xobject + specification.attr
+ if bbox and not specification.width then
+ specification.width = bbox[3]
+ end
+ if bbox and not specification.height then
+ specification.height = bbox[4]
+ end
+ local dict = xobject()
+ --
+ nofobjects = nofobjects + 1
+ local objnum = nofobjects
+ local nolength = specification.nolength
+ local stream = specification.stream or specification.string
+ --
+ -- We cannot set type in native img so we need this hack or
+ -- otherwise we need to patch too much. Better that i write
+ -- a wrapper then. Anyway, it has to be done better: a key that
+ -- tells either or not to scale by xsize/ysize when flushing.
+ --
+ if not specification.type then
+ local kind = specification.kind
+ if kind then
+ -- take that one
+ elseif attr and find(attr,"BBox") then
+ kind = img_stream
+ else
+ -- hack: a bitmap
+ kind = img_none
+ end
+ specification.type = kind
+ specification.kind = kind
+ end
+ local compress = compresslevel and compresslevel > 0 or nil
+ flushstreamobj(stream,objnum,dict,compress,nolength)
+ specification.objnum = objnum
+ specification.rotation = specification.rotation or 0
+ specification.orientation = specification.orientation or 0
+ specification.transform = specification.transform or 0
+ specification.stream = nil
+ specification.attr = nil
+ specification.type = specification.kind or specification.type or img_none
+ indices[index] = specification -- better create a real specification
+ return specification
+ end
+ end
+
+ codeinjections.embedimage = embedimage
+
+ function codeinjections.wrapimage(specification)
+ --
+ local index = specification.index
+ if not index then
+ embedimage(specification)
+ end
+ --
+ local width = specification.width or 0
+ local height = specification.height or 0
+ local depth = specification.depth or 0
+ -- newimagerule
+ local n = nodes.pool.rule(width,height,depth)
+ n.subtype = imagerule_code
+ setprop(tonut(n),"index",specification.index)
+ return n
+ end
+
+ function pdf.includeimage(index)
+ local specification = indices[index]
+ if specification then
+ local bbox = specification.bbox
+ local xorigin = bbox[1]
+ local yorigin = bbox[2]
+ local xsize = bbox[3] - xorigin -- we need the original ones, not the 'rotated' ones
+ local ysize = bbox[4] - yorigin -- we need the original ones, not the 'rotated' ones
+ local transform = specification.transform or 0
+ local objnum = specification.objnum or pdfreserveobj()
+ local groupref = nil
+ local kind = specification.kind or specification.type or img_none -- determines scaling type
+ return
+ kind,
+ xorigin, yorigin,
+ xsize, ysize,
+ transform,
+ objnum,
+ groupref
+ end
+ end
+
+end)
+
+updaters.register("backend.update.lpdf",function()
+
+ -- todo: an md5 or sha2 hash can save space
+ -- todo: make a type 3 font instead
+ -- todo: move to lpdf namespace
+
+ local pdfimage = lpdf.epdf.image
+ local newpdf = pdfimage.new
+ local openpdf = pdfimage.open
+ local closepdf = pdfimage.close
+ local copypage = pdfimage.copy
+
+ local embedimage = images.embed
+
+ local nofstreams = 0
+ local topdf = { }
+ local toidx = { }
+
+ local function storedata_s(pdf)
+ local idx = toidx[pdf]
+ if not idx then
+ nofstreams = nofstreams + 1
+ idx = nofstreams
+ toidx[pdf] = nofstreams
+ topdf[idx] = pdf
+ end
+ return idx
+ end
+
+ local function vfimage_s(id,wd,ht,dp,pos_h,pos_v)
+ local index = topdf[id]
+ if type(index) == "string" then
+ local pdfdoc = newpdf(index,#index)
+ local image = copypage(pdfdoc)
+ local bbox = image.bbox
+ image.width = bbox[3] - bbox[1]
+ image.height = bbox[4] - bbox[2]
+ embedimage(image)
+ index = image.index
+ topdf[id] = index
+ end
+ -- pdf.print or pdf.literal
+ flushimage(index,wd,ht,dp,pos_h,pos_v)
+ end
+
+ local function storedata_n(name,page)
+ local idx = toidx[pdf]
+ if not idx then
+ nofstreams = nofstreams + 1
+ idx = nofstreams
+ toidx[pdf] = nofstreams
+ topdf[idx] = pdf
+ end
+ return idx
+ end
+
+ -- We need to have a way to close such a pdf ... esp for fonts.
+
+ local pdfdocs = { }
+
+ local function vfimage_n(name,page,wd,ht,dp,pos_h,pos_v)
+ local d = pdfdocs[name]
+ if not d then
+ d = { doc = openpdf(name), pages = { } }
+ pdfdocs[name] = d
+ end
+ local index = d.pages[page]
+ if not index then
+ local image = copypage(d.doc,page)
+ local bbox = image.bbox
+ image.width = bbox[3] - bbox[1]
+ image.height = bbox[4] - bbox[2]
+ embedimage(image)
+ index = image.index
+ d.pages[page] = index
+ end
+ flushimage(index,wd,ht,dp,pos_h,pos_v)
+ end
+
+ local function pdfvfimage(wd,ht,dp,data,name)
+ if type(data) == "number" then
+ return { "lua", function(font,char,pos_h,pos_v)
+ vfimage_n(name,data,wd,ht,dp,pos_h,pos_v)
+ end }
+ else
+ return { "lua", function(font,char,pos_h,pos_v)
+ local id = storedata_s(data)
+ vfimage_s(id,wd,ht,dp,pos_h,pos_v)
+ end }
+ end
+ end
+
+ lpdf.vfimage = pdfvfimage
+
+end)
+
+-- The driver.
+
+do
+
+ local isfile = lfs.isfile
+ local removefile = os.remove
+ local renamefile = os.rename
+ -- local copyfile = file.copy
+ -- local addsuffix = file.addsuffix
+ local texgetbox = tex.getbox
+
+ local pdfname = nil
+ local converter = nil
+ local useddriver = nil -- a bit of a hack
+
+ local function outputfilename(driver)
+ return pdfname
+ end
+
+ -- todo: prevent twice
+
+ local function prepare(driver)
+ if not environment.initex then
+ -- install new functions in pdf namespace
+ updaters.apply("backend.update.pdf")
+ -- install new functions in lpdf namespace
+ updaters.apply("backend.update.lpdf")
+ -- adapt existing shortcuts to lpdf namespace
+ updaters.apply("backend.update.tex")
+ -- adapt existing shortcuts to tex namespace
+ updaters.apply("backend.update")
+ --
+ -- if rawget(pdf,"setforcefile") then
+ -- pdf.setforcefile(false) -- default anyway
+ -- end
+ --
+ pdfname = file.addsuffix(tex.jobname,"pdf")
+ openfile(pdfname)
+ --
+ luatex.registerstopactions(1,function()
+ if pdfname then
+ lpdf.finalizedocument()
+ closefile()
+ end
+ end)
+ --
+ luatex.registerpageactions(1,function()
+ if pdfname then
+ lpdf.finalizepage(true)
+ end
+ end)
+ -- --
+ lpdf.registerdocumentfinalizer(wrapup,nil,"wrapping up")
+ --
+ end
+ --
+ environment.lmtxmode = CONTEXTLMTXMODE
+ --
+ converter = drivers.converters.lmtx
+ useddriver = driver
+ end
+
+ local function wrapup(driver)
+ if pdfname then
+ closefile()
+ pdfname = nil
+ end
+ end
+
+ local function cleanup(driver)
+ if pdfname then
+ closefile(pdfname)
+ pdfname = nil
+ end
+ end
+
+ local function convert(driver,boxnumber)
+ converter(driver,texgetbox(boxnumber),"page")
+ end
+
+ localconverter = function(...)
+ converter(useddriver,...)
+ end
+
+ drivers.install {
+ name = "pdf",
+ flushers = {
+ character = flushcharacter,
+ fontchar = flushfontchar,
+ rule = flushrule,
+ simplerule = flushsimplerule,
+ pushorientation = pushorientation,
+ poporientation = poporientation,
+ --
+ literal = flushliteral,
+ setmatrix = flushsetmatrix,
+ save = flushsave,
+ restore = flushrestore,
+ image = flushimage,
+ group = flushgroup,
+ --
+ updatefontstate = updatefontstate,
+ },
+ actions = {
+ prepare = prepare,
+ wrapup = wrapup,
+ cleanup = cleanup,
+ --
+ initialize = initialize,
+ convert = convert,
+ finalize = finalize,
+ --
+ outputfilename = outputfilename,
+ },
+ }
+
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lpdf-mis.lua b/Master/texmf-dist/tex/context/base/mkiv/lpdf-mis.lua
index 77f11918b46..7227f9dba8a 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lpdf-mis.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/lpdf-mis.lua
@@ -76,6 +76,7 @@ local v_layer = variables.layer
local v_lefttoright = variables.lefttoright
local v_righttoleft = variables.righttoleft
local v_title = variables.title
+local v_nomenubar = variables.nomenubar
local positive = register(pageliteral("/GSpositive gs"))
local negative = register(pageliteral("/GSnegative gs"))
@@ -195,6 +196,10 @@ function codeinjections.setupidentity(specification)
end
end
+function codeinjections.getidentityvariable(name)
+ return identity[name]
+end
+
local done = false -- using "setupidentity = function() end" fails as the meaning is frozen in register
local function setupidentity()
@@ -327,7 +332,10 @@ local plusspecs = {
direction = "L2R",
},
[v_righttoleft] ={
- direction = "R2R",
+ direction = "R2L",
+ },
+ [v_nomenubar] ={
+ nomenubar = true,
},
}
@@ -393,6 +401,11 @@ local pagespecs = {
duplex = "Simplex",
paper = true,
},
+ [v_nomenubar] = {
+ mode = "UseNone",
+ layout = "auto",
+ nomenubar = true,
+ },
}
local pagespec, topoffset, leftoffset, height, width, doublesided = "default", 0, 0, 0, 0, false
@@ -472,6 +485,7 @@ local function documentspecification()
local paper = spec.paper
local title = spec.title
local direction = spec.direction
+ local nomenubar = spec.nomenubar
if layout then
addtocatalog("PageLayout",pdfconstant(layout))
end
@@ -490,7 +504,7 @@ local function documentspecification()
prints = pdfarray(flattened(pages.toranges(marked)))
end
end
- if fit or fixed or duplex or copies or paper or prints or title or direction then
+ if fit or fixed or duplex or copies or paper or prints or title or direction or nomenubar then
addtocatalog("ViewerPreferences",pdfdictionary {
FitWindow = fit and true or nil,
PrintScaling = fixed and pdfconstant("None") or nil,
@@ -500,6 +514,7 @@ local function documentspecification()
PrintPageRange = prints or nil,
DisplayDocTitle = title and true or nil,
Direction = direction and pdfconstant(direction) or nil,
+ HideMenubar = nomenubar and true or nil,
})
end
addtoinfo ("Trapped", pdfconstant("False")) -- '/Trapped' in /Info, 'Trapped' in XMP
@@ -510,11 +525,7 @@ end
-- temp hack: the mediabox is not under our control and has a precision of 5 digits
local factor = number.dimenfactors.bp
-local f_value = formatters["%.6F"]
-
-directives.register("pdf.stripzeros",function()
- local f_value = formatters["%.6N"]
-end)
+local f_value = formatters["%.6N"]
local function boxvalue(n) -- we could share them
return pdfverbose(f_value(factor * n))
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lpdf-nod.lua b/Master/texmf-dist/tex/context/base/mkiv/lpdf-nod.lua
index 8bcf18c62ae..fcb2d145732 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lpdf-nod.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/lpdf-nod.lua
@@ -6,10 +6,6 @@ if not modules then modules = { } end modules ['lpdf-nod'] = {
license = "see context related readme files"
}
-if CONTEXTLMTXMODE > 1 then
- return
-end
-
local nodecodes = nodes.nodecodes
local whatsitcodes = nodes.whatsitcodes
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lpdf-pde.lua b/Master/texmf-dist/tex/context/base/mkiv/lpdf-pde.lua
index c1680137da2..ec1064a0dfd 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lpdf-pde.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/lpdf-pde.lua
@@ -41,7 +41,7 @@ if not modules then modules = { } end modules ['lpdf-epd'] = {
-- PPCRYPT_PASS -1 encryption present, need non-empty password
-- PPCRYPT_FAIL -2 invalid or unsupported encryption (eg. undocumented in pdf spec)
-local setmetatable, rawset, rawget, type, next = setmetatable, rawset, rawget, type, next
+local setmetatable, type, next = setmetatable, type, next
local tostring, tonumber, unpack = tostring, tonumber, unpack
local char, byte, find = string.char, string.byte, string.find
local abs = math.abs
@@ -60,29 +60,29 @@ if not (number and number.dimenfactors) then
require("util-dim")
end
-local epdf = pdfe
+local pdfe = pdfe
lpdf = lpdf or { }
local lpdf = lpdf
local lpdf_epdf = { }
-lpdf.epdf = lpdf_epdf
-
-local openPDF = epdf.open
-local newPDF = epdf.new
-local closePDF = epdf.close
-
-local getcatalog = epdf.getcatalog
-local getinfo = epdf.getinfo
-local gettrailer = epdf.gettrailer
-local getnofpages = epdf.getnofpages
-local getversion = epdf.getversion
-local getbox = epdf.getbox
-local getstatus = epdf.getstatus
-local unencrypt = epdf.unencrypt
-
-local dictionarytotable = epdf.dictionarytotable
-local arraytotable = epdf.arraytotable
-local pagestotable = epdf.pagestotable
-local readwholestream = epdf.readwholestream
+ lpdf.epdf = lpdf_epdf
+
+local pdfopen = pdfe.open
+local pdfnew = pdfe.new
+local pdfclose = pdfe.close
+
+local getcatalog = pdfe.getcatalog
+local getinfo = pdfe.getinfo
+local gettrailer = pdfe.gettrailer
+local getnofpages = pdfe.getnofpages
+local getversion = pdfe.getversion
+local getbox = pdfe.getbox
+local getstatus = pdfe.getstatus
+local unencrypt = pdfe.unencrypt
+
+local dictionarytotable = pdfe.dictionarytotable
+local arraytotable = pdfe.arraytotable
+local pagestotable = pdfe.pagestotable
+local readwholestream = pdfe.readwholestream
local getfromreference = pdfe.getfromreference
@@ -405,21 +405,25 @@ function resolvers.pages(document)
--
for pagenumber=1,nofpages do
local rawpagedata = rawpages[pagenumber]
- local pagereference = rawpagedata[3]
- local pageobject = rawpagedata[1]
- local pagedata = some_dictionary(pageobject,document)
- if pagedata and pageobject then
- pagedata.number = pagenumber
- pagedata.MediaBox = getbox(pageobject,"MediaBox")
- pagedata.CropBox = getbox(pageobject,"CropBox")
- pagedata.BleedBox = getbox(pageobject,"BleedBox")
- pagedata.ArtBox = getbox(pageobject,"ArtBox")
- pagedata.TrimBox = getbox(pageobject,"TrimBox")
- pages[pagenumber] = pagedata
- __xrefs__[pagedata] = pagereference
- __cache__[pagereference] = pagedata
+ if rawpagedata then
+ local pagereference = rawpagedata[3]
+ local pageobject = rawpagedata[1]
+ local pagedata = some_dictionary(pageobject,document)
+ if pagedata and pageobject then
+ pagedata.number = pagenumber
+ pagedata.MediaBox = getbox(pageobject,"MediaBox")
+ pagedata.CropBox = getbox(pageobject,"CropBox")
+ pagedata.BleedBox = getbox(pageobject,"BleedBox")
+ pagedata.ArtBox = getbox(pageobject,"ArtBox")
+ pagedata.TrimBox = getbox(pageobject,"TrimBox")
+ pages[pagenumber] = pagedata
+ __xrefs__[pagedata] = pagereference
+ __cache__[pagereference] = pagedata
+ else
+ report_epdf("missing pagedata for page %i, case %i",pagenumber,1)
+ end
else
- report_epdf("missing pagedata for page %i",i)
+ report_epdf("missing pagedata for page %i, case %i",pagenumber,2)
end
end
--
@@ -437,9 +441,9 @@ function lpdf_epdf.load(filename,userpassword,ownerpassword,fromstring)
statistics.starttiming(lpdf_epdf)
local __data__
if fromstring then
- __data__ = newPDF(filename,#filename)
+ __data__ = pdfnew(filename,#filename)
else
- __data__ = openPDF(filename)
+ __data__ = pdfopen(filename)
end
if __data__ then
if userpassword and getstatus(__data__) < 0 then
@@ -455,6 +459,8 @@ function lpdf_epdf.load(filename,userpassword,ownerpassword,fromstring)
if __data__ then
document = {
filename = filename,
+ nofcopied = 0,
+ copied = { },
__cache__ = { },
__xrefs__ = { },
__fonts__ = { },
@@ -481,6 +487,9 @@ function lpdf_epdf.load(filename,userpassword,ownerpassword,fromstring)
statistics.stoptiming(lpdf_epdf)
-- print(statistics.elapsedtime(lpdf_epdf))
end
+ if document then
+ nofloaded = nofloaded + 1
+ end
return document or nil
end
@@ -491,10 +500,9 @@ function lpdf_epdf.unload(filename)
if type(filename) == "string" then
local document = loaded[filename]
if document then
--- report_epdf("%04i closed: %s",nofloaded,filename)
--- nofloaded = nofloaded - 1
loaded[document] = nil
loaded[filename] = nil
+ pdfclose(document.__data__)
end
end
end
@@ -519,6 +527,7 @@ lpdf_epdf.expanded = expanded
local spaces = lpegpatterns.whitespace^1
local optspaces = lpegpatterns.whitespace^0
+local comment = P("%") * (1 - lpegpatterns.newline)^0
local numchar = P("\\")/"" * (R("09")^3/function(s) return char(tonumber(s,8)) end)
+ P("\\") * P(1)
local key = P("/") * C(R("AZ","az","09","__")^1)
@@ -527,7 +536,7 @@ local keyword = Ct(Cc("name") * key)
local operator = C((R("AZ","az")+P("*")+P("'")+P('"'))^1)
local grammar = P { "start",
- start = (keyword + number + V("dictionary") + V("array") + V("hexstring") + V("decstring") + spaces)^1,
+ start = (comment + keyword + number + V("dictionary") + V("array") + V("hexstring") + V("decstring") + spaces)^1,
keyvalue = key * optspaces * V("start"),
array = Ct(Cc("array") * P("[") * Ct(V("start")^1) * P("]")),
dictionary = Ct(Cc("dict") * P("<<") * Ct(V("keyvalue")^1) * P(">>")),
@@ -635,6 +644,8 @@ local function analyzefonts(document,resources) -- unfinished, see mtx-pdf for b
return fonts
end
+lpdf_epdf.analyzefonts = analyzefonts
+
local more = 0
local unic = nil -- cheaper than passing each time as Carg(1)
@@ -680,27 +691,34 @@ function lpdf_epdf.getpagecontent(document,pagenumber)
local size = #entry
local operator = entry[size]
if operator == "Tf" then
- font = fonts[entry[1]]
- unic = font.tounicode
- elseif operator == "TJ" then -- { array, TJ }
- local list = entry[1]
+ font = fonts[entry[1][2]]
+ unic = font and font.tounicode or { }
+ elseif operator == "TJ" then
+ local data = entry[1] -- { "array", { ... } }
+ local list = data[2] -- { { ... }, { ... } }
for i=1,#list do
local li = list[i]
- if type(li) == "table" then
- if li[1] == "hex" then
+-- if type(li) == "table" then
+ local kind = li[1]
+ if kind == "hex" then
list[i] = lpegmatch(p_hex_to_utf,li[2])
- else
+ elseif kind == "string" then
list[i] = lpegmatch(p_dec_to_utf,li[2])
+ else
+ list[i] = li[2] -- kern
end
- else
- -- kern
- end
+-- else
+-- -- kern
+-- end
end
- elseif operator == "Tj" or operator == "'" or operator == '"' then -- { string, Tj } { string, ' } { n, m, string, " }
- local list = entry[size-1]
- if list[1] == "hex" then
+ elseif operator == "Tj" or operator == "'" or operator == '"' then
+ -- { string, Tj } { string, ' } { n, m, string, " }
+ local data = entry[size-1]
+ local list = data[2]
+ local kind = list[1]
+ if kind == "hex" then
list[2] = lpegmatch(p_hex_to_utf,li[2])
- else
+ elseif kind == "string" then
list[2] = lpegmatch(p_dec_to_utf,li[2])
end
end
@@ -729,25 +747,32 @@ function lpdf_epdf.contenttotext(document,list) -- maybe signal fonts
local size = #entry
local operator = entry[size]
if operator == "Tf" then
- last_f = entry[2]
+ last_f = entry[2][2] -- size
elseif operator == "TJ" then
- local list = entry[1]
+ local data = entry[1] -- { "array", { ... } }
+ local list = data[2] -- { { ... }, { ... } }
for i=1,#list do
local li = list[i]
- if type(li) == "string" then
+ local kind = type(li)
+ if kind == "string" then
last = last + 1
text[last] = li
- elseif li < -50 then
+ elseif kind == "number" and li < -50 then
last = last + 1
text[last] = " "
end
end
- line = concat(list)
elseif operator == "Tj" then
last = last + 1
- text[last] = entry[size-1]
+ local li = entry[size-1]
+ local kind = type(li)
+ if kind == "string" then
+ last = last + 1
+ text[last] = li
+ end
elseif operator == "cm" or operator == "Tm" then
- local ty = entry[6]
+ local data = entry
+ local ty = entry[6][2]
local dy = abs(last_y - ty)
if dy > linefactor*last_f then
if last > 0 then
@@ -793,7 +818,7 @@ function lpdf_epdf.getstructure(document,list) -- just a test
end
end
-if img then do
+if images then do
-- This can be made a bit faster (just get raw data and pass it) but I will
-- do that later. In the end the benefit is probably neglectable.
@@ -887,6 +912,8 @@ if img then do
value = pdfnull()
elseif kind == reference_object_code then
value = deepcopyobject(xref,copied,entry)
+ elseif entry == nil then
+ value = pdfnull()
else
value = tostring(entry)
end
@@ -999,6 +1026,8 @@ if img then do
local openpdf = lpdf_epdf.load
local closepdf = lpdf_epdf.unload
+ -- todo: keep track of already open files
+
local function newpdf(str,userpassword,ownerpassword)
return openpdf(str,userpassword,ownerpassword,true)
end
@@ -1019,7 +1048,7 @@ if img then do
local root = pdfdoc.Catalog
local page = pdfdoc.pages[pagenumber]
if page then
- local sizetag = sizes[size or "crop"] or sizes.cro
+ local sizetag = sizes[size or "crop"] or sizes.crop
local mediabox = page.MediaBox or { 0, 0, 0, 0 }
local cropbox = page[sizetag] or mediabox
return {
@@ -1046,92 +1075,96 @@ if img then do
local page = pdfdoc.pages[pagenumber or 1]
local pageinfo = querypdf(pdfdoc,pagenumber)
local contents = page.Contents
- local xref = pdfdoc.__xrefs__
- local copied = pdfdoc.__copied__
- if compact and lpdf_epdf.plugin then
- plugins = lpdf_epdf.plugin(pdfdoc,xref,copied,page)
- end
- local xobject = pdfdictionary {
- Type = pdfconstant("XObject"),
- Subtype = pdfconstant("Form"),
- FormType = 1,
- Group = copyobject(xref,copied,page,"Group"),
- LastModified = copyobject(xref,copied,page,"LastModified"),
- Metadata = copyobject(xref,copied,page,"Metadata"),
- PieceInfo = copyobject(xref,copied,page,"PieceInfo"),
- Resources = copyresources(pdfdoc,xref,copied,page),
- SeparationInfo = copyobject(xref,copied,page,"SeparationInfo"),
- } + attr
- if attributes then
- for k, v in expanded(attributes) do
- page[k] = v -- maybe nested
+ if contents then
+ local xref = pdfdoc.__xrefs__
+ local copied = pdfdoc.__copied__
+ if compact and lpdf_epdf.plugin then
+ plugins = lpdf_epdf.plugin(pdfdoc,xref,copied,page)
end
- end
- local content = ""
- local nolength = nil
- local ctype = contents.__type__
- -- we always recompress because image object streams can not be
- -- influenced (yet)
- if ctype == stream_object_code then
- if stripmarked then
- content = contents() -- uncompressed
- local stripped = lpdf_epdf.stripcontent(content)
- if stripped ~= content then
- -- report("%i bytes stripped on page %i",#content-#stripped,pagenumber or 1)
- content = stripped
+ local xobject = pdfdictionary {
+ Type = pdfconstant("XObject"),
+ Subtype = pdfconstant("Form"),
+ FormType = 1,
+ Group = copyobject(xref,copied,page,"Group"),
+ LastModified = copyobject(xref,copied,page,"LastModified"),
+ Metadata = copyobject(xref,copied,page,"Metadata"),
+ PieceInfo = copyobject(xref,copied,page,"PieceInfo"),
+ Resources = copyresources(pdfdoc,xref,copied,page),
+ SeparationInfo = copyobject(xref,copied,page,"SeparationInfo"),
+ } + attr
+ if attributes then
+ for k, v in expanded(attributes) do
+ page[k] = v -- maybe nested
end
- elseif recompress then
- content = contents() -- uncompressed
- else
- local Filter = copyobject(xref,copied,contents,"Filter")
- local Length = copyobject(xref,copied,contents,"Length")
- if Length and Filter then
- nolength = true
- xobject.Length = Length
- xobject.Filter = Filter
- content = contents(false) -- uncompressed
- else
+ end
+ local content = ""
+ local nolength = nil
+ local ctype = contents.__type__
+ -- we always recompress because image object streams can not be
+ -- influenced (yet)
+ if ctype == stream_object_code then
+ if stripmarked then
+ content = contents() -- uncompressed
+ local stripped = lpdf_epdf.stripcontent(content)
+ if stripped ~= content then
+ -- report("%i bytes stripped on page %i",#content-#stripped,pagenumber or 1)
+ content = stripped
+ end
+ elseif recompress then
content = contents() -- uncompressed
+ else
+ local Filter = copyobject(xref,copied,contents,"Filter")
+ local Length = copyobject(xref,copied,contents,"Length")
+ if Length and Filter then
+ nolength = true
+ xobject.Length = Length
+ xobject.Filter = Filter
+ content = contents(false) -- uncompressed
+ else
+ content = contents() -- uncompressed
+ end
+ end
+ elseif ctype == array_object_code then
+ content = { }
+ for i=1,#contents do
+ content[i] = contents[i]() -- uncompressed
end
+ content = concat(content," ")
end
- elseif ctype == array_object_code then
- content = { }
- for i=1,#contents do
- content[i] = contents[i]() -- uncompressed
+ -- still not nice: we double wrap now
+ plugins = nil
+ local rotation = pageinfo.rotation
+ local boundingbox = pageinfo.boundingbox
+ local transform = nil
+ if rotation == 90 then
+ transform = 3
+ elseif rotation == 180 then
+ transform = 2
+ elseif rotation == 270 then
+ transform = 1
+ elseif rotation > 1 and rotation < 4 then
+ transform = rotation
end
- content = concat(content," ")
- end
- -- still not nice: we double wrap now
- plugins = nil
- local rotation = pageinfo.rotation
- local boundingbox = pageinfo.boundingbox
- local transform = nil
- if rotation == 90 then
- transform = 3
- elseif rotation == 180 then
- transform = 2
- elseif rotation == 270 then
- transform = 1
- elseif rotation > 1 and rotation < 4 then
- transform = rotation
+ xobject.BBox = pdfarray {
+ boundingbox[1] * bpfactor,
+ boundingbox[2] * bpfactor,
+ boundingbox[3] * bpfactor,
+ boundingbox[4] * bpfactor,
+ }
+ -- maybe like bitmaps
+ return createimage { -- beware: can be a img.new or a dummy
+ bbox = boundingbox,
+ transform = transform,
+ nolength = nolength,
+ nobbox = true,
+ notype = true,
+ stream = content, -- todo: no compress, pass directly also length, filter etc
+ attr = xobject(),
+ kind = images.types.stream,
+ }
+ else
+ -- maybe report an error
end
- xobject.BBox = pdfarray {
- boundingbox[1] * bpfactor,
- boundingbox[2] * bpfactor,
- boundingbox[3] * bpfactor,
- boundingbox[4] * bpfactor,
- }
- -- maybe like bitmaps
- return createimage { -- beware: can be a img.new or a dummy
- bbox = boundingbox,
- transform = transform,
- nolength = nolength,
- nobbox = true,
- notype = true,
- stream = content, -- todo: no compress, pass directly also length, filter etc
- attr = xobject(),
- kind = images.types.stream,
- }
end
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lpdf-swf.lua b/Master/texmf-dist/tex/context/base/mkiv/lpdf-swf.lua
index 44e42dc5f8d..df59fc79cf1 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lpdf-swf.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/lpdf-swf.lua
@@ -41,11 +41,7 @@ local embedimage = images.embed
local basepoints = number.dimenfactors.bp
-local f_image = formatters["%.6F 0 0 %.6F 0 0 cm /%s Do"]
-
-directives.register("pdf.stripzeros",function()
- f_image = formatters["%.6N 0 0 %.6N 0 0 cm /%s Do"]
-end)
+local f_image = formatters["%.6N 0 0 %.6N 0 0 cm /%s Do"]
local function package(image) -- see lpdf-u3d **
local boundingbox = image.bbox
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lpdf-tag.lua b/Master/texmf-dist/tex/context/base/mkiv/lpdf-tag.lua
index 0a2fe679ea8..11174c4db29 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lpdf-tag.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/lpdf-tag.lua
@@ -6,11 +6,11 @@ if not modules then modules = { } end modules ['lpdf-tag'] = {
license = "see context related readme files"
}
-local next = next
-local format, match, concat = string.format, string.match, table.concat
+local next, type = next, type
+local format, match, gmatch = string.format, string.match, string.gmatch
+local concat, sortedhash = table.concat, table.sortedhash
local lpegmatch, P, S, C = lpeg.match, lpeg.P, lpeg.S, lpeg.C
local settings_to_hash = utilities.parsers.settings_to_hash
-local sortedhash = table.sortedhash
local formatters = string.formatters
local trace_tags = false trackers.register("structures.tags", function(v) trace_tags = v end)
@@ -26,6 +26,7 @@ local nodeinjections = backends.pdf.nodeinjections
local codeinjections = backends.pdf.codeinjections
local enableaction = nodes.tasks.enableaction
+local disableaction = nodes.tasks.disableaction
local pdfdictionary = lpdf.dictionary
local pdfarray = lpdf.array
@@ -36,6 +37,7 @@ local pdfunicode = lpdf.unicode
local pdfflushobject = lpdf.flushobject
local pdfreserveobject = lpdf.reserveobject
local pdfpagereference = lpdf.pagereference
+local pdfmakenametree = lpdf.makenametree
local addtocatalog = lpdf.addtocatalog
local addtopageattributes = lpdf.addtopageattributes
@@ -62,6 +64,7 @@ local getattr = nuts.getattr
local getprev = nuts.getprev
local getnext = nuts.getnext
local getlist = nuts.getlist
+local getchar = nuts.getchar
local setlink = nuts.setlink
local setlist = nuts.setlist
@@ -75,7 +78,7 @@ local structure_kids -- delayed
local structure_ref -- delayed
local parent_ref -- delayed
local root -- delayed
-local names -- delayed
+local names = { }
local tree = { }
local elements = { }
@@ -90,29 +93,49 @@ local usedmapping = { }
----- tagsplitter = structurestags.patterns.splitter
--- local embeddedtags = false -- true will id all, for tracing
--- local f_tagid = formatters["%s-%04i"]
--- local embeddedfilelist = pdfarray() -- /AF crap
---
--- directives.register("structures.tags.embedmath",function(v)
--- if not v then
--- -- only enable
--- elseif embeddedtags == true then
--- -- already all tagged
--- elseif embeddedtags then
--- embeddedtags.math = true
--- else
--- embeddedtags = { math = true }
--- end
--- end)
+local embeddedtags = false -- true will id all, for tracing, otherwise table
+local f_tagid = formatters["%s-%04i"]
+local embeddedfilelist = pdfarray() -- /AF crap
--- function codeinjections.maptag(original,target,kind)
--- mapping[original] = { target, kind or "inline" }
--- end
+-- for testing, not that it was ever used:
+
+directives.register("structures.tags.embed",function(v)
+ if type(v) == "string" then
+ if type(embeddedtags) ~= "table" then
+ embeddedtags = { }
+ end
+ for s in gmatch(v,"([^, ]+)") do
+ embeddedtags[s] = true
+ end
+ elseif v and not embeddedtags then
+ embeddedtags = true
+ end
+end)
+
+-- for old times sake, not that it was ever used:
+
+directives.register("structures.tags.embedmath",function(v)
+ if not v then
+ -- only enable
+ elseif embeddedtags == true then
+ -- already all tagged
+ elseif embeddedtags then
+ embeddedtags.math = true
+ else
+ embeddedtags = { math = true }
+ end
+end)
+
+function codeinjections.maptag(original,target,kind)
+ mapping[original] = { target, kind or "inline" }
+end
+
+-- mostly the same as the annotations tree
local function finishstructure()
if root and #structure_kids > 0 then
- local nums, n = pdfarray(), 0
+ local nums = pdfarray()
+ local n = 0
for i=1,#tree do
n = n + 1 ; nums[n] = i - 1
n = n + 1 ; nums[n] = pdfreference(pdfflushobject(tree[i]))
@@ -120,17 +143,7 @@ local function finishstructure()
local parenttree = pdfdictionary {
Nums = nums
}
- -- we need to split names into smaller parts (e.g. alphabetic or so)
- -- we already have code for that somewhere
- if #names > 0 then
- local kids = pdfdictionary {
- Limits = pdfarray { names[1], names[#names-1] },
- Names = names,
- }
- local idtree = pdfdictionary {
- Kids = pdfarray { pdfreference(pdfflushobject(kids)) },
- }
- end
+ local idtree = pdfmakenametree(names)
--
local rolemap = pdfdictionary()
for k, v in next, usedmapping do
@@ -142,7 +155,7 @@ local function finishstructure()
Type = pdfconstant("StructTreeRoot"),
K = pdfreference(pdfflushobject(structure_kids)),
ParentTree = pdfreference(pdfflushobject(parent_ref,parenttree)),
- IDTree = #names > 0 and pdfreference(pdfflushobject(idtree)) or nil,
+ IDTree = idtree,
RoleMap = rolemap, -- sorted ?
}
pdfflushobject(structure_ref,structuretree)
@@ -191,6 +204,9 @@ end
local pdf_userproperties = pdfconstant("UserProperties")
+-- /O /Table
+-- /Headers [ ]
+
local function makeattribute(t)
if t and next(t) then
local properties = pdfarray()
@@ -209,40 +225,65 @@ end
local function makeelement(fulltag,parent)
local specification = specifications[fulltag]
- local tag = specification.tagname
- if tag == "ignore" then
+ local tagname = specification.tagname
+ local tagnameused = tagname
+ local attributes = nil
+ if tagname == "ignore" then
return false
- elseif tag == "mstackertop" or tag == "mstackerbot" or tag == "mstackermid"then
+ elseif tagname == "mstackertop" or tagname == "mstackerbot" or tagname == "mstackermid"then
-- TODO
return true
+ elseif tagname == "tabulatecell" then
+ local d = structurestags.gettabulatecell(fulltag)
+ if d and d.kind == 1 then
+ tagnameused = "tabulateheadcell"
+ end
+ elseif tagname == "tablecell" then
+ -- will become a plugin model
+ local d = structurestags.gettablecell(fulltag)
+ if d then
+ if d.kind == 1 then
+ tagnameused = "tableheadcell"
+ end
+ local rows = d.rows or 1
+ local cols = d.columns or 1
+ if rows > 1 or cols > 1 then
+ attributes = pdfdictionary {
+ O = pdfconstant("Table"),
+ RowSpan = rows > 1 and rows or nil,
+ ColSpan = cols > 1 and cols or nil,
+ }
+ end
+
+ end
end
--
local detail = specification.detail
local userdata = specification.userdata
--
- usedmapping[tag] = true
+ usedmapping[tagname] = true
--
-- specification.attribute is unique
--
local id = nil
- -- local af = nil
- -- if embeddedtags then
- -- local tagname = specification.tagname
- -- local tagindex = specification.tagindex
- -- if embeddedtags == true or embeddedtags[tagname] then
- -- id = f_tagid(tagname,tagindex)
- -- af = job.fileobjreferences.collected[id]
- -- if af then
- -- local r = pdfreference(af)
- -- af = pdfarray { r }
- -- -- embeddedfilelist[#embeddedfilelist+1] = r
- -- end
- -- end
- -- end
+ local af = nil
+ if embeddedtags then
+ local tagindex = specification.tagindex
+ if embeddedtags == true or embeddedtags[tagname] then
+ id = f_tagid(tagname,tagindex)
+ af = job.fileobjreferences.collected[id]
+ if af then
+ local r = pdfreference(af)
+ af = pdfarray { r }
+ -- embeddedfilelist[#embeddedfilelist+1] = r
+ end
+ end
+ end
--
local k = pdfarray()
local r = pdfreserveobject()
- local t = usedlabels[tag] or tag
+ local t = usedlabels[tagnameused] or tagnameused
+ -- local a = nil
local d = pdfdictionary {
Type = pdf_struct_element,
S = pdfconstant(t),
@@ -251,16 +292,15 @@ local function makeelement(fulltag,parent)
P = parent.pref,
Pg = pageref,
K = pdfreference(r),
- A = a and makeattribute(a) or nil,
+ -- A = a and makeattribute(a) or nil,
+ A = attributes,
-- Alt = " Who cares ",
-- ActualText = " Hi Hans ",
AF = af,
}
local s = pdfreference(pdfflushobject(d))
if id and names then
- local size = #names
- names[size+1] = id
- names[size+2] = s
+ names[id] = s
end
local kids = parent.kids
kids[#kids+1] = s
@@ -341,6 +381,7 @@ function nodeinjections.addtags(head)
for n, id in nextnode, head do
if id == glyph_code then
-- maybe also disc
+if getchar(n) ~= 0 then
local at = getattr(n,a_tagged) or false -- false: pagebody or so, so artifact
-- if not at then
-- range = nil
@@ -352,6 +393,7 @@ function nodeinjections.addtags(head)
elseif range then
range[4] = n -- stop
end
+end
elseif id == hlist_code or id == vlist_code then
local at = getattr(n,a_image)
if at then
@@ -363,7 +405,10 @@ function nodeinjections.addtags(head)
-- end
last = nil
else
- collectranges(getlist(n),n)
+ local list = getlist(n)
+ if list then
+ collectranges(list,n)
+ end
end
end
end
@@ -390,7 +435,6 @@ function nodeinjections.addtags(head)
local top = nil
local noftop = 0
-
local function inject(start,stop,list,literal,left,right)
local prev = getprev(start)
if prev then
@@ -401,7 +445,7 @@ function nodeinjections.addtags(head)
else
setlink(literal,start)
end
- if list and getlist(list) == start then
+ if list and not prev then
setlist(list,literal)
end
local literal = copy_node(EMCliteral)
@@ -461,7 +505,6 @@ function nodeinjections.addtags(head)
prev = prv
end
end
-
if prev then
literal = pageliteral(makecontent(prev,id,specification))
elseif ignore then
@@ -655,13 +698,36 @@ end
-- this belongs elsewhere (export is not pdf related)
-function codeinjections.enabletags(tg,lb)
- structures.tags.handler = nodeinjections.addtags
- enableaction("shipouts","structures.tags.handler")
- enableaction("shipouts","nodes.handlers.accessibility")
- enableaction("math","noads.handlers.tags")
- -- maybe also textblock
- if trace_tags then
- report_tags("enabling structure tags")
+local permitted = true
+local enabled = false
+
+function codeinjections.settaggingsupport(option)
+ if option == false then
+ if enabled then
+ disableaction("shipouts","structures.tags.handler")
+ disableaction("shipouts","nodes.handlers.accessibility") -- maybe not this one
+ disableaction("math","noads.handlers.tags")
+ enabled = false
+ end
+ if permitted then
+ if trace_tags then
+ report_tags("blocking structure tags")
+ end
+ permitted = false
+ end
+ end
+end
+
+function codeinjections.enabletags()
+ if permitted and not enabled then
+ structures.tags.handler = nodeinjections.addtags
+ enableaction("shipouts","structures.tags.handler")
+ enableaction("shipouts","nodes.handlers.accessibility")
+ enableaction("math","noads.handlers.tags")
+ -- maybe also textblock
+ if trace_tags then
+ report_tags("enabling structure tags")
+ end
+ enabled = true
end
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lpdf-u3d.lua b/Master/texmf-dist/tex/context/base/mkiv/lpdf-u3d.lua
index f6897e92d20..54dc8a22725 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lpdf-u3d.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/lpdf-u3d.lua
@@ -348,11 +348,7 @@ end
local stored_js, stored_3d, stored_pr, streams = { }, { }, { }, { }
-local f_image = formatters["q /GS gs %.6F 0 0 %.6F 0 0 cm /IM Do Q"]
-
-directives.register("pdf.stripzeros",function()
- f_image = formatters["q /GS gs %.6N 0 0 %.6N 0 0 cm /IM Do Q"]
-end)
+local f_image = formatters["q /GS gs %.6N 0 0 %.6N 0 0 cm /IM Do Q"]
local function insert3d(spec) -- width, height, factor, display, controls, label, foundname
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lpdf-wid.lua b/Master/texmf-dist/tex/context/base/mkiv/lpdf-wid.lua
index a929ed2ceb9..106eb98cca3 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lpdf-wid.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/lpdf-wid.lua
@@ -26,6 +26,8 @@ if not modules then modules = { } end modules ['lpdf-wid'] = {
local tonumber, next = tonumber, next
local gmatch, gsub, find, lower = string.gmatch, string.gsub, string.find, string.lower
+local filenameonly, basefilename, filesuffix, addfilesuffix = file.nameonly, file.basename, file.suffix, file.addsuffix
+local isfile, modificationtime = lfs.isfile, lfs.modification
local stripstring = string.strip
local settings_to_array = utilities.parsers.settings_to_array
local settings_to_hash = utilities.parsers.settings_to_hash
@@ -55,6 +57,7 @@ local v_max = variables.max
local v_yes = variables.yes
local pdfconstant = lpdf.constant
+local pdfnull = lpdf.null
local pdfdictionary = lpdf.dictionary
local pdfarray = lpdf.array
local pdfreference = lpdf.reference
@@ -222,6 +225,15 @@ local referenced = { }
local ignorereferenced = true -- fuzzy pdf spec .. twice in attachment list, can become an option
local tobesavedobjrefs = utilities.storage.allocate()
local collectedobjrefs = utilities.storage.allocate()
+local permitted = true
+local enabled = true
+
+function codeinjections.setattachmentsupport(option)
+ if option == false then
+ permitted = false
+ enabled = false
+ end
+end
local fileobjreferences = {
collected = collectedobjrefs,
@@ -238,192 +250,215 @@ end
job.register('job.fileobjreferences.collected', tobesavedobjrefs, initializer)
local function flushembeddedfiles()
- if next(filestreams) then
+ if enabled and next(filestreams) then
local e = pdfarray()
+ local f = pdfarray()
for tag, reference in sortedhash(filestreams) do
if not reference then
report_attachment("unreferenced file, tag %a",tag)
elseif referenced[tag] == "hidden" then
e[#e+1] = pdfstring(tag)
e[#e+1] = reference -- already a reference
+ f[#f+1] = reference -- collect all file description references
else
- -- -- messy spec ... when annot not in named else twice in menu list acrobat
+ -- messy spec ... when annot not in named else twice in menu list acrobat
+ f[#f+1] = reference
end
end
if #e > 0 then
lpdf.addtonames("EmbeddedFiles",pdfreference(pdfflushobject(pdfdictionary{ Names = e })))
end
+ if #f > 0 then -- PDF/A-2|3: all associated files must have a relationship to the PDF document (global or part)
+ lpdf.addtocatalog("AF", pdfreference(pdfflushobject(f))) -- global (Catalog)
+ end
end
end
lpdf.registerdocumentfinalizer(flushembeddedfiles,"embeddedfiles")
function codeinjections.embedfile(specification)
- local data = specification.data
- local filename = specification.file
- local name = specification.name or ""
- local title = specification.title or ""
- local hash = specification.hash or filename
- local keepdir = specification.keepdir -- can change
- local usedname = specification.usedname
- local filetype = specification.filetype
- local compress = specification.compress
- if filename == "" then
- filename = nil
- end
- if compress == nil then
- compress = true
- end
- if data then
- local r = filestreams[hash]
- if r == false then
- return nil
- elseif r then
- return r
- elseif not filename then
- filename = specification.tag
- if not filename or filename == "" then
- filename = specification.registered
- end
- if not filename or filename == "" then
- filename = hash
- end
+ if enabled then
+ local data = specification.data
+ local filename = specification.file
+ local name = specification.name or ""
+ local title = specification.title or ""
+ local hash = specification.hash or filename
+ local keepdir = specification.keepdir -- can change
+ local usedname = specification.usedname
+ local filetype = specification.filetype
+ local compress = specification.compress
+ local mimetype = specification.mimetype or specification.mime
+ if filename == "" then
+ filename = nil
end
- else
- if not filename then
- return nil
+ if compress == nil then
+ compress = true
end
- local r = filestreams[hash]
- if r == false then
- return nil
- elseif r then
- return r
+ if data then
+ local r = filestreams[hash]
+ if r == false then
+ return nil
+ elseif r then
+ return r
+ elseif not filename then
+ filename = specification.tag
+ if not filename or filename == "" then
+ filename = specification.registered
+ end
+ if not filename or filename == "" then
+ filename = hash
+ end
+ end
else
- local foundname = resolvers.findbinfile(filename) or ""
- if foundname == "" or not lfs.isfile(foundname) then
- filestreams[filename] = false
+ if not filename then
+ return nil
+ end
+ local r = filestreams[hash]
+ if r == false then
return nil
+ elseif r then
+ return r
else
- specification.foundname = foundname
+ local foundname = resolvers.findbinfile(filename) or ""
+ if foundname == "" or not isfile(foundname) then
+ filestreams[filename] = false
+ return nil
+ else
+ specification.foundname = foundname
+ end
end
end
- end
- -- needs to cleaned up:
- usedname = usedname ~= "" and usedname or filename or name
- local basename = keepdir == true and usedname or file.basename(usedname)
- local basename = gsub(basename,"%./","")
- local savename = name ~= "" and name or basename
- if not filetype or filetype == "" then
- filetype = name and (filename and file.suffix(filename)) or "txt"
- end
- savename = file.addsuffix(savename,filetype) -- type is mandate for proper working in viewer
- local mimetype = specification.mimetype
- local a = pdfdictionary {
- Type = pdfconstant("EmbeddedFile"),
- Subtype = mimetype and mimetype ~= "" and pdfconstant(mimetype) or nil,
- }
- local f
- if data then
- f = pdfflushstreamobject(data,a)
- specification.data = true -- signal that still data but already flushed
- else
+ -- needs to be cleaned up:
+ usedname = usedname ~= "" and usedname or filename or name
+ local basename = keepdir == true and usedname or basefilename(usedname)
+ local basename = gsub(basename,"%./","")
+ local savename = name ~= "" and name or basename
local foundname = specification.foundname or filename
- f = pdfflushstreamfileobject(foundname,a,compress)
+ if not filetype or filetype == "" then
+ filetype = name and (filename and filesuffix(filename)) or "txt"
+ end
+ savename = addfilesuffix(savename,filetype) -- type is mandate for proper working in viewer
+ local a = pdfdictionary {
+ Type = pdfconstant("EmbeddedFile"),
+ Subtype = mimetype and mimetype ~= "" and pdfconstant(mimetype) or nil,
+ }
+ local f
+ if data then
+ f = pdfflushstreamobject(data,a)
+ specification.data = true -- signal that still data but already flushed
+ else
+ local attributes = lfs.attributes(foundname)
+ local modification = modificationtime(foundname)
+ a.Params = {
+ Size = attributes.size,
+ ModDate = lpdf.pdftimestamp(modification),
+ }
+ f = pdfflushstreamfileobject(foundname,a,compress)
+ end
+ local d = pdfdictionary {
+ Type = pdfconstant("Filespec"),
+ F = pdfstring(savename),
+ -- UF = pdfstring(savename),
+ UF = pdfunicode(savename),
+ EF = pdfdictionary { F = pdfreference(f) },
+ Desc = title ~= "" and pdfunicode(title) or nil,
+ AFRelationship = pdfconstant("Unspecified"), -- Supplement, Data, Source, Alternative, Data
+ }
+ local r = pdfreference(pdfflushobject(d))
+ filestreams[hash] = r
+ return r
end
- local d = pdfdictionary {
- Type = pdfconstant("Filespec"),
- F = pdfstring(savename),
- -- UF = pdfstring(savename),
- UF = pdfunicode(savename),
- EF = pdfdictionary { F = pdfreference(f) },
- Desc = title ~= "" and pdfunicode(title) or nil,
- -- AFRelationship = pdfconstant("Source"), -- some day maybe, not mandate
- }
- local r = pdfreference(pdfflushobject(d))
- filestreams[hash] = r
- return r
end
function nodeinjections.attachfile(specification)
- local registered = specification.registered or "<unset>"
- local data = specification.data
- local hash
- local filename
- if data then
- hash = md5.HEX(data)
- else
- filename = specification.file
- if not filename or filename == "" then
- report_attachment("no file specified, using registered %a instead",registered)
- filename = registered
- specification.file = registered
+ if enabled then
+ local registered = specification.registered or "<unset>"
+ local data = specification.data
+ local hash
+ local filename
+ if data then
+ hash = md5.HEX(data)
+ else
+ filename = specification.file
+ if not filename or filename == "" then
+ report_attachment("no file specified, using registered %a instead",registered)
+ filename = registered
+ specification.file = registered
+ end
+ local foundname = resolvers.findbinfile(filename) or ""
+ if foundname == "" or not isfile(foundname) then
+ report_attachment("invalid filename %a, ignoring registered %a",filename,registered)
+ return nil
+ else
+ specification.foundname = foundname
+ end
+ hash = filename
+ end
+ specification.hash = hash
+ nofattachments = nofattachments + 1
+ local registered = specification.registered or ""
+ local title = specification.title or ""
+ local subtitle = specification.subtitle or ""
+ local author = specification.author or ""
+ local onlyname = filename and filenameonly(filename) or ""
+ if registered == "" then
+ registered = filename
end
- local foundname = resolvers.findbinfile(filename) or ""
- if foundname == "" or not lfs.isfile(foundname) then
- report_attachment("invalid filename %a, ignoring registered %a",filename,registered)
- return nil
+ if author == "" and title ~= "" then
+ author = title
+ title = onlyname or ""
+ end
+ if author == "" then
+ author = onlyname or "<unknown>"
+ end
+ if title == "" then
+ title = registered
+ end
+ if title == "" and filename then
+ title = onlyname
+ end
+ local aref = attachments[registered]
+ if not aref then
+ aref = codeinjections.embedfile(specification)
+ attachments[registered] = aref
+ end
+ local reference = specification.reference
+ if reference and aref then
+ tobesavedobjrefs[reference] = aref[1]
+ end
+ if not aref then
+ report_attachment("skipping attachment, registered %a",registered)
+ -- already reported
+ elseif specification.method == v_hidden then
+ referenced[hash] = "hidden"
else
- specification.foundname = foundname
+ referenced[hash] = "annotation"
+ local name, appearance = analyzesymbol(specification.symbol,attachment_symbols)
+ local flags = specification.flags or 0 -- to keep it expandable
+ local d = pdfdictionary {
+ Subtype = pdfconstant("FileAttachment"),
+ FS = aref,
+ Contents = pdfunicode(title),
+ Name = name,
+ NM = pdfstring("attachment:"..nofattachments),
+ T = author ~= "" and pdfunicode(author) or nil,
+ Subj = subtitle ~= "" and pdfunicode(subtitle) or nil,
+ C = analyzecolor(specification.colorvalue,specification.colormodel),
+ CA = analyzetransparency(specification.transparencyvalue),
+ AP = appearance,
+ OC = analyzelayer(specification.layer),
+ -- F = pdfnull(), -- another rediculous need to satisfy validation
+ F = bit32.band(bit32.bor(flags,4),(1023-1-2-32-256)), -- set 3, clear 1,2,6,9; PDF 32000-1, p385
+ }
+ local width = specification.width or 0
+ local height = specification.height or 0
+ local depth = specification.depth or 0
+ local box = hpack_node(nodeinjections.annotation(width,height,depth,d()))
+ box.width = width
+ box.height = height
+ box.depth = depth
+ return box
end
- hash = filename
- end
- specification.hash = hash
- nofattachments = nofattachments + 1
- local registered = specification.registered or ""
- local title = specification.title or ""
- local subtitle = specification.subtitle or ""
- local author = specification.author or ""
- if registered == "" then
- registered = filename
- end
- if author == "" and title ~= "" then
- author = title
- title = filename or ""
- end
- if author == "" then
- author = filename or "<unknown>"
- end
- if title == "" then
- title = registered
- end
- local aref = attachments[registered]
- if not aref then
- aref = codeinjections.embedfile(specification)
- attachments[registered] = aref
- end
- local reference = specification.reference
- if reference and aref then
- tobesavedobjrefs[reference] = aref[1]
- end
- if not aref then
- report_attachment("skipping attachment, registered %a",registered)
- -- already reported
- elseif specification.method == v_hidden then
- referenced[hash] = "hidden"
- else
- referenced[hash] = "annotation"
- local name, appearance = analyzesymbol(specification.symbol,attachment_symbols)
- local d = pdfdictionary {
- Subtype = pdfconstant("FileAttachment"),
- FS = aref,
- Contents = pdfunicode(title),
- Name = name,
- NM = pdfstring("attachment:"..nofattachments),
- T = author ~= "" and pdfunicode(author) or nil,
- Subj = subtitle ~= "" and pdfunicode(subtitle) or nil,
- C = analyzecolor(specification.colorvalue,specification.colormodel),
- CA = analyzetransparency(specification.transparencyvalue),
- AP = appearance,
- OC = analyzelayer(specification.layer),
- }
- local width = specification.width or 0
- local height = specification.height or 0
- local depth = specification.depth or 0
- local box = hpack_node(nodeinjections.annotation(width,height,depth,d()))
- box.width = width
- box.height = height
- box.depth = depth
- return box
end
end
@@ -431,6 +466,8 @@ function codeinjections.attachmentid(filename) -- not used in context
return filestreams[filename]
end
+-- Comments
+
local nofcomments = 0
local usepopupcomments = false
@@ -478,11 +515,7 @@ function nodeinjections.comment(specification) -- brrr: seems to be done twice
local subtitle = specification.subtitle or "" -- as author
local author = specification.author or ""
local option = settings_to_hash(specification.option or "")
- if author == "" then
- if title == "" then
- title = tag
- end
- else
+ if author ~= "" then
if subtitle == "" then
subtitle = title
elseif title ~= "" then
@@ -490,6 +523,9 @@ function nodeinjections.comment(specification) -- brrr: seems to be done twice
end
title = author
end
+ if title == "" then
+ title = tag
+ end
local content, richcontent = checkcontent(text,option)
local d = pdfdictionary {
Subtype = pdfconstant("Text"),
diff --git a/Master/texmf-dist/tex/context/base/mkiv/luat-bwc.lua b/Master/texmf-dist/tex/context/base/mkiv/luat-bwc.lua
index 993de7bf3f4..a86514fa85b 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/luat-bwc.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/luat-bwc.lua
@@ -8,25 +8,25 @@ if not modules then modules = { } end modules ['luat-bwc'] = {
-- backward compatibility
-if not tex.wd then
-
- local box = tex.box
-
- local wd = { } setmetatable(wd, {
- __index = function(t,k) local bk = box[k] return bk and bk.width or 0 end,
- __newindex = function(t,k,v) local bk = box[k] if bk then bk.width = v end end,
- } )
-
- local ht = { } setmetatable(ht, {
- __index = function(t,k) local bk = box[k] return bk and bk.height or 0 end,
- __newindex = function(t,k,v) local bk = box[k] if bk then bk.height = v end end,
- } )
-
- local dp = { } setmetatable(dp, {
- __index = function(t,k) local bk = box[k] return bk and bk.depth or 0 end,
- __newindex = function(t,k,v) local bk = box[k] if bk then bk.depth = v end end,
- } )
-
- -- tex.wd, tex.ht, tex.dp = wd, ht, dp
-
-end
+-- if not tex.wd then
+--
+-- local box = tex.box
+--
+-- local wd = { } setmetatable(wd, {
+-- __index = function(t,k) local bk = box[k] return bk and bk.width or 0 end,
+-- __newindex = function(t,k,v) local bk = box[k] if bk then bk.width = v end end,
+-- } )
+--
+-- local ht = { } setmetatable(ht, {
+-- __index = function(t,k) local bk = box[k] return bk and bk.height or 0 end,
+-- __newindex = function(t,k,v) local bk = box[k] if bk then bk.height = v end end,
+-- } )
+--
+-- local dp = { } setmetatable(dp, {
+-- __index = function(t,k) local bk = box[k] return bk and bk.depth or 0 end,
+-- __newindex = function(t,k,v) local bk = box[k] if bk then bk.depth = v end end,
+-- } )
+--
+-- tex.wd, tex.ht, tex.dp = wd, ht, dp
+--
+-- end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/luat-cnf.lua b/Master/texmf-dist/tex/context/base/mkiv/luat-cnf.lua
index 5e3f026e95b..4939b05c39c 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/luat-cnf.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/luat-cnf.lua
@@ -31,7 +31,8 @@ texconfig.param_size = 25000
texconfig.save_size = 100000
texconfig.stack_size = 10000
texconfig.function_size = 32768
-texconfig.properties_size = 65536
+texconfig.properties_size = 10000
+texconfig.fix_mem_init = 750000
local stub = [[
@@ -60,18 +61,37 @@ function texconfig.init()
libraries = { -- we set it here as we want libraries also 'indexed'
basiclua = {
- "string", "table", "coroutine", "debug", "file", "io", "lpeg", "math", "os", "package", "bit32",
+ -- always
+ "string", "table", "coroutine", "debug", "file", "io", "lpeg", "math", "os", "package",
+ -- bonus
+ "bit32", "utf8",
},
- basictex = { -- noad
- "callback", "font", "img", "lang", "lua", "node", "pdf", "status", "tex", "texconfig", "texio", "token",
+ basictex = {
+ -- always
+ "callback", "font", "lang", "lua", "node", "status", "tex", "texconfig", "texio", "token",
+ -- not in luametatex
+ "img", "pdf",
},
extralua = {
- "gzip", "zip", "zlib", "lfs", "ltn12", "mime", "socket", "md5", "fio", "unicode", "utf",
+ -- not in luametatex
+ "unicode", "utf", "gzip", "zip", "zlib",
+ -- in luametatex
+ "xzip", "xmath", "xcomplex", "basexx",
+ -- maybe some day in luametatex
+ "lz4", "lzo",
+ -- always (mime can go)
+ "lfs","socket", "mime", "md5", "sha2", "fio", "sio",
},
extratex = {
- "epdf", "kpse", "mplib", -- "fontloader",
+ -- not in luametatex
+ "kpse",
+ -- always
+ "pdfe", "mplib",
+ -- in luametatex
+ "pdfdecode", "pngdecode",
},
obsolete = {
+ "epdf",
"fontloader", -- can be filled by luat-log
"kpse",
},
@@ -102,7 +122,7 @@ function texconfig.init()
local tv = type(gv)
if tv == "table" then
for k, v in next, gv do
- keys[k] = tostring(v) -- true -- by tostring we cannot call overloades functions (security)
+ keys[k] = tostring(v) -- true -- by tostring we cannot call overloads functions (security)
end
end
lib[v] = keys
@@ -121,16 +141,29 @@ function texconfig.init()
-- shortcut and helper
- local setbytecode = lua.setbytecode
- local getbytecode = lua.getbytecode
+ local setbytecode = lua.setbytecode
+ local getbytecode = lua.getbytecode
+ local callbytecode = lua.callbytecode or function(i)
+ local b = getbytecode(i)
+ if type(b) == "function" then
+ b()
+ return true
+ else
+ return false
+ end
+ end
local function init(start)
local i = start
local t = os.clock()
while true do
- local b = getbytecode(i)
+ -- local b = callbytecode(i)
+ local e, b = pcall(callbytecode,i)
+ if not e then
+ print(string.format("\nfatal error : unable to load bytecode register %%i, maybe wipe the cache first\n",i))
+ os.exit()
+ end
if b then
- b() ;
setbytecode(i,nil) ;
i = i + 1
else
@@ -218,7 +251,9 @@ local function makestub()
t[#t+1] = format("texconfig.%s=%s",v,tv)
end
end
- io.savedata(name,format("%s\n\n%s",concat(t,"\n"),format(stub,firsttable,tostring(CONTEXTLMTXMODE) or 0)))
+ t[#t+1] = ""
+ t[#t+1] = format(stub,firsttable,tostring(CONTEXTLMTXMODE or 0))
+ io.savedata(name,concat(t,"\n"))
logs.newline()
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/luat-cod.lua b/Master/texmf-dist/tex/context/base/mkiv/luat-cod.lua
index c667f3eccb5..3125495b47b 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/luat-cod.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/luat-cod.lua
@@ -31,11 +31,11 @@ texconfig.param_size = 25000
texconfig.save_size = 100000
texconfig.stack_size = 10000
texconfig.function_size = 32768
-texconfig.properties_size = 65536
+texconfig.properties_size = 10000
+texconfig.fix_mem_init = 750000
-- registering bytecode chunks
------ bytecode = lua.bytecode or { } -- we use functions
local bytedata = lua.bytedata or { }
local bytedone = lua.bytedone or { }
@@ -136,29 +136,23 @@ if LUATEXENGINE == nil then
or (find(status.banner,"LuajitTeX",1,true) and "luajittex" or "luatex")
end
-if LUATEXVERION == nil then
- LUATEXVERSION = status.luatex_revision
+if LUATEXVERSION == nil then
LUATEXVERSION = status.luatex_version/100
- -- + tonumber(LUATEXVERSION)/1000
- + (tonumber(LUATEXVERSION) or (string.byte(LUATEXVERSION)-string.byte("a")+10))/1000
+ + tonumber(status.luatex_revision)/10000
end
if CONTEXTLMTXMODE == nil then
- if status.obj_ptr == nil then
- CONTEXTLMTXMODE = 2
- else
- CONTEXTLMTXMODE = 0
- for i=1,#arg do if arg[i] == "--c:lmtx" then
- CONTEXTLMTXMODE, pdf, img = 1, nil, nil
- break
- end end
- end
+ CONTEXTLMTXMODE = LUATEXENGINE == "luametatex" and 1 or 0
end
if LUATEXFUNCTIONALITY == nil then
LUATEXFUNCTIONALITY = status.development_id or 6346
end
+if LUATEXFORMATID == nil then
+ LUATEXFORMATID = status.format_id or 0
+end
+
if JITSUPPORTED == nil then
JITSUPPORTED = LUATEXENGINE == "luajittex" or jit
end
@@ -263,6 +257,10 @@ local function find_write_file(id,name)
return target_file(name)
end
+local function find_log_file(name)
+ return target_file(name)
+end
+
local function open_read_file(name)
local f = io.open(name,'rb')
return {
@@ -281,6 +279,7 @@ local open_data_file = open_read_file
callback.register('find_read_file' , find_read_file )
callback.register('open_read_file' , open_read_file )
callback.register('find_write_file', find_write_file)
+callback.register('find_log_file', find_log_file)
callback.register('find_data_file' , find_data_file )
callback.register('open_data_file' , open_data_file )
diff --git a/Master/texmf-dist/tex/context/base/mkiv/luat-env.lua b/Master/texmf-dist/tex/context/base/mkiv/luat-env.lua
index e0c69d2079b..1620a26e521 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/luat-env.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/luat-env.lua
@@ -11,7 +11,7 @@
-- sense. Much of this evolved before bytecode arrays were available and so a lot of
-- code has disappeared already.
-local rawset, rawget, loadfile = rawset, rawget, loadfile
+local rawset, loadfile = rawset, loadfile
local gsub = string.gsub
local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end)
@@ -71,6 +71,17 @@ function environment.texfile(filename)
end
function environment.luafile(filename) -- needs checking
+
+ if CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 and file.suffix(filename) == "lua" then
+ -- no "tex", as that's pretty slow when not found (suffixes get appended, shouldn't happen)
+ -- trackers.enable("resolvers.*")
+ local resolved = resolvers.findfile(file.replacesuffix(filename,"lmt")) or ""
+ -- trackers.disable("resolvers.*")
+ if resolved ~= "" then
+ return resolved
+ end
+ end
+
local resolved = resolvers.findfile(filename,'tex') or ""
if resolved ~= "" then
return resolved
diff --git a/Master/texmf-dist/tex/context/base/mkiv/luat-fio.lua b/Master/texmf-dist/tex/context/base/mkiv/luat-fio.lua
index 2996ae66ab0..26db46a88ab 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/luat-fio.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/luat-fio.lua
@@ -117,6 +117,8 @@ if not resolvers.initialized() then
-- register('read_cidmap_file' , function(file) return loadbinfile(file,"cidmap") end, true)
register('find_write_file' , function(id,name) return name end, true)
+
+ register('find_log_file' , function(name) return name end, true)
register('find_format_file' , function(name) return name end, true)
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/luat-fmt.lua b/Master/texmf-dist/tex/context/base/mkiv/luat-fmt.lua
index 586c5948e98..5502e1a1da2 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/luat-fmt.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/luat-fmt.lua
@@ -13,8 +13,10 @@ local luasuffixes = utilities.lua.suffixes
local report_format = logs.reporter("resolvers","formats")
-local function primaryflags()
- local arguments = environment.arguments
+-- this is a bit messy: we also handle flags in mtx-context so best we
+-- can combine this some day (all here)
+
+local function primaryflags(arguments)
local flags = { }
if arguments.silent then
flags[#flags+1] = "--interaction=batchmode"
@@ -25,8 +27,7 @@ local function primaryflags()
return concat(flags," ")
end
-local function secondaryflags()
- local arguments = environment.arguments
+local function secondaryflags(arguments)
local trackers = arguments.trackers
local directives = arguments.directives
local flags = { }
@@ -48,6 +49,9 @@ local function secondaryflags()
if arguments.ansi then
flags[#flags+1] = "--c:ansi"
end
+ if arguments.ansilog then
+ flags[#flags+1] = "--c:ansilog"
+ end
if arguments.strip then
flags[#flags+1] = "--c:strip"
end
@@ -63,12 +67,13 @@ end
local template = [[--ini %primaryflags% --lua=%luafile% %texfile% %secondaryflags% %dump% %redirect%]]
local checkers = {
- primaryflags = "string",
- secondaryflags = "string",
+ primaryflags = "verbose", -- "flags"
+ secondaryflags = "verbose", -- "flags"
luafile = "readable", -- "cache"
texfile = "readable", -- "cache"
redirect = "string",
dump = "string",
+ binarypath = "string",
}
local runners = {
@@ -95,50 +100,110 @@ local runners = {
},
}
-function environment.make_format(name,arguments)
- local engine = environment.ownmain or "luatex"
- local silent = environment.arguments.silent
- local errors = environment.arguments.errors
- -- change to format path (early as we need expanded paths)
- local olddir = dir.current()
- local path = caches.getwritablepath("formats",engine) or "" -- maybe platform
- if path ~= "" then
- lfs.chdir(path)
- end
- report_format("using format path %a",dir.current())
- -- check source file
- local texsourcename = file.addsuffix(name,"mkiv")
- local fulltexsourcename = resolvers.findfile(texsourcename,"tex") or ""
+local function validbinarypath()
+ -- if environment.arguments.addbinarypath then
+ if not environment.arguments.nobinarypath then
+ local path = environment.ownpath or file.dirname(environment.ownname)
+ if path and path ~= "" then
+ path = dir.expandname(path)
+ if path ~= "" and lfs.isdir(path) then
+ return path
+ end
+ end
+ end
+end
+
+function environment.make_format(formatname)
+ -- first we set up the engine and normally that information is provided
+ -- by the engine ... when we move to luametatex we could decide to simplfy
+ -- all the following
+ local arguments = environment.arguments
+ local engine = environment.ownmain or "luatex"
+ local silent = arguments.silent
+ local errors = arguments.errors
+ -- now we locate the to be used source files ... there are some variants that we
+ -- need to take care
+ local texsourcename = ""
+ local texsourcepath = ""
+ local fulltexsourcename = ""
+ if engine == "luametatex" then
+ texsourcename = file.addsuffix(formatname,"mkxl")
+ fulltexsourcename = resolvers.findfile(texsourcename,"tex") or ""
+ end
+ if fulltexsourcename == "" then
+ texsourcename = file.addsuffix(formatname,"mkiv")
+ fulltexsourcename = resolvers.findfile(texsourcename,"tex") or ""
+ end
if fulltexsourcename == "" then
- texsourcename = file.addsuffix(name,"tex")
+ texsourcename = file.addsuffix(formatname,"tex")
fulltexsourcename = resolvers.findfile(texsourcename,"tex") or ""
end
if fulltexsourcename == "" then
- report_format("no tex source file with name %a (mkiv or tex)",name)
- lfs.chdir(olddir)
+ report_format("no tex source file with name %a (mkiv or tex)",formatname)
return
- else
- report_format("using tex source file %a",fulltexsourcename)
end
- local texsourcepath = dir.expandname(file.dirname(fulltexsourcename)) -- really needed
- -- check specification
- local specificationname = file.replacesuffix(fulltexsourcename,"lus")
- local fullspecificationname = resolvers.findfile(specificationname,"tex") or ""
- if fullspecificationname == "" then
- specificationname = file.join(texsourcepath,"context.lus")
- fullspecificationname = resolvers.findfile(specificationname,"tex") or ""
+ report_format("using tex source file %a",fulltexsourcename)
+ -- this is tricky: we normally have an expanded path but when we don't have one,
+ -- the current path gets appended
+ fulltexsourcename = dir.expandname(fulltexsourcename)
+ texsourcepath = file.dirname(fulltexsourcename)
+ if not lfs.isfile(fulltexsourcename) then
+ report_format("no accessible tex source file with name %a",fulltexsourcename)
+ return
end
+ -- we're getting there, that is: we have a file that specifies the context format;
+ -- in addition to that file we need a stub for setting up lua as we start rather
+ -- minimalistic
+ local specificationname = "context.lus"
+ local specificationpath = ""
+ local fullspecificationname = resolvers.findfile(specificationname) or ""
if fullspecificationname == "" then
- report_format("unknown stub specification %a",specificationname)
- lfs.chdir(olddir)
+ report_format("unable to locate specification file %a",specificationname)
+ return
+ end
+ report_format("using specification file %a",fullspecificationname)
+ -- let's expand the found name and so an extra check
+ fullspecificationname = dir.expandname(fullspecificationname)
+ specificationpath = file.dirname(fullspecificationname)
+ if texsourcepath ~= specificationpath then
+ report_format("tex source file and specification file are on different paths")
+ return
+ end
+ -- let's do an additional check here, if only because we then have a bit better
+ -- feedback on what goes wrong
+ if not lfs.isfile(fulltexsourcename) then
+ report_format("no accessible tex source file with name %a",fulltexsourcename)
+ return
+ end
+ if not lfs.isfile(fullspecificationname) then
+ report_format("no accessible specification file with name %a",fulltexsourcename)
+ return
+ end
+ -- we're still going strong
+ report_format("using tex source path %a",texsourcepath)
+ -- we will change tot the format path because some local files will be created
+ -- in the process and we don't want clutter
+ local validformatpath = caches.getwritablepath("formats",engine) or ""
+ local startupdir = dir.current()
+ if validformatpath == "" then
+ report_format("invalid format path, insufficient write access")
+ return
+ end
+ -- in case we have a qualified path, we need to do this before we change
+ -- because we can have half qualified paths (in lxc)
+ local binarypath = validbinarypath()
+ report_format("changing to format path %a",validformatpath)
+ lfs.chdir(validformatpath)
+ if dir.current() ~= validformatpath then
+ report_format("unable to change to format path %a",validformatpath)
return
end
- local specificationpath = file.dirname(fullspecificationname)
- -- load specification
+ -- we're now ready for making the format which we do on the first found
+ -- writable path
local usedluastub = nil
local usedlualibs = dofile(fullspecificationname)
if type(usedlualibs) == "string" then
- usedluastub = file.join(file.dirname(fullspecificationname),usedlualibs)
+ usedluastub = file.join(specificationpath,usedlualibs)
elseif type(usedlualibs) == "table" then
report_format("using stub specification %a",fullspecificationname)
local texbasename = file.basename(name)
@@ -157,56 +222,68 @@ function environment.make_format(name,arguments)
end
else
report_format("invalid stub specification %a",fullspecificationname)
- lfs.chdir(olddir)
+ lfs.chdir(startupdir)
return
end
- -- generate format
+ -- we're ready to go now but first we check if we actually do have a runner
+ -- for this engine ... we'd better have one
+ local runner = runners[engine]
+ if not runner then
+ report_format("the format %a cannot be generated, no runner available for engine %a",name,engine)
+ lfs.chdir(startupdir)
+ return
+ end
+ -- now we can generate the format, where we use a couple of flags,
+ -- split into two categories
+ local primaryflags = primaryflags(arguments)
+ local secondaryflags = secondaryflags(arguments)
local specification = {
- primaryflags = primaryflags(),
- secondaryflags = secondaryflags(),
+ binarypath = binarypath,
+ primaryflags = primaryflags,
+ secondaryflags = secondaryflags,
luafile = quoted(usedluastub),
texfile = quoted(fulltexsourcename),
dump = os.platform == "unix" and "\\\\dump" or "\\dump",
}
- local runner = runners[engine]
- if not runner then
- report_format("format %a cannot be generated, no runner available for engine %a",name,engine)
- elseif silent then
- statistics.starttiming()
+ if silent then
specification.redirect = "> temp.log"
- local result = runner(specification)
- local runtime = statistics.stoptiming()
- if result ~= 0 then
- print(format("%s silent make > fatal error when making format %q",engine,name)) -- we use a basic print
- else
- print(format("%s silent make > format %q made in %.3f seconds",engine,name,runtime)) -- we use a basic print
- end
+ end
+ statistics.starttiming()
+ local result = runner(specification)
+ local runtime = statistics.stoptiming()
+ if silent then
os.remove("temp.log")
- else
- runner(specification)
- end
- -- remove related mem files
- local pattern = file.removesuffix(file.basename(usedluastub)).."-*.mem"
- -- report_format("removing related mplib format with pattern %a", pattern)
- local mp = dir.glob(pattern)
- if mp then
- for i=1,#mp do
- local name = mp[i]
- report_format("removing related mplib format %a", file.basename(name))
- os.remove(name)
- end
end
- lfs.chdir(olddir)
+ -- some final report
+ report_format()
+ if binarypath and binarypath ~= "" then
+ report_format("binary path : %s",binarypath or "?")
+ end
+ report_format("format path : %s",validformatpath)
+ report_format("luatex engine : %s",engine)
+ report_format("lua startup file : %s",usedluastub)
+ if primaryflags ~= "" then
+ report_format("primary flags : %s",primaryflags)
+ end
+ if secondaryflags ~= "" then
+ report_format("secondary flags : %s",secondaryflags)
+ end
+ report_format("context file : %s",fulltexsourcename)
+ report_format("run time : %.3f seconds",runtime)
+ report_format("return value : %s",result == 0 and "okay" or "error")
+ report_format()
+ -- last we go back to the home base
+ lfs.chdir(startupdir)
end
-local template = [[%flags% --fmt=%fmtfile% --lua=%luafile% %texfile% %more%]]
+local template = [[%primaryflags% --fmt=%fmtfile% --lua=%luafile% %texfile% %secondaryflags%]]
local checkers = {
- flags = "string",
- more = "string",
- fmtfile = "readable", -- "cache"
- luafile = "readable", -- "cache"
- texfile = "readable", -- "cache"
+ primaryflags = "verbose",
+ secondaryflags = "verbose",
+ fmtfile = "readable", -- "cache"
+ luafile = "readable", -- "cache"
+ texfile = "readable", -- "cache"
}
local runners = {
@@ -217,6 +294,13 @@ local runners = {
checkers = checkers,
reporter = report_format,
},
+ luametatex = sandbox.registerrunner {
+ name = "run luametatex format",
+ program = "luametatex",
+ template = template,
+ checkers = checkers,
+ reporter = report_format,
+ },
luajittex = sandbox.registerrunner {
name = "run luajittex format",
program = "luajittex",
@@ -226,40 +310,67 @@ local runners = {
},
}
-function environment.run_format(name,data,more)
- if name and name ~= "" then
- local engine = environment.ownmain or "luatex"
- local barename = file.removesuffix(name)
- local fmtname = caches.getfirstreadablefile(file.addsuffix(barename,"fmt"),"formats",engine)
- if fmtname == "" then
- fmtname = resolvers.findfile(file.addsuffix(barename,"fmt")) or ""
- end
- fmtname = resolvers.cleanpath(fmtname)
- if fmtname == "" then
- report_format("no format with name %a",name)
- else
- local barename = file.removesuffix(name) -- expanded name
- local luaname = file.addsuffix(barename,"luc")
- if not lfs.isfile(luaname) then
- luaname = file.addsuffix(barename,"lua")
- end
- if not lfs.isfile(luaname) then
- report_format("using format name %a",fmtname)
- report_format("no luc/lua file with name %a",barename)
- else
- local runner = runners[engine]
- if not runner then
- report_format("format %a cannot be run, no runner available for engine %a",name,engine)
- else
- runner {
- flags = primaryflags(),
- fmtfile = quoted(barename),
- luafile = quoted(luaname),
- texfile = quoted(data),
- more = more,
- }
- end
- end
- end
+function environment.run_format(formatname,scriptname,filename,primaryflags,secondaryflags,verbose)
+ local engine = environment.ownmain or "luatex"
+ if not formatname or formatname == "" then
+ report_format("missing format name")
+ return
+ end
+ if not scriptname or scriptname == "" then
+ report_format("missing script name")
+ return
+ end
+ if not lfs.isfile(formatname) or not lfs.isfile(scriptname) then
+ formatname, scriptname = resolvers.locateformat(formatname)
+ end
+ if not formatname or formatname == "" then
+ report_format("invalid format name")
+ return
+ end
+ if not scriptname or scriptname == "" then
+ report_format("invalid script name")
+ return
+ end
+ local runner = runners[engine]
+ if not runner then
+ report_format("format %a cannot be run, no runner available for engine %a",file.nameonly(name),engine)
+ return
+ end
+ if not filename then
+ filename ""
+ end
+ local binarypath = validbinarypath()
+ local specification = {
+ binarypath = binarypath,
+ primaryflags = primaryflags or "",
+ secondaryflags = secondaryflags or "",
+ fmtfile = quoted(formatname),
+ luafile = quoted(scriptname),
+ texfile = filename ~= "" and quoted(filename) or "",
+ }
+ statistics.starttiming()
+ local result = runner(specification)
+ local runtime = statistics.stoptiming()
+ if verbose then
+ report_format()
+ if binarypath and binarypath ~= "" then
+ report_format("binary path : %s",binarypath)
+ end
+ report_format("luatex engine : %s",engine)
+ report_format("lua startup file : %s",scriptname)
+ report_format("tex format file : %s",formatname)
+ if filename ~= "" then
+ report_format("tex input file : %s",filename)
+ end
+ if primaryflags ~= "" then
+ report_format("primary flags : %s",primaryflags)
+ end
+ if secondaryflags ~= "" then
+ report_format("secondary flags : %s",secondaryflags)
+ end
+ report_format("run time : %.3f seconds",runtime)
+ report_format("return value : %s",result == 0 and "okay" or "error")
+ report_format()
end
+ return result
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/luat-ini.lua b/Master/texmf-dist/tex/context/base/mkiv/luat-ini.lua
index ffd402c7752..cec0161e7b0 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/luat-ini.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/luat-ini.lua
@@ -26,18 +26,20 @@ if not global then
end
LUATEXVERSION = status.luatex_version/100
- + tonumber(status.luatex_revision)/1000
+ + tonumber(status.luatex_revision)/10000
LUATEXENGINE = status.luatex_engine and string.lower(status.luatex_engine)
or (string.find(status.banner,"LuajitTeX",1,true) and "luajittex" or "luatex")
LUATEXFUNCTIONALITY = status.development_id or 6346
+LUATEXFORMATID = status.format_id or 0
+
JITSUPPORTED = LUATEXENGINE == "luajittex" or jit
INITEXMODE = status.ini_version
-CONTEXTLMTXMODE = CONTEXTLMTXMODE or (status.obj_ptr == nil and 2 or 1)
+CONTEXTLMTXMODE = CONTEXTLMTXMODE or (LUATEXENGINE == "luametatex" and 1) or 0
function os.setlocale()
-- no need for a message
diff --git a/Master/texmf-dist/tex/context/base/mkiv/luat-ini.mkiv b/Master/texmf-dist/tex/context/base/mkiv/luat-ini.mkiv
index da5a3a3109f..d1d829be978 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/luat-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/luat-ini.mkiv
@@ -265,23 +265,23 @@
% \def\syst_helpers_checked_stripped_csname#1%
% {\if\noexpand#1\letterbackslash\else#1\fi}
-\ifdefined\normalluadef
+% \ifdefined\normalluadef
\normalprotected\def\installctxfunction#1#2% expandable
{\edef\m_syst_name{\csstring#1}%
- \global\expandafter\normalluadef\csname\m_syst_name\endcsname\ctxcommand{ctxfunction("#2",true)}\relax}
+ \global\expandafter\normalluadef\csname\m_syst_name\endcsname\ctxcommand{ctxfunction(\!!bs#2\!!es,true)}\relax}
\normalprotected\def\installctxscanner#1#2% expandable
{\edef\m_syst_name{\csstring#1}%
- \global\expandafter\normalluadef\csname\m_syst_name\endcsname\ctxcommand{ctxscanner("\m_syst_name","#2",true)}\relax}
+ \global\expandafter\normalluadef\csname\m_syst_name\endcsname\ctxcommand{ctxscanner("\m_syst_name",\!!bs#2\!!es,true)}\relax}
\normalprotected\def\installprotectedctxfunction#1#2% protected
{\edef\m_syst_name{\csstring#1}%
- \global\normalprotected\expandafter\normalluadef\csname\m_syst_name\endcsname\ctxcommand{ctxfunction("#2",true)}\relax}
+ \global\normalprotected\expandafter\normalluadef\csname\m_syst_name\endcsname\ctxcommand{ctxfunction(\!!bs#2\!!es,true)}\relax}
\normalprotected\def\installprotectedctxscanner#1#2% protected
{\edef\m_syst_name{\csstring#1}%
- \global\normalprotected\expandafter\normalluadef\csname\m_syst_name\endcsname\ctxcommand{ctxscanner("\m_syst_name","#2",true)}\relax}
+ \global\normalprotected\expandafter\normalluadef\csname\m_syst_name\endcsname\ctxcommand{ctxscanner("\m_syst_name",\!!bs#2\!!es,true)}\relax}
\normalprotected\def\resetctxscanner#1%
{\edef\m_syst_name{\csstring#1}%
@@ -292,57 +292,57 @@
% \let\installprotectedctxfunctioncall\installprotectedctxfunction
% \let\installprotectedctxscannercall \installprotectedctxscanner
-\else
-
- \ifdefined\luafunctioncall \else
- \normalprotected\def\luafunctioncall{\luafunction}
- \fi
-
- \normalprotected\def\installctxfunction#1#2% expandable
- {\edef\m_syst_name{\csstring#1}%
- \global\expandafter\chardef\csname\??luafunction\m_syst_name\endcsname\ctxcommand{ctxfunction("#2",true)}\relax
- \expandafter\xdef\csname\m_syst_name\endcsname{\noexpand\luafunction\csname\??luafunction\m_syst_name\endcsname}}
-
- \normalprotected\def\installctxscanner#1#2% expandable
- {\edef\m_syst_name{\csstring#1}%
- \global\expandafter\chardef\csname\??luafunction\m_syst_name\endcsname\ctxcommand{ctxscanner("\m_syst_name","#2",true)}\relax
- \expandafter\xdef\csname\m_syst_name\endcsname{\noexpand\luafunction\csname\??luafunction\m_syst_name\endcsname}}
-
- \normalprotected\def\installprotectedctxfunction#1#2% protected
- {\edef\m_syst_name{\csstring#1}%
- \global\expandafter\chardef\csname\??luafunction\m_syst_name\endcsname\ctxcommand{ctxfunction("#2",true)}\relax
- \expandafter\xdef\csname\m_syst_name\endcsname{\noexpand\luafunctioncall\csname\??luafunction\m_syst_name\endcsname}}
-
- \normalprotected\def\installprotectedctxscanner#1#2% protected
- {\edef\m_syst_name{\csstring#1}%
- \global\expandafter\chardef\csname\??luafunction\m_syst_name\endcsname\ctxcommand{ctxscanner("\m_syst_name","#2",true)}\relax
- \expandafter\xdef\csname\m_syst_name\endcsname{\noexpand\luafunctioncall\csname\??luafunction\m_syst_name\endcsname}}
-
- \normalprotected\def\resetctxscanner#1%
- {\edef\m_syst_name{\csstring#1}%
- \global\expandafter\chardef\csname\??luafunction\m_syst_name\endcsname\zerocount
- \expandafter\glet\csname\m_syst_name\endcsname\relax}
-
- % \normalprotected\def\installctxfunctioncall#1#2%
- % {\edef\m_syst_name{\csstring#1}%
- % \global\expandafter\chardef\csname\??luafunction\m_syst_name\endcsname\ctxcommand{ctxfunction("#2",true)}\relax
- % \expandafter\xdef\csname\m_syst_name\endcsname{\luafunctioncall\csname\??luafunction\m_syst_name\endcsname}}
- %
- % \normalprotected\def\installctxscannercall#1#2%
- % {\edef\m_syst_name{\csstring#1}%
- % \global\expandafter\chardef\csname\??luafunction\m_syst_name\endcsname\ctxcommand{ctxscanner("\m_syst_name","#2",true)}\relax
- % \expandafter\xdef\csname\m_syst_name\endcsname{\luafunctioncall\csname\??luafunction\m_syst_name\endcsname}}
- %
- % \normalprotected\def\installprotectedctxfunctioncall#1#2%
- % {\edef\m_syst_name{\csstring#1}%
- % \global\expandafter\chardef\csname\??luafunction\m_syst_name\endcsname\ctxcommand{ctxfunction("#2",true)}\relax
- % \normalprotected\expandafter\xdef\csname\m_syst_name\endcsname{\luafunctioncall\csname\??luafunction\m_syst_name\endcsname}}
- %
- % \normalprotected\def\installprotectedctxscannercall#1#2%
- % {\edef\m_syst_name{\csstring#1}%
- % \global\expandafter\chardef\csname\??luafunction\m_syst_name\endcsname\ctxcommand{ctxscanner("\m_syst_name","#2",true)}\relax
- % \normalprotected\expandafter\xdef\csname\m_syst_name\endcsname{\luafunctioncall\csname\??luafunction\m_syst_name\endcsname}}
-
-\fi
+% \else
+%
+% \ifdefined\luafunctioncall \else
+% \normalprotected\def\luafunctioncall{\luafunction}
+% \fi
+%
+% \normalprotected\def\installctxfunction#1#2% expandable
+% {\edef\m_syst_name{\csstring#1}%
+% \global\expandafter\chardef\csname\??luafunction\m_syst_name\endcsname\ctxcommand{ctxfunction("#2",true)}\relax
+% \expandafter\xdef\csname\m_syst_name\endcsname{\noexpand\luafunction\csname\??luafunction\m_syst_name\endcsname}}
+%
+% \normalprotected\def\installctxscanner#1#2% expandable
+% {\edef\m_syst_name{\csstring#1}%
+% \global\expandafter\chardef\csname\??luafunction\m_syst_name\endcsname\ctxcommand{ctxscanner("\m_syst_name","#2",true)}\relax
+% \expandafter\xdef\csname\m_syst_name\endcsname{\noexpand\luafunction\csname\??luafunction\m_syst_name\endcsname}}
+%
+% \normalprotected\def\installprotectedctxfunction#1#2% protected
+% {\edef\m_syst_name{\csstring#1}%
+% \global\expandafter\chardef\csname\??luafunction\m_syst_name\endcsname\ctxcommand{ctxfunction("#2",true)}\relax
+% \expandafter\xdef\csname\m_syst_name\endcsname{\noexpand\luafunctioncall\csname\??luafunction\m_syst_name\endcsname}}
+%
+% \normalprotected\def\installprotectedctxscanner#1#2% protected
+% {\edef\m_syst_name{\csstring#1}%
+% \global\expandafter\chardef\csname\??luafunction\m_syst_name\endcsname\ctxcommand{ctxscanner("\m_syst_name","#2",true)}\relax
+% \expandafter\xdef\csname\m_syst_name\endcsname{\noexpand\luafunctioncall\csname\??luafunction\m_syst_name\endcsname}}
+%
+% \normalprotected\def\resetctxscanner#1%
+% {\edef\m_syst_name{\csstring#1}%
+% \global\expandafter\chardef\csname\??luafunction\m_syst_name\endcsname\zerocount
+% \expandafter\glet\csname\m_syst_name\endcsname\relax}
+%
+% % \normalprotected\def\installctxfunctioncall#1#2%
+% % {\edef\m_syst_name{\csstring#1}%
+% % \global\expandafter\chardef\csname\??luafunction\m_syst_name\endcsname\ctxcommand{ctxfunction("#2",true)}\relax
+% % \expandafter\xdef\csname\m_syst_name\endcsname{\luafunctioncall\csname\??luafunction\m_syst_name\endcsname}}
+% %
+% % \normalprotected\def\installctxscannercall#1#2%
+% % {\edef\m_syst_name{\csstring#1}%
+% % \global\expandafter\chardef\csname\??luafunction\m_syst_name\endcsname\ctxcommand{ctxscanner("\m_syst_name","#2",true)}\relax
+% % \expandafter\xdef\csname\m_syst_name\endcsname{\luafunctioncall\csname\??luafunction\m_syst_name\endcsname}}
+% %
+% % \normalprotected\def\installprotectedctxfunctioncall#1#2%
+% % {\edef\m_syst_name{\csstring#1}%
+% % \global\expandafter\chardef\csname\??luafunction\m_syst_name\endcsname\ctxcommand{ctxfunction("#2",true)}\relax
+% % \normalprotected\expandafter\xdef\csname\m_syst_name\endcsname{\luafunctioncall\csname\??luafunction\m_syst_name\endcsname}}
+% %
+% % \normalprotected\def\installprotectedctxscannercall#1#2%
+% % {\edef\m_syst_name{\csstring#1}%
+% % \global\expandafter\chardef\csname\??luafunction\m_syst_name\endcsname\ctxcommand{ctxscanner("\m_syst_name","#2",true)}\relax
+% % \normalprotected\expandafter\xdef\csname\m_syst_name\endcsname{\luafunctioncall\csname\??luafunction\m_syst_name\endcsname}}
+%
+% \fi
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/luat-lib.mkiv b/Master/texmf-dist/tex/context/base/mkiv/luat-lib.mkiv
index 6660323698b..0ffd1dd4076 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/luat-lib.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/luat-lib.mkiv
@@ -19,18 +19,13 @@
\registerctxluafile{util-sac}{optimize}
\registerctxluafile{util-sto}{} % could also be done in trac-deb.mkiv
\registerctxluafile{util-pck}{}
-% \registerctxluafile{util-seq}{}
-%registerctxluafile{util-mrg}{} % not needed in context itself, only mtxrun
-%registerctxluafile{util-lua}{} % moved
\registerctxluafile{util-prs}{}
\registerctxluafile{util-fmt}{}
\registerctxluafile{util-dim}{}
-%registerctxluafile{trac-inf}{}
\registerctxluafile{trac-set}{}
\registerctxluafile{trac-log}{}
\registerctxluafile{trac-inf}{}
-%registerctxluafile{trac-pro}{}
\registerctxluafile{util-lua}{}
\registerctxluafile{util-deb}{} % could also be done in trac-deb.mkiv
@@ -43,16 +38,12 @@
\registerctxluafile{util-soc-imp-reset} {}
\registerctxluafile{util-soc-imp-socket} {}
-%registerctxluafile{util-soc-imp-copas} {}
\registerctxluafile{util-soc-imp-ltn12} {}
-%registerctxluafile{util-soc-imp-mbox} {}
\registerctxluafile{util-soc-imp-mime} {}
\registerctxluafile{util-soc-imp-url} {}
\registerctxluafile{util-soc-imp-headers}{}
\registerctxluafile{util-soc-imp-http} {}
\registerctxluafile{util-soc-imp-tp} {}
-%registerctxluafile{util-soc-imp-ftp} {}
-%registerctxluafile{util-soc-imp-smtp} {}
\ifcase\contextlmtxmode\else
\registerctxluafile{util-zip}{}
@@ -66,12 +57,12 @@
\registerctxluafile{data-res}{}
\registerctxluafile{data-inp}{}
\registerctxluafile{data-out}{}
-\registerctxluafile{data-fil}{}
+\registerctxluafile{data-fil}{} % opener gets overloaded in data-tex
-\registerctxluafile{data-pre}{}
-\registerctxluafile{data-tex}{}
+\registerctxluafile{data-pre}{} % after data-res
+\registerctxluafile{data-bin}{} % before data-tex
+\registerctxluafile{data-tex}{} % after data-pre
\registerctxluafile{data-vir}{}
-\registerctxluafile{data-bin}{}
\registerctxluafile{data-zip}{}
%registerctxluafile{data-crl}{}
\registerctxluafile{data-sch}{}
@@ -82,7 +73,9 @@
\registerctxluafile{data-use}{}
\registerctxluafile{data-aux}{}
-\registerctxluafile{util-lib}{}
+% \ifcase\contextlmtxmode
+% \registerctxluafile{util-lib}{}
+% \fi
\registerctxluafile{luat-cbk}{}
\registerctxluafile{luat-run}{}
@@ -95,7 +88,7 @@
\registerctxluafile{luat-env}{}
\registerctxluafile{luat-exe}{} % simplified
\registerctxluafile{luat-iop}{} % simplified
-\registerctxluafile{luat-bwc}{}
+%registerctxluafile{luat-bwc}{}
\registerctxluafile{trac-lmx}{} % might become l-lmx or luat-lmx
\registerctxluafile{luat-mac}{}
%registerctxluafile{luat-prp}{} % for the moment of not much use
diff --git a/Master/texmf-dist/tex/context/base/mkiv/luat-mac.lua b/Master/texmf-dist/tex/context/base/mkiv/luat-mac.lua
index 44630b19427..e6789a2338a 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/luat-mac.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/luat-mac.lua
@@ -22,6 +22,7 @@ local rep, sub = string.rep, string.sub
local setmetatable = setmetatable
local filesuffix = file.suffix
local convertlmxstring = lmx and lmx.convertstring
+local savedata = io.savedata
local pushtarget, poptarget = logs.pushtarget, logs.poptarget
@@ -195,35 +196,27 @@ local checker = P("%") * (1 - newline - P("macros"))^0
-- maybe namespace
-local macros = { } resolvers.macros = macros
+local resolvers = resolvers
+
+local macros = { }
+resolvers.macros = macros
+
+local loadtexfile = resolvers.loadtexfile
function macros.preprocessed(str,strip)
return lpegmatch(parser,str,1,strip)
end
function macros.convertfile(oldname,newname) -- beware, no testing on oldname == newname
- local data = resolvers.loadtexfile(oldname)
+ local data = loadtexfile(oldname)
data = interfaces.preprocessed(data) or "" -- interfaces not yet defined
- io.savedata(newname,data)
+ savedata(newname,data)
end
function macros.version(data)
return lpegmatch(checker,data)
end
--- function macros.processmkvi(str,filename)
--- if filename and filesuffix(filename) == "mkvi" or lpegmatch(checker,str) == "mkvi" then
--- local oldsize = #str
--- str = lpegmatch(parser,str,1,true) or str
--- pushtarget("logfile")
--- report_macros("processed mkvi file %a, delta %s",filename,oldsize-#str)
--- poptarget()
--- end
--- return str
--- end
---
--- utilities.sequencers.appendaction(resolvers.openers.helpers.textfileactions,"system","resolvers.macros.processmkvi")
-
-- the document variables hack is temporary
local processors = { }
@@ -268,6 +261,9 @@ function processors.mkxi(str,filename)
return str
end
+processors.mklx = processors.mkvi
+processors.mkxl = processors.mkiv
+
function macros.processmk(str,filename)
if filename then
local suffix = filesuffix(filename)
@@ -279,8 +275,18 @@ function macros.processmk(str,filename)
return str
end
+local function validvi(filename,str)
+ local suffix = filesuffix(filename)
+ if suffix == "mkvi" or suffix == "mklx" then
+ return true
+ else
+ local check = lpegmatch(checker,str)
+ return check == "mkvi" or check == "mklx"
+ end
+end
+
function macros.processmkvi(str,filename)
- if filename and filesuffix(filename) == "mkvi" or lpegmatch(checker,str) == "mkvi" then
+ if filename and filename ~= "" and validvi(filename,str) then
local oldsize = #str
str = lpegmatch(parser,str,1,true) or str
pushtarget("logfile")
@@ -290,39 +296,35 @@ function macros.processmkvi(str,filename)
return str
end
-local sequencers = utilities.sequencers
-
-if sequencers then
-
- sequencers.appendaction(resolvers.openers.helpers.textfileactions,"system","resolvers.macros.processmk")
- sequencers.appendaction(resolvers.openers.helpers.textfileactions,"system","resolvers.macros.processmkvi")
-
-end
+macros.processmklx = macros.processmkvi
-- bonus
-if resolvers.schemes then
+local schemes = resolvers.schemes
+
+if schemes then
local function handler(protocol,name,cachename)
local hashed = url.hashed(name)
local path = hashed.path
if path and path ~= "" then
- local str = resolvers.loadtexfile(path)
- if filesuffix(path) == "mkvi" or lpegmatch(checker,str) == "mkvi" then
+ local str = loadtexfile(path)
+ if validvi(path,str) then
-- already done automatically
- io.savedata(cachename,str)
+ savedata(cachename,str)
else
local result = lpegmatch(parser,str,1,true) or str
pushtarget("logfile")
report_macros("processed scheme %a, delta %s",filename,#str-#result)
poptarget()
- io.savedata(cachename,result)
+ savedata(cachename,result)
end
end
return cachename
end
- resolvers.schemes.install('mkvi',handler,1) -- this will cache !
+ schemes.install('mkvi',handler,1)
+ schemes.install('mklx',handler,1)
end
@@ -414,7 +416,7 @@ local encodepattern = Cs((encodecomment + 1)^0)
local decodecomment = P(commentsignal) / "%%%%" -- why doubles here?
local decodepattern = Cs((decodecomment + 1)^0)
-function resolvers.macros.encodecomment(str)
+function macros.encodecomment(str)
if txtcatcodes and tex.catcodetable == txtcatcodes then
return lpegmatch(encodepattern,str) or str
else
@@ -422,7 +424,7 @@ function resolvers.macros.encodecomment(str)
end
end
-function resolvers.macros.decodecomment(str) -- normally not needed
+function macros.decodecomment(str) -- normally not needed
return txtcatcodes and lpegmatch(decodepattern,str) or str
end
@@ -430,9 +432,22 @@ end
-- resolvers.macros.encodecommentpattern = encodepattern
-- resolvers.macros.decodecommentpattern = decodepattern
-function resolvers.macros.enablecomment(thecatcodes)
- if not txtcatcodes then
- txtcatcodes = thecatcodes or catcodes.numbers.txtcatcodes
- utilities.sequencers.appendaction(resolvers.openers.helpers.textlineactions,"system","resolvers.macros.encodecomment")
+local sequencers = utilities.sequencers
+local appendaction = sequencers and sequencers.appendaction
+
+if appendaction then
+
+ local textlineactions = resolvers.openers.helpers.textlineactions
+ local textfileactions = resolvers.openers.helpers.textfileactions
+
+ appendaction(textfileactions,"system","resolvers.macros.processmk")
+ appendaction(textfileactions,"system","resolvers.macros.processmkvi")
+
+ function macros.enablecomment(thecatcodes)
+ if not txtcatcodes then
+ txtcatcodes = thecatcodes or catcodes.numbers.txtcatcodes
+ appendaction(textlineactions,"system","resolvers.macros.encodecomment")
+ end
end
+
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/luat-run.lua b/Master/texmf-dist/tex/context/base/mkiv/luat-run.lua
index 00cc6507502..d29a463b88c 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/luat-run.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/luat-run.lua
@@ -7,8 +7,9 @@ if not modules then modules = { } end modules ['luat-run'] = {
}
local next = next
-local format, find = string.format, string.find
+local find = string.find
local insert, remove = table.insert, table.remove
+local osexit = os.exit
-- trace_job_status is also controlled by statistics.enable that is set via the directive system.nostatistics
@@ -118,14 +119,18 @@ end
-- For Taco ...
-local sequencers = utilities.sequencers
-local appendgroup = sequencers.appendgroup
-local appendaction = sequencers.appendaction
-local wrapupactions = sequencers.new { }
+local sequencers = utilities.sequencers
+local appendgroup = sequencers.appendgroup
+local appendaction = sequencers.appendaction
+local wrapupactions = sequencers.new { }
+local cleanupactions = sequencers.new { }
appendgroup(wrapupactions,"system")
appendgroup(wrapupactions,"user")
+appendgroup(cleanupactions,"system")
+appendgroup(cleanupactions,"user")
+
local function wrapup_run()
local runner = wrapupactions.runner
if runner then
@@ -133,10 +138,26 @@ local function wrapup_run()
end
end
+local function cleanup_run()
+ local runner = cleanupactions.runner
+ if runner then
+ runner()
+ end
+end
+
function luatex.wrapup(action)
appendaction(wrapupactions,"user",action)
end
+function luatex.cleanup(action)
+ appendaction(cleanupactions,"user",action)
+end
+
+function luatex.abort()
+ cleanup_run()
+ osexit(1)
+end
+
appendaction(wrapupactions,"system",synctex.wrapup)
-- this can be done later
@@ -204,7 +225,8 @@ end
luatex.registerstopactions(luatex.cleanuptempfiles)
--- filenames
+-- Reporting filenames has been simplified since lmtx because we don't need the
+-- traditional () {} <> etc methods (read: that directive option was never chosen).
local report_open = logs.reporter("open source")
local report_close = logs.reporter("close source")
@@ -215,13 +237,20 @@ local register = callbacks.register
local level = 0
local total = 0
local stack = { }
-local all = false
function luatex.currentfile()
return stack[#stack] or tex.jobname
end
-local function report_start(name)
+local function report_start(name,rest)
+ if rest then
+ -- luatex
+ if name ~= 1 then
+ insert(stack,false)
+ return
+ end
+ name = rest
+ end
if find(name,"virtual://",1,true) then
insert(stack,false)
else
@@ -244,39 +273,6 @@ local function report_stop()
end
end
-if CONTEXTLMTXMODE < 2 then
-
- local types = {
- "data",
- "font map",
- "image",
- "font subset",
- "full font",
- }
-
- local do_report_start = report_start
- local do_report_stop = report_stop
-
- report_start = function(left,name)
- if not left then
- -- skip
- elseif left ~= 1 then
- if all then
- report_load("type %a, name %a",types[left],name or "?")
- end
- else
- do_report_start(name)
- end
- end
-
- report_stop = function(right)
- if level == 1 or not right or right == 1 then
- do_report_stop()
- end
- end
-
-end
-
local function report_none()
end
@@ -284,17 +280,9 @@ register("start_file",report_start)
register("stop_file", report_stop)
directives.register("system.reportfiles", function(v)
- if v == "noresources" then
- all = false
- register("start_file",report_start)
- register("stop_file", report_stop)
- elseif toboolean(v) or v == "all" then
- all = true
+ if v then
register("start_file",report_start)
register("stop_file", report_stop)
- elseif v == "traditional" then
- register("start_file",nil)
- register("stop_file", nil)
else
register("start_file",report_none)
register("stop_file", report_none)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/luat-sto.lua b/Master/texmf-dist/tex/context/base/mkiv/luat-sto.lua
index ce891765aa9..620de9a15b4 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/luat-sto.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/luat-sto.lua
@@ -72,7 +72,7 @@ if environment.initex then
end
local dumped = serialize(original,target)
if trace_storage then
- report_storage('saving %a in slot %a, size %s',message,max,#dumped)
+ report_storage("saving %a in slot %a, size %s",message,max,#dumped)
end
-- we don't need tracing in such tables
dumped = concat({ definition, comment, dumped },"\n")
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lxml-css.lua b/Master/texmf-dist/tex/context/base/mkiv/lxml-css.lua
index b0f5c9b72f6..96dc626f7db 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lxml-css.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/lxml-css.lua
@@ -146,45 +146,116 @@ if context then
end
-local pattern = Cf( Ct("") * (
- Cg(
- Cc("style") * (
- C("italic")
- + C("oblique")
- + C("slanted") / "oblique"
- )
- + Cc("variant") * (
- (C("smallcaps") + C("caps")) / "small-caps"
- )
- + Cc("weight") *
- C("bold")
- + Cc("family") * (
- (C("mono") + C("type")) / "monospace" -- just ignore the "space(d)"
- + (C("sansserif") + C("sans")) / "sans-serif" -- match before serif
- + C("serif")
+
+do
+
+ local p_digit = lpegpatterns.digit
+ local p_unquoted = Cs(lpegpatterns.unquoted)
+ local p_size = (S("+-")^0 * (p_digit^0 * P(".") * p_digit^1 + p_digit^1 * P(".") + p_digit^1)) / tonumber
+ * C(P("p") * S("txc") + P("e") * S("xm") + S("mc") * P("m") + P("in") + P("%"))
+
+ local pattern = Cf( Ct("") * (
+ Cg(
+ Cc("style") * (
+ C("italic")
+ + C("oblique")
+ + C("slanted") / "oblique"
+ )
+ + Cc("variant") * (
+ (C("smallcaps") + C("caps")) / "small-caps"
+ )
+ + Cc("weight") * (
+ C("bold")
+ )
+ + Cc("family") * (
+ (C("mono") + C("type")) / "monospace" -- just ignore the "space(d)"
+ + (C("sansserif") + C("sans")) / "sans-serif" -- match before serif
+ + C("serif")
+ )
+ + Cc("size") * Ct(p_size)
)
- )
---+ P("\\") * (
--- P("bf") * ( Cg ( Cc("weight") * Cc("bold") ) )
--- + P("bi") * ( Cg ( Cc("weight") * Cc("bold") )
--- * Cg ( Cc("style") * Cc("italic") ) )
--- + P("bs") * ( Cg ( Cc("weight") * Cc("bold") )
--- * Cg ( Cc("style") * Cc("oblique") ) )
--- + P("it") * ( Cg ( Cc("style") * Cc("italic") ) )
--- + P("sl") * ( Cg ( Cc("style") * Cc("oblique") ) )
--- + P("sc") * ( Cg ( Cc("variant") * Cc("small-caps") ) )
--- + P("tt") * ( Cg ( Cc("family") * Cc("monospace") ) )
---)
- + P(1)
-)^0 , rawset)
-
-function css.fontspecification(str)
- return str and lpegmatch(pattern,lower(str))
-end
+ + P(1)
+ )^0 , rawset)
+
+ function css.fontspecification(str)
+ return str and lpegmatch(pattern,lower(str))
+ end
+
+ -- These map onto context!
+
+ function css.style(str)
+ if str and str ~= "" then
+ str = lower(str)
+ if str == "italic" then
+ return "italic"
+ elseif str == "slanted" or str == "oblique" then
+ return "slanted"
+ end
+ end
+ return "normal"
+ end
+
+ function css.variant(str) -- will change to a feature
+ if str and str ~= "" then
+ str = lower(str)
+ if str == "small-caps" or str == "caps" or str == "smallcaps" then
+ return "caps"
+ end
+ end
+ return "normal"
+ end
+
+ function css.weight(str)
+ if str and str ~= "" then
+ str = lower(str)
+ if str == "bold" then
+ return "bold"
+ end
+ end
+ return "normal"
+ end
+
+ function css.family(str)
+ if str and str ~= "" then
+ str = lower(str)
+ if str == "mono" or str == "type" or str == "monospace" then
+ return "mono"
+ elseif str == "sansserif" or str == "sans" then
+ return "sans"
+ elseif str == "serif" then
+ return "serif"
+ else
+ -- what if multiple ...
+ return lpegmatch(p_unquoted,str) or str
+ end
+ end
+ end
+
+ function css.size(str,factors)
+ local size, unit
+ if type(str) == "table" then
+ size, unit = str[1], str[2]
+ elseif str and str ~= "" then
+ size, unit = lpegmatch(p_size,lower(str))
+ end
+ if size and unit then
+ if factors then
+ return (factors[unit] or 1) * size
+ else
+ return size, unit
+ end
+ end
+ end
+
+ function css.colorspecification(str)
+ if str and str ~= "" then
+ local c = attributes.colors.values[tonumber(str)]
+ if c then
+ return format("rgb(%s%%,%s%%,%s%%)",c[3]*100,c[4]*100,c[5]*100)
+ end
+ end
+ end
-function css.colorspecification(str)
- local c = str and attributes.colors.values[tonumber(str)]
- return c and format("rgb(%s%%,%s%%,%s%%)",c[3]*100,c[4]*100,c[5]*100)
end
-- The following might be handy. It hooks into the normal parser as <selector>
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lxml-ini.lua b/Master/texmf-dist/tex/context/base/mkiv/lxml-ini.lua
index b255477cb71..348ecbbe45c 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lxml-ini.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/lxml-ini.lua
@@ -82,7 +82,7 @@ implement { name = "xmllast", actions = lxml.last, arg
implement { name = "xmllastatt", actions = lxml.lastatt }
implement { name = "xmllastmatch", actions = lxml.lastmatch }
implement { name = "xmllastpar", actions = lxml.lastpar }
-implement { name = "xmlload", actions = lxml.load, arguments = "3 strings" }
+implement { name = "xmlloadfile", actions = lxml.load, arguments = "3 strings" }
implement { name = "xmlloadbuffer", actions = lxml.loadbuffer, arguments = "3 strings" }
implement { name = "xmlloaddata", actions = lxml.loaddata, arguments = "3 strings" }
implement { name = "xmlloaddirectives", actions = lxml.directives.load, arguments = "string" }
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lxml-ini.mkiv b/Master/texmf-dist/tex/context/base/mkiv/lxml-ini.mkiv
index 5cb4bb22d65..09358e11cba 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lxml-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/lxml-ini.mkiv
@@ -38,9 +38,14 @@
\def\xmlconcat #1#2#3{\clf_xmlconcat {#1}{#2}{\detokenize{#3}}}
\def\xmlconcatrange #1#2#3#4#5{\clf_xmlconcatrange{#1}{#2}{#3}{#4}{\detokenize{#5}}}
-\def\xmlload #1#2{\clf_xmlload {#1}{#2}{\directxmlparameter\c!compress}}
-\def\xmlloadbuffer #1#2{\clf_xmlloadbuffer {#1}{#2}{\directxmlparameter\c!compress}}
-\def\xmlloaddata #1#2{\clf_xmlloaddata {#1}{#2}{\directxmlparameter\c!compress}}
+
+%D Maybe I should add \type {\unexpanded} here:
+
+\def\xmlloadfile #1#2{\clf_xmlloadfile {#1}{#2}{\directxmlparameter\c!compress}}
+\def\xmlloadbuffer#1#2{\clf_xmlloadbuffer{#1}{#2}{\directxmlparameter\c!compress}}
+\def\xmlloaddata #1#2{\clf_xmlloaddata {#1}{#2}{\directxmlparameter\c!compress}}
+
+\let\xmlload\xmlloadfile
% aliased
@@ -317,6 +322,8 @@
\unexpanded\def\startxmldisplayverbatim
{\dosingleempty\lxml_start_display_verbatim}
+\let\stopxmldisplayverbatim\relax
+
\def\lxml_start_display_verbatim[#1]%
{\startpacked
\edef\currenttyping{#1}%
@@ -334,6 +341,8 @@
\unexpanded\def\startxmlinlineverbatim
{\dosingleempty\lxml_start_inline_verbatim}
+\let\stopxmlinlineverbatim\relax
+
\unexpanded\def\lxml_start_inline_verbatim[#1]%
{\begingroup
\edef\currenttype{#1}%
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lxml-lpt.lua b/Master/texmf-dist/tex/context/base/mkiv/lxml-lpt.lua
index 392c1a4014e..5bcdfbabcb0 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lxml-lpt.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/lxml-lpt.lua
@@ -614,27 +614,6 @@ local lp_doequal = P("=") / "=="
local lp_or = P("|") / " or "
local lp_and = P("&") / " and "
--- local lp_builtin = (
--- P("text") / "(ll.dt[1] or '')" + -- fragile
--- P("content") / "ll.dt" +
--- P("name") / "((ll.ns~='' and ll.ns..':'..ll.tg) or ll.tg)" +
--- P("tag") / "ll.tg" +
--- P("position") / "l" + -- is element in finalizer
--- P("firstindex") / "1" +
--- P("lastindex") / "(#ll.__p__.dt or 1)" +
--- P("firstelement") / "1" +
--- P("lastelement") / "(ll.__p__.en or 1)" +
--- P("first") / "1" +
--- P("last") / "#list" +
--- P("rootposition") / "order" +
--- P("order") / "order" +
--- P("element") / "(ll.ei or 1)" +
--- P("index") / "(ll.ni or 1)" +
--- P("match") / "(ll.mi or 1)" +
--- P("namespace") / "ll.ns" +
--- P("ns") / "ll.ns"
--- ) * ((spaces * P("(") * spaces * P(")"))/"")
-
local builtin = {
text = "(ll.dt[1] or '')", -- fragile
content = "ll.dt",
@@ -647,6 +626,8 @@ local builtin = {
lastindex = "(#ll.__p__.dt or 1)",
lastelement = "(ll.__p__.en or 1)",
last = "#list",
+ list = "list",
+ self = "ll",
rootposition = "order",
order = "order",
element = "(ll.ei or 1)",
@@ -654,6 +635,7 @@ local builtin = {
match = "(ll.mi or 1)",
namespace = "ll.ns",
ns = "ll.ns",
+
}
local lp_builtin = lpeg.utfchartabletopattern(builtin)/builtin * ((spaces * P("(") * spaces * P(")"))/"")
@@ -806,7 +788,9 @@ end
local function register_expression(expression)
local converted = lpegmatch(converter,expression)
- local runner = load(format(template_e,converted))
+ local wrapped = format(template_e,converted)
+ local runner = load(wrapped)
+ -- print(wrapped)
runner = (runner and runner()) or function() errorrunner_e(expression,converted) end
return { kind = "expression", expression = expression, converted = converted, evaluator = runner }
end
@@ -1306,6 +1290,21 @@ expressions.count = function(e,pattern) -- what if pattern == empty or nil
return pattern and (collected and #collected) or 0
end
+expressions.attribute = function(e,name,value)
+ if type(e) == "table" and name then
+ local a = e.at
+ if a then
+ local v = a[name]
+ if value then
+ return v == value
+ else
+ return v
+ end
+ end
+ end
+ return nil
+end
+
-- external
-- expressions.oneof = function(s,...)
@@ -1371,7 +1370,7 @@ function expressions.contains(str,pattern)
return false
end
-function xml.expressions.idstring(str)
+function expressions.idstring(str)
return type(str) == "string" and gsub(str,"^#","") or ""
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lxml-tab.lua b/Master/texmf-dist/tex/context/base/mkiv/lxml-tab.lua
index 1ef83c47de7..8f6379f2f8b 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lxml-tab.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/lxml-tab.lua
@@ -920,6 +920,15 @@ local function handlenewline()
currentline = currentline + 1
end
+-- first = ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#x00F8-#x02FF] |
+-- [#x0370-#x037D] | [#x037F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] |
+-- [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] |
+-- [#x10000-#xEFFFF]
+-- rest = "-" | "." | [0-9] | #xB7 | [#x300-#x36F] | [#x203F-#x2040]
+-- name = first + (first + rest)^1
+--
+-- We assume utf and do no real checking!
+
local spacetab = S(' \t')
local space = S(' \r\n\t')
local newline = lpegpatterns.newline / handlenewline
@@ -933,7 +942,11 @@ local slash = P('/')
local colon = P(':')
local semicolon = P(';')
local ampersand = P('&')
-local valid = R('az', 'AZ', '09') + S('_-.')
+----- valid_0 = lpegpatterns.utf8two + lpegpatterns.utf8three + lpegpatterns.utf8four
+local valid_0 = R("\128\255") -- basically any encoding without checking (fast)
+local valid_1 = R('az', 'AZ') + S('_') + valid_0
+local valid_2 = valid_1 + R('09') + S('-.')
+local valid = valid_1 * valid_2^0
local name_yes = C(valid^1) * colon * C(valid^1)
local name_nop = C(P(true)) * C(valid^1)
local name = name_yes + name_nop
@@ -971,8 +984,9 @@ end
local function entityfile(pattern,k,v,n)
if n then
local okay, data
- if resolvers then
- okay, data = resolvers.loadbinfile(n)
+ local loadbinfile = resolvers and resolvers.loadbinfile
+ if loadbinfile then
+ okay, data = loadbinfile(n)
else
data = io.loaddata(n)
okay = data and data ~= ""
@@ -1146,13 +1160,15 @@ publicentityfile +
end
-grammar_parsed_text_one_nop ,
-grammar_parsed_text_two_nop ,
-grammar_unparsed_text_nop = install(space, spacing, anything)
+local
+ grammar_parsed_text_one_nop ,
+ grammar_parsed_text_two_nop ,
+ grammar_unparsed_text_nop = install(space, spacing, anything)
-grammar_parsed_text_one_yes ,
-grammar_parsed_text_two_yes ,
-grammar_unparsed_text_yes = install(space_nl, spacing_nl, anything_nl)
+local
+ grammar_parsed_text_one_yes ,
+ grammar_parsed_text_two_yes ,
+ grammar_unparsed_text_yes = install(space_nl, spacing_nl, anything_nl)
-- maybe we will add settings to result as well
diff --git a/Master/texmf-dist/tex/context/base/mkiv/lxml-tex.lua b/Master/texmf-dist/tex/context/base/mkiv/lxml-tex.lua
index ae3edba5613..9ab8cafc60a 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/lxml-tex.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/lxml-tex.lua
@@ -92,7 +92,7 @@ local forceraw = false
local p_texescape = patterns.texescape
-local tokenizedcs = context.tokenizedcs
+local tokenizedxmlw = context.tokenizedcs and context.tokenizedcs.xmlw
directives.enable("xml.path.keeplastmatch")
@@ -337,7 +337,7 @@ do
noferrors = noferrors + 1
errors[filename] = errors[filename] + 1
end
- errorhandler(filename)
+ errorhandler(message) -- (filename)
end
logs.registerfinalactions(function()
@@ -501,15 +501,14 @@ function lxml.checkindex(name)
return root and root.index or 0
end
-if tokenizedcs then
+if tokenizedxmlw then
function lxml.withindex(name,n,command) -- will change as name is always there now
local i, p = lpegmatch(splitter,n)
- local w = tokenizedcs.xmlw
if p then
- contextsprint(ctxcatcodes,w,"{",command,"}{",n,"}")
+ contextsprint(ctxcatcodes,tokenizedxmlw,"{",command,"}{",n,"}")
else
- contextsprint(ctxcatcodes,w,"{",command,"}{",name,"::",n,"}")
+ contextsprint(ctxcatcodes,tokenizedxmlw,"{",command,"}{",name,"::",n,"}")
end
end
@@ -770,7 +769,7 @@ end)
local tex_element
-if tokenizedcs then
+if tokenizedxmlw then
tex_element = function(e,handlers)
if setfilename then
@@ -788,16 +787,15 @@ if tokenizedcs then
local tc = type(command)
if tc == "string" then
local rootname, ix = e.name, e.ix
- local w = tokenizedcs.xmlw
if rootname then
if not ix then
addindex(rootname,false,true)
ix = e.ix
end
- contextsprint(ctxcatcodes,w,"{",command,"}{",rootname,"::",ix,"}")
+ contextsprint(ctxcatcodes,tokenizedxmlw,"{",command,"}{",rootname,"::",ix,"}")
else
report_lxml("fatal error: no index for %a",command)
- contextsprint(ctxcatcodes,w,"{",command,"}{",ix or 0,"}")
+ contextsprint(ctxcatcodes,tokenizedxmlw,"{",command,"}{",ix or 0,"}")
end
elseif tc == "function" then
command(e)
@@ -1488,11 +1486,10 @@ end
local command
-if tokenizedcs then
+if tokenizedxmlw then
command = function(collected,cmd,otherwise)
local n = collected and #collected
- local w = tokenizedcs.xmlw
if n and n > 0 then
local wildcard = find(cmd,"*",1,true)
for c=1,n do -- maybe optimize for n=1
@@ -1506,13 +1503,13 @@ if tokenizedcs then
if not ix or not name then
report_lxml("no valid node index for element %a using command %s",name or "?",cmd)
elseif wildcard then
- contextsprint(ctxcatcodes,w,"{",(gsub(cmd,"%*",e.tg)),"}{",name,"::",ix,"}")
+ contextsprint(ctxcatcodes,tokenizedxmlw,"{",(gsub(cmd,"%*",e.tg)),"}{",name,"::",ix,"}")
else
- contextsprint(ctxcatcodes,w,"{",cmd,"}{",name,"::",ix,"}")
+ contextsprint(ctxcatcodes,tokenizedxmlw,"{",cmd,"}{",name,"::",ix,"}")
end
end
elseif otherwise then
- contextsprint(ctxcatcodes,w,"{",otherwise,"}{#1}")
+ contextsprint(ctxcatcodes,tokenizedxmlw,"{",otherwise,"}{#1}")
end
end
@@ -2215,16 +2212,15 @@ function lxml.direct(id)
end
end
-if tokenizedcs then
+if tokenizedxmlw then
function lxml.command(id,pattern,cmd)
local i, p = getid(id,true)
- local collected = xmlapplylpath(getid(i),pattern)
+ local collected = xmlapplylpath(getid(i),pattern) -- again getid?
if collected then
local nc = #collected
if nc > 0 then
local rootname = p or i.name
- local w = tokenizedcs.xmlw
for c=1,nc do
local e = collected[c]
local ix = e.ix
@@ -2232,7 +2228,7 @@ if tokenizedcs then
addindex(rootname,false,true)
ix = e.ix
end
- contextsprint(ctxcatcodes,w,"{",cmd,"}{",rootname,"::",ix,"}")
+ contextsprint(ctxcatcodes,tokenizedxmlw,"{",cmd,"}{",rootname,"::",ix,"}")
end
end
end
@@ -2242,7 +2238,7 @@ else
function lxml.command(id,pattern,cmd)
local i, p = getid(id,true)
- local collected = xmlapplylpath(getid(i),pattern)
+ local collected = xmlapplylpath(getid(i),pattern) -- again getid?
if collected then
local nc = #collected
if nc > 0 then
diff --git a/Master/texmf-dist/tex/context/base/mkiv/m-fonts-plugins.mkiv b/Master/texmf-dist/tex/context/base/mkiv/m-fonts-plugins.mkiv
index 154e4780427..255a2ac7217 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/m-fonts-plugins.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/m-fonts-plugins.mkiv
@@ -193,6 +193,7 @@
[mode=plug,
features=harfbuzz,
% method=binary,
+% method=internal,
script=arab,language=dflt,
% ccmp=yes,
% init=yes,medi=yes,fina=yes,isol=yes,
diff --git a/Master/texmf-dist/tex/context/base/mkiv/m-gnuplot.mkxl b/Master/texmf-dist/tex/context/base/mkiv/m-gnuplot.mkxl
new file mode 100644
index 00000000000..2077b174182
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/m-gnuplot.mkxl
@@ -0,0 +1,97 @@
+%D \module
+%D [ file=m-gnuplot,
+%D version=2020.02.10,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=Gnuplot,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This is a variant on the \GNUPLOT\ terminal code. At some point (when there is a
+%D reason) I will make a proper environment that can be used for embedded code.
+
+\unexpanded\def\includegnuplotsvgfile[#1]%
+ {\hbox\bgroup
+ \ctxlua{metapost.startsvghashing()}%
+ \includesvgfile[#1]%
+ \ctxlua{metapost.stopsvghashing()}%
+ \egroup}
+
+\startluacode
+
+local modificationtime = lfs.modification
+local longtostring = string.longtostring
+local formatters = string.formatters
+local expandfilename = dir.expandname
+local isfile = lfs.isfile
+
+local runner = sandbox.registerrunner {
+ name = "gnuplot to svg",
+ program = "gnuplot",
+ template = longtostring [[
+ -e "set output '%newname%'; set terminal svg"
+ "%oldname%"
+ ]],
+ checkers = {
+ oldname = "readable",
+ newname = "writable",
+ },
+}
+
+figures.programs.gnuplot = {
+ runner = runner,
+}
+
+local function remap(specification)
+ local oldname = specification.fullname
+ if oldname then
+ local newname = file.replacesuffix(oldname,"svg")
+ local oldtime = modificationtime(oldname) or 0
+ local newtime = modificationtime(newname) or 0
+ if newtime == 0 or oldtime > newtime then
+ runner {
+ newname = expandfilename(newname),
+ oldname = expandfilename(oldname),
+ }
+ end
+ if isfile(newname) then
+ local only = file.nameonly(newname)
+ local name = formatters["svg-%s-inclusion"](only)
+ local code = formatters["\\includegnuplotsvgfile[%s]\\resetbuffer[%s]"](newname,name)
+ buffers.assign(name,code)
+ specification.format = "buffer"
+ specification.fullname = name
+ end
+ end
+ return specification
+end
+
+figures.remappers.gp = { svg = remap }
+
+\stopluacode
+
+\continueifinputfile{m-gnuplot.mkxl}
+
+\startluacode
+io.savedata("m-gnuplot-demo.gp", [[
+set format xy "$%g$"
+
+set title 'This is a plot of $y=\\sin(x)$'
+set xlabel 'This is the $x$ axis'
+set ylabel 'This is the $y$ axis'
+
+plot [0:6.28] [0:1] sin(x)
+]])
+\stopluacode
+
+\starttext
+
+ \externalfigure[m-gnuplot-demo.gp][conversion=svg,width=4cm]
+
+ \externalfigure[m-gnuplot-demo.gp][conversion=svg,width=8cm]
+
+\stoptext
diff --git a/Master/texmf-dist/tex/context/base/mkiv/math-act.lua b/Master/texmf-dist/tex/context/base/mkiv/math-act.lua
index 07ef32746a4..1f0140960fe 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/math-act.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/math-act.lua
@@ -441,7 +441,8 @@ mathematics.tweaks = tweaks
-- helpers
local setmetatableindex = table.setmetatableindex
-local family_font = node.family_font
+
+local getfontoffamily = tex.getfontoffamily
local fontcharacters = fonts.hashes.characters
local extensibles = utilities.storage.allocate()
@@ -512,7 +513,7 @@ setmetatableindex(extensibles,function(extensibles,font)
end)
local function extensiblecode(family,unicode)
- return extensibles[family_font(family or 0)][unicode][1]
+ return extensibles[getfontoffamily(family or 0)][unicode][1]
end
-- left : [head] ...
@@ -522,7 +523,7 @@ end
-- abs(right["start"] - right["end"]) | right.advance | characters[right.glyph].width
local function horizontalcode(family,unicode)
- local font = family_font(family or 0)
+ local font = getfontoffamily(family or 0)
local data = extensibles[font][unicode]
local kind = data[1]
local loffset = 0
diff --git a/Master/texmf-dist/tex/context/base/mkiv/math-ali.mkiv b/Master/texmf-dist/tex/context/base/mkiv/math-ali.mkiv
index ecfac68870f..400326d2691 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/math-ali.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/math-ali.mkiv
@@ -42,7 +42,8 @@
\unexpanded\def\math_eqalign_distance
{\relax
\ifdim\d_math_eqalign_distance>\zeropoint
- \hskip\d_math_eqalign_distance
+ % \hskip\d_math_eqalign_distance
+ \tabskip\d_math_eqalign_distance
\fi
\mathalignmentparameter\c!separator
\relax}
@@ -68,7 +69,7 @@
\def\math_build_eqalign
{\scratchtoks\emptytoks
- \d_math_eqalign_distance\mathalignmentparameter\c!distance
+ \d_math_eqalign_distance\mathalignmentparameter\c!distance\relax
\scratchcounterone\mathalignmentparameter\c!m
\scratchcountertwo\mathalignmentparameter\c!n
\etoksapp\scratchtoks{\the\t_math_align_a}%
@@ -712,6 +713,8 @@
\let\math_cases_NR\math_align_NR_generic
+\installmacrostack\math_cases_NC
+
\unexpanded\def\math_cases_start_indeed[#1]%
{\iffirstargument
\setupcurrentmathcases[#1]%
@@ -724,7 +727,7 @@
\fi
\mathcasesparameter\c!left
\vcenter\bgroup
- \pushmacro\math_cases_NC
+ \push_macro_math_cases_NC
\let\endmath\relax
\let\NC\math_cases_NC_zero
\let\MC\math_cases_MC_zero
@@ -743,7 +746,7 @@
\hfil
\aligntab
\hskip\mathcasesparameter\c!distance\relax
- \popmacro\math_cases_NC
+ \pop_macro_math_cases_NC
\math_cases_strut % looks better
\alignmark\alignmark
\hfil
@@ -968,9 +971,16 @@
{\c_math_eqalign_column\zerocount
\rawprocesscommacommand[\mathmatrixparameter\c!align]\math_matrix_set_columns_step}
+\newcount\c_math_eqalign_column_saved
+\newcount\c_math_eqalign_first_saved
+
+% \installglobalmacrostack\c_math_matrix_first
+
\unexpanded\def\math_matrix_start#1%
{\begingroup
- \globalpushmacro\c_math_matrix_first
+ \globalpushmacro\c_math_matrix_first % hm, does that work?
+ \c_math_eqalign_column_saved\c_math_eqalign_column
+ \c_math_eqalign_first_saved \c_math_eqalign_first
\edef\currentmathmatrix{#1}%
\dosingleempty\math_matrix_start_indeed}
@@ -985,6 +995,8 @@
\def\math_matrix_stop
{\math_matrix_stop_processing
+ \global\c_math_eqalign_first\c_math_eqalign_first_saved
+ \global\c_math_eqalign_column\c_math_eqalign_column_saved
\globalpopmacro\c_math_matrix_first
\endgroup}
@@ -1457,7 +1469,7 @@
\ifcase\mathraggedstatus\or\or\hfill\or\hfill\fi
\else
\ifconditional\c_strc_math_indent
- \ifdim\d_strc_math_indent=\zeropoint\else
+ \ifzeropt\d_strc_math_indent\else
\hangafter\plusone
\hangindent\d_strc_math_indent
\fi
@@ -1817,31 +1829,31 @@
\or
\bgroup \hsize\displaywidth
\fi
- \ifcase\mathnumberstatus
+ \ifcase\mathnumberstatus
+ \strc_math_flush_box
+ \or % status 1
+ \ifcase\c_strc_math_number_location
\strc_math_flush_box
- \or % status 1
- \ifcase\c_strc_math_number_location
- \strc_math_flush_box
- \or % number left
- \ifzeropt\wd\b_strc_formulas_number
- \strc_math_flush_number_no
- \else
- \strc_math_flush_number_left
- \fi
- \else % number right
- \ifzeropt\wd\b_strc_formulas_number
- \strc_math_flush_number_no
- \else
- \strc_math_flush_number_right
- \fi
+ \or % number left
+ \ifzeropt\wd\b_strc_formulas_number
+ \strc_math_flush_number_no
+ \else
+ \strc_math_flush_number_left
+ \fi
+ \else % number right
+ \ifzeropt\wd\b_strc_formulas_number
+ \strc_math_flush_number_no
+ \else
+ \strc_math_flush_number_right
\fi
- \or % status 2
- \hskip\d_math_number_correction % probably no longer used
- \strc_math_flush_box
- \hss
- \else
- \strc_math_flush_box
\fi
+ \or % status 2
+ \hskip\d_math_number_correction % probably no longer used
+ \strc_math_flush_box
+ \hss
+ \else
+ \strc_math_flush_box
+ \fi
\ifcase\c_strc_math_vertical
\or
\or
@@ -1864,22 +1876,22 @@
% 4=disable 6=only when no spaces
\mathsurroundskip\mathematicsparameter\c!textdistance\relax
\ifzeropt\mathsurroundskip
- \ifdim\gluestretch\mathsurroundskip=\zeropoint
- \ifdim\glueshrink\mathsurroundskip=\zeropoint
- \mathsurroundmode\plussix
+ \ifzeropt\gluestretch\mathsurroundskip
+ \ifzeropt\glueshrink\mathsurroundskip
+ \mathsurroundmode\plussix
\else
- \mathsurroundskip\zeropoint
- \mathsurroundmode\plusfour
+ \mathsurroundskip\zeropoint
+ \mathsurroundmode\plusfour
\fi
- \else
+ \else
\mathsurroundmode\plussix
- \fi
+ \fi
\else
- \mathsurroundmode\plussix
+ \mathsurroundmode\plussix
\fi
\else
- \mathsurroundmode\plusfour
- \mathsurroundskip\zeropoint
+ \mathsurroundmode\plusfour
+ \mathsurroundskip\zeropoint
\fi
\to \everymathematics
diff --git a/Master/texmf-dist/tex/context/base/mkiv/math-ext.lua b/Master/texmf-dist/tex/context/base/mkiv/math-ext.lua
index b923853f4a6..762f1f904ed 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/math-ext.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/math-ext.lua
@@ -6,7 +6,6 @@ if not modules then modules = { } end modules ['math-ext'] = {
license = "see context related readme files"
}
-local rawget = rawget
local basename = file.basename
local sortedhash = table.sortedhash
diff --git a/Master/texmf-dist/tex/context/base/mkiv/math-ini.lua b/Master/texmf-dist/tex/context/base/mkiv/math-ini.lua
index 7a841970209..0af9a2121ba 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/math-ini.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/math-ini.lua
@@ -319,7 +319,7 @@ function mathematics.define(family)
if mathclass then
local name = character.mathname
if name then
- report_math("fatal error, conlicting mathclass and mathspec for %C",unicode)
+ report_math("fatal error, conflicting mathclass and mathspec for %C",unicode)
os.exit()
else
local class = classes[mathclass] or mathclass -- no real checks needed
diff --git a/Master/texmf-dist/tex/context/base/mkiv/math-ini.mkiv b/Master/texmf-dist/tex/context/base/mkiv/math-ini.mkiv
index 3c27bbf07f1..caddfca531d 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/math-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/math-ini.mkiv
@@ -129,6 +129,10 @@
\mathflattenmode 31
+\ifdefined\ordlimits\else
+ \let\ordlimits\limits
+\fi
+
\appendtoks
\attribute\mathmodeattribute\plusone
\to \everydisplay
@@ -254,11 +258,25 @@
\def\math_m_yes_math[#1]#2%
{#2}
+% \def\math_m_yes_text[#1]%
+% {\begingroup
+% \doifassignmentelse{#1}%
+% {\setupcurrentmathematics[#1]}%
+% {\edef\currentmathematics{#1}}% check for valid
+% \edef\p_openup{\mathematicsparameter\c!openup}%
+% \ifx\p_openup\v!yes
+% \expandafter\math_m_yes_text_openedup
+% \else
+% \expandafter\math_m_yes_text_normal
+% \fi}
+
\def\math_m_yes_text[#1]%
{\begingroup
- \doifassignmentelse{#1}%
- {\setupcurrentmathematics[#1]}%
- {\edef\currentmathematics{#1}}% check for valid
+ \ifcondition\validassignment{#1}%
+ \setupcurrentmathematics[#1]%
+ \else
+ \edef\currentmathematics{#1}% check for valid
+ \fi
\edef\p_openup{\mathematicsparameter\c!openup}%
\ifx\p_openup\v!yes
\expandafter\math_m_yes_text_openedup
@@ -1474,7 +1492,7 @@
\to \everymathematics
\setupmathematics
- [\s!collapsing=3] % mathlist wins over specials
+ [\s!collapsing=\v!none] % was 3 : mathlist wins over specials
%D Math italics (experiment)
@@ -2768,7 +2786,7 @@
\def\checkeddisplaywidth % hsize if zero
{\dimexpr
- \ifdim\displaywidth=\zeropoint
+ \ifzeropt\displaywidth
\hsize
\else
\displaywidth
@@ -2777,7 +2795,7 @@
\def\maximizeddisplaywidth % larger than zero but within hsize
{\dimexpr
- \ifdim\displaywidth=\zeropoint
+ \ifzeropt\displaywidth
\hsize
\else\ifdim\displaywidth>\hsize
\hsize
diff --git a/Master/texmf-dist/tex/context/base/mkiv/math-noa.lua b/Master/texmf-dist/tex/context/base/mkiv/math-noa.lua
index 37676722740..f53410b18cd 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/math-noa.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/math-noa.lua
@@ -28,7 +28,7 @@ local utfchar, utfbyte = utf.char, utf.byte
local formatters, gmatch = string.formatters, string.gmatch
local sortedhash = table.sortedhash
local insert, remove = table.insert, table.remove
-local div = math.div
+local div, round = math.div, math.round
local bor, band = bit32.bor, bit32.band
local fonts = fonts
@@ -136,8 +136,6 @@ local set_visual = nuts.setvisual
local mlist_to_hlist = nuts.mlist_to_hlist
-local font_of_family = node.family_font
-
local new_kern = nodepool.kern
local new_submlist = nodepool.submlist
local new_noad = nodepool.noad
@@ -152,6 +150,7 @@ local fontitalics = fonthashes.italics
local variables = interfaces.variables
local texsetattribute = tex.setattribute
local texgetattribute = tex.getattribute
+local getfontoffamily = tex.getfontoffamily
local unsetvalue = attributes.unsetvalue
local implement = interfaces.implement
@@ -177,15 +176,19 @@ local noadcodes = nodes.noadcodes
local fencecodes = nodes.fencecodes
local ordnoad_code = noadcodes.ord
-local relnode_code = noadcodes.rel
+local opdisplaylimitsnoad_code = noadcodes.opdisplaylimits
+local oplimitsnoad_code = noadcodes.oplimits
+local opnolimitsnoad_code = noadcodes.opnolimits
local binnoad_code = noadcodes.bin
+local relnode_code = noadcodes.rel
local opennoad_code = noadcodes.open
local closenoad_code = noadcodes.close
local punctnoad_code = noadcodes.punct
-local opdisplaylimitsnoad_code = noadcodes.opdisplaylimits
-local oplimitsnoad_code = noadcodes.oplimits
-local opnolimitsnoad_code = noadcodes.opnolimits
local innernoad_code = noadcodes.inner
+local undernoad_code = noadcodes.under
+local overnoad_code = noadcodes.over
+local vcenternoad_code = noadcodes.vcenter
+local ordlimitsnoad_code = noadcodes.ordlimits or oplimitsnoad_code
local noad_code = nodecodes.noad -- attr nucleus sub sup
local accent_code = nodecodes.accent -- attr nucleus sub sup accent
@@ -197,6 +200,7 @@ local mathchar_code = nodecodes.mathchar -- attr fam char
local mathtextchar_code = nodecodes.mathtextchar -- attr fam char
local delim_code = nodecodes.delim -- attr small_fam small_char large_fam large_char
----- style_code = nodecodes.style -- attr style
+----- parameter_code = nodecodes.parameter -- attr style
local math_choice = nodecodes.choice -- attr display text script scriptscript
local fence_code = nodecodes.fence -- attr subtype
@@ -299,6 +303,8 @@ local function process(start,what,n,parent)
noad = getfield(start,"bot_accent") if noad then process(noad,what,n,start) end -- list
-- elseif id == style_code then
-- -- has a next
+ -- elseif id == parameter_code then
+ -- -- has a next
-- else
-- -- glue, penalty, etc
end
@@ -505,7 +511,7 @@ do
report_families("no bold replacement for %C, family %s with remap %s becomes %s with remap %s",char,a,familymap[a],newa,familymap[newa])
end
setfam(pointer,newa)
- elseif not fontcharacters[font_of_family(newa)][bold] then
+ elseif not fontcharacters[getfontoffamily(newa)][bold] then
if trace_families then
report_families("no bold character for %C, family %s with remap %s becomes %s with remap %s",char,a,familymap[a],newa,familymap[newa])
end
@@ -522,7 +528,7 @@ do
end
else
local char = getchar(pointer)
- if not fontcharacters[font_of_family(a)][char] then
+ if not fontcharacters[getfontoffamily(a)][char] then
if trace_families then
report_families("no bold replacement for %C",char)
end
@@ -546,14 +552,14 @@ do
a = a - 3
end
local char = getfield(pointer,"small_char")
- local okay = fontcharacters[font_of_family(a)][char]
+ local okay = fontcharacters[getfontoffamily(a)][char]
if okay then
setfield(pointer,"small_fam",a)
elseif a > 2 then
setfield(pointer,"small_fam",a-3)
end
local char = getfield(pointer,"large_char")
- local okay = fontcharacters[font_of_family(a)][char]
+ local okay = fontcharacters[getfontoffamily(a)][char]
if okay then
setfield(pointer,"large_fam",a)
elseif a > 2 then
@@ -578,7 +584,7 @@ do
-- a = a - 3
-- end
-- local char = getchar(pointer)
- -- local okay = fontcharacters[font_of_family(a)][char]
+ -- local okay = fontcharacters[getfontoffamily(a)][char]
-- if okay then
-- setfam(pointer,a)
-- elseif a > 2 then
@@ -785,7 +791,7 @@ do
local chr = getchar(delimiter)
if chr > 0 then
local fam = getfam(delimiter)
- local id = font_of_family(fam)
+ local id = getfontoffamily(fam)
if id > 0 then
local data = fontdata[id]
local char = mathematics.big(data,chr,size,method)
@@ -835,8 +841,8 @@ do
if chr == dummyfencechar then
chr = 0
end
- setfield(d,"small_char",chr)
- setfield(d,"small_fam",fam)
+ setchar(d,chr)
+ setfam(d,fam)
flush_node(sym)
end
setattrlist(d,char)
@@ -847,100 +853,102 @@ do
return f
end
- -- will become
-
- -- local function makefence(what,char)
- -- local d = new_delimiter() -- todo: attr
- -- local f = new_fence() -- todo: attr
- -- if char then
- -- local sym = getnucleus(char)
- -- local chr = getchar(sym)
- -- local fam = getfam(sym)
- -- if chr == dummyfencechar then
- -- chr = 0
- -- end
- -- setchar(d,chr)
- -- setfam(d,fam)
- -- flush_node(sym)
- -- end
- -- setsubtype(f,what)
- -- setfield(f,"delim",d)
- -- setfield(f,"class",-1) -- tex itself does this, so not fenceclasses[what]
- -- return f
- -- end
-
- local function makelist(noad,f_o,o_next,c_prev,f_c,middle)
+ local function show(where,pointer)
+ print("")
+ local i = 0
+ for n in nuts.traverse(pointer) do
+ i = i + 1
+ print(i,where,nuts.tonode(n))
+ end
+ print("")
+ end
+
+ local function makelist(middle,noad,f_o,o_next,c_prev,f_c)
+-- report_fences(
+-- "middle %s, noad %s, open %s, opennext %s, closeprev %s, close %s",
+-- middle or "?",
+-- noad or "?",
+-- f_o or "?",
+-- o_next or "?",
+-- c_prev or "?",
+-- f_c or "?"
+-- )
local list = new_submlist()
- setlist(list,f_o)
setsubtype(noad,innernoad_code)
setnucleus(noad,list)
- setlink(f_o,o_next)
- setlink(c_prev,f_c)
+ setlist(list,f_o)
+ setlink(f_o,o_next) -- prev of list is nil
+ setlink(c_prev,f_c) -- next of list is nil
+-- show("list",f_o)
if middle and next(middle) then
local prev = f_o
local current = o_next
while current ~= f_c do
- local m = middle[current]
- if m then
- local next = getnext(current)
+ local midl = middle[current]
+ local next = getnext(current)
+ if midl then
local fence = makefence(middlefence_code,current)
setnucleus(current)
flush_node(current)
middle[current] = nil
-- replace_node
setlink(prev,fence,next)
- prev = fence
- current = next
+ prev = fence
else
prev = current
- current = getnext(current)
end
+ current = next
end
end
+ return noad
end
+ -- relinking is now somewhat overdone
+
local function convert_both(open,close,middle)
- local o_prev, o_next = getboth(open)
- local c_prev, c_next = getboth(close)
+ local o_next = getnext(open)
if o_next == close then
return close
else
+ local c_prev, c_next = getboth(close)
local f_o = makefence(leftfence_code,open)
local f_c = makefence(rightfence_code,close)
- makelist(open,f_o,o_next,c_prev,f_c,middle)
+ makelist(middle,open,f_o,o_next,c_prev,f_c)
setnucleus(close)
flush_node(close)
- if c_next then
- setprev(c_next,open)
- end
- setnext(open,c_next)
+ -- open is now a list
+ setlink(open,c_next)
return open
end
end
- local function convert_open(open,last,middle)
+ local function convert_open(open,last,middle) -- last is really last (final case)
local f_o = makefence(leftfence_code,open)
local f_c = makefence(rightfence_code)
- local o_prev, o_next = getboth(open)
- local l_prev, l_next = getboth(last)
- makelist(open,f_o,o_next,last,f_c,middle)
- if l_next then
- setprev(l_next,open)
- end
- setnext(open,l_next)
+ local o_next = getnext(open)
+ makelist(middle,open,f_o,o_next,last,nil)
+ -- open is now a list
+ setlink(open,l_next)
return open
end
- local function convert_close(close,first,middle)
+ local function convert_close(first,close,middle)
local f_o = makefence(leftfence_code)
local f_c = makefence(rightfence_code,close)
local c_prev = getprev(close)
- makelist(close,f_o,first,c_prev,f_c,middle)
+ local f_next = getnext(first)
+ makelist(middle, close, f_o,f_next,c_prev,f_c)
+ -- close is now a list
+ if c_prev ~= first then
+ setlink(first,close)
+ end
return close
end
local stacks = setmetatableindex("table")
+ -- 1=open 2=close 3=middle 4=both
+
local function processfences(pointer,n,parent)
local current = pointer
local last = pointer
@@ -950,47 +958,75 @@ do
local stack = nil
local middle = nil -- todo: use properties
while current do
+-- show("before",pointer)
local id = getid(current)
if id == noad_code then
local a = getattr(current,a_autofence)
if a and a > 0 then
local stack = stacks[n]
- setattr(current,a_autofence,0)
- if a == 1 or (a == 4 and (not stack or #stack == 0)) then
+ setattr(current,a_autofence,0) -- hm, better use a property
+ local level = #stack
+ if a == 1 then
if trace_fences then
- report_fences("%2i: pushing open on stack",n)
+ report_fences("%2i: level %i, handling %s, action %s",n,level,"open","open")
end
insert(stack,current)
- elseif a == 2 or a == 4 then
+ elseif a == 2 then
local open = remove(stack)
if open then
if trace_fences then
- report_fences("%2i: handling %s, stack depth %i",n,"both",#stack+1)
+ report_fences("%2i: level %i, handling %s, action %s",n,level,"close","both")
end
current = convert_both(open,current,middle)
elseif current == start then
- -- skip
+ if trace_fences then
+ report_fences("%2i: level %i, handling %s, action %s",n,level,"close","skip")
+ end
else
if trace_fences then
- report_fences("%2i: handling %s, stack depth %i",n,"close",#stack+1)
+ report_fences("%2i: level %i, handling %s, action %s",n,level,"close","close")
end
- current = convert_close(current,initial,middle)
+ current = convert_close(initial,current,middle)
if not parent then
initial = current
end
end
- if trace_fences then
- report_fences("%2i: popping close from stack",n)
- end
elseif a == 3 then
if trace_fences then
- report_fences("%2i: registering middle",n)
+ report_fences("%2i: level %i, handling %s, action %s",n,level,"middle","middle")
end
if middle then
middle[current] = last
else
middle = { [current] = last }
end
+ elseif a == 4 then
+ if not stack or #stack == 0 then
+ if trace_fences then
+ report_fences("%2i: level %i, handling %s, action %s",n,level,"both","open")
+ end
+ insert(stack,current)
+ else
+ local open = remove(stack)
+ if open then
+ if trace_fences then
+ report_fences("%2i: level %i, handling %s, action %s",n,level,"both","both")
+ end
+ current = convert_both(open,current,middle)
+ elseif current == start then
+ if trace_fences then
+ report_fences("%2i: level %i, handling %s, action %s",n,level,"both","skip")
+ end
+ else
+ if trace_fences then
+ report_fences("%2i: level %i, handling %s, action %s",n,level,"both","close")
+ end
+ current = convert_close(initial,current,middle)
+ if not parent then
+ initial = current
+ end
+ end
+ end
end
done = true
else
@@ -1000,6 +1036,7 @@ do
-- next at current level
processstep(current,processfences,n,id)
end
+-- show("after",pointer)
last = current
current = getnext(current)
end
@@ -1007,16 +1044,14 @@ do
local stack = stacks[n]
local s = #stack
if s > 0 then
- if trace_fences then
- report_fences("%2i: handling %s stack levels",n,s)
- end
for i=1,s do
local open = remove(stack)
if trace_fences then
- report_fences("%2i: handling %s, stack depth %i",n,"open",#stack)
+ report_fences("%2i: level %i, handling %s, action %s",n,#stack,"flush","open")
end
last = convert_open(open,last,middle)
end
+-- show("done",pointer)
end
end
end
@@ -1326,7 +1361,7 @@ do
local fontresources = fonts.hashes.resources
local function getalternate(fam,tag,current)
- local resources = fontresources[font_of_family(fam)]
+ local resources = fontresources[getfontoffamily(fam)]
local attribute = unsetvalue
if resources then
local mathalternates = resources.mathalternates
@@ -1557,6 +1592,7 @@ do
else
correction = correction - 100
end
+ correction = round(correction)
setattr(pointer,a_mathitalics,correction)
setattr(parent,a_mathitalics,correction)
return -- so no reset later on
@@ -1714,14 +1750,19 @@ do
local mathlists = characters.mathlists
local validpair = {
[ordnoad_code] = true,
- [relnode_code] = true,
+ [opdisplaylimitsnoad_code] = true,
+ [oplimitsnoad_code] = true,
+ [opnolimitsnoad_code] = true,
[binnoad_code] = true, -- new
+ [relnode_code] = true,
[opennoad_code] = true, -- new
[closenoad_code] = true, -- new
[punctnoad_code] = true, -- new
- [opdisplaylimitsnoad_code] = true,
- [oplimitsnoad_code] = true,
- [opnolimitsnoad_code] = true,
+ [innernoad_code] = false,
+ [undernoad_code] = false,
+ [overnoad_code] = false,
+ [vcenternoad_code] = false,
+ [ordlimitsnoad_code] = true,
}
local reported = setmetatableindex("table")
@@ -2043,6 +2084,7 @@ do
-- [opdisplaylimitsnoad_code] = "",
-- [oplimitsnoad_code] = "",
-- [opnolimitsnoad_code] = "",
+ -- [ordlimitsnoad_code] = "",
-- [innernoad_code = "",
-- [undernoad_code] = "",
-- [overnoad_code] = "",
diff --git a/Master/texmf-dist/tex/context/base/mkiv/math-stc.mkvi b/Master/texmf-dist/tex/context/base/mkiv/math-stc.mkvi
index 92325d0afd0..8048bf92364 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/math-stc.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/math-stc.mkvi
@@ -86,11 +86,19 @@
\def\math_stackers_regular
{\mathstylehbox{\usemathstackerscolorparameter\c!color
- \Umathaccent\fam\zerocount\scratchunicode{\hskip\scratchwidth}}}
+ \hskip\d_math_stackers_offset_l
+ \Umathaccent\fam\zerocount\scratchunicode
+ {\hskip\dimexpr\scratchwidth-\d_math_stackers_offset_l-\d_math_stackers_offset_r}%
+ \hskip\d_math_stackers_offset_r
+ }}
\def\math_stackers_stretch % we don't have that one yet
{\mathstylehbox{\usemathstackerscolorparameter\c!color
- \Umathaccent\fam\zerocount\scratchunicode{\hskip\hsize}}}
+ \hskip\d_math_stackers_offset_l
+ \Umathaccent\fam\zerocount\scratchunicode
+ {\hskip\dimexpr\hsize-\d_math_stackers_offset_l-\d_math_stackers_offset_r}%
+ \hskip\d_math_stackers_offset_r
+ }}
% these delimiters are a unuseable as they don't center for small arguments:
%
@@ -499,7 +507,7 @@
\dostoptagged
\mathstackersparameter\c!right\relax
\endgroup}
- %\math_stackers_start_group}
+ %\math_stackers_stop_group}
\unexpanded\def\definemathextensible
{\dotripleempty\math_stackers_define_normal}
@@ -566,14 +574,33 @@
\edef\currentmathstackers{#category}%
\edef\p_limits{\mathstackersparameter\c!mathlimits}%
\ifx\p_limits\v!yes
- \def\math_stackers_stop_group{\egroup\endgroup\limits}%
+ \def\math_stackers_stop_group{\egroup\endgroup\ordlimits}%
\mathop\bgroup
\else
\let\math_stackers_stop_group\endgroup
\fi}
-\unexpanded\def\math_stackers_make_double#top#bottom#category#codepoint#codeextra#text%
+\newconstant\c_math_stackers_top
+\newconstant\c_math_stackers_bottom
+\newconstant\c_math_stackers_codepoint
+\newconstant\c_math_stackers_extracode
+\newdimen \d_math_stackers_offset_l
+\newdimen \d_math_stackers_offset_r
+
+\setupmathstackers[lt=\zeropoint,rt=\zeropoint,lb=\zeropoint,rb=\zeropoint]
+
+\unexpanded\def\math_stackers_make_double#top#bottom#category#codepoint#codeextra%
{\math_stackers_start_group{#category}%
+ \c_math_stackers_top #top\relax
+ \c_math_stackers_bottom #bottom\relax
+ \c_math_stackers_codepoint#codepoint\relax
+ \c_math_stackers_extracode#codeextra\relax
+ \dosingleempty\math_stackers_make_double_indeed}
+
+\unexpanded\def\math_stackers_make_double_indeed[#settings]#text%
+ {\iffirstargument
+ \setupcurrentmathstackers[#settings]%
+ \fi
\mathstackersparameter\c!left\relax
\dostarttagged\t!mathstacker\currentmathstackers
\ifmmode\math_class_by_parameter\mathstackersparameter\else\dontleavehmode\fi
@@ -587,7 +614,7 @@
\scratchleftoffset \zeropoint
\scratchrightoffset\zeropoint
%
- \math_stackers_check_unicode{#codepoint}%
+ \math_stackers_check_unicode\c_math_stackers_codepoint
%
\ifx\math_stackers_middle\empty
\setbox\scratchboxthree\emptyhbox
@@ -602,24 +629,37 @@
\fi
\advance\scratchwidth2\scratchhoffset
%
+ %\scratchunicode\c_math_stackers_codepoint
+ \ifcase\c_math_stackers_bottom
+ \d_math_stackers_offset_l\mathstackersparameter{lt}%
+ \d_math_stackers_offset_r\mathstackersparameter{rt}%
+ \else\ifcase\c_math_stackers_top
+ \d_math_stackers_offset_l\mathstackersparameter{lb}%
+ \d_math_stackers_offset_r\mathstackersparameter{rb}%
+ \else
+ \d_math_stackers_offset_l\mathstackersparameter{lt}%
+ \d_math_stackers_offset_r\mathstackersparameter{rt}%
+ \fi\fi
\setbox\scratchboxtwo\csname\??mathstackersalternative\p_alternative\endcsname
\setbox\scratchboxthree\hpack to \scratchwidth{\hss\box\scratchboxthree\hss}%
%
- \scratchunicode#codeextra\relax
- \ifcase\scratchunicode\else
+ \ifcase\c_math_stackers_extracode\else
+ \scratchunicode\c_math_stackers_extracode
+ \d_math_stackers_offset_l\mathstackersparameter{lb}%
+ \d_math_stackers_offset_r\mathstackersparameter{rb}%
\setbox\scratchboxone\csname\??mathstackersalternative\p_alternative\endcsname
\fi
%
\math_stackers_normalize_three
% analysis
- \ifcase#bottom\relax
- \ifcase#top\relax
+ \ifcase\c_math_stackers_bottom
+ \ifcase\c_math_stackers_top
\dosettagproperty\s!subtype\t!munderover
\else
\dosettagproperty\s!subtype\t!mover
\fi
\else
- \ifcase#top\relax
+ \ifcase\c_math_stackers_top
\dosettagproperty\s!subtype\t!munder
\else
% brrr
@@ -633,7 +673,7 @@
\math_stackers_stop_tagged
%
\ifdim\htdp\scratchboxtwo>\zeropoint
- \ifcase#bottom\else
+ \ifcase\c_math_stackers_bottom\else
\kern-\scratchwidth
% under
\math_stackers_start_tagged_bot
@@ -643,7 +683,7 @@
+\ht\scratchboxtwo
+\mathstackersparameter\c!distance % was \c!voffset
\relax
- \ifcase#top\relax
+ \ifcase\c_math_stackers_top
\box\scratchboxtwo
\else
\box\scratchboxone
@@ -651,7 +691,7 @@
\egroup
\math_stackers_stop_tagged
\fi
- \ifcase#top\else
+ \ifcase\c_math_stackers_top\else
\kern-\scratchwidth
% over
\math_stackers_start_tagged_top
@@ -665,7 +705,6 @@
\egroup
\math_stackers_stop_tagged
\fi
- %
\fi}%
\dostoptagged
\mathstackersparameter\c!right\relax
@@ -696,10 +735,6 @@
\setuevalue{#1}{\math_stackers_make_double\plusone \plusone\noexpand\currentmathstackers{\number#2}{\number#3}}%
\fi}
-\unexpanded\def\mathover {\begingroup\dosingleempty\math_stackers_handle_over }
-\unexpanded\def\mathunder {\begingroup\dosingleempty\math_stackers_handle_under }
-\unexpanded\def\mathdouble{\begingroup\dodoubleempty\math_stackers_handle_double}
-
\unexpanded\def\definemathover {\dotripleargument \math_stackers_define_over }
\unexpanded\def\definemathunder {\dotripleargument \math_stackers_define_under }
\unexpanded\def\definemathdouble{\doquadrupleargument\math_stackers_define_double}
@@ -713,29 +748,41 @@
\def\math_stackers_define_double[#category][#command][#topcode][#bottomcode]%
{\setuvalue{#command}{\math_stackers_handle_direct\plusone\plusone{#category}{#topcode}{#bottomcode}}}
-\unexpanded\def\mathover {\begingroup\dosingleempty\math_stackers_handle_over }
-\unexpanded\def\mathunder {\begingroup\dosingleempty\math_stackers_handle_under }
-\unexpanded\def\mathdouble{\begingroup\dosingleempty\math_stackers_handle_double}
+\unexpanded\def\mathover {\begingroup\dodoubleempty\math_stackers_handle_over }
+\unexpanded\def\mathunder {\begingroup\dodoubleempty\math_stackers_handle_under }
+\unexpanded\def\mathdouble{\begingroup\dodoubleempty\math_stackers_handle_double}
-\def\math_stackers_handle_over[#category]#topcode#text%
- {\math_stackers_make_double\plusone\zerocount
- {\iffirstargument#category\else\v!top\fi}%
+\def\math_stackers_handle_over[#category][#settings]#topcode#text%
+ {\edef\currentmathstackers{\iffirstargument#category\else\v!top\fi}%
+ \ifsecondargument
+ \setupcurrentmathstackers[#settings]%
+ \fi
+ \math_stackers_make_double\plusone\zerocount
+ {\currentmathstackers}%
{#topcode}%
{0}%
{#text}%
\endgroup}
-\def\math_stackers_handle_under[#category]#bottomcode#text%
- {\math_stackers_make_double\zerocount\plusone
- {\iffirstargument#category\else\v!bottom\fi}%
+\def\math_stackers_handle_under[#category][#settings]#bottomcode#text%
+ {\edef\currentmathstackers{\iffirstargument#category\else\v!bottom\fi}%
+ \ifsecondargument
+ \setupcurrentmathstackers[#settings]%
+ \fi
+ \math_stackers_make_double\zerocount\plusone
+ {\currentmathstackers}%
{#bottomcode}%
{0}%
{#text}%
\endgroup}
-\def\math_stackers_handle_double[#category]#topcode#bottomcode#text%
- {\math_stackers_make_double\plusone\plusone
- {\iffirstargument#category\else\v!both\fi}%
+\def\math_stackers_handle_double[#category][#settings]#topcode#bottomcode#text%
+ {\edef\currentmathstackers{\iffirstargument#category\else\v!both\fi}%
+ \ifsecondargument
+ \setupcurrentmathstackers[#settings]%
+ \fi
+ \math_stackers_make_double\plusone\plusone
+ {\currentmathstackers}%
{#topcode}%
{#bottomcode}%
{#text}%
@@ -1189,39 +1236,39 @@
% alternatively we can move the original to FE*
-\definemathoverextensible [vfenced] [overbar] ["FE33E] % ["203E]
-\definemathunderextensible [vfenced] [underbar] ["FE33F] % ["203E]
-\definemathdoubleextensible [vfenced] [doublebar] ["FE33E] ["FE33F]
+\definemathoverextensible [\v!vfenced] [overbar] ["FE33E] % ["203E]
+\definemathunderextensible [\v!vfenced] [underbar] ["FE33F] % ["203E]
+\definemathdoubleextensible [\v!vfenced] [doublebar] ["FE33E] ["FE33F]
-\definemathoverextensible [vfenced] [overbrace] ["FE3DE] % ["023DE]
-\definemathunderextensible [vfenced] [underbrace] ["FE3DF] % ["023DF]
-\definemathdoubleextensible [vfenced] [doublebrace] ["FE3DE] ["FE3DF]
+\definemathoverextensible [\v!vfenced] [overbrace] ["FE3DE] % ["023DE]
+\definemathunderextensible [\v!vfenced] [underbrace] ["FE3DF] % ["023DF]
+\definemathdoubleextensible [\v!vfenced] [doublebrace] ["FE3DE] ["FE3DF]
-\definemathoverextensible [vfenced] [overparent] ["FE3DC] % ["023DC]
-\definemathunderextensible [vfenced] [underparent] ["FE3DD] % ["023DD]
-\definemathdoubleextensible [vfenced] [doubleparent] ["FE3DC] ["FE3DD]
+\definemathoverextensible [\v!vfenced] [overparent] ["FE3DC] % ["023DC]
+\definemathunderextensible [\v!vfenced] [underparent] ["FE3DD] % ["023DD]
+\definemathdoubleextensible [\v!vfenced] [doubleparent] ["FE3DC] ["FE3DD]
-\definemathoverextensible [vfenced] [overbracket] ["FE3B4] % ["023B4]
-\definemathunderextensible [vfenced] [underbracket] ["FE3B5] % ["023B5]
-\definemathdoubleextensible [vfenced] [doublebracket] ["FE3B4] ["FE3B5]
+\definemathoverextensible [\v!vfenced] [overbracket] ["FE3B4] % ["023B4]
+\definemathunderextensible [\v!vfenced] [underbracket] ["FE3B5] % ["023B5]
+\definemathdoubleextensible [\v!vfenced] [doublebracket] ["FE3B4] ["FE3B5]
% \unexpanded\def\mathopwithlimits#1#2{\mathop{#1{#2}}\limits}
%D For mathml:
-\definemathdoubleextensible [both] [overbarunderbar] ["FE33E] ["FE33F]
-\definemathdoubleextensible [both] [overbraceunderbrace] ["FE3DE] ["FE3DF]
-\definemathdoubleextensible [both] [overparentunderparent] ["FE3DC] ["FE3DD]
-\definemathdoubleextensible [both] [overbracketunderbracket] ["FE3B4] ["FE3B5]
-
-\definemathovertextextensible [bothtext] [overbartext] ["FE33E]
-\definemathundertextextensible [bothtext] [underbartext] ["FE33F]
-\definemathovertextextensible [bothtext] [overbracetext] ["FE3DE]
-\definemathundertextextensible [bothtext] [underbracetext] ["FE3DF]
-\definemathovertextextensible [bothtext] [overparenttext] ["FE3DC]
-\definemathundertextextensible [bothtext] [underparenttext] ["FE3DD]
-\definemathovertextextensible [bothtext] [overbrackettext] ["FE3B4]
-\definemathundertextextensible [bothtext] [underbrackettext] ["FE3B5]
+\definemathdoubleextensible [\v!both] [overbarunderbar] ["FE33E] ["FE33F]
+\definemathdoubleextensible [\v!both] [overbraceunderbrace] ["FE3DE] ["FE3DF]
+\definemathdoubleextensible [\v!both] [overparentunderparent] ["FE3DC] ["FE3DD]
+\definemathdoubleextensible [\v!both] [overbracketunderbracket] ["FE3B4] ["FE3B5]
+
+\definemathovertextextensible [\v!bothtext] [overbartext] ["FE33E]
+\definemathundertextextensible [\v!bothtext] [underbartext] ["FE33F]
+\definemathovertextextensible [\v!bothtext] [overbracetext] ["FE3DE]
+\definemathundertextextensible [\v!bothtext] [underbracetext] ["FE3DF]
+\definemathovertextextensible [\v!bothtext] [overparenttext] ["FE3DC]
+\definemathundertextextensible [\v!bothtext] [underparenttext] ["FE3DD]
+\definemathovertextextensible [\v!bothtext] [overbrackettext] ["FE3B4]
+\definemathundertextextensible [\v!bothtext] [underbrackettext] ["FE3B5]
%D Some bonus ones (for the moment here):
diff --git a/Master/texmf-dist/tex/context/base/mkiv/math-tag.lua b/Master/texmf-dist/tex/context/base/mkiv/math-tag.lua
index 03f9e70bbbb..daa757f6a35 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/math-tag.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/math-tag.lua
@@ -58,11 +58,16 @@ local choice_code = nodecodes.choice -- attr display text script s
local fence_code = nodecodes.fence -- attr subtype
local accentcodes = nodes.accentcodes
+local fencecodes = nodes.fencecodes
local fixedtopaccent_code = accentcodes.fixedtop
local fixedbottomaccent_code = accentcodes.fixedbottom
local fixedbothaccent_code = accentcodes.fixedboth
+local leftfence_code = fencecodes.left
+local middlefence_code = fencecodes.middle
+local rightfence_code = fencecodes.right
+
local kerncodes = nodes.kerncodes
local fontkern_code = kerncodes.fontkern
@@ -116,10 +121,10 @@ local function processsubsup(start)
-- start_tagged("mrow")
process(nucleus)
-- stop_tagged()
- start_tagged("mrow")
+ start_tagged("mrow", { subscript = true })
process(sub)
stop_tagged()
- start_tagged("mrow")
+ start_tagged("mrow", { superscript = true })
process(sup)
stop_tagged()
stop_tagged()
@@ -158,7 +163,7 @@ local fencesstack = { }
-- local function getunicode(n) -- instead of getchar
-- local char = getchar(n)
--- -- local font = font_of_family(getfield(n,"fam")) -- font_of_family
+-- -- local font = getfontoffamily(getfield(n,"fam"))
-- local font = getfont(n)
-- local data = fontcharacters[font][char]
-- return data.unicode or char
@@ -204,7 +209,7 @@ process = function(start) -- we cannot use the processor as we have no finalizer
local mtexttag = nil
while start do
local id = getid(start)
- -- showtag(start,id,true)
+-- showtag(start,id,true)
if id == glyph_code or id == disc_code then
if not mtexttag then
mtexttag = start_tagged("mtext")
@@ -265,7 +270,7 @@ process = function(start) -- we cannot use the processor as we have no finalizer
elseif id == noad_code then
-- setattr(start,a_tagged,tags.current())
processsubsup(start)
- elseif id == dubbox_code or id == hlist_code or id == vlist_code then
+ elseif id == subbox_code or id == hlist_code or id == vlist_code then
-- keep an eye on subbox_code and see what ends up in there
local attr = getattr(start,a_tagged)
if not attr then
@@ -372,7 +377,7 @@ process = function(start) -- we cannot use the processor as we have no finalizer
end
end
end
- elseif id == submlistcode then -- normally a hbox
+ elseif id == submlist_code then -- normally a hbox
local list = getlist(start)
if list then
local attr = getattr(start,a_tagged)
@@ -450,16 +455,16 @@ process = function(start) -- we cannot use the processor as we have no finalizer
process(scriptscript)
end
elseif id == fence_code then
+ local subtype = getsubtype(start)
local delim = getfield(start,"delim")
- local subtype = getfield(start,"subtype")
- if subtype == 1 then
+ if subtype == leftfence_code then
-- left
local properties = { }
insert(fencesstack,properties)
setattr(start,a_tagged,start_tagged("mfenced",properties)) -- needs checking
if delim then
start_tagged("ignore")
- local chr = getfield(delim,"small_char")
+ local chr = getchar(delim)
if chr ~= 0 then
properties.left = chr
end
@@ -467,12 +472,12 @@ process = function(start) -- we cannot use the processor as we have no finalizer
stop_tagged()
end
start_tagged("mrow") -- begin of subsequence
- elseif subtype == 2 then
+ elseif subtype == middlefence_code then
-- middle
if delim then
start_tagged("ignore")
local top = fencesstack[#fencesstack]
- local chr = getfield(delim,"small_char")
+ local chr = getchar(delim)
if chr ~= 0 then
local mid = top.middle
if mid then
@@ -486,7 +491,7 @@ process = function(start) -- we cannot use the processor as we have no finalizer
end
stop_tagged() -- end of subsequence
start_tagged("mrow") -- begin of subsequence
- elseif subtype == 3 then
+ elseif subtype == rightfence_code then
local properties = remove(fencesstack)
if not properties then
report_tags("missing right fence")
@@ -494,7 +499,7 @@ process = function(start) -- we cannot use the processor as we have no finalizer
end
if delim then
start_tagged("ignore")
- local chr = getfield(delim,"small_char")
+ local chr = getchar(delim)
if chr ~= 0 then
properties.right = chr
end
@@ -525,9 +530,9 @@ process = function(start) -- we cannot use the processor as we have no finalizer
stop_tagged()
end
elseif id == accent_code then
+ local subtype = getsubtype(start)
local accent = getfield(start,"accent")
local bot_accent = getfield(start,"bot_accent")
- local subtype = getsubtype(start)
if bot_accent then
if accent then
setattr(start,a_tagged,start_tagged("munderover", {
@@ -582,9 +587,10 @@ end
function noads.handlers.tags(head,style,penalties)
start_tagged("math", { mode = (getattr(head,a_mathmode) == 1) and "display" or "inline" })
--- start_tagged("mrow")
setattr(head,a_tagged,start_tagged("mrow"))
+-- showtag(head,getid(head),true)
process(head)
+-- showtag(head,getid(head),false)
stop_tagged()
stop_tagged()
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/math-vfu.lua b/Master/texmf-dist/tex/context/base/mkiv/math-vfu.lua
index ed6f69f41d9..9090955e9c4 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/math-vfu.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/math-vfu.lua
@@ -1106,13 +1106,16 @@ function vfmath.define(specification,set,goodies)
end
end
--
+ main.mathparameters = mathparameters -- still traditional ones
+ -- This should change (some day) as it's the only place where we look forward,
+ -- so better is to also reserve the id already which then involves some more
+ -- management (so not now).
fontlist[#fontlist+1] = {
id = font.nextid(),
size = size,
}
- --
- main.mathparameters = mathparameters -- still traditional ones
vfmath.addmissing(main,#fontlist,size)
+ --
mathematics.addfallbacks(main)
--
main.properties.math_is_scaled = true -- signal
diff --git a/Master/texmf-dist/tex/context/base/mkiv/meta-blb.lua b/Master/texmf-dist/tex/context/base/mkiv/meta-blb.lua
index e1c0de74f37..9ee57d80dd1 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/meta-blb.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/meta-blb.lua
@@ -142,11 +142,7 @@ end
local sxsy = metapost.sxsy
local cm = metapost.cm
-local f_f = formatters["%.6F"]
-
-directives.register("pdf.stripzeros",function()
- f_f = formatters["%.6N"]
-end)
+local f_f = formatters["%.6N"]
local function injectblob(object,blob)
local sx, rx, ry, sy, tx, ty = cm(object)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/meta-fig.mkiv b/Master/texmf-dist/tex/context/base/mkiv/meta-fig.mkiv
index bf37aa7bfa7..e89cb14425d 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/meta-fig.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/meta-fig.mkiv
@@ -44,12 +44,17 @@
\definefittingpage
[MPpage]
[\c!align=,
- \c!command=\meta_process_graphic_instance{\fittingpageparameter\c!instance},
+ \c!command=\meta_process_graphic_command,
\c!instance=]
\unexpanded\def\setupMPpage
{\setupfittingpage[MPpage]}
+\unexpanded\def\meta_process_graphic_command
+ {\doif{\fittingpageparameter\c!alternative}\v!offset
+ {\def\meta_relocate_graphic{\clf_setpageorigin\MPllx\MPlly\relax}}%
+ \meta_process_graphic_instance{\fittingpageparameter\c!instance}}
+
%D \macros
%D {MPfigure}
%D
diff --git a/Master/texmf-dist/tex/context/base/mkiv/meta-fnt.lua b/Master/texmf-dist/tex/context/base/mkiv/meta-fnt.lua
index 69212d08c79..92bbe071617 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/meta-fnt.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/meta-fnt.lua
@@ -167,8 +167,8 @@ local function build(g,v)
local t = { }
for d=1,#data do
t = fonts.constructors.scale(data[d],-1000)
- local id = font.nextid()
- t.fonts = { { id = id } }
+ -- local id = font.nextid()
+ -- t.fonts = { { id = id } }
fontdata[id] = t
if v[5] then
vffonts.helpers.composecharacters(t)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/meta-imp-dum.mkiv b/Master/texmf-dist/tex/context/base/mkiv/meta-imp-dum.mkiv
index 481afe82a54..74a2de8755e 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/meta-imp-dum.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/meta-imp-dum.mkiv
@@ -13,8 +13,7 @@
\unprotect
-%D This library overloads the normal external figure
-%D placeholder by a nicer one.
+%D This library overloads the normal external figure placeholder by a nicer one.
%D
%D \startbuffer
%D \useMPlibrary[dum]
@@ -30,69 +29,70 @@
%D
%D \typebuffer \getbuffer
-% currently preparempvariables is unable to resolve number
-% fractions like reduction
-
-% June 22, 2003, this definition was patched to adapt itself
-% to transparent colors, but ... in 2011 we no longer have
-% is_transparent so we revert.
-%
-% \startuseMPgraphic{placeholder}{width,height,reduction,color}
-% numeric w, h, d, r ; color c, b, cc ; path p ; boolean t ;
-% t := is_transparent(\MPvar{color}) ;
-% c := not_transparent(\MPvar{color}) ;
-% b := not_transparent(white) ;
-% w := \MPvar{width} ;
-% h := \MPvar{height} ;
-% r := \MPvar{reduction} ;
-% d := max(w,h) ;
-% p := unitsquare xyscaled (w,h) ;
-% cc := r[.5c,b] ;
-% fill p withcolor if t : transparent(1,.5,cc) else : cc fi ;
-% for i := 1 upto 60 :
-% cc := r[c randomized(.3,.9),b] ;
-% fill fullcircle
-% scaled (d/5 randomized (d/5))
-% shifted (center p randomized (d))
-% withcolor if t : transparent(1,.5,cc) else : cc fi ;
-% endfor ;
-% clip currentpicture to p ;
-% \stopuseMPgraphic
-
-\startuseMPgraphic{minifun::figure:placeholder}{width,height,reduction,color}
- begingroup ;
- save w, h, d, r, p, c, b ;
- numeric w, h, d, r ; path p ;
- if cmykcolor \MPvar{color} :
- cmykcolor c, b ; b := (0,0,0,0)
- else :
- color c, b ; ; b := (1,1,1)
- fi ;
- c := \MPvar{color} ;
- w := \MPvar{width} ;
- h := \MPvar{height} ;
- r := \MPvar{reduction} ;
- d := max(w,h) ;
- p := unitsquare xyscaled (w,h) ;
- fill p withcolor r[.5c,b] ;
- for i := 1 upto 60 :
- fill fullcircle
- scaled (d/5 randomized (d/5))
- shifted (center p randomized (d))
- withcolor r[c randomized(.3,.9),b] ;
- endfor ;
- clip currentpicture to p ;
- endgroup ;
-\stopuseMPgraphic
-
-\defineoverlay
- [figure:placeholder:graphic]
- [\useMPgraphic
- {minifun::figure:placeholder}%
- {width=\figurewidth,%
- height=\figureheight,%
- reduction=\externalfigureparameter\c!reduction,%
- color=placeholder:\the\c_grph_replacement_n}]
+\startmkivmode
+
+%D Currently preparempvariables is unable to resolve number fractions like
+%D reduction.
+
+ \startuseMPgraphic{minifun::figure:placeholder}{width,height,reduction,color}
+ begingroup ;
+ save w, h, d, r, p, c, b ;
+ numeric w, h, d, r ; path p ;
+ if cmykcolor \MPvar{color} :
+ cmykcolor c, b ; b := (0,0,0,0)
+ else :
+ color c, b ; b := (1,1,1)
+ fi ;
+ c := \MPvar{color} ;
+ w := \MPvar{width} ;
+ h := \MPvar{height} ;
+ r := \MPvar{reduction} ;
+ d := max(w,h) ;
+ p := unitsquare xyscaled (w,h) ;
+ fill p withcolor r[.5c,b] ;
+ for i := 1 upto 60 :
+ fill fullcircle
+ scaled (d/5 randomized (d/5))
+ shifted (center p randomized (d))
+ withcolor r[c randomized(.3,.9),b] ;
+ endfor ;
+ clip currentpicture to p ;
+ endgroup ;
+ \stopuseMPgraphic
+
+ \defineoverlay
+ [figure:placeholder:graphic]
+ [\useMPgraphic
+ {minifun::figure:placeholder}%
+ {width=\figurewidth,%
+ height=\figureheight,%
+ reduction=\externalfigureparameter\c!reduction,%
+ color=placeholder:\the\c_grph_replacement_n}] % weird, why do we need to prefix the palette
+
+\stopmkivmode
+
+\startlmtxmode
+
+ \defineMPparameterset
+ [placeholder]
+ [width=dimension,
+ height=dimension,
+ reduction=number,
+ color=string,
+ alternative=string]
+
+ \defineoverlay
+ [figure:placeholder:graphic]
+ [{\useMPmacro
+ [minifun]%
+ [placeholder]%
+ [width=\figurewidth,%
+ height=\figureheight,%
+ alternative=\externalfigureparameter\c!alternative,
+ reduction=\externalfigureparameter\c!reduction,%
+ color=placeholder:\the\c_grph_replacement_n]}]
+
+\stoplmtxmode
\definepalet
[placeholder]
@@ -108,6 +108,7 @@
\unexpanded\def\grph_include_replacement#1#2#3%
{\begingroup
+% \setuppalet[placeholder]%
\getpaletsize[placeholder]%
\ifnum\c_grph_replacement_n=\zerocount
\getrandomnumber \m_grph_replacement_n\plusone\paletsize
diff --git a/Master/texmf-dist/tex/context/base/mkiv/meta-imp-gamesymbols.mkxl b/Master/texmf-dist/tex/context/base/mkiv/meta-imp-gamesymbols.mkxl
new file mode 100644
index 00000000000..d79e59f69f4
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/meta-imp-gamesymbols.mkxl
@@ -0,0 +1,349 @@
+%D \module
+%D [ file=meta-imp-gamesymbols,
+%D version=2019.10.10,
+%D title=\METAPOST\ Graphics,
+%D subtitle=Game Symbols,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D The \METAFUN\ code here is not optimal and efficient but as it serves as an
+%D example I decided to keep it simple. Also, performance is not really an issue
+%D here anyway. Inspired by the classic \quote {Concrete Mathematics} by Don Knuth
+%D we define dice and dominos, which happen to be \UNICODE\ characters now. We
+%D use this opportunity to demonstrate slightly different approached.
+
+%D Each dice gets it's own macro at the \METAPOST\ end. Watch how we use the \type
+%D {simplefun} instance in combination with a calculation wrapper. This will just
+%D execute the code and leave no traces in the text flow. The code itself is not
+%D that spectacular:
+
+\startMPcalculation{simplefun}
+
+ def DiceFrame =
+ pickup pencircle scaled 1/2 ;
+ draw unitsquare scaled 8 ;
+ pickup pencircle scaled 3/2 ;
+ enddef ;
+
+ vardef DiceOne =
+ DiceFrame ;
+ draw (4,4) ;
+ enddef ;
+ vardef DiceTwoA =
+ DiceFrame ;
+ draw (2,6) ; draw (6,2) ;
+ enddef ;
+ vardef DiceTwoB =
+ DiceFrame ;
+ draw (6,6) ; draw (2,2) ;
+ enddef ;
+ vardef DiceTwo =
+ if hasoption "mpsfont" "option" "reverse" :
+ DiceTwoB
+ else :
+ DiceTwoA
+ fi ;
+ enddef ;
+ vardef DiceThreeA =
+ DiceFrame ;
+ draw (2,6) ; draw (4,4) ; draw (6,2) ;
+ enddef ;
+ vardef DiceThreeB =
+ DiceFrame ;
+ draw (6,6) ; draw (4,4) ; draw (2,2) ;
+ enddef ;
+ vardef DiceThree =
+ if hasoption "mpsfont" "option" "reverse" :
+ DiceThreeB
+ else :
+ DiceThreeA
+ fi ;
+ enddef ;
+ vardef DiceFour =
+ DiceFrame ;
+ draw (2,6) ; draw (6,6) ; draw (2,2) ; draw (6,2) ;
+ enddef ;
+ vardef DiceFive =
+ DiceFrame ;
+ draw (2,6) ; draw (6,6) ; draw (4,4) ; draw (2,2) ; draw (6,2) ;
+ enddef ;
+ vardef DiceSix =
+ DiceFrame ;
+ draw (2,6) ; draw (6,6) ; draw (2,4) ; draw (6,4) ; draw (2,2) ; draw (6,2) ;
+ enddef ;
+
+ vardef DiceBad =
+ pickup pencircle scaled 1/2 ;
+ draw unitsquare scaled 8 ;
+ draw (1,7) -- (7,1) ; draw (1,1) -- (7,7) ;
+ enddef ;
+
+ lmt_registerglyphs [
+ name = "dice",
+ units = 12,
+ width = 8,
+ height = 8,
+ depth = 0,
+ usecolor = true,
+ ] ;
+
+ lmt_registerglyph [ category = "dice", unicode = "0x2680", code = "DiceOne;" ] ;
+ lmt_registerglyph [ category = "dice", unicode = "0x2681", code = "DiceTwo;" ] ;
+ lmt_registerglyph [ category = "dice", unicode = "0x2682", code = "DiceThree;" ] ;
+ lmt_registerglyph [ category = "dice", unicode = "0x2683", code = "DiceFour;" ] ;
+ lmt_registerglyph [ category = "dice", unicode = "0x2684", code = "DiceFive;" ] ;
+ lmt_registerglyph [ category = "dice", unicode = "0x2685", code = "DiceSix;" ] ;
+
+ lmt_registerglyph [ category = "dice", private = "invaliddice", code = "DiceBad;" ] ;
+
+\stopMPcalculation
+
+%D At the \TEX\ end we define three features. The reverse is just there for fun. The
+%D digits features will map digits onto dice.
+
+\definefontfeature
+ [dice:normal]
+ [default]
+ [metapost={category=dice}]
+
+\definefontfeature
+ [dice:reverse]
+ [default]
+ [metapost={category=dice,option=reverse}]
+
+\definefontfeature
+ [dice:digits]
+ [dice:digits=yes]
+
+%D The mapping to dice happens here:
+
+\startluacode
+
+ -- local invalid = fonts.helpers.privateslot("invaliddice")
+
+ fonts.handlers.otf.addfeature("dice:digits", {
+ type = "substitution",
+ order = { "dice:digits" },
+ nocheck = true,
+ data = {
+ [0x30] = "invaliddice",
+ [0x31] = 0x2680,
+ [0x32] = 0x2681,
+ [0x33] = 0x2682,
+ [0x34] = 0x2683,
+ [0x35] = 0x2684,
+ [0x36] = 0x2685,
+ [0x37] = "invaliddice",
+ [0x38] = "invaliddice",
+ [0x39] = "invaliddice",
+ },
+ } )
+
+\stopluacode
+
+%D An example is given at the the end of this file so we now move forward with
+%D the dominos.
+
+\startMPcalculation{simplefun}
+
+ %D Because there are so many dominos we predefine the shapes and then register
+ %D the lot in a loop.
+
+ picture Dominos[] ;
+
+ Dominos[0] := image() ;
+ Dominos[1] := image(draw(4,4);) ;
+ Dominos[2] := image(draw(2,6);draw(6,2););
+ Dominos[3] := image(draw(2,6);draw(4,4);draw(6,2););
+ Dominos[4] := image(draw(2,6);draw(6,6);draw(2,2);draw(6,2););
+ Dominos[5] := image(draw(2,6);draw(6,6);draw(4,4);draw(2,2);draw(6,2););
+ Dominos[6] := image(draw(2,6);draw(4,6);draw(6,6);draw(2,2);draw(4,2);draw(6,2););
+ % Dominos[7] := Dominos[0] ;
+ % Dominos[8] := Dominos[0] ;
+ % Dominos[9] := Dominos[0] ;
+
+ %D Defining the font properties is straightforward:
+
+ lmt_registerglyphs [
+ name = "dominos",
+ units = 12,
+ width = 16,
+ height = 8,
+ depth = 0,
+ usecolor = true,
+ ] ;
+
+ %D We have horizontal dominos:
+
+ def DrawDominoH(expr a, b) =
+ draw image (
+ pickup pencircle scaled 1/2 ;
+ if (getparameterdefault "mpsfont" "color" "") = "black" :
+ fillup unitsquare xyscaled (16,8) ;
+ draw (8,.5) -- (8,7.5) withcolor white ;
+ pickup pencircle scaled 3/2 ;
+ draw Dominos[a]
+ withpen currentpen
+ withcolor white ;
+ draw Dominos[b] shifted (8,0)
+ withpen currentpen
+ withcolor white ;
+ else :
+ draw unitsquare xyscaled (16,8) ;
+ draw (8,0) -- (8,8) ;
+ pickup pencircle scaled 3/2 ;
+ draw Dominos[a]
+ withpen currentpen ;
+ draw Dominos[b] shifted (8,0)
+ withpen currentpen ;
+ fi ;
+ ) ;
+ enddef ;
+
+ %D and vertical ones. We could use the above macro and rotate and shift and reflect
+ %D but why bother with it:
+
+ def DrawDominoV(expr a, b) = % is H rotated and shifted
+ draw image (
+ pickup pencircle scaled 1/2 ;
+ if (getparameterdefault "mpsfont" "color" "") = "black" :
+ fillup unitsquare xyscaled (8,16) ;
+ draw (.5,8) -- (7.5,8) withcolor white ;
+ pickup pencircle scaled 3/2 ;
+ draw Dominos[a] rotatedaround(center Dominos[a],90)
+ withpen currentpen
+ withcolor white ;
+ draw Dominos[b] rotatedaround(center Dominos[b],90) shifted (0,8)
+ withpen currentpen
+ withcolor white ;
+ else :
+ draw unitsquare xyscaled (8,16) ;
+ draw (0,8) -- (8,8) ;
+ pickup pencircle scaled 3/2 ;
+ draw Dominos[a] rotatedaround(center Dominos[a],90)
+ withpen currentpen ;
+ draw Dominos[b] rotatedaround(center Dominos[b],90) shifted (0,8)
+ withpen currentpen ;
+ fi ;
+ ) ;
+ enddef ;
+
+ %D We have two simple loops that define the horizontal range:
+
+ save unicode ; numeric unicode ; unicode := 127025 ; % 1F031
+
+ for i=0 upto 6 :
+ for j=0 upto 6 :
+ lmt_registerglyph [
+ category = "dominos",
+ unicode = unicode,
+ code = "DrawDominoH(" & decimal i & "," & decimal j & ");",
+ width = 16,
+ height = 8,
+ ] ;
+ unicode := unicode + 1 ;
+ endfor ;
+ endfor ;
+
+ %D and the vertical range:
+
+ save unicode ; numeric unicode ; unicode := 127075 ;
+
+ for i=0 upto 6 :
+ for j=0 upto 6 :
+ lmt_registerglyph [
+ category = "dominos",
+ unicode = unicode,
+ code = "DrawDominoV(" & decimal i & "," & decimal j & ");",
+ width = 8,
+ height = 16,
+ ] ;
+ unicode := unicode + 1 ;
+ endfor ;
+ endfor ;
+
+ %D Now we're done at the \METAFUN\ end.
+
+\stopMPcalculation
+
+%D We predefine two features:
+
+\definefontfeature
+ [dominos:white]
+ [default]
+ [metapost={category=dominos}]
+
+\definefontfeature
+ [dominos:black]
+ [default]
+ [metapost={category=dominos,color=black}]
+
+\definefontfeature
+ [dominos:digits]
+ [dominos:digits=yes]
+
+%D This last feature is yet to be defined. We could deal with the invalid
+%D dominos with some substitution trickery but let's keep it simple.
+
+\startluacode
+
+ local ligatures = { }
+ local unicode = 127025
+
+ for i=0x30,0x36 do
+ for j=0x30,0x36 do
+ ligatures[unicode] = { i, j }
+ unicode = unicode + 1 ;
+ end
+ end
+
+ fonts.handlers.otf.addfeature("dominos:digits", {
+ type = "ligature",
+ order = { "dominos:digits" },
+ nocheck = true,
+ data = ligatures,
+ } )
+
+\stopluacode
+
+\continueifinputfile{meta-imp-gamesymbols.mkxl}
+
+\starttext
+
+ \definefont[DominoW][Serif*dominos:white]
+ \definefont[DominoB][Serif*dominos:black]
+ \definefont[DominoD][Serif*dominos:white,dominos:digits]
+
+ \startTEXpage[offset=3pt]
+ \DominoW
+ \char"1F043\quad 🀱\quad
+ \char"1F052\quad 🀲\quad
+ \char"1F038\quad 🀳\quad
+ \darkgreen\char"1F049\quad \char"1F07B\quad
+ \DominoB
+ \char"1F087\quad
+ \char"1F088\quad
+ \char"1F089\quad
+ \DominoD
+ \darkred 12\quad56\quad64%
+ \stopTEXpage
+
+ \definefont[DiceN][Serif*dice:normal]
+ \definefont[DiceR][Serif*dice:reverse]
+ \definefont[DiceD][Serif*dice:normal,dice:digits]
+
+ \startTEXpage[offset=3pt]
+ \DiceN
+ \dostepwiserecurse{"2680}{"2685}{1}{\char#1\quad}%
+ \DiceN
+ \dostepwiserecurse{"2680}{"2685}{1}{\char#1\quad}%
+ \DiceD
+ \darkblue 2\quad5\quad3\quad0
+ \stopTEXpage
+
+\stoptext
diff --git a/Master/texmf-dist/tex/context/base/mkiv/meta-imp-symbols.mkxl b/Master/texmf-dist/tex/context/base/mkiv/meta-imp-symbols.mkxl
new file mode 100644
index 00000000000..f88fd6f8787
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/meta-imp-symbols.mkxl
@@ -0,0 +1,99 @@
+%D \module
+%D [ file=meta-imp-symbols,
+%D version=2019.10.01,
+%D title=\METAPOST\ Graphics,
+%D subtitle=Symbols,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This is an (experimental) prelude to more.
+
+\startMPcalculation{simplefun}
+
+ pen SymbolPen ; SymbolPen := pencircle scaled 1/4 ;
+
+ vardef SymbolBullet = fill unitcircle scaled 3 shifted (1.5,1.5) withpen SymbolPen enddef ; % 0x2022 •
+ vardef SymbolDash = draw (origin--right) scaled 3 shifted (1.5,3.0) withpen SymbolPen scaled 2 enddef ; % 0x2013 –
+ vardef SymbolTriangle = draw unittriangle scaled 3 shifted (1.5,1.5) withpen SymbolPen enddef ; % 0x25B6 ⊳
+ vardef SymbolCircle = fill unitcircle scaled 3 shifted (1.5,1.5) withpen SymbolPen enddef ; % 0x2218 ∘
+ vardef SymbolSquare = draw unitsquare scaled (3-1/16) shifted (1.5,1.5) withpen SymbolPen enddef ; % 0x25A1 □
+ vardef SymbolDiamond = draw unitdiamond scaled 3 shifted (1.5,1.5) withpen SymbolPen enddef ; % 0x22C4 ⋄
+ vardef SymbolBlackTriangle = fillup unittriangle scaled (3-1/16) shifted (1.5,1.5) withpen SymbolPen enddef ; % 0x25B6 ▶
+ vardef SymbolBlackSquare = fillup unitsquare scaled (3-1/16) shifted (1.5,1.5) withpen SymbolPen enddef ; % 0x25A0 ■
+ vardef SymbolBlackDiamond = fillup unitdiamond scaled (3-1/16) shifted (1.5,1.5) withpen SymbolPen enddef ; % 0x25C6 ◆
+
+ vardef SymbolNotDef =
+ draw center unitcircle
+ scaled 3
+ shifted (1.5,1.5)
+ withpen SymbolPen scaled 4
+ enddef ;
+
+ vardef SymbolStar = % 0x22C6 % ⋆
+ SymbolNotDef
+ enddef ;
+
+ vardef SymbolCheckmark = % 0x2713 ✓
+ SymbolNotDef
+ enddef ;
+
+ vardef SymbolAsterisk = % 0x2217 ∗
+ SymbolNotDef
+ enddef ;
+
+ % We could set code directly to the meaning of the macro.
+
+ lmt_registerglyphs [
+ name = "symbols",
+ units = 10,
+ usecolor = true,
+ width = 6,
+ height = 6,
+ depth = 0,
+ code = "SymbolNotDef ;",
+ ] ;
+
+ lmt_registerglyph [ category = "symbols", unicode = "0x2022", code = "SymbolBullet ;" ] ;
+ lmt_registerglyph [ category = "symbols", unicode = "0x2013", code = "SymbolDash ;" ] ;
+ lmt_registerglyph [ category = "symbols", unicode = "0x22C6" ] ; % , code = "SymbolStar ;" ] ;
+ lmt_registerglyph [ category = "symbols", unicode = "0x22B3", code = "SymbolTriangle ;" ] ;
+ lmt_registerglyph [ category = "symbols", unicode = "0x2218", code = "SymbolCircle ;" ] ;
+ lmt_registerglyph [ category = "symbols", unicode = "0x25A1", code = "SymbolSquare ;" ] ;
+ lmt_registerglyph [ category = "symbols", unicode = "0x22C4", code = "SymbolDiamond ;" ] ;
+ lmt_registerglyph [ category = "symbols", unicode = "0x2713" ] ; % , code = "SymbolCheckmark ;" ] ;
+ lmt_registerglyph [ category = "symbols", unicode = "0x2217" ] ; % , code = "SymbolAsterisk ;" ] ;
+ lmt_registerglyph [ category = "symbols", unicode = "0x25B6", code = "SymbolBlackTriangle ;" ] ;
+ lmt_registerglyph [ category = "symbols", unicode = "0x25A0", code = "SymbolBlackSquare ;" ] ;
+ lmt_registerglyph [ category = "symbols", unicode = "0x25C6", code = "SymbolBlackDiamond ;" ] ;
+
+\stopMPcalculation
+
+\continueifinputfile{meta-imp-symbols.mkxl}
+
+\usemodule[article-basic] \setupbodyfont[pagella]
+
+\starttext
+
+\definefontfeature[metasymbols][metapost=symbols]
+
+\definefont[MyFont] [Serif*default,metasymbols sa 1]
+
+Some metasymbols:
+
+\startitem {\MyFont • □ ◆}\quad Regular rendering. \stopitem
+\startitem {\MyFont\red • □ ◆}\quad Rendering with color. \stopitem
+\startitem {\MyFont\blue\showglyphs • □ ◆}\quad Idem but with boundingboxes shown. \stopitem
+
+And some more:
+
+\startlines
+ • – ⋆ ⊳ ∘ □ ⋄ ✓ ∗ ▶ ■ ◆
+ {\MyFont • – ⋆ ⊳ ∘ □ ⋄ ✓ ∗ ▶ ■ ◆}
+\stoplines
+
+\stoptext
diff --git a/Master/texmf-dist/tex/context/base/mkiv/meta-imp-tab.mkiv b/Master/texmf-dist/tex/context/base/mkiv/meta-imp-tab.mkiv
index a4affbea458..2604c3aa454 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/meta-imp-tab.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/meta-imp-tab.mkiv
@@ -34,7 +34,7 @@
\unexpanded\def\tallynumeral#1%
{\dontleavehmode
- \lower.25\exheight\hbox{\useMPgraphic{TallyBar}{n=#1}}}
+ \lower.25\exheight\hpack{\useMPgraphic{TallyBar}{n=#1}}}
\unexpanded\def\tallynumerals#1%
{\dontleavehmode
@@ -42,11 +42,11 @@
\scratchcounter#1\relax
\doloop
{\ifnum\scratchcounter>\plusfive
- \lower.25\exheight\hbox{\useMPgraphic{TallyBar}{n=5}}%
+ \lower.25\exheight\hpack{\useMPgraphic{TallyBar}{n=5}}%
\advance\scratchcounter-\plusfive
\space
\else
- \lower.25\exheight\hbox{\useMPgraphic{TallyBar}{n=\the\scratchcounter}}%
+ \lower.25\exheight\hpack{\useMPgraphic{TallyBar}{n=\the\scratchcounter}}%
\exitloop
\fi}%
\endgroup}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/meta-imp-threesix.mkxl b/Master/texmf-dist/tex/context/base/mkiv/meta-imp-threesix.mkxl
new file mode 100644
index 00000000000..277aa85f717
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/meta-imp-threesix.mkxl
@@ -0,0 +1,253 @@
+% not yet a module
+
+\startluacode
+ local gsub, utfbyte = string.gsub, utf.byte
+
+ -- The font from DEK's facs9b.ps (I wish I was clever enough to understand all the good
+ -- stuff in there):
+
+ local font36 = {
+ ["0"] = [[00111100 01111110 11000011 11000011 11000011 11000011 01111110 00111100]],
+ ["1"] = [[00011100 11111100 11101100 00001100 00001100 00001100 11111111 11111111]],
+ ["2"] = [[00111110 01110011 01110011 00000011 00001110 00111000 11110001 11111111]],
+ ["3"] = [[01111110 01100110 00000110 00111100 00000110 11100111 11100111 01111110]],
+ ["4"] = [[00001110 00011110 00110110 01100110 11111111 11111111 00000110 00001110]],
+ ["5"] = [[01111110 01111110 01000000 01111100 01000111 00000011 11000111 11111110]],
+ ["6"] = [[01111110 01100110 11000000 11011100 11100110 11000011 01100011 01111110]],
+ ["7"] = [[11111111 11111111 10000111 10001110 00011100 00011100 00011100 00011100]],
+ ["8"] = [[01111110 01100110 01100110 00111100 11000011 11000011 11000011 01111110]],
+ ["9"] = [[01111110 11000110 11000011 01100111 00111011 00000011 01100110 01111110]],
+ ["A"] = [[000110000 000111000 001111100 001101100 011001110 011111110 010000110 111100111]],
+ ["B"] = [[1111100 1110110 0110110 0111100 0110011 0110011 1110011 1111100]],
+ ["C"] = [[01111101 11110011 11100001 11100001 11100000 11100000 11100001 01111110]],
+ ["D"] = [[11111100 11100010 01100011 01100011 01100011 01100011 11100010 11111100]],
+ ["E"] = [[1111111 1110001 0110101 0111100 0110100 0110001 1110001 1111111]],
+ ["F"] = [[11111111 11100001 01100101 01111100 01100100 01100000 11111000 11111000]],
+ ["G"] = [[01111010 11100110 11100010 11100000 11100111 11100010 11100010 01111100]],
+ ["H"] = [[11100111 11100111 01000010 01111110 01000010 01000010 11100111 11100111]],
+ ["I"] = [[1111111 1111111 0011000 0011000 0011000 0011000 1111111 1111111]],
+ ["J"] = [[01111111 01111111 00000110 00000110 11110110 01100110 01100110 00111100]],
+ ["K"] = [[11101110 11100100 01101000 01110000 01111000 01101100 11100110 11101111]],
+ ["L"] = [[111111000 111111000 011000000 011000000 011000000 011000011 111000011 111111111]],
+ ["M"] = [[1100000011 1110000111 0111111110 0100110010 0100110010 0100000010 1100000011 1100000011]],
+ ["N"] = [[11000011 11100011 01110010 01111010 01011110 01001110 11100110 11100010]],
+ ["O"] = [[01111110 11000011 11000011 11000011 11000011 11000011 11000011 01111110]],
+ ["P"] = [[11111110 11100011 01100011 01111110 01100000 01100000 11111000 11111000]],
+ ["Q"] = [[01111100 11000110 11000110 11000110 11000110 11001110 11000110 01111101]],
+ ["R"] = [[11111100 11100110 01100110 01111100 01101000 01100100 11100010 11100111]],
+ ["S"] = [[01111110 11100001 11100001 01111000 00011110 10000111 11000011 10111110]],
+ ["T"] = [[1111111111 1100110011 1100110011 0000110000 0000110000 0000110000 0001111000 0001111000]],
+ ["U"] = [[111101111 111101111 011000010 011000010 011000010 011000010 011000010 001111100]],
+ ["V"] = [[11111000111 11111000111 01110000010 00110000100 00111000100 00011001000 00001101000 00001110000]],
+ ["W"] = [[111000000111 111000000111 110000000010 011000000100 011001000100 001101101000 001101101000 000110110000]],
+ ["X"] = [[1111001110 1111000110 0001101000 0000110000 0000110000 0001011000 0110001111 0111001111]],
+ ["Y"] = [[111100011 111100011 011000010 001110100 000111000 000011000 001111110 001111110]],
+ ["Z"] = [[11111111 10000111 00001110 00011100 00111000 01110000 11100001 11111111]],
+ }
+
+ local f_code = string.formatters["ThreeSix(%s);"]
+ local replace = { ["0"] = "N;", ["1"] = "Y;", [" "] = "L;" }
+
+ local function remap(str)
+ -- permit abundant spacing (bonus)
+ str = gsub(str,"%s+", " ")
+ -- remap what we got to macro calls
+ str = gsub(str,".",replace)
+ -- return the result
+ return str
+ end
+
+ function MP.registerthreesix(name)
+ fonts.dropins.registerglyphs {
+ name = name,
+ units = 12,
+ usecolor = true,
+ preamble = "InitializeThreeSix;",
+ }
+ for u, v in table.sortedhash(font36) do
+ local ny = 8
+ local nx = (#v - ny + 1) // ny
+ local height = ny * 1.1 - 0.1
+ local width = nx * 1.1 - 0.1
+ fonts.dropins.registerglyph {
+ category = name,
+ unicode = utfbyte(u),
+ width = width,
+ height = height,
+ code = f_code(remap(v)),
+ }
+ end
+ end
+
+ MP.registerthreesix("fontthreesix")
+\stopluacode
+
+% \startMPcalculation{simplefun}
+% def InitializeThreeSix =
+% save Y, N, L, S ; save dx, dy, nx, ny ;
+% save shape, fillcolor, mypen, random, currentpen, spread, hoffset ;
+% string shape, fillcolor, mypen ; boolean random ; pen currentpen ;
+% dx := 11/10 ;
+% dy := - 11/10 ;
+% nx := - dx ;
+% ny := 0 ;
+% shape := getparameterdefault "mpsfont" "shape" "circle" ;
+% random := hasoption "mpsfont" "random" "true" ;
+% fillcolor := getparameterdefault "mpsfont" "color" "" ;
+% mypen := getparameterdefault "mpsfont" "pen" "" ;
+% spread := getparameterdefault "mpsfont" "spread" 0 ;
+% hoffset := 12 * spread / 2 ;
+% currentpen := pencircle
+% if mypen = "fancy" :
+% xscaled 1/20 yscaled 2/20 rotated 45
+% else :
+% scaled 1/20
+% fi ;
+% if shape == "square" :
+% def S =
+% unitsquare if random : randomized 1/10 fi
+% shifted (nx,ny)
+% enddef ;
+% elseif shape = "diamond" :
+% def S =
+% unitdiamond if random : randomized 1/10 fi
+% shifted (nx,ny)
+% enddef ;
+% else :
+% def S =
+% unitcircle if random : randomizedcontrols 1/20 fi
+% shifted (nx,ny)
+% enddef ;
+% fi ;
+% def N =
+% nx := nx + dx ;
+% draw S ;
+% enddef ;
+% if fillcolor = "random" :
+% def Y =
+% nx := nx + dx ;
+% fillup S withcolor white randomized (2/3,2/3,2/3) ;
+% enddef ;
+% elseif fillcolor = "" :
+% def Y =
+% nx := nx + dx ;
+% fillup S ;
+% enddef ;
+% else :
+% def Y =
+% nx := nx + dx ;
+% fillup S withcolor fillcolor ;
+% enddef ;
+% fi ;
+% def L =
+% nx := - dx ;
+% ny := ny + dy ;
+% enddef ;
+% enddef ;
+%
+% vardef ThreeSix (text code) =
+% InitializeThreeSix ;
+% draw image (code) shifted (hoffset,-ny) ;
+% enddef ;
+% \stopMPcalculation
+
+\startMPcalculation{simplefun}
+ def InitializeThreeSix =
+ save Y, N, L, S ;
+ % save dx, dy, nx, ny ;
+ save shape, fillcolor, mypen, random, threesixpen, spread, hoffset ;
+ string shape, fillcolor, mypen ; boolean random ; pen threesixpen ;
+ % dx := 11/10 ;
+ % dy := - 11/10 ;
+ % nx := - dx ;
+ % ny := 0 ;
+ shape := getparameterdefault "mpsfont" "shape" "circle" ;
+ random := hasoption "mpsfont" "random" "true" ;
+ fillcolor := getparameterdefault "mpsfont" "color" "" ;
+ mypen := getparameterdefault "mpsfont" "pen" "" ;
+ spread := getparameterdefault "mpsfont" "spread" 0 ;
+ hoffset := 12 * spread / 2 ;
+ threesixpen := pencircle
+ if mypen = "fancy" :
+ xscaled 1/20 yscaled 2/20 rotated 45
+ else :
+ scaled 1/20
+ fi ;
+ if shape == "square" :
+ def S =
+ unitsquare if random : randomized 1/10 fi
+ shifted (nx,ny)
+ enddef ;
+ elseif shape = "diamond" :
+ def S =
+ unitdiamond if random : randomized 1/10 fi
+ shifted (nx,ny)
+ enddef ;
+ else :
+ def S =
+ unitcircle if random : randomizedcontrols 1/20 fi
+ shifted (nx,ny)
+ enddef ;
+ fi ;
+ def N =
+ nx := nx + dx ;
+ draw S ;
+ enddef ;
+ if fillcolor = "random" :
+ def Y =
+ nx := nx + dx ;
+ fillup S withcolor white randomized (2/3,2/3,2/3) ;
+ enddef ;
+ elseif fillcolor = "" :
+ def Y =
+ nx := nx + dx ;
+ fillup S ;
+ enddef ;
+ else :
+ def Y =
+ nx := nx + dx ;
+ fillup S withcolor fillcolor ;
+ enddef ;
+ fi ;
+ def L =
+ nx := - dx ;
+ ny := ny + dy ;
+ enddef ;
+ enddef ;
+
+ vardef ThreeSix (text code) =
+ save dx, dy, nx, ny ;
+ dx := 11/10 ;
+ dy := - 11/10 ;
+ nx := - dx ;
+ ny := 0 ;
+ pickup threesixpen ;
+ draw image (code) shifted (hoffset,-ny) ;
+ enddef ;
+\stopMPcalculation
+
+\definefontfeature % black and white, with some spread
+ [fontthreesix]
+ [default]
+ [metapost=fontthreesix]
+
+\definefontfeature % color, with some spread
+ [fontthreesix-tweak]
+ [default]
+ [metapost={category=fontthreesix,spread=.1}]
+
+\definefontfeature % color, with some spread
+ [fontthreesix-color]
+ [default]
+ [metapost={category=fontthreesix,shape=diamond,color=random,pen=fancy,spread=.1}]
+
+\definefontfeature % color, tight
+ [fontthreesix-initial]
+ [metapost={category=fontthreesix,color=random,shape=circle}] % units?
+
+\definefont[DEKFontA][Serif*fontthreesix]
+\definefont[DEKFontB][Serif*fontthreesix-color]
+\definefont[DEKFontC][Serif*fontthreesix-initial]
+\definefont[DEKFontD][Serif*fontthreesix-tweak]
+
+\endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/meta-imp-txt.mkiv b/Master/texmf-dist/tex/context/base/mkiv/meta-imp-txt.mkiv
index d4329cd6ffd..e683c3766c9 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/meta-imp-txt.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/meta-imp-txt.mkiv
@@ -58,7 +58,7 @@
\scratchcounter\zerocount
\scratchtoks\emptytoks
\def\docommand##1%
- {\setbox\scratchbox\hbox{\useMPgraphic{##1}}%
+ {\setbox\scratchbox\hpack{\useMPgraphic{##1}}%
\global\parfirst\zerocount
\getMPdata
\setshapecharacteristics
@@ -389,7 +389,7 @@
%D \stoplinecorrection
\unexpanded\def\TightText#1#2#3#4%
- {\hbox % \ruledhbox
+ {\hpack
{\startMPcode
picture p ; p := image (graphictext "#1" withfillcolor red) ;
draw p xsized #2 ysized #3 withcolor \MPcolor{#4} ;
diff --git a/Master/texmf-dist/tex/context/base/mkiv/meta-ini.mkiv b/Master/texmf-dist/tex/context/base/mkiv/meta-ini.mkiv
index 89c7699deb5..97d2e1a7d19 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/meta-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/meta-ini.mkiv
@@ -167,10 +167,10 @@
\appendtoks
\ifcsname\??mpdefinitions\currentMPinstance\endcsname \else
- \expandafter\newtoks\csname\??mpdefinitions\currentMPinstance\endcsname
+ \expandafter\newtoks\csname\??mpdefinitions\currentMPinstance\endcsname
\fi
\ifcsname\??mpinclusions\currentMPinstance\endcsname \else
- \expandafter\newtoks\csname\??mpinclusions\currentMPinstance\endcsname
+ \expandafter\newtoks\csname\??mpinclusions\currentMPinstance\endcsname
\fi
\t_meta_definitions\emptytoks % in case we redefine
\t_meta_inclusions \emptytoks % in case we redefine
@@ -243,7 +243,6 @@
{\ifconditional\c_meta_include_initializations
\the\t_meta_initializations
\fi}
- % \theMPrandomseed;}
\def\meta_flush_current_inclusions
{\the\t_meta_inclusions}
@@ -279,9 +278,12 @@
{\pushMPboundingbox
\setbox\b_meta_graphic\hpack\bgroup}
+\let\meta_relocate_graphic\relax % experimental hook
+
\def\meta_process_graphic_stop
{\egroup
\meta_place_graphic
+ \meta_relocate_graphic
\popMPboundingbox}
\unexpanded\def\meta_process_graphic_instance#1%
@@ -408,37 +410,42 @@
\let\stopMPclip\relax
-\unexpanded\def\meta_grab_clip_path#1#2#3#4% #4 is alternative (called in backend code)
+\unexpanded\def\meta_grab_clip_path#1#2#3%
{\begingroup
- \edef\width {#2}% \let\overlaywidth \width
- \edef\height{#3}% \let\overlayheight\height
- \d_overlay_width #2\onebasepoint
- \d_overlay_height#3\onebasepoint
+ \d_overlay_width #2\relax
+ \d_overlay_height#3\relax
+ \edef\width {\the\d_overlay_width \space}%
+ \edef\height{\the\d_overlay_height\space}%
\edef\currentMPclip{#1}%
\ifcsname\??mpclip\currentMPclip\endcsname
- \meta_grab_clip_path_indeed
- \ifx\MPclippath\empty
- \xdef\MPclippath{#4}%
- \fi
+ \meta_grab_clip_path_yes
\else
- \xdef\MPclippath{#4}%
+ \meta_grab_clip_path_nop
\fi
\endgroup}
-\def\meta_grab_clip_path_indeed
+\def\meta_grab_clip_path_yes
{\meta_start_current_graphic
\normalexpanded{\noexpand\clf_mpsetclippath
- instance {\currentMPinstance}%
- format {\currentMPformat}%
- data {\csname\??mpclip\currentMPclip\endcsname}%
- initializations {\meta_flush_current_initializations}%
- useextensions {\MPinstanceparameter\s!extensions}%
- inclusions {\meta_flush_current_inclusions}%
- method {\MPinstanceparameter\c!method}%
+ instance {\currentMPinstance}%
+ format {\currentMPformat}%
+ data {\csname\??mpclip\currentMPclip\endcsname}%
+ initializations {\meta_flush_current_initializations}%
+ useextensions {\MPinstanceparameter\s!extensions}%
+ inclusions {\meta_flush_current_inclusions}%
+ method {\MPinstanceparameter\c!method}%
+ width \d_overlay_width
+ height \d_overlay_height
\relax}%
\meta_stop_current_graphic}
-%D Since we want lables to follow the document settings, we also set the font
+\def\meta_grab_clip_path_nop
+ {\clf_mpsetclippath
+ width \d_overlay_width
+ height \d_overlay_height
+ \relax}
+
+%D Since we want labels to follow the document settings, we also set the font
%D related variables.
\unexpanded\def\MPfontsizehskip#1%
@@ -565,7 +572,7 @@
\def\meta_prepare_variable_nop
{\expandafter \let\csname\m_meta_current_variable_template\endcsname\meta_prepare_variable_default}
-\def\meta_prepare_variable_color
+\def\meta_prepare_variable_color % we use the attribute so we dont' go through namedcolor (why not)
{\expandafter\edef\csname\m_meta_current_variable_template\endcsname{\MPcolor\m_meta_current_variable}}
\def\meta_prepare_variable_number
@@ -604,7 +611,11 @@
%D \defineoverlay[example][\uniqueMPgraphic{test}]
%D
%D \startuniqueMPgraphic {test}
-%D draw unitsquare xscaled \overlaywidth yscaled \overlayheight ;
+%D draw OverlayBox ;
+%D \stopuniqueMPgraphic
+%D
+%D \startuniqueMPgraphic {test}
+%D draw OverlayBox ;
%D \stopuniqueMPgraphic
%D \stoptyping
@@ -655,10 +666,10 @@
\kern\MPllx\raise\MPlly\box\b_meta_graphic
\egroup}
-\unexpanded\def\obeyMPboxdepth {\let\meta_relocate_box\meta_obey_box_depth }
+\unexpanded\def\obeyMPboxdepth {\let\meta_relocate_box\meta_obey_box_depth}
\unexpanded\def\ignoreMPboxdepth{\let\meta_relocate_box\meta_ignore_box_depth}
-\unexpanded\def\obeyMPboxorigin {\let\meta_relocate_box\meta_obey_box_origin }
-\unexpanded\def\normalMPboxdepth{\let\meta_relocate_box\relax }
+\unexpanded\def\obeyMPboxorigin {\let\meta_relocate_box\meta_obey_box_origin}
+\unexpanded\def\normalMPboxdepth{\let\meta_relocate_box\relax}
\let\meta_relocate_box\relax
@@ -691,20 +702,19 @@
\unexpanded\def\startuniqueMPgraphic
{\dodoublegroupempty\meta_start_unique_graphic}
+\let\stopuniqueMPgraphic\relax
+
\def\meta_start_unique_graphic#1%
{\normalexpanded{\meta_start_unique_graphic_indeed{#1}}}
\unexpanded\def\meta_start_unique_graphic_indeed#1#2#3\stopuniqueMPgraphic
{\setgvalue{\??mpgraphic#1}{\meta_handle_unique_graphic{#1}{#2}{#3}}}
-\let\stopuniqueMPgraphic\relax
-
\unexpanded\def\uniqueMPgraphic
{\dodoublegroupempty\meta_unique_graphic}
\def\meta_unique_graphic#1#2%
{\meta_begin_graphic_group{#1}%
-% \setupMPvariables[\currentMPgraphicname][#2]%
\setupMPvariables[#1][#2]%
\csname\??mpgraphic#1\endcsname\empty
\meta_end_graphic_group}
@@ -723,6 +733,8 @@
\unexpanded\def\startuseMPgraphic
{\dodoublegroupempty\meta_start_use_graphic}
+\let\stopuseMPgraphic\relax
+
% \def\meta_start_use_graphic#1#2#3\stopuseMPgraphic
% {\setgvalue{\??mpgraphic#1}{\meta_handle_use_graphic{#1}{#2}{#3}}}
%
@@ -741,13 +753,10 @@
\unexpanded\def\meta_start_use_graphic_indeed#1#2#3\stopuseMPgraphic
{\setgvalue{\??mpgraphic#1}{\meta_handle_use_graphic{#1}{#2}{#3}}}
-\let\stopuseMPgraphic\relax
-
\unexpanded\def\startusableMPgraphic % redundant but handy
{\dodoublegroupempty\meta_start_usable_graphic}
-% \def\meta_start_usable_graphic#1#2#3\stopusableMPgraphic
-% {\setgvalue{\??mpgraphic#1}{\meta_handle_use_graphic{#1}{#2}{#3}}}
+\let\stopusableMPgraphic\relax
\def\meta_start_usable_graphic#1%
{\normalexpanded{\meta_start_usable_graphic_indeed{#1}}}
@@ -755,8 +764,6 @@
\unexpanded\def\meta_start_usable_graphic_indeed#1#2#3\stopusableMPgraphic
{\setgvalue{\??mpgraphic#1}{\meta_handle_use_graphic{#1}{#2}{#3}}}
-\let\stopusableMPgraphic\relax
-
\def\meta_handle_reusable_graphic#1#2#3%
{\begingroup
\edef\currentmpvariableclass{#1}%
@@ -774,8 +781,7 @@
\unexpanded\def\startreusableMPgraphic
{\dodoublegroupempty\meta_start_reusable_graphic}
-% \def\meta_start_reusable_graphic#1#2#3\stopreusableMPgraphic
-% {\setgvalue{\??mpgraphic#1}{\meta_handle_reusable_graphic{#1}{#2}{#3}}}
+\let\stopreusableMPgraphic\relax
\def\meta_start_reusable_graphic#1%
{\normalexpanded{\meta_start_reusable_graphic_indeed{#1}}}
@@ -783,18 +789,9 @@
\unexpanded\def\meta_start_reusable_graphic_indeed#1#2#3\stopreusableMPgraphic
{\setgvalue{\??mpgraphic#1}{\meta_handle_reusable_graphic{#1}{#2}{#3}}}
-\let\stopreusableMPgraphic\relax
-
\unexpanded\def\useMPgraphic
{\dodoublegroupempty\meta_use_graphic}
-% \def\meta_use_graphic#1#2%
-% {\meta_begin_graphic_group{#1}%
-% %\doifsomething{#2}{\setupMPvariables[\currentMPgraphicname][#2]}%
-% \doifsomething{#2}{\setupMPvariables[#1][#2]}%
-% \csname\??mpgraphic#1\endcsname\empty
-% \meta_end_graphic_group}
-
\def\meta_use_graphic#1#2%
{\meta_begin_graphic_group{#1}%
\ifcsname\??mpgraphic#1\endcsname
@@ -822,9 +819,6 @@
\def\m_meta_page_prefix{\doifelseoddpage oe}
-% \def\overlaypagestamp
-% {\m_meta_page_prefix:\overlaywidth:\overlayheight:\overlaydepth:\MPcolor\overlaycolor:\MPcolor\overlaylinecolor}
-
\def\overlaypagestamp
{\m_meta_page_prefix :%
\the\d_overlay_width :%
@@ -838,9 +832,7 @@
\unexpanded\def\startuniqueMPpagegraphic
{\dodoublegroupempty\meta_start_unique_page_graphic}
-% \def\meta_start_unique_page_graphic#1#2#3\stopuniqueMPpagegraphic % inefficient, double storage
-% {\setgvalue{\??mpgraphic o:#1}{\meta_handle_unique_graphic{o:#1}{#2}{#3}}% % but these also keep the state
-% \setgvalue{\??mpgraphic e:#1}{\meta_handle_unique_graphic{e:#1}{#2}{#3}}} % and meaning will be redefined
+\let\stopuniqueMPpagegraphic\relax
\def\meta_start_unique_page_graphic#1%
{\normalexpanded{\meta_start_unique_page_graphic_indeed{#1}}}
@@ -849,15 +841,12 @@
{\setgvalue{\??mpgraphic o:#1}{\meta_handle_unique_graphic{o:#1}{#2}{#3}}% % but these also keep the state
\setgvalue{\??mpgraphic e:#1}{\meta_handle_unique_graphic{e:#1}{#2}{#3}}} % and meaning will be redefined
-\let\stopuniqueMPpagegraphic\relax
-
\unexpanded\def\uniqueMPpagegraphic
{\dodoublegroupempty\meta_unique_page_graphic}
\def\meta_unique_page_graphic#1#2%
{\meta_begin_graphic_group{#1}%
\let\overlaystamp\overlaypagestamp
-% \setupMPvariables[\m_meta_page_prefix:\currentMPgraphicname][#2]% prefix is new here
\setupMPvariables[\m_meta_page_prefix:#1][#2]% prefix is new here
\csname\??mpgraphic\m_meta_page_prefix:#1\endcsname\empty
\meta_end_graphic_group}
@@ -954,6 +943,8 @@
\unexpanded\def\startMPcode
{\dosinglegroupempty\meta_start_code}
+\let\stopMPcode\relax
+
\def\meta_start_code
{\iffirstargument
\expandafter\meta_start_code_instance
@@ -978,8 +969,6 @@
\meta_process_graphic{#2}%
\endgroup}
-\let\stopMPcode\relax
-
\unexpanded\def\MPcode
{\dodoublegroupempty\meta_code}
@@ -1425,6 +1414,8 @@
\setbox\nextbox\hpack\bgroup
\dosinglegroupempty\meta_start_calculation}
+\let\stopMPcalculation\relax
+
\def\meta_start_calculation
{\iffirstargument
\expandafter\meta_start_calculation_instance
@@ -1449,8 +1440,6 @@
\egroup
\endgroup}
-\let\stopMPcalculation\relax
-
%D \macros
%D {setupMPgraphics}
%D
diff --git a/Master/texmf-dist/tex/context/base/mkiv/meta-ini.mkxl b/Master/texmf-dist/tex/context/base/mkiv/meta-ini.mkxl
new file mode 100644
index 00000000000..e08aa560a71
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/meta-ini.mkxl
@@ -0,0 +1,1465 @@
+%D \module
+%D [ file=meta-ini,
+%D version=2008.03.25,
+%D title=\METAPOST\ Graphics,
+%D subtitle=Initialization,
+%D author=Hans Hagen,
+%D date=\ currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% initializations:
+%
+% - pass settings from tex to mp (delayed expansion)
+% - used by context core (and modules)
+% - cummulative definitions
+% - flushed each graphic
+% - can be disabled per instance
+% - managed at the tex end
+%
+% extensions:
+%
+% - add mp functionality (immediate expansion)
+% - cummulative
+% - all instances or subset of instances
+% - can be disabled per instance
+% - managed at the lua/mp end
+% - could be managed at the tex end but no real reason and also messy
+%
+% definitions:
+%
+% - add mp functionality (delayed expansion)
+% - cummulative
+% - per instance
+% - managed at the tex end
+%
+% inclusions:
+%
+% - add mp functionality (delayed expansion)
+% - cummulative only when [+]
+% - per instance
+% - managed at the tex end
+%
+% order of execution:
+%
+% definitions
+% extensions
+% inclusions
+% beginfig
+% initializations
+% graphic
+% endfig
+
+% The instance will be implemented stepwise ... I should redo some code in order to
+% make the macros look better than they do now.
+
+\writestatus{loading}{MetaPost Graphics / Initializations}
+
+\registerctxluafile{meta-ini}{}
+
+\unprotect
+
+\newtoks \everyMPgraphic % mp % public or not ?
+
+\appendtoks
+ \restoreendofline % see interferences-001.tex
+\to \everyMPgraphic
+
+\def\MPruntimefile {mprun}
+\def\currentMPformat {metafun}
+\def\defaultMPinstance{metafun}
+
+\installcorenamespace{mpinstance}
+\installcorenamespace{mpinclusions}
+\installcorenamespace{mpdefinitions}
+\installcorenamespace{mpgraphic}
+\installcorenamespace{mpstaticgraphic}
+\installcorenamespace{mpclip}
+
+\newtoks \t_meta_initializations % tex, each
+\def \t_meta_inclusions {\csname\??mpinclusions \currentMPinstance\endcsname} % token register
+\def \t_meta_definitions {\csname\??mpdefinitions\currentMPinstance\endcsname} % token register
+
+%D The next command is, of course, dedicated to Mojca, who needs it for gnuplot.
+%D Anyway, the whole multiple engine mechanism is to keep her gnuplot from
+%D interfering.
+
+\unexpanded\def\startMPdefinitions
+ {\dosinglegroupempty\meta_start_definitions}
+
+\def\meta_start_definitions#1#2\stopMPdefinitions
+ {\let\m_meta_saved_instance\currentMPinstance
+ \edef\currentMPinstance{#1}%
+ \ifx\currentMPinstance\empty
+ \let\currentMPinstance\defaultMPinstance
+ \fi
+ \gtoksapp\t_meta_definitions{#2}%
+ \let\currentMPinstance\m_meta_saved_instance}
+
+\let\stopMPdefinitions\relax
+
+\unexpanded\def\startMPextensions
+ {\dosinglegroupempty\meta_start_extensions}
+
+\def\meta_start_extensions#1#2\stopMPextensions % we could use buffers instead
+ {\clf_setmpextensions{#1}{#2}}
+
+\let\stopMPextensions\relax
+
+\unexpanded\def\startMPinitializations#1\stopMPinitializations % for all instances, when enabled
+ {\gtoksapp\t_meta_initializations{#1}}
+
+\let\stopMPinitializations\relax
+
+\unexpanded\def\startMPinclusions
+ {\dosingleempty\meta_start_inclusions}
+
+\unexpanded\def\meta_start_inclusions[#1]%
+ {\edef\m_meta_option{#1}%
+ \dosinglegroupempty\meta_start_inclusions_indeed}
+
+\def\meta_start_inclusions_indeed#1#2\stopMPinclusions
+ {\let\m_meta_saved_instance\currentMPinstance
+ \edef\currentMPinstance{#1}%
+ \ifx\currentMPinstance\empty
+ \let\currentMPinstance\defaultMPinstance
+ \fi
+ \ifx\m_meta_option\!!plustoken \else
+ \global\t_meta_inclusions\emptytoks
+ \fi
+ \gtoksapp\t_meta_inclusions{#2}%
+ \let\currentMPinstance\m_meta_saved_instance}
+
+\let\stopMPinclusions\relax
+
+\unexpanded\def\MPinclusions
+ {\dosingleempty\meta_inclusions}
+
+\def\meta_inclusions[#1]%
+ {\edef\m_meta_option{#1}%
+ \dosinglegroupempty\meta_inclusions_indeed}
+
+\def\meta_inclusions_indeed#1#2%
+ {\let\m_meta_saved_instance\currentMPinstance
+ \edef\currentMPinstance{#1}%
+ \ifx\currentMPinstance\empty
+ \let\currentMPinstance\defaultMPinstance
+ \fi
+ \ifx\m_meta_option\!!plustoken \else
+ \global\t_meta_inclusions\emptytoks
+ \fi
+ \gtoksapp\t_meta_inclusions{#2}%
+ \let\currentMPinstance\m_meta_saved_instance}
+
+\installcommandhandler \??mpinstance {MPinstance} \??mpinstance
+
+\setupMPinstance
+ [\s!format=metafun,
+ \s!extensions=\v!no,
+ \s!initializations=\v!no,
+ \c!method=\s!default,
+ \c!textstyle=,
+ \c!textcolor=]
+
+\appendtoks
+ \ifcsname\??mpdefinitions\currentMPinstance\endcsname \else
+ \expandafter\newtoks\csname\??mpdefinitions\currentMPinstance\endcsname
+ \fi
+ \ifcsname\??mpinclusions\currentMPinstance\endcsname \else
+ \expandafter\newtoks\csname\??mpinclusions\currentMPinstance\endcsname
+ \fi
+ \t_meta_definitions\emptytoks % in case we redefine
+ \t_meta_inclusions \emptytoks % in case we redefine
+\to \everydefineMPinstance
+
+\unexpanded\def\resetMPinstance[#1]%
+ {\writestatus\m!metapost{reset will be implemented when needed}}
+
+\def\meta_analyze_graphicname[#1]%
+ %{\normalexpanded{\meta_analyze_graphicname_indeed[#1::::]}}
+ {\normalexpanded{\meta_analyze_graphicname_indeed[#1}::::]}
+
+\def\meta_show_properties_indeed
+ {\writestatus{metapost}{name: \currentMPgraphicname, instance: \currentMPinstance, format: \currentMPformat}}
+
+\let\meta_show_properties\donothing
+
+\installtextracker
+ {metapost.properties}
+ {\let\meta_show_properties\meta_show_properties_indeed}
+ {\let\meta_show_properties\donothing}
+
+\unexpanded\def\meta_analyze_graphicname_indeed[#1::#2::#3]% instance ::
+ {\edef\currentMPgraphicname{#2}%
+ \ifx\currentMPgraphicname\empty
+ \edef\currentMPgraphicname{#1}%
+ \let\currentMPinstance\defaultMPinstance
+ \orelse\ifcsname\??mpdefinitions#1\endcsname
+ \edef\currentMPinstance{#1}%
+ \else
+ \let\currentMPinstance\defaultMPinstance
+ \fi
+ \edef\currentMPformat{\MPinstanceparameter\s!format}%
+ \meta_show_properties}
+
+\def\currentMPgraphicname{\s!unknown}
+\def\currentMPinstance {\defaultMPinstance}
+\def\currentMPformat {\currentMPinstance}
+
+\defineMPinstance[metafun] [\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes]
+\defineMPinstance[minifun] [\s!format=minifun,\s!extensions=\v!yes,\s!initializations=\v!yes]
+\defineMPinstance[extrafun] [\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes]
+\defineMPinstance[lessfun] [\s!format=metafun]
+\defineMPinstance[doublefun] [\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes,\c!method=\s!double]
+\defineMPinstance[binaryfun] [\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes,\c!method=\s!binary]
+\defineMPinstance[decimalfun] [\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes,\c!method=\s!decimal]
+
+\defineMPinstance[mprun] [\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes]
+
+\defineMPinstance[metapost] [\s!format=mpost]
+\defineMPinstance[nofun] [\s!format=mpost]
+\defineMPinstance[doublepost] [\s!format=mpost,\c!method=\s!double]
+\defineMPinstance[binarypost] [\s!format=mpost,\c!method=\s!binary]
+\defineMPinstance[decimalpost][\s!format=mpost,\c!method=\s!decimal]
+
+\defineMPinstance[simplefun] [\s!format=metafun,\c!method=\s!double] % maybe use minifun
+
+%defineMPinstance[megapost] [\s!format=mpost,\c!method=\s!decimal]
+
+\newconditional\c_meta_include_initializations
+
+\def\meta_begin_graphic_group#1%
+ {\begingroup
+ \meta_analyze_graphicname[#1]}
+
+\def\meta_end_graphic_group
+ {\endgroup}
+
+\def\MPaskedfigure{false}
+
+\def\meta_flush_current_initializations
+ {\ifconditional\c_meta_include_initializations
+ \the\t_meta_initializations
+ \fi}
+
+\def\meta_flush_current_inclusions
+ {\the\t_meta_inclusions}
+
+\def\meta_flush_current_definitions
+ {\the\t_meta_definitions}
+
+\def\meta_start_current_graphic
+ {\begingroup
+ \meta_enable_include
+ \the\everyMPgraphic
+ \edef\p_initializations{\MPinstanceparameter\s!initializations}%
+ \ifx\p_initializations\v!yes
+ \settrue \c_meta_include_initializations
+ \else
+ \setfalse\c_meta_include_initializations
+ \fi
+ \edef\p_setups{\MPinstanceparameter\c!setups}%
+ \ifx\p_setups\empty \else
+ \setups[\p_setups]%
+ \fi
+ \useMPinstancestyleparameter\c!textstyle}
+
+\def\meta_set_current_color
+ {\useMPinstancecolorparameter\c!textcolor}
+
+\def\meta_stop_current_graphic
+ {\global\t_meta_definitions\emptytoks
+ \global\t_meta_inclusions\emptytoks
+ \endgroup}
+
+\def\meta_process_graphic_start
+ {\pushMPboundingbox
+ \setbox\b_meta_graphic\hpack\bgroup}
+
+\let\meta_relocate_graphic\relax % experimental hook
+
+\def\meta_process_graphic_stop
+ {\egroup
+ \meta_place_graphic
+ \meta_relocate_graphic
+ \popMPboundingbox}
+
+\unexpanded\def\meta_process_graphic_instance#1%
+ {\edef\currentMPinstance{#1}%
+ \ifx\currentMPinstance\empty
+ \let\currentMPinstance\defaultMPinstance
+ \fi
+ \edef\currentMPformat{\MPinstanceparameter\s!format}%
+ \meta_process_graphic}
+
+\unexpanded\def\meta_process_graphic#1% todo: extensions and inclusions outside beginfig
+ {\meta_start_current_graphic
+ \forgetall
+ \edef\p_extensions{\MPinstanceparameter\s!extensions}%
+ \meta_process_graphic_start
+ \normalexpanded{\noexpand\clf_mpgraphic
+ instance {\currentMPinstance}%
+ format {\currentMPformat}%
+ data {#1;}%
+ initializations {\meta_flush_current_initializations}%
+ \ifx\p_extensions\v!yes
+ extensions {\clf_getmpextensions{\currentMPinstance}}% goes through tex again
+ \fi
+ inclusions {\meta_flush_current_inclusions}%
+ definitions {\meta_flush_current_definitions}%
+ figure {\MPaskedfigure}%
+ method {\MPinstanceparameter\c!method}%
+ namespace {\??graphicvariable\currentmpvariableclass:}%
+ \relax}%
+ \meta_process_graphic_stop
+ \meta_stop_current_graphic}
+
+\let\meta_process_graphic_figure_start\relax
+\let\meta_process_graphic_figure_stop \relax
+
+\unexpanded\def\processMPfigurefile#1% special case: obeys beginfig .. endfig and makes pages
+ {\begingroup
+ \let\normal_meta_process_graphic_start\meta_process_graphic_start
+ \let\normal_meta_process_graphic_stop \meta_process_graphic_stop
+ \let\meta_process_graphic_start\relax
+ \let\meta_process_graphic_stop \relax
+ \def\meta_process_graphic_figure_start{\startTEXpage[\c!offset=\v!overlay,\c!align=]\normal_meta_process_graphic_start}%
+ \def\meta_process_graphic_figure_stop {\normal_meta_process_graphic_stop\stopTEXpage}
+ \def\MPaskedfigure{all}%
+ \meta_process_graphic{input "#1" ;}%
+ \endgroup}
+
+%D Calling up previously defined graphics.
+
+% \def\includeMPgraphic#1% gets expanded !
+% {\ifcsname\??mpgraphic#1\endcsname
+% \csname\??mpgraphic#1\endcsname ; % ; is safeguard
+% \fi}
+%
+% \unexpanded\def\meta_enable_include % public
+% {\let\meta_handle_use_graphic \thirdofthreearguments
+% \let\meta_handle_reusable_graphic\thirdofthreearguments}
+%
+% but ... we want this too:
+%
+% \startuseMPgraphic{x}
+% draw textext("\externalfigure[foo.pdf]") ;
+% \stopuseMPgraphic
+%
+% \useMPgraphic{x}
+%
+% so we cannot overload unless we let back to the original meanings each graphic
+% ... a better solution is:
+
+\def\includeMPgraphic#1% gets expanded !
+ {\ifcsname\??mpgraphic#1\endcsname
+ \doubleexpandafter\fourthoffourarguments\lastnamedcs ; % ; is safeguard
+ \fi}
+
+\let\meta_enable_include\relax
+
+%D Drawings (stepwise built):
+
+\newif\ifMPdrawingdone \MPdrawingdonefalse
+
+\unexpanded\def\finalizeMPdrawing
+ {\MPdrawingdonetrue}
+
+\let\MPdrawingdata\empty
+
+\unexpanded\def\resetMPdrawing
+ {\glet\MPdrawingdata\empty
+ \global\MPdrawingdonefalse}
+
+\unexpanded\def\pushMPdrawing
+ {\globalpushmacro\MPdrawingdata
+ \glet\MPdrawingdata\empty}
+
+\unexpanded\def\popMPdrawing
+ {\globalpopmacro\MPdrawingdata}
+
+\unexpanded\def\getMPdrawing
+ {\ifMPdrawingdone
+ \expandafter\meta_process_graphic\expandafter{\MPdrawingdata}% is this expansion still needed?
+ \fi}
+
+\def\startMPdrawing
+ {\dosingleempty\meta_start_drawing}
+
+\def\meta_start_drawing[#1]#2\stopMPdrawing % to be redone, this ascii stuff
+ {\relax
+ \bgroup
+ \meta_enable_include
+ \doifelse{#1}{-}{\convertargument#2\to\asciia}{\def\asciia{#2}}%
+ \xdef\MPdrawingdata{\MPdrawingdata\asciia}%
+ \egroup}
+
+\let\stopMPdrawing\relax
+
+\def\MPdrawing#1%
+ {\relax
+ \bgroup
+ \meta_enable_include
+ \xdef\MPdrawingdata{\MPdrawingdata#1}%
+ \egroup}
+
+\unexpanded\def\startMPclip#1#2\stopMPclip % todo: store at the lua end or just store less
+ {\setgvalue{\??mpclip#1}{#2}}
+
+\let\stopMPclip\relax
+
+\unexpanded\def\meta_grab_clip_path#1#2#3%
+ {\begingroup
+ \d_overlay_width #2\relax
+ \d_overlay_height#3\relax
+ \edef\width {\the\d_overlay_width \space}%
+ \edef\height{\the\d_overlay_height\space}%
+ \edef\currentMPclip{#1}%
+ \ifcsname\??mpclip\currentMPclip\endcsname
+ \meta_grab_clip_path_yes
+ \else
+ \meta_grab_clip_path_nop
+ \fi
+ \endgroup}
+
+\def\meta_grab_clip_path_yes
+ {\meta_start_current_graphic
+ \normalexpanded{\noexpand\clf_mpsetclippath
+ instance {\currentMPinstance}%
+ format {\currentMPformat}%
+ data {\csname\??mpclip\currentMPclip\endcsname}%
+ initializations {\meta_flush_current_initializations}%
+ useextensions {\MPinstanceparameter\s!extensions}%
+ inclusions {\meta_flush_current_inclusions}%
+ method {\MPinstanceparameter\c!method}%
+ width \d_overlay_width
+ height \d_overlay_height
+ \relax}%
+ \meta_stop_current_graphic}
+
+\def\meta_grab_clip_path_nop
+ {\clf_mpsetclippath
+ width \d_overlay_width
+ height \d_overlay_height
+ \relax}
+
+%D Since we want labels to follow the document settings, we also set the font
+%D related variables.
+
+\unexpanded\def\MPfontsizehskip#1%
+ {\dontleavehmode
+ \begingroup
+ \definedfont[#1]%
+ \hskip\clf_currentdesignsize\scaledpoint\relax
+ \endgroup}
+
+\definefontsynonym[MetafunDefault][Regular*default]
+
+\startMPinitializations % scale is not yet ok
+ defaultfont:="\truefontname{MetafunDefault}";
+ % defaultscale:=\the\bodyfontsize/10pt; % only when hard coded 10pt
+ % defaultscale:=1;
+\stopMPinitializations
+
+%D A signal that we're in combined \CONTEXT||\METAFUN mode:
+
+\startMPextensions
+ string contextversion;contextversion:="\contextversion"; % expanded
+\stopMPextensions
+
+%D \macros
+%D {setupMPvariables}
+%D
+%D When we build collections of \METAPOST\ graphics, like background and buttons,
+%D the need for passing settings arises. By (mis|)|using the local prefix that
+%D belongs to \type {\framed}, we get a rather natural interface to backgrounds. To
+%D prevent conflicts, we will use the \type {-} in \METAPOST\ specific variables,
+%D like:
+%D
+%D \starttyping
+%D \setupMPvariables[meta:button][size=20pt]
+%D \stoptyping
+
+% \lineheight 2pt 2 \scratchcounter red 0.4 .5\bodyfontsize
+%
+% see cont-loc for test code
+
+%D Currently the inheritance of backgrounds does not work and we might drop it
+%D anyway (too messy)
+
+\newbox\b_meta_variable_box
+
+\let \currentmpvariableclass \empty
+\let \m_meta_current_variable \empty
+\let \m_meta_current_variable_template\empty
+
+\installcorenamespace{graphicvariable}
+
+\def\meta_prepare_variable_default{\MPcolor{black}} % just to be sure we use a color but ...
+
+\unexpanded\def\setupMPvariables
+ {\dodoubleempty\meta_setup_variables}
+
+\def\meta_setup_variables[#1][#2]%
+ {\ifsecondargument
+ \getrawparameters[\??graphicvariable#1:][#2]%
+ \else
+ \getrawparameters[\??graphicvariable:][#1]%
+ \fi}
+
+\unexpanded\def\presetMPvariable
+ {\dodoubleargument\meta_preset_variable}
+
+\def\meta_preset_variable[#1][#2=#3]%
+ {\ifcsname\??graphicvariable#1:#2\endcsname \else
+ \setvalue{\??graphicvariable#1:#2}{#3}%
+ \fi}
+
+\def\MPrawvar#1#2% no checking
+ {\begincsname\??graphicvariable#1:#2\endcsname}
+
+\def\MPvariable#1% todo: could be a framed chain
+ {\begincsname\??graphicvariable\currentmpvariableclass:#1\endcsname}
+
+\unexpanded\def\useMPvariables
+ {\dodoubleargument\meta_use_variables}
+
+\def\meta_use_variables[#1][#2]%
+ {\edef\currentmpvariableclass{#1}%
+ \meta_prepare_variables{#2}}
+
+\unexpanded\def\meta_prepare_variables#1%
+ {\processcommalist[#1]\meta_prepare_variable}
+
+\unexpanded\def\meta_prepare_variable#1%
+ {\edef\m_meta_current_variable_template
+ {\??graphicvariable\currentmpvariableclass:#1}%
+ \edef\m_meta_current_variable
+ {\begincsname\m_meta_current_variable_template\endcsname}%
+ \ifx\m_meta_current_variable\empty
+ \expandafter\meta_prepare_variable_nop
+ \else
+ \expandafter\meta_prepare_variable_yes
+ \fi}
+
+\unexpanded\def\meta_prepare_instance_variables
+ {\expandafter\processcommalist\expandafter[\m_meta_instance_variables]\meta_prepare_instance_variable}
+
+\unexpanded\def\meta_prepare_instance_variable#1%
+ {\edef\m_meta_current_variable_template
+ {\??graphicvariable\currentmpvariableclass:#1}%
+ \edef\m_meta_current_variable
+ {\ifcsname\m_meta_current_variable_template\endcsname
+ \lastnamedcs
+ \else
+ \begincsname\??graphicvariable\currentMPgraphicname:#1\endcsname
+ \fi}%
+ \ifx\m_meta_current_variable\empty
+ \expandafter\meta_prepare_variable_nop
+ \else
+ \expandafter\meta_prepare_variable_yes
+ \fi}
+
+\def\meta_prepare_variable_nop
+ {\expandafter \let\csname\m_meta_current_variable_template\endcsname\meta_prepare_variable_default}
+
+\def\meta_prepare_variable_color % we use the attribute so we dont' go through namedcolor (why not)
+ {\expandafter\edef\csname\m_meta_current_variable_template\endcsname{\MPcolor\m_meta_current_variable}}
+
+\def\meta_prepare_variable_number
+ {\expandafter\edef\csname\m_meta_current_variable_template\endcsname{\number\m_meta_current_variable}}% also accepts 0.number
+
+\def\meta_prepare_variable_dimension
+ {\expandafter\edef\csname\m_meta_current_variable_template\endcsname{\the\dimexpr\m_meta_current_variable}}
+
+\def\meta_prepare_variable_yes
+ {\ifchkdim\m_meta_current_variable\or
+ \meta_prepare_variable_dimension
+ \else\ifchknum\m_meta_current_variable\or
+ \meta_prepare_variable_number
+ \else
+ \doifelsecolor\m_meta_current_variable
+ \meta_prepare_variable_color
+ \meta_prepare_variable_dimension
+ \fi\fi}
+
+\let\MPvar \MPvariable
+\let\setMPvariables\setupMPvariables
+
+%D \macros
+%D {startuniqueMPgraphic, uniqueMPgraphic}
+%D
+%D This macros is probably of most use to myself, since I like to use graphics that
+%D adapt themselves. The next \METAPOST\ kind of graphic is both unique and reused
+%D when possible.
+%D
+%D \starttyping
+%D \defineoverlay[example][\uniqueMPgraphic{test}]
+%D
+%D \startuniqueMPgraphic {test}
+%D draw OverlayBox ;
+%D \stopuniqueMPgraphic
+%D
+%D \startuniqueMPgraphic {test}
+%D draw OverlayBox ;
+%D \stopuniqueMPgraphic
+%D \stoptyping
+
+\def\overlaystamp % watch the \MPcolor, since colors can be redefined
+ {\the\d_overlay_width :%
+ \the\d_overlay_height :%
+ \the\d_overlay_depth :%
+ \the\d_overlay_offset :%
+ \the\d_overlay_linewidth:%
+ \MPcolor\overlaycolor :% % todo, expand once \m_overlaycolor
+ \MPcolor\overlaylinecolor} % todo, expand once \m_overlaylinecolor
+
+%D A better approach is to let additional variables play a role in determining the
+%D uniqueness. In the next macro, the second, optional, argument is used to
+%D guarantee the uniqueness, as well as prepare variables for passing them to
+%D \METAPOST.
+%D
+%D \starttyping
+%D \startuniqueMPgraphic{meta:hash}{gap,angle,...}
+%D \stoptyping
+%D
+%D The calling macro also accepts a second argument. For convenient use in overlay
+%D definitions, we use \type {{}} instead of \type {[]}.
+%D
+%D \starttyping
+%D \uniqueMPgraphic{meta:hash}{gap=10pt,angle=30}
+%D \stoptyping
+
+\newcount\c_meta_object_counter
+\newbox \b_meta_graphic
+
+% hm, isn't this already done elsewhere?
+
+\unexpanded\def\meta_obey_box_depth
+ {\setbox\b_meta_graphic\hpack\bgroup
+ \raise\MPlly\box\b_meta_graphic
+ \egroup}
+
+\unexpanded\def\meta_ignore_box_depth
+ {\normalexpanded
+ {\meta_obey_box_depth % hence the \unexpanded
+ \wd\b_meta_graphic\the\wd\b_meta_graphic
+ \ht\b_meta_graphic\the\ht\b_meta_graphic
+ \dp\b_meta_graphic\the\dp\b_meta_graphic}}
+
+\unexpanded\def\meta_obey_box_origin
+ {\setbox\b_meta_graphic\hpack\bgroup
+ \kern\MPllx\raise\MPlly\box\b_meta_graphic
+ \egroup}
+
+\unexpanded\def\obeyMPboxdepth {\let\meta_relocate_box\meta_obey_box_depth}
+\unexpanded\def\ignoreMPboxdepth{\let\meta_relocate_box\meta_ignore_box_depth}
+\unexpanded\def\obeyMPboxorigin {\let\meta_relocate_box\meta_obey_box_origin}
+\unexpanded\def\normalMPboxdepth{\let\meta_relocate_box\relax}
+
+\let\meta_relocate_box\relax
+
+\unexpanded\def\meta_place_graphic % the converter also displaces so in fact we revert
+ {\meta_relocate_box
+ \box\b_meta_graphic}
+
+\unexpanded\def\meta_reuse_box#1#2#3#4#5% space delimiting would save some tokens
+ {\MPllx#2\MPlly#3\MPurx#4\MPury#5%
+ \hpack{\forcecolorhack\getobject{MP}{#1}}} % else no proper color intent
+
+\unexpanded\def\meta_use_box
+ {\setunreferencedobject{MP}}
+
+\def\meta_handle_unique_graphic#1#2#3% when there are too many, we can store data at the lua end, although,
+ {\begingroup % when there are that many they're probably not that unique anyway
+ \edef\currentmpvariableclass{#1}%
+ \extendMPoverlaystamp{#2}% incl prepare
+ \ifcsname\??mpgraphic\overlaystamp:#1\endcsname
+ \lastnamedcs
+ \else
+ \meta_enable_include % redundant
+ \global\advance\c_meta_object_counter\plusone
+ \meta_use_box{\number\c_meta_object_counter}\hpack{\meta_process_graphic{#3}}% was vbox, graphic must end up as hbox
+ \setxvalue{\??mpgraphic\overlaystamp:#1}{\meta_reuse_box{\number\c_meta_object_counter}{\the\MPllx}{\the\MPlly}{\the\MPurx}{\the\MPury}}%
+ \csname\??mpgraphic\overlaystamp:#1\endcsname\empty
+ \fi
+ \endgroup}
+
+\unexpanded\def\startuniqueMPgraphic
+ {\dodoublegroupempty\meta_start_unique_graphic}
+
+\let\stopuniqueMPgraphic\relax
+
+\def\meta_start_unique_graphic#1%
+ {\normalexpanded{\meta_start_unique_graphic_indeed{#1}}}
+
+\unexpanded\def\meta_start_unique_graphic_indeed#1#2#3\stopuniqueMPgraphic
+ {\setgvalue{\??mpgraphic#1}{\meta_handle_unique_graphic{#1}{#2}{#3}}}
+
+\unexpanded\def\uniqueMPgraphic
+ {\dodoublegroupempty\meta_unique_graphic}
+
+\def\meta_unique_graphic#1#2%
+ {\meta_begin_graphic_group{#1}%
+ \setupMPvariables[#1][#2]%
+ \begincsname\??mpgraphic#1\endcsname\empty
+ \meta_end_graphic_group}
+
+\def\meta_handle_use_graphic#1#2#3%
+ {\begingroup
+ \edef\currentmpvariableclass{#1}%
+ \edef\m_meta_instance_variables{#2}%
+ \ifx\m_meta_instance_variables\empty \else
+ \meta_prepare_instance_variables
+ \fi
+ \meta_enable_include % redundant
+ \meta_process_graphic{#3}%
+ \endgroup}
+
+\unexpanded\def\startuseMPgraphic
+ {\dodoublegroupempty\meta_start_use_graphic}
+
+\let\stopuseMPgraphic\relax
+
+\def\meta_start_use_graphic#1%
+ {\normalexpanded{\meta_start_use_graphic_indeed{#1}}}
+
+\unexpanded\def\meta_start_use_graphic_indeed#1#2#3\stopuseMPgraphic
+ {\setgvalue{\??mpgraphic#1}{\meta_handle_use_graphic{#1}{#2}{#3}}}
+
+\unexpanded\def\startusableMPgraphic % redundant but handy
+ {\dodoublegroupempty\meta_start_usable_graphic}
+
+\let\stopusableMPgraphic\relax
+
+\def\meta_start_usable_graphic#1%
+ {\normalexpanded{\meta_start_usable_graphic_indeed{#1}}}
+
+\unexpanded\def\meta_start_usable_graphic_indeed#1#2#3\stopusableMPgraphic
+ {\setgvalue{\??mpgraphic#1}{\meta_handle_use_graphic{#1}{#2}{#3}}}
+
+\def\meta_handle_reusable_graphic#1#2#3%
+ {\begingroup
+ \edef\currentmpvariableclass{#1}%
+ \edef\m_meta_instance_variables{#2}%
+ \ifx\m_meta_instance_variables\empty \else
+ \meta_prepare_instance_variables
+ \fi
+ \meta_enable_include % redundant
+ \global\advance\c_meta_object_counter\plusone
+ \meta_use_box{\number\c_meta_object_counter}\hpack{\meta_process_graphic{#3}}% was vbox, graphic must end up as hbox
+ \setxvalue{\??mpgraphic#1}{\meta_reuse_box{\number\c_meta_object_counter}{\the\MPllx}{\the\MPlly}{\the\MPurx}{\the\MPury}}%
+ \csname\??mpgraphic#1\endcsname\empty
+ \endgroup}
+
+\unexpanded\def\startreusableMPgraphic
+ {\dodoublegroupempty\meta_start_reusable_graphic}
+
+\let\stopreusableMPgraphic\relax
+
+\def\meta_start_reusable_graphic#1%
+ {\normalexpanded{\meta_start_reusable_graphic_indeed{#1}}}
+
+\unexpanded\def\meta_start_reusable_graphic_indeed#1#2#3\stopreusableMPgraphic
+ {\setgvalue{\??mpgraphic#1}{\meta_handle_reusable_graphic{#1}{#2}{#3}}}
+
+\unexpanded\def\useMPgraphic
+ {\dodoublegroupempty\meta_use_graphic}
+
+\def\meta_use_graphic#1#2%
+ {\meta_begin_graphic_group{#1}%
+ \ifcsname\??mpgraphic#1\endcsname
+ \edef\usedMPgraphicname{#1}%
+ \orelse\ifcsname\??mpgraphic\currentMPgraphicname\endcsname
+ \let\usedMPgraphicname\currentMPgraphicname
+ \else
+ \let\usedMPgraphicname\empty
+ \fi
+ \ifx\usedMPgraphicname\empty
+ % message
+ \else
+ \doifsomething{#2}{\setupMPvariables[\usedMPgraphicname][#2]}%
+ \csname\??mpgraphic\usedMPgraphicname\endcsname
+ \fi
+ \meta_end_graphic_group}
+
+\let\reuseMPgraphic \useMPgraphic % we can save a setup here if needed
+\let\reusableMPgraphic\reuseMPgraphic % we can save a setup here if needed
+
+%D \macros
+%D {startuniqueMPpagegraphic,uniqueMPpagegraphic}
+%D
+%D Experimental.
+
+\def\m_meta_page_prefix{\doifelseoddpage oe}
+
+\def\overlaypagestamp
+ {\m_meta_page_prefix :%
+ \the\d_overlay_width :%
+ \the\d_overlay_height :%
+ \the\d_overlay_depth :%
+ \the\d_overlay_offset :%
+ \the\d_overlay_linewidth:%
+ \MPcolor\overlaycolor :%
+ \MPcolor\overlaylinecolor}
+
+\unexpanded\def\startuniqueMPpagegraphic
+ {\dodoublegroupempty\meta_start_unique_page_graphic}
+
+\let\stopuniqueMPpagegraphic\relax
+
+\def\meta_start_unique_page_graphic#1%
+ {\normalexpanded{\meta_start_unique_page_graphic_indeed{#1}}}
+
+\unexpanded\def\meta_start_unique_page_graphic_indeed#1#2#3\stopuniqueMPpagegraphic % inefficient, double storage
+ {\setgvalue{\??mpgraphic o:#1}{\meta_handle_unique_graphic{o:#1}{#2}{#3}}% % but these also keep the state
+ \setgvalue{\??mpgraphic e:#1}{\meta_handle_unique_graphic{e:#1}{#2}{#3}}} % and meaning will be redefined
+
+\unexpanded\def\uniqueMPpagegraphic
+ {\dodoublegroupempty\meta_unique_page_graphic}
+
+\def\meta_unique_page_graphic#1#2%
+ {\meta_begin_graphic_group{#1}%
+ \let\overlaystamp\overlaypagestamp
+ \setupMPvariables[\m_meta_page_prefix:#1][#2]% prefix is new here
+ \csname\??mpgraphic\m_meta_page_prefix:#1\endcsname\empty
+ \meta_end_graphic_group}
+
+%D One way of defining a stamp is:
+%D
+%D \starttyping
+%D \def\extendMPoverlaystamp#1%
+%D {\def\docommand##1%
+%D {\edef\overlaystamp{\overlaystamp:\MPvariable{##1}}}%
+%D \processcommalist[#1]\docommand}
+%D \stoptyping
+%D
+%D Since we need to feed \METAPOST\ with expanded dimensions, we introduce a
+%D dedicated expansion engine. We redefine \type {\extendMPoverlaystamp} to
+
+\unexpanded\def\extendMPoverlaystamp#1%
+ {\processcommalist[#1]\meta_extend_overlay_stamp}
+
+\def\meta_extend_overlay_stamp#1%
+ {\meta_prepare_instance_variable{#1}%
+ \edef\overlaystamp{\overlaystamp:\MPvariable{#1}}}
+
+\unexpanded\def\getMPdata {\clf_getMPdata}
+ \let\rawMPdata \clf_getMPdata
+
+\unexpanded\def\getMPstored{\clf_getMPstored}
+ \let\rawMPstored \clf_getMPstored
+
+%D We need this trick because we need to make sure that the tex scanner sees
+%D newlines and does not quit. Also, we do need to flush the buffer under a normal
+%D catcode regime in order to expand embedded tex macros. As usual with buffers,
+%D \type {#1} can be a list.
+
+\unexpanded\def\processMPbuffer
+ {\dosingleempty\meta_process_buffer}
+
+\def\meta_process_buffer[#1]%
+ {\meta_begin_graphic_group{#1}%
+ \meta_process_graphic{\clf_feedback{\currentMPgraphicname}}%
+ \meta_end_graphic_group}
+
+\unexpanded\def\runMPbuffer
+ {\dosingleempty\meta_run_buffer}
+
+\def\meta_run_buffer[#1]% processing only
+ {\startnointerference\meta_process_buffer[#1]\stopnointerference}
+
+%D \macros
+%D {startMPenvironment, resetMPenvironment}
+%D
+%D In order to synchronize the main \TEX\ run and the runs local to \METAPOST,
+%D environments can be passed.
+
+\unexpanded\def\startMPenvironment
+ {\begingroup
+ \catcode\endoflineasciicode \ignorecatcode
+ \dosingleempty\meta_start_environment}
+
+\def\meta_start_environment[#1]#2\stopMPenvironment
+ {\endgroup
+ \edef\m_meta_option{#1}
+ \ifx\m_meta_option\s!reset
+ \resetMPenvironment % reset mp toks
+ \orelse\ifx\m_meta_option\v!global
+ #2% % use in main doc too
+ \orelse\ifx\m_meta_option\!!plustoken
+ #2% % use in main doc too
+ \fi
+ \clf_mptexset{\detokenize{#2}}}
+
+\let\stopMPenvironment\relax
+
+\unexpanded\def\resetMPenvironment
+ {\clf_mptexreset}
+
+\unexpanded\def\useMPenvironmentbuffer[#1]%
+ {\clf_mptexsetfrombuffer{#1}}
+
+%D This command takes \type {[reset]} as optional argument.
+%D
+%D \starttyping
+%D \startMPenvironment
+%D \setupbodyfont[pos,14.4pt]
+%D \stopMPenvironment
+%D
+%D \startMPcode
+%D draw btex \sl Hans Hagen etex scaled 5 ;
+%D \stopMPcode
+%D \stoptyping
+%D
+%D The most simple case:
+
+\unexpanded\def\startMPcode
+ {\dosinglegroupempty\meta_start_code}
+
+\let\stopMPcode\relax
+
+\def\meta_start_code
+ {\iffirstargument
+ \expandafter\meta_start_code_instance
+ \else
+ \expandafter\meta_start_code_standard
+ \fi}
+
+\def\meta_start_code_instance#1#2\stopMPcode
+ {\begingroup
+ \edef\currentMPinstance{#1}%
+ \let\currentMPgraphicname\empty
+ \edef\currentMPformat{\MPinstanceparameter\s!format}%
+ \meta_enable_include
+ \meta_process_graphic{#2}%
+ \endgroup}
+
+\def\meta_start_code_standard#1#2\stopMPcode
+ {\begingroup
+ \let\currentMPinstance\defaultMPinstance
+ \let\currentMPgraphicname\empty
+ \edef\currentMPformat{\MPinstanceparameter\s!format}%
+ \meta_process_graphic{#2}%
+ \endgroup}
+
+\unexpanded\def\MPcode
+ {\dodoublegroupempty\meta_code}
+
+\def\meta_code
+ {\ifsecondargument
+ \expandafter\meta_code_instance
+ \else
+ \expandafter\meta_code_standard
+ \fi}
+
+\def\meta_code_instance#1#2%
+ {\meta_begin_graphic_group{#1}%
+ \meta_enable_include
+ \meta_process_graphic{#2}%
+ \meta_end_graphic_group}
+
+\def\meta_code_standard#1#2%
+ {\let\currentMPinstance\defaultMPinstance
+ \meta_enable_include
+ \meta_process_graphic{#1}}
+
+% a bit nasty (also needed for compatibility:
+
+% \startMPrun input mp-www.mp ; \stopMPrun
+% \externalfigure[mprun.3][width=10cm,height=8cm]
+
+% \startMPrun{mprun} input mp-www.mp ; \stopMPrun % instance
+% \externalfigure[mprun.4][width=10cm,height=8cm]
+
+\let\MPruninstance\defaultMPinstance
+
+\unexpanded\def\useMPrun#1#2% name n
+ {\begingroup
+ \def\MPaskedfigure{#2}%
+ \doifelsenothing{#1}
+ {\useMPgraphic{mprun}}%
+ {\useMPgraphic{#1}}%
+ \endgroup}
+
+\unexpanded\def\startMPrun
+ {\dosinglegroupempty\meta_start_run}
+
+\def\meta_start_run#1#2\stopMPrun
+ {\iffirstargument
+ \startuseMPgraphic{#1}#2\stopuseMPgraphic
+ \else
+ \startuseMPgraphic{mprun}#2\stopuseMPgraphic
+ \fi}
+
+\let\stopMPrun\relax
+
+%D The \type {\resetMPenvironment} is a quick way to erase
+%D the token list.
+%D
+%D You should be aware of independencies. For instance, if you use a font
+%D in a graphic that is not used in the main document, you need to load the
+%D typescript at the outer level (either directly or by using the global
+%D option).
+%D
+%D \starttyping
+%D \usetypescript[palatino][texnansi]
+%D
+%D \startMPenvironment
+%D \usetypescript[palatino][texnansi]
+%D \enableregime[utf]
+%D \setupbodyfont[palatino]
+%D \stopMPenvironment
+%D
+%D \startMPpage
+%D draw btex aap‒noot coördinatie – één etex ;
+%D \stopMPpage
+%D \stoptyping
+
+%D Loading specific \METAPOST\ related definitions is
+%D accomplished by:
+
+\unexpanded\def\useMPlibrary[#1]{\clf_useMPlibrary{#1}}
+
+%D \macros
+%D {setMPtext, MPtext, MPstring, MPbetex}
+%D
+%D To be documented:
+%D
+%D \starttyping
+%D \setMPtext{identifier}{text}
+%D
+%D \MPtext {identifier}
+%D \MPstring{identifier}
+%D \MPbetex {identifier}
+%D \stoptyping
+
+\installcorenamespace{mptext}
+
+\unexpanded\def\setMPtext#1#2% todo : #1 must be made : safe
+ {\defconvertedargument\ascii{#2}%
+ \dodoglobal\letvalue{\??mptext#1}\ascii}
+
+\def\MPtext #1{\begincsname\??mptext#1\endcsname\empty}
+\def\MPstring#1{"\begincsname\??mptext#1\endcsname\empty"}
+\def\MPbetex #1{btex \begincsname\??mptext#1\endcsname\space etex}
+
+%D In order to communicate conveniently with the \TEX\ engine, we introduce some
+%D typesetting variables.
+
+% \setupcolors[state=stop,conversion=never] % quite tricky ... type mismatch
+
+% \startMPextensions
+% color OverlayColor,OverlayLineColor;
+% \stopMPextensions
+
+\startMPinitializations
+ CurrentLayout:="\currentlayout";
+\stopMPinitializations
+
+% \startMPinitializations
+% OverlayWidth:=\overlaywidth;
+% OverlayHeight:=\overlayheight;
+% OverlayDepth:=\overlaydepth;
+% OverlayLineWidth:=\overlaylinewidth;
+% OverlayOffset:=\overlayoffset;
+% \stopMPinitializations
+
+%D A dirty trick, ** in colo-ini.lua (mpcolor). We cannot use a vardef, because
+%D that fails with spot colors.
+
+\startMPinitializations
+ def OverlayLineColor=\ifx\overlaylinecolor\empty black \else\MPcolor{\overlaylinecolor} \fi enddef;
+ def OverlayColor =\ifx\overlaycolor \empty black \else\MPcolor{\overlaycolor} \fi enddef;
+\stopMPinitializations
+
+% \newcount\c_overlay_colormodel
+% \newcount\c_overlay_color
+% \newcount\c_overlay_transparency
+% \newcount\c_overlay_linecolor
+% \newcount\c_overlay_linetransparency
+
+% \appendtoks
+% \c_overlay_colormodel \attribute\colormodelattribute
+% \c_overlay_color \colo_helpers_inherited_current_ca\overlaycolor
+% \c_overlay_transparency \colo_helpers_inherited_current_ta\overlaycolor
+% \c_overlay_linecolor \colo_helpers_inherited_current_ca\overlaylinecolor
+% \c_overlay_linetransparency\colo_helpers_inherited_current_ta\overlaylinecolor
+% \to \everyMPgraphic
+
+% \startMPinitializations
+% BaseLineSkip:=\the\baselineskip;
+% LineHeight:=\the\baselineskip;
+% BodyFontSize:=\the\bodyfontsize;
+% %
+% TopSkip:=\the\topskip;
+% StrutHeight:=\strutheight;
+% StrutDepth:=\strutdepth;
+% %
+% CurrentWidth:=\the\hsize;
+% CurrentHeight:=\the\vsize;
+% HSize:=\the\hsize ;
+% VSize:=\the\vsize ;
+% %
+% EmWidth:=\the\emwidth;
+% ExHeight:=\the\exheight;
+% \stopMPinitializations
+
+\appendtoks
+ \disablediscretionaries
+ %\disablecompoundcharacters
+\to \everyMPgraphic
+
+% \appendtoks % before color, inefficient, replace by low level copy
+% \doregistercolor{currentcolor}\currentcolorname
+% \to \everyMPgraphic
+
+% \color[green]{abc \startMPcode
+% fill fullcircle scaled 3cm withoutcolor;
+% fill fullcircle scaled 2cm withcolor \MPcolor{currentcolor} ;
+% fill fullcircle scaled 1cm withcolor \MPcolor{red} ;
+% \stopMPcode def}
+
+\appendtoks
+ \baselineskip1\baselineskip
+ \lineheight 1\lineheight
+ \topskip 1\topskip
+\to \everyMPgraphic
+
+\appendtoks
+ \let \# \letterhash
+ \let \_ \letterunderscore
+ \let \& \letterampersand
+ \let \{ \letteropenbrace
+ \let \} \letterclosebrace
+\to \everyMPgraphic
+
+%D \macros
+%D {PDFMPformoffset}
+%D
+%D In \PDF, forms are clipped and therefore we have to take precautions to get this
+%D right. Since this is related to objects, we use the same offset as used there.
+
+\def\PDFMPformoffset{\objectoffset}
+
+\newtoks\everyinsertMPfile
+
+\startMPextensions
+ def initialize_form_numbers =
+ do_initialize_numbers;
+ enddef;
+\stopMPextensions
+
+\startMPextensions
+ vardef ForegroundBox =
+ unitsquare xysized(HSize,VSize)
+ enddef ;
+\stopMPextensions
+
+% \startMPextensions
+% PageFraction := 1 ;
+% \stopMPextensions
+
+% \startMPinitializations
+% PageFraction := if \lastpage>1: (\realfolio-1)/(\lastpage-1) else: 1 fi ;
+% \stopMPinitializations
+
+\startMPdefinitions {metapost}
+ if unknown context_bare : input mp-bare.mpiv ; fi ;
+\stopMPdefinitions
+\startMPdefinitions {binarypost}
+ if unknown context_bare : input mp-bare.mpiv ; fi ;
+\stopMPdefinitions
+\startMPdefinitions {decimalpost}
+ if unknown context_bare : input mp-bare.mpiv ; fi ;
+\stopMPdefinitions
+\startMPdefinitions {doublepost}
+ if unknown context_bare : input mp-bare.mpiv ; fi ;
+\stopMPdefinitions
+
+% \startMPdefinitions {nofun}
+% if unknown context_bare : input mp-bare.mpiv ; fi ;
+% \stopMPdefinitions
+
+%D And some more. These are not really needed since we don't use the normal figure
+%D inclusion macros any longer.
+
+\appendtoks
+ \externalfigurepostprocessors\emptytoks % safeguard
+\to \everyinsertMPfile
+
+%D We also take care of disabling fancy figure features, that can terribly interfere
+%D when dealing with symbols, background graphics and running (postponed) graphics.
+%D You won't believe me if I tell you what funny side effects can occur. One took me
+%D over a day to uncover when processing the screen version of the \METAFUN\ manual.
+
+\def\doifelseMPgraphic#1%
+ {\ifcsname\??mpgraphic #1\endcsname\expandafter\firstoftwoarguments \orelse
+ \ifcsname\??mpgraphic o:#1\endcsname\expandafter\firstoftwoarguments \orelse
+ \ifcsname\??mpgraphic e:#1\endcsname\expandafter\firstoftwoarguments \else
+ \expandafter\secondoftwoarguments\fi}
+
+\let\doifMPgraphicelse\doifelseMPgraphic
+
+%D New:
+
+\definelayerpreset % no dx,dy - else nasty non-mp placement
+ [mp]
+ [\c!y=-\MPury,
+ \c!x=\MPllx,
+ \c!method=\v!fit]
+
+\definelayer
+ [mp]
+ [\c!preset=mp]
+
+%D Usage:
+%D
+%D \starttyping
+%D \defineviewerlayer[one][state=start]
+%D \defineviewerlayer[two][state=stop]
+%D
+%D \startuseMPgraphic{step-1}
+%D fill fullcircle scaled 10cm withcolor red ;
+%D \stopuseMPgraphic
+%D
+%D \startuseMPgraphic{step-2}
+%D fill fullcircle scaled 5cm withcolor green ;
+%D \stopuseMPgraphic
+%D
+%D \setlayer[mp]{\viewerlayer[one]{\useMPgraphic{step-1}}}
+%D \setlayer[mp]{\viewerlayer[two]{\useMPgraphic{step-2}}}
+%D
+%D \ruledhbox{\flushlayer[mp]}
+%D \stoptyping
+%D
+%D Reusing graphics is also possible (now):
+%D
+%D \starttyping
+%D \startreusableMPgraphic{axis}
+%D tickstep := 1cm ; ticklength := 2mm ;
+%D drawticks unitsquare xscaled 4cm yscaled 3cm shifted (-1cm,-1cm) ;
+%D tickstep := tickstep/2 ; ticklength := ticklength/2 ;
+%D drawticks unitsquare xscaled 4cm yscaled 3cm shifted (-1cm,-1cm) ;
+%D \stopreusableMPgraphic
+%D
+%D \startuseMPgraphic{demo}
+%D drawpoint "1cm,1.5cm" ;
+%D \stopuseMPgraphic
+%D
+%D \definelayer[mp][preset=mp]
+%D \setlayer[mp]{\reuseMPgraphic{axis}}
+%D \setlayer[mp]{\useMPgraphic{demo}}
+%D \ruledhbox{\flushlayer[mp]}
+%D \stoptyping
+
+%D \macros
+%D {startstaticMPfigure,useMPstaticfigure}
+%D
+%D Static figures are processed only when there has been something changed. Here is
+%D Aditya Mahajan's testcase:
+%D
+%D \startbuffer
+%D \startstaticMPfigure{circle}
+%D fill fullcircle scaled 1cm withcolor blue;
+%D \stopstaticMPfigure
+%D
+%D \startstaticMPfigure{axis}
+%D drawarrow (0,0)--(2cm,0) ;
+%D drawarrow (0,0)--(0,2cm) ;
+%D label.llft(textext("(0,0)") ,origin) ;
+%D \stopstaticMPfigure
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+\unexpanded\def\startstaticMPfigure#1#2\stopstaticMPfigure
+ {\startreusableMPgraphic{\??mpstaticgraphic#1}#2\stopreusableMPgraphic}
+
+\unexpanded\def\startstaticMPgraphic
+ {\dodoublegroupempty\meta_start_static_graphic}
+
+\def\meta_start_static_graphic#1#2#3\stopstaticMPgraphic
+ {\startreusableMPgraphic{\??mpstaticgraphic#1}{#2}#3\stopreusableMPgraphic}
+
+\let\stopstaticMPfigure \relax
+\let\stopstaticMPgraphic\relax
+
+\unexpanded\def\usestaticMPfigure
+ {\dodoubleempty\meta_use_static_figure}
+
+\def\meta_use_static_figure[#1][#2]%
+ {\ifsecondargument
+ \scale[#2]{\reuseMPgraphic{\??mpstaticgraphic#1}}%
+ \else
+ \reuseMPgraphic{\??mpstaticgraphic#1}%
+ \fi}
+
+%D Goody for preventing overflows:
+
+\def\MPdivten[#1]{\withoutpt\the\dimexpr#1pt/10\relax}
+
+%D There is no way to distinguish the black color that you get when you issue a
+%D \type {draw} without color specification from a color that has an explicit black
+%D specification unless you set the variable \type {defaultcolormodel} to 1.
+%D Hoewever, in that case you cannot distinguish that draw from one with a \type
+%D {withoutcolor} specification. This means that we have to provide multiple
+%D variants of inheritance.
+%D
+%D In any case we need to tell the converter what the inherited color is to start
+%D with. Case~3 is kind of unpredictable as it closely relates to the order in which
+%D paths are flushed. If you want to inherit automatically from the surrounding, you
+%D can best stick to variant 1. Variant 0 (an isolated graphic) is the default.
+%D
+%D \startbuffer
+%D \startuseMPgraphic{test}
+%D drawoptions(withpen pencircle scaled 1pt) ;
+%D def shift_cp = currentpicture := currentpicture shifted (-15pt,0) ; enddef ;
+%D draw fullcircle scaled 10pt withoutcolor ; shift_cp ;
+%D fill fullcircle scaled 10pt ; shift_cp ;
+%D draw fullcircle scaled 10pt withoutcolor ; shift_cp ;
+%D fill fullcircle scaled 10pt withcolor red ; shift_cp ;
+%D draw fullcircle scaled 10pt withoutcolor ; shift_cp ;
+%D fill fullcircle scaled 10pt ; shift_cp ;
+%D \stopuseMPgraphic
+%D
+%D \starttabulate
+%D \NC 0\quad \NC \MPcolormethod0 \green XX\quad \useMPgraphic{test}\quad XX \NC \NR
+%D \NC 1\quad \NC \MPcolormethod1 \green XX\quad \useMPgraphic{test}\quad XX \NC \NR
+%D \NC 2\quad \NC \MPcolormethod2 \green XX\quad \useMPgraphic{test}\quad XX \NC \NR
+%D \NC 3\quad \NC \MPcolormethod3 \green XX\quad \useMPgraphic{test}\quad XX \NC \NR
+%D \stoptabulate
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+\newconstant\MPcolormethod
+
+\appendtoks
+ \clf_mpsetoutercolor
+ \MPcolormethod\space
+ \attribute\colormodelattribute\space
+ \attribute\colorattribute\space
+ \dogetattribute{transparency}\relax
+\to \everyMPgraphic
+
+% \startMPinitializations
+% defaultcolormodel := \ifcase\MPcolormethod1\or1\or3\else3\fi;
+% \stopMPinitializations
+
+%D macros
+%D {mprunvar,mpruntab,mprunset}
+%D
+%D \starttyping
+%D \startMPcode
+%D passvariable("version","1.0") ;
+%D passvariable("number",123) ;
+%D passvariable("string","whatever") ;
+%D passvariable("point",(1.5,2.8)) ;
+%D passvariable("triplet",(1/1,1/2,1/3)) ;
+%D passvariable("quad",(1.1,2.2,3.3,4.4)) ;
+%D passvariable("boolean",false) ;
+%D passvariable("path",fullcircle scaled 1cm) ;
+%D draw fullcircle scaled 20pt ;
+%D \stopMPcode
+%D
+%D \ctxlua{inspect(metapost.variables)}
+%D
+%D \MPrunvar{version} \MPruntab{quad}{3} (\MPrunset{triplet}{,})
+%D
+%D $(x,y) = (\MPruntab{point}{1},\MPruntab{point}{2})$
+%D $(x,y) = (\MPrunset{point}{,})$
+%D \stoptyping
+
+\def\MPrunvar #1{\clf_mprunvar{#1}} \let\mprunvar\MPrunvar
+\def\MPruntab#1#2{\clf_mpruntab{#1}#2\relax} \let\mpruntab\MPruntab % #2 is number
+\def\MPrunset#1#2{\clf_mprunset{#1}{#2}} \let\mprunset\MPrunset
+
+\prependtoks \clf_mppushvariables \to \everybeforepagebody
+\appendtoks \clf_mppopvariables \to \everyafterpagebody
+
+\let\MPpushvariables\clf_mppushvariables
+\let\MPpopvariables \clf_mppopvariables
+
+%D We also provide an outputless run:
+
+\unexpanded\def\startMPcalculation
+ {\begingroup
+ \setbox\nextbox\hpack\bgroup
+ \dosinglegroupempty\meta_start_calculation}
+
+\let\stopMPcalculation\relax
+
+\def\meta_start_calculation
+ {\iffirstargument
+ \expandafter\meta_start_calculation_instance
+ \else
+ \expandafter\meta_start_calculation_standard
+ \fi}
+
+\def\meta_start_calculation_instance#1#2\stopMPcalculation
+ {\edef\currentMPinstance{#1}%
+ \let\currentMPgraphicname\empty
+ \edef\currentMPformat{\MPinstanceparameter\s!format}%
+ \meta_enable_include
+ \meta_process_graphic{#2;draw origin}%
+ \egroup
+ \endgroup}
+
+\def\meta_start_calculation_standard#1#2\stopMPcalculation
+ {\let\currentMPinstance\defaultMPinstance
+ \let\currentMPgraphicname\empty
+ \edef\currentMPformat{\MPinstanceparameter\s!format}%
+ \meta_process_graphic{#2;draw origin}%
+ \egroup
+ \endgroup}
+
+%D \macros
+%D {setupMPgraphics}
+%D
+%D Here is a generic setup command:
+
+\installcorenamespace{MPgraphics}
+
+\installsetuponlycommandhandler \??MPgraphics {MPgraphics}
+
+%D Here we hook in the outer color. When \type {color} is set to \type {global} we
+%D get the outer color automatically. If you change this setting, you should do it
+%D grouped in order not to make other graphics behave in unexpected ways.
+
+\appendtoks
+ \doifelse{\directMPgraphicsparameter\c!color}\v!global{\MPcolormethod\plusone}{\MPcolormethod\zerocount}%
+\to \everysetupMPgraphics
+
+\setupMPgraphics
+ [\c!color=\v!local]
+
+%D This can save some runtime: rename the mpy file from a first run (when stable) to
+%D another file and reuse it. One can also use the original filename, but a copy is
+%D often better.
+%D
+%D \starttyping
+%D \setupMPgraphics
+%D [mpy=\jobname.mpy]
+%D \stoptyping
+
+\appendtoks
+ \edef\p_mpy{\directMPgraphicsparameter{mpy}}%
+ \ifx\p_mpy\empty \else
+ \let\MPdataMPYfile\p_mpy
+ \clf_registermpyfile{\p_mpy}%
+ \fi
+\to \everysetupMPgraphics
+
+%D Some more helpers (see \type {meta-grd.mkiv} for an example of usage):
+
+\def\MPdpar#1#2{\the\dimexpr#1#2\relax\empty}
+\def\MPnpar#1#2{\the\numexpr#1#2\relax\empty}
+\def\MPspar#1#2{"#1#2"}
+
+%D Done.
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/meta-mac.mkxl b/Master/texmf-dist/tex/context/base/mkiv/meta-mac.mkxl
new file mode 100644
index 00000000000..3bf38b4c826
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/meta-mac.mkxl
@@ -0,0 +1,66 @@
+%D \module
+%D [ file=meta-scn,
+%D version=2019.07.19,
+%D title=\METAPOST\ Graphics,
+%D subtitle=LMTX support,
+%D author=Hans Hagen,
+%D date=\ currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\unprotect
+
+\unexpanded\def\defineMPparameterset[#1]{\clf_lmt_parameters_define{#1}}
+\unexpanded\def\presetMPparameters [#1]{\clf_lmt_parameters_preset{#1}}
+\unexpanded\def\resetMPparameters [#1]{\clf_lmt_parameters_reset {#1}}
+
+% \unexpanded\def\useMPgraphic
+% {\doifnextoptionalelse\meta_use_MP_graphic_yes\meta_use_MP_graphic_nop}
+
+% \def\meta_use_MP_graphic_nop
+% {\dodoublegroupempty\meta_use_graphic}
+
+% \def\meta_use_MP_graphic_yes
+% {\dodoubleempty\meta_use_graphic_new}
+
+% \def\meta_use_graphic_new[#1][#2]%
+% {\begingroup
+% % If really needed weh can use grouplevel but normally these graphics are
+% % not nested.
+% \clf_lmt_parameters_preset{#1}[#2]%
+% \meta_use_graphic{#1}{}%
+% \clf_lmt_parameters_reset{#1}%
+% \endgroup}
+
+\unexpanded\def\useMPmacro
+ {\dotripleempty\meta_use_macro}
+
+\def\meta_use_macro[#1][#2][#3]%
+ {\ifthirdargument
+ \meta_begin_graphic_group{#1}%
+ \meta_enable_include
+ \clf_lmt_parameters_preset{#2}[#3]%
+ \meta_process_graphic{lmt_#2;}%
+ \clf_lmt_parameters_reset{#2}%
+ \meta_end_graphic_group
+ \else\ifsecondargument
+ \doifelseassignment{#2}
+ {\let\currentMPinstance\defaultMPinstance
+ \meta_enable_include
+ \clf_lmt_parameters_preset{#1}[#2]%
+ \meta_process_graphic{lmt_#1;}%
+ \clf_lmt_parameters_reset{#1}}%
+ {\meta_begin_graphic_group{#1}%
+ \meta_enable_include
+ \meta_process_graphic{lmt_#1;}%
+ \meta_end_graphic_group}%
+ \else
+ \let\currentMPinstance\defaultMPinstance
+ \meta_enable_include
+ \meta_process_graphic{lmt_#1;}%
+ \fi\fi}
+
+\protect
diff --git a/Master/texmf-dist/tex/context/base/mkiv/meta-pag.mkiv b/Master/texmf-dist/tex/context/base/mkiv/meta-pag.mkiv
index 6b6abd21135..b147c0af4b1 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/meta-pag.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/meta-pag.mkiv
@@ -11,21 +11,19 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-%D These definitions used to be part of the old \type
-%D {core-mps} file, later changed into \type {meta-ini}, but
-%D keeping them separate is cleaner.
+%D These definitions used to be part of the old \type {core-mps} file, later changed
+%D into \type {meta-ini}, but keeping them separate is cleaner.
\writestatus{loading}{MetaPost Graphics / Page Data Management}
\unprotect
-%D The next few macros tell \METAPOST\ how the \CONTEXT\
-%D pagebody looks.
+%D The next few macros tell \METAPOST\ how the \CONTEXT\ pagebody looks.
-\startMPextensions
- boolean PageStateAvailable;
- PageStateAvailable:=true;
-\stopMPextensions
+% \startMPextensions
+% boolean PageStateAvailable;
+% PageStateAvailable:=true;
+% \stopMPextensions
% maybe always set as frozen anyway
@@ -87,24 +85,22 @@
% NOfColumns:=\number\nofcolumns;
% \stopMPinitializations
-\def\MPonrightpage{true}
-\def\MPonoddpage {true}
+% \def\MPonrightpage{true} % just in case they're used
+% \def\MPonoddpage {true} % just in case they're used
-\def\freezeMPpagelayout
- {\edef\MPonrightpage{\doifbothsides {tru}{tru}{fals}e}%
- \edef\MPonoddpage {\doifelseoddpage {tru}{fals}e}}
+% \def\freezeMPpagelayout
+% {\edef\MPonrightpage{\doifbothsides {tru}{tru}{fals}e}%
+% \edef\MPonoddpage {\doifelseoddpage {tru}{fals}e}}
-%D We need to freeze the pagelayout before the backgrounds
-%D are build, because the overlay will temporarily become
-%D zero (overlay).
+%D We need to freeze the pagelayout before the backgrounds are build, because the
+%D overlay will temporarily become zero (overlay).
-\appendtoks
- \freezeMPpagelayout
-\to \everybeforepagebody
+% \appendtoks
+% \freezeMPpagelayout
+% \to \everybeforepagebody
-%D By freezing these value every graphic, we can use layout
-%D variables that change halfways a page, whatever use that
-%D has.
+%D By freezing these value every graphic, we can use layout variables that change
+%D halfways a page, whatever use that has.
% obsolete (but keep the code)
%
diff --git a/Master/texmf-dist/tex/context/base/mkiv/meta-pag.mkxl b/Master/texmf-dist/tex/context/base/mkiv/meta-pag.mkxl
new file mode 100644
index 00000000000..86de11eeb5c
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/meta-pag.mkxl
@@ -0,0 +1,26 @@
+%D \module
+%D [ file=meta-pag,
+%D version=1999.07.10,
+%D title=\METAPOST\ Graphics,
+%D subtitle=Initialization,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D These definitions used to be part of the old \type {core-mps} file, later changed
+%D into \type {meta-ini}, but keeping them separate is cleaner. In the meantime not
+%D that much is left here.
+
+\writestatus{loading}{MetaPost Graphics / Page Data Management}
+
+\unprotect
+
+\prependtoks
+ \calculatereducedvsizes % bah, this is really needed
+\to \everyMPgraphic
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/meta-pdf.lua b/Master/texmf-dist/tex/context/base/mkiv/meta-pdf.lua
index 5bcd161c02f..5bcbe418606 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/meta-pdf.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/meta-pdf.lua
@@ -44,13 +44,8 @@ local mptopdf = metapost.mptopdf
mptopdf.nofconverted = 0
-local f_translate = formatters["1 0 0 0 1 %.6F %.6F cm"]
-local f_concat = formatters["%.6F %.6F %.6F %.6F %.6F %.6F cm"]
-
-directives.register("pdf.stripzeros",function()
- f_translate = formatters["1 0 0 0 1 %.6N %.6N cm"]
- f_concat = formatters["%.6N %.6N %.6N %.6N %.6N %.6N cm"]
-end)
+local f_translate = formatters["1 0 0 0 1 %.6N %.6N cm"]
+local f_concat = formatters["%.6N %.6N %.6N %.6N %.6N %.6N cm"]
local m_path, m_stack, m_texts, m_version, m_date, m_shortcuts = { }, { }, { }, 0, 0, false
diff --git a/Master/texmf-dist/tex/context/base/mkiv/meta-tex.mkiv b/Master/texmf-dist/tex/context/base/mkiv/meta-tex.mkiv
index 03ad5ee398c..c580596f797 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/meta-tex.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/meta-tex.mkiv
@@ -153,4 +153,90 @@
\clf_MPLIBconvertoutlinetext\numexpr#1\relax{#2}\scratchbox
\endgroup}
+%D For now here. We don't do the whole thing, because then one can as
+%D well just export to pdf. We assume consistent integration.
+
+\definefontsynonym[serif-normal-normal] [\s!Serif]
+\definefontsynonym[serif-normal-italic] [\s!SerifItalic]
+\definefontsynonym[serif-normal-oblique][\s!SerifSlanted]
+\definefontsynonym[serif-bold-normal] [\s!SerifBold]
+\definefontsynonym[serif-bold-italic] [\s!SerifBoldItalic]
+\definefontsynonym[serif-bold-oblique] [\s!SerifBoldSlanted]
+
+\definefontsynonym[sans-normal-normal] [\s!Sans]
+\definefontsynonym[sans-normal-italic] [\s!SansItalic]
+\definefontsynonym[sans-normal-oblique] [\s!SansSlanted]
+\definefontsynonym[sans-bold-normal] [\s!SansBold]
+\definefontsynonym[sans-bold-italic] [\s!SansBoldItalic]
+\definefontsynonym[sans-bold-oblique] [\s!SansBoldSlanted]
+
+\definefontsynonym[mono-normal-normal] [\s!Mono]
+\definefontsynonym[mono-normal-italic] [\s!MonoItalic]
+\definefontsynonym[mono-normal-oblique] [\s!MonoSlanted]
+\definefontsynonym[mono-bold-normal] [\s!MonoBold]
+\definefontsynonym[mono-bold-italic] [\s!MonoBoldItalic]
+\definefontsynonym[mono-bold-oblique] [\s!MonoBoldSlanted]
+
+\installcorenamespace {svgfamily}
+
+\setvalue{\??svgfamily }{serif}
+\setvalue{\??svgfamily serif}{serif}
+\setvalue{\??svgfamily sans}{sans}
+\setvalue{\??svgfamily mono}{mono}
+
+%D This can't change because otherwise \type {\scale[width=4cm]{graphic}} fails.
+
+\unexpanded\def\svgscaled#1%
+ {\fastsxsy{#1}{#1}\svgnormal}
+
+\unexpanded\def\svgnormal#1#2#3#4% family weight style text
+ {\bgroup
+ \edef\p_family{#1}%
+ \ifx\p_family\empty\else
+ \edef\p_font{\ifcsname\??svgfamily#1\endcsname\lastnamedcs\else#1\fi-#2-#3}%
+ \predefinedfont[\s!spec:\p_font*\s!default\space @ 10bp]%
+ \fi
+ #4%
+ \egroup}
+
+\unexpanded\def\svgcolored#1#2#3#4% r g b text
+ {\colored[r=#1,g=#2,b=#3]{#4}}
+
+\unexpanded\def\svgplaced#1#2#3#4% dx dy width text
+ {\doifelsenothing{#3}%
+ {\hpack}%
+ {\hpack to #3}%
+ {\raise#2\onebasepoint\hbox{\kern#1\onebasepoint\relax#4}}}
+
+\newdimen\grph_svg_scratchwidth % maybe \startsvgpos etc
+
+\unexpanded\def\svgposchar#1#2#3% dx dy char
+ {\setbox\scratchbox\hpack\bgroup
+ \raise#2\onebasepoint\hbox\bgroup
+ \kern\dimexpr#1\onebasepoint-\grph_svg_scratchwidth\relax
+ \char#3\relax
+ \egroup
+ \egroup
+ \advance\grph_svg_scratchwidth\wd\scratchbox
+ \box\scratchbox}
+
+\unexpanded\def\svgchar#1% char
+ {\char#1\relax}
+
+\definelayer[svgmps][\c!method=\v!fit]
+
+\unexpanded\def\svgstartlayer
+ {\resetlayer[svgmps]%
+ \setlayer[svgmps]\bgroup}
+
+\unexpanded\def\svgstoplayer
+ {\egroup
+ \flushlayer[svgmps]}
+
+\unexpanded\def\svgsetlayer#1#2%
+ {\setlayer[svgmps][\c!x=#1\onebasepoint,\c!y=#2\onebasepoint]} % {#3}
+
+\unexpanded\def\svghashed#1%
+ {\clf_svghashed#1\relax}
+
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mlib-cnt.lua b/Master/texmf-dist/tex/context/base/mkiv/mlib-cnt.lua
new file mode 100644
index 00000000000..761eac6551a
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/mlib-cnt.lua
@@ -0,0 +1,2021 @@
+if not modules then modules = { } end modules ['mlib-cnt'] = {
+ version = 1.001,
+ comment = "companion to mlib-ctx.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+}
+
+-- The only useful reference that I could find about this topic is in wikipedia:
+--
+-- https://en.wikipedia.org/wiki/Marching_squares
+--
+-- I derived the edge code from:
+--
+-- https://physiology.arizona.edu/people/secomb/contours
+--
+-- and also here:
+--
+-- https://github.com/secomb/GreensV4
+--
+-- which has the banner:
+--
+-- TWS, November 1989. Converted to C September 2007. Revised February 2009.
+--
+-- and has a liberal licence. I optimized the code so that it runs a bit faster in Lua and
+-- there's probably more room for optimization (I tried several variants). For instance I
+-- don't use that many tables because access is costly. We don't have a compiler that does
+-- some optimizing (even then the c code can probably be made more efficient).
+--
+-- We often have the same node so it's cheaper to reuse the wsp tables and reconstruct
+-- the point in the path then to alias the original point. We can be more clever:
+-- straighten, but it's more work so maybe I will do that later; for now I only added
+-- a test for equality. There are some experiments in this file too and not all might
+-- work. It's a playground for me.
+--
+-- The code is meant for metafun so it is not general purpose. The bitmap variant is
+-- relatively fast and bitmaps compress well. When all is settled I might make a couple
+-- of helpers in C for this purpose but not now.
+--
+-- I removed optimization code (more aggressive flattening and such because it didn't really
+-- pay off now that we use combined paths with just line segments. I also moved some other
+-- code to a experimental copy. So we now only have the bare helpers needed here.
+
+-- Todo: look into zero case (lavel 1) for shapes ... omiting the background calculation
+-- speeds up quite a bit.
+
+local next, type, tostring = next, type, tostring
+local round, abs, min, max, floor = math.round, math.abs, math.min, math.max, math.floor
+local concat, move = table.concat, table.move
+
+local bor = bit32.bor -- it's really time to ditch support for luajit
+
+local starttiming = statistics.starttiming
+local stoptiming = statistics.stoptiming
+local elapsedtime = statistics.elapsedtime
+
+local formatters = string.formatters
+local setmetatableindex = table.setmetatableindex
+local sortedkeys = table.sortedkeys
+local sequenced = table.sequenced
+
+local metapost = metapost or { }
+local mp = mp or { }
+
+local getparameterset = metapost.getparameterset
+
+local mpflush = mp.flush
+local mpcolor = mp.color
+local mpstring = mp.string
+local mpdraw = mp.draw
+local mpfill = mp.fill
+local mpflatten = mp.flatten
+
+local report = logs.reporter("mfun contour")
+
+local version = 0.007
+
+-- we iterate using integers so that we get a better behaviour at zero
+
+local f_function_n = formatters [ [[
+ local math = math
+ local round = math.round
+ %s
+ return function(data,nx,ny,nxmin,nxmax,xstep,nymin,nymax,ystep)
+ local sx = nxmin
+ for mx=1,nx do
+ local dx = data[mx]
+ local x = sx * xstep
+ local sy = nymin
+ for my=1,ny do
+ local y = sy * ystep
+ dx[my] = %s
+ sy = sy + 1
+ end
+ sx = sx + 1
+ end
+ return 0
+ end
+]] ]
+
+local f_function_y = formatters [ [[
+ local math = math
+ local round = math.round
+ local nan = NaN
+ local inf = math.huge
+ %s
+ return function(data,nx,ny,nxmin,nxmax,xstep,nymin,nymax,ystep,dnan,dinf,report)
+ local sx = nxmin
+ local er = 0
+ for mx=nxmin,nxmax do
+ local dx = data[mx]
+ local x = sx * xstep
+ local sy = nymin
+ for my=nymin,nymax do
+ local y = sy * ystep
+ local n = %s
+ if n == nan then
+ er = er + 1
+ if er < 10 then
+ report("nan at (%s,%s)",x,y)
+ end
+ n = dnan
+ elseif n == inf then
+ er = er + 1
+ if er < 10 then
+ report("inf at (%s,%s)",x,y)
+ end
+ n = dinf
+ end
+ dx[my] = n
+ sy = sy + 1
+ end
+ sx = sx + 1
+ end
+ return er
+ end
+]] ]
+
+local f_color = formatters [ [[
+ local math = math
+ local min = math.min
+ local max = math.max
+ local n = %s
+ local minz = %s
+ local maxz = %s
+
+ local color_value = 0
+ local color_step = mp.lmt_color_functions.step
+ local color_shade = mp.lmt_color_functions.shade
+
+ local function step(...)
+ return color_step(color_value,n,...)
+ end
+ local function shade(...)
+ return color_shade(color_value,n,...)
+ end
+ local function lin(l)
+ return l/n
+ end
+ %s
+ return function(l)
+ color_value = l
+ return %s
+ end
+]] ]
+
+local inbetween = attributes and attributes.colors.helpers.inbetween
+
+mp.lmt_color_functions = {
+ step = function(l,n,r,g,b,s)
+ if not s then
+ s = 1
+ end
+ local f = l / n
+ local r = s * 1.5 - 4 * abs(f-r)
+ local g = s * 1.5 - 4 * abs(f-g)
+ local b = s * 1.5 - 4 * abs(f-b)
+ return min(max(r,0),1), min(max(g,0),1), min(max(b,0),1)
+ end,
+ shade = function(l,n,one,two)
+ local f = l / n
+ local r = inbetween(one,two,1,f)
+ local g = inbetween(one,two,2,f)
+ local b = inbetween(one,two,3,f)
+ return min(max(r,0),1), min(max(g,0),1), min(max(b,0),1)
+ end,
+}
+
+local f_box = formatters [ [[draw rawtexbox("contour",%s) xysized (%s,%s) ;]] ]
+
+local n_box = 0
+
+-- todo: remove old one, so we need to store old hashes
+
+local nofcontours = 0
+
+-- We don't want cosmetics like axis and labels to trigger a calculation,
+-- especially a slow one.
+
+local hashfields = {
+ "xmin", "xmax", "xstep", "ymin", "ymax", "ystep",
+ "levels", "colors", "level", "preamble", "function", "functions", "color", "values",
+ "background", "foreground", "linewidth", "backgroundcolor", "linecolor",
+}
+
+local function prepare(p)
+ local h = { }
+ for i=1,#hashfields do
+ local f = hashfields[i]
+ h[f] = p[f]
+ end
+ local hash = md5.HEX(sequenced(h))
+ local name = formatters["%s-m-c-%03i.lua"](tex.jobname,nofcontours)
+ return name, hash
+end
+
+local function getcache(p)
+ local cache = p.cache
+ if cache then
+ local name, hash = prepare(p)
+ local data = table.load(name)
+ if data and data.hash == hash and data.version == version then
+ p.result = data
+ return true
+ else
+ return false, hash, name
+ end
+ end
+ return false, nil, nil
+end
+
+local function setcache(p)
+ local result = p.result
+ local name = result.name
+ if name then
+ if result.bitmap then
+ result.bitmap = nil
+ else
+ result.data = nil
+ end
+ result.color = nil
+ result.action = nil
+ result.cached = nil
+ io.savedata(name, table.fastserialize(result))
+ else
+ os.remove((prepare(p)))
+ end
+end
+
+function mp.lmt_contours_start()
+
+ starttiming("lmt_contours")
+
+ nofcontours = nofcontours + 1
+
+ local p = getparameterset()
+
+ local xmin = p.xmin
+ local xmax = p.xmax
+ local ymin = p.ymin
+ local ymax = p.ymax
+ local xstep = p.xstep
+ local ystep = p.ystep
+ local levels = p.levels
+ local colors = p.colors
+ local nx = 0
+ local ny = 0
+ local means = setmetatableindex("number")
+ local values = setmetatableindex("number")
+ local data = setmetatableindex("table")
+ local minmean = false
+ local maxmean = false
+
+ local cached, hash, name = getcache(p)
+
+ local function setcolors(preamble,levels,minz,maxz,color,nofvalues)
+ if colors then
+ local function f(k)
+ return #colors[1] == 1 and 0 or { 0, 0, 0 }
+ end
+ setmetatableindex(colors, function(t,k)
+ local v = f(k)
+ t[k] = v
+ return v
+ end)
+ local c = { }
+ local n = 1
+ for i=1,nofvalues do
+ c[i] = colors[n]
+ n = n + 1
+ end
+ return c, f
+ else
+ local tcolor = f_color(levels,minz,maxz,preamble,color)
+ local colors = { }
+ local fcolor = load(tcolor)
+ if type(fcolor) ~= "function" then
+ report("error in color function, case %i: %s",1,color)
+ fcolor = false
+ else
+ fcolor = fcolor()
+ if type(fcolor) ~= "function" then
+ report("error in color function, case %i: %s",2,color)
+ fcolor = false
+ end
+ end
+ if not fcolor then
+ local color_step = mp.lmt_color_functions.step
+ fcolor = function(l)
+ return color_step(l,levels,0.25,0.50,0.75)
+ end
+ end
+ for i=1,nofvalues do
+ colors[i] = { fcolor(i) }
+ end
+ if attributes.colors.model == "cmyk" then
+ for i=1,#colors do
+ local c = colors[i]
+ colors[i] = { 1 - c[1], 1 - c[2], 1 - c[3], 0 }
+ end
+ end
+ return colors, fcolor
+ end
+ end
+
+ if cached then
+ local result = p.result
+ local colors, color = setcolors(
+ p.preamble,
+ p.levels,
+ result.minz,
+ result.maxz,
+ p.color,
+ result.nofvalues
+ )
+ result.color = color
+ result.colors = colors
+ result.cached = true
+ return
+ end
+
+ local functioncode = p["function"]
+ local functionrange = p.range
+ local functionlist = functionrange and p.functions
+ local preamble = p.preamble
+
+ if xstep == 0 then xstep = (xmax - xmin)/100 end
+ if ystep == 0 then ystep = (ymax - ymin)/100 end
+
+ local nxmin = round(xmin/xstep)
+ local nxmax = round(xmax/xstep)
+ local nymin = round(ymin/ystep)
+ local nymax = round(ymax/ystep)
+ local nx = nxmax - nxmin + 1
+ local ny = nymax - nymin + 1
+
+ local function executed(data,code)
+ local fcode = p.check and f_function_y or f_function_n
+ fcode = fcode(preamble,code)
+ fcode = load(fcode)
+ if type(fcode) == "function" then
+ fcode = fcode()
+ end
+ if type(fcode) == "function" then
+ local er = fcode(
+ data, nx, ny,
+ nxmin, nxmax, xstep,
+ nymin, nymax, ystep,
+ p.defaultnan, p.defaultinf, report
+ )
+ if er > 0 then
+ report("%i errors in: %s",er,code)
+ end
+ return true
+ else
+ return false -- fatal error
+ end
+ end
+
+ -- for i=1,nx do
+ -- data[i] = lua.newtable(ny,0)
+ -- end
+
+ if functionlist then
+
+ local datalist = { }
+ local minr = functionrange[1]
+ local maxr = functionrange[2] or minr
+ local size = #functionlist
+
+ for l=1,size do
+
+ local func = setmetatableindex("table")
+ if not executed(func,functionlist[l]) then
+ report("error in executing function %i from functionlist",l)
+ return
+ end
+
+ local bit = l -- + 1
+
+ if l == 1 then
+ for i=1,nx do
+ local di = data[i]
+ local fi = func[i]
+ for j=1,ny do
+ local f = fi[j]
+ if f >= minr and f <= maxr then
+ di[j] = bit
+ else
+ di[j] = 0
+ end
+ end
+ end
+ else
+ for i=1,nx do
+ local di = data[i]
+ local fi = func[i]
+ for j=1,ny do
+ local f = fi[j]
+ if f >= minr and f <= maxr then
+ di[j] = bor(di[j],bit)
+ end
+ end
+ end
+ end
+
+ end
+
+ -- we can simplify the value mess below
+
+ elseif functioncode then
+
+ if not executed(data,functioncode) then
+ report("error in executing function")
+ return -- fatal error
+ end
+
+ else
+
+ report("no valid function(s)")
+ return -- fatal error
+
+ end
+
+ minz = data[1][1]
+ maxz = minz
+
+ for i=1,nx do
+ local d = data[i]
+ for j=1,ny do
+ local v = d[j]
+ if v < minz then
+ minz = v
+ elseif v > maxz then
+ maxz = v
+ end
+ end
+ end
+
+ if functionlist then
+
+ for i=minz,maxz do
+ values[i] = i
+ end
+
+ levels = maxz
+
+ minmean = minz
+ maxmean = maxz
+
+ else
+
+ local snap = (maxz - minz + 1) / levels
+
+ for i=1,nx do
+ local d = data[i]
+ for j=1,ny do
+ local dj = d[j]
+ local v = round((dj - minz) / snap)
+ values[v] = values[v] + 1
+ means [v] = means [v] + dj
+ d[j] = v
+ end
+ end
+
+ local list = sortedkeys(values)
+ local count = values
+ local remap = { }
+
+ values = { }
+
+ for i=1,#list do
+ local v = list[i]
+ local m = means[v] / count[v]
+ remap [v] = i
+ values[i] = m
+ if not minmean then
+ minmean = m
+ maxmean = m
+ elseif m < minmean then
+ minmean = m
+ elseif m > maxmean then
+ maxmean = m
+ end
+ end
+
+ for i=1,nx do
+ local d = data[i]
+ for j=1,ny do
+ d[j] = remap[d[j]]
+ end
+ end
+
+ end
+
+ -- due to rounding we have values + 1 so we can have a floor, ceil, round
+ -- option as well as levels -1
+
+ local nofvalues = #values
+
+ local colors = setcolors(
+ p.preamble,levels,minz,maxz,p.color,nofvalues
+ )
+
+ p.result = {
+ version = version,
+ values = values,
+ nofvalues = nofvalues,
+ minz = minz,
+ maxz = maxz,
+ minmean = minmean,
+ maxmean = maxmean,
+ data = data,
+ color = color,
+ nx = nx,
+ ny = ny,
+ colors = colors,
+ name = name,
+ hash = hash,
+ islist = functionlist and true or false,
+ }
+
+ report("index %i, nx %i, ny %i, levels %i", nofcontours, nx, ny, nofvalues)
+end
+
+function mp.lmt_contours_stop()
+ local p = getparameterset()
+ local e = stoptiming("lmt_contours")
+ setcache(p)
+ p.result = nil
+ local f = p["function"]
+ local l = p.functions
+ report("index %i, %0.3f seconds for: %s",
+ nofcontours, e, "[ " .. concat(l or { f } ," ] [ ") .. " ]"
+ )
+end
+
+function mp.lmt_contours_bitmap_set()
+ local p = getparameterset()
+ local result = p.result
+
+ local values = result.values
+ local nofvalues = result.nofvalues
+ local rawdata = result.data
+ local nx = result.nx
+ local ny = result.ny
+ local colors = result.colors
+ local depth = #colors[1] -- == 3 and "rgb" or "gray"
+
+ -- i need to figure out this offset of + 1
+
+ local bitmap = graphics.bitmaps.new(
+ nx, ny,
+ (depth == 3 and "rgb") or (depth == 4 and "cmyk") or "gray",
+ 1, false, true
+ )
+
+ local palette = bitmap.index or { } -- has to start at 0
+ local data = bitmap.data
+ local p = 0
+
+ if depth == 3 or depth == 4 then
+ for i=1,nofvalues do
+ local c = colors[i]
+ local r = round((c[1] or 0) * 255)
+ local g = round((c[2] or 0) * 255)
+ local b = round((c[3] or 0) * 255)
+ local k = depth == 4 and round((c[4] or 0) * 255) or nil
+ palette[p] = {
+ (r > 255 and 255) or (r < 0 and 0) or r,
+ (g > 255 and 255) or (g < 0 and 0) or g,
+ (b > 255 and 255) or (b < 0 and 0) or b,
+ k
+ }
+ p = p + 1
+ end
+ else
+ for i=1,nofvalues do
+ local s = colors[i][1]
+ local s = round((s or 0) * 255)
+ palette[p] = (
+ (s > 255 and 255) or (s < 0 and 0) or s
+ )
+ p = p + 1
+ end
+ end
+
+ -- As (1,1) is the left top corner so we need to flip of we start in
+ -- the left bottom (we cannot loop reverse because we want a properly
+ -- indexed table.
+
+ local k = 0
+ for y=ny,1,-1 do
+ k = k + 1
+ local d = data[k]
+ for x=1,nx do
+ d[x] = rawdata[x][y] - 1
+ end
+ end
+
+ result.bitmap = bitmap
+end
+
+function mp.lmt_contours_bitmap_get()
+ local p = getparameterset()
+ local result = p.result
+ local bitmap = result.bitmap
+ local box = nodes.hpack(graphics.bitmaps.flush(bitmap))
+ n_box = n_box + 1
+ nodes.boxes.savenode("contour",tostring(n_box),box)
+ return f_box(n_box,bitmap.xsize,bitmap.ysize)
+end
+
+function mp.lmt_contours_cleanup()
+ nodes.boxes.reset("contour")
+ n_box = 0
+end
+
+function mp.lmt_contours_edge_set()
+ local p = getparameterset()
+ local result = p.result
+
+ if result.cached then return end
+
+ local values = result.values
+ local nofvalues = result.nofvalues
+ local data = result.data
+ local nx = result.nx
+ local ny = result.ny
+
+ local xmin = p.xmin
+ local xmax = p.xmax
+ local ymin = p.ymin
+ local ymax = p.ymax
+ local xstep = p.xstep
+ local ystep = p.ystep
+
+ local wsp = { }
+ local edges = { }
+
+ for value=1,nofvalues do
+
+ local iwsp = 0
+ local di = data[1]
+ local dc
+ local edge = { }
+ local e = 0
+ -- the next loop is fast
+ for i=1,nx do
+ local di1 = data[i+1]
+ local dij = di[1]
+ local d = dij - value
+ local dij1
+ for j=1,ny do
+ if j < ny then
+ dij1 = di[j+1]
+ dc = dij1 - value
+ if (d >= 0 and dc < 0) or (d < 0 and dc >= 0) then
+ iwsp = iwsp + 1
+ local y = (d * (j+1) - dc * j) / (d - dc)
+ if i == 1 then
+ wsp[iwsp] = { i, y, 0, (i + (j-1)*nx) }
+ elseif i == nx then
+ wsp[iwsp] = { i, y, (i - 1 + (j-1)*nx), 0 }
+ else
+ local jx = (i + (j-1)*nx)
+ wsp[iwsp] = { i, y, jx - 1, jx }
+ end
+ end
+ end
+ if i < nx then
+ local dc = di1[j] - value
+ if (d >= 0 and dc < 0) or (d < 0 and dc >= 0) then
+ iwsp = iwsp + 1
+ local x = (d * (i+1) - dc * i) / (d - dc)
+ if j == 1 then
+ wsp[iwsp] = { x, j, 0, (i + (j-1)*nx) }
+ elseif j == ny then
+ wsp[iwsp] = { x, j, (i + (j-2)*nx), 0 }
+ else
+ local jx = i + (j-1)*nx
+ wsp[iwsp] = { x, j, jx - nx, jx }
+ end
+ end
+ end
+ dij = dij1
+ d = dc
+ end
+ di = di1
+ end
+ -- the next loop takes time
+ for i=1,iwsp do
+ local wspi = wsp[i]
+ for isq=3,4 do
+ local nsq = wspi[isq]
+ if nsq ~= 0 then
+ local px = wspi[1]
+ local py = wspi[2]
+ local p = { px, py }
+ local pn = 2
+ wspi[isq] = 0
+ while true do
+ for ii=1,iwsp do
+ local w = wsp[ii]
+ local n1 = w[3]
+ local n2 = w[4]
+ if n1 == nsq then
+ local x = w[1]
+ local y = w[2]
+ if x ~= px or y ~= py then
+ pn = pn + 1
+ p[pn] = x
+ pn = pn + 1
+ p[pn] = y
+ px = x
+ py = y
+ end
+ nsq = n2
+ w[3] = 0
+ w[4] = 0
+ if nsq == 0 then
+ if pn == 1 then
+ pn = pn + 1
+ p[pn] = w
+ end
+ goto flush
+ end
+ elseif n2 == nsq then
+ local x = w[1]
+ local y = w[2]
+ if x ~= px or y ~= py then
+ pn = pn + 1
+ p[pn] = x
+ pn = pn + 1
+ p[pn] = y
+ px = x
+ py = y
+ end
+ nsq = n1
+ w[3] = 0
+ w[4] = 0
+ if nsq == 0 then
+ goto flush
+ end
+ end
+ end
+ end
+ ::flush::
+ e = e + 1
+ edge[e] = p
+ if mpflatten then
+ mpflatten(p)
+ end
+ end
+ end
+ end
+
+
+ edges[value] = edge
+
+ end
+
+ result.edges = edges
+
+end
+
+function mp.lmt_contours_shade_set(edgetoo)
+ local p = getparameterset()
+ local result = p.result
+
+ if result.cached then return end
+
+ local values = result.values
+ local nofvalues = result.nofvalues
+ local data = result.data
+ local nx = result.nx
+ local ny = result.ny
+ local color = result.color
+
+ local edges = setmetatableindex("table")
+ local shades = setmetatableindex("table")
+
+ local sqtype = setmetatableindex("table")
+
+ local xspoly = { 0, 0, 0, 0, 0, 0 }
+ local yspoly = { 0, 0, 0, 0, 0, 0 }
+ local xrpoly = { }
+ local yrpoly = { }
+
+ local xrpoly = { } -- lua.newtable(2000,0)
+ local yrpoly = { } -- lua.newtable(2000,0)
+
+ -- for i=1,2000 do
+ -- xrpoly[i] = 0
+ -- yrpoly[i] = 0
+ -- end
+
+ -- Unlike a c compiler lua will not optimize loops to run in parallel so we expand
+ -- some of the loops and make sure we don't calculate when not needed. Not that nice
+ -- but not that bad either. Maybe I should just write this from scratch.
+
+-- local i = 0
+-- local j = 0
+
+ -- Analyze each rectangle separately. Overwrite lower colors
+
+ -- Unrolling the loops and copying code and using constants is faster and doesn't
+ -- produce much more code in the end, also because we then can leave out the not
+ -- seen branches. One can argue about the foundit2* blobs but by stepwise optimizing
+ -- this is the result.
+
+ shades[1] = { { 0, 0, nx - 1, 0, nx - 1, ny - 1, 0, ny - 1 } }
+ edges [1] = { { } }
+
+ -- this is way too slow ... i must have messed up some loop .. what is this with value 1
+
+ for value=1,nofvalues do
+-- for value=2,nofvalues do
+
+ local edge = { }
+ local nofe = 0
+ local shade = { }
+ local nofs = 0
+
+ for i=1,nx-1 do
+ local s = sqtype[i]
+ for j=1,ny-1 do
+ s[j] = 0
+ end
+ end
+
+ local nrp = 0
+
+ local function addedge(a,b,c,d)
+ nofe = nofe + 1 edge[nofe] = a
+ nofe = nofe + 1 edge[nofe] = b
+ nofe = nofe + 1 edge[nofe] = c
+ nofe = nofe + 1 edge[nofe] = d
+ end
+ while true do
+ -- search for a square of type 0 with >= 1 corner above contour level
+ local i
+ local j
+ local d0 = data[1]
+ local d1 = data[2]
+ for ii=1,nx do
+ local s = sqtype[ii]
+ for jj=1,ny do
+ if s[jj] == 0 then
+ if d0[jj] > value then i = ii j = jj goto foundit end
+ if d1[jj] > value then i = ii j = jj goto foundit end
+ local j1 = jj + 1
+ if d1[j1] > value then i = ii j = jj goto foundit end
+ if d0[j1] > value then i = ii j = jj goto foundit end
+ end
+ end
+ d0 = d1
+ d1 = data[ii+1]
+ end
+ break
+ ::foundit::
+ -- initialize r-polygon (nrp seems to be 1 or 2)
+ nrp = nrp + 1
+
+ local first = true
+ local nrpoly = 0
+ local nspoly = 0
+ local nrpm = -nrp
+ -- this is the main loop
+ while true do
+ -- search for a square of type -nrp
+ if first then
+ first = false
+ if sqtype[i][j] == 0 then -- true anyway
+ goto foundit1
+ end
+ end
+ for ii=1,nx do
+ local s = sqtype[ii]
+ for jj=1,ny do
+ if s[jj] == nrpm then
+ i = ii
+ j = jj
+ goto foundit1
+ end
+ end
+ end
+ break
+ ::foundit1::
+ while true do
+
+ -- search current then neighboring squares for square type 0, with a corner in common with current square above contour level
+
+ -- top/bottom ... a bit cheating here
+
+ local i_l, i_c, i_r -- i left current right
+ local j_b, j_c, j_t -- j bottom current top
+
+ local i_n = i + 1 -- i next (right)
+ local j_n = j + 1 -- j next (top)
+
+ local i_p = i - 1 -- i previous (bottom)
+ local j_p = j - 1 -- j previous (right)
+
+ local d_c = data[i]
+ local d_r = data[i_n]
+
+ local sq
+
+ i_c = i ; j_c = j ; if i_c < nx and j_c < ny then sq = sqtype[i_c] if sq[j_c] == 0 then
+ if d_c[j_c] > value then i_l = i_p ; i_r = i_n ; j_b = j_p ; j_t = j_n ; goto foundit21 end
+ if d_c[j_n] > value then i_l = i_p ; i_r = i_n ; j_b = j_p ; j_t = j_n ; goto foundit22 end
+ if d_r[j_c] > value then i_l = i_p ; i_r = i_n ; j_b = j_p ; j_t = j_n ; goto foundit23 end
+ if d_r[j_n] > value then i_l = i_p ; i_r = i_n ; j_b = j_p ; j_t = j_n ; goto foundit24 end
+ end end
+
+ i_c = i_n ; j_c = j ; if i_c < nx and j_c < ny then sq = sqtype[i_c] if sq[j_c] == 0 then
+ if d_r[j_c] > value then i_l = i ; i_r = i_n + 1 ; j_b = j_p ; j_t = j_n ; d_c = d_r ; d_r = data[i_r] ; goto foundit21 end
+ if d_r[j_n] > value then i_l = i ; i_r = i_n + 1 ; j_b = j_p ; j_t = j_n ; d_c = d_r ; d_r = data[i_r] ; goto foundit22 end
+ end end
+
+ i_c = i ; j_c = j_n ; if i_c < nx and j_c < ny then sq = sqtype[i_c] if sq[j_c] == 0 then
+ if d_c[j_n] > value then i_l = i_p ; i_r = i_n ; j_b = j ; j_t = j_n + 1 ; goto foundit21 end
+ if d_r[j_n] > value then i_l = i_p ; i_r = i_n ; j_b = j ; j_t = j_n + 1 ; goto foundit23 end
+ end end
+
+ i_c = i_p ; j_c = j ; if i_c > 0 and j_c < ny then sq = sqtype[i_c] if sq[j_c] == 0 then
+ if d_c[j_c] > value then i_l = i_p - 1 ; i_r = i ; j_b = j_p ; j_t = j_n ; d_r = d_c ; d_c = data[i_p] ; goto foundit23 end
+ if d_c[j_n] > value then i_l = i_p - 1 ; i_r = i ; j_b = j_p ; j_t = j_n ; d_r = d_c ; d_c = data[i_p] ; goto foundit24 end
+ end end
+
+ i_c = i ; j_c = j_p ; if i < nx and j_c > 0 then sq = sqtype[i_c] if sq[j_c] == 0 then
+ if d_c[j] > value then i_l = i_p ; i_r = i_n ; j_b = j_p - 1 ; j_t = j ; goto foundit22 end
+ if d_r[j] > value then i_l = i_p ; i_r = i_n ; j_b = j_p - 1 ; j_t = j ; goto foundit24 end
+ end end
+
+ -- not found
+
+ sqtype[i][j] = nrp
+
+ break
+
+ -- define s-polygon for found square (i_c,j_c) - may have up to 6 sides
+
+ ::foundit21:: -- 1 2 3 4
+
+ sq[j_c] = nrpm
+
+ xspoly[1] = i_l ; yspoly[1] = j_b
+ xspoly[2] = i_c ; yspoly[2] = j_b
+ if d_r[j_c] > value then -- dd2
+ xspoly[3] = i_c ; yspoly[3] = j_c
+ if d_r[j_t] > value then -- dd3
+ xspoly[4] = i_l ; yspoly[4] = j_c
+ if d_c[j_t] > value then -- dd4
+ nspoly = 4
+ else
+ xspoly[5] = i_l ; yspoly[5] = j_c ; nspoly = 5
+ end
+ elseif d_c[j_t] > value then -- dd4
+ xspoly[4] = i_c ; yspoly[4] = j_c ;
+ xspoly[5] = i_l ; yspoly[5] = j_c ; nspoly = 5
+ else
+ xspoly[4] = i_l ; yspoly[4] = j_c ; nspoly = 4
+ if edgetoo then addedge(i_c, j_c, i_l, j_c) end
+ end
+ elseif d_r[j_t] > value then -- dd3
+ xspoly[3] = i_c ; yspoly[3] = j_b
+ xspoly[4] = i_c ; yspoly[4] = j_c
+ if d_c[j_t] > value then -- dd4
+ xspoly[5] = i_l ; yspoly[5] = j_c ; nspoly = 5
+ else
+ xspoly[5] = i_l ; yspoly[5] = j_c ;
+ xspoly[6] = i_l ; yspoly[6] = j_c ; nspoly = 6
+ end
+ elseif d_c[j_t] > value then -- dd4
+ if edgetoo then addedge(i_c, j_b, i_c, j_c) end
+ xspoly[3] = i_c ; yspoly[3] = j_c ;
+ xspoly[4] = i_l ; yspoly[4] = j_c ; nspoly = 4
+ else
+ if edgetoo then addedge(i_c, j_b, i_l, j_c) end
+ xspoly[3] = i_l ; yspoly[3] = j_c ; nspoly = 3
+ end
+ goto done
+
+ ::foundit22:: -- 4 1 2 3
+
+ sq[j_c] = nrpm
+
+ xspoly[1] = i_l ; yspoly[1] = j_c
+ xspoly[2] = i_l ; yspoly[2] = j_b
+ if d_c[j_c] > value then -- dd2
+ xspoly[3] = i_c ; yspoly[3] = j_b
+ if d_r[j_c] > value then -- dd3
+ xspoly[4] = i_c ; yspoly[4] = j_c
+ if d_r[j_t] > value then -- dd4
+ nspoly = 4
+ else
+ xspoly[5] = i_c ; yspoly[5] = j_c ; nspoly = 5 -- suspicious, the same
+ end
+ elseif d_r[j_t] > value then -- dd4
+ xspoly[4] = i_c ; yspoly[4] = j_b ;
+ xspoly[5] = i_c ; yspoly[5] = j_c ; nspoly = 5
+ else
+ if edgetoo then addedge(i_c, j_b, i_c, j_c) end
+ xspoly[4] = i_c ; yspoly[4] = j_c ; nspoly = 4
+ end
+ elseif d_r[j_c] > value then -- dd3
+ xspoly[3] = i_l ; yspoly[3] = j_b
+ xspoly[4] = i_c ; yspoly[4] = j_b
+ xspoly[5] = i_c ; yspoly[5] = j_c
+ if d_r[j_t] > value then -- dd4
+ nspoly = 5
+ else
+ xspoly[6] = i_c ; yspoly[6] = j_c ; nspoly = 6
+ end
+ elseif d_r[j_t] > value then -- dd4
+ if edgetoo then addedge(i_l, j_b, i_c, j_b) end
+ xspoly[3] = i_c ; yspoly[3] = j_b
+ xspoly[4] = i_c ; yspoly[4] = j_c ; nspoly = 4
+ else
+ if edgetoo then addedge(i_l, j_b, i_c, j_c) end
+ xspoly[3] = i_c ; yspoly[3] = j_c ; nspoly = 3
+ end
+ goto done
+
+ ::foundit23:: -- 2 3 4 1
+
+ sq[j_c] = nrpm
+
+ xspoly[1] = i_c ; yspoly[1] = j_b
+ xspoly[2] = i_c ; yspoly[2] = j_c
+ if d_r[j_t] > value then -- dd2
+ xspoly[3] = i_l ; yspoly[3] = j_c
+ if d_c[j_t] > value then -- dd3
+ xspoly[4] = i_l ; yspoly[4] = j_b
+ if d_c[j_c] > value then -- dd4
+ nspoly = 4
+ else
+ xspoly[5] = i_l ; yspoly[5] = j_b ; nspoly = 5
+ end
+ elseif d_c[j_c] > value then -- dd4
+ xspoly[4] = i_l ; yspoly[4] = j_c
+ xspoly[5] = i_l ; yspoly[5] = j_b ; nspoly = 5
+ else
+ if edgetoo then addedge(i_l, j_c, i_l, j_b) end
+ xspoly[4] = i_l ; yspoly[4] = j_b ; nspoly = 4
+ end
+ elseif d_c[j_t] > value then -- dd3
+ xspoly[3] = i_c ; yspoly[3] = j_c
+ xspoly[4] = i_l ; yspoly[4] = j_c
+ xspoly[5] = i_l ; yspoly[5] = j_b
+ if d_c[j_c] > value then -- dd4
+ nspoly = 5
+ else
+ xspoly[6] = i_l ; yspoly[6] = j_b ; nspoly = 6
+ end
+ elseif d_c[j_c] > value then -- dd4
+ if edgetoo then addedge(i_c, j_c, i_l, j_c) end
+ xspoly[3] = i_l ; yspoly[3] = j_c ;
+ xspoly[4] = i_l ; yspoly[4] = j_b ; nspoly = 4
+ else
+ if edgetoo then addedge(i_c, j_c, i_l, j_b) end
+ xspoly[3] = i_l ; yspoly[3] = j_b ; nspoly = 3
+ end
+ goto done
+
+ ::foundit24:: -- 3 4 1 2
+
+ sq[j_c] = nrpm
+
+ xspoly[1] = i_c ; yspoly[1] = j_c
+ xspoly[2] = i_l ; yspoly[2] = j_c
+ if d_c[j_t] > value then -- dd2
+ if d_c[j_c] > value then -- dd3
+ xspoly[3] = i_l ; yspoly[3] = j_b
+ xspoly[4] = i_c ; yspoly[4] = j_b
+ if d_r[j_c] > value then -- dd4
+ nspoly = 4
+ else
+ xspoly[5] = i_c ; yspoly[5] = j_b ; nspoly = 5
+ end
+ else
+ xspoly[3] = i_l ; yspoly[3] = j_b
+ if d_r[j_c] > value then -- dd4
+
+ local xv34 = (dd3*i_c-dd4*i_l)/(dd3 - dd4) -- probably i_l
+ print("4.4 : xv34",xv34,i_c,i_l)
+
+ -- if edgetoo then addedge(i_l, j_b, xv34, j_b) end
+ xspoly[4] = xv34 ; yspoly[4] = j_b ;
+ xspoly[5] = i_c ; yspoly[5] = j_b ; nspoly = 5
+ else
+ if edgetoo then addedge(i_l, j_b, i_c, j_b) end
+ xspoly[4] = i_c ; yspoly[4] = j_b ; nspoly = 4
+ end
+ end
+ elseif d_c[j_c] > value then -- dd3
+ xspoly[3] = i_l ; yspoly[3] = j_b
+ xspoly[4] = i_l ; yspoly[4] = j_b
+ xspoly[5] = i_c ; yspoly[5] = j_b
+ if d_r[j_c] > value then -- dd4
+ nspoly = 5
+ else
+ xspoly[6] = i_c ; yspoly[6] = j_b ; nspoly = 6
+ end
+ elseif d_r[j_c] > value then -- dd4
+ if edgetoo then addedge(i_l, j_c, i_l, j_b) end
+ xspoly[3] = i_l ; yspoly[3] = j_b
+ xspoly[4] = i_c ; yspoly[4] = j_b ; nspoly = 4
+ else
+ if edgetoo then addedge(i_l, j_c, i_c, j_b) end
+ xspoly[3] = i_c ; yspoly[3] = j_b ; nspoly = 3
+ end
+ -- goto done
+
+ ::done::
+ -- combine s-polygon with existing r-polygon, eliminating redundant segments
+
+ if nrpoly == 0 then
+ -- initiate r-polygon
+ for i=1,nspoly do
+ xrpoly[i] = xspoly[i]
+ yrpoly[i] = yspoly[i]
+ end
+ nrpoly = nspoly
+ else
+ -- search r-polygon and s-polygon for one side that matches
+ --
+ -- this is a bottleneck ... we keep this variant here but next go for a faster
+ -- alternative
+ --
+ -- local ispoly, irpoly
+ -- for r=nrpoly,1,-1 do
+ -- local r1
+ -- for s=1,nspoly do
+ -- local s1 = s % nspoly + 1
+ -- if xrpoly[r] == xspoly[s1] and yrpoly[r] == yspoly[s1] then
+ -- if not r1 then
+ -- r1 = r % nrpoly + 1
+ -- end
+ -- if xrpoly[r1] == xspoly[s] and yrpoly[r1] == yspoly[s] then
+ -- ispoly = s
+ -- irpoly = r
+ -- goto foundit3
+ -- end
+ -- end
+ -- end
+ -- end
+ --
+ -- local ispoly, irpoly
+ -- local xr1 = xrpoly[1]
+ -- local yr1 = yrpoly[1]
+ -- for r0=nrpoly,1,-1 do
+ -- for s0=1,nspoly do
+ -- if xr1 == xspoly[s0] and yr1 == yspoly[s0] then
+ -- if s0 == nspoly then
+ -- if xr0 == xspoly[1] and yr0 == yspoly[1] then
+ -- ispoly = s0
+ -- irpoly = r0
+ -- goto foundit3
+ -- end
+ -- else
+ -- local s1 = s0 + 1
+ -- if xr0 == xspoly[s1] and yr0 == yspoly[s1] then
+ -- ispoly = s0
+ -- irpoly = r0
+ -- goto foundit3
+ -- end
+ -- end
+ -- end
+ -- end
+ -- xr1 = xrpoly[r0]
+ -- yr1 = yrpoly[r0]
+ -- end
+ --
+ -- but ...
+ --
+ local minx = xspoly[1]
+ local miny = yspoly[1]
+ local maxx = xspoly[1]
+ local maxy = yspoly[1]
+ for i=1,nspoly do
+ local y = yspoly[i]
+ if y < miny then
+ miny = y
+ elseif y > maxy then
+ maxy = y
+ end
+ local x = xspoly[i]
+ if x < minx then
+ minx = y
+ elseif x > maxx then
+ maxx = x
+ end
+ end
+ -- we can delay accessing y ...
+ local ispoly, irpoly
+ local xr1 = xrpoly[1]
+ local yr1 = yrpoly[1]
+ for r0=nrpoly,1,-1 do
+ if xr1 >= minx and xr1 <= maxx and yr1 >= miny and yr1 <= maxy then
+ local xr0 = xrpoly[r0]
+ local yr0 = yrpoly[r0]
+ for s0=1,nspoly do
+ if xr1 == xspoly[s0] and yr1 == yspoly[s0] then
+ if s0 == nspoly then
+ if xr0 == xspoly[1] and yr0 == yspoly[1] then
+ ispoly = s0
+ irpoly = r0
+ goto foundit3
+ end
+ else
+ local s1 = s0 + 1
+ if xr0 == xspoly[s1] and yr0 == yspoly[s1] then
+ ispoly = s0
+ irpoly = r0
+ goto foundit3
+ end
+ end
+ end
+ end
+ xr1 = xr0
+ yr1 = yr0
+ else
+ xr1 = xrpoly[r0]
+ yr1 = yrpoly[r0]
+ end
+ end
+ --
+ goto nomatch3
+ ::foundit3::
+ local match1 = 0
+ local rpoly1 = irpoly + nrpoly
+ local spoly1 = ispoly - 1
+ for i=2,nspoly-1 do
+ -- search for further matches nearby
+ local ir = (rpoly1 - i) % nrpoly + 1
+ local is = (spoly1 + i) % nspoly + 1
+ if xrpoly[ir] == xspoly[is] and yrpoly[ir] == yspoly[is] then
+ match1 = match1 + 1
+ else
+ break -- goto nomatch1
+ end
+ end
+ ::nomatch1::
+ local match2 = 0
+ local rpoly2 = irpoly - 1
+ local spoly2 = ispoly + nspoly
+ for i=2,nspoly-1 do
+ -- search other way for further matches nearby
+ local ir = (rpoly2 + i) % nrpoly + 1
+ local is = (spoly2 - i) % nspoly + 1
+ if xrpoly[ir] == xspoly[is] and yrpoly[ir] == yspoly[is] then
+ match2 = match2 + 1
+ else
+ break -- goto nomatch2
+ end
+ end
+ ::nomatch2::
+ -- local dnrpoly = nspoly - 2 - 2*match1 - 2*match2
+ local dnrpoly = nspoly - 2*(match1 + match2 + 1)
+ local ispolystart = (ispoly + match1) % nspoly + 1 -- first node of s-polygon to include
+ local irpolyend = (rpoly1 - match1 - 1) % nrpoly + 1 -- last node of s-polygon to include
+ if dnrpoly ~= 0 then
+ local irpolystart = (irpoly + match2) % nrpoly + 1 -- first node of s-polygon to include
+ if irpolystart > irpolyend then
+ -- local ispolyend = (spoly1 - match2 + nspoly)%nspoly + 1 -- last node of s-polygon to include
+ if dnrpoly > 0 then
+ -- expand the arrays xrpoly and yrpoly
+ for i=nrpoly,irpolystart,-1 do
+ local k = i + dnrpoly
+ xrpoly[k] = xrpoly[i]
+ yrpoly[k] = yrpoly[i]
+ end
+ else -- if dnrpoly < 0 then
+ -- contract the arrays xrpoly and yrpoly
+ for i=irpolystart,nrpoly do
+ local k = i + dnrpoly
+ xrpoly[k] = xrpoly[i]
+ yrpoly[k] = yrpoly[i]
+ end
+ end
+ end
+ nrpoly = nrpoly + dnrpoly
+ end
+ if nrpoly < irpolyend then
+ for i=irpolyend,nrpoly+1,-1 do
+ -- otherwise these values get lost!
+ local k = i - nrpoly
+ xrpoly[k] = xrpoly[i]
+ yrpoly[k] = yrpoly[i]
+ end
+ end
+ local n = nspoly - 2 - match1 - match2
+ if n == 1 then
+ local irpoly1 = irpolyend % nrpoly + 1
+ local ispoly1 = ispolystart % nspoly + 1
+ xrpoly[irpoly1] = xspoly[ispoly1]
+ yrpoly[irpoly1] = yspoly[ispoly1]
+ elseif n > 0 then
+ -- often 2
+ for i=1,n do
+ local ii = i - 1
+ local ir = (irpolyend + ii) % nrpoly + 1
+ local is = (ispolystart + ii) % nspoly + 1
+ xrpoly[ir] = xspoly[is]
+ yrpoly[ir] = yspoly[is]
+ end
+ end
+ ::nomatch3::
+ end
+ end
+ end
+
+ if nrpoly > 0 then
+ local t = { }
+ local n = 0
+ for i=1,nrpoly do
+ n = n + 1 t[n] = xrpoly[i]
+ n = n + 1 t[n] = yrpoly[i]
+ end
+ if mpflatten then
+ mpflatten(t) -- maybe integrate
+ end
+ nofs = nofs + 1
+ shade[nofs] = t
+ -- print(value,nrpoly,#t,#t-nrpoly*2)
+ end
+
+ end
+
+ edges [value+1] = edge
+ shades[value+1] = shade
+-- edges [value] = edge
+-- shades[value] = shade
+ end
+
+ result.shades = shades
+ result.shapes = edges
+
+end
+
+-- accessors
+
+function mp.lmt_contours_nx (i) return getparameterset().result.nx end
+function mp.lmt_contours_ny (i) return getparameterset().result.ny end
+
+function mp.lmt_contours_nofvalues() return getparameterset().result.nofvalues end
+function mp.lmt_contours_value (i) return getparameterset().result.values[i] end
+
+function mp.lmt_contours_minz (i) return getparameterset().result.minz end
+function mp.lmt_contours_maxz (i) return getparameterset().result.maxz end
+
+function mp.lmt_contours_minmean (i) return getparameterset().result.minmean end
+function mp.lmt_contours_maxmean (i) return getparameterset().result.maxmean end
+
+function mp.lmt_contours_xrange () local p = getparameterset() mpstring(formatters["x = [%.3N,%.3N] ;"](p.xmin,p.xmax)) end
+function mp.lmt_contours_yrange () local p = getparameterset() mpstring(formatters["y = [%.3N,%.3N] ;"](p.ymin,p.ymax)) end
+
+function mp.lmt_contours_format()
+ local p = getparameterset()
+ return mpstring(p.result.islist and "@i" or p.zformat or p.format)
+end
+
+function mp.lmt_contours_function()
+ local p = getparameterset()
+ return mpstring(p.result.islist and concat(p["functions"], ", ") or p["function"])
+end
+
+function mp.lmt_contours_range()
+ local p = getparameterset()
+ local r = p.result.islist and p.range
+ if not r or #r == 0 then
+ return mpstring("")
+ elseif #r == 1 then
+ return mpstring(r[1])
+ else
+ return mpstring(formatters["z = [%s,%s]"](r[1],r[2]))
+ end
+end
+
+function mp.lmt_contours_edge_paths(value)
+ mpdraw(getparameterset().result.edges[value],true)
+ mpflush()
+end
+
+function mp.lmt_contours_shape_paths(value)
+ mpdraw(getparameterset().result.shapes[value],false)
+ mpflush()
+end
+
+function mp.lmt_contours_shade_paths(value)
+ mpfill(getparameterset().result.shades[value],true)
+ mpflush()
+end
+
+function mp.lmt_contours_color(value)
+ local p = getparameterset()
+ local color = p.result.colors[value]
+ if color then
+ mpcolor(color)
+ end
+end
+
+-- The next code is based on the wikipedia page. It was a bit tedius job to define the
+-- coordinates but hupefully I made no errors. I rendered all shapes independently and
+-- tripple checked bit one never knows ...
+
+-- maybe some day write from scatch, like this (axis are swapped):
+
+local d = 1/2
+
+local paths = {
+ { 0, d, d, 0 },
+ { 1, d, d, 0 },
+ { 0, d, 1, d },
+ { 1, d, d, 1 },
+ { 0, d, d, 1, d, 0, 1, d }, -- saddle
+ { d, 0, d, 1 },
+ { 0, d, d, 1 },
+ { 0, d, d, 1 },
+ { d, 0, d, 1 },
+ { 0, d, d, 0, 1, d, d, 1 }, -- saddle
+ { 1, d, d, 1 },
+ { 0, d, 1, d },
+ { d, 0, 1, d },
+ { d, 0, 0, d },
+}
+
+local function whatever(data,nx,ny,threshold)
+ local edges = { }
+ local e = 0
+ local d0 = data[1]
+ for j=1,ny-1 do
+ local d1 = data[j+1]
+ local k = j + 1
+ for i=1,nx-1 do
+ local v = 0
+ local l = i + 1
+ local c1 = d0[i]
+ if c1 < threshold then
+ v = v + 8
+ end
+ local c2 = d0[l]
+ if c2 < threshold then
+ v = v + 4
+ end
+ local c3 = d1[l]
+ if c3 < threshold then
+ v = v + 2
+ end
+ local c4 = d1[i]
+ if c4 < threshold then
+ v = v + 1
+ end
+ if v > 0 and v < 15 then
+ if v == 5 or v == 10 then
+ local a = (c1 + c2 + c3 + c4) / 4
+ if a < threshold then
+ v = v == 5 and 10 or 5
+ end
+ local p = paths[v]
+ e = e + 1 edges[e] = k - p[2]
+ e = e + 1 edges[e] = i + p[1]
+ e = e + 1 edges[e] = k - p[4]
+ e = e + 1 edges[e] = i + p[3]
+ e = e + 1 edges[e] = k - p[6]
+ e = e + 1 edges[e] = i + p[5]
+ e = e + 1 edges[e] = k - p[8]
+ e = e + 1 edges[e] = i + p[7]
+ else
+ local p = paths[v]
+ e = e + 1 edges[e] = k - p[2]
+ e = e + 1 edges[e] = i + p[1]
+ e = e + 1 edges[e] = k - p[4]
+ e = e + 1 edges[e] = i + p[3]
+ end
+ end
+ end
+ d0 = d1
+ end
+ return edges
+end
+
+-- todo: just fetch when needed, no need to cache
+
+function mp.lmt_contours_edge_set_by_cell()
+ local p = getparameterset()
+ local result = p.result
+
+ if result.cached then return end
+
+ local values = result.values
+ local nofvalues = result.nofvalues
+ local data = result.data
+ local nx = result.nx
+ local ny = result.ny
+ local lines = { }
+ result.lines = lines
+ for value=1,nofvalues do
+ lines[value] = whatever(data,ny,nx,value)
+ end
+end
+
+function mp.lmt_contours_edge_get_cell(value)
+ mpdraw(getparameterset().result.lines[value])
+ mpflush()
+end
+
+local singles = {
+ { d, 0, 0, 0, 0, d }, -- 1 0001
+ { d, 0, 0, d }, -- 2 0002
+ { 1, d, 1, 0, d, 0 }, -- 3 0010
+ { 1, d, 1, 0, 0, 0, 0, d }, -- 4 0011
+ { 1, d, 1, 0, d, 0, 0, d }, -- 5 0012
+ { 1, d, d, 0 }, -- 6 0020
+ { 1, d, d, 0, 0, 0, 0, d }, -- 7 0021
+ { 1, d, 0, d }, -- 8 0022
+ { d, 1, 1, 1, 1, d }, -- 9 0100
+ false, -- 10 0101
+ false, -- 11 0102
+ { d, 1, 1, 1, 1, 0, d, 0 }, -- 12 0110
+ { d, 1, 1, 1, 1, 0, 0, 0, 0, d }, -- 13 0111
+ { d, 1, 1, 1, 1, 0, d, 0, 0, d }, -- 14 0112
+ { d, 1, 1, 1, 1, d, d, 0 }, -- 15 0120
+ { d, 1, 1, 1, 1, d, d, 0, 0, 0, 0, d }, -- 16 0121
+ { d, 1, 1, 1, 1, d, 0, d }, -- 17 0122
+ { d, 1, 1, d }, -- 18 0200
+ false, -- 19 0201
+ false, -- 20 0202
+ { d, 1, 1, d, 1, 0, d, 0 }, -- 21 0210
+ { d, 1, 1, d, 1, 0, 0, 0, 0, d }, -- 22 0211
+ false, -- 23 0212
+ { d, 1, d, 0 }, -- 24 0220
+ { d, 1, d, 0, 0, 0, 0, d }, -- 25 0221
+ { d, 1, 0, d }, -- 26 0222
+ { 0, 1, d, 1, 0, d }, -- 27 1000
+ { 0, 1, d, 1, d, 0, 0, 0 }, -- 28 1001
+ { 0, 1, d, 1, d, 0, 0, d }, -- 29 1002
+ false, -- 30 1010
+ { 0, 1, d, 1, 1, d, 1, 0, 0, 0 }, -- 31 1011
+ { 0, 1, d, 1, 1, d, 1, 0, d, 0, 0, d }, -- 32 1012
+ false, -- 33 1020
+ { 0, 1, d, 1, 1, d, d, 0, 0, 0 }, -- 34 1021
+ { 0, 1, d, 1, 1, d, 0, d }, -- 35 1022
+ { 0, 1, 1, 1, 1, d, 0, d }, -- 36 1100
+ { 0, 1, 1, 1, 1, d, d, 0, 0, 0 }, -- 37 1101
+ { 0, 1, 1, 1, 1, d, d, 0, 0, d }, -- 38 1102
+ { 0, 1, 1, 1, 1, 0, d, 0, 0, d }, -- 39 1110
+ { 0, 1, 1, 1, 1, 0, 0, 0 }, -- 40 1111
+ { 0, 1, 1, 1, 1, 0, d, 0, 0, d }, -- 41 1112
+ { 0, 1, 1, 1, 1, d, d, 0, 0, d }, -- 42 1120
+ { 0, 1, 1, 1, 1, d, d, 0, 0, 0 }, -- 43 1121
+ { 0, 1, 1, 1, 1, d, 0, d }, -- 44 1122
+ { 0, 1, d, 1, 1, d, 0, d }, -- 45 1200
+ { 0, 1, d, 1, 1, d, d, 0, 0, 0 }, -- 46 1201
+ false, -- 47 1202
+ { 0, 1, d, 1, 1, d, 1, 0, d, 0, 0, d }, -- 48 1210
+ { 0, 1, d, 1, 1, d, 1, 0, 0, 0 }, -- 49 1211
+ false, -- 50 1212
+ { 0, 1, d, 1, d, 0, 0, d }, -- 51 1220
+ { 0, 1, d, 1, d, 0, 0, 0 }, -- 52 1221
+ { 0, 1, d, 1, 0, d }, -- 53 1222
+ { d, 1, 0, d }, -- 54 2000
+ { d, 1, d, 0, 0, 0, 0, d }, -- 55 2001
+ { d, 1, d, 0 }, -- 56 2002
+ false, -- 57 2010
+ { d, 1, 1, d, 1, 0, 0, 0, 0, d }, -- 58 2011
+ { d, 1, 1, d, 1, 0, d, 0 }, -- 59 2012
+ false, -- 60 2020
+ false, -- 61 2021
+ { d, 1, 1, d }, -- 62 2022
+ { d, 1, 1, 1, 1, d, 0, d }, -- 63 2100
+ { d, 1, 1, 1, 1, d, d, 0, 0, 0, 0, d }, -- 64 2101
+ { d, 1, 1, 1, 1, d, d, 0 }, -- 65 2102
+ { d, 1, 1, 1, 1, 0, d, 0, 0, d }, -- 66 2110
+ { d, 1, 1, 1, 1, 0, 0, 0, 0, d }, -- 67 2111
+ { d, 1, 1, 1, 1, 0, d, 0 }, -- 68 2112
+ false, -- 69 2120
+ false, -- 70 2121
+ { d, 1, 1, 1, 1, d }, -- 71 2122
+ { 1, d, 0, d }, -- 72 2200
+ { 1, d, d, 0, 0, 0, 0, d }, -- 73 2201
+ { 1, d, d, 0 }, -- 74 2202
+ { 1, d, 1, 0, d, 0, 0, d }, -- 75 2210
+ { 1, d, 1, 0, 0, 0, 0, d }, -- 76 2211
+ { 1, d, 1, 0, d, 0 }, -- 77 2212
+ { d, 0, 0, d }, -- 78 2220
+ { 0, d, 0, 0, d, 0 }, -- 79 2221
+}
+
+local sadles = {
+ false, false, false, false, false, false, false, false, false,
+ { { d, 1, 1, 1, 1, d }, { d, 0, 0, 0, 0, d }, { d, 1, 1, 1, 1, d, d, 0, 0, 0, 0, d }, false, false, false }, -- 10 0101
+ { { d, 1, 1, 1, 1, d }, { d, 0, 0, d }, { d, 1, 1, 1, 1, d, d, 0, 0, d }, false, false, false }, -- 11 0102
+ false, false, false, false, false, false, false,
+ { { d, 1, 1, d }, { d, 0, 0, 0, 0, d }, { d, 1, 1, d, d, 0, 0, 0, 0, d }, false, false, false }, -- 19 0201
+ { { d, 1, 1, d }, { d, 0, 0, d }, { d, 1, 1, d, d, 0, 0, d }, false, { d, 1, 0, d }, { 1, d, d, 0 } }, -- 20 0202
+ false, false,
+ { false, false, { d, 1, 1, d, 1, 0, d, 0, 0, d }, false, { d, 1, 0,d, }, { 1, d, 1, 0,d, 0 } }, -- 23 0212
+ false, false, false, false, false, false,
+ { { 0, 1, d, 1, 0, d }, { 1, d, 1, 0, d, 0 }, { 0, 1, d, 1, 1, d, 1, 0, d, 0, 0, d }, false, false, false }, -- 30 1010
+ false, false,
+ { { 1, 0, d, 0, 0, d, }, { 1, d, d, 0 }, { 0, 1, d, 1, 1, d, d, 0, 0, d }, false, false, false }, -- 33 1020
+ false, false, false, false, false, false, false, false, false, false, false, false, false,
+ { false, false, { 0,1, d, 1, 1, d, d, 0, 0, d }, false, { 0,1, d, 1, 0, d }, {1, d, d, 0 } }, -- 47 1202
+ false, false,
+ { false, false, { 0, 1, d, 1, 1, d, 1, 0, d, 0, 0, d }, false, { 0, 1, d, 1, 0, d }, { 1, d, 1, 0, d, 0 } }, -- 50 1212
+ false, false, false, false, false, false,
+ { { d, 1, 0, d }, { 1, d, 1, 0, 0, d }, { d, 1, 1, d, 1, 0, d, 0, 0, d }, false, false, false }, -- 57 2010
+ false, false,
+ { { d, 1, 0,d }, { 1, d, d, 0 }, { d, 1, 1, d, d, 0, 0, d }, false, { d, 1, 1, d }, { d, 0, 0, d } }, -- 60 2020
+ { false, false, { d, 1, 1, d, d, 0, 0, 0, 0, d }, false, { d, 1, 1, d }, { d, 0, 0, 0, 0, d } }, -- 61 2021
+ false, false, false, false, false, false, false,
+ { false, false, { d, 1, 1, 1, 1, d, d, 0, 0, d }, false, { d, 1, 1, 1, 1, d }, { d, 0,0,d } }, -- 69 2120
+ { false, false, { d, 1, 1, 1, 1, d, d, 0, 0, 0, 0, d }, false, { d, 1, 1, 1, 1, d }, { d, 0, 0, 0, 0, d } }, -- 70 2121
+}
+
+local function whatever(data,nx,ny,threshold,background)
+
+ if background then
+
+ local llx = 1/2
+ local lly = llx
+ local urx = ny + llx
+ local ury = nx + lly
+
+ return { { llx, lly, urx, 0, urx, ury, 0, ury } }
+
+ else
+
+ local bands = { }
+ local b = 0
+
+ local function band(s,n,x,y) -- simple. no closure so fast
+ if n == 6 then
+ return {
+ x - s[ 2], y + s[ 1], x - s[ 4], y + s[ 3], x - s[ 6], y + s[ 5],
+ }
+ elseif n == 8 then
+ return {
+ x - s[ 2], y + s[ 1], x - s[ 4], y + s[ 3], x - s[ 6], y + s[ 5],
+ x - s[ 8], y + s[ 7],
+ }
+ elseif n == 10 then
+ return {
+ x - s[ 2], y + s[ 1], x - s[ 4], y + s[ 3], x - s[ 6], y + s[ 5],
+ x - s[ 8], y + s[ 7], x - s[10], y + s[ 9],
+ }
+ elseif n == 4 then
+ return {
+ x - s[ 2], y + s[ 1], x - s[ 4], y + s[ 3],
+ }
+ else -- 12
+ return {
+ x - s[ 2], y + s[ 1], x - s[ 4], y + s[ 3], x - s[ 6], y + s[ 5],
+ x - s[ 8], y + s[ 7], x - s[10], y + s[ 9], x - s[12], y + s[11],
+ }
+ end
+ end
+
+ local pp = { }
+
+ local d0 = data[1]
+ for j=1,ny-1 do
+ local d1 = data[j+1]
+ local k = j + 1
+ local p = false
+ for i=1,nx-1 do
+ local v = 0
+ local l = i + 1
+ local c1 = d0[i]
+ if c1 == threshold then
+ v = v + 27
+ elseif c1 > threshold then
+ v = v + 54
+ end
+ local c2 = d0[l]
+ if c2 == threshold then
+ v = v + 9
+ elseif c2 > threshold then
+ v = v + 18
+ end
+ local c3 = d1[l]
+ if c3 == threshold then
+ v = v + 3
+ elseif c3 > threshold then
+ v = v + 6
+ end
+ local c4 = d1[i]
+ if c4 == threshold then
+ v = v + 1
+ elseif c4 > threshold then
+ v = v + 2
+ end
+ if v > 0 and v < 80 then
+ if v == 40 then
+ -- a little optimization: full areas appended horizontally
+ if p then
+ p[4] = l -- i + 1
+ p[6] = l -- i + 1
+ else
+ -- x-0 y+1 x-1 y+1 x-1 y+0 x-0 y+0
+ p = { j, i, j, l, k, l, k, i }
+ b = b + 1 ; bands[b] = p
+ end
+ else
+ local s = singles[v]
+ if s then
+ b = b + 1 ; bands[b] = band(s,#s,k,i)
+ else
+ local s = sadles[v]
+ if s then
+ local m = (c1 + c2 + c3 + c4) / 4
+ if m < threshold then
+ local s1 = s[1] if s1 then b = b + 1 ; bands[b] = band(s1,#s1,i,j) end
+ local s2 = s[2] if s2 then b = b + 1 ; bands[b] = band(s2,#s2,i,j) end
+ elseif m == threshold then
+ local s3 = s[3] if s3 then b = b + 1 ; bands[b] = band(s3,#s3,i,j) end
+ local s4 = s[4] if s4 then b = b + 1 ; bands[b] = band(s4,#s4,i,j) end
+ else
+ local s5 = s[5] if s5 then b = b + 1 ; bands[b] = band(s5,#s5,i,j) end
+ local s6 = s[6] if s6 then b = b + 1 ; bands[b] = band(s6,#s6,i,j) end
+ end
+ end
+ end
+ p = false
+ end
+ else
+ p = false
+ end
+ end
+ d0 = d1
+ end
+ return bands
+ end
+end
+
+function mp.lmt_contours_edge_set_by_band(value)
+ local p = getparameterset()
+ local result = p.result
+
+ if result.cached then return end
+
+ local values = result.values
+ local nofvalues = result.nofvalues
+ local data = result.data
+ local nx = result.nx
+ local ny = result.ny
+ local bands = { }
+ result.bands = bands
+ for value=1,nofvalues do
+ bands[value] = whatever(data,ny,nx,value,value == 1)
+ end
+end
+
+function mp.lmt_contours_edge_get_band(value)
+ mpfill(getparameterset().result.bands[value],true)
+ mpflush()
+end
+
+-- Because we share some code surface plots also end up here. When working on the
+-- contour macros by concidence I ran into a 3D plot in
+--
+-- https://staff.science.uva.nl/a.j.p.heck/Courses/mptut.pdf
+--
+-- The code is pure MetaPost and works quite well. With a bit of optimization
+-- performance is also ok, but in the end a Lua solution is twice as fast and also
+-- permits some more tweaking at no cost. So, below is an adaptation of an example
+-- in the mentioned link. It's one of these cases where access to pseudo arrays
+-- is slowing down MP.
+
+local sqrt, sin, cos = math.sqrt, math.sin, math.cos
+
+local f_fill_rgb = formatters["F (%.6N,%.6N)--(%.6N,%.6N)--(%.6N,%.6N)--(%.6N,%.6N)--C withcolor (%.3N,%.3N,%.3N) ;"]
+local f_draw_rgb = formatters["D (%.6N,%.6N)--(%.6N,%.6N)--(%.6N,%.6N)--(%.6N,%.6N)--C withcolor %.3F ;"]
+local f_mesh_rgb = formatters["U (%.6N,%.6N)--(%.6N,%.6N)--(%.6N,%.6N)--(%.6N,%.6N)--C withcolor (%.3N,%.3N,%.3N) ;"]
+local f_fill_cmy = formatters["F (%.6N,%.6N)--(%.6N,%.6N)--(%.6N,%.6N)--(%.6N,%.6N)--C withcolor (%.3N,%.3N,%.3N,0) ;"]
+local f_draw_cmy = formatters["D (%.6N,%.6N)--(%.6N,%.6N)--(%.6N,%.6N)--(%.6N,%.6N)--C withcolor %.3F ;"]
+local f_mesh_cmy = formatters["U (%.6N,%.6N)--(%.6N,%.6N)--(%.6N,%.6N)--(%.6N,%.6N)--C withcolor (%.3N,%.3N,%.3N,0) ;"]
+
+local f_function_n = formatters [ [[
+ local math = math
+ local round = math.round
+ %s
+ return function(x,y)
+ return %s
+ end
+]] ]
+
+local f_function_y = formatters [ [[
+ local math = math
+ local round = math.round
+ local nan = NaN
+ local inf = math.huge
+ local er = 0
+ %s
+ return function(x,y,dnan,dinf,report)
+ local n = %s
+ if n == nan then
+ er = er + 1
+ if er < 10 then
+ report("nan at (%s,%s)",x,y)
+ end
+ n = dnan
+ elseif n == inf then
+ er = er + 1
+ if er < 10 then
+ report("inf at (%s,%s)",x,y)
+ end
+ n = dinf
+ end
+ dx[my] = n
+ sy = sy + 1
+ end
+ return n, er
+end
+]] ]
+
+local f_color = formatters [ [[
+ local math = math
+ return function(f)
+ return %s
+ end
+]] ]
+
+function mp.lmt_surface_do(specification)
+ --
+ -- The projection and color brightness calculation have been inlined. We also store
+ -- differently.
+ --
+ -- todo: ignore weird paths
+ --
+ -- The prototype is now converted to use lmt parameter sets.
+ --
+ local p = getparameterset("surface")
+ --
+ local preamble = p.preamble or ""
+ local code = p.code or "return x + y"
+ local colorcode = p.color or "return f, f, f"
+ local linecolor = p.linecolor or 1
+ local xmin = p.xmin or -1
+ local xmax = p.xmax or 1
+ local ymin = p.ymin or -1
+ local ymax = p.ymax or 1
+ local xstep = p.xstep or .1
+ local ystep = p.ystep or .1
+ local bf = p.brightness or 100
+ local clip = p.clip or false
+ local lines = p.lines
+ local ha = p.snap or 0.01
+ local hb = 2 * ha
+ --
+ if lines == nil then lines = true end
+ --
+ if xstep == 0 then xstep = (xmax - xmin)/100 end
+ if ystep == 0 then ystep = (ymax - ymin)/100 end
+
+ local nxmin = round(xmin/xstep)
+ local nxmax = round(xmax/xstep)
+ local nymin = round(ymin/ystep)
+ local nymax = round(ymax/ystep)
+ local nx = nxmax - nxmin + 1
+ local ny = nymax - nymin + 1
+ --
+ local xvector = p.xvector or { -0.7, -0.7 }
+ local yvector = p.yvector or { 1, 0 }
+ local zvector = p.zvector or { 0, 1 }
+ local light = p.light or { 3, 3, 10 }
+ --
+ local xrx, xry = xvector[1], xvector[2]
+ local yrx, yry = yvector[1], yvector[2]
+ local zrx, zry = zvector[1], zvector[2]
+ local xp, yp, zp = light[1], light[2], light[3]
+ --
+ local data = setmetatableindex("table")
+ local dx = (xmax - xmin) / nx
+ local dy = (ymax - ymin) / ny
+ local xt = xmin
+ --
+ local minf, maxf
+ --
+ -- similar as contours but no data loop here
+ --
+ local fcode = load((p.check and f_function_y or f_function_n)(preamble,code))
+ local func = type(fcode) == "function" and fcode()
+ if type(func) ~= "function" then
+ return false -- fatal error
+ end
+ --
+ local ccode = load(f_color(colorcode))
+ local color = type(ccode) == "function" and ccode()
+ if type(color) ~= "function" then
+ return false -- fatal error
+ end
+ --
+ for i=0,nx do
+ local yt = ymin
+ for j=0,ny do
+ local zt = func(xt,yt)
+ -- projection from 3D to 2D coordinates
+ local x = xt * xrx + yt * yrx + zt * zrx
+ local y = xt * xry + yt * yry + zt * zry
+ local z = zt
+ -- numerical derivatives by central differences
+ local dfx = (func(xt+ha,yt) - func(xt-ha,yt)) / hb
+ local dfy = (func(xt,yt+ha) - func(xt,yt-ha)) / hb
+ -- compute brightness factor at a point
+ local ztp = zt - zp
+ local ytp = yt - yp
+ local xtp = xt - xp
+ local ztp = zt - zp
+ local ytp = yt - yp
+ local xtp = xt - xp
+ local ca = -ztp + dfy*ytp + dfx*xtp
+ local cb = sqrt(1+dfx*dfx+dfy*dfy)
+ local cc = sqrt(ztp*ztp + ytp*ytp + xtp*xtp)
+ local fac = bf*ca/(cb*cc*cc*cc)
+ -- addition: check range
+ if not minf then
+ minf = fac
+ maxf = fac
+ elseif fac < minf then
+ minf = fac
+ elseif fac > maxf then
+ maxf = fac
+ end
+ --
+ data[i][j] = { x, y, fac }
+ --
+ yt = yt + dy
+ end
+ xt = xt + dx
+ end
+ local result = { }
+ local r = 0
+ local range = maxf - minf
+ local cl = linecolor or 1
+ local enforce = attributes.colors.model == "cmyk"
+ for i=0,nx-1 do
+ for j=0,ny-1 do
+ -- points
+ local z1 = data[i] [j]
+ local z2 = data[i] [j+1]
+ local z3 = data[i+1][j+1]
+ local z4 = data[i+1][j]
+ -- color
+ local cf = z1[3]
+ if clip then
+ -- best clip here if needed
+ if cf < 0 then
+ cf = 0
+ elseif cf > 1 then
+ cf = 1
+ end
+ else
+ -- or remap when we want to
+ cf = (z1[3] - minf) / range
+ end
+ local z11 = z1[1]
+ local z12 = z1[2]
+ local z21 = z2[1]
+ local z22 = z2[2]
+ local z31 = z3[1]
+ local z32 = z3[2]
+ local z41 = z4[1]
+ local z42 = z4[2]
+ -- if lines then
+ -- -- fill first and draw then, previous shapes can be covered
+ -- else
+ -- -- fill and draw in one go to prevent artifacts
+ -- end
+ local cr, cg, cb = color(cf)
+ if not cr then cr = 0 end
+ if not cg then cg = 0 end
+ if not cb then cb = 0 end
+ if enforce then
+ cr, cg, cb = 1 - cr, 1 - cg, 1 - cb
+ r = r + 1
+ if lines then
+ result[r] = f_fill_cmy(z11,z12,z21,z22,z31,z32,z41,z42,cr,cg,cb)
+ r = r + 1
+ result[r] = f_draw_cmy(z11,z12,z21,z22,z31,z32,z41,z42,cl)
+ else
+ result[r] = f_mesh_cmy(z11,z12,z21,z22,z31,z32,z41,z42,cr,cg,cb)
+ end
+ else
+ r = r + 1
+ if lines then
+ result[r] = f_fill_rgb(z11,z12,z21,z22,z31,z32,z41,z42,cr,cg,cb)
+ r = r + 1
+ result[r] = f_draw_rgb(z11,z12,z21,z22,z31,z32,z41,z42,cl)
+ else
+ result[r] = f_mesh_rgb(z11,z12,z21,z22,z31,z32,z41,z42,cr,cg,cb)
+ end
+ end
+ end
+ end
+ mp.direct(concat(result))
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mlib-ctx.lua b/Master/texmf-dist/tex/context/base/mkiv/mlib-ctx.lua
index 89f2fa0eeb1..c913408cd05 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/mlib-ctx.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/mlib-ctx.lua
@@ -80,6 +80,7 @@ implement {
}
local patterns = {
+ CONTEXTLMTXMODE > 0 and "meta-imp-%s.mkxl" or "",
"meta-imp-%s.mkiv",
"meta-imp-%s.tex",
-- obsolete:
@@ -88,10 +89,8 @@ local patterns = {
}
local function action(name,foundname)
+ commands.loadlibrary(name,foundname,false)
status_metapost("library %a is loaded",name)
- context.startreadingfile()
- context.input(foundname)
- context.stopreadingfile()
end
local function failure(name)
@@ -245,6 +244,8 @@ implement {
arguments = "string",
}
+-- this has to become a codeinjection
+
function metapost.getclippath(specification) -- why not a special instance for this
local mpx = metapost.pushformat(specification)
local data = specification.data or ""
@@ -304,7 +305,14 @@ end
implement {
name = "mpsetclippath",
actions = function(specification)
- setmacro("MPclippath",metapost.theclippath(specification),"global")
+ local p = specification.data and metapost.theclippath(specification)
+ if not p or p == "" then
+ local b = number.dimenfactors.bp
+ local w = b * (specification.width or 0)
+ local h = b * (specification.height or 0)
+ p = formatters["0 0 m %.6N 0 l %.6N %.6N l 0 %.6N l"](w,w,h,h)
+ end
+ setmacro("MPclippath",p,"global")
end,
arguments = {
{
@@ -316,12 +324,14 @@ implement {
{ "inclusions" },
{ "method" },
{ "namespace" },
+ { "width", "dimension" },
+ { "height", "dimension" },
},
}
}
statistics.register("metapost", function()
- local n = metapost.n
+ local n = metapost.nofruns
if n and n > 0 then
local elapsedtime = statistics.elapsedtime
local elapsed = statistics.elapsed
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mlib-ctx.mkiv b/Master/texmf-dist/tex/context/base/mkiv/mlib-ctx.mkiv
index 1f05b6ef880..a1ed7efeb8c 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/mlib-ctx.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/mlib-ctx.mkiv
@@ -11,73 +11,17 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-%D This file contains the \MPLIB\ variants of the by now ancient
-%D \MPTOPDF\ code.
-
\writestatus{loading}{MetaPost Library Graphics / Initializations}
\registerctxluafile{mlib-run}{}
\registerctxluafile{mlib-ctx}{}
\registerctxluafile{mlib-lua}{}
-\registerctxluafile{mlib-int}{} % here ?
+\registerctxluafile{mlib-lmp}{}
+\registerctxluafile{mlib-int}{}
+
+\doifelsefileexists{mlib-cnt.lua}{\registerctxluafile{mlib-cnt}{optimize}}{}
+\doifelsefileexists{mlib-svg.lua}{\registerctxluafile{mlib-svg}{optimize}}{}
\unprotect
\protect \endinput
-
-% local mpgraphic = [[
-% for i=1 upto 1000 :
-% beginfig(0);
-% draw halfcircle scaled 1cm withcolor green ;
-% picture p ; p := "oeps" infont defaultfont scaled .75 rotated 45 ;
-% p := p shifted - (xpart center p,0) ;
-% draw p ; draw boundingbox p ;
-% endfig ;
-% beginfig(0);
-% draw halfcircle scaled 1cm dashed evenly withcolor green ;
-% endfig ;
-% beginfig(0);
-% pickup pencircle xscaled .5mm yscaled .25mm rotated 45 ;
-% draw halfcircle scaled 1cm withcolor red ;
-% endfig ;
-% beginfig(0);
-% draw halfcircle scaled 1cm ;
-% endfig ;
-% beginfig(0);
-% pickup pencircle xscaled .5mm yscaled .25mm rotated 45 ;
-% for k:=1 upto 10 :
-% draw halfcircle scaled uniformdeviate(1cm) withcolor (red/(k/4)) ;
-% endfor ;
-% endfig ;
-% endfor ;
-% ]]
-% -- local mpx = metapost.format("metafun")
-% metapost.process(metapost.format("metafun"),mpgraphic)
-
-% \starttext
-% \setupcolors[state=start]
-% \definecolor[red] [r=1]
-% \definecolor[cyan][c=1]
-% \setbox\scratchbox\hbox{\startMPcode\stopMPcode} % first specials are forgotten
-% \definecolor[sss][t=.5,a=1,r=1]
-% \definespotcolor[oeps1][green][p=.5]
-% \definespotcolor[oeps2][green][p=.25]
-% \definespotcolor[oeps3][green][p=.25,t=.5,a=1]
-% \startMPpage
-% fill fullcircle scaled 10cm withcolor \MPcolor{red} ;
-% fill fullcircle scaled 8cm withcolor cmyk(1,0,0,0) ;
-% fill fullcircle scaled 6cm withcolor cmyk(0,1,0,0) ;
-% fill fullcircle scaled 4cm withcolor cmyk(0,0,1,0) ;
-% fill fullcircle scaled 2cm withcolor cmyk(0,0,0,1) ;
-% currentpicture := currentpicture shifted (-7.5cm,0) ;
-% fill fullcircle scaled 10cm withcolor transparent(1,0.75,cmyk(0,0,1,0)) ;
-% fill fullcircle scaled 8cm withcolor \MPcolor{sss} ;
-% fill fullcircle scaled 6cm withcolor \MPcolor{oeps1} ;
-% fill fullcircle scaled 4cm withcolor \MPcolor{oeps2} ;
-% currentpicture := currentpicture shifted (-7.5cm,0) ;
-% fill fullcircle scaled 10cm withcolor \MPcolor{oeps3} ;
-% circular_shade(fullcircle scaled 8cm, 1, red, blue) ;
-% circular_shade(fullcircle scaled 6cm, 1, (1,0,0,0), (0,1,0,0)) ;
-% circular_shade(fullcircle scaled 4cm, 1, cmyk(.5,.5,1,0), (0,1,0,0)) ;
-% \stopMPpage
-% \stoptext
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mlib-ctx.mkxl b/Master/texmf-dist/tex/context/base/mkiv/mlib-ctx.mkxl
new file mode 100644
index 00000000000..bb246062710
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/mlib-ctx.mkxl
@@ -0,0 +1,31 @@
+%D \module
+%D [ file=mlib-ctx,
+%D version=2008.03.25,
+%D title=\METAPOST\ Integrated Graphics,
+%D subtitle=Basics,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{MetaPost Library Graphics / Initializations}
+
+\registerctxluafile{mlib-run}{}
+\registerctxluafile{mlib-ctx}{}
+\registerctxluafile{mlib-lua}{}
+\registerctxluafile{mlib-scn}{}
+\registerctxluafile{mlib-mat}{}
+\registerctxluafile{mlib-lmp}{}
+\registerctxluafile{mlib-int}{}
+\registerctxluafile{mlib-lmt}{}
+
+\doifelsefileexists{mlib-cnt.lua}{\registerctxluafile{mlib-cnt}{}}{}
+\doifelsefileexists{mlib-svg.lua}{\registerctxluafile{mlib-svg}{}}{}
+
+\unprotect
+
+\protect \endinput
+
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mlib-int.lua b/Master/texmf-dist/tex/context/base/mkiv/mlib-int.lua
index 63e7278dae7..6fca9530236 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/mlib-int.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/mlib-int.lua
@@ -6,150 +6,261 @@ if not modules then modules = { } end modules ['mlib-int'] = {
license = "see context related readme files",
}
-local factor = number.dimenfactors.bp
------ mpprint = mp.print
-local mpnumeric = mp.numeric
-local mpboolean = mp.boolean
-local mpstring = mp.string
-local mpquoted = mp.quoted
-local getdimen = tex.getdimen
-local getcount = tex.getcount
-local getmacro = tokens.getters.macro
-local get = tex.get
-local mpcolor = attributes.colors.mpcolor
-local emwidths = fonts.hashes.emwidths
-local exheights = fonts.hashes.exheights
-
-local mpgetdimen = mp.getdimen
-
-function mp.PaperHeight () mpnumeric(getdimen("paperheight") *factor) end
-function mp.PaperWidth () mpnumeric(getdimen("paperwidth") *factor) end
-function mp.PrintPaperHeight () mpnumeric(getdimen("printpaperheight") *factor) end
-function mp.PrintPaperWidth () mpnumeric(getdimen("printpaperwidth") *factor) end
-function mp.TopSpace () mpnumeric(getdimen("topspace") *factor) end
-function mp.BottomSpace () mpnumeric(getdimen("bottomspace") *factor) end
-function mp.BackSpace () mpnumeric(getdimen("backspace") *factor) end
-function mp.CutSpace () mpnumeric(getdimen("cutspace") *factor) end
-function mp.MakeupHeight () mpnumeric(getdimen("makeupheight") *factor) end
-function mp.MakeupWidth () mpnumeric(getdimen("makeupwidth") *factor) end
-function mp.TopHeight () mpnumeric(getdimen("topheight") *factor) end
-function mp.TopDistance () mpnumeric(getdimen("topdistance") *factor) end
-function mp.HeaderHeight () mpnumeric(getdimen("headerheight") *factor) end
-function mp.HeaderDistance () mpnumeric(getdimen("headerdistance") *factor) end
-function mp.TextHeight () mpnumeric(getdimen("textheight") *factor) end
-function mp.FooterDistance () mpnumeric(getdimen("footerdistance") *factor) end
-function mp.FooterHeight () mpnumeric(getdimen("footerheight") *factor) end
-function mp.BottomDistance () mpnumeric(getdimen("bottomdistance") *factor) end
-function mp.BottomHeight () mpnumeric(getdimen("bottomheight") *factor) end
-function mp.LeftEdgeWidth () mpnumeric(getdimen("leftedgewidth") *factor) end
-function mp.LeftEdgeDistance () mpnumeric(getdimen("leftedgedistance") *factor) end
-function mp.LeftMarginWidth () mpnumeric(getdimen("leftmarginwidth") *factor) end
-function mp.LeftMarginDistance () mpnumeric(getdimen("leftmargindistance") *factor) end
-function mp.TextWidth () mpnumeric(getdimen("textwidth") *factor) end
-function mp.RightMarginDistance () mpnumeric(getdimen("rightmargindistance") *factor) end
-function mp.RightMarginWidth () mpnumeric(getdimen("rightmarginwidth") *factor) end
-function mp.RightEdgeDistance () mpnumeric(getdimen("rightedgedistance") *factor) end
-function mp.RightEdgeWidth () mpnumeric(getdimen("rightedgewidth") *factor) end
-function mp.InnerMarginDistance () mpnumeric(getdimen("innermargindistance") *factor) end
-function mp.InnerMarginWidth () mpnumeric(getdimen("innermarginwidth") *factor) end
-function mp.OuterMarginDistance () mpnumeric(getdimen("outermargindistance") *factor) end
-function mp.OuterMarginWidth () mpnumeric(getdimen("outermarginwidth") *factor) end
-function mp.InnerEdgeDistance () mpnumeric(getdimen("inneredgedistance") *factor) end
-function mp.InnerEdgeWidth () mpnumeric(getdimen("inneredgewidth") *factor) end
-function mp.OuterEdgeDistance () mpnumeric(getdimen("outeredgedistance") *factor) end
-function mp.OuterEdgeWidth () mpnumeric(getdimen("outeredgewidth") *factor) end
-function mp.PageOffset () mpnumeric(getdimen("pagebackgroundoffset")*factor) end
-function mp.PageDepth () mpnumeric(getdimen("pagebackgrounddepth") *factor) end
-function mp.LayoutColumns () mpnumeric(getcount("layoutcolumns")) end
-function mp.LayoutColumnDistance() mpnumeric(getdimen("layoutcolumndistance")*factor) end
-function mp.LayoutColumnWidth () mpnumeric(getdimen("layoutcolumnwidth") *factor) end
-function mp.SpineWidth () mpnumeric(getdimen("spinewidth") *factor) end
-function mp.PaperBleed () mpnumeric(getdimen("paperbleed") *factor) end
-
-function mp.RealPageNumber () mpnumeric(getcount("realpageno")) end
-function mp.LastPageNumber () mpnumeric(getcount("lastpageno")) end
-
-function mp.PageNumber () mpnumeric(getcount("pageno")) end
-function mp.NOfPages () mpnumeric(getcount("lastpageno")) end
-
-function mp.SubPageNumber () mpnumeric(getcount("subpageno")) end
-function mp.NOfSubPages () mpnumeric(getcount("lastsubpageno")) end
-
-function mp.CurrentColumn () mpnumeric(getcount("mofcolumns")) end
-function mp.NOfColumns () mpnumeric(getcount("nofcolumns")) end
-
-function mp.BaseLineSkip () mpnumeric(get ("baselineskip",true) *factor) end
-function mp.LineHeight () mpnumeric(getdimen("lineheight") *factor) end
-function mp.BodyFontSize () mpnumeric(getdimen("bodyfontsize") *factor) end
-
-function mp.TopSkip () mpnumeric(get ("topskip",true) *factor) end
-function mp.StrutHeight () mpnumeric(getdimen("strutht") *factor) end
-function mp.StrutDepth () mpnumeric(getdimen("strutdp") *factor) end
-
-function mp.PageNumber () mpnumeric(getcount("pageno")) end
-function mp.RealPageNumber () mpnumeric(getcount("realpageno")) end
-function mp.NOfPages () mpnumeric(getcount("lastpageno")) end
-
-function mp.CurrentWidth () mpnumeric(get ("hsize") *factor) end
-function mp.CurrentHeight () mpnumeric(get ("vsize") *factor) end
-
-function mp.EmWidth () mpnumeric(emwidths [false]*factor) end
-function mp.ExHeight () mpnumeric(exheights[false]*factor) end
-
-mp.HSize = mp.CurrentWidth
-mp.VSize = mp.CurrentHeight
-mp.LastPageNumber = mp.NOfPages
-
-function mp.PageFraction()
- local lastpage = getcount("lastpageno")
- if lastpage > 1 then
- mpnumeric((getcount("realpageno")-1)/(lastpage-1))
- else
- mpnumeric(1)
- end
+local factor = number.dimenfactors.bp
+----- mpprint = mp.print
+local mpnumeric = mp.numeric
+local mpboolean = mp.boolean
+local mpstring = mp.string
+local mpquoted = mp.quoted
+local getdimen = tex.getdimen
+local getcount = tex.getcount
+local getmacro = tokens.getters.macro
+local get = tex.get
+local mpcolor = attributes.colors.mpcolor
+local emwidths = fonts.hashes.emwidths
+local exheights = fonts.hashes.exheights
+
+local mpgetdimen = mp.getdimen
+
+local registerscript = metapost.registerscript
+
+local on_right_page = structures.pages.on_right
+local is_odd_page = structures.pages.is_odd
+local in_body_page = structures.pages.in_body
+local page_fraction = structures.pages.fraction
+
+local function defaultcolormodel() -- can be helper
+ local colormethod = getcount("MPcolormethod")
+ return (colormethod == 0 or colormethod == 1) and 1 or 3
end
--- locals
+if CONTEXTLMTXMODE > 0 then
-local on_right = structures.pages.on_right
-local is_odd = structures.pages.is_odd
-local in_body = structures.pages.in_body
+ local t = os.date("*t") -- maybe this should be a very early on global
-mp.OnRightPage = function() mpboolean(on_right()) end -- needs checking
-mp.OnOddPage = function() mpboolean(is_odd ()) end -- needs checking
-mp.InPageBody = function() mpboolean(in_body ()) end -- needs checking
+ registerscript("year", function() return t.year end)
+ registerscript("month", function() return t.month end)
+ registerscript("day", function() return t.day end)
+ registerscript("hour", function() return t.hour end)
+ registerscript("minute", function() return t.min end)
+ registerscript("second", function() return t.sec end)
--- mp.CurrentLayout : \currentlayout
+ registerscript("PaperHeight", function() return getdimen("paperheight") * factor end)
+ registerscript("PaperWidth", function() return getdimen("paperwidth") * factor end)
+ registerscript("PrintPaperHeight", function() return getdimen("printpaperheight") * factor end)
+ registerscript("PrintPaperWidth", function() return getdimen("printpaperwidth") * factor end)
+ registerscript("TopSpace", function() return getdimen("topspace") * factor end)
+ registerscript("BottomSpace", function() return getdimen("bottomspace") * factor end)
+ registerscript("BackSpace", function() return getdimen("backspace") * factor end)
+ registerscript("CutSpace", function() return getdimen("cutspace") * factor end)
+ registerscript("MakeupHeight", function() return getdimen("makeupheight") * factor end)
+ registerscript("MakeupWidth", function() return getdimen("makeupwidth") * factor end)
+ registerscript("TopHeight", function() return getdimen("topheight") * factor end)
+ registerscript("TopDistance", function() return getdimen("topdistance") * factor end)
+ registerscript("HeaderHeight", function() return getdimen("headerheight") * factor end)
+ registerscript("HeaderDistance", function() return getdimen("headerdistance") * factor end)
+ registerscript("TextHeight", function() return getdimen("textheight") * factor end)
+ registerscript("FooterDistance", function() return getdimen("footerdistance") * factor end)
+ registerscript("FooterHeight", function() return getdimen("footerheight") * factor end)
+ registerscript("BottomDistance", function() return getdimen("bottomdistance") * factor end)
+ registerscript("BottomHeight", function() return getdimen("bottomheight") * factor end)
+ registerscript("LeftEdgeWidth", function() return getdimen("leftedgewidth") * factor end)
+ registerscript("LeftEdgeDistance", function() return getdimen("leftedgedistance") * factor end)
+ registerscript("LeftMarginWidth", function() return getdimen("leftmarginwidth") * factor end)
+ registerscript("LeftMarginDistance", function() return getdimen("leftmargindistance") * factor end)
+ registerscript("TextWidth", function() return getdimen("textwidth") * factor end)
+ registerscript("RightMarginDistance", function() return getdimen("rightmargindistance") * factor end)
+ registerscript("RightMarginWidth", function() return getdimen("rightmarginwidth") * factor end)
+ registerscript("RightEdgeDistance", function() return getdimen("rightedgedistance") * factor end)
+ registerscript("RightEdgeWidth", function() return getdimen("rightedgewidth") * factor end)
+ registerscript("InnerMarginDistance", function() return getdimen("innermargindistance") * factor end)
+ registerscript("InnerMarginWidth", function() return getdimen("innermarginwidth") * factor end)
+ registerscript("OuterMarginDistance", function() return getdimen("outermargindistance") * factor end)
+ registerscript("OuterMarginWidth", function() return getdimen("outermarginwidth") * factor end)
+ registerscript("InnerEdgeDistance", function() return getdimen("inneredgedistance") * factor end)
+ registerscript("InnerEdgeWidth", function() return getdimen("inneredgewidth") * factor end)
+ registerscript("OuterEdgeDistance", function() return getdimen("outeredgedistance") * factor end)
+ registerscript("OuterEdgeWidth", function() return getdimen("outeredgewidth") * factor end)
+ registerscript("PageOffset", function() return getdimen("pagebackgroundoffset") * factor end)
+ registerscript("PageDepth", function() return getdimen("pagebackgrounddepth") * factor end)
+ registerscript("LayoutColumns", function() return getcount("layoutcolumns") end)
+ registerscript("LayoutColumnDistance", function() return getdimen("layoutcolumndistance") * factor end)
+ registerscript("LayoutColumnWidth", function() return getdimen("layoutcolumnwidth") * factor end)
+ registerscript("SpineWidth", function() return getdimen("spinewidth") * factor end)
+ registerscript("PaperBleed", function() return getdimen("paperbleed") * factor end)
-function mp.OverlayWidth () mpnumeric(getdimen("d_overlay_width") * factor) end
-function mp.OverlayHeight () mpnumeric(getdimen("d_overlay_height") * factor) end
-function mp.OverlayDepth () mpnumeric(getdimen("d_overlay_depth") * factor) end
-function mp.OverlayLineWidth() mpnumeric(getdimen("d_overlay_linewidth") * factor) end
-function mp.OverlayOffset () mpnumeric(getdimen("d_overlay_offset") * factor) end
-function mp.OverlayRegion () mpstring(getmacro("m_overlay_region")) end
+ registerscript("RealPageNumber", function() return getcount("realpageno") end)
+ registerscript("LastPageNumber", function() return getcount("lastpageno") end)
+
+ registerscript("PageNumber", function() return getcount("pageno") end)
+ registerscript("NOfPages", function() return getcount("lastpageno") end)
+
+ registerscript("SubPageNumber", function() return getcount("subpageno") end)
+ registerscript("NOfSubPages", function() return getcount("lastsubpageno") end)
+
+ registerscript("CurrentColumn", function() return getcount("mofcolumns") end)
+ registerscript("NOfColumns", function() return getcount("nofcolumns") end)
+
+ registerscript("BaseLineSkip", function() return get ("baselineskip",true) * factor end)
+ registerscript("LineHeight", function() return getdimen("lineheight") * factor end)
+ registerscript("BodyFontSize", function() return getdimen("bodyfontsize") * factor end)
+
+ registerscript("TopSkip", function() return get ("topskip",true) * factor end)
+ registerscript("StrutHeight", function() return getdimen("strutht") * factor end)
+ registerscript("StrutDepth", function() return getdimen("strutdp") * factor end)
+
+ registerscript("PageNumber", function() return getcount("pageno") end)
+ registerscript("RealPageNumber", function() return getcount("realpageno") end)
+ registerscript("NOfPages", function() return getcount("lastpageno") end)
+
+ registerscript("CurrentWidth", function() return get ("hsize") * factor end)
+ registerscript("CurrentHeight", function() return get ("vsize") * factor end)
+
+ registerscript("EmWidth", function() return emwidths [false] * factor end)
+ registerscript("ExHeight", function() return exheights[false] * factor end)
+
+ registerscript("HSize", function() return get ("hsize") * factor end)
+ registerscript("VSize", function() return get ("vsize") * factor end)
+ registerscript("LastPageNumber", function() return getcount("lastpageno") end)
+
+ registerscript("OverlayWidth", function() return getdimen("d_overlay_width") * factor end)
+ registerscript("OverlayHeight", function() return getdimen("d_overlay_height") * factor end)
+ registerscript("OverlayDepth", function() return getdimen("d_overlay_depth") * factor end)
+ registerscript("OverlayLineWidth", function() return getdimen("d_overlay_linewidth") * factor end)
+ registerscript("OverlayOffset", function() return getdimen("d_overlay_offset") * factor end)
+ registerscript("OverlayRegion", function() mpstring(getmacro("m_overlay_region")) end)
+ -- ("CurrentLayout", function() mpstring(getmacro("currentlayout")) end)
+
+ registerscript("PageFraction", page_fraction)
+ registerscript("OnRightPage", on_right_page)
+ registerscript("OnOddPage", is_odd_page )
+ registerscript("InPageBody", in_body_page )
+
+ registerscript("defaultcolormodel", defaultcolormodel)
+
+else
+
+ function mp.PaperHeight () mpnumeric(getdimen("paperheight") * factor) end
+ function mp.PaperWidth () mpnumeric(getdimen("paperwidth") * factor) end
+ function mp.PrintPaperHeight () mpnumeric(getdimen("printpaperheight") * factor) end
+ function mp.PrintPaperWidth () mpnumeric(getdimen("printpaperwidth") * factor) end
+ function mp.TopSpace () mpnumeric(getdimen("topspace") * factor) end
+ function mp.BottomSpace () mpnumeric(getdimen("bottomspace") * factor) end
+ function mp.BackSpace () mpnumeric(getdimen("backspace") * factor) end
+ function mp.CutSpace () mpnumeric(getdimen("cutspace") * factor) end
+ function mp.MakeupHeight () mpnumeric(getdimen("makeupheight") * factor) end
+ function mp.MakeupWidth () mpnumeric(getdimen("makeupwidth") * factor) end
+ function mp.TopHeight () mpnumeric(getdimen("topheight") * factor) end
+ function mp.TopDistance () mpnumeric(getdimen("topdistance") * factor) end
+ function mp.HeaderHeight () mpnumeric(getdimen("headerheight") * factor) end
+ function mp.HeaderDistance () mpnumeric(getdimen("headerdistance") * factor) end
+ function mp.TextHeight () mpnumeric(getdimen("textheight") * factor) end
+ function mp.FooterDistance () mpnumeric(getdimen("footerdistance") * factor) end
+ function mp.FooterHeight () mpnumeric(getdimen("footerheight") * factor) end
+ function mp.BottomDistance () mpnumeric(getdimen("bottomdistance") * factor) end
+ function mp.BottomHeight () mpnumeric(getdimen("bottomheight") * factor) end
+ function mp.LeftEdgeWidth () mpnumeric(getdimen("leftedgewidth") * factor) end
+ function mp.LeftEdgeDistance () mpnumeric(getdimen("leftedgedistance") * factor) end
+ function mp.LeftMarginWidth () mpnumeric(getdimen("leftmarginwidth") * factor) end
+ function mp.LeftMarginDistance () mpnumeric(getdimen("leftmargindistance") * factor) end
+ function mp.TextWidth () mpnumeric(getdimen("textwidth") * factor) end
+ function mp.RightMarginDistance () mpnumeric(getdimen("rightmargindistance") * factor) end
+ function mp.RightMarginWidth () mpnumeric(getdimen("rightmarginwidth") * factor) end
+ function mp.RightEdgeDistance () mpnumeric(getdimen("rightedgedistance") * factor) end
+ function mp.RightEdgeWidth () mpnumeric(getdimen("rightedgewidth") * factor) end
+ function mp.InnerMarginDistance () mpnumeric(getdimen("innermargindistance") * factor) end
+ function mp.InnerMarginWidth () mpnumeric(getdimen("innermarginwidth") * factor) end
+ function mp.OuterMarginDistance () mpnumeric(getdimen("outermargindistance") * factor) end
+ function mp.OuterMarginWidth () mpnumeric(getdimen("outermarginwidth") * factor) end
+ function mp.InnerEdgeDistance () mpnumeric(getdimen("inneredgedistance") * factor) end
+ function mp.InnerEdgeWidth () mpnumeric(getdimen("inneredgewidth") * factor) end
+ function mp.OuterEdgeDistance () mpnumeric(getdimen("outeredgedistance") * factor) end
+ function mp.OuterEdgeWidth () mpnumeric(getdimen("outeredgewidth") * factor) end
+ function mp.PageOffset () mpnumeric(getdimen("pagebackgroundoffset") * factor) end
+ function mp.PageDepth () mpnumeric(getdimen("pagebackgrounddepth") * factor) end
+ function mp.LayoutColumns () mpnumeric(getcount("layoutcolumns")) end
+ function mp.LayoutColumnDistance() mpnumeric(getdimen("layoutcolumndistance") * factor) end
+ function mp.LayoutColumnWidth () mpnumeric(getdimen("layoutcolumnwidth") * factor) end
+ function mp.SpineWidth () mpnumeric(getdimen("spinewidth") * factor) end
+ function mp.PaperBleed () mpnumeric(getdimen("paperbleed") * factor) end
+
+ function mp.RealPageNumber () mpnumeric(getcount("realpageno") ) end
+ function mp.LastPageNumber () mpnumeric(getcount("lastpageno") ) end
+
+ function mp.PageNumber () mpnumeric(getcount("pageno") ) end
+ function mp.NOfPages () mpnumeric(getcount("lastpageno") ) end
+
+ function mp.SubPageNumber () mpnumeric(getcount("subpageno") ) end
+ function mp.NOfSubPages () mpnumeric(getcount("lastsubpageno") ) end
+
+ function mp.CurrentColumn () mpnumeric(getcount("mofcolumns") ) end
+ function mp.NOfColumns () mpnumeric(getcount("nofcolumns") ) end
+
+ function mp.BaseLineSkip () mpnumeric(get ("baselineskip",true) * factor) end
+ function mp.LineHeight () mpnumeric(getdimen("lineheight") * factor) end
+ function mp.BodyFontSize () mpnumeric(getdimen("bodyfontsize") * factor) end
+
+ function mp.TopSkip () mpnumeric(get ("topskip",true) * factor) end
+ function mp.StrutHeight () mpnumeric(getdimen("strutht") * factor) end
+ function mp.StrutDepth () mpnumeric(getdimen("strutdp") * factor) end
+
+ function mp.PageNumber () mpnumeric(getcount("pageno") ) end
+ function mp.RealPageNumber () mpnumeric(getcount("realpageno") ) end
+ function mp.NOfPages () mpnumeric(getcount("lastpageno") ) end
+
+ function mp.CurrentWidth () mpnumeric(get ("hsize") * factor) end
+ function mp.CurrentHeight () mpnumeric(get ("vsize") * factor) end
+
+ function mp.EmWidth () mpnumeric(emwidths [false] * factor) end
+ function mp.ExHeight () mpnumeric(exheights[false] * factor) end
+
+ function mp.OverlayWidth () mpnumeric(getdimen("d_overlay_width") * factor) end
+ function mp.OverlayHeight () mpnumeric(getdimen("d_overlay_height") * factor) end
+ function mp.OverlayDepth () mpnumeric(getdimen("d_overlay_depth") * factor) end
+ function mp.OverlayLineWidth () mpnumeric(getdimen("d_overlay_linewidth") * factor) end
+ function mp.OverlayOffset () mpnumeric(getdimen("d_overlay_offset") * factor) end
+ function mp.OverlayRegion () mpstring (getmacro("m_overlay_region") ) end
+
+ function mp.PageFraction () mpnumeric(page_fraction() ) end
+ function mp.OnRightPage () mpboolean(on_right_page() ) end
+ function mp.OnOddPage () mpboolean(is_odd_page () ) end
+ function mp.InPageBody () mpboolean(in_body_page () ) end
+
+ function mp.OverlayWidth () mpnumeric(getdimen("d_overlay_width") * factor) end
+ function mp.OverlayHeight () mpnumeric(getdimen("d_overlay_height") * factor) end
+ function mp.OverlayDepth () mpnumeric(getdimen("d_overlay_depth") * factor) end
+ function mp.OverlayLineWidth () mpnumeric(getdimen("d_overlay_linewidth") * factor) end
+ function mp.OverlayOffset () mpnumeric(getdimen("d_overlay_offset") * factor) end
+ function mp.OverlayRegion () mpstring (getmacro("m_overlay_region") ) end
+ -- mp.CurrentLayout () mpstring (getmacro("currentlayout")) end
+
+ function mp.defaultcolormodel () mpnumeric(defaultcolormodel()) end
+
+ mp.HSize = mp.CurrentWidth
+ mp.VSize = mp.CurrentHeight
+ mp.LastPageNumber = mp.NOfPages
+
+ -- not much difference (10000 calls in a graphic neither as expansion seems to win
+ -- over defining the macro etc) so let's not waste counters then
+
+ -- function mp.OverlayColor()
+ -- local c = mpcolor(
+ -- getcount("c_overlay_colormodel"),
+ -- getcount("c_overlay_color"),
+ -- getcount("c_overlay_transparency")
+ -- )
+ -- mpquoted(c)
+ -- end
+ --
+ -- function mp.OverlayLineColor()
+ -- local c = mpcolor(
+ -- getcount("c_overlay_colormodel"),
+ -- getcount("c_overlay_linecolor"),
+ -- getcount("c_overlay_linetransparency")
+ -- )
+ -- mpquoted(c)
+ -- end
-function mp.mf_default_color_model()
- local colormethod = getcount("MPcolormethod")
- return mpnumeric((colormethod == 0 or colormethod == 1) and 1 or 3)
end
--- not much difference (10000 calls in a graphic neither as expansion seems to win
--- over defining the macro etc) so let's not waste counters then
-
--- function mp.OverlayColor()
--- local c = mpcolor(
--- getcount("c_overlay_colormodel"),
--- getcount("c_overlay_color"),
--- getcount("c_overlay_transparency")
--- )
--- mpquoted(c)
--- end
---
--- function mp.OverlayLineColor()
--- local c = mpcolor(
--- getcount("c_overlay_colormodel"),
--- getcount("c_overlay_linecolor"),
--- getcount("c_overlay_linetransparency")
--- )
--- mpquoted(c)
--- end
+
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mlib-lmp.lua b/Master/texmf-dist/tex/context/base/mkiv/mlib-lmp.lua
new file mode 100644
index 00000000000..402c194fe34
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/mlib-lmp.lua
@@ -0,0 +1,215 @@
+if not modules then modules = { } end modules ['mlib-lmp'] = {
+ version = 1.001,
+ comment = "companion to mlib-ctx.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+}
+
+local type = type
+
+local aux = mp.aux
+local mpnumeric = aux.numeric
+local mppair = aux.pair
+local mpquoted = aux.quoted
+local mpdirect = aux.direct
+
+-- todo: use a stack?
+
+do
+
+ local p = nil
+ local n = 0
+
+ local function mf_path_reset()
+ p = nil
+ n = 0
+ end
+
+ if CONTEXTLMTXMODE > 0 then
+
+ local scan = mp.scan
+ local scannumber = scan.number
+ local scanpath = scan.path
+
+ local function mf_path_length()
+ p = scanpath()
+ n = p and #p or 1
+ mpnumeric(n)
+ end
+
+ local function mf_path_point()
+ local i = scannumber()
+ if i > 0 and i <= n then
+ local pi = p[i]
+ mppair(pi[1],pi[2])
+ end
+ end
+
+ local function mf_path_left()
+ local i = scannumber()
+ if i > 0 and i <= n then
+ local pi = p[i]
+ mppair(pi[5],pi[6])
+ end
+ end
+
+ local function mf_path_right()
+ local i = scannumber()
+ if i > 0 and i <= n then
+ local pn
+ if i == 1 then
+ pn = p[2] or p[1]
+ else
+ pn = p[i+1] or p[1]
+ end
+ mppair(pn[3],pn[4])
+ end
+ end
+
+ local registerscript = metapost.registerscript
+
+ registerscript("pathreset", mf_path_reset)
+ registerscript("pathlengthof", mf_path_length)
+ registerscript("pathpointof", mf_path_point)
+ registerscript("pathleftof", mf_path_left)
+ registerscript("pathrightof", mf_path_right)
+
+ else
+
+ local get = mp.get
+ local mpgetpath = get.path
+
+ local function mf_path_length(name)
+ p = mpgetpath(name)
+ n = p and #p or 0
+ mpnumeric(n)
+ end
+
+ local function mf_path_point(i)
+ if i > 0 and i <= n then
+ local pi = p[i]
+ mppair(pi[1],pi[2])
+ end
+ end
+
+ local function mf_path_left(i)
+ if i > 0 and i <= n then
+ local pi = p[i]
+ mppair(pi[5],pi[6])
+ end
+ end
+
+ local function mf_path_right(i)
+ if i > 0 and i <= n then
+ local pn
+ if i == 1 then
+ pn = p[2] or p[1]
+ else
+ pn = p[i+1] or p[1]
+ end
+ mppair(pn[3],pn[4])
+ end
+ end
+
+ mp.mf_path_length = mf_path_length mp.pathlength = mf_path_length
+ mp.mf_path_point = mf_path_point mp.pathpoint = mf_path_point
+ mp.mf_path_left = mf_path_left mp.pathleft = mf_path_left
+ mp.mf_path_right = mf_path_right mp.pathright = mf_path_right
+ mp.mf_path_reset = mf_path_reset mp.pathreset = mf_path_reset
+
+ end
+
+end
+
+do
+
+ -- if needed we can optimize the sub (cache last split)
+
+ local utflen, utfsub = utf.len, utf.sub
+
+ function mp.utflen(s)
+ mpnumeric(utflen(s))
+ end
+
+ function mp.utfsub(s,f,t)
+ mpquoted(utfsub(s,f,t or f))
+ end
+
+end
+
+if CONTEXTLMTXMODE > 0 then
+
+ function mp.lmt_svg_include()
+ local labelfile = metapost.getparameter { "labelfile" }
+ if labelfile then
+ local labels = table.load(labelfile) -- todo: same path as svg file
+ if type(labels) == "table" then
+ for i=1,#labels do
+ metapost.remaptext(labels[i])
+ end
+ end
+ end
+ local fontname = metapost.getparameter { "fontname" }
+ if fontname and fontname ~= "" then
+ local unicode = metapost.getparameter { "unicode" }
+ if unicode then
+ mpdirect (
+ metapost.svgglyphtomp(fontname,math.round(unicode))
+ )
+ end
+ return
+ end
+ local filename = metapost.getparameter { "filename" }
+ if filename and filename ~= "" then
+ mpdirect ( metapost.svgtomp {
+ data = io.loaddata(filename),
+ remap = true,
+ } )
+ return
+ end
+ local buffer = metapost.getparameter { "buffer" }
+ if buffer then
+ mpdirect ( metapost.svgtomp {
+ data = buffers.getcontent(buffer),
+ -- remap = true,
+ } )
+ return
+ end
+ local code = metapost.getparameter { "code" }
+ if code then
+ mpdirect ( metapost.svgtomp {
+ data = code,
+ } )
+ return
+ end
+ end
+
+end
+
+if CONTEXTLMTXMODE > 0 then
+
+ function mp.lmt_do_remaptext()
+ local parameters = metapost.scanparameters()
+ if parameters and parameters.label then
+ metapost.remaptext(parameters)
+ end
+ end
+
+end
+
+if CONTEXTLMTXMODE > 0 then
+
+ local dropins = fonts.dropins
+ local registerglyphs = dropins.registerglyphs
+ local registerglyph = dropins.registerglyph
+
+ function mp.lmt_register_glyph()
+ registerglyph(metapost.getparameterset("mpsglyph"))
+ end
+
+ function mp.lmt_register_glyphs()
+ registerglyphs(metapost.getparameterset("mpsglyphs"))
+ end
+
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mlib-lmt.lua b/Master/texmf-dist/tex/context/base/mkiv/mlib-lmt.lua
new file mode 100644
index 00000000000..9137861a58e
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/mlib-lmt.lua
@@ -0,0 +1,63 @@
+if not modules then modules = { } end modules ['mlib-lmt'] = {
+ version = 1.001,
+ comment = "companion to mlib-ctx.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+}
+
+local mppath = mp.path
+
+local scannumeric = mp.scan.numeric
+local scanpath = mp.scan.path
+
+local getparameter = metapost.getparameter
+
+function mp.lmt_function_x(xmin,xmax,xstep,code,shape) -- experimental
+ local code = "return function(x) return " .. code .. " end"
+ local action = load(code)
+ local points = { }
+ local nofpoints = 0
+ if action then
+ action = action()
+ end
+ if shape == "steps" then
+ local halfx = xstep / 2
+ local lastx = xmin
+ local lasty = action(xmin)
+ for xi = xmin, xmax, xstep do
+ local yi = action(xi)
+ local xx = lastx + halfx
+ nofpoints = nofpoints + 1 ; points[nofpoints] = { xx, lasty }
+ nofpoints = nofpoints + 1 ; points[nofpoints] = { xx, yi }
+ lastx = xi
+ lasty = yi
+ end
+ if points[nofpoints][1] ~= xmax then
+ local yi = action(xmax)
+ local xx = lastx + halfx
+ nofpoints = nofpoints + 1 ; points[nofpoints] = { xx, lasty }
+ nofpoints = nofpoints + 1 ; points[nofpoints] = { xx, yi }
+ lastx = xi
+ lasty = yi
+ end
+ else
+ for xi = xmin, xmax, xstep do
+ nofpoints = nofpoints + 1 ; points[nofpoints] = { xi, action(xi) }
+ end
+ if points[nofpoints][1] ~= xmax then
+ nofpoints = nofpoints + 1 ; points[nofpoints] = { xmax, action(xmax) }
+ end
+ end
+ mppath(points,shape == "curve" and ".." or "--",false)
+end
+
+function mp.lmt_mesh_set()
+ local mesh = getparameter { "mesh", "paths" }
+ structures.references.currentset.mesh = mesh
+end
+
+function mp.lmt_mesh_update()
+ local mesh = getparameter { "paths" } or getparameter { "mesh", "paths" }
+ mesh[scannumeric()] = scanpath(true)
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mlib-lua.lua b/Master/texmf-dist/tex/context/base/mkiv/mlib-lua.lua
index d7c2a0fc3f2..83ce152e201 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/mlib-lua.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/mlib-lua.lua
@@ -21,19 +21,20 @@ local lpegpatterns = lpeg.patterns
local P, S, Ct, Cs, Cc, C = lpeg.P, lpeg.S, lpeg.Ct, lpeg.Cs, lpeg.Cc, lpeg.C
local report_luarun = logs.reporter("metapost","lua")
+local report_script = logs.reporter("metapost","script")
local report_message = logs.reporter("metapost")
local trace_luarun = false trackers.register("metapost.lua",function(v) trace_luarun = v end)
-local trace_enabled = true
local be_tolerant = true directives.register("metapost.lua.tolerant", function(v) be_tolerant = v end)
-local get, set, aux = { }, { }, { }
+local get, set, aux, scan = { }, { }, { }, { }
mp = mp or { -- system namespace
- set = set,
- get = get,
- aux = aux,
+ set = set,
+ get = get,
+ aux = aux,
+ scan = scan,
}
MP = MP or { -- user namespace
@@ -56,22 +57,60 @@ table.setmetatablecall(MP,function(t,k,...) return t[k](...) end)
do
- local currentmpx = nil
- local stack = { }
+ local currentmpx = nil
+ local stack = { }
+
+ if CONTEXTLMTXMODE > 0 then
+
+ local scan_next = mplib.scan_next
+ local scan_expression = mplib.scan_expression
+ local scan_token = mplib.scan_token
+ local scan_symbol = mplib.scan_symbol
+ local scan_numeric = mplib.scan_numeric
+ local scan_integer = mplib.scan_integer
+ local scan_boolean = mplib.scan_boolean
+ local scan_string = mplib.scan_string
+ local scan_pair = mplib.scan_pair
+ local scan_color = mplib.scan_color
+ local scan_cmykcolor = mplib.scan_cmykcolor
+ local scan_transform = mplib.scan_transform
+ local scan_path = mplib.scan_path
+ local scan_pen = mplib.scan_pen
+
+ scan.next = function(k) return scan_next (currentmpx,k) end
+ scan.expression = function(k) return scan_expression(currentmpx,k) end
+ scan.token = function(k) return scan_token (currentmpx,k) end
+ scan.symbol = function(k,e) return scan_symbol (currentmpx,k,e) end
+ scan.numeric = function() return scan_numeric (currentmpx) end
+ scan.number = function() return scan_numeric (currentmpx) end
+ scan.integer = function() return scan_integer (currentmpx) end
+ scan.boolean = function() return scan_boolean (currentmpx) end
+ scan.string = function() return scan_string (currentmpx) end
+ scan.pair = function(t) return scan_pair (currentmpx,t) end
+ scan.color = function(t) return scan_color (currentmpx,t) end
+ scan.cmykcolor = function(t) return scan_cmykcolor (currentmpx,t) end
+ scan.transform = function(t) return scan_transform (currentmpx,t) end
+ scan.path = function(t) return scan_path (currentmpx,t) end
+ scan.pen = function(t) return scan_pen (currentmpx,t) end
+
+ else
+
+ local get_numeric = mplib.get_numeric
+ local get_integer = mplib.get_integer
+ local get_string = mplib.get_string
+ local get_boolean = mplib.get_boolean
+ local get_path = mplib.get_path
+ local set_path = mplib.set_path
+
+ get.numeric = function(s) return get_numeric(currentmpx,s) end
+ get.number = function(s) return get_numeric(currentmpx,s) end
+ get.integer = function(s) return get_integer(currentmpx,s) end
+ get.string = function(s) return get_string (currentmpx,s) end
+ get.boolean = function(s) return get_boolean(currentmpx,s) end
+ get.path = function(s) return get_path (currentmpx,s) end
+ set.path = function(s,t) return set_path (currentmpx,s,t) end -- not working yet
- local get_numeric = mplib.get_numeric
- local get_string = mplib.get_string
- local get_boolean = mplib.get_boolean
- local get_path = mplib.get_path
- local set_path = mplib.set_path
-
- get.numeric = function(s) return get_numeric(currentmpx,s) end
- get.string = function(s) return get_string (currentmpx,s) end
- get.boolean = function(s) return get_boolean(currentmpx,s) end
- get.path = function(s) return get_path (currentmpx,s) end
- get.number = function(s) return get_numeric(currentmpx,s) end
-
- set.path = function(s,t) return set_path(currentmpx,s,t) end -- not working yet
+ end
function metapost.pushscriptrunner(mpx)
insert(stack,mpx)
@@ -82,55 +121,36 @@ do
currentmpx = remove(stack,mpx)
end
-end
-
-do
+ function metapost.currentmpx()
+ return currentmpx
+ end
- local buffer = { }
- local n = 0
- local max = 20 -- we reuse upto max
- local nesting = 0
- local runs = 0
+ local status = mplib.status
- local function _f_()
- if trace_enabled and trace_luarun then
- local result = concat(buffer," ",1,n)
- if n > max then
- buffer = { }
- end
- n = 0
- report_luarun("%i: data: %s",nesting,result)
- return result
- else
- if n == 0 then
- return ""
- end
- local result
- if n == 1 then
- result = buffer[1]
- else
- result = concat(buffer," ",1,n)
- end
- if n > max then
- buffer = { }
- end
- n = 0
- return result
- end
+ function metapost.currentmpxstatus()
+ return status and status(currentmpx) or 0
end
- mp._f_ = _f_ -- convenient to have it in a top module
- aux.flush = _f_
+end
+
+do
- ----- f_code = formatters["%s return mp._f_()"]
+ -- serializers
local f_integer = formatters["%i"]
+ local f_numeric = formatters["%F"]
- local f_numeric = formatters["%n"] -- maybe %N
- local f_pair = formatters["(%n,%n)"]
- local f_ctrl = formatters["(%n,%n) .. controls (%n,%n) and (%n,%n)"]
- local f_triplet = formatters["(%n,%n,%n)"]
- local f_quadruple = formatters["(%n,%n,%n,%n)"]
+ -- no %n as that can produce -e notation and that is not so nice for scaled butmaybe we
+ -- should then switch between ... i.e. make a push/pop for the formatters here ... not now.
+
+ local f_integer = formatters["%i"]
+ local f_numeric = formatters["%F"]
+ local f_pair = formatters["(%F,%F)"]
+ local f_ctrl = formatters["(%F,%F) .. controls (%F,%F) and (%F,%F)"]
+ local f_triplet = formatters["(%F,%F,%F)"]
+ local f_quadruple = formatters["(%F,%F,%F,%F)"]
+ local f_transform = formatters["totransform(%F,%F,%F,%F,%F,%F)"]
+ local f_pen = formatters["(pencircle transformed totransform(%F,%F,%F,%F,%F,%F))"]
local f_points = formatters["%p"]
local f_pair_pt = formatters["(%p,%p)"]
@@ -148,24 +168,183 @@ do
mp.cleaned = function(s) return lpegmatch(p,s) or s end
- -- local function mpprint(...) -- we can optimize for n=1
- -- for i=1,select("#",...) do
- -- local value = (select(i,...))
- -- if value ~= nil then
- -- n = n + 1
- -- local t = type(value)
- -- if t == "number" then
- -- buffer[n] = f_numeric(value)
- -- elseif t == "string" then
- -- buffer[n] = value
- -- elseif t == "table" then
- -- buffer[n] = "(" .. concat(value,",") .. ")"
- -- else -- boolean or whatever
- -- buffer[n] = tostring(value)
- -- end
- -- end
- -- end
- -- end
+ -- management
+
+ -- sometimes we gain (e.g. .5 sec on the sync test)
+
+ local cache = table.makeweak()
+
+ local runscripts = { }
+ local runnames = { }
+ local nofscripts = 0
+
+ function metapost.registerscript(name,f)
+ nofscripts = nofscripts + 1
+ if f then
+ runscripts[nofscripts] = f
+ runnames[name] = nofscripts
+ else
+ runscripts[nofscripts] = name
+ end
+ return nofscripts
+ end
+
+ function metapost.scriptindex(name)
+ return runnames[name] or 0
+ end
+
+ -- The gbuffer sharing and such is not really needed now but make a dent when
+ -- we have a high volume of simpel calls (loops) so we keep it around for a
+ -- while.
+
+ local nesting = 0
+ local runs = 0
+ local gbuffer = { }
+ local buffer = gbuffer
+ local n = 0
+
+ local function mpdirect1(a)
+ n = n + 1 buffer[n] = a
+ end
+ local function mpdirect2(a,b)
+ n = n + 1 buffer[n] = a
+ n = n + 1 buffer[n] = b
+ end
+ local function mpdirect3(a,b,c)
+ n = n + 1 buffer[n] = a
+ n = n + 1 buffer[n] = b
+ n = n + 1 buffer[n] = c
+ end
+ local function mpdirect4(a,b,c,d)
+ n = n + 1 buffer[n] = a
+ n = n + 1 buffer[n] = b
+ n = n + 1 buffer[n] = c
+ n = n + 1 buffer[n] = d
+ end
+ local function mpdirect5(a,b,c,d,e)
+ n = n + 1 buffer[n] = a
+ n = n + 1 buffer[n] = b
+ n = n + 1 buffer[n] = c
+ n = n + 1 buffer[n] = d
+ n = n + 1 buffer[n] = e
+ end
+
+ local function mpflush(separator)
+ buffer[1] = concat(buffer,separator or "",1,n)
+ n = 1
+ end
+
+ function metapost.runscript(code)
+ nesting = nesting + 1
+ runs = runs + 1
+
+ local index = type(code) == "number"
+ local f
+ local result
+
+ if index then
+ f = runscripts[code]
+ if not f then
+ report_luarun("%i: bad index: %s",nesting,code)
+ elseif trace_luarun then
+ report_luarun("%i: index: %i",nesting,code)
+ end
+ else
+ if trace_luarun then
+ report_luarun("%i: code: %s",nesting,code)
+ end
+ f = cache[code]
+ if not f then
+ f = loadstring("return " .. code)
+ if f then
+ cache[code] = f
+ elseif be_tolerant then
+ f = loadstring(code)
+ if f then
+ cache[code] = f
+ end
+ end
+ end
+ end
+
+ -- returning nil is more efficient and a signal not to scan in mp
+
+ if f then
+
+ local lbuffer, ln
+
+ if nesting == 1 then
+ buffer = gbuffer
+ n = 0
+ else
+ lbuffer = buffer
+ ln = n
+ buffer = { }
+ n = 0
+ end
+
+ result = f()
+
+ if result then
+ local t = type(result)
+ if t == "number" then
+ result = f_numeric(result)
+ elseif t == "table" then
+ result = concat(result) -- no spaces here
+ else
+ result = tostring(result)
+ end
+ if trace_luarun then
+ report_luarun("%i: %s result: %s",nesting,t,result)
+ end
+ elseif n == 0 then
+ result = ""
+ if trace_luarun then
+ report_luarun("%i: no buffered result",nesting)
+ end
+ elseif n == 1 then
+ result = buffer[1]
+ if trace_luarun then
+ report_luarun("%i: 1 buffered result: %s",nesting,result)
+ end
+ else
+ -- the space is why we sometimes have collectors
+ if nesting == 1 then
+ result = concat(buffer," ",1,n)
+ if n > 500 or #result > 10000 then
+ gbuffer = { } -- newtable(20,0)
+ lbuffer = gbuffer
+ end
+ else
+ result = concat(buffer," ")
+ end
+ if trace_luarun then
+ report_luarun("%i: %i buffered results: %s",nesting,n,result)
+ end
+ end
+
+ if nesting == 1 then
+ n = 0
+ else
+ buffer = lbuffer
+ n = ln
+ end
+
+ else
+ report_luarun("%i: no result, invalid code: %s",nesting,code)
+ result = ""
+ end
+
+ nesting = nesting - 1
+
+ return result
+ end
+
+ function metapost.nofscriptruns()
+ return runs
+ end
+
+ -- writers
local function mpp(value)
n = n + 1
@@ -175,7 +354,11 @@ do
elseif t == "string" then
buffer[n] = value
elseif t == "table" then
- buffer[n] = "(" .. concat(value,",") .. ")"
+ if #t == 6 then
+ buffer[n] = "totransform(" .. concat(value,",") .. ")"
+ else
+ buffer[n] = "(" .. concat(value,",") .. ")"
+ end
else -- boolean or whatever
buffer[n] = tostring(value)
end
@@ -317,6 +500,37 @@ do
end
end
+ local function mptransform(x,y,xx,xy,yx,yy)
+ n = n + 1
+ if type(x) == "table" then
+ buffer[n] = f_transform(x[1],x[2],x[3],x[4],x[5],x[6])
+ else
+ buffer[n] = f_transform(x,y,xx,xy,yx,yy)
+ end
+ end
+
+ local function mpcolor(c,m,y,k)
+ n = n + 1
+ if type(c) == "table" then
+ local l = #c
+ if l == 4 then
+ buffer[n] = f_quadruple(c[1],c[2],c[3],c[4])
+ elseif l == 3 then
+ buffer[n] = f_triplet(c[1],c[2],c[3])
+ else
+ buffer[n] = f_numeric(c[1])
+ end
+ else
+ if k then
+ buffer[n] = f_quadruple(c,m,y,k)
+ elseif y then
+ buffer[n] = f_triplet(c,m,y)
+ else
+ buffer[n] = f_numeric(c)
+ end
+ end
+ end
+
-- we have three kind of connectors:
--
-- .. ... -- (true)
@@ -326,7 +540,12 @@ do
local tn = #t
if tn == 1 then
local t1 = t[1]
- n = n + 1 ; buffer[n] = f2(t1[1],t1[2])
+ n = n + 1
+ if t.pen then
+ buffer[n] = f_pen(unpack(t1))
+ else
+ buffer[n] = f2(t1[1],t1[2])
+ end
elseif tn > 0 then
if connector == true or connector == nil then
connector = ".."
@@ -344,6 +563,8 @@ do
local a = t[1]
local b = t[2]
n = n + 1
+ buffer[n] = "("
+ n = n + 1
if six and #a == 6 and #b == 6 then
buffer[n] = f6(a[1],a[2],a[5],a[6],b[3],b[4])
controls = ".."
@@ -385,6 +606,8 @@ do
else
buffer[n] = f2(a[1],a[2])
end
+ n = n + 1
+ buffer[n] = ")"
end
end
end
@@ -429,6 +652,13 @@ do
end
end
+ aux.direct = mpdirect1
+ aux.direct1 = mpdirect1
+ aux.direct2 = mpdirect2
+ aux.direct3 = mpdirect3
+ aux.direct4 = mpdirect4
+ aux.flush = mpflush
+
aux.print = mpprint
aux.vprint = mpvprint
aux.boolean = mpboolean
@@ -448,72 +678,77 @@ do
aux.size = mpsize
aux.fprint = mpfprint
aux.quoted = mpquoted
+ aux.transform = mptransform
+ aux.color = mpcolor
- -- we need access to the variables
-
- function metapost.nofscriptruns()
- return runs
- end
-
- -- sometimes we gain (e.g. .5 sec on the sync test)
-
- local cache = table.makeweak()
+ -- for the moment
- function metapost.runscript(code)
- nesting = nesting + 1
- local trace = trace_enabled and trace_luarun
- if trace then
- report_luarun("%i: code: %s",nesting,code)
- end
- runs = runs + 1
- local f = cache[code]
- if not f then
- f = loadstring(code .. " return mp._f_()")
- if f then
- cache[code] = f
- elseif be_tolerant then
- f = loadstring(code)
- if f then
- cache[code] = f
+ local function mpdraw(lines,list) -- n * 4
+ if list then
+ local c = #lines
+ for i=1,c do
+ local ci = lines[i]
+ local ni = #ci
+ n = n + 1 buffer[n] = i < c and "d(" or "D("
+ for j=1,ni,2 do
+ local l = j + 1
+ n = n + 1 buffer[n] = ci[j]
+ n = n + 1 buffer[n] = ","
+ n = n + 1 buffer[n] = ci[l]
+ n = n + 1 buffer[n] = l < ni and ")--(" or ");"
end
end
+ else
+ local l = #lines
+ local m = l - 4
+ for i=1,l,4 do
+ n = n + 1 buffer[n] = i < m and "d(" or "D("
+ n = n + 1 buffer[n] = lines[i]
+ n = n + 1 buffer[n] = ","
+ n = n + 1 buffer[n] = lines[i+1]
+ n = n + 1 buffer[n] = ")--("
+ n = n + 1 buffer[n] = lines[i+2]
+ n = n + 1 buffer[n] = ","
+ n = n + 1 buffer[n] = lines[i+3]
+ n = n + 1 buffer[n] = ");"
+ end
end
- if f then
- local _buffer_ = buffer
- local _n_ = n
- buffer = { }
- n = 0
- local result = f()
- if result then
- local t = type(result)
- if t == "number" then
- result = f_numeric(result)
- elseif t ~= "string" then
- result = tostring(result)
- end
- if trace then
- if #result == 0 then
- report_luarun("%i: no result",nesting)
- else
- report_luarun("%i: result: %s",nesting,result)
- end
+ end
+
+ local function mpfill(lines,list)
+ if list then
+ local c = #lines
+ for i=1,c do
+ local ci = lines[i]
+ local ni = #ci
+ n = n + 1 buffer[n] = i < c and "f(" or "F("
+ for j=1,ni,2 do
+ local l = j + 1
+ n = n + 1 buffer[n] = ci[j]
+ n = n + 1 buffer[n] = ","
+ n = n + 1 buffer[n] = ci[l]
+ n = n + 1 buffer[n] = l < ni and ")--(" or ")--C;"
end
- buffer = _buffer_
- n = _n_
- nesting = nesting - 1
- return result
- elseif trace then
- report_luarun("%i: no result",nesting)
end
- buffer, n = _buffer_, _n_
else
- report_luarun("%i: no result, invalid code: %s",nesting,code)
+ local l = #lines
+ local m = l - 4
+ for i=1,l,4 do
+ n = n + 1 buffer[n] = i < m and "f(" or "F("
+ n = n + 1 buffer[n] = lines[i]
+ n = n + 1 buffer[n] = ","
+ n = n + 1 buffer[n] = lines[i+1]
+ n = n + 1 buffer[n] = ")--("
+ n = n + 1 buffer[n] = lines[i+2]
+ n = n + 1 buffer[n] = ","
+ n = n + 1 buffer[n] = lines[i+3]
+ n = n + 1 buffer[n] = ")--C;"
+ end
end
- nesting = nesting - 1
- return ""
end
- -- for the moment
+ aux.draw = mpdraw
+ aux.fill = mpfill
for k, v in next, aux do mp[k] = v end
@@ -521,13 +756,46 @@ end
do
+ -- Another experimental feature:
+
+ local mpnumeric = mp.numeric
+ local scanstring = scan.string
+ local scriptindex = metapost.scriptindex
+
+ function mp.mf_script_index(name)
+ local index = scriptindex(name)
+ -- report_script("method %i, name %a, index %i",1,name,index)
+ mpnumeric(index)
+ end
+
+ -- once bootstrapped ... (needs pushed mpx instances)
+
+ metapost.registerscript("scriptindex",function()
+ local name = scanstring()
+ local index = scriptindex(name)
+ -- report_script("method %i, name %a, index %i",2,name,index)
+ mpnumeric(index)
+ end)
+
+end
+
+-- the next will move to mlib-lmp.lua
+
+do
+
local mpnamedcolor = attributes.colors.mpnamedcolor
local mpprint = aux.print
+ local scanstring = scan.string
mp.mf_named_color = function(str)
mpprint(mpnamedcolor(str))
end
+ metapost.registerscript("namedcolor",function()
+ mpprint(mpnamedcolor(scanstring()))
+-- test: return mpnamedcolor(scanstring())
+ end)
+
end
function mp.n(t) -- used ?
@@ -773,15 +1041,16 @@ end
do
- local mprint = mp.print
- local fprint = mp.fprint
- local qprint = mp.quoted
- local getwhd = job.positions.whd
- local getxy = job.positions.xy
- local getposition = job.positions.position
- local getpage = job.positions.page
- local getregion = job.positions.region
- local getmacro = tokens.getters.macro
+ local mprint = mp.print
+ local fprint = mp.fprint
+ local qprint = mp.quoted
+ local jobpositions = job.positions
+ local getwhd = jobpositions.whd
+ local getxy = jobpositions.xy
+ local getposition = jobpositions.position
+ local getpage = jobpositions.page
+ local getregion = jobpositions.region
+ local getmacro = tokens.getters.macro
function mp.positionpath(name)
local w, h, d = getwhd(name)
@@ -820,12 +1089,7 @@ do
end
function mp.positionpage(name)
- local p = getpage(name)
- if p then
- fprint("%p",p)
- else
- mprint("0")
- end
+ fprint("%i",getpage(name) or 0)
end
function mp.positionregion(name)
@@ -961,6 +1225,8 @@ end
do
-- a bit overkill: just a find(str,"mf_object=") can be enough
+ --
+ -- todo : share with mlib-pps.lua metapost,isobject
local mpboolean = aux.boolean
@@ -974,56 +1240,71 @@ do
end
-do
-
- local mpnumeric = aux.numeric
- local mppair = aux.pair
- local mpgetpath = get.path
-
- local p = nil
- local n = 0
-
- local function mf_path_length(name)
- p = mpgetpath(name)
- n = p and #p or 0
- mpnumeric(n)
- end
-
- local function mf_path_point(i)
- if i > 0 and i <= n then
- local pi = p[i]
- mppair(pi[1],pi[2])
+function mp.flatten(t)
+ local tn = #t
+
+ local t1 = t[1]
+ local t2 = t[2]
+ local t3 = t[3]
+ local t4 = t[4]
+
+ for i=1,tn-5,2 do
+ local t5 = t[i+4]
+ local t6 = t[i+5]
+ if t1 == t3 and t3 == t5 and ((t2 <= t4 and t4 <= t6) or (t6 <= t4 and t4 <= t2)) then
+ t[i+3] = t2
+ t4 = t2
+ t[i] = false
+ t[i+1] = false
+ elseif t2 == t4 and t4 == t6 and ((t1 <= t3 and t3 <= t5) or (t5 <= t3 and t3 <= t1)) then
+ t[i+2] = t1
+ t3 = t1
+ t[i] = false
+ t[i+1] = false
end
+ t1 = t3
+ t2 = t4
+ t3 = t5
+ t4 = t6
end
- local function mf_path_left(i)
- if i > 0 and i <= n then
- local pi = p[i]
- mppair(pi[5],pi[6])
+ -- remove duplicates
+
+ local t1 = t[1]
+ local t2 = t[2]
+ for i=1,tn-2,2 do
+ local t3 = t[i+2]
+ local t4 = t[i+3]
+ if t1 == t3 and t2 == t4 then
+ t[i] = false
+ t[i+1] = false
end
+ t1 = t3
+ t2 = t4
end
- local function mf_path_right(i)
- if i > 0 and i <= n then
- local pn
- if i == 1 then
- pn = p[2] or p[1]
- else
- pn = p[i+1] or p[1]
- end
- mppair(pn[3],pn[4])
+ -- move coordinates
+
+ local m = 0
+ for i=1,tn,2 do
+ if t[i] then
+ m = m + 1 t[m] = t[i]
+ m = m + 1 t[m] = t[i+1]
end
end
- local function mf_path_reset()
- p = nil
- n = 0
+ -- prune the table (not gc'd)
+
+ for i=tn,m+1,-1 do
+ t[i] = nil
end
- mp.mf_path_length = mf_path_length mp.pathlength = mf_path_length
- mp.mf_path_point = mf_path_point mp.pathpoint = mf_path_point
- mp.mf_path_left = mf_path_left mp.pathleft = mf_path_left
- mp.mf_path_right = mf_path_right mp.pathright = mf_path_right
- mp.mf_path_reset = mf_path_reset mp.pathreset = mf_path_reset
+ -- safeguard so that we have at least one segment
+
+ if m == 2 then
+ t[3] = t[1]
+ t[4] = t[2]
+ end
end
+
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mlib-mat.lua b/Master/texmf-dist/tex/context/base/mkiv/mlib-mat.lua
new file mode 100644
index 00000000000..6c82a4658b5
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/mlib-mat.lua
@@ -0,0 +1,137 @@
+if not modules then modules = { } end modules ['mlib-mat'] = {
+ version = 1.001,
+ comment = "companion to mlib-ctx.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+}
+
+local scanners = mp.scan
+local registerscript = metapost.registerscript
+
+local scannumeric = scanners.numeric
+local scanpair = scanners.pair
+local scancolor = scanners.color
+
+local mppair = mp.pair
+
+local m = xmath
+local c = xcomplex
+
+local m_acos = m.acos registerscript("m_acos", function() return m_acos (scannumeric()) end)
+local m_acosh = m.acosh registerscript("m_acosh", function() return m_acosh (scannumeric()) end)
+local m_asin = m.asin registerscript("m_asin", function() return m_asin (scannumeric()) end)
+local m_asinh = m.asinh registerscript("m_asinh", function() return m_asinh (scannumeric()) end)
+local m_atan = m.atan registerscript("m_atan", function() return m_atan (scannumeric()) end)
+local m_atan2 = m.atan2 registerscript("m_atan2", function() return m_atan2 (scanpair ()) end)
+local m_atanh = m.atanh registerscript("m_atanh", function() return m_atanh (scannumeric()) end)
+local m_cbrt = m.cbrt registerscript("m_cbrt", function() return m_cbrt (scannumeric()) end)
+local m_ceil = m.ceil registerscript("m_ceil", function() return m_ceil (scannumeric()) end)
+local m_copysign = m.copysign registerscript("m_copysign", function() return m_copysign (scanpair ()) end)
+local m_cos = m.cos registerscript("m_cos", function() return m_cos (scannumeric()) end)
+local m_cosh = m.cosh registerscript("m_cosh", function() return m_cosh (scannumeric()) end)
+local m_deg = m.deg registerscript("m_deg", function() return m_deg (scannumeric()) end)
+local m_erf = m.erf registerscript("m_erf", function() return m_erf (scannumeric()) end)
+local m_erfc = m.erfc registerscript("m_erfc", function() return m_erfc (scannumeric()) end)
+local m_exp = m.exp registerscript("m_exp", function() return m_exp (scannumeric()) end)
+local m_exp2 = m.exp2 registerscript("m_exp2", function() return m_exp2 (scannumeric()) end)
+local m_expm1 = m.expm1 registerscript("m_expm1", function() return m_expm1 (scannumeric()) end)
+local m_fabs = m.fabs registerscript("m_fabs", function() return m_fabs (scannumeric()) end)
+local m_fdim = m.fdim registerscript("m_fdim", function() return m_fdim (scanpair ()) end)
+local m_floor = m.floor registerscript("m_floor", function() return m_floor (scannumeric()) end)
+local m_fma = m.fma registerscript("m_fma", function() return m_fma (scancolor ()) end)
+local m_fmax = m.fmax registerscript("m_fmax", function() return m_fmax (scannumeric()) end)
+local m_fmin = m.fmin registerscript("m_fmin", function() return m_fmin (scannumeric()) end)
+local m_fmod = m.fmod registerscript("m_fmod", function() return m_fmod (scanpair ()) end)
+local m_frexp = m.frexp registerscript("m_frexp", function() return m_frexp (scannumeric()) end)
+local m_gamma = m.gamma registerscript("m_gamma", function() return m_gamma (scannumeric()) end)
+local m_hypot = m.hypot registerscript("m_hypot", function() return m_hypot (scanpair ()) end)
+local m_isfinite = m.isfinite registerscript("m_isfinite", function() return m_isfinite (scannumeric()) end)
+local m_isinf = m.isinf registerscript("m_isinf", function() return m_isinf (scannumeric()) end)
+local m_isnan = m.isnan registerscript("m_isnan", function() return m_isnan (scannumeric()) end)
+local m_isnormal = m.isnormal registerscript("m_isnormal", function() return m_isnormal (scannumeric()) end)
+local m_j0 = m.j0 registerscript("m_j0", function() return m_j0 (scannumeric()) end)
+local m_j1 = m.j1 registerscript("m_j1", function() return m_j1 (scannumeric()) end)
+local m_jn = m.jn registerscript("m_jn", function() return m_jn (scanpair ()) end)
+local m_ldexp = m.ldexp registerscript("m_ldexp", function() return m_ldexp (scanpair ()) end)
+local m_lgamma = m.lgamma registerscript("m_lgamma", function() return m_lgamma (scannumeric()) end)
+local m_log = m.log registerscript("m_log", function() return m_log (scannumeric()) end)
+local m_log10 = m.log10 registerscript("m_log10", function() return m_log10 (scannumeric()) end)
+local m_log1p = m.log1p registerscript("m_log1p", function() return m_log1p (scannumeric()) end)
+local m_log2 = m.log2 registerscript("m_log2", function() return m_log2 (scannumeric()) end)
+local m_logb = m.logb registerscript("m_logb", function() return m_logb (scannumeric()) end)
+local m_modf = m.modf registerscript("m_modf", function() return m_modf (scannumeric()) end)
+local m_nearbyint = m.nearbyint registerscript("m_nearbyint", function() return m_nearbyint(scannumeric()) end)
+local m_nextafter = m.nextafter registerscript("m_nextafter", function() return m_nextafter(scanpair ()) end)
+local m_pow = m.pow registerscript("m_pow", function() return m_pow (scanpair ()) end)
+local m_rad = m.rad registerscript("m_rad", function() return m_rad (scannumeric()) end)
+local m_remainder = m.remainder registerscript("m_remainder", function() return m_remainder(scanpair ()) end)
+local m_remquo = m.remquo registerscript("m_remquo", function() return m_remquo (scannumeric()) end)
+local m_round = m.round registerscript("m_round", function() return m_round (scannumeric()) end)
+local m_scalbn = m.scalbn registerscript("m_scalbn", function() return m_scalbn (scanpair ()) end)
+local m_sin = m.sin registerscript("m_sin", function() return m_sin (scannumeric()) end)
+local m_sinh = m.sinh registerscript("m_sinh", function() return m_sinh (scannumeric()) end)
+local m_sqrt = m.sqrt registerscript("m_sqrt", function() return m_sqrt (scannumeric()) end)
+local m_tan = m.tan registerscript("m_tan", function() return m_tan (scannumeric()) end)
+local m_tanh = m.tanh registerscript("m_tanh", function() return m_tanh (scannumeric()) end)
+local m_tgamma = m.tgamma registerscript("m_tgamma", function() return m_tgamma (scannumeric()) end)
+local m_trunc = m.trunc registerscript("m_trunc", function() return m_trunc (scannumeric()) end)
+local m_y0 = m.y0 registerscript("m_y0", function() return m_y0 (scannumeric()) end)
+local m_y1 = m.y1 registerscript("m_y1", function() return m_y1 (scannumeric()) end)
+local m_yn = m.yn registerscript("m_yn", function() return m_yn (scanpair ()) end)
+
+if not (c and c.sin) then
+ return
+end
+
+local c_topair = c.topair
+local c_new = c.new
+
+local c_sin = c.sin registerscript("c_sin", function() return mppair(c_topair(c_sin (c_new(scanpair())))) end)
+local c_cos = c.cos registerscript("c_cos", function() return mppair(c_topair(c_cos (c_new(scanpair())))) end)
+local c_tan = c.tan registerscript("c_tan", function() return mppair(c_topair(c_tan (c_new(scanpair())))) end)
+local c_sinh = c.sinh registerscript("c_sinh", function() return mppair(c_topair(c_sinh (c_new(scanpair())))) end)
+local c_cosh = c.cosh registerscript("c_cosh", function() return mppair(c_topair(c_cosh (c_new(scanpair())))) end)
+local c_tanh = c.tanh registerscript("c_tanh", function() return mppair(c_topair(c_tanh (c_new(scanpair())))) end)
+
+local c_asin = c.asin registerscript("c_asin", function() return mppair(c_topair(c_sin (c_new(scanpair())))) end)
+local c_acos = c.acos registerscript("c_acos", function() return mppair(c_topair(c_cos (c_new(scanpair())))) end)
+local c_atan = c.atan registerscript("c_atan", function() return mppair(c_topair(c_tan (c_new(scanpair())))) end)
+local c_asinh = c.asinh registerscript("c_asinh", function() return mppair(c_topair(c_sinh (c_new(scanpair())))) end)
+local c_acosh = c.acosh registerscript("c_acosh", function() return mppair(c_topair(c_cosh (c_new(scanpair())))) end)
+local c_atanh = c.atanh registerscript("c_atanh", function() return mppair(c_topair(c_tanh (c_new(scanpair())))) end)
+
+local c_sqrt = c.sqrt registerscript("c_sqrt", function() return mppair(c_topair(c_sqrt (c_new(scanpair())))) end)
+local c_abs = c.abs registerscript("c_abs", function() return c_topair(c_abs (c_new(scanpair()))) end)
+local c_arg = c.arg registerscript("c_arg", function() return c_topair(c_arg (c_new(scanpair()))) end)
+local c_conj = c.conj registerscript("c_conj", function() return mppair(c_topair(c_conj (c_new(scanpair())))) end)
+local c_exp = c.exp registerscript("c_exp", function() return mppair(c_topair(c_exp (c_new(scanpair())))) end)
+local c_log = c.log registerscript("c_log", function() return mppair(c_topair(c_log (c_new(scanpair())))) end)
+local c_proj = c.proj registerscript("c_proj", function() return mppair(c_topair(c_proj (c_new(scanpair())))) end)
+
+local c_erf = c.erf registerscript("c_erf", function() return mppair(c_topair(c_erf (c_new(scanpair())))) end)
+local c_erfc = c.erfc registerscript("c_erfc", function() return mppair(c_topair(c_erfc (c_new(scanpair())))) end)
+local c_erfcx = c.erfcx registerscript("c_erfcx", function() return mppair(c_topair(c_erfcx (c_new(scanpair())))) end)
+local c_erfi = c.erfi registerscript("c_erfi", function() return mppair(c_topair(c_erfi (c_new(scanpair())))) end)
+local c_dawson = c.dawson registerscript("c_dawson", function() return mppair(c_topair(c_dawson(c_new(scanpair())))) end)
+
+local c_voigt = c.voigt
+local c_voigt_hwhm = c.voigt_hwhm
+
+registerscript("c_voigt", function()
+ return mppair(c_topair(c_voigt(c_new(scanpair()),c_new(scanpair()),c_new(scanpair()))))
+end)
+
+registerscript("c_voigt_hwhm", function()
+ return mppair(c_topair(c_voigt_hwhm(c_new(scanpair()),c_new(scanpair()))))
+end)
+
+local c_pow = c.pow registerscript("c_pow", function() return mppair(c_topair(c_pow(c_new(scanpair()),c_new(scanpair())))) end)
+local c_add = c.add registerscript("c_add", function() return mppair(c_topair(c_add(c_new(scanpair()),c_new(scanpair())))) end)
+local c_sub = c.sub registerscript("c_sub", function() return mppair(c_topair(c_sub(c_new(scanpair()),c_new(scanpair())))) end)
+local c_mul = c.mul registerscript("c_mul", function() return mppair(c_topair(c_mul(c_new(scanpair()),c_new(scanpair())))) end)
+local c_div = c.div registerscript("c_div", function() return mppair(c_topair(c_div(c_new(scanpair()),c_new(scanpair())))) end)
+
+local c_imag = c.imag registerscript("c_imag", function() return c_topair(c_imag(c_new(scanpair()))) end)
+local c_real = c.real registerscript("c_real", function() return c_topair(c_real(c_new(scanpair()))) end)
+local c_neg = c.neg registerscript("c_new", function() return c_topair(c_neg (c_new(scanpair()))) end)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mlib-pdf.lua b/Master/texmf-dist/tex/context/base/mkiv/mlib-pdf.lua
index 92fde5e1369..372a77f4181 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/mlib-pdf.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/mlib-pdf.lua
@@ -45,29 +45,16 @@ local experiment = true -- uses context(node) that already does delayed nod
local savedliterals = nil -- needs checking
local mpsliteral = nodes.pool.originliteral
-local f_f = formatters["%.6F"]
-local f_m = formatters["%.6F %.6F m"]
-local f_c = formatters["%.6F %.6F %.6F %.6F %.6F %.6F c"]
-local f_l = formatters["%.6F %.6F l"]
-local f_cm = formatters["%.6F %.6F %.6F %.6F %.6F %.6F cm"]
-local f_M = formatters["%.6F M"]
+local f_f = formatters["%.6N"]
+local f_m = formatters["%.6N %.6N m"]
+local f_c = formatters["%.6N %.6N %.6N %.6N %.6N %.6N c"]
+local f_l = formatters["%.6N %.6N l"]
+local f_cm = formatters["%.6N %.6N %.6N %.6N %.6N %.6N cm"]
+local f_M = formatters["%.6N M"]
local f_j = formatters["%i j"]
local f_J = formatters["%i J"]
-local f_d = formatters["[%s] %.6F d"]
-local f_w = formatters["%.3F w"]
-
-directives.register("metapost.stripzeros",function()
- f_f = formatters["%.6N"]
- f_m = formatters["%.6N %.6N m"]
- f_c = formatters["%.6N %.6N %.6N %.6N %.6N %.6N c"]
- f_l = formatters["%.6N %.6N l"]
- f_cm = formatters["%.6N %.6N %.6N %.6N %.6N %.6N cm"]
- f_M = formatters["%.6N M"]
- f_j = formatters["%i j"]
- f_J = formatters["%i J"]
- f_d = formatters["[%s] %.6N d"]
- f_w = formatters["%.3N w"]
-end)
+local f_d = formatters["[%s] %.6N d"]
+local f_w = formatters["%.6N w"]
directives.register("metapost.savetable",function(v)
if type(v) == "string" then
@@ -274,6 +261,34 @@ local function flushconcatpath(path, t, open)
return t
end
+local function toboundingbox(path)
+ local size = #path
+ if size == 4 then
+ local pth = path[1]
+ local x = pth.x_coord
+ local y = pth.y_coord
+ local llx, lly, urx, ury = x, y, x, y
+ for i=2,size do
+ pth = path[i]
+ x = pth.x_coord
+ y = pth.y_coord
+ if x < llx then
+ llx = x
+ elseif x > urx then
+ urx = x
+ end
+ if y < lly then
+ lly = y
+ elseif y > ury then
+ ury = y
+ end
+ end
+ return { llx, lly, urx, ury }
+ else
+ return { 0, 0, 0, 0 }
+ end
+end
+
metapost.flushnormalpath = flushnormalpath
-- The flusher is pdf based, if another backend is used, we need to overload the
@@ -283,8 +298,10 @@ metapost.flushnormalpath = flushnormalpath
-- We can avoid the before table but I like symmetry. There is of course a small
-- performance penalty, but so is passing extra arguments (result, flusher, after)
-- and returning stuff.
+--
+-- This variable stuff will change in lmtx.
-local ignore = function () end
+local ignore = function() end
local space = P(" ")
local equal = P("=")
@@ -380,10 +397,10 @@ function metapost.flush(specification,result)
local figures = result.fig
if figures then
flusher = flusher or pdfflusher
- local resetplugins = metapost.resetplugins or ignore -- before figure
- local processplugins = metapost.processplugins or ignore -- each object
+ local resetplugins = metapost.resetplugins or ignore -- before figure
+ local processplugins = metapost.processplugins or ignore -- each object
local synchronizeplugins = metapost.synchronizeplugins or ignore
- local pluginactions = metapost.pluginactions or ignore -- before / after
+ local pluginactions = metapost.pluginactions or ignore -- before / after
local startfigure = flusher.startfigure
local stopfigure = flusher.stopfigure
local flushfigure = flusher.flushfigure
@@ -400,6 +417,7 @@ function metapost.flush(specification,result)
local linecap = -1
local linejoin = -1
local dashed = false
+ local linewidth = false
local llx = properties.llx
local lly = properties.lly
local urx = properties.urx
@@ -412,6 +430,8 @@ function metapost.flush(specification,result)
-- we need to be indirect if we want the one-pass solution
+ local groupstack = { }
+
local function processfigure()
result[#result+1] = "q"
if objects then
@@ -443,6 +463,35 @@ function metapost.flush(specification,result)
miterlimit, linecap, linejoin, dashed = -1, -1, -1, "" -- was false
elseif objecttype == "start_bounds" or objecttype == "stop_bounds" then
-- skip
+ elseif objecttype == "start_group" then
+ if lpdf.flushgroup then
+ local before, after = processplugins(object)
+ if before then
+ result[#result+1] = "q"
+ result = pluginactions(before,result,flushfigure)
+ insert(groupstack, {
+ after = after,
+ result = result,
+ bbox = toboundingbox(object.path),
+ })
+ result = { }
+miterlimit, linecap, linejoin, dashed, linewidth = -1, -1, -1, "", false
+ else
+ insert(groupstack,false)
+ end
+ else
+ insert(groupstack,false)
+ end
+ elseif objecttype == "stop_group" then
+ local data = remove(groupstack)
+ if data then
+ local reference = lpdf.flushgroup(concat(result,"\r"),data.bbox)
+ result = data.result
+ result[#result+1] = reference
+ result = pluginactions(data.after,result,flushfigure)
+ result[#result+1] = "Q"
+miterlimit, linecap, linejoin, dashed, linewidth = -1, -1, -1, "", false
+ end
else
-- we use an indirect table as we want to overload
-- entries but this is not possible in userdata
@@ -450,7 +499,7 @@ function metapost.flush(specification,result)
-- can be optimized if no path
--
local original = object
- local object = { }
+ local object = { }
setmetatable(object, {
__index = original
})
@@ -459,12 +508,15 @@ function metapost.flush(specification,result)
local evenodd = false
local collect = false
local both = false
+ local flush = false
local postscript = object.postscript
if not object.istext then
if postscript == "evenodd" then
evenodd = true
elseif postscript == "collect" then
collect = true
+ elseif postscript == "flush" then
+ flush = true
elseif postscript == "both" then
both = true
elseif postscript == "eoboth" then
@@ -473,7 +525,9 @@ function metapost.flush(specification,result)
end
end
--
- if collect then
+ if flush and not savedpath then
+ -- forget about it
+ elseif collect then
if not savedpath then
savedpath = { object.path or false }
savedhtap = { object.htap or false }
@@ -527,7 +581,10 @@ function metapost.flush(specification,result)
if pen then
if pen.type == "elliptical" then
transformed, penwidth = pen_characteristics(original) -- boolean, value
- result[#result+1] = f_w(penwidth) -- todo: only if changed
+ if penwidth ~= linewidth then
+ result[#result+1] = f_w(penwidth)
+ linewidth = penwidth
+ end
if objecttype == "fill" then
objecttype = "both"
end
@@ -550,7 +607,9 @@ function metapost.flush(specification,result)
end
savedpath = nil
end
- if transformed then
+ if flush then
+ -- ignore this path
+ elseif transformed then
flushconcatpath(path,result,open)
else
flushnormalpath(path,result,open)
@@ -613,7 +672,7 @@ function metapost.flush(specification,result)
end
if object.grouped then
-- can be qQ'd so changes can end up in groups
- miterlimit, linecap, linejoin, dashed = -1, -1, -1, "" -- was false
+ miterlimit, linecap, linejoin, dashed, linewidth = -1, -1, -1, "", false
end
end
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mlib-pdf.mkiv b/Master/texmf-dist/tex/context/base/mkiv/mlib-pdf.mkiv
index 6dc73a15352..d251a5145a9 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/mlib-pdf.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/mlib-pdf.mkiv
@@ -13,13 +13,12 @@
\unprotect
-% We use bit more code that needed because we want to limit the
-% amount of boxing.
+%D We use bit more code that needed because we want to limit the amount of boxing.
\registerctxluafile{mlib-pdf}{}
-%D Some code is shared between MPLIB and MPS. The following variables
-%D are also available for introspection and other purposes.
+%D Some code is shared between MPLIB and MPS. The following variables are also
+%D available for introspection and other purposes.
\ifdefined\MPwidth \else \newdimen\MPwidth \fi
\ifdefined\MPheight \else \newdimen\MPheight \fi
@@ -88,16 +87,6 @@
\wd\MPbox\MPwidth
\ht\MPbox\MPheight}
-% \unexpanded\def\MPtextext#1#2#3#4#5% beware: we use a different method now (see mlib-pps)
-% {\begingroup
-% \setbox\MPbox\hbox{\font\temp=#1\space at #2\onebasepoint \let\c\char \temp #3}% text
-% \MPllx-#4\onebasepoint
-% \MPlly-#5\onebasepoint
-% \repositionMPbox
-% \smashbox\MPbox
-% \box\MPbox
-% \endgroup}
-
% MPLIB specific:
\def\MPLIBtoPDF{\clf_mpflushliteral} % expanded
@@ -146,30 +135,6 @@
\unexpanded\def\directMPgraphic
{\dodoublegroupempty\mlib_direct_graphic}
-% \def\mlib_direct_graphic#1#2% makes pages (todo: make boxes)
-% {\meta_begin_graphic_group{#1}%
-% \let\startMPLIBtoPDF\directstartMPLIBtoPDF
-% \let\stopMPLIBtoPDF \directstopMPLIBtoPDF
-% \meta_start_current_graphic
-% \forgetall
-% \edef\p_extensions{\MPinstanceparameter\s!extensions}%
-% \normalexpanded{\noexpand\ctxlua{metapost.graphic {
-% instance = "\currentMPinstance",
-% format = "\currentMPformat",
-% data = \!!bs#2;\!!es,
-% initializations = \!!bs\meta_flush_current_initializations\!!es,
-% % useextensions = "\MPinstanceparameter\s!extensions",
-% \ifx\p_extensions\v!yes
-% extensions = \!!bs\clf_getmpextensions{\currentMPinstance}\!!es,
-% \fi
-% inclusions = \!!bs\meta_flush_current_inclusions\!!es,
-% definitions = \!!bs\meta_flush_current_definitions\!!es,
-% figure = "all",
-% method = "\MPinstanceparameter\c!method",
-% }}}%
-% \meta_stop_current_graphic
-% \meta_end_graphic_group}
-
\def\mlib_direct_graphic#1#2% makes pages (todo: make boxes)
{\meta_begin_graphic_group{#1}%
\let\startMPLIBtoPDF\directstartMPLIBtoPDF
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mlib-pdf.mkxl b/Master/texmf-dist/tex/context/base/mkiv/mlib-pdf.mkxl
new file mode 100644
index 00000000000..763e7ecdd46
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/mlib-pdf.mkxl
@@ -0,0 +1,171 @@
+%D \module
+%D [ file=mlib-pdf,
+%D version=2008.03.25,
+%D title=\METAPOST\ Integrated Graphics,
+%D subtitle=Conversion to PDF,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\unprotect
+
+%D We use bit more code that needed because we want to limit the amount of boxing.
+
+\registerctxluafile{mlib-pdf}{}
+
+%D Some code is shared between MPLIB and MPS. The following variables are also
+%D available for introspection and other purposes.
+
+\ifdefined\MPwidth \else \newdimen\MPwidth \fi
+\ifdefined\MPheight \else \newdimen\MPheight \fi
+
+\ifdefined\MPllx \else \newdimen\MPllx \fi
+\ifdefined\MPlly \else \newdimen\MPlly \fi
+\ifdefined\MPurx \else \newdimen\MPurx \fi
+\ifdefined\MPury \else \newdimen\MPury \fi
+
+\ifdefined\MPbox \else \newbox \MPbox \fi
+
+\unexpanded\def\setMPboundingbox#1#2#3#4% at some point we might pass them as base or scaled points
+ {\global\MPllx #1\onebasepoint
+ \global\MPlly #2\onebasepoint
+ \global\MPurx #3\onebasepoint
+ \global\MPury #4\onebasepoint
+ \global\MPwidth \dimexpr\MPurx-\MPllx\relax
+ \global\MPheight\dimexpr\MPury-\MPlly\relax}
+
+\unexpanded\def\resetMPboundingbox
+ {\global\MPwidth \zeropoint
+ \global\MPheight\zeropoint
+ \global\MPllx \zeropoint
+ \global\MPlly \zeropoint
+ \global\MPurx \zeropoint
+ \global\MPury \zeropoint}
+
+\let\popMPboundingbox\relax
+
+\unexpanded\def\pushMPboundingbox
+ {\edef\popMPboundingbox
+ {\global\MPwidth \the\MPwidth
+ \global\MPheight\the\MPheight
+ \global\MPllx \the\MPllx
+ \global\MPlly \the\MPlly
+ \global\MPurx \the\MPurx
+ \global\MPury \the\MPury
+ \relax}}
+
+% we need to combine these
+
+\unexpanded\def\repositionMPboxindeed
+ {\setbox\MPbox\hpack\bgroup
+ \kern-\MPllx
+ \raise-\MPlly
+ \box\MPbox
+ \egroup}
+
+\unexpanded\def\repositionMPbox
+ {\ifzeropt\MPllx
+ \ifzeropt\MPlly
+ % okay
+ \else
+ \repositionMPboxindeed
+ \fi
+ \else
+ \repositionMPboxindeed
+ \fi}
+
+\unexpanded\def\finalizeMPbox
+ {\repositionMPbox
+ \setbox\MPbox\vpack to \MPheight\bgroup
+ \vfill
+ \hsize\MPwidth
+ \smashbox\MPbox
+ \box\MPbox
+ \egroup
+ \wd\MPbox\MPwidth
+ \ht\MPbox\MPheight}
+
+% combined
+
+\unexpanded\def\finalizeMPbox
+ {\boxxoffset\MPbox-\MPllx\relax
+ \boxyoffset\MPbox\dimexpr\boxyoffset\MPbox-\MPheight-\MPlly\relax
+ \wd\MPbox\MPwidth
+ \ht\MPbox\MPheight}
+
+% MPLIB specific:
+
+\def\MPLIBtoPDF{\clf_mpflushliteral} % expanded
+
+\unexpanded\def\startMPLIBtoPDF#1#2#3#4%
+ {\meta_process_graphic_figure_start
+ \dostarttagged\t!mpgraphic\empty
+ \naturalhpack attr \imageattribute \plusone \bgroup
+ \dousecolorparameter\s!black\forcecolorhack
+ \setMPboundingbox{#1}{#2}{#3}{#4}%
+ \setbox\MPbox\vpack\bgroup
+ % \forgetall % already done elsewhere
+ \noindent} % forces the proper cm in the backend
+
+\unexpanded\def\stopMPLIBtoPDF
+ {\egroup
+ \finalizeMPbox
+ \box\MPbox
+ \egroup
+ \dostoptagged
+ \meta_process_graphic_figure_stop}
+
+\def\MPLIBflushreset % This can (will) move to the Lua end.
+ {\clf_mpflushreset}
+
+%D Kind of special:
+%
+% test.mp:
+%
+% beginfig(1) fill fullcircle scaled 10cm withcolor red ; endfig ;
+% beginfig(2) draw fullcircle scaled 5cm withcolor blue ; endfig ;
+% beginfig(3) draw textext("just some text") ; endfig ;
+%
+% standalone pages:
+%
+% \starttext
+% \directMPgraphic{input "test.mp" ;}
+% \stoptext
+
+\let\normalstartMPLIBtoPDF\startMPLIBtoPDF
+\let\normalstopMPLIBtoPDF \stopMPLIBtoPDF
+
+\unexpanded\def\directstartMPLIBtoPDF{\startTEXpage\normalstartMPLIBtoPDF}
+\unexpanded\def\directstopMPLIBtoPDF {\normalstopMPLIBtoPDF\stopTEXpage}
+
+\unexpanded\def\directMPgraphic
+ {\dodoublegroupempty\mlib_direct_graphic}
+
+\def\mlib_direct_graphic#1#2% makes pages (todo: make boxes)
+ {\meta_begin_graphic_group{#1}%
+ \let\startMPLIBtoPDF\directstartMPLIBtoPDF
+ \let\stopMPLIBtoPDF \directstopMPLIBtoPDF
+ \meta_start_current_graphic
+ \forgetall
+ \edef\p_extensions{\MPinstanceparameter\s!extensions}%
+ \normalexpanded{\noexpand\clf_mpgraphic
+ instance {\currentMPinstance}%
+ format {\currentMPformat}%
+ data {#2;}%
+ initializations {\meta_flush_current_initializations}%
+ \ifx\p_extensions\v!yes
+ extensions {\clf_getmpextensions{\currentMPinstance}}%
+ \fi
+ inclusions {\meta_flush_current_inclusions}%
+ definitions {\meta_flush_current_definitions}%
+ figure {all}%
+ method {\MPinstanceparameter\c!method}%
+ \relax}%
+ \meta_stop_current_graphic
+ \meta_end_graphic_group}
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mlib-pps.lua b/Master/texmf-dist/tex/context/base/mkiv/mlib-pps.lua
index 5708577fea6..0250df35c60 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/mlib-pps.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/mlib-pps.lua
@@ -30,6 +30,8 @@ local flush_list = node.flush_list
local setmetatableindex = table.setmetatableindex
local sortedhash = table.sortedhash
+local new_hlist = nodes.pool.hlist
+
local starttiming = statistics.starttiming
local stoptiming = statistics.stoptiming
@@ -92,28 +94,18 @@ end
-- todo: get this from the lpdf module
-local f_f = formatters["%F"]
-local f_f3 = formatters["%.3F"]
-local f_gray = formatters["%.3F g %.3F G"]
-local f_rgb = formatters["%.3F %.3F %.3F rg %.3F %.3F %.3F RG"]
-local f_cmyk = formatters["%.3F %.3F %.3F %.3F k %.3F %.3F %.3F %.3F K"]
-local f_cm_b = formatters["q %.6F %.6F %.6F %.6F %.6F %.6F cm"]
-local f_scn = formatters["%.3F"]
+local f_f = formatters["%.6N"]
+local f_f3 = formatters["%.3N"]
+local f_gray = formatters["%.3N g %.3N G"]
+local f_rgb = formatters["%.3N %.3N %.3N rg %.3N %.3N %.3N RG"]
+local f_cmyk = formatters["%.3N %.3N %.3N %.3N k %.3N %.3N %.3N %.3N K"]
+local f_cm_b = formatters["q %.6N %.6N %.6N %.6N %.6N %.6N cm"]
+local f_scn = formatters["%.3N"]
local f_shade = formatters["MpSh%s"]
local f_spot = formatters["/%s cs /%s CS %s SCN %s scn"]
local s_cm_e = "Q"
-directives.register("metapost.stripzeros",function()
- f_f = formatters["%N"]
- f_f3 = formatters["%.3N"]
- f_gray = formatters["%.3N g %.3N G"]
- f_rgb = formatters["%.3N %.3N %.3N rg %.3N %.3N %.3N RG"]
- f_cmyk = formatters["%.3N %.3N %.3N %.3N k %.3N %.3N %.3N %.3N K"]
- f_cm_b = formatters["q %.6N %.6N %.6N %.6N %.6N %.6N cm"]
- f_scn = formatters["%.3N"]
-end)
-
local function checked_color_pair(color,...)
if not color then
return innercolor, outercolor
@@ -253,14 +245,18 @@ local function preset(t,k)
return v
end
-local function startjob(plugmode,kind)
+local function startjob(plugmode,kind,mpx)
insert(stack,top)
top = {
textexts = { }, -- all boxes, optionally with a different color
texstrings = { },
+ mapstrings = { },
+ mapindices = { },
+ mapmoves = { },
texlast = 0,
texdata = setmetatableindex({},preset), -- references to textexts in order or usage
plugmode = plugmode, -- some day we can then skip all pre/postscripts
+ extradata = mpx and metapost.getextradata(mpx),
}
if trace_runs then
report_metapost("starting %s run at level %i in %s mode",
@@ -441,7 +437,7 @@ function models.cmyk(cr)
local y = cr[3]
local k = cr[4]
if c == m and m == y and y == 0 then
- k = k - 1
+ k = 1 - k
return checked_color_pair(f_gray,k,k)
else
return checked_color_pair(f_cmyk,c,m,y,k,c,m,y,k)
@@ -456,7 +452,11 @@ function models.cmyk(cr)
local y = cr[3]
local k = cr[4]
if n == 3 then
- c, m, y, k = rgbtocmyk(c,m,y)
+ if c == m and m == y then
+ k, c, m, y = 1 - c, 0, 0, 0
+ else
+ c, m, y, k = rgbtocmyk(c,m,y)
+ end
end
return checked_color_pair(f_cmyk,c,m,y,k,c,m,y,k)
end
@@ -580,8 +580,8 @@ end
-- side effect of going single pass).
function metapost.graphic_base_pass(specification)
- local top = startjob(true,"base")
local mpx = specification.mpx -- mandate
+ local top = startjob(true,"base",mpx)
local data = specification.data or ""
local inclusions = specification.inclusions or ""
local initializations = specification.initializations or ""
@@ -629,7 +629,7 @@ function metapost.process(specification,...)
if type(specification) ~= "table" then
oldschool(specification,...)
else
- startjob(specification.incontext or specification.useplugins,"process")
+ startjob(specification.incontext or specification.useplugins,"process",false)
runmetapost(specification)
stopjob()
end
@@ -690,7 +690,7 @@ metapost.splitprescript = splitprescript
-- end
function metapost.pluginactions(what,t,flushfigure) -- before/after object, depending on what
- if top.plugmode then -- hm, what about other features
+ if top and top.plugmode then -- hm, what about other features
for i=1,#what do
local wi = what[i]
if type(wi) == "function" then
@@ -707,19 +707,19 @@ function metapost.pluginactions(what,t,flushfigure) -- before/after object, depe
end
function metapost.resetplugins(t) -- intialize plugins, before figure
- if top.plugmode then
+ if top and top.plugmode then
outercolormodel = colors.currentmodel() -- currently overloads the one set at the tex end
resetteractions.runner(t)
end
end
function metapost.processplugins(object) -- each object (second pass)
- if top.plugmode then
+ if top and top.plugmode then
local prescript = object.prescript -- specifications
if prescript and #prescript > 0 then
local before = { }
local after = { }
- processoractions.runner(object,splitprescript(prescript) or {},before,after)
+ processoractions.runner(object,splitprescript(prescript) or { },before,after)
return #before > 0 and before, #after > 0 and after
else
local c = object.color
@@ -791,21 +791,12 @@ local tx_reset, tx_process do
----- pat = tsplitat(":")
local pat = lpeg.tsplitter(":",tonumber) -- so that %F can do its work
- local f_gray_yes = formatters["s=%.3F,a=%i,t=%.3F"]
- local f_gray_nop = formatters["s=%.3F"]
- local f_rgb_yes = formatters["r=%.3F,g=%.3F,b=%.3F,a=%.3F,t=%.3F"]
- local f_rgb_nop = formatters["r=%.3F,g=%.3F,b=%.3F"]
- local f_cmyk_yes = formatters["c=%.3F,m=%.3F,y=%.3F,k=%.3F,a=%.3F,t=%.3F"]
- local f_cmyk_nop = formatters["c=%.3F,m=%.3F,y=%.3F,k=%.3F"]
-
- directives.register("metapost.stripzeros",function()
- f_gray_yes = formatters["s=%.3N,a=%i,t=%.3N"]
- f_gray_nop = formatters["s=%.3N"]
- f_rgb_yes = formatters["r=%.3N,g=%.3N,b=%.3N,a=%.3N,t=%.3N"]
- f_rgb_nop = formatters["r=%.3N,g=%.3N,b=%.3N"]
- f_cmyk_yes = formatters["c=%.3N,m=%.3N,y=%.3N,k=%.3N,a=%.3N,t=%.3N"]
- f_cmyk_nop = formatters["c=%.3N,m=%.3N,y=%.3N,k=%.3N"]
- end)
+ local f_gray_yes = formatters["s=%.3N,a=%i,t=%.3N"]
+ local f_gray_nop = formatters["s=%.3N"]
+ local f_rgb_yes = formatters["r=%.3N,g=%.3N,b=%.3N,a=%.3N,t=%.3N"]
+ local f_rgb_nop = formatters["r=%.3N,g=%.3N,b=%.3N"]
+ local f_cmyk_yes = formatters["c=%.3N,m=%.3N,y=%.3N,k=%.3N,a=%.3N,t=%.3N"]
+ local f_cmyk_nop = formatters["c=%.3N,m=%.3N,y=%.3N,k=%.3N"]
local ctx_MPLIBsetNtext = context.MPLIBsetNtextX
local ctx_MPLIBsetCtext = context.MPLIBsetCtextX
@@ -833,7 +824,7 @@ local tx_reset, tx_process do
end
elseif #mp_c == 3 then
if mp_a and mp_t then
- ctx_MPLIBsetCtext(mp_target,f_rgb_nop(mp_c[1],mp_c[2],mp_c[3],mp_a,mp_t),mp_text)
+ ctx_MPLIBsetCtext(mp_target,f_rgb_yes(mp_c[1],mp_c[2],mp_c[3],mp_a,mp_t),mp_text)
else
ctx_MPLIBsetCtext(mp_target,f_rgb_nop(mp_c[1],mp_c[2],mp_c[3]),mp_text)
end
@@ -849,6 +840,8 @@ local tx_reset, tx_process do
end
end
+ local madetext = nil
+
function mp.mf_some_text(index,str)
mp_target = index
mp_index = index
@@ -863,24 +856,132 @@ local tx_reset, tx_process do
madetext = nil
end
- local madetext = nil
-
function mp.mf_made_text(index)
mp.mf_some_text(index,madetext)
end
+ -- a label can be anything, also something mp doesn't like in strings
+ -- so we return an index instead
+
+ function metapost.processing()
+ return top and true or false
+ end
+
+ function metapost.remaptext(replacement)
+ if top then
+ local mapstrings = top.mapstrings
+ local mapindices = top.mapindices
+ local label = replacement.label
+ local index = 0
+ if label then
+ local found = mapstrings[label]
+ if found then
+ setmetatableindex(found,replacement)
+ index = found.index
+ else
+ index = #mapindices + 1
+ replacement.index = index
+ mapindices[index] = replacement
+ mapstrings[label] = replacement
+ end
+ end
+ return index
+ else
+ return 0
+ end
+ end
+
+ function metapost.remappedtext(what)
+ return top and (top.mapstrings[what] or top.mapindices[tonumber(what)])
+ end
+
+ function mp.mf_map_move(index)
+ mp.triplet(top.mapmoves[index])
+ end
+
+ function mp.mf_map_text(index,str)
+ local map = top.mapindices[tonumber(str)]
+ if type(map) == "table" then
+ local text = map.text
+ local overload = map.overload
+ local offset = 0
+ local width = 0
+ local where = nil
+ --
+ mp_index = index
+ -- the image text
+ if overload then
+ top.texstrings[mp_index] = map.template or map.label or "error"
+ tex.runtoks("mptexttoks")
+ local box = textakebox("mptextbox") or new_hlist()
+ width = bp * box.width
+ where = overload.where
+ end
+ -- the real text
+ top.texstrings[mp_index] = overload and overload.text or text or "error"
+ tex.runtoks("mptexttoks")
+ local box = textakebox("mptextbox") or new_hlist()
+ local twd = bp * box.width
+ local tht = bp * box.height
+ local tdp = bp * box.depth
+ -- the check
+ if where then
+ local scale = 1 -- / (map.scale or 1)
+ if where == "l" or where == "left" then
+ offset = scale * (twd - width)
+ elseif where == "m" or where == "middle" then
+ offset = scale * (twd - width) / 2
+ end
+ end
+ -- the result
+ top.textexts[mp_index] = box
+ top.mapmoves[mp_index] = { offset, map.dx or 0, map.dy or 0 }
+ --
+ mp.triplet(twd,tht,tdp)
+ madetext = nil
+ return
+ else
+ map = type(map) == "string" and map or str
+ return mp.mf_some_text(index,context.escape(map) or map)
+ end
+ end
+
+ -- This is a bit messy. In regular metapost it's a kind of immediate replacement
+ -- so embedded btex ... etex is not really working as one would expect. We now have
+ -- a mix: it's immediate when we are at the outer level (rawmadetext) and indirect
+ -- (with the danger of stuff that doesn't work well in strings) when we are for
+ -- instance in a macro definition (rawtextext (pass back string)) ... of course one
+ -- should use textext so this is just a catch. When not in lmtx it's never immediate.
+
+ local reported = false
+ local awayswrap = CONTEXTLMTXMODE <= 1
+
function metapost.maketext(s,mode)
+ if not reported then
+ reported = true
+ report_metapost("use 'textext(.....)' instead of 'btex ..... etex'")
+ end
if mode and mode == 1 then
if trace_btexetex then
report_metapost("ignoring verbatimtex: [[%s]]",s)
end
+ elseif alwayswrap then
+ if trace_btexetex then
+ report_metapost("rewrapping btex ... etex [[%s]]",s)
+ end
+ return 'rawtextext("' .. gsub(s,'"','"&ditto&"') .. '")' -- nullpicture
+ elseif metapost.currentmpxstatus() ~= 0 then
+ if trace_btexetex then
+ report_metapost("rewrapping btex ... etex at the outer level [[%s]]",s)
+ end
+ return 'rawtextext("' .. gsub(s,'"','"&ditto&"') .. '")' -- nullpicture
else
if trace_btexetex then
report_metapost("handling btex ... etex: [[%s]]",s)
end
-- madetext = utilities.strings.collapse(s)
madetext = s
- return "rawmadetext"
+ return "rawmadetext" -- is assuming immediate processing
end
end
@@ -910,7 +1011,7 @@ local tx_reset, tx_process do
end
tx_process = function(object,prescript,before,after)
- local data = top.texdata[metapost.properties.number]
+ local data = top.texdata[metapost.properties.number] -- the current figure number, messy
local index = tonumber(prescript.tx_index)
if index then
if trace_textexts then
@@ -932,19 +1033,45 @@ local tx_reset, tx_process do
top.texlast = mp_target
--
local mp_text = top.texstrings[mp_index]
+ local mp_hash = prescript.tx_cache
local box
- if prescript.tx_cache == "no" then
+ if mp_hash == "no" then
tex.runtoks("mptexttoks")
box = textakebox("mptextbox")
else
- local hash = fmt(mp_text,mp_a or "-",mp_t or "-",mp_c or "-")
- box = data.texhash[hash]
+ local cache = data.texhash
+ if mp_hash then
+ mp_hash = tonumber(mp_hash)
+ end
+ if mp_hash then
+ local extradata = top.extradata
+ if extradata then
+ cache = extradata.globalcache
+ if not cache then
+ cache = { }
+ extradata.globalcache = cache
+ end
+ if trace_runs then
+ if cache[mp_hash] then
+ report_textexts("reusing global entry %i",mp_hash)
+ else
+ report_textexts("storing global entry %i",mp_hash)
+ end
+ end
+ else
+ mp_hash = nil
+ end
+ end
+ if not mp_hash then
+ mp_hash = fmt(mp_text,mp_a or "-",mp_t or "-",mp_c or "-")
+ end
+ box = cache[mp_hash]
if box then
box = copy_list(box)
else
tex.runtoks("mptexttoks")
box = textakebox("mptextbox")
- data.texhash[hash] = box
+ cache[mp_hash] = box
end
end
top.textexts[mp_target] = box
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mlib-run.lua b/Master/texmf-dist/tex/context/base/mkiv/mlib-run.lua
index 09872ef0fb7..07fa6a19198 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/mlib-run.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/mlib-run.lua
@@ -6,8 +6,6 @@ if not modules then modules = { } end modules ['mlib-run'] = {
license = "see context related readme files",
}
--- todo mpx :execute -> mlib.execute(mpx,)
-
-- cmyk -> done, native
-- spot -> done, but needs reworking (simpler)
-- multitone ->
@@ -32,7 +30,7 @@ nears zero.</p>
--ldx]]--
local type, tostring, tonumber, next = type, tostring, tonumber, next
-local striplines = utilities.strings.striplines
+local find, striplines = string.find, utilities.strings.striplines
local concat, insert, remove = table.concat, table.insert, table.remove
local emptystring = string.is_empty
@@ -40,8 +38,10 @@ local P = lpeg.P
local trace_graphics = false trackers.register("metapost.graphics", function(v) trace_graphics = v end)
local trace_tracingall = false trackers.register("metapost.tracingall", function(v) trace_tracingall = v end)
+local trace_terminal = false trackers.register("metapost.terminal", function(v) trace_terminal = v end)
local report_metapost = logs.reporter("metapost")
+local report_terminal = logs.reporter("metapost","terminal")
local texerrormessage = logs.texerrormessage
local starttiming = statistics.starttiming
@@ -55,11 +55,55 @@ local metapost = metapost
metapost.showlog = false
metapost.lastlog = ""
-metapost.collapse = true -- currently mplib cannot deal with begingroup/endgroup mismatch in stepwise processing
metapost.texerrors = false
metapost.exectime = metapost.exectime or { } -- hack
+metapost.nofruns = 0
+
+local mpxformats = { }
+local mpxterminals = { }
+local nofformats = 0
+local mpxpreambles = { }
+local mpxextradata = { }
+
+-- The flatten hack is needed because the library currently barks on \n\n and the
+-- collapse because mp cannot handle snippets due to grouping issues.
+
+-- todo: pass tables to executempx instead of preparing beforehand,
+-- as it's more efficient for the terminal
+
+local function flatten(source,target)
+ for i=1,#source do
+ local d = source[i]
+ if type(d) == "table" then
+ flatten(d,target)
+ elseif d and d ~= "" then
+ target[#target+1] = d
+ end
+ end
+ return target
+end
+
+local function prepareddata(data)
+ if data and data ~= "" then
+ if type(data) == "table" then
+ data = flatten(data,{ })
+ data = #data > 1 and concat(data,"\n") or data[1]
+ end
+ return data
+ end
+end
--- metapost.collapse = false
+local function executempx(mpx,data)
+ local terminal = mpxterminals[mpx]
+ if terminal then
+ terminal.writer(data)
+ data = ""
+ elseif type(data) == "table" then
+ data = prepareddata(data,collapse)
+ end
+ metapost.nofruns = metapost.nofruns + 1
+ return mpx:execute(data)
+end
directives.register("mplib.texerrors", function(v) metapost.texerrors = v end)
trackers.register ("metapost.showlog", function(v) metapost.showlog = v end)
@@ -77,7 +121,7 @@ local mpbasepath = lpeg.instringchecker(P("/metapost/") * (P("context") + P("bas
-- for some reason mp sometimes calls this function twice which is inefficient
-- but we cannot catch this
-do
+local realtimelogging do
local finders = { }
mplib.finders = finders -- also used in meta-lua.lua
@@ -85,12 +129,10 @@ do
local new_instance = mplib.new
local function validftype(ftype)
- if ftype == "" then
- -- whatever
- elseif ftype == 0 then
- -- mplib bug
+ if ftype == "mp" then
+ return "mp"
else
- return ftype
+ return nil
end
end
@@ -98,6 +140,8 @@ do
return resolvers.findfile(name,validftype(ftype))
end
+ -- this will be redone in lmtx
+
local function i_finder(name,mode,ftype) -- fake message for mpost.map and metafun.mpvi
local specification = url.hashed(name)
local finder = finders[specification.scheme] or finders.file
@@ -115,9 +159,172 @@ do
return (mode == "w" and o_finder or i_finder)(name,mode,validftype(ftype))
end
- function mplib.new(specification)
- specification.find_file = finder -- so we block an overload
- return new_instance(specification)
+ local report_logger = logs.reporter("metapost log")
+ local report_error = logs.reporter("metapost error")
+
+ local l, nl, dl = { }, 0, false
+ local t, nt, dt = { }, 0, false
+ local e, ne, de = { }, 0, false
+
+ local function logger(target,str)
+ if target == 1 then
+ -- log
+ elseif target == 2 or target == 3 then
+ -- term
+ if str == "\n" then
+ realtimelogging = true
+ if nl > 0 then
+ report_logger(concat(l,"",1,nl))
+ nl, dl = 0, false
+ elseif not dl then
+ report_logger("")
+ dl = true
+ end
+ else
+ nl = nl + 1
+ l[nl] = str
+ end
+ elseif target == 4 then
+ report_error(str)
+ end
+ end
+
+ -- experiment, todo: per instance, just a push / pop ?
+
+ local findtexfile = resolvers.findtexfile
+ local opentexfile = resolvers.opentexfile
+ local splitlines = string.splitlines
+
+ local function writetoterminal(terminaldata,maxterm,d)
+ local t = type(d)
+ local n = 0
+ if t == "string" then
+ d = splitlines(d)
+ n = #d
+ for i=1,#d do
+ maxterm = maxterm + 1
+ terminaldata[maxterm] = d[i]
+ end
+ elseif t == "table" then
+ for i=1,#d do
+ local l = d[i]
+ if find(l,"[\n\r]") then
+ local s = splitlines(l)
+ local m = #s
+ for i=1,m do
+ maxterm = maxterm + 1
+ terminaldata[maxterm] = s[i]
+ end
+ n = n + m
+ else
+ maxterm = maxterm + 1
+ terminaldata[maxterm] = d[i]
+ n = 1
+ end
+ end
+ end
+ if trace_terminal then
+ report_metapost("writing %i lines, in cache %s",n,maxterm)
+ end
+ return maxterm
+ end
+
+ local function readfromterminal(terminaldata,maxterm,nowterm)
+ if nowterm >= maxterm then
+ terminaldata[nowterm] = false
+ maxterm = 0
+ nowterm = 0
+ if trace_terminal then
+ report_metapost("resetting, maxcache %i",#terminaldata)
+ end
+ return maxterm, nowterm, nil
+ else
+ if nowterm > 0 then
+ terminaldata[nowterm] = false
+ end
+ nowterm = nowterm + 1
+ local s = terminaldata[nowterm]
+ if trace_terminal then
+ report_metapost("reading line %i: %s",nowterm,s)
+ end
+ return maxterm, nowterm, s
+ end
+ end
+
+ local function fileopener()
+
+ -- these can go into the table itself
+
+ local terminaldata = { }
+ local maxterm = 0
+ local nowterm = 0
+
+ local terminal = {
+ name = "terminal",
+ close = function()
+ -- terminal = { }
+ -- maxterm = 0
+ -- nowterm = 0
+ end,
+ reader = function()
+ local line
+ maxterm, nowterm, line = readfromterminal(terminaldata,maxterm,nowterm)
+ return line
+ end,
+ writer = function(d)
+ maxterm = writetoterminal(terminaldata,maxterm,d)
+ end,
+ }
+
+ return function(name,mode,kind)
+ if name == "terminal" then
+ -- report_metapost("opening terminal")
+ return terminal
+ elseif mode == "w" then
+ local f = io.open(name,"wb")
+ if f then
+ -- report_metapost("opening file %a for writing",full)
+ return {
+ name = full,
+ writer = function(s) return f:write(s) end, -- io.write(f,s)
+ close = function() f:close() end,
+ }
+ end
+ else
+ local full = findtexfile(name,validftype(ftype))
+ if full then
+ -- report_metapost("opening file %a for reading",full)
+ return opentexfile(full)
+ end
+ end
+ end
+
+ end
+
+ -- end of experiment
+
+ if CONTEXTLMTXMODE > 0 then
+
+ function mplib.new(specification)
+ local openfile = fileopener()
+ specification.find_file = finder
+ specification.run_logger = logger
+ specification.open_file = openfile
+ specification.interaction = "silent"
+ specification.halt_on_error = true
+ local instance = new_instance(specification)
+ mpxterminals[instance] = openfile("terminal")
+ return instance
+ end
+
+ else
+
+ function mplib.new(specification)
+ specification.find_file = finder
+ specification.run_logger = logger
+ return new_instance(specification)
+ end
+
end
mplib.finder = finder
@@ -130,7 +337,12 @@ local find_file = mplib.finder
function metapost.reporterror(result)
if not result then
report_metapost("error: no result object returned")
- elseif result.status > 0 then
+ return true
+ elseif result.status == 0 then
+ return false
+ elseif realtimelogging then
+ return false -- we already reported
+ else
local t = result.term
local e = result.error
local l = result.log
@@ -150,10 +362,8 @@ function metapost.reporterror(result)
else
report_metapost("error: unknown, no error, terminal or log messages")
end
- else
- return false
+ return true
end
- return true
end
local f_preamble = formatters [ [[
@@ -173,7 +383,7 @@ local methods = {
}
function metapost.runscript(code)
- return code
+ return ""
end
function metapost.scripterror(str)
@@ -203,13 +413,17 @@ function metapost.load(name,method)
make_text = metapost.maketext,
extensions = 1,
-- random_seed = seed,
+ utf8_mode = true,
}
report_metapost("initializing number mode %a",method)
local result
if not mpx then
result = { status = 99, error = "out of memory"}
else
- result = mpx:execute(f_preamble(file.addsuffix(name,"mp"),seed)) -- addsuffix is redundant
+ -- pushing permits advanced features
+ metapost.pushscriptrunner(mpx)
+ result = executempx(mpx,f_preamble(file.addsuffix(name,"mp"),seed))
+ metapost.popscriptrunner()
end
stoptiming(mplib)
metapost.reporterror(result)
@@ -222,8 +436,11 @@ function metapost.checkformat(mpsinput,method)
if file.suffix(mpsinput) ~= "" then
foundfile = find_file(mpsinput) or ""
end
- if foundfile == "" then
- foundfile = find_file(file.replacesuffix(mpsinput,"mpvi")) or ""
+ -- if foundfile == "" then
+ -- foundfile = find_file(file.replacesuffix(mpsinput,"mpvi")) or ""
+ -- end
+ if CONTEXTLMTXMODE > 0 and foundfile == "" then
+ foundfile = find_file(file.replacesuffix(mpsinput,"mpxl")) or ""
end
if foundfile == "" then
foundfile = find_file(file.replacesuffix(mpsinput,"mpiv")) or ""
@@ -253,40 +470,13 @@ function metapost.unload(mpx)
stoptiming(mplib)
end
--- The flatten hack is needed because the library currently barks on \n\n and the
--- collapse because mp cannot handle snippets due to grouping issues.
-
-local function flatten(source,target)
- for i=1,#source do
- local d = source[i]
- if type(d) == "table" then
- flatten(d,target)
- elseif d and d ~= "" then
- target[#target+1] = d
- end
- end
- return target
-end
-
-local function prepareddata(data,collapse)
- if data and data ~= "" then
- if type(data) == "table" then
- data = flatten(data,{ })
- if collapse then
- data = #data > 1 and concat(data,"\n") or data[1]
- end
- end
- return data
- end
-end
-
metapost.defaultformat = "metafun"
metapost.defaultinstance = "metafun"
metapost.defaultmethod = "default"
-local mpxformats = { }
-local nofformats = 0
-local mpxpreambles = { }
+function metapost.getextradata(mpx)
+ return mpxextradata[mpx]
+end
function metapost.pushformat(specification,f,m) -- was: instance, name, method
if type(specification) ~= "table" then
@@ -326,29 +516,30 @@ function metapost.pushformat(specification,f,m) -- was: instance, name, method
end
nofformats = nofformats + 1
local usedinstance = instance .. ":" .. nofformats
- local mpx = mpxformats[usedinstance]
+ local mpx = mpxformats [usedinstance]
local mpp = mpxpreambles[instance] or ""
+ -- report_metapost("push instance %a (%S)",usedinstance,mpx)
if preamble then
- preamble = prepareddata(preamble,true)
+ preamble = prepareddata(preamble)
mpp = mpp .. "\n" .. preamble
mpxpreambles[instance] = mpp
end
if not mpx then
report_metapost("initializing instance %a using format %a and method %a",usedinstance,format,method)
mpx = metapost.checkformat(format,method)
- mpxformats[usedinstance] = mpx
+ mpxformats [usedinstance] = mpx
+ mpxextradata[mpx] = { }
if mpp ~= "" then
preamble = mpp
end
end
if preamble then
- mpx:execute(preamble)
+ executempx(mpx,preamble)
end
specification.mpx = mpx
return mpx
end
-
-- luatex.wrapup(function()
-- for k, mpx in next, mpxformats do
-- mpx:finish()
@@ -364,14 +555,19 @@ function metapost.reset(mpx)
-- nothing
elseif type(mpx) == "string" then
if mpxformats[mpx] then
- mpxformats[mpx]:finish()
- mpxformats[mpx] = nil
+ local instance = mpxformats[mpx]
+ instance:finish()
+ mpxterminals[instance] = nil
+ mpxextradata[mpx] = nil
+ mpxformats [mpx] = nil
end
else
for name, instance in next, mpxformats do
if instance == mpx then
mpx:finish()
- mpxformats[name] = nil
+ mpxextradata[mpx] = nil
+ mpxformats [mpx] = nil
+ mpxterminals[mpx] = nil
break
end
end
@@ -461,7 +657,7 @@ function metapost.run(specification)
end
if mpx and data then
local tra = nil
- starttiming(metapost)
+ starttiming(metapost) -- why not at the outer level ...
metapost.variables = { } -- todo also push / pop
metapost.pushscriptrunner(mpx)
if trace_graphics then
@@ -479,20 +675,25 @@ function metapost.run(specification)
tra.inp:write(banner)
tra.log:write(banner)
end
- local data = prepareddata(data,metapost.collapse)
local function process(d,i)
if d then
if trace_graphics then
if i then
tra.inp:write(formatters["\n%% begin snippet %s\n"](i))
end
- tra.inp:write(d)
+ if type(d) == "table" then
+ for i=1,#d do
+ tra.inp:write(d[i])
+ end
+ else
+ tra.inp:write(d)
+ end
if i then
tra.inp:write(formatters["\n%% end snippet %s\n"](i))
end
end
starttiming(metapost.exectime)
- result = mpx:execute(d)
+ result = executempx(mpx,d)
stoptiming(metapost.exectime)
if trace_graphics and result then
local str = result.log or result.error
@@ -502,6 +703,7 @@ function metapost.run(specification)
end
if not metapost.reporterror(result) then
if metapost.showlog then
+ -- make function and overload in lmtx
local str = result.term ~= "" and result.term or "no terminal output"
if not emptystring(str) then
metapost.lastlog = metapost.lastlog .. "\n" .. str
@@ -519,14 +721,16 @@ function metapost.run(specification)
end
end
+-- local data = prepareddata(data)
if type(data) == "table" then
if trace_tracingall then
- mpx:execute("tracingall;")
+ executempx(mpx,"tracingall;")
end
- for i=1,#data do
- process(data[i],i)
- end
- else
+ process(data)
+-- for i=1,#data do
+-- process(data[i],i)
+-- end
+ else
if trace_tracingall then
data = "tracingall;" .. data
end
@@ -554,125 +758,71 @@ if not metapost.convert then
end
--- handy
+-- This will be redone as we no longer output svg of ps!
-function metapost.directrun(formatname,filename,outputformat,astable,mpdata)
- local fullname = file.addsuffix(filename,"mp")
- local data = mpdata or io.loaddata(fullname)
- if outputformat ~= "svg" then
- outputformat = "mps"
- end
- if not data then
- report_metapost("unknown file %a",filename)
- else
- local mpx = metapost.checkformat(formatname)
- if not mpx then
- report_metapost("unknown format %a",formatname)
- else
- report_metapost("processing %a",(mpdata and (filename or "data")) or fullname)
- local result = mpx:execute(data)
- if not result then
- report_metapost("error: no result object returned")
- elseif result.status > 0 then
- report_metapost("error: %s",(result.term or "no-term") .. "\n" .. (result.error or "no-error"))
- else
- if metapost.showlog then
- metapost.lastlog = metapost.lastlog .. "\n" .. result.term
- report_metapost("info: %s",result.term or "no-term")
- end
- local figures = result.fig
- if figures then
- local sorted = table.sortedkeys(figures)
- if astable then
- local result = { }
- report_metapost("storing %s figures in table",#sorted)
- for k=1,#sorted do
- local v = sorted[k]
- if outputformat == "mps" then
- result[v] = figures[v]:postscript()
- else
- result[v] = figures[v]:svg() -- (3) for prologues
- end
- end
- return result
- else
- local basename = file.removesuffix(file.basename(filename))
- for k=1,#sorted do
- local v = sorted[k]
- local output
- if outputformat == "mps" then
- output = figures[v]:postscript()
- else
- output = figures[v]:svg() -- (3) for prologues
- end
- local outname = formatters["%s-%s.%s"](basename,v,outputformat)
- report_metapost("saving %s bytes in %a",#output,outname)
- io.savedata(outname,output)
- end
- return #sorted
- end
- end
- end
- end
- end
-end
-
--- goodie
-
-function metapost.quickanddirty(mpxformat,data,incontext)
- if not data then
- mpxformat = "metafun"
- data = mpxformat
- end
- local code, bbox
- local flusher = {
- startfigure = function(n,llx,lly,urx,ury)
- code = { }
- bbox = { llx, lly, urx, ury }
- end,
- flushfigure = function(t)
- for i=1,#t do
- code[#code+1] = t[i]
- end
- end,
- stopfigure = function()
- end
- }
- local data = formatters["; beginfig(1) ;\n %s\n ; endfig ;"](data)
- metapost.process {
- mpx = mpxformat,
- flusher = flusher,
- askedfig = "all",
- useplugins = incontext,
- incontext = incontext,
- data = { data },
- }
- if code then
- return {
- bbox = bbox or { 0, 0, 0, 0 },
- code = code,
- data = data,
- }
- else
- report_metapost("invalid quick and dirty run")
- end
-end
+-- function metapost.directrun(formatname,filename,outputformat,astable,mpdata)
+-- local fullname = file.addsuffix(filename,"mp")
+-- local data = mpdata or io.loaddata(fullname)
+-- if outputformat ~= "svg" then
+-- outputformat = "mps"
+-- end
+-- if not data then
+-- report_metapost("unknown file %a",filename)
+-- else
+-- local mpx = metapost.checkformat(formatname)
+-- if not mpx then
+-- report_metapost("unknown format %a",formatname)
+-- else
+-- report_metapost("processing %a",(mpdata and (filename or "data")) or fullname)
+-- local result = executempx(mpx,data)
+-- if not result then
+-- report_metapost("error: no result object returned")
+-- elseif result.status > 0 then
+-- report_metapost("error: %s",(result.term or "no-term") .. "\n" .. (result.error or "no-error"))
+-- else
+-- if metapost.showlog then
+-- metapost.lastlog = metapost.lastlog .. "\n" .. result.term
+-- report_metapost("info: %s",result.term or "no-term")
+-- end
+-- local figures = result.fig
+-- if figures then
+-- local sorted = table.sortedkeys(figures)
+-- if astable then
+-- local result = { }
+-- report_metapost("storing %s figures in table",#sorted)
+-- for k=1,#sorted do
+-- local v = sorted[k]
+-- if outputformat == "mps" then
+-- result[v] = figures[v]:postscript()
+-- else
+-- result[v] = figures[v]:svg() -- (3) for prologues
+-- end
+-- end
+-- return result
+-- else
+-- local basename = file.removesuffix(file.basename(filename))
+-- for k=1,#sorted do
+-- local v = sorted[k]
+-- local output
+-- if outputformat == "mps" then
+-- output = figures[v]:postscript()
+-- else
+-- output = figures[v]:svg() -- (3) for prologues
+-- end
+-- local outname = formatters["%s-%s.%s"](basename,v,outputformat)
+-- report_metapost("saving %s bytes in %a",#output,outname)
+-- io.savedata(outname,output)
+-- end
+-- return #sorted
+-- end
+-- end
+-- end
+-- end
+-- end
+-- end
-function metapost.getstatistics(memonly)
- if memonly then
- local n, m = 0, 0
- for name, mpx in next, mpxformats do
- n = n + 1
- m = m + mpx:statistics().memory
- end
- return n, m
- else
- local t = { }
- for name, mpx in next, mpxformats do
- t[name] = mpx:statistics()
- end
- return t
- end
+function metapost.directrun(formatname,filename,outputformat,astable,mpdata)
+ report_metapost("producing postscript and svg is no longer supported")
end
do
@@ -681,6 +831,7 @@ do
local width = 0
local height = 0
local depth = 0
+ local bbox = { 0, 0, 0, 0 }
local flusher = {
startfigure = function(n,llx,lly,urx,ury)
@@ -688,35 +839,62 @@ do
width = urx - llx
height = ury
depth = -lly
+ bbox = { llx, lly, urx, ury }
end,
flushfigure = function(t)
+ local r = #result
for i=1,#t do
- result[#result+1] = t[i]
+ r = r + 1
+ result[r] = t[i]
end
end,
stopfigure = function()
- end
+ end,
}
- function metapost.simple(format,code) -- even less than metapost.quickcanddirty
- local mpx = metapost.pushformat { } -- takes defaults
- -- metapost.setoutercolor(2)
+ -- make table variant:
+
+ function metapost.simple(instance,code,useextensions,dontwrap)
+ -- can we pickup the instance ?
+ local mpx = metapost.pushformat {
+ instance = instance or "simplefun",
+ format = "metafun", -- or: minifun
+ method = "double",
+ }
metapost.process {
mpx = mpx,
flusher = flusher,
askedfig = 1,
- useplugins = false,
+ useplugins = useextensions,
+ data = dontwrap and { code } or { "beginfig(1);", code, "endfig;" },
incontext = false,
- data = { "beginfig(1);", code, "endfig;" },
}
metapost.popformat()
if result then
local stream = concat(result," ")
- result = nil -- cleanup
- return stream, width, height, depth
+ result = { } -- nil -- cleanup .. weird, we can have a dangling q
+ return stream, width, height, depth, bbox
else
- return "", 0, 0, 0
+ return "", 0, 0, 0, { 0, 0, 0, 0 }
end
end
end
+
+function metapost.getstatistics(memonly)
+ if memonly then
+ local n, m = 0, 0
+ for name, mpx in next, mpxformats do
+ n = n + 1
+ m = m + mpx:statistics().memory
+ end
+ return n, m
+ else
+ local t = { }
+ for name, mpx in next, mpxformats do
+ t[name] = mpx:statistics()
+ end
+ return t
+ end
+end
+
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mlib-scn.lua b/Master/texmf-dist/tex/context/base/mkiv/mlib-scn.lua
new file mode 100644
index 00000000000..709961543bf
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/mlib-scn.lua
@@ -0,0 +1,777 @@
+if not modules then modules = { } end modules ['mlib-scn'] = {
+ version = 1.001,
+ comment = "companion to mlib-ctx.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+}
+
+-- Very experimental, for Alan and me.
+
+-- for i = 1 upto 32000 : % 0.062
+-- ts := 5mm / 20;
+-- endfor ;
+--
+-- for i = 1 upto 32000 : % 0.219
+-- ts := (getparameter "axis" "sy") / 20;
+-- endfor ;
+--
+-- for i = 1 upto 32000 : % 0.266
+-- ts := (getparameterx "axis" "sy") / 20;
+-- endfor ;
+--
+-- pushparameters "axis";
+-- for i = 1 upto 32000 : % 0.250
+-- ts := (getparameterx "sy") / 20;
+-- endfor ;
+-- popparameters;
+
+local type, next, rawget, getmetatable = type, next, rawget, getmetatable
+local byte, gmatch = string.byte, string.gmatch
+local insert, remove = table.insert, table.remove
+
+local mplib = mplib
+local metapost = metapost
+
+local codes = mplib.codes()
+local types = mplib.types()
+
+table.hashed(codes)
+table.hashed(types)
+
+metapost.codes = codes
+metapost.types = types
+
+local setmetatableindex = table.setmetatableindex
+
+local scanners = mp.scan
+
+local scannext = scanners.next
+local scanexpression = scanners.expression
+local scantoken = scanners.token
+local scansymbol = scanners.symbol
+local scannumeric = scanners.numeric
+local scannumber = scanners.number
+local scaninteger = scanners.integer
+local scanboolean = scanners.boolean
+local scanstring = scanners.string
+local scanpair = scanners.pair
+local scancolor = scanners.color
+local scancmykcolor = scanners.cmykcolor
+local scantransform = scanners.transform
+local scanpath = scanners.path
+local scanpen = scanners.pen
+
+local mpprint = mp.print
+local mpnumeric = mp.numeric
+local mpstring = mp.string
+local mpquoted = mp.quoted
+local mpboolean = mp.boolean
+local mppair = mp.pair
+local mppath = mp.path
+local mptriplet = mp.triplet
+local mpquadruple = mp.quadruple
+local mptransform = mp.transform
+local mpvalue = mp.value
+
+local report = logs.reporter("metapost")
+
+local semicolon_code <const> = codes.semicolon
+local equals_code <const> = codes.equals
+local comma_code <const> = codes.comma
+local colon_code <const> = codes.colon
+local leftbrace_code <const> = codes.leftbrace
+local rightbrace_code <const> = codes.rightbrace
+local leftbracket_code <const> = codes.leftbracket
+local rightbracket_code <const> = codes.rightbracket
+local leftdelimiter_code <const> = codes.leftdelimiter
+local rightdelimiter_code <const> = codes.rightdelimiter
+local numeric_code <const> = codes.numeric
+local string_code <const> = codes.string
+local capsule_code <const> = codes.capsule
+local nullary_code <const> = codes.nullary
+local tag_code <const> = codes.tag
+local definedmacro_code <const> = codes.definedmacro
+
+local typescanners = nil
+local tokenscanners = nil
+local scanset = nil
+local scanparameters = nil
+
+scanset = function() -- can be optimized, we now read twice
+ scantoken()
+ if scantoken(true) == rightbrace_code then
+ scantoken()
+ return { }
+ else
+ local l = { }
+ local i = 0
+ while true do
+ i = i + 1
+ local s = scansymbol(true)
+ if s == "{" then
+ l[i] = scanset()
+ elseif s == "[" then
+ local d = { }
+ scansymbol()
+ while true do
+ local s = scansymbol()
+ if s == "]" then
+ break;
+ elseif s == "," then
+ -- continue
+ else
+ local t = scantoken(true)
+ if t == equals_code or t == colon_code then
+ scantoken()
+ end
+ d[s] = tokenscanners[scantoken(true)]()
+ end
+ end
+ l[i] = d
+ else
+ local e = scanexpression(true)
+ l[i] = (typescanners[e] or scanexpression)()
+ end
+ if scantoken() == rightbrace_code then
+ break
+ else
+ -- whatever
+ end
+ end
+ return l
+ end
+end
+
+local function scan_pair () return scanpair (true) end
+local function scan_color () return scancolor (true) end
+local function scan_cmykcolor() return scancmykcolor(true) end
+local function scan_transform() return scantransform(true) end
+
+tokenscanners = {
+ [leftbrace_code] = scanset,
+ [numeric_code] = scannumeric,
+ [string_code] = scanstring,
+ [nullary_code] = scanboolean, -- todo
+}
+
+typescanners = {
+ [types.known] = scannumeric,
+ [types.numeric] = scannumeric,
+ [types.string] = scanstring,
+ [types.boolean] = scanboolean,
+ [types.pair] = scan_pair,
+ [types.color] = scan_color,
+ [types.cmykcolor] = scan_cmykcolor,
+ [types.transform] = scan_transform,
+ [types.path] = scanpath,
+ [types.pen] = scanpen,
+}
+
+table.setmetatableindex(tokenscanners,function()
+ local e = scanexpression(true)
+ return typescanners[e] or scanexpression
+end)
+
+-- a key like 'color' has code 'declare'
+
+local function scanparameters(fenced)
+ local data = { }
+ local close = "]"
+ if not fenced then
+ close = ";"
+ elseif scansymbol(true) == "[" then
+ scansymbol()
+ else
+ return data
+ end
+ while true do
+ -- local s = scansymbol()
+ local s = scansymbol(false,false)
+ if s == close then
+ break;
+ elseif s == "," then
+ -- continue
+ else
+ local t = scantoken(true)
+ if t == equals_code or t == colon_code then
+ -- optional equal or :
+ scantoken()
+ end
+ local kind = scantoken(true)
+ if kind == leftdelimiter_code or kind == tag_code or kind == capsule_code then
+ kind = scanexpression(true)
+ data[s] = (typescanners[kind] or scanexpression)()
+ elseif kind == leftbracket_code then
+ data[s] = get_parameters(true)
+ else
+ data[s] = tokenscanners[kind]()
+ end
+ end
+ end
+ return data
+end
+
+local namespaces = { }
+local presets = { }
+local passed = { }
+
+local function get_parameters(nested)
+ local data = { }
+ if nested or scansymbol(true) == "[" then
+ scansymbol()
+ else
+ return data
+ end
+ while true do
+ local s = scansymbol(false,false)
+ if s == "]" then
+ break;
+ elseif s == "," then
+ -- continue
+ else
+ local t = scantoken(true)
+ if t == equals_code or t == colon_code then
+ -- optional equal or :
+ scantoken()
+ end
+ local kind = scantoken(true)
+ if kind == leftdelimiter_code or kind == tag_code or kind == capsule_code then
+ kind = scanexpression(true)
+ data[s] = (typescanners[kind] or scanexpression)()
+ elseif kind == leftbracket_code then
+ data[s] = get_parameters(true)
+ else
+ data[s] = tokenscanners[kind]()
+ end
+ end
+ end
+ return data
+end
+
+local function getparameters()
+ local namespace = scanstring()
+ -- same as below
+ local parameters = get_parameters()
+ local presets = presets[namespace]
+ local passed = passed[namespace]
+ if passed then
+ if presets then
+ setmetatableindex(passed,presets)
+ end
+ setmetatableindex(parameters,passed)
+ elseif presets then
+ setmetatableindex(parameters,presets)
+ end
+ namespaces[namespace] = parameters
+ --
+end
+
+local function applyparameters()
+ local saved = namespaces
+ local namespace = scanstring()
+ local action = scanstring() -- before we scan the parameters
+ -- same as above
+ local parameters = get_parameters()
+ local presets = presets[namespace]
+ local passed = passed[namespace]
+ if passed then
+ if presets then
+ setmetatableindex(passed,presets)
+ end
+ setmetatableindex(parameters,passed)
+ elseif presets then
+ setmetatableindex(parameters,presets)
+ end
+ namespaces[namespace] = parameters
+ -- till here
+ mpprint(action)
+ namespaces = saved
+end
+
+local function presetparameters()
+ local namespace = scanstring()
+ local parent = nil
+ local t = scantoken(true)
+ if t == string_code then
+ parent = presets[scanstring()]
+ end
+ local p = get_parameters()
+ if parent then
+ setmetatableindex(p,parent)
+ end
+ presets[namespace] = p
+end
+
+local function collectnames()
+ local l = { } -- can be reused but then we can't nest
+ local n = 0
+ while true do
+ local t = scantoken(true)
+ -- (1) not really needed
+ if t == numeric_code then
+ n = n + 1 l[n] = scaninteger(1)
+ elseif t == string_code then
+ n = n + 1 l[n] = scanstring(1)
+ elseif t == nullary_code then
+ n = n + 1 l[n] = scanboolean(1)
+ elseif t == leftdelimiter_code or t == tag_code or t == capsule_code then
+ t = scanexpression(true)
+ n = n + 1 l[n] = (typescanners[t] or scanexpression)()
+ else
+ break
+ end
+ end
+ return l, n
+end
+
+local function get(v)
+ local t = type(v)
+ if t == "number" then
+ return mpnumeric(v)
+ elseif t == "boolean" then
+ return mpboolean(v)
+ elseif t == "string" then
+ return mpquoted(v)
+ elseif t == "table" then
+ local n = #v
+ if type(v[1]) == "table" then
+ return mppath(v) -- cycle ?
+ elseif n == 2 then
+ return mppair(v)
+ elseif n == 3 then
+ return mptriplet(v)
+ elseif n == 4 then
+ return mpquadruple(v)
+ elseif n == 6 then
+ return mptransform(v)
+ end
+ end
+ return mpnumeric(0)
+end
+
+local stack = { }
+
+local function pushparameters()
+ local l, n = collectnames()
+ insert(stack,namespaces)
+ for i=1,n do
+ local n = namespaces[l[i]]
+ if type(n) == "table" then
+ namespaces = n
+ else
+ break
+ end
+ end
+end
+
+local function popparameters()
+ local n = remove(stack)
+ if n then
+ namespaces = n
+ else
+ report("stack error")
+ end
+end
+
+-- todo:
+
+local function getparameter()
+ local list, n = collectnames()
+ local v = namespaces
+ for i=1,n do
+ local l = list[i]
+ local vl = v[l]
+ if vl == nil then
+ if type(l) == "number" then
+ vl = v[1]
+ if vl == nil then
+ return mpnumeric(0)
+ end
+ else
+ return mpnumeric(0)
+ end
+ end
+ v = vl
+ end
+ if v == nil then
+ return mpnumeric(0)
+ else
+ return get(v)
+ end
+end
+
+local function hasparameter()
+ local list, n = collectnames()
+ local v = namespaces
+ for i=1,n do
+ local l = list[i]
+ local vl = rawget(v,l)
+ if vl == nil then
+ if type(l) == "number" then
+ vl = rawget(v,1)
+ if vl == nil then
+ return mpboolean(false)
+ end
+ else
+ return mpboolean(false)
+ end
+ end
+ v = vl
+ end
+ if v == nil then
+ return mpboolean(false)
+ else
+ return mpboolean(true)
+ end
+end
+
+local function hasoption()
+ local list, n = collectnames()
+ if n > 1 then
+ local v = namespaces
+ if n > 2 then
+ for i=1,n-1 do
+ local l = list[i]
+ local vl = v[l]
+ if vl == nil then
+ return mpboolean(false)
+ end
+ v = vl
+ end
+ else
+ v = v[list[1]]
+ end
+ if type(v) == "string" then
+ -- no caching .. slow anyway
+ local o = list[n]
+ if v == o then
+ return mpboolean(true)
+ end
+ for vv in gmatch(v,"[^%s,]+") do
+ for oo in gmatch(o,"[^%s,]+") do
+ if vv == oo then
+ return mpboolean(true)
+ end
+ end
+ end
+ end
+ end
+ return mpboolean(false)
+end
+
+local function getparameterdefault()
+ local list, n = collectnames()
+ local v = namespaces
+ if n == 1 then
+ local l = list[1]
+ local vl = v[l]
+ if vl == nil then
+ -- maybe backtrack
+ local top = stack[#stack]
+ if top then
+ vl = top[l]
+ end
+ end
+ if vl == nil then
+ return mpnumeric(0)
+ else
+ return get(vl)
+ end
+ else
+ for i=1,n-1 do
+ local l = list[i]
+ local vl = v[l]
+ if vl == nil then
+ if type(l) == "number" then
+ vl = v[1]
+ if vl == nil then
+ return get(list[n])
+ end
+ else
+ local last = list[n]
+ if last == "*" then
+ -- so, only when not pushed
+ local m = getmetatable(namespaces[list[1]])
+ if n then
+ m = m.__index -- can also be a _m_
+ end
+ if m then
+ local v = m
+ for i=2,n-1 do
+ local l = list[i]
+ local vl = v[l]
+ if vl == nil then
+ return mpnumeric(0)
+ end
+ v = vl
+ end
+ if v == nil then
+ return mpnumeric(0)
+ else
+ return get(v)
+ end
+ end
+ return mpnumeric(0)
+ else
+ return get(last)
+ end
+ end
+ end
+ v = vl
+ end
+ if v == nil then
+ return get(list[n])
+ else
+ return get(v)
+ end
+ end
+end
+
+local function getparametercount()
+ local list, n = collectnames()
+ local v = namespaces
+ for i=1,n do
+ v = v[list[i]]
+ if not v then
+ break
+ end
+ end
+ return mpnumeric(type(v) == "table" and #v or 0)
+end
+
+local function getmaxparametercount()
+ local list, n = collectnames()
+ local v = namespaces
+ for i=1,n do
+ v = v[list[i]]
+ if not v then
+ break
+ end
+ end
+ local n = 0
+ if type(v) == "table" then
+ local v1 = v[1]
+ if type(v1) == "table" then
+ n = #v1
+ for i=2,#v do
+ local vi = v[i]
+ if type(vi) == "table" then
+ local vn = #vi
+ if vn > n then
+ n = vn
+ end
+ else
+ break;
+ end
+ end
+ end
+
+ end
+ return mpnumeric(n)
+end
+
+local validconnectors = {
+ [".."] = true,
+ ["..."] = true,
+ ["--"] = true,
+}
+
+local function getparameterpath()
+ local list, n = collectnames()
+ local close = list[n]
+ if type(close) == "boolean" then
+ n = n - 1
+ else
+ close = false
+ end
+ local connector = list[n]
+ if type(connector) == "string" and validconnectors[connector] then
+ n = n - 1
+ else
+ connector = "--"
+ end
+ local v = namespaces
+ for i=1,n do
+ v = v[list[i]]
+ if not v then
+ break
+ end
+ end
+ if type(v) == "table" then
+ return mppath(v,connector,close)
+ else
+ return mppair(0,0)
+ end
+end
+
+local function getparameterpen()
+ local list, n = collectnames()
+ local v = namespaces
+ for i=1,n do
+ v = v[list[i]]
+ if not v then
+ break
+ end
+ end
+ if type(v) == "table" then
+ return mppath(v,"..",true)
+ else
+ return mppair(0,0)
+ end
+end
+
+local function getparametertext()
+ local list, n = collectnames()
+ local strut = list[n]
+ if type(strut) == "boolean" then
+ n = n - 1
+ else
+ strut = false
+ end
+ local v = namespaces
+ for i=1,n do
+ v = v[list[i]]
+ if not v then
+ break
+ end
+ end
+ if type(v) == "string" then
+ return mpquoted("\\strut " .. v)
+ else
+ return mpquoted("")
+ end
+end
+
+-- local function getparameteroption()
+-- local list, n = collectnames()
+-- local last = list[n]
+-- if type(last) == "string" then
+-- n = n - 1
+-- else
+-- return false
+-- end
+-- local v = namespaces
+-- for i=1,n do
+-- v = v[list[i]]
+-- if not v then
+-- break
+-- end
+-- end
+-- if type(v) == "string" and v ~= "" then
+-- for s in gmatch(v,"[^ ,]+") do
+-- if s == last then
+-- return true
+-- end
+-- end
+-- end
+-- return false
+-- end
+
+function metapost.scanparameters()
+-- scantoken() -- we scan the semicolon
+ return get_parameters()
+end
+
+metapost.registerscript("getparameters", getparameters)
+metapost.registerscript("applyparameters", applyparameters)
+metapost.registerscript("presetparameters", presetparameters)
+metapost.registerscript("hasparameter", hasparameter)
+metapost.registerscript("hasoption", hasoption)
+metapost.registerscript("getparameter", getparameter)
+metapost.registerscript("getparameterdefault", getparameterdefault)
+metapost.registerscript("getparametercount", getparametercount)
+metapost.registerscript("getmaxparametercount",getmaxparametercount)
+metapost.registerscript("getparameterpath", getparameterpath)
+metapost.registerscript("getparameterpen", getparameterpen)
+metapost.registerscript("getparametertext", getparametertext)
+--------.registerscript("getparameteroption", getparameteroption)
+metapost.registerscript("pushparameters", pushparameters)
+metapost.registerscript("popparameters", popparameters)
+
+function metapost.getparameter(list)
+ local n = #list
+ local v = namespaces
+ for i=1,n do
+ local l = list[i]
+ local vl = v[l]
+ if vl == nil then
+ return
+ end
+ v = vl
+ end
+ return v
+end
+
+function metapost.getparameterset(namespace)
+ return namespace and namespaces[namespace] or namespaces
+end
+
+function metapost.setparameterset(namespace,t)
+ namespaces[namespace] = t
+end
+
+-- goodies
+
+metapost.registerscript("definecolor", function()
+ scantoken() -- we scan the semicolon
+ local s = get_parameters()
+ attributes.colors.defineprocesscolordirect(s)
+end)
+
+-- tex scanners
+
+local scanners = tokens.scanners
+local scanhash = scanners.hash
+local scanstring = scanners.string
+local scanvalue = scanners.value
+local scaninteger = scanners.integer
+local scanboolean = scanners.boolean
+local scanfloat = scanners.float
+local scandimension = scanners.dimension
+
+local definitions = { }
+
+local bpfactor <const> = number.dimenfactors.bp
+local comma <const> = byte(",")
+local close <const> = byte("]")
+
+local scanrest = function() return scanvalue(comma,close) or "" end
+local scandimension = function() return scandimension() * bpfactor end
+
+local scanners = {
+ ["integer"] = scaninteger,
+ ["number"] = scanfloat,
+ ["numeric"] = scanfloat,
+ ["boolean"] = scanboolean,
+ ["string"] = scanrest,
+ ["dimension"] = scandimension,
+}
+
+interfaces.implement {
+ name = "lmt_parameters_define",
+ arguments = "string",
+ actions = function(namespace)
+ local d = scanhash()
+ for k, v in next, d do
+ d[k] = scanners[v] or scanrest
+ end
+ definitions[namespace] = d
+ end,
+}
+
+interfaces.implement {
+ name = "lmt_parameters_preset",
+ arguments = "string",
+ actions = function(namespace)
+ passed[namespace] = scanhash(definitions[namespace])
+ end,
+}
+
+interfaces.implement {
+ name = "lmt_parameters_reset",
+ arguments = "string",
+ actions = function(namespace)
+ passed[namespace] = nil
+ end,
+}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mlib-svg.lua b/Master/texmf-dist/tex/context/base/mkiv/mlib-svg.lua
new file mode 100644
index 00000000000..f4b3117a62f
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/mlib-svg.lua
@@ -0,0 +1,3118 @@
+if not modules then modules = { } end modules ['mlib-svg'] = {
+ version = 1.001,
+ comment = "companion to mlib-ctx.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+}
+
+-- Just a few notes:
+--
+-- There is no real need to boost performance here .. we can always make a fast
+-- variant when really needed. I will also do some of the todo's when I run into
+-- proper fonts. I need to optimize this a bit but will do that once I'm satisfied
+-- with the outcome and don't need more hooks and plugs. At some point I will
+-- optimize the MetaPost part because now we probably have more image wrapping
+-- than needed.
+--
+-- As usual with these standards, things like a path can be very compact while the
+-- rest is very verbose which defeats the point. This is a first attempt. There will
+-- be a converter to MP as well as directly to PDF. This module was made for one of
+-- the dangerous curves talks at the 2019 CTX meeting. I will do the font when I
+-- need it (not that hard).
+--
+-- The fact that in the more recent versions of SVG the older text related elements
+-- are depricated and not even supposed to be supported, combined with the fact that
+-- the text element assumes css styling, demonstrates that there is not so much as a
+-- standard. It basically means that whatever technology dominates at some point
+-- (probably combined with some libraries that at that point exist) determine what
+-- is standard. Anyway, it probably also means that these formats are not that
+-- suitable for long term archival purposes. So don't take the next implementation
+-- too serious. So in the end we now have (1) attributes for properties (which is
+-- nice and clean and what attributes are for, (2) a style attribute that needs to
+-- be parsed, (3) classes that map to styles and (4) element related styles, plus a
+-- kind of inheritance (given the limited number of elements sticking to only <g> as
+-- wrapper would have made much sense. Anyway, we need to deal with it. With all
+-- these style things going on, one can wonder where it will end. Basically svg
+-- became just a html element that way and less clean too. The same is true for
+-- tspan, which means that text itself is nested xml.
+--
+-- We can do a direct conversion to PDF but then we also loose the abstraction which
+-- in the future will be used, and for fonts we need to spawn out to TeX anyway, so
+-- the little overhead of calling MetaPost is okay I guess. Also, we want to
+-- overload labels, share fonts with the main document, etc. and are not aiming at a
+-- general purpose SVG converter. For going to PDF one can just use InkScape.
+--
+-- Written with Anne Clark on speakers as distraction.
+--
+-- Todo when I run into an example (but ony when needed and reasonable):
+--
+-- var(color,color)
+-- --color<decimal>
+-- currentColor : when i run into an example
+-- a bit more shading
+-- clip = [ auto | rect(llx,lly,urx,ury) ] (in svg)
+-- xlink url ... whatever
+-- masks
+-- opacity per group (i need to add that to metafun first, inefficient pdf but
+-- maybe filldraw can help here)
+--
+-- Maybe in metafun:
+--
+-- penciled n -> withpen pencircle scaled n
+-- applied (...) -> transformed bymatrix (...)
+-- withopacity n -> withtransparency (1,n)
+
+-- When testing mbo files:
+--
+-- empty paths
+-- missing control points
+-- funny fontnames like abcdefverdana etc
+-- paths representing glyphs but also with style specs
+-- all kind of attributes
+-- very weird and inefficient shading
+
+-- One can run into pretty crazy images, like lines that are fills being clipped
+-- to some width. That's the danger of hiding yourself behind an interface I guess.
+
+local rawget, rawset, type, tonumber, tostring, next, setmetatable = rawget, rawset, type, tonumber, tostring, next, setmetatable
+
+local P, S, R, C, Ct, Cs, Cc, Cp, Cg, Cf, Carg = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Ct, lpeg.Cs, lpeg.Cc, lpeg.Cp, lpeg.Cg, lpeg.Cf, lpeg.Carg
+
+local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns
+local sqrt = math.sqrt
+local concat, setmetatableindex, sortedhash = table.concat, table.setmetatableindex, table.sortedhash
+local gmatch, gsub, find, match, rep = string.gmatch, string.gsub, string.find, string.match, string.rep
+local formatters, fullstrip = string.formatters, string.fullstrip
+local utfsplit, utfbyte = utf.split, utf.byte
+
+local xmlconvert, xmlcollected, xmlcount, xmlfirst, xmlroot = xml.convert, xml.collected, xml.count, xml.first, xml.root
+local xmltext, xmltextonly = xml.text, xml.textonly
+local css = xml.css or { } -- testing
+
+local function xmlinheritattributes(c,pa)
+ local at = c.at
+ local dt = c.dt
+ if at and dt then
+ if pa then
+ setmetatableindex(at,pa)
+ end
+ for i=1,#dt do
+ local dti = dt[i]
+ if type(dti) == "table" then
+ xmlinheritattributes(dti,at)
+ end
+ end
+ else
+ -- comment of so
+ end
+end
+
+xml.inheritattributes = xmlinheritattributes
+
+-- Maybe some day helpers will move to the metapost.svg namespace!
+
+metapost = metapost or { }
+local metapost = metapost
+local context = context
+
+local report = logs.reporter("metapost","svg")
+
+local trace = false trackers.register("metapost.svg", function(v) trace = v end)
+local trace_text = false trackers.register("metapost.svg.text", function(v) trace_text = v end)
+local trace_path = false trackers.register("metapost.svg.path", function(v) trace_path = v end)
+local trace_result = false trackers.register("metapost.svg.result", function(v) trace_result = v end)
+
+local pathtracer = {
+ ["stroke"] = "darkred",
+ ["stroke-opacity"] = ".5",
+ ["stroke-width"] = ".5",
+ ["fill"] = "darkgray",
+ ["fill-opacity"] = ".75",
+}
+
+-- This is just an experiment. Todo: reset hash etc. Also implement
+-- an option handler.
+
+local svghash = false do
+
+ local svglast = 0
+ local svglist = false
+
+ local function checkhash(t,k)
+ local n = svglast + 1
+ svglast = n
+ svglist[n] = k
+ t[k] = n
+ return n
+ end
+
+ function metapost.startsvghashing()
+ svglast = 0
+ svglist = { }
+ svghash = setmetatableindex(checkhash)
+ end
+
+ function metapost.stopsvghashing()
+ svglast = 0
+ svglist = false
+ svghash = false
+ end
+
+ interfaces.implement {
+ name = "svghashed",
+ arguments = "integer",
+ actions = function(n)
+ local t = svglist and svglist[n]
+ if t then
+ context(t)
+ end
+ end
+ }
+
+end
+
+-- We have quite some closures because otherwise we run into the local variable
+-- limitations. It doesn't always look pretty now, sorry. I'll clean up this mess
+-- some day (the usual nth iteration of code).
+--
+-- Most of the conversion is rather trivial code till I ran into a file with arcs. A
+-- bit of searching lead to the a2c javascript function but it has some puzzling
+-- thingies (like sin and cos definitions that look like leftovers and possible
+-- division by zero). Anyway, we can if needed optimize it a bit more. Here does it
+-- come from:
+
+-- http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
+-- https://github.com/adobe-webplatform/Snap.svg/blob/b242f49e6798ac297a3dad0dfb03c0893e394464/src/path.js
+
+local a2c do
+
+ local pi, sin, cos, tan, asin, abs = math.pi, math.sin, math.cos, math.tan, math.asin, math.abs
+
+ local d120 = (pi * 120) / 180
+ local pi2 = 2 * pi
+
+ a2c = function(x1, y1, rx, ry, angle, large, sweep, x2, y2, f1, f2, cx, cy)
+
+ if (rx == 0 or ry == 0 ) or (x1 == x2 and y1 == y2) then
+ return { x1, y1, x2, y2, x2, y2 }
+ end
+
+ local recursive = f1
+ local rad = pi / 180 * angle
+ local res = nil
+ local cosrad = cos(-rad) -- local cosrad = cosd(angle)
+ local sinrad = sin(-rad) -- local sinrad = sind(angle)
+
+ if not recursive then
+
+ x1, y1 = x1 * cosrad - y1 * sinrad, x1 * sinrad + y1 * cosrad
+ x2, y2 = x2 * cosrad - y2 * sinrad, x2 * sinrad + y2 * cosrad
+
+ local x = (x1 - x2) / 2
+ local y = (y1 - y2) / 2
+ local xx = x * x
+ local yy = y * y
+ local h = xx / (rx * rx) + yy / (ry * ry)
+
+ if h > 1 then
+ h = sqrt(h)
+ rx = h * rx
+ ry = h * ry
+ end
+
+ local rx2 = rx * rx
+ local ry2 = ry * ry
+ local ry2xx = ry2 * xx
+ local rx2yy = rx2 * yy
+ local total = rx2yy + ry2xx -- otherwise overflow
+
+ local k = total == 0 and 0 or sqrt(abs((rx2 * ry2 - rx2yy - ry2xx) / total))
+
+ if large == sweep then
+ k = -k
+ end
+
+ cx = k * rx * y / ry + (x1 + x2) / 2
+ cy = k * -ry * x / rx + (y1 + y2) / 2
+
+ f1 = (y1 - cy) / ry -- otherwise crash on a tiny eps
+ f2 = (y2 - cy) / ry -- otherwise crash on a tiny eps
+
+ f1 = asin((f1 < -1.0 and -1.0) or (f1 > 1.0 and 1.0) or f1)
+ f2 = asin((f2 < -1.0 and -1.0) or (f2 > 1.0 and 1.0) or f2)
+
+ if x1 < cx then f1 = pi - f1 end
+ if x2 < cx then f2 = pi - f2 end
+
+ if f1 < 0 then f1 = pi2 + f1 end
+ if f2 < 0 then f2 = pi2 + f2 end
+
+ if sweep ~= 0 and f1 > f2 then f1 = f1 - pi2 end
+ if sweep == 0 and f2 > f1 then f2 = f2 - pi2 end
+
+ end
+
+ if abs(f2 - f1) > d120 then
+ local f2old = f2
+ local x2old = x2
+ local y2old = y2
+ f2 = f1 + d120 * ((sweep ~= 0 and f2 > f1) and 1 or -1)
+ x2 = cx + rx * cos(f2)
+ y2 = cy + ry * sin(f2)
+ res = a2c(x2, y2, rx, ry, angle, 0, sweep, x2old, y2old, f2, f2old, cx, cy)
+ end
+
+ local c1 = cos(f1)
+ local s1 = sin(f1)
+ local c2 = cos(f2)
+ local s2 = sin(f2)
+
+ local t = tan((f2 - f1) / 4)
+ local hx = 4 * rx * t / 3
+ local hy = 4 * ry * t / 3
+
+ local r = { x1 - hx * s1, y1 + hy * c1, x2 + hx * s2, y2 - hy * c2, x2, y2, unpack(res or { }) }
+
+ if not recursive then -- we can also check for sin/cos being 0/1
+ cosrad = cos(rad)
+ sinrad = sin(rad)
+ -- cosrad = cosd(angle)
+ -- sinrad = sind(angle)
+ for i0=1,#r,2 do
+ local i1 = i0 + 1
+ local x = r[i0]
+ local y = r[i1]
+ r[i0] = x * cosrad - y * sinrad
+ r[i1] = x * sinrad + y * cosrad
+ end
+ end
+
+ return r
+ end
+
+end
+
+-- We share some patterns.
+
+local p_digit = lpegpatterns.digit
+local p_hexdigit = lpegpatterns.hexdigit
+local p_space = lpegpatterns.whitespace
+
+local factors = {
+ ["pt"] = 1.25,
+ ["mm"] = 3.543307,
+ ["cm"] = 35.43307,
+ ["px"] = 1,
+ ["pc"] = 15,
+ ["in"] = 90,
+ ["em"] = 12 * 1.25,
+ ["ex"] = 8 * 1.25,
+}
+
+local percentage_r = 1/100
+local percentage_x = percentage_r
+local percentage_y = percentage_r
+
+-- incredible: we can find .123.456 => 0.123 0.456 ...
+
+local p_command_x = C(S("Hh"))
+local p_command_y = C(S("Vv"))
+local p_command_xy = C(S("CcLlMmQqSsTt"))
+local p_command_a = C(S("Aa"))
+local p_command = C(S("Zz"))
+
+local p_optseparator = S("\t\n\r ,")^0
+local p_separator = S("\t\n\r ,")^1
+local p_number = (S("+-")^0 * (p_digit^0 * P(".") * p_digit^1 + p_digit^1 * P(".") + p_digit^1))
+ * (P("e") * S("+-")^0 * p_digit^1)^-1
+
+local function convert (n) n = tonumber(n) return n end
+local function convert_r (n,u) n = tonumber(n) if u == true then return percentage_r * n elseif u then return u * n else return n end end
+local function convert_x (n,u) n = tonumber(n) if u == true then return percentage_x * n elseif u then return u * n else return n end end
+local function convert_y (n,u) n = tonumber(n) if u == true then return percentage_y * n elseif u then return u * n else return n end end
+local function convert_vx(n,u) n = tonumber(n) if u == true then return percentage_x * n elseif u then return u * n else return n end end
+local function convert_vy(n,u) n = - tonumber(n) if u == true then return percentage_y * n elseif u then return u * n else return n end end
+
+local p_unit = (P("p") * S("txc") + P("e") * S("xm") + S("mc") * P("m") + P("in")) / factors
+local p_percent = P("%") * Cc(true)
+
+local c_number_n = C(p_number)
+local c_number_u = C(p_number) * (p_unit + p_percent)^-1
+
+local p_number_n = c_number_n / convert
+local p_number_x = c_number_u / convert_x
+local p_number_vx = c_number_u / convert_vx
+local p_number_y = c_number_u / convert_y
+local p_number_vy = c_number_u / convert_vy
+local p_number_r = c_number_u / convert_r
+
+local function asnumber (s) return s and lpegmatch(p_number, s) or 0 end
+local function asnumber_r (s) return s and lpegmatch(p_number_r, s) or 0 end
+local function asnumber_x (s) return s and lpegmatch(p_number_x, s) or 0 end
+local function asnumber_y (s) return s and lpegmatch(p_number_y, s) or 0 end
+local function asnumber_vx(s) return s and lpegmatch(p_number_vx,s) or 0 end
+local function asnumber_vy(s) return s and lpegmatch(p_number_vy,s) or 0 end
+
+local p_number_vx_t = Ct { (p_number_vx + p_separator)^1 }
+local p_number_vy_t = Ct { (p_number_vy + p_separator)^1 }
+
+local zerotable = { 0 }
+
+local function asnumber_vx_t(s) return s and lpegmatch(p_number_vx_t,s) or zerotable end
+local function asnumber_vy_t(s) return s and lpegmatch(p_number_vy_t,s) or zerotable end
+
+local p_numbersep = p_number_n + p_separator
+local p_numbers = p_optseparator * P("(") * p_numbersep^0 * p_optseparator * P(")")
+local p_fournumbers = p_numbersep^4
+local p_path = Ct ( (
+ p_command_xy * (p_optseparator * p_number_vx *
+ p_optseparator * p_number_vy )^1
+ + p_command_x * (p_optseparator * p_number_vx )^1
+ + p_command_y * (p_optseparator * p_number_vy )^1
+ + p_command_a * (p_optseparator * p_number_vx *
+ p_optseparator * p_number_vy *
+ p_optseparator * p_number_r *
+ p_optseparator * p_number_n * -- flags
+ p_optseparator * p_number_n * -- flags
+ p_optseparator * p_number_vx *
+ p_optseparator * p_number_vy )^1
+ + p_command
+ + p_separator
+)^1 )
+
+-- We can actually use the svg color definitions from the tex end but maybe a user
+-- doesn't want those replace the normal definitions.
+--
+-- local hexhash = setmetatableindex(function(t,k) local v = lpegmatch(p_hexcolor, k) t[k] = v return v end) -- per file
+-- local hexhash3 = setmetatableindex(function(t,k) local v = lpegmatch(p_hexcolor3,k) t[k] = v return v end) -- per file
+--
+-- local function hexcolor (c) return hexhash [c] end -- directly do hexhash [c]
+-- local function hexcolor3(c) return hexhash3[c] end -- directly do hexhash3[c]
+
+local rgbcomponents, withcolor, thecolor do
+
+ local svgcolors = {
+ aliceblue = 0xF0F8FF, antiquewhite = 0xFAEBD7, aqua = 0x00FFFF, aquamarine = 0x7FFFD4,
+ azure = 0xF0FFFF, beige = 0xF5F5DC, bisque = 0xFFE4C4, black = 0x000000,
+ blanchedalmond = 0xFFEBCD, blue = 0x0000FF, blueviolet = 0x8A2BE2, brown = 0xA52A2A,
+ burlywood = 0xDEB887, cadetblue = 0x5F9EA0, hartreuse = 0x7FFF00, chocolate = 0xD2691E,
+ coral = 0xFF7F50, cornflowerblue = 0x6495ED, cornsilk = 0xFFF8DC, crimson = 0xDC143C,
+ cyan = 0x00FFFF, darkblue = 0x00008B, darkcyan = 0x008B8B, darkgoldenrod = 0xB8860B,
+ darkgray = 0xA9A9A9, darkgreen = 0x006400, darkgrey = 0xA9A9A9, darkkhaki = 0xBDB76B,
+ darkmagenta = 0x8B008B, darkolivegreen = 0x556B2F, darkorange = 0xFF8C00, darkorchid = 0x9932CC,
+ darkred = 0x8B0000, darksalmon = 0xE9967A, darkseagreen = 0x8FBC8F, darkslateblue = 0x483D8B,
+ darkslategray = 0x2F4F4F, darkslategrey = 0x2F4F4F, darkturquoise = 0x00CED1, darkviolet = 0x9400D3,
+ deeppink = 0xFF1493, deepskyblue = 0x00BFFF, dimgray = 0x696969, dimgrey = 0x696969,
+ dodgerblue = 0x1E90FF, firebrick = 0xB22222, floralwhite = 0xFFFAF0, forestgreen = 0x228B22,
+ fuchsia = 0xFF00FF, gainsboro = 0xDCDCDC, ghostwhite = 0xF8F8FF, gold = 0xFFD700,
+ goldenrod = 0xDAA520, gray = 0x808080, green = 0x008000, greenyellow = 0xADFF2F,
+ grey = 0x808080, honeydew = 0xF0FFF0, hotpink = 0xFF69B4, indianred = 0xCD5C5C,
+ indigo = 0x4B0082, ivory = 0xFFFFF0, khaki = 0xF0E68C, lavender = 0xE6E6FA,
+ lavenderblush = 0xFFF0F5, lawngreen = 0x7CFC00, lemonchiffon = 0xFFFACD, lightblue = 0xADD8E6,
+ lightcoral = 0xF08080, lightcyan = 0xE0FFFF, lightgoldenrodyellow = 0xFAFAD2, lightgray = 0xD3D3D3,
+ lightgreen = 0x90EE90, lightgrey = 0xD3D3D3, lightpink = 0xFFB6C1, lightsalmon = 0xFFA07A,
+ lightseagreen = 0x20B2AA, lightskyblue = 0x87CEFA, lightslategray = 0x778899, lightslategrey = 0x778899,
+ lightsteelblue = 0xB0C4DE, lightyellow = 0xFFFFE0, lime = 0x00FF00, limegreen = 0x32CD32,
+ linen = 0xFAF0E6, magenta = 0xFF00FF, maroon = 0x800000, mediumaquamarine = 0x66CDAA,
+ mediumblue = 0x0000CD, mediumorchid = 0xBA55D3, mediumpurple = 0x9370DB, mediumseagreen = 0x3CB371,
+ mediumslateblue = 0x7B68EE, mediumspringgreen = 0x00FA9A, mediumturquoise = 0x48D1CC, mediumvioletred = 0xC71585,
+ midnightblue = 0x191970, mintcream = 0xF5FFFA, mistyrose = 0xFFE4E1, moccasin = 0xFFE4B5,
+ navajowhite = 0xFFDEAD, navy = 0x000080, oldlace = 0xFDF5E6, olive = 0x808000,
+ olivedrab = 0x6B8E23, orange = 0xFFA500, orangered = 0xFF4500, orchid = 0xDA70D6,
+ palegoldenrod = 0xEEE8AA, palegreen = 0x98FB98, paleturquoise = 0xAFEEEE, palevioletred = 0xDB7093,
+ papayawhip = 0xFFEFD5, peachpuff = 0xFFDAB9, peru = 0xCD853F, pink = 0xFFC0CB,
+ plum = 0xDDA0DD, powderblue = 0xB0E0E6, purple = 0x800080, red = 0xFF0000,
+ rosybrown = 0xBC8F8F, royalblue = 0x4169E1, saddlebrown = 0x8B4513, salmon = 0xFA8072,
+ sandybrown = 0xF4A460, seagreen = 0x2E8B57, seashell = 0xFFF5EE, sienna = 0xA0522D,
+ silver = 0xC0C0C0, skyblue = 0x87CEEB, slateblue = 0x6A5ACD, slategray = 0x708090,
+ slategrey = 0x708090, snow = 0xFFFAFA, springgreen = 0x00FF7F, steelblue = 0x4682B4,
+ tan = 0xD2B48C, teal = 0x008080, thistle = 0xD8BFD8, tomato = 0xFF6347,
+ turquoise = 0x40E0D0, violet = 0xEE82EE, wheat = 0xF5DEB3, white = 0xFFFFFF,
+ whitesmoke = 0xF5F5F5, yellow = 0xFFFF00, yellowgreen = 0x9ACD32,
+ }
+
+ local f_rgb = formatters['withcolor svgcolor(%.3N,%.3N,%.3N)']
+ local f_gray = formatters['withcolor svggray(%.3N)']
+ local f_rgba = formatters['withcolor svgcolor(%.3N,%.3N,%.3N) withtransparency (1,%.3N)']
+ local f_graya = formatters['withcolor svggray(%.3N) withtransparency (1,%.3N)']
+ local f_name = formatters['withcolor "%s"']
+ local f_svgcolor = formatters['svgcolor(%.3N,%.3N,%.3N)']
+ local f_svggray = formatters['svggray(%.3N)']
+ local f_svgname = formatters['"%s"']
+
+ local extract = bit32.extract
+
+ local triplets = setmetatableindex(function(t,k)
+ -- we delay building all these strings
+ local v = svgcolors[k]
+ if v then
+ v = { extract(v,16,8)/255, extract(v,8,8)/255, extract(v,0,8)/255 }
+ else
+ v = false
+ end
+ t[k] = v
+ return v
+ end)
+
+ local p_fraction = C(p_number) * C("%")^-1 / function(a,b)
+ a = tonumber(a) return a / (b and 100 or 255)
+ end
+ local p_hexcolor = P("#") * C(p_hexdigit*p_hexdigit)^1 / function(r,g,b)
+ return r and tonumber(r,16)/255 or nil, g and tonumber(g,16)/255 or nil, b and tonumber(b,16)/255 or nil
+ end
+ local p_rgbacolor = P("rgb") * (P("a")^-1) * P("(") * (p_fraction + p_separator)^1 * P(")")
+
+ rgbcomponents = function(color)
+ local h = lpegmatch(p_hexcolor,color)
+ if h then
+ return h
+ end
+ local r, g, b, a = lpegmatch(p_rgbacolor,color)
+ if r then
+ return r, g or r, b or r
+ end
+ local t = triplets[color]
+ return t[1], t[2], t[3]
+
+ end
+
+ withcolor = function(color)
+ local r, g, b = lpegmatch(p_hexcolor,color)
+ if b and not (r == g and g == b) then
+ return f_rgb(r,g,b)
+ elseif r then
+ return f_gray(r)
+ end
+ local r, g, b, a = lpegmatch(p_rgbacolor,color)
+ if a then
+ if a == 1 then
+ if r == g and g == b then
+ return f_gray(r)
+ else
+ return f_rgb(r,g,b)
+ end
+ else
+ if r == g and g == b then
+ return f_graya(r,a)
+ else
+ return f_rgba(r,g,b,a)
+ end
+ end
+ end
+ if not r then
+ local t = triplets[color]
+ if t then
+ r, g, b = t[1], t[2], t[3]
+ end
+ end
+ if r then
+ if r == g and g == b then
+ return f_gray(r)
+ elseif g and b then
+ return f_rgb(r,g,b)
+ else
+ return f_gray(r)
+ end
+ end
+ return f_name(color)
+ end
+
+ thecolor = function(color)
+ local h = lpegmatch(p_hexcolor,color)
+ if h then
+ return h
+ end
+ local r, g, b, a = lpegmatch(p_rgbacolor,color)
+ if not r then
+ local t = triplets[color]
+ if t then
+ r, g, b = t[1], t[2], t[3]
+ end
+ end
+ if r then
+ if r == g and g == b then
+ return f_svggray(r)
+ elseif g and b then
+ return f_svgcolor(r,g,b)
+ else
+ return f_svggray(r)
+ end
+ end
+ return f_svgname(color)
+ end
+
+end
+
+-- actually we can loop faster because we can go to the last one
+
+local grabpath, grablist do
+
+ local f_moveto = formatters['(%N,%N)']
+ local f_curveto_z = formatters['controls(%N,%N)and(%N,%N)..(%N,%N)']
+ local f_curveto_n = formatters['..controls(%N,%N)and(%N,%N)..(%N,%N)']
+ local f_lineto_z = formatters['(%N,%N)']
+ local f_lineto_n = formatters['--(%N,%N)']
+
+ local m = { __index = function() return 0 end }
+
+ grabpath = function(str)
+ local p = lpegmatch(p_path,str) or { }
+ local np = #p
+ local all = { entries = np, closed = false, curve = false }
+ if np == 0 then
+ return all
+ end
+ setmetatable(p,m)
+ local t = { } -- no real saving here if we share
+ local n = 0
+ local a = 0
+ local i = 0
+ local last = "M"
+ local prev = last
+ local kind = "L"
+ local x, y = 0, 0
+ local x1, y1 = 0, 0
+ local x2, y2 = 0, 0
+ local rx, ry = 0, 0
+ local ar, al = 0, 0
+ local as, ac = 0, nil
+ local mx, my = 0, 0
+ while i < np do
+ i = i + 1
+ local pi = p[i]
+ if type(pi) ~= "number" then
+ last = pi
+ i = i + 1
+ pi = p[i]
+ end
+ -- most often
+ if last == "c" then
+ x1 = x + pi
+ i = i + 1 ; y1 = y + p[i]
+ i = i + 1 ; x2 = x + p[i]
+ i = i + 1 ; y2 = y + p[i]
+ i = i + 1 ; x = x + p[i]
+ i = i + 1 ; y = y + p[i]
+ goto curveto
+ elseif last == "l" then
+ x = x + pi
+ i = i + 1 ; y = y + p[i]
+ goto lineto
+ elseif last == "h" then
+ x = x + pi
+ goto lineto
+ elseif last == "v" then
+ y = y + pi
+ goto lineto
+ elseif last == "a" then
+ x1 = x
+ y1 = y
+ rx = pi
+ i = i + 1 ; ry = p[i]
+ i = i + 1 ; ar = p[i]
+ i = i + 1 ; al = p[i]
+ i = i + 1 ; as = p[i]
+ i = i + 1 ; x = x + p[i]
+ i = i + 1 ; y = y + p[i]
+ goto arc
+ elseif last == "s" then
+ if prev == "C" then
+ x1 = 2 * x - x2
+ y1 = 2 * y - y2
+ else
+ x1 = x
+ y1 = y
+ end
+ x2 = x + pi
+ i = i + 1 ; y2 = y + p[i]
+ i = i + 1 ; x = x + p[i]
+ i = i + 1 ; y = y + p[i]
+ goto curveto
+ elseif last == "m" then
+ if n > 0 then
+ a = a + 1 ; all[a] = concat(t,"",1,n) ; n = 0
+ end
+ x = x + pi
+ i = i + 1 ; y = y + p[i]
+ goto moveto
+ elseif last == "z" then
+ goto close
+ -- less frequent
+ elseif last == "C" then
+ x1 = pi
+ i = i + 1 ; y1 = p[i]
+ i = i + 1 ; x2 = p[i]
+ i = i + 1 ; y2 = p[i]
+ i = i + 1 ; x = p[i]
+ i = i + 1 ; y = p[i]
+ goto curveto
+ elseif last == "L" then
+ x = pi
+ i = i + 1 ; y = p[i]
+ goto lineto
+ elseif last == "H" then
+ x = pi
+ goto lineto
+ elseif last == "V" then
+ y = pi
+ goto lineto
+ elseif last == "A" then
+ x1 = x
+ y1 = y
+ rx = pi
+ i = i + 1 ; ry = p[i]
+ i = i + 1 ; ar = p[i]
+ i = i + 1 ; al = p[i]
+ i = i + 1 ; as = p[i]
+ i = i + 1 ; x = p[i]
+ i = i + 1 ; y = p[i]
+ goto arc
+ elseif last == "S" then
+ if prev == "C" then
+ x1 = 2 * x - x2
+ y1 = 2 * y - y2
+ else
+ x1 = x
+ y1 = y
+ end
+ x2 = pi
+ i = i + 1 ; y2 = p[i]
+ i = i + 1 ; x = p[i]
+ i = i + 1 ; y = p[i]
+ goto curveto
+ elseif last == "M" then
+ if n > 0 then
+ a = a + 1 ; all[a] = concat(t,"",1,n) ; n = 0
+ end
+ x = pi ;
+ i = i + 1 ; y = p[i]
+ goto moveto
+ elseif last == "Z" then
+ goto close
+ -- very seldom
+ elseif last == "q" then
+ x1 = x + pi
+ i = i + 1 ; y1 = y + p[i]
+ i = i + 1 ; x2 = x + p[i]
+ i = i + 1 ; y2 = y + p[i]
+ goto quadratic
+ elseif last == "t" then
+ if prev == "C" then
+ x1 = 2 * x - x1
+ y1 = 2 * y - y1
+ else
+ x1 = x
+ y1 = y
+ end
+ x2 = x + pi
+ i = i + 1 ; y2 = y + p[i]
+ goto quadratic
+ elseif last == "Q" then
+ x1 = pi
+ i = i + 1 ; y1 = p[i]
+ i = i + 1 ; x2 = p[i]
+ i = i + 1 ; y2 = p[i]
+ goto quadratic
+ elseif last == "T" then
+ if prev == "C" then
+ x1 = 2 * x - x1
+ y1 = 2 * y - y1
+ else
+ x1 = x
+ y1 = y
+ end
+ x2 = pi
+ i = i + 1 ; y2 = p[i]
+ goto quadratic
+ else
+ goto continue
+ end
+ ::moveto::
+ n = n + 1 ; t[n] = f_moveto(x,y)
+ last = last == "M" and "L" or "l"
+ prev = "M"
+ mx = x
+ my = y
+ goto continue
+ ::lineto::
+ n = n + 1 ; t[n] = (n > 0 and f_lineto_n or f_lineto_z)(x,y)
+ prev = "L"
+ goto continue
+ ::curveto::
+ n = n + 1 ; t[n] = (n > 0 and f_curveto_n or f_curveto_z)(x1,y1,x2,y2,x,y)
+ prev = "C"
+ goto continue
+ ::arc::
+ ac = a2c(x1,y1,rx,ry,ar,al,as,x,y)
+ for i=1,#ac,6 do
+ n = n + 1 ; t[n] = (n > 0 and f_curveto_n or f_curveto_z)(
+ ac[i],ac[i+1],ac[i+2],ac[i+3],ac[i+4],ac[i+5]
+ )
+ end
+ prev = "A"
+ goto continue
+ ::quadratic::
+ n = n + 1 ; t[n] = (n > 0 and f_curveto_n or f_curveto_z)(
+ x + 2/3 * (x1-x ), y + 2/3 * (y1-y ),
+ x2 + 2/3 * (x1-x2), y2 + 2/3 * (y1-y2),
+ x2, y2
+ )
+ x = x2
+ y = y2
+ prev = "C"
+ goto continue
+ ::close::
+ -- n = n + 1 ; t[n] = prev == "C" and "..cycle" or "--cycle"
+ n = n + 1 ; t[n] = "--cycle"
+ if n > 0 then
+ a = a + 1 ; all[a] = concat(t,"",1,n) ; n = 0
+ end
+ if i == np then
+ break
+ else
+ i = i - 1
+ end
+ kind = prev
+ prev = "Z"
+ -- this is kind of undocumented: a close also moves back
+ x = mx
+ y = my
+ ::continue::
+ end
+ if n > 0 then
+ a = a + 1 ; all[a] = concat(t,"",1,n) ; n = 0
+ end
+ if prev == "Z" then
+ all.closed = true
+ end
+ all.curve = (kind == "C" or kind == "A")
+ return all, p
+ end
+
+ -- this is a bit tricky as what are points for a mark ... the next can be simplified
+ -- a lot
+
+ grablist = function(p)
+ local np = #p
+ if np == 0 then
+ return nil
+ end
+ local t = { }
+ local n = 0
+ local a = 0
+ local i = 0
+ local last = "M"
+ local prev = last
+ local kind = "L"
+ local x, y = 0, 0
+ local x1, y1 = 0, 0
+ local x2, y2 = 0, 0
+ local rx, ry = 0, 0
+ local ar, al = 0, 0
+ local as, ac = 0, nil
+ local mx, my = 0, 0
+ while i < np do
+ i = i + 1
+ local pi = p[i]
+ if type(pi) ~= "number" then
+ last = pi
+ i = i + 1
+ pi = p[i]
+ end
+ -- most often
+ if last == "c" then
+ x1 = x + pi
+ i = i + 1 ; y1 = y + p[i]
+ i = i + 1 ; x2 = x + p[i]
+ i = i + 1 ; y2 = y + p[i]
+ i = i + 1 ; x = x + p[i]
+ i = i + 1 ; y = y + p[i]
+ goto curveto
+ elseif last == "l" then
+ x = x + pi
+ i = i + 1 ; y = y + p[i]
+ goto lineto
+ elseif last == "h" then
+ x = x + pi
+ goto lineto
+ elseif last == "v" then
+ y = y + pi
+ goto lineto
+ elseif last == "a" then
+ x1 = x
+ y1 = y
+ rx = pi
+ i = i + 1 ; ry = p[i]
+ i = i + 1 ; ar = p[i]
+ i = i + 1 ; al = p[i]
+ i = i + 1 ; as = p[i]
+ i = i + 1 ; x = x + p[i]
+ i = i + 1 ; y = y + p[i]
+ goto arc
+ elseif last == "s" then
+ if prev == "C" then
+ x1 = 2 * x - x2
+ y1 = 2 * y - y2
+ else
+ x1 = x
+ y1 = y
+ end
+ x2 = x + pi
+ i = i + 1 ; y2 = y + p[i]
+ i = i + 1 ; x = x + p[i]
+ i = i + 1 ; y = y + p[i]
+ goto curveto
+ elseif last == "m" then
+ x = x + pi
+ i = i + 1 ; y = y + p[i]
+ goto moveto
+ elseif last == "z" then
+ goto close
+ -- less frequent
+ elseif last == "C" then
+ x1 = pi
+ i = i + 1 ; y1 = p[i]
+ i = i + 1 ; x2 = p[i]
+ i = i + 1 ; y2 = p[i]
+ i = i + 1 ; x = p[i]
+ i = i + 1 ; y = p[i]
+ goto curveto
+ elseif last == "L" then
+ x = pi
+ i = i + 1 ; y = p[i]
+ goto lineto
+ elseif last == "H" then
+ x = pi
+ goto lineto
+ elseif last == "V" then
+ y = pi
+ goto lineto
+ elseif last == "A" then
+ x1 = x
+ y1 = y
+ rx = pi
+ i = i + 1 ; ry = p[i]
+ i = i + 1 ; ar = p[i]
+ i = i + 1 ; al = p[i]
+ i = i + 1 ; as = p[i]
+ i = i + 1 ; x = p[i]
+ i = i + 1 ; y = p[i]
+ goto arc
+ elseif last == "S" then
+ if prev == "C" then
+ x1 = 2 * x - x2
+ y1 = 2 * y - y2
+ else
+ x1 = x
+ y1 = y
+ end
+ x2 = pi
+ i = i + 1 ; y2 = p[i]
+ i = i + 1 ; x = p[i]
+ i = i + 1 ; y = p[i]
+ goto curveto
+ elseif last == "M" then
+ x = pi ;
+ i = i + 1 ; y = p[i]
+ goto moveto
+ elseif last == "Z" then
+ goto close
+ -- very seldom
+ elseif last == "q" then
+ x1 = x + pi
+ i = i + 1 ; y1 = y + p[i]
+ i = i + 1 ; x2 = x + p[i]
+ i = i + 1 ; y2 = y + p[i]
+ goto quadratic
+ elseif last == "t" then
+ if prev == "C" then
+ x1 = 2 * x - x1
+ y1 = 2 * y - y1
+ else
+ x1 = x
+ y1 = y
+ end
+ x2 = x + pi
+ i = i + 1 ; y2 = y + p[i]
+ goto quadratic
+ elseif last == "Q" then
+ x1 = pi
+ i = i + 1 ; y1 = p[i]
+ i = i + 1 ; x2 = p[i]
+ i = i + 1 ; y2 = p[i]
+ goto quadratic
+ elseif last == "T" then
+ if prev == "C" then
+ x1 = 2 * x - x1
+ y1 = 2 * y - y1
+ else
+ x1 = x
+ y1 = y
+ end
+ x2 = pi
+ i = i + 1 ; y2 = p[i]
+ goto quadratic
+ else
+ goto continue
+ end
+ ::moveto::
+ n = n + 1 ; t[n] = x
+ n = n + 1 ; t[n] = y
+ last = last == "M" and "L" or "l"
+ prev = "M"
+ mx = x
+ my = y
+ goto continue
+ ::lineto::
+ n = n + 1 ; t[n] = x
+ n = n + 1 ; t[n] = y
+ prev = "L"
+ goto continue
+ ::curveto::
+ n = n + 1 ; t[n] = x
+ n = n + 1 ; t[n] = y
+ prev = "C"
+ goto continue
+ ::arc::
+ ac = a2c(x1,y1,rx,ry,ar,al,as,x,y)
+ for i=1,#ac,6 do
+ n = n + 1 ; t[n] = ac[i+4]
+ n = n + 1 ; t[n] = ac[i+5]
+ end
+ prev = "A"
+ goto continue
+ ::quadratic::
+ n = n + 1 ; t[n] = x2
+ n = n + 1 ; t[n] = y2
+ x = x2
+ y = y2
+ prev = "C"
+ goto continue
+ ::close::
+ n = n + 1 ; t[n] = mx
+ n = n + 1 ; t[n] = my
+ if i == np then
+ break
+ end
+ kind = prev
+ prev = "Z"
+ x = mx
+ y = my
+ ::continue::
+ end
+ return t
+ end
+
+end
+
+-- todo: viewbox helper
+
+local s_wrapped_start = "draw image ("
+local f_wrapped_stop = formatters[") shifted (0,%N) scaled %N ;"]
+
+local handletransform, handleviewbox do
+
+ local sind = math.sind
+
+ --todo: better lpeg
+
+ local f_rotatedaround = formatters[" rotatedaround((%N,%N),%N)"]
+ local f_rotated = formatters[" rotated(%N)"]
+ local f_shifted = formatters[" shifted(%N,%N)"]
+ local f_slanted_x = formatters[" xslanted(%N)"]
+ local f_slanted_y = formatters[" yslanted(%N)"]
+ local f_scaled = formatters[" scaled(%N)"]
+ local f_xyscaled = formatters[" xyscaled(%N,%N)"]
+ local f_matrix = formatters[" transformed bymatrix(%N,%N,%N,%N,%N,%N)"]
+
+ local s_transform_start = "draw image ( "
+ local f_transform_stop = formatters[")%s ;"]
+
+ local function rotate(r,x,y)
+ if x then
+ return r and f_rotatedaround(x,-(y or x),-r)
+ elseif r then
+ return f_rotated(-r)
+ else
+ return ""
+ end
+ end
+
+ local function translate(x,y)
+ if y then
+ return f_shifted(x,-y)
+ elseif x then
+ return f_shifted(x,0)
+ else
+ return ""
+ end
+ end
+
+ local function scale(x,y)
+ if y then
+ return f_xyscaled(x,y)
+ elseif x then
+ return f_scaled(x)
+ else
+ return ""
+ end
+ end
+
+ local function skewx(x)
+ if x then
+ return f_slanted_x(sind(-x))
+ else
+ return ""
+ end
+ end
+
+ local function skewy(y)
+ if y then
+ return f_slanted_y(sind(-y))
+ else
+ return ""
+ end
+ end
+
+ local function matrix(rx,sx,sy,ry,tx,ty)
+ return f_matrix(rx or 1, sx or 0, sy or 0, ry or 1, tx or 0, - (ty or 0))
+ end
+
+ -- How to deal with units here? Anyway, order seems to matter.
+
+ local p_transform = Cf ( Ct("") * (
+ lpegpatterns.whitespace^0 * Cg(
+ C("translate") * (p_numbers / translate) -- maybe xy
+ + C("scale") * (p_numbers / scale)
+ + C("rotate") * (p_numbers / rotate)
+ + C("matrix") * (p_numbers / matrix)
+ + C("skewX") * (p_numbers / skewx)
+ + C("skewY") * (p_numbers / skewy)
+ )
+ )^1, rawset)
+
+ handletransform = function(at)
+ local t = at.transform
+ if t then
+ local e = lpegmatch(p_transform,t)
+ if e then
+ e = concat({
+ e.rotate or "",
+ e.skewX or "",
+ e.skewY or "",
+ e.scale or "",
+ e.translate or "",
+ e.matrix or "",
+ }, " ")
+ return s_transform_start, f_transform_stop(e), t
+ end
+ end
+ end
+
+ handleviewbox = function(v)
+ if v then
+ local x, y, w, h = lpegmatch(p_fournumbers,v)
+ if h then
+ return x, y, w, h
+ end
+ end
+ end
+
+end
+
+local dashed do
+
+ -- actually commas are mandate but we're tolerant
+
+ local f_dashed_n = formatters[" dashed dashpattern (%s ) "]
+ local f_dashed_y = formatters[" dashed dashpattern (%s ) shifted (%N,0) "]
+
+ local p_number = p_optseparator/"" * p_number_r
+ local p_on = Cc(" on ") * p_number
+ local p_off = Cc(" off ") * p_number
+ local p_dashed = Cs((p_on * p_off^-1)^1)
+
+ dashed = function(s,o)
+ if not find(s,",") then
+ -- a bit of a hack:
+ s = s .. " " .. s
+ end
+ return (o and f_dashed_y or f_dashed_n)(lpegmatch(p_dashed,s),o)
+ end
+
+end
+
+do
+
+ local handlers = { }
+ local process = false
+ local root = false
+ local result = false
+ local r = false
+ local definitions = false
+ local classstyles = false
+ local tagstyles = false
+
+ local tags = {
+ ["a"] = true,
+ -- ["altgGlyph"] = true,
+ -- ["altgGlyphDef"] = true,
+ -- ["altgGlyphItem"] = true,
+ -- ["animate"] = true,
+ -- ["animateColor"] = true,
+ -- ["animateMotion"] = true,
+ -- ["animateTransform"] = true,
+ ["circle"] = true,
+ ["clipPath"] = true,
+ -- ["color-profile"] = true,
+ -- ["cursor"] = true,
+ ["defs"] = true,
+ -- ["desc"] = true,
+ ["ellipse"] = true,
+ -- ["filter"] = true,
+ -- ["font"] = true,
+ -- ["font-face"] = true,
+ -- ["font-face-format"] = true,
+ -- ["font-face-name"] = true,
+ -- ["font-face-src"] = true,
+ -- ["font-face-uri"] = true,
+ -- ["foreignObject"] = true,
+ ["g"] = true,
+ -- ["glyph"] = true,
+ -- ["glyphRef"] = true,
+ -- ["hkern"] = true,
+ ["image"] = true,
+ ["line"] = true,
+ ["linearGradient"] = true,
+ ["marker"] = true,
+ -- ["mask"] = true,
+ -- ["metadata"] = true,
+ -- ["missing-glyph"] = true,
+ -- ["mpath"] = true,
+ ["path"] = true,
+ -- ["pattern"] = true,
+ ["polygon"] = true,
+ ["polyline"] = true,
+ ["radialGradient"] = true,
+ ["rect"] = true,
+ -- ["script"] = true,
+ -- ["set"] = true,
+ ["stop"] = true,
+ ["style"] = true,
+ ["svg"] = true,
+ -- ["switch"] = true,
+ ["symbol"] = true,
+ ["text"] = true,
+ -- ["textPath"] = true,
+ -- ["title"] = true,
+ ["tspan"] = true,
+ ["use"] = true,
+ -- ["view"] = true,
+ -- ["vkern"] = true,
+ }
+
+ local function handlechains(c)
+ if tags[c.tg] then
+ local at = c.at
+ local dt = c.dt
+ if at and dt then
+ -- at["inkscape:connector-curvature"] = nil -- cleare entry and might prevent table growth
+ local estyle = rawget(at,"style")
+ if estyle and estyle ~= "" then
+ for k, v in gmatch(estyle,"%s*([^:]+):%s*([^;]+);?") do
+ at[k] = v
+ end
+ end
+ local eclass = rawget(at,"class")
+ if eclass and eclass ~= "" then
+ for c in gmatch(eclass,"[^ ]+") do
+ local s = classstyles[c]
+ if s then
+ for k, v in next, s do
+ at[k] = v
+ end
+ end
+ end
+ end
+ local tstyle = tagstyles[tag]
+ if tstyle then
+ for k, v in next, tstyle do
+ at[k] = v
+ end
+ end
+ if trace_path and pathtracer then
+ for k, v in next, pathtracer do
+ at[k] = v
+ end
+ end
+ for i=1,#dt do
+ local dti = dt[i]
+ if type(dti) == "table" then
+ handlechains(dti)
+ end
+ end
+ end
+ end
+ end
+
+ local handlestyle do
+
+ -- It can also be CDATA but that is probably dealt with because we only
+ -- check for style entries and ignore the rest. But maybe we also need
+ -- to check a style at the outer level?
+
+ local p_key = C((R("az","AZ","09","__","--")^1))
+ local p_spec = P("{") * C((1-P("}"))^1) * P("}")
+ local p_valid = Carg(1) * P(".") * p_key + Carg(2) * p_key
+ local p_grab = ((p_valid * p_space^0 * p_spec / rawset) + p_space^1 + P(1))^1
+
+ local fontspecification = css.fontspecification
+
+ handlestyle = function(c)
+ local s = xmltext(c)
+ lpegmatch(p_grab,s,1,classstyles,tagstyles)
+ for k, v in next, classstyles do
+ local t = { }
+ for k, v in gmatch(v,"%s*([^:]+):%s*([^;]+);?") do
+ if k == "font" then
+ local s = fontspecification(v)
+ for k, v in next, s do
+ t["font-"..k] = v
+ end
+ else
+ t[k] = v
+ end
+ end
+ classstyles[k] = t
+ end
+ for k, v in next, tagstyles do
+ local t = { }
+ for k, v in gmatch(v,"%s*([^:]+):%s*([^;]+);?") do
+ if k == "font" then
+ local s = fontspecification(v)
+ for k, v in next, s do
+ t["font-"..k] = v
+ end
+ else
+ t[k] = v
+ end
+ end
+ tagstyles[k] = t
+ end
+ end
+
+ function handlers.style()
+ -- ignore
+ end
+
+ end
+
+ -- We can have root in definitions and then do a metatable lookup but use
+ -- is not used that often I guess.
+
+ local function locate(id)
+ local res = definitions[id]
+ if res then
+ return res
+ end
+ local ref = gsub(id,"^url%(#(.-)%)$","%1")
+ local ref = gsub(ref,"^#","")
+ -- we can make a fast id lookup
+ local res = xmlfirst(root,"**[@id='"..ref.."']")
+ if res then
+ definitions[id] = res
+ end
+ return res
+ end
+
+ -- also locate
+
+ local function handleclippath(at)
+ local clippath = at["clip-path"]
+
+ if not clippath then
+ return
+ end
+
+ local spec = definitions[clippath] or locate(clippath)
+
+ -- do we really need thsi crap
+ if not spec then
+ local index = match(clippath,"(%d+)")
+ if index then
+ spec = xmlfirst(root,"clipPath["..tostring(tonumber(index) or 0).."]")
+ end
+ end
+ -- so far for the crap
+
+ if not spec then
+ report("unknown clip %a",clippath)
+ return
+ elseif spec.tg ~= "clipPath" then
+ report("bad clip %a",clippath)
+ return
+ end
+
+ ::again::
+ for c in xmlcollected(spec,"/(path|use|g)") do
+ local tg = c.tg
+ if tg == "use" then
+ local ca = c.at
+ local id = ca["xlink:href"]
+ if id then
+ spec = locate(id)
+ if spec then
+ local sa = spec.at
+ setmetatableindex(sa,ca)
+ if spec.tg == "path" then
+ local d = sa.d
+ if d then
+ local p = grabpath(d)
+ p.evenodd = sa["clip-rule"] == "evenodd"
+ p.close = true
+ return p, clippath
+ else
+ return
+ end
+ else
+ goto again
+ end
+ end
+ end
+ -- break
+ elseif tg == "path" then
+ local ca = c.at
+ local d = ca.d
+ if d then
+ local p = grabpath(d)
+ p.evenodd = ca["clip-rule"] == "evenodd"
+ p.close = true
+ return p, clippath
+ else
+ return
+ end
+ else
+ -- inherit?
+ end
+ end
+ end
+
+ local s_shade_linear = ' withshademethod "linear" '
+ local s_shade_circular = ' withshademethod "circular" '
+ local f_shade_step = formatters['withshadestep ( withshadefraction %N withshadecolors(%s,%s) )']
+ local f_shade_one = formatters['withprescript "sh_center_a=%N %N"']
+ local f_shade_two = formatters['withprescript "sh_center_b=%N %N"']
+
+ local f_color = formatters['withcolor "%s"']
+ local f_opacity = formatters['withtransparency (1,%N)']
+ local f_pen = formatters['withpen pencircle scaled %N']
+
+ -- todo: gradient unfinished
+ -- todo: opacity but first we need groups in mp
+
+ local function gradient(id)
+ local spec = definitions[id] -- no locate !
+ if spec then
+ local kind = spec.tg
+ local shade = nil
+ local n = 1
+ local a = spec.at
+ if kind == "linearGradient" then
+ shade = { s_shade_linear }
+ --
+ local x1 = rawget(a,"x1")
+ local y1 = rawget(a,"y1")
+ local x2 = rawget(a,"x2")
+ local y2 = rawget(a,"y2")
+ if x1 and y1 then
+ n = n + 1 ; shade[n] = f_shade_one(asnumber_vx(x1),asnumber_vy(y1))
+ end
+ if x2 and y2 then
+ n = n + 1 ; shade[n] = f_shade_one(asnumber_vx(x2),asnumber_vy(y2))
+ end
+ --
+ elseif kind == "radialGradient" then
+ shade = { s_shade_circular }
+ --
+ local cx = rawget(a,"cx") -- x center
+ local cy = rawget(a,"cy") -- y center
+ local r = rawget(a,"r" ) -- radius
+ local fx = rawget(a,"fx") -- focal points
+ local fy = rawget(a,"fy") -- focal points
+ --
+ if cx and cy then
+ -- todo
+ end
+ if r then
+ -- todo
+ end
+ if fx and fy then
+ -- todo
+ end
+ else
+ report("unknown gradient %a",id)
+ return
+ end
+ -- local gu = a.gradientUnits
+ -- local gt = a.gradientTransform
+ -- local sm = a.spreadMethod
+ local colora, colorb
+ -- startcolor ?
+ for c in xmlcollected(spec,"/stop") do
+ local a = c.at
+ local offset = rawget(a,"offset")
+ local colorb = rawget(a,"stop-color")
+ local opacity = rawget(a,"stop-opacity")
+ if colorb then
+ colorb = thecolor(colorb)
+ end
+ if not colora then
+ colora = colorb
+ end
+ -- what if no percentage
+
+ local fraction = offset and asnumber_r(offset)
+ if not fraction then
+ -- offset = tonumber(offset)
+ -- for now
+ fraction = xmlcount(spec,"/stop")/100
+ end
+
+ if colora and colorb and color_a ~= "" and color_b ~= "" then
+ n = n + 1 ; shade[n] = f_shade_step(fraction,colora,colorb)
+ end
+
+ colora = colorb
+ end
+ return concat(shade," ")
+ end
+ end
+
+ local function drawproperties(stroke,at,opacity)
+ local p = at["stroke-width"]
+ if p then
+ p = f_pen(asnumber_r(p))
+ end
+ local d = at["stroke-dasharray"]
+ if d == "none" then
+ d = nil
+ elseif d then
+ local o = at["stroke-dashoffset"]
+ if o and o ~= "none" then
+ o = asnumber_r(o)
+ else
+ o = false
+ end
+ d = dashed(d,o)
+ end
+ local c = withcolor(stroke)
+ local o = at["stroke-opacity"] or (opacity and at["opacity"])
+ if o == "none" then
+ o = nil
+ elseif o then
+ o = asnumber_r(o)
+ if o and o ~= 1 then
+ o = f_opacity(o)
+ else
+ o = nil
+ end
+ end
+ return p, d, c, o
+ end
+
+ local s_opacity_start = "draw image ("
+ local f_opacity_stop = formatters["setgroup currentpicture to boundingbox currentpicture withtransparency (1,%N)) ;"]
+
+ local function sharedopacity(at)
+ local o = at["opacity"]
+ if o and o ~= "none" then
+ o = asnumber_r(o)
+ if o and o ~= 1 then
+ return s_opacity_start, f_opacity_stop(o)
+ end
+ end
+ end
+
+ local function fillproperties(fill,at,opacity)
+ local c = c ~= "none" and (gradient(fill) or withcolor(fill)) or nil
+ local o = at["fill-opacity"] or (opacity and at["opacity"])
+ if o and o ~= "none" then
+ o = asnumber_r(o)
+ if o == 1 then
+ return c
+ elseif o then
+ return c, f_opacity(o), o == 0
+ end
+ end
+ return c
+ end
+
+ -- todo: clip = [ auto | rect(llx,lly,urx,ury) ]
+
+ local s_offset_start = "draw image ( "
+ local f_offset_stop = formatters[") shifted (%N,%N) ;"]
+ local s_rotation_start = "draw image ( "
+ local f_rotation_stop = formatters[") rotatedaround((0,0),-angle((%N,%N))) ;"]
+ local f_rotation_angle = formatters[") rotatedaround((0,0),-%N) ;"]
+
+ local function offset(at)
+ local x = asnumber_vx(rawget(at,"x"))
+ local y = asnumber_vy(rawget(at,"y"))
+ if x ~= 0 or y ~= 0 then
+ return s_offset_start, f_offset_stop(x,y)
+ end
+ end
+
+ local s_viewport_start = "draw image ("
+ local s_viewport_stop = ") ;"
+ local f_viewport_shift = formatters["currentpicture := currentpicture shifted (%03N,%03N);"]
+ local f_viewport_scale = formatters["currentpicture := currentpicture xysized (%03N,%03N);"]
+ local f_viewport_clip = formatters["clip currentpicture to (unitsquare xyscaled (%03N,%03N));"]
+
+ local function viewport(x,y,w,h,noclip,scale)
+ r = r + 1 ; result[r] = s_viewport_start
+ return function()
+ local okay = w ~= 0 and h ~= 0
+ if okay and scale then
+ r = r + 1 ; result[r] = f_viewport_scale(w,h)
+ end
+ if x ~= 0 or y ~= 0 then
+ r = r + 1 ; result[r] = f_viewport_shift(-x,y)
+ end
+ if okay and not noclip then
+ r = r + 1 ; result[r] = f_viewport_clip(w,-h)
+ end
+
+ r = r + 1 ; result[r] = s_viewport_stop
+ end
+ end
+
+ -- maybe forget about defs and just always locate (and then backtrack
+ -- over <g> if needed)
+
+ function handlers.defs(c)
+ for c in xmlcollected(c,"/*") do
+ local a = c.at
+ if a then
+ local id = rawget(a,"id")
+ if id then
+ definitions["#" .. id ] = c
+ definitions["url(#" .. id .. ")"] = c
+ end
+ end
+ end
+ end
+
+ function handlers.symbol(c)
+ if uselevel == 0 then
+ local id = rawget(c.at,"id")
+ if id then
+ definitions["#" .. id ] = c
+ definitions["url(#" .. id .. ")"] = c
+ end
+ else
+ handlers.g(c)
+ end
+ end
+
+ local uselevel = 0
+
+ function handlers.use(c)
+ local at = c.at
+ local id = rawget(at,"href") or rawget(at,"xlink:href") -- better a rawget
+ local res = locate(id)
+ if res then
+ -- width height ?
+ uselevel = uselevel + 1
+ local boffset, eoffset = offset(at)
+ local btransform, etransform, transform = handletransform(at)
+
+ if boffset then
+ r = r + 1 result[r] = boffset
+ end
+
+ -- local clippath = at.clippath
+
+ if btransform then
+ r = r + 1 result[r] = btransform
+ end
+
+ local _transform = transform
+ local _clippath = clippath
+ at["transform"] = false
+ -- at["clip-path"] = false
+
+ process(res,"/*")
+
+ at["transform"] = _transform
+ -- at["clip-path"] = _clippath
+
+ if etransform then
+ r = r + 1 ; result[r] = etransform
+ end
+
+ if eoffset then
+ r = r + 1 result[r] = eoffset
+ end
+
+ uselevel = uselevel - 1
+ else
+ report("use: unknown definition %a",id)
+ end
+ end
+
+ local f_no_draw = formatters['nodraw (%s)']
+ local f_do_draw = formatters['draw (%s)']
+ local f_no_fill_c = formatters['nofill (%s..cycle)']
+ local f_do_fill_c = formatters['fill (%s..cycle)']
+ local f_eo_fill_c = formatters['eofill (%s..cycle)']
+ local f_no_fill_l = formatters['nofill (%s--cycle)']
+ local f_do_fill_l = formatters['fill (%s--cycle)']
+ local f_eo_fill_l = formatters['eofill (%s--cycle)']
+ local f_do_fill = f_do_fill_c
+ local f_eo_fill = f_eo_fill_c
+ local f_no_fill = f_no_fill_c
+ local s_clip_start = 'draw image ('
+ local f_clip_stop_c = formatters[') ; clip currentpicture to (%s..cycle) ;']
+ local f_clip_stop_l = formatters[') ; clip currentpicture to (%s--cycle) ;']
+ local f_clip_stop = f_clip_stop_c
+ local f_eoclip_stop_c = formatters[') ; eoclip currentpicture to (%s..cycle) ;']
+ local f_eoclip_stop_l = formatters[') ; eoclip currentpicture to (%s--cycle) ;']
+ local f_eoclip_stop = f_eoclip_stop_c
+
+ -- could be shared and then beginobject | endobject
+
+ local function flushobject(object,at,c,o)
+ local btransform, etransform = handletransform(at)
+ local cpath = handleclippath(at)
+
+ if cpath then
+ r = r + 1 ; result[r] = s_clip_start
+ end
+
+ if btransform then
+ r = r + 1 ; result[r] = btransform
+ end
+
+ r = r + 1 ; result[r] = f_do_draw(object)
+
+ if c then
+ r = r + 1 ; result[r] = c
+ end
+
+ if o then
+ r = r + 1 ; result[r] = o
+ end
+
+ if etransform then
+ r = r + 1 ; result[r] = etransform
+ end
+
+ r = r + 1 ; result[r] = ";"
+
+ if cpath then
+ local f_done = cpath.evenodd
+ if cpath.curve then
+ f_done = f_done and f_eoclip_stop_c or f_clip_stop_c
+ else
+ f_done = f_done and f_eoclip_stop_l or f_clip_stop_l
+ end
+ r = r + 1 ; result[r] = f_done(cpath[1])
+ end
+ end
+
+ do
+
+ local flush
+
+ local f_linecap = formatters["interim linecap := %s ;"]
+ local f_linejoin = formatters["interim linejoin := %s ;"]
+ local f_miterlimit = formatters["interim miterlimit := %s ;"]
+
+ local s_begingroup = "begingroup;"
+ local s_endgroup = "endgroup;"
+
+ local linecaps = { butt = "butt", square = "squared", round = "rounded" }
+ local linejoins = { miter = "mitered", bevel = "beveled", round = "rounded" }
+
+ local function startlineproperties(at)
+ local cap = at["stroke-linecap"]
+ local join = at["stroke-linejoin"]
+ local limit = at["stroke-miterlimit"]
+ cap = cap and linecaps [cap]
+ join = join and linejoins[join]
+ limit = limit and asnumber_r(limit)
+ if cap or join or limit then
+ r = r + 1 ; result[r] = s_begingroup
+ if cap then
+ r = r + 1 ; result[r] = f_linecap(cap)
+ end
+ if join then
+ r = r + 1 ; result[r] = f_linejoin(join)
+ end
+ if limit then
+ r = r + 1 ; result[r] = f_miterlimit(limit)
+ end
+ return function()
+ at["stroke-linecap"] = false
+ at["stroke-linejoin"] = false
+ at["stroke-miterlimit"] = false
+ r = r + 1 ; result[r] = s_endgroup
+ at["stroke-linecap"] = cap
+ at["stroke-linejoin"] = join
+ at["stroke-miterlimit"] = limit
+ end
+ end
+ end
+
+ -- markers are a quite rediculous thing .. let's assume simple usage for now
+
+ function handlers.marker()
+ -- todo: is just a def too
+ end
+
+ -- kind of local svg ... so make a generic one
+ --
+ -- todo: combine more (offset+scale+rotation)
+
+ local function makemarker(where,c,x1,y1,x2,y2,x3,y3)
+ local at = c.at
+ local refx = rawget(at,"refX")
+ local refy = rawget(at,"refY")
+ local width = rawget(at,"markerWidth")
+ local height = rawget(at,"markerHeight")
+ local view = rawget(at,"viewBox")
+ local orient = rawget(at,"orient")
+ -- local ratio = rawget(at,"preserveAspectRatio")
+ local units = at["markerUnits"]
+ local height = at["markerHeight"]
+ local angx = 0
+ local angy = 0
+ local angle = 0
+
+ if where == "beg" then
+ if orient == "auto" then -- unchecked
+ -- no angle
+ angx = x2 - x3
+ angy = y2 - y3
+ elseif orient == "auto-start-reverse" then -- checked
+ -- points to start
+ angx = x3 - x2
+ angy = y3 - y2
+ elseif orient then -- unchecked
+ angle = asnumber_r(orient)
+ end
+ elseif where == "end" then
+ if orient == "auto" then -- unchecked
+ -- no angle ?
+ angx = x1 - x2
+ angy = y1 - y2
+ elseif orient == "auto-start-reverse" then -- unchecked
+ -- points to end
+ angx = x2 - x1
+ angy = y2 - y1
+ elseif orient then -- unchecked
+ angle = asnumber_r(orient)
+ end
+ elseif orient then -- unchecked
+ angle = asnumber_r(orient)
+ end
+
+ -- what wins: viewbox or w/h
+
+ refx = asnumber_x(refx)
+ refy = asnumber_y(refy)
+
+ width = width and asnumber_x(width) or 3 -- defaults
+ height = height and asnumber_y(height) or 3 -- defaults
+
+ local x = 0
+ local y = 0
+ local w = width
+ local h = height
+
+ -- kind of like the main svg
+
+ r = r + 1 ; result[r] = s_offset_start
+
+ local wrapupviewport
+-- todo : better viewbox code
+ local xpct, ypct, rpct
+ if view then
+ x, y, w, h = handleviewbox(view)
+ end
+
+ if width ~= 0 then
+ w = width
+ end
+ if height ~= 0 then
+ h = height
+ end
+
+ if h then
+ xpct = percentage_x
+ ypct = percentage_y
+ rpct = percentage_r
+ percentage_x = w / 100
+ percentage_y = h / 100
+ percentage_r = (sqrt(w^2 + h^2) / sqrt(2)) / 100
+ wrapupviewport = viewport(x,y,w,h,true,true) -- no clip
+ end
+
+ -- we can combine a lot here:
+
+ local hasref = refx ~= 0 or refy ~= 0
+ local hasrot = angx ~= 0 or angy ~= 0 or angle ~= 0
+
+ local btransform, etransform, transform = handletransform(at)
+
+ if btransform then
+ r = r + 1 ; result[r] = btransform
+ end
+
+ if hasrot then
+ r = r + 1 ; result[r] = s_rotation_start
+ end
+
+ if hasref then
+ r = r + 1 ; result[r] = s_offset_start
+ end
+
+ local _transform = transform
+ at["transform"] = false
+
+ handlers.g(c)
+
+ at["transform"] = _transform
+
+ if hasref then
+ r = r + 1 ; result[r] = f_offset_stop(-refx,refy)
+ end
+
+ if hasrot then
+ if angle ~= 0 then
+ r = r + 1 ; result[r] = f_rotation_angle(angle)
+ else
+ r = r + 1 ; result[r] = f_rotation_stop(angx,angy)
+ end
+ end
+
+ if etransform then
+ r = r + 1 ; result[r] = etransform
+ end
+
+ if h then
+ percentage_x = xpct
+ percentage_y = ypct
+ percentage_r = rpct
+ if wrapupviewport then
+ wrapupviewport()
+ end
+ end
+ r = r + 1 ; result[r] = f_offset_stop(x2,y2)
+
+ end
+
+ local function addmarkers(list,begmarker,midmarker,endmarker)
+ local n = #list
+ if n > 3 then
+ if begmarker then
+ local m = locate(begmarker)
+ if m then
+ makemarker("beg",m,false,false,list[1],list[2],list[3],list[4])
+ end
+ end
+ if midmarker then
+ local m = locate(midmarker)
+ if m then
+ for i=3,n-2,2 do
+ makemarker("mid",m,list[i-2],list[i-1],list[i],list[i+1],list[i+2],list[i+3])
+ end
+ end
+ end
+ if endmarker then
+ local m = locate(endmarker)
+ if m then
+ makemarker("end",m,list[n-3],list[n-2],list[n-1],list[n],false,false)
+ end
+ end
+ else
+ -- no line
+ end
+ end
+
+ local function flush(shape,dofill,at,list,begmarker,midmarker,endmarker)
+
+ local fill = dofill and (at["fill"] or "black")
+ local stroke = at["stroke"] or "none"
+
+ local btransform, etransform = handletransform(at)
+ local cpath = handleclippath(at)
+
+ if cpath then
+ r = r + 1 ; result[r] = s_clip_start
+ end
+
+ local has_stroke = stroke and stroke ~= "none"
+ local has_fill = fill and fill ~= "none"
+
+ local bopacity, eopacity
+ if has_stroke and has_fill then
+ bopacity, eopacity = sharedopacity(at)
+ end
+
+ if bopacity then
+ r = r + 1 ; result[r] = bopacity
+ end
+
+ if has_fill then
+ local color, opacity = fillproperties(fill,at,not has_stroke)
+ local f_xx_fill = at["fill-rule"] == "evenodd" and f_eo_fill or f_do_fill
+ if btransform then
+ r = r + 1 ; result[r] = btransform
+ end
+ r = r + 1 result[r] = f_xx_fill(shape)
+ if color then
+ r = r + 1 ; result[r] = color
+ end
+ if opacity then
+ r = r + 1 ; result[r] = opacity
+ end
+ r = r + 1 ; result[r] = etransform or ";"
+ end
+
+ if has_stroke then
+ local wrapup = startlineproperties(at)
+ local pen, dashing, color, opacity = drawproperties(stroke,at,not has_fill)
+ if btransform then
+ r = r + 1 ; result[r] = btransform
+ end
+ r = r + 1 ; result[r] = f_do_draw(shape)
+ if pen then
+ r = r + 1 ; result[r] = pen
+ end
+ if dashing then
+ r = r + 1 ; result[r] = dashing
+ end
+ if color then
+ r = r + 1 ; result[r] = color
+ end
+ if opacity then
+ r = r + 1 ; result[r] = opacity
+ end
+ r = r + 1 ; result[r] = etransform or ";"
+ --
+ if list then
+ addmarkers(list,begmarker,midmarker,endmarker)
+ end
+ --
+ if wrapup then
+ wrapup()
+ end
+ end
+
+ if eopacity then
+ r = r + 1 ; result[r] = eopacity
+ end
+
+ if cpath then
+ r = r + 1 ; result[r] = (cpath.evenodd and f_eoclip_stop or f_clip_stop)(cpath[1])
+ end
+
+ end
+
+ local f_rectangle = formatters['unitsquare xyscaled (%N,%N) shifted (%N,%N)']
+ local f_rounded = formatters['roundedsquarexy(%N,%N,%N,%N) shifted (%N,%N)']
+ local f_line = formatters['((%N,%N)--(%N,%N))']
+ local f_ellipse = formatters['(fullcircle xyscaled (%N,%N) shifted (%N,%N))']
+ local f_circle = formatters['(fullcircle scaled %N shifted (%N,%N))']
+
+ function handlers.line(c)
+ local at = c.at
+ local x1 = rawget(at,"x1")
+ local y1 = rawget(at,"y1")
+ local x2 = rawget(at,"x2")
+ local y2 = rawget(at,"y2")
+
+ x1 = x1 and asnumber_vx(x1) or 0
+ y1 = y1 and asnumber_vy(y1) or 0
+ x2 = x2 and asnumber_vx(x2) or 0
+ y2 = y2 and asnumber_vy(y2) or 0
+
+ flush(f_line(x1,y1,x2,y2),false,at)
+ end
+
+ function handlers.rect(c)
+ local at = c.at
+ local width = rawget(at,"width")
+ local height = rawget(at,"height")
+ local x = rawget(at,"x")
+ local y = rawget(at,"y")
+ local rx = rawget(at,"rx")
+ local ry = rawget(at,"ry")
+
+ width = width and asnumber_x(width) or 0
+ height = height and asnumber_y(height) or 0
+ x = x and asnumber_vx(x) or 0
+ y = y and asnumber_vy(y) or 0
+
+ y = y - height
+
+ if rx then rx = asnumber(rx) end
+ if ry then ry = asnumber(ry) end
+
+ if rx or ry then
+ if not rx then rx = ry end
+ if not ry then ry = rx end
+ flush(f_rounded(width,height,rx,ry,x,y),true,at)
+ else
+ flush(f_rectangle(width,height,x,y),true,at)
+ end
+ end
+
+ function handlers.ellipse(c)
+ local at = c.at
+ local cx = rawget(at,"cx")
+ local cy = rawget(at,"cy")
+ local rx = rawget(at,"rx")
+ local ry = rawget(at,"ry")
+
+ cx = cx and asnumber_vx(cx) or 0
+ cy = cy and asnumber_vy(cy) or 0
+ rx = rx and asnumber_r (rx) or 0
+ ry = ry and asnumber_r (ry) or 0
+
+ flush(f_ellipse(2*rx,2*ry,cx,cy),true,at)
+ end
+
+ function handlers.circle(c)
+ local at = c.at
+ local cx = rawget(at,"cx")
+ local cy = rawget(at,"cy")
+ local r = rawget(at,"r")
+
+ cx = cx and asnumber_vx(cx) or 0
+ cy = cy and asnumber_vy(cy) or 0
+ r = r and asnumber_r (r) or 0
+
+ flush(f_circle(2*r,cx,cy),true,at)
+ end
+
+ local f_lineto_z = formatters['(%N,%N)']
+ local f_lineto_n = formatters['--(%N,%N)']
+
+ local p_pair = p_optseparator * p_number_vx * p_optseparator * p_number_vy
+ local p_open = Cc("(")
+ local p_close = Carg(1) * P(true) / function(s) return s end
+ local p_polyline = Cs(p_open * (p_pair / f_lineto_z) * (p_pair / f_lineto_n)^0 * p_close)
+ local p_polypair = Ct(p_pair^0)
+
+ local function poly(c,final)
+ local at = c.at
+ local points = rawget(at,"points")
+ if points then
+ local path = lpegmatch(p_polyline,points,1,final)
+ local list = nil
+ local begmarker = rawget(at,"marker-start")
+ local midmarker = rawget(at,"marker-mid")
+ local endmarker = rawget(at,"marker-end")
+ if begmarker or midmarker or endmarker then
+ list = lpegmatch(p_polypair,points)
+ end
+ flush(path,true,at,list,begmarker,midmarker,endmarker)
+ end
+ end
+
+ function handlers.polyline(c) poly(c, ")") end
+ function handlers.polygon (c) poly(c,"--cycle)") end
+
+ local s_image_start = "draw image ("
+ local s_image_stop = ") ;"
+
+ function handlers.path(c)
+ local at = c.at
+ local d = rawget(at,"d")
+ if d then
+ local shape, l = grabpath(d)
+ local fill = at["fill"] or "black"
+ local stroke = at["stroke"] or "none"
+ local n = #shape
+
+ local btransform, etransform = handletransform(at)
+ local cpath = handleclippath(at)
+
+ if cpath then
+ r = r + 1 ; result[r] = s_clip_start
+ end
+
+ -- todo: image (nicer for transform too)
+
+ if fill and fill ~= "none" then
+ local color, opacity = fillproperties(fill,at)
+ local f_xx_fill = at["fill-rule"] == "evenodd"
+ if shape.closed then
+ f_xx_fill = f_xx_fill and f_eo_fill or f_do_fill
+ elseif shape.curve then
+ f_xx_fill = f_xx_fill and f_eo_fill_c or f_do_fill_c
+ else
+ f_xx_fill = f_xx_fill and f_eo_fill_l or f_do_fill_l
+ end
+ if n == 1 then
+ if btransform then
+ r = r + 1 ; result[r] = btransform
+ end
+ r = r + 1 result[r] = f_xx_fill(shape[1])
+ if color then
+ r = r + 1 ; result[r] = color
+ end
+ if opacity then
+ r = r + 1 ; result[r] = opacity
+ end
+ r = r + 1 ; result[r] = etransform or ";"
+ else
+ r = r + 1 ; result[r] = btransform or s_image_start
+ for i=1,n do
+ if i == n then
+ r = r + 1 ; result[r] = f_xx_fill(shape[i])
+ if color then
+ r = r + 1 ; result[r] = color
+ end
+ if opacity then
+ r = r + 1 ; result[r] = opacity
+ end
+ else
+ r = r + 1 ; result[r] = f_no_fill(shape[i])
+ end
+ r = r + 1 ; result[r] = ";"
+ end
+ r = r + 1 ; result[r] = etransform or s_image_stop
+ end
+ end
+
+ if stroke and stroke ~= "none" then
+ local begmarker = rawget(at,"marker-start")
+ local midmarker = rawget(at,"marker-mid")
+ local endmarker = rawget(at,"marker-end")
+ if begmarker or midmarker or endmarker then
+ list = grablist(l)
+ end
+ local wrapup = startlineproperties(at)
+ local pen, dashing, color, opacity = drawproperties(stroke,at)
+ if n == 1 and not list then
+ if btransform then
+ r = r + 1 ; result[r] = btransform
+ end
+ r = r + 1 result[r] = f_do_draw(shape[1])
+ if pen then
+ r = r + 1 ; result[r] = pen
+ end
+ if dashing then
+ r = r + 1 ; result[r] = dashing
+ end
+ if color then
+ r = r + 1 ; result[r] = color
+ end
+ if opacity then
+ r = r + 1 ; result[r] = opacity
+ end
+ r = r + 1 result[r] = etransform or ";"
+ else
+ r = r + 1 result[r] = btransform or "draw image ("
+ for i=1,n do
+ r = r + 1 result[r] = f_do_draw(shape[i])
+ if pen then
+ r = r + 1 ; result[r] = pen
+ end
+ if dashing then
+ r = r + 1 ; result[r] = dashing
+ end
+ if color then
+ r = r + 1 ; result[r] = color
+ end
+ if opacity then
+ r = r + 1 ; result[r] = opacity
+ end
+ r = r + 1 ; result[r] = ";"
+ end
+ if list then
+ addmarkers(list,begmarker,midmarker,endmarker)
+ end
+ r = r + 1 ; result[r] = etransform or ") ;"
+ end
+ if wrapup then
+ wrapup()
+ end
+ end
+
+ if cpath then
+ r = r + 1 ; result[r] = f_clip_stop(cpath[1])
+ end
+
+ end
+ end
+
+ end
+
+ -- kind of special
+
+ do
+
+ -- some day:
+ --
+ -- specification = identifiers.jpg(data."string")
+ -- specification.data = data
+ -- inclusion takes from data
+ -- specification.data = false
+
+ local f_image = formatters[ [[figure("%s") xysized (%N,%N) shifted (%N,%N)]] ]
+
+ local nofimages = 0
+
+ function handlers.image(c)
+ local at = c.at
+ local im = rawget(at,"xlink:href")
+ if im then
+ local kind, data = match(im,"^data:image/([a-z]+);base64,(.*)$")
+ if kind == "png" then
+ -- ok
+ elseif kind == "jpeg" then
+ kind = "jpg"
+ else
+ kind = false
+ end
+ if kind and data then
+ local w = rawget(at,"width")
+ local h = rawget(at,"height")
+ local x = rawget(at,"x")
+ local y = rawget(at,"y")
+ w = w and asnumber_x(w)
+ h = h and asnumber_y(h)
+ x = x and asnumber_vx(x) or 0
+ y = y and asnumber_vy(y) or 0
+ nofimages = nofimages + 1
+ local name = "temp-svg-image-" .. nofimages .. "." .. kind
+ local data = mime.decode("base64")(data)
+ io.savedata(name,data)
+ if not w or not h then
+ local info = graphics.identifiers[kind](data,"string")
+ if info then
+ -- todo: keep aspect ratio attribute
+ local xsize = info.xsize
+ local ysize = info.ysize
+ if not w then
+ if not h then
+ w = xsize
+ h = ysize
+ else
+ w = (h / ysize) * xsize
+ end
+ else
+ h = (w / xsize) * ysize
+ end
+ end
+ end
+ -- safeguard:
+ if not w then w = h or 1 end
+ if not h then h = w or 1 end
+ luatex.registertempfile(name)
+ -- done:
+ flushobject(f_image(name,w,h,x,y - h),at)
+ else
+ -- nothing done
+ end
+ end
+ end
+
+ end
+
+ -- these transform: g a text svg symbol
+
+ do
+
+ function handlers.a(c)
+ process(c,"/*")
+ end
+
+ function handlers.g(c) -- much like flushobject so better split and share
+ local at = c.at
+
+ local btransform, etransform, transform = handletransform(at)
+ local cpath, clippath = handleclippath(at)
+
+ if cpath then
+ r = r + 1 ; result[r] = s_clip_start
+ end
+
+ if btransform then
+ r= r + 1 result[r] = btransform
+ end
+
+ local _transform = transform
+ local _clippath = clippath
+ at["transform"] = false
+ at["clip-path"] = false
+
+ process(c,"/*")
+
+ at["transform"] = _transform
+ at["clip-path"] = _clippath
+
+ if etransform then
+ r = r + 1 ; result[r] = etransform
+ end
+
+ if cpath then
+ local f_done = cpath.evenodd
+ if cpath.curve then
+ f_done = f_done and f_eoclip_stop_c or f_clip_stop_c
+ else
+ f_done = f_done and f_eoclip_stop_l or f_clip_stop_l
+ end
+ r = r + 1 ; result[r] = f_done(cpath[1])
+ end
+ end
+
+ -- this will never really work out
+ --
+ -- todo: register text in lua in mapping with id, then draw mapping unless overloaded
+ -- using lmt_svglabel with family,style,weight,size,id passed
+
+ -- nested tspans are messy: they can have displacements but in inkscape we also
+ -- see x and y (inner and outer element)
+
+ -- The size is a bit of an issue. I assume that the specified size relates to the
+ -- designsize but we want to be able to use other fonts.
+
+ do
+
+ local f_styled = formatters["\\svgstyled{%s}{%s}{%s}{%s}"]
+ local f_colored = formatters["\\svgcolored{%.3N}{%.3N}{%.3N}{"]
+ local f_placed = formatters["\\svgplaced{%.3N}{%.3N}{}{"]
+ local f_poschar = formatters["\\svgposchar{%.3N}{%.3N}{%s}"]
+ local f_char = formatters["\\svgchar{%s}"]
+
+ local f_scaled = formatters["\\svgscaled{%N}{%s}{%s}{%s}"]
+ local f_normal = formatters["\\svgnormal{%s}{%s}{%s}"]
+ local f_hashed = formatters["\\svghashed{%s}"]
+
+ -- We move to the outer (x,y) and when we have an inner offset we
+ -- (need to) compensate for that outer offset.
+
+ -- local f_text_scaled_svg = formatters['(svgtext("%s") scaled %N shifted (%N,%N))']
+ -- local f_text_normal_svg = formatters['(svgtext("%s") shifted (%N,%N))']
+ -- local f_text_simple_svg = formatters['svgtext("%s")']
+
+ local anchors = {
+ ["start"] = "drt",
+ ["end"] = "dflt",
+ ["middle"] = "d",
+ }
+
+ local f_text_normal_svg = formatters['(textext.%s("%s") shifted (%N,%N))']
+ local f_text_simple_svg = formatters['textext.%s("%s")']
+
+ -- or just maptext
+
+ local f_mapped_normal_svg = formatters['(svgtext("%s") shifted (%N,%N))']
+ local f_mapped_simple_svg = formatters['svgtext("%s")']
+
+ local cssfamily = css.family
+ local cssstyle = css.style
+ local cssweight = css.weight
+ local csssize = css.size
+
+ local usedfonts = setmetatableindex(function(t,k)
+ local v = setmetatableindex("table")
+ t[k] = v
+ return v
+ end)
+
+ local p_texescape = lpegpatterns.texescape
+
+ -- For now as I need it for my (some 1500) test files.
+
+ local function checkedfamily(name)
+ if find(name,"^.-verdana.-$") then
+ name = "verdana"
+ end
+ return name
+ end
+
+ -- todo: only escape some chars and handle space
+
+ local defaultsize = 10
+
+ local function collect(t,c,x,y,size,scale,family,tx,ty)
+ local at = c.at
+ local ax = rawget(at,"x")
+ local ay = rawget(at,"y")
+ local dx = rawget(at,"dx")
+ local dy = rawget(at,"dy")
+ local v_fill = at["fill"]
+ local v_family = at["font-family"]
+ local v_style = at["font-style"]
+ local v_weight = at["font-weight"]
+ local v_size = at["font-size"]
+ --
+ ax = ax and asnumber_vx(ax) or x
+ ay = ay and asnumber_vy(ay) or y
+ dx = dx and asnumber_vx(dx) or 0
+ dy = dy and asnumber_vy(dy) or 0
+ --
+ if v_family then v_family = cssfamily(v_family) end
+ if v_style then v_style = cssstyle (v_style) end
+ if v_weight then v_weight = cssweight(v_weight) end
+ if v_size then v_size = csssize (v_size,factors) end
+ --
+ ax = ax - x
+ ay = ay - y
+ --
+ local elayered = ax ~= 0 or ay ~= 0 or false
+ local eplaced = dx ~= 0 or dy ~= 0 or false
+
+ local usedsize, usedscaled
+
+ if elayered then
+ -- we're now at the outer level again so we need to scale
+ -- back to the outer level values
+ t[#t+1] = formatters["\\svgsetlayer{%0N}{%0N}{"](ax,-ay)
+ usedsize = v_size or defaultsize
+ usedscale = usedsize / defaultsize
+ else
+ -- we're nested so we can be scaled
+ usedsize = v_size or size
+ usedscale = (usedsize / defaultsize) / scale
+ end
+ --
+ -- print("element ",c.tg)
+ -- print(" layered ",elayered)
+ -- print(" font size ",v_size)
+ -- print(" parent size ",size)
+ -- print(" parent scale",scale)
+ -- print(" used size ",usedsize)
+ -- print(" used scale ",usedscale)
+ --
+ if eplaced then
+ t[#t+1] = f_placed(dx,dy)
+ end
+ --
+ if not v_family then v_family = family end
+ if not v_weight then v_weight = "normal" end
+ if not v_style then v_style = "normal" end
+ --
+ if v_family then
+ v_family = fonts.names.cleanname(v_family)
+ v_family = checkedfamily(v_family)
+ end
+ --
+ usedfonts[v_family][v_weight][v_style] = true
+ --
+-- if usedscale == 1 then
+-- t[#t+1] = f_normal( v_family,v_weight,v_style)
+-- else
+ t[#t+1] = f_scaled(usedscale,v_family,v_weight,v_style)
+-- end
+ t[#t+1] = "{"
+ --
+ local ecolored = v_fill and v_fill ~= "" or false
+ if ecolored then
+ -- todo
+ local r, g, b = rgbcomponents(v_fill)
+ if r and g and b then
+ t[#t+1] = f_colored(r,g,b)
+ else
+ ecolored = false
+ end
+ end
+ --
+ local dt = c.dt
+ local nt = #dt
+ for i=1,nt do
+ local di = dt[i]
+ if type(di) == "table" then
+ -- can be a tspan (should we pass dx too)
+ collect(t,di,x,y,usedsize,usedscale,v_family)
+ else
+ if i == 1 then
+ di = gsub(di,"^%s+","")
+ end
+ if i == nt then
+ di = gsub(di,"%s+$","")
+ end
+ local chars = utfsplit(di)
+ if svghash then
+ di = f_hashed(svghash[di])
+ elseif tx then
+ for i=1,#chars do
+ chars[i] = f_poschar(
+ (tx[i] or 0) - x,
+ (ty[i] or 0) - y,
+ utfbyte(chars[i])
+ )
+ end
+ di = "{" .. concat(chars) .. "}"
+ else
+ -- this needs to be texescaped ! and even quotes and newlines
+ -- or we could register it but that's a bit tricky as we nest
+ -- and don't know what we can expect here
+ -- di = lpegmatch(p_texescape,di) or di
+ for i=1,#chars do
+ chars[i] = f_char(utfbyte(chars[i]))
+ end
+ di = concat(chars)
+ end
+ t[#t+1] = di
+ end
+ end
+ --
+ if ecolored then
+ t[#t+1] = "}"
+ end
+ --
+ t[#t+1] = "}"
+ --
+ if eplaced then
+ t[#t+1] = "}"
+ end
+ if elayered then
+ t[#t+1] = "}"
+ end
+ --
+ return t
+ end
+
+ local s_startlayer = "\\svgstartlayer "
+ local s_stoplayer = "\\svgstoplayer "
+
+ function handlers.text(c)
+ local only = fullstrip(xmltextonly(c))
+ -- if metapost.processing() then
+ local at = c.at
+ local x = rawget(at,"x")
+ local y = rawget(at,"y")
+
+ local tx = asnumber_vx_t(x)
+ local ty = asnumber_vy_t(y)
+
+ x = tx[1] or 0 -- catch bad x/y spec
+ y = ty[1] or 0 -- catch bad x/y spec
+
+ local v_fill = at["fill"]
+ if not v_fill or v_fill == "none" then
+ v_fill = "black"
+ end
+ local color, opacity, invisible = fillproperties(v_fill,at)
+ local anchor = anchors[at["text-anchor"] or "start"] or "drt"
+ local r = metapost.remappedtext(only)
+ if r then
+ if x == 0 and y == 0 then
+ only = f_mapped_simple_svg(r.index)
+ else
+ only = f_mapped_normal_svg(r.index,x,y)
+ end
+ flushobject(only,at,color,opacity)
+ if trace_text then
+ report("text: %s",only)
+ end
+ elseif not invisible then -- can be an option
+ local scale = 1
+ local textid = 0
+ local result = { }
+ local nx = #tx
+ local ny = #ty
+ --
+ result[#result+1] = s_startlayer
+ if nx > 1 or ny > 1 then
+ concat(collect(result,c,x,y,defaultsize,1,"serif",tx,ty))
+ else
+ concat(collect(result,c,x,y,defaultsize,1,"serif"))
+ end
+ result[#result+1] = s_stoplayer
+ result = concat(result)
+ if x == 0 and y == 0 then
+ result = f_text_simple_svg(anchor,result)
+ else
+ result = f_text_normal_svg(anchor,result,x,y)
+ end
+ flushobject(result,at,color,opacity)
+ if trace_text then
+ report("text: %s",result)
+ end
+ elseif trace_text then
+ report("invisible text: %s",only)
+ end
+ -- elseif trace_text then
+ -- report("ignored text: %s",only)
+ -- end
+ end
+
+ function metapost.reportsvgfonts()
+ for family, weights in sortedhash(usedfonts) do
+ for weight, styles in sortedhash(weights) do
+ for style in sortedhash(styles) do
+ report("used font: %s-%s-%s",family,weight,style)
+ end
+ end
+ end
+ end
+
+ statistics.register("used svg fonts",function()
+ if next(usedfonts) then
+ -- also in log file
+ logs.startfilelogging(report,"used svg fonts")
+ local t = { }
+ for family, weights in sortedhash(usedfonts) do
+ for weight, styles in sortedhash(weights) do
+ for style in sortedhash(styles) do
+ report("%s-%s-%s",family,weight,style)
+ t[#t+1] = formatters["%s-%s-%s"](family,weight,style)
+ end
+ end
+ end
+ logs.stopfilelogging()
+ return concat(t," ")
+ end
+ end)
+
+ end
+
+ function handlers.svg(c,x,y,w,h,noclip,notransform,normalize,usetextindex)
+ local at = c.at
+
+ local wrapupviewport
+ local bhacked
+ local ehacked
+ local wd = w
+ -- local ex, em
+ local xpct, ypct, rpct
+
+ local btransform, etransform, transform = handletransform(at)
+
+ if trace then
+ report("view: %s, xpct %N, ypct %N","before",percentage_x,percentage_y)
+ end
+
+ local viewbox = at.viewBox
+
+ if viewbox then
+ x, y, w, h = handleviewbox(viewbox)
+ if trace then
+ report("viewbox: x %N, y %N, width %N, height %N",x,y,w,h)
+ end
+ end
+ if not w or not h or w == 0 or h == 0 then
+ noclip = true
+ end
+ if h then
+ --
+ -- em = factors["em"]
+ -- ex = factors["ex"]
+ -- factors["em"] = em
+ -- factors["ex"] = ex
+ --
+ xpct = percentage_x
+ ypct = percentage_y
+ rpct = percentage_r
+ percentage_x = w / 100
+ percentage_y = h / 100
+ percentage_r = (sqrt(w^2 + h^2) / sqrt(2)) / 100
+ if trace then
+ report("view: %s, xpct %N, ypct %N","inside",percentage_x,percentage_y)
+ end
+ wrapupviewport = viewport(x,y,w,h,noclip)
+ end
+ -- todo: combine transform and offset here
+
+ -- some fonts need this (bad transforms + viewbox)
+ if v and normalize and w and wd and w ~= wd and w > 0 and wd > 0 then
+ bhacked = s_wrapped_start
+ ehacked = f_wrapped_stop(y or 0,wd/w)
+ end
+ if btransform then
+ r = r + 1 ; result[r] = btransform
+ end
+ if bhacked then
+ r = r + 1 ; result[r] = bhacked
+ end
+ local boffset, eoffset = offset(at)
+ if boffset then
+ r = r + 1 result[r] = boffset
+ end
+ textindex = usetextindex and 0 or false
+
+ at["transform"] = false
+ at["viewBox"] = false
+
+ process(c,"/*")
+
+ at["transform"] = transform
+ at["viewBox"] = viewbox
+
+ if eoffset then
+ r = r + 1 result[r] = eoffset
+ end
+ if ehacked then
+ r = r + 1 ; result[r] = ehacked
+ end
+ if etransform then
+ r = r + 1 ; result[r] = etransform
+ end
+ if h then
+ --
+ -- factors["em"] = em
+ -- factors["ex"] = ex
+ --
+ percentage_x = xpct
+ percentage_y = ypct
+ percentage_r = rpct
+ if wrapupviewport then
+ wrapupviewport()
+ end
+ end
+ if trace then
+ report("view: %s, xpct %N, ypct %N","after",percentage_x,percentage_y)
+ end
+ end
+
+ end
+
+ process = function(x,p)
+ for c in xmlcollected(x,p) do
+ local tg = c.tg
+ local h = handlers[c.tg]
+ if h then
+ h(c)
+ end
+ end
+ end
+
+ -- For huge inefficient files there can be lots of garbage to collect so
+ -- maybe we should run the collector when a file is larger than say 50K.
+
+ function metapost.svgtomp(specification,pattern,notransform,normalize)
+ local mps = ""
+ local svg = specification.data
+ if type(svg) == "string" then
+ svg = xmlconvert(svg)
+ end
+ if svg then
+ local c = xmlfirst(svg,pattern or "/svg")
+ if c then
+ root = svg
+ result = { }
+ r = 0
+ definitions = { }
+ tagstyles = { }
+ classstyles = { }
+ for s in xmlcollected(c,"style") do -- can also be in a def, so let's play safe
+ handlestyle(c)
+ end
+ handlechains(c)
+ xmlinheritattributes(c) -- put this in handlechains
+ handlers.svg (
+ c,
+ specification.x,
+ specification.y,
+ specification.width,
+ specification.height,
+ specification.noclip,
+ notransform,
+ normalize,
+ specification.remap
+ )
+ if trace_result then
+ report("result graphic:\n %\n t",result)
+ end
+ mps = concat(result," ")
+ root, result, r, definitions, styles = false, false, false, false, false
+ else
+ report("missing svg root element")
+ end
+ else
+ report("bad svg blob")
+ end
+ return mps
+ end
+
+end
+
+-- These helpers might move to their own module .. some day ... also they will become
+-- a bit more efficient, because we now go to mp and back which is kind of redundant,
+-- but for now it will do.
+
+do
+
+ local bpfactor = number.dimenfactors.bp
+
+ function metapost.includesvgfile(filename,offset) -- offset in sp
+ if lfs.isfile(filename) then
+ context.startMPcode("doublefun")
+ context('draw lmt_svg [ filename = "%s", offset = %N ] ;',filename,(offset or 0)*bpfactor)
+ context.stopMPcode()
+ end
+ end
+
+ function metapost.includesvgbuffer(name,offset) -- offset in sp
+ context.startMPcode("doublefun")
+ context('draw lmt_svg [ buffer = "%s", offset = %N ] ;',name or "",(offset or 0)*bpfactor)
+ context.stopMPcode()
+ end
+
+ interfaces.implement {
+ name = "includesvgfile",
+ actions = metapost.includesvgfile,
+ arguments = { "string", "dimension" },
+ }
+
+ interfaces.implement {
+ name = "includesvgbuffer",
+ actions = metapost.includesvgbuffer,
+ arguments = { "string", "dimension" },
+ }
+
+ function metapost.showsvgpage(data)
+ local dd = data.data
+ if not dd then
+ local fn = data.filename
+ dd = fn and table.load(fn)
+ end
+ if type(dd) == "table" then
+ local comment = data.comment
+ local offset = data.pageoffset
+ local index = data.index
+ local first = math.max(index or 1,1)
+ local last = math.min(index or #dd,#dd)
+ for i=first,last do
+ local d = setmetatableindex( {
+ data = dd[i],
+ comment = comment and i or false,
+ pageoffset = offset or nil,
+ }, data)
+ metapost.showsvgpage(d)
+ end
+ elseif data.method == "code" then
+ context.startMPcode(doublefun)
+ context(metapost.svgtomp(data))
+ context.stopMPcode()
+ else
+ context.startMPpage { instance = "doublefun", offset = data.pageoffset or nil }
+ context(metapost.svgtomp(data))
+ local comment = data.comment
+ if comment then
+ context("draw boundingbox currentpicture withcolor .6red ;")
+ context('draw textext.bot("\\strut\\tttf %s") ysized (10pt) shifted center bottomboundary currentpicture ;',comment)
+ end
+ context.stopMPpage()
+ end
+ end
+
+ function metapost.typesvgpage(data)
+ local dd = data.data
+ if not dd then
+ local fn = data.filename
+ dd = fn and table.load(fn)
+ end
+ if type(dd) == "table" then
+ local index = data.index
+ if index and index > 0 and index <= #dd then
+ data = dd[index]
+ else
+ data = nil
+ end
+ end
+ if type(data) == "string" and data ~= "" then
+ buffers.assign("svgpage",data)
+ context.typebuffer ({ "svgpage" }, { option = "XML", strip = "yes" })
+ end
+ end
+
+ function metapost.svgtopdf(data,...)
+ local mps = metapost.svgtomp(data,...)
+ if mps then
+ -- todo: special instance, only basics needed
+ local pdf = metapost.simple("metafun",mps,true,false,"svg")
+ if pdf then
+ return pdf
+ else
+ -- message
+ end
+ else
+ -- message
+ end
+ end
+
+end
+
+do
+
+ local runner = sandbox.registerrunner {
+ name = "otfsvg2pdf",
+ program = "context",
+ template = "--batchmode --purgeall --runs=2 %filename%",
+ reporter = report_svg,
+ }
+
+ -- By using an independent pdf file instead of pdf streams we can use resources and still
+ -- cache. This is the old method updated. Maybe a future version will just do this runtime
+ -- but for now this is the most efficient method.
+
+ local decompress = gzip.decompress
+ local compress = gzip.compress
+
+ function metapost.svgshapestopdf(svgshapes,pdftarget,report_svg)
+ local texname = "temp-otf-svg-to-pdf.tex"
+ local pdfname = "temp-otf-svg-to-pdf.pdf"
+ local tucname = "temp-otf-svg-to-pdf.tuc"
+ local nofshapes = #svgshapes
+ local pdfpages = { filename = pdftarget }
+ local pdfpage = 0
+ local t = { }
+ local n = 0
+ --
+ os.remove(texname)
+ os.remove(pdfname)
+ os.remove(tucname)
+ --
+ if report_svg then
+ report_svg("processing %i svg containers",nofshapes)
+ statistics.starttiming(pdfpages)
+ end
+ --
+ -- can be option:
+ --
+ -- n = n + 1 ; t[n] = "\\nopdfcompression"
+ --
+ n = n + 1 ; t[n] = "\\starttext"
+ n = n + 1 ; t[n] = "\\setupMPpage[alternative=offset,instance=doublefun]"
+ --
+ for i=1,nofshapes do
+ local entry = svgshapes[i]
+ local data = entry.data
+ if decompress then
+ data = decompress(data) or data
+ end
+ local specification = {
+ data = xmlconvert(data),
+ x = 0,
+ y = 1000,
+ width = 1000,
+ height = 1000,
+ noclip = true,
+ }
+ for index=entry.first,entry.last do
+ if not pdfpages[index] then
+ pdfpage = pdfpage + 1
+ pdfpages[index] = pdfpage
+ local pattern = "/svg[@id='glyph" .. index .. "']"
+ n = n + 1 ; t[n] = "\\startMPpage"
+ n = n + 1 ; t[n] = metapost.svgtomp(specification,pattern,true,true) or ""
+ n = n + 1 ; t[n] = "\\stopMPpage"
+ end
+ end
+ end
+ n = n + 1 ; t[n] = "\\stoptext"
+ io.savedata(texname,concat(t,"\n"))
+ runner { filename = texname }
+ os.remove(pdftarget)
+ file.copy(pdfname,pdftarget)
+ if report_svg then
+ statistics.stoptiming(pdfpages)
+ report_svg("svg conversion time %s",statistics.elapsedseconds(pdfpages))
+ end
+ os.remove(texname)
+ os.remove(pdfname)
+ os.remove(tucname)
+ return pdfpages
+ end
+
+ function metapost.svgshapestomp(svgshapes,report_svg)
+ local nofshapes = #svgshapes
+ local mpshapes = { }
+ if report_svg then
+ report_svg("processing %i svg containers",nofshapes)
+ statistics.starttiming(mpshapes)
+ end
+ for i=1,nofshapes do
+ local entry = svgshapes[i]
+ local data = entry.data
+ if decompress then
+ data = decompress(data) or data
+ end
+ local specification = {
+ data = xmlconvert(data),
+ x = 0,
+ y = 1000,
+ width = 1000,
+ height = 1000,
+ noclip = true,
+ }
+ for index=entry.first,entry.last do
+ if not mpshapes[index] then
+ local pattern = "/svg[@id='glyph" .. index .. "']"
+ local mpcode = metapost.svgtomp(specification,pattern,true,true) or ""
+ if mpcode ~= "" and compress then
+ mpcode = compress(mpcode) or mpcode
+ end
+ mpshapes[index] = mpcode
+ end
+ end
+ end
+ if report_svg then
+ statistics.stoptiming(mpshapes)
+ report_svg("svg conversion time %s",statistics.elapsedseconds(mpshapes))
+ end
+ return mpshapes
+ end
+
+ function metapost.svgglyphtomp(fontname,unicode)
+ if fontname and unicode then
+ local id = fonts.definers.internal { name = fontname }
+ if id then
+ local tfmdata = fonts.hashes.identifiers[id]
+ if tfmdata then
+ local properties = tfmdata.properties
+ local svg = properties.svg
+ local hash = svg and svg.hash
+ local timestamp = svg and svg.timestamp
+ if hash then
+ local svgfile = containers.read(fonts.handlers.otf.svgcache,hash)
+ local svgshapes = svgfile and svgfile.svgshapes
+ if svgshapes then
+ if type(unicode) == "string" then
+ unicode = utfbyte(unicode)
+ end
+ local chardata = tfmdata.characters[unicode]
+ local index = chardata and chardata.index
+ if index then
+ for i=1,#svgshapes do
+ local entry = svgshapes[i]
+ if index >= entry.first and index <= entry.last then
+ local data = entry.data
+ if data then
+ local root = xml.convert(gzip.decompress(data) or data)
+ return metapost.svgtomp (
+ {
+ data = root,
+ x = 0,
+ y = 1000,
+ width = 1000,
+ height = 1000,
+ noclip = true,
+ },
+ "/svg[@id='glyph" .. index .. "']",
+ true,
+ true
+ )
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mtx-context-copy.tex b/Master/texmf-dist/tex/context/base/mkiv/mtx-context-copy.tex
index b798b3f8d16..d29f1d07ce2 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/mtx-context-copy.tex
+++ b/Master/texmf-dist/tex/context/base/mkiv/mtx-context-copy.tex
@@ -56,11 +56,17 @@
\startluacode
+ local find = string.find
+
if #document.files == 0 then
context("no files given")
else
- for _, filename in ipairs(document.files) do
- if not string.find(filename,"^mtx%-context%-") then
+ if document.arguments.pattern then
+ document.files = dir.glob(document.arguments.pattern)
+ end
+ for i=1,#document.files do
+ local filename = document.files[i]
+ if not find(filename,"^mtx%-context%-") and not find(filename,"^context%-extra") then
logs.report("copy",filename)
context.getfiguredimensions
{ filename }
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mtx-context-listing.tex b/Master/texmf-dist/tex/context/base/mkiv/mtx-context-listing.tex
index 285113850e1..1053e80b9c3 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/mtx-context-listing.tex
+++ b/Master/texmf-dist/tex/context/base/mkiv/mtx-context-listing.tex
@@ -116,10 +116,10 @@
-- forced
end
context.page()
--- context.setupfootertexts( -- return true: we need to keep this entry
--- { function() context.detokenize(pattern and filename or file.basename(filename)) return true end },
--- { function() context.pagenumber() return true end }
--- )
+ context.setupfootertexts( -- return true: we need to keep this entry
+ { function() context.detokenize(pattern and filename or file.basename(filename)) return true end },
+ { function() context.pagenumber() return true end }
+ )
if scite then
context.scitefile { filename } -- here { }
elseif pretty then
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mtx-context-markdown.tex b/Master/texmf-dist/tex/context/base/mkiv/mtx-context-markdown.tex
deleted file mode 100644
index 1bd57945f21..00000000000
--- a/Master/texmf-dist/tex/context/base/mkiv/mtx-context-markdown.tex
+++ /dev/null
@@ -1,92 +0,0 @@
-%D \module
-%D [ file=mtx-context-markdown,
-%D version=2011.07.24,
-%D title=\CONTEXT\ Extra Trickry,
-%D subtitle=Rendering Markdown Files,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-% begin help
-%
-% usage: context --extra=markdown [options] list-of-files
-%
-% --sort : sort filenames first
-% --paperoffset=dimension : left-top-offset
-% --duplex : doublesided (singlesided is default)
-% --backspace=dimension : extra left offset
-% --topspace=dimension : extra top offset
-% --bodyfont=specification : additional bodyfont specification
-% --contents : add table of contents
-%
-% end help
-
-\usemodule[markdown]
-
-\doifdocumentargument {paperoffset} {
- \definepapersize
- [offset=\getdocumentargument{paperoffset}]
-}
-
-\doifdocumentargument{duplex} {
- \setuppagenumbering
- [alternative=doublesided]
-} {
- \setuppagenumbering
- [alternative=singlesided]
-}
-
-\setdocumentargumentdefault {textwidth} {middle}
-\setdocumentargumentdefault {backspace} {2cm}
-\setdocumentargumentdefault {topspace} {2cm}
-\setdocumentargumentdefault {bodyfont} {}
-
-\setuptolerance
- [verytolerant,stretch]
-
-\setuplayout
- [width=middle,
- height=middle,
- backspace=\getdocumentargument{backspace},
- topspace=\getdocumentargument{topspace},
- footer=0pt]
-
-\setupbodyfont
- [dejavu,10pt,\getdocumentargument{bodyfont}]
-
-\setupwhitespace
- [big]
-
-% \enabletrackers[context.trace]
-
-\setuplist
- [chapter,section,subsection]
- [aligntitle=yes,
- width=4em]
-
-\starttext
-
-\doifdocumentargument{contents} {
- \starttitle[title={Table of contents}]
- \placelist[chapter,section,subsection] % todo: levels
- \stoptitle
-}
-
-
-\startluacode
- if #document.files > 0 then
- if document.arguments.sort then
- table.sort(document.files)
- end
- for i=1,#document.files do
- context.processmarkdownfile(document.files[i])
- context.page()
- end
- end
-\stopluacode
-
-\stoptext
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mult-aux.mkiv b/Master/texmf-dist/tex/context/base/mkiv/mult-aux.mkiv
index 5e7de227096..99d252c6b67 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/mult-aux.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/mult-aux.mkiv
@@ -11,17 +11,9 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-% todo: setupxxx and setupxxxs (so a plural for the root setup and
-% we can consider blocking the root)
-
-% todo (e.g for columnsets and registers): \definexxx[parent][1]
-%
-
-%D A generalization of \MKIV-like inheritance. Just something to play
-%D with (interface might change). The code here evolved in an email
-%D exchange between me and Wolgang Schuster.
-
-% todo: doifelse<whatever>
+%D A generalization of \MKIV-like inheritance. Just something to play with
+%D (interface might change). The code here evolved in an email exchange between me
+%D and Wolgang Schuster.
\writestatus{loading}{ConTeXt Multilingual Macros / Helpers}
@@ -29,9 +21,9 @@
\unprotect
-\edef\??empty{\Uchar25} \letvalue{\Uchar25}\empty % cancel: dec:24 hex:18
+\edef\??empty{\Uchar25} \letvalue{\Uchar25}\empty % hex 19
-%edef\s!parent{\Uchar29} \letvalue{\Uchar29}\empty % + inlining  is ugly, a tiny bit faster, but neglectable on a run
+% \edef\s!parent{\Uchar29} % inlining  is ugly, a tiny bit faster, but neglectable on a run
%D \starttyping
%D \unprotect
@@ -76,15 +68,15 @@
% todo: add (relaxed) postsetup and postdefine hooks, just after the everys
-% Start of experimental code: especially tables can have many assignments
-% and although most time is spent in the typesetting anyway, we can squeeze
-% out a little bit. Of course having 500 rows of 50 columns each with some
-% setting does not happen that often. One should keep in mind that in the
-% average document having some 500 assignments is no exception but there we're
-% talking of neglectable runtime for them. Of course in the definitions below
-% there is no real gain, only in the generated \setup* commands. Another
-% situation with many assignments is \XML\ where we can pass attributes
-% and normally don't do testing of them making sense.
+%D Start of experimental code: especially tables can have many assignments and
+%D although most time is spent in the typesetting anyway, we can squeeze out a
+%D little bit. Of course having 500 rows of 50 columns each with some setting does
+%D not happen that often. One should keep in mind that in the average document
+%D having some 500 assignments is no exception but there we're talking of
+%D neglectable runtime for them. Of course in the definitions below there is no real
+%D gain, only in the generated \setup* commands. Another situation with many
+%D assignments is \XML\ where we can pass attributes and normally don't do testing
+%D of them making sense.
%
% \testfeatureonce{100000}{\getparameters[bla][a=111,b=222,c=333]}% 1.669s
% \testfeatureonce{100000}{\mult_interfaces_get_parameters{bla} [a=111,b=222,c=333]}% 1.529s
@@ -101,7 +93,7 @@
\fi#2}
\def\mult_interfaces_get_parameters_indeed#1]% namespace already set
- {\mult_interfaces_get_parameters_item#1,],\_e_o_p_}
+ {\mult_interfaces_get_parameters_item#1,],^^^^0004}
\def\mult_interfaces_get_parameters_item#1,#2% #2 takes space before ,
{\if,#1,% dirty trick for testing #1=empty
@@ -109,7 +101,7 @@
\else\if]#1%
\doubleexpandafter\gobbleoneargument
\else
- \mult_interfaces_get_parameters_assign#1==\empty\_e_o_p_
+ \mult_interfaces_get_parameters_assign#1==\empty^^^^0004%
% \doubleexpandafter\mult_interfaces_get_parameters_item % saves skipping when at end
\fi\fi#2}
@@ -120,7 +112,7 @@
\def\mult_interfaces_get_parameters_error_indeed#1#2%
{\showassignerror{#2}{\the\inputlineno\space(#1)}}
-\def\mult_interfaces_get_parameters_assign#1=#2=#3#4\_e_o_p_
+\def\mult_interfaces_get_parameters_assign#1=#2=#3#4^^^^0004%
{\ifx\empty#1\empty
\expandafter\mult_interfaces_get_parameters_error
\else\ifx#3\empty
@@ -143,7 +135,7 @@
\def\mult_interfaces_get_parameters_error_two#1\csname#2#3\endcsname#4%
{\mult_interfaces_get_parameters_error_indeed{#2}{#3}}
- \def\mult_interfaces_get_parameters_assign#1=#2=#3#4\_e_o_p_
+ \def\mult_interfaces_get_parameters_assign#1=#2=#3#4^^^^0004%
{\ifx\empty#1\empty
\mult_interfaces_get_parameters_error_one
\else\ifx#3\empty
@@ -161,7 +153,7 @@
% \def\mult_interfaces_get_parameters_error_two#1\m_mult_interfaces_namespace#2\fi\fi%
% {\mult_interfaces_get_parameters_error_indeed\m_mult_interfaces_namespace{#2}\m_mult_interfaces_namespace\s!dummy\fi\fi}
%
- % \def\mult_interfaces_get_parameters_assign#1=#2=#3#4\_e_o_p_
+ % \def\mult_interfaces_get_parameters_assign#1=#2=#3#4^^^^0004%
% {\expandafter\def\csname
% \ifx\empty#1\empty
% \mult_interfaces_get_parameters_error_one
@@ -177,34 +169,45 @@
\newif\ifassignment
-\def\mult_check_for_assignment_indeed#1=#2#3\_end_
- {\if#2@\assignmentfalse\else\assignmenttrue\fi}
-
-\def\mult_check_for_assignment_indeed_begin_#1=#2#3\_end_
- {\if#2@}
+\def\mult_check_for_assignment_indeed#1=#2#3^^^^0004%
+ {\if#2^^^^0003\assignmentfalse\else\assignmenttrue\fi}
+\def\mult_check_for_assignment_indeed_begin_#1=#2#3^^^^0004%
+ {\if#2^^^^0003}
\def\mult_check_for_assignment#1%
- {\expandafter\mult_check_for_assignment_indeed\detokenize{#1}=@@\_end_}
+ {\expandafter\mult_check_for_assignment_indeed\detokenize{#1}=^^^^0003^^^^0003^^^^0004}
% End of experimental code.
-\unexpanded\def\mult_interfaces_let #1#2{\expandafter\let \csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname}
-\unexpanded\def\mult_interfaces_lete#1#2{\expandafter\let \csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname\empty}
-\unexpanded\def\mult_interfaces_def #1#2{\expandafter\def \csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname}
-\unexpanded\def\mult_interfaces_edef#1#2{\expandafter\edef\csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname}
-\unexpanded\def\mult_interfaces_gdef#1#2{\expandafter\gdef\csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname}
-\unexpanded\def\mult_interfaces_xdef#1#2{\expandafter\xdef\csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname}
+%D This can give wrong results when we pass e.g. \type{\c!format}, so either we need
+%D to use the \type {\k!} ones, but these are not defined in the english interface
+%D so from now on we assume that the low level ones are used with the symbolic names
+%D and that only the high level setup commands are used with language specific
+%D interfaces.
-\startinterface english
+% \unexpanded\def\mult_interfaces_let #1#2{\expandafter\let \csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname}
+% \unexpanded\def\mult_interfaces_lete#1#2{\expandafter\let \csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname\empty}
+% \unexpanded\def\mult_interfaces_def #1#2{\expandafter\def \csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname}
+% \unexpanded\def\mult_interfaces_edef#1#2{\expandafter\edef\csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname}
+% \unexpanded\def\mult_interfaces_gdef#1#2{\expandafter\gdef\csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname}
+% \unexpanded\def\mult_interfaces_xdef#1#2{\expandafter\xdef\csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname}
+% \startinterface english
\unexpanded\def\mult_interfaces_let #1#2{\expandafter \let\csname#1#2\endcsname}
\unexpanded\def\mult_interfaces_lete#1#2{\expandafter \let\csname#1#2\endcsname\empty}
\unexpanded\def\mult_interfaces_def #1#2{\expandafter \def\csname#1#2\endcsname}
\unexpanded\def\mult_interfaces_edef#1#2{\expandafter\edef\csname#1#2\endcsname}
\unexpanded\def\mult_interfaces_gdef#1#2{\expandafter\gdef\csname#1#2\endcsname}
\unexpanded\def\mult_interfaces_xdef#1#2{\expandafter\xdef\csname#1#2\endcsname}
+% \stopinterface
+
+%D Do, we only interface the assignment definition:
+
+\unexpanded\def\mult_interfaces_adef#1#2{\expandafter\def \csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname}
+\startinterface english
+ \unexpanded\def\mult_interfaces_adef#1#2{\expandafter \def\csname#1#2\endcsname}
\stopinterface
% the commented detokenized variant that backtracks ... needs testing usage first
@@ -217,21 +220,23 @@
% \def\currenttest{oeps} \edef\hans{\detokenizedtestparameter{reggab}}\meaning\hans\par
%
% slower: \def#3##1{\csname\ifcsname#1#2:##1\endcsname\expandafter\csstring\lastnamedcs\else\expandafter#5\csname#1#2:\s!parent\endcsname{##1}\fi\endcsname}%
-%
-% pre-expansion can be a bit faster but handly any effect on a normal run so let's go for
-% saving some memory
+
+%D pre-expansion can be a bit faster but handly any effect on a normal run so let's
+%D go for saving some memory
\def\mult_interfaces_detokenize{\expandafter\expandafter\expandafter\detokenize\expandafter\expandafter\expandafter}
-\unexpanded\def\mult_interfaces_install_parameter_handler#1#2#3#4#5#6#7#8% inlining \csname*\endcsname is more efficient (#3 and #6 only)
- {\ifx#2\relax\let#2\empty\fi % it is hardly faster but produces less expansion tracing
+\unexpanded\def\mult_interfaces_install_parameter_handler#1#2#3#4#5#6#7#8#9% inlining \csname*\endcsname is more efficient (#3 and #6 only)
+ {\ifx#2\relax\let#2\empty\fi % it is hardly faster but produces less expansion tracing
\def#3##1{\csname\ifcsname#1#2:##1\endcsname#1#2:##1\else\expandafter#5\csname#1#2:\s!parent\endcsname{##1}\fi\endcsname}%
\def#4##1##2{\ifcsname##1:##2\endcsname##1:##2\else\expandafter#5\csname##1:\s!parent\endcsname{##2}\fi}%
%\def#5##1##2{\ifx##1\relax\??empty\else#4{##1}{##2}\fi}% is {} needed around ##1 ?
- \def#5##1##2{\ifx##1\relax\??empty\else#4##1{##2}\fi}% is {} needed around ##1 ?
+ %\def#5##1##2{\ifx##1\relax\??empty\else#4##1{##2}\fi}% is {} needed around ##1 ?
+ \def#5##1##2{\ifx##1\relax^^^^0019\else#4##1{##2}\fi}% is {} needed around ##1 ?
\def#6##1##2{\csname\ifcsname#1##1:##2\endcsname#1##1:##2\else\expandafter#5\csname#1##1:\s!parent\endcsname{##2}\fi\endcsname}%
\def#7##1{\detokenize\expandafter\expandafter\expandafter{\csname#1#2:##1\endcsname}}% always root, no backtrack
- \def#8##1{\begincsname#1#2:##1\endcsname}}
+ \def#8##1{\begincsname#1#2:##1\endcsname}
+ \def#9##1##2{\expandafter\let\expandafter##1\csname\ifcsname#1#2:##2\endcsname#1#2:##2\else\expandafter#5\csname#1#2:\s!parent\endcsname{##2}\fi\endcsname}}
\unexpanded\def\installparameterhandler#1#2%
{\normalexpanded
@@ -243,7 +248,8 @@
\expandafter\noexpand\csname do#2parentparameter\endcsname % or : #2_parent_parameter
\expandafter\noexpand\csname named#2parameter\endcsname
\expandafter\noexpand\csname detokenized#2parameter\endcsname
- \expandafter\noexpand\csname direct#2parameter\endcsname}} % strict#2parameter is gone
+ \expandafter\noexpand\csname direct#2parameter\endcsname
+ \expandafter\noexpand\csname letfrom#2parameter\endcsname}} % strict#2parameter is gone
\unexpanded\def\mult_interfaces_install_root_parameter_handler#1#2#3%
{\def#2##1{\detokenize\expandafter\expandafter\expandafter{\csname#1:##1\endcsname}}% always root
@@ -281,28 +287,25 @@
\expandafter\noexpand\csname check#2parent\endcsname
\expandafter\noexpand\csname chaintocurrent#2\endcsname}}
-% In \MKIV\ we can probably use the english variant for all other
-% languages too.
+%D In \MKIV\ we can probably use the english variant for all other languages too.
% todo: inline the def/let
-\unexpanded\def\mult_interfaces_install_parameter_set_handler#1#2#3#4#5#6%
- {\ifx#2\relax\let#2\empty\fi
- \unexpanded\def#3{\mult_interfaces_def {#1#2:}}% ##1 {##2} (braces are mandate)
- \unexpanded\def#4{\mult_interfaces_edef{#1#2:}}% ##1 {##2} (braces are mandate)
- \unexpanded\def#5{\mult_interfaces_let {#1#2:}}% ##1 ##2
- \unexpanded\def#6{\mult_interfaces_lete{#1#2:}}}% ##1
-
-\startinterface english
-
+% \unexpanded\def\mult_interfaces_install_parameter_set_handler#1#2#3#4#5#6%
+% {\ifx#2\relax\let#2\empty\fi
+% \unexpanded\def#3{\mult_interfaces_def {#1#2:}}% ##1 {##2} (braces are mandate)
+% \unexpanded\def#4{\mult_interfaces_edef{#1#2:}}% ##1 {##2} (braces are mandate)
+% \unexpanded\def#5{\mult_interfaces_let {#1#2:}}% ##1 ##2
+% \unexpanded\def#6{\mult_interfaces_lete{#1#2:}}}% ##1
+%
+% \startinterface english
\unexpanded\def\mult_interfaces_install_parameter_set_handler#1#2#3#4#5#6%
{\ifx#2\relax\let#2\empty\fi
\unexpanded\def#3##1{\expandafter \def\csname#1#2:##1\endcsname}% ##1 {##2} (braces are mandate)
\unexpanded\def#4##1{\expandafter\edef\csname#1#2:##1\endcsname}% ##1 {##2} (braces are mandate)
\unexpanded\def#5##1{\expandafter \let\csname#1#2:##1\endcsname}% ##1 ##2
\unexpanded\def#6##1{\expandafter \let\csname#1#2:##1\endcsname\empty}}% ##1
-
-\stopinterface
+% \stopinterface
\unexpanded\def\installparametersethandler#1#2%
{\normalexpanded
@@ -357,44 +360,6 @@
\def\getparentchain #1#2{\begincsname#1#2:\s!chain\endcsname}
\def\getcurrentparentchain#1#2{\begincsname#1#2:\s!chain\endcsname}
-\unexpanded\def\mult_interfaces_install_define_handler#1#2#3#4#5#6#7#8#9% why is \expanded still needed in clones
- {\ifx#4\relax\let#4\empty\fi % see \defineregister
- \unexpanded\def#2{\dotripleempty#5}%
- \newtoks#6%
- \newtoks#7%
- \unexpanded\def#5[##1][##2][##3]% [child][parent][settings] | [child][settings] | [child][parent] | [child]
- {\let#9#4%
- \edef#4{##1}%
- \ifthirdargument
- \the#6% predefine
- \edef#8{##2}%
- \mult_check_for_parent{#1}{#3}#4#8%
- \expandafter\edef\csname#1#4:\s!chain\endcsname{\mult_interfaces_chain#1{##2}##1}%
- \expandafter\edef\csname#1#4:\s!parent\endcsname{#1##2}%
- \mult_interfaces_get_parameters{#1#4:}[##3]%
- \else\ifsecondargument
- \the#6% predefine
- \expandafter\mult_check_for_assignment_indeed\detokenize{##2}=@@\_end_
- \ifassignment
- \let#8\empty
- \expandafter\edef\csname#1#4:\s!chain\endcsname{##1}%
- \expandafter\edef\csname#1#4:\s!parent\endcsname{#3}%
- \mult_interfaces_get_parameters{#1#4:}[##2]%
- \else
- \edef#8{##2}%
- \mult_check_for_parent{#1}{#3}#4#8%
- \expandafter\edef\csname#1#4:\s!chain\endcsname{\mult_interfaces_chain#1{##2}##1}%
- \expandafter\edef\csname#1#4:\s!parent\endcsname{#1##2}%
- \fi
- \else
- \the#6% predefine
- \let#8\empty
- \expandafter\edef\csname#1#4:\s!chain\endcsname{##1}%
- \expandafter\edef\csname#1#4:\s!parent\endcsname{#3}%
- \fi\fi
- \the#7%
- \let#4#9}}
-
% \unexpanded\def\mult_interfaces_install_define_handler#1#2#3#4#5#6#7#8#9% why is \expanded still needed in clones
% {\ifx#4\relax\let#4\empty\fi % see \defineregister
% \unexpanded\def#2{\dotripleempty#5}%
@@ -412,16 +377,17 @@
% \mult_interfaces_get_parameters{#1#4:}[##3]%
% \else\ifsecondargument
% \the#6% predefine
-% \ifcondition\expandafter\mult_check_for_assignment_indeed_begin_\detokenize{##2}=@@\_end_
-% \edef#8{##2}%
-% \mult_check_for_parent{#1}{#3}#4#8%
-% \expandafter\edef\csname#1#4:\s!chain\endcsname{\mult_interfaces_chain#1{##2}##1}%
-% \expandafter\edef\csname#1#4:\s!parent\endcsname{#1##2}%
-% \else
+% \expandafter\mult_check_for_assignment_indeed\detokenize{##2}=^^^^0003^^^^0003^^^^0004%
+% \ifassignment
% \let#8\empty
% \expandafter\edef\csname#1#4:\s!chain\endcsname{##1}%
% \expandafter\edef\csname#1#4:\s!parent\endcsname{#3}%
% \mult_interfaces_get_parameters{#1#4:}[##2]%
+% \else
+% \edef#8{##2}%
+% \mult_check_for_parent{#1}{#3}#4#8%
+% \expandafter\edef\csname#1#4:\s!chain\endcsname{\mult_interfaces_chain#1{##2}##1}%
+% \expandafter\edef\csname#1#4:\s!parent\endcsname{#1##2}%
% \fi
% \else
% \the#6% predefine
@@ -432,6 +398,43 @@
% \the#7%
% \let#4#9}}
+\unexpanded\def\mult_interfaces_install_define_handler#1#2#3#4#5#6#7#8#9% why is \expanded still needed in clones
+ {\ifx#4\relax\let#4\empty\fi % see \defineregister
+ \unexpanded\def#2{\dotripleempty#5}%
+ \newtoks#6%
+ \newtoks#7%
+ \unexpanded\def#5[##1][##2][##3]% [child][parent][settings] | [child][settings] | [child][parent] | [child]
+ {\let#9#4%
+ \edef#4{##1}%
+ \ifthirdargument
+ \the#6% predefine
+ \edef#8{##2}%
+ \mult_check_for_parent{#1}{#3}#4#8%
+ \expandafter\edef\csname#1#4:\s!chain\endcsname{\mult_interfaces_chain#1{##2}##1}%
+ \expandafter\edef\csname#1#4:\s!parent\endcsname{#1##2}%
+ \mult_interfaces_get_parameters{#1#4:}[##3]%
+ \else\ifsecondargument
+ \the#6% predefine
+ \ifcondition\expandafter\mult_check_for_assignment_indeed_begin_\detokenize{##2}=^^^^0003^^^^0003^^^^0004%
+ \edef#8{##2}%
+ \mult_check_for_parent{#1}{#3}#4#8%
+ \expandafter\edef\csname#1#4:\s!chain\endcsname{\mult_interfaces_chain#1{##2}##1}%
+ \expandafter\edef\csname#1#4:\s!parent\endcsname{#1##2}%
+ \else
+ \let#8\empty
+ \expandafter\edef\csname#1#4:\s!chain\endcsname{##1}%
+ \expandafter\edef\csname#1#4:\s!parent\endcsname{#3}%
+ \mult_interfaces_get_parameters{#1#4:}[##2]%
+ \fi
+ \else
+ \the#6% predefine
+ \let#8\empty
+ \expandafter\edef\csname#1#4:\s!chain\endcsname{##1}%
+ \expandafter\edef\csname#1#4:\s!parent\endcsname{#3}%
+ \fi\fi
+ \the#7%
+ \let#4#9}}
+
\unexpanded\def\installdefinehandler#1#2#3%
{\normalexpanded
{\mult_interfaces_install_define_handler
@@ -490,55 +493,6 @@
\unexpanded\def#2{\dodoubleempty#4}%
\unexpanded\def#5{\mult_interfaces_get_parameters{#1#3:}}}
-\unexpanded\def\mult_interfaces_install_switch_setup_handler_b#1#2#3#4#5#6#7#8#9%
- {\newtoks#5%
- \newconstant#2%
- \newtoks#8%
- \newtoks#9%
- \ifx#6\relax\let#6\empty\fi
- \unexpanded\def#4[##1][##2]% maybe helper
- {\ifsecondargument % no commalist here
- % \setuplayout[whatever][key=value]
- \let#7#3%
- \let#6#3%
- \edef#3{##1}%
- #2\doingrootsetupnamed
- \mult_interfaces_get_parameters{#1#3:}[##2]%
- \the#5%
- \ifx#3#6\the#8\fi % only switchsetups if previous == current
- \let#3#7%
- \else\iffirstargument
- % \mult_check_for_assignment{##1}%
- \expandafter\mult_check_for_assignment_indeed\detokenize{##1}=@@\_end_
- \ifassignment
- % \setuplayout[key=value]
- \let#7#3%
- \let#6#3%
- \let#3\empty
- #2\doingrootsetuproot
- \mult_interfaces_get_parameters{#1:}[##1]%
- \the#5%
- \the#8% switchsetups
- \let#3#7%
- \else
- % \setuplayout[whatever]
- \let#6#3% % previous becomes current
- \edef#3{##1}% this will catch reset so one needs to test for it
- #2\doingrootsetnamed
- \the#5% % we can check for previous vs current
- \the#8% switchsetups
- \fi
- \else
- % \setuplayout
- \let#6#3% % previous becomes current
- \let#3\empty % current becomes empty
- #2\doingrootsetroot
- \the#5%
- \the#8% switchsetups
- \fi\fi
- #2\zerocount % mode is always zero at the end
- \the#9}}
-
% \unexpanded\def\mult_interfaces_install_switch_setup_handler_b#1#2#3#4#5#6#7#8#9%
% {\newtoks#5%
% \newconstant#2%
@@ -558,14 +512,8 @@
% \let#3#7%
% \else\iffirstargument
% % \mult_check_for_assignment{##1}%
-% \ifcondition\expandafter\mult_check_for_assignment_indeed_begin_\detokenize{##1}=@@\_end_
-% % \setuplayout[whatever]
-% \let#6#3% % previous becomes current
-% \edef#3{##1}% this will catch reset so one needs to test for it
-% #2\doingrootsetnamed
-% \the#5% % we can check for previous vs current
-% \the#8% switchsetups
-% \else
+% \expandafter\mult_check_for_assignment_indeed\detokenize{##1}=^^^^0003^^^^0003^^^^0004%
+% \ifassignment
% % \setuplayout[key=value]
% \let#7#3%
% \let#6#3%
@@ -575,6 +523,13 @@
% \the#5%
% \the#8% switchsetups
% \let#3#7%
+% \else
+% % \setuplayout[whatever]
+% \let#6#3% % previous becomes current
+% \edef#3{##1}% this will catch reset so one needs to test for it
+% #2\doingrootsetnamed
+% \the#5% % we can check for previous vs current
+% \the#8% switchsetups
% \fi
% \else
% % \setuplayout
@@ -587,6 +542,54 @@
% #2\zerocount % mode is always zero at the end
% \the#9}}
+\unexpanded\def\mult_interfaces_install_switch_setup_handler_b#1#2#3#4#5#6#7#8#9%
+ {\newtoks#5%
+ \newconstant#2%
+ \newtoks#8%
+ \newtoks#9%
+ \ifx#6\relax\let#6\empty\fi
+ \unexpanded\def#4[##1][##2]% maybe helper
+ {\ifsecondargument % no commalist here
+ % \setuplayout[whatever][key=value]
+ \let#7#3%
+ \let#6#3%
+ \edef#3{##1}%
+ #2\doingrootsetupnamed
+ \mult_interfaces_get_parameters{#1#3:}[##2]%
+ \the#5%
+ \ifx#3#6\the#8\fi % only switchsetups if previous == current
+ \let#3#7%
+ \else\iffirstargument
+ % \mult_check_for_assignment{##1}%
+ \ifcondition\expandafter\mult_check_for_assignment_indeed_begin_\detokenize{##1}=^^^^0003^^^^0003^^^^0004%
+ % \setuplayout[whatever]
+ \let#6#3% % previous becomes current
+ \edef#3{##1}% this will catch reset so one needs to test for it
+ #2\doingrootsetnamed
+ \the#5% % we can check for previous vs current
+ \the#8% switchsetups
+ \else
+ % \setuplayout[key=value]
+ \let#7#3%
+ \let#6#3%
+ \let#3\empty
+ #2\doingrootsetuproot
+ \mult_interfaces_get_parameters{#1:}[##1]%
+ \the#5%
+ \the#8% switchsetups
+ \let#3#7%
+ \fi
+ \else
+ % \setuplayout
+ \let#6#3% % previous becomes current
+ \let#3\empty % current becomes empty
+ #2\doingrootsetroot
+ \the#5%
+ \the#8% switchsetups
+ \fi\fi
+ #2\zerocount % mode is always zero at the end
+ \the#9}}
+
\unexpanded\def\installswitchsetuphandler#1#2%
{\normalexpanded
{\mult_interfaces_install_switch_setup_handler_a
@@ -685,14 +688,14 @@
\installsetuphandler {#1}{#2}%
\installstyleandcolorhandler {#1}{#2}}
-%D Many mechanisms have some kind of inheritance in place, and these are
-%D the speed||critical ones. Therefore there is no reason to stick to
-%D \type {\@@xxkey} for the sake of performance. For this reason we also
-%D provide a direct variant. This permits a more consistent treatment of
-%D namespaces. A \type {\whateverparameter} call is three times slower
-%D and a \type {\directwhateverparameter} call two times but for some
-%D 100K expansions we only loose some .1 second which is neglectable
-%D given the small amount of expansions in real runs.
+%D Many mechanisms have some kind of inheritance in place, and these are the
+%D speed||critical ones. Therefore there is no reason to stick to \type {\@@xxkey}
+%D for the sake of performance. For this reason we also provide a direct variant.
+%D This permits a more consistent treatment of namespaces. A \type
+%D {\whateverparameter} call is three times slower and a \type
+%D {\directwhateverparameter} call two times but for some 100K expansions we only
+%D loose some .1 second which is neglectable given the small amount of expansions in
+%D real runs.
%D We don't need colons for such simple cases.
@@ -727,21 +730,19 @@
\expandafter\noexpand\csname setupcurrent#2\endcsname % no \every (we use 'current' for consistency)
\expandafter\noexpand\csname everysetup#2\endcsname}}
-\unexpanded\def\mult_interfaces_install_direct_parameter_set_handler#1#2#3#4#5%
- {\unexpanded\def#2{\mult_interfaces_def #1}%
- \unexpanded\def#3{\mult_interfaces_edef#1}%
- \unexpanded\def#4{\mult_interfaces_let #1}%
- \unexpanded\def#5{\mult_interfaces_let #1\empty}}%
-
-\startinterface english
+% \unexpanded\def\mult_interfaces_install_direct_parameter_set_handler#1#2#3#4#5%
+% {\unexpanded\def#2{\mult_interfaces_def #1}%
+% \unexpanded\def#3{\mult_interfaces_edef#1}%
+% \unexpanded\def#4{\mult_interfaces_let #1}%
+% \unexpanded\def#5{\mult_interfaces_let #1\empty}}%
+% \startinterface english
\unexpanded\def\mult_interfaces_install_direct_parameter_set_handler#1#2#3#4#5%
{\unexpanded\def#2##1{\expandafter \def\csname#1##1\endcsname}%
\unexpanded\def#3##1{\expandafter\edef\csname#1##1\endcsname}%
\unexpanded\def#4##1{\expandafter \let\csname#1##1\endcsname}%
\unexpanded\def#5##1{\expandafter \let\csname#1##1\endcsname\empty}}%
-
-\stopinterface
+% \stopinterface
\unexpanded\def\installdirectparametersethandler#1#2%
{\normalexpanded
@@ -804,6 +805,24 @@
\expandafter\noexpand\csname setupcurrent#1\endcsname
\expandafter\noexpand\csname #1_action\endcsname}}
+% \unexpanded\def\mult_interfaces_install_action_handler#1#2#3#4%
+% {\unexpanded\expandafter\def\csname#1\endcsname{\dodoubleempty#4}%
+% \unexpanded\def#4[##1][##2]%
+% {\begingroup
+% \ifsecondargument
+% \edef#2{##1}%
+% #3[##2]%
+% \else\iffirstargument
+% \doifelseassignment{##1}
+% {\let#2\empty
+% #3[##1]}%
+% {\edef#2{##1}}%
+% \else
+% \let#2\empty
+% \fi\fi
+% \directsetup{handler:action:#1}%
+% \endgroup}}
+
\unexpanded\def\mult_interfaces_install_action_handler#1#2#3#4%
{\unexpanded\expandafter\def\csname#1\endcsname{\dodoubleempty#4}%
\unexpanded\def#4[##1][##2]%
@@ -812,10 +831,12 @@
\edef#2{##1}%
#3[##2]%
\else\iffirstargument
- \doifelseassignment{##1}
- {\let#2\empty
- #3[##1]}%
- {\edef#2{##1}}%
+ \ifcondition\expandafter\mult_check_for_assignment_indeed_begin_\detokenize{##1}=^^^^0003^^^^0003^^^^0004%
+ \edef#2{##1}%
+ \else
+ \let#2\empty
+ #3[##1]%
+ \fi
\else
\let#2\empty
\fi\fi
@@ -828,22 +849,21 @@
% \unexpanded\def\installnamespace#1{\setvalue{????#1}{@@@@#1}}
% \stoptyping
%
-% The following variant is nicer and in principle faster but that gets
-% unnoticed unless lots of expansion happens. Also, we can use long tags
-% but the internal expansion will be relatively small (and unlikely more
-% than 4 characters). For instance, \??xx used to expand to @@xx but now
-% becomes for instance 123::. This is one character more but in quite some
-% cases we had : after such a tag in the old situation. In the new situation
-% we create more namespaces and don't need that : any more, so we end up
-% with on the average the same amount of tokens and definitely less when
-% we consider cases like \??xx:\c!align: which now is just \??somealign and
-% therefore has length 5 now (instead of 4+1+5+1=10).
+% The following variant is nicer and in principle faster but that gets unnoticed
+% unless lots of expansion happens. Also, we can use long tags but the internal
+% expansion will be relatively small (and unlikely more than 4 characters). For
+% instance, \??xx used to expand to @@xx but now becomes for instance 123::. This
+% is one character more but in quite some cases we had : after such a tag in the
+% old situation. In the new situation we create more namespaces and don't need that
+% : any more, so we end up with on the average the same amount of tokens and
+% definitely less when we consider cases like \??xx:\c!align: which now is just
+% \??somealign and therefore has length 5 now (instead of 4+1+5+1=10).
%
-% Eventualy we will have a verbose \blablanamespace and the difference between
-% core and regular can go ... after all, \xxxparameter can already clash between
-% the two prefix groups .. if users use this mechanism a lot they should use
-% verbose names anyway (the old two character names were mostly an optimization
-% as they also expanded to these characters).
+% Eventualy we will have a verbose \blablanamespace and the difference between core
+% and regular can go ... after all, \xxxparameter can already clash between the two
+% prefix groups .. if users use this mechanism a lot they should use verbose names
+% anyway (the old two character names were mostly an optimization as they also
+% expanded to these characters).
% todo: register namespaces at lua end for logging and reverse resolve
% todo: move this to syst-ini so that we can use it real early
@@ -878,7 +898,7 @@
\fi}
\def\mult_interfaces_get_parameters_error_indeed#1#2%
- {\clf_showassignerror{#1}{#2}\inputlineno} % no longer \waitonfatalerror
+ {\clf_showassignerror{#1}{#2}\inputlineno}
% We install two core namespaces here, as we want nice error messages. Maybe
% we will reserve the first 9.
@@ -916,8 +936,8 @@
\usedummystyleparameter
\usedummycolorparameter
-% Maybe a \definecorenamespace[name][directparameter,directsetup][parent]
-% but we don't gain much. Actually we might just inline all definitions.
+% Maybe a \definecorenamespace[name][directparameter,directsetup][parent] but we
+% don't gain much. Actually we might just inline all definitions.
% \enabletrackers[interfaces.namespaces,context.flush]
%
@@ -1328,23 +1348,23 @@
\unexpanded\def\syst_helpers_install_macro_stack#1#2#3%
{\xdef\m_syst_helpers_push_macro{\csstring#1}%
- \expandafter\newcount\csname#3\m_syst_helpers_push_macro\endcsname
- \expandafter\edef\csname push_macro_\m_syst_helpers_push_macro\endcsname
- {\noexpand\expandafter\glet
- \noexpand\csname\m_syst_helpers_push_macro\noexpand\the\csname#3\m_syst_helpers_push_macro\endcsname\endcsname
- \noexpand#1%
- \global\advance\csname#3\m_syst_helpers_push_macro\endcsname\plusone}%
- \expandafter\edef\csname pop_macro_\m_syst_helpers_push_macro\endcsname
- {\global\advance\csname#3\m_syst_helpers_push_macro\endcsname\minusone
- \noexpand\expandafter#2%
- \noexpand\expandafter\noexpand#1%
- \noexpand\csname\m_syst_helpers_push_macro\noexpand\the\csname#3\m_syst_helpers_push_macro\endcsname\endcsname}}
+ \ifcsname#3\m_syst_helpers_push_macro\endcsname\else
+ \expandafter\newcount\csname#3\m_syst_helpers_push_macro\endcsname
+ \expandafter\edef\csname push_macro_\m_syst_helpers_push_macro\endcsname
+ {\noexpand\expandafter\glet
+ \noexpand\csname\m_syst_helpers_push_macro\noexpand\the\csname#3\m_syst_helpers_push_macro\endcsname\endcsname
+ \noexpand#1%
+ \global\advance\csname#3\m_syst_helpers_push_macro\endcsname\plusone}%
+ \expandafter\edef\csname pop_macro_\m_syst_helpers_push_macro\endcsname
+ {\global\advance\csname#3\m_syst_helpers_push_macro\endcsname\minusone
+ \noexpand\expandafter#2%
+ \noexpand\expandafter\noexpand#1%
+ \noexpand\csname\m_syst_helpers_push_macro\noexpand\the\csname#3\m_syst_helpers_push_macro\endcsname\endcsname}%
+ \fi}
\unexpanded\def\installmacrostack #1{\syst_helpers_install_macro_stack#1\let \??localpushedmacro }
\unexpanded\def\installglobalmacrostack#1{\syst_helpers_install_macro_stack#1\glet\??globalpushedmacro}
-\protect
-
% \unprotect
%
% \installcorenamespace {test} \installcommandhandler \??test {test} \??test
@@ -1366,87 +1386,94 @@
%
% \starttext
% \definetest[foo] \definetest[bar][foo] \setuptest[bar][before=indeed]
-% \resettimer \dorecurse{100000}{\TestMeA[bar]} A:\elapsedtime \par % 0.502
-% \resettimer \dorecurse{100000}{\TestMeB[bar]} B:\elapsedtime \par % 0.530
-% \resettimer \dorecurse{100000}{\TestMeC[bar]} C:\elapsedtime \par % 0.487
-% \resettimer \dorecurse{100000}{\TestMeD[bar]} D:\elapsedtime \par % 0.493
+% \testfeatureonce{100000}{\TestMeA[bar]} A:\elapsedtime \par % 0.502
+% \testfeatureonce{100000}{\TestMeB[bar]} B:\elapsedtime \par % 0.530
+% \testfeatureonce{100000}{\TestMeC[bar]} C:\elapsedtime \par % 0.487
+% \testfeatureonce{100000}{\TestMeD[bar]} D:\elapsedtime \par % 0.493
% \stoptext
-% There is no real demand for this ... even if this is twice as fast we only gain
-% a few milliseconds:
-%
-% \unexpanded\def\foo#1{[foo:#1]}
+% There is no real demand for this ... even if this is two to three times as fast we
+% only gain a few milliseconds:
%
-% \installcommalistprocessor {foo} \foo
-% \installcommalistprocessorcommand \processfoolist {foo} \foo
+% \starttyping
+% \unexpanded\def\foo#1{[foo:#1]}
%
-% \commalistprocessor{foo}[a,b,c,d]
-% \processfoolist [a, b, c, d]
+% \installcommalistprocessor {foo} \foo
+% \installcommalistprocessorcommand \processfoolist \foo
%
-% \testfeatureonce{30000}{} \elapsedtime\par % 0.01 -> 0.00
-% \testfeatureonce{30000}{\processfoolist [fixed,middle]} \elapsedtime\par % 0.07 -> 0.06
-% \testfeatureonce{30000}{\commalistprocessor{foo}[fixed,middle]} \elapsedtime\par % 0.09 -> 0.08
-% \testfeatureonce{30000}{\processcommalist [fixed,middle]\foo} \elapsedtime\par % 0.13 -> 0.12
+% \infofont
%
-% For instance the luatex manual only has some 3000 calls. But I keep this around as one
-% never knows when we might need it.
+% \commalistprocessor{foo}[a,b,c,{x,y,z},d]\par
+% \processfoolist[a, b, c, {x,y,z}, d]\par
+% \processcommalist[{x,y,z}]\foo\blank
%
-% \installcorenamespace{commalistprocessor}
-% \installcorenamespace{commalistprocessorcheck}
-% \installcorenamespace{commalistprocessorwrap}
-% \installcorenamespace{commalistprocessorfirst}
-% \installcorenamespace{commalistprocessorcheckspace}
-% \installcorenamespace{commalistprocessorcheckfinish}
-% \installcorenamespace{commalistprocessoraction}
-% \installcorenamespace{commalistprocessorgobblespace}
+% \commalistprocessor{foo}[{x,y,z},a]\par
+% \commalistprocessor{foo}[{x,y,z}]\par
+% \processfoolist[{x,y,z},a]\par
+% \processfoolist[{x,y,z}]\par
+% \processcommalist[{x,y,z}]\foo\blank
%
-% \unexpanded\def\installcommalistprocessor#1#2% 7 macro names overhead
-% {\let\nexttoken\relax
-% %
-% \unexpanded\expandafter\edef\csname\??commalistprocessor#1\endcsname[%
-% {\futurelet\nexttoken\csname\??commalistprocessorcheck#1\endcsname}%
-% %
-% \unexpanded\expandafter\edef\csname\??commalistprocessorcheck#1\endcsname
-% {\noexpand\ifx\nexttoken]%
-% \noexpand\expandafter\noexpand\gobblethreearguments
-% \noexpand\else
-% \noexpand\expandafter\csname\??commalistprocessorwrap#1\endcsname
-% \noexpand\fi
-% \relax}% this one preserved the next {}
-% %
-% \unexpanded\expandafter\edef\csname\??commalistprocessorwrap#1\endcsname##1]%
-% {\csname\??commalistprocessorfirst#1\endcsname##1,]\relax}%
-% %
-% \unexpanded\expandafter\edef\csname\??commalistprocessorfirst#1\endcsname##1% picks up \relax
-% {\csname\??commalistprocessorcheckspace#1\endcsname}%
-% %
-% \unexpanded\expandafter\edef\csname\??commalistprocessorcheckspace#1\endcsname
-% {\noexpand\ifx\nexttoken\noexpand\blankspace
-% \noexpand\expandafter\csname\??commalistprocessorgobblespace#1\endcsname
-% \noexpand\else
-% \noexpand\expandafter\csname\??commalistprocessorcheckfinish#1\endcsname
-% \noexpand\fi}%
-% %
-% \unexpanded\expandafter\edef\csname\??commalistprocessorcheckfinish#1\endcsname
-% {\noexpand\ifx\nexttoken]%
-% \noexpand\expandafter\noexpand\gobbleoneargument
-% \noexpand\else
-% \noexpand\expandafter\csname\??commalistprocessoraction#1\endcsname
-% \noexpand\fi}%
-% %
-% \unexpanded\expandafter\edef\csname\??commalistprocessoraction#1\endcsname##1,%
-% {\noexpand#2{##1}%
-% \futurelet\nexttoken\csname\??commalistprocessorcheckspace#1\endcsname}%
-% %
-% \let\next\:%
-% \unexpanded\edef \:{\csname\??commalistprocessorgobblespace#1\endcsname}%
-% \unexpanded\expandafter\edef\: {\futurelet\nexttoken\csname\??commalistprocessorcheckspace#1\endcsname}%
-% \let\:\next
-% %
-% }
+% \unexpanded\def\foo#1{}
%
-% \unexpanded\def\installcommalistprocessorcommand#1#2#3%
-% {\installcommalistprocessor{#2}{#3}%
-% \expandafter\let\expandafter#1\csname\??commalistprocessor#2\endcsname}
+% \testfeatureonce{400000}{\processfoolist [fixed,middle,bar]} \elapsedtime\quad
+%%\testfeatureonce{400000}{\commalistprocessor{foo}[fixed,middle,bar]} \elapsedtime\quad
+% \testfeatureonce{400000}{\processcommalist [fixed,middle,bar]\foo} \elapsedtime\quad
+% \stoptyping
%
-% \unexpanded\def\commalistprocessor#1{\csname\??commalistprocessor#1\endcsname}
+% For instance the luatex manual only has some 3000 calls. But I keep this around as one
+% never knows when we might need it.
+
+\installcorenamespace{commalistprocessor}
+\installcorenamespace{commalistprocessorwrap}
+\installcorenamespace{commalistprocessorfirst}
+\installcorenamespace{commalistprocessornext}
+\installcorenamespace{commalistprocessoraction}
+
+\installcorenamespace{commalistprocessorcheck}
+\installcorenamespace{commalistprocessorspace}
+\installcorenamespace{commalistprocessorpickup}
+\installcorenamespace{commalistprocessorfinish}
+
+\unexpanded\def\installcommalistprocessor#1#2% 8 macro names overhead
+ {\let\nexttoken\relax
+ \unexpanded\expandafter\edef\csname\??commalistprocessor#1\endcsname[%
+ {\futurelet\nexttoken\csname\??commalistprocessorcheck#1\endcsname}%
+ \unexpanded\expandafter\edef\csname\??commalistprocessorcheck#1\endcsname
+ {\noexpand\ifx\nexttoken]%
+ \noexpand\expandafter\noexpand\gobblethreearguments
+ \noexpand\else
+ \noexpand\expandafter\csname\??commalistprocessorwrap#1\endcsname
+ \noexpand\fi
+ \relax}% this one preserved the next {}
+ \unexpanded\expandafter\edef\csname\??commalistprocessorwrap#1\endcsname##1]%
+ {\csname\??commalistprocessorfirst#1\endcsname##1,]\relax}%
+ \unexpanded\expandafter\edef\csname\??commalistprocessorfirst#1\endcsname##1% picks up \relax
+ {\csname\??commalistprocessornext#1\endcsname}%
+ \unexpanded\expandafter\edef\csname\??commalistprocessornext#1\endcsname
+ {\noexpand\ifx\nexttoken\noexpand\blankspace
+ \noexpand\expandafter\csname\??commalistprocessorspace#1\endcsname
+ \noexpand\else
+ \noexpand\expandafter\csname\??commalistprocessorfinish#1\endcsname
+ \noexpand\fi}%
+ \unexpanded\expandafter\edef\csname\??commalistprocessorfinish#1\endcsname
+ {\noexpand\ifx\nexttoken]%
+ \noexpand\expandafter\noexpand\gobbleoneargument
+ \noexpand\else
+ \noexpand\expandafter\csname\??commalistprocessoraction#1\endcsname
+ \noexpand\fi}%
+ \unexpanded\expandafter\edef\csname\??commalistprocessoraction#1\endcsname##1,%
+ {\noexpand#2{##1}%
+ \futurelet\nexttoken\csname\??commalistprocessornext#1\endcsname}%
+ \let\next\:%
+ \unexpanded\edef \:{\csname\??commalistprocessorspace#1\endcsname}%
+ \unexpanded\expandafter\edef\: {\futurelet\nexttoken\csname\??commalistprocessornext#1\endcsname}%
+ \let\:\next}
+
+\unexpanded\def\installcommalistprocessorcommand#1#2% \processor \action
+ {\edef\p_name{\csstring#2}%
+ \installcommalistprocessor\p_name{#2}%
+ \expandafter\let\expandafter#1\csname\??commalistprocessor\p_name\endcsname}
+
+\unexpanded\def\commalistprocessor#1{\csname\??commalistprocessor#1\endcsname}
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mult-aux.mkxl b/Master/texmf-dist/tex/context/base/mkiv/mult-aux.mkxl
new file mode 100644
index 00000000000..3fed8c26e68
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/mult-aux.mkxl
@@ -0,0 +1,1170 @@
+%D \module
+%D [ file=mult-aux,
+%D version=2010.08.2,
+%D title=\CONTEXT\ Multilingual Macros,
+%D subtitle=Helpers,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D A generalization of \MKIV-like inheritance. Just something to play with
+%D (interface might change). The code here evolved in an email exchange between me
+%D and Wolgang Schuster.
+
+\writestatus{loading}{ConTeXt Multilingual Macros / Helpers}
+
+\registerctxluafile{mult-aux}{}
+
+\unprotect
+
+\edef\??empty{\Uchar25} \letvalue{\Uchar25}\empty % hex 19
+
+% \edef\s!parent{\Uchar29} % inlining  is ugly, a tiny bit faster, but neglectable on a run
+
+%D \starttyping
+%D \unprotect
+%D \def\????aa{@@@@aa}
+%D
+%D \installparameterhandler \????aa {whatever}
+%D \installsetuphandler \????aa {whatever}
+%D \installdefinehandler \????aa {whatever} \????aa % #3 == defaultroot
+%D \installfontandcolorhandler\????aa {whatever}
+%D
+%D % \installcommandhandler \????aa {whatever} \????aa
+%D \protect
+%D
+%D % \whateverparameter \c!test
+%D % \whateverparameterhash \c!test
+%D % \namedwhateverparameter \mycurrentwhatever \c!test
+%D % \usewhateverstyleandcolor \c!style \c!color
+%D % \everydefinewhatever (sets \currentwhatever)
+%D % \everypresetwhatever (can be used to reset parameters as we can redefine)
+%D % \everysetupwhatever (sets \currentwhatever)
+%D
+%D \starttext
+%D \definewhatever[first] \definewhatever[second][first]
+%D test: \def\currentwhatever{first} \whateverparameter{method} \par
+%D \setupwhatever [method=unset] test: \def\currentwhatever{first} \whateverparameter{method} \par
+%D \setupwhatever[first] [method=first] test: \def\currentwhatever{first} \whateverparameter{method} \par
+%D test: \def\currentwhatever{second} \whateverparameter{method} \par
+%D \setupwhatever[second][method=second] test: \def\currentwhatever{second} \whateverparameter{method} \par
+%D \stoptext
+%D \stoptyping
+
+% problem: every* could clash
+%
+% There can be less {} in the following definitions if we assume \??aa and \c!somecs
+%
+% todo: \def\detokenized...parameter#1{\detokenize\expandafter\expandafter\expandafter{\csname#1#2\endcsname}} % always root
+%
+% it might be more efficient to do this at the lua and
+%
+% watch the push/pop and predefinition of current .. this is needed for nested
+% definitions and overloaded defines using the predefined one
+
+% todo: add (relaxed) postsetup and postdefine hooks, just after the everys
+
+%D Start of experimental code: especially tables can have many assignments and
+%D although most time is spent in the typesetting anyway, we can squeeze out a
+%D little bit. Of course having 500 rows of 50 columns each with some setting does
+%D not happen that often. One should keep in mind that in the average document
+%D having some 500 assignments is no exception but there we're talking of
+%D neglectable runtime for them. Of course in the definitions below there is no real
+%D gain, only in the generated \setup* commands. Another situation with many
+%D assignments is \XML\ where we can pass attributes and normally don't do testing
+%D of them making sense.
+%
+% \testfeatureonce{100000}{\getparameters[bla][a=111,b=222,c=333]}% 1.669s
+% \testfeatureonce{100000}{\mult_interfaces_get_parameters{bla} [a=111,b=222,c=333]}% 1.529s
+% \testfeatureonce{100000}{\def\m_mult_interfaces_namespace{bla}\mult_interfaces_get_parameters_indeed[a=111,b=222,c=333]}% 1.466s
+
+\let\m_mult_interfaces_namespace\empty
+
+\def\mult_interfaces_get_parameters#1[#2%
+ {\if\noexpand#2]%
+ \expandafter\gobbleoneargument
+ \else
+ \def\m_mult_interfaces_namespace{#1}%
+ \expandafter\mult_interfaces_get_parameters_indeed
+ \fi#2}
+
+\def\mult_interfaces_get_parameters_indeed#1]% namespace already set
+ {\mult_interfaces_get_parameters_item#1,],^^^^0004}
+
+\def\mult_interfaces_get_parameters_item#1,#2% #2 takes space before ,
+ {\if,#1,% dirty trick for testing #1=empty
+ \expandafter\mult_interfaces_get_parameters_item
+ \orelse\if]#1%
+ \expandafter\gobbleoneargument
+ \else
+ \mult_interfaces_get_parameters_assign#1==\empty^^^^0004%
+ % \expandafter\mult_interfaces_get_parameters_item % saves skipping when at end
+ \fi#2}
+
+\def\mult_interfaces_get_parameters_error#1#2% #3%
+ {\mult_interfaces_get_parameters_error_indeed{#1}{#2}%
+ \gobbleoneargument}
+
+\def\mult_interfaces_get_parameters_error_indeed#1#2%
+ {\showassignerror{#2}{\the\inputlineno\space(#1)}}
+
+\def\mult_interfaces_get_parameters_assign#1=#2=#3#4^^^^0004%
+ {\ifx\empty#1\empty
+ \expandafter\mult_interfaces_get_parameters_error
+ \orelse\ifx#3\empty
+ \expandafter\mult_interfaces_get_parameters_error
+ \else
+ \expandafter\mult_interfaces_adef % assignment def
+ \fi
+ \m_mult_interfaces_namespace{#1}{#2}%
+ \doubleexpandafter\mult_interfaces_get_parameters_item}
+
+\startinterface english
+
+ % some 10% faster
+
+ \let\mult_interfaces_get_parameters_error\undefined
+
+ \def\mult_interfaces_get_parameters_error_one#1\csname#2#3\endcsname#4%
+ {\mult_interfaces_get_parameters_error_indeed{#2}{#3}\iftrue}
+
+ \def\mult_interfaces_get_parameters_error_two#1\csname#2#3\endcsname#4%
+ {\mult_interfaces_get_parameters_error_indeed{#2}{#3}}
+
+ \def\mult_interfaces_get_parameters_assign#1=#2=#3#4^^^^0004%
+ {\ifx\empty#1\empty
+ \mult_interfaces_get_parameters_error_one
+ \orelse\ifx#3\empty
+ \mult_interfaces_get_parameters_error_two
+ \else
+ \expandafter\def\csname\m_mult_interfaces_namespace#1\endcsname{#2}%
+ \fi
+ \doubleexpandafter\mult_interfaces_get_parameters_item}
+
+\stopinterface
+
+\newif\ifassignment
+
+\def\mult_check_for_assignment_indeed#1=#2#3^^^^0004%
+ {\if#2^^^^0003\assignmentfalse\else\assignmenttrue\fi}
+
+\def\mult_check_for_assignment_indeed_begin_#1=#2#3^^^^0004%
+ {\if#2^^^^0003}
+
+\def\mult_check_for_assignment#1%
+ {\expandafter\mult_check_for_assignment_indeed\detokenize{#1}=^^^^0003^^^^0003^^^^0004}
+
+% End of experimental code.
+
+%D This can give wrong results when we pass e.g. \type{\c!format}, so either we need
+%D to use the \type {\k!} ones, but these are not defined in the english interface
+%D so from now on we assume that the low level ones are used with the symbolic names
+%D and that only the high level setup commands are used with language specific
+%D interfaces.
+
+% \unexpanded\def\mult_interfaces_let #1#2{\expandafter\let \csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname}
+% \unexpanded\def\mult_interfaces_lete#1#2{\expandafter\let \csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname\empty}
+% \unexpanded\def\mult_interfaces_def #1#2{\expandafter\def \csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname}
+% \unexpanded\def\mult_interfaces_edef#1#2{\expandafter\edef\csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname}
+% \unexpanded\def\mult_interfaces_gdef#1#2{\expandafter\gdef\csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname}
+% \unexpanded\def\mult_interfaces_xdef#1#2{\expandafter\xdef\csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname}
+
+% \startinterface english
+ \unexpanded\def\mult_interfaces_let #1#2{\expandafter \let\csname#1#2\endcsname}
+ \unexpanded\def\mult_interfaces_lete#1#2{\expandafter \let\csname#1#2\endcsname\empty}
+ \unexpanded\def\mult_interfaces_def #1#2{\expandafter \def\csname#1#2\endcsname}
+ \unexpanded\def\mult_interfaces_edef#1#2{\expandafter\edef\csname#1#2\endcsname}
+ \unexpanded\def\mult_interfaces_gdef#1#2{\expandafter\gdef\csname#1#2\endcsname}
+ \unexpanded\def\mult_interfaces_xdef#1#2{\expandafter\xdef\csname#1#2\endcsname}
+% \stopinterface
+
+%D Do, we only interface the assignment definition:
+
+\unexpanded\def\mult_interfaces_adef#1#2{\expandafter\def \csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname}
+
+\startinterface english
+ \unexpanded\def\mult_interfaces_adef#1#2{\expandafter \def\csname#1#2\endcsname}
+\stopinterface
+
+% the commented detokenized variant that backtracks ... needs testing usage first
+%
+% \let\whatever\relax
+%
+% \definetest[oeps][bagger=\whatever]
+%
+% \def\currenttest{oeps} \edef\hans{\detokenizedtestparameter{bagger}}\meaning\hans\par
+% \def\currenttest{oeps} \edef\hans{\detokenizedtestparameter{reggab}}\meaning\hans\par
+%
+% slower: \def#3##1{\csname\ifcsname#1#2:##1\endcsname\expandafter\csstring\lastnamedcs\else\expandafter#5\csname#1#2:\s!parent\endcsname{##1}\fi\endcsname}%
+
+%D pre-expansion can be a bit faster but handly any effect on a normal run so let's
+%D go for saving some memory
+
+\def\mult_interfaces_detokenize{\expandafter\expandafter\expandafter\detokenize\expandafter\expandafter\expandafter}
+
+\unexpanded\def\mult_interfaces_install_parameter_handler#1#2#3#4#5#6#7#8#9% inlining \csname*\endcsname is more efficient (#3 and #6 only)
+ {\ifx#2\relax\let#2\empty\fi % it is hardly faster but produces less expansion tracing
+ \def#3##1{\csname\ifcsname#1#2:##1\endcsname#1#2:##1\else\expandafter#5\csname#1#2:\s!parent\endcsname{##1}\fi\endcsname}%
+ \def#4##1##2{\ifcsname##1:##2\endcsname##1:##2\else\expandafter#5\csname##1:\s!parent\endcsname{##2}\fi}%
+ %\def#5##1##2{\ifx##1\relax\??empty\else#4{##1}{##2}\fi}% is {} needed around ##1 ?
+ %\def#5##1##2{\ifx##1\relax\??empty\else#4##1{##2}\fi}% is {} needed around ##1 ?
+ \def#5##1##2{\ifx##1\relax^^^^0019\else#4##1{##2}\fi}% is {} needed around ##1 ?
+ \def#6##1##2{\csname\ifcsname#1##1:##2\endcsname#1##1:##2\else\expandafter#5\csname#1##1:\s!parent\endcsname{##2}\fi\endcsname}%
+ \def#7##1{\detokenize\expandafter\expandafter\expandafter{\csname#1#2:##1\endcsname}}% always root, no backtrack
+ \def#8##1{\begincsname#1#2:##1\endcsname}
+ \def#9##1##2{\expandafter\let\expandafter##1\csname\ifcsname#1#2:##2\endcsname#1#2:##2\else\expandafter#5\csname#1#2:\s!parent\endcsname{##2}\fi\endcsname}}
+
+\unexpanded\def\installparameterhandler#1#2%
+ {\normalexpanded
+ {\mult_interfaces_install_parameter_handler
+ {\noexpand#1}% \??aa
+ \expandafter\noexpand\csname current#2\endcsname
+ \expandafter\noexpand\csname #2parameter\endcsname
+ \expandafter\noexpand\csname do#2parameter\endcsname % or : #2_parameter
+ \expandafter\noexpand\csname do#2parentparameter\endcsname % or : #2_parent_parameter
+ \expandafter\noexpand\csname named#2parameter\endcsname
+ \expandafter\noexpand\csname detokenized#2parameter\endcsname
+ \expandafter\noexpand\csname direct#2parameter\endcsname
+ \expandafter\noexpand\csname letfrom#2parameter\endcsname}} % strict#2parameter is gone
+
+\unexpanded\def\mult_interfaces_install_root_parameter_handler#1#2#3%
+ {\def#2##1{\detokenize\expandafter\expandafter\expandafter{\csname#1:##1\endcsname}}% always root
+ \def#3##1{\begincsname#1:##1\endcsname}}
+
+\unexpanded\def\installrootparameterhandler#1#2%
+ {\normalexpanded
+ {\mult_interfaces_install_root_parameter_handler
+ {\noexpand#1}% \??aa
+ \expandafter\noexpand\csname detokenizedroot#2parameter\endcsname
+ \expandafter\noexpand\csname root#2parameter\endcsname}}
+
+\unexpanded\def\mult_interfaces_install_parameter_hash_handler#1#2#3#4#5#6#7#8#9%
+ {\ifx#2\relax\let#2\empty\fi
+ \def#3##1{#1#4{#1#2}{##1}:}% leading #1 was missing .. is this one used?
+ \def#4##1##2{\ifcsname##1:##2\endcsname##1\else\expandafter#5\csname##1:\s!parent\endcsname{##2}\fi}%
+ %\def#5##1##2{\ifx##1\relax\else#4{##1}{##2}\fi}%
+ \def#5##1##2{\ifx##1\relax\else#4##1{##2}\fi}%
+ \def#6{#1#2:}%
+ \def#7##1{#1##1:}%
+ \def#8{\ifx#2\empty\orelse\ifcsname#1#2:\s!parent\endcsname\else\expandafter\let\csname#1#2:\s!parent\endcsname#1\fi}%
+ \unexpanded\def#9##1{\expandafter\edef\csname#1##1:\s!parent\endcsname{#1#2}}}
+
+\unexpanded\def\installparameterhashhandler#1#2%
+ {\expandafter\let\csname#2namespace\endcsname#1%
+ \normalexpanded
+ {\mult_interfaces_install_parameter_hash_handler
+ {\noexpand#1}% \??aa
+ \expandafter\noexpand\csname current#2\endcsname
+ \expandafter\noexpand\csname #2parameterhash\endcsname
+ \expandafter\noexpand\csname do#2parameterhash\endcsname % or : #2_parameter_hash
+ \expandafter\noexpand\csname do#2parentparameterhash\endcsname % or : #2_parent_parameter_hash
+ \expandafter\noexpand\csname current#2hash\endcsname
+ \expandafter\noexpand\csname named#2hash\endcsname
+ \expandafter\noexpand\csname check#2parent\endcsname
+ \expandafter\noexpand\csname chaintocurrent#2\endcsname}}
+
+%D In \MKIV\ we can probably use the english variant for all other languages too.
+
+% todo: inline the def/let
+
+% \unexpanded\def\mult_interfaces_install_parameter_set_handler#1#2#3#4#5#6%
+% {\ifx#2\relax\let#2\empty\fi
+% \unexpanded\def#3{\mult_interfaces_def {#1#2:}}% ##1 {##2} (braces are mandate)
+% \unexpanded\def#4{\mult_interfaces_edef{#1#2:}}% ##1 {##2} (braces are mandate)
+% \unexpanded\def#5{\mult_interfaces_let {#1#2:}}% ##1 ##2
+% \unexpanded\def#6{\mult_interfaces_lete{#1#2:}}}% ##1
+%
+% \startinterface english
+ \unexpanded\def\mult_interfaces_install_parameter_set_handler#1#2#3#4#5#6%
+ {\ifx#2\relax\let#2\empty\fi
+ \unexpanded\def#3##1{\expandafter \def\csname#1#2:##1\endcsname}% ##1 {##2} (braces are mandate)
+ \unexpanded\def#4##1{\expandafter\edef\csname#1#2:##1\endcsname}% ##1 {##2} (braces are mandate)
+ \unexpanded\def#5##1{\expandafter \let\csname#1#2:##1\endcsname}% ##1 ##2
+ \unexpanded\def#6##1{\expandafter \let\csname#1#2:##1\endcsname\empty}}% ##1
+% \stopinterface
+
+\unexpanded\def\installparametersethandler#1#2%
+ {\normalexpanded
+ {\mult_interfaces_install_parameter_set_handler
+ {\noexpand#1}% \??aa
+ \expandafter\noexpand\csname current#2\endcsname
+ \expandafter\noexpand\csname set#2parameter\endcsname
+ \expandafter\noexpand\csname setexpanded#2parameter\endcsname
+ \expandafter\noexpand\csname let#2parameter\endcsname
+ \expandafter\noexpand\csname reset#2parameter\endcsname}}
+
+\let\dousecurrentstyleparameter\relax
+\let\dousecurrentcolorparameter\relax
+
+\let\currentstyleparameter\empty
+\let\currentcolorparameter\empty
+
+\unexpanded\def\mult_interfaces_install_style_and_color_handler#1#2#3#4%
+ {\unexpanded\def#2##1##2% style color
+ {\edef\currentstyleparameter{#1{##1}}% this name is public (can also set color e.g. in underline)
+ \ifx\currentstyleparameter\empty\else\dousecurrentstyleparameter\fi
+ \edef\currentcolorparameter{#1{##2}}% this name is public (so we do this after the style switch)
+ \ifx\currentcolorparameter\empty\else\dousecurrentcolorparameter\fi}%
+ \unexpanded\def#3##1% style
+ {\edef\currentstyleparameter{#1{##1}}% this name is public
+ \ifx\currentstyleparameter\empty\else\dousecurrentstyleparameter\fi}%
+ \unexpanded\def#4##1% color
+ {\edef\currentcolorparameter{#1{##1}}% this name is public
+ \ifx\currentcolorparameter\empty\else\dousecurrentcolorparameter\fi}}
+
+\unexpanded\def\installstyleandcolorhandler#1#2%
+ {\normalexpanded
+ {\mult_interfaces_install_style_and_color_handler
+ \expandafter\noexpand\csname #2parameter\endcsname
+ \expandafter\noexpand\csname use#2styleandcolor\endcsname % maybe an alias use#2styleandcolorparameters
+ \expandafter\noexpand\csname use#2styleparameter\endcsname
+ \expandafter\noexpand\csname use#2colorparameter\endcsname}}
+
+\let\definehandlerparent\empty
+
+% \def\mult_check_for_parent#1#2#3#4%
+% {\ifcsname#1#4:\s!parent\endcsname \else \ifx#4\empty \else
+% \writestatus\m!system{error: invalid parent #4 for #3, #4 defined too (best check it)}%
+% \expandafter\edef\csname#1#4:\s!parent\endcsname{#2}%
+% \fi \fi}
+
+\def\mult_check_for_parent#1#2#3#4%
+ {\ifcsname#1#4:\s!parent\endcsname\orelse\ifx#4\empty\else
+ \writestatus\m!system{error: invalid parent #4 for #3, #4 defined too (best check it)}%
+ \expandafter\edef\csname#1#4:\s!parent\endcsname{#2}%
+ \fi}
+
+%def\mult_interfaces_chain#1#2{\ifcsname#1#2:\s!chain\endcsname\csname#1#2:\s!chain\endcsname\space\fi}
+%def\getparentchain #1#2{\ifcsname#1#2:\s!chain\endcsname\csname#1#2:\s!chain\endcsname\fi}
+%def\getcurrentparentchain#1#2{\ifcsname#1#2:\s!chain\endcsname\csname#1#2:\s!chain\endcsname\fi}
+
+\def\mult_interfaces_chain#1#2{\ifcsname#1#2:\s!chain\endcsname\lastnamedcs\space\fi}
+\def\getparentchain #1#2{\begincsname#1#2:\s!chain\endcsname}
+\def\getcurrentparentchain#1#2{\begincsname#1#2:\s!chain\endcsname}
+
+\unexpanded\def\mult_interfaces_install_define_handler#1#2#3#4#5#6#7#8#9% why is \expanded still needed in clones
+ {\ifx#4\relax\let#4\empty\fi % see \defineregister
+ \unexpanded\def#2{\dotripleempty#5}%
+ \newtoks#6%
+ \newtoks#7%
+ \unexpanded\def#5[##1][##2][##3]% [child][parent][settings] | [child][settings] | [child][parent] | [child]
+ {\let#9#4%
+ \edef#4{##1}%
+ \ifthirdargument
+ \the#6% predefine
+ \edef#8{##2}%
+ \mult_check_for_parent{#1}{#3}#4#8%
+ \expandafter\edef\csname#1#4:\s!chain\endcsname{\mult_interfaces_chain#1{##2}##1}%
+ \expandafter\edef\csname#1#4:\s!parent\endcsname{#1##2}%
+ \mult_interfaces_get_parameters{#1#4:}[##3]%
+ \orelse\ifsecondargument
+ \the#6% predefine
+ \ifcondition\expandafter\mult_check_for_assignment_indeed_begin_\detokenize{##2}=^^^^0003^^^^0003^^^^0004%
+ \edef#8{##2}%
+ \mult_check_for_parent{#1}{#3}#4#8%
+ \expandafter\edef\csname#1#4:\s!chain\endcsname{\mult_interfaces_chain#1{##2}##1}%
+ \expandafter\edef\csname#1#4:\s!parent\endcsname{#1##2}%
+ \else
+ \let#8\empty
+ \expandafter\edef\csname#1#4:\s!chain\endcsname{##1}%
+ \expandafter\edef\csname#1#4:\s!parent\endcsname{#3}%
+ \mult_interfaces_get_parameters{#1#4:}[##2]%
+ \fi
+ \else
+ \the#6% predefine
+ \let#8\empty
+ \expandafter\edef\csname#1#4:\s!chain\endcsname{##1}%
+ \expandafter\edef\csname#1#4:\s!parent\endcsname{#3}%
+ \fi
+ \the#7%
+ \let#4#9}}
+
+\unexpanded\def\installdefinehandler#1#2#3%
+ {\normalexpanded
+ {\mult_interfaces_install_define_handler
+ {\noexpand#1}% \??aa
+ \expandafter\noexpand\csname define#2\endcsname
+ {\noexpand#3}% root
+ \expandafter\noexpand\csname current#2\endcsname
+ \expandafter\noexpand\csname define_#2\endcsname % semi-public
+ \expandafter\noexpand\csname everypreset#2\endcsname
+ \expandafter\noexpand\csname everydefine#2\endcsname
+ \expandafter\noexpand\csname current#2parent\endcsname
+ \expandafter\noexpand\csname saved_defined_#2\endcsname}}
+
+\unexpanded\def\mult_interfaces_install_setup_handler#1#2#3#4#5#6#7#8#9%
+ {\ifx#3\relax\let#3\empty\fi
+ \unexpanded\def#2{\dodoubleempty#4}%
+ \unexpanded\def#6{\mult_interfaces_get_parameters{#1#3:}}% no every ! don't change it
+ \newtoks#5%
+ \newtoks#8%
+ \unexpanded\def#4[##1][##2]% maybe helper
+ {\let#7#3%
+ \ifsecondargument
+ \def#9####1% we will have a simple one as well
+ {\edef#3{####1}%
+ \mult_interfaces_get_parameters{#1#3:}[##2]%
+ \the#5}%
+ \processcommalist[##1]#9%
+ \else
+ \let#3\empty
+ \mult_interfaces_get_parameters{#1:}[##1]%
+ \the#5%
+ \fi
+ \let#3#7%
+ \the#8}}
+
+\unexpanded\def\installsetuphandler#1#2%
+ {\normalexpanded
+ {\mult_interfaces_install_setup_handler
+ {\noexpand#1}% \??aa
+ \expandafter\noexpand\csname setup#2\endcsname
+ \expandafter\noexpand\csname current#2\endcsname
+ \expandafter\noexpand\csname setup_#2\endcsname % semi-public
+ \expandafter\noexpand\csname everysetup#2\endcsname
+ \expandafter\noexpand\csname setupcurrent#2\endcsname
+ \expandafter\noexpand\csname saved_setup_current#2\endcsname
+ \expandafter\noexpand\csname everysetup#2root\endcsname
+ \expandafter\noexpand\csname nested_setup_current#2\endcsname}}
+
+\let\doingrootsetupnamed\plusone % \setuplayout[name][key=value]
+\let\doingrootsetuproot \plustwo % \setuplayout [key=value]
+\let\doingrootsetnamed \plusthree % \setuplayout[name]
+\let\doingrootsetroot \plusfour % \setuplayout
+
+\unexpanded\def\mult_interfaces_install_switch_setup_handler_a#1#2#3#4#5%
+ {\ifx#3\relax\let#3\empty\fi
+ \unexpanded\def#2{\dodoubleempty#4}%
+ \unexpanded\def#5{\mult_interfaces_get_parameters{#1#3:}}}
+
+\unexpanded\def\mult_interfaces_install_switch_setup_handler_b#1#2#3#4#5#6#7#8#9%
+ {\newtoks#5%
+ \newconstant#2%
+ \newtoks#8%
+ \newtoks#9%
+ \ifx#6\relax\let#6\empty\fi
+ \unexpanded\def#4[##1][##2]% maybe helper
+ {\ifsecondargument % no commalist here
+ % \setuplayout[whatever][key=value]
+ \let#7#3%
+ \let#6#3%
+ \edef#3{##1}%
+ #2\doingrootsetupnamed
+ \mult_interfaces_get_parameters{#1#3:}[##2]%
+ \the#5%
+ \ifx#3#6\the#8\fi % only switchsetups if previous == current
+ \let#3#7%
+ \orelse\iffirstargument
+ % \mult_check_for_assignment{##1}%
+ \ifcondition\expandafter\mult_check_for_assignment_indeed_begin_\detokenize{##1}=^^^^0003^^^^0003^^^^0004%
+ % \setuplayout[whatever]
+ \let#6#3% % previous becomes current
+ \edef#3{##1}% this will catch reset so one needs to test for it
+ #2\doingrootsetnamed
+ \the#5% % we can check for previous vs current
+ \the#8% switchsetups
+ \else
+ % \setuplayout[key=value]
+ \let#7#3%
+ \let#6#3%
+ \let#3\empty
+ #2\doingrootsetuproot
+ \mult_interfaces_get_parameters{#1:}[##1]%
+ \the#5%
+ \the#8% switchsetups
+ \let#3#7%
+ \fi
+ \else
+ % \setuplayout
+ \let#6#3% % previous becomes current
+ \let#3\empty % current becomes empty
+ #2\doingrootsetroot
+ \the#5%
+ \the#8% switchsetups
+ \fi
+ #2\zerocount % mode is always zero at the end
+ \the#9}}
+
+\unexpanded\def\installswitchsetuphandler#1#2%
+ {\normalexpanded
+ {\mult_interfaces_install_switch_setup_handler_a
+ {\noexpand#1}% \??aa
+ \expandafter\noexpand\csname setup#2\endcsname
+ \expandafter\noexpand\csname current#2\endcsname
+ \expandafter\noexpand\csname setup_#2\endcsname % semi-public
+ \expandafter\noexpand\csname setupcurrent#2\endcsname
+ \mult_interfaces_install_switch_setup_handler_b
+ {\noexpand#1}% \??aa
+ \expandafter\noexpand\csname #2setupmode\endcsname
+ \expandafter\noexpand\csname current#2\endcsname
+ \expandafter\noexpand\csname setup_#2\endcsname % semi-public
+ \expandafter\noexpand\csname everysetup#2\endcsname
+ \expandafter\noexpand\csname previous#2\endcsname
+ \expandafter\noexpand\csname saved_setup_current#2\endcsname
+ \expandafter\noexpand\csname everyswitch#2\endcsname
+ \expandafter\noexpand\csname everysetup#2root\endcsname}}
+
+\unexpanded\def\mult_interfaces_install_auto_setup_handler#1#2#3#4#5#6#7#8#9%
+ {\ifx#3\relax\let#3\empty\fi
+ \unexpanded\def#2{\dotripleempty#4}%
+ \unexpanded\def#6{\mult_interfaces_get_parameters{#1#3:}}%
+ \newtoks#5%
+ \def#4[##1][##2][##3]%
+ {\let#8#3%
+ \ifthirdargument
+ \def#9####1%
+ {\edef#3{####1}%
+ \expandafter\def\csname#1#3:\s!parent\endcsname{#1##2}%
+ \mult_interfaces_get_parameters{#1#3:}[##3]% always sets parent
+ \the#5}%
+ \processcommalist[##1]#9%
+ \orelse\ifsecondargument
+ \def#9####1%
+ {\edef#3{####1}%
+ #7% checks parent and sets if needed
+ \mult_interfaces_get_parameters{#1#3:}[##2]%
+ \the#5}%
+ \processcommalist[##1]#9%
+ \else
+ \let#3\empty
+ \mult_interfaces_get_parameters{#1:}[##1]%
+ \the#5%
+ \fi
+ \let#3#8}}
+
+\unexpanded\def\installautosetuphandler#1#2%
+ {\normalexpanded
+ {\mult_interfaces_install_auto_setup_handler
+ {\noexpand#1}% \??aa
+ \expandafter\noexpand\csname setup#2\endcsname
+ \expandafter\noexpand\csname current#2\endcsname
+ \expandafter\noexpand\csname setup_#2\endcsname % semi-public
+ \expandafter\noexpand\csname everysetup#2\endcsname
+ \expandafter\noexpand\csname setupcurrent#2\endcsname
+ \expandafter\noexpand\csname check#2parent\endcsname
+ \expandafter\noexpand\csname saved_setup_current#2\endcsname
+ \expandafter\noexpand\csname nested_setup_current#2\endcsname}}
+
+\unexpanded\def\installbasicparameterhandler#1#2%
+ {\installparameterhandler {#1}{#2}%
+ \installparameterhashhandler{#1}{#2}%
+ \installparametersethandler {#1}{#2}%
+ \installrootparameterhandler{#1}{#2}}
+
+\unexpanded\def\installbasicautosetuphandler#1#2#3% \??self name \??parent (can be \??self)
+ {\installbasicparameterhandler{#1}{#2}%
+ \installautosetuphandler {#1}{#2}}
+
+\unexpanded\def\installstylisticautosetuphandler#1#2#3% \??self name \??parent (can be \??self)
+ {\installbasicparameterhandler{#1}{#2}%
+ \installautosetuphandler {#1}{#2}%
+ \installstyleandcolorhandler {#1}{#2}}
+
+\unexpanded\def\installcommandhandler#1#2#3% \??self name \??parent (can be \??self)
+ {\installbasicparameterhandler{#1}{#2}%
+ \installdefinehandler {#1}{#2}{#3}%
+ \installsetuphandler {#1}{#2}%
+ \installstyleandcolorhandler {#1}{#2}}
+
+\unexpanded\def\installswitchcommandhandler#1#2#3% \??self name \??parent (can be \??self)
+ {\installbasicparameterhandler{#1}{#2}%
+ \installdefinehandler {#1}{#2}{#3}%
+ \installswitchsetuphandler {#1}{#2}%
+ \installstyleandcolorhandler {#1}{#2}}
+
+\unexpanded\def\installautocommandhandler#1#2#3% automatically defined cloned setups
+ {\installbasicparameterhandler{#1}{#2}%
+ \installdefinehandler {#1}{#2}{#3}%
+ \installautosetuphandler {#1}{#2}%
+ \installstyleandcolorhandler {#1}{#2}}
+
+\unexpanded\def\installsimplecommandhandler#1#2#3% no define (experiment) - use \check*parent when defining
+ {\installbasicparameterhandler{#1}{#2}%
+ \installsetuphandler {#1}{#2}%
+ \installstyleandcolorhandler {#1}{#2}}
+
+%D Many mechanisms have some kind of inheritance in place, and these are the
+%D speed||critical ones. Therefore there is no reason to stick to \type {\@@xxkey}
+%D for the sake of performance. For this reason we also provide a direct variant.
+%D This permits a more consistent treatment of namespaces. A \type
+%D {\whateverparameter} call is three times slower and a \type
+%D {\directwhateverparameter} call two times but for some 100K expansions we only
+%D loose some .1 second which is neglectable given the small amount of expansions in
+%D real runs.
+
+%D We don't need colons for such simple cases.
+
+\unexpanded\def\mult_interfaces_install_direct_parameter_handler#1#2#3#4#5%
+%%{\def#3##1{\csname\ifcsname#1##1\endcsname#1##1\else\s!empty\fi\endcsname}%
+ {\def#3##1{\begincsname#1##1\endcsname}%
+ \def#4##1{\detokenize\expandafter\expandafter\expandafter{\csname#1##1\endcsname}}%
+ % \def#4##1{\mult_interfaces_detokenize{\csname\ifcsname#1#2:##1\endcsname#1#2:##1\else\expandafter#5\csname#1#2:\s!parent\endcsname{##1}\fi\endcsname}}%
+ \def#5##1{\begincsname#1##1\endcsname}}
+
+\unexpanded\def\installdirectparameterhandler#1#2%
+ {\normalexpanded
+ {\mult_interfaces_install_direct_parameter_handler
+ {\noexpand#1}%
+ \expandafter\noexpand\csname current#2\endcsname
+ \expandafter\noexpand\csname #2parameter\endcsname
+ \expandafter\noexpand\csname detokenized#2parameter\endcsname
+ \expandafter\noexpand\csname direct#2parameter\endcsname}}
+
+\unexpanded\def\mult_interfaces_install_direct_setup_handler#1#2#3#4#5%
+ {\unexpanded\def#2{\dosingleempty#3}%
+ \newtoks#5%
+ \def#3[##1]{\mult_interfaces_get_parameters#1[##1]\the#5}%
+ \def#4{\mult_interfaces_get_parameters#1}}
+
+\unexpanded\def\installdirectsetuphandler#1#2%
+ {\normalexpanded
+ {\mult_interfaces_install_direct_setup_handler
+ {\noexpand#1}% \??aa
+ \expandafter\noexpand\csname setup#2\endcsname
+ \expandafter\noexpand\csname setup_#2\endcsname % semi-public
+ \expandafter\noexpand\csname setupcurrent#2\endcsname % no \every (we use 'current' for consistency)
+ \expandafter\noexpand\csname everysetup#2\endcsname}}
+
+% \unexpanded\def\mult_interfaces_install_direct_parameter_set_handler#1#2#3#4#5%
+% {\unexpanded\def#2{\mult_interfaces_def #1}%
+% \unexpanded\def#3{\mult_interfaces_edef#1}%
+% \unexpanded\def#4{\mult_interfaces_let #1}%
+% \unexpanded\def#5{\mult_interfaces_let #1\empty}}%
+
+% \startinterface english
+ \unexpanded\def\mult_interfaces_install_direct_parameter_set_handler#1#2#3#4#5%
+ {\unexpanded\def#2##1{\expandafter \def\csname#1##1\endcsname}%
+ \unexpanded\def#3##1{\expandafter\edef\csname#1##1\endcsname}%
+ \unexpanded\def#4##1{\expandafter \let\csname#1##1\endcsname}%
+ \unexpanded\def#5##1{\expandafter \let\csname#1##1\endcsname\empty}}%
+% \stopinterface
+
+\unexpanded\def\installdirectparametersethandler#1#2%
+ {\normalexpanded
+ {\mult_interfaces_install_direct_parameter_set_handler
+ {\noexpand#1}% \??aa
+ \expandafter\noexpand\csname set#2parameter\endcsname
+ \expandafter\noexpand\csname setexpanded#2parameter\endcsname
+ \expandafter\noexpand\csname let#2parameter\endcsname
+ \expandafter\noexpand\csname reset#2parameter\endcsname}}
+
+\let\installdirectstyleandcolorhandler\installstyleandcolorhandler
+
+\unexpanded\def\installdirectcommandhandler#1#2%
+ {\installdirectparameterhandler {#1}{#2}%
+ \installdirectsetuphandler {#1}{#2}%
+ \installdirectparametersethandler {#1}{#2}%
+ \installdirectstyleandcolorhandler{#1}{#2}}
+
+\unexpanded\def\installsetuponlycommandhandler#1#2%
+ {\installdirectparameterhandler{#1}{#2}%
+ \installdirectsetuphandler {#1}{#2}%
+ }% maybe \installdirectparametersethandler {#1}{#2}%
+
+% Experiment:
+
+% \installcorenamespace {one}
+% \installcorenamespace {two}
+%
+% \installcommandhandler \??one {one} \??one
+% \installcommandhandler \??two {two} \??two
+%
+% \defineone[test] \setupone[test][alpha=first]
+% \definetwo[test] \setuptwo[test][beta=second]
+%
+% \protect
+%
+% \def\currentone{test}
+% \def\currenttwo{test}
+%
+% \relateparameterhandlers {two} {test} {one} {test}
+%
+% yes:\oneparameter{alpha}\par
+% nop:\oneparameter{beta}\par
+% yes:\twoparameter{alpha}\par
+% yes:\twoparameter{beta}\par
+
+\unexpanded\def\relateparameterhandlers#1#2#3#4% {from} {instance} {to} {instance}
+ {\expandafter\edef\csname\csname#1namespace\endcsname#2:\s!parent\endcsname{\csname#3namespace\endcsname#4}}
+
+\unexpanded\def\relateparameterhandlersbyns#1#2#3#4% {from} {instance} {to} {instance}
+ {\expandafter\edef\csname#1#2:\s!parent\endcsname{#3#4}}
+
+%D Here is another experiment:
+
+\unexpanded\def\installactionhandler#1%
+ {\normalexpanded
+ {\mult_interfaces_install_action_handler
+ {#1}%
+ \expandafter\noexpand\csname current#1\endcsname
+ \expandafter\noexpand\csname setupcurrent#1\endcsname
+ \expandafter\noexpand\csname #1_action\endcsname}}
+
+% \unexpanded\def\mult_interfaces_install_action_handler#1#2#3#4%
+% {\unexpanded\expandafter\def\csname#1\endcsname{\dodoubleempty#4}%
+% \unexpanded\def#4[##1][##2]%
+% {\begingroup
+% \ifsecondargument
+% \edef#2{##1}%
+% #3[##2]%
+% \else\iffirstargument
+% \doifelseassignment{##1}
+% {\let#2\empty
+% #3[##1]}%
+% {\edef#2{##1}}%
+% \else
+% \let#2\empty
+% \fi\fi
+% \directsetup{handler:action:#1}%
+% \endgroup}}
+
+\unexpanded\def\mult_interfaces_install_action_handler#1#2#3#4%
+ {\unexpanded\expandafter\def\csname#1\endcsname{\dodoubleempty#4}%
+ \unexpanded\def#4[##1][##2]%
+ {\begingroup
+ \ifsecondargument
+ \edef#2{##1}%
+ #3[##2]%
+ \orelse\iffirstargument
+ \ifcondition\expandafter\mult_check_for_assignment_indeed_begin_\detokenize{##1}=^^^^0003^^^^0003^^^^0004%
+ \edef#2{##1}%
+ \else
+ \let#2\empty
+ #3[##1]%
+ \fi
+ \else
+ \let#2\empty
+ \fi
+ \directsetup{handler:action:#1}%
+ \endgroup}}
+
+% First we had, in tune with the regular system variables:
+%
+% \starttyping
+% \unexpanded\def\installnamespace#1{\setvalue{????#1}{@@@@#1}}
+% \stoptyping
+%
+% The following variant is nicer and in principle faster but that gets unnoticed
+% unless lots of expansion happens. Also, we can use long tags but the internal
+% expansion will be relatively small (and unlikely more than 4 characters). For
+% instance, \??xx used to expand to @@xx but now becomes for instance 123::. This
+% is one character more but in quite some cases we had : after such a tag in the
+% old situation. In the new situation we create more namespaces and don't need that
+% : any more, so we end up with on the average the same amount of tokens and
+% definitely less when we consider cases like \??xx:\c!align: which now is just
+% \??somealign and therefore has length 5 now (instead of 4+1+5+1=10).
+%
+% Eventualy we will have a verbose \blablanamespace and the difference between core
+% and regular can go ... after all, \xxxparameter can already clash between the two
+% prefix groups .. if users use this mechanism a lot they should use verbose names
+% anyway (the old two character names were mostly an optimization as they also
+% expanded to these characters).
+
+% todo: register namespaces at lua end for logging and reverse resolve
+% todo: move this to syst-ini so that we can use it real early
+
+\newcount\c_mult_interfaces_n_of_namespaces
+
+%def\v_interfaces_prefix_template{\number \c_mult_interfaces_n_of_namespaces>}
+%def\v_interfaces_prefix_template{\characters\c_mult_interfaces_n_of_namespaces>}
+
+%def\v_interfaces_prefix_template % consistently %03i>
+% {\ifnum\c_mult_interfaces_n_of_namespaces<\plusten00\else\ifnum\c_mult_interfaces_n_of_namespaces<\plushundred0\fi\fi
+% \number\c_mult_interfaces_n_of_namespaces>}
+
+\def\v_interfaces_prefix_template
+ {\number\c_mult_interfaces_n_of_namespaces>}
+
+\unexpanded\def\installnamespace#1% for modules and users
+ {\ifcsname ????#1\endcsname
+ \writestatus\m!system{duplicate user namespace '#1'}\wait
+ \else
+ \global\advance\c_mult_interfaces_n_of_namespaces\plusone
+ \expandafter\edef\csname ????#1\endcsname{\v_interfaces_prefix_template}%
+ \fi}
+
+\unexpanded\def\installcorenamespace#1%
+ {\ifcsname ??#1\endcsname
+ \writestatus\m!system{duplicate core namespace '#1'}\wait
+ \else
+ \global\advance\c_mult_interfaces_n_of_namespaces\plusone
+ \expandafter\edef\csname ??#1\endcsname{\v_interfaces_prefix_template}%
+ \clf_registernamespace\c_mult_interfaces_n_of_namespaces{#1}%
+ \fi}
+
+\def\mult_interfaces_get_parameters_error_indeed#1#2%
+ {\clf_showassignerror{#1}{#2}\inputlineno}
+
+% We install two core namespaces here, as we want nice error messages. Maybe
+% we will reserve the first 9.
+
+\installcorenamespace{fontinstanceready}
+\installcorenamespace{fontinstancebasic}
+\installcorenamespace{fontinstanceclass}
+
+%D The next one is handy for local assignments.
+
+\installcorenamespace{dummy}
+
+\letvalue\??dummy\empty
+
+ \def\dummyparameter #1{\begincsname\??dummy#1\endcsname}
+ \def\directdummyparameter #1{\begincsname\??dummy#1\endcsname}
+\unexpanded\def\setdummyparameter #1{\expandafter\def\csname\??dummy#1\endcsname}
+\unexpanded\def\setexpandeddummyparameter#1{\expandafter\edef\csname\??dummy#1\endcsname}
+\unexpanded\def\letdummyparameter #1{\expandafter\let\csname\??dummy#1\endcsname}
+
+% \unexpanded\def\getdummyparameters
+% {\mult_interfaces_get_parameters\??dummy}
+
+\unexpanded\def\getdummyparameters[#1%
+ {\if\noexpand#1]%
+ \expandafter\gobbleoneargument
+ \else
+ \let\m_mult_interfaces_namespace\??dummy
+ \expandafter\mult_interfaces_get_parameters_indeed
+ \fi#1}
+
+\mult_interfaces_install_style_and_color_handler
+ \directdummyparameter
+ \usedummystyleandcolor
+ \usedummystyleparameter
+ \usedummycolorparameter
+
+% Maybe a \definecorenamespace[name][directparameter,directsetup][parent] but we
+% don't gain much. Actually we might just inline all definitions.
+
+% \enabletrackers[interfaces.namespaces,context.flush]
+%
+% \definenamespace
+% [xy]
+% [type=module,
+% comment=test module,
+% version=1,
+% name=test,
+% style=yes,
+% command=yes,
+% setup=list,
+% set=yes,
+% parent=xy]
+%
+% \unprotect
+% \getparameters
+% [\????xy]
+% [text=]
+% \protect
+%
+% \definetest[one]
+%
+% \starttext
+%
+% “\testparameter{text}”
+%
+% \setuptest[text=foo]
+%
+% “\testparameter{text}”
+%
+% \setuptest[one][text=bar]
+%
+% “\testparameter{text}”
+%
+% \stoptext
+%
+% This is a user (module) command:
+
+\unexpanded\def\definenamespace
+ {\dodoubleargument\mult_interfaces_define_name_space}
+
+\def\mult_interfaces_define_name_space[#1][#2]% namespace settings
+ {\clf_definenamespace{#1}{#2}}
+
+\def\listnamespaces
+ {\clf_listnamespaces}
+
+%D Helper:
+%D
+%D \starttyping
+%D \showparentchain{@@am}{left}
+%D \stoptyping
+
+\unexpanded\def\showparentchain#1#2%
+ {\writestatus\m!system{chain: [ \mult_interfaces_show_parent_chain{#1#2}]}}
+
+% \def\mult_interfaces_show_parent_chain#1%
+% {#1 => %
+% \ifcsname#1:\s!parent\endcsname
+% \expandafter\mult_interfaces_show_parent_chain\csname#1:\s!parent\endcsname
+% \fi}
+
+\def\mult_interfaces_show_parent_chain#1%
+ {#1 => %
+ \ifcsname#1:\s!parent\endcsname
+ %\expandafter\mult_interfaces_show_parent_chain\csname#1:\s!parent\endcsname
+ \expandafter\mult_interfaces_show_parent_chain\lastnamedcs
+ \fi}
+
+%D Another helper (needs to be applied):
+
+\unexpanded\def\doifelsecommandhandler#1#2% namespace name
+ {\ifcsname#1#2:\s!parent\endcsname
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\let\doifcommandhandlerelse\doifelsecommandhandler
+
+\unexpanded\def\doifcommandhandler#1#2% namespace name
+ {\ifcsname#1#2:\s!parent\endcsname
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\unexpanded\def\doifnotcommandhandler#1#2% namespace name
+ {\ifcsname#1#2:\s!parent\endcsname
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+\let\doifcommandhandlerelse\doifelsecommandhandler
+
+% another set of (fast) helpers (grep for usage):
+
+\def\expandnamespaceparameter#1#2#3% \??xx \getp \c!xx \v!yy
+ {\csname#1\ifcsname#1\expandafter\expandafter\expandafter\mult_aux_expand_namespace_parameter#2#3}
+
+\def\mult_aux_expand_namespace_parameter#1#2% \cs \v!yy
+ {#1\endcsname#1\else#2\fi\endcsname}
+
+\def\expandnamespacemacro#1#2#3% \??xx \some_edefed_cs \c!yy
+ {\csname#1\ifcsname#1#2\endcsname#2\else#3\fi\endcsname}
+
+\def\expandnamespacevalue#1#2% \??xx {...} \c!yy == optimized \expandcheckedcsname
+ {\csname#1\ifcsname#1\normalexpanded{\noexpand\syst_helpers_expand_checked_value{#2}}}
+
+\def\syst_helpers_expand_checked_value#1#2%
+ {#1\endcsname#1\else#2\fi\endcsname}
+
+%D Conventions:
+%D
+%D \starttyping
+%D \newcount \c_class_whatever
+%D \newconditional \c_class_whatever
+%D \newconstant \c_class_whatever
+%D \newdimen \d_class_whatever
+%D \newskip \s_class_whatever
+%D \newmuskip \s_class_whatever
+%D \newbox \b_class_whatever
+%D \newtoks \t_class_whatever
+%D
+%D \edef\p_class_whatever{\classparameter\c!whatever}
+%D \edef\m_class_whatever{whatever}
+%D \stoptyping
+
+% experiment: in principle this is faster but not that noticeable as we don't do that
+% many assignments and mechanism that do are also slow; the advantage is mostly nicer
+% in tracing
+
+\def\s!simple{simple}
+\def\s!single{single}
+\def\s!double{double}
+\def\s!triple{triple}
+
+\let\c_mult_set\relax
+
+\unexpanded\def\mult_interfaces_install_definition_set#1#2#3#4#5#6#7%
+ {\newcount#3%
+ \let#6\empty
+ \unexpanded\def#2%
+ {\expandafter\let\expandafter\c_mult_set\csname #1_t_#6\endcsname
+ \ifx\c_mult_set\relax
+ \expandafter\newtoks\c_mult_set
+ \expandafter\let\csname #1_t_#6\endcsname\c_mult_set
+ \fi}
+ \unexpanded\def#4##1%
+ {\pushmacro#6%
+ \advance#3\plusone
+ \edef#6{##1}%
+ \unprotect}%
+ \unexpanded\def#5%
+ {\protect
+ \advance#3\minusone
+ \popmacro#6}%
+ \unexpanded\def#7##1%
+ {\edef#6{##1}%
+ #2%
+ \the\c_mult_set\relax}}
+
+\unexpanded\def\installdefinitionset#1#2%
+ {\normalexpanded
+ {\mult_interfaces_install_definition_set
+ {\noexpand#1}% \??aa
+ \expandafter\noexpand\csname set_#2_toks\endcsname
+ \expandafter\noexpand\csname #2_nesting_depth\endcsname
+ \expandafter\noexpand\csname push#2\endcsname
+ \expandafter\noexpand\csname pop#2\endcsname
+ \expandafter\noexpand\csname current#2\endcsname
+ \expandafter\noexpand\csname use#2\endcsname}}
+
+\unexpanded\def\mult_interfaces_install_definition_set_member#1#2#3#4#5#6#7#8#9% no everysetups etc
+ {\let#5#2%
+ \unexpanded\def#2%
+ {\ifcase#4\relax\expandafter#5\else\expandafter#6\fi}%
+ \unexpanded\def#6%
+ {\dodoubleempty#7}%
+ \unexpanded\def#7[##1][##2]%
+ {\ifsecondargument
+ %#3\c_mult_set\expandafter{\the\c_mult_set#9[##1][##2]}%
+ #3\toksapp\c_mult_set{#9[##1][##2]}%
+ \orelse\iffirstargument
+ %#3\c_mult_set\expandafter{\the\c_mult_set#8[##1]}%
+ #3\toksapp\c_mult_set{#8[##1]}%
+ \fi}}
+
+\unexpanded\def\installdefinitionsetmember#1#2#3#4%
+ {\normalexpanded
+ {\mult_interfaces_install_definition_set_member
+ {\noexpand#3}% \??aa
+ \expandafter\noexpand\csname setup#4\endcsname
+ \expandafter\noexpand\csname set_#2_toks\endcsname
+ \expandafter\noexpand\csname #2_nesting_depth\endcsname
+ \expandafter\noexpand\csname normal_setup_#4\endcsname
+ \expandafter\noexpand\csname delayed_setup_#4\endcsname
+ \expandafter\noexpand\csname do_delayed_setup_#4\endcsname
+ \expandafter\noexpand\csname setup#4_\s!single\endcsname
+ \expandafter\noexpand\csname setup#4_\s!double\endcsname}}
+
+%D Another experiment:
+
+\unexpanded\def\mult_interfaces_install_parent_injector#1#2#3#4%
+ {\unexpanded\def#4##1%
+ {\ifx#3\empty
+ \expandafter\def\csname#1#2:\s!parent\endcsname{#1##1}%
+ \fi}}
+
+\unexpanded\def\installparentinjector#1#2%
+ {\normalexpanded{\mult_interfaces_install_parent_injector
+ {\noexpand#1}%
+ \expandafter\noexpand\csname current#2\endcsname
+ \expandafter\noexpand\csname current#2parent\endcsname
+ \expandafter\noexpand\csname inject#2parent\endcsname}}
+
+% Faster but not used that much to make a dent in performance. But, because it's
+% cleaner anyway and also gives less tracing, we apply it a few times.
+
+\unexpanded\def\syst_helpers_install_macro_stack#1#2#3%
+ {\xdef\m_syst_helpers_push_macro{\csstring#1}%
+ \ifcsname#3\m_syst_helpers_push_macro\endcsname\else
+ \expandafter\newcount\csname#3\m_syst_helpers_push_macro\endcsname
+ \expandafter\edef\csname push_macro_\m_syst_helpers_push_macro\endcsname
+ {\noexpand\expandafter\glet
+ \noexpand\csname\m_syst_helpers_push_macro\noexpand\the\csname#3\m_syst_helpers_push_macro\endcsname\endcsname
+ \noexpand#1%
+ \global\advance\csname#3\m_syst_helpers_push_macro\endcsname\plusone}%
+ \expandafter\edef\csname pop_macro_\m_syst_helpers_push_macro\endcsname
+ {\global\advance\csname#3\m_syst_helpers_push_macro\endcsname\minusone
+ \noexpand\expandafter#2%
+ \noexpand\expandafter\noexpand#1%
+ \noexpand\csname\m_syst_helpers_push_macro\noexpand\the\csname#3\m_syst_helpers_push_macro\endcsname\endcsname}%
+ \fi}
+
+\unexpanded\def\installmacrostack #1{\syst_helpers_install_macro_stack#1\let \??localpushedmacro }
+\unexpanded\def\installglobalmacrostack#1{\syst_helpers_install_macro_stack#1\glet\??globalpushedmacro}
+
+% \unprotect
+%
+% \installcorenamespace {test} \installcommandhandler \??test {test} \??test
+% \unexpanded\def\TestMeA[#1]%
+% {\edef\currenttest{#1}
+% \edef\p_before{\testparameter\c!before}%
+% \ifx\p_before\empty \relax \else \relax \fi}
+% \unexpanded\def\TestMeB[#1]%
+% {\edef\currenttest{#1}
+% \doifelsenothing{\testparameter\c!before}\relax\relax}
+% \unexpanded\def\TestMeC[#1]%
+% {\edef\currenttest{#1}
+% \expandafter\expandafter\expandafter\ifx\testparameter\c!before\empty \relax \else \relax \fi}
+% \unexpanded\def\TestMeD[#1]%
+% {\edef\currenttest{#1}
+% \doubleexpandafter\ifx\testparameter\c!before\empty \relax \else \relax \fi}
+%
+% \protect
+%
+% \starttext
+% \definetest[foo] \definetest[bar][foo] \setuptest[bar][before=indeed]
+% \testfeatureonce{100000}{\TestMeA[bar]} A:\elapsedtime \par % 0.502
+% \testfeatureonce{100000}{\TestMeB[bar]} B:\elapsedtime \par % 0.530
+% \testfeatureonce{100000}{\TestMeC[bar]} C:\elapsedtime \par % 0.487
+% \testfeatureonce{100000}{\TestMeD[bar]} D:\elapsedtime \par % 0.493
+% \stoptext
+
+% There is no real demand for this ... even if this is two to three times as fast we
+% only gain a few milliseconds:
+%
+% \starttyping
+% \unexpanded\def\foo#1{[foo:#1]}
+%
+% \installcommalistprocessor {foo} \foo
+% \installcommalistprocessorcommand \processfoolist \foo
+%
+% \infofont
+%
+% \commalistprocessor{foo}[a,b,c,{x,y,z},d]\par
+% \processfoolist[a, b, c, {x,y,z}, d]\par
+% \processcommalist[{x,y,z}]\foo\blank
+%
+% \commalistprocessor{foo}[{x,y,z},a]\par
+% \commalistprocessor{foo}[{x,y,z}]\par
+% \processfoolist[{x,y,z},a]\par
+% \processfoolist[{x,y,z}]\par
+% \processcommalist[{x,y,z}]\foo\blank
+%
+% \unexpanded\def\foo#1{}
+%
+% \testfeatureonce{400000}{\processfoolist [fixed,middle,bar]} \elapsedtime\quad
+%%\testfeatureonce{400000}{\commalistprocessor{foo}[fixed,middle,bar]} \elapsedtime\quad
+% \testfeatureonce{400000}{\processcommalist [fixed,middle,bar]\foo} \elapsedtime\quad
+% \stoptyping
+%
+% For instance the luatex manual only has some 3000 calls. But I keep this around as one
+% never knows when we might need it.
+
+\installcorenamespace{commalistprocessor}
+\installcorenamespace{commalistprocessorwrap}
+\installcorenamespace{commalistprocessorfirst}
+\installcorenamespace{commalistprocessornext}
+\installcorenamespace{commalistprocessoraction}
+
+\unexpanded\def\installcommalistprocessor#1#2% 5 macro names overhead
+ {\unexpanded\expandafter\edef\csname\??commalistprocessor#1\endcsname[%
+ % {\noexpand\futureexpandis]%
+ % \noexpand\gobbleoneargument
+ % \csname\??commalistprocessorpickup#1\endcsname}
+ %\unexpanded\expandafter\edef\csname\??commalistprocessorpickup#1\endcsname
+ {\csname\??commalistprocessorwrap#1\endcsname\relax}% \relax preserves {}
+ \unexpanded\expandafter\edef\csname\??commalistprocessorwrap#1\endcsname##1]%
+ {\csname\??commalistprocessorfirst#1\endcsname##1,]}
+ \unexpanded\expandafter\edef\csname\??commalistprocessorfirst#1\endcsname\relax
+ {\csname\??commalistprocessornext#1\endcsname}%
+ \unexpanded\expandafter\edef\csname\??commalistprocessornext#1\endcsname
+ {\noexpand\futureexpandis]%
+ \noexpand\gobbleoneargument
+ \csname\??commalistprocessoraction#1\endcsname}
+ \unexpanded\expandafter\edef\csname\??commalistprocessoraction#1\endcsname##1,%
+ {\noexpand#2{##1}%
+ \csname\??commalistprocessornext#1\endcsname}}
+
+\unexpanded\def\installcommalistprocessorcommand#1#2% \processor \action
+ {\edef\p_name{\csstring#2}%
+ \installcommalistprocessor\p_name{#2}%
+ \expandafter\let\expandafter#1\csname\??commalistprocessor\p_name\endcsname}
+
+\unexpanded\def\commalistprocessor#1{\csname\??commalistprocessor#1\endcsname}
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mult-chk.mkiv b/Master/texmf-dist/tex/context/base/mkiv/mult-chk.mkiv
index b3005b012cf..83b82242e67 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/mult-chk.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/mult-chk.mkiv
@@ -62,7 +62,7 @@
\def\mult_checkers_get_checked_parameters_nop_indeed#1#2]% needs checking with adapted syst-aux.mkiv
{\def\syst_helpers_get_parameters_assign{\syst_helpers_get_parameters_assign_indeed#1}% will change
- \syst_helpers_process_comma_item#2,],\_e_o_p_}
+ \syst_helpers_process_comma_item#2,],^^^^0004}
\unexpanded\def\disablecheckparameters{\let\getcheckedparameters\mult_checkers_get_checked_parameters_nop}
\unexpanded\def\enablecheckparameters {\let\getcheckedparameters\mult_checkers_get_checked_parameters_yes}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mult-def.lua b/Master/texmf-dist/tex/context/base/mkiv/mult-def.lua
index e03a82a765f..1e22aaa865c 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/mult-def.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/mult-def.lua
@@ -7337,6 +7337,15 @@ return {
["compressseparator"]={
["en"]="compressseparator",
},
+ ["compressdistance"]={
+ ["en"]="compressdistance",
+ },
+ ["compressmethod"]={
+ ["en"]="compressmethod",
+ },
+ ["compressstopper"]={
+ ["en"]="compressstopper",
+ },
["concerns"]={
["en"]="concerns",
["nl"]="betreft",
@@ -8312,6 +8321,16 @@ return {
["hidenumber"]={
["en"]="hidenumber",
},
+ ["horizontal"]={
+ ["cs"]="horizontalne",
+ ["de"]="horizontal",
+ ["en"]="horizontal",
+ ["fr"]="horizontale",
+ ["it"]="orizzontale",
+ ["nl"]="horizontaal",
+ ["pe"]="افقی",
+ ["ro"]="orizontal",
+ },
["hoffset"]={
["cs"]="hoffset",
["de"]="hoffset",
@@ -9089,6 +9108,18 @@ return {
["en"]="middlecommand",
["nl"]="middencommando",
},
+ ["middlecolor"]={
+ ["en"]="middlecolor",
+ ["nl"]="middenkleur",
+ },
+ ["middlestyle"]={
+ ["en"]="middlestyle",
+ ["nl"]="middenletter",
+ },
+ ["middlewidth"]={
+ ["en"]="middlewidth",
+ ["nl"]="middenbreedte",
+ },
["middlespeech"]={
["cs"]="middlespeech",
["de"]="middlespeech",
@@ -9551,6 +9582,10 @@ return {
["en"]="order",
["nl"]="volgorde",
},
+ ["anchoring"]={
+ ["en"]="anchoring",
+ ["nl"]="verankering",
+ },
["orientation"]={
["cs"]="orientation",
["de"]="orientation",
@@ -9594,6 +9629,10 @@ return {
["pe"]="شماره‌خود",
["ro"]="numarpropriu",
},
+ ["packcriterium"]={
+ ["en"]="packcriterium",
+ ["nl"]="opelkaarcriterium",
+ },
["page"]={
["cs"]="stranka",
["de"]="seite",
@@ -9650,6 +9689,10 @@ return {
["pageleft"]={
["en"]="pageleft",
},
+ ["pagemethod"]={
+ ["en"]="pagemethod",
+ ["nl"]="paginamethode",
+ },
["pagenumber"]={
["cs"]="cislostranky",
["de"]="seitennummer",
@@ -11371,6 +11414,16 @@ return {
["en"]="vector",
["nl"]="vector",
},
+ ["vertical"]={
+ ["cs"]="vertikalne",
+ ["de"]="vertikal",
+ ["en"]="vertical",
+ ["fr"]="verticale",
+ ["it"]="verticale",
+ ["nl"]="vertikaal",
+ ["pe"]="عمودی",
+ ["ro"]="vertical",
+ },
["veroffset"]={
["cs"]="offsethlavicky",
["de"]="kopfoffset",
@@ -11476,6 +11529,10 @@ return {
["xmlsetup"]={
["en"]="xmlsetup",
},
+ ["xanchor"]={
+ ["en"]="xanchor",
+ ["nl"]="xanker",
+ },
["xoffset"]={
["cs"]="xoffset",
["de"]="xoffset",
@@ -11526,6 +11583,10 @@ return {
["pe"]="ymax",
["ro"]="ymax",
},
+ ["yanchor"]={
+ ["en"]="yanchor",
+ ["nl"]="yanker",
+ },
["yoffset"]={
["cs"]="yoffset",
["de"]="yoffset",
@@ -13119,6 +13180,9 @@ return {
["compressseparator"]={
["en"]="compressseparator",
},
+ ["compressstopper"]={
+ ["en"]="compressstopper",
+ },
["concept"]={
["cs"]="koncept",
["de"]="konzept",
@@ -13368,6 +13432,10 @@ return {
["pe"]="ته‌نوشت",
["ro"]="endnote",
},
+ ["textnote"]={
+ ["en"]="textnote",
+ ["nl"]="tekstnoot",
+ },
["enumeration"]={
["cs"]="vycet",
["de"]="nummerierung",
@@ -13902,6 +13970,10 @@ return {
["pe"]="آویزان",
["ro"]="suspendat",
},
+ ["hangingboth"]={
+ ["en"]="hangingboth",
+ ["nl"]="beidehangend",
+ },
["head"]={
["cs"]="hlavicka",
["de"]="kopf",
@@ -14276,6 +14348,10 @@ return {
["pe"]="درون‌متن",
["ro"]="intext",
},
+ ["headintext"]={
+ ["en"]="headintext",
+ ["nl"]="kopintekst",
+ },
["intro"]={
["cs"]="uvod",
["de"]="intro",
@@ -15154,6 +15230,10 @@ return {
["pe"]="بدون‌نشانه‌گذاری",
["ro"]="faramarcare",
},
+ ["nomenubar"]={
+ ["en"]="nomenubar",
+ ["nl"]="geenmenubalk",
+ },
["none"]={
["cs"]="zadny",
["de"]="kein",
@@ -16097,6 +16177,10 @@ return {
["selectfont"]={
["en"]="selectfont",
},
+ ["separator"]={
+ ["en"]="separator",
+ ["nl"]="scheider",
+ },
["september"]={
["cs"]="zari",
["de"]="september",
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mult-def.mkiv b/Master/texmf-dist/tex/context/base/mkiv/mult-def.mkiv
index d9404bc1625..78fcdf667dd 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/mult-def.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/mult-def.mkiv
@@ -37,9 +37,9 @@
% some left-overs
-\def\c!HL {HL}
-\def\c!VL {VL}
-\def\c!NL {NL}
+\def\c!HL{HL}
+\def\c!VL{VL}
+\def\c!NL{NL}
% stop todo
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mult-fun.lua b/Master/texmf-dist/tex/context/base/mkiv/mult-fun.lua
index 0776f36b4b2..99700f47458 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/mult-fun.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/mult-fun.lua
@@ -17,6 +17,26 @@ return {
"drawoptionsfactor",
"dq", "sq",
"crossingscale", "crossingoption",
+ "contextlmtxmode",
+ --
+ -- for the moment we put these here as they need to stand out
+ --
+ "getparameters",
+ "presetparameters",
+ "hasparameter",
+ "hasoption",
+ "getparameter",
+ "getparameterdefault",
+ "getparametercount",
+ "getmaxparametercount",
+ "getparameterpath",
+ "getparameterpen",
+ "getparametertext",
+ -- "getparameteroption",
+ "applyparameters",
+ "pushparameters",
+ "popparameters",
+ "definecolor",
},
commands = {
"loadfile", "loadimage", "loadmodule",
@@ -65,7 +85,7 @@ return {
"withmask", "bitmapimage",
"colordecimals", "ddecimal", "dddecimal", "ddddecimal", "colordecimalslist",
"textext", "thetextext", "rawtextext", "textextoffset", "texbox", "thetexbox", "rawtexbox", "istextext",
- "notcached",
+ "notcached", "keepcached",
"verbatim",
"thelabel", "label",
"autoalign",
@@ -136,7 +156,7 @@ return {
"passvariable", "passarrayvariable", "tostring", "topair", "format", "formatted", "quotation", "quote",
"startpassingvariable", "stoppassingvariable",
--
- "eofill", "eoclip", "nofill", "fillup", "eofillup",
+ "eofill", "eoclip", "nofill", "dofill", "fillup", "eofillup", "nodraw", "dodraw",
"area",
--
"addbackground",
@@ -165,6 +185,8 @@ return {
--
"inpath", "pointof", "leftof", "rightof",
--
+ "utflen", "utfsub",
+ --
"newhash", "disposehash", "inhash", "tohash",
--
"isarray", "prefix", "isobject",
@@ -172,5 +194,7 @@ return {
"comment", "report", "lua", "mp", "MP", "luacall",
--
"mirrored", "mirroredabout",
+ --
+ "scriptindex",
},
}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mult-ini.mkiv b/Master/texmf-dist/tex/context/base/mkiv/mult-ini.mkiv
index 634e2c1d827..641c8a4f50e 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/mult-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/mult-ini.mkiv
@@ -124,6 +124,13 @@
\def\s!top {top}
\def\s!both {both}
+\def\s!reverse {reverse}
+\def\s!orientation{orientation}
+\def\s!xoffset {xoffset}
+\def\s!xmove {xmove}
+\def\s!yoffset {yoffset}
+\def\s!ymove {ymove}
+
%D \macros
%D {defineinterfaceconstant,
%D defineinterfacevariable,
@@ -356,12 +363,12 @@
{\ifcsname\m!prefix!#1\endcsname\else\setgvalue{\m!prefix!#1}{#1}\fi
\clf_setinterfacemessage{#1}{#2}{#3}}
-\unexpanded\def\setmessagetext #1#2{\edef\currentmessagetext{\clf_getmessage{#1}{#2}}}
-\unexpanded\def\getmessage #1#2{\clf_getmessage{#1}{#2}}
-\unexpanded\def\doifelsemessage #1#2{\clf_doifelsemessage{#1}{#2}}
-\unexpanded\def\showmessage #1#2#3{\clf_showmessage{#1}{#2}{#3}}
-\unexpanded\def\writestatus #1#2{\clf_writestatus{#1}{#2}}
-\unexpanded\def\message {\clf_message}
+\unexpanded\def\setmessagetext #1#2{\relax\edef\currentmessagetext{\clf_getmessage{#1}{#2}}}
+\unexpanded\def\getmessage #1#2{\relax\clf_getmessage{#1}{#2}}
+\unexpanded\def\doifelsemessage #1#2{\relax\clf_doifelsemessage{#1}{#2}}
+\unexpanded\def\showmessage #1#2#3{\relax\clf_showmessage{#1}{#2}{#3}}
+\unexpanded\def\writestatus #1#2{\relax\clf_writestatus{#1}{#2}}
+\unexpanded\def\message {\relax\clf_message}
\let\doifmessageelse\doifelsemessage
@@ -371,40 +378,9 @@
\let\getsetupstring\clf_getsetupstring
\let\rawsetupstring\clf_rawsetupstring
-%D \macros
-%D {ifshowwarnings, ifshowmessages}
-%D
-%D Sometimes displaying message can slow down processing considerably. We therefore
-%D introduce warnings. Users can turn of warnings and messages by saying:
-%D
-%D \starttyping
-%D \showwarningstrue
-%D \showmessagestrue
-%D \stoptyping
-%D
-%D Turning off messages also turns off warnings, which is quote logical because they
-%D are less important.
-
-% not yet mkiv
+%D For old times sake:
-\newif\ifshowwarnings \showwarningstrue
-\newif\ifshowmessages \showmessagestrue
-
-\let\normalshowmessage\showmessage
-
-\unexpanded\def\showwarning
- {\ifshowwarnings
- \expandafter\showmessage
- \else
- \expandafter\gobblethreearguments
- \fi}
-
-\unexpanded\def\showmessage
- {\ifshowmessages
- \expandafter\normalshowmessage
- \else
- \expandafter\gobblethreearguments
- \fi}
+\let\showwarning\showmessage
%D \macros
%D {dosetvalue,dosetevalue,dosetgvalue,dosetxvalue,docopyvalue,doresetvalue} % dogetvalue
@@ -452,9 +428,9 @@
%D We can now redefine some messages that will be introduced in the multi||lingual
%D system module.
-\unexpanded\def\showassignerror #1#2{\showmessage\m!check1{#1,#2}\waitonfatalerror}
-\unexpanded\def\showargumenterror#1#2{\showmessage\m!check2{#1,#2}\waitonfatalerror}
-\unexpanded\def\showdefinederror #1#2{\showmessage\m!check3{#1,#2}\waitonfatalerror}
+\unexpanded\def\showassignerror #1#2{\showmessage\m!check1{#1,#2}}
+\unexpanded\def\showargumenterror#1#2{\showmessage\m!check2{#1,#2}}
+\unexpanded\def\showdefinederror #1#2{\showmessage\m!check3{#1,#2}}
%D \CONTEXT\ is a parameter driven package. This means that users instruct the
%D system by means of variables, values and keywords. These instructions take the
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mult-low.lua b/Master/texmf-dist/tex/context/base/mkiv/mult-low.lua
index 75c048c92de..aa0329e48cf 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/mult-low.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/mult-low.lua
@@ -141,6 +141,10 @@ return {
"Ux", "eUx", "Umathaccents",
--
"parfillleftskip", "parfillrightskip",
+ --
+ "startlmtxmode", "stoplmtxmode", "startmkivmode", "stopmkivmode",
+ --
+ "wildcardsymbol",
},
["helpers"] = {
--
@@ -240,7 +244,9 @@ return {
"nextbox", "dowithnextbox", "dowithnextboxcs", "dowithnextboxcontent", "dowithnextboxcontentcs", "flushnextbox",
"boxisempty",
--
- "scratchwidth", "scratchheight", "scratchdepth", "scratchoffset", "scratchdistance",
+ "givenwidth", "givenheight", "givendepth", "scangivendimensions",
+ --
+ "scratchwidth", "scratchheight", "scratchdepth", "scratchoffset", "scratchdistance", "scratchtotal",
"scratchhsize", "scratchvsize",
"scratchxoffset", "scratchyoffset", "scratchhoffset", "scratchvoffset",
"scratchxposition", "scratchyposition",
@@ -263,6 +269,7 @@ return {
"doifinset", "doifnotinset",
"doifelseinset", "doifinsetelse",
"doifelsenextchar", "doifnextcharelse",
+ "doifelsenextcharcs", "doifnextcharcselse",
"doifelsenextoptional", "doifnextoptionalelse",
"doifelsenextoptionalcs", "doifnextoptionalcselse",
"doifelsefastoptionalcheck", "doiffastoptionalcheckelse",
@@ -284,8 +291,11 @@ return {
"doifelsecommon", "doifcommonelse", "doifcommon", "doifnotcommon",
"doifinstring", "doifnotinstring", "doifelseinstring", "doifinstringelse",
"doifelseassignment", "doifassignmentelse", "docheckassignment", "doifelseassignmentcs", "doifassignmentelsecs",
+ "validassignment", "novalidassignment",
"doiftext", "doifelsetext", "doiftextelse", "doifnottext",
--
+ "quitcondition", "truecondition", "falsecondition",
+ --
"tracingall", "tracingnone", "loggingall",
--
"removetoks", "appendtoks", "prependtoks", "appendtotoks", "prependtotoks", "to",
@@ -303,7 +313,11 @@ return {
--
"wait", "writestatus", "define", "defineexpandable", "redefine",
--
- "setmeasure", "setemeasure", "setgmeasure", "setxmeasure", "definemeasure", "freezemeasure", "measure", "measured",
+ "setmeasure", "setemeasure", "setgmeasure", "setxmeasure", "definemeasure", "freezemeasure",
+ "measure", "measured", "directmeasure",
+ "setquantity", "setequantity", "setgquantity", "setxquantity", "definequantity", "freezequantity",
+ "quantity", "quantitied", "directquantity",
+ -- "quantified",
--
"installcorenamespace",
--
@@ -367,6 +381,8 @@ return {
"strut", "halfstrut", "quarterstrut", "depthstrut", "halflinestrut", "noheightstrut", "setstrut", "strutbox", "strutht", "strutdp", "strutwd", "struthtdp", "strutgap", "begstrut", "endstrut", "lineheight",
"leftboundary", "rightboundary", "signalcharacter",
--
+ "shiftbox", "vpackbox", "hpackbox", "vpackedbox", "hpackedbox",
+ --
"ordordspacing", "ordopspacing", "ordbinspacing", "ordrelspacing",
"ordopenspacing", "ordclosespacing", "ordpunctspacing", "ordinnerspacing",
--
@@ -458,5 +474,7 @@ return {
"compoundhyphenpenalty",
--
"start", "stop",
+ --
+ "unsupportedcs",
}
}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mult-mes.lua b/Master/texmf-dist/tex/context/base/mkiv/mult-mes.lua
index 1eb429763a0..299f1a404ae 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/mult-mes.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/mult-mes.lua
@@ -1169,6 +1169,10 @@ return {
no = "leser inn symbolsett %a",
ro = "se incarca setul de simboluri %a",
},
+ ["symbols:2"] = {
+ en = "symbolset %a is unknown",
+ nl = "symboolset %a is onbekend",
+ },
["system:1"] = {
cs = "nacteni pomocneho souboru odlozeno (typemode)",
de = "Laden der Hilfsdatei aufgeschoben (Eingabe-Modus)",
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mult-mps.lua b/Master/texmf-dist/tex/context/base/mkiv/mult-mps.lua
index 1d7252c29e2..6385d3fe51f 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/mult-mps.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/mult-mps.lua
@@ -15,7 +15,7 @@ return {
"false", "nullpicture", "pencircle", "penspec", "true",
"and", "angle", "arclength", "arctime", "ASCII", "boolean", "bot",
"char", "color", "cosd", "cycle", "decimal", "directiontime", "floor", "fontsize",
- "hex", "infont", "intersectiontimes", "known", "length", "llcorner",
+ "hex", "infont", "intersectiontimes", "known", "void", "length", "llcorner",
"lrcorner", "makepath", "makepen", "mexp", "mlog", "normaldeviate", "not",
"numeric", "oct", "odd", "or", "path", "pair", "pen", "penoffset", "picture", "point",
"postcontrol", "precontrol", "reverse", "rotated", "scaled",
@@ -23,7 +23,7 @@ return {
"transform", "transformed", "ulcorner", "uniformdeviate", "unknown",
"urcorner", "xpart", "xscaled", "xxpart", "xypart", "ypart", "yscaled", "yxpart",
"yypart", "zscaled",
- "addto", "clip", "input", "interim", "let", "newinternal", "save", "setbounds",
+ "addto", "clip", "input", "interim", "let", "newinternal", "save", "setbounds", "setgroup",
"shipout", "show", "showdependencies", "showtoken", "showvariable",
"special",
"begingroup", "endgroup", "of", "curl", "tension", "and", "controls",
@@ -49,7 +49,7 @@ return {
"extra_beginfig", "extra_endfig", "mpxbreak",
"endinput",
"message", "delimiters", "turningnumber", "errmessage",
- "readstring", "scantokens", "end", "outer", "inner", "write", "to", "readfrom",
+ "scantokens", "end", "outer", "inner", "write", "to", "readfrom", "closefrom",
"withprescript", "withpostscript",
"top", "bot", "lft", "rt", "ulft", "urt", "llft", "lrt",
--
@@ -67,7 +67,7 @@ return {
"outputformat", "outputtemplate", "filenametemplate", "fontmapfile", "fontmapline",
"fontpart", "fontsize", "glyph", "restoreclipcolor", "troffmode",
--
- "runscript", "maketext",
+ "runscript", "maketext", "numbersystem",
},
commands = {
"upto", "downto",
@@ -117,7 +117,8 @@ return {
--
"mm", "pt", "dd", "bp", "cm", "pc", "cc", "in",
--
- "triplet", "quadruplet",
+ "triplet", "quadruplet", "totransform", "bymatrix",
+ --
},
internals = { -- we need to remove duplicates above
--
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mult-prm.lua b/Master/texmf-dist/tex/context/base/mkiv/mult-prm.lua
index 579750bc97d..279de60e2d6 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/mult-prm.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/mult-prm.lua
@@ -15,10 +15,6 @@ return {
"detokenize",
"dimexpr",
"displaywidowpenalties",
- "eTeXVersion",
- "eTeXminorversion",
- "eTeXrevision",
- "eTeXversion",
"everyeof",
"firstmarks",
"fontchardp",
@@ -76,6 +72,7 @@ return {
"Udelimiterover",
"Udelimiterunder",
"Uhextensible",
+ "Uleft",
"Umathaccent",
"Umathaxis",
"Umathbinbinspacing",
@@ -199,10 +196,12 @@ return {
"Umathunderbarvgap",
"Umathunderdelimiterbgap",
"Umathunderdelimitervgap",
+ "Umiddle",
"Unosubscript",
"Unosuperscript",
"Uoverdelimiter",
"Uradical",
+ "Uright",
"Uroot",
"Uskewed",
"Uskewedwithdelims",
@@ -216,6 +215,10 @@ return {
"Uunderdelimiter",
"Uvextensible",
"adjustspacing",
+ "adjustspacingshrink",
+ "adjustspacingstep",
+ "adjustspacingstretch",
+ "aftergrouped",
"alignmark",
"aligntab",
"attribute",
@@ -224,66 +227,79 @@ return {
"automatichyphenmode",
"automatichyphenpenalty",
"begincsname",
- "bodydir",
- "bodydirection",
- "boxdir",
+ "beginlocalcontrol",
+ "boundary",
+ "boxattr",
"boxdirection",
+ "boxorientation",
+ "boxtotal",
+ "boxxmove",
+ "boxxoffset",
+ "boxymove",
+ "boxyoffset",
"breakafterdirmode",
"catcodetable",
"clearmarks",
"compoundhyphenmode",
- "copyfont",
"crampeddisplaystyle",
"crampedscriptscriptstyle",
"crampedscriptstyle",
"crampedtextstyle",
"csstring",
- "draftmode",
- "dviextension",
- "dvifeedback",
- "dvivariable",
"efcode",
"endlocalcontrol",
"etoksapp",
"etokspre",
"exceptionpenalty",
"expanded",
- "expandglyphsinfont",
"explicitdiscretionary",
"explicithyphenpenalty",
+ "firstvalidlanguage",
"fixupboxesmode",
"fontid",
"formatname",
+ "frozen",
+ "futureexpand",
+ "futureexpandis",
+ "futureexpandisap",
"gleaders",
+ "glet",
+ "glyphdatafield",
"gtoksapp",
"gtokspre",
"hjcode",
+ "hpack",
"hyphenationbounds",
"hyphenationmin",
"hyphenpenaltymode",
"ifabsdim",
"ifabsnum",
+ "ifchkdim",
+ "ifchknum",
+ "ifcmpdim",
+ "ifcmpnum",
"ifcondition",
+ "ifcstok",
+ "ifdimval",
+ "iffrozen",
"ifincsname",
- "ifprimitive",
- "ignoreligaturesinfont",
+ "ifnumval",
+ "ifprotected",
+ "iftok",
+ "ifusercmd",
+ "ignorepars",
"immediateassigned",
"immediateassignment",
"initcatcodetable",
"insertht",
+ "internalcodesmode",
"lastnamedcs",
- "lastsavedboxresourceindex",
- "lastsavedimageresourceindex",
- "lastsavedimageresourcepages",
- "lastxpos",
- "lastypos",
- "latelua",
- "lateluafunction",
+ "lastnodesubtype",
"leftghost",
"leftmarginkern",
"letcharcode",
- "letterspacefont",
- "linedir",
+ "letfrozen",
+ "letprotected",
"linedirection",
"localbrokenpenalty",
"localinterlinepenalty",
@@ -301,14 +317,13 @@ return {
"luatexrevision",
"luatexversion",
"mathdelimitersmode",
- "mathdir",
"mathdirection",
"mathdisplayskipmode",
"matheqnogapstep",
"mathflattenmode",
"mathitalicsmode",
"mathnolimitsmode",
- "mathoption",
+ "matholdmode",
"mathpenaltiesmode",
"mathrulesfam",
"mathrulesmode",
@@ -319,27 +334,14 @@ return {
"mathstyle",
"mathsurroundmode",
"mathsurroundskip",
+ "noboundary",
"nohrule",
"nokerns",
"noligs",
- "normaldeviate",
"nospaces",
"novrule",
"outputbox",
- "outputmode",
- "pagebottomoffset",
- "pagedir",
- "pagedirection",
- "pageheight",
- "pageleftoffset",
- "pagerightoffset",
- "pagetopoffset",
- "pagewidth",
- "pardir",
"pardirection",
- "pdfextension",
- "pdffeedback",
- "pdfvariable",
"postexhyphenchar",
"posthyphenchar",
"prebinoppenalty",
@@ -347,38 +349,26 @@ return {
"preexhyphenchar",
"prehyphenchar",
"prerelpenalty",
- "primitive",
"protrudechars",
+ "protrusionboundary",
"pxdimen",
"quitvmode",
- "randomseed",
"rightghost",
"rightmarginkern",
"rpcode",
- "saveboxresource",
"savecatcodetable",
- "saveimageresource",
- "savepos",
"scantextokens",
"setfontid",
- "setrandomseed",
"shapemode",
- "suppressfontnotfounderror",
- "suppressifcsnameerror",
- "suppresslongerror",
- "suppressmathparerror",
- "suppressoutererror",
- "suppressprimitiveerror",
- "synctex",
- "tagcode",
- "textdir",
"textdirection",
"toksapp",
"tokspre",
+ "tpack",
"tracingfonts",
- "uniformdeviate",
- "useboxresource",
- "useimageresource",
+ "unletfrozen",
+ "unletprotected",
+ "vpack",
+ "wordboundary",
"xtoksapp",
"xtokspre",
},
@@ -505,9 +495,6 @@ return {
" ",
"-",
"/",
- "Uleft",
- "Umiddle",
- "Uright",
"above",
"abovedisplayshortskip",
"abovedisplayskip",
@@ -527,7 +514,6 @@ return {
"belowdisplayskip",
"binoppenalty",
"botmark",
- "boundary",
"box",
"boxmaxdepth",
"brokenpenalty",
@@ -536,7 +522,6 @@ return {
"chardef",
"cleaders",
"closein",
- "closeout",
"clubpenalty",
"copy",
"count",
@@ -586,6 +571,7 @@ return {
"everyjob",
"everymath",
"everypar",
+ "everytab",
"everyvbox",
"exhyphenchar",
"exhyphenpenalty",
@@ -594,14 +580,12 @@ return {
"fi",
"finalhyphendemerits",
"firstmark",
- "firstvalidlanguage",
"floatingpenalty",
"font",
"fontdimen",
"fontname",
"futurelet",
"gdef",
- "glet",
"global",
"globaldefs",
"halign",
@@ -615,7 +599,6 @@ return {
"hfuzz",
"hoffset",
"holdinginserts",
- "hpack",
"hrule",
"hsize",
"hskip",
@@ -642,7 +625,6 @@ return {
"ifvoid",
"ifx",
"ignorespaces",
- "immediate",
"indent",
"input",
"inputlineno",
@@ -703,7 +685,6 @@ return {
"muskipdef",
"newlinechar",
"noalign",
- "noboundary",
"noexpand",
"noindent",
"nolimits",
@@ -714,8 +695,9 @@ return {
"number",
"omit",
"openin",
- "openout",
"or",
+ "ordlimits",
+ "orelse",
"outer",
"output",
"outputpenalty",
@@ -745,7 +727,6 @@ return {
"pretolerance",
"prevdepth",
"prevgraf",
- "protrusionboundary",
"radical",
"raise",
"read",
@@ -770,6 +751,7 @@ return {
"showboxbreadth",
"showboxdepth",
"showlists",
+ "shownodedetails",
"showthe",
"skewchar",
"skip",
@@ -777,7 +759,6 @@ return {
"spacefactor",
"spaceskip",
"span",
- "special",
"splitbotmark",
"splitfirstmark",
"splitmaxdepth",
@@ -795,7 +776,6 @@ return {
"tolerance",
"topmark",
"topskip",
- "tpack",
"tracingcommands",
"tracinglostchars",
"tracingmacros",
@@ -826,7 +806,6 @@ return {
"vfilneg",
"vfuzz",
"voffset",
- "vpack",
"vrule",
"vsize",
"vskip",
@@ -835,8 +814,6 @@ return {
"vtop",
"wd",
"widowpenalty",
- "wordboundary",
- "write",
"xdef",
"xleaders",
"xspaceskip",
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mult-sys.mkiv b/Master/texmf-dist/tex/context/base/mkiv/mult-sys.mkiv
index ae0214bd60a..8f8794df71c 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/mult-sys.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/mult-sys.mkiv
@@ -239,39 +239,41 @@
\definesystemconstant {xml}
\definesystemconstant {lua}
-\definesystemconstant {next}
-\definesystemconstant {pickup}
-\definesystemconstant {forget}
-\definesystemconstant {ascii}
-\definesystemconstant {default}
-\definesystemconstant {unknown}
\definesystemconstant {action}
+\definesystemconstant {ascii}
+\definesystemconstant {chain}
+\definesystemconstant {child}
+\definesystemconstant {class}
+\definesystemconstant {clone}
\definesystemconstant {compare}
-\definesystemconstant {do}
-\definesystemconstant {dodo}
\definesystemconstant {complex}
-\definesystemconstant {simple}
-\definesystemconstant {start}
-\definesystemconstant {stop}
-\definesystemconstant {dummy}
-\definesystemconstant {local}
-\definesystemconstant {global}
+\definesystemconstant {counter}
+\definesystemconstant {current}
+\definesystemconstant {default}
+\definesystemconstant {dodo}
\definesystemconstant {done}
+\definesystemconstant {do}
+\definesystemconstant {dummy}
\definesystemconstant {font}
+\definesystemconstant {forget}
+\definesystemconstant {global}
+\definesystemconstant {handler}
+\definesystemconstant {indeed}
+\definesystemconstant {internal}
\definesystemconstant {link}
+\definesystemconstant {local}
+\definesystemconstant {multi}
+\definesystemconstant {next}
\definesystemconstant {parent}
-\definesystemconstant {child}
-\definesystemconstant {clone}
+\definesystemconstant {pickup}
+\definesystemconstant {plural}
\definesystemconstant {section}
-\definesystemconstant {handler}
-\definesystemconstant {counter}
+\definesystemconstant {simple}
\definesystemconstant {single}
-\definesystemconstant {multi}
-\definesystemconstant {indeed}
-\definesystemconstant {internal}
-\definesystemconstant {current}
-\definesystemconstant {chain}
-\definesystemconstant {class}
+\definesystemconstant {singular}
+\definesystemconstant {start}
+\definesystemconstant {stop}
+\definesystemconstant {unknown}
% translating setups is asking for a mess so we keep them as-is:
@@ -365,6 +367,7 @@
\definesystemconstant {marker}
\definesystemconstant {kernpairs}
\definesystemconstant {mixedcolumn}
+\definesystemconstant {orientation}
\definesystemconstant {ampersand}
@@ -457,6 +460,10 @@
\definesystemconstant {xoffset}
\definesystemconstant {yoffset}
+\definesystemconstant {topfloat}
+\definesystemconstant {bottomfloat}
+\definesystemconstant {pagefloat}
+
%D As the name of their define command states, the next set of constants is used in
%D the message macro's.
diff --git a/Master/texmf-dist/tex/context/base/mkiv/node-aux.lua b/Master/texmf-dist/tex/context/base/mkiv/node-aux.lua
index d6a9950fe8c..2a747f3b53b 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/node-aux.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/node-aux.lua
@@ -21,6 +21,7 @@ local glyph_code = nodecodes.glyph
local hlist_code = nodecodes.hlist
local vlist_code = nodecodes.vlist
local attributelist_code = nodecodes.attributelist -- temporary
+local localpar_code = nodecodes.localpar
local nuts = nodes.nuts
local tonut = nuts.tonut
@@ -34,6 +35,7 @@ local getsubtype = nuts.getsubtype
local getlist = nuts.getlist
local getattr = nuts.getattr
local getboth = nuts.getboth
+local getprev = nuts.getprev
local getcomponents = nuts.getcomponents
local getwidth = nuts.getwidth
local setwidth = nuts.setwidth
@@ -49,17 +51,16 @@ local setprev = nuts.setprev
local setcomponents = nuts.setcomponents
local setattrlist = nuts.setattrlist
------ traverse_nodes = nuts.traverse
------ traverse_id = nuts.traverse_id
-local nextnode = nuts.traversers.node
-local nextglyph = nuts.traversers.glyph
+local traversers = nuts.traversers
+local nextnode = traversers.node
+local nextglyph = traversers.glyph
+
local flush_node = nuts.flush
local flush_list = nuts.flush_list
local hpack_nodes = nuts.hpack
local unset_attribute = nuts.unset_attribute
local first_glyph = nuts.first_glyph
local copy_node = nuts.copy
------ copy_node_list = nuts.copy_list
local find_tail = nuts.tail
local getbox = nuts.getbox
local count = nuts.count
@@ -380,25 +381,6 @@ function nodes.rehpack(n,...)
rehpack(tonut(n),...)
end
--- I have no use for this yet:
---
--- \skip0=10pt plus 2pt minus 2pt
--- \cldcontext{"\letterpercent p",tex.stretch_amount(tex.skip[0],1000)} -- 14.30887pt
---
--- local gluespec_code = nodes.nodecodes.gluespec
---
--- function tex.badness_to_ratio(badness)
--- return (badness/100)^(1/3)
--- end
---
--- function tex.stretch_amount(skip,badness) -- node no nut
--- if skip.id == gluespec_code then
--- return skip.width + (badness and (badness/100)^(1/3) or 1) * skip.stretch
--- else
--- return 0
--- end
--- end
-
-- nodemode helper: the next and prev pointers are untouched
function nuts.copy_no_components(g,copyinjection)
@@ -482,12 +464,336 @@ function nuts.use_components(head,current)
return head, first, last
end
--- function nuts.current_tail()
--- local whatever = texnest[texnest.ptr]
--- if whatever then
--- local tail = whatever.tail
--- if tail then
--- return tonut(tail)
--- end
--- end
--- end
+do
+
+ local localparcodes = nodes.localparcodes
+ local hmodepar_code = localparcodes.vmode_par
+ local vmodepar_code = localparcodes.hmode_par
+
+ local getnest = tex.getnest
+ local getsubtype = nuts.getsubtype
+
+ function nuts.setparproperty(action,...)
+ local tail = tonut(getnest().tail)
+ while tail do
+ if getid(tail) == localpar_code then
+ local s = getsubtype(tail)
+ if s == hmodepar_code or s == vmodepar_code then
+ return action(tail,...)
+ else
+ -- something is wrong here
+ end
+ end
+ tail = getprev(tail)
+ end
+ end
+
+ local getsubtype = nodes.getsubtype
+
+ function nodes.start_of_par(n)
+ local s = getsubtype(n)
+ return s == hmodepar_code or s == vmodepar_code
+ end
+
+end
+
+-- Currently only in luametatex ... experimental anyway .. if it doesn't end
+-- up in luatex I'll move this to a different module.
+
+do
+
+ local nextnode = traversers.glue
+ local findfail = nuts.tail
+
+ local getid = nuts.getid
+ local getsubtype = nuts.getsubtype
+ local getlist = nuts.getlist
+ local getwidth = nuts.getwidth
+
+ local direct = node.direct
+
+ local nodecodes = nodes.nodecodes
+ local skipcodes = nodes.skipcodes
+
+ local hlist_code = nodecodes.hlist
+ local line_code = nodecodes.line
+
+ local leftskip_code = skipcodes.leftskip
+ local rightskip_code = skipcodes.rightskip
+ local lefthangskip_code = skipcodes.lefthangskip
+ local righthangskip_code = skipcodes.righthangskip
+ local indentskip_code = skipcodes.indentskip
+ local parfillskip_code = skipcodes.parfillskip
+
+ local find_node = direct.find_node or function(h,t,s)
+ if h then
+ if s then
+ for node, subtype in traversers[t] do
+ if s == subtype then
+ return current
+ end
+ end
+ else
+ for node, subtype in traversers[t] do
+ return current, subtype
+ end
+ end
+ end
+ end
+
+ nuts.find_node = find_node
+
+ nodes.getnormalizeline = nodes.getnormalizeline or function() return 0 end
+ nodes.setnormalizeline = nodes.setnormalizeline or function() end
+
+ nuts.getnormalizedline = direct.getnormalizedline or function(h)
+ if getid(h) == hlist_code and getsubtype(h) == line_code then
+ local ls, rs = 0, 0
+ local lh, rh = 0, 0
+ local is, ps = 0, 0
+ local h = getlist(h)
+ local t = findtail(h)
+ for n, subtype in nextglue, h do
+ if subtype == leftskip_code then ls = getwidth(n)
+ elseif subtype == rightskip_code then rs = getwidth(n)
+ elseif subtype == lefthangskip_code then lh = getwidth(n)
+ elseif subtype == righthangskip_code then rh = getwidth(n)
+ elseif subtype == indentskip_code then is = getwidth(n)
+ elseif subtype == parfillskip_code then ps = getwidth(n)
+ end
+ end
+ return ls, rs, lh, rh, is, ps, h, t
+ end
+ end
+
+end
+
+if not nodes.count then
+
+ local type = type
+
+ local direct = node.direct
+ local todirect = direct.tovaliddirect
+ local tonode = direct.tonode
+
+ local count = direct.count
+ local length = direct.length
+ local slide = direct.slide
+
+ function node.count(id,first,last)
+ return count(id,first and todirect(first), last and todirect(last) or nil)
+ end
+
+ function node.length(first,last)
+ return length(first and todirect(first), last and todirect(last) or nil)
+ end
+
+ function node.slide(n)
+ if n then
+ n = slide(todirect(n))
+ if n then
+ return tonode(n)
+ end
+ end
+ return nil
+ end
+
+ local hyphenating = direct.hyphenating
+ local ligaturing = direct.ligaturing
+ local kerning = direct.kerning
+
+ -- kind of inconsistent
+
+ function node.hyphenating(first,last)
+ if first then
+ local h, t = hyphenating(todirect(first), last and todirect(last) or nil)
+ return h and tonode(h) or nil, t and tonode(t) or nil, true
+ else
+ return nil, false
+ end
+ end
+
+ function node.ligaturing(first,last)
+ if first then
+ local h, t = ligaturing(todirect(first), last and todirect(last) or nil)
+ return h and tonode(h) or nil, t and tonode(t) or nil, true
+ else
+ return nil, false
+ end
+ end
+
+ function node.kerning(first,last)
+ if first then
+ local h, t = kerning(todirect(first), last and todirect(last) or nil)
+ return h and tonode(h) or nil, t and tonode(t) or nil, true
+ else
+ return nil, false
+ end
+ end
+
+ local protect_glyph = direct.protect_glyph
+ local unprotect_glyph = direct.unprotect_glyph
+ local protect_glyphs = direct.protect_glyphs
+ local unprotect_glyphs = direct.unprotect_glyphs
+
+ function node.protect_glyphs(first,last)
+ protect_glyphs(todirect(first), last and todirect(last) or nil)
+ end
+
+ function node.unprotect_glyphs(first,last)
+ unprotect_glyphs(todirect(first), last and todirect(last) or nil)
+ end
+
+ function node.protect_glyph(first)
+ protect_glyph(todirect(first))
+ end
+
+ function node.unprotect_glyph(first)
+ unprotect_glyph(todirect(first))
+ end
+
+ local flatten_discretionaries = direct.flatten_discretionaries
+ local check_discretionaries = direct.check_discretionaries
+ local check_discretionary = direct.check_discretionary
+
+ function node.flatten_discretionaries(first)
+ local h, count = flatten_discretionaries(todirect(first))
+ return tonode(h), count
+ end
+
+ function node.check_discretionaries(n)
+ check_discretionaries(todirect(n))
+ end
+
+ function node.check_discretionary(n)
+ check_discretionary(todirect(n))
+ end
+
+ local hpack = direct.hpack
+ local vpack = direct.vpack
+ local list_to_hlist = direct.mlist_to_hlist
+
+ function node.hpack(head,...)
+ local h, badness = hpack(head and todirect(head) or nil,...)
+ return tonode(h), badness
+ end
+
+ function node.vpack(head,...)
+ local h, badness = vpack(head and todirect(head) or nil,...)
+ return tonode(h), badness
+ end
+
+ function node.mlist_to_hlist(head,...)
+ return tonode(mlist_to_hlist(head and todirect(head) or nil,...))
+ end
+
+ local end_of_math = direct.end_of_math
+ local find_attribute = direct.find_attribute
+ local first_glyph = direct.first_glyph
+
+ function node.end_of_math(n)
+ if n then
+ n = end_of_math(todirect(n))
+ if n then
+ return tonode(n)
+ end
+ end
+ return nil
+ end
+
+ function node.find_attribute(n,a)
+ if n then
+ local v, n = find_attribute(todirect(n),a)
+ if n then
+ return v, tonode(n)
+ end
+ end
+ return nil
+ end
+
+ function node.first_glyph(first,last)
+ local n = first_glyph(todirect(first), last and todirect(last) or nil)
+ return n and tonode(n) or nil
+ end
+
+ local dimensions = direct.dimensions
+ local rangedimensions = direct.rangedimensions
+ local effective_glue = direct.effective_glue
+
+ function node.dimensions(a,b,c,d,e)
+ if type(a) == "userdata" then
+ a = todirect(a)
+ if type(b) == "userdata" then
+ b = todirect(b)
+ end
+ return dimensions(a,b)
+ else
+ d = todirect(d)
+ if type(e) == "userdata" then
+ e = todirect(e)
+ end
+ return dimensions(a,b,c,d,e)
+ end
+ return 0, 0, 0
+ end
+
+ function node.rangedimensions(parent,first,last)
+ return rangedimenensions(todirect(parent),todirect(first),last and todirect(last))
+ end
+
+ function node.effective_glue(list,parent)
+ return effective_glue(list and todirect(list) or nil,parent and todirect(parent) or nil)
+ end
+
+ local uses_font = direct.uses_font
+ local has_glyph = direct.has_glyph
+ local protrusion_skippable = direct.protrusion_skippable
+ local prepend_prevdepth = direct.prepend_prevdepth
+ local make_extensible = direct.make_extensible
+
+ function node.uses_font(n,f)
+ return uses_font(todirect(n),f)
+ end
+
+ function node.has_glyph(n)
+ return has_glyph(todirect(n))
+ end
+
+ function node.protrusion_skippable(n)
+ return protrusion_skippable(todirect(n))
+ end
+
+ function node.prepend_prevdepth(n)
+ local n, d = prepend_prevdepth(todirect(n))
+ return tonode(n), d
+ end
+
+ function node.make_extensible(...)
+ local n = make_extensible(...)
+ return n and tonode(n) or nil
+ end
+
+ local last_node = direct.last_node
+
+ function node.last_node()
+ local n = last_node()
+ return n and tonode(n) or nil
+ end
+
+ local is_zero_glue = direct.is_zero_glue
+ local getglue = direct.getglue
+ local setglue = direct.setglue
+
+ function node.is_zero_glue(n)
+ return is_zero_glue(todirect(n))
+ end
+
+ function node.get_glue(n)
+ return get_glue(todirect(n))
+ end
+
+ function node.set_glue(n)
+ return set_glue(todirect(n))
+ end
+
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/node-bck.lua b/Master/texmf-dist/tex/context/base/mkiv/node-bck.lua
index a19e5e969a7..53ace65e99e 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/node-bck.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/node-bck.lua
@@ -170,7 +170,7 @@ end
local function add_backgrounds(head,id,list)
if list then
- for current, id, subtype, list in nextlist, list do
+ for current, id, subtype, list in nextlist, list do
if list then
if alignments and subtype == alignmentlist_code then
local l = add_alignbackgrounds(current,list)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/node-cmp.lua b/Master/texmf-dist/tex/context/base/mkiv/node-cmp.lua
new file mode 100644
index 00000000000..e13e93d1f14
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/node-cmp.lua
@@ -0,0 +1,232 @@
+if node.count then
+ return
+end
+
+local type = type
+
+local node = node
+local direct = node.direct
+local todirect = direct.tovaliddirect
+local tonode = direct.tonode
+
+local count = direct.count
+local length = direct.length
+local slide = direct.slide
+
+function node.count(id,first,last)
+ return count(id,first and todirect(first), last and todirect(last) or nil)
+end
+
+function node.length(first,last)
+ return length(first and todirect(first), last and todirect(last) or nil)
+end
+
+function node.slide(n)
+ if n then
+ n = slide(todirect(n))
+ if n then
+ return tonode(n)
+ end
+ end
+ return nil
+end
+
+local hyphenating = direct.hyphenating
+local ligaturing = direct.ligaturing
+local kerning = direct.kerning
+
+-- kind of inconsistent
+
+function node.hyphenating(first,last)
+ if first then
+ local h, t = hyphenating(todirect(first), last and todirect(last) or nil)
+ return h and tonode(h) or nil, t and tonode(t) or nil, true
+ else
+ return nil, false
+ end
+end
+
+function node.ligaturing(first,last)
+ if first then
+ local h, t = ligaturing(todirect(first), last and todirect(last) or nil)
+ return h and tonode(h) or nil, t and tonode(t) or nil, true
+ else
+ return nil, false
+ end
+end
+
+function node.kerning(first,last)
+ if first then
+ local h, t = kerning(todirect(first), last and todirect(last) or nil)
+ return h and tonode(h) or nil, t and tonode(t) or nil, true
+ else
+ return nil, false
+ end
+ end
+
+local protect_glyph = direct.protect_glyph
+local unprotect_glyph = direct.unprotect_glyph
+local protect_glyphs = direct.protect_glyphs
+local unprotect_glyphs = direct.unprotect_glyphs
+
+function node.protect_glyphs(first,last)
+ protect_glyphs(todirect(first), last and todirect(last) or nil)
+end
+
+function node.unprotect_glyphs(first,last)
+ unprotect_glyphs(todirect(first), last and todirect(last) or nil)
+end
+
+function node.protect_glyph(first)
+ protect_glyph(todirect(first))
+end
+
+function node.unprotect_glyph(first)
+ unprotect_glyph(todirect(first))
+end
+
+local flatten_discretionaries = direct.flatten_discretionaries
+local check_discretionaries = direct.check_discretionaries
+local check_discretionary = direct.check_discretionary
+
+function node.flatten_discretionaries(first)
+ local h, count = flatten_discretionaries(todirect(first))
+ return tonode(h), count
+end
+
+function node.check_discretionaries(n)
+ check_discretionaries(todirect(n))
+end
+
+function node.check_discretionary(n)
+ check_discretionary(todirect(n))
+end
+
+local hpack = direct.hpack
+local vpack = direct.vpack
+local list_to_hlist = direct.mlist_to_hlist
+
+function node.hpack(head,...)
+ local h, badness = hpack(head and todirect(head) or nil,...)
+ return tonode(h), badness
+end
+
+function node.vpack(head,...)
+ local h, badness = vpack(head and todirect(head) or nil,...)
+ return tonode(h), badness
+end
+
+function node.mlist_to_hlist(head,...)
+ return tonode(mlist_to_hlist(head and todirect(head) or nil,...))
+end
+
+local end_of_math = direct.end_of_math
+local find_attribute = direct.find_attribute
+local first_glyph = direct.first_glyph
+
+function node.end_of_math(n)
+ if n then
+ n = end_of_math(todirect(n))
+ if n then
+ return tonode(n)
+ end
+ end
+ return nil
+end
+
+function node.find_attribute(n,a)
+ if n then
+ local v, n = find_attribute(todirect(n),a)
+ if n then
+ return v, tonode(n)
+ end
+ end
+ return nil
+end
+
+function node.first_glyph(first,last)
+ local n = first_glyph(todirect(first), last and todirect(last) or nil)
+ return n and tonode(n) or nil
+end
+
+local dimensions = direct.dimensions
+local rangedimensions = direct.rangedimensions
+local effective_glue = direct.effective_glue
+
+function node.dimensions(a,b,c,d,e)
+ if type(a) == "userdata" then
+ a = todirect(a)
+ if type(b) == "userdata" then
+ b = todirect(b)
+ end
+ return dimensions(a,b)
+ else
+ d = todirect(d)
+ if type(e) == "userdata" then
+ e = todirect(e)
+ end
+ return dimensions(a,b,c,d,e)
+ end
+ return 0, 0, 0
+end
+
+function node.rangedimensions(parent,first,last)
+ return rangedimenensions(todirect(parent),todirect(first),last and todirect(last))
+end
+
+function node.effective_glue(list,parent)
+ return effective_glue(list and todirect(list) or nil,parent and todirect(parent) or nil)
+end
+
+local uses_font = direct.uses_font
+local has_glyph = direct.has_glyph
+local protrusion_skippable = direct.protrusion_skippable
+local prepend_prevdepth = direct.prepend_prevdepth
+local make_extensible = direct.make_extensible
+
+function node.uses_font(n,f)
+ return uses_font(todirect(n),f)
+end
+
+function node.has_glyph(n)
+ return has_glyph(todirect(n))
+end
+
+function node.protrusion_skippable(n)
+ return protrusion_skippable(todirect(n))
+end
+
+function node.prepend_prevdepth(n)
+ local n, d = prepend_prevdepth(todirect(n))
+ return tonode(n), d
+end
+
+function node.make_extensible(...)
+ local n = make_extensible(...)
+ return n and tonode(n) or nil
+end
+
+local last_node = direct.last_node
+
+function node.last_node()
+ local n = last_node()
+ return n and tonode(n) or nil
+end
+
+local is_zero_glue = direct.is_zero_glue
+local getglue = direct.getglue
+local setglue = direct.setglue
+
+function node.is_zero_glue(n)
+ return is_zero_glue(todirect(n))
+end
+
+function node.get_glue(n)
+ return get_glue(todirect(n))
+end
+
+function node.set_glue(n)
+ return set_glue(todirect(n))
+end
+
+node.family_font = tex.getfontoffamily
diff --git a/Master/texmf-dist/tex/context/base/mkiv/node-dir.lua b/Master/texmf-dist/tex/context/base/mkiv/node-dir.lua
index 3f0cba67e91..762f20739da 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/node-dir.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/node-dir.lua
@@ -1,66 +1,114 @@
if not modules then modules = { } end modules ['node-dir'] = {
version = 1.001,
comment = "companion to node-ini.mkiv",
- author = "Taco Hoekwater and Hans Hagen",
+ author = "Hans Hagen",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
}
--- This is experimental code, so when I change it I need to check other modules
--- too.
---
--- Local par nodes are somewhat special. They start a paragraph and then register
--- the par direction. But they can also show op mid paragraph in which case they
--- register boxes and penalties. In that case the direction should not be affected.
---
--- We can assume that when hpack and prelinebreak filters are called, a local par
--- still sits at the head, but after a linebreak pass this node can be after the
--- leftskip (when present).
+local nodes = nodes
+local nuts = nodes.nuts
-local nodes = nodes
-local nuts = nodes.nuts
+local normaldir_code = nodes.dircodes.normal
+local line_code = nodes.listcodes.line
+local lefttoright_code = nodes.dirvalues.lefttoright
-local nodecodes = nodes.nodecodes
-local localpar_code = nodecodes.localpar
+local getnext = nuts.getnext
+local getlist = nuts.getlist
+local getwhd = nuts.getwhd
+local getdirection = nuts.getdirection
-local getid = nuts.getid
-local getsubtype = nuts.getsubtype
-local getdirection = nuts.getdirection
+local setlist = nuts.setlist
-local dirvalues = nodes.dirvalues
-local lefttoright = dirvalues.lefttoright
-local righttoleft = dirvalues.righttoleft
+local nextdir = nuts.traversers.dir
+local nexthlist = nuts.traversers.hlist
-local localparnewgraf_code = 0
+local rangedimensions = nuts.rangedimensions
+local insert_before = nuts.insert_before
-local function newstack(head,direction)
- local stack = { }
- local top = 0
- if head and getid(head) == localpar_code and getsubtype(head) == localparnewgraf_code then
- direction = getdirection(head)
- end
- if not direction then
- direction = lefttoright
- elseif direction == "TLT" then
- direction = lefttoright
- elseif direction == "TRT" then
- direction = righttoleft
- end
- local function update(node)
- local dir, pop = getdirection(node)
- if not pop then
- top = top + 1
- stack[top] = dir
- return dir
- elseif top == 0 then
- return direction
- elseif top == 1 then
- top = 0
- return direction
+local new_rule = nuts.pool.rule
+local new_kern = nuts.pool.kern
+
+local setcolor = nodes.tracers.colors.set
+local settransparency = nodes.tracers.transparencies.set
+
+-- local function dirdimensions(parent,begindir) -- can be a helper
+-- local level = 1
+-- local enddir = begindir
+-- local width = 0
+-- for current, subtype in nextdir, getnext(begindir) do
+-- if subtype == normaldir_code then -- todo
+-- level = level + 1
+-- else
+-- level = level - 1
+-- end
+-- if level == 0 then -- does the type matter
+-- enddir = current
+-- width = rangedimensions(parent,begindir,enddir)
+-- return width, enddir
+-- end
+-- end
+-- if enddir == begindir then
+-- width = rangedimensions(parent,begindir)
+-- end
+-- return width, enddir
+-- end
+
+local function dirdimensions(parent,begindir) -- can be a helper
+ local level = 1
+ local lastdir = nil
+ local width = 0
+ for current, subtype in nextdir, getnext(begindir) do
+ if subtype == normaldir_code then -- todo
+ level = level + 1
else
- top = top - 1
- return stack[top]
+ level = level - 1
+ end
+ if level == 0 then -- does the type matter
+ return (rangedimensions(parent,begindir,current)), current
+ end
+ end
+ return (rangedimensions(parent,begindir)), begindir
+end
+
+nuts.dirdimensions = dirdimensions
+
+local function colorit(list,current,dir,w,h,d)
+ local rule = new_rule(w,h,d)
+ local kern = new_kern(-w)
+ local color = dir == lefttoright_code and "trace:s" or "trace:o"
+ setcolor(rule,color)
+ settransparency(rule,color)
+ list, current = insert_before(list,current,kern)
+ list, current = insert_before(list,current,rule)
+ return list, current
+end
+
+function nodes.tracers.directions(head)
+ for hlist, subtype in nexthlist, head do
+ if subtype == line_code then
+ local list = getlist(hlist)
+ local w, h, d = getwhd(hlist)
+ list = colorit(list,list,getdirection(hlist),w,h,d)
+ for current in nextdir, list do
+ local dir, cancel = getdirection(current)
+ if not cancel then
+ local width = dirdimensions(hlist,current)
+ list = colorit(list,current,dir,width,h,d)
+ end
+ end
+ setlist(hlist,list)
end
end
- return direction, update
+ return head
end
+
+local enabled = false
+
+trackers.register("nodes.directions", function(v)
+ if not enabled then
+ enabled = true
+ nodes.tasks.appendaction("finalizers","after","nodes.tracers.directions",nil,"nut","enabled")
+ end
+ nodes.tasks.setaction(v)
+end)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/node-fin.lua b/Master/texmf-dist/tex/context/base/mkiv/node-fin.lua
index dc681d16556..a848cef69da 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/node-fin.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/node-fin.lua
@@ -12,10 +12,12 @@ if not modules then modules = { } end modules ['node-fin'] = {
-- leaders are also triggers ... see colo-ext for an example (negate a box)
local next, type, format = next, type, string.format
+local setmetatableindex = table.setmetatableindex
local attributes, nodes, node = attributes, nodes, node
local nuts = nodes.nuts
+local tonut = nodes.tonut
local getnext = nuts.getnext
local getid = nuts.getid
@@ -25,6 +27,8 @@ local getattr = nuts.getattr
local getwidth = nuts.getwidth
local getwhd = nuts.getwhd
local getorientation = nuts.getorientation
+local has_dimensions = nuts.has_dimensions
+local getbox = nuts.getbox
local setlist = nuts.setlist
local setleader = nuts.setleader
@@ -38,16 +42,9 @@ local nextnode = nuts.traversers.node
local nodecodes = nodes.nodecodes
local rulecodes = nodes.rulecodes
------ normalrule_code = rulecodes.normal
local boxrule_code = rulecodes.box
local imagerule_code = rulecodes.image
local emptyrule_code = rulecodes.empty
------ userrule_code = rulecodes.user
------ overrule_code = rulecodes.over
------ underrule_code = rulecodes.under
------ fractionrule_code = rulecodes.fraction
------ radicalrule_code = rulecodes.radical
------ outlinerule_code = rulecodes.outline
local glyph_code = nodecodes.glyph
local disc_code = nodecodes.disc
@@ -56,6 +53,9 @@ local rule_code = nodecodes.rule
local hlist_code = nodecodes.hlist
local vlist_code = nodecodes.vlist
+local texlists = tex.lists
+local texgetnest = tex.getnest
+
local states = attributes.states
local numbers = attributes.numbers
local a_trigger = attributes.private('trigger')
@@ -182,7 +182,7 @@ local function process(attribute,head,inheritance,default) -- one attribute
local leader = nil
for stack, id in nextnode, head do
if id == glyph_code or id == disc_code then
- check = true -- disc no longer needed as we flatten replace
+ check = true
elseif id == glue_code then
leader = getleader(stack)
if leader then
@@ -235,8 +235,7 @@ local function process(attribute,head,inheritance,default) -- one attribute
-- end nested --
end
elseif id == rule_code then
- local wd, ht, dp = getwhd(stack)
- check = wd ~= 0 or (ht+dp) ~= 0
+ check = has_dimensions(stack)
end
-- much faster this way than using a check() and nested() function
if check then
@@ -309,7 +308,7 @@ local function selective(attribute,head,inheritance,default) -- two attributes
local leader = nil
for stack, id, subtype in nextnode, head do
if id == glyph_code or id == disc_code then
- check = true -- disc no longer needed as we flatten replace
+ check = true
elseif id == glue_code then
leader = getleader(stack)
if leader then
@@ -374,8 +373,7 @@ local function selective(attribute,head,inheritance,default) -- two attributes
-- so no redundant color stuff (only here, layers for instance should obey)
check = false
else
- local wd, ht, dp = getwhd(stack)
- check = wd ~= 0 or (ht+dp) ~= 0
+ check = has_dimensions(stack)
end
end
if check then
@@ -485,8 +483,7 @@ local function stacked(attribute,head,default) -- no triggering, no inheritance,
end
end
elseif id == rule_code then
- local wd, ht, dp = getwhd(stack)
- check = wd ~= 0 or (ht+dp) ~= 0
+ check = has_dimensions(stack)
end
if check then
local a = getattr(stack,attribute)
@@ -559,20 +556,25 @@ local function stacker(attribute,head,default) -- no triggering, no inheritance,
if a and attrib ~= a and nslistwise[a] then -- viewerlayer
head = insert_node_before(head,current,copy_node(nsdata[a]))
list = stacker(attribute,content,a)
+ if list ~= content then
+ setlist(current,list)
+ end
head, current = insert_node_after(head,current,copy_node(nsnone))
else
list = stacker(attribute,content,attrib)
+ if list ~= content then
+ setlist(current,list)
+ end
end
else
list = stacker(attribute,content,default)
- end
- if list ~= content then
- setlist(current,list)
+ if list ~= content then
+ setlist(current,list)
+ end
end
end
elseif id == rule_code then
- local wd, ht, dp = getwhd(current)
- check = wd ~= 0 or (ht+dp) ~= 0
+ check = has_dimensions(current)
end
if check then
@@ -621,89 +623,6 @@ local function stacker(attribute,head,default) -- no triggering, no inheritance,
return head
end
--- local nextid = nodes.nuts.traversers.id
---
--- local function stacker(attribute,head,default) -- no triggering, no inheritance, but list-wise
---
--- -- nsbegin()
--- local stacked = false
---
--- local current = head
--- local previous = head
--- local attrib = default or unsetvalue
--- local check = false
--- local leader = false
---
--- local id = getid(current)
--- while current do
--- if id == glyph_code then
--- check = true
--- elseif id == glue_code then
--- leader = getleader(current)
--- if leader then
--- check = true
--- end
--- elseif id == hlist_code or id == vlist_code then
--- local content = getlist(current)
--- if content then
--- local list
--- if nslistwise then
--- local a = getattr(current,attribute)
--- if a and attrib ~= a and nslistwise[a] then -- viewerlayer
--- head = insert_node_before(head,current,copy_node(nsdata[a]))
--- list = stacker(attribute,content,a)
--- head, current = insert_node_after(head,current,copy_node(nsnone))
--- else
--- list = stacker(attribute,content,attrib)
--- end
--- else
--- list = stacker(attribute,content,default)
--- end
--- if list ~= content then
--- setlist(current,list)
--- end
--- end
--- elseif id == rule_code then
--- check = getwidth(current) ~= 0
--- end
---
--- if check then
--- local a = getattr(current,attribute) or unsetvalue
--- if a ~= attrib then
--- if not stacked then
--- stacked = true
--- nsbegin()
--- end
--- local n = nsstep(a)
--- if n then
--- head = insert_node_before(head,current,n) -- a
--- end
--- attrib = a
--- if leader then
--- -- tricky as a leader has to be a list so we cannot inject before
--- local list = stacker(attribute,leader,attrib)
--- leader = false
--- end
--- end
--- check = false
--- end
---
--- previous = current
---
--- current, id = nextid(current,current)
--- end
---
--- if stacked then
--- local n = nsend()
--- while n do
--- head = insert_node_after(head,previous,n)
--- n = nsend()
--- end
--- end
---
--- return head
--- end
-
states.stacker = function(namespace,attribute,head,default)
local head = stacker(attribute,head,default)
nsreset()
@@ -715,3 +634,100 @@ end
statistics.register("attribute processing time", function()
return statistics.elapsedseconds(attributes,"front- and backend")
end)
+
+-- -- --
+
+do
+
+ local cleaners = { }
+ local trace = true -- false
+
+ function attributes.cleanup()
+ if next(cleaners) then
+ local values = setmetatableindex("table")
+
+ if trace then
+ starttiming(values)
+ end
+
+ local function check(l)
+ for n, id in nextnode, l do
+ if id == hlist_code or id == vlist_code or id == glue_code then
+ local l = getlist(n)
+ if l then
+ check(l)
+ end
+ end
+ for a in next, cleaners do
+ local v = getattr(n,a)
+ if v then
+ -- values[a] = values[a] + 1
+ values[a][v] = true
+ end
+ end
+ end
+ end
+
+ local top = texgetnest("ptr")
+ for i=1,top do
+ local l = texgetnest(i)
+ if l then
+ check(tonut(l.head))
+ end
+ end
+
+ do local l
+ l = tonut(texlists.page_ins_head) if l then check(l) end
+ l = tonut(texlists.contrib_head) if l then check(l) end
+ l = tonut(texlists.page_discards_head) if l then check(l) end
+ l = tonut(texlists.split_discards_head) if l then check(l) end
+ l = tonut(texlists.page_head) if l then check(l) end
+ end
+
+ -- todo: traverseboxes
+
+ for i=0,65535 do
+ local b = getbox(i)
+ if b then
+ local l = getlist(b)
+ if l then
+ check(l)
+ end
+ end
+ end
+
+ for a, t in next, values do
+ cleaners[a](a,t)
+ end
+
+ if trace then
+ stoptiming(values)
+ local a = table.sortedkeys(values)
+ local t = statistics.elapsedtime(values)
+ local r = tex.getcount("realpageno")
+ if #a == 0 then
+ logs.report("attributes","cleaning up at page %i took %s seconds, no attributes",r,t)
+ else
+ logs.report("attributes","cleaning up at page %i took %s seconds, attributes: % t",r,t,a)
+ end
+ end
+ end
+ end
+
+ -- not yet used but when we do ... delay a call till we enable it (attr-ini.mkiv)
+
+ -- local function show(a,t) for k, v in next, t do print(a,k) end end
+ --
+ -- attributes.registercleaner( 1, show)
+ -- attributes.registercleaner( 2, show)
+
+ function attributes.registercleaner(a,f)
+ cleaners[a] = f
+ end
+
+ implement {
+ name = "cleanupattributes",
+ actions = attributes.cleanup,
+ }
+
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/node-fnt.lua b/Master/texmf-dist/tex/context/base/mkiv/node-fnt.lua
index 01d7e42e5d6..1b245639b78 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/node-fnt.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/node-fnt.lua
@@ -43,7 +43,6 @@ local handlers = nodes.handlers
local nuts = nodes.nuts
-local getattr = nuts.getattr
local getid = nuts.getid
local getsubtype = nuts.getsubtype
local getdisc = nuts.getdisc
@@ -51,7 +50,9 @@ local getnext = nuts.getnext
local getprev = nuts.getprev
local getboth = nuts.getboth
local getdata = nuts.getdata
+local getglyphdata = nuts.getglyphdata
----- getdisc = nuts.getdisc
+
local setchar = nuts.setchar
local setlink = nuts.setlink
local setnext = nuts.setnext
@@ -179,7 +180,7 @@ local function start_trace(head)
local char, id = isglyph(n)
if char then
local font = id
- local attr = getattr(n,0) or 0
+ local attr = getglyphdata(n) or 0
report_fonts("font %03i, dynamic %03i, glyph %C",font,attr,char)
elseif id == disc_code then
report_fonts("[disc] %s",nodes.listtoutf(n,true,false,n))
@@ -209,12 +210,12 @@ do
local usedfonts
local attrfonts
- local basefonts
+ local basefonts -- could be reused
local basefont
local prevfont
local prevattr
local variants
- local redundant
+ local redundant -- could be reused
local firstnone
local lastfont
local lastproc
@@ -316,8 +317,8 @@ do
-- metafun manual (with some 2500 single char lists) the difference is just noise.
for n, char, font in nextchar, head do
- -- local attr = (none and prevattr) or getattr(n,0) or 0 -- zero attribute is reserved for fonts in context
- local attr = getattr(n) or 0 -- zero attribute is reserved for fonts in context
+ -- local attr = (none and prevattr) or getglyphdata(n) or 0 -- zero attribute is reserved for fonts in context
+ local attr = getglyphdata(n) or 0 -- zero attribute is reserved for fonts in context
if font ~= prevfont or attr ~= prevattr then
prevfont = font
prevattr = attr
@@ -440,7 +441,7 @@ do
firstnone = nil
basefont = nil
for n, char, font in nextchar, r do
- local attr = getattr(n) or 0 -- zero attribute is reserved for fonts in context
+ local attr = getglyphdata(n) or 0 -- zero attribute is reserved for fonts in context
if font ~= prevfont or attr ~= prevattr then
prevfont = font
prevattr = attr
diff --git a/Master/texmf-dist/tex/context/base/mkiv/node-ini.lua b/Master/texmf-dist/tex/context/base/mkiv/node-ini.lua
index f910c7e012f..806ac5658d7 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/node-ini.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/node-ini.lua
@@ -7,15 +7,13 @@ if not modules then modules = { } end modules ['node-ini'] = {
}
--[[ldx--
-<p>Most of the code that had accumulated here is now separated in
-modules.</p>
+<p>Most of the code that had accumulated here is now separated in modules.</p>
--ldx]]--
--- this module is being reconstructed
---
--- todo: datatype table per node type
-
--- todo: query names with new node.subtypes
+-- I need to clean up this module as it's a bit of a mess now. The latest luatex
+-- has most tables but we have a few more in luametatex. Also, some are different
+-- between these engines. We started out with hardcoded tables, that then ended
+-- up as comments and are now gone (as they differ per engine anyway).
local next, type, tostring = next, type, tostring
local gsub = string.gsub
@@ -23,36 +21,34 @@ local concat, remove = table.concat, table.remove
local sortedhash, sortedkeys, swapped = table.sortedhash, table.sortedkeys, table.swapped
--[[ldx--
-<p>Access to nodes is what gives <l n='luatex'/> its power. Here we
-implement a few helper functions. These functions are rather optimized.</p>
+<p>Access to nodes is what gives <l n='luatex'/> its power. Here we implement a
+few helper functions. These functions are rather optimized.</p>
--ldx]]--
--[[ldx--
-<p>When manipulating node lists in <l n='context'/>, we will remove
-nodes and insert new ones. While node access was implemented, we did
-quite some experiments in order to find out if manipulating nodes
-in <l n='lua'/> was feasible from the perspective of performance.</p>
-
-<p>First of all, we noticed that the bottleneck is more with excessive
-callbacks (some gets called very often) and the conversion from and to
-<l n='tex'/>'s datastructures. However, at the <l n='lua'/> end, we
-found that inserting and deleting nodes in a table could become a
-bottleneck.</p>
-
-<p>This resulted in two special situations in passing nodes back to
-<l n='tex'/>: a table entry with value <type>false</type> is ignored,
-and when instead of a table <type>true</type> is returned, the
-original table is used.</p>
-
-<p>Insertion is handled (at least in <l n='context'/> as follows. When
-we need to insert a node at a certain position, we change the node at
-that position by a dummy node, tagged <type>inline</type> which itself
-has_attribute the original node and one or more new nodes. Before we pass
-back the list we collapse the list. Of course collapsing could be built
-into the <l n='tex'/> engine, but this is a not so natural extension.</p>
-
-<p>When we collapse (something that we only do when really needed), we
-also ignore the empty nodes. [This is obsolete!]</p>
+<p>When manipulating node lists in <l n='context'/>, we will remove nodes and
+insert new ones. While node access was implemented, we did quite some experiments
+in order to find out if manipulating nodes in <l n='lua'/> was feasible from the
+perspective of performance.</p>
+
+<p>First of all, we noticed that the bottleneck is more with excessive callbacks
+(some gets called very often) and the conversion from and to <l n='tex'/>'s
+datastructures. However, at the <l n='lua'/> end, we found that inserting and
+deleting nodes in a table could become a bottleneck.</p>
+
+<p>This resulted in two special situations in passing nodes back to <l n='tex'/>:
+a table entry with value <type>false</type> is ignored, and when instead of a
+table <type>true</type> is returned, the original table is used.</p>
+
+<p>Insertion is handled (at least in <l n='context'/> as follows. When we need to
+insert a node at a certain position, we change the node at that position by a
+dummy node, tagged <type>inline</type> which itself has_attribute the original
+node and one or more new nodes. Before we pass back the list we collapse the
+list. Of course collapsing could be built into the <l n='tex'/> engine, but this
+is a not so natural extension.</p>
+
+<p>When we collapse (something that we only do when really needed), we also
+ignore the empty nodes. [This is obsolete!]</p>
--ldx]]--
-- local gf = node.direct.getfield
@@ -76,206 +72,25 @@ tex.magicconstants = { -- we use tex.constants for something else
trueinch = 4736286,
}
--- local listcodes = allocate {
--- [0] = "unknown",
--- [1] = "line",
--- [2] = "box",
--- [3] = "indent",
--- [4] = "alignment", -- row or column
--- [5] = "cell",
--- [6] = "equation",
--- [7] = "equationnumber",
--- }
-
-local listcodes = mark(getsubtypes("list"))
-
--- local rulecodes = allocate {
--- [0] = "normal",
--- [1] = "box",
--- [2] = "image",
--- [3] = "empty",
--- [4] = "user",
--- }
-
-local rulecodes = mark(getsubtypes("rule"))
-
-if not rulecodes[5] then
- rulecodes[5] = "over"
- rulecodes[6] = "under"
- rulecodes[7] = "fraction"
- rulecodes[8] = "radical"
-end
-
--- local dircodes = mark(getsubtypes("dir"))
-
-dircodes = allocate {
- [0] = "normal",
- [1] = "cancel",
-}
-
--- local glyphcodes = allocate {
--- [ 1] = "character",
--- [ 2] = "ligature",
--- [ 4] = "ghost",
--- [ 8] = "left",
--- [16] = "right",
--- }
-
-local glyphcodes = mark(getsubtypes("glyph"))
-
--- local disccodes = allocate {
--- [0] = "discretionary", -- \discretionary
--- [1] = "explicit", -- \-
--- [2] = "automatic", -- following a -
--- [3] = "regular", -- by hyphenator: simple
--- [4] = "first", -- by hyphenator: hard first item
--- [5] = "second", -- by hyphenator: hard second item
--- }
-
-local disccodes = mark(getsubtypes("disc"))
-
--- local gluecodes = allocate {
--- [ 0] = "userskip",
--- [ 1] = "lineskip",
--- [ 2] = "baselineskip",
--- [ 3] = "parskip",
--- [ 4] = "abovedisplayskip",
--- [ 5] = "belowdisplayskip",
--- [ 6] = "abovedisplayshortskip",
--- [ 7] = "belowdisplayshortskip",
--- [ 8] = "leftskip",
--- [ 9] = "rightskip",
--- [ 10] = "topskip",
--- [ 11] = "splittopskip",
--- [ 12] = "tabskip",
--- [ 13] = "spaceskip",
--- [ 14] = "xspaceskip",
--- [ 15] = "parfillskip",
--- [ 16] = "mathskip", -- experiment
--- [ 17] = "thinmuskip",
--- [ 18] = "medmuskip",
--- [ 19] = "thickmuskip",
--- [ 98] = "conditionalmathglue",
--- [ 99] = "muskip",
--- [100] = "leaders",
--- [101] = "cleaders",
--- [102] = "xleaders",
--- [103] = "gleaders",
--- }
-
-local gluecodes = mark(getsubtypes("glue"))
-
--- local leadercodes = allocate {
--- [100] = "leaders",
--- [101] = "cleaders",
--- [102] = "xleaders",
--- [103] = "gleaders",
--- }
-
-local leadercodes = mark(getsubtypes("leader"))
-
--- local fillcodes = allocate {
--- [0] = "stretch",
--- [1] = "fi",
--- [2] = "fil",
--- [3] = "fill",
--- [4] = "filll",
--- }
-
-local fillcodes = mark(getsubtypes("fill"))
-
--- for now:
-
-local boundarycodes = allocate {
- [0] = "cancel",
- [1] = "user",
- [2] = "protrusion",
- [3] = "word",
-}
-
--- local boundarycodes = mark(getsubtypes("boundary"))
-
--- local penaltycodes = allocate { -- unfortunately not used (yet)
--- [ 0] = "userpenalty",
--- }
-
-local penaltycodes = mark(getsubtypes("penalty"))
-
-table.setmetatableindex(penaltycodes,function(t,k) return "userpenalty" end) -- not used anyway
-
--- local kerncodes = allocate {
--- [0] = "fontkern",
--- [1] = "userkern",
--- [2] = "accentkern",
--- [3] = "italiccorrection",
--- }
-
-local kerncodes = mark(getsubtypes("kern"))
-
--- local margincodes = allocate {
--- [0] = "left",
--- [1] = "right",
--- }
-
-local margincodes = mark(getsubtypes("marginkern"))
-
--- local mathcodes = allocate {
--- [0] = "beginmath",
--- [1] = "endmath",
--- }
-
-local mathcodes = mark(getsubtypes("math"))
-
--- local noadcodes = allocate { -- simple nodes
--- [ 0] = "ord",
--- [ 1] = "opdisplaylimits",
--- [ 2] = "oplimits",
--- [ 3] = "opnolimits",
--- [ 4] = "bin",
--- [ 5] = "rel",
--- [ 6] = "open",
--- [ 7] = "close",
--- [ 8] = "punct",
--- [ 9] = "inner",
--- [10] = "under",
--- [11] = "over",
--- [12] = "vcenter",
--- }
-
-local noadcodes = mark(getsubtypes("noad"))
-
--- local radicalcodes = allocate {
--- [0] = "radical",
--- [1] = "uradical",
--- [2] = "uroot",
--- [3] = "uunderdelimiter",
--- [4] = "uoverdelimiter",
--- [5] = "udelimiterunder",
--- [6] = "udelimiterover",
--- }
-
-local radicalcodes = mark(getsubtypes("radical"))
-
--- local accentcodes = allocate {
--- [0] = "bothflexible",
--- [1] = "fixedtop",
--- [2] = "fixedbottom",
--- [3] = "fixedboth",
--- }
-
-local accentcodes = mark(getsubtypes("accent"))
-
--- local fencecodes = allocate {
--- [0] = "unset",
--- [1] = "left",
--- [2] = "middle",
--- [3] = "right",
--- [4] = "no",
--- }
-
-local fencecodes = mark(getsubtypes("fence"))
-
--- maybe we also need fractioncodes
+local listcodes = mark(getsubtypes("list"))
+local rulecodes = mark(getsubtypes("rule"))
+local dircodes = mark(getsubtypes("dir"))
+local glyphcodes = mark(getsubtypes("glyph"))
+local disccodes = mark(getsubtypes("disc"))
+local gluecodes = mark(getsubtypes("glue"))
+local leadercodes = mark(getsubtypes("leader"))
+local fillcodes = mark(getsubtypes("fill"))
+local boundarycodes = mark(getsubtypes("boundary"))
+local penaltycodes = mark(getsubtypes("penalty"))
+local kerncodes = mark(getsubtypes("kern"))
+local margincodes = mark(getsubtypes("marginkern"))
+local mathcodes = mark(getsubtypes("math"))
+local noadcodes = mark(getsubtypes("noad"))
+local radicalcodes = mark(getsubtypes("radical"))
+local accentcodes = mark(getsubtypes("accent"))
+local fencecodes = mark(getsubtypes("fence"))
+----- fractioncodes = mark(getsubtypes("fraction"))
+local localparcodes = allocate { [0] = "new_graf", "local_box", "hmode_par", "penalty", "math" } -- only in luametatex now
local function simplified(t)
local r = { }
@@ -356,6 +171,7 @@ margincodes = allocate(swapped(margincodes,margincodes))
disccodes = allocate(swapped(disccodes,disccodes))
accentcodes = allocate(swapped(accentcodes,accentcodes))
fencecodes = allocate(swapped(fencecodes,fencecodes))
+localparcodes = allocate(swapped(localparcodes,localparcodes))
rulecodes = allocate(swapped(rulecodes,rulecodes))
leadercodes = allocate(swapped(leadercodes,leadercodes))
usercodes = allocate(swapped(usercodes,usercodes))
@@ -364,7 +180,15 @@ dirvalues = allocate(swapped(dirvalues,dirvalues))
gluevalues = allocate(swapped(gluevalues,gluevalues))
literalvalues = allocate(swapped(literalvalues,literalvalues))
-if CONTEXTLMTXMODE > 1 then
+if not gluecodes.indentskip then
+ gluecodes.indentskip = gluecodes.userskip
+ gluecodes.lefthangskip = gluecodes.userskip
+ gluecodes.righthangskip = gluecodes.userskip
+ gluecodes.correctionskip = gluecodes.userskip
+ gluecodes.intermathskip = gluecodes.userskip
+end
+
+if CONTEXTLMTXMODE > 0 then
whatcodes.literal = 0x1 whatcodes[0x1] = "literal"
whatcodes.latelua = 0x2 whatcodes[0x2] = "latelua"
whatcodes.userdefined = 0x3 whatcodes[0x3] = "userdefined"
@@ -399,6 +223,7 @@ nodes.disccodes = disccodes
nodes.accentcodes = accentcodes
nodes.radicalcodes = radicalcodes
nodes.fencecodes = fencecodes
+nodes.localparcodes = localparcodes
nodes.rulecodes = rulecodes
nodes.leadercodes = leadercodes
nodes.usercodes = usercodes
@@ -420,12 +245,14 @@ nodes.subtypes = allocate {
[nodecodes.glyph] = glyphcodes,
[nodecodes.hlist] = listcodes,
[nodecodes.kern] = kerncodes,
+ [nodecodes.localpar] = localparcodes,
[nodecodes.marginkern] = margincodes,
[nodecodes.math] = mathcodes,
[nodecodes.noad] = noadcodes,
[nodecodes.penalty] = penaltycodes,
[nodecodes.radical] = radicalcodes,
[nodecodes.rule] = rulecodes,
+ -- [nodecodes.user] = usercodes,
[nodecodes.vlist] = listcodes,
[nodecodes.whatsit] = whatcodes,
}
@@ -447,6 +274,8 @@ nodes.literalvalues = literalvalues -- more friendly
glyphcodes.glyph = glyphcodes.character
+localparcodes.vmode_par = localparcodes.new_graf
+
listcodes.row = listcodes.alignment
listcodes.column = listcodes.alignment
@@ -512,14 +341,24 @@ end
trackers.register("system.showcodes", nodes.showcodes)
-if not nodecodes.dir then
- report_codes("use a newer version of luatex")
- os.exit()
-end
-
-- We don't need this sanitize-after-callback in ConTeXt and by disabling it we
-- also have a way to check if LuaTeX itself does the right thing.
if node.fix_node_lists then
node.fix_node_lists(false)
end
+
+-- We use the real node code numbers.
+
+if CONTEXTLMTXMODE > 0 then
+
+ local texchardef = tex.chardef
+
+ if texchardef then
+ for i=0,nodecodes.glyph do
+ texchardef(nodecodes[i] .. "nodecode",i)
+ end
+ tex.set("internalcodesmode",1)
+ end
+
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/node-ini.mkiv b/Master/texmf-dist/tex/context/base/mkiv/node-ini.mkiv
index 35013c4b801..5bf53cd2d01 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/node-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/node-ini.mkiv
@@ -17,18 +17,22 @@
\newcount\filterstate \filterstate\plusone % hm, public
+\ifcase\contextlmtxmode \else
+ \registerctxluafile{node-cmp}{}
+\fi
+
\registerctxluafile{node-ini}{}
\registerctxluafile{node-met}{}
\registerctxluafile{node-nut}{}
\registerctxluafile{node-res}{}
%registerctxluafile{node-ppt}{} % experimental, not used so probably useless
-\registerctxluafile{node-dir}{}
\registerctxluafile{node-aux}{}
\registerctxluafile{node-tst}{}
\registerctxluafile{node-tra}{} % we might split it off (module)
\registerctxluafile{node-snp}{}
\registerctxluafile{node-tsk}{}
\registerctxluafile{node-tex}{}
+\registerctxluafile{node-dir}{} % experimental, not yet (and maybe never) used
\registerctxluafile{node-pro}{}
\registerctxluafile{node-ser}{}
\registerctxluafile{node-ext}{}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/node-ltp.lua b/Master/texmf-dist/tex/context/base/mkiv/node-ltp.lua
index 0d501890b92..dd655f93d41 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/node-ltp.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/node-ltp.lua
@@ -8,23 +8,16 @@ if not modules then modules = { } end modules ['node-par'] = {
}
-- todo: remove nest_stack from linebreak.w
--- todo: use ex field as signal (index in ?)
--- todo: attr driven unknown/on/off
-- todo: permit global steps i.e. using an attribute that sets min/max/step and overloads the font parameters
-- todo: split the three passes into three functions
--- todo: simplify the direction stack, no copy needed
-- todo: see if we can do without delta nodes (needs thinking)
-- todo: add more mkiv like tracing
-- todo: add a couple of plugin hooks
--- todo: maybe split expansion code paths
-- todo: fix line numbers (cur_list.pg_field needed)
--- todo: check and improve protrusion
--- todo: arabic etc (we could use pretty large scales there) .. marks and cursive
--- todo: see: we need to check this with the latest patches to the tex kernel
--- todo: adapt math glue spacing to new model (left/right)
-
-- todo: optimize a bit more (less par.*)
+-- issue: ls / rs added when zero content and normalize
+
--[[
This code is derived from traditional TeX and has bits of pdfTeX, Aleph (Omega), and of course LuaTeX. So,
@@ -126,66 +119,23 @@ if not modules then modules = { } end modules ['node-par'] = {
retrofit the same approach into the core, the overhead of expansion can be sort of nilled.
In 2013 the expansion factor method became also used at the TeX end so then I could complete the code
- here, and indeed, expansions works quite well now (not compatible of course because we use floats at the
- Lua end. The Lua base variant is still slower but quite ok, especially if we go nuts.
-
- A next iteration will provide plug-ins and more control. I will also explore the possibility to avoid the
- redundant hpack calculations (easier now, although I've only done some quick and dirty experiments.)
-
-]]--
-
---[[--
-
-#define dir_TLT 0
-#define dir_TRT 1
-#define dir_LTL 2
-#define dir_RTT 3
-
-#define dir_TLT_or_TRT(A) (A < 2)
-#define dir_LTL_or_RTT(A) (A > 1)
-
-#define textdir_parallel(A,B) (\
-(dir_TLT_or_TRT(A) and dir_TLT_or_TRT(B)) or \
-(dir_LTL_or_RTT(A) and dir_LTL_or_RTT(B))\
-)
-
-#define pardir_parallel(A,B) (\
-(dir_TLT_or_TRT(A) and dir_TLT_or_TRT(B)) or \
-(dir_LTL_or_RTT(A) and dir_LTL_or_RTT(B))\
-)
+ here, and indeed, expansions works quite well now (not compatible of course because we use floats at
+ the Lua end. The Lua base variant is still slower but quite ok, especially if we go nuts.
-#define pardir_opposite(A,B) (\
-(A == dir_LTL and B == dir_RTT) or \
-(A == dir_RTT and B == dir_LTL)\
-)
+ A next iteration will provide plug-ins and more control. I will also explore the possibility to avoid
+ the redundant hpack calculations (easier now, although I've only done some quick and dirty experiments.)
-#define textdir_opposite(A,B) (\
-(A == dir_TLT and B == dir_TRT) or \
-(A == dir_TRT and B == dir_TLT)\
-)
+ The code has been adapted to the more reasonable and simplified direction model.
-#define glyphdir_opposite(A,B) 0
+ In case I forget when I added the normalization code: it was november 2019 and it took me way more time
+ than usual because I got distracted after discovering Alyona Yarushina on YT (in november 2019) which
+ blew some fuses in the musical aware part of my brain in a similar way as when I discovered Kate Bush,
+ so I had to watch a whole lot of her perfect covers (multiple times and for sure many more times). A
+ new benchmark.
-#define pardir_equal(A,B) (\
-(dir_TLT_or_TRT(A) and dir_TLT_or_TRT(B)) or \
-(A == dir_LTL and B == dir_LTL) or \
-(A == dir_RTT and B == dir_RTT)\
-)
-
-#define textdir_equal(A,B) (\
-(A == dir_TLT and B == dir_TLT) or \
-(A == dir_TRT and B == dir_TRT) or \
-(A == dir_LTL and dir_LTL_or_RTT(B)) or \
-(A == dir_RTT and dir_LTL_or_RTT(B))\
-)
-
---]]--
+]]--
-local tonumber = tonumber
-local utfchar = utf.char
-local write, write_nl = texio.write, texio.write_nl
-local sub, formatters = string.sub, string.formatters
-local insert, remove = table.insert, table.remove
+local unpack = unpack
-- local fonts, nodes, node = fonts, nodes, node -- too many locals
@@ -199,8 +149,10 @@ local report_parbuilders = logs.reporter("nodes","parbuilders")
----- report_hpackers = logs.reporter("nodes","hpackers")
local calculate_badness = tex.badness
-local texnest = tex.nest
local texlists = tex.lists
+local texget = tex.get
+local texset = tex.set
+local texgetglue = tex.getglue
-- (t == 0 and 0) or (s <= 0 and 10000) or calculate_badness(t,s)
@@ -226,228 +178,275 @@ local texlists = tex.lists
-- end
-- end
-local parbuilders = builders.paragraphs
-local constructors = parbuilders.constructors
-
-local setmetatableindex = table.setmetatableindex
-
-local fonthashes = fonts.hashes
-local chardata = fonthashes.characters
-local quaddata = fonthashes.quads
-local parameters = fonthashes.parameters
-
-local nuts = nodes.nuts
-local tonut = nuts.tonut
-
-local getfield = nuts.getfield
-local getid = nuts.getid
-local getsubtype = nuts.getsubtype
-local getnext = nuts.getnext
-local getprev = nuts.getprev
-local getboth = nuts.getboth
-local getlist = nuts.getlist
-local getdisc = nuts.getdisc
-local getattr = nuts.getattr
-local getdisc = nuts.getdisc
-local getglue = nuts.getglue
-local getwhd = nuts.getwhd
-local getkern = nuts.getkern
-local getpenalty = nuts.getpenalty
-local getdirection = nuts.getdirection
-local getshift = nuts.getshift
-local getwidth = nuts.getwidth
-local getheight = nuts.getheight
-local getdepth = nuts.getdepth
-local getdata = nuts.getdata
-local getwhd = nuts.getwhd
-
-local isglyph = nuts.isglyph
-
-local setfield = nuts.setfield
-local setlink = nuts.setlink
-local setlist = nuts.setlist
-local setboth = nuts.setboth
-local setnext = nuts.setnext
-local setprev = nuts.setprev
-local setdisc = nuts.setdisc
-local setsubtype = nuts.setsubtype
-local setglue = nuts.setglue
-local setwhd = nuts.setwhd
-local setkern = nuts.setkern
-local setdirection = nuts.setdirection
-local setshift = nuts.setshift
-local setwidth = nuts.setwidth
-local setexpansion = nuts.setexpansion
-
-local slide_node_list = nuts.slide -- get rid of this, probably ok > 78.2
-local find_tail = nuts.tail
-local copy_node = nuts.copy
-local flush_node = nuts.flush
-local flush_node_list = nuts.flush_list
------ hpack_nodes = nuts.hpack
-local xpack_nodes = nuts.hpack
-local replace_node = nuts.replace
-local insert_node_after = nuts.insert_after
-local insert_node_before = nuts.insert_before
-local is_zero_glue = nuts.is_zero_glue
-local is_skipable = nuts.protrusion_skippable
-
-local nodepool = nuts.pool
-
-local nodecodes = nodes.nodecodes
-local kerncodes = nodes.kerncodes
-local glyphcodes = nodes.glyphcodes
-local leadercodes = nodes.leadercodes
-local margincodes = nodes.margincodes
-local disccodes = nodes.disccodes
-local mathcodes = nodes.mathcodes
-local fillcodes = nodes.fillcodes
-local boundarycodes = nodes.boundarycodes
-
-local temp_code = nodecodes.temp
-local glyph_code = nodecodes.glyph
-local ins_code = nodecodes.ins
-local mark_code = nodecodes.mark
-local adjust_code = nodecodes.adjust
-local penalty_code = nodecodes.penalty
-local disc_code = nodecodes.disc
-local math_code = nodecodes.math
-local kern_code = nodecodes.kern
-local glue_code = nodecodes.glue
-local hlist_code = nodecodes.hlist
-local vlist_code = nodecodes.vlist
-local unset_code = nodecodes.unset
-local marginkern_code = nodecodes.marginkern
-local dir_code = nodecodes.dir
-local boundary_code = nodecodes.boundary
-
-local protrusionboundary_code = boundarycodes.protrusion
-
-local leaders_code = leadercodes.leaders
-
-local localpar_code = nodecodes.localpar
-
-local userkern_code = kerncodes.userkern
-local italickern_code = kerncodes.italiccorrection
-local fontkern_code = kerncodes.fontkern
-local accentkern_code = kerncodes.accentkern
-
-local ligatureglyph_code = glyphcodes.ligature
-
-local fillcodes = nodes.fillcodes
-
-local leftmargin_code = margincodes.left
------ rightmargin_code = margincodes.right
-
-local automaticdisc_code = disccodes.automatic
-local regulardisc_code = disccodes.regular
-local firstdisc_code = disccodes.first
-local seconddisc_code = disccodes.second
-
-local endmath_code = mathcodes.endmath
-
-local nosubtype_code = 0
-
-local unhyphenated_code = nodecodes.unhyphenated or 1
-local hyphenated_code = nodecodes.hyphenated or 2
-local delta_code = nodecodes.delta or 3
-local passive_code = nodecodes.passive or 4
-
-local maxdimen = number.maxdimen
-
-local max_halfword = 0x7FFFFFFF
-local infinite_penalty = 10000
-local eject_penalty = -10000
-local infinite_badness = 10000
-local awful_badness = 0x3FFFFFFF
-local ignore_depth = -65536000
-
-local fit_very_loose_class = 0 -- fitness for lines stretching more than their stretchability
-local fit_loose_class = 1 -- fitness for lines stretching 0.5 to 1.0 of their stretchability
-local fit_decent_class = 2 -- fitness for all other lines
-local fit_tight_class = 3 -- fitness for lines shrinking 0.5 to 1.0 of their shrinkability
-
-local new_penalty = nodepool.penalty
-local new_direction = nodepool.direction
-local new_leftmarginkern = nodepool.leftmarginkern
-local new_rightmarginkern = nodepool.rightmarginkern
-local new_leftskip = nodepool.leftskip
-local new_rightskip = nodepool.rightskip
-local new_lineskip = nodepool.lineskip
-local new_baselineskip = nodepool.baselineskip
-local new_temp = nodepool.temp
-local new_rule = nodepool.rule
-local new_hlist = nodepool.hlist
+local parbuilders = builders.paragraphs
+local constructors = parbuilders.constructors
+
+local setmetatableindex = table.setmetatableindex
+
+local fonthashes = fonts.hashes
+local chardata = fonthashes.characters
+local quaddata = fonthashes.quads
+local parameters = fonthashes.parameters
+
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+
+local getfield = nuts.getfield
+local getid = nuts.getid
+local getsubtype = nuts.getsubtype
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getboth = nuts.getboth
+local getlist = nuts.getlist
+local getdisc = nuts.getdisc
+local getattr = nuts.getattr
+local getdisc = nuts.getdisc
+local getglue = nuts.getglue
+local getwhd = nuts.getwhd
+local getkern = nuts.getkern
+local getpenalty = nuts.getpenalty
+local getdirection = nuts.getdirection
+local getshift = nuts.getshift
+local getwidth = nuts.getwidth
+local getheight = nuts.getheight
+local getdepth = nuts.getdepth
+local getdata = nuts.getdata
+local getreplace = nuts.getreplace
+local setreplace = nuts.setreplace
+local getpost = nuts.getpost
+local setpost = nuts.setpost
+local getpre = nuts.getpre
+local setpre = nuts.setpre
+
+local isglyph = nuts.isglyph
+local start_of_par = nuts.start_of_par
+
+local setfield = nuts.setfield
+local setlink = nuts.setlink
+local setlist = nuts.setlist
+local setboth = nuts.setboth
+local setnext = nuts.setnext
+local setprev = nuts.setprev
+local setdisc = nuts.setdisc
+local setsubtype = nuts.setsubtype
+local setglue = nuts.setglue
+local setwhd = nuts.setwhd
+local setkern = nuts.setkern
+local setdirection = nuts.setdirection
+local setshift = nuts.setshift
+local setwidth = nuts.setwidth
+local setexpansion = nuts.setexpansion
+
+local find_tail = nuts.tail
+local copy_node = nuts.copy
+local flush_node = nuts.flush
+local flush_node_list = nuts.flush_list
+----- hpack_nodes = nuts.hpack
+local xpack_nodes = nuts.hpack
+local replace_node = nuts.replace
+local remove_node = nuts.remove
+local insert_node_after = nuts.insert_after
+local insert_node_before = nuts.insert_before
+local is_zero_glue = nuts.is_zero_glue
+local is_skipable = nuts.protrusion_skippable
+local setattributelist = nuts.setattributelist
+local find_node = nuts.find_node
+
+local nextnode = nuts.traversers.node
+local nextglue = nuts.traversers.glue
+
+local nodepool = nuts.pool
+
+local nodecodes = nodes.nodecodes
+local kerncodes = nodes.kerncodes
+local margincodes = nodes.margincodes
+local disccodes = nodes.disccodes
+local mathcodes = nodes.mathcodes
+local fillcodes = nodes.fillcodes
+local gluecodes = nodes.gluecodes
+
+local temp_code = nodecodes.temp
+local glyph_code = nodecodes.glyph
+local ins_code = nodecodes.ins
+local mark_code = nodecodes.mark
+local adjust_code = nodecodes.adjust
+local penalty_code = nodecodes.penalty
+local disc_code = nodecodes.disc
+local math_code = nodecodes.math
+local kern_code = nodecodes.kern
+local glue_code = nodecodes.glue
+local hlist_code = nodecodes.hlist
+local vlist_code = nodecodes.vlist
+local unset_code = nodecodes.unset
+local marginkern_code = nodecodes.marginkern
+local dir_code = nodecodes.dir
+local boundary_code = nodecodes.boundary
+local localpar_code = nodecodes.localpar
+
+local protrusionboundary_code = nodes.boundarycodes.protrusion
+local leaders_code = nodes.leadercodes.leaders
+local indentlist_code = nodes.listcodes.indent
+local ligatureglyph_code = nodes.glyphcodes.ligature
+local cancel_code = nodes.dircodes.cancel
+
+local userkern_code = kerncodes.userkern
+local italickern_code = kerncodes.italiccorrection
+local fontkern_code = kerncodes.fontkern
+local accentkern_code = kerncodes.accentkern
+
+local leftmargin_code = margincodes.left
+----- rightmargin_code = margincodes.right
+
+local automaticdisc_code = disccodes.automatic
+local regulardisc_code = disccodes.regular
+local firstdisc_code = disccodes.first
+local seconddisc_code = disccodes.second
+
+local spaceskip_code = gluecodes.spaceskip
+local xspaceskip_code = gluecodes.xspaceskip
+local rightskip_code = gluecodes.rightskip
+
+local endmath_code = mathcodes.endmath
+
+local righttoleft_code = nodes.dirvalues.righttoleft
+
+local nosubtype_code = 0
+
+local unhyphenated_code = nodecodes.unhyphenated or 1
+local hyphenated_code = nodecodes.hyphenated or 2
+local delta_code = nodecodes.delta or 3
+local passive_code = nodecodes.passive or 4
+
+local maxdimen = number.maxdimen
+
+local max_halfword = 0x7FFFFFFF
+local infinite_penalty = 10000
+local eject_penalty = -10000
+local infinite_badness = 10000
+local awful_badness = 0x3FFFFFFF
+local ignore_depth = -65536000
+
+local fit_very_loose_class = 0 -- fitness for lines stretching more than their stretchability
+local fit_loose_class = 1 -- fitness for lines stretching 0.5 to 1.0 of their stretchability
+local fit_decent_class = 2 -- fitness for all other lines
+local fit_tight_class = 3 -- fitness for lines shrinking 0.5 to 1.0 of their shrinkability
+
+local new_penalty = nodepool.penalty
+local new_direction = nodepool.direction
+local new_leftmarginkern = nodepool.leftmarginkern
+local new_rightmarginkern = nodepool.rightmarginkern
+local new_leftskip = nodepool.leftskip
+local new_rightskip = nodepool.rightskip
+local new_lefthangskip = nodepool.lefthangskip
+local new_righthangskip = nodepool.righthangskip
+local new_indentskip = nodepool.indentskip
+local new_correctionskip = nodepool.correctionskip
+local new_lineskip = nodepool.lineskip
+local new_baselineskip = nodepool.baselineskip
+local new_temp = nodepool.temp
+local new_rule = nodepool.rule
+local new_hlist = nodepool.hlist
+
+local getnormalizeline = nuts.getnormalizeline
-- helpers --
-- It makes more sense to move the somewhat messy dir state tracking
-- out of the main functions. First we create a stack allocator.
-local function new_dir_stack(dir) -- also use elsewhere
- return { n = 0, dir }
-end
-
-- The next function checks a dir node and returns the new dir state. By
-- using a static table we are quite efficient. This function is used
-- in the parbuilder.
-local function checked_line_dir(stack,current)
+local function checked_line_dir(stack,current) -- can be inlined now
local direction, pop = getdirection(current)
+ local n = stack.n
if not pop then
- local n = stack.n + 1
+ n = n + 1
stack.n = n
- stack[n] = current
+ stack[n] = direction
return direction
elseif n > 0 then
- local n = stack.n
- local dirnode = stack[n]
- dirstack.n = n - 1
- direction = getdirection(dirnode) -- we could save it
- return direction
+ n = n - 1
+ stack.n = n
+ return stack[n]
else
report_parbuilders("warning: missing pop node (%a)",1) -- in line ...
end
end
--- The next function checks dir nodes in a list and appends the negations
--- that are currently needed (some day LuaTeX will be more tolerant). We use
--- the negations for the next line.
+-- The next function checks dir nodes in a list and injects dir nodes
+-- that are currently needed.
+
+local function inject_dirs_at_begin_of_line(stack,current)
+ local n = stack.n
+ if n > 0 then
+ local h = current
+ for i=1,n do
+ local d = new_direction(stack[i])
+ setattributelist(d,current)
+ h, current = insert_node_after(h,current,d)
+ end
+ stack.n = 0
+ return h
+ else
+ return current
+ end
+end
local function inject_dirs_at_end_of_line(stack,current,start,stop)
- local e = start
local n = stack.n
- local h = nil
- -- todo: traverse
while start and start ~= stop do
local id = getid(start)
if id == dir_code then
local direction, pop = getdirection(start)
if not pop then
n = n + 1
- stack[n] = start
+ stack[n] = direction
elseif n > 0 then
+if direction == stack[n] then
+ -- like in the engine
n = n - 1
+end
else
report_parbuilders("warning: missing pop node (%a)",2) -- in line ...
end
end
start = getnext(start)
end
- for i=n,1,-1 do
- h, current = insert_node_after(current,current,new_direction(getdirection(stack[i]),true))
+ if n > 0 then
+ -- from 1,n and before
+ local h = start
+ for i=n,1,-1 do
+ local d = new_direction(stack[i],true)
+ setattributelist(d,start)
+ h, current = insert_node_after(h,current,d)
+ end
end
stack.n = n
return current
end
-local function inject_dirs_at_begin_of_line(stack,current)
- local h = nil
- for i=stack.n,1,-1 do
- h, current = insert_node_after(current,current,new_direction(stack[i]))
+local ignore_math_skip = node.direct.ignore_math_skip or function(current)
+ local mode = texget("mathskipmode")
+ if mode == 6 or mode == 7 then
+ local b = true
+ local n = getsubtype(current) == endmath_code and getnext(current) or getprev(current)
+ if n and getid(n) == glue_code then
+ local s = getsubtype(n)
+ if s == spaceskip_code or s == xspaceskip_code then
+ b = false
+ end
+ end
+ if mode == 7 then
+ b = not b
+ end
+ if b then
+ setglue(current)
+ return true
+ end
end
- stack.n = 0
- return current
+ return false
end
-- diagnostics --
@@ -487,59 +486,117 @@ local function calculate_fraction(x,n,d,max_answer)
end
end
-local function check_shrinkage(par,n)
- -- called often, so maybe move inline -- use NORMAL
- if getfield(n,"shrink_order") ~= 0 and getfield(n,"shrink") ~= 0 then
- if par.no_shrink_error_yet then
- par.no_shrink_error_yet = false
- report_parbuilders("infinite glue shrinkage found in a paragraph and removed")
- end
- n = copy_node(n)
- setfield(n,"shrink_order",0)
+local function infinite_shrinkage_error(par)
+ if par.no_shrink_error_yet then
+ par.no_shrink_error_yet = false
+ report_parbuilders("infinite glue shrinkage found in a paragraph and removed")
end
- return n
end
-- It doesn't really speed up much but the additional memory usage is
-- rather small so it doesn't hurt too much.
local expansions = { }
-local nothing = { stretch = 0, shrink = 0 }
+local nothing = { stretch = 0, shrink = 0 } -- or just true or so
+
+-- setmetatableindex(expansions,function(t,font) -- we can store this in tfmdata if needed
+-- local expansion = parameters[font].expansion -- can be an extra hash
+-- if expansion and expansion.step ~= 0 then
+-- local stretch = expansion.stretch
+-- local shrink = expansion.shrink
+-- if shrink ~= 0 or stretch ~= 0 then
+-- local factors = { }
+-- local c = chardata[font]
+-- setmetatableindex(factors,function(t,char)
+-- local fc = c[char]
+-- local ef = fc.expansion_factor
+-- if ef and ef > 0 then
+-- if stretch ~= 0 or shrink ~= 0 then
+-- -- todo in lmtx: get rid of quad related scaling
+-- local factor = ef / 1000
+-- local ef_quad = factor * quaddata[font] / 1000
+-- local v = {
+-- glyphstretch = stretch * ef_quad,
+-- glyphshrink = shrink * ef_quad,
+-- factor = factor, -- do we need these, if not then we
+-- stretch = stretch, -- can as well use the chardata table
+-- shrink = shrink, -- to store the two above
+-- }
+-- t[char] = v
+-- return v
+-- end
+-- end
+-- t[char] = nothing
+-- return nothing
+-- end)
+-- t[font] = factors
+-- return factors
+-- end
+-- end
+-- t[font] = false
+-- return false
+-- end)
+
+-- local function kern_stretch_shrink(p,d)
+-- local left = getprev(p)
+-- if left then
+-- local char, font = isglyph(left)
+-- if char then
+-- local data = expansions[font]
+-- if data then
+-- data = data[char]
+-- if data then
+-- local stretch = data.stretch
+-- local shrink = data.shrink
+-- if stretch ~= 0 then
+-- stretch = data.factor * d * (stretch - 1)
+-- end
+-- if shrink ~= 0 then
+-- shrink = data.factor * d * (shrink - 1)
+-- end
+-- return stretch, shrink
+-- end
+-- end
+-- end
+-- end
+-- return 0, 0
+-- end
setmetatableindex(expansions,function(t,font) -- we can store this in tfmdata if needed
local expansion = parameters[font].expansion -- can be an extra hash
- if expansion and expansion.auto then
- local factors = { }
- local c = chardata[font]
- setmetatableindex(factors,function(t,char)
- local fc = c[char]
- local ef = fc.expansion_factor
- if ef and ef > 0 then
- local stretch = expansion.stretch
- local shrink = expansion.shrink
- if stretch ~= 0 or shrink ~= 0 then
+ if expansion and expansion.step ~= 0 then
+ local stretch = expansion.stretch
+ local shrink = expansion.shrink
+ if shrink ~= 0 or stretch ~= 0 then
+ local factors = {
+ stretch = stretch,
+ shrink = shrink,
+ }
+ local c = chardata[font]
+ setmetatableindex(factors,function(t,char)
+ local fc = c[char]
+ local ef = fc.expansion_factor
+ if ef and ef > 0 and stretch ~= 0 or shrink ~= 0 then
+ -- todo in lmtx: get rid of quad related scaling
local factor = ef / 1000
local ef_quad = factor * quaddata[font] / 1000
local v = {
glyphstretch = stretch * ef_quad,
glyphshrink = shrink * ef_quad,
factor = factor,
- stretch = stretch,
- shrink = shrink,
}
t[char] = v
return v
end
- end
- t[char] = nothing
- return nothing
- end)
- t[font] = factors
- return factors
- else
- t[font] = false
- return false
+ t[char] = nothing
+ return nothing
+ end)
+ t[font] = factors
+ return factors
+ end
end
+ t[font] = false
+ return false
end)
local function kern_stretch_shrink(p,d)
@@ -547,19 +604,21 @@ local function kern_stretch_shrink(p,d)
if left then
local char, font = isglyph(left)
if char then
- local data = expansions[font][char]
- if data then
- local stretch = data.stretch
- local shrink = data.shrink
- if stretch ~= 0 then
- -- stretch = data.factor * (d * stretch - d)
- stretch = data.factor * d * (stretch - 1)
- end
- if shrink ~= 0 then
- -- shrink = data.factor * (d * shrink - d)
- shrink = data.factor * d * (shrink - 1)
+ local fdata = expansions[font]
+ if fdata then
+ local cdata = fdata[char]
+ if cdata then
+ local stretch = fdata.stretch
+ local shrink = fdata.shrink
+ local factor = cdata.factor * d
+ if stretch ~= 0 then
+ stretch = factor * (stretch - 1)
+ end
+ if shrink ~= 0 then
+ shrink = factor * (shrink - 1)
+ end
+ return stretch, shrink
end
- return stretch, shrink
end
end
end
@@ -583,6 +642,9 @@ end)
-- state:
+-- the step criterium is no longer an issue, we can be way more tolerant in
+-- luatex as we act per glyph
+
local function check_expand_pars(checked_expansion,f)
local expansion = parameters[f].expansion
if not expansion then
@@ -670,7 +732,7 @@ local function find(head) -- do we really want to recurse into an hlist?
elseif id == boundary_code then
if getsubtype(head) == protrusionboundary_code then
local v = getdata(head)
- if v == 1 or v == 3 then
+ if v == 1 or v == 3 then -- brrr
head = getnext(head)
if head then
head = getnext(head)
@@ -754,7 +816,7 @@ local function left_pw(p)
if not prot or prot == 0 then
return 0
end
- return prot * quaddata[font] / 1000, p
+ return prot, p
end
local function right_pw(p)
@@ -763,7 +825,7 @@ local function right_pw(p)
if not prot or prot == 0 then
return 0
end
- return prot * quaddata[font] / 1000, p
+ return prot, p
end
-- par parameters
@@ -785,12 +847,7 @@ local function add_to_width(line_break_dir,checked_expansion,s) -- split into tw
while s do
local char, id = isglyph(s)
if char then
- local wd, ht, dp = getwhd(s)
- if is_rotated(line_break_dir) then
- size = size + ht + dp
- else
- size = size + wd
- end
+ size = size + getwidth(s)
if checked_expansion then
local data = checked_expansion[id] -- id == font
if data then
@@ -802,12 +859,7 @@ local function add_to_width(line_break_dir,checked_expansion,s) -- split into tw
end
end
elseif id == hlist_code or id == vlist_code then
- local wd, ht, dp = getwhd(s)
- if textdir_parallel(getdirection(s),line_break_dir) then
- size = size + wd
- else
- size = size + ht + dp
- end
+ size = size + getwidth(s)
elseif id == kern_code then
local kern = getkern(s)
if kern ~= 0 then
@@ -910,20 +962,21 @@ do
local function append_to_vlist(par, b)
local prev_depth = par.prev_depth
local head_field = par.head_field
- local tail_field = head_field and slide_node_list(head_field) -- todo: find_tail
+ local tail_field = head_field and find_tail(head_field)
local is_hlist = getid(b) == hlist_code
- -- if prev_depth > par.ignored_dimen then
if prev_depth > ignore_depth then
if is_hlist then
- local width, stretch, shrink, stretch_order, shrink_order = getglue(par.baseline_skip)
+ -- we can fetch the skips values earlier if needed
+ local width, stretch, shrink, stretch_order, shrink_order = unpack(par.baseline_skip)
local delta = width - prev_depth - getheight(b) -- deficiency of space between baselines
local skip = nil
if delta < par.line_skip_limit then
- width, stretch, shrink, stretch_order, shrink_order = getglue(par.lineskip)
+ width, stretch, shrink, stretch_order, shrink_order = unpack(par.lineskip)
skip = new_lineskip(width, stretch, shrink, stretch_order, shrink_order)
else
skip = new_baselineskip(delta, stretch, shrink, stretch_order, shrink_order)
end
+ setattributelist(skip,par.head)
if head_field then
setlink(tail_field,skip)
else
@@ -941,14 +994,14 @@ do
if is_hlist then
local pd = getdepth(b)
par.prev_depth = pd
- texnest[texnest.ptr].prevdepth = pd
+ texset("prevdepth",pd)
end
end
local function append_list(par, b)
local head_field = par.head_field
if head_field then
- local n = slide_node_list(head_field) -- todo: find_tail
+ local n = find_tail(head_field)
setlink(n,b)
else
par.head_field = b
@@ -961,18 +1014,18 @@ do
local function initialize_line_break(head,display)
- local hang_indent = tex.hangindent or 0
- local hsize = tex.hsize or 0
- local hang_after = tex.hangafter or 0
- local par_shape_ptr = tex.parshape
- local left_skip = tonut(tex.leftskip) -- nodes
- local right_skip = tonut(tex.rightskip) -- nodes
- local pretolerance = tex.pretolerance
- local tolerance = tex.tolerance
- local adjust_spacing = tex.adjustspacing
- local protrude_chars = tex.protrudechars
- local last_line_fit = tex.lastlinefit
- local par_dir = tex.pardirection
+ local hang_indent = texget("hangindent")
+ local hsize = texget("hsize")
+ local hang_after = texget("hangafter")
+ local par_shape_ptr = texget("parshape")
+ local left_skip = { texgetglue("leftskip") }
+ local right_skip = { texgetglue("rightskip") }
+ local pretolerance = texget("pretolerance")
+ local tolerance = texget("tolerance")
+ local adjust_spacing = texget("adjustspacing")
+ local protrude_chars = texget("protrudechars")
+ local last_line_fit = texget("lastlinefit")
+ local par_dir = texget("pardirection")
local newhead = new_temp()
setnext(newhead,head)
@@ -996,11 +1049,11 @@ do
pass_number = 0, -- the number of passive nodes allocated on this pass
auto_breaking = 0, -- make auto_breaking accessible out of line_break
- active_width = { size = 0, stretch = 0, fi = 0, fil = 0, fill = 0, filll = 0, shrink = 0, adjust_stretch = 0, adjust_shrink = 0 },
- break_width = { size = 0, stretch = 0, fi = 0, fil = 0, fill = 0, filll = 0, shrink = 0, adjust_stretch = 0, adjust_shrink = 0 },
- disc_width = { size = 0, adjust_stretch = 0, adjust_shrink = 0 },
- fill_width = { stretch = 0, fi = 0, fil = 0, fill = 0, filll = 0, shrink = 0 },
- background = { size = 0, stretch = 0, fi = 0, fil = 0, fill = 0, filll = 0, shrink = 0 },
+ active_width = { size = 0, normal = 0, fi = 0, fil = 0, fill = 0, filll = 0, shrink = 0, adjust_stretch = 0, adjust_shrink = 0 },
+ break_width = { size = 0, normal = 0, fi = 0, fil = 0, fill = 0, filll = 0, shrink = 0, adjust_stretch = 0, adjust_shrink = 0 },
+ disc_width = { size = 0, adjust_stretch = 0, adjust_shrink = 0 },
+ fill_width = { normal = 0, fi = 0, fil = 0, fill = 0, filll = 0, shrink = 0 },
+ background = { size = 0, normal = 0, fi = 0, fil = 0, fill = 0, filll = 0, shrink = 0 },
hang_indent = hang_indent,
hsize = hsize,
@@ -1017,39 +1070,29 @@ do
max_shrink_ratio = adjust_spacing_status,
cur_font_step = adjust_spacing_status,
checked_expansion = false,
- tracing_paragraphs = tex.tracingparagraphs > 0,
-
- emergency_stretch = tex.emergencystretch or 0,
- looseness = tex.looseness or 0,
- line_penalty = tex.linepenalty or 0,
- hyphen_penalty = tex.hyphenpenalty or 0,
- broken_penalty = tex.brokenpenalty or 0,
- inter_line_penalty = tex.interlinepenalty or 0,
- club_penalty = tex.clubpenalty or 0,
- widow_penalty = tex.widowpenalty or 0,
- display_widow_penalty = tex.displaywidowpenalty or 0,
- ex_hyphen_penalty = tex.exhyphenpenalty or 0,
+ tracing_paragraphs = texget("tracingparagraphs") > 0,
- adj_demerits = tex.adjdemerits or 0,
- double_hyphen_demerits = tex.doublehyphendemerits or 0,
- final_hyphen_demerits = tex.finalhyphendemerits or 0,
+ emergency_stretch = texget("emergencystretch") or 0,
+ looseness = texget("looseness") or 0,
+ line_penalty = texget("linepenalty") or 0,
+ broken_penalty = texget("brokenpenalty") or 0,
+ inter_line_penalty = texget("interlinepenalty") or 0,
+ club_penalty = texget("clubpenalty") or 0,
+ widow_penalty = texget("widowpenalty") or 0,
+ display_widow_penalty = texget("displaywidowpenalty") or 0,
- first_line = 0, -- texnest[texnest.ptr].modeline, -- 0, -- cur_list.pg_field
+ adj_demerits = texget("adjdemerits") or 0,
+ double_hyphen_demerits = texget("doublehyphendemerits") or 0,
+ final_hyphen_demerits = texget("finalhyphendemerits") or 0,
- -- each_line_height = tex.pdfeachlineheight or 0, -- this will go away
- -- each_line_depth = tex.pdfeachlinedepth or 0, -- this will go away
- -- first_line_height = tex.pdffirstlineheight or 0, -- this will go away
- -- last_line_depth = tex.pdflastlinedepth or 0, -- this will go away
+ first_line = texget("prevgraf"),
+ prev_depth = texget("prevdepth"),
- -- ignored_dimen = tex.pdfignoreddimen or 0,
+ baseline_skip = { texgetglue("baselineskip") },
+ lineskip = { texgetglue("lineskip") },
+ line_skip_limit = texget("lineskiplimit"),
- baseline_skip = tonut(tex.baselineskip),
- lineskip = tonut(tex.lineskip),
- line_skip_limit = tex.lineskiplimit,
-
- prev_depth = texnest[texnest.ptr].prevdepth,
-
- final_par_glue = slide_node_list(head), -- todo: we know tail already, slow
+ final_par_glue = find_tail(head),
par_break_dir = par_dir,
line_break_dir = par_dir,
@@ -1118,11 +1161,6 @@ do
}
- -- optimizers
-
- par.used_left_skip = used_skip(par.left_skip)
- par.used_right_skip = used_skip(par.right_skip)
-
-- so far
if adjust_spacing > 1 then
@@ -1138,7 +1176,7 @@ do
par.tolerance = hztolerance
end
- expand_kerns = expand_kerns_mode or (adjust_spacing == 2)
+ expand_kerns = expand_kerns_mode or (adjust_spacing == 2) -- why not > 1 ?
end
@@ -1146,11 +1184,17 @@ do
local background = par.background
- local l = check_shrinkage(par,left_skip)
- local r = check_shrinkage(par,right_skip)
+ local lwidth, lstretch, lshrink, lstretch_order, lshrink_order = unpack(left_skip)
+ local rwidth, rstretch, rshrink, rstretch_order, rshrink_order = unpack(right_skip)
- local lwidth, lstretch, lshrink, lstretch_order, lshrink_order = getglue(l)
- local rwidth, rstretch, rshrink, rstretch_order, rshrink_order = getglue(r)
+ if lshrink_order ~= 0 and lshrink ~= 0 then
+ infinite_shrinkage_error(par)
+ lshrink_order = 0
+ end
+ if rshrink_order ~= 0 and rshrink ~= 0 then
+ infinite_shrinkage_error(par)
+ rshrink_order = 0
+ end
local l_order = fillcodes[lstretch_order]
local r_order = fillcodes[rstretch_order]
@@ -1167,8 +1211,8 @@ do
par.second_width = hsize
par.second_indent = 0
else
- local abs_hang_after = hang_after >0 and hang_after or -hang_after
- local abs_hang_indent = hang_indent>0 and hang_indent or -hang_indent
+ local abs_hang_after = hang_after > 0 and hang_after or -hang_after
+ local abs_hang_indent = hang_indent > 0 and hang_indent or -hang_indent
par.last_special_line = abs_hang_after
if hang_after < 0 then
par.first_width = hsize - abs_hang_indent
@@ -1243,21 +1287,19 @@ do
local function post_line_break(par)
- local prevgraf = texnest[texnest.ptr].prevgraf
+ local prevgraf = par.first_line -- or texget("prevgraf")
local current_line = prevgraf + 1 -- the current line number being justified
-
local adjust_spacing = par.adjust_spacing
local protrude_chars = par.protrude_chars
local statistics = par.statistics
-
- local stack = new_dir_stack()
-
- local leftskip = par.used_left_skip -- used or normal ?
+ local leftskip = par.left_skip
local rightskip = par.right_skip
local parshape = par.par_shape_ptr
- ----- ignored_dimen = par.ignored_dimen
+ -- local adapt_width = par.adapt_width
+ local hsize = par.hsize
- local adapt_width = par.adapt_width
+ local dirstack = par.dirstack
+ local normalize = getnormalizeline()
-- reverse the links of the relevant passive nodes, goto first breakpoint
@@ -1273,11 +1315,15 @@ do
local head = par.head
- -- maybe : each_...
+ -- when we normalize and have no content still ls/rs gets appended while
+ -- the engine doesnt' do that so there is some test missing that prevents
+ -- entering here
while current_break do
- inject_dirs_at_begin_of_line(stack,head)
+ -- hm, here we have head == localpar and in the engine it's a temp node
+
+ head = inject_dirs_at_begin_of_line(dirstack,head)
local disc_break = false
local post_disc_break = false
@@ -1285,10 +1331,9 @@ do
local lineend = nil -- lineend : the last node of the line (and paragraph)
local lastnode = current_break.cur_break -- lastnode: the node after which the dir nodes should be closed
-
if not lastnode then
-- only at the end
- lastnode = slide_node_list(head) -- todo: find_tail
+ lastnode = find_tail(head)
if lastnode == par.final_par_glue then
lineend = lastnode
lastnode = getprev(lastnode)
@@ -1296,16 +1341,16 @@ do
else -- todo: use insert_list_after
local id = getid(lastnode)
if id == glue_code then
- -- lastnode is normal skip
- lastnode = replace_node(lastnode,new_rightskip(rightskip))
+ local r = new_rightskip(unpack(rightskip))
+ setattributelist(r,lastnode)
+ lastnode = replace_node(lastnode,r)
glue_break = true
lineend = lastnode
lastnode = getprev(lastnode)
elseif id == disc_code then
- local prevlast = getprev(lastnode)
- local nextlast = getnext(lastnode)
- local subtype = getsubtype(lastnode)
+ local prevlast, nextlast = getboth(lastnode)
local pre, post, replace, pretail, posttail, replacetail = getdisc(lastnode,true)
+ local subtype = getsubtype(lastnode)
if subtype == seconddisc_code then
if not (getid(prevlast) == disc_code and getsubtype(prevlast) == firstdisc_code) then
report_parbuilders('unsupported disc at location %a',3)
@@ -1337,8 +1382,8 @@ do
report_parbuilders('unsupported disc at location %a',4)
end
setsubtype(nextlast,regulardisc_code)
- setfield(nextlast,"replace",post)
- setfield(lastnode,"post") -- nil
+ setreplace(nextlast,post)
+ setpost(lastnode)
end
if replace then
flush_node_list(replace)
@@ -1356,13 +1401,16 @@ do
disc_break = true
elseif id == kern_code then
setkern(lastnode,0)
- elseif getid(lastnode) == math_code then
+ elseif id == math_code then
setkern(lastnode,0) -- surround
-- new in luatex
setglue(lastnode) -- zeros
end
end
- lastnode = inject_dirs_at_end_of_line(stack,lastnode,getnext(head),current_break.cur_break)
+ -- todo: clean up this mess which results from all kind of engine merges
+ -- (start/end nodes)
+ -- hm, head ?
+ lastnode = inject_dirs_at_end_of_line(dirstack,lastnode,getnext(head),current_break.cur_break)
local rightbox = current_break.passive_right_box
if rightbox then
lastnode = insert_node_after(lastnode,lastnode,copy_node(rightbox))
@@ -1371,50 +1419,186 @@ do
lineend = lastnode
end
if lineend and lineend ~= head and protrude_chars > 0 then
- local id = getid(lineend)
- local c = (disc_break and (id == glyph_code or id ~= disc_code) and lineend) or getprev(lineend)
- local p = find_protchar_right(getnext(head),c)
- if p and getid(p) == glyph_code then
- local w, last_rightmost_char = right_pw(p)
- if last_rightmost_char and w ~= 0 then
- -- so we inherit attributes, lineend is new pseudo head
- lineend, c = insert_node_after(lineend,c,new_rightmarginkern(copy_node(last_rightmost_char),-w))
+ if par.line_break_dir == righttoleft_code then
+ if protrude_chars > 2 then
+ local p = lineend
+ local l = nil
+ -- Backtrack over the last zero glues and dirs.
+ while p do
+ local id = getid(p)
+ if id == dir_code then
+ if getsubtype(p) ~= cancel_code then
+ break
+ end
+ p = getprev(p)
+ elseif id == glue_code then
+ if getwidth(p) == 0 then
+ p = getprev(p)
+ else
+ p = nil
+ break
+ end
+ elseif id == glyph_code then
+ break
+ else
+ p = nil
+ break
+ end
+ end
+ -- When |p| is non zero we have something.
+ while p do
+ local id = getid(p)
+ if id == glyph_code then
+ l = p
+ elseif id == glue_code then
+ if getwidth(p) == 0 then
+ -- No harm done.
+ else
+ l = nil
+ end
+ elseif id == dir_code then
+ if getdirection(p) ~= righttoleft_code then
+ p = nil
+ end
+ break
+ elseif id == localpar_code then
+ break
+ elseif id == temp_code then
+ -- Go on.
+ else
+ l = nil
+ end
+ p = getprev(p)
+ end
+ if l and p then
+ local w, last_rightmost_char = right_pw(l)
+ if last_rightmost_char and w ~= 0 then
+ local k = new_rightmarginkern(copy_node(last_rightmost_char),-w)
+ setattributelist(k,l)
+ setlink(p,k,l)
+ end
+ end
+ end
+ else
+ local id = getid(lineend)
+ local c = nil
+ if disc_break and (id == glyph_code or id ~= disc_code) then
+ c = lineend
+ else
+ c = getprev(lineend)
+ end
+ local p = find_protchar_right(getnext(head),c)
+ if p and getid(p) == glyph_code then
+ local w, last_rightmost_char = right_pw(p)
+ if last_rightmost_char and w ~= 0 then
+ -- so we inherit attributes, lineend is new pseudo head
+ local k = new_rightmarginkern(copy_node(last_rightmost_char),-w)
+ setattributelist(k,p)
+-- insert_node_after(c,c,k)
+ insert_node_after(p,p,k)
+-- if c == lineend then
+-- lineend = getnext(c)
+-- end
+ end
end
end
end
-- we finish the line
local r = getnext(lineend)
- setnext(lineend)
+ setnext(lineend) -- lineend moves on as pseudo head
+ local start = getnext(head)
+ setlink(head,r)
if not glue_break then
- if rightskip then
- insert_node_after(lineend,lineend,new_rightskip(right_skip)) -- lineend moves on as pseudo head
- end
+ local rs = new_rightskip(unpack(rightskip))
+ setattributelist(rs,lineend)
+ start, lineend = insert_node_after(start,lineend,rs)
end
- -- each time ?
- local q = getnext(head)
- setlink(head,r)
+ local rs = lineend
-- insert leftbox (if needed after parindent)
local leftbox = current_break.passive_left_box
if leftbox then
- local first = getnext(q)
+ local first = getnext(start)
if first and current_line == (par.first_line + 1) and getid(first) == hlist_code and not getlist(first) then
- insert_node_after(q,q,copy_node(leftbox))
+ insert_node_after(start,start,copy_node(leftbox))
else
- q = insert_node_before(q,q,copy_node(leftbox))
+ start = insert_node_before(start,start,copy_node(leftbox))
end
end
if protrude_chars > 0 then
- local p = find_protchar_left(q)
- if p and getid(p) == glyph_code then
- local w, last_leftmost_char = left_pw(p)
- if last_leftmost_char and w ~= 0 then
- -- so we inherit attributes, q is pseudo head and moves back
- q = insert_node_before(q,q,new_leftmarginkern(copy_node(last_leftmost_char),-w))
+ if par.line_break_dir == righttoleft_code then
+ if protrude_chars > 2 then
+ local p = find_protchar_left(start)
+ if p then
+ local w, last_leftmost_char = right_pw(p)
+ if last_leftmost_char and w ~= 0 then
+ local k = new_rightmarginkern(copy_node(last_leftmost_char),-w)
+ setattributelist(k,p)
+ start = insert_node_before(start,start,k)
+ end
+ end
+ end
+ else
+ local p = find_protchar_left(start)
+ if p and getid(p) == glyph_code then
+ local w, last_leftmost_char = left_pw(p)
+ if last_leftmost_char and w ~= 0 then
+ -- so we inherit attributes, start is pseudo head and moves back
+ local k = new_leftmarginkern(copy_node(last_leftmost_char),-w)
+ setattributelist(k,p)
+ start = insert_node_before(start,start,k)
+ end
end
end
end
- if leftskip then
- q = insert_node_before(q,q,new_leftskip(leftskip))
+ local ls
+ if leftskip or normalize > 0 then
+ -- we could check for non zero but we will normalize anyway
+ ls = new_leftskip(unpack(leftskip))
+ setattributelist(ls,start)
+ start = insert_node_before(start,start,ls)
+ end
+ if normalize > 0 then
+ local localpar = nil
+ local localdir = nil
+ local indent = nil
+ local localpars = nil
+ local notflocal = 0
+ for n, id, subtype in nextnode, start do
+ if id == hlist_code then
+ if normalize > 1 and subtype == indentlist_code then
+ indent = n
+ end
+ elseif id == localpar_code then
+ if start_of_par(n) then --- maybe subtype check instead
+ localpar = n
+ elseif noflocals then
+ noflocals = noflocals + 1
+ localpars[noflocals] = n
+ else
+ noflocals = 1
+ localpars = { n }
+ end
+ elseif id == dir_code then
+ if localpar and not localdir and subtype(n) == cancel_code then
+ localdir = n
+ end
+ end
+ end
+ if indent then
+ local i = new_indentskip(getwidth(indent))
+ setattributelist(i,start)
+ replace_node(indent,i)
+ end
+ if localdir then
+ local d = new_direction((getdirection(localpar)))
+ setattributelist(d,start)
+ replace_node(localpar,d)
+ end
+ if localpars then
+ for i=1,noflocals do
+ start = remove_node(start,localpars[i],true)
+ end
+ end
end
local cur_width, cur_indent
if current_line > par.last_special_line then
@@ -1428,20 +1612,48 @@ do
cur_indent = par.first_indent
cur_width = par.first_width
end
-
- if adapt_width then -- extension
- local l, r = adapt_width(par,current_line)
- cur_indent = cur_indent + l
- cur_width = cur_width - l - r
+ -- extension
+ -- if adapt_width then
+ -- local l, r = adapt_width(par,current_line)
+ -- cur_indent = cur_indent + l
+ -- cur_width = cur_width - l - r
+ -- end
+ --
+ if normalize > 2 then
+ local l = new_lefthangskip()
+ local r = new_righthangskip()
+ if cur_width ~= hsize then
+ cur_indent = hsize - cur_width
+ end
+ if cur_indent > 0 then
+ setwidth(l,cur_indent)
+ elseif cur_indent < 0 then
+ setwidth(r,-cur_indent)
+ end
+ setattributelist(l,start)
+ setattributelist(r,start)
+ if normalize > 3 then
+ -- makes most sense
+ start = insert_node_after(start,ls,l)
+ start = insert_node_before(start,rs,r)
+ else
+ start = insert_node_before(start,ls,l)
+ start = insert_node_after(start,rs,r)
+ end
+ cur_width = hsize
+ cur_indent = 0
end
-
+ --
statistics.noflines = statistics.noflines + 1
+ --
+ -- here we could cleanup: remove all if we have (zero) skips only
+ --
local finished_line = nil
if adjust_spacing > 0 then
statistics.nofadjustedlines = statistics.nofadjustedlines + 1
- finished_line = xpack_nodes(q,cur_width,"cal_expand_ratio",par.par_break_dir,par.first_line,current_line) -- ,current_break.analysis)
+ finished_line = xpack_nodes(start,cur_width,"cal_expand_ratio",par.par_break_dir,par.first_line,current_line) -- ,current_break.analysis)
else
- finished_line = xpack_nodes(q,cur_width,"exactly",par.par_break_dir,par.first_line,current_line) -- ,current_break.analysis)
+ finished_line = xpack_nodes(start,cur_width,"exactly",par.par_break_dir,par.first_line,current_line) -- ,current_break.analysis)
end
if protrude_chars > 0 then
statistics.nofprotrudedlines = statistics.nofprotrudedlines + 1
@@ -1451,22 +1663,7 @@ do
local pre_adjust_head = texlists.pre_adjust_head
--
setshift(finished_line,cur_indent)
- --
- -- -- this is gone:
- --
- -- if par.each_line_height ~= ignored_dimen then
- -- setheight(finished_line,par.each_line_height)
- -- end
- -- if par.each_line_depth ~= ignored_dimen then
- -- setdepth(finished_line,par.each_line_depth)
- -- end
- -- if par.first_line_height ~= ignored_dimen and (current_line == par.first_line + 1) then
- -- setheight(finished_line,par.first_line_height)
- -- end
- -- if par.last_line_depth ~= ignored_dimen and current_line + 1 == par.best_line then
- -- setdepth(finished_line,par.last_line_depth)
- -- end
- --
+ --
if texlists.pre_adjust_head ~= pre_adjust_head then
append_list(par, texlists.pre_adjust_head)
texlists.pre_adjust_head = pre_adjust_head
@@ -1502,7 +1699,9 @@ do
end
end
if pen ~= 0 then
- append_to_vlist(par,new_penalty(pen))
+ local p = new_penalty(pen)
+ setattributelist(p,par.head)
+ append_to_vlist(par,p)
end
end
current_line = current_line + 1
@@ -1544,16 +1743,29 @@ do
setlink(head,next)
end
end
+par.head = head
end
-- if current_line ~= par.best_line then
-- report_parbuilders("line breaking")
-- end
- par.head = nil -- needs checking
+ local h = par.head -- hm, head
+ if h then
+ if trace_basic then
+ if getnext(h) then
+ report_parbuilders("something is left over")
+ end
+ if getid(h) ~= localpar_code then
+ report_parbuilders("no local par node")
+ end
+ end
+ flush_node(h)
+ par.head = nil -- needs checking
+ end
current_line = current_line - 1
if trace_basic then
report_parbuilders("paragraph broken into %a lines",current_line)
end
- texnest[texnest.ptr].prevgraf = current_line
+ texset("prevgraf",current_line)
end
local function wrap_up(par)
@@ -1578,10 +1790,14 @@ do
end
end
end
- -- we have a bunch of glue and and temp nodes not freed
+ -- This differs from the engine, where the temp node is removed elsewhere.
local head = par.head
- if getid(head) == temp_code then
- par.head = getnext(head)
+ if head and getid(head) == temp_code then
+ local next = getnext(head)
+ par.head = next
+ if next then
+ setprev(next)
+ end
flush_node(head)
end
post_line_break(par)
@@ -1603,13 +1819,13 @@ do
if prev_r == active then
r = active.next
if r.id == delta_code then
- local aw = active_width.size + r.size active_width.size = aw cur_active_width.size = aw
- local aw = active_width.stretch + r.stretch active_width.stretch = aw cur_active_width.stretch = aw
- local aw = active_width.fi + r.fi active_width.fi = aw cur_active_width.fi = aw
- local aw = active_width.fil + r.fil active_width.fil = aw cur_active_width.fil = aw
- local aw = active_width.fill + r.fill active_width.fill = aw cur_active_width.fill = aw
- local aw = active_width.filll + r.filll active_width.filll = aw cur_active_width.filll = aw
- local aw = active_width.shrink + r.shrink active_width.shrink = aw cur_active_width.shrink = aw
+ local aw = active_width.size + r.size active_width.size = aw cur_active_width.size = aw
+ local aw = active_width.normal + r.normal active_width.normal = aw cur_active_width.normal = aw
+ local aw = active_width.fi + r.fi active_width.fi = aw cur_active_width.fi = aw
+ local aw = active_width.fil + r.fil active_width.fil = aw cur_active_width.fil = aw
+ local aw = active_width.fill + r.fill active_width.fill = aw cur_active_width.fill = aw
+ local aw = active_width.filll + r.filll active_width.filll = aw cur_active_width.filll = aw
+ local aw = active_width.shrink + r.shrink active_width.shrink = aw cur_active_width.shrink = aw
if checked_expansion then
local aw = active_width.adjust_stretch + r.adjust_stretch active_width.adjust_stretch = aw cur_active_width.adjust_stretch = aw
local aw = active_width.adjust_shrink + r.adjust_shrink active_width.adjust_shrink = aw cur_active_width.adjust_shrink = aw
@@ -1621,13 +1837,13 @@ do
elseif prev_r.id == delta_code then
r = prev_r.next
if r == active then
- cur_active_width.size = cur_active_width.size - prev_r.size
- cur_active_width.stretch = cur_active_width.stretch - prev_r.stretch
- cur_active_width.fi = cur_active_width.fi - prev_r.fi
- cur_active_width.fil = cur_active_width.fil - prev_r.fil
- cur_active_width.fill = cur_active_width.fill - prev_r.fill
- cur_active_width.filll = cur_active_width.filll - prev_r.filll
- cur_active_width.shrink = cur_active_width.shrink - prev_r.shrink
+ cur_active_width.size = cur_active_width.size - prev_r.size
+ cur_active_width.normal = cur_active_width.normal - prev_r.normal
+ cur_active_width.fi = cur_active_width.fi - prev_r.fi
+ cur_active_width.fil = cur_active_width.fil - prev_r.fil
+ cur_active_width.fill = cur_active_width.fill - prev_r.fill
+ cur_active_width.filll = cur_active_width.filll - prev_r.filll
+ cur_active_width.shrink = cur_active_width.shrink - prev_r.shrink
if checked_expansion then
cur_active_width.adjust_stretch = cur_active_width.adjust_stretch - prev_r.adjust_stretch
cur_active_width.adjust_shrink = cur_active_width.adjust_shrink - prev_r.adjust_shrink
@@ -1637,13 +1853,13 @@ do
-- prev_r = nil
prev_r = prev_prev_r
elseif r.id == delta_code then
- local rn = r.size cur_active_width.size = cur_active_width.size + rn prev_r.size = prev_r.size + rn
- local rn = r.stretch cur_active_width.stretch = cur_active_width.stretch + rn prev_r.stretch = prev_r.stretch + rn
- local rn = r.fi cur_active_width.fi = cur_active_width.fi + rn prev_r.fi = prev_r.fi + rn
- local rn = r.fil cur_active_width.fil = cur_active_width.fil + rn prev_r.fil = prev_r.fil + rn
- local rn = r.fill cur_active_width.fill = cur_active_width.fill + rn prev_r.fill = prev_r.fill + rn
- local rn = r.filll cur_active_width.filll = cur_active_width.filll + rn prev_r.filll = prev_r.fill + rn
- local rn = r.shrink cur_active_width.shrink = cur_active_width.shrink + rn prev_r.shrink = prev_r.shrink + rn
+ local rn = r.size cur_active_width.size = cur_active_width.size + rn prev_r.size = prev_r.size + rn
+ local rn = r.normal cur_active_width.normal = cur_active_width.normal + rn prev_r.normal = prev_r.normal + rn
+ local rn = r.fi cur_active_width.fi = cur_active_width.fi + rn prev_r.fi = prev_r.fi + rn
+ local rn = r.fil cur_active_width.fil = cur_active_width.fil + rn prev_r.fil = prev_r.fil + rn
+ local rn = r.fill cur_active_width.fill = cur_active_width.fill + rn prev_r.fill = prev_r.fill + rn
+ local rn = r.filll cur_active_width.filll = cur_active_width.filll + rn prev_r.filll = prev_r.fill + rn
+ local rn = r.shrink cur_active_width.shrink = cur_active_width.shrink + rn prev_r.shrink = prev_r.shrink + rn
if checked_expansion then
local rn = r.adjust_stretch cur_active_width.adjust_stretch = cur_active_width.adjust_stretch + rn prev_r.adjust_stretch = prev_r.adjust_stretch + rn
local rn = r.adjust_shrink cur_active_width.adjust_shrink = cur_active_width.adjust_shrink + rn prev_r.adjust_shrink = prev_r.adjust_shrink + rn
@@ -1663,7 +1879,7 @@ do
if cur_active_width.fi ~= fill_width.fi or cur_active_width.fil ~= fill_width.fil or cur_active_width.fill ~= fill_width.fill or cur_active_width.filll ~= fill_width.filll then
return false, 0, fit_decent_class, 0, 0
end
- local adjustment = active_short > 0 and cur_active_width.stretch or cur_active_width.shrink
+ local adjustment = active_short > 0 and cur_active_width.normal or cur_active_width.shrink
if adjustment <= 0 then
return false, 0, fit_decent_class, adjustment, 0
end
@@ -1673,7 +1889,7 @@ do
end
local fit_class = fit_decent_class
if adjustment > 0 then
- local stretch = cur_active_width.stretch
+ local stretch = cur_active_width.normal
if adjustment > shortfall then
adjustment = shortfall
end
@@ -1750,13 +1966,13 @@ do
local tracing_paragraphs = par.tracing_paragraphs
-- local par_active = par.active
- local adapt_width = par.adapt_width
+ -- local adapt_width = par.adapt_width
local parshape = par.par_shape_ptr
local cur_active_width = checked_expansion and { -- distance from current active node
size = active_width.size,
- stretch = active_width.stretch,
+ normal = active_width.normal,
fi = active_width.fi,
fil = active_width.fil,
fill = active_width.fill,
@@ -1766,7 +1982,7 @@ do
adjust_shrink = active_width.adjust_shrink,
} or {
size = active_width.size,
- stretch = active_width.stretch,
+ normal = active_width.normal,
fi = active_width.fi,
fil = active_width.fil,
fill = active_width.fill,
@@ -1777,13 +1993,13 @@ do
while true do
r = prev_r.next
if r.id == delta_code then
- cur_active_width.size = cur_active_width.size + r.size
- cur_active_width.stretch = cur_active_width.stretch + r.stretch
- cur_active_width.fi = cur_active_width.fi + r.fi
- cur_active_width.fil = cur_active_width.fil + r.fil
- cur_active_width.fill = cur_active_width.fill + r.fill
- cur_active_width.filll = cur_active_width.filll + r.filll
- cur_active_width.shrink = cur_active_width.shrink + r.shrink
+ cur_active_width.size = cur_active_width.size + r.size
+ cur_active_width.normal = cur_active_width.normal + r.normal
+ cur_active_width.fi = cur_active_width.fi + r.fi
+ cur_active_width.fil = cur_active_width.fil + r.fil
+ cur_active_width.fill = cur_active_width.fill + r.fill
+ cur_active_width.filll = cur_active_width.filll + r.filll
+ cur_active_width.shrink = cur_active_width.shrink + r.shrink
if checked_expansion then
cur_active_width.adjust_stretch = cur_active_width.adjust_stretch + r.adjust_stretch
cur_active_width.adjust_shrink = cur_active_width.adjust_shrink + r.adjust_shrink
@@ -1797,13 +2013,13 @@ do
if minimum_demerits < awful_badness and (old_line_number ~= par.easy_line or r == par.active) then
if no_break_yet then
no_break_yet = false
- break_width.size = background.size
- break_width.stretch = background.stretch
- break_width.fi = background.fi
- break_width.fil = background.fil
- break_width.fill = background.fill
- break_width.filll = background.filll
- break_width.shrink = background.shrink
+ break_width.size = background.size
+ break_width.normal = background.normal
+ break_width.fi = background.fi
+ break_width.fil = background.fil
+ break_width.fill = background.fill
+ break_width.filll = background.filll
+ break_width.shrink = background.shrink
if checked_expansion then
break_width.adjust_stretch = 0
break_width.adjust_shrink = 0
@@ -1813,25 +2029,25 @@ do
end
end
if prev_r.id == delta_code then
- prev_r.size = prev_r.size - cur_active_width.size + break_width.size
- prev_r.stretch = prev_r.stretch - cur_active_width.stretc + break_width.stretch
- prev_r.fi = prev_r.fi - cur_active_width.fi + break_width.fi
- prev_r.fil = prev_r.fil - cur_active_width.fil + break_width.fil
- prev_r.fill = prev_r.fill - cur_active_width.fill + break_width.fill
- prev_r.filll = prev_r.filll - cur_active_width.filll + break_width.filll
- prev_r.shrink = prev_r.shrink - cur_active_width.shrink + break_width.shrink
+ prev_r.size = prev_r.size - cur_active_width.size + break_width.size
+ prev_r.normal = prev_r.normal - cur_active_width.normal + break_width.normal
+ prev_r.fi = prev_r.fi - cur_active_width.fi + break_width.fi
+ prev_r.fil = prev_r.fil - cur_active_width.fil + break_width.fil
+ prev_r.fill = prev_r.fill - cur_active_width.fill + break_width.fill
+ prev_r.filll = prev_r.filll - cur_active_width.filll + break_width.filll
+ prev_r.shrink = prev_r.shrink - cur_active_width.shrink + break_width.shrink
if checked_expansion then
prev_r.adjust_stretch = prev_r.adjust_stretch - cur_active_width.adjust_stretch + break_width.adjust_stretch
prev_r.adjust_shrink = prev_r.adjust_shrink - cur_active_width.adjust_shrink + break_width.adjust_shrink
end
elseif prev_r == par.active then
- active_width.size = break_width.size
- active_width.stretch = break_width.stretch
- active_width.fi = break_width.fi
- active_width.fil = break_width.fil
- active_width.fill = break_width.fill
- active_width.filll = break_width.filll
- active_width.shrink = break_width.shrink
+ active_width.size = break_width.size
+ active_width.normal = break_width.normal
+ active_width.fi = break_width.fi
+ active_width.fil = break_width.fil
+ active_width.fill = break_width.fill
+ active_width.filll = break_width.filll
+ active_width.shrink = break_width.shrink
if checked_expansion then
active_width.adjust_stretch = break_width.adjust_stretch
active_width.adjust_shrink = break_width.adjust_shrink
@@ -1842,7 +2058,7 @@ do
subtype = nosubtype_code,
next = r,
size = break_width.size - cur_active_width.size,
- stretch = break_width.stretch - cur_active_width.stretch,
+ normal = break_width.normal - cur_active_width.normal,
fi = break_width.fi - cur_active_width.fi,
fil = break_width.fil - cur_active_width.fil,
fill = break_width.fill - cur_active_width.fill,
@@ -1851,16 +2067,16 @@ do
adjust_stretch = break_width.adjust_stretch - cur_active_width.adjust_stretch,
adjust_shrink = break_width.adjust_shrink - cur_active_width.adjust_shrink,
} or {
- id = delta_code,
- subtype = nosubtype_code,
- next = r,
- size = break_width.size - cur_active_width.size,
- stretch = break_width.stretch - cur_active_width.stretch,
- fi = break_width.fi - cur_active_width.fi,
- fil = break_width.fil - cur_active_width.fil,
- fill = break_width.fill - cur_active_width.fill,
- filll = break_width.filll - cur_active_width.filll,
- shrink = break_width.shrink - cur_active_width.shrink,
+ id = delta_code,
+ subtype = nosubtype_code,
+ next = r,
+ size = break_width.size - cur_active_width.size,
+ normal = break_width.normal - cur_active_width.normal,
+ fi = break_width.fi - cur_active_width.fi,
+ fil = break_width.fil - cur_active_width.fil,
+ fill = break_width.fill - cur_active_width.fill,
+ filll = break_width.filll - cur_active_width.filll,
+ shrink = break_width.shrink - cur_active_width.shrink,
}
prev_r.next = q
prev_prev_r = prev_r
@@ -1893,7 +2109,6 @@ do
passive_left_box_width = prev_break and prev_break.passive_last_left_box_width or par.init_internal_left_box_width,
passive_right_box = par.internal_right_box,
passive_right_box_width = par.internal_right_box_width,
- -- analysis = table.fastcopy(cur_active_width),
}
par.passive = passive
local q = {
@@ -1929,7 +2144,7 @@ do
subtype = nosubtype_code,
next = r,
size = cur_active_width.size - break_width.size,
- stretch = cur_active_width.stretch - break_width.stretch,
+ normal = cur_active_width.normal - break_width.normal,
fi = cur_active_width.fi - break_width.fi,
fil = cur_active_width.fil - break_width.fil,
fill = cur_active_width.fill - break_width.fill,
@@ -1938,16 +2153,16 @@ do
adjust_stretch = cur_active_width.adjust_stretch - break_width.adjust_stretch,
adjust_shrink = cur_active_width.adjust_shrink - break_width.adjust_shrink,
} or {
- id = delta_code,
- subtype = nosubtype_code,
- next = r,
- size = cur_active_width.size - break_width.size,
- stretch = cur_active_width.stretch - break_width.stretch,
- fi = cur_active_width.fi - break_width.fi,
- fil = cur_active_width.fil - break_width.fil,
- fill = cur_active_width.fill - break_width.fill,
- filll = cur_active_width.filll - break_width.filll,
- shrink = cur_active_width.shrink - break_width.shrink,
+ id = delta_code,
+ subtype = nosubtype_code,
+ next = r,
+ size = cur_active_width.size - break_width.size,
+ normal = cur_active_width.normal - break_width.normal,
+ fi = cur_active_width.fi - break_width.fi,
+ fil = cur_active_width.fil - break_width.fil,
+ fill = cur_active_width.fill - break_width.fill,
+ filll = cur_active_width.filll - break_width.filll,
+ shrink = cur_active_width.shrink - break_width.shrink,
}
-- q.next = r -- already done
prev_r.next = q
@@ -1971,10 +2186,10 @@ do
line_width = par.first_width
end
end
- if adapt_width then
- local l, r = adapt_width(par,line_number)
- line_width = line_width - l - r
- end
+ -- if adapt_width then
+ -- local l, r = adapt_width(par,line_number)
+ -- line_width = line_width - l - r
+ -- end
end
local artificial_demerits = false -- has d been forced to zero
local shortfall = line_width - cur_active_width.size - par.internal_right_box_width -- used in badness calculations
@@ -1983,69 +2198,53 @@ do
else
shortfall = shortfall - (r.break_node.passive_last_left_box_width or 0)
end
- local pw, lp, rp -- used later on
if protrude_chars > 1 then
- -- this is quite time consuming
- local b = r.break_node
- local l = b and b.cur_break or first_p
- local o = current and getprev(current)
- if current and getid(current) == disc_code then
- local pre, _, _, pretail = getdisc(current,true)
- if pre then
- o = pretail
+ if par.line_break_dir == righttoleft_code then
+ -- not now, we need to keep more track
+ else
+ -- this is quite time consuming
+ local b = r.break_node
+ local l = b and b.cur_break or first_p
+ local o = current and getprev(current)
+ if current and getid(current) == disc_code then
+ local pre, _, _, pretail = getdisc(current,true)
+ if pre then
+ o = pretail
+ else
+ o = find_protchar_right(l,o)
+ end
else
o = find_protchar_right(l,o)
end
- else
- o = find_protchar_right(l,o)
- end
- if o and getid(o) == glyph_code then
- pw, rp = right_pw(o)
- shortfall = shortfall + pw
- end
- local id = getid(l)
- if id == glyph_code then
- -- ok ?
- elseif id == disc_code and getfield(l,"post") then
- l = getfield(l,"post") -- TODO: first char could be a disc
- else
- l = find_protchar_left(l)
- end
- if l and getid(l) == glyph_code then
- pw, lp = left_pw(l)
- shortfall = shortfall + pw
+ if o and getid(o) == glyph_code then
+ shortfall = shortfall + right_pw(o)
+ end
+ local id = getid(l)
+ if id == glyph_code then
+ -- ok ?
+ elseif id == disc_code and getpost(l) then
+ l = getpost(l) -- TODO: first char could be a disc
+ else
+ l = find_protchar_left(l)
+ end
+ if l and getid(l) == glyph_code then
+ shortfall = shortfall + left_pw(l)
+ end
end
end
if checked_expansion and shortfall ~= 0 then
- local margin_kern_stretch = 0
- local margin_kern_shrink = 0
- if protrude_chars > 1 then
- if lp then
- local char, font = isglyph(lp)
- local data = expansions[font][char]
- if data then
- margin_kern_stretch, margin_kern_shrink = data.glyphstretch, data.glyphshrink
- end
- end
- if rp then
- local char, font = isglyph(rp)
- local data = expansions[font][char]
- if data then
- margin_kern_stretch = margin_kern_stretch + data.glyphstretch
- margin_kern_shrink = margin_kern_shrink + data.glyphshrink
+ if shortfall > 0 then
+ local total = cur_active_width.adjust_stretch
+ if total > 0 then
+ if total > shortfall then
+ shortfall = total / (par.max_stretch_ratio / par.cur_font_step) / 2
+ else
+ shortfall = shortfall - total
end
end
- end
- local total = cur_active_width.adjust_stretch + margin_kern_stretch
- if shortfall > 0 and total > 0 then
- if total > shortfall then
- shortfall = total / (par.max_stretch_ratio / par.cur_font_step) / 2
- else
- shortfall = shortfall - total
- end
- else
- total = cur_active_width.adjust_shrink + margin_kern_shrink
- if shortfall < 0 and total > 0 then
+ elseif shortfall < 0 then
+ local total = cur_active_width.adjust_shrink
+ if total > 0 then
if total > - shortfall then
shortfall = - total / (par.max_shrink_ratio / par.cur_font_step) / 2
else
@@ -2068,7 +2267,7 @@ do
shortfall = 0
end
else
- local stretch = cur_active_width.stretch
+ local stretch = cur_active_width.normal
if shortfall > 7230584 and stretch < 1663497 then
b = infinite_badness
fit_class = fit_very_loose_class
@@ -2101,7 +2300,7 @@ do
-- g = 0
shortfall = 0
elseif shortfall > 0 then
- g = cur_active_width.stretch
+ g = cur_active_width.normal
elseif shortfall < 0 then
g = cur_active_width.shrink
else
@@ -2192,7 +2391,6 @@ do
if trace_basic then
report_parbuilders("starting at %a",head)
end
-
local par = initialize_line_break(head,d)
local checked_expansion = par.checked_expansion
@@ -2200,8 +2398,9 @@ do
local disc_width = par.disc_width
local background = par.background
local tracing_paragraphs = par.tracing_paragraphs
+ local dirstack = { n = 0 }
- local dirstack = new_dir_stack()
+ par.dirstack = dirstack
if tracing_paragraphs then
diagnostics.start()
@@ -2225,13 +2424,13 @@ do
active_short = 0,
active_glue = 0,
}
- active_width.size = background.size
- active_width.stretch = background.stretch
- active_width.fi = background.fi
- active_width.fil = background.fil
- active_width.fill = background.fill
- active_width.filll = background.filll
- active_width.shrink = background.shrink
+ active_width.size = background.size
+ active_width.normal = background.normal
+ active_width.fi = background.fi
+ active_width.fil = background.fil
+ active_width.fill = background.fill
+ active_width.filll = background.filll
+ active_width.shrink = background.shrink
if checked_expansion then
active_width.adjust_stretch = 0
@@ -2241,13 +2440,12 @@ do
par.passive = nil -- = 0
par.printed_node = temp_head -- only when tracing, shared
par.pass_number = 0
- -- par.auto_breaking = true
+ -- par.auto_breaking = true
setnext(temp_head,head)
local current = head
local first_p = current
-
local auto_breaking = true
par.font_in_short_display = 0
@@ -2288,12 +2486,7 @@ do
while current and p_active ~= n_active do
local char, id = isglyph(current)
if char then
- local wd, ht, dp = getwhd(current)
- if is_rotated(par.line_break_dir) then
- active_width.size = active_width.size + ht + dp
- else
- active_width.size = active_width.size + wd
- end
+ active_width.size = active_width.size + getwidth(current)
if checked_expansion then
local font = id -- == font
local data = checked_expansion[font]
@@ -2312,44 +2505,15 @@ do
end
end
elseif id == hlist_code or id == vlist_code then
- local wd, ht, dp = getwhd(current)
- if textdir_parallel(getdirection(current),par.line_break_dir) then
- active_width.size = active_width.size + wd
- else
- active_width.size = active_width.size + ht + dp
- end
+ active_width.size = active_width.size + getwidth(current)
elseif id == glue_code then
- -- if par.auto_breaking then
- if auto_breaking then
- local prev_p = getprev(current)
- if prev_p and prev_p ~= temp_head then
- local id = getid(prev_p)
- -- we need to check this with the latest patches to the tex kernel
- if (id == glyph_code) or (id < math_code) then
- p_active, n_active = try_break(0, unhyphenated_code, par, first_p, current, checked_expansion)
- elseif id == kern_code then
- local s = getsubtype(prev_p)
- if s ~= userkern_code and s ~= italickern_code then
- p_active, n_active = try_break(0, unhyphenated_code, par, first_p, current, checked_expansion)
- end
- end
- end
- end
- check_shrinkage(par,current)
- local width, stretch, shrink, stretch_order = getglue(current)
- local order = fillcodes[stretch_order]
- active_width.size = active_width.size + width
- active_width[order] = active_width[order] + stretch
- active_width.shrink = active_width.shrink + shrink
+ goto glue
elseif id == disc_code then
local subtype = getsubtype(current)
if subtype ~= seconddisc_code then
local line_break_dir = par.line_break_dir
if second_pass or subtype <= automaticdisc_code then
- local actual_pen = subtype == automaticdisc_code and par.ex_hyphen_penalty or par.hyphen_penalty
- -- 0.81 :
- -- local actual_pen = getpenalty(current)
- --
+ local actual_pen = getpenalty(current)
local pre, post, replace = getdisc(current)
if not pre then -- trivial pre-break
disc_width.size = 0
@@ -2377,7 +2541,7 @@ do
if getid(cur_p_next) ~= disc_code or getsubtype(cur_p_next) ~= seconddisc_code then
report_parbuilders("unsupported disc at location %a",1)
else
- local pre = getfield(cur_p_next,"pre")
+ local pre = getpre(cur_p_next)
if pre then
local size, adjust_stretch, adjust_shrink = add_to_width(line_break_dir,checked_expansion,pre)
disc_width.size = disc_width.size + size
@@ -2386,16 +2550,7 @@ do
disc_width.adjust_shrink = disc_width.adjust_shrink + adjust_shrink
end
p_active, n_active = try_break(actual_pen, hyphenated_code, par, first_p, cur_p_next, checked_expansion)
- --
- -- I will look into this some day ... comment in linebreak.w says that this fails,
- -- maybe this is what Taco means with his comment in the luatex manual.
- --
- -- do_one_seven_eight(sub_disc_width_from_active_width);
- -- do_one_seven_eight(reset_disc_width);
- -- s = vlink_no_break(vlink(current));
- -- add_to_widths(s, line_break_dir, adjust_spacing,disc_width);
- -- ext_try_break(...,first_p,vlink(current));
- --
+ -- there is a comment about something messy here in the source
else
report_parbuilders("unsupported disc at location %a",2)
end
@@ -2420,49 +2575,46 @@ do
end
elseif id == kern_code then
local s = getsubtype(current)
+ local kern = getkern(current)
if s == userkern_code or s == italickern_code then
local v = getnext(current)
- -- if par.auto_breaking and getid(v) == glue_code then
if auto_breaking and getid(v) == glue_code then
p_active, n_active = try_break(0, unhyphenated_code, par, first_p, current, checked_expansion)
end
local active_width = par.active_width
- active_width.size = active_width.size + getkern(current)
- else
- local kern = getkern(current)
- if kern ~= 0 then
- active_width.size = active_width.size + kern
- if checked_expansion and expand_kerns and getsubtype(current) == fontkern_code then
- local stretch, shrink = kern_stretch_shrink(current,kern)
- if expand_kerns == "stretch" then
- active_width.adjust_stretch = active_width.adjust_stretch + stretch
- elseif expand_kerns == "shrink" then
- active_width.adjust_shrink = active_width.adjust_shrink + shrink
- else
- active_width.adjust_stretch = active_width.adjust_stretch + stretch
- active_width.adjust_shrink = active_width.adjust_shrink + shrink
- end
+ active_width.size = active_width.size + kern
+ elseif kern ~= 0 then
+ active_width.size = active_width.size + kern
+ if checked_expansion and expand_kerns and s == fontkern_code then
+ local stretch, shrink = kern_stretch_shrink(current,kern)
+ if expand_kerns == "stretch" then
+ active_width.adjust_stretch = active_width.adjust_stretch + stretch
+ elseif expand_kerns == "shrink" then
+ active_width.adjust_shrink = active_width.adjust_shrink + shrink
+ else
+ active_width.adjust_stretch = active_width.adjust_stretch + stretch
+ active_width.adjust_shrink = active_width.adjust_shrink + shrink
end
end
end
elseif id == math_code then
- -- par.auto_breaking = getsubtype(current) == endmath_code
auto_breaking = getsubtype(current) == endmath_code
- local v = getnext(current)
- -- if par.auto_breaking and getid(v) == glue_code then
- if auto_breaking and getid(v) == glue_code then
- p_active, n_active = try_break(0, unhyphenated_code, par, first_p, current, checked_expansion)
+ if is_zero_glue(current) or ignore_math_skip(current) then
+ local v = getnext(current)
+ if auto_breaking and getid(v) == glue_code then
+ p_active, n_active = try_break(0, unhyphenated_code, par, first_p, current, checked_expansion)
+ end
+ local active_width = par.active_width
+ active_width.size = active_width.size + getkern(current) + getwidth(current)
+ else
+ goto glue
end
- local active_width = par.active_width
- active_width.size = active_width.size + getkern(current) -- surround
- -- new in luatex
- + getwidth(current)
elseif id == rule_code then
active_width.size = active_width.size + getwidth(current)
elseif id == penalty_code then
p_active, n_active = try_break(getpenalty(current), unhyphenated_code, par, first_p, current, checked_expansion)
elseif id == dir_code then
- par.line_break_dir = checked_line_dir(dirstack) or par.line_break_dir
+ par.line_break_dir = checked_line_dir(dirstack,current) or par.line_break_dir
elseif id == localpar_code then
par.internal_pen_inter = getfield(current,"pen_inter")
par.internal_pen_broken = getfield(current,"pen_broken")
@@ -2477,6 +2629,35 @@ do
report_parbuilders("node of type %a found in paragraph",type(id))
end
end
+ goto done
+ ::glue::
+ do
+ if auto_breaking then
+ local prev_p = getprev(current)
+ if prev_p and prev_p ~= temp_head then
+ local id = getid(prev_p)
+ -- we need to check this with the latest patches to the tex kernel
+ if (id == glyph_code) or (id < math_code) then
+ p_active, n_active = try_break(0, unhyphenated_code, par, first_p, current, checked_expansion)
+ elseif id == kern_code then
+ local s = getsubtype(prev_p)
+ if s ~= userkern_code and s ~= italickern_code then
+ p_active, n_active = try_break(0, unhyphenated_code, par, first_p, current, checked_expansion)
+ end
+ end
+ end
+ end
+ local width, stretch, shrink, stretch_order, shrink_order = getglue(current)
+ if shrink_order ~= 0 and shrink ~= 0 then
+ infinite_shrinkage_error(par)
+ shrink_order = 0
+ end
+ local order = fillcodes[stretch_order]
+ active_width.size = active_width.size + width
+ active_width[order] = active_width[order] + stretch
+ active_width.shrink = active_width.shrink + shrink
+ end
+ ::done::
current = getnext(current)
end
if not current then
@@ -2533,8 +2714,8 @@ do
if tracing_paragraphs then
diagnostics.current_pass(par,"emergencypass")
end
- par.background.stretch = par.background.stretch + par.emergency_stretch
- par.final_pass = true
+ par.background.normal = par.background.normal + par.emergency_stretch
+ par.final_pass = true
end
end
return wrap_up(par)
@@ -2546,8 +2727,14 @@ end
do
+ local tonumber = tonumber
+ local utfchar = utf.char
+ local write = texio.write
+ local write_nl = texio.write_nl
+ local formatters = string.formatters
+
local function write_esc(cs)
- local esc = tex.escapechar
+ local esc = texget("escapechar")
if esc then
write("log",utfchar(esc),cs)
else
@@ -2623,13 +2810,13 @@ do
local passive = par.passive
local typ_ind = break_type == hyphenated_code and '-' or ""
if par.do_last_line_fit then
- local s = number.toscaled(q.active_short)
- local g = number.toscaled(q.active_glue)
+ local s = q.active_short
+ local g = q.active_glue
if current then
- write_nl("log",formatters["@@%d: line %d.%d%s t=%s s=%s g=%s"](
+ write_nl("log",formatters["@@%d: line %d.%d%s t=%s s=%p g=%p"](
passive.serial or 0,q.line_number-1,fit_class,typ_ind,q.total_demerits,s,g))
else
- write_nl("log",formatters["@@%d: line %d.%d%s t=%s s=%s a=%s"](
+ write_nl("log",formatters["@@%d: line %d.%d%s t=%s s=%p a=%p"](
passive.serial or 0,q.line_number-1,fit_class,typ_ind,q.total_demerits,s,g))
end
else
@@ -2716,7 +2903,7 @@ do
end
function diagnostics.overfull_hbox(hlist,line,d)
- common_message(hlist,line,formatters["Overfull \\hbox (%spt too wide)"](number.toscaled(d)))
+ common_message(hlist,line,formatters["Overfull \\hbox (%p too wide)"](d))
end
function diagnostics.bad_hbox(hlist,line,b)
@@ -2731,15 +2918,15 @@ do
common_message(hlist,line,formatters["Loose \\hbox (badness %i)"](b))
end
-end
+ -- reporting --
--- reporting --
+ statistics.register("alternative parbuilders", function()
+ if nofpars > 0 then
+ return formatters["%s paragraphs, %s lines (%s protruded, %s adjusted)"](nofpars,noflines,nofprotrudedlines,nofadjustedlines)
+ end
+ end)
-statistics.register("alternative parbuilders", function()
- if nofpars > 0 then
- return formatters["%s paragraphs, %s lines (%s protruded, %s adjusted)"](nofpars,noflines,nofprotrudedlines,nofadjustedlines)
- end
-end)
+end
do
@@ -2757,126 +2944,6 @@ do
local setnodecolor = nodes.tracers.colors.set
- -- local function xpack(head,width,method,direction,analysis)
- --
- -- -- inspect(analysis)
- --
- -- local expansion = method == "cal_expand_ratio"
- -- local natural = analysis.size
- -- local font_stretch = analysis.adjust_stretch
- -- local font_shrink = analysis.adjust_shrink
- -- local font_expand_ratio = 0
- -- local delta = width - natural
- --
- -- local hlist = new_hlist()
- --
- -- setlist(hlist,head)
- -- setdirection(hlist,direction or tex.textdirection)
- -- setwhd(hlist,width,height,depth)
- --
- -- if delta == 0 then
- --
- -- setfield(hlist,"glue_sign",0)
- -- setfield(hlist,"glue_order",0)
- -- setfield(hlist,"glue_set",0)
- --
- -- else
- --
- -- local order = analysis.filll ~= 0 and fillcodes.filll or
- -- analysis.fill ~= 0 and fillcodes.fill or
- -- analysis.fil ~= 0 and fillcodes.fil or
- -- analysis.fi ~= 0 and fillcodes.fi or 0
- --
- -- if delta > 0 then
- --
- -- if expansion and order == 0 and font_stretch > 0 then
- -- font_expand_ratio = (delta/font_stretch) * 1000
- -- else
- -- local stretch = analysis.stretch
- -- if stretch ~= 0 then
- -- setfield(hlist,"glue_sign",1) -- stretch
- -- setfield(hlist,"glue_order",order)
- -- setfield(hlist,"glue_set",delta/stretch)
- -- else
- -- setfield(hlist,"glue_sign",0) -- nothing
- -- setfield(hlist,"glue_order",order)
- -- setfield(hlist,"glue_set",0)
- -- end
- -- end
- --
- -- else
- --
- -- if expansion and order == 0 and font_shrink > 0 then
- -- font_expand_ratio = (delta/font_shrink) * 1000
- -- else
- -- local shrink = analysis.shrink
- -- if shrink ~= 0 then
- -- setfield(hlist,"glue_sign",2) -- shrink
- -- setfield(hlist,"glue_order",order)
- -- setfield(hlist,"glue_set",-delta/stretch)
- -- else
- -- setfield(hlist,"glue_sign",0) -- nothing
- -- setfield(hlist,"glue_order",order)
- -- setfield(hlist,"glue_set",0)
- -- end
- -- end
- --
- -- end
- --
- -- end
- --
- -- if not expansion or font_expand_ratio == 0 then
- -- -- nothing
- -- elseif font_expand_ratio > 0 then
- -- if font_expand_ratio > 1000 then
- -- font_expand_ratio = 1000
- -- end
- -- local current = head
- -- while current do
- -- local id = getid(current)
- -- if id == glyph_code then
- -- local stretch, shrink = char_stretch_shrink(current) -- get only one
- -- if stretch then
- -- if trace_expansion then
- -- setnodecolor(g,"hz:positive")
- -- end
- -- current.expansion_factor = font_expand_ratio * stretch
- -- end
- -- elseif id == kern_code then
- -- local kern = getkern(current)
- -- if kern ~= 0 and getsubtype(current) == fontkern_code then
- -- setkern(current,font_expand_ratio * kern)
- -- end
- -- end
- -- current = getnext(current)
- -- end
- -- elseif font_expand_ratio < 0 then
- -- if font_expand_ratio < -1000 then
- -- font_expand_ratio = -1000
- -- end
- -- local current = head
- -- while current do
- -- local id = getid(current)
- -- if id == glyph_code then
- -- local stretch, shrink = char_stretch_shrink(current) -- get only one
- -- if shrink then
- -- if trace_expansion then
- -- setnodecolor(g,"hz:negative")
- -- end
- -- current.expansion_factor = font_expand_ratio * shrink
- -- end
- -- elseif id == kern_code then
- -- local kern = getkern(current)
- -- if kern ~= 0 and getsubtype(current) == fontkern_code then
- -- setkern(current,font_expand_ratio * kern)
- -- end
- -- end
- -- current = getnext(current)
- -- end
- -- end
- -- return hlist, 0
- -- end
-
local function hpack(head,width,method,direction,firstline,line) -- fast version when head = nil
-- we can pass the adjust_width and adjust_height so that we don't need to recalculate them but
@@ -2885,6 +2952,7 @@ do
local hlist = new_hlist()
setdirection(hlist,direction)
+ setattributelist(hlist,head)
if head == nil then
setwidth(hlist,width)
@@ -2895,7 +2963,7 @@ do
local cal_expand_ratio = method == "cal_expand_ratio" or method == "subst_ex_font"
- direction = direction or tex.textdir
+ direction = direction or texget("textdir")
local line = 0
@@ -2915,10 +2983,8 @@ do
local adjust_head = texlists.adjust_head
local pre_adjust_head = texlists.pre_adjust_head
- local adjust_tail = adjust_head and slide_node_list(adjust_head) -- todo: find_tail
- local pre_adjust_tail = pre_adjust_head and slide_node_list(pre_adjust_head) -- todo: find_tail
-
- new_dir_stack(hpack_dir)
+ local adjust_tail = adjust_head and find_tail(adjust_head)
+ local pre_adjust_tail = pre_adjust_head and find_tail(pre_adjust_head)
local checked_expansion = false
@@ -2929,10 +2995,11 @@ do
-- this one also needs to check the font, so in the end indeed we might end up with two variants
+ -- we now have fast loops so maybe no longer a need for an expansion stack
+
local fontexps, lastfont
local function process(current) -- called nested in disc replace
-
while current do
local char, id = isglyph(current)
if char then
@@ -2952,20 +3019,19 @@ do
end
end
end
- -- use inline
local wd, ht, dp = getwhd(current)
- natural = natural + wd
if ht > height then
height = ht
end
if dp > depth then
depth = dp
end
+ natural = natural + wd
elseif id == kern_code then
local kern = getkern(current)
if kern == 0 then
-- no kern
- elseif getsubtype(current) == fontkern_code then -- check getkern(p)
+ elseif getsubtype(current) == fontkern_code then
if cal_expand_ratio then
local stretch, shrink = kern_stretch_shrink(current,kern)
font_stretch = font_stretch + stretch
@@ -2981,19 +3047,18 @@ do
local subtype = getsubtype(current)
if subtype ~= seconddisc_code then
-- todo : local stretch, shrink = char_stretch_shrink(s)
- local replace = getfield(current,"replace")
+ local replace = getreplace(current)
if replace then
process(replace)
end
end
elseif id == glue_code then
local wd, stretch, shrink, stretch_order, shrink_order = getglue(current)
- natural = natural + wd
total_stretch[stretch_order] = total_stretch[stretch_order] + stretch
total_shrink [shrink_order] = total_shrink[shrink_order] + shrink
if getsubtype(current) >= leaders_code then
+ local wd, ht, dp = getwhd(leader)
local leader = getleader(current)
- local wd, ht, dp = getwhd(leader) -- can become getwhd(current) after 1.003
if ht > height then
height = ht
end
@@ -3001,41 +3066,36 @@ do
depth = dp
end
end
+ natural = natural + wd
elseif id == hlist_code or id == vlist_code then
- local sh = getshift(current)
local wd, ht, dp = getwhd(current)
- local hs, ds = ht - sh, dp + sh
- natural = natural + wd
+ local sh = getshift(current)
+ local hs = ht - sh
+ local ds = dp + sh
if hs > height then
height = hs
end
if ds > depth then
depth = ds
end
- elseif id == rule_code then
- local wd, ht, dp = getwhd(current)
natural = natural + wd
+ elseif id == rule_code or id == unset_code then
+ local wd, ht, dp = getwhd(current)
if ht > height then
height = ht
end
if dp > depth then
depth = dp
end
- elseif id == math_code then
- natural = natural + getkern(current) -- surround
- -- new in luatex
- + getwidth(current)
- elseif id == unset_code then
- local wd, ht, dp = getwhd(current)
- local sh = getshift(current)
- local hs = ht - sh
- local ds = dp + sh
natural = natural + wd
- if hs > height then
- height = hs
- end
- if ds > depth then
- depth = ds
+ elseif id == math_code then
+ if is_zero_glue(current) or ignore_math_skip(current) then
+ natural = natural + getkern(current)
+ else
+ local wd, stretch, shrink, stretch_order, shrink_order = getglue(current)
+ total_stretch[stretch_order] = total_stretch[stretch_order] + stretch
+ total_shrink [shrink_order] = total_shrink[shrink_order] + shrink
+ natural = natural + wd
end
elseif id == ins_code or id == mark_code then
local prev, next = getboth(current)
@@ -3056,21 +3116,11 @@ do
else
adjust_head = list
end
- adjust_tail = slide_node_list(list) -- find_tail(list)
+ adjust_tail = find_tail(list)
elseif id == dir_code then
- hpack_dir = checked_line_dir(stack,current) or hpack_dir
+ -- no need to deal with directions here (as we only support two)
elseif id == marginkern_code then
- local width = getwidth(current)
- if cal_expand_ratio then
- -- is this ok?
- local glyph = getfield(current,"glyph")
- local char_pw = getsubtype(current) == leftmargin_code and left_pw or right_pw
- font_stretch = font_stretch - width - char_pw(glyph)
- font_shrink = font_shrink - width - char_pw(glyph)
- expansion_index = expansion_index + 1
- expansion_stack[expansion_index] = glyph
- end
- natural = natural + width
+ natural = natural + getwidth(current)
end
current = getnext(current)
end
@@ -3088,25 +3138,21 @@ do
if method == "additional" then
width = width + natural
end
-
setwhd(hlist,width,height,depth)
-
local delta = width - natural
if delta == 0 then
- setfield(hlist,"glue_sign",0)
- setfield(hlist,"glue_order",0)
- setfield(hlist,"glue_set",0)
+ setglue(hlist,0,0,0) -- set order sign
elseif delta > 0 then
-- natural width smaller than requested width
- local order = (total_stretch[4] ~= 0 and 4 or total_stretch[3] ~= 0 and 3) or
- (total_stretch[2] ~= 0 and 2 or total_stretch[1] ~= 0 and 1) or 0
+ local order = (total_stretch[4] ~= 0 and 4) or (total_stretch[3] ~= 0 and 3) or
+ (total_stretch[2] ~= 0 and 2) or (total_stretch[1] ~= 0 and 1) or 0
if cal_expand_ratio and order == 0 and font_stretch > 0 then -- check sign of font_stretch
font_expand_ratio = delta/font_stretch
-
if font_expand_ratio > 1 then
font_expand_ratio = 1
+ elseif font_expand_ratio < -1 then
+ font_expand_ratio = -1
end
-
local fontexps, lastfont
for i=1,expansion_index do
local g = expansion_stack[i]
@@ -3118,33 +3164,33 @@ do
lastfont = font
end
local data = fontexps[char]
- if trace_expansion then
- setnodecolor(g,"hz:positive")
+ if data then
+ if trace_expansion then
+ setnodecolor(g,"hz:positive")
+ end
+ e = font_expand_ratio * data.glyphstretch
end
- e = font_expand_ratio * data.glyphstretch / 1000
else
local kern = getkern(g)
local stretch, shrink = kern_stretch_shrink(g,kern)
- e = font_expand_ratio * stretch / 1000
+ e = font_expand_ratio * stretch
end
setexpansion(g,e)
end
+ font_stretch = font_expand_ratio * font_stretch
+ delta = delta - font_stretch
end
local tso = total_stretch[order]
if tso ~= 0 then
- setfield(hlist,"glue_sign",1)
- setfield(hlist,"glue_order",order)
- setfield(hlist,"glue_set",delta/tso)
+ setglue(hlist,delta/tso,order,1) -- set order sign
else
- setfield(hlist,"glue_sign",0)
- setfield(hlist,"glue_order",order)
- setfield(hlist,"glue_set",0)
+ setglue(hlist,0,order,0) -- set order sign
end
if font_expand_ratio ~= 0 then
-- todo
elseif order == 0 then -- and getlist(hlist) then
last_badness = calculate_badness(delta,total_stretch[0])
- if last_badness > tex.hbadness then
+ if last_badness > texget("hbadness") then
if last_badness > 100 then
diagnostics.underfull_hbox(hlist,line,last_badness)
else
@@ -3154,15 +3200,15 @@ do
end
else
-- natural width larger than requested width
- local order = total_shrink[4] ~= 0 and 4 or total_shrink[3] ~= 0 and 3
- or total_shrink[2] ~= 0 and 2 or total_shrink[1] ~= 0 and 1 or 0
+ local order = (total_shrink[4] ~= 0 and 4) or (total_shrink[3] ~= 0 and 3)
+ or (total_shrink[2] ~= 0 and 2) or (total_shrink[1] ~= 0 and 1) or 0
if cal_expand_ratio and order == 0 and font_shrink > 0 then -- check sign of font_shrink
font_expand_ratio = delta/font_shrink
-
- if font_expand_ratio < 1 then
+ if font_expand_ratio > 1 then
+ font_expand_ratio = 1
+ elseif font_expand_ratio < -1 then
font_expand_ratio = -1
end
-
local fontexps, lastfont
for i=1,expansion_index do
local g = expansion_stack[i]
@@ -3174,44 +3220,62 @@ do
lastfont = font
end
local data = fontexps[char]
- if trace_expansion then
- setnodecolor(g,"hz:negative")
+ if data then
+ if trace_expansion then
+ setnodecolor(g,"hz:negative")
+ end
+ e = font_expand_ratio * data.glyphshrink
end
- e = font_expand_ratio * data.glyphshrink / 1000
else
local kern = getkern(g)
local stretch, shrink = kern_stretch_shrink(g,kern)
- e = font_expand_ratio * shrink / 1000
+ e = font_expand_ratio * shrink
end
setexpansion(g,e)
end
+ font_shrink = font_expand_ratio * font_shrink
+ delta = delta - font_shrink
end
local tso = total_shrink[order]
if tso ~= 0 then
- setfield(hlist,"glue_sign",2)
- setfield(hlist,"glue_order",order)
- setfield(hlist,"glue_set",-delta/tso)
+ setglue(hlist,-delta/tso,order,2) -- set order sign
else
- setfield(hlist,"glue_sign",0)
- setfield(hlist,"glue_order",order)
- setfield(hlist,"glue_set",0)
+ setglue(hlist,0,order,0) -- set order sign
end
if font_expand_ratio ~= 0 then
-- todo
- elseif tso < -delta and order == 0 then -- and getlist(hlist) then
+ elseif tso < -delta and order == 0 then
last_badness = 1000000
setfield(hlist,"glue_set",1)
- local fuzz = - delta - total_shrink[0]
- local hfuzz = tex.hfuzz
- if fuzz > hfuzz or tex.hbadness < 100 then
- local overfullrule = tex.overfullrule
+ local fuzz = - delta - tso
+ local hfuzz = texget("hfuzz")
+ if fuzz > hfuzz or texget("hbadness") < 100 then
+ local overfullrule = texget("overfullrule")
if fuzz > hfuzz and overfullrule > 0 then
-- weird, is always called and no rules shows up
- setnext(slide_node_list(list),new_rule(overfullrule,nil,nil,getdirection(hlist))) -- todo: find_tail
+ setnext(find_tail(list),new_rule(overfullrule,nil,nil,getdirection(hlist)))
+ end
+ diagnostics.overfull_hbox(hlist,line,fuzz)
+ if head and getnormalizeline() > 4 then
+ -- we need to get rid of this one when we unpack a box but on the
+ -- other hand, we only do this when a specific width is set so
+ -- probably we have a fixed box then
+ local h = getnext(head)
+ if h then
+ local found = find_node(glue_code,rightskip_code)
+ if found then
+ local p = getprev(found)
+ local g = new_correctionskip(-fuzz)
+ setattributelist(g,found)
+ if p and getid(p) == marginkern_code then
+ found = p
+ end
+ insert_node_before(head,found,g)
+ end
+ end
end
- diagnostics.overfull_hbox(hlist,line,-delta)
end
- elseif order == 0 and getlist(hlist) and last_badness > tex.hbadness then
+ elseif order == 0 and getlist(hlist) and last_badness > texget("hbadness") then
diagnostics.bad_hbox(hlist,line,last_badness)
end
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/node-met.lua b/Master/texmf-dist/tex/context/base/mkiv/node-met.lua
index 574c71f60fd..db079c11628 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/node-met.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/node-met.lua
@@ -322,19 +322,6 @@ function nodes.concat(list) -- consider tail instead of slide
return head, tail
end
---[[
-<p>At some point we ran into a problem that the glue specification
-of the zeropoint dimension was overwritten when adapting a glue spec
-node. This is a side effect of glue specs being shared. After a
-couple of hours tracing and debugging Taco and I came to the
-conclusion that it made no sense to complicate the spec allocator
-and settled on a writable flag. This all is a side effect of the
-fact that some glues use reserved memory slots (with the zeropoint
-glue being a noticeable one). So, next we wrap this into a function
-and hide it for the user. And yes, LuaTeX now gives a warning as
-well.</p>
-]]--
-
function nodes.reference(n)
return n and tonut(n) or "<none>"
end
@@ -601,8 +588,7 @@ local keys = { whatsit = whatsitkeys }
local messyhack = table.tohash { -- temporary solution
nodecodes.attributelist,
nodecodes.attribute,
- nodecodes.gluespec,
- nodecodes.action,
+ nodecodes.action, -- hm
}
setmetatableindex(keys,function(t,k)
@@ -643,3 +629,233 @@ end
nodes.keys = keys -- [id][subtype]
nodes.fields = nodefields -- (n)
+
+if not nodes.count then
+
+ local type = type
+
+ local direct = node.direct
+ local todirect = direct.tovaliddirect
+ local tonode = direct.tonode
+
+ local count = direct.count
+ local length = direct.length
+ local slide = direct.slide
+
+ function node.count(id,first,last)
+ return count(id,first and todirect(first), last and todirect(last) or nil)
+ end
+
+ function node.length(first,last)
+ return length(first and todirect(first), last and todirect(last) or nil)
+ end
+
+ function node.slide(n)
+ if n then
+ n = slide(todirect(n))
+ if n then
+ return tonode(n)
+ end
+ end
+ return nil
+ end
+
+ local hyphenating = direct.hyphenating
+ local ligaturing = direct.ligaturing
+ local kerning = direct.kerning
+
+ -- kind of inconsistent
+
+ function node.hyphenating(first,last)
+ if first then
+ local h, t = hyphenating(todirect(first), last and todirect(last) or nil)
+ return h and tonode(h) or nil, t and tonode(t) or nil, true
+ else
+ return nil, false
+ end
+ end
+
+ function node.ligaturing(first,last)
+ if first then
+ local h, t = ligaturing(todirect(first), last and todirect(last) or nil)
+ return h and tonode(h) or nil, t and tonode(t) or nil, true
+ else
+ return nil, false
+ end
+ end
+
+ function node.kerning(first,last)
+ if first then
+ local h, t = kerning(todirect(first), last and todirect(last) or nil)
+ return h and tonode(h) or nil, t and tonode(t) or nil, true
+ else
+ return nil, false
+ end
+ end
+
+ local protect_glyph = direct.protect_glyph
+ local unprotect_glyph = direct.unprotect_glyph
+ local protect_glyphs = direct.protect_glyphs
+ local unprotect_glyphs = direct.unprotect_glyphs
+
+ function node.protect_glyphs(first,last)
+ protect_glyphs(todirect(first), last and todirect(last) or nil)
+ end
+
+ function node.unprotect_glyphs(first,last)
+ unprotect_glyphs(todirect(first), last and todirect(last) or nil)
+ end
+
+ function node.protect_glyph(first)
+ protect_glyph(todirect(first))
+ end
+
+ function node.unprotect_glyph(first)
+ unprotect_glyph(todirect(first))
+ end
+
+ local flatten_discretionaries = direct.flatten_discretionaries
+ local check_discretionaries = direct.check_discretionaries
+ local check_discretionary = direct.check_discretionary
+
+ function node.flatten_discretionaries(first)
+ local h, count = flatten_discretionaries(todirect(first))
+ return tonode(h), count
+ end
+
+ function node.check_discretionaries(n)
+ check_discretionaries(todirect(n))
+ end
+
+ function node.check_discretionary(n)
+ check_discretionary(todirect(n))
+ end
+
+ local hpack = direct.hpack
+ local vpack = direct.vpack
+ local list_to_hlist = direct.mlist_to_hlist
+
+ function node.hpack(head,...)
+ local h, badness = hpack(head and todirect(head) or nil,...)
+ return tonode(h), badness
+ end
+
+ function node.vpack(head,...)
+ local h, badness = vpack(head and todirect(head) or nil,...)
+ return tonode(h), badness
+ end
+
+ function node.mlist_to_hlist(head,...)
+ return tonode(mlist_to_hlist(head and todirect(head) or nil,...))
+ end
+
+ local end_of_math = direct.end_of_math
+ local find_attribute = direct.find_attribute
+ local first_glyph = direct.first_glyph
+
+ function node.end_of_math(n)
+ if n then
+ n = end_of_math(todirect(n))
+ if n then
+ return tonode(n)
+ end
+ end
+ return nil
+ end
+
+ function node.find_attribute(n,a)
+ if n then
+ local v, n = find_attribute(todirect(n),a)
+ if n then
+ return v, tonode(n)
+ end
+ end
+ return nil
+ end
+
+ function node.first_glyph(first,last)
+ local n = first_glyph(todirect(first), last and todirect(last) or nil)
+ return n and tonode(n) or nil
+ end
+
+ local dimensions = direct.dimensions
+ local rangedimensions = direct.rangedimensions
+ local effective_glue = direct.effective_glue
+
+ function node.dimensions(a,b,c,d,e)
+ if type(a) == "userdata" then
+ a = todirect(a)
+ if type(b) == "userdata" then
+ b = todirect(b)
+ end
+ return dimensions(a,b)
+ else
+ d = todirect(d)
+ if type(e) == "userdata" then
+ e = todirect(e)
+ end
+ return dimensions(a,b,c,d,e)
+ end
+ return 0, 0, 0
+ end
+
+ function node.rangedimensions(parent,first,last)
+ return rangedimenensions(todirect(parent),todirect(first),last and todirect(last))
+ end
+
+ function node.effective_glue(list,parent)
+ return effective_glue(list and todirect(list) or nil,parent and todirect(parent) or nil)
+ end
+
+ local uses_font = direct.uses_font
+ local has_glyph = direct.has_glyph
+ local protrusion_skippable = direct.protrusion_skippable
+ local prepend_prevdepth = direct.prepend_prevdepth
+ local make_extensible = direct.make_extensible
+
+ function node.uses_font(n,f)
+ return uses_font(todirect(n),f)
+ end
+
+ function node.has_glyph(n)
+ return has_glyph(todirect(n))
+ end
+
+ function node.protrusion_skippable(n)
+ return protrusion_skippable(todirect(n))
+ end
+
+ function node.prepend_prevdepth(n)
+ local n, d = prepend_prevdepth(todirect(n))
+ return tonode(n), d
+ end
+
+ function node.make_extensible(...)
+ local n = make_extensible(...)
+ return n and tonode(n) or nil
+ end
+
+ local last_node = direct.last_node
+
+ function node.last_node()
+ local n = last_node()
+ return n and tonode(n) or nil
+ end
+
+ local is_zero_glue = direct.is_zero_glue
+ local getglue = direct.getglue
+ local setglue = direct.setglue
+
+ function node.is_zero_glue(n)
+ return is_zero_glue(todirect(n))
+ end
+
+ function node.get_glue(n)
+ return get_glue(todirect(n))
+ end
+
+ function node.set_glue(n)
+ return set_glue(todirect(n))
+ end
+
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/node-mig.lua b/Master/texmf-dist/tex/context/base/mkiv/node-mig.lua
index 32b09a1869c..6c10625eb64 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/node-mig.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/node-mig.lua
@@ -24,13 +24,16 @@ local tonut = nuts.tonut
local getnext = nuts.getnext
local getid = nuts.getid
local getlist = nuts.getlist
-local getattr = nuts.getattr
+----- getattr = nuts.getattr
+local getprop = nuts.getprop
-local setattr = nuts.setattr
+----- setattr = nuts.setattr
+local setprop = nuts.setprop
local setlink = nuts.setlink
local setlist = nuts.setlist
local setprev = nuts.setprev
local setnext = nuts.setnext
+local setboth = nuts.setboth
local remove_node = nuts.remove
@@ -60,11 +63,11 @@ local function locate(head,first,last,ni,nm)
elseif migrate_inserts and id == insert_code then
local insert
head, current, insert = remove_node(head,current)
- setnext(insert)
if first then
+ setnext(insert)
setlink(last,insert)
else
- setprev(insert)
+ setboth(insert)
first = insert
end
last = insert
@@ -72,11 +75,11 @@ local function locate(head,first,last,ni,nm)
elseif migrate_marks and id == mark_code then
local mark
head, current, mark = remove_node(head,current)
- setnext(mark)
if first then
+ setnext(mark)
setlink(last,mark)
else
- setprev(mark)
+ setboth(mark)
first = mark
end
last = mark
@@ -98,8 +101,13 @@ function nodes.handlers.migrate(head,where)
local id = getid(current)
-- inserts_too is a temp hack, we should only do them when it concerns
-- newly placed (flushed) inserts
- if id == vlist_code or id == hlist_code or (inserts_too and id == insert_code) and not getattr(current,a_migrated) then
- setattr(current,a_migrated,1)
+
+ -- todo: getprop / setprop
+
+ -- if id == vlist_code or id == hlist_code or (inserts_too and id == insert_code) and not getattr(current,a_migrated) then
+ if id == vlist_code or id == hlist_code or (inserts_too and id == insert_code) and not getprop(current,"migrated") then
+ -- setattr(current,a_migrated,1)
+ setprop(current,"migrated",true)
t_sweeps = t_sweeps + 1
local h = getlist(current)
local first, last, ni, nm
@@ -112,7 +120,7 @@ function nodes.handlers.migrate(head,where)
end
if first then
t_inserts = t_inserts + ni
- t_marks = t_marks + nm
+ t_marks = t_marks + nm
if trace_migrations and (ni > 0 or nm > 0) then
report_nodes("sweep %a, container %a, %s inserts and %s marks migrated outwards during %a",
t_sweeps,nodecodes[id],ni,nm,where)
@@ -126,7 +134,7 @@ function nodes.handlers.migrate(head,where)
current = last
end
end
- current = getnext(next)
+ current = getnext(current)
end
return head
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/node-nut.lua b/Master/texmf-dist/tex/context/base/mkiv/node-nut.lua
index 50e87e988b8..7174bd47565 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/node-nut.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/node-nut.lua
@@ -147,8 +147,9 @@ local nuts = nodes.nuts
nuts.check_discretionaries = direct.check_discretionaries
nuts.copy = direct.copy
-nuts.copy_list = direct.copy_list
nuts.copy_node = direct.copy
+nuts.copy_only = direct.copy_only or direct.copy
+nuts.copy_list = direct.copy_list
nuts.count = direct.count
nuts.current_attr = direct.current_attr
nuts.delete = direct.delete
@@ -202,6 +203,8 @@ nuts.vpack = direct.vpack
nuts.writable_spec = direct.writable_spec
nuts.write = direct.write
nuts.mlist_to_hlist = direct.mlist_to_hlist
+nuts.has_dimensions = direct.has_dimensions
+nuts.start_of_par = direct.start_of_par
if not nuts.mlist_to_hlist then
@@ -218,134 +221,174 @@ if not nuts.mlist_to_hlist then
end
-nuts.getfield = direct.getfield
-nuts.setfield = direct.setfield
-
-nuts.getnext = direct.getnext
-nuts.setnext = direct.setnext
-
-nuts.getid = direct.getid
-
-nuts.getprev = direct.getprev
-nuts.setprev = direct.setprev
-
-nuts.getattr = direct.get_attribute
-nuts.setattr = direct.set_attribute
-nuts.takeattr = direct.unset_attribute -- ?
-
-nuts.is_zero_glue = direct.is_zero_glue
-nuts.effective_glue = direct.effective_glue
-
-nuts.getglue = direct.getglue
-nuts.setglue = direct.setglue
-nuts.getboxglue = direct.getglue
-nuts.setboxglue = direct.setglue
-
-nuts.getdisc = direct.getdisc
-nuts.setdisc = direct.setdisc
-nuts.getdiscretionary = direct.getdisc
-nuts.setdiscretionary = direct.setdisc
-
-nuts.getdata = direct.getdata
-nuts.setdata = direct.setdata
-nuts.getvalue = direct.getdata
-nuts.setvalue = direct.setdata
-
-nuts.getexpansion = direct.getexpansion
-nuts.setexpansion = direct.setexpansion
-
-nuts.getwhd = direct.getwhd
-nuts.setwhd = direct.setwhd
-nuts.getwidth = direct.getwidth
-nuts.setwidth = direct.setwidth
-nuts.getheight = direct.getheight
-nuts.setheight = direct.setheight
-nuts.getdepth = direct.getdepth
-nuts.setdepth = direct.setdepth
-nuts.getshift = direct.getshift
-nuts.setshift = direct.setshift
-nuts.getorientation = direct.getorientation or function() end
-nuts.setorientation = direct.setorientation or function() end
-
-nuts.getnucleus = direct.getnucleus
-nuts.setnucleus = direct.setnucleus
-nuts.getsup = direct.getsup
-nuts.setsup = direct.setsup
-nuts.getsub = direct.getsub
-nuts.setsub = direct.setsub
-
-nuts.getchar = direct.getchar
-nuts.setchar = direct.setchar
-nuts.getfont = direct.getfont
-nuts.setfont = direct.setfont
-nuts.getfam = direct.getfam
-nuts.setfam = direct.setfam
-
-nuts.getboth = direct.getboth
-nuts.setboth = direct.setboth
-nuts.setlink = direct.setlink
-nuts.setsplit = direct.setsplit
-
-nuts.getlist = direct.getlist -- only hlist and vlist !
-nuts.setlist = direct.setlist
-nuts.getleader = direct.getleader
-nuts.setleader = direct.setleader
-nuts.getcomponents = direct.getcomponents
-nuts.setcomponents = direct.setcomponents
-
-nuts.getsubtype = direct.getsubtype
-nuts.setsubtype = direct.setsubtype
-
-nuts.getlang = direct.getlang
-nuts.setlang = direct.setlang
-nuts.getlanguage = direct.getlang
-nuts.setlanguage = direct.setlang
-
-nuts.getattrlist = direct.getattributelist
-nuts.setattrlist = direct.setattributelist
-nuts.getattributelist = direct.getattributelist
-nuts.setattributelist = direct.setattributelist
-
-nuts.getoffsets = direct.getoffsets
-nuts.setoffsets = direct.setoffsets
-
-nuts.getkern = direct.getkern
-nuts.setkern = direct.setkern
-
-nuts.getdir = direct.getdir
-nuts.setdir = direct.setdir
-
-nuts.getdirection = direct.getdirection
-nuts.setdirection = direct.setdirection
-
-nuts.getpenalty = direct.getpenalty
-nuts.setpenalty = direct.setpenalty
-
-nuts.getbox = direct.getbox
-nuts.setbox = direct.setbox
-
-nuts.is_char = direct.is_char
-nuts.ischar = direct.is_char
-nuts.is_glyph = direct.is_glyph
-nuts.isglyph = direct.is_glyph
-
-local d_remove_node = direct.remove
-local d_flush_node = direct.flush_node
-local d_getnext = direct.getnext
-local d_getprev = direct.getprev
-local d_getid = direct.getid
-local d_getlist = direct.getlist
-local d_find_tail = direct.tail
-local d_insert_after = direct.insert_after
-local d_insert_before = direct.insert_before
-local d_slide = direct.slide
------ d_copy_node = direct.copy
-local d_traverse = direct.traverse
-local d_setlink = direct.setlink
-local d_setboth = direct.setboth
-local d_getboth = direct.getboth
-
-local function remove(head,current,free_too)
+if not nuts.has_dimensions then
+
+ local getwhd = direct.getwhd
+
+ function nuts.has_dimensions(n)
+ local wd, ht, dp = getwhd(n)
+ return wd ~= 0 or (ht + dp) ~= 0
+ end
+
+end
+
+local getfield = direct.getfield
+local setfield = direct.setfield
+
+nuts.getfield = getfield
+nuts.setfield = setfield
+
+nuts.getnext = direct.getnext
+nuts.setnext = direct.setnext
+
+nuts.getid = direct.getid
+
+nuts.getprev = direct.getprev
+nuts.setprev = direct.setprev
+
+local get_attribute = direct.get_attribute
+local set_attribute = direct.set_attribute
+local unset_attribute = direct.unset_attribute
+
+nuts.getattr = get_attribute
+nuts.setattr = set_attribute
+nuts.takeattr = unset_attribute -- ?
+
+nuts.is_zero_glue = direct.is_zero_glue
+nuts.effective_glue = direct.effective_glue
+
+nuts.getglue = direct.getglue
+nuts.setglue = direct.setglue
+nuts.getboxglue = direct.getglue
+nuts.setboxglue = direct.setglue
+
+nuts.getdisc = direct.getdisc
+nuts.setdisc = direct.setdisc
+nuts.getdiscretionary = direct.getdisc
+nuts.setdiscretionary = direct.setdisc
+
+nuts.getpre = direct.getpre
+nuts.setpre = direct.setpre
+nuts.getpost = direct.getpost
+nuts.setpost = direct.setpost
+nuts.getreplace = direct.getreplace
+nuts.setreplace = direct.setreplace
+
+local getdata = direct.getdata
+local setdata = direct.setdata
+
+nuts.getdata = getdata
+nuts.setdata = setdata
+nuts.getvalue = getdata
+nuts.setvalue = setdata
+
+nuts.getexpansion = direct.getexpansion
+nuts.setexpansion = direct.setexpansion
+
+nuts.getwhd = direct.getwhd
+nuts.setwhd = direct.setwhd
+nuts.getwidth = direct.getwidth
+nuts.setwidth = direct.setwidth
+nuts.getheight = direct.getheight
+nuts.setheight = direct.setheight
+nuts.getdepth = direct.getdepth
+nuts.setdepth = direct.setdepth
+nuts.getshift = direct.getshift
+nuts.setshift = direct.setshift
+
+-- lmtx compatibility
+
+nuts.getorientation = direct.getorientation or function() end
+nuts.setorientation = direct.setorientation or function() end
+
+nuts.getglyphdata = direct.getglyphdata or get_attribute
+nuts.setglyphdata = direct.setglyphdata or function(n,d) set_attribute(n,0,d) end
+
+nuts.getruledata = direct.getglyphdata and getdata or function(n) return getfield(n,"transform") end
+nuts.setruledata = direct.setglyphdata and setdata or function(n,d) return setfield(n,"transform",d) end
+
+-- so far
+
+nuts.getnucleus = direct.getnucleus
+nuts.setnucleus = direct.setnucleus
+nuts.getsup = direct.getsup
+nuts.setsup = direct.setsup
+nuts.getsub = direct.getsub
+nuts.setsub = direct.setsub
+
+nuts.getchar = direct.getchar
+nuts.setchar = direct.setchar
+nuts.getfont = direct.getfont
+nuts.setfont = direct.setfont
+nuts.getfam = direct.getfam
+nuts.setfam = direct.setfam
+
+nuts.getboth = direct.getboth
+nuts.setboth = direct.setboth
+nuts.setlink = direct.setlink
+nuts.setsplit = direct.setsplit
+
+nuts.getlist = direct.getlist -- only hlist and vlist !
+nuts.setlist = direct.setlist
+nuts.getleader = direct.getleader
+nuts.setleader = direct.setleader
+nuts.getcomponents = direct.getcomponents
+nuts.setcomponents = direct.setcomponents
+
+nuts.getsubtype = direct.getsubtype
+nuts.setsubtype = direct.setsubtype
+
+nuts.getlang = direct.getlang
+nuts.setlang = direct.setlang
+nuts.getlanguage = direct.getlang
+nuts.setlanguage = direct.setlang
+
+nuts.getattrlist = direct.getattributelist
+nuts.setattrlist = direct.setattributelist
+nuts.getattributelist = direct.getattributelist
+nuts.setattributelist = direct.setattributelist
+
+nuts.getoffsets = direct.getoffsets
+nuts.setoffsets = direct.setoffsets
+
+nuts.getkern = direct.getkern
+nuts.setkern = direct.setkern
+
+nuts.getdir = direct.getdir
+nuts.setdir = direct.setdir
+
+nuts.getdirection = direct.getdirection
+nuts.setdirection = direct.setdirection
+
+nuts.getpenalty = direct.getpenalty
+nuts.setpenalty = direct.setpenalty
+
+nuts.getbox = direct.getbox
+nuts.setbox = direct.setbox
+
+nuts.ischar = direct.is_char
+nuts.isglyph = direct.is_glyph
+
+----.is_char = nuts.ischar
+----.is_glyph = nuts.isglyph
+
+local d_remove_node = direct.remove
+local d_flush_node = direct.flush_node
+local d_getnext = direct.getnext
+local d_getprev = direct.getprev
+local d_getid = direct.getid
+local d_getlist = direct.getlist
+local d_find_tail = direct.tail
+local d_insert_after = direct.insert_after
+local d_insert_before = direct.insert_before
+local d_slide = direct.slide
+----- d_copy_node = direct.copy
+local d_traverse = direct.traverse
+local d_setlink = direct.setlink
+local d_setboth = direct.setboth
+local d_getboth = direct.getboth
+
+local remove = CONTEXTLMTXMODE > 0 and d_remove_node or function(head,current,free_too)
if current then
local h, c = d_remove_node(head,current)
if free_too then
@@ -359,13 +402,45 @@ local function remove(head,current,free_too)
return head, current
end
+-- for now
+
+if not nuts.start_of_par then
+
+ local localparcodes = nodes.localparcodes
+ local hmodepar_code = localparcodes.vmode_par
+ local vmodepar_code = localparcodes.hmode_par
+
+ local getsubtype = nuts.getsubtype
+
+ function nuts.start_of_par(n)
+ local s = getsubtype(n)
+ return s == hmodepar_code or s == vmodepar_code
+ end
+
+end
+
+-- for now
+
+if not nuts.getpre then
+
+ local d_getdisc = direct.getdisc
+ local d_setfield = direct.setfield
+
+ function nuts.getpre (n) local h, _, _, t, _, _ = d_getdisc(n,true) return h, t end
+ function nuts.getpost (n) local _, h, _, _, t, _ = d_getdisc(n,true) return h, t end
+ function nuts.getreplace(n) local _, _, h, _, _, t = d_getdisc(n,true) return h, t end
+
+ function nuts.setpre (n,h) d_setfield(d,"pre", h) end
+ function nuts.setpost (n,h) d_setfield(d,"post", h) end
+ function nuts.setreplace(n,h) d_setfield(d,"replace",h) end
+
+end
+
-- alias
nuts.getsurround = nuts.getkern
nuts.setsurround = nuts.setkern
--- bad: we can have prev's being glue_spec
-
nuts.remove = remove
function nuts.delete(head,current)
@@ -717,14 +792,22 @@ end
nuts.getprop = function(n,k)
local p = propertydata[n]
if p then
- return p[k]
+ if k then
+ return p[k]
+ else
+ return p
+ end
end
end
nuts.rawprop = function(n,k)
local p = rawget(propertydata,n)
if p then
- return p[k]
+ if k then
+ return p[k]
+ else
+ return p
+ end
end
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/node-par.lua b/Master/texmf-dist/tex/context/base/mkiv/node-par.lua
index 8564c8764bd..d89edf6f4ca 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/node-par.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/node-par.lua
@@ -39,7 +39,7 @@ local function newgraf(mode,indented)
local runner = actions.runner
if runner then
starttiming(builders)
- indent = runner(mode,indented)
+ indented = runner(mode,indented)
stoptiming(builders)
end
return indented
diff --git a/Master/texmf-dist/tex/context/base/mkiv/node-pro.lua b/Master/texmf-dist/tex/context/base/mkiv/node-pro.lua
index 606d5b8d773..4d748af89bd 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/node-pro.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/node-pro.lua
@@ -176,7 +176,8 @@ end
do
- local texnest = tex.nest
+ ----- texnest = tex.nest
+ local getnest = tex.getnest
local getlist = nuts.getlist
local setlist = nuts.setlist
@@ -188,7 +189,7 @@ do
function processors.contribute_filter(groupcode)
if groupcode == "box" then -- "pre_box"
- local whatever = texnest[texnest.ptr]
+ local whatever = getnest()
if whatever then
local line = whatever.tail
if line then
diff --git a/Master/texmf-dist/tex/context/base/mkiv/node-ref.lua b/Master/texmf-dist/tex/context/base/mkiv/node-ref.lua
index e12bd95bdd6..ac43a84a368 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/node-ref.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/node-ref.lua
@@ -77,6 +77,7 @@ local getdimensions = nuts.dimensions
local getrangedimensions = nuts.rangedimensions
local traverse = nuts.traverse
local find_node_tail = nuts.tail
+local start_of_par = nuts.start_of_par
local nodecodes = nodes.nodecodes
local gluecodes = nodes.gluecodes
@@ -166,33 +167,33 @@ local function dimensions(parent,start,stop) -- in principle we could move some
-- todo: if no prev and no next and parent
-- todo: we need a a list_dimensions for a vlist
if getid(parent) == vlist_code then
- if false then
- local l = getlist(parent)
- local c = l
- local ok = false
- while c do
- if c == start then
- ok = true
- end
- if ok and getid(c) == hlist_code then
- break
- else
- c = getnext(c)
- end
- end
- if ok and c then
- if trace_areas then
- report_area("dimensions taken of first line in vlist")
- end
- local w, h, d = getwhd(c)
- return w, h, d, c
- else
- if trace_areas then
- report_area("dimensions taken of vlist (probably wrong)")
- end
- return hlist_dimensions(start,stop,parent)
- end
- else
+ -- if false then
+ -- local l = getlist(parent)
+ -- local c = l
+ -- local ok = false
+ -- while c do
+ -- if c == start then
+ -- ok = true
+ -- end
+ -- if ok and getid(c) == hlist_code then
+ -- break
+ -- else
+ -- c = getnext(c)
+ -- end
+ -- end
+ -- if ok and c then
+ -- if trace_areas then
+ -- report_area("dimensions taken of first line in vlist")
+ -- end
+ -- local w, h, d = getwhd(c)
+ -- return w, h, d, c
+ -- else
+ -- if trace_areas then
+ -- report_area("dimensions taken of vlist (probably wrong)")
+ -- end
+ -- return hlist_dimensions(start,stop,parent)
+ -- end
+ -- else
--
-- we can as well calculate here because we only have kerns and glue
--
@@ -200,7 +201,7 @@ local function dimensions(parent,start,stop) -- in principle we could move some
local last = nil
local current = start
local noflines = 0
- while current do
+ while current do -- can be loop
local id = getid(current)
if id == hlist_code or id == vlist_code or id == rule_code then
if noflines == 0 then
@@ -239,7 +240,7 @@ local function dimensions(parent,start,stop) -- in principle we could move some
return hlist_dimensions(start,stop,parent)
end
end
- end
+ -- end
else
if trace_areas then
report_area("dimensions taken of range starting with %a using parent",nodecodes[id])
@@ -258,7 +259,7 @@ local function inject_range(head,first,last,reference,make,stack,parent,pardir,t
local width, height, depth, line = dimensions(parent,first,last)
if txtdir == righttoleft_code then
width = - width
- elseif textdir == lefttoright_code then
+ elseif txtdir == lefttoright_code then
-- go on
elseif pardir == righttoleft_code then
width = - width
@@ -374,6 +375,9 @@ end
-- where we can end up with a first and last spanning lines so maybe
-- we need to do vlists differently
+-- todo: no need for dir here if we inject in the right spot as then we can
+-- pick up the dir elsewhere (in lmtx)
+
local function inject_areas(head,attribute,make,stack,done,skip,parent,pardir,txtdir) -- main
local first, last, firstdir, reference
local current = head
@@ -383,9 +387,6 @@ local function inject_areas(head,attribute,make,stack,done,skip,parent,pardir,tx
local r = getattr(current,attribute)
-- test \goto{test}[page(2)] test \gotobox{test}[page(2)]
-- test \goto{\TeX}[page(2)] test \gotobox{\hbox {x} \hbox {x}}[page(2)]
- -- if r and (not skip or r >) skip then -- maybe no > test
- -- inject_list(id,current,r,make,stack,pardir,txtdir)
- -- end
if r then
if not reference then
reference, first, last, firstdir = r, current, current, txtdir
@@ -419,7 +420,7 @@ local function inject_areas(head,attribute,make,stack,done,skip,parent,pardir,tx
local direction, pop = getdirection(current)
txtdir = not pop and direction -- we might need a stack
elseif id == localpar_code then
- if getsubtype(current) == 0 then
+ if start_of_par(current) then
pardir = getdirection(current)
end
else
@@ -447,182 +448,6 @@ local function inject_areas(head,attribute,make,stack,done,skip,parent,pardir,tx
return head, pardir, txtdir
end
--- -- not faster either:
---
--- local findattr = node.direct.find_attribute
---
--- local function inject_areas(head,attribute,make,stack,done,skip,parent,pardir,txtdir) -- main
--- local first, last, firstdir, reference
--- local someatt = findattr(head,attribute)
--- if someatt then
--- local current = head
--- while current do
--- local id = getid(current)
--- if id == hlist_code or id == vlist_code then
--- local r = getattr(current,attribute)
--- -- test \goto{test}[page(2)] test \gotobox{test}[page(2)]
--- -- test \goto{\TeX}[page(2)] test \gotobox{\hbox {x} \hbox {x}}[page(2)]
--- -- if r and (not skip or r >) skip then -- maybe no > test
--- -- inject_list(id,current,r,make,stack,pardir,txtdir)
--- -- end
--- if r then
--- if not reference then
--- reference, first, last, firstdir = r, current, current, txtdir
--- elseif r == reference then
--- -- same link
--- last = current
--- elseif (done[reference] or 0) == 0 then
--- if not skip or r > skip then -- maybe no > test
--- head, current = inject_range(head,first,last,reference,make,stack,parent,pardir,firstdir)
--- reference, first, last, firstdir = nil, nil, nil, nil
--- end
--- else
--- reference, first, last, firstdir = r, current, current, txtdir
--- end
--- done[r] = (done[r] or 0) + 1
--- end
--- local list = getlist(current)
--- if list then
--- local h
--- h, pardir, txtdir = inject_areas(list,attribute,make,stack,done,r or skip or 0,current,pardir,txtdir)
--- if h ~= current then
--- setlist(current,h)
--- end
--- end
--- if r then
--- done[r] = done[r] - 1
--- end
--- elseif id == dir_code then
--- local direction, pop = getdirection(current)
--- txtdir = not pop and direction -- we might need a stack
--- elseif id == localpar_code then -- only test at begin
--- pardir = getdirection(current)
--- elseif id == glue_code and getsubtype(current) == leftskip_code then -- any glue at the left?
--- --
--- else
--- local r = getattr(current,attribute)
--- if not r then
--- -- just go on, can be kerns
--- elseif not reference then
--- reference, first, last, firstdir = r, current, current, txtdir
--- elseif r == reference then
--- last = current
--- elseif (done[reference] or 0) == 0 then -- or id == glue_code and getsubtype(current) == right_skip_code
--- if not skip or r > skip then -- maybe no > test
--- head, current = inject_range(head,first,last,reference,make,stack,parent,pardir,firstdir)
--- reference, first, last, firstdir = nil, nil, nil, nil
--- end
--- else
--- reference, first, last, firstdir = r, current, current, txtdir
--- end
--- end
--- current = getnext(current)
--- end
--- if reference and (done[reference] or 0) == 0 then
--- head = inject_range(head,first,last,reference,make,stack,parent,pardir,firstdir)
--- end
--- else
--- local current = head
--- while current do
--- local id = getid(current)
--- if id == hlist_code or id == vlist_code then
--- local list = getlist(current)
--- if list then
--- local h = inject_areas(list,attribute,make,stack,done,skip or 0,current,pardir,txtdir)
--- if h ~= current then
--- setlist(current,h)
--- end
--- end
--- elseif id == dir_code then
--- local direction, pop = getdirection(current)
--- txtdir = not pop and direction -- we might need a stack
--- elseif id == localpar_code then -- only test at begin
--- pardir = getdirection(current)
--- end
--- current = getnext(current)
--- end
--- end
--- return head, pardir, txtdir
--- end
-
--- -- maybe first check for glyphs and use a goto:
---
--- local function inject_areas(head,attribute,make,stack,done,skip,parent,pardir,txtdir) -- main
--- local first, last, firstdir, reference
--- local current = head
--- while current do
--- local id = getid(current)
--- local r -- else scope message due to goto
--- if id == glyph_code then
--- goto rest
--- elseif id == hlist_code or id == vlist_code then
--- r = getattr(current,attribute)
--- -- test \goto{test}[page(2)] test \gotobox{test}[page(2)]
--- -- test \goto{\TeX}[page(2)] test \gotobox{\hbox {x} \hbox {x}}[page(2)]
--- -- if r and (not skip or r >) skip then -- maybe no > test
--- -- inject_list(id,current,r,make,stack,pardir,txtdir)
--- -- end
--- if r then
--- if not reference then
--- reference, first, last, firstdir = r, current, current, txtdir
--- elseif r == reference then
--- -- same link
--- last = current
--- elseif (done[reference] or 0) == 0 then
--- if not skip or r > skip then -- maybe no > test
--- head, current = inject_range(head,first,last,reference,make,stack,parent,pardir,firstdir)
--- reference, first, last, firstdir = nil, nil, nil, nil
--- end
--- else
--- reference, first, last, firstdir = r, current, current, txtdir
--- end
--- done[r] = (done[r] or 0) + 1
--- end
--- local list = getlist(current)
--- if list then
--- local h
--- h, pardir, txtdir = inject_areas(list,attribute,make,stack,done,r or skip or 0,current,pardir,txtdir)
--- if h ~= current then
--- setlist(current,h)
--- end
--- end
--- if r then
--- done[r] = done[r] - 1
--- end
--- elseif id == glue_code and getsubtype(current) == leftskip_code then -- any glue at the left?
--- --
--- elseif id == dir_code then
--- local direction, pop = getdirection(current)
--- txtdir = not pop and direction -- we might need a stack
--- elseif id == localpar_code then -- only test at begin
--- pardir = getdirection(current)
--- end
--- goto next
--- ::rest::
--- r = getattr(current,attribute)
--- if not r then
--- -- just go on, can be kerns
--- elseif not reference then
--- reference, first, last, firstdir = r, current, current, txtdir
--- elseif r == reference then
--- last = current
--- elseif (done[reference] or 0) == 0 then -- or id == glue_code and getsubtype(current) == right_skip_code
--- if not skip or r > skip then -- maybe no > test
--- head, current = inject_range(head,first,last,reference,make,stack,parent,pardir,firstdir)
--- reference, first, last, firstdir = nil, nil, nil, nil
--- end
--- else
--- reference, first, last, firstdir = r, current, current, txtdir
--- end
--- ::next::
--- current = getnext(current)
--- end
--- if reference and (done[reference] or 0) == 0 then
--- head = inject_range(head,first,last,reference,make,stack,parent,pardir,firstdir)
--- end
--- return head, pardir, txtdir
--- end
-
-- tracing: todo: use predefined colors
local register_color = colors.register
@@ -766,7 +591,7 @@ local function makereference(width,height,depth,reference) -- height and depth a
if depth < dp then depth = dp end
end
-- logs.report("temp","used: ht=%p dp=%p",height,depth)
- local annot = nodeinjections.reference(width,height,depth,set)
+ local annot = nodeinjections.reference(width,height,depth,set,resolved.mesh)
if annot then
annot = tonut(annot) -- todo
nofreferences = nofreferences + 1
@@ -929,7 +754,6 @@ local function makedestination(width,height,depth,reference)
end
end
-
function nodes.destinations.handler(head)
if head and topofstack > 0 then
return (inject_areas(head,attribute,makedestination,stack,done))
diff --git a/Master/texmf-dist/tex/context/base/mkiv/node-res.lua b/Master/texmf-dist/tex/context/base/mkiv/node-res.lua
index 5b4961683ce..a27f5c4e5ff 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/node-res.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/node-res.lua
@@ -96,9 +96,10 @@ local setsubtype = nuts.setsubtype
local setleader = nuts.setleader
local setdata = nuts.setdata
+local setruledata = nuts.setruledata
local setvalue = nuts.setvalue
-local copy_nut = nuts.copy
+local copy_nut = nuts.copy_only or nuts.copy
local new_nut = nuts.new
local flush_nut = nuts.flush
@@ -161,8 +162,7 @@ local kern = register_nut(new_nut(kern_code,kerncodes.userkern))
local fontkern = register_nut(new_nut(kern_code,kerncodes.fontkern))
local italickern = register_nut(new_nut(kern_code,kerncodes.italiccorrection))
local penalty = register_nut(new_nut(nodecodes.penalty))
-local glue = register_nut(new_nut(glue_code)) -- glue.spec = nil
-local glue_spec = register_nut(new_nut(nodecodes.gluespec))
+local glue = register_nut(new_nut(glue_code))
local glyph = register_nut(new_nut(glyph_code,0))
local textdir = register_nut(new_nut(nodecodes.dir))
@@ -172,7 +172,7 @@ local savepos = register_nut(new_nut(whatsit_code,whatsitcodes.savepos
local user_node = new_nut(whatsit_code,whatsitcodes.userdefined)
-if CONTEXTLMTXMODE < 2 then
+if CONTEXTLMTXMODE == 0 then
setfield(user_node,"type",usercodes.number)
end
@@ -183,6 +183,10 @@ local lineskip = register_nut(new_nut(glue_code,gluecodes.lineskip))
local baselineskip = register_nut(new_nut(glue_code,gluecodes.baselineskip))
local leftskip = register_nut(new_nut(glue_code,gluecodes.leftskip))
local rightskip = register_nut(new_nut(glue_code,gluecodes.rightskip))
+local lefthangskip = register_nut(new_nut(glue_code,gluecodes.lefthangskip))
+local righthangskip = register_nut(new_nut(glue_code,gluecodes.righthangskip))
+local indentskip = register_nut(new_nut(glue_code,gluecodes.indentskip))
+local correctionskip = register_nut(new_nut(glue_code,gluecodes.correctionskip))
local temp = register_nut(new_nut(nodecodes.temp,0))
@@ -272,15 +276,6 @@ function nutpool.italickern(k)
return n
end
-function nutpool.gluespec(width,stretch,shrink,stretch_order,shrink_order)
- -- maybe setglue
- local s = copy_nut(glue_spec)
- if width or stretch or shrink or stretch_order or shrink_order then
- setglue(s,width,stretch,shrink,stretch_order,shrink_order)
- end
- return s
-end
-
local function someskip(skip,width,stretch,shrink,stretch_order,shrink_order)
-- maybe setglue
local n = copy_nut(skip)
@@ -328,6 +323,18 @@ function nutpool.rightskip(width,stretch,shrink,stretch_order,shrink_order)
return someskip(rightskip,width,stretch,shrink,stretch_order,shrink_order)
end
+function nutpool.lefthangskip(width,stretch,shrink,stretch_order,shrink_order)
+ return someskip(lefthangskip,width,stretch,shrink,stretch_order,shrink_order)
+end
+
+function nutpool.righthangskip(width,stretch,shrink,stretch_order,shrink_order)
+ return someskip(righthangskip,width,stretch,shrink,stretch_order,shrink_order)
+end
+
+function nutpool.indentskip(width,stretch,shrink,stretch_order,shrink_order)
+ return someskip(indentskip,width,stretch,shrink,stretch_order,shrink_order)
+end
+
function nutpool.lineskip(width,stretch,shrink,stretch_order,shrink_order)
return someskip(lineskip,width,stretch,shrink,stretch_order,shrink_order)
end
@@ -344,14 +351,6 @@ function nutpool.disc(pre,post,replace)
return d
end
-function nutpool.textdir(dir) -- obsolete !
- local t = copy_nut(textdir)
- if dir then
- setdir(t,dir)
- end
- return t
-end
-
function nutpool.direction(dir,swap)
local t = copy_nut(textdir)
if not dir then
@@ -394,7 +393,7 @@ function nutpool.outlinerule(width,height,depth,line) -- w/h/d == nil will let t
setwhd(n,width,height,depth)
end
if line then
- if CONTEXTLMTXMODE > 1 then setdata(n,line) else setfield(n,"transform",line) end
+ setruledata(n,line)
end
return n
end
@@ -414,11 +413,16 @@ function nutpool.savepos()
return copy_nut(savepos)
end
-if CONTEXTLMTXMODE > 1 then
+if CONTEXTLMTXMODE == 0 then
function nutpool.latelua(code)
local n = copy_nut(latelua)
- nodeproperties[n] = { data = code }
+ if type(code) == "table" then
+ local action = code.action
+ local specification = code.specification or code
+ code = function() action(specification) end
+ end
+ setdata(n,code)
return n
end
@@ -426,12 +430,7 @@ else
function nutpool.latelua(code)
local n = copy_nut(latelua)
- if type(code) == "table" then
- local action = code.action
- local specification = code.specification or code
- code = function() action(specification) end
- end
- setdata(n,code)
+ nodeproperties[n] = { data = code }
return n
end
@@ -560,8 +559,7 @@ local function cleanup(nofboxes) -- todo
return nr, nl, nofboxes -- can be nil
end
-
-local function usage()
+local usage = CONTEXTLMTXMODE > 0 and node.inuse or function()
local t = { }
for n, tag in gmatch(status.node_mem_usage,"(%d+) ([a-z_]+)") do
t[tag] = tonumber(n) or 0
@@ -582,9 +580,13 @@ statistics.register("cleaned up reserved nodes", function()
end) -- \topofboxstack
statistics.register("node memory usage", function() -- comes after cleanup !
- local usage = status.node_mem_usage
- if usage ~= "" then
- return usage
+ local used = usage()
+ if next(used) then
+ local t, n = { }, 0
+ for k, v in table.sortedhash(used) do
+ n = n + 1 ; t[n] = format("%s %s",v,k)
+ end
+ return table.concat(t,", ")
end
end)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/node-rul.lua b/Master/texmf-dist/tex/context/base/mkiv/node-rul.lua
index 1df5bf32ae7..b904e54d616 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/node-rul.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/node-rul.lua
@@ -22,7 +22,7 @@ local tonumber = tonumber
local context = context
local attributes = attributes
local nodes = nodes
-local properties = nodes.properties
+local properties = nodes.properties.data
local enableaction = nodes.tasks.enableaction
@@ -30,7 +30,6 @@ local nuts = nodes.nuts
local tonode = nuts.tonode
local tonut = nuts.tonut
-local getfield = nuts.getfield
local setnext = nuts.setnext
local setprev = nuts.setprev
local setlink = nuts.setlink
@@ -50,7 +49,10 @@ local getwidth = nuts.getwidth
local setwidth = nuts.setwidth
local setoffsets = nuts.setoffsets
local setfield = nuts.setfield
-local getdata = nuts.getdata
+
+----- getfield = nuts.getfield
+----- getdata = nuts.getdata
+local getruledata = nuts.getruledata
local isglyph = nuts.isglyph
@@ -122,6 +124,9 @@ local dimenfactor = fonts.helpers.dimenfactor
local splitdimen = number.splitdimen
local setmetatableindex = table.setmetatableindex
+local magicconstants = tex.magicconstants
+local running = magicconstants.running
+
--
local striprange = nuts.striprange
@@ -166,7 +171,7 @@ rules .ruleactions = ruleactions
nutrules.ruleactions = ruleactions -- convenient
local function mathaction(n,h,v,what)
- local font = CONTEXTLMTXMODE > 1 and getdata(n) or getfield(n,"transform")
+ local font = getruledata(n)
local actions = fontresources[font].mathruleactions
if actions then
local action = actions[what]
@@ -184,6 +189,8 @@ local function mathrule(n,h,v)
mathaction(n,h,v,"hruleaction")
end
+local x
+
local function useraction(n,h,v)
local p = properties[n]
if p then
@@ -222,7 +229,7 @@ local trace_ruled = false trackers.register("nodes.rules", function(v) trace_
local report_ruled = logs.reporter("nodes","rules")
function rules.define(settings)
- local nofdata = #data+1
+ local nofdata = #data + 1
data[nofdata] = settings
local text = settings.text
if text then
@@ -234,7 +241,7 @@ function rules.define(settings)
settings.text = nil
end
end
- context(nofdata)
+ return nofdata
end
local function flush_ruled(head,f,l,d,level,parent,strip) -- not that fast but acceptable for this purpose
@@ -263,7 +270,7 @@ local function flush_ruled(head,f,l,d,level,parent,strip) -- not that fast but a
if not f then
return head
end
- local w, ht, dp = getrangedimensions(parent,f,getnext(l))
+ local wd, ht, dp = getrangedimensions(parent,f,getnext(l))
local method = d.method
local empty = d.empty == v_yes
local offset = d.offset
@@ -304,7 +311,7 @@ local function flush_ruled(head,f,l,d,level,parent,strip) -- not that fast but a
m = 0
end
- local function inject(r,w,ht,dp)
+ local function inject(r,wd,ht,dp)
if layer then
setattr(r,a_viewerlayer,layer)
end
@@ -315,7 +322,7 @@ local function flush_ruled(head,f,l,d,level,parent,strip) -- not that fast but a
setnext(l)
flushlist(f)
else
- local k = new_kern(-w)
+ local k = new_kern(-wd)
if foreground then
insert_node_after(head,l,k)
insert_node_after(head,k,r)
@@ -327,12 +334,12 @@ local function flush_ruled(head,f,l,d,level,parent,strip) -- not that fast but a
end
if trace_ruled then
report_ruled("level %a, width %p, height %p, depth %p, nodes %a, text %a",
- level,w,ht,dp,n_tostring(f,l),n_tosequence(f,l,true))
+ level,wd,ht,dp,n_tostring(f,l),n_tosequence(f,l,true))
end
end
if mp and mp ~= "" then
local r = usernutrule {
- width = w,
+ width = wd,
height = ht,
depth = dp,
type = "mp",
@@ -344,22 +351,26 @@ local function flush_ruled(head,f,l,d,level,parent,strip) -- not that fast but a
ca = color,
ta = transparency,
}
- inject(r,w,ht,dp)
+ inject(r,wd,ht,dp)
else
local tx = d.text
if tx then
local l = copy_list(tx)
if d["repeat"] == v_yes then
- l = new_leader(w,l)
+ l = new_leader(wd,l)
setattrlist(l,tx)
end
- l = hpack_nodes(l,w,"exactly")
- inject(l,w,ht,dp)
+ l = hpack_nodes(l,wd,"exactly")
+ inject(l,wd,ht,dp)
else
for i=1,level do
- local ht = (offset+(i-1)*dy)*e + rulethickness - m
- local dp = -(offset+(i-1)*dy)*e + rulethickness + m
- local r = new_rule(w,ht,dp)
+ local hd = (offset+(i-1)*dy)*e - m
+-- local ht = hd + rulethickness - m
+-- local dp = -hd + rulethickness + m
+ local ht = hd + rulethickness
+ local dp = -hd + rulethickness
+ local r = new_rule(wd,ht,dp)
+ -- can be done more efficient
if color then
setattr(r,a_colormodel,colorspace)
setattr(r,a_color,color)
@@ -367,7 +378,7 @@ local function flush_ruled(head,f,l,d,level,parent,strip) -- not that fast but a
if transparency then
setattr(r,a_transparency,transparency)
end
- inject(r,w,ht,dp)
+ inject(r,wd,ht,dp)
end
end
end
@@ -388,16 +399,18 @@ local report_shifted = logs.reporter("nodes","shifting")
local a_shifted = attributes.private('shifted')
-nodes.shifts = nodes.shifts or { }
-nodes.shifts.data = nodes.shifts.data or { }
+local shifts = nodes.shifts or { }
+nodes.shifts = shifts
+shifts.data = shifts.data or { }
-storage.register("nodes/shifts/data", nodes.shifts.data, "nodes.shifts.data")
+storage.register("nodes/shifts/data", shifts.data, "nodes.shifts.data")
-local data = nodes.shifts.data
+local data = shifts.data
-function nodes.shifts.define(settings)
- data[#data+1] = settings
- context(#data)
+function shifts.define(settings)
+ local nofdata = #data + 1
+ data[nofdata] = settings
+ return nofdata
end
local function flush_shifted(head,first,last,data,level,parent,strip) -- not that fast but acceptable for this purpose
@@ -428,26 +441,28 @@ local function flush_shifted(head,first,last,data,level,parent,strip) -- not tha
return head
end
-nodes.shifts.handler = function(head)
+shifts.handler = function(head)
return processwords(a_shifted,data,flush_shifted,head)
end
-function nodes.shifts.enable()
+function shifts.enable()
enableaction("shipouts","nodes.shifts.handler")
end
-- linefillers
-nodes.linefillers = nodes.linefillers or { }
-nodes.linefillers.data = nodes.linefillers.data or { }
+local linefillers = nodes.linefillers or { }
+nodes.linefillers = linefillers
+linefillers.data = linefillers.data or { }
-storage.register("nodes/linefillers/data", nodes.linefillers.data, "nodes.linefillers.data")
+storage.register("nodes/linefillers/data", linefillers.data, "nodes.linefillers.data")
-local data = nodes.linefillers.data
+local data = linefillers.data
-function nodes.linefillers.define(settings)
- data[#data+1] = settings
- context(#data)
+function linefillers.define(settings)
+ local nofdata = #data + 1
+ data[nofdata] = settings
+ return nofdata
end
local function linefiller(current,data,width,location)
@@ -484,7 +499,7 @@ local function linefiller(current,data,width,location)
end
end
-function nodes.linefillers.filler(current,data,width,height,depth)
+function linefillers.filler(current,data,width,height,depth)
if width and width > 0 then
local height = height or data.height or 0
local depth = depth or data.depth or 0
@@ -532,9 +547,9 @@ local function find_attr(head,attr)
end
end
-function nodes.linefillers.handler(head)
- for current, subtype, list in nexthlist, head do
- if list and subtype == linelist_code then
+function linefillers.handler(head)
+ for current, subtype in nexthlist, head do
+ if current and subtype == linelist_code then
-- why doesn't leftskip take the attributes
-- or list[linefiller] or maybe first match (maybe we need a fast helper for that)
local a = getattr(current,a_linefiller)
@@ -558,6 +573,8 @@ function nodes.linefillers.handler(head)
rightlocal = true
end
--
+ local list = getlist(current)
+ --
if location == v_left or location == v_both then
local lskip = nil -- leftskip
local iskip = nil -- indentation
@@ -656,7 +673,7 @@ end
local enable = false
-function nodes.linefillers.enable()
+function linefillers.enable()
if not enable then
-- we could now nil it
enableaction("finalizers","nodes.linefillers.handler")
@@ -698,7 +715,7 @@ implement {
implement {
name = "defineshift",
- actions = { nodes.shifts.define, context },
+ actions = { shifts.define, context },
arguments = {
{
{ "continue" },
@@ -712,12 +729,12 @@ implement {
implement {
name = "enableshifts",
onlyonce = true,
- actions = nodes.shifts.enable
+ actions = shifts.enable
}
implement {
name = "definelinefiller",
- actions = { nodes.linefillers.define, context },
+ actions = { linefillers.define, context },
arguments = {
{
{ "method", "integer" },
@@ -739,7 +756,7 @@ implement {
implement {
name = "enablelinefillers",
onlyonce = true,
- actions = nodes.linefillers.enable
+ actions = linefillers.enable
}
-- We add a bonus feature here (experiment):
@@ -759,9 +776,9 @@ interfaces.implement {
},
actions = function(t)
local n = new_rule(
- t.width,
- t.height,
- t.depth
+ t.width or running,
+ t.height or running,
+ t.depth or running
)
setattrlist(n,true)
setoffsets(n,t.xoffset,t.yoffset) -- ,t.left, t.right
diff --git a/Master/texmf-dist/tex/context/base/mkiv/node-rul.mkiv b/Master/texmf-dist/tex/context/base/mkiv/node-rul.mkiv
index 19f398eb900..7f2093bf2c3 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/node-rul.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/node-rul.mkiv
@@ -146,6 +146,12 @@
{\node_rules_set{#1}\barparameter\c!left}%
{\relax\barparameter\c!right}}
+\unexpanded\def\inlinebar[#1]%
+ {\node_rules_direct{#1}}
+
+% \unexpanded\def\inlinecurrentbar
+% {\node_rules_direct{\currentbar}}
+
% store in properties
\unexpanded\def\node_rules_set#1% maybe reverse the 1000 (also maybe use more attributes instead of settings)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/node-scn.lua b/Master/texmf-dist/tex/context/base/mkiv/node-scn.lua
index a40a5271a9e..055f5e20def 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/node-scn.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/node-scn.lua
@@ -124,7 +124,7 @@ local function processwords(attribute,data,flush,head,parent,skip) -- we have hl
local continue, leaders, done, strip, level = false, false, false, true, -1
while n do
local id = getid(n)
- if id == glyph_code or id == rule_code or (id == hlist_code and getattr(n,a_runningtext) == 1) then
+ if id == glyph_code or id == rule_code or (id == hlist_code and getattr(n,a_runningtext)) then
local aa = getattr(n,attribute)
if aa and aa ~= skip then
if aa == a then
diff --git a/Master/texmf-dist/tex/context/base/mkiv/node-syn.lua b/Master/texmf-dist/tex/context/base/mkiv/node-syn.lua
index a00dc65ec53..68a05234e90 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/node-syn.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/node-syn.lua
@@ -89,7 +89,6 @@ if not modules then modules = { } end modules ['node-syn'] = {
-- h2,5:4661756,12973165:22918783,655360,327680
-- h2,6:27884864,12973165:4746833,655360,327680
-- h2,6:4661756,13922231:18320732,655360,327680
--- )
-- ]
-- !533
-- }1
@@ -106,7 +105,6 @@ if not modules then modules = { } end modules ['node-syn'] = {
-- h3,4:8459505,11075033:19885281,655360,327680
-- h3,5:28571312,11075033:4060385,655360,327680
-- h3,5:4661756,12024099:15344870,655360,327680
--- )
-- ]
-- !441
-- }2
@@ -156,8 +154,11 @@ local kern_code = nodecodes.kern
----- rule_code = nodecodes.rule
local hlist_code = nodecodes.hlist
local vlist_code = nodecodes.vlist
+local dir_code = nodecodes.dir
local fontkern_code = kerncodes.fontkern
+local cancel_code = nodes.dircodes.cancel
+
local insert_before = nuts.insert_before
local insert_after = nuts.insert_after
@@ -170,7 +171,7 @@ local getdimensions = nuts.dimensions
local getrangedimensions = nuts.rangedimensions
local get_synctex_fields = nuts.get_synctex_fields
-local set_synctex_fields = nuts.set_synctex_fields
+----- set_synctex_fields = nuts.set_synctex_fields
local set_synctex_line = tex.set_synctex_line
local set_synctex_tag = tex.set_synctex_tag
local force_synctex_tag = tex.force_synctex_tag
@@ -227,6 +228,8 @@ local blockedsuffixes = {
mkii = true,
mkiv = true,
mkvi = true,
+ mkxl = true,
+ mklx = true,
mkix = true,
mkxi = true,
-- lfg = true,
@@ -641,6 +644,19 @@ local function collect_max(head,parent)
current = getnext(current)
if current then
id = getid(current)
+
+-- while id == dir_code do
+-- current = getnext(current)
+-- if current then
+-- id = getid(current)
+-- else
+-- if tag > 0 then
+-- head = inject(parent,head,first,last,tag,line)
+-- end
+-- return head
+-- end
+-- end
+
else
if tag > 0 then
head = inject(parent,head,first,last,tag,line)
@@ -649,12 +665,12 @@ local function collect_max(head,parent)
end
end
end
- -- pick up(as id can have changed)
+ -- pick up (as id can have changed)
if id == hlist_code or id == vlist_code then
local list = getlist(current)
if list then
local l = collect(list,current)
- if l ~= list then
+ if l and l ~= list then
setlist(current,l)
end
end
@@ -692,7 +708,8 @@ end
function synctex.stop()
if enabled then
- filehandle:write(s_vlist,s_hlist)
+ -- filehandle:write(s_vlist,s_hlist)
+ filehandle:write(s_hlist)
writeanchor()
filehandle:write("}",nofsheets,eol)
nofobjects = nofobjects + 2
diff --git a/Master/texmf-dist/tex/context/base/mkiv/node-tra.lua b/Master/texmf-dist/tex/context/base/mkiv/node-tra.lua
index e1b6927fbce..c7556aba6d0 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/node-tra.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/node-tra.lua
@@ -83,6 +83,8 @@ local whatsit_code = nodecodes.whatsit
local dimenfactors = number.dimenfactors
local formatters = string.formatters
+local start_of_par = nuts.start_of_par
+
-- this will be reorganized:
function nodes.showlist(head, message)
@@ -165,7 +167,7 @@ local function tosequence(start,stop,compact)
elseif id == dir_code then
local d, p = getdirection(start)
n = n + 1 ; t[n] = "[<" .. (p and "-" or "+") .. d .. ">]" -- todo l2r etc
- elseif id == localpar_code and getsubtype(start) == 0 then
+ elseif id == localpar_code and start_of_par(current) then
n = n + 1 ; t[n] = "[<" .. getdirection(start) .. ">]" -- todo l2r etc
elseif compact then
n = n + 1 ; t[n] = "[]"
@@ -355,7 +357,9 @@ local function listtoutf(h,joiner,textonly,last,nodisc)
n = n + 1 ; w[n] = " "
end
elseif id == hlist_code or id == vlist_code then
- n = n + 1 ; w[n] = "[]"
+ n = n + 1 ; w[n] = "["
+ n = n + 1 ; w[n] = listtoutf(getlist(h),joiner,textonly,last,nodisc)
+ n = n + 1 ; w[n] = "]"
end
else
n = n + 1 ; w[n] = "[-]"
diff --git a/Master/texmf-dist/tex/context/base/mkiv/pack-bck.mkvi b/Master/texmf-dist/tex/context/base/mkiv/pack-bck.mkvi
index 9f9d843cef7..6cbe281d975 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/pack-bck.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/pack-bck.mkvi
@@ -105,6 +105,11 @@
\strut
\vskip-2\lineheight
\strut
+ % safeguard added
+ \ifdim\dimexpr\pagetotal+2\lineheight\relax>\pagegoal
+ \page
+ \fi
+ % till here
\egroup
\dimen2\leftskip % new **
\forgetall
@@ -120,7 +125,7 @@
\splitmaxdepth\boxmaxdepth
\splittopskip\topskip
\doloop
- {\ifdim\pagetotal=\zeropoint % empty page
+ {\ifzeropt\pagetotal % empty page
\scratchdimen\textheight
\backgroundsplitmode\plusone % split to max height
\else
diff --git a/Master/texmf-dist/tex/context/base/mkiv/pack-box.mkiv b/Master/texmf-dist/tex/context/base/mkiv/pack-box.mkiv
index bf6d4662dac..422f090f0b9 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/pack-box.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/pack-box.mkiv
@@ -913,15 +913,15 @@
\scratchtopoffset \offsetboxparameter\c!topoffset
\scratchbottomoffset\offsetboxparameter\c!bottomoffset
\relax % really needed
- \ifdim\scratchleftoffset =\zeropoint\else\donetrue\fi
- \ifdim\scratchrightoffset =\zeropoint\else\donetrue\fi
- \ifdim\scratchtopoffset =\zeropoint\else\donetrue\fi
- \ifdim\scratchbottomoffset=\zeropoint\else\donetrue\fi
+ \ifzeropt\scratchleftoffset \else\donetrue\fi
+ \ifzeropt\scratchrightoffset \else\donetrue\fi
+ \ifzeropt\scratchtopoffset \else\donetrue\fi
+ \ifzeropt\scratchbottomoffset\else\donetrue\fi
\ifdone
\edef\p_method{\offsetboxparameter\c!method}%
\ifx\p_method\v!fixed % new
- \ifdim\scratchleftoffset=\zeropoint
- \ifdim\scratchrightoffset=\zeropoint \else
+ \ifzeropt\scratchleftoffset
+ \ifzeropt\scratchrightoffset \else
\scratchxposition-\scratchrightoffset
\scratchrightoffset\zeropoint
\fi
@@ -929,8 +929,8 @@
\scratchxposition\scratchleftoffset
\scratchleftoffset\zeropoint
\fi
- \ifdim\scratchtopoffset=\zeropoint
- \ifdim\scratchbottomoffset=\zeropoint \else
+ \ifzeropt\scratchtopoffset
+ \ifzeropt\scratchbottomoffset \else
\scratchyposition-\scratchbottomoffset
\scratchbottomoffset\zeropoint
\fi
diff --git a/Master/texmf-dist/tex/context/base/mkiv/pack-com.mkiv b/Master/texmf-dist/tex/context/base/mkiv/pack-com.mkiv
index 1c6f2de7361..fe622509a10 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/pack-com.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/pack-com.mkiv
@@ -227,26 +227,74 @@
\newtoks\everycombination
+% \def\pack_combinations_start[#1][#2]% needs a cleanup, also nx ny (pretty old, this one)
+% {\edef\currentcombination{#1}%
+% \edef\currentcombinationspec{#2}%
+% \ifx\currentcombinationspec\empty
+% \doifelseassignment{#1}%
+% {\let\currentcombination\empty
+% \setupcurrentcombination[#1]%
+% \edef\currentcombinationspec{\combinationparameter\c!nx*\combinationparameter\c!ny*}}
+% {\doifelseinstring{*}\currentcombination
+% {\edef\currentcombinationspec{\currentcombination*\plusone*}%
+% \let\currentcombination\empty}
+% {\doifelsenumber\currentcombination
+% {\edef\currentcombinationspec{\currentcombination*\plusone*}%
+% \let\currentcombination\empty}
+% {\edef\currentcombinationspec{\combinationparameter\c!nx*\combinationparameter\c!ny*}}}}%
+% \else
+% \doifelseassignment{#2}%
+% {\setupcurrentcombination[#2]%
+% \edef\currentcombinationspec{\combinationparameter\c!nx*\combinationparameter\c!ny*}}
+% {\edef\currentcombinationspec{\currentcombinationspec*\plusone*}}%
+% \fi
+% %
+% \forgetall
+% %
+% \the\everycombination
+% %
+% \let\startcontent\pack_common_content_start
+% \let\stopcontent \pack_common_content_stop
+% \let\startcaption\pack_common_caption_start
+% \let\stopcaption \pack_common_caption_stop
+% %
+% \edef\p_height {\combinationparameter\c!height}%
+% \edef\p_width {\combinationparameter\c!width}%
+% \edef\p_location{\combinationparameter\c!location}%
+% \edef\p_distance{\combinationparameter\c!distance}%
+% %
+% \pack_combinations_location_reset
+% \rawprocesscommacommand[\p_location]\pack_combinations_location_step
+% %
+% \dostarttaggedchained\t!combination\currentcombination\??combination
+% \vbox \ifx\p_height\v!fit\else to \p_height \fi \bgroup
+% \let\combination\empty % permits \combination{}{} handy for cld
+% \normalexpanded{\pack_combinations_start_indeed[\currentcombinationspec]}}
+
\def\pack_combinations_start[#1][#2]% needs a cleanup, also nx ny (pretty old, this one)
{\edef\currentcombination{#1}%
\edef\currentcombinationspec{#2}%
\ifx\currentcombinationspec\empty
- \doifelseassignment{#1}%
- {\let\currentcombination\empty
- \setupcurrentcombination[#1]%
- \edef\currentcombinationspec{\combinationparameter\c!nx*\combinationparameter\c!ny*}}
- {\doifelseinstring{*}\currentcombination
- {\edef\currentcombinationspec{\currentcombination*\plusone*}%
- \let\currentcombination\empty}
- {\doifelsenumber\currentcombination
- {\edef\currentcombinationspec{\currentcombination*\plusone*}%
- \let\currentcombination\empty}
- {\edef\currentcombinationspec{\combinationparameter\c!nx*\combinationparameter\c!ny*}}}}%
+ \ifcondition\validassignment{#1}%
+ \let\currentcombination\empty
+ \setupcurrentcombination[#1]%
+ \edef\currentcombinationspec{\combinationparameter\c!nx*\combinationparameter\c!ny*}%
+ \else
+ \doifelseinstring{*}\currentcombination
+ {\edef\currentcombinationspec{\currentcombination*\plusone*}%
+ \let\currentcombination\empty}
+ {\doifelsenumber\currentcombination
+ {\edef\currentcombinationspec{\currentcombination*\plusone*}%
+ \let\currentcombination\empty}
+ {\edef\currentcombinationspec{\combinationparameter\c!nx*\combinationparameter\c!ny*}}}%
+ \fi
\else
- \doifelseassignment{#2}%
- {\setupcurrentcombination[#2]%
- \edef\currentcombinationspec{\combinationparameter\c!nx*\combinationparameter\c!ny*}}
- {\edef\currentcombinationspec{\currentcombinationspec*\plusone*}}%
+ \ifcondition\validassignment{#2}%
+ \setupcurrentcombination[#2]%
+ \edef\currentcombinationspec{\combinationparameter\c!nx*\combinationparameter\c!ny*}%
+ \else
+ \edef\currentcombinationspec{\currentcombinationspec*\plusone*}%
+ \fi
\fi
%
\forgetall
@@ -521,10 +569,8 @@
{\pack_combinations_float_hack_a{\recurselevel}}%
{\pack_combinations_float_hack_b{\recurselevel}}%
\to\scratchtoks}% brrr
- \let\pack_combinations_check_x_y\pack_combinations_float_check_x_y
- \doifassignmentelse{#1}
- {\expanded{\startcombination[#1]\the\scratchtoks}\stopcombination}%
- {\expanded{\startcombination[#1]\the\scratchtoks}\stopcombination}%
+ \let\pack_combinations_check_x_y\pack_combinations_float_check_x_y
+ \expanded{\startcombination[#1]\the\scratchtoks}\stopcombination
\resetlocalfloats
\egroup}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/pack-lyr.mkiv b/Master/texmf-dist/tex/context/base/mkiv/pack-lyr.mkiv
index e7070cfdec1..e952a73b98f 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/pack-lyr.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/pack-lyr.mkiv
@@ -19,18 +19,16 @@
\unprotect
-% When being backgrounds layers get the background offset
-% displacement. Should be an option, on by default
-% (compatibility).
+% When being backgrounds layers get the background offset displacement. Should be
+% an option, on by default (compatibility).
-%D The layering mechanism implemented here is independent of
-%D the output routine, but future extensions may depend on a
-%D more close cooperation.
-
-%D First we overload a macro from \type {pack-rul}. From now on
-%D we accept a (optional) argument: the specific layer it
-%D will go in. This means that we can move an overlay from one
-%D background to the other using the dimensions of the parent.
+%D The layering mechanism implemented here is independent of the output routine, but
+%D future extensions may depend on a more close cooperation.
+%D
+%D First we overload a macro from \type {pack-rul}. From now on we accept a
+%D (optional) argument: the specific layer it will go in. This means that we can
+%D move an overlay from one background to the other using the dimensions of the
+%D parent.
\ifdefined\defineoverlay \else \message{loaded to early} \wait \fi
@@ -46,13 +44,12 @@
\fi
\processcommalist[#1]\pack_framed_define_overlay_indeed}
-%D We use the command handler code. The previous, more direct parameter
-%D handling was 25\% faster when no parameters were passed when adding
-%D content to a layer. However, when we pass for instance a preset, the
-%D new methos is some 10\% faster and it happens that in most cases we
-%D do pass some parameters. It would be interesting to see if we can push
-%D the preset in between the regular chain but it could also lead to
-%D unwanted side effects when nesting layer placement.
+%D We use the command handler code. The previous, more direct parameter handling was
+%D 25\% faster when no parameters were passed when adding content to a layer.
+%D However, when we pass for instance a preset, the new methos is some 10\% faster
+%D and it happens that in most cases we do pass some parameters. It would be
+%D interesting to see if we can push the preset in between the regular chain but it
+%D could also lead to unwanted side effects when nesting layer placement.
\installcorenamespace{layer}
\installcorenamespace{layerbox}
@@ -62,13 +59,11 @@
%D \macros
%D {definelayer,setuplayer}
%D
-%D Each layer gets its own (global) box. This also means that
-%D the data that goes into a layer, is typeset immediately.
-%D Each layer automatically gets an associated overlay,
-%D which can be used in any background assignment.
+%D Each layer gets its own (global) box. This also means that the data that goes
+%D into a layer, is typeset immediately. Each layer automatically gets an associated
+%D overlay, which can be used in any background assignment.
%D
-%D After a layer is defined, you can change its
-%D characteristics.
+%D After a layer is defined, you can change its characteristics.
\installcommandhandler \??layer {layer} \??layer
@@ -175,8 +170,7 @@
%D \macros
%D {resetlayer}
%D
-%D This macro hardly needs an explanation (but is seldom
-%D needed anyway).
+%D This macro hardly needs an explanation (but is seldom needed anyway).
\def\pack_layers_reset_box#1%
{\ifcsname\??layerbox#1\endcsname
@@ -193,10 +187,9 @@
%D \macros
%D {setlayer}
%D
-%D Data is moved into a layer with the following macro. When
-%D \type {position} is set, relative positioning is used, with
-%D the current point as reference point. Otherwise the topleft
-%D corner is used as reference point.
+%D Data is moved into a layer with the following macro. When \type {position} is
+%D set, relative positioning is used, with the current point as reference point.
+%D Otherwise the topleft corner is used as reference point.
%D
%D \starttyping
%D \setlayer [identifier] [optional parameters] {data}
@@ -474,11 +467,10 @@
{\ifdim\d_pack_layers_x_size>\zeropoint \advance\d_pack_layers_x_position.5\d_pack_layers_x_size \fi
\ifdim\d_pack_layers_y_size>\zeropoint \advance\d_pack_layers_y_position.5\d_pack_layers_y_size \fi}
-%D Given the task to be accomplished, the previous macro is
-%D not even that complicated. It mainly comes down to skipping
-%D to the right place and placing a box on top of or below the
-%D existing content. In the case of position tracking, another
-%D reference point is chosen.
+%D Given the task to be accomplished, the previous macro is not even that
+%D complicated. It mainly comes down to skipping to the right place and placing a
+%D box on top of or below the existing content. In the case of position tracking,
+%D another reference point is chosen.
%D \macros
%D {doifelselayerdata}
@@ -500,10 +492,9 @@
%D \macros
%D {flushlayer}
%D
-%D When we flush a layer, we flush both the main one and the
-%D page dependent one (when defined). This feature is more
-%D efficient in \ETEX\ since there testing for an undefined
-%D macro does not takes hash space.
+%D When we flush a layer, we flush both the main one and the page dependent one
+%D (when defined). This feature is more efficient in \ETEX\ since there testing for
+%D an undefined macro does not takes hash space.
% todo: setups before flush, handy hook
@@ -593,22 +584,22 @@
\def\pack_layers_flush_double#1%
{\startoverlay
{\ifcsname\??layerbox\currentlayer\endcsname
- \ifvoid\lastnamedcss\else \chardef\b_layer_two\lastnamedcs
+ \ifvoid\lastnamedcs\else \chardef\b_layer_two\lastnamedcs
\pack_layers_flush_indeed\plusone\currentlayer\b_layer_two
\fi
\fi}%
{\ifcsname\??layerbox\currentlayer:\the\realpageno\endcsname
- \ifvoid\lastnamedcss\else \chardef\b_layer_two\lastnamedcs
+ \ifvoid\lastnamedcs\else \chardef\b_layer_two\lastnamedcs
\pack_layers_flush_indeed\zerocount{\currentlayer:\the\realpageno}\b_layer_two
\fi
\fi}%
{\ifcsname\??layerbox#1\currentlayer\endcsname
- \ifvoid\lastnamedcss\else \chardef\b_layer_two\lastnamedcs
+ \ifvoid\lastnamedcs\else \chardef\b_layer_two\lastnamedcs
\pack_layers_flush_indeed\plusone{#1\currentlayer}\b_layer_two
\fi
\fi}%
{\ifcsname\??layerbox#1\currentlayer:\the\realpageno\endcsname
- \ifvoid\lastnamedcss\else \chardef\b_layer_two\lastnamedcs
+ \ifvoid\lastnamedcs\else \chardef\b_layer_two\lastnamedcs
\pack_layers_flush_indeed\zerocount{#1\currentlayer:\the\realpageno}\b_layer_two
\fi
\fi}%
@@ -709,9 +700,8 @@
%D \macros
%D {composedlayer,placelayer,tightlayer}
%D
-%D This is a handy shortcut, which saves a couple of braces
-%D when we use it as parameter. This name also suits better
-%D to other layering commands.
+%D This is a handy shortcut, which saves a couple of braces when we use it as
+%D parameter. This name also suits better to other layering commands.
\unexpanded\def\composedlayer#1{\flushlayer[#1]}
@@ -736,8 +726,7 @@
%D \macros
%D {setMPlayer}
%D
-%D The following layer macro uses the positions that are
-%D registered by \METAPOST.
+%D The following layer macro uses the positions that are registered by \METAPOST.
%D
%D \starttyping
%D \definelayer[test]
diff --git a/Master/texmf-dist/tex/context/base/mkiv/pack-lyr.mkxl b/Master/texmf-dist/tex/context/base/mkiv/pack-lyr.mkxl
new file mode 100644
index 00000000000..43460092e7e
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/pack-lyr.mkxl
@@ -0,0 +1,794 @@
+%D \module
+%D [ file=pack-lyr,
+%D version=2000.10.20,
+%D title=\CONTEXT\ Packaging Macros,
+%D subtitle=Layers,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Packaging Macros / Layers}
+
+% todo : first / last / next / +... => page key
+% test on left/right box when no doublesided option given
+% use \ifcsname instead of doifvalue
+
+\unprotect
+
+% When being backgrounds layers get the background offset displacement. Should be
+% an option, on by default (compatibility).
+
+%D The layering mechanism implemented here is independent of the output routine, but
+%D future extensions may depend on a more close cooperation.
+%D
+%D First we overload a macro from \type {pack-rul}. From now on we accept a
+%D (optional) argument: the specific layer it will go in. This means that we can
+%D move an overlay from one background to the other using the dimensions of the
+%D parent.
+
+\ifdefined\defineoverlay \else \message{loaded to early} \wait \fi
+
+\unexpanded\def\defineoverlay
+ {\dotripleempty\pack_framed_define_overlay}
+
+\def\pack_framed_define_overlay[#1][#2][#3]% overlay [layer] content
+ {\ifthirdargument
+ %\writestatus{BEWARE}{This (overlay definition) has changed!}% temp
+ \def\pack_framed_define_overlay_indeed##1{\setvalue{\??overlay##1}{\setlayer[#2]{\executedefinedoverlay{##1}{#3}}}}%
+ \else
+ \def\pack_framed_define_overlay_indeed##1{\setvalue{\??overlay##1}{\executedefinedoverlay{##1}{#2}}}%
+ \fi
+ \processcommalist[#1]\pack_framed_define_overlay_indeed}
+
+%D We use the command handler code. The previous, more direct parameter handling was
+%D 25\% faster when no parameters were passed when adding content to a layer.
+%D However, when we pass for instance a preset, the new methos is some 10\% faster
+%D and it happens that in most cases we do pass some parameters. It would be
+%D interesting to see if we can push the preset in between the regular chain but it
+%D could also lead to unwanted side effects when nesting layer placement.
+
+\installcorenamespace{layer}
+\installcorenamespace{layerbox}
+\installcorenamespace{layerpreset}
+\installcorenamespace{layerposition} % brr, unreadable
+
+%D \macros
+%D {definelayer,setuplayer}
+%D
+%D Each layer gets its own (global) box. This also means that the data that goes
+%D into a layer, is typeset immediately. Each layer automatically gets an associated
+%D overlay, which can be used in any background assignment.
+%D
+%D After a layer is defined, you can change its characteristics.
+
+\installcommandhandler \??layer {layer} \??layer
+
+\setuplayer
+ [\c!state=\v!start,
+ %\c!doublesided=,
+ %\c!preset=,
+ %\c!option=,
+ %\c!corner=,
+ %\c!page=,
+ %\c!rotation=, % geen 0 !
+ \c!direction=\v!normal,
+ \c!position=\v!no,
+ \c!method=\v!overlay,
+ \c!x=\zeropoint,
+ \c!y=\zeropoint,
+ \c!line=0,
+ \c!column=0,
+ \c!width=\wd\nextbox, % don't change this globally
+ \c!height=\ht\nextbox, % don't change this globally
+ \c!offset=\zeropoint,
+ \c!hoffset=\zeropoint,
+ \c!voffset=\zeropoint,
+ \c!dx=\zeropoint,
+ \c!dy=\zeropoint,
+ \c!location=rb,
+ \c!sx=1,
+ \c!sy=1,
+ \c!region=\layeranchor]
+
+\def\layeranchor{\currentlayer:\the\realpageno}
+
+\let\p_pack_layers_doublesided\empty
+\let\p_pack_layers_state \empty
+\let\p_pack_layers_option \empty
+\let\p_pack_layers_method \empty
+\let\p_pack_layers_preset \empty
+\let\p_pack_layers_rotation \empty
+\let\p_pack_layers_position \empty
+\let\p_pack_layers_hoffset \empty
+\let\p_pack_layers_voffset \empty
+\let\p_pack_layers_offset \empty
+\let\p_pack_layers_dx \empty
+\let\p_pack_layers_dy \empty
+\let\p_pack_layers_sx \empty
+\let\p_pack_layers_sy \empty
+\let\p_pack_layers_x \empty
+\let\p_pack_layers_y \empty
+\let\p_pack_layers_corner \empty
+\let\p_pack_layers_location \empty
+\let\p_pack_layers_line \empty
+\let\p_pack_layers_column \empty
+\let\p_pack_layers_width \empty
+\let\p_pack_layers_height \empty
+\let\p_pack_layers_direction \empty
+\let\p_pack_layers_region \empty
+
+\let\m_pack_layers_page \empty
+\let\m_pack_layers_target \empty
+\let\m_pack_layers_region \empty
+\let\m_pack_layers_anchor \empty
+
+\newconditional\c_pack_layers_repeated
+\newconditional\c_pack_layers_trace
+\newcount \c_pack_layers_current_data
+
+\newbox\b_layers
+
+\newdimen\d_pack_layers_x_size
+\newdimen\d_pack_layers_y_size
+\newdimen\d_pack_layers_x_offset
+\newdimen\d_pack_layers_y_offset
+\newdimen\d_pack_layers_x_position
+\newdimen\d_pack_layers_y_position
+
+\newdimen\layerwidth
+\newdimen\layerheight
+
+\let\lastlayerxpos\!!zeropoint
+\let\lastlayerypos\!!zeropoint
+\let\lastlayerwd \!!zeropoint
+\let\lastlayerht \!!zeropoint
+\let\lastlayerdp \!!zeropoint
+
+\appendtoks
+ \edef\p_pack_layers_doublesided{\layerparameter\c!doublesided}%
+ \ifx\p_pack_layers_doublesided\v!yes
+ \relateparameterhandlers{layer}{\v!left \currentlayer}{layer}\currentlayer % permits left*
+ \relateparameterhandlers{layer}{\v!right\currentlayer}{layer}\currentlayer % permits right*
+ \pack_layers_preset_box{\v!left \currentlayer}%
+ \pack_layers_preset_box{\v!right\currentlayer}%
+ \fi
+ \pack_layers_preset_box\currentlayer
+ \normalexpanded{\defineoverlay[\currentlayer][\noexpand\composedlayer{\currentlayer}]}%
+\to \everydefinelayer
+
+\def\pack_layers_preset_box#1%
+ {\ifcsname\??layerbox#1\endcsname
+ \resetlayer[#1]%
+ \else
+ \expandafter\newbox\csname\??layerbox#1\endcsname
+ \fi}
+
+%D \macros
+%D {resetlayer}
+%D
+%D This macro hardly needs an explanation (but is seldom needed anyway).
+
+\def\pack_layers_reset_box#1%
+ {\ifcsname\??layerbox#1\endcsname
+ %\global\setbox\csname\??layerbox#1\endcsname\emptybox
+ \global\setbox\lastnamedcs\emptybox
+ \fi}
+
+\def\resetlayer[#1]%
+ {\pack_layers_reset_box{#1}%
+ \pack_layers_reset_box{\v!left #1}%
+ \pack_layers_reset_box{\v!right#1}%
+ \pack_layers_reset_box{#1:\the\realpageno}}
+
+%D \macros
+%D {setlayer}
+%D
+%D Data is moved into a layer with the following macro. When \type {position} is
+%D set, relative positioning is used, with the current point as reference point.
+%D Otherwise the topleft corner is used as reference point.
+%D
+%D \starttyping
+%D \setlayer [identifier] [optional parameters] {data}
+%D \stoptyping
+
+\def\setcurrentlayerdimensions
+ {\dodoubleempty\pack_layers_set_current_dimensions}
+
+\def\pack_layers_set_current_dimensions[#1][#2]% name left|right
+ {\edef\currentlayerwidth {\thelayerwidth {#2#1}}%
+ \edef\currentlayerheight{\thelayerheight{#2#1}}}
+
+\def\thelayerwidth #1{\the\ifcsname\??layerbox#1\endcsname\wd\lastnamedcs\else\zeropoint\fi}
+\def\thelayerheight#1{\the\ifcsname\??layerbox#1\endcsname\ht\lastnamedcs\else\zeropoint\fi}
+
+\unexpanded\def\setlayer
+ {\dotripleempty\pack_layers_set}
+
+\def\pack_layers_set[#1][#2][#3]% #4 == box do \fi is ok
+ {\bgroup
+ \checkpositionoverlays % otherwise funny regions
+ \edef\currentlayer{#1}%
+ \edef\p_pack_layers_state{\layerparameter\c!state}%
+ \ifx\p_pack_layers_state\v!stop
+ \dowithnextboxcs\egroup\hbox % no pack ?
+ \orelse\ifthirdargument
+ \pack_layers_set_indeed[#1][#2][#3]%
+ \else
+ \ifcondition\validassignment{#2}%
+ \pack_layers_set_indeed[#1][][#2]%
+ \else
+ \pack_layers_set_indeed[#1][#2][]%
+ \fi
+ \fi}
+
+\def\pack_layers_set_indeed[#1][#2][#3]% #2 = links/rechts
+ {\page_backgrounds_recalculate % brrr
+ \global\advance\c_pack_layers_current_data\plusone
+ \forgetall
+ \dontcomplain
+ \edef\p_pack_layers_option{\layerparameter\c!option}%
+ \ifx\p_pack_layers_option\v!test
+ \settrue\c_pack_layers_trace
+ \traceboxplacementtrue
+ \fi
+ \edef\m_pack_layers_target{#2}%
+ \dowithnextbox{\pack_layers_set_finish{#3}}\hbox}
+
+\def\pack_layers_set_finish#1%
+ {\ifcsname\??layerbox\currentlayer\endcsname % can move up
+ \ifx\m_pack_layers_target\v!even
+ \ifodd\realpageno
+ % discard nextbox
+ \else
+ \let\m_pack_layers_target\v!left
+ \pack_layers_set_content{#1}%
+ \fi
+ \orelse\ifx\m_pack_layers_target\v!odd
+ \ifodd\realpageno
+ \let\m_pack_layers_target\v!right
+ \pack_layers_set_content{#1}%
+ \else
+ % discard nextbox
+ \fi
+ \else
+ \pack_layers_set_content{#1}%
+ \fi
+ \else
+ \writestatus{layer}{unknown layer \currentlayer}%
+ \fi
+ \egroup}
+
+% todo: left/right
+% todo: get position data in one go
+
+\def\pack_layers_set_last_position_yes % target: left|right
+ {% this will become one call
+ \edef\m_pack_layers_anchor{\??layerposition\the\c_pack_layers_current_data}%
+ \edef\m_pack_layers_page {\MPp\m_pack_layers_anchor}%
+ %edef\m_pack_layers_region{\MPr\m_pack_layers_anchor}% wrong one
+ \edef\m_pack_layers_region{\layerparameter\c!region}%
+ \d_pack_layers_x_position \dimexpr-\MPx\m_pack_layers_region+\MPx\m_pack_layers_anchor\relax
+ \d_pack_layers_y_position \dimexpr \MPy\m_pack_layers_region-\MPy\m_pack_layers_anchor+\MPh\m_pack_layers_region\relax
+ \xdef\lastlayerxpos{\the\d_pack_layers_x_position}%
+ \xdef\lastlayerypos{\the\d_pack_layers_y_position}%
+ % \writestatus{layering}{region: \m_pack_layers_region=>\MPxywhd\m_pack_layers_region}%
+ % \writestatus {}{anchor: \m_pack_layers_anchor=>\MPxywhd\m_pack_layers_anchor}%
+ % \writestatus {}{offset: \c!dx,\c!dy =>\lastlayerxpos,\lastlayerypos}%
+ \global\letlayerparameter\c!state\v!start % needed ?
+ \setbox\b_layers\vpack to \d_pack_layers_y_size
+ {\hpack to \d_pack_layers_x_size
+ {\xypos\m_pack_layers_anchor\hss}%
+ \vss}}
+
+\def\pack_layers_set_last_position_nop
+ {\setbox\b_layers\emptybox
+ \d_pack_layers_x_position\p_pack_layers_sx\dimexpr\p_pack_layers_x\relax
+ \d_pack_layers_y_position\p_pack_layers_sy\dimexpr\p_pack_layers_y\relax
+ \glet\lastlayerxpos\!!zeropoint
+ \glet\lastlayerypos\!!zeropoint
+ \doifinset\v!bottom\p_pack_layers_corner\pack_layers_set_bottom_positions
+ \doifinset\v!right \p_pack_layers_corner\pack_layers_set_right_positions
+ \doifinset\v!middle\p_pack_layers_corner\pack_layers_set_middle_positions
+ \edef\m_pack_layers_page{\layerparameter\c!page}}
+
+\unexpanded\def\definelayerpreset
+ {\dodoubleargument\pack_layers_define_preset}
+
+\def\pack_layers_define_preset[#1][#2]%
+ {\doifelseassignment{#2}
+ {\setvalue{\??layerpreset#1}{\setupcurrentlayer[#2]}}
+ {\setvalue{\??layerpreset#1}{\csname\??layerpreset#2\endcsname}}}
+
+\def\pack_layers_set_content#1%
+ {\layerwidth \layerparameter\c!width % global (local later)
+ \layerheight\layerparameter\c!height % global (local later)
+ \d_pack_layers_x_size\layerwidth
+ \d_pack_layers_y_size\layerheight
+ %
+ \setupcurrentlayer[#1]% preroll
+ %
+ \edef\p_pack_layers_preset {\layerparameter\c!preset }%
+ %
+ \ifcsname\??layerpreset\p_pack_layers_preset\endcsname
+ \lastnamedcs
+ \setupcurrentlayer[#1]% postroll
+ \fi
+ %
+ \edef\p_pack_layers_rotation {\layerparameter\c!rotation }%
+ \edef\p_pack_layers_position {\layerparameter\c!position }%
+ \edef\p_pack_layers_hoffset {\layerparameter\c!hoffset }%
+ \edef\p_pack_layers_voffset {\layerparameter\c!voffset }%
+ \edef\p_pack_layers_offset {\layerparameter\c!offset }%
+ \edef\p_pack_layers_dx {\layerparameter\c!dx }%
+ \edef\p_pack_layers_dy {\layerparameter\c!dy }%
+ \edef\p_pack_layers_sx {\layerparameter\c!sx }%
+ \edef\p_pack_layers_sy {\layerparameter\c!sy }%
+ \edef\p_pack_layers_x {\layerparameter\c!x }%
+ \edef\p_pack_layers_y {\layerparameter\c!y }%
+ \edef\p_pack_layers_corner {\layerparameter\c!corner }%
+ \edef\p_pack_layers_location {\layerparameter\c!location }%
+ \edef\p_pack_layers_line {\layerparameter\c!line }%
+ \edef\p_pack_layers_column {\layerparameter\c!column }%
+ \edef\p_pack_layers_width {\layerparameter\c!width }% local ones
+ \edef\p_pack_layers_height {\layerparameter\c!height }% local ones
+ \edef\p_pack_layers_direction{\layerparameter\c!direction}%
+ %
+ \ifx\p_pack_layers_position\v!overlay
+ \let\p_pack_layers_width \zeropoint
+ \let\p_pack_layers_height \zeropoint
+ \let\p_pack_layers_position\v!yes
+ \fi
+ \ifx\p_pack_layers_rotation\empty \else
+ % use direct call
+ \setbox\nextbox\hpack
+ {\rotate[\c!location=\v!high,\c!rotation=\layerparameter\c!rotation]{\box\nextbox}}%
+ \fi
+ \d_pack_layers_x_offset\p_pack_layers_sx\dimexpr
+ \ifx\p_pack_layers_hoffset\v!max\d_pack_layers_x_size\else\p_pack_layers_hoffset\fi+\p_pack_layers_offset+\p_pack_layers_dx
+ \relax
+ \d_pack_layers_y_offset\p_pack_layers_sy\dimexpr
+ \ifx\p_pack_layers_voffset\v!max\d_pack_layers_y_size\else\p_pack_layers_voffset\fi+\p_pack_layers_offset+\p_pack_layers_dy
+ \relax
+ \ifx\p_pack_layers_position\v!yes
+ \pack_layers_set_last_position_yes
+ \else
+ \pack_layers_set_last_position_nop
+ \fi
+ %
+ \ifx\m_pack_layers_page\empty \else % is expanded
+ \edef\m_pack_layers_page{:\m_pack_layers_page}%
+ \ifcsname\??layerbox\m_pack_layers_target\currentlayer\m_pack_layers_page\endcsname \else
+ \expandafter\newbox\csname\??layerbox\m_pack_layers_target\currentlayer\m_pack_layers_page\endcsname
+ \fi
+ \fi
+ \chardef\layerpagebox\csname\??layerbox\m_pack_layers_target\currentlayer\m_pack_layers_page\endcsname
+ \ifvoid\layerpagebox
+ \gsetboxllx\layerpagebox\zeropoint
+ \gsetboxlly\layerpagebox\zeropoint
+ \fi
+ \global\setbox\layerpagebox\vpack %to \layerparameter\c!height % new, otherwise no negative y possible
+ {\offinterlineskip
+ \ifvoid\layerpagebox
+ \let\lastlayerwidth \zeropoint
+ \let\lastlayerheight\zeropoint
+ \else
+ \edef\lastlayerwidth {\the\wd\layerpagebox}%
+ \edef\lastlayerheight{\the\ht\layerpagebox}%
+ \ht\layerpagebox\zeropoint
+ \dp\layerpagebox\zeropoint
+ \wd\layerpagebox\zeropoint
+ \ifx\p_pack_layers_direction\v!reverse\else
+ \box\layerpagebox
+ \fi
+ \fi
+ % don't move
+ \xdef\lastlayerwd{\the\wd\nextbox}%
+ \xdef\lastlayerht{\the\ht\nextbox}% % not entirely ok when grid !
+ \xdef\lastlayerdp{\the\dp\nextbox}% % not entirely ok when grid !
+ % this code
+ \ifx\p_pack_layers_location\v!grid
+ \ht\nextbox\strutheight
+ \dp\nextbox\strutdepth
+ \else
+ \setbox\nextbox\hpack
+ {\alignedbox[\p_pack_layers_location]\vpack{\box\nextbox}}%
+ \fi
+ \ifnum\p_pack_layers_line=\zerocount\else % no \ifcase, can be negative
+ \advance\d_pack_layers_y_position\dimexpr\p_pack_layers_line\lineheight+\topskip-\lineheight-\ht\nextbox\relax
+ \fi
+ \ifnum\p_pack_layers_column=\zerocount\else % no \ifcase, can be negative
+ \advance\d_pack_layers_x_position\layoutcolumnoffset\p_pack_layers_column\relax
+ \fi
+ \ifx\p_pack_layers_location\v!grid
+ \setbox\nextbox\hpack
+ {\alignedbox[rb]\vpack{\box\nextbox}}%
+ \fi
+ % ll registration
+ \scratchdimen\dimexpr\d_pack_layers_x_position+\d_pack_layers_x_offset\relax
+ \ifdim\scratchdimen<\getboxllx\layerpagebox
+ \gsetboxllx\layerpagebox\scratchdimen
+ \fi
+ \advance\scratchdimen\wd\nextbox
+ \wd\nextbox\ifdim\scratchdimen>\lastlayerwidth \scratchdimen \else \lastlayerwidth \fi
+ \scratchdimen\dimexpr\d_pack_layers_y_position+\d_pack_layers_y_offset\relax
+ \ifdim\scratchdimen<\getboxlly\layerpagebox
+ \gsetboxlly\layerpagebox\scratchdimen
+ \fi
+ % ll compensation
+ \advance\scratchdimen\dimexpr\ht\nextbox+\dp\nextbox\relax
+ \ht\nextbox\ifdim\scratchdimen>\lastlayerheight \scratchdimen \else \lastlayerheight \fi
+ \dp\nextbox\zeropoint
+ % placement
+ \hsize\p_pack_layers_width
+ \vpack to \p_pack_layers_height \bgroup
+ \smashbox\nextbox
+ \vskip\dimexpr\d_pack_layers_y_position+\d_pack_layers_y_offset\relax
+ \hskip\dimexpr\d_pack_layers_x_position+\d_pack_layers_x_offset\relax
+ % or maybe instead of the \vskip
+ % \raise-\dimexpr\d_pack_layers_y_position+\d_pack_layers_y_offset\relax
+ \box\nextbox
+ \ifvoid\layerpagebox
+ % already flushed
+ \else
+ % the reverse case % check !
+ \vskip-\dimexpr\d_pack_layers_y_position+\d_pack_layers_y_offset\relax
+ \box\layerpagebox
+ \fi
+ \egroup}%
+ % when position is true, the layerbox holds the compensation and needs
+ % to be placed; never change this !
+ \ifvoid\b_layers \else
+ \box\b_layers
+ \fi}
+
+\def\pack_layers_set_bottom_positions
+ {\ifnum\p_pack_layers_line=\zerocount\else % can be < 0
+ \edef\p_pack_layers_line{\the\numexpr-\p_pack_layers_line+\layoutlines+\plusone\relax}% use counter instead ?
+ \fi
+ \ifdim\d_pack_layers_y_size>\zeropoint
+ \advance\d_pack_layers_y_position-\d_pack_layers_y_size
+ \d_pack_layers_y_position-\d_pack_layers_y_position
+ \d_pack_layers_y_offset-\d_pack_layers_y_offset
+ \fi}
+
+\def\pack_layers_set_right_positions
+ {\ifnum\p_pack_layers_column=\zerocount\else % can be < 0
+ \edef\p_pack_layers_column{\the\numexpr-\layerparameter\c!column+\layoutcolumns+\plusone\relax}% use counter instead ?
+ \fi
+ \ifdim\d_pack_layers_x_size>\zeropoint
+ \advance\d_pack_layers_x_position-\d_pack_layers_x_size
+ \d_pack_layers_x_position-\d_pack_layers_x_position
+ \d_pack_layers_x_offset-\d_pack_layers_x_offset
+ \fi}
+
+\def\pack_layers_set_middle_positions
+ {\ifdim\d_pack_layers_x_size>\zeropoint \advance\d_pack_layers_x_position.5\d_pack_layers_x_size \fi
+ \ifdim\d_pack_layers_y_size>\zeropoint \advance\d_pack_layers_y_position.5\d_pack_layers_y_size \fi}
+
+%D Given the task to be accomplished, the previous macro is not even that
+%D complicated. It mainly comes down to skipping to the right place and placing a
+%D box on top of or below the existing content. In the case of position tracking,
+%D another reference point is chosen.
+
+%D \macros
+%D {doifelselayerdata}
+
+\def\doifelselayerdata#1%
+ {\ifcsname\??layerbox#1\endcsname
+ %\ifvoid\csname\??layerbox#1\endcsname
+ \ifvoid\lastnamedcs
+ \doubleexpandafter\secondoftwoarguments
+ \else
+ \doubleexpandafter\firstoftwoarguments
+ \fi
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\let\doiflayerdataelse\doifelselayerdata
+
+%D \macros
+%D {flushlayer}
+%D
+%D When we flush a layer, we flush both the main one and the page dependent one
+%D (when defined). This feature is more efficient in \ETEX\ since there testing for
+%D an undefined macro does not takes hash space.
+
+% todo: setups before flush, handy hook
+
+\unexpanded\def\flushlayer[#1]% quite core, so optimized (todo: check for void)
+ {\begingroup
+ \forgetall
+ \edef\currentlayer{#1}%
+ \edef\p_pack_layers_state{\layerparameter\c!state}%
+ \ifx\p_pack_layers_state\v!stop
+ % nothing
+ \orelse\ifx\p_pack_layers_state\v!next
+ \global\letlayerparameter\c!state\v!start % dangerous, stack-built-up
+ \orelse\ifx\p_pack_layers_state\v!continue
+ \global\letlayerparameter\c!state\v!repeat % dangerous, stack-built-up
+ \else
+ \edef\p_pack_layers_doublesided{\layerparameter\c!doublesided}%
+ \ifx\p_pack_layers_doublesided\v!yes
+ \ifcsname\??layerbox#1\endcsname
+ % we can make a dedicated one for this
+ \doifbothsidesoverruled
+ {\pack_layers_flush_double\v!left }%
+ {\pack_layers_flush_double\v!right}%
+ {\pack_layers_flush_double\v!left }%
+ \else
+ \pack_layers_flush_single
+ \fi
+ \else
+ \pack_layers_flush_single
+ \fi
+ \fi
+ \endgroup}
+
+% \def\pack_layers_flush_single
+% {\startoverlay
+% {\ifcsname\??layerbox \currentlayer \endcsname\pack_layers_flush_indeed\plusone \currentlayer \fi}%
+% {\ifcsname\??layerbox \currentlayer:\the\realpageno\endcsname\pack_layers_flush_indeed\zerocount{\currentlayer:\the\realpageno}\fi}%
+% \stopoverlay}
+%
+% \def\pack_layers_flush_double#1%
+% {\startoverlay
+% {\ifcsname\??layerbox \currentlayer \endcsname\pack_layers_flush_indeed\plusone \currentlayer \fi}%
+% {\ifcsname\??layerbox \currentlayer:\the\realpageno\endcsname\pack_layers_flush_indeed\zerocount {\currentlayer:\the\realpageno}\fi}%
+% {\ifcsname\??layerbox#1\currentlayer \endcsname\pack_layers_flush_indeed\plusone {#1\currentlayer }\fi}%
+% {\ifcsname\??layerbox#1\currentlayer:\the\realpageno\endcsname\pack_layers_flush_indeed\zerocount{#1\currentlayer:\the\realpageno}\fi}%
+% \stopoverlay}
+
+% optimized:
+
+\def\pack_layers_flush_single
+ {\ifcsname\??layerbox\currentlayer\endcsname
+ \ifvoid\lastnamedcs
+ \ifcsname\??layerbox\currentlayer:\the\realpageno\endcsname
+ \ifvoid\lastnamedcs\else
+ \chardef\b_layer_two\lastnamedcs
+ \pack_layers_flush_indeed\zerocount{\currentlayer:\the\realpageno}\b_layer_two
+ \fi
+ \fi
+ \else
+ \chardef\b_layer_one\lastnamedcs
+ \ifcsname\??layerbox\currentlayer:\the\realpageno\endcsname
+ \ifvoid\lastnamedcs\else
+ \chardef\b_layer_two\lastnamedcs
+ \startoverlay
+ {\pack_layers_flush_indeed\plusone \currentlayer \b_layer_one}%
+ {\pack_layers_flush_indeed\zerocount{\currentlayer:\the\realpageno}\b_layer_two}%
+ \stopoverlay
+ \fi
+ \else
+ \pack_layers_flush_indeed\plusone\currentlayer\b_layer_one
+ \fi
+ \fi
+ \orelse\ifcsname\??layerbox\currentlayer:\the\realpageno\endcsname
+ \ifvoid\lastnamedcs
+ % nothing
+ \else
+ \chardef\b_layer_two\lastnamedcs
+ \pack_layers_flush_indeed\zerocount{\currentlayer:\the\realpageno}\b_layer_two
+ \fi
+ \fi}
+
+% less optimized:
+
+\def\pack_layers_flush_double#1%
+ {\startoverlay
+ {\ifcsname\??layerbox\currentlayer\endcsname
+ \ifvoid\lastnamedcs\else \chardef\b_layer_two\lastnamedcs
+ \pack_layers_flush_indeed\plusone\currentlayer\b_layer_two
+ \fi
+ \fi}%
+ {\ifcsname\??layerbox\currentlayer:\the\realpageno\endcsname
+ \ifvoid\lastnamedcs\else \chardef\b_layer_two\lastnamedcs
+ \pack_layers_flush_indeed\zerocount{\currentlayer:\the\realpageno}\b_layer_two
+ \fi
+ \fi}%
+ {\ifcsname\??layerbox#1\currentlayer\endcsname
+ \ifvoid\lastnamedcs\else \chardef\b_layer_two\lastnamedcs
+ \pack_layers_flush_indeed\plusone{#1\currentlayer}\b_layer_two
+ \fi
+ \fi}%
+ {\ifcsname\??layerbox#1\currentlayer:\the\realpageno\endcsname
+ \ifvoid\lastnamedcs\else \chardef\b_layer_two\lastnamedcs
+ \pack_layers_flush_indeed\zerocount{#1\currentlayer:\the\realpageno}\b_layer_two
+ \fi
+ \fi}%
+ \stopoverlay}
+
+\let\pack_layers_top_fill \relax
+\let\pack_layers_bottom_fill\vss
+
+%def\pack_layers_flush_indeed#1#2%
+\def\pack_layers_flush_indeed#1#2#3%
+ {\begingroup % already grouped
+ \offinterlineskip
+ \edef\p_pack_layers_preset{\layerparameter\c!preset}%
+ \ifcsname\??layerpreset\p_pack_layers_preset\endcsname
+ \lastnamedcs
+ \fi
+ \edef\p_pack_layers_method{\layerparameter\c!method}%
+ \edef\p_pack_layers_option{\layerparameter\c!option}%
+ \ifx\p_pack_layers_option\v!test
+ \settrue\c_pack_layers_trace
+ \traceboxplacementtrue
+ \fi
+ \ifcase#1\relax
+ \setfalse\c_pack_layers_repeated
+ \else
+ \edef\p_pack_layers_position{\layerparameter\c!position}%
+ \ifx\p_pack_layers_position\v!yes
+ \setfalse\c_pack_layers_repeated
+ \else
+ \edef\p_pack_layers_repeat{\layerparameter\c!repeat}%
+ \ifx\p_pack_layers_repeat\v!yes
+ \settrue\c_pack_layers_repeated
+ \orelse\ifx\p_pack_layers_state\v!repeat
+ \settrue\c_pack_layers_repeated
+ \else
+ \setfalse\c_pack_layers_repeated
+ \fi
+ \fi
+ \fi
+ %chardef\b_layers\csname\??layerbox#2\endcsname % trick
+ \let\b_layers#3%
+ % we need to copy in order to retain the negative offsets for a next
+ % stage of additions, i.e. llx/lly accumulate in repeat mode and the
+ % compensation may differ each flush depending on added content
+ \setbox\nextbox
+ \ifx\p_pack_layers_method\v!fit
+ \pack_layers_positioned_box_yes
+ \else
+ \pack_layers_positioned_box_nop
+ \fi
+ % todo: method=offset => overlayoffset right/down (handy for backgrounds with offset)
+ \doifelseoverlay{#2}%
+ {\setlayoutcomponentattribute{\v!layer:#2}}%
+ \resetlayoutcomponentattribute
+ % we have conflicting demands: some mechanisms want ll anchoring .. I need to figure this out
+ % and maybe we will have 'origin=bottom' or so
+ \setbox\nextbox
+ \ifx\p_pack_layers_option\v!test \ruledvbox \else \vpack \fi \ifx\p_pack_layers_method\v!overlay to \d_overlay_height \fi \layoutcomponentboxattribute
+ {\pack_layers_top_fill
+%
+% \hpack \ifx\p_pack_layers_method\v!overlay to \d_overlay_width \fi
+% {\box\nextbox
+% \hss}%
+%
+ \ifx\p_pack_layers_method\v!overlay \wd\nextbox\d_overlay_width\fi
+ \box\nextbox
+%
+ \pack_layers_bottom_fill}%
+ % \edef\currentlayer{#2}% :\the\realpageno}% local .. check \anchor
+ % \edef\p_pack_layers_position{\layerparameter\c!position}% local
+ \ifx\p_pack_layers_position\v!yes
+ \edef\p_pack_layers_region{\layerparameter\c!region}%
+ \ifx\p_pack_layers_region\empty
+ \else
+ \anch_mark_tagged_box\nextbox\p_pack_layers_region % was \layeranchor
+ \fi
+ \fi
+ \box\nextbox
+ %
+ \ifconditional\c_pack_layers_repeated\else
+ \gsetboxllx\b_layers\zeropoint
+ \gsetboxlly\b_layers\zeropoint
+ \fi
+ \endgroup}
+
+\def\pack_layers_positioned_box_yes
+ {\vpack
+ {\vskip-\getboxlly\b_layers
+ \hskip-\getboxllx\b_layers
+ \hsize-\dimexpr\getboxllx\b_layers-\wd\b_layers\relax
+ \ifconditional\c_pack_layers_repeated\copy\else\box\fi\b_layers}}
+
+\def\pack_layers_positioned_box_nop
+ {\ifconditional\c_pack_layers_repeated\copy\else\box\fi\b_layers}
+
+% \definelayer[test][method=fit] \setupcolors[state=start,option=test]
+%
+% \framed[framecolor=red,offset=overlay]{\setlayer[test]{aa}\setlayer[test][x=10pt]{g}\flushlayer[test]}
+% \framed[framecolor=red,offset=overlay]{\setlayer[test]{aa}\setlayer[test][x=-10pt]{bb}\flushlayer[test]}
+% \framed[framecolor=red,offset=overlay]{\setlayer[test][x=-20pt]{cccccc}\flushlayer[test]}
+% \framed[framecolor=red,offset=overlay]{\setlayer[test]{dd}\setlayer[test][x=-20pt,y=-3pt]{eeeeee}\flushlayer[test]}
+
+%D \macros
+%D {composedlayer,placelayer,tightlayer}
+%D
+%D This is a handy shortcut, which saves a couple of braces when we use it as
+%D parameter. This name also suits better to other layering commands.
+
+\unexpanded\def\composedlayer#1{\flushlayer[#1]}
+
+\unexpanded\def\tightlayer[#1]%
+ {\hpack
+ {\def\currentlayer{#1}% todo: left/right
+ \setbox\nextbox\emptybox
+ \d_overlay_width \layerparameter\c!width
+ \d_overlay_height\layerparameter\c!height
+ \composedlayer{#1}}}
+
+\let\placelayer\flushlayer
+
+%D \macros
+%D {setMPlayer}
+%D
+%D The following layer macro uses the positions that are registered by \METAPOST.
+%D
+%D \starttyping
+%D \definelayer[test]
+%D
+%D \setMPlayer [test] [somepos-1] {Whatever we want here!}
+%D \setMPlayer [test] [somepos-2] {Whatever we need there!}
+%D \setMPlayer [test] [somepos-3] {\externalfigure[cow.mps][width=2cm]}
+%D
+%D \startuseMPgraphic{oeps}
+%D draw fullcircle scaled 10cm withcolor red ;
+%D register ("somepos-1",2cm,3cm,center currentpicture) ;
+%D register ("somepos-2",8cm,5cm,(-1cm,-2cm)) ;
+%D register ("somepos-3",0cm,0cm,(-2cm,2cm)) ;
+%D \stopuseMPgraphic
+%D
+%D \getMPlayer[test]{\useMPgraphic{oeps}}
+%D \stoptyping
+%D
+%D The last line is equivalent to
+%D
+%D \starttyping
+%D \framed
+%D [background={foreground,test},offset=overlay]
+%D {\useMPgraphic{oeps}}
+%D \stoptyping
+
+\unexpanded\def\setMPlayer
+ {\dotripleempty\pack_layers_set_MP}
+
+\def\MPlayerwidth {\hsize}
+\def\MPlayerheight{\vsize}
+
+\def\pack_layers_set_MP[#1][#2][#3]%
+ {\edef\MPlayerwidth {\MPw{#2}}%
+ \edef\MPlayerheight{\MPh{#2}}%
+ \setlayer[#1][\c!x=\MPx{#2},\c!y=\MPy{#2},\c!position=\v!no,#3]}
+
+\unexpanded\def\getMPlayer
+ {\dodoubleempty\pack_layers_get_MP}
+
+\def\pack_layers_get_MP[#1][#2]%
+ {\framed[\c!background={\v!foreground,#1},\c!frame=\v!off,\c!offset=\v!overlay,#2]} % takes argument
+
+%D Watch out, a redefinition:
+
+\ifdefined\settextpagecontent \else
+ \writestatus\m!system{error in page-lyr.tex} \wait
+\fi
+
+\definelayer
+ [OTRTEXT]
+
+\setuplayer
+ [OTRTEXT]
+ [\c!width=\innermakeupwidth,
+ \c!height=\textheight]
+
+\let\normalsettextpagecontent\settextpagecontent % will be overloaded in page-spr
+
+\unexpanded\def\settextpagecontent#1#2#3% #2 and #3 will disappear
+ {\doifelselayerdata{OTRTEXT}
+ {\setbox#1\hpack to \makeupwidth
+ {\startoverlay
+ {\tightlayer[OTRTEXT]} % first, otherwise problems with toc
+ {\normalsettextpagecontent{#1}{#2}{#3}\box#1}
+ \stopoverlay}%
+ \dp#1\zeropoint}%
+ {\normalsettextpagecontent{#1}{#2}{#3}}}
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/pack-mrl.mkiv b/Master/texmf-dist/tex/context/base/mkiv/pack-mrl.mkiv
index 665d245b346..e5d19d3b3de 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/pack-mrl.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/pack-mrl.mkiv
@@ -145,14 +145,16 @@
\setvalue{\??blackruletype mp}%
{\frule
type {mp}%
- data {\includeMPgraphic{\directblackrulesparameter\c!mp}}}
+ data {\includeMPgraphic{\directblackrulesparameter\c!mp}}
+ line \dimexpr\directblackrulesparameter\c!rulethickness\relax
+ }
\letvalue{\??blackruletype\s!no }\novrule
%letvalue{\??blackruletype\s!yes}\vrule
-
\setupblackrules
[\c!n=3,
+ \c!rulethickness=\linewidth,
\c!alternative=\c!a,
\c!distance=.25\emwidth,
\c!color=]
@@ -279,7 +281,7 @@
\edef\p_background{\directthinrulesparameter\c!background}%
\edef\p_frame {\directthinrulesparameter\c!frame}%
\linewidth\dimexpr\directthinrulesparameter\c!rulethickness/\plustwo\relax
- \ifdim\linewidth=\zeropoint
+ \ifzeropt\linewidth
\c_pack_thinrules_type\zerocount
\else\ifx\p_frame\v!on
\c_pack_thinrules_type\expandnamespaceparameter\??thinrulealternatives\directthinrulesparameter\c!alternative\v!b\relax
@@ -642,7 +644,7 @@
\pack_textrule_correct_depth_yes
\pack_textrule_correct_depth_nop
\nointerlineskip
- \noindent\vpack % was \dontleavehmode
+ \noindent\naturalvpack % was \dontleavehmode
{\color[\directtextrulesparameter\c!rulecolor]
{\hrule
\s!depth \directtextrulesparameter\c!rulethickness
@@ -841,32 +843,32 @@
\unexpanded\def\fillinline
{\dosingleempty\pack_fillinline}
-\ifdefined\endpar % experiment with \endpar
-
- \def\pack_fillinline[#1]%
- {% \endpar % no, as it interferes with \definedescription cum suis
- \begingroup
- \setupcurrentfillinlines[#1]%
- \directfillinlinesparameter\c!before
- \begingroup
- \advance\rightskip \directfillinlinesparameter\c!margin\relax
- \parfillskip\zeropoint
- \pushmacro\endpar
- \def\endpar
- {\popmacro\endpar
- \ifhmode\unskip\hfill\fi
- \scratchwidth\dimexpr\directfillinlinesparameter\c!width-\directfillinlinesparameter\c!distance\relax
- \ifdim\scratchwidth>\directfillinlinesparameter\c!margin\else\expandafter\rlap\fi
- {\kern\directfillinlinesparameter\c!distance
- \scratchheight\dimexpr\directfillinlinesparameter\c!rulethickness/\plustwo\relax
- \color[\directfillinlinesparameter\c!color]{\vrule\s!width\scratchwidth\s!height\scratchheight\s!depth\scratchheight}}%
- \endpar
- \endgroup
- \endpar
- \directfillinlinesparameter\c!after
- \endgroup}} % carryover ?
-
-\else
+% \ifdefined\endpar % experiment with \endpar
+%
+% \def\pack_fillinline[#1]%
+% {% \endpar % no, as it interferes with \definedescription cum suis
+% \begingroup
+% \setupcurrentfillinlines[#1]%
+% \directfillinlinesparameter\c!before
+% \begingroup
+% \advance\rightskip \directfillinlinesparameter\c!margin\relax
+% \parfillskip\zeropoint
+% \pushmacro\endpar
+% \def\endpar
+% {\popmacro\endpar
+% \ifhmode\unskip\hfill\fi
+% \scratchwidth\dimexpr\directfillinlinesparameter\c!width-\directfillinlinesparameter\c!distance\relax
+% \ifdim\scratchwidth>\directfillinlinesparameter\c!margin\else\expandafter\rlap\fi
+% {\kern\directfillinlinesparameter\c!distance
+% \scratchheight\dimexpr\directfillinlinesparameter\c!rulethickness/\plustwo\relax
+% \color[\directfillinlinesparameter\c!color]{\vrule\s!width\scratchwidth\s!height\scratchheight\s!depth\scratchheight}}%
+% \endpar
+% \endgroup
+% \endpar
+% \directfillinlinesparameter\c!after
+% \endgroup}} % carryover ?
+%
+% \else
\def\pack_fillinline[#1]%
{%\endgraf % no, as it interferes with \definedescription cum suis
@@ -890,6 +892,6 @@
\directfillinlinesparameter\c!after
\endgroup}} % carryover ?
-\fi
+% \fi
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/pack-obj.mkiv b/Master/texmf-dist/tex/context/base/mkiv/pack-obj.mkiv
index d08c664944f..4b3b6c2f0fa 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/pack-obj.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/pack-obj.mkiv
@@ -20,24 +20,22 @@
%D \macros
%D {setobject,getobject,ifinobject}
%D
-%D Boxes can be considered reuable objects. Traditionally once passed
-%D to the \DVI\ file, such objects cannot be reused. In \PDF\ however,
-%D reusing is possible and sometimes even a necessity. Therefore,
-%D \CONTEXT\ supports reusable objects and \LUATEX\ has native support
-%D for so called box resources.
+%D Boxes can be considered reuable objects. Traditionally once passed to the \DVI\
+%D file, such objects cannot be reused. In \PDF\ however, reusing is possible and
+%D sometimes even a necessity. Therefore, \CONTEXT\ supports reusable objects and
+%D \LUATEX\ has native support for so called box resources.
%D
-%D The first application of objects in \CONTEXT\ concerned \METAPOST\
-%D graphics and fill||in form fields. Reusing resources can save lots
-%D of bytes and sometimes also runtime.
+%D The first application of objects in \CONTEXT\ concerned \METAPOST\ graphics and
+%D fill||in form fields. Reusing resources can save lots of bytes and sometimes also
+%D runtime.
%D
%D \starttyping
%D \setobject{class}{name}\somebox{}
%D \getobject{class}{name}
%D \stoptyping
%D
-%D Here \type {\somebox} can be whatever box specification suits \TEX.
-%D Although the implementation in \MKIV\ is somewhat different the
-%D principles have not changed.
+%D Here \type {\somebox} can be whatever box specification suits \TEX. Although the
+%D implementation in \MKIV\ is somewhat different the principles have not changed.
\installcorenamespace {objects}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/pack-ori.lua b/Master/texmf-dist/tex/context/base/mkiv/pack-ori.lua
new file mode 100644
index 00000000000..a786b19ef13
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/pack-ori.lua
@@ -0,0 +1,70 @@
+if not modules then modules = { } end modules ['pack-ori'] = {
+ version = 1.001,
+ comment = "companion to supp-box.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local context = context
+local implement = interfaces.implement
+local variables = interfaces.variables
+
+local settings_to_array = utilities.parsers.settings_to_array
+
+local orientation = {
+ [variables.up] = 0x000,
+ [variables.left] = 0x001,
+ [variables.down] = 0x002,
+ [variables.right] = 0x003,
+ [variables.top] = 0x004,
+ [variables.bottom] = 0x005,
+}
+local vertical = {
+ [variables.line] = 0x000,
+ [variables.top] = 0x010,
+ [variables.bottom] = 0x020,
+ [variables.middle] = 0x030,
+}
+local horizontal = {
+ [variables.middle] = 0x000,
+ [variables.flushleft] = 0x100,
+ [variables.flushright] = 0x200,
+ [variables.left] = 0x300,
+ [variables.right] = 0x400,
+}
+
+implement {
+ name = "toorientation",
+ public = true,
+ arguments = {
+ {
+ { "horizontal", "string" },
+ { "vertical", "string" },
+ { "orientation", "string" },
+ }
+ },
+ actions = function(t)
+ local n = 0
+ local m = t.horizontal if m then n = n | (horizontal [m] or 0) end
+ local m = t.vertical if m then n = n | (vertical [m] or 0) end
+ local m = t.orientation if m then n = n | (orientation[m] or 0) end
+ -- logs.report("orientation","0x%03X : %s",n,table.sequenced(t))
+ context(n)
+ end,
+}
+
+implement {
+ name = "stringtoorientation",
+ public = true,
+ arguments = "string",
+ actions = function(s)
+ local n = 0
+ local t = settings_to_array(s)
+ local m = t[1] if m then n = n | (horizontal [m] or 0) end
+ local m = t[2] if m then n = n | (vertical [m] or 0) end
+ local m = t[3] if m then n = n | (orientation[m] or 0) end
+ -- logs.report("orientation","0x%03X : %s",n,s)
+ context(n)
+ end,
+}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/pack-ori.mkxl b/Master/texmf-dist/tex/context/base/mkiv/pack-ori.mkxl
new file mode 100644
index 00000000000..061768f94f9
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/pack-ori.mkxl
@@ -0,0 +1,88 @@
+%D \module
+%D [ file=pack-ori, % was experimental
+%D version=2019.07.30,
+%D title=\CONTEXT\ Packaging Macros,
+%D subtitle=Anchoring,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Packaging Macros / Anchoring}
+
+\registerctxluafile{pack-ori}{}
+
+\unprotect
+
+%D Possible options are:
+%D
+%D \starttabulate[|T|T|]
+%D \NC orientation \NC up left down right top bottom
+%D \NC vertical \NC line top bottom middle
+%D \NC horizontal \NC middle flushleft flushright left right
+%D \stoptabulate
+
+\installcorenamespace{orientation}
+\installcorenamespace{orientations}
+
+\installcommandhandler \??orientation {orientation} \??orientation
+
+\setuporientation
+ [\c!orientation=\v!normal,
+ \c!horizontal=\v!normal,
+ \c!vertical=\v!normal]
+
+\appendtoks
+ \expandafter\chardef\csname\??orientations\currentorientation\endcsname\toorientation
+ orientation {\orientationparameter\c!orientation}
+ horizontal {\orientationparameter\c!horizontal}
+ vertical {\orientationparameter\c!vertical}
+ \relax\relax
+\to \everydefineorientation
+
+\defineorientation[\v!normal]
+
+\defineorientation[\v!up] [\c!orientation=\v!up]
+\defineorientation[\v!down] [\c!orientation=\v!down]
+\defineorientation[\v!left] [\c!orientation=\v!left]
+\defineorientation[\v!right] [\c!orientation=\v!right]
+\defineorientation[\v!top] [\c!orientation=\v!top]
+\defineorientation[\v!bottom][\c!orientation=\v!bottom]
+
+%D There will be some more helpers here.
+
+\def\theorientation#1%
+ {\numexpr
+ \ifcsname\??orientations#1\endcsname
+ \lastnamedcs
+ \else
+ \zerocount
+ \fi
+ \relax}
+
+\def\autoorientation#1%
+ {\numexpr
+ \ifcsname\??orientations#1\endcsname
+ \lastnamedcs
+ \else
+ \auto_orientation{#1}%
+ \fi
+ \relax}
+
+\def\auto_orientation#1%
+ {\immediateassignment\global\expandafter\chardef\csname\??orientations#1\endcsname\stringtoorientation{#1}%
+ \csname\??orientations#1\endcsname}
+
+\unexpanded\def\doifelseorientation#1%
+ {\ifcsname\??orientations#1\endcsname
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+% \def\iforientationcsname#1{\ifcsname\??orientations}
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/pack-rul.lua b/Master/texmf-dist/tex/context/base/mkiv/pack-rul.lua
index 455d0bff832..ef8d8136f48 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/pack-rul.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/pack-rul.lua
@@ -123,6 +123,8 @@ local function doreshapeframedbox(n)
for h, id, subtype, list in nextlist, list do
if list and id == hlist_code then
if subtype == boxlist_code or subtype == linelist_code then
+ -- getdirection is irrelevant here so it will go
+ -- somehow a parfillskip also can get influenced
local p = hpack(list,maxwidth,'exactly',getdirection(h)) -- multiple return value
local set, order, sign = getboxglue(p)
setboxglue(h,set,order,sign)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/pack-rul.mkiv b/Master/texmf-dist/tex/context/base/mkiv/pack-rul.mkiv
index 3d03942aab2..8732c7e6b7c 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/pack-rul.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/pack-rul.mkiv
@@ -43,24 +43,6 @@
\def\pack_framed_setup_line_width[#1]%
{\assigndimension{#1}\linewidth{.2\points}{.4\points}{.6\points}}
-% %D \macros
-% %D {setupscreens}
-% %D
-% %D Sort of obsolete:
-% %D
-% %D \showsetup{setupscreens}
-%
-% \installcorenamespace{screens}
-%
-% \installsetuponlycommandhandler \??screens {screens}
-%
-% \appendtoks
-% \edef\defaultbackgroundscreen{\directscreensparameter\c!screen}
-% \to \everysetupscreens
-%
-% \setupscreens
-% [\c!screen=.90] % was .95 but that's hardly visible
-
%D The parameter handler:
\installcorenamespace{framed}
@@ -105,6 +87,7 @@
\unexpanded\def\doinstallinheritedframed#1#2#3#4#5#6#7#8#9%
{\def#5##1##2{\ifx##1\relax#6{##2}\else#4{##1}{##2}\fi}%
%\def#6##1{\ifcsname\??framed:##1\endcsname\??framed:##1\else\s!empty\fi}% root
+ %\def#6##1{\ifcsname\??framed:##1\endcsname\??framed:##1\else\??empty\fi}% root
\def#6##1{\ifcsname\??framed:##1\endcsname\??framed:##1\else\??empty\fi}% root
\unexpanded\def#8%
{\bgroup
@@ -272,10 +255,15 @@
\fi}
\def\pack_framed_filled_box_round
- {\back_ovalbox
- \d_framed_target_wd \d_framed_target_ht \d_framed_target_dp
- \d_framed_linewidth \p_framed_backgroundradius
- \zerocount \plusone {\ifx\p_framed_backgroundcorner\v!round0\else\number\p_framed_backgroundcorner\fi}}
+ {\raise\d_framed_target_dp\hpack{\frule
+ type fill
+ width \d_framed_target_wd
+ height \d_framed_target_ht
+ depth \d_framed_target_dp
+ line \d_framed_linewidth
+ radius \p_framed_backgroundradius\space
+ corner {\p_framed_backgroundcorner}
+ \relax}}
\def\pack_framed_stroked_box
{\edef\p_framed_framecorner{\framedparameter\c!framecorner}%
@@ -296,10 +284,14 @@
% \pack_framed_stroked_box_normal % later
\def\pack_framed_stroked_box_round
- {\back_ovalbox
- \d_framed_target_wd \d_framed_target_ht \d_framed_target_dp
- \d_framed_linewidth \p_framed_frameradius
- \plusone \zerocount {\ifx\p_framed_framecorner\v!round0\else\number\p_framed_framecorner\fi}}
+ {\raise\d_framed_target_dp\hpack{\frule
+ width \d_framed_target_wd
+ height \d_framed_target_ht
+ depth \d_framed_target_dp
+ line \d_framed_linewidth
+ radius \p_framed_frameradius\space
+ corner {\p_framed_framecorner}
+ \relax}}
% a lot of weird corners
%
@@ -347,18 +339,6 @@
% \quad}
% \stopTEXpage
-%D The oval box is drawn using a special macro, depending on
-%D the driver in use.
-
-% \def\pack_framed_background_box_gray % avoid black rules when no gray
-% {\edef\p_framed_backgroundscreen{\framedparameter\c!backgroundscreen}%
-% \ifx\p_framed_backgroundscreen\empty \else
-% \pack_framed_background_box_gray_indeed
-% \fi}
-%
-% \def\pack_framed_background_box_gray_indeed % can be more direct but who cares, just compatibility
-% {\colored[s=\p_framed_backgroundscreen]{\pack_framed_filled_box}}
-
%D It won't be a surprise that we not only provide gray boxes, but also colored
%D ones. Here it is:
@@ -568,21 +548,6 @@
\box\b_framed_extra
\egroup}
-% \def\pack_framed_process_background_indeed_external#1%
-% {\pack_framed_overlay_initialize
-% \bgroup
-% \setbox\b_framed_extra\hpack\bgroup
-% \ifzeropt\framedbackgroundoffset\else
-% \kern-\framedbackgroundoffset
-% \fi
-% \hbox\bgroup#1\egroup
-% \egroup
-% \wd\b_framed_extra\zeropoint
-% \ht\b_framed_extra\framedbackgroundheight
-% \dp\b_framed_extra\framedbackgrounddepth
-% \box\b_framed_extra
-% \egroup}
-
\def\pack_framed_process_background_indeed_external
{\pack_framed_overlay_initialize
\pack_framed_process_background_indeed_internal}
@@ -610,13 +575,6 @@
\edef\m_overlay_region{\reservedautoregiontag}%
\fi}
-% \def\pack_framed_add_region % experiment
-% {\ifx\m_overlay_region\v!yes
-% \anch_mark_region_box\b_framed_normal
-% \else
-% \anch_mark_tagged_box\b_framed_normal\m_overlay_region
-% \fi}
-
\def\pack_framed_add_region % experiment
{\anch_mark_tagged_box\b_framed_normal\m_overlay_region}
@@ -645,18 +603,6 @@
\hss
\egroup}}
-% \def\pack_framed_overlay_initialize_indeed
-% {\edef\overlaywidth {\the\d_framed_target_wd\space}%
-% \edef\overlayheight {\the\dimexpr\d_framed_target_ht+\d_framed_target_dp\relax\space}%
-% \edef\overlaydepth {\the\d_framed_target_dp\space}%
-% \edef\overlaycolor {\framedparameter\c!backgroundcolor}% let ?
-% \edef\overlaylinecolor{\framedparameter\c!framecolor}% only needed for layers
-% \edef\overlaylinewidth{\the\d_framed_linewidth\space}%
-% %\edef\overlaycorner {\framedparameter\c!backgroundcorner}%
-% %\edef\overlayradius {\framedparameter\c!backgroundradius}%
-% \edef\overlayoffset {\the\framedbackgroundoffset\space}% \backgroundoffset % we steal this one
-% \let\pack_framed_overlay_initialize\relax}
-
\def\pack_framed_overlay_initialize_indeed
{\d_overlay_width \d_framed_target_wd
\d_overlay_height \dimexpr\d_framed_target_ht+\d_framed_target_dp\relax
@@ -710,27 +656,6 @@
\box\b_framed_normal
\box\b_framed_extra}}
-% \def\pack_framed_stroked_box_normal
-% {\setbox\scratchbox\emptyhbox
-% \wd\scratchbox\d_framed_target_wd
-% \ht\scratchbox\d_framed_target_ht
-% \dp\scratchbox\d_framed_target_dp
-% \setbox\scratchbox\vpack \bgroup
-% \csname \??framedtop\p_framed_frame\framedparameter\c!topframe \endcsname
-% \nointerlineskip % new (needed for fences)
-% \hbox \bgroup
-% \csname \??framedleft\p_framed_frame\framedparameter\c!leftframe \endcsname
-% \box\scratchbox
-% \csname \??framedright\p_framed_frame\framedparameter\c!rightframe \endcsname
-% \egroup
-% \nointerlineskip % new (needed for fences)
-% \csname \??framedbottom\p_framed_frame\framedparameter\c!bottomframe\endcsname
-% \egroup
-% \wd\scratchbox\d_framed_target_wd
-% \ht\scratchbox\d_framed_target_ht
-% \dp\scratchbox\d_framed_target_dp
-% \box\scratchbox}
-
\def\pack_framed_stroked_box_normal_opened
{\setbox\scratchbox\vpack \bgroup
\csname\??framedtop\p_framed_frame\framedparameter\c!topframe\endcsname
@@ -876,35 +801,6 @@
\newcount\c_pack_framed_nesting
-% to be tested (slightly more efficient):
-%
-% \unexpanded\def\pack_frame_common % #1 #2
-% {\bgroup
-% \advance\c_pack_framed_nesting\plusone
-% \expandafter\let\csname\??framed>\the\c_pack_framed_nesting:\s!parent\endcsname\??framed
-% \edef\currentframed{>\the\c_pack_framed_nesting}%
-% \pack_framed_initialize
-% \bgroup
-% \doifnextoptionalcselse} % #1 #2
-%
-% \unexpanded\def\framed {\pack_frame_common\pack_framed_process_framed_pickup\pack_framed_process_indeed}
-% \unexpanded\def\startframed{\pack_frame_common\pack_framed_start_framed_pickup \pack_framed_start_indeed }
-%
-% \def\pack_framed_process_framed_pickup[#1]%
-% {\setupcurrentframed[#1]%
-% \pack_framed_process_indeed}
-%
-% \def\pack_framed_start_framed_pickup[#1]%
-% {\setupcurrentframed[#1]% here !
-% \secondargumenttrue % dirty trick
-% \pack_framed_start_framed_indeed}
-%
-% \def\pack_framed_start_framed_indeed
-% {\pack_framed_process_indeed
-% \bgroup}
-%
-% no longer .. we also accept \startframed[tag]
-
\unexpanded\def\pack_framed_process_framed[#1]%
{\bgroup
\iffirstargument % faster
@@ -920,24 +816,6 @@
\pack_framed_initialize
\dosingleempty\pack_framed_process_framed}
-% \unexpanded\def\startframed
-% {\dosingleempty\pack_framed_start_framed}
-%
-% \def\pack_framed_start_framed[#1]%
-% {\bgroup
-% \advance\c_pack_framed_nesting\plusone
-% \expandafter\let\csname\??framed>\the\c_pack_framed_nesting:\s!parent\endcsname\??framed
-% \edef\currentframed{>\the\c_pack_framed_nesting}%
-% \pack_framed_initialize
-% \bgroup
-% \iffirstargument
-% \secondargumenttrue % dirty trick
-% \setupcurrentframed[#1]% here !
-% \fi
-% \pack_framed_process_indeed
-% \bgroup
-% \ignorespaces}
-
\unexpanded\def\startframed
{\dosingleempty\pack_framed_start_framed}
@@ -1723,8 +1601,8 @@
{\setvalue{\??framedlocatorbefore#1}{#2}%
\setvalue{\??framedlocatorafter #1}{#3}}
-\def\pack_framed_locator_before#1{\csname\??framedlocatorbefore#1\endcsname}
-\def\pack_framed_locator_after #1{\csname\??framedlocatorafter #1\endcsname}
+\def\pack_framed_locator_before#1{\begincsname\??framedlocatorbefore#1\endcsname}
+\def\pack_framed_locator_after #1{\begincsname\??framedlocatorafter #1\endcsname}
\newdimen\d_framed_locator_ht
\newdimen\d_framed_locator_dp
@@ -1827,14 +1705,14 @@
\setbox\b_framed_normal\hpack{\lower\d_framed_locator_dp\box\b_framed_normal}%
\ht\b_framed_normal\strutht
\dp\b_framed_normal\strutdp
- \hpack{\box\b_framed_normal}} % why pack
+ \hpack{\box\b_framed_normal}} % why do we pack .. dange of loosing?
\installframedlocator \v!line
{}
{\setbox\b_framed_normal\hpack{\lower.5\ht\b_framed_normal\box\b_framed_normal}%
\ht\b_framed_normal.5\lineheight
\dp\b_framed_normal.5\lineheight
- \hpack{\box\b_framed_normal}}
+ \hpack{\box\b_framed_normal}} % why do we pack .. dange of loosing?
\installframedlocator \v!low
{}
@@ -1850,7 +1728,7 @@
\setbox\b_framed_normal\hpack{\lower\d_framed_locator_dp\box\b_framed_normal}%
\ht\b_framed_normal\d_framed_locator_ht
\dp\b_framed_normal\d_framed_locator_dp
- \hpack{\box\b_framed_normal}}
+ \hpack{\box\b_framed_normal}} % why do we pack .. dange of loosing?
\installframedlocator \v!middle
{}
@@ -1858,7 +1736,7 @@
\setbox\b_framed_normal\hpack{\lower\scratchdimen\box\b_framed_normal}%
\ht\b_framed_normal\scratchdimen
\dp\b_framed_normal\scratchdimen
- \hpack{\box\b_framed_normal}}
+ \hpack{\box\b_framed_normal}} % why do we pack .. dange of loosing?
\installframedlocator \v!lohi % maybe also \v!center
{\pack_framed_locator_before\v!middle}
@@ -1870,7 +1748,7 @@
\setbox\b_framed_normal\hpack{\lower\d_framed_locator_ht\box\b_framed_normal}%
\ht\b_framed_normal\d_framed_locator_dp
\dp\b_framed_normal\d_framed_locator_ht
- \hpack{\box\b_framed_normal}}
+ \hpack{\box\b_framed_normal}} % why do we pack .. dange of loosing?
\installframedlocator \v!keep % retains height/depth
{\pack_framed_remove_depth}
@@ -1884,7 +1762,7 @@
\setbox\b_framed_normal\hpack{\lower\d_framed_locator_dp\box\b_framed_normal}%
\ht\b_framed_normal\d_framed_locator_ht
\dp\b_framed_normal\d_framed_locator_dp
- \hpack{\box\b_framed_normal}}
+ \hpack{\box\b_framed_normal}} % why do we pack .. dange of loosing?
% also used in fastlocalframed
@@ -1919,30 +1797,6 @@
% \framed[width=12cm,height=3cm,orientation=-180]{\input ward\relax}
% \framed[width=12cm,height=3cm,orientation=-270]{\input ward\relax}
-% \def\pack_framed_start_orientation
-% {\ifcase\p_framed_orientation
-% \let\pack_framed_stop_orientation\relax
-% \else
-% \scratchcounter\p_framed_orientation % weird .. why
-% \divide\scratchcounter\plustwo
-% \ifodd\scratchcounter
-% \let\pack_framed_stop_orientation\pack_framed_stop_orientation_odd
-% \else
-% \let\pack_framed_stop_orientation\pack_framed_stop_orientation_even
-% \fi
-% \fi}
-%
-% \def\pack_framed_stop_orientation_odd
-% {\swapmacros\framedwidth\framedheight
-% \swapmacros\localwidth\localheight
-% \swapdimens\d_framed_height\d_framed_width
-% \pack_framed_stop_orientation_even}
-%
-% \def\pack_framed_stop_orientation_even
-% {\setbox\b_framed_normal\hbox{\dorotatebox\p_framed_orientation\hbox{\box\b_framed_normal}}%
-% \d_framed_height\ht\b_framed_normal
-% \d_framed_width \wd\b_framed_normal}
-
\def\pack_framed_start_orientation
{\ifcase\p_framed_orientation
\let\pack_framed_stop_orientation\relax
@@ -2033,15 +1887,6 @@
\edef\currentmathframed{#1}%
\dosingleempty\pack_framed_mathframed_indeed}
-% \def\pack_framed_mathframed_indeed[#1]#2% no fancy nesting supported here
-% {\iffirstargument
-% \setupcurrentmathframed[#1]%
-% \fi
-% \c_framed_mstyle\mathstyle
-% \doifnot{\mathframedparameter\c!location}\v!low{\let\normalstrut\pack_framed_math_strut}%
-% \inheritedmathframedframed{\Ustartmath\triggermathstyle\c_framed_mstyle#2\Ustopmath}%
-% \endgroup}
-
\newcount\c_pack_framed_mathframed
\newtoks \t_pack_framed_mathframed
diff --git a/Master/texmf-dist/tex/context/base/mkiv/pack-rul.mkxl b/Master/texmf-dist/tex/context/base/mkiv/pack-rul.mkxl
new file mode 100644
index 00000000000..8fd23fbb1b7
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/pack-rul.mkxl
@@ -0,0 +1,3089 @@
+%D \module
+%D [ file=pack-rul, % was core-rul,
+%D version=1998.10.16,
+%D title=\CONTEXT\ Packaging Macros,
+%D subtitle=Ruled Content,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Packaging Macros / Ruled Content}
+
+%D The code here is expanded lots of time as framed is used in many places. This is
+%D why the code here is (and gets) optimized as much as possible. Also, by avoiding
+%D packaging and expansion we also keep tracing reasonable. For instance, multiple
+%D stacked backgrounds can slow down a run if not optimized this way.
+
+\registerctxluafile{pack-rul}{optimize}
+
+\unprotect
+
+% \definesystemvariable {ol} % OmLijnd -> check scrn-fld too
+
+%D \macros
+%D {linewidth, setuplinewidth}
+%D
+%D This module deals with rules (lines) in several ways. First we introduce two
+%D macros that can be used to set some common characteristics.
+%D
+%D \showsetup{setuplinewidth}
+%D
+%D The linewidth is available in \type{\linewidth}. The preset value of .4pt equals
+%D the default hard coded \TEX\ rule width.
+
+\newdimen\linewidth
+
+\unexpanded\def\setuplinewidth
+ {\dosingleargument\pack_framed_setup_line_width}
+
+\def\pack_framed_setup_line_width[#1]%
+ {\assigndimension{#1}\linewidth{.2\points}{.4\points}{.6\points}}
+
+%D The parameter handler:
+
+\installcorenamespace{framed}
+\installcorenamespace{framedtop}
+\installcorenamespace{framedbottom}
+\installcorenamespace{framedleft}
+\installcorenamespace{framedright}
+
+\installcorenamespace{regularframed}
+\installcorenamespace{simplifiedframed}
+
+\installcommandhandler \??framed {framed} \??framed
+
+\let\pack_framed_framedparameter \framedparameter
+\let\pack_framed_framedparameterhash\framedparameterhash
+\let\pack_framed_setupcurrentframed \setupcurrentframed
+
+\def\pack_framed_initialize
+ {\let\framedparameter \pack_framed_framedparameter
+ \let\framedparameterhash\pack_framed_framedparameterhash
+ \let\setupcurrentframed \pack_framed_setupcurrentframed
+ \inframedtrue}
+
+%D A helper:
+
+\def\frameddimension#1{\the\dimexpr\framedparameter{#1}\relax}
+
+%D Inheritance:
+
+\def\installinheritedframed#1%
+ {\normalexpanded{\doinstallinheritedframed
+ \expandafter\noexpand\csname current#1\endcsname
+ \expandafter\noexpand\csname #1parameter\endcsname
+ \expandafter\noexpand\csname #1parameterhash\endcsname
+ \expandafter\noexpand\csname do#1parameter\endcsname
+ \expandafter\noexpand\csname do#1parentparameter\endcsname
+ \expandafter\noexpand\csname do#1rootparameter\endcsname
+ \expandafter\noexpand\csname setupcurrent#1\endcsname
+ \expandafter\noexpand\csname inherited#1framed\endcsname
+ \expandafter\noexpand\csname inherited#1framedbox\endcsname}} % new
+
+\unexpanded\def\doinstallinheritedframed#1#2#3#4#5#6#7#8#9%
+ {\def#5##1##2{\ifx##1\relax#6{##2}\else#4{##1}{##2}\fi}%
+ %\def#6##1{\ifcsname\??framed:##1\endcsname\??framed:##1\else\s!empty\fi}% root
+ \def#6##1{\ifcsname\??framed:##1\endcsname\??framed:##1\else\??empty\fi}% root
+ \unexpanded\def#8%
+ {\bgroup
+ \bgroup
+ \inframedtrue
+ \let\currentframed #1%
+ \let\framedparameter #2%
+ \let\framedparameterhash#3%
+ \let\setupcurrentframed #7%
+ \pack_framed_process_indeed}%
+ \unexpanded\def#9%
+ {\bgroup
+ \inframedtrue
+ \let\currentframed #1%
+ \let\framedparameter #2%
+ \let\framedparameterhash#3%
+ \let\setupcurrentframed #7%
+ \pack_framed_process_box_indeed}}
+
+\unexpanded\def\installframedcommandhandler#1#2#3%
+ {\installcommandhandler{#1}{#2}{#3}%
+ \installinheritedframed{#2}}
+
+\unexpanded\def\installframedautocommandhandler#1#2#3%
+ {\installautocommandhandler{#1}{#2}{#3}%
+ \installinheritedframed{#2}}
+
+\unexpanded\def\installsimpleframedcommandhandler#1#2#3%
+ {\installsimplecommandhandler{#1}{#2}{#3}%
+ \installinheritedframed{#2}}
+
+% for regular framed
+
+\setupframed
+ [\c!width=\v!fit,
+ \c!height=\v!broad,
+ %\c!minheight=\zeropoint,
+ %\c!lines=,
+ \c!offset=.25\exheight, % \defaultframeoffset
+ \c!empty=\v!no,
+ \c!frame=\v!on,
+ %\c!topframe=,
+ %\c!bottomframe=,
+ %\c!leftframe=,
+ %\c!rightframe=,
+ \c!radius=.5\bodyfontsize,
+ \c!rulethickness=\linewidth,
+ \c!corner=\v!rectangular,
+ \c!depth=\zeropoint,
+ %\c!foregroundcolor=,
+ %\c!foregroundstyle=,
+ %\c!background=,
+ %\c!backgroundcolor=,
+ \c!backgroundoffset=\zeropoint,
+ %\c!framecolor=,
+ \c!frameoffset=\zeropoint,
+ \c!backgroundcorner=\framedparameter\c!corner, % use \p_ here
+ \c!backgroundradius=\framedparameter\c!radius,
+ \c!backgrounddepth=\framedparameter\c!depth,
+ \c!framecorner=\framedparameter\c!corner,
+ \c!frameradius=\framedparameter\c!radius,
+ \c!framedepth=\framedparameter\c!depth,
+ %\c!component=,
+ %\c!region=,
+ %\c!align=,
+ \c!bottom=\vss,
+ %\c!top=,
+ \c!strut=\v!yes,
+ \c!autostrut=\v!yes,
+ \c!location=\v!normal,
+ %\c!orientation=,
+ %\c!anchoring=,
+ \c!autowidth=\v!yes,
+ %\c!setups=,
+ \c!loffset=\zeropoint,
+ \c!roffset=\zeropoint,
+ \c!toffset=\zeropoint,
+ \c!boffset=\zeropoint]
+
+%D For backgrounds and such:
+
+\defineframed
+ [\??simplifiedframed]
+ [\c!frame=\v!off,
+ \c!depth=\zeropoint,
+ \c!offset=\v!overlay,
+ \c!component=,
+ \c!region=,
+ \c!radius=.5\bodyfontsize,
+ \c!rulethickness=\linewidth,
+ \c!corner=\v!rectangular,
+ \c!backgroundoffset=\zeropoint,
+ \c!frameoffset=\zeropoint,
+ \c!backgroundcorner=\framedparameter\c!corner, % use \p_ here
+ \c!backgroundradius=\framedparameter\c!radius,
+ \c!backgrounddepth=\framedparameter\c!depth,
+ \c!framecorner=\framedparameter\c!corner,
+ \c!frameradius=\framedparameter\c!radius,
+ \c!framedepth=\framedparameter\c!depth,
+ \c!location=\v!normal,
+ \c!loffset=\zeropoint,
+ \c!roffset=\zeropoint,
+ \c!toffset=\zeropoint,
+ \c!boffset=\zeropoint]
+
+\unexpanded\def\definesimplifiedframed[#1]% no settings
+ {\defineframed[#1][\??simplifiedframed]%
+ \expandafter\let\csname#1\endcsname\undefined}
+
+\expandafter\let\csname\??simplifiedframed\endcsname\undefined
+
+%D We will communicate through module specific variables, current framed
+%D parameters and some reserved dimension registers.
+
+\newdimen\d_framed_target_wd
+\newdimen\d_framed_target_ht
+\newdimen\d_framed_target_dp
+\newdimen\d_framed_linewidth \let\ruledlinewidth\d_framed_linewidth % needed at lua end
+
+\let\p_framed_frame \empty % \framedparameter\c!frame
+\let\p_framed_backgroundoffset\empty
+\let\p_framed_foregroundstyle \empty
+\let\p_framed_autostrut \empty
+\let\p_framed_location \empty
+\let\p_framed_orientation \empty
+\let\p_framed_anchoring \empty
+\let\p_framed_autowidth \empty
+\let\p_framed_franalyze \empty
+\let\p_framed_backgroundcorner\empty
+\let\p_framed_backgroundradius\empty
+\let\p_framed_framecorner \empty
+\let\p_framed_frameradius \empty
+\let\p_framed_lines \empty
+\let\p_framed_empty \empty
+\let\p_framed_backgroundcolor \empty
+\let\p_framed_framecolor \empty
+\let\p_framed_component \empty
+\let\p_framed_background \empty
+\let\p_framed_rulethickness \empty
+\let\p_framed_foregroundcolor \empty
+\let\p_framed_setups \empty
+
+%D We don't have to stick to a \TEX\ drawn rule, but also can use rounded
+%D or even fancier shapes, as we will see later on.
+
+\def\pack_framed_filled_box
+ {\edef\p_framed_backgroundcorner{\framedparameter\c!backgroundcorner}%
+ \ifx\p_framed_backgroundcorner\v!rectangular
+ \pack_framed_filled_box_normal
+ \else
+ \pack_framed_filled_box_radius
+ \fi}
+
+\def\pack_framed_filled_box_normal
+ {\vrule
+ \s!width \d_framed_target_wd
+ \s!height\d_framed_target_ht
+ \s!depth \d_framed_target_dp
+ \relax}
+
+\def\pack_framed_filled_box_radius
+ {\edef\p_framed_backgroundradius{\framedparameter\c!backgroundradius}%
+ \ifzeropt\dimexpr\p_framed_backgroundradius\relax % just in case of .x\bodyfontsize
+ \pack_framed_filled_box_normal
+ \else
+ \pack_framed_filled_box_round
+ \fi}
+
+\def\pack_framed_filled_box_round
+ {\raise\d_framed_target_dp\hpack{\frule
+ type fill
+ width \d_framed_target_wd
+ height \d_framed_target_ht
+ depth \d_framed_target_dp
+ line \d_framed_linewidth
+ radius \p_framed_backgroundradius\space
+ corner {\p_framed_backgroundcorner}
+ \relax}}
+
+\def\pack_framed_stroked_box
+ {\edef\p_framed_framecorner{\framedparameter\c!framecorner}%
+ \ifx\p_framed_framecorner\v!rectangular
+ \pack_framed_stroked_box_normal
+ \else
+ \pack_framed_stroked_box_radius
+ \fi}
+
+\def\pack_framed_stroked_box_radius
+ {\edef\p_framed_frameradius{\framedparameter\c!frameradius}%
+ \ifzeropt\dimexpr\p_framed_frameradius\relax % just in case of .x\bodyfontsize
+ \pack_framed_stroked_box_normal
+ \orelse\ifx\p_framed_frame\v!on
+ \pack_framed_stroked_box_round
+ \fi}
+
+% \pack_framed_stroked_box_normal % later
+
+\def\pack_framed_stroked_box_round
+ {\raise\d_framed_target_dp\hpack{\frule
+ width \d_framed_target_wd
+ height \d_framed_target_ht
+ depth \d_framed_target_dp
+ line \d_framed_linewidth
+ radius \p_framed_frameradius\space
+ corner {\p_framed_framecorner}
+ \relax}}
+
+% a lot of weird corners
+%
+% \startTEXpage
+% \dontleavehmode\framed
+% [corner=0,frame=on,framecolor=green,
+% background=color,backgroundcolor=yellow]{\tttf TEST \twodigits\recurselevel}%
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse {1} {4}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green,
+% background=color,backgroundcolor=yellow]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse {5} {8}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green,
+% background=color,backgroundcolor=yellow]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse {1} {4}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse {5} {8}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse {9}{12}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse{13}{16}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse{17}{20}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse{21}{24}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse{25}{28}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \stopTEXpage
+
+%D It won't be a surprise that we not only provide gray boxes, but also colored
+%D ones. Here it is:
+
+\def\pack_framed_background_box_color
+ {\edef\p_framed_backgroundcolor{\framedparameter\c!backgroundcolor}%
+ \ifx\p_framed_backgroundcolor\empty \else
+ \doifcolor\p_framed_backgroundcolor\pack_framed_background_box_color_indeed
+ \fi}
+
+\def\pack_framed_background_box_color_indeed
+ {\hpack{\dousecolorparameter\p_framed_backgroundcolor\pack_framed_filled_box}}
+
+%D \macros
+%D {defineoverlay, doifoverlayelse, overlayoffset,
+%D overlaywidth, overlayheight, overlaydepth,
+%D overlaycolor, overlaylinecolor, overlaylinewidth}
+%D
+%D Before we define the macro that actually takes card of the backgrounds, we
+%D introduce overlays. An overlay is something that contrary to its name lays {\em
+%D under} the text. An example of an overlay definition is:
+%D
+%D \startbuffer[tmp-1]
+%D \defineoverlay
+%D [fancy]
+%D [{\externalfigure
+%D [mp-cont.502]
+%D [width=\overlaywidth,
+%D height=\overlayheight]}]
+%D \stopbuffer
+%D
+%D \typebuffer[tmp-1]
+%D
+%D That for instance can be uses in:
+%D
+%D \startbuffer[tmp-2]
+%D \framed[backgroundachtergrond=fancy]{How Fancy!}
+%D \framed[backgroundachtergrond=fancy,frame=off]{Even More Fancy!}
+%D \stopbuffer
+%D
+%D and looks like:
+%D
+%D \startlinecorrection
+%D \vbox{\baselineskip24pt\getbuffer[tmp-1]\getbuffer[tmp-2]}
+%D \stoplinecorrection
+%D
+%D The formal definition is:
+%D
+%D \showsetup{defineoverlay}
+%D
+%D This macro's definition is a bit obscure, due the many non||used arguments and
+%D the two step call that enable the setting of the width, height and depth
+%D variables. Multiple backgrounds are possible and are specified as:
+%D
+%D \starttyping
+%D \framed[background={one,two,three}]{Three backgrounds!}
+%D \stoptyping
+%D
+%D Most drawing packages only know width and height. Therefore the dimensions have a
+%D slightly different meaning here:
+%D
+%D \startitemize[packed]
+%D \item \type{\overlaywidth }: width of the overlay
+%D \item \type{\overlayheight}: height plus depth of the overlay
+%D \item \type{\overlaydepth }: depth of the overlay
+%D \stopitemize
+%D
+%D The resulting box is lowered to the right depth.
+
+%def\overlaywidth {\the\hsize\space} % We preset the variables
+%def\overlayheight {\the\vsize\space} % to some reasonable default
+%def\overlaydepth {0pt } % values. The attributes
+%let\overlayoffset \overlaydepth % of the frame can be (are)
+%let\overlaylinewidth \overlaydepth % set somewhere else.
+\let\overlaycolor \empty
+\let\overlaylinecolor \empty
+
+\def\overlayradius{\framedparameter\c!frameradius}
+
+\newdimen\d_overlay_width
+\newdimen\d_overlay_height
+\newdimen\d_overlay_depth
+\newdimen\d_overlay_offset
+\newdimen\d_overlay_linewidth
+
+\let\m_overlay_region\empty
+
+% expandable ... in a future version the space will go (in mp one can use Overlay*)
+
+\def\overlaywidth {\the\d_overlay_width \space} % We preset the variables
+\def\overlayheight {\the\d_overlay_height \space} % to some reasonable default
+\def\overlaydepth {\the\d_overlay_depth \space} % values.
+\def\overlayoffset {\the\d_overlay_offset \space} % of the frame can be (are)
+\def\overlaylinewidth {\the\d_overlay_linewidth\space} % set somewhere else.
+\def\overlayregion {\m_overlay_region}
+
+% public but kind of protected
+
+\def\usedoverlaywidth {\dimexpr\d_overlay_width \relax}
+\def\usedoverlayheight {\dimexpr\d_overlay_height \relax}
+\def\usedoverlaydepth {\dimexpr\d_overlay_depth \relax}
+\def\usedoverlayoffset {\dimexpr\d_overlay_offset \relax}
+\def\usedoverlaylinewidth{\dimexpr\d_overlay_linewidth\relax}
+
+%D The next register is used to initialize overlays.
+
+\newtoks\everyoverlay
+
+%D An example of an initialization is the following (overlays can contain text
+%D and be executed under an regime where interlineskip is off).
+
+\installcorenamespace{overlay}
+\installcorenamespace{overlaybuiltin}
+
+\appendtoks
+ \oninterlineskip
+\to \everyoverlay
+
+\prependtoks
+ \hsize\d_overlay_width
+ \vsize\d_overlay_height
+\to \everyoverlay
+
+\unexpanded\def\defineoverlay
+ {\dodoubleargument\pack_framed_define_overlay}
+
+\def\pack_framed_define_overlay[#1][#2]%
+ {\def\pack_framed_define_overlay_indeed##1{\setvalue{\??overlay##1}{\executedefinedoverlay{##1}{#2}}}%
+ \processcommalist[#1]\pack_framed_define_overlay_indeed}
+
+% \unexpanded\def\executedefinedoverlay#1#2% we can share the definitions
+% {\bgroup % redundant grouping
+% \setbox\scratchbox\hbox\bgroup
+% \ifzeropt\d_framed_target_dp
+% \the\everyoverlay#2% saves wrapping (and lua call)
+% \else
+% \lower\d_framed_target_dp
+% \hbox{\the\everyoverlay#2}%
+% \fi
+% \egroup
+% \setlayoutcomponentattribute{\v!overlay:#1}%
+% \setbox\scratchbox\hpack \layoutcomponentboxattribute
+% {\kern -.5\dimexpr\wd\scratchbox-\d_framed_target_wd\relax % was \d_overlay_width
+% \raise-.5\dimexpr\ht\scratchbox-\d_framed_target_ht\relax % not \d_overlay_height !
+% \box\scratchbox}%
+% \wd\scratchbox\d_framed_target_wd
+% \ht\scratchbox\d_framed_target_ht
+% \dp\scratchbox\d_framed_target_dp
+% \box\scratchbox
+% \egroup}
+
+% 20191231: moved from cont-exp:
+
+\unexpanded\def\executedefinedoverlay#1#2% we can share the definitions
+ {\bgroup % redundant grouping
+ \setlayoutcomponentattribute{\v!overlay:#1}%
+ \setbox\scratchbox\hbox \layoutcomponentboxattribute{\the\everyoverlay#2}%
+ \boxxoffset\scratchbox-.5\dimexpr\wd\scratchbox-\d_framed_target_wd\relax % was \d_overlay_width
+ \boxyoffset\scratchbox-.5\dimexpr\ht\scratchbox-\d_framed_target_ht+\d_framed_target_dp\relax % not \d_overlay_height !
+ \wd\scratchbox\d_framed_target_wd
+ \ht\scratchbox\d_framed_target_ht
+ \dp\scratchbox\d_framed_target_dp
+ \box\scratchbox
+ \egroup}
+
+%D \macros
+%D {overlayfakebox}
+
+% \unexpanded\def\overlayfakebox
+% {\hpack
+% {\setbox\scratchbox\emptyhbox
+% \wd\scratchbox\d_overlay_width
+% \ht\scratchbox\d_overlay_height
+% \box\scratchbox}}
+
+\unexpanded\def\overlayfakebox
+ {\hpack % redundant but needs testing
+ {\novrule
+ \s!width \d_overlay_width
+ \s!height\d_overlay_height
+ \s!depth \zeropoint}}
+
+%D For testing we provide:
+
+\def\doifelseoverlay#1% only tests external overlays
+ {\ifcsname\??overlay#1\endcsname
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\let\doifoverlayelse\doifelseoverlay
+
+%D The content of the box will be (temporary) saved in a box. We also have an
+%D extra box for backgrounds.
+
+\newbox\b_framed_normal
+\newbox\b_framed_extra
+
+\newtoks\everybackgroundbox
+
+\let\m_framed_background\empty % we might need a public name
+
+\def\pack_framed_process_background
+ {\ifcsname\??overlaybuiltin\m_framed_background\endcsname
+ \expandafter\pack_framed_process_background_indeed_internal\lastnamedcs
+ \orelse\ifcsname\??overlay\m_framed_background\endcsname
+ \expandafter\pack_framed_process_background_indeed_external\lastnamedcs
+ \fi}
+
+\def\pack_framed_process_background_indeed_internal#1% % : in name
+ {\bgroup
+ \setbox\b_framed_extra\hpack\bgroup
+ \ifzeropt\framedbackgroundoffset\else
+ \kern-\framedbackgroundoffset
+ \fi
+ \hbox\bgroup#1\egroup
+ \egroup
+ \wd\b_framed_extra\zeropoint
+ \ht\b_framed_extra\framedbackgroundheight
+ \dp\b_framed_extra\framedbackgrounddepth
+ \box\b_framed_extra
+ \egroup}
+
+\def\pack_framed_process_background_indeed_external
+ {\pack_framed_overlay_initialize
+ \pack_framed_process_background_indeed_internal}
+
+\def\pack_framed_process_backgrounds#1,#2% #2 gobbles spaces (we could avoid one catch if we have nextbackground)
+ {\edef\m_framed_background{#1}%
+ \ifx\m_framed_background\s!unknown\else
+ \pack_framed_process_background
+ \expandafter\pack_framed_process_backgrounds
+ \fi#2}
+
+%D Beware, a backgroundbox can be empty which is another reason why we set the
+%D width to zero instead of back-skipping.
+
+\newdimen\framedbackgroundwidth
+\newdimen\framedbackgroundheight
+\newdimen\framedbackgrounddepth
+\newdimen\framedbackgroundoffset
+
+\def\pack_framed_background_box_content% fuzzy but needed hack, this \vss, otherwise
+ {\vpack to \framedbackgroundheight{\vss\box\b_framed_normal\vss}} % vertical shift \backgroundheight
+
+\def\pack_framed_set_region % experiment
+ {\ifx\m_overlay_region\v!yes
+ \edef\m_overlay_region{\reservedautoregiontag}%
+ \fi}
+
+\def\pack_framed_add_region % experiment
+ {\anch_mark_tagged_box\b_framed_normal\m_overlay_region}
+
+\def\pack_framed_add_background
+ {\setbox\b_framed_normal\hpack % was vbox % see also *1*
+ {%\pack_framed_forgetall % can be relaxed
+ \boxmaxdepth\maxdimen
+ \framedbackgroundoffset\d_framed_backgroundoffset
+ \framedbackgroundwidth \wd\b_framed_normal
+ \framedbackgroundheight\ht\b_framed_normal
+ \framedbackgrounddepth \dp\b_framed_normal
+ \d_framed_target_wd\dimexpr\framedbackgroundwidth +2\framedbackgroundoffset\relax
+ \d_framed_target_ht\dimexpr\framedbackgroundheight+ \framedbackgroundoffset\relax
+ \d_framed_target_dp\dimexpr\framedbackgrounddepth + \framedbackgroundoffset+\framedparameter\c!backgrounddepth\relax
+ \let\pack_framed_overlay_initialize\pack_framed_overlay_initialize_indeed
+ \ifx\p_framed_component\empty
+ \resetlayoutcomponentattribute
+ \else
+ \setlayoutcomponentattribute{\v!background:\p_framed_component}%
+ \fi
+ \let\foregroundbox\pack_framed_background_box_content
+ \hpack \layoutcomponentboxattribute to \framedbackgroundwidth\bgroup % width in case 'foreground' is used as overlay
+ \the\everybackgroundbox % moved
+ \expandafter\pack_framed_process_backgrounds\p_framed_background,\s!unknown,\relax % hm, messy .. look into it
+ \box\b_framed_normal
+ \hss
+ \egroup}}
+
+\def\pack_framed_overlay_initialize_indeed
+ {\d_overlay_width \d_framed_target_wd
+ \d_overlay_height \dimexpr\d_framed_target_ht+\d_framed_target_dp\relax
+ \d_overlay_depth \d_framed_target_dp
+ \d_overlay_linewidth \d_framed_linewidth
+ \d_overlay_offset \framedbackgroundoffset\relax
+ \edef\overlaycolor {\framedparameter\c!backgroundcolor}% let ?
+ \edef\overlaylinecolor{\framedparameter\c!framecolor}% only needed for layers
+ %\edef\overlaycorner {\framedparameter\c!backgroundcorner}%
+ %\edef\overlayradius {\framedparameter\c!backgroundradius}%
+ \let\pack_framed_overlay_initialize\relax}
+
+%D One can explictly insert the foreground box. For that purpose we introduce the
+%D overlay \type {foreground}.
+%D
+%D We predefine two already familiar backgrounds:
+
+%letvalue{\??overlaybuiltin\v!screen }\pack_framed_background_box_gray
+\letvalue{\??overlaybuiltin\v!color }\pack_framed_background_box_color
+\letvalue{\??overlaybuiltin\v!foreground}\pack_framed_background_box_content % replaces: \defineoverlay[\v!foreground][\foregroundbox]
+
+%D We can specify overlays as a comma separated list of overlays, a sometimes
+%D handy feature.
+%D
+%D Besides backgrounds (overlays) we also need some macros to draw outlines (ruled
+%D borders). Again we have to deal with square and round corners. The first category
+%D can be handled by \TEX\ itself, the latter one depends on the driver. This macro
+%D also support a negative offset.
+
+\def\pack_framed_add_outline
+ {\setbox\b_framed_normal\hpack % rules on top of box
+ {\d_framed_target_wd\dimexpr\wd\b_framed_normal+2\d_framed_frameoffset\relax
+ \d_framed_target_ht\dimexpr\ht\b_framed_normal+ \d_framed_frameoffset\relax
+ \d_framed_target_dp\dimexpr\dp\b_framed_normal+ \d_framed_frameoffset+\framedparameter\c!framedepth\relax
+ \ifdim\d_framed_target_dp<\zeropoint
+ \advance\d_framed_target_ht \d_framed_target_dp
+ \scratchdimen-\d_framed_target_dp
+ \d_framed_target_dp\zeropoint
+ \else
+ \scratchdimen\zeropoint
+ \fi
+ \edef\overlaylinecolor{\framedparameter\c!framecolor}% twice, also in background
+ \setbox\b_framed_extra\hpack
+ {\kern-\d_framed_frameoffset
+ \raise\scratchdimen
+ \hpack{\ifx\overlaylinecolor\empty\else\dousecolorparameter\overlaylinecolor\fi\pack_framed_stroked_box}}%
+ \wd\b_framed_extra\wd\b_framed_normal
+ \ht\b_framed_extra\ht\b_framed_normal
+ \dp\b_framed_extra\dp\b_framed_normal
+ \wd\b_framed_normal\zeropoint
+ \box\b_framed_normal
+ \box\b_framed_extra}}
+
+\def\pack_framed_stroked_box_normal_opened
+ {\setbox\scratchbox\vpack \bgroup
+ \csname\??framedtop\p_framed_frame\framedparameter\c!topframe\endcsname
+ \nointerlineskip % new (needed for fences)
+ \hpack \bgroup
+ \csname\??framedleft\p_framed_frame\framedparameter\c!leftframe\endcsname
+ \novrule
+ \s!width \d_framed_target_wd
+ \s!height\d_framed_target_ht
+ \s!depth \d_framed_target_dp
+ \csname\??framedright\p_framed_frame\framedparameter\c!rightframe\endcsname
+ \egroup
+ \nointerlineskip % new (needed for fences)
+ \csname\??framedbottom\p_framed_frame\framedparameter\c!bottomframe\endcsname
+ \egroup
+ \wd\scratchbox\d_framed_target_wd
+ \ht\scratchbox\d_framed_target_ht
+ \dp\scratchbox\d_framed_target_dp
+ \box\scratchbox}
+
+\def\pack_framed_stroked_box_normal_closed
+ {\hpack\bgroup
+ \scratchdimen.5\d_framed_linewidth
+ \hskip\scratchdimen
+ \clf_framedoutline
+ \dimexpr\d_framed_target_wd-\d_framed_linewidth\relax
+ \dimexpr\d_framed_target_ht-\scratchdimen\relax
+ \dimexpr\d_framed_target_dp-\scratchdimen\relax
+ \d_framed_linewidth
+ \relax
+ \egroup}
+
+\def\pack_framed_stroked_box_normal
+ {\ifx\p_framed_frame\v!closed
+ \pack_framed_stroked_box_normal_closed
+ \else
+ \pack_framed_stroked_box_normal_opened
+ \fi}
+
+\def\pack_framed_t_rule{\hrule\s!height\d_framed_linewidth\kern-\d_framed_linewidth}
+\def\pack_framed_b_rule{\kern-\d_framed_linewidth\hrule\s!height\d_framed_linewidth}
+\def\pack_framed_r_rule{\kern-\d_framed_linewidth\vrule\s!width\d_framed_linewidth}
+\def\pack_framed_l_rule{\vrule\s!width\d_framed_linewidth\kern-\d_framed_linewidth}
+
+\letvalue{\??framedtop \v!on \v!on}\pack_framed_t_rule
+\letvalue{\??framedtop \v!off\v!on}\pack_framed_t_rule
+\letvalue{\??framedtop \v!on }\pack_framed_t_rule
+
+\letvalue{\??framedbottom\v!on \v!on}\pack_framed_b_rule
+\letvalue{\??framedbottom\v!off\v!on}\pack_framed_b_rule
+\letvalue{\??framedbottom\v!on }\pack_framed_b_rule
+
+\letvalue{\??framedleft \v!on \v!on}\pack_framed_l_rule
+\letvalue{\??framedleft \v!off\v!on}\pack_framed_l_rule
+\letvalue{\??framedleft \v!on }\pack_framed_l_rule
+
+\letvalue{\??framedright \v!on \v!on}\pack_framed_r_rule
+\letvalue{\??framedright \v!off\v!on}\pack_framed_r_rule
+\letvalue{\??framedright \v!on }\pack_framed_r_rule
+
+% no overlapping rules
+
+\def\pack_framed_t_rules{\hpack{\kern\d_framed_linewidth\vrule\s!width\dimexpr\d_framed_target_wd-2\d_framed_linewidth\relax\s!height\d_framed_linewidth}\nointerlineskip\kern-\d_framed_linewidth}
+\def\pack_framed_b_rules{\kern-\d_framed_linewidth\nointerlineskip\hpack{\kern\d_framed_linewidth\vrule\s!width\dimexpr\d_framed_target_wd-2\d_framed_linewidth\relax\s!height\d_framed_linewidth}}
+\def\pack_framed_r_rules{\kern-\d_framed_linewidth\vrule\s!height\dimexpr\d_framed_target_ht-\d_framed_linewidth\relax\s!depth-\d_framed_linewidth\s!width\d_framed_linewidth}
+\def\pack_framed_l_rules{\vrule\s!height\dimexpr\d_framed_target_ht-\d_framed_linewidth\relax\s!depth-\d_framed_linewidth\s!width\d_framed_linewidth\kern-\d_framed_linewidth}
+
+\letvalue{\??framedtop \v!small\v!small}\pack_framed_t_rules
+\letvalue{\??framedtop \v!off \v!small}\pack_framed_t_rules
+\letvalue{\??framedtop \v!small }\pack_framed_t_rules
+
+\letvalue{\??framedbottom\v!small\v!small}\pack_framed_b_rules
+\letvalue{\??framedbottom\v!off \v!small}\pack_framed_b_rules
+\letvalue{\??framedbottom\v!small }\pack_framed_b_rules
+
+\letvalue{\??framedleft \v!small\v!small}\pack_framed_l_rules
+\letvalue{\??framedleft \v!off \v!small}\pack_framed_l_rules
+\letvalue{\??framedleft \v!small }\pack_framed_l_rules
+
+\letvalue{\??framedright \v!small\v!small}\pack_framed_r_rules
+\letvalue{\??framedright \v!off \v!small}\pack_framed_r_rules
+\letvalue{\??framedright \v!small }\pack_framed_r_rules
+
+% \framed
+% [width=4cm,height=3cm,rulethickness=3mm,
+% frame=off,rightframe=on,leftframe=on,topframe=on,bottomframe=on]
+% {}
+% \framed
+% [width=4cm,height=3cm,rulethickness=3mm,
+% frame=off,rightframe=small,leftframe=small,topframe=small,bottomframe=small]
+% {}
+% \framed
+% [width=4cm,height=3cm,rulethickness=3mm,
+% frame=off,rightframe=small,leftframe=small,topframe=small,bottomframe=on]
+% {}
+
+%D The next few macros are probably the most misused ones in \CONTEXT. They deal
+%D with putting rules around boxes, provide backgrounds, offer alignment features,
+%D and some more. We start with defining some booleans. These give an impression of
+%D what we are going to take into account.
+
+% todo : \c_framed_hasoffset
+% faster : \let\c_framed_hasoffset\falseconditional
+
+\newconditional\c_framed_has_offset
+\newconditional\c_framed_has_width
+\newconditional\c_framed_has_height
+\newconditional\c_framed_has_format
+\newconditional\c_framed_is_overlaid
+\newconditional\c_framed_has_frame
+\newconditional\c_framed_has_extra_offset
+\newconditional\c_framed_text_location_none
+
+\newconstant \c_framed_has_strut % 0=relaxes 1=pseudostruts 2=realstruts
+
+%D \macros
+%D {framed, setupframed}
+%D
+%D Ruled boxes are typeset using \type{\framed}. This command is quite versatile
+%D and, although some users will probably seldom use it, one cannot overlook its
+%D features.
+%D
+%D \showsetup{setupframed}
+%D \showsetup{framed}
+%D
+%D This general macro is a special version of an even more general case, that can
+%D easily be linked into other macros that need some kind of framing. The local
+%D version is called with an extra parameter: the variable identifier. The reason
+%D for passing this identifier between brackets lays in the mere fact that this way
+%D we can use the optional argument grabbers.
+
+\def\defaultframeoffset{.25\exheight}
+
+\installcorenamespace{regularframedlevel}
+
+\unexpanded\def\installregularframed#1%
+ {\defineframed[#1]}
+
+\unexpanded\def\presetlocalframed[#1]%
+ {\defineframed[#1]}
+
+% \presetlocalframed[\??framed]
+
+\newcount\c_pack_framed_nesting
+
+\unexpanded\def\pack_framed_process_framed[#1]%
+ {\bgroup
+ \iffirstargument % faster
+ \setupcurrentframed[#1]% here !
+ \fi
+ \pack_framed_process_indeed}
+
+\unexpanded\def\framed
+ {\bgroup
+ \advance\c_pack_framed_nesting\plusone
+ \expandafter\let\csname\??framed>\the\c_pack_framed_nesting:\s!parent\endcsname\??framed
+ \edef\currentframed{>\the\c_pack_framed_nesting}%
+ \pack_framed_initialize
+ \dosingleempty\pack_framed_process_framed}
+
+\unexpanded\def\startframed
+ {\dosingleempty\pack_framed_start_framed}
+
+\def\pack_framed_start_framed[#1]%
+ {\bgroup
+ \doifelseassignment{#1}\pack_framed_start_framed_yes\pack_framed_start_framed_nop{#1}}
+
+\def\pack_framed_start_framed_yes#1%
+ {\advance\c_pack_framed_nesting\plusone
+ \expandafter\let\csname\??framed>\the\c_pack_framed_nesting:\s!parent\endcsname\??framed
+ \iffirstargument\secondargumenttrue\fi % dirty trick
+ \edef\currentframed{>\the\c_pack_framed_nesting}%
+ \pack_framed_initialize
+ \bgroup
+ \iffirstargument
+ \secondargumenttrue % dirty trick
+ \setupcurrentframed[#1]% here !
+ \fi
+ \pack_framed_process_indeed
+ \bgroup
+ \ignorespaces}
+
+\def\pack_framed_start_framed_nop#1%
+ {\edef\currentframed{#1}%
+ \dosingleempty\pack_framed_start_framed_nop_indeed}
+
+\def\pack_framed_start_framed_nop_indeed[#1]%
+ {\pack_framed_initialize
+ \bgroup
+ \iffirstargument
+ \setupcurrentframed[#1]% here !
+ \fi
+ \pack_framed_process_indeed
+ \bgroup
+ \ignorespaces}
+
+% till here
+
+\unexpanded\def\stopframed
+ {\removeunwantedspaces
+ \egroup}
+
+\unexpanded\def\normalframedwithsettings[#1]%
+ {\bgroup
+ \advance\c_pack_framed_nesting\plusone
+ \expandafter\let\csname\??framed>\the\c_pack_framed_nesting:\s!parent\endcsname\??framed
+ \bgroup
+ \edef\currentframed{>\the\c_pack_framed_nesting}%
+ \pack_framed_initialize
+ \setupcurrentframed[#1]%
+ \pack_framed_process_indeed}
+
+%D \startbuffer
+%D \setupframed [framecolor=yellow] \framed{A}
+%D \defineframed[myframed] [framecolor=blue] \myframed{B}
+%D \setupframed [myframed] [framecolor=red] \myframed{C}
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \presetlocalframed[myframed]
+%D \localframed[myframed][framecolor=green]{oeps}
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+%D \macros
+%D {ifinframed}
+%D
+%D The normal case first presets all parameters and next starts looking for the user
+%D supplied ones. The first step is omitted in the local case, because these are
+%D preset at declaration time and keep their values unless explictly changed. By
+%D presetting the variables everytime the normal command is called, we can use this
+%D command nested, without the unwanted side effect of inheritance. The boolean is
+%D used to speed up the color stack.
+
+\newif\ifinframed
+
+%D The next one is faster on multiple backgrounds per page. No
+%D dimensions can be set, only frames and backgrounds.
+
+\unexpanded\def\fastlocalframed[#1]#2[#3]#4% 3-4
+ {\bgroup
+ \edef\currentframed{#1}%
+ \pack_framed_initialize
+ \setbox\b_framed_normal\hbox{#4}%
+ \iftrialtypesetting \else
+ \edef\m_overlay_region{\framedparameter\c!region}%
+ \ifx\m_overlay_region\empty\else
+ \pack_framed_set_region
+ \fi
+ \fi
+ \setupcurrentframed[#3]%
+ \edef\p_framed_rulethickness{\framedparameter\c!rulethickness}% also used in backgrounds
+ \d_framed_frameoffset\framedparameter\c!frameoffset\relax % also used in backgrounds
+ \edef\p_framed_frame{\framedparameter\c!frame}%
+ \edef\p_framed_background{\framedparameter\c!background}%
+ % not here, in calling macro: setups
+ \pack_framed_remove_depth
+ \ifx\p_framed_frame\v!overlay \orelse \ifx\p_framed_frame\v!none \else
+ \ifx\p_framed_rulethickness\empty\else
+ \d_framed_linewidth\p_framed_rulethickness\relax
+ \fi
+ \pack_framed_add_outline % real or invisible frame
+ \fi
+ \ifx\p_framed_background\empty \else
+ \edef\p_framed_backgroundoffset{\framedparameter\c!backgroundoffset}%
+ \d_framed_backgroundoffset
+ \ifx\p_framed_backgroundoffset\v!frame
+ \d_framed_frameoffset
+ \else
+ \p_framed_backgroundoffset
+ \fi
+ \edef\p_framed_component{\framedparameter\c!component}%
+ \pack_framed_add_background
+ \fi
+ \pack_framed_restore_depth
+ \iftrialtypesetting\orelse\ifx\m_overlay_region\empty\else
+ \pack_framed_add_region
+ \fi
+ \box\b_framed_normal
+ \egroup}
+
+%D The next macro uses a box and takes its natural width and height so these
+%D can better be correct.
+
+\unexpanded\def\pack_framed_process_box_indeed#1#2% component box (assumes parameters set and grouped usage)
+ {\setbox\b_framed_normal\box#2% could actually be \let\b_framed_normal#2
+ \edef\m_overlay_region{\framedparameter\c!region}%
+ \ifx\m_overlay_region\empty\else
+ \pack_framed_set_region
+ \fi
+ \edef\p_framed_rulethickness{\framedparameter\c!rulethickness}% also used in backgrounds
+ \d_framed_frameoffset\framedparameter\c!frameoffset\relax % also used in backgrounds
+ \edef\p_framed_frame{\framedparameter\c!frame}%
+ \edef\p_framed_background{\framedparameter\c!background}%
+ \ifx\p_framed_frame\v!overlay \orelse \ifx\p_framed_frame\v!none \else
+ \ifx\p_framed_rulethickness\empty \else
+ \d_framed_linewidth\p_framed_rulethickness\relax
+ \fi
+ \pack_framed_add_outline % real or invisible frame
+ \fi
+ \ifx\p_framed_background\empty \else
+ \edef\p_framed_backgroundoffset{\framedparameter\c!backgroundoffset}%
+ \d_framed_backgroundoffset
+ \ifx\p_framed_backgroundoffset\v!frame
+ \d_framed_frameoffset
+ \else
+ \p_framed_backgroundoffset
+ \fi
+ \edef\p_framed_component{#1}%
+ \pack_framed_add_background
+ \fi
+ \ifx\m_overlay_region\empty\else
+ \pack_framed_add_region
+ \fi
+ \box\b_framed_normal
+ \egroup}
+
+\unexpanded\def\localbackgroundframed#1% namespace component box
+ {\bgroup
+ \edef\currentframed{#1}%
+ \pack_framed_initialize
+ \pack_framed_process_box_indeed} % group ends here
+
+\let\postprocessframebox\relax
+
+%D A nice example by Aditya:
+%D
+%D \starttyping
+%D \setupframed
+%D [loffset=\framedparameter{hoffset},
+%D roffset=\framedparameter{hoffset},
+%D hoffset=\zeropoint]
+%D
+%D \defineframed[test][hoffset=1cm]
+%D \stoptyping
+
+\newdimen\d_framed_width
+\newdimen\d_framed_height
+\newdimen\d_framed_frameoffset
+\newdimen\d_framed_backgroundoffset
+\newdimen\d_framed_local_offset
+
+% todo: protect local \framednames
+
+\unexpanded\def\localframed
+ {\bgroup
+ \dodoubleempty\pack_framed_local}
+
+\unexpanded\def\pack_framed_local[#1][#2]%
+ {\bgroup
+ \edef\currentframed{#1}%
+ \pack_framed_initialize
+ \ifsecondargument % faster
+ \setupcurrentframed[#2]% here !
+ \fi
+ \pack_framed_process_indeed}
+
+\unexpanded\def\directlocalframed[#1]% no optional
+ {\bgroup
+ \bgroup
+ \edef\currentframed{#1}%
+ \pack_framed_initialize
+ \pack_framed_process_indeed}
+
+\unexpanded\def\localframedwithsettings[#1][#2]% no checking (so no spaces between)
+ {\bgroup
+ \bgroup
+ \edef\currentframed{#1}%
+ \pack_framed_initialize
+ \setupcurrentframed[#2]% here !
+ \pack_framed_process_indeed}
+
+% done
+
+\def\c!fr!analyze{fr:analyze} % private option
+
+\let\delayedbegstrut\relax
+\let\delayedendstrut\relax
+\let\delayedstrut \relax
+
+\let\localoffset\empty
+\let\localwidth \empty
+\let\localheight\empty
+\let\localformat\empty
+\let\localstrut \empty
+
+\unexpanded\def\pack_framed_process_indeed
+ {\d_framed_frameoffset\framedparameter\c!frameoffset
+ \edef\p_framed_backgroundoffset{\framedparameter\c!backgroundoffset}%
+ \d_framed_backgroundoffset
+ \ifx\p_framed_backgroundoffset\v!frame
+ \d_framed_frameoffset
+ \else
+ \p_framed_backgroundoffset
+ \fi
+ % new, experimental dirty hook
+ \framedparameter\c!extras
+ % to get the right spacing
+ \edef\p_framed_foregroundstyle{\framedparameter\c!foregroundstyle}%
+ \ifx\p_framed_foregroundstyle\empty\else\dousestyleparameter\p_framed_foregroundstyle\fi
+ % beware, both the frame and background offset can be overruled
+ %
+ \edef\p_framed_setups{\framedparameter\c!setups}%
+ % the next macros are visible
+ \edef\localoffset{\framedparameter\c!offset}%
+ \edef\localwidth {\framedparameter\c!width}%
+ \edef\localheight{\framedparameter\c!height}%
+ \edef\localformat{\framedparameter\c!align}%
+ \edef\localstrut {\framedparameter\c!strut}%
+ % these are not
+ \edef\p_framed_autostrut {\framedparameter\c!autostrut}%
+ \edef\p_framed_frame {\framedparameter\c!frame}%
+ \edef\p_framed_location {\framedparameter\c!location}%
+ \edef\p_framed_orientation{\framedparameter\c!orientation}%
+ \edef\p_framed_anchoring {\framedparameter\c!anchoring}%
+ %
+ \edef\p_framed_autowidth {\framedparameter\c!autowidth}%
+ \edef\p_framed_franalyze {\framedparameter\c!fr!analyze}% experimental option
+ %
+ \ifx\p_framed_frame\v!overlay % no frame, no offset, no framewidth
+ \setfalse\c_framed_has_frame
+ \let\localoffset\v!overlay
+ \orelse\ifx\p_framed_frame\v!none % no frame, no framewidth
+ \setfalse\c_framed_has_frame
+ \else
+ \settrue\c_framed_has_frame
+ \fi
+ \ifconditional\c_framed_has_frame
+ \edef\p_framed_rulethickness{\framedparameter\c!rulethickness}%
+ \ifx\p_framed_rulethickness\empty\else
+ \d_framed_linewidth\p_framed_rulethickness\relax
+ \fi
+ \else
+ \d_framed_linewidth\zeropoint
+ \fi
+ % 2013/03/12: a change of order (sizes before align
+ \ifx\localwidth\v!local
+ \setlocalhsize
+ \fi
+ %
+ \forgetall % should happen after \localwidth but before align
+ %
+ \ifx\localformat\empty
+ \setfalse\c_framed_has_format
+ \else
+ \settrue\c_framed_has_format
+ \dosetraggedcommand\localformat % not that fast
+ \fi
+ %
+ \ifcsname\??framedoffsetalternative\localoffset\endcsname
+ \lastnamedcs
+ \else
+ \framed_offset_alternative_unknown
+ \fi
+ \ifcsname\??framedwidthalternative\localwidth\endcsname
+ \lastnamedcs
+ \else
+ \framed_width_alternative_unknown
+ \fi
+ \ifcsname\??framedheightalternative\localheight\endcsname
+ \lastnamedcs
+ \else
+ \framed_height_alternative_unknown
+ \fi
+ % the next check could move to heightalternative
+ \ifconditional\c_framed_has_height
+ % obey user set height, also downward compatible
+ \else
+ \edef\p_framed_lines{\framedparameter\c!lines}%
+ \ifx\p_framed_lines\empty
+ \orelse\ifcase\p_framed_lines
+ \else
+ \d_framed_height\p_framed_lines\lineheight
+ \edef\localheight{\the\d_framed_height}%
+ \settrue\c_framed_has_height
+ \fi
+ \fi
+ % this is now an option: width=local
+ %
+ % \ifdim\d_framed_width=\hsize
+ % \parindent\zeropoint
+ % \setlocalhsize
+ % \d_framed_width\localhsize
+ % \fi
+ % i.e. disable (colsetbackgroundproblemintechniek)
+ \advance\d_framed_width -2\d_framed_local_offset
+ \advance\d_framed_height -2\d_framed_local_offset
+ \ifcsname\??framedstrutalternative\localstrut\endcsname
+ \lastnamedcs
+ \else
+ \framed_offset_alternative_unknown
+ \fi
+ % the next check could move to strutalternative
+ \ifcase\c_framed_has_strut % none (not even noindent)
+ \let\localbegstrut\relax
+ \let\localendstrut\relax
+ \let\localstrut \relax
+ \or % no / overlay
+ \let\localbegstrut\pseudobegstrut
+ \let\localendstrut\pseudoendstrut
+ \let\localstrut \pseudostrut
+ \else
+ \let\localbegstrut\begstrut
+ \let\localendstrut\endstrut
+ \let\localstrut \strut
+ \fi
+ \ifx\p_framed_autostrut\v!yes
+ \let\delayedbegstrut\relax
+ \let\delayedendstrut\relax
+ \let\delayedstrut \relax
+ \else
+ \let\delayedbegstrut\localbegstrut
+ \let\delayedendstrut\localendstrut
+ \let\delayedstrut \localstrut
+ \let\localbegstrut \relax
+ \let\localendstrut \relax
+ \let\localstrut \relax
+ \fi
+ \ifconditional\c_framed_has_height
+ \let\\\pack_framed_vboxed_newline
+ \ifconditional\c_framed_has_width
+ \let\hairline\pack_framed_vboxed_hairline
+ \ifconditional\c_framed_has_format
+ \let\next\pack_framed_format_format_yes
+ \else
+ \let\next\pack_framed_format_format_nop
+ \fi
+ \else
+ \let\hairline\pack_framed_hboxed_hairline
+ \ifconditional\c_framed_has_format
+ \let\next\pack_framed_format_format_height
+ \else
+ \let\next\pack_framed_format_format_vsize
+ \fi
+ \fi
+ \orelse\ifconditional\c_framed_has_width
+ \ifconditional\c_framed_has_format
+ \let\hairline\pack_framed_vboxed_hairline
+ \let\\\pack_framed_vboxed_newline
+ \let\next\pack_framed_format_format_width
+ \else
+ \let\hairline\pack_framed_hboxed_hairline
+ \let\\\pack_framed_hboxed_newline
+ \let\next\pack_framed_format_format_hsize
+ \fi
+ \else
+ \let\hairline\pack_framed_hboxed_hairline
+ \let\\\pack_framed_hboxed_newline
+ \let\next\pack_framed_format_format_no_size
+ \fi
+ \pack_framed_check_extra_offsets
+ \edef\p_framed_background{\framedparameter\c!background}%
+% \ifx\p_framed_background\empty
+% \let\pack_framed_forgetall\forgetall
+% \else
+% \let\pack_framed_forgetall\relax
+% \forgetall
+% \fi
+ \edef\framedwidth {\the\ifdim\d_framed_width >\zeropoint \d_framed_width \else\zeropoint\fi}% public
+ \edef\framedheight{\the\ifdim\d_framed_height>\zeropoint \d_framed_height\else\zeropoint\fi}% public
+ \edef\framedoffset{\the\dimexpr\ifconditional\c_framed_has_offset\localoffset \else\zeropoint\fi}% public
+ \ifx\p_framed_orientation\empty
+ \let\pack_framed_stop_orientation\relax
+ \else
+ \pack_framed_start_orientation
+ \fi
+ \afterassignment\pack_framed_restart
+ \setbox\b_framed_normal\next}
+
+% alternatives for width, height, strut and offset
+
+\installcorenamespace{framedwidthalternative}
+\installcorenamespace{framedheightalternative}
+\installcorenamespace{framedstrutalternative}
+\installcorenamespace{framedoffsetalternative}
+
+% widths
+
+\setvalue{\??framedwidthalternative\empty}%
+ {\ifconditional\c_framed_has_format
+ \settrue\c_framed_has_width
+ \d_framed_width\hsize
+ \else
+ \setfalse\c_framed_has_width
+ \d_framed_width\zeropoint
+ \fi}
+
+\setvalue{\??framedwidthalternative\v!fit}%
+ {\ifconditional\c_framed_has_format
+ \settrue\c_framed_has_width
+ \d_framed_width\hsize
+ \else
+ \setfalse\c_framed_has_width
+ \d_framed_width\zeropoint
+ \fi}
+
+\setvalue{\??framedwidthalternative\v!fixed}% equals \v!fit but no shapebox
+ {\ifconditional\c_framed_has_format
+ \settrue\c_framed_has_width
+ \d_framed_width\hsize
+ \else
+ \setfalse\c_framed_has_width
+ \d_framed_width\zeropoint
+ \fi}
+
+\setvalue{\??framedwidthalternative\v!broad}%
+ {\settrue\c_framed_has_width
+ \d_framed_width\hsize}
+
+\setvalue{\??framedwidthalternative\v!max}% idem broad
+ {\settrue\c_framed_has_width
+ \d_framed_width\hsize}
+
+\setvalue{\??framedwidthalternative\v!local}%
+ {\settrue\c_framed_has_width
+ %\setlocalhsize
+ \d_framed_width\localhsize}
+
+\setvalue{\??framedwidthalternative\s!unknown}%
+ {\settrue\c_framed_has_width
+ \d_framed_width\localwidth}
+
+\def\framed_width_alternative_unknown
+ {\settrue\c_framed_has_width
+ \d_framed_width\localwidth}
+
+% heights
+
+\setvalue{\??framedheightalternative\empty}%
+ {\setfalse\c_framed_has_height
+ \d_framed_height\zeropoint}
+
+\setvalue{\??framedheightalternative\v!fit}%
+ {\setfalse\c_framed_has_height
+ \d_framed_height\zeropoint}
+
+\setvalue{\??framedheightalternative\v!broad}%
+ {\setfalse\c_framed_has_height
+ \d_framed_height\zeropoint}
+
+\setvalue{\??framedheightalternative\v!max}%
+ {\settrue\c_framed_has_height
+ \d_framed_height\vsize}
+
+\setvalue{\??framedheightalternative\s!unknown}%
+ {\settrue\c_framed_has_height
+ \d_framed_height\localheight}
+
+\def\framed_height_alternative_unknown
+ {\settrue\c_framed_has_height
+ \d_framed_height\localheight}
+
+% struts (use let instead?)
+
+\setvalue{\??framedstrutalternative\v!no}%
+ {\c_framed_has_strut\plusone}
+
+\setvalue{\??framedstrutalternative\v!global}%
+ {\setstrut}
+
+\setvalue{\??framedstrutalternative\v!local}%
+ {\setfontstrut}
+
+\setvalue{\??framedstrutalternative\v!yes}%
+ {\setstrut}
+
+\setvalue{\??framedstrutalternative\s!unknown}%
+ {\setstrut}
+
+\def\framed_strut_alternative_unknown
+ {\setstrut}
+
+\setvalue{\??framedstrutalternative\v!none}% not even pseudo struts
+ {\c_framed_has_strut\zerocount}
+
+% offsets
+
+\setvalue{\??framedoffsetalternative\v!none}%
+ {\setfalse\c_framed_has_offset
+ \c_framed_has_strut\plusone
+ \setfalse\c_framed_is_overlaid
+ \d_framed_local_offset\d_framed_linewidth}
+
+\setvalue{\??framedoffsetalternative\v!overlay}%
+ {% \ifx\p_framed_frame\v!no \setfalse\c_framed_has_frame \fi % test first
+ \setfalse\c_framed_has_offset
+ \c_framed_has_strut\plusone
+ \settrue\c_framed_is_overlaid
+ \d_framed_local_offset\zeropoint}
+
+% \setvalue{\??framedoffsetalternative\v!strut}%
+% {\setfalse\c_framed_has_offset
+% \c_framed_has_strut\plustwo
+% \settrue\c_framed_is_overlaid
+% \d_framed_local_offset\zeropoint}
+
+\setvalue{\??framedoffsetalternative\v!default}% new per 2-6-2000
+ {\settrue \c_framed_has_offset
+ \c_framed_has_strut\plustwo
+ \setfalse\c_framed_is_overlaid
+ \let\localoffset\defaultframeoffset
+ \letframedparameter\c!offset\defaultframeoffset % brrr
+ \d_framed_local_offset\dimexpr\localoffset+\d_framed_linewidth\relax}
+
+\def\framed_offset_alternative_unknown
+ {\settrue \c_framed_has_offset
+ \c_framed_has_strut\plustwo
+ \setfalse\c_framed_is_overlaid
+ \let\defaultframeoffset\localoffset
+ \d_framed_local_offset\dimexpr\localoffset+\d_framed_linewidth\relax}
+
+\letvalue{\??framedoffsetalternative\s!unknown}\framed_offset_alternative_unknown
+
+% so far for alternatives
+
+\let\pack_framed_stop_orientation\relax
+
+\def\pack_framed_restart
+ {\aftergroup\pack_framed_finish}
+
+\def\pack_framed_do_top
+ {\raggedtopcommand
+ \framedparameter\c!top
+ \edef\p_blank{\framedparameter\c!blank}%
+ \ifx\p_blank\v!yes\else % auto or no
+ \doinhibitblank
+ \fi}
+
+\def\pack_framed_do_bottom
+ {\framedparameter\c!bottom
+ \raggedbottomcommand}
+
+%D Careful analysis of this macro will learn us that not all branches in the last
+%D conditionals can be encountered, that is, some assignments to \type{\next} will
+%D never occur. Nevertheless we implement the whole scheme, if not for future
+%D extensions.
+
+%D \macros
+%D {doassigncheckedframeoffset}
+%D
+%D Offset helper (see menus):
+
+\def\doassigncheckedframeoffset#1#2% could be a fast \csname .. \endcsname
+ {\edef\checkedframeoffset{#2}%
+ #1%
+ \ifx\checkedframeoffset\empty \zeropoint\orelse
+ \ifx\checkedframeoffset\v!overlay\zeropoint\orelse
+ \ifx\checkedframeoffset\v!none \zeropoint\orelse
+ \ifx\checkedframeoffset\v!frame \zeropoint\orelse
+ \ifx\checkedframeoffset\v!default\zeropoint\else
+ #2%
+ \fi
+ \relax}
+
+%D \macros
+%D {ifreshapeframebox}
+%D
+%D The last few lines tell what to do after the content of the box is collected and
+%D passed to the next macro. In the case of a fixed width and centered alignment,
+%D the content is evaluated and used to determine the most natural width. The rest
+%D of the code deals with backgrounds and frames.
+
+\newif\ifreshapeframebox \reshapeframeboxtrue
+
+%D Beware: setting \type {top} and \type {bottom} to nothing, may
+%D result in a frame that is larger that the given height! try:
+%D
+%D \starttyping
+%D \framed
+%D [height=3cm,top=,bottom=,offset=overlay]
+%D {\strut test \shapefill \strut test}
+%D \stoptyping
+%D
+%D This is intended behaviour and not a bug! One can always set
+%D
+%D \starttyping
+%D ...,bottom=\kern0pt,...
+%D \stoptyping
+
+% experiment ... \p_framed_franalyze -> we could support 'first' as location key
+% option but then we will always do an analysis and reimplement the location
+% options (btw, beware of location settings of derived functionality that bleed
+% into this
+
+\def\pack_framed_finish_a
+ {\ifreshapeframebox
+ \pack_framed_reshape_process
+ \orelse\ifx\p_framed_franalyze\v!yes
+ \pack_framed_reshape_analyze
+ \else
+ \pack_framed_reshape_reset
+ \fi
+ \setfalse\c_framed_has_width}
+
+\def\pack_framed_finish_b
+ {\ifx\p_framed_franalyze\v!yes
+ \pack_framed_reshape_analyze
+ \else
+ \pack_framed_reshape_reset
+ \fi
+ \setfalse\c_framed_has_width}
+
+\def\pack_framed_finish_c
+ {\ifx\p_framed_franalyze\v!yes
+ \pack_framed_reshape_analyze
+ \else
+ \pack_framed_reshape_reset
+ \fi}
+
+\def\pack_framed_profile_box
+ {\profilegivenbox\p_profile\b_framed_normal
+ \setbox\b_framed_normal\vpack{\unvbox\b_framed_normal}}
+
+\unexpanded\def\pack_framed_finish
+ {%\pack_framed_stop_orientation % hm, wrong place ! should rotate the result (after reshape) .. moved down
+ \pack_framed_locator_before\p_framed_location
+ \ifconditional\c_framed_has_format
+ %\ifconditional\c_framed_has_height \else
+ % \edef\p_profile{\framedparameter\c!profile}%
+ % \ifx\p_profile\empty\else
+ % \pack_framed_profile_box
+ % \fi
+ %\fi
+ \ifx\p_framed_autowidth\v!force
+ \pack_framed_finish_a
+ \orelse\ifx\localwidth\v!fit
+ \ifx\p_framed_autowidth\v!yes
+ \pack_framed_finish_a
+ \else
+ \pack_framed_finish_b
+ \fi
+ \orelse\ifx\localwidth\v!fixed
+ \pack_framed_finish_b
+ \else
+ \pack_framed_finish_c
+ \fi
+ \ifconditional\c_framed_has_height \else
+ \edef\p_profile{\framedparameter\c!profile}%
+ \ifx\p_profile\empty\else
+ \pack_framed_profile_box
+ \fi
+ \fi
+ \ifconditional\page_postprocessors_needed_box
+ % quite late
+ \page_postprocessors_linenumbers_box\b_framed_normal
+ \fi
+ \else
+ \pack_framed_finish_c
+ \fi
+ \ifconditional\c_framed_has_width
+ \wd\b_framed_normal\d_framed_width
+ \fi
+ \ifconditional\c_framed_has_height
+ \ht\b_framed_normal\d_framed_height
+ \else
+ \edef\p_framed_minheight{\framedparameter\c!minheight}%
+ \ifx\p_framed_minheight\empty \else
+ \ifdim\ht\b_framed_normal<\p_framed_minheight
+ \ht\b_framed_normal\p_framed_minheight
+ \fi
+ \fi
+ \fi
+ \edef\p_framed_empty{\framedparameter\c!empty}%
+ \ifx\p_framed_empty\v!yes
+ \pack_framed_fake_box
+ \fi
+ \ifx\p_framed_anchoring\empty\else
+ \pack_framed_handle_anchoring
+ \fi
+ \pack_framed_stop_orientation % moved here at 2014-05-25
+ \iftrialtypesetting \else
+ \edef\m_overlay_region{\framedparameter\c!region}%
+ \ifx\m_overlay_region\empty\else
+ \pack_framed_set_region
+ \fi
+ \fi
+ \d_framed_applied_offset
+ \ifconditional\c_framed_is_overlaid
+ \zeropoint
+ \else
+ \d_framed_linewidth
+ \fi
+ \ifconditional\c_framed_has_offset
+ \advance\d_framed_applied_offset\localoffset
+ \fi
+ \ifconditional\c_framed_has_extra_offset
+ \pack_framed_apply_extra_offsets % includes \d_framed_applied_offset
+ \else
+ \ifzeropt\d_framed_applied_offset
+ \else
+ \pack_framed_widen_box
+ \fi
+ \fi
+ %
+ \ifx\postprocessframebox\relax \else
+ \let\next\postprocessframebox
+ \let\postprocessframebox\relax % prevent nesting
+ \next\b_framed_normal
+ \fi
+ \iftrialtypesetting
+ % new
+ \else
+ \ifconditional\c_framed_has_frame % real or invisible frame
+ \pack_framed_add_outline
+ \fi
+ \ifx\p_framed_background\empty \else
+ \edef\p_framed_component{\framedparameter\c!component}%
+ \pack_framed_add_background
+ \fi
+ \fi
+ \pack_framed_locator_after\p_framed_location
+ \iftrialtypesetting \else
+ \ifx\m_overlay_region\empty\else
+ \pack_framed_add_region
+ \fi
+ \fi
+ \box\b_framed_normal
+ \global\frameddimensionstate % global so to be used directly afterwards !
+ \ifconditional\c_framed_has_width
+ \ifconditional\c_framed_has_height \plusthree \else \plusone \fi
+ \else
+ \ifconditional\c_framed_has_height \plustwo \else \zerocount \fi
+ \fi
+ \egroup
+ \egroup}
+
+%D Anchoring is experimental and was prototyped around the ctx meeting in 2018 but
+%D never mede it into the core yet. It operates independent of the orientation
+%D mechanism already present. It's a rather efficient feature. Best is to use
+%D predefined orientations, like:
+%D
+%D \starttyping
+%D \defineorientation[leftflushleft] [orientation=left,horizontal=flushleft]
+%D
+%D \framed [anchoring={leftflushleft}] {anchoring}
+%D \stoptyping
+%D
+%D But this also works:
+%D
+%D \starttyping
+%D \framed [anchoring={flushleft,top,up}] {anchoring}
+%D \stoptyping
+%D
+%D When an anchoring is given (use \type {normal} for the default) you can also
+%D use the \type {xanchor} and \type {yanchor} offsets.
+
+% because we mess with the width later on, we need double wrapping:
+
+\def\pack_framed_handle_anchoring
+ {\scratchcounter\autoorientation\p_framed_anchoring\relax
+ \edef\p_xanchor{\framedparameter\c!xanchor}%
+ \edef\p_yanchor{\framedparameter\c!yanchor}%
+ \setbox\b_framed_normal\hpack{\hpack % here
+ % using the keyword approachs works ok, don't mess with orientation
+ % directly here using \boxorientation ... it doesn't work that well
+ \s!orientation\scratchcounter
+ \ifx\p_xanchor\empty\else \s!xoffset \p_xanchor\fi
+ \ifx\p_yanchor\empty\else \s!yoffset \p_yanchor\fi
+ {\box\b_framed_normal}}}
+
+\installcorenamespace{framedlocatorbefore}
+\installcorenamespace{framedlocatorafter}
+
+\newconstant\frameddimensionstate % global state: 0=unknown 1=width 2=height 3=both
+
+\def\pack_framed_fake_box
+ {\setbox\scratchbox\emptyhbox
+ \wd\scratchbox\wd\b_framed_normal
+ \ht\scratchbox\ht\b_framed_normal
+ \dp\scratchbox\dp\b_framed_normal
+ \setbox\b_framed_normal\box\scratchbox}
+
+\def\installframedlocator#1#2#3%
+ {\setvalue{\??framedlocatorbefore#1}{#2}%
+ \setvalue{\??framedlocatorafter #1}{#3}}
+
+\def\pack_framed_locator_before#1{\begincsname\??framedlocatorbefore#1\endcsname}
+\def\pack_framed_locator_after #1{\begincsname\??framedlocatorafter #1\endcsname}
+
+\newdimen\d_framed_locator_ht
+\newdimen\d_framed_locator_dp
+\newdimen\d_framed_locator_lo
+\newdimen\d_framed_locator_ro
+
+\def\pack_framed_locator_set#1%
+ {\d_framed_locator_ht\dimexpr
+ #1+\d_framed_linewidth
+ \ifconditional\c_framed_has_offset
+ +\framedparameter\c!offset
+ \fi
+ +\framedparameter\c!toffset
+ \relax
+ \d_framed_locator_dp\dimexpr\ht\b_framed_normal-\d_framed_locator_ht\relax}
+
+\def\pack_framed_locator_set_lo
+ {\global\d_framed_locator_lo\dimexpr
+ \d_framed_linewidth
+ \ifconditional\c_framed_has_offset
+ +\framedparameter\c!offset
+ \fi
+ +\framedparameter\c!loffset
+ \relax}
+
+\def\pack_framed_locator_set_ro
+ {\global\d_framed_locator_ro\dimexpr
+ \d_framed_linewidth
+ \ifconditional\c_framed_has_offset
+ +\framedparameter\c!offset
+ \fi
+ +\framedparameter\c!roffset
+ \relax}
+
+% \ruledhbox
+% {A
+% \framed[width=2cm,align=middle,location=hanging]{location\\equals\\hanging}
+% \framed[width=2cm,align=middle,location=depth] {location\\equals\\depth}
+% \framed[width=2cm,align=middle,location=height] {location\\equals\\height}
+% B}
+% \vskip2cm
+% \ruledhbox
+% {A
+% \framed[width=2cm,align=middle,location=low] {location\\equals\\low}
+% \framed[width=2cm,align=middle,location=line] {location\\equals\\line}
+% \framed[width=2cm,align=middle,location=high] {location\\equals\\high}
+% B}
+% \vskip2cm
+% \ruledhbox
+% {A
+% \framed[width=2cm,align=middle,location=top] {location\\equals\\top}
+% \framed[width=2cm,align=middle,location=bottom] {location\\equals\\bottom}
+% \framed[width=2cm,align=middle,location=lohi] {location\\equals\\lohi}
+% \framed[width=2cm,align=middle,location=middle] {location\\equals\\middle}
+% B}
+
+% \installframedlocator \v!hanging % best with strut=no
+% {}
+% {\dp\b_framed_normal\ht\b_framed_normal
+% \ht\b_framed_normal\zeropoint}
+%
+% \installframedlocator \v!depth
+% {}
+% {\ht\b_framed_normal\dimexpr\ht\b_framed_normal-\strutdp\relax
+% \dp\b_framed_normal\strutdp
+% \box\b_framed_normal}
+%
+% \installframedlocator \v!height
+% {}
+% {\dp\b_framed_normal\dimexpr\ht\b_framed_normal-\strutht\relax
+% \ht\b_framed_normal\strutht
+% \box\b_framed_normal}
+
+\installframedlocator \v!hanging % best with strut=no *1* / see mail to list by SB
+ {}
+ {\scratchdimen\ht\b_framed_normal
+ \setbox\b_framed_normal\hpack{\lower\scratchdimen\box\b_framed_normal}%
+ \dp\b_framed_normal\scratchdimen
+ \ht\b_framed_normal\zeropoint
+ \box\b_framed_normal}
+
+\installframedlocator \v!depth % *1*
+ {}
+ {\setbox\b_framed_normal\hpack{\lower\strutdp\box\b_framed_normal}%
+ \ht\b_framed_normal\dimexpr\ht\b_framed_normal-\strutdp\relax
+ \dp\b_framed_normal\strutdp
+ \box\b_framed_normal}
+
+\installframedlocator \v!height % *1*
+ {}
+ {\scratchdimen\dimexpr \ht\b_framed_normal - \strutht \relax
+ \setbox\b_framed_normal\hpack{\lower\scratchdimen\box\b_framed_normal}%
+ \dp\b_framed_normal\dimexpr\ht\b_framed_normal-\strutht\relax
+ \ht\b_framed_normal\strutht
+ \box\b_framed_normal}
+
+\installframedlocator \v!high
+ {}
+ {\pack_framed_locator_set\strutht
+ \setbox\b_framed_normal\hpack{\lower\d_framed_locator_dp\box\b_framed_normal}%
+ \ht\b_framed_normal\strutht
+ \dp\b_framed_normal\strutdp
+ \hpack{\box\b_framed_normal}} % why do we pack .. dange of loosing?
+
+\installframedlocator \v!line
+ {}
+ {\setbox\b_framed_normal\hpack{\lower.5\ht\b_framed_normal\box\b_framed_normal}%
+ \ht\b_framed_normal.5\lineheight
+ \dp\b_framed_normal.5\lineheight
+ \hpack{\box\b_framed_normal}} % why do we pack .. dange of loosing?
+
+\installframedlocator \v!low
+ {}
+ {\pack_framed_locator_set\strutdp
+ \setbox\b_framed_normal\hpack{\lower\d_framed_locator_ht\box\b_framed_normal}%
+ \ht\b_framed_normal\strutht
+ \dp\b_framed_normal\strutdp
+ \box\b_framed_normal}
+
+\installframedlocator \v!top
+ {}
+ {\pack_framed_locator_set\strutht
+ \setbox\b_framed_normal\hpack{\lower\d_framed_locator_dp\box\b_framed_normal}%
+ \ht\b_framed_normal\d_framed_locator_ht
+ \dp\b_framed_normal\d_framed_locator_dp
+ \hpack{\box\b_framed_normal}} % why do we pack .. dange of loosing?
+
+\installframedlocator \v!middle
+ {}
+ {\scratchdimen.5\ht\b_framed_normal
+ \setbox\b_framed_normal\hpack{\lower\scratchdimen\box\b_framed_normal}%
+ \ht\b_framed_normal\scratchdimen
+ \dp\b_framed_normal\scratchdimen
+ \hpack{\box\b_framed_normal}} % why do we pack .. dange of loosing?
+
+\installframedlocator \v!lohi % maybe also \v!center
+ {\pack_framed_locator_before\v!middle}
+ {\pack_framed_locator_after \v!middle}
+
+\installframedlocator \v!bottom
+ {}
+ {\pack_framed_locator_set\strutdp
+ \setbox\b_framed_normal\hpack{\lower\d_framed_locator_ht\box\b_framed_normal}%
+ \ht\b_framed_normal\d_framed_locator_dp
+ \dp\b_framed_normal\d_framed_locator_ht
+ \hpack{\box\b_framed_normal}} % why do we pack .. dange of loosing?
+
+\installframedlocator \v!keep % retains height/depth
+ {\pack_framed_remove_depth}
+ {\pack_framed_restore_depth}
+
+\newdimen\d_framed_formula
+
+\installframedlocator \v!formula % private, will become a more generic name
+ {}
+ {\pack_framed_locator_set\d_framed_formula
+ \setbox\b_framed_normal\hpack{\lower\d_framed_locator_dp\box\b_framed_normal}%
+ \ht\b_framed_normal\d_framed_locator_ht
+ \dp\b_framed_normal\d_framed_locator_dp
+ \hpack{\box\b_framed_normal}} % why do we pack .. danger of loosing?
+
+% also used in fastlocalframed
+
+\newdimen\d_framed_original_wd
+\newdimen\d_framed_original_ht
+\newdimen\d_framed_original_dp
+
+\def\pack_framed_remove_depth
+ {\d_framed_original_wd\wd\b_framed_normal
+ \d_framed_original_ht\ht\b_framed_normal
+ \d_framed_original_dp\dp\b_framed_normal
+ \ifzeropt\d_framed_original_dp\else
+ \setbox\b_framed_normal\hpack{\raise\d_framed_original_dp\box\b_framed_normal}%
+ \fi
+ \wd\b_framed_normal\d_framed_original_wd
+ \ht\b_framed_normal\dimexpr\d_framed_original_ht+\d_framed_original_dp\relax
+ \dp\b_framed_normal\zeropoint}
+
+\def\pack_framed_restore_depth
+ {\ifzeropt\d_framed_original_dp \else
+ \setbox\b_framed_normal\hpack{\lower\d_framed_original_dp\box\b_framed_normal}%
+ \fi
+ \wd\b_framed_normal\d_framed_original_wd
+ \ht\b_framed_normal\d_framed_original_ht
+ \dp\b_framed_normal\d_framed_original_dp}
+
+% \framed[width=12cm,height=3cm,orientation=0]{\input ward\relax}
+% \framed[width=12cm,height=3cm,orientation=90]{\input ward\relax}
+% \framed[width=12cm,height=3cm,orientation=180]{\input ward\relax}
+% \framed[width=12cm,height=3cm,orientation=270]{\input ward\relax}
+% \framed[width=12cm,height=3cm,orientation=-90]{\input ward\relax}
+% \framed[width=12cm,height=3cm,orientation=-180]{\input ward\relax}
+% \framed[width=12cm,height=3cm,orientation=-270]{\input ward\relax}
+
+\def\pack_framed_start_orientation
+ {\ifcase\p_framed_orientation
+ \let\pack_framed_stop_orientation\relax
+ \else
+ \let\pack_framed_stop_orientation\pack_framed_stop_orientation_indeed
+ \fi}
+
+\def\pack_framed_stop_orientation_indeed
+ {\setbox\b_framed_normal\hpack{\dorotatebox\p_framed_orientation\hpack{\box\b_framed_normal}}%
+ \d_framed_height\ht\b_framed_normal
+ \d_framed_width \wd\b_framed_normal}
+
+%D The last conditional takes care of the special situation of in||line \inframed
+%D [height=3cm] {framed} boxes. Such boxes have to be \inframed {aligned} with the
+%D running text.
+
+\unexpanded\def\inframed
+ {\dosingleempty\pack_framed_inline}
+
+% \def\pack_framed_inline[#1]%
+% {\framed[\c!location=\v!low,#1]}
+%
+% or:
+
+\def\pack_framed_inline[%
+ {\framed[\c!location=\v!low,}
+
+%D When we set \type{empty} to \type{yes}, we get ourselves a frame and/or background,
+%D but no content, so actually we have a sort of phantom framed box.
+
+%D \macros
+%D {mframed, minframed}
+%D
+%D When Tobias asked how to frame mathematical elements in formulas, Taco's posted the
+%D next macro:
+%D
+%D \starttyping
+%D \def\mframed#1%
+%D {\relax
+%D \ifmmode
+%D \vcenter{\hbox{\framed{$\ifinner\else\displaystyle\fi#1$}}}%
+%D \else
+%D \framed{$#1$}%
+%D \fi}
+%D \stoptyping
+%D
+%D Because \type {\ifinner} does not (always) reports what one would expect, we move the
+%D test to the outer level. We also want to pass arguments,
+%D
+%D \starttyping
+%D \def\mframed%
+%D {\dosingleempty\domframed}
+%D
+%D \def\domframed[#1]#2% % tzt \dowithnextmathbox ?
+%D {\relax
+%D \ifmmode
+%D \ifinner
+%D \inframed[#1]{$#2$}%
+%D \else
+%D \vcenter{\hbox{\framed[#1]{$\displaystyle#2$}}}%
+%D \fi
+%D \else
+%D \inframed[#1]{$#2$}%
+%D \fi}
+%D \stoptyping
+%D
+%D Still better is the next alternative, if only because it takes care of setting the super-
+%D and subscripts styles
+
+\newcount\c_framed_mstyle
+
+\unexpanded\def\pack_framed_math_strut
+ {\Ustartmath
+ \triggermathstyle\c_framed_mstyle
+ \vphantom{(}%
+ \Ustopmath}
+
+\installcorenamespace{mathframed}
+
+\installframedcommandhandler \??mathframed {mathframed} \??mathframed
+
+\appendtoks
+ \setuevalue{\currentmathframed}{\pack_framed_mathframed{\currentmathframed}}%
+\to \everydefinemathframed
+
+\unexpanded\def\pack_framed_mathframed#1%
+ {\begingroup
+ \edef\currentmathframed{#1}%
+ \dosingleempty\pack_framed_mathframed_indeed}
+
+\newcount\c_pack_framed_mathframed
+\newtoks \t_pack_framed_mathframed
+
+\def\pack_framed_math_pos
+ {\global\advance\c_pack_framed_mathframed\plusone
+ \xdef\pack_framed_mc_one{mcf:1:\number\c_pack_framed_mathframed}%
+ \xdef\pack_framed_mc_two{mcf:2:\number\c_pack_framed_mathframed}%
+ \xypos\pack_framed_mc_two}
+
+\def\pack_framed_mathframed_indeed[#1]#2% no fancy nesting supported here
+ {\iffirstargument
+ \setupcurrentmathframed[#1]%
+ \fi
+ \c_framed_mstyle\mathstyle
+ \edef\m_framed_location{\mathframedparameter\c!location}%
+ \ifx\m_framed_location\v!mathematics
+ \let\normalstrut\pack_framed_math_pos
+ \orelse\ifx\m_framed_location\v!low\else
+ \let\normalstrut\pack_framed_math_strut
+ \fi
+ \inheritedmathframedframed\bgroup
+ \Ustartmath
+ \triggermathstyle\c_framed_mstyle
+ \the\t_pack_framed_mathframed
+ #2%
+ \Ustopmath
+ \egroup
+ \endgroup}
+
+\appendtoks
+ \mathraggedstatus\plustwo % makes \startalign work
+ \eqalignmode \zerocount % makes \startalign fit
+\to \t_pack_framed_mathframed
+
+\installframedlocator \v!mathematics
+ {}
+ {\lower\dimexpr\MPy\pack_framed_mc_two-\MPy\pack_framed_mc_one\relax
+ \hpack{\xypos\pack_framed_mc_one\box\b_framed_normal}}
+
+\definemathframed[mframed]
+\definemathframed[inmframed][\c!location=\v!low]
+\definemathframed[mcframed] [\c!location=\v!mathematics]
+
+%D So instead of the rather versatile \type {\framed}, we use \type {\mframed}:
+%D
+%D \startbuffer
+%D \startformula
+%D x \times \mframed{y} \times y^{z_z}
+%D x \times \inmframed{y} \times y^{z_z}
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D And:
+%D
+%D \startbuffer
+%D \startformula
+%D x \times \mframed{y} \times y^{\mframed{z}_{\mframed{z}}}
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D As usual, one can specify in what way the text should be framed. One should be
+%D aware of the fact that, inorder to preserve the proper spacing, the \type
+%D {offset} is set to \type {overlay} and \type {frameoffset} is used used instead.
+%D
+%D \startbuffer
+%D \startformula
+%D x \times y^{\mframed[framecolor=red]{z}_{z}}
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D For inline use, we also provide the \type {\inmframed} alternative: we want $x
+%D \times \inmframed{y}$ in inline math, right?
+
+%D This previous framing macros needs a lot of alternatives for putting rules around
+%D boxes, inserting offsets and aligning text. Each step is handled by separate macros.
+
+\newdimen\d_framed_applied_offset
+\newdimen\d_framed_loffset
+\newdimen\d_framed_roffset
+\newdimen\d_framed_toffset
+\newdimen\d_framed_boffset
+
+\def\pack_framed_check_extra_offsets % we could check h and v indepently
+ {\setfalse\c_framed_has_extra_offset
+ \d_framed_loffset\framedparameter\c!loffset\relax
+ \d_framed_roffset\framedparameter\c!roffset\relax
+ \d_framed_toffset\framedparameter\c!toffset\relax
+ \d_framed_boffset\framedparameter\c!boffset\relax
+ \ifzeropt\d_framed_loffset\else \advance\d_framed_width -\d_framed_loffset \settrue\c_framed_has_extra_offset \fi
+ \ifzeropt\d_framed_roffset\else \advance\d_framed_width -\d_framed_roffset \settrue\c_framed_has_extra_offset \fi
+ \ifzeropt\d_framed_toffset\else \advance\d_framed_height-\d_framed_toffset \settrue\c_framed_has_extra_offset \fi
+ \ifzeropt\d_framed_boffset\else \advance\d_framed_height-\d_framed_boffset \settrue\c_framed_has_extra_offset \fi}
+
+\def\pack_framed_apply_extra_offsets
+ {\setbox\b_framed_normal\vpack\bgroup
+ \advance\d_framed_toffset\d_framed_applied_offset
+ \advance\d_framed_boffset\d_framed_applied_offset
+ \advance\d_framed_loffset\d_framed_applied_offset
+ \advance\d_framed_roffset\d_framed_applied_offset
+ \kern\d_framed_toffset
+ \hpack\bgroup
+ \kern\d_framed_loffset
+ \box\b_framed_normal
+ \kern\d_framed_roffset
+ \egroup
+ \kern\d_framed_boffset
+ \egroup}
+
+\def\pack_framed_widen_box
+ {\setbox\b_framed_normal\vpack
+ {\kern\d_framed_applied_offset
+ \hpack{\kern\d_framed_applied_offset\box\b_framed_normal\kern\d_framed_applied_offset}%
+ \kern\d_framed_applied_offset}}
+
+%D Let's hope that the next few examples show us enough of what needs to be
+%D done by the auxiliary macros.
+%D
+%D \startbuffer
+%D \framed[height=1cm,offset=.5cm] {rule based learning}
+%D \framed[height=1cm,offset=0cm] {rule based learning}
+%D \framed[height=1cm,offset=none] {rule based learning}
+%D \framed[height=1cm,offset=overlay]{rule based learning}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlinecorrection
+%D \hbox{\getbuffer}
+%D \stoplinecorrection
+%D
+%D \startbuffer
+%D \framed[offset=.5cm] {rule based learning}
+%D \framed[offset=0cm] {rule based learning}
+%D \framed[offset=none] {rule based learning}
+%D \framed[offset=overlay]{rule based learning}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlinecorrection
+%D \hbox{\getbuffer}
+%D \stoplinecorrection
+%D
+%D \startbuffer
+%D \framed[strut=no,offset=.5cm] {rule based learning}
+%D \framed[strut=no,offset=0cm] {rule based learning}
+%D \framed[strut=no,offset=none] {rule based learning}
+%D \framed[strut=no,offset=overlay]{rule based learning}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlinecorrection
+%D \hbox{\getbuffer}
+%D \stoplinecorrection
+%D
+%D \startbuffer
+%D \framed[width=3cm,align=left] {rule\\based\\learning}
+%D \framed[width=3cm,align=middle] {rule\\based\\learning}
+%D \framed[width=3cm,align=right] {rule\\based\\learning}
+%D \framed[width=fit,align=middle] {rule\\based\\learning}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlinecorrection
+%D \hbox{\dontcomplain\getbuffer}
+%D \stoplinecorrection
+%D
+%D So now we're ready for the complicated stuff. We distinguish between borders with
+%D straight lines and those with round corners. When using the first alternative it
+%D is possible to turn off one or more lines. More fancy shapes are also possible by
+%D specifying dedicated backgrounds. Turning lines on and off is implemented as
+%D efficient as possible and as a result is interface language dependant. This next
+%D implementation evolved from simpler ones. It puts for instance the rules on top
+%D of the content and provides additional offset capabilities. The lot of calls to
+%D other macros makes this mechanism not that easy to comprehend.
+%D
+%D We handle left, right or middle alignment as well as fixed or free widths and
+%D heights. Each combination gets its own macro.
+%D
+%D The following code handles one-liners: \type {align={line,flushright}}. Beware,
+%D since we entered a group and either or not grab the next bgroup token, we need to
+%D finish the group in the oneliner mode.
+
+\ifdefined\raggedonelinerstate \else \newconditional\raggedonelinerstate \fi
+
+\def\doformatonelinerbox % beware: assumes explicit preceding bgroup
+ {\ifconditional\raggedonelinerstate
+ \expandafter\dodoformatonelinerbox
+ \else
+ \expandafter\nodoformatonelinerbox
+ \fi}
+
+\def\dodoformatonelinerbox
+ {\afterassignment\redoformatonelinerbox
+ \setbox\nextbox\hbox} % maybe \hpack
+
+\def\redoformatonelinerbox
+ {\aftergroup\dododoformatonelinerbox
+ \ignorespaces}
+
+\def\dododoformatonelinerbox
+ {\hpack to \hsize % was \hbox
+ {\ifcase\raggedstatus\or\hss\or\hss \fi
+ \unhbox\nextbox \removeunwantedspaces
+ \ifcase\raggedstatus\or \or\hss\or\hss\fi}%
+ \egroup}
+
+\def\nodoformatonelinerbox % grabs {
+ {\let\next=}
+
+%D The handlers:
+
+% Beware, we have a \noindent so an empty line is indeed an empty line and
+% the \synchronizeinlinedirection triggers a vbox instead of a line.
+%
+% \startTEXpage[offset=0.5ex,align={lohi,middle}]
+%
+% \vbox{\hbox{x}}
+% \stopTEXpage
+%
+% \startTEXpage[offset=0.5ex,align={lohi,middle}]
+% \vbox{\hbox{x}}
+% \stopTEXpage
+
+% \def\pack_framed_forgetall{\forgetall}
+
+\def\pack_framed_set_foregroundcolor
+ {\edef\p_framed_foregroundcolor{\framedparameter\c!foregroundcolor}%
+ \ifx\p_framed_foregroundcolor\empty\else\dousecolorparameter\p_framed_foregroundcolor\fi}
+
+\def\pack_framed_do_setups
+ {\ifx\p_framed_setups\empty \else
+ \setups[\p_framed_setups]% \texsetup (or only one!)
+ % \fastsetup\p_framed_setup % singular would have been better
+ \fi}
+
+\def\pack_framed_format_format_yes
+ {\vbox to \d_framed_height
+ \bgroup
+ \let\postprocessframebox\relax
+ % \pack_framed_forgetall
+ \iftrialtypesetting \else
+ \pack_framed_set_foregroundcolor
+ \fi
+ \oninterlineskip
+ \hsize\d_framed_width
+ \vsize\d_framed_height
+ \pack_framed_do_setups
+ \raggedcommand
+ \pack_framed_do_top
+ \bgroup
+ \synchronizeinlinedirection
+ \localbegstrut
+ \aftergroup\localendstrut
+ \aftergroup\pack_framed_do_bottom
+ \aftergroup\egroup
+ \doformatonelinerbox}
+
+\def\pack_framed_format_format_nop
+ {\vbox to \d_framed_height
+ \bgroup
+ \let\postprocessframebox\relax
+ % \pack_framed_forgetall
+ \iftrialtypesetting \else
+ \pack_framed_set_foregroundcolor
+ \fi
+ \oninterlineskip
+ \hsize\d_framed_width
+ \vsize\d_framed_height
+ \pack_framed_do_setups
+ \raggedcenter
+ \vss
+ \bgroup
+ \synchronizeinlinedirection
+ \localbegstrut
+ \aftergroup\localendstrut
+ \aftergroup\vss
+ \aftergroup\egroup
+ \doformatonelinerbox}
+
+\def\pack_framed_format_format_height
+ {\vbox to \d_framed_height
+ \bgroup
+ \let\postprocessframebox\relax
+ % \pack_framed_forgetall
+ \iftrialtypesetting \else
+ \pack_framed_set_foregroundcolor
+ \fi
+ \oninterlineskip
+ \pack_framed_do_setups
+ \raggedcommand
+ \vss
+ \bgroup
+ \aftergroup\localendstrut
+ \aftergroup\vss
+ \aftergroup\egroup
+ \synchronizeinlinedirection
+ \localbegstrut
+ \doformatonelinerbox}
+
+\def\pack_framed_format_format_width
+ {\vbox
+ \bgroup
+ \let\postprocessframebox\relax
+ % \pack_framed_forgetall
+ \iftrialtypesetting \else
+ \pack_framed_set_foregroundcolor
+ \fi
+ \oninterlineskip
+ \hsize\d_framed_width
+ \pack_framed_do_setups
+ \raggedcommand
+ \pack_framed_do_top
+ \bgroup
+ \synchronizeinlinedirection
+ \localbegstrut
+ \aftergroup\localendstrut
+ \aftergroup\pack_framed_do_bottom
+ \aftergroup\egroup
+ \doformatonelinerbox}
+
+\def\pack_framed_format_format_vsize
+ {\vbox to \d_framed_height % no vpack .. maybe grid
+ \bgroup
+ \let\postprocessframebox\relax
+ % \pack_framed_forgetall
+ \iftrialtypesetting \else
+ \pack_framed_set_foregroundcolor
+ \fi
+ \vsize\d_framed_height
+ \pack_framed_do_setups
+ \vss
+ \bgroup
+ \aftergroup\vss
+ \aftergroup\egroup
+ \hbox
+ \bgroup
+ \aftergroup\egroup
+ \synchronizeinlinedirection
+ \localstrut
+ \doformatonelinerbox}
+
+\def\pack_framed_format_format_hsize
+ {\hbox to \d_framed_width
+ \bgroup
+ \let\postprocessframebox\relax
+ % \pack_framed_forgetall
+ \iftrialtypesetting \else
+ \pack_framed_set_foregroundcolor
+ \fi
+ \pack_framed_do_setups
+ \hss
+ \synchronizeinlinedirection
+ \localstrut
+ \bgroup
+ \aftergroup\hss
+ \aftergroup\egroup
+ \doformatonelinerbox}
+
+\def\pack_framed_format_format_no_size
+ {\hbox
+ \bgroup
+ \iftrialtypesetting \else
+ \pack_framed_set_foregroundcolor
+ \fi
+ \let\postprocessframebox\relax
+ \pack_framed_do_setups
+ \synchronizeinlinedirection
+ \localstrut
+ \doformatonelinerbox}
+
+%D On the next page we show some examples of how these macros come into action. The
+%D examples show us how \type {fit}, \type {broad} dimensions influence the
+%D formatting. Watch the visualized struts. \footnote {Here we used \type
+%D {\showstruts}.}
+%D
+%D \startpostponing
+%D \bgroup
+%D \showstruts
+%D \dontcomplain
+%D \starttabulate[|c|c|c|c|c|c|]
+%D % \HL
+%D \NC \framed[width=.2\hsize, height=.2\hsize, align=] {a\endgraf b\endgraf c}
+%D \NC \framed[width=.2\hsize, height=broad, align=] {a\endgraf b\endgraf c}
+%D \NC \framed[width=.2\hsize, height=fit, align=] {a\endgraf b\endgraf c}
+%D \NC \framed[width=fit, height=.2\hsize, align=] {a\endgraf b\endgraf c}
+%D \NC \framed[width=fit, height=broad, align=] {a\endgraf b\endgraf c}
+%D \NC \framed[width=fit, height=fit, align=] {a\endgraf b\endgraf c}
+%D \NC \NR
+%D % \HL
+%D \NC \framed[width=.2\hsize, height=.2\hsize, align=yes] {a\endgraf b\endgraf c}
+%D \NC \framed[width=.2\hsize, height=broad, align=yes] {a\endgraf b\endgraf c}
+%D \NC \framed[width=.2\hsize, height=fit, align=yes] {a\endgraf b\endgraf c}
+%D \NC \framed[width=fit, height=.2\hsize, align=yes] {a\endgraf b\endgraf c}
+%D \NC \framed[width=fit, height=broad, align=yes] {a\endgraf b\endgraf c}
+%D \NC \framed[width=fit, height=fit, align=yes] {a\endgraf b\endgraf c}
+%D \NC \NR
+%D % \HL
+%D \NC \framed[width=.2\hsize, height=.2\hsize, align=right] {a\endgraf b\endgraf c}
+%D \NC \framed[width=.2\hsize, height=broad, align=right] {a\endgraf b\endgraf c}
+%D \NC \framed[width=.2\hsize, height=fit, align=right] {a\endgraf b\endgraf c}
+%D \NC \framed[width=fit, height=.2\hsize, align=right] {a\endgraf b\endgraf c}
+%D \NC \framed[width=fit, height=broad, align=right] {a\endgraf b\endgraf c}
+%D \NC \framed[width=fit, height=fit, align=right] {a\endgraf b\endgraf c}
+%D \NC \NR
+%D % \HL
+%D \NC \framed[width=.2\hsize, height=.2\hsize, align=left] {a\endgraf b\endgraf c}
+%D \NC \framed[width=.2\hsize, height=broad, align=left] {a\endgraf b\endgraf c}
+%D \NC \framed[width=.2\hsize, height=fit, align=left] {a\endgraf b\endgraf c}
+%D \NC \framed[width=fit, height=.2\hsize, align=left] {a\endgraf b\endgraf c}
+%D \NC \framed[width=fit, height=broad, align=left] {a\endgraf b\endgraf c}
+%D \NC \framed[width=fit, height=fit, align=left] {a\endgraf b\endgraf c}
+%D \NC \NR
+%D % \HL
+%D \NC \framed[width=.2\hsize, height=.2\hsize, align=middle] {a\endgraf b\endgraf c}
+%D \NC \framed[width=.2\hsize, height=broad, align=middle] {a\endgraf b\endgraf c}
+%D \NC \framed[width=.2\hsize, height=fit, align=middle] {a\endgraf b\endgraf c}
+%D \NC \framed[width=fit, height=.2\hsize, align=middle] {a\endgraf b\endgraf c}
+%D \NC \framed[width=fit, height=broad, align=middle] {a\endgraf b\endgraf c}
+%D \NC \framed[width=fit, height=fit, align=middle] {a\endgraf b\endgraf c}
+%D \NC \NR
+%D % \HL
+%D \stoptabulate
+%D \egroup
+%D \stoppostponing
+
+%D \macros
+%D {framednoflines, framedlastlength}
+%D
+%D It is possible to let the frame macro calculate the width of a centered box
+%D automatically (\type {fit}). When doing so, we need to reshape the box:
+
+\newcount\framednoflines
+\newdimen\framedfirstheight
+\newdimen\framedlastdepth
+\newdimen\framedminwidth
+\newdimen\framedmaxwidth
+\newdimen\framedaveragewidth
+
+\def\pack_framed_reshape_reset
+ {\framednoflines \zerocount
+ \framedfirstheight \zeropoint
+ \framedlastdepth \zeropoint
+ \framedminwidth \zeropoint
+ \framedmaxwidth \zeropoint
+ \framedaveragewidth\zeropoint}
+
+\def\pack_framed_reshape_process{\ifvbox\b_framed_normal\clf_doreshapeframedbox\b_framed_normal\relax\fi}
+\def\pack_framed_reshape_analyze{\ifvbox\b_framed_normal\clf_doanalyzeframedbox\b_framed_normal\relax\fi}
+
+% torture test / strange case (much depth) / method 2 needed
+%
+% \startTEXpage[frame=on]
+% \startformula \startalign \NC A \NC B \NR \intertext{test} \NC C \NC D \NR \stopalign \stopformula
+% test outside formula
+% \startformula \startalign \NC A \NC B \NR \intertext{test} \NC C \NC D \NR \stopalign \stopformula
+% \blank[big]
+% \startformula \startalign \NC \int_01 \NC B \NR \intertext{test} \NC \int_01 \NC D \NR \stopalign \stopformula
+% test outside formula
+% \startformula \startalign \NC \int_01 \NC B \NR \intertext{test} \NC \int_01 \NC D \NR \stopalign \stopformula
+% \stopTEXpage
+
+%D The examples on the next page show how one can give the frame as well as the
+%D background an additional offset and even a bit more depth. The blue outline is
+%D the frame, the red box is the background and the small black outline is the
+%D visualization of the resulting box, that is, we applied \type {\ruledhbox} to
+%D the result.
+%D
+%D \startpostponing
+%D \bgroup
+%D \unprotect
+%D \dontcomplain
+%D
+%D \startbuffer
+%D \unprotect
+%D \vbox to \vsize
+%D \bgroup
+%D \startalignment[middle]
+%D \vss
+%D \dontleavehmode\vbox to .8\vsize
+%D \bgroup
+%D \hsize=300pt
+%D \setupframed
+%D [background=color,
+%D backgroundcolorachtergrondkleur=darkred,
+%D width=300pt,
+%D height=60pt,
+%D framecolorkaderkleur=DemoBlue,
+%D rulethickness=2pt]
+%D \def\status%
+%D {backgroundoffset=\the\dimexpr\framedparameter\c!backgroundoffset\relax\\
+%D frameoffset=\the\dimexpr\framedparameter\c!frameoffset\relax\\
+%D depth=\the\dimexpr\framedparameter\c!depth\relax}
+%D \dontleavehmode \ruledhbox{\framed[backgroundoffset=0pt,frameoffset=0pt]{\status}}
+%D \vss
+%D \dontleavehmode \ruledhbox{\framed[backgroundoffset=5pt,frameoffset=0pt]{\status}}
+%D \vss
+%D \dontleavehmode \ruledhbox{\framed[backgroundoffset=0pt,frameoffset=5pt]{\status}}
+%D \vss
+%D \dontleavehmode \ruledhbox{\framed[backgroundoffset=2pt,frameoffset=5pt]{\status}}
+%D \vss
+%D \dontleavehmode \ruledhbox{\framed[backgroundoffset=5pt,frameoffset=2pt]{\status}}
+%D \vss
+%D \dontleavehmode \ruledhbox{\framed[backgroundoffset=5pt,frameoffset=5pt]{\status}}
+%D \egroup
+%D \vss
+%D \stopalignment
+%D \egroup
+%D \protect
+%D \stopbuffer
+%D
+%D \getbuffer \page
+%D
+%D {\setupframed[depth=4pt]\getbuffer} \page
+%D
+%D \protect
+%D \egroup
+%D \stoppostponing
+
+%D We can draw lines from left to right and top to bottom by using the normal \type
+%D {\hairline} command. Both directions need a different treatment.
+%D
+%D \startbuffer
+%D \framed[width=4cm] {alfa\hairline beta\hairline gamma}
+%D \framed[height=2cm] {alfa\hairline beta\hairline gamma}
+%D \framed[width=4cm,height=2cm]{alfa\hairline beta\hairline gamma}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlinecorrection
+%D \hbox{\getbuffer}
+%D \stoplinecorrection
+%D
+%D These macros try to adapt their behaviour as good as possible to the circumstances
+%D and act as natural as possible.
+
+\unexpanded\def\pack_framed_vboxed_hairline % nasty overlay mess .. needed for autowidth
+ {\begingroup
+ \scratchoffset\ifconditional\c_framed_has_offset \localoffset \else \zeropoint \fi
+ \scratchwidth \dimexpr\scratchoffset+\d_framed_linewidth\relax
+ \par
+ \nointerlineskip
+ \kern\scratchoffset
+ \dontleavehmode
+ \hrule\s!height\d_framed_linewidth\s!depth\zeropoint
+ \par
+ \kern-\d_framed_linewidth
+ \dontleavehmode
+ \hpack to \zeropoint{\hss\vrule\s!height\d_framed_linewidth\s!depth\zeropoint\s!width\scratchwidth}%
+ \hfill
+ \hpack to \zeropoint{\vrule\s!height\d_framed_linewidth\s!depth\zeropoint\s!width\scratchwidth\hss}%
+ \par
+ \nointerlineskip
+ \kern\scratchoffset
+ \nointerlineskip
+ \endgraf
+ \nointerlineskip
+ \localbegstrut
+ \endgroup}
+
+\unexpanded\def\pack_framed_hboxed_hairline % use framed dimen
+ {\bgroup
+ \scratchoffset\ifconditional\c_framed_has_offset \localoffset \else \zeropoint \fi
+ \ifconditional\c_framed_has_height
+ \dimen\scratchheight\dimexpr\localheight/\plustwo+\strutdp-\plustwo\d_framed_linewidth\relax
+ \dimen\scratchdepth \dimexpr\localheight/\plustwo-\strutdp+\plustwo\d_framed_linewidth\relax
+ \else
+ \dimen\scratchheight\dimexpr\strutht+\scratchoffset\relax
+ \dimen\scratchdepth \dimexpr\strutdp+\scratchoffset\relax
+ \fi
+ \unskip
+ \setbox\scratchbox\hpack
+ {\kern\scratchoffset
+ \vrule\s!height\dimen\scratchheight\s!depth\dimen\scratchdepth\s!width\d_framed_linewidth
+ \kern\scratchoffset}%
+ \ht\scratchbox\strutht
+ \dp\scratchbox\strutdp
+ \box\scratchbox
+ \ignorespaces
+ \egroup}
+
+%D The argument of the frame command accepts \type{\\} as a sort of newline signal. In
+%D horizontal boxes it expands to a space.
+
+\unexpanded\def\pack_framed_vboxed_newline
+ {\endgraf\ignorespaces}
+
+\unexpanded\def\pack_framed_hboxed_newline
+ {\unskip\normalspace\ignorespaces}
+
+%D We can set each rule on or off. The default setting is inherited from
+%D \type {frame}. An earlier implementation use a bit different approach, but the new
+%D one seems more natural:
+%D
+%D \bgroup
+%D \setuptyping[margin=0pt]
+%D \startlinecorrection
+%D \startbuffer
+%D \framed[offset=overlay,frame=on]{\darkred\blackrule}
+%D \stopbuffer
+%D \hbox{\getbuffer\vbox{\typebuffer}}
+%D
+%D \startbuffer
+%D \framed[offset=overlay,frame=on,bottomframe=off]{\darkred\blackrule}
+%D \stopbuffer
+%D \hbox{\getbuffer\vbox{\typebuffer}}
+%D
+%D \startbuffer
+%D \framed[offset=overlay,frame=on,bottomframe=on]{\darkred\blackrule}
+%D \stopbuffer
+%D \hbox{\getbuffer\vbox{\typebuffer}}
+%D
+%D \startbuffer
+%D \framed[offset=overlay,frame=off]{\darkred\blackrule}
+%D \stopbuffer
+%D \hbox{\getbuffer\vbox{\typebuffer}}
+%D
+%D \startbuffer
+%D \framed[offset=overlay,frame=off,bottomframe=off]{\darkred\blackrule}
+%D \stopbuffer
+%D \hbox{\getbuffer\vbox{\typebuffer}}
+%D
+%D \startbuffer
+%D \framed[offset=overlay,frame=off,bottomframe=on]{\darkred\blackrule}
+%D \stopbuffer
+%D \hbox{\getbuffer\vbox{\typebuffer}}
+%D \stoplinecorrection
+%D \egroup
+
+%D \macros
+%D {startframedtext, setupframedtexts, defineframedtext}
+%D
+%D The general framing command we discussed previously, is not entirely suited for
+%D what we call framed texts, as for instance used in intermezzo's. The next
+%D examples show what we have in mind.
+%D
+%D \startbuffer[framed-0]
+%D \setupframedtexts
+%D [frame=off,
+%D width=\hsize,
+%D background=screen]
+%D
+%D \startframedtext
+%D By default the framed text is centered \dots
+%D \stopframedtext
+%D
+%D \startframedtext[right]
+%D \dots\ but we can also align left, middle and right.
+%D \stopframedtext
+%D \stopbuffer
+%D
+%D \startbuffer[framed-1]
+%D \defineframedtext
+%D [Example]
+%D [width=6cm,
+%D height=5cm]
+%D
+%D \startExample
+%D \typebuffer[framed-1]
+%D \stopExample
+%D \stopbuffer
+%D
+%D \startbuffer[framed-2]
+%D \defineframedtext
+%D [Example]
+%D [width=6cm]
+%D
+%D \startExample
+%D \typebuffer[framed-2]
+%D \stopExample
+%D \stopbuffer
+%D
+%D \startbuffer[framed-3]
+%D \defineframedtext
+%D [Example]
+%D [height=5cm]
+%D
+%D \startExample
+%D \typebuffer[framed-3]
+%D \stopExample
+%D \stopbuffer
+%D
+%D \startbuffer[framed-4]
+%D \defineframedtext
+%D [Example]
+%D [width=fit,height=broad]
+%D
+%D \Example{a very exciting example}
+%D \stopbuffer
+%D
+%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-0] \egroup
+%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-1] \egroup
+%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-2] \egroup
+%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-3] \egroup
+%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-4] \egroup
+%D
+%D Here we can see that we have a predefined framed text class as well as the
+%D tools for defining our own. So we have:
+%D
+%D \showsetup{setupframedtexts}
+%D
+%D as well as the definition command:
+%D
+%D \showsetup{defineframedtext}
+%D
+%D that generates two commands:
+%D
+%D \showsetup{start<<framedtext>>}
+%D \showsetup{<<framedtext>>}
+%D
+%D The next definition shows the defaults.
+
+\installcorenamespace{framedtext}
+\installcorenamespace{framedtextlocation}
+
+\installframedcommandhandler \??framedtext {framedtext} \??framedtext
+
+\let\setupframedtexts\setupframedtext
+
+\setupframedtext
+ [\c!width=.75\hsize,
+ \c!height=\v!fit,
+ \c!align=\v!yes,
+ %\c!top=,
+ \c!bottom=\vfill,
+ \c!offset=1em,
+ %\c!bodyfont=,
+ %\c!style=,
+ %\c!color=,
+ %\c!left=,
+ \c!right=\hfill,
+ \c!before=\blank,
+ \c!after=\blank,
+ %\c!inner=,
+ \c!frame=\v!on,
+ %\c!topframe=,
+ %\c!bottomframe=,
+ %\c!leftframe=,
+ %\c!rightframe=,
+ \c!radius=.5\bodyfontsize,
+ \c!corner=\v!rectangular,
+ %\c!orientation=,
+ %\c!indenting=,
+ %\c!foregroundcolor=,
+ %\c!foregroundstyle=,
+ %\c!background=,
+ %\c!backgroundcolor=,
+ \c!linecorrection=\v!on,
+ \c!depthcorrection=\v!on,
+ \c!margin=\v!standard]
+
+\appendtoks
+ \setuevalue{\e!start\currentframedtext}{\pack_framed_text_start {\currentframedtext}}%
+ \setuevalue{\e!stop \currentframedtext}{\pack_framed_text_stop }%
+ \setuevalue {\currentframedtext}{\pack_framed_text_direct{\currentframedtext}}%
+\to \everydefineframedtext
+
+\setvalue{\??framedtextlocation\v!left }{\letframedtextparameter\c!left \relax
+ \letframedtextparameter\c!right\hfill}
+
+\setvalue{\??framedtextlocation\v!right }{\letframedtextparameter\c!left \hfill
+ \letframedtextparameter\c!right\relax}
+
+\setvalue{\??framedtextlocation\v!middle}{\letframedtextparameter\c!left \hfill
+ \letframedtextparameter\c!right\hfill}
+
+\setvalue{\??framedtextlocation\v!none }{\letframedtextparameter\c!left \relax
+ \letframedtextparameter\c!right\relax
+ \settrue\c_framed_text_location_none}
+
+\unexpanded\def\pack_framed_text_start#1%
+ {\bgroup
+ \edef\currentframedtext{#1}%
+ \dodoubleempty\pack_framed_text_start_indeed}
+
+\def\pack_framed_text_start_indeed[#1][#2]%
+ {\doifelseassignment{#1}
+ {\pack_framed_text_start_continue\empty{#1}}
+ {\pack_framed_text_start_continue{#1}{#2}}}
+
+% todo: sort out first/lastline ht/dp
+
+\def\pack_framed_text_start_continue#1#2%
+ {\setupframedtexts[\currentframedtext][#2]%
+ \doifsomething{#1}{\setframedtextparameter\c!location{#1}}% does not listen to #3
+ \setfalse\c_framed_text_location_none
+ \csname\??framedtextlocation\framedtextparameter\c!location\endcsname
+ \resetframedtextparameter\c!location
+ \pack_framed_text_check
+ \setbox\b_framed_normal\vbox % \vpack
+ \startboxedcontent
+ \hsize\localhsize
+ % \insidefloattrue % ? better
+ \usebodyfontparameter\framedtextparameter
+ % \edef\p_framed_text_strut{\letframedtextparameter\c!strut}% to be used
+ \letframedtextparameter\c!strut\v!no
+ \inheritedframedtextframed\bgroup
+ \let\\=\endgraf
+ \edef\p_framed_text_depthcorrection{\framedtextparameter\c!depthcorrection}%
+ \ifx\p_framed_text_depthcorrection\v!on
+ \pack_framed_text_start_depth_correction
+ \else
+ \bgroup
+ \fi
+ \vskip-\strutdp % brrr why is this needed ... needs to be sorted out, see testcase 1
+ \doinhibitblank
+ \useindentingparameter\framedtextparameter
+ \useframedtextstyleandcolor\c!style\c!color
+ \framedtextparameter\c!inner
+ \ignorespaces}
+
+% testcase 1:
+%
+% \showstruts
+% \startframedtext[align={normal,tolerant},offset=0pt] \input tufte \stopframedtext
+% \startframedtext[align={normal,tolerant},offset=0pt,depthcorrection=off] \input tufte \stopframedtext
+% \startframedtext[align={normal,tolerant},offset=0pt,depthcorrection=off] \inframed{x} \stopframedtext
+% \framed[align={normal,tolerant},offset=0pt]{\input tufte }
+
+%D The \type {none} option is handy for nested usage, as in the presentation
+%D styles, where we don't want interference.
+
+\defineplacement[\??framedtext][\s!parent=\??framedtext\currentframedtext]
+
+\unexpanded\def\pack_framed_text_stop % no \baselinecorrection, see faq docs
+ {\endgraf
+ \removelastskip
+ \ifx\p_framed_text_depthcorrection\v!on
+ \pack_framed_text_stop_depth_correction
+ \else
+ \egroup
+ \fi
+ \stopboxedcontent
+ \ifconditional\c_framed_text_location_none
+ \egroup
+ \box\b_framed_normal
+ \orelse\ifinsidefloat
+ \egroup
+ \box\b_framed_normal
+ \else
+ \egroup
+ \placement[\??framedtext][\c!depthcorrection=\v!off]{\box\b_framed_normal}%
+ \fi
+ \egroup}
+
+%D We define the general (and original) case by just saying:
+
+\def\pack_framed_text_check % messy dependency
+ {\localhsize\hsize
+ \ifinsidefloat \orelse \ifdim\d_page_sides_vsize>\zeropoint % also possible: \c_page_sides_checks_done>\zeropoint
+ % \strut % rather clean way to invoke the sidefloat OTR
+ % \setbox0=\lastbox % and get the widths set, so from now on we
+ % \setlocalhsize % can have framed texts alongside sidefloats
+ \checksidefloat
+ \setlocalhsize
+ \fi}
+
+\def\pack_framed_text_start_depth_correction
+ {\bgroup
+ \ifhmode
+ \par
+ \fi
+ \ifvmode
+ \verticalstrut
+ % we need \nowhitespace in case of setups setting whitespace
+ % nb, not safe, text vs \vbox as next
+ \vskip-\struttotal
+ \nowhitespace
+ \fi} % na vskip ! new 20/05/2004, fails with next content being box (\scale{..})
+
+\def\pack_framed_text_stop_depth_correction
+ {\ifhmode
+ \par
+ \fi
+ \ifvmode
+ \forgetall
+ \vskip-\struttotal
+ \verticalstrut
+ \egroup
+ \forgetall % brrr too often
+ \vskip-\lineheight
+ \verticalstrut
+ \else
+ \egroup
+ \fi}
+
+%D Placement can be ignored:
+%D
+%D \starttyping
+%D \hbox to \hsize \bgroup
+%D \startframedtext[none][width=.5\textwidth] \input tufte \stopframedtext
+%D \startframedtext[none][width=.5\textwidth] \input zapf \stopframedtext
+%D \egroup
+%D
+%D \hbox to \hsize \bgroup
+%D \setupframedtexts[location=none]%
+%D \startframedtext[width=.5\textwidth] \input zapf \stopframedtext
+%D \startframedtext[width=.5\textwidth] \input tufte \stopframedtext
+%D \egroup
+%D \stoptyping
+
+%D The simple brace (or group) delimited case is typeset slightly different
+%D and is not aligned.
+
+\unexpanded\def\pack_framed_text_direct#1%
+ {\bgroup
+ \edef\currentframedtext{#1}%
+ \dosingleempty\pack_framed_text_start_direct}
+
+\def\pack_framed_text_start_direct[#1]%
+ {\usebodyfontparameter\framedtextparameter
+ \iffirstargument
+ \setupcurrentframedtext[#1]%
+ \fi
+ \edef\p_framed_text_strut{\framedtextparameter\c!strut}%
+ \letframedtextparameter\c!strut\v!no
+ \inheritedframedtextframed\bgroup
+ \blank[\v!disable]%
+ \let\\=\endgraf
+ \useframedtextstyleandcolor\c!style\c!color
+ \vskip-\strutdp % brrr why is this needed ... needs to be sorted out, see testcase 1
+ \framedtextparameter\c!inner
+ \ifx\p_framed_text_strut\v!no
+ \let\pack_framed_strut\relax
+ \else
+ \let\pack_framed_strut\strut
+ \fi
+ \bgroup
+ \aftergroup\pack_framed_text_stop_direct
+ \afterassignment\ignorespaces
+ \afterassignment\pack_framed_strut
+ \let\next=}
+
+\def\pack_framed_text_stop_direct
+ {\removelastskip
+ \egroup
+ \egroup}
+
+\defineframedtext
+ [\v!framedtext]
+
+%D \macros
+%D {defineframed}
+%D
+%D One can also define simple framed texts, using:
+%D
+%D \showsetup{defineframed}
+%D
+%D As suggested by Wolfgang we can now use the new \MKIV\ inheritance model instead
+%D of passing a combination of arguments. This also also simplified the \type
+%D {\setupframed} command. There are certainly more places where such improvements
+%D can be made.
+
+\appendtoks
+ \ifcsname\??regularframedlevel\currentframed\endcsname
+ % already defined, keeps settings
+ \else
+ \expandafter\newcount\csname\??regularframedlevel\currentframed\endcsname
+ \fi
+\to \everypresetframed
+
+\appendtoks
+ \setuevalue\currentframed{\pack_framed_defined_process[\currentframed]}%
+\to \everydefineframed
+
+\newcount\c_temp_framed_crap
+
+\unexpanded\def\pack_framed_defined_process[#1]% official (not much checking, todo: parent)
+ {\bgroup
+ \ifcsname\??regularframedlevel#1\endcsname
+ %\expandafter\let\expandafter\c_pack_framed_temp\csname\??regularframedlevel#1\endcsname
+ \expandafter\let\expandafter\c_pack_framed_temp\lastnamedcs
+ \else
+ \let\c_pack_framed_temp\c_temp_framed_crap
+ \fi
+ \advance\c_pack_framed_temp\plusone
+ \expandafter\def\csname\??framed#1>\the\c_pack_framed_temp:\s!parent\endcsname{\??framed#1}% \inheritlocalframed
+ \bgroup
+ \edef\currentframed{#1>\the\c_pack_framed_temp}%
+ \pack_framed_initialize
+ \dosingleempty\pack_framed_defined_process_indeed}
+
+\def\pack_framed_defined_process_indeed[#1]%
+ {\iffirstargument % faster
+ \setupcurrentframed[#1]% here !
+ \fi
+ \pack_framed_process_indeed}
+
+\let\placeframed\pack_framed_defined_process % new per 2012/04/23
+
+%D We can do:
+%D
+%D \starttyping
+%D \defineframed[\v!framed]
+%D \stoptyping
+%D
+%D but the existing one is ok as well (less csname messy too).
+
+%D New, for the moment private; let's see when GB finds out about this one and its
+%D obscure usage. It's used in:
+%D
+%D \startbuffer
+%D \defineframedtext
+%D [tabulateframe]
+%D [offset=overlay,
+%D backgroundoffset=3pt,
+%D background=color,
+%D backgroundcolor=green]
+%D
+%D \setuptabulate
+%D [tabulate]
+%D [frame=tabulateframe]
+%D
+%D \setuptables
+%D [frame=tabulateframe]
+%D
+%D \input tufte
+%D
+%D \starttabulate[|l|l|]
+%D \NC test \NC test \NC \NR \NC test \NC test \NC \NR
+%D \NC test \NC test \NC \NR \NC test \NC test \NC \NR
+%D \stoptabulate
+%D
+%D \input tufte
+%D
+%D \starttable[|l|l|]
+%D \NC test \NC test \NC \AR \NC test \NC test \NC \AR
+%D \NC test \NC test \NC \AR \NC test \NC test \NC \AR
+%D \stoptable
+%D \stopbuffer
+%D
+%D \typebuffer
+
+\installcorenamespace{framedcontent}
+
+\installframedcommandhandler \??framedcontent {framedcontent} \??framedcontent
+
+\setupframedcontent
+ [\c!leftoffset=\zeropoint,
+ %\c!rightoffset=\framedcontentparameter\c!leftoffset,
+ \c!rightoffset=\scratchleftoffset,
+ \c!topoffset=\zeropoint,
+ %\c!bottomoffset=\framedcontentparameter\c!topoffset,
+ \c!bottomoffset=\scratchtopoffset,
+ \c!strut=\v!no,
+ %\c!linecorrection=\v!no,
+ %\c!left=,
+ %\c!right=,
+ %\c!width=\v!fit,
+ \c!offset=\v!overlay]
+
+\unexpanded\def\startframedcontent
+ {\dosingleempty\pack_framed_start_content}
+
+\def\pack_framed_start_content[#1]%
+ {\bgroup
+ \edef\currentframedcontent{#1}%
+ \ifx\currentframedcontent\v!off
+ \let\stopframedcontent\egroup
+ \else
+ \checkframedcontentparent
+ \let\stopframedcontent\pack_framed_stop_content_indeed
+ \expandafter\pack_framed_start_content_indeed
+ \fi}
+
+\def\pack_framed_start_content_indeed
+ {\setbox\b_framed_normal\hpack\bgroup
+ \setlocalhsize
+ \hsize\localhsize
+ \scratchleftoffset \framedcontentparameter\c!leftoffset \relax
+ \scratchrightoffset \framedcontentparameter\c!rightoffset \relax
+ \scratchtopoffset \framedcontentparameter\c!topoffset \relax
+ \scratchbottomoffset\framedcontentparameter\c!bottomoffset\relax
+ \advance\hsize\dimexpr-\scratchleftoffset-\scratchrightoffset \relax
+ \advance\vsize\dimexpr-\scratchtopoffset -\scratchbottomoffset\relax
+ \kern\scratchleftoffset
+ \vpack\bgroup
+ \vskip\scratchtopoffset
+ \vbox\bgroup
+ \forgetall
+ \blank[\v!disable]}
+
+\def\pack_framed_stop_content_indeed
+ {\removelastskip
+ \egroup
+ \vskip\scratchbottomoffset
+ \egroup
+ \kern\scratchrightoffset
+ \egroup
+ \doif{\framedcontentparameter\c!width}\v!fit
+ {\letframedcontentparameter\c!width\v!fixed}% no shapebox
+ \ifinsidefloat
+ \donefalse
+ \else
+ \doifelse{\framedcontentparameter\c!linecorrection}\v!yes\donetrue\donefalse
+ \fi
+ % plaats ?
+ \ifdone\startlinecorrection\fi
+ \framedcontentparameter\c!left % new
+ \inheritedframedcontentframed{\box\b_framed_normal}% hm
+ \framedcontentparameter\c!right % new
+ \ifdone\stoplinecorrection\fi
+ \egroup}
+
+% A shared setting.
+
+\setuplinewidth
+ [\v!medium]
+
+%D A Goodie:
+
+\def\v!unframed{unframed}
+
+\defineframed
+ [\v!unframed]
+ [\c!frame=\v!off,
+ \c!rulethickness=\zeropoint,
+ \c!foregroundstyle=\framedparameter\c!style,
+ \c!foregroundcolor=\framedparameter\c!color]
+
+%D Bonus (as defined in \type {pack-rul.lua}):
+%D
+%D \starttyping
+%D \setbox\scratchbox\vbox{a\par aa\par aaa\par}
+%D \the\dimexpr\themaxboxwidth\scratchbox\relax
+%D \stoptyping
+
+\let\themaxboxwidth\clf_themaxboxwidth
+
+%D New: slow but ok for most cases:
+
+\unexpanded\def\doifelseframed#1%
+ {\ifcase\numexpr\zerocount
+ \immediateassignment\edef\tempstring{#1\c!frame }\ifx\tempstring\v!on +\plusone\fi
+ \immediateassignment\edef\tempstring{#1\c!topframe }\ifx\tempstring\v!on +\plusone\fi
+ \immediateassignment\edef\tempstring{#1\c!bottomframe}\ifx\tempstring\v!on +\plusone\fi
+ \immediateassignment\edef\tempstring{#1\c!leftframe }\ifx\tempstring\v!on +\plusone\fi
+ \immediateassignment\edef\tempstring{#1\c!rightframe }\ifx\tempstring\v!on +\plusone\fi
+ \immediateassignment\edef\tempstring{#1\c!background }\ifx\tempstring\empty\else+\plusone\fi
+ \relax\expandafter\secondoftwoarguments\else\expandafter\firstoftwoarguments\fi}
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-box.mkvi b/Master/texmf-dist/tex/context/base/mkiv/page-box.mkvi
index 10d5916319f..4804e83706a 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-box.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-box.mkvi
@@ -63,8 +63,8 @@
\v_page_target_bottom}}
\def\page_boxes_apply_offset % #box
- {\ifdim\topoffset=\zeropoint
- \ifdim\backoffset=\zeropoint
+ {\ifzeropt\topoffset
+ \ifzeropt\backoffset
\doubleexpandafter\gobbleoneargument
\else
\doubleexpandafter\page_boxes_apply_offset_indeed
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-col.mkiv b/Master/texmf-dist/tex/context/base/mkiv/page-col.mkiv
index 14b5124210f..272ffe18168 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-col.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-col.mkiv
@@ -30,6 +30,9 @@
\setnewconstant\maxnofcolumns 50
\setnewconstant\allocatednofcolumns 0
+\newdimen\columnwidth
+\newdimen\columndistance
+
%D During initialization the temporary boxes are allocated. This enables us to
%D use as much columns as we want, without exhausting the pool of boxes too
%D fast. We could have packed them in one box, but we've got enough boxes.
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-cst.lua b/Master/texmf-dist/tex/context/base/mkiv/page-cst.lua
index 1c2f5fc0b48..a6315ff05f9 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-cst.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-cst.lua
@@ -8,20 +8,20 @@ if not modules then modules = { } end modules ["page-cst"] = {
-- todo: check what is used
-local next, type, tonumber = next, type, tonumber
+local next, type, tonumber, rawget = next, type, tonumber, rawget
local ceil, odd, round = math.ceil, math.odd, math.round
local lower = string.lower
local copy = table.copy
-local trace_state = false trackers.register("columnsets.trace", function(v) trace_state = v end)
-local trace_detail = false trackers.register("columnsets.detail", function(v) trace_detail = v end)
-local trace_cells = false trackers.register("columnsets.cells", function(v) trace_cells = v end)
+local trace_state = false trackers.register("columnsets.trace", function(v) trace_state = v end)
+local trace_details = false trackers.register("columnsets.details", function(v) trace_details = v end)
+local trace_cells = false trackers.register("columnsets.cells", function(v) trace_cells = v end)
local report = logs.reporter("column sets")
local setmetatableindex = table.setmetatableindex
-local properties = nodes.properties
+local properties = nodes.properties.data
local nodecodes = nodes.nodecodes
@@ -36,7 +36,6 @@ local nuts = nodes.nuts
local tonode = nuts.tonode
local tonut = nuts.tonut
-local hpack = nuts.hpack
local vpack = nuts.vpack
local flushlist = nuts.flush_list
----- removenode = nuts.remove
@@ -442,11 +441,13 @@ local function here(c,r,nr,nofcolumns,nofrows,cells,width,spans)
return c, r, nc
end
+-- we use c/r as range limiters
+
local methods = {
[v_here] = here,
[v_fixed] = here,
tblr = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
- for j=1,nofrows-nr+1 do
+ for j=r,nofrows-nr+1 do
for i=c,nofcolumns do
if not cells[i][j] then
local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
@@ -459,7 +460,7 @@ local methods = {
end,
lrtb = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
for i=c,nofcolumns do
- for j=1,nofrows-nr+1 do
+ for j=r,nofrows-nr+1 do
if not cells[i][j] then
local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
if c then
@@ -470,7 +471,7 @@ local methods = {
end
end,
tbrl = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
- for j=1,nofrows-nr+1 do
+ for j=r,nofrows-nr+1 do
for i=nofcolumns,c,-1 do
if not cells[i][j] then
local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
@@ -483,7 +484,7 @@ local methods = {
end,
rltb = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
for i=nofcolumns,c,-1 do
- for j=1,nofrows-nr+1 do
+ for j=r,nofrows-nr+1 do
if not cells[i][j] then
local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
if c then
@@ -494,7 +495,8 @@ local methods = {
end
end,
btlr = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
- for j=nofrows-nr+1,1,-1 do
+ -- for j=nofrows-nr+1,1,-1 do
+ for j=nofrows-nr+1-r+1,1,-1 do
for i=c,nofcolumns do
if not cells[i][j] then
local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
@@ -507,7 +509,8 @@ local methods = {
end,
lrbt = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
for i=c,nofcolumns do
- for j=nofrows-nr+1,1,-1 do
+ -- for j=nofrows-nr+1,1,-1 do
+ for j=nofrows-nr+1-r+1,1,-1 do
if not cells[i][j] then
local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
if c then
@@ -518,7 +521,8 @@ local methods = {
end
end,
btrl = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
- for j=nofrows-nr+1,1,-1 do
+ -- for j=nofrows-nr+1,1,-1 do
+ for j=nofrows-nr+1-r+1,1,-1 do
for i=nofcolumns,c,-1 do
if not cells[i][j] then
local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
@@ -531,7 +535,8 @@ local methods = {
end,
rlbt = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
for i=nofcolumns,c,-1 do
- for j=nofrows-nr+1,1,-1 do
+ -- for j=nofrows-nr+1,1,-1 do
+ for j=nofrows-nr+1-r+1,1,-1 do
if not cells[i][j] then
local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
if c then
@@ -921,7 +926,7 @@ local function findslice(dataset,head,available,column,row)
local used = getheight(done)
local rest = takebox("scratchbox")
if used > (usedsize+slack) then
- if trace_detail then
+ if trace_details then
report("at (%i,%i) available %p, used %p, overflow %p",column,row,usedsize,used,used-usedsize)
end
-- flush copy
@@ -1318,6 +1323,7 @@ interfaces.implement {
{ "r", "integer" },
{ "nc", "integer" },
{ "nr", "integer" },
+ { "method", "string" },
{ "box", "integer" },
} }
}
@@ -1330,6 +1336,7 @@ interfaces.implement {
{ "method", "string" },
{ "c", "integer" },
{ "r", "integer" },
+ { "method", "string" },
{ "box", "integer" },
{ "width", "dimension" },
{ "height", "dimension" },
@@ -1344,6 +1351,7 @@ interfaces.implement {
{ "name", "string" },
{ "c", "integer" },
{ "r", "integer" },
+ { "method", "string" },
{ "box", "integer" },
} }
}
@@ -1415,6 +1423,7 @@ interfaces.implement {
{ "name", "string" },
{ "c", "integer" },
{ "r", "integer" },
+ { "method", "string" },
{ "box", "integer" },
} }
}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-cst.mkiv b/Master/texmf-dist/tex/context/base/mkiv/page-cst.mkiv
index 37df4e8b17c..6ce10a8822e 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-cst.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-cst.mkiv
@@ -181,6 +181,12 @@
\setupoutputroutine[\s!pagegrid]%
\page_grd_command_set_hsize
\page_grd_command_set_vsize
+ %
+ \columnwidth \d_page_grd_column_width
+ \columndistance\d_page_grd_distance
+ \nofcolumns \c_page_grd_n_of_left % not always ok
+ \textwidth \d_page_grd_column_width % kind of redundant but we had it so ...
+ %
}%\begingroup}
\unexpanded\def\stoppagegrid
@@ -221,6 +227,7 @@
{\begingroup
\letdummyparameter\c!c\zerocount
\letdummyparameter\c!r\zerocount
+ \letdummyparameter\c!method\v!here
\letdummyparameter\c!option\v!none
\getdummyparameters[#1]%
\dowithnextboxcs\page_grd_set_indeed\hbox}
@@ -231,6 +238,7 @@
c \dummyparameter\c!c
r \dummyparameter\c!r
box \nextbox
+ method {\dummyparameter\c!method}
option {\dummyparameter\c!option}
}%
\ifcase\c_page_grd_reserved_state
@@ -250,6 +258,7 @@
\fi
\endgroup}
+
\unexpanded\def\page_grd_command_set_vsize
{\clf_setvsizecolumnset{\currentpagegrid}%
\ifdim\d_page_grd_gap_height<\lineheight
@@ -293,9 +302,9 @@
% todo line numbers and marks
\unexpanded\def\page_grd_command_flush_page_column#1%
- {\privatescratchcounter#1\relax
+ {\privatescratchcounter#1\relax % or just currentcolumn as in page-col.mkiv
\clf_flushcolumnsetcolumn{\currentpagegrid}\privatescratchcounter
- \anch_mark_column_box\b_page_grd_column
+ \anch_mark_column_box\b_page_grd_column\privatescratchcounter
\page_marks_synchronize_column\c_page_grd_first_column\c_page_grd_last_column\privatescratchcounter\b_page_grd_column
\ifnum\privatescratchcounter>\c_page_grd_n_of_left
\advance\privatescratchcounter-\c_page_grd_n_of_left
@@ -398,11 +407,13 @@
\global\setfalse\c_page_floats_flushing}
\def\page_grd_command_flush_floats_indeed % much in common with OTRSET
- {\wait\ifconditional\c_page_floats_some_waiting
- \ifconditional\c_page_floats_pack_flushed
- \page_floats_collect\s!text\hsize\emwidth
+ {\ifconditional\c_page_floats_some_waiting
+ \ifconditional\c_page_floats_compress_flushed
+ \page_floats_collect\s!text\hsize\d_page_floats_compress_distance
\ifcase\nofcollectedfloats
\page_floats_get
+ % \or
+ % \page_floats_get
\else
\setfalse\c_page_floats_center_box % not needed as we do call directly
\global\setbox\floatbox\hbox to \hsize
@@ -640,11 +651,12 @@
\edef\currentpagegridspan{#1}%
\clf_sethsizecolumnspan{\currentpagegrid}\pagegridspanparameter\c!n\relax
\setbox\scratchbox\hbox\bgroup\inheritedpagegridspanframed\bgroup
+ \def\page_grd_span_stop{\page_grd_span_stop_indeed{#2}}%
\usepagegridspanstyleandcolor\c!style\c!color
\pagegridspanparameter\c!before
\ignorespaces}
-\unexpanded\def\stoppagegridspan
+\unexpanded\def\page_grd_span_stop_indeed#1%
{\removeunwantedspaces
\par
\verticalstrut
@@ -653,11 +665,14 @@
\endgraf
\pagegridspanparameter\c!after
\egroup\egroup
- \setpagegrid{\box\scratchbox}%
+ \setpagegrid[#1]{\box\scratchbox}%
% todo: push into slot
\egroup
\endgraf}
+\unexpanded\def\stoppagegridspan % indirectness permits aliasing
+ {\page_grd_span_stop}
+
\def\pagegridspanwidth#1% assumes equal distances
{\the\dimexpr
#1\d_page_grd_column_width
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-ffl.mkiv b/Master/texmf-dist/tex/context/base/mkiv/page-ffl.mkiv
index 414cae4ac11..176c4a185e7 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-ffl.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-ffl.mkiv
@@ -65,7 +65,7 @@
\c!inbetween={\blank[\v!big]},
%\c!style,
%\c!color,
- \c!page=\v!yes]
+ \c!page=\v!left]
\appendtoks
\ifx\currentfacingfloatparent\empty
@@ -74,8 +74,8 @@
\fi
\to \everydefinefacingfloat
-\newcount\c_strc_floats_saved
-\newcount\c_strc_floats_flushed
+\newcount\c_strc_floats_facing_saved
+\newcount\c_strc_floats_facing_flushed
\newbox\b_strc_floats_facing_l
\newbox\b_strc_floats_facing_r
@@ -83,12 +83,24 @@
\let\m_strc_floats_state\relax
\def\strc_floats_facing_flush
- {\ifnum\c_strc_floats_flushed<\c_strc_floats_saved
- \strc_floats_facing_flush_indeed % less tracing
+ {\ifnum\c_strc_floats_facing_flushed<\c_strc_floats_facing_saved
+ \ifodd\c_strc_floats_facing_flushed
+ \ifodd\realpageno
+ \strc_floats_facing_flush_indeed
+ \doifelsependingpagecontent\relax{\null\page}%
+ \else
+ \fi
+ \else
+ \ifodd\realpageno
+ \else
+ \strc_floats_facing_flush_indeed
+ \doifelsependingpagecontent\relax{\null\page}%
+ \fi
+ \fi
\fi}
\def\strc_floats_facing_flush_indeed
- {\global\advance\c_strc_floats_flushed\plusone
+ {\global\advance\c_strc_floats_facing_flushed\plusone
\floatingpenalty\zerocount
\insert\namedinsertionnumber\s!topfloat\bgroup
\forgetall
@@ -100,12 +112,12 @@
\prevdepth\maxdimen
\fi
\fi
- \directboxfromcache{\currentfacingfloat}{\number\c_strc_floats_flushed}%
+ \directboxfromcache{\currentfacingfloat}{\number\c_strc_floats_facing_flushed}%
\vkern\s_page_one_between_top_insert
\egroup
- \ifnum\c_strc_floats_saved=\c_strc_floats_flushed
- \global\c_strc_floats_saved \zerocount
- \global\c_strc_floats_flushed\zerocount
+ \ifnum\c_strc_floats_facing_saved=\c_strc_floats_facing_flushed
+ \global\c_strc_floats_facing_saved \zerocount
+ \global\c_strc_floats_facing_flushed\zerocount
\resetboxesincache{\currentfacingfloat}%
\fi}
@@ -145,34 +157,34 @@
\fi\fi}
\unexpanded\def\strc_floats_facing_handle
- {\strc_floats_facing_collect
- \doifnextbgroupelse
+ {\doifnextbgroupelse
\strc_floats_facing_handle_indeed
- \strc_floats_wrap_up}
+ \strc_floats_facing_wrap_up}
\unexpanded\def\strc_floats_facing_handle_indeed
{\dowithnextboxcontent
\strc_floats_facing_setup
- \strc_floats_facing_handle
+ {\strc_floats_facing_collect\strc_floats_facing_handle}
\vbox}
\unexpanded\def\startfacingfloat[#1]%
{\begingroup
% todo: \usepageparameter
- \edef\p_page{\facingfloatparameter\c!page}%
- \ifx\p_page\empty
- \page[\p_page]%
- \fi
+% \edef\p_page{\facingfloatparameter\c!page}%
+% \ifx\p_page\empty\else
+% \page[\p_page]%
+% \fi
%
\let\startcontent\bgroup
\let\stopcontent\egroup
\def\currentfacingfloat{#1}%
+ \let\m_strc_floats_state\v!left
\strc_floats_facing_handle}
\unexpanded\def\stopfacingfloat
{\endgroup}
-\unexpanded\def\strc_floats_wrap_up
+\unexpanded\def\strc_floats_facing_wrap_up
{\edef\p_spaceinbetween{\facingfloatparameter\c!spaceinbetween}%
\ifx\p_spaceinbetween\empty
\scratchdimen\zeropoint
@@ -180,6 +192,12 @@
\setbox\scratchbox\vbox{\directvspacing\p_spaceinbetween}%
\scratchdimen\htdp\scratchbox
\fi
+ \ifvoid\b_strc_floats_facing_l\else
+ \page_postprocessors_linenumbers_box\b_strc_floats_facing_l
+ \fi
+ \ifvoid\b_strc_floats_facing_r\else
+ \page_postprocessors_linenumbers_box\b_strc_floats_facing_r
+ \fi
\doloop{%
\strc_floats_facing_flush_wrap\b_strc_floats_facing_l\v!left
\strc_floats_facing_flush_wrap\b_strc_floats_facing_r\v!right
@@ -202,13 +220,9 @@
\else
\setbox\scratchbox\vbox to \textheight{\box\scratchbox\vss}%
\fi
- \global\advance\c_strc_floats_saved\plusone
- \putboxincache{\currentfacingfloat}{\number\c_strc_floats_saved}\scratchbox
+ \global\advance\c_strc_floats_facing_saved\plusone
+ \putboxincache{\currentfacingfloat}{\number\c_strc_floats_facing_saved}\scratchbox
\endgroup
\fi}
-\appendtoks
- \strc_floats_facing_flush
-\to \everyafteroutput
-
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-flt.lua b/Master/texmf-dist/tex/context/base/mkiv/page-flt.lua
index 41a35d47b8b..b1f729f7a6d 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-flt.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-flt.lua
@@ -87,22 +87,32 @@ end
local function setdimensions(t,b)
local bw, bh, bd = 0, 0, 0
local nw, nh, nd = 0, 0, 0
+ local cw, ch, cd = 0, 0, 0
if b then
bw = b.width
bh = b.height
bd = b.depth
+ cw = b.cwidth
+ ch = b.cheight
+ cd = b.cdepth
end
if t then
- nw = t.width or bw
- nh = t.height or bh
- nd = t.depth or bd
+ nw = t.width or bw
+ nh = t.height or bh
+ nd = t.depth or bd
+ cw = t.cwidth or cw
+ ch = t.cheight or ch
+ cd = t.cdepth or cd
end
setdimen("global","floatwidth", bw)
setdimen("global","floatheight", bh+bd)
setdimen("global","naturalfloatwd", nw)
setdimen("global","naturalfloatht", nh)
setdimen("global","naturalfloatdp", nd)
- return bw, bh, bd, nw, nh, dp
+ setdimen("global","floatcaptionwd", cw)
+ setdimen("global","floatcaptionht", ch)
+ setdimen("global","floatcaptiondp", cd)
+ return bw, bh, bd, nw, nh, dp, cw, xh, xp
end
local function get(stack,n,bylabel)
@@ -125,19 +135,22 @@ local function get(stack,n,bylabel)
end
end
-function floats.save(which,data)
+function floats.save(which,data) -- todo: just pass
which = which or default
local b = textakebox("floatbox")
if b then
local stack = stacks[which]
noffloats = noffloats + 1
local t = {
- n = noffloats,
- data = data or { },
- width = getdimen("naturalfloatwd"),
- height = getdimen("naturalfloatht"),
- depth = getdimen("naturalfloatdp"),
- box = b,
+ n = noffloats,
+ data = data or { },
+ width = getdimen("naturalfloatwd"),
+ height = getdimen("naturalfloatht"),
+ depth = getdimen("naturalfloatdp"),
+ cwidth = getdimen("floatcaptionwd"),
+ cheight = getdimen("floatcaptionht"),
+ cdepth = getdimen("floatcaptiondp"),
+ box = b,
}
insert(stack,t)
-- inspect(stacks)
@@ -240,11 +253,15 @@ function floats.collect(which,maxwidth,distance)
for i=1,stacksize do
local t, b, n = get(stack,i)
if t then
- local w, h, d, nw = setdimensions(t,b)
+ local w, h, d, nw, nh, nd, cw, ch, cd = setdimensions(t,b)
-- we use the real width
- w = nw
+ if cw > nw then
+ w = cw
+ else
+ w = nw
+ end
-- which could be an option
- local rest = maxwidth - w - (1 == 1 and 0 or distance)
+ local rest = maxwidth - w - distance
local fits = rest > -10
if trace_collecting then
report_collecting("%s, category %a, number %a, slot %a width %p, rest %p, fit %a","collecting",
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-flt.mkiv b/Master/texmf-dist/tex/context/base/mkiv/page-flt.mkiv
index 83e2b49547a..01ee8b689e8 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-flt.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-flt.mkiv
@@ -20,10 +20,6 @@
\unprotect
-\ifdefined\s!topfloat \else \def\s!topfloat {topfloat} \fi
-\ifdefined\s!bottomfloat \else \def\s!bottomfloat{bottomfloat} \fi
-\ifdefined\s!pagefloat \else \def\s!pagefloat {pagefloat} \fi
-
\defineinsertion[\s!topfloat]
\defineinsertion[\s!bottomfloat]
\defineinsertion[\s!pagefloat]
@@ -63,7 +59,9 @@
\newconditional\c_page_floats_center_box \settrue\c_page_floats_center_box
\newconditional\c_page_floats_center_box_local
\newconditional\c_page_floats_center_box_global
-\newconditional\c_page_floats_pack_flushed \settrue\c_page_floats_pack_flushed
+\newconditional\c_page_floats_compress_flushed \settrue\c_page_floats_compress_flushed
+
+\newdimen \d_page_floats_compress_distance
%D For the moment we keep this but they will become private too.
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-imp.mkiv b/Master/texmf-dist/tex/context/base/mkiv/page-imp.mkiv
index 838ad742188..a7ef6ca38f7 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-imp.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-imp.mkiv
@@ -136,7 +136,7 @@
{\begingroup
\writestatus\m!system
{\ifarrangingpages arranged \fi page
- \ifarrangingpages\the\arrangeno\else\the\realpageno\fi\normalspace
+ \ifarrangingpages\the\arrangeno\else\the\realpageno\fi\normalspace
not flushed}%
% \setbox\scratchbox\hpack
% {#1}% no finalize
@@ -162,11 +162,15 @@
\box\scratchbox
\endgroup}
-\ifdefined \page_shipout_box \else
+%D Also in normal \MKIV\ we nos use the indirect way so that we benefit from timing and
+%D tracing.
- \def\page_shipout_box#1{\normalshipout\box#1\relax} % takes a number
+% \def\page_shipout_box#1{\normalshipout\box#1\relax} % takes a number
-\fi
+\unexpanded\def\page_shipout_box#1%
+ {\clf_shipoutpage#1\relax
+ \global\setbox#1\emptybox
+ \global\deadcycles\zerocount}
\def\page_shipouts_normal#1%
{\global\advance\shippedoutpages\plusone
@@ -206,6 +210,10 @@
\page_shipouts_ignore{#1}%
\fi}
+\newconditional\c_page_shipouts_use_objects \settrue\c_page_shipouts_use_objects
+
+\installcorenamespace {arrangedpage}
+
\def\page_shipouts_arrange#1%
{\begingroup
\setbox\shipoutscratchbox\hpack
@@ -214,6 +222,12 @@
{\page_otr_flush_every_stuff
\page_otr_flush_special_content
\box\shipoutscratchbox}%
+ %
+ \ifconditional\c_page_shipouts_use_objects
+ \setobject\??arrangedpage{\the\realpageno}\hpack{\box\shipoutscratchbox}%
+ \setbox\shipoutscratchbox\hpack{\getobject\??arrangedpage{\the\realpageno}}%
+ \fi
+ %
\pusharrangedpage\shipoutscratchbox
\deadcycles\zerocount
\endgroup}
@@ -313,8 +327,10 @@
\fi
\setuppapersize
\ifarrangingpages
- \clf_disablejobsave
- %\disabledirective[job.save]%
+ \ifconditional\c_page_shipouts_use_objects\else
+ \clf_disablejobsave
+ %\disabledirective[job.save]%
+ \fi
\fi
\fi}
@@ -417,6 +433,7 @@
\def\outputarrangedbox#1%
{\begingroup
\forgetall % somehow we're back and need to redo this
+ \dontcomplain
\gotonextarrangepage
\ifnum\arrangedrotationO\arrangedrotationE>\zerocount
\setbox#1\vpack
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-ini.lua b/Master/texmf-dist/tex/context/base/mkiv/page-ini.lua
index 3d553412815..17f4c44dadd 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-ini.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-ini.lua
@@ -16,6 +16,8 @@ local texgetcount = tex.getcount
local context = context
local ctx_doifelse = commands.doifelse
+local implement = interfaces.implement
+
local data = table.setmetatableindex("table")
local last = 0
local pages = structures.pages
@@ -177,19 +179,19 @@ luatex.registerpageactions(function()
end
end)
-interfaces.implement {
+implement {
name = "markpage",
arguments = "2 strings",
actions = pages.mark
}
-interfaces.implement {
+implement {
name = "doifelsemarkedpage",
arguments = "string",
actions = { marked, ctx_doifelse }
}
-interfaces.implement {
+implement {
name = "markedpages",
arguments = "string",
actions = function(name)
@@ -200,7 +202,7 @@ interfaces.implement {
end
}
-interfaces.implement {
+implement {
name = "startmarkpages",
arguments = "string",
actions = function(name)
@@ -208,7 +210,7 @@ interfaces.implement {
end
}
-interfaces.implement {
+implement {
name = "stopmarkpages",
arguments = "string",
actions = function(name)
@@ -217,3 +219,23 @@ interfaces.implement {
end
end
}
+
+local tonut = nodes.tonut
+local nextlist = nodes.nuts.traversers.list
+local texlists = tex.lists
+
+implement {
+ name = "doifelsependingpagecontent",
+ actions = function()
+ local h = texlists.contrib_head
+ -- local t = texlists.contrib_tail
+ local p = false
+ if h then
+ for n in nextlist, tonut(h) do
+ p = true
+ break
+ end
+ end
+ ctx_doifelse(p)
+ end,
+}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-ini.mkiv b/Master/texmf-dist/tex/context/base/mkiv/page-ini.mkiv
index 38477dc2747..e56c3ac0404 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-ini.mkiv
@@ -58,9 +58,27 @@
\newbox\pagebox
-\ifdefined\page_postprocessors_column \else \let\page_postprocessors_column\gobbleoneargument \fi
-\ifdefined\page_postprocessors_page \else \let\page_postprocessors_page \gobbleoneargument \fi
-\ifdefined\page_postprocessors_box \else \let\page_postprocessors_box \gobbleoneargument \fi
+% \ifdefined\page_postprocessors_column \else \let\page_postprocessors_column\gobbleoneargument \fi
+% \ifdefined\page_postprocessors_page \else \let\page_postprocessors_page \gobbleoneargument \fi
+% \ifdefined\page_postprocessors_box \else \let\page_postprocessors_box \gobbleoneargument \fi
+
+\newtoks\t_page_postprocessors_box
+\newtoks\t_page_postprocessors_page
+\newtoks\t_page_postprocessors_column
+
+\newconstant\b_page_postprocessor
+
+\def\page_apply_postprocessors_box#1%
+ {\b_page_postprocessor#1\relax
+ \the\t_page_postprocessors_box}
+
+\def\page_apply_postprocessors_page#1%
+ {\b_page_postprocessor#1\relax
+ \the\t_page_postprocessors_page}
+
+\def\page_apply_postprocessors_column#1%
+ {\b_page_postprocessor#1\relax
+ \the\t_page_postprocessors_column}
%D Floats.
@@ -144,6 +162,7 @@
\strc_pagenumbers_increment_counters % should hook into an every
\page_adapts_synchronize
\page_otr_check_for_pending_inserts
+ \page_otr_command_flush_facing_floats
\page_floats_flush_page_floats % before postponed blocks
\page_spread_flush % defined later
\ifnum#3=\plusone
@@ -344,6 +363,10 @@
{\clf_forcestrutdepth\normalpagebox\strutdp\c_page_force_strut_depth_trace_mode
\unvbox\normalpagebox}
+\installoutputroutine\forcestrutdepthplus % experimental
+ {\clf_forcestrutdepthplus\normalpagebox\strutdp\c_page_force_strut_depth_trace_mode
+ \unvbox\normalpagebox}
+
% maybe better:
%
% \installoutputroutine\doforcestrutdepth
@@ -353,4 +376,8 @@
% \unexpanded\def\forcestrutdepth
% {\par\ifvmode\ifinner\else\doforcestrutdepth\fi\fi}
+% Also experimental:
+
+\unexpanded\def\doifelsependingpagecontent{\clf_doifelsependingpagecontent}
+
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-inj.mkvi b/Master/texmf-dist/tex/context/base/mkiv/page-inj.mkvi
index 5f48ffd13dd..b1a2913cf6f 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-inj.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-inj.mkvi
@@ -93,7 +93,7 @@
\def\page_injections_direct_indeed_yes#parameters%
{\clf_savepageinjections
- name {\currentpageinjection}%
+ name {\currentpageinjection}%
state {\p_page_injections_state}%
userdata {\normalunexpanded{#parameters}}%
\relax
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-lay.mkiv b/Master/texmf-dist/tex/context/base/mkiv/page-lay.mkiv
index 02cc5aa17f2..d115b588d6f 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-lay.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-lay.mkiv
@@ -166,6 +166,8 @@
\def\layoutdistance#1#2{\ifdim\zeropoint<#1#2\else\zeropoint\fi}
+% \newconditional\reverselayout
+
\def\page_layouts_set_dimensions
{\global\naturalmarginwidth \layoutparameter\c!margin
\global\naturaledgewidth \layoutparameter\c!edge
@@ -194,8 +196,7 @@
\global\headerdistance \layoutdistance\headerheight \naturalheaderdistance
\global\textdistance \naturaltextdistance
\global\footerdistance \layoutdistance\footerheight \naturalfooterdistance
- \global\bottomdistance \layoutdistance\bottomheight \naturalbottomdistance
- }
+ \global\bottomdistance \layoutdistance\bottomheight \naturalbottomdistance}
\def\page_layouts_set_distances % local in \setreducedvsize
{\headerdistance\layoutdistance\headerheight\naturalheaderdistance
@@ -367,16 +368,16 @@
{\edef\currentlayouttarget{#1}%
\ifx\currentlayouttarget\empty
% invalid target
+ \else\ifcondition\validassignment{#2}%
+ \definelayouttarget[#1][#2]%
\else
- \doifelseassignment{#2}
- {\definelayouttarget[#1][#2]}
- {\setevalue{\??layoutpaper#1}{#2}%
- \ifthirdargument
- \setevalue{\??layoutprint#1}{#3}%
- \else
- \setevalue{\??layoutprint#1}{#2}%
- \fi}%
- \fi}
+ \setevalue{\??layoutpaper#1}{#2}%
+ \ifthirdargument
+ \setevalue{\??layoutprint#1}{#3}%
+ \else
+ \setevalue{\??layoutprint#1}{#2}%
+ \fi
+ \fi\fi}
\appendtoks
\letvalue{\??layoutcurrent\currentlayouttarget}\relax
@@ -400,11 +401,13 @@
\unexpanded\def\page_paper_setup_size[#1][#2]%
{\iffirstargument
- \doifelseassignment{#1}
- {\page_paper_setup_size_settings[#1]}
- {\doifelseassignment{#2}
- {\page_paper_setup_size_settings_by_name[#1][#2]}
- {\page_paper_setup_size_change_size[#1][#2]}}%
+ \ifcondition\validassignment{#1}%
+ \page_paper_setup_size_settings[#1]%
+ \else\ifcondition\validassignment{#2}%
+ \page_paper_setup_size_settings_by_name[#1][#2]%
+ \else
+ \page_paper_setup_size_change_size[#1][#2]%
+ \fi\fi
\else
\page_paper_restore
\fi}
@@ -612,10 +615,6 @@
\fi
-\ifdefined\setups \else
- \unexpanded\def\setups[#1]{\setdefaultpenalties} % still needed?
-\fi
-
\ifdefined\synchronizegridsnapping \else
\let\synchronizegridsnapping\relax
\fi
@@ -644,12 +643,12 @@
\global\cutspace\layoutparameter\c!cutspace\relax
\edef\p_page_layouts_width{\layoutparameter\c!width}%
\ifx\p_page_layouts_width\v!middle
- \ifdim\cutspace=\zeropoint
+ \ifzeropt\cutspace
\global\cutspace\backspace
\fi
\global\makeupwidth\dimexpr\paperwidth-\backspace-\cutspace\relax
\else\ifx\p_page_layouts_width\v!fit
- \ifdim\cutspace=\zeropoint
+ \ifzeropt\cutspace
\global\cutspace\backspace
\fi
\global\makeupwidth\dimexpr\paperwidth-\cutspace\relax
@@ -665,7 +664,7 @@
-\scratchdimen\relax
\else
\global\makeupwidth\p_page_layouts_width\relax
- \ifdim\cutspace=\zeropoint
+ \ifzeropt\cutspace
\global\cutspace\dimexpr\paperwidth-\makeupwidth-\backspace\relax
% \else
% A kind of inconsistent specification, but used
@@ -675,7 +674,7 @@
\fi
\fi\fi
\scratchdimen\layoutparameter\c!bottomspace\relax
- %\ifdim\scratchdimen=\zeropoint
+ %\ifzeropt\scratchdimen
% \scratchdimen\topspace
%\fi
\global\bottomspace\layoutparameter\c!bottomspace\relax
@@ -683,12 +682,12 @@
\ifcase\layoutlines
\edef\p_page_layouts_height{\layoutparameter\c!height}%
\ifx\p_page_layouts_height\v!middle
- \ifdim\bottomspace=\zeropoint
+ \ifzeropt\bottomspace
\global\bottomspace\topspace
\fi
\global\makeupheight\dimexpr\paperheight-\topspace-\bottomspace\relax
\else\ifx\p_page_layouts_height\v!fit
- \ifdim\bottomspace=\zeropoint
+ \ifzeropt\bottomspace
\global\bottomspace\topspace
\fi
\global\makeupheight\dimexpr\paperheight-\bottomspace\relax
@@ -699,7 +698,7 @@
\global\advance\makeupheight\dimexpr-\bottomdistance-\bottomheight-\scratchdimen\relax
\else
\global\makeupheight\layoutparameter\c!height\relax
- \ifdim\bottomspace=\zeropoint
+ \ifzeropt\bottomspace
\global\bottomspace\dimexpr\paperheight-\makeupheight-\topspace\relax
% \else
% inconsistent specification
@@ -731,6 +730,7 @@
+\rightedgetotal
\relax
% \page_layouts_check_next % here ?
+ \page_layouts_check_direction
\page_layouts_calculate_extras
\page_target_check_centering
\calculatehsizes
@@ -738,6 +738,21 @@
\page_layouts_check_pseudo_columns
\page_backgrounds_recalculate}
+\def\page_layouts_check_direction
+ {\edef\p_direction{\layoutparameter\c!direction}%
+ \ifx\p_direction\v!reverse
+ \globalswapdimens\naturalleftedgedistance \naturalrightedgedistance
+ \globalswapdimens\naturalleftmargindistance\naturalrightmargindistance
+ \globalswapdimens\leftedgedistance \rightedgedistance
+ \globalswapdimens\leftmargindistance \rightmargindistance
+ \globalswapdimens\leftmarginwidth \rightmarginwidth
+ \globalswapdimens\leftedgewidth \rightedgewidth
+ \globalswapdimens\backspace \cutspace
+ \expandafter\setsystemmode
+ \else
+ \expandafter\resetsystemmode
+ \fi{reverselayout}}
+
\def\page_layouts_check_pseudo_columns
{\global\layoutcolumns\layoutparameter\c!columns
\global\layoutcolumndistance\layoutparameter\c!columndistance
@@ -1340,6 +1355,7 @@
%D \showsetup{showsetups}
%D %showsetup{showmargins}
%D %showsetup{showgrid}
+%D %showsetup{showusage}
\fetchruntimecommand \showprint \f!page_run
\fetchruntimecommand \showframe \f!page_run
@@ -1347,6 +1363,7 @@
\fetchruntimecommand \showsetups \f!page_run
\fetchruntimecommand \showmargins \f!page_run
\fetchruntimecommand \showgrid \f!page_run
+\fetchruntimecommand \showusage \f!page_run
\glet\page_grids_add_to_box\gobbleoneargument
\glet\page_grids_add_to_one\gobbleoneargument
@@ -1408,6 +1425,7 @@
\c!dx=\zeropoint,
\c!dy=\zeropoint,
\c!grid=\v!no,
+ \c!direction=\v!normal,
\c!preset=,
\c!setups=\systemsetupsprefix\s!default,
\c!clipoffset=\zeropoint,
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-lin.lua b/Master/texmf-dist/tex/context/base/mkiv/page-lin.lua
index 3689c7f8d1d..5ad660460c1 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-lin.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-lin.lua
@@ -40,7 +40,7 @@ local v_next = variables.next
local v_page = variables.page
local v_no = variables.no
-local properties = nodes.properties
+local properties = nodes.properties.data
local nodecodes = nodes.nodecodes
local listcodes = nodes.listcodes
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-lin.mkvi b/Master/texmf-dist/tex/context/base/mkiv/page-lin.mkvi
index a27ba5736c5..6a03d12e45b 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-lin.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-lin.mkvi
@@ -72,10 +72,22 @@
\newconditional\page_postprocessors_needed_box
-\unexpanded\def\page_postprocessors_linenumbers_page #tag{\page_lines_add_numbers_to_box{#tag}\plusone \plusone \zerocount}
-\unexpanded\def\page_postprocessors_linenumbers_box #tag{\page_lines_add_numbers_to_box{#tag}\plusone \plusone \zerocount}
-\unexpanded\def\page_postprocessors_linenumbers_deepbox#tag{\page_lines_add_numbers_to_box{#tag}\plusone \plusone \plusone }
-\unexpanded\def\page_postprocessors_linenumbers_column #tag{\page_lines_add_numbers_to_box{#tag}\currentcolumn\nofcolumns\zerocount}
+\unexpanded\def\page_postprocessors_linenumbers_page_indeed #tag{\page_lines_add_numbers_to_box{#tag}\plusone \plusone \zerocount}
+\unexpanded\def\page_postprocessors_linenumbers_box_indeed #tag{\page_lines_add_numbers_to_box{#tag}\plusone \plusone \zerocount}
+\unexpanded\def\page_postprocessors_linenumbers_deepbox_indeed#tag{\page_lines_add_numbers_to_box{#tag}\plusone \plusone \plusone }
+\unexpanded\def\page_postprocessors_linenumbers_column_indeed #tag{\page_lines_add_numbers_to_box{#tag}\currentcolumn\nofcolumns\zerocount}
+
+\let\page_postprocessors_linenumbers_page \gobbleoneargument
+\let\page_postprocessors_linenumbers_box \gobbleoneargument
+\let\page_postprocessors_linenumbers_deepbox\gobbleoneargument
+\let\page_postprocessors_linenumbers_column \gobbleoneargument
+
+\unexpanded\def\page_postprocessors_linenumbers_check
+ {\glet\page_postprocessors_linenumbers_check \relax
+ \glet\page_postprocessors_linenumbers_page \page_postprocessors_linenumbers_page_indeed
+ \glet\page_postprocessors_linenumbers_box \page_postprocessors_linenumbers_box_indeed
+ \glet\page_postprocessors_linenumbers_deepbox\page_postprocessors_linenumbers_deepbox_indeed
+ \glet\page_postprocessors_linenumbers_column \page_postprocessors_linenumbers_column_indeed}
\def\page_lines_start_define
{\setxvalue{\??linenumberinginstance\currentlinenumbering}%
@@ -179,6 +191,7 @@
\unexpanded\def\startlinenumbering
{\begingroup
+ \page_postprocessors_linenumbers_check
\dodoubleempty\page_lines_start}
\newcount\c_pages_lines_nesting
@@ -255,6 +268,19 @@
\page_lines_start_followup}
\newconditional\c_page_lines_auto_narrow
+%\newconditional\c_page_lines_enabled
+
+\appendtoks
+ \ifconditional\page_postprocessors_needed_box
+ \page_postprocessors_linenumbers_page\b_page_postprocessor
+ \fi
+\to \t_page_postprocessors_page
+
+\appendtoks
+ \ifconditional\page_postprocessors_needed_box
+ \page_postprocessors_linenumbers_column\b_page_postprocessor
+ \fi
+\to \t_page_postprocessors_column
\def\page_lines_start_followup
{\numberinglinestrue
@@ -279,8 +305,7 @@
\fi\fi\fi
\fi
\the\beforeeverylinenumbering
- \glet\page_postprocessors_page \page_postprocessors_linenumbers_page
- \glet\page_postprocessors_column\page_postprocessors_linenumbers_column
+ %\global\settrue\c_page_lines_enabled %
\global\settrue\page_postprocessors_needed_box % see core-rul.mkiv
\ifcase\c_page_lines_mode\relax
\page_lines_start_update % continue
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-mix.lua b/Master/texmf-dist/tex/context/base/mkiv/page-mix.lua
index 192b8a30aa6..dacc829d7e6 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-mix.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-mix.lua
@@ -19,8 +19,8 @@ local next, type = next, type
local concat = table.concat
local ceil = math.ceil
-local trace_state = false trackers.register("mixedcolumns.trace", function(v) trace_state = v end)
-local trace_detail = false trackers.register("mixedcolumns.detail", function(v) trace_detail = v end)
+local trace_state = false trackers.register("mixedcolumns.trace", function(v) trace_state = v end)
+local trace_details = false trackers.register("mixedcolumns.details", function(v) trace_details = v end)
local report_state = logs.reporter("mixed columns")
@@ -41,7 +41,6 @@ local nuts = nodes.nuts
local tonode = nuts.tonode
local listtoutf = nodes.listtoutf
-local hpack = nuts.hpack
local vpack = nuts.vpack
local flushnode = nuts.flush
local concatnodes = nuts.concat
@@ -124,7 +123,7 @@ local function collectinserts(result,nxt,nxtid)
inserttotal = inserttotal + getheight(nxt) -- height includes depth (hm, still? needs checking)
local s = getsubtype(nxt)
local c = inserts[s]
- if trace_detail then
+ if trace_details then
report_state("insert of class %s found",s)
end
if not c then
@@ -138,7 +137,7 @@ local function collectinserts(result,nxt,nxtid)
end
c[#c+1] = nxt
elseif nxtid == mark_code then
- if trace_detail then
+ if trace_details then
report_state("mark found")
end
else
@@ -326,20 +325,24 @@ local function preparesplit(specification) -- a rather large function
report_state("setting collector to column %s",column)
end
- local function unlock(penalty)
+ local function unlock(case,penalty)
if lastlocked then
if trace_state then
- report_state("penalty %s, unlocking in column %s",penalty or "-",column)
+ report_state("penalty %s, unlocking in column %s, case %i",penalty or "-",column,case)
end
lastlocked = nil
+ else
+ if trace_state then
+ report_state("penalty %s, ignoring in column %s, case %i",penalty or "-",column,case)
+ end
end
lastcurrent = nil
lastcontent = nil
end
- local function lock(penalty,current)
+ local function lock(case,penalty,current)
if trace_state then
- report_state("penalty %s, locking in column %s",penalty,column)
+ report_state("penalty %s, locking in column %s, case %i",penalty,column,case)
end
lastlocked = penalty
lastcurrent = current or lastcurrent
@@ -353,12 +356,12 @@ local function preparesplit(specification) -- a rather large function
local id = getid(current)
if id == glue_code then
if trace_state then
- report_state("backtracking over %s in column %s","glue",column)
+ report_state("backtracking over %s in column %s, value %p","glue",column,getwidth(current))
end
current = getprev(current)
elseif id == penalty_code then
if trace_state then
- report_state("backtracking over %s in column %s","penalty",column)
+ report_state("backtracking over %s in column %s, value %i","penalty",column,getpenalty(current))
end
current = getprev(current)
else
@@ -370,12 +373,12 @@ local function preparesplit(specification) -- a rather large function
local id = getid(current)
if id == glue_code then
if trace_state then
- report_state("quitting at %s in column %s","glue",column)
+ report_state("quitting at %s in column %s, value %p","glue",column,getwidth(current))
end
break
elseif id == penalty_code then
if trace_state then
- report_state("quitting at %s in column %s","penalty",column)
+ report_state("quitting at %s in column %s, value %i","penalty",column,getpenalty(current))
end
break
else
@@ -398,7 +401,11 @@ local function preparesplit(specification) -- a rather large function
report_state("backtracking to preferred break in column %s",column)
end
-- todo: also remember height/depth
- current = backtrack(lastcurrent)
+ if true then -- todo: option to disable this
+ current = backtrack(lastcurrent) -- not ok yet
+ else
+ current = lastcurrent
+ end
backtracked = true
end
lastcurrent = nil
@@ -441,7 +448,7 @@ local function preparesplit(specification) -- a rather large function
report_state("setting collector to column %s",column)
end
current, skipped = discardtopglue(current,discarded)
- if trace_detail and skipped ~= 0 then
+ if trace_details and skipped ~= 0 then
report_state("check > column 1, discarded %p",skipped)
end
head = current
@@ -465,7 +472,7 @@ local function preparesplit(specification) -- a rather large function
state = "quit"
end
end
- if trace_detail then
+ if trace_details then
report_state("%-8s > column %s, delta %p, threshold %p, advance %p, total %p, target %p => %a (height %p, depth %p, skip %p)",
where,curcol,delta,threshold,advance,total,target,state,height,depth,skip)
end
@@ -473,7 +480,7 @@ local function preparesplit(specification) -- a rather large function
end
current, skipped = discardtopglue(current,discarded)
- if trace_detail and skipped ~= 0 then
+ if trace_details and skipped ~= 0 then
report_state("check > column 1, discarded %p",skipped)
end
@@ -483,6 +490,8 @@ local function preparesplit(specification) -- a rather large function
--
-- ok, we could use vsplit but we don't have that one opened up yet .. maybe i should look into the c-code
-- .. something that i try to avoid so let's experiment more before we entry dirty trick mode
+ --
+ -- what if we can do a preroll in lua, get head and tail and then slice of a bit and push that ahead
head = current
@@ -517,7 +526,7 @@ local function preparesplit(specification) -- a rather large function
-- what else? ignore? treat as valid as usual?
end
if lastcontent then
- unlock()
+ unlock(1)
end
end
@@ -578,7 +587,7 @@ local function preparesplit(specification) -- a rather large function
local function process_penalty(current,nxt)
local penalty = getpenalty(current)
if penalty == 0 then
- unlock(penalty)
+ unlock(2,penalty)
elseif penalty == forcedbreak then
local needed = getattribute(current,a_checkedbreak)
local proceed = not needed or needed == 0
@@ -590,7 +599,7 @@ local function preparesplit(specification) -- a rather large function
end
end
if proceed then
- unlock(penalty)
+ unlock(3,penalty)
local okay, skipped = gotonext()
if okay then
if trace_state then
@@ -611,15 +620,17 @@ local function preparesplit(specification) -- a rather large function
end
elseif penalty < 0 then
-- we don't care too much
- unlock(penalty)
+ unlock(4,penalty)
elseif penalty >= 10000 then
if not lastcurrent then
- lock(penalty,current)
+ lock(1,penalty,current)
elseif penalty > lastlocked then
- lock(penalty)
+ lock(2,penalty)
+ elseif trace_state then
+ report_state("penalty %s, ignoring in column %s, case %i",penalty,column,3)
end
else
- unlock(penalty)
+ unlock(5,penalty)
end
end
@@ -687,6 +698,10 @@ local function preparesplit(specification) -- a rather large function
local id = getid(current)
local nxt = getnext(current)
+ if trace_state then
+ report_state("%-8s > column %s, height %p, depth %p, id %s","node",column,height,depth,nodecodes[id])
+ end
+
backtracked = false
if id == hlist_code or id == vlist_code then
@@ -788,7 +803,7 @@ local function finalize(result)
local t = { }
for i=1,#list do
local l = list[i]
- local h = new_hlist()
+ local h = new_vlist() -- was hlist but that's wrong
local g = getlist(l)
t[i] = h
setlist(h,g)
@@ -869,12 +884,12 @@ end
local function getsplit(result,n)
if not result then
- report_state("flush, column %s, no result",n)
+ report_state("flush, column %s, %s",n,"no result")
return
end
local r = result.results[n]
if not r then
- report_state("flush, column %s, empty",n)
+ report_state("flush, column %s, %s",n,"empty")
end
local h = r.head
if not h then
@@ -970,9 +985,8 @@ local function getsplit(result,n)
for i=1,#list-1 do
setdepth(list[i],0)
end
- local b = vpack(l) -- multiple arguments, todo: fastvpack
- -- setbox("global",c,b)
- setbox(c,b)
+ local b = vpack(l) -- multiple arguments, todo: fastvpack
+ setbox("global",c,b) -- when we wrap in a box
r.inserts[c] = nil
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-mix.mkiv b/Master/texmf-dist/tex/context/base/mkiv/page-mix.mkiv
index 436c4a1dcf6..f54b8ec71d4 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-mix.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-mix.mkiv
@@ -242,7 +242,8 @@
\page_one_command_routine
\fi
\global\setbox\b_page_mix_preceding\vbox % pack ?
- {\page_otr_command_flush_top_insertions
+ {\forgetall
+ \page_otr_command_flush_top_insertions
\ifdim\htdp\b_page_mix_preceding=\zeropoint \else
\writestatus\m!columns{preceding error}%
\unvbox\b_page_mix_preceding
@@ -261,7 +262,7 @@
\unexpanded\def\page_mix_command_set_hsize
{\hsize\d_page_mix_column_width
- \textwidth\d_page_mix_column_width}
+ \columnwidth\d_page_mix_column_width}
%D When setting the vsize we make sure that we collect a few more lines than needed
%D so that we have enough to split over the columns. Collecting too much is somewhat
@@ -566,6 +567,11 @@
%
\d_page_mix_column_width\dimexpr(\d_page_mix_max_width-\d_page_mix_distance*\numexpr(\c_page_mix_n_of_columns-\plusone)\relax)/\c_page_mix_n_of_columns\relax
%
+ \columnwidth \d_page_mix_column_width
+ \columndistance\d_page_mix_distance
+ \nofcolumns \c_page_mix_n_of_columns
+ \textwidth \d_page_mix_column_width % kind of redundant but we had it so ...
+ %
\usemixedcolumnscolorparameter\c!color
%
\insidecolumnstrue % new
@@ -704,7 +710,7 @@
\page_lines_add_numbers_to_box\scratchbox\recurselevel\c_page_mix_n_of_columns\plusone % new
\page_marks_synchronize_column\plusone\c_page_mix_n_of_columns\recurselevel\scratchbox
% backgrounds
- \anch_mark_column_box\scratchbox
+ \anch_mark_column_box\scratchbox\recurselevel
% for the moment a quick and dirty patch .. we need to go into the box (hence the \plusone) .. a slowdowner
% moved to start: \page_lines_add_numbers_to_box\scratchbox\recurselevel\c_page_mix_n_of_columns\plusone
% the framed needs a reset of strut, align, setups etc
@@ -773,6 +779,23 @@
\hss
\egroup}
+% \unexpanded\def\page_mix_command_package_column
+% {\page_mix_hbox to \d_page_mix_column_width \bgroup
+% % maybe intercept empty
+% \ruledhpack\bgroup
+% \clf_mixgetsplit\recurselevel\relax
+% \egroup
+% \hskip-\d_page_mix_column_width
+% \ruledhpack \bgroup
+% \hsize\d_page_mix_column_width
+% \ifconditional\c_page_mix_process_notes
+% \placenoteinserts
+% \fi
+% \egroup
+% \hss
+% \egroup}
+
+
\unexpanded\def\page_mix_routine_continue
{\bgroup
\forgetall
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-mul.mkiv b/Master/texmf-dist/tex/context/base/mkiv/page-mul.mkiv
index 957981703e4..f1d68827ab7 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-mul.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-mul.mkiv
@@ -461,7 +461,7 @@
\setfalse\c_page_mul_preceding_present % will be set elsewhere
\else
\settrue\c_page_mul_preceding_present
- \page_postprocessors_box\b_page_mul_preceding
+ \page_apply_postprocessors_box\b_page_mul_preceding
\fi
\forgetall
\page_mul_initialize_variables
@@ -487,7 +487,7 @@
{\setbox\scratchbox\hpack
{\ifx\finishcolumnbox\relax\else\strut\fi
\box\currentcolumnbox}% hm, why strut
- \anch_mark_column_box\scratchbox
+ \anch_mark_column_box\scratchbox\currentcolumn
\box\scratchbox}%
\hfil}%
\unskip
@@ -612,18 +612,21 @@
%D This feature is implemented using the reshape macros presented
%D in \type{supp-box}.
-\ifdefined\page_postprocessors_column\else\let\page_postprocessors_column\relax\fi % operates on passed box
+%ifdefined\page_postprocessors_column\else\let\page_postprocessors_column\relax\fi % operates on passed box
\ifdefined\postprocesscolumnline \else\let\postprocesscolumnline \relax\fi % operates on passed box
\ifdefined\postprocesscolumnbox \else\let\postprocesscolumnbox \relax\fi % operates on passed box
\ifdefined\postprocesscolumnpagebox \else\let\postprocesscolumnpagebox \relax\fi % operates on passed box
-\def\page_mul_postprocess_linenumbers{\ifx\page_postprocessors_column\relax\else\page_mul_postprocess_linenumbers_indeed\fi}
+%def\page_mul_postprocess_linenumbers{\ifx\page_postprocessors_column\relax\else\page_mul_postprocess_linenumbers_indeed\fi}
\def\page_mul_postprocess_lines {\ifx\postprocesscolumnline \relax\else\page_mul_postprocess_lines_indeed \fi}
\def\page_mul_postprocess_columns {\ifx\postprocesscolumnbox \relax\else\page_mul_postprocess_columns_indeed \fi}
\def\page_mul_postprocess_page {\ifx\postprocesscolumnpagebox \relax\else\page_mul_postprocess_page_indeed \fi}
-\def\page_mul_postprocess_linenumbers_indeed
- {\dohandleallcolumns{\page_postprocessors_column\currentcolumnbox}}
+% \def\page_mul_postprocess_linenumbers_indeed
+% {\dohandleallcolumns{\page_apply_postprocessors_column\currentcolumnbox}}
+
+\def\page_mul_postprocess_linenumbers
+ {\dohandleallcolumns{\page_apply_postprocessors_column\currentcolumnbox}}
\def\page_mul_postprocess_lines_indeed
{\dohandleallcolumnscs\page_mul_postprocess_lines_step}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-not.mkiv b/Master/texmf-dist/tex/context/base/mkiv/page-not.mkiv
index d7602bd2658..d6f63846f6e 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-not.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-not.mkiv
@@ -22,20 +22,20 @@
\unprotect
-\def\checkbegincolumnfootnotes % should happen inside otr
- {\ifcase\c_strc_notes_page_location
- \erasenotebackup
- \else
- \flushnotes
- \savenotecontent
- \fi
- \savenotedata}
+% \def\checkbegincolumnfootnotes % should happen inside otr
+% {\ifcase\c_strc_notes_page_location
+% \erasenotebackup
+% \else
+% \flushnotes
+% \savenotecontent
+% \fi
+% \savenotedata}
-\def\checkendcolumnfootnotes
- {\restorenotedata
- \ifcase\c_strc_notes_page_location\else
- \restorenotecontent
- \fi}
+% \def\checkendcolumnfootnotes
+% {\restorenotedata
+% \ifcase\c_strc_notes_page_location\else
+% \restorenotecontent
+% \fi}
\let\checksinglecolumnfootnotes\relax
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-one.mkiv b/Master/texmf-dist/tex/context/base/mkiv/page-one.mkiv
index 64c4a713498..85ed76da180 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-one.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-one.mkiv
@@ -29,7 +29,8 @@
{\page_otr_eject_page_and_flush_inserts}
\unexpanded\def\page_one_command_set_hsize
- {\global\hsize\textwidth}
+ {\global\hsize\textwidth
+ \columnwidth\textwidth} % bonus so that it's not zero
\unexpanded\def\page_one_command_set_float_hsize
{\global\hsize\textwidth}
@@ -76,7 +77,7 @@
\global\advance\vsize\d_page_adapts_delta
% alternatively we could set it in builders.buildpage_filter
% \ifdim\pagegoal<\maxdimen .. \fi
- \global\pagegoal\dimexpr\vsize-\d_page_floats_inserted_top-\d_page_floats_inserted_bottom\relax}
+ \pagegoal\dimexpr\vsize-\d_page_floats_inserted_top-\d_page_floats_inserted_bottom\relax}
% 1 = partial page, 2 = whole page, 3 = partial page
@@ -146,14 +147,18 @@
\page_one_registered_text_area_a#1#2% \unvbox <box>
%
\ifgridsnapping
+ \unskip % new per 2019-06-18, otherwise weird bottom floats
\vkern\dimexpr\openstrutdepth-\d_page_one_natural_depth\relax
\prevdepth\openstrutdepth
\page_otr_command_flush_bottom_insertions
\vfil
\else\ifcase\bottomraggednessmode
% ragged (default)
+ \unskip % new per 2019-06-18, otherwise weird bottom floats
\vkern\dimexpr\openstrutdepth-\d_page_one_natural_depth\relax
\prevdepth\openstrutdepth
+ % these have whitespace before but we can have some more options
+ % like a \vfill or so
\page_otr_command_flush_bottom_insertions
\vfil
\or
@@ -161,6 +166,7 @@
\page_otr_command_flush_bottom_insertions
\or
% baseline
+ \unskip % new per 2019-06-18, otherwise weird bottom floats
\vkern\dimexpr\maxdepth-\d_page_one_natural_depth\relax
\page_otr_command_flush_bottom_insertions
\fi\fi
@@ -373,35 +379,37 @@
\fi \fi
\snaptogrid\hpack{\box\floatbox}} % was copy
-\def\page_one_command_flush_floats_indeed % much in common with OTRSET
+\def\page_one_command_floats_get_compressed
+ {\setfalse\c_page_floats_center_box % not needed as we do call directly
+ %% no longer (interferes with footnotes):
+ %%
+ %% \page_one_command_set_vsize % test 2011.06.24.001
+ %%
+ \global\setbox\floatbox\hbox to \hsize
+ {\hfil
+ \dorecurse\nofcollectedfloats
+ {\ifcase\columndirection % nog document wide
+ \page_floats_flush\s!text\plusone
+ \else
+ \page_floats_flush\s!text{\the\numexpr\nofcollectedfloats-\recurselevel+1\relax}%
+ \fi
+ \hpack to \ifdim\naturalfloatwd>\makeupwidth\makeupwidth\else\naturalfloatwd\fi
+ {\hss\box\floatbox\hss}%
+ \ifnum\recurselevel<\nofcollectedfloats
+ \hfil
+ \fi}%
+ \hfil}}
+
+\def\page_one_command_flush_floats_indeed
{\ifconditional\c_page_floats_some_waiting
\ifconditional\c_page_floats_pack_flushed
- \page_floats_collect\s!text\hsize\emwidth
+ \page_floats_collect\s!text\hsize\d_page_floats_compress_distance
\ifcase\nofcollectedfloats
\page_floats_get
+ \or
+ \page_floats_get
\else
- \setfalse\c_page_floats_center_box % not needed as we do call directly
- %% no longer (interferes with footnotes):
- %%
- %% \page_one_command_set_vsize % test 2011.06.24.001
- %%
- \global\setbox\floatbox\hbox to \hsize
- {\hfil
- \dorecurse\nofcollectedfloats
- {\ifcase\columndirection % nog document wide
- \page_floats_flush\s!text\plusone
- \else
- \page_floats_flush\s!text{\the\numexpr\nofcollectedfloats-\recurselevel+1\relax}%
- \fi
- \ifdim\wd\floatbox>\makeupwidth % \hsize
- \hpack to \makeupwidth{\hss\box\floatbox\hss}%
- \else
- \box\floatbox
- \fi
- \ifnum\recurselevel<\nofcollectedfloats
- \hfil
- \fi}%
- \hfil}%
+ \page_one_command_floats_get_compressed
\fi
\else
\page_floats_get
@@ -438,7 +446,13 @@
\fi
% should be an option
\endgroup
- \scratchdimenone\dimexpr\pagetotal+\floatheight+\d_strc_floats_top-\pageshrink\relax
+ \scratchdimenone\dimexpr
+ \pagetotal
+ +\floatheight
+ +\d_strc_floats_top
+ +\d_strc_floats_overflow
+ -\pageshrink
+ \relax
\scratchdimentwo\pagegoal
\relax % needed
\ifcase\c_page_one_float_method
@@ -666,6 +680,9 @@
\endgroup
\fi}
+\unexpanded\def\page_one_command_flush_facing_floats
+ {\strc_floats_facing_flush}
+
\defineoutputroutine
[\s!singlecolumn]
[\s!page_otr_command_routine =\page_one_command_routine,
@@ -689,8 +706,9 @@
\s!page_otr_command_flush_saved_floats =\page_one_command_flush_saved_floats,
\s!page_otr_command_flush_all_floats =\page_one_command_flush_all_floats,
\s!page_otr_command_flush_margin_blocks =\page_one_command_flush_margin_blocks,
- \s!page_otr_command_test_column =\page_one_command_test_page
- ]
+ \s!page_otr_command_test_column =\page_one_command_test_page,
+ \s!page_otr_command_flush_facing_floats =\page_one_command_flush_facing_floats
+]
% \setupoutputroutine
% [\s!singlecolumn]
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-otr.mkvi b/Master/texmf-dist/tex/context/base/mkiv/page-otr.mkvi
index 909f5cd4d1e..6feb15a9d61 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-otr.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-otr.mkvi
@@ -285,6 +285,7 @@
\definesystemconstant{page_otr_command_flush_all_floats}
\definesystemconstant{page_otr_command_flush_margin_blocks}
\definesystemconstant{page_otr_command_test_column}
+\definesystemconstant{page_otr_command_flush_facing_floats}
\definesystemconstant{singlecolumn}
\definesystemconstant{multicolumn} % will move
@@ -313,7 +314,8 @@
\s!page_otr_command_flush_saved_floats,
\s!page_otr_command_flush_all_floats,
\s!page_otr_command_flush_margin_blocks,
- \s!page_otr_command_test_column]
+ \s!page_otr_command_test_column,
+ \s!page_otr_command_flush_facing_floats]
\appendtoks
\setupoutputroutine[\s!singlecolumn]%
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-pcl.mkiv b/Master/texmf-dist/tex/context/base/mkiv/page-pcl.mkiv
index 140444fc27b..09368c53746 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-pcl.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-pcl.mkiv
@@ -94,7 +94,9 @@
\else
\numexpr\c_page_col_n_of_columns-\plusone\relax
\dimexpr\d_page_col_column_width+\d_page_col_distance\relax
- \fi}
+ \fi
+ % consistent with mixed:
+ \textwidth\d_page_col_column_width}
%D \unknown
@@ -112,13 +114,19 @@
%D \unknown
+\def\page_col_registered_text_area_b#1%
+ {\begingroup
+ \makeupwidth\d_page_col_column_width
+ \page_one_registered_text_area_b{#1}%
+ \endgroup}
+
\unexpanded\def\page_col_command_package_contents#1#2% \box<n> \unvbox<n> % this one will be redone (checked)
{\bgroup
\setbox\b_page_one_contents\vbox to \textheight
{\page_one_registered_text_area_a#1#2}%
\page_one_command_package_show_state
\ht\b_page_one_contents\textheight
- \page_one_registered_text_area_b
+ \page_col_registered_text_area_b
{\box\b_page_one_contents}%
\egroup}
@@ -174,13 +182,13 @@
\ht\b_page_one_bottom_notes\zeropoint
\wd\b_page_one_bottom_notes\zeropoint
\wd\b_page_one_bottom_notes\d_page_col_column_width
- \page_one_registered_text_area_b
+ \page_col_registered_text_area_b
{\vpack to \textheight
- {\hbox{\box\b_page_one_contents\box\b_page_one_bottom_notes}}}%
+ {\hpack{\box\b_page_one_contents\box\b_page_one_bottom_notes}}}%
\else
\ht\b_page_one_contents\textheight
\wd\b_page_one_contents\d_page_col_column_width
- \page_one_registered_text_area_b
+ \page_col_registered_text_area_b
{\box\b_page_one_contents}%
\fi
\egroup}
@@ -238,7 +246,7 @@
\page_lines_add_numbers_to_box\scratchbox\recurselevel\c_page_col_n_of_columns\plusone % new
\page_marks_synchronize_column\plusone\c_page_col_n_of_columns\recurselevel\scratchbox
% backgrounds
- \anch_mark_column_box\scratchbox
+ \anch_mark_column_box\scratchbox\recurselevel
\mixedcolumnseparatorheight\ht\scratchbox
\mixedcolumnseparatordepth \dp\scratchbox
\inheritedpagecolumnsframedbox\recurselevel\scratchbox}
@@ -392,10 +400,9 @@
\def\page_col_command_flush_floats_indeed % much in common with OTRSET
{\ifconditional\c_page_floats_some_waiting
- \ifconditional\c_page_floats_pack_flushed
+ \ifconditional\c_page_floats_compress_flushed
\setfalse\c_page_floats_center_box % not needed as we do call directly
- %
- \page_floats_collect\s!text\hsize\emwidth
+ \page_floats_collect\s!text\hsize\d_page_floats_compress_distance
%
\ifnum\nofcollectedfloats=\plusone
\ifdim\naturalfloatwd>\hsize
@@ -415,7 +422,7 @@
% this could happen at the lua end instead
\scratchdimen\dimexpr\wd\floatbox-\naturalfloatwd\relax
\ifdim\scratchdimen<\zeropoint
- \global\setbox\floatbox\hpack spread -\scratchdimen{\hss\box\floatbox\hss}%
+ \global\setbox\floatbox\hpack spread -\scratchdimen{\hss\box\floatbox\hss}%
\fi
%
\ifdim\wd\floatbox>\textwidth % \hsize
@@ -724,9 +731,6 @@
\setuevalue{\e!stop \currentpagecolumns}{\stoppagecolumns}%
\to \everydefinepagecolumns
-\ifdefined \columnwidth \else \newdimen\columnwidth \fi
-\ifdefined \columndistance \else \newdimen\columndistance \fi
-
\def\page_col_pickup_preceding
{\begingroup
\setupoutputroutine[\s!mixedcolumn]%
@@ -795,6 +799,8 @@
%
\columnwidth \d_page_col_column_width
\columndistance \d_page_col_distance
+ \nofcolumns \c_page_col_n_of_columns
+ \textwidth \columnwidth % kind of redundant
%
\nopenalties
%
@@ -830,8 +836,6 @@
\page_col_command_set_vsize
\page_col_command_set_hsize
%
- \nofcolumns\c_page_mix_n_of_columns
- %
\unexpanded\def\page_col_start[##1]%
{\page_col_start_nop}%
%
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-run.lua b/Master/texmf-dist/tex/context/base/mkiv/page-run.lua
index c0a2022b24f..cb8cf03117f 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-run.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-run.lua
@@ -186,3 +186,38 @@ function commands.showlayout(options)
end
+local report = logs.reporter("usage")
+
+function commands.showusage()
+ report("")
+ report("status after shipping out page %s",tex.getcount("realpageno"))
+ report("")
+ report(" filename : %s", status.filename)
+ report(" inputid : %s", status.inputid)
+ report(" linenumber : %s", status.linenumber)
+ report(" input pointer : %s", status.input_ptr)
+ report("")
+ report(" string pointer : %s of %s", status.str_ptr, status.max_strings + status.init_str_ptr)
+ report(" pool size : %s", status.pool_size)
+ report("")
+ report(" node memory usage : %s of %s", status.var_used, status.var_mem_max)
+ report(" token memory usage : %s of %s", status.dyn_used, status.fix_mem_max)
+ report("")
+ report(" cs count : %s of %s", status.cs_count, status.hash_size + status.hash_extra)
+ report("")
+ report(" stack size : %s of %s", status.max_in_stack, status.stack_size)
+ report(" nest size : %s of %s", status.max_nest_stack, status.nest_size)
+ report(" parameter size : %s of %s", status.max_param_stack, status.param_size)
+ report(" buffer size : %s of %s", status.max_buf_stack, status.buf_size)
+ report(" save size : %s of %s", status.max_save_stack, status.save_size)
+ report("")
+ report(" luabytecode bytes : %s in %s registers", status.luabytecode_bytes, status.luabytecodes)
+ report(" luastate bytes : %s of %s", status.luastate_bytes, status.luastate_bytes_max or "unknown")
+ report("")
+ report(" callbacks : %s", status.callbacks)
+ report(" indirect callbacks : %s", status.indirect_callbacks)
+ report(" saved callbacks : %s", status.saved_callbacks)
+ report(" direct callbacks : %s", status.direct_callbacks)
+ report(" function callbacks : %s", status.function_callbacks)
+ report("")
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-run.mkiv b/Master/texmf-dist/tex/context/base/mkiv/page-run.mkiv
index 85da8d9e5fb..d3efe169816 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-run.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-run.mkiv
@@ -206,13 +206,19 @@
\gdef\page_grids_add_to_one_indeed#1%
{\begingroup
\resetvisualizers
- \global\setbox#1\vpack{\backgroundline[layout:one]{\box#1}}%
+ \global\setbox#1\vpack{\noindent\backgroundline[layout:one]{\box#1}}%
\endgroup}
\gdef\page_grids_add_to_mix_indeed#1%
{\begingroup
\resetvisualizers
- \global\setbox#1\vpack{\backgroundline[layout:mix]{\box#1}}%
+ \global\setbox#1\vpack{\noindent\backgroundline[layout:mix]{\box#1}}%
\endgroup}
+%D The next command shows some statistics (we might add more in due time):
+
+\unexpanded\gdef\showusage
+ {\gtoksapp\everyaftershipout{\ctxcommand{showusage()}}%
+ \glet\showusage\relax}
+
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-sid.mkiv b/Master/texmf-dist/tex/context/base/mkiv/page-sid.mkiv
index 8033812447b..e6c1be985d7 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-sid.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-sid.mkiv
@@ -84,6 +84,8 @@
\newcount \c_page_sides_m_of_lines
\newconditional \c_page_sides_delayed
+\newconditional \c_page_sides_check_same_page
+
\newif \iftracesidefloats % public (might change)
%D Defaults:
@@ -399,10 +401,18 @@
{\iftracesidefloats
\begingroup
\c_page_force_strut_depth_trace_mode\plusone
- \forcestrutdepth
+ \ifconditional\c_page_sides_check_same_page
+ \forcestrutdepthplus
+ \else
+ \forcestrutdepth
+ \fi
\endgroup
\else
- \forcestrutdepth
+ \ifconditional\c_page_sides_check_same_page
+ \forcestrutdepthplus
+ \else
+ \forcestrutdepth
+ \fi
\fi
\page_otr_command_set_vsize} % new
@@ -712,7 +722,7 @@
\advance\d_page_sides_progress-\pagetotal
\fi}
-\def\page_sides_analyse_space
+\def\page_sides_analyse_space_stage_one
{\global\settrue\c_page_sides_flag
% \ifdim\pagegoal=\maxdimen
% \pagegoal\textheight % maybe
@@ -751,8 +761,10 @@
% \advance\scratchdimenone -\onepoint (maybe)
\else
\advance\scratchdimentwo -\strutdp
- \fi
- % how about \pagedepth
+ \fi}
+
+\def\page_sides_analyse_space_stage_two
+ {% how about \pagedepth
\ifdim\scratchdimenone>\scratchdimentwo
\global\setfalse\c_page_floats_room
\else
@@ -767,6 +779,22 @@
\global\settrue\c_page_floats_room
\fi}
+\def\page_sides_analyse_space
+ {\page_sides_analyse_space_stage_one
+ \ifconditional\c_page_sides_check_same_page
+ \ifdim\d_spac_prevcontent>\zeropoint
+ \ifdim\dimexpr\scratchdimenone+\d_spac_prevcontent>\scratchdimentwo
+ \clf_pushatsame
+ \setbox\scratchbox\vpack{\clf_popatsame}%
+ \page
+ \box\scratchbox
+ \vskip-\lineskip
+ \page_sides_analyse_space_stage_one
+ \fi
+ \fi
+ \fi
+ \page_sides_analyse_space_stage_two}
+
%D As we have no clear end of one or more paragraphs we only have pre float
%D skips.
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-str.lua b/Master/texmf-dist/tex/context/base/mkiv/page-str.lua
index ebb49a918c2..73f1782d0b6 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-str.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-str.lua
@@ -177,19 +177,21 @@ function streams.synchronize(list) -- this is an experiment !
for i=1,#list do
local name = list[i]
local dana = data[name]
- local slot = dana[m]
- if slot then
- local vbox = vpack_node_list(slot)
- local wd, ht, dp = getwhd(vbox)
- if ht > height then
- height = ht
- end
- if dp > depth then
- depth = dp
- end
- dana[m] = vbox
- if trace_flushing then
- report_streams("slot %s of %a is packed to height %p and depth %p",m,name,ht,dp)
+ if dana then
+ local slot = dana[m]
+ if slot then
+ local vbox = vpack_node_list(slot)
+ local wd, ht, dp = getwhd(vbox)
+ if ht > height then
+ height = ht
+ end
+ if dp > depth then
+ depth = dp
+ end
+ dana[m] = vbox
+ if trace_flushing then
+ report_streams("slot %s of %a is packed to height %p and depth %p",m,name,ht,dp)
+ end
end
end
end
@@ -202,41 +204,43 @@ function streams.synchronize(list) -- this is an experiment !
for i=1,#list do
local name = list[i]
local dana = data[name]
- local vbox = dana[m]
- if vbox then
- local wd, ht, dp = getwhd(vbox)
- local delta_height = height - ht
- local delta_depth = depth - dp
- if delta_height > 0 or delta_depth > 0 then
- if false then
- -- actually we need to add glue and repack
- setwhd(vbox,false,height,depth)
- if trace_flushing then
- report_streams("slot %s of %a with delta (%p,%p) is compensated",m,i,delta_height,delta_depth)
- end
- else
- -- this is not yet ok as we also need to keep an eye on vertical spacing
- -- so we might need to do some splitting or whatever
- local list = getlist(vbox)
- local tail = list and slide_node_list(list)
- local n = 0
- local delta = delta_height -- for tracing
- while delta > 0 do
- -- we need to add some interline penalties
- local line = copy_node_list(getbox("strutbox"))
- setwhd(line,false,strutht,strutdp)
- if tail then
- setlink(tail,line)
+ if dana then
+ local vbox = dana[m]
+ if vbox then
+ local wd, ht, dp = getwhd(vbox)
+ local delta_height = height - ht
+ local delta_depth = depth - dp
+ if delta_height > 0 or delta_depth > 0 then
+ if false then
+ -- actually we need to add glue and repack
+ setwhd(vbox,false,height,depth)
+ if trace_flushing then
+ report_streams("slot %s of %a with delta (%p,%p) is compensated",m,i,delta_height,delta_depth)
+ end
+ else
+ -- this is not yet ok as we also need to keep an eye on vertical spacing
+ -- so we might need to do some splitting or whatever
+ local list = getlist(vbox)
+ local tail = list and slide_node_list(list)
+ local n = 0
+ local delta = delta_height -- for tracing
+ while delta > 0 do
+ -- we need to add some interline penalties
+ local line = copy_node_list(getbox("strutbox"))
+ setwhd(line,false,strutht,strutdp)
+ if tail then
+ setlink(tail,line)
+ end
+ tail = line
+ n = n + 1
+ delta = delta - struthtdp
+ end
+ dana[m] = vpack_node_list(getlist(vbox))
+ setlist(vbox)
+ flush_node(vbox)
+ if trace_flushing then
+ report_streams("slot %s:%s with delta (%p,%p) is compensated by %s lines",m,i,delta_height,delta_depth,n)
end
- tail = line
- n = n + 1
- delta = delta - struthtdp
- end
- dana[m] = vpack_node_list(getlist(vbox))
- setlist(vbox)
- flush_node(vbox)
- if trace_flushing then
- report_streams("slot %s:%s with delta (%p,%p) is compensated by %s lines",m,i,delta_height,delta_depth,n)
end
end
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-txt.mklx b/Master/texmf-dist/tex/context/base/mkiv/page-txt.mklx
new file mode 100644
index 00000000000..b8184e44367
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-txt.mklx
@@ -0,0 +1,969 @@
+% macros=mkvi
+
+%D \module
+%D [ file=page-txt, % copied from main-001,
+%D version=1997.03.31,
+%D title=\CONTEXT\ Page Macros,
+%D subtitle=Texts,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Page Macros / Texts}
+
+\unprotect
+
+\newtoks\toptextcontent \newtoks\leftedgetextcontent
+\newtoks\headertextcontent \newtoks\leftmargintextcontent
+\newtoks\footertextcontent \newtoks\rightmargintextcontent
+\newtoks\bottomtextcontent \newtoks\rightedgetextcontent
+
+\newtoks\texttextcontent
+
+%D \macros
+%D {setuptop, setupheader, setuptext,setupfooter, setupbottom}
+%D
+%D The macros in this module sometimes look a bit more complicated than needed,
+%D which is a direct result of the fact that their ancestors are quite old and
+%D upward compatibility is a must.
+%D
+%D \showsetup{setuptop}
+%D \showsetup{setupheader}
+%D \showsetup{setuptext}
+%D \showsetup{setupfooter}
+%D \showsetup{setupbottom}
+
+\installcorenamespace{layouttexts}
+\installcorenamespace{layouttextsline}
+\installcorenamespace{layouttextsreset}
+\installcorenamespace{layouttextssynchronize}
+\installcorenamespace{layouttextstrut}
+\installcorenamespace{layouttextspecial}
+\installcorenamespace{layouttextcontent}
+
+\installcommandhandler \??layouttexts {layoutelement} \??layouttexts
+
+% \appendtoks
+% \resetlayoutelementparameter\c!lefttext % resolves better
+% \resetlayoutelementparameter\c!middletext
+% \resetlayoutelementparameter\c!righttext
+% \to \everydefinelayoutelement
+
+\definelayoutelement[\v!top ]
+\definelayoutelement[\v!header]
+\definelayoutelement[\v!text ]
+\definelayoutelement[\v!footer]
+\definelayoutelement[\v!bottom]
+
+\definelayoutelement[\v!top :\v!text] [\v!top ][\c!lefttext=,\c!middletext=,\c!righttext=]
+\definelayoutelement[\v!header:\v!text] [\v!header][\c!lefttext=,\c!middletext=,\c!righttext=]
+\definelayoutelement[\v!text :\v!text] [\v!text ][\c!lefttext=,\c!middletext=,\c!righttext=]
+\definelayoutelement[\v!footer:\v!text] [\v!footer][\c!lefttext=,\c!middletext=,\c!righttext=]
+\definelayoutelement[\v!bottom:\v!text] [\v!bottom][\c!lefttext=,\c!middletext=,\c!righttext=]
+
+\definelayoutelement[\v!top :\v!margin][\v!top ][\c!lefttext=,\c!middletext=,\c!righttext=]
+\definelayoutelement[\v!header:\v!margin][\v!header][\c!lefttext=,\c!middletext=,\c!righttext=]
+\definelayoutelement[\v!text :\v!margin][\v!text ][\c!lefttext=,\c!middletext=,\c!righttext=]
+\definelayoutelement[\v!footer:\v!margin][\v!footer][\c!lefttext=,\c!middletext=,\c!righttext=]
+\definelayoutelement[\v!bottom:\v!margin][\v!bottom][\c!lefttext=,\c!middletext=,\c!righttext=]
+
+\definelayoutelement[\v!top :\v!edge] [\v!top ][\c!lefttext=,\c!middletext=,\c!righttext=]
+\definelayoutelement[\v!header:\v!edge] [\v!header][\c!lefttext=,\c!middletext=,\c!righttext=]
+\definelayoutelement[\v!text :\v!edge] [\v!text ][\c!lefttext=,\c!middletext=,\c!righttext=]
+\definelayoutelement[\v!footer:\v!edge] [\v!footer][\c!lefttext=,\c!middletext=,\c!righttext=]
+\definelayoutelement[\v!bottom:\v!edge] [\v!bottom][\c!lefttext=,\c!middletext=,\c!righttext=]
+
+\unexpanded\def\setuplayouttext
+ {\dotripleempty\page_layouts_setup_text}
+
+\def\page_layouts_setup_text[#vertical][#horizontal][#settings]%
+ {\ifthirdargument
+ \setuplayoutelement[#vertical:#horizontal][#settings]%
+ \else
+ \setuplayoutelement[#vertical][#horizontal]%
+ \fi}
+
+\appendtoks
+ \ifx\currentlayoutelement\empty\else
+ \page_layouts_synchronize_element\currentlayoutelement % brr, can be vertical:horizontal
+ \fi
+\to \everysetuplayoutelement
+
+\def\page_layouts_reset_element_status#vertical%
+ {\expandafter\normalgdef\csname\??layouttextsreset#vertical\endcsname{\page_layouts_set_element_status_normal#vertical}}
+
+\def\page_layouts_set_element_status_normal#vertical%
+ {\expandafter\glet\csname\namedlayoutelementhash#vertical\c!state\endcsname\v!normal
+ \expandafter\glet\csname\??layouttextsreset#vertical\endcsname\relax
+ \page_layouts_synchronize_element{#vertical}}
+
+\def\page_layouts_synchronize_element#vertical%
+ {\xdef\previoustextstate{\csname\??layouttextssynchronize#vertical\endcsname}% can be a let
+ \edef\currenttextstate {\namedlayoutelementparameter{#vertical}\c!state}%
+ %\writestatus{>>}{[#vertical:\currenttextstate/\previoustextstate]}%
+ \ifx\currenttextstate\previoustextstate \else
+ \page_layouts_synchronize_element_indeed{#vertical}%
+ \fi}
+
+\def\page_layouts_synchronize_element_indeed#vertical%
+ {\ifx\currenttextstate \v!high \calculatevsizes\page_backgrounds_recalculate \orelse
+ \ifx\previoustextstate\v!high \calculatevsizes\page_backgrounds_recalculate \orelse
+ \ifx\currenttextstate \v!none \calculatevsizes\page_backgrounds_recalculate \orelse
+ \ifx\previoustextstate\v!none \calculatevsizes\page_backgrounds_recalculate \fi
+ \letgvalue{\??layouttextssynchronize#vertical}\currenttextstate}
+
+\unexpanded\def\setuptop {\dotripleempty\page_layouts_setup_text[\v!top ]}
+\unexpanded\def\setupheader{\dotripleempty\page_layouts_setup_text[\v!header]}
+\unexpanded\def\setuptext {\dotripleempty\page_layouts_setup_text[\v!text ]}
+\unexpanded\def\setupfooter{\dotripleempty\page_layouts_setup_text[\v!footer]}
+\unexpanded\def\setupbottom{\dotripleempty\page_layouts_setup_text[\v!bottom]}
+
+%D We inherit some settings:
+
+\setuplayoutelement
+ [ \c!leftstyle=\layoutelementparameter\c!style,
+ \c!middlestyle=\layoutelementparameter\c!style,
+ \c!rightstyle=\layoutelementparameter\c!style,
+ \c!leftcolor=\layoutelementparameter\c!color,
+ \c!middlecolor=\layoutelementparameter\c!color,
+ \c!rightcolor=\layoutelementparameter\c!color,
+ \c!leftwidth=\layoutelementparameter\c!width,
+ \c!middlewidth=\layoutelementparameter\c!width,
+ \c!rightwidth=\layoutelementparameter\c!width]
+
+%D \macros
+%D {noheaderandfooterlines,notopandbottomlines}
+%D
+%D Although not really needed, the following shortcuts sometimes come in handy.
+%D
+%D \showsetup{noheaderandfooterlines}
+%D \showsetup{notopandbottomlines}
+
+\unexpanded\def\noheaderandfooterlines
+ {\setuplayoutelement[\v!header][\c!state=\v!empty]%
+ \setuplayoutelement[\v!footer][\c!state=\v!empty]}
+
+\unexpanded\def\notopandbottomlines
+ {\setuplayoutelement[\v!top ][\c!state=\v!empty]%
+ \setuplayoutelement[\v!bottom][\c!state=\v!empty]}
+
+%D \macros
+%D {setuptoptexts,setupheadertexts,setuptexttexts,setupfootertexts,setupbottomtexts}
+%D
+%D The next macros take one or more arguments. The exact setup depends on the number
+%D of arguments. Although not that intuitive, the current scheme evolved out of the
+%D original. When margin and edge texts as well as middle texts showed up, the
+%D current odd|/|even scheme surfaced.
+%D
+%D \showsetup{setuptoptexts}
+%D \showsetup{setupheadertexts}
+%D \showsetup{setuptexttexts}
+%D \showsetup{setupfootertexts}
+%D \showsetup{setupbottomtexts}
+%D
+%D Only the following have checking for pagenumber, date and mark built in, so when
+%D someone uses the key|/|value interface these things have to be set explicitly as
+%D part of the text.
+
+\unexpanded\def\setuptoptexts {\dosixtupleempty\page_layouts_setup_texts[\v!top ]}
+\unexpanded\def\setupheadertexts{\dosixtupleempty\page_layouts_setup_texts[\v!header]}
+\unexpanded\def\setuptexttexts {\dosixtupleempty\page_layouts_setup_texts[\v!text ]}
+\unexpanded\def\setupfootertexts{\dosixtupleempty\page_layouts_setup_texts[\v!footer]}
+\unexpanded\def\setupbottomtexts{\dosixtupleempty\page_layouts_setup_texts[\v!bottom]}
+
+\unexpanded\def\page_layouts_setup_text_six[#vertical][#horizontal][#a][#b][#c][#d]%
+ {\edef\currentlayoutelement{#vertical:#horizontal}%
+ \setlayoutelementparameter\c!lefttext {\page_layouts_process_element_double{#a}{#d}}%
+ \setlayoutelementparameter\c!righttext{\page_layouts_process_element_double{#b}{#c}}}
+
+\unexpanded\def\page_layouts_setup_text_five[#vertical][#horizontal][#a][#b][#c][#d]%
+ {\edef\currentlayoutelement{#vertical:\v!text}%
+ \setlayoutelementparameter\c!lefttext {\page_layouts_process_element_double{#horizontal}{#c}}%
+ \setlayoutelementparameter\c!righttext{\page_layouts_process_element_double{#a}{#b}}}
+
+\unexpanded\def\page_layouts_setup_text_four[#vertical][#horizontal][#a][#b][#c][#d]%
+ {\edef\currentlayoutelement{#vertical:#horizontal}%
+ \setlayoutelementparameter\c!lefttext {\page_layouts_process_element_single{#a}}%
+ \setlayoutelementparameter\c!righttext{\page_layouts_process_element_single{#b}}}
+
+\unexpanded\def\page_layouts_setup_text_three[#vertical][#horizontal][#a][#b][#c][#d]%
+ {\edef\currentlayoutelement{#vertical:\v!text}%
+ \setlayoutelementparameter\c!lefttext {\page_layouts_process_element_single{#horizontal}}%
+ \setlayoutelementparameter\c!righttext{\page_layouts_process_element_single{#a}}}
+
+\unexpanded\def\page_layouts_setup_text_two[#vertical][#horizontal][#a][#b][#c][#d]%
+ {\edef\currentlayoutelement{#vertical:\v!text}%
+ \resetlayoutelementparameter\c!lefttext
+ \resetlayoutelementparameter\c!righttext
+ \setlayoutelementparameter \c!middletext{\page_layouts_process_element_single{#horizontal}}}
+
+\unexpanded\def\page_layouts_setup_text_one[#vertical][#horizontal][#a][#b][#c][#d]%
+ {\edef\currentlayoutelement{#vertical:\v!text}%
+ \resetlayoutelementparameter\c!lefttext
+ \resetlayoutelementparameter\c!righttext
+ \resetlayoutelementparameter\c!middletext
+ \edef\currentlayoutelement{#vertical:\v!margin}%
+ \resetlayoutelementparameter\c!lefttext
+ \resetlayoutelementparameter\c!righttext
+ \resetlayoutelementparameter\c!middletext
+ \edef\currentlayoutelement{#vertical:\v!edge}%
+ \resetlayoutelementparameter\c!lefttext
+ \resetlayoutelementparameter\c!righttext
+ \resetlayoutelementparameter\c!middletext}
+
+\unexpanded\def\page_layouts_setup_texts
+ {\ifsixthargument \expandafter\page_layouts_setup_text_six \orelse
+ \iffifthargument \expandafter\page_layouts_setup_text_five \orelse
+ \iffourthargument\expandafter\page_layouts_setup_text_four \orelse
+ \ifthirdargument \expandafter\page_layouts_setup_text_three\orelse
+ \ifsecondargument\expandafter\page_layouts_setup_text_two \else
+ \expandafter\page_layouts_setup_text_one \fi}
+
+%D Left and right texts are swapped on odd and even pages, but only when double
+%D sided typesetting is enabled.
+
+\setvalue{\??layouttextstrut\v!yes}{\setstrut\strut} % maybe more variants
+
+\let\m_page_layouts_element_content\empty
+
+\unexpanded\def\page_layouts_process_element_single#content%
+ {\edef\m_page_layouts_element_content{\detokenize{#content}}% so no \v!xxx
+ \ifcsname\??layouttextspecial\m_page_layouts_element_content\endcsname
+ \lastnamedcs
+ \else
+ \doifelsemarking\m_page_layouts_element_content
+ {\getmarking[\m_page_layouts_element_content][\v!first]}%
+ {#content}%
+ \fi}
+
+\unexpanded\def\page_layouts_process_element_double#first#second%
+ {\doifelseoddpage
+ {\page_layouts_process_element_single{#first}}
+ {\page_layouts_process_element_single{#second}}}
+
+\unexpanded\def\page_layouts_process_element_indeed#style#color#width%
+ {\begingroup
+ \uselayoutelementstyleandcolor#style#color%
+ \begincsname\??layouttextstrut\layoutelementparameter\c!strut\endcsname
+ \ignorecrlf
+ \edef\currentlayoutelementwidth{\layoutelementparameter#width}%
+ \ifx\currentlayoutelementwidth\empty\else
+ \expandafter\page_layouts_process_element_limited
+ \fi\p_text
+ \endgroup}
+
+\def\page_layouts_process_element_limited#content% are the {}{}{} still needed?
+% {\limitatetext{#content{}{}{}}\currentlayoutelementwidth\unknown}
+ {\limitated
+ left \currentlayoutelementwidth
+ text {#content}
+ sentinel {\unknown}
+ \relax}
+
+\setvalue{\??layouttextspecial\v!pagenumber}{\page_layouts_place_page_number}
+\setvalue{\??layouttextspecial\v!date }{\currentdate}
+
+%D When specified, the texts are automatically limited in length.
+
+\appendtoks \page_layouts_place_text_line\v!top \topheight \to \toptextcontent
+\appendtoks \page_layouts_place_text_line\v!header\headerheight \to \headertextcontent
+\appendtoks \page_layouts_place_text_line\v!text \textheight \to \texttextcontent
+\appendtoks \page_layouts_place_text_line\v!footer\footerheight \to \footertextcontent
+\appendtoks \page_layouts_place_text_line\v!bottom\bottomheight \to \bottomtextcontent
+
+%D Texts can be disabled, moved up and ignored, depending in the \type {status}
+%D variable. This is handled by the next couple of macros.
+
+\newcount\c_page_layouts_element_state_n
+
+\def\page_layouts_set_element_status#vertical%
+ {\c_page_layouts_element_state_n=0\namedlayoutelementparameter#vertical\c!n\relax
+ \ifcase\c_page_layouts_element_state_n
+ \edef\textlinestatus{\namedlayoutelementparameter#vertical\c!state}%
+ \else
+ \setxvalue{\namedlayoutelementhash#vertical\c!n}{\the\numexpr\c_page_layouts_element_state_n+\minusone}%
+ \let\textlinestatus\v!stop
+ \fi}
+
+\appendtoks
+ \doifinset\v!header\floatspecification{\setxvalue{\namedlayoutelementhash\v!header\c!n}{1}}%
+ \doifinset\v!footer\floatspecification{\setxvalue{\namedlayoutelementhash\v!footer\c!n}{1}}%
+\to \everybeforeflushedpagefloat
+
+\unexpanded\def\page_layouts_place_text_line#vertical%
+ {\page_layouts_set_element_status#vertical\relax
+ \ifcsname\??layouttextsline\textlinestatus\endcsname
+ \expandafter\lastnamedcs
+ \else
+ \expandafter\page_layouts_place_text_line_unknown
+ \fi#vertical}
+
+\unexpanded\def\doifelselayouttextline#vertical% shown or not
+ {\edef\currentlayoutelementstate{\namedlayoutelementparameter{#vertical}\c!state}%
+ \ifx\currentlayoutelementstate\v!normal
+ \expandafter\firstoftwoarguments
+ \orelse\ifx\currentlayoutelementstate\v!start
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\unexpanded\def\doifelselayoutsomeline#vertical% present or not
+ {\edef\currentlayoutelementstate{\namedlayoutelementparameter{#vertical}\c!state}%
+ \ifx\currentlayoutelementstate\v!none
+ \expandafter\secondoftwoarguments
+ \orelse\ifx\currentlayoutelementstate\v!high
+ \expandafter\secondoftwoarguments
+ \else
+ \expandafter\firstoftwoarguments
+ \fi}
+
+\let\doiflayouttextlineelse\doifelselayouttextline
+\let\doiflayoutsomelineelse\doifelselayoutsomeline
+
+\newconditional\resyncaftertextline
+
+\setvalue{\??layouttextsline\v!normal}{\page_layouts_place_text_line_indeed}
+\setvalue{\??layouttextsline\empty }{\page_layouts_place_text_line_indeed}
+
+\letvalue{\??layouttextsline\v!none}\gobbletwoarguments
+\letvalue{\??layouttextsline\v!stop}\gobbletwoarguments
+
+\setvalue{\??layouttextsline\v!high}#vertical#height%
+ {\global\settrue\resyncaftertextline
+ \page_layouts_reset_element_status#vertical}
+
+\setvalue{\??layouttextsline\v!empty}#vertical#height%
+ {\page_layouts_reset_element_status#vertical}
+
+\setvalue{\??layouttextsline\v!start}#vertical#height%
+ {\page_layouts_reset_element_status#vertical%
+ \page_layouts_place_text_line_indeed#vertical#height}
+
+\setvalue{\??layouttextsline\v!nomarking}#vertical#height%
+ {\bgroup
+ \page_layouts_reset_element_status#vertical%
+ \settrue\inhibitgetmarking
+ \page_layouts_place_text_line_indeed#vertical#height%
+ \egroup}
+
+% \setupheadertexts [11]
+% \definetext [title] [header] [aa]
+% \setupheadertexts [11] [22]
+% \definetext [title] [header] [aa] [bb]
+% \setupheadertexts [text] [11] [22]
+% \definetext [title] [header] [text] [aa] [bb]
+% \setupheadertexts [11] [22] [33] [44]
+% \definetext [title] [header] [aa] [bb] [cc] [dd]
+% \setupheadertexts [text] [11] [22] [33] [44]
+% \definetext [title] [header] [text] [aa] [bb] [cc] [dd]
+
+\def\page_layouts_place_text_line_unknown#vertical#height%
+ {\global\settrue\resyncaftertextline
+ \begingroup % new
+ \page_layouts_reset_element_status#vertical%
+ \begincsname\namedlayoutelementhash{#vertical}\textlinestatus\endcsname
+ \begincsname\namedlayoutelementhash{#vertical:\v!text}\textlinestatus\endcsname
+ \begincsname\namedlayoutelementhash{#vertical:\v!margin}\textlinestatus\endcsname
+ \begincsname\namedlayoutelementhash{#vertical:\v!edge}\textlinestatus\endcsname
+ \page_layouts_place_text_line_indeed#vertical#height%
+ \endgroup}
+
+\letvalue{\??layouttextsline\s!unknown}\page_layouts_place_text_line_unknown
+
+%D The following macro has to be called after a page is flushed.
+
+\unexpanded\def\resetlayouttextlines % public
+ {\begincsname\??layouttextsreset\v!top \endcsname
+ \begincsname\??layouttextsreset\v!header\endcsname
+ \begincsname\??layouttextsreset\v!text \endcsname
+ \begincsname\??layouttextsreset\v!footer\endcsname
+ \begincsname\??layouttextsreset\v!bottom\endcsname
+ \ifconditional\resyncaftertextline
+ \calculateglobalvsizes
+ \page_backgrounds_recalculate
+ \global\setfalse\resyncaftertextline
+ \fi}
+
+\def\getspecificlayouttext#vertical#horizontal#what%
+ {\begincsname\namedlayoutelementhash{#vertical:#horizontal}#what\endcsname}
+
+% \settext[header][text][middle][xxx][yyy]
+
+\unexpanded\def\settextcontent
+ {\doquintupleempty\page_layouts_set_text_content}
+
+\def\page_layouts_set_text_content[#vertical][#horizontal][#one][#two][#three]% header text middle text/text
+ {\iffifthargument
+ \setvalue{\namedlayoutelementhash{#vertical:#horizontal}\begincsname\??layouttextcontent\v!text:#one\endcsname\c!middletext}%
+ {\page_layouts_process_element_double{#two}{#three}}%
+ \orelse\iffourthargument
+ \setvalue{\namedlayoutelementhash{#vertical:#horizontal}\begincsname\??layouttextcontent\v!text:#one\endcsname\c!middletext}%
+ {\page_layouts_process_element_double{#two}{#two}}%
+ \orelse\ifthirdargument
+ \setvalue{\namedlayoutelementhash{#vertical:#horizontal}\c!middletext}%
+ {\page_layouts_process_element_double{#one}{#one}}%
+ \fi}
+
+\let\currentlayoutelement\relax
+
+\unexpanded\def\resettextcontent
+ {\dotripleempty\page_layouts_reset_text_content}
+
+\def\page_layouts_reset_text_content[#vertical][#horizontal][#tag]% header text middle
+ {\edef\currentlayoutelement{#vertical:#horizontal}%
+ \ifthirdargument
+ \letvalueempty{\layoutelementhash\begincsname\??layouttextcontent\v!text:#tag\endcsname\c!middletext}%
+ \orelse\ifsecondargument
+ \resetlayoutelementparameter\c!lefttext
+ \resetlayoutelementparameter\c!middletext
+ \resetlayoutelementparameter\c!righttext
+ \fi}
+
+\letvalue{\??layouttextcontent\v!text:\c!middle}\c!middletext
+\letvalue{\??layouttextcontent\v!text:\c!left }\c!lefttext
+\letvalue{\??layouttextcontent\v!text:\c!right }\c!righttext
+
+%D The placement of a whole line is handled by the next two macros. These are hooked
+%D into the general purpose token list registers mentioned before.
+
+\let\currentlayouttextline\relax
+
+\def\page_layouts_place_text_line_indeed#vertical#height%
+ {\let\currentlayouttextline#vertical%
+ \ifdim#height>\zeropoint\relax % prevents pagenumbers when zero height
+ \page_layouts_place_text_line_left_or_right{#height}%
+ \fi}
+
+\def\page_layouts_place_text_line_left_or_right#height%
+ {\goleftonpage
+ \setbox\b_page_layouts_element\vbox to #height
+ {\vsize#height\relax
+ %\hsize\zeropoint % hack so that e.g. after=\hairline gives predictable results
+ \hsize\totaltextwidth
+ \normalbaselines
+ \let\\\ignoredlinebreak
+ \let\crlf\ignoredlinebreak
+ \namedlayoutelementparameter\currentlayouttextline\c!before
+ \doifbothsidesoverruled
+ \page_layouts_place_text_line_right
+ \page_layouts_place_text_line_right
+ \page_layouts_place_text_line_left
+ \namedlayoutelementparameter\currentlayouttextline\c!after
+ \vkern\zeropoint}% keep the \dp, beware of \vtops, never change this!
+ \dp\b_page_layouts_element\zeropoint
+ \box\b_page_layouts_element
+ \vkern-#height\relax}
+
+\let\page_layouts_place_extra_text_left \empty % historic
+\let\page_layouts_place_extra_text_right\empty % historic
+
+\def\page_layouts_place_text_line_right
+ {\hpack
+ {\ifdim\leftedgewidth>\zeropoint
+ \page_layouts_left_edge_element\c!lefttext\c!leftstyle\c!leftcolor\c!leftwidth
+ \fi
+ \ifdim\leftmarginwidth>\zeropoint
+ \page_layouts_left_margin_element\c!lefttext\c!leftstyle\c!leftcolor\c!leftwidth\zerocount
+ \fi
+ \ifdim\makeupwidth>\zeropoint
+ \page_layouts_text_body_element_l_m_r_e
+ \fi
+ \ifdim\rightmarginwidth>\zeropoint
+ \page_layouts_right_margin_element\c!righttext\c!rightstyle\c!rightcolor\c!rightwidth\plusone
+ \fi
+ \ifdim\rightedgewidth>\zeropoint
+ \page_layouts_right_edge_element\c!righttext\c!rightstyle\c!rightcolor\c!rightwidth
+ \fi}}
+
+\def\page_layouts_place_text_line_left
+ {\hpack
+ {\ifdim\leftedgewidth>\zeropoint
+ \page_layouts_left_edge_element\c!righttext\c!rightstyle\c!rightcolor\c!rightwidth
+ \fi
+ \ifdim\leftmarginwidth>\zeropoint
+ \page_layouts_left_margin_element\c!righttext\c!rightstyle\c!rightcolor\c!rightwidth\zerocount
+ \fi
+ \ifdim\makeupwidth>\zeropoint
+ \page_layouts_text_body_element_e_r_m_l
+ \fi
+ \ifdim\rightmarginwidth>\zeropoint
+ \page_layouts_right_margin_element\c!lefttext\c!leftstyle\c!leftcolor\c!leftwidth\plusone
+ \fi
+ \ifdim\rightedgewidth>\zeropoint
+ \page_layouts_right_edge_element\c!lefttext\c!leftstyle\c!leftcolor\c!leftwidth
+ \fi}}
+
+\def\page_layouts_left_edge_element_indeed#text#style#color#width%
+ {\letfromlayoutelementparameter\p_text#text%
+ \ifx\p_text\empty
+ \kern\leftedgewidth
+ \else
+ \hbox to \leftedgewidth\bgroup
+ \hss
+ \page_layouts_process_element_indeed#style#color#width%
+ \egroup
+ \fi}
+
+\def\page_layouts_left_edge_element#text#style#color#width%
+ {\edef\currentlayoutelement{\currentlayouttextline:\v!edge}%
+ \page_layouts_place_element_indeed\leftedgewidth
+ {\page_layouts_left_edge_element_indeed#text#style#color#width}%
+ \kern\leftedgedistance}
+
+\def\page_layouts_right_edge_element_indeed#text#style#color#width%
+ {\letfromlayoutelementparameter\p_text#text%
+ \ifx\p_text\empty
+ \kern\rightedgewidth
+ \else
+ \hbox to \rightedgewidth\bgroup
+ \page_layouts_process_element_indeed#style#color#width%
+ \hss
+ \egroup
+ \fi}
+
+\def\page_layouts_right_edge_element#text#style#color#width%
+ {\edef\currentlayoutelement{\currentlayouttextline:\v!edge}%
+ \kern\rightedgedistance
+ \page_layouts_place_element_indeed\rightedgewidth
+ {\page_layouts_right_edge_element_indeed#text#style#color#width}}
+
+% margin needs checking!
+
+\def\page_layouts_left_margin_element_indeed#text#style#color#width#margintoo%
+ {\letfromlayoutelementparameter\p_text#text%
+ \ifx\p_text\empty
+ \kern\leftmarginwidth
+ \else
+ \hbox to \leftmarginwidth\bgroup
+ \hss
+ \page_layouts_process_element_indeed#style#color#width%
+ \egroup
+ \fi
+ \ifcase#margintoo\or
+ \letfromlayoutelementparameter\p_text\c!margintext
+ \ifx\p_text\empty\else
+ \kern-\leftmarginwidth
+ \hbox to \leftmarginwidth\bgroup
+ \hss
+ \p_text % styling ?
+ \egroup
+ \fi
+ \fi}
+
+\def\page_layouts_left_margin_element#text#style#color#width#margintoo%
+ {\edef\currentlayoutelement{\currentlayouttextline:\v!margin}%
+ \page_layouts_place_element_indeed\leftmarginwidth
+ {\page_layouts_left_margin_element_indeed#text#style#color#width#margintoo}%
+ \kern\leftmargindistance}
+
+\def\page_layouts_right_margin_element_indeed#text#style#color#width#margintoo%
+ {\letfromlayoutelementparameter\p_text#text%
+ \ifx\p_text\empty
+ \kern\rightmarginwidth
+ \else
+ \hbox to \rightmarginwidth\bgroup
+ \page_layouts_process_element_indeed#style#color#width%
+ \hss
+ \egroup
+ \fi
+ \ifcase#margintoo\or
+ \letfromlayoutelementparameter\p_text\c!margintext
+ \ifx\p_text\empty\else
+ \kern-\rightmarginwidth
+ \hbox to \rightmarginwidth\bgroup
+ \p_text % ? styling
+ \hss
+ \egroup
+ \fi
+ \fi}
+
+\def\page_layouts_right_margin_element#text#style#color#width#margintoo%
+ {\edef\currentlayoutelement{\currentlayouttextline:\v!margin}%
+ \kern\rightmargindistance
+ \page_layouts_place_element_indeed\rightmarginwidth
+ {\page_layouts_right_margin_element_indeed#text#style#color#width#margintoo}}
+
+\def\page_layouts_text_body_element_indeed_l_m_r_e
+ {\letfromlayoutelementparameter\p_text\c!lefttext
+ \ifx\p_text\empty
+ \ifx\page_layouts_place_extra_text_left\empty\else
+ \hbox to \makeupwidth\bgroup
+ \page_layouts_place_extra_text_left
+ \hss
+ \egroup
+ \kern-\makeupwidth
+ \fi
+ \else
+ \hbox to \makeupwidth\bgroup
+ \page_layouts_place_extra_text_left
+ \page_layouts_process_element_indeed\c!leftstyle\c!leftcolor\c!leftwidth
+ \hss
+ \egroup
+ \kern-\makeupwidth
+ \fi
+ \letfromlayoutelementparameter\p_text\c!middletext
+ \ifx\p_text\empty\else
+ \hbox to \makeupwidth\bgroup
+ \hss
+ \page_layouts_process_element_indeed\c!middlestyle\c!middlecolor\c!middlewidth
+ \hss
+ \egroup
+ \kern-\makeupwidth
+ \fi
+ \letfromlayoutelementparameter\p_text\c!righttext
+ \ifx\p_text\empty
+ \kern\makeupwidth
+ \else
+ \hbox to \makeupwidth\bgroup
+ \hss
+ \page_layouts_process_element_indeed\c!rightstyle\c!rightcolor\c!rightwidth
+ \egroup
+ \fi}
+
+\def\page_layouts_text_body_element_indeed_e_r_m_l
+ {\letfromlayoutelementparameter\p_text\c!righttext
+ \ifx\p_text\empty\else
+ \hbox to \makeupwidth\bgroup
+ \page_layouts_process_element_indeed\c!rightstyle\c!rightcolor\c!rightwidth
+ \hss
+ \egroup
+ \kern-\makeupwidth
+ \fi
+ \letfromlayoutelementparameter\p_text\c!middletext
+ \ifx\p_text\empty\else
+ \hbox to \makeupwidth\bgroup
+ \hss
+ \page_layouts_process_element_indeed\c!middlestyle\c!middlecolor\c!middlewidth
+ \hss
+ \egroup
+ \kern-\makeupwidth
+ \fi
+ \letfromlayoutelementparameter\p_text\c!lefttext
+ \ifx\p_text\empty
+ \ifx\page_layouts_place_extra_text_right\empty
+ \kern\makeupwidth
+ \else
+ \hbox to \makeupwidth\bgroup
+ \hss
+ \page_layouts_place_extra_text_right
+ \egroup
+ \fi
+ \else
+ \hbox to \makeupwidth\bgroup
+ \hss
+ \page_layouts_process_element_indeed\c!leftstyle\c!leftcolor\c!leftwidth
+ \page_layouts_place_extra_text_right
+ \egroup
+ \fi}
+
+\def\page_layouts_text_body_element_l_m_r_e
+ {\edef\currentlayoutelement{\currentlayouttextline:\v!text}%
+ \page_layouts_place_element_indeed\makeupwidth\page_layouts_text_body_element_indeed_l_m_r_e}
+
+\def\page_layouts_text_body_element_e_r_m_l
+ {\edef\currentlayoutelement{\currentlayouttextline:\v!text}%
+ \page_layouts_place_element_indeed\makeupwidth\page_layouts_text_body_element_indeed_e_r_m_l}
+
+\def\page_layouts_place_element_indeed#width#content%
+ {\vbox % to \vsize
+ {\hsize#width\relax
+ \layoutelementparameter\c!before
+ \setlayoutcomponentattribute\currentlayoutelement
+ \hbox \layoutcomponentboxattribute to #width{#content}%
+ \layoutelementparameter\c!after}}
+
+%D Although it is far better to use backgrounds for this purpose, one can add a rule
+%D in the following way. This method makes the rules disappear in case of an empty
+%D text line. Consider this a feature.
+%D
+%D \starttyping
+%D \setupheadertexts[left][right]
+%D
+%D \setupheader[text][after=\hrule,style=bold]
+%D
+%D \starttext
+%D \input tufte \page
+%D \setupheader[state=empty]
+%D \input tufte \page
+%D \stoptext
+%D \stoptyping
+
+%D This code will move to \type {page-flt.tex}.
+
+\appendtoks \placerightmarginblock \kern-\rightmarginwidth \to \rightmargintextcontent
+\appendtoks \placeleftmarginblock \kern-\leftmarginwidth \to \leftmargintextcontent
+
+%D \macros
+%D {definetext}
+%D
+%D Some macros ago, we implemented the \type {status} option \type {unknown}. This
+%D one is used to take care of symbolic texts handlers.
+%D
+%D \showsetup{definetext}
+%D
+%D The next example demonstrates how we can use this mechanism to provide page
+%D (event) dependent text lines.
+%D
+%D \starttyping
+%D \definetext[chapter][footer][pagenumber]
+%D \setuphead[chapter][header=high,footer=chapter]
+%D \setupheadertexts[pagenumber]
+%D \setupfootertexts[left][right]
+%D \chapter{eerste} \dorecurse{20}{\input tufte \relax}
+%D \chapter{tweede} \dorecurse{20}{\input tufte \relax}
+%D \stoptyping
+
+\unexpanded\def\definetext
+ {\doseventupleempty\page_layouts_define_text}
+
+\def\page_layouts_define_text[#tag][#vertical][#horizontal][#a][#b][#c][#d]%
+ {\ifseventhargument
+ \setvalue{\namedlayoutelementhash{#vertical:#horizontal}#tag}{\page_layouts_setup_text_six [#vertical][#horizontal][#a][#b][#c][#d]}%
+ \orelse\ifsixthargument
+ \setvalue{\namedlayoutelementhash {#vertical}#tag}{\page_layouts_setup_text_five [#vertical][#horizontal][#a][#b][#c][]}%
+ \orelse\iffifthargument
+ \setvalue{\namedlayoutelementhash{#vertical:#horizontal}#tag}{\page_layouts_setup_text_four [#vertical][#horizontal][#a][#b][][]}%
+ \orelse\iffourthargument
+ \setvalue{\namedlayoutelementhash {#vertical}#tag}{\page_layouts_setup_text_three[#vertical][#horizontal][#a][][][]}%
+ \else
+ \setvalue{\namedlayoutelementhash {#vertical}#tag}{\page_layouts_setup_text_two [#vertical][#horizontal][][][][]}%
+ \fi}
+
+%D A few more page breakers:
+
+\installpagebreakmethod \v!empty
+ {\page_otr_flush_all_floats
+ \page_otr_command_next_page
+ \doifnot{\namedlayoutelementparameter\v!header\c!state}\v!stop{\setuplayoutelement[\v!header][\c!state=\v!empty]}%
+ \doifnot{\namedlayoutelementparameter\v!footer\c!state}\v!stop{\setuplayoutelement[\v!footer][\c!state=\v!empty]}%
+ \page_otr_insert_dummy_page}
+
+\installpagebreakmethod \v!header
+ {\doifnot{\namedlayoutelementparameter\v!header\c!state}\v!stop{\setuplayoutelement[\v!header][\c!state=\v!empty]}}
+
+\installpagebreakmethod \v!footer
+ {\doifnot{\namedlayoutelementparameter\v!footer\c!state}\v!stop{\setuplayoutelement[\v!footer][\c!state=\v!empty]}}
+
+%D While the header and footer lines are moved away from the main text, the top and
+%D bottom lines are centered.
+
+\setuplayoutelement[\v!top ][\c!state=\v!normal,\c!n=0,\c!before=\vss,\c!after=\vss,\c!strut=]
+\setuplayoutelement[\v!header][\c!state=\v!normal,\c!n=0,\c!before=, \c!after=\vss,\c!strut=\v!yes]
+\setuplayoutelement[\v!text ][\c!state=\v!normal,\c!n=0,\c!before=\vss,\c!after=\vss,\c!strut=]
+\setuplayoutelement[\v!footer][\c!state=\v!normal,\c!n=0,\c!before=\vss,\c!after=, \c!strut=\v!yes]
+\setuplayoutelement[\v!bottom][\c!state=\v!normal,\c!n=0,\c!before=\vss,\c!after=\vss,\c!strut=]
+
+%D Moved here from strc-pag:
+%D
+%D We reset a previous location but only when it has a pagenumber associated. This
+%D is a rather messy test but better than the MkII way where we use states and keep
+%D settings.
+
+\let\m_page_layouts_page_number_location \relax
+\let\m_page_layouts_page_number_location_v\relax
+\let\m_page_layouts_page_number_location_h\relax
+\let\m_page_layouts_page_number_location_x\relax
+
+\def\page_layouts_place_page_number % also elsewhere .. beware, not \unexpanded else
+ {\strc_pagenumbers_place_location} % test below fails
+
+\def\page_layouts_reset_page_number_location
+ {\ifx\m_page_layouts_page_number_location_v\relax\else
+ \edef\currentlayoutelement{\m_page_layouts_page_number_location_v:\m_page_layouts_page_number_location_h}%
+ \edef\page_layouts_previous_page_number_locator{\detokenizedlayoutelementparameter\m_page_layouts_page_number_location_x}%
+ \doif{\meaning\page_layouts_previous_page_number_locator}{\meaning\page_layouts_place_page_number}
+ {\resetlayoutelementparameter\m_page_layouts_page_number_location_x}%
+ \fi}
+
+\def\page_layouts_set_page_number_location
+ {\edef\currentlayoutelement{\m_page_layouts_page_number_location_v:\m_page_layouts_page_number_location_h}%
+ \letlayoutelementparameter\m_page_layouts_page_number_location_x\page_layouts_place_page_number
+ \ifx\m_page_layouts_page_number_location_x\c!marginedgetext
+ \let\page_layouts_place_extra_text_left \page_layouts_place_page_number_left
+ \let\page_layouts_place_extra_text_right\page_layouts_place_page_number_right
+ \else
+ \let\page_layouts_place_extra_text_left \empty
+ \let\page_layouts_place_extra_text_right\empty
+ \fi}
+
+\def\page_layouts_identify_page_number_location
+ {\let\m_page_layouts_page_number_location_v\v!footer
+ \let\m_page_layouts_page_number_location_h\v!text
+ \let\m_page_layouts_page_number_location_x\c!middletext
+ \processallactionsinset[\directpagenumberingparameter\c!location]
+ [ \v!header=>\let\m_page_layouts_page_number_location_v\v!header,
+ \v!footer=>\let\m_page_layouts_page_number_location_v\v!footer,
+ \v!middle=>\let\m_page_layouts_page_number_location_h\v!text
+ \let\m_page_layouts_page_number_location_x\c!middletext,
+ \v!left=>\let\m_page_layouts_page_number_location_h\v!text
+ \let\m_page_layouts_page_number_location_x\c!lefttext,
+ \v!right=>\let\m_page_layouts_page_number_location_h\v!text
+ \let\m_page_layouts_page_number_location_x\c!righttext,
+ \v!inleft=>\let\m_page_layouts_page_number_location_h\v!margin
+ \let\m_page_layouts_page_number_location_x\c!lefttext,
+ \v!inright=>\let\m_page_layouts_page_number_location_h\v!margin
+ \let\m_page_layouts_page_number_location_x\c!righttext,
+ \v!inmargin=>\let\m_page_layouts_page_number_location_h\v!margin
+ \def\m_page_layouts_page_number_location_x{\ifdoublesided\c!margintext\else\c!righttext\fi},
+ \v!margin=>\let\m_page_layouts_page_number_location_h\v!margin
+ \def\m_page_layouts_page_number_location_x{\ifdoublesided\c!margintext\else\c!righttext\fi},
+ \v!atmargin=>\let\m_page_layouts_page_number_location_h\v!text
+ \let\m_page_layouts_page_number_location_x\c!marginedgetext,
+ \v!marginedge=>\let\m_page_layouts_page_number_location_h\v!text
+ \let\m_page_layouts_page_number_location_x\c!marginedgetext]}
+
+\unexpanded\def\strc_pagenumbers_set_location
+ {\edef\p_strc_pagenumbers_location{\directpagenumberingparameter\c!location}%
+ \ifx\p_strc_pagenumbers_location\m_page_layouts_page_number_location
+ % unchanged
+ \else
+ \let\m_page_layouts_page_number_location\p_strc_pagenumbers_location
+ \page_layouts_reset_page_number_location
+ \ifx\p_strc_pagenumbers_location\empty
+ % set otherwise
+ \orelse\ifx\p_strc_pagenumbers_location\v!none
+ % set otherwise
+ \else
+ \page_layouts_identify_page_number_location
+ \page_layouts_set_page_number_location
+ \fi
+ \fi}
+
+\def\page_layouts_place_page_number_left % historic
+ {\begingroup
+ \setbox\scratchbox\hbox{\ignorespaces\layoutelementparameter\c!marginedgetext\removeunwantedspaces}%
+ \ifzeropt\wd\scratchbox\else
+ \edef\p_strc_pagenumbers_width{\directpagenumberingparameter\c!width}%
+ \ifx\p_strc_pagenumbers_width\empty
+ \box\scratchbox\tfskip
+ \else
+ \hpack to \p_strc_pagenumbers_width{\box\scratchbox\hss}%
+ \fi
+ \fi
+ \endgroup}
+
+\def\page_layouts_place_page_number_right % historic
+ {\begingroup
+ \setbox\scratchbox\hbox{\ignorespaces\layoutelementparameter\c!marginedgetext\removeunwantedspaces}%
+ \ifzeropt\wd\scratchbox\else
+ \edef\p_strc_pagenumbers_width{\directpagenumberingparameter\c!width}%
+ \ifx\p_strc_pagenumbers_width\empty
+ \tfskip\box\scratchbox
+ \else
+ \hpack to \p_strc_pagenumbers_width{\hss\box\scratchbox}%
+ \fi
+ \fi
+ \endgroup}
+
+\strc_pagenumbers_set_location % initializes
+
+\newbox\b_page_layouts_element
+
+\def\page_layouts_insert_elements
+ {\ifcase\pageornamentstate
+ \page_layouts_place_elements_indeed % we could have a special flag for always ignored
+ \fi}
+
+\def\page_layouts_place_elements_indeed
+ {\setbox\b_page_layouts_element\vpack
+ {\dontcomplain
+ \calculatereducedvsizes
+ \swapmargins
+ \offinterlineskip
+ \vkern\dimexpr-\topheight-\topdistance\relax
+ \the\toptextcontent
+ \vkern\dimexpr\topheight+\topdistance\relax
+ \the\headertextcontent
+ \vkern\dimexpr\headerheight+\headerdistance+\textdistance\relax
+ \anch_positions_place_anchors
+ \vkern\dimexpr-\textdistance-\textheight\relax
+ \the\texttextcontent
+ \vkern\textheight
+ \the\everyendoftextbody
+ \vkern\footerdistance
+ \the\footertextcontent
+ \vkern\dimexpr\footerheight+\bottomdistance\relax
+ \the\bottomtextcontent
+ \vkern\bottomheight
+ \vfilll}%
+ \smashbox\b_page_layouts_element
+ \box\b_page_layouts_element}
+
+% \ifdefined\page_prepare_backgrounds\else
+% \let\page_prepare_backgrounds\gobbleoneargument
+% \fi
+
+% only for very special controlled cases or experiments:
+
+\let\page_scale_text_box\gobbleoneargument
+
+\def\page_insert_body#1#2%
+ {\setbox\b_page_layouts_element\vpack
+ {\offinterlineskip
+ \calculatereducedvsizes
+ \calculatehsizes
+ \swapmargins
+ \vkern\dimexpr\headerheight+\headerdistance+\textdistance\relax
+ \dontleavehmode
+ %\page_prepare_backgrounds{#2}%
+ \hpack to \makeupwidth
+ {\begingroup
+ \swapmargins
+ \goleftonpage
+ \ifdim\leftedgewidth>\zeropoint
+ \the\leftedgetextcontent
+ \kern\dimexpr\leftedgewidth+\leftedgedistance\relax
+ \fi
+ \ifdim\leftmarginwidth>\zeropoint
+ \the\leftmargintextcontent
+ \kern\dimexpr\leftmarginwidth+\leftmargindistance\relax
+ \fi
+ \endgroup
+ \page_apply_postprocessors_page{#2}%
+ \settextpagecontent\b_page_layouts_element{#1}{#2}%
+ \page_backgrounds_add_to_text\b_page_layouts_element
+ \page_grids_add_to_box\b_page_layouts_element
+ \page_scale_text_box\b_page_layouts_element
+ \box\b_page_layouts_element
+ \begingroup
+ \ifdim\rightmarginwidth>\zeropoint
+ \kern\rightmargindistance
+ \the\rightmargintextcontent
+ \kern\rightmarginwidth
+ \fi
+ \ifdim\rightedgewidth>\zeropoint
+ \kern\rightedgedistance
+ \the\rightedgetextcontent
+ \kern\rightedgewidth
+ \fi
+ \endgroup
+ \hss}}%
+ \smashbox\b_page_layouts_element
+ \box\b_page_layouts_element}
+
+%D The main text area has to be combined with some additional (tracing) information.
+%D
+%D This will be stored as normal and overloaded in page-lyr and later in page-spr we
+%D overload the the stored version .. evenatually i will clear up the experimental
+%D mess.
+
+\def\settextpagecontent#1#2#3% #2 and #3 will disappear / is overloaded
+ {\setbox#1\hpack to \makeupwidth
+ {\hss % so don't change this
+ \setlayoutcomponentattribute{\v!page:\v!text}%
+ \vpack \layoutcomponentboxattribute to \textheight
+ {\offinterlineskip
+ \freezetextwidth
+ \hsize\textwidth % local variant of \sethsize <<< in columns?
+ \boxmaxdepth\maxdepth
+ \noindent % content can be < \hsize
+ \page_otr_command_package_contents#2#3}% this will vbox
+ \hss}%
+ \dp#1\zeropoint}
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/page-txt.mkvi b/Master/texmf-dist/tex/context/base/mkiv/page-txt.mkvi
index 97668c14377..8b021acca5d 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/page-txt.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/page-txt.mkvi
@@ -25,12 +25,11 @@
\newtoks\texttextcontent
%D \macros
-%D {setuptop, setupheader, setuptext,
-%D setupfooter, setupbottom}
+%D {setuptop, setupheader, setuptext,setupfooter, setupbottom}
%D
-%D The macros in this module sometimes look a bit more complicated than
-%D needed, which is a direct result of the fact that their ancestors are
-%D quite old and upward compatibility is a must.
+%D The macros in this module sometimes look a bit more complicated than needed,
+%D which is a direct result of the fact that their ancestors are quite old and
+%D upward compatibility is a must.
%D
%D \showsetup{setuptop}
%D \showsetup{setupheader}
@@ -136,8 +135,7 @@
%D \macros
%D {noheaderandfooterlines,notopandbottomlines}
%D
-%D Although not really needed, the following shortcuts
-%D sometimes come in handy.
+%D Although not really needed, the following shortcuts sometimes come in handy.
%D
%D \showsetup{noheaderandfooterlines}
%D \showsetup{notopandbottomlines}
@@ -151,8 +149,7 @@
\setuplayoutelement[\v!bottom][\c!state=\v!empty]}
%D \macros
-%D {setuptoptexts, setupheadertexts, setuptexttexts,
-%D setupfootertexts, setupbottomtexts}
+%D {setuptoptexts,setupheadertexts,setuptexttexts,setupfootertexts,setupbottomtexts}
%D
%D The next macros take one or more arguments. The exact setup depends on the number
%D of arguments. Although not that intuitive, the current scheme evolved out of the
@@ -171,11 +168,6 @@
\unexpanded\def\setupfootertexts{\dosixtupleempty\page_layouts_setup_texts[\v!footer ]}
\unexpanded\def\setupbottomtexts{\dosixtupleempty\page_layouts_setup_texts[\v!bottom ]}
-% todo: \setuplayoutelementtext
-
-%D An alternative approach is to have more variables but that does not make the code
-%D less complex (probably more).
-
\unexpanded\def\page_layouts_setup_text_six#vertical#horizontal#a#b#c#d%
{\edef\currentlayoutelement{#vertical:#horizontal}%
\setlayoutelementparameter\c!lefttext
@@ -320,22 +312,6 @@
%D When specified, the texts are automatically limited in length.
-% % where used ?
-%
-% \def\page_layouts_limitate_element_text#width%
-% {\edef\currentlayoutelementwidth{\layoutelementparameter#width}%
-% \ifx\currentlayoutelementwidth\empty
-% \expandafter\firstofoneargument
-% \else
-% \expandafter\page_layouts_limitate_element_text_indeed
-% \fi}
-%
-% \def\page_layouts_limitate_element_text_indeed#content%
-% {\limitatetext{#content}\currentlayoutelementwidth\unknown}
-
-%D The placement of text is hooked into the token lists
-%D associated to the area at hand.
-
\appendtoks \page_layouts_place_text_line\v!top \topheight \to \toptextcontent
\appendtoks \page_layouts_place_text_line\v!header\headerheight \to \headertextcontent
\appendtoks \page_layouts_place_text_line\v!text \textheight \to \texttextcontent
@@ -445,11 +421,11 @@
%D The following macro has to be called after a page is flushed.
\unexpanded\def\resetlayouttextlines % public
- {\csname\??layouttextsreset\v!top \endcsname
- \csname\??layouttextsreset\v!header\endcsname
- \csname\??layouttextsreset\v!text \endcsname
- \csname\??layouttextsreset\v!footer\endcsname
- \csname\??layouttextsreset\v!bottom\endcsname
+ {\begincsname\??layouttextsreset\v!top \endcsname
+ \begincsname\??layouttextsreset\v!header\endcsname
+ \begincsname\??layouttextsreset\v!text \endcsname
+ \begincsname\??layouttextsreset\v!footer\endcsname
+ \begincsname\??layouttextsreset\v!bottom\endcsname
\ifconditional\resyncaftertextline
\calculateglobalvsizes
\page_backgrounds_recalculate
@@ -814,10 +790,6 @@
\strc_pagenumbers_set_location % initializes
-% will go to page-box.mkiv
-
-% the next macros will be redone (less boxing)
-
\newbox\b_page_layouts_element
\def\page_layouts_insert_elements
@@ -880,7 +852,7 @@
\kern\dimexpr\leftmarginwidth+\leftmargindistance\relax
\fi
\endgroup
- \page_postprocessors_page{#2}%
+ \page_apply_postprocessors_page{#2}%
\settextpagecontent\b_page_layouts_element{#1}{#2}%
\page_backgrounds_add_to_text\b_page_layouts_element
\page_grids_add_to_box\b_page_layouts_element
diff --git a/Master/texmf-dist/tex/context/base/mkiv/phys-dim.mkiv b/Master/texmf-dist/tex/context/base/mkiv/phys-dim.mkiv
index 3ea042b0570..1eb1f37f76b 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/phys-dim.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/phys-dim.mkiv
@@ -441,6 +441,7 @@
\appendtoks
\disablemathpunctuation
+ \nocharacteralign
\to \everyunits
\appendtoks
@@ -449,6 +450,7 @@
\unexpanded\def\phys_units_direct#1%
{\begingroup
+ \the\everyunits
\ifdim\lastskip>\zeropoint
\settrue\c_phys_units_dospace
\removelastskip
@@ -459,7 +461,7 @@
\edef\unitlanguage{\unitparameter\s!language}%
\let\prefixlanguage\unitlanguage
\let\operatorlanguage\unitlanguage
- \the\everyunits
+% \the\everyunits
%\removeunwantedspaces % not ok yet
\useunitstyleandcolor\c!style\c!color
\edef\currentunitsalternative{\unitparameter\c!alternative}%
diff --git a/Master/texmf-dist/tex/context/base/mkiv/publ-imp-apa.mkvi b/Master/texmf-dist/tex/context/base/mkiv/publ-imp-apa.mkvi
index 36e4882d25a..5603b79a5f1 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/publ-imp-apa.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/publ-imp-apa.mkvi
@@ -703,20 +703,20 @@
apa:edition={Utgåva},
apa:Editor=Redaktör,
apa:Editors=Redaktörer,
- apa:Volume=Band,
+ apa:Volume=Band,
apa:Volumes=Band,
apa:nd={u.å.}, % utan årtal
apa:supplement=Bilaga, % Supplement
apa:MotionPicture=Spelfilm, % ?
apa:Writer={Manusförfattare}, % Assuming for a movie
- apa:Writers={Manusförfattare}, %
+ apa:Writers={Manusförfattare}, %
apa:Producer=Producent, % Assuming for a movie
- apa:Producers=Producenter, %
+ apa:Producers=Producenter, %
apa:Director={Regissör}, % Assuming for a movie
- apa:Directors={Regissörer}, %
+ apa:Directors={Regissörer}, %
apa:Recordedby={Inspelad av}, % Assuming for a movie
apa:Author={Författare},
- apa:Translator={Översättare},
+ apa:Translator={Översättare},
apa:Advanced={Avancerad onlinepublikation}, % ?
apa:Retrieved={Hämtad från}]
diff --git a/Master/texmf-dist/tex/context/base/mkiv/publ-imp-aps.mkvi b/Master/texmf-dist/tex/context/base/mkiv/publ-imp-aps.mkvi
index 4e12fbfc7b3..d085b96eb63 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/publ-imp-aps.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/publ-imp-aps.mkvi
@@ -665,8 +665,10 @@
\stoptexdefinition
\starttexdefinition unexpanded btx:aps:author
- \btxflush{author}
- \btxcomma
+ \btxdoif {author} {
+ \btxflush{author}
+ \btxcomma
+ }
\stoptexdefinition
\starttexdefinition unexpanded btx:aps:organization-if-not-author
diff --git a/Master/texmf-dist/tex/context/base/mkiv/publ-imp-chicago.lua b/Master/texmf-dist/tex/context/base/mkiv/publ-imp-chicago.lua
new file mode 100644
index 00000000000..cda76f52a39
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/publ-imp-chicago.lua
@@ -0,0 +1,560 @@
+local specification = {
+ --
+ -- metadata
+ --
+ name = "chicago",
+ version = "1.00",
+ comment = "Chicago Manual of Style specification",
+ author = "Alan Braslau and Hans Hagen",
+ copyright = "ConTeXt development team",
+ --
+ -- derived (combinations of) fields (all share the same default set)
+ --
+ virtual = {
+ "authoryear",
+ "authoryears",
+ "authornum",
+ "num",
+ "suffix",
+ },
+ --
+ -- special datatypes
+ --
+ types = {
+ --
+ -- list of fields that are interpreted as names: "NAME [and NAME]" where
+ -- NAME is one of the following:
+ --
+ -- First vons Last
+ -- vons Last, First
+ -- vons Last, Jrs, First
+ -- Vons, Last, Jrs, First
+ --
+ author = "author", -- interpreted as name(s)
+ withauthor = "author",
+ editor = "author",
+ translator = "author",
+ artist = "author",
+ composer = "author",
+ producer = "author",
+ director = "author",
+ doi = "url", -- an external link
+ url = "url",
+ page = "pagenumber", -- number or range: f--t
+ pages = "pagenumber",
+ volume = "range",
+ number = "range",
+ keywords = "keyword", -- comma|-|separated list
+ year = "number",
+ },
+ --
+ -- categories with their specific fields
+ --
+ categories = {
+ --
+ -- categories are added below
+ --
+ },
+}
+
+local generic = {
+ --
+ -- A set returns the first field (in order of position below) that is found
+ -- present in an entry. A set having the same name as a field conditionally
+ -- allows the substitution of an alternate field.
+ --
+ -- note that anything can get assigned a doi or be available online.
+ doi = { "doi", "url" },
+ editionset = { "edition", "volume", "number", "pages" },
+}
+
+-- Definition of recognized categories and the fields that they contain.
+-- Required fields should be present; optional fields may also be rendered;
+-- all other fields will be ignored.
+
+-- Sets contain either/or in order of precedence.
+--
+-- For a category *not* defined here yet present in the dataset, *all* fields
+-- are taken as optional. This allows for flexibility in the addition of new
+-- categories.
+
+local categories = specification.categories
+
+-- an article from a journal
+
+categories.article = {
+ sets = {
+ author = { "author", "organization", "editor", "title" },
+ doi = generic.doi,
+ },
+ required = {
+ "author", -- a set
+ },
+ optional = {
+ "withauthor", "translator",
+ "year",
+ "subtitle", "type", "file",
+ "journal", "volume", "number", "pages",
+ "doi", "note",
+ -- APA ignores this:
+ --
+ -- "month",
+ --
+ -- fields defined in jabref but presently ignored:
+ --
+ -- "issn",
+ },
+}
+
+-- an article from a magazine
+
+categories.magazine = {
+ sets = categories.article.sets,
+ required = {
+ "author",
+ "year",
+ "journal",
+ },
+ optional = {
+ "withauthor", "translator",
+ "subtitle", "type", "file",
+ "number",
+ "month", "day",
+ "doi", "note",
+ },
+}
+
+categories.newspaper = categories.magazine
+
+-- (from jabref) to be identified and setup ...
+
+categories.periodical = {
+ sets = {
+ author = { "editor", "publisher", "organization", },
+ doi = generic.doi,
+ },
+ required = {
+ "title",
+ "year",
+ },
+ optional = {
+ "author", "withauthor", "translator",
+ "subtitle", "file",
+ "series", "volume", "number", "month",
+ "organization",
+ "doi", "note",
+ },
+}
+
+-- (from jabref) to be identified and setup ...
+
+categories.standard = {
+ sets = {
+ author = { "author", "institution", "organization" },
+ doi = generic.doi,
+ },
+ required = {
+ "author",
+ "year",
+ "title", "subtitle",
+ "doi", "note",
+ },
+ optional = {
+ "withauthor", "translator",
+ },
+}
+
+-- a book with an explicit publisher.
+
+categories.book = {
+ sets = {
+ author = { "author", "editor", "publisher", "title" },
+ ineditor = { "editor" },
+ editionset = generic.editionset,
+ doi = generic.doi,
+ },
+ required = { "author" },
+ optional = {
+ "ineditor",
+ "withauthor", "translator",
+ "year", "month", "day",
+ "subtitle", "type", "file",
+ "editionset", "series",
+ "address",
+ "doi", "note",
+ "abstract",
+ },
+}
+
+-- a part of a book, which may be a chapter (or section or whatever) and/or a range of pages.
+
+categories.inbook = {
+ sets = {
+ author = { "author", "organization", "editor", "publisher", "title", },
+ ineditor = { "editor" },
+ editionset = generic.editionset,
+ doi = generic.doi,
+ },
+ required = {
+ "author",
+ "year" ,
+ },
+ optional = {
+ "ineditor",
+ "withauthor", "translator",
+ "subtitle", "type", "file",
+ "booktitle", "subbooktitle",
+ -- APA ignores this: "chapter",
+ "editionset", "series",
+ "month",
+ "address",
+ "doi", "note",
+ },
+}
+
+-- a book having its own title as part of a collection.
+-- (like inbook, but we here make booktitle required)
+
+categories.incollection = {
+ sets = {
+ author = { "author", "editor", "publisher", "title", },
+ ineditor = { "editor" },
+ editionset = generic.editionset,
+ doi = generic.doi,
+ },
+ required = {
+ "author",
+ "booktitle",
+ "year",
+ },
+ optional = {
+ "ineditor",
+ "withauthor", "translator",
+ "subtitle", "type", "file",
+ "subbooktitle",
+ "editionset", "series",
+ -- APA ignores this: "chapter",
+ "month",
+ "address",
+ "doi", "note",
+ },
+}
+
+-- a work that is printed and bound, but without a named publisher or sponsoring institution.
+
+categories.booklet = {
+ sets = {
+ author = { "author", "title", },
+ publisher = { "howpublished" }, -- no "publisher"!
+ doi = generic.doi,
+ },
+ required = {
+ "author"
+ },
+ optional = {
+ "withauthor", "translator",
+ "publisher",
+ "year", "month",
+ "subtitle", "type", "file",
+ "address",
+ "doi", "note",
+ },
+}
+
+-- the proceedings of a conference.
+
+categories.proceedings = {
+ sets = {
+ author = { "editor", "organization", "publisher", "title" }, -- no "author"!
+ publisher = { "publisher", "organization" },
+ editionset = generic.editionset,
+ doi = generic.doi,
+ },
+ required = {
+ "author",
+ "year"
+ },
+ optional = {
+ "withauthor", "translator",
+ "publisher",
+ "subtitle", "file",
+ "editionset", "series",
+ "month",
+ "address",
+ "doi", "note",
+ },
+}
+
+-- an article in a conference proceedings.
+
+categories.inproceedings = {
+ sets = categories.incollection.sets,
+ required = categories.incollection.required,
+ optional = {
+ "withauthor", "translator",
+ "subtitle", "type", "file",
+ "month",
+ "edition", "series",
+ "address", "organization",
+ "doi", "note",
+ },
+}
+
+categories.conference = categories.inproceedings
+
+-- a thesis (of course).
+
+categories.thesis = {
+ sets = {
+ doi = generic.doi,
+ },
+ required = {
+ "author",
+ "title",
+ "school",
+ "year",
+ "type"
+ },
+ optional = {
+ "withauthor", "translator",
+ "subtitle", "file",
+ "month",
+ "address",
+ "doi", "note",
+ },
+}
+
+categories.mastersthesis = {
+ sets = categories.thesis.sets,
+ required = {
+ "author",
+ "title",
+ "school",
+ "year"
+ },
+ optional = {
+ "withauthor", "translator",
+ "type",
+ "subtitle", "file",
+ "month",
+ "address",
+ "doi", "note",
+ },
+}
+categories.phdthesis = categories.mastersthesis
+
+-- a report published by a school or other institution, usually numbered within a series.
+
+categories.techreport = {
+ sets = {
+ author = { "author", "institution", "publisher", "title" },
+ publisher = { "publisher", "institution", },
+ editionset = { "type", "volume", "number", "pages" }, -- no "edition"!
+ doi = generic.doi,
+ },
+ required = {
+ "author",
+ "title",
+ "institution",
+ "year"
+ },
+ optional = {
+ "withauthor", "translator",
+ "publisher",
+ "address",
+ "subtitle", "file",
+ "editionset",
+ "month",
+ "doi", "note",
+ },
+}
+
+-- technical documentation.
+
+categories.manual = {
+ sets = {
+ author = { "author", "organization", "publisher", "title" },
+ publisher = { "publisher", "organization", },
+ editionset = generic.editionset,
+ doi = generic.doi,
+ },
+ required = {
+ "title"
+ },
+ optional = {
+ "author", "publisher",
+ "withauthor", "translator",
+ "address",
+ "subtitle", "file",
+ "editionset", "month", "year",
+ "doi", "note",
+-- "abstract",
+ },
+}
+
+-- a patent (of course).
+
+categories.patent = {
+ sets = {
+ author = { "author", "assignee", },
+ publisher = { "publisher", "assignee", },
+ year = { "year", "yearfiled", },
+ month = { "month", "monthfiled", },
+ day = { "day", "dayfiled", },
+ doi = generic.doi,
+ },
+ required = {
+ "nationality",
+ "number",
+ "year",
+ },
+ optional = {
+ "type",
+ --check this: "language",
+ "author", "publisher",
+ "withauthor", "translator",
+ "title", "subtitle", "file",
+ "address",
+ "day", "month",
+ "doi", "note"
+ },
+}
+
+-- a document having an author and title, but not formally published.
+
+categories.unpublished = {
+ sets = {
+ doi = generic.doi,
+ },
+ required = {
+ "author",
+ "title",
+ "note"
+ },
+ optional = {
+ "withauthor", "translator",
+ "subtitle", "file",
+ "year", "month",
+ "doi"
+ },
+}
+
+-- like misc below but includes organization.
+
+categories.electronic = {
+ sets = {
+ doi = generic.doi,
+ author = { "author", "organization", },
+ },
+ required = {
+ "title"
+ },
+ optional = {
+ "subtitle", "type", "file",
+ "year", "month",
+ "author", "withauthor", "translator",
+ "address",
+ "organization",
+ "howpublished",
+ "doi", "note"
+ },
+}
+
+-- not bibtex categories...
+
+categories.film = {
+ sets = {
+ doi = generic.doi,
+ author = { "author", "producer", "director", },
+ },
+ required = {
+ "author",
+ "title",
+ "year",
+ "address", "publisher", -- aka studio
+ },
+ optional = {
+ "withauthor", "translator",
+ "type",
+ "note",
+ "doi",
+ },
+}
+
+categories.music = {
+ sets = {
+ doi = generic.doi,
+ author = { "composer", "artist", "title", "album" },
+ title = { "title", "album", },
+ },
+ required = {
+ "author",
+ "title",
+ "year",
+ "address", "publisher", -- aka label
+ },
+ optional = {
+ "withauthor", "translator",
+ "type",
+ "note",
+ "doi",
+ },
+}
+
+-- use this type when nothing else fits.
+
+categories.misc = {
+ sets = {
+ doi = generic.doi,
+ },
+ required = {
+ -- nothing is really important here
+ },
+ optional = {
+ "author", "withauthor", "translator",
+ "title", "subtitle", "file",
+ "year", "month",
+ "howpublished",
+ "doi", "note",
+ },
+}
+
+-- other (whatever jabref does not know!)
+
+categories.other = {
+ sets = {
+ doi = generic.doi,
+ },
+ required = {
+ "author",
+ "title",
+ "year"
+ },
+ optional = {
+ "withauthor", "translator",
+ "subtitle", "file",
+ "doi", "note",
+ },
+}
+
+-- if all else fails to match:
+
+categories.literal = {
+ sets = {
+ author = { "key" },
+ doi = generic.doi,
+ },
+ required = {
+ "author",
+ "text"
+ },
+ optional = {
+ "withauthor", "translator",
+ "doi", "note"
+ },
+ virtual = false,
+}
+
+-- done
+
+return specification
diff --git a/Master/texmf-dist/tex/context/base/mkiv/publ-imp-chicago.mkvi b/Master/texmf-dist/tex/context/base/mkiv/publ-imp-chicago.mkvi
new file mode 100644
index 00000000000..867535ca6be
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/publ-imp-chicago.mkvi
@@ -0,0 +1,1686 @@
+%D \module
+%D [ file=publ-imp-chicago,
+%D version=2019.05.20,
+%D title=Chicago bibliography style,
+%D subtitle=Publications,
+%D author=Alan Braslau and Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is therefore copyrighted
+%D by \PRAGMA. See mreadme.pdf for details.
+
+\startbtxrenderingdefinitions[chicago]
+
+\ifdefined\c!translate \else \def\c!translate{translate} \fi
+
+%D Reference:
+%D \startTEX
+%D @Book{Chicago2010,
+%D title ={The Chicago Manual of Style},
+%D subtitle ={The Essential Guide for Writers, Editors, and Publishers},
+%D year ={2010},
+%D edition ={Sixteenth},
+%D address ={Chicago and London},
+%D publisher={The University of Chicago Press},
+%D Xpages ={1026},
+%D url ={https://www.chicagomanualofstyle.org/},
+%D }
+%D \stopTEX
+
+% set ALL specific Chicago compliant values
+
+\definebtx
+ [chicago]
+ [\c!default=default,
+ \c!specification=chicago,
+ \c!otherstext={\btxspace\btxlabeltext{others}},
+ %\c!journalconversion=\v!normal,
+ \c!monthconversion=\v!month,
+ \c!stopper:initials={. }, % with a (breakable) space
+ \c!separator:names:2={\btxcomma}, % aka namesep - in this namespace
+ \c!separator:names:3={\btxcomma\btxlabeltext{and}\space}, % comma separated list
+ \c!separator:names:4={\btxspace\btxlabeltext{and}\space}] % last of two, no comma!
+
+% First, define list and rendering parameters
+
+% The Chicago style sorts the unnumbered rendered list by authoryear
+
+\definebtxrendering
+ [chicago]
+ [\c!specification=chicago,
+ \c!sorttype=authoryear,
+ \c!numbering=\v!no]
+
+\setupbtxlist
+ [chicago]
+ [\c!alternative=\v!paragraph,
+ \c!align={normal,verytolerant,stretch},
+ %\c!width=\v!fit,
+ %\c!distance=.5\emwidth,
+ \c!margin=3.5\emwidth]
+
+\definebtx
+ [chicago:\s!list]
+ [chicago]
+ %[\c!otherstext={\btxcomma\btxnobreakspace\textellipsis\space},
+ % \c!etallimit=7,
+ % \c!etaldisplay=6,
+ % \c!etaloption=last,
+ [\c!authorconversion=inverted]
+
+% First, we define a namespace for a few special fields
+
+\definebtx
+ [chicago:\s!list:author]
+ [chicago:\s!list]
+
+\definebtx
+ [chicago:\s!list:withauthor]
+ [chicago:\s!list:author]
+
+\definebtx
+ [chicago:\s!list:editor]
+ [chicago:\s!list:author]
+
+\definebtx
+ [chicago:\s!list:ineditor]
+ [chicago:\s!list:editor]
+ [\c!authorconversion=normalshort]
+
+\definebtx
+ [chicago:\s!list:translator]
+ [chicago:\s!list:author]
+ [\c!authorconversion=normalshort]
+
+\definebtx
+ [chicago:\s!list:director]
+ [chicago:\s!list:author]
+
+\definebtx
+ [chicago:\s!list:producer]
+ [chicago:\s!list:author]
+
+\definebtx
+ [chicago:\s!list:suffix]
+ [chicago:\s!list]
+
+\definebtx
+ [chicago:\s!list:url]
+ [chicago:\s!list]
+
+\definebtx
+ [chicago:\s!list:doi]
+ [chicago:\s!list]
+
+\definebtx
+ [chicago:\s!list:\s!page]
+ [chicago:\s!list]
+ %[\c!separator:2={\btxcomma},
+ % \c!separator:3={\btxcomma\btxlabeltext{and}\space},
+ % \c!separator:4={\btxspace\btxlabeltext{and}\space},
+ [\c!left={\btxleftparenthesis},
+ \c!right={\btxrightparenthesis},
+ \c!command={\wordright}]
+
+\definebtx
+ [chicago:\s!list:numbering]
+ [chicago:\s!list]
+ [\c!right={\btxspace}]
+
+\definebtx
+ [chicago:\s!list:numbering:default]
+ [chicago:\s!list:numbering]
+
+\definebtx
+ [chicago:\s!list:numbering:num]
+ [chicago:\s!list:numbering]
+ [\c!stopper={.}]
+
+\definebtx
+ [chicago:\s!list:numbering:short]
+ [chicago:\s!list:numbering]
+
+\definebtx
+ [chicago:\s!list:numbering:tag]
+ [chicago:\s!list:numbering]
+
+\definebtx
+ [chicago:\s!list:numbering:index]
+ [chicago:\s!list:numbering]
+
+% Next, we define a namespace for each category
+
+%D In order to be able to get journals expanded (or normalized or abbreviated) you need
+%D to load a list:
+%D
+%D \starttyping
+%D \btxloadjournallist[journals.txt] % the jabref list
+%D \stoptyping
+
+\definebtx
+ [chicago:\s!list:journal]
+ [chicago:\s!list]
+ [\c!style=\v!italic]
+ %command=\btxexpandedjournal] % btxabbreviatedjournal
+
+\definebtx
+ [chicago:\s!list:volume]
+ [chicago:\s!list]
+ [\c!style=\v!italic]
+
+\definebtx
+ [chicago:\s!list:title]
+ [chicago:\s!list]
+ [\c!style=\v!italic,
+ \c!command=\Word,
+ \c!translate=\v!yes]
+
+\definebtx
+ [chicago:\s!list:title:article]
+ [chicago:\s!list:title]
+ [\c!style=] % journal is set in italics
+
+\definebtx
+ [chicago:\s!list:title:magazine]
+ [chicago:\s!list:title]
+
+\definebtx
+ [chicago:\s!list:title:newspaper]
+ [chicago:\s!list:title]
+
+\definebtx
+ [chicago:\s!list:title:periodical]
+ [chicago:\s!list:title]
+
+\definebtx
+ [chicago:\s!list:title:standard]
+ [chicago:\s!list:title]
+
+\definebtx
+ [chicago:\s!list:title:book]
+ [chicago:\s!list:title]
+
+\definebtx
+ [chicago:\s!list:booktitle:inbook]
+ [chicago:\s!list:title]
+
+\definebtx
+ [chicago:\s!list:title:inbook]
+ [chicago:\s!list:title]
+ [\c!style=] % booktitle is set in italics
+
+\definebtx
+ [chicago:\s!list:booktitle:incollection]
+ [chicago:\s!list:title]
+
+\definebtx
+ [chicago:\s!list:title:incollection]
+ [chicago:\s!list:title]
+ [\c!style=] % booktitle is set in italics
+
+\definebtx
+ [chicago:\s!list:title:proceedings]
+ [chicago:\s!list:title]
+
+\definebtx
+ [chicago:\s!list:booktitle:inproceedings]
+ [chicago:\s!list:title]
+
+\definebtx
+ [chicago:\s!list:title:inproceedings]
+ [chicago:\s!list:title]
+ [\c!style=] % booktitle is set in italics
+
+\definebtx
+ [chicago:\s!list:booktitle:conference]
+ [chicago:\s!list:title]
+
+\definebtx
+ [chicago:\s!list:title:conference]
+ [chicago:\s!list:title]
+ [\c!style=] % booktitle is set in italics
+
+\definebtx
+ [chicago:\s!list:title:thesis]
+ [chicago:\s!list:title]
+
+\definebtx
+ [chicago:\s!list:title:phdthesis]
+ [chicago:\s!list:title]
+
+\definebtx
+ [chicago:\s!list:title:mastersthesis]
+ [chicago:\s!list:title]
+
+\definebtx
+ [chicago:\s!list:title:booklet]
+ [chicago:\s!list:title]
+
+\definebtx
+ [chicago:\s!list:title:manual]
+ [chicago:\s!list:title]
+
+\definebtx
+ [chicago:\s!list:title:techreport]
+ [chicago:\s!list:title]
+
+\definebtx
+ [chicago:\s!list:title:unpublished]
+ [chicago:\s!list:title]
+
+\definebtx
+ [chicago:\s!list:title:patent]
+ [chicago:\s!list:title]
+
+\definebtx
+ [chicago:\s!list:title:electronic]
+ [chicago:\s!list:title]
+
+\definebtx
+ [chicago:\s!list:title:music]
+ [chicago:\s!list:title]
+
+\definebtx
+ [chicago:\s!list:title:film]
+ [chicago:\s!list:title]
+
+\definebtx
+ [chicago:\s!list:title:other]
+ [chicago:\s!list:title]
+
+\definebtx
+ [chicago:\s!list:title:misc]
+ [chicago:\s!list:title]
+
+\definebtx
+ [chicago:\s!list:title:literal]
+ [chicago:\s!list:title]
+
+\definebtx
+ [chicago:\s!list:type]
+ [\c!command=\Word]
+
+% Then define and set cite parameters.
+
+\definebtx
+ [chicago:\s!cite]
+ [chicago]
+ [\c!alternative=authoryear,
+ \c!otherstext={\btxcomma\btxlabeltext{others}},
+ \c!etallimit=1,
+ \c!etaldisplay=1,
+ \c!authorconversion=\v!name,
+ \c!sorttype=normal, % \v!normal ?
+ \c!style=,
+ \c!compress=\v!yes] % note that cite sorts only work with compress=yes.
+
+\definebtx
+ [chicago:\s!cite:name]
+ [chicago:\s!cite]
+ [\c!authorconversion=\v!name]
+
+\definebtx
+ [chicago:\s!cite:inverted]
+ [chicago:\s!cite]
+ [\c!authorconversion=\v!invertedshort]
+
+\definebtx
+ [chicago:\s!cite:invertedshort]
+ [chicago:\s!cite]
+ [\c!authorconversion=\v!invertedshort]
+
+\definebtx
+ [chicago:\s!cite:normalshort]
+ [chicago:\s!cite]
+ [\c!authorconversion=\v!normalshort]
+
+\definebtx
+ [chicago:\s!cite:normal]
+ [chicago:\s!cite]
+ [\c!authorconversion=\v!normal]
+
+\definebtx
+ [chicago:\s!cite:author]
+ [chicago:\s!cite]
+
+\definebtx
+ [chicago:\s!cite:editor]
+ [chicago:\s!cite:author]
+
+\definebtx
+ [chicago:\s!cite:translator]
+ [chicago:\s!cite:author]
+
+\definebtx
+ [chicago:\s!cite:organization]
+ [chicago:\s!cite]
+
+\definebtx
+ [chicago:\s!cite:authoryear]
+ [chicago:\s!cite:author]
+ [\c!left={(},
+ \c!right={)},
+ \c!inbetween={\btxspace}]
+
+\definebtx
+ [chicago:\s!cite:default]
+ [chicago:\s!cite:authoryear]
+
+\definebtx
+ [chicago:\s!cite:authoryears]
+ [chicago:\s!cite:author]
+ [\c!left=, % these two settings are perhaps redundant?
+ \c!right=,
+ \c!inbetween={\btxspace}]
+
+\definebtx
+ [chicago:\s!cite:authornum]
+ [chicago:\s!cite:author]
+ [\c!left={(},
+ \c!right={)}]
+
+\definebtx
+ [chicago:\s!cite:author:num] % todo
+ [chicago:\s!cite:authornum]
+ [\c!left={\btxspace[},
+ \c!right={]}]
+
+\definebtx
+ [chicago:\s!cite:author:year] % todo
+ [chicago:\s!cite]
+
+\definebtx
+ [chicago:\s!cite:author:years] % todo
+ [chicago:\s!cite:authoryears]
+ [\c!inbetween=,
+ \c!left={\btxspace(},
+ \c!right={)}]
+
+\definebtx
+ [chicago:\s!cite:lefttext]
+ [chicago:\s!cite]
+ [\c!left=,
+ \c!right={\btxspace}]
+
+\definebtx
+ [chicago:\s!cite:righttext]
+ [chicago:\s!cite]
+ [\c!left={\btxcomma},
+ \c!right=]
+
+\definebtx
+ [chicago:\s!cite:year]
+ [chicago:\s!cite]
+ [\c!separator:2={\btxcomma}, % :0 and :1 - between items of a list
+ \c!separator:3={\btxcomma\btxlabeltext{and}\space},
+ \c!separator:4={\btxspace\btxlabeltext{and}\space}]
+
+\definebtx
+ [chicago:\s!cite:title]
+ [chicago:\s!cite]
+ [\c!separator:2={\btxcomma}, % :0 and :1 - between items of a list
+ \c!separator:3={\btxcomma\btxlabeltext{and}\space},
+ \c!separator:4={\btxspace\btxlabeltext{and}\space},
+ \c!command={\language[\currentbtxlanguage]}, % BAH
+ \c!sorttype=none,
+ \c!style=\v!italic]
+
+\definebtx
+ [chicago:\s!cite:subtitle]
+ [chicago:\s!cite:title]
+
+\definebtx
+ [chicago:\s!cite:booktitle]
+ [chicago:\s!cite:title]
+
+\definebtx
+ [chicago:\s!cite:subbooktitle]
+ [chicago:\s!cite:booktitle]
+
+% Will these get used?
+
+\definebtx
+ [chicago:\s!cite:title:inbook]
+ [chicago:\s!cite:title]
+ [\c!style=] % not italic
+
+\definebtx
+ [chicago:\s!cite:title:incollection]
+ [chicago:\s!cite:title:inbook]
+
+\definebtx
+ [chicago:\s!cite:title:inproceedings]
+ [chicago:\s!cite:title:inbook]
+
+\definebtx
+ [chicago:\s!cite:subtitle:inbook]
+ [chicago:\s!cite:title:inbook]
+
+\definebtx
+ [chicago:\s!cite:subtitle:incollection]
+ [chicago:\s!cite:title:incollection]
+
+\definebtx
+ [chicago:\s!cite:subtitle:inproceedings]
+ [chicago:\s!cite:title:inproceedings]
+
+
+\definebtx
+ [chicago:\s!cite:tag]
+ [chicago:\s!cite]
+ [\c!left={[},
+ \c!right={]}]
+
+\definebtx
+ [chicago:\s!cite:index]
+ [chicago:\s!cite]
+ [\c!left={[},
+ \c!right={]}]
+
+\definebtx
+ [chicago:\s!cite:page]
+ [chicago:\s!cite]
+ [\c!left=,
+ \c!right=,
+ \c!separator:2={\btxcomma}, % :0 and :1 - between items of a list
+ \c!separator:3={\btxcomma\btxlabeltext{and}\space},
+ \c!separator:4={\btxspace\btxlabeltext{and}\space}]
+
+\definebtx
+ [chicago:\s!cite:pages]
+ [chicago:\s!cite:page]
+
+\definebtx
+ [chicago:\s!cite:keywords]
+ [chicago:\s!cite]
+
+\definebtx
+ [chicago:\s!cite:short]
+ [chicago:\s!cite]
+ [\c!left={[},
+ \c!right={]}]
+
+\definebtx
+ [chicago:\s!cite:category]
+ [chicago:\s!cite]
+
+\definebtx
+ [chicago:\s!cite:url]
+ [chicago:\s!cite]
+ [\c!left={(},
+ \c!right={)}]
+
+\definebtx
+ [chicago:\s!cite:doi]
+ [chicago:\s!cite:url]
+
+\definebtx
+ [chicago:\s!cite:num]
+ [chicago:\s!cite]
+ [\c!left={[},
+ \c!right={]},
+ \c!separator:2={,}, % no space
+ \c!separator:3=\btxparameter{\c!separator:2},
+ \c!separator:4=\btxparameter{\c!separator:2}]
+
+\definebtx
+ [chicago:\s!cite:textnum]
+ [chicago:\s!cite:num]
+ [\c!left={Ref.\nbsp},
+ \c!right=,
+ \c!separator:2={\btxcomma},
+ \c!separator:3={\btxspace\btxlabeltext{and}\space},
+ \c!separator:4={\btxspace\btxlabeltext{and}\space}]
+
+\definebtx
+ [chicago:\s!cite:entry]
+ [chicago:\s!cite]
+ [\c!left=,
+ \c!right=,
+ \c!inbetween={\btxspace},
+ \c!separator:2={\btxsemicolon},
+ \c!separator:3=\btxparameter{\c!separator:2},
+ \c!separator:4=\btxparameter{\c!separator:2}]
+
+\definebtx
+ [chicago:\s!cite:footnote]
+ [chicago:\s!cite:entry]
+
+% Now we setup for the details of the renderings
+
+%D Sometimes we have verbose injections in an entry and these can be language
+%D dependent, so we use labels.
+%D
+%D Because we want to mix rendering (in the manual) we need a namespace in label
+%D texts:
+
+\setupbtxlabeltext
+ [en]
+ [chicago:number={No.},
+ chicago:edition={ed.},
+ chicago:Editor={Ed.},
+ chicago:Editors={Eds.},
+ chicago:Volume={Vol.},
+ chicago:Volumes={Vols.},
+ chicago:nd={n.d.}, % no date
+ chicago:supplement={Suppl.}, % Supplement (not used?)
+ chicago:MotionPicture={Motion picture},
+ chicago:Writer=Writer,
+ chicago:Writers=Writers,
+ chicago:Producer=Producer,
+ chicago:Producers=Producers,
+ chicago:Director=Director,
+ chicago:Directors=Directors,
+ chicago:Recordedby={Recorded by},
+ chicago:Author=Author,
+ chicago:Translator={Trans.}, % Translator(s)
+ chicago:Advanced={Advanced online publication},
+ chicago:Retrieved={Retrieved from}] % {Available from}]
+
+\setupbtxlabeltext
+ [nl]
+ [chicago:number={Nr.},
+ chicago:edition={ed.}, % editie
+ chicago:Editor=Editor, % Ed./Eds.
+ chicago:Editors=Editors,
+ chicago:Volume={Vol.},
+ chicago:Volumes={Vols.},
+ chicago:nd={g.d.} % geen datum
+ chicago:supplement=Supplement,
+ chicago:MotionPicture=Film, % ?
+ chicago:Writer=Scenarioschrijver, % ?
+ chicago:Writers=Schrijvers, % ?
+ chicago:Producer=Producent, % ?
+ chicago:Producers=Producents, % ?
+ chicago:Director=Directeur,
+ chicago:Directors=Directeurs,
+ chicago:Recordedby={Opgenomen door}, % ?
+ chicago:Author=Auteur,
+ chicago:Translator=Vertaler,
+ chicago:Advanced={Geavanceerde online publicatie},
+ chicago:Retrieved={Ontvangen van}] % {Beschikbaar vanaf}]
+
+\setupbtxlabeltext
+ [fr]
+ [chicago:number={N\high{o}},
+ chicago:edition={édition},
+ chicago:Editor=Éditeur,
+ chicago:Editors=Éditeurs,
+ chicago:Volume=Volume,
+ chicago:Volumes=Volumes,
+ chicago:nd={s.d.}, % sans date
+ chicago:supplement=Supplément,
+ chicago:MotionPicture={Film cinématographique},
+ chicago:Writer=Scénariste,
+ chicago:Writers=Scénaristes,
+ chicago:Producer=Producteur,
+ chicago:Producers=Producteurs,
+ chicago:Director=Réalisateur,
+ chicago:Directors=Réalisateurs,
+ chicago:Recordedby={Enregistré par},
+ chicago:Author=Auteur,
+ chicago:Translator=Traducteur,
+ chicago:Advanced={Publication en ligne anticipée},
+ chicago:Retrieved={Téléchargé de}] % {Disponible à}]
+
+\setupbtxlabeltext
+ [de]
+ [chicago:number={Nr.},
+ chicago:edition=Auf\/lage,
+ chicago:Editor=Herausgeber, % Hrsg./Hg.
+ chicago:Editors=Herausgeber,
+ chicago:Volume=Band, % Bd.
+ chicago:Volumes={Bände},
+ chicago:nd={o.D.}, % ohne Datum (mostly: o.J. / ohne Jahr)
+ chicago:supplement={Beilage}, % Supplement
+ chicago:MotionPicture=Kinofilm, % ?
+ chicago:Writer=Drehbuchautor, % ?
+ chicago:Writers=Schriftsteller, % ?
+ chicago:Producer=Producer, % ?
+ chicago:Producers=Produzenten, % ?
+ chicago:Director=Director, % ?
+ chicago:Directors=Directors, % ?
+ chicago:Recordedby={per Einschreiben}, % ?
+ chicago:Author=Autor,
+ chicago:Translator={Übersetzer}, % Übers.
+ chicago:Advanced={Erweiterte Online-Publikation},
+ chicago:Retrieved={heruntergeladen von}]
+
+% thanks: Andrea Valle
+
+\setupbtxlabeltext
+ [it]
+ [chicago:number={Nº},
+ chicago:edition={ed.}, % edizione
+ chicago:Editor={A cura di},
+ chicago:Editors={A cura di},
+ chicago:Volume={Vol.}, % Volume
+ chicago:Volumes={Vol.}, % Volumi
+ chicago:nd={s.d.}, % senza data
+ chicago:supplement={Supplemento},
+ chicago:MotionPicture=Film, % ?
+ chicago:Writer=Sceneggiatore, % ?
+ chicago:Writers=Scrittori, % ?
+ chicago:Producer=Produttore,
+ chicago:Producers=Produttori,
+ chicago:Director=Direttore,
+ chicago:Directors=Direttori,
+ chicago:Recordedby={Registrato da},
+ chicago:Author=Autore,
+ chicago:Translator={Trad.}, % Translator(s)
+ chicago:Advanced={Pre-pubblicazione on line},
+ chicago:Retrieved={Accessible online}]
+
+\setupbtxlabeltext
+ [es]
+ [chicago:number={Nº},
+ chicago:edition={ed.}, % edición
+ chicago:Editor=Editor, % Ed./Eds.
+ chicago:Editors=Editores,
+ chicago:Volume={Vol.}, % Volumen
+ chicago:Volumes={Vols.}, % Volúmenes
+ chicago:nd={s.f.}, % sin fecha
+ chicago:supplement=Suplemento,
+ chicago:MotionPicture=Cinematográfica,
+ chicago:Writer=Guionista, % ?
+ chicago:Writers=Escritores, % ?
+ chicago:Producer=Productor,
+ chicago:Producers=Productores,
+ chicago:Director=Director,
+ chicago:Directors=Directores,
+ chicago:Recordedby={Grabada por},
+ chicago:Author=Autor,
+ chicago:Translator=Traductor,
+ chicago:Advanced={Publicación en línea avanzada},
+ chicago:Retrieved={Obtenido de}] % {Disponible desde}]
+
+
+\setupbtxlabeltext
+ [sv]
+ [chicago:number={nr.},
+ chicago:edition={Utgåva},
+ chicago:Editor=Redaktör,
+ chicago:Editors=Redaktörer,
+ chicago:Volume=Band,
+ chicago:Volumes=Band,
+ chicago:nd={u.å.}, % utan årtal
+ chicago:supplement=Bilaga, % Supplement
+ chicago:MotionPicture=Spelfilm, % ?
+ chicago:Writer={Manusförfattare}, % Assuming for a movie
+ chicago:Writers={Manusförfattare}, %
+ chicago:Producer=Producent, % Assuming for a movie
+ chicago:Producers=Producenter, %
+ chicago:Director={Regissör}, % Assuming for a movie
+ chicago:Directors={Regissörer}, %
+ chicago:Recordedby={Inspelad av}, % Assuming for a movie
+ chicago:Author={Författare},
+ chicago:Translator={Översättare},
+ chicago:Advanced={Avancerad onlinepublikation}, % ?
+ chicago:Retrieved={Hämtad från}]
+
+% cite setups
+
+% The following differs from the default returning n.d. if year is empty
+
+\startsetups btx:chicago:cite:author:year
+ \ifx\currentbtxfirst\empty
+ \def\currentbtxfirst{\fastsetup{\s!btx:chicago:nd}}
+ \fi
+ \fastsetup{\s!btx:\s!cite:author:year}
+\stopsetups
+
+\startsetups btx:chicago:cite:author:years
+ \ifx\currentbtxfirst\empty
+ \def\currentbtxfirst{\fastsetup{\s!btx:chicago:nd}}
+ \fi
+ \fastsetup{\s!btx:\s!cite:author:years}
+\stopsetups
+
+% these setups need to be explicitly defined in order to get cite rendering
+
+\startsetups \s!btx:chicago:\s!cite:organization
+ \fastsetup{\s!btx:\s!cite:normal}
+\stopsetups
+
+\startsetups \s!btx:chicago:\s!cite:subtitle
+ \fastsetup{\s!btx:\s!cite:normal}
+\stopsetups
+
+\startsetups \s!btx:chicago:\s!cite:booktitle
+ \fastsetup{\s!btx:\s!cite:normal}
+\stopsetups
+
+\startsetups \s!btx:chicago:\s!cite:subbooktitle
+ \fastsetup{\s!btx:\s!cite:normal}
+\stopsetups
+
+% are these needed?
+
+\startsetups \s!btx:chicago:\s!cite:title:inbook
+ \fastsetup{\s!btx:\s!cite:normal}
+\stopsetups
+
+\startsetups \s!btx:chicago:\s!cite:title:incollection
+ \fastsetup{\s!btx:\s!cite:normal}
+\stopsetups
+
+\startsetups \s!btx:chicago:\s!cite:title:inproceedings
+ \fastsetup{\s!btx:\s!cite:normal}
+\stopsetups
+
+\startsetups \s!btx:chicago:\s!cite:subtitle:inbook
+ \fastsetup{\s!btx:\s!cite:normal}
+\stopsetups
+
+\startsetups \s!btx:chicago:\s!cite:subtitle:incollection
+ \fastsetup{\s!btx:\s!cite:normal}
+\stopsetups
+
+\startsetups \s!btx:chicago:\s!cite:subtitle:inproceedings
+ \fastsetup{\s!btx:\s!cite:normal}
+\stopsetups
+
+% used in publ-imp-page.mkvi
+
+\startsetups btx:chicago:list:page-or-pages
+ \ifx\currentbtxlastpage\empty
+ \btxlabeltext{p}
+ \else
+ \btxlabeltext{pp}
+ \fi
+ \btxnbsp
+\stopsetups
+
+% The sameauthor feature may not be Chicago compliant
+% (there is nothing in the manual cited above).
+% It can be removed using the command:
+% \resetsetups [chicago:list:sameauthor]
+
+% :rule, :empty or :ditto ...
+
+\startsetups chicago:list:sameauthor
+ \fastsetup{chicago:list:sameauthor:rule}
+\stopsetups
+
+\startsetups chicago:list:sameauthor:rule
+ \blackrule
+ [\c!width=3em,
+ \c!height=1.5\linewidth]% \linewidth is just too thin with respect to font strokes...
+\stopsetups
+
+\startsetups [chicago:list:sameauthor:\v!empty]
+ \kern\dimexpr\listparameter\c!margin-\interwordspace\relax
+\stopsetups
+
+% horrible !
+
+\startsetups chicago:list:sameauthor:ditto
+ \inframed
+ [\c!width=\dimexpr\listparameter\c!margin-\interwordspace\relax,
+ \c!frame=\v!off,
+ \c!align=\v!middle]
+ {\doubleprime}
+\stopsetups
+
+%D Instead of texdefinitions without arguments, we could have used setups but in my
+%D editor (hh, scite) the commands stand out better. It also saves an additional
+%D component in the name (e.g. common:) because commands and setups have a different
+%D namespace, so similar calls don't clash. Performance of definitions is somewhat
+%D better.
+
+%D We use "texdefinitions" (with eventual arguments) for helpers that are used
+%D in the rendering "setups" defined for each category below.
+
+%D Note that \btxdoif... and \btxflush rely on the definitions in
+%D publ-imp-chicago.lua: fields that are not listed as required nor optional are
+%D IGNORED. We also make heavy use of the notion of sets - comma-separated lists
+%D of alternative fields to be used in hierarchal order. For example:
+%D author = { "author", "editor", "publisher", "title" }, will return the
+%D author field if it exists; if not, the editor field will be returned, if it
+%D exists; if not, the publisher field will be returned, if it exists; if not,
+%D the title field will be returned, it it exists; if not, nothing will be
+%D returned. In lua syntax, it can be understood as
+%D author or editor or publisher or title or ""
+
+% #title can be title or booktitle
+
+\starttexdefinition unexpanded btx:chicago:translated-title #title
+ \ifx\currentbtxlanguage\empty
+ % no need for an extra
+ \else\ifx\mainbtxlanguage\currentbtxlanguage
+ % no need for an extra
+ \else
+ \btxdoif {#title:\mainbtxlanguage} {
+ \begingroup
+ \language[\mainbtxlanguage]
+ \btxleftbracket
+ \btxusecommand [chicago:\s!list:#title:\currentbtxcategory] {
+ \btxflush{#title:\mainbtxlanguage}
+ }
+ \btxrightbracket
+ \endgroup
+ }
+ \fi\fi
+\stoptexdefinition
+
+\starttexdefinition unexpanded btx:chicago:composed-title #title
+ \btxstartstyleandcolor[chicago:\s!list:#title:\currentbtxcategory]
+ \begingroup
+ \language[\currentbtxlanguage]
+ \btxusecommand [chicago:\s!list:#title:\currentbtxcategory] {
+ \btxflush{#title}
+ \btxdoif {sub#title} {
+ \btxcolon
+ \btxflush{sub#title}
+ }
+ }
+ \endgroup
+ % which namespace?
+ %\doif{\btxparameter{translate}}\v!yes {
+ \texdefinition{btx:chicago:translated-title}{#title}
+ %}
+ \btxstopstyleandcolor
+\stoptexdefinition
+
+\starttexdefinition unexpanded btx:chicago:title
+ \setmode{btx:chicago:title-placed}
+ % we make the title active, opening "file"
+ \btxdoifelse {file} {
+ \texdefinition{btx:format:inject}
+ {url(file:\btxflush{file})}
+ {
+ \texdefinition{btx:chicago:composed-title}{title}
+ }
+ } {
+ \texdefinition{btx:chicago:composed-title}{title}
+ }
+ \btxdoif {title} {
+ % A book might have an editor AND an author
+ \doif {\currentbtxcategory} {book} {
+ \doifnot {\btxfoundname{author}} {editor} {
+ \btxdoif {ineditor} { % ineditor specific authorconversion
+ \btxleftparenthesis
+ \btxflush{ineditor}
+ \btxcomma
+ \btxsingularorplural {ineditor} {
+ \btxlabeltext{chicago:Editor}
+ } {
+ \btxlabeltext{chicago:Editors}
+ }
+ \btxrightparenthesis
+ }
+ }
+ }
+ \btxdoif {translator} {
+ \btxleftparenthesis
+ \btxflush{translator}
+ \btxcomma
+ \btxlabeltext{chicago:Translator}
+ \btxrightparenthesis
+ }
+ \btxperiod
+ % TODO: this period may NOT be wanted, as in: Title (2nd ed.).
+ }
+\stoptexdefinition
+
+\starttexdefinition unexpanded btx:chicago:title-if-not-placed
+ \doifelsemode {btx:chicago:title-placed} {
+ \resetmode{btx:chicago:title-placed}
+ } {
+ \btxdoif {title} {
+ \btxspace
+ \texdefinition {btx:chicago:title}
+ }
+ }
+\stoptexdefinition
+
+\startsetups btx:chicago:nd
+ \btxlabeltext{chicago:nd}
+\stopsetups
+
+\starttexdefinition unexpanded btx:chicago:suffixedyear
+ \btxdoifelse {year} {
+ \btxflush{year}
+ \btxflushsuffix
+ \btxdoif {month} { % month and day optional in publ-imp-chicago.lua
+ \btxcomma
+ \btxflush{month}
+ \btxdoif {day} {
+ \btxspace
+ \btxflush{day}
+ }
+ }
+ } {
+ \fastsetup{btx:chicago:nd}
+ % Hans: the following won't work but should.
+ \btxdoif {suffix} {
+ \btxspace
+ \btxflushsuffix
+ % Hans: similarly, why can't \btxflush{suffix} be made to work?
+ }
+ }
+\stoptexdefinition
+
+% #author may be author(set) or editor
+
+\starttexdefinition unexpanded btx:chicago:author-or-editor #author
+ \btxdoifelse {#author} {
+ \btxstartstyleandcolor[chicago:\s!list:#author]
+ \btxusecommand[chicago:\s!list:#author]{
+ \btxflush{#author}
+ }
+ \btxstopstyleandcolor
+ % use \processaction [] [] here?
+ \doifelse {\btxfoundname{#author}} {editor} {
+ \btxleftparenthesis
+ \btxsingularorplural {editor} {
+ \btxlabeltext{chicago:Editor}
+ } {
+ \btxlabeltext{chicago:Editors}
+ }
+ \btxrightparenthesis
+ } {\doif {\btxfoundname{#author}} {ineditor} {
+ \btxleftparenthesis
+ \btxsingularorplural {ineditor} {
+ \btxlabeltext{chicago:Editor}
+ } {
+ \btxlabeltext{chicago:Editors}
+ }
+ \btxrightparenthesis
+ } }
+ \doif {\currentbtxcategory} {film} {
+ \btxleftparenthesis
+ \doifelse {\btxfoundname{#author}} {director} {
+ \btxsingularorplural {director} {
+ \btxlabeltext{chicago:Director}
+ } {
+ \btxlabeltext{chicago:Directors}
+ }
+ } {
+ \doif {\btxfoundname{#author}} {author} {
+ \btxsingularorplural {author} {
+ \btxlabeltext{chicago:Writer}
+ } {
+ \btxlabeltext{chicago:Writers}
+ }
+ }
+ \doif {\btxfoundname{#author}} {producer} {
+ \btxsingularorplural {producer} {
+ \btxlabeltext{chicago:Producer}
+ } {
+ \btxlabeltext{chicago:Producers}
+ }
+ }
+ \btxdoif {director} {
+ \btxrightparenthesis
+ \removeunwantedspaces
+ \btxparameter{\c!separator:names:3}
+ \btxstartstyleandcolor[chicago:\s!list:director]
+ \btxusecommand[chicago:\s!list:director]{
+ \btxflush{director}
+ }
+ \btxstopstyleandcolor
+ \btxleftparenthesis
+ \btxsingularorplural {director} {
+ \btxlabeltext{chicago:Director}
+ } {
+ \btxlabeltext{chicago:Directors}
+ }
+ }
+ }
+ \btxrightparenthesis
+ }
+ \btxdoif {withauthor} {
+ \btxleftparenthesis
+ \btxlabeltext{with}
+ \btxspace
+ \btxstartstyleandcolor[chicago:\s!list:withauthor]
+ \btxusecommand[chicago:\s!list:withauthor]{
+ \btxflush{withauthor}
+ }
+ \btxstopstyleandcolor
+ \btxrightparenthesis
+ }
+ } {
+ \texdefinition{btx:chicago:title}
+ }
+\stoptexdefinition
+
+\starttexdefinition unexpanded btx:chicago:authoryear
+ % we make the authoryear active, pointing to the citation
+ \texdefinition{btx:format:inject}
+ {internal(\currentbtxinternal)}
+ {
+ \doifelsesetups{chicago:list:sameauthor} {
+ \btxdoifelsesameasprevious {author} {
+ \fastsetup{chicago:list:sameauthor}
+ } {
+ \texdefinition{btx:chicago:author-or-editor} {author}
+ }
+ } {
+ \texdefinition{btx:chicago:author-or-editor} {author}
+ }
+ \texdefinition{btx:chicago:suffixedyear}
+ }
+ % outside of interaction
+ \btxperiod
+ \doif {\btxfoundname{author}} {title} {
+ \setmode{btx:chicago:title-placed}
+ }
+\stoptexdefinition
+
+\starttexdefinition unexpanded btx:chicago:editor-in
+ \btxdoif {booktitle} {
+ \btxlabeltext{In}
+ \btxspace
+ \doifnot {\btxfoundname{author}} {editor} {
+ \texdefinition{btx:chicago:author-or-editor} {ineditor}
+ \btxcomma
+ }
+ \texdefinition{btx:chicago:composed-title}{booktitle}
+ \btxperiod
+ }
+\stoptexdefinition
+
+\starttexdefinition unexpanded btx:chicago:organization-if-not-author
+ \btxdoif {organization} {
+ \doifnot {\btxfoundname{author}} {organization} {
+ \btxspace
+ \btxflush{organization}
+ \btxcomma
+ }
+ }
+\stoptexdefinition
+
+% TODO: The title is terminated with period. However,
+% we probably don't want this before the parenthesis.
+
+\starttexdefinition unexpanded btx:chicago:leftparenthesis-or-comma
+ \doifelsemode {btx:chicago:editionset-is-empty} {
+ \btxleftparenthesis
+ \resetmode{btx:chicago:editionset-is-empty}
+ } {
+ \btxcomma
+ }
+\stoptexdefinition
+
+\starttexdefinition unexpanded btx:chicago:editionset
+ \setmode{btx:chicago:editionset-is-empty}
+ \doif {\currentbtxcategory} {techreport} {
+ \texdefinition{btx:chicago:leftparenthesis-or-comma}
+ \btxdoifelse {type} {
+ \btxusecommand [chicago:\s!list:type] {
+ \btxflush{type}
+ }
+ } {
+ \btxlabeltext{technicalreport}
+ }
+ }
+ \btxdoif {volume} {
+ \texdefinition{btx:chicago:leftparenthesis-or-comma}
+ \btxoneorrange {volume} {
+ \btxlabeltext{chicago:Volume}
+ } {
+ \btxlabeltext{chicago:Volumes}
+ }
+ \btxspace
+ \btxflush{volume}
+ }
+ \btxdoif {number} {
+ \texdefinition{btx:chicago:leftparenthesis-or-comma}
+ \btxlabeltext{chicago:number}
+ \btxspace
+ \btxflush{number}
+ }
+ \btxdoif {edition} {
+ \texdefinition{btx:chicago:leftparenthesis-or-comma}
+ \btxflush{edition}
+ \btxspace
+ \btxlabeltext{chicago:edition}
+ }
+ \btxdoif {pages} {
+ \texdefinition{btx:chicago:leftparenthesis-or-comma}
+ \btxoneorrange {pages} {
+ \btxlabeltext{p}
+ } {
+ \btxlabeltext{pp}
+ }
+ \btxnbsp
+ \btxflush{pages}
+ }
+ \doifnotmode {btx:chicago:editionset-is-empty} {
+ \btxrightparenthesisperiod
+ }
+\stoptexdefinition
+
+\starttexdefinition unexpanded btx:chicago:journal
+ \btxstartstyleandcolor[chicago:\s!list:journal]
+ \btxusecommand [chicago:\s!list:journal] {
+ \btxflush{journal}
+ }
+ \btxstopstyleandcolor
+\stoptexdefinition
+
+\starttexdefinition unexpanded btx:chicago:volume
+ \btxstartstyleandcolor[chicago:\s!list:volume]
+ \btxflush{volume}
+ \btxstopstyleandcolor
+\stoptexdefinition
+
+ % this could be simplified!
+
+\starttexdefinition unexpanded btx:chicago:journal-volume-number-pages
+ \btxdoif {journal} {
+ \btxspace
+ \texdefinition{btx:chicago:journal}
+ \btxdoifelse {volume} {
+ \btxcomma
+ \texdefinition{btx:chicago:volume}
+ \btxdoif {number} {
+ %\btxleftparenthesis
+ (\btxflush{number}
+ \btxrightparenthesis
+ }
+ } {
+ \btxdoif {number} {
+ \btxcomma
+ \btxleftparenthesis
+ \btxflush{number}
+ \btxrightparenthesis
+ }
+ }
+ \btxdoif {pages} {
+ \btxcomma
+ \doif {\currentbtxcategory} {newspaper} {
+ \btxoneorrange {pages} {
+ \btxlabeltext{p}
+ } {
+ \btxlabeltext{pp}
+ }
+ \btxnbsp
+ }
+ \btxflush{pages}
+ }
+ \btxperiod
+ \doifnot {\currentbtxcategory} {newspaper} {
+ \btxdoifnot {volume} {
+ \btxdoifnot {number} {
+ \btxdoifnot {pages} {
+ \btxdoif {doi} {%set: doi or url
+ \btxspace
+ \btxlabeltext{chicago:Advanced}
+ \btxperiod
+ }
+ }
+ }
+ }
+ }
+ }
+\stoptexdefinition
+
+\starttexdefinition unexpanded btx:chicago:wherefrom-publisher
+ \btxdoifelse {address} {
+ \btxflush{address}
+ \btxdoif {country} {
+ \btxcomma
+ \btxflush{country}
+ }
+ \btxcolon
+ } {
+ \btxdoif {country} {
+ \btxflush{country}
+ \btxcolon
+ }
+ }
+ \doifelse {\btxfoundname{author}} {\btxfoundname{publisher}} {
+ \btxlabeltext{chicago:Author}
+ } {
+ \btxdoifelse {publisher} {
+ \btxflush{publisher}
+ } {
+ \btxlabeltext{chicago:Author}
+ }
+ }
+ \btxperiod
+\stoptexdefinition
+
+\definebreakpoints[doi]
+\definebreakpoint [doi][:][nleft=3,type=1]
+\definebreakpoint [doi][/][nleft=3,type=1]
+\definebreakpoint [doi][-][nleft=3,type=1]
+\definebreakpoint [doi][.][nleft=3,type=1]
+
+% use \btxentry here?
+
+\starttexdefinition unexpanded btx:chicago:url
+ \begingroup
+ \setbreakpoints[doi]
+ \ifconditional\btxinteractive
+ \goto {
+ \hyphenatedurl{\btxflush{url}}
+ } [
+ url(\btxflush{url})
+ ]
+ \else
+ \hyphenatedurl{\btxflush{url}}
+ \fi
+ \endgroup
+\stoptexdefinition
+
+% use \btxentry here?
+
+\starttexdefinition unexpanded btx:chicago:doi
+ \begingroup
+ \setbreakpoints[doi]
+ \ifconditional\btxinteractive
+ \goto {
+ \hyphenatedurl{doi:\btxflush{doi}}
+ } [
+ url(http://dx.doi.org/\btxflush{doi})
+ ]
+ \else
+ \hyphenatedurl{doi:\btxflush{doi}}
+ \fi
+ \endgroup
+\stoptexdefinition
+
+\starttexdefinition unexpanded btx:chicago:note
+ \btxdoif {note} {
+ \btxleftparenthesis
+ \btxflush{note}
+ \btxrightparenthesis
+ }
+\stoptexdefinition
+
+\starttexdefinition unexpanded btx:chicago:url-doi-note
+ \doif {\btxfoundname{doi}} {url} {
+ \btxspace
+ \btxlabeltext{chicago:Retrieved}
+ \btxspace
+ \texdefinition{btx:chicago:url}
+ }
+ \doif {\btxfoundname{doi}} {doi} {
+ \btxspace
+ \texdefinition{btx:chicago:doi}
+ }
+ \texdefinition{btx:chicago:note}
+ \removeunwantedspaces
+\stoptexdefinition
+
+\starttexdefinition unexpanded btx:chicago:type
+ \btxdoif {type} {
+ \btxleftbracket
+ \btxflush{type}
+ \btxrightbracketperiod
+ }
+\stoptexdefinition
+
+% Then setups, by category
+
+% An article from a journal
+% Required fields: author or organization or editor or title, journal, (year).
+% Optional fields: volume, number, pages, type, doi, url, note.
+% Note that bibtex (and tools) do not include editor (e.g. special issue or section)
+
+\startsetups btx:chicago:list:article
+ \texdefinition{btx:chicago:authoryear}
+ \texdefinition{btx:chicago:title-if-not-placed}
+ \texdefinition{btx:chicago:type}
+ \texdefinition{btx:chicago:journal-volume-number-pages}
+ \texdefinition{btx:chicago:url-doi-note}
+\stopsetups
+
+% An article from a magazine.
+% Required fields: author or title, journal, (year).
+% Optional fields: number, pages, type, month, day, doi, url, note.
+
+\startsetups btx:chicago:list:magazine
+ \fastsetup{btx:chicago:list:article}
+\stopsetups
+
+% An article from a newspaper.
+% Required fields: author or title, journal, (year).
+% Optional fields: volume, number, pages, type, month, day, doi, url, note.
+
+\startsetups btx:chicago:list:newspaper
+ \fastsetup{btx:chicago:list:article}
+\stopsetups
+
+% A complete issue of a periodical, such as a special issue of a journal.
+% Required fields: title, year
+% Optional fields: editor, publisher, subtitle, series, volume, number, month, organization, doi, url, issn, note
+
+% needs to be tuned...
+
+\startsetups btx:chicago:list:periodical
+ \fastsetup{btx:chicago:list:article}
+\stopsetups
+
+% National and international standards issued by a standards body
+% Required fields: author, institution, or organization, year, title
+% Optional fields: subtitle, doi, url, note
+
+\startsetups btx:chicago:list:standard
+ \texdefinition{btx:chicago:authoryear}
+ \texdefinition{btx:chicago:title-if-not-placed}
+ \texdefinition{btx:chicago:url-doi-note}
+\stopsetups
+
+% A book with an explicit publisher.
+% Required fields: author or editor or publisher, title, (year).
+% Optional fields: volume or number, series, address, edition, month, day, note.
+% Chicago ignores: month, day
+
+% todo: series?
+
+\startsetups btx:chicago:list:book
+ \texdefinition{btx:chicago:authoryear}
+ \texdefinition{btx:chicago:title-if-not-placed}
+ \texdefinition{btx:chicago:type}
+ \texdefinition{btx:chicago:editionset}
+ \texdefinition{btx:chicago:wherefrom-publisher}
+ \texdefinition{btx:chicago:url-doi-note}
+\stopsetups
+
+% There is some debate about how inbook should differ from incollection
+
+% A part of a book, which may be a chapter (or section or whatever) and/or a range of pages.
+% (note that inbook is handled differently by bibtex and biblatex)
+% Required fields: author or editor, title, chapter and/or pages, publisher, year.
+% Optional fields: volume or number, series, type, address, edition, month, note.
+% We add optional: booktitle.
+% Chicago ignores: chapter, month
+
+\startsetups btx:chicago:list:inbook
+ \texdefinition{btx:chicago:authoryear}
+ \texdefinition{btx:chicago:title-if-not-placed}
+ \texdefinition{btx:chicago:type}
+ \texdefinition{btx:chicago:editor-in}
+ \texdefinition{btx:chicago:editionset}
+ \texdefinition{btx:chicago:wherefrom-publisher}
+ \texdefinition{btx:chicago:url-doi-note}
+\stopsetups
+
+% A part of a book having its own title.
+% Required fields: author, title, booktitle, publisher, year.
+% Optional fields: editor, volume or number, series, type, chapter, pages, address, edition, month, note.
+% Chicago ignores: chapter, month
+
+\startsetups btx:chicago:list:incollection
+ \fastsetup{btx:chicago:list:inbook}
+\stopsetups
+
+% The proceedings of a conference.
+% Required fields: title, year.
+% Optional fields: editor, volume or number, series, address, month, organization, publisher, note.
+% todo: series?
+
+\startsetups btx:chicago:list:proceedings
+ \fastsetup{btx:chicago:list:book}
+\stopsetups
+
+% An article in a conference proceedings.
+% Required fields: author, title, booktitle, year.
+% Optional fields: editor, volume or number, series, pages, address, month, organization, publisher, note.
+
+\startsetups btx:chicago:list:inproceedings
+ \texdefinition{btx:chicago:authoryear}
+ \texdefinition{btx:chicago:title-if-not-placed}
+ \texdefinition{btx:chicago:editor-in}
+ \texdefinition{btx:chicago:editionset}
+ \texdefinition{btx:chicago:organization-if-not-author}
+ \texdefinition{btx:chicago:wherefrom-publisher}
+ \texdefinition{btx:chicago:url-doi-note}
+\stopsetups
+
+\startsetups btx:chicago:list:conference
+ \fastsetup{btx:chicago:list:inproceedings}
+\stopsetups
+
+% A thesis.
+% Required fields: author, title, school, year.
+% Optional fields: type, address, month, note.
+
+\startsetups btx:chicago:list:thesis
+ \texdefinition{btx:chicago:authoryear}
+ \texdefinition{btx:chicago:title-if-not-placed}
+ \btxleftparenthesis
+ \btxdoifelse {type} {
+ \btxusecommand [chicago:\s!list:type] {
+ \btxflush{type}
+ }
+ } {
+ \btxlabeltext{\currentbtxcategory}
+ }
+ \btxrightparenthesis
+ \btxdoif {school} {
+ \btxperiod
+ \btxflush{school}
+ }
+ \btxdoif {address} {
+ \btxdoifelse {school} {
+ \btxcomma
+ } {
+ \btxperiod
+ }
+ \btxflush{address}
+ \btxdoif {country} {
+ \btxcomma
+ \btxflush{country}
+ }
+ }
+ \btxperiod
+ \texdefinition{btx:chicago:url-doi-note}
+\stopsetups
+
+\startsetups btx:chicago:list:phdthesis
+ \fastsetup{btx:chicago:list:thesis}
+\stopsetups
+
+\startsetups btx:chicago:list:mastersthesis
+ \fastsetup{btx:chicago:list:thesis}
+\stopsetups
+
+% A work that is printed and bound, but without a named publisher or sponsoring institution.
+% Required field: title.
+% Optional fields: author, howpublished, address, month, year, note.
+
+\startsetups btx:chicago:list:booklet
+ \fastsetup{btx:chicago:list:book}
+\stopsetups
+
+% Technical documentation.
+% Required field: title.
+% Optional fields: author, organization, address, edition, month, year, note.
+
+\startsetups btx:chicago:list:manual
+ \fastsetup{btx:chicago:list:book}
+\stopsetups
+
+% A report published by a school or other institution, usually numbered within a series.
+% Required fields: author, title, institution, year.
+% Optional fields: type, number, address, month, note.
+
+\startsetups btx:chicago:list:techreport
+ \fastsetup{btx:chicago:list:book}
+\stopsetups
+
+% A document having an author and title, but not formally published.
+% Required fields: author, title, note.
+% Optional fields: month, year.
+
+\startsetups btx:chicago:list:unpublished
+ \fastsetup{btx:chicago:list:book}
+\stopsetups
+
+% A patent. Note that this category was not defined with BIBTEX. Below from JabRef:
+% Required fields: nationality, number, year, yearfiled
+% Optional fields: author, title, assignee, address, type, number, day, dayfiled, month, monthfiled, note, url
+% Also optional: publisher
+
+% todo: yearfiled, monthfiled, dayfiled
+
+\startsetups btx:chicago:list:patent
+ \texdefinition{btx:chicago:authoryear}
+ \texdefinition{btx:chicago:title-if-not-placed}
+ \begingroup
+ \it
+ \btxdoif {nationality} {
+ \btxspace
+ \btxflush{nationality}
+ }
+ \btxspace
+ \btxdoifelse{type}{
+ \btxflush{type}
+ }{
+ \btxlabeltext{patent}
+ }
+ \btxdoif {number} {
+ \btxspace
+ \btxlabeltext{chicago:number}
+ \btxspace
+ \btxflush{number}
+ }
+ \btxperiod
+ \italiccorrection
+ \endgroup
+ \texdefinition{btx:chicago:wherefrom-publisher}
+ \texdefinition{btx:chicago:url}
+ \texdefinition{btx:chicago:note}
+\stopsetups
+
+% Electronic. Note that this category was not defined with BIBTEX. Below from JabRef:
+% Required fields: title
+% Optional fields: address, author, howpublished, month, note, organization, url, year, doi
+% Also optional: type
+
+% Like Misc below but includes organization.
+
+\startsetups btx:chicago:list:electronic
+ \texdefinition{btx:chicago:authoryear}
+ \texdefinition{btx:chicago:title-if-not-placed}
+ \texdefinition{btx:chicago:type}
+ \texdefinition{btx:chicago:organization-if-not-author}
+ \btxdoif {howpublished} {
+ \btxspace
+ \btxflush{howpublished}
+ \btxperiod
+ }
+ \texdefinition{btx:chicago:url-doi-note}
+\stopsetups
+
+% Film. Note that this category was not defined with BIBTEX.
+% Required fields: producer, director, title, year, address, publisher
+% Optional fields: subtitle, type, note, url, doi
+
+\startsetups btx:chicago:list:film
+ \texdefinition{btx:chicago:authoryear}
+ \texdefinition {btx:chicago:title}
+ \btxleftbracket
+ \btxdoifelse {type} {
+ \btxflush{type}
+ } {
+ \btxlabeltext{chicago:MotionPicture}
+ }
+ \btxrightbracketperiod
+ \texdefinition{btx:chicago:wherefrom-publisher}
+ \texdefinition{btx:chicago:url-doi-note}
+\stopsetups
+
+% Music. Note that this category was not defined with BIBTEX.
+% Required fields: composer, artist, title, album, year, address, publisher
+% Optional fields: subtitle, type, note, url, doi
+
+\startsetups btx:chicago:list:music
+ \texdefinition{btx:chicago:authoryear}
+ \texdefinition{btx:chicago:title-if-not-placed}
+ \doifnot {\btxfoundname{author}} {artist} {
+ \btxdoif {artist} {
+ \btxleftbracket
+ \btxlabeltext{chicago:Recordedby}
+ \btxspace
+ \btxflush{artist}
+ \btxrightbracketperiod
+ }
+ }
+ \doifnot {\btxfoundname{title}} {album} {
+ \btxdoif {album} {
+ \btxlabeltext{In}
+ \btxspace
+ \btxflush{album}
+ \btxperiod
+ }
+ }
+ \texdefinition{btx:chicago:type}
+ \texdefinition{btx:chicago:wherefrom-publisher}
+ \texdefinition{btx:chicago:url-doi-note}
+\stopsetups
+
+% Other. Note that this category was not defined with BIBTEX. Below from JabRef:
+% Required fields: author or title, year
+% Optional fields: note, doi, url
+
+\startsetups btx:chicago:list:other
+ \fastsetup{btx:chicago:list:book}
+\stopsetups
+
+% Use this category when nothing else fits.
+% Required fields: none.
+% Optional fields: author, title, howpublished, month, year, note.
+
+\startsetups btx:chicago:list:misc
+ \texdefinition{btx:chicago:authoryear}
+ \texdefinition{btx:chicago:title-if-not-placed}
+ \btxdoif {howpublished} {
+ \btxspace
+ \btxflush{howpublished}
+ \btxperiod
+ }
+ \texdefinition{btx:chicago:url-doi-note}
+\stopsetups
+
+% If all else fails to match:
+
+\startsetups btx:chicago:list:literal
+ %\btxleftparenthesis
+ \removeunwantedspaces(
+ \btxflush{tag}
+ \btxrightparenthesis
+ \btxdoif {text} {
+ \btxflush{text}
+ }
+\stopsetups
+
+% HH: an example of setting up translations using a sub rendering. Keep it here
+% till we find another spot as otherwise I forget about it and I don't want to
+% waste hours reinventing a wheel when something like this is needed.
+%
+% \definebtx
+% [chicago:cite:title:translated]
+% [chicago:cite:title]
+% [left=\btxleftbracket,
+% right=\btxrightbracket,
+% style=\v!bolditalic]
+%
+% \startsetups btx:chicago:cite:title
+% % need to add concat, etc.
+% \btxcitereference
+% \currentbtxfirst
+% \doifmode {btx:chicago:translatedtitles} {
+% \ifx\currentbtxlanguage\empty
+% % no need for an extra
+% \else\ifx\mainbtxlanguage\currentbtxlanguage
+% % no need for an extra
+% \else
+% \btxdoif {title:\mainbtxlanguage} {
+% \btxstartciterendering[title:translated]
+% \language[\mainbtxlanguage]
+% \btxflush{title:\mainbtxlanguage}
+% \btxstopciterendering
+% }
+% \fi\fi
+% }
+% \stopsetups
+
+\stopbtxrenderingdefinitions
diff --git a/Master/texmf-dist/tex/context/base/mkiv/publ-imp-cite.mkvi b/Master/texmf-dist/tex/context/base/mkiv/publ-imp-cite.mkvi
index 56af83a1b15..3a01b219a65 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/publ-imp-cite.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/publ-imp-cite.mkvi
@@ -168,6 +168,12 @@
\fastsetup{\s!btx:\s!cite:righttext}
\stopsetups
+\startsetups \s!btx:\s!cite:footnote
+ \startfootnote
+ \fastsetup{btx:cite:entry}
+ \stopfootnote
+\stopsetups
+
% these three are goodies to get something but are not set up as it makes no
% sense to have something root for combinations like this (esp not because one
% gets default anyway
diff --git a/Master/texmf-dist/tex/context/base/mkiv/publ-ini.lua b/Master/texmf-dist/tex/context/base/mkiv/publ-ini.lua
index f62352f07f0..da6c74b2e46 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/publ-ini.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/publ-ini.lua
@@ -43,7 +43,7 @@ local trace = false trackers.register("publications",
local trace_cite = false trackers.register("publications.cite", function(v) trace_cite = v end)
local trace_missing = false trackers.register("publications.cite.missing", function(v) trace_missing = v end)
local trace_references = false trackers.register("publications.cite.references", function(v) trace_references = v end)
-local trace_detail = false trackers.register("publications.detail", function(v) trace_detail = v end)
+local trace_details = false trackers.register("publications.details", function(v) trace_details = v end)
local trace_suffixes = false trackers.register("publications.suffixes", function(v) trace_suffixes = v end)
publications = publications or { }
@@ -456,7 +456,7 @@ do
end
end
end
- if trace_detail then
+ if trace_details then
report("%s unique references, %s reused entries",nofunique,nofreused)
end
initialize = nil
@@ -502,13 +502,18 @@ local findallused do
local luadata = current.luadata
local details = current.details
local ordered = current.ordered
- if allused then
+ if allused then -- always true
local registered = { }
local function register(tag)
local entry = forcethem and luadata[tag]
if entry then
if registered[tag] then
+ if trace_cite then
+ report_cite("dataset: %s, tag: %s, state: %s",dataset,tag,"already cited (1)")
+ end
return
+ elseif trace_cite then
+ report_cite("dataset: %s, tag: %s, state: %s",dataset,tag,"okay")
end
okay[#okay+1] = entry
-- todo[tag] = true
@@ -516,6 +521,9 @@ local findallused do
return tag
end
entry = allused[tag]
+ if trace_cite then
+ report_cite("dataset: %s, tag: %s, used: % t",dataset,tag,table.sortedkeys(allused))
+ end
if not entry then
local parent = details[tag].parent
if parent then
@@ -524,9 +532,16 @@ local findallused do
if entry then
report("using reference of parent %a for %a",parent,tag)
tag = parent
+ elseif trace_cite then
+ report_cite("dataset: %s, tag: %s, state: %s",dataset,tag,"not used")
end
+ elseif trace_cite then
+ report_cite("dataset: %s, tag: %s, state: %s",dataset,tag,"used")
end
if registered[tag] then
+ if trace_cite then
+ report_cite("dataset: %s, tag: %s, state: %s",dataset,tag,"already cited (2)")
+ end
return
end
if entry then
@@ -564,7 +579,17 @@ local findallused do
entry = entry[1]
end
end
+ if not entry then
+ report_cite("dataset: %s, tag: %s, state: %s",dataset,tag,"no entry (1)")
+ elseif trace_cite then
+ report_cite("dataset: %s, tag: %s, state: %s",dataset,tag,"new entry")
+ end
okay[#okay+1] = entry
+ elseif not entry then
+ if trace_cite then
+ report_cite("dataset: %s, tag: %s, state: %s",dataset,tag,"no entry (2)")
+ end
+ -- okay[#okay+1] = luadata[tag]
end
todo[tag] = true
registered[tag] = true
@@ -670,7 +695,7 @@ end
local function unknowncite(reference)
ctx_btxsettag(reference)
- if trace_detail then
+ if trace_details then
report("expanding %a cite setup %a","unknown","unknown")
end
ctx_btxcitesetup("unknown")
@@ -693,7 +718,7 @@ local function marknocite(dataset,tag,nofcitations,setup)
ctx_btxsetdataset(dataset)
ctx_btxsettag(tag)
ctx_btxsetbacklink(nofcitations)
- if trace_detail then
+ if trace_details then
report("expanding cite setup %a",setup)
end
ctx_btxcitesetup(setup)
@@ -1453,10 +1478,10 @@ do
local name, value = found(dataset,tag,field,valid,fields)
if value then
typesetters[currentspecification.types[name]](field,value,manipulator)
- elseif trace_detail then
+ elseif trace_details then
report("%s %s %a in category %a for tag %a in dataset %a","unknown","entry",field,category,tag,name)
end
- elseif trace_detail then
+ elseif trace_details then
report("%s %s %a in category %a for tag %a in dataset %a","invalid","entry",field,category,tag,name)
end
else
@@ -1478,10 +1503,10 @@ do
local value = fields[field]
if value then
typesetters[currentspecification.types[field]](field,value,manipulator)
- elseif trace_detail then
+ elseif trace_details then
report("%s %s %a in category %a for tag %a in dataset %a","unknown","field",field,category,tag,name)
end
- elseif trace_detail then
+ elseif trace_details then
report("%s %s %a in category %a for tag %a in dataset %a","invalid","field",field,category,tag,name)
end
else
@@ -1505,10 +1530,10 @@ do
local value = details[field]
if value then
typesetters[currentspecification.types[field]](field,value,manipulator)
- elseif trace_detail then
+ elseif trace_details then
report("%s %s %a in category %a for tag %a in dataset %a","unknown","detail",field,category,tag,name)
end
- elseif trace_detail then
+ elseif trace_details then
report("%s %s %a in category %a for tag %a in dataset %a","invalid","detail",field,category,tag,name)
end
else
@@ -1531,7 +1556,7 @@ do
local value = fields[field]
if value then
context(typesetters.default(field,value,manipulator))
- elseif trace_detail then
+ elseif trace_details then
report("field %a of tag %a in dataset %a has no value",field,tag,name)
end
else
@@ -1590,6 +1615,8 @@ end
do
local patterns = {
+ CONTEXTLMTXMODE > 0 and "symb-imp-%s.mklx" or "",
+ CONTEXTLMTXMODE > 0 and "symb-imp-%s.mkxl" or "",
"publ-imp-%s.mkvi",
"publ-imp-%s.mkiv",
"publ-imp-%s.tex",
@@ -1600,7 +1627,7 @@ do
end
local function action(name,foundname)
- context.input(foundname)
+ context.loadfoundpublicationfile(name,foundname)
end
function publications.loaddefinitionfile(name) -- a more specific name
@@ -1712,7 +1739,6 @@ do
end
end
-
-- tag | listindex | reference | userdata | dataindex
local methods = { }
@@ -1794,7 +1820,7 @@ do
if traced then
local l = traced[tag]
if l then
- l[#l+1] = u.btxint
+ l[#l+1] = u.btxint -- tonumber ?
else
local data = luadata[tag]
local l = { tag, listindex, 0, u, data and data.index or 0 }
@@ -2034,7 +2060,7 @@ do
ctx_btxsetlastinternal(last[2].internal)
ctx_btxsetlastpage(last[1])
end
- if trace_detail then
+ if trace_details then
report("expanding page setup")
end
ctx_btxpagesetup("") -- nothing yet
@@ -2100,12 +2126,12 @@ do
local prealpage = plist.references.realpage
if crealpage ~= prealpage then
if method == v_always or not conditionals.layoutisdoublesided then
- if trace_detail then
+ if trace_details then
report("previous %a, current %a, different page",previous,current)
end
return false
elseif crealpage % 2 == 0 then
- if trace_detail then
+ if trace_details then
report("previous %a, current %a, different page",previous,current)
end
return false
@@ -2125,7 +2151,7 @@ do
sameentry = identical(c_casted,p_casted)
end
end
- if trace_detail then
+ if trace_details then
if sameentry then
report("previous %a, current %a, same entry",previous,current)
else
@@ -2736,7 +2762,7 @@ do
ctx_btxsetfirst("") -- (f_missing(tag))
end
ctx_btxsetconcat(concatstate(i,n))
- if trace_detail then
+ if trace_details then
report("expanding cite setup %a",setup)
end
ctx_btxcitesetup(setup)
@@ -3193,7 +3219,7 @@ do
end
end
ctx_btxsetconcat(concatstate(i,nofcollected))
- if trace_detail then
+ if trace_details then
report("expanding %a cite setup %a","multiple author",setup)
end
ctx_btxsubcitesetup(setup)
@@ -3212,7 +3238,7 @@ do
if suffix then
ctx_btxsetsuffix(entry.suffix)
end
- if trace_detail then
+ if trace_details then
report("expanding %a cite setup %a","single author",setup)
end
ctx_btxcitesetup(setup)
@@ -3384,7 +3410,7 @@ do
function listvariants.default(dataset,block,tag,variant)
ctx_btxsetfirst("?")
- if trace_detail then
+ if trace_details then
report("expanding %a list setup %a","default",variant)
end
ctx_btxnumberingsetup("default")
@@ -3392,7 +3418,7 @@ do
function listvariants.num(dataset,block,tag,variant,listindex)
ctx_btxsetfirst(listindex)
- if trace_detail then
+ if trace_details then
report("expanding %a list setup %a","num",variant)
end
ctx_btxnumberingsetup(variant or "num")
@@ -3403,7 +3429,7 @@ do
function listvariants.index(dataset,block,tag,variant,listindex)
local index = getdetail(dataset,tag,"index")
ctx_btxsetfirst(index or "?")
- if trace_detail then
+ if trace_details then
report("expanding %a list setup %a","index",variant)
end
ctx_btxnumberingsetup(variant or "index")
@@ -3411,7 +3437,7 @@ do
function listvariants.tag(dataset,block,tag,variant,listindex)
ctx_btxsetfirst(tag)
- if trace_detail then
+ if trace_details then
report("expanding %a list setup %a","tag",variant)
end
ctx_btxnumberingsetup(variant or "tag")
@@ -3426,7 +3452,7 @@ do
if suffix then
ctx_btxsetsuffix(suffix)
end
- if trace_detail then
+ if trace_details then
report("expanding %a list setup %a","short",variant)
end
ctx_btxnumberingsetup(variant or "short")
diff --git a/Master/texmf-dist/tex/context/base/mkiv/publ-ini.mkiv b/Master/texmf-dist/tex/context/base/mkiv/publ-ini.mkiv
index ead46929d44..996b6d3cab7 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/publ-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/publ-ini.mkiv
@@ -122,6 +122,9 @@
{\pop_macro_currentbtxspecification
\protect}
+\unexpanded\def\loadfoundpublicationfile#1#2% name foundname / not a user command
+ {\input{#2}}
+
\unexpanded\def\loadbtxdefinitionfile [#1]{\clf_btxloaddefinitionfile {#1}}
\unexpanded\def\loadbtxreplacementfile[#1]{\clf_btxloadreplacementfile{#1}}
@@ -1080,7 +1083,7 @@
\relax}
\unexpanded\def\btx_reference_checked
- {\dontleavehmode\hbox\bgroup
+ {\dontleavehmode\hbox\bgroup % \hpack
\btx_reference_indeed
\egroup}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/publ-tra.lua b/Master/texmf-dist/tex/context/base/mkiv/publ-tra.lua
index 81bbc2fd375..80dd143d0bf 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/publ-tra.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/publ-tra.lua
@@ -8,7 +8,7 @@ if not modules then modules = { } end modules ['publ-tra'] = {
-- todo: use context.tt .. more efficient, less code
-local next, type = next, type
+local next, type, rawget = next, type, rawget
local sortedhash = table.sortedhash
local sortedkeys = table.sortedkeys
diff --git a/Master/texmf-dist/tex/context/base/mkiv/regi-ini.lua b/Master/texmf-dist/tex/context/base/mkiv/regi-ini.lua
index 7691e876510..8d4f2bfd5a1 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/regi-ini.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/regi-ini.lua
@@ -16,9 +16,11 @@ runtime.</p>
local commands, context = commands, context
+
+local tostring = tostring
local utfchar = utf.char
local P, Cs, Cc, lpegmatch = lpeg.P, lpeg.Cs, lpeg.Cc, lpeg.match
-local char, gsub, format, gmatch, byte, match = string.char, string.gsub, string.format, string.gmatch, string.byte, string.match
+local char, gsub, format, gmatch, byte, match, lower = string.char, string.gsub, string.format, string.gmatch, string.byte, string.match, string.lower
local next = next
local insert, remove, fastcopy = table.insert, table.remove, table.fastcopy
local concat = table.concat
@@ -103,11 +105,14 @@ local synonyms = { -- backward compatibility list
["pdf"] = "pdfdoc",
+ ["437"] = "ibm",
}
local currentregime = "utf"
local function loadregime(mapping,regime)
+ regime = lower(tostring(regime))
+ regime = synonyms[regime] or synonyms["windows-"..regime] or regime
local name = resolvers.findfile(format("regi-%s.lua",regime)) or ""
local data = name ~= "" and dofile(name)
if data then
@@ -126,8 +131,11 @@ end
local function loadreverse(t,k)
local t = { }
- for k, v in next, mapping[k] do
- t[v] = k
+ local m = mapping[k]
+ if m then
+ for k, v in next, m do
+ t[v] = k
+ end
end
backmapping[k] = t
return t
@@ -141,7 +149,8 @@ regimes.backmapping = backmapping
local function fromregime(regime,line)
if line and #line > 0 then
- local map = mapping[regime and synonyms[regime] or regime or currentregime]
+-- local map = mapping[regime and synonyms[regime] or regime or currentregime]
+ local map = mapping[regime or currentregime]
if map then
line = gsub(line,".",map)
end
@@ -459,3 +468,21 @@ if interfaces then
}
end
+
+-- Actually we can have a function returned from the lookup but we don't
+-- really use this code so I'm in no hurry.
+
+-- if os.getcodepage then
+-- local cod, acp, map
+-- function os.tocodepage(name)
+-- if map == nil then
+-- cod, acp = os.getcodepage()
+-- map = cod and cod ~= 65001 and regimes.toregime
+-- end
+-- return map and map(cod,name) or name
+-- end
+-- else
+-- function os.tocodepage(name)
+-- return name
+-- end
+-- end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/regi-ini.mkiv b/Master/texmf-dist/tex/context/base/mkiv/regi-ini.mkiv
index 532a4db0bfc..0cd9cf89d44 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/regi-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/regi-ini.mkiv
@@ -30,4 +30,8 @@
\unexpanded\def\startregime [#1]{\clf_startregime{#1}}
\unexpanded\def\stopregime {\clf_stopregime}
+% only for diagnostics:
+
+% \def\codepagename#1{\cldcontext{os.tocodepage("#1")}}
+
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/scrn-bar.mkvi b/Master/texmf-dist/tex/context/base/mkiv/scrn-bar.mkvi
index 0c320cd03bf..c089eb94576 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/scrn-bar.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/scrn-bar.mkvi
@@ -129,7 +129,7 @@
\setupcurrentinteractionbar[#settings]%
\d_scrn_bar_width \interactionbarparameter\c!width\relax
\d_scrn_bar_distance\interactionbarparameter\c!distance\relax
- \ifdim\d_scrn_bar_width=\zeropoint
+ \ifzeropt\d_scrn_bar_width
\d_scrn_bar_width1.5\emwidth
\fi
\doifnothing{\interactionbarparameter\c!height}{\letinteractionbarparameter\c!height\v!broad}%
@@ -145,7 +145,7 @@
[ \v!page=>\advance\scratchcounterone\plusfour,
\v!subpage=>\advance\scratchcounterone\plusfour,
\s!unknown=>\advance\scratchcounterone\plusone]%
- \ifdim\d_scrn_bar_width=\zeropoint
+ \ifzeropt\d_scrn_bar_width
\scratchdimenone\dimexpr2\emwidth+\d_scrn_bar_distance\relax
\scratchdimentwo\dimexpr\scratchcounterone\scratchdimenone-\d_scrn_bar_distance\relax
\else
diff --git a/Master/texmf-dist/tex/context/base/mkiv/scrn-but.mkvi b/Master/texmf-dist/tex/context/base/mkiv/scrn-but.mkvi
index 87af29cfb9d..0c9b4cfb51b 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/scrn-but.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/scrn-but.mkvi
@@ -455,10 +455,10 @@
\dp\b_scrn_menu\zeropoint}
\def\scrn_menu_apply_used
- {\ifdim\d_scrn_menu_offset_left=\zeropoint \else
+ {\ifzeropt\d_scrn_menu_offset_left \else
\setbox\b_scrn_menu\hbox{\hskip-\d_scrn_menu_offset_left \box\b_scrn_menu}%
\fi
- \ifdim\d_scrn_menu_offset_bottom=\zeropoint \else
+ \ifzeropt\d_scrn_menu_offset_bottom \else
\setbox\b_scrn_menu\hbox{\lower \d_scrn_menu_offset_bottom \box\b_scrn_menu}%
\fi
\wd\b_scrn_menu\d_scrn_menu_asked_width
diff --git a/Master/texmf-dist/tex/context/base/mkiv/scrn-wid.lua b/Master/texmf-dist/tex/context/base/mkiv/scrn-wid.lua
index 5b70bec7556..17c9ebddc4a 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/scrn-wid.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/scrn-wid.lua
@@ -143,6 +143,7 @@ implement {
{ "file" },
{ "name" },
{ "buffer" },
+ { "mimetype" },
}
}
}
@@ -172,6 +173,7 @@ implement {
{ "file" },
{ "name" },
{ "buffer" },
+ { "mimetype" },
}
}
}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/scrn-wid.mkvi b/Master/texmf-dist/tex/context/base/mkiv/scrn-wid.mkvi
index d1571ca656d..6808bd0b3e4 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/scrn-wid.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/scrn-wid.mkvi
@@ -25,6 +25,8 @@
%D As usual in \CONTEXT\ we separate the general definition (frontend)
%D and the rendering (backend).
+% hack: x\footnote{x\inleftmargin[scope=local]{\attachment[location=high,file=i-context.pdf]}}x
+
% old but stil valid method:
%
% \useattachment[test.tex]
@@ -109,6 +111,7 @@
file {\attachmentparameter\c!file}%
name {\attachmentparameter\c!name}%
buffer {\attachmentparameter\c!buffer}%
+ mimetype {\attachmentparameter\c!type}%
\relax
\endgroup
\else
@@ -211,6 +214,7 @@
file {\attachmentparameter\c!file}%
name {\attachmentparameter\c!name}%
buffer {\attachmentparameter\c!buffer}%
+ mimetype {\attachmentparameter\c!type}%
\relax
\wd\b_scrn_attachment_link\currentattachmentwidth
\ht\b_scrn_attachment_link\currentattachmentheight
@@ -228,6 +232,7 @@
file {\attachmentparameter\c!file}%
name {\attachmentparameter\c!name}%
buffer {\attachmentparameter\c!buffer}%
+ mimetype {\attachmentparameter\c!type}%
\relax}
\unexpanded\def\scrn_attachment_flush_traced
diff --git a/Master/texmf-dist/tex/context/base/mkiv/scrp-ini.lua b/Master/texmf-dist/tex/context/base/mkiv/scrp-ini.lua
index e6aa5f0720c..3d3aa44066e 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/scrp-ini.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/scrp-ini.lua
@@ -11,10 +11,10 @@ if not modules then modules = { } end modules ['scrp-ini'] = {
local tonumber, next = tonumber, next
-local trace_analyzing = false trackers.register("scripts.analyzing", function(v) trace_analyzing = v end)
-local trace_injections = false trackers.register("scripts.injections", function(v) trace_injections = v end)
-local trace_splitting = false trackers.register("scripts.splitting", function(v) trace_splitting = v end)
-local trace_splitdetail = false trackers.register("scripts.splitting.detail", function(v) trace_splitdetail = v end)
+local trace_analyzing = false trackers.register("scripts.analyzing", function(v) trace_analyzing = v end)
+local trace_injections = false trackers.register("scripts.injections", function(v) trace_injections = v end)
+local trace_splitting = false trackers.register("scripts.splitting", function(v) trace_splitting = v end)
+local trace_splitdetails = false trackers.register("scripts.splitting.details", function(v) trace_splitdetails = v end)
local report_preprocessing = logs.reporter("scripts","preprocessing")
local report_splitting = logs.reporter("scripts","splitting")
@@ -57,8 +57,11 @@ local getnext = nuts.getnext
local getchar = nuts.getchar
local getfont = nuts.getfont
local getid = nuts.getid
+local getglyphdata = nuts.getglyphdata
+
local getattr = nuts.getattr
local setattr = nuts.setattr
+
local isglyph = nuts.isglyph
local insert_node_after = nuts.insert_after
@@ -767,7 +770,7 @@ function splitters.handler(head) -- todo: also first_glyph test
if not nextchar then
-- we're done
elseif tree[nextchar] then
- if trace_splitdetail then
+ if trace_splitdetails then
if type(final) == "string" then
report_splitting("advance %s processing between <%s> and <%c>","with",final,nextchar)
else
@@ -776,7 +779,7 @@ function splitters.handler(head) -- todo: also first_glyph test
end
head, current = proc(handler,head,current,last,1)
else
- if trace_splitdetail then
+ if trace_splitdetails then
-- could be punctuation
if type(final) == "string" then
report_splitting("advance %s processing between <%s> and <%c>","without",final,nextchar)
@@ -894,7 +897,7 @@ function autofontfeature.handler(head)
-- else
local script = otfscripts[char]
if script then
- local dynamic = getattr(n,0) or 0
+ local dynamic = getglyphdata(n) or 0
if dynamic > 0 then
local slot = cache_yes[font]
local attr = slot[script]
diff --git a/Master/texmf-dist/tex/context/base/mkiv/spac-ali.lua b/Master/texmf-dist/tex/context/base/mkiv/spac-ali.lua
index b58040ac72a..c30a4fa942d 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/spac-ali.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/spac-ali.lua
@@ -24,11 +24,14 @@ local getid = nuts.getid
local getlist = nuts.getlist
local setlist = nuts.setlist
local setlink = nuts.setlink
+local getdirection = nuts.getdirection
local takeattr = nuts.takeattr
local getsubtype = nuts.getsubtype
local getwidth = nuts.getwidth
local findtail = nuts.tail
+local righttoleft_code = nodes.dirvalues.righttoleft
+
local hpack_nodes = nuts.hpack
local unsetvalue = attributes.unsetvalue
@@ -85,17 +88,28 @@ local function handler(head,leftpage,realpageno) -- traverse_list
elseif align == 2 then -- flushleft
action = leftpage and 2 or 1
end
+ -- WS: watch this
+ local direction = getdirection(current)
+ -- or should this happen at the tex end:
+ if direction == righttoleft_code then
+ if action == 1 then
+ action = 2
+ elseif action == 2 then
+ action = 1
+ end
+ end
+ --
if action == 1 then
local head = getlist(current)
setlink(findtail(head),new_stretch(3)) -- append
- setlist(current,hpack_nodes(head,getwidth(current),"exactly"))
+ setlist(current,hpack_nodes(head,getwidth(current),"exactly",direction))
if trace_realign then
report_realign("flushing left, align %a, page %a, realpage %a",align,pageno,realpageno)
end
elseif action == 2 then
local list = getlist(current)
local head = setlink(new_stretch(3),list) -- prepend
- setlist(current,hpack_nodes(head,getwidth(current),"exactly"))
+ setlist(current,hpack_nodes(head,getwidth(current),"exactly",direction))
if trace_realign then
report_realign("flushing right. align %a, page %a, realpage %a",align,pageno,realpageno)
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/spac-ali.mkiv b/Master/texmf-dist/tex/context/base/mkiv/spac-ali.mkiv
index 4362ff25002..8451e2494f9 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/spac-ali.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/spac-ali.mkiv
@@ -203,7 +203,7 @@
% oeps, hsize can be 0pt in which case we get a strange division
% was: 6\bodyfontsize, fails on: \placefigure{x $x=x$ x}{}
-\def\spac_align_set_raggedness_middle{\ifdim\hsize=\zeropoint\plussix\bodyfontsize\else.5\hsize\fi}
+\def\spac_align_set_raggedness_middle{\ifzeropt\hsize\plussix\bodyfontsize\else.5\hsize\fi}
\unexpanded\def\setraggedness#1% tricky .. we keep the global tolerance otherwise ... to be reconsidered
{\ifnum\tolerance<\c_spac_tolerance_minimum
@@ -691,8 +691,8 @@
\c_spac_align_state_horizontal\zerocount}
\setvalue{\??aligncommand\v!inner }{\c_spac_align_state_horizontal\plusfour }
\setvalue{\??aligncommand\v!outer }{\c_spac_align_state_horizontal\plusfive }
-\setvalue{\??aligncommand\v!flushinner }{\c_spac_align_state_horizontal\plusfive }
-\setvalue{\??aligncommand\v!flushouter }{\c_spac_align_state_horizontal\plusfour }
+\setvalue{\??aligncommand\v!flushinner }{\c_spac_align_state_horizontal\plusfour }
+\setvalue{\??aligncommand\v!flushouter }{\c_spac_align_state_horizontal\plusfive }
\setvalue{\??aligncommand\v!right }{\c_spac_align_state_horizontal\plustwo }
\setvalue{\??aligncommand\v!left }{\c_spac_align_state_horizontal\plusthree}
\setvalue{\??aligncommand\v!center }{\c_spac_align_state_horizontal\plusone
@@ -702,7 +702,6 @@
\setvalue{\??aligncommand\v!end }{\c_spac_align_state_horizontal\pluseight}
\setvalue{\??aligncommand\v!paragraph }{\c_spac_align_state_horizontal\plusnine}
-
\setvalue{\??aligncommand\v!lefttoright }{\c_spac_align_state_direction \plusone }
\setvalue{\??aligncommand\v!righttoleft }{\c_spac_align_state_direction \plustwo }
\setvalue{\??aligncommand l2r}{\c_spac_align_state_direction \plusone }
@@ -716,6 +715,7 @@
\setvalue{\??aligncommand\v!morehyphenation}{\toksapp\t_spac_align_collected{\morehyphens}}
\setvalue{\??aligncommand\v!hanging }{\toksapp\t_spac_align_collected{\font_protruding_enable }}
+\setvalue{\??aligncommand\v!hangingboth }{\toksapp\t_spac_align_collected{\font_protruding_enable_b}}
\setvalue{\??aligncommand\v!nothanging }{\toksapp\t_spac_align_collected{\font_protruding_disable}}
\setvalue{\??aligncommand\v!hz }{\toksapp\t_spac_align_collected{\font_expansion_enable }}
\setvalue{\??aligncommand\v!fullhz }{\toksapp\t_spac_align_collected{\font_expansion_enable_k}}
@@ -1153,26 +1153,6 @@
\letvalue{\??alignsimplereverse\v!flushright}\spac_align_simple_left
\letvalue{\??alignsimplereverse\v!middle }\spac_align_simple_middle
-% \unexpanded\def\simplealignedbox#1#2%
-% {\hbox \ifdim#1>\zeropoint to #1
-% \csname\??alignsimple\ifcsname\??alignsimple#2\endcsname#2\else\v!right\fi\expandafter\endcsname
-% \fi}
-
-% \unexpanded\def\simplealignedboxplus#1#2#3%
-% {\hbox #3 \ifdim#1>\zeropoint to #1
-% \csname\??alignsimple\ifcsname\??alignsimple#2\endcsname#2\else\v!right\fi\expandafter\endcsname
-% \fi}
-
-% \unexpanded\def\simplealignedbox#1#2%
-% {\hbox \ifdim#1>\zeropoint to #1
-% \csname\??alignsimple\ifcsname\??alignsimple#2\endcsname#2\else\v!right\fi\expandafter\endcsname
-% \fi}
-%
-% \unexpanded\def\simplealignedboxplus#1#2#3%
-% {\hbox #3 \ifdim#1>\zeropoint to #1
-% \csname\??alignsimple\ifcsname\??alignsimple#2\endcsname#2\else\v!right\fi\expandafter\endcsname
-% \fi}
-
\unexpanded\def\simplealignedbox#1#2%
{\hbox \ifdim#1>\zeropoint to #1
\ifcsname\??alignsimple#2\endcsname
@@ -1202,16 +1182,6 @@
\newconditional\alignsimplelefttoright \settrue\alignsimplelefttoright
-% \unexpanded\def\simplereversealignedbox#1#2%
-% {\hbox \ifdim#1>\zeropoint to #1
-% \csname\??alignsimplereverse\ifcsname\??alignsimplereverse#2\endcsname#2\else\v!left\fi\expandafter\endcsname
-% \fi}
-%
-% \unexpanded\def\simplereversealignedboxplus#1#2#3%
-% {\hbox #3 \ifdim#1>\zeropoint to #1
-% \csname\??alignsimplereverse\ifcsname\??alignsimplereverse#2\endcsname#2\else\v!left\fi\expandafter\endcsname
-% \fi}
-
\unexpanded\def\simplereversealignedbox#1#2%
{\hbox \ifdim#1>\zeropoint to #1
\ifcsname\??alignsimplereverse#2\endcsname
@@ -1253,5 +1223,17 @@
\def\spac_align_definehbox[#1][#2]%
{\setvalue{hbox#1}##1{\hbox to #2{\begstrut##1\endstrut\hss}}}
+%D Some direction related helpers:
+
+\installcorenamespace {reverse}
+
+\setvalue{\??reverse\v!normal }{\ifconditional\inlinelefttoright\else\s!reverse\fi}
+\setvalue{\??reverse\v!reverse}{\ifconditional\inlinelefttoright \s!reverse\fi}
+
+\ifcase\contextlmtxmode
+ \let\usedirectionparameterreverse\gobbleoneargument
+\else
+ \def\usedirectionparameterreverse#1{\begincsname\??reverse#1\c!direction\endcsname}
+\fi
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/spac-chr.lua b/Master/texmf-dist/tex/context/base/mkiv/spac-chr.lua
index 23cf9741b14..9b8453ca690 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/spac-chr.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/spac-chr.lua
@@ -27,6 +27,7 @@ local nodes, node = nodes, node
local nuts = nodes.nuts
+local getboth = nuts.getboth
local getnext = nuts.getnext
local getprev = nuts.getprev
local getattr = nuts.getattr
@@ -131,11 +132,10 @@ local function nbsp(head,current)
local para = fontparameters[getfont(current)]
if getattr(current,a_alignstate) == 1 then -- flushright
head, current = inject_nobreak_space(0x00A0,head,current,para.space,0,0)
- setsubtype(current,spaceskip_code)
else
head, current = inject_nobreak_space(0x00A0,head,current,para.space,para.spacestretch,para.spaceshrink)
- setsubtype(current,spaceskip_code)
end
+ setsubtype(current,spaceskip_code)
return head, current
end
@@ -199,7 +199,7 @@ local methods = {
end,
[0x00A0] = function(head,current) -- nbsp
- local next = getnext(current)
+ local prev, next = getboth(current)
if next then
local char = isglyph(current)
if not char then
@@ -216,7 +216,6 @@ local methods = {
return false
end
end
- local prev = getprev(current)
if prev then
local char = isglyph(prev)
if char and nbsphash[char] then
diff --git a/Master/texmf-dist/tex/context/base/mkiv/spac-flr.mkiv b/Master/texmf-dist/tex/context/base/mkiv/spac-flr.mkiv
index bd50bfea68b..4c3c0c0421f 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/spac-flr.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/spac-flr.mkiv
@@ -47,14 +47,14 @@
\edef\currentfiller{#1}%
\usefillerstyleandcolor\c!style\c!color
\scratchdimen\fillerparameter\c!leftmargin\relax
- \ifdim\scratchdimen=\zeropoint\else
+ \ifzeropt\scratchdimen\else
\hskip\scratchdimen
\fi
\fillerparameter\c!left\relax
\expandnamespaceparameter\??filleralternative\fillerparameter\c!alternative\s!unknown\relax
\fillerparameter\c!right\relax
\scratchdimen\fillerparameter\c!rightmargin\relax
- \ifdim\scratchdimen=\zeropoint\else
+ \ifzeropt\scratchdimen\else
\hskip\scratchdimen
\fi
\endgroup
@@ -80,7 +80,7 @@
\begingroup
\edef\currentfiller{#1}%
\scratchdimen\dimexpr\fillerparameter\c!rightmargindistance\relax
- \ifdim\scratchdimen=\zeropoint\else
+ \ifzeropt\scratchdimen\else
\parfillskip \scratchdimen\s!plus \plusone\s!fil\relax
\fi
\spac_fillers_indeed[#1]%
diff --git a/Master/texmf-dist/tex/context/base/mkiv/spac-hor.mkiv b/Master/texmf-dist/tex/context/base/mkiv/spac-hor.mkiv
index 24c7c789341..0f65eea3310 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/spac-hor.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/spac-hor.mkiv
@@ -38,8 +38,14 @@
\unexpanded\def\setupindenting
{\doifelsenextoptionalcs\spac_indentation_setup_options\spac_indentation_setup_size}
+% \unexpanded\def\spac_indentation_setup_size
+% {\assigndimension\v_spac_indentation_current\d_spac_indentation_par{1\emwidth}{1.5\emwidth}{2\emwidth}}
+
\unexpanded\def\spac_indentation_setup_size
- {\assigndimension\v_spac_indentation_current\d_spac_indentation_par{1\emwidth}{1.5\emwidth}{2\emwidth}}
+ {\assigndimension\v_spac_indentation_current\d_spac_indentation_par{1\emwidth}{1.5\emwidth}{2\emwidth}%
+ \ifzeropt\parindent\else
+ \parindent\d_spac_indentation_par\relax % new per 2019-04-12 : just in case it has been set beforehand
+ \fi}
\let\synchronizeindenting\spac_indentation_setup_size
@@ -60,7 +66,9 @@
\ifzeropt\parindent\else
\doifemptytoks\everypar\spac_indentation_set_everypar
\fi
- \ifconditional\c_spac_indentation_indent_first\else
+ \ifconditional\c_spac_indentation_indent_first
+ \spac_indentation_variant_yes % better than: \let\checkindentation\relax
+ \else
\spac_indentation_variant_no
\fi
\spac_indentation_check_toggle}
@@ -191,7 +199,7 @@
\parindent\zeropoint
\c_spac_indentation_toggle_state\zerocount}
-\installindentingmethod \v!toggle{\parindent\ifdim\parindent=\zeropoint
+\installindentingmethod \v!toggle{\parindent\ifzeropt\parindent
\d_spac_indentation_par
\else
\zeropoint
@@ -210,7 +218,7 @@
\installmacrostack\ifindentation
\def\spac_indentation_remove
- {\ifdim\parindent=\zeropoint \else
+ {\ifzeropt\parindent \else
\begingroup
\setbox\scratchbox\lastbox
\endgroup
@@ -267,7 +275,7 @@
\fi}
\def\spac_indentation_variant_force
- {\ifvmode \ifdim\parindent=\zeropoint \else
+ {\ifvmode \ifzeropt\parindent \else
% was : \hskip\parindent
% can be: \indent
% but we test:
@@ -839,7 +847,7 @@
\letvalue{\??skipadaptionright\v!no }\zeropoint
\letvalue{\??skipadaptionright\empty }\zeropoint
-% \setvalue{\??skipadaptionleft \v!standard}{\ifdim\d_spac_indentation_par=\zeropoint\narrowerparameter\c!left\else\d_spac_indentation_par\fi}
+% \setvalue{\??skipadaptionleft \v!standard}{\ifzeropt\d_spac_indentation_par\narrowerparameter\c!left\else\d_spac_indentation_par\fi}
% \setvalue{\??skipadaptionright\v!standard}{\narrowerparameter\c!right}
\letcsnamecsname\csname\??skipadaptionleft \v!standard\endcsname\csname\??skipadaptionleft \v!yes\endcsname
@@ -1253,7 +1261,7 @@
\advance\c_spac_ignore_spaces\minusone}
\def\spac_ignore_spaces_body
- {\ifdim\lastskip=\zeropoint
+ {\ifzeropt\lastskip
\exitloop
\else\ifdim\lastskip=\s_spac_ignore_spaces
\unskip
@@ -1267,4 +1275,13 @@
\def\obeyfollowingtoken{{}} % end \cs scanning
+%D Something new:
+
+\unexpanded\def\interwordspacebefore{\wordboundary\zwnj\hskip\interwordspace\relax}
+\unexpanded\def\interwordspaceafter {\hskip\interwordspace\relax\zwnj\wordboundary}
+
+\unexpanded\def\interwordspacesbefore#1{\dofastloopcs{#1}\interwordspacebefore}
+\unexpanded\def\interwordspacesafter #1{\dofastloopcs{#1}\interwordspaceafter}
+\unexpanded\def\interwordspaces #1{\wordboundary\zwnj\dofastloopcs{\numexpr#1+\minusone}\interwordspaceafter}
+
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/spac-par.mkiv b/Master/texmf-dist/tex/context/base/mkiv/spac-par.mkiv
index 0932b735989..7678cc34bdd 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/spac-par.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/spac-par.mkiv
@@ -218,7 +218,7 @@
{\begingroup
\the\everyflushatnextpar
\glet\flushpostponednodedata\spac_postponed_data_flush
- \dowithnextboxcs\spac_postponed_data_finish\hbox}
+ \dowithnextboxcs\spac_postponed_data_finish\hpack}
\def\spac_postponed_data_finish
{\global\setbox\b_spac_postponed_data\hpack % to\zeropoint
diff --git a/Master/texmf-dist/tex/context/base/mkiv/spac-prf.lua b/Master/texmf-dist/tex/context/base/mkiv/spac-prf.lua
index 32582c56fc5..049e62ac569 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/spac-prf.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/spac-prf.lua
@@ -45,7 +45,7 @@ local nuts = nodes.nuts
local tonut = nodes.tonut
local tonode = nuts.tonode
-local getfield = nuts.getfield
+local getreplace = nuts.getreplace
local getattr = nuts.getattr
local getid = nuts.getid
local getnext = nuts.getnext
@@ -185,7 +185,7 @@ local function getprofile(line,step)
dp = 0
progress()
elseif id == disc_code then
- local replace = getfield(current,"replace")
+ local replace = getreplace(current)
if replace then
process(replace)
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/spac-ver.lua b/Master/texmf-dist/tex/context/base/mkiv/spac-ver.lua
index b55f1ca7cae..33b81e5c7e8 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/spac-ver.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/spac-ver.lua
@@ -153,6 +153,7 @@ local remove_node = nuts.remove
local count_nodes = nuts.countall
local hpack_node = nuts.hpack
local vpack_node = nuts.vpack
+local start_of_par = nuts.start_of_par
local nextnode = nuts.traversers.node
local nexthlist = nuts.traversers.hlist
@@ -168,6 +169,7 @@ local nodepool = nuts.pool
local new_penalty = nodepool.penalty
local new_kern = nodepool.kern
+local new_glue = nodepool.glue
local new_rule = nodepool.rule
local nodecodes = nodes.nodecodes
@@ -290,7 +292,7 @@ end
local function validvbox(parentid,list)
if parentid == hlist_code then
local id = getid(list)
- if id == localpar_code and getsubtype(list) == 0 then
+ if id == localpar_code and start_of_par(list) then
list = getnext(list)
if not next then
return nil
@@ -326,7 +328,7 @@ local function already_done(parentid,list,a_snapmethod) -- todo: done when only
-- problem: any snapped vbox ends up in a line
if list and parentid == hlist_code then
local id = getid(list)
- if id == localpar_code and getsubtype(list) == 0 then
+ if id == localpar_code and start_of_par(list) then
list = getnext(list)
if not list then
return false
@@ -2062,6 +2064,7 @@ end
do
local outer = texnest[0]
+
local enabled = true
local trace = false
local report = logs.reporter("vspacing")
@@ -2157,27 +2160,105 @@ do
trackers.register("vspacing.forcestrutdepth",function(v) trace = v end)
- function vspacing.forcestrutdepth(n,depth,trace_mode)
+ local last = nil
+
+ -- function vspacing.forcestrutdepth(n,depth,trace_mode,plus)
+ -- local box = texgetbox(n)
+ -- if box then
+ -- box = tonut(box)
+ -- local head = getlist(box)
+ -- if head then
+ -- local tail = find_node_tail(head)
+ -- if tail and getid(tail) == hlist_code then
+ -- local dp = getdepth(tail)
+ -- if dp < depth then
+ -- setdepth(tail,depth)
+ -- outer.prevdepth = depth
+ -- if trace or trace_mode > 0 then
+ -- nuts.setvisual(tail,"depth")
+ -- end
+ -- end
+ -- end
+ -- end
+ -- end
+ -- end
+
+ function vspacing.forcestrutdepth(n,depth,trace_mode,plus)
local box = texgetbox(n)
if box then
box = tonut(box)
local head = getlist(box)
if head then
local tail = find_node_tail(head)
- if tail and getid(tail) == hlist_code then
- local dp = getdepth(tail)
- if dp < depth then
- setdepth(tail,depth)
- outer.prevdepth = depth
- if trace or trace_mode > 0 then
- nuts.setvisual(tail,"depth")
+ if tail then
+ if getid(tail) == hlist_code then
+ local dp = getdepth(tail)
+ if dp < depth then
+ setdepth(tail,depth)
+ outer.prevdepth = depth
+ if trace or trace_mode > 0 then
+ nuts.setvisual(tail,"depth")
+ end
+ end
+ end
+ last = nil
+ if plus then
+ -- penalty / skip ...
+ local height = 0
+ local sofar = 0
+ local same = false
+ local seen = false
+ local list = { }
+ last = nil
+ while tail do
+ local id = getid(tail)
+ if id == hlist_code or id == vlist_code then
+ local w, h, d = getwhd(tail)
+ height = height + h + d + sofar
+ sofar = 0
+ last = tail
+ elseif id == kern_code then
+ sofar = sofar + getkern(tail)
+ elseif id == glue_code then
+ if seen then
+ sofar = sofar + getwidth(tail)
+ seen = false
+ else
+ break
+ end
+ elseif id == penalty_code then
+ local p = getpenalty(tail)
+ if p >= 10000 then
+ same = true
+ seen = true
+ else
+ break
+ end
+ else
+ break
+ end
+ tail = getprev(tail)
end
+ texsetdimen("global","d_spac_prevcontent",same and height or 0)
end
end
end
end
end
+ function vspacing.pushatsame()
+ -- needs better checking !
+ if last then -- setsplit
+ nuts.setnext(getprev(last))
+ nuts.setprev(last)
+ end
+ end
+
+ function vspacing.popatsame()
+ -- needs better checking !
+ nuts.write(last)
+ end
+
end
-- interface
@@ -2205,6 +2286,25 @@ do
}
implement {
+ name = "forcestrutdepthplus",
+ arguments = { "integer", "dimension", "integer", true },
+ actions = vspacing.forcestrutdepth,
+ scope = "private"
+ }
+
+ implement {
+ name = "pushatsame",
+ actions = vspacing.pushatsame,
+ scope = "private"
+ }
+
+ implement {
+ name = "popatsame",
+ actions = vspacing.popatsame,
+ scope = "private"
+ }
+
+ implement {
name = "vspacingsetamount",
actions = vspacing.setskip,
scope = "private",
diff --git a/Master/texmf-dist/tex/context/base/mkiv/spac-ver.mkiv b/Master/texmf-dist/tex/context/base/mkiv/spac-ver.mkiv
index 7b36f9a5b52..6ed1847c577 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/spac-ver.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/spac-ver.mkiv
@@ -27,8 +27,8 @@
%
% There might be more namespace protection.
-%D There are two ways to influence the interline spacing. The
-%D most general and often most consistent way is using
+%D There are two ways to influence the interline spacing. The most general and often
+%D most consistent way is using
%D
%D \showsetup{setupinterlinespace}
%D
@@ -38,23 +38,21 @@
%D \setupinterlinespace[line=2.8ex]
%D \stoptyping
%D
-%D This setting adapts itself to the bodyfontsize, while for
-%D instance saying
+%D This setting adapts itself to the bodyfontsize, while for instance saying
%D
%D \starttyping
%D \setupinterlinespace[line=12pt]
%D \stoptyping
%D
-%D sets things fixed for all sizes, which is definitely not
-%D what we want. Therefore one can also say:
+%D sets things fixed for all sizes, which is definitely not what we want. Therefore
+%D one can also say:
%D
%D \starttyping
%D \definebodyfontenvironment[9pt][interlinespace=11pt]
%D \stoptyping
%D
-%D One can still use \type{\setupinterlinespace} (without
-%D arguments) to set the interline space according to the
-%D current font, e.g. a \type{\bfa}.
+%D One can still use \type {\setupinterlinespace} (without arguments) to set the
+%D interline space according to the current font, e.g. a \type {\bfa}.
% will be cleaned up but it will stay messy because we accept so
% many variants
@@ -244,9 +242,10 @@
\newskip \s_spac_lastskip
\newdimen\d_spac_prevdepth
\newcount\c_spac_spacefactor
+\newdimen\d_spac_prevcontent % set by lua
\unexpanded\def\removelastskip
- {\ifvmode\ifdim\lastskip=\zeropoint\else\vskip-\lastskip\fi\fi}
+ {\ifvmode\ifzeropt\lastskip\else\vskip-\lastskip\fi\fi}
\def\doifoutervmode
{\ifvmode
@@ -264,7 +263,7 @@
{\s_spac_lastskip\lastskip
\removelastskip
#1\relax
- \ifdim\s_spac_lastskip=\zeropoint
+ \ifzeropt\s_spac_lastskip
% avoid interference with footnotes
\else
\vskip\s_spac_lastskip
@@ -628,46 +627,35 @@
\unexpanded\def\verticalstrut {\vpack{\hsize\zeropoint\forgetall\strut}}
\unexpanded\def\horizontalstrut{\hpack {\strut}}
-% Hieronder volgen enkele instellingen en macro's ten behoeve
-% van de interlinie en \strut. De waarden 2.8, 0.07, 0.72 en
-% 0.28 zijn ooit eens ontleend aan INRS-TEX en moeten wellicht
-% nog eens instelbaar worden.
-%
-% \lineheight : de hoogte van een regel
-% \spacing{getal} : instellen interlinie
-% \normalbaselines : instellen regelafstend
-%
-% \setstrut : instellen \strut
-% \setnostrut : resetten \strut, \endstrut, \begstrut
-% \setnonestrut : resetten \strut (fast one)
-%
-% \setteststrut : instellen zichtbare struts
-% \resetteststrut : instellen onzichtbare struts
-%
-% \setfontparameters : instellen na fontset
-%
-% De hoogte van een regel (\lineheight) is gelijk aan de
-% som van de hoogte (\ht) en diepte (\dp) van \strutbox.
-%
-% \strut : denkbeeldig blokje met hoogte en diepte
-%
-% Een \hbox kan als deze aan het begin van een regel staat
-% een breedte \hsize krijgen. Dit is soms te voorkomen met het
-% commando \leavevmode. Binnen een \vbox geeft dit echter
-% niet altijd het gewenste resultaat, vandaar het commando
-%
-% \dontleavehmode
-
-% Pas op: niet zomaar \topskip en \baselineskip aanpassen
-% en zeker niet \widowpenalty. Dit kan ernstige gevolgen
-% hebben voor kolommen.
-%
-% Enige glue kan op zich geen kwaad, echter als blanko=vast,
-% dan moet ook de rek 0 zijn. Binnen kolommen is rek ook
-% niet bepaald mooi. Een hele kleine waarde (0.025) voldoet,
-% omdat een positieve glue eindeloos rekbaar is.
-
-% more of the next will become private:
+%D Here follow some presets related to interline spacing and therefore also struts.
+%D The values 2.8, 0.07, 0.72 and 0.28 originate in \INRSTEX, a package that we used
+%D a while after we decided that \LATEX\ was not flexible enough. After that
+%D \CONTEXT\ evolved, from some wrapper code around (old) \LATEX\ (on a floppy
+%D disk), to using modules from \INRSTEX\ (which also fit on a floppy) and finally
+%D all written from scratch. I simply didn't understand all that \TEX\ code at that
+%D time, and it was easier to figure it out myself. But \unknown\ some settings
+%D stayed, as the height|/|depth ratios, and they never proved to be bad ones! The
+%D same is true for the font size relations.
+
+%D \starttabulate
+%D \NC \type {\lineheight} \NC the height of a line \NC \NR
+%D \NC \type {\spacing{number}} \NC adapting the interline space \NC \NR
+%D \NC \type {\normalbaselines} \NC initialize the interline spacing \NC \NR
+%D \NC \type {\setstrut} \NC initialize \type {\strut} \NC \NR
+%D \NC \type {\setnostrut} \NC disable the \type {\strut}, \type {\endstrut}, \type {\begstrut} \NC \NR
+%D \NC \type {\setteststrut} \NC initialize the visual \type {\strut} \NC \NR
+%D \NC \type {\resetteststrut} \NC disable the visual \type {\strut} \NC \NR
+%D \NC \type {\setfontparameters} \NC synchronize parameters with foints \NC \NR
+%D \stoptabulate
+%D
+%D \unknown\ and many more (this is a decades old list).
+%D
+%D The lineheight is the sum of the height and depth of \type {strut}, which is
+%D an invisible blob that can be used to enforce the proper dimensions.
+%D
+%D Such a blob, when placed at the beginning of a paragraph can have side effects
+%D that can be prevented with \type {\dontleavehmode}. Never use \type
+%D {\leavevmode}!
\newdimen\strutdimen
\newdimen\lineheight
@@ -836,13 +824,19 @@
\noexpand\def\noexpand\normallineheight{\the\dimexpr\normallineheight}%
\noexpand\normalbaselines}}
-% plain definition:
-%
-% \def\strut{\relax\ifmmode\copy\strutbox\else\unhcopy\strutbox\fi}
-%
-% could be:
-%
-% \def\strut{\relax\ifmmode\copy\else\unhcopy\fi\strutbox}
+%D This is the plain definition:
+%D
+%D \starttyping
+%D \def\strut{\relax\ifmmode\copy\strutbox\else\unhcopy\strutbox\fi}
+%D \stoptyping
+%D
+%D which could be:
+%D
+%D \starttyping
+%D \def\strut{\relax\ifmmode\copy\else\unhcopy\fi\strutbox}
+%D \stoptyping
+%D
+%D But we do things differently.
\newbox\strutbox
@@ -856,8 +850,7 @@
\let\normalstrut\strut
-% The double \hbox construction enables us to \backtrack
-% boxes.
+%D The double \type {\hbox} construction enables us to backtrack boxes.
\let\strutht\undefined \newdimen\strutht
\let\strutdp\undefined \newdimen\strutdp
@@ -928,10 +921,10 @@
\vrule\s!width\zeropoint\s!depth\strutdp\s!height\zeropoint
\endgroup}
-% because of all the callbacks in mkiv, we avoid unnecessary boxes ...
-% maybe use an attribute so that we can tag boxes that don't need a
-% treatment; tests with using an attribute so far have shown that
-% it's slower because testing the attribute takes time too
+%D Because of all the callbacks in mkiv, we avoid unnecessary boxes ... maybe use an
+%D attribute so that we can tag boxes that don't need a treatment; tests with using
+%D an attribute so far have shown that it's slower because testing the attribute
+%D takes time too.
\unexpanded\def\dosetstrut
{\let\strut\normalstrut
@@ -1004,11 +997,9 @@
\let\spac_struts_vide_hbox\hbox % overloaded in trac-vis.mkiv
-%D The dimen \type {\struttotal} holds the exact size of the
-%D strut; occasionally a one scaled point difference can show
-%D up with the lineheight.
-
-% This is more efficient (less callbacks):
+%D The dimen \type {\struttotal} holds the exact size of the strut; occasionally a
+%D one scaled point difference can show up with the lineheight. This is more
+%D efficient (less callbacks):
\newbox\b_spac_struts_empty \setbox\b_spac_struts_empty\emptyhbox
@@ -1084,7 +1075,7 @@
%D \NC A B \unknown \NC a character strut (e.g. A) \NC {\showstruts\setupstrut[A]\strut} \NC \NR
%D \NC \NC a normal strut \NC {\showstruts\setupstrut\strut} \NC \NR
%D \stoptabulate
-
+%D
%D Beware: using an unknown value results in char struts.
\installcorenamespace{struts}
@@ -1165,10 +1156,8 @@
\let\begstrut\empty
\to \everysetnostrut
-% when enabled, sigstruts will remove themselves if nothing
-% goes inbetween
-
-%D For practical reasons we define some boundary characters here.
+%D When enabled, sigstruts will remove themselves if nothing goes inbetween. For
+%D practical reasons we define some boundary characters here.
\unexpanded\def\leftboundary {\protrusionboundary\plusone}
\unexpanded\def\rightboundary {\protrusionboundary\plustwo}
@@ -1197,11 +1186,6 @@
\hskip-\strutsignal
\hskip\strutsignal}
-% \def\spac_struts_beg_normal
-% {\strut
-% \penalty\plustenthousand
-% \hskip\zeropoint}
-
\def\spac_struts_beg_normal
{\boundary\plusone
\strut
@@ -1238,12 +1222,6 @@
\strut
\fi}
-% \def\spac_struts_end_normal
-% {\removeunwantedspaces
-% \penalty\plustenthousand
-% \hskip\zeropoint
-% \strut}
-
\def\spac_struts_end_normal
{\removeunwantedspaces
\penalty\plustenthousand
@@ -1298,10 +1276,9 @@
\def\baselinedistance{\the\lineheight}
-%D We need \type{\normaloffinterlineskip} because the new
-%D definition contains an assignment, and |<|don't ask me
-%D why|>| this assignment gives troubles in for instance the
-%D visual debugger.
+%D We need \type {\normaloffinterlineskip} because the new definition contains an
+%D assignment, and |<|don't ask me why|>| this assignment gives troubles in for
+%D instance the visual debugger.
\unexpanded\def\offinterlineskip
{\baselineskip-\thousandpoint
@@ -1322,8 +1299,8 @@
%D So, here we kick in a checker but it has to happen after the output group and it
%D only has to be done once (output can trigger itself!).
%D
-%D However, prevgraf is somehow bound to hangindent so we can get very
-%D nasty side effects. So, in tne end we use our own variable!
+%D However, prevgraf is somehow bound to hangindent so we can get very nasty side
+%D effects. So, in tne end we use our own variable!
\ifdefined\getnofpreviouslines
% defined public at the lua end
@@ -1445,7 +1422,7 @@
\resetpenalties\interlinepenalties
\stopsetups
-% we use \directsetup because it's faster and we know there is no csl
+%D We use \directsetup because it's faster and we know there is no csl:
\startsetups [\systemsetupsprefix\s!default]
@@ -1475,7 +1452,7 @@
\stopsetups
-% as an illustration:
+%D As an illustration:
\startsetups [\systemsetupsprefix\v!strict]
@@ -2191,13 +2168,16 @@
\doubleexpandafter\gobbleoneargument
\fi\fi}
-\unexpanded\def\useblankparameter#1% faster local variant
- {\edef\m_spac_blank_asked{#1\c!blank}%
+\unexpanded\def\usespecificblankparameter#1#2% faster local variant
+ {\edef\m_spac_blank_asked{#1#2}%
\ifx\m_spac_blank_asked\empty\else
\directvspacing\m_spac_blank_asked
\fi}
-% handy (and faster):
+\unexpanded\def\useblankparameter#1% faster local variant
+ {\usespecificblankparameter#1\c!blank}
+
+%D Handy (and faster):
\unexpanded\def\directvpenalty#1%
{\begingroup
@@ -2215,7 +2195,7 @@
\vskip#1\relax
\endgroup}
-% these depend on bigskipamount cum suis so we'd better sync them
+%D These depend on bigskipamount cum suis so we'd better sync them:
\unexpanded\def\setupvspacing
{\doifelsenextoptionalcs\setupvspacing_yes\setupvspacing_nop}
@@ -2238,9 +2218,7 @@
\let\synchronizevspacing\setupvspacing_nop
-% category:4 is default
-
-% this interface might change (into an \install, but we will then keep this one hidden)
+%D The \type {category:4} is default.
\definevspacingamount[\v!none] [\zeropoint] [\zeropoint]
\definevspacingamount[\v!big] [\bigskipamount] [\bodyfontlineheight]
@@ -2258,7 +2236,7 @@
\def\bodyfontwhitespace
{\dimexpr
- \ifdim\parskip=\zeropoint
+ \ifzeropt\parskip
\zeropoint
\else\ifgridsnapping
\bodyfontlineheight
@@ -2267,7 +2245,7 @@
\fi\fi
\relax}
-% used in itemize ... always test this
+%D used in itemize \unknown\ always test this:
\newdimen\d_spac_overlay
@@ -2316,21 +2294,33 @@
\newcount\c_spac_vspacing_special_base \c_spac_vspacing_special_base = 32250 % 4000
\newcount\c_spac_vspacing_special_step \c_spac_vspacing_special_step = 10 % 250
+\newcount\c_spac_vspacing_special_done
+
+% 2019-05-31 : upgraded a bit to more distinctive samepage-[level]-[0|1|2] names
+
+\unexpanded\def\spac_vspacing_define_same_step#1#2% alternatively we could have samepage-n-m
+ {\begingroup
+ \scratchcounterone\numexpr\plusthree*#1+#2\relax
+ \scratchcountertwo\numexpr\c_spac_vspacing_special_base+\c_spac_vspacing_special_step*\scratchcounterone\relax
+ %\writestatus{defined}{\v!samepage-\number#1-\number#2\space=>\space penalty:\the\scratchcountertwo}%
+ \normalexpanded{\definevspacing[\v!samepage-\number#1-\number#2][penalty:\the\scratchcountertwo]}%
+ \endgroup}
\unexpanded\def\spac_vspacing_define_same_page#1%
- {\normalexpanded{\definevspacing
- [\v!samepage-#1]%
- [penalty:\the\numexpr\c_spac_vspacing_special_base+\c_spac_vspacing_special_step*#1\relax]}}
+ {\dostepwiserecurse\c_spac_vspacing_special_done{#1}\plusone
+ {\spac_vspacing_define_same_step\recurselevel\zerocount % before
+ \spac_vspacing_define_same_step\recurselevel\plusone % after
+ \spac_vspacing_define_same_step\recurselevel\plustwo}% % whatever
+ \global\c_spac_vspacing_special_done#1\relax}
-\dorecurse{20}{\spac_vspacing_define_same_page{#1}}
+\spac_vspacing_define_same_page{12} % 12 levels should be more than enough as a start
-\ifdefined\everydefinesection
- \appendtoks
- \spac_vspacing_define_same_page\maxstructuredepth
- \to \everydefinesection
-\else
- % the order has changed so this code has to move to strf-def.mkiv then
-\fi
+\def\spac_vspacing_same_page#1#2% level offset (starts at 0)
+ {\ifnum#1>\c_spac_vspacing_special_done
+ \spac_vspacing_define_same_page{#1}%
+ \fi
+ %\writestatus{used}{\v!samepage-\number#1-\number#2}%
+ \vspacing[\v!samepage-\number#1-\number#2]}
\definevspacing[\v!default] [\v!big] % todo: needs to adapt to \setupblank
\definevspacing[\v!before] [\v!default] % but we need to avoid circular references
@@ -2340,9 +2330,8 @@
\setupvspacing
[\v!big] % alternatively [\v!standard]
-%D Maybe at some point we will differ between \type {\vspacing} and
-%D \type {\blank} (we needed the first one while playing with the
-%D new code).
+%D Maybe at some point we will differ between \type {\vspacing} and \type {\blank}
+%D (we needed the first one while playing with the new code).
% We keep this one as reference
%
@@ -2367,9 +2356,8 @@
\let\synchronizeblank \synchronizevspacing
\let\defineblankmethod\definevspacingamount
-%D The following command is for Wolfgang. It has to be used with
-%D care as it does {\em not} work in tandem with the other spacing
-%D commands.
+%D The following command is for Wolfgang. It has to be used with care as it does
+%D {\em not} work in tandem with the other spacing commands.
\installcorenamespace{vspace}
@@ -2451,8 +2439,7 @@
\relax
\fi}
-%D Some preliminary code: a simple and fast hanger, for usage in
-%D macros (moved from cont-new).
+%D Some preliminary code: a simple and fast hanger, for usage in macros.
\installcorenamespace {hanging}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/spac-ver.mkxl b/Master/texmf-dist/tex/context/base/mkiv/spac-ver.mkxl
new file mode 100644
index 00000000000..c56352077f3
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/spac-ver.mkxl
@@ -0,0 +1,2605 @@
+%D \module
+%D [ file=spac-ver,
+%D version=2009.10.16, % 1997.03.31, was core-spa.tex
+%D title=\CONTEXT\ Spacing Macros,
+%D subtitle=Vertical,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Spacing Macros / Vertical}
+
+\unprotect
+
+\registerctxluafile{spac-ver}{optimize}
+
+% todo: use usernodes ?
+
+% todo: itemize : intro ... only when there is one or two lines preceding and then
+% keep these together i.e. \blank[intro]
+
+% Isn't it about time to get rid of topskip i.e. make it equivalent to
+% \openstrutheight so that we can remove delta code.
+%
+% There might be more namespace protection.
+
+%D There are two ways to influence the interline spacing. The most general and often
+%D most consistent way is using
+%D
+%D \showsetup{setupinterlinespace}
+%D
+%D For instance
+%D
+%D \starttyping
+%D \setupinterlinespace[line=2.8ex]
+%D \stoptyping
+%D
+%D This setting adapts itself to the bodyfontsize, while for instance saying
+%D
+%D \starttyping
+%D \setupinterlinespace[line=12pt]
+%D \stoptyping
+%D
+%D sets things fixed for all sizes, which is definitely not what we want. Therefore
+%D one can also say:
+%D
+%D \starttyping
+%D \definebodyfontenvironment[9pt][interlinespace=11pt]
+%D \stoptyping
+%D
+%D One can still use \type {\setupinterlinespace} (without arguments) to set the
+%D interline space according to the current font, e.g. a \type {\bfa}.
+
+% will be cleaned up but it will stay messy because we accept so
+% many variants
+
+\newif\iflocalinterlinespace
+
+\newskip \s_spac_vspacing_temp \s_spac_vspacing_temp\bigskipamount
+
+\def\skipfactor {.75}
+\def\skipgluefactor{.25}
+
+% \def\normalskipamount
+% {\openlineheight
+% \ifgridsnapping \else \ifblankflexible
+% \s!plus \skipgluefactor\openlineheight
+% \s!minus\skipgluefactor\openlineheight
+% \fi \fi
+% \relax}
+
+\def\normalskipamount
+ {\openlineheight
+ \ifgridsnapping \orelse \ifblankflexible
+ \s!plus \skipgluefactor\openlineheight
+ \s!minus\skipgluefactor\openlineheight
+ \fi
+ \relax}
+
+\ifdefined\bodyfontinterlinespace \else
+ \let\bodyfontinterlinespace\empty
+\fi
+
+\unexpanded\def\presetnormallineheight % each bodyfont
+ {\edef\normallineheight{\interlinespaceparameter\c!line}%
+ \iflocalinterlinespace \else
+ \edef\m_spac_normallineheight{\bodyfontinterlinespace}%
+ \ifx\m_spac_normallineheight\empty \else
+ \let\normallineheight\m_spac_normallineheight
+ \fi
+ \fi}
+
+\unexpanded\def\setupspecifiedinterlinespace[#1]%
+ {\setupcurrentinterlinespace[#1]%
+ \spac_linespacing_setup_specified_interline_space}
+
+\def\spac_linespacing_setup_specified_interline_space
+ {\edef\strutheightfactor {\interlinespaceparameter\c!height }%
+ \edef\strutdepthfactor {\interlinespaceparameter\c!depth }%
+ \edef\minimumstrutheight {\interlinespaceparameter\c!minheight}%
+ \edef\minimumstrutdepth {\interlinespaceparameter\c!mindepth }%
+ \edef\minimumlinedistance {\interlinespaceparameter\c!distance }%
+ \edef\normallineheight {\interlinespaceparameter\c!line }%
+ \edef\topskipfactor {\interlinespaceparameter\c!top }%
+ \edef\maxdepthfactor {\interlinespaceparameter\c!bottom }%
+ \edef\m_spac_vertical_baseline_stretch_factor{\interlinespaceparameter\c!stretch }%
+ \edef\m_spac_vertical_baseline_shrink_factor {\interlinespaceparameter\c!shrink }%
+ % often topskip does more bad than good, so:
+ \ifx\topskipfactor\v!height
+ \let\topskipfactor\strutheightfactor
+ \fi
+ \setfontparameters % redundant, can be \setstrut, test first
+ \updateraggedskips} % yes indeed
+
+\installcorenamespace{interlinespacerelative}
+
+\let\setrelativeinterlinespace \relax % used elsewhere
+\let\currentrelativeinterlinespace\empty
+
+\setvalue{\??interlinespacerelative\v!on }{\oninterlineskip}
+\setvalue{\??interlinespacerelative\v!off }{\offinterlineskip}
+\setvalue{\??interlinespacerelative\v!reset}{\let\currentrelativeinterlinespace\empty
+ \let\setrelativeinterlinespace\relax
+ \setfontparameters}
+\setvalue{\??interlinespacerelative\v!auto }{\let\setrelativeinterlinespace\spac_linespacing_set_relative_interlinespace}
+
+\def\spac_linespacing_set_specified_relative_interlinespace#1% fragile?
+ {\doifelsedimenstring{#1}
+ {\setupspecifiedinterlinespace[\c!line=#1]}
+ {\assignvalue{#1}\currentrelativeinterlinespace{1.00}{1.25}{1.50}%
+ \spacing\currentrelativeinterlinespace}}
+
+\unexpanded\def\setuprelativeinterlinespace[#1]%
+ {\processcommalist[#1]\spac_linespacing_setup_relative_interlinespace}
+
+\def\spac_linespacing_setup_relative_interlinespace#1%
+ {\ifcsname\??interlinespacerelative#1\endcsname
+ \lastnamedcs
+ \else
+ \spac_linespacing_set_specified_relative_interlinespace{#1}%
+ \fi}
+
+\def\spac_linespacing_set_relative_interlinespace
+ {\ifx\currentrelativeinterlinespace\empty\else
+ \spacing\currentrelativeinterlinespace
+ \fi}
+
+\unexpanded\def\spac_linespacing_setup_use
+ {\ifcsname\namedinterlinespacehash\m_spac_interlinespace\s!parent\endcsname
+ \let\currentinterlinespace\m_spac_interlinespace
+ \spac_linespacing_setup_specified_interline_space
+ % \else
+ % we only support named interlinespaces
+ \fi}
+
+\unexpanded\def\useinterlinespaceparameter#1% see footnotes
+ {\edef\m_spac_interlinespace{#1\c!interlinespace}%
+ \ifx\m_spac_interlinespace\empty \else
+ \spac_linespacing_setup_use
+ \fi}
+
+\newtoks\everysetupglobalinterlinespace
+\newtoks\everysetuplocalinterlinespace
+
+\newconditional\interlinespaceisset
+
+\installcorenamespace{interlinespace}
+
+\installcommandhandler \??interlinespace {interlinespace} \??interlinespace
+
+\installmacrostack\currentinterlinespace
+
+\unexpanded\def\setupinterlinespace
+ {\dodoubleempty\spac_linespacing_setup}
+
+\ifdefined\setupinterlinespace_double \else
+ \let\setupinterlinespace_double\setup_interlinespace % for a while
+\fi
+
+\def\spac_linespacing_setup[#1][#2]%
+ {\settrue\interlinespaceisset % reset has to be done when needed
+ \ifsecondargument
+ \setupinterlinespace_double[#1][#2]%
+ \orelse\iffirstargument
+ \ifcsname\namedinterlinespacehash{#1}\s!parent\endcsname
+ \edef\currentinterlinespace{#1}%
+ \spac_linespacing_setup_specified_interline_space
+ %\dosetupspecifiedinterlinespaceindeed
+ \else
+ \spac_linespacing_setup_specified_or_relative[#1]%
+ \fi
+ \else
+ \let\currentinterlinespace\empty
+ \spac_linespacing_synchronize_local
+ \fi}
+
+\def\spac_linespacing_setup_specified_or_relative[#1]%
+ {\doifelseassignment{#1}\setupspecifiedinterlinespace\setuprelativeinterlinespace[#1]%
+ \the\iflocalinterlinespace\everysetuplocalinterlinespace\else\everysetupglobalinterlinespace\fi}
+
+\def\spac_linespacing_synchronize_local % adapts to the font
+ {\localinterlinespacetrue
+ \setfontparameters
+ \updateraggedskips % funny one here
+ \the\everysetuplocalinterlinespace
+ \localinterlinespacefalse}
+
+\unexpanded\def\dosetupcheckedinterlinespace#1% often a chain
+ {\edef\p_spac_checked_interlinespace{#1}%
+ \ifx\p_spac_checked_interlinespace\empty
+ \spac_linespacing_synchronize_local
+ \orelse\ifcsname\namedinterlinespacehash\p_spac_checked_interlinespace\s!parent\endcsname % we could have a \s!check
+ \push_macro_currentinterlinespace
+ \let\currentinterlinespace\p_spac_checked_interlinespace
+ \spac_linespacing_setup_specified_interline_space % \dosetupspecifiedinterlinespaceindeed
+ \iflocalinterlinespace
+ \the\everysetuplocalinterlinespace
+ \else
+ \localinterlinespacetrue
+ \the\everysetuplocalinterlinespace
+ \localinterlinespacefalse
+ \fi
+ \pop_macro_currentinterlinespace
+ \else
+ \normalexpanded{\noexpand\doifelseassignment{\p_spac_checked_interlinespace}%
+ \setupspecifiedinterlinespace\setuprelativeinterlinespace[\p_spac_checked_interlinespace]}%
+ \iflocalinterlinespace
+ \the\everysetuplocalinterlinespace
+ \else
+ \localinterlinespacetrue
+ \the\everysetuplocalinterlinespace
+ \localinterlinespacefalse
+ \fi
+ \fi}
+
+\unexpanded\def\setuplocalinterlinespace[#1]%
+ {\localinterlinespacetrue
+ \push_macro_currentinterlinespace
+ \setupinterlinespace[#1]%
+ \pop_macro_currentinterlinespace
+ \localinterlinespacefalse}
+
+\let\switchtointerlinespace\setuplocalinterlinespace
+
+%D Helpers
+
+\newskip \s_spac_lastskip
+\newdimen\d_spac_prevdepth
+\newcount\c_spac_spacefactor
+\newdimen\d_spac_prevcontent % set by lua
+
+\unexpanded\def\removelastskip
+ {\ifvmode\ifzeropt\lastskip\else\vskip-\lastskip\fi\fi}
+
+\def\doifoutervmode
+ {\ifvmode
+ \ifinner
+ \doubleexpandafter\gobbleoneargument
+ \else
+ \doubleexpandafter\firstofoneargument
+ \fi
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\unexpanded\def\dosomebreak#1%
+ {\doifoutervmode
+ {\s_spac_lastskip\lastskip
+ \removelastskip
+ #1\relax
+ \ifzeropt\s_spac_lastskip
+ % avoid interference with footnotes
+ \else
+ \vskip\s_spac_lastskip
+ \fi}}
+
+\unexpanded\def\packed
+ {\nointerlineskip}
+
+\unexpanded\def\godown[#1]%
+ {\relax
+ \ifhmode\endgraf\fi
+ \ifvmode\nointerlineskip\vskip#1\relax\fi}
+
+\unexpanded\def\smallskip{\vskip\smallskipamount}
+\unexpanded\def\medskip {\vskip\medskipamount}
+\unexpanded\def\bigskip {\vskip\bigskipamount}
+
+\unexpanded\def\smallbreak
+ {\par
+ \ifvmode\ifdim\lastskip<\smallskipamount
+ \removelastskip
+ \penalty-\plusfifty
+ \smallskip
+ \fi\fi}
+
+\unexpanded\def\medbreak
+ {\par
+ \ifvmode\ifdim\lastskip<\medskipamount
+ \removelastskip
+ \penalty-\plusonehundred
+ \medskip
+ \fi\fi}
+
+\unexpanded\def\bigbreak
+ {\par
+ \ifvmode\ifdim\lastskip<\bigskipamount
+ \removelastskip
+ \penalty-\plustwohundred
+ \bigskip
+ \fi\fi}
+
+\unexpanded\def\break {\penalty-\plustenthousand} % can be hmode or vmode
+\unexpanded\def\nobreak {\penalty \plustenthousand} % can be hmode or vmode
+\unexpanded\def\allowbreak{\penalty \zerocount} % can be hmode or vmode
+
+\unexpanded\def\goodbreak {\par\ifvmode\penalty-\plusfivehundred\relax\fi} % forces vmode
+\unexpanded\def\filbreak {\par\ifvmode\vfil\penalty-\plustwohundred\vfilneg\fi} % forces vmode
+
+%D Made slightly more readable:
+
+\unexpanded\def\vglue {\afterassignment\spac_helpers_vglue_indeed\s_spac_lastskip=}
+\unexpanded\def\hglue {\afterassignment\spac_helpers_hglue_indeed\s_spac_lastskip=}
+\unexpanded\def\topglue{\par\ifvmode\nointerlineskip\vglue-\topskip\vglue\fi}
+
+\def\spac_helpers_vglue_indeed
+ {\par
+ \ifvmode
+ \d_spac_prevdepth\prevdepth
+ \hrule\s!height\zeropoint
+ \nobreak
+ \vskip\s_spac_lastskip
+ \prevdepth\d_spac_prevdepth
+ \fi}
+
+\def\spac_helpers_hglue_indeed
+ {\dontleavehmode
+ \c_spac_spacefactor\spacefactor
+ \vrule\s!width\zeropoint
+ \nobreak
+ \hskip\s_spac_lastskip
+ \spacefactor\c_spac_spacefactor}
+
+%D We adapt plain's \type {\removelastskip} a bit:
+
+\unexpanded\def\removelastskip % also in supp-box
+ {\ifvmode\ifzeropt\lastskip\else\vskip-\lastskip\fi\fi}
+
+% The whitespace handler. We could cache settings but normally there are not
+% that many in a set.
+
+\installcorenamespace{whitespacemethod}
+
+\newskip \s_spac_whitespace_parskip \s_spac_whitespace_parskip\zeropoint
+\newconditional\c_spac_whitespace_flexible \settrue\c_spac_whitespace_flexible
+\newconstant \c_spac_whitespace_grid_mode % option in layout / 1=permit_half_lines
+
+%def\v_spac_whitespace_current{\zeropoint}
+\let\v_spac_whitespace_current\v!none
+
+\unexpanded\def\setupwhitespace
+ {\doifelsenextoptionalcs\spac_whitespace_setup_yes\spac_whitespace_setup_nop}
+
+\def\spac_whitespace_setup_nop
+ {\ifx\v_spac_whitespace_current\v!none\else
+ \spac_whitespace_setup
+ \fi}
+
+\let\synchronizewhitespace\spac_whitespace_setup_nop
+
+\def\spac_whitespace_setup_yes[#1]%
+ {\edef\m_spac_whitespace_asked{#1}%
+ \ifx\m_spac_whitespace_asked\empty
+ \spac_whitespace_setup_nop
+ \else
+ \let\v_spac_whitespace_current\m_spac_whitespace_asked
+ \spac_whitespace_setup
+ \fi}
+
+\def\spac_whitespace_setup % quick test for no list
+ {\ifcsname\??whitespacemethod\v_spac_whitespace_current\endcsname
+ \lastnamedcs
+ \else
+ \expandafter\processcommalist\expandafter[\v_spac_whitespace_current]\spac_whitespace_setup_method % can be raw
+ \fi\relax
+ \ifgridsnapping
+ \spac_whitespace_setup_grid
+ \else
+ \spac_whitespace_setup_normal
+ \fi
+ \parskip\s_spac_whitespace_parskip}
+
+\def\spac_whitespace_setup_normal
+ {\ifconditional\c_spac_whitespace_flexible \else
+ \s_spac_whitespace_parskip\plusone\s_spac_whitespace_parskip
+ \fi}
+
+\def\spac_whitespace_setup_grid
+ {\setfalse\c_spac_whitespace_flexible
+ \ifdim\s_spac_whitespace_parskip>\zeropoint
+ \s_spac_whitespace_parskip
+ \ifcase\c_spac_whitespace_grid_mode
+ \baselineskip
+ \or
+ \ifdim\scratchdimen=\baselineskip % maybe range
+ \baselineskip
+ \else
+ \numexpr\s_spac_whitespace_parskip/\dimexpr.5\lineheight\relax\relax\dimexpr.5\lineheight\relax
+ \fi
+ \else
+ \baselineskip
+ \fi
+ \fi}
+
+\unexpanded\def\installwhitespacemethod#1#2%
+ {\setvalue{\??whitespacemethod#1}{#2}}
+
+\installwhitespacemethod \v!fix {}
+\installwhitespacemethod \v!fixed {\setfalse\c_spac_whitespace_flexible}
+\installwhitespacemethod \v!flexible {\settrue \c_spac_whitespace_flexible}
+
+\installwhitespacemethod \v!line {\s_spac_whitespace_parskip \baselineskip}
+\installwhitespacemethod \v!halfline {\s_spac_whitespace_parskip .5\baselineskip}
+\installwhitespacemethod \v!quarterline {\s_spac_whitespace_parskip.25\baselineskip}
+\installwhitespacemethod \v!none {\s_spac_whitespace_parskip \zeropoint}
+\installwhitespacemethod \v!big {\s_spac_whitespace_parskip \bigskipamount}
+\installwhitespacemethod \v!medium {\s_spac_whitespace_parskip \medskipamount}
+\installwhitespacemethod \v!small {\s_spac_whitespace_parskip \smallskipamount}
+
+\installwhitespacemethod \s!default {\spac_whitespace_setup_nop} % also covers none
+
+\def\spac_whitespace_setup_method#1%
+ {\ifcsname\??whitespacemethod#1\endcsname
+ \lastnamedcs
+ \else
+ \s_spac_whitespace_parskip#1\fi
+ \relax}
+
+\unexpanded\def\forgetparskip
+ {\s_spac_whitespace_parskip\zeropoint
+ \parskip\zeropoint
+ \let\v_spac_whitespace_current\v!none}
+
+\appendtoks
+ \forgetparskip
+\to \everyforgetall
+
+% \installwhitespacemethod \s!unknown {\s_spac_whitespace_parskip\commalistelement\relax}
+%
+% \def\spac_whitespace_setup_method#1%
+% {\csname\??whitespacemethod\ifcsname\??whitespacemethod#1\endcsname#1\else\s!unknown\endcsname\relax}
+
+\unexpanded\def\nowhitespace{\directcheckedvspacing\v!nowhite} % {\vspacing[\v!nowhite]}
+\unexpanded\def\whitespace {\directcheckedvspacing\v!white} % {\vspacing[\v!white]}
+
+\setupwhitespace
+ [\v!none]
+
+% Packed:
+
+% todo: when packed blocks blank, we need to enable forced
+
+\newconditional\c_spac_packed_blank \settrue\c_spac_packed_blank
+\newcount \c_spac_packed_level
+
+\unexpanded\def\startpacked
+ {\dosingleempty\spac_packed_start}
+
+\def\spac_packed_start[#1]% nesting afvangen
+ {\global\advance\c_spac_packed_level\plusone
+ \par
+ \ifnum\c_spac_packed_level=\plusone \ifvmode
+ \begingroup
+ \whitespace % not combined
+ \directcheckedvspacing\v!disable % \blank[\v!disable]% or \inhibitblank
+ \doifelse{#1}\v!blank\settrue\setfalse\c_spac_packed_blank
+ \setupwhitespace[\v!none]% or \forgetparskip
+ \fi \fi}
+
+\unexpanded\def\stoppacked
+ {\par
+ \ifnum\c_spac_packed_level=\plusone \ifvmode
+ \endgroup
+ \fi \fi
+ \global\advance\c_spac_packed_level\minusone}
+
+\unexpanded\def\startunpacked
+ {\directdefaultvspacing % \blank
+ \begingroup}
+
+\unexpanded\def\stopunpacked
+ {\endgroup
+ \directdefaultvspacing}% \blank}
+
+% \prevdepth crosses pageboundaries!
+%
+% todo: a version that works ok inside a box
+
+% global : outer hsize + keep skips
+% local : inner hsize + reset skips
+
+\installcorenamespace{linesaround}
+
+\let\spac_lines_vbox\vbox
+
+\installtextracker
+ {linecorrection.boxes}
+ {\let\spac_lines_vbox\ruledvbox}
+ {\let\spac_lines_vbox\vbox}
+
+\let\v_spac_lines_around_action_set\relax
+\let\m_spac_lines_around \empty
+
+\newconstant\c_spac_lines_correction_mode
+
+\setvalue{\??linesaround\v!blank }{\blank}
+\letvalue{\??linesaround\empty }\relax
+\setvalue{\??linesaround\s!unknown}{\directcheckedvspacing\m_spac_lines_around} % \blank[\m_spac_lines_around]}
+
+\def\spac_lines_action_around % we used to let this one but it's cleaner this way
+ {\csname\??linesaround % i.e. do it twice
+ \ifcsname\??linesaround\m_spac_lines_around\endcsname\m_spac_lines_around\else\s!unknown\fi
+ \endcsname}
+
+\unexpanded\def\startlinecorrection
+ {\endgraf
+ \begingroup
+ \setconstant\c_spac_lines_correction_mode\plusone
+ \dosingleempty\spac_lines_start_correction}
+
+\unexpanded\def\startlocallinecorrection
+ {\endgraf
+ \begingroup
+ \setconstant\c_spac_lines_correction_mode\plustwo
+ \dosingleempty\spac_lines_start_correction}
+
+\unexpanded\def\spac_lines_start_correction[#1]%
+ {\edef\m_spac_lines_around{#1}%
+ \spac_lines_action_around
+ \d_spac_prevdepth\prevdepth
+ \spac_lines_initialize_corrections
+ \offbaselinecorrection % ???
+ \setbox\scratchbox\spac_lines_vbox\bgroup
+ \ifcase\c_spac_lines_correction_mode
+ % nothing
+ \or
+ % global
+ \or
+ % local
+ \setlocalhsize
+ \hsize\localhsize
+ \forgetbothskips
+ \fi
+ \ignorespaces}
+
+\unexpanded\def\spac_lines_stop_correction
+ {\removeunwantedspaces
+ \egroup
+ \ifgridsnapping
+ \spac_lines_stop_correction_ongrid
+ \else
+ \spac_lines_stop_correction_normal
+ \fi
+ \endgroup}
+
+\unexpanded\def\spac_lines_stop_correction_ongrid
+ {\directcheckedvspacing\v!white % \blank[\v!white]%
+ \spac_lines_action_around
+ \snaptogrid\hpack{\box\scratchbox}%
+ \directcheckedvspacing\v!white
+ \spac_lines_action_around}
+
+\unexpanded\def\spac_lines_stop_correction_normal
+ {\directcheckedvspacing\v!nowhite % \blank[\v!nowhite]%
+ \ifdim\parskip>\zeropoint
+ % too fuzzy otherwise
+ \else
+ % doesn't like whitespace
+ \ifdim\d_spac_prevdepth<\maxdimen
+ \unless\ifdim\d_spac_prevdepth<\zeropoint
+ \ifdim\d_spac_prevdepth<\strutdp \relax
+ \pushlastnode
+ \ifdim\d_spac_prevdepth>\zeropoint
+ \kern-\d_spac_prevdepth
+ \fi
+ \kern\strutdp
+ \prevdepth\strutdp
+ \poplastnode
+ \fi
+ \fi
+ \fi
+ \fi
+ \ifdim\pagegoal<\maxdimen
+ % \blank[\v!white,\the\d_spac_lines_correction_before]% \blank[\v!white]\dotopbaselinecorrection
+ \directcheckedvspacing{\v!white,\the\d_spac_lines_correction_before}% \blank[\v!white]\dotopbaselinecorrection
+ \fi
+ \nointerlineskip % new
+ \noindent % not \dontleavehmode !
+ \ifcase\c_spac_lines_correction_mode
+ % nothing
+ \or
+ % global
+ \hskip-\leftskip % more tricky would be hangindent so we ignore that one
+ \or
+ % local
+ \fi
+ \box\scratchbox
+ \endgraf
+ %
+ % eventually i'll get it right ... (i also need to check all whitespace code elsewhere)
+ %
+ % \blank[\the\d_spac_lines_correction_after]% \dobotbaselinecorrection
+ % \directcheckedvspacing{\the\d_spac_lines_correction_after}% \dobotbaselinecorrection
+ \directcheckedvspacing{\v!white,\the\d_spac_lines_correction_after}% \dobotbaselinecorrection
+ % \allowbreak % new, otherwise problems when many in a row
+ \prevdepth\strutdp
+ \spac_lines_action_around}
+
+\let\stoplinecorrection \spac_lines_stop_correction
+\let\stoplocallinecorrection\spac_lines_stop_correction
+
+% todo:
+
+\unexpanded\def\correctwhitespace
+ {\dowithnextboxcs\correctwhitespacefinish\vbox}
+
+\unexpanded\def\correctwhitespacefinish
+ {\startbaselinecorrection
+ \flushnextbox
+ \stopbaselinecorrection}
+
+\unexpanded\def\verticalstrut {\vpack{\hsize\zeropoint\forgetall\strut}}
+\unexpanded\def\horizontalstrut{\hpack {\strut}}
+
+%D Here follow some presets related to interline spacing and therefore also struts.
+%D The values 2.8, 0.07, 0.72 and 0.28 originate in \INRSTEX, a package that we used
+%D a while after we decided that \LATEX\ was not flexible enough. After that
+%D \CONTEXT\ evolved, from some wrapper code around (old) \LATEX\ (on a floppy
+%D disk), to using modules from \INRSTEX\ (which also fit on a floppy) and finally
+%D all written from scratch. I simply didn't understand all that \TEX\ code at that
+%D time, and it was easier to figure it out myself. But \unknown\ some settings
+%D stayed, as the height|/|depth ratios, and they never proved to be bad ones! The
+%D same is true for the font size relations.
+
+%D \starttabulate
+%D \NC \type {\lineheight} \NC the height of a line \NC \NR
+%D \NC \type {\spacing{number}} \NC adapting the interline space \NC \NR
+%D \NC \type {\normalbaselines} \NC initialize the interline spacing \NC \NR
+%D \NC \type {\setstrut} \NC initialize \type {\strut} \NC \NR
+%D \NC \type {\setnostrut} \NC disable the \type {\strut}, \type {\endstrut}, \type {\begstrut} \NC \NR
+%D \NC \type {\setteststrut} \NC initialize the visual \type {\strut} \NC \NR
+%D \NC \type {\resetteststrut} \NC disable the visual \type {\strut} \NC \NR
+%D \NC \type {\setfontparameters} \NC synchronize parameters with foints \NC \NR
+%D \stoptabulate
+%D
+%D \unknown\ and many more (this is a decades old list).
+%D
+%D The lineheight is the sum of the height and depth of \type {strut}, which is
+%D an invisible blob that can be used to enforce the proper dimensions.
+%D
+%D Such a blob, when placed at the beginning of a paragraph can have side effects
+%D that can be prevented with \type {\dontleavehmode}. Never use \type
+%D {\leavevmode}!
+
+\newdimen\strutdimen
+\newdimen\lineheight
+\newdimen\openlineheight
+\newdimen\openstrutheight
+\newdimen\openstrutdepth
+\newdimen\topskipgap
+\newdimen\struttotal
+
+\def\strutheightfactor {.72}
+\def\strutdepthfactor {.28}
+
+\def\baselinefactor {2.8}
+
+\let\m_spac_vertical_baseline_stretch_factor \zerocount
+\let\m_spac_vertical_baseline_shrink_factor \zerocount
+
+\def\minimumstrutheight {\zeropoint}
+\def\minimumstrutdepth {\zeropoint}
+
+\def\normallineheight {\baselinefactor\exheight}
+\def\minimumlinedistance {\lineskip}
+
+\def\strutheight {\zeropoint}
+\def\strutdepth {\zeropoint}
+\def\strutwidth {\zeropoint}
+
+\let\spacingfactor \plusone
+
+\def\topskipfactor {1.0}
+\def\maxdepthfactor {0.5}
+
+\def\systemtopskipfactor {\topskipfactor}
+\def\systemmaxdepthfactor {\maxdepthfactor}
+
+\ifdefined\globalbodyfontsize \else
+ \newdimen\globalbodyfontsize
+ \globalbodyfontsize=12pt
+\fi
+
+\ifdefined\normalizedbodyfontsize \else
+ \def\normalizedbodyfontsize{12pt}
+\fi
+
+\unexpanded\def\topskipcorrection
+ {\simpletopskipcorrection
+ \vskip-\struttotal
+ \verticalstrut}
+
+\unexpanded\def\simpletopskipcorrection
+ {\ifdim\topskip>\openstrutheight
+ % == \vskip\topskipgap
+ \vskip\topskip
+ \vskip-\openstrutheight
+ \fi}
+
+\unexpanded\def\settopskip % the extra test is needed for the lbr family
+ {\topskip
+ \ifgridsnapping
+ \zeropoint
+ \else
+ \systemtopskipfactor\globalbodyfontsize
+ \ifcase\bottomraggednessmode % ragged bottom
+ \s!plus5\globalbodyfontsize
+ \fi
+ \fi
+ %\relax
+ \topskipgap\topskip
+ \advance\topskipgap -\openstrutheight\relax
+ \ifdim\minimumstrutheight>\zeropoint
+ \ifdim\topskip<\minimumstrutheight
+ \topskip\minimumstrutheight\relax
+ \fi
+ \else
+ \ifdim\topskip<\strutheightfactor\openlineheight
+ \topskip\strutheightfactor\openlineheight\relax
+ \fi
+ \fi}
+
+\unexpanded\def\setmaxdepth
+ {\maxdepth\systemmaxdepthfactor\globalbodyfontsize}
+
+\let\normalbaselineskip \relax \newskip \normalbaselineskip % these got lost in the transition to mkiv due
+\let\normallineskip \relax \newskip \normallineskip % to auto-\normal* definitions and registers
+\let\normallineskiplimit\relax \newdimen\normallineskiplimit % being protected
+
+\unexpanded\def\normalbaselines
+ {\baselineskip \normalbaselineskip
+ \lineskip \normallineskip
+ \lineskiplimit\normallineskiplimit}
+
+\unexpanded\def\flexiblebaselines
+ {\baselineskip \normalbaselineskip
+ \lineskip 1\normallineskip \s!plus 1\s!fill
+ \lineskiplimit\normallineskiplimit}
+
+\unexpanded\def\setnormalbaselines
+ {\ifdim\normallineheight>\zeropoint
+ \lineheight\normallineheight
+ \fi
+ \openlineheight\spacingfactor\lineheight
+ \openstrutheight \ifdim\minimumstrutheight>\zeropoint
+ \minimumstrutheight % new
+ \else
+ \strutheightfactor\openlineheight
+ \fi
+ \openstrutdepth \ifdim\minimumstrutdepth>\zeropoint
+ \minimumstrutdepth % new
+ \else
+ \strutdepthfactor \openlineheight
+ \fi
+ \ifdim\dimexpr\minimumstrutdepth+\minimumstrutheight\relax>\zeropoint
+ \openlineheight\dimexpr\openstrutheight+\openstrutdepth\relax % new
+ \fi
+ \normalbaselineskip\openlineheight
+ \ifgridsnapping\else
+ \s!plus \m_spac_vertical_baseline_stretch_factor\openlineheight
+ \s!minus\m_spac_vertical_baseline_shrink_factor \openlineheight
+ \fi
+ \normallineskip\minimumlinedistance\relax % \onepoint\relax
+ \normallineskiplimit\zeropoint\relax
+ \normalbaselines}
+
+\unexpanded\def\spacing#1% vertical
+ {\ifgridsnapping
+ \let\spacingfactor\plusone
+ \else
+ \edef\spacingfactor{#1}%
+ \fi
+ \edef\systemtopskipfactor {\withoutpt\the\dimexpr#1\dimexpr\topskipfactor \points}%
+ \edef\systemmaxdepthfactor{\withoutpt\the\dimexpr#1\dimexpr\maxdepthfactor\points}%
+ \setnormalbaselines
+ \setstrut}
+
+% \unexpanded\def\forgetverticalstretch % \forgetspacing
+% {\spacing\plusone}
+
+\unexpanded\def\forgetverticalstretch
+ {\let\spacingfactor \plusone
+ \let\systemtopskipfactor \topskipfactor
+ \let\systemmaxdepthfactor\maxdepthfactor
+ \setnormalbaselines
+ \setstrut}
+
+\appendtoks
+ \forgetverticalstretch
+\to \everyforgetall % needed in otr
+
+%D Sometimes one needs to freeze the interlinespacing
+%D
+%D \starttyping
+%D \rm \saveinterlinespace .... {\ss \restoreinterlinespace .... \endgraf}
+%D \stoptyping
+
+\let\restoreinterlinespace\relax
+
+\unexpanded\def\saveinterlinespace
+ {\unexpanded\edef\restoreinterlinespace
+ {\lineheight \the\lineheight
+ \openstrutheight \the\openstrutheight
+ \openstrutdepth \the\openstrutdepth
+ \openlineheight \the\openlineheight
+ \normalbaselineskip \the\normalbaselineskip
+ \normallineskip \the\normallineskip
+ \normallineskiplimit\the\normallineskiplimit
+ \noexpand\def\noexpand\normallineheight{\the\dimexpr\normallineheight}%
+ \noexpand\normalbaselines}}
+
+%D This is the plain definition:
+%D
+%D \starttyping
+%D \def\strut{\relax\ifmmode\copy\strutbox\else\unhcopy\strutbox\fi}
+%D \stoptyping
+%D
+%D which could be:
+%D
+%D \starttyping
+%D \def\strut{\relax\ifmmode\copy\else\unhcopy\fi\strutbox}
+%D \stoptyping
+%D
+%D But we do things differently.
+
+\newbox\strutbox
+
+\setbox\strutbox\hpack{\vrule\s!height8.5pt\s!depth3.5pt\s!width\zeropoint} % just a start
+
+\def\strut{\relax\ifmmode\copy\else\unhcopy\fi\strutbox}
+
+% \unexpanded\def\strut
+% {\relax
+% \ifmmode\copy\else\dontleavehmode\unhcopy\fi\strutbox}
+
+\let\normalstrut\strut
+
+%D The double \type {\hbox} construction enables us to backtrack boxes.
+
+\let\strutht\undefined \newdimen\strutht
+\let\strutdp\undefined \newdimen\strutdp
+
+\unexpanded\def\setstrut
+ {\ifgridsnapping
+ \setstrutgridyes
+ \else
+ \setstrutgridnop
+ \fi}
+
+\unexpanded\def\setstrutgridyes
+ {\strutht\spacingfactor\dimexpr
+ \ifdim\minimumstrutheight>\zeropoint
+ \minimumstrutheight
+ \else
+ \strutheightfactor\dimexpr\normallineheight
+ \fi
+ \strutdp\dimexpr
+ \ifdim\minimumstrutdepth>\zeropoint
+ \minimumstrutdepth
+ \else
+ \normallineheight-\strutht
+ \fi
+ \dosetstrut}
+
+\unexpanded\def\setstrutgridnop
+ {\strutht\spacingfactor\dimexpr
+ \ifdim\minimumstrutheight>\zeropoint
+ \minimumstrutheight
+ \else
+ \strutheightfactor\dimexpr\normallineheight
+ \fi
+ \strutdp\spacingfactor\dimexpr
+ \ifdim\minimumstrutdepth>\zeropoint
+ \minimumstrutdepth
+ \else
+ \strutdepthfactor\dimexpr\normallineheight
+ \fi
+ \dosetstrut}
+
+\unexpanded\def\setcharstrut#1%
+ {\setbox\strutbox\hbox{#1}% no \hpack, in case we have smallcaps
+ \strutht\ht\strutbox
+ \strutdp\dp\strutbox
+ \dosetstrut}
+
+\unexpanded\def\settightstrut
+ {\setcharstrut{(}}
+
+\unexpanded\def\setfontstrut
+ {\setcharstrut{(gplQT}}
+
+\unexpanded\def\setcapstrut% could be M, but Q has descender
+ {\setcharstrut{Q}}
+
+%D Handy for math (used in mathml):
+
+\unexpanded\def\charhtstrut
+ {\begingroup
+ \setcharstrut{GJY}%
+ \vrule\s!width\zeropoint\s!depth\zeropoint\s!height\strutht
+ \endgroup}
+
+\unexpanded\def\chardpstrut
+ {\begingroup
+ \setcharstrut{gjy}%
+ \vrule\s!width\zeropoint\s!depth\strutdp\s!height\zeropoint
+ \endgroup}
+
+%D Because of all the callbacks in mkiv, we avoid unnecessary boxes ... maybe use an
+%D attribute so that we can tag boxes that don't need a treatment; tests with using
+%D an attribute so far have shown that it's slower because testing the attribute
+%D takes time too.
+
+\unexpanded\def\dosetstrut
+ {\let\strut\normalstrut
+ \ifabsnum\dimexpr\strutht+\strutdp-\lineheight\relax<\plustwo
+ % compensate rounding error /- 1sp to avoid too many
+ % 1sp baselineskips in for instance verbatim
+ % \strutht\dimexpr\lineheight-\strutdp\relax
+ % better:
+ \strutdp\dimexpr\lineheight-\strutht\relax
+ \struttotal\lineheight
+ \else
+ \struttotal\dimexpr\strutht+\strutdp\relax
+ \fi
+ \edef\strutheight{\the\strutht}%
+ \edef\strutdepth {\the\strutdp}%
+ \ifdim\strutwidth=\zeropoint
+ \spac_struts_set_hide
+ \else
+ \spac_struts_set_vide
+ \fi}
+
+\def\spac_struts_set_hide
+ {\setbox\strutbox\hpack
+ {\vrule
+ \s!width \zeropoint
+ \s!height\strutht
+ \s!depth \strutdp}}
+
+\newconstant\c_strut_visual_mode
+
+\def\spac_struts_set_vide
+ {\setbox\strutbox\hpack % at some time this extra wrapping was needed
+ {\spac_struts_vide_hbox to \zeropoint
+ {\ifcase\c_strut_visual_mode
+ \spac_struts_black
+ \or
+ \spac_struts_color
+ \else
+ \spac_struts_black
+ \fi}}}
+
+\def\spac_struts_black
+ {\vrule
+ \s!width \strutwidth
+ \s!height\strutht
+ \s!depth \strutdp
+ \hss}
+
+\def\spac_struts_color
+ {\hss % new, will be option
+ \scratchwidth.1\struthtdp
+ \begingroup
+ \directcolor[f:b:t]%
+ \vrule
+ \s!width \scratchwidth
+ \s!height\strutht
+ \s!depth \strutdp
+ \kern-\scratchwidth
+ \vrule
+ \s!width \scratchwidth
+ \s!height\zeropoint
+ \s!depth \strutdp
+ \endgroup
+ \kern-.625\scratchwidth
+ \vrule
+ \s!width .25\scratchwidth
+ \s!height\strutht
+ \s!depth \strutdp
+ \hss}
+
+\let\spac_struts_vide_hbox\hbox % overloaded in trac-vis.mkiv
+
+%D The dimen \type {\struttotal} holds the exact size of the strut; occasionally a
+%D one scaled point difference can show up with the lineheight. This is more
+%D efficient (less callbacks):
+
+\newbox\b_spac_struts_empty \setbox\b_spac_struts_empty\emptyhbox
+
+\def\spac_struts_set_hide
+ {\setbox\strutbox\copy\b_spac_struts_empty
+ \ht\strutbox\strutht
+ \dp\strutbox\strutdp}
+
+\unexpanded\def\strut % still callbacks for \hbox{\strut}
+ {\relax
+ \dontleavehmode
+ \copy\strutbox}
+
+% \unexpanded\def\strut % slightly faster
+% {\relax
+% \ifmmode\copy\else\dontleavehmode\unhcopy\fi\strutbox}
+
+\let\normalstrut\strut
+
+\unexpanded\def\halfstrut
+ {\relax
+ \dontleavehmode
+ \begingroup
+ \setbox\scratchbox\copy\strutbox
+ \ht\scratchbox\dimexpr\strutht/\plustwo\relax
+ \dp\scratchbox\dimexpr\strutdp/\plustwo\relax
+ \box\scratchbox
+ \endgroup}
+
+\unexpanded\def\quarterstrut
+ {\relax
+ \dontleavehmode
+ \begingroup
+ \setbox\scratchbox\copy\strutbox
+ \ht\scratchbox\dimexpr\strutht/\plusfour\relax
+ \dp\scratchbox\dimexpr\strutdp/\plusfour\relax
+ \box\scratchbox
+ \endgroup}
+
+\unexpanded\def\depthstrut
+ {\relax
+ \dontleavehmode
+ \begingroup
+ \setbox\scratchbox\copy\strutbox
+ \ht\scratchbox\dimexpr\strutht-\struthtdp/\plustwo\relax % assumes that ht > lineheight/2
+ \box\scratchbox
+ \endgroup}
+
+\unexpanded\def\halflinestrut
+ {\relax
+ \dontleavehmode
+ \begingroup
+ \setbox\scratchbox\copy\strutbox
+ \ht\scratchbox\dimexpr\strutht-.5\strutht-.5\strutdp\relax
+ \box\scratchbox
+ \endgroup}
+
+\unexpanded\def\noheightstrut
+ {\relax
+ \dontleavehmode
+ \begingroup
+ \setbox\scratchbox\copy\strutbox
+ \ht\scratchbox\zeropoint
+ \box\scratchbox
+ \endgroup}
+
+%D Sometimes a capstrut comes in handy
+%D
+%D \starttabulate[|Tl|l|l|]
+%D \NC yes \NC normal strut \NC {\showstruts\setupstrut[yes]\strut} \NC \NR
+%D \NC no \NC no strut \NC {\showstruts\setupstrut[no]\strut} \NC \NR
+%D \NC kap \NC a capital strut (i.e. Q) \NC {\showstruts\setupstrut[cap]\strut} \NC \NR
+%D \NC A B \unknown \NC a character strut (e.g. A) \NC {\showstruts\setupstrut[A]\strut} \NC \NR
+%D \NC \NC a normal strut \NC {\showstruts\setupstrut\strut} \NC \NR
+%D \stoptabulate
+%D
+%D Beware: using an unknown value results in char struts.
+
+\installcorenamespace{struts}
+
+\unexpanded\def\setupstrut
+ {\dosingleempty\spac_struts_setup}
+
+\def\spac_struts_setup[#1]%
+ {\edef\m_strut{#1}%
+ \ifcsname\??struts\m_strut\endcsname
+ \lastnamedcs
+ \else
+ \setcharstrut\m_strut
+ \fi}
+
+\unexpanded\def\synchronizestrut#1% no [] parsing, faster for internal
+ {\edef\m_strut{#1}%
+ \ifcsname\??struts\m_strut\endcsname
+ \lastnamedcs
+ \else
+ \setcharstrut\m_strut
+ \fi}
+
+\unexpanded\def\dosynchronizestrut#1% no [] parsing, faster for internal
+ {\ifcsname\??struts#1\endcsname
+ \lastnamedcs
+ \else
+ \setcharstrut{#1}%
+ \fi}
+
+\unexpanded\def\showstruts % adapts .. is wrong
+ {\c_strut_visual_mode\zerocount
+ \setteststrut
+ \settestcrlf}
+
+\unexpanded\def\showcolorstruts % adapts .. is wrong
+ {\c_strut_visual_mode\plusone
+ \setteststrut
+ \settestcrlf}
+
+\unexpanded\def\setteststrut
+ {\def\strutwidth{.8pt}%
+ \setstrut}
+
+\unexpanded\def\dontshowstruts
+ {\unsetteststrut
+ \settestcrlf}
+
+\unexpanded\def\unsetteststrut
+ {\let\strutwidth\zeropoint
+ \setstrut}
+
+\def\autostrutfactor{1.1}
+
+\unexpanded\def\setautostrut
+ {\begingroup
+ \setbox\scratchbox\copy\strutbox
+ \setstrut
+ \ifdim\strutht>\autostrutfactor\ht\scratchbox
+ \endgroup \setstrut
+ \orelse\ifdim\strutdp>\autostrutfactor\dp\scratchbox
+ \endgroup \setstrut
+ \else
+ \endgroup
+ \fi}
+
+\newbox\nostrutbox \setbox\nostrutbox\emptyhbox
+
+\newtoks\everysetnostrut
+
+\unexpanded\def\setnostrut
+ {\the\everysetnostrut}
+
+\appendtoks
+ \setbox\strutbox\copy\nostrutbox
+ \let\strut\empty
+ \let\endstrut\empty
+ \let\begstrut\empty
+\to \everysetnostrut
+
+%D When enabled, sigstruts will remove themselves if nothing goes inbetween. For
+%D practical reasons we define some boundary characters here.
+
+\unexpanded\def\leftboundary {\protrusionboundary\plusone}
+\unexpanded\def\rightboundary {\protrusionboundary\plustwo}
+\unexpanded\def\signalcharacter{\boundary\plusone\char\zerocount\boundary\plustwo} % not the same as strut signals
+
+\newsignal\strutsignal \setfalse\sigstruts
+
+\unexpanded\def\begstrut
+ {\relax\ifcase\strutht
+ % \ignorespaces % maybe
+ \else
+ \spac_struts_beg
+ \fi}
+
+\def\spac_struts_beg
+ {\ifconditional\sigstruts
+ \spac_struts_beg_signal
+ \else
+ \spac_struts_beg_normal
+ \fi
+ \ignorespaces}
+
+\def\spac_struts_beg_signal
+ {\noindent\horizontalstrut
+ \penalty\plustenthousand
+ \hskip-\strutsignal
+ \hskip\strutsignal}
+
+\def\spac_struts_beg_normal
+ {\boundary\plusone
+ \strut
+ %\boundary\plusone
+ \penalty\plustenthousand
+ %\boundary\plusone
+ \hskip\zeropoint}
+
+\unexpanded\def\endstrut
+ {\relax\ifhmode
+ \ifcase\strutht
+ % \removeunwantedspaces % maybe
+ \else
+ \spac_struts_end
+ \fi
+ \fi}
+
+\def\spac_struts_end
+ {\ifconditional\sigstruts
+ \spac_struts_end_signal
+ \else
+ \spac_struts_end_normal
+ \fi}
+
+\def\spac_struts_end_signal
+ {\ifdim\lastskip=\strutsignal
+ \unskip
+ \unskip
+ \unpenalty
+ \setbox\scratchbox\lastbox
+ \else
+ \penalty\plustenthousand
+ \hskip\zeropoint
+ \strut
+ \fi}
+
+\def\spac_struts_end_normal
+ {\removeunwantedspaces
+ \penalty\plustenthousand
+ %\boundary\plustwo
+ \hskip\zeropoint
+ %\boundary\plustwo
+ \strut
+ \boundary\plustwo}
+
+% unsave:
+%
+% \def\pseudostrut
+% {\bgroup
+% \setnostrut
+% \normalstrut
+% \egroup}
+%
+% try:
+%
+% \startchemie
+% \chemie[ONE,Z0,SB15,MOV1,SB15,Z0][C,C]
+% \stopchemie
+%
+% so:
+
+\unexpanded\def\pseudostrut
+ {\noindent} % better: \dontleavehmode
+
+\let\pseudobegstrut\pseudostrut
+\let\pseudoendstrut\removeunwantedspaces
+
+\unexpanded\def\resetteststrut
+ {\def\strutwidth{\zeropoint}% no let
+ \setstrut}
+
+\ifdefined\setfontparameters \else
+ \def\setfontparameters{\the\everybodyfont}
+\fi
+
+%D Keyword based strutting:
+
+\letvalue{\??struts\v!yes }\setstrut
+\letvalue{\??struts\v!auto }\setautostrut
+\letvalue{\??struts\v!no }\setnostrut
+\letvalue{\??struts\v!cap }\setcapstrut
+\letvalue{\??struts\v!fit }\setfontstrut
+\letvalue{\??struts\v!line }\setstrut
+\letvalue{\??struts\s!default}\setstrut
+\letvalue{\??struts\empty }\setstrut
+
+%D Handy:
+
+\def\baselinedistance{\the\lineheight}
+
+%D We need \type {\normaloffinterlineskip} because the new definition contains an
+%D assignment, and |<|don't ask me why|>| this assignment gives troubles in for
+%D instance the visual debugger.
+
+\unexpanded\def\offinterlineskip
+ {\baselineskip-\thousandpoint
+ \lineskip \zeropoint
+ \lineskiplimit\maxdimen
+ % We also need this here now; thanks to taco for figuring that out!
+ \def\minimumlinedistance{\zeropoint}}
+
+\unexpanded\def\nointerlineskip
+ {\prevdepth-\thousandpoint}
+
+\let\normaloffinterlineskip\offinterlineskip % knuth's original
+
+%D This is tricky. The prevdepth value is still set to the last one even if there is
+%D nothing on the page. The same is true for prevgraf, which doesn't resemble the
+%D value on the current page.
+%D
+%D So, here we kick in a checker but it has to happen after the output group and it
+%D only has to be done once (output can trigger itself!).
+%D
+%D However, prevgraf is somehow bound to hangindent so we can get very nasty side
+%D effects. So, in tne end we use our own variable!
+
+\ifdefined\getnofpreviouslines
+ % defined public at the lua end
+\else
+ \let\getnofpreviouslines\!!zerocount
+\fi
+
+\unexpanded\def\page_otr_synchronize_page_yes
+ {\aftergroup\page_otr_synchronize_page_indeed
+ \glet\page_otr_synchronize_page\relax}
+
+% \unexpanded\def\page_otr_synchronize_page_indeed
+% {\clf_synchronizepage
+% \glet\page_otr_synchronize_page\page_otr_synchronize_page_yes}
+%
+% This has to become an otr method: \s!page_otr_command_synchonize_page
+
+\unexpanded\def\page_otr_synchronize_page_indeed
+ {\ifx\currentoutputroutine\s!multicolumn\else\clf_synchronizepage\fi
+ \glet\page_otr_synchronize_page\page_otr_synchronize_page_yes}
+
+\let\page_otr_synchronize_page\page_otr_synchronize_page_yes
+
+\appendtoks
+ \page_otr_synchronize_page
+\to \everyaftershipout
+
+%D My own one:
+
+\unexpanded\def\spac_helpers_push_interlineskip_yes
+ {\edef\oninterlineskip
+ {\baselineskip \the\baselineskip
+ \lineskip \the\lineskip
+ \lineskiplimit\the\lineskiplimit
+ \noexpand\edef\noexpand\minimumlinedistance{\the\dimexpr\minimumlinedistance}%
+ \let\noexpand\offinterlineskip\noexpand\normaloffinterlineskip}} % \noexpand not needed
+
+\unexpanded\def\spac_helpers_push_interlineskip_nop
+ {\let\oninterlineskip\setnormalbaselines}
+
+\unexpanded\def\offinterlineskip
+ {\ifdim\baselineskip>\zeropoint
+ \spac_helpers_push_interlineskip_yes
+ \else
+ \spac_helpers_push_interlineskip_nop
+ \fi
+ \normaloffinterlineskip}
+
+\let\oninterlineskip\relax
+
+\unexpanded\def\leaveoutervmode
+ {\ifvmode\ifinner\else
+ \leavevmode
+ \fi\fi}
+
+\unexpanded\def\resetpenalties#1%
+ {\ifdefined#1%
+ #1\minusone
+ \fi}
+
+\unexpanded\def\setpenalties#1#2#3%
+ {\ifdefined#1% space before #3 prevents lookahead problems, needed when #3=text
+ #1\numexpr#2+\plusone\relax\space\doexpandedrecurse{\the\numexpr#2\relax}{ #3}\zerocount\relax
+ \fi}
+
+%D \macros
+%D {keeplinestogether}
+%D
+%D Dirty hack, needed in margin content that can run of a page.
+
+% just before margintexts ... will eventually be done differently in mkiv using
+% attributes
+
+\newcount\c_spac_keep_lines_together
+\let\restoreinterlinepenalty\relax
+
+\unexpanded\def\spac_penalties_restore
+ {\glet\restoreinterlinepenalty\relax
+ \global\resetpenalties\interlinepenalties
+ \global\c_spac_keep_lines_together\zerocount}
+
+\unexpanded\def\keeplinestogether#1%
+ {\ifnum#1>\c_spac_keep_lines_together
+ \global\c_spac_keep_lines_together#1%
+ \global\setpenalties\interlinepenalties\c_spac_keep_lines_together\plustenthousand
+ \glet\restoreinterlinepenalty\spac_penalties_restore
+ \fi}
+
+\def\defaultdisplaywidowpenalty {50}
+\def\defaultwidowpenalty {2000} % was: 1000
+\def\defaultclubpenalty {2000} % was: 800
+\def\defaultbrokenpenalty {100}
+\def\defaultdoublehyphendemerits {10000}
+\def\defaultfinalhyphendemerits {5000}
+\def\defaultadjdemerits {10000}
+
+\def\defaultgriddisplaywidowpenalty {0}
+\def\defaultgridwidowpenalty {0}
+\def\defaultgridclubpenalty {0}
+\def\defaultgridbrokenpenalty {0}
+\def\defaultgriddoublehyphendemerits{10000} % always was so
+\def\defaultgridfinalhyphendemerits {5000} % always was so
+\def\defaultgridadjdemerits {10000} % always was so
+
+\unexpanded\def\nopenalties
+ {\widowpenalty \zerocount
+ \clubpenalty \zerocount
+ \brokenpenalty \zerocount
+ \doublehyphendemerits\zerocount
+ \finalhyphendemerits \zerocount
+ \adjdemerits \zerocount}
+
+\unexpanded\def\setdefaultpenalties
+ {\directsetup{\systemsetupsprefix\s!default}}
+
+\startsetups [\systemsetupsprefix\s!reset]
+ \resetpenalties\widowpenalties
+ \resetpenalties\clubpenalties
+ \resetpenalties\interlinepenalties
+\stopsetups
+
+%D We use \directsetup because it's faster and we know there is no csl:
+
+\startsetups [\systemsetupsprefix\s!default]
+
+ \directsetup{\systemsetupsprefix\s!reset}
+
+ \widowpenalty \defaultwidowpenalty
+ \clubpenalty \defaultclubpenalty
+ \displaywidowpenalty \defaultdisplaywidowpenalty
+ \brokenpenalty \defaultbrokenpenalty
+ \doublehyphendemerits\defaultdoublehyphendemerits
+ \finalhyphendemerits \defaultfinalhyphendemerits
+ \adjdemerits \defaultadjdemerits
+
+\stopsetups
+
+\startsetups [\v!grid] [\systemsetupsprefix\s!default]
+
+ \directsetup{\systemsetupsprefix\s!reset}
+
+ \widowpenalty \defaultgridwidowpenalty
+ \clubpenalty \defaultgridclubpenalty
+ \displaywidowpenalty \defaultgriddisplaywidowpenalty
+ \brokenpenalty \defaultgridbrokenpenalty
+ \doublehyphendemerits\defaultgriddoublehyphendemerits
+ \finalhyphendemerits \defaultgridfinalhyphendemerits
+ \adjdemerits \defaultgridadjdemerits
+
+\stopsetups
+
+%D As an illustration:
+
+\startsetups [\systemsetupsprefix\v!strict]
+
+ \directsetup{\systemsetupsprefix\s!reset}
+
+ \setpenalties \widowpenalties \plustwo \maxdimen
+ \setpenalties \clubpenalties \plustwo \maxdimen
+ \brokenpenalty \maxdimen
+ \doublehyphendemerits \defaultdoublehyphendemerits
+ \finalhyphendemerits \defaultfinalhyphendemerits
+ \adjdemerits \defaultadjdemerits
+
+\stopsetups
+
+\setdefaultpenalties % will happen later in \setuplayout
+
+%D To be checked:
+
+\newbox\b_spac_struts_saved
+
+\unexpanded\def\savestrut {\setbox\b_spac_struts_saved\copy\strutbox}
+\unexpanded\def\savedstrut{\copy \b_spac_struts_saved}
+
+%D Good old blank redone:
+
+%definesystemattribute[kernchars] [public]
+\definesystemattribute[skipcategory] [public]
+\definesystemattribute[skippenalty] [public]
+\definesystemattribute[skiporder] [public]
+\definesystemattribute[snapmethod] [public]
+\definesystemattribute[snapvbox] [public]
+%definesystemattribute[snapcategory] [public]
+
+% TODO: NAMED SNAPPERS
+
+\installcorenamespace{gridsnappers}
+\installcorenamespace{gridsnapperattributes}
+\installcorenamespace{gridsnappersets}
+
+\newskip \bodyfontlineheight
+\newdimen \bodyfontstrutheight
+\newdimen \bodyfontstrutdepth
+
+\newskip \globalbodyfontlineheight % why a skip
+\newdimen \globalbodyfontstrutheight
+\newdimen \globalbodyfontstrutdepth
+
+\def\snappedvboxattribute{\ifgridsnapping attr \snapvboxattribute \attribute\snapmethodattribute\fi}
+\def\setlocalgridsnapping{\ifgridsnapping \attribute \snapvboxattribute \attribute\snapmethodattribute\fi}
+
+\def\spac_grids_set_local_snapping#1%
+ {\ifgridsnapping
+ \doifsomething{#1}%
+ {\spac_grids_snap_value_set{#1}%
+ \attribute \snapvboxattribute \attribute\snapmethodattribute}%
+ \fi}
+
+\def\spac_grids_expand_snapper#1%
+ {\edef\m_spac_snapper
+ {\ifx\m_spac_snapper\empty\else\m_spac_snapper,\fi
+ \ifcsname\??gridsnappersets#1\endcsname
+ \lastnamedcs\else#1%
+ \fi}}
+
+\unexpanded\def\installsnapvalues#1#2%
+ {\let\m_spac_snapper\empty
+ \rawprocesscommacommand[#2]\spac_grids_expand_snapper
+ \edef\currentsnapper{#1:\m_spac_snapper}%
+ \ifcsname\??gridsnapperattributes\currentsnapper\endcsname
+ \scratchcounter\lastnamedcs % already defined
+ \else
+ \scratchcounter\clf_definesnapmethod{#1}{\m_spac_snapper}%
+ \setevalue{\??gridsnapperattributes\currentsnapper}{\the\scratchcounter}%
+ \fi
+ \setevalue{\??gridsnappers#1}{\attribute\snapmethodattribute\the\scratchcounter\relax}%
+ \letvalue{\??gridsnappersets#1}\m_spac_snapper}
+
+\def\theexpandedsnapperset#1{\begincsname\??gridsnappersets#1\endcsname} % only for manuals
+
+\unexpanded\def\usegridparameter#1% no checking here
+ {\edef\m_spac_grid_asked{#1\c!grid}%
+ \ifx\m_spac_grid_asked\empty
+ \attribute \snapvboxattribute\attributeunsetvalue
+ \else
+ \spac_grids_snap_value_set\m_spac_grid_asked
+ \attribute \snapvboxattribute\attribute\snapmethodattribute
+ \fi}
+
+\unexpanded\def\definegridsnapping
+ {\dodoubleargument\spac_grids_define}
+
+\def\spac_grids_define[#1][#2]%
+ {\installsnapvalues{#1}{#2}}
+
+\edef\spac_grids_snap_value_reset
+ {%\gridsnappingfalse
+ \attribute\snapmethodattribute\attributeunsetvalue}
+
+\def\spac_grids_snap_value_set#1%
+ {%\gridsnappingtrue
+ \begincsname\??gridsnappers#1\endcsname}
+
+% maybe:
+%
+% \def\spac_grids_snap_value_set#1%
+% {%\gridsnappingtrue
+% \ifcsname\??gridsnappers#1\endcsname
+% \lastnamedcs
+% \else
+% \definegridsnapping[#1][#1]%
+% \begincsname\??gridsnappers#1\endcsname
+% \fi}
+
+\def\spac_grids_snap_value_auto#1%
+ {\ifcsname\??gridsnappers#1\endcsname
+ \lastnamedcs
+ \else
+ \installsnapvalues\s!dummy{#1}%
+ \csname\??gridsnappers\s!dummy\endcsname
+ \fi}
+
+% \installsnapvalues{loose} {\v!maxdepth:0.8,\v!maxheight:0.8,\v!strut}
+% \installsnapvalues{normal}{\v!maxdepth:1.0,\v!maxheight:1.0,\v!strut}
+% \installsnapvalues{tight} {\v!maxdepth:1.2,\v!maxheight:1.2,\v!strut}
+
+% none don't enlarge
+% halfline enlarge by halfline/halfline
+% line enlarge by line/line
+% strut enlarge by ht/dp (default)
+% first align to top line
+% last align to bottom line
+% mindepth round depth down
+% maxdepth round depth up
+% minheight round height down
+% maxheight round height up
+% local use local interline space
+% offset:-3tp vertical shift within box
+% bottom:lines
+% top:lines
+% box centers a box rounded upwards (box:.5 -> tolerance)
+% min centers a box rounded downwards
+% max centers a box rounded upwards
+
+%D We're not downward compatible with \MKII ! Not yet in interface file:
+
+\definegridsnapping[\v!normal] [\v!maxheight,\v!maxdepth,\v!strut]
+\definegridsnapping[\v!standard] [\v!maxheight,\v!maxdepth,\v!strut]
+\definegridsnapping[\v!yes] [\v!maxheight,\v!maxdepth,\v!strut]
+
+\definegridsnapping[\v!strict] [\v!maxdepth:0.8,\v!maxheight:0.8,\v!strut]
+\definegridsnapping[\v!tolerant] [\v!maxdepth:1.2,\v!maxheight:1.2,\v!strut]
+\definegridsnapping[\v!verytolerant] [\v!maxdepth:1.4,\v!maxheight:1.4,\v!strut]
+
+\definegridsnapping[\v!tolerant:10] [\v!maxdepth:1.1,\v!maxheight:1.1,\v!strut] % 10 pct tolerance
+\definegridsnapping[\v!tolerant:20] [\v!maxdepth:1.2,\v!maxheight:1.2,\v!strut] % 20 pct tolerance
+\definegridsnapping[\v!tolerant:30] [\v!maxdepth:1.3,\v!maxheight:1.3,\v!strut] % 30 pct tolerance
+\definegridsnapping[\v!tolerant:40] [\v!maxdepth:1.4,\v!maxheight:1.4,\v!strut] % 40 pct tolerance
+
+\definegridsnapping[\v!top] [\v!minheight,\v!maxdepth,\v!strut]
+\definegridsnapping[\v!bottom] [\v!maxheight,\v!mindepth,\v!strut]
+\definegridsnapping[\v!both] [\v!minheight,\v!mindepth,\v!strut]
+
+\definegridsnapping[\v!broad] [\v!maxheight,\v!maxdepth,\v!strut,0.8] % maybe 0.85
+\definegridsnapping[\v!fit] [\v!maxheight,\v!maxdepth,\v!strut,1.2] % tight 0.15
+
+\definegridsnapping[\v!first] [\v!first]
+\definegridsnapping[\v!last] [\v!last]
+\definegridsnapping[\v!high] [\v!minheight,\v!maxdepth,\v!none]
+\definegridsnapping[\v!one] [\v!minheight,\v!mindepth]
+\definegridsnapping[\v!low] [\v!maxheight,\v!mindepth,\v!none]
+\definegridsnapping[\v!none] [\v!none]
+\definegridsnapping[\v!line] [\v!line]
+\definegridsnapping[\v!strut] [\v!strut]
+\definegridsnapping[\v!box] [\v!box]
+\definegridsnapping[\v!min] [\v!min]
+\definegridsnapping[\v!max] [\v!max]
+
+\definegridsnapping[\v!middle] [\v!maxheight,\v!maxdepth] % used in placement
+
+\definegridsnapping[\v!math] [\v!maxdepth:1.05,\v!maxheight:1.05,\v!strut] % experimental, maybe 1.1
+\definegridsnapping[\v!math:\v!line] [\v!math,\v!line,\v!split]
+\definegridsnapping[\v!math:\v!halfline] [\v!math,\v!halfline,\v!split]
+\definegridsnapping[\v!math:-\v!line] [\v!math,-\v!line,\v!split]
+\definegridsnapping[\v!math:-\v!halfline][\v!math,-\v!halfline,\v!split]
+
+\unexpanded\def\synchronizelocallinespecs
+ {\bodyfontlineheight \normallineheight
+ \bodyfontstrutheight\strutht
+ \bodyfontstrutdepth \strutdp}
+
+\unexpanded\def\synchronizegloballinespecs
+ {\global\globalbodyfontlineheight \normallineheight
+ \global\globalbodyfontstrutheight\strutht
+ \global\globalbodyfontstrutdepth \strutdp}
+
+\appendtoks
+ \synchronizegloballinespecs
+ \synchronizelocallinespecs
+\to \everysetupglobalinterlinespace
+
+\appendtoks
+ \synchronizelocallinespecs
+\to \everysetuplocalinterlinespace
+
+%D We still have to synchronize these:
+
+\unexpanded\def\synchronizeskipamounts
+ {\bigskipamount
+ \skipfactor\baselineskip
+ \s!plus\skipgluefactor\baselineskip
+ \s!minus\skipgluefactor\baselineskip
+ \relax
+ \medskipamount \bigskipamount \divide\medskipamount \plustwo
+ \smallskipamount\bigskipamount \divide\smallskipamount\plusfour}
+
+%D Snapping.
+
+\newif\ifgridsnapping
+
+%unexpanded\def\moveongrid {\dosingleempty\spac_grids_move_on}
+\unexpanded\def\snaptogrid {\dosingleempty\spac_grids_snap_to}
+\unexpanded\def\placeongrid{\dosingleempty\spac_grids_place_on}
+
+\unexpanded\def\startgridsnapping
+ {\dosingleempty\spac_grids_start_snapping}
+
+\unexpanded\def\spac_grids_start_snapping[#1]%
+ {\snaptogrid[#1]\vbox\bgroup}
+
+\unexpanded\def\stopgridsnapping
+ {\egroup}
+
+% \def\spac_grids_move_on[#1]%
+% {[obsolete]} % gone, unless we set an attribute
+
+\def\spac_grids_place_on[#1]%
+ {\snaptogrid[#1]\vbox} % mark as done
+
+\def\spac_grids_snap_to[#1]% list or predefined
+ {\ifgridsnapping
+ \expandafter\spac_grids_snap_to_indeed
+ \else
+ \expandafter\gobbleoneargument
+ \fi{#1}}
+
+\def\spac_grids_snap_to_indeed#1%
+ {\bgroup
+ \spac_grids_snap_value_reset
+ \dowithnextbox{\spac_grids_snap_to_finish{#1}}}
+
+% eventually there will always be a line snap
+
+\def\spac_grids_snap_to_finish#1%
+ {\ifvbox\nextbox % this will go away
+ \clf_vspacingcollapse\nextbox\relax % isn't that already done?
+ \fi
+ \doifelsenothing{#1}{\spac_grids_snap_value_set\v!normal}{\spac_grids_snap_value_set{#1}}%
+ \clf_vspacingsnap\nextbox\attribute\snapmethodattribute\relax
+ \ifvbox\nextbox\vbox\else\hbox\fi attr \snapmethodattribute \zerocount {\box\nextbox}% no pack (?), we snap
+ \egroup}
+
+\def\spac_grids_check_nop
+ {\gridsnappingfalse
+ \resetsystemmode\v!grid
+ \spac_grids_snap_value_reset}
+
+\def\spac_grids_check_yes
+ {\gridsnappingtrue
+ \setsystemmode\v!grid
+ \spac_grids_snap_value_set\askedgridmode}
+
+\unexpanded\def\synchronizegridsnapping
+ {\edef\askedgridmode{\layoutparameter\c!grid}%
+ \ifx\askedgridmode\v!no % official
+ \spac_grids_check_nop
+ \orelse\ifx\askedgridmode\v!off % for taco and luigi
+ \spac_grids_check_nop
+ \orelse\ifx\askedgridmode\empty % to be sure
+ \spac_grids_check_nop
+ \else
+ \spac_grids_check_yes
+ \fi}
+
+\unexpanded\def\setupgridsnapping[#1]% less overhead than setuplayout (needs testing)
+ {\setlayoutparameter\c!grid{#1}\synchronizegridsnapping}
+
+\unexpanded\def\checkgridmethod#1%
+ {\edef\p_grid{#1}%
+ \ifx\p_grid\empty
+ \let\checkedgridmethod\empty
+ \let\checkedgridscope \v!local
+ \else
+ \splitatcolon\p_grid\checkedgridscope\checkedgridmethod
+ \ifx\checkedgridmethod\empty
+ \ifx\checkedgridscope\v!local\orelse\ifx\checkedgridscope\v!global\else
+ \let\checkedgridmethod\checkedgridscope
+ \let\checkedgridscope \v!local
+ \fi
+ \fi
+ \fi}
+
+\unexpanded\def\applygridmethod#1#2#3% content localsettings (used in head rendering)
+ {\checkgridmethod{#1}%
+ \ifx\checkedgridscope\v!global
+ \ifx\checkedgridmethod\empty \else
+ % we assume that the call is grouped because grouping here has the side
+ % effect that the eventually constructed line will get the value outside
+ % the group
+ %
+ % overkill: \setupgridsnapping[\checkedgridmethod]%
+ % maybe : \spac_grids_snap_value_auto\checkedgridmethod
+ \spac_grids_snap_value_set\checkedgridmethod
+ \fi
+ \hbox{#3}%
+ \else
+ % the extra hbox will trigger the global snapper on top of the local and
+ % we really need that in this case (compatibility etc etc) so here we don't
+ % het an already done hit (otherwise we would not snap)
+ \hbox\bgroup
+ \ifx\checkedgridmethod\empty\orelse\ifconditional\headisdisplay
+ #2%
+ \fi
+ \snaptogrid[\checkedgridmethod]\hbox{#3}%
+ \egroup
+ \fi}
+
+\unexpanded\gdef\page_layouts_calculate_overshoot
+ {\ifgridsnapping\ifcase\layoutlines
+ \getnoflines\textheight
+ \textovershoot\dimexpr\noflines\globalbodyfontlineheight-\textheight\relax
+ \fi\fi}
+
+\unexpanded\def\page_layouts_report_overshoot
+ {\page_layouts_calculate_overshoot
+ \ifdim\textovershoot>\zeropoint
+ \writestatus\m!layouts{gridmode,\space
+ noflines: \the\noflines,\space
+ textheight: \the\textheight,\space
+ textovershoot: \the\textovershoot\space
+ (maybe set number of lines instead)%
+ }%
+ \fi
+ \glet\page_layouts_report_overshoot\page_layouts_calculate_overshoot}
+
+\appendtoks
+ \page_layouts_report_overshoot
+\to \everybeforepagebody
+
+%D Visualization:
+
+\definepalet
+ [grid]
+ [ one=red,
+ two=green,
+ three=blue,
+ four=gray]
+
+\unexpanded\def\setgridtracebox#1[#2]% % maybe reverse the order
+ {\setbox\nextbox#1%
+ {\hbox
+ {\hbox to \zeropoint
+ {\setlayoutcomponentattribute{\v!grid:\v!test}%
+ \color[grid:#2]{\ruledhbox \layoutcomponentboxattribute {\fakebox\nextbox}}%
+ \hss}%
+ \flushnextbox}}}
+
+\setnewconstant\gridboxlinenomode\plusone % 0:nothing 1:all 2:lines 3:frame 4:l/r
+\setnewconstant\gridboxlinemode \plusone
+
+\unexpanded\def\gridboxvbox
+ {\ifcase\gridboxlinemode
+ \vpack
+ \or
+ \ruledvpack
+ \or
+ \vpack
+ \or
+ \ruledvpack
+ \else
+ \ruledvpack
+ \fi}
+
+\def\gridboxwidth{\ifcase\gridboxlinemode0\or.5\or.5\or0\else.5\fi\linewidth}
+
+\unexpanded\def\setgridbox#1#2#3% maybe ifgridsnapping at outer level
+ {\setbox#1\gridboxvbox to #3 % given size
+ {\forgetall
+ \resetvisualizers
+ \resetteststrut
+ \offinterlineskip
+ \hsize#2%
+ \ifcase\gridboxlinenomode\or\or\or
+ \gridboxlinenomode\doifoddpageelse\plusone\plustwo % 3: outer
+ \or
+ \gridboxlinenomode\doifoddpageelse\plustwo\plusone % 4: inner
+ \fi
+ \topskipcorrection
+ \gridboxvbox % calculated size
+ {\getrawnoflines{#3}% \getnoflines{#3}%
+ \scratchdimen\dimexpr#2+\lineheight\relax
+ \dorecurse\noflines
+ {\strut
+ \hskip-.5\lineheight\relax
+ \ifcase\gridboxlinenomode\or
+ \rlap
+ {\hskip\dimexpr.2\bodyfontsize+\scratchdimen\relax
+ \infofont\hbox to \emwidth{\hss\recurselevel}}%
+ \or
+ \llap
+ {\infofont\hbox to \emwidth{\hss\recurselevel}%
+ \hskip.2\bodyfontsize}%
+ \fi
+ \vrule
+ \s!height \gridboxwidth
+ \s!depth \gridboxwidth
+ \s!width \scratchdimen
+ \par}}
+ \vfill}}
+
+%D This has become obsolete:
+
+\def\fuzzysnappedbox#1#2% \box<n> \unvbox<n>
+ {#1#2}
+
+\def\moveboxontogrid#1#2#3% will become obsolete, but it needs checking
+ {}
+
+%D Helper:
+
+\unexpanded\def\spac_helpers_assign_skip#1#2% ook nog \v!halfline+fuzzysnap
+ {\doifelse{#2}\v!line
+ {#1\ifgridsnapping
+ \bodyfontlineheight
+ \else
+ \openlineheight
+ \fi}
+ {\ifgridsnapping
+ \assigndimension{#2}{#1}{.25\bodyfontlineheight}{.5\bodyfontlineheight}\bodyfontlineheight
+ \else
+ \assigndimension{#2}{#1}\smallskipamount\medskipamount\bigskipamount
+ \fi}%
+ \relax}
+
+% \start \dosetstretch{.25em} \setuptolerance[tolerant,stretch] \input tufte \endgraf \stop
+% \start \dosetstretch{.5em} effe flink doorfietsen \stop
+
+% experimental code, not yet interfaced:
+
+% category:
+%
+% 0 == discard discard
+% 1 == only if larger largest
+% 2 == force even if smaller force
+% 3 == only take penalty component penalty
+% 4 == add to existing skip add
+% 5 == disable (ignore following) disable
+% 6 == kill whitespace nowhite
+% 7 == discard previous back
+% 10 == no topskip
+%
+% penalty: larger wins
+% order: larger wins
+% category:2,order:5,penalty:10000,skip:value|kw
+%
+% \defineblankmethod [\v!joinedup] {\ifvmode\nointerlineskip\fi}
+
+% todo, in grid mode: builders.vspacing.fixed = false
+%
+% \ifgridsnapping will go
+
+\installcorenamespace{vspacingamount}
+
+\unexpanded\def\definevspacingamount
+ {\dotripleempty\spac_vspacing_define_amount}
+
+\def\spac_vspacing_define_amount[#1][#2][#3]% can be combined
+ {\ifthirdargument
+ \setvalue{\??vspacingamount#1}{\ifgridsnapping#3\else#2\fi}%
+ \orelse\ifsecondargument
+ \setvalue{\??vspacingamount#1}{\ifgridsnapping\lineheight\else#2\fi}%
+ \else
+ \setvalue{\??vspacingamount#1}{\lineheight}%
+ \fi
+ \clf_vspacingsetamount{#1}}
+
+\def\spac_vspacing_no_topskip % use grouped
+ {\attribute\skipcategoryattribute\plusten}
+
+% \installcorenamespace{vspacingamountnormal}
+% \installcorenamespace{vspacingamountgrid}
+
+% \def\spac_vspacing_define_amount[#1][#2][#3]% can be combined
+% {\ifcsname n>#1\endcsname\else
+% \expandafter\newtoks\csname n>#1\endcsname
+% \expandafter\newtoks\csname g>#1\endcsname
+% \fi
+% \csname n>#1\endcsname{#2}%
+% \csname g>#1\endcsname{#3}%
+% \clf_vspacingsetamount{#1}}
+
+\unexpanded\def\definevspacing
+ {\dodoubleempty\spac_vspacing_define}
+
+\def\spac_vspacing_define[#1][#2]%
+ {\clf_vspacingdefine{#1}{#2}}
+
+%D The injector code (generated at the \LUA\ end):
+
+\newtoks\everybeforeblankhandling
+\newtoks\everyafterblankhandling
+
+\newconditional\c_space_vspacing_done
+\newconditional\c_space_vspacing_fixed
+\newconditional\c_space_ignore_parskip
+
+\appendtoks
+ \s_spac_vspacing_temp\zeropoint
+ \attribute\skipcategoryattribute\plusone
+ \attribute\skippenaltyattribute \attributeunsetvalue
+ \attribute\skiporderattribute \attributeunsetvalue
+ \ifgridsnapping
+ \settrue\c_space_vspacing_fixed
+ \else
+ \setfalse\c_space_vspacing_fixed
+ \fi
+\to \everybeforeblankhandling
+
+\appendtoks
+ \s_spac_vspacing_temp\plusone\s_spac_vspacing_temp
+ \ifconditional\c_space_vspacing_fixed \else
+ \s!plus \skipgluefactor\s_spac_vspacing_temp
+ \s!minus\skipgluefactor\s_spac_vspacing_temp
+ \fi
+ \relax
+\to \everyafterblankhandling
+
+\unexpanded\def\setblankpacked
+ {\settrue\c_space_ignore_parskip}
+
+\unexpanded\def\setblankcategory#1%
+ {\settrue\c_space_vspacing_done
+ \attribute\skipcategoryattribute#1\relax}
+
+\unexpanded\def\setblankorder#1%
+ {\attribute\skiporderattribute#1\relax}
+
+\unexpanded\def\fixedblankskip
+ {\settrue\c_space_vspacing_fixed}
+
+\unexpanded\def\flexibleblankskip
+ {\setfalse\c_space_vspacing_fixed}
+
+% \unexpanded\def\addblankskip#1#2#3%
+% {\settrue\c_space_vspacing_done
+% \advance\s_spac_vspacing_temp#1\dimexpr\ifgridsnapping#3\else#2\fi\relax\relax}
+
+\unexpanded\def\setblankpenalty#1%
+ {\flushblankhandling
+ \settrue\c_space_vspacing_done
+ \attribute\skipcategoryattribute \plusthree
+ \attribute\skippenaltyattribute #1\relax
+ \flushblankhandling}
+
+\unexpanded\def\startblankhandling % move this to \vspacing
+ {\par
+ \ifvmode
+ \expandafter\dostartblankhandling
+ \else
+ \expandafter\nostartblankhandling
+ \fi}
+
+\unexpanded\def\nostartblankhandling#1\stopblankhandling
+ {}
+
+\def\dostartblankhandling
+ {\begingroup
+ \setfalse\c_space_vspacing_done
+ \setfalse\c_space_ignore_parskip
+ \the\everybeforeblankhandling}
+
+\unexpanded\def\stopblankhandling
+ {\the\everyafterblankhandling
+ \ifconditional\c_space_vspacing_done
+ \vskip\s_spac_vspacing_temp
+ \fi
+ \ifconditional\c_space_ignore_parskip
+ \endgroup\ignoreparskip
+ \else
+ \endgroup
+ \fi}
+
+\unexpanded\def\flushblankhandling
+ {\the\everyafterblankhandling
+ \ifconditional\c_space_vspacing_done
+ \vskip\s_spac_vspacing_temp
+ \fi
+ \setfalse\c_space_vspacing_done
+ \the\everybeforeblankhandling}
+
+\unexpanded\def\addpredefinedblankskip#1#2%
+ {\settrue\c_space_vspacing_done
+ \advance\s_spac_vspacing_temp#1\dimexpr\csname\??vspacingamount#2\endcsname\relax}
+
+% \unexpanded\def\addpredefinedblankskip#1#2%
+% {\settrue\c_space_vspacing_done
+% \advance\s_spac_vspacing_temp#1\dimexpr\the\csname\ifgridsnapping g\else n\fi>#2\endcsname\relax}
+
+\unexpanded\def\addaskedblankskip#1#2%
+ {\settrue\c_space_vspacing_done
+ \advance\s_spac_vspacing_temp#1\dimexpr#2\relax}
+
+% The main spacer:
+
+\unexpanded\def\vspacing
+ {\doifelsenextoptionalcs\spac_vspacing_yes\spac_vspacing_nop}
+
+\def\spac_vspacing_yes
+ {\ifinpagebody % somewhat weird
+ \expandafter\spac_vspacing_yes_indeed
+ \orelse\ifconditional\c_spac_packed_blank
+ \expandafter\spac_vspacing_yes_indeed
+ \else
+ \expandafter\spac_vspacing_yes_ignore
+ \fi}
+
+\def\spac_vspacing_nop
+ {\ifinpagebody % somewhat weird
+ \expandafter\spac_vspacing_nop_indeed
+ \orelse\ifconditional\c_spac_packed_blank
+ \expandafter\spac_vspacing_nop_indeed
+ \else
+ \expandafter\spac_vspacing_nop_ignore
+ \fi}
+
+\def\spac_vspacing_yes_indeed[#1]%
+ {\ifmmode\else\par\clf_vspacing{#1}\fi}
+
+\def\spac_vspacing_yes_ignore[#1]%
+ {\ifmmode\else\par\fi}
+
+\def\spac_vspacing_nop_indeed
+ {\ifmmode\else\par\clf_vspacing{\currentvspacing}\fi}
+
+\def\spac_vspacing_nop_ignore
+ {\ifmmode\else\par\fi}
+
+\installcorenamespace{vspacing}
+
+\unexpanded\def\directvspacing#1%
+ {\par
+ \ifchkdim#1\or
+ \spac_vspacing_dim_preset{\the\dimexpr#1}%
+ \orelse\ifcsname\??vspacing#1\endcsname
+ \lastnamedcs
+ \else
+ \spac_vspacing_yes_preset{#1}%
+ \fi}
+
+\def\spac_vspacing_dim_preset#1%
+ {\ifcsname\??vspacing#1\endcsname
+ \lastnamedcs
+ \else
+ \spac_vspacing_yes_preset{#1}%
+ \fi}
+
+\def\spac_vspacing_yes_preset#1%
+ {\setxvalue{\??vspacing#1}{\clf_vspacing{#1}}%
+ %\writestatus{}{}%
+ %\writestatus{#1}{\expandafter\meaning\csname\??vspacing#1\endcsname}%
+ %\writestatus{}{}%
+ \csname\??vspacing#1\endcsname}
+
+\def\spac_vspacing_yes_indeed[#1]%
+ {\ifmmode\else
+ \directvspacing{#1}%
+ \fi}
+
+\def\spac_vspacing_nop_indeed
+ {\ifmmode\else
+ \directvspacing\currentvspacing
+ \fi}
+
+\def\directdefaultvspacing
+ {\ifinpagebody % somewhat weird
+ \directvspacing\currentvspacing
+ \orelse\ifconditional\c_spac_packed_blank
+ \directvspacing\currentvspacing
+ \fi}
+
+\def\directcheckedvspacing
+ {\ifinpagebody % somewhat weird
+ \expandafter\directvspacing
+ \orelse\ifconditional\c_spac_packed_blank
+ \expandafter\directvspacing
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\unexpanded\def\useblankparameter#1% faster local variant
+ {\edef\m_spac_blank_asked{#1\c!blank}%
+ \ifx\m_spac_blank_asked\empty\else
+ \directvspacing\m_spac_blank_asked
+ \fi}
+
+%D Handy (and faster):
+
+\unexpanded\def\directvpenalty#1%
+ {\begingroup
+ \attribute\skipcategoryattribute \plusthree
+ \attribute\skippenaltyattribute #1\relax
+ \attribute\skiporderattribute \attributeunsetvalue
+ \vskip\zeropoint
+ \endgroup}
+
+\unexpanded\def\directvskip#1%
+ {\begingroup
+ \attribute\skipcategoryattribute \plusone
+ \attribute\skippenaltyattribute \attributeunsetvalue
+ \attribute\skiporderattribute \attributeunsetvalue
+ \vskip#1\relax
+ \endgroup}
+
+%D These depend on bigskipamount cum suis so we'd better sync them:
+
+\unexpanded\def\setupvspacing
+ {\doifelsenextoptionalcs\setupvspacing_yes\setupvspacing_nop}
+
+\let\currentvspacing\s!default % hm, default, standard ...
+
+\def\setupvspacing_yes[#1]%
+ {\edef\currentvspacing{#1}%
+ \spac_whitespace_setup_nop % yes or no, was forgotten
+ }
+
+\def\setupvspacing_nop
+ {\ifx\empty\currentvspacing % mistakenly had an \else
+ \let\currentvspacing\s!default
+ \fi
+ \spac_whitespace_setup_nop}
+
+\unexpanded\def\restorestandardblank % or default ?
+ {\let\currentvspacing\v!standard}
+
+\let\synchronizevspacing\setupvspacing_nop
+
+%D The \type {category:4} is default.
+
+\definevspacingamount[\v!none] [\zeropoint] [\zeropoint]
+\definevspacingamount[\v!big] [\bigskipamount] [\bodyfontlineheight]
+\definevspacingamount[\v!medium] [\medskipamount] [.5\bodyfontlineheight]
+\definevspacingamount[\v!small] [\smallskipamount] [.25\bodyfontlineheight]
+\definevspacingamount[\v!line] [\openlineheight] [\bodyfontlineheight]
+\definevspacingamount[\v!halfline] [.5\openlineheight] [.5\bodyfontlineheight]
+\definevspacingamount[\v!quarterline] [.25\openlineheight] [.25\bodyfontlineheight]
+\definevspacingamount[\v!formula] [\medskipamount] [.5\bodyfontlineheight]
+\definevspacingamount[\v!white] [\parskip] [\bodyfontwhitespace]
+\definevspacingamount[\v!height] [\strutht] [\bodyfontstrutheight]
+\definevspacingamount[\v!depth] [\strutdp] [\bodyfontstrutdepth]
+
+\definevspacingamount[\v!standard] [.75\openlineheight] [.75\openlineheight] % mkii compatible
+
+\def\bodyfontwhitespace
+ {\dimexpr
+ \ifzeropt\parskip
+ \zeropoint
+ \orelse\ifgridsnapping
+ \bodyfontlineheight
+ \else
+ \parskip
+ \fi
+ \relax}
+
+%D used in itemize \unknown\ always test this:
+
+\newdimen\d_spac_overlay
+
+\def\spac_overlay_lines
+ {\directcheckedvspacing{\v!back,\v!overlay}% \blank[\v!back,\v!overlay]%
+ \nointerlineskip}
+
+% \startitemize[n]
+% \item \input zapf
+% \item \startitemize[a]
+% \item \input knuth
+% \stopitemize
+% \stopitemize
+%
+% \strut \hfill first line \blank[overlay] second line \hfill \strut
+%
+% \ruledvbox {
+% \strut \hfill line 1 \blank[overlay]
+% line 2 \hfill \strut \blank[overlay]
+% \strut \hfill line 3 \hfill \strut
+% }
+%
+% \dorecurse{50}
+% {\startitemize[n] \startitem \startitemize[a] \item #1 \stopitemize \stopitem \stopitemize}
+
+\definevspacing[\v!preference][penalty:-500] % goodbreak
+\definevspacing[\v!samepage] [penalty:10000] % nobreak
+
+\definevspacing[\v!always] [category:0] % hm, internally it's discard
+\definevspacing[\v!max] [category:1]
+\definevspacing[\v!force] [category:2]
+\definevspacing[\v!disable] [category:5]
+\definevspacing[\v!nowhite] [category:6]
+\definevspacing[\v!back] [category:7]
+\definevspacing[\v!packed] [category:8] % noparskip (kind of special)
+\definevspacing[\v!overlay] [category:9]
+\definevspacing[\v!enable] [category:10]
+
+%definevspacing[\v!noparskip] [category:8]
+%definevspacing[\v!notopskip] [category:11]
+
+\definevspacing[\v!weak] [order:0]
+\definevspacing[\v!strong] [order:100]
+
+\definevspacing[\s!default] [\v!white] % was big for a while
+
+\newcount\c_spac_vspacing_special_base \c_spac_vspacing_special_base = 32250 % 4000
+\newcount\c_spac_vspacing_special_step \c_spac_vspacing_special_step = 10 % 250
+\newcount\c_spac_vspacing_special_done
+
+% 2019-05-31 : upgraded a bit to more distinctive samepage-[level]-[0|1|2] names
+
+\unexpanded\def\spac_vspacing_define_same_step#1#2% alternatively we could have samepage-n-m
+ {\begingroup
+ \scratchcounterone\numexpr\plusthree*#1+#2\relax
+ \scratchcountertwo\numexpr\c_spac_vspacing_special_base+\c_spac_vspacing_special_step*\scratchcounterone\relax
+ %\writestatus{defined}{\v!samepage-\number#1-\number#2\space=>\space penalty:\the\scratchcountertwo}%
+ \normalexpanded{\definevspacing[\v!samepage-\number#1-\number#2][penalty:\the\scratchcountertwo]}%
+ \endgroup}
+
+\unexpanded\def\spac_vspacing_define_same_page#1%
+ {\dostepwiserecurse\c_spac_vspacing_special_done{#1}\plusone
+ {\spac_vspacing_define_same_step\recurselevel\zerocount % before
+ \spac_vspacing_define_same_step\recurselevel\plusone % after
+ \spac_vspacing_define_same_step\recurselevel\plustwo}% % whatever
+ \global\c_spac_vspacing_special_done#1\relax}
+
+\spac_vspacing_define_same_page{12} % 12 levels should be more than enough as a start
+
+\def\spac_vspacing_same_page#1#2% level offset (starts at 0)
+ {\ifnum#1>\c_spac_vspacing_special_done
+ \spac_vspacing_define_same_page{#1}%
+ \fi
+ %\writestatus{used}{\v!samepage-\number#1-\number#2}%
+ \vspacing[\v!samepage-\number#1-\number#2]}
+
+\definevspacing[\v!default] [\v!big] % todo: needs to adapt to \setupblank
+\definevspacing[\v!before] [\v!default] % but we need to avoid circular references
+\definevspacing[\v!inbetween][\v!default] % then
+\definevspacing[\v!after] [\v!before]
+
+\setupvspacing
+ [\v!big] % alternatively [\v!standard]
+
+%D Maybe at some point we will differ between \type {\vspacing} and \type {\blank}
+%D (we needed the first one while playing with the new code).
+
+% We keep this one as reference
+%
+% \unexpanded\def\inhibitblank
+% {\vspacing[\v!disable]}
+%
+% but use the following more efficient variant instead:
+
+\unexpanded\def\inhibitblank
+ {\ifvmode
+ \begingroup
+ \attribute\skipcategoryattribute\plusfive
+ \vskip\zeropoint
+ \endgroup
+ \fi}
+
+\let\doinhibitblank\inhibitblank % keep this command, used in styles
+
+\let\defineblank \definevspacing
+\let\setupblank \setupvspacing
+\let\blank \vspacing
+\let\synchronizeblank \synchronizevspacing
+\let\defineblankmethod\definevspacingamount
+
+%D The following command is for Wolfgang. It has to be used with care as it does
+%D {\em not} work in tandem with the other spacing commands.
+
+\installcorenamespace{vspace}
+
+\unexpanded\def\definevspace
+ {\dotripleempty\spac_vspace_define}
+
+\def\spac_vspace_define[#1][#2][#3]%
+ {\ifthirdargument
+ \setvalue{\??vspace#1:#2}{#3}%
+ \else
+ \setvalue{\??vspace:#1}{#2}%
+ \fi}
+
+\letvalue{\??vspace:\s!unknown}\zeropoint
+
+\unexpanded\def\vspace
+ {\dodoubleempty\spac_vspace_inject}
+
+\def\spac_vspace_unknown
+ {\csname\??vspace:\s!unknown\endcsname}
+
+\def\spac_vspace_inject[#1][#2]% use \lastnamedcs
+ {\par
+ \ifvmode
+ \removelastskip
+ \vskip
+ \ifsecondargument
+ \ifcsname\??vspace#1:#2\endcsname
+ \lastnamedcs
+ \orelse\ifcsname\??vspace:#2\endcsname
+ \lastnamedcs
+ \else
+ \spac_vspace_unknown
+ \fi
+ \orelse\iffirstargument
+ \ifcsname\??vspace:#1\endcsname
+ \lastnamedcs
+ \else
+ \spac_vspace_unknown
+ \fi
+ \else
+ \ifcsname\??vspace:\s!default\endcsname
+ \lastnamedcs
+ \else
+ \spac_vspace_unknown
+ \fi
+ \fi
+ \relax
+ \fi}
+
+%D Some preliminary code: a simple and fast hanger, for usage in macros.
+
+\installcorenamespace {hanging}
+
+\installdirectcommandhandler \??hanging {hanging}
+
+\setuphanging
+ [\c!distance=.5\emwidth,
+ \c!location=\v!left,
+ \c!n=\zerocount]
+
+\unexpanded\def\starthanging
+ {\dontleavehmode\bgroup
+ \dosingleempty\spac_hanging_start}
+
+\unexpanded\def\stophanging
+ {\endgraf
+ \egroup}
+
+\let\m_spac_hanging_location\empty
+
+\def\spac_hanging_start[#1]%
+ {\doifelseassignment{#1}
+ {\let\m_spac_hanging_location\empty
+ \setupcurrenthanging[#1]}%
+ {\edef\m_spac_hanging_location{#1}}%
+ \ifx\m_spac_hanging_location\empty
+ \edef\m_spac_hanging_location{\directhangingparameter\c!location}%
+ \fi
+ \dowithnextboxcs\spac_hanging_finish\hbox}
+
+\def\spac_hanging_finish
+ {\scratchdistance\directhangingparameter\c!distance\relax
+ \ifdim\ht\nextbox>\strutht
+ \setbox\nextbox\tbox{\box\nextbox}%
+ \fi
+ \scratchcounter\directhangingparameter\c!n\relax
+ \ifnum\scratchcounter>\zerocount
+ \hangafter-\scratchcounter
+ \else
+ \getboxheight\scratchdimen\of\box\nextbox
+ \getnoflines\scratchdimen
+ \hangafter-\noflines
+ \fi
+ \ht\nextbox\strutht
+ \dp\nextbox\strutdp
+ \scratchwidth\dimexpr\wd\nextbox+\scratchdistance\relax
+ \ifx\m_spac_hanging_location\v!right
+ \hangindent\ifconditional\displaylefttoright-\fi\scratchwidth
+ \rlap{\hskip\dimexpr\hsize-\leftskip-\wd\nextbox\relax\box\nextbox}% \leftskip is new
+ \else
+ \hangindent\ifconditional\displaylefttoright\else-\fi\scratchwidth
+ \llap{\box\nextbox\hskip\scratchdistance}%
+ \fi
+ \ignorespaces}
+
+
+%D \macros
+%D {startfixed}
+%D
+%D \starttyping
+%D \startitemize
+%D \startitem \externalfigure[cow][height=1cm] \stopitem
+%D \startitem \externalfigure[cow][height=1cm] \stopitem
+%D
+%D \startitem \startfixed \externalfigure[cow][height=1cm]\stopfixed \stopitem
+%D \startitem \startfixed[high]\externalfigure[cow][height=1cm]\stopfixed \stopitem
+%D \startitem \startfixed[low] \externalfigure[cow][height=1cm]\stopfixed \stopitem
+%D \startitem \startfixed[lohi]\externalfigure[cow][height=1cm]\stopfixed \stopitem
+%D
+%D \startitem test \par \startfixed \externalfigure[koe][height=1cm]\stopfixed \stopitem
+%D \startitem test \par \startfixed[high]\externalfigure[koe][height=1cm]\stopfixed \stopitem
+%D \startitem test \par \startfixed[low] \externalfigure[koe][height=1cm]\stopfixed \stopitem
+%D \startitem test \par \startfixed[lohi]\externalfigure[koe][height=1cm]\stopfixed \stopitem
+%D \stopitemize
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+\installcorenamespace{fixedalternatives}
+
+\unexpanded\def\startfixed
+ {\bgroup
+ \dosingleempty\typo_fixed_start}
+
+\def\typo_fixed_start
+ {\ifhmode
+ \expandafter\typo_fixed_start_h
+ \else
+ \expandafter\typo_fixed_start_v
+ \fi}
+
+\def\typo_fixed_start_h[#1]%
+ {\let\stopfixed\typo_fixed_stop_h
+ \dowithnextbox{\typo_fixed_finish{#1}}%
+ \vbox\bgroup
+ %ignorespaces
+ \setlocalhsize}
+
+\unexpanded\def\typo_fixed_stop_h
+ {%removeunwantedspaces
+ \egroup
+ \egroup}
+
+\def\typo_fixed_start_v[#1]%
+ {\let\stopfixed\typo_fixed_stop_v
+ \startbaselinecorrection}
+
+\unexpanded\def\typo_fixed_stop_v
+ {\stopbaselinecorrection
+ \egroup}
+
+\letvalue{\??fixedalternatives \v!high}\bbox
+\letvalue{\??fixedalternatives \v!low}\tbox
+\letvalue{\??fixedalternatives \v!middle}\vcenter
+\letvalue{\??fixedalternatives \v!lohi}\vcenter
+\letvalue{\??fixedalternatives\s!unknown}\tbox
+\letvalue{\??fixedalternatives\s!default}\tbox
+
+\unexpanded\def\typo_fixed_finish#1%
+ {\expandnamespacevalue\??fixedalternatives{#1}\s!default{\box\nextbox}}
+
+% %D Forgotten already:
+%
+% \def\shapefill{\vskip\zeropoint\s!plus\lineheight\s!minus\lineheight\relax}
+
+%D Nasty:
+
+% \writestatus{1}{\the\prevdepth} \blank[force,5*big] { \writestatus{1}{\the\prevdepth} \baselineskip1cm xxxxxxxxx \par } \page
+% \writestatus{2}{\the\prevdepth} \blank[force,5*big] { \writestatus{2}{\the\prevdepth} \baselineskip1cm xxxxxxxxx \par } \page
+% \writestatus{3}{\the\prevdepth} \blank[force,5*big] { \writestatus{3}{\the\prevdepth} \baselineskip5cm xxxxxxxxx \par } \page
+% \writestatus{4}{\the\prevdepth} \input tufte \page
+% \writestatus{5}{\the\prevdepth} \input tufte \page
+% \writestatus{6}{\the\prevdepth} \blank[force,5*big] { \writestatus{6}{\the\prevdepth} \baselineskip1cm xxxxxxxxx \par } \page
+
+% \writestatus{1}{\the\prevdepth} \null\vskip4cm { \writestatus{1}{\the\prevdepth} \baselineskip1cm xxxxxxxxx \par } \page
+% \writestatus{2}{\the\prevdepth} \null\vskip4cm { \writestatus{2}{\the\prevdepth} \baselineskip1cm xxxxxxxxx \par } \page
+% \writestatus{3}{\the\prevdepth} \null\vskip4cm { \writestatus{3}{\the\prevdepth} \baselineskip5cm xxxxxxxxx \par } \page
+% \writestatus{4}{\the\prevdepth} \input tufte \page
+% \writestatus{5}{\the\prevdepth} \input tufte \page
+% \writestatus{6}{\the\prevdepth} \null\vskip4cm { \writestatus{6}{\the\prevdepth} \baselineskip1cm xxxxxxxxx \par } \page
+
+\appendtoks
+ \ifvmode\prevdepth\zeropoint\fi % consistent, else first page -1000pt .. needed for fixed,3*big first/successive pages consistency
+\to \everystarttext
+
+\prevdepth\zeropoint
+
+%D Helper:
+
+\unexpanded\def\checkedblank[#1]%
+ {\edef\p_blank{#1}%
+ \ifx\p_blank\empty
+ % ignore
+ \orelse\ifx\p_blank\v!none
+ % ignore
+ \else
+ \blank[\p_blank]%
+ \fi}
+
+% \setupwhitespace[line]
+% \prerollblank[2*line] \the\prerolledblank
+% \prerollblank[-2*line] \the\prerolledblank
+
+\newskip\prerolledblank
+
+\unexpanded\def\prerollblank[#1]%
+ {\begingroup
+ \edef\p_blank{#1}%
+ \ifx\p_blank\empty
+ \global\prerolledblank\zeropoint
+ \orelse\ifx\p_blank\v!none
+ \global\prerolledblank\zeropoint
+ \else
+ % don't mess with \arskip here!
+ \scratchskip\plusten\lineheight
+ \setbox\scratchbox\vbox
+ {\vskip\scratchskip
+ \kern\zeropoint
+ \blank[\p_blank]}%
+ % \dimexpr doesn't work well with skips
+ \advance\scratchskip-\ht\scratchbox
+ \global\prerolledblank-\scratchskip
+ \fi
+ \endgroup}
+
+\newcount\c_spac_vspacing_ignore_parskip
+
+% \setupwhitespace[line]
+% \setuphead[subject][after={\blank[packed]},style=\bfb]
+% \subject{foo}
+% test \par
+% test \par
+% \blank[packed] % \ignoreparskip
+% test \par
+% test \par
+% \ignoreparskip
+% test \par
+% test \par
+% \setuphead[subject][after={\blank[nowhite]},style=\bfb]
+% \subject{foo}
+% test \par
+% test \par
+
+\unexpanded\def\ignoreparskip{\c_spac_vspacing_ignore_parskip\plusone}
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/status-files.pdf b/Master/texmf-dist/tex/context/base/mkiv/status-files.pdf
index 211e6773fae..baed04d322d 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/status-files.pdf
+++ b/Master/texmf-dist/tex/context/base/mkiv/status-files.pdf
Binary files differ
diff --git a/Master/texmf-dist/tex/context/base/mkiv/status-lua.pdf b/Master/texmf-dist/tex/context/base/mkiv/status-lua.pdf
index a9c4cb67312..9e63b48f6bd 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/status-lua.pdf
+++ b/Master/texmf-dist/tex/context/base/mkiv/status-lua.pdf
Binary files differ
diff --git a/Master/texmf-dist/tex/context/base/mkiv/strc-bkm.lua b/Master/texmf-dist/tex/context/base/mkiv/strc-bkm.lua
index ee9233a9ae6..41a12833305 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/strc-bkm.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/strc-bkm.lua
@@ -42,6 +42,19 @@ local opened = { }
local forced = { }
local numbered = { }
+function bookmarks.setopened(key,value)
+ if value == nil then
+ value = true
+ end
+ if type(key) == "table" then
+ for i=1,#key do
+ opened[key[i]] = value
+ end
+ else
+ opened[key] = value
+ end
+end
+
function bookmarks.register(settings)
local force = settings.force == variables.yes
local number = settings.number == variables.yes
diff --git a/Master/texmf-dist/tex/context/base/mkiv/strc-blk.lua b/Master/texmf-dist/tex/context/base/mkiv/strc-blk.lua
index 89df440c966..6717c37773a 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/strc-blk.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/strc-blk.lua
@@ -118,10 +118,12 @@ function blocks.select(state,name,tag,criterium)
printblock(ri.index,name,ri.data,hide)
else
local mtags = metadata.tags
- for tag, sta in next, tags do
- if mtags[tag] then
- printblock(ri.index,name,ri.data,hide)
- break
+ if mtags then
+ for tag, sta in next, tags do
+ if mtags[tag] then
+ printblock(ri.index,name,ri.data,hide)
+ break
+ end
end
end
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/strc-con.mkvi b/Master/texmf-dist/tex/context/base/mkiv/strc-con.mkvi
index d67307ba73b..8c75eb6df5e 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/strc-con.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/strc-con.mkvi
@@ -737,7 +737,7 @@
\stopsetups
\startsetups[\??constructionrenderings:\v!top]
- \strc_sectioning_prevent_page_break\plusone
+ % \strc_sectioning_prevent_page_break % commented per 31/5/2019
\let\\=\space
\noindent
\copy\constructionheadbox % why copy ?
@@ -746,6 +746,7 @@
\edef\p_strc_constructions_inbetween{\constructionparameter\c!inbetween}%
\ifx\p_strc_constructions_inbetween\empty \else
\p_strc_constructions_inbetween
+ % shouldn't this move to after the fi?
\directcheckedvspacing\v!samepage
\fi
\useconstructionstyleandcolor\c!style\c!color
diff --git a/Master/texmf-dist/tex/context/base/mkiv/strc-def.mkiv b/Master/texmf-dist/tex/context/base/mkiv/strc-def.mkiv
index 941f561c8ef..52b3b3ad972 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/strc-def.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/strc-def.mkiv
@@ -90,13 +90,18 @@
% \definesection (could become \definehead with one parameter)
-\definesection[\s!section-1] % part
-\definesection[\s!section-2] % chapter
-\definesection[\s!section-3] % section
-\definesection[\s!section-4] % subsection
-\definesection[\s!section-5] % subsubsection
-\definesection[\s!section-6] % subsubsubsection
-\definesection[\s!section-7] % subsubsubsubsection
+\definesection[\s!section-1] % part
+\definesection[\s!section-2] % chapter
+\definesection[\s!section-3] % section
+\definesection[\s!section-4] % subsection
+\definesection[\s!section-5] % subsubsection
+\definesection[\s!section-6] % subsubsubsection
+\definesection[\s!section-7] % subsubsubsubsection
+\definesection[\s!section-8] % subsubsubsubsubsection
+\definesection[\s!section-9] % subsubsubsubsubsubsection
+\definesection[\s!section-10] % subsubsubsubsubsubsubsection
+\definesection[\s!section-11] % subsubsubsubsubsubsubsubsection
+\definesection[\s!section-12] % subsubsubsubsubsubsubsubsubsection
% \definehead
@@ -133,6 +138,31 @@
\c!default=\v!subsubsubsection]
\definehead
+ [\v!subsubsubsubsubsection]
+ [\c!section=\s!section-8,
+ \c!default=\v!subsubsubsubsection]
+
+\definehead
+ [\v!subsubsubsubsubsubsection]
+ [\c!section=\s!section-9,
+ \c!default=\v!subsubsubsubsubsection]
+
+\definehead
+ [\v!subsubsubsubsubsubsubsection]
+ [\c!section=\s!section-10,
+ \c!default=\v!subsubsubsubsubsubsection]
+
+\definehead
+ [\v!subsubsubsubsubsubsubsubsection]
+ [\c!section=\s!section-11,
+ \c!default=\v!subsubsubsubsubsubsubsection]
+
+\definehead
+ [\v!subsubsubsubsubsubsubsubsubsection]
+ [\c!section=\s!section-12,
+ \c!default=\v!subsubsubsubsubsubsubsubsection]
+
+\definehead
[\v!title]
[\c!coupling=\v!chapter,
\c!default=\v!chapter,
@@ -168,63 +198,6 @@
\c!default=\v!subsubsubsubsection,
\c!incrementnumber=\v!no]
-\setuphead
- [\v!part]
- [\c!placehead=\v!no]
-
-\setuphead
- [\v!chapter]
- [\v!appendix\c!label=\v!appendix,
- \v!bodypart\c!label=\v!chapter] % bijlageconversie=\Character
-
-\setuphead
- [\v!section]
- [\v!appendix\c!label=\v!section,
- \v!bodypart\c!label=\v!section] % bijlageconversie=\Character
-
-\setuphead
- [\v!subsection]
- [\v!appendix\c!label=\v!subsection,
- \v!bodypart\c!label=\v!subsection] % bijlageconversie=\Character
-
-\setuphead
- [\v!subsubsection]
- [\v!appendix\c!label=\v!subsubsection,
- \v!bodypart\c!label=\v!subsubsection] % bijlageconversie=\Character
-
-% extras
-
-\definesection[\s!section-8] % subsubsubsubsubsection
-\definesection[\s!section-9] % subsubsubsubsubsubsection
-\definesection[\s!section-10] % subsubsubsubsubsubsubsection
-\definesection[\s!section-11] % subsubsubsubsubsubsubsubsection
-\definesection[\s!section-12] % subsubsubsubsubsubsubsubsubsection
-
-\definehead
- [\v!subsubsubsubsubsection]
- [\c!section=\s!section-8,
- \c!default=\v!subsubsubsubsection]
-
-\definehead
- [\v!subsubsubsubsubsubsection]
- [\c!section=\s!section-9,
- \c!default=\v!subsubsubsubsubsection]
-
-\definehead
- [\v!subsubsubsubsubsubsubsection]
- [\c!section=\s!section-10,
- \c!default=\v!subsubsubsubsubsubsection]
-
-\definehead
- [\v!subsubsubsubsubsubsubsubsection]
- [\c!section=\s!section-11,
- \c!default=\v!subsubsubsubsubsubsubsection]
-
-\definehead
- [\v!subsubsubsubsubsubsubsubsubsection]
- [\c!section=\s!section-12,
- \c!default=\v!subsubsubsubsubsubsubsubsection]
-
\definehead
[\v!subsubsubsubsubsubject]
[\c!coupling=\v!subsubsubsubsubsection,
@@ -255,6 +228,34 @@
\c!default=\v!subsubsubsubsubsubsubsubsubsection,
\c!incrementnumber=\v!no]
+% setups
+
+\setuphead
+ [\v!part]
+ [\c!placehead=\v!no]
+
+\setuphead
+ [\v!chapter]
+ [\v!appendix\c!label=\v!appendix,
+ \v!bodypart\c!label=\v!chapter] % bijlageconversie=\Character
+
+\setuphead
+ [\v!section]
+ [\v!appendix\c!label=\v!section,
+ \v!bodypart\c!label=\v!section] % bijlageconversie=\Character
+
+\setuphead
+ [\v!subsection]
+ [\v!appendix\c!label=\v!subsection,
+ \v!bodypart\c!label=\v!subsection] % bijlageconversie=\Character
+
+\setuphead
+ [\v!subsubsection]
+ [\v!appendix\c!label=\v!subsubsection,
+ \v!bodypart\c!label=\v!subsubsection] % bijlageconversie=\Character
+
+% prefixes
+
\defineprefixset
[\v!all]
[section-1,section-2,section-3,section-4,section-5,section-6,section-7,%
@@ -321,12 +322,17 @@
[\c!before={\blank[\v!preference,\v!big]}, % sort of mkii compatible, watch columns
\c!after=]
-\setuplist [\v!part] [\c!width=0\emwidth]
-\setuplist [\v!chapter] [\c!width=2\emwidth]
-\setuplist [\v!section] [\c!width=3\emwidth]
-\setuplist [\v!subsection] [\c!width=4\emwidth]
-\setuplist [\v!subsubsection] [\c!width=5\emwidth]
-\setuplist [\v!subsubsubsection] [\c!width=6\emwidth]
+\setuplist [\v!part] [\c!width=0\emwidth]
+\setuplist [\v!chapter] [\c!width=2\emwidth]
+\setuplist [\v!section] [\c!width=3\emwidth]
+\setuplist [\v!subsection] [\c!width=4\emwidth]
+\setuplist [\v!subsubsection] [\c!width=5\emwidth]
+\setuplist [\v!subsubsubsection] [\c!width=6\emwidth]
\setuplist [\v!subsubsubsubsection] [\c!width=7\emwidth]
+\setuplist [\v!subsubsubsubsubsection] [\c!width=8\emwidth]
+\setuplist [\v!subsubsubsubsubsubsection] [\c!width=9\emwidth]
+\setuplist [\v!subsubsubsubsubsubsubsection] [\c!width=10\emwidth]
+\setuplist [\v!subsubsubsubsubsubsubsubsection] [\c!width=11\emwidth]
+\setuplist [\v!subsubsubsubsubsubsubsubsubsection] [\c!width=12\emwidth]
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/strc-doc.lua b/Master/texmf-dist/tex/context/base/mkiv/strc-doc.lua
index 4b2ac04b7f3..9877a0f9c0e 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/strc-doc.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/strc-doc.lua
@@ -41,7 +41,7 @@ local v_positive = variables.positive
local v_current = variables.current
local trace_sectioning = false trackers.register("structures.sectioning", function(v) trace_sectioning = v end)
-local trace_detail = false trackers.register("structures.detail", function(v) trace_detail = v end)
+local trace_details = false trackers.register("structures.details", function(v) trace_details = v end)
local report_structure = logs.reporter("structure","sectioning")
local report_used = logs.reporter("structure")
@@ -335,7 +335,7 @@ function sections.setentry(given)
-- a trick to permit userdata to overload title, ownnumber and reference
-- normally these are passed as argument but nowadays we provide several
-- interfaces (we need this because we want to be compatible)
- if trace_detail then
+ if trace_details then
report_structure("name %a, mapped level %a, old depth %a, new depth %a, reset set %a",
givenname,mappedlevel,olddepth,newdepth,resetset)
end
@@ -354,7 +354,7 @@ function sections.setentry(given)
if newdepth > olddepth then
for i=olddepth+1,newdepth do
local s = tonumber(sets.get("structure:resets",data.block,saveset and saveset[i] or resetset,i))
- if trace_detail then
+ if trace_details then
report_structure("new depth %s, old depth %s, reset set %a, reset value %a, current %a",olddepth,newdepth,resetset,s,numbers[i])
end
if not s or s == 0 then
@@ -369,7 +369,7 @@ function sections.setentry(given)
elseif newdepth < olddepth then
for i=olddepth,newdepth+1,-1 do
local s = tonumber(sets.get("structure:resets",data.block,saveset and saveset[i] or resetset,i))
- if trace_detail then
+ if trace_details then
report_structure("new depth %s, old depth %s, reset set %a, reset value %a, current %a",olddepth,newdepth,resetset,s,numbers[i])
end
if not s or s == 0 then
@@ -402,12 +402,12 @@ function sections.setentry(given)
newn = 1 -- maybe zero is nicer
end
forced[newdepth] = nil
- if trace_detail then
+ if trace_details then
report_structure("old depth %a, new depth %a, old n %a, new n %a, forced %t",olddepth,newdepth,oldn,newn,fd)
end
else
newn = oldn + 1
- if trace_detail then
+ if trace_details then
report_structure("old depth %a, new depth %a, old n %a, new n %a, increment",olddepth,newdepth,oldn,newn)
end
end
@@ -426,7 +426,7 @@ function sections.setentry(given)
if #ownnumbers > 0 then
numberdata.ownnumbers = fastcopy(ownnumbers) -- { unpack(ownnumbers) }
end
- if trace_detail then
+ if trace_details then
report_structure("name %a, numbers % a, own numbers % a",givenname,numberdata.numbers,numberdata.ownnumbers)
end
if not references.block then
@@ -672,8 +672,15 @@ local function process(index,numbers,ownnumbers,criterium,separatorset,conversio
end
end
-function sections.typesetnumber(entry,kind,...) -- kind='section','number','prefix'
- if entry and entry.hidenumber ~= true then -- can be nil
+-- kind : section number prefix
+
+function sections.typesetnumber(entry,kind,...)
+ --
+ -- Maybe the hiding becomes an option .. after all this test was there
+ -- for a reason, but for now we have this:
+ --
+ -- if entry and entry.hidenumber ~= true then
+ if entry then
local separatorset = ""
local conversionset = ""
local conversion = ""
@@ -878,7 +885,7 @@ function sections.findnumber(depth,what) -- needs checking (looks wrong and slow
if sectiondata and sectiondata.hidenumber ~= true then -- can be nil
local quit = what == v_previous or what == v_next
if what == v_first or what == v_previous then
- for i=index,1,-1 do
+ for i=index-1,1,-1 do
local s = collected[i]
if s then
local n = s.numbers
@@ -893,7 +900,7 @@ function sections.findnumber(depth,what) -- needs checking (looks wrong and slow
end
end
elseif what == v_last or what == v_next then
- for i=index,#collected do
+ for i=index+1,#collected do
local s = collected[i]
if s then
local n = s.numbers
diff --git a/Master/texmf-dist/tex/context/base/mkiv/strc-flt.mkvi b/Master/texmf-dist/tex/context/base/mkiv/strc-flt.mkvi
index 02f6fd75343..d6a6723d7be 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/strc-flt.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/strc-flt.mkvi
@@ -173,13 +173,26 @@
%\c!bottomafter=,
%\c!default=, % default location
\c!sidethreshold=.5\strutdp, % set to "old" to check with old method
- \c!numbering=\v!yes]
+ \c!numbering=\v!yes,
+ \c!compress=\v!yes, % when possible pack floats when flushing
+ \c!compressdistance=\emwidth]
\setupfloatframed
[\c!frame=\v!off,
\c!offset=\v!overlay,
\c!strut=\v!no]
+\appendtoks
+ \doifelse{\floatparameter\c!compress}\v!yes\settrue\setfalse\c_page_floats_pack_flushed
+ \d_page_floats_compress_distance\floatparameter\c!compressdistance\relax
+\to \everysetupfloat
+
+%D We need to do it again here:
+
+\setupfloat
+ [\c!compress=\v!yes, % when possible pack floats when flushing
+ \c!compressdistance=\emwidth]
+
%D Individial settings:
\installcounterassociation{floatcaption}
@@ -312,30 +325,86 @@
\let\floatcaptionsuffix\empty % an optional suffix
\let\floatcaptionnumber\empty % a logical counter
-% the split is needed when for instance the float goes into
-% a multi page field and the list of figs becomes larger than
-% one page: cycle between 'only flush when object ref ok'
-% and 'one/many page fig list'; see "uguide finometer"
+% For a while these were placeholders:
%
-% potential sync bug with sectionblocks, see uguide.tex
-
-% begin of todo
-
-\unexpanded\def\placefloatcaption{\dodoubleempty\strc_floats_place_caption}
-\unexpanded\def\setfloatcaption {\dodoubleempty\strc_floats_set_caption}
-
-\def\strc_floats_place_caption[#tag][#reference]#caption{[not supported]}
-\def\strc_floats_set_caption [#tag][#reference]#caption{[not supported]}
-
-\unexpanded\def\placefloatcaptiontext [#tag]{[not suported yet]}
-\unexpanded\def\placefloatcaptionnumber [#tag]{[not suported yet]}
-\unexpanded\def\placefloatcaptionreference[#tag]{[not suported yet]}
-
-\let\placefloatlabel \placefloatcaption
-\let\placefloatlabeltext \placefloatcaptiontext
-\let\placefloatlabelreference\placefloatcaptionreference
-
-% end of todo
+%D \starttyping
+%D \unexpanded\def\placefloatcaption{\dodoubleempty\strc_floats_place_caption}
+%D \unexpanded\def\setfloatcaption {\dodoubleempty\strc_floats_set_caption}
+%D
+%D \def\strc_floats_place_caption[#tag][#reference]#caption{[not supported]}
+%D \def\strc_floats_set_caption [#tag][#reference]#caption{[not supported]}
+%D
+%D \unexpanded\def\placefloatcaptiontext [#tag]{[not suported yet]}
+%D \unexpanded\def\placefloatcaptionnumber [#tag]{[not suported yet]}
+%D \unexpanded\def\placefloatcaptionreference[#tag]{[not suported yet]}
+%D \stoptyping
+%D
+%D because in \MKII\ we had:
+%D
+%D \starttyping
+%D \let\placefloatlabel \placefloatcaption
+%D \let\placefloatlabeltext \placefloatcaptiontext
+%D \let\placefloatlabelreference\placefloatcaptionreference
+%D \stoptyping
+%D
+%D But as it was never advertised we don't provide it in \MKIV. However, at some
+%D point HvdM wanted this:
+%D
+%D \starttyping
+%D \placefigure {labeltext-1} {\externalfigure[figure-1]}
+%D \placefloatcaption[figure][title={labeltext-2}] \externalfigure[figure-2]
+%D \placefigure {labeltext-3} {\externalfigure[figure-3]}
+%D \stoptyping
+%D
+%D So there you have it:
+
+\unexpanded\def\placefloatcaption
+ {\dotripleempty\strc_floats_place_caption}
+
+\def\strc_floats_place_caption[#category][#settings][#userdata]%
+ {\ifsecondargument
+ % we need at least a category and title
+ \dontleavehmode
+ \bgroup
+ \edef\currentfloat{#category}%
+ \let\currentfloatcaption\currentfloat
+ \resetfloatcaptionparameter\c!reference
+ \resetfloatcaptionparameter\c!title
+ \resetfloatcaptionparameter\c!marking
+ \resetfloatcaptionparameter\c!list
+ \resetfloatcaptionparameter\c!bookmark
+ \setupcurrentfloatcaption[#settings]%
+ \edef\currentfloatcounter{\namedcounterparameter\currentfloat\s!name}%
+ \iftrialtypesetting\strc_counters_save\currentfloatcounter\fi
+ \strc_counters_increment\currentfloatcounter
+ \strc_counters_register_component
+ \s!float
+ \setupcurrentfloatcaption
+ \floatcaptionparameter
+ \detokenizedfloatcaptionparameter
+ \relax
+ \relax
+ \relax
+ [\s!name=\currentfloat,
+ \s!counter=\currentfloatcounter,%
+ \s!hascaption=\v!yes,%
+ \s!hasnumber=\v!yes,%
+ \s!hastitle=\v!yes]%
+ [#userdata]%
+ \glet\previousfloatnumber \m_strc_counters_last_registered_index
+ \glet\currentfloatnumber \m_strc_counters_last_registered_index
+ \glet\currentfloatattribute \m_strc_counters_last_registered_attribute
+ \glet\currentfloatsynchronize\m_strc_counters_last_registered_synchronize
+ %
+ % \iflocation
+ % \attribute\destinationattribute\currentfloatattribute\relax
+ % \fi
+ \currentfloatsynchronize
+ \strc_floats_make_complete_caption
+ %
+ \iftrialtypesetting\strc_counters_restore\currentfloatcounter\fi
+ \egroup
+ \fi}
\newbox \b_strc_floats_caption
\newbox \b_strc_floats_content
@@ -349,25 +418,34 @@
\noindent
\gdef\lastcaptiontag{\strut\thecurrentfloatnumber}% was xdef ... needs checking
\begingroup
- \usefloatcaptionstyleandcolor\c!style\c!color
- \clf_doifelselisthastitle{\currentfloat}\numexpr\currentfloatnumber\relax
- \donothing
- \emptyfloatcaptiontrue
- \ifnofloatnumber
- \else
- \hbox{\usefloatcaptionstyleandcolor\c!headstyle\c!headcolor\thecurrentfloatnumber}%
- \ifnofloatcaption \else \ifemptyfloatcaption \else
- \doifelsenothing{\floatcaptionparameter\c!spaceinbetween}
- {\floatcaptionparameter\c!headseparator\relax
- \scratchskip\floatcaptionparameter\c!distance\relax
- \dotfskip\scratchskip\emergencystretch.5\scratchskip}
- {\blank[\floatcaptionparameter\c!spaceinbetween]}%
- \fi \fi
- \fi
\ifnofloatcaption
\global\d_strc_floats_caption_height\zeropoint
\global\d_strc_floats_caption_depth \zeropoint
\else
+ \usefloatcaptionstyleandcolor\c!style\c!color
+ \clf_doifelselisthastitle{\currentfloat}\numexpr\currentfloatnumber\relax
+ \donothing
+ \emptyfloatcaptiontrue
+ \ifnofloatnumber \else \ifnofloatcaption \else
+ \ifemptyfloatcaption
+ \hbox{\usefloatcaptionstyleandcolor\c!headstyle\c!headcolor\thecurrentfloatnumber}%
+ \else
+ \doifelsenothing{\floatcaptionparameter\c!spaceinbetween}
+ {\scratchskip\floatcaptionparameter\c!distance\relax
+ \setbox\scratchbox\hbox
+ {\usefloatcaptionstyleandcolor\c!headstyle\c!headcolor
+ \thecurrentfloatnumber
+ \floatcaptionparameter\c!headseparator
+ \dotfskip\scratchskip}%
+ \doifelse{\floatcaptionparameter\c!hang}\v!yes
+ {\leftskip\wd\scratchbox
+ \llap{\box\scratchbox}}
+ {\unhbox\scratchbox}%
+ \emergencystretch.5\scratchskip}
+ {\hbox{\usefloatcaptionstyleandcolor\c!headstyle\c!headcolor\thecurrentfloatnumber}%
+ \blank[\floatcaptionparameter\c!spaceinbetween]}%
+ \fi
+ \fi \fi
\usefloatcaptionstyleandcolor\c!textstyle\c!textcolor
\global\d_strc_floats_caption_height\strutheight
\global\d_strc_floats_caption_depth \strutdepth
@@ -429,7 +507,7 @@
% new, \placefigure{\xmlfirst{#1}{somecaption}}{} passes earlier empty check
% so here we misuse the scratch box; actually this means that the previous
% test can go away (some day, when i redo this module)
- \ifdim\wd\b_strc_floats_caption=\zeropoint
+ \ifzeropt\wd\b_strc_floats_caption
\global\emptyfloatcaptiontrue
\ifnofloatnumber
\global\nofloatcaptiontrue
@@ -770,11 +848,47 @@
\strc_floats_finish_placement}
\vbox}
+%D \starttyping
+%D \definefloat
+%D [one] [figure]
+%D [default=right,
+%D rightmargindistance=-20cm,
+%D criterium=129pt,
+%D fallback=rightmargin]
+%D
+%D \definefloat
+%D [two] [figure]
+%D [default=right,
+%D rightmargindistance=-20cm,
+%D criterium=129pt,
+%D fallback=three]
+%D
+%D \definefloat
+%D [three] [figure]
+%D [default=rightmargin,
+%D rightmargindistance=0cm]
+%D
+%D \placefloat[one]{}{\blackrule[width=30pt]} \samplefile{tufte}
+%D \placefloat[one]{}{\blackrule[width=60pt]} \samplefile{tufte}
+%D \placefloat[one]{}{\blackrule[width=90pt]} \samplefile{tufte}
+%D \placefloat[one]{}{\blackrule[width=130pt]} \samplefile{tufte}
+%D \placefloat[two]{}{\blackrule[width=130pt]} \samplefile{tufte}
+%D \stoptyping
+
\def\strc_floats_finish_placement
{\doifsomething{\floatparameter\c!criterium}
{\ifdim\wd\nextbox>\floatparameter\c!criterium\relax
\edef\forcedfloatmethod{\floatparameter\c!fallback}%
- \ifx\forcedfloatmethod\empty\let\forcedfloatmethod\v!here\fi
+ \ifx\forcedfloatmethod\empty \else
+ \doifelsecommandhandler\??float\forcedfloatmethod
+ {\let\currentfloat\forcedfloatmethod
+ \edef\floatlocation{\floatparameter\c!default}%
+ \let\forcedfloatmethod\floatlocation}
+ \donothing
+ \fi
+ \ifx\forcedfloatmethod\empty
+ \let\forcedfloatmethod\v!here
+ \fi
\fi}%
\strc_floats_check_extra_actions
\strc_floats_analyze_variables_two
@@ -794,6 +908,7 @@
\newdimen\d_strc_floats_top
\newdimen\d_strc_floats_bottom
+\newdimen\d_strc_floats_overflow
% \def\strc_floats_calculate_skip#target#skip%
% {\begingroup
@@ -842,6 +957,7 @@
\global\c_page_one_float_method \floatparameter\c!textmethod
\global\c_page_floats_n_of_top \rootfloatparameter\c!ntop
\global\c_page_floats_n_of_bottom\rootfloatparameter\c!nbottom
+ \global\d_strc_floats_overflow \zeropoint
\ifconditional\c_strc_floats_par_float
\global\d_strc_floats_top \zeropoint
\global\d_strc_floats_bottom \zeropoint
@@ -922,15 +1038,28 @@
\def\naturalfloatwidth {\the\naturalfloatht}
\def\naturalfloatdepth {\the\naturalfloatdp}
+\def\floatcaptionheight{\the\floatcaptionwd}
+\def\floatcaptionwidth {\the\floatcaptionht}
+\def\floatcaptiondepth {\the\floatcaptiondp}
+
\newdimen\naturalfloatwd
\newdimen\naturalfloatht
\newdimen\naturalfloatdp
+\newdimen\floatcaptionwd
+\newdimen\floatcaptionht
+\newdimen\floatcaptiondp
+
\def\strc_floats_set_natural_dimensions#box%
{\global\naturalfloatwd\wd#box\relax
\global\naturalfloatht\ht#box\relax
\global\naturalfloatdp\dp#box\relax}
+\def\strc_floats_set_caption_dimensions#box%
+ {\global\floatcaptionwd\wd#box\relax
+ \global\floatcaptionht\ht#box\relax
+ \global\floatcaptiondp\dp#box\relax}
+
\def\doifelsemainfloatbody
{\ifinsidesplitfloat
\ifconditional\splitfloatfirstdone
@@ -950,8 +1079,9 @@
\def\floatcaptionattribute
{\iflocation
- %\ifnofloatnumber
- %\else
+ \ifx\currentfloatattribute\empty
+ % safeguard, can be samepage too
+ \else
\ifnofloatcaption
\else
\ifinsidesplitfloat
@@ -963,7 +1093,7 @@
attr \destinationattribute \currentfloatattribute
\fi
\fi
- %\fi
+ \fi
\fi}
\newconditional\usesamefloatnumber
@@ -1026,12 +1156,12 @@
\glet\currentfloatsynchronize\m_strc_counters_last_registered_synchronize
\fi
%
- \global\setfalse\usesamefloatnumber % one shot
+ \iftrialtypesetting\else\global\setfalse\usesamefloatnumber\fi % one shot
% check float box
\strc_floats_set_natural_dimensions\nextbox
\global\setbox\floatbox\vbox{\floatparameter\c!command{\box\nextbox}}% can be anything so no pack
\strc_floats_set_natural_dimensions\floatbox
- \ifdim\htdp\floatbox=\zeropoint
+ \ifzeropt\htdp\floatbox
\showmessage\m!floatblocks{11}\empty
\global\setbox\floatbox\vpack
{\dostarttagged\t!floatcontent\empty
@@ -1052,6 +1182,7 @@
\strc_floats_get_box
\global\insidefloatfalse}
+
\newdimen\availablefloatwidth
\newdimen\availablefloatheight
@@ -1209,7 +1340,7 @@
\def\strc_floats_set_local_dimensions
{\global\d_page_sides_shift \zeropoint % duplicate
\global\d_page_sides_maximum\zeropoint\relax % duplicate
- \ifdim\d_page_sides_downshift=\zeropoint\else
+ \ifzeropt\d_page_sides_downshift\else
\global\setbox\floatbox\vpack
{\vskip\d_page_sides_downshift
\nointerlineskip
@@ -1481,8 +1612,9 @@
% nothing
\or
% automatic
- \ifnofloatcaption
+ \ifnofloatcaption
\strc_floats_prepare_no_caption
+ \strc_floats_set_caption_dimensions\voidbox
%\page_backgrounds_add_local_to_box\floatbox % was \doglobal but not needed
\else
% todo: installable maken, variant/method=auto vs macro
@@ -1490,6 +1622,7 @@
%\page_backgrounds_add_local_to_box\b_strc_floats_content
\setbox\b_strc_floats_caption\hbox % text
{\floatcaptionparameter\c!command{\box\b_strc_floats_caption}}%
+ \strc_floats_set_caption_dimensions\b_strc_floats_caption
\moveboxontogrid\b_strc_floats_caption{\floatcaptionparameter\c!grid}\d_strc_floats_caption_height
%\page_backgrounds_add_local_to_box\b_strc_floats_caption
\strc_floats_build_box
@@ -1520,7 +1653,6 @@
\fi\fi
\strc_floats_align_content{\copy\b_strc_floats_content}}}
-
\def\strc_floats_prepare_page_caption
{\edef\p_strc_floats_caption_width {\floatcaptionparameter\c!width}%
\edef\p_strc_floats_caption_minwidth{\floatcaptionparameter\c!minwidth}%
@@ -1697,7 +1829,7 @@
{\strc_floats_align_content{\box\b_strc_floats_content}}
\def\strc_floats_build_box_next_right#1%
- {\ifconditional\c_strc_floats_par_float \hbox \else \expandafter \strc_floats_align_content \fi % skip, no pack
+ {\ifconditional\c_strc_floats_par_float \hpack \else \expandafter \strc_floats_align_content \fi % skip, no pack
{\d_strc_float_temp_height\ht\b_strc_floats_content
\box\b_strc_floats_content
\doifnotinset\v!hang\floatcaptionlocation
@@ -1705,7 +1837,7 @@
\vbox to\d_strc_float_temp_height{#1}}}
\def\strc_floats_build_box_next_left#1%
- {\ifconditional\c_strc_floats_par_float \hbox \else \expandafter \strc_floats_align_content \fi % skip, no pack
+ {\ifconditional\c_strc_floats_par_float \hpack \else \expandafter \strc_floats_align_content \fi % skip, no pack
{\d_strc_float_temp_height\ht\b_strc_floats_content
\vbox to\d_strc_float_temp_height{#1}%
\doifnotinset\v!hang\floatcaptionlocation
@@ -1730,6 +1862,36 @@
\vbox to\d_strc_float_temp_height{#1}%
\box\b_strc_floats_content}}
+% \def\strc_floats_build_box_next_right_margin_indeed#1#2%
+% {\ifconditional\c_strc_floats_par_float
+% \hpack\bgroup
+% \d_strc_float_temp_height\ht\b_strc_floats_content
+% \box\b_strc_floats_content
+% \hsmash{\hskip#1\vbox to\d_strc_float_temp_height{#2}}%
+% \egroup
+% \else
+% \begingroup
+% \d_strc_float_temp_height\ht\b_strc_floats_content
+% \everyrightofalignedline{\hsmash{\hskip#1\vbox to\d_strc_float_temp_height{#2}}}%
+% \strc_floats_align_content{\box\b_strc_floats_content}%
+% \endgroup
+% \fi}
+%
+% \def\strc_floats_build_box_next_left_margin_indeed#1#2%
+% {\ifconditional\c_strc_floats_par_float
+% \hpack\bgroup
+% \d_strc_float_temp_height\ht\b_strc_floats_content
+% \hsmash{\hskip-\dimexpr#1+\wd\b_strc_floats_caption\relax\vbox to\d_strc_float_temp_height{#2}}%
+% \box\b_strc_floats_content
+% \egroup
+% \else
+% \begingroup
+% \d_strc_float_temp_height\ht\b_strc_floats_content
+% \everyleftofalignedline{\hsmash{\hskip-\dimexpr#1+\wd\b_strc_floats_caption\relax\vbox to\d_strc_float_temp_height{#2}}}%
+% \strc_floats_align_content{\box\b_strc_floats_content}%
+% \endgroup
+% \fi}
+
\def\strc_floats_build_box_next_right_margin_indeed#1#2%
{\ifconditional\c_strc_floats_par_float
\hpack\bgroup
@@ -1740,7 +1902,12 @@
\else
\begingroup
\d_strc_float_temp_height\ht\b_strc_floats_content
- \everyrightofalignedline{\hsmash{\hskip#1\vbox to\d_strc_float_temp_height{#2}}}%
+ \setbox\scratchboxone\vbox{#2}%
+ \ifdim\htdp\scratchboxone>\htdp\b_strc_floats_content
+ \global\d_strc_floats_overflow\dimexpr\htdp\scratchboxone-\htdp\b_strc_floats_content\relax
+ \fi
+ \ht\scratchboxone\d_strc_float_temp_height
+ \everyrightofalignedline{\hsmash{\hskip#1\box\scratchboxone}}%
\strc_floats_align_content{\box\b_strc_floats_content}%
\endgroup
\fi}
@@ -1755,7 +1922,12 @@
\else
\begingroup
\d_strc_float_temp_height\ht\b_strc_floats_content
- \everyleftofalignedline{\hsmash{\hskip-\dimexpr#1+\wd\b_strc_floats_caption\relax\vbox to\d_strc_float_temp_height{#2}}}%
+ \setbox\scratchboxone\vbox{#2}%
+ \ifdim\htdp\scratchboxone>\htdp\b_strc_floats_content
+ \global\d_strc_floats_overflow\dimexpr\htdp\scratchboxone-\htdp\b_strc_floats_content\relax
+ \fi
+ \ht\scratchboxone\d_strc_float_temp_height
+ \everyleftofalignedline{\hsmash{\hskip-\dimexpr#1+\wd\scratchboxone\relax\box\scratchboxone}}%
\strc_floats_align_content{\box\b_strc_floats_content}%
\endgroup
\fi}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/strc-itm.lua b/Master/texmf-dist/tex/context/base/mkiv/strc-itm.lua
index adec591c1c1..e2fbdc96055 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/strc-itm.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/strc-itm.lua
@@ -36,8 +36,8 @@ local function analyzeitemgroup(name,level)
local stamp = f_stamp(name,n)
local n = getvariable(stamp,level,1,0)
local w = getvariable(stamp,level,2,0)
- texsetcount("local","c_strc_itemgroups_max_items",n)
- texsetdimen("local","d_strc_itemgroups_max_width",w)
+ texsetcount("c_strc_itemgroups_max_items",n)
+ texsetdimen("d_strc_itemgroups_max_width",w)
end
local function registeritemgroup(name,level,nofitems,maxwidth)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/strc-itm.mklx b/Master/texmf-dist/tex/context/base/mkiv/strc-itm.mklx
new file mode 100644
index 00000000000..60fe3ee746a
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/strc-itm.mklx
@@ -0,0 +1,1882 @@
+%D \module
+%D [ file=strc-itm,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=Itemgroups,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Structure Macros / Itemgroups}
+
+\registerctxluafile{strc-itm}{}
+
+%D As we analyze/register widths and such we could as well push and pop the numbers
+%D at the \LUA\ end (which saves a few calls).
+%D
+%D Cleaning up this module happened around the time when Kate Bush came up with the
+%D nicest numbered list of words: 50 Words For Snow. It's therefore no surprise that
+%D I had that cd running several times when updating this code. One of the
+%D highlights of 2011.
+%D
+%D This module needs to be rewritten but that is tricky with respect to
+%D compatibilitity. Basically each major variant (regular, text, columns,
+%D horizontal, etc) needs to be on its own.
+
+% todo: check breaks
+% todo: check grouping
+% todo: fixedconversion
+
+% \startitemize[n,packed]
+% \item test \item test \item test
+% \stopitemize
+%
+% \startitemize[n,packed,reverse]
+% \item test \item test \item test
+% \stopitemize
+%
+% \startitemize[n,packed,reverse] \item test \item test \stopitemize
+% \startitemize[continue]
+% \item test \startitemize[n,packed] \item test \item test \stopitemize
+% \item test
+% \item test
+% \stopitemize
+% \startitemize[continue] \item test \stopitemize
+%
+% \startitemize[n,packed] \item test \item test \stopitemize
+% \startitemize[continue] \item test \stopitemize
+% \startitemize[continue] \item test \stopitemize
+%
+% \setupwhitespace[big]
+% \starttext
+% test \startitemize[joinedup] \item test \item test \stopitemize test \par
+% test \startitemize[joinedup,nowhite] \item test \item test \stopitemize test \par
+% test \startitemize[joinedup,nowhite,before] \item test \item test \stopitemize test \par
+% test \startitemize[joinedup,nowhite,after] \item test \item test \stopitemize test \par
+% \stoptext
+%
+% test / example
+%
+% \startnarrower[left] \startcolumns[n=3] \startitemize
+% \item \input ward \item \input ward \item \input ward
+% \stopitemize \stopcolumns\stopnarrower \blank
+%
+% \startnarrower[left] \startitemize[columns,three]
+% \item \input ward \item \input ward \item \input ward
+% \stopitemize \stopnarrower \blank
+%
+% \setupitemize[leftmargin=1.5em] \startitemize[columns,three]
+% \item \input ward \item \input ward \item \input ward
+% \stopitemize \blank
+%
+% beware, we don't group (yet) as we want to keep the left/right skip
+%
+% \startitemize
+% \startitem \stopitem
+% some intermediate text that will properly indent
+% \startitem \stopitem
+% \stopitem
+%
+% so we need to keep that property
+%
+% \startitemize
+% \starthead {xx} test \stophead
+% \startitem test \stopitem
+% \startitem test \stopitem
+% \stopitemize
+%
+% Sometimes the user demands get pretty weird:
+%
+% \startitemize
+% \item test
+% \item test
+% \headsym{xx} test \par test
+% \stopitemize
+%
+% aligned items
+%
+% \startitemize[n,fit,broad][itemalign=flushright]
+% \dorecurse{100}{\item The first item.}
+% \stopitemize
+%
+% \setupitemgroup[itemize][each][fit]
+% \setupitemgroup[itemize][each][distance=.5em,factor=1,itemalign=flushright]
+%
+% \startitemize[n]
+% \dorecurse{100}{\item The first item.}
+% \stopitemize
+%
+% \defineitemgroup[gbitemize]
+% \setupitemgroup[gbitemize][each][headstyle=bold]
+%
+% \startgbitemize
+% \txt{italian} some italians like this kind of cross||breed between
+% an itemize and a description
+% \txt{sicilians} i wonder how many sicilian mathematicians do a thesis
+% on the math involved in predicting the next big bang of the vulcano
+% \stopgbitemize
+%
+% \startitemize[n,repeat]
+% \noitem \startitemize[a] \item Item 1.a. \item Item 1.b. \stopitemize
+% \noitem \startitemize[a] \item Item 2.a. \item Item 2.b. \stopitemize
+% \stopitemize
+%
+% \startitemize[n,repeat][width=0pt]
+% \noitem \startitemize[a][width=2em] \item Item 1.a. \item Item 1.b. \stopitemize
+% \noitem \startitemize[a][width=2em] \item Item 2.a. \item Item 2.b. \stopitemize
+% \stopitemize
+%
+% \startbuffer
+% \item
+% \startitemize[n]
+% \item item 1.1
+% \item item 1.2
+% \startitemize[n] \item item 1.2.1 \item item 1.2.2 \stopitemize
+% \item item 1.3
+% \stopitemize
+% \item
+% \startitemize[n] \item item 2.1 \item item 2.2 \stopitemize
+% \item item 3
+% \startitemize[n] \item item 3.1 \item item 3.2 \stopitemize
+% \item
+% \startitemize[n] \item item 4.1 \item item 4.2 \stopitemize
+% \stopbuffer
+%
+% \startitemize[n,repeat,6*broad,packed] \getbuffer \stopitemize \blank[3*big]
+% \startitemize[n,repeat,packed] \getbuffer \stopitemize \blank[3*big]
+% \setupitemize[each][atmargin][width=3em]
+% \startitemize[n,repeat,packed] \getbuffer \stopitemize
+%
+% todo: assume startitem ... stopitem and do an autostopitem .. cleaner for
+% elements
+%
+% \startitemize[text][space=medium]
+% \item one \item two \item three
+% \stopitemize
+%
+% For Giuseppe "Oblomov" Bilotta, inspired on a suggestion by Taco
+% Hoekwater.
+%
+% \def\MyItemCommand#1{{\bf#1}\quad}
+% \setupitemgroup[itemize][command=\MyItemCommand]
+%
+% \startitemize
+% \item {test} is this okay?
+% \item {test} is this okay?
+% \item {test} is this okay?
+% \stopitemize
+
+\unprotect
+
+\newconditional\c_strc_itemgroups_sub
+\newconditional\c_strc_itemgroups_head
+\newconditional\c_strc_itemgroups_intro
+\newconditional\c_strc_itemgroups_randomize
+\newconditional\c_strc_itemgroups_horizontal
+\newconditional\c_strc_itemgroups_collecting
+\newconditional\c_strc_itemgroups_auto_intro
+\newconditional\c_strc_itemgroups_pack
+\newconditional\c_strc_itemgroups_paragraph
+\newconditional\c_strc_itemgroups_text
+\newconditional\c_strc_itemgroups_text_saved
+\newconditional\c_strc_itemgroups_first
+\newconditional\c_strc_itemgroups_before
+\newconditional\c_strc_itemgroups_after
+\newconditional\c_strc_itemgroups_nowhite
+\newconditional\c_strc_itemgroups_joined
+\newconditional\c_strc_itemgroups_reverse
+\newconditional\c_strc_itemgroups_continue
+\newconditional\c_strc_itemgroups_fitting
+\newconditional\c_strc_itemgroups_indented_first
+\newconditional\c_strc_itemgroups_inline
+\newconditional\c_strc_itemgroups_columns
+\newconditional\c_strc_itemgroups_concat
+\newconditional\c_strc_itemgroups_txt
+\newconditional\c_strc_itemgroups_extra
+\newconditional\c_strc_itemgroups_repeat
+\newconditional\c_strc_itemgroups_inline_head
+
+% 0 = before/after
+% 1 = between unless before
+% 2 = between
+
+\newconstant \c_strc_itemgroups_spacing_mode \c_strc_itemgroups_spacing_mode\plustwo
+\newconditional\c_strc_itemgroups_optimize \settrue\c_strc_itemgroups_optimize
+\newconditional\c_strc_itemgroups_auto_concat \settrue\c_strc_itemgroups_auto_concat
+
+\newsignal \d_strc_itemgroups_signal
+
+\newbox \b_strc_itemgroups
+
+\newdimen \d_strc_itemgroups_list_width
+\newdimen \d_strc_itemgroups_asked_width
+
+\newdimen \d_strc_itemgroups_max_width % multipass
+\newcount \c_strc_itemgroups_max_items % multipass
+
+\newcount \c_strc_itemgroups_n_of_items
+\newcount \c_strc_itemgroups_nesting
+\newcount \c_strc_itemgroups_column_depth
+
+\def \v_strc_itemgroups_counter {itemgroup:\currentparentitemgroup}
+\let \m_strc_itemgroups_repeat_start \empty
+\def \v_strc_itemgroups_unknown_symbol {?}
+\let \m_strc_itemgroups_indenting \empty
+\let \m_strc_itemgroups_destination \empty
+
+\let \currentitemlevel \!!zerocount % public
+\def \currentnofitems {\the\c_strc_itemgroups_max_items}
+\def \currentitemnumber {\strc_counters_raw_sub\v_strc_itemgroups_counter\currentitemlevel} % public
+
+\newtoks \itemgroupcommands % maybe public
+
+\def \currentitemgroupsymbol {n} % here we cannot use a _ in the name
+\let \currentitemgroupconversionset \empty % here we cannot use a _ in the name
+\let \currentitemgroupsegments \empty
+
+\def\strc_itemgroups_register_status
+ {\clf_registeritemgroup{\currentparentitemgroup}\c_strc_itemgroups_nesting\c_strc_itemgroups_n_of_items\dimexpr\itemgroupparameter\c!maxwidth\relax}
+
+\def\strc_itemgroups_check_n_of_items % we could do this at the lua end and save a call (i.e. will be dimen and counter)
+ {\clf_analyzeitemgroup{\currentparentitemgroup}\c_strc_itemgroups_nesting\relax
+ \edef\currentnofitems{\the\c_strc_itemgroups_max_items}}
+
+% todo: \dodosetreference -> \strc_counters_register_component (to be checked)
+
+\def\strc_itemgroups_insert_reference % we will make a decent number helper
+ {\iftrialtypesetting \orelse \ifx\currentitemreference \empty \else
+ \strc_itemgroups_insert_reference_indeed
+ \fi}
+
+\def\strc_itemgroups_insert_extra_reference
+ {\iftrialtypesetting \orelse \ifx\currentitemreference \empty \else
+ \normalexpanded{\textreference[\currentitemreference]{\strc_itemgroups_extra_symbol}}%
+ \fi}
+
+\def\strc_itemgroups_insert_reference_indeed % maybe we need a 'frozen counter' numberdata blob / quick hack .. .mive this to strc-ref
+ {% needs testing, gave problems:
+ \setnextinternalreference
+ % no need to collect nodes in \b_strc_destination_nodes here ... maybe at some point
+ \strc_references_start_destination_nodes
+ % this is somewhat over the top ... we should use the counter's reference
+ \clf_setdestinationattribute
+ {%
+ metadata {%
+ kind {item}% was item, why?
+ \ifx\currentreferencecoding\s!xml
+ xmlroot {\xmldocument}% only useful when text
+ \fi
+ catcodes \catcodetable
+ }%
+ references {%
+ internal \locationcount % no: this spoils references
+ % block {\currentsectionblock}%
+ view {\interactionparameter\c!focus}%
+ prefix {\referenceprefix}%
+ reference {\currentitemreference}%
+ }%
+ prefixdata {%
+ prefix {\namedcounterparameter\v_strc_itemgroups_counter\c!prefix}%
+ separatorset {\namedcounterparameter\v_strc_itemgroups_counter\c!prefixseparatorset}%
+ conversion {\namedcounterparameter\v_strc_itemgroups_counter\c!prefixconversion}%
+ conversionset {\namedcounterparameter\v_strc_itemgroups_counter\c!prefixconversionset}%
+ set {\namedcounterparameter\v_strc_itemgroups_counter\c!prefixset}%
+ segments {\namedcounterparameter\v_strc_itemgroups_counter\c!prefixsegments}%
+ % segments {\askedprefixsegments}%
+ connector {\namedcounterparameter\v_strc_itemgroups_counter\c!prefixconnector}%
+ }%
+ numberdata {%
+ numbers {\v_strc_itemgroups_counter}%
+ separatorset {\namedcounterparameter\v_strc_itemgroups_counter\c!numberseparatorset}%
+ % conversion {\namedcounterparameter\v_strc_itemgroups_counter\c!numberconversion}%
+ % conversionset {\namedcounterparameter\v_strc_itemgroups_counter\c!numberconversionset}%
+ % fixedconversion {\currentitemgroupconversionset}%
+ conversionset {fixed::\currentitemgroupconversionset}% temp hack
+ %
+ % for the moment no stopper, we need to make references configurable first
+ % stopper {\namedcounterparameter\v_strc_itemgroups_counter\c!numberstopper}%
+ segments {\namedcounterparameter\v_strc_itemgroups_counter\c!numbersegments}%
+ }%
+ }%
+ \relax
+ \strc_references_stop_destination_nodes
+ \xdef\currentdestinationattribute{\number\lastdestinationattribute}%
+ % will become an option:
+ \ifnum\lastdestinationattribute>\zerocount
+ \dontleavehmode\hbox attr \destinationattribute\lastdestinationattribute\bgroup
+ \strc_references_flush_destination_nodes
+ \egroup
+ \fi}
+
+%D Defining and setup:
+
+\installcorenamespace{itemgroup}
+\installcorenamespace{itemgroupoption}
+\installcorenamespace{itemgroupsetting}
+\installcorenamespace{itemgroupkeyword}
+\installcorenamespace{itemgroupalign}
+\installcorenamespace{itemgrouplocal}
+\installcorenamespace{itemgroupglobal}
+\installcorenamespace{itemgroupdistance}
+\installcorenamespace{itemgroupstack}
+\installcorenamespace{itemgroupfirst}
+\installcorenamespace{itemgroupstart}
+
+\installcommandhandler \??itemgroup {itemgroup} \??itemgroup
+
+\let\setupitemgroups\setupitemgroup
+
+\appendtoks
+ \setuevalue{\e!start\currentitemgroup}{\startitemgroup[\currentitemgroup]}%
+ \setuevalue{\e!stop \currentitemgroup}{\stopitemgroup}%
+ \setuevalue{\e!setup\currentitemgroup\e!endsetup}{\setupitemgroup[\currentitemgroup]}% obsolete
+ \let\currentparentitemgroup\currentitemgroup
+ \definecounter[\v_strc_itemgroups_counter]%
+ % beware ... we cannot use _ as the conversion set is not expanded
+ % \defineconversionset[\v_strc_itemgroups_counter][\currentitemgroupconversionset][\currentitemgroupsymbol]%
+\to \everydefineitemgroup
+
+%D Global states
+
+\def\strc_itemgroups_store_continue_state#options#settings%
+ {\setxvalue{\??itemgroupoption \currentitemgroup}{\strc_itemgroups_process_options{#options}}%
+ \setgvalue{\??itemgroupsetting\currentitemgroup}{\setupcurrentitemgroup[#settings]}}
+
+\def\strc_itemgroups_fetch_continue_state
+ {\csname\??itemgroupoption \currentitemgroup\endcsname
+ \csname\??itemgroupsetting\currentitemgroup\endcsname}
+
+\def\strc_itemgroups_reset_continue_state
+ {\expandafter\glet\csname\??itemgroupoption \currentitemgroup\endcsname\relax
+ \expandafter\glet\csname\??itemgroupsetting\currentitemgroup\endcsname\relax}
+
+% These will become keywords. We will also add a feature to keep the while set
+% together.
+
+\definevspacing[\v!item @0] [penalty:0] % allow
+\definevspacing[\v!item @10000] [penalty:10000] % no
+\definevspacing[\v!item @-5] [penalty:-5]
+\definevspacing[\v!item @5] [penalty:5]
+\definevspacing[\v!item @500] [penalty:500] % discourage .. too low, 5000 is better
+
+\def\strc_itemgroups_insert_break_when_needed#break%
+ {\ifconditional\c_strc_itemgroups_optimize
+ \ifconditional\c_strc_itemgroups_text \else
+ #break\relax
+ \fi
+ \fi}
+
+\def\strc_itemgroups_insert_breakallow {\strc_itemgroups_insert_break_when_needed\strc_itemgroups_insert_breakallow_indeed}
+\def\strc_itemgroups_insert_breakno {\strc_itemgroups_insert_break_when_needed\strc_itemgroups_insert_breakno_indeed }
+\def\strc_itemgroups_insert_break {\strc_itemgroups_insert_break_when_needed\strc_itemgroups_insert_break_indeed }
+\def\strc_itemgroups_insert_nobreak {\strc_itemgroups_insert_break_when_needed\strc_itemgroups_insert_nobreak_indeed }
+
+\def\strc_itemgroups_insert_breakallow_indeed{\vspacing[\v!item @0]}
+\def\strc_itemgroups_insert_breakno_indeed {\vspacing[\v!item @10000]}
+\def\strc_itemgroups_insert_break_indeed {\flushnotes
+ \vspacing[\v!item @-5]}
+\def\strc_itemgroups_insert_nobreak_indeed {\flushnotes
+ \ifinsidecolumns % todo
+ \vspacing[\v!item @5]%
+ \else
+ \vspacing[\v!item @500]%
+ \fi}
+
+\unexpanded\def\strc_itemgroups_process_options#options%
+ {\processcommacommand[#options]\strc_itemgroups_process_option} % expansion of options is handy for xml
+
+% \installcommalistprocessorcommand \strc_itemgroups_process_option_list \strc_itemgroups_process_option
+%
+% \unexpanded\def\strc_itemgroups_process_options#options%
+% {\normalexpanded{\strc_itemgroups_process_option_list[#options]}} % expansion of options is handy for xml
+
+\def\strc_itemgroups_process_option#option%
+ {\edef\itemgroupconstantvalue{#option}%
+ \ifx\itemgroupconstantvalue\empty\else
+ \splitatasterisk\itemgroupconstantvalue\itemgroupfirst\itemgroupsecond
+ \ifx\itemgroupsecond\empty
+ \let\itemgroupsecond\itemgroupfirst
+ \let\itemgroupfirst\!!plusone
+ \fi
+ \ifcsname\??itemgroupkeyword\itemgroupsecond\endcsname
+ \lastnamedcs
+ \else
+ \strc_itemgroups_set_symbol\itemgroupconstantvalue
+ \fi
+ \fi}
+
+\def\strc_itemgroups_process_set_option_pack
+ {\ifcase\c_strc_itemgroups_nesting \else
+ \settrue\c_strc_itemgroups_pack
+ \fi}
+
+\def\strc_itemgroups_process_set_option_unpack
+ {\ifcase\c_strc_itemgroups_nesting\else
+ \setfalse\c_strc_itemgroups_pack
+ \fi}
+
+\setvalue{\??itemgroupkeyword\!!zerocount }{} % ignore 0
+\setvalue{\??itemgroupkeyword\v!packed }{\strc_itemgroups_process_set_option_pack}
+\setvalue{\??itemgroupkeyword\v!unpacked }{\strc_itemgroups_process_set_option_unpack}
+\setvalue{\??itemgroupkeyword\v!intro }{\settrue\c_strc_itemgroups_intro} % here? not set to false
+\setvalue{\??itemgroupkeyword\v!autointro }{\settrue\c_strc_itemgroups_auto_intro}
+\setvalue{\??itemgroupkeyword\v!broad }{\ifx\itemgroupfirst\empty
+ \let\itemgroupfirst\!!plusone
+ \fi
+ \letitemgroupparameter\c!factor\itemgroupfirst}
+\setvalue{\??itemgroupkeyword\v!text }{\settrue\c_strc_itemgroups_text
+ \settrue\c_strc_itemgroups_inline
+ \settrue\c_strc_itemgroups_joined
+ \strc_itemgroups_process_set_option_pack}
+\setvalue{\??itemgroupkeyword\v!before }{\settrue\c_strc_itemgroups_before}
+\setvalue{\??itemgroupkeyword\v!after }{\settrue\c_strc_itemgroups_after}
+\setvalue{\??itemgroupkeyword\v!nowhite }{\settrue\c_strc_itemgroups_nowhite}
+\setvalue{\??itemgroupkeyword\v!margin }{\setitemgroupparameter\c!width{-2em}} % signal
+\setvalue{\??itemgroupkeyword\v!inmargin }{\setitemgroupparameter\c!width{-2em}} % signal
+\setvalue{\??itemgroupkeyword\v!atmargin }{\ifnum\c_strc_itemgroups_nesting>\plusone
+ \setitemgroupparameter\c!width{0em}%
+ \fi} % signal
+\setvalue{\??itemgroupkeyword\v!intext }{\settrue\c_strc_itemgroups_inline}
+\setvalue{\??itemgroupkeyword\v!headintext }{\settrue\c_strc_itemgroups_inline_head}
+\setvalue{\??itemgroupkeyword\v!loose }{\setfalse\c_strc_itemgroups_optimize}
+\setvalue{\??itemgroupkeyword\v!fit }{\settrue\c_strc_itemgroups_fitting}
+\setvalue{\??itemgroupkeyword\v!nofit }{\setfalse\c_strc_itemgroups_fitting}
+\setvalue{\??itemgroupkeyword\v!paragraph }{\settrue\c_strc_itemgroups_paragraph
+ \strc_itemgroups_process_set_option_pack}
+\setvalue{\??itemgroupkeyword\v!joinedup }{\settrue\c_strc_itemgroups_joined
+ \strc_itemgroups_process_set_option_pack}
+\setvalue{\??itemgroupkeyword\v!notjoinedup}{\setfalse\c_strc_itemgroups_joined}
+\setvalue{\??itemgroupkeyword\v!serried }{\edef\itemgroupfirst{-\ifx\itemgroupfirst\empty1\else\itemgroupfirst\fi}%
+ \letitemgroupparameter\c!factor\itemgroupfirst}
+\setvalue{\??itemgroupkeyword\v!stopper }{\letitemgroupparameter\c!placestopper\v!yes} % keep {}
+\setvalue{\??itemgroupkeyword\v!nostopper }{\letitemgroupparameter\c!placestopper\v!no} % keep {}
+\setvalue{\??itemgroupkeyword\v!repeat }{\settrue\c_strc_itemgroups_repeat}
+\setvalue{\??itemgroupkeyword\v!norepeat }{\setfalse\c_strc_itemgroups_repeat}
+\setvalue{\??itemgroupkeyword\v!reverse }{\settrue\c_strc_itemgroups_reverse}
+\setvalue{\??itemgroupkeyword\v!columns }{\settrue\c_strc_itemgroups_columns}
+\setvalue{\??itemgroupkeyword\v!one }{\letitemgroupparameter\c!n\plusone}
+\setvalue{\??itemgroupkeyword\v!two }{\letitemgroupparameter\c!n\plustwo}
+\setvalue{\??itemgroupkeyword\v!three }{\letitemgroupparameter\c!n\plusthree}
+\setvalue{\??itemgroupkeyword\v!four }{\letitemgroupparameter\c!n\plusfour}
+\setvalue{\??itemgroupkeyword\v!five }{\letitemgroupparameter\c!n\plusfive}
+\setvalue{\??itemgroupkeyword\v!six }{\letitemgroupparameter\c!n\plussix}
+\setvalue{\??itemgroupkeyword\v!seven }{\letitemgroupparameter\c!n\plusseven}
+\setvalue{\??itemgroupkeyword\v!eight }{\letitemgroupparameter\c!n\pluseight}
+\setvalue{\??itemgroupkeyword\v!nine }{\letitemgroupparameter\c!n\plusnine}
+\setvalue{\??itemgroupkeyword\v!standard }{\setitemgroupparameter\c!width {1.5\emwidth}%
+ \setitemgroupparameter\c!distance {.5\emwidth}%
+ %\letitemgroupparameter\c!factor \!!zerocount
+ \letitemgroupparameter\c!factor {\zerocount}%
+ \setitemgroupparameter\c!packcriterium{\zerocount}%
+ \letitemgroupparameter\c!inner \empty
+ \letitemgroupparameter\c!beforehead \empty
+ \letitemgroupparameter\c!afterhead \blank
+ \letitemgroupparameter\c!before \blank
+ \letitemgroupparameter\c!inbetween \blank
+ \letitemgroupparameter\c!after \blank}
+
+\def\strc_itemgroups_initialize_local
+ {\setfalse\c_strc_itemgroups_inline
+ \setfalse\c_strc_itemgroups_concat
+ \setfalse\c_strc_itemgroups_txt
+ %
+ \setfalse\c_strc_itemgroups_reverse
+ \setfalse\c_strc_itemgroups_intro
+ \setfalse\c_strc_itemgroups_auto_intro
+ \setfalse\c_strc_itemgroups_before
+ \setfalse\c_strc_itemgroups_after
+ \setfalse\c_strc_itemgroups_nowhite
+ \setfalse\c_strc_itemgroups_randomize
+ \setfalse\c_strc_itemgroups_horizontal
+ \setfalse\c_strc_itemgroups_collecting
+ \setfalse\c_strc_itemgroups_intro
+ \setfalse\c_strc_itemgroups_continue
+ % this will be a constant
+ \setfalse\c_strc_itemgroups_head
+ \setfalse\c_strc_itemgroups_sub
+ \setfalse\c_strc_itemgroups_symbol
+ \setfalse\c_strc_itemgroups_columns
+ % to be checked
+ \let\m_strc_itemgroups_destination\empty
+ \let\strc_itemgroups_used_symbol \empty % ** start value
+ \let\strc_itemgroups_margin_symbol\empty
+ \let\strc_itemgroups_extra_symbol \empty
+ %
+ \global\letitemgroupparameter\c!maxwidth\!!zeropoint
+ }
+
+\setvalue{\??itemgroupfirst\v!intro }{\settrue\c_strc_itemgroups_intro}
+\setvalue{\??itemgroupfirst\v!continue }{\settrue\c_strc_itemgroups_continue}
+\setvalue{\??itemgroupfirst\v!random }{\settrue\c_strc_itemgroups_randomize
+ \settrue\c_strc_itemgroups_collecting}
+\setvalue{\??itemgroupkeyword\v!horizontal}{\settrue\c_strc_itemgroups_horizontal
+ \settrue\c_strc_itemgroups_collecting
+ \settrue\c_strc_itemgroups_inline
+ \settrue\c_strc_itemgroups_joined
+ \strc_itemgroups_process_set_option_pack}
+
+\def\strc_itemgroups_preset_stage_one#options%
+ {\processcommacommand[#options]\strc_itemgroups_preset_stage_one_indeed}
+
+% \installcommalistprocessorcommand \strc_itemgroups_preset_stage_one_list \strc_itemgroups_preset_stage_one_indeed
+%
+% \def\strc_itemgroups_preset_stage_one#options%
+% {\normalexpanded{\strc_itemgroups_preset_stage_one_list[#options]}}
+
+\def\strc_itemgroups_preset_stage_one_indeed#option%
+ {\ifcsname\??itemgroupfirst#option\endcsname
+ \lastnamedcs
+ \fi}
+
+\ifdefined\dotagsetitemgroup \else \let\dotagsetitemgroup\relax \fi
+\ifdefined\dotagsetitem \else \let\dotagsetitem \gobbleoneargument \fi
+
+\def\strc_itemgroups_tag_start_group
+ {\dostarttaggedchained\t!itemgroup\currentparentitemgroup\??itemgroup
+ \dotagsetitemgroup}
+
+\def\strc_itemgroups_tag_stop_group
+ {\dostoptagged}
+
+\def\strc_itemgroups_before_command
+ {\ifconditional\c_strc_itemgroups_nowhite
+ \ifconditional\c_strc_itemgroups_before
+ \ifcase\c_strc_itemgroups_nesting\or\itemgroupparameter\c!before\fi
+ \else
+ \nowhitespace
+ \fi
+ \orelse\ifconditional\c_strc_itemgroups_joined
+ % \empty
+ \else
+ \itemgroupparameter\c!before
+ \fi}
+
+\def\strc_itemgroups_after_command
+ {\ifconditional\c_strc_itemgroups_nowhite
+ \ifconditional\c_strc_itemgroups_after
+ \ifcase\c_strc_itemgroups_nesting\or\itemgroupparameter\c!after\fi
+ \else
+ \nowhitespace
+ \fi
+ \orelse\ifconditional\c_strc_itemgroups_joined
+ % \empty
+ \else
+ \itemgroupparameter\c!after
+ \fi}
+
+\def\strc_itemgroups_between_command
+ {\ifconditional\c_strc_itemgroups_nowhite
+ \nowhitespace
+ \orelse\ifconditional\c_strc_itemgroups_joined
+ % \empty
+ \else
+ \itemgroupparameter\c!inbetween
+ \fi}
+
+\def\strc_itemgroups_before_head_command
+ {\ifconditional\c_strc_itemgroups_nowhite
+ \nowhitespace
+ \orelse\ifconditional\c_strc_itemgroups_joined
+ % \empty
+ \else
+ \itemgroupparameter\c!beforehead
+ \fi}
+
+\def\strc_itemgroups_after_head_command
+ {\ifconditional\c_strc_itemgroups_nowhite
+ \nowhitespace
+ \orelse\ifconditional\c_strc_itemgroups_joined
+ % \empty
+ \else
+ \itemgroupparameter\c!afterhead
+ \fi}
+
+% compatible setup command:
+
+\let\strc_itemgroups_normal_setup\setupitemgroup
+
+\unexpanded\def\setupitemgroup
+ {\doquadrupleempty\strc_itemgroups_setup}
+
+\def\strc_itemgroups_setup[#category][#levels][#options][#settings]% category level|each options|settings settings|options
+ {\edef\strc_itemgroups_setup_what{#levels}%
+ \iffourthargument
+ \ifx\strc_itemgroups_setup_what\v!each
+ \strc_itemgroups_setup_each{#category}{#options}%
+ \strc_itemgroups_setup_each{#category}{#settings}%
+ \else
+ \strc_itemgroups_setup_list{#levels}{#category}{#options}%
+ \strc_itemgroups_setup_list{#levels}{#category}{#settings}%
+ \fi
+ \orelse\ifthirdargument
+ \ifx\strc_itemgroups_setup_what\v!each
+ \strc_itemgroups_setup_each{#category}{#options}%
+ \else
+ \strc_itemgroups_setup_list{#levels}{#category}{#options}%
+ \fi
+ \orelse\ifsecondargument
+ \strc_itemgroups_setup_each{#category}{#levels}%
+ \else
+ \strc_itemgroups_normal_setup[#category]% == settings
+ \fi}
+
+% can be made a bit faster
+
+% \def\strc_itemgroups_setup_each#category#whatever%
+% {\doifelseassignment{#whatever}
+% {\strc_itemgroups_normal_setup[#category][#whatever]}
+% {\strc_itemgroups_normal_setup[#category][\c!option={#whatever}]}}
+
+\def\strc_itemgroups_setup_each#category#whatever%
+ {\ifcondition\validassignment{#whatever}%
+ \strc_itemgroups_normal_setup[#category][#whatever]%
+ \else
+ \strc_itemgroups_normal_setup[#category][\c!option={#whatever}]%
+ \fi}
+
+\def\strc_itemgroups_setup_list_level_a#category#whatever#level%
+ {\strc_itemgroups_normal_setup[#category:#level][#whatever]}
+
+\def\strc_itemgroups_setup_list_level_b#category#whatever#level%
+ {\strc_itemgroups_normal_setup[#category:#level][\c!option={#whatever}]}
+
+% \def\strc_itemgroups_setup_list#subcategories#category#whatever%
+% {\doifelseassignment{#whatever}
+% {\processcommalist[#subcategories]{\strc_itemgroups_setup_list_level_a{#category}{#whatever}}}
+% {\processcommalist[#subcategories]{\strc_itemgroups_setup_list_level_b{#category}{#whatever}}}}
+
+\def\strc_itemgroups_setup_list#subcategories#category#whatever%
+ {\ifcondition\validassignment{#whatever}%
+ \processcommalist[#subcategories]{\strc_itemgroups_setup_list_level_a{#category}{#whatever}}%
+ \else
+ \processcommalist[#subcategories]{\strc_itemgroups_setup_list_level_b{#category}{#whatever}}%
+ \fi}
+
+\def\strc_itemgroups_increment_item_counter
+ {\ifconditional\c_strc_itemgroups_sub \else
+ \ifconditional\c_strc_itemgroups_symbol \else % \ifx\strc_itemgroups_extra_symbol\empty
+ \strc_counters_increment_sub\v_strc_itemgroups_counter\currentitemlevel
+ \fi
+ \fi}
+
+\unexpanded\def\strc_itemgroups_insert_item_counter
+ {\ifconditional\c_strc_itemgroups_repeat
+ \ifcase\c_strc_itemgroups_nesting
+ % skip
+ \or
+ \strc_itemgroups_insert_item_counter_indeed % this could become an option
+ \else
+ \strc_itemgroups_insert_item_counter_indeed
+ \fi
+ \else
+ \strc_itemgroups_insert_item_counter_indeed
+ \fi}
+
+\def\strc_itemgroups_insert_item_counter_indeed % quite slow ... every time this setup .. but it
+ {\begingroup % can be optimized ... best move some to strc-num
+ \setupcounter
+ [\v_strc_itemgroups_counter]%
+ [\c!prefix=\itemgroupparameter\c!prefix,
+ \c!prefixstopper=\itemgroupparameter\c!prefixstopper,
+ \c!prefixseparatorset=\itemgroupparameter\c!prefixseparatorset,
+ \c!prefixconversion=\itemgroupparameter\c!prefixconversion,
+ \c!prefixconversionset=\itemgroupparameter\c!prefixseparatorset,
+ \c!prefixset=\itemgroupparameter\c!prefixset,
+ \c!prefixsegments=\itemgroupparameter\c!prefixsegments,
+ \c!prefixconnector=\itemgroupparameter\c!prefixconnector,
+ \c!criterium=\itemgroupparameter\c!criterium,
+ \c!numberorder=\ifconditional\c_strc_itemgroups_reverse\v!reverse\else\v!normal\fi,
+ \c!numberstopper=\expdoif{\itemgroupparameter\c!placestopper}\v!yes{\itemgroupparameter\c!stopper},
+ \c!numberconversionset=\v_strc_itemgroups_counter,
+ \c!numbersegments=\currentitemgroupsegments]%
+ % there will be a fixedconversion key
+ %\normalexpanded{\defineconversionset[\v_strc_itemgroups_counter][\currentitemgroupconversionset][\currentitemgroupsymbol]}%
+ \normalexpanded{\strc_sets_define_conversion_set[\v_strc_itemgroups_counter][\currentitemgroupconversionset][\currentitemgroupsymbol]}%
+ %
+ \convertedcounter[\v_strc_itemgroups_counter]% [\number\currentitemlevel]%
+ \strc_itemgroups_insert_reference
+ \endgroup}
+
+% needs testing (maybe it need to happen later)
+%
+% \appendtoks
+% \setupcounter
+% [\v_strc_itemgroups_counter]%
+% [\c!prefix=\itemgroupparameter\c!prefix,
+% \c!prefixstopper=\itemgroupparameter\c!prefixstopper,
+% \c!prefixseparatorset=\itemgroupparameter\c!prefixseparatorset,
+% \c!prefixconversion=\itemgroupparameter\c!prefixconversion,
+% \c!prefixconversionset=\itemgroupparameter\c!prefixseparatorset,
+% \c!prefixset=\itemgroupparameter\c!prefixset,
+% \c!prefixsegments=\itemgroupparameter\c!prefixsegments,
+% \c!prefixconnector=\itemgroupparameter\c!prefixconnector,
+% \c!criterium=\itemgroupparameter\c!criterium,
+% \c!numberorder=\ifconditional\c_strc_itemgroups_reverse\v!reverse\else\v!normal\fi,
+% \c!numberstopper=\expdoif{\itemgroupparameter\c!placestopper}\v!yes{\itemgroupparameter\c!stopper},
+% \c!numberconversionset=\v_strc_itemgroups_counter,
+% \c!numbersegments=\currentitemgroupsegments]%
+% \to\itemgroupcommands
+%
+% \def\strc_itemgroups_insert_item_counter_indeed % quite slow ... every time this setup .. but it
+% {\begingroup % can be optimized ... best move some to strc-num
+% % there will be a fixedconversion key
+% %\normalexpanded{\defineconversionset[\v_strc_itemgroups_counter][\currentitemgroupconversionset][\currentitemgroupsymbol]}%
+% \normalexpanded{\strc_sets_define_conversion_set[\v_strc_itemgroups_counter][\currentitemgroupconversionset][\currentitemgroupsymbol]}%
+% %
+% \convertedcounter[\v_strc_itemgroups_counter]% [\number\currentitemlevel]%
+% \strc_itemgroups_insert_reference
+% \endgroup}
+
+\def\strc_itemgroups_set_symbol#symbol%
+ {\edef\strc_itemgroups_tmp_symbol{#symbol}%
+ \ifx\strc_itemgroups_tmp_symbol\empty \else
+ \doifelsesymboldefined\strc_itemgroups_tmp_symbol
+ \strc_itemgroups_set_symbol_symbol
+ {\doifelseconversiondefined\strc_itemgroups_tmp_symbol
+ \strc_itemgroups_set_symbol_conversion
+ \donothing}%
+ \fi}
+
+\def\strc_itemgroups_set_symbol_symbol
+ {\let\currentitemgroupsymbol\strc_itemgroups_tmp_symbol
+ \strc_itemgroups_store_global_symbol\currentitemgroupsymbol
+ \strc_itemgroups_store_local_symbol\v_strc_itemgroups_unknown_symbol
+ \let\strc_itemgroups_used_symbol\strc_itemgroups_set_symbol_symbol_item
+ \let\strc_itemgroups_asked_symbol\empty}
+
+\def\strc_itemgroups_set_symbol_conversion
+ {\let\currentitemgroupsymbol\strc_itemgroups_tmp_symbol
+ \strc_itemgroups_store_global_symbol\currentitemgroupsymbol
+ \strc_itemgroups_store_local_symbol\strc_itemgroups_insert_item_counter
+ \let\strc_itemgroups_used_symbol\strc_itemgroups_set_symbol_conversion_item
+ \let\strc_itemgroups_asked_symbol\empty}
+
+\def\strc_itemgroups_set_symbol_symbol_item
+ {\symbol[\currentitemgroupsymbol]}
+
+\def\strc_itemgroups_set_symbol_conversion_item
+ {\ifconditional\c_strc_itemgroups_text
+ % maybe block stopper here, but one can as well clone an itemgroup then
+ \itemgroupparameter\c!lefttext
+ \strc_itemgroups_fetch_local_symbol
+ \itemgroupparameter\c!righttext
+ \else
+ \itemgroupparameter\c!left
+ \strc_itemgroups_fetch_local_symbol
+ \itemgroupparameter\c!right
+ \fi}
+
+\def\strc_itemgroups_calculate_list_width#level%
+ {\let\savedcurrentitemgroup\currentitemgroup
+ \edef\currentitemgroup{\currentparentitemgroup:\number#level}%
+ \ifdim\d_strc_itemgroups_max_width>\zeropoint
+ \d_strc_itemgroups_list_width\d_strc_itemgroups_max_width
+ \orelse\ifnum\itemgroupparameter\c!factor>\zerocount
+ \d_strc_itemgroups_list_width\itemgroupparameter\c!step\relax
+ \ifzeropt\d_strc_itemgroups_list_width \d_strc_itemgroups_list_width=.5em\fi
+ \multiply\d_strc_itemgroups_list_width \itemgroupparameter\c!factor
+ \advance\d_strc_itemgroups_list_width\itemgroupparameter\c!width\relax
+ \else
+ \d_strc_itemgroups_list_width\itemgroupparameter\c!width\relax
+ \fi
+ \advance\d_strc_itemgroups_list_width\itemgroupparameter\c!distance\relax
+ \let\currentitemgroup\savedcurrentitemgroup}
+
+\unexpanded\def\startitemgroup
+ {\dotripleempty\strc_itemgroups_start}
+
+\def\strc_itemgroups_start[#category][#options][#settings]%
+ {\begingroup % (1)
+ \def\currentitemgroup{#category}% no nested mixing of itemgroups
+ \let\currentparentitemgroup\currentitemgroup
+ \global\advance\c_strc_itemgroups_nesting\plusone
+ \def\currentitemlevel{\number\c_strc_itemgroups_nesting}%
+ \normalexpanded{\chaintocurrentitemgroup{\currentparentitemgroup:\currentitemlevel}}%
+ \edef\currentitemgroup{\currentparentitemgroup:\currentitemlevel}%
+ %
+ \ifthirdargument
+ \strc_itemgroups_start_indeed[#options][#settings]%
+ \orelse\ifsecondargument
+ \ifcondition\validassignment{#options}%
+ \strc_itemgroups_start_indeed[][#options]%
+ \else
+ \strc_itemgroups_start_indeed[#options][]%
+ \fi
+ \else
+ \strc_itemgroups_start_indeed[][]%
+ \fi}
+
+\def\strc_itemgroups_start_indeed[#options][#settings]%
+ {\edef\itemgroupoptions{\itemgroupparameter\c!option}%
+ \edef\itemgroupextraoptions{#options}%
+ \ifx\itemgroupoptions\empty
+ \let\itemgroupoptions\itemgroupextraoptions
+ \orelse\ifx\itemgroupextraoptions\empty
+ % ok
+ \else
+ \edef\itemgroupoptions{\itemgroupoptions,\itemgroupextraoptions}%
+ \fi
+ \begingroup % (2)
+ \the\itemgroupcommands
+ \let\c_strc_itemgroups_text_saved\c_strc_itemgroups_text
+ \strc_itemgroups_initialize_local
+ \strc_itemgroups_preset_stage_one\itemgroupoptions
+%
+% \ifhmode
+% \ifconditional\c_strc_itemgroups_auto_concat
+% \ifdim\lastskip=\d_strc_itemgroups_signal
+% \settrue\c_strc_itemgroups_concat
+% \fi
+% \fi
+% \ifconditional\c_strc_itemgroups_text_saved \else
+% \ifconditional\c_strc_itemgroups_text \else
+% \par
+% \fi
+% \fi
+% \fi
+%
+ \iftrialtypesetting
+ \strc_counters_save\v_strc_itemgroups_counter
+ \fi
+ \c_strc_itemgroups_n_of_items\zerocount
+ \strc_itemgroups_check_n_of_items
+ \ifx\itemgroupoptions\empty
+ \strc_itemgroups_setup_symbol_default
+ \strc_itemgroups_reset_continue_state
+ \setupcurrentitemgroup[#settings]%
+ \else
+ \strc_itemgroups_process_options\itemgroupoptions
+ \setupcurrentitemgroup[#settings]%
+ \ifconditional\c_strc_itemgroups_continue
+ \strc_itemgroups_setup_symbol_continue
+ \strc_itemgroups_fetch_continue_state
+ \else
+ \strc_itemgroups_setup_symbol_asked
+ \strc_itemgroups_store_continue_state\itemgroupoptions{#settings}%
+ \fi
+ \fi
+ %
+ \ifhmode
+ \ifconditional\c_strc_itemgroups_auto_concat
+ \ifdim\lastskip=\d_strc_itemgroups_signal
+ \settrue\c_strc_itemgroups_concat
+ \fi
+ \fi
+ \ifconditional\c_strc_itemgroups_text_saved \else
+ \ifconditional\c_strc_itemgroups_text \else
+ \par
+ \fi
+ \fi
+ \fi
+ %
+ \ifconditional\c_strc_itemgroups_pack
+ \ifnum\currentnofitems>\itemgroupparameter\c!packcriterium\relax\else
+ \setfalse\c_strc_itemgroups_pack
+ \fi
+ \fi
+ %
+ \ifnum\c_strc_itemgroups_nesting=\plusone % NIEUW
+ \doadaptleftskip {\itemgroupparameter\c!margin}%
+ \doadaptleftskip {\itemgroupparameter\c!leftmargin}%
+ \doadaptrightskip{\itemgroupparameter\c!rightmargin}%
+ \fi
+ %
+ \doadaptleftskip {\itemgroupparameter\c!leftmargindistance}%
+ \doadaptrightskip{\itemgroupparameter\c!rightmargindistance}%
+ %
+ \usealignparameter\itemgroupparameter
+ \edef\m_strc_itemgroups_indenting{\itemgroupparameter\c!indenting}%
+ \ifnum\c_strc_itemgroups_nesting>\zerocount
+ \settrue\c_strc_itemgroups_first
+ \ifconditional\c_strc_itemgroups_continue \else
+ \strc_counters_restart_sub\v_strc_itemgroups_counter\currentitemlevel{\numexpr\itemgroupparameter\c!start-\plusone\relax}%
+ \fi
+ \fi
+ \ifx\strc_itemgroups_used_symbol\empty
+ \strc_itemgroups_set_symbol\strc_itemgroups_asked_symbol % ** default value
+ \ifx\strc_itemgroups_used_symbol\empty
+ \let\currentitemgroupsymbol\currentitemlevel % ** fall back
+ \fi
+ \fi
+ \ifconditional\c_strc_itemgroups_auto_intro\ifnum\prevgraf<\plusthree
+ \settrue\c_strc_itemgroups_intro
+ \fi\fi
+ \ifconditional\c_strc_itemgroups_paragraph
+ \ifnum\c_strc_itemgroups_nesting>\plusone
+ \letitemgroupparameter\c!inbetween\empty
+ \fi
+ \fi
+ \ifconditional\c_strc_itemgroups_pack
+ \letitemgroupparameter\c!inbetween\empty
+ \fi
+ \ifconditional\c_strc_itemgroups_columns
+ \ifinsidecolumns\else\ifcase\c_strc_itemgroups_column_depth
+ \global\c_strc_itemgroups_column_depth\c_strc_itemgroups_nesting % global ?
+ \strc_itemgroups_before_command
+ \strc_itemgroups_tag_start_group
+ \strc_itemgroups_start_columns
+ \fi\fi
+ \fi
+ \ifconditional\c_strc_itemgroups_fitting
+ \ifdim\d_strc_itemgroups_max_width>\zeropoint
+ \letitemgroupparameter\c!width\d_strc_itemgroups_max_width
+ \fi
+ \fi
+ \strc_itemgroups_calculate_list_width\c_strc_itemgroups_nesting
+ \ifdim\d_strc_itemgroups_list_width>\zeropoint\relax
+ \ifconditional\c_strc_itemgroups_inline\else
+ \advance\leftskip\d_strc_itemgroups_list_width\relax
+ \fi
+ \fi
+ \ifx\m_strc_itemgroups_repeat_start\empty
+ \let\currentitemgroupconversionset \currentitemgroupsymbol
+ \edef\currentitemgroupsegments {\currentitemlevel}%
+ \else
+ \edef\currentitemgroupconversionset{\currentitemgroupconversionset,\currentitemgroupsymbol}%
+ \edef\currentitemgroupsegments {\m_strc_itemgroups_repeat_start:\currentitemlevel}%
+ \fi
+ \d_strc_itemgroups_asked_width\itemgroupparameter\c!width\relax
+ \startcollectitems}
+
+\let\startcollectitems\relax
+\let\stopcollectitems \relax
+
+\letvalue{\??itemgroupalign\v!flushleft }\relax
+\letvalue{\??itemgroupalign\v!right }\relax
+\letvalue{\??itemgroupalign\v!flushright}\hfill
+\letvalue{\??itemgroupalign\v!left }\hfill
+\letvalue{\??itemgroupalign\v!middle }\hfil
+\letvalue{\??itemgroupalign\v!center }\hfil
+
+\def\strc_itemgroups_left_sym_filler
+ {\csname\??itemgroupalign\itemgroupparameter\c!symalign\endcsname}
+
+% symbols + states
+
+\def\strc_itemgroups_store_global_symbol#symbol%
+ {\letgvalue{\??itemgroupglobal\currentitemgroup:\currentitemlevel}#symbol}
+
+\def\strc_itemgroups_store_local_symbol#symbol%
+ {\letgvalue{\??itemgrouplocal\currentitemgroup:\currentitemlevel}#symbol}
+
+\def\strc_itemgroups_fetch_global_symbol
+ {\csname\??itemgroupglobal\currentitemgroup:\currentitemlevel\endcsname}
+
+\def\strc_itemgroups_fetch_local_symbol
+ {\csname\??itemgrouplocal\currentitemgroup:\currentitemlevel\endcsname}
+
+\def\strc_itemgroups_setup_symbol_default
+ {\edef\strc_itemgroups_asked_symbol{\itemgroupparameter\c!symbol}%
+ \strc_itemgroups_store_global_symbol\empty}
+
+\def\strc_itemgroups_setup_symbol_continue
+ {\ifcsname\??itemgroupglobal\currentitemgroup:\currentitemlevel\endcsname
+ \let\strc_itemgroups_asked_symbol\strc_itemgroups_fetch_global_symbol
+ \else
+ \let\strc_itemgroups_asked_symbol\currentitemlevel
+ \fi}
+
+\def\strc_itemgroups_setup_symbol_asked
+ {\edef\strc_itemgroups_asked_symbol{\itemgroupparameter\c!symbol}}
+
+\ifdefined\strc_itemgroups_start_columns
+
+ % already defined in page-mix
+
+\else
+
+ % will be redefined in page-mix
+
+ \ifdefined\startcolumns \else
+ \unexpanded\def\startcolumns[#settings]{}
+ \unexpanded\def\stopcolumns {}
+ \fi
+
+ \def\strc_itemgroups_start_columns
+ {\startcolumns
+ [\c!n=\itemgroupparameter\c!n,
+ \c!height=,
+ \c!rule=\v!off,
+ \c!balance=\v!yes,
+ \c!align=\v!no]}
+
+ \def\strc_itemgroups_stop_columns
+ {\stopcolumns}
+
+\fi
+
+\unexpanded\def\stopitemgroup
+ {\stopcollectitems
+ \ifconditional\c_strc_itemgroups_text
+ \removeunwantedspaces
+ \space
+ \ignorespaces
+ \else
+ \par
+ \fi
+ \strc_itemgroups_register_status
+ \ifconditional\c_strc_itemgroups_first \else
+ \dostoptagged
+ \dostoptagged
+ % \endgroup % (3)
+ \fi
+ \ifnum\c_strc_itemgroups_column_depth=\c_strc_itemgroups_nesting\relax
+ \strc_itemgroups_stop_columns
+ \global\c_strc_itemgroups_column_depth\zerocount % global ?
+ \strc_itemgroups_tag_stop_group
+ \strc_itemgroups_after_command
+ \dontrechecknextindentation
+ \orelse\ifnum\c_strc_itemgroups_nesting=\plusone
+ \strc_itemgroups_insert_breakallow
+ \strc_itemgroups_tag_stop_group
+ \strc_itemgroups_after_command
+ \useindentnextparameter\itemgroupparameter
+ \else
+ % nieuw, not yet nobreak handling
+ \strc_itemgroups_tag_stop_group
+ \ifcase\c_strc_itemgroups_spacing_mode
+ \strc_itemgroups_after_command
+ \or
+ \strc_itemgroups_after_command
+ \fi
+ \dontrechecknextindentation
+ \fi
+ % new test, needed in sidefloats (surfaced in volker's proceedings)
+ \iftrialtypesetting
+ \strc_counters_restore\v_strc_itemgroups_counter % could happen in LUA
+ \fi
+ \global\advance\c_strc_itemgroups_nesting\minusone
+ \xdef\currentitemlevel{\number\c_strc_itemgroups_nesting}%
+ %\ifconditional\c_strc_itemgroups_text
+ \endgroup % (2)
+ \endgroup % (1)
+ %\else
+ % \endgroup % (2)
+ % \endgroup % (1)
+ % \par % hm, already done, and dangerous as \c_strc_itemgroups_text is already forgotten
+ %\fi
+ \dorechecknextindentation}
+
+% The items.
+
+\unexpanded\def\startitemgroupitem
+ {\dosingleempty\strc_itemgroups_start_item}
+
+\def\strc_itemgroups_start_item_first
+ {\setfalse\c_strc_itemgroups_first
+ % \begingroup % (3)
+ \ifcase\c_strc_itemgroups_nesting
+ % 0
+ \or
+ \strc_itemgroups_start_item_first_one % 1
+ \else
+ \strc_itemgroups_start_item_first_two % 2+
+ \fi}
+
+\def\strc_itemgroups_start_item_first_one
+ {\ifcase\c_strc_itemgroups_column_depth
+ \ifconditional\c_strc_itemgroups_intro\strc_itemgroups_insert_breakno\fi
+ \strc_itemgroups_before_command
+ \strc_itemgroups_tag_start_group
+ \ifconditional\c_strc_itemgroups_intro\strc_itemgroups_insert_breakno\fi
+ \fi}
+
+\def\strc_itemgroups_start_item_first_two
+ {\ifconditional\c_strc_itemgroups_paragraph\else
+ \edef\previtemlevel{\the\numexpr\c_strc_itemgroups_nesting-\plusone}%
+ \ifcase\c_strc_itemgroups_spacing_mode
+ \strc_itemgroups_before_command
+ \or
+ \doifelsenothing\strc_itemgroups_before_command % should possibly expand to empty
+ {\nameditemgroupparameter{\currentparentitemgroup:\previtemlevel}\c!inbetween}%
+ \strc_itemgroups_before_command
+ \else
+ \nameditemgroupparameter{\currentparentitemgroup:\previtemlevel}\c!inbetween
+ \fi
+ \strc_itemgroups_tag_start_group
+ \fi}
+
+\def\strc_itemgroups_start_item_next
+ {\dostoptagged % ok? what do we stop here?
+ \dostoptagged % ok? what do we stop here?
+ \ifconditional\c_strc_itemgroups_text
+ \ifhmode
+ % WS: make the distance between items customizable, think about better default values -> see itemize-1.tex
+ \strc_itemgroups_set_text_item_distance% HH: moved out and made configurable (sort of)
+ \removeunwantedspaces
+ \hskip\m_strc_itemgroups_text_distance\relax
+ \fi
+ \else
+ \strc_itemgroups_between_command
+ \fi}
+
+% c_strc_itemgroups_concat:
+%
+% the problem is that we use leftskip so concat cannot reliable take the height into
+% account; it's .. rather tricky when white space in there anyway (due to \par) .. so
+% we rely on a special blank method
+%
+% \startitemize[n]
+% \item bla
+% \item \startitemize[a]
+% \item bla $\displaystyle\int^{x^{y^4}}$ \item bla
+% \stopitemize
+% \stopitemize
+
+\unexpanded\def\strc_itemgroups_start_item[#reference]% we can reuse more
+ {\def\currentitemreference{#reference}%
+ \ifconditional\c_strc_itemgroups_text
+ % begin of item
+ \else
+ \par
+ \fi
+ \ifconditional\c_strc_itemgroups_concat
+ \strc_itemgroups_insert_breakno
+ \fi
+ \strc_itemgroups_increment_item_counter
+ \ifconditional\c_strc_itemgroups_first
+ \strc_itemgroups_start_item_first
+ \else
+ \strc_itemgroups_start_item_next
+ \fi
+ \ifconditional\c_strc_itemgroups_concat
+ \spac_overlay_lines % see spac-ver.mkvi ... a typical potential problem
+ \setfalse\c_strc_itemgroups_concat
+ \fi
+ \dostarttagged\t!item\empty
+ % \dotagsetitem\empty
+ \dostarttagged\t!itemtag\empty
+ \strc_itemgroups_insert_item
+ \dostoptagged
+ \ifconditional\c_strc_itemgroups_pack
+ \setupwhitespace[\v!none]%
+ \fi
+ \itemgroupparameter\c!inner % will become obsolete (better use setups)
+ \strc_itemgroups_margin_symbol
+ \let\strc_itemgroups_margin_symbol\relax
+ \dostarttagged\t!itemcontent\empty
+ \begstrut % \strut
+ \nobreak % else problems with intext items
+ \seteffectivehsize % NEW !
+ \hskip\d_strc_itemgroups_signal % concat
+ \itemgroupparameter\c!command}
+
+\unexpanded\def\stopitemgroupitem
+ {\ifhmode
+ \endstrut % new per 2017-12-15
+ \fi
+ \ifconditional\c_strc_itemgroups_text
+ % nothing
+ \else
+ \endgraf
+ \fi}
+\unexpanded\def\startitemgrouphead
+ {\dosingleempty\strc_itemgroups_start_head}
+
+\unexpanded\def\strc_itemgroups_start_head[#reference]%
+ {\ifconditional\c_strc_itemgroups_first \else
+ \strc_itemgroups_insert_breakallow
+ \fi
+ \ifconditional\c_strc_itemgroups_pack \else
+ \strc_itemgroups_before_head_command
+ \fi
+ \ifconditional\c_strc_itemgroups_first
+ \ifconditional\c_strc_itemgroups_intro \else
+ \ifcase\c_strc_itemgroups_nesting
+ \strc_itemgroups_insert_breakallow
+ \fi
+ \fi
+ \fi
+ \strc_itemgroups_start_item[#reference]%
+ \pickupgroupedcommand
+ \strc_itemgroups_start_head_indeed
+ \strc_itemgroups_stop_head_indeed
+ \strc_itemgroups_head_body_indeed}
+
+\unexpanded\def\stopitemgrouphead
+ {\dostoptagged
+ \stopitemgroupitem}
+
+\unexpanded\def\strc_itemgroups_start_head_indeed
+ {\settrue\c_strc_itemgroups_head
+ \dotagsetitem\s!head% % weird place
+ \dostarttagged\t!itemhead\empty
+ \useitemgroupstyleandcolor\c!headstyle\c!headcolor\ignorespaces}
+
+\unexpanded\def\strc_itemgroups_stop_head_indeed
+ {\removeunwantedspaces
+ \dostoptagged
+ \ifconditional\c_strc_itemgroups_inline_head
+ \space
+ \ignorespaces
+ \else
+ \ifconditional\c_strc_itemgroups_text
+ \space
+ \ignorespaces
+ \else
+ \par
+ \fi
+ \strc_itemgroups_insert_breakno
+ \ifconditional\c_strc_itemgroups_pack\else\strc_itemgroups_after_head_command\fi
+ \strc_itemgroups_insert_breakno
+ \fi}
+
+\unexpanded\def\strc_itemgroups_head_body_indeed
+ {\dostarttagged\t!itembody\empty
+ \noindentation
+ \ignorespaces}
+
+% Simple commands.
+
+\unexpanded\def\strc_itemgroups_start_do_item
+ {\startitemgroupitem}
+
+\unexpanded\def\strc_itemgroups_start_no_item
+ {\let\currentitemreference\empty
+ \strc_itemgroups_increment_item_counter
+ %\advance\c_strc_itemgroups_n_of_items\plusone
+ \setbox\b_strc_itemgroups\emptyhbox
+ \strc_itemgroups_check_for_repeated
+ \ignorespaces}
+
+\unexpanded\def\strc_itemgroups_start_button[#destination]%
+ {\edef\m_strc_itemgroups_destination{#destination}%
+ \startitemgroupitem}
+
+\unexpanded\def\strc_itemgroups_start_symbol#text%
+ {\def\strc_itemgroups_extra_symbol{#text}%
+ \settrue\c_strc_itemgroups_symbol
+ \startitemgroupitem
+ \dotagsetitem\s!symbol}
+
+\unexpanded\def\strc_itemgroups_start_dummy
+ {\strc_itemgroups_start_symbol
+ %\strut\strut} % two ?
+ \begstrut}
+
+\unexpanded\def\strc_itemgroups_start_subitem
+ {\settrue\c_strc_itemgroups_sub
+ \startitemgroupitem
+ \dotagsetitem\s!sub}
+
+\unexpanded\def\strc_itemgroups_start_edge#text%
+ {\strc_itemgroups_start_symbol
+ {\strc_itemgroups_calculate_list_width\c_strc_itemgroups_nesting
+ \dostarttagged\t!ignore\empty % for the moment, maybe an attribute
+ \hbox to \d_strc_itemgroups_list_width
+ {#text\hskip\itemgroupparameter\c!distance}%
+ \dostoptagged}}
+
+\unexpanded\def\strc_itemgroups_start_margin#text%
+ {\def\strc_itemgroups_margin_symbol % brrr
+ {\dostarttagged\t!ignore\empty % for the moment, maybe an attribute
+ \llap
+ {\begingroup
+ \useitemgroupstyleandcolor\c!marstyle\c!marcolor
+ #text% keep em/ex local
+ \endgroup
+ \hskip\dimexpr\leftskip+\leftmargindistance\relax}%
+ \dostoptagged}%
+ \startitemgroupitem
+ \dotagsetitem\s!margin}
+
+\unexpanded\def\strc_itemgroups_start_text#text%
+ {\def\strc_itemgroups_extra_symbol{#text}%
+ \settrue\c_strc_itemgroups_symbol
+ \settrue\c_strc_itemgroups_txt
+ \startitemgroupitem}
+
+% \unexpanded\def\strc_itemgroups_start_head
+% {\settrue\c_strc_itemgroups_head
+% \startitemgrouphead}
+
+\unexpanded\def\strc_itemgroups_start_items
+ {\dosingleempty\strc_itemgroups_start_items_indeed}
+
+\unexpanded\def\strc_itemgroups_start_items_indeed[#whatever]% something got lost
+ {\strc_itemgroups_start_edge
+ {\dorecurse{0\itemgroupparameter\c!items}{\strc_itemgroups_used_symbol\hss}%
+ \unskip}}
+
+% \unexpanded\def\startspecialitemgroupitem[#name]%
+% {\csname\??itemgroupstart\ifcsname\??itemgroupstart#name\endcsname#name\else\v!item\fi\endcsname}
+
+\unexpanded\def\startspecialitemgroupitem[#name]%
+ {\ifcsname\??itemgroupstart#name\endcsname
+ \expandafter\lastnamedcs
+ \else
+ \expandafter\strc_itemgroups_start_do_item
+ \fi}
+
+\unexpanded\def\stopspecialitemgroupitem
+ {\stopitemgroupitem}
+
+\letvalue{\??itemgroupstart\v!item}\strc_itemgroups_start_do_item
+\letvalue{\??itemgroupstart\v!sub }\strc_itemgroups_start_subitem
+\letvalue{\??itemgroupstart\v!sym }\strc_itemgroups_start_symbol
+\letvalue{\??itemgroupstart\v!ran }\strc_itemgroups_start_edge
+\letvalue{\??itemgroupstart\v!its }\strc_itemgroups_start_items
+\letvalue{\??itemgroupstart\v!mar }\strc_itemgroups_start_margin
+
+\def\optimizelistitemsbreak
+ {\ifcase\c_strc_itemgroups_column_depth
+ \ifconditional\c_strc_itemgroups_optimize
+ \ifcase\c_strc_itemgroups_max_items
+ \orelse\ifnum\c_strc_itemgroups_max_items=\plusthree
+ \ifnum\c_strc_itemgroups_n_of_items>\plusone
+ \strc_itemgroups_insert_nobreak
+ \fi
+ \orelse\ifnum\c_strc_itemgroups_max_items>\plusthree
+ \ifnum\c_strc_itemgroups_n_of_items=\plustwo
+ \ifconditional\c_strc_itemgroups_intro
+ \strc_itemgroups_insert_breakno
+ \else
+ \strc_itemgroups_insert_nobreak
+ \fi
+ \orelse\ifnum\c_strc_itemgroups_max_items=\c_strc_itemgroups_n_of_items\relax
+ \strc_itemgroups_insert_nobreak
+ \orelse\ifnum\c_strc_itemgroups_n_of_items>\plustwo
+ \strc_itemgroups_insert_break
+ \else
+ \ifconditional\c_strc_itemgroups_intro\else\strc_itemgroups_insert_break\fi
+ \fi
+ \fi
+ \fi
+ \fi}
+
+\def\strc_itemgroups_handle_text_item
+ {\scratchdimen\wd\b_strc_itemgroups
+ \advance \scratchdimen \itemgroupparameter\c!distance\relax
+ \ifdim\scratchdimen>\d_strc_itemgroups_list_width
+ \advance\scratchdimen -\d_strc_itemgroups_list_width
+ \else
+ \scratchdimen\zeropoint
+ \fi
+ \llap{\hbox to \d_strc_itemgroups_list_width{\ifconditional\c_strc_itemgroups_sub\llap{+\enspace}\fi\box\b_strc_itemgroups\hss}}% was: \hfill
+ \hskip\scratchdimen}
+
+\def\strc_itemgroups_handle_lapped_item_positive
+ {\llap
+ {\dontcomplain
+ \hbox to \d_strc_itemgroups_list_width
+ {\ifconditional\c_strc_itemgroups_sub
+ \dostarttagged\t!ignore\empty
+ \llap{+\enspace}%
+ \dostoptagged
+ \fi
+ \strc_itemgroups_left_sym_filler
+ \box\b_strc_itemgroups % can already have a forced widt, only factor handled here
+ \hfil
+ \hskip\itemgroupparameter\c!distance}}}
+
+\def\strc_itemgroups_handle_lapped_item_negative
+ {\llap
+ {\ifconditional\c_strc_itemgroups_sub
+ \dostarttagged\t!ignore\empty
+ \llap{+\enspace}%
+ \dostoptagged
+ \fi
+ \box\b_strc_itemgroups
+ \hskip\leftmargindistance}}
+
+\def\strc_itemgroups_handle_groups_text_item
+ {\hbox
+ {\ifconditional\c_strc_itemgroups_sub
+ \dostarttagged\t!ignore\empty
+ +\enspace
+ \dostoptagged
+ \fi
+ \box\b_strc_itemgroups
+ \hskip\interwordspace}%
+ \nobreak}
+
+\def\strc_itemgroups_handle_groups_inline_item
+ {\hbox to \d_strc_itemgroups_list_width
+ {\ifconditional\c_strc_itemgroups_sub
+ \dostarttagged\t!ignore\empty
+ \llap{+\enspace}%
+ \dostoptagged
+ \fi
+ \box\b_strc_itemgroups
+ \hss}} % was: \hfill
+
+\unexpanded\def\strc_itemgroups_start_head_sym#text%
+ {\def\strc_itemgroups_extra_symbol{#text}%
+ \settrue\c_strc_itemgroups_symbol
+ \settrue\c_strc_itemgroups_head
+ \strc_itemgroups_start_head}
+
+\def\strc_itemgroups_make_symbol_box
+ {\setbox\b_strc_itemgroups\autodirhbox
+ {\ifconditional\c_strc_itemgroups_head
+ \ifconditional\c_strc_itemgroups_symbol
+ \strc_itemgroups_insert_extra_reference
+ \useitemgroupstyleandcolor\c!symstyle\c!symcolor
+ \strc_itemgroups_extra_symbol
+ \else
+ \useitemgroupstyleandcolor\c!headstyle\c!headcolor
+ \strc_itemgroups_used_symbol
+ \fi
+ \else
+ \ifconditional\c_strc_itemgroups_symbol
+ \strc_itemgroups_insert_extra_reference
+ \useitemgroupstyleandcolor\c!symstyle\c!symcolor
+ \strc_itemgroups_extra_symbol
+ \else
+ \useitemgroupstyleandcolor\c!style\c!color
+ \strc_itemgroups_used_symbol
+ \fi
+ \fi}%
+ \let\strc_itemgroups_extra_symbol\empty
+ \setfalse\c_strc_itemgroups_symbol}
+
+\def\strc_itemgroups_make_fitting_box
+ {\ifdim\wd\b_strc_itemgroups>\itemgroupparameter\c!maxwidth\relax
+ \normalexpanded{\global\setitemgroupparameter{\c!maxwidth}{\the\wd\b_strc_itemgroups}}%
+ \fi
+ \ifdim\d_strc_itemgroups_max_width>\zeropoint
+ \setbox\b_strc_itemgroups\simplealignedbox
+ {\dimexpr\d_strc_itemgroups_max_width+\itemgroupparameter\c!distance\relax}
+ {\itemgroupparameter\c!itemalign}
+ {\box\b_strc_itemgroups\hskip\itemgroupparameter\c!distance}%
+ \fi}
+
+\def\strc_itemgroups_make_aligned_box
+ {\doifsomething{\itemgroupparameter\c!itemalign}
+ {\setbox\b_strc_itemgroups\simplealignedbox
+ {\dimexpr\d_strc_itemgroups_asked_width+\itemgroupparameter\c!distance\relax}
+ {\itemgroupparameter\c!itemalign}
+ {\box\b_strc_itemgroups\hskip\itemgroupparameter\c!distance}}}
+
+\def\strc_itemgroups_make_destination_box
+ {\iftrialtypesetting \orelse \ifx\m_strc_itemgroups_destination\empty \else
+ \setbox\b_strc_itemgroups\hbox{\directgotobox{\box\b_strc_itemgroups}[\m_strc_itemgroups_destination]}%
+ \fi}
+
+\def\strc_itemgroups_check_indenting
+ {\setfalse\c_strc_itemgroups_indented_first
+ \ifx\m_strc_itemgroups_indenting\empty \else
+ \normalexpanded{\setupindenting[\v!reset,\v!yes,\m_strc_itemgroups_indenting]}%
+ \ifconditional\c_spac_indentation_indent_first % better is to have a mode
+ \doifnot{\itemgroupparameter\c!alignsymbol}\v!yes
+ {\settrue\c_strc_itemgroups_indented_first}%
+ \fi
+ \fi}
+
+\def\strc_itemgroups_check_for_repeated
+ {\ifconditional\c_strc_itemgroups_repeat
+ \ifx\m_strc_itemgroups_repeat_start\empty
+ \edef\m_strc_itemgroups_repeat_start{\currentitemlevel}%
+ \fi
+ \else
+ \let\m_strc_itemgroups_repeat_start\empty
+ \fi}
+
+\def\strc_itemgroups_insert_item
+ {\ifconditional\c_strc_itemgroups_text % again?
+ % begin of item
+ \else
+ \par % done twice?
+ \fi
+ \advance\c_strc_itemgroups_n_of_items\plusone
+ \optimizelistitemsbreak
+ \strc_itemgroups_check_indenting
+ \dontleavehmode
+ \ifconditional\c_strc_itemgroups_indented_first
+ \hskip-\parindent
+ \fi
+ \strc_itemgroups_make_symbol_box
+ \strc_itemgroups_make_destination_box
+ \ifconditional\c_strc_itemgroups_fitting
+ \strc_itemgroups_make_fitting_box
+ \else\ifdim\d_strc_itemgroups_asked_width>\zeropoint
+ \strc_itemgroups_make_aligned_box
+ \fi\fi
+ \let\m_strc_itemgroups_destination\empty
+ \ht\b_strc_itemgroups\strutheight % just in case a symbols is not yet available in
+ \dp\b_strc_itemgroups\strutdepth % the current run (more a mkii mp side artifact)
+ \strc_itemgroups_check_for_repeated
+ \ifdim\d_strc_itemgroups_asked_width<\zeropoint\relax
+ \strc_itemgroups_handle_lapped_item_negative
+ \else
+ \ifzeropt\d_strc_itemgroups_asked_width
+ \strc_itemgroups_calculate_list_width\plusone
+ \else
+ \strc_itemgroups_calculate_list_width\c_strc_itemgroups_nesting
+ \fi
+ \ifconditional\c_strc_itemgroups_text
+ \strc_itemgroups_handle_groups_text_item
+ \orelse\ifconditional\c_strc_itemgroups_inline
+ \strc_itemgroups_handle_groups_inline_item
+ \orelse\ifconditional\c_strc_itemgroups_txt
+ \strc_itemgroups_handle_text_item
+ \else
+ \strc_itemgroups_handle_lapped_item_positive
+ \fi
+ \fi
+ \setfalse\c_strc_itemgroups_head
+ \setfalse\c_strc_itemgroups_sub
+ \ifconditional\c_strc_itemgroups_indented_first
+ \hskip\parindent
+ \fi
+ \ignorespaces}
+
+\def\strc_itemgroups_start_item_nop
+ {\let\currentitemreference\empty
+ \strc_itemgroups_increment_item_counter
+ \advance\c_strc_itemgroups_n_of_items\plusone
+ \setbox\b_strc_itemgroups\hbox
+ {\useitemgroupstyleandcolor\c!style\c!color
+ \strc_itemgroups_used_symbol}%
+ \strc_itemgroups_check_for_repeated
+ \ignorespaces}
+
+\setvalue{\??itemgroupdistance\v!none}%
+ {\let\m_strc_itemgroups_text_distance\zeropoint}
+
+\setvalue{\??itemgroupdistance\v!space}%
+ {\def\m_strc_itemgroups_text_distance{\interwordspace\!!plus\interwordstretch\!!minus\interwordshrink}}
+
+\setvalue\??itemgroupdistance % catches empty value
+ {\let\m_strc_itemgroups_text_distance\zeropoint}
+
+\unexpanded\def\strc_itemgroups_set_text_item_distance
+ {\edef\m_strc_itemgroups_text_distance{\itemgroupparameter\c!textdistance}%
+ \ifx\m_strc_itemgroups_text_distance\empty
+ %
+ \orelse\ifcsname\??itemgroupdistance\m_strc_itemgroups_text_distance\endcsname
+ \lastnamedcs
+ \else
+ \strc_itemgroups_set_text_item_distance_indeed
+ \fi}
+
+\def\strc_itemgroups_set_text_item_distance_indeed
+ {\assignvalue
+ \m_strc_itemgroups_text_distance
+ \m_strc_itemgroups_text_distance
+ {.5\interwordspace\!!plus.5\emwidth}%
+ {\interwordspace \!!plus \emwidth}%
+ {\emwidth \!!plus \interwordstretch\!!minus\interwordshrink}}
+
+% \unexpanded\def\strc_itemgroups_default_command
+% {\EveryPar{\ignorespaces}% needed ?
+% \ignorespaces}
+
+\unexpanded\def\strc_itemgroups_default_command
+ {\ignorespaces}
+
+%D Special case:
+
+\unexpanded\def\strc_itemgroups_head#text\par
+ {\startitemgrouphead{#text}}
+
+%D The local commands:
+
+\appendtoks
+ \let\item \strc_itemgroups_start_do_item
+ \let\noitem \strc_itemgroups_start_no_item
+ \let\itm \strc_itemgroups_start_do_item
+ \let\but \strc_itemgroups_start_button
+ \let\nop \strc_itemgroups_start_dummy
+ \let\txt \strc_itemgroups_start_text
+ \let\head \strc_itemgroups_head
+ \let\headsym \strc_itemgroups_start_head_sym
+ \let\startitem \startitemgroupitem
+ \let\stopitem \stopitemgroupitem
+ \let\starthead \startitemgrouphead
+ \let\stophead \stopitemgroupitemhead
+ \let\startspecialitem\startspecialitemgroupitem
+ \let\stopspecialitem \stopspecialitemgroupitem
+\to \itemgroupcommands
+
+\ifx\currentinterface \v!english \else
+
+ \appendtoks
+ \expandafter\let\csname\v!item \endcsname\strc_itemgroups_start_do_item
+ \expandafter\let\csname\v!sub \endcsname\strc_itemgroups_start_subitem
+ \expandafter\let\csname\v!sym \endcsname\strc_itemgroups_start_symbol
+ \expandafter\let\csname\v!ran \endcsname\strc_itemgroups_start_edge
+ \expandafter\let\csname\v!head \endcsname\strc_itemgroups_head
+ \expandafter\let\csname\v!its \endcsname\strc_itemgroups_start_items
+ \expandafter\let\csname\v!mar \endcsname\strc_itemgroups_start_margin
+ \expandafter\let\csname\v!txt \endcsname\strc_itemgroups_start_text
+ \expandafter\let\csname\e!start\v!item\endcsname\startitemgroupitem
+ \expandafter\let\csname\e!stop \v!item\endcsname\stopitemgroupitem
+ \expandafter\let\csname\e!start\v!head\endcsname\startitemgrouphead
+ \expandafter\let\csname\e!stop \v!head\endcsname\stopitemgrouphead
+ \to \itemgroupcommands
+
+\fi
+
+\relaxvalueifundefined \v!item
+\relaxvalueifundefined \v!sub
+\relaxvalueifundefined \v!sym
+\relaxvalueifundefined \v!ran
+\relaxvalueifundefined \v!head
+\relaxvalueifundefined \v!its
+\relaxvalueifundefined \v!mar
+\relaxvalueifundefined \v!txt
+\relaxvalueifundefined {\e!start\v!item}
+\relaxvalueifundefined {\e!stop \v!item}
+\relaxvalueifundefined {\e!start\v!head}
+\relaxvalueifundefined {\e!stop \v!head}
+
+%D A nice example of a plugin:
+%D
+%D \startbuffer
+%D \startitemize[a,random,packed]
+%D \startitem first \stopitem \startitem second \stopitem
+%D \startitem third \stopitem \startitem fourth \stopitem
+%D \stopitemize
+%D
+%D \startitemize[a,random,packed]
+%D \startitem first \stopitem \startitem second \stopitem
+%D \startitem third \stopitem \startitem fourth \stopitem
+%D \stopitemize
+%D
+%D \startitemize[a,packed]
+%D \startitem first \stopitem \startitem second \stopitem
+%D \startitem third \stopitem \startitem fourth \stopitem
+%D \stopitemize
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+% better collectitems als conditional and a real plugin mechanism (some day)
+
+\newcount\c_strc_itemgroups_collected_stored
+\newcount\c_strc_itemgroups_collected_done
+\newcount\c_strc_itemgroups_collected_current
+
+% \expandafter\def\expandafter\strc_itemgroups_collected_store\expandafter#\expandafter1\csname\e!stop\v!item\endcsname % use grabuntil
+% {\advance\c_strc_itemgroups_collected_stored\plusone
+% \setvalue{\??itemgroupstack\number\c_strc_itemgroups_collected_stored}{\startitemgroupitem#1\stopitemgroupitem}}
+
+\let\strc_itemgroups_collected_store\relax
+
+\normalexpanded{\def\strc_itemgroups_collected_store#1\csname\e!stop\v!item\endcsname}%
+ {\advance\c_strc_itemgroups_collected_stored\plusone
+ \setvalue{\??itemgroupstack\number\c_strc_itemgroups_collected_stored}{\startitemgroupitem#1\stopitemgroupitem}}
+
+\def\strc_itemgroups_collected_flush_randomize
+ {\collecteditemgroupitem}
+
+\def\strc_itemgroups_collected_flush_horizontal
+ {\begingroup
+ \scratchcounter\itemgroupparameter\c!n\relax
+ \ifnum\c_strc_itemgroups_collected_done>\plusone
+ \ifcase\modulonumber\scratchcounter\c_strc_itemgroups_collected_done\relax
+ % compensate for rounding errors
+ \hfill % \hskip\zeropoint plus \scaledpoint minus \scaledpoint
+ \allowbreak
+ \fi
+ \fi
+ \noindent % no \dontleavehmode
+ \hbox to \dimexpr\availablehsize/\scratchcounter\relax{\collecteditemgroupitem\hss}%
+ \endgroup}
+
+% \def\strc_itemgroups_collected_flush_indeed
+% {\collecteditemgroupitem
+% \iftrialtypesetting
+% \undefinevalue{\??itemgroupstack\number\c_strc_itemgroups_collected_current}%
+% \fi}
+
+\def\strc_itemgroups_collected_flush_indeed
+ {\collecteditemgroupitem
+ \undefinevalue{\??itemgroupstack\number\c_strc_itemgroups_collected_current}}
+
+\def\strc_itemgroups_collected_flush
+ {\ifconditional\c_strc_itemgroups_randomize
+ \getrandomcount\c_strc_itemgroups_collected_current\plusone\c_strc_itemgroups_collected_stored
+ \else
+ \advance\c_strc_itemgroups_collected_current\plusone
+ \fi
+ \ifcsname\??itemgroupstack\number\c_strc_itemgroups_collected_current\endcsname
+ \edef\collecteditemgroupitem{\lastnamedcs}%
+ \ifconditional\c_strc_itemgroups_horizontal
+ \strc_itemgroups_collected_flush_horizontal
+ \else
+ \strc_itemgroups_collected_flush_indeed
+ \fi
+ \advance\c_strc_itemgroups_collected_done\plusone
+ \fi
+ \ifnum\c_strc_itemgroups_collected_done<\c_strc_itemgroups_collected_stored
+ \expandafter\strc_itemgroups_collected_flush
+ \fi}
+
+\unexpanded\def\stopcollectitems
+ {\ifconditional\c_strc_itemgroups_collecting
+ \c_strc_itemgroups_collected_done \zerocount
+ \c_strc_itemgroups_collected_current\zerocount
+ \ifnum\c_strc_itemgroups_collected_stored>\zerocount
+ \ifconditional\c_strc_itemgroups_horizontal
+ \strc_itemgroups_before_command
+ \setfalse\c_strc_itemgroups_first
+ \strc_itemgroups_collected_flush
+ %\strc_itemgroups_after_command % triggered elsewhere
+ \else
+ \strc_itemgroups_collected_flush
+ \fi
+ \fi
+ \fi}
+
+\unexpanded\def\startcollectitems
+ {\ifconditional\c_strc_itemgroups_collecting
+ \c_strc_itemgroups_collected_stored\zerocount
+ \letvalue{\e!start\v!item}\strc_itemgroups_collected_store
+ \fi}
+
+%D Left-overs:
+
+\unexpanded\def\item
+ {\strc_itemgroups_item_alone}
+
+\def\strc_itemgroups_item_alone[#category]#text\par
+ {\doifelsesomething{#category}{\startitemgroup[#category]}{\startitemgroup[\v!itemize]}%
+ \startitem#text\stopitem
+ \stopitemgroup}
+
+\unexpanded\def\head
+ {\strc_itemgroups_head_alone}
+
+\def\strc_itemgroups_head_alone[#category]#head\par#body\par
+ {\doifelsesomething{#category}{\startitemgroup[#category]}{\startitemgroup[\v!itemize]}%
+ \starthead{#head}#body\stophead
+ \stopitemgroup}
+
+\setuvalue{\e!start\v!item}%
+ {\startitemgroup[\v!itemize]%
+ \startitemgroupitem
+ \setuvalue{\e!stop\v!item}{\stopitemgroupitem\stopitemgroup}}
+
+% \def\sym#text%
+% {\noindent
+% \begingroup
+% \setbox\scratchbox\hbox{\settrialtypesetting#text}%
+% \setbox\scratchbox\hbox\ifdim\wd\scratchbox<1em to 1.5\else spread 1\fi em{#text\hfil}%
+% \normalexpanded{\box\scratchbox\endgroup\hangindent\the\wd\scratchbox}%
+% \ignorespaces}
+
+%D End of plugin.
+
+%D Something for tables:
+
+\unexpanded\def\itemtag
+ {\dosingleempty\strc_itemgroups_item_tag}
+
+\unexpanded\def\strc_itemgroups_item_tag[#reference]% we can reuse more
+ {\def\currentitemreference{#reference}%
+ \iftrialtypesetting
+ \strc_counters_save\v_strc_itemgroups_counter
+ \strc_itemgroups_increment_item_counter
+ \strc_itemgroups_insert_item_tag_indeed
+ \strc_counters_restore\v_strc_itemgroups_counter
+ \else
+ \strc_itemgroups_increment_item_counter
+ \strc_itemgroups_insert_item_tag_indeed
+ \fi}
+
+\def\strc_itemgroups_insert_item_tag_indeed
+ {\letitemgroupparameter\c!distance\zeropoint
+ %letitemgroupparameter\c!width\zeropoint
+ \strc_itemgroups_make_symbol_box
+ \strc_itemgroups_make_destination_box
+ \let\m_strc_itemgroups_destination\empty
+ \ht\b_strc_itemgroups\strutheight
+ \dp\b_strc_itemgroups\strutdepth
+ \box\b_strc_itemgroups
+ \ignorespaces}
+
+%D Done again.
+
+\setupitemgroup
+ [\c!margin=\zeropoint,
+ \c!leftmargin=\zeropoint,
+ \c!rightmargin=\zeropoint,
+ \c!leftmargindistance=\zeropoint,
+ \c!rightmargindistance=\zeropoint,
+ \c!indentnext=\v!yes,
+ \c!width=1.5\emwidth,
+ \c!factor=0,
+ %\c!distance=.5em, % is now:
+ \c!step=.5\emwidth, % deals with broad
+ \c!distance=\zeropoint,
+ %\c!align=\v!normal, % definitely not \v!normal !
+ %\c!symalign=,
+ %\c!color=,
+ %\c!indenting=, % untouched if empty
+ %\c!style=,
+ \c!marstyle=\v!type,
+ %\c!symstyle=,
+ %\c!headstyle=,
+ %\c!marcolor=,
+ %\c!symcolor=,
+ %\c!headcolor=,
+ %\c!beforehead=,
+ \c!symcolor=\itemgroupparameter\c!color, % new per 2012.01.17
+ \c!symstyle=\itemgroupparameter\c!style, % new per 2012.01.17
+ \c!afterhead=\blank,
+ \c!before=\blank,
+ \c!inbetween=\blank,
+ \c!after=\blank,
+ %\c!stopper=.,
+ \c!placestopper=\v!yes,
+ \c!stopper=.,
+ %\c!inner=,
+ \c!n=2,
+ \c!items=4,
+ \c!levels=10,
+ \c!lefttext=(,
+ \c!righttext=),
+ \c!start=1,
+ \c!packcriterium=\zerocount,
+ \c!criterium=\v!all, % permits 0 and negative numbers
+ %\c!option=,
+ \c!textdistance=\v!space, % none big medium small <dimension>
+ \c!command=\strc_itemgroups_default_command,
+ \c!indenting=\v!next,
+ %\c!alignsymbol=v!no,
+ \c!symbol=\currentitemlevel,
+ \c!prefix=\v!no,
+ %\c!prefixstopper=.,
+ %\c!prefixseparatorset=,
+ %\c!prefixconversion=,
+ %\c!prefixconversionset=,
+ %\c!prefixset=,
+ %\c!prefixsegments=1:100,
+ \c!prefixconnector=.,
+ \c!numberseparatorset=,
+ \c!numberconversionset=,
+ \c!numberstopper=.,
+ \c!numbersegments=1]
+
+\defineitemgroup
+ [\v!itemize]
+
+%D This is really ugly I should get rid of the global mess, whuch is a side
+%D effect of the simple \type {\item} interface that we're stuck with for
+%D compatibility reasons. See footnotes for usage. It's probablynot robust
+%D for mixed itemgroups so in the end I need to get rid of the globals. One
+%D problem is that counters are set.
+
+\defineitemgroup
+ [\v!itemize:\v!note]
+
+\def\strc_itemgroups_push
+ {\edef\strc_itemgroups_pop
+ {\xdef\noexpand\currentitemlevel{\currentitemlevel}%
+ \global\c_strc_itemgroups_nesting \the\c_strc_itemgroups_nesting \relax
+ \global\c_strc_itemgroups_column_depth\the\c_strc_itemgroups_column_depth\relax}%
+ \global\c_strc_itemgroups_column_depth\zerocount
+ \global\c_strc_itemgroups_nesting \zerocount
+ \glet\currentitemlevel\!!zerocount
+ \unexpanded\def\startitemize{\startitemgroup[\v!itemize:\v!note]}%
+ \unexpanded\def\stopitemize {\stopitemgroup}}
+
+\let\strc_itemgroups_pop\relax
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/strc-itm.mkvi b/Master/texmf-dist/tex/context/base/mkiv/strc-itm.mkvi
index 0fc20432081..cbbefd5dbcc 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/strc-itm.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/strc-itm.mkvi
@@ -15,14 +15,14 @@
\registerctxluafile{strc-itm}{}
-%D As we analyze/register widths and such we could as well push and pop the
-%D numbers at the \LUA\ end (which saves a few calls).
-
-%D Cleaning up this module happened around the time when Kate Bush came up
-%D with the nicest numbered list of words: 50 Words For Snow. It's therefore
-%D no surprise that I had that cd running several times when updating this
-%D code. One of the highlights of 2011.
-
+%D As we analyze/register widths and such we could as well push and pop the numbers
+%D at the \LUA\ end (which saves a few calls).
+%D
+%D Cleaning up this module happened around the time when Kate Bush came up with the
+%D nicest numbered list of words: 50 Words For Snow. It's therefore no surprise that
+%D I had that cd running several times when updating this code. One of the
+%D highlights of 2011.
+%D
%D This module needs to be rewritten but that is tricky with respect to
%D compatibilitity. Basically each major variant (regular, text, columns,
%D horizontal, etc) needs to be on its own.
@@ -198,14 +198,15 @@
\newconditional\c_strc_itemgroups_txt
\newconditional\c_strc_itemgroups_extra
\newconditional\c_strc_itemgroups_repeat
+\newconditional\c_strc_itemgroups_inline_head
% 0 = before/after
% 1 = between unless before
% 2 = between
-\newconstant \c_strc_itemgroups_spacing_mode \c_strc_itemgroups_spacing_mode\plustwo
-\newconditional\c_strc_itemgroups_optimize \settrue\c_strc_itemgroups_optimize
-\newconditional\c_strc_itemgroups_auto_concat \settrue\c_strc_itemgroups_auto_concat
+\newconstant \c_strc_itemgroups_spacing_mode \c_strc_itemgroups_spacing_mode\plustwo
+\newconditional\c_strc_itemgroups_optimize \settrue\c_strc_itemgroups_optimize
+\newconditional\c_strc_itemgroups_auto_concat \settrue\c_strc_itemgroups_auto_concat
\newsignal \d_strc_itemgroups_signal
@@ -214,30 +215,28 @@
\newdimen \d_strc_itemgroups_list_width
\newdimen \d_strc_itemgroups_asked_width
-\newdimen \d_strc_itemgroups_max_width % multipass
-\newcount \c_strc_itemgroups_max_items % multipass
+\newdimen \d_strc_itemgroups_max_width % multipass
+\newcount \c_strc_itemgroups_max_items % multipass
\newcount \c_strc_itemgroups_n_of_items
\newcount \c_strc_itemgroups_nesting
\newcount \c_strc_itemgroups_column_depth
-\def \v_strc_itemgroups_counter {itemgroup:\currentparentitemgroup}
-
-\let \m_strc_itemgroups_repeat_start \empty
-\def \v_strc_itemgroups_unknown_symbol {?}
+\def \v_strc_itemgroups_counter {itemgroup:\currentparentitemgroup}
+\let \m_strc_itemgroups_repeat_start \empty
+\def \v_strc_itemgroups_unknown_symbol {?}
+\let \m_strc_itemgroups_indenting \empty
+\let \m_strc_itemgroups_destination \empty
-\let \m_strc_itemgroups_indenting \empty
-\let \m_strc_itemgroups_destination \empty
+\let \currentitemlevel \!!zerocount % public
+\def \currentnofitems {\the\c_strc_itemgroups_max_items}
+\def \currentitemnumber {\strc_counters_raw_sub\v_strc_itemgroups_counter\currentitemlevel} % public
-\let \currentitemlevel \!!zerocount % public
-\def \currentnofitems {\the\c_strc_itemgroups_max_items}
-\def \currentitemnumber {\strc_counters_raw_sub\v_strc_itemgroups_counter\currentitemlevel} % public
+\newtoks \itemgroupcommands % maybe public
-\newtoks \itemgroupcommands % maybe public
-
-\def \currentitemgroupsymbol {n} % here we cannot use a _ in the name
-\let \currentitemgroupconversionset \empty % here we cannot use a _ in the name
-\let \currentitemgroupsegments \empty
+\def \currentitemgroupsymbol {n} % here we cannot use a _ in the name
+\let \currentitemgroupconversionset \empty % here we cannot use a _ in the name
+\let \currentitemgroupsegments \empty
\def\strc_itemgroups_register_status
{\clf_registeritemgroup{\currentparentitemgroup}\c_strc_itemgroups_nesting\c_strc_itemgroups_n_of_items\dimexpr\itemgroupparameter\c!maxwidth\relax}
@@ -390,6 +389,11 @@
\unexpanded\def\strc_itemgroups_process_options#options%
{\processcommacommand[#options]\strc_itemgroups_process_option} % expansion of options is handy for xml
+% \installcommalistprocessorcommand \strc_itemgroups_process_option_list \strc_itemgroups_process_option
+%
+% \unexpanded\def\strc_itemgroups_process_options#options%
+% {\normalexpanded{\strc_itemgroups_process_option_list[#options]}} % expansion of options is handy for xml
+
\def\strc_itemgroups_process_option#option%
{\edef\itemgroupconstantvalue{#option}%
\ifx\itemgroupconstantvalue\empty\else
@@ -437,6 +441,7 @@
\setitemgroupparameter\c!width{0em}%
\fi} % signal
\setvalue{\??itemgroupkeyword\v!intext }{\settrue\c_strc_itemgroups_inline}
+\setvalue{\??itemgroupkeyword\v!headintext }{\settrue\c_strc_itemgroups_inline_head}
\setvalue{\??itemgroupkeyword\v!loose }{\setfalse\c_strc_itemgroups_optimize}
\setvalue{\??itemgroupkeyword\v!fit }{\settrue\c_strc_itemgroups_fitting}
\setvalue{\??itemgroupkeyword\v!nofit }{\setfalse\c_strc_itemgroups_fitting}
@@ -462,26 +467,17 @@
\setvalue{\??itemgroupkeyword\v!seven }{\letitemgroupparameter\c!n\plusseven}
\setvalue{\??itemgroupkeyword\v!eight }{\letitemgroupparameter\c!n\pluseight}
\setvalue{\??itemgroupkeyword\v!nine }{\letitemgroupparameter\c!n\plusnine}
-%setvalue{\??itemgroupkeyword\v!standard }{\setupcurrentitemgroup
-% [\c!width =1.5\emwidth,%
-% \c!distance =.5\emwidth,%
-% \c!factor =0,%
-% \c!inner =,%
-% \c!beforehead=,%
-% \c!afterhead =\blank,%
-% \c!before =\blank,%
-% \c!inbetween =\blank,%
-% \c!after =\blank]}
-\setvalue{\??itemgroupkeyword\v!standard }{\setitemgroupparameter\c!width {1.5\emwidth}%
- \setitemgroupparameter\c!distance {.5\emwidth}%
- \letitemgroupparameter\c!factor \!!zerocount
- \letitemgroupparameter\c!inner \empty
- \letitemgroupparameter\c!beforehead\empty
- \letitemgroupparameter\c!afterhead \blank
- \letitemgroupparameter\c!before \blank
- \letitemgroupparameter\c!inbetween \blank
- \letitemgroupparameter\c!after \blank}
-
+\setvalue{\??itemgroupkeyword\v!standard }{\setitemgroupparameter\c!width {1.5\emwidth}%
+ \setitemgroupparameter\c!distance {.5\emwidth}%
+ %\letitemgroupparameter\c!factor \!!zerocount
+ \letitemgroupparameter\c!factor {\zerocount}%
+ \setitemgroupparameter\c!packcriterium{\zerocount}%
+ \letitemgroupparameter\c!inner \empty
+ \letitemgroupparameter\c!beforehead \empty
+ \letitemgroupparameter\c!afterhead \blank
+ \letitemgroupparameter\c!before \blank
+ \letitemgroupparameter\c!inbetween \blank
+ \letitemgroupparameter\c!after \blank}
\def\strc_itemgroups_initialize_local
{\setfalse\c_strc_itemgroups_inline
@@ -506,9 +502,9 @@
\setfalse\c_strc_itemgroups_columns
% to be checked
\let\m_strc_itemgroups_destination\empty
- \let\strc_itemgroups_used_symbol\empty % ** start value
+ \let\strc_itemgroups_used_symbol \empty % ** start value
\let\strc_itemgroups_margin_symbol\empty
- \let\strc_itemgroups_extra_symbol\empty
+ \let\strc_itemgroups_extra_symbol \empty
%
\global\letitemgroupparameter\c!maxwidth\!!zeropoint
}
@@ -526,6 +522,11 @@
\def\strc_itemgroups_preset_stage_one#options%
{\processcommacommand[#options]\strc_itemgroups_preset_stage_one_indeed}
+% \installcommalistprocessorcommand \strc_itemgroups_preset_stage_one_list \strc_itemgroups_preset_stage_one_indeed
+%
+% \def\strc_itemgroups_preset_stage_one#options%
+% {\normalexpanded{\strc_itemgroups_preset_stage_one_list[#options]}}
+
\def\strc_itemgroups_preset_stage_one_indeed#option%
{\ifcsname\??itemgroupfirst#option\endcsname
\lastnamedcs
@@ -625,10 +626,17 @@
% can be made a bit faster
+% \def\strc_itemgroups_setup_each#category#whatever%
+% {\doifelseassignment{#whatever}
+% {\strc_itemgroups_normal_setup[#category][#whatever]}
+% {\strc_itemgroups_normal_setup[#category][\c!option={#whatever}]}}
+
\def\strc_itemgroups_setup_each#category#whatever%
- {\doifelseassignment{#whatever}
- {\strc_itemgroups_normal_setup[#category][#whatever]}
- {\strc_itemgroups_normal_setup[#category][\c!option={#whatever}]}}
+ {\ifcondition\validassignment{#whatever}%
+ \strc_itemgroups_normal_setup[#category][#whatever]%
+ \else
+ \strc_itemgroups_normal_setup[#category][\c!option={#whatever}]%
+ \fi}
\def\strc_itemgroups_setup_list_level_a#category#whatever#level%
{\strc_itemgroups_normal_setup[#category:#level][#whatever]}
@@ -636,10 +644,17 @@
\def\strc_itemgroups_setup_list_level_b#category#whatever#level%
{\strc_itemgroups_normal_setup[#category:#level][\c!option={#whatever}]}
+% \def\strc_itemgroups_setup_list#subcategories#category#whatever%
+% {\doifelseassignment{#whatever}
+% {\processcommalist[#subcategories]{\strc_itemgroups_setup_list_level_a{#category}{#whatever}}}
+% {\processcommalist[#subcategories]{\strc_itemgroups_setup_list_level_b{#category}{#whatever}}}}
+
\def\strc_itemgroups_setup_list#subcategories#category#whatever%
- {\doifelseassignment{#whatever}
- {\processcommalist[#subcategories]{\strc_itemgroups_setup_list_level_a{#category}{#whatever}}}
- {\processcommalist[#subcategories]{\strc_itemgroups_setup_list_level_b{#category}{#whatever}}}}
+ {\ifcondition\validassignment{#whatever}%
+ \processcommalist[#subcategories]{\strc_itemgroups_setup_list_level_a{#category}{#whatever}}%
+ \else
+ \processcommalist[#subcategories]{\strc_itemgroups_setup_list_level_b{#category}{#whatever}}%
+ \fi}
\def\strc_itemgroups_increment_item_counter
{\ifconditional\c_strc_itemgroups_sub \else
@@ -762,7 +777,7 @@
\d_strc_itemgroups_list_width\d_strc_itemgroups_max_width
\else\ifnum\itemgroupparameter\c!factor>\zerocount
\d_strc_itemgroups_list_width\itemgroupparameter\c!step\relax
- \ifdim\d_strc_itemgroups_list_width=\zeropoint \d_strc_itemgroups_list_width=.5em\fi
+ \ifzeropt\d_strc_itemgroups_list_width \d_strc_itemgroups_list_width=.5em\fi
\multiply\d_strc_itemgroups_list_width \itemgroupparameter\c!factor
\advance\d_strc_itemgroups_list_width\itemgroupparameter\c!width\relax
\else
@@ -786,9 +801,11 @@
\ifthirdargument
\strc_itemgroups_start_indeed[#options][#settings]%
\else\ifsecondargument
- \doifelseassignment{#options}
- {\strc_itemgroups_start_indeed[][#options]}
- {\strc_itemgroups_start_indeed[#options][]}%
+ \ifcondition\validassignment{#options}%
+ \strc_itemgroups_start_indeed[][#options]%
+ \else
+ \strc_itemgroups_start_indeed[#options][]%
+ \fi
\else
\strc_itemgroups_start_indeed[][]%
\fi\fi}
@@ -856,11 +873,21 @@
\fi
\fi
%
+ \ifconditional\c_strc_itemgroups_pack
+ \ifnum\currentnofitems>\itemgroupparameter\c!packcriterium\relax\else
+ \setfalse\c_strc_itemgroups_pack
+ \fi
+ \fi
+ %
\ifnum\c_strc_itemgroups_nesting=\plusone % NIEUW
\doadaptleftskip {\itemgroupparameter\c!margin}%
\doadaptleftskip {\itemgroupparameter\c!leftmargin}%
\doadaptrightskip{\itemgroupparameter\c!rightmargin}%
\fi
+ %
+ \doadaptleftskip {\itemgroupparameter\c!leftmargindistance}%
+ \doadaptrightskip{\itemgroupparameter\c!rightmargindistance}%
+ %
\usealignparameter\itemgroupparameter
\edef\m_strc_itemgroups_indenting{\itemgroupparameter\c!indenting}%
\ifnum\c_strc_itemgroups_nesting>\zerocount
@@ -1183,19 +1210,25 @@
\unexpanded\def\strc_itemgroups_stop_head_indeed
{\removeunwantedspaces
\dostoptagged
- \ifconditional\c_strc_itemgroups_text
- \space
- \ignorespaces
+ \ifconditional\c_strc_itemgroups_inline_head
+ \space
+ \ignorespaces
\else
- \par
- \fi
- \strc_itemgroups_insert_breakno
- \ifconditional\c_strc_itemgroups_pack\else\strc_itemgroups_after_head_command\fi
- \strc_itemgroups_insert_breakno}
+ \ifconditional\c_strc_itemgroups_text
+ \space
+ \ignorespaces
+ \else
+ \par
+ \fi
+ \strc_itemgroups_insert_breakno
+ \ifconditional\c_strc_itemgroups_pack\else\strc_itemgroups_after_head_command\fi
+ \strc_itemgroups_insert_breakno
+ \fi}
\unexpanded\def\strc_itemgroups_head_body_indeed
{\dostarttagged\t!itembody\empty
- \noindentation}
+ \noindentation
+ \ignorespaces}
% Simple commands.
@@ -1469,7 +1502,7 @@
\ifdim\d_strc_itemgroups_asked_width<\zeropoint\relax
\strc_itemgroups_handle_lapped_item_negative
\else
- \ifdim\d_strc_itemgroups_asked_width=\zeropoint\relax
+ \ifzeropt\d_strc_itemgroups_asked_width
\strc_itemgroups_calculate_list_width\plusone
\else
\strc_itemgroups_calculate_list_width\c_strc_itemgroups_nesting
@@ -1763,6 +1796,8 @@
[\c!margin=\zeropoint,
\c!leftmargin=\zeropoint,
\c!rightmargin=\zeropoint,
+ \c!leftmargindistance=\zeropoint,
+ \c!rightmargindistance=\zeropoint,
\c!indentnext=\v!yes,
\c!width=1.5\emwidth,
\c!factor=0,
@@ -1797,6 +1832,7 @@
\c!lefttext=(,
\c!righttext=),
\c!start=1,
+ \c!packcriterium=\zerocount,
\c!criterium=\v!all, % permits 0 and negative numbers
%\c!option=,
\c!textdistance=\v!space, % none big medium small <dimension>
@@ -1820,4 +1856,26 @@
\defineitemgroup
[\v!itemize]
+%D This is really ugly I should get rid of the global mess, whuch is a side
+%D effect of the simple \type {\item} interface that we're stuck with for
+%D compatibility reasons. See footnotes for usage. It's probablynot robust
+%D for mixed itemgroups so in the end I need to get rid of the globals. One
+%D problem is that counters are set.
+
+\defineitemgroup
+ [\v!itemize:\v!note]
+
+\def\strc_itemgroups_push
+ {\edef\strc_itemgroups_pop
+ {\xdef\noexpand\currentitemlevel{\currentitemlevel}%
+ \global\c_strc_itemgroups_nesting \the\c_strc_itemgroups_nesting \relax
+ \global\c_strc_itemgroups_column_depth\the\c_strc_itemgroups_column_depth\relax}%
+ \global\c_strc_itemgroups_column_depth\zerocount
+ \global\c_strc_itemgroups_nesting \zerocount
+ \glet\currentitemlevel\!!zerocount
+ \unexpanded\def\startitemize{\startitemgroup[\v!itemize:\v!note]}%
+ \unexpanded\def\stopitemize {\stopitemgroup}}
+
+\let\strc_itemgroups_pop\relax
+
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/strc-lnt.mkvi b/Master/texmf-dist/tex/context/base/mkiv/strc-lnt.mkvi
index 4a6f142458e..ad8c80d93e6 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/strc-lnt.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/strc-lnt.mkvi
@@ -160,13 +160,6 @@
% compress=yes|no
% compressmethod=separator|stopper
-\def\c!compressdistance{compressdistance}
-\def\c!compressmethod {compressmethod}
-\def\c!compressstopper {compressstopper} % c
-\def\v!compressstopper {compressstopper} % v
-
-\def\v!separator {separator} % v
-
\setvalue{\??linenotescompressmethod\v!separator}%
{\edef\p_compressseparator{\noteparameter\c!compressseparator}%
\scratchskip\noteparameter\c!compressdistance\relax
diff --git a/Master/texmf-dist/tex/context/base/mkiv/strc-lst.mkvi b/Master/texmf-dist/tex/context/base/mkiv/strc-lst.mkvi
index 7bc859b670b..d29b1f6fdae 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/strc-lst.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/strc-lst.mkvi
@@ -1117,7 +1117,7 @@
\hangindent\dimexpr\wd\b_strc_lists_number+\scratchdistance\relax
\hangafter\ifx\p_hang\v!no\zerocount\else\plusone\fi
\scratchdimen\listalternativeparameter\c!distance\relax
- \ifdim\wd\b_strc_lists_page=\zeropoint \else\ifdim\scratchdimen>\zeropoint\relax
+ \ifzeropt\wd\b_strc_lists_page \else \ifdim\scratchdimen>\zeropoint\relax
\rightskip\scratchdimen\!!plus\listalternativeparameter\c!stretch\relax
\parfillskip-\rightskip
\fi \fi
@@ -1144,7 +1144,7 @@
\strc_lists_limitated_text\currentlistentrytitle
\endstrut
\endgroup
- \ifdim\wd\b_strc_lists_page=\zeropoint\else
+ \ifzeropt\wd\b_strc_lists_page\else
\nobreak
\currentlistfiller
\box\b_strc_lists_page
@@ -1381,7 +1381,7 @@
\leftskip\scratchoffset
\else
\scratchwidth\p_width
- \ifdim\scratchoffset=\zeropoint
+ \ifzeropt\scratchoffset
\leftskip\dimexpr\scratchwidth+\scratchdistance\relax
\else
\leftskip\scratchoffset
diff --git a/Master/texmf-dist/tex/context/base/mkiv/strc-mar.lua b/Master/texmf-dist/tex/context/base/mkiv/strc-mar.lua
index 0221b9b8f19..b5fd2667b1a 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/strc-mar.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/strc-mar.lua
@@ -45,9 +45,9 @@ local texsetattribute = tex.setattribute
local a_marks = attributes.private("structure","marks")
-local trace_marks_set = false trackers.register("marks.set", function(v) trace_marks_set = v end)
-local trace_marks_get = false trackers.register("marks.get", function(v) trace_marks_get = v end)
-local trace_marks_all = false trackers.register("marks.detail", function(v) trace_marks_all = v end)
+local trace_set = false trackers.register("marks.set", function(v) trace_set = v end)
+local trace_get = false trackers.register("marks.get", function(v) trace_get = v end)
+local trace_details = false trackers.register("marks.details", function(v) trace_details = v end)
local report_marks = logs.reporter("structure","marks")
@@ -100,7 +100,7 @@ local ranges = {
local function resolve(t,k)
if k then
- if trace_marks_set or trace_marks_get then
+ if trace_set or trace_get then
report_marks("undefined mark, name %a",k)
end
local crap = { autodefined = true } -- maybe set = 0 and reset = 0
@@ -162,7 +162,7 @@ function marks.synchronize(class,n,option)
if box then
local first, last = sweep(getlist(box),0,0)
if option == v_keep and first == 0 and last == 0 then
- if trace_marks_get or trace_marks_set then
+ if trace_get or trace_set then
report_marks("action %a, class %a, box %a","retain at synchronize",class,n)
end
-- todo: check if still valid firts/last in range
@@ -184,12 +184,12 @@ function marks.synchronize(class,n,option)
}
ranges[class] = range
end
- if trace_marks_get or trace_marks_set then
+ if trace_get or trace_set then
report_marks("action %a, class %a, first %a, last %a","synchronize",class,range.first,range.last)
end
end
end
- elseif trace_marks_get or trace_marks_set then
+ elseif trace_get or trace_set then
report_marks("action %s, class %a, box %a","synchronize without content",class,n)
end
end
@@ -262,7 +262,7 @@ function marks.relate(name,chain)
end
children[#children+1] = name
end
- elseif trace_marks_set then
+ elseif trace_set then
report_marks("error: invalid relation, name %a, chain %a",name,chain)
end
end
@@ -276,7 +276,7 @@ local function resetchildren(new,name)
for i=1,#children do
local ci = children[i]
new[ci] = false
- if trace_marks_set then
+ if trace_set then
report_marks("action %a, parent %a, child %a","reset",name,ci)
end
resetchildren(new,ci)
@@ -316,7 +316,7 @@ function marks.set(name,value)
new[name] = value
topofstack = topofstack + 1
stack[topofstack] = new
- if trace_marks_set then
+ if trace_set then
if name == child then
report_marks("action %a, name %a, index %a, value %a","set",name,topofstack,value)
else
@@ -329,7 +329,7 @@ end
local function reset(name)
if v_all then
- if trace_marks_set then
+ if trace_set then
report_marks("action %a","reset all")
end
stack = { }
@@ -348,7 +348,7 @@ local function reset(name)
name = parent
dn = data[name]
end
- if trace_marks_set then
+ if trace_set then
report_marks("action %a, name %a, index %a","reset",name,topofstack)
end
dn.reset = topofstack
@@ -404,24 +404,24 @@ local function resolve(name,first,last,strict,quitonfalse,notrace)
else
step, method = 1, "top-down"
end
- if trace_marks_get and not notrace then
+ if trace_get and not notrace then
report_marks("action %a, strategy %a, name %a, parent %a, strict %a","request",method,child,parent,strict or false)
end
- if trace_marks_all and not notrace then
+ if trace_details and not notrace then
marks.show(first,last)
end
local r = dn.reset
local s = dn.set
if first <= last and first <= r then
- if trace_marks_get and not notrace then
+ if trace_get and not notrace then
report_marks("action %a, name %a, first %a, last %a, reset %a, index %a","reset first",name,first,last,r,first)
end
elseif first >= last and last <= r then
- if trace_marks_get and not notrace then
+ if trace_get and not notrace then
report_marks("action %a, name %a, first %a, last %a, reset %a, index %a","reset last",name,first,last,r,last)
end
elseif not stack[first] or not stack[last] then
- if trace_marks_get and not notrace then
+ if trace_get and not notrace then
-- a previous or next method can give an out of range, which is valid
report_marks("error: out of range, name %a, reset %a, index %a",name,r,first)
end
@@ -429,12 +429,12 @@ local function resolve(name,first,last,strict,quitonfalse,notrace)
local top = stack[first]
local fullchain = dn.fullchain
if not fullchain or #fullchain == 0 then
- if trace_marks_get and not notrace then
+ if trace_get and not notrace then
report_marks("warning: no full chain, trying again, name %a, first %a, last %a",name,first,last)
end
return resolve(name,first,last)
else
- if trace_marks_get and not notrace then
+ if trace_get and not notrace then
report_marks("found chain [ % => T ]",fullchain)
end
local chaindata = { }
@@ -444,7 +444,7 @@ local function resolve(name,first,last,strict,quitonfalse,notrace)
if data[cname].set > 0 then
local value = resolve(cname,first,last,false,false,true)
if value == "" then
- if trace_marks_get and not notrace then
+ if trace_get and not notrace then
report_marks("quitting chain, name %a, reset %a, start %a",name,r,first)
end
return ""
@@ -453,28 +453,28 @@ local function resolve(name,first,last,strict,quitonfalse,notrace)
end
end
end
- if trace_marks_get and not notrace then
+ if trace_get and not notrace then
report_marks("using chain [ % => T ]",chaindata)
end
local value, index, found = resolve(name,first,last,false,false,true)
if value ~= "" then
- if trace_marks_get and not notrace then
+ if trace_get and not notrace then
report_marks("following chain [ % => T ]",chaindata)
end
for i=1,chainlength do
local cname = fullchain[i]
if data[cname].set > 0 and chaindata[i] ~= found[cname] then
- if trace_marks_get and not notrace then
+ if trace_get and not notrace then
report_marks("quiting chain, name %a, reset %a, index %a",name,r,first)
end
return ""
end
end
- if trace_marks_get and not notrace then
+ if trace_get and not notrace then
report_marks("found in chain, name %a, reset %a, start %a, index %a, value %a",name,r,first,index,value)
end
return value, index, found
- elseif trace_marks_get and not notrace then
+ elseif trace_get and not notrace then
report_marks("not found, name %a, reset %a",name,r)
end
end
@@ -489,18 +489,18 @@ local function resolve(name,first,last,strict,quitonfalse,notrace)
return ""
end
elseif value == true then
- if trace_marks_get and not notrace then
+ if trace_get and not notrace then
report_marks("quitting steps, name %a, reset %a, start %a, index %a",name,r,first,i)
end
return ""
elseif value ~= "" then
- if trace_marks_get and not notrace then
+ if trace_get and not notrace then
report_marks("found in steps, name %a, reset %a, start %a, index %a, value %a",name,r,first,i,value)
end
return value, i, current
end
end
- if trace_marks_get and not notrace then
+ if trace_get and not notrace then
report_marks("not found in steps, name %a, reset %a",name,r)
end
end
@@ -516,7 +516,7 @@ local function doresolve(name,rangename,swap,df,dl,strict)
local range = ranges[rangename] or ranges[v_page]
local first = range.first
local last = range.last
- if trace_marks_get then
+ if trace_get then
report_marks("action %a, name %a, range %a, swap %a, first %a, last %a, df %a, dl %a, strict %a",
"resolving",name,rangename,swap or false,first,last,df,dl,strict or false)
end
@@ -550,12 +550,12 @@ methods[v_bottom_nocheck] = function(name,range) return doresolve(name,range,t
methods[v_next_nocheck] = function(name,range) return doresolve(name,range,true , 0,1,false) end
local function do_first(name,range,check)
- if trace_marks_get then
+ if trace_get then
report_marks("action %a, name %a, range %a","resolving first",name,range)
end
local f_value, f_index, f_found = doresolve(name,range,false,0,0,check)
if f_found then
- if trace_marks_get then
+ if trace_get then
report_marks("action %a, name %a, range %a","resolving last",name,range)
end
local l_value, l_index, l_found = doresolve(name,range,true ,0,0,check)
@@ -565,7 +565,7 @@ local function do_first(name,range,check)
local si = stack[i]
local sn = si[name]
if sn and sn ~= false and sn ~= true and sn ~= "" and sn ~= f_value then
- if trace_marks_get then
+ if trace_get then
report_marks("action %a, name %a, range %a, index %a, value %a","resolving",name,range,i,sn)
end
return sn, i, si
@@ -573,19 +573,19 @@ local function do_first(name,range,check)
end
end
end
- if trace_marks_get then
+ if trace_get then
report_marks("resolved, name %a, range %a, using first",name,range)
end
return f_value, f_index, f_found
end
local function do_last(name,range,check)
- if trace_marks_get then
+ if trace_get then
report_marks("action %a, name %a, range %a","resolving last",name,range)
end
local l_value, l_index, l_found = doresolve(name,range,true ,0,0,check)
if l_found then
- if trace_marks_get then
+ if trace_get then
report_marks("action %a, name %a, range %a","resolving first",name,range)
end
local f_value, f_index, f_found = doresolve(name,range,false,0,0,check)
@@ -595,7 +595,7 @@ local function do_last(name,range,check)
local si = stack[i]
local sn = si[name]
if sn and sn ~= false and sn ~= true and sn ~= "" and sn ~= l_value then
- if trace_marks_get then
+ if trace_get then
report_marks("action %a, name %a, range %a, index %a, value %a","resolving",name,range,i,sn)
end
return sn, i, si
@@ -603,7 +603,7 @@ local function do_last(name,range,check)
end
end
end
- if trace_marks_get then
+ if trace_get then
report_marks("resolved, name %a, range %a, using first",name,range)
end
return l_value, l_index, l_found
@@ -621,7 +621,7 @@ end
local function fetched(name,range,method)
local value = (methods[method] or methods[v_first])(name,range) or ""
- if not trace_marks_get then
+ if not trace_get then
-- no report
elseif value == "" then
report_marks("nothing fetched, name %a, range %a, method %a",name,range,method)
@@ -701,7 +701,7 @@ end
end
function marks.fetch(name,range,method) -- chapter page first | chapter column:1 first
- if trace_marks_get then
+ if trace_get then
report_marks("marking requested, name %a, range %a, method %a",name,range,method)
end
if method == "" or method == v_default then
diff --git a/Master/texmf-dist/tex/context/base/mkiv/strc-not.mkvi b/Master/texmf-dist/tex/context/base/mkiv/strc-not.mkvi
index 3ce01ef3454..05aa1eb6bbe 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/strc-not.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/strc-not.mkvi
@@ -120,7 +120,7 @@
\c!state=\v!start,
\c!levels=3]
-%D The code here is mostly the same as enumersations but we want to keep them
+%D The code here is mostly the same as enumerations but we want to keep them
%D isolated and at some point we might differentiate.
% \installcorenamespace{noteclass}
@@ -943,11 +943,22 @@
\letvalue{\??notepenalty\v!verystrict}\notepenaltyverystrict
\letvalue{\??notepenalty }\notepenaltytolerant
+% \def\strc_notes_set_width
+% {\edef\p_width{\noteparameter\c!width}%
+% \ifx\p_width\empty
+% \setnoteparameter\c!width{\hsize}%
+% \fi}
+
+\setupnotes
+ [\c!width=\v!auto]
+
\def\strc_notes_set_width
{\edef\p_width{\noteparameter\c!width}%
- \ifx\p_width\empty
+ \ifx\p_width\v!auto
+ \setnoteparameter\c!width{\ifdim\hsize<\makeupwidth\hsize\else\makeupwidth\fi}%
+ \else\ifx\p_width\empty
\setnoteparameter\c!width{\hsize}%
- \fi}
+ \fi\fi}
\appendtoks
\strc_notes_set_width
@@ -1388,6 +1399,11 @@
\pickupattributes
\to \everyinsidenoteinsert
+%D Nasty, the might be more:
+
+\appendtoks \strc_itemgroups_push \to \everybeforenoteinsert
+\appendtoks \strc_itemgroups_pop \to \everyafternoteinsert
+
% maybe but better use [scope=local] here
%
% \appendtoks
@@ -1458,7 +1474,7 @@
\c!strut=\v!no,
\c!offset=\v!overlay]%
\inheritednoteframed
- {\ifdim\dp\scratchbox=\zeropoint % this hack is needed because \vadjust
+ {\ifzeropt\dp\scratchbox % this hack is needed because \vadjust
\hpack{\lower\strutdp\box\scratchbox}% % in margin number placement
\else % hides the (always) present depth
\box\scratchbox
diff --git a/Master/texmf-dist/tex/context/base/mkiv/strc-pag.lua b/Master/texmf-dist/tex/context/base/mkiv/strc-pag.lua
index ee1b245b99b..9b3a77e741f 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/strc-pag.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/strc-pag.lua
@@ -45,10 +45,21 @@ pages.collected = collected
pages.tobesaved = tobesaved
pages.nofpages = 0
+-- utilitydata.structures.counters.collected.realpage[1]
+
local function initializer()
collected = pages.collected
tobesaved = pages.tobesaved
- pages.nofpages = #collected
+ -- tricky, with pageinjection we can have holes
+ -- pages.nofpages = #collected
+ -- pages.nofpages = table.count(collected) -- could be a helper
+ local n = 0
+ for k in next, collected do
+ if k > n then
+ n = k
+ end
+ end
+ pages.nofpages = n
end
job.register('structures.pages.collected', tobesaved, initializer)
@@ -172,18 +183,18 @@ function pages.analyze(entry,pagespecification)
if not sectiondata then
return pagedata, false, "no sectiondata"
end
- local no = variables.no
+ local v_no = variables.no
-- local preferences
- if pagespecification and pagespecification.prefix == no then
+ if pagespecification and pagespecification.prefix == v_no then
return pagedata, false, "current spec blocks prefix"
end
-- stored preferences
- -- if entry.prefix == no then
+ -- if entry.prefix == v_no then
-- return pagedata, false, "entry blocks prefix"
-- end
-- stored page state
pagespecification = pagedata.prefixdata
- if pagespecification and pagespecification.prefix == no then
+ if pagespecification and pagespecification.prefix == v_no then
return pagedata, false, "pagedata blocks prefix"
end
-- final verdict
@@ -258,11 +269,18 @@ function helpers.analyze(entry,specification)
return entry, sectiondata, "okay"
end
-function helpers.prefix(data,prefixspec)
+function helpers.prefix(data,prefixspec,nosuffix)
if data then
local _, prefixdata, status = helpers.analyze(data,prefixspec)
if prefixdata then
- sections.typesetnumber(prefixdata,"prefix",prefixspec or false,data.prefixdata or false,prefixdata or false)
+ if nosuffix and prefixspec then
+ local connector = prefixspec.connector
+ prefixspec.connector = nil
+ sections.typesetnumber(prefixdata,"prefix",prefixspec or false,data.prefixdata or false,prefixdata or false)
+ prefixspec.connector = connector
+ else
+ sections.typesetnumber(prefixdata,"prefix",prefixspec or false,data.prefixdata or false,prefixdata or false)
+ end
end
end
end
@@ -305,6 +323,11 @@ function pages.in_body(n)
return texgetcount("pagebodymode") > 0
end
+function pages.fraction(n)
+ local lastpage = texgetcount("lastpageno") -- can be cached
+ return lastpage > 1 and (texgetcount("realpageno")-1)/(lastpage-1) or 1
+end
+
-- move to strc-pag.lua
function counters.analyze(name,counterspecification)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/strc-ref.lua b/Master/texmf-dist/tex/context/base/mkiv/strc-ref.lua
index e01bacaac32..c85b3338a32 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/strc-ref.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/strc-ref.lua
@@ -427,7 +427,7 @@ end
local function synchronizepage(reference) -- non public helper
reference.realpage = texgetcount("realpageno")
- if jobpositions.used then
+ if jobpositions.used() then
reference.x, reference.y = getpos()
end
end
@@ -2603,15 +2603,52 @@ implement {
arguments = { "string", "boolean", "boolean" }
}
-local function referencerealpage()
+-- local function referencerealpage()
+-- local actions = references.currentset
+-- return not actions and 0 or actions.realpage or setreferencerealpage(actions)
+-- end
+--
+-- implement {
+-- name = "referencerealpage",
+-- actions = { referencerealpage, context },
+-- -- arguments = "string" -- hm, weird
+-- }
+
+implement {
+ name = "referencerealpage",
+ actions = function()
+ local actions = references.currentset
+ context(not actions and 0 or actions.realpage or setreferencerealpage(actions))
+ end
+}
+
+local function referencepos(key)
local actions = references.currentset
- return not actions and 0 or actions.realpage or setreferencerealpage(actions)
+ local i = actions[1].i -- brrr
+ local v = 0
+ if i then
+ local a = i.references
+ if a then
+ v = a[key] or 0
+ end
+ end
+ return v
end
+implement { name = "referenceposx", actions = function() context("%p",referencepos("x")) end }
+implement { name = "referenceposy", actions = function() context("%p",referencepos("y")) end }
+
+
implement {
- name = "referencerealpage",
- actions = { referencerealpage, context },
- arguments = "string"
+ name = "referencecolumn",
+ actions = function()
+ local actions = references.currentset
+ local column = 1
+ if actions then
+ column = jobpositions.columnofpos(actions.realpage or setreferencerealpage(actions),referencepos("x"))
+ end
+ context(column or 1)
+ end
}
local plist, nofrealpages
diff --git a/Master/texmf-dist/tex/context/base/mkiv/strc-ref.mkvi b/Master/texmf-dist/tex/context/base/mkiv/strc-ref.mkvi
index c7f20481592..e774117fa50 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/strc-ref.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/strc-ref.mkvi
@@ -1053,7 +1053,7 @@
\relax}
\def\referencepagedetail
- {\numexpr\clf_referencepagestate
+ {\numexpr\clf_referencepagedetail
{rst::\number\nofreferencestates}%
true %
\ifconditional\pagestatespread false\ifdoublesided true\else false\fi\fi
@@ -1062,6 +1062,24 @@
\def\referencerealpage
{\clf_referencerealpage}
+\def\referencecolumnnumber
+ {\clf_referencecolumn}
+
+% So we need : instead of \ but that's only lmtx:
+%
+% \def\referencecolumnnumber
+% {\numexpr\dimexpr\clf_referenceposx-\cutspace\relax:\dimexpr\makeupwidth/\nofcolumns\relax+\plusone\relax}
+%
+% Tacos patch of the older one, kept here as illustration
+%
+% \def\referencecolumnnumber
+% {\numexpr
+% \dimexpr\clf_referenceposx-\cutspace-\makeupwidth/(2*\nofcolumns)\relax
+% /\dimexpr \makeupwidth/ \nofcolumns \relax
+% +\plusone
+% \relax}
+
+
\unexpanded\def\tracedpagestate
{{\blue\tttf(\ifcase\referencepagedetail unknown\or same\or previous\or next\or above\or below\else unknown\fi)}}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/strc-reg.lua b/Master/texmf-dist/tex/context/base/mkiv/strc-reg.lua
index 47ba1c5338b..6873f89eb72 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/strc-reg.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/strc-reg.lua
@@ -6,7 +6,7 @@ if not modules then modules = { } end modules ['strc-reg'] = {
license = "see context related readme files"
}
-local next, type, tonumber = next, type, tonumber
+local next, type, tonumber, rawget = next, type, tonumber, rawget
local char, format, gmatch = string.char, string.format, string.gmatch
local equal, concat, remove = table.are_equal, table.concat, table.remove
local lpegmatch, P, C, Ct = lpeg.match, lpeg.P, lpeg.C, lpeg.Ct
@@ -46,6 +46,7 @@ local v_previous = variables.previous
local v_first = variables.first
local v_last = variables.last
local v_text = variables.text
+local v_section = variables.section
local context = context
local ctx_latelua = context.latelua
@@ -69,6 +70,7 @@ local absmaxlevel = 5 -- \c_strc_registers_maxlevel
local h_prefixpage = helpers.prefixpage
local h_prefixlastpage = helpers.prefixlastpage
local h_title = helpers.title
+local h_prefix = helpers.prefix
local ctx_startregisteroutput = context.startregisteroutput
local ctx_stopregisteroutput = context.stopregisteroutput
@@ -87,7 +89,7 @@ local ctx_registerentry = context.registerentry
local ctx_registerseeword = context.registerseeword
local ctx_registerpagerange = context.registerpagerange
local ctx_registeronepage = context.registeronepage
-
+local ctx_registersection = context.registersection
local ctx_registerpacked = context.registerpacked
-- possible export, but ugly code (overloads)
@@ -719,14 +721,30 @@ function registers.compare(a,b)
local ka = a.metadata.kind
local kb = b.metadata.kind
if ka == kb then
- local page_a = a.references.realpage
- local page_b = b.references.realpage
- if not page_a or not page_b then
+ local ra = a.references
+ local rb = b.references
+ local pa = ra.realpage
+ local pb = rb.realpage
+ if not pa or not pb then
return 0
- elseif page_a < page_b then
+ elseif pa < pb then
return -1
- elseif page_a > page_b then
+ elseif pa > pb then
return 1
+ else
+ -- new, we need to pick the right one of multiple and
+ -- we want to prevent oscillation in the tuc file so:
+ local ia = ra.internal
+ local ib = rb.internal
+ if not ia or not ib then
+ return 0
+ elseif ia < ib then
+ return -1
+ elseif ia > ib then
+ return 1
+ else
+ return 0
+ end
end
elseif ka == "see" then
return 1
@@ -745,6 +763,8 @@ local seeindex = 0
-- meerdere loops, seewords, dan words, anders seewords
+-- todo: split seeword
+
local function crosslinkseewords(result,check) -- all words
-- collect all seewords
local seewords = { }
@@ -762,23 +782,68 @@ local function crosslinkseewords(result,check) -- all words
end
end
end
+
-- mark seeparents
+
+ -- local seeparents = { }
+ -- for i=1,#result do
+ -- local data = result[i]
+ -- local word = data.list[1]
+ -- local okay = word and word[1]
+ -- if okay then
+ -- local seeindex = seewords[okay]
+ -- if seeindex then
+ -- seeparents[okay] = data
+ -- data.references.seeparent = seeindex
+ -- if trace_registers then
+ -- report_registers("see parent %03i: %s",seeindex,okay)
+ -- end
+ -- end
+ -- end
+ -- end
+
+ local entries = { }
+ local keywords = { }
local seeparents = { }
for i=1,#result do
local data = result[i]
- local word = data.list[1]
- word = word and word[1]
- if word then
- local seeindex = seewords[word]
+ local word = data.list
+ local size = #word
+ if data.seeword then
+ -- beware: a seeword has an extra entry for sorting purposes
+ size = size - 1
+ end
+ for i=1,size do
+ local w = word[i]
+ local e = w[1]
+ local k = w[2] or e
+ entries [i] = e
+ keywords[i] = k
+ end
+ -- first try the keys
+ local okay, seeindex
+ for n=size,1,-1 do
+ okay = concat(keywords,"+",1,n)
+ seeindex = seewords[okay]
+ -- first try the entries
if seeindex then
- seeparents[word] = data
- data.references.seeparent = seeindex
- if trace_registers then
- report_registers("see parent %03i: %s",seeindex,word)
- end
+ break
+ end
+ okay = concat(entries,"+",1,n)
+ seeindex = seewords[okay]
+ if seeindex then
+ break
+ end
+ end
+ if seeindex then
+ seeparents[okay] = data
+ data.references.seeparent = seeindex
+ if trace_registers then
+ report_registers("see parent %03i: %s",seeindex,okay)
end
end
end
+
-- mark seewords and extend sort list
for i=1,#result do
local data = result[i]
@@ -869,6 +934,7 @@ function registers.unique(data,options)
local nofresult = 0
local prev = nil
local dataresult = data.result
+ local bysection = options.pagemethod == v_section -- normally page
for k=1,#dataresult do
local v = dataresult[k]
if prev then
@@ -876,6 +942,9 @@ function registers.unique(data,options)
local pr = prev.references
if not equal(prev.list,v.list) then
-- ok
+ elseif bysection and vr.section == pr.section then
+ v = nil
+ -- ok
elseif pr.realpage ~= vr.realpage then
-- ok
else
@@ -1139,6 +1208,7 @@ function registers.flush(data,options,prefixspec,pagespec)
local collapse_ranges = compress == v_all
local collapse_packed = compress == v_packed
local show_page_number = options.pagenumber ~= false -- true or false
+ local bysection = options.pagemethod == v_section
local result = data.result
local maxlevel = 0
--
@@ -1389,14 +1459,61 @@ function registers.flush(data,options,prefixspec,pagespec)
local seetext = seeword.text or ""
local processor = seeword.processor or (entry.processors and entry.processors[1]) or ""
local seeindex = entry.references.seeindex or ""
- ctx_registerseeword(metadata.name or "",i,nt,processor,0,seeindex,function() h_title(seetext,metadata) end)
+ ctx_registerseeword(
+ metadata.name or "",
+ i,
+ nt,
+ processor,
+ 0,
+ seeindex,
+ function() h_title(seetext,metadata) end
+ )
+ end
+ end
+
+ local function case_5()
+ local first = d
+ while true do
+ if d == #data then
+ break
+ else
+ d = d + 1
+ local next = data[d]
+ if next.metadata.kind == "see" or not equal(entry.list,next.list) then
+ d = d - 1
+ break
+ else
+ entry = next
+ end
+ end
+ end
+ local last = d
+ local n = last - first + 1
+ local i = 0
+ local name = metadata.name or ""
+ local processor = entry.processors and entry.processors[1] or ""
+ for e=first,last do
+ local d = data[e]
+ local sectionindex = d.references.internal or 0
+ i = i + 1
+ ctx_registersection(
+ name,
+ i,
+ n,
+ processor,
+ 0,
+ sectionindex,
+ function() h_prefix(d,prefixspec,true) end
+ )
end
end
if kind == "entry" then
if show_page_number then
ctx_startregisterpages()
- if collapse_singles or collapse_ranges then
+ if bysection then
+ case_5()
+ elseif collapse_singles or collapse_ranges then
case_1()
elseif collapse_packed then
case_2()
@@ -1454,6 +1571,7 @@ implement {
{ "compress" },
{ "criterium" },
{ "check" },
+ { "pagemethod" },
{ "pagenumber", "boolean" },
},
{
diff --git a/Master/texmf-dist/tex/context/base/mkiv/strc-reg.mkiv b/Master/texmf-dist/tex/context/base/mkiv/strc-reg.mkiv
index 559e1bd4231..e955c700ba7 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/strc-reg.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/strc-reg.mkiv
@@ -425,7 +425,12 @@
\def\strc_registers_finish_entry_indeed#1#2#3% register data userdata
{\begingroup
\edef\currentregister{#1}%
- \setupcurrentregister[\c!entries=,\c!label=,\c!keys=,\c!alternative=,#2]% todo: fast setter
+ %\setupcurrentregister[\c!entries=,\c!label=,\c!keys=,\c!alternative=,#2]% todo: fast setter
+ \resetregisterparameter\c!entries
+ \resetregisterparameter\c!label
+ \resetregisterparameter\c!keys
+ \resetregisterparameter\c!alternative
+ \setupcurrentregister[#2]%
\edef\currentregisterlabel {\registerparameter\c!label}%
\edef\currentregisterexpansion{\registerparameter\c!expansion}%
\edef\currentregisterownnumber{\registerparameter\c!ownnumber}%
@@ -628,13 +633,14 @@
\clf_processregister
{#1}%
{%
- language {\registerparameter\s!language}%
- method {\registerparameter\c!method}%
- numberorder {\registerparameter\c!numberorder}%
- check {\registerparameter\c!check}%
- compress {\registerparameter\c!compress}%
- criterium {\registerparameter\c!criterium}%
- pagenumber \ifx\registerpageseparatorsymbol\empty false\else true\fi
+ language {\registerparameter\s!language}%
+ method {\registerparameter\c!method}%
+ numberorder {\registerparameter\c!numberorder}%
+ check {\registerparameter\c!check}%
+ compress {\registerparameter\c!compress}%
+ criterium {\registerparameter\c!criterium}%
+ pagemethod {\registerparameter\c!pagemethod}%
+ pagenumber \ifx\registerpageseparatorsymbol\empty false\else true\fi
}{%
separatorset {\registerparameter\c!pageprefixseparatorset}%
conversionset {\registerparameter\c!pageprefixconversionset}%
@@ -939,6 +945,18 @@
\fi
\popcurrentregister}
+\newconditional\c_strc_registers_following
+
+\appendtoks
+ \edef\p_compress{\registerparameter\c!compress}%
+ \ifx\p_compress\v!text
+ \settrue\c_strc_registers_following
+ \letregisterparameter\c!compress\v!yes
+ \else
+ \setfalse\c_strc_registers_following
+ \fi
+\to \everyplaceregister
+
\unexpanded\def\registerpagerange#1#2#3#4#5#6#7#8% #1:class #2:processor content, content todo: -- configurable
{\pushcurrentregister{#1}%
\edef\p_pagenumber{\registerparameter\c!pagenumber}%
@@ -949,9 +967,17 @@
\dostarttagged\t!registerfrompage\empty
\withregisterpagecommand{#2}{#3}{#4}{#5}%
\dostoptagged
- \registeronepagerangeseparator
- \dostarttagged\t!registertopage\empty
- \withregisterpagecommand{#2}{#6}{#7}{#8}%
+ \ifconditional\c_strc_registers_following
+ \ifnum#3=\numexpr#6-1\relax
+ \labeltext{following:\s!singular}%
+ \else
+ \labeltext{following:\s!plural}%
+ \fi
+ \else
+ \registeronepagerangeseparator
+ \dostarttagged\t!registertopage\empty
+ \withregisterpagecommand{#2}{#6}{#7}{#8}%
+ \fi
\dostoptagged
\dostoptagged
\fi
@@ -1015,10 +1041,66 @@
\dostoptagged
\popcurrentregister}
+\unexpanded\def\doapplyregistersectioncommand#1#2%
+ {\ifx\currentregistersectionindex\empty
+ \applyprocessor{#1}{#2}%
+ \else\iflocation
+ \strc_references_goto_internal{\applyprocessor{#1}{#2}}[sectionindex:\currentregistersectionindex]%
+ \else
+ \applyprocessor{#1}{#2}%
+ \fi\fi}
+
+\unexpanded\def\defaultregistersection#1#2#3#4#5#6#7% class i n #4:processor #5:internal #6:sectionindex #7:word
+ {\pushcurrentregister{#1}%
+ \ifnum#2=\plusone
+ \registerpageseparator
+ \fi
+ \global\setconstant\c_strc_registers_page_state\plustwo
+ \def\currentregisterpageindex{#5}%
+ \dostarttagged\t!registersection\empty
+ \settrue\c_strc_registers_page_done
+ \iflocation
+ \def\currentregistersectionindex{#6}%
+ \else
+ \let\currentregistersectionindex\empty
+ \fi
+ \ifnum#2=\plusone\else
+ ,\space
+ \fi
+ \doapplyregistersectioncommand{#4}{#7}%
+ \dostoptagged
+ \popcurrentregister}
+
+\let\registersection \defaultregistersection
\let\registerseeword \defaultregisterseeword
\let\registerentry \defaultregisterentry
\let\registercharacter\defaultregistercharacter
+%D Experimental:
+%D
+%D \starttyping
+%D \setupregister
+%D [index]
+%D [pagesegments=1:4,
+%D pagemethod=section]
+%D
+%D \starttext
+%D
+%D \chapter {one} \section {alpha}
+%D
+%D x\index {whatever 1}x\index {whatever 2}x\index {whatever 2}x \page
+%D x\index {whatever 1}x\index {whatever 2}x\index {whatever 2}x \page
+%D
+%D \chapter {one} \section {alpha}
+%D
+%D x\index {whatever 1}x\index {whatever 2}x\index {whatever 2}x \page
+%D x\index {whatever 1}x\index {whatever 2}x\index {whatever 2}x \page
+%D
+%D \placeindex[n=1]
+%D
+%D \stoptext
+%D \stoptyping
+
%D A few specific rendering variants:
% \def\doregisterpagelocation#1#2%
diff --git a/Master/texmf-dist/tex/context/base/mkiv/strc-ren.mkiv b/Master/texmf-dist/tex/context/base/mkiv/strc-ren.mkiv
index 5cdf5f4a711..59f3a9256ee 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/strc-ren.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/strc-ren.mkiv
@@ -261,7 +261,7 @@
\d_strc_rendering_hang_height\htdp\b_strc_rendering_head
\getnoflines\d_strc_rendering_hang_height
\normalexpanded{\endgroup\n_strc_rendering_hang_lines\the\numexpr\noflines-\plusone\relax}% brrr
- \setbox\b_strc_rendering_head\hbox{\lower\n_strc_rendering_hang_lines\d_strc_rendering_hang_height\box\b_strc_rendering_head}%
+ \setbox\b_strc_rendering_head\hpack{\lower\n_strc_rendering_hang_lines\d_strc_rendering_hang_height\box\b_strc_rendering_head}%
\d_strc_rendering_hang_height\dimexpr\htdp\b_strc_rendering_head-\d_strc_rendering_local_height+\strutdp\relax
\ht\b_strc_rendering_head\strutht
\dp\b_strc_rendering_head\strutdp
@@ -599,24 +599,24 @@
\vbox {
\headsetupspacing
\ifconditional\headshownumber
- \ifdim\headwidth=\zeropoint \else
- \ifdim\headnumberwidth=\zeropoint
- \ifdim\headtextwidth=\zeropoint \else
+ \ifzeropt\headwidth \else
+ \ifzeropt\headnumberwidth
+ \ifzeropt\headtextwidth \else
\headnumberwidth\dimexpr\headwidth-\headtextwidth\relax
\fi
\else
- \ifdim\headtextwidth=\zeropoint
+ \ifzeropt\headtextwidth
\headtextwidth\dimexpr\headwidth-\headnumberwidth\relax
\fi
\fi
\hsize\headwidth
\fi
- \ifdim\headnumberwidth=\zeropoint\else
+ \ifzeropt\headnumberwidth \else
\headnumberdistance\zeropoint
\fi
- \setbox\scratchbox\hbox \ifdim\headnumberwidth=\zeropoint\else to \headnumberwidth\fi{\headnumbercontent}
+ \setbox\scratchbox\hbox \ifzeropt\headnumberwidth\else to \headnumberwidth\fi{\headnumbercontent}
\scratchdimen\dimexpr\wd\scratchbox+\headnumberdistance\relax
- \ifdim\headtextwidth=\zeropoint\else
+ \ifzeropt\headtextwidth \else
\hsize\dimexpr\scratchdimen+\headtextwidth\relax
\fi
\hangindent\scratchdimen
@@ -625,8 +625,8 @@
\box\scratchbox
\hskip\headnumberdistance
\else
- \ifdim\headtextwidth=\zeropoint
- \ifdim\headwidth=\zeropoint \else
+ \ifzeropt\headtextwidth
+ \ifzeropt\headwidth \else
\hsize\headwidth
\fi
\else
@@ -795,7 +795,7 @@
\advance\hsize-\wd\scratchboxone\relax
\headtextcontent
}
- \hbox {
+ \hpack {
\box\scratchboxone
\hskip\headnumberdistance
\box\scratchboxtwo
@@ -824,7 +824,7 @@
\advance\hsize-\wd\scratchboxone\relax
\headtextcontent
}
- \hbox {
+ \hpack {
\box\scratchboxone
\hskip\headnumberdistance
\box\scratchboxtwo
diff --git a/Master/texmf-dist/tex/context/base/mkiv/strc-sec.mkiv b/Master/texmf-dist/tex/context/base/mkiv/strc-sec.mkiv
index 4066a1f38c8..0e30d92fa03 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/strc-sec.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/strc-sec.mkiv
@@ -430,6 +430,9 @@
}%
\doifelselist\currenthead\donothing
{\definelist[\currenthead][\c!prefix=\v!no]}%
+ % we can't do this now for backward compatibility reasons
+ % \doifelselist\currenthead\donothing
+ % {\normalexpanded{\definelist[\currenthead][\currentheadparent][\c!prefix=\v!no]}}%
\else
\normalexpanded {%
\setheadparameter{\c!label}{\currenthead}%
@@ -637,10 +640,20 @@
\triggerautostructurelevel
\strc_sectioning_handle{#1}{\c!reference={#2},\c!ownnumber={#3},\c!title={#4}}{}} % name ref nr title --
+% \unexpanded\def\strc_sectioning_handle_nop_indeed[#1][#2]% for taco: [key=value] variant
+% {\setfalse\currentstructureown
+% \triggerautostructurelevel
+% \doifelseassignment{#2}\strc_sectioning_handle_nop_indeed_yes\strc_sectioning_handle_nop_indeed_nop{#1}{#2}}
+
\unexpanded\def\strc_sectioning_handle_nop_indeed[#1][#2]% for taco: [key=value] variant
{\setfalse\currentstructureown
\triggerautostructurelevel
- \doifelseassignment{#2}\strc_sectioning_handle_nop_indeed_yes\strc_sectioning_handle_nop_indeed_nop{#1}{#2}}
+ \ifcondition\validassignment{#2}%
+ \expandafter\strc_sectioning_handle_nop_indeed_yes
+ \else
+ \expandafter\strc_sectioning_handle_nop_indeed_nop
+ \fi
+ {#1}{#2}}
\unexpanded\def\strc_sectioning_handle_nop_indeed_yes#1#2%
{\strc_sectioning_handle{#1}{#2}{}}
@@ -1143,16 +1156,6 @@
\prevdepth\strutdepth
\fi}
-\def\strc_sectioning_after_yes
- {\ifconditional\headisdisplay
- \ifconditional\c_strc_sectioning_auto_break
- % \vspacing[\v!samepage-\currentheadlevel]%
- \vspacing[\v!samepage]%
- \fi
- \strc_sectioning_empty_correction
- \headparameter\c!after
- \fi}
-
\def\strc_sectioning_after_nop
{}
@@ -1215,6 +1218,47 @@
\fi
\glet\previoushead\currenthead}
+% \def\strc_sectioning_handle_page_yes
+% {\ifconditional\c_strc_sectioning_ignore_page
+% \setfalse\c_strc_sectioning_ignore_page
+% \else
+% % beware, these numbers are not yet know here
+% \strc_sectioning_handle_page_nop
+% \edef\p_aligntitle{\headparameter\c!aligntitle}%
+% \ifx\p_aligntitle\v!float
+% \ifconditional\c_strc_sectioning_auto_break
+% \vspacing[\v!samepage-\currentheadlevel]%
+% \fi
+% \headparameter\c!before\relax
+% \indent
+% \else
+% \page_otr_command_flush_side_floats
+% \ifconditional\c_strc_sectioning_auto_break
+% \vspacing[\v!samepage-\currentheadlevel]%
+% \fi
+% \headparameter\c!before\relax
+% \fi
+% \global\c_strc_sectioning_preceding_level\currentheadlevel
+% \fi
+% \glet\previoushead\currenthead}
+%
+% \unexpanded\def\strc_sectioning_prevent_page_break% see strc-con
+% {\ifconditional\c_strc_sectioning_auto_break
+% \vspacing[\v!samepage-\the\numexpr\currentheadlevel+\plusone\relax]%
+% \fi}
+%
+% \def\strc_sectioning_after_yes
+% {\ifconditional\headisdisplay
+% \ifconditional\c_strc_sectioning_auto_break
+% % \vspacing[\v!samepage-\currentheadlevel]%
+% \vspacing[\v!samepage]%
+% \fi
+% \strc_sectioning_empty_correction
+% \headparameter\c!after
+% \fi}
+
+% This works better in columns ... but also elsewhere?
+
\def\strc_sectioning_handle_page_yes
{\ifconditional\c_strc_sectioning_ignore_page
\setfalse\c_strc_sectioning_ignore_page
@@ -1224,14 +1268,14 @@
\edef\p_aligntitle{\headparameter\c!aligntitle}%
\ifx\p_aligntitle\v!float
\ifconditional\c_strc_sectioning_auto_break
- \vspacing[\v!samepage-\currentheadlevel]%
+ \spac_vspacing_same_page\currentheadlevel\zerocount
\fi
\headparameter\c!before\relax
\indent
\else
\page_otr_command_flush_side_floats
\ifconditional\c_strc_sectioning_auto_break
- \vspacing[\v!samepage-\currentheadlevel]%
+ \spac_vspacing_same_page\currentheadlevel\zerocount
\fi
\headparameter\c!before\relax
\fi
@@ -1239,11 +1283,21 @@
\fi
\glet\previoushead\currenthead}
-\unexpanded\def\strc_sectioning_prevent_page_break#1% see strc-con
+\def\strc_sectioning_after_yes
+ {\ifconditional\headisdisplay
+ \ifconditional\c_strc_sectioning_auto_break
+ \spac_vspacing_same_page\currentheadlevel\plusone
+ \fi
+ \strc_sectioning_empty_correction
+ \headparameter\c!after
+ \fi}
+
+\unexpanded\def\strc_sectioning_prevent_page_break % see strc-con
{\ifconditional\c_strc_sectioning_auto_break
- \vspacing[\v!samepage-\the\numexpr\currentheadlevel+\ifx#1\empty\plusone\else#1\fi\relax]%
+ \spac_vspacing_same_page\currentheadlevel\plustwo
\fi}
+
% We do support negative numbers but it can have side effects that we won't catch:
%
% \chapter{some} \setupheadnumber[chapter][3] \chapter{more}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/strc-tag.lua b/Master/texmf-dist/tex/context/base/mkiv/strc-tag.lua
index 0453640ca00..88e0f108dc9 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/strc-tag.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/strc-tag.lua
@@ -124,10 +124,18 @@ local properties = allocate { -- todo: more "record = true" to improve forma
table = { pdf = "Table", nature = "display" },
tablerow = { pdf = "TR", nature = "display" },
tablecell = { pdf = "TD", nature = "mixed" },
+ tableheadcell = { pdf = "TH", nature = "mixed" },
+ tablehead = { pdf = "THEAD", nature = "display" },
+ tablebody = { pdf = "TBODY", nature = "display" },
+ tablefoot = { pdf = "TFOOT", nature = "display" },
tabulate = { pdf = "Table", nature = "display" },
tabulaterow = { pdf = "TR", nature = "display" },
tabulatecell = { pdf = "TD", nature = "mixed" },
+ tabulateheadcell = { pdf = "TH", nature = "mixed" },
+ tabulatehead = { pdf = "THEAD", nature = "display" },
+ tabulatebody = { pdf = "TBODY", nature = "display" },
+ tabulatefoot = { pdf = "TFOOT", nature = "display" },
list = { pdf = "TOC", nature = "display" },
listitem = { pdf = "TOCI", nature = "display" },
diff --git a/Master/texmf-dist/tex/context/base/mkiv/strc-tag.mkiv b/Master/texmf-dist/tex/context/base/mkiv/strc-tag.mkiv
index 84e11a63235..83ee030902a 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/strc-tag.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/strc-tag.mkiv
@@ -73,6 +73,7 @@
\def\t!registerentry {registerentry} % Span
\def\t!registercontent {registercontent} % Span
\def\t!registersee {registersee} % Span
+\def\t!registersection {registersection} % Span
\def\t!registerpages {registerpages} % Span
\def\t!registerpage {registerpage} % Span
\def\t!registerpagerange {registerpagerange} % Span
@@ -83,9 +84,19 @@
\def\t!table {table} % Table
\def\t!tablerow {tablerow} % TR
\def\t!tablecell {tablecell} % TD
+\def\t!tableheadcell {tableheadcell} % TH
+\def\t!tablehead {tablehead} % THEAD
+\def\t!tablebody {tablebody} % TBODY
+\def\t!tablefoot {tablefoot} % TFOOT
+
+
\def\t!tabulate {tabulate} % Table
\def\t!tabulaterow {tabulaterow} % TR
\def\t!tabulatecell {tabulatecell} % TD
+\def\t!tabulateheadcell {tabulateheadcell} % TH
+\def\t!tabulatehead {tabulatehead} % THEAD
+\def\t!tabulatebody {tabulatebody} % TBODY
+\def\t!tabulatefoot {tabulatefoot} % TFOOT
\def\t!math {math} % math
\def\t!mathtable {mtable} % Table
@@ -463,11 +474,14 @@
{\let\currentparagraph\empty
\paragraph_start_indeed}
+\ifdefined\dotagparagraph \else \let\dotagparagraph \gobbleoneargument \fi
+
\def\paragraph_start_indeed
{\useparagraphstyleandcolor\c!style\c!color
\usealignparameter\paragraphparameter
\usesetupsparameter\paragraphparameter
- \dostarttagged\t!paragraph\currentparagraph}
+ \dostarttagged\t!paragraph\currentparagraph
+ \dotagparagraph{\paragraphparameter\c!align}}
\unexpanded\def\stopparagraph
{\dostoptagged
diff --git a/Master/texmf-dist/tex/context/base/mkiv/strc-tnt.mkiv b/Master/texmf-dist/tex/context/base/mkiv/strc-tnt.mkiv
new file mode 100644
index 00000000000..0b092b35fcc
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/strc-tnt.mkiv
@@ -0,0 +1,120 @@
+%D \module
+%D [ file=strc-tnt,
+%D version=2019.05.30, % based on older code
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=Text Notes,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\unprotect
+
+%D \macros
+%D {definetextnote,setuptextnote}
+%D
+%D \startbuffer
+%D \definetextnote
+%D [textnote]
+%D
+%D \startbuffer
+%D Test test test \textnote [n=5] {alpha}. test test test test tets test test
+%D \textnote [n=10] {beta}. Test test test test tets test test \textnote [n=12]
+%D {gamma}. Test test test test tets test test \textnote [n=24] {delta}. Test test
+%D test test test test \textnote {epsilon} test test \textnote [n=*] {zeta}.
+%D \stopbuffer
+%D
+%D \blank {\setuptextnote[empty=yes] \getbuffer\par} \blank
+%D \blank {\setuptextnote[empty=number] \getbuffer\par} \blank
+%D \blank {\setuptextnote[empty=none] \getbuffer\par} \blank
+%D \blank { \getbuffer\par} \blank
+%D
+%D \blank[2*big]
+%D
+%D \placenotes[textnote:note][criterium=text]
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+\installcorenamespace{textnote}
+
+\installcommandhandler \??textnote {textnote} \??textnote
+
+\definebar
+ [\v!textnote:\v!underbar]
+ [\v!underbar]
+
+\definenote
+ [\v!textnote:\v!note]
+
+\setuptextnote
+ [\c!rule=\v!textnote:\v!underbar,
+ \c!note=\v!textnote:\v!note,
+ \c!n=10] % * will use the real space
+
+\appendtoks
+ \setuevalue{\currenttextnote}{\educ_textnote{\currenttextnote}}%
+\to \everydefinetextnote
+
+\unexpanded\def\educ_textnote#1%
+ {\dontleavehmode
+ \begingroup
+ \def\currenttextnote{#1}%
+ \dosingleempty\educ_textnote_indeed}
+
+\def\educ_textnote_indeed[#1]#2% we could use setups but it's overkill
+ {\iffirstargument\setupcurrenttextnote[#1]\fi
+ \edef\p_n{\textnoteparameter\c!n}%
+ \edef\p_empty{\textnoteparameter\c!empty}%
+ \edef\currentbar{\textnoteparameter\c!rule}%
+ \edef\currentnote{\textnoteparameter\c!note}%
+ \ifx\p_n\wildcardsymbol
+ \donefalse
+ \ifx\p_empty\v!yes
+ \donetrue
+ \else\ifx\p_empty\v!number
+ \donetrue
+ \else\ifx\p_empty\v!none
+ \donetrue
+ \fi\fi\fi
+ \ifdone
+ \setupbar[\currentbar][\c!empty=\v!yes]%
+ \fi
+ \inlinebar[\currentbar]\bgroup
+ \wordboundary#2%
+ \ifx\p_empty\v!yes
+ \setnotetext[\currentnote]{#2}%
+ \else\ifx\p_empty\v!number
+ \runninghbox{\resetbar\setnote[\currentnote]{#2}}%
+ \else\ifx\p_empty\v!none
+ \setupnote[\currentnote][\c!location=\v!none]%
+ \runninghbox{\resetbar\setnote[\currentnote]{#2}}%
+ \fi\fi\fi
+ \egroup
+ \else
+ \inlinebar[\currentbar]\bgroup
+ \scratchcounter\numexpr\p_n/\plustwo\relax
+ \ifx\p_empty\v!yes
+ \interwordspacesbefore\scratchcounter
+ \setnotetext[\currentnote]{#2}%
+ \interwordspacesafter\scratchcounter
+ \else\ifx\p_empty\v!number
+ \interwordspacesbefore\scratchcounter
+ \zwnj\runninghbox{\resetbar\setnote[\currentnote]{#2}}\zwnj
+ \interwordspacesafter\scratchcounter
+ \else\ifx\p_empty\v!none
+ \setupnote[\currentnote][\c!location=\v!none]%
+ \interwordspacesbefore\scratchcounter
+ \zwnj\runninghbox{\resetbar\setnote[\currentnote]{#2}}\zwnj
+ \interwordspacesafter\scratchcounter
+ \else
+ #2%
+ \fi\fi\fi
+ \egroup
+ \fi
+ \endgroup}
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/supp-box.lua b/Master/texmf-dist/tex/context/base/mkiv/supp-box.lua
index 1f31f768130..e547c8710d6 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/supp-box.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/supp-box.lua
@@ -12,13 +12,13 @@ local report_hyphenation = logs.reporter("languages","hyphenation")
local tonumber, next, type = tonumber, next, type
-local lpegmatch = lpeg.match
+local lpegmatch = lpeg.match
-local tex = tex
-local context = context
-local nodes = nodes
+local tex = tex
+local context = context
+local nodes = nodes
-local implement = interfaces.implement
+local implement = interfaces.implement
local nodecodes = nodes.nodecodes
@@ -26,6 +26,7 @@ local disc_code = nodecodes.disc
local hlist_code = nodecodes.hlist
local vlist_code = nodecodes.vlist
local glue_code = nodecodes.glue
+local penalty_code = nodecodes.penalty
local glyph_code = nodecodes.glyph
local nuts = nodes.nuts
@@ -49,6 +50,7 @@ local takebox = nuts.takebox
local setlink = nuts.setlink
local setboth = nuts.setboth
local setnext = nuts.setnext
+local setprev = nuts.setprev
local setbox = nuts.setbox
local setlist = nuts.setlist
local setdisc = nuts.setdisc
@@ -56,6 +58,8 @@ local setwidth = nuts.setwidth
local setheight = nuts.setheight
local setdepth = nuts.setdepth
local setshift = nuts.setshift
+local setsplit = nuts.setsplit
+local setattrlist = nuts.setattrlist
local flush_node = nuts.flush_node
local flush_list = nuts.flush_list
@@ -64,6 +68,10 @@ local copy_list = nuts.copy_list
local find_tail = nuts.tail
local getdimensions = nuts.dimensions
local hpack = nuts.hpack
+local vpack = nuts.vpack
+local traverse_id = nuts.traverse_id
+local free = nuts.free
+local findtail = nuts.tail
local nextdisc = nuts.traversers.disc
local nextdir = nuts.traversers.dir
@@ -378,13 +386,13 @@ local function getnaturaldimensions(n)
return w, h, d
end
-interfaces.implement {
+implement {
name = "getnaturaldimensions",
arguments = "integer",
actions = getnaturaldimensions
}
-interfaces.implement {
+implement {
name = "naturalwd",
arguments = "integer",
actions = function(n)
@@ -393,7 +401,7 @@ interfaces.implement {
end
}
-interfaces.implement {
+implement {
name = "getnaturalwd",
arguments = "integer",
actions = function(n)
@@ -416,7 +424,7 @@ local function setboxtonaturalwd(n)
setbox(n,new)
end
-interfaces.implement {
+implement {
name = "setnaturalwd",
arguments = "integer",
actions = setboxtonaturalwd
@@ -450,7 +458,7 @@ do
nodes.firstdirinbox = firstdirinbox
- interfaces.implement {
+ implement {
name = "doifelserighttoleftinbox",
arguments = "integer",
actions = function(n)
@@ -481,15 +489,23 @@ do
trackers.register("nodes.boxes",function(v) trace = v end)
- function boxes.save(category,name,box)
+ function boxes.save(category,name,b)
name = tonumber(name) or name
- local b = takebox(box)
+ local b = takebox(b)
if trace then
report("category %a, name %a, %s (%s)",category,name,"save",b and "content" or "empty")
end
cache[category][name] = b or false
end
+ function boxes.savenode(category,name,n)
+ name = tonumber(name) or name
+ if trace then
+ report("category %a, name %a, %s (%s)",category,name,"save",n and "content" or "empty")
+ end
+ cache[category][name] = tonut(n) or false
+ end
+
function boxes.found(category,name)
name = tonumber(name) or name
return cache[category][name] and true or false
@@ -625,8 +641,187 @@ implement {
end
}
-interfaces.implement {
+implement {
name = "shiftbox",
arguments = { "integer", "dimension" },
- actions = function(n,d) setshift(getbox(n),d) end,
+ actions = function(n,d)
+ setshift(getbox(n),d)
+ end,
+}
+
+implement { name = "vpackbox", arguments = "integer", actions = function(n) setbox(n,(vpack(takebox(n)))) end }
+implement { name = "hpackbox", arguments = "integer", actions = function(n) setbox(n,(hpack(takebox(n)))) end }
+
+implement { name = "vpackedbox", arguments = "integer", actions = function(n) context(vpack(takebox(n))) end }
+implement { name = "hpackedbox", arguments = "integer", actions = function(n) context(hpack(takebox(n))) end }
+
+implement {
+ name = "scangivendimensions",
+ public = true,
+ protected = true,
+ arguments = {
+ {
+ { "width", "dimension" },
+ { "height", "dimension" },
+ { "depth", "dimension" },
+ },
+ },
+ actions = function(t)
+ texsetdimen("givenwidth", t.width or 0)
+ texsetdimen("givenheight",t.height or 0)
+ texsetdimen("givendepth", t.depth or 0)
+ end,
+}
+
+local function stripglue(list)
+ local done = false
+ local first = list
+ while first do
+ local id = getid(first)
+ if id == glue_code or id == penalty_code then
+ first = getnext(first)
+ else
+ break
+ end
+ end
+ if first and first ~= list then
+ -- we have discardables
+ setsplit(getprev(first),first)
+ flush_list(list)
+ list = first
+ done = true
+ end
+ if list then
+ local tail = findtail(list)
+ local last = tail
+ while last do
+ local id = getid(last)
+ if id == glue_code or id == penalty_code then
+ last = getprev(last)
+ else
+ break
+ end
+ end
+ if last ~= tail then
+ -- we have discardables
+ flush_list(getnext(last))
+ setnext(last)
+ done = true
+ end
+ end
+ return list, done
+end
+
+local function limitate(t) -- don't pack the result !
+ local text = t.text
+ if text then
+ text = tonut(text)
+ else
+ return
+ end
+ local sentinel = t.sentinel
+ if sentinel then
+ sentinel = tonut(sentinel)
+ local s = getlist(sentinel)
+ setlist(sentinel)
+ free(sentinel)
+ sentinel = s
+ else
+ return tonode(text)
+ end
+ local width = getwidth(text)
+ local list = getlist(text)
+ local done = false
+ if t.strip then
+ list, done = stripglue(list)
+ if not list then
+ setlist(text)
+ setwidth(text,0)
+ return text
+ elseif done then
+ width = getdimensions(list)
+ setlist(text,list)
+ end
+ end
+ local left = t.left or 0
+ local right = t.right or 0
+ if left + right < width then
+ local last = nil
+ local first = nil
+ local maxleft = left
+ local maxright = right
+ local swidth = getwidth(sentinel)
+ if maxright > 0 then
+ maxleft = maxleft - swidth/2
+ maxright = maxright - swidth/2
+ else
+ maxleft = maxleft - swidth
+ end
+ for n in traverse_id(glue_code,list) do
+ local width = getdimensions(list,n)
+ if width > maxleft then
+ if not last then
+ last = n
+ end
+ break
+ else
+ last = n
+ end
+ end
+ if last and maxright > 0 then
+ for n in traverse_id(glue_code,last) do
+ local width = getdimensions(n)
+ if width < maxright then
+ first = n
+ break
+ else
+ first = n
+ end
+ end
+ end
+ if last then
+ local rest = getnext(last)
+ if rest then
+ local tail = findtail(sentinel)
+ if first and getid(first) == glue_code and getid(tail) == glue_code then
+ setwidth(first,0)
+ end
+ if last and getid(last) == glue_code and getid(sentinel) == glue_code then
+ setwidth(last,0)
+ end
+ if first and first ~= last then
+ local prev = getprev(first)
+ if prev then
+ setnext(prev)
+ end
+ setlink(tail,first)
+ end
+ setlink(last,sentinel)
+ setprev(rest)
+ flush_list(rest)
+ end
+ end
+ end
+ setlist(text)
+ free(text)
+ return tonode(list)
+end
+
+implement {
+ name = "limitated",
+ public = true,
+ protected = true,
+ arguments = {
+ {
+ { "left", "dimension" },
+ { "right", "dimension" },
+ { "text", "hbox" },
+ { "sentinel", "hbox" },
+ { "strip", "boolean" },
+ }
+ },
+ actions = function(t)
+ context.dontleavehmode()
+ context(limitate(t))
+ end,
}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/supp-box.mkiv b/Master/texmf-dist/tex/context/base/mkiv/supp-box.mkiv
index 59e7105207b..d43459c631b 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/supp-box.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/supp-box.mkiv
@@ -23,6 +23,12 @@
\fixupboxesmode\plusone
+%D And some dimensions:
+
+\newdimen\givenwidth
+\newdimen\givenheight
+\newdimen\givendepth
+
% handy to have
%
% \hbox to \hsize
@@ -57,8 +63,8 @@
%D \macros
%D {dontcomplain}
%D
-%D The next macro suppresses over- and underfull messages which
-%D often makes sense when we deal with boxes.
+%D The next macro suppresses over- and underfull messages which often makes sense
+%D when we deal with boxes.
\unexpanded\def\dontcomplain
{\hbadness\plustenthousand
@@ -66,18 +72,15 @@
\hfuzz \maxdimen
\vfuzz \maxdimen}
-%D This module implements some box manipulation macros. Some
-%D are quite simple, some are more advanced and when understood
-%D well, all can be of use.
+%D This module implements some box manipulation macros. Some are quite simple, some
+%D are more advanced and when understood well, all can be of use.
%D
%D \macros
%D {strutdp,strutht,strutwd}
%D
-%D The next shortcuts save memory and keying. The width is
-%D normally zero points (if not, you're in trouble). These
-%D shortcuts can be used like a dimension, opposite to the
-%D core macros \type {\strutdepth} and alike, which are
-%D values.
+%D The next shortcuts save memory and keying. The width is normally zero points (if
+%D not, you're in trouble). These shortcuts can be used like a dimension, opposite
+%D to the core macros \type {\strutdepth} and alike, which are values.
\def\strutdp {\dp\strutbox}
\def\strutht {\ht\strutbox}
@@ -88,8 +91,8 @@
%D \macros
%D {voidbox,nextbox}
%D
-%D Let's start with an easy one. The next macro hides the
-%D ugly \type {@} in \type {\voidb@x}.
+%D Let's start with an easy one. The next macro hides the ugly \type {@} in \type
+%D {\voidb@x}.
\ifdefined\voidbox \else \newbox\voidbox \fi
\ifdefined\nextbox \else \newbox\nextbox \fi
@@ -97,19 +100,17 @@
%D \macros
%D {nextdepth}
%D
-%D Let's start with a rather simple declaration. Sometimes we
-%D need to save the \TEX\ \DIMENSION\ \type{\prevdepth} and
-%D append it later on. The name \type{\nextdepth} suits
-%D this purpose well.
+%D Let's start with a rather simple declaration. Sometimes we need to save the \TEX\
+%D \DIMENSION\ \type{\prevdepth} and append it later on. The name \type {\nextdepth}
+%D suits this purpose well.
\newdimen\nextdepth
%D \macros
%D {smashbox, smashedbox}
%D
-%D Smashing is introduced in \PLAIN\ \TEX, and stands for
-%D reducing the dimensions of a box to zero. The most resolute
-%D one is presented first.
+%D Smashing is introduced in \PLAIN\ \TEX, and stands for reducing the dimensions of
+%D a box to zero. The most resolute one is presented first.
\unexpanded\def\smashbox#1%
{\wd#1\zeropoint
@@ -125,8 +126,8 @@
%D \macros
%D {hsmashbox,vsmashbox}
%D
-%D Smashing can be used for overlaying boxes. Depending on
-%D the mode, horizontal or vertical, one can use:
+%D Smashing can be used for overlaying boxes. Depending on the mode, horizontal or
+%D vertical, one can use:
\unexpanded\def\hsmashbox#1%
{\wd#1\zeropoint}
@@ -135,8 +136,7 @@
{\ht#1\zeropoint
\dp#1\zeropoint}
-%D The next implementation is less sensitive for spurious
-%D spaces.
+%D The next implementation is less sensitive for spurious spaces.
\newcount\c_boxes_register
@@ -174,10 +174,9 @@
%D {hsmash,vsmash,
%D hsmashed,vsmashed}
%D
-%D While the previous macros expected a \BOX, the next act on a
-%D content. They are some subtle differences betreen the smash
-%D and smashed alternatives. The later ones reduce all
-%D dimensions to zero.
+%D While the previous macros expected a \BOX, the next act on a content. They are
+%D some subtle differences betreen the smash and smashed alternatives. The later
+%D ones reduce all dimensions to zero.
\unexpanded\def\hsmash {\bgroup\dowithnextboxcs\syst_boxes_hsmashed_nextbox\hbox}
\unexpanded\def\vsmash {\bgroup\dowithnextboxcs\syst_boxes_vsmashed_nextbox\vbox}
@@ -227,10 +226,9 @@
%D \macros
%D {smash}
%D
-%D This smash alternative takes an optional arg [whdtb] as
-%D well as is potentially catcode safer. It is needed by the
-%D math module (although the \type {\leavevmode} is not added
-%D here).
+%D This smash alternative takes an optional arg [whdtb] as well as is potentially
+%D catcode safer. It is needed by the math module (although the \type {\leavevmode}
+%D is not added here).
\unexpanded\def\smash
{\begingroup
@@ -304,12 +302,12 @@
%D \macros
%D {phantom, hphantom, vphantom, mathstrut}
%D
-%D The next implementation of \type {\phantom} cum suis does
-%D not grab an argument in the non||math case, which is better.
+%D The next implementation of \type {\phantom} cum suis does not grab an argument in
+%D the non||math case, which is better.
%D
-%D Due to a complicated call to \type {\mathpallete} and
-%D thereby \type {\mathchoice}, the next macro looks ugly.
-%D We also take care of non||braced arguments.
+%D Due to a complicated call to \type {\mathpallete} and thereby \type
+%D {\mathchoice}, the next macro looks ugly. We also take care of non||braced
+%D arguments.
\unexpanded\def\phantom {\begingroup\futurelet\nexttoken\syst_boxes_phantom_indeed }
\unexpanded\def\vphantom{\begingroup\futurelet\nexttoken\syst_boxes_phantom_indeed_v}
@@ -382,8 +380,7 @@
%D \macros
%D {getboxheight}
%D
-%D Although often needed, \TEX\ does not support arithmics
-%D like:
+%D Although often needed, \TEX\ does not support arithmics like:
%D
%D \starttyping
%D \dimen0 = \ht0 + \dp0
@@ -409,33 +406,29 @@
%D {#1\ht#3\advance#1\dp#3\relax}
%D \stoptyping
%D
-%D The next alternative is slightly more clever, since
-%D it accepts \type {{12}} as well as \type {12} as box
-%D number.
+%D The next alternative is slightly more clever, since it accepts \type {{12}} as
+%D well as \type {12} as box number.
\unexpanded\def\getboxheight#1\of#2\box#3%
{\def\next{#1\dimexpr\ht\c_boxes_register+\dp\c_boxes_register\relax}%
\afterassignment\next\c_boxes_register=#3}
-%D For a long time the following three macros were part of
-%D the grid snapping core module, but it makes more sense to
-%D have them here so that users can see them.
+%D For a long time the following three macros were part of the grid snapping core
+%D module, but it makes more sense to have them here so that users can see them.
%D
%D \macros
%D {getnoflines, getroundednoflines, getrawnoflines}
%D
-%D Het commando \type{\getnoflines} converteert een hoogte
-%D (dimensie) in een aantal regels en kent dit toe aan
-%D \type{\noflines}.
+%D Het commando \type {\getnoflines} converteert een hoogte (dimensie) in een aantal
+%D regels en kent dit toe aan \type {\noflines}.
%D
%D \starttyping
%D \getnoflines{dimensie}
%D \stoptyping
%D
-%D Er wordt gedeeld door \type{\openlineheight} en een hoogte
-%D van~0pt komt overeen met 0~regels. The raw alternative
-%D does not round.
-
+%D Er wordt gedeeld door \type {\openlineheight} en een hoogte van~0pt komt overeen
+%D met 0~regels. The raw alternative does not round.
+%D
%D For a long time we had:
%D
%D \starttyping
@@ -444,7 +437,7 @@
%D
%D \def\dogetnoflines#1#2%
%D {\noflinesheight#2\relax
-%D \ifzeropt\noflinesheight % \ifdim\noflinesheight=\zeropoint
+%D \ifzeropt\noflinesheight
%D \noflines\zerocount
%D \else
%D \divide\noflinesheight \openlineheight
@@ -538,9 +531,9 @@
%D \macros
%D {determinenoflines}
%D
-%D The next macro determines the number of lines and
-%D returns it it \type {\noflines}. The macro works
-%D reasonable well as long as the content can be unboxed.
+%D The next macro determines the number of lines and returns it it \type
+%D {\noflines}. The macro works reasonable well as long as the content can be
+%D unboxed.
%D
%D \starttyping
%D \determinenoflines{test\\test}
@@ -548,30 +541,26 @@
%D \determinenoflines{\definedfont[Sans at 40pt]test\\test}
%D \stoptyping
-\def\dodeterminenoflines % can be mkiv'd
+\def\syst_boxes_determine_noflines % can be mkiv'd
{\beginofshapebox
\unvbox\nextbox
\endofshapebox
- % \global\count1\zerocount
- % \reshapebox{\global\advance\count1\plusone}%
- % \egroup\noflines\count1 }%
- \scratchcounter\zerocount
- \reshapebox{\global\advance\scratchcounter\plusone}%
- \expandafter\egroup\expandafter\noflines\the\scratchcounter\relax}
+ \globalscratchcounter\zerocount
+ \reshapebox{\global\advance\globalscratchcounter\plusone}%
+ \expandafter\egroup\expandafter\noflines\the\globalscratchcounter\relax}
\unexpanded\def\determinenoflines
{\bgroup
\forgetall
\let\crlf\endgraf
\let\\\endgraf
- \dowithnextboxcs\dodeterminenoflines\vbox}
+ \dowithnextboxcs\syst_boxes_determine_noflines\vbox}
%D \macros
%D {doiftextelse, doiftext}
%D
-%D When \type {\doifelse} cum suis hopelessly fail, for
-%D instance because we pass data, we can fall back on the next
-%D macro:
+%D When \type {\doifelse} cum suis hopelessly fail, for instance because we pass
+%D data, we can fall back on the next macro:
%D
%D \starttyping
%D \doiftextelse {data} {then branch} {else branch}
@@ -580,7 +569,7 @@
\unexpanded\def\doifelsetext#1%
{\begingroup
- \setbox\scratchbox\hpack
+ \setbox\scratchbox\hbox % no \hpack because we can have fallbacks
{\settrialtypesetting
\ignorespaces#1\removeunwantedspaces}%
\ifzeropt\wd\scratchbox
@@ -593,7 +582,7 @@
\unexpanded\def\doiftext#1%
{\begingroup
- \setbox\scratchbox\hpack
+ \setbox\scratchbox\hbox % no \hpack because we can have fallbacks
{\settrialtypesetting
\ignorespaces#1\removeunwantedspaces}%
\ifzeropt\wd\scratchbox
@@ -605,23 +594,19 @@
%D \macros
%D {dowithnextbox,nextbox}
%D
-%D Sometimes we want a macro to grab a box and do something
-%D on the content. One could pass an argument to a box, but
-%D this can violate the specific \CATCODES\ of its content and
-%D leads to unexpected results. The next macro treats the
-%D following braced text as the content of a box and
-%D manipulates it afterwards in a predefined way.
+%D Sometimes we want a macro to grab a box and do something on the content. One
+%D could pass an argument to a box, but this can violate the specific \CATCODES\ of
+%D its content and leads to unexpected results. The next macro treats the following
+%D braced text as the content of a box and manipulates it afterwards in a predefined
+%D way.
%D
-%D The first argument specifies what to do with the content.
-%D This content is available in \type{\nextbox}. The second
-%D argument is one of \type{\hbox}, \type{\vbox} or
-%D \type{\vtop}. The third argument must be grouped with
-%D \type{\bgroup} and \type{\egroup}, \type{{...}} or can be
-%D a \type{\box} specification.
+%D The first argument specifies what to do with the content. This content is
+%D available in \type {\nextbox}. The second argument is one of \type {\hbox}, \type
+%D {\vbox} or \type {\vtop}. The third argument must be grouped with \type {\bgroup}
+%D and \type {\egroup}, \type {{...}} or can be a \type {\box} specification.
%D
-%D In \CONTEXT\ this macro is used for picking up a box and
-%D treating it according to earlier specifications. We use for
-%D instance something like:
+%D In \CONTEXT\ this macro is used for picking up a box and treating it according to
+%D earlier specifications. We use for instance something like:
%D
%D \starttyping
%D \def\getfloat%
@@ -636,9 +621,8 @@
%D {...#1...}
%D \stoptyping
%D
-%D In this implementation the \type{\aftergroup} construction
-%D is needed because \type{\afterassignment} is executed inside
-%D the box.
+%D In this implementation the \type {\aftergroup} construction is needed because
+%D \type {\afterassignment} is executed inside the box.
\unexpanded\def\dowithnextbox#1%
{\def\syst_boxes_with_next_box{#1}%
@@ -684,28 +668,27 @@
%D \setbox\nextbox#2}
%D \stoptyping
%D
-%D This alternative also accepts \type{\box0} and alike, but
-%D we don't really need this functionality now.
+%D This alternative also accepts \type {\box0} and alike, but we don't really need
+%D this functionality now.
%D \macros
%D {nextboxht,nextboxwd,nextboxdp,flushnextbox}
%D
-%D The next couple of shortcuts saves us memory as well as
-%D \type {{}}'s in passing parameters.
+%D The next couple of shortcuts saves us memory as well as \type {{}}'s in passing
+%D parameters.
-\def\nextboxht {\ht\nextbox}
-\def\nextboxwd {\wd\nextbox}
-\def\nextboxdp {\dp\nextbox}
-\def\nextboxhtdp {\dimexpr\ht\nextbox+\dp\nextbox\relax}
+\def\nextboxht {\ht\nextbox}
+\def\nextboxwd {\wd\nextbox}
+\def\nextboxdp {\dp\nextbox}
+\def\nextboxhtdp{\dimexpr\ht\nextbox+\dp\nextbox\relax}
\unexpanded\def\flushnextbox{\box\nextbox}
%D \macros
%D {dowithnextboxcontent}
%D
-%D But, occasionally we do need to pass some local settings
-%D without wanting to use additional grouping. Therefore we
-%D provide:
+%D But, occasionally we do need to pass some local settings without wanting to use
+%D additional grouping. Therefore we provide:
%D
%D \starttyping
%D \dowithnextboxcontent{inside}{after}{box content}
@@ -731,8 +714,8 @@
%D \macros
%D {llap, rlap, tlap, blap, clap}
%D
-%D Some well known friends, but we implement them our own
-%D way. We want the macros to work in both math and text mode.
+%D Some well known friends, but we implement them our own way. We want the macros to
+%D work in both math and text mode.
\def\dodorlap{\hpack to \zeropoint{\box\nextbox\hss}\endgroup}
\def\dodollap{\hpack to \zeropoint{\hss\box\nextbox}\endgroup}
@@ -764,16 +747,14 @@
%D shapebox,
%D ifreshapingbox}
%D
-%D The next utility macro originates from some linenumbering
-%D mechanism. Due to \TEX's advanced way of typesetting
-%D paragraphs, it's not easy to do things on a line||by||line
-%D basis. This macro is able to reprocess a given box and can
-%D act upon its vertical boxed components, such as lines. The
-%D unwinding sequence in this macro is inspired by a \NTG\
-%D workshop of David Salomon in June 1992.
+%D The next utility macro originates from some linenumbering mechanism. Due to
+%D \TEX's advanced way of typesetting paragraphs, it's not easy to do things on a
+%D line||by||line basis. This macro is able to reprocess a given box and can act
+%D upon its vertical boxed components, such as lines. The unwinding sequence in this
+%D macro is inspired by a \NTG\ workshop of David Salomon in June 1992.
%D
-%D First we have to grab the piece of text we want to act
-%D upon. This is done by means of the duo macros:
+%D First we have to grab the piece of text we want to act upon. This is done by
+%D means of the duo macros:
%D
%D \starttyping
%D \beginofshapebox
@@ -781,16 +762,14 @@
%D \endofshapebox
%D \stoptyping
%D
-%D When all texts is collected, we can call \type{\reshapebox}
-%D and do something with it's vertical components. We can make
-%D as much passes as needed. When we're done, the box can be
-%D unloaded with \type{\flushshapebox}. The only condition in
-%D this scheme is that \type{\reshapebox} must somehow unload
-%D the \BOX\ \type{\shapebox}.
+%D When all texts is collected, we can call \type {\reshapebox} and do something
+%D with it's vertical components. We can make as much passes as needed. When we're
+%D done, the box can be unloaded with \type {\flushshapebox}. The only condition in
+%D this scheme is that \type {\reshapebox} must somehow unload the \BOX\ \type
+%D {\shapebox}.
%D
-%D An important aspect is that the content is unrolled
-%D bottom||up. The next example illustrates this maybe
-%D unexpected characteristic.
+%D An important aspect is that the content is unrolled bottom||up. The next example
+%D illustrates this maybe unexpected characteristic.
%D
%D \startbuffer
%D \beginofshapebox
@@ -810,8 +789,7 @@
%D
%D \getbuffer
%D
-%D As we can see, when some kind of numbering is done, we have
-%D to add a second pass.
+%D As we can see, when some kind of numbering is done, we have to add a second pass.
%D
%D \startbuffer
%D \newcounter\LineNumber
@@ -835,9 +813,9 @@
%D
%D \getbuffer
%D
-%D This example shows that the content of the box is still
-%D available after flushing. Another feature is that only the
-%D last reshaping counts. Multiple reshaping can be done by:
+%D This example shows that the content of the box is still available after flushing.
+%D Another feature is that only the last reshaping counts. Multiple reshaping can be
+%D done by:
%D
%D \startbuffer
%D \beginofshapebox
@@ -856,29 +834,27 @@
%D
%D \getbuffer
%D
-%D The macros are surprisingly easy to follow and in fact
-%D introduce no new concepts. Nearly all books on \TEX\ show
-%D similar solutions for unwinding \BOXES.
+%D The macros are surprisingly easy to follow and in fact introduce no new concepts.
+%D Nearly all books on \TEX\ show similar solutions for unwinding \BOXES.
%D
-%D Some macros, like footnote ones, can be sensitive for
-%D reshaping, which can result in an endless loop. We
-%D therefore offer:
+%D Some macros, like footnote ones, can be sensitive for reshaping, which can result
+%D in an endless loop. We therefore offer:
%D
%D \starttyping
%D \ifreshapingbox
%D \stoptyping
%D
-%D Some \CONTEXT\ commands are protected this way. Anyhow,
-%D reshaping is aborted after 100 dead cycles.
+%D Some \CONTEXT\ commands are protected this way. Anyhow, reshaping is aborted
+%D after 100 dead cycles.
%D
-%D By the way, changing the height and depth of \BOX\
-%D \type{\shapebox} results in bad spacing. This means that
-%D for instance linenumbers etc. should be given zero height
-%D and depth before being lapped into the margin. The
-%D previous examples ignore this side effect, but beware!
+%D By the way, changing the height and depth of \BOX\ \type {\shapebox} results in
+%D bad spacing. This means that for instance linenumbers etc. should be given zero
+%D height and depth before being lapped into the margin. The previous examples
+%D ignore this side effect, but beware!
\newif \ifsomeshapeleft
\newif \ifreshapingbox
+\newif \ifreshapingfailed % may save redundant runs
\newbox \shapebox
\newcount \shapepenalty
@@ -887,6 +863,7 @@
\newbox \newshapebox
\newbox \oldshapebox
+\newbox \tmpshapebox
\newcount \shapecounter
@@ -901,13 +878,9 @@
{\kern \shapekern }%
{\vskip \shapeskip }}
-\newbox\tmpshapebox
-
-\newif\ifreshapingfailed % may save redundant runs
-
\def\doreshapebox#1#2#3#4% \shapebox, \shapepenalty, \shapekern, \shapeskip
{\global\reshapingfailedfalse
- \ifzeropt\ht\oldshapebox % \ifdim\ht\oldshapebox=\zeropoint
+ \ifzeropt\ht\oldshapebox
\setbox\newshapebox\emptyvbox
\else
\setbox\newshapebox\vbox % can be \vpack
@@ -979,7 +952,7 @@
\unexpanded\def\flushshapebox
{\bgroup
- \ifzeropt\ht\newshapebox % \ifdim\ht\newshapebox=\zeropoint
+ \ifzeropt\ht\newshapebox
\else
% make \prevdepth legal
% \par before the next \vskip gives far worse results
@@ -1034,9 +1007,8 @@
% \kern-\dp\newshapebox\relax
\fi}
-%D For absolute control, one can use \type{\doreshapebox}
-%D directly. This macro takes four arguments, that take care
-%D of:
+%D For absolute control, one can use \type {\doreshapebox} directly. This macro
+%D takes four arguments, that take care of:
%D
%D \startitemize[n,packed]
%D \item \type{\shapebox}
@@ -1048,17 +1020,16 @@
%D \macros
%D {shapedhbox}
%D
-%D When constructing a new box, using the content of \type
-%D {\shapebox}, one can best use \type {\shapedhbox} instead
-%D of \type {\hbox}, since it manages the height and depth of
-%D the line.
+%D When constructing a new box, using the content of \type {\shapebox}, one can best
+%D use \type {\shapedhbox} instead of \type {\hbox}, since it manages the height and
+%D depth of the line.
\unexpanded\def\shapedhbox % lines with non strutted dimensions have
{\expanded{\dowithnextbox % interlineskip so if we want the original
- {\dp\nextbox\the\ht\shapebox % spacing, we need to preserve the original
+ {\ht\nextbox\the\ht\shapebox % spacing, we need to preserve the original
\dp\nextbox\the\dp\shapebox % height and depth which is definitely
\box\nextbox}} % needed if we apply struts to the 'new'
- \hbox} % box or do something that changed ist size
+ \hbox} % box or do something that changed ist size
%D \macros
%D {hyphenatedword,
@@ -1066,8 +1037,8 @@
%D hyphenatedfile,
%D dohyphenateword}
%D
-%D We no longer use the pure \TEX\ variant. In due time we will
-%D report some more advanced statistics.
+%D We no longer use the pure \TEX\ variant. In due time we will report some more
+%D advanced statistics.
%D
%D \starttyping
%D \showhyphens{dohyphenatedword}
@@ -1104,11 +1075,10 @@
%D \macros
%D {processtokens}
%D
-%D We fully agree with (most) typographers that inter||letter
-%D spacing is only permitted in fancy titles, we provide a
-%D macro that can be used to do so. Because this is
-%D (definitely and fortunately) no feature of \TEX, we have to
-%D step through the token list ourselves.
+%D We fully agree with (most) typographers that inter||letter spacing is only
+%D permitted in fancy titles, we provide a macro that can be used to do so. Because
+%D this is (definitely and fortunately) no feature of \TEX, we have to step through
+%D the token list ourselves.
%D
%D \starttyping
%D \processtokens {before} {between} {after} {space} {tokens}
@@ -1126,12 +1096,12 @@
%D
%D \getbuffer
%D
-%D The list of tokens may contain spaces, while \type{\\},
-%D \type{{}} and \type{\ } are handled as space too.
+%D The list of tokens may contain spaces, while \type {\\}, \type {{}} and \type {\
+%D } are handled as space too.
\unexpanded\def\processtokens#1#2#3#4#5%
{\begingroup
- \def\lastcharacter{\lastcharacter}%
+ \def\lastcharacter{\lastcharacter}% hm, recursive ?
\def\space{ }%
\let\\=\space
\def\before {#1}%
@@ -1171,20 +1141,18 @@
%D \macros
%D {doboundtext}
%D
-%D Sometimes there is not enough room to show the complete
-%D (line of) text. In such a situation we can strip of some
-%D characters by using \type{\doboundtext}. When the text is
-%D wider than the given width, it's split and the third
-%D argument is appended. When the text to be checked is packed
-%D in a command, we'll have to use \type{\expandafter}.
+%D Sometimes there is not enough room to show the complete (line of) text. In such a
+%D situation we can strip of some characters by using \type {\doboundtext}. When the
+%D text is wider than the given width, it's split and the third argument is
+%D appended. When the text to be checked is packed in a command, we'll have to use
+%D \type {\expandafter}.
%D
%D \starttyping
%D \doboundtext{a very, probably to long, text}{3cm}{...}
%D \stoptyping
%D
-%D When calculating the room needed, we take the width of the
-%D third argument into account, which leads to a bit more
-%D complex macro than needed at first sight.
+%D When calculating the room needed, we take the width of the third argument into
+%D account, which leads to a bit more complex macro than needed at first sight.
\def\dodoboundtext#1%
{\setbox\scratchboxone\hbox{#1}%
@@ -1205,18 +1173,17 @@
%D \macros
%D {limitatetext}
%D
-%D A bit more beautiful alternative for the previous command is
-%D the next one. This command is more robust because we let
-%D \TEX\ do most of the job. The previous command works better
-%D on text that cannot be hyphenated.
+%D A bit more beautiful alternative for the previous command is the next one. This
+%D command is more robust because we let \TEX\ do most of the job. The previous
+%D command works better on text that cannot be hyphenated.
%D
%D \starttyping
%D \limitatetext {text} {width} {sentinel}
%D \limitatetext {text} {-width} {prelude}
%D \stoptyping
%D
-%D When no width is given, the whole text comes available. The
-%D sentinel is optional. This is about the third version.
+%D When no width is given, the whole text comes available. The sentinel is optional.
+%D This is about the third version.
\ifdefined\fakecompoundhyphen\else \let\fakecompoundhyphen\relax \fi
\ifdefined\veryraggedright \else \def\veryraggedright{\raggedright} \fi
@@ -1310,6 +1277,7 @@
\let\speciallimitatetext\firstoffourarguments
\setbox\scratchboxone\hbox
{\nohyphens
+ \dontcomplain
\normallimitatetext{#1}{+#2}{}#4%
\normallimitatetext{#1}{-#3}{}}%
\setbox\scratchboxtwo\hbox
@@ -1477,10 +1445,9 @@
%D \macros
%D {sbox}
%D
-%D This is a rather strange command. It grabs some box content
-%D and and limits the size to the height and depth of a
-%D \type{\strut}. The resulting bottom||alligned box can be used
-%D aside other ones, without disturbing the normal baseline
+%D This is a rather strange command. It grabs some box content and and limits the
+%D size to the height and depth of a \type {\strut}. The resulting bottom||alligned
+%D box can be used aside other ones, without disturbing the normal baseline
%D distance.
%D
%D \startbuffer
@@ -1496,26 +1463,29 @@
%D \getbuffer
%D \stopexample
%D
-%D Before displaying the result we added some skip, otherwise
-%D the first two lines would have ended up in the text. This
-%D macro can be useful when building complicated menus, headers
-%D and footers and|/|or margin material.
+%D Before displaying the result we added some skip, otherwise the first two lines
+%D would have ended up in the text. This macro can be useful when building
+%D complicated menus, headers and footers and|/|or margin material.
\unexpanded\def\sbox
- {\vbox\bgroup
+ {\vpack\bgroup
\dowithnextboxcs\syst_boxes_sbox_finish\vbox}
\unexpanded\def\syst_boxes_sbox_finish
{\setbox\nextbox\hpack
- {\strut
- \dp\nextbox\zeropoint
+ {\strut % not needed
+ \dp\nextbox\zeropoint % not needed
\lower\strutdp\box\nextbox}%
- \dp\nextbox\strutdp
- \ht\nextbox\strutht
- \box\nextbox
- \egroup}
+ \dp\nextbox\strutdp
+ \ht\nextbox\strutht
+ \box\nextbox
+ \egroup}
%D A variant on this:
+%D
+%D \starttyping
+%D xx \ruledhbox{\inlinedbox{\tfd test}} xx
+%D \stoptyping
\unexpanded\def\inlinedbox
{\bgroup
@@ -1533,8 +1503,7 @@
%D \macros
%D {struttedbox}
%D
-%D This boxing macro limits the height and depth to those of
-%D a strut.
+%D This boxing macro limits the height and depth to those of a strut.
\unexpanded\def\struttedbox
{\hpack\bgroup
@@ -1549,9 +1518,8 @@
%D \macros
%D {topskippedbox}
%D
-%D This macro compensates the difference between the topskip
-%D and strutheight. Watch how we preserve the depth when it
-%D equals strutdepth.
+%D This macro compensates the difference between the topskip and strutheight. Watch
+%D how we preserve the depth when it equals strutdepth.
\unexpanded\def\topskippedbox
{\hpack\bgroup\dowithnextboxcs\syst_boxes_topskippedbox_finish\hbox}
@@ -1565,13 +1533,12 @@
%D \macros
%D {centeredbox, centerednextbox}
%D
-%D Here is another strange one. This one offers a sort of overlay
-%D with positive or negative offsets. This command can be used
-%D in well defined areas where no offset options are available.
-%D We first used it when building a button inside the margin
-%D footer, where the button should have a horizontal offset and
-%D should be centered with respect to the surrounding box. The
-%D last of the three examples we show below says:
+%D Here is another strange one. This one offers a sort of overlay with positive or
+%D negative offsets. This command can be used in well defined areas where no offset
+%D options are available. We first used it when building a button inside the margin
+%D footer, where the button should have a horizontal offset and should be centered
+%D with respect to the surrounding box. The last of the three examples we show below
+%D says:
%D
%D \starttyping
%D \vsize=3cm
@@ -1581,8 +1548,8 @@
%D {\vrule width \hsize height \vsize}}}
%D \stoptyping
%D
-%D Here the \type{\ruledvbox} just shows the surrounding box
-%D and \type{\vrule} is used to show the centered box.
+%D Here the \type {\ruledvbox} just shows the surrounding box and \type {\vrule} is
+%D used to show the centered box.
%D
%D \def\AnExample#1#2%
%D {\vsize=3cm
@@ -1599,14 +1566,12 @@
%D \stopcombination
%D \stoplinecorrection
%D
-%D This command takes two optional arguments: \type{width} and
-%D \type{height}. Observing readers can see that we use \TEX's
-%D own scanner for grabbing these arguments: \type{#1#} reads
-%D everyting till the next brace and passes it to both rules.
-%D The setting of the box dimensions at the end is needed for
-%D special cases. The dimensions of the surrounding box are kept
-%D intact. This commands handles positive and negative
-%D dimensions (which is why we need two boxes with rules).
+%D This command takes two optional arguments: \type {width} and \type {height}.
+%D Observing readers can see that we use \TEX's own scanner for grabbing these
+%D arguments: \type {#1#} reads everyting till the next brace and passes it to both
+%D rules. The setting of the box dimensions at the end is needed for special cases.
+%D The dimensions of the surrounding box are kept intact. This commands handles
+%D positive and negative dimensions (which is why we need two boxes with rules).
\unexpanded\def\centeredbox#1#% height +/-dimen width +/-dimen
{\bgroup
@@ -1666,8 +1631,8 @@
%D \centerbox <optional specs> {content}
%D \stoptyping
%D
-%D When omitted, the current \type {\hsize} and \type
-%D {\vsize} are used. Local dimensions are supported.
+%D When omitted, the current \type {\hsize} and \type {\vsize} are used. Local
+%D dimensions are supported.
\unexpanded\def\centerbox#1#% optional height +/-dimen width +/-dimen
{\bgroup
@@ -1684,27 +1649,21 @@
%D \macros
%D {setrigidcolumnhsize,rigidcolumnbalance,rigidcolumnlines}
%D
-%D These macros are copied from the \TEX book, page~397, and
-%D extended by a macro that sets the \type{\hsize}.
+%D These macros are copied from the \TEX book, page~397, and extended by a macro
+%D that sets the \type {\hsize}.
%D
%D \starttyping
%D \setrigidcolumnhsize {total width} {distance} {n}
%D \rigidcolumnbalance {box}
%D \stoptyping
%D
-%D Both these macros are for instance used in typesetting
-%D footnotes.
-%D
-%D Men kan het proces van breken enigzins beinvloeden met de
-%D volgende twee switches:
+%D Both these macros are for instance used in typesetting footnotes. The following
+%D flags influence the process.
\newif\ifalignrigidcolumns
\newif\ifstretchrigidcolumns
\newif\iftightrigidcolumns % if true: just a vbox, no depth/noflines/gridsnap corrrections
-%D De eerste switch bepaald het uitlijnen, de tweede rekt de
-%D individuele kolommen op naar \type{\vsize}.
-
\unexpanded\def\setrigidcolumnhsize#1#2#3% todo: \dimexpr
{\xdef\savedrigidhsize{\the\hsize}%
\hsize#1\relax
@@ -1791,9 +1750,8 @@
%D \macros
%D {startvboxtohbox,stopvboxtohbox,convertvboxtohbox}
%D
-%D Here is another of Knuth's dirty tricks, as presented on
-%D pages 398 and 399 of the \TEX book. These macros can be used
-%D like:
+%D Here is another of Knuth's dirty tricks, as presented on pages 398 and 399 of the
+%D \TEX book. These macros can be used like:
%D
%D \starttyping
%D \vbox
@@ -1809,14 +1767,14 @@
%D \egroup
%D \stoptyping
%D
-%D These macros are used in reformatting footnotes, so they do
-%D what they're meant for.
+%D These macros are used in reformatting footnotes, so they do what they're meant
+%D for.
\newdimen\vboxtohboxslack
\newdimen\hboxestohboxslack
-% Create line and fake height of paragraph by messign with heights:
-% a nice hack by DEK himself.
+%D Create line and fake height of paragraph by messign with heights: a nice hack by
+%D DEK himself.
%\unexpanded\def\setvboxtohbox
% {\bgroup
@@ -1933,8 +1891,8 @@
%D \macros
%D {unhhbox}
%D
-%D The next macro is used in typesetting inline headings.
-%D Let's first look at the macro and then show an example.
+%D The next macro is used in typesetting inline headings. Let's first look at the
+%D macro and then show an example.
\newbox \unhhedbox
\newbox \hhbox
@@ -1954,7 +1912,7 @@
\fi
\ht\hhbox\strutht
\dp\hhbox\strutdp
- \ifzeropt\hhboxindent\else % \ifdim\hhboxindent=\zeropoint\else
+ \ifzeropt\hhboxindent\else
\setbox\hhbox\hpack{\kern-\hhboxindent\box\hhbox}%
\hhboxindent\zeropoint
\fi
@@ -1977,10 +1935,9 @@
\afterassignment\dohboxofvbox
\scratchcounter=}
-%D This macro can be used to break a paragraph apart and treat
-%D each line seperately, for instance, making it clickable. The
-%D main complication is that we want to be able to continue the
-%D paragraph, something that's needed in the in line section
+%D This macro can be used to break a paragraph apart and treat each line seperately,
+%D for instance, making it clickable. The main complication is that we want to be
+%D able to continue the paragraph, something that's needed in the in line section
%D headers.
%D
%D \startbuffer
@@ -1999,23 +1956,22 @@
%D
%D \typebuffer
%D
-%D Not that nice a definition, but effective. Note the stretch
-%D we've build in the line that connects the two paragraphs.
+%D Not that nice a definition, but effective. Note the stretch we've build in the
+%D line that connects the two paragraphs.
%D \macros
%D {doifcontent}
%D
-%D When processing depends on the availability of content, one
-%D can give the next macro a try.
+%D When processing depends on the availability of content, one can give the next
+%D macro a try.
%D
%D \starttyping
%D \doifcontent{pre content}{post content}{no content}\somebox
%D \stoptyping
%D
-%D Where \type{\somebox} is either a \type{\hbox} or
-%D \type{\vbox}. If the dimension of this box suggest some
-%D content, the resulting box is unboxed and surrounded by the
-%D first two arguments, else the third arguments is executed.
+%D Where \type {\somebox} is either a \type {\hbox} or \type {\vbox}. If the
+%D dimension of this box suggest some content, the resulting box is unboxed and
+%D surrounded by the first two arguments, else the third arguments is executed.
\unexpanded\def\doifcontent#1#2#3%
{\dowithnextbox
@@ -2049,17 +2005,17 @@
%D
%D \getbuffer
%D
-%D Where the last call of course does not show up in this
-%D document, but definitely generates a confusing message.
+%D Where the last call of course does not show up in this document, but definitely
+%D generates a confusing message.
%D \macros
%D {processboxes}
%D
-%D The next macro gobble boxes and is for instance used for
-%D overlays. First we show the general handler.
+%D The next macro gobble boxes and is for instance used for overlays. First we show
+%D the general handler.
-% we cannot use \futurelet here as we want to skip spaces between
-% boxes (see startoverlay for an example usage)
+% We cannot use \futurelet here as we want to skip spaces between boxes (see
+% startoverlay for an example usage)
% \newbox\processbox % public : this is the one where \nextbox's end up in
%
@@ -2184,8 +2140,7 @@
%D \hbox{\fakebox0}
%D \stoptyping
%D
-%D returns an empty box with the dimensions of the box
-%D specified, here being zero.
+%D returns an empty box with the dimensions of the box specified, here being zero.
\unexpanded\def\fakebox
{\bgroup
@@ -2210,10 +2165,9 @@
%D \rbox{text ...}
%D \stoptyping
%D
-%D Are similar to \type {\vbox}, which means that they also
-%D accept something like \type{to 3cm}, but align to the left,
-%D middle and right. These box types can be used to typeset
-%D paragraphs.
+%D Are similar to \type {\vbox}, which means that they also accept something like
+%D \type {to 3cm}, but align to the left, middle and right. These box types can be
+%D used to typeset paragraphs.
\def\syst_boxes_lrc_process#1{\bgroup\forgetall\let\\\endgraf#1\let\next}
@@ -2225,8 +2179,8 @@
\unexpanded\def\ctop#1#{\vtop#1\syst_boxes_lrc_process\raggedcenter}
\unexpanded\def\rtop#1#{\vtop#1\syst_boxes_lrc_process\raggedright }
-%D The alternatives \type {\tbox} and \type {\bbox} can be used
-%D to properly align boxes, like in:
+%D The alternatives \type {\tbox} and \type {\bbox} can be used to properly align
+%D boxes, like in:
%D
%D \setupexternalfigures[directory={../sample}]
%D \startbuffer
@@ -2288,16 +2242,15 @@
%D \macros
%D {boxofsize}
%D
-%D Sometimes we need to construct a box with a height or
-%D width made up of several dimensions. Instead of cumbersome
-%D additions, we can use:
+%D Sometimes we need to construct a box with a height or width made up of several
+%D dimensions. Instead of cumbersome additions, we can use:
%D
%D \starttyping
%D \boxofsize \vbox 10cm 3cm -5cm {the text to be typeset}
%D \stoptyping
%D
-%D This example demonstrates that one can use positive and
-%D negative values. Dimension registers are also accepted.
+%D This example demonstrates that one can use positive and negative values.
+%D Dimension registers are also accepted.
\newdimen\sizeofbox
@@ -2325,11 +2278,11 @@
\unexpanded\def\limitatelines#1#2% size sentinel
{\dowithnextbox
- {\dimen0=#1\hsize
- \ifdim\wd\nextbox>\dimen0
+ {\scratchdimen#1\hsize
+ \ifdim\wd\nextbox>\scratchdimen
\setbox\nextbox\hbox
- {\advance\dimen0 -.1\hsize
- \limitatetext{\unhbox\nextbox}{\dimen0}{\nobreak#2}}%
+ {\advance\scratchdimen -.1\hsize
+ \limitatetext{\unhbox\nextbox}{\scratchdimen}{\nobreak#2}}%
\fi
\unhbox\nextbox}
\hbox}
@@ -2338,14 +2291,14 @@
{\dowithnextbox
{\bgroup
\par
- \dimen0\ht\nextbox
+ \scratchdimen\ht\nextbox
\ht\nextbox\strutht
\dp\nextbox\strutdp
\hpack{\box\nextbox}
\prevdepth\strutdp
\doloop
- {\advance\dimen0 -\lineheight
- \ifdim\dimen0<\zeropoint
+ {\advance\scratchdimen -\lineheight
+ \ifdim\scratchdimen<\zeropoint
\exitloop
\else
\nobreak
@@ -2527,8 +2480,8 @@
%D \macros
%D {initializeboxstack,savebox,foundbox}
%D
-%D At the cost of some memory, but saving box registers, we
-%D have implemented a box repository.
+%D At the cost of some memory, but saving box registers, we have implemented a box
+%D repository.
%D
%D \starttyping
%D \initializeboxstack{one}
@@ -2665,9 +2618,8 @@
%D \macros
%D {removedepth, obeydepth}
%D
-%D While \type {\removedepth} removes the preceding depth,
-%D \type {\obeydepth} makes sure we have depth. Both macros
-%D leave the \type {\prevdepth} untouched.
+%D While \type {\removedepth} removes the preceding depth, \type {\obeydepth} makes
+%D sure we have depth. Both macros leave the \type {\prevdepth} untouched.
\unexpanded\def\removedepth
{\ifvmode
@@ -2700,8 +2652,8 @@
%D \macros
%D {makestrutofbox}
%D
-%D This macro sets the dimensions of a box to those of a strut. Sort of obsolete
-%D so it will go away.
+%D This macro sets the dimensions of a box to those of a strut. Sort of obsolete so
+%D it will go away.
\unexpanded\def\makestrutofbox % not used
{\afterassignment\syst_boxes_makestrutofbox\c_boxes_register}
@@ -2714,9 +2666,8 @@
%D \macros
%D {raisebox,lowerbox}
%D
-%D Some more box stuff, related to positioning (under
-%D construction). Nice stuff for a tips and tricks maps
-%D article.
+%D Some more box stuff, related to positioning (under construction). Nice stuff for
+%D a tips and tricks maps article.
%D
%D \starttyping
%D \raisebox{100pt}\hbox{test}
@@ -2895,12 +2846,6 @@
%D A bit dirty:
-% \unexpanded\def\nodestostring#1% \cs {content}
-% {\dowithnextbox{\edef#1{\syst_boxes_nodestostring}}\hbox}
-%
-% \def\syst_boxes_nodestostring
-% {\clf_boxtostring\nextbox}
-
\unexpanded\def\nodestostring#1#2% more tolerant for #2=\cs
{\begingroup
\setbox\nextbox\hbox{#2}%
@@ -2995,7 +2940,11 @@
%D This one keeps dimensions and sets the shift field (and so it's more for testing
%D than for real usage):
-\unexpanded\def\shiftbox{\clf_shiftbox}
+\unexpanded\def\shiftbox {\clf_shiftbox}
+\unexpanded\def\vpackbox {\clf_vpackbox}
+\unexpanded\def\hpackbox {\clf_hpackbox}
+\unexpanded\def\vpackedbox{\clf_vpackedbox}
+\unexpanded\def\hpackedbox{\clf_hpackedbox}
%D This one has been moved from a 2 decade old file. It makes something boxed
%D sit on the baseline.
diff --git a/Master/texmf-dist/tex/context/base/mkiv/supp-box.mkxl b/Master/texmf-dist/tex/context/base/mkiv/supp-box.mkxl
new file mode 100644
index 00000000000..e6ab96e8929
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/supp-box.mkxl
@@ -0,0 +1,2952 @@
+%D \module
+%D [ file=supp-box,
+%D version=1995.10.10,
+%D title=\CONTEXT\ Support Macros,
+%D subtitle=Boxes,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Support Macros / Boxes}
+
+\unprotect
+
+\registerctxluafile{supp-box}{optimize}
+
+% This file is partially cleaned up.
+
+%D First some defaults:
+
+\fixupboxesmode\plusone
+
+%D And some dimensions:
+
+\newdimen\givenwidth
+\newdimen\givenheight
+\newdimen\givendepth
+
+%D \macros
+%D {dontcomplain}
+%D
+%D The next macro suppresses over- and underfull messages which often makes sense
+%D when we deal with boxes.
+
+\unexpanded\def\dontcomplain
+ {\hbadness\plustenthousand
+ \vbadness\plustenthousand
+ \hfuzz \maxdimen
+ \vfuzz \maxdimen}
+
+%D This module implements some box manipulation macros. Some are quite simple, some
+%D are more advanced and when understood well, all can be of use.
+%D
+%D \macros
+%D {strutdp,strutht,strutwd}
+%D
+%D The next shortcuts save memory and keying. The width is normally zero points (if
+%D not, you're in trouble). These shortcuts can be used like a dimension, opposite
+%D to the core macros \type {\strutdepth} and alike, which are values.
+
+\def\strutdp {\dp\strutbox}
+\def\strutht {\ht\strutbox}
+\def\strutwd {\wd\strutbox}
+\def\struthtdp{\htdp\strutbox}
+\def\strutgap {\dimexpr\ht\strutbox-\dp\strutbox\relax}
+
+%D \macros
+%D {voidbox,nextbox}
+%D
+%D Let's start with an easy one. The next macro hides the ugly \type {@} in \type
+%D {\voidb@x}.
+
+\ifdefined\voidbox \else \newbox\voidbox \fi
+\ifdefined\nextbox \else \newbox\nextbox \fi
+
+%D \macros
+%D {nextdepth}
+%D
+%D Let's start with a rather simple declaration. Sometimes we need to save the \TEX\
+%D \DIMENSION\ \type{\prevdepth} and append it later on. The name \type {\nextdepth}
+%D suits this purpose well.
+
+\newdimen\nextdepth
+
+%D \macros
+%D {smashbox, smashedbox}
+%D
+%D Smashing is introduced in \PLAIN\ \TEX, and stands for reducing the dimensions of
+%D a box to zero. The most resolute one is presented first.
+
+\unexpanded\def\smashbox#1%
+ {\wd#1\zeropoint
+ \ht#1\zeropoint
+ \dp#1\zeropoint}
+
+\unexpanded\def\smashboxed#1%
+ {\wd#1\zeropoint
+ \ht#1\zeropoint
+ \dp#1\zeropoint
+ \box#1\relax}
+
+%D \macros
+%D {hsmashbox,vsmashbox}
+%D
+%D Smashing can be used for overlaying boxes. Depending on the mode, horizontal or
+%D vertical, one can use:
+
+\unexpanded\def\hsmashbox#1%
+ {\wd#1\zeropoint}
+
+\unexpanded\def\vsmashbox#1%
+ {\ht#1\zeropoint
+ \dp#1\zeropoint}
+
+%D The next implementation is less sensitive for spurious spaces.
+
+\newcount\c_boxes_register
+
+\unexpanded\def\smashbox
+ {\afterassignment\syst_boxes_smash_boxes_register\c_boxes_register}
+
+\def\syst_boxes_smash_boxes_register
+ {\wd\c_boxes_register\zeropoint
+ \ht\c_boxes_register\zeropoint
+ \dp\c_boxes_register\zeropoint}
+
+\unexpanded\def\hsmashbox
+ {\afterassignment\syst_boxes_hsmashed_boxes_register\c_boxes_register}
+
+\def\syst_boxes_hsmashed_boxes_register
+ {\wd\c_boxes_register\zeropoint}
+
+\unexpanded\def\vsmashbox
+ {\afterassignment\syst_boxes_vsmashed_boxes_register\c_boxes_register}
+
+\def\syst_boxes_vsmashed_boxes_register
+ {\ht\c_boxes_register\zeropoint
+ \dp\c_boxes_register\zeropoint}
+
+\unexpanded\def\smashedbox
+ {\afterassignment\syst_boxes_smashed_boxes_register\c_boxes_register}
+
+\unexpanded\def\syst_boxes_smashed_boxes_register
+ {\wd\c_boxes_register\zeropoint
+ \ht\c_boxes_register\zeropoint
+ \dp\c_boxes_register\zeropoint
+ \box\c_boxes_register}
+
+%D \macros
+%D {hsmash,vsmash,
+%D hsmashed,vsmashed}
+%D
+%D While the previous macros expected a \BOX, the next act on a content. They are
+%D some subtle differences betreen the smash and smashed alternatives. The later
+%D ones reduce all dimensions to zero.
+
+\unexpanded\def\hsmash {\bgroup\dowithnextboxcs\syst_boxes_hsmashed_nextbox\hbox}
+\unexpanded\def\vsmash {\bgroup\dowithnextboxcs\syst_boxes_vsmashed_nextbox\vbox}
+\unexpanded\def\hsmashed{\bgroup\dowithnextboxcs\syst_boxes_smashed_nextbox \hbox}
+\unexpanded\def\vsmashed{\bgroup\dowithnextboxcs\syst_boxes_smashed_nextbox \vbox}
+
+\unexpanded\def\syst_boxes_hsmashed_nextbox
+ {\wd\nextbox\zeropoint
+ \box\nextbox
+ \egroup}
+
+\unexpanded\def\syst_boxes_vsmashed_nextbox
+ {\ht\nextbox\zeropoint
+ \dp\nextbox\zeropoint
+ \box\nextbox
+ \egroup}
+
+\unexpanded\def\syst_boxes_smashed_nextbox
+ {\ht\nextbox\zeropoint
+ \dp\nextbox\zeropoint
+ \wd\nextbox\zeropoint
+ \box\nextbox
+ \egroup}
+
+%D \macros
+%D {smashedhbox,smashedvbox}
+%D
+%D Also handy (all dimensions zeroed):
+%D
+%D \starttyping
+%D \smashedhbox to ... {...}
+%D \smashedvbox to ... {...}
+%D \stoptyping
+
+\unexpanded\def\smashedhbox{\hpack\bgroup\dowithnextboxcs\syst_boxes_smashed_nextbox\hbox}
+\unexpanded\def\smashedvbox{\vpack\bgroup\dowithnextboxcs\syst_boxes_smashed_nextbox\vbox}
+
+%D First we define a helper. We use a \LUATEX\ feature in order to avoid
+%D mathpalettes.
+
+\newcount\c_boxes_math_style
+
+\unexpanded\def\syst_boxes_math_set_nextbox#1%
+ {\c_boxes_math_style\mathstyle
+ \setbox\nextbox\hbox{\normalstartimath\mathsurround\zeropoint\triggermathstyle\c_boxes_math_style{#1}\normalstopimath}}
+
+%D \macros
+%D {smash}
+%D
+%D This smash alternative takes an optional arg [whdtb] as well as is potentially
+%D catcode safer. It is needed by the math module (although the \type {\leavevmode}
+%D is not added here).
+
+\unexpanded\def\smash
+ {\begingroup
+ \futureexpandis[\syst_boxes_smash_yes\syst_boxes_smash_nop}
+
+\def\syst_boxes_smash_nop
+ {\edef\m_boxes_smash_options{hd}%
+ \futurelet\nexttoken\syst_boxes_smash_indeed}
+
+\def\syst_boxes_smash_yes[#1]%
+ {\edef\m_boxes_smash_options{#1}%
+ \futurelet\nexttoken\syst_boxes_smash_indeed}
+
+\def\syst_boxes_smash_indeed
+ {\ifmmode
+ \expandafter\syst_boxes_smash_math
+ \orelse\ifx\nexttoken\bgroup
+ \expandafter\syst_boxes_smash_hbox
+ \else
+ \expandafter\syst_boxes_smash_text
+ \fi}
+
+\def\syst_boxes_smash_math#1%
+ {\syst_boxes_math_set_nextbox{#1}%
+ \syst_boxes_smash_process}
+
+\def\syst_boxes_smash_hbox
+ {\dowithnextboxcs\syst_boxes_smash_process\hbox}
+
+\def\syst_boxes_smash_text#1%
+ {\setbox\nextbox\hbox{#1}%
+ \syst_boxes_smash_process}
+
+\def\syst_boxes_smash_process
+ {\expandafter\syst_boxes_smash_process_option\m_boxes_smash_options\relax
+ \box\nextbox
+ \endgroup}
+
+\installcorenamespace {smashoptions}
+
+\setvalue{\??smashoptions w}{\wd\nextbox\zeropoint}
+\setvalue{\??smashoptions h}{\ht\nextbox\zeropoint}
+\setvalue{\??smashoptions d}{\dp\nextbox\zeropoint}
+\setvalue{\??smashoptions t}{\ht\nextbox\zeropoint}
+\setvalue{\??smashoptions b}{\dp\nextbox\zeropoint}
+
+\def\syst_boxes_smash_process_option#1%
+ {\ifx#1\relax\else
+ \begincsname\??smashoptions#1\endcsname
+ \expandafter\syst_boxes_smash_process_option
+ \fi}
+
+\def\syst_boxes_lower_nextbox_dp
+ {\setbox\nextbox\hpack{\lower\dp\nextbox\box\nextbox}}
+
+%D \starttabulate[|l|l|]
+%D \NC w \NC \ruledhbox{\smash [w]{This is some great smashing, isn't it?}} \NC \NR
+%D \NC h \NC \ruledhbox{\smash [h]{This is some great smashing, isn't it?}} \NC \NR
+%D \NC d \NC \ruledhbox{\smash [d]{This is some great smashing, isn't it?}} \NC \NR
+%D \NC tb \NC \ruledhbox{\smash [tb]{This is some great smashing, isn't it?}} \NC \NR
+%D \NC whd \NC \ruledhbox{\smash[whd]{This is some great smashing, isn't it?}} \NC \NR
+%D \stoptabulate
+
+%D \macros
+%D {phantom, hphantom, vphantom, mathstrut}
+%D
+%D The next implementation of \type {\phantom} cum suis does not grab an argument in
+%D the non||math case, which is better.
+%D
+%D Due to a complicated call to \type {\mathpallete} and thereby \type
+%D {\mathchoice}, the next macro looks ugly. We also take care of non||braced
+%D arguments.
+
+\unexpanded\def\phantom {\begingroup\futurelet\nexttoken\syst_boxes_phantom_indeed }
+\unexpanded\def\vphantom{\begingroup\futurelet\nexttoken\syst_boxes_phantom_indeed_v}
+\unexpanded\def\hphantom{\begingroup\futurelet\nexttoken\syst_boxes_phantom_indeed_h}
+
+\def\syst_boxes_phantom_math #1{\syst_boxes_math_set_nextbox{#1}\syst_boxes_phantom_make }
+\def\syst_boxes_phantom_math_v#1{\syst_boxes_math_set_nextbox{#1}\syst_boxes_phantom_make_v}
+\def\syst_boxes_phantom_math_h#1{\syst_boxes_math_set_nextbox{#1}\syst_boxes_phantom_make_h}
+
+\def\syst_boxes_phantom_hbox {\dowithnextboxcs\syst_boxes_phantom_make \hbox} % always hbox
+\def\syst_boxes_phantom_hbox_v{\dowithnextboxcs\syst_boxes_phantom_make_v\hbox} % always hbox
+\def\syst_boxes_phantom_hbox_h{\dowithnextboxcs\syst_boxes_phantom_make_h\hbox} % always hbox
+
+\def\syst_boxes_phantom_text #1{\setbox\nextbox\hbox{#1}\syst_boxes_phantom_make } % always hbox
+\def\syst_boxes_phantom_text_v#1{\setbox\nextbox\hbox{#1}\syst_boxes_phantom_make_v} % always hbox
+\def\syst_boxes_phantom_text_h#1{\setbox\nextbox\hbox{#1}\syst_boxes_phantom_make_h} % always hbox
+
+\def\syst_boxes_phantom_indeed
+ {\ifmmode
+ \expandafter\syst_boxes_phantom_math
+ \orelse\ifx\nexttoken\bgroup
+ \expandafter\syst_boxes_phantom_hbox
+ \else
+ \expandafter\syst_boxes_phantom_text
+ \fi}
+
+\def\syst_boxes_phantom_indeed_v
+ {\ifmmode
+ \expandafter\syst_boxes_phantom_math_v
+ \orelse\ifx\nexttoken\bgroup
+ \expandafter\syst_boxes_phantom_hbox_v
+ \else
+ \expandafter\syst_boxes_phantom_text_v
+ \fi}
+
+\def\syst_boxes_phantom_indeed_h
+ {\ifmmode
+ \expandafter\syst_boxes_phantom_math_h
+ \orelse\ifx\nexttoken\bgroup
+ \expandafter\syst_boxes_phantom_hbox_h
+ \else
+ \expandafter\syst_boxes_phantom_text_h
+ \fi}
+
+\def\syst_boxes_phantom_make
+ {\setbox\scratchbox\emptyhbox
+ \ht\scratchbox\ht\nextbox
+ \dp\scratchbox\dp\nextbox
+ \wd\scratchbox\wd\nextbox
+ \box\scratchbox
+ \endgroup}
+
+\def\syst_boxes_phantom_make_v
+ {\setbox\scratchbox\emptyhbox
+ \ht\scratchbox\ht\nextbox
+ \dp\scratchbox\dp\nextbox
+ \box\scratchbox
+ \endgroup}
+
+\def\syst_boxes_phantom_make_h
+ {\setbox\scratchbox\emptyhbox
+ \wd\scratchbox\wd\nextbox
+ \box\scratchbox
+ \endgroup}
+
+%D We also define plain's \type {\mathstrut}.
+
+\unexpanded\def\mathstrut{\vphantom(} % can be made faster by inlining
+
+%D \macros
+%D {getboxheight}
+%D
+%D Although often needed, \TEX\ does not support arithmics like:
+%D
+%D \starttyping
+%D \dimen0 = \ht0 + \dp0
+%D \stoptyping
+%D
+%D so we implemented:
+%D
+%D \starttyping
+%D \getboxheight ... \of \box...
+%D \stoptyping
+%D
+%D For instance,
+%D
+%D \starttyping
+%D \getboxheight \dimen0 \of \box0
+%D \getboxheight \someheight \of \box \tempbox
+%D \stoptyping
+%D
+%D The implementation is rather stupid:
+%D
+%D \starttyping
+%D \def\getboxheight#1\of#2\box#3%
+%D {#1\ht#3\advance#1\dp#3\relax}
+%D \stoptyping
+%D
+%D The next alternative is slightly more clever, since it accepts \type {{12}} as
+%D well as \type {12} as box number.
+
+\unexpanded\def\getboxheight#1\of#2\box#3%
+ {\def\next{#1\htdp\c_boxes_register}%
+ \afterassignment\next\c_boxes_register=#3}
+
+%D For a long time the following three macros were part of the grid snapping core
+%D module, but it makes more sense to have them here so that users can see them.
+%D
+%D \macros
+%D {getnoflines, getroundednoflines, getrawnoflines}
+%D
+%D Het commando \type {\getnoflines} converteert een hoogte (dimensie) in een aantal
+%D regels en kent dit toe aan \type {\noflines}.
+%D
+%D \starttyping
+%D \getnoflines{dimensie}
+%D \stoptyping
+%D
+%D Er wordt gedeeld door \type {\openlineheight} en een hoogte van~0pt komt overeen
+%D met 0~regels. The raw alternative does not round.
+%D
+%D For a long time we had:
+%D
+%D \starttyping
+%D \newcount\noflines
+%D \newdimen\noflinesheight
+%D
+%D \def\dogetnoflines#1#2%
+%D {\noflinesheight#2\relax
+%D \ifzeropt\noflinesheight
+%D \noflines\zerocount
+%D \else
+%D \divide\noflinesheight \openlineheight
+%D \noflines\noflinesheight
+%D #1\ifdim\noflines\openlineheight=#2\relax \else
+%D \advance\noflines\ifdim#2>\zeropoint\plusone\else\minusone\fi
+%D \fi\fi
+%D \fi}
+%D
+%D \def\getnoflines {\dogetnoflines\iftrue } % compensated
+%D \def\getrawnoflines{\dogetnoflines\iffalse} % no compensation
+%D \stoptyping
+%D
+%D A more recent variant is:
+
+\ifx\roundingeps\undefined \newdimen\roundingeps \roundingeps=10sp \fi
+
+\newcount\noflines
+\newdimen\noflinesheight
+
+\unexpanded\def\getnoflines#1%
+ {\noflinesheight#1\relax
+ \ifzeropt\noflinesheight
+ \noflines\zerocount
+ \orelse\ifdim\noflinesheight>\zeropoint
+ \advance\noflinesheight-\roundingeps
+ \divide\noflinesheight\openlineheight
+ \noflines\noflinesheight
+ \advance\noflines\plusone
+ \else
+ \advance\noflinesheight\roundingeps
+ \divide\noflinesheight\openlineheight
+ \noflines\noflinesheight
+ \advance\noflines\minusone
+ \fi}
+
+\unexpanded\def\getroundednoflines#1%
+ {\noflinesheight#1\relax
+ \ifzeropt\noflinesheight
+ \noflines\zerocount
+ \orelse\ifdim\noflinesheight>\zeropoint
+ \advance\noflinesheight\roundingeps
+ \divide\noflinesheight\openlineheight
+ \noflines\noflinesheight
+ \else
+ \advance\noflinesheight-\roundingeps
+ \divide\noflinesheight\openlineheight
+ \noflines\noflinesheight
+ \fi}
+
+\unexpanded\def\getrawnoflines#1%
+ {\noflinesheight#1\relax
+ \ifzeropt\noflinesheight
+ \noflines\zerocount
+ \orelse\ifdim\noflinesheight>\zeropoint
+ \advance\noflinesheight\roundingeps
+ \advance\noflinesheight.5\openlineheight
+ \divide\noflinesheight\openlineheight
+ \noflines\noflinesheight
+ \else
+ \advance\noflinesheight-\roundingeps
+ \advance\noflinesheight-.5\openlineheight
+ \divide\noflinesheight\openlineheight
+ \noflines\noflinesheight
+ \fi}
+
+%D Let's proof that it works:
+%D
+%D \startbuffer
+%D \scratchdimen\dimexpr(3pt) \getnoflines\scratchdimen 1=\the\noflines \endgraf
+%D \scratchdimen\dimexpr(10\lineheight) \getnoflines\scratchdimen 10=\the\noflines \endgraf
+%D \scratchdimen\dimexpr(10.1\lineheight) \getnoflines\scratchdimen 11=\the\noflines \endgraf
+%D \scratchdimen\dimexpr(10.5\lineheight) \getnoflines\scratchdimen 11=\the\noflines \endgraf
+%D \scratchdimen\dimexpr(10.9\lineheight) \getnoflines\scratchdimen 11=\the\noflines \endgraf
+%D \scratchdimen\dimexpr(10\lineheight+3pt) \getnoflines\scratchdimen 11=\the\noflines \endgraf
+%D \scratchdimen\dimexpr(10\lineheight+3sp) \getnoflines\scratchdimen 10=\the\noflines \endgraf
+%D \scratchdimen\dimexpr(10\lineheight-3sp) \getnoflines\scratchdimen 10=\the\noflines \endgraf
+%D
+%D \scratchdimen\dimexpr(3pt) \getrawnoflines\scratchdimen 0=\the\noflines \endgraf
+%D \scratchdimen\dimexpr(10\lineheight) \getrawnoflines\scratchdimen 10=\the\noflines \endgraf
+%D \scratchdimen\dimexpr(10.1\lineheight) \getrawnoflines\scratchdimen 10=\the\noflines \endgraf
+%D \scratchdimen\dimexpr(10.5\lineheight) \getrawnoflines\scratchdimen 11=\the\noflines \endgraf
+%D \scratchdimen\dimexpr(10.9\lineheight) \getrawnoflines\scratchdimen 11=\the\noflines \endgraf
+%D \scratchdimen\dimexpr(10\lineheight+3pt) \getrawnoflines\scratchdimen 10=\the\noflines \endgraf
+%D \scratchdimen\dimexpr(10\lineheight+3sp) \getrawnoflines\scratchdimen 10=\the\noflines \endgraf
+%D \scratchdimen\dimexpr(10\lineheight-3sp) \getrawnoflines\scratchdimen 10=\the\noflines \endgraf
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+%D \macros
+%D {determinenoflines}
+%D
+%D The next macro determines the number of lines and returns it it \type
+%D {\noflines}. The macro works reasonable well as long as the content can be
+%D unboxed.
+%D
+%D \starttyping
+%D \determinenoflines{test\\test}
+%D \determinenoflines{\bfd test\\test}
+%D \determinenoflines{\definedfont[Sans at 40pt]test\\test}
+%D \stoptyping
+
+\def\syst_boxes_determine_noflines % can be mkiv'd
+ {\beginofshapebox
+ \unvbox\nextbox
+ \endofshapebox
+ \globalscratchcounter\zerocount
+ \reshapebox{\global\advance\globalscratchcounter\plusone}%
+ \expandafter\egroup\expandafter\noflines\the\globalscratchcounter\relax}
+
+\unexpanded\def\determinenoflines
+ {\bgroup
+ \forgetall
+ \let\crlf\endgraf
+ \let\\\endgraf
+ \dowithnextboxcs\syst_boxes_determine_noflines\vbox}
+
+%D \macros
+%D {doiftextelse, doiftext}
+%D
+%D When \type {\doifelse} cum suis hopelessly fail, for instance because we pass
+%D data, we can fall back on the next macro:
+%D
+%D \starttyping
+%D \doiftextelse {data} {then branch} {else branch}
+%D \doiftext {data} {then branch}
+%D \stoptyping
+
+\unexpanded\def\doifelsetext#1%
+ {\begingroup
+ \setbox\scratchbox\hbox % no \hpack because we can have fallbacks
+ {\settrialtypesetting
+ \ignorespaces#1\removeunwantedspaces}%
+ \ifzeropt\wd\scratchbox
+ \endgroup\expandafter\secondoftwoarguments
+ \else
+ \endgroup\expandafter\firstoftwoarguments
+ \fi}
+
+\unexpanded\def\doiftext#1%
+ {\begingroup
+ \setbox\scratchbox\hbox % no \hpack because we can have fallbacks
+ {\settrialtypesetting
+ \ignorespaces#1\removeunwantedspaces}%
+ \ifzeropt\wd\scratchbox
+ \endgroup\expandafter\gobbleoneargument
+ \else
+ \endgroup\expandafter\firstofoneargument
+ \fi}
+
+% more efficient but maybe fragile:
+%
+% \nospacing#1}%
+
+\let\doiftextelse\doifelsetext
+
+%D \macros
+%D {dowithnextbox,nextbox}
+%D
+%D Sometimes we want a macro to grab a box and do something on the content. One
+%D could pass an argument to a box, but this can violate the specific \CATCODES\ of
+%D its content and leads to unexpected results. The next macro treats the following
+%D braced text as the content of a box and manipulates it afterwards in a predefined
+%D way.
+%D
+%D The first argument specifies what to do with the content. This content is
+%D available in \type {\nextbox}. The second argument is one of \type {\hbox}, \type
+%D {\vbox} or \type {\vtop}. The third argument must be grouped with \type {\bgroup}
+%D and \type {\egroup}, \type {{...}} or can be a \type {\box} specification.
+%D
+%D In \CONTEXT\ this macro is used for picking up a box and treating it according to
+%D earlier specifications. We use for instance something like:
+%D
+%D \starttyping
+%D \def\getfloat%
+%D {\def\handlefloat{...\box\nextbox...}
+%D \dowithnextboxcs\handlefloat\vbox}
+%D \stoptyping
+%D
+%D instead of:
+%D
+%D \starttyping
+%D \def\getfloat#1%
+%D {...#1...}
+%D \stoptyping
+%D
+%D In this implementation the \type {\aftergroup} construction is needed because
+%D \type {\afterassignment} is executed inside the box.
+
+\unexpanded\def\dowithnextbox#1%
+ {\def\syst_boxes_with_next_box{#1}%
+ \afterassignment\syst_boxes_with_next_box_indeed
+ \setbox\nextbox}
+
+\def\syst_boxes_with_next_box_indeed
+ {\aftergroup\syst_boxes_with_next_box}
+
+\unexpanded\def\dowithnextboxcs#1%
+ {\let\syst_boxes_with_next_box#1%
+ \afterassignment\syst_boxes_with_next_box_indeed
+ \setbox\nextbox}
+
+%D So in fact we get:
+%D
+%D \starttyping
+%D \setbox\nextbox { \aftergroup\syst_boxes_with_next_box ... }
+%D \stoptyping
+%D
+%D or
+%D
+%D \starttyping
+%D \setbox\nextbox { ... } \syst_boxes_with_next_box
+%D \stoptyping
+%D
+%D A slower but more versatile implementation is:
+%D
+%D \starttyping
+%D \unexpanded\def\dowithnextbox#1#2%
+%D {\def\syst_boxes_with_next_box{#1}%
+%D \ifx#2\hbox
+%D \afterassignment\syst_boxes_with_next_box_indeed
+%D \else\ifx#2\vbox
+%D \afterassignment\syst_boxes_with_next_box_indeed
+%D \else\ifx#2\vtop
+%D \afterassignment\syst_boxes_with_next_box_indeed
+%D \else\ifx#2\normalvcenter
+%D \afterassignment\syst_boxes_with_next_box_indeed
+%D \else
+%D \afterassignment\syst_boxes_with_next_box
+%D \fi\fi\fi\fi
+%D \setbox\nextbox#2}
+%D \stoptyping
+%D
+%D This alternative also accepts \type {\box0} and alike, but we don't really need
+%D this functionality now.
+
+%D \macros
+%D {nextboxht,nextboxwd,nextboxdp,flushnextbox}
+%D
+%D The next couple of shortcuts saves us memory as well as \type {{}}'s in passing
+%D parameters.
+
+\def\nextboxht {\ht\nextbox}
+\def\nextboxwd {\wd\nextbox}
+\def\nextboxdp {\dp\nextbox}
+\def\nextboxhtdp{\htdp\nextbox}
+
+\unexpanded\def\flushnextbox{\box\nextbox}
+
+%D \macros
+%D {dowithnextboxcontent}
+%D
+%D But, occasionally we do need to pass some local settings without wanting to use
+%D additional grouping. Therefore we provide:
+%D
+%D \starttyping
+%D \dowithnextboxcontent{inside}{after}{box content}
+%D \stoptyping
+%D
+%D {\em todo: Search source for potential usage!}
+
+\unexpanded\def\dowithnextboxcontent#1#2% inside, after
+ {\def\syst_boxes_with_next_box_one{#2}%
+ \def\syst_boxes_with_next_box_two{#1}%
+ \afterassignment\syst_boxes_with_next_box_content_indeed
+ \setbox\nextbox}
+
+\unexpanded\def\dowithnextboxcontentcs#1#2% inside, after
+ {\let\syst_boxes_with_next_box_one#2%
+ \let\syst_boxes_with_next_box_two#1%
+ \afterassignment\syst_boxes_with_next_box_content_indeed
+ \setbox\nextbox}
+
+\def\syst_boxes_with_next_box_content_indeed
+ {\syst_boxes_with_next_box_two\aftergroup\syst_boxes_with_next_box_one}
+
+%D \macros
+%D {llap, rlap, tlap, blap, clap}
+%D
+%D Some well known friends, but we implement them our own way. We want the macros to
+%D work in both math and text mode.
+
+\def\dodorlap{\hpack to \zeropoint{\box\nextbox\hss}\endgroup}
+\def\dodollap{\hpack to \zeropoint{\hss\box\nextbox}\endgroup}
+\def\dodoclap{\hpack to \zeropoint{\hss\box\nextbox\hss}\endgroup}
+
+\def\dorlap{\begingroup\dowithnextboxcs\dodorlap\hbox}
+\def\dollap{\begingroup\dowithnextboxcs\dodollap\hbox}
+\def\doclap{\begingroup\dowithnextboxcs\dodoclap\hbox}
+
+\def\domathclap{\mathpalette\dodomathclap} \def\dodomathclap#1#2{\doclap{\normalstartimath\mathsurround\zeropoint#1#2\normalstopimath}}
+\def\domathllap{\mathpalette\dodomathllap} \def\dodomathllap#1#2{\dollap{\normalstartimath\mathsurround\zeropoint#1#2\normalstopimath}}
+\def\domathrlap{\mathpalette\dodomathrlap} \def\dodomathrlap#1#2{\dorlap{\normalstartimath\mathsurround\zeropoint#1#2\normalstopimath}}
+
+\unexpanded\def\rlap{\mathortext\domathrlap\dorlap}
+\unexpanded\def\llap{\mathortext\domathllap\dollap}
+\unexpanded\def\clap{\mathortext\domathclap\doclap}
+
+\def\dodotlap{\vpack to \zeropoint{\vss\box\nextbox}\endgroup}
+\def\dodoblap{\vpack to \zeropoint{\box\nextbox\vss}\endgroup}
+
+\unexpanded\def\tlap{\begingroup\dowithnextboxcs\dodotlap\vbox}
+\unexpanded\def\blap{\begingroup\dowithnextboxcs\dodoblap\vbox}
+
+%D \macros
+%D {beginofshapebox,
+%D reshapebox, doreshapebox,
+%D flushshapebox,
+%D innerflushshapebox,
+%D shapebox,
+%D ifreshapingbox}
+%D
+%D The next utility macro originates from some linenumbering mechanism. Due to
+%D \TEX's advanced way of typesetting paragraphs, it's not easy to do things on a
+%D line||by||line basis. This macro is able to reprocess a given box and can act
+%D upon its vertical boxed components, such as lines. The unwinding sequence in this
+%D macro is inspired by a \NTG\ workshop of David Salomon in June 1992.
+%D
+%D First we have to grab the piece of text we want to act upon. This is done by
+%D means of the duo macros:
+%D
+%D \starttyping
+%D \beginofshapebox
+%D a piece of text
+%D \endofshapebox
+%D \stoptyping
+%D
+%D When all texts is collected, we can call \type {\reshapebox} and do something
+%D with it's vertical components. We can make as much passes as needed. When we're
+%D done, the box can be unloaded with \type {\flushshapebox}. The only condition in
+%D this scheme is that \type {\reshapebox} must somehow unload the \BOX\ \type
+%D {\shapebox}.
+%D
+%D An important aspect is that the content is unrolled bottom||up. The next example
+%D illustrates this maybe unexpected characteristic.
+%D
+%D \startbuffer
+%D \beginofshapebox
+%D \em \input tufte
+%D \endofshapebox
+%D
+%D \newcounter\LineNumber
+%D
+%D \reshapebox
+%D {\doglobal\increment\LineNumber
+%D \hbox{\llap{\LineNumber\hskip2em}\box\shapebox}}
+%D
+%D \flushshapebox
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D As we can see, when some kind of numbering is done, we have to add a second pass.
+%D
+%D \startbuffer
+%D \newcounter\LineNumber
+%D \newcounter\NumberOfLines
+%D
+%D \reshapebox
+%D {\doglobal\increment\NumberOfLines
+%D \box\shapebox}
+%D
+%D \reshapebox
+%D {\doglobal\increment\LineNumber
+%D \hbox
+%D {\llap{\LineNumber\ (\NumberOfLines)\hskip2em}%
+%D \box\shapebox}%
+%D \doglobal\decrement\NumberOfLines}
+%D
+%D \flushshapebox
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D This example shows that the content of the box is still available after flushing.
+%D Another feature is that only the last reshaping counts. Multiple reshaping can be
+%D done by:
+%D
+%D \startbuffer
+%D \beginofshapebox
+%D \flushshapebox
+%D \endofshapebox
+%D
+%D \reshapebox
+%D {\doglobal\increment\LineNumber
+%D \hbox{\llap{$\star$\hskip1em}\box\shapebox}%
+%D \doglobal\decrement\NumberOfLines}
+%D
+%D \flushshapebox
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D The macros are surprisingly easy to follow and in fact introduce no new concepts.
+%D Nearly all books on \TEX\ show similar solutions for unwinding \BOXES.
+%D
+%D Some macros, like footnote ones, can be sensitive for reshaping, which can result
+%D in an endless loop. We therefore offer:
+%D
+%D \starttyping
+%D \ifreshapingbox
+%D \stoptyping
+%D
+%D Some \CONTEXT\ commands are protected this way. Anyhow, reshaping is aborted
+%D after 100 dead cycles.
+%D
+%D By the way, changing the height and depth of \BOX\ \type {\shapebox} results in
+%D bad spacing. This means that for instance linenumbers etc. should be given zero
+%D height and depth before being lapped into the margin. The previous examples
+%D ignore this side effect, but beware!
+
+\newif \ifsomeshapeleft
+\newif \ifreshapingbox
+\newif \ifreshapingfailed % may save redundant runs
+
+\newbox \shapebox
+\newcount \shapepenalty
+\newdimen \shapekern
+\newskip \shapeskip
+
+\newbox \newshapebox
+\newbox \oldshapebox
+\newbox \tmpshapebox
+
+\newcount \shapecounter
+
+\newevery \everyshapebox \relax
+
+\def\shapesignal{.12345678pt} % or 12345sp
+
+\unexpanded\def\reshapebox#1%
+ {\doreshapebox
+ {#1}%
+ {\penalty\shapepenalty}%
+ {\kern \shapekern }%
+ {\vskip \shapeskip }}
+
+\def\doreshapebox#1#2#3#4% \shapebox, \shapepenalty, \shapekern, \shapeskip
+ {\global\reshapingfailedfalse
+ \ifzeropt\ht\oldshapebox
+ \setbox\newshapebox\emptyvbox
+ \else
+ \setbox\newshapebox\vbox % can be \vpack
+ {\unvcopy\oldshapebox
+ \setbox\newshapebox\emptybox
+ \shapecounter\zerocount
+ \doloop{\dodoreshapebox{#1}{#2}{#3}{#4}}}%
+ \setbox\newshapebox\box\tmpshapebox
+ \fi}
+
+\ifx\originalshapebox\undefined \let\originalshapebox\oldshapebox \fi
+
+% We will turn this into a \MKIV\ variant (we can use \type {\vpack} too).
+
+\unexpanded\def\insertshapesignal
+ {\hpack to \shapesignal{\strut\hss}% plus \strut
+ \prevdepth\strutdp} % never \nointerlineskip
+
+\unexpanded\def\restoreshapebox % compensates for the signal
+ {\global\setbox\tmpshapebox\vbox{\vskip-\lineheight\unvcopy\oldshapebox}}
+
+\def\dodoreshapebox#1#2#3#4% \shapebox, \shapepenalty, \shapekern, \shapeskip
+ {\ifnum\lastnodetype=\gluenodecode
+ \shapeskip\lastskip
+ \global\setbox\tmpshapebox\vbox{#4\unvbox\tmpshapebox}%
+ \unskip
+ \orelse\ifnum\lastnodetype=\kernnodecode
+ \shapekern\lastkern
+ \global\setbox\tmpshapebox\vbox{#3\unvbox\tmpshapebox}%
+ \unkern
+ \orelse\ifnum\lastnodetype=\penaltynodecode
+ \shapepenalty\lastpenalty
+ \global\setbox\tmpshapebox\vbox{#2\unvbox\tmpshapebox}%
+ \unpenalty
+ \orelse\ifnum\lastnodetype<\zeropoint
+ \exitloop
+ \else
+ \setbox\shapebox\lastbox
+ \ifvoid\shapebox
+ \orelse\ifdim\wd\shapebox=\shapesignal\relax
+ \exitloop
+ \else
+ \shapecounter\zerocount
+ \global\setbox\tmpshapebox\vbox{#1\unvbox\tmpshapebox}%
+ \fi
+ \fi
+ \ifnum\shapecounter>100 % can be less
+ \global\reshapingfailedtrue
+ \message{!!forced exit from shapebox \the\lastnodetype !!}%
+ \restoreshapebox
+ \exitloop
+ \else
+ \advance\shapecounter \plusone
+ \fi}
+
+\unexpanded\def\beginofshapebox
+ {\setbox\oldshapebox\vbox
+ \bgroup
+ \reshapingboxtrue
+ \the\everyshapebox
+ \insertshapesignal}
+
+\unexpanded\def\endofshapebox
+ {\endgraf
+ \egroup}
+
+\let\beginshapebox\beginofshapebox
+\let\endshapebox \endofshapebox
+
+\unexpanded\def\flushshapebox
+ {\bgroup
+ \ifzeropt\ht\newshapebox
+ \else
+ % make \prevdepth legal
+ % \par before the next \vskip gives far worse results
+ \ifdim\parskip>\zeropoint\vskip\parskip\else\par\fi
+ % and take a look
+ \ifdim\prevdepth=-\thousandpoint
+ \prevdepth\zeropoint
+ \fi
+ \ifdim\prevdepth<\zeropoint\relax
+ % something like a line or a signal or ...
+ \donetrue
+ \orelse\ifinner
+ % not watertight and not ok
+ \donefalse
+ \orelse\ifdim\pagegoal=\maxdimen
+ \donetrue
+ \else
+ % give the previous line a normal depth
+ \donetrue
+ {\forgeteverypar\verticalstrut}\nobreak
+ \kern-\struttotal % geen \vskip
+ \kern-\parskip
+ % \vskip-\strutdp
+ \fi
+ \scratchdimen\dp\newshapebox
+ \unvbox\newshapebox
+ % \prevdepth=0pt and \dp\newshapebox depend on last line
+ \kern-\scratchdimen % ??
+ % now \prevdepth=0pt
+ \ifdone
+ \kern\strutdp
+ \prevdepth\strutdp
+ \fi
+ \fi
+ \egroup}
+
+%D In real inner situations we can use:
+%D
+%D \starttyping
+%D \flushinnershapebox
+%D \stoptyping
+%D
+%D This one is used in \type{\framed}.
+
+% The kern fails on for instance:
+%
+% \omlijnd[offset=0pt,hoogte=8mm,uitlijnen={rechts,laho}]{\bfa test}
+
+\unexpanded\def\innerflushshapebox
+ {\ifzeropt\ht\newshapebox \else
+ \unvcopy\newshapebox\relax % unvcopy ! else spacing problem
+ % \kern-\dp\newshapebox\relax
+ \fi}
+
+%D For absolute control, one can use \type {\doreshapebox} directly. This macro
+%D takes four arguments, that take care of:
+%D
+%D \startitemize[n,packed]
+%D \item \type{\shapebox}
+%D \item \type{\shapepenalty}
+%D \item \type{\shapekern}
+%D \item \type{\shapeskip}
+%D \stopitemize
+
+%D \macros
+%D {shapedhbox}
+%D
+%D When constructing a new box, using the content of \type {\shapebox}, one can best
+%D use \type {\shapedhbox} instead of \type {\hbox}, since it manages the height and
+%D depth of the line.
+
+\unexpanded\def\shapedhbox % lines with non strutted dimensions have
+ {\expanded{\dowithnextbox % interlineskip so if we want the original
+ {\ht\nextbox\the\ht\shapebox % spacing, we need to preserve the original
+ \dp\nextbox\the\dp\shapebox % height and depth which is definitely
+ \box\nextbox}} % needed if we apply struts to the 'new'
+ \hbox} % box or do something that changed ist size
+
+%D \macros
+%D {hyphenatedword,
+%D hyphenatedpar,
+%D hyphenatedfile,
+%D dohyphenateword}
+%D
+%D We no longer use the pure \TEX\ variant. In due time we will report some more
+%D advanced statistics.
+%D
+%D \starttyping
+%D \showhyphens{dohyphenatedword}
+%D \stoptyping
+
+\unexpanded\def\doshowhyphenatednextbox
+ {\clf_showhyphenatedinlist\nextbox}
+
+\unexpanded\def\showhyphens % hpack: so no processing (we hyphenate in lua)
+ {\dowithnextboxcs\doshowhyphenatednextbox\hpack}
+
+%D The following macros are seldom used but handy for tracing.
+%D
+%D \starttyping
+%D \hyphenatedword{dohyphenatedword}
+%D \hyphenatedpar {\dorecurse{10}{dohyphenatedword }}
+%D \hyphenatedfile{tufte}
+%D \stoptyping
+
+\unexpanded\def\dohyphenatednextbox
+ {\clf_hyphenatedlist\nextbox false\relax
+ \unhbox\nextbox}
+
+\unexpanded\def\hyphenatedword {\dowithnextboxcs\dohyphenatednextbox\hbox}
+\unexpanded\def\hyphenatedpar {\dowithnextboxcs\dohyphenatednextbox\hbox}
+\unexpanded\def\hyphenatedfile#1{\dowithnextboxcs\dohyphenatednextbox\hbox{\readfile{#1}\donothing\donothing}}
+
+\unexpanded\def\dohyphenatednextboxcolor
+ {\clf_hyphenatedlist\nextbox true\relax
+ \unhbox\nextbox}
+
+\unexpanded\def\hyphenatedcoloredword{\dowithnextboxcs\dohyphenatednextboxcolor\hbox}
+
+%D \macros
+%D {processtokens}
+%D
+%D We fully agree with (most) typographers that inter||letter spacing is only
+%D permitted in fancy titles, we provide a macro that can be used to do so. Because
+%D this is (definitely and fortunately) no feature of \TEX, we have to step through
+%D the token list ourselves.
+%D
+%D \starttyping
+%D \processtokens {before} {between} {after} {space} {tokens}
+%D \stoptyping
+%D
+%D An example of a call is:
+%D
+%D \startbuffer
+%D \processtokens {[} {+} {]} {\space} {hello world}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D This results in:
+%D
+%D \getbuffer
+%D
+%D The list of tokens may contain spaces, while \type {\\}, \type {{}} and \type {\
+%D } are handled as space too.
+
+\unexpanded\def\processtokens#1#2#3#4#5%
+ {\begingroup
+ \def\lastcharacter{\lastcharacter}% hm, recursive ?
+ \def\space{ }%
+ \let\\=\space
+ \def\before {#1}%
+ \def\between{#2}%
+ \def\after {#3}%
+ \def\white {#4}%
+ \let\savedbefore\before
+ \doprocesstokens#5\lastcharacter
+ \endgroup}
+
+\def\doprocesstokens% the space after = is essential
+ {\afterassignment\dodoprocesstokens\let\nextprocessedtoken= }
+
+\def\redoprocessedtoken
+ {\dowithnextbox
+ {\before{\copy\nextbox}% \before can use nextbox several times
+ \let\before\between
+ \doprocesstokens}
+ \hbox\bgroup}
+
+\def\dodoprocesstokens
+ {\ifx\nextprocessedtoken\lastcharacter
+ \after
+ \orelse\ifx\nextprocessedtoken\bgroup
+ \expandafter\redoprocessedtoken
+ \else
+ \expandafter\if\space\nextprocessedtoken
+ \after\white
+ \let\before\savedbefore
+ \else
+ \before\nextprocessedtoken
+ \let\before\between
+ \fi
+ \expandafter\doprocesstokens
+ \fi}
+
+%D \macros
+%D {doboundtext}
+%D
+%D Sometimes there is not enough room to show the complete (line of) text. In such a
+%D situation we can strip of some characters by using \type {\doboundtext}. When the
+%D text is wider than the given width, it's split and the third argument is
+%D appended. When the text to be checked is packed in a command, we'll have to use
+%D \type {\expandafter}.
+%D
+%D \starttyping
+%D \doboundtext{a very, probably to long, text}{3cm}{...}
+%D \stoptyping
+%D
+%D When calculating the room needed, we take the width of the third argument into
+%D account, which leads to a bit more complex macro than needed at first sight.
+
+\def\dodoboundtext#1%
+ {\setbox\scratchboxone\hbox{#1}%
+ \advance\scratchdimen -\wd\scratchboxone
+ \ifdim\scratchdimen>\zeropoint\relax#1\fi}
+
+\def\doboundtext#1#2#3% still used?
+ {\hbox
+ {\setbox\scratchbox\hbox{#1}%
+ \scratchdimen#2\relax
+ \ifdim\wd\scratchbox>\scratchdimen
+ \setbox\scratchbox\hbox{#3}%
+ \advance\scratchdimen -\wd\scratchbox
+ \handletokens#1\with\dodoboundtext
+ \fi
+ \box\scratchbox}}
+
+%D \macros
+%D {limitatetext}
+%D
+%D A bit more beautiful alternative for the previous command is the next one. This
+%D command is more robust because we let \TEX\ do most of the job. The previous
+%D command works better on text that cannot be hyphenated.
+%D
+%D \starttyping
+%D \limitatetext {text} {width} {sentinel}
+%D \limitatetext {text} {-width} {prelude}
+%D \stoptyping
+%D
+%D When no width is given, the whole text comes available. The sentinel is optional.
+%D This is about the third version.
+
+\ifdefined\fakecompoundhyphen\else \let\fakecompoundhyphen\relax \fi
+\ifdefined\veryraggedright \else \def\veryraggedright{\raggedright} \fi
+
+% \unexpanded\def\limitatetext
+% {\bgroup % evt \setstrut
+% \forgetall % otherwise indentation and so
+% \let\limitatetext\firstofthreearguments
+% \fakecompoundhyphen % dangerous ! ! ! ! ! ! ! ! !
+% \dowithnextboxcs\syst_boxes_limitate_text\hbox}
+%
+% \def\syst_boxes_limitate_text#1% #2
+% {\doifelsenothing{#1}\syst_boxes_limitate_text_nop\syst_boxes_limitate_text_yes{#1}} % {#2}
+%
+% \def\syst_boxes_limitate_text_nop#1#2%
+% {\unhbox\nextbox
+% \egroup}
+%
+% \def\syst_boxes_limitate_text_yes#1#2%
+% {\nopenalties
+% \scratchdimen#1\relax
+% \ifdim\scratchdimen<\zeropoint\relax % we'll take the last line
+% \donefalse
+% \scratchdimen-\scratchdimen
+% \else
+% \donetrue
+% \fi
+% \ifdim\wd\nextbox>\scratchdimen
+% \setbox\scratchbox\hbox{\ifdone\space#2\else#2\space\fi}%
+% \advance\scratchdimen -\wd\scratchbox
+% \setbox\scratchboxone\box\nextbox
+% \setbox\nextbox\vbox
+% {\hsize\scratchdimen
+% \hfuzz\maxdimen
+% \veryraggedright
+% \strut
+% \ifdone \else
+% \parfillskip\zeropoint
+% \rightskip\zeropoint
+% \hskip\zeropoint \s!plus 1\s!fill % \hsize
+% \fi
+% \unhcopy\scratchboxone}%
+% \ifdim\ht\nextbox>\strutht
+% \setbox\nextbox\vbox % if omitted: missing brace reported
+% {\splittopskip\openstrutheight
+% \ifdone
+% \setbox\nextbox\vsplit\nextbox to \strutht
+% \else
+% \doloop
+% {\setbox\scratchboxone\vsplit\nextbox to \strutht
+% \ifdim\ht\nextbox>\strutht \else \exitloop \fi}%
+% \fi
+% \unvbox\nextbox
+% \setbox\nextbox\lastbox
+% \global\setbox1\hpack
+% {\ifdone
+% \unhbox\nextbox\unskip\kern\zeropoint\box\scratchbox
+% \else
+% \box\scratchbox\unhbox\nextbox
+% \fi
+% \unskip}}%
+% \unhbox1
+% \else
+% \unhbox0%
+% \fi
+% \else
+% \unhbox\nextbox
+% \fi
+% \egroup}
+%
+% %D We can also limit a text with more control:
+% %D
+% %D \startbuffer
+% %D \limitatetext {\input tufte } {2cm,5mm} {\unknown}
+% %D \limitatetext {ton en hans} {2cm,5mm} {\unknown}
+% %D \limitatetext {ton en hans zijn eikels} {2cm,5mm} {\unknown}
+% %D \limitatetext {ton} {2cm,5mm} {\unknown}
+% %D \stopbuffer
+% %D
+% %D \typebuffer \getbuffer
+% %D
+% %D We build this feature on top of the previous macro.
+%
+% % we could move the text argument to the end
+%
+% \let\normallimitatetext\limitatetext
+%
+% \def\speciallimitatetext#1#2#3#4% text left right placeholder
+% {%\dontleavehmode
+% \bgroup
+% \let\speciallimitatetext\firstoffourarguments
+% \setbox\scratchboxone\hbox
+% {\nohyphens
+% \normallimitatetext{#1}{+#2}{}#4%
+% \normallimitatetext{#1}{-#3}{}}%
+% \setbox\scratchboxtwo\hbox
+% {#1}%
+% \ifdim\wd\scratchboxtwo<\wd\scratchboxone #1\else\unhbox\scratchboxone\fi
+% \egroup}
+%
+% \unexpanded\def\limitatetext#1#2#3% \expanded added 2003/01/16
+% {\splitatcomma{#2}\leftlimit\rightlimit
+% \ifx\rightlimit\empty
+% \normallimitatetext {#1}\leftlimit {#3}%
+% \else
+% \speciallimitatetext{#1}\leftlimit\rightlimit{#3}%
+% \fi}
+
+\unexpanded\def\limitatetext#1#2#3% \expanded added 2003/01/16
+ {\splitatcomma{#2}\leftlimit\rightlimit
+ \limitated
+ left \leftlimit
+ \ifx\rightlimit\empty\else
+ right \rightlimit
+ \fi
+ strip true
+ sentinel {#3}
+ text {#1}
+ \relax}
+
+%D Undocumented bonus (see wiki):
+%D
+%D \starttyping
+%D \limitatefirstline{\input tufte\relax}{10cm}{\unknown}
+%D \stoptyping
+
+\unexpanded\def\limitatefirstline#1#2#3%
+ {\hbox\bgroup\strut % \hpack
+ \setbox\scratchbox\hbox{\begstrut#1\endstrut}%
+ \ifdim\wd\scratchbox>#2\relax
+ \setbox\scratchbox\hbox{#3}%
+ \hsize#2\relax
+ \advance\hsize-\wd\scratchbox
+ \setbox\scratchbox\vbox{\forgetall\veryraggedright#1}%
+ \setbox\scratchbox\vsplit\scratchbox to \lineheight
+ \vbox
+ {\unvbox\scratchbox
+ \global\setbox\plusone\lastbox
+ \global\setbox\plusone\hbox{\strut\unhbox\plusone}%
+ \hbox % to #2 % \hpack
+ {\ifx\clip\undefined
+ \box\plusone
+ \orelse\ifdim\wd\plusone>\hsize
+ \lower\strutdepth\hpack{\clip[\c!width=\hsize,\c!height=\lineheight]{\hpack{\raise\strutdepth\box\plusone}}}%
+ \else
+ \box\plusone
+ \fi
+ \removeunwantedspaces#3}}% \removeunwantedspaces\hss#3}}%
+ \else
+ #1%
+ \fi
+ \egroup}
+
+%D \macros
+%D {processisolatedwords,processisolatedchars}
+%D
+%D \startbuffer
+%D \processisolatedchars{some more words} \ruledhbox \par
+%D \processisolatedchars{and some $x + y = z$ math} \ruledhbox \par
+%D \processisolatedchars{and a \hbox{$x + y = z$}} \ruledhbox \par
+%D \processisolatedwords{some more words} \ruledhbox \par
+%D \processisolatedwords{and some $x + y = z$ math} \ruledhbox \par
+%D \processisolatedwords{and a \hbox{$x + y = z$}} \ruledhbox \par
+%D \stopbuffer
+%D
+%D \typebuffer \blank \getbuffer \blank
+
+% todo: provide variant with #1 picked up as box
+
+\unexpanded\def\processisolatedchars#1#2%
+ {\dontleavehmode
+ \begingroup
+ \setbox\scratchbox\hbox{\settrialtypesetting#2{\savecurrentattributes{pic}}}%
+ \setbox\scratchbox\hbox{\restorecurrentattributes{pic}#1}%
+ \clf_applytobox
+ method {char}%
+ box \scratchbox
+ command {\csstring#2}%
+ nested true%
+ \relax
+ \endgroup}
+
+\unexpanded\def\processisolatedwords#1#2%
+ {\dontleavehmode
+ \begingroup
+ \setbox\scratchbox\hbox{\settrialtypesetting#2{\savecurrentattributes{pic}}}%
+ \setbox\scratchbox\hbox{\restorecurrentattributes{pic}#1}%
+ \clf_applytobox
+ method {word}%
+ box \scratchbox
+ command {\csstring#2}%
+ nested true%
+ \relax
+ \endgroup}
+
+%D A variant:
+
+\unexpanded\def\applytocharacters#1%
+ {\dontleavehmode
+ \dowithnextbox{\clf_applytobox
+ method {char}%
+ box \nextbox
+ command {\csstring#1}%
+ nested true%
+ \relax}%
+ \hbox}
+
+\unexpanded\def\applytowords#1%
+ {\dontleavehmode
+ \dowithnextbox{\clf_applytobox
+ method {word}%
+ box \nextbox
+ command {\csstring#1}%
+ nested true%
+ \relax}%
+ \hbox}
+
+%D The old call:
+
+\unexpanded\def\processwords#1%
+ {\processisolatedwords{#1}\processword}
+
+\let\processword\relax
+
+\unexpanded\def\applytosplitstringchar#1#2%
+ {\dontleavehmode\clf_processsplit
+ data {#2}%
+ command {\csstring#1}%
+ method {char}%
+ \relax}
+
+\unexpanded\def\applytosplitstringword#1#2%
+ {\dontleavehmode\clf_processsplit
+ data {#2}%
+ command {\csstring#1}%
+ method {word}%
+ \relax}
+
+\unexpanded\def\applytosplitstringline#1#2%
+ {\dontleavehmode\clf_processsplit
+ data {#2}%
+ command {\csstring#1}%
+ method {line}%
+ \relax}
+
+\unexpanded\def\applytosplitstringcharspaced#1#2%
+ {\dontleavehmode\clf_processsplit
+ data {#2}%
+ command {\csstring#1}%
+ method {char}%
+ spaced true%
+ \relax}
+
+\unexpanded\def\applytosplitstringwordspaced#1#2%
+ {\dontleavehmode\clf_processsplit
+ data {#2}%
+ command {\csstring#1}%
+ method {word}%
+ spaced true%
+ \relax}
+
+\unexpanded\def\applytosplitstringlinespaced#1#2%
+ {\dontleavehmode\clf_processsplit
+ data {#2}%
+ command {\csstring#1}%
+ method {line}%
+ spaced true%
+ \relax}
+
+%D \macros
+%D {sbox}
+%D
+%D This is a rather strange command. It grabs some box content and and limits the
+%D size to the height and depth of a \type {\strut}. The resulting bottom||alligned
+%D box can be used aside other ones, without disturbing the normal baseline
+%D distance.
+%D
+%D \startbuffer
+%D \ruledhbox to .5\hsize{\sbox{eerste\par tweede \par derde}}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D Shows up as:
+%D
+%D \startexample
+%D \vskip3\baselineskip
+%D \getbuffer
+%D \stopexample
+%D
+%D Before displaying the result we added some skip, otherwise the first two lines
+%D would have ended up in the text. This macro can be useful when building
+%D complicated menus, headers and footers and|/|or margin material.
+
+\unexpanded\def\sbox
+ {\vpack\bgroup
+ \dowithnextboxcs\syst_boxes_sbox_finish\vbox}
+
+\unexpanded\def\syst_boxes_sbox_finish
+ {\boxyoffset\nextbox-\strutdp
+ \dp\nextbox\strutdp
+ \ht\nextbox\strutht
+ \box\nextbox
+ \egroup}
+
+%D A variant on this:
+%D
+%D \starttyping
+%D xx \ruledhbox{\inlinedbox{\tfd test}} xx
+%D \stoptyping
+
+\unexpanded\def\inlinedbox
+ {\bgroup
+ \dowithnextboxcs\syst_boxes_inlined_finish\hbox}
+
+\unexpanded\def\syst_boxes_inlined_finish
+ {\boxyoffset\nextbox-\dimexpr(\htdp\nextbox-\lineheight)/\plustwo+\strutdp\relax
+ \ht\nextbox\strutht
+ \dp\nextbox\strutdp
+ \box\nextbox
+ \egroup}
+
+%D \macros
+%D {struttedbox}
+%D
+%D This boxing macro limits the height and depth to those of a strut.
+
+\unexpanded\def\struttedbox
+ {\hpack\bgroup
+ \dowithnextboxcs\syst_boxes_struttedbox_finish\hbox}
+
+\def\syst_boxes_struttedbox_finish
+ {\dp\nextbox\strutdepth
+ \ht\nextbox\strutheight
+ \box\nextbox
+ \egroup}
+
+%D \macros
+%D {topskippedbox}
+%D
+%D This macro compensates the difference between the topskip and strutheight. Watch
+%D how we preserve the depth when it equals strutdepth.
+
+\unexpanded\def\topskippedbox
+ {\hpack\bgroup\dowithnextboxcs\syst_boxes_topskippedbox_finish\hbox}
+
+\def\syst_boxes_topskippedbox_finish
+ {\edef\m_boxes_tmp{\ifdim\strutdepth=\dp\nextbox\dp\nextbox\the\dp\nextbox\fi}%
+ \lower\topskip\hpack{\raise\strutheight\box\nextbox}%
+ \m_boxes_tmp
+ \egroup}
+
+%D \macros
+%D {centeredbox, centerednextbox}
+%D
+%D Here is another strange one. This one offers a sort of overlay with positive or
+%D negative offsets. This command can be used in well defined areas where no offset
+%D options are available. We first used it when building a button inside the margin
+%D footer, where the button should have a horizontal offset and should be centered
+%D with respect to the surrounding box. The last of the three examples we show below
+%D says:
+%D
+%D \starttyping
+%D \vsize=3cm
+%D \hsize=3cm
+%D \ruledvbox to \vsize
+%D {\centeredbox height .5cm width -1cm
+%D {\vrule width \hsize height \vsize}}}
+%D \stoptyping
+%D
+%D Here the \type {\ruledvbox} just shows the surrounding box and \type {\vrule} is
+%D used to show the centered box.
+%D
+%D \def\AnExample#1#2%
+%D {\vsize=3cm
+%D \hsize=3cm
+%D \ruledvbox to \vsize
+%D {\centeredbox height #1 width #2
+%D {\color[green]{\vrule width \hsize height \vsize}}}}
+%D
+%D \startlinecorrection
+%D \startcombination[3*1]
+%D {\AnExample {-1cm} {.5cm}} {}
+%D {\AnExample {.5cm} {-1cm}} {}
+%D {\AnExample {-1cm} {-.5cm}} {}
+%D \stopcombination
+%D \stoplinecorrection
+%D
+%D This command takes two optional arguments: \type {width} and \type {height}.
+%D Observing readers can see that we use \TEX's own scanner for grabbing these
+%D arguments: \type {#1#} reads everyting till the next brace and passes it to both
+%D rules. The setting of the box dimensions at the end is needed for special cases.
+%D The dimensions of the surrounding box are kept intact. This commands handles
+%D positive and negative dimensions (which is why we need two boxes with rules).
+
+\unexpanded\def\centeredbox#1#% height +/-dimen width +/-dimen
+ {\bgroup
+ \dontcomplain
+ \forgetall
+ \scangivendimensions#1\relax
+ \advance\vsize\givenheight
+ \advance\hsize\givenwidth
+ \dowithnextboxcs\syst_boxes_centered_finish
+ \hbox}
+
+\def\syst_boxes_centered_finish
+ {\boxxoffset\nextbox.5\dimexpr
+ \hsize
+ -\wd\nextbox
+ -\givenwidth
+ \relax
+ \boxyoffset\nextbox.5\dimexpr
+ \vsize
+ -\ht\nextbox
+ +\dp\nextbox
+ -\givenheight
+ \relax
+ \wd\nextbox\dimexpr\hsize-\givenwidth \relax
+ \ht\nextbox\dimexpr\vsize-\givenheight\relax
+ \dp\nextbox\zeropoint
+ \box\nextbox
+ \egroup}
+
+%D For those who don't want to deal with \type {\hsize} and \type {\vsize}, we have:
+%D
+%D \starttyping
+%D \centerednextbox width 2bp height 2bp
+%D {\framed[width=100bp,height=100bp]{}}
+%D \stoptyping
+%D
+%D Do you see why we call this one \type {next}?
+
+\unexpanded\def\centerednextbox#1#%
+ {\bgroup
+ \dowithnextbox
+ {\hsize\wd\nextbox
+ \vsize\ht\nextbox
+ \centeredbox#1{\box\nextbox}%
+ \egroup}
+ \hbox}
+
+%D \macros
+%D {centerbox}
+%D
+%D Centering on the available space is done by:
+%D
+%D \starttyping
+%D \centerbox <optional specs> {content}
+%D \stoptyping
+%D
+%D When omitted, the current \type {\hsize} and \type {\vsize} are used. Local
+%D dimensions are supported.
+
+\unexpanded\def\centerbox#1#% optional height +/-dimen width +/-dimen
+ {\bgroup
+ \dowithnextbox
+ {\setlocalhsize
+ \setbox\scratchbox\hpack{\vrule\s!width \zeropoint#1}%
+ \ifzeropt\wd\scratchbox\else\hsize\wd\scratchbox\fi
+ \setbox\scratchbox\vpack{\hrule\s!height\zeropoint#1}%
+ \ifzeropt\ht\scratchbox\else\vsize\ht\scratchbox\fi
+ \vpack to \vsize{\vss\hpack to \hsize{\hss\box\nextbox\hss}\vss}%
+ \egroup}%
+ \hbox}
+
+%D \macros
+%D {setrigidcolumnhsize,rigidcolumnbalance,rigidcolumnlines}
+%D
+%D These macros are copied from the \TEX book, page~397, and extended by a macro
+%D that sets the \type {\hsize}.
+%D
+%D \starttyping
+%D \setrigidcolumnhsize {total width} {distance} {n}
+%D \rigidcolumnbalance {box}
+%D \stoptyping
+%D
+%D Both these macros are for instance used in typesetting footnotes. The following
+%D flags influence the process.
+
+\newif\ifalignrigidcolumns
+\newif\ifstretchrigidcolumns
+\newif\iftightrigidcolumns % if true: just a vbox, no depth/noflines/gridsnap corrrections
+
+\unexpanded\def\setrigidcolumnhsize#1#2#3% todo: \dimexpr
+ {\xdef\savedrigidhsize{\the\hsize}%
+ \hsize#1\relax
+ \global\chardef\rigidcolumns#3\relax
+ \scratchdimen -#2\relax
+ \multiply\scratchdimen #3\relax
+ \advance\scratchdimen #2\relax
+ \advance\hsize \scratchdimen
+ \divide\hsize #3\relax}
+
+% ==
+%
+% \def\setrigidcolumnhsize#1#2#3%
+% {\xdef\savedrigidhsize{\the\hsize}%
+% \global\chardef\rigidcolumns#3\relax
+% \hsize=\dimexpr(#1-\numexpr#3-1\relax\dimexpr#2\relax)/#3\relax}
+
+\newbox\rigidcolumnbox
+
+\let\rigidcolumnlines\!!zerocount
+
+\unexpanded\def\rigidcolumnbalance#1%
+ {\ifnum\rigidcolumns=1 % tzt ook h/d correctie
+ \ifinner\ifhmode\box\else\unvbox\fi\else\unvbox\fi#1\relax
+ \else
+ \vbox % \vpack
+ {\forgetall
+ \nopenalties
+ \dontcomplain
+ \setbox\rigidcolumnbox\vbox
+ {\line{}\goodbreak\unvbox#1\removebottomthings}%
+ \splittopskip\openstrutheight
+ \setbox\scratchbox\vsplit\rigidcolumnbox to \zeropoint
+ \ifcase\rigidcolumnlines\relax
+ % \iffalse
+ % % maybe some day an option
+ % \scratchskip\ht\rigidcolumnbox
+ % \advance\scratchskip\dp\rigidcolumnbox
+ % \getnoflines\scratchskip
+ % \ifodd\noflines
+ % \advance\noflines\plusone
+ % \fi
+ % \divide\noflines\rigidcolumns
+ %\else
+ \scratchdimen\ht\rigidcolumnbox
+ \divide\scratchdimen \rigidcolumns
+ \getnoflines\scratchdimen
+ %\fi
+ \else
+ \noflines\rigidcolumnlines % to be sure
+ \fi
+ \scratchdimen\noflines\lineheight
+ % new: we now loop so that we don't loose content
+ % since in practice we also use this macro for
+ % funny lineheights and border cases
+ \setbox0=\box\rigidcolumnbox
+ \doloop
+ {\setbox\rigidcolumnbox=\copy0
+ \setbox\scratchbox\hpack to \savedrigidhsize
+ {\dorecurse\rigidcolumns
+ {\setbox\scratchbox\vsplit\rigidcolumnbox to \scratchdimen
+ \dp\scratchbox\openstrutdepth
+ \setbox\scratchbox\vtop
+ \ifalignrigidcolumns to
+ \ifstretchrigidcolumns\vsize\else\scratchdimen\fi
+ \fi
+ {\unvbox\scratchbox}%
+ \wd\scratchbox\hsize
+ \box\scratchbox
+ \hfill}%
+ \hfillneg}%
+ \ifvoid\rigidcolumnbox\exitloop\else\advance\scratchdimen\lineheight\fi}%
+ \iftightrigidcolumns
+ \setbox\scratchbox\hpack{\raise\dp\scratchbox\box\scratchbox}%
+ \else
+ \advance\scratchdimen -\openstrutdepth
+ \setbox\scratchbox\hpack{\raise\scratchdimen\box\scratchbox}%
+ \dp\scratchbox\openstrutdepth
+ \ht\scratchbox\scratchdimen
+ \fi
+ \box\scratchbox}%
+ \fi}
+
+%D \macros
+%D {startvboxtohbox,stopvboxtohbox,convertvboxtohbox}
+%D
+%D Here is another of Knuth's dirty tricks, as presented on pages 398 and 399 of the
+%D \TEX book. These macros can be used like:
+%D
+%D \starttyping
+%D \vbox
+%D \bgroup
+%D \startvboxtohbox ... \stopvboxtohbox
+%D \startvboxtohbox ... \stopvboxtohbox
+%D \startvboxtohbox ... \stopvboxtohbox
+%D \egroup
+%D
+%D \vbox
+%D \bgroup
+%D \convertvboxtohbox
+%D \egroup
+%D \stoptyping
+%D
+%D These macros are used in reformatting footnotes, so they do what they're meant
+%D for.
+
+\newdimen\vboxtohboxslack
+\newdimen\hboxestohboxslack
+
+%D Create line and fake height of paragraph by messign with heights: a nice hack by
+%D DEK himself.
+
+%\unexpanded\def\setvboxtohbox
+% {\bgroup
+% \ifdim\baselineskip<16pt \relax
+% \scratchdimen\baselineskip
+% \multiply\scratchdimen 1024
+% \else
+% \message{cropping \baselineskip to 16pt}%
+% \scratchdimen\maxdimen
+% \fi
+% \divide\scratchdimen \hsize
+% \multiply\scratchdimen 64
+% \xdef\vboxtohboxfactor{\withoutpt\the\scratchdimen}%
+% \egroup}
+%
+% \unexpanded\def\startvboxtohbox
+% {\bgroup
+% \setvboxtohbox
+% \setbox\scratchbox\hbox\bgroup}
+%
+% \unexpanded\def\stopvboxtohbox
+% {\ifcase\vboxtohboxslack\else\hskip\zeropoint\!!minus\vboxtohboxslack\fi
+% \egroup
+% \dp\scratchbox\zeropoint
+% \ht\scratchbox\vboxtohboxfactor\wd\scratchbox
+% \box\scratchbox
+% \egroup}
+
+% More modern:
+
+% \definesystemattribute[vboxtohboxseparator][public]
+
+%newbox\d_syst_boxes_vboxtohbox
+\newbox\d_syst_boxes_separator
+
+\unexpanded\def\startvboxtohboxseparator
+ {\setbox\d_syst_boxes_separator\hbox attr \vboxtohboxseparatorattribute\plusone\bgroup}
+
+\unexpanded\def\stopvboxtohboxseparator
+ {\egroup}
+
+\unexpanded\def\startvboxtohbox
+ {\begingroup
+ \setbox\scratchbox\hbox\bgroup}
+
+\unexpanded\def\stopvboxtohbox
+ {\ifvoid\d_syst_boxes_separator
+ \hskip\zeropoint\ifcase\vboxtohboxslack\else\s!minus\vboxtohboxslack\fi % we really need a skip
+ \else
+ \box\d_syst_boxes_separator
+ \fi
+ \egroup
+ \clf_hboxtovbox\scratchbox
+ \box\scratchbox
+ \endgroup}
+
+% A possible reconstruction:
+
+\unexpanded\def\convertvboxtohbox
+ {\makehboxofhboxes
+ \setbox\scratchboxone\hpack{\unhbox\scratchboxone\removehboxes}% \hpack
+ \noindent\unhbox\scratchboxone\par}
+
+\unexpanded\def\makehboxofhboxes
+ {\setbox\scratchboxone\emptyhbox
+ \loop % \doloop { .. \exitloop .. }
+ \setbox\scratchboxtwo\lastbox
+ \ifhbox\scratchboxtwo
+ \setbox\scratchboxone\hpack{\box\scratchboxtwo\unhbox\scratchboxone}%
+ \repeat}
+
+\unexpanded\def\removehboxes
+ {\setbox\scratchboxone\lastbox
+ \ifhbox\scratchboxone
+ {\removehboxes}\unhbox\scratchboxone
+ \fi}
+
+% And one special for notes:
+
+\unexpanded\def\starthboxestohbox
+ {\bgroup
+ \setbox\scratchbox\vbox\bgroup}
+
+\unexpanded\def\stophboxestohbox
+ {\egroup
+ \clf_vboxlisttohbox\scratchbox\nextbox\dimexpr\hboxestohboxslack\relax
+ \dontleavehmode
+ \unhbox\nextbox
+ \removeunwantedspaces
+ \par
+ \egroup}
+
+%D \macros
+%D {unhhbox}
+%D
+%D The next macro is used in typesetting inline headings. Let's first look at the
+%D macro and then show an example.
+
+\newbox \unhhedbox
+\newbox \hhbox
+\newdimen \lasthhboxwidth
+\newskip \hhboxindent
+
+\unexpanded\def\unhhbox#1\with#2%
+ {\bgroup
+ \nopenalties
+ \dontcomplain
+ \forgetall
+ \setbox\unhhedbox\vbox{\hskip\hhboxindent\strut\unhbox#1}% => \hsize
+ \doloop
+ {\setbox\hhbox\vsplit\unhhedbox to \lineheight
+ \ifvoid\unhhedbox
+ \setbox\hhbox\hbox{\strut\hboxofvbox\hhbox}% \hpack
+ \fi
+ \ht\hhbox\strutht
+ \dp\hhbox\strutdp
+ \ifzeropt\hhboxindent\else
+ \setbox\hhbox\hpack{\kern-\hhboxindent\box\hhbox}%
+ \hhboxindent\zeropoint
+ \fi
+ \global\lasthhboxwidth\wd\hhbox
+ #2\relax
+ \ifvoid\unhhedbox
+ \exitloop
+ \else
+ \hskip\zeropoint \s!plus \zeropoint
+ \fi}%
+ \egroup}
+
+\def\dohboxofvbox
+ {\setbox0\vpack{\unvbox\scratchcounter\global\setbox1\lastbox}%
+ \unhbox1
+ \egroup}
+
+\unexpanded\def\hboxofvbox
+ {\bgroup
+ \afterassignment\dohboxofvbox
+ \scratchcounter=}
+
+%D This macro can be used to break a paragraph apart and treat each line seperately,
+%D for instance, making it clickable. The main complication is that we want to be
+%D able to continue the paragraph, something that's needed in the in line section
+%D headers.
+%D
+%D \startbuffer
+%D \setbox0=\hbox{\input tufte \relax}
+%D \setbox2=\hbox{\input knuth \relax}
+%D \unhhbox0\with{\ruledhbox{\box\hhbox}}
+%D \hskip1em plus 1em minus 1em
+%D \hhboxindent=\lasthhboxwidth
+%D \advance\hhboxindent by \lastskip
+%D \unhhbox2\with{\ruledhbox{\box\hhbox}}
+%D \stopbuffer
+%D
+%D \getbuffer
+%D
+%D This piece of text was typeset by saying:
+%D
+%D \typebuffer
+%D
+%D Not that nice a definition, but effective. Note the stretch we've build in the
+%D line that connects the two paragraphs.
+
+%D \macros
+%D {doifcontent}
+%D
+%D When processing depends on the availability of content, one can give the next
+%D macro a try.
+%D
+%D \starttyping
+%D \doifcontent{pre content}{post content}{no content}\somebox
+%D \stoptyping
+%D
+%D Where \type {\somebox} is either a \type {\hbox} or \type {\vbox}. If the
+%D dimension of this box suggest some content, the resulting box is unboxed and
+%D surrounded by the first two arguments, else the third arguments is executed.
+
+\unexpanded\def\doifcontent#1#2#3%
+ {\dowithnextbox
+ {\ifhbox\nextbox
+ \ifdim\wd\nextbox>\zeropoint
+ #1\unhbox\nextbox#2\relax
+ \else
+ #3\relax
+ \fi
+ \else
+ \ifdim\ht\nextbox>\zeropoint
+ #1\unvbox\nextbox#2\relax
+ \else
+ #3\relax
+ \fi
+ \fi}}
+
+%D So when we say:
+%D
+%D \startbuffer
+%D \doifcontent{[}{]}{}\hbox{content sensitive typesetting}
+%D
+%D \doifcontent{}{\page}{}\vbox{content sensitive typesetting}
+%D
+%D \doifcontent{}{}{\message{Didn't you forget something?}}\hbox{}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D We get:
+%D
+%D \getbuffer
+%D
+%D Where the last call of course does not show up in this document, but definitely
+%D generates a confusing message.
+
+%D \macros
+%D {processboxes}
+%D
+%D The next macro gobble boxes and is for instance used for overlays. First we show
+%D the general handler.
+
+\newbox\processbox % public : this is the one where \nextbox's end up in
+
+\unexpanded\def\processboxes#1%
+ {\bgroup
+ \def\syst_boxes_process_indeed{#1}% #1 can be redefined halfway
+ \setbox\processbox\emptybox
+ \doifelsenextbgroup\syst_boxes_process_yes\syst_boxes_process_nop}
+
+\def\syst_boxes_process_yes
+ {\dowithnextboxcs\syst_boxes_process_content\hbox}
+
+\def\syst_boxes_process_content
+ {\removeunwantedspaces
+ \syst_boxes_process_indeed % takes \nextbox makes \processbox
+ \doifelsenextbgroup\syst_boxes_process_yes\syst_boxes_process_nop}
+
+\unexpanded\def\syst_boxes_process_nop
+ {\removeunwantedspaces
+ \box\processbox
+ \egroup}
+
+%D \macros
+%D {startoverlay}
+%D
+%D We can overlay boxes by saying:
+%D
+%D \startbuffer
+%D \startoverlay
+%D {\framed{hans}}
+%D {\framed[width=3cm]{ton}}
+%D {\framed[height=2cm]{oeps}}
+%D \stopoverlay
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D shows up as:
+%D
+%D \leavevmode\getbuffer
+
+\def\boxisempty#1%
+ {\ifdim\wd#1=\zeropoint
+ \ifdim\ht#1=\zeropoint
+ \ifdim\dp#1=\zeropoint
+ \zerocount
+ \else
+ \plusone
+ \fi
+ \else
+ \plusone
+ \fi
+ \else
+ \plusone
+ \fi}
+
+\def\syst_boxes_overlay_process
+ {\ifcase\boxisempty\nextbox\else
+ \syst_boxes_overlay_process_indeed
+ \fi}
+
+\def\syst_boxes_overlay_process_indeed
+ {%\removeunwantedspaces % already done
+ \scratchdepth\dp\ifdim\dp\nextbox>\dp\processbox\nextbox\else\processbox\fi
+ \ifdim\ht\nextbox>\ht\processbox
+ \setbox\processbox\vpack to \ht\nextbox {\dp\processbox\zeropoint\vss\box\processbox\vss}%
+ \else
+ \setbox\nextbox \vpack to \ht\processbox{\dp\nextbox \zeropoint\vss\box\nextbox \vss}%
+ \fi
+ \dp\nextbox \scratchdepth
+ \dp\processbox\scratchdepth
+ \scratchwidth\wd\ifdim\wd\nextbox>\wd\processbox\nextbox\else\processbox\fi
+ \setbox\processbox\hpack to \scratchwidth
+ {\hpack to \scratchwidth{\hss\box\processbox\hss}%
+ \kern-\scratchwidth
+ \hpack to \scratchwidth{\hss\box\nextbox \hss}}}
+
+\unexpanded\def\startoverlay
+ {\bgroup
+ \let\stopoverlay\egroup
+ \processboxes\syst_boxes_overlay_process}
+
+\let\stopoverlay\relax
+
+%D \macros
+%D {fakebox}
+%D
+%D The next macro is a rather silly one, but saves space.
+%D
+%D \starttyping
+%D \hbox{\fakebox0}
+%D \stoptyping
+%D
+%D returns an empty box with the dimensions of the box specified, here being zero.
+
+\unexpanded\def\fakebox
+ {\bgroup
+ \afterassignment\syst_boxes_fakebox_finish\scratchcounter}
+
+\def\syst_boxes_fakebox_finish
+ {\setbox\scratchbox\ifhbox\scratchcounter\emptyhbox\else\emptyvbox\fi
+ \wd\scratchbox\wd\scratchcounter
+ \ht\scratchbox\ht\scratchcounter
+ \dp\scratchbox\dp\scratchcounter
+ \box\scratchbox
+ \egroup}
+
+%D \macros
+%D {lbox,rbox,cbox,tbox,bbox}
+%D
+%D Here are some convenient alternative box types:
+%D
+%D \starttyping
+%D \lbox{text ...}
+%D \cbox{text ...}
+%D \rbox{text ...}
+%D \stoptyping
+%D
+%D Are similar to \type {\vbox}, which means that they also accept something like
+%D \type {to 3cm}, but align to the left, middle and right. These box types can be
+%D used to typeset paragraphs.
+
+\def\syst_boxes_lrc_process#1{\bgroup\forgetall\let\\\endgraf#1\let\next}
+
+\unexpanded\def\lbox#1#{\vbox#1\syst_boxes_lrc_process\raggedleft }
+\unexpanded\def\cbox#1#{\vbox#1\syst_boxes_lrc_process\raggedcenter}
+\unexpanded\def\rbox#1#{\vbox#1\syst_boxes_lrc_process\raggedright }
+
+\unexpanded\def\ltop#1#{\vtop#1\syst_boxes_lrc_process\raggedleft }
+\unexpanded\def\ctop#1#{\vtop#1\syst_boxes_lrc_process\raggedcenter}
+\unexpanded\def\rtop#1#{\vtop#1\syst_boxes_lrc_process\raggedright }
+
+%D The alternatives \type {\tbox} and \type {\bbox} can be used to properly align
+%D boxes, like in:
+%D
+%D \setupexternalfigures[directory={../sample}]
+%D \startbuffer
+%D \starttable[|||]
+%D \HL
+%D \VL \tbox{\externalfigure[cow][height=3cm,frame=on]} \VL top aligned \VL\SR
+%D \HL
+%D \VL \bbox{\externalfigure[cow][height=3cm,frame=on]} \VL bottom aligned \VL\SR
+%D \HL
+%D \stoptable
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D The positioning depends on the strut settings:
+%D
+%D \getbuffer
+
+\unexpanded\def\tbox{\hpack\bgroup\dowithnextboxcs\syst_boxes_tbox_finish\hbox}
+\unexpanded\def\bbox{\hpack\bgroup\dowithnextboxcs\syst_boxes_bbox_finish\hbox}
+
+\def\syst_boxes_tbox_finish
+ {\scratchheight\ht\strutbox
+ \scratchdepth\dimexpr\htdp\nextbox-\scratchheight\relax
+ \ht\nextbox\scratchheight
+ \dp\nextbox\scratchdepth
+ \boxyoffset\nextbox-\scratchdepth
+ \box\nextbox
+ \egroup}
+
+\def\syst_boxes_bbox_finish
+ {\scratchdepth\dp\strutbox
+ \scratchheight\dimexpr\htdp\nextbox-\scratchdepth\relax
+ \dp\nextbox\scratchdepth
+ \ht\nextbox\scratchheight
+ \boxyoffset\nextbox-\scratchdepth
+ \box\nextbox
+ \egroup}
+
+%D \macros
+%D {lhbox,mhbox,rhbox}
+%D
+%D A few more boxes.
+
+\def\dodolhbox{\hpack to \hsize{\box\nextbox\hss }}
+\def\dodomhbox{\hpack to \hsize{\hss\box\nextbox\hss}}
+\def\dodorhbox{\hpack to \hsize{\hss\box\nextbox }}
+
+\unexpanded\def\lhbox{\dowithnextboxcs\dodolhbox\hbox}
+\unexpanded\def\mhbox{\dowithnextboxcs\dodomhbox\hbox}
+\unexpanded\def\rhbox{\dowithnextboxcs\dodorhbox\hbox}
+
+\let\lefthbox \lhbox
+\let\midhbox \mhbox
+\let\righthbox\rhbox
+
+%D \macros
+%D {boxofsize}
+%D
+%D Sometimes we need to construct a box with a height or width made up of several
+%D dimensions. Instead of cumbersome additions, we can use:
+%D
+%D \starttyping
+%D \boxofsize \vbox 10cm 3cm -5cm {the text to be typeset}
+%D \stoptyping
+%D
+%D This example demonstrates that one can use positive and negative values.
+%D Dimension registers are also accepted.
+
+\newdimen\sizeofbox
+
+\unexpanded\def\boxofsize#1%
+ {\bgroup
+ \sizeofbox\zeropoint
+ \scratchdimen\zeropoint
+ \def\docommand
+ {\advance\sizeofbox\scratchdimen
+ \futurelet\next\dodocommand}%
+ \def\dodocommand
+ {\ifx\next\bgroup
+ \expanded{\egroup#1 to \the\sizeofbox}%
+ \else
+ \expandafter\afterassignment\expandafter\docommand\expandafter\scratchdimen
+ \fi}%
+ \docommand}
+
+%D Some new, still undocumented features:
+
+% limitatetext -> beter {text} als laatste !!
+%
+% \limitvbox
+% \limithbox
+
+\unexpanded\def\limitatelines#1#2% size sentinel
+ {\dowithnextbox
+ {\scratchdimen#1\hsize
+ \ifdim\wd\nextbox>\scratchdimen
+ \setbox\nextbox\hbox
+ {\advance\scratchdimen -.1\hsize
+ \limitatetext{\unhbox\nextbox}{\scratchdimen}{\nobreak#2}}%
+ \fi
+ \unhbox\nextbox}
+ \hbox}
+
+\unexpanded\def\fittoptobaselinegrid % weg hier
+ {\dowithnextbox
+ {\bgroup
+ \par
+ \scratchdimen\ht\nextbox
+ \ht\nextbox\strutht
+ \dp\nextbox\strutdp
+ \hpack{\box\nextbox}
+ \prevdepth\strutdp
+ \doloop
+ {\advance\scratchdimen -\lineheight
+ \ifdim\scratchdimen<\zeropoint
+ \exitloop
+ \else
+ \nobreak
+ \hpack{\strut}
+ \fi}
+ \egroup}
+ \vbox}
+
+%D Some more undocumented macros (used in m-chart).
+
+\newif\iftraceboxplacement % \traceboxplacementtrue
+
+\newbox\fakedboxcursor
+
+\setbox\fakedboxcursor\hpack
+ {\vrule\s!width\zeropoint\s!height\zeropoint\s!depth\zeropoint}
+
+\unexpanded\def\boxcursor % overloaded in core-vis
+ {\iftraceboxplacement
+ \bgroup
+ \scratchdimen2\onepoint
+ \setbox\scratchbox\hpack to \zeropoint
+ {\hss
+ \vrule
+ \s!width \scratchdimen
+ \s!height\scratchdimen
+ \s!depth \scratchdimen
+ \hss}%
+ \smashedbox\scratchbox
+ \egroup
+ \else
+ \copy\fakedboxcursor
+ \fi}
+
+\unexpanded\def\placedbox
+ {\iftraceboxplacement\ruledhbox\else\hbox\fi}
+
+\newdimen\boxoffset
+\newdimen\boxhdisplacement
+\newdimen\boxvdisplacement
+
+\unexpanded\def\rightbox {\hpack\bgroup\dowithnextboxcs\syst_boxes_rightbox_finish \placedbox}
+\unexpanded\def\leftbox {\hpack\bgroup\dowithnextboxcs\syst_boxes_leftbox_finish \placedbox}
+\unexpanded\def\topbox {\hpack\bgroup\dowithnextboxcs\syst_boxes_topbox_finish \placedbox}
+\unexpanded\def\bottombox {\hpack\bgroup\dowithnextboxcs\syst_boxes_bottombox_finish \placedbox}
+\unexpanded\def\lefttopbox {\hpack\bgroup\dowithnextboxcs\syst_boxes_lefttopbox_finish \placedbox}
+\unexpanded\def\righttopbox {\hpack\bgroup\dowithnextboxcs\syst_boxes_righttopbox_finish \placedbox}
+\unexpanded\def\leftbottombox {\hpack\bgroup\dowithnextboxcs\syst_boxes_leftbottombox_finish \placedbox}
+\unexpanded\def\rightbottombox{\hpack\bgroup\dowithnextboxcs\syst_boxes_rightbottombox_finish\placedbox}
+
+\let\topleftbox \lefttopbox
+\let\toprightbox \righttopbox
+\let\bottomleftbox \leftbottombox
+\let\bottomrightbox\rightbottombox
+
+\def\syst_boxes_rightbox_finish
+ {\global\boxhdisplacement\boxoffset
+ \global\boxvdisplacement.5\dimexpr\ht\nextbox-\dp\nextbox\relax
+ \boxcursor
+ \boxxmove\nextbox \boxhdisplacement
+ \boxymove\nextbox-\boxvdisplacement
+ \box\nextbox
+ \egroup}
+
+\def\syst_boxes_leftbox_finish
+ {\global\boxhdisplacement\dimexpr-\wd\nextbox-\boxoffset\relax
+ \global\boxvdisplacement.5\dimexpr\ht\nextbox-\dp\nextbox\relax
+ \boxcursor
+ \boxxmove\nextbox \boxhdisplacement
+ \boxymove\nextbox-\boxvdisplacement
+ \box\nextbox
+ \egroup}
+
+\def\syst_boxes_topbox_finish
+ {\global\boxhdisplacement-.5\wd\nextbox
+ \global\boxvdisplacement\dimexpr-\dp\nextbox-\boxoffset\relax
+ \boxcursor
+ \boxxmove\nextbox \boxhdisplacement
+ \boxymove\nextbox-\boxvdisplacement
+ \box\nextbox
+ \egroup}
+
+\def\syst_boxes_bottombox_finish
+ {\global\boxhdisplacement-.5\wd\nextbox
+ \global\boxvdisplacement\dimexpr\ht\nextbox+\boxoffset\relax
+ \boxcursor
+ \boxxmove\nextbox \boxhdisplacement
+ \boxymove\nextbox-\boxvdisplacement
+ \box\nextbox
+ \egroup}
+
+\def\syst_boxes_lefttopbox_finish
+ {\global\boxhdisplacement\dimexpr-\wd\nextbox-\boxoffset\relax
+ \global\boxvdisplacement\dimexpr-\dp\nextbox-\boxoffset\relax
+ \boxcursor
+ \boxxmove\nextbox \boxhdisplacement
+ \boxymove\nextbox-\boxvdisplacement
+ \box\nextbox
+ \egroup}
+
+\def\syst_boxes_righttopbox_finish
+ {\global\boxhdisplacement\boxoffset
+ \global\boxvdisplacement\dimexpr-\dp\nextbox-\boxoffset\relax
+ \boxcursor
+ \boxxmove\nextbox \boxhdisplacement
+ \boxymove\nextbox-\boxvdisplacement
+ \box\nextbox
+ \egroup}
+
+\def\syst_boxes_leftbottombox_finish
+ {\global\boxhdisplacement\dimexpr-\wd\nextbox-\boxoffset\relax
+ \global\boxvdisplacement\dimexpr\ht\nextbox+\boxoffset\relax
+ \boxcursor
+ \boxxmove\nextbox \boxhdisplacement
+ \boxymove\nextbox-\boxvdisplacement
+ \box\nextbox
+ \egroup}
+
+\def\syst_boxes_rightbottombox_finish
+ {\global\boxhdisplacement\boxoffset
+ \global\boxvdisplacement\dimexpr\ht\nextbox+\boxoffset\relax
+ \boxcursor
+ \boxxmove\nextbox \boxhdisplacement
+ \boxymove\nextbox-\boxvdisplacement
+ \box\nextbox
+ \egroup}
+
+\unexpanded\def\middlebox {\hpack\bgroup\dowithnextboxcs\syst_boxes_middlebox_finish \placedbox}
+\unexpanded\def\baselinemiddlebox{\hpack\bgroup\dowithnextboxcs\syst_boxes_baselinemiddlebox_finish\placedbox}
+\unexpanded\def\baselineleftbox {\hpack\bgroup\dowithnextboxcs\syst_boxes_baselineleftbox_finish \placedbox}
+\unexpanded\def\baselinerightbox {\hpack\bgroup\dowithnextboxcs\syst_boxes_baselinerightbox_finish \placedbox}
+
+\def\syst_boxes_middlebox_finish
+ {\global\boxhdisplacement-.5\wd\nextbox
+ \global\boxvdisplacement.5\dimexpr\ht\nextbox-\dp\nextbox\relax
+ \boxcursor
+ \boxxmove\nextbox \boxhdisplacement
+ \boxymove\nextbox-\boxvdisplacement
+ \box\nextbox
+ \egroup}
+
+\def\syst_boxes_baselinemiddlebox_finish
+ {\global\boxhdisplacement\dimexpr-.5\wd\nextbox-\boxoffset\relax
+ \global\boxvdisplacement-\boxoffset
+ \boxcursor
+ \boxxmove\nextbox \boxhdisplacement
+ \boxymove\nextbox-\boxvdisplacement
+ \box\nextbox
+ \egroup}
+
+\def\syst_boxes_baselineleftbox_finish
+ {\global\boxhdisplacement\dimexpr-\wd\nextbox-\boxoffset\relax
+ \global\boxvdisplacement-\boxoffset
+ \boxcursor
+ \boxxmove\nextbox \boxhdisplacement
+ \boxymove\nextbox-\boxvdisplacement
+ \box\nextbox
+ \egroup}
+
+\def\syst_boxes_baselinerightbox_finish
+ {\global\boxhdisplacement\boxoffset
+ \global\boxvdisplacement-\boxoffset
+ \boxcursor
+ \boxxmove\nextbox \boxhdisplacement
+ \boxymove\nextbox-\boxvdisplacement
+ \box\nextbox
+ \egroup}
+
+%D \macros
+%D {obox}
+%D
+%D Experimental, not yet frozen:
+
+\unexpanded\def\lrtbbox#1#2#3#4% l r t b
+ {\bgroup
+ \dowithnextboxcontent
+ {\advance\hsize-#1\advance\hsize-#2\relax
+ \advance\vsize-#3\advance\vsize-#4\relax}
+ {\forgetall\vpack to \vsize{\vskip#3\hpack to \hsize{\hskip#1\box\nextbox\hss}\vss}\egroup}
+ \vbox}
+
+%D \macros
+%D {toplinebox}
+%D
+%D See core-tbl.tex for an example of its usage:
+
+\unexpanded\def\toplinebox
+ {\dowithnextboxcs\syst_boxes_toplinebox_finish\tbox}
+
+\def\syst_boxes_toplinebox_finish
+ {\ifdim\dp\nextbox>\strutdepth
+ \scratchdimen\dp\nextbox
+ \advance\scratchdimen-\strutdepth
+ \getnoflines\scratchdimen
+ \struttedbox{\box\nextbox}%
+ \dorecurse\noflines\verticalstrut
+ \else
+ \box\nextbox
+ \fi}
+
+%D \macros
+%D {initializeboxstack,savebox,foundbox}
+%D
+%D At the cost of some memory, but saving box registers, we have implemented a box
+%D repository.
+%D
+%D \starttyping
+%D \initializeboxstack{one}
+%D
+%D \savebox{one}{a}{test a}
+%D \savebox{one}{p}{test p}
+%D \savebox{one}{q}{test q}
+%D
+%D \hbox{a:\foundbox{one}{a}} \par
+%D \hbox{q:\foundbox{one}{q}} \par
+%D \hbox{p:\foundbox{one}{p}} \par
+%D \hbox{x:\foundbox{one}{x}} \par
+%D \hbox{y:\foundbox{two}{a}} \par
+%D \stoptyping
+
+%D Kind of obsolete:
+
+\installcorenamespace {stackbox}
+\installcorenamespace {stacklst}
+
+\unexpanded\def\setstackbox#1#2%
+ {\ifcsname\??stackbox#1:#2\endcsname\else
+ \expandafter\newbox\csname\??stackbox#1:#2\endcsname
+ \fi
+ \global\setbox\csname\??stackbox#1:#2\endcsname\vbox}
+
+\unexpanded\def\initializeboxstack#1%
+ {\def\docommand##1{\setstackbox{#1}{##1}{}}%
+ \ifcsname\??stacklst#1\endcsname
+ \expandafter\processcommacommand\expandafter[\lastnamedcs]\docommand
+ \fi
+ \letgvalueempty{\??stacklst#1}}
+
+\unexpanded\def\savebox#1#2% stack name
+ {% beware, \setxvalue defines the cs beforehand so we cannot use the
+ % test inside the { }
+ \ifcsname\??stacklst#1\endcsname
+ %\setxvalue{\??stacklst#1}{\csname\??stacklst#1\endcsname,#2}%
+ \expandafter\xdef\csname\??stacklst#1\expandafter\endcsname\expandafter{\lastnamedcs,#2}%
+ \else
+ \expandafter\xdef\csname\??stacklst#1\endcsname{#2}%
+ \fi
+ \setstackbox{#1}{#2}}
+
+\unexpanded\def\flushbox#1#2% unwrapped
+ {\ifcsname\??stackbox#1:#2\endcsname
+ \box\lastnamedcs
+ \else
+ \emptybox
+ \fi}
+
+\unexpanded\def\restorebox#1#2% unwrapped
+ {\ifcsname\??stackbox#1:#2\endcsname
+ \copy\lastnamedcs
+ \else
+ \emptybox
+ \fi}
+
+\unexpanded\def\foundbox#1#2% wrapped
+ {\vpack
+ {\ifcsname\??stackbox#1:#2\endcsname
+ \copy\lastnamedcs
+ \fi}}
+
+\unexpanded\def\doifelsebox#1#2%
+ {\ifcsname\??stackbox#1:#2\endcsname
+ \ifvoid\lastnamedcs
+ \doubleexpandafter\secondoftwoarguments
+ \else
+ \doubleexpandafter\firstoftwoarguments
+ \fi
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\let\doifboxelse\doifelsebox
+
+%D This one is cheaper (the above is no longer used that much):
+
+\installcorenamespace {boxstack}
+
+\newcount\c_syst_boxes_stack
+\let \b_syst_boxes_stack\relax
+
+\unexpanded\def\syst_boxes_stack_allocate
+ {\newbox\b_syst_boxes_stack
+ \expandafter\let\csname\??boxstack\number\c_syst_boxes_stack\endcsname\b_syst_boxes_stack}
+
+\unexpanded\def\syst_boxes_push#1#2%
+ {\global\advance\c_syst_boxes_stack\plusone
+ \expandafter\let\expandafter\b_syst_boxes_stack\csname\??boxstack\number\c_syst_boxes_stack\endcsname
+ \ifx\b_syst_boxes_stack\relax % cheaper then csname check as in most cases it's defined
+ \syst_boxes_stack_allocate
+ \fi
+ #1\setbox\b_syst_boxes_stack\box#2\relax}
+
+\unexpanded\def\syst_boxes_pop#1#2%
+ {#1\setbox#2\box\csname\??boxstack\number\c_syst_boxes_stack\endcsname
+ \global\advance\c_syst_boxes_stack\minusone}
+
+\unexpanded\def\localpushbox {\syst_boxes_push\relax}
+\unexpanded\def\localpopbox {\syst_boxes_pop \relax}
+
+\unexpanded\def\globalpushbox{\syst_boxes_push\global}
+\unexpanded\def\globalpopbox {\syst_boxes_pop \global}
+
+%D And here is a more modern one (not yet in i-*):
+%D
+%D \starttyping
+%D \dorecurse {100} {
+%D \setbox\zerocount\hbox{test \recurselevel}
+%D \putboxincache{foo}{\recurselevel}\zerocount
+%D \copyboxfromcache{foo}{\recurselevel}\zerocount
+%D \iftrue
+%D \setbox\zerocount\hbox{\directboxfromcache{foo}{\recurselevel}}%
+%D \else
+%D \getboxfromcache{foo}{\recurselevel}\zerocount
+%D \fi
+%D }
+%D \resetboxesincache{foo}
+%D \stoptyping
+
+\unexpanded\def\putboxincache #1#2#3{\clf_putboxincache {#1}{#2}#3\relax}
+\unexpanded\def\getboxfromcache #1#2#3{\clf_getboxfromcache {#1}{#2}#3\relax}
+\unexpanded\def\doifelseboxincache #1#2{\clf_doifelseboxincache {#1}{#2}}
+\unexpanded\def\copyboxfromcache #1#2#3{\clf_copyboxfromcache {#1}{#2}#3\relax}
+\unexpanded\def\directboxfromcache #1#2{\clf_directboxfromcache {#1}{#2}}
+\unexpanded\def\directcopyboxfromcache#1#2{\clf_directcopyboxfromcache{#1}{#2}}
+\unexpanded\def\resetboxesincache #1{\clf_resetboxesincache {#1}}
+
+\unexpanded\def\putnextboxincache#1#2%
+ {\dowithnextbox{\putboxincache{#1}{#2}\nextbox}}
+
+%D \macros
+%D {removedepth, obeydepth}
+%D
+%D While \type {\removedepth} removes the preceding depth, \type {\obeydepth} makes
+%D sure we have depth. Both macros leave the \type {\prevdepth} untouched.
+
+\unexpanded\def\removedepth
+ {\ifvmode
+ \ifdim\prevdepth>\zeropoint
+ \kern-\prevdepth
+ \fi
+ \fi}
+
+\unexpanded\def\obeydepth
+ {\par % watch out for changes in math formulas
+ \ifvmode\ifdim\prevdepth<\zeropoint\orelse\ifdim\prevdepth<\strutdp
+ \kern\dimexpr\strutdp-\prevdepth\relax
+ \prevdepth\strutdp
+ \fi\fi}
+
+\unexpanded\def\undepthed
+ {\dowithnextbox{\dp\nextbox\zeropoint\box\nextbox}\hbox}
+
+%D \macros
+%D {removebottomthings, removelastskip}
+%D
+%D A funny (but rather stupid) one, plus a redefinition.
+
+\unexpanded\def\removebottomthings
+ {\dorecurse\plusfive{\unskip\unkern\unpenalty}}
+
+\unexpanded\def\removelastskip % \ifvmode the plain tex one \fi
+ {\ifvmode\ifzeropt\lastskip\else\vskip-\lastskip\fi\fi}
+
+%D \macros
+%D {makestrutofbox}
+%D
+%D This macro sets the dimensions of a box to those of a strut. Sort of obsolete so
+%D it will go away.
+
+\unexpanded\def\makestrutofbox % not used
+ {\afterassignment\syst_boxes_makestrutofbox\c_boxes_register}
+
+\def\syst_boxes_makestrutofbox
+ {\ht\c_boxes_register\strutht
+ \dp\c_boxes_register\strutdp
+ \wd\c_boxes_register\zeropoint}
+
+%D \macros
+%D {raisebox,lowerbox}
+%D
+%D Some more box stuff, related to positioning (under construction). Nice stuff for
+%D a tips and tricks maps article.
+%D
+%D \starttyping
+%D \raisebox{100pt}\hbox{test}
+%D \hsmash{\raisebox{100pt}\hbox{test}}
+%D \stoptyping
+
+\unexpanded\def\raisebox#1{\bgroup\afterassignment\syst_boxes_raise_indeed\scratchdimen#1} % so both 10pt and {10pt} is accepted
+\unexpanded\def\lowerbox#1{\bgroup\afterassignment\syst_boxes_lower_indeed\scratchdimen#1} % so both 10pt and {10pt} is accepted
+
+\def\syst_boxes_raise_indeed{\dowithnextboxcs\syst_boxes_raise_finish}
+\def\syst_boxes_lower_indeed{\dowithnextboxcs\syst_boxes_lower_finish}
+
+\def\syst_boxes_raise_finish
+ {\boxyoffset\nextbox\scratchdimen
+ \ht\nextbox\strutht
+ \dp\nextbox\strutdp
+ \box\nextbox
+ \egroup}
+
+\def\syst_boxes_lower_finish
+ {\boxyoffset\nextbox-\scratchdimen
+ \ht\nextbox\strutht
+ \dp\nextbox\strutdp
+ \box\nextbox
+ \egroup}
+
+% vcenter in text, we kunnen vcenter overloaden
+
+\unexpanded\def\halfwaybox
+ {\hpack\bgroup
+ \dowithnextboxcs\syst_boxes_halfwaybox_finish\hbox}
+
+\def\syst_boxes_halfwaybox_finish
+ {\dp\nextbox\zeropoint
+ \lower.5\ht\nextbox\box\nextbox
+ \egroup}
+
+\unexpanded\def\depthonlybox
+ {\tpack\bgroup
+ \dowithnextboxcs\syst_boxes_depthonlybox_finish\vbox}
+
+\def\syst_boxes_depthonlybox_finish
+ {\hsize\wd\nextbox
+ \kern\zeropoint\box\nextbox
+ \egroup}
+
+%D New:
+
+\def\setdimentoatleast#1#2{\ifdim#1>\zeropoint\else#1=#2\fi}
+\def\setdimentoatmost #1#2{\ifdim#1>#2\relax \else#1=#2\fi}
+
+%D And even rawer:
+
+\let\naturalvcenter\normalvtop % will go away
+
+%D \macros
+%D {vcenter}
+%D
+%D Also new: tex mode \type {\vcenter}.
+
+\unexpanded\def\vcenter
+ {\vbox\bgroup
+ \dowithnextboxcs\syst_boxes_vcenter_finish\vbox}
+
+\def\syst_boxes_vcenter_finish
+ {\hpack{\normalstartimath\vcenter{\box\nextbox}\normalstopimath}%
+ \egroup}
+
+% could be \everymathematics
+
+\prependtoks \let\vcenter\normalvcenter \to \everymath
+\prependtoks \let\vcenter\normalvcenter \to \everydisplay
+
+% \appendtoks \let\vcenter\normalvcenter \to \everymathematics
+
+%D \macros
+%D {frozenhbox}
+%D
+%D A not so well unhboxable box can be made with:
+
+\unexpanded\def\frozenhbox
+ {\hpack\bgroup
+ \dowithnextboxcs\syst_boxes_frozenhbox_finish\hbox}
+
+\def\syst_boxes_frozenhbox_finish
+ {\hpack{\hpack{\box\nextbox}}%
+ \egroup}
+
+%D \macros
+%D {setboxllx,setboxlly,gsetboxllx,gsetboxlly,getboxllx,getboxlly}
+%D
+%D A prelude to an extended \TEX\ feature:
+
+\installcorenamespace {box_x}
+\installcorenamespace {box_y}
+
+\unexpanded\def\setboxllx #1#2{\expandafter\edef\csname\??box_x\number#1\endcsname{\the\dimexpr#2\relax}}
+\unexpanded\def\setboxlly #1#2{\expandafter\edef\csname\??box_y\number#1\endcsname{\the\dimexpr#2\relax}}
+
+\unexpanded\def\gsetboxllx#1#2{\expandafter\xdef\csname\??box_x\number#1\endcsname{\the\dimexpr#2\relax}}
+\unexpanded\def\gsetboxlly#1#2{\expandafter\xdef\csname\??box_y\number#1\endcsname{\the\dimexpr#2\relax}}
+
+%def\getboxllx#1{\ifcsname\??box_x\number#1\endcsname\csname\??box_x\number#1\endcsname\else\zeropoint\fi}
+%def\getboxlly#1{\ifcsname\??box_y\number#1\endcsname\csname\??box_y\number#1\endcsname\else\zeropoint\fi}
+\def\getboxllx#1{\ifcsname\??box_x\number#1\endcsname\lastnamedcs\else\zeropoint\fi}
+\def\getboxlly#1{\ifcsname\??box_y\number#1\endcsname\lastnamedcs\else\zeropoint\fi}
+
+\def\directgetboxllx#1{\csname\??box_x\number#1\endcsname} % use when sure existence
+\def\directgetboxlly#1{\csname\??box_y\number#1\endcsname} % use when sure existence
+
+%D \macros
+%D {shownextbox}
+%D
+%D Handy for tracing
+%D
+%D \starttyping
+%D \shownextbox\vbox{test}
+%D \shownextbox\vbox{test\endgraf}
+%D \shownextbox\vbox{test\endgraf\strut\endgraf}
+%D \shownextbox\vbox{test\endgraf\thinrule}
+%D \shownextbox\vbox{\setupwhitespace[big]test\endgraf\thinrule}
+%D \stoptyping
+
+\unexpanded\def\shownextbox % seldom used
+ {\dowithnextbox
+ {\bgroup
+ \showboxbreadth\maxdimen
+ \showboxdepth \maxdimen
+ \scratchcounter\interactionmode
+ \batchmode
+ \showbox\nextbox
+ \box\nextbox
+ \interactionmode\scratchcounter
+ \egroup}}
+
+\unexpanded\def\spreadhbox#1% rebuilds \hbox{<box><hss><box><hss><box>}
+ {\bgroup
+ \ifhbox#1\relax
+ \setbox\scratchboxtwo\emptybox
+ \unhbox#1%
+ \doloop
+ {\unpenalty\unskip\unpenalty\unskip\unpenalty\unskip
+ \setbox\scratchboxone\lastbox
+ \ifvoid\scratchboxone
+ \exitloop
+ \else
+ \setbox\scratchboxtwo\hbox
+ {\ifhbox\scratchboxone \spreadhbox\scratchboxone\else\box\scratchboxone\fi
+ \ifvoid\scratchboxtwo \else\hss\unhbox\scratchboxtwo\fi}%
+ \fi}%
+ \ifvoid\scratchboxtwo\else\unhbox\scratchboxtwo\fi
+ \else
+ \box#1%
+ \fi
+ \egroup}
+
+% makes sense but too much log for overfull boxes:
+%
+% \showboxbreadth\maxdimen
+% \showboxdepth \maxdimen
+
+%D Moved from cont-new:
+%D
+%D \starttyping
+%D \minimalhbox 100pt {test}
+%D \stoptyping
+
+\unexpanded\def\minimalhbox#1#%
+ {\dowithnextbox
+ {\bgroup
+ \setbox\scratchbox\hpack#1{\hss}%
+ \ifdim\wd\nextbox<\wd\scratchbox\wd\nextbox\wd\scratchbox\fi
+ \box\nextbox
+ \egroup}
+ \hbox}
+
+%D A bit dirty:
+
+\unexpanded\def\nodestostring#1#2% more tolerant for #2=\cs
+ {\begingroup
+ \setbox\nextbox\hbox{#2}%
+ \normalexpanded{\endgroup\edef\noexpand#1{\clf_boxtostring\nextbox}}}
+
+%D Even more dirty:
+
+\let\hyphenatedhbox\hbox
+
+%D We can do this:
+%D
+%D \starttyping
+%D \setbox0\hbox to 10cm{foo} \setbox2\hbox{\unhbox0} \the\wd2
+%D \stoptyping
+%D
+%D But this saves a copy (and hpack pass):
+%D
+%D \starttyping
+%D \setbox0\hbox to 10cm{foo} \the\naturalwd0
+%D \stoptyping
+
+\newdimen\lastnaturalboxwd
+\newdimen\lastnaturalboxht
+\newdimen\lastnaturalboxdp
+
+\let\getnaturaldimensions\clf_getnaturaldimensions % sets three dimensions
+\let\naturalwd \clf_naturalwd % calculates and returns wd
+
+\let\getnaturalwd\clf_getnaturalwd % no intermediate
+\let\setnaturalwd\clf_setnaturalwd % no intermediate
+
+\unexpanded\def\doifelserighttoleftinbox{\clf_doifelserighttoleftinbox}
+
+\let\doifrighttoleftinboxelse\doifelserighttoleftinbox
+
+%D New, used in high/low:
+
+\definesystemattribute [runningtext] [public]
+
+%unexpanded\def\runninghbox{\hbox attr \runningtextattribute \plusone} % not yet in i-*
+\unexpanded\def\runninghbox{\hbox attr \runningtextattribute \fontid\font} % not yet in i-*
+
+%D To complement lua (yet undocumented):
+
+\unexpanded\def\beginhbox{\hbox\bgroup} \let\endhbox\egroup
+\unexpanded\def\beginvbox{\vbox\bgroup} \let\endvbox\egroup
+\unexpanded\def\beginvtop{\vtop\bgroup} \let\endvtop\egroup
+
+\unexpanded\def\sethboxregister#1{\setbox#1\hbox}
+\unexpanded\def\setvboxregister#1{\setbox#1\vbox}
+\unexpanded\def\setvtopregister#1{\setbox#1\vtop}
+
+\unexpanded\def\flushboxregister#1{\box\numexpr#1\relax}
+
+\unexpanded\def\starthboxregister#1{\setbox#1\hbox\bgroup} \let\stophboxregister\egroup
+\unexpanded\def\startvboxregister#1{\setbox#1\vbox\bgroup} \let\stopvboxregister\egroup
+\unexpanded\def\startvtopregister#1{\setbox#1\vtop\bgroup} \let\stopvtopregister\egroup
+
+%D For whatever third party package needs it:
+%D
+%D \starttyping
+%D \newlocalbox\BoxOne
+%D \newlocalbox\BoxTwo
+%D
+%D \setbox\BoxOne\hbox{Box One}
+%D \setbox\BoxTwo\hbox{Box Two}
+%D
+%D [\box\BoxTwo] [\box\BoxOne]
+%D \stoptyping
+
+\installcorenamespace{localbox}
+
+\unexpanded\def\newlocalbox#1%
+ {\expandafter\let\expandafter#1\csname\??localbox\string#1\endcsname
+ \ifx#1\relax
+ \syst_aux_new_localbox#1%
+ \fi}
+
+\def\syst_aux_new_localbox#1%
+ {\expandafter\newbox\csname\??localbox\string#1\endcsname
+ \newlocalbox#1}
+
+%D Who knows when this comes in handy:
+
+\unexpanded\def\lastlinewidth{\dimexpr\clf_lastlinewidth\scaledpoint\relax}
+
+%D Keep as reference:
+
+% \unexpanded\def\tightvbox{\dowithnextbox{\dp\nextbox\zeropoint\box\nextbox}\vbox}
+% \unexpanded\def\tightvtop{\dowithnextbox{\ht\nextbox\zeropoint\box\nextbox}\vtop}
+
+%D This one keeps dimensions and sets the shift field (and so it's more for testing
+%D than for real usage):
+
+\unexpanded\def\shiftbox {\clf_shiftbox}
+\unexpanded\def\vpackbox {\clf_vpackbox}
+\unexpanded\def\hpackbox {\clf_hpackbox}
+\unexpanded\def\vpackedbox{\clf_vpackedbox}
+\unexpanded\def\hpackedbox{\clf_hpackedbox}
+
+%D This one has been moved from a 2 decade old file. It makes something boxed
+%D sit on the baseline.
+
+\unexpanded\def\linebox
+ {\hpack\bgroup\dowithnextbox
+ {\scratchdimen\dimexpr\dimexpr\htdp\nextbox-\lineheight\relax/2+\dp\strutbox\relax
+ \setbox\nextbox\hpack{\lower\scratchdimen\box\nextbox}%
+ \ht\nextbox\ht\strutbox
+ \dp\nextbox\dp\strutbox
+ \box\nextbox
+ \egroup}
+ \hbox}
+
+\protect \endinput
+
+% a bit of test code:
+
+% \hbox \bgroup
+% \ruledvbox {\hbox{\strut gans}}
+% \ruledvbox to \lineheight {\hbox{\strut gans}}
+% \ruledvbox to \lineheight {\hbox {gans}}
+% \ruledvbox to \strutheight{\hbox {gans}}
+% \ruledvbox to \strutheight{\hbox{\strut gans}}
+% \ruledvbox to \strutheight{\vss\hbox{gans}}
+% \egroup
+
+% to be considered
+
+% \startluacode
+%
+% local spacer = lpeg.patterns.spacer
+%
+% function commands.withwords(command,str)
+% if str then
+% command = command or "ruledhbox"
+% local done = false
+% local function apply(s)
+% if done then
+% context.space()
+% done = true
+% else
+% context.dontleavehmode()
+% end
+% context[command](s)
+% end
+% lpeg.match(lpeg.splitter(spacer,apply),str)
+% end
+%
+% end
+%
+% \stopluacode
+%
+% \unprotect
+%
+% \unexpanded\def\withwordsinstring#1#2% command str
+% {\ctxcommand{withwords(\!!bs#1\!!es,\!!bs#2\!!es)}}
+%
+% \unexpanded\def\withwordsinfile#1#2% command name
+% {\ctxcommand{withwords(\!!bs#1\!!es,io.loaddata(resolvers.findfile("#2")))}}
+%
+% \protect
+%
+% \starttext
+%
+% \defineframed[colored][foregroundcolor=red,foregroundstyle=\bfc\underbar,location=low]
+%
+% \withwordsinstring{colored}{bla bla}
+% \withwordsinfile{colored}{ward.tex}
+%
+% \stoptext
diff --git a/Master/texmf-dist/tex/context/base/mkiv/supp-mat.mkiv b/Master/texmf-dist/tex/context/base/mkiv/supp-mat.mkiv
index f72a0ff89dc..f3b94f73522 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/supp-mat.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/supp-mat.mkiv
@@ -160,8 +160,8 @@
\unexpanded\def\dimension#1%
{\pushmacro\dodimensionsignal
\gdef\dodimensionsignal{\kern\dimensionsignal}%
- \ifdim\lastskip=\zeropoint\relax
- \ifdim\lastkern=\zeropoint\relax
+ \ifzeropt\lastskip
+ \ifzeropt\lastkern
\ifmmode
\mathematics{\dimensionhalfspace\dimensionhalfspace\dimensiontypeface#1}%
\else
diff --git a/Master/texmf-dist/tex/context/base/mkiv/supp-ran.lua b/Master/texmf-dist/tex/context/base/mkiv/supp-ran.lua
index 1ad9293ee44..1a2d10bea72 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/supp-ran.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/supp-ran.lua
@@ -10,8 +10,8 @@ if not modules then modules = { } end modules ['supp-ran'] = {
local report_system = logs.reporter("system","randomizer")
-local trace_random = false trackers.register("system.randomizer", function(v) trace_random = v end)
-local trace_detail = false trackers.register("system.randomizer.detail",function(v) trace_detail = v end)
+local trace_random = false trackers.register("system.randomizer", function(v) trace_random = v end)
+local trace_details = false trackers.register("system.randomizer.details", function(v) trace_details = v end)
local insert, remove = table.insert, table.remove
@@ -28,7 +28,7 @@ local maxcount = 0x3FFFFFFF -- 2^30-1
math.random = function(...)
local n = random(...)
- if trace_detail then
+ if trace_details then
report_system("math %s",n)
end
return n
@@ -43,7 +43,7 @@ local function setrandomseedi(n)
n = round(n)
randomseed(n)
last = random(0,maxcount) -- we need an initial value
- if trace_detail then
+ if trace_details then
report_system("seed %s from %s",last,n)
elseif trace_random then
report_system("setting seed %s",n)
@@ -54,7 +54,7 @@ math.setrandomseedi = setrandomseedi
local function getrandomnumber(min,max)
last = random(min,max)
- if trace_detail then
+ if trace_details then
report_system("number %s",last)
end
return last
@@ -71,7 +71,7 @@ end
-- local function getmprandomnumber()
-- last = random(0,4095)
--- if trace_detail then
+-- if trace_details then
-- report_system("mp number %s",last)
-- end
-- return last
@@ -81,7 +81,7 @@ end
local function pushrandomseed()
insert(stack,last)
- if trace_random or trace_detail then
+ if trace_random or trace_details then
report_system("pushing seed %s",last)
end
end
@@ -89,7 +89,7 @@ end
local function reuserandomseed(n)
local seed = stack[#stack]
if seed then
- if trace_random or trace_detail then
+ if trace_random or trace_details then
report_system("reusing seed %s",last)
end
randomseed(seed)
@@ -99,7 +99,7 @@ end
local function poprandomseed()
local seed = remove(stack)
if seed then
- if trace_random or trace_detail then
+ if trace_random or trace_details then
report_system("popping seed %s",seed)
end
randomseed(seed)
@@ -109,13 +109,13 @@ end
local function getrandom(where,...)
if type(where) == "string" then
local n = random(...)
- if trace_detail then
+ if trace_details then
report_system("%s %s",where,n)
end
return n
else
local n = random(where,...)
- if trace_detail then
+ if trace_details then
report_system("utilities %s",n)
end
return n
diff --git a/Master/texmf-dist/tex/context/base/mkiv/symb-emj.lua b/Master/texmf-dist/tex/context/base/mkiv/symb-emj.lua
index d6e2aebea6f..4d16bbb7311 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/symb-emj.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/symb-emj.lua
@@ -24,6 +24,7 @@ local tonode = nuts.tonode
local tonut = nuts.tonut
local remove_node = nuts.remove
local isglyph = nuts.isglyph
+local getnext = nuts.getnext
local function removemodifiers(head)
local head = tonut(head)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/symb-ini.lua b/Master/texmf-dist/tex/context/base/mkiv/symb-ini.lua
index 6a4a1882529..588e5d2ab5c 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/symb-ini.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/symb-ini.lua
@@ -21,6 +21,7 @@ local report_symbols = logs.reporter ("fonts","symbols")
local status_symbols = logs.messenger("fonts","symbols")
local patterns = {
+ CONTEXTLMTXMODE > 0 and "symb-imp-%s.mkxl" or "",
"symb-imp-%s.mkiv",
"symb-imp-%s.tex",
-- obsolete:
@@ -29,12 +30,8 @@ local patterns = {
}
local function action(name,foundname)
- -- context.startnointerference()
- context.startreadingfile()
- context.input(foundname)
+ commands.loadlibrary(name,foundname,false)
status_symbols("library %a loaded",name)
- context.stopreadingfile()
- -- context.stopnointerference()
end
local function failure(name)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/syst-aux.lua b/Master/texmf-dist/tex/context/base/mkiv/syst-aux.lua
index 9b0ca82c430..46bb8e3f748 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/syst-aux.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/syst-aux.lua
@@ -390,6 +390,13 @@ implement {
}
implement {
+ name = "benchmarktimer",
+ actions = function()
+ statistics.benchmarktimer("whatever")
+ end
+}
+
+implement {
name = "elapsedtime",
actions = function()
statistics.stoptiming("whatever")
@@ -423,6 +430,9 @@ context.secondoftwoarguments = ctx_secondoftwoarguments
context.firstofoneargument = ctx_firstofoneargument
context.gobbleoneargument = ctx_gobbleoneargument
+local ctx_iftrue = context.iftrue
+local ctx_iffalse = context.iffalse
+
local hash = utilities.parsers.hashes.settings_to_set
local function doifelsecommon(a,b)
@@ -554,6 +564,45 @@ local function doifnotcommon(a,b)
ctx_firstofoneargument()
end
+-- local function hascommonargumentcondition(a,b)
+-- if a == b then
+-- setmacro("commalistelement",a)
+-- if a == "" then
+-- ctx_iffalse()
+-- else
+-- ctx_iftrue()
+-- end
+-- return
+-- end
+-- local ba = find(a,",",1,true)
+-- local bb = find(b,",",1,true)
+-- if ba and bb then
+-- local ha = hash[a]
+-- local hb = hash[b]
+-- for k in next, ha do
+-- if hb[k] then
+-- setmacro("commalistelement",k)
+-- ctx_iftrue()
+-- return
+-- end
+-- end
+-- elseif ba then
+-- if hash[a][b] then
+-- setmacro("commalistelement",b)
+-- ctx_iftrue()
+-- return
+-- end
+-- elseif bb then
+-- if hash[b][a] then
+-- setmacro("commalistelement",a)
+-- ctx_iftrue()
+-- return
+-- end
+-- end
+-- setmacro("commalistelement","")
+-- ctx_iffalse()
+-- end
+
local function doifelseinset(a,b)
if a == b then
setmacro("commalistelement",a)
@@ -641,10 +690,18 @@ implement {
arguments = "2 strings",
}
+-- implement {
+-- name = "hascommonargumentcondition",
+-- actions = hascommonargumentcondition,
+-- arguments = "2 strings",
+-- arguments = { "argument", "argument" },
+-- }
+
implement {
name = "doifelseinset",
actions = doifelseinset,
arguments = "2 strings",
+-- arguments = { "argument", "argument" },
}
implement {
diff --git a/Master/texmf-dist/tex/context/base/mkiv/syst-aux.mkiv b/Master/texmf-dist/tex/context/base/mkiv/syst-aux.mkiv
index 3004c08b805..255f0746c39 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/syst-aux.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/syst-aux.mkiv
@@ -11,11 +11,6 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-%D There are some references to \LUA\ variants here but these concern (often old)
-%D experiments, moved from local test modules to here, cleaned up, but not really
-%D used. After all it's not that urgent and replacing helpers is a delicate process.
-%D Don't depend on it.
-
\registerctxluafile{syst-aux}{}
% A dedicated primitive \ifvoidmacro\cs == \ifx\cs\empty is some 10% faster but
@@ -60,19 +55,21 @@
\let\unexpanded\normalprotected
-% %D \macros
-% %D {expunded}
-% %D
-% %D \unexpanded\edef\TestA{zzz}
-% %D \edef\TestB{zzz}
-% %D
-% %D \doifelse {\TestA} {\TestB} {WRONG} {OKAY} \par
-% %D \doifelse {\TestA} {\expunded\TestB} {WRONG} {OKAY} \par
-% %D \doifelse {\expunded\TestA} {\TestB} {OKAY} {WRONG} \par
-% %D \doifelse {\expunded\TestA} {\expunded\TestB} {OKAY} {WRONG} \par
+\ifcase\contextlmtxmode
-% %def\expunded#1{\normalexpanded\expandafter{#1}}
-% \def\expunded#1{\expandafter\empty#1} % used within an edef anyway
+ \def\startlmtxmode#1\stoplmtxmode{}
+ \let\stoplmtxmode \relax
+ \let\startmkivmode\relax
+ \let\stopmkivmode \relax
+
+\else
+
+ \let\startlmtxmode\relax
+ \let\stoplmtxmode \relax
+ \def\startmkivmode#1\stopmkivmode{}
+ \let\stopmkivmode \relax
+
+\fi
%D As we don't have namespace definers yet, we use a special one:
@@ -212,8 +209,7 @@
%D Recent \TEX\ engines have a primitive \type {\expanded} and we will use that when
%D possible. After all, we can make not expandable macros now.
-% We cannot use the next variant as first we need to adapt \type {##}'s
-% in callers:
+% We cannot use the next variant as first we need to adapt \type {##}'s in callers:
%
% \def\expanded#1%
% {\normalexpanded{\noexpand#1}}
@@ -274,9 +270,8 @@
%D \doifnextcharelse {karakter} {then ...} {else ...}
%D \stoptyping
%D
-%D This macro differs from the original in the use of \type
-%D {\localnext} because we don't want clashes with \type
-%D {\next}.
+%D This macro differs from the original in the use of \type {\localnext} because we
+%D don't want clashes with \type {\next}.
\let\next \relax
\let\nextnext \relax
@@ -287,14 +282,6 @@
\let\m_syst_action_yes\relax
\let\m_syst_action_nop\relax
-\unexpanded\def\doifelsenextchar#1#2#3% #1 should not be {} !
- {\let\charactertoken=#1% = needed here
- \def\m_syst_action_yes{#2}%
- \def\m_syst_action_nop{#3}%
- \futurelet\nexttoken\syst_helpers_inspect_next_character}
-
-\let\doifnextcharelse\doifelsenextchar
-
\def\syst_helpers_inspect_next_character
{\ifx\nexttoken\blankspace
\expandafter\syst_helpers_reinspect_next_character
@@ -309,14 +296,29 @@
\expandafter\m_syst_action_nop
\fi}
+\unexpanded\def\doifelsenextchar#1#2#3% #1 should not be {} !
+ {\let\charactertoken=#1% = needed here
+ \def\m_syst_action_yes{#2}%
+ \def\m_syst_action_nop{#3}%
+ \futurelet\nexttoken\syst_helpers_inspect_next_character}
+
+\unexpanded\def\doifelsenextcharcs#1#2#3% #1 should not be {} !
+ {\let\charactertoken=#1% = needed here
+ \let\m_syst_action_yes#2%
+ \let\m_syst_action_nop#3%
+ \futurelet\nexttoken\syst_helpers_inspect_next_character}
+
+\let\doifnextcharelse \doifelsenextchar
+\let\doifnextcharcselse\doifelsenextcharcs
+
%D Because we will mostly use this macro for testing if the next character is \type
%D {[}, we also make a slightly faster variant as it is not uncommon to have tens of
%D thousands of calls to this test in a run. Of course it also is more convenient to
%D read a trace then.
-% We could make variants without the \if_next_blank_space_token but the overhead is
-% only .1 sec on 3.5 for 10^6 tests and often that branch is not entered anyway. The
-% fast variants with less checking do make a difference however:
+%D We could make variants without the \if_next_blank_space_token but the overhead is
+%D only .1 sec on 3.5 for 10^6 tests and often that branch is not entered anyway. The
+%D fast variants with less checking do make a difference however:
% \testfeature{1000000}{\doifnextoptionalelse \gobbleoneargument\gobbleoneargument[} % 2.902s
% \testfeature{1000000}{\doifnextoptionalcselse \gobbleoneargument\gobbleoneargument[} % 2.590s
@@ -327,6 +329,20 @@
\let\syst_helpers_next_optional_character_token=[
+\def\syst_helpers_inspect_next_optional_character
+ {\ifx\nexttoken\blankspace
+ \expandafter\syst_helpers_reinspect_next_optional_character
+ \else
+ \expandafter\syst_helpers_inspect_next_optional_character_indeed
+ \fi}
+
+\def\syst_helpers_inspect_next_optional_character_indeed
+ {\ifx\nexttoken\syst_helpers_next_optional_character_token
+ \expandafter\m_syst_action_yes
+ \else
+ \expandafter\m_syst_action_nop
+ \fi}
+
\unexpanded\def\doifelsenextoptional#1#2%
{\def\m_syst_action_yes{#1}%
\def\m_syst_action_nop{#2}%
@@ -354,22 +370,22 @@
% \def\doifelsenextoptionalcs_n_n{\let\if_next_blank_space_token\iffalse
% \futurelet\nexttoken\syst_helpers_inspect_next_optional_character}
-\def\syst_helpers_inspect_next_optional_character
+\let\syst_helpers_next_bgroup_character_token\bgroup
+
+\def\syst_helpers_inspect_next_bgroup_character
{\ifx\nexttoken\blankspace
- \expandafter\syst_helpers_reinspect_next_optional_character
+ \expandafter\syst_helpers_reinspect_next_bgroup_character
\else
- \expandafter\syst_helpers_inspect_next_optional_character_indeed
+ \expandafter\syst_helpers_inspect_next_bgroup_character_indeed
\fi}
-\def\syst_helpers_inspect_next_optional_character_indeed
- {\ifx\nexttoken\syst_helpers_next_optional_character_token
+\def\syst_helpers_inspect_next_bgroup_character_indeed
+ {\ifx\nexttoken\syst_helpers_next_bgroup_character_token
\expandafter\m_syst_action_yes
\else
\expandafter\m_syst_action_nop
\fi}
-\let\syst_helpers_next_bgroup_character_token\bgroup
-
\unexpanded\def\doifelsenextbgroup#1#2%
{\def\m_syst_action_yes{#1}%
\def\m_syst_action_nop{#2}%
@@ -385,22 +401,22 @@
\let\doifnextbgroupelse \doifelsenextbgroup
\let\doifnextbgroupcselse\doifelsenextbgroupcs
-\def\syst_helpers_inspect_next_bgroup_character
+\let\syst_helpers_next_parenthesis_character_token(
+
+\def\syst_helpers_inspect_next_parenthesis_character
{\ifx\nexttoken\blankspace
- \expandafter\syst_helpers_reinspect_next_bgroup_character
+ \expandafter\syst_helpers_reinspect_next_parenthesis_character
\else
- \expandafter\syst_helpers_inspect_next_bgroup_character_indeed
+ \expandafter\syst_helpers_inspect_next_parenthesis_character_indeed
\fi}
-\def\syst_helpers_inspect_next_bgroup_character_indeed
- {\ifx\nexttoken\syst_helpers_next_bgroup_character_token
+\def\syst_helpers_inspect_next_parenthesis_character_indeed
+ {\ifx\nexttoken\syst_helpers_next_parenthesis_character_token
\expandafter\m_syst_action_yes
\else
\expandafter\m_syst_action_nop
\fi}
-\let\syst_helpers_next_parenthesis_character_token(
-
\unexpanded\def\doifelsenextparenthesis#1#2%
{\def\m_syst_action_yes{#1}%
\def\m_syst_action_nop{#2}%
@@ -409,22 +425,15 @@
\let\doifnextparenthesiselse\doifelsenextparenthesis
-\def\syst_helpers_inspect_next_parenthesis_character
- {\ifx\nexttoken\blankspace
- \expandafter\syst_helpers_reinspect_next_parenthesis_character
- \else
- \expandafter\syst_helpers_inspect_next_parenthesis_character_indeed
- \fi}
+%D The next one is handy in predictable situations:
-\def\syst_helpers_inspect_next_parenthesis_character_indeed
- {\ifx\nexttoken\syst_helpers_next_parenthesis_character_token
+\def\syst_helpers_do_if_fast_optional_check_else
+ {\ifx\nexttoken\syst_helpers_next_optional_character_token
\expandafter\m_syst_action_yes
\else
\expandafter\m_syst_action_nop
\fi}
-%D The next one is handy in predictable situations:
-
\unexpanded\def\doifelsefastoptionalcheck#1#2%
{\def\m_syst_action_yes{#1}%
\def\m_syst_action_nop{#2}%
@@ -438,13 +447,6 @@
\let\doiffastoptionalcheckelse \doifelsefastoptionalcheck
\let\doiffastoptionalcheckcselse\doifelsefastoptionalcheckcs
-\def\syst_helpers_do_if_fast_optional_check_else
- {\ifx\nexttoken\syst_helpers_next_optional_character_token
- \expandafter\m_syst_action_yes
- \else
- \expandafter\m_syst_action_nop
- \fi}
-
%D Here's one for skipping spaces and pars, handy for:
%D
%D \starttyping
@@ -474,7 +476,7 @@
% \def\syst_helpers_ignore_par_partoken
% {\afterassignment\m_syst_action\let\nexttoken}
-\unexpanded\def\assumelongusagecs#1% can be relaxed when we have long support in \hbox etc
+\unexpanded\def\assumelongusagecs#1%
{\let\m_syst_action#1%
\futurelet\nexttoken\syst_helpers_ignore_spacing}
@@ -500,26 +502,34 @@
%D \type {\def} comes into action. This way the space after \type {\:} becomes a
%D delimiter of the longer named \type {\reinspectnextcharacter}.
-\let\next\:
+% \ifcase\contextlmtxmode
+
+ \let\next\:
-\def\:{\let\blankspace= } \:
+ \def\:{\let\blankspace= } \:
-\def\:{\syst_helpers_reinspect_next_character}
-\expandafter\def\: {\let\if_next_blank_space_token\iftrue\futurelet\nexttoken\syst_helpers_inspect_next_character}
+ \def\:{\syst_helpers_reinspect_next_character}
+ \expandafter\def\: {\let\if_next_blank_space_token\iftrue\futurelet\nexttoken\syst_helpers_inspect_next_character}
-\def\:{\syst_helpers_reinspect_next_optional_character}
-\expandafter\def\: {\let\if_next_blank_space_token\iftrue\futurelet\nexttoken\syst_helpers_inspect_next_optional_character}
+ \def\:{\syst_helpers_reinspect_next_optional_character}
+ \expandafter\def\: {\let\if_next_blank_space_token\iftrue\futurelet\nexttoken\syst_helpers_inspect_next_optional_character}
-\def\:{\syst_helpers_reinspect_next_bgroup_character}
-\expandafter\def\: {\let\if_next_blank_space_token\iftrue\futurelet\nexttoken\syst_helpers_inspect_next_bgroup_character}
+ \def\:{\syst_helpers_reinspect_next_bgroup_character}
+ \expandafter\def\: {\let\if_next_blank_space_token\iftrue\futurelet\nexttoken\syst_helpers_inspect_next_bgroup_character}
-\def\:{\syst_helpers_reinspect_next_parenthesis_character}
-\expandafter\def\: {\let\if_next_blank_space_token\iftrue\futurelet\nexttoken\syst_helpers_inspect_next_parenthesis_character}
+ \def\:{\syst_helpers_reinspect_next_parenthesis_character}
+ \expandafter\def\: {\let\if_next_blank_space_token\iftrue\futurelet\nexttoken\syst_helpers_inspect_next_parenthesis_character}
-\def\:{\syst_helpers_ignore_spacing_blankspace}
-\expandafter\def\: {\futurelet\nexttoken\syst_helpers_ignore_spacing}
+ \def\:{\syst_helpers_ignore_spacing_blankspace}
+ \expandafter\def\: {\futurelet\nexttoken\syst_helpers_ignore_spacing}
-\let\:\next
+ \let\:\next
+
+% \else
+%
+% % nothing here
+%
+% \fi
%D This is much nicer and works too:
@@ -590,9 +600,9 @@
%D \macros
%D {globallet,glet}
%D
-%D In \CONTEXT\ of May 2000 using \type {\globallet} instead of the two
-%D tokens will save us some $300\times4=1200$ bytes of format file on a 32~bit
-%D system. Not that it matters much today. This shortcut is already defined:
+%D In \CONTEXT\ of May 2000 using \type {\globallet} instead of the two tokens will
+%D save us some $300\times4=1200$ bytes of format file on a 32~bit system. Not that
+%D it matters much today. This shortcut is already defined:
\let\globallet\glet
@@ -660,13 +670,13 @@
%D {\undefined}! In \ETEX\ we have \type {\ifcsname} and that way of testing on
%D existance is not the same as the one described here. Therefore we introduce:
-\def\letbeundefined#1% potential stack buildup when used \global
+\unexpanded\def\letbeundefined#1% potential stack buildup when used \global
{\expandafter\let\csname#1\endcsname\undefined} % or use \undefinevalue to match \setvalue
-\def\localundefine#1% conditional
+\unexpanded\def\localundefine#1% conditional
{\ifcsname#1\endcsname\expandafter\let\csname#1\endcsname\undefined\fi}
-\def\globalundefine#1% conditional
+\unexpanded\def\globalundefine#1% conditional
{\ifcsname#1\endcsname\expandafter\glet\csname#1\endcsname\undefined\fi}
%D Beware, being \type {\undefined} in \ETEX\ means that the macro {\em is} defined!
@@ -737,23 +747,6 @@
\expandafter\secondoftwoarguments
\fi}
-%D Slightly faster on longer arguments (0.179 downto 0.141):
-%D
-%D \testfeatureonce{100000}{\doifelse{aaaaaaaaaaaaaaa}{bbbbbbbbbbbbbbb}\relax\relax}
-
-% \unexpanded\def\doifelse
-% {\afterassignment\doifelse_n\edef\m_syst_string_one}
-%
-% \unexpanded\def\doifelse_n
-% {\afterassignment\doifelse_n_n\edef\m_syst_string_two}
-%
-% \unexpanded\def\doifelse_n_n
-% {\ifx\m_syst_string_one\m_syst_string_two
-% \expandafter\firstoftwoarguments
-% \else
-% \expandafter\secondoftwoarguments
-% \fi}
-
%D \macros
%D {doifempty,doifemptyelse,doifnotempty}
%D
@@ -1100,22 +1093,31 @@
\def\syst_helpers_do_do_do_process_comma_item
{\csname\??nextcommalevel\the\commalevel\endcsname}
-\def\syst_helpers_do_do_process_comma_item
- {\ifx\nexttoken\blankspace
- \expandafter\syst_helpers_re_do_process_comma_item
- \else
- \expandafter\syst_helpers_do_do_process_comma_item_indeed
- \fi}
+% \ifcase\contextlmtxmode
-\def\syst_helpers_do_do_process_comma_item_indeed
- {\ifx\nexttoken]%
- \expandafter\gobbleoneargument
- \else
- \expandafter\syst_helpers_do_do_do_process_comma_item
- \fi}
+ \def\syst_helpers_do_process_comma_item
+ {\futurelet\nexttoken\syst_helpers_do_do_process_comma_item}
+
+ \def\syst_helpers_do_do_process_comma_item
+ {\ifx\nexttoken\blankspace
+ \expandafter\syst_helpers_re_do_process_comma_item
+ \else
+ \expandafter\syst_helpers_do_do_process_comma_item_indeed
+ \fi}
+
+ \def\syst_helpers_do_do_process_comma_item_indeed
+ {\ifx\nexttoken]%
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\syst_helpers_do_do_do_process_comma_item
+ \fi}
-\def\syst_helpers_do_process_comma_item
- {\futurelet\nexttoken\syst_helpers_do_do_process_comma_item}
+% \else
+%
+% \def\syst_helpers_do_process_comma_item
+% {\futureexpandis]\gobbleoneargument\syst_helpers_do_do_do_process_comma_item}
+%
+% \fi
%D Empty arguments are not processed. Empty items (\type {,,}) however are
%D treated. We have to check for the special case \type {[{a,b,c}]}.
@@ -1164,13 +1166,17 @@
%D The hack we used for checking the next character \type {\doifnextcharelse}
%D is also used here.
-\let\next\:
+% \ifcase\contextlmtxmode
+
+ \let\next\:
-\def\:{\syst_helpers_re_do_process_comma_item} % \:not saved ?
+ \def\:{\syst_helpers_re_do_process_comma_item} % \:not saved ?
-\expandafter\def\: {\futurelet\nexttoken\syst_helpers_do_do_process_comma_item}
+ \expandafter\def\: {\futurelet\nexttoken\syst_helpers_do_do_process_comma_item}
-\let\:\next
+ \let\:\next
+
+% \fi
%D The previous examples lead to:
%D
@@ -1199,14 +1205,14 @@
%D \processcommacommand[\first,between,\second]\message
%D \stoptyping
%D
-%D Commands that are part of the list are expanded, so the use of
-%D this macro has its limits.
+%D Commands that are part of the list are expanded, so the use of this macro has its
+%D limits.
\unexpanded\def\processcommacommand[#1]%
{\normalexpanded{\processcommalist[#1]}}
-%D The argument to \type{\command} is not delimited. Because we often
-%D use \type{[]} as delimiters, we also have:
+%D The argument to \type{\command} is not delimited. Because we often use \type {[]}
+%D as delimiters, we also have:
%D
%D \starttyping
%D \processcommalistwithparameters[string,string,...]\command
@@ -1245,10 +1251,9 @@
%D processfirstactioninset,
%D processallactionsinset}
%D
-%D \CONTEXT\ makes extensive use of a sort of case or switch
-%D command. Depending of the presence of one or more provided
-%D items, some actions is taken. These macros can be nested
-%D without problems.
+%D \CONTEXT\ makes extensive use of a sort of case or switch command. Depending of
+%D the presence of one or more provided items, some actions is taken. These macros
+%D can be nested without problems.
%D
%D \starttyping
%D \processaction [x] [a=>\a,b=>\b,c=>\c]
@@ -1256,8 +1261,8 @@
%D \processallactionsinset [x,y,z] [a=>\a,b=>\b,c=>\c]
%D \stoptyping
%D
-%D We can supply both a \type{default} action and an action
-%D to be undertaken when an \type{unknown} value is met:
+%D We can supply both a \type {default} action and an action to be undertaken when
+%D an \type {unknown} value is met:
%D
%D \starttyping
%D \processallactionsinset
@@ -1269,16 +1274,14 @@
%D unknown=>\unknown{... \commalistelement ...}]
%D \stoptyping
%D
-%D When \type{#1} is empty, this macro scans list \type{#2} for
-%D the keyword \type{default} and executed the related action
-%D if present. When \type{#1} is non empty and not in the list,
-%D the action related to \type{unknown} is executed. Both
-%D keywords must be at the end of list \type{#2}. Afterwards,
-%D the actually found keyword is available in
-%D \type{\commalistelement}. An advanced example of the use of
-%D this macro can be found in \PPCHTEX, where we completely
-%D rely on \TEX\ for interpreting user supplied keywords like
-%D \type{SB}, \type{SB1..6}, \type{SB125} etc.
+%D When \type {#1} is empty, this macro scans list \type {#2} for the keyword \type
+%D {default} and executed the related action if present. When \type {#1} is non
+%D empty and not in the list, the action related to \type {unknown} is executed.
+%D Both keywords must be at the end of list \type{#2}. Afterwards, the actually
+%D found keyword is available in \type {\commalistelement}. An advanced example of
+%D the use of this macro can be found in \PPCHTEX, where we completely rely on \TEX\
+%D for interpreting user supplied keywords like \type {SB}, \type {SB1..6}, \type
+%D {SB125} etc.
\newcount\processlevel
@@ -1396,17 +1399,15 @@
%D \macros
%D {getfirstcharacter, firstcharacter, remainingcharacters, doiffirstcharacter}
%D
-%D Sometimes the action to be undertaken depends on the
-%D next character. This macro get this character and puts it in
-%D \type {\firstcharacter}.
+%D Sometimes the action to be undertaken depends on the next character. This macro
+%D get this character and puts it in \type {\firstcharacter}.
%D
%D \starttyping
%D \getfirstcharacter {string}
%D \stoptyping
%D
-%D A two step expansion is used to prevent problems with
-%D complicated arguments, for instance arguments that
-%D consist of two or more expandable tokens.
+%D A two step expansion is used to prevent problems with complicated arguments, for
+%D instance arguments that consist of two or more expandable tokens.
\let\firstcharacter \empty
\let\remainingcharacters\empty
@@ -1421,8 +1422,7 @@
%D \macros
%D {doifinstringelse, doifincsnameelse}
%D
-%D We can check for the presence of a substring in a given
-%D sequence of characters.
+%D We can check for the presence of a substring in a given sequence of characters.
%D
%D \starttyping
%D \doifinsetelse {substring} {string} {then ...} {else ...}
@@ -1481,26 +1481,24 @@
\unexpanded\def\syst_helpers_do_if_in_string_else#1#2% ##2 can be {abc}
{\expandafter\def\expandafter\syst_helpers_do_do_if_in_string_else
- \expandafter##\expandafter1#1##2##3\_e_o_s_{\unless\if##2@}% expand #1 here
- \expandafter\syst_helpers_do_do_if_in_string_else\normalexpanded{#2#1}@@\_e_o_s_} % expand #2 here
+ \expandafter##\expandafter1#1##2##3^^^^0004{\unless\if##2@}% expand #1 here
+ \expandafter\syst_helpers_do_do_if_in_string_else\normalexpanded{#2#1}@@^^^^0004} % expand #2 here
-%D The next alternative proved to be upto twice as fast on
-%D tasks like checking reserved words in pretty verbatim
-%D typesetting! This is mainly due to the fact that passing
-%D (expanded) strings is much slower that passing a macro.
+%D The next alternative proved to be upto twice as fast on tasks like checking
+%D reserved words in pretty verbatim typesetting! This is mainly due to the fact
+%D that passing (expanded) strings is much slower that passing a macro.
%D
%D \starttyping
%D \doifincsnameelse {substring} {\string} {then ...} {else ...}
%D \stoptyping
%D
-%D Where \type{\doifinstringelse} does as much expansion as
-%D possible, the latter alternative does minimal (one level)
-%D expansion.
+%D Where \type {\doifinstringelse} does as much expansion as possible, the latter
+%D alternative does minimal (one level) expansion.
\unexpanded\def\syst_helpers_do_if_in_csname_else#1#2%
- {\def\syst_helpers_do_do_if_in_csname_else##1#1##2##3\_e_o_s_
+ {\def\syst_helpers_do_do_if_in_csname_else##1#1##2##3^^^^0004%
{\unless\if##2@}%
- \expandafter\syst_helpers_do_do_if_in_csname_else#2#1@@\_e_o_s_}
+ \expandafter\syst_helpers_do_do_if_in_csname_else#2#1@@^^^^0004}
\unexpanded\def\doifelseincsname#1#2%
{\normalexpanded{\syst_helpers_do_if_in_csname_else{#1}}{#2}%
@@ -1514,17 +1512,16 @@
%D \macros
%D {doifnumberelse,doifnumber,doifnotnumber}
%D
-%D The next macro executes a command depending of the outcome of a test on
-%D numerals. This is probably one of the fastest test possible, exept from
-%D a less robust 10||step \type {\if}||ladder or some tricky \type {\lcode}
-%D checking.
+%D The next macro executes a command depending of the outcome of a test on numerals.
+%D This is probably one of the fastest test possible, exept from a less robust
+%D 10||step \type {\if}||ladder or some tricky \type {\lcode} checking.
%D
%D \starttyping
%D \doifnumberelse {string} {then ...} {else ...}
%D \stoptyping
%D
-%D The macro accepts \type {123}, \type {abc}, \type {{}}, \type {\getal} and
-%D \type {\the\count...}. This macro is a rather dirty one.
+%D The macro accepts \type {123}, \type {abc}, \type {{}}, \type {\getal} and \type
+%D {\the\count...}. This macro is a rather dirty one.
\def\doifelsenumber#1% does not accept counters (fully expandable)
{\ifcase0\ifcase1#1\or\or\or\or\or\or\or\or\or\else1\fi\space
@@ -1533,8 +1530,6 @@
\expandafter\firstoftwoarguments
\fi}
-\let\doifnumberelse\doifelsenumber
-
\def\doifnumber#1%
{\ifcase0\ifcase1#1\or\or\or\or\or\or\or\or\or\else1\fi\space
\expandafter\firstofoneargument
@@ -1549,6 +1544,8 @@
\expandafter\firstofoneargument
\fi}
+\let\doifnumberelse\doifelsenumber
+
%D \macros
%D {setpercentdimen}
%D
@@ -1570,14 +1567,12 @@
%D rawprocesscommalist,
%D rawprocessaction}
%D
-%D Some of the commands mentioned earlier are effective but
-%D slow. When one is desperately in need of faster alternatives
-%D and when the conditions are predictable safe, the \type{\raw}
-%D alternatives come into focus. A major drawback is that
-%D they do not take \type{\c!constants} into account, simply
-%D because no expansion is done. This is no problem with
-%D \type{\rawprocesscommalist}, because this macro does not
-%D compare anything. Expandable macros are permitted as search
+%D Some of the commands mentioned earlier are effective but slow. When one is
+%D desperately in need of faster alternatives and when the conditions are
+%D predictable safe, the \type {\raw} alternatives come into focus. A major drawback
+%D is that they do not take \type {\c!constants} into account, simply because no
+%D expansion is done. This is no problem with \type {\rawprocesscommalist}, because
+%D this macro does not compare anything. Expandable macros are permitted as search
%D string.
%D
%D \starttyping
@@ -1587,10 +1582,9 @@
%D \rawprocessaction[x][a=>\a,b=>\b,c=>\c]
%D \stoptyping
%D
-%D Spaces embedded in the list, for instance after commas,
-%D spoil the search process. The gain in speed depends on the
-%D length of the argument (the longer the argument, the less
-%D we gain).
+%D Spaces embedded in the list, for instance after commas, spoil the search process.
+%D The gain in speed depends on the length of the argument (the longer the argument,
+%D the less we gain).
\unexpanded\def\makerawcommalist[#1]#2% use \processnext ... here
{\def\syst_helpers_do_make_raw_comma_list##1% we don't expand ##1
@@ -1617,6 +1611,22 @@
\unexpanded\def\rawprocesscommacommand[#1]% not really needed
{\normalexpanded{\rawprocesscommalist[#1]}}
+%D Here is one without nesting:
+
+\unexpanded\def\syst_helpers_fast_process_comma_item#1,#2% #2 eats up preceding space
+ {\if]#1\else
+ \syst_helpers_fast_process_comma_command{#1}%
+ \expandafter\syst_helpers_fast_process_comma_item
+ \fi#2}
+
+\unexpanded\def\fastprocesscommalist[#1]#2% accepteert ook [\cs]
+ {\let\syst_helpers_fast_process_comma_command#2%
+ \expandafter\syst_helpers_fast_process_comma_item#1,],}% \relax
+
+\unexpanded\def\fastprocesscommacommand[#1]#2% accepteert ook [\cs]
+ {\let\syst_helpers_fast_process_comma_command#2%
+ \normalexpanded{\syst_helpers_fast_process_comma_item#1},],}% \relax
+
% \def\rawdoifelseinset#1#2{\doifinstringelse{,#1,}{,#2,}}
% \def\rawdoifinset #1#2{\doifinstring {,#1,}{,#2,}}
@@ -1657,11 +1667,11 @@
%D Some more raw material:
\def\syst_helpers_do_raw_process_action[#1][#2]%
- {\def\syst_helpers_do_do_raw_process_action##1,#1=>##2,##3\_e_o_s_
+ {\def\syst_helpers_do_do_raw_process_action##1,#1=>##2,##3^^^^0004%
{\if##3@\else
\def\m_syst_helpers_process_action{##2}%
\fi}%
- \syst_helpers_do_do_raw_process_action,#2,#1=>,@\_e_o_s_}
+ \syst_helpers_do_do_raw_process_action,#2,#1=>,@^^^^0004}
\unexpanded\def\rawprocessaction[#1]#2[#3]%
{\edef\m_syst_string_one{#1}%
@@ -1680,11 +1690,11 @@
\m_syst_helpers_process_action
\fi}
-%D When we process the list \type{a,b,c,d,e}, the raw routine takes over 30\% less
+%D When we process the list \type {a,b,c,d,e}, the raw routine takes over 30\% less
%D time, when we feed $20+$ character strings we gain about 20\%. Alternatives which
-%D use \type{\futurelet} perform worse. Part of the speedup is due to the
-%D \type{\let} and \type{\expandafter} in the test.
-
+%D use \type {\futurelet} perform worse. Part of the speedup is due to the \type
+%D {\let} and \type {\expandafter} in the test.
+%D
%D \macros
%D {dosetvalue,dosetevalue,dosetgvalue,docopyvalue,doresetvalue,
%D dogetvalue}
@@ -1753,14 +1763,8 @@
%D will redefine this macro later on, when a more advanced message mechanism is
%D implemented.
-\newif\iferrorisfatal
-
-\unexpanded\def\waitonfatalerror
- {\iferrorisfatal\wait\fi}
-
\unexpanded\def\showassignerror#1#2%
- {\writestatus{setup}{missing or ungrouped '=' after '#1' in line #2}%
- \waitonfatalerror}
+ {\writestatus{setup}{missing or ungrouped '=' after '#1' in line #2}}
\unexpanded\def\doassignempty[#1][#2=#3]%
{\ifcsname#1#2\endcsname\else\dosetvalue{#1}{#2}{#3}\fi}
@@ -1850,7 +1854,7 @@
\fi#4}
\def\syst_helpers_get_parameters#1]%
- {\xprocesscommaitem#1,],\_e_o_p_}
+ {\xprocesscommaitem#1,],^^^^0004}
\def\syst_helpers_process_comma_item#1,#2% #2 takes space before ,
{\if,#1,% dirty trick for testing #1=empty
@@ -1858,14 +1862,14 @@
\else\if]#1%
\doubleexpandafter\gobbleoneargument
\else
- \syst_helpers_get_parameters_assign\_e_o_p_#1==\empty\_e_o_p_
+ \syst_helpers_get_parameters_assign^^^^0004#1==\empty^^^^0004%
\doubleexpandafter\syst_helpers_process_comma_item
\fi\fi#2}
\def\syst_helpers_assign_error#1#2#3%
{\showassignerror{#2}{\the\inputlineno\space(#1)}}
-\def\syst_helpers_get_parameters_assign_normal#1\_e_o_p_#2=#3=#4#5\_e_o_p_
+\def\syst_helpers_get_parameters_assign_normal#1^^^^0004#2=#3=#4#5^^^^0004%
{\ifx\empty#2\empty
\expandafter\syst_helpers_assign_error
\else\ifx#4\empty
@@ -1875,7 +1879,7 @@
\fi\fi
{#1}{#2}{#3}}
-\def\syst_helpers_get_parameters_assign_error#1\_e_o_p_#2=#3=#4#5\_e_o_p_
+\def\syst_helpers_get_parameters_assign_error#1^^^^0004#2=#3=#4#5^^^^0004%
{\ifx\empty#2\empty
\expandafter\syst_helpers_assign_error
\else\ifx#4\empty
@@ -1892,9 +1896,9 @@
\let\syst_helpers_get_parameters_assign_indeed\syst_helpers_get_parameters_assign_normal
-\unexpanded\def\doassign [#1][#2]{\let\setsomevalue\dosetvalue \syst_helpers_get_parameters_assign_indeed#1\_e_o_p_#2==\empty\_e_o_p_}
-\unexpanded\def\doeassign [#1][#2]{\let\setsomevalue\dosetevalue \syst_helpers_get_parameters_assign_indeed#1\_e_o_p_#2==\empty\_e_o_p_}
-\unexpanded\def\undoassign[#1][#2]{\let\setsomevalue\doresetvalue\syst_helpers_get_parameters_assign_indeed#1\_e_o_p_#2==\empty\_e_o_p_}
+\unexpanded\def\doassign [#1][#2]{\let\setsomevalue\dosetvalue \syst_helpers_get_parameters_assign_indeed#1^^^^0004#2==\empty^^^^0004}
+\unexpanded\def\doeassign [#1][#2]{\let\setsomevalue\dosetevalue \syst_helpers_get_parameters_assign_indeed#1^^^^0004#2==\empty^^^^0004}
+\unexpanded\def\undoassign[#1][#2]{\let\setsomevalue\doresetvalue\syst_helpers_get_parameters_assign_indeed#1^^^^0004#2==\empty^^^^0004}
%D \macros
%D {processassignmentlist,processassignmentcommand,
@@ -1907,8 +1911,8 @@
%D \processassignmentlist[a=1,b=2]\showpair
%D \stoptyping
%D
-%D We can optimize this one if needed but it's not a core macro so hardly
-%D worth the trouble and tokens.
+%D We can optimize this one if needed but it's not a core macro so hardly worth the
+%D trouble and tokens.
\unexpanded\def\processassignmentlist[#1]#2% #2 == \command{key}{value]
{\def\syst_helpers_process_assignment_entry##1{#2}% {##2}{##3} % namespace is ignored
@@ -1960,14 +1964,14 @@
%D Here we hook in the code (beware, this is the optimized get **):
\def\syst_helpers_get_parameters_normal#1]%
- {\syst_helpers_process_comma_item#1,],\_e_o_p_}
+ {\syst_helpers_process_comma_item#1,],^^^^0004}
\def\syst_helpers_get_parameters_expanded#1]%
{\let\dosetnvalue\setsomevalue
\let\setsomevalue\dosetevalue
\let\syst_helpers_get_parameters_assign_indeed\syst_helpers_get_parameters_assign_error
\let\setsomevalue\dosetevalue
- \syst_helpers_process_comma_item#1,],\_e_o_p_
+ \syst_helpers_process_comma_item#1,],^^^^0004%
\let\syst_helpers_get_parameters_assign_indeed\syst_helpers_get_parameters_assign_normal
\let\setsomevalue\dosetnvalue
\let\syst_helpers_get_parameters\syst_helpers_get_parameters_normal
@@ -1981,8 +1985,8 @@
%D \macros
%D {getemptyparameters}
%D
-%D Sometimes we explicitly want variables to default to an
-%D empty string, so we welcome:
+%D Sometimes we explicitly want variables to default to an empty string, so we
+%D welcome:
%D
%D \starttyping
%D \getemptyparameters [label] [...=...,...=...]
@@ -1995,11 +1999,9 @@
%D \macros
%D {copyparameters}
%D
-%D Some \CONTEXT\ commands take their default setups from
-%D others. All commands that are able to provide backgounds
-%D or rules around some content, for instance default to the
-%D standard command for ruled boxes. Is situations like this
-%D we can use:
+%D Some \CONTEXT\ commands take their default setups from others. All commands that
+%D are able to provide backgounds or rules around some content, for instance default
+%D to the standard command for ruled boxes. Is situations like this we can use:
%D
%D \starttyping
%D \copyparameters [to-label] [from-label] [name1,name2,...]
@@ -2020,8 +2022,8 @@
%D \def\internalbeta {\externalbeta}
%D \stoptyping
%D
-%D By using \type{\docopyvalue} we've prepared this command
-%D for use in a multi||lingual environment.
+%D By using \type {\docopyvalue} we've prepared this command for use in a
+%D multi||lingual environment.
\unexpanded\def\copyparameters[#1]#2[#3]#4[#5]%
{\doifnot{#1}{#3}
@@ -2031,12 +2033,11 @@
%D \macros
%D {ifparameters,checkparameters}
%D
-%D A slightly different one is \type{\checkparameters}, which
-%D also checks on the presence of a~\type{=}.
+%D A slightly different one is \type {\checkparameters}, which also checks on the
+%D presence of a~\type {=}.
%D
-%D The boolean \type{\ifparameters} can be used afterwards.
-%D Combining both in one \type{\if}||macro would lead to
-%D problems with nested \type{\if}'s.
+%D The boolean \type {\ifparameters} can be used afterwards. Combining both in one
+%D \type {\if}||macro would lead to problems with nested \type {\if}'s.
%D
%D \starttyping
%D \checkparameters[argument]
@@ -2044,11 +2045,11 @@
\newif\ifparameters
-\def\syst_helpers_check_parameters#1=#2#3\_e_o_s_
- {\if#2@\parametersfalse\else\parameterstrue\fi}
+\def\syst_helpers_check_parameters#1=#2#3^^^^0004%
+ {\if#2^^^^0003\parametersfalse\else\parameterstrue\fi}
\unexpanded\def\checkparameters[#1]%
- {\syst_helpers_check_parameters#1=@@\_e_o_s_}
+ {\syst_helpers_check_parameters#1=^^^^0003^^^^0003^^^^0004}
%D \macros
%D {getfromcommalist,getfromcommacommand,
@@ -2112,9 +2113,8 @@
\unexpanded\def\getfromcommacommand[#1]%
{\normalexpanded{\getfromcommalist[#1]}}
-%D Watertight (and efficient) solutions are hard to find, due
-%D to the handling of braces during parameters passing and
-%D scanning. Nevertheless:
+%D Watertight (and efficient) solutions are hard to find, due to the handling of
+%D braces during parameters passing and scanning. Nevertheless:
%D
%D \startbuffer
%D \def\dosomething#1{(#1=\commalistsize) }
@@ -2138,8 +2138,8 @@
%D \macros
%D {dogetcommalistelement,dogetcommacommandelement}
%D
-%D For low level (fast) purposes, we can also use the next
-%D alternative, which can handle 8~elements at most.
+%D For low level (fast) purposes, we can also use the next alternative, which can
+%D handle 8~elements at most.
%D
%D \starttyping
%D \dogetcommalistelement1\from a,b,c\to\commalistelement
@@ -2156,9 +2156,8 @@
%D doquadrupleargument,doquintupleargument,dosixtupleargument,
%D doseventupleargument}
%D
-%D When working with delimited arguments, spaces and
-%D lineendings can interfere. The next set of macros uses
-%D \TEX' internal scanner for grabbing everything between
+%D When working with delimited arguments, spaces and lineendings can interfere. The
+%D next set of macros uses \TEX' internal scanner for grabbing everything between
%D arguments. Forgive me the funny names.
%D
%D \starttyping
@@ -2195,17 +2194,15 @@
%D \dodoquintupleargument}
%D \stoptyping
%D
-%D Because \TEX\ accepts 9~arguments at most, we have to use
-%D two||step solution when getting five or more arguments.
+%D Because \TEX\ accepts 9~arguments at most, we have to use two||step solution when
+%D getting five or more arguments.
%D
-%D When developing more and more of the real \CONTEXT, we
-%D started using some alternatives that provided empty
-%D arguments (in fact optional ones) whenever the user failed
-%D to supply them. Because this more complicated macros enable
-%D us to do some checking, we reimplemented the non||empty
-%D ones.
+%D When developing more and more of the real \CONTEXT, we started using some
+%D alternatives that provided empty arguments (in fact optional ones) whenever the
+%D user failed to supply them. Because this more complicated macros enable us to do
+%D some checking, we reimplemented the non||empty ones.
-% no longer a mesage:
+% no longer a message:
%
% \unexpanded\def\dosingleargument {\let\expectedarguments\plusone \dosingleempty }
% \unexpanded\def\dodoubleargument {\let\expectedarguments\plustwo \dodoubleempty }
@@ -2220,8 +2217,8 @@
%D iffourthargument,iffifthargument,ifsixthargument,
%D ifseventhargument}
%D
-%D We use some signals for telling the calling macros if all
-%D wanted arguments are indeed supplied by the user.
+%D We use some signals for telling the calling macros if all wanted arguments are
+%D indeed supplied by the user.
\newif\iffirstargument
\newif\ifsecondargument
@@ -2256,24 +2253,23 @@
%D \command[][]
%D \stoptyping
%D
-%D Depending of the generousity of the user. Afterwards one can
-%D use the \type{\if...argument} boolean. For novice: watch
-%D the stepwise doubling of \type{#}'s
-
-\setnewconstant\noexpectedarguments\zerocount
-\setnewconstant\expectedarguments \zerocount
-
-\unexpanded\def\showargumenterror#1#2%
- {\writestatus{system}{\number#1 argument(s) expected in line #2}}
-
-\unexpanded\def\syst_helpers_argument_error
- {\ifnum\expectedarguments>\noexpectedarguments
- \showargumenterror{\number\expectedarguments}{\number\inputlineno}%
- \fi
- \syst_helpers_argument_reset}
+%D Depending of the generousity of the user. Afterwards one can use the \type
+%D {\if...argument} boolean. For novice: watch the stepwise doubling of \type {#}'s.
-\unexpanded\def\syst_helpers_argument_reset
- {\let\expectedarguments\noexpectedarguments}
+% \setnewconstant\noexpectedarguments\zerocount
+% \setnewconstant\expectedarguments \zerocount
+%
+% \unexpanded\def\showargumenterror#1#2%
+% {\writestatus{system}{\number#1 argument(s) expected in line #2}}
+%
+% \unexpanded\def\syst_helpers_argument_error
+% {\ifnum\expectedarguments>\noexpectedarguments
+% \showargumenterror{\number\expectedarguments}{\number\inputlineno}%
+% \fi
+% \syst_helpers_argument_reset}
+%
+% \unexpanded\def\syst_helpers_argument_reset
+% {\let\expectedarguments\noexpectedarguments}
% \def\test[#1]{(#1)}
%
@@ -2372,7 +2368,7 @@
% #1[]}
\unexpanded\def\dosingleempty#1%
- {\syst_helpers_argument_reset
+ {%syst_helpers_argument_reset
\t_syst_aux{#1}%
\let\m_syst_action_yes\syst_helpers_single_empty_one_yes
\let\m_syst_action_nop\syst_helpers_single_empty_one_nop
@@ -2414,7 +2410,7 @@
% \def\syst_helpers_double_empty_one_normal#1#2{#1[{#2}][]}
\unexpanded\def\dodoubleempty#1%
- {\syst_helpers_argument_reset
+ {%syst_helpers_argument_reset
\t_syst_aux{#1}%
\let\m_syst_action_yes\syst_helpers_double_empty_one_yes
\let\m_syst_action_nop\syst_helpers_double_empty_one_nop
@@ -2491,7 +2487,7 @@
% \def\syst_helpers_triple_empty_three_normal#1#2#3{#1[{#2}][{#3}][]}
\unexpanded\def\dotripleempty#1%
- {\syst_helpers_argument_reset
+ {%syst_helpers_argument_reset
\t_syst_aux{#1}%
\let\m_syst_action_yes\syst_helpers_triple_empty_one_yes
\let\m_syst_action_nop\syst_helpers_triple_empty_one_nop
@@ -2605,7 +2601,7 @@
% \def\syst_helpers_quadruple_empty_four_normal #1#2#3#4{#1[{#2}][{#3}][{#4}][]}
\unexpanded\def\doquadrupleempty#1%
- {\syst_helpers_argument_reset
+ {%syst_helpers_argument_reset
\t_syst_aux{#1}%
\let\m_syst_action_yes\syst_helpers_quadruple_empty_one_yes
\let\m_syst_action_nop\syst_helpers_quadruple_empty_one_nop
@@ -2758,7 +2754,7 @@
% \def\syst_helpers_quintuple_empty_five_normal #1#2#3#4#5{#1[{#2}][{#3}][{#4}][{#5}][]}
\unexpanded\def\doquintupleempty#1%
- {\syst_helpers_argument_reset
+ {%syst_helpers_argument_reset
\t_syst_aux{#1}%
\let\m_syst_action_yes\syst_helpers_quintuple_empty_one_yes
\let\m_syst_action_nop\syst_helpers_quintuple_empty_one_nop
@@ -2952,7 +2948,7 @@
% \def\syst_helpers_sixtuple_empty_six_normal #1#2#3#4#5#6{#1[{#2}][{#3}][{#4}][{#5}][{#6}][]}
\unexpanded\def\dosixtupleempty#1%
- {\syst_helpers_argument_reset
+ {%syst_helpers_argument_reset
\t_syst_aux{#1}%
\let\m_syst_action_yes\syst_helpers_sixtuple_empty_one_yes
\let\m_syst_action_nop\syst_helpers_sixtuple_empty_one_nop
@@ -3189,7 +3185,7 @@
% \def\syst_helpers_seventuple_empty_seven_normal#1#2#3#4#5#6#7{#1[{#2}][{#3}][{#4}][{#5}][{#6}][{#7}][]}
\unexpanded\def\doseventupleempty#1%
- {\syst_helpers_argument_reset
+ {%syst_helpers_argument_reset
\t_syst_aux{#1}%
\let\m_syst_action_yes\syst_helpers_seventuple_empty_one_yes
\let\m_syst_action_nop\syst_helpers_seventuple_empty_one_nop
@@ -3330,8 +3326,7 @@
%D \macros
%D {strippedcsname}
%D
-%D The next macro can be very useful when using \type{\csname}
-%D like in:
+%D The next macro can be very useful when using \type{\csname} like in:
%D
%D \starttyping
%D \csname if\strippedcsname\something\endcsname
@@ -3347,9 +3342,9 @@
%D \macros
%D {complexorsimple,complexorsimpleempty}
%D
-%D Setups can be optional. A command expecting a setup is
-%D prefixed by \type{\complex}, a command without one gets the
-%D prefix \type{\simple}. Commands like this can be defined by:
+%D Setups can be optional. A command expecting a setup is prefixed by \type
+%D {\complex}, a command without one gets the prefix \type {\simple}. Commands like
+%D this can be defined by:
%D
%D \starttyping
%D \complexorsimple\command
@@ -3373,17 +3368,15 @@
%D \complexorsimpleempty {command}
%D \stoptyping
%D
-%D Depending on the presence of \type{[setup]}, this one
-%D leads to one of:
+%D Depending on the presence of \type{[setup]}, this one leads to one of:
%D
%D \starttyping
%D \complexcommando [setup]
%D \complexcommando []
%D \stoptyping
%D
-%D Many \CONTEXT\ commands started as complex or simple ones,
-%D but changed into more versatile (more object oriented) ones
-%D using the \type{\get..argument} commands.
+%D Many \CONTEXT\ commands started as complex or simple ones, but changed into more
+%D versatile (more object oriented) ones using the \type {\get..argument} commands.
\unexpanded\def\complexorsimple#1%
{% \relax % prevents lookahead, brrr
@@ -3400,9 +3393,8 @@
%D \macros
%D {definecomplexorsimple,definecomplexorsimpleempty}
%D
-%D The previous commands are used that often that we found it
-%D worthwile to offer two more alternatives. Watch the build
-%D in protection.
+%D The previous commands are used that often that we found it worthwile to offer two
+%D more alternatives. Watch the build in protection.
\unexpanded\def\syst_helpers_complex_or_simple#1#2%
{\doifelsenextoptional{\firstargumenttrue#1}{\firstargumentfalse#2}}
@@ -3449,9 +3441,8 @@
%D \doquadruplegroupempty \ineedFOURarguments
%D \doquintuplegroupempty \ineedFIVEarguments
%D \stoptyping
-
-%D We can add additional definitions later when we have defined
-%D \type {\appendtoks}.
+%D
+%D We can add additional definitions later when we have defined \type {\appendtoks}.
\newconditional\c_syst_helpers_permit_spaces_between_groups
@@ -3460,10 +3451,10 @@
\dontpermitspacesbetweengroups
-%D We can avoid the nasty if handling in \type {syst-gen} by splitting
-%D the lot in pieces so that we have no nested \type {\nextarguments}
-%D potentially being an \type {conditional} token. Okay, these macros
-%D are not called that often but it saves crap when tracing.
+%D We can avoid the nasty if handling in \type {syst-gen} by splitting the lot in
+%D pieces so that we have no nested \type {\nextarguments} potentially being an
+%D \type {conditional} token. Okay, these macros are not called that often but it
+%D saves crap when tracing.
\unexpanded\def\syst_helpers_get_grouped_argument#1#2%
{\let\syst_helpers_get_grouped_argument_yes#1%
@@ -3478,7 +3469,7 @@
\fi}
\def\syst_helpers_get_grouped_argument_a
- {\syst_helpers_argument_reset
+ {%syst_helpers_argument_reset
\syst_helpers_get_grouped_argument_yes\syst_helpers_get_grouped_argument_nested}
\def\syst_helpers_get_grouped_argument_b
@@ -3489,7 +3480,7 @@
\fi}
\def\syst_helpers_get_grouped_argument_d
- {\syst_helpers_argument_error
+ {%syst_helpers_argument_error
\syst_helpers_get_grouped_argument_nop\syst_helpers_get_grouped_argument_nested{}}
\begingroup
@@ -3504,13 +3495,13 @@
\expandafter\syst_helpers_get_grouped_argument_d % h
\fi}
-\def\dosinglegroupempty#1%
+\unexpanded\def\dosinglegroupempty#1%
{\def\syst_helpers_get_grouped_argument_nested
{\dontpermitspacesbetweengroups
#1}%
\syst_helpers_get_grouped_argument\firstargumenttrue\firstargumentfalse}
-\def\dodoublegroupempty#1%
+\unexpanded\def\dodoublegroupempty#1%
{\def\syst_helpers_get_grouped_argument_nested##1%
{\def\syst_helpers_get_grouped_argument_nested
{\dontpermitspacesbetweengroups
@@ -3518,7 +3509,7 @@
\syst_helpers_get_grouped_argument\secondargumenttrue\secondargumentfalse}%
\syst_helpers_get_grouped_argument\firstargumenttrue\firstargumentfalse}
-\def\dotriplegroupempty#1%
+\unexpanded\def\dotriplegroupempty#1%
{\def\syst_helpers_get_grouped_argument_nested##1%
{\def\syst_helpers_get_grouped_argument_nested####1%
{\def\syst_helpers_get_grouped_argument_nested
@@ -3528,7 +3519,7 @@
\syst_helpers_get_grouped_argument\secondargumenttrue\secondargumentfalse}%
\syst_helpers_get_grouped_argument\firstargumenttrue\firstargumentfalse}
-\def\doquadruplegroupempty#1%
+\unexpanded\def\doquadruplegroupempty#1%
{\def\syst_helpers_get_grouped_argument_nested##1%
{\def\syst_helpers_get_grouped_argument_nested####1%
{\def\syst_helpers_get_grouped_argument_nested########1%
@@ -3540,7 +3531,7 @@
\syst_helpers_get_grouped_argument\secondargumenttrue\secondargumentfalse}%
\syst_helpers_get_grouped_argument\firstargumenttrue\firstargumentfalse}
-\def\doquintuplegroupempty#1%
+\unexpanded\def\doquintuplegroupempty#1%
{\def\syst_helpers_get_grouped_argument_nested##1%
{\def\syst_helpers_get_grouped_argument_nested####1%
{\def\syst_helpers_get_grouped_argument_nested########1%
@@ -3554,8 +3545,8 @@
\syst_helpers_get_grouped_argument\secondargumenttrue\secondargumentfalse}%
\syst_helpers_get_grouped_argument\firstargumenttrue\firstargumentfalse}
-%D These macros can explictly take care of spaces, which means
-%D that the next definition and calls are valid:
+%D These macros can explictly take care of spaces, which means that the next
+%D definition and calls are valid:
%D
%D \starttyping
%D \def\test#1#2#3{[#1#2#3]}
@@ -3578,9 +3569,8 @@
%D secondoftwoarguments, secondofthreearguments,
%D thirdofthreearguments}
%D
-%D The next six macros (dedicated to Taco) can conveniently
-%D used to select arguments. Their names explain their
-%D functionality.
+%D The next six macros (dedicated to Taco) can conveniently used to select
+%D arguments. Their names explain their functionality.
\def\firstofoneargument #1{#1}
@@ -3641,9 +3631,8 @@
%D \macros
%D {wait}
%D
-%D The next macro hardly needs explanation. Because no
-%D nesting is to be expected, we can reuse \type{\wait} within
-%D \type{\wait} itself.
+%D The next macro hardly needs explanation. Because no nesting is to be expected, we
+%D can reuse \type {\wait} within \type {\wait} itself.
\unexpanded\def\wait
{\begingroup
@@ -3654,10 +3643,9 @@
%D {writestring,writeline,
%D writestatus,statuswidth,normalwritestatus}
%D
-%D Maybe one didn't notice, but we've already introduced a
-%D macro for showing messages. In the multi||lingual modules,
-%D we will also introduce a mechanism for message passing. For
-%D the moment we stick to the core macros:
+%D Maybe one didn't notice, but we've already introduced a macro for showing
+%D messages. In the multi||lingual modules, we will also introduce a mechanism for
+%D message passing. For the moment we stick to the core macros:
%D
%D \starttyping
%D \writestring {string}
@@ -3665,9 +3653,8 @@
%D \writestatus {category} {message}
%D \stoptyping
%D
-%D Messages are formatted. One can provide the maximum with
-%D of the identification string with the macro \type
-%D {\statuswidth}.
+%D Messages are formatted. One can provide the maximum with of the identification
+%D string with the macro \type {\statuswidth}.
\setnewconstant\statuswidth 15
\setnewconstant\statuswrite 128 % \pluscxxviii
@@ -3703,8 +3690,7 @@
%D \macros
%D {rawgetparameters}
%D
-%D A raw and dirty alternative for \type {\getparameters}; no
-%D checking is done!
+%D A raw and dirty alternative for \type {\getparameters}; no checking is done!
\unexpanded\def\rawsetparameter#1=#2,%
{\if]#1\else
@@ -3727,13 +3713,11 @@
%D {doglobal,
%D redoglobal,dodoglobal,resetglobal}
%D
-%D The two macros \type {\redoglobal} and \type{\dodoglobal} are
-%D used in this and some other modules to enforce a user
-%D specified \type {\doglobal} action. The last and often only
-%D global assignment in a macro is done with
-%D \type {\dodoglobal}, but all preceding ones with
-%D \type {\redoglobal}. When using only alternatives, one can
-%D reset this mechanism with \type {\resetglobal}.
+%D The two macros \type {\redoglobal} and \type{\dodoglobal} are used in this and
+%D some other modules to enforce a user specified \type {\doglobal} action. The last
+%D and often only global assignment in a macro is done with \type {\dodoglobal}, but
+%D all preceding ones with \type {\redoglobal}. When using only alternatives, one
+%D can reset this mechanism with \type {\resetglobal}.
\unexpanded\def\resetglobal
{\let\redoglobal\relax
@@ -3758,9 +3742,8 @@
{\let\redoglobal\syst_helpers_redo_global
\let\dodoglobal\syst_helpers_dodo_global}
-%D A very useful application of this macro is \type {\newif},
-%D \TEX's fake boolean type. Not being a primitive,
-%D \type {\global} hopelessly fails here. But a slight
+%D A very useful application of this macro is \type {\newif}, \TEX's fake boolean
+%D type. Not being a primitive, \type {\global} hopelessly fails here. But a slight
%D adaption of Knuth's original macro permits:
%D
%D \starttyping
@@ -3774,8 +3757,7 @@
%D \global\testfalse
%D \stoptyping
%D
-%D Apart from the prefixes, a few more \type{\expandafters}
-%D are needed:
+%D Apart from the prefixes, a few more \type {\expandafters} are needed:
% \unexpanded\def\newif#1% uses the original plain \@if
% {\privatescratchcounter\escapechar
@@ -3953,9 +3935,9 @@
%D {newcounter,
%D increment,decrement}
%D
-%D Unfortunately the number of \COUNTERS\ in \TEX\ is limited,
-%D but fortunately we can store numbers in a macro. We can
-%D increment such pseudo \COUNTERS\ with \type{\increment}.
+%D Unfortunately the number of \COUNTERS\ in \TEX\ is limited, but fortunately we
+%D can store numbers in a macro. We can increment such pseudo \COUNTERS\ with \type
+%D {\increment}.
%D
%D \starttyping
%D \increment(\counter,20)
@@ -3964,9 +3946,8 @@
%D \increment\counter
%D \stoptyping
%D
-%D After this sequence of commands, the value of
-%D \type{\counter} is 20, 16, 17 and~18. Of course there is
-%D also the complementary command \type{\decrement}.
+%D After this sequence of commands, the value of \type {\counter} is 20, 16, 17
+%D and~18. Of course there is also the complementary command \type {\decrement}.
%D
%D Global assignments are possible too, using \type{\doglobal}:
%D
@@ -3974,44 +3955,39 @@
%D \doglobal\increment\counter
%D \stoptyping
%D
-%D When \type{\counter} is undefined, it's value is initialized
-%D at~0. It is nevertheless better to define a \COUNTER\
-%D explicitly. One reason could be that the \COUNTER\ can be
-%D part of a test with \type{\ifnum} and this conditional does
-%D not accept undefined macro's. The \COUNTER\ in our example
-%D can for instance be defined with:
+%D When \type {\counter} is undefined, it's value is initialized at~0. It is
+%D nevertheless better to define a \COUNTER\ explicitly. One reason could be that
+%D the \COUNTER\ can be part of a test with \type {\ifnum} and this conditional does
+%D not accept undefined macro's. The \COUNTER\ in our example can for instance be
+%D defined with:
%D
%D \starttyping
%D \newcounter\counter
%D \stoptyping
%D
-%D The command \type{\newcounter} must not be confused with
-%D \type{\newcount}! Of course this mechanism is much slower
-%D than using \TEX's \COUNTERS\ directly. In practice
-%D \COUNTERS\ (and therefore our pseudo counters too) are
-%D seldom the bottleneck in the processing of a text. Apart
-%D from some other incompatilities we want to mention a pitfal
-%D when using \type{\ifnum}.
+%D The command \type {\newcounter} must not be confused with \type {\newcount}! Of
+%D course this mechanism is much slower than using \TEX's \COUNTERS\ directly. In
+%D practice \COUNTERS\ (and therefore our pseudo counters too) are seldom the
+%D bottleneck in the processing of a text. Apart from some other incompatilities we
+%D want to mention a pitfal when using \type {\ifnum}.
%D
%D \starttyping
%D \ifnum\normalcounter=\pseudocounter \doif \else \doelse \fi
%D \ifnum\pseudocounter=\normalcounter \doif \else \doelse \fi
%D \stoptyping
%D
-%D In the first test, \TEX\ continues it's search for the
-%D second number after reading \type{\pseudocounter}, while
-%D in the second test, it stops reading after having
-%D encountered a real one. Tests like the first one therefore
-%D can give unexpected results, for instance execution
-%D of \type{\doif} even if both numbers are unequal.
+%D In the first test, \TEX\ continues it's search for the second number after
+%D reading \type {\pseudocounter}, while in the second test, it stops reading after
+%D having encountered a real one. Tests like the first one therefore can give
+%D unexpected results, for instance execution of \type {\doif} even if both numbers
+%D are unequal.
\def\zerocountervalue{0}
\unexpanded\def\newcounter#1%
{\dodoglobal\let#1\zerocountervalue}
-%D Nowadays we don't mind a few more tokens if we can gain a
-%D bit of speed.
+%D Nowadays we don't mind a few more tokens if we can gain a bit of speed.
\def\syst_helpers_do_increment#1{\dodoglobal\edef#1{\the\numexpr\ifdefined#1\ifx#1\relax\else#1\fi\fi+\plusone \relax}}
\def\syst_helpers_do_decrement#1{\dodoglobal\edef#1{\the\numexpr\ifdefined#1\ifx#1\relax\else#1\fi\fi+\minusone\relax}}
@@ -4019,34 +3995,39 @@
\def\syst_helpers_do_do_do_increment#1,#2){\dodoglobal\edef#1{\the\numexpr\ifdefined#1\ifx#1\relax\else#1\fi\fi+#2\relax}}
\def\syst_helpers_do_do_do_decrement#1,#2){\dodoglobal\edef#1{\the\numexpr\ifdefined#1\ifx#1\relax\else#1\fi\fi-#2\relax}}
-\def\syst_helpers_do_do_increment(#1{\doifelsenextchar,{\syst_helpers_do_do_do_increment#1}{\syst_helpers_do_do_do_increment#1,\plusone}}
-\def\syst_helpers_do_do_decrement(#1{\doifelsenextchar,{\syst_helpers_do_do_do_decrement#1}{\syst_helpers_do_do_do_decrement#1,\plusone}}
+\def\syst_helpers_do_do_increment(#1%
+ {\def\m_syst_action_yes{\syst_helpers_do_do_do_increment#1}%
+ \def\m_syst_action_nop{\syst_helpers_do_do_do_increment#1,\plusone}%
+ \doifelsenextcharcs,\m_syst_action_yes\m_syst_action_nop}
+
+\def\syst_helpers_do_do_decrement(#1%
+ {\def\m_syst_action_yes{\syst_helpers_do_do_do_decrement#1}%
+ \def\m_syst_action_nop{\syst_helpers_do_do_do_decrement#1,\plusone}%
+ \doifelsenextcharcs,\m_syst_action_yes\m_syst_action_nop}
+
+\unexpanded\def\increment{\doifelsenextcharcs(\syst_helpers_do_do_increment\syst_helpers_do_increment}
+\unexpanded\def\decrement{\doifelsenextcharcs(\syst_helpers_do_do_decrement\syst_helpers_do_decrement}
\unexpanded\def\fastincrement#1{\dodoglobal\edef#1{\the\numexpr#1+\plusone \relax}}
\unexpanded\def\fastdecrement#1{\dodoglobal\edef#1{\the\numexpr#1+\minusone\relax}}
-\unexpanded\def\increment{\doifelsenextchar(\syst_helpers_do_do_increment\syst_helpers_do_increment}
-\unexpanded\def\decrement{\doifelsenextchar(\syst_helpers_do_do_decrement\syst_helpers_do_decrement}
-
\unexpanded\def\incrementvalue#1{\expandafter\increment\csname#1\endcsname}
\unexpanded\def\decrementvalue#1{\expandafter\decrement\csname#1\endcsname}
%D \macros
%D {newsignal}
%D
-%D When writing advanced macros, we cannot do without
-%D signaling. A signal is a small (invisible) kern or penalty
-%D that signals the next macro that something just happened.
-%D This macro can take any action depending on the previous
-%D signal. Signals must be unique and the next macro takes care
-%D of that.
+%D When writing advanced macros, we cannot do without signaling. A signal is a small
+%D (invisible) kern or penalty that signals the next macro that something just
+%D happened. This macro can take any action depending on the previous signal.
+%D Signals must be unique and the next macro takes care of that.
%D
%D \starttyping
%D \newsignal\somesignal
%D \stoptyping
%D
-%D Signals old dimensions and can be used in skips, kerns and
-%D tests like \type{\ifdim}.
+%D Signals old dimensions and can be used in skips, kerns and tests like \type
+%D {\ifdim}.
\newdimen\maximumsignal % step is about 0.00025pt
@@ -4059,8 +4040,7 @@
%D \macros
%D {strippedcsname}
%D
-%D The next macro can be very useful when using \type{\csname}
-%D like in:
+%D The next macro can be very useful when using \type {\csname} like in:
%D
%D \starttyping
%D \csname if\strippedcsname\something\endcsname
@@ -4089,21 +4069,18 @@
%D {dorecurse,recurselevel,recursedepth,
%D dostepwiserecurse}
%D
-%D \TEX\ does not offer us powerfull for||loop mechanisms. On
-%D the other hand its recursion engine is quite unique. We
-%D therefore identify the for||looping macros by this method.
-%D The most simple alternative is the one that only needs a
-%D number.
+%D \TEX\ does not offer us powerfull for||loop mechanisms. On the other hand its
+%D recursion engine is quite unique. We therefore identify the for||looping macros
+%D by this method. The most simple alternative is the one that only needs a number.
%D
%D \starttyping
%D \dorecurse {n} {whatever we want}
%D \stoptyping
%D
-%D This macro can be nested without problems and therefore be
-%D used in situations where \PLAIN\ \TEX's \type{\loop} macro
-%D ungracefully fails. The current value of the counter is
-%D available in \type{\recurselevel}, before as well as after
-%D the \typ{whatever we wat} stuff.
+%D This macro can be nested without problems and therefore be used in situations
+%D where \PLAIN\ \TEX's \type {\loop} macro ungracefully fails. The current value of
+%D the counter is available in \type {\recurselevel}, before as well as after the
+%D \typ {whatever we wat} stuff.
%D
%D \starttyping
%D \dorecurse % inner loop
@@ -4118,14 +4095,12 @@
%D \endgraf}
%D \stoptyping
%D
-%D In this example the first, second and fourth
-%D \type{\recurselevel} concern the outer loop, while the third
-%D and fifth one concern the inner loop. The depth of the
-%D nesting is available for inspection in \type{\recursedepth}.
+%D In this example the first, second and fourth \type {\recurselevel} concern the
+%D outer loop, while the third and fifth one concern the inner loop. The depth of
+%D the nesting is available for inspection in \type {\recursedepth}.
%D
-%D Both \type{\recurselevel} and \type{\recursedepth} are
-%D macros. The real \COUNTERS\ are hidden from the user because
-%D we don't want any interference.
+%D Both \type {\recurselevel} and \type {\recursedepth} are macros. The real
+%D \COUNTERS\ are hidden from the user because we don't want any interference.
\newcount\outerrecurse
\newcount\innerrecurse
@@ -4208,24 +4183,22 @@
#2\expandafter\doexpandedrecurse\expandafter{\the\numexpr#1-\plusone\relax}{#2}%
\fi}
-%D As we can see here, the simple command \type{\dorecurse} is
-%D a special case of the more general:
+%D As we can see here, the simple command \type{\dorecurse} is a special case of the
+%D more general:
%D
%D \starttyping
%D \dostepwiserecurse {from} {to} {step} {action}
%D \stoptyping
%D
-%D This commands accepts positive and negative steps. Illegal
-%D values are handles as good as possible and the macro accepts
-%D numbers and \COUNTERS.
+%D This commands accepts positive and negative steps. Illegal values are handles as
+%D good as possible and the macro accepts numbers and \COUNTERS.
%D
%D \starttyping
%D \dostepwiserecurse {1} {10} {2} {...}
%D \dostepwiserecurse {10} {1} {-2} {...}
%D \stoptyping
%D
-%D Because the simple case is used often, we implement it
-%D more efficiently:
+%D Because the simple case is used often, we implement it more efficiently:
\unexpanded\def\dorecurse#1%
{\ifcase#1\relax
@@ -4291,11 +4264,10 @@
%D \macros
%D {doloop,exitloop}
%D
-%D Sometimes loops are not determined by counters, but by
-%D (a combinations of) conditions. We therefore implement a
-%D straightforward loop, which can only be left when we
-%D explictly exit it. Nesting is supported. First we present
-%D a more extensive alternative.
+%D Sometimes loops are not determined by counters, but by (a combinations of)
+%D conditions. We therefore implement a straightforward loop, which can only be left
+%D when we explictly exit it. Nesting is supported. First we present a more
+%D extensive alternative.
%D
%D \starttyping
%D \doloop
@@ -4303,8 +4275,7 @@
%D \ifnum\pageno>100 \exitloop \fi}
%D \stoptyping
%D
-%D When needed, one can call for \type{\looplevel} and
-%D \type{\loopdepth}.
+%D When needed, one can call for \type {\looplevel} and \type {\loopdepth}.
\let\endofloop\donothing % maybe \syst_helpers_loop_end
@@ -4341,8 +4312,8 @@
%D \doloop {\exitloop some commands}
%D \stoptyping
%D
-%D It's just a matter of putting the text into the \type{\if}
-%D statement that should be there anyway, like in:
+%D It's just a matter of putting the text into the \type {\if} statement that should
+%D be there anyway, like in:
%D
%D \starttyping
%D \doloop {\ifwhatever \exitloop \else some commands\fi}
@@ -4352,10 +4323,9 @@
%D {\exitloopnow} instead. Beware, this is more sensitive
%D for conditional errors.
-%D Krzysztof Leszczynski suggested to provide access to the level by
-%D means of a \type {#1}. I decided to pass the more frequently used
-%D level as \type {#1} and the less favoured depth as \type {#2}. The
-%D intended usage is:
+%D Krzysztof Leszczynski suggested to provide access to the level by means of a
+%D \type {#1}. I decided to pass the more frequently used level as \type {#1} and
+%D the less favoured depth as \type {#2}. The intended usage is:
%D
%D \starttyping
%D \dorecurse{3}{\definesymbol[test-#1][xx-#1]}
@@ -4365,8 +4335,7 @@
%D \symbol[test-1]\quad\symbol[test-2]\quad\symbol[test-3]
%D \stoptyping
%D
-%D Since the hashed arguments are expanded, we don't need tricky
-%D expansion here.
+%D Since the hashed arguments are expanded, we don't need tricky expansion here.
%D
%D \starttyping
%D \dorecurse{3}{\expanded{\definesymbol[test-\recurselevel][xx-\recurselevel]}}
@@ -4494,19 +4463,26 @@
\let\m_syst_helpers_fast_loop_cs\relax
-\unexpanded\def\dofastloopcs#1#2%
- {\let\m_syst_helpers_fast_loop_cs#2%
+\unexpanded\def\dofastloopcs#1%
+ {\fastloopfinal#1\relax
+ \ifcase\fastloopfinal
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\syst_helpers_fast_loop_cs
+ \fi}
+
+\unexpanded\def\syst_helpers_fast_loop_cs#1%
+ {\let\m_syst_helpers_fast_loop_cs#1%
\fastloopindex\plusone
- \fastloopfinal#1\relax
- \syst_helpers_fast_loop_cs}
+ \syst_helpers_fast_loop_cs_step}
-\unexpanded\def\syst_helpers_fast_loop_cs
+\unexpanded\def\syst_helpers_fast_loop_cs_step
{\ifnum\fastloopindex>\fastloopfinal
\let\m_syst_helpers_fast_loop_cs\relax
\else
\m_syst_helpers_fast_loop_cs
\advance\fastloopindex\plusone
- \expandafter\syst_helpers_fast_loop_cs
+ \expandafter\syst_helpers_fast_loop_cs_step
\fi}
% Helper:
@@ -4621,52 +4597,46 @@
\unexpanded\def\forgeteverypar
{\everypar{\the\neverypar}}
-%D Which we're going to use indeed! When the second argument
-%D equals \type {\relax}, the first token list is created
-%D unless it is already defined.
-
-%D Technically spoken we could have used the method we are
-%D going to present in the visual debugger. First we save
-%D the primitive \type{\everypar}:
+%D Which we're going to use indeed! When the second argument equals \type {\relax},
+%D the first token list is created unless it is already defined.
+%D
+%D Technically spoken we could have used the method we are going to present in the
+%D visual debugger. First we save the primitive \type{\everypar}:
%D
%D \starttyping
%D \let\normaleverypar=\everypar
%D \stoptyping
%D
-%D Next we allocate a \TOKENLIST\ named \type{\everypar},
-%D which means that \type{\everypar} is no longer a primitive
-%D but something like \type{\toks44}.
+%D Next we allocate a \TOKENLIST\ named \type{\everypar}, which means that
+%D \type{\everypar} is no longer a primitive but something like \type{\toks44}.
%D
%D \starttyping
%D \newtoks\everypar
%D \stoptyping
%D
-%D Because \TEX\ now executes \type{\normaleverypar} instead
-%D of \type{\everypar}, we are ready to assign some tokens to
-%D this internally known and used \TOKENLIST.
+%D Because \TEX\ now executes \type{\normaleverypar} instead of \type{\everypar}, we
+%D are ready to assign some tokens to this internally known and used \TOKENLIST.
%D
%D \starttyping
%D \normaleverypar={all the things the system wants to do \the\everypar}
%D \stoptyping
%D
-%D Where the user can provide his own tokens to be expanded
-%D every time he expects them to expand.
+%D Where the user can provide his own tokens to be expanded every time he expects
+%D them to expand.
%D
%D \starttyping
%D \everypar={something the user wants to do}
%D \stoptyping
%D
-%D We don't use this method because it undoubtly leads to
-%D confusing situations, especially when other packages are
-%D used, but it's this kind of tricks that make \TEX\ so
-%D powerful.
+%D We don't use this method because it undoubtly leads to confusing situations,
+%D especially when other packages are used, but it's this kind of tricks that make
+%D \TEX\ so powerful.
%D \macros
%D {convertargument,convertcommand,convertvalue}
%D
-%D Some persistent experimenting led us to the next macro. This
-%D macro converts a parameter or an expanded macro to it's
-%D textual meaning.
+%D Some persistent experimenting led us to the next macro. This macro converts a
+%D parameter or an expanded macro to it's textual meaning.
%D
%D \starttyping
%D \convertargument ... \to \command
@@ -4678,9 +4648,9 @@
%D \convertargument{one \two \three{four}}\to\ascii
%D \stoptyping
%D
-%D The resulting macro \type{\ascii} can be written to a file
-%D or the terminal without problems. In \CONTEXT\ we use this
-%D macro for generating registers and tables of contents.
+%D The resulting macro \type{\ascii} can be written to a file or the terminal
+%D without problems. In \CONTEXT\ we use this macro for generating registers and
+%D tables of contents.
%D
%D The second conversion alternative accepts a command:
%D
@@ -4688,8 +4658,7 @@
%D \convertcommand\command\to\ascii
%D \stoptyping
%D
-%D Both commands accept the prefix \type{\doglobal} for global
-%D assignments.
+%D Both commands accept the prefix \type{\doglobal} for global assignments.
\unexpanded\def\convertvalue#1\to
{\expandafter\convertcommand\csname#1\endcsname\to}
@@ -4700,8 +4669,7 @@
%D \macros
%D {doifassignmentelse}
%D
-%D A lot of \CONTEXT\ commands take optional arguments, for
-%D instance:
+%D A lot of \CONTEXT\ commands take optional arguments, for instance:
%D
%D \starttyping
%D \dothisorthat[alfa,beta]
@@ -4709,25 +4677,25 @@
%D \dothisorthat[alfa,beta][first=foo,second=bar]
%D \stoptyping
%D
-%D Although a combined solution is possible, we prefer a
-%D seperation. The next command takes care of propper
-%D handling of such multi||faced commands.
+%D Although a combined solution is possible, we prefer a seperation. The next
+%D command takes care of propper handling of such multi||faced commands.
%D
%D \starttyping
%D \doifassignmentelse {...} {then ...} {else ...}
%D \stoptyping
-\def\syst_helpers_check_if_assignment_else#1=#2#3\_e_o_p_{\if#2@}%
+\def\syst_helpers_check_if_assignment_else#1=#2#3^^^^0004{\if#2^^^^0003}%
+\def\syst_helpers_check_else_assignment_if#1=#2#3^^^^0004{\unless\if#2^^^^0003}%
\unexpanded\def\doifelseassignment#1%
- {\expandafter\syst_helpers_check_if_assignment_else\detokenize{#1}=@@\_e_o_p_
+ {\expandafter\syst_helpers_check_if_assignment_else\detokenize{#1}=^^^^0003^^^^0003^^^^0004%
\expandafter\secondoftwoarguments
\else
\expandafter\firstoftwoarguments
\fi}
\unexpanded\def\doifelseassignmentcs#1#2#3%
- {\expandafter\syst_helpers_check_if_assignment_else\detokenize{#1}=@@\_e_o_p_
+ {\expandafter\syst_helpers_check_if_assignment_else\detokenize{#1}=^^^^0003^^^^0003^^^^0004%
\expandafter#3%
\else
\expandafter#2%
@@ -4739,18 +4707,24 @@
\newif\ifassignment
\unexpanded\def\docheckassignment#1%
- {\expandafter\syst_helpers_check_if_assignment_else\detokenize{#1}=@@\_e_o_p_
+ {\expandafter\syst_helpers_check_if_assignment_else\detokenize{#1}=^^^^0003^^^^0003^^^^0004%
\assignmentfalse
\else
\assignmenttrue
\fi}
-%D In \ETEX\ we can use \type {\detokenize} and gain some
-%D speed, but in general far less that 1\% for \type
-%D {\convertargument} and nil for \type {\convertcommand}.
-%D This macro is more robust than the pure \TEX\ one,
-%D something I found out when primitives like \type
-%D {\jobname} were fed (or something undefined).
+%D These can be used for cases where we want less tracing noise.
+
+\unexpanded\def\validassignment#1%
+ {\expandafter\syst_helpers_check_else_assignment_if\detokenize{#1}=^^^^0003^^^^0003^^^^0004}
+
+\unexpanded\def\novalidassignment#1%
+ {\expandafter\syst_helpers_check_if_assignment_else\detokenize{#1}=^^^^0003^^^^0003^^^^0004}
+
+%D In \ETEX\ we can use \type {\detokenize} and gain some speed, but in general far
+%D less that 1\% for \type {\convertargument} and nil for \type {\convertcommand}.
+%D This macro is more robust than the pure \TEX\ one, something I found out when
+%D primitives like \type {\jobname} were fed (or something undefined).
\unexpanded\def\convertargument#1\to#2{\dodoglobal\edef#2{\detokenize{#1}}}
\unexpanded\def\convertcommand #1\to#2{\dodoglobal\edef#2{\expandafter\detokenize\expandafter{#1}}} % hm, only second is also ok
@@ -4764,23 +4738,21 @@
\unexpanded\def\xdefconvertedargument#1#2{\xdef#1{#2}%
\xdef#1{\detokenize\expandafter{#1}}}
-%D When you try to convert a primitive command, you'll find
-%D out that the \ETEX\ method fails on for instance \type
-%D {\jobname} in the sense that it returns the filename
-%D instead of just \type {\jobname}. So far this does not
-%D give real problems.
+%D When you try to convert a primitive command, you'll find out that the \ETEX\
+%D method fails on for instance \type {\jobname} in the sense that it returns the
+%D filename instead of just \type {\jobname}. So far this does not give real
+%D problems.
-%D This is typically a macro that one comes to after reading
-%D the \TEX book carefully. Even then, the definite solution
-%D was found after rereading the \TEX book. The first
-%D implementation was:
+%D This is typically a macro that one comes to after reading the \TEX book
+%D carefully. Even then, the definite solution was found after rereading the \TEX
+%D book. The first implementation was:
%D
%D \starttyping
%D \def\doconvertargument#1->#2\\\\{#2}
%D \stoptyping
%D
-%D The \type{-}, the delimiter \type{\\\\} and the the second
-%D argument are completely redundant.
+%D The \type {-}, the delimiter \type {\\\\} and the the second argument are
+%D completely redundant.
%D \macros
%D {showvalue}
@@ -4797,10 +4769,9 @@
%D \macros
%D {doifmeaningelse}
%D
-%D We can use both commands in testing, but alas, not all
-%D meanings expand to something \type {->}. This is no problem
-%D in the \ETEX\ implementation, but since we want
-%D compatibility, we need:
+%D We can use both commands in testing, but alas, not all meanings expand to
+%D something \type {->}. This is no problem in the \ETEX\ implementation, but since
+%D we want compatibility, we need:
%D
%D \starttyping
%D \doifmeaningelse {\next} {\something} {true} {false}
@@ -4823,9 +4794,9 @@
%D \macros
%D {doifsamestringselse,doifsamestring,doifnotsamestring}
%D
-%D The next comparison macro converts the arguments into
-%D expanded strings. This command can be used to compare for
-%D instance \type {\jobname} with a name stored in a macro.
+%D The next comparison macro converts the arguments into expanded strings. This
+%D command can be used to compare for instance \type {\jobname} with a name stored
+%D in a macro.
%D
%D \starttyping
%D \doifelse {\jobname}{oeps}{YES}{NO}
@@ -4846,18 +4817,17 @@
%D \macros
%D {ConvertToConstant,ConvertConstantAfter}
%D
-%D When comparing arguments with a constant, we can get into
-%D trouble when this argument consists of tricky expandable
-%D commands. One solution for this is converting the
-%D argument to a string of unexpandable characters. To make
-%D comparison possible, we have to convert the constant too
+%D When comparing arguments with a constant, we can get into trouble when this
+%D argument consists of tricky expandable commands. One solution for this is
+%D converting the argument to a string of unexpandable characters. To make
+%D comparison possible, we have to convert the constant too.
%D
%D \starttyping
%D \ConvertToConstant\doifelse {...} {...} {then ...} {else ...}
%D \stoptyping
%D
-%D This construction is only needed when the first argument
-%D can give troubles. Misuse can slow down processing.
+%D This construction is only needed when the first argument can give troubles.
+%D Misuse can slow down processing.
%D
%D \starttyping
%D \ConvertToConstant\doifelse{\c!alfa} {\c!alfa}{...}{...}
@@ -4866,16 +4836,14 @@
%D \ConvertToConstant\doifelse{alfa \alfa test}{\c!alfa}{...}{...}
%D \stoptyping
%D
-%D In examples~2 and~3 both arguments equal, in~1 and~4
-%D they differ.
+%D In examples~2 and~3 both arguments equal, in~1 and~4 they differ.
\unexpanded\def\ConvertToConstant#1#2#3%
{\edef\m_syst_string_one{\expandafter\detokenize\expandafter{#2}}%
\edef\m_syst_string_two{\expandafter\detokenize\expandafter{#3}}%
#1{\m_syst_string_one}{\m_syst_string_two}}
-%D When the argument \type{#1} consists of commands, we had
-%D better use
+%D When the argument \type{#1} consists of commands, we had better use
%D
%D \starttyping
%D \ConvertConstantAfter\processaction[#1][...]
@@ -4890,8 +4858,7 @@
%D \hbox to \hsize{\rubish}
%D \stoptyping
%D
-%D As we will see in the core modules, this macro permits
-%D constructions like:
+%D As we will see in the core modules, this macro permits constructions like:
%D
%D \starttyping
%D \setupfootertexts[...][...]
@@ -4899,7 +4866,7 @@
%D \setupfootertexts[\v!margin][...][...]
%D \stoptyping
%D
-%D where \type{...} can be anything legally \TEX.
+%D where \type {...} can be anything legally \TEX.
\unexpanded\def\CheckConstantAfter#1#2%
{\expandafter\convertargument\v!prefix!\to\ascii
@@ -4931,33 +4898,28 @@
%D {gobbleuntil,grabuntil,gobbleuntilrelax,
%D processbetween,processuntil}
%D
-%D In \TEX\ gobbling usually stand for skipping arguments, so
-%D here are our gobbling macros.
-%D
-%D In \CONTEXT\ we use a lot of \type{\start}||\type{\stop}
-%D like constructions. Sometimes, the \type{\stop} is used as a
-%D hard coded delimiter like in:
+%D In \TEX\ gobbling usually stand for skipping arguments, so here are our gobbling
+%D macros.
%D
+%D In \CONTEXT\ we use a lot of \type {\start}||\type {\stop} like constructions.
+%D Sometimes, the \type {\stop} is used as a hard coded delimiter like in: %D
%D \starttyping
%D \unexpanded\def\startcommand#1\stopcommand%
%D {... #1 ...}
%D \stoptyping
%D
-%D In many cases the \type{\start}||\type{\stop} pair is
-%D defined at format generation time or during a job. This
-%D means that we cannot hardcode the \type{\stop} criterium.
-%D Only after completely understanding \type{\csname} and
-%D \type{\expandafter} I was able to to implement a solution,
-%D starting with:
+%D In many cases the \type {\start}||\type {\stop} pair is defined at format
+%D generation time or during a job. This means that we cannot hardcode the \type
+%D {\stop} criterium. Only after completely understanding \type {\csname} and \type
+%D {\expandafter} I was able to to implement a solution, starting with:
%D
%D \starttyping
%D \grabuntil{stop}\command
%D \stoptyping
%D
-%D This commands executes, after having encountered
-%D \type {\stop} the command \type {\command}. This command
-%D receives as argument the text preceding the \type {\stop}.
-%D This means that:
+%D This commands executes, after having encountered \type {\stop} the command \type
+%D {\command}. This command receives as argument the text preceding the \type
+%D {\stop}. This means that:
%D
%D \starttyping
%D \unexpanded\def\starthello%
@@ -5288,7 +5250,7 @@
\unexpanded\def\pickupgroupedcommand#1#2#3%
{\def\m_syst_helpers_handle_group_b{#1}%
\def\m_syst_helpers_handle_group_a{#2}%
- \def\m_syst_helpers_handle_group_p{#2}%
+ \def\m_syst_helpers_handle_group_p{#3}%
\doifelsenextbgroupcs\syst_helpers_handle_group_pickup\syst_helpers_handle_group_nop}
\unexpanded\def\triggergroupedcommand#1%
@@ -5312,19 +5274,17 @@
%D \macros
%D {checkdefined}
%D
-%D The bigger the system, the greater the change that
-%D user defined commands collide with those that are part of
-%D the system. The next macro gives a warning when a command is
-%D already defined. We considered blocking the definition, but
-%D this is not always what we want.
+%D The bigger the system, the greater the change that user defined commands collide
+%D with those that are part of the system. The next macro gives a warning when a
+%D command is already defined. We considered blocking the definition, but this is
+%D not always what we want.
%D
%D \starttyping
%D \checkdefined {category} {class} {command}
%D \stoptyping
%D
-%D The user is warned with the suggestion to use
-%D \type{CAPITALS}. This suggestion is feasible, because
-%D \CONTEXT only defines lowcased macros.
+%D The user is warned with the suggestion to use \type {CAPITALS}. This suggestion
+%D is feasible, because \CONTEXT only defines lowcased macros.
\unexpanded\def\showdefinederror#1#2%
{\writestatus\m!system{#1 #2 replaces a macro, use CAPITALS!}}
@@ -5335,10 +5295,9 @@
%D \macros
%D {GotoPar,GetPar}
%D
-%D Typesetting a paragraph in a special way can be done by
-%D first grabbing the contents of the paragraph and processing
-%D this contents grouped. The next macro for instance typesets
-%D a paragraph in boldface.
+%D Typesetting a paragraph in a special way can be done by first grabbing the
+%D contents of the paragraph and processing this contents grouped. The next macro
+%D for instance typesets a paragraph in boldface.
%D
%D \starttyping
%D \def\remark#1\par%
@@ -5351,13 +5310,12 @@
%D \remark some text ... ending with \par
%D \stoptyping
%D
-%D Instead of \type{\par} we can of course use an empty line.
-%D When we started typesetting with \TEX, we already had
-%D produced lots of text in plain \ASCII. In producing such
-%D simple formatted texts, we adopted an open layout, and when
-%D switching to \TEX, we continued this open habit. Although
-%D \TEX\ permits a cramped and badly formatted source, it adds
-%D to confusion and sometimes introduces errors. So we prefer:
+%D Instead of \type {\par} we can of course use an empty line. When we started
+%D typesetting with \TEX, we already had produced lots of text in plain \ASCII. In
+%D producing such simple formatted texts, we adopted an open layout, and when
+%D switching to \TEX, we continued this open habit. Although \TEX\ permits a cramped
+%D and badly formatted source, it adds to confusion and sometimes introduces errors.
+%D So we prefer:
%D
%D \starttyping
%D \remark
@@ -5365,9 +5323,8 @@
%D some text ... ending with an empty line
%D \stoptyping
%D
-%D We are going to implement a mechanism that allows such open
-%D specifications. The definition of the macro handling
-%D \type{\remark} becomes:
+%D We are going to implement a mechanism that allows such open specifications. The
+%D definition of the macro handling \type {\remark} becomes:
%D
%D \starttyping
%D \def\remark%
@@ -5376,15 +5333,13 @@
%D \GetPar}
%D \stoptyping
%D
-%D A macro like \type{\GetPar} can be defined in several
-%D ways. The recent version, the fourth one in a row,
-%D originally was far more complicated, but some functionality
-%D has been moved to other macros.
+%D A macro like \type {\GetPar} can be defined in several ways. The recent version,
+%D the fourth one in a row, originally was far more complicated, but some
+%D functionality has been moved to other macros.
%D
-%D We start with the more simple but in some cases more
-%D appropriate alternative is \type{\GotoPar}. This one leaves
-%D \type{\par} unchanged and is therefore more robust. On the
-%D other hand, \type{\AfterPar} is not supported.
+%D We start with the more simple but in some cases more appropriate alternative is
+%D \type {\GotoPar}. This one leaves \type {\par} unchanged and is therefore more
+%D robust. On the other hand, \type {\AfterPar} is not supported.
\newtoks\BeforePar
\newtoks\AfterPar
@@ -5425,12 +5380,10 @@
%D \macros
%D {dowithpargument,dowithwargument}
%D
-%D The next macros are a variation on \type{\GetPar}. When
-%D macros expect an argument, it interprets a grouped sequence
-%D of characters a one token. While this adds to robustness and
-%D less ambiguous situations, we sometimes want to be a bit
-%D more flexible, or at least want to be a bit more tolerant
-%D to user input.
+%D The next macros are a variation on \type {\GetPar}. When macros expect an
+%D argument, it interprets a grouped sequence of characters a one token. While this
+%D adds to robustness and less ambiguous situations, we sometimes want to be a bit
+%D more flexible, or at least want to be a bit more tolerant to user input.
%D
%D We start with a commands that acts on paragraphs. This
%D command is called as:
@@ -5440,11 +5393,10 @@
%D \dowithpargument{\command ... }
%D \stoptyping
%D
-%D In \CONTEXT\ we use this one to read in the titles of
-%D chapters, sections etc. The commands responsible for these
-%D activities accept several alternative ways of argument
-%D passing. In these examples, the \type{\par} can be omitted
-%D when an empty line is present.
+%D In \CONTEXT\ we use this one to read in the titles of chapters, sections etc. The
+%D commands responsible for these activities accept several alternative ways of
+%D argument passing. In these examples, the \type {\par} can be omitted when an
+%D empty line is present.
%D
%D \starttyping
%D \command{...}
@@ -5463,18 +5415,16 @@
\def\syst_helpers_next_arg##1{#1{##1}}%
\doifelsenextbgroup\syst_helpers_next_arg{\doifelsenextchar\par{#1{}}\syst_helpers_next_par}}
-%D The \type{p} in the previous command stands for paragraph.
-%D When we want to act upon words we can use the \type{w}
-%D alternative.
+%D The \type {p} in the previous command stands for paragraph. When we want to act
+%D upon words we can use the \type{w} alternative.
%D
%D \starttyping
%D \dowithwargument\command
%D \dowithwargument{... \command ...}
%D \stoptyping
%D
-%D The main difference bwteen two alternatives is in the
-%D handling of \type{\par}'s. This time the space token acts
-%D as a delimiter.
+%D The main difference bwteen two alternatives is in the handling of \type {\par}'s.
+%D This time the space token acts as a delimiter.
%D
%D \starttyping
%D \command{...}
@@ -5496,9 +5446,8 @@
%D \macros
%D {dorepeat,dorepeatwithcommand}
%D
-%D When doing repetitive tasks, we stromgly advice to use
-%D \type{\dorecurse}. The next alternative however, suits
-%D better some of the \CONTEXT\ interface commands.
+%D When doing repetitive tasks, we stromgly advice to use \type {\dorecurse}. The
+%D next alternative however, suits better some of the \CONTEXT\ interface commands.
%D
%D \starttyping
%D \dorepeat[n*\command]
@@ -5519,9 +5468,9 @@
%D \dorepeatwithcommand[3*{Hello}]\message
%D \stoptyping
%D
-%D we get ourselves three \type{\message{Hello}} messages in
-%D a row. In both commands, the \type{n*} is optional. When this
-%D specification is missing, the command executes once.
+%D we get ourselves three \type {\message{Hello}} messages in a row. In both
+%D commands, the \type {n*} is optional. When this specification is missing, the
+%D command executes once.
\unexpanded\def\dorepeatwithcommand[#1]%
{\syst_helpers_repeat_with_command#1*\empty*\relax}
@@ -5565,8 +5514,8 @@
%D \macros
%D {doifstringinstringelse}
%D
-%D The next macro is meant for situations where both strings
-%D are macros. This save some unneeded expansion.
+%D The next macro is meant for situations where both strings are macros. This save
+%D some unneeded expansion.
%D
%D \starttyping
%D \def\doifstringinstringelse#1#2%
@@ -5587,9 +5536,9 @@
\fi}
\def\doifelsestringinstring#1#2%
- {\expandafter\def\expandafter\syst_helpers_if_instring_else\expandafter##\expandafter1#1##2##3\_e_o_s_
+ {\expandafter\def\expandafter\syst_helpers_if_instring_else\expandafter##\expandafter1#1##2##3^^^^0004%
{\syst_helpers_if_instring_else_indeed##2}%
- \expandafter\expandafter\expandafter\syst_helpers_if_instring_else\expandafter#2#1@@\_e_o_s_}
+ \expandafter\expandafter\expandafter\syst_helpers_if_instring_else\expandafter#2#1@@^^^^0004}
\let\doifstringinstringelse\doifelsestringinstring
@@ -5597,9 +5546,8 @@
%D {appendtoks,prependtoks,appendtoksonce,prependtoksonce,
%D doifintokselse,flushtoks,dotoks}
%D
-%D We use \TOKENLISTS\ sparsely within \CONTEXT, because the
-%D comma separated lists are more suitable for the user
-%D interface. Nevertheless we have:
+%D We use tokenlists sparsely within \CONTEXT, because the comma separated lists are
+%D more suitable for the user interface. Nevertheless we have:
%D
%D \starttyping
%D (\doglobal) \appendtoks ... \to\tokenlist
@@ -5608,8 +5556,7 @@
%D \dotoks\tokenlist
%D \stoptyping
%D
-%D These macros are clones of the ones implemented in page~378 of
-%D Knuth's \TeX book.
+%D These macros are clones of the ones implemented in page~378 of Knuth's \TEX book.
\newtoks\t_syst_helpers_scratch
\let \m_syst_helpers_scratch\empty
@@ -5651,29 +5598,61 @@
% \donothing
% \syst_helpers_prepend_toks_indeed}
+% \unexpanded\def\appendtoks#1\to#2%
+% {\toksapp#2{#1}%
+% \ifx\dodoglobal\relax\else
+% \dodoglobal#2#2%
+% \fi}
+%
+% \unexpanded\def\prependtoks#1\to#2%
+% {\tokspre#2{#1}%
+% \ifx\dodoglobal\relax\else
+% \dodoglobal#2#2%
+% \fi}
+%
+% \def\syst_helpers_append_toks_indeed
+% {\toksapp\m_syst_helpers_scratch\t_syst_helpers_scratch
+% \ifx\dodoglobal\relax\else
+% \dodoglobal\m_syst_helpers_scratch\m_syst_helpers_scratch
+% \fi}
+%
+% \def\syst_helpers_prepend_toks_indeed
+% {\tokspre\m_syst_helpers_scratch\t_syst_helpers_scratch
+% \ifx\dodoglobal\relax\else
+% \dodoglobal\m_syst_helpers_scratch\m_syst_helpers_scratch
+% \fi}
+
\unexpanded\def\appendtoks#1\to#2%
- {\toksapp#2{#1}%
- \ifx\dodoglobal\relax\else
- \global#2#2%
- \fi}
+ {\ifx\dodoglobal\relax
+ \expandafter\toksapp
+ \else
+ \resetglobal
+ \expandafter\gtoksapp
+ \fi#2{#1}}
\unexpanded\def\prependtoks#1\to#2%
- {\tokspre#2{#1}%
- \ifx\dodoglobal\relax\else
- \global#2#2%
- \fi}
+ {\ifx\dodoglobal\relax
+ \expandafter\tokspre
+ \else
+ \resetglobal
+ \expandafter\gtokspre
+ \fi#2{#1}}
\def\syst_helpers_append_toks_indeed
- {\toksapp\m_syst_helpers_scratch\t_syst_helpers_scratch
- \ifx\dodoglobal\relax\else
- \global\m_syst_helpers_scratch\m_syst_helpers_scratch
- \fi}
+ {\ifx\dodoglobal\relax
+ \expandafter\toksapp
+ \else
+ \resetglobal
+ \expandafter\gtoksapp
+ \fi\m_syst_helpers_scratch\t_syst_helpers_scratch}
\def\syst_helpers_prepend_toks_indeed
- {\tokspre\m_syst_helpers_scratch\t_syst_helpers_scratch
- \ifx\dodoglobal\relax\else
- \global\m_syst_helpers_scratch\m_syst_helpers_scratch
- \fi}
+ {\ifx\dodoglobal\relax
+ \expandafter\tokspre
+ \else
+ \resetglobal
+ \expandafter\gtokspre
+ \fi\m_syst_helpers_scratch\t_syst_helpers_scratch}
\unexpanded\def\appendtoksonce#1\to#2%
{\let\m_syst_helpers_scratch#2%
@@ -5698,9 +5677,9 @@
\let\doifintokselse\doifelseintoks
-%D Moved from \type{lxml-ini.tex} to here. This one is for generators that
-%D collect stuff piecewise, which is sometimes hard on mechanisms that
-%D grab content using delimiters:
+%D Moved from \type {lxml-ini.tex} to here. This one is for generators that collect
+%D stuff piecewise, which is sometimes hard on mechanisms that grab content using
+%D delimiters:
%D
%D \starttyping
%D \startcollecting
@@ -5737,27 +5716,43 @@
% {\scratchtoks{a\relax b} \removetoks \relax\from\scratchtoks [\showthe\scratchtoks]}
\unexpanded\def\removetoks#1\from#2%
- {\def\syst_helpers_remove_toks##1#1##2\empty\empty\empty##3\_e_o_t_
+ {\def\syst_helpers_remove_toks##1#1##2\empty\empty\empty##3^^^^0004%
{\def\m_syst_string_one{##3}%
\ifx\m_syst_string_one\empty#2{##1}\else#2{##1##2}\fi}%
- \expandafter\syst_helpers_remove_toks\the#2\empty\empty\empty#1\empty\empty\empty\_e_o_t_}
+ \expandafter\syst_helpers_remove_toks\the#2\empty\empty\empty#1\empty\empty\empty^^^^0004}
%D Also:
% \unexpanded\def\appendetoks #1\to{\normalexpanded{\appendtoks #1}\to}
% \unexpanded\def\prependetoks#1\to{\normalexpanded{\prependtoks#1}\to}
+% \unexpanded\def\appendetoks#1\to#2%
+% {\etoksapp#2{#1}%
+% \ifx\dodoglobal\relax\else
+% \global#2#2%
+% \fi}
+%
+% \unexpanded\def\prependetoks#1\to#2%
+% {\etokspre#2{#1}%
+% \ifx\dodoglobal\relax\else
+% \global#2#2%
+% \fi}
+
\unexpanded\def\appendetoks#1\to#2%
- {\etoksapp#2{#1}%
- \ifx\dodoglobal\relax\else
- \global#2#2%
- \fi}
+ {\ifx\dodoglobal\relax
+ \expandafter\etoksapp
+ \else
+ \resetglobal
+ \expandafter\xtoksapp
+ \fi#2{#1}}
\unexpanded\def\prependetoks#1\to#2%
- {\etokspre#2{#1}%
- \ifx\dodoglobal\relax\else
- \global#2#2%
- \fi}
+ {\ifx\dodoglobal\relax
+ \expandafter\etokspre
+ \else
+ \resetglobal
+ \expandafter\xtokspre
+ \fi#2{#1}}
%D Hm.
@@ -5781,11 +5776,10 @@
%D \aftersplitstring test.tex\at.\to\extension
%D \stoptyping
%D
-%D The first routine looks (and is indeed) a bit simpler than
-%D the second one. The alternative looking more or less like
-%D the first one did not always give the results we needed.
-%D Both implementations show some insight in the manipulation
-%D of arguments.
+%D The first routine looks (and is indeed) a bit simpler than the second one. The
+%D alternative looking more or less like the first one did not always give the
+%D results we needed. Both implementations show some insight in the manipulation of
+%D arguments.
\let\syst_helpers_split_string\relax
@@ -5890,10 +5884,9 @@
%D {appendtocommalist,prependtocommalist,
%D addtocommalist,removefromcommalist}
%D
-%D When working with comma separated lists, one sooner or
-%D later want the tools to append or remove items from such a
-%D list. When we add an item, we first check if it's already
-%D there. This means that every item in the list is unique.
+%D When working with comma separated lists, one sooner or later want the tools to
+%D append or remove items from such a list. When we add an item, we first check if
+%D it's already there. This means that every item in the list is unique.
%D
%D \starttyping
%D \addtocommalist {alfa} \name
@@ -5902,22 +5895,18 @@
%D \removefromcommalist {beta} \name
%D \stoptyping
%D
-%D These commands can be prefixed with \type{\doglobal}. The
-%D implementation of the second command is more complecated,
-%D because we have to take leading spaces into account. Keep in
-%D mind that users may provide lists with spaces after the
-%D commas. When one item is left, we also have to get rid of
-%D trailing spaces.
+%D These commands can be prefixed with \type {\doglobal}. The implementation of the
+%D second command is more complecated, because we have to take leading spaces into
+%D account. Keep in mind that users may provide lists with spaces after the commas.
+%D When one item is left, we also have to get rid of trailing spaces.
%D
%D \starttyping
%D \def\words{alfa, beta, gamma, delta}
%D \def\words{alfa,beta,gamma,delta}
%D \stoptyping
%D
-%D Removing an item takes more time than adding one.
-%D
-%D A fast appending alternative, without any testing, is
-%D also provided:
+%D Removing an item takes more time than adding one. A fast appending alternative,
+%D without any testing, is also provided:
%D
%D \starttyping
%D \appendtocommalist {something} \name
@@ -6003,8 +5992,7 @@
%D \macros
%D {substituteincommalist}
%D
-%D Slow but seldom used, so for the moment we stick to this
-%D implementation.
+%D Slow but seldom used, so for the moment we stick to this implementation.
%D
%D \starttyping
%D \substituteincommalist{old}{new}{list}
@@ -6094,10 +6082,9 @@
%D \macros
%D {globalprocesscommalist}
%D
-%D The commalist processing commands are characterized by the
-%D fact that the way they handle expansion as well as the fact
-%D that they can be nested. This makes them kind of useless for
-%D handling comma lists in alignments. In these situations the
+%D The commalist processing commands are characterized by the fact that the way they
+%D handle expansion as well as the fact that they can be nested. This makes them
+%D kind of useless for handling comma lists in alignments. In these situations the
%D next macro can be of use.
\let\m_syst_helpers_comma_list_command_global\empty
@@ -6130,13 +6117,11 @@
\def\withoutpt#1%
{\expandafter\WITHOUTPT#1}
-%D The capitals are needed because \type{p} and \type{t} have
-%D \CATCODE~12, while macronames only permit tokens with the
-%D \CATCODE~11. As a result we cannot use the \type{.group}
-%D primitives. Those who want to know more about this kind of
-%D manipulations, we advice to study the \TEX book in detail.
-%D Because this macro does not do any assignment, we can use it
-%D in the following way too.
+%D The capitals are needed because \type {p} and \type {t} have catcode~12, while
+%D macronames only permit tokens with the catcode~11. As a result we cannot use the
+%D \type {.group} primitives. Those who want to know more about this kind of
+%D manipulations, we advice to study the \TEX book in detail. Because this macro
+%D does not do any assignment, we can use it in the following way too.
\def\PtToCm#1%
{\withoutpt\the\dimexpr0.0351459804\dimexpr#1\relax\relax cm}
@@ -6160,8 +6145,8 @@
%D {swapdimens,swapcounts,swapmacros,
%D globalswapdimens,globalswapcounts,globalswapmacros}
%D
-%D Simple but effective are the next two macros. There name
-%D exactly states their purpose.
+%D Simple but effective are the next two macros. There name exactly states their
+%D purpose.
\newdimen\d_syst_helpers_swapped
\newcount\c_syst_helpers_swapped
@@ -6273,10 +6258,9 @@
%D \macros
%D {setlocalhsize,distributedhsize}
%D
-%D Sometimes we need to work with the \type{\hsize} that is
-%D corrected for indentation and left and right skips. The
-%D corrected value is available in \type{\localhsize}, which
-%D needs to be calculated with \type{\setlocalhsize} first.
+%D Sometimes we need to work with the \type{ \hsize} that is corrected for
+%D indentation and left and right skips. The corrected value is available in \type
+%D {\localhsize}, which needs to be calculated with \type {\setlocalhsize} first. %D
%D
%D \starttyping
%D \setlocalhsize \hbox to \localhsize{...}
@@ -6284,8 +6268,8 @@
%D \setlocalhsize[.5ex] \hbox to \localhsize{...}
%D \stoptyping
%D
-%D These examples show us that an optional can be used. The
-%D value provided is added to \type{\localhsize}.
+%D These examples show us that an optional can be used. The value provided is added
+%D to \type {\localhsize}.
\newdimen\localhsize
@@ -6320,11 +6304,10 @@
%D doifnothing,doifsomething,doifelsenothing,
%D doifvaluenothing,doifvaluesomething,doifelsevaluenothing}
%D
-%D These long named \type{\if} commands can be used to access
-%D macros (or variables) that are normally accessed by using
-%D \type{\getvalue}. Using these alternatives safes us three
-%D tokens per call. Anyone familiar with the not||values
-%D ones, can derive their meaning from the definitions.
+%D These \type {\if} commands can be used to access macros (or variables) that are
+%D normally accessed by using \type {\getvalue}. Using these alternatives safes us
+%D three tokens per call. Anyone familiar with the not||values ones, can derive
+%D their meaning from the definitions.
\unexpanded\def\doifvalue#1#2%
{\edef\m_syst_string_one{\csname#1\endcsname}%
@@ -6445,9 +6428,8 @@
%D \macros
%D {doifallcommonelse}
%D
-%D A complete match of two sets can be tested with
-%D \type {\doifallcommonelse}, where the first two
-%D arguments are sets.
+%D A complete match of two sets can be tested with \type {\doifallcommonelse}, where
+%D the first two arguments are sets.
\def\syst_helpers_do_if_all_common_else#1#2#3#4% slow
{\def\syst_helpers_do_common_check_all##1%
@@ -6466,10 +6448,9 @@
%D \macros
%D {DOIF,DOIFELSE,DOIFNOT}
%D
-%D \TEX\ is case sensitive. When comparing arguments, this
-%D feature sometimes is less desirable, for instance when we
-%D compare filenames. The next three alternatives upcase their
-%D arguments before comparing them.
+%D \TEX\ is case sensitive. When comparing arguments, this feature sometimes is less
+%D desirable, for instance when we compare filenames. The next three alternatives
+%D upcase their arguments before comparing them.
%D
%D \starttyping
%D \DOIF {string1} {string2} {...}
@@ -6521,8 +6502,7 @@
%D dodoubleargumentwithset,dodoubleemptywithset,
%D dotripleargumentwithset,dotripleemptywithset}
%D
-%D These maybe too mysterious macros enable us to handle more
-%D than one setup at once.
+%D These maybe too mysterious macros enable us to handle more than one setup at once.
%D
%D \starttyping
%D \dosingleargumentwithset \command[#1]
@@ -6532,10 +6512,9 @@
%D \dotripleemptywithset \command[#1][#2][#3]
%D \stoptyping
%D
-%D The first macro calls \type{\command[##1]} for each string
-%D in the set~\type{#1}. The second one calls for
-%D \type{\commando[##1][#2]} and the third, well one may guess.
-%D These commands support constructions like:
+%D The first macro calls \type {\command[##1]} for each string in the set~\type
+%D {#1}. The second one calls for \typ {\command [##1][#2]} and the third, well one
+%D may guess. These commands support constructions like:
%D
%D \starttyping
%D \def\dodefinesomething[#1][#2]%
@@ -6555,12 +6534,12 @@
\let\syst_helpers_with_set_step \relax
\def\syst_helpers_with_set_double[#1][#2]%
- {\doifsomething{#1}
+ {\doifsomething{#1}%
{\def\syst_helpers_with_set_step##1{\m_syst_helpers_with_set_command[##1][#2]}%
\processcommalist[#1]\syst_helpers_with_set_step}}
\def\syst_helpers_with_set_triple[#1][#2][#3]%
- {\doifsomething{#1}
+ {\doifsomething{#1}%
{\def\syst_helpers_with_set_step##1{\m_syst_helpers_with_set_command[##1][#2][#3]}%
\processcommalist[#1]\syst_helpers_with_set_step}}
@@ -6573,13 +6552,11 @@
%D \macros
%D {stripcharacters,stripspaces}
%D
-%D The next command was needed first when we implemented
-%D the \CONTEXT\ interactivity macros. When we use labeled
-%D destinations, we often cannot use all the characters we
-%D want. We therefore strip some of the troublemakers, like
-%D spaces, from the labels before we write them to the
-%D \DVI||file, which passes them to for instance a PostScript
-%D file.
+%D The next command was needed first when we implemented the \CONTEXT\ interactivity
+%D macros. When we use labeled destinations, we often cannot use all the characters
+%D we want. We therefore strip some of the troublemakers, like spaces, from the
+%D labels before we write them to the \DVI||file, which passes them to for instance
+%D a \POSTSCRIPT\ file.
%D
%D \starttyping
%D \stripspaces\from\one\to\two
@@ -6592,8 +6569,8 @@
%D \stripcharacter\char\from\one\to\two
%D \stoptyping
%D
-%D As we can see below, spaces following a control sequence are
-%D to enclosed in \type{{}}.
+%D As we can see below, spaces following a control sequence are to enclosed in \type
+%D {{}}.
\let\m_syst_helpers_strip_character\empty
@@ -6612,8 +6589,8 @@
%D \macros
%D {unspacestring}
%D
-%D The next macro does the same but is more compatible with other macros,
-%D like \type {\convert...}.
+%D The next macro does the same but is more compatible with other macros, like \type
+%D {\convert...}.
\unexpanded\def\unspacestring#1\to#2%
{\stripcharacter{ }\from#1\to#2}
@@ -6621,22 +6598,19 @@
%D \macros
%D {executeifdefined}
%D
-%D \CONTEXT\ uses one auxiliary file for all data concerning
-%D tables of contents, references, two||pass optimizations,
-%D sorted lists etc. This file is loaded as many times as
-%D needed. During such a pass we skip the commands thate are of
-%D no use at that moment. Because we don't want to come into
-%D trouble with undefined auxiliary commands, we call the
-%D macros in a way similar to \type{\getvalue}. The next macro
-%D take care of such executions and when not defined, gobbles
-%D the unwanted arguments.
+%D \CONTEXT\ uses one auxiliary file for all data concerning tables of contents,
+%D references, two||pass optimizations, sorted lists etc. This file is loaded as
+%D many times as needed. During such a pass we skip the commands thate are of no use
+%D at that moment. Because we don't want to come into trouble with undefined
+%D auxiliary commands, we call the macros in a way similar to \type {\getvalue}. The
+%D next macro take care of such executions and when not defined, gobbles the
+%D unwanted arguments.
%D
%D \starttyping
%D \executeifdefined{name}\gobbleoneargument
%D \stoptyping
%D
-%D We can of course gobble more arguments using the
-%D appropriate gobbling command.
+%D We can of course gobble more arguments using the appropriate gobbling command.
\def\executeifdefined#1% #2 / never change this one again
{\ifcsname#1\endcsname
@@ -6646,29 +6620,28 @@
\expandafter\firstofoneargument
\fi}
-%D This one also has the advantage that it is fully
-%D expandable and that it can be used after an assignment.
+%D This one also has the advantage that it is fully expandable and that it can be
+%D used after an assignment.
%D \macros
%D {doifsomespaceelse}
%D
-%D The next command checks a string on the presence of a space
-%D and executed a command accordingly.
+%D The next command checks a string on the presence of a space and executed a
+%D command accordingly.
%D
%D \starttyping
%D \doifsomespaceelse {tekst} {then ...} {else ...}
%D \stoptyping
%D
-%D We use this command in \CONTEXT\ for determing if an
-%D argument must be broken into words when made interactive.
-%D Watch the use of \type{\noexpand}.
+%D We use this command in \CONTEXT\ for determing if an argument must be broken into
+%D words when made interactive. Watch the use of \type {\noexpand}.
%D Is this one still needed?
-\def\syst_helpers_if_some_space_else#1 #2#3\_e_o_s_{\if\noexpand#2@}
+\def\syst_helpers_if_some_space_else#1 #2#3^^^^0004{\if\noexpand#2@}
\def\doifelsesomespace#1% % #2#3%
- {\syst_helpers_if_some_space_else#1 @ @\_e_o_s_ % #3\else#2\fi}
+ {\syst_helpers_if_some_space_else#1 @ @^^^^0004% #3\else#2\fi}
\expandafter\secondoftwoarguments
\else
\expandafter\firstoftwoarguments
@@ -6679,9 +6652,9 @@
%D \macros
%D {processseparatedlist}
%D
-%D Maybe a bit late, but here is a more general version of the
-%D \type{\processcommalist} command. This time we don't handle
-%D nesting but accept arbitrary seperators.
+%D Maybe a bit late, but here is a more general version of the \type
+%D {\processcommalist} command. This time we don't handle nesting but accept
+%D arbitrary seperators.
%D
%D \starttyping
%D \processseparatedlist[list][separator]\command
@@ -6704,8 +6677,8 @@
%D
%D \typebuffer \getbuffer
%D
-%D Therefore we smuggle a \type {\relax} in front of the
-%D argument, which we remove afterwards.
+%D Therefore we smuggle a \type {\relax} in front of the argument, which we remove
+%D afterwards.
\let\syst_helpers_process_separated_list_step\relax
@@ -6736,8 +6709,8 @@
%D \processlist{beginsym}{endsym}{separator}\docommand list
%D \stoptyping
%D
-%D This one supports arbitrary open and close symbols as well as user
-%D defined separators.
+%D This one supports arbitrary open and close symbols as well as user defined
+%D separators.
%D
%D \starttyping
%D \processlist(){=>}\docommand(a=>b=>c=>d)
@@ -6766,16 +6739,15 @@
%D \macros
%D {processassignlist}
%D
-%D Is possible to combine an assignment list with one
-%D containing keywords. Assignments are treated accordingly,
-%D keywords are treated by \type{\command}.
+%D Is possible to combine an assignment list with one containing keywords.
+%D Assignments are treated accordingly, keywords are treated by \type {\command}.
%D
%D \starttyping
%D \processassignlist[...=...,...=...,...]\commando
%D \stoptyping
%D
-%D This command can be integrated in \type{\getparameters}, but
-%D we decided best not to do so.
+%D This command can be integrated in \type {\getparameters}, but we decided best not
+%D to do so.
\unexpanded\def\processassignlist#1[#2]#3%
{\def\syst_helpers_process_assign_list_assign[##1=##2=##3]%
@@ -6788,16 +6760,15 @@
%D {untextargument
%D untexcommand}
%D
-%D When manipulating data(bases) and for instance generating
-%D index entries, the next three macros can be of help:
+%D When manipulating data(bases) and for instance generating index entries, the next
+%D three macros can be of help:
%D
%D \starttyping
%D \untextargument{...}\to\name
%D \untexcommand {...}\to\name
%D \stoptyping
%D
-%D They remove braces and backslashes and give us something to
-%D sort.
+%D They remove braces and backslashes and give us something to sort.
\let\m_syst_helpers_untexed\empty
@@ -6828,7 +6799,6 @@
%D \ScaledPointsToWholeBigPoints {number} \target
%D \stoptyping
%D
-
%D In pure \TEX:
% \unexpanded\def\PointsToBigPoints#1#2%
@@ -6870,16 +6840,15 @@
%D \macros
%D {dontleavehmode}
%D
-%D Sometimes when we enter a paragraph with some command, the
-%D first token gets the whole first line. We can prevent this
-%D by saying:
+%D Sometimes when we enter a paragraph with some command, the first token gets the
+%D whole first line. We can prevent this by saying:
%D
%D \starttyping
%D \dontleavehmode
%D \stoptyping
%D
-%D This command is used in for instance the language module
-%D \type{lang-ini}. The first version was:
+%D This command is used in for instance the language module \type {lang-ini}. The
+%D first version was:
%D
%D \starttyping
%D \def\dontleavehmode{\ifhmode\else\ifmmode\else$ $\fi\fi}
@@ -6894,8 +6863,8 @@
%D \fi \fi}
%D \stoptyping
%D
-%D And finaly we got the following alternative, one that avoids
-%D interfering grouping at the cost of a box.
+%D And finaly we got the following alternative, one that avoids interfering grouping
+%D at the cost of a box.
%D
%D \starttyping
%D \newbox\b_syst_helpers_dlh
@@ -6928,8 +6897,8 @@
% \unexpanded\def\lowercasestring#1\to#2%
% {\lowercase\expandafter{\expandafter\dodoglobal\expandafter\edef\expandafter#2\expandafter{\normalexpanded{#1}}}}
-%D These macros are sort of obsolete as we never use uppercase this
-%D way. But nevertheless we provide them:
+%D These macros are sort of obsolete as we never use uppercase this way. But
+%D nevertheless we provide them:
\def\utfupper#1{\clf_upper{#1}} % expandable
\def\utflower#1{\clf_lower{#1}} % expandable
@@ -6940,8 +6909,8 @@
%D \macros
%D {handletokens}
%D
-%D With the next macro we enter a critical area of macro
-%D expansion. What we want is a macro that looks like:
+%D With the next macro we enter a critical area of macro expansion. What we want is
+%D a macro that looks like:
%D
%D \starttyping
%D \handletokens some tokens\with \somemacro
@@ -6960,17 +6929,16 @@
%D \macros
%D {counttoken,counttokens}
%D
-%D For the few occasions that we want to know the number of
-%D specific tokens in a string, we can use:
+%D For the few occasions that we want to know the number of specific tokens in a
+%D string, we can use:
%D
%D \starttyping
%D \counttoken token\in string\to \somecount
%D \counttokens string\to \somecount
%D \stoptyping
%D
-%D This macro, that for instance is used in \type{cont-tab},
-%D takes a real counter. The macro can be preceded by \type
-%D {\doglobal}.
+%D This macro, that for instance is used in \type {cont-tab}, takes a real counter.
+%D The macro can be preceded by \type {\doglobal}.
\def\syst_helpers_count_token#1% obeys {}
{\def\m_syst_string_three{#1}%
@@ -6997,9 +6965,8 @@
%D \macros
%D {splitofftokens}
%D
-%D Running this one not always gives the expected results.
-%D Consider for instance the macro for which I originally
-%D wrote this token handler.
+%D Running this one not always gives the expected results. Consider for instance the
+%D macro for which I originally wrote this token handler.
\unexpanded\def\splitofftokens#1\from#2\to#3% slow but hardly used
{\ifnum#1>\zerocount
@@ -7022,10 +6989,9 @@
%D \splitofftokens10\from01234567 890123456789\to\test [\test]
%D \stopbuffer
%D
-%D However, the characters that we expect to find in
-%D \type{\test} just don't show up there. The reason for this
-%D is not that logical but follows from \TEX's sometimes
-%D mysterious way of expanding. Look at this:
+%D up there. The reason for this is not that logical but follows from \TEX's
+%D However, the characters that we expect to find in \type {\test} just don't show
+%D sometimes mysterious way of expanding. Look at this:
%D
%D \startbuffer[next]
%D \def\next{a} \edef\test{\next} [\test]
@@ -7037,16 +7003,14 @@
%D
%D \typebuffer[next]
%D
-%D Careful reading shows that inside an \type{\edef} macro's
-%D that are \type{\let} are not expanded!
+%D Careful reading shows that inside an \type {\edef} macro's that are \type {\let}
+%D are not expanded!
%D
%D \unprotect\getbuffer[next]\protect
%D
-%D That's why we finally end up with a macro that looks
-%D ahead by using an assignment, this time by using \type
-%D {\futurelet}, and grabbing an argument as well. That
-%D way we can handle the sentinal, a blank space and grouped
-%D tokens.
+%D That's why we finally end up with a macro that looks ahead by using an
+%D assignment, this time by using \type {\futurelet}, and grabbing an argument as
+%D well. That way we can handle the sentinal, a blank space and grouped tokens.
\unexpanded\def\syst_helpers_handle_tokens % \nexthandledtoken is part of interface
{\futurelet\nexthandledtoken\syst_helpers_handle_tokens_indeed}
@@ -7089,12 +7053,11 @@
%D \macros
%D {iftrialtypesetting, ifvisible}
%D
-%D The next boolean is at first sight a strange one. Sometimes
-%D one does a trial typesetting run, for instance to determine
-%D dimensions. Some mechanisms, like object inclusion, can fail
-%D on such trials. Temporary setting the next boolean to true,
-%D helps a lot. The second boolena can be used to inhibit
-%D processing completely.
+%D The next boolean is at first sight a strange one. Sometimes one does a trial
+%D typesetting run, for instance to determine dimensions. Some mechanisms, like
+%D object inclusion, can fail on such trials. Temporary setting the next boolean to
+%D true, helps a lot. The second boolena can be used to inhibit processing
+%D completely.
\newif\ifvisible \visibletrue
@@ -7112,10 +7075,9 @@
%D \macros
%D {twodigitrounding}
%D
-%D When using \type {\special}s or \type {\pdfliteral}s, it
-%D sometimes makes sense to limit the precission. The next
-%D macro rounds a real number to two digits. It takes one
-%D argument and only works in \ETEX.
+%D When using \type {\special}s or \type {\pdfliteral}s, it sometimes makes sense to
+%D limit the precission. The next macro rounds a real number to two digits. It takes
+%D one argument and only works in \ETEX.
% \def\dointegerrounding #1.#2\relax {#1}
% \def\doonedigitrounding #1.#2#3\relax {\ifx#2*#1\else#1.#2\fi}
@@ -7168,18 +7130,17 @@
\let\gobblesingleempty\dogobblesingleempty % also used
\let\gobbledoubleempty\dogobbledoubleempty % also used
-%D \macros
-%D {@True, @False, @Not, @And}
-%D
-%D Some predicate logic functions, used in for instance the
-%D math module.
-
-% These have rather ugly names ... will change:
-
-\def\@True {00}
-\def\@False {01}
-\def\@Not #1{0\ifcase#11 \or\expandafter 1\else \expandafter 0\fi}
-\def\@And #1#2{0\ifcase#1#2 \expandafter 0\else \expandafter 1\fi}
+% %D \macros
+% %D {@True, @False, @Not, @And}
+% %D
+% %D Some predicate logic functions, used in for instance the math module.
+%
+% % These have rather ugly names ... will change:
+%
+% \def\@True {00}
+% \def\@False {01}
+% \def\@Not #1{0\ifcase#11 \or\expandafter 1\else \expandafter 0\fi}
+% \def\@And #1#2{0\ifcase#1#2 \expandafter 0\else \expandafter 1\fi}
%D \macros
%D {setdimensionwithunit, freezedimensionwithunit}
@@ -7194,9 +7155,8 @@
%D \freezedimensionwithunit\SomeDepth{\dp\strutbox}
%D \stoptyping
%D
-%D As an alternative for the next macro we can use a global
-%D assignment inside a box. The \type{\empty}'s permits
-%D gobbling while preventing spurious \type{\relax}'s.
+%D As an alternative for the next macro we can use a global assignment inside a box.
+%D The \type {\empty}'s permits gobbling while preventing spurious \type {\relax}'s.
\unexpanded\def\setdimensionwithunit#1#2#3% number unit dimension / nice trick
{\afterassignment\gobblefourarguments#1=#2#3pt\relax\empty\empty\empty\empty}
@@ -7207,8 +7167,7 @@
%D \macros
%D {doifsometokselse, doifsometoks}
%D
-%D Not that fast I guess, but here's a way to test for token
-%D registers being empty.
+%D Not that fast I guess, but here's a way to test for token registers being empty.
\unexpanded\def\doifelsesometoks#1%
{\edef\m_syst_string_one{\the#1}% one level expansion so quite ok
@@ -7218,8 +7177,6 @@
\expandafter\firstoftwoarguments
\fi}
-\let\doifsometokselse\doifelsesometoks
-
\unexpanded\def\doifsometoks#1%
{\edef\m_syst_string_one{\the#1}% one level expansion so quite ok
\ifx\m_syst_string_one\empty
@@ -7236,31 +7193,26 @@
\expandafter\gobbleoneargument
\fi}
+\let\doifsometokselse\doifelsesometoks
+
%D \macros
%D {startstrictinspectnextcharacter}
%D
-%D This one if for Taco's bibliography module:
+%D This one is for the bibliography module (still?):
-\let\syst_helpers_normal_inspect_next_character\syst_helpers_inspect_next_character
+\let\syst_helpers_strict_inspect_next_character[
\def\syst_helpers_strict_inspect_next_character% no user macro !
- {\ifx\nexttoken\charactertoken
+ {\ifx\nexttoken[%
\expandafter\m_syst_action_yes
\else
\expandafter\m_syst_action_nop
\fi}
-% better: push/pop
-
-\unexpanded\def\startstrictinspectnextcharacter
- {\let\syst_helpers_inspect_next_character\syst_helpers_strict_inspect_next_character}
-
-\unexpanded\def\stopstrictinspectnextcharacter
- {\let\syst_helpers_inspect_next_character\syst_helpers_normal_inspect_next_character}
-
\unexpanded\def\strictdoifelsenextoptional#1#2%
- {\startstrictinspectnextcharacter
- \doifelsenextchar[{\stopstrictinspectnextcharacter#1}{\stopstrictinspectnextcharacter#2}}
+ {\def\m_syst_action_yes{#1}%
+ \def\m_syst_action_nop{#2}%
+ \futurelet\nexttoken\syst_helpers_strict_inspect_next_character}
\let\strictdoifnextoptionalelse\strictdoifelsenextoptional
@@ -7278,8 +7230,7 @@
%D \macros
%D {verbatimargument}
%D
-%D As the name says, this macro converts its argument to a
-%D (rather safe) string.
+%D As the name says, this macro converts its argument to a (rather safe) string.
\let\verbatimstring\detokenize
@@ -7314,18 +7265,16 @@
%D \macros
%D {purenumber}
%D
-%D Sometimes we need control over when \TEX\ stops reading a
-%D number, especially in full expandable macros where using
-%D \type {\relax} would lead to disasters.
+%D Sometimes we need control over when \TEX\ stops reading a number, especially in
+%D full expandable macros where using \type {\relax} would lead to disasters.
%D
%D \starttyping
%D \ifodd\purenumber{...}\space ... \else ... \fi
%D \stoptyping
%D
-%D Here we use a space as number delimiter in combination
-%D with a space- and relax-less \type {\purenumber}. This
-%D macro works ok with \type {\the}, \type {\number} as well
-%D as \ETEX's \type {\numexpr}.
+%D Here we use a space as number delimiter in combination with a space- and
+%D relax-less \type {\purenumber}. This macro works ok with \type {\the}, \type
+%D {\number} as well as \ETEX's \type {\numexpr}.
\def\purenumber#1{\expandafter\firstofoneargument\expandafter{\number#1}}
@@ -7350,8 +7299,7 @@
%D \filterfromvalues{3}{xx}{1}
%D \stoptyping
%D
-%D I'll implement this when I'm in \quotation {writing dirty
-%D macros mood}.
+%D I'll implement this when I'm in \quotation {writing dirty macros mood}.
\def\dofilterfromstr#1#2% max n % no need to be fast
{\expandafter \expandafter \expandafter \csstring
@@ -7429,6 +7377,9 @@
%{\dimexpr\ifcsname\??measure#1\endcsname\csname\??measure#1\endcsname\else\zeropoint\fi\relax}
{\dimexpr\ifcsname\??measure#1\endcsname\lastnamedcs\else\zeropoint\fi\relax}
+\def\directmeasure#1%
+ {\the\dimexpr#1\relax}
+
% #2 could be omitted, but we want to support spaces
%
% \setmeasure {x} {1cm}
@@ -7436,6 +7387,41 @@
% \setmeasure {xxx}{1cm}
%D \macros
+%D {definequantity}
+%D
+%D These do the same but for numbers.
+
+\installsystemnamespace{quantity}
+
+\unexpanded\def\definequantity
+ {\dodoubleargument\syst_helpers_define_quantity}
+
+\def\syst_helpers_define_quantity[#1][#2]%
+ {\expandafter\def\csname\??quantity#1\endcsname{#2}}
+
+\unexpanded\def\freezequantity
+ {\dodoubleargument\syst_helpers_freeze_quantity}
+
+\def\syst_helpers_freeze_quantity[#1][#2]%
+ {\expandafter\edef\csname\??quantity#1\endcsname{\the\numexpr#2}}
+
+\unexpanded\def\setquantity #1#2{\expandafter\def \csname\??quantity#1\endcsname{#2}} % quick way
+\unexpanded\def\setgquantity#1#2{\expandafter\gdef\csname\??quantity#1\endcsname{#2}} % quick way
+\unexpanded\def\setequantity#1#2{\expandafter\edef\csname\??quantity#1\endcsname{\the\numexpr#2}} % quick way
+\unexpanded\def\setxquantity#1#2{\expandafter\xdef\csname\??quantity#1\endcsname{\the\numexpr#2}} % quick way
+
+\def\quantity
+ {\the\quantitied}
+
+\def\quantitied#1%
+ {\numexpr\ifcsname\??quantity#1\endcsname\lastnamedcs\else\zeropoint\fi\relax}
+
+\def\directquantity#1%
+ {\the\numexpr#1\relax}
+
+% let\quantified\quantitied
+
+%D \macros
%D {dividedsize}
%D
%D This one can be used inside a measure (used in m4all):
@@ -7459,7 +7445,8 @@
\def\doifelsedimension#1%
{\afterassignment\syst_helpers_if_dimension_else\privatescratchdimen#1pt\relax}
-\let\doifdimensionelse\doifelsedimension
+% \def\doifelsedimension#1%
+% {\expandafter\syst_helpers_if_dimension_else\immediateassignment\privatescratchdimen#1pt\relax}
\def\syst_helpers_if_dimension_else#1%
{\ifx#1\relax
@@ -7468,6 +7455,8 @@
\expandafter\thirdoffourarguments
\fi}
+\let\doifdimensionelse\doifelsedimension
+
%D Ok, here's another one, slower but seldom used. This one scans the text.
%D
%D \starttabulate[|Tc|Tc|]
@@ -7491,8 +7480,6 @@
\def\doifelsedimenstring#1{\normalexpanded{\noexpand\dodimenteststageone#1}\empty\empty]}
-\let\doifdimenstringelse\doifelsedimenstring
-
\def\dodimenteststageone #1#2{\csname \??dimenchecka\ifcsname \??dimenchecka#2\endcsname#2\else x\fi\endcsname#2}
\def\dodimenteststagetwo #1#2{\csname \??dimencheckb\ifcsname \??dimencheckb#2\endcsname#2\else x\fi\endcsname#2}
\def\dodimenteststagethree #1]{\csname \??dimencheckc\ifcsname \??dimencheckc#1\endcsname#1\else x\fi\endcsname}
@@ -7539,6 +7526,8 @@
\expandafter\let\csname \??dimencheckc nd\endcsname\firstoftwoarguments
\expandafter\let\csname \??dimencheckc nc\endcsname\firstoftwoarguments
+\let\doifdimenstringelse\doifelsedimenstring
+
%D \macros
%D {comparedimension,comparedimensioneps}
%D
@@ -7569,8 +7558,6 @@
\plustwo
\fi\fi\fi}
-% % % % % % % % % % % % % % % % % % % % % %
-
% pretty ugly but fast
% \copycsname xxx\endcsname\csname ..\endcsname
@@ -7675,6 +7662,8 @@
\expandafter\secondoftwoarguments
\fi}
+% used ?
+
\def\doifelsenonzeropositive#1%
{\begingroup\afterassignment\syst_helpers_if_non_zero_positive_else\privatescratchcounter=0#1\relax\empty\end}
@@ -7720,26 +7709,34 @@
\let\elapsedseconds \elapsedtime
\newcount\c_syst_helpers_test_feature_n
-\chardef \c_syst_helpers_test_feature_m\zerocount
+\newcount\c_syst_helpers_test_feature_m
\def\currentfeaturetest{\number\c_syst_helpers_test_feature_n}
\unexpanded\def\testfeature#1#2%
- {\chardef\c_syst_helpers_test_feature_m#1\relax
- \def\syst_helpers_test_feature_step
+ {\c_syst_helpers_test_feature_m#1\relax
+ \def\syst_helpers_test_feature_yes
{\advance\c_syst_helpers_test_feature_n\plusone
\ifnum\c_syst_helpers_test_feature_n>\c_syst_helpers_test_feature_m\else
- #2\expandafter\syst_helpers_test_feature_step
+ #2\expandafter\syst_helpers_test_feature_yes
+ \fi}%
+ \def\syst_helpers_test_feature_nop
+ {\advance\c_syst_helpers_test_feature_n\plusone
+ \ifnum\c_syst_helpers_test_feature_n>\c_syst_helpers_test_feature_m\else
+ \expandafter\syst_helpers_test_feature_nop
\fi}%
\retestfeature}
\unexpanded\def\retestfeature % timer support is new per 10/5/2005
{\bgroup
\ifcase\interactionmode\let\wait\relax\fi
+ \clf_resettimer
+ \c_syst_helpers_test_feature_n\zerocount
+ \syst_helpers_test_feature_nop
+ \clf_benchmarktimer
\writestatus\m!system{starting feature test (n=\number\c_syst_helpers_test_feature_m)}\wait
- \resettimer
\c_syst_helpers_test_feature_n\zerocount
- \syst_helpers_test_feature_step
+ \syst_helpers_test_feature_yes
\writestatus\m!system{\number\c_syst_helpers_test_feature_m\space feature tests done (\elapsedseconds s)}%
\wait
\egroup}
@@ -7765,8 +7762,8 @@
\unexpanded\def\freezedimenmacro#1%
{\edef#1{\the\dimexpr#1}}
-%D The next macro negates a macro (dimension or number, or actually, whatever.
-%D It's a typical example of \type {\if} usage:
+%D The next macro negates a macro (dimension or number, or actually, whatever. It's
+%D a typical example of \type {\if} usage:
%D
%D \starttyping
%D \if-\whatever \else-\whatever\fi => else => -whatever
@@ -7795,8 +7792,8 @@
%D \macros
%D {dowithrange}
%D
-%D This one is for Mojca Miklavec, who made me aware of the fact that
-%D \type {page-imp.tex} was not the best place to hide it.
+%D This one is for Mojca Miklavec, who made me aware of the fact that \type
+%D {page-imp.tex} was not the best place to hide it.
%D
%D \startbuffer
%D \def\DoSomething#1{ [item #1] }
@@ -7878,8 +7875,8 @@
\def\syst_helpers_expand_checked_csname#1#2#3%
{\csname#1\ifcsname#1#2\endcsname#2\else#3\fi\endcsname}
-%D Signal. Some fonts have a char0 rendering so we need to make sure that it
-%D is not set in the font! (THis will be overloaded)
+%D Signal. Some fonts have a char0 rendering so we need to make sure that it is not
+%D set in the font! (This will be overloaded)
\unexpanded\def\signalcharacter{\char\zerocount} % \zwj
@@ -8103,6 +8100,21 @@
%
% \def\additemtolist#1#2{\normalexpanded{\noexpand\clf_additemtolist{#1}{#2}}}
+%D Experiment (sometimes looks nicer in code):
+
+\unexpanded\def\sameargumentscondition#1#2%
+ {\edef\m_syst_string_one{#1}%
+ \edef\m_syst_string_two{#2}%
+ \ifx\m_syst_string_one\m_syst_string_two}
+
+\unexpanded\def\emptyargumentcondition#1%
+ {\edef\m_syst_string_one{#1}%
+ \ifx\m_syst_string_one\empty}
+
+% \unexpanded\def\hascommonargumentcondition#1#2{\clf_hascommonargumentcondition{#1}{#2}}
+% \let\hascommonargumentcondition \clf_hascommonargumentcondition
+% \unexpanded\def\hascommonargumentcondition{\clf_hascommonargumentcondition}
+
\protect \endinput
% \edef\choicetokenyes{+}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/syst-aux.mkxl b/Master/texmf-dist/tex/context/base/mkiv/syst-aux.mkxl
new file mode 100644
index 00000000000..7ade250d970
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/syst-aux.mkxl
@@ -0,0 +1,6587 @@
+%D \module
+%D [ file=syst-aux, % merge of syst-gen cum suis
+%D version=1996.03.20,
+%D title=\CONTEXT\ System Macros,
+%D subtitle=General,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\registerctxluafile{syst-aux}{}
+
+%D This fils is a follow up in \type {syst-aux.mkii} and \type {syst-aux.mkiv}
+%D where you can find some more pure \TEX\ or \LUATEX| variants.
+
+\unprotect
+
+%D \macros
+%D {unexpanded}
+%D
+%D Because we use this module only in \MKIV, we have removed the old protection
+%D code.
+%D
+%D \starttyping
+%D \unexpanded\def\somecommand{... ... ...}
+%D \stoptyping
+%D
+%D This overloads the \ETEX\ primitive but as we already had an \MKII\ solution we
+%D keep the same name for a similar mechanism.
+
+\let\unexpanded\normalprotected
+
+\ifcase\contextlmtxmode
+
+ \def\startlmtxmode#1\stoplmtxmode{}
+ \let\stoplmtxmode \relax
+ \let\startmkivmode\relax
+ \let\stopmkivmode \relax
+
+\else
+
+ \let\startlmtxmode\relax
+ \let\stoplmtxmode \relax
+ \def\startmkivmode#1\stopmkivmode{}
+ \let\stopmkivmode \relax
+
+\fi
+
+%D As we don't have namespace definers yet, we use a special one:
+
+\ifdefined\c_syst_helpers_n_of_namespaces
+
+ % lets plug in a better error message
+
+\else
+
+ \newcount\c_syst_helpers_n_of_namespaces \c_syst_helpers_n_of_namespaces\pluseight % 1-8 reserved for catcodes
+
+ \def\v_interfaces_prefix_template_system{\number \c_syst_helpers_n_of_namespaces>>}
+ %def\v_interfaces_prefix_template_system{\characters\c_syst_helpers_n_of_namespaces>>} % no \characters yet
+
+\fi
+
+\unexpanded\def\installsystemnamespace#1% maybe move this to syst-ini
+ {\ifcsname ??#1\endcsname
+ \writestatus\m!system{duplicate system namespace '#1'}\wait
+ \else
+ \global\advance\c_syst_helpers_n_of_namespaces\plusone
+ \expandafter\edef\csname ??#1\endcsname{\v_interfaces_prefix_template_system}%
+ \fi}
+
+%D \macros
+%D {normalspace}
+%D
+%D There is already \type{\space} but just to be sure we also provide:
+
+\def\normalspace{ }
+
+%D \macros
+%D {!!count, !!toks, !!dimen, !!box,
+%D !!width, !!height, !!depth, !!string, !!done}
+%D
+%D We define some more \COUNTERS\ and \DIMENSIONS. We also define some shortcuts to
+%D the local scatchregisters~0, 2, 4, 6 and~8.
+
+\newcount\!!counta \newtoks\!!toksa \newdimen\!!dimena \newbox\!!boxa
+\newcount\!!countb \newtoks\!!toksb \newdimen\!!dimenb \newbox\!!boxb
+\newcount\!!countc \newtoks\!!toksc \newdimen\!!dimenc \newbox\!!boxc
+\newcount\!!countd \newtoks\!!toksd \newdimen\!!dimend \newbox\!!boxd
+\newcount\!!counte \newtoks\!!tokse \newdimen\!!dimene \newbox\!!boxe
+\newcount\!!countf \newtoks\!!toksf \newdimen\!!dimenf \newbox\!!boxf
+ \newdimen\!!dimeng
+ \newdimen\!!dimenh
+ \newdimen\!!dimeni
+ \newdimen\!!dimenj
+ \newdimen\!!dimenk
+
+\let\!!stringa\empty \let\!!stringb\empty \let\!!stringc\empty
+\let\!!stringd\empty \let\!!stringe\empty \let\!!stringf\empty
+
+\newdimen\!!widtha \newdimen\!!heighta \newdimen\!!deptha
+\newdimen\!!widthb \newdimen\!!heightb \newdimen\!!depthb
+\newdimen\!!widthc \newdimen\!!heightc \newdimen\!!depthc
+\newdimen\!!widthd \newdimen\!!heightd \newdimen\!!depthd
+
+\newif\if!!donea \newif\if!!doneb \newif\if!!donec
+\newif\if!!doned \newif\if!!donee \newif\if!!donef
+
+\def\!!zerocount {0} % alongside \zerocount
+\def\!!minusone {-1} % ...
+\def\!!plusone {1} % ...
+\def\!!plustwo {2} % ...
+\def\!!plusthree {3} % ...
+\def\!!plusfour {4} % ...
+\def\!!plusfive {5} % ...
+\def\!!plussix {6} % ...
+\def\!!plusseven {7} % ...
+\def\!!pluseight {8} % ...
+\def\!!plusnine {9} % alongside \plusnine
+
+\setnewconstant \uprotationangle 0
+\setnewconstant\rightrotationangle 90
+\setnewconstant \downrotationangle 180
+\setnewconstant \leftrotationangle 270
+
+\ifdefined\data \else \let\data \relax \fi % dep checker
+
+%D \macros
+%D {s!,c!,e!,p!,v!,@@,??}
+%D
+%D To save memory, we use constants (sometimes called variables). Redefining these
+%D constants can have disastrous results.
+
+\def\v!prefix! {v!}
+\def\c!prefix! {c!}
+\def\s!prefix! {s!}
+
+\def\s!next {next}
+\def\s!default {default}
+\def\s!dummy {dummy}
+\def\s!unknown {unknown}
+
+\def\s!do {do}
+\def\s!dodo {dodo}
+
+\def\s!complex {complex}
+\def\s!start {start}
+\def\s!simple {simple}
+\def\s!stop {stop}
+
+\def\s!empty {empty}
+
+%D Sometimes we pass macros as arguments to commands that don't expand them
+%D before interpretation. Such commands can be enclosed with \type {\expanded},
+%D like:
+%D
+%D \starttyping
+%D \expanded{\setupsomething[\alfa]}
+%D \stoptyping
+%D
+%D Such situations occur for instance when \type{\alfa} is a commalist or when data
+%D stored in macros is fed to index of list commands. If needed, one should use
+%D \type{\noexpand} inside the argument. Later on we will meet some more clever
+%D alternatives to this command. Beware, only the simple one has \type {\noexpand}
+%D before its argument.
+
+\let\m_syst_helpers_expanded\empty
+
+\unexpanded\def\expanded#1%
+ {\xdef\m_syst_helpers_expanded{\noexpand#1}\m_syst_helpers_expanded}
+
+\unexpanded\def\startexpanded#1\stopexpanded
+ {\xdef\m_syst_helpers_expanded{#1}\m_syst_helpers_expanded}
+
+\let\stopexpanded\relax
+
+%D Recent \TEX\ engines have a primitive \type {\expanded} and we will use that when
+%D possible. After all, we can make not expandable macros now.
+
+% We cannot use the next variant as first we need to adapt \type {##}'s in callers:
+%
+% \def\expanded#1%
+% {\normalexpanded{\noexpand#1}}
+%
+% \def\startexpanded#1\stopexpanded
+% {\normalexpanded{#1}}
+
+%D \macros
+%D {gobbleoneargument,gobble...arguments}
+%D
+%D The next set of macros just do nothing, except that they get rid of a number of
+%D arguments.
+
+\def\gobbleoneargument #1{}
+\def\gobbletwoarguments #1#2{}
+\def\gobblethreearguments#1#2#3{}
+\def\gobblefourarguments #1#2#3#4{}
+\def\gobblefivearguments #1#2#3#4#5{}
+\def\gobblesixarguments #1#2#3#4#5#6{}
+\def\gobblesevenarguments#1#2#3#4#5#6#7{}
+\def\gobbleeightarguments#1#2#3#4#5#6#7#8{}
+\def\gobbleninearguments #1#2#3#4#5#6#7#8#9{}
+\def\gobbletenarguments #1{\gobbleninearguments}
+
+\def\gobbleoneoptional [#1]{}
+\def\gobbletwooptionals [#1][#2]{}
+\def\gobblethreeoptionals[#1][#2][#3]{}
+\def\gobblefouroptionals [#1][#2][#3][#4]{}
+\def\gobblefiveoptionals [#1][#2][#3][#4][#5]{}
+
+%D Reserved macros for tests:
+
+\let\donothing\empty
+
+\let\m_syst_string_one \empty
+\let\m_syst_string_two \empty
+\let\m_syst_string_three\empty
+\let\m_syst_string_four \empty
+
+\let\m_syst_action_yes \empty
+\let\m_syst_action_nop \empty
+
+%D \macros
+%D {doifnextcharelse}
+%D
+%D When we started using \TEX\ in the late eighties, our first experiences with
+%D programming concerned a simple shell around \LATEX. The commands probably use
+%D most at \PRAGMA, are the itemizing ones. One of those few shell commands took
+%D care of an optional argument, that enabled us to specify what kind of item symbol
+%D we wanted. Without understanding anything we were able to locate a \LATEX\ macro
+%D that could be used to inspect the next character.
+%D
+%D It's this macro that the ancester of the next one presented here. It executes one
+%D of two actions, dependant of the next character. Disturbing spaces and line
+%D endings, which are normally interpreted as spaces too, are skipped.
+%D
+%D \starttyping
+%D \doifnextcharelse {karakter} {then ...} {else ...}
+%D \stoptyping
+%D
+%D This macro differs from the original in the use of \type {\localnext} because we
+%D don't want clashes with \type {\next}.
+
+\let\next \relax
+\let\nextnext \relax
+\let\nextnextnext \relax
+\let\nexttoken \relax
+\let\charactertoken\relax
+
+\let\m_syst_action_yes\relax
+\let\m_syst_action_nop\relax
+
+% \def\syst_helpers_inspect_next_character
+% {\ifx\nexttoken\blankspace
+% \expandafter\syst_helpers_reinspect_next_character
+% \else
+% \expandafter\syst_helpers_inspect_next_character_indeed
+% \fi}
+%
+% \def\syst_helpers_inspect_next_character_indeed
+% {\ifx\nexttoken\charactertoken
+% \expandafter\m_syst_action_yes
+% \else
+% \expandafter\m_syst_action_nop
+% \fi}
+
+\unexpanded\def\doifelsenextchar#1#2#3% #1 should not be {} !
+ {\def\m_syst_action_yes{#2}%
+ \def\m_syst_action_nop{#3}%
+ \futureexpandis#1\m_syst_action_yes\m_syst_action_nop}
+
+\unexpanded\def\doifelsenextcharcs % #1#2#3% #1 should not be {} !
+ {\futureexpandis}
+
+\let\doifnextcharelse \doifelsenextchar
+\let\doifnextcharcselse\doifelsenextcharcs
+
+%D Because we will mostly use this macro for testing if the next character is \type
+%D {[}, we also make a slightly faster variant as it is not uncommon to have tens of
+%D thousands of calls to this test in a run. Of course it also is more convenient to
+%D read a trace then.
+
+% \newif\if_next_blank_space_token
+
+% \let\syst_helpers_next_optional_character_token=[
+%
+% \def\syst_helpers_inspect_next_optional_character
+% {\ifx\nexttoken\blankspace
+% \expandafter\syst_helpers_reinspect_next_optional_character
+% \else
+% \expandafter\syst_helpers_inspect_next_optional_character_indeed
+% \fi}
+%
+% \def\syst_helpers_inspect_next_optional_character_indeed
+% {\ifx\nexttoken\syst_helpers_next_optional_character_token
+% \expandafter\m_syst_action_yes
+% \else
+% \expandafter\m_syst_action_nop
+% \fi}
+
+\unexpanded\def\doifelsenextoptional#1#2%
+ {\def\m_syst_action_yes{#1}%
+ \def\m_syst_action_nop{#2}%
+ \futureexpandis[\m_syst_action_yes\m_syst_action_nop}
+
+\unexpanded\def\doifelsenextoptionalcs
+ {\futureexpandis[}
+
+\let\doifnextoptionalelse \doifelsenextoptional
+\let\doifnextoptionalcselse\doifelsenextoptionalcs
+
+% \let\syst_helpers_next_bgroup_character_token\bgroup
+%
+% \def\syst_helpers_inspect_next_bgroup_character
+% {\ifx\nexttoken\blankspace
+% \expandafter\syst_helpers_reinspect_next_bgroup_character
+% \else
+% \expandafter\syst_helpers_inspect_next_bgroup_character_indeed
+% \fi}
+%
+% \def\syst_helpers_inspect_next_bgroup_character_indeed
+% {\ifx\nexttoken\syst_helpers_next_bgroup_character_token
+% \expandafter\m_syst_action_yes
+% \else
+% \expandafter\m_syst_action_nop
+% \fi}
+
+\unexpanded\def\doifelsenextbgroup#1#2%
+ {\def\m_syst_action_yes{#1}%
+ \def\m_syst_action_nop{#2}%
+ \futureexpandis\bgroup\m_syst_action_yes\m_syst_action_nop}
+
+\unexpanded\def\doifelsenextbgroupcs % #1#2
+ {\futureexpandis\bgroup}
+
+\let\doifnextbgroupelse \doifelsenextbgroup
+\let\doifnextbgroupcselse\doifelsenextbgroupcs
+
+% \let\syst_helpers_next_parenthesis_character_token(
+%
+% \def\syst_helpers_inspect_next_parenthesis_character
+% {\ifx\nexttoken\blankspace
+% \expandafter\syst_helpers_reinspect_next_parenthesis_character
+% \else
+% \expandafter\syst_helpers_inspect_next_parenthesis_character_indeed
+% \fi}
+%
+% \def\syst_helpers_inspect_next_parenthesis_character_indeed
+% {\ifx\nexttoken\syst_helpers_next_parenthesis_character_token
+% \expandafter\m_syst_action_yes
+% \else
+% \expandafter\m_syst_action_nop
+% \fi}
+
+\unexpanded\def\doifelsenextparenthesis#1#2%
+ {\def\m_syst_action_yes{#1}%
+ \def\m_syst_action_nop{#2}%
+ \futureexpandis(\m_syst_action_yes\m_syst_action_nop}
+
+\let\doifnextparenthesiselse\doifelsenextparenthesis
+
+%D The next one is handy in predictable situations:
+
+\def\syst_helpers_do_if_fast_optional_check_else
+ {\ifx\nexttoken\syst_helpers_next_optional_character_token
+ \expandafter\m_syst_action_yes
+ \else
+ \expandafter\m_syst_action_nop
+ \fi}
+
+\unexpanded\def\doifelsefastoptionalcheck#1#2%
+ {\def\m_syst_action_yes{#1}%
+ \def\m_syst_action_nop{#2}%
+ \futureexpandis[\m_syst_action_yes\m_syst_action_nop}
+
+\unexpanded\def\doifelsefastoptionalcheckcs
+ {\futureexpandis[}
+
+\let\doiffastoptionalcheckelse \doifelsefastoptionalcheck
+\let\doiffastoptionalcheckcselse\doifelsefastoptionalcheckcs
+
+%D Here's one for skipping spaces and pars, handy for:
+%D
+%D \starttyping
+%D \hbox
+%D
+%D {a few lines later}
+%D \stoptyping
+%D
+%D like:
+%D
+%D \starttyping
+%D \def\somecommand{\dowithnextbox{\box\nextbox}\ruledhbox}
+%D
+%D \assumelongusagecs\somecommand
+%D
+%D \bgroup
+%D oeps
+%D \egroup
+%D \stoptyping
+
+%D The cumbersome original:
+
+% \unexpanded\def\assumelongusagecs#1%
+% {\let\m_syst_action#1%
+% \futurelet\nexttoken\syst_helpers_ignore_spacing}
+%
+% \def\syst_helpers_ignore_spacing
+% {\ifx\nexttoken\blankspace
+% \expandafter\syst_helpers_ignore_spacing_blankspace
+% \orelse\ifx\nexttoken\par
+% \expandafter\syst_helpers_ignore_spacing_partoken
+% \else
+% \expandafter\m_syst_action
+% \fi}
+%
+% \def\syst_helpers_ignore_spacing_partoken\par
+% {\futurelet\nexttoken\syst_helpers_ignore_spacing}
+
+%D A bit less tracing noise:
+
+% \def\assume_long_usage_cs
+% {\futureexpandis\par\assume_long_usage_par\m_syst_action}
+%
+% \def\assume_long_usage_par\par%
+% {\assume_long_usage_cs}
+%
+% \unexpanded\def\assumelongusagecs#1{\let\m_syst_action#1\assume_long_usage_cs}
+
+%D Ok, using \type {\futureexpandisap} is maybe feature creep but I'd like to experiment
+%D with more tolerant user input. It might go away in which case we use the above.
+
+\unexpanded\def\assumelongusagecs#1%
+ {\futureexpandisap\relax#1#1}
+
+% D These macros use some auxiliary macros. Although we were able to program quite
+% D complicated things, I only understood these after rereading the \TEX book. The
+% D trick is in using a command with a one character name. Such commands differ from
+% D the longer ones in the fact that trailing spaces are {\em not} skipped. This
+% D enables us to indirectly define a long named macro that gobbles a space. In the
+% D first line we define \type {\blankspace}. Next we make \type {\:} equivalent to
+% D \type {\reinspect...}. This one||character command is expanded before the next
+% D \type {\def} comes into action. This way the space after \type {\:} becomes a
+% D delimiter of the longer named \type {\reinspectnextcharacter}.
+
+\let\next\:
+
+\def\:{\let\blankspace= } \:
+
+% \def\:{\syst_helpers_reinspect_next_character}
+% \expandafter\def\: {\let\if_next_blank_space_token\iftrue\futurelet\nexttoken\syst_helpers_inspect_next_character}
+%
+% \def\:{\syst_helpers_reinspect_next_optional_character}
+% \expandafter\def\: {\let\if_next_blank_space_token\iftrue\futurelet\nexttoken\syst_helpers_inspect_next_optional_character}
+%
+% \def\:{\syst_helpers_reinspect_next_bgroup_character}
+% \expandafter\def\: {\let\if_next_blank_space_token\iftrue\futurelet\nexttoken\syst_helpers_inspect_next_bgroup_character}
+%
+% \def\:{\syst_helpers_reinspect_next_parenthesis_character}
+% \expandafter\def\: {\let\if_next_blank_space_token\iftrue\futurelet\nexttoken\syst_helpers_inspect_next_parenthesis_character}
+%
+% \def\:{\syst_helpers_ignore_spacing_blankspace}
+% \expandafter\def\: {\futurelet\nexttoken\syst_helpers_ignore_spacing}
+
+\let\:\next
+
+%D \macros
+%D {setvalue,setgvalue,setevalue,setxvalue,
+%D letvalue,letgvalue,getvalue,resetvalue,
+%D undefinevalue,ignorevalue}
+%D
+%D \TEX's primitive \type {\csname} can be used to construct all kind of commands
+%D that cannot be defined with \type {\def} and \type {\let}. Every macro programmer
+%D sooner or later wants macros like these.
+%D
+%D \starttyping
+%D \setvalue {name}{...} = \def\name{...}
+%D \setgvalue {name}{...} = \gdef\name{...}
+%D \setevalue {name}{...} = \edef\name{...}
+%D \setxvalue {name}{...} = \xdef\name{...}
+%D \letvalue {name}=\... = \let\name=\...
+%D \letgvalue {name}=\... = \glet\name=\...
+%D \getvalue {name} = \name
+%D \resetvalue {name} = \def\name{}
+%D \stoptyping
+%D
+%D As we will see, \CONTEXT\ uses these commands many times, which is mainly due to
+%D its object oriented and parameter driven character.
+
+\def\setvalue #1{\expandafter\def \csname#1\endcsname}
+\def\setgvalue #1{\expandafter\gdef\csname#1\endcsname}
+\def\setevalue #1{\expandafter\edef\csname#1\endcsname}
+\def\setxvalue #1{\expandafter\xdef\csname#1\endcsname}
+\def\getvalue #1{\csname#1\endcsname} % maybe: \begincsname#1\endcsname
+\def\letvalue #1{\expandafter\let \csname#1\endcsname}
+\def\letgvalue #1{\expandafter\glet\csname#1\endcsname}
+\def\resetvalue #1{\expandafter\let \csname#1\endcsname\empty}
+\def\undefinevalue#1{\expandafter\let \csname#1\endcsname\undefined}
+\def\ignorevalue#1#2{\expandafter\let \csname#1\endcsname\empty}
+
+\def\setuvalue #1{\normalprotected\expandafter \def\csname#1\endcsname}
+\def\setuevalue #1{\normalprotected\expandafter\edef\csname#1\endcsname}
+\def\setugvalue #1{\normalprotected\expandafter\gdef\csname#1\endcsname}
+\def\setuxvalue #1{\normalprotected\expandafter\xdef\csname#1\endcsname}
+
+\unexpanded\def\getuvalue#1{\csname#1\endcsname}
+
+%D \macros
+%D {globallet,glet}
+%D
+%D In \CONTEXT\ of May 2000 using \type {\globallet} instead of the two tokens will
+%D save us some $300\times4=1200$ bytes of format file on a 32~bit system. Not that
+%D it matters much today. This shortcut is already defined:
+
+\let\globallet\glet
+
+%D \macros
+%D {doifundefined,doifdefined,
+%D doifundefinedelse,doifdefinedelse,
+%D doifalldefinedelse}
+%D
+%D The standard way of testing if a macro is defined is comparing its meaning with
+%D another undefined one, usually \type{\undefined}. To garantee correct working of
+%D the next set of macros, \type{\undefined} may never be defined!
+%D
+%D \starttyping
+%D \doifundefined {string} {...}
+%D \doifdefined {string} {...}
+%D \doifundefinedelse {string} {then ...} {else ...}
+%D \doifdefinedelse {string} {then ...} {else ...}
+%D \doifalldefinedelse {commalist} {then ...} {else ...}
+%D \stoptyping
+%D
+%D Every macroname that \TEX\ builds gets an entry in the hash table, which is of
+%D limited size. It is expected that \ETEX\ will offer a less memory||consuming
+%D alternative.
+
+%D Although it will probably never be a big problem, it is good to be aware of the
+%D difference between testing on a macro name to be build by using \type{\csname} and
+%D \type{\endcsname} and testing the \type{\name} directly.
+%D
+%D \starttyping
+%D \expandafter\ifx\csname NameA\endcsname\relax ... \else ... \fi
+%D
+%D \ifundefined\NameB ... \else ... \fi
+%D \stoptyping
+
+% \suppressifcsnameerror\plusone % already set
+
+\def\doifelseundefined#1%
+ {\ifcsname#1\endcsname
+ \expandafter\secondoftwoarguments\else\expandafter\firstoftwoarguments
+ \fi}
+
+\def\doifelsedefined#1%
+ {\ifcsname#1\endcsname
+ \expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments
+ \fi}
+
+\def\doifundefined#1%
+ {\ifcsname#1\endcsname
+ \expandafter\gobbleoneargument\else\expandafter\firstofoneargument
+ \fi}
+
+\def\doifdefined#1%
+ {\ifcsname#1\endcsname
+ \expandafter\firstofoneargument\else\expandafter\gobbleoneargument
+ \fi}
+
+\let\doifundefinedelse\doifelseundefined
+\let\doifdefinedelse \doifelsedefined
+
+%D \macros
+%D {letbeundefined}
+%D
+%D Testing for being undefined comes down to testing on \type {\relax} when we use
+%D \type {\csname}, but when using \type {\ifx}, we test on being \type
+%D {\undefined}! In \ETEX\ we have \type {\ifcsname} and that way of testing on
+%D existance is not the same as the one described here. Therefore we introduce:
+
+\unexpanded\def\letbeundefined#1% potential stack buildup when used \global
+ {\expandafter\let\csname#1\endcsname\undefined} % or use \undefinevalue to match \setvalue
+
+\unexpanded\def\localundefine#1% conditional
+ {\ifcsname#1\endcsname\expandafter\let\csname#1\endcsname\undefined\fi}
+
+\unexpanded\def\globalundefine#1% conditional
+ {\ifcsname#1\endcsname\expandafter\glet\csname#1\endcsname\undefined\fi}
+
+%D Beware, being \type {\undefined} in \ETEX\ means that the macro {\em is} defined!
+%D
+%D When we were developing the scientific units module, we encountered different
+%D behavior in text and math mode, which was due to this grouping subtilities. We
+%D therefore decided to use \type{\begingroup} instead of \type{\bgroup}.
+
+\unexpanded\def\doifelsealldefined#1%
+ {\begingroup
+ \donetrue % we could use a reserved one and avoid the group
+ \processcommalist[#1]\syst_helpers_do_if_all_defined_else
+ \ifdone
+ \endgroup\expandafter\firstoftwoarguments
+ \else
+ \endgroup\expandafter\secondoftwoarguments
+ \fi}
+
+\let\doifalldefinedelse\doifelsealldefined
+
+\def\syst_helpers_do_if_all_defined_else#1%
+ {\ifcsname#1\endcsname\else
+ \donefalse
+ \expandafter\quitcommalist % added
+ \fi}
+
+%D \macros
+%D {doif,doifelse,doifnot}
+%D
+%D Programming in \TEX\ differs from programming in procedural languages like
+%D \MODULA. This means that one --- well, let me speek for myself --- tries to do
+%D the things in the well known way. Therefore the next set of \type{\ifthenelse}
+%D commands were between the first ones we needed. A few years later, the opposite
+%D became true: when programming in \MODULA, I sometimes miss handy things like
+%D grouping, runtime redefinition, expansion etc. While \MODULA\ taught me to
+%D structure, \TEX\ taught me to think recursive.
+%D
+%D \starttyping
+%D \doif {string1} {string2} {...}
+%D \doifnot {string1} {string2} {...}
+%D \doifelse {string1} {string2} {then ...}{else ...}
+%D \stoptyping
+
+\unexpanded\def\doifelse#1#2%
+ {\iftok{#1}{#2}%
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\unexpanded\def\doif#1#2%
+ {\iftok{#1}{#2}%
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\unexpanded\def\doifnot#1#2%
+ {\iftok{#1}{#2}%
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+%D \macros
+%D {doifempty,doifemptyelse,doifnotempty}
+%D
+%D We complete our set of conditionals with:
+%D
+%D \starttyping
+%D \doifempty {string} {...}
+%D \doifnotempty {string} {...}
+%D \doifemptyelse {string} {then ...} {else ...}
+%D \stoptyping
+%D
+%D This time, the string is not expanded.
+
+\unexpanded\def\doifelseempty#1%
+ {\def\m_syst_string_one{#1}%
+ \ifx\m_syst_string_one\empty
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\let\doifemptyelse\doifelseempty
+
+\unexpanded\def\doifempty#1%
+ {\def\m_syst_string_one{#1}%
+ \ifx\m_syst_string_one\empty
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\unexpanded\def\doifnotempty#1%
+ {\def\m_syst_string_one{#1}%
+ \ifx\m_syst_string_one\empty
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+%D \macros
+%D {doifinset,doifnotinset,doifinsetelse}
+%D
+%D We can check if a string is present in a comma separated set of strings.
+%D Depending on the result, some action is taken.
+%D
+%D \starttyping
+%D \doifinset {string} {string,...} {...}
+%D \doifnotinset {string} {string,...} {...}
+%D \doifinsetelse {string} {string,...} {then ...} {else ...}
+%D \stoptyping
+
+% !0nop=\doifinsetelse{ccc}{,}{yes}{nop}
+% !0nop=\doifinsetelse{ccc}{,,}{yes}{nop}
+% !0nop=\doifinsetelse{ccc}{,,,}{yes}{nop}
+
+% !1nop=\doifinsetelse{}{}{yes}{nop}
+% !2yes=\doifinsetelse{aaa}{bbb,ccc,ddd,aaa,eee}{yes}{nop}
+% !3nop=\doifinsetelse{aaa}{bbb}{yes}{nop}
+% !4yes=\doifinsetelse{aaa}{aaa}{yes}{nop}
+% !5nop=\doifinsetelse{aaaa}{bbb,ccc,ddd,aaa,eee}{yes}{nop}
+% !6nop=\doifinsetelse{}{}{yes}{nop}
+% !7nop=\doifinsetelse{}{aaa}{yes}{nop}
+% !8nop=\doifinsetelse{aaa}{}{yes}{nop}
+
+% !1=\doifinset{}{}{yes}
+% !2yes=\doifinset{aaa}{bbb,ccc,ddd,aaa,eee}{yes}
+% !3=\doifinset{aaa}{bbb}{yes}
+% !4yes=\doifinset{aaa}{aaa}{yes}
+% !5=\doifinset{}{}{yes}
+% !6=\doifinset{aaa}{}{yes}
+
+% !1yes=\doifnotinset{}{}{yes}
+% !2=\doifnotinset{aaa}{bbb,ccc,ddd,aaa,eee}{yes}
+% !3yes=\doifnotinset{aaa}{bbb}{yes}
+% !4=\doifnotinset{aaa}{aaa}{yes}
+% !5yes=\doifnotinset{}{}{yes}
+% !6yes=\doifnotinset{aaa}{}{yes}
+
+\unexpanded\def\doifelseinset#1#2{\clf_doifelseinset{#1}{#2}}
+\unexpanded\def\doifinset #1#2{\clf_doifinset {#1}{#2}}
+\unexpanded\def\doifnotinset #1#2{\clf_doifnotinset {#1}{#2}}
+ % \let\firstinset \clf_firstinset
+
+\let\doifinsetelse\doifelseinset
+
+%D \macros
+%D {doifcommon,doifnotcommon,doifcommonelse}
+%D
+%D Probably the most time consuming tests are those that test for overlap in sets
+%D of strings.
+%D
+%D \starttyping
+%D \doifcommon {string,...} {string,...} {...}
+%D \doifnotcommon {string,...} {string,...} {...}
+%D \doifcommonelse {string,...} {string,...} {then ...} {else ...}
+%D \stoptyping
+
+% !1yes=\doifcommonelse{aaa,bbb,ccc}{aaa,bbb,ccc}{yes}{nop}
+% !2nop=\doifcommonelse{aaa,bbb,ccc}{ddd,eee,fff}{yes}{nop}
+% !3nop=\doifcommonelse{aaa}{ddd,eee,fff}{yes}{nop}
+% !4yes=\doifcommonelse{aaa}{aaa}{yes}{nop}
+% !5nop=\doifcommonelse{bbb}{aaa}{yes}{nop}
+% !6nop=\doifcommonelse{}{aaa,bbb,ccc}{yes}{nop}
+% !7nop=\doifcommonelse{aaa,bbb,ccc}{}{yes}{nop}
+% !8nop=\doifcommonelse{}{}{yes}{nop}
+
+% !9nop=\doifcommonelse{,,}{,,}{yes}{nop}
+% !9yes=\doifcommonelse{,a,}{,a,}{yes}{nop}
+% !9yes=\doifcommonelse{,,a,}{,a,}{yes}{nop}
+% !9yes=\doifcommonelse{,a,}{,,a,}{yes}{nop}
+% !9yes=\doifcommonelse{,a,}{,,,a,}{yes}{nop}
+% !9yes=\doifcommonelse{,,a,}{,,,a,}{yes}{nop}
+
+\unexpanded\def\doifelsecommon#1#2{\clf_doifelsecommon{#1}{#2}}
+\unexpanded\def\doifcommon #1#2{\clf_doifcommon {#1}{#2}}
+\unexpanded\def\doifnotcommon #1#2{\clf_doifnotcommon {#1}{#2}}
+
+\let\doifcommonelse\doifelsecommon
+
+%D \macros
+%D {processcommalist,processcommacommand,quitcommalist,
+%D processcommalistwithparameters}
+%D
+%D We've already seen some macros that take care of comma separated lists. Such
+%D list can be processed with
+%D
+%D \starttyping
+%D \processcommalist[string,string,...]\commando
+%D \stoptyping
+%D
+%D The user supplied command \type{\commando} receives one argument: the string.
+%D This command permits nesting and spaces after commas are skipped. Empty sets
+%D are no problem.
+%D
+%D \startbuffer
+%D \def\dosomething#1{(#1)}
+%D
+%D 1: \processcommalist [\hbox{$a,b,c,d,e,f$}] \dosomething \par
+%D 2: \processcommalist [{a,b,c,d,e,f}] \dosomething \par
+%D 3: \processcommalist [{a,b,c},d,e,f] \dosomething \par
+%D 4: \processcommalist [a,b,{c,d,e},f] \dosomething \par
+%D 5: \processcommalist [a{b,c},d,e,f] \dosomething \par
+%D 6: \processcommalist [{a,b}c,d,e,f] \dosomething \par
+%D 7: \processcommalist [] \dosomething \par
+%D 8: \processcommalist [{[}] \dosomething \par
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D Before we show the result, we present the macro's:
+
+\newcount\commalevel
+
+\installsystemnamespace{nextcommalevel}
+
+\def\syst_helpers_do_do_do_process_comma_item
+ {\csname\??nextcommalevel\the\commalevel\endcsname}
+
+% \ifcase\contextlmtxmode
+
+ \def\syst_helpers_do_process_comma_item
+ {\futurelet\nexttoken\syst_helpers_do_do_process_comma_item}
+
+ \def\syst_helpers_do_do_process_comma_item
+ {\ifx\nexttoken\blankspace
+ \expandafter\syst_helpers_re_do_process_comma_item
+ \else
+ \expandafter\syst_helpers_do_do_process_comma_item_indeed
+ \fi}
+
+ \def\syst_helpers_do_do_process_comma_item_indeed
+ {\ifx\nexttoken]%
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\syst_helpers_do_do_do_process_comma_item
+ \fi}
+
+% \else
+%
+% \def\syst_helpers_do_process_comma_item
+% {\futureexpandis]\gobbleoneargument\syst_helpers_do_do_do_process_comma_item}
+%
+% \fi
+
+%D Empty arguments are not processed. Empty items (\type {,,}) however are
+%D treated. We have to check for the special case \type {[{a,b,c}]}.
+
+\unexpanded\def\processcommalist[%
+ {\futurelet\nexttoken\syst_helpers_do_check_comma_item}
+
+\def\syst_helpers_do_check_comma_item
+ {\ifx\nexttoken]%
+ \expandafter\gobblethreearguments
+ \else
+ \expandafter\syst_helpers_do_process_comma_list
+ \fi
+ \relax} % this one preserved the next {}
+
+\def\syst_helpers_do_process_comma_list#1]#2%
+ {\global\advance\commalevel \plusone
+ \expandafter\def\csname\??nextcommalevel\the\commalevel\endcsname##1,%
+ {#2{##1}\syst_helpers_do_process_comma_item}%
+ \syst_helpers_do_do_process_comma_item_gobble#1,]\relax
+ \global\advance\commalevel \minusone }
+
+\def\syst_helpers_do_do_process_comma_item_gobble#1{\syst_helpers_do_do_process_comma_item}
+
+%D One way of quitting a commalist halfway is:
+
+\unexpanded\def\quitcommalist
+ {\begingroup\let\syst_helpers_do_process_comma_item\syst_helpers_do_quit_comma_list}
+
+\def\syst_helpers_do_quit_comma_list#1]%
+ {\endgroup}
+
+\unexpanded\def\quitprevcommalist
+ {\begingroup\let\syst_helpers_do_process_comma_item\syst_helpers_do_quit_prev_comma_list}
+
+\def\syst_helpers_do_quit_prev_comma_list#1]%
+ {\let\syst_helpers_do_process_comma_item\syst_helpers_do_quit_comma_list}
+
+%D The hack we used for checking the next character \type {\doifnextcharelse}
+%D is also used here.
+
+% \ifcase\contextlmtxmode
+
+ \let\next\:
+
+ \def\:{\syst_helpers_re_do_process_comma_item} % \:not saved ?
+
+ \expandafter\def\: {\futurelet\nexttoken\syst_helpers_do_do_process_comma_item}
+
+ \let\:\next
+
+% \fi
+
+%D The previous examples lead to:
+%D
+%D \getbuffer
+
+%D When a list is saved in a macro, we can use a construction like:
+%D
+%D \starttyping
+%D \expandafter\processcommalist\expandafter[\list]\command
+%D \stoptyping
+%D
+%D Such solutions suit most situations, but we wanted a bit more.
+%D
+%D \starttyping
+%D \processcommacommand[string,\stringset,string]\commando
+%D \stoptyping
+%D
+%D where \type{\stringset} is a predefined set, like:
+%D
+%D \starttyping
+%D \def\first{aap,noot,mies}
+%D \def\second{laatste}
+%D
+%D \processcommacommand[\first]\message
+%D \processcommacommand[\first,second,third]\message
+%D \processcommacommand[\first,between,\second]\message
+%D \stoptyping
+%D
+%D Commands that are part of the list are expanded, so the use of this macro has its
+%D limits.
+
+\unexpanded\def\processcommacommand[#1]%
+ {\normalexpanded{\processcommalist[#1]}}
+
+%D The argument to \type{\command} is not delimited. Because we often use \type {[]}
+%D as delimiters, we also have:
+%D
+%D \starttyping
+%D \processcommalistwithparameters[string,string,...]\command
+%D \stoptyping
+%D
+%D where \type{\command} looks like:
+%D
+%D \starttyping
+%D \def\command[#1]{... #1 ...}
+%D \stoptyping
+
+\unexpanded\def\processcommalistwithparameters[#1]#2%
+ {\def\syst_helpers_do_process_comma_list_with_parameters##1{#2[##1]}%
+ \processcommalist[#1]\syst_helpers_do_process_comma_list_with_parameters}
+
+%D \macros
+%D {startprocesscommalist,startprocesscommacommand}
+%D
+%D Two more:
+
+\let\syst_helpers_comma_list_step\relax
+
+\unexpanded\def\startprocesscommalist[#1]#2\stopprocesscommalist
+ {\def\syst_helpers_comma_list_step##1{\def\currentcommalistitem{##1}#2}%
+ \processcommalist[#1]\syst_helpers_comma_list_step}
+
+\unexpanded\def\startprocesscommacommand[#1]#2\stopprocesscommacommand
+ {\def\syst_helpers_comma_list_step##1{\def\currentcommalistitem{##1}#2}%
+ \normalexpanded{\processcommalist[#1]}\syst_helpers_comma_list_step}
+
+\let\stopprocesscommalist \relax
+\let\stopprocesscommacommand\relax
+
+%D \macros
+%D {processaction,
+%D processfirstactioninset,
+%D processallactionsinset}
+%D
+%D \CONTEXT\ makes extensive use of a sort of case or switch command. Depending of
+%D the presence of one or more provided items, some actions is taken. These macros
+%D can be nested without problems.
+%D
+%D \starttyping
+%D \processaction [x] [a=>\a,b=>\b,c=>\c]
+%D \processfirstactioninset [x,y,z] [a=>\a,b=>\b,c=>\c]
+%D \processallactionsinset [x,y,z] [a=>\a,b=>\b,c=>\c]
+%D \stoptyping
+%D
+%D We can supply both a \type {default} action and an action to be undertaken when
+%D an \type {unknown} value is met:
+%D
+%D \starttyping
+%D \processallactionsinset
+%D [x,y,z]
+%D [ a=>\a,
+%D b=>\b,
+%D c=>\c,
+%D default=>\default,
+%D unknown=>\unknown{... \commalistelement ...}]
+%D \stoptyping
+%D
+%D When \type {#1} is empty, this macro scans list \type {#2} for the keyword \type
+%D {default} and executed the related action if present. When \type {#1} is non
+%D empty and not in the list, the action related to \type {unknown} is executed.
+%D Both keywords must be at the end of list \type{#2}. Afterwards, the actually
+%D found keyword is available in \type {\commalistelement}. An advanced example of
+%D the use of this macro can be found in \PPCHTEX, where we completely rely on \TEX\
+%D for interpreting user supplied keywords like \type {SB}, \type {SB1..6}, \type
+%D {SB125} etc.
+
+\newcount\processlevel
+
+\unexpanded\def\syst_helpers_do_compare_process_action_a[#1=>#2][#3]%
+ {\edef\m_syst_string_two{#1}%
+ \ifx\m_syst_string_two\s!default
+ \let\commalistelement\empty
+ #2%
+ \fi}
+
+% met \quitcommalist tot meer dan 25\% sneller
+
+\unexpanded\def\syst_helpers_do_compare_process_action_b[#1=>#2][#3]%
+ {\edef\m_syst_string_two{#1}%
+ \ifx\m_syst_string_one\m_syst_string_two
+ \def\commalistelement{#3}%
+ #2%
+ \expandafter\quitcommalist
+ \orelse\ifx\m_syst_string_two\s!unknown
+ \def\commalistelement{#3}% beware of loops
+ #2%
+ \fi}
+
+\unexpanded\def\processaction[#1]#2[%
+ {\edef\m_syst_string_one{#1}%
+ \ifx\m_syst_string_one\empty
+ \let\syst_helpers_do_compare_process_action\syst_helpers_do_compare_process_action_a
+ \else
+ \let\syst_helpers_do_compare_process_action\syst_helpers_do_compare_process_action_b
+ \fi
+ \edef\syst_helpers_do_process_action##1{\syst_helpers_do_compare_process_action[##1][#1]}% expands #1
+ \processnextcommalist\relax\relax\syst_helpers_do_process_action[}
+
+\unexpanded\def\syst_helpers_do_compare_process_action_c[#1=>#2][#3]%
+ {\edef\m_syst_string_one{#1}%
+ \edef\m_syst_string_two{#3}%
+ \ifx\m_syst_string_one\m_syst_string_two
+ \def\commalistelement{#3}%
+ #2%
+ \expandafter\quitprevcommalist
+ \else
+ \edef\m_syst_string_one{#1}%
+ \ifx\m_syst_string_one\s!unknown
+ \def\commalistelement{#3}%
+ #2%
+ \fi
+ \fi}
+
+\unexpanded\def\processfirstactioninset[#1]%
+ {\edef\m_syst_string_one{#1}%
+ \ifx\m_syst_string_one\empty
+ \expandafter\processaction
+ \else
+ \expandafter\syst_helpers_process_first_action_in_set_indeed
+ \fi
+ [#1]}
+
+\unexpanded\def\syst_helpers_process_first_action_in_set_indeed[#1]#2[#3]%
+ {\def\syst_helpers_do_process_action##1%
+ {\def\syst_helpers_do_do_process_action####1{\syst_helpers_do_compare_process_action_c[####1][##1]}%
+ \processcommalist[#3]\syst_helpers_do_do_process_action}%
+ \normalexpanded{\processcommalist[#1]}\syst_helpers_do_process_action}
+
+\unexpanded\def\syst_helpers_do_compare_process_action_d[#1=>#2][#3]%
+ {\edef\m_syst_string_one{#1}%
+ \edef\m_syst_string_two{#3}%
+ \ifx\m_syst_string_one\m_syst_string_two
+ \def\commalistelement{#3}%
+ #2%
+ \expandafter\quitcommalist
+ \else
+ \edef\m_syst_string_one{#1}%
+ \ifx\m_syst_string_one\s!unknown
+ \def\commalistelement{#3}%
+ #2%
+ \fi
+ \fi}
+
+\installsystemnamespace{nextactionlevel}
+
+\unexpanded\def\syst_helpers_do_process_all_actions_in_set
+ {\csname\??nextactionlevel\the\processlevel\endcsname}
+
+\unexpanded\def\processallactionsinset[#1]%
+ {\edef\m_syst_string_one{#1}%
+ \ifx\m_syst_string_one\empty
+ \expandafter\processaction
+ \else
+ \expandafter\syst_helpers_process_all_actions_in_set_indeed
+ \fi
+ [#1]}
+
+\unexpanded\def\syst_helpers_process_all_actions_in_set_indeed[#1]#2[#3]%
+ {\advance\processlevel \plusone
+ \expandafter\def\csname\??nextactionlevel\the\processlevel\endcsname##1%
+ {\def\syst_helpers_do_do_process_action####1{\syst_helpers_do_compare_process_action_d[####1][##1]}%
+ \processcommalist[#3]\syst_helpers_do_do_process_action}%
+ \normalexpanded{\processcommalist[#1]}\syst_helpers_do_process_all_actions_in_set
+ \advance\processlevel\minusone}
+
+%D These macros use:
+
+\unexpanded\def\processnextcommalist#1#2#3[#4#5]%
+ {#1%
+ \let\nexttoken#4%
+ \global\advance\commalevel \plusone
+ \expandafter\def\csname\??nextcommalevel\the\commalevel\endcsname##1,%
+ {#3{##1}\syst_helpers_do_process_comma_item}%
+ \syst_helpers_do_do_process_comma_item#4#5,]\relax
+ \global\advance\commalevel\minusone
+ #2}
+
+%D \macros
+%D {getfirstcharacter, firstcharacter, remainingcharacters, doiffirstcharacter}
+%D
+%D Sometimes the action to be undertaken depends on the next character. This macro
+%D get this character and puts it in \type {\firstcharacter}.
+%D
+%D \starttyping
+%D \getfirstcharacter {string}
+%D \stoptyping
+%D
+%D A two step expansion is used to prevent problems with complicated arguments, for
+%D instance arguments that consist of two or more expandable tokens.
+
+\let\firstcharacter \empty
+\let\remainingcharacters\empty
+
+\unexpanded\def\getfirstcharacter #1{\clf_getfirstcharacter{#1}}
+\unexpanded\def\doifelsefirstchar #1#2{\clf_doifelsefirstchar{#1}{#2}}
+\unexpanded\def\thefirstcharacter #1{\clf_thefirstcharacter{#1}}
+\unexpanded\def\theremainingcharacters#1{\clf_theremainingcharacters{#1}}
+
+\let\doiffirstcharelse\doifelsefirstchar
+
+%D \macros
+%D {doifinstringelse, doifincsnameelse}
+%D
+%D We can check for the presence of a substring in a given sequence of characters.
+%D
+%D \starttyping
+%D \doifinsetelse {substring} {string} {then ...} {else ...}
+%D \stoptyping
+
+\let\m_syst_sub_string\empty
+
+\unexpanded\def\doifelseinstring#1%
+ {\edef\m_syst_sub_string{#1}% expand #1 here
+ \ifx\m_syst_sub_string\empty
+ \expandafter\thirdofthreearguments
+ \else
+ \expandafter\syst_helpers_do_if_in_string_else_indeed
+ \fi}
+
+\let\doifinstringelse\doifelseinstring
+
+\unexpanded\def\syst_helpers_do_if_in_string_else_indeed#1%
+ {\syst_helpers_do_if_in_string_else\m_syst_sub_string{#1}%
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\unexpanded\def\doifinstring#1%%
+ {\edef\m_syst_sub_string{#1}% expand #1 here
+ \ifx\m_syst_sub_string\empty
+ \expandafter\gobbletwoarguments
+ \else
+ \expandafter\syst_helpers_do_if_in_string_indeed
+ \fi}
+
+\unexpanded\def\syst_helpers_do_if_in_string_indeed#1%
+ {\syst_helpers_do_if_in_string_else\m_syst_sub_string{#1}%
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\unexpanded\def\doifnotinstring#1%%
+ {\edef\m_syst_sub_string{#1}% expand #1 here
+ \ifx\m_syst_sub_string\empty
+ \expandafter\gobbletwoarguments
+ \else
+ \expandafter\syst_helpers_do_if_not_in_string_indeed
+ \fi}
+
+\unexpanded\def\syst_helpers_do_if_not_in_string_indeed#1%
+ {\syst_helpers_do_if_in_string_else\m_syst_sub_string{#1}%
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+% replaces prev
+
+\unexpanded\def\syst_helpers_do_if_in_string_else#1#2% ##2 can be {abc}
+ {\expandafter\def\expandafter\syst_helpers_do_do_if_in_string_else
+ \expandafter##\expandafter1#1##2##3^^^^0004{\unless\if##2@}% expand #1 here
+ \expandafter\syst_helpers_do_do_if_in_string_else\normalexpanded{#2#1}@@^^^^0004} % expand #2 here
+
+%D The next alternative proved to be upto twice as fast on tasks like checking
+%D reserved words in pretty verbatim typesetting! This is mainly due to the fact
+%D that passing (expanded) strings is much slower that passing a macro.
+%D
+%D \starttyping
+%D \doifincsnameelse {substring} {\string} {then ...} {else ...}
+%D \stoptyping
+%D
+%D Where \type {\doifinstringelse} does as much expansion as possible, the latter
+%D alternative does minimal (one level) expansion.
+
+\unexpanded\def\syst_helpers_do_if_in_csname_else#1#2%
+ {\def\syst_helpers_do_do_if_in_csname_else##1#1##2##3^^^^0004%
+ {\unless\if##2@}%
+ \expandafter\syst_helpers_do_do_if_in_csname_else#2#1@@^^^^0004}
+
+\unexpanded\def\doifelseincsname#1#2%
+ {\normalexpanded{\syst_helpers_do_if_in_csname_else{#1}}{#2}%
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\let\doifincsnameelse\doifelseincsname
+
+%D \macros
+%D {doifnumberelse,doifnumber,doifnotnumber}
+%D
+%D The next macro executes a command depending of the outcome of a test on numerals.
+%D This is probably one of the fastest test possible, exept from a less robust
+%D 10||step \type {\if}||ladder or some tricky \type {\lcode} checking.
+%D
+%D \starttyping
+%D \doifnumberelse {string} {then ...} {else ...}
+%D \stoptyping
+%D
+%D The macro accepts \type {123}, \type {abc}, \type {{}}, \type {\getal} and \type
+%D {\the\count...}. This macro is a rather dirty one.
+
+\def\doifelsenumber#1%
+ {\ifchknum#1\or
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\def\doifnumber#1%
+ {\ifchknum#1\or
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\def\doifnotnumber#1%
+ {\ifchknum#1\or
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+\let\doifnumberelse\doifelsenumber
+
+%D \macros
+%D {setpercentdimen}
+%D
+%D \starttyping
+%D \scratchdimen=100pt \setpercentdimen\scratchdimen{10\letterpercent}
+%D \scratchdimen=100pt \setpercentdimen\scratchdimen{5pt}
+%D \scratchdimen \percentdimen \hsize {10\letterpercent}
+%D \stoptyping
+
+\def\percentdimen#1#2% dimen percentage (with %)
+ {\dimexpr\clf_percentageof{#2}\dimexpr#1\relax}
+
+\unexpanded\def\setpercentdimen#1#2% dimen percentage (with %)
+ {#1=\clf_percentageof{#2}\dimexpr#1\relax}
+
+%D \macros
+%D {makerawcommalist,
+%D rawdoinsetelse,
+%D rawprocesscommalist,
+%D rawprocessaction}
+%D
+%D Some of the commands mentioned earlier are effective but slow. When one is
+%D desperately in need of faster alternatives and when the conditions are
+%D predictable safe, the \type {\raw} alternatives come into focus. A major drawback
+%D is that they do not take \type {\c!constants} into account, simply because no
+%D expansion is done. This is no problem with \type {\rawprocesscommalist}, because
+%D this macro does not compare anything. Expandable macros are permitted as search
+%D string.
+%D
+%D \starttyping
+%D \makerawcommalist[string,string,...]\stringlist
+%D \rawdoifelseinset{string}{string,...}{...}{...}
+%D \rawprocesscommalist[string,string,...]\commando
+%D \rawprocessaction[x][a=>\a,b=>\b,c=>\c]
+%D \stoptyping
+%D
+%D Spaces embedded in the list, for instance after commas, spoil the search process.
+%D The gain in speed depends on the length of the argument (the longer the argument,
+%D the less we gain).
+
+\unexpanded\def\makerawcommalist[#1]#2% use \processnext ... here
+ {\def\syst_helpers_do_make_raw_comma_list##1% we don't expand ##1
+ {\ifx#2\empty
+ \def#2{##1}%
+ \else
+ \expandafter\def\expandafter#2\expandafter{#2,##1}%
+ \fi}%
+ \let#2\empty
+ \processcommalist[#1]\syst_helpers_do_make_raw_comma_list}
+
+\def\syst_helpers_raw_process_comma_item#1,#2% #2 eats up preceding space
+ {\if]#1\else
+ \csname\??nextcommalevel\the\commalevel\endcsname{#1}%
+ \expandafter\syst_helpers_raw_process_comma_item
+ \fi#2}
+
+\unexpanded\def\rawprocesscommalist[#1]#2% accepteert ook [\cs]
+ {\global\advance\commalevel \plusone
+ \expandafter\let\csname\??nextcommalevel\the\commalevel\endcsname#2%
+ \expandafter\syst_helpers_raw_process_comma_item#1,],% \relax
+ \global\advance\commalevel \minusone }
+
+\unexpanded\def\rawprocesscommacommand[#1]% not really needed
+ {\normalexpanded{\rawprocesscommalist[#1]}}
+
+%D Here is one without nesting:
+
+\unexpanded\def\syst_helpers_fast_process_comma_item#1,#2% #2 eats up preceding space
+ {\if]#1\else
+ \syst_helpers_fast_process_comma_command{#1}%
+ \expandafter\syst_helpers_fast_process_comma_item
+ \fi#2}
+
+\unexpanded\def\fastprocesscommalist[#1]#2% accepteert ook [\cs]
+ {\let\syst_helpers_fast_process_comma_command#2%
+ \expandafter\syst_helpers_fast_process_comma_item#1,],}% \relax
+
+\unexpanded\def\fastprocesscommacommand[#1]#2% accepteert ook [\cs]
+ {\let\syst_helpers_fast_process_comma_command#2%
+ \normalexpanded{\syst_helpers_fast_process_comma_item#1},],}% \relax
+
+% \def\rawdoifelseinset#1#2{\doifinstringelse{,#1,}{,#2,}}
+% \def\rawdoifinset #1#2{\doifinstring {,#1,}{,#2,}}
+
+\def\m_syst_two_commas{,,}
+
+\unexpanded\def\rawdoifelseinset#1%
+ {\edef\m_syst_sub_string{,#1,}% expand #1 here
+ \ifx\m_syst_sub_string\m_syst_two_commas
+ \expandafter\thirdofthreearguments
+ \else
+ \expandafter\syst_helpers_raw_do_if_in_set_else
+ \fi}
+
+\let\rawdoifinsetelse\rawdoifinsetelse
+
+\unexpanded\def\syst_helpers_raw_do_if_in_set_else#1%
+ {\syst_helpers_do_if_in_string_else\m_syst_sub_string{,#1,}%
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\unexpanded\def\rawdoifinset#1%
+ {\edef\m_syst_sub_string{,#1,}% expand #1 here
+ \ifx\m_syst_sub_string\m_syst_two_commas
+ \expandafter\gobbletwoarguments
+ \else
+ \expandafter\syst_helpers_raw_do_if_in_set
+ \fi}
+
+\unexpanded\def\syst_helpers_raw_do_if_in_set#1%%
+ {\syst_helpers_do_if_in_string_else\m_syst_sub_string{,#1,}%
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+%D Some more raw material:
+
+\def\syst_helpers_do_raw_process_action[#1][#2]%
+ {\def\syst_helpers_do_do_raw_process_action##1,#1=>##2,##3^^^^0004%
+ {\if##3@\else
+ \def\m_syst_helpers_process_action{##2}%
+ \fi}%
+ \syst_helpers_do_do_raw_process_action,#2,#1=>,@^^^^0004}
+
+\unexpanded\def\rawprocessaction[#1]#2[#3]%
+ {\edef\m_syst_string_one{#1}%
+ \edef\m_syst_string_two{undefined}% better \!!undefined
+ \let\m_syst_helpers_process_action\m_syst_string_two
+ \ifx\m_syst_string_one\empty
+ \expandafter\syst_helpers_do_raw_process_action\expandafter[\s!default][#3]%
+ \else
+ \expandafter\syst_helpers_do_raw_process_action\expandafter[\m_syst_string_one][#3]%
+ \ifx\m_syst_helpers_process_action\m_syst_string_two
+ \expandafter\syst_helpers_do_raw_process_action\expandafter[\s!unknown][#3]%
+ \fi
+ \fi
+ \ifx\m_syst_helpers_process_action\m_syst_string_two
+ \else
+ \m_syst_helpers_process_action
+ \fi}
+
+%D When we process the list \type {a,b,c,d,e}, the raw routine takes over 30\% less
+%D time, when we feed $20+$ character strings we gain about 20\%. Alternatives which
+%D use \type {\futurelet} perform worse. Part of the speedup is due to the \type
+%D {\let} and \type {\expandafter} in the test.
+%D
+%D \macros
+%D {dosetvalue,dosetevalue,dosetgvalue,docopyvalue,doresetvalue,
+%D dogetvalue}
+%D
+%D When we are going to do assignments, we have to take multi||linguality into account.
+%D For the moment we keep things simple and single||lingual.
+%D
+%D \starttyping
+%D \dosetvalue {label} {variable} {value}
+%D \dosetevalue {label} {variable} {value}
+%D \dosetgvalue {label} {variable} {value}
+%D \docopyvalue {to label} {from label} {variable}
+%D \doresetvalue {label} {variable}
+%D \stoptyping
+%D
+%D These macros are in fact auxiliary ones and are not meant for use outside the
+%D assignment macros.
+
+\def\dosetvalue#1#2% #3
+ {\expandafter\def\csname#1#2\endcsname} % {#3}}
+
+\def\dosetevalue#1#2% #3
+ {\expandafter\edef\csname#1#2\endcsname} % {#3}}
+
+\def\dosetgvalue#1#2% #3
+ {\expandafter\gdef\csname#1#2\endcsname} % {#3}}
+
+\def\doresetvalue#1#2%
+ {\expandafter\let\csname#1#2\endcsname\empty}
+
+\def\doignorevalue#1#2#3%
+ {\expandafter\let\csname#1#2\endcsname\empty}
+
+\def\docopyvalue#1#2#3%
+ {\expandafter\def\csname#1#3\endcsname{\csname#2#3\endcsname}}
+
+%D \macros
+%D {doassign,undoassign,doassignempty}
+%D
+%D Assignments are the backbone of \CONTEXT. Abhorred by the concept of style file
+%D hacking, we took a considerable effort in building a parameterized system.
+%D Unfortunately there is a price to pay in terms of speed. Compared to other
+%D packages and taking the functionality of \CONTEXT\ into account, the total size
+%D of the format file is still very acceptable. Now how are these assignments done.
+%D
+%D Assignments can be realized with:
+%D
+%D \starttyping
+%D \doassign[label][variable=value]
+%D \undoassign[label][variable=value]
+%D \stoptyping
+%D
+%D and:
+%D
+%D \starttyping
+%D \doassignempty[label][variable=value]
+%D \stoptyping
+%D
+%D Assignments like \type{\doassign} are compatible with:
+%D
+%D \starttyping
+%D \def\labelvariable{value}
+%D \stoptyping
+%D
+%D We do check for the presence of an \type{=} and loudly complain of it's missed. We
+%D will redefine this macro later on, when a more advanced message mechanism is
+%D implemented.
+
+\unexpanded\def\showassignerror#1#2%
+ {\writestatus{setup}{missing or ungrouped '=' after '#1' in line #2}}
+
+\unexpanded\def\doassignempty[#1][#2=#3]%
+ {\ifcsname#1#2\endcsname\else\dosetvalue{#1}{#2}{#3}\fi}
+
+%D \macros
+%D {getparameters,geteparameters,getgparameters,
+%D forgetparameters}
+%D
+%D Using the assignment commands directly is not our ideal of user friendly interfacing,
+%D so we take some further steps.
+%D
+%D \starttyping
+%D \getparameters [label] [...=...,...=...]
+%D \forgetparameters [label] [...=...,...=...]
+%D \stoptyping
+%D
+%D Again, the label identifies the category a variable belongs to. The second argument
+%D can be a comma separated list of assignments.
+%D
+%D \starttyping
+%D \getparameters
+%D [demo]
+%D [alfa=1,
+%D beta=2]
+%D \stoptyping
+%D
+%D is equivalent to
+%D
+%D \starttyping
+%D \def\demoalfa{1}
+%D \def\demobeta{2}
+%D \stoptyping
+%D
+%D
+%D In the pre||multi||lingual stadium \CONTEXT\ took the next approach. With
+%D
+%D \starttyping
+%D \def\??demo {@@demo}
+%D \def\!!alfa {alfa}
+%D \def\!!beta {beta}
+%D \stoptyping
+%D
+%D calling
+%D
+%D \starttyping
+%D \getparameters
+%D [\??demo]
+%D [\!!alfa=1,
+%D \!!beta=2]
+%D \stoptyping
+%D
+%D lead to:
+%D
+%D \starttyping
+%D \def\@@demoalfa{1}
+%D \def\@@demobeta{2}
+%D \stoptyping
+%D
+%D Because we want to be able to distinguish the \type{!!} pre||tagged user supplied
+%D variables from internal counterparts, we will introduce a slightly different tag
+%D in the multi||lingual modules. There we will use \type{c!} or \type{v!},
+%D depending on the context.
+%D
+%D By calling \type{doassign} directly, we save ourselves some argument passing
+%D and gain some speed. Whatever optimizations we do, this command will always be
+%D one of the bigger bottlenecks. The alternative \type{\geteparameters} --- it's
+%D funny to see that this alternative saw the light so lately --- can be used to do
+%D expanded assigments.
+
+\let\currentvalue\empty
+
+\unexpanded\def\getparameters {\dogetparameters\dosetvalue}
+\unexpanded\def\geteparameters {\dogetparameters\dosetevalue}
+\unexpanded\def\getgparameters {\dogetparameters\dosetgvalue}
+\unexpanded\def\getxparameters {\dogetparameters\dosetxvalue}
+\unexpanded\def\forgetparameters{\dogetparameters\doignorevalue}
+
+\let\getexpandedparameters\geteparameters
+
+\unexpanded\def\dogetparameters#1[#2]#3[#4%
+ {\if\noexpand#4]%
+ \expandafter\gobbleoneargument
+ \else
+ \let\setsomevalue#1%
+ \def\syst_helpers_get_parameters_assign{\syst_helpers_get_parameters_assign_indeed#2}%
+ \expandafter\syst_helpers_get_parameters
+ \fi#4}
+
+\def\syst_helpers_get_parameters#1]%
+ {\xprocesscommaitem#1,],^^^^0004}
+
+\def\syst_helpers_process_comma_item#1,#2% #2 takes space before ,
+ {\if,#1,% dirty trick for testing #1=empty
+ \expandafter\syst_helpers_process_comma_item
+ \orelse\if]#1%
+ \expandafter\gobbleoneargument
+ \else
+ \syst_helpers_get_parameters_assign^^^^0004#1==\empty^^^^0004%
+ \expandafter\syst_helpers_process_comma_item
+ \fi#2}
+
+\def\syst_helpers_assign_error#1#2#3%
+ {\showassignerror{#2}{\the\inputlineno\space(#1)}}
+
+\def\syst_helpers_get_parameters_assign_normal#1^^^^0004#2=#3=#4#5^^^^0004%
+ {\ifx\empty#2\empty
+ \expandafter\syst_helpers_assign_error
+ \orelse\ifx#4\empty
+ \expandafter\syst_helpers_assign_error
+ \else
+ \expandafter\setsomevalue
+ \fi
+ {#1}{#2}{#3}}
+
+\def\syst_helpers_get_parameters_assign_error#1^^^^0004#2=#3=#4#5^^^^0004%
+ {\ifx\empty#2\empty
+ \expandafter\syst_helpers_assign_error
+ \orelse\ifx#4\empty
+ \expandafter\syst_helpers_assign_error
+ \orelse\ifcsname#1#2\endcsname
+ \expandafter\let\expandafter\currentvalue\csname#1#2\endcsname
+ \expandafter\setsomevalue
+ \else
+ \let\currentvalue\empty
+ \expandafter\setsomevalue
+ \fi
+ {#1}{#2}{#3}}
+
+\let\syst_helpers_get_parameters_assign_indeed\syst_helpers_get_parameters_assign_normal
+
+\unexpanded\def\doassign [#1][#2]{\let\setsomevalue\dosetvalue \syst_helpers_get_parameters_assign_indeed#1^^^^0004#2==\empty^^^^0004}
+\unexpanded\def\doeassign [#1][#2]{\let\setsomevalue\dosetevalue \syst_helpers_get_parameters_assign_indeed#1^^^^0004#2==\empty^^^^0004}
+\unexpanded\def\undoassign[#1][#2]{\let\setsomevalue\doresetvalue\syst_helpers_get_parameters_assign_indeed#1^^^^0004#2==\empty^^^^0004}
+
+%D \macros
+%D {processassignmentlist,processassignmentcommand,
+%D startprocessassignmentlist,startprocessassignmentcommand}
+%D
+%D For Wolfgang:
+%D
+%D \starttyping
+%D \def\showpair#1#2{key:#1, value:#2\par}
+%D \processassignmentlist[a=1,b=2]\showpair
+%D \stoptyping
+%D
+%D We can optimize this one if needed but it's not a core macro so hardly worth the
+%D trouble and tokens.
+
+\unexpanded\def\processassignmentlist[#1]#2% #2 == \command{key}{value]
+ {\def\syst_helpers_process_assignment_entry##1{#2}% {##2}{##3} % namespace is ignored
+ \dogetparameters\syst_helpers_process_assignment_entry[][#1]}
+
+\unexpanded\def\processassignmentcommand[#1]%
+ {\normalexpanded{\processassignmentlist[#1]}}
+
+\unexpanded\def\startprocessassignmentlist[#1]#2\stopprocessassignmentlist
+ {\def\currentassignmentlistcommand##1##2{\def\currentassignmentlistkey{##1}\def\currentassignmentlistvalue{##2}#2}%
+ \processassignmentlist[#1]\currentassignmentlistcommand}
+
+\unexpanded\def\startprocessassignmentcommand[#1]#2\stopprocessassignmentcommand
+ {\def\currentassignmentlistcommand##1##2{\def\currentassignmentlistkey{##1}\def\currentassignmentlistvalue{##2}#2}%
+ \normalexpanded{\processassignmentlist[#1]}\currentassignmentlistcommand}
+
+%D \macros{currentvalue}
+%D
+%D Just in case a \type{\getparameter} argument itself ends up inside a \type
+%D {\write} or other expandable location, our new macro needs a default value.
+%D
+%D \starttyping
+%D \getparameters[xxx][aaa=bbb]\par
+%D \getparameters[xxx][=bbb]\par
+%D \getparameters[xxx][aaa=]\par
+%D \getparameters[xxx][=]\par
+%D \getparameters[xxx][aaa]\par
+%D \stoptyping
+
+%D \macros
+%D {expandparameters}
+%D
+%D Example usage:
+%D
+%D \startbuffer
+%D \getparameters[taco][name=taco]
+%D \convertcommand\taconame\to\ascii \ascii
+%D \expandparameters \getparameters[taco][name=\currentvalue\space hoekwater]
+%D \convertcommand\taconame\to\ascii \ascii
+%D \getparameters[taco][name=\currentvalue\space hoekwater]
+%D \convertcommand\taconame\to\ascii \ascii
+%D \stopbuffer
+%D
+%D \typebuffer
+%D \startlines
+%D \getbuffer
+%D \stoplines
+%D
+%D Here we hook in the code (beware, this is the optimized get **):
+
+\def\syst_helpers_get_parameters_normal#1]%
+ {\syst_helpers_process_comma_item#1,],^^^^0004}
+
+\def\syst_helpers_get_parameters_expanded#1]%
+ {\let\dosetnvalue\setsomevalue
+ \let\setsomevalue\dosetevalue
+ \let\syst_helpers_get_parameters_assign_indeed\syst_helpers_get_parameters_assign_error
+ \let\setsomevalue\dosetevalue
+ \syst_helpers_process_comma_item#1,],^^^^0004%
+ \let\syst_helpers_get_parameters_assign_indeed\syst_helpers_get_parameters_assign_normal
+ \let\setsomevalue\dosetnvalue
+ \let\syst_helpers_get_parameters\syst_helpers_get_parameters_normal
+ \let\currentvalue\empty}
+
+\let\syst_helpers_get_parameters\syst_helpers_get_parameters_normal % **
+
+\unexpanded\def\expandparameters
+ {\let\syst_helpers_get_parameters\syst_helpers_get_parameters_expanded}
+
+%D \macros
+%D {getemptyparameters}
+%D
+%D Sometimes we explicitly want variables to default to an empty string, so we
+%D welcome:
+%D
+%D \starttyping
+%D \getemptyparameters [label] [...=...,...=...]
+%D \stoptyping
+
+\unexpanded\def\getemptyparameters[#1]#2[#3]%
+ {\def\syst_helpers_get_empty_parameters##1{\doassignempty[#1][##1]}%
+ \processcommalist[#3]\syst_helpers_get_empty_parameters}
+
+%D \macros
+%D {copyparameters}
+%D
+%D Some \CONTEXT\ commands take their default setups from others. All commands that
+%D are able to provide backgounds or rules around some content, for instance default
+%D to the standard command for ruled boxes. Is situations like this we can use:
+%D
+%D \starttyping
+%D \copyparameters [to-label] [from-label] [name1,name2,...]
+%D \stoptyping
+%D
+%D For instance
+%D
+%D \starttyping
+%D \copyparameters
+%D [internal][external]
+%D [alfa,beta]
+%D \stoptyping
+%D
+%D Leads to:
+%D
+%D \starttyping
+%D \def\internalalfa {\externalalfa}
+%D \def\internalbeta {\externalbeta}
+%D \stoptyping
+%D
+%D By using \type {\docopyvalue} we've prepared this command for use in a
+%D multi||lingual environment.
+
+\unexpanded\def\copyparameters[#1]#2[#3]#4[#5]%
+ {\doifnot{#1}{#3}
+ {\def\syst_helpers_copy_parameter{\docopyvalue{#1}{#3}}% ##1
+ \processcommalist[#5]\syst_helpers_copy_parameter}}
+
+%D \macros
+%D {ifparameters,checkparameters}
+%D
+%D A slightly different one is \type {\checkparameters}, which also checks on the
+%D presence of a~\type {=}.
+%D
+%D The boolean \type {\ifparameters} can be used afterwards. Combining both in one
+%D \type {\if}||macro would lead to problems with nested \type {\if}'s.
+%D
+%D \starttyping
+%D \checkparameters[argument]
+%D \stoptyping
+
+\newif\ifparameters
+
+\def\syst_helpers_check_parameters#1=#2#3^^^^0004%
+ {\if#2^^^^0003\parametersfalse\else\parameterstrue\fi}
+
+\unexpanded\def\checkparameters[#1]%
+ {\syst_helpers_check_parameters#1=^^^^0003^^^^0003^^^^0004}
+
+%D \macros
+%D {getfromcommalist,getfromcommacommand,
+%D commalistelement,
+%D getcommalistsize,getcommacommandsize}
+%D
+%D It's possible to get an element from a commalist or a command representing
+%D a commalist.
+%D
+%D \starttyping
+%D \getfromcommalist [string] [n]
+%D \getfromcommacommand [string,\strings,string,...] [n]
+%D \stoptyping
+%D
+%D The difference betwee the two of them is the same as the difference between
+%D \type {\processcomma...}. The found string is stored in \type
+%D {\commalistelement}.
+%D
+%D We can calculate the size of a comma separated list by using:
+%D
+%D \starttyping
+%D \getcommalistsize [string,string,...]
+%D \getcommacommandsize [string,\strings,string,...]
+%D \stoptyping
+%D
+%D Afterwards, the length is available in the macro \type {\commalistsize}
+%D (not a \COUNTER).
+
+\newcount\commalistcounter
+
+\def\commalistsize{0}
+
+\def\syst_helpers_get_comma_list_size#1%
+ {\advance\commalistcounter\plusone}
+
+\unexpanded\def\getcommalistsize#1]% don't loose [{#1}]
+ {\commalistcounter\zerocount
+ \processcommalist#1]\syst_helpers_get_comma_list_size % was [{#1}]
+ \edef\commalistsize{\the\commalistcounter}}
+
+% \def\getcommacommandsize[#1]%
+% {\edef\commacommand{#1}%
+% \scratchtoks\expandafter{\expandafter[\commacommand]}%
+% \expandafter\getcommalistsize\the\scratchtoks }
+
+\unexpanded\def\getcommacommandsize[#1]%
+ {\normalexpanded{\getcommalistsize[#1]}}
+
+\def\syst_helpers_get_from_comma_list#1%
+ {\advance\commalistcounter \minusone
+ \ifcase\commalistcounter
+ \def\commalistelement{#1}%
+ \expandafter\quitcommalist
+ \fi}
+
+\unexpanded\def\getfromcommalist[#1]#2[#3]%
+ {\let\commalistelement\empty
+ \commalistcounter#3\relax
+ \processcommalist[#1]\syst_helpers_get_from_comma_list}
+
+\unexpanded\def\getfromcommacommand[#1]%
+ {\normalexpanded{\getfromcommalist[#1]}}
+
+%D Watertight (and efficient) solutions are hard to find, due to the handling of
+%D braces during parameters passing and scanning. Nevertheless:
+%D
+%D \startbuffer
+%D \def\dosomething#1{(#1=\commalistsize) }
+%D
+%D \getcommalistsize [\hbox{$a,b,c,d,e,f$}] \dosomething 1
+%D \getcommalistsize [{a,b,c,d,e,f}] \dosomething 1
+%D \getcommalistsize [{a,b,c},d,e,f] \dosomething 4
+%D \getcommalistsize [a,b,{c,d,e},f] \dosomething 4
+%D \getcommalistsize [a{b,c},d,e,f] \dosomething 4
+%D \getcommalistsize [{a,b}c,d,e,f] \dosomething 4
+%D \getcommalistsize [] \dosomething 0
+%D \getcommalistsize [{[}] \dosomething 1
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D reports:
+%D
+%D \getbuffer
+
+%D \macros
+%D {dogetcommalistelement,dogetcommacommandelement}
+%D
+%D For low level (fast) purposes, we can also use the next alternative, which can
+%D handle 8~elements at most.
+%D
+%D \starttyping
+%D \dogetcommalistelement1\from a,b,c\to\commalistelement
+%D \stoptyping
+
+\def\syst_helpers_get_comma_list_element#1\from#2,#3,#4,#5,#6,#7,#8\to#9%
+ {\edef#9{\ifcase#1\relax\or#2\or#3\or#4\or#5\or#6\or#7\or#8\fi}}
+
+\def\dogetcommacommandelement#1\from#2\to%
+ {\expandafter\syst_helpers_get_comma_list_element\expandafter#1\expandafter\from#2,,,,,,\to}
+
+%D \macros
+%D {dosingleargument,dodoubleargument,dotripleargument,
+%D doquadrupleargument,doquintupleargument,dosixtupleargument,
+%D doseventupleargument}
+%D
+%D When working with delimited arguments, spaces and lineendings can interfere. The
+%D next set of macros uses \TEX' internal scanner for grabbing everything between
+%D arguments. Forgive me the funny names.
+%D
+%D \starttyping
+%D \dosingleargument\commando = \commando[#1]
+%D \dodoubleargument\commando = \commando[#1][#2]
+%D \dotripleargument\commando = \commando[#1][#2][#3]
+%D \doquadrupleargument\commando = \commando[#1][#2][#3][#4]
+%D \doquintupleargument\commando = \commando[#1][#2][#3][#4][#5]
+%D \dosixtupleargument\commando = \commando[#1][#2][#3][#4][#5][#6]
+%D \doseventupleargument\command = \commando[#1][#2][#3][#4][#5][#6][#7]
+%D \stoptyping
+%D
+%D These macros are used in the following way:
+%D
+%D \starttyping
+%D \def\dosetupsomething[#1][#2]%
+%D {... #1 ... #2 ...}
+%D
+%D \unexpanded\def\setupsomething
+%D {\dodoubleargument\dosetupsomething}
+%D \stoptyping
+%D
+%D The implementation can be surprisingly simple and needs no
+%D further explanation, like:
+%D
+%D \starttyping
+%D \def\dosingleargument#1[#2]%
+%D {#1[#2]}
+%D \def\dotripleargument#1[#2]#3[#4]#5[#6]%
+%D {#1[#2][#4][#6]}
+%D \def\doquintupleargument#1%
+%D {\def\dodoquintupleargument[##1]##2[##3]##4[##5]##6[##7]##8[##9]%
+%D {#1[##1][##3][##5][##7][##9]}%
+%D \dodoquintupleargument}
+%D \stoptyping
+%D
+%D Because \TEX\ accepts 9~arguments at most, we have to use two||step solution when
+%D getting five or more arguments.
+%D
+%D When developing more and more of the real \CONTEXT, we started using some
+%D alternatives that provided empty arguments (in fact optional ones) whenever the
+%D user failed to supply them. Because this more complicated macros enable us to do
+%D some checking, we reimplemented the non||empty ones.
+
+%D \macros
+%D {iffirstagument,ifsecondargument,ifthirdargument,
+%D iffourthargument,iffifthargument,ifsixthargument,
+%D ifseventhargument}
+%D
+%D We use some signals for telling the calling macros if all wanted arguments are
+%D indeed supplied by the user.
+
+\newif\iffirstargument
+\newif\ifsecondargument
+\newif\ifthirdargument
+\newif\iffourthargument
+\newif\iffifthargument
+\newif\ifsixthargument
+\newif\ifseventhargument
+
+%D \macros
+%D {dosingleempty,dodoubleempty,dotripleempty,
+%D doquadrupleempty,doquintupleempty,dosixtupeempty,
+%D doseventupleempty}
+%D
+%D The empty argument supplying macros mentioned before, look like:
+%D
+%D \starttyping
+%D \dosingleempty \command
+%D \dodoubleempty \command
+%D \dotripleempty \command
+%D \doquadrupleempty \command
+%D \doquintupleempty \command
+%D \dosixtuple_empty \command
+%D \doseventupleempty\command
+%D \stoptyping
+%D
+%D So \type{\dodoubleempty} leads to:
+%D
+%D \starttyping
+%D \command[#1][#2]
+%D \command[#1][]
+%D \command[][]
+%D \stoptyping
+%D
+%D Depending of the generousity of the user. Afterwards one can use the \type
+%D {\if...argument} boolean. For novice: watch the stepwise doubling of \type {#}'s.
+
+%D Common:
+
+\newtoks\t_syst_aux
+
+\def\syst_helpers_single_empty_one_yes {\firstargumenttrue \the\t_syst_aux}
+\def\syst_helpers_double_empty_two_yes {\secondargumenttrue \the\t_syst_aux}
+\def\syst_helpers_triple_empty_three_yes {\thirdargumenttrue \the\t_syst_aux}
+\def\syst_helpers_quadruple_empty_four_yes {\fourthargumenttrue \the\t_syst_aux}
+\def\syst_helpers_quintuple_empty_five_yes {\fifthargumenttrue \the\t_syst_aux}
+\def\syst_helpers_sixtuple_empty_six_yes {\sixthargumenttrue \the\t_syst_aux}
+\def\syst_helpers_seventuple_empty_seven_yes{\seventhargumenttrue\the\t_syst_aux}
+
+%D Single:
+
+\unexpanded\def\dosingleempty#1%
+ {%syst_helpers_argument_reset
+ \t_syst_aux{#1}%
+ \futureexpand[\syst_helpers_single_empty_one_yes\syst_helpers_single_empty_one_nop}
+
+\def\syst_helpers_single_empty_one_nop
+ {\firstargumentfalse
+ \the\t_syst_aux[]}
+
+%D Double
+
+\unexpanded\def\dodoubleempty#1%
+ {%syst_helpers_argument_reset
+ \t_syst_aux{#1}%
+ \futureexpand[\syst_helpers_double_empty_one_yes\syst_helpers_double_empty_one_nop}
+
+\def\syst_helpers_double_empty_one_yes[#1]%
+ {\firstargumenttrue
+ \toksapp\t_syst_aux{[{#1}]}%
+ \futureexpand[\syst_helpers_double_empty_two_yes\syst_helpers_double_empty_two_nop}
+
+\def\syst_helpers_double_empty_one_nop
+ {\firstargumentfalse
+ \secondargumentfalse
+ \the\t_syst_aux[][]}
+
+\def\syst_helpers_double_empty_two_nop
+ {\secondargumentfalse
+ \the\t_syst_aux[]}
+
+% Triple
+
+\unexpanded\def\dotripleempty#1%
+ {%syst_helpers_argument_reset
+ \t_syst_aux{#1}%
+ \futureexpand[\syst_helpers_triple_empty_one_yes\syst_helpers_triple_empty_one_nop}
+
+\def\syst_helpers_triple_empty_one_yes[#1]%
+ {\firstargumenttrue
+ \toksapp\t_syst_aux{[{#1}]}%
+ \futureexpand[\syst_helpers_triple_empty_two_yes\syst_helpers_triple_empty_two_nop}
+
+\def\syst_helpers_triple_empty_two_yes[#1]%
+ {\secondargumenttrue
+ \toksapp\t_syst_aux{[{#1}]}%
+ \futureexpand[\syst_helpers_triple_empty_three_yes\syst_helpers_triple_empty_three_nop}
+
+\def\syst_helpers_triple_empty_one_nop
+ {\firstargumentfalse
+ \secondargumentfalse
+ \thirdargumentfalse
+ \the\t_syst_aux[][][]}
+
+\def\syst_helpers_triple_empty_two_nop
+ {\secondargumentfalse
+ \thirdargumentfalse
+ \the\t_syst_aux[][]}
+
+\def\syst_helpers_triple_empty_three_nop
+ {\thirdargumentfalse
+ \the\t_syst_aux[]}
+
+%D Quadruple:
+
+\unexpanded\def\doquadrupleempty#1%
+ {%syst_helpers_argument_reset
+ \t_syst_aux{#1}%
+ \futureexpand[\syst_helpers_quadruple_empty_one_yes\syst_helpers_quadruple_empty_one_nop}
+
+\def\syst_helpers_quadruple_empty_one_yes[#1]%
+ {\firstargumenttrue
+ \toksapp\t_syst_aux{[{#1}]}%
+ \futureexpand[\syst_helpers_quadruple_empty_two_yes\syst_helpers_quadruple_empty_two_nop}
+
+\def\syst_helpers_quadruple_empty_two_yes[#1]%
+ {\secondargumenttrue
+ \toksapp\t_syst_aux{[{#1}]}%
+ \futureexpand[\syst_helpers_quadruple_empty_three_yes\syst_helpers_quadruple_empty_three_nop}
+
+\def\syst_helpers_quadruple_empty_three_yes[#1]%
+ {\thirdargumenttrue
+ \toksapp\t_syst_aux{[{#1}]}%
+ \futureexpand[\syst_helpers_quadruple_empty_four_yes\syst_helpers_quadruple_empty_four_nop}
+
+\def\syst_helpers_quadruple_empty_one_nop
+ {\firstargumentfalse
+ \secondargumentfalse
+ \thirdargumentfalse
+ \fourthargumentfalse
+ \the\t_syst_aux[][][][]}
+
+\def\syst_helpers_quadruple_empty_two_nop
+ {\secondargumentfalse
+ \thirdargumentfalse
+ \fourthargumentfalse
+ \the\t_syst_aux[][][]}
+
+\def\syst_helpers_quadruple_empty_three_nop
+ {\thirdargumentfalse
+ \fourthargumentfalse
+ \the\t_syst_aux[][]}
+
+\def\syst_helpers_quadruple_empty_four_nop
+ {\fourthargumentfalse
+ \the\t_syst_aux[]}
+
+%D Quintuple:
+
+\unexpanded\def\doquintupleempty#1%
+ {%syst_helpers_argument_reset
+ \t_syst_aux{#1}%
+ \futureexpand[\syst_helpers_quintuple_empty_one_yes\syst_helpers_quintuple_empty_one_nop}
+
+\def\syst_helpers_quintuple_empty_one_yes[#1]%
+ {\firstargumenttrue
+ \toksapp\t_syst_aux{[{#1}]}%
+ \futureexpand[\syst_helpers_quintuple_empty_two_yes\syst_helpers_quintuple_empty_two_nop}
+
+\def\syst_helpers_quintuple_empty_two_yes[#1]%
+ {\secondargumenttrue
+ \toksapp\t_syst_aux{[{#1}]}%
+ \futureexpand[\syst_helpers_quintuple_empty_three_yes\syst_helpers_quintuple_empty_three_nop}
+
+\def\syst_helpers_quintuple_empty_three_yes[#1]%
+ {\thirdargumenttrue
+ \toksapp\t_syst_aux{[{#1}]}%
+ \futureexpand[\syst_helpers_quintuple_empty_four_yes\syst_helpers_quintuple_empty_four_nop}
+
+\def\syst_helpers_quintuple_empty_four_yes[#1]%
+ {\fourthargumenttrue
+ \toksapp\t_syst_aux{[{#1}]}%
+ \futureexpand[\syst_helpers_quintuple_empty_five_yes\syst_helpers_quintuple_empty_five_nop}
+
+\def\syst_helpers_quintuple_empty_one_nop
+ {\firstargumentfalse
+ \secondargumentfalse
+ \thirdargumentfalse
+ \fourthargumentfalse
+ \fifthargumentfalse
+ \the\t_syst_aux[][][][][]}
+
+\def\syst_helpers_quintuple_empty_two_nop
+ {\secondargumentfalse
+ \thirdargumentfalse
+ \fourthargumentfalse
+ \fifthargumentfalse
+ \the\t_syst_aux[][][][]}
+
+\def\syst_helpers_quintuple_empty_three_nop
+ {\thirdargumentfalse
+ \fourthargumentfalse
+ \fifthargumentfalse
+ \the\t_syst_aux[][][]}
+
+\def\syst_helpers_quintuple_empty_four_nop
+ {\fourthargumentfalse
+ \fifthargumentfalse
+ \the\t_syst_aux[][]}
+
+\def\syst_helpers_quintuple_empty_five_nop
+ {\fifthargumentfalse
+ \the\t_syst_aux[]}
+
+%D Sixtuple:
+
+\unexpanded\def\dosixtupleempty#1%
+ {%syst_helpers_argument_reset
+ \t_syst_aux{#1}%
+ \futureexpand[\syst_helpers_sixtuple_empty_one_yes\syst_helpers_sixtuple_empty_one_nop}
+
+\def\syst_helpers_sixtuple_empty_one_yes[#1]%
+ {\firstargumenttrue
+ \toksapp\t_syst_aux{[{#1}]}%
+ \futureexpand[\syst_helpers_sixtuple_empty_two_yes\syst_helpers_sixtuple_empty_two_nop}
+
+\def\syst_helpers_sixtuple_empty_two_yes[#1]%
+ {\secondargumenttrue
+ \toksapp\t_syst_aux{[{#1}]}%
+ \futureexpand[\syst_helpers_sixtuple_empty_three_yes\syst_helpers_sixtuple_empty_three_nop}
+
+\def\syst_helpers_sixtuple_empty_three_yes[#1]%
+ {\thirdargumenttrue
+ \toksapp\t_syst_aux{[{#1}]}%
+ \futureexpand[\syst_helpers_sixtuple_empty_four_yes\syst_helpers_sixtuple_empty_four_nop}
+
+\def\syst_helpers_sixtuple_empty_four_yes[#1]%
+ {\fourthargumenttrue
+ \toksapp\t_syst_aux{[{#1}]}%
+ \futureexpand[\syst_helpers_sixtuple_empty_five_yes\syst_helpers_sixtuple_empty_five_nop}
+
+\def\syst_helpers_sixtuple_empty_five_yes[#1]%
+ {\fifthargumenttrue
+ \toksapp\t_syst_aux{[{#1}]}%
+ \futureexpand[\syst_helpers_sixtuple_empty_six_yes\syst_helpers_sixtuple_empty_six_nop}
+
+\def\syst_helpers_sixtuple_empty_one_nop
+ {\firstargumentfalse
+ \secondargumentfalse
+ \thirdargumentfalse
+ \fourthargumentfalse
+ \fifthargumentfalse
+ \sixthargumentfalse
+ \the\t_syst_aux[][][][][][]}
+
+\def\syst_helpers_sixtuple_empty_two_nop
+ {\secondargumentfalse
+ \thirdargumentfalse
+ \fourthargumentfalse
+ \fifthargumentfalse
+ \sixthargumentfalse
+ \the\t_syst_aux[][][][][]}
+
+\def\syst_helpers_sixtuple_empty_three_nop
+ {\thirdargumentfalse
+ \fourthargumentfalse
+ \fifthargumentfalse
+ \sixthargumentfalse
+ \the\t_syst_aux[][][][]}
+
+\def\syst_helpers_sixtuple_empty_four_nop
+ {\fourthargumentfalse
+ \fifthargumentfalse
+ \sixthargumentfalse
+ \the\t_syst_aux[][][]}
+
+\def\syst_helpers_sixtuple_empty_five_nop
+ {\fifthargumentfalse
+ \sixthargumentfalse
+ \the\t_syst_aux[][]}
+
+\def\syst_helpers_sixtuple_empty_six_nop
+ {\sixthargumentfalse
+ \the\t_syst_aux[]}
+
+%D Seventuple:
+
+\unexpanded\def\doseventupleempty#1%
+ {%syst_helpers_argument_reset
+ \t_syst_aux{#1}%
+ \futureexpand[\syst_helpers_seventuple_empty_one_yes\syst_helpers_seventuple_empty_one_nop}
+
+\def\syst_helpers_seventuple_empty_one_yes[#1]%
+ {\firstargumenttrue
+ \toksapp\t_syst_aux{[{#1}]}%
+ \futureexpand[\syst_helpers_seventuple_empty_two_yes\syst_helpers_seventuple_empty_two_nop}
+
+\def\syst_helpers_seventuple_empty_two_yes[#1]%
+ {\secondargumenttrue
+ \toksapp\t_syst_aux{[{#1}]}%
+ \futureexpand[\syst_helpers_seventuple_empty_three_yes\syst_helpers_seventuple_empty_three_nop}
+
+\def\syst_helpers_seventuple_empty_three_yes[#1]%
+ {\thirdargumenttrue
+ \toksapp\t_syst_aux{[{#1}]}%
+ \futureexpand[\syst_helpers_seventuple_empty_four_yes\syst_helpers_seventuple_empty_four_nop}
+
+\def\syst_helpers_seventuple_empty_four_yes[#1]%
+ {\fourthargumenttrue
+ \toksapp\t_syst_aux{[{#1}]}%
+ \futureexpand[\syst_helpers_seventuple_empty_five_yes\syst_helpers_seventuple_empty_five_nop}
+
+\def\syst_helpers_seventuple_empty_five_yes[#1]%
+ {\fifthargumenttrue
+ \toksapp\t_syst_aux{[{#1}]}%
+ \futureexpand[\syst_helpers_seventuple_empty_six_yes\syst_helpers_seventuple_empty_six_nop}
+
+\def\syst_helpers_seventuple_empty_six_yes[#1]%
+ {\sixthargumenttrue
+ \toksapp\t_syst_aux{[{#1}]}%
+ \futureexpand[\syst_helpers_seventuple_empty_seven_yes\syst_helpers_seventuple_empty_seven_nop}
+
+\def\syst_helpers_seventuple_empty_one_nop
+ {\firstargumentfalse
+ \secondargumentfalse
+ \thirdargumentfalse
+ \fourthargumentfalse
+ \fifthargumentfalse
+ \sixthargumentfalse
+ \seventhargumentfalse
+ \the\t_syst_aux[][][][][][][]}
+
+\def\syst_helpers_seventuple_empty_two_nop
+ {\secondargumentfalse
+ \thirdargumentfalse
+ \fourthargumentfalse
+ \fifthargumentfalse
+ \sixthargumentfalse
+ \seventhargumentfalse
+ \the\t_syst_aux[][][][][][]}
+
+\def\syst_helpers_seventuple_empty_three_nop
+ {\thirdargumentfalse
+ \fourthargumentfalse
+ \fifthargumentfalse
+ \sixthargumentfalse
+ \seventhargumentfalse
+ \the\t_syst_aux[][][][][]}
+
+\def\syst_helpers_seventuple_empty_four_nop
+ {\fourthargumentfalse
+ \fifthargumentfalse
+ \sixthargumentfalse
+ \seventhargumentfalse
+ \the\t_syst_aux[][][][]}
+
+\def\syst_helpers_seventuple_empty_five_nop
+ {\fifthargumentfalse
+ \sixthargumentfalse
+ \seventhargumentfalse
+ \the\t_syst_aux[][][]}
+
+\def\syst_helpers_seventuple_empty_six_nop
+ {\sixthargumentfalse
+ \seventhargumentfalse
+ \the\t_syst_aux[][]}
+
+\def\syst_helpers_seventuple_empty_seven_nop
+ {\seventhargumentfalse
+ \the\t_syst_aux[]}
+
+%D Aliases:
+
+\let\dosingleargument \dosingleempty
+\let\dodoubleargument \dodoubleempty
+\let\dotripleargument \dotripleempty
+\let\doquadrupleargument \doquadrupleempty
+\let\doquintupleargument \doquintupleempty
+\let\dosixtupleargument \dosixtupleempty
+\let\doseventupleargument\doseventupleempty
+
+%D \macros
+%D {strippedcsname}
+%D
+%D The next macro can be very useful when using \type{\csname} like in:
+%D
+%D \starttyping
+%D \csname if\strippedcsname\something\endcsname
+%D \stoptyping
+%D
+%D This expands to \type{\ifsomething}.
+
+% \def\strippedcsname
+% {\expandafter\gobbleoneargument\string}
+
+\let\strippedcsname\csstring
+
+%D \macros
+%D {complexorsimple,complexorsimpleempty}
+%D
+%D Setups can be optional. A command expecting a setup is prefixed by \type
+%D {\complex}, a command without one gets the prefix \type {\simple}. Commands like
+%D this can be defined by:
+%D
+%D \starttyping
+%D \complexorsimple\command
+%D \stoptyping
+%D
+%D When \type{\command} is followed by a \type{[setup]}, then
+%D
+%D \starttyping
+%D \complexcommand [setup]
+%D \stoptyping
+%D
+%D executes, else we get
+%D
+%D \starttyping
+%D \simplecommand
+%D \stoptyping
+%D
+%D An alternative for \type{\complexorsimple} is:
+%D
+%D \starttyping
+%D \complexorsimpleempty {command}
+%D \stoptyping
+%D
+%D Depending on the presence of \type{[setup]}, this one leads to one of:
+%D
+%D \starttyping
+%D \complexcommando [setup]
+%D \complexcommando []
+%D \stoptyping
+%D
+%D Many \CONTEXT\ commands started as complex or simple ones, but changed into more
+%D versatile (more object oriented) ones using the \type {\get..argument} commands.
+
+\unexpanded\def\complexorsimple#1%
+ {% \relax % prevents lookahead, brrr
+ \doifelsenextoptional
+ {\firstargumenttrue \csname\s!complex\csstring#1\endcsname}
+ {\firstargumentfalse\csname\s!simple \csstring#1\endcsname}}
+
+\unexpanded\def\complexorsimpleempty#1%
+ {% \relax % prevents lookahead, brrr
+ \doifelsenextoptional
+ {\firstargumenttrue \csname\s!complex\csstring#1\endcsname}
+ {\firstargumentfalse\csname\s!complex\csstring#1\endcsname[]}}
+
+%D \macros
+%D {definecomplexorsimple,definecomplexorsimpleempty}
+%D
+%D The previous commands are used that often that we found it worthwile to offer two
+%D more alternatives. Watch the build in protection.
+
+\unexpanded\def\syst_helpers_complex_or_simple#1#2%
+ {\doifelsenextoptional{\firstargumenttrue#1}{\firstargumentfalse#2}}
+
+\unexpanded\def\syst_helpers_complex_or_simple_empty#1%
+ {\doifelsenextoptional{\firstargumenttrue#1}{\firstargumentfalse#1[]}}
+
+\unexpanded\def\definecomplexorsimple#1%
+ {\unexpanded\edef#1{\syst_helpers_complex_or_simple
+ \expandafter\noexpand\csname\s!complex\csstring#1\endcsname
+ \expandafter\noexpand\csname\s!simple \csstring#1\endcsname}}
+
+\unexpanded\def\definecomplexorsimpleempty#1%
+ {\unexpanded\edef#1{\syst_helpers_complex_or_simple_empty
+ \expandafter\noexpand\csname\s!complex\csstring#1\endcsname}}
+
+%D These commands are called as:
+%D
+%D \starttyping
+%D \definecomplexorsimple\command
+%D \stoptyping
+%D
+%D Of course, we must have available
+%D
+%D \starttyping
+%D \def\complexcommand[#1]{...}
+%D \def\simplecommand {...}
+%D \stoptyping
+%D
+%D Using this construction saves a few string now and then.
+
+%D \macros
+%D {dosinglegroupempty,dodoublegroupempty,dotriplegroupempty,
+%D doquadruplegroupempty, doquintuplegroupempty}
+%D
+%D We've already seen some commands that take care of
+%D optional arguments between \type{[]}. The next two commands
+%D handle the ones with \type{{}}. They are called as:
+%D
+%D \starttyping
+%D \dosinglegroupempty \ineedONEargument
+%D \dodoublegroupempty \ineedTWOarguments
+%D \dotriplegroupempty \ineedTHREEarguments
+%D \doquadruplegroupempty \ineedFOURarguments
+%D \doquintuplegroupempty \ineedFIVEarguments
+%D \stoptyping
+%D
+%D We can add additional definitions later when we have defined \type {\appendtoks}.
+
+\newconditional\c_syst_helpers_permit_spaces_between_groups
+
+\unexpanded\def \permitspacesbetweengroups{\settrue \c_syst_helpers_permit_spaces_between_groups}
+\unexpanded\def\dontpermitspacesbetweengroups{\setfalse\c_syst_helpers_permit_spaces_between_groups}
+
+\dontpermitspacesbetweengroups
+
+%D We can avoid the nasty if handling in \type {syst-gen} by splitting the lot in
+%D pieces so that we have no nested \type {\nextarguments} potentially being an
+%D \type {conditional} token. Okay, these macros are not called that often but it
+%D saves crap when tracing.
+
+\unexpanded\def\dosinglegroupempty#1%
+ {\t_syst_aux{#1}%
+ \futureexpand\bgroup\syst_helpers_single_empty_one_yes\syst_helpers_single_group_empty_one_nop}
+
+\def\syst_helpers_single_group_empty_one_nop
+ {\firstargumentfalse
+ \the\t_syst_aux{}}
+
+\unexpanded\def\dodoublegroupempty#1%
+ {\t_syst_aux{#1}%
+ \futureexpand\bgroup\syst_helpers_group_double_empty_one_yes\syst_helpers_group_double_empty_one_nop}
+
+\def\syst_helpers_group_double_empty_one_yes#1%
+ {\firstargumenttrue
+ \toksapp\t_syst_aux{{#1}}%
+ \futureexpand\bgroup\syst_helpers_double_empty_two_yes\syst_helpers_group_double_empty_two_nop}
+
+\def\syst_helpers_group_double_empty_one_nop
+ {\firstargumentfalse
+ \secondargumentfalse
+ \the\t_syst_aux{}{}}
+
+\def\syst_helpers_group_double_empty_two_nop
+ {\secondargumentfalse
+ \the\t_syst_aux{}}
+
+\unexpanded\def\dotriplegroupempty#1%
+ {\t_syst_aux{#1}%
+ \futureexpand\bgroup\syst_helpers_group_triple_empty_one_yes\syst_helpers_group_triple_empty_one_nop}
+
+\def\syst_helpers_group_triple_empty_one_yes#1%
+ {\firstargumenttrue
+ \toksapp\t_syst_aux{{#1}}%
+ \futureexpand\bgroup\syst_helpers_group_triple_empty_two_yes\syst_helpers_group_triple_empty_two_nop}
+
+\def\syst_helpers_group_triple_empty_two_yes#1%
+ {\secondargumenttrue
+ \toksapp\t_syst_aux{{#1}}%
+ \futureexpand\bgroup\syst_helpers_triple_empty_three_yes\syst_helpers_group_triple_empty_three_nop}
+
+\def\syst_helpers_group_triple_empty_one_nop
+ {\firstargumentfalse
+ \secondargumentfalse
+ \thirdargumentfalse
+ \the\t_syst_aux{}{}{}}
+
+\def\syst_helpers_group_triple_empty_two_nop
+ {\secondargumentfalse
+ \thirdargumentfalse
+ \the\t_syst_aux{}{}}
+
+\def\syst_helpers_group_triple_empty_three_nop
+ {\thirdargumentfalse
+ \the\t_syst_aux{}}
+
+\unexpanded\def\doquadruplegroupempty#1%
+ {\t_syst_aux{#1}%
+ \futureexpand\bgroup\syst_helpers_group_quadruple_empty_one_yes\syst_helpers_group_quadruple_empty_one_nop}
+
+\def\syst_helpers_group_quadruple_empty_one_yes#1%
+ {\firstargumenttrue
+ \toksapp\t_syst_aux{{#1}}%
+ \futureexpand\bgroup\syst_helpers_group_quadruple_empty_two_yes\syst_helpers_group_quadruple_empty_two_nop}
+
+\def\syst_helpers_group_quadruple_empty_two_yes#1%
+ {\secondargumenttrue
+ \toksapp\t_syst_aux{{#1}}%
+ \futureexpand\bgroup\syst_helpers_group_quadruple_empty_three_yes\syst_helpers_group_quadruple_empty_three_nop}
+
+\def\syst_helpers_group_quadruple_empty_three_yes#1%
+ {\thirdargumenttrue
+ \toksapp\t_syst_aux{{#1}}%
+ \futureexpand\bgroup\syst_helpers_quadruple_empty_four_yes\syst_helpers_group_quadruple_empty_four_nop}
+
+\def\syst_helpers_group_quadruple_empty_one_nop
+ {\firstargumentfalse
+ \secondargumentfalse
+ \thirdargumentfalse
+ \fourthargumentfalse
+ \the\t_syst_aux{}{}{}{}}
+
+\def\syst_helpers_group_quadruple_empty_two_nop
+ {\secondargumentfalse
+ \thirdargumentfalse
+ \fourthargumentfalse
+ \the\t_syst_aux{}{}{}}
+
+\def\syst_helpers_group_quadruple_empty_three_nop
+ {\thirdargumentfalse
+ \fourthargumentfalse
+ \the\t_syst_aux{}{}}
+
+\def\syst_helpers_group_quadruple_empty_four_nop
+ {\fourthargumentfalse
+ \the\t_syst_aux{}}
+
+\unexpanded\def\doquintuplegroupempty#1%
+ {\t_syst_aux{#1}%
+ \futureexpand\bgroup\syst_helpers_group_quintuple_empty_one_yes\syst_helpers_group_quintuple_empty_one_nop}
+
+\def\syst_helpers_group_quintuple_empty_one_yes#1%
+ {\firstargumenttrue
+ \toksapp\t_syst_aux{{#1}}%
+ \futureexpand\bgroup\syst_helpers_group_quintuple_empty_two_yes\syst_helpers_group_quintuple_empty_two_nop}
+
+\def\syst_helpers_group_quintuple_empty_two_yes#1%
+ {\secondargumenttrue
+ \toksapp\t_syst_aux{{#1}}%
+ \futureexpand\bgroup\syst_helpers_group_quintuple_empty_three_yes\syst_helpers_group_quintuple_empty_three_nop}
+
+\def\syst_helpers_group_quintuple_empty_three_yes#1%
+ {\thirdargumenttrue
+ \toksapp\t_syst_aux{{#1}}%
+ \futureexpand\bgroup\syst_helpers_group_quintuple_empty_four_yes\syst_helpers_group_quintuple_empty_four_nop}
+
+\def\syst_helpers_group_quintuple_empty_four_yes#1%
+ {\fourthargumenttrue
+ \toksapp\t_syst_aux{{#1}}%
+ \futureexpand\bgroup\syst_helpers_quintuple_empty_five_yes\syst_helpers_group_quintuple_empty_five_nop}
+
+\def\syst_helpers_group_quintuple_empty_one_nop
+ {\firstargumentfalse
+ \secondargumentfalse
+ \thirdargumentfalse
+ \fourthargumentfalse
+ \fifthargumentfalse
+ \the\t_syst_aux{}{}{}{}{}}
+
+\def\syst_helpers_group_quintuple_empty_two_nop
+ {\secondargumentfalse
+ \thirdargumentfalse
+ \fourthargumentfalse
+ \fifthargumentfalse
+ \the\t_syst_aux{}{}{}{}}
+
+\def\syst_helpers_group_quintuple_empty_three_nop
+ {\thirdargumentfalse
+ \fourthargumentfalse
+ \fifthargumentfalse
+ \the\t_syst_aux{}{}{}}
+
+\def\syst_helpers_group_quintuple_empty_four_nop
+ {\fourthargumentfalse
+ \fifthargumentfalse
+ \the\t_syst_aux{}{}}
+
+\def\syst_helpers_group_quintuple_empty_five_nop
+ {\fifthargumentfalse
+ \the\t_syst_aux{}}
+
+%D These macros can explictly take care of spaces, which means that the next
+%D definition and calls are valid:
+%D
+%D \starttyping
+%D \def\test#1#2#3{[#1#2#3]}
+%D
+%D \dotriplegroupempty\test {a}{b}{c}
+%D \dotriplegroupempty\test {a}{b}
+%D \dotriplegroupempty\test {a}
+%D \dotriplegroupempty\test
+%D \dotriplegroupempty\test {a} {b} {c}
+%D \dotriplegroupempty\test {a} {b}
+%D \dotriplegroupempty\test
+%D {a}
+%D {b}
+%D \stoptyping
+%D
+%D And alike.
+
+%D \macros
+%D {firstofoneargument, firstoftwoarguments, firstofthreearguments
+%D secondoftwoarguments, secondofthreearguments,
+%D thirdofthreearguments}
+%D
+%D The next six macros (dedicated to Taco) can conveniently used to select
+%D arguments. Their names explain their functionality.
+
+\def\firstofoneargument #1{#1}
+
+\def\firstoftwoarguments #1#2{#1}
+\def\secondoftwoarguments #1#2{#2}
+
+\def\firstofthreearguments #1#2#3{#1}
+\def\secondofthreearguments #1#2#3{#2}
+\def\thirdofthreearguments #1#2#3{#3}
+
+\def\firstoffourarguments #1#2#3#4{#1}
+\def\secondoffourarguments #1#2#3#4{#2}
+\def\thirdoffourarguments #1#2#3#4{#3}
+\def\fourthoffourarguments #1#2#3#4{#4}
+
+\def\firstoffivearguments #1#2#3#4#5{#1}
+\def\secondoffivearguments #1#2#3#4#5{#2}
+\def\thirdoffivearguments #1#2#3#4#5{#3}
+\def\fourthoffivearguments #1#2#3#4#5{#4}
+\def\fifthoffivearguments #1#2#3#4#5{#5}
+
+\def\firstofsixarguments #1#2#3#4#5#6{#1}
+\def\secondofsixarguments#1#2#3#4#5#6{#2}
+\def\thirdofsixarguments #1#2#3#4#5#6{#3}
+\def\fourthofsixarguments#1#2#3#4#5#6{#4}
+\def\fifthofsixarguments #1#2#3#4#5#6{#5}
+\def\sixthofsixarguments #1#2#3#4#5#6{#6}
+
+\unexpanded\def\firstofoneunexpanded #1{#1}
+
+\unexpanded\def\firstoftwounexpanded #1#2{#1}
+\unexpanded\def\secondoftwounexpanded #1#2{#2}
+
+\unexpanded\def\firstofthreeunexpanded #1#2#3{#1}
+\unexpanded\def\secondofthreeunexpanded#1#2#3{#2}
+\unexpanded\def\thirdofthreeunexpanded #1#2#3{#3}
+
+%D \macros
+%D {globalletempty,letempty,
+%D letvalueempty,letgvalueempty,
+%D letvaluerelax,letgvaluerelax}
+%D
+%D Trivial:
+
+\unexpanded\def\letempty #1{\let #1\empty}
+\unexpanded\def\globalletempty#1{\glet#1\empty}
+
+\unexpanded\def\letvalueempty #1{\expandafter\let \csname#1\endcsname\empty}
+\unexpanded\def\letgvalueempty#1{\expandafter\glet\csname#1\endcsname\empty}
+\unexpanded\def\letvaluerelax #1{\expandafter\let \csname#1\endcsname\relax}
+\unexpanded\def\letgvalurelax #1{\expandafter\glet\csname#1\endcsname\relax}
+
+\unexpanded\def\relaxvalueifundefined#1%
+ {\ifcsname#1\endcsname \else
+ \expandafter\let\csname#1\endcsname\relax
+ \fi}
+
+%D \macros
+%D {wait}
+%D
+%D The next macro hardly needs explanation. Because no nesting is to be expected, we
+%D can reuse \type {\wait} within \type {\wait} itself.
+
+\unexpanded\def\wait
+ {\begingroup
+ \read16 to \wait
+ \endgroup}
+
+%D \macros
+%D {writestring,writeline,
+%D writestatus,statuswidth,normalwritestatus}
+%D
+%D Maybe one didn't notice, but we've already introduced a macro for showing
+%D messages. In the multi||lingual modules, we will also introduce a mechanism for
+%D message passing. For the moment we stick to the core macros:
+%D
+%D \starttyping
+%D \writestring {string}
+%D \writeline
+%D \writestatus {category} {message}
+%D \stoptyping
+%D
+%D Messages are formatted. One can provide the maximum with of the identification
+%D string with the macro \type {\statuswidth}.
+
+\setnewconstant\statuswidth 15
+\setnewconstant\statuswrite 128 % \pluscxxviii
+
+\ifdefined\writestring \else
+
+ \unexpanded\def\writestring{\immediate\write\statuswrite}
+ \unexpanded\def\writeline {\writestring{}}
+
+\fi
+
+\unexpanded\def\normalwritestatus#1#2%
+ {\writestring{\expandafter\syst_helpers_split_status_yes\expandafter\statuswidth#1%
+ \space\space\space\space\space\space\space
+ \space\space\space\space\space\space\space
+ \space\space\space\space\space\space\end
+ \space:\space#2}}
+
+\def\syst_helpers_split_status_yes#1#2%
+ {\ifcase#1 \expandafter\syst_helpers_split_status_nop\fi#2%
+ \expandafter\syst_helpers_split_status_yes\expandafter{\the\numexpr#1+\minusone\relax}}
+
+\def\syst_helpers_split_status_nop#1\end
+ {}
+
+%D \macros
+%D {immediatemessage}
+%D
+%D A fully expandable message:
+
+\let\immediatemessage\clf_immediatemessage % {} mandate
+
+%D \macros
+%D {rawgetparameters}
+%D
+%D A raw and dirty alternative for \type {\getparameters}; no checking is done!
+
+\unexpanded\def\rawsetparameter#1=#2,%
+ {\if]#1\else
+ \expandafter\def\csname\rawparameterprefix#1\endcsname{#2}%
+ \expandafter\rawsetparameter
+ \fi}
+
+\unexpanded\def\rawgetparameters[#1][#2% some 5-10% faster
+ {\ifx#2]% test is needed, else bomb on [#1][]
+ \expandafter\gobbleoneargument
+ \else
+ \def\rawparameterprefix{#1}%
+ \expandafter\dorawgetparameters
+ \fi#2}
+
+\def\dorawgetparameters#1]%
+ {\expandafter\rawsetparameter#1,]=,}
+
+%D \macros
+%D {doglobal,
+%D redoglobal,dodoglobal,resetglobal}
+%D
+%D The two macros \type {\redoglobal} and \type{\dodoglobal} are used in this and
+%D some other modules to enforce a user specified \type {\doglobal} action. The last
+%D and often only global assignment in a macro is done with \type {\dodoglobal}, but
+%D all preceding ones with \type {\redoglobal}. When using only alternatives, one
+%D can reset this mechanism with \type {\resetglobal}.
+
+\unexpanded\def\resetglobal
+ {\let\redoglobal\relax
+ \let\dodoglobal\relax}
+
+\resetglobal
+
+\unexpanded\def\doglobal
+ {\ifx\redoglobal\relax
+ \let\redoglobal\global
+ \let\dodoglobal\syst_helpers_dodo_global
+ \fi}
+
+\def\syst_helpers_dodo_global
+ {\resetglobal\global}
+
+\def\saveglobal
+ {\let\syst_helpers_dodo_global\dodoglobal
+ \let\syst_helpers_redo_global\redoglobal}
+
+\def\restoreglobal
+ {\let\redoglobal\syst_helpers_redo_global
+ \let\dodoglobal\syst_helpers_dodo_global}
+
+%D A very useful application of this macro is \type {\newif}, \TEX's fake boolean
+%D type. Not being a primitive, \type {\global} hopelessly fails here. But a slight
+%D adaption of Knuth's original macro permits:
+%D
+%D \starttyping
+%D \doglobal\newif\iftest
+%D \stoptyping
+%D
+%D Of course one can still say:
+%D
+%D \starttyping
+%D \global\testtrue
+%D \global\testfalse
+%D \stoptyping
+%D
+%D Apart from the prefixes, a few more \type {\expandafters} are needed:
+
+% \unexpanded\def\newif#1% uses the original plain \@if
+% {\privatescratchcounter\escapechar
+% \escapechar\minusone
+% \expandafter\expandafter\expandafter
+% \redoglobal\expandafter\expandafter\expandafter
+% \edef\@if#1{true}{\let\noexpand#1\noexpand\iftrue}%
+% \expandafter\expandafter\expandafter
+% \redoglobal\expandafter\expandafter\expandafter
+% \edef\@if#1{false}{\let\noexpand#1\noexpand\iffalse}%
+% \dodoglobal\@if#1{false}%
+% \escapechar\privatescratchcounter}
+
+\normalprotected\def\newif#1% see syst-ini.mkiv
+ {\let\new_if_saved\newif
+ \let\newif\new_if_check
+ \expandafter\redoglobal\expandafter\def\csname\expandafter\newif\csstring#1true\endcsname {\let#1\iftrue }%
+ \expandafter\redoglobal\expandafter\def\csname\expandafter\newif\csstring#1false\endcsname{\let#1\iffalse}%
+ \dodoglobal\csname\expandafter\newif\csstring#1false\endcsname
+ \let\newif\new_if_saved}
+
+%D Also new:
+
+\unexpanded\def\define#1%
+ {\ifdefined#1%
+ \message{[\noexpand#1is already defined]}%
+ \unexpanded\expandafter\def\expandafter\gobbleddefinition
+ \else
+ \unexpanded\expandafter\def
+ \fi#1}
+
+\unexpanded\def\redefine#1%
+ {\ifdefined#1%
+ \message{[\noexpand#1is redefined]}%
+ \fi
+ \unexpanded\def#1}
+
+\unexpanded\def\definemacro#1%
+ {\ifdefined#1%
+ \message{[\noexpand#1is already defined]}%
+ \unexpanded\expandafter\def\expandafter\gobbleddefinition
+ \else
+ \unexpanded\expandafter\def
+ \fi#1}
+
+% \define\hans{hans}
+% \redefine\hans{hans}
+% \define\hans#1[]#2#3{hans}
+
+%D The next variant fits nicely in the setups syntax:
+%D
+%D \starttyping
+%D \starttexdefinition bagger [#1] #2
+%D oeps
+%D #1
+%D oeps
+%D \stoptexdefinition
+%D
+%D \bagger [a] {b}
+%D \stoptyping
+
+% \starttexdefinition test
+% oeps
+% \stoptexdefinition
+%
+% [\test]
+
+\def\s!unexpanded{unexpanded}
+
+\bgroup \obeylines
+
+\glet\stoptexdefinition\relax
+
+\unexpanded\gdef\starttexdefinition%
+ {\bgroup%
+ \obeylines%
+ \syst_helpers_start_tex_definition}
+
+\gdef\syst_helpers_start_tex_definition#1
+ {\catcode\endoflineasciicode\ignorecatcode%
+ \clf_texdefinition_one{#1}}
+
+\gdef\dostarttexdefinition#1\stoptexdefinition%
+ {\egroup%
+ \clf_texdefinition_two{#1}}
+
+\egroup
+
+% \unexpanded\def\texdefinition#1{\csname\ifcsname#1\endcsname#1\else donothing\fi\endcsname} % todo: a nop cs: char 0 or some corenamespace
+
+\unexpanded\def\texdefinition#1{\begincsname#1\endcsname}
+
+% This is a first variant, more might be added:
+
+\unexpanded\def\starttexcode{\unprotect}
+\unexpanded\def\stoptexcode {\protect}
+
+%D \macros
+%D {newcounter,
+%D increment,decrement}
+%D
+%D Unfortunately the number of \COUNTERS\ in \TEX\ is limited, but fortunately we
+%D can store numbers in a macro. We can increment such pseudo \COUNTERS\ with \type
+%D {\increment}.
+%D
+%D \starttyping
+%D \increment(\counter,20)
+%D \increment(\counter,-4)
+%D \increment(\counter)
+%D \increment\counter
+%D \stoptyping
+%D
+%D After this sequence of commands, the value of \type {\counter} is 20, 16, 17
+%D and~18. Of course there is also the complementary command \type {\decrement}.
+%D
+%D Global assignments are possible too, using \type{\doglobal}:
+%D
+%D \starttyping
+%D \doglobal\increment\counter
+%D \stoptyping
+%D
+%D When \type {\counter} is undefined, it's value is initialized at~0. It is
+%D nevertheless better to define a \COUNTER\ explicitly. One reason could be that
+%D the \COUNTER\ can be part of a test with \type {\ifnum} and this conditional does
+%D not accept undefined macro's. The \COUNTER\ in our example can for instance be
+%D defined with:
+%D
+%D \starttyping
+%D \newcounter\counter
+%D \stoptyping
+%D
+%D The command \type {\newcounter} must not be confused with \type {\newcount}! Of
+%D course this mechanism is much slower than using \TEX's \COUNTERS\ directly. In
+%D practice \COUNTERS\ (and therefore our pseudo counters too) are seldom the
+%D bottleneck in the processing of a text. Apart from some other incompatilities we
+%D want to mention a pitfal when using \type {\ifnum}.
+%D
+%D \starttyping
+%D \ifnum\normalcounter=\pseudocounter \doif \else \doelse \fi
+%D \ifnum\pseudocounter=\normalcounter \doif \else \doelse \fi
+%D \stoptyping
+%D
+%D In the first test, \TEX\ continues it's search for the second number after
+%D reading \type {\pseudocounter}, while in the second test, it stops reading after
+%D having encountered a real one. Tests like the first one therefore can give
+%D unexpected results, for instance execution of \type {\doif} even if both numbers
+%D are unequal.
+
+\def\zerocountervalue{0}
+
+\unexpanded\def\newcounter#1%
+ {\dodoglobal\let#1\zerocountervalue}
+
+%D Nowadays we don't mind a few more tokens if we can gain a bit of speed.
+
+\def\syst_helpers_do_increment#1{\dodoglobal\edef#1{\the\numexpr\ifdefined#1\ifx#1\relax\else#1\fi\fi+\plusone \relax}}
+\def\syst_helpers_do_decrement#1{\dodoglobal\edef#1{\the\numexpr\ifdefined#1\ifx#1\relax\else#1\fi\fi+\minusone\relax}}
+
+\def\syst_helpers_do_do_do_increment#1,#2){\dodoglobal\edef#1{\the\numexpr\ifdefined#1\ifx#1\relax\else#1\fi\fi+#2\relax}}
+\def\syst_helpers_do_do_do_decrement#1,#2){\dodoglobal\edef#1{\the\numexpr\ifdefined#1\ifx#1\relax\else#1\fi\fi-#2\relax}}
+
+\def\syst_helpers_do_do_increment(#1%
+ {\def\m_syst_action_yes{\syst_helpers_do_do_do_increment#1}%
+ \def\m_syst_action_nop{\syst_helpers_do_do_do_increment#1,\plusone}%
+ \doifelsenextcharcs,\m_syst_action_yes\m_syst_action_nop}
+
+\def\syst_helpers_do_do_decrement(#1%
+ {\def\m_syst_action_yes{\syst_helpers_do_do_do_decrement#1}%
+ \def\m_syst_action_nop{\syst_helpers_do_do_do_decrement#1,\plusone}%
+ \doifelsenextcharcs,\m_syst_action_yes\m_syst_action_nop}
+
+\unexpanded\def\increment{\doifelsenextcharcs(\syst_helpers_do_do_increment\syst_helpers_do_increment}
+\unexpanded\def\decrement{\doifelsenextcharcs(\syst_helpers_do_do_decrement\syst_helpers_do_decrement}
+
+\unexpanded\def\fastincrement#1{\dodoglobal\edef#1{\the\numexpr#1+\plusone \relax}}
+\unexpanded\def\fastdecrement#1{\dodoglobal\edef#1{\the\numexpr#1+\minusone\relax}}
+
+\unexpanded\def\incrementvalue#1{\expandafter\increment\csname#1\endcsname}
+\unexpanded\def\decrementvalue#1{\expandafter\decrement\csname#1\endcsname}
+
+%D \macros
+%D {newsignal}
+%D
+%D When writing advanced macros, we cannot do without signaling. A signal is a small
+%D (invisible) kern or penalty that signals the next macro that something just
+%D happened. This macro can take any action depending on the previous signal.
+%D Signals must be unique and the next macro takes care of that.
+%D
+%D \starttyping
+%D \newsignal\somesignal
+%D \stoptyping
+%D
+%D Signals old dimensions and can be used in skips, kerns and tests like \type
+%D {\ifdim}.
+
+\newdimen\maximumsignal % step is about 0.00025pt
+
+\unexpanded\def\newsignal#1%
+ {\ifdefined#1\else
+ \advance\maximumsignal 2\scaledpoint % to be save in rounding
+ \edef#1{\the\maximumsignal}%
+ \fi}
+
+%D \macros
+%D {strippedcsname}
+%D
+%D The next macro can be very useful when using \type {\csname} like in:
+%D
+%D \starttyping
+%D \csname if\strippedcsname\something\endcsname
+%D \stoptyping
+
+\let\checkedstrippedcsname\csstring
+
+%D \macros
+%D {savenormalmeaning}
+%D
+%D We will use this one in:
+
+\unexpanded\def\savenormalmeaning#1%
+ {\ifcsname normal\csstring#1\endcsname \else
+ \expandafter\let\csname normal\csstring#1\endcsname#1%
+ \fi}
+
+%D \macros
+%D {dorecurse,recurselevel,recursedepth,
+%D dostepwiserecurse}
+%D
+%D \TEX\ does not offer us powerfull for||loop mechanisms. On the other hand its
+%D recursion engine is quite unique. We therefore identify the for||looping macros
+%D by this method. The most simple alternative is the one that only needs a number.
+%D
+%D \starttyping
+%D \dorecurse {n} {whatever we want}
+%D \stoptyping
+%D
+%D This macro can be nested without problems and therefore be used in situations
+%D where \PLAIN\ \TEX's \type {\loop} macro ungracefully fails. The current value of
+%D the counter is available in \type {\recurselevel}, before as well as after the
+%D \typ {whatever we wat} stuff.
+%D
+%D \starttyping
+%D \dorecurse % inner loop
+%D {10}
+%D {\recurselevel: % outer value
+%D \dorecurse % inner loop
+%D {\recurselevel} % outer value
+%D {\recurselevel} % inner value
+%D \dorecurse % inner loop
+%D {\recurselevel} % outer value
+%D {\recurselevel} % inner value
+%D \endgraf}
+%D \stoptyping
+%D
+%D In this example the first, second and fourth \type {\recurselevel} concern the
+%D outer loop, while the third and fifth one concern the inner loop. The depth of
+%D the nesting is available for inspection in \type {\recursedepth}.
+%D
+%D Both \type {\recurselevel} and \type {\recursedepth} are macros. The real
+%D \COUNTERS\ are hidden from the user because we don't want any interference.
+
+\newcount\outerrecurse
+\newcount\innerrecurse
+
+\def\recursedepth{\the\outerrecurse}
+\def\recurselevel{0}
+
+\let\syst_helpers_stepwise_next\relax
+
+\installsystemnamespace{recurseindex}
+\installsystemnamespace{recurseaction}
+
+\unexpanded\def\dostepwiserecurse#1#2#3#4% can be made faster by postponing #4
+ {\global\advance\outerrecurse \plusone
+ \expandafter\gdef\csname\??recurseaction\the\outerrecurse\endcsname{#4}%
+ \expandafter\glet\csname\??recurseindex \the\outerrecurse\endcsname\recurselevel
+ \ifnum#3>\zerocount\relax
+ \ifnum#2<#1\relax
+ \let\syst_helpers_stepwise_next\syst_helpers_stepwise_exit
+ \else
+ \let\syst_helpers_stepwise_next\syst_helpers_stepwise_recurse
+ \fi
+ \orelse\ifnum#3<\zerocount\relax
+ \ifnum#1<#2\relax
+ \let\syst_helpers_stepwise_next\syst_helpers_stepwise_exit
+ \else
+ \let\syst_helpers_stepwise_next\syst_helpers_stepwise_reverse
+ \fi
+ \else
+ \let\syst_helpers_stepwise_next\syst_helpers_stepwise_exit
+ \fi\normalexpanded{\syst_helpers_stepwise_next{\number#1}{\number#2}{\number#3}}}
+
+\unexpanded\def\syst_helpers_stepwise_recurse#1#2#3% from to step
+ {\ifnum#1>#2\relax
+ \expandafter\syst_helpers_stepwise_recurse_nop
+ \else
+ \def\recurselevel{#1}%
+ \doubleexpandafter\syst_helpers_stepwise_recurse_yes\expandafter
+ \fi\expandafter{\the\numexpr\recurselevel+#3\relax}{#2}{#3}}
+
+\unexpanded\def\syst_helpers_recurse_content
+ {\csname\??recurseaction\the\outerrecurse\endcsname}
+
+\unexpanded\def\syst_helpers_stepwise_recurse_yes
+ {\syst_helpers_recurse_content
+ \syst_helpers_stepwise_recurse}
+
+\unexpanded\def\syst_helpers_stepwise_reverse#1#2#3% from to step
+ {\ifnum#1<#2\relax
+ \expandafter\syst_helpers_stepwise_recurse_nop
+ \else
+ \def\recurselevel{#1}%
+ \innerrecurse#1\relax
+ \advance\innerrecurse#3\relax
+ \doubleexpandafter\syst_helpers_stepwise_reverse_yes\expandafter
+ \fi\expandafter{\the\innerrecurse}{#2}{#3}}
+
+\unexpanded\def\syst_helpers_stepwise_reverse_yes
+ {\syst_helpers_recurse_content
+ \syst_helpers_stepwise_reverse}
+
+\unexpanded\def\syst_helpers_stepwise_exit
+ {\syst_helpers_stepwise_recurse_nop\relax}
+
+\unexpanded\def\syst_helpers_stepwise_recurse_nop#1#2#3#4%
+ {\expandafter\let\expandafter\recurselevel\csname\??recurseindex\the\outerrecurse\endcsname
+ \global\advance\outerrecurse\minusone}
+
+\unexpanded\def\dorecurse#1%
+ {\dostepwiserecurse\plusone{#1}\plusone}
+
+\def\doexpandedrecurse#1#2% user macro (also was \doxprecurse)
+ {\ifnum#1>\zerocount
+ #2\expandafter\doexpandedrecurse\expandafter{\the\numexpr#1-\plusone\relax}{#2}%
+ \fi}
+
+%D As we can see here, the simple command \type{\dorecurse} is a special case of the
+%D more general:
+%D
+%D \starttyping
+%D \dostepwiserecurse {from} {to} {step} {action}
+%D \stoptyping
+%D
+%D This commands accepts positive and negative steps. Illegal values are handles as
+%D good as possible and the macro accepts numbers and \COUNTERS.
+%D
+%D \starttyping
+%D \dostepwiserecurse {1} {10} {2} {...}
+%D \dostepwiserecurse {10} {1} {-2} {...}
+%D \stoptyping
+%D
+%D Because the simple case is used often, we implement it more efficiently:
+
+\unexpanded\def\dorecurse#1%
+ {\ifcase#1\relax
+ \expandafter\gobbletwoarguments
+ \or
+ \expandafter\syst_helpers_recurse_y
+ \else
+ \expandafter\syst_helpers_recurse_x
+ \fi{#1}}
+
+\unexpanded\def\syst_helpers_recurse_x#1#2%
+ {\global\advance\outerrecurse \plusone
+ \expandafter\gdef\csname\??recurseaction\the\outerrecurse\endcsname{#2}%
+ \expandafter\glet\csname\??recurseindex \the\outerrecurse\endcsname\recurselevel
+ \expandafter\syst_helpers_recurse_indeed\expandafter1\expandafter{\number#1}}
+
+\unexpanded\def\syst_helpers_recurse_y#1#2%
+ {\global\advance\outerrecurse \plusone
+ \expandafter\glet\csname\??recurseindex\the\outerrecurse\endcsname\recurselevel
+ \let\recurselevel\!!plusone
+ #2%
+ \expandafter\let\expandafter\recurselevel\csname\??recurseindex\the\outerrecurse\endcsname
+ \global\advance\outerrecurse \minusone}
+
+\unexpanded\def\syst_helpers_recurse_indeed#1#2% from to
+ {\ifnum#1>#2\relax
+ \expandafter\syst_helpers_recurse_indeed_nop
+ \else
+ \def\recurselevel{#1}%
+ \doubleexpandafter\syst_helpers_recurse_indeed_yes
+ \fi\expandafter{\the\numexpr\recurselevel+\plusone\relax}{#2}}
+
+\unexpanded\def\syst_helpers_recurse_indeed#1#2% from to
+ {\ifnum#1>#2\relax
+ \expandafter\syst_helpers_recurse_indeed_nop
+ \else
+ \def\recurselevel{#1}%
+ \innerrecurse#1\advance\innerrecurse\plusone
+ \doubleexpandafter\syst_helpers_recurse_indeed_yes
+ \fi\expandafter{\the\innerrecurse}{#2}}
+
+\unexpanded\def\syst_helpers_recurse_indeed_yes
+ {\syst_helpers_recurse_content
+ \syst_helpers_recurse_indeed}
+
+\unexpanded\def\syst_helpers_recurse_indeed_nop#1#2#3%
+ {\expandafter\let\expandafter\recurselevel\csname\??recurseindex\the\outerrecurse\endcsname
+ \global\advance\outerrecurse \minusone }
+
+%D \macros
+%D {dowith}
+%D
+%D Here's a loop over whatever is in a list:
+%D
+%D \starttyping
+%D \dowith{a,b,c}{[#1]}
+%D \stoptyping
+
+\unexpanded\def\dowith#1#2%
+ {\def\syst_helpers_with##1{#2}%
+ \normalexpanded{\processcommalist[#1]}\syst_helpers_with}
+
+%D \macros
+%D {doloop,exitloop}
+%D
+%D Sometimes loops are not determined by counters, but by (a combinations of)
+%D conditions. We therefore implement a straightforward loop, which can only be left
+%D when we explictly exit it. Nesting is supported. First we present a more
+%D extensive alternative.
+%D
+%D \starttyping
+%D \doloop
+%D {Some kind of typesetting punishment \par
+%D \ifnum\pageno>100 \exitloop \fi}
+%D \stoptyping
+%D
+%D When needed, one can call for \type {\looplevel} and \type {\loopdepth}.
+
+\let\endofloop\donothing % maybe \syst_helpers_loop_end
+
+\unexpanded\def\doloop#1%
+ {\global\advance\outerrecurse \plusone
+ \expandafter\gdef\csname\??recurseaction\the\outerrecurse\endcsname{#1}%
+ \expandafter\glet\csname\??recurseindex \the\outerrecurse\endcsname\recurselevel
+ \let\endofloop\syst_helpers_loop
+ \syst_helpers_loop1} % no \plusone else \recurselevel wrong
+
+\unexpanded\def\syst_helpers_loop#1%
+ {\def\recurselevel{#1}%
+ \expandafter\syst_helpers_loop_yes\expandafter{\the\numexpr\recurselevel+\plusone\relax}}
+
+\unexpanded\def\syst_helpers_loop_yes
+ {\syst_helpers_recurse_content
+ \endofloop}
+
+\unexpanded\def\syst_helpers_loop_nop#1%
+ {\let\endofloop\syst_helpers_loop % new, permits nested \doloop's
+ \expandafter\let\expandafter\recurselevel\csname\??recurseindex\the\outerrecurse\endcsname
+ \global\advance\outerrecurse\minusone}
+
+\unexpanded\def\exitloop % \exitloop quits at end
+ {\let\endofloop\syst_helpers_loop_nop}
+
+\unexpanded\def\exitloopnow#1\endofloop % \exitloopnow quits directly
+ {\syst_helpers_loop_nop}
+
+%D The loop is executed at least once, so beware of situations
+%D like:
+%D
+%D \starttyping
+%D \doloop {\exitloop some commands}
+%D \stoptyping
+%D
+%D It's just a matter of putting the text into the \type {\if} statement that should
+%D be there anyway, like in:
+%D
+%D \starttyping
+%D \doloop {\ifwhatever \exitloop \else some commands\fi}
+%D \stoptyping
+%D
+%D You can also quit a loop immediately, by using \type
+%D {\exitloopnow} instead. Beware, this is more sensitive
+%D for conditional errors.
+
+%D Krzysztof Leszczynski suggested to provide access to the level by means of a
+%D \type {#1}. I decided to pass the more frequently used level as \type {#1} and
+%D the less favoured depth as \type {#2}. The intended usage is:
+%D
+%D \starttyping
+%D \dorecurse{3}{\definesymbol[test-#1][xx-#1]}
+%D
+%D \def\test{\dorecurse{3}{\definesymbol[test-##1][xx-##1]}} \test
+%D
+%D \symbol[test-1]\quad\symbol[test-2]\quad\symbol[test-3]
+%D \stoptyping
+%D
+%D Since the hashed arguments are expanded, we don't need tricky expansion here.
+%D
+%D \starttyping
+%D \dorecurse{3}{\expanded{\definesymbol[test-\recurselevel][xx-\recurselevel]}}
+%D \stoptyping
+
+\def\syst_helpers_recurse_content
+ {\csname\??recurseaction\the\outerrecurse\expandafter\expandafter\expandafter\endcsname
+ \expandafter\expandafter\expandafter{\expandafter\recurselevel\expandafter}\expandafter{\the\outerrecurse}}
+
+\unexpanded\def\syst_helpers_recurse_x#1#2%
+ {\global\advance\outerrecurse \plusone
+ \expandafter\gdef\csname\??recurseaction\the\outerrecurse\endcsname##1##2{#2}%
+ \expandafter\glet\csname\??recurseindex \the\outerrecurse\endcsname\recurselevel
+ \expandafter\syst_helpers_recurse_indeed\expandafter1\expandafter{\number#1}}
+
+\unexpanded\def\syst_helpers_recurse_y#1#2%
+ {\global\advance\outerrecurse \plusone
+ \expandafter\glet\csname\??recurseindex \the\outerrecurse\endcsname\recurselevel
+ \let\recurselevel\!!plusone
+ \expandafter\gdef\csname\??recurseaction\the\outerrecurse\endcsname##1##2{#2}%
+ \syst_helpers_recurse_content
+ \expandafter\let\expandafter\recurselevel\csname\??recurseindex\the\outerrecurse\endcsname
+ \global\advance\outerrecurse \minusone}
+
+\unexpanded\def\doloop#1%
+ {\global\advance\outerrecurse \plusone
+ \expandafter\gdef\csname\??recurseaction\the\outerrecurse\endcsname##1##2{#1}%
+ \expandafter\glet\csname\??recurseindex \the\outerrecurse\endcsname\recurselevel
+ \let\endofloop\syst_helpers_loop
+ \syst_helpers_loop1} % no \plusone else \recurselevel wrong
+
+\installsystemnamespace{recursestepwise}
+
+\unexpanded\def\dostepwiserecurse#1#2#3#4% can be made faster by postponing #4
+ {\global\advance\outerrecurse \plusone
+ \expandafter\gdef\csname\??recurseaction\the\outerrecurse\endcsname##1##2{#4}%
+ \expandafter\glet\csname\??recurseindex \the\outerrecurse\endcsname\recurselevel
+ \csname\??recursestepwise
+ % we need the x in order to avoid the \relax that tex adds
+ \ifnum#3>\zerocount
+ \ifnum#2<#1x\else d\fi
+ \orelse\ifnum#3<\zerocount
+ \ifnum#1<#2x\else r\fi
+ \fi
+ \expandafter\endcsname\normalexpanded{{\number#1}{\number#2}{\number#3}}}
+ % \expandafter\endcsname\expandafter{\number#1\expandafter}\expandafter{\number#2\expandafter}\expandafter{\number#3}}
+
+\letvalue{\??recursestepwise x}\syst_helpers_stepwise_exit
+\letvalue{\??recursestepwise d}\syst_helpers_stepwise_recurse
+\letvalue{\??recursestepwise r}\syst_helpers_stepwise_reverse
+
+\newcount\fastloopindex
+\newcount\fastloopfinal
+
+\let\m_syst_helpers_fast_loop_cs\relax
+
+\unexpanded\def\dofastloopcs#1%
+ {\fastloopfinal#1\relax
+ \ifcase\fastloopfinal
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\syst_helpers_fast_loop_cs
+ \fi}
+
+\unexpanded\def\syst_helpers_fast_loop_cs#1%
+ {\let\m_syst_helpers_fast_loop_cs#1%
+ \fastloopindex\plusone
+ \syst_helpers_fast_loop_cs_step}
+
+\unexpanded\def\syst_helpers_fast_loop_cs_step
+ {\ifnum\fastloopindex>\fastloopfinal
+ \let\m_syst_helpers_fast_loop_cs\relax
+ \else
+ \m_syst_helpers_fast_loop_cs
+ \advance\fastloopindex\plusone
+ \expandafter\syst_helpers_fast_loop_cs_step
+ \fi}
+
+% Helper:
+
+\unexpanded\def\resetrecurselevel{\let\recurselevel\!!zerocount}
+
+\let\recurselevel\!!zerocount
+
+% \appendtoks \resetrecurselevel \to \everydump
+
+%D \macros
+%D {doloopoverlist}
+%D
+%D \starttyping
+%D \doloopoverlist {red,green,blue} {
+%D \setuppalet[\recursestring]
+%D \doloopoverlist {light,normal,dark} {
+%D \blackrule[color=\recursestring,width=20cm,height=2cm,depth=0cm]\par
+%D }
+%D }
+%D \stoptyping
+%D
+%D or:
+%D
+%D \starttyping
+%D \doloopoverlist {red,green,blue} {
+%D \setuppalet[#1]
+%D \doloopoverlist {light,normal,dark} {
+%D \blackrule[color=##1,width=20cm,height=2cm,depth=0cm]\par
+%D }
+%D }
+%D \stoptyping
+
+\unexpanded\def\doloopoverlist#1#2%
+ {\global\advance\outerrecurse\plusone
+ \expandafter\gdef\csname\??recurseaction\the\outerrecurse\endcsname##1{\edef\recursestring{##1}#2}%
+ \expandafter\glet\csname\??recurseindex \the\outerrecurse\endcsname\recursestring
+ \normalexpanded{\processcommalist[#1]{\expandafter\noexpand\csname\??recurseaction\the\outerrecurse\endcsname}}%
+ \expandafter\let\expandafter\recursestring\csname\??recurseindex\the\outerrecurse\endcsname
+ \global\advance\outerrecurse\minusone}
+
+%D \macros
+%D {newevery,everyline,EveryLine,EveryPar}
+%D
+%D Lets skip to something quite different. It's common use to use \type {\everypar}
+%D for special purposes. In \CONTEXT\ we use this primitive for locating sidefloats.
+%D This means that when user assignments to \type {\everypar} can interfere with
+%D those of the package. We therefore introduce \type {\EveryPar}.
+%D
+%D The same goes for \type {\EveryLine}. Because \TEX\ offers no \type {\everyline}
+%D primitive, we have to call for \type {\everyline} when we are working on a line
+%D by line basis. Just by calling \type {\EveryPar{}} and \type {\EveryLine{}} we
+%D restore the old situation.
+
+% \dorecurse{2}{
+% \expanded{\everypar{before \recurselevel\space}}
+% \EveryPar{x } [before \recurselevel\space x] \par
+% \EveryPar{y } [before \recurselevel\space y] \par
+% \EveryPar{} [before \recurselevel] \par
+% \EveryPar{x } \EveryPar{y } \EveryPar{} [before \recurselevel] \par
+% \EveryPar{y } \everypar{before } [before] \par
+% }
+
+\installsystemnamespace{extraevery}
+
+\unexpanded\def\newevery#1#2%
+ {\ifx#1\everypar\else\newtoks#1\fi% we test for redefinition elsewhere
+ \ifx#2\relax\orelse\ifdefined#2\else
+ \expandafter\newtoks\csname\??extraevery\csstring#1\endcsname
+ \edef#2{\syst_helpers_every#1\csname\??extraevery\csstring#1\endcsname}%
+ \fi}
+
+\unexpanded\def\syst_helpers_every#1#2%
+ {\removetoks\the#2\from#1%
+ \appendtoks\the#2\to #1%
+ #2}
+
+%D This one permits definitions like:
+
+\newevery \everypar \EveryPar % we get a warning which is ok
+\newevery \everyline \EveryLine
+
+%D and how about:
+
+\newtoks \neverypar
+
+\unexpanded\def\forgeteverypar
+ {\everypar{\the\neverypar}}
+
+%D Which we're going to use indeed! When the second argument equals \type {\relax},
+%D the first token list is created unless it is already defined.
+%D
+%D Technically spoken we could have used the method we are going to present in the
+%D visual debugger. First we save the primitive \type{\everypar}:
+%D
+%D \starttyping
+%D \let\normaleverypar=\everypar
+%D \stoptyping
+%D
+%D Next we allocate a \TOKENLIST\ named \type{\everypar}, which means that
+%D \type{\everypar} is no longer a primitive but something like \type{\toks44}.
+%D
+%D \starttyping
+%D \newtoks\everypar
+%D \stoptyping
+%D
+%D Because \TEX\ now executes \type{\normaleverypar} instead of \type{\everypar}, we
+%D are ready to assign some tokens to this internally known and used \TOKENLIST.
+%D
+%D \starttyping
+%D \normaleverypar={all the things the system wants to do \the\everypar}
+%D \stoptyping
+%D
+%D Where the user can provide his own tokens to be expanded every time he expects
+%D them to expand.
+%D
+%D \starttyping
+%D \everypar={something the user wants to do}
+%D \stoptyping
+%D
+%D We don't use this method because it undoubtly leads to confusing situations,
+%D especially when other packages are used, but it's this kind of tricks that make
+%D \TEX\ so powerful.
+
+%D \macros
+%D {convertargument,convertcommand,convertvalue}
+%D
+%D Some persistent experimenting led us to the next macro. This macro converts a
+%D parameter or an expanded macro to it's textual meaning.
+%D
+%D \starttyping
+%D \convertargument ... \to \command
+%D \stoptyping
+%D
+%D For example,
+%D
+%D \starttyping
+%D \convertargument{one \two \three{four}}\to\ascii
+%D \stoptyping
+%D
+%D The resulting macro \type{\ascii} can be written to a file or the terminal
+%D without problems. In \CONTEXT\ we use this macro for generating registers and
+%D tables of contents.
+%D
+%D The second conversion alternative accepts a command:
+%D
+%D \starttyping
+%D \convertcommand\command\to\ascii
+%D \stoptyping
+%D
+%D Both commands accept the prefix \type{\doglobal} for global assignments.
+
+\unexpanded\def\convertvalue#1\to
+ {\expandafter\convertcommand\csname#1\endcsname\to}
+
+\unexpanded\def\defconvertedvalue#1#2% less sensitive for \to
+ {\expandafter\defconvertedcommand\expandafter#1\csname#2\endcsname}
+
+%D \macros
+%D {doifassignmentelse}
+%D
+%D A lot of \CONTEXT\ commands take optional arguments, for instance:
+%D
+%D \starttyping
+%D \dothisorthat[alfa,beta]
+%D \dothisorthat[first=foo,second=bar]
+%D \dothisorthat[alfa,beta][first=foo,second=bar]
+%D \stoptyping
+%D
+%D Although a combined solution is possible, we prefer a seperation. The next
+%D command takes care of propper handling of such multi||faced commands.
+%D
+%D \starttyping
+%D \doifassignmentelse {...} {then ...} {else ...}
+%D \stoptyping
+
+\def\syst_helpers_check_if_assignment_else#1=#2#3^^^^0004{\if#2^^^^0003}%
+\def\syst_helpers_check_else_assignment_if#1=#2#3^^^^0004{\unless\if#2^^^^0003}%
+
+\unexpanded\def\doifelseassignment#1%
+ {\expandafter\syst_helpers_check_if_assignment_else\detokenize{#1}=^^^^0003^^^^0003^^^^0004%
+ \expandafter\secondoftwoarguments
+ \else
+ \expandafter\firstoftwoarguments
+ \fi}
+
+\unexpanded\def\doifelseassignmentcs#1#2#3%
+ {\expandafter\syst_helpers_check_if_assignment_else\detokenize{#1}=^^^^0003^^^^0003^^^^0004%
+ \expandafter#3%
+ \else
+ \expandafter#2%
+ \fi}
+
+\let\doifassignmentelse \doifelseassignment
+\let\doifassignmentelsecs\doifelseassignmentcs
+
+\newif\ifassignment
+
+\unexpanded\def\docheckassignment#1%
+ {\expandafter\syst_helpers_check_if_assignment_else\detokenize{#1}=^^^^0003^^^^0003^^^^0004%
+ \assignmentfalse
+ \else
+ \assignmenttrue
+ \fi}
+
+%D These can be used for cases where we want less tracing noise.
+
+\unexpanded\def\validassignment#1%
+ {\expandafter\syst_helpers_check_else_assignment_if\detokenize{#1}=^^^^0003^^^^0003^^^^0004}
+
+\unexpanded\def\novalidassignment#1%
+ {\expandafter\syst_helpers_check_if_assignment_else\detokenize{#1}=^^^^0003^^^^0003^^^^0004}
+
+%D In \ETEX\ we can use \type {\detokenize} and gain some speed, but in general far
+%D less that 1\% for \type {\convertargument} and nil for \type {\convertcommand}.
+%D This macro is more robust than the pure \TEX\ one, something I found out when
+%D primitives like \type {\jobname} were fed (or something undefined).
+
+\unexpanded\def\convertargument#1\to#2{\dodoglobal\edef#2{\detokenize{#1}}}
+\unexpanded\def\convertcommand #1\to#2{\dodoglobal\edef#2{\expandafter\detokenize\expandafter{#1}}} % hm, only second is also ok
+
+\unexpanded\def\defconvertedargument #1#2{\edef#1{\detokenize{#2}}}
+\unexpanded\def\defconvertedcommand #1#2{\edef#1{\detokenize\expandafter{#2}}}
+\unexpanded\def\edefconvertedargument#1#2{\edef#1{#2}%
+ \edef#1{\detokenize\expandafter{#1}}}
+\unexpanded\def\gdefconvertedargument#1#2{\xdef#1{\detokenize{#2}}}
+\unexpanded\def\gdefconvertedcommand #1#2{\xdef#1{\detokenize\expandafter{#2}}}
+\unexpanded\def\xdefconvertedargument#1#2{\xdef#1{#2}%
+ \xdef#1{\detokenize\expandafter{#1}}}
+
+%D When you try to convert a primitive command, you'll find out that the \ETEX\
+%D method fails on for instance \type {\jobname} in the sense that it returns the
+%D filename instead of just \type {\jobname}. So far this does not give real
+%D problems.
+
+%D This is typically a macro that one comes to after reading the \TEX book
+%D carefully. Even then, the definite solution was found after rereading the \TEX
+%D book. The first implementation was:
+%D
+%D \starttyping
+%D \def\doconvertargument#1->#2\\\\{#2}
+%D \stoptyping
+%D
+%D The \type {-}, the delimiter \type {\\\\} and the the second argument are
+%D completely redundant.
+
+%D \macros
+%D {showvalue}
+%D
+%D Ahandy macro, for testing purposes only:
+
+\unexpanded\def\showvalue#1%
+ {\ifcsname#1\endcsname
+ \expandafter\show\csname#1\endcsname
+ \else
+ \show\undefined
+ \fi}
+
+%D \macros
+%D {doifmeaningelse}
+%D
+%D We can use both commands in testing, but alas, not all meanings expand to
+%D something \type {->}. This is no problem in the \ETEX\ implementation, but since
+%D we want compatibility, we need:
+%D
+%D \starttyping
+%D \doifmeaningelse {\next} {\something} {true} {false}
+%D \stoptyping
+%D
+%D Watch the one level expansion of the second argument.
+
+\unexpanded\def\doifelsemeaning#1#2%
+ {\edef\m_syst_string_one{\normalmeaning#1}%
+ \def \m_syst_string_two{#2}%
+ \edef\m_syst_string_two{\normalmeaning\m_syst_string_two}%
+ \ifx\m_syst_string_one\m_syst_string_two
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\let\doifmeaningelse\doifelsemeaning
+
+%D \macros
+%D {doifsamestringselse,doifsamestring,doifnotsamestring}
+%D
+%D The next comparison macro converts the arguments into expanded strings. This
+%D command can be used to compare for instance \type {\jobname} with a name stored
+%D in a macro.
+%D
+%D \starttyping
+%D \doifelse {\jobname}{oeps}{YES}{NO}
+%D \doifsamestringelse{\jobname}{oeps}{YES}{NO}
+%D \stoptyping
+
+\def\syst_helpers_if_samestring_else#1#2#3#4%
+ {\edef\m_syst_string_one{\detokenize\expandafter{\normalexpanded{#3}}}%
+ \edef\m_syst_string_two{\detokenize\expandafter{\normalexpanded{#4}}}%
+ \ifx\m_syst_string_one\m_syst_string_two\expandafter#1\else\expandafter#2\fi}
+
+\unexpanded\def\doifelsesamestring{\syst_helpers_if_samestring_else\firstoftwoarguments\secondoftwoarguments}
+\unexpanded\def\doifsamestring {\syst_helpers_if_samestring_else\firstofoneargument \gobbleoneargument }
+\unexpanded\def\doifnotsamestring {\syst_helpers_if_samestring_else\gobbleoneargument \firstofoneargument }
+
+\let\doifsamestringelse\doifelsesamestring
+
+%D \macros
+%D {ConvertToConstant,ConvertConstantAfter}
+%D
+%D When comparing arguments with a constant, we can get into trouble when this
+%D argument consists of tricky expandable commands. One solution for this is
+%D converting the argument to a string of unexpandable characters. To make
+%D comparison possible, we have to convert the constant too.
+%D
+%D \starttyping
+%D \ConvertToConstant\doifelse {...} {...} {then ...} {else ...}
+%D \stoptyping
+%D
+%D This construction is only needed when the first argument can give troubles.
+%D Misuse can slow down processing.
+%D
+%D \starttyping
+%D \ConvertToConstant\doifelse{\c!alfa} {\c!alfa}{...}{...}
+%D \ConvertToConstant\doifelse{alfa} {\c!alfa}{...}{...}
+%D \ConvertToConstant\doifelse{alfa} {alfa} {...}{...}
+%D \ConvertToConstant\doifelse{alfa \alfa test}{\c!alfa}{...}{...}
+%D \stoptyping
+%D
+%D In examples~2 and~3 both arguments equal, in~1 and~4 they differ.
+
+\unexpanded\def\ConvertToConstant#1#2#3%
+ {\edef\m_syst_string_one{\expandafter\detokenize\expandafter{#2}}%
+ \edef\m_syst_string_two{\expandafter\detokenize\expandafter{#3}}%
+ #1{\m_syst_string_one}{\m_syst_string_two}}
+
+%D When the argument \type{#1} consists of commands, we had better use
+%D
+%D \starttyping
+%D \ConvertConstantAfter\processaction[#1][...]
+%D \ConvertConstantAfter\doifelse{#1}{\v!something}{}{}
+%D \stoptyping
+%D
+%D This commands accepts things like:
+%D
+%D \starttyping
+%D \v!constant
+%D constant
+%D \hbox to \hsize{\rubish}
+%D \stoptyping
+%D
+%D As we will see in the core modules, this macro permits constructions like:
+%D
+%D \starttyping
+%D \setupfootertexts[...][...]
+%D \setupfootertexts[margin][...][...]
+%D \setupfootertexts[\v!margin][...][...]
+%D \stoptyping
+%D
+%D where \type {...} can be anything legally \TEX.
+
+\unexpanded\def\CheckConstantAfter#1#2%
+ {\expandafter\convertargument\v!prefix!\to\ascii
+ \convertargument#1\to#2\relax
+ \doifelseinstring\ascii{#2}
+ {\expandafter\convertargument#1\to#2}
+ {}}
+
+\unexpanded\def\ConvertConstantAfter#1#2#3%
+ {\CheckConstantAfter{#2}\asciia
+ \CheckConstantAfter{#3}\asciib
+ #1{\asciia}{\asciib}}
+
+%D \macros
+%D {assignifempty}
+%D
+%D We can assign a default value to an empty macro using:
+%D
+%D \starttyping
+%D \assignifempty \macros {default value}
+%D \stoptyping
+%D
+%D We don't explicitly test if the macro is defined.
+
+\unexpanded\def\assignifempty#1#2% can be sped up
+ {\doifsomething{#1}{\def#1{#2}}} % {\doifnot{#1}{}{\def#1{#2}}}
+
+%D \macros
+%D {gobbleuntil,grabuntil,gobbleuntilrelax,
+%D processbetween,processuntil}
+%D
+%D In \TEX\ gobbling usually stand for skipping arguments, so here are our gobbling
+%D macros.
+%D
+%D In \CONTEXT\ we use a lot of \type {\start}||\type {\stop} like constructions.
+%D Sometimes, the \type {\stop} is used as a hard coded delimiter like in: %D
+%D \starttyping
+%D \unexpanded\def\startcommand#1\stopcommand%
+%D {... #1 ...}
+%D \stoptyping
+%D
+%D In many cases the \type {\start}||\type {\stop} pair is defined at format
+%D generation time or during a job. This means that we cannot hardcode the \type
+%D {\stop} criterium. Only after completely understanding \type {\csname} and \type
+%D {\expandafter} I was able to to implement a solution, starting with:
+%D
+%D \starttyping
+%D \grabuntil{stop}\command
+%D \stoptyping
+%D
+%D This commands executes, after having encountered \type {\stop} the command \type
+%D {\command}. This command receives as argument the text preceding the \type
+%D {\stop}. This means that:
+%D
+%D \starttyping
+%D \unexpanded\def\starthello%
+%D {\grabuntil{stophello}\message}
+%D
+%D \starthello Hello world!\stophello
+%D \stoptyping
+%D
+%D results in: \type{\message{Hello world!}}.
+
+\let\syst_helpers_grab_indeed\relax
+
+\unexpanded\def\syst_helpers_grab#1#2%
+ {\def\syst_helpers_grab_indeed##1#1{#2{##1}}\syst_helpers_grab_indeed}
+
+\unexpanded\def\grabuntil#1%
+ {\expandafter\syst_helpers_grab\expandafter{\csname#1\endcsname}}
+
+%D The next command build on this mechanism:
+%D
+%D \starttyping
+%D \processbetween{string}\command
+%D \stoptyping
+%D
+%D Here:
+%D
+%D \starttyping
+%D \processbetween{hello}\message
+%D \starthello Hello again!\stophello
+%D \stoptyping
+%D
+%D leads to: \type{\message{Hello again!}}. The command
+%D
+%D \starttyping
+%D \gobbleuntil{sequence}
+%D \stoptyping
+%D
+%D is related to these commands. This one simply throws away
+%D everything preceding \type{\command}.
+
+\let\syst_helpers_gobble_indeed\relax
+
+\unexpanded\def\processbetween#1#2%
+ {\setvalue{\s!start#1}{\grabuntil{\s!stop#1}{#2}}}
+
+\unexpanded\def\gobbleuntil#1%
+ {\def\syst_helpers_gobble_indeed##1#1{}\syst_helpers_gobble_indeed}
+
+\unexpanded\def\gobbleuntilrelax#1\relax
+ {}
+
+%D The next one simply expands the pickup up tokens.
+%D
+%D \starttyping
+%D \processuntil{sequence}
+%D \stoptyping
+
+\let\syst_helpers_until_indeed\relax
+
+\unexpanded\def\processuntil#1%
+ {\def\syst_helpers_until_indeed##1#1{##1}\syst_helpers_until_indeed}
+
+%D \macros
+%D {groupedcommand}
+%D
+%D Commands often manipulate argument as in:
+%D
+%D \starttyping
+%D \def\doezomaarwat#1{....#1....}
+%D \stoptyping
+%D
+%D A disadvantage of this approach is that the tokens that form \type{#1} are fixed
+%D the the moment the argument is read in. Normally this is no problem, but for
+%D instance verbatim environments adapt the \CATCODES\ of characters and therefore
+%D are not always happy with already fixed tokens.
+%D
+%D Another problem arises when the argument is grouped not by \type {{}} but by
+%D \type {\bgroup} and \type {\egroup}. Such an argument fails, because the \type
+%D {\bgroup} is een as the argument (which is quite normal).
+%D
+%D The next macro offers a solution for both unwanted situations:
+%D
+%D \starttyping
+%D \groupedcommand {before} {after}
+%D \stoptyping
+%D
+%D Which can be used like:
+%D
+%D \starttyping
+%D \def\cite%
+%D {\groupedcommand{\rightquote\rightquote}{\leftquote\leftquote}}
+%D \stoptyping
+%D
+%D This command is equivalent to, but more 'robust' than:
+%D
+%D \starttyping
+%D \def\cite#1%
+%D {\rightquote\rightquote#1\leftquote\leftquote}
+%D \stoptyping
+%D
+%D \starttyping
+%D \def\rightword%
+%D {\groupedcommand{\hfill\hbox}{\parfillskip\zeropoint}}
+%D
+%D .......... \rightword{the right way}
+%D \stoptyping
+%D
+%D Here \TEX\ typesets \type {\bf the right way} unbreakable at the end of the line.
+%D The solution mentioned before does not work here. We also handle
+%D
+%D \starttyping
+%D to be \bold{bold} or not, that's the question
+%D \stoptyping
+%D
+%D and
+%D
+%D \starttyping
+%D to be {\bold bold} or not, that's the question
+%D \stoptyping
+%D
+%D This alternative checks for a \type {\bgroup} token first. The internal
+%D alternative does not accept the box handling mentioned before, but further
+%D nesting works all right. The extra \type {\bgroup}||\type {\egroup} is needed to
+%D keep \type {\m_syst_helpers_handle_group_after} both into sight and local.
+
+\let\m_syst_helpers_handle_group_after \relax
+\let\m_syst_helpers_handle_group_before\relax
+
+\unexpanded\def\syst_helpers_handle_group_nop
+ {\ifnum\currentgrouptype=\semisimplegroupcode
+ \expandafter\syst_helpers_handle_group_nop_a
+ \else
+ \expandafter\syst_helpers_handle_group_nop_b
+ \fi}
+
+\def\syst_helpers_handle_group_nop_a
+ {\begingroup
+ \aftergroup\m_syst_helpers_handle_group_a
+ \aftergroup\endgroup
+ \m_syst_helpers_handle_group_b}
+
+\def\syst_helpers_handle_group_nop_b
+ {\bgroup
+ \aftergroup\m_syst_helpers_handle_group_a
+ \aftergroup\egroup
+ \m_syst_helpers_handle_group_b}
+
+\unexpanded\def\syst_helpers_handle_group_normal
+ {\bgroup
+ \afterassignment\m_syst_helpers_handle_group_normal_before
+ \let\next=}
+
+\def\m_syst_helpers_handle_group_normal_before
+ {\bgroup
+ \m_syst_helpers_handle_group_b
+ \bgroup
+ \aftergroup\m_syst_helpers_handle_group_a
+ \aftergroup\egroup
+ \aftergroup\egroup}
+
+\unexpanded\def\syst_helpers_handle_group_simple% no inner group (so no kerning interference)
+ {\bgroup
+ \afterassignment\m_syst_helpers_handle_group_simple_before
+ \let\next=}
+
+\def\m_syst_helpers_handle_group_simple_before
+ {\bgroup
+ \aftergroup\m_syst_helpers_handle_group_simple_after
+ \m_syst_helpers_handle_group_b}
+
+\def\m_syst_helpers_handle_group_simple_after
+ {\m_syst_helpers_handle_group_a
+ \egroup}%
+
+\unexpanded\def\syst_helpers_handle_group_pickup% no inner group (so no kerning interference)
+ {\bgroup
+ \afterassignment\m_syst_helpers_handle_group_pickup_before
+ \let\next=}
+
+\def\m_syst_helpers_handle_group_pickup_before
+ {\bgroup
+ \aftergroup\m_syst_helpers_handle_group_a
+ \aftergroup\egroup
+ \aftergroup\m_syst_helpers_handle_group_p
+ \m_syst_helpers_handle_group_b}
+
+\unexpanded\def\syst_helpers_handle_group_nop_x
+ {\ifnum\currentgrouptype=\semisimplegroupcode
+ \begingroup
+ \aftergroup\endgroup
+ \else
+ \bgroup
+ \aftergroup\egroup
+ \fi
+ \m_syst_helpers_handle_group_b}
+
+\unexpanded\def\syst_helpers_handle_group_normal_x
+ {\bgroup
+ \afterassignment\m_syst_helpers_handle_group_normal_before_x
+ \let\next=}
+
+\def\m_syst_helpers_handle_group_normal_before_x
+ {\bgroup
+ \m_syst_helpers_handle_group_b
+ \bgroup
+ \aftergroup\egroup
+ \aftergroup\egroup}
+
+%D I considered it a nuisance that
+%D
+%D \starttyping
+%D \color[green]
+%D {as grass}
+%D \stoptyping
+%D
+%D was not interpreted as one would expect. This is due to the fact that \type
+%D {\futurelet} obeys blank spaces, and a line||ending token is treated as a blank
+%D space. So the final implementation became:
+
+\unexpanded\def\groupedcommand#1#2%
+ {\def\m_syst_helpers_handle_group_b{#1}%
+ \def\m_syst_helpers_handle_group_a{#2}%
+ \futureexpandis\bgroup\syst_helpers_handle_group_normal\syst_helpers_handle_group_nop}
+
+\unexpanded\def\groupedcommandcs#1#2%
+ {\let\m_syst_helpers_handle_group_b#1%
+ \let\m_syst_helpers_handle_group_a#2%
+ \futureexpandis\bgroup\syst_helpers_handle_group_normal\syst_helpers_handle_group_nop}
+
+\unexpanded\def\simplegroupedcommand#1#2%
+ {\def\m_syst_helpers_handle_group_b{#1}%
+ \def\m_syst_helpers_handle_group_a{#2}%
+ \futureexpandis\bgroup\syst_helpers_handle_group_simple\syst_helpers_handle_group_nop}
+
+\unexpanded\def\pickupgroupedcommand#1#2#3%
+ {\def\m_syst_helpers_handle_group_b{#1}%
+ \def\m_syst_helpers_handle_group_a{#2}%
+ \def\m_syst_helpers_handle_group_p{#3}%
+ \futureexpandis\bgroup\syst_helpers_handle_group_pickup\syst_helpers_handle_group_nop}
+
+\unexpanded\def\triggergroupedcommand#1%
+ {\def\m_syst_helpers_handle_group_b{#1}%
+ \futureexpandis\bgroup\syst_helpers_handle_group_normal_x\syst_helpers_handle_group_nop_x}
+
+\unexpanded\def\triggergroupedcommandcs#1%
+ {\let\m_syst_helpers_handle_group_b#1%
+ \futureexpandis\bgroup\syst_helpers_handle_group_normal_x\syst_helpers_handle_group_nop_x}
+
+%D Users should be aware of the fact that grouping can interfere with ones paragraph
+%D settings that are executed after the paragraph is closed. One should therefore
+%D explictly close the paragraph with \type {\par}, else the settings will be
+%D forgotten and not applied. So it's:
+%D
+%D \starttyping
+%D \def\BoldRaggedCenter%
+%D {\groupedcommand{\raggedcenter\bf}{\par}}
+%D \stoptyping
+
+%D \macros
+%D {checkdefined}
+%D
+%D The bigger the system, the greater the change that user defined commands collide
+%D with those that are part of the system. The next macro gives a warning when a
+%D command is already defined. We considered blocking the definition, but this is
+%D not always what we want.
+%D
+%D \starttyping
+%D \checkdefined {category} {class} {command}
+%D \stoptyping
+%D
+%D The user is warned with the suggestion to use \type {CAPITALS}. This suggestion
+%D is feasible, because \CONTEXT only defines lowcased macros.
+
+\unexpanded\def\showdefinederror#1#2%
+ {\writestatus\m!system{#1 #2 replaces a macro, use CAPITALS!}}
+
+\unexpanded\def\checkdefined#1#2#3%
+ {\doifdefined{#3}{\showdefinederror{#2}{#3}}}
+
+%D \macros
+%D {GotoPar,GetPar}
+%D
+%D Typesetting a paragraph in a special way can be done by first grabbing the
+%D contents of the paragraph and processing this contents grouped. The next macro
+%D for instance typesets a paragraph in boldface.
+%D
+%D \starttyping
+%D \def\remark#1\par%
+%D {\bgroup\bf#1\egroup}
+%D \stoptyping
+%D
+%D This macro has to be called like
+%D
+%D \starttyping
+%D \remark some text ... ending with \par
+%D \stoptyping
+%D
+%D Instead of \type {\par} we can of course use an empty line. When we started
+%D typesetting with \TEX, we already had produced lots of text in plain \ASCII. In
+%D producing such simple formatted texts, we adopted an open layout, and when
+%D switching to \TEX, we continued this open habit. Although \TEX\ permits a cramped
+%D and badly formatted source, it adds to confusion and sometimes introduces errors.
+%D So we prefer:
+%D
+%D \starttyping
+%D \remark
+%D
+%D some text ... ending with an empty line
+%D \stoptyping
+%D
+%D We are going to implement a mechanism that allows such open specifications. The
+%D definition of the macro handling \type {\remark} becomes:
+%D
+%D \starttyping
+%D \def\remark%
+%D {\BeforePar{\bgroup\bf}%
+%D \AfterPar{\egroup}%
+%D \GetPar}
+%D \stoptyping
+%D
+%D A macro like \type {\GetPar} can be defined in several ways. The recent version,
+%D the fourth one in a row, originally was far more complicated, but some
+%D functionality has been moved to other macros.
+%D
+%D We start with the more simple but in some cases more appropriate alternative is
+%D \type {\GotoPar}. This one leaves \type {\par} unchanged and is therefore more
+%D robust. On the other hand, \type {\AfterPar} is not supported.
+
+\newtoks\BeforePar
+\newtoks\AfterPar
+
+\def\redowithpar\par
+ {\doifelsenextchar\par\redowithpar\dodowithpar}%
+
+\def\dowithpar#1#2%
+ {\def\dodowithpar##1\par{#1##1#2}%
+ \redowithpar\par}
+
+\def\redogotopar\par
+ {\doifelsenextchar\par\redogotopar\dodogotopar}%
+
+\def\dogotopar#1%
+ {\def\dodogotopar{#1}%
+ \redogotopar\par}
+
+\def\dogotoparcs#1%
+ {\let\dodogotopar#1%
+ \redogotopar\par}
+
+\unexpanded\def\GetPar
+ {\expanded
+ {\dowithpar
+ {\the\BeforePar
+ \BeforePar\emptytoks}
+ {\the\AfterPar
+ \BeforePar\emptytoks
+ \AfterPar\emptytoks}}}
+
+\unexpanded\def\GotoPar
+ {\expanded
+ {\dogotopar
+ {\the\BeforePar
+ \BeforePar\emptytoks}}}
+
+%D \macros
+%D {dowithpargument,dowithwargument}
+%D
+%D The next macros are a variation on \type {\GetPar}. When macros expect an
+%D argument, it interprets a grouped sequence of characters a one token. While this
+%D adds to robustness and less ambiguous situations, we sometimes want to be a bit
+%D more flexible, or at least want to be a bit more tolerant to user input.
+%D
+%D We start with a commands that acts on paragraphs. This
+%D command is called as:
+%D
+%D \starttyping
+%D \dowithpargument\command
+%D \dowithpargument{\command ... }
+%D \stoptyping
+%D
+%D In \CONTEXT\ we use this one to read in the titles of chapters, sections etc. The
+%D commands responsible for these activities accept several alternative ways of
+%D argument passing. In these examples, the \type {\par} can be omitted when an
+%D empty line is present.
+%D
+%D \starttyping
+%D \command{...}
+%D \command ... \par
+%D \command
+%D {...}
+%D \command
+%D ... \par
+%D \stoptyping
+
+\let\syst_helpers_next_par\relax
+\let\syst_helpers_next_arg\relax
+
+\unexpanded\def\dowithpargument#1%
+ {\def\syst_helpers_next_par##1 \par{#1{##1}}%
+ \def\syst_helpers_next_arg##1{#1{##1}}%
+ \doifelsenextbgroup\syst_helpers_next_arg{\doifelsenextchar\par{#1{}}\syst_helpers_next_par}}
+
+%D The \type {p} in the previous command stands for paragraph. When we want to act
+%D upon words we can use the \type{w} alternative.
+%D
+%D \starttyping
+%D \dowithwargument\command
+%D \dowithwargument{... \command ...}
+%D \stoptyping
+%D
+%D The main difference bwteen two alternatives is in the handling of \type {\par}'s.
+%D This time the space token acts as a delimiter.
+%D
+%D \starttyping
+%D \command{...}
+%D \command ...
+%D \command
+%D {...}
+%D \command
+%D ...
+%D \stoptyping
+
+\let\syst_helpers_next_war\relax
+\let\syst_helpers_next_arg\relax
+
+\unexpanded\def\dowithwargument#1%
+ {\def\syst_helpers_next_war##1 {#1{##1}}%
+ \def\syst_helpers_next_arg##1{#1{##1}}%
+ \doifelsenextbgroup\syst_helpers_next_arg\syst_helpers_next_war}
+
+%D \macros
+%D {dorepeat,dorepeatwithcommand}
+%D
+%D When doing repetitive tasks, we stromgly advice to use \type {\dorecurse}. The
+%D next alternative however, suits better some of the \CONTEXT\ interface commands.
+%D
+%D \starttyping
+%D \dorepeat[n*\command]
+%D \stoptyping
+%D
+%D The value of the used \COUNTER\ can be called within
+%D \type{\command} by \type{\repeater}.
+%D
+%D A slightly different alternative is:
+%D
+%D \starttyping
+%D \dorepeatwithcommand[n*{...}]\command
+%D \stoptyping
+%D
+%D When we call for something like:
+%D
+%D \starttyping
+%D \dorepeatwithcommand[3*{Hello}]\message
+%D \stoptyping
+%D
+%D we get ourselves three \type {\message{Hello}} messages in a row. In both
+%D commands, the \type {n*} is optional. When this specification is missing, the
+%D command executes once.
+
+\unexpanded\def\dorepeatwithcommand[#1]%
+ {\syst_helpers_repeat_with_command#1*\empty*\relax}
+
+\def\syst_helpers_repeat_with_command#1*#2#3*#4\relax#5%
+ {\ifx#2\empty\syst_helpers_repeat_with_command_again[#1]#5\else\syst_helpers_repeat_with_command_indeed{#1}{#2}{#3}#5\fi}
+
+\def\syst_helpers_repeat_with_command_indeed#1#2#3#4%
+ {\ifx#2\empty % redundant but gives cleaner extensions
+ #4{#1}%
+ \orelse\ifnum#1<\zerocount
+ %\normalexpanded{\dorecurse{\number-\number#1}}{#4{-#2#3}}%
+ \dorecurse{-#1}{#4{-#2#3}}%
+ \orelse\ifx#2+%
+ \dorecurse{#1}{#4{#3}}%
+ \else
+ \dorecurse{#1}{#4{#2#3}}%
+ \fi}
+
+\def\syst_helpers_repeat_with_command_again[#1]#2%
+ {#2{#1}}
+
+%D The extension hook permits something like:
+%D
+%D \starttyping
+%D \bgroup
+%D
+%D \catcode`\*=\superscriptcatcode
+%D
+%D \gdef\syst_helpers_repeat_with_command_again[#1]%
+%D {\redodorepeatwithcommand#1*\empty*\relax}
+%D
+%D \gdef\redodorepeatwithcommand#1*#2#3*#4\relax#5%
+%D {\syst_helpers_repeat_with_command_indeed{#1}{#2}{#3}#5}
+%D
+%D \egroup
+%D \stoptyping
+%D
+%D although one may wonder if changing the catcode of \type {*} is wise.
+
+%D \macros
+%D {doifstringinstringelse}
+%D
+%D The next macro is meant for situations where both strings are macros. This save
+%D some unneeded expansion.
+%D
+%D \starttyping
+%D \def\doifstringinstringelse#1#2%
+%D {\syst_helpers_do_if_in_string_else#1#2%
+%D \expandafter\firstoftwoarguments
+%D \else
+%D \expandafter\secondoftwoarguments
+%D \fi}
+%D \stoptyping
+%D
+%D A bit faster is:
+
+\def\syst_helpers_if_instring_else_indeed#1%
+ {\if#1@%
+ \expandafter\secondoftwoarguments
+ \else
+ \expandafter\firstoftwoarguments
+ \fi}
+
+\def\doifelsestringinstring#1#2%
+ {\expandafter\def\expandafter\syst_helpers_if_instring_else\expandafter##\expandafter1#1##2##3^^^^0004%
+ {\syst_helpers_if_instring_else_indeed##2}%
+ \expandafter\expandafter\expandafter\syst_helpers_if_instring_else\expandafter#2#1@@^^^^0004}
+
+\let\doifstringinstringelse\doifelsestringinstring
+
+%D \macros
+%D {appendtoks,prependtoks,appendtoksonce,prependtoksonce,
+%D doifintokselse,flushtoks,dotoks}
+%D
+%D We use tokenlists sparsely within \CONTEXT, because the comma separated lists are
+%D more suitable for the user interface. Nevertheless we have:
+%D
+%D \starttyping
+%D (\doglobal) \appendtoks ... \to\tokenlist
+%D (\doglobal) \prependtoks ... \to\tokenlist
+%D (\doglobal) \flushtoks\tokenlist
+%D \dotoks\tokenlist
+%D \stoptyping
+%D
+%D These macros are clones of the ones implemented in page~378 of Knuth's \TEX book.
+
+\newtoks\t_syst_helpers_scratch
+\let \m_syst_helpers_scratch\empty
+
+\unexpanded\def\appendtoks#1\to#2%
+ {\ifx\dodoglobal\relax
+ \expandafter\toksapp
+ \else
+ \resetglobal
+ \expandafter\gtoksapp
+ \fi#2{#1}}
+
+\unexpanded\def\prependtoks#1\to#2%
+ {\ifx\dodoglobal\relax
+ \expandafter\tokspre
+ \else
+ \resetglobal
+ \expandafter\gtokspre
+ \fi#2{#1}}
+
+\def\syst_helpers_append_toks_indeed
+ {\ifx\dodoglobal\relax
+ \expandafter\toksapp
+ \else
+ \resetglobal
+ \expandafter\gtoksapp
+ \fi\m_syst_helpers_scratch\t_syst_helpers_scratch}
+
+\def\syst_helpers_prepend_toks_indeed
+ {\ifx\dodoglobal\relax
+ \expandafter\tokspre
+ \else
+ \resetglobal
+ \expandafter\gtokspre
+ \fi\m_syst_helpers_scratch\t_syst_helpers_scratch}
+
+\unexpanded\def\appendtoksonce#1\to#2%
+ {\let\m_syst_helpers_scratch#2%
+ \t_syst_helpers_scratch{#1}%
+ \doifelseintoks\t_syst_helpers_scratch\m_syst_helpers_scratch
+ \donothing
+ \syst_helpers_append_toks_indeed}
+
+\unexpanded\def\prependtoksonce#1\to#2%
+ {\let\m_syst_helpers_scratch#2%
+ \t_syst_helpers_scratch{#1}%
+ \doifelseintoks\t_syst_helpers_scratch\m_syst_helpers_scratch
+ \donothing
+ \syst_helpers_prepend_toks_indeed}
+
+%D The test macro:
+
+\unexpanded\def\doifelseintoks#1#2% #1 en #2 zijn toks
+ {\edef\asciia{\detokenize\expandafter{\the#1}}%
+ \edef\asciib{\detokenize\expandafter{\the#2}}%
+ \doifelsestringinstring\asciia\asciib}
+
+\let\doifintokselse\doifelseintoks
+
+%D Moved from \type {lxml-ini.tex} to here. This one is for generators that collect
+%D stuff piecewise, which is sometimes hard on mechanisms that grab content using
+%D delimiters:
+%D
+%D \starttyping
+%D \startcollecting
+%D \startcollect \bTABLE \stopcollect
+%D \startcollect \bTR \stopcollect
+%D \startcollect \bTD \stopcollect
+%D \startcollect foo\stopcollect
+%D \startcollect \eTD \stopcollect
+%D \startcollect \bTD \stopcollect
+%D \startcollect bar\stopcollect
+%D \startcollect \eTD \stopcollect
+%D \startcollect \eTR \stopcollect
+%D \startcollect \eTABLE \stopcollect
+%D \stopcollecting
+%D \stoptyping
+
+\newtoks \collectingtoks
+
+\unexpanded\def\startcollect #1\stopcollect {\toksapp \collectingtoks{#1}}
+\unexpanded\def\startexpandedcollect#1\stopexpandedcollect{\etoksapp\collectingtoks{#1}}
+
+\unexpanded\def\startcollecting{\collectingtoks\emptytoks}
+\unexpanded\def\stopcollecting {\the\collectingtoks}
+
+\unexpanded\def\collect {\toksapp \collectingtoks}
+\unexpanded\def\collectexpanded{\etoksapp\collectingtoks}
+
+%D A nice one too:
+
+% {\scratchtoks{abc} \removetoks b\from\scratchtoks [\the\scratchtoks]}
+% {\scratchtoks{abc} \removetoks x\from\scratchtoks [\the\scratchtoks]}
+% {\scratchtoks{} \removetoks x\from\scratchtoks [\the\scratchtoks]}
+% {\scratchtoks{xaa} \removetoks x\from\scratchtoks [\the\scratchtoks]}
+% {\scratchtoks{a\relax b} \removetoks \relax\from\scratchtoks [\showthe\scratchtoks]}
+
+\unexpanded\def\removetoks#1\from#2%
+ {\def\syst_helpers_remove_toks##1#1##2\empty\empty\empty##3^^^^0004%
+ {\def\m_syst_string_one{##3}%
+ \ifx\m_syst_string_one\empty#2{##1}\else#2{##1##2}\fi}%
+ \expandafter\syst_helpers_remove_toks\the#2\empty\empty\empty#1\empty\empty\empty^^^^0004}
+
+%D Also:
+
+\unexpanded\def\appendetoks#1\to#2%
+ {\ifx\dodoglobal\relax
+ \expandafter\etoksapp
+ \else
+ \resetglobal
+ \expandafter\xtoksapp
+ \fi#2{#1}}
+
+\unexpanded\def\prependetoks#1\to#2%
+ {\ifx\dodoglobal\relax
+ \expandafter\etokspre
+ \else
+ \resetglobal
+ \expandafter\xtokspre
+ \fi#2{#1}}
+
+%D Hm.
+
+\unexpanded\def\flushtoks#1% nb: can reassign to #1 again, hence the indirectness
+ {\t_syst_helpers_scratch#1\relax
+ \dodoglobal#1\emptytoks
+ \the\t_syst_helpers_scratch\relax}
+
+\let\dotoks\the
+
+%D \macros
+%D {beforesplitstring,aftersplitstring}
+%D
+%D These both commands split a string at a given point in two
+%D parts, so \type{x.y} becomes \type{x} or \type{y}.
+%D
+%D \starttyping
+%D \beforesplitstring test.tex\at.\to\filename
+%D \aftersplitstring test.tex\at.\to\extension
+%D \stoptyping
+%D
+%D The first routine looks (and is indeed) a bit simpler than the second one. The
+%D alternative looking more or less like the first one did not always give the
+%D results we needed. Both implementations show some insight in the manipulation of
+%D arguments.
+
+\let\syst_helpers_split_string\relax
+
+\unexpanded\def\beforesplitstring#1\at#2\to#3%
+ {\def\syst_helpers_split_string##1#2##2#2##3\\%
+ {\def#3{##1}}%
+ \expandafter\syst_helpers_split_string#1#2#2\\}
+
+\unexpanded\def\aftersplitstring#1\at#2\to#3%
+ {\def\syst_helpers_split_string##1#2##2@@@##3\\%
+ {\def#3{##2}}%
+ \expandafter\syst_helpers_split_string#1@@@#2@@@\\}
+
+%D \macros
+%D {splitstring,greedysplitstring}
+%D
+%D A bonus macro.
+
+\unexpanded\def\splitstring#1\at#2\to#3\and#4%
+ {\def\syst_helpers_split_string##1#2##2\empty\empty\empty##3\\%
+ {\def#3{##1}%
+ \def\syst_helpers_split_string{##3}%
+ \ifx\syst_helpers_split_string\empty
+ \let#4\empty
+ \else
+ \def#4{##2}%
+ \fi}%
+ \expandafter\syst_helpers_split_string#1\empty\empty\empty#2\empty\empty\empty\\}
+
+\unexpanded\def\greedysplitstring#1\at#2\to#3\and#4%
+ {\edef\asciib{#1}%
+ \let\asciic\asciib
+ \let#3\empty
+ \let#4\empty
+ \doloop
+ {\expandafter\splitstring\asciib\at#2\to\asciia\and\asciib
+ \ifx\asciib\empty
+ \exitloop
+ \else
+ % not \edef#3{\ifx#3\empty\else#3#2\fi\asciia} else
+ % /root/path fails because then #3==empty
+ \edef#3{\ifcase\recurselevel\or\else#3#2\fi\asciia}%
+ \let#4\asciib
+ \fi}%
+ \ifx#3\empty\let#3\asciic\fi}
+
+%D \macros
+%D {beforetestandsplitstring,
+%D aftertestandsplitstring,
+%D testandsplitstring}
+
+\unexpanded\def\beforetestandsplitstring#1\at#2\to#3%
+ {\def\syst_helpers_split_string##1#2##2#2##3##4\\%
+ {\ifx##3\empty\let#3\empty\else\def#3{##1}\fi}%
+ \expandafter\syst_helpers_split_string#1#2#2\empty\\}
+
+\unexpanded\def\aftertestandsplitstring#1\at#2\to#3%
+ {\def\syst_helpers_split_string ##1#2##2@@@##3##4\\%
+ {\ifx##3\empty\let#3\empty\else\def#3{##2}\fi}%
+ \expandafter\syst_helpers_split_string #1@@@#2@@@\empty\\}
+
+\def\testandsplitstring#1\at#2\to#3\and#4%
+ {\def\syst_helpers_split_string##1#2##2#2##3##4\\%
+ {\ifx##3\empty\let#3\empty\let#4\empty\else\def#3{##1}\def#4{##2}\fi}%
+ \expandafter\syst_helpers_split_string#1#2#2\empty\\}
+
+%D \macros
+%D {splitatperiod,
+%D {splitatcomma,
+%D splitatasterisk,
+%D splitatcolon,
+%D splitatcolons}
+
+\unexpanded\def\splitatperiod #1{\normalexpanded{\syst_helpers_splitatperiod #1}..\relax}
+\unexpanded\def\splitatcomma #1{\normalexpanded{\syst_helpers_splitatcomma #1},,\relax} % not at ", "
+\unexpanded\def\splitatasterisk#1{\normalexpanded{\syst_helpers_splitatasterisk#1}**\relax}
+\unexpanded\def\splitatcolon #1{\normalexpanded{\syst_helpers_splitatcolon #1}::\relax}
+\unexpanded\def\splitatcolons #1{\normalexpanded{\syst_helpers_splitatcolons #1}::::\relax}
+
+\unexpanded\def\syst_helpers_splitatperiod #1.#2.#3\relax#4#5{\def#4{#1}\def#5{#2}}
+\unexpanded\def\syst_helpers_splitatcomma #1,#2,#3\relax#4#5{\def#4{#1}\def#5{#2}}
+\unexpanded\def\syst_helpers_splitatasterisk #1*#2*#3\relax#4#5{\def#4{#1}\def#5{#2}}
+\unexpanded\def\syst_helpers_splitatcolon #1:#2:#3\relax#4#5{\def#4{#1}\def#5{#2}}
+\unexpanded\def\syst_helpers_splitatcolons #1::#2::#3\relax#4#5{\edef#4{#1}\edef#5{#2}}
+
+%D \macros
+%D {removesubstring}
+%D
+%D A first application of the two routines defined above is:
+%D
+%D \starttyping
+%D \removesubstring-\from first-last\to\nothyphenated
+%D \stoptyping
+%D
+%D Which in terms of \TEX\ looks like:
+
+\unexpanded\def\removesubstring#1\from#2\to#3%
+ {\splitstring#2\to\m_syst_string_one\and\m_syst_string_two
+ \dodoglobal#3{\m_syst_string_one\m_syst_string_two}}
+
+%D \macros
+%D {appendtocommalist,prependtocommalist,
+%D addtocommalist,removefromcommalist}
+%D
+%D When working with comma separated lists, one sooner or later want the tools to
+%D append or remove items from such a list. When we add an item, we first check if
+%D it's already there. This means that every item in the list is unique.
+%D
+%D \starttyping
+%D \addtocommalist {alfa} \name
+%D \addtocommalist {beta} \name
+%D \addtocommalist {gamma} \name
+%D \removefromcommalist {beta} \name
+%D \stoptyping
+%D
+%D These commands can be prefixed with \type {\doglobal}. The implementation of the
+%D second command is more complecated, because we have to take leading spaces into
+%D account. Keep in mind that users may provide lists with spaces after the commas.
+%D When one item is left, we also have to get rid of trailing spaces.
+%D
+%D \starttyping
+%D \def\words{alfa, beta, gamma, delta}
+%D \def\words{alfa,beta,gamma,delta}
+%D \stoptyping
+%D
+%D Removing an item takes more time than adding one. A fast appending alternative,
+%D without any testing, is also provided:
+%D
+%D \starttyping
+%D \appendtocommalist {something} \name
+%D \prependtocommalist {something} \name
+%D \stoptyping
+%D
+%D This can be implemented as follows:
+%D
+%D \starttyping
+%D \def\appendtocommalist#1#2%
+%D {\ifx#2\empty
+%D \dodoglobal\edef#2{#1}%
+%D \else % no test on empty
+%D \dodoglobal\edef#2{#2,#1}%
+%D \fi}
+%D
+%D \def\prependtocommalist#1#2%
+%D {\ifx#2\empty
+%D \dodoglobal\edef#2{#1}%
+%D \else % no test on empty
+%D \dodoglobal\edef#2{#1,#2}%
+%D \fi}
+%D \stoptyping
+%D
+%D The faster alternatives are:
+
+\unexpanded\def\appendtocommalist#1#2%
+ {\dodoglobal\edef#2{\ifx#2\empty\else#2,\fi#1}}
+
+\unexpanded\def\prependtocommalist#1#2%
+ {\dodoglobal\edef#2{#1\ifx#2\empty\else,#2\fi}}
+
+\unexpanded\def\addtocommalist#1#2% {item} \cs
+ {\rawdoifelseinset{#1}#2\resetglobal
+ {\dodoglobal\edef#2{\ifx#2\empty\else#2,\fi#1}}}
+
+\unexpanded\def\pretocommalist#1#2% {item} \cs
+ {\rawdoifelseinset{#1}#2\resetglobal
+ {\dodoglobal\edef#2{#1\ifx#2\empty\else,#2\fi}}}
+
+\unexpanded\def\robustdoifelseinset#1#2%
+ {\edef\m_syst_string_one{\detokenize\expandafter{\normalexpanded{#1}}}%
+ \edef\m_syst_string_two{\detokenize\expandafter{\normalexpanded{#2}}}%
+ \rawdoifelseinset\m_syst_string_one\m_syst_string_two}
+
+\let\robustdoifinsetelse\robustdoifelseinset
+
+\unexpanded\def\robustaddtocommalist#1#2% {item} \cs
+ {\robustdoifelseinset{#1}#2\resetglobal
+ {\dodoglobal\edef#2{\ifx#2\empty\else#2,\fi#1}}}
+
+\unexpanded\def\robustpretocommalist#1#2% {item} \cs
+ {\robustdoifelseinset{#1}#2\resetglobal
+ {\dodoglobal\edef#2{#1\ifx#2\empty\else,#2\fi}}}
+
+\unexpanded\def\xsplitstring#1#2% \cs {str}
+ {\def\syst_helpers_split_string##1,#2,##2,#2,##3\\%
+ {\edef\m_syst_string_one{\bcleanedupcommalist##1\empty\empty\relax}%
+ \edef\m_syst_string_two{\acleanedupcommalist##2,,\relax}}%
+ \expandafter\syst_helpers_split_string\expandafter,#1,,#2,,#2,\\}
+
+\def\bcleanedupcommalist#1#2#3\relax{\if#1,\else#1\fi\if#2,\else#2\fi#3}
+\def\bcleanedupcommalist#1#2\relax{\if#1,\else#1\fi#2}
+\def\acleanedupcommalist#1,,#2\relax{#1}
+
+\unexpanded\def\removefromcommalist#1#2% to be sped up
+ {\rawdoifelseinset{#1}#2%
+ {\normalexpanded{\xsplitstring\noexpand#2{#1}}%
+ \dodoglobal\edef#2%
+ {\ifx\m_syst_string_one\empty
+ \m_syst_string_two
+ \else
+ \m_syst_string_one\ifx\m_syst_string_two\empty\else,\m_syst_string_two\fi
+ \fi}}
+ \resetglobal}
+
+%D \macros
+%D {substituteincommalist}
+%D
+%D Slow but seldom used, so for the moment we stick to this implementation.
+%D
+%D \starttyping
+%D \substituteincommalist{old}{new}{list}
+%D \stoptyping
+
+\def\syst_helpers_substitute_in_comma_list_step#1%
+ {\edef\m_syst_string_three{#1}%
+ \ifx\m_syst_string_one\m_syst_string_three
+ \ifx\m_syst_string_two\empty \else
+ \edef\m_syst_string_four{\ifx\m_syst_string_four\empty\else\m_syst_string_four,\fi\m_syst_string_two}%
+ \fi
+ \else
+ \edef\m_syst_string_four{\ifx\m_syst_string_four\empty\else\m_syst_string_four,\fi#1}%
+ \fi}
+
+\unexpanded\def\substituteincommalist#1#2#3% old, new, list (slooow)
+ {\edef\m_syst_string_one{#1}%
+ \edef\m_syst_string_two{#2}%
+ \let\m_syst_string_four\empty
+ \normalexpanded{\rawprocesscommacommand[#3]}\syst_helpers_substitute_in_comma_list_step
+ \let#3\m_syst_string_four}
+
+%D \macros
+%D {replaceincommalist}
+%D
+%D The next macro can be used to replace an indexed element in a commalist:
+%D
+%D \starttyping
+%D \replaceincommalist\MyList{2}
+%D \stoptyping
+%D
+%D Element~2 will be replaced by the current meaning of the macro \type
+%D {\newcommalistelement}. The old meaning is saved in \type {\commalistelement}.
+%D The replacement honors grouped items, like in:
+%D
+%D \starttyping
+%D \def\MyList{a,b,c,d,e,f} \replaceincommalist\MyList{3}
+%D \def\MyList{a,b,c,d,e,f} \replaceincommalist\MyList{3}
+%D \def\MyList{a,{b,c},d,e,f} \replaceincommalist\MyList{3}
+%D \def\MyList{a,b,c,{d,e,f}} \replaceincommalist\MyList{3}
+%D \stoptyping
+%D
+%D This macro was used in the bibtex code (and is probably no longer needed).
+
+\newcount\c_syst_helpers_comma_list_index
+\let \m_syst_helpers_comma_list_target\empty
+
+\let\newcommalistelement\empty
+
+\def\syst_helpers_replace_in_comma_list_step#1%
+ {\ifnum\commalistcounter=\c_syst_helpers_comma_list_index\relax
+ \ifx\newcommalistelement\empty\else
+ \ifx\m_syst_helpers_comma_list_target\empty
+ \let\m_syst_helpers_comma_list_target\newcommalistelement
+ \else
+ \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter
+ \m_syst_helpers_comma_list_target\expandafter\expandafter\expandafter
+ {\expandafter\m_syst_helpers_comma_list_target\expandafter,\newcommalistelement}%
+ \fi
+ \fi
+ \def\commalistelement{#1}%
+ \else
+ \ifx\m_syst_helpers_comma_list_target\empty
+ \ifx\nexttoken\bgroup % is known -)
+ \def\m_syst_helpers_comma_list_target{{#1}}%
+ \else
+ \def\m_syst_helpers_comma_list_target{#1}%
+ \fi
+ \else
+ \ifx\nexttoken\bgroup % is known -)
+ \expandafter\def\expandafter\m_syst_helpers_comma_list_target\expandafter{\m_syst_helpers_comma_list_target,{#1}}%
+ \else
+ \expandafter\def\expandafter\m_syst_helpers_comma_list_target\expandafter{\m_syst_helpers_comma_list_target,#1}%
+ \fi
+ \fi
+ \fi
+ \advance\commalistcounter\plusone}
+
+\unexpanded\def\replaceincommalist#1#2% #1 = commalistelement #2 = position starts at 1
+ {\c_syst_helpers_comma_list_index#2\relax
+ \let\m_syst_helpers_comma_list_target\empty
+ \let\commalistelement\empty
+ \commalistcounter\plusone
+ \expandafter\processcommalist\expandafter[#1]\syst_helpers_replace_in_comma_list_step
+ \dodoglobal\let#1\m_syst_helpers_comma_list_target}
+
+%D \macros
+%D {globalprocesscommalist}
+%D
+%D The commalist processing commands are characterized by the fact that the way they
+%D handle expansion as well as the fact that they can be nested. This makes them
+%D kind of useless for handling comma lists in alignments. In these situations the
+%D next macro can be of use.
+
+\let\m_syst_helpers_comma_list_command_global\empty
+
+\def\syst_helpers_comma_list_command_global_step#1,%
+ {\if]#1\else
+ \m_syst_helpers_comma_list_command_global{#1}%
+ \expandafter\syst_helpers_comma_list_command_global_step
+ \fi}
+
+\unexpanded\def\globalprocesscommalist[#1]#2%
+ {\glet\m_syst_helpers_comma_list_command_global#2%
+ \expandafter\syst_helpers_comma_list_command_global_step#1,],}
+
+%D \macros
+%D {withoutpt,PtToCm,
+%D numberofpoints,dimensiontocount}
+%D
+%D We can convert point into centimeters with:
+%D
+%D \starttyping
+%D \PtToCm{dimension}
+%D \stoptyping
+
+{\catcode`\.=\othercatcode
+ \catcode`\p=\othercatcode
+ \catcode`\t=\othercatcode
+ \gdef\WITHOUTPT#1pt{#1}}
+
+\def\withoutpt#1%
+ {\expandafter\WITHOUTPT#1}
+
+%D The capitals are needed because \type {p} and \type {t} have catcode~12, while
+%D macronames only permit tokens with the catcode~11. As a result we cannot use the
+%D \type {.group} primitives. Those who want to know more about this kind of
+%D manipulations, we advice to study the \TEX book in detail. Because this macro
+%D does not do any assignment, we can use it in the following way too.
+
+\def\PtToCm#1%
+ {\withoutpt\the\dimexpr0.0351459804\dimexpr#1\relax\relax cm}
+
+%D We also support:
+%D
+%D \starttyping
+%D \numberofpoints {dimension}
+%D \dimensiontocount {dimension} {\count}
+%D \stoptyping
+%D
+%D Both macros return a rounded number.
+
+% \dimensiontocount{10.49pt}\scratchcounter \the\scratchcounter / \numberofpoints{10.49pt}
+% \dimensiontocount{10.51pt}\scratchcounter \the\scratchcounter / \numberofpoints{10.51pt}
+
+\def\dimensiontocount#1#2{#2\numexpr\dimexpr#1\relax/\maxcard\relax}
+\def\numberofpoints #1{\the\numexpr\dimexpr#1\relax/\maxcard\relax}
+
+%D \macros
+%D {swapdimens,swapcounts,swapmacros,
+%D globalswapdimens,globalswapcounts,globalswapmacros}
+%D
+%D Simple but effective are the next two macros. There name exactly states their
+%D purpose.
+
+\newdimen\d_syst_helpers_swapped
+\newcount\c_syst_helpers_swapped
+\let \m_syst_helpers_swapped\relax
+
+\unexpanded\def\swapdimens#1#2{\d_syst_helpers_swapped#1#1#2#2\d_syst_helpers_swapped}
+\unexpanded\def\swapcounts#1#2{\c_syst_helpers_swapped#1#1#2#2\c_syst_helpers_swapped}
+\unexpanded\def\swapmacros#1#2{\let\m_syst_helpers_swapped#1\let#1#2\let#2\m_syst_helpers_swapped}
+
+\unexpanded\def\globalswapdimens#1#2{\d_syst_helpers_swapped#1\global#1#2\global#2\d_syst_helpers_swapped}
+\unexpanded\def\globalswapcounts#1#2{\c_syst_helpers_swapped#1\global#1#2\global#2\c_syst_helpers_swapped}
+\unexpanded\def\globalswapmacros#1#2{\let\m_syst_helpers_swapped#1\glet#1#2\glet#2\m_syst_helpers_swapped}
+
+%D \macros
+%D {pushmacro,popmacro}
+%D
+%D Premature and a bit of beta, we offer:
+%D
+%D \starttyping
+%D \pushmacro\macro
+%D \popmacro\macro
+%D \stoptyping
+%D
+%D Beware: global!
+
+\installsystemnamespace{localpushedmacro}
+\installsystemnamespace{globalpushedmacro}
+
+\let\m_syst_helpers_push_macro\empty
+
+\newcount\c_syst_helpers_pop_count
+
+\def\syst_helpers_push_macro_new_global
+ {\expandafter\newcount\csname\??globalpushedmacro\m_syst_helpers_push_macro\endcsname
+ \global\advance\csname\??globalpushedmacro\m_syst_helpers_push_macro\endcsname\plusone}
+
+\def\syst_helpers_push_macro_new_local
+ {\expandafter\newcount\csname\??localpushedmacro\m_syst_helpers_push_macro\endcsname
+ \global\advance\csname\??localpushedmacro\m_syst_helpers_push_macro\endcsname\plusone}
+
+\unexpanded\def\globalpushmacro#1%
+ {\xdef\m_syst_helpers_push_macro{\csstring#1}%
+ \ifcsname\??globalpushedmacro\m_syst_helpers_push_macro\endcsname
+ \global\advance\lastnamedcs\plusone
+ \else
+ \syst_helpers_push_macro_new_global
+ \fi
+ \expandafter\glet\csname\the\lastnamedcs\m_syst_helpers_push_macro\endcsname#1}
+
+\unexpanded\def\localpushmacro#1% this one can be used to push a value over an \egroup
+ {\xdef\m_syst_helpers_push_macro{\csstring#1}%
+ \ifcsname\??localpushedmacro\m_syst_helpers_push_macro\endcsname
+ \global\advance\lastnamedcs\plusone
+ \else
+ \syst_helpers_push_macro_new_local
+ \fi
+ \expandafter\glet\csname\the\lastnamedcs\m_syst_helpers_push_macro\endcsname#1}
+
+\unexpanded\def\globalpopmacro#1%
+ {\xdef\m_syst_helpers_push_macro{\csstring#1}%
+ \c_syst_helpers_pop_count\csname\??globalpushedmacro\m_syst_helpers_push_macro\endcsname
+ \global\advance\lastnamedcs \minusone
+ \expandafter\glet\expandafter#1\csname\the\c_syst_helpers_pop_count\m_syst_helpers_push_macro\endcsname}
+
+\unexpanded\def\localpopmacro#1%
+ {\xdef\m_syst_helpers_push_macro{\csstring#1}%
+ \c_syst_helpers_pop_count\csname\??localpushedmacro\m_syst_helpers_push_macro\endcsname
+ \global\advance\lastnamedcs \minusone
+ \expandafter\let\expandafter#1\csname\the\c_syst_helpers_pop_count\m_syst_helpers_push_macro\endcsname}
+
+\let\pushmacro\localpushmacro
+\let\popmacro \localpopmacro
+
+%D \macros
+%D {setlocalhsize,distributedhsize}
+%D
+%D Sometimes we need to work with the \type{ \hsize} that is corrected for
+%D indentation and left and right skips. The corrected value is available in \type
+%D {\localhsize}, which needs to be calculated with \type {\setlocalhsize} first. %D
+%D
+%D \starttyping
+%D \setlocalhsize \hbox to \localhsize{...}
+%D \setlocalhsize[-1em] \hbox to \localhsize{...}
+%D \setlocalhsize[.5ex] \hbox to \localhsize{...}
+%D \stoptyping
+%D
+%D These examples show us that an optional can be used. The value provided is added
+%D to \type {\localhsize}.
+
+\newdimen\localhsize
+
+\unexpanded\def\setlocalhsize % don't change !
+ {\doifelsenextoptional
+ \syst_helpers_set_local_hsize_yes
+ \syst_helpers_set_local_hsize_nop}
+
+\def\syst_helpers_set_local_hsize_nop
+ {\localhsize\availablehsize}
+
+\def\syst_helpers_set_local_hsize_yes[#1]%
+ {\syst_helpers_set_local_hsize_nop
+ \advance\localhsize#1\relax}
+
+\def\availablehsize
+ {\dimexpr
+ \hsize-\leftskip-\rightskip
+ \ifnum\hangafter<\zerocount
+ \ifdim\hangindent>\zeropoint-\else+\fi\hangindent
+ \fi
+ \relax}
+
+\def\distributedhsize#1#2#3%
+ {\dimexpr(#1-\numexpr#3-1\relax\dimexpr#2\relax)/#3\relax}
+
+\def\hsizefraction#1#2%
+ {\dimexpr#1/#2\relax}
+
+%D \macros
+%D {doifvalue,doifnotvalue,doifelsevalue,
+%D doifnothing,doifsomething,doifelsenothing,
+%D doifvaluenothing,doifvaluesomething,doifelsevaluenothing}
+%D
+%D These \type {\if} commands can be used to access macros (or variables) that are
+%D normally accessed by using \type {\getvalue}. Using these alternatives safes us
+%D three tokens per call. Anyone familiar with the not||values ones, can derive
+%D their meaning from the definitions.
+
+\unexpanded\def\doifvalue#1#2%
+ {\iftok{\csname#1\endcsname}{#2}%
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\unexpanded\def\doifnotvalue#1#2%
+ {\iftok{\csname#1\endcsname}{#2}%
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+\unexpanded\def\doifelsevalue#1#2%
+ {\iftok{\csname#1\endcsname}{#2}%
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\unexpanded\def\doifnothing#1%
+ {\iftok{#1}\emptytoks
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\unexpanded\def\doifsomething#1%
+ {\iftok{#1}\emptytoks
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+\unexpanded\def\doifelsenothing#1%
+ {\iftok{#1}\emptytoks
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\unexpanded\def\doifelsesomething#1%
+ {\iftok{#1}\emptytoks
+ \expandafter\secondoftwoarguments
+ \else
+ \expandafter\firstoftwoarguments
+ \fi}
+
+\unexpanded\def\doifvaluenothing#1%
+ {\iftok{\csname#1\endcsname}\emptytoks
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\unexpanded\def\doifvaluesomething#1%
+ {\iftok{\csname#1\endcsname}\emptytoks
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+\unexpanded\def\doifelsevaluenothing#1%
+ {\iftok{\csname#1\endcsname}\emptytoks
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\let\doifvalueelse \doifelsevalue
+\let\doifnothingelse \doifelsenothing
+\let\doifsomethingelse \doifelsesomething
+\let\doifvaluenothingelse\doifelsevaluenothing
+
+%D \macros
+%D {doifemptyelsevalue, doifemptyvalue, doifnotemptyvalue}
+%D
+%D Also handy:
+
+\def\doifelseemptyvalue#1%
+ {\expandafter\ifx\csname#1\endcsname\empty
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\let\doifemptyvalueelse\doifelseemptyvalue
+
+\def\doifemptyvalue#1%
+ {\expandafter\ifx\csname#1\endcsname\empty
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\def\doifnotemptyvalue#1%
+ {\expandafter\ifx\csname#1\endcsname\empty
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+%D \macros
+%D {doifallcommonelse}
+%D
+%D A complete match of two sets can be tested with \type {\doifallcommonelse}, where
+%D the first two arguments are sets.
+
+\def\syst_helpers_do_if_all_common_else#1#2#3#4% slow
+ {\def\syst_helpers_do_common_check_all##1%
+ {\doifnotinset{##1}{#4}\donefalse
+ \ifdone\else\expandafter\quitcommalist\fi}%
+ \donetrue
+ \processcommalist[#3]\syst_helpers_do_common_check_all
+ \ifdone\expandafter#1\else\expandafter#2\fi}
+
+\unexpanded\def\doifelseallcommon{\syst_helpers_do_if_all_common_else\firstoftwoarguments\secondoftwoarguments}
+\unexpanded\def\doifallcommon {\syst_helpers_do_if_all_common_else\firstofonearguments\gobbleoneargument }
+\unexpanded\def\doifnotallcommon {\syst_helpers_do_if_all_common_else\gobbleoneargument \firstofonearguments }
+
+\let\doifallcommonelse\doifelseallcommon
+
+%D \macros
+%D {DOIF,DOIFELSE,DOIFNOT}
+%D
+%D \TEX\ is case sensitive. When comparing arguments, this feature sometimes is less
+%D desirable, for instance when we compare filenames. The next three alternatives
+%D upcase their arguments before comparing them.
+%D
+%D \starttyping
+%D \DOIF {string1} {string2} {...}
+%D \DOIFNOT {string1} {string2} {...}
+%D \DOIFELSE {string1} {string2} {then ...}{else ...}
+%D \stoptyping
+%D
+%D We have to use a two||step implementation, because the
+%D expansion has to take place outside \type{\uppercase}.
+%D
+%D These might end up as \LUA based helpers (i.e. consider these
+%D obsolete:
+
+\unexpanded\def\syst_helpers_do_IF#1#2%
+ {\uppercase{\syst_helpers_do_if_in_string_else{$#1$}{$#2$}}%
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\unexpanded\def\syst_helpers_do_IF_NOT#1#2%
+ {\uppercase{\syst_helpers_do_if_in_string_else{$#1$}{$#2$}}%
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+\unexpanded\def\syst_helpers_do_IF_ELSE#1#2%
+ {\uppercase{\syst_helpers_do_if_in_string_else{$#1$}{$#2$}}%
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\unexpanded\def\syst_helpers_do_IF_INSTRING_ELSE#1#2%
+ {\uppercase{\syst_helpers_do_if_in_string_else{$#1$}{$#2$}}%
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\unexpanded\def\DOIF #1#2{\normalexpanded{\syst_helpers_do_IF {#1}{#2}}}% will become obsolete
+\unexpanded\def\DOIFNOT #1#2{\normalexpanded{\syst_helpers_do_IF_NOT {#1}{#2}}}% will become obsolete
+\unexpanded\def\DOIFELSE #1#2{\normalexpanded{\syst_helpers_do_IF_ELSE {#1}{#2}}}% will become obsolete
+\unexpanded\def\DOIFINSTRINGELSE #1#2{\normalexpanded{\syst_helpers_do_IF_INSTRING_ELSE{#1}{#2}}}% will become obsolete
+
+%D \macros
+%D {dosingleargumentwithset,
+%D dodoubleargumentwithset,dodoubleemptywithset,
+%D dotripleargumentwithset,dotripleemptywithset}
+%D
+%D These maybe too mysterious macros enable us to handle more than one setup at once.
+%D
+%D \starttyping
+%D \dosingleargumentwithset \command[#1]
+%D \dodoubleargumentwithset \command[#1][#2]
+%D \dotripleargumentwithset \command[#1][#2][#3]
+%D \dodoubleemptywithset \command[#1][#2]
+%D \dotripleemptywithset \command[#1][#2][#3]
+%D \stoptyping
+%D
+%D The first macro calls \type {\command[##1]} for each string in the set~\type
+%D {#1}. The second one calls for \typ {\command [##1][#2]} and the third, well one
+%D may guess. These commands support constructions like:
+%D
+%D \starttyping
+%D \def\dodefinesomething[#1][#2]%
+%D {\getparameters[\??xx#1][#2]}
+%D
+%D \unexpanded\def\definesomething%
+%D {\dodoubleargumentwithset\dodefinesomething}
+%D \stoptyping
+%D
+%D Which accepts calls like:
+%D
+%D \starttyping
+%D \definesomething[alfa,beta,...][variable=...,...]
+%D \stoptyping
+
+\let\m_syst_helpers_with_set_command\empty
+\let\syst_helpers_with_set_step \relax
+
+\def\syst_helpers_with_set_double[#1][#2]%
+ {\doifsomething{#1}%
+ {\def\syst_helpers_with_set_step##1{\m_syst_helpers_with_set_command[##1][#2]}%
+ \processcommalist[#1]\syst_helpers_with_set_step}}
+
+\def\syst_helpers_with_set_triple[#1][#2][#3]%
+ {\doifsomething{#1}%
+ {\def\syst_helpers_with_set_step##1{\m_syst_helpers_with_set_command[##1][#2][#3]}%
+ \processcommalist[#1]\syst_helpers_with_set_step}}
+
+\def\dodoubleemptywithset #1{\let\m_syst_helpers_with_set_command#1\dodoubleempty \syst_helpers_with_set_double} % \command
+\def\dodoubleargumentwithset#1{\let\m_syst_helpers_with_set_command#1\dodoubleargument\syst_helpers_with_set_double} % \command
+
+\def\dotripleemptywithset #1{\let\m_syst_helpers_with_set_command#1\dotripleempty \syst_helpers_with_set_triple} % \command
+\def\dotripleargumentwithset#1{\let\m_syst_helpers_with_set_command#1\dotripleargument\syst_helpers_with_set_triple} % \command
+
+%D \macros
+%D {stripcharacters,stripspaces}
+%D
+%D The next command was needed first when we implemented the \CONTEXT\ interactivity
+%D macros. When we use labeled destinations, we often cannot use all the characters
+%D we want. We therefore strip some of the troublemakers, like spaces, from the
+%D labels before we write them to the \DVI||file, which passes them to for instance
+%D a \POSTSCRIPT\ file.
+%D
+%D \starttyping
+%D \stripspaces\from\one\to\two
+%D \stoptyping
+%D
+%D Both the old string \type{\one} and the new one \type{\two}
+%D are expanded. This command is a special case of:
+%D
+%D \starttyping
+%D \stripcharacter\char\from\one\to\two
+%D \stoptyping
+%D
+%D As we can see below, spaces following a control sequence are to enclosed in \type
+%D {{}}.
+
+\let\m_syst_helpers_strip_character\empty
+
+\unexpanded\def\stripcharacter#1\from#2\to#3%
+ {\def\syst_helpers_strip_character##1#1##2\end
+ {\edef\m_syst_helpers_strip_character{\m_syst_helpers_strip_character##1}%
+ \doifnotempty{##2}{\syst_helpers_strip_character##2\end}}%
+ \let\m_syst_helpers_strip_character\empty
+ \edef\m_syst_string_one{#2}%
+ \expandafter\syst_helpers_strip_character\m_syst_string_one#1\end
+ \dodoglobal\let#3\m_syst_helpers_strip_character}
+
+\unexpanded\def\stripspaces\from#1\to#2% will become \unspacestring#1\from#2
+ {\stripcharacter{ }\from#1\to#2}
+
+%D \macros
+%D {unspacestring}
+%D
+%D The next macro does the same but is more compatible with other macros, like \type
+%D {\convert...}.
+
+\unexpanded\def\unspacestring#1\to#2%
+ {\stripcharacter{ }\from#1\to#2}
+
+%D \macros
+%D {executeifdefined}
+%D
+%D \CONTEXT\ uses one auxiliary file for all data concerning tables of contents,
+%D references, two||pass optimizations, sorted lists etc. This file is loaded as
+%D many times as needed. During such a pass we skip the commands thate are of no use
+%D at that moment. Because we don't want to come into trouble with undefined
+%D auxiliary commands, we call the macros in a way similar to \type {\getvalue}. The
+%D next macro take care of such executions and when not defined, gobbles the
+%D unwanted arguments.
+%D
+%D \starttyping
+%D \executeifdefined{name}\gobbleoneargument
+%D \stoptyping
+%D
+%D We can of course gobble more arguments using the appropriate gobbling command.
+
+\def\executeifdefined#1% #2 / never change this one again
+ {\ifcsname#1\endcsname
+ % \csname#1\expandafter\expandafter\expandafter\endcsname\expandafter\gobbleoneargument
+ \expandafter\expandafter\expandafter\lastnamedcs\expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+%D This one also has the advantage that it is fully expandable and that it can be
+%D used after an assignment.
+
+%D \macros
+%D {doifsomespaceelse}
+%D
+%D The next command checks a string on the presence of a space and executed a
+%D command accordingly.
+%D
+%D \starttyping
+%D \doifsomespaceelse {tekst} {then ...} {else ...}
+%D \stoptyping
+%D
+%D We use this command in \CONTEXT\ for determing if an argument must be broken into
+%D words when made interactive. Watch the use of \type {\noexpand}.
+
+%D Is this one still needed?
+
+\def\syst_helpers_if_some_space_else#1 #2#3^^^^0004{\if\noexpand#2@}
+
+\def\doifelsesomespace#1% % #2#3%
+ {\syst_helpers_if_some_space_else#1 @ @^^^^0004% #3\else#2\fi}
+ \expandafter\secondoftwoarguments
+ \else
+ \expandafter\firstoftwoarguments
+ \fi}
+
+\let\doifsomespaceelse\doifelsesomespace
+
+%D \macros
+%D {processseparatedlist}
+%D
+%D Maybe a bit late, but here is a more general version of the \type
+%D {\processcommalist} command. This time we don't handle nesting but accept
+%D arbitrary seperators.
+%D
+%D \starttyping
+%D \processseparatedlist[list][separator]\command
+%D \stoptyping
+%D
+%D One can think of things like:
+%D
+%D \starttyping
+%D \processseparatedlist[alfa+beta+gamma][+]\message
+%D \stoptyping
+%D
+%D We want to handle all situations, like:
+%D
+%D \startbuffer
+%D \processseparatedlist[{aap noot}] [ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii}
+%D \processseparatedlist[{aap} {noot}][ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii}
+%D \processseparatedlist[aap {noot}] [ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii}
+%D \processseparatedlist[aap noot] [ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii}
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D Therefore we smuggle a \type {\relax} in front of the argument, which we remove
+%D afterwards.
+
+\let\syst_helpers_process_separated_list_step\relax
+
+\def\syst_helpers_process_separated_list#1]#2[#3]#4%
+ {\def\syst_helpers_process_separated_list_step##1##2#3%
+ {\def\m_syst_string_one{##2}% suggested by VZ
+ \if]##1%
+ \let\syst_helpers_process_separated_list_step\relax
+ \orelse\ifx\blankspace\m_syst_string_one
+ #4{##1}%
+ \orelse\if]##2%
+ \let\syst_helpers_process_separated_list_step\relax
+ \else
+ #4{##1##2}%
+ \fi
+ \syst_helpers_process_separated_list_step}%
+ \expandafter\syst_helpers_process_separated_list_step\gobbleoneargument#1#3]#3}
+
+\unexpanded\def\processseparatedlist[%
+ {\syst_helpers_process_separated_list\relax}
+
+%D \macros
+%D {processlist}
+%D
+%D An even more general list processing macro is the following one:
+%D
+%D \starttyping
+%D \processlist{beginsym}{endsym}{separator}\docommand list
+%D \stoptyping
+%D
+%D This one supports arbitrary open and close symbols as well as user defined
+%D separators.
+%D
+%D \starttyping
+%D \processlist(){=>}\docommand(a=>b=>c=>d)
+%D \stoptyping
+
+\let\syst_helpers_process_any_list \relax
+\let\syst_helpers_process_any_list_indeed\relax
+\let\syst_helpers_process_any_list_step \relax
+
+\unexpanded\def\processlist#1#2#3#4% no blank skipping !
+ {\def\syst_helpers_process_any_list_indeed##1#2%
+ {\def\syst_helpers_process_any_list_step####1####2#3%
+ {\ifx#2####1%
+ \let\syst_helpers_process_any_list_step\relax
+ \orelse\ifx#2####2%
+ \let\syst_helpers_process_any_list_step\relax
+ \else
+ #4{####1####2}%
+ \fi
+ \syst_helpers_process_any_list_step}%
+ \expandafter\syst_helpers_process_any_list_step\gobbleoneargument##1#3#2#3}%
+ \def\syst_helpers_process_any_list#1%
+ {\syst_helpers_process_any_list_indeed\relax}%
+ \syst_helpers_process_any_list}
+
+%D \macros
+%D {processassignlist}
+%D
+%D Is possible to combine an assignment list with one containing keywords.
+%D Assignments are treated accordingly, keywords are treated by \type {\command}.
+%D
+%D \starttyping
+%D \processassignlist[...=...,...=...,...]\commando
+%D \stoptyping
+%D
+%D This command can be integrated in \type {\getparameters}, but we decided best not
+%D to do so.
+
+\unexpanded\def\processassignlist#1[#2]#3%
+ {\def\syst_helpers_process_assign_list_assign[##1=##2=##3]%
+ {\doif{##3}\relax{#3{##1}}}%
+ \def\syst_helpers_process_assign_list_step##1%
+ {\syst_helpers_process_assign_list_assign[##1==\relax]}%
+ \processcommalist[#2]\syst_helpers_process_assign_list_step}
+
+%D \macros
+%D {untextargument
+%D untexcommand}
+%D
+%D When manipulating data(bases) and for instance generating index entries, the next
+%D three macros can be of help:
+%D
+%D \starttyping
+%D \untextargument{...}\to\name
+%D \untexcommand {...}\to\name
+%D \stoptyping
+%D
+%D They remove braces and backslashes and give us something to sort.
+
+\let\m_syst_helpers_untexed\empty
+
+\unexpanded\def\untexsomething
+ {\begingroup
+ \catcode\leftbraceasciicode \ignorecatcode
+ \catcode\rightbraceasciicode\ignorecatcode
+ \escapechar\minusone
+ \syst_helpers_untex_something}
+
+\def\syst_helpers_untex_something#1#2\to#3%
+ {\doglobal#1#2\to\m_syst_helpers_untexed
+ \endgroup
+ \let#3\m_syst_helpers_untexed}
+
+\unexpanded\def\untexargument{\untexsomething\convertargument}
+\unexpanded\def\untexcommand {\untexsomething\convertcommand}
+
+%D \macros
+%D {ScaledPointsToBigPoints,ScaledPointsToWholeBigPoints}
+%D
+%D One characteristic of \POSTSCRIPT\ and \PDF\ is that both used big points (\TEX's
+%D bp). The next macros convert points and scaled points into big points. The magic
+%D factor $72/72.27$ can be found in most \TEX\ related books.
+%D
+%D \starttyping
+%D \ScaledPointsToBigPoints {number} \target
+%D \ScaledPointsToWholeBigPoints {number} \target
+%D \stoptyping
+
+\let\tobigpoints \clf_tobigpoints
+\let\towholebigpoints\clf_towholebigpoints
+
+\unexpanded\def\PointsToBigPoints #1#2{\edef#2{\tobigpoints #1}} % can be avoided
+\unexpanded\def\PointsToWholeBigPoints #1#2{\edef#2{\towholebigpoints#1}} % can be avoided
+\unexpanded\def\ScaledPointsToBigPoints #1#2{\edef#2{\tobigpoints #1\scaledpoint}} % obsolete
+\unexpanded\def\ScaledPointsToWholeBigPoints#1#2{\edef#2{\towholebigpoints#1\scaledpoint}} % obsolete
+
+%D \macros
+%D {PointsToReal}
+%D
+%D Points can be stripped from their suffix by using \type {\withoutpt}. The next
+%D macro enveloppes this macro.
+%D
+%D \starttyping
+%D \PointsToReal {dimension} \target
+%D \stoptyping
+
+\unexpanded\def\PointsToReal#1#2%
+ {\edef#2{\withoutpt\the\dimexpr#1}}
+
+%D \macros
+%D {dontleavehmode}
+%D
+%D Sometimes when we enter a paragraph with some command, the first token gets the
+%D whole first line. We can prevent this by saying:
+%D
+%D \starttyping
+%D \dontleavehmode
+%D \stoptyping
+%D
+%D This command is used in for instance the language module \type {lang-ini}. The
+%D first version was:
+%D
+%D \starttyping
+%D \def\dontleavehmode{\ifhmode\else\ifmmode\else$ $\fi\fi}
+%D \stoptyping
+%D
+%D Next, Taco came with a better alternative (using mathsurround):
+%D
+%D \starttyping
+%D \def\dontleavehmode
+%D {\ifhmode\else \ifmmode\else
+%D {\mathsurround\zeropoint\everymath\emptytoks$ $}%
+%D \fi \fi}
+%D \stoptyping
+%D
+%D And finaly we got the following alternative, one that avoids interfering grouping
+%D at the cost of a box.
+%D
+%D \starttyping
+%D \newbox\b_syst_helpers_dlh
+%D
+%D \unexpanded\def\dontleavehmode
+%D {\ifhmode\else \ifmmode\else
+%D \setbox\b_syst_helpers_dlh\hbox{\mathsurround\zeropoint\everymath\emptytoks$ $}\unhbox\b_syst_helpers_dlh
+%D \fi \fi}
+%D \stoptyping
+%D
+%D But, as we run a recent version of \TEX, we can use the new primitive:
+
+\ifdefined\normalquitvmode \let\dontleavehmode\normalquitvmode \fi
+
+%D \macros
+%D {utfupper, utflower, uppercasestring, lowercasestring}
+%D
+%D The names tell what they do:
+%D
+%D \starttyping
+%D \uppercasestring somestring\to\somestring
+%D \lowercasestring somestring\to\somestring
+%D \stoptyping
+%D
+%D The first argument may be a \type{\macro}.
+%D
+%D These macros are sort of obsolete as we never use uppercase this way. But
+%D nevertheless we provide them:
+
+\def\utfupper#1{\clf_upper{#1}} % expandable
+\def\utflower#1{\clf_lower{#1}} % expandable
+
+\unexpanded\def\uppercasestring#1\to#2{\dodoglobal\edef#2{\clf_upper{#1}}}
+\unexpanded\def\lowercasestring#1\to#2{\dodoglobal\edef#2{\clf_lower{#1}}}
+
+%D \macros
+%D {handletokens}
+%D
+%D With the next macro we enter a critical area of macro expansion. What we want is
+%D a macro that looks like:
+%D
+%D \starttyping
+%D \handletokens some tokens\with \somemacro
+%D \stoptyping
+%D
+%D A bonus example:
+%D
+%D \starttyping
+%D \hbox{\handletokens tekst en meer tekst\with\ruledhbox}
+%D
+%D \def\weetikveel#1{\if#1\blankspace\space\else\ruledhbox{#1}\fi}
+%D
+%D \hbox{\handletokens tekst en meer tekst\with\weetikveel}
+%D \stoptyping
+
+%D \macros
+%D {counttoken,counttokens}
+%D
+%D For the few occasions that we want to know the number of specific tokens in a
+%D string, we can use:
+%D
+%D \starttyping
+%D \counttoken token\in string\to \somecount
+%D \counttokens string\to \somecount
+%D \stoptyping
+%D
+%D This macro, that for instance is used in \type {cont-tab}, takes a real counter.
+%D The macro can be preceded by \type {\doglobal}.
+
+\def\syst_helpers_count_token#1% obeys {}
+ {\def\m_syst_string_three{#1}%
+ \ifx\m_syst_string_two\m_syst_string_three \else
+ \ifx\m_syst_string_one\m_syst_string_three
+ \advance\privatescratchcounter\plusone
+ \fi
+ \expandafter\syst_helpers_count_token
+ \fi}
+
+\unexpanded\def\counttoken#1\in#2\to#3%
+ {\privatescratchcounter\zerocount
+ \def\m_syst_string_one{#1}%
+ \def\m_syst_string_two{\end}%
+ \syst_helpers_count_token#2\end
+ \dodoglobal#3\privatescratchcounter}
+
+\unexpanded\def\counttokens#1\to#2%
+ {\privatescratchcounter\zerocount
+ \def\syst_helpers_count_token##1{\advance\privatescratchcounter\plusone}%
+ \handletokens#1\with\syst_helpers_count_token
+ \dodoglobal#2\privatescratchcounter}
+
+%D \macros
+%D {splitofftokens}
+%D
+%D Running this one not always gives the expected results. Consider for instance the
+%D macro for which I originally wrote this token handler.
+
+\unexpanded\def\splitofftokens#1\from#2\to#3% slow but hardly used
+ {\ifnum#1>\zerocount
+ \privatescratchcounter#1\relax
+ \def\syst_helpers_split_off_tokens##1%
+ {\ifnum\privatescratchcounter>\zerocount
+ \advance\privatescratchcounter \minusone
+ \edef#3{#3##1}%
+ \fi}%
+ % \let#3\empty % #3 can be #2, so:
+ \expandafter\let\expandafter#3\expandafter\empty
+ \expandafter\handletokens#2\with\syst_helpers_split_off_tokens
+ \else
+ \edef#3{#2}%
+ \fi}
+
+%D This macro can be called like:
+%D
+%D \startbuffer[example]
+%D \splitofftokens10\from01234567 890123456789\to\test [\test]
+%D \stopbuffer
+%D
+%D up there. The reason for this is not that logical but follows from \TEX's
+%D However, the characters that we expect to find in \type {\test} just don't show
+%D sometimes mysterious way of expanding. Look at this:
+%D
+%D \startbuffer[next]
+%D \def\next{a} \edef\test{\next} [\test]
+%D \let\next=b \edef\test{\test\next} [\test]
+%D \let\next=c \edef\test{\next} [\test]
+%D \let\next=d \edef\test{\test\next} [\test]
+%D \let\next=e \expandafter\edef\expandafter\test\expandafter{\test\next} [\test]
+%D \stopbuffer
+%D
+%D \typebuffer[next]
+%D
+%D Careful reading shows that inside an \type {\edef} macro's that are \type {\let}
+%D are not expanded!
+%D
+%D \unprotect\getbuffer[next]\protect
+%D
+%D That's why we finally end up with a macro that looks ahead by using an
+%D assignment, this time by using \type {\futurelet}, and grabbing an argument as
+%D well. That way we can handle the sentinal, a blank space and grouped tokens.
+
+\unexpanded\def\syst_helpers_handle_tokens % \nexthandledtoken is part of interface
+ {\futurelet\nexthandledtoken\syst_helpers_handle_tokens_indeed}
+
+\def\handletokens#1\with#2%
+ {\gdef\syst_helpers_handle_tokens_command{#2}% permits more complex #2's
+ \syst_helpers_handle_tokens#1\end}
+
+\def\syst_helpers_handle_tokens_indeed
+ {\ifx\nexthandledtoken\blankspace
+ \expandafter\syst_helpers_handle_tokens_indeed_one
+ \orelse\ifx\nexthandledtoken\end
+ \expandafter\gobbletwoarguments % also gobble the \end
+ \else
+ \expandafter\syst_helpers_handle_tokens_indeed_two
+ \fi *}
+
+\def\syst_helpers_handle_tokens_indeed_one * %
+ {\syst_helpers_handle_tokens_command{ }\syst_helpers_handle_tokens}
+
+\def\syst_helpers_handle_tokens_indeed_two *#1%
+ {\syst_helpers_handle_tokens_command{#1}\syst_helpers_handle_tokens}
+
+%D This macro is tested on:
+%D
+%D \def\xxx#1{[#1]}
+%D
+%D \startlines
+%D \handletokens abc\with\xxx
+%D \handletokens a b c\with\xxx
+%D \handletokens a b c\with\xxx
+%D \handletokens a{bc}d\with\xxx
+%D \handletokens a\space bc \with\xxx
+%D \stoplines
+%D
+%D And our previous example shows up as:
+%D
+%D \getbuffer[example]
+
+%D \macros
+%D {iftrialtypesetting, ifvisible}
+%D
+%D The next boolean is at first sight a strange one. Sometimes one does a trial
+%D typesetting run, for instance to determine dimensions. Some mechanisms, like
+%D object inclusion, can fail on such trials. Temporary setting the next boolean to
+%D true, helps a lot. The second boolena can be used to inhibit processing
+%D completely.
+
+\newif\ifvisible \visibletrue
+
+\newtoks\everysettrialtypesetting
+\newtoks\everyresettrialtypesetting
+
+\unexpanded\def\settrialtypesetting {\the\everysettrialtypesetting } % obeys grouping so
+\unexpanded\def\resettrialtypesetting{\the\everyresettrialtypesetting} % this one is seldom needed
+
+\let\iftrialtypesetting\iffalse % so we have no \trialtypesettingtrue|false in mkiv !
+
+\appendtoks \let\iftrialtypesetting\iftrue \to \everysettrialtypesetting
+\appendtoks \let\iftrialtypesetting\iffalse \to \everyresettrialtypesetting
+
+%D \macros
+%D {twodigitrounding}
+%D
+%D When using \type {\special}s or \type {\pdfliteral}s, it sometimes makes sense to
+%D limit the precission. The next macro rounds a real number to two digits. It takes
+%D one argument and only works in \ETEX.
+
+\def\integerrounding #1{\clf_rounded\zerocount\numexpr#1\relax}
+\def\onedigitrounding #1{\clf_rounded\plusone \numexpr#1\relax}
+\def\twodigitrounding #1{\clf_rounded\plustwo \numexpr#1\relax}
+\def\threedigitrounding#1{\clf_rounded\plusthree\numexpr#1\relax}
+
+%D \macros
+%D {processcontent}
+%D
+%D This macro is first used in the tabulation macros.
+%D
+%D \starttyping
+%D \unexpanded\def\starthans%
+%D {\processcontent{stophans}\test{\message{\test}\wait}}
+%D \stoptyping
+
+\unexpanded\def\processcontent#1%
+ {\begingroup\expandafter\syst_helpers_process_content\csname#1\endcsname}
+
+\unexpanded\def\syst_helpers_process_content#1#2#3%
+ {\unexpanded\def\syst_helpers_process_content##1#1%
+ {\endgroup\def#2{##1}#3}%
+ \syst_helpers_process_content}
+
+%D \macros
+%D {dogobblesingleempty, dogobbledoubleempty}
+%D
+%D These two macros savely grab and dispose two arguments.
+
+\def\dogobblesingleempty{\dosingleempty\syst_helpers_gobble_single_empty}
+\def\dogobbledoubleempty{\dodoubleempty\syst_helpers_gobble_double_empty}
+
+\def\syst_helpers_gobble_single_empty [#1]{}
+\def\syst_helpers_gobble_double_empty[#1][#2]{}
+
+\let\gobblesingleempty\dogobblesingleempty % also used
+\let\gobbledoubleempty\dogobbledoubleempty % also used
+
+%D \macros
+%D {setdimensionwithunit, freezedimensionwithunit}
+%D
+%D The next assignments are all valid:
+%D
+%D \starttyping
+%D \setdimensionwithunit\scratchdimen{10} {cm}
+%D \setdimensionwithunit\scratchdimen{10cm}{cm}
+%D \setdimensionwithunit\scratchdimen{10cm}{}
+%D \freezedimensionwithunit\SomeWidth{\textwidth}
+%D \freezedimensionwithunit\SomeDepth{\dp\strutbox}
+%D \stoptyping
+%D
+%D As an alternative for the next macro we can use a global assignment inside a box.
+%D The \type {\empty}'s permits gobbling while preventing spurious \type {\relax}'s.
+
+\unexpanded\def\setdimensionwithunit#1#2#3% number unit dimension / nice trick
+ {\afterassignment\gobblefourarguments#1=#2#3pt\relax\empty\empty\empty\empty}
+
+\unexpanded\def\freezedimensionwithunit#1#2%
+ {\setdimensionwithunit\privatescratchdimen#1{#2}\edef#1{\the\privatescratchdimen}}
+
+%D \macros
+%D {doifsometokselse, doifsometoks}
+%D
+%D Not that fast I guess, but here's a way to test for token registers being empty.
+
+\unexpanded\def\doifelsesometoks#1%
+ {\iftok#1\emptytoks
+ \expandafter\secondoftwoarguments
+ \else
+ \expandafter\firstoftwoarguments
+ \fi}
+
+\unexpanded\def\doifsometoks#1%
+ {\iftok#1\emptytoks
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+\unexpanded\def\doifemptytoks#1%
+ {\iftok#1\emptytoks
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\let\doifsometokselse\doifelsesometoks
+
+%D \macros
+%D {startstrictinspectnextcharacter}
+%D
+%D This one is for the bibliography module (still?):
+
+\let\syst_helpers_strict_inspect_next_character[
+
+\def\syst_helpers_strict_inspect_next_character% no user macro !
+ {\ifx\nexttoken[%
+ \expandafter\m_syst_action_yes
+ \else
+ \expandafter\m_syst_action_nop
+ \fi}
+
+\unexpanded\def\strictdoifelsenextoptional#1#2%
+ {\def\m_syst_action_yes{#1}%
+ \def\m_syst_action_nop{#2}%
+ \futurelet\nexttoken\syst_helpers_strict_inspect_next_character}
+
+\let\strictdoifnextoptionalelse\strictdoifelsenextoptional
+
+%D \macros
+%D {gobblespacetokens}
+%D
+%D This macro needs a speed-up!
+
+%\def\gobblespacetokens
+% {\doifnextcharelse\empty\donothing\donothing} % no {}\do\do !
+
+\def\gobblespacetokens
+ {\afterassignment\nexttoken\let\nexttoken=}
+
+%D \macros
+%D {verbatimargument}
+%D
+%D As the name says, this macro converts its argument to a (rather safe) string.
+
+\let\verbatimstring\detokenize
+
+%D These are needed in ordinal number conversions:
+
+\def\lastdigit#1%
+ {\expandafter\thelastdigit\number#1\relax}
+
+\def\thelastdigit#1#2%
+ {\ifx#2\relax#1\else\expandafter\thelastdigit\expandafter#2\fi}
+
+\def\lasttwodigits#1%
+ {\expandafter\thelasttwodigits\expandafter0\number#1\relax}
+
+\def\thelasttwodigits#1#2#3% 0 dig ... \relax
+ {\ifx#3\relax#1#2\else\expandafter\thelasttwodigits\expandafter#2\expandafter#3\fi}
+
+%D \macros
+%D {serializecommalist}
+%D
+%D Concatenate commalists:
+
+\let\syst_helpers_serialize_comma_list_step\relax
+
+\def\syst_helpers_serialize_comma_list_step#1%
+ {\edef\serializedcommalist{\serializedcommalist#1}}
+
+\unexpanded\def\serializecommalist[#1]%
+ {\let\serializedcommalist\empty
+ \processcommacommand[#1]\syst_helpers_serialize_comma_list_step}
+
+%D \macros
+%D {purenumber}
+%D
+%D Sometimes we need control over when \TEX\ stops reading a number, especially in
+%D full expandable macros where using \type {\relax} would lead to disasters.
+%D
+%D \starttyping
+%D \ifodd\purenumber{...}\space ... \else ... \fi
+%D \stoptyping
+%D
+%D Here we use a space as number delimiter in combination with a space- and
+%D relax-less \type {\purenumber}. This macro works ok with \type {\the}, \type
+%D {\number} as well as \ETEX's \type {\numexpr}.
+
+\def\purenumber#1{\expandafter\firstofoneargument\expandafter{\number#1}}
+
+%D \macros
+%D {filterfromvalue}
+%D
+%D \starttyping
+%D \setvalue{xx}{{A}{B}{C}}
+%D
+%D \filterfromvalue{xx}{3}{3}
+%D \filterfromvalue{xx}{3}{2}
+%D \filterfromvalue{xx}{3}{1}
+%D \stoptyping
+%D
+%D An alternative is to store 'max' in the list, say:
+%D
+%D \starttyping
+%D \setvalue{xx}{3{A}{B}{C}}
+%D
+%D \filterfromvalues{3}{xx}{3}
+%D \filterfromvalues{3}{xx}{2}
+%D \filterfromvalues{3}{xx}{1}
+%D \stoptyping
+%D
+%D I'll implement this when I'm in \quotation {writing dirty macros mood}.
+
+\def\dofilterfromstr#1#2% max n % no need to be fast
+ {\expandafter \expandafter \expandafter \csstring
+ \ifcase#1\or \ifcase#2\or
+ \firstofoneargument \else
+ \gobbleoneargument \fi
+ \or \ifcase#2\or
+ \firstoftwoarguments \or
+ \secondoftwoarguments \else
+ \gobbletwoarguments \fi
+ \or \ifcase#2\or
+ \firstofthreearguments \or
+ \secondofthreearguments \or
+ \thirdofthreearguments \else
+ \gobblethreearguments \fi
+ \or \ifcase#2\or
+ \firstoffourarguments \or
+ \secondoffourarguments \or
+ \thirdoffourarguments \or
+ \fourthoffourarguments \else
+ \gobblefourarguments \fi
+ \or \ifcase#2\or
+ \firstoffivearguments \or
+ \secondoffivearguments \or
+ \thirdoffivearguments \or
+ \fourthoffivearguments \or
+ \fifthoffivearguments \else
+ \gobblefivearguments \fi
+ \fi}
+
+\def\filterfromvalue#1#2#3% value max n
+ {\expandafter\doubleexpandafter\csname % we use the fact that an
+ \expandafter\ifx\csname#1\endcsname\relax % undefined cs has become \relax
+ \csstring\gobbleoneargument % which we then gobble here
+ \else
+ \dofilterfromstr{#2}{#3}%
+ \fi
+ \endcsname\csname#1\endcsname}
+
+\def\filterfromnext#1#2% max n {..}{..}{..}{..}
+ {\csname\dofilterfromstr{#1}{#2}\endcsname}
+
+%D \macros
+%D {definemeasure}
+%D
+%D \starttyping
+%D \definemeasure[mywidth][\dimexpr(\textwidth-1cm)]
+%D
+%D ... \measure{mywidth} ...
+%D \stoptyping
+
+\installsystemnamespace{measure}
+
+\unexpanded\def\definemeasure
+ {\dodoubleargument\syst_helpers_define_measure}
+
+\def\syst_helpers_define_measure[#1][#2]%
+ {\expandafter\def\csname\??measure#1\endcsname{#2}}
+
+\unexpanded\def\freezemeasure
+ {\dodoubleargument\syst_helpers_freeze_measure}
+
+\def\syst_helpers_freeze_measure[#1][#2]%
+ {\expandafter\edef\csname\??measure#1\endcsname{\the\dimexpr#2}}
+
+\unexpanded\def\setmeasure #1#2{\expandafter\def \csname\??measure#1\endcsname{#2}} % quick way
+\unexpanded\def\setgmeasure#1#2{\expandafter\gdef\csname\??measure#1\endcsname{#2}} % quick way
+\unexpanded\def\setemeasure#1#2{\expandafter\edef\csname\??measure#1\endcsname{\the\dimexpr#2}} % quick way
+\unexpanded\def\setxmeasure#1#2{\expandafter\xdef\csname\??measure#1\endcsname{\the\dimexpr#2}} % quick way
+
+\def\measure
+ {\the\measured}
+
+\def\measured#1%
+ %{\dimexpr\ifcsname\??measure#1\endcsname\csname\??measure#1\endcsname\else\zeropoint\fi\relax}
+ {\dimexpr\ifcsname\??measure#1\endcsname\lastnamedcs\else\zeropoint\fi\relax}
+
+% #2 could be omitted, but we want to support spaces
+%
+% \setmeasure {x} {1cm}
+% \setmeasure {xx} {1cm}
+% \setmeasure {xxx}{1cm}
+
+%D \macros
+%D {definequantity}
+%D
+%D These do the same but for numbers.
+
+\installsystemnamespace{quantity}
+
+\unexpanded\def\definequantity
+ {\dodoubleargument\syst_helpers_define_quantity}
+
+\def\syst_helpers_define_quantity[#1][#2]%
+ {\expandafter\def\csname\??quantity#1\endcsname{#2}}
+
+\unexpanded\def\freezequantity
+ {\dodoubleargument\syst_helpers_freeze_quantity}
+
+\def\syst_helpers_freeze_quantity[#1][#2]%
+ {\expandafter\edef\csname\??quantity#1\endcsname{\the\numexpr#2}}
+
+\unexpanded\def\setquantity #1#2{\expandafter\def \csname\??quantity#1\endcsname{#2}} % quick way
+\unexpanded\def\setgquantity#1#2{\expandafter\gdef\csname\??quantity#1\endcsname{#2}} % quick way
+\unexpanded\def\setequantity#1#2{\expandafter\edef\csname\??quantity#1\endcsname{\the\numexpr#2}} % quick way
+\unexpanded\def\setxquantity#1#2{\expandafter\xdef\csname\??quantity#1\endcsname{\the\numexpr#2}} % quick way
+
+\def\quantity
+ {\the\quantitied}
+
+\def\quantitied#1%
+ {\numexpr\ifcsname\??quantity#1\endcsname\lastnamedcs\else\zeropoint\fi\relax}
+
+\def\directquantity#1%
+ {\the\numexpr#1\relax}
+
+% let\quantified\quantitied
+
+%D \macros
+%D {dividedsize}
+%D
+%D This one can be used inside a measure (used in m4all):
+%D
+%D \starttyping
+%D \definemeasure[columnwidth][\dividedsize\textwidth{1em}{3}]
+%D \stoptyping
+
+\def\dividedsize#1#2#3% size gap n
+ {\dimexpr
+ \ifnum\dimexpr#1\relax>\plusone
+ (\dimexpr#1\relax-\numexpr#3-\plusone\relax\dimexpr#2\relax)/#3\else#1%
+ \fi
+ \relax}
+
+%D \macros
+%D {doifdimensionelse}
+%D
+%D This is a dirty one: we simply append a unit and discard it when needed.
+
+\def\doifelsedimension#1%
+ {\ifchkdim#1\or
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\let\doifdimensionelse\doifelsedimension
+
+%D Ok, here's another one, slower but seldom used. This one scans the text.
+%D
+%D \starttabulate[|Tc|Tc|]
+%D \NC pt \NC \doifdimenstringelse {pt}{yes}{no} \NC \NR
+%D \NC 12pt \NC \doifdimenstringelse {-12pt}{yes}{no} \NC \NR
+%D \NC 1pt \NC \doifdimenstringelse {1pt}{yes}{no} \NC \NR
+%D \NC 12pt \NC \doifdimenstringelse {12pt}{yes}{no} \NC \NR
+%D \NC 12.0pt \NC \doifdimenstringelse {12.0pt}{yes}{no} \NC \NR
+%D \NC -.12pt \NC \doifdimenstringelse {-.12pt}{yes}{no} \NC \NR
+%D \NC .12pt \NC \doifdimenstringelse {.12pt}{yes}{no} \NC \NR
+%D \NC -12pt \NC \doifdimenstringelse {-12pt}{yes}{no} \NC \NR
+%D \NC -12.0pt \NC \doifdimenstringelse{-12.0pt}{yes}{no} \NC \NR
+%D \NC big \NC \doifdimenstringelse {big}{yes}{no} \NC \NR
+%D \NC 10 \NC \doifdimenstringelse {10}{yes}{no} \NC \NR
+%D \NC 1 \NC \doifdimenstringelse {1}{yes}{no} \NC \NR
+%D \stoptabulate
+
+\let\doifelsedimenstring\doifelsedimension
+\let\doifdimenstringelse\doifelsedimenstring
+
+%D \macros
+%D {comparedimension,comparedimensioneps}
+%D
+%D This is a dirty one: we simply append a unit and discard it when needed.
+
+\newdimen \roundingeps \roundingeps=10sp
+\newconstant\compresult
+
+\def\comparedimension#1#2%
+ {\compresult
+ \ifdim#1<#2%
+ \zerocount
+ \orelse\ifdim#1<#2%
+ \plusone
+ \else
+ \plustwo
+ \fi}
+
+\def\comparedimensioneps#1#2% todo: use eps feature
+ {\compresult
+ \ifdim\dimexpr#1-#2\relax<\roudingeps
+ \zerocount
+ \orelse\ifdim\dimexpr#2-#1\relax<\roudingeps
+ \zerocount
+ \orelse\ifdim#1<#2%
+ \plusone
+ \else
+ \plustwo
+ \fi}
+
+% pretty ugly but fast
+
+% \copycsname xxx\endcsname\csname ..\endcsname
+
+\unexpanded\def\copycsname{\expandafter\expandafter\expandafter\let\expandafter\expandafter\csname}
+
+% \letcscsname \crap \csname ..\endcsname
+% \letcsnamecs \csname ..\endcsname\crap
+% \letcsnamecsname\csname ..\endcsname\csname ..\endcsname
+
+\unexpanded\def\letcscsname {\expandafter\let\expandafter}
+\unexpanded\def\letcsnamecs {\expandafter\let}
+\unexpanded\def\letcsnamecsname{\expandafter\expandafter\expandafter\let\expandafter\expandafter}
+
+% another one, add an item to a commalist
+
+\unexpanded\def\addvalue#1#2% cs item
+ {\ifcsname#1\endcsname\else\expandafter\let\csname#1\endcsname\empty\fi
+ \normalexpanded{\noexpand\addtocommalist{#2}\expandafter\noexpand\csname#1\endcsname}}
+
+\def\unspaced#1%
+ {\syst_helpers_unspaced#1\end}
+
+\def\syst_helpers_unspaced#1%
+ {\ifx#1\end
+ \expandafter\gobbleoneargument
+ \orelse\ifx#1\blankspace
+ % go on
+ \else
+ #1%
+ \fi
+ \syst_helpers_unspaced}
+
+\unexpanded\def\unspaceargument#1\to#2%
+ {\privatescratchcounter\catcode\spaceasciicode
+ \catcode\spaceasciicode\ignorecatcode
+ \scantextokens{\edef#2{#1}}%
+ \catcode\spaceasciicode\privatescratchcounter}
+
+\unexpanded\def\unspaceafter#1#2%
+ {\unspaceargument#2\to\ascii
+ \expandafter#1\expandafter{\ascii}}
+
+% sometimes handy:
+
+\unexpanded\def\doifelsehasspace#1%
+ {\edef\m_syst_string_one{#1}%
+ \normalexpanded{\syst_helpers_if_has_space_else#1\space}\empty\relax}
+
+\let\doifhasspaceelse\doifelsehasspace
+
+\unexpanded\def\syst_helpers_if_has_space_else#1 #2#3\relax % \space\empty\relax
+ {\ifx\m_syst_string_one\space
+ \expandafter\firstoftwoarguments
+ \orelse\ifx#2\empty
+ \expandafter\secondoftwoarguments
+ \else
+ \expandafter\firstoftwoarguments
+ \fi}
+
+% this will replace loadfile once and alike !!! todo
+
+\installsystemnamespace{flag}
+
+\unexpanded\def\setflag #1{\expandafter\dodoglobal\expandafter\let\csname\??flag#1\endcsname\zerocount}
+\unexpanded\def\resetflag#1{\expandafter\dodoglobal\expandafter\let\csname\??flag#1\endcsname\plusone}
+
+\def\flag#1{\csname\??flag#1\endcsname}
+
+\def\doifelseflagged#1%
+ {\expandafter\ifx\csname\??flag#1\endcsname\relax
+ \expandafter\secondoftwoarguments
+ \orelse\ifcase\csname\??flag#1\endcsname
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\let\doifflaggedelse\doifelseflagged
+
+\def\doifnotflagged#1%
+ {\expandafter\ifx\csname\??flag#1\endcsname\relax
+ \expandafter\firstofoneargument
+ \orelse\ifcase\csname\??flag#1\endcsname
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+\unexpanded\def\inheritparameter[#1]#2[#3]#4[#5]% tag tokey fromkey
+ {\expandafter\def\csname#1#3\expandafter\endcsname\expandafter{\csname#1#5\endcsname}}
+
+\def\syst_helpers_if_non_zero_positive_else#1#2\end % #3#4%
+ {\ifx#1\relax
+ \ifcase\privatescratchcounter
+ \endgroup
+ \doubleexpandafter\secondoftwoarguments
+ \else
+ \endgroup
+ \doubleexpandafter\firstoftwoarguments
+ \fi
+ \else
+ \endgroup
+ \expandafter\secondoftwoarguments
+ \fi}
+
+% used ?
+
+\def\doifelsenonzeropositive#1%
+ {\begingroup\afterassignment\syst_helpers_if_non_zero_positive_else\privatescratchcounter=0#1\relax\empty\end}
+
+\let\doifnonzeropositiveelse\doifelsenonzeropositive
+
+% here ?
+
+\unexpanded\def\dosetrawvalue #1#2#3{\expandafter \def\csname#1#2\endcsname{#3}}
+\unexpanded\def\dosetrawevalue#1#2#3{\expandafter\edef\csname#1#2\endcsname{#3}}
+\unexpanded\def\dosetrawgvalue#1#2#3{\expandafter\gdef\csname#1#2\endcsname{#3}}
+\unexpanded\def\dosetrawxvalue#1#2#3{\expandafter\xdef\csname#1#2\endcsname{#3}}
+
+\unexpanded\def\getrawparameters {\dogetparameters\dosetrawvalue }
+\unexpanded\def\getraweparameters {\dogetparameters\dosetrawevalue}
+\unexpanded\def\getrawgparameters {\dogetparameters\dosetrawgvalue}
+\unexpanded\def\getrawxparameters {\dogetparameters\dosetrawxvalue}
+
+\unexpanded\def\globalgetrawparameters{\dogetparameters\dosetrawgvalue} % obsolete
+
+%D Sort of obsolete:
+
+\newcount\c_syst_helpers_mod
+
+\unexpanded\def\dosetmodulo#1#2#3%
+ {\c_syst_helpers_mod#1\divide\c_syst_helpers_mod#2\multiply\c_syst_helpers_mod#2%
+ #3#1\advance#3-\c_syst_helpers_mod}
+
+\unexpanded\def\dosetdivision#1#2#3%
+ {#3#1\divide#3 #2\relax}
+
+\unexpanded\def\DoMod#1by#2to#3{\dosetmodulo {#1}{#2}{#3}}
+\unexpanded\def\DoDiv#1by#2to#3{\dosetdivision{#1}{#2}{#3}}
+
+\def\syst_helpers_unprotected#1\par
+ {#1\protect}
+
+\unexpanded\def\unprotected
+ {\unprotect
+ \syst_helpers_unprotected}
+
+\let\resettimer \clf_resettimer
+\let\elapsedtime \clf_elapsedtime
+\let\elapsedseconds \elapsedtime
+
+\newcount\c_syst_helpers_test_feature_n
+\newcount\c_syst_helpers_test_feature_m
+
+\def\currentfeaturetest{\number\c_syst_helpers_test_feature_n}
+
+\unexpanded\def\testfeature#1#2%
+ {\c_syst_helpers_test_feature_m#1\relax
+ \def\syst_helpers_test_feature_yes
+ {\advance\c_syst_helpers_test_feature_n\plusone
+ \ifnum\c_syst_helpers_test_feature_n>\c_syst_helpers_test_feature_m\else
+ #2\expandafter\syst_helpers_test_feature_yes
+ \fi}%
+ \def\syst_helpers_test_feature_nop
+ {\advance\c_syst_helpers_test_feature_n\plusone
+ \ifnum\c_syst_helpers_test_feature_n>\c_syst_helpers_test_feature_m\else
+ \expandafter\syst_helpers_test_feature_nop
+ \fi}%
+ \retestfeature}
+
+\unexpanded\def\retestfeature % timer support is new per 10/5/2005
+ {\bgroup
+ \ifcase\interactionmode\let\wait\relax\fi
+ \clf_resettimer
+ \c_syst_helpers_test_feature_n\zerocount
+ \syst_helpers_test_feature_nop
+ \clf_benchmarktimer
+ \writestatus\m!system{starting feature test (n=\number\c_syst_helpers_test_feature_m)}\wait
+ \c_syst_helpers_test_feature_n\zerocount
+ \syst_helpers_test_feature_yes
+ \writestatus\m!system{\number\c_syst_helpers_test_feature_m\space feature tests done (\elapsedseconds s)}%
+ \wait
+ \egroup}
+
+\unexpanded\def\showtimer#1%
+ {\writestatus{runtime}{\elapsedseconds\space s / #1}}
+
+\unexpanded\def\testfeatureonce#1#2%
+ {\begingroup
+ \let\wait\relax
+ \testfeature{#1}{#2}%
+ \endgroup}
+
+%D \macros
+%D {freezedimenmacro}
+%D
+%D This macro is use as:
+%D
+%D \starttyping
+%D \freezedimenmacro\leftmargindistance
+%D \stoptyping
+
+\unexpanded\def\freezedimenmacro#1%
+ {\edef#1{\the\dimexpr#1}}
+
+%D The next macro negates a macro (dimension or number, or actually, whatever. It's
+%D a typical example of \type {\if} usage:
+%D
+%D \starttyping
+%D \if-\whatever \else-\whatever\fi => else => -whatever
+%D \if--\whatever\else-\whatever\fi => then => whatever
+%D \stoptyping
+
+\def\negated#1{\if-#1\else-#1\fi} % does only work in macros or text
+
+\def\gobbleassigndimen#1\\{}
+
+\def\assigndimen#1#2%
+ {\afterassignment\gobbleassigndimen#1=#2\zeropoint\\}
+
+\unexpanded\def\appended#1#2#3{\expandafter#1\expandafter#2\expandafter{#2#3}}
+\unexpanded\def\appendvalue #1{\expandafter\appended\expandafter \def\csname#1\endcsname}
+\unexpanded\def\appendgvalue#1{\expandafter\appended\expandafter\gdef\csname#1\endcsname}
+
+\unexpanded\def\prepended#1#2#3%
+ {\t_syst_helpers_scratch{#3}%
+ \expandafter\expandafter\expandafter#1\expandafter\expandafter\expandafter#2\expandafter\expandafter\expandafter
+ {\expandafter\the\expandafter\t_syst_helpers_scratch#2}}
+
+\unexpanded\def\prependvalue #1{\expandafter\prepended\expandafter \def\csname#1\endcsname}
+\unexpanded\def\prependgvalue#1{\expandafter\prepended\expandafter\gdef\csname#1\endcsname}
+
+%D \macros
+%D {dowithrange}
+%D
+%D This one is for Mojca Miklavec, who made me aware of the fact that \type
+%D {page-imp.tex} was not the best place to hide it.
+%D
+%D \startbuffer
+%D \def\DoSomething#1{ [item #1] }
+%D
+%D \processranges[1,4:5]\DoSomething \par
+%D \dowithrange {1,4:5}\DoSomething \par
+%D \stopbuffer
+%D
+%D \typebuffer \blank \getbuffer \blank
+
+\def\syst_helpers_with_range#1%
+ {\splitstring#1\at:\to\m_syst_helpers_range_from\and\m_syst_helpers_range_to
+ \ifx\m_syst_helpers_range_to\empty\let\m_syst_helpers_range_to\m_syst_helpers_range_from\fi
+ \dostepwiserecurse\m_syst_helpers_range_from\m_syst_helpers_range_to\plusone{\m_helpers_range_action{##1}}}%
+
+\unexpanded\def\processranges[#1]#2% #1= n:m,p,q:r
+ {\def\m_helpers_range_action{#2}%
+ \processcommacommand[#1]\syst_helpers_with_range}
+
+\unexpanded\def\dowithrange#1#2%
+ {\def\m_helpers_range_action{#2}%
+ \processcommacommand[#1]\syst_helpers_with_range}
+
+% \def\DoSomething#1{ [item #1] }
+% \dowithrange[1,4:5]\DoSomething
+
+%D \macros
+%D {ignoreimplicitspaces}
+%D
+%D \startbuffer
+%D \def\whatever[#1]{\expanded{\definedfont[#1 at 12pt]}\ignorespaces}
+%D {a\whatever[Serif]b a\whatever[Serif] b a\whatever[Serif]\space b}
+%D \def\whatever[#1]{\expanded{\definedfont[#1 at 12pt]}\ignoreimplicitspaces}
+%D {a\whatever[Serif]b a\whatever[Serif] b a\whatever[Serif]\space b}
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+\unexpanded\def\ignoreimplicitspaces
+ {\doifelsenextchar\relax\relax\relax}
+
+%D \macros
+%D {processwords}
+%D
+%D Not that sophisticated but sometimes users (like in metafun).
+
+\def\syst_helpers_process_word#1 #2\_e_o_w_
+ {\doifsomething{#1}{\processword{#1} \syst_helpers_process_word#2 \_e_o_w_}}
+
+\def\processwords#1%
+ {\syst_helpers_process_word#1 \_e_o_w_}% no \unskip
+
+\let\processword\relax
+
+%D \macros
+%D {startnointerference}
+%D
+%D \starttyping
+%D \startnointerference
+%D all kind of code
+%D \stopnointerference
+%D \stoptyping
+
+\newbox\b_syst_helpers_no_interference
+
+\unexpanded\def\startnointerference % not even grouped !
+ {\setbox\b_syst_helpers_no_interference\vbox
+ \bgroup}
+
+\unexpanded\def\stopnointerference
+ {\egroup
+ \setbox\b_syst_helpers_no_interference\emptybox}
+
+%D A variant for \type {\executeifdefined}:
+
+\def\expandcheckedcsname#1#2% #2 is often a \xxxparameter so let's expand it once
+ {\normalexpanded{\noexpand\syst_helpers_expand_checked_csname{#1}{#2}}}
+
+\def\syst_helpers_expand_checked_csname#1#2#3%
+ {\csname#1\ifcsname#1#2\endcsname#2\else#3\fi\endcsname}
+
+%D Signal. Some fonts have a char0 rendering so we need to make sure that it is not
+%D set in the font! (This will be overloaded)
+
+\unexpanded\def\signalcharacter{\char\zerocount} % \zwj
+
+%D A few secial variants of commands defined here. Some more will be moved here (e.g.
+%D from table modules.
+
+\def\dodirectdoubleempty#1#2% used in math (lookahead issues)
+ {\ifx#2[%
+ \expandafter\syst_helpers_direct_double_empty_one_yes
+ \else
+ \expandafter\syst_helpers_direct_double_empty_one_nop
+ \fi#1#2}
+
+\def\syst_helpers_direct_double_empty_one_yes#1[#2]#3%
+ {\ifx#3[\else\expandafter\syst_helpers_direct_double_empty_two_nop\fi#1[#2]#3}
+
+\def\syst_helpers_direct_double_empty_one_nop#1{#1[][]}
+\def\syst_helpers_direct_double_empty_two_nop#1[#2]{#1[#2][]}
+
+%D Used in math definitions (in an \type {\edef}):
+
+%D \startbuffer
+%D [\docheckedpair{}]
+%D [\docheckedpair{a}]
+%D [\docheckedpair{a,b}]
+%D [\docheckedpair{a,b,c}]
+%D \stopbuffer
+%D
+%D \typebuffer \startlines \getbuffer \stoplines
+
+\def\docheckedpair#1%
+ {\syst_helpers_checked_pair#1,,\_o_e_p_}
+
+\def\syst_helpers_checked_pair#1,#2,#3\_o_e_p_
+ {#1,#2}
+
+%D Here are some nasty helpers. They can be used to fill often expanded token
+%D lists efficiently (see tabulate for an example).
+
+\def\constantnumber#1%
+ {\ifcase#1\zerocount
+ \or \plusone
+ \or \plustwo
+ \or \plusthree
+ \or \plusfour
+ \or \plusfive
+ \or \plussix
+ \or \plusseven
+ \or \pluseight
+ \or \plusnine
+ \or \plusten
+ \else \number#1\relax\fi}
+
+\def\constantnumberargument#1%
+ {\ifcase#1\zerocount
+ \or \plusone
+ \or \plustwo
+ \or \plusthree
+ \or \plusfour
+ \or \plusfive
+ \or \plussix
+ \or \plusseven
+ \or \pluseight
+ \or \plusnine
+ \or \plusten
+ \else {\number#1}\fi}
+
+\def\constantdimen#1%
+ {\ifdim#1=\zeropoint
+ \zeropoint
+ \else
+ \the#1\relax
+ \fi}
+
+\def\constantdimenargument#1%
+ {\ifdim#1=\zeropoint
+ \zeropoint
+ \else
+ {\the#1}%
+ \fi}
+
+\def\constantemptyargument#1%
+ {\ifx#1\empty
+ \noexpand\empty
+ \else
+ {#1}%
+ \fi}
+
+%D \macros
+%D {getsubstring}
+%D \startbuffer
+%D
+%D \getsubstring{4}{}{Who Wants This}
+%D \getsubstring{4}{9}{Who Wants This}
+%D \getsubstring{9}{-2}{Who Wants This}
+%D \getsubstring{1}{5}{Who Wants This}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlines
+%D \getbuffer
+%D \stoplines
+
+% expandable:
+
+\def\getsubstring#1#2#3{\clf_getsubstring{#3}{#1}{#2}}
+
+%D Other dimensions than pt (used in mb-mp)
+
+\def\converteddimen#1#2{\clf_converteddimen\dimexpr#1\relax{#2}}
+
+%D Maybe (looks ugly):
+%D
+%D \starttyping
+%D \doifcase {foo}
+%D {bar} {BAR}
+%D {foo} {FOO}
+%D {default} {DEFAULT}
+%D
+%D \doifcase {foo}
+%D {bar} {BAR}
+%D {foo} {\doifcase {bar}
+%D {bar} {BAR}
+%D {foo} {FOO}
+%D {default} {DEFAULT}
+%D }
+%D {default} {DEFAULT}
+%D \stoptyping
+
+% \doifcase {\btxfoundname{author}}
+% {author} {\btxflush{author}}
+% {editor} {\texdefinition{btx:apa:editor-or-editors}}
+% {title} {\texdefinition{btx:apa:title-subtitle-type}}
+% {default} {\btxflush{author}}
+
+% \unexpanded\def\doifcase#1%
+% {\edef\m_case_asked{#1}%
+% \syst_aux_case}
+%
+% \def\syst_aux_case#1%
+% {\edef\m_case_temp{#1}%
+% \ifx\m_case_temp\m_case_asked
+% \expandafter\syst_aux_case_yes
+% \orelse\ifx\m_case_temp\s!default
+% \expandafter\firstofoneargument
+% \else
+% \expandafter\syst_aux_case_nop
+% \fi}
+%
+% \def\syst_aux_skip#1#2%
+% {\edef\m_case_temp{#1}%
+% \ifx\m_case_temp\s!default
+% \expandafter\syst_aux_done
+% \else
+% \expandafter\syst_aux_skip
+% \fi}
+%
+% \def\syst_aux_case_yes#1%
+% {\def\syst_aux_done{#1}%
+% \syst_aux_skip}
+%
+% \def\syst_aux_case_nop#1%
+% {\syst_aux_case}
+
+%D \macros
+%D {ntimes}
+%D
+%D some repetition:
+%D
+%D \startbuffer
+%D \ntimes{*}{20}
+%D \stopbuffer
+%D
+%D \typebuffer \blank gives: \getbuffer \blank
+%D
+%D This is not real fast but quite okay:
+
+%def\ntimes#1#2{\ifnum#2>\zerocount#1\ntimes{#1}{\numexpr#2-\plusone\relax}\fi} % 1.72
+\def\ntimes#1#2{\clf_ntimes{#1}\numexpr#2\relax} % 0.33
+
+%D Experiment (sometimes looks nicer in code):
+
+\unexpanded\def\sameargumentscondition#1#2%
+ {\edef\m_syst_string_one{#1}%
+ \edef\m_syst_string_two{#2}%
+ \ifx\m_syst_string_one\m_syst_string_two}
+
+\unexpanded\def\emptyargumentcondition#1%
+ {\edef\m_syst_string_one{#1}%
+ \ifx\m_syst_string_one\empty}
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/syst-con.lua b/Master/texmf-dist/tex/context/base/mkiv/syst-con.lua
index 0fa685b2dab..1af2d9a5d5e 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/syst-con.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/syst-con.lua
@@ -66,3 +66,11 @@ implement { name = "tand", actions = { math.tand, nicenumber, context }, argumen
-- only as commands
function commands.format(fmt,...) context((gsub(fmt,"@","%%")),...) end
+
+implement {
+ name = "formatone",
+ public = true,
+ protected = true,
+ arguments = "2 strings",
+ actions = function(f,s) context((gsub(f,"@","%%")),s) end,
+}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/syst-con.mkiv b/Master/texmf-dist/tex/context/base/mkiv/syst-con.mkiv
index afbdf8605b2..56155460a90 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/syst-con.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/syst-con.mkiv
@@ -15,36 +15,10 @@
\unprotect
-%D When the number of conversions grew, it did no longer make
-%D sense to spread them over multiple files. So, instead of
-%D defining these in \type {font-ini}, we now have a dedicated
-%D module.
-
-%D \macros
-%D {lchexnumber,uchexnumber,lchexnumbers,uchexnumbers}
-%D
-%D In addition to the uppercase hex conversion, as needed in
-%D math families, we occasionally need a lowercase one, for
-%D instance when we want to compose gbsong fontnames.
-%D
-%D The ugly indirectness is needed to get rid of \TEX\
-%D induced spaces and \type {\relax}'s.
+%D \macros{lchexnumber,uchexnumber,lchexnumbers,uchexnumbers}
%D
-%D \starttyping
-%D [\uchexnumber{0}]
-%D [\uchexnumber\scratchcounter]
-%D [\uchexnumber\zerocount]
-%D [\uchexnumber{\number0}]
-%D [\uchexnumber{\number\scratchcounter}]
-%D [\uchexnumber{\number\zerocount}]
-%D [\uchexnumber{\the\scratchcounter}]
-%D [\uchexnumber{\the\zerocount}]
-%D [\expandafter\uchexnumber\expandafter{\number0}]
-%D [\expandafter\uchexnumber\expandafter{\number\scratchcounter}]
-%D [\expandafter\uchexnumber\expandafter{\number\zerocount}]
-%D [\expandafter\uchexnumber\expandafter{\the\scratchcounter}]
-%D [\expandafter\uchexnumber\expandafter{\the\zerocount}]
-%D \stoptyping
+%D In addition to the uppercase hex conversion, as needed in math families, we
+%D occasionally need a lowercase one.
\def\lchexnumber #1{\clf_lchexnumber \numexpr#1\relax}
\def\uchexnumber #1{\clf_uchexnumber \numexpr#1\relax}
@@ -53,33 +27,28 @@
\let\hexnumber\uchexnumber
-%D \macros
-%D {octnumber}
+%D \macros{octnumber}
%D
-%D For unicode remapping purposes, we need octal numbers.
+%D For \UNICODE\ remapping purposes, we need octal numbers.
\def\octnumber#1{\clf_octnumber\numexpr#1\relax}
-%D \macros
-%D {hexstringtonumber,octstringtonumber}
+%D \macros{hexstringtonumber,octstringtonumber}
%D
-%D This macro converts a two character hexadecimal number into
-%D a decimal number, thereby taking care of lowercase characters
-%D as well.
+%D This macro converts a two character hexadecimal number into a decimal number,
+%D thereby taking care of lowercase characters as well.
\def\hexstringtonumber#1{\clf_hexstringtonumber\numexpr#1\relax}
\def\octstringtonumber#1{\clf_octstringtonumber\numexpr#1\relax}
-%D \macros
-%D {rawcharacter}
+%D \macros{rawcharacter}
%D
-%D This macro can be used to produce proper 8 bit characters
-%D that we sometimes need in backends and round||trips.
+%D This macro can be used to produce proper 8 bit characters that we sometimes need
+%D in backends and round||trips.
\def\rawcharacter#1{\clf_rawcharacter\numexpr#1\relax}
-%D \macros
-%D {twodigits, threedigits}
+%D \macros{twodigits, threedigits}
%D
%D These macros provides two or three digits always:
@@ -88,50 +57,42 @@
%D \macros{modulonumber}
%D
-%D In the conversion macros described in \type {core-con} we
-%D need a wrap||around method. The following solution is
-%D provided by Taco.
+%D In the conversion macros described in \type {core-con} we need a wrap||around
+%D method. The following solution is provided by Taco.
%D
-%D The \type {modulonumber} macro expands to the mathematical
-%D modulo of a positive integer. It is crucial for it's
-%D application that this macro is fully exandable.
+%D The \type {modulonumber} macro expands to the mathematical modulo of a positive
+%D integer. It is crucial for it's application that this macro is fully exandable.
%D
-%D The expression inside the \type {\numexpr} itself is
-%D somewhat bizarre because \ETEX\ uses a rounding
-%D division instead of truncation. If \ETEX's division
-%D would have behaved like \TEX's normal\type{\divide}, then
-%D the expression could have been somewhat simpler, like
-%D \type {#2-(#2/#1)*#1}. This works just as well, but a bit
-%D more complex.
+%D The expression inside the \type {\numexpr} itself is somewhat bizarre because
+%D \ETEX\ uses a rounding division instead of truncation. If \ETEX's division would
+%D have behaved like \TEX's normal\type {\divide}, then the expression could have
+%D been somewhat simpler, like \type {#2-(#2/#1)*#1}. This works just as well, but a
+%D bit more complex.
-\def\modulonumber#1#2%
- {\the\numexpr#2-((((#2+(#1/2))/#1)-1)*#1)\relax}
+\def\modulonumber#1#2{\the\numexpr#2-((((#2+(#1/2))/#1)-1)*#1)\relax}
%D \macros{modulatednumber}
%D
-%D Modulo numbers run from zero to one less than the limit,
-%D but for conversion sets, we need a value between 1 and the
-%D limit. The \type{\modulatednumber} arranges that. This
-%D macro also needs to be fully expandable, resulting in
-%D two \type{\numexpr}s.
+%D Modulo numbers run from zero to one less than the limit, but for conversion sets,
+%D we need a value between 1 and the limit. The \type {\modulatednumber} arranges
+%D that. This macro also needs to be fully expandable, resulting in two \type
+%D {\numexpr}s.
\def\modulatednumber#1#2%
{\ifnum\the\numexpr\modulonumber{#1}{#2}\relax=0 #1%
\else \the\numexpr\modulonumber{#1}{#2}\relax \fi}
-%D \macros
-%D {realnumber} % used?
+%D \macros{setcalculatedsin,setcalculatedcos,setcalculatedtan}
-\def\realnumber#1{\withoutpt\the\dimexpr#1\s!pt\relax} % brrr
+\unexpanded\def\setcalculatedsin#1#2{\edef#1{\clf_sind#2}}
+\unexpanded\def\setcalculatedcos#1#2{\edef#1{\clf_cosd#2}}
+\unexpanded\def\setcalculatedtan#1#2{\edef#1{\clf_tand#2}}
-%D \macros
-%D {setcalculatedsin,setcalculatedcos,setcalculatedtan}
-
-\def\setcalculatedsin#1#2{\edef#1{\clf_sind#2}}
-\def\setcalculatedcos#1#2{\edef#1{\clf_cosd#2}}
-\def\setcalculatedtan#1#2{\edef#1{\clf_tand#2}}
+%D \macros{formatted,format}
\def\formatted#1{\ctxcommand{format(#1)}} % not clf
\unexpanded\def\format #1{\ctxcommand{format(#1)}} % not clf
+%D The \type {\modulatednumber} and \type {\realnumber} macros have been removed.
+
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/syst-con.mkxl b/Master/texmf-dist/tex/context/base/mkiv/syst-con.mkxl
new file mode 100644
index 00000000000..c3293b221f8
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/syst-con.mkxl
@@ -0,0 +1,93 @@
+%D \module
+%D [ file=syst-con,
+%D version=2006.09.16, % real old stuff ... 2000.12.10
+%D title=\CONTEXT\ System Macros,
+%D subtitle=Conversions,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\registerctxluafile{syst-con}{}
+
+\unprotect
+
+%D \macros{lchexnumber,uchexnumber,lchexnumbers,uchexnumbers}
+%D
+%D In addition to the uppercase hex conversion, as needed in math families, we
+%D occasionally need a lowercase one.
+
+\def\lchexnumber #1{\clf_lchexnumber \numexpr#1\relax}
+\def\uchexnumber #1{\clf_uchexnumber \numexpr#1\relax}
+\def\lchexnumbers#1{\clf_lchexnumbers\numexpr#1\relax}
+\def\uchexnumbers#1{\clf_uchexnumbers\numexpr#1\relax}
+
+\let\hexnumber\uchexnumber
+
+%D \macros{octnumber}
+%D
+%D For \UNICODE\ remapping purposes, we need octal numbers.
+
+\def\octnumber#1{\clf_octnumber\numexpr#1\relax}
+
+%D \macros{hexstringtonumber,octstringtonumber}
+%D
+%D This macro converts a two character hexadecimal number into a decimal number,
+%D thereby taking care of lowercase characters as well.
+
+\def\hexstringtonumber#1{\clf_hexstringtonumber\numexpr#1\relax}
+\def\octstringtonumber#1{\clf_octstringtonumber\numexpr#1\relax}
+
+%D \macros{rawcharacter}
+%D
+%D This macro can be used to produce proper 8 bit characters that we sometimes need
+%D in backends and round||trips.
+
+\def\rawcharacter#1{\clf_rawcharacter\numexpr#1\relax}
+
+%D \macros{twodigits, threedigits}
+%D
+%D These macros provides two or three digits always:
+
+\def\twodigits #1{\ifnum #1<10 0\fi\number#1}
+\def\threedigits#1{\ifnum#1<100 \ifnum#1<10 0\fi0\fi\number#1}
+
+%D \macros{modulonumber}
+%D
+%D In the conversion macros described in \type {core-con} we need a wrap||around
+%D method. The following solution is provided by Taco.
+%D
+%D The \type {modulonumber} macro expands to the mathematical modulo of a positive
+%D integer. It is crucial for it's application that this macro is fully exandable.
+%D
+%D The expression inside the \type {\numexpr} itself is somewhat bizarre because
+%D \ETEX\ uses a rounding division instead of truncation. If \ETEX's division would
+%D have behaved like \TEX's normal\type {\divide}, then the expression could have
+%D been somewhat simpler, like \type {#2-(#2/#1)*#1}. This works just as well, but a
+%D bit more complex.
+%D
+%D \starttyping
+%D \def\modulonumber#1#2{\the\numexpr#2-((((#2+(#1/2))/#1)-1)*#1)\relax}
+%D \stoptyping
+%D
+%D But \unknown\ now we can also do this:
+
+\def\modulonumber#1#2{\the\numexpr#2-(#2:#1)*#1\relax}
+
+%D \macros{setcalculatedsin,setcalculatedcos,setcalculatedtan}
+
+\unexpanded\def\setcalculatedsin#1#2{\edef#1{\clf_sind#2}}
+\unexpanded\def\setcalculatedcos#1#2{\edef#1{\clf_cosd#2}}
+\unexpanded\def\setcalculatedtan#1#2{\edef#1{\clf_tand#2}}
+
+%D \macros{formatted,format}
+
+ \def\formatted#1{\ctxcommand{format(#1)}} % not clf
+\unexpanded\def\format #1{\ctxcommand{format(#1)}} % not clf
+
+%D The \type {\modulatednumber} and \type {\realnumber} macros have been removed.
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/syst-ini.mkiv b/Master/texmf-dist/tex/context/base/mkiv/syst-ini.mkiv
index 7ce48c79f66..0dd1fe29cf6 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/syst-ini.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/syst-ini.mkiv
@@ -97,13 +97,12 @@
%D Initialization of primitives.
\directlua {
- local baseprimitives = tex.extraprimitives("core","tex")
- local moreprimitives = tex.extraprimitives("etex","luatex")
+ local primitives = tex.extraprimitives("core","tex","etex","luatex")
- tex.enableprimitives("",moreprimitives)
+ % table.sort(primitives)
- tex.enableprimitives("normal",baseprimitives)
- tex.enableprimitives("normal",moreprimitives)
+ tex.enableprimitives("", primitives)
+ tex.enableprimitives("normal",primitives)
function tex.enableprimitives() end
}
@@ -370,6 +369,7 @@
\newdimen\scratchwidth
\newdimen\scratchheight
\newdimen\scratchdepth
+\newdimen\scratchtotal
\newdimen\scratchoffset
\newdimen\scratchleftoffset
@@ -412,7 +412,7 @@
\newdimen \zeropoint \zeropoint 0pt
\newdimen \onepoint \onepoint 1pt
\newdimen \halfapoint \halfapoint 0.5pt
-\newdimen \maxdimen \maxdimen 16383.99999pt
+\newdimen \maxdimen \maxdimen 16383.99999pt % 1073741823sp
\newcount \maxcount \maxcount 2147483647
\newdimen \onebasepoint \onebasepoint 1bp
\newdimen \scaledpoint \scaledpoint 1sp
@@ -570,9 +570,7 @@
\newif\ifdone
\newif\iffound
-%D Potential primitive in \LUATEX:
-
-\ifdefined\htdp \else \def\htdp#1{\dimexpr\ht#1+\dp#1\relax} \fi
+\def\htdp#1{\dimexpr\ht#1+\dp#1\relax}
%D A few shortcuts:
@@ -619,48 +617,64 @@
%D have number 0 (used to be char node) and ligature nodes are mapped to 7. That way
%D macro packages can use the same symbolic names as in traditional \ETEX. Keep in
%D mind that the internal node numbers are different and that there are more node
-%D types that 15.
-
-\chardef\charnodecode = 0
-\chardef\hlistnodecode = 1
-\chardef\vlistnodecode = 2
-\chardef\rulenodecode = 3
-\chardef\insertnodecode = 4
-\chardef\marknodecode = 5
-\chardef\adjustnodecode = 6
-\chardef\ligaturenodecode = 7
-\chardef\discretionarynodecode = 8
-\chardef\whatsitnodecode = 9
-\chardef\mathnodecode = 10
-\chardef\gluenodecode = 11
-\chardef\kernnodecode = 12
-\chardef\penaltynodecode = 13
-\chardef\unsetnodecode = 14
-\chardef\mathsnodecode = 15
+%D types that 15. The mode parameter forces \LUAMETATEX\ to use the real node
+%D numbers.
+
+\ifdefined\internalcodesmode
+
+ \internalcodesmode\plusone
+
+ % \chardef\gluenodecode = 12
+ % \chardef\kernnodecode = 13
+ % \chardef\penaltynodecode = 14
+
+\else
+
+ % \chardef\charnodecode = 0
+ % \chardef\hlistnodecode = 1
+ % \chardef\vlistnodecode = 2
+ % \chardef\rulenodecode = 3
+ % \chardef\insertnodecode = 4
+ % \chardef\marknodecode = 5
+ % \chardef\adjustnodecode = 6
+ % \chardef\ligaturenodecode = 7
+ % \chardef\discretionarynodecode = 8
+ % \chardef\whatsitnodecode = 9
+ % \chardef\mathnodecode = 10
+ \chardef\gluenodecode = 11
+ \chardef\kernnodecode = 12
+ \chardef\penaltynodecode = 13
+ % \chardef\unsetnodecode = 14
+ % \chardef\mathsnodecode = 15
+
+\fi
%D Constants to be used with \type {\currentiftype}. I wonder if we will ever
-%D use these in \CONTEXT.
-
-\chardef\charifcode = 1
-\chardef\catifcode = 2
-\chardef\numifcode = 3
-\chardef\dimifcode = 4
-\chardef\oddifcode = 5
-\chardef\vmodeifcode = 6
-\chardef\hmodeifcode = 7
-\chardef\mmodeifcode = 8
-\chardef\innerifcode = 9
-\chardef\voidifcode = 10
-\chardef\hboxifcode = 11
-\chardef\vboxifcode = 12
-\chardef\xifcode = 13
-\chardef\eofifcode = 14
-\chardef\trueifcode = 15
-\chardef\falseifcode = 16
-\chardef\caseifcode = 17
-\chardef\definedifcode = 18
-\chardef\csnameifcode = 19
-\chardef\fontcharifcode = 20
+%D use these in \CONTEXT. We have a few more anyway and in \LUAMETATEX\ we
+%D have different numbers. So for now let's just not define them. The
+%D previously mentioned mode parameters enables the real numbers (we have
+%D some more and they are therefore ordered differently).
+
+% \chardef\charifcode = 1
+% \chardef\catifcode = 2
+% \chardef\numifcode = 3
+% \chardef\dimifcode = 4
+% \chardef\oddifcode = 5
+% \chardef\vmodeifcode = 6
+% \chardef\hmodeifcode = 7
+% \chardef\mmodeifcode = 8
+% \chardef\innerifcode = 9
+% \chardef\voidifcode = 10
+% \chardef\hboxifcode = 11
+% \chardef\vboxifcode = 12
+% \chardef\xifcode = 13
+% \chardef\eofifcode = 14
+% \chardef\trueifcode = 15
+% \chardef\falseifcode = 16
+% \chardef\caseifcode = 17
+% \chardef\definedifcode = 18
+% \chardef\csnameifcode = 19
+% \chardef\fontcharifcode = 20
%D Of course we want even bigger log files, so we copied this from the \ETEX\
%D source files.
@@ -695,7 +709,7 @@
\tracinggroups \plusone
\tracingifs \plusone
\tracingscantokens\plusone
- \tracingnesting \plusone
+ \tracingnesting \plustwo
\tracingassigns \plustwo}
\normalprotected\def\loggingall
@@ -720,6 +734,11 @@
\tracingcommands \zerocount
\tracingonline \zerocount}
+%D When we want to see a box we can as well show all of it.
+
+\showboxdepth \maxdimen
+\showboxbreadth\maxdimen
+
%D Just for tracing purposes we set:
\tracingstats\plusone
@@ -801,6 +820,9 @@
\let\then\relax % so that we can say: \ifnum1>2\then -)
+\def\truecondition {\iftrue}
+\def\falsecondition{\iffalse}
+
%D \macros
%D {newmacro,setnewmacro,newfraction}
%D
@@ -1002,7 +1024,7 @@
\spanomit \advance\mscount\minusone
\repeat}
-%D Backend:
+%D For the \LUATEX\ backend (overloaded anyway):
\ifdefined\pdfvariable
@@ -1093,21 +1115,27 @@
\let\pagebottomoffset\voffset \let\normalpagebottomoffset\voffset
\fi
-%D Handy.
+%D Handy (this will change, again).
-\suppresslongerror \plusone
-\suppressoutererror \plusone
-\suppressmathparerror \plusone
-\suppressifcsnameerror\plusone
+\ifdefined\suppresslongerror \suppresslongerror \plusone \fi
+\ifdefined\suppressoutererror \suppressoutererror \plusone \fi
+\ifdefined\suppressmathparerror \suppressmathparerror \plusone \fi
+\ifdefined\suppressifcsnameerror \suppressifcsnameerror \plusone \fi
+\ifdefined\suppressfontnotfounderror\suppressfontnotfounderror\zerocount\fi
-\let \suppresslongerror \relax
-\newcount\suppresslongerror \let\normalsuppresslongerror \suppresslongerror
-\let \suppressoutererror \suppresslongerror \let\normalsuppressoutererror \suppresslongerror
-\let \suppressmathparerror \suppresslongerror \let\normalsuppressmathparerror \suppresslongerror
-\let \suppressifcsnameerror\suppresslongerror \let\normalsuppressifcsnameerror\suppresslongerror
+\let \suppresslongerror \relax
+\newcount\suppresslongerror \let\normalsuppresslongerror \suppresslongerror
+\let \suppressoutererror \suppresslongerror \let\normalsuppressoutererror \suppresslongerror
+\let \suppressmathparerror \suppresslongerror \let\normalsuppressmathparerror \suppresslongerror
+\let \suppressifcsnameerror \suppresslongerror \let\normalsuppressifcsnameerror \suppresslongerror
+\let \suppressfontnotfounderror\suppresslongerror \let\normalsuppressfontnotfounderror\suppresslongerror
\matheqnogapstep\zerocount % for now
+%D Experiment:
+
+\ifdefined\frozen \else \def\frozen{} \let\normalfrozen\frozen \fi
+
%D Now we define a few helpers that we need in a very early stage. We have no
%D message system yet but redundant definitions are fatal anyway.
@@ -1136,4 +1164,14 @@
\let\normalstartdmath \Ustartdisplaymath
\let\normalstopdmath \Ustopdisplaymath
+%D Also better here:
+
+\def\wildcardsymbol{*}
+
+%D Get rid of this, we don't need it. If we ever need to check the order we will
+%D use proper symbolic constants.
+
+\let\eTeXglueshrinkorder \undefined
+\let\eTeXgluestretchorder\undefined
+
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/syst-ini.mkxl b/Master/texmf-dist/tex/context/base/mkiv/syst-ini.mkxl
new file mode 100644
index 00000000000..baca0bb5c1a
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/syst-ini.mkxl
@@ -0,0 +1,1111 @@
+%D \module
+%D [ file=syst-ini,
+%D version=2008.11.04, % 2001.11.16, % 1999.03.17, % an oldie: 1995.10.10
+%D title=\CONTEXT\ System Macros,
+%D subtitle=Bootstrapping \TEX,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D We used to load plain \TEX\ in a special way, but redefining a couple of
+%D primitives so that for instance font loading was ignored. For those interested,
+%D this loader is found in \type {syst-tex.tex}. Some of the comment's are Don
+%D Knuths and more of it can be found in the plain \TEX\ format.
+%D
+%D Characters can have special states, that can be triggered by setting their
+%D category coded. Some are preset, others are to be set as soon as possible,
+%D otherwise we cannot define any useful macros.
+%D
+%D First we define a bunch of constants. Normally we would \type {\setconstant}
+%D but we're prestine and have no macros defined yet. Abstraction also makes it
+%D possible to avoid the \type {^^} in the input.
+
+\chardef\escapecatcode 0
+\chardef\begingroupcatcode 1
+\chardef\endgroupcatcode 2
+\chardef\mathshiftcatcode 3
+\chardef\alignmentcatcode 4
+\chardef\endoflinecatcode 5
+\chardef\parametercatcode 6
+\chardef\superscriptcatcode 7
+\chardef\subscriptcatcode 8
+\chardef\ignorecatcode 9
+\chardef\spacecatcode 10
+\chardef\lettercatcode 11
+\chardef\othercatcode 12 % finally obsolete: \let\other \othercatcode
+\chardef\activecatcode 13 % finally obsolete: \let\active\activecatcode
+\chardef\commentcatcode 14
+\chardef\invalidcatcode 15
+
+%chardef\zeroasciicode 0
+\chardef\tabasciicode 9
+\chardef\newlineasciicode 10 % don't confuse this one with \endoflineasciicode
+\chardef\formfeedasciicode 12
+\chardef\endoflineasciicode 13 % somewhat messy but this can be the active \par
+\chardef\endoffileasciicode 26
+\chardef\spaceasciicode 32
+\chardef\exclamationmarkasciicode 33 % ! used in namespace protection
+\chardef\doublequoteasciicode 34 % "
+\chardef\hashasciicode 35
+\chardef\dollarasciicode 36
+\chardef\commentasciicode 37
+\chardef\ampersandasciicode 38
+\chardef\singlequoteasciicode 39 % '
+\chardef\primeasciicode 39 % '
+\chardef\leftparentasciicode 40
+\chardef\rightparentasciicode 41
+\chardef\hyphenasciicode 45
+\chardef\forwardslashasciicode 47 % /
+\chardef\colonasciicode 58
+\chardef\lessthanasciicode 60 % < used as alternative verbatim {
+\chardef\morethanasciicode 62 % > used as alternative verbatim }
+\chardef\questionmarkasciicode 63 % ? used in namespace protection
+\chardef\atsignasciicode 64 % @ used in namespace protection
+\chardef\backslashasciicode 92 % `\\
+\chardef\circumflexasciicode 94
+\chardef\underscoreasciicode 95
+\chardef\leftbraceasciicode 123 % `\{
+\chardef\barasciicode 124 % `\|
+\chardef\rightbraceasciicode 125 % `\}
+\chardef\tildeasciicode 126 % `\~
+\chardef\delasciicode 127
+
+%catcode\zeroasciicode \ignorecatcode % `\^^@ ascii null is ignored
+\catcode\tabasciicode \spacecatcode % `\^^I ascii tab is a blank space
+\catcode\formfeedasciicode \activecatcode % `\^^L ascii form-feed (active, set later)
+%catcode\endoflineasciicode \endoflinecatcode % `\^^M ascii return is end-line
+\catcode\endoffileasciicode \ignorecatcode % `\^^Z endoffile (ignored in ConTeXt)
+%catcode\spaceasciicode \spacecatcode % `\ ascii space is blank space
+\catcode\hashasciicode \parametercatcode % `\# hash mark is macro parameter character
+\catcode\dollarasciicode \mathshiftcatcode % `\$ dollar sign is math shift
+%catcode\commentasciicode \commentcatcode % `\% percent sign is comment character
+\catcode\ampersandasciicode \alignmentcatcode % `\& ampersand is alignment tab
+%catcode\backslashasciicode \escapecatcode % `\\ backslash is TeX escape character
+\catcode\circumflexasciicode \superscriptcatcode % `\^ circumflex and uparrow are for superscripts
+\catcode\underscoreasciicode \subscriptcatcode % `\_ underline and downarrow are for subscripts
+\catcode\leftbraceasciicode \begingroupcatcode % `\{ left brace is begin-group character
+\catcode\rightbraceasciicode \endgroupcatcode % `\} right brace is end-group character
+\catcode\tildeasciicode \activecatcode % `\~ tilde is active
+%catcode\delasciicode \invalidcatcode % `\^^? ascii delete is invalid
+
+\chardef\statuswrite 128
+
+%D First we need to initialization the primitives. Because \CONTEXT\ is already a
+%D pretty old macro package, we have a couple of issues with respect to primitives.
+%D The \ETEX\ engine added a few as did \PDFTEX. The \LUATEX\ engine added even
+%D more. This means that there can be a potential clash between primitives and
+%D existing macros. The most noticeable ones are:
+%D
+%D \starttyping
+%D \protected
+%D \expanded
+%D \unexpanded
+%D \stoptyping
+%D
+%D Because we had macros like that before the primitives showed up. The protection
+%D related macros were there before we even knew about extensions to the engine.
+%D When the expansion related ones were introduced, we originally came up with
+%D different names but due to requests we used the current names, somethng that in
+%D retrospect was a bad idea: they should have gotten different names in \LUATEX, if
+%D only because at that time only \CONTEXT\ was using them in rolling releases.
+%D Anyway, we're now stuck with this situation, and it means that one should use the
+%D \type {\normal...} variants in low level code:
+%D
+%D \starttyping
+%D \normalexpanded
+%D \normalprotected
+%D \normalunexpanded
+%D \stoptyping
+%D
+%D In the end not using different names in \LUATEX\ for these kind of backfires. It
+%D makes not much sense to fix this in \LUAMETATEX\ because we're now to long on the
+%D road. It is actually the reason why we have the option in \LUATEX\ to alias all
+%D primitives in one go using a prefix. Actually this trick could be used to recover
+%D a primitive meaning: just enable it with some prefix and \type {\let} the
+%D original to that. But \unknown\ we prevent that trick below.
+%D
+%D The code below differs from \LUATEX: in \LUAMETATEX\ all primitives are already
+%D available; it cannot limit itself to being \TEX\ or \ETEX. It could not do that
+%D anyway because there are differences (no backend, to mention one).
+
+\directlua {
+ local primitives = tex.extraprimitives() % "core","tex","etex","luatex"
+ tex.enableprimitives("normal",primitives) % could default to everything
+ function tex.enableprimitives() end % so we kind of protect what's there
+}
+
+\def\space{ }
+\def\empty{}
+
+\letcharcode \formfeedasciicode \par % \def ^^L{\par} formfeed
+\letcharcode \tildeasciicode \ % tilde
+\letcharcode \spaceasciicode \space % space
+
+\expandafter\def\csname\Uchar\tabasciicode \endcsname {\ } % \def\^^I{\ } tab
+\expandafter\def\csname\Uchar\formfeedasciicode \endcsname {\par} % \def\^^L{\par} formfeed
+\expandafter\def\csname\Uchar\endoflineasciicode\endcsname {\ } % \def\^^M{\ } return
+
+%D For now:
+
+\def\gobbleoneargument#1{} % will be defined later on anyway
+
+%D First we define a simplified version of the \CONTEXT\ protection mechanism.
+%D Later we will implement a better variant.
+
+\def\unprotect
+ {\edef\protect
+ {\catcode\atsignasciicode \the\catcode\atsignasciicode \relax
+ \catcode\exclamationmarkasciicode\the\catcode\exclamationmarkasciicode\relax
+ \catcode\questionmarkasciicode \the\catcode\questionmarkasciicode \relax
+ \catcode\underscoreasciicode \the\catcode\underscoreasciicode \relax
+ \let\protect\relax}%
+ \catcode\atsignasciicode \lettercatcode
+ \catcode\exclamationmarkasciicode\lettercatcode
+ \catcode\questionmarkasciicode \lettercatcode
+ \catcode\underscoreasciicode \lettercatcode}
+
+\let\protect\relax
+
+\unprotect
+
+%D Some pretty important definitions:
+
+\let\bgroup={
+\let\egroup=}
+
+%D \macros
+%D {normalbgroup,normalgroup}
+%D
+%D No comment.
+
+%D Allocation of registers is done slightly different than in plain \TEX. First of
+%D all we use different reserved counters. We also don't implement a family handler
+%D because users are not supposed to implement their own math. We reserve the lowest
+%D 31 registers for scratch purposes. Keep in mind that in the core engine some
+%D registers are reserved: counters 0 upto 9, and counter 255.
+%D
+%D As with plain \TEX\ we recommend that macro designers always use \type {\global}
+%D assignments with respect to registers numbered 1, 3, 5 \unknown\ 31, and always
+%D non||\type {\global} assignments with respect to registers 0, 2, 4, \unknown\ 30.
+%D This will prevent \quote {save stack buildup} that might otherwise occur.
+%D
+%D We reserve some registers for special (management) purposes:
+
+% 0 - 20 : scratch
+% 21 - 127 : internal
+% 128 - 254 : inserts
+% 255 : page
+% 256 - : user
+
+\countdef \c_syst_min_allocated_register = 52 \c_syst_min_allocated_register = 256 % can change
+\countdef \c_syst_max_allocated_register = 53 \c_syst_max_allocated_register = 32767
+\countdef \c_syst_min_allocated_read = 54 \c_syst_min_allocated_read = -1
+\countdef \c_syst_max_allocated_read = 55 \c_syst_max_allocated_read = 16
+\countdef \c_syst_min_allocated_language = 56 \c_syst_min_allocated_language = 0
+\countdef \c_syst_max_allocated_language = 57 \c_syst_max_allocated_language = 255
+\countdef \c_syst_min_allocated_insert = 58 \c_syst_min_allocated_insert = 128
+\countdef \c_syst_max_allocated_insert = 59 \c_syst_max_allocated_insert = 254
+\countdef \c_syst_min_allocated_family = 60 \c_syst_min_allocated_family = 128
+\countdef \c_syst_max_allocated_family = 61 \c_syst_max_allocated_family = 255
+\countdef \c_syst_min_allocated_attribute = 62 \c_syst_min_allocated_attribute = 1024 % 0-1023 : private
+\countdef \c_syst_min_allocated_write = 63 \c_syst_min_allocated_write = 0
+\countdef \c_syst_max_allocated_write = 64 \c_syst_max_allocated_write = 127
+
+\countdef \c_syst_last_allocated_count = 32 \c_syst_last_allocated_count = \c_syst_min_allocated_register
+\countdef \c_syst_last_allocated_dimen = 33 \c_syst_last_allocated_dimen = \c_syst_min_allocated_register
+\countdef \c_syst_last_allocated_skip = 34 \c_syst_last_allocated_skip = \c_syst_min_allocated_register
+\countdef \c_syst_last_allocated_muskip = 35 \c_syst_last_allocated_muskip = \c_syst_min_allocated_register
+\countdef \c_syst_last_allocated_box = 36 \c_syst_last_allocated_box = \c_syst_min_allocated_register
+\countdef \c_syst_last_allocated_toks = 37 \c_syst_last_allocated_toks = \c_syst_min_allocated_register
+\countdef \c_syst_last_allocated_read = 38 \c_syst_last_allocated_read = \c_syst_min_allocated_read
+\countdef \c_syst_last_allocated_write = 39 \c_syst_last_allocated_write = \c_syst_min_allocated_write
+\countdef \c_syst_last_allocated_marks = 40 \c_syst_last_allocated_marks = \c_syst_min_allocated_register
+\countdef \c_syst_last_allocated_language = 41 \c_syst_last_allocated_language = \c_syst_min_allocated_language % not used in context
+\countdef \c_syst_last_allocated_insertion = 42 \c_syst_last_allocated_insertion = \c_syst_min_allocated_insert
+\countdef \c_syst_last_allocated_family = 43 \c_syst_last_allocated_family = \c_syst_min_allocated_family % not used in context
+\countdef \c_syst_last_allocated_attribute = 44 \c_syst_last_allocated_attribute = \c_syst_min_allocated_attribute % not used in context
+
+\countdef \c_syst_min_counter_value = 125 \c_syst_min_counter_value = -"7FFFFFFF % beware, we use index 125 at the lua end
+\countdef \c_syst_max_counter_value = 126 \c_syst_max_counter_value = "7FFFFFFF % beware, we use index 126 at the lua end
+
+\countdef \zerocount = 120 \zerocount = 0
+\countdef \plusone = 121 \plusone = 1
+\countdef \minusone = 122 \minusone = -1
+
+\countdef \normalpagebox = 127 \normalpagebox = 255 % hardcoded in pdftex/xetex
+
+% Only to be used by developers in very special cases!
+
+% \def\lastallocatedcount {\the\c_syst_last_allocated_count}
+% \def\lastallocateddimen {\the\c_syst_last_allocated_dimen}
+% \def\lastallocatedskip {\the\c_syst_last_allocated_skip}
+% \def\lastallocatedmuskip {\the\c_syst_last_allocated_muskip}
+% \def\lastallocatedbox {\the\c_syst_last_allocated_dimen}
+% \def\lastallocatedtoks {\the\c_syst_last_allocated_toks}
+% \def\lastallocatedattribute{\the\c_syst_last_allocated_attribute}
+
+% A few traditional allocations (these might go):
+
+\countdef \count@ 255 % hm, used in \newif .. todo: replace it there
+\dimendef \dimen@ 0
+\dimendef \dimen@i 1 % global only
+\dimendef \dimen@ii 2
+
+%D So, effectively we start allocating from 256 and upwards. The inserts sit in the
+%D range 128 upto 254. Page numbers use the counters 0 upto 9 and the pagebox is
+%D 255. Users can use the scratch registers upto 31 without problem but all others
+%D are reserved.
+
+\let\wlog\gobbleoneargument % Let's get rid of this one.
+
+%D The allocators share a common helper macro.
+
+\normalprotected\def\newcount {\syst_basics_allocate\c_syst_last_allocated_count \count \countdef \c_syst_max_allocated_register}
+\normalprotected\def\newdimen {\syst_basics_allocate\c_syst_last_allocated_dimen \dimen \dimendef \c_syst_max_allocated_register}
+\normalprotected\def\newskip {\syst_basics_allocate\c_syst_last_allocated_skip \skip \skipdef \c_syst_max_allocated_register}
+\normalprotected\def\newmuskip {\syst_basics_allocate\c_syst_last_allocated_muskip \muskip \muskipdef \c_syst_max_allocated_register}
+\normalprotected\def\newbox {\syst_basics_allocate\c_syst_last_allocated_box \box \mathchardef\c_syst_max_allocated_register}
+\normalprotected\def\newtoks {\syst_basics_allocate\c_syst_last_allocated_toks \toks \toksdef \c_syst_max_allocated_register}
+\normalprotected\def\newread {\syst_basics_allocate\c_syst_last_allocated_read \read \chardef \c_syst_max_allocated_read}
+\normalprotected\def\newwrite {\syst_basics_allocate\c_syst_last_allocated_write \write \chardef \c_syst_max_allocated_write}
+\normalprotected\def\newmarks {\syst_basics_allocate\c_syst_last_allocated_marks \marks \mathchardef\c_syst_max_allocated_register}
+\normalprotected\def\newinsert {\syst_basics_allocate\c_syst_last_allocated_insertion\insert \chardef \c_syst_max_allocated_insert}
+
+%D We don't need these in \CONTEXT:
+
+\normalprotected\def\newlanguage{\syst_basics_allocate\c_syst_last_allocated_language \language\chardef \c_syst_max_allocated_language}
+\normalprotected\def\newfamily {\syst_basics_allocate\c_syst_last_allocated_family \fam \chardef \c_syst_max_allocated_family}
+
+\let\newfam\newfamily
+
+\firstvalidlanguage\plusone
+
+% Watch out, for the moment we disable the check for already being defined
+% later we will revert this but first all chardefs must be replaced.
+
+\normalprotected\def\newconstant #1{\ifdefined#1\let#1\undefined\fi\newcount#1}
+\normalprotected\def\setnewconstant #1{\ifdefined#1\let#1\undefined\fi\newcount#1#1} % just a number
+\normalprotected\def\setconstant {} % dummy, no checking, so it warns
+\normalprotected\def\setconstantvalue#1#2{\csname#1\endcsname\numexpr#2\relax}
+
+% maybe setconstant with check
+
+% %D The next definitions are really needed (in \CONTEXT):
+
+\newlinechar\newlineasciicode \edef\outputnewlinechar{\Uchar\newlineasciicode} % {^^J}
+
+%D One reason to start high with allocation is that it permits us to allocate
+%D consecutive ranges more easily, for instance if for \MPLIB\ we want to allocate a
+%D continuous range of boxes. It also permits us to do a proper upward allocation
+%D for inserts. The current code evolved from code that dealt with older engines but
+%D as all engines now provide many registers we removed all traces.
+
+\ifdefined\writestatus \else
+ %\normalprotected\def\writestatus#1#2{\immediate\write\statuswrite{#1: #2}}
+ \normalprotected\def\writestatus#1#2{\message{#1: #2}}
+\fi
+
+\def\syst_basics_allocate_yes#1#2#3#4#5% last class method max name
+ {\ifnum#1<#4\relax
+ \global\advance#1\plusone
+ \global#3#5=#1\relax
+ \else
+ \writestatus{warning}{no room for \string#2\space \string#5\space (max: \number#4)}%
+ \fi}
+
+\def\syst_basics_allocate_nop#1#2#3#4#5% last class method max name
+ {\writestatus{warning}{\string#2 \string#5 is already defined (\string\relax\space it first)}}
+
+\def\syst_basics_allocate#1#2#3#4#5% last class method max name
+ {\ifx#5\undefined
+ \expandafter\syst_basics_allocate_yes
+ \else\ifx#5\relax
+ \expandafter\expandafter\expandafter\syst_basics_allocate_yes
+ \else
+ \expandafter\expandafter\expandafter\syst_basics_allocate_nop
+ \fi\fi
+ #1#2#3#4#5}
+
+%D Since the number of chars exceed 256 now, we can use \type {\chardef} instead of
+%D the more limited \type {\mathchardef}.
+
+\normalprotected\def\newbox {\syst_basics_allocate\c_syst_last_allocated_box \box \chardef\c_syst_max_allocated_register}
+\normalprotected\def\newmarks{\syst_basics_allocate\c_syst_last_allocated_marks\marks\chardef\c_syst_max_allocated_register}
+
+%D Attributes are something very \LUATEX. In \CONTEXT\ you are not supposed to use
+%D the attributes directly but always allocate then first. For instance attribute~0
+%D is reserved for special purposes (this might change). Attributes in the range
+%D 128-1023 are private and should not be touched.
+
+\let\attributeunsetvalue\c_syst_min_counter_value % used to be \minusone
+
+\normalprotected\def\newattribute{\syst_basics_allocate\c_syst_last_allocated_attribute\attribute\attributedef\c_syst_max_allocated_register}
+
+%D Not used by \CONTEXT\ but for instance \PICTEX\ needs it. It's a trick to force
+%D strings instead of tokens that take more memory. It's a trick to trick to force
+%D strings. This macro is never used in \CONTEXT.
+
+%normalprotected\def\newhelp#1#2{\newtoks#1#1\expandafter{\csname#2\endcsname}}
+\normalprotected\def\newhelp#1#2{\newtoks#1#1\expandafter{\detokenize{#2}}}
+
+%D \macros
+%D {scratchcounter,
+%D scratchdimen,scratchskip,scratchmuskip,
+%D scratchbox,
+%D scratchtoks}
+%D
+%D We now define a few scratch registers, so that successive loads at least have
+%D some available. The private ones are used in cases where we don't want to
+%D intrude on normal scratch ones.
+
+\newcount \scratchcounter \newcount \globalscratchcounter \newcount \privatescratchcounter
+\newdimen \scratchdimen \newdimen \globalscratchdimen \newdimen \privatescratchdimen
+\newskip \scratchskip \newskip \globalscratchskip \newskip \privatescratchskip
+\newmuskip\scratchmuskip \newmuskip\globalscratchmuskip \newmuskip\privatescratchmuskip
+\newtoks \scratchtoks \newtoks \globalscratchtoks \newtoks \privatescratchtoks
+\newbox \scratchbox \newbox \globalscratchbox \newbox \privatescratchbox
+
+\newcount\scratchcounterone \newcount\scratchcountertwo \newcount\scratchcounterthree
+\newdimen \scratchdimenone \newdimen \scratchdimentwo \newdimen \scratchdimenthree
+\newskip \scratchskipone \newskip \scratchskiptwo \newskip \scratchskipthree
+\newmuskip\scratchmuskipone \newmuskip\scratchmuskiptwo \newmuskip\scratchmuskipthree
+\newtoks \scratchtoksone \newtoks \scratchtokstwo \newtoks \scratchtoksthree
+\newbox \scratchboxone \newbox \scratchboxtwo \newbox \scratchboxthree
+
+\newcount\scratchcounterfour \newcount\scratchcounterfive \newcount\scratchcountersix
+\newdimen \scratchdimenfour \newdimen \scratchdimenfive \newdimen \scratchdimensix
+\newskip \scratchskipfour \newskip \scratchskipfive \newskip \scratchskipsix
+\newmuskip\scratchmuskipfour \newmuskip\scratchmuskipfive \newmuskip\scratchmuskipsix
+\newtoks \scratchtoksfour \newtoks \scratchtoksfive \newtoks \scratchtokssix
+\newbox \scratchboxfour \newbox \scratchboxfive \newbox \scratchboxsix
+
+\newcount\globalscratchcounterone
+\newcount\globalscratchcountertwo
+\newcount\globalscratchcounterthree
+
+%D \macros
+%D {tempstring}
+
+\let\tempstring\empty
+
+%D \macros
+%D {scratchwidth, scratchheight, scratchdepth, scratchoffset, scratchdistance}
+%D
+%D A few more scratch dimensions:
+
+\newdimen\scratchwidth
+\newdimen\scratchheight
+\newdimen\scratchdepth
+\newdimen\scratchtotal
+
+\newdimen\scratchoffset
+\newdimen\scratchleftoffset
+\newdimen\scratchrightoffset
+\newdimen\scratchtopoffset
+\newdimen\scratchbottomoffset
+
+\newdimen\scratchdistance
+
+\newdimen\scratchhsize
+\newdimen\scratchvsize
+
+\newdimen\scratchxoffset
+\newdimen\scratchyoffset
+\newdimen\scratchhoffset
+\newdimen\scratchvoffset
+
+\newdimen\scratchxposition
+\newdimen\scratchyposition
+
+\newcount\scratchnx
+\newcount\scratchny
+
+\newcount\scratchmx
+\newcount\scratchmy
+
+\newcount\scratchmin
+\newcount\scratchmax
+
+\newcount\scratchunicode
+
+\newdimen\scratchleftskip
+\newdimen\scratchrightskip
+\newdimen\scratchtopskip
+\newdimen\scratchbottomskip
+
+%D More allocations:
+
+\newskip \zeroskip \zeroskip 0pt plus 0pt minus 0pt
+\newdimen \zeropoint \zeropoint 0pt
+\newdimen \onepoint \onepoint 1pt
+\newdimen \halfapoint \halfapoint 0.5pt
+\newdimen \maxdimen \maxdimen 16383.99999pt % 1073741823sp
+\newcount \maxcount \maxcount 2147483647
+\newdimen \onebasepoint \onebasepoint 1bp
+\newdimen \scaledpoint \scaledpoint 1sp
+\newdimen \thousandpoint \thousandpoint 1000pt
+\newmuskip\zeromuskip \zeromuskip 0mu
+\newmuskip\onemuskip \onemuskip 1mu
+
+\newmuskip\muquad \muquad 18mu
+
+\let\points \onepoint
+\let\halfpoint\halfapoint
+
+\newtoks \emptytoks
+
+%D And even more: (todo: countdefs 60+)
+
+%newcount\minusone \minusone -1
+\newcount\minustwo \minustwo -2
+%chardef \zerocount 0
+%chardef \plusone 1
+\chardef \plustwo 2
+\chardef \plusthree 3
+\chardef \plusfour 4
+\chardef \plusfive 5
+\chardef \plussix 6
+\chardef \plusseven 7
+\chardef \pluseight 8
+\chardef \plusnine 9
+\chardef \plusten 10
+\chardef \plussixteen 16
+\chardef \plusfifty 50
+\chardef \plushundred 100
+\chardef \plusonehundred 100
+\chardef \plustwohundred 200
+\chardef \plusfivehundred 500
+\chardef \pluscxxvii 127
+\chardef \pluscxxviii 128
+\chardef \pluscclv 255
+\chardef \pluscclvi 256
+\chardef \plusthousand 1000
+\chardef \plustenthousand 10000
+\chardef \plustwentythousand 20000
+\chardef \medcard 32768
+\chardef \maxcard 65536 % pdftex has less mathchars
+\chardef \maxcardminusone 65535
+
+%D \macros
+%D {doubleexpandafter,tripleexpandafter,expanded,startexpanded}
+%D
+%D A few handy shortcuts
+
+\let\singleexpandafter \expandafter
+\def\doubleexpandafter{\expandafter\expandafter\expandafter}
+\def\tripleexpandafter{\expandafter\doubleexpandafter\expandafter}
+
+%D We prefer the more readable variant than in plain \TEX. User should only
+%D use \type {\emptybox}:
+
+\newbox\voidbox % public
+
+\let\normalhbox\hbox
+\let\normalvbox\vbox
+
+\def\unvoidbox{\unhbox\voidbox}
+\def\emptybox {\box \voidbox} % used in initializations so no attributes
+\def\emptyvbox{\normalvpack{}} % no copy as we need to set attributes
+\def\emptyhbox{\normalhpack{}} % no copy as we need to set attributes
+
+\let\leavevmode\unvoidbox % we prefer to use \dontleavehmode
+
+%D \macros
+%D {dontcomplain}
+%D
+%D We need this one soon:
+
+\normalprotected\def\dontcomplain
+ {\hbadness\plustenthousand
+ \vbadness\plustenthousand
+ \hfuzz \maxdimen
+ \vfuzz \maxdimen}
+
+%D Some expected plain variants follow. We don't reuse registers because we
+%D don't want clashes.
+
+\let \p@ \onepoint
+\let \m@ne \minusone
+\let \z@ \zeropoint
+\let \@ne \plusone
+\let \tw@ \plustwo
+\let \thr@@ \plusthree
+\let \sixt@@n \plussixteen
+\let \@cclv \pluscclv
+\let \@cclvi \pluscclvi
+\let \voidb@x \voidbox
+\newtoks \toks@ % \scratchtoks
+
+%D We define \type {\newif} a la plain \TEX, but will redefine it later. As
+%D Knuth says:
+%D
+%D \startnarrower
+%D And here's a different sort of allocation: for example,
+%D
+%D \starttyping
+%D \newif\iffoo
+%D \stoptyping
+%D
+%D creates \type {\footrue}, \type {\foofalse} to go with \type {\iffoo}.
+%D \stopnarrower
+
+% \normalprotected\def\newif#1%
+% {\count@\escapechar
+% \escapechar\minusone
+% \expandafter\expandafter\expandafter\def\new_if #1{true}{\let#1\iftrue }%
+% \expandafter\expandafter\expandafter\def\new_if#1{false}{\let#1\iffalse}%
+% \new_if#1{false}% the condition starts out false
+% \escapechar\count@}
+%
+% \def\new_if#1#2%
+% {\csname\expandafter\if@\string#1#2\endcsname}
+%
+% \bgroup % `if' is required
+% \uccode`1=`i \uccode`2=`f \uppercase{\gdef\if@12{}}
+% \egroup
+
+% We use \csstring so there is no need to push/pop escapechar.
+% We use different names so that we get a better error message.
+%
+% \normalprotected\def\newif#1%
+% {\let\new_if_saved\newif
+% \let\newif\new_if_check
+% \expandafter\expandafter\expandafter\def\new_if_cs #1{true}{\let#1\iftrue }%
+% \expandafter\expandafter\expandafter\def\new_if_cs#1{false}{\let#1\iffalse}%
+% \new_if_cs#1{false}%
+% \let\newif\new_if_saved}
+%
+% \normalprotected\def\new_if_cs#1#2%
+% {\csname\expandafter\newif\csstring#1#2\endcsname}
+%
+% We wrap all into one macro:
+
+\normalprotected\def\newif#1%
+ {\let\new_if_saved\newif
+ \let\newif\new_if_check
+ \expandafter\def\csname\expandafter\newif\csstring#1true\endcsname {\let#1\iftrue }%
+ \expandafter\def\csname\expandafter\newif\csstring#1false\endcsname{\let#1\iffalse}%
+ \csname\expandafter\newif\csstring#1false\endcsname
+ \let\newif\new_if_saved}
+
+\bgroup
+ \normalexpanded{\gdef\noexpand\new_if_check\string i\string f{}}
+\egroup
+
+%D Let's test this one:
+
+\newif\ifdone
+\newif\iffound
+
+\let\htdp\boxtotal
+
+%D A few shortcuts:
+
+\normalprotected\def\udef {\normalprotected\def }
+\normalprotected\def\ugdef{\normalprotected\gdef}
+\normalprotected\def\uedef{\normalprotected\edef}
+\normalprotected\def\uxdef{\normalprotected\xdef}
+
+%D For a while we keep the following, as systems like tikz need it. Best
+%D not use that one \CONTEXT.
+
+\let\active\activecatcode
+
+%D Constants to be used with \type {\currentgrouptype}.
+
+\chardef\bottomlevelgroupcode = 0
+\chardef\simplegroupcode = 1
+\chardef\hboxgroupcode = 2
+\chardef\adjustedhboxgroupcode = 3
+\chardef\vboxgroupcode = 4
+\chardef\vtopgroupcode = 5
+\chardef\aligngroupcode = 6
+\chardef\noaligngroupcode = 7
+\chardef\outputgroupcode = 8
+\chardef\mathgroupcode = 9
+\chardef\discretionarygroupcode = 10
+\chardef\insertgroupcode = 11
+\chardef\vcentergroupcode = 12
+\chardef\mathchoicegroupcode = 13
+\chardef\semisimplegroupcode = 14
+\chardef\mathshiftgroupcode = 15
+\chardef\mathleftgroupcode = 16
+\chardef\vadjustgroupcode = \insertgroupcode
+
+%D Constants to be used with \type {\interactionmode}.
+
+\chardef\batchmodecode \zerocount
+\chardef\nonstopmodecode \plusone
+\chardef\scrollmodecode \plustwo
+\chardef\errorstopmodecode \plusthree
+
+%D Constants to be used with \type {\lastnodetype}. The \type {\lastnodetype}
+%D primitive is \ETEX\ compliant. The valid range is still -1 .. 15 and glyph nodes
+%D have number 0 (used to be char node) and ligature nodes are mapped to 7. That way
+%D macro packages can use the same symbolic names as in traditional \ETEX. Keep in
+%D mind that the internal node numbers are different and that there are more node
+%D types that 15. The mode parameter forces \LUAMETATEX\ to use the real node
+%D numbers.
+
+\internalcodesmode\plusone
+
+%D Constants to be used with \type {\currentiftype}. I wonder if we will ever
+%D use these in \CONTEXT. We have a few more anyway and in \LUAMETATEX\ we
+%D have different numbers. So for now let's just not define them. The
+%D previously mentioned mode parameters enables the real numbers (we have
+%D some more and they are therefore ordered differently).
+
+% \chardef\charifcode = 1
+% \chardef\catifcode = 2
+% \chardef\numifcode = 3
+% \chardef\dimifcode = 4
+% \chardef\oddifcode = 5
+% \chardef\vmodeifcode = 6
+% \chardef\hmodeifcode = 7
+% \chardef\mmodeifcode = 8
+% \chardef\innerifcode = 9
+% \chardef\voidifcode = 10
+% \chardef\hboxifcode = 11
+% \chardef\vboxifcode = 12
+% \chardef\xifcode = 13
+% \chardef\eofifcode = 14
+% \chardef\trueifcode = 15
+% \chardef\falseifcode = 16
+% \chardef\caseifcode = 17
+% \chardef\definedifcode = 18
+% \chardef\csnameifcode = 19
+% \chardef\fontcharifcode = 20
+%
+% % there are some more in luametatex
+
+%D Of course we want even bigger log files, so we copied this from the \ETEX\
+%D source files.
+%D
+%D When watching such logs, beware of nasty side effects of \type {\scantokens},
+%D as in:
+%D
+%D \starttyping
+%D \bgroup
+%D \lccode`a=12\lowercase{\xdef\whatever{a}}\egroup
+%D \def\whatever{test \whatever test}
+%D \scantokens\expandafter{\whatever}
+%D \egroup
+%D \stoptyping
+%D
+%D In \LUATEX\ we have ways around this.
+
+% no longer \errorstopmode cf. plain tex 3.141592653
+
+\normalprotected\def\tracingall
+ {\tracingonline \plusone
+ \tracingcommands \plusthree
+ \tracingstats \plustwo
+ \tracingpages \plusone
+ \tracingoutput \plusone
+ \tracinglostchars \plustwo
+ \tracingmacros \plustwo
+ \tracingparagraphs\plusone
+ \tracingrestores \plusone
+ \showboxbreadth \maxdimen
+ \showboxdepth \maxdimen
+ \tracinggroups \plusone
+ \tracingifs \plusone
+ \tracingscantokens\plusone
+ \tracingnesting \plustwo
+ \tracingassigns \plustwo}
+
+\normalprotected\def\loggingall
+ {\tracingall
+ \tracingonline \zerocount}
+
+\normalprotected\def\tracingnone
+ {\tracingassigns \zerocount
+ \tracingnesting \zerocount
+ \tracingscantokens\zerocount
+ \tracingifs \zerocount
+ \tracinggroups \zerocount
+ \showboxdepth \plusthree
+ \showboxbreadth \plusfive
+ \tracingrestores \zerocount
+ \tracingparagraphs\zerocount
+ \tracingmacros \zerocount
+ \tracinglostchars \plusone
+ \tracingoutput \zerocount
+ \tracingpages \zerocount
+ \tracingstats \zerocount
+ \tracingcommands \zerocount
+ \tracingonline \zerocount}
+
+%D When we want to see a box we can as well show all of it.
+
+\showboxdepth \maxdimen
+\showboxbreadth\maxdimen
+
+%D Just for tracing purposes we set:
+
+\tracingstats\plusone
+
+%D Here we also save \type {\input}, more will be saved later.
+
+\ifdefined\normalinput \else \let\normalinput\input \fi
+
+%D We don't like outer commands, and we always want access to the original
+%D \type {\input} primitive.
+
+\let\normalouter\outer \def\outer{} % no longer \relax
+
+%D To circumvent dependencies, we can postpone certain initializations to
+%D dumping time, by appending them to the \type {\everydump} token register.
+
+\ifdefined\normaldump \else \let\normaldump\dump \fi
+
+\newtoks\everydump
+
+\def\dump{\the\everydump\normaldump}
+
+%D The same applies for the startup actions.
+
+\ifdefined\normaleveryjob \else \let\normaleveryjob\everyjob \fi
+
+\let\everyjob\relax \newtoks\everyjob
+
+\normaleveryjob{\the\everyjob}
+
+%D \macros
+%D {newconditional,
+%D settrue, setfalse,
+%D ifconditional,then}
+%D
+%D \TEX's lacks boolean variables, although the \PLAIN\ format implements \type
+%D {\newif}. The main disadvantage of this scheme is that it takes three hash table
+%D entries. A more memory saving alternative is presented here. A conditional is
+%D defined by:
+%D
+%D \starttyping
+%D \newconditional\doublesided
+%D \setfalse
+%D \stoptyping
+%D Setting a conditional is done by \type{\settrue} and
+%D \type{\setfalse}:
+%D
+%D \starttyping
+%D \settrue\doublesided
+%D \setfalse
+%D \stoptyping
+%D while testing is accomplished by:
+%D
+%D \starttyping
+%D \ifconditional\doublesided ... \else ... \fi
+%D \setfalse
+%D \stoptyping
+%D We cannot use the simple scheme:
+%D
+%D \starttyping
+%D \def\settrue #1{\let#1=\iftrue}
+%D \def\setfalse#1{\let#1=\iffalse}
+%D \stoptyping
+%D
+%D Such an implementation gives problems with nested conditionals. The next
+%D implementation is about as fast and just as straightforward:
+
+\let\conditionalfalse\plusone % maybe we will have a dedicated count/chardef
+\let\conditionaltrue \zerocount % maybe we will have a dedicated count/chardef
+
+\normalprotected\def\settrue #1{\let#1\conditionaltrue }
+\normalprotected\def\setfalse#1{\let#1\conditionalfalse}
+
+\normalprotected\def\settruevalue #1{\expandafter\let\csname#1\endcsname\conditionaltrue }
+\normalprotected\def\setfalsevalue#1{\expandafter\let\csname#1\endcsname\conditionalfalse}
+
+\let\newconditional\setfalse
+\let\ifconditional \ifcase
+
+\let\then\relax % so that we can say: \ifnum1>2\then -)
+
+\def\truecondition {\iftrue}
+\def\falsecondition{\iffalse}
+
+% This one has to be unprotected otherwise we get a files-ends-to-soon but it's ok
+% as conditions expand anyway.
+
+\def\quitcondition{\orelse\iffalse}
+
+%D \macros
+%D {newmacro,setnewmacro,newfraction}
+%D
+%D Let's be complete and also introduce some definers. These are not mandate
+%D but handy for grepping.
+
+\normalprotected\def\newmacro #1{\let#1\empty}
+\normalprotected\def\setnewmacro#1{\let#1}
+
+\def\!!zerocount{0}
+\def\!!plusone {1}
+
+\normalprotected\def\newfraction#1{\let#1\!!plusone}
+
+%D It would be handy to have a primitive \type {\unless\ifcase} because then we
+%D could use nicer values. Anyhow, this conditional code used to be in the \type
+%D {syst-aux} module but is now promoted to here.
+
+%D \macros
+%D {ifzeropt}
+%D
+%D The next macro is both cosmetic and byte saving. It is pretty \type
+%D {\if}||safe too. It can be used in cases like:
+%D
+%D \starttyping
+%D \ifzeropt \somedimen ... \else ... \fi
+%D \stoptyping
+
+\let\ifzeropt\ifcase
+
+% these token list helpers might move to syst-aux.mkiv
+%
+% we assume a \cs. not toks0 or so
+%
+% \normalprotected\def\appendtotoks #1#{\def\temp{#1}\afterassignment\doappendtotoks \scratchtoks=}
+% \normalprotected\def\prependtotoks#1#{\def\temp{#1}\afterassignment\doprependtotoks\scratchtoks=}
+
+\newtoks\t_syst_toks_temp \let\m_syst_toks_temp\t_syst_toks_temp
+
+\normalprotected\def\appendtotoks #1{\let\m_syst_toks_temp#1\afterassignment\syst_toks_append_l \t_syst_toks_temp=}
+\normalprotected\def\prependtotoks#1{\let\m_syst_toks_temp#1\afterassignment\syst_toks_prepend_l\t_syst_toks_temp=}
+
+% \def\syst_toks_append {\m_syst_toks_temp\expandafter\expandafter\expandafter{\expandafter\the\expandafter\m_syst_toks_temp\the\t_syst_toks_temp}}}
+% \def\syst_toks_prepend{\m_syst_toks_temp\expandafter\expandafter\expandafter{\expandafter\the\expandafter\t_syst_toks_temp\the\m_syst_toks_temp}}}
+
+\normalprotected\def\globalappendtotoks #1{\let\m_syst_toks_temp#1\afterassignment\syst_toks_append_g \t_syst_toks_temp=}
+\normalprotected\def\globalprependtotoks#1{\let\m_syst_toks_temp#1\afterassignment\syst_toks_prepend_g\t_syst_toks_temp=}
+
+\def\syst_toks_append_l {\normalexpanded{\m_syst_toks_temp{\the\m_syst_toks_temp\the\t_syst_toks_temp}}}
+\def\syst_toks_prepend_l{\normalexpanded{\m_syst_toks_temp{\the\t_syst_toks_temp\the\m_syst_toks_temp}}}
+
+\def\syst_toks_append_g {\global\syst_toks_append_l }
+\def\syst_toks_prepend_g{\global\syst_toks_prepend_l}
+
+\normalprotected\def\addtotoks #1{\let\m_syst_toks_temp#1\afterassignment\syst_toks_add_l\let\next}
+\normalprotected\def\globaladdtotoks#1{\let\m_syst_toks_temp#1\afterassignment\syst_toks_add_g\let\next}
+
+\def\syst_toks_add_l{\m_syst_toks_temp\expandafter\bgroup\the\m_syst_toks_temp}
+\def\syst_toks_add_g{\global\syst_toks_add_l}
+
+\normalprotected\def\addtotokscs #1#2{#1{\the#1#2}} % saves a few bytes
+\normalprotected\def\globaladdtotokscs#1#2{\global#1{\the#1#2}} % saves a few bytes
+
+%D \macros
+%D {begcsname}
+%D
+%D Handy for \ETEX-only usage (avoids making \type {\relax}'s:
+
+% \def\begcsname#1\endcsname{\ifcsname#1\endcsname\csname#1\endcsname\fi}
+
+\let\begcsname\begincsname
+
+%D Now come a few macros that might be needed in successive loading. We redefine the
+%D \type {\par} primitive pretty soon so that we get the equivalents right.
+
+% too tricky: \par is use more often than a par starts so we have too much change
+% that we get assymetrical behaviour
+%
+% \newtoks\everyendpar
+%
+% \normalprotected\def\endpar{\the\everyendpar\normalpar}
+% \normalprotected\def\par {\endpar}
+%
+% \normalprotected\def\reseteverypar
+% {\everypar \emptytoks
+% \everyendpar\emptytoks}
+
+\normalprotected\def\reseteverypar
+ {\everypar\emptytoks}
+
+\let\endgraf\par
+\let\endline\cr
+
+\normalprotected\def\null{\hpack{}}
+
+%D The following two might be overloaded later on but some modules need then
+%D earlier. These functionality is reflected in the name and will not change.
+
+% \bgroup
+% \catcode`\^^M=\activecatcode%
+% \gdef\obeylines{\catcode`\^^M\activecatcode \let^^M\par}%
+% \glet^^M\par%
+% \egroup
+%
+% \bgroup
+% \gdef\obeyspaces{\catcode`\ \activecatcode}%
+% \obeyspaces\glet =\space%
+% \egroup
+
+\def\obeylines {\catcode\endoflineasciicode\activecatcode\letcharcode\endoflineasciicode\par}
+\def\obeyspaces{\catcode\spaceasciicode \activecatcode\letcharcode\spaceasciicode \space}
+
+% %D A constant:
+%
+% \let\endoflinetoken=^^M
+
+%D Also needed might be a simple loop structure and we borrow plain \TEX's one
+%D as it is often expected to be present and it is about the fastest you can
+%D get. Beware: this macro does not support nested loops. We use a namespace
+%D prefix \type {@@pln}.
+
+\def\loop#1\repeat{\def\@@plnbody{#1}\@@plniterate} % might go
+
+%D The following makes \type {\loop} \unknown\ \type {\if} \unknown\ \type
+%D {\repeat} skippable (clever trick):
+
+\let\repeat\fi % so both \loop and \repeat are reserved words!
+
+%D The original (no \type {@@pln} there):
+%D
+%D \starttyping
+%D \def\@@plniterate{\@@plnbody\let\next\@@plniterate\else\let\next\relax\fi\next}
+%D \stoptyping
+%D
+%D A more efficient alternative:
+%D
+%D \starttyping
+%D \def\@@plniterate{\@@plnbody\expandafter\@@plniterate\else\expandafter\relax\fi}
+%D \stoptyping
+%D
+%D An even more efficient one:
+
+\def\@@plniterate{\@@plnbody\expandafter\@@plniterate\else\fi}
+
+%D We don't define a real output routine yet but at least get rid of pages:
+
+\output{\shipout\box\normalpagebox}
+
+%D Although we don't add pagenumbers yet we alias the default register used
+%D for counting pages:
+
+\countdef\pageno\zerocount \pageno\plusone % first page is number 1
+
+%D Beside the raw counter \type {\pageno} the \type {\folio} macro provides
+%D the value.
+
+\def\folio{\the\pageno} % kind of expected and therefore reserved
+
+%D The following registers are kind of standard and (for the moment) we define
+%D them here. This might change.
+
+\newskip \bigskipamount \bigskipamount = 12pt plus 4pt minus 4pt
+\newskip \medskipamount \medskipamount = 6pt plus 2pt minus 2pt
+\newskip \smallskipamount \smallskipamount = 3pt plus 1pt minus 1pt
+
+\baselineskip = 12pt
+\lineskip = 1pt
+\lineskiplimit = 0pt
+
+%D Sometimes kerns make more sense than glue but we need to be in the
+%D right mode:
+
+\normalprotected\def\vkern{\ifhmode\par \fi\kern}
+\normalprotected\def\hkern{\ifvmode\dontleavehmode\fi\kern}
+
+%D Again a few kind-of-extensions the core. These come from plain \TEX\ but
+%D are probably not used in \CONTEXT.
+
+\newskip \hideskip \hideskip = -1000pt plus 1fill
+\newskip \centering \centering = 0pt plus 1000pt minus 1000pt
+
+\def\hidewidth % for alignment entries that can stick out
+ {\hskip\hideskip}
+
+\def\ialign % initialized \halign
+ {\everycr\emptytoks
+ \tabskip\zeroskip
+ \halign}
+
+\newcount \mscount
+
+\def\spanomit{\span\omit} % bypass error message
+
+\def\multispan#1%
+ {\omit
+ \mscount#1\relax
+ \loop
+ \ifnum\mscount>\plusone
+ \spanomit \advance\mscount\minusone
+ \repeat}
+
+\let\nopdfcompression \relax
+\let\onlypdfobjectcompression\relax
+\let\maximumpdfcompression \relax
+\let\normalpdfcompression \relax
+
+%D Basic status stuff.
+
+\newif\ifproductionrun
+
+%D For those who expect this \unknown
+
+\ifx\fmtname \undefined \def\fmtname {ConTeXt Initial TeX} \fi
+\ifx\fmtversion\undefined \def\fmtversion{3.1415926} \fi
+
+%D A few bonus macros:
+
+\def\modulonumber#1#2{\the\numexpr#2-((((#2+(#1/2))/#1)-1)*#1)\relax}
+\def\dividenumber#1#2{\the\numexpr(#2-(#1/2))/#1\relax}
+
+%D These could be set at the \LUA\ end instead:
+
+\edef\texenginename {\directlua{tex.print(LUATEXENGINE)}}
+\edef\texengineversion {\directlua{tex.print(LUATEXVERSION)}}
+\edef\texenginefunctionality{\directlua{tex.print(LUATEXFUNCTIONALITY)}}
+
+%D We have no reason not to enable this:
+
+\savingvdiscards\plusone
+
+%D We only can set this one via directives (system.synctex) and we only support
+%D the context variant. This will go away completely.
+
+\newcount\synctex \let\normalsynctex\synctex
+
+%D We get rid of the funny \TEX\ offset defaults of one inch by setting them to zero.
+
+\voffset\zeropoint \let\voffset\relax \newdimen\voffset \let\normalvoffset\voffset
+\hoffset\zeropoint \let\hoffset\relax \newdimen\hoffset \let\normalhoffset\hoffset
+
+\matheqnogapstep\zerocount % for now
+
+%D Now we define a few helpers that we need in a very early stage. We have no
+%D message system yet but redundant definitions are fatal anyway.
+
+\newcount\c_syst_helpers_n_of_namespaces \c_syst_helpers_n_of_namespaces\pluseight % 1-8 reserved for catcodes
+
+\def\v_interfaces_prefix_template_system{\number \c_syst_helpers_n_of_namespaces>>}
+%def\v_interfaces_prefix_template_system{\characters\c_syst_helpers_n_of_namespaces>>} % no \characters yet
+
+\normalprotected\def\installsystemnamespace#1%
+ {\ifcsname ??#1\endcsname
+ \immediate\write\statuswrite{fatal error: duplicate system namespace '#1'}%
+ \expandafter\normalend
+ \else
+ \global\advance\c_syst_helpers_n_of_namespaces\plusone
+ \expandafter\edef\csname ??#1\endcsname{\v_interfaces_prefix_template_system}%
+ \fi}
+
+%D It makes more sense to have these here:
+
+\let\normalsuperscript \Usuperscript
+\let\normalsubscript \Usubscript
+\let\normalnosuperscript\Unosuperscript
+\let\normalnosubscript \Unosubscript
+\let\normalstartimath \Ustartmath
+\let\normalstopimath \Ustopmath
+\let\normalstartdmath \Ustartdisplaymath
+\let\normalstopdmath \Ustopdisplaymath
+
+%D Also better here:
+
+\def\wildcardsymbol{*}
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/syst-lua.lua b/Master/texmf-dist/tex/context/base/mkiv/syst-lua.lua
index a63c49e8faf..5911d7f0059 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/syst-lua.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/syst-lua.lua
@@ -156,3 +156,245 @@ implement {
end
end
}
+
+-- This is a bit of a joke as I never really needed floating point expressions (okay,
+-- maybe only with scaling because there one can get numbers that are too large for
+-- dimensions to deal with). Of course one can write a parser in \TEX\ speak but then
+-- one also needs to implement a bunch of functions. It doesn't pay of so we just
+-- stick to the next gimmick. It looks inefficient but performance is actually quite
+-- efficient.
+
+local concat = table.concat
+local utfchar = utf.char
+local load, type, tonumber = load, type, tonumber
+
+local xmath = xmath or math
+local xcomplex = xcomplex or { }
+
+local cmd = tokens.commands
+
+local get_next = token.get_next
+local get_command = token.get_command
+local get_mode = token.get_mode
+local get_index = token.get_index
+local get_csname = token.get_csname
+local get_macro = token.get_macro
+
+local put_next = token.put_next
+
+local scan_token = token.scan_token
+
+local getdimen = tex.getdimen
+local getglue = tex.getglue
+local getcount = tex.getcount
+local gettoks = tex.gettoks
+local gettex = tex.get
+
+local context = context
+local dimenfactors = number.dimenfactors
+
+local result = { "return " }
+local word = { }
+local r = 1
+local w = 0
+
+local report = logs.reporter("system","expression")
+
+local function unexpected(c)
+ report("unexpected token %a",c)
+end
+
+local function expression()
+ local w = 0
+ local r = 1
+ while true do
+ local t = get_next()
+ local n = get_command(t)
+ local c = cmd[n]
+ -- todo, helper: returns number
+ if c == "letter" then
+ w = w + 1 ; word[w] = utfchar(get_mode(t))
+ else
+ if w > 0 then
+ local s = concat(word,"",1,w)
+ local d = dimenfactors[s]
+ if d then
+ r = r + 1 ; result[r] = "*"
+ r = r + 1 ; result[r] = 1/d
+ else
+ if xmath[s] then
+ r = r + 1 ; result[r] = "xmath."
+ elseif xcomplex[s] then
+ r = r + 1 ; result[r] = "xcomplex."
+ end
+ r = r + 1 ; result[r] = s
+ end
+ w = 0
+ end
+ if c == "other_char" then
+ r = r + 1 ; result[r] = utfchar(get_mode(t))
+ elseif c == "spacer" then
+ -- r = r + 1 ; result[r] = " "
+ elseif c == "relax" then
+ break
+ elseif c == "assign_int" then
+ r = r + 1 ; result[r] = getcount(get_index(t))
+ elseif c == "assign_dimen" then
+ r = r + 1 ; result[r] = getdimen(get_index(t))
+ elseif c == "assign_glue" then
+ r = r + 1 ; result[r] = getglue(get_index(t))
+ elseif c == "assign_toks" then
+ r = r + 1 ; result[r] = gettoks(get_index(t))
+ elseif c == "char_given" or c == "math_given" or c == "xmath_given" then
+ r = r + 1 ; result[r] = get_mode(t)
+ elseif c == "last_item" then
+ local n = get_csname(t)
+ if n then
+ local s = gettex(n)
+ if s then
+ r = r + 1 ; result[r] = s
+ else
+ unexpected(c)
+ end
+ else
+ unexpected(c)
+ end
+ elseif c == "call" then
+ local n = get_csname(t)
+ if n then
+ local s = get_macro(n)
+ if s then
+ r = r + 1 ; result[r] = s
+ else
+ unexpected(c)
+ end
+ else
+ unexpected(c)
+ end
+ elseif c == "the" or c == "convert" or c == "lua_expandable_call" then
+ put_next(t)
+ scan_token() -- expands
+ else
+ unexpected(c)
+ end
+ end
+ end
+ local code = concat(result,"",1,r)
+ local func = load(code)
+ if type(func) == "function" then
+ context(func())
+ else
+ report("invalid lua %a",code)
+ end
+end
+
+-- local letter_code <const> = cmd.letter
+-- local other_char_code <const> = cmd.other_char
+-- local spacer_code <const> = cmd.spacer
+-- local other_char_code <const> = cmd.other_char
+-- local relax_code <const> = cmd.relax
+-- local assign_int_code <const> = cmd.assign_int
+-- local assign_dimen_code <const> = cmd.assign_dimen
+-- local assign_glue_code <const> = cmd.assign_glue
+-- local assign_toks_code <const> = cmd.assign_toks
+-- local char_given_code <const> = cmd.char_given
+-- local math_given_code <const> = cmd.math_given
+-- local xmath_given_code <const> = cmd.xmath_given
+-- local last_item_code <const> = cmd.last_item
+-- local call_code <const> = cmd.call
+-- local the_code <const> = cmd.the
+-- local convert_code <const> = cmd.convert
+-- local lua_expandable_call_code <const> = cmd.lua_expandable_call
+--
+-- local function unexpected(c)
+-- report("unexpected token %a",c)
+-- end
+--
+-- local function expression()
+-- local w = 0
+-- local r = 1
+-- while true do
+-- local t = get_next()
+-- local n = get_command(t)
+-- if n == letter_code then
+-- w = w + 1 ; word[w] = utfchar(get_mode(t))
+-- else
+-- if w > 0 then
+-- -- we could use a metatable for all math, complex and factors
+-- local s = concat(word,"",1,w)
+-- local d = dimenfactors[s]
+-- if d then
+-- r = r + 1 ; result[r] = "*"
+-- r = r + 1 ; result[r] = 1/d
+-- else
+-- if xmath[s] then
+-- r = r + 1 ; result[r] = "xmath."
+-- elseif xcomplex[s] then
+-- r = r + 1 ; result[r] = "xcomplex."
+-- end
+-- r = r + 1 ; result[r] = s
+-- end
+-- w = 0
+-- end
+-- if n == other_char_code then
+-- r = r + 1 ; result[r] = utfchar(get_mode(t))
+-- elseif n == spacer_code then
+-- -- r = r + 1 ; result[r] = " "
+-- elseif n == relax_code then
+-- break
+-- elseif n == assign_int_code then
+-- r = r + 1 ; result[r] = getcount(get_index(t))
+-- elseif n == assign_dimen_code then
+-- r = r + 1 ; result[r] = getdimen(get_index(t))
+-- elseif n == assign_glue_code then
+-- r = r + 1 ; result[r] = getglue(get_index(t))
+-- elseif n == assign_toks_code then
+-- r = r + 1 ; result[r] = gettoks(get_index(t))
+-- elseif n == char_given_code or n == math_given_code or n == xmath_given_code then
+-- r = r + 1 ; result[r] = get_mode(t)
+-- elseif n == last_item_code then
+-- local n = get_csname(t)
+-- if n then
+-- local s = gettex(n)
+-- if s then
+-- r = r + 1 ; result[r] = s
+-- else
+-- unexpected(c)
+-- end
+-- else
+-- unexpected(c)
+-- end
+-- elseif n == call_code then
+-- local n = get_csname(t)
+-- if n then
+-- local s = get_macro(n)
+-- if s then
+-- r = r + 1 ; result[r] = s
+-- else
+-- unexpected(c)
+-- end
+-- else
+-- unexpected(c)
+-- end
+-- elseif n == the_code or n == convert_code or n == lua_expandable_call_code then
+-- put_next(t)
+-- scan_token() -- expands
+-- else
+-- unexpected(c)
+-- end
+-- end
+-- end
+-- local code = concat(result,"",1,r)
+-- local func = load(code)
+-- if type(func) == "function" then
+-- context(func())
+-- else
+-- report("invalid lua %a",code)
+-- end
+-- end
+
+implement {
+ public = true,
+ name = "expression",
+ actions = expression,
+}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/syst-lua.mkiv b/Master/texmf-dist/tex/context/base/mkiv/syst-lua.mkiv
index 3600dac3460..d275acd7dd1 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/syst-lua.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/syst-lua.mkiv
@@ -24,36 +24,32 @@
%D {\expanded} primitive were mentioned in talks.} trip. For now I don't really see
%D other useful applications.
-\ifdefined\immediateassignment
-
- \def\expandeddoif#1#2%
- {\immediateassignment\edef\m_syst_string_one{#1}%
- \immediateassignment\edef\m_syst_string_two{#2}%
- \ifx\m_syst_string_one\m_syst_string_two
- \expandafter\firstofoneargument
- \else
- \expandafter\gobbleoneargument
- \fi}
-
- \def\expandeddoifnot#1#2%
- {\immediateassignment\edef\m_syst_string_one{#1}%
- \immediateassignment\edef\m_syst_string_two{#2}%
- \ifx\m_syst_string_one\m_syst_string_two
- \expandafter\gobbleoneargument
- \else
- \expandafter\firstofoneargument
- \fi}
-
- \def\expandeddoifelse#1#2%
- {\immediateassignment\edef\m_syst_string_one{#1}%
- \immediateassignment\edef\m_syst_string_two{#2}%
- \ifx\m_syst_string_one\m_syst_string_two
- \expandafter\firstoftwoarguments
- \else
- \expandafter\secondoftwoarguments
- \fi}
-
-\fi
+\def\expandeddoifelse#1#2%
+ {\immediateassignment\edef\m_syst_string_one{#1}%
+ \immediateassignment\edef\m_syst_string_two{#2}%
+ \ifx\m_syst_string_one\m_syst_string_two
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\def\expandeddoif#1#2%
+ {\immediateassignment\edef\m_syst_string_one{#1}%
+ \immediateassignment\edef\m_syst_string_two{#2}%
+ \ifx\m_syst_string_one\m_syst_string_two
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\def\expandeddoifnot#1#2%
+ {\immediateassignment\edef\m_syst_string_one{#1}%
+ \immediateassignment\edef\m_syst_string_two{#2}%
+ \ifx\m_syst_string_one\m_syst_string_two
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
% \testfeatureonce{100000}{\doifelse{hello world}{here i am}{}} % 0.3
% \testfeatureonce{100000}{\expandabledoifelse{hello world}{here i am}{}} % 1.5
@@ -64,36 +60,64 @@
\def\expdoifcommonelse\expdoifelsecommon
\def\expdoifinsetelse \expdoifelseinset
-% we define these here, just in case ...
+%D We define these here, just in case. This permits \typefile {self} otherwise
+%D nested b|/|e sep problems.
-\def\luastringsep{===} % this permits \typefile{self} otherwise nested b/e sep problems
+\def\luastringsep{===}
\edef\!!bs{[\luastringsep[}
\edef\!!es{]\luastringsep]}
\unexpanded\def\writestatus#1#2{\clf_writestatus{#1}{#2}}
-% A handy helper:
-
-% \def\luaexpr#1{\ctxlua{context(tostring(#1))}} % more efficient:
-
-% We can omit the tex.ctxcatcodes here as nowadays we seldom
-% change the regime at the \TEX\ end:
+%D We can omit the tex.ctxcatcodes here as nowadays we seldom change the regime at
+%D the \TEX\ end:
+%def\luaexpr#1{\ctxlua{context (tostring(#1))}} % more efficient:
\def\luaexpr#1{\ctxlua{tex.print(tostring(#1))}} % no use is shortcutting has to be compiled
-% helpers:
-
-\def\ui_fo #1{#1}
-\def\ui_go #1{}
-\def\ui_ft#1#2{#1}
-\def\ui_st#1#2{#2}
-
-
-%D But as we only use write 16 we could as well do all in \LUA\
-%D and ignore the rest. Okay, we still can do writes here but only
-%D when not blocked.
+%D But as we only use write 16 we could as well do all in \LUA\ and ignore the rest.
+%D Okay, we still can do writes here but only when not blocked.
\let\syst_write_execute\clf_execute % always {...}
+%D There is a probably rather useless \type {\expression} command that can mix \LUA\ numeric
+%D expressions with \TEX\ commands (for as far that makes sense) that works like this:
+%D
+%D \starttyping
+%D \mathchardef\foooo 1234
+%D \def \mymacro {123.45}
+%D \scratchdimen 123pt
+%D \scratchskip 123pt
+%D \scratchtoks {34}
+%D
+%D \testfeatureonce{10000}{\edef\foo{\expression
+%D round(
+%D 12.3 * \scratchdimen
+%D - (12.3 * \scratchskip) / 2
+%D + 2 ^ 3
+%D * (
+%D - sqrt(12)
+%D - 10pt
+%D - \foooo
+%D + \luatexversion
+%D - \mymacro
+%D + \scratchtoks
+%D + \the\scratchcounter
+%D + \number\scratchcounter
+%D )
+%D )
+%D \relax}}
+%D
+%D \expression string.format("\letterpercent f",\elapsedtime/50000) \relax
+%D \stoptyping
+%D
+%D The final \type {\relax} is mandate because we also accept spaces. Of course we
+%D could have avoided it by using outer parenthesis but this is cleaner anyway.
+%D
+%D The \MKIV\ version is a bit more limited than the \LMTX\ version because it only
+%D supports the standard math functions.
+
+% maybe: \let\texexpr\expression
+
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/syst-lua.mkxl b/Master/texmf-dist/tex/context/base/mkiv/syst-lua.mkxl
new file mode 100644
index 00000000000..cf20c3341f8
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/syst-lua.mkxl
@@ -0,0 +1,100 @@
+%D \module
+%D [ file=syst-lua,
+%D version=2008.01.25,
+%D title=\CONTEXT\ System Macros,
+%D subtitle=Helper macros based on \LUA,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\registerctxluafile{syst-lua}{}
+
+\unprotect
+
+\def\expdoifelse#1#2{\clf_doifelsesame{#1}{#2}}
+\def\expdoif #1#2{\clf_doifsame {#1}{#2}}
+\def\expdoifnot #1#2{\clf_doifnotsame {#1}{#2}}
+
+%D Here is variant using a brainwave of the 12\high{+} hour \quotation {Long Road
+%D Out of Eden}\footnote {Eden being Backo\TeX\ 2018, where the virtues of the \type
+%D {\expanded} primitive were mentioned in talks.} trip. For now I don't really see
+%D other useful applications.
+
+\def\expandeddoifelse#1#2{\iftok{#1}{#2}\expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments\fi}
+\def\expandeddoif #1#2{\iftok{#1}{#2}\expandafter\firstofoneargument \else\expandafter\gobbleoneargument \fi}
+\def\expandeddoifnot #1#2{\iftok{#1}{#2}\expandafter\gobbleoneargument \else\expandafter\firstofoneargument \fi}
+
+% \testfeatureonce{100000}{\doifelse{hello world}{here i am}{}} % 0.3
+% \testfeatureonce{100000}{\expandabledoifelse{hello world}{here i am}{}} % 1.5
+
+\def\expdoifelsecommon#1#2{\clf_doifelsecommon{#1}{#2}}
+\def\expdoifelseinset #1#2{\clf_doifelseinset {#1}{#2}}
+
+\def\expdoifcommonelse\expdoifelsecommon
+\def\expdoifinsetelse \expdoifelseinset
+
+%D We define these here, just in case. This permits \typefile {self} otherwise
+%D nested b|/|e sep problems.
+
+\def\luastringsep{===}
+
+\edef\!!bs{[\luastringsep[}
+\edef\!!es{]\luastringsep]}
+
+\unexpanded\def\writestatus#1#2{\clf_writestatus{#1}{#2}}
+
+%D We can omit the tex.ctxcatcodes here as nowadays we seldom change the regime at
+%D the \TEX\ end:
+
+%def\luaexpr#1{\ctxlua{context (tostring(#1))}} % more efficient:
+\def\luaexpr#1{\ctxlua{tex.print(tostring(#1))}} % no use is shortcutting has to be compiled
+
+%D But as we only use write 16 we could as well do all in \LUA\ and ignore the rest.
+%D Okay, we still can do writes here but only when not blocked.
+
+\let\syst_write_execute\clf_execute % always {...}
+
+%D There is a probably rather useless \type {\expression} command that can mix \LUA\ numeric
+%D expressions with \TEX\ commands (for as far that makes sense) that works like this:
+%D
+%D \starttyping
+%D \mathchardef\foooo 1234
+%D \def \mymacro {123.45}
+%D \scratchdimen 123pt
+%D \scratchskip 123pt
+%D \scratchtoks {34}
+%D
+%D \testfeatureonce{10000}{\edef\foo{\expression
+%D round(
+%D 12.3 * \scratchdimen
+%D - (12.3 * \scratchskip) / 2
+%D + 2 ^ 3
+%D * (
+%D - sqrt(12)
+%D - 10pt
+%D - \foooo
+%D + \luatexversion
+%D - \mymacro
+%D + \scratchtoks
+%D + \the\scratchcounter
+%D + \number\scratchcounter
+%D )
+%D )
+%D \relax}}
+%D
+%D \expression string.format("\letterpercent f",\elapsedtime/50000) \relax
+%D \stoptyping
+%D
+%D The final \type {\relax} is mandate because we also accept spaces. Of course we
+%D could have avoided it by using outer parenthesis but this is cleaner anyway.
+%D
+%D The \LMTX\ version supports te \type {xmath} and \type {xcomplex} functions and
+%D therefore one can have expressions that don't work in \MKIV.
+
+% maybe: \let\texexpr\expression
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/syst-mes.mkiv b/Master/texmf-dist/tex/context/base/mkiv/syst-mes.mkiv
index 3b16d7f974d..4ed2697f15a 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/syst-mes.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/syst-mes.mkiv
@@ -11,8 +11,8 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\def\writestring {\immediate\write\statuswrite}
-\def\writeline {\writestring{}}
-\let\message \normalmessage
+\normalprotected\def\writestring {\immediate\write\statuswrite}
+\normalprotected\def\writeline {\writestring{}}
+ \let\message \normalmessage
\endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/tabl-frm.mkiv b/Master/texmf-dist/tex/context/base/mkiv/tabl-frm.mkiv
index c0f4b7cd16c..14f3506b9e3 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/tabl-frm.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/tabl-frm.mkiv
@@ -134,54 +134,6 @@
{\framedparameter\c!after
\endgroup}
-% \unexpanded\def\startframedrow
-% {\advance\c_tabl_framed_r\plusone
-% \c_tabl_framed_c\zerocount
-% \d_tabl_framed_h\zeropoint
-% \bgroup
-% \edef\currentframed{\number\c_tabl_framed_r}%
-% \edef\currentframed
-% {\??framedtablerow\currentframedtable
-% \ifcsname\??framedtablerow\currentframedtable:\currentframed\endcsname
-% :\currentframed
-% \else\ifcsname\??framedtablerow\currentframedtable:\v!each\endcsname
-% :\v!each
-% \fi\fi}%
-% \dosingleempty\pack_framed_start_framed_nop_indeed}
-%
-% \unexpanded\def\stopframedrow
-% {\dofastloopcs\c_tabl_framed_c\tabl_framed_flush_row
-% \stopframed
-% \nointerlineskip
-% \vskip\zeropoint\relax
-% \framedparameter\c!inbetween}
-%
-% \unexpanded\def\tabl_framed_flush_row
-% {\vpack to \d_tabl_framed_h{\flushbox\??framedtable{\number\fastloopindex}\vfill}%
-% \ifdim\d_tabl_framed_d=\zeropoint\else\kern\d_tabl_framed_d\fi}
-%
-% \unexpanded\def\startframedcell
-% {\advance\c_tabl_framed_c\plusone
-% \setbox\b_tabl_framed\hpack\bgroup
-% %\bgroup
-% \edef\currentframed{\number\c_tabl_framed_c}%
-% \edef\currentframed
-% {\??framedtablecolumn\currentframedtable
-% \ifcsname\??framedtablecolumn\currentframedtable:\currentframed\endcsname
-% :\currentframed
-% \else\ifcsname\??framedtablecolumn\currentframedtable:\v!each\endcsname
-% :\v!each
-% \fi\fi}%
-% \dosingleempty\pack_framed_start_framed_nop_indeed}
-%
-% \unexpanded\def\stopframedcell
-% {\stopframed
-% %\egroup
-% \ifdim\ht\b_tabl_framed>\d_tabl_framed_h
-% \d_tabl_framed_h\ht\b_tabl_framed
-% \fi
-% \savebox\??framedtable{\number\c_tabl_framed_c}{\box\b_tabl_framed}}
-
% a two pass variant that deals with the height .. so no catcode changes here
\unexpanded\def\startframedrow
@@ -208,7 +160,7 @@
\unexpanded\def\tabl_framed_flush_row
{\vpack to \d_tabl_framed_h{\flushbox\??framedtable{\number\fastloopindex}\vfill}%
- \ifdim\d_tabl_framed_d=\zeropoint\else\kern\d_tabl_framed_d\fi}
+ \ifzeropt\d_tabl_framed_d\else\kern\d_tabl_framed_d\fi}
\newcount\c_tabl_framed_pass
@@ -253,7 +205,7 @@
\unexpanded\def\tabl_framed_flush_row_two
{\vpack to \d_tabl_framed_h{\flushbox\??framedtable{\number\fastloopindex}\vfill}%
- \ifdim\d_tabl_framed_d=\zeropoint\else\kern\d_tabl_framed_d\fi}
+ \ifzeropt\d_tabl_framed_d\else\kern\d_tabl_framed_d\fi}
\unexpanded\def\startframedcell
diff --git a/Master/texmf-dist/tex/context/base/mkiv/tabl-ltb.mkiv b/Master/texmf-dist/tex/context/base/mkiv/tabl-ltb.mkiv
index 20ae8bf5a2b..de90d658528 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/tabl-ltb.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/tabl-ltb.mkiv
@@ -125,7 +125,8 @@
\c!width=5\emwidth,
\c!height=\v!fit, % \v!line = faster
\c!background=,
- \c!backgroundcolor=]
+ \c!backgroundcolor=,
+ \c!rulethickness=\linewidth]
\def\linetableparameter#1%
{\begincsname\??linetable#1\endcsname}
@@ -290,30 +291,70 @@
\box\scratchbox
\fi}
+% \startuseMPgraphic{one}
+% path p, q ;
+% numeric r ;
+% r := RuleThickness ;
+% p := unitsquare xysized(RuleWidth,RuleHeight+RuleDepth) ;
+% q := p topenlarged -r bottomenlarged -r ;
+% draw q ;
+% setbounds currentpicture to p;
+% \stopuseMPgraphic
+%
+% \setuplinetable[r][odd] [type=mp,mp=one,backgroundcolor=gray,rulethickness=1pt]
+% \setuplinetable[r][even][type=mp,mp=one,backgroundcolor=green,rulethickness=1pt]
+%
+% \startlinetable
+% \dorecurse{10}{\NC aaa \NC bb \NC c \NC ddddd \NC eeee \NC ff \NC \NR}
+% \stoplinetable
+
\def\tabl_lines_wrap_up_auto
{\edef\p_height{\linetablerparameter{x\c!height}}%
\edef\p_depth {\linetablerparameter{x\c!depth }}%
- \hbox
+ \hpack
{\blackrule
[ \c!color=\linetablecparameter\c!backgroundcolor,
+ \c!type=\linetablecparameter\c!type,
+ \c!mp=\linetablecparameter\c!mp,
+ \c!rulethickness=\linetablecparameter\c!rulethickness,
\c!height=\ifx\p_height\empty\ht\scratchbox\else\p_height\fi,
\c!depth=\ifx\p_depth \empty\dp\scratchbox\else\p_depth \fi,
\c!width=\wd\scratchbox]%
\hskip-\wd\scratchbox\box\scratchbox}}
+\def\tabl_lines_wrap_up_auto_r
+ {\hpack
+ {\blackrule
+ [ \c!color=\linetablerparameter\c!backgroundcolor,
+ \c!type=\linetablerparameter\c!type,
+ \c!mp=\linetablerparameter\c!mp,
+ \c!rulethickness=\linetablerparameter\c!rulethickness,
+ \c!height=\ht\scratchbox,
+ \c!depth=\dp\scratchbox,
+ \c!width=\wd\scratchbox]%
+ \hskip-\wd\scratchbox\box\scratchbox}}
+
\def\tabl_lines_wrap_up_line
{\backgroundline[\linetablecparameter\c!backgroundcolor]{\box\scratchbox}}
\def\tabl_lines_save_part
{\global\setbox\tablebox\c_tabl_lines_part
- \ifnum\c_tabl_lines_part=\zerocount
+ \ifcase\c_tabl_lines_part\relax
\box\scratchbox % just storing
\else
\vbox
{\ifvoid\tablebox\c_tabl_lines_part\else\unvbox\tablebox\c_tabl_lines_part\fi
- \doif{\linetablerparameter\c!background}\v!color
- {\backgroundline[\linetablerparameter\c!backgroundcolor]}%
- {\box\scratchbox}% is also arg to \backgroundline
+ \edef\p_background{\linetablerparameter\c!background}%
+ \ifx\p_background\v!color
+ \backgroundline[\linetablerparameter\c!backgroundcolor]{\box\scratchbox}%
+ \else
+ \edef\p_type{\linetablerparameter\c!type}%
+ \ifx\p_type\empty
+ \box\scratchbox
+ \else
+ \tabl_lines_wrap_up_auto_r
+ \fi
+ \fi
\endgraf
\linetablerparameter\c!after}%
\fi}
@@ -340,7 +381,7 @@
\nointerlineskip % fix topskip
\fi
\noindent\strut
- \hbox to \hsize{\box\tablebox\c_tabl_lines_part\hss}%
+ \hpack to \hsize{\box\tablebox\c_tabl_lines_part\hss}%
\endgraf
\ifnum\c_tabl_lines_part<\c_tabl_lines_n_of_parts\relax
\linetableparameter\c!inbetween
@@ -756,8 +797,6 @@
\showframe \showstruts
-\setupcolors[state=start]
-
\setuppagenumbering[alternative=doublesided]\page[left]
\startlinetable
diff --git a/Master/texmf-dist/tex/context/base/mkiv/tabl-ntb.mkiv b/Master/texmf-dist/tex/context/base/mkiv/tabl-ntb.mkiv
index ca3d78800ac..8ff02330a9a 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/tabl-ntb.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/tabl-ntb.mkiv
@@ -11,13 +11,12 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-%D This module has a more modern variant in xtables but as we follow a bit
-%D different approach with settings there, this mechanism will stay. In fact
-%D each of them has its advantages. This module could be sped up a bit and made
-%D more efficient by delegating some housekeeping to \LUA\ but it's not worth
-%D the effort. The code could me made more readable but again, there is no
-%D real purpose in it. If needed I can squeeze out a few more percentages
-%D runtime.
+%D This module has a more modern variant in xtables but as we follow a bit different
+%D approach with settings there, this mechanism will stay. In fact each of them has
+%D its advantages. This module could be sped up a bit and made more efficient by
+%D delegating some housekeeping to \LUA\ but it's not worth the effort. The code
+%D could me made more readable but again, there is no real purpose in it. If needed
+%D I can squeeze out a few more percentages runtime.
% columndistance 'optimized' ... needs checking
%
@@ -27,8 +26,8 @@
% sometimes this helps (with nc going wild): \setupTABLE[maxwidth=100cm]
%
-% bug: width 3cm is not honored and column becomes too wide
-% as given width is added to distributed width
+% bug: width 3cm is not honored and column becomes too wide as given width is added
+% to distributed width
%
% \bTABLE
% \bTR
@@ -61,16 +60,14 @@
% \stopcelltable
% \stoptext
-%D As always, this is the n\high{th} version. Much time went in
-%D trying to speed up the many cell calculations, some
-%D optimizations were rejected in order not to complicate this
-%D module too much (and in order to prevail extensibility). In the
+%D As always, this is the n\high{th} version. Much time went in trying to speed up
+%D the many cell calculations, some optimizations were rejected in order not to
+%D complicate this module too much (and in order to prevail extensibility). In the
%D meantime we've sacrified some speed for readability.
\unprotect
-%D The next alternative also takes care of preceding and following
-%D white space.
+%D The next alternative also takes care of preceding and following white space.
%D
%D \startbuffer
%D \bTABLE[left={(},right={)},top=\startnarrower,bottom=\stopnarrower]
@@ -203,25 +200,35 @@
\newbox\b_tabl_ntb_final
-%D We have already prepared the previous macros for nesting,
-%D so we only have to pop in the right ones:
+%D For tagging and export:
+
+\newconstant \c_tabl_ntb_head
+\newconstant \c_tabl_ntb_body
+\newconstant \c_tabl_ntb_foot
+\newconditional \c_tabl_ntb_okay
+
+%D We have already prepared the previous macros for nesting, so we only have to pop
+%D in the right ones:
\newcount\c_tabl_level
+\installglobalmacrostack\m_tabl_ntb_saved_row
+\installglobalmacrostack\m_tabl_ntb_saved_col
+
\unexpanded\def\tabl_ntb_table_push
{\ifnum\m_tabl_tbl_level>\plusone
\tabl_ntb_parameters_reset
% we need a proper count push/pop
- \xdef\m_tabl_ntb_saved_row{\the\c_tabl_ntb_row}\globalpushmacro\m_tabl_ntb_saved_row
- \xdef\m_tabl_ntb_saved_col{\the\c_tabl_ntb_col}\globalpushmacro\m_tabl_ntb_saved_col
+ \xdef\m_tabl_ntb_saved_row{\the\c_tabl_ntb_row}\push_macro_m_tabl_ntb_saved_row
+ \xdef\m_tabl_ntb_saved_col{\the\c_tabl_ntb_col}\push_macro_m_tabl_ntb_saved_col
\else
\global\intabletrue
\fi}
\unexpanded\def\tabl_ntb_table_pop
{\ifnum\m_tabl_tbl_level>\plusone
- \globalpopmacro\m_tabl_ntb_saved_row\global\c_tabl_ntb_row\m_tabl_ntb_saved_row
- \globalpopmacro\m_tabl_ntb_saved_col\global\c_tabl_ntb_col\m_tabl_ntb_saved_col
+ \pop_macro_m_tabl_ntb_saved_row\global\c_tabl_ntb_row\m_tabl_ntb_saved_row
+ \pop_macro_m_tabl_ntb_saved_col\global\c_tabl_ntb_col\m_tabl_ntb_saved_col
\else
\global\intablefalse
\fi}
@@ -858,8 +865,8 @@
\def\tabl_ntb_tn[#1]#2\eTN
{\tabl_ntb_td[#1]\digits#2\relax\eTD}
-%D Vit Zyka needed the option to create a distance between columns, so I
-%D added support for individual column distances.
+%D Vit Zyka needed the option to create a distance between columns, so I added
+%D support for individual column distances.
%D
%D \startbuffer
%D % \setupTABLE[c][each][distance=2em]
@@ -881,9 +888,8 @@
%D
%D \typebuffer \startlinecorrection \getbuffer \stoplinecorrection
%D
-%D and he provided patches for the global left and right margin distances
-%D as well as the columndistance (although i changed the names -). Here
-%D is his testcase:
+%D and he provided patches for the global left and right margin distances as well as
+%D the columndistance (although i changed the names -). Here is his testcase:
%D
%D \startbuffer
%D \framed[offset=overlay]\bgroup
@@ -992,6 +998,8 @@
\let\nofTABLErows \!!zerocount
\let\nofTABLEcolumns \!!zerocount
+% there is no gain in a \doifelsenextoptionalcs variant
+
\unexpanded\def\dobTR{\dosingleempty\tabl_ntb_tr} % also used in tabl-nte
\unexpanded\def\dobTD{\dosingleempty\tabl_ntb_td} % also used in tabl-nte
\unexpanded\def\dobTH{\dosingleempty\tabl_ntb_th} % also used in tabl-nte
@@ -1006,19 +1014,30 @@
\unexpanded\def\eTABLE % beware, we need to get rid of spurious spaces when in hmode
{% tricky and dirty order -)
+ \setfalse\c_tabl_ntb_okay
+ % head
\doifelsesometoks\t_tabl_ntb_head % slow, better a flag
- {\the\t_tabl_ntb_head
+ {\c_tabl_ntb_head\numexpr\c_tabl_ntb_maximum_row+\plusone\relax
+ \the\t_tabl_ntb_head
\c_tabl_ntb_n_of_head_lines\c_tabl_ntb_maximum_row\relax
\doifelsesometoks\t_tabl_ntb_next
{\the\t_tabl_ntb_next
\c_tabl_ntb_n_of_next_lines\numexpr\c_tabl_ntb_maximum_row-\c_tabl_ntb_n_of_head_lines\relax}%
{\c_tabl_ntb_n_of_next_lines\zerocount}% was 1
\c_tabl_ntb_n_of_hdnx_lines\c_tabl_ntb_maximum_row}
- {\c_tabl_ntb_n_of_head_lines\zerocount % was 1
+ {\c_tabl_ntb_head\zerocount
+ \c_tabl_ntb_n_of_head_lines\zerocount % was 1
\c_tabl_ntb_n_of_next_lines\zerocount
\c_tabl_ntb_n_of_hdnx_lines\zerocount}%
+ % body
+ \c_tabl_ntb_body\numexpr\c_tabl_ntb_maximum_row+\plusone\relax
\the\t_tabl_ntb_body
- \the\t_tabl_ntb_foot
+ % foot
+ \doifelsesometoks\t_tabl_ntb_foot
+ {\c_tabl_ntb_foot\numexpr\c_tabl_ntb_maximum_row+\plusone\relax
+ \the\t_tabl_ntb_foot}%
+ {\c_tabl_ntb_foot\zerocount}%
+ % done
\removeunwantedspaces % only if hmode
% finish cells
\tabl_ntb_loop_one
@@ -1228,25 +1247,76 @@
\def\tabl_ntb_prelocate_okay
{\expandafter\let\expandafter\t_tabl_ntb_row\csname\??naturaltabletok\the\c_tabl_ntb_row\endcsname\t_tabl_ntb_row\emptytoks}
-% We use aligments to handle the empty (skipped) columns, so
-% that we don't have to (re|)|calculate these.
+%D We use aligments to handle the empty (skipped) columns, so that we don't have to
+%D (re|)|calculate these.
\let\m_tabl_ntb_saved_row\!!zerocount
\let\m_tabl_ntb_saved_col\!!zerocount
+\def\tabl_ntb_start_tagged
+ {\scratchcounter\numexpr\c_tabl_ntb_row+\plusone\relax
+ \ifnum\scratchcounter=\c_tabl_ntb_head
+ \ifconditional\c_tabl_ntb_okay
+ \dostoptagged
+ \else
+ \settrue\c_tabl_ntb_okay
+ \fi
+ \dostarttagged\t!tablehead\empty
+ \else\ifnum\scratchcounter=\c_tabl_ntb_body
+ \ifconditional\c_tabl_ntb_okay
+ \dostoptagged
+ \else
+ \settrue\c_tabl_ntb_okay
+ \fi
+ \dostarttagged\t!tablebody\empty
+ \else\ifnum\scratchcounter=\c_tabl_ntb_foot
+ \ifconditional\c_tabl_ntb_okay
+ \dostoptagged
+ \else
+ \settrue\c_tabl_ntb_okay
+ \fi
+ \dostarttagged\t!tablefoot\empty
+ \fi\fi\fi
+ \dostarttagged\t!tablerow\empty}
+
+\def\tabl_ntb_stop_tagged
+ {\dostoptagged
+ \ifconditional\c_tabl_ntb_okay
+ \scratchcounter\numexpr\c_tabl_ntb_row+\plustwo\relax
+ \ifnum\scratchcounter=\c_tabl_ntb_body
+ \dostoptagged
+ \setfalse\c_tabl_ntb_okay
+ \else\ifnum\scratchcounter=\c_tabl_ntb_foot
+ \dostoptagged
+ \setfalse\c_tabl_ntb_okay
+ \else\ifnum\scratchcounter>\c_tabl_ntb_maximum_row
+ \dostoptagged
+ \setfalse\c_tabl_ntb_okay
+ \fi\fi\fi
+ \fi}
+
\unexpanded\def\tabl_ntb_row_align_start
{\global\advance\c_tabl_ntb_row\plusone
\global\c_tabl_ntb_col\plusone
\global\c_tabl_ntb_spn\zerocount
\tabl_ntb_row_align_start_inject
- \dostarttagged\t!tablerow\empty
- \hbox\bgroup
- \kern\dimexpr\d_tabl_ntb_leftmargindistance\relax}
+ \ifconditional\c_strc_tags_enabled
+ \tabl_ntb_start_tagged
+ \fi
+ % we are in sync but just to be sure:
+ \synchronizedisplaydirection
+ \synchronizeinlinedirection
+ \hbox
+ \usedirectionparameterreverse\naturaltablelocalparameter
+ \bgroup
+ \kern\dimexpr\d_tabl_ntb_leftmargindistance\relax}
\unexpanded\def\tabl_ntb_row_align_stop
{\kern\dimexpr\d_tabl_ntb_rightmargindistance-\d_tabl_ntb_columndistance\relax
\egroup
- \dostoptagged
+ \ifconditional\c_strc_tags_enabled
+ \tabl_ntb_stop_tagged
+ \fi
\tabl_ntb_row_align_stop_inject}
\unexpanded\def\tabl_ntb_before_page
@@ -1723,12 +1793,14 @@
\tabl_ntb_set_aut\recurselevel{\the\scratchdimen}%
\fi
\else
- \ifdim\scratchdimen=\zeropoint % auto set width
+ \ifzeropt\scratchdimen % auto set width
\tabl_ntb_set_wid\recurselevel{\the\!!dimena}%
\fi
\fi}%
\ifconditional\c_tabl_ntb_trace_widths\tabl_ntb_show_widths E#1\fi}
+% todo: use scratchcounters, not !! ones
+
\def\tabl_ntb_check_heights_one_indeed
{\!!countb\tabl_ntb_get_row\c_tabl_ntb_current_row_three\c_tabl_ntb_current_col_three\relax
% check row span
@@ -1810,19 +1882,6 @@
{\writestatus\m!TABLE{\space\space\recurselevel: \the\dimexpr\tabl_ntb_get_wid\recurselevel}}%
\endgroup}
-% \def\tabl_ntb_char_align
-% {\doifelse{\naturaltablelocalparameter\c!aligncharacter}\v!yes
-% \tabl_ntb_char_align_indeed\gobbletwoarguments}
-
-% \def\tabl_ntb_char_align_indeed#1#2#3% row column data
-% {\edef\alignmentclass{#2}%
-% \edef\alignmentcharacter{\naturaltablelocalparameter\c!alignmentcharacter}%
-% \ifcase\c_tabl_tbl_pass\or
-% \setfirstpasscharacteralign\checkalignment{#3}% {\strut#2\unskip}%
-% \fi % force hsize, so always a second
-% \setsecondpasscharacteralign \checkalignment{#3}% {\strut#2\unskip}%
-% \ignorespaces}
-
\def\tabl_ntb_char_align % called often
{\edef\p_characteralign{\naturaltablelocalparameter\c!aligncharacter}%
\ifx\p_characteralign\v!yes
@@ -1852,25 +1911,12 @@
\unexpanded\def\tabl_ntb_cell_process_x#1#2[#3]#4%
{}
-% problem: when span doesn't break we can have a span that is the sum of
-% cells but still to small .. chicken egg problem ... for that we should
-% also have a smallest width run
+% problem: when span doesn't break we can have a span that is the sum of cells but
+% still to small .. chicken egg problem ... for that we should also have a smallest
+% width run
%
% nilling the background makes a run upto 25% faster
-% \def\tabl_ntb_cell_process_a_check_span_one
-% {\ifautosqueezeTBLspan
-% \edef\p_width{\naturaltablelocalparameter\c!width}%
-% \csname\??naturaltablesqueeze\ifcsname\??naturaltablesqueeze\p_width\endcsname\p_width\fi\endcsname
-% \else
-% \donetrue
-% \fi
-% \ifdone % brr, 0
-% \ifnum\scratchcounter>\plusone
-% \tabl_ntb_set_spn\c_tabl_ntb_col
-% \fi
-% \fi}
-
\def\tabl_ntb_cell_process_a_check_span_one
{\ifautosqueezeTBLspan
\edef\p_width{\naturaltablelocalparameter\c!width}%
@@ -1884,47 +1930,6 @@
\fi
\fi}
-% \def\tabl_ntb_cell_process_a_check_span_two_yes
-% {\iftightTBLcolspan
-% \donefalse
-% \else
-% \ifnum\scratchcounter>\plusone
-% \begingroup
-% \edef\p_width{\naturaltablelocalparameter\c!width}%
-% \csname\??naturaltablesqueeze\ifcsname\??naturaltablesqueeze\p_width\endcsname\p_width\fi\endcsname
-% \ifdone
-% \endgroup
-% \edef\p_option{\naturaltablelocalparameter\c!option}%
-% \ifx\p_option\v!tight\donefalse\else\donetrue\fi
-% \else
-% % a dimension
-% \endgroup
-% \donefalse
-% \fi
-% \else
-% \edef\p_option{\naturaltablelocalparameter\c!option}%
-% \ifx\p_option\v!tight\donefalse\else\donetrue\fi
-% \fi
-% \fi
-% \ifdone
-% \ifdim\tabl_ntb_get_wid\c_tabl_ntb_col<\wd\scratchbox
-% \tabl_ntb_set_wid\c_tabl_ntb_col{\the\wd\scratchbox}%
-% \fi
-% \fi}
-
-% \def\tabl_ntb_cell_process_a_check_span_two_nop
-% {\ifnum\scratchcounter>\plusone
-% \edef\p_width{\naturaltablelocalparameter\c!width}%
-% \csname\??naturaltablesqueeze\ifcsname\??naturaltablesqueeze\p_width\endcsname\p_width\fi\endcsname
-% \else
-% \donetrue
-% \fi
-% \ifdone
-% \ifdim\tabl_ntb_get_wid\c_tabl_ntb_col<\wd\scratchbox
-% \tabl_ntb_set_wid\c_tabl_ntb_col{\the\wd\scratchbox}%
-% \fi
-% \fi}
-
\let\tabl_ntb_cell_process_a_check_span_two_yes\relax
\def\tabl_ntb_cell_process_a_check_span_two_nop
@@ -1948,9 +1953,9 @@
\anch_backgrounds_text_level_start
\inheritednaturaltablelocalframed{\tabl_ntb_cell_start\tabl_ntb_char_align{#1}{#2}#4\tabl_ntb_cell_stop\tabl_ntb_cell_finalize}%
\anch_backgrounds_text_level_stop
-\ifcase\c_anch_backgrounds_text_count\else
- \tabl_ntb_let_bck{#1}{#2}\c_anch_backgrounds_text_state
-\fi
+ \ifcase\c_anch_backgrounds_text_count\else
+ \tabl_ntb_let_bck{#1}{#2}\c_anch_backgrounds_text_state
+ \fi
}%
\scratchdimen\tabl_ntb_get_wid\c_tabl_ntb_col\relax
\ifdim\wd\scratchbox>\scratchdimen
@@ -1972,7 +1977,7 @@
\ifdim\wd\scratchbox<.75\hsize % fuzzy guess
\ifdim\ht\scratchbox>2\openlineheight % honor width since this
\scratchdimen\tabl_ntb_get_aut\c_tabl_ntb_col\relax % can be a figure or so
- \ifdim\scratchdimen=\zeropoint
+ \ifzeropt\scratchdimen
% side effect: when width is set to 0pt,
% we can force a span that fits the sum of spans widths
\tabl_ntb_set_aut\c_tabl_ntb_col{\the\scratchdimen}%
@@ -2050,16 +2055,16 @@
[\naturaltablelocalparameter\c!color] % as well as permits local colors to take precedence
{\letnaturaltablelocalparameter\c!color\empty
\setnaturaltablelocalparameter\c!width{\d_tabl_ntb_width}%
- \ifdim\d_tabl_ntb_height=\zeropoint\relax % case: nc=maxcolumns
+ \ifzeropt\d_tabl_ntb_height % case: nc=maxcolumns
\else
\setnaturaltablelocalparameter\c!height{\d_tabl_ntb_height}%
\fi
-\ifcase\c_anch_backgrounds_text_count\else
- \edef\p_region{\naturaltablelocalparameter\c!region}%
- \ifx\p_region\empty\ifnum\tabl_ntb_get_bck{#1}{#2}>\zerocount
- \letnaturaltablelocalparameter\c!region\v!yes
- \fi\fi
-\fi
+ \ifcase\c_anch_backgrounds_text_count\else
+ \edef\p_region{\naturaltablelocalparameter\c!region}%
+ \ifx\p_region\empty\ifnum\tabl_ntb_get_bck{#1}{#2}>\zerocount
+ \letnaturaltablelocalparameter\c!region\v!yes
+ \fi\fi
+ \fi
\inheritednaturaltablelocalframed{\tabl_ntb_cell_start\tabl_ntb_char_align{#1}{#2}#4\tabl_ntb_cell_stop}}%
\hskip\tabl_ntb_get_dis{#2}}
@@ -2193,12 +2198,6 @@
\let\eTDs\relax
\let\eTRs\relax
-% \unexpanded\def\bTDs[#1]#2\eTDs
-% {\normalexpanded{\bTD[\ifcsname\??naturaltablesetup#1\endcsname\csname\??naturaltablesetup#1\endcsname\fi]}#2\eTD}
-%
-% \unexpanded\def\bTRs[#1]#2\eTRs
-% {\normalexpanded{\bTR[\ifcsname\??naturaltablesetup#1\endcsname\csname\??naturaltablesetup#1\endcsname\fi]}#2\eTR}
-
\unexpanded\def\bTDs[#1]#2\eTDs
{\normalexpanded{\bTD[\begincsname\??naturaltablesetup#1\endcsname]}#2\eTD}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/tabl-ntb.mkxl b/Master/texmf-dist/tex/context/base/mkiv/tabl-ntb.mkxl
new file mode 100644
index 00000000000..6b84411b2a9
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/tabl-ntb.mkxl
@@ -0,0 +1,2202 @@
+%D \module
+%D [ file=tabl-ntb,
+%D version=2000.04.18,
+%D title=\CONTEXT\ Table Macros,
+%D subtitle=Natural Tables,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This module has a more modern variant in xtables but as we follow a bit different
+%D approach with settings there, this mechanism will stay. In fact each of them has
+%D its advantages. This module could be sped up a bit and made more efficient by
+%D delegating some housekeeping to \LUA\ but it's not worth the effort. The code
+%D could me made more readable but again, there is no real purpose in it. If needed
+%D I can squeeze out a few more percentages runtime.
+
+% columndistance 'optimized' ... needs checking
+%
+% we don't need the alignment mechanism .. we can just pack the row in a box
+
+\writestatus{loading}{ConTeXt Table Macros / Natural Tables}
+
+% sometimes this helps (with nc going wild): \setupTABLE[maxwidth=100cm]
+%
+% bug: width 3cm is not honored and column becomes too wide as given width is added
+% to distributed width
+%
+% \bTABLE
+% \bTR
+% \bTD test \eTD
+% \bTD \framed[height=3cm]{test} \eTD
+% \bTD[width=3cm] \dorecurse{30}{a } \eTD
+% \bTD \input ward \eTD
+% \eTR
+% \bTR
+% \bTD test \eTD
+% \bTD \framed[height=3cm]{test} \eTD
+% \bTD \dorecurse{30}{a } \eTD
+% \bTD \input ward \eTD
+% \eTR
+% \eTABLE
+
+% \unexpanded\def\startrow {\bTR}
+% \unexpanded\def\stoprow {\eTR}
+% \unexpanded\def\startcell#1\stopcell{\bTD#1\eTD}
+% \let\stopcell \relax
+% \let\startcelltable \bTABLE
+% \let\stopcelltable \eTABLE
+
+% \starttext
+% \startcelltable
+% \startrow \startcell a \stopcell \stoprow
+% \startrow \startcell a \stopcell \stoprow
+% \startrow \startcell a \stopcell \stoprow
+% \startrow \startcell a \stopcell \stoprow
+% \stopcelltable
+% \stoptext
+
+%D As always, this is the n\high{th} version. Much time went in trying to speed up
+%D the many cell calculations, some optimizations were rejected in order not to
+%D complicate this module too much (and in order to prevail extensibility). In the
+%D meantime we've sacrified some speed for readability.
+
+\unprotect
+
+%D The next alternative also takes care of preceding and following white space.
+%D
+%D \startbuffer
+%D \bTABLE[left={(},right={)},top=\startnarrower,bottom=\stopnarrower]
+%D \bTR \bTD something \eTD \eTR
+%D \eTABLE
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+\ifdefined\dotagTABLEcell \else \let\dotagTABLEcell \relax \fi % todo: namespace
+\ifdefined\dotagTABLEsignal \else \let\dotagTABLEsignal\relax \fi % todo: namespace
+
+\let\tabl_ntb_next_level\relax
+
+\newtoks\t_tabl_ntb_cell_start
+\newtoks\t_tabl_ntb_cell_stop
+
+\appendtoks
+ \naturaltablelocalparameter\c!left
+ \delayedbegstrut
+\to \t_tabl_ntb_cell_start
+
+\appendtoks
+ \delayedendstrut
+ \naturaltablelocalparameter\c!right
+\to \t_tabl_ntb_cell_stop
+
+\appendtoks
+ \flushpostponednodedata
+ % maybe: \the\neverypar
+\to \t_tabl_ntb_cell_start
+
+\unexpanded\def\tabl_ntb_cell_start
+ {% \inhibitblank
+ \dotagTABLEcell
+ %\tabl_ntb_next_level
+ \font_styles_math_reset
+ \usenaturaltablelocalstyleandcolor\c!style\c!color
+ \everypar\t_tabl_ntb_cell_start
+ \font_styles_math_start}
+
+\unexpanded\def\tabl_ntb_cell_stop
+ {\font_styles_math_stop
+ \ifhmode
+ \the\t_tabl_ntb_cell_stop
+ \par % added 13/4/2006
+ \orelse\ifdim\prevdepth<\zeropoint % =-1000pt ?
+ % not sure yet:\naturaltablelocalparameter\c!right
+ \vskip-\strutdp
+ \else
+ \removebottomthings
+ \fi}
+
+% maybe:
+%
+% \unexpanded\def\tabl_ntb_cell_stop
+% {\ifhmode
+% \the\t_tabl_ntb_cell_stop
+% \par % added 13/4/2006
+% \else
+% % not sure yet:\naturaltablelocalparameter\c!right
+% \par
+% \ifhmode
+% % \removeunwantedspaces
+% \else\ifdim\prevdepth<\zeropoint % =-1000pt ?
+% \vskip-\strutdp
+% \else
+% \removebottomthings
+% \fi\fi
+% \fi}
+
+\newcount\c_tabl_ntb_row
+\newcount\c_tabl_ntb_col
+\newcount\c_tabl_ntb_spn
+
+\newcount\c_tabl_ntb_nx
+\newcount\c_tabl_ntb_ny
+
+\setnewconstant\c_tabl_ntb_cell \plusone
+\setnewconstant\c_tabl_ntb_none \plustwo
+
+\newcount\c_tabl_ntb_current_row
+\newcount\c_tabl_ntb_current_col
+\newcount\c_tabl_ntb_current_row_one
+\newcount\c_tabl_ntb_current_col_one
+\newcount\c_tabl_ntb_current_row_two
+\newcount\c_tabl_ntb_current_col_two
+\newcount\c_tabl_ntb_current_row_three
+\newcount\c_tabl_ntb_current_col_three
+\newcount\c_tabl_ntb_current_row_four
+\newcount\c_tabl_ntb_current_col_four
+
+\newcount\c_tabl_ntb_running_col
+\newcount\c_tabl_ntb_maximum_row
+\newcount\c_tabl_ntb_maximum_col
+\newcount\c_tabl_ntb_maximum_row_span
+\newcount\c_tabl_ntb_maximum_col_span
+
+\newcount\c_tabl_ntb_encountered_col
+\newcount\c_tabl_ntb_encountered_max
+
+\newtoks\t_tabl_ntb
+\newtoks\t_tabl_ntb_row
+
+\newconstant\c_tabl_tbl_pass
+
+\newtoks\t_tabl_ntb_head
+\newtoks\t_tabl_ntb_next
+\newtoks\t_tabl_ntb_body
+\newtoks\t_tabl_ntb_foot
+
+\newcount\c_tabl_ntb_n_of_head_lines
+\newcount\c_tabl_ntb_n_of_next_lines
+\newcount\c_tabl_ntb_n_of_hdnx_lines
+
+\newdimen\d_tabl_ntb_height
+\newdimen\d_tabl_ntb_width
+
+\newdimen\d_tabl_ntb_leftmargindistance
+\newdimen\d_tabl_ntb_rightmargindistance
+\newdimen\d_tabl_ntb_columndistance
+\newdimen\d_tabl_ntb_maxwidth
+
+\newtoks\everyTABLEpass % public
+
+\newcount\tablecellrows % public (needs checking)
+\newcount\tablecellcolumns % public (needs checking)
+
+\newbox\b_tabl_ntb_final
+
+%D For tagging and export:
+
+\newconstant \c_tabl_ntb_head
+\newconstant \c_tabl_ntb_body
+\newconstant \c_tabl_ntb_foot
+\newconditional \c_tabl_ntb_okay
+
+%D We have already prepared the previous macros for nesting, so we only have to pop
+%D in the right ones:
+
+\newcount\c_tabl_level
+
+\installglobalmacrostack\m_tabl_ntb_saved_row
+\installglobalmacrostack\m_tabl_ntb_saved_col
+
+\unexpanded\def\tabl_ntb_table_push
+ {\ifnum\m_tabl_tbl_level>\plusone
+ \tabl_ntb_parameters_reset
+ % we need a proper count push/pop
+ \xdef\m_tabl_ntb_saved_row{\the\c_tabl_ntb_row}\push_macro_m_tabl_ntb_saved_row
+ \xdef\m_tabl_ntb_saved_col{\the\c_tabl_ntb_col}\push_macro_m_tabl_ntb_saved_col
+ \else
+ \global\intabletrue
+ \fi}
+
+\unexpanded\def\tabl_ntb_table_pop
+ {\ifnum\m_tabl_tbl_level>\plusone
+ \pop_macro_m_tabl_ntb_saved_row\global\c_tabl_ntb_row\m_tabl_ntb_saved_row
+ \pop_macro_m_tabl_ntb_saved_col\global\c_tabl_ntb_col\m_tabl_ntb_saved_col
+ \else
+ \global\intablefalse
+ \fi}
+
+\unexpanded\def\tabl_ntb_next_level
+ {\advance\c_tabl_level\plusone
+ \edef\m_tabl_tbl_level{\the\c_tabl_level}}
+
+\unexpanded\def\tabl_ntb_prev_level
+ {\advance\c_tabl_level\minusone
+ \edef\m_tabl_tbl_level{\the\c_tabl_level}}
+
+\tabl_ntb_next_level % go to level 1
+
+\installcorenamespace{naturaltable} % was tbl
+\installcorenamespace{naturaltablelocal} % was tbltbl
+
+\installdirectcommandhandler \??naturaltable {naturaltable} % \??naturaltable
+\installsimpleframedcommandhandler \??naturaltablelocal {naturaltablelocal} \??naturaltablelocal
+
+\installcorenamespace{naturaltabletal}
+\installcorenamespace{naturaltablegal}
+\installcorenamespace{naturaltablenob}
+\installcorenamespace{naturaltabletag}
+\installcorenamespace{naturaltablecol}
+\installcorenamespace{naturaltablerow}
+\installcorenamespace{naturaltablewd}
+\installcorenamespace{naturaltableht}
+\installcorenamespace{naturaltabledp}
+\installcorenamespace{naturaltablewid}
+\installcorenamespace{naturaltablehei}
+\installcorenamespace{naturaltabledis}
+\installcorenamespace{naturaltableaut}
+\installcorenamespace{naturaltablebck}
+%installcorenamespace{naturaltablefwd} % forcedwidth
+\installcorenamespace{naturaltabletxt}
+\installcorenamespace{naturaltablespn}
+\installcorenamespace{naturaltableref}
+\installcorenamespace{naturaltableset}
+\installcorenamespace{naturaltablecell}
+\installcorenamespace{naturaltablesqueeze}
+\installcorenamespace{naturaltabletok}
+
+\letvalue{\??naturaltablesqueeze }\donefalse
+\letvalue{\??naturaltablesqueeze\v!fit }\donetrue
+\letvalue{\??naturaltablesqueeze\v!fixed}\donetrue
+\letvalue{\??naturaltablesqueeze\v!broad}\donetrue
+\letvalue{\??naturaltablesqueeze\v!local}\donetrue
+
+\def\tabl_ntb_let_gal{\expandafter\glet\csname\??naturaltablegal\m_tabl_tbl_level\endcsname}
+\def\tabl_ntb_get_gal{\csname\??naturaltablegal\m_tabl_tbl_level\endcsname}
+
+\def\tabl_ntb_let_tal#1{\expandafter\glet\csname\??naturaltabletal\m_tabl_tbl_level:\number#1\endcsname}
+\def\tabl_ntb_get_tal#1{\csname\??naturaltabletal\m_tabl_tbl_level:\number#1\endcsname}
+
+\def\tabl_ntb_set_nob#1{\expandafter\let\csname\??naturaltablenob\m_tabl_tbl_level:\number#1\endcsname\plusone}
+\def\tabl_ntb_get_nob#1{\ifcsname\??naturaltablenob\m_tabl_tbl_level:\number#1\endcsname\plusone\else\zerocount\fi}
+
+%def\tabl_ntb_set_tag#1#2{\expandafter\edef\csname\??naturaltabletag\m_tabl_tbl_level:\number#1:\number#2\endcsname}
+\def\tabl_ntb_set_col#1#2{\expandafter\edef\csname\??naturaltablecol\m_tabl_tbl_level:\number#1:\number#2\endcsname}
+\def\tabl_ntb_set_row#1#2{\expandafter\edef\csname\??naturaltablerow\m_tabl_tbl_level:\number#1:\number#2\endcsname}
+
+\def\tabl_ntb_let_tag#1#2{\expandafter\let\csname\??naturaltabletag\m_tabl_tbl_level:\number#1:\number#2\endcsname}
+\def\tabl_ntb_let_col#1#2{\expandafter\let\csname\??naturaltablecol\m_tabl_tbl_level:\number#1:\number#2\endcsname}
+\def\tabl_ntb_let_row#1#2{\expandafter\let\csname\??naturaltablerow\m_tabl_tbl_level:\number#1:\number#2\endcsname}
+
+%def\tabl_ntb_set_wd#1#2{\expandafter\xdef\csname\??naturaltablewd\m_tabl_tbl_level:\number#1:\number#2\endcsname} % global !
+\def\tabl_ntb_set_ht#1#2{\expandafter\xdef\csname\??naturaltableht\m_tabl_tbl_level:\number#1:\number#2\endcsname} % global !
+
+%def\tabl_ntb_let_wd#1#2{\expandafter\glet\csname\??naturaltablewd\m_tabl_tbl_level:\number#1:\number#2\endcsname} % global !
+\def\tabl_ntb_let_ht#1#2{\expandafter\glet\csname\??naturaltableht\m_tabl_tbl_level:\number#1:\number#2\endcsname} % global !
+
+\def\tabl_ntb_get_tag#1#2{\csname\??naturaltabletag\m_tabl_tbl_level:\number#1:\number#2\endcsname}
+\def\tabl_ntb_get_col#1#2{\csname\??naturaltablecol\m_tabl_tbl_level:\number#1:\number#2\endcsname}
+\def\tabl_ntb_get_row#1#2{\csname\??naturaltablerow\m_tabl_tbl_level:\number#1:\number#2\endcsname}
+
+%def\tabl_ntb_get_wd#1#2{\csname\??naturaltablewd\m_tabl_tbl_level:\number#1:\number#2\endcsname}
+\def\tabl_ntb_get_ht#1#2{\csname\??naturaltableht\m_tabl_tbl_level:\number#1:\number#2\endcsname}
+
+\def\tabl_ntb_set_wid#1{\expandafter\xdef\csname\??naturaltablewid\m_tabl_tbl_level:\number#1\endcsname} % {#2} global !
+\def\tabl_ntb_set_hei#1{\expandafter\xdef\csname\??naturaltablehei\m_tabl_tbl_level:\number#1\endcsname} % {#2} global !
+\def\tabl_ntb_set_dis#1{\expandafter\xdef\csname\??naturaltabledis\m_tabl_tbl_level:\number#1\endcsname} % {#2} global !
+\def\tabl_ntb_set_aut#1{\expandafter\xdef\csname\??naturaltableaut\m_tabl_tbl_level:\number#1\endcsname} % {#2} global !
+
+\def\tabl_ntb_let_wid#1{\expandafter\glet\csname\??naturaltablewid\m_tabl_tbl_level:\number#1\endcsname} % {#2} global !
+\def\tabl_ntb_let_hei#1{\expandafter\glet\csname\??naturaltablehei\m_tabl_tbl_level:\number#1\endcsname} % {#2} global !
+\def\tabl_ntb_let_dis#1{\expandafter\glet\csname\??naturaltabledis\m_tabl_tbl_level:\number#1\endcsname} % {#2} global !
+\def\tabl_ntb_let_aut#1{\expandafter\glet\csname\??naturaltableaut\m_tabl_tbl_level:\number#1\endcsname} % {#2} global !
+
+\def\tabl_ntb_get_wid#1{\ifcsname\??naturaltablewid\m_tabl_tbl_level:\number#1\endcsname\lastnamedcs\else\zeropoint\fi}
+\def\tabl_ntb_get_hei#1{\ifcsname\??naturaltablehei\m_tabl_tbl_level:\number#1\endcsname\lastnamedcs\else\zeropoint\fi}
+\def\tabl_ntb_get_dis#1{\ifcsname\??naturaltabledis\m_tabl_tbl_level:\number#1\endcsname\lastnamedcs\else\zeropoint\fi}
+\def\tabl_ntb_get_aut#1{\csname \??naturaltableaut\m_tabl_tbl_level:\number#1\endcsname}
+
+\def\tabl_ntb_let_bck#1#2{\global\expandafter\chardef\csname\??naturaltablebck\m_tabl_tbl_level:\number#1:\number#2\endcsname}
+
+\def\tabl_ntb_get_bck#1#2{\csname\??naturaltablebck\m_tabl_tbl_level:\number#1:\number#2\endcsname}
+
+\def\tabl_ntb_tag_pattern#1#2{\??naturaltabletag\m_tabl_tbl_level:\number#1:\number#2}
+\def\tabl_ntb_row_pattern#1#2{\??naturaltablerow\m_tabl_tbl_level:\number#1:\number#2}
+\def\tabl_ntb_col_pattern#1#2{\??naturaltablecol\m_tabl_tbl_level:\number#1:\number#2}
+
+\def\tabl_ntb_tag_doif #1#2{\ifcsname\??naturaltabletag\m_tabl_tbl_level:\number#1:\number#2\endcsname\expandafter\firstofoneargument \else\expandafter\gobbleoneargument \fi}
+\def\tabl_ntb_tag_doifnot #1#2{\ifcsname\??naturaltabletag\m_tabl_tbl_level:\number#1:\number#2\endcsname\expandafter\gobbleoneargument \else\expandafter\firstofoneargument \fi}
+\def\tabl_ntb_tag_doifelse#1#2{\ifcsname\??naturaltabletag\m_tabl_tbl_level:\number#1:\number#2\endcsname\expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments\fi}
+\def\tabl_ntb_row_doif #1#2{\ifcsname\??naturaltablerow\m_tabl_tbl_level:\number#1:\number#2\endcsname\expandafter\firstofoneargument \else\expandafter\gobbleoneargument \fi}
+\def\tabl_ntb_col_doif #1#2{\ifcsname\??naturaltablecol\m_tabl_tbl_level:\number#1:\number#2\endcsname\expandafter\firstofoneargument \else\expandafter\gobbleoneargument \fi}
+\def\tabl_ntb_col_doifnot #1#2{\ifcsname\??naturaltablecol\m_tabl_tbl_level:\number#1:\number#2\endcsname\expandafter\gobbleoneargument \else\expandafter\firstofoneargument \fi}
+
+%D If we ever run into memory issues we can do:
+%
+% \def\tabl_ntb_let_tag#1#2#3%
+% {\ifx#3\c_tabl_ntb_none\else
+% \expandafter\let\csname\??naturaltabletag\m_tabl_tbl_level:\number#1:\number#2\endcsname#3%
+% \fi}
+%
+% \def\tabl_ntb_get_tag#1#2%
+% {\ifcsname\??naturaltabletag\m_tabl_tbl_level:\number#1:\number#2\endcsname
+% \lastnamedcs
+% \else
+% \c_tabl_ntb_none
+% \fi}
+
+% not used
+%
+% \def\tabl_ntb_tag_state#1#2{\ifcsname\??naturaltabletag\m_tabl_tbl_level:\number#1:\number#2\endcsname\zerocount\else\plusone\fi}
+% \def\tabl_ntb_row_state#1#2{\ifcsname\??naturaltablerow\m_tabl_tbl_level:\number#1:\number#2\endcsname\zerocount\else\plusone\fi}
+% \def\tabl_ntb_col_state#1#2{\ifcsname\??naturaltablecol\m_tabl_tbl_level:\number#1:\number#2\endcsname\zerocount\else\plusone\fi}
+
+%def\tabl_ntb_set_spn #1{\expandafter\let\csname\??naturaltablespn\m_tabl_tbl_level:\number#1\endcsname \!!plusone}
+%def\tabl_ntb_spn_doifelse#1{\doifelse {\csname\??naturaltablespn\m_tabl_tbl_level:\number#1\endcsname}\!!plusone}
+
+%def\tabl_ntb_set_spn #1{\setvalue {\??naturaltablespn\m_tabl_tbl_level:\number#1}{1}}
+%def\tabl_ntb_spn_doifelse#1{\doifelsevalue{\??naturaltablespn\m_tabl_tbl_level:\number#1}{1}}
+
+\def\tabl_ntb_let_ref #1#2{\expandafter\glet\csname\??naturaltableref\m_tabl_tbl_level:\number#1:\number#2\endcsname}
+\def\tabl_ntb_set_ref #1#2{\expandafter\xdef\csname\??naturaltableref\m_tabl_tbl_level:\number#1:\number#2\endcsname}
+%def\tabl_ntb_get_ref #1#2{\ifcsname\??naturaltableref\m_tabl_tbl_level:\number#1:\number#2\endcsname\csname\??naturaltableref\m_tabl_tbl_level:\number#1:\number#2\endcsname\fi}
+\def\tabl_ntb_get_ref #1#2{\begincsname\??naturaltableref\m_tabl_tbl_level:\number#1:\number#2\endcsname}
+
+\def\tabl_ntb_set_spn #1{\expandafter\let\csname\??naturaltablespn\m_tabl_tbl_level:\number#1\endcsname \!!plusone}
+\def\tabl_ntb_spn_doifelse#1{\ifcase0\csname\??naturaltablespn\m_tabl_tbl_level:\number#1\endcsname\relax % could be inlined
+ \expandafter\secondoftwoarguments % unset
+ \else
+ \expandafter\firstoftwoarguments % a span
+ \fi}
+
+% keep for a while:
+%
+% \unexpanded\def\tabl_ntb_set_txt_process#1#2#3#4#5#6% nasty: we restore the level
+% {\expandafter\def\csname\??naturaltabletxt\m_tabl_tbl_level:\number#1:\number#2\expandafter\endcsname\expandafter
+% {\expandafter\def\expandafter\m_tabl_tbl_level\expandafter{\m_tabl_tbl_level}\tabl_ntb_cell_process{#3}{#4}[#5]{#6}}}
+
+\unexpanded\def\tabl_ntb_set_txt_process#1#2#3#4#5#6%
+ {\expandafter\def\csname\??naturaltabletxt\m_tabl_tbl_level:\number#1:\number#2\endcsname
+ {\tabl_ntb_cell_process{#3}{#4}[#5]{\tabl_ntb_next_level#6\tabl_ntb_prev_level}}}
+
+\def\tabl_ntb_get_txt#1#2%
+ {\csname\??naturaltabletxt\m_tabl_tbl_level:\number#1:\number#2\endcsname}
+
+% to be changed:
+
+\newif\ifsqueezeTBLspan \squeezeTBLspantrue % spans one column cell over multi column par cells
+\newif\ifautosqueezeTBLspan \autosqueezeTBLspantrue % unless explicit widths are given
+\newif\ifautoTBLspread \autoTBLspreadfalse
+\newif\ifautoTBLhsize \autoTBLhsizetrue
+\newif\ifautoTBLrowspan \autoTBLrowspantrue
+\newif\ifautoTBLemptycell \autoTBLemptycelltrue
+\newif\ifautoTBLcheckwidth \autoTBLcheckwidthtrue
+\newif\ifappendTBLsetups \appendTBLsetupstrue
+\newif\ifenableTBLbreak \enableTBLbreakfalse
+\newif\ifmultipleTBLheads \multipleTBLheadsfalse
+\newif\iftightTBLrowspan \tightTBLrowspantrue
+\newif\iftightTBLcolspan \tightTBLcolspanfalse
+
+\newconditional \c_tabl_ntb_trace_widths
+
+\installtextracker
+ {tables.natural.widths}
+ {\settrue \c_tabl_ntb_trace_widths}
+ {\setfalse\c_tabl_ntb_trace_widths}
+
+% so far
+
+\unexpanded\def\tabl_ntb_cell_process#1#2[#3]{}
+
+\unexpanded\def\bTC#1\eTC{\bTD#1\eTD} \let\eTC\relax
+\unexpanded\def\bTX#1\eTX{\bTD#1\eTD} \let\eTX\relax
+\unexpanded\def\bTY#1\eTY{\bTR#1\eTR} \let\eTY\relax
+
+\unexpanded\def\setupTABLE
+ {\dotripleempty\tabl_ntb_setup}
+
+\let\tabl_ntb_parameters_get\setupcurrentnaturaltablelocal
+
+\def\tabl_ntb_setup
+ {\ifthirdargument
+ \expandafter\tabl_ntb_setup_three
+ \orelse\ifsecondargument
+ \doubleexpandafter\tabl_ntb_setup_two
+ \else
+ \doubleexpandafter\tabl_ntb_setup_one
+ \fi}
+
+\def\tabl_ntb_setup_one[#1][#2][#3]%
+ {\setupcurrentnaturaltablelocal[#1]}
+
+\def\tabl_ntb_setup_xy[#1][#2][#3]%
+ {\def\tabl_ntb_setup_step##1{\tabl_ntb_parameters_set[#1##1][#3]}%
+ \processcommalist[#2]\tabl_ntb_setup_step}
+
+\def\tabl_ntb_setup_un[#1][#2][#3]%
+ {\def\tabl_ntb_setup_step##1%
+ {\def\tabl_ntb_setup_step_step####1{\tabl_ntb_parameters_set[\c!x##1\c!y####1][#3]}%
+ \processcommalist[#2]\tabl_ntb_setup_step_step}%
+ \processcommalist[#1]\tabl_ntb_setup_step}
+
+\def\tabl_ntb_setup_each[#1][#2][#3]% ignores #3
+ {\tabl_ntb_parameters_set[#1\v!each][#2]}
+
+\def\tabl_ntb_setup_ux[#1][#2][#3]% ignores #3
+ {\def\tabl_ntb_setup_step##1{\tabl_ntb_parameters_set[\c!x##1][#2]}%
+ \processcommalist[#1]\tabl_ntb_setup_step}
+
+\installcorenamespace{naturaltablesetupthree}
+\installcorenamespace{naturaltablesetuptwo}
+
+%def\tabl_ntb_setup_three[#1]{\csname\??naturaltablesetupthree\ifcsname\??naturaltablesetupthree#1\endcsname#1\else\s!unknown\fi\endcsname[#1]}
+%def\tabl_ntb_setup_two [#1]{\csname\??naturaltablesetuptwo \ifcsname\??naturaltablesetuptwo #1\endcsname#1\else\s!unknown\fi\endcsname[#1]}
+
+\def\tabl_ntb_setup_three[#1]{\ifcsname\??naturaltablesetupthree#1\endcsname\expandafter\lastnamedcs\else\expandafter\tabl_ntb_setup_un\fi[#1]}
+\def\tabl_ntb_setup_two [#1]{\ifcsname\??naturaltablesetuptwo #1\endcsname\expandafter\lastnamedcs\else\expandafter\tabl_ntb_setup_ux\fi[#1]}
+
+\setvalue{\??naturaltablesetupthree \v!row}[#1]{\tabl_ntb_setup_xy [\c!y]}
+\setvalue{\??naturaltablesetupthree \v!column}[#1]{\tabl_ntb_setup_xy [\c!x]}
+\setvalue{\??naturaltablesetupthree \v!start}[#1]{\tabl_ntb_setup_xy [\v!start]}
+\setvalue{\??naturaltablesetupthree \v!header}[#1]{\tabl_ntb_setup_xy [\v!header]}
+
+\setvalue{\??naturaltablesetuptwo \v!row}[#1]{\tabl_ntb_setup_each[\c!y]}
+\setvalue{\??naturaltablesetuptwo \v!column}[#1]{\tabl_ntb_setup_each[\c!x]}
+\setvalue{\??naturaltablesetuptwo \v!start}[#1]{\tabl_ntb_setup_each[\v!start]}
+\setvalue{\??naturaltablesetuptwo \v!header}[#1]{\tabl_ntb_setup_each[\v!header]}
+
+\letvalue{\??naturaltablesetupthree\s!unknown}\tabl_ntb_setup_un
+\letvalue{\??naturaltablesetuptwo \s!unknown}\tabl_ntb_setup_ux
+
+\letcsnamecsname\csname\??naturaltablesetupthree r\endcsname\csname\??naturaltablesetupthree \v!row\endcsname
+\letcsnamecsname\csname\??naturaltablesetupthree c\endcsname\csname\??naturaltablesetupthree\v!column\endcsname
+\letcsnamecsname\csname\??naturaltablesetupthree y\endcsname\csname\??naturaltablesetupthree \v!row\endcsname
+\letcsnamecsname\csname\??naturaltablesetupthree x\endcsname\csname\??naturaltablesetupthree\v!column\endcsname
+
+\letcsnamecsname\csname\??naturaltablesetuptwo r\endcsname\csname\??naturaltablesetuptwo \v!row\endcsname
+\letcsnamecsname\csname\??naturaltablesetuptwo c\endcsname\csname\??naturaltablesetuptwo \v!column\endcsname
+\letcsnamecsname\csname\??naturaltablesetuptwo y\endcsname\csname\??naturaltablesetuptwo \v!row\endcsname
+\letcsnamecsname\csname\??naturaltablesetuptwo x\endcsname\csname\??naturaltablesetuptwo \v!column\endcsname
+
+\def\tabl_ntb_parameters_set[#1][#2]%
+ {\ifappendTBLsetups
+ \ifcsname\??naturaltableset\m_tabl_tbl_level:#1\endcsname
+ \def\tabl_ntb_parameters_get[##1]%
+ {\setvalue{\??naturaltableset\m_tabl_tbl_level:#1}{\tabl_ntb_parameters_get[##1,#2]}}%
+ \csname\??naturaltableset\m_tabl_tbl_level:#1\endcsname
+ \let\tabl_ntb_parameters_get\setupcurrentnaturaltablelocal
+ \else
+ \setvalue{\??naturaltableset\m_tabl_tbl_level:#1}{\tabl_ntb_parameters_get[#2]}%
+ \fi
+ \else
+ \setvalue{\??naturaltableset\m_tabl_tbl_level:#1}{\tabl_ntb_parameters_get[#2]}%
+ \fi}
+
+% % \setupTABLE [y] [first][background=color,backgroundcolor=blue,frame=off,bottomframe=on,topframe=on,framecolor=white]
+% \setupTABLE [first][first][backgroundcorner=2,corner=10,frame=on]
+% \setupTABLE [last] [first][backgroundcorner=4,corner=12,frame=on]
+%
+% \setupTABLE [row] [each] [background=color,backgroundcolor=blue,frame=on,framecolor=white]
+% \setupTABLE [first][2] [corner=8]
+% \setupTABLE [last] [2] [corner=5]
+% \setupTABLE [first][last] [corner=7]
+% \setupTABLE [last] [last] [corner=6]
+%
+% \startTEXpage
+% \bTABLE[frame=off,align=middle]
+% \bTR \bTD one \eTD \bTD two \eTD \bTD three \eTD \eTR
+% \bTR \bTD first \eTD \bTD second \eTD \bTD third \eTD \eTR
+% \bTR \bTD alpha \eTD \bTD beta \eTD \bTD gamma \eTD \eTR
+% \eTABLE
+% \stopTEXpage
+%
+% \setupTABLE [first] [two][corner=2] % special case
+% \setupTABLE [last] [two][corner=4] % special case
+%
+% % % \setupTABLE [one] [first] ... special case of span
+%
+% \startTEXpage
+% \bTABLE[frame=off,align=middle]
+% \bTR \bTD one \eTD \bTD two \eTD \bTD three \eTD \eTR
+% \bTR \bTD first \eTD \bTD second \eTD \bTD third \eTD \eTR
+% \eTABLE
+% \stopTEXpage
+
+%D By default rowspans are tight but you can change that:
+%D
+%D \startbuffer
+%D \bTABLE
+%D \bTR[height=20pt] \bTH 1. col \eTH \bTH 2. col \eTH \eTR
+%D \bTR[height=20pt] \bTD 1 row in 1. col \eTD \bTD[nr=2] 2 rows in 2. col \eTD \eTR
+%D \bTR[height=20pt] \bTD[nr=2] 2 rows in 1. col\eTD \eTR
+%D \bTR[height=20pt] \bTD[nr=3] 3 rows in 2. col \eTD \eTR
+%D \bTR[height=20pt] \bTD 1 row in 1. col \eTD \eTR
+%D \bTR[height=20pt] \bTD 1 row in 1. col \eTD \eTR
+%D \eTABLE
+%D
+%D \bTABLE
+%D \bTR[height=20pt] \bTH 2. col \eTH \bTH 1. col \eTH \eTR
+%D \bTR[height=20pt] \bTD[nr=2] 2 rows in 2. col \eTD \bTD 1 row in 1. col \eTD \eTR
+%D \bTR[height=20pt] \bTD[nr=2] 2 rows in 1. col\eTD \eTR
+%D \bTR[height=20pt] \bTD[nr=3] 3 rows in 2. col \eTD \eTR
+%D \bTR[height=20pt] \bTD 1 row in 1. col \eTD \eTR
+%D \bTR[height=20pt] \bTD 1 row in 1. col \eTD \eTR
+%D \eTABLE
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D With \type {\tightTBLrowspanfalse} we get:
+%D
+%D \start \tightTBLrowspanfalse \getbuffer \stop
+
+\let\tabl_ntb_setup_section\relax
+
+\unexpanded\def\tabl_ntb_setup_cell#1#2% cell over col over row
+ {\tabl_ntb_setup_section % already forgotten
+ \edef\m_tabl_ntb_positive_row{\number#1}%
+ \edef\m_tabl_ntb_positive_col{\number#2}%
+ \edef\m_tabl_ntb_negative_row{\the\numexpr-\c_tabl_ntb_maximum_row+#1+\minusone\relax}%
+ \edef\m_tabl_ntb_negative_col{\the\numexpr-\c_tabl_ntb_maximum_col+#2+\minusone\relax}%
+ % saves tokens (no speed gain)
+ \edef\m_tabl_ntb_prefix{\??naturaltableset\m_tabl_tbl_level:}%
+ % each each
+ \begincsname\m_tabl_ntb_prefix\c!x\v!each\c!y\v!each\endcsname
+ \begincsname\m_tabl_ntb_prefix\c!y\v!each\endcsname
+ \begincsname\m_tabl_ntb_prefix\c!x\v!each\endcsname
+ % odd even
+ \begincsname\m_tabl_ntb_prefix\c!y\v!oddeven\m_tabl_ntb_positive_row\endcsname
+ \begincsname\m_tabl_ntb_prefix\c!x\v!oddeven\m_tabl_ntb_positive_col\endcsname
+ \begincsname\m_tabl_ntb_prefix\c!x\v!oddeven\m_tabl_ntb_positive_col\c!y\v!oddeven\m_tabl_ntb_positive_row\endcsname
+ % row/col number combinations
+ \begincsname\m_tabl_ntb_prefix\c!y\m_tabl_ntb_positive_row\endcsname
+ \begincsname\m_tabl_ntb_prefix\c!y\m_tabl_ntb_negative_row\endcsname
+ \naturaltablelocalparameter\c!extras
+ \letnaturaltablelocalparameter\c!extras\relax % new, see x-fo
+ \begincsname\m_tabl_ntb_prefix\c!x\m_tabl_ntb_positive_col\endcsname
+ \begincsname\m_tabl_ntb_prefix\c!x\m_tabl_ntb_negative_col\endcsname
+ \naturaltablelocalparameter\c!extras
+ \letnaturaltablelocalparameter\c!extras\relax % new, see x-fo
+ % first/last combinations
+ \ifnum\m_tabl_ntb_positive_row=\plusone
+ \begincsname\m_tabl_ntb_prefix\c!y\v!first\endcsname
+ \begincsname\m_tabl_ntb_prefix\c!x\m_tabl_ntb_positive_col\c!y\v!first\endcsname
+ \fi
+ \ifnum\m_tabl_ntb_positive_col=\plusone
+ \begincsname\m_tabl_ntb_prefix\c!x\v!first\endcsname
+ \begincsname\m_tabl_ntb_prefix\c!x\v!first\c!y\m_tabl_ntb_positive_row\endcsname
+ \fi
+ \ifnum\m_tabl_ntb_positive_row=\c_tabl_ntb_maximum_row\relax
+ \begincsname\m_tabl_ntb_prefix\c!y\v!last\endcsname
+ \begincsname\m_tabl_ntb_prefix\c!x\m_tabl_ntb_positive_col\c!y\v!last\endcsname
+ \fi
+ \ifnum\m_tabl_ntb_positive_col=\c_tabl_ntb_maximum_col\relax
+ \begincsname\m_tabl_ntb_prefix\c!x\v!last\endcsname
+ \begincsname\m_tabl_ntb_prefix\c!x\v!last\c!y\m_tabl_ntb_positive_row\endcsname
+ \fi
+ \ifnum\m_tabl_ntb_positive_row=\c_tabl_ntb_maximum_row\relax \ifnum\m_tabl_ntb_positive_col=\c_tabl_ntb_maximum_col\relax
+ \begincsname\m_tabl_ntb_prefix\c!x\v!last\c!y\v!last\endcsname
+ \fi\fi
+ \ifnum\m_tabl_ntb_positive_row=\plusone \ifnum\m_tabl_ntb_positive_col=\plusone
+ \begincsname\m_tabl_ntb_prefix\c!x\v!first\c!y\v!first\endcsname
+ \fi\fi
+ \ifnum\m_tabl_ntb_positive_row=\plusone \ifnum\m_tabl_ntb_positive_col=\c_tabl_ntb_maximum_col\relax
+ \begincsname\m_tabl_ntb_prefix\c!x\v!last\c!y\v!first\endcsname
+ \fi\fi
+ \ifnum\m_tabl_ntb_positive_row=\c_tabl_ntb_maximum_row\relax \ifnum\m_tabl_ntb_positive_col=\plusone
+ \begincsname\m_tabl_ntb_prefix\c!x\v!first\c!y\v!last\endcsname
+ \fi\fi
+ % special case: two rows and last row : two&first and two&last (round corners)
+ \ifnum\c_tabl_ntb_maximum_row=\plustwo\relax
+ \ifnum\m_tabl_ntb_positive_row=\c_tabl_ntb_maximum_row\relax \ifnum\m_tabl_ntb_positive_col=\plusone
+ \begincsname\m_tabl_ntb_prefix\c!x\v!first\c!y\v!two\endcsname
+ \fi\fi
+ \ifnum\m_tabl_ntb_positive_row=\c_tabl_ntb_maximum_row\relax \ifnum\m_tabl_ntb_positive_col=\c_tabl_ntb_maximum_col\relax
+ \begincsname\m_tabl_ntb_prefix\c!x\v!last\c!y\v!two\endcsname
+ \fi\fi
+ \fi
+ \ifnum\tabl_ntb_get_col\m_tabl_ntb_positive_row\m_tabl_ntb_positive_col=\c_tabl_ntb_maximum_col\relax % top span over whole width
+ \ifnum\m_tabl_ntb_positive_row=\plusone
+ \begincsname\m_tabl_ntb_prefix\c!x\v!one\c!y\v!first\endcsname
+ \fi
+ \ifnum\m_tabl_ntb_positive_row=\c_tabl_ntb_maximum_row\relax
+ \begincsname\m_tabl_ntb_prefix\c!x\v!one\c!y\v!last\endcsname
+ \fi
+ \fi
+ % header things
+ \ifnum#1>\c_tabl_ntb_n_of_hdnx_lines\else
+ \begincsname\m_tabl_ntb_prefix\v!header\v!each\endcsname
+ \begincsname\m_tabl_ntb_prefix\v!header\m_tabl_ntb_positive_col\endcsname
+ \fi
+ % explicit cells
+ \begincsname\m_tabl_ntb_prefix\c!x\m_tabl_ntb_positive_col\c!y\m_tabl_ntb_positive_row\endcsname
+ \begincsname\m_tabl_ntb_prefix\c!x\m_tabl_ntb_negative_col\c!y\m_tabl_ntb_negative_row\endcsname
+ % local
+ \begincsname\m_tabl_ntb_prefix\c!y++\m_tabl_ntb_positive_row\endcsname
+ % done
+ \relax}
+
+% we cannot use +n (checking on number/last/first would slow down too much)
+%
+% \setupTABLE[r] [2][color=red]
+% \setupTABLE[r] [-2][color=red]
+% \setupTABLE[c] [2][color=green]
+% \setupTABLE[c] [-2][color=green]
+% \setupTABLE[4] [4][color=blue]
+% \setupTABLE[-4][-4][color=blue]
+%
+% \bTABLE
+% \dorecurse{10}{\bTR \dorecurse{6}{\bTD xxx \eTD} \eTR}
+% \eTABLE
+
+\let\m_tabl_ntb_before_split\empty
+\let\m_tabl_ntb_after_split \empty
+\let\m_tabl_ntb_same_page \empty
+
+% split + page:
+%
+% \bTABLE[split=yes]
+% \bTR \bTD left \eTD\bTD right \eTD\eTR
+% \bTR[after=\page] \bTD left \eTD\bTD right \eTD\eTR
+% \bTR \bTD left \eTD\bTD right \eTD\eTR
+% \eTABLE
+
+\unexpanded\def\tabl_ntb_tr
+ {\c_tabl_ntb_running_col\zerocount
+ \c_tabl_ntb_encountered_col\zerocount
+ \advance\c_tabl_ntb_maximum_row\plusone
+ \iffirstargument
+ \expandafter\tabl_ntb_tr_yes
+ \else
+ \expandafter\gobbleoneoptional
+ \fi}
+
+\def\tabl_ntb_tr_yes[#1]%
+ {\setvalue{\??naturaltableset\m_tabl_tbl_level:\c!y++\the\c_tabl_ntb_maximum_row}{\setupcurrentnaturaltablelocal[#1]}}
+
+\def\m_tabl_ntb_default_nr{\naturaltableparameter\c!nr}
+\def\m_tabl_ntb_default_nc{\naturaltableparameter\c!nc}
+
+\unexpanded\def\tabl_ntb_td
+ {\advance\c_tabl_ntb_encountered_col\plusone
+ \iffirstargument
+ \expandafter\tabl_ntb_td_yes
+ \else
+ \expandafter\tabl_ntb_td_nop
+ \fi}
+
+\def\tabl_ntb_td_yes[#1]#2\eTD
+ {\letnaturaltableparameter\c!ny \m_tabl_ntb_default_nr
+ \letnaturaltableparameter\c!nx \m_tabl_ntb_default_nc
+ \letnaturaltableparameter\c!nc \plusone
+ \letnaturaltableparameter\c!nr \plusone
+ \letnaturaltableparameter\c!n \c_tabl_ntb_running_col
+ \letnaturaltableparameter\c!m \empty
+ \letnaturaltableparameter\c!action\empty % not that important
+ \setupcurrentnaturaltable[#1]%
+ %
+ \c_tabl_ntb_nx\naturaltableparameter\c!nx\relax
+ \c_tabl_ntb_ny\naturaltableparameter\c!ny\relax
+ % goto first cell n/m=cellnumber
+ \edef\m_tabl_ntb_n{\naturaltableparameter\c!n}%
+ \edef\m_tabl_ntb_m{\naturaltableparameter\c!m}%
+ %
+ \ifx\m_tabl_ntb_n\empty
+ \global\advance\c_tabl_ntb_spn\c_tabl_ntb_nx\relax
+ \orelse\ifnum\m_tabl_ntb_n=\c_tabl_ntb_running_col\else
+ \tabl_ntb_td_pass_n{#1}%
+ \fi
+ \ifx\m_tabl_ntb_m\empty \else
+ \ifnum\m_tabl_ntb_m=\c_tabl_ntb_running_col\else
+ \tabl_ntb_td_pass_m{#1}%
+ \fi
+ \fi
+ \doloop % skip over columns that result from earlier span
+ {\advance\c_tabl_ntb_running_col\plusone
+ \ifcsname\tabl_ntb_tag_pattern\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col\endcsname \else
+ \exitloop
+ \fi}%
+ % fill r*c cells and set span
+ \c_tabl_ntb_nx\naturaltableparameter\c!nx\relax
+ \c_tabl_ntb_ny\naturaltableparameter\c!ny\relax
+ \ifnum\c_tabl_ntb_nx=\plusone
+ \ifnum\c_tabl_ntb_ny=\plusone
+ \ifnum\c_tabl_ntb_running_col>\c_tabl_ntb_maximum_col\relax
+ \c_tabl_ntb_maximum_col\c_tabl_ntb_running_col
+ \fi
+ \else
+ \tabl_ntb_cell_preset
+ \fi
+ \else
+ \tabl_ntb_cell_preset
+ \fi
+ % set values
+ \tabl_ntb_let_tag\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col\c_tabl_ntb_cell
+ \tabl_ntb_set_col\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col{\the\c_tabl_ntb_nx}%
+ \tabl_ntb_set_row\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col{\the\c_tabl_ntb_ny}%
+ % the action key will change!
+ \tabl_ntb_set_ref\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col{\naturaltableparameter\c!action}%
+ % save text
+ \normalexpanded
+ {\tabl_ntb_set_txt_process\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col{\the\c_tabl_ntb_maximum_row}{\the\c_tabl_ntb_running_col}}%
+ {#1}{#2}%
+ \ifnum\c_tabl_ntb_encountered_col>\c_tabl_ntb_encountered_max
+ \c_tabl_ntb_encountered_max\c_tabl_ntb_encountered_col
+ \fi}
+
+\def\tabl_ntb_td_nop[#1]#2\eTD
+ {\global\advance\c_tabl_ntb_spn\plusone\relax
+ \doloop
+ {\advance\c_tabl_ntb_running_col\plusone
+ \ifcsname\tabl_ntb_tag_pattern\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col\endcsname \else
+ \exitloop
+ \fi}%
+ \c_tabl_ntb_nx\plusone
+ \c_tabl_ntb_ny\plusone
+ \ifnum\c_tabl_ntb_running_col>\c_tabl_ntb_maximum_col\relax
+ \c_tabl_ntb_maximum_col\c_tabl_ntb_running_col
+ \fi
+ \tabl_ntb_let_tag\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col\c_tabl_ntb_cell
+ \tabl_ntb_set_col\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col{\the\c_tabl_ntb_nx}%
+ \tabl_ntb_set_row\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col{\the\c_tabl_ntb_ny}%
+ \tabl_ntb_let_ref\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col\empty
+ \normalexpanded
+ {\tabl_ntb_set_txt_process\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col{\the\c_tabl_ntb_maximum_row}{\the\c_tabl_ntb_running_col}}%
+ {#1}{#2}%
+ \ifnum\c_tabl_ntb_encountered_col>\c_tabl_ntb_encountered_max
+ \c_tabl_ntb_encountered_max\c_tabl_ntb_encountered_col
+ \fi}
+
+\def\tabl_ntb_td_pass_n#1%
+ {\scratchcounter\numexpr\m_tabl_ntb_n-\c_tabl_ntb_running_col+\minusone-\c_tabl_ntb_spn\relax
+ \ifnum\scratchcounter>\zerocount
+ \normalexpanded{\tabl_ntb_td[\c!nx=\the\scratchcounter,\c!n=,\c!m=,*sq=\v!no]}\eTD
+ \fi
+ \letnaturaltableparameter\c!ny\m_tabl_ntb_default_nr
+ \letnaturaltableparameter\c!nx\m_tabl_ntb_default_nc
+ \letnaturaltableparameter\c!nc\plusone
+ \letnaturaltableparameter\c!nr\plusone
+ \setupcurrentnaturaltable[#1]%
+ \letnaturaltableparameter\c!n \empty
+ \letnaturaltableparameter\c!m \empty}
+
+\def\tabl_ntb_td_pass_m#1%
+ {\scratchcounter\numexpr\m_tabl_ntb_m-\c_tabl_ntb_running_col+\minusone-\c_tabl_ntb_spn\relax
+ \dorecurse\scratchcounter{\normalexpanded{\tabl_ntb_td[\c!n=,\c!m=]}\eTD}%
+ % can be sped up
+ \letnaturaltableparameter\c!ny\m_tabl_ntb_default_nr
+ \letnaturaltableparameter\c!nx\m_tabl_ntb_default_nc
+ \letnaturaltableparameter\c!nc\plusone
+ \letnaturaltableparameter\c!nr\plusone
+ \setupcurrentnaturaltable[#1]%
+ \letnaturaltableparameter\c!n \empty
+ \letnaturaltableparameter\c!m \empty}
+
+\def\tabl_ntb_cell_preset
+ {\c_tabl_ntb_current_row\c_tabl_ntb_maximum_row
+ \c_tabl_ntb_current_col\c_tabl_ntb_running_col
+ \dorecurse\c_tabl_ntb_ny\tabl_ntb_cell_preset_rows
+ % check max column
+ \advance\c_tabl_ntb_current_col\minusone
+ \ifnum\c_tabl_ntb_current_col>\c_tabl_ntb_maximum_col\relax
+ \c_tabl_ntb_maximum_col\c_tabl_ntb_current_col
+ \fi}
+
+\def\tabl_ntb_cell_preset_rows
+ {\c_tabl_ntb_current_col\c_tabl_ntb_running_col
+ \tabl_ntb_set_col\c_tabl_ntb_current_row\c_tabl_ntb_current_col{\the\c_tabl_ntb_nx}%
+ \ifnum\c_tabl_ntb_nx>\c_tabl_ntb_maximum_row_span\relax
+ \c_tabl_ntb_maximum_row_span\c_tabl_ntb_nx
+ \fi
+ \dorecurse\c_tabl_ntb_nx\tabl_ntb_cell_preset_cells
+ \advance\c_tabl_ntb_current_row\plusone}
+
+\def\tabl_ntb_cell_preset_cells
+ {\tabl_ntb_let_tag\c_tabl_ntb_current_row\c_tabl_ntb_current_col\c_tabl_ntb_none
+ \advance\c_tabl_ntb_current_col\plusone}
+
+%D The usage of n and m:
+%D
+%D \startbuffer
+%D \bTABLE[width=3em]
+%D \bTR\bTD d1 \eTD\bTD[n=2] d2 \eTD\bTD[n=5] d5 \eTD\bTD[n=7] d7 \eTD\eTR
+%D \bTR\bTD f1 \eTD\bTD[n=4] f4 \eTD\bTD[n=5] f5 \eTD\bTD[n=7] f7 \eTD\eTR
+%D \eTABLE
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \bTABLE[width=3em]
+%D \bTR\bTD d1 \eTD\bTD[m=2] d2 \eTD\bTD[m=5] d5 \eTD\bTD[m=7] d7 \eTD\eTR
+%D \bTR\bTD f1 \eTD\bTD[m=4] f4 \eTD\bTD[m=5] f5 \eTD\bTD[m=7] f7 \eTD\eTR
+%D \eTABLE
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \bTABLE[frame=on]
+%D \bTR \bTH[nc=3] One \eTH \bTH[m=4] Four \eTH\eTR
+%D \bTR \bTD a \eTD\bTD b \eTD\bTD c \eTD\bTD d \eTD\eTR
+%D \eTABLE
+%D
+%D \bTABLE[frame=on]
+%D \bTR \bTH[nr=2] One \eTH \bTH[m=3] Three \eTH\eTR
+%D \bTR \bTD[m=3] a \eTD\bTD b \eTD\bTD c \eTD\bTD d \eTD\eTR
+%D \bTR \bTD[m=3] a \eTD\bTD b \eTD\bTD c \eTD\bTD d \eTD\eTR
+%D \eTABLE
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+\def\tabl_ntb_th[#1]#2\eTH
+ {\tabl_ntb_td[#1,\c!color=\naturaltablelocalparameter\c!headcolor,\c!style=\naturaltablelocalparameter\c!headstyle,\c!aligncharacter=\v!no]#2\eTD}
+
+\def\tabl_ntb_tn[#1]#2\eTN
+ {\tabl_ntb_td[#1]\digits#2\relax\eTD}
+
+%D Vit Zyka needed the option to create a distance between columns, so I added
+%D support for individual column distances.
+%D
+%D \startbuffer
+%D % \setupTABLE[c][each][distance=2em]
+%D \setupTABLE[c][1][distance=2em]
+%D \setupTABLE[c][2][distance=3em]
+%D
+%D \bTABLE
+%D \bTR \bTD test \eTD \bTD test \eTD \bTD test \eTD \eTR
+%D \bTR \bTD[nx=2] test \eTD \bTD test \eTD \eTR
+%D \bTR \bTD test \eTD \bTD[nx=2] test \eTD \eTR
+%D \eTABLE
+%D
+%D \bTABLE[option=stretch]
+%D \bTR \bTD test \eTD \bTD test \eTD \bTD test \eTD \eTR
+%D \bTR \bTD[nx=2] test \eTD \bTD test \eTD \eTR
+%D \bTR \bTD test \eTD \bTD[nx=2] test \eTD \eTR
+%D \eTABLE
+%D \stopbuffer
+%D
+%D \typebuffer \startlinecorrection \getbuffer \stoplinecorrection
+%D
+%D and he provided patches for the global left and right margin distances as well as
+%D the columndistance (although i changed the names -). Here is his testcase:
+%D
+%D \startbuffer
+%D \framed[offset=overlay]\bgroup
+%D \setupTABLE[column][2][align=left]%
+%D \setupTABLE[column][3][align=right]%
+%D \bTABLE[columndistance=2cm,leftmargindistance=.3cm,rightmargindistance=.5cm]
+%D \bTR \bTH[nc=3] Table head\eTH \eTR
+%D \bTR \bTD[nc=2] AB\eTD \bTD C\eTD \eTR
+%D \bTR \bTD[nc=2,align=left] AB\eTD \bTD C\eTD \eTR
+%D \bTR \bTD[nc=2,align=middle] AB\eTD \bTD C\eTD \eTR
+%D \bTR \bTD A\eTD \bTD B\eTD \bTD C\eTD \eTR
+%D \bTR \bTD Aa\eTD \bTD Bb\eTD \bTD Cccc\eTD \eTR
+%D \bTR \bTD[nc=3,align=middle] ABC\eTD \eTR
+%D \eTABLE
+%D \egroup
+%D \stopbuffer
+%D
+%D \typebuffer \startlinecorrection \getbuffer \stoplinecorrection
+
+% to be done: head <raw> foot, dus state var
+
+\unexpanded\def\bTABLEhead{\dosingleempty\tabl_ntb_head} \let\eTABLEhead\relax
+\unexpanded\def\bTABLEnext{\dosingleempty\tabl_ntb_next} \let\eTABLEnext\relax
+\unexpanded\def\bTABLEbody{\dosingleempty\tabl_ntb_body} \let\eTABLEbody\relax
+\unexpanded\def\bTABLEfoot{\dosingleempty\tabl_ntb_foot} \let\eTABLEfoot\relax
+
+\def\tabl_ntb_head[#1]#2\eTABLEhead{\appendtoks\tabl_ntb_section[#1]{#2}\to\t_tabl_ntb_head}
+\def\tabl_ntb_next[#1]#2\eTABLEnext{\appendtoks\tabl_ntb_section[#1]{#2}\to\t_tabl_ntb_next}
+\def\tabl_ntb_body[#1]#2\eTABLEbody{\appendtoks\tabl_ntb_section[#1]{#2}\to\t_tabl_ntb_body}
+\def\tabl_ntb_foot[#1]#2\eTABLEfoot{\appendtoks\tabl_ntb_section[#1]{#2}\to\t_tabl_ntb_foot}
+
+\def\tabl_ntb_section[#1]#2% also used in tabl-nte
+ {\unexpanded\def\tabl_ntb_setup_section{\setupcurrentnaturaltablelocal[#1]}%
+ #2%
+ \let\tabl_ntb_setup_section\relax}
+
+\def\tabl_ntb_preset_parameters% each odd|even level / can be sped up but only once per table
+ {\begincsname\??naturaltableset\m_tabl_tbl_level:\v!start\v!each\endcsname
+ \begincsname\??naturaltableset\m_tabl_tbl_level:\v!start\v!oddeven\m_tabl_tbl_level\endcsname
+ \begincsname\??naturaltableset\m_tabl_tbl_level:\v!start\m_tabl_tbl_level\endcsname}
+
+\unexpanded\def\bTABLE
+ {\dosingleempty\tabl_ntb_table}
+
+\def\tabl_ntb_table[#1]%
+ {\tabl_ntb_table_push
+ % box not here
+ \bgroup
+ \pushpostponednodedata
+ \t_tabl_ntb_head\emptytoks
+ \t_tabl_ntb_next\emptytoks
+ \t_tabl_ntb_body\emptytoks
+ \t_tabl_ntb_foot\emptytoks
+ \ifhmode\kern\zeropoint\fi % blocks \removeunwantedspaces: check this on icare handelingsschema
+ \resetcharacteralign % new
+ \setupcurrentnaturaltablelocal[\c!align={\v!right,\v!broad,\v!high},#1]%
+ %
+ \d_tabl_ntb_leftmargindistance \naturaltablelocalparameter\c!leftmargindistance\relax
+ \d_tabl_ntb_rightmargindistance\naturaltablelocalparameter\c!rightmargindistance\relax
+ \d_tabl_ntb_columndistance \naturaltablelocalparameter\c!columndistance\relax
+ \d_tabl_ntb_maxwidth \naturaltablelocalparameter\c!maxwidth\relax
+ %
+ \usesetupsparameter\naturaltablelocalparameter
+ \doifelse{\naturaltablelocalparameter\c!textwidth}\v!local
+ {\hsize\availablehsize}
+ {\hsize\naturaltablelocalparameter\c!textwidth}%
+ \enableTBLbreakfalse
+ \multipleTBLheadsfalse
+ \autoTBLspreadfalse
+ \tightTBLcolspanfalse
+ \processaction
+ [\naturaltablelocalparameter\c!split]
+ [ \v!yes=>\enableTBLbreaktrue,
+ \v!repeat=>\enableTBLbreaktrue\multipleTBLheadstrue,
+ \v!auto=>\ifinsidesplitfloat\enableTBLbreaktrue\fi]
+ \processaction
+ [\naturaltablelocalparameter\c!header]
+ [\v!repeat=>\multipleTBLheadstrue]%
+ \tabl_ntb_preset_parameters
+ \processallactionsinset
+ [\naturaltablelocalparameter\c!option]
+ [\v!stretch=>\autoTBLspreadtrue,%
+ \v!tight=>\tightTBLcolspantrue]%
+ \linewidth\naturaltablelocalparameter\c!rulethickness % needs to be frozen
+ \dontcomplain
+ \c_tabl_ntb_running_col \zerocount
+ \c_tabl_ntb_maximum_col \zerocount
+ \c_tabl_ntb_maximum_row \zerocount
+ \c_tabl_ntb_maximum_row_span\plusone
+ \let\currentTABLErow \tabl_ntb_current_row
+ \let\currentTABLEcolumn\tabl_ntb_current_column
+ \let\nofTABLErows \tabl_ntb_n_of_rows
+ \let\nofTABLEcolumns \tabl_ntb_n_of_columns
+ \let\bTR\dobTR
+ \let\bTD\dobTD
+ \let\bTH\dobTH
+ \let\bTN\dobTN}
+
+\def\tabl_ntb_current_row {\m_tabl_ntb_positive_row}
+\def\tabl_ntb_current_column{\m_tabl_ntb_positive_col}
+\def\tabl_ntb_n_of_rows {\number\c_tabl_ntb_maximum_row}
+\def\tabl_ntb_n_of_columns {\number\c_tabl_ntb_maximum_col}
+
+\let\currentTABLErow \!!zerocount
+\let\currentTABLEcolumn\!!zerocount
+\let\nofTABLErows \!!zerocount
+\let\nofTABLEcolumns \!!zerocount
+
+% there is no gain in a \doifelsenextoptionalcs variant
+
+\unexpanded\def\dobTR{\dosingleempty\tabl_ntb_tr} % also used in tabl-nte
+\unexpanded\def\dobTD{\dosingleempty\tabl_ntb_td} % also used in tabl-nte
+\unexpanded\def\dobTH{\dosingleempty\tabl_ntb_th} % also used in tabl-nte
+\unexpanded\def\dobTN{\dosingleempty\tabl_ntb_tn} % also used in tabl-nte
+
+% permits \expanded{\bTD ... \eTD}
+
+\let\bTR\relax \unexpanded\def\eTR{\ignorespaces} % handy in case we use a macro to generate rows
+\let\bTD\relax \unexpanded\def\eTD{\ignorespaces}
+\let\bTH\relax \unexpanded\def\eTH{\ignorespaces}
+\let\bTN\relax \unexpanded\def\eTN{\ignorespaces}
+
+\unexpanded\def\eTABLE % beware, we need to get rid of spurious spaces when in hmode
+ {% tricky and dirty order -)
+ \setfalse\c_tabl_ntb_okay
+ % head
+ \doifelsesometoks\t_tabl_ntb_head % slow, better a flag
+ {\c_tabl_ntb_head\numexpr\c_tabl_ntb_maximum_row+\plusone\relax
+ \the\t_tabl_ntb_head
+ \c_tabl_ntb_n_of_head_lines\c_tabl_ntb_maximum_row\relax
+ \doifelsesometoks\t_tabl_ntb_next
+ {\the\t_tabl_ntb_next
+ \c_tabl_ntb_n_of_next_lines\numexpr\c_tabl_ntb_maximum_row-\c_tabl_ntb_n_of_head_lines\relax}%
+ {\c_tabl_ntb_n_of_next_lines\zerocount}% was 1
+ \c_tabl_ntb_n_of_hdnx_lines\c_tabl_ntb_maximum_row}
+ {\c_tabl_ntb_head\zerocount
+ \c_tabl_ntb_n_of_head_lines\zerocount % was 1
+ \c_tabl_ntb_n_of_next_lines\zerocount
+ \c_tabl_ntb_n_of_hdnx_lines\zerocount}%
+ % body
+ \c_tabl_ntb_body\numexpr\c_tabl_ntb_maximum_row+\plusone\relax
+ \the\t_tabl_ntb_body
+ % foot
+ \doifelsesometoks\t_tabl_ntb_foot
+ {\c_tabl_ntb_foot\numexpr\c_tabl_ntb_maximum_row+\plusone\relax
+ \the\t_tabl_ntb_foot}%
+ {\c_tabl_ntb_foot\zerocount}%
+ % done
+ \removeunwantedspaces % only if hmode
+ % finish cells
+ \tabl_ntb_loop_one
+ % to be sure
+ \tabl_ntb_loop_two
+ % check and do
+ \ifcase\c_tabl_ntb_maximum_col\else
+ \startTBLprocessing
+ \tabl_ntb_table_start
+ \dorecurse\c_tabl_ntb_maximum_row
+ {\tabl_ntb_row_start
+ \c_tabl_ntb_current_row\recurselevel\relax
+ \dorecurse\c_tabl_ntb_maximum_col
+ {\c_tabl_ntb_current_col\recurselevel\relax
+ \normalexpanded{\tabl_ntb_cell{\the\c_tabl_ntb_current_row}{\the\c_tabl_ntb_current_col}}}%
+ \tabl_ntb_row_stop}%
+ \removeunwantedspaces % only if hmode
+ \tabl_ntb_table_stop
+ \stopTBLprocessing
+ % wrong ! ! ! better to have an auto-offset-overlay
+ % \ifnum\m_tabl_tbl_level>1
+ % \vskip-\strutdp
+ % \fi
+ \fi
+ % tracing
+ % \iftrue
+ % \blank \tttf
+ % \dorecurse\c_tabl_ntb_maximum_row
+ % {\c_tabl_ntb_current_row\recurselevel\relax
+ % \dorecurse\c_tabl_ntb_maximum_col
+ % {\c_tabl_ntb_current_col\recurselevel\relax
+ % [r=\the\c_tabl_ntb_current_row,c=\the\c_tabl_ntb_current_col,h=\the\dimexpr\tabl_ntb_get_ht\c_tabl_ntb_current_row\c_tabl_ntb_current_col,w=\the\dimexpr\tabl_ntb_get_wd\c_tabl_ntb_current_row\c_tabl_ntb_current_col]}%
+ % \par}%
+ % \blank
+ % \fi
+ \poppostponednodedata
+ \egroup
+ \tabl_ntb_table_pop}
+
+\def\tabl_ntb_loop_one
+ {\dorecurse\c_tabl_ntb_maximum_row{\tabl_ntb_loop_one_rows}}
+
+\def\tabl_ntb_loop_one_rows
+ {\c_tabl_ntb_current_row\recurselevel\relax
+ \dorecurse\c_tabl_ntb_maximum_col\tabl_ntb_loop_one_cells}
+
+\def\tabl_ntb_loop_one_cells
+ {\c_tabl_ntb_current_col\recurselevel\relax
+ \ifcsname\tabl_ntb_tag_pattern\c_tabl_ntb_current_row\c_tabl_ntb_current_col\endcsname \else
+ \tabl_ntb_loop_one_cells_indeed
+ \fi}
+
+\def\tabl_ntb_loop_one_cells_indeed
+ {\c_tabl_ntb_current_col_two\c_tabl_ntb_current_col
+ \c_tabl_ntb_current_row_two\c_tabl_ntb_current_row
+ \c_tabl_ntb_current_row_one\c_tabl_ntb_current_row
+ \doloop
+ {\c_tabl_ntb_current_col_one\c_tabl_ntb_current_col
+ \doloop
+ {\ifcsname\tabl_ntb_tag_pattern\c_tabl_ntb_current_row_one\c_tabl_ntb_current_col_one\endcsname
+ \exitloop
+ \else
+ \advance\c_tabl_ntb_current_col_one\plusone
+ \ifnum\c_tabl_ntb_current_col_one>\c_tabl_ntb_maximum_col\relax
+ \exitloop
+ \fi
+ \fi}%
+ \ifcsname\tabl_ntb_tag_pattern\c_tabl_ntb_current_row_one\c_tabl_ntb_current_col_one\endcsname
+ \exitloop
+ \else
+ \c_tabl_ntb_current_row_two\c_tabl_ntb_current_row_one
+ \c_tabl_ntb_current_col_two\c_tabl_ntb_current_col_one
+ \advance\c_tabl_ntb_current_row_one\plusone
+ \ifnum\c_tabl_ntb_current_row_one>\c_tabl_ntb_maximum_row
+ \exitloop
+ \fi
+ \fi}%
+ \ifnum\c_tabl_ntb_current_row_two>\c_tabl_ntb_maximum_row\c_tabl_ntb_current_row_two\c_tabl_ntb_maximum_row\fi
+ \ifnum\c_tabl_ntb_current_col_two>\c_tabl_ntb_maximum_col\c_tabl_ntb_current_col_two\c_tabl_ntb_maximum_col\fi
+ \c_tabl_ntb_current_row_two\numexpr\c_tabl_ntb_current_row_two-\c_tabl_ntb_current_row+\plusone\relax
+ \c_tabl_ntb_current_col_two\numexpr\c_tabl_ntb_current_col_two-\c_tabl_ntb_current_col+\plusone\relax
+ \c_tabl_ntb_current_row_one\c_tabl_ntb_current_row
+ \dorecurse\c_tabl_ntb_current_row_two
+ {\c_tabl_ntb_current_col_one\c_tabl_ntb_current_col
+ \tabl_ntb_set_col\c_tabl_ntb_current_row_one\c_tabl_ntb_current_col_one{\the\c_tabl_ntb_current_col_two}%
+ \dorecurse\c_tabl_ntb_current_col_two
+ {\tabl_ntb_let_tag\c_tabl_ntb_current_row_one\c_tabl_ntb_current_col_one\c_tabl_ntb_none
+ \advance\c_tabl_ntb_current_col_one\plusone}%
+ \advance\c_tabl_ntb_current_row_one\plusone}%
+ \tabl_ntb_let_tag\c_tabl_ntb_current_row\c_tabl_ntb_current_col\c_tabl_ntb_cell
+ \tabl_ntb_set_col\c_tabl_ntb_current_row\c_tabl_ntb_current_col{\the\c_tabl_ntb_current_col_two}%
+ \tabl_ntb_set_row\c_tabl_ntb_current_row\c_tabl_ntb_current_col{\the\c_tabl_ntb_current_row_two}%
+ \ifautoTBLemptycell
+ \normalexpanded
+ {\tabl_ntb_set_txt_process\c_tabl_ntb_current_row\c_tabl_ntb_current_col{\the\c_tabl_ntb_current_row}{\the\c_tabl_ntb_current_col}}%
+ {\c!option=\v!tight}{\strut\kern\scaledpoint}% the kern forces the tight
+ \fi}
+
+\def\tabl_ntb_loop_two
+ {\dorecurse\c_tabl_ntb_maximum_row\tabl_ntb_loop_two_rows}
+
+\def\tabl_ntb_loop_two_rows
+ {\c_tabl_ntb_current_row\recurselevel\relax
+ \dorecurse\c_tabl_ntb_maximum_col\tabl_ntb_loop_two_cells}
+
+\def\tabl_ntb_loop_two_cells
+ {\c_tabl_ntb_current_col\recurselevel\relax
+ \ifcsname\tabl_ntb_row_pattern\c_tabl_ntb_current_row\c_tabl_ntb_current_col\endcsname
+ \scratchcounter\numexpr\c_tabl_ntb_maximum_row-\c_tabl_ntb_current_row+\plusone\relax
+ \ifnum\tabl_ntb_get_row\c_tabl_ntb_current_row\c_tabl_ntb_current_col>\scratchcounter
+ \tabl_ntb_set_row\c_tabl_ntb_current_row\c_tabl_ntb_current_col{\the\scratchcounter}%
+ \fi
+ \fi
+ \tabl_ntb_let_ht\c_tabl_ntb_current_row\c_tabl_ntb_current_col\zeropoint
+ %tabl_ntb_let_wd\c_tabl_ntb_current_row\c_tabl_ntb_current_col\zeropoint
+ \ifcsname\tabl_ntb_col_pattern\c_tabl_ntb_current_row\c_tabl_ntb_current_col\endcsname \else
+ \tabl_ntb_let_col\c_tabl_ntb_current_row\c_tabl_ntb_current_col\zerocount
+ \fi
+ \ifcsname\tabl_ntb_tag_pattern\c_tabl_ntb_current_row\c_tabl_ntb_current_col\endcsname \else
+ \tabl_ntb_let_tag\c_tabl_ntb_current_row\c_tabl_ntb_current_col\c_tabl_ntb_none
+ \fi}
+
+\let\startTBLprocessing\relax % public
+\let\stopTBLprocessing \relax % public
+
+\newcount\c_tabl_prelocated_rows % \prelocateTBLrows{1000} may speed up large tables
+
+% \def\tabl_ntb_row_start{\t_tabl_ntb_row\emptytoks}
+% \def\tabl_ntb_row_stop {\normalexpanded{\t_tabl_ntb{\the\t_tabl_ntb\noexpand\tabl_ntb_row_align_start\the\t_tabl_ntb_row\tabl_ntb_row_align_stop}}}
+
+\def\tabl_ntb_row_start
+ {\t_tabl_ntb_row\emptytoks}
+
+\def\tabl_ntb_row_stop
+ {\ifenableTBLbreak
+ \tabl_ntb_row_stop_split
+ \else
+ \tabl_ntb_row_stop_boxed
+ \fi}
+
+\def\tabl_ntb_row_stop_boxed
+ {% \noindent % no, else double leftskip in narrower
+ \etoksapp\t_tabl_ntb
+ {% no need for init
+ \tabl_ntb_row_align_start
+ \the\t_tabl_ntb_row
+ \tabl_ntb_row_align_stop}}
+
+\def\tabl_ntb_row_stop_split
+ {\ifcsname\??naturaltableset\m_tabl_tbl_level:\c!y++\the\c_tabl_ntb_current_row\endcsname
+ \tabl_ntb_row_stop_split_yes
+ \else
+ \tabl_ntb_row_stop_split_nop
+ \fi}
+
+\def\tabl_ntb_row_stop_split_nop
+ {\etoksapp\t_tabl_ntb
+ {\tabl_ntb_row_align_reset
+ \tabl_ntb_row_align_start
+ \the\t_tabl_ntb_row
+ \tabl_ntb_row_align_stop}}
+
+\def\tabl_ntb_row_stop_split_yes
+ {\begingroup
+ \csname\??naturaltableset\m_tabl_tbl_level:\c!y++\the\c_tabl_ntb_current_row\endcsname
+ \xdef\m_tabl_ntb_before_split{\naturaltablelocalparameter\c!before}% to be checked
+ \xdef\m_tabl_ntb_after_split {\naturaltablelocalparameter\c!after}% to be checked
+ \xdef\m_tabl_ntb_same_page {\naturaltablelocalparameter\c!samepage}%
+ \endgroup
+ \etoksapp\t_tabl_ntb
+ {\tabl_ntb_row_align_set{\m_tabl_ntb_before_split}{\m_tabl_ntb_after_split}{\m_tabl_ntb_same_page}%
+ \tabl_ntb_row_align_start
+ \the\t_tabl_ntb_row
+ \tabl_ntb_row_align_stop}}
+
+\unexpanded\def\tabl_ntb_row_align_set#1#2#3%
+ {\xdef\m_tabl_ntb_before_split{#1}%
+ \xdef\m_tabl_ntb_after_split {#2}%
+ \xdef\m_tabl_ntb_same_page {#3}}
+
+\unexpanded\def\tabl_ntb_row_align_reset
+ {\glet\m_tabl_ntb_before_split\empty
+ \glet\m_tabl_ntb_after_split \empty
+ \glet\m_tabl_ntb_same_page \empty}
+
+\def\tabl_ntb_prelocate_error
+ {\writestatus\m!TABLE{fatal error: use \string\prelocateTBLrows\space to increase table memory (now: \the\c_tabl_prelocated_rows)}}
+
+% \prelocateTBLrows{1000} % may speed up large tables
+
+\def\prelocateTBLrows#1% we start at zero so we have one to much, better play safe anyway
+ {\dostepwiserecurse\c_tabl_prelocated_rows{#1}\plusone
+ {\expandafter\newtoks\csname\??naturaltabletok\recurselevel\endcsname}%
+ \def\tabl_ntb_row_start
+ {\ifnum\c_tabl_ntb_row<\c_tabl_prelocated_rows\relax
+ \tabl_ntb_prelocate_okay
+ \else
+ \tabl_ntb_prelocate_error
+ \fi}%
+ \def\tabl_ntb_row_stop
+ {\etoksapp\t_tabl_ntb
+ {\tabl_ntb_row_align_start
+ \the\csname\??naturaltabletok\the\c_tabl_ntb_row\endcsname
+ \tabl_ntb_row_align_stop}}%
+ \global\c_tabl_prelocated_rows#1\relax}
+
+\def\tabl_ntb_prelocate_okay
+ {\expandafter\let\expandafter\t_tabl_ntb_row\csname\??naturaltabletok\the\c_tabl_ntb_row\endcsname\t_tabl_ntb_row\emptytoks}
+
+%D We use aligments to handle the empty (skipped) columns, so that we don't have to
+%D (re|)|calculate these.
+
+\let\m_tabl_ntb_saved_row\!!zerocount
+\let\m_tabl_ntb_saved_col\!!zerocount
+
+\def\tabl_ntb_start_tagged
+ {\scratchcounter\numexpr\c_tabl_ntb_row+\plusone\relax
+ \ifnum\scratchcounter=\c_tabl_ntb_head
+ \ifconditional\c_tabl_ntb_okay
+ \dostoptagged
+ \else
+ \settrue\c_tabl_ntb_okay
+ \fi
+ \dostarttagged\t!tablehead\empty
+ \orelse\ifnum\scratchcounter=\c_tabl_ntb_body
+ \ifconditional\c_tabl_ntb_okay
+ \dostoptagged
+ \else
+ \settrue\c_tabl_ntb_okay
+ \fi
+ \dostarttagged\t!tablebody\empty
+ \orelse\ifnum\scratchcounter=\c_tabl_ntb_foot
+ \ifconditional\c_tabl_ntb_okay
+ \dostoptagged
+ \else
+ \settrue\c_tabl_ntb_okay
+ \fi
+ \dostarttagged\t!tablefoot\empty
+ \fi
+ \dostarttagged\t!tablerow\empty}
+
+\def\tabl_ntb_stop_tagged
+ {\dostoptagged
+ \ifconditional\c_tabl_ntb_okay
+ \scratchcounter\numexpr\c_tabl_ntb_row+\plustwo\relax
+ \ifnum\scratchcounter=\c_tabl_ntb_body
+ \dostoptagged
+ \setfalse\c_tabl_ntb_okay
+ \orelse\ifnum\scratchcounter=\c_tabl_ntb_foot
+ \dostoptagged
+ \setfalse\c_tabl_ntb_okay
+ \orelse\ifnum\scratchcounter>\c_tabl_ntb_maximum_row
+ \dostoptagged
+ \setfalse\c_tabl_ntb_okay
+ \fi
+ \fi}
+
+\unexpanded\def\tabl_ntb_row_align_start
+ {\global\advance\c_tabl_ntb_row\plusone
+ \global\c_tabl_ntb_col\plusone
+ \global\c_tabl_ntb_spn\zerocount
+ \tabl_ntb_row_align_start_inject
+ \ifconditional\c_strc_tags_enabled
+ \tabl_ntb_start_tagged
+ \fi
+ \hbox\bgroup
+ \kern\dimexpr\d_tabl_ntb_leftmargindistance\relax}
+
+\unexpanded\def\tabl_ntb_row_align_stop
+ {\kern\dimexpr\d_tabl_ntb_rightmargindistance-\d_tabl_ntb_columndistance\relax
+ \egroup
+ \ifconditional\c_strc_tags_enabled
+ \tabl_ntb_stop_tagged
+ \fi
+ \tabl_ntb_row_align_stop_inject}
+
+\unexpanded\def\tabl_ntb_before_page
+ {\ifx\m_tabl_ntb_same_page\v!before
+ % \blank[\v!samepage,\v!strong]%
+ \unpenalty
+ \nobreak
+ \orelse\ifx\m_tabl_ntb_same_page\v!both
+ % \blank[\v!samepage,\v!strong]%
+ \unpenalty
+ \nobreak
+ \fi}
+
+\unexpanded\def\tabl_ntb_after_page
+ {\ifnum\c_tabl_ntb_row>\c_tabl_ntb_n_of_head_lines
+ \ifnum\tabl_ntb_get_nob\c_tabl_ntb_row=\zerocount
+ \unpenalty
+ \ifx\m_tabl_ntb_same_page\v!after
+ % \blank[\v!samepage,\v!strong]%
+ \nobreak
+ \orelse\ifx\m_tabl_ntb_same_page\v!both
+ % \blank[\v!samepage,\v!strong]%
+ \nobreak
+ \else
+ % \blank[\v!preference,\v!weak]%
+ \allowbreak
+ \fi
+ \fi
+ \else
+ % \blank[\v!preference,\v!weak]%
+ \allowbreak % else no proper head split off
+ \fi}
+
+\unexpanded\def\tabl_ntb_inbetween
+ {\scratchcounter\numexpr\c_tabl_ntb_row+\plusone\relax
+ \ifnum\scratchcounter>\c_tabl_ntb_n_of_hdnx_lines\relax
+ \ifnum\scratchcounter<\c_tabl_ntb_maximum_row\relax
+ \edef\p_spaceinbetween{\naturaltablelocalparameter\c!spaceinbetween}%
+ \ifx\p_spaceinbetween\empty\else
+ \blank[\p_spaceinbetween]%
+ \fi
+ \fi
+ \fi}
+
+\unexpanded\def\tabl_ntb_row_align_start_inject
+ {\bgroup % protect local vars
+ \m_tabl_ntb_before_split
+ \egroup
+ \ifenableTBLbreak
+ \tabl_ntb_before_page
+ \fi}
+
+\unexpanded\def\tabl_ntb_row_align_stop_inject
+ {\par
+ \nointerlineskip
+ \ifenableTBLbreak
+ \tabl_ntb_after_page
+ \fi
+ \bgroup % protect local vars
+ \m_tabl_ntb_after_split
+ \egroup
+ \bgroup % protect local vars
+ \tabl_ntb_inbetween
+ \egroup}
+
+\def\tabl_ntb_flush_content
+ {\the\everyTABLEpass
+ \global\c_tabl_ntb_spn\zerocount
+ \global\c_tabl_ntb_col\zerocount
+ \global\c_tabl_ntb_row\zerocount
+ \global\advance\c_tabl_ntb_row\minusone
+ \dostarttaggedchained\t!table\empty\??naturaltable
+ %\registerparoptions % (*) triggers max hsize
+ \the\t_tabl_ntb
+ \dostoptagged}
+
+\unexpanded\def\tabl_ntb_span#1%
+ {\hskip\tabl_ntb_get_dis\c_tabl_ntb_col
+ \dorecurse{#1}
+ {\hskip\tabl_ntb_get_wid\c_tabl_ntb_col\relax
+ \global\advance\c_tabl_ntb_col\plusone}}
+
+\unexpanded\def\tabl_ntb_skip#1%
+ {\global\advance\c_tabl_ntb_col#1\relax}
+
+\unexpanded\def\tabl_ntb_plus
+ {\global\advance\c_tabl_ntb_col\plusone
+ \kern\d_tabl_ntb_columndistance}
+
+\setvalue{\??naturaltablecell\the\c_tabl_ntb_none}#1#2%
+ {\scratchcounter\tabl_ntb_get_col{#1}{#2}\relax
+ \ifnum\scratchcounter>\zerocount
+ \etoksapp\t_tabl_ntb_row
+ {\tabl_ntb_span{\the\scratchcounter}}%
+ \fi}
+
+\setvalue{\??naturaltablecell\the\c_tabl_ntb_cell}#1#2%
+ {\toksapp\t_tabl_ntb_row{\tabl_ntb_pass #1 #2 }% space delimited -> less tokens
+ \scratchcounter\tabl_ntb_get_col{#1}{#2}\relax
+ \ifnum\scratchcounter>\zerocount
+ \etoksapp\t_tabl_ntb_row
+ {\ifnum\scratchcounter=\plusone
+ \tabl_ntb_plus
+ \else
+ \tabl_ntb_skip{\the\scratchcounter}%
+ \fi}%
+ \fi}
+
+\unexpanded\def\tabl_ntb_cell#1#2%
+ {\csname\??naturaltablecell\the\tabl_ntb_get_tag{#1}{#2}\endcsname{#1}{#2}}
+
+\unexpanded\def\tabl_ntb_table_start
+ {\global\c_tabl_ntb_spn\zerocount
+ \global\c_tabl_ntb_row\zerocount
+ \global\c_tabl_ntb_col\zerocount
+ \c_tabl_tbl_pass\zerocount
+ \t_tabl_ntb\emptytoks}
+
+\def\tabl_ntb_pass_one#1 #2 %
+ {\tabl_ntb_get_txt{#1}{#2}}%
+
+\def\tabl_ntb_pass_two#1 #2 % meer in cellD
+ {\d_tabl_ntb_width\zeropoint
+ \scratchcounter\c_tabl_ntb_col
+ \!!counta\tabl_ntb_get_col{#1}{#2}\relax
+ \ifcase\!!counta\or
+ \advance\d_tabl_ntb_width\dimexpr
+ \tabl_ntb_get_wid\scratchcounter
+ \relax
+ \advance\scratchcounter\plusone
+ \else
+ \dorecurse\!!counta
+ {\advance\d_tabl_ntb_width\dimexpr
+ \tabl_ntb_get_wid\scratchcounter
+ \ifnum\recurselevel<\!!counta
+ +\d_tabl_ntb_columndistance
+ +\tabl_ntb_get_dis\scratchcounter
+ \fi
+ \relax
+ \advance\scratchcounter\plusone}%
+ \fi
+ \setbox\scratchbox\hbox{\tabl_ntb_get_txt{#1}{#2}}%
+ \tabl_ntb_set_ht{#1}{#2}{\the\ht\scratchbox}%
+ %tabl_ntb_set_wd{#1}{#2}{\the\wd\scratchbox}%
+ \ifdim\ht\scratchbox>\tabl_ntb_get_hei{#1}\relax
+ \tabl_ntb_set_hei{#1}{\the\ht\scratchbox}%
+ \fi}%
+
+\def\tabl_ntb_pass_three#1 #2 %
+ {% height
+ \dostarttagged\t!tablecell\empty
+ \!!counta \tabl_ntb_get_col{#1}{#2}\relax
+ \!!countb \tabl_ntb_get_row{#1}{#2}\relax
+ \!!heighta\tabl_ntb_get_ht {#1}{#2}\relax
+ \tablecellcolumns\!!counta % used later so don't adapt these
+ \tablecellrows \!!countb % used later so don't adapt these
+ \d_tabl_ntb_height\zeropoint
+ \ifnum\!!counta=\c_tabl_ntb_maximum_col\relax
+ % case: nc=maxcolumns
+ \else
+ \scratchcounter#1\relax
+ \dorecurse\!!countb
+ {\advance\d_tabl_ntb_height\tabl_ntb_get_hei\scratchcounter
+ \advance\scratchcounter\plusone}%
+ \ifdim\d_tabl_ntb_height<\!!heighta\relax
+ \d_tabl_ntb_height\!!heighta
+ \fi
+ \fi
+ % width
+ \d_tabl_ntb_width\zeropoint
+ \scratchcounter\c_tabl_ntb_col
+ \ifcase\!!counta\or
+ \advance\d_tabl_ntb_width\dimexpr
+ \tabl_ntb_get_wid\scratchcounter
+ \relax
+ \advance\scratchcounter\plusone
+ \else
+ \dorecurse\!!counta
+ {\advance\d_tabl_ntb_width\dimexpr
+ \tabl_ntb_get_wid\scratchcounter
+ \ifnum\recurselevel<\!!counta
+ +\d_tabl_ntb_columndistance
+ +\tabl_ntb_get_dis\scratchcounter
+ \fi
+ \relax
+ \advance\scratchcounter\plusone}%
+ \fi
+ % cell
+ \setbox\scratchbox\hbox attr \taggedattribute \attribute\taggedattribute \bgroup
+ \dotagTABLEsignal % maybe we need to add some packaging in this case
+ \tabl_ntb_get_txt{#1}{#2}%
+ \egroup
+ \ifnum\!!counta=\c_tabl_ntb_maximum_col\relax
+ % case: nc=maxcolumns
+ \else
+ \scratchdimen\tabl_ntb_get_hei{#1}%
+ \setbox\scratchbox\hpack
+ {\lower\ht\scratchbox\hpack{\raise\scratchdimen\box\scratchbox}}%
+ \ht\scratchbox\scratchdimen
+ \fi
+ \dp\scratchbox\zeropoint
+ \edef\!!stringa{\tabl_ntb_get_ref{#1}{#2}}%
+ \ifx\!!stringa\empty
+ \box\scratchbox
+ \else
+ \normalexpanded{\noexpand\directgotobox{\box\scratchbox}[\!!stringa]}% to be checked
+ \fi
+ \dostoptagged} % right spot
+
+% \def\tabl_ntb_cell_finalize
+% {\doifnotinset\localwidth{\v!fit,\v!broad}% user set
+% {\scratchdimen\tabl_ntb_get_aut\c_tabl_ntb_col\relax
+% \ifdim\localwidth>\scratchdimen
+% \tabl_ntb_set_aut\c_tabl_ntb_col{\the\dimexpr\localwidth}%
+% \fi}}
+
+\def\tabl_ntb_cell_finalize
+ {\ifx\localwidth\v!fit
+ % nothing
+ \orelse\ifx\localwidth\v!broad
+ % nothing
+ \orelse\ifx\localwidth\empty
+ % nothing (safeguard)
+ \else
+ \tabl_ntb_cell_finalize_indeed
+ \fi}
+
+\def\tabl_ntb_cell_finalize_indeed
+ {\scratchdimen\tabl_ntb_get_aut\c_tabl_ntb_col\relax
+ \ifdim\localwidth>\scratchdimen
+ \tabl_ntb_set_aut\c_tabl_ntb_col{\the\dimexpr\localwidth}%
+ \fi}
+
+\let\tabl_ntb_preroll\relax
+
+\def\tabl_ntb_table_get_max_width
+ {\scratchdimen\wd\scratchbox\relax}
+
+% enable dper 2018-02-22
+
+\def\tabl_ntb_table_get_max_width_step
+ {\advance\scratchdimen\tabl_ntb_get_wid\fastloopindex
+ \advance\scratchdimen\tabl_ntb_get_dis\fastloopindex}
+
+\def\tabl_ntb_table_get_max_width
+ {\scratchdimen\zeropoint
+ \dofastloopcs\c_tabl_ntb_maximum_col\tabl_ntb_table_get_max_width_step
+ \ifdim\scratchdimen<\wd\scratchbox\relax
+ \scratchdimen\wd\scratchbox\relax
+ \fi}
+
+\def\tabl_ntb_table_stop
+ {\forgetall % new, here see narrower-004.tex
+ %\setbox\scratchbox\hbox
+ % {\letnaturaltablelocalparameter\c!frame\v!off
+ % \letnaturaltablelocalparameter\c!background\empty
+ % \letnaturaltablelocalparameter\c!align\v!no
+ % \inheritednaturaltablelocalframed{\strut}}%
+ %\edef\minimalcellheight{\the\ht\scratchbox}% not used
+ \dorecurse\c_tabl_ntb_maximum_col
+ {\tabl_ntb_let_aut\recurselevel\zeropoint
+ % new
+ \c_tabl_ntb_current_col_one\recurselevel\relax
+ \dorecurse\c_tabl_ntb_maximum_row
+ {%tabl_ntb_let_wd\recurselevel\c_tabl_ntb_current_col_one\zeropoint
+ \tabl_ntb_let_ht\recurselevel\c_tabl_ntb_current_col_one\zeropoint}%
+ % till here
+ \tabl_ntb_let_tal\recurselevel\zerocount
+ \tabl_ntb_let_wid\recurselevel\zeropoint
+ \tabl_ntb_let_dis\recurselevel\zeropoint}%
+ \dorecurse\c_tabl_ntb_maximum_row
+ {\tabl_ntb_let_hei\recurselevel\maxdimen}%
+ \tabl_ntb_let_gal\zerocount
+ \tabl_ntb_preroll\relax
+ \c_tabl_tbl_pass\plusone
+ \let\tabl_ntb_pass\tabl_ntb_pass_one
+ \let\tabl_ntb_cell_process\tabl_ntb_cell_process_a
+ \setbox\scratchbox\vbox{\settrialtypesetting \tabl_ntb_flush_content}%
+ \ifcase\tabl_ntb_get_gal\or
+ % \c_tabl_tbl_pass\plusone
+ % \let\tabl_ntb_pass\tabl_ntb_pass_one
+ \let\tabl_ntb_cell_process\tabl_ntb_cell_process_a_extra
+ \setbox\scratchbox\vbox{\settrialtypesetting \tabl_ntb_flush_content}%
+ \fi
+ \tabl_ntb_let_dis\c_tabl_ntb_maximum_col\zeropoint
+ %
+ \tabl_ntb_table_get_max_width % \scratchdimen\scratchbox
+ %
+ \ifautoTBLspread
+ % experimental, stretch non fixed cells to \hsize
+ \tabl_ntb_check_widths_one % trial run
+ \tabl_ntb_check_widths_two % real run
+ \tabl_ntb_stretch_widths
+ \let\tabl_ntb_cell_process\tabl_ntb_cell_process_b
+ \setbox\scratchbox\vbox{\settrialtypesetting \tabl_ntb_flush_content}%
+ % \orelse\ifdim\wd\scratchbox>\hsize
+ \orelse\ifdim\scratchdimen>\hsize
+ \ifautoTBLhsize
+ \tabl_ntb_check_widths_one % trial run
+ \tabl_ntb_check_widths_two % real run
+ \let\tabl_ntb_cell_process\tabl_ntb_cell_process_b
+ \setbox\scratchbox\vbox{\settrialtypesetting \tabl_ntb_flush_content}%
+ \fi
+ \orelse\ifautoTBLrowspan
+ \ifnum\c_tabl_ntb_maximum_row_span>\plusone % max ?
+ % added jan 2002 because nx=* did no longer work
+ \ifnum\c_tabl_ntb_encountered_max<\c_tabl_ntb_maximum_col
+ % added jun 2014 because someone had less columns than nx .. sigh / see *nx*
+ \writestatus\m!TABLE{missing\space\number\numexpr\c_tabl_ntb_maximum_col-\c_tabl_ntb_encountered_max\relax\space column(s), guessing widths}%
+ \fi
+ \edef\savedhsize{\the\hsize}%
+ % \hsize\wd\scratchbox\relax % new per 17/04/2006
+ \hsize\scratchdimen\relax % new per 17/04/2006
+ \tabl_ntb_check_widths_one % trial run
+ \tabl_ntb_check_widths_two % real run
+ \hsize\savedhsize
+ \let\tabl_ntb_cell_process\tabl_ntb_cell_process_c
+ \setbox\scratchbox\vbox{\settrialtypesetting \tabl_ntb_flush_content}%
+ \fi
+ \fi
+ \let\tabl_ntb_cell_process\tabl_ntb_cell_process_d
+ \c_tabl_tbl_pass\plustwo
+ \let\tabl_ntb_pass\tabl_ntb_pass_two
+ \setbox\scratchbox\vbox{\settrialtypesetting \tabl_ntb_flush_content}%
+ \tabl_ntb_check_heights_one
+ \tabl_ntb_check_heights_two
+ \let\tabl_ntb_cell_process\tabl_ntb_cell_process_e
+ \c_tabl_tbl_pass\plusthree
+ \let\tabl_ntb_pass\tabl_ntb_pass_three
+ \ifnum\m_tabl_tbl_level>\plusone
+ \tabl_tbl_split_nop
+ \orelse\ifenableTBLbreak
+ \tabl_tbl_split_yes
+ \else
+ \tabl_tbl_split_nop
+ \fi}
+
+\def\tabl_ntb_stretch_widths % more variants, e.g. a max to \dimend
+ {\ifcase\c_tabl_ntb_maximum_col\else % else division by zero
+ \!!dimend\zeropoint
+ \!!dimene\dimexpr
+ \hsize
+ -\d_tabl_ntb_leftmargindistance
+ -\d_tabl_ntb_rightmargindistance
+ +\d_tabl_ntb_columndistance
+ \relax
+ \dorecurse\c_tabl_ntb_maximum_col
+ {\advance\!!dimend\dimexpr
+ \tabl_ntb_get_wid\recurselevel
+ \relax
+ \advance\!!dimene\dimexpr
+ -\tabl_ntb_get_dis\recurselevel
+ -\d_tabl_ntb_columndistance
+ \relax}%
+ \relax
+ % distribute width (stretch)
+ \ifdim\!!dimend<\!!dimene
+ \advance\!!dimend-\!!dimene
+ \divide\!!dimend\c_tabl_ntb_maximum_col
+ \dorecurse\c_tabl_ntb_maximum_col
+ {\tabl_ntb_set_wid\recurselevel{\the\dimexpr\tabl_ntb_get_wid\recurselevel-\!!dimend\relax}}%
+ \fi
+ \fi}
+
+\def\tabl_tbl_split_nop
+ {\setbox\b_tabl_ntb_final\vbox{\tabl_ntb_flush_content}%
+ \postprocessTABLEbox\b_tabl_ntb_final
+ \beforeTABLEbox
+ % packaging prevents max hsized box
+ % \hbox{\registerparoptions\box\b_tabl_ntb_final}% (*) better here
+ % better :
+ \ifinsidefloat
+ % no \dontleavehmode else too wide, otherwise we get a \hsized box
+ \else
+ \registerparoptions % (*) better here (also does a \dontleavehmode)
+ \ifhmode\else\dontleavehmode\fi
+ \fi
+ \box\b_tabl_ntb_final
+ \afterTABLEbox}
+
+\def\tabl_tbl_split_yes
+ {\ifinsidesplitfloat
+ \donetrue
+ \orelse\ifinsidefloat
+ \donefalse
+ \else
+ \donetrue
+ \fi
+ \ifdone
+ \expandafter\tabl_ntb_split_box
+ \else
+ \expandafter\tabl_tbl_split_nop
+ \fi}
+
+\newbox\TABLEsplitbox % public, don't change
+
+\let\extratblsplitheight\zeropoint % additional space taken by before/afterTABLEsplitbox
+
+\def\tabl_ntb_split_box
+ {\resettsplit
+ \def\tsplitminimumfreelines{2}%
+ \def\tsplitminimumfreespace{\dimexpr\extratblsplitheight+\naturaltablelocalparameter\c!splitoffset\relax}%
+ \def\tsplitbeforeresult {\beforeTABLEsplitbox}%
+ \def\tsplitafterresult {\afterTABLEsplitbox}%
+ \def\tsplitafter {\m_tabl_ntb_after_split}%
+ \def\tsplitbefore {\m_tabl_ntb_before_split}% supported ?
+ \setbox\tsplitcontent\vbox{\tabl_ntb_flush_content}%
+ \ifmultipleTBLheads
+ \dorecurse\c_tabl_ntb_n_of_head_lines
+ {\setbox\scratchbox\vsplit\tsplitcontent to \lineheight
+ \setbox\tsplithead\vbox{\unvcopy\tsplithead\unvcopy\scratchbox}}% \vpack ?
+ \dorecurse\c_tabl_ntb_n_of_next_lines
+ {\setbox\scratchbox\vsplit\tsplitcontent to \lineheight
+ \setbox\tsplitnext\vbox{\unvcopy\tsplitnext\unvcopy\scratchbox}}% \vpack ?
+ \fi
+ \edef\p_spaceinbetween{\naturaltablelocalparameter\c!spaceinbetween}%
+ \ifx\p_spaceinbetween\empty\else
+ \blank[\p_spaceinbetween]%
+ \fi
+ \def\postprocesstsplit{\postprocessTABLEsplitbox{\box\tsplitresult}}%
+ \handletsplit}
+
+% ! ! ! ! TODO: naast \postprocessTABLEsplitbox ook evt \postprocessTABLEbox voor niet split
+
+\let\postprocessTABLEsplitbox\gobbleoneargument
+\let\postprocessTABLEbox \gobbleoneargument
+
+\let\beforeTABLEsplitbox\relax
+\let\afterTABLEsplitbox \relax
+\let\beforeTABLEbox \relax
+\let\afterTABLEbox \relax
+
+\def\tabl_ntb_check_widths_one{\tabl_ntb_check_widths_indeed\zerocount} % 0 = trial run
+\def\tabl_ntb_check_widths_two{\tabl_ntb_check_widths_indeed\plusone } % 1 = real run
+
+\def\tabl_ntb_check_widths_indeed#1%
+ {\ifconditional\c_tabl_ntb_trace_widths\tabl_ntb_show_widths B#1\fi
+ \!!counta\zerocount
+ \!!dimena\dimexpr
+ \hsize
+ -\d_tabl_ntb_leftmargindistance
+ -\d_tabl_ntb_rightmargindistance
+ -\d_tabl_ntb_columndistance
+ \relax
+ \dorecurse\c_tabl_ntb_maximum_col
+ {\scratchdimen\tabl_ntb_get_aut\recurselevel\relax
+ \advance\!!dimena\dimexpr
+ -\tabl_ntb_get_dis\recurselevel
+ -\d_tabl_ntb_columndistance
+ \relax
+ \ifdim\scratchdimen>\zeropoint\relax
+ \advance\!!dimena -\scratchdimen
+ \else
+ \scratchdimen\tabl_ntb_get_wid\recurselevel\relax
+ \ifdim\scratchdimen>\d_tabl_ntb_maxwidth\relax
+ \ifcase#1\else\tabl_ntb_let_wid\recurselevel\zeropoint\fi
+ \advance\!!counta \plusone
+ \orelse\ifdim\scratchdimen>\zeropoint\relax
+ \advance\!!dimena -\scratchdimen
+ \else
+ % eigenlijk moet dit alleen als de kolom wordt overspannen door een
+ % vorige, maw extra dubbele loop en status var
+ \ifnum\c_tabl_ntb_encountered_max=\c_tabl_ntb_maximum_col % *nx* bah
+ \advance\!!counta \plusone % setting maxwidth to a large value also works
+ \fi
+ \fi
+ \fi}%
+ \ifconditional\c_tabl_ntb_trace_widths\tabl_ntb_show_widths M#1\fi
+ \ifcase\!!counta \else \divide\!!dimena \!!counta \fi
+ \dorecurse\c_tabl_ntb_maximum_col
+ {\scratchdimen\tabl_ntb_get_wid\recurselevel\relax
+ \ifcase#1\relax
+ \ifdim\scratchdimen<\!!dimena % take natural width
+ \tabl_ntb_set_aut\recurselevel{\the\scratchdimen}%
+ \fi
+ \else
+ \ifzeropt\scratchdimen % auto set width
+ \tabl_ntb_set_wid\recurselevel{\the\!!dimena}%
+ \fi
+ \fi}%
+ \ifconditional\c_tabl_ntb_trace_widths\tabl_ntb_show_widths E#1\fi}
+
+% todo: use scratchcounters, not !! ones
+
+\def\tabl_ntb_check_heights_one_indeed
+ {\!!countb\tabl_ntb_get_row\c_tabl_ntb_current_row_three\c_tabl_ntb_current_col_three\relax
+ % check row span
+ \ifnum\!!countb>\plusone
+ % current height in row
+ \dimen0=\tabl_ntb_get_ht\c_tabl_ntb_current_row_three\c_tabl_ntb_current_col_three
+ % find nearest height in row
+ \dimen2=\zeropoint
+ \dorecurse\c_tabl_ntb_maximum_col
+ {\ifnum\recurselevel=\c_tabl_ntb_current_col_three\else
+ \ifcsname\tabl_ntb_row_pattern\c_tabl_ntb_current_row_three\recurselevel\endcsname
+ \!!countc=\tabl_ntb_get_row\c_tabl_ntb_current_row_three\recurselevel\relax
+ \ifnum\!!countc=\plusone
+ \dimen4=\tabl_ntb_get_ht\c_tabl_ntb_current_row_three\recurselevel\relax
+ \ifdim\dimen2<\dimen4
+ \dimen2=\dimen4
+ \fi
+ \fi
+ \fi
+ \fi}%
+ \c_tabl_ntb_current_row_four\c_tabl_ntb_current_row_three
+ % calculate cummulative height
+ \dimen4=\dimen2
+ \!!countc\c_tabl_ntb_current_row_three
+ \advance\!!countc\minusone
+ \dorecurse\!!countb
+ {\ifnum\c_tabl_ntb_current_row_four=\c_tabl_ntb_current_row_three\else
+ \advance\dimen4 \tabl_ntb_get_hei\c_tabl_ntb_current_row_four
+ \fi
+ \ifnum\recurselevel=\!!countb\else
+ \tabl_ntb_set_nob\!!countc
+ \advance\!!countc\plusone
+ \fi
+ \advance\c_tabl_ntb_current_row_four\plusone}%
+ % distribute overshoot equally
+ \ifdim\dimen2>\zeropoint % new: test on natural-003
+ \ifdim\dimen4<\dimen0
+ \advance\dimen0 -\dimen4
+ \divide\dimen0 \!!countb
+ \c_tabl_ntb_current_row_four\c_tabl_ntb_current_row_three
+ \tabl_ntb_set_hei\c_tabl_ntb_current_row_three{\the\dimen2}%
+ \dorecurse\!!countb
+ {\dorecurse\c_tabl_ntb_maximum_col
+ {\ifnum\recurselevel=\c_tabl_ntb_current_col_three\else
+ \scratchdimen\dimexpr\tabl_ntb_get_ht\c_tabl_ntb_current_row_four\recurselevel+\dimen0\relax
+ \tabl_ntb_set_ht\c_tabl_ntb_current_row_four\recurselevel{\the\scratchdimen}%
+ \ifdim\tabl_ntb_get_hei\c_tabl_ntb_current_row_four<\scratchdimen
+ \tabl_ntb_set_hei\c_tabl_ntb_current_row_four{\the\scratchdimen}%
+ \fi
+ \fi}%
+ \advance\c_tabl_ntb_current_row_four\plusone}%
+ \orelse\ifdim\dimen4>\dimen0
+ \iftightTBLrowspan
+ \tabl_ntb_set_hei\c_tabl_ntb_current_row_three{\the\dimen2}%
+ \fi
+ \fi
+ \fi
+ \fi}
+
+\def\tabl_ntb_check_heights_one
+ {\dorecurse\c_tabl_ntb_maximum_row
+ {\c_tabl_ntb_current_row_three\recurselevel\relax
+ \dorecurse\c_tabl_ntb_maximum_col
+ {\c_tabl_ntb_current_col_three\recurselevel\relax
+ \ifcsname\tabl_ntb_row_pattern\c_tabl_ntb_current_row_three\c_tabl_ntb_current_col_three\endcsname
+ \tabl_ntb_check_heights_one_indeed
+ \fi}}}
+
+\def\tabl_ntb_check_heights_two
+ {}
+
+\def\tabl_ntb_show_widths#1#2%
+ {\begingroup
+ \scratchdimen\zeropoint
+ \dorecurse\c_tabl_ntb_maximum_col
+ {\advance\scratchdimen\tabl_ntb_get_wid\recurselevel\relax}%
+ \writestatus\m!TABLE{#1 \ifcase#2trial\else real\fi: hsize: \the\hsize, total: \the\scratchdimen}%
+ \dorecurse\c_tabl_ntb_maximum_col
+ {\writestatus\m!TABLE{\space\space\recurselevel: \the\dimexpr\tabl_ntb_get_wid\recurselevel}}%
+ \endgroup}
+
+\def\tabl_ntb_char_align % called often
+ {\edef\p_characteralign{\naturaltablelocalparameter\c!aligncharacter}%
+ \ifx\p_characteralign\v!yes
+ \ifcase\c_tabl_tbl_pass\or
+ \tabl_ntb_let_tal\currentTABLEcolumn\plusone
+ \tabl_ntb_let_gal\plusone
+ \fi
+ \expandafter\tabl_ntb_char_align_indeed
+ \else
+ \expandafter\gobbletwoarguments
+ \fi}
+
+\def\tabl_ntb_char_align_indeed#1#2% row column
+ {\ifcase\c_tabl_tbl_pass \or
+ \setcharacteralign{#2}{\naturaltablelocalparameter\c!alignmentcharacter}% we could store the character in tal
+ \fi
+ \typo_charalign_adapt_font
+ \signalcharacteralign{#2}{#1}}
+
+\unexpanded\def\tabl_ntb_cell_process_a_extra#1#2%
+ {\ifcase\tabl_ntb_get_tal{#2}\relax
+ \expandafter\tabl_ntb_cell_process_x
+ \else
+ \expandafter\tabl_ntb_cell_process_a
+ \fi{#1}{#2}}
+
+\unexpanded\def\tabl_ntb_cell_process_x#1#2[#3]#4%
+ {}
+
+% problem: when span doesn't break we can have a span that is the sum of cells but
+% still to small .. chicken egg problem ... for that we should also have a smallest
+% width run
+%
+% nilling the background makes a run upto 25% faster
+
+\def\tabl_ntb_cell_process_a_check_span_one
+ {\ifautosqueezeTBLspan
+ \edef\p_width{\naturaltablelocalparameter\c!width}%
+ \ifcsname\??naturaltablesqueeze\p_width\endcsname\lastnamedcs\else\donefalse\fi
+ \else
+ \donetrue
+ \fi
+ \ifdone % brr, 0
+ \ifnum\scratchcounter>\plusone
+ \tabl_ntb_set_spn\c_tabl_ntb_col
+ \fi
+ \fi}
+
+\let\tabl_ntb_cell_process_a_check_span_two_yes\relax
+
+\def\tabl_ntb_cell_process_a_check_span_two_nop
+ {\ifdim\tabl_ntb_get_wid\c_tabl_ntb_col<\wd\scratchbox
+ \tabl_ntb_set_wid\c_tabl_ntb_col{\the\wd\scratchbox}%
+ \fi}
+
+\unexpanded\def\tabl_ntb_cell_process_a#1#2[#3]#4% grouping added ! ! !
+ {\bgroup
+ \letnaturaltablelocalparameter\c!option\empty
+ \tabl_ntb_setup_cell{#1}{#2}%
+ \setupcurrentnaturaltablelocal[#3]%
+ \letnaturaltablelocalparameter\c!background\empty
+ \letnaturaltablelocalparameter\c!frame\v!off
+ \scratchcounter\tabl_ntb_get_col{#1}{#2}\relax
+ \setbox\scratchbox\hbox
+ {\scratchdimen\naturaltablelocalparameter\c!distance\relax
+ \ifdim\scratchdimen>\tabl_ntb_get_dis{#2}\relax
+ \tabl_ntb_set_dis{#2}{\the\scratchdimen}%
+ \fi
+ \anch_backgrounds_text_level_start
+ \inheritednaturaltablelocalframed{\tabl_ntb_cell_start\tabl_ntb_char_align{#1}{#2}#4\tabl_ntb_cell_stop\tabl_ntb_cell_finalize}%
+ \anch_backgrounds_text_level_stop
+ \ifcase\c_anch_backgrounds_text_count\else
+ \tabl_ntb_let_bck{#1}{#2}\c_anch_backgrounds_text_state
+ \fi
+ }%
+ \scratchdimen\tabl_ntb_get_wid\c_tabl_ntb_col\relax
+ \ifdim\wd\scratchbox>\scratchdimen
+ \ifsqueezeTBLspan
+ \tabl_ntb_cell_process_a_check_span_one
+ \fi
+ \tabl_ntb_spn_doifelse\c_tabl_ntb_col
+ \tabl_ntb_cell_process_a_check_span_two_yes
+ \tabl_ntb_cell_process_a_check_span_two_nop
+ \fi
+ \scratchcounter\numexpr\c_tabl_ntb_row+\plusone\relax
+ \scratchdimen\tabl_ntb_get_hei\scratchcounter\relax
+ \ifdim\ht\scratchbox<\scratchdimen
+ \tabl_ntb_set_hei\scratchcounter{\the\ht\scratchbox}% auto set
+ \fi
+ \tabl_ntb_set_ht{#1}{#2}{\the\ht\scratchbox}%
+ %tabl_ntb_set_wd{#1}{#2}{\the\wd\scratchbox}%
+ \ifautoTBLcheckwidth
+ \ifdim\wd\scratchbox<.75\hsize % fuzzy guess
+ \ifdim\ht\scratchbox>2\openlineheight % honor width since this
+ \scratchdimen\tabl_ntb_get_aut\c_tabl_ntb_col\relax % can be a figure or so
+ \ifzeropt\scratchdimen
+ % side effect: when width is set to 0pt,
+ % we can force a span that fits the sum of spans widths
+ \tabl_ntb_set_aut\c_tabl_ntb_col{\the\scratchdimen}%
+ \orelse\ifdim\wd\scratchbox>\scratchdimen
+ % unless span
+ \tabl_ntb_set_aut\c_tabl_ntb_col{\the\wd\scratchbox}%
+ % to be translated
+ \writestatus\m!TABLE{no auto width in (\number#1,\number#2)\space\the\wd\scratchbox/\the\hsize}%
+ \fi
+ \fi
+ \fi
+ \fi
+ \setbox\scratchboxone\emptyhbox
+ \wd\scratchboxone\wd\scratchbox
+ \ht\scratchboxone\ht\scratchbox
+ \dp\scratchboxone\dp\scratchbox
+ \box\scratchboxone
+ \egroup}
+
+\unexpanded\def\tabl_ntb_cell_process_b_c#1#2#3[#4]#5%
+ {\setbox\scratchbox\hbox
+ {\tabl_ntb_setup_cell{#2}{#3}%
+ \setupcurrentnaturaltablelocal[#4,#1]%
+ \letnaturaltablelocalparameter\c!background\empty
+ \letnaturaltablelocalparameter\c!frame\v!off
+ \inheritednaturaltablelocalframed{\tabl_ntb_cell_start#5\tabl_ntb_cell_stop}}%
+ \setbox2\emptyhbox % todo: \scratchboxtwo
+ \wd2\wd\scratchbox
+ \ht2\ht\scratchbox
+ \dp2\dp\scratchbox
+ \ifautoTBLrowspan
+ \scratchcounter\numexpr\c_tabl_ntb_row+\plusone\relax
+ \ifcsname\tabl_ntb_row_pattern\scratchcounter\c_tabl_ntb_col\endcsname
+ \scratchdimen\tabl_ntb_get_hei\scratchcounter\relax
+ \ifnum\tabl_ntb_get_row\scratchcounter\c_tabl_ntb_col>\plusone
+ \ifdim\ht\scratchbox>\scratchdimen
+ \ht2\dimexpr-\scratchdimen-\ht\scratchbox\relax
+ \fi
+ \fi
+ \fi
+ \fi
+ \box2 }
+
+\unexpanded\def\tabl_ntb_cell_process_b#1#2[#3]#4%
+ {\scratchdimen\tabl_ntb_get_aut\c_tabl_ntb_col\relax
+ \ifdim\scratchdimen>\zeropoint\relax
+ \else
+ \scratchdimen\tabl_ntb_get_wid\c_tabl_ntb_col\relax
+ \ifdim\scratchdimen>\zeropoint\relax
+ \ifnum\tabl_ntb_get_col{#1}{#2}=\c_tabl_ntb_maximum_col\relax
+ \scratchdimen\hsize
+ \fi
+ \fi
+ \fi
+ \normalexpanded{\tabl_ntb_cell_process_b_c{\ifdim\scratchdimen>\zeropoint \c!width=\the\scratchdimen\fi}}%
+ {#1}{#2}[#3]{\tabl_ntb_char_align{#1}{#2}#4}}
+
+\unexpanded\def\tabl_ntb_cell_process_c
+ {\tabl_ntb_cell_process_b_c{}}
+
+\unexpanded\def\tabl_ntb_cell_process_d#1#2[#3]#4%
+ {\tabl_ntb_setup_cell{#1}{#2}%
+ \bgroup
+ \setupcurrentnaturaltablelocal[#3]%
+ \letnaturaltablelocalparameter\c!background\empty
+ \letnaturaltablelocalparameter\c!frame\v!off
+ \setnaturaltablelocalparameter\c!width{\d_tabl_ntb_width}%
+ \inheritednaturaltablelocalframed{\tabl_ntb_cell_start\tabl_ntb_char_align{#1}{#2}#4\tabl_ntb_cell_stop}%
+ \egroup}
+
+\unexpanded\def\tabl_ntb_cell_process_e#1#2[#3]#4%
+ {\tabl_ntb_setup_cell{#1}{#2}%
+ \setupcurrentnaturaltablelocal[#3]% to get the color right, the way we
+ \color % handle color here prevents interference due to whatsit nodes
+ [\naturaltablelocalparameter\c!color] % as well as permits local colors to take precedence
+ {\letnaturaltablelocalparameter\c!color\empty
+ \setnaturaltablelocalparameter\c!width{\d_tabl_ntb_width}%
+ \ifzeropt\d_tabl_ntb_height % case: nc=maxcolumns
+ \else
+ \setnaturaltablelocalparameter\c!height{\d_tabl_ntb_height}%
+ \fi
+ \ifcase\c_anch_backgrounds_text_count\else
+ \edef\p_region{\naturaltablelocalparameter\c!region}%
+ \ifx\p_region\empty\ifnum\tabl_ntb_get_bck{#1}{#2}>\zerocount
+ \letnaturaltablelocalparameter\c!region\v!yes
+ \fi\fi
+ \fi
+ \inheritednaturaltablelocalframed{\tabl_ntb_cell_start\tabl_ntb_char_align{#1}{#2}#4\tabl_ntb_cell_stop}}%
+ \hskip\tabl_ntb_get_dis{#2}}
+
+\newtoks\everyresetTABLEyes
+\newtoks\everyresetTABLEnop
+
+\appendtoks
+ \setupTABLE [%
+ %
+ % framed defaults
+ %
+ \c!width=\v!fit,%
+ \c!height=\v!fit,%
+ \c!lines=,%
+ \c!offset=.25\exheight,%
+ \c!empty=\v!no,%
+ \c!frame=\v!on,%
+ \c!topframe=,%
+ \c!bottomframe=,%
+ \c!leftframe=,%
+ \c!rightframe=,%
+ \c!radius=.5\bodyfontsize,%
+ \c!rulethickness=\linewidth,%
+ \c!corner=\v!rectangular,%
+ \c!depth=\zeropoint,%
+ \c!foregroundcolor=,%
+ \c!foregroundstyle=,%
+ \c!background=,%
+ \c!backgroundcolor=,%
+ \c!backgroundoffset=\v!frame,%
+ \c!framecolor=,%
+ \c!frameoffset=.5\linewidth,%
+ % \c!backgroundcorner=\framedparameter\c!corner,%
+ % \c!backgrounddepth=\framedparameter\c!depth,%
+ % \c!backgroundradius=\framedparameter\c!radius,%
+ % \c!framecorner=\framedparameter\c!corner,%
+ % \c!framedepth=\framedparameter\c!depth,%
+ % \c!frameradius=\framedparameter\c!radius,%
+ \c!component=,%
+ \c!region=,%
+ \c!align=,%
+ \c!bottom=\vss,%
+ \c!top=,%
+ \c!strut=\v!yes,%
+ \c!autostrut=\v!no,%
+ \c!location=\v!normal,%
+ \c!orientation=,%
+ \c!autowidth=\v!yes,%
+ \c!setups=,%
+ \c!loffset=\zeropoint,%
+ \c!roffset=\zeropoint,%
+ \c!toffset=\zeropoint,%
+ \c!boffset=\zeropoint,%
+ %
+ % table specific
+ %
+ \c!aligncharacter=\v!no,%
+ \c!alignmentcharacter={,},%
+ \c!color=,%
+ \c!columndistance=\zeropoint,% each column (whole table)
+ \c!distance=\zeropoint,% individual column
+ \c!headcolor=,%
+ \c!header=,%
+ \c!headstyle=\v!bold,%
+ \c!left=,%
+ \c!leftmargindistance=\zeropoint,% whole table
+ \c!maxwidth=8\emwidth,%
+ \c!option=,% \v!stretch
+ \c!right=,%
+ \c!rightmargindistance=\zeropoint,% whole table
+ \c!spaceinbetween=,%
+ \c!split=\v!auto,%
+ \c!splitoffset=\zeropoint,%
+ \c!style=,%
+ \c!textwidth=\v!local,% was \hsize
+ ]%
+\to \everyresetTABLEyes
+
+\appendtoks
+ \setupTABLE [%
+ \c!width=\v!fit,%
+ \c!height=\v!fit%
+ ]%
+\to \everyresetTABLEnop
+
+\the\everyresetTABLEyes
+
+% \bgroup
+% \setupTABLE[column][1][aligncharacter=yes, alignmentcharacter={,}]
+% \bTABLE
+% \bTR \bTD 1,2 \eTD \bTD 2 \eTD \eTR
+% \bTR \bTD 11,2 \eTD \bTD
+% {\setupTABLE[column][1][aligncharacter=yes, alignmentcharacter={,}]
+% \bTABLE
+% \bTR \bTD 1,2 \eTD \bTD 2 \eTD \eTR
+% \bTR \bTD 11,22 \eTD \bTD 2 \eTD \eTR
+% \bTR \bTD 11,2 \eTD \bTD 2 \eTD \eTR \eTABLE} \eTD \eTR
+% \bTR \bTD 11,22 \eTD \bTD 2 \eTD \eTR
+% \eTABLE
+% \egroup
+
+\newconditional\resetTABLEmode \settrue\resetTABLEmode
+
+\def\tabl_ntb_parameters_reset % we can use setters instead
+ {\ifnum\m_tabl_tbl_level>\plusone % in ieder geval
+ \ifconditional\resetTABLEmode
+ \the\everyresetTABLEyes
+ \else
+ \the\everyresetTABLEnop
+ \fi
+ \fi}
+
+% new (for Olivier Turlier)
+%
+% \defineTABLEsetup [xx] [foregroundcolor=red]
+%
+% \bTABLE
+% \bTR \bTD oeps \eTD \bTD oeps \eTD \eTR
+% \bTR \bTDs[xx] oeps \eTDs \bTD oeps \eTD \eTR
+% \bTRs[xx] \bTD oeps \eTD \bTD oeps \eTD \eTRs
+% \eTABLE
+
+\installcorenamespace{naturaltablesetup}
+
+\unexpanded\def\defineTABLEsetup
+ {\dodoubleargument\tabl_ntb_define_setup}
+
+\def\tabl_ntb_define_setup[#1][#2]%
+ {\setvalue{\??naturaltablesetup#1}{#2}}
+
+\let\eTDs\relax
+\let\eTRs\relax
+
+\unexpanded\def\bTDs[#1]#2\eTDs
+ {\normalexpanded{\bTD[\begincsname\??naturaltablesetup#1\endcsname]}#2\eTD}
+
+\unexpanded\def\bTRs[#1]#2\eTRs
+ {\normalexpanded{\bTR[\begincsname\??naturaltablesetup#1\endcsname]}#2\eTR}
+
+\protect \endinput
+
+% todo: mode: first|next (of niets)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/tabl-tab.mkiv b/Master/texmf-dist/tex/context/base/mkiv/tabl-tab.mkiv
index 631f29bc084..3799964c9f8 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/tabl-tab.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/tabl-tab.mkiv
@@ -666,7 +666,7 @@
\ifx\tempstring\empty
\!taDimenC\zeropoint
\else
- \setbox\scratchbox=\hbox{\mathsurround\zeropoint #1.#3#1}%
+ \setbox\scratchbox\hbox{\mathsurround\zeropoint #1.#3#1}%
\!taDimenC\wd\scratchbox
\fi
\setbox\scratchbox\hbox{\mathsurround\zeropoint #1#2#1}%
@@ -864,8 +864,13 @@
\lineskip \zeropoint
\tabskip \zeropoint
\edef\p_tabl_table_textwidth{\directtablesparameter\c!textwidth}%
- \halign \ifx\p_tabl_table_textwidth\empty \else to \ifx\p_tabl_table_textwidth\v!max \hsize \else \p_tabl_table_textwidth \fi\fi
-% \the\!taTableSpread
+ % we are not in sync so:
+ \synchronizedisplaydirection
+ \synchronizeinlinedirection
+ \halign
+ \usedirectionparameterreverse\directtablesparameter
+ \ifx\p_tabl_table_textwidth\empty \else to \ifx\p_tabl_table_textwidth\v!max \hsize \else \p_tabl_table_textwidth \fi\fi
+ %\the\!taTableSpread
\bgroup
\span
\the\!taPreamble
diff --git a/Master/texmf-dist/tex/context/base/mkiv/tabl-tbl.mkiv b/Master/texmf-dist/tex/context/base/mkiv/tabl-tbl.mkiv
index f3c2e2e105a..6e87d186383 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/tabl-tbl.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/tabl-tbl.mkiv
@@ -17,17 +17,15 @@
\registerctxluafile{tabl-tbl}{} % experiment
-%D I can probably reimplement this using a \LUATEX\ combination
-%D but it does not pay of in development time. If I need something
-%D else I will write it from scratch anyway. This module looks
-%D a bit complex which is a consequence of it dealing with paragraphs
-%D being split over pages and that there are several passes over the
-%D data set. We can probably do some cleanup (combine/split).
+%D I can probably reimplement this using a \LUATEX\ combination but it does not pay
+%D of in development time. If I need something else I will write it from scratch
+%D anyway. This module looks a bit complex which is a consequence of it dealing with
+%D paragraphs being split over pages and that there are several passes over the data
+%D set. We can probably do some cleanup (combine/split).
%D
-%D Caching the preamble does not save much (compared to other
-%D bits and pieces of \CONTEXT). There are not that many ways to
-%D deal with preambles and this is just one of them. The keys are
-%D somewhat similar to those of the \TABLE\ package.
+%D Caching the preamble does not save much (compared to other bits and pieces of
+%D \CONTEXT). There are not that many ways to deal with preambles and this is just
+%D one of them. The keys are somewhat similar to those of the \TABLE\ package.
% |p2|p3| 2:3 -> spanning (maybe)
%
@@ -579,15 +577,17 @@
\installtabulatepreambleoption{ }{\tabl_tabulate_set_preamble}
\installtabulatepreambleoption{A}{\tabl_tabulate_set_alignment}
-% We no longer deal with '~' here but map it onto 'd' instead. Of course
-% we could prefix a key with \type {\meaning} instead, which works ok (and
-% is needed in order to pseudo expand \type {\next}, but is ugly at the
-% same time. The 'd' stands for digitspace.
-%
-% \installtabulatepreambleoption{~}{...} % see 'd'
-%
-% Also, as there is always a key, we no longer do some after assigment or
-% future let but just pick up the key.
+%D We no longer deal with \type {~} here but map it onto \type {d} instead. Of
+%D course we could prefix a key with \type {\meaning} instead, which works ok (and
+%D is needed in order to pseudo expand \type {\next}, but is ugly at the same time.
+%D The type {d} stands for digitspace.
+
+%D \starttyping
+%D \installtabulatepreambleoption{~}{...} % see 'd'
+%D \stoptyping
+%D
+%D Also, as there is always a key, we no longer do some after assigment or future
+%D let but just pick up the key.
% \installtabulatepreambleoption \s!unknown %
% {\writestatus{tabulate}{unknown preamble key [\normalmeaning\next]}%
@@ -909,7 +909,7 @@
\let\tabl_tabulate_hook\tabl_tabulate_hook_nop
-\def\tabl_tabulate_hook_yes{\csname\??tabulatehook\the\c_tabl_tabulate_column\endcsname}
+\def\tabl_tabulate_hook_yes{\begincsname\??tabulatehook\the\c_tabl_tabulate_column\endcsname}
\def\tabl_tabulate_pheight_reset
{\global\c_tabl_tabulate_plines_min\plusone
@@ -976,9 +976,8 @@
%D
%D \typebuffer {\tracetabulatetrue\getbuffer}
-%D As we want to be compatible we use an indirect way to
-%D implement the definers. The next examples demonstrate
-%D the difference:
+%D Because we want to be compatible we use an indirect way to implement the
+%D definers. The next examples demonstrate the difference:
%D
%D \starttyping
%D \definetabulate[test][|l|c|r|]
@@ -1090,12 +1089,12 @@
\def\tabl_tabulate_insert_head_content
{\tabulatenoalign{\global\settrue\c_tabl_tabulate_someamble}%
- \csname\??tabulatehead\currenttabulation\endcsname
+ \begincsname\??tabulatehead\currenttabulation\endcsname
\tabulatenoalign{\global\setfalse\c_tabl_tabulate_someamble}}%
\def\tabl_tabulate_insert_foot_content
{\tabulatenoalign{\global\settrue\c_tabl_tabulate_someamble}%
- \csname\??tabulatefoot\currenttabulation\endcsname
+ \begincsname\??tabulatefoot\currenttabulation\endcsname
\tabulatenoalign{\global\setfalse\c_tabl_tabulate_someamble}}%
\def\tabl_tabulate_check_full_content % - needed, else confusion with \c!header
@@ -1151,15 +1150,6 @@
\def\tabl_tabulate_start_head_nop{\tabl_tabulate_start_head_yes[\v!tabulate]}
\def\tabl_tabulate_start_foot_nop{\tabl_tabulate_start_foot_yes[\v!tabulate]}
-% \def\tabl_tabulate_start_head_nop{\tabl_tabulate_start_head_yes[]}
-% \def\tabl_tabulate_start_foot_nop{\tabl_tabulate_start_foot_yes[]}
-
-% \unexpanded\def\tabl_start_defined[#1]%
-% {\bgroup
-% \edef\currenttabulationparent{#1}%
-% \let\currenttabulation\currenttabulationparent
-% \dodoubleargument\tabl_start_defined_indeed}
-
\unexpanded\def\tabl_start_defined[#1]%
{\bgroup
\edef\currenttabulationparent{#1}%
@@ -1185,9 +1175,11 @@
\fi}
\def\tabl_start_defined_one[#1][#2]%
- {\doifelseassignment{#1}
- {\setuptabulation[\currenttabulation][#1]}%
- {\edef\currenttabulation{\currenttabulation:#1}}%
+ {\ifcondition\validassignment{#1}%
+ \setuptabulation[\currenttabulation][#1]%
+ \else
+ \edef\currenttabulation{\currenttabulation:#1}%
+ \fi
\tabl_tabulate_start_building}
\def\tabl_start_defined_two[#1][#2]%
@@ -1216,14 +1208,16 @@
\def\tabl_default_format{|l|p|}
\def\tabl_start_regular_one[#1][#2]%
- {\doifelseassignment{#1}
- {\lettabulationparameter\c!format\tabl_default_format
- \setupcurrenttabulation[#1]}
- {\def\p_format{#1}%
- \ifx\p_format\empty
- \def\p_format{|l|p|}%
- \fi
- \lettabulationparameter\c!format\p_format}%
+ {\ifcondition\validassignment{#1}%
+ \lettabulationparameter\c!format\tabl_default_format
+ \setupcurrenttabulation[#1]%
+ \else
+ \def\p_format{#1}%
+ \ifx\p_format\empty
+ \def\p_format{|l|p|}%
+ \fi
+ \lettabulationparameter\c!format\p_format
+ \fi
\tabl_tabulate_start_building}
\def\tabl_start_regular_two[#1][#2]%
@@ -1364,7 +1358,7 @@
\fi
%
\settrue\c_tabl_tabulate_split
- \csname\??tabulatesplit\tabulationparameter\c!split\endcsname
+ \begincsname\??tabulatesplit\tabulationparameter\c!split\endcsname
%
\let\m_tabl_tabulate_blank_default\p_blank
%
@@ -1479,15 +1473,6 @@
% normal columns:
-% \def\tabl_tabulate_column_normal#1#2%
-% {\unskip
-% \aligntab
-% \ifconditional\c_tabl_tabulate_equal\tabulateequalpos\else\tabulatenormalpos\fi
-% \aligntab
-% \global\c_tabl_tabulate_kind#1%
-% \global\c_tabl_tabulate_type#2%
-% \aligntab}
-
\def\tabl_tabulate_column_normal#1#2%
{\unskip
\aligntab
@@ -1834,9 +1819,8 @@
\def\tabl_tabulate_digits{\digits}
-%D Beware, we cannot use \type {\unexpanded} on \type {\HL}
-%D cum suis, since \TEX's hard coded noalign lookahead fails
-%D on it! I mistakenly added this for a while.
+%D Beware, we cannot use \type {\unexpanded} on \type {\HL} cum suis, since \TEX's
+%D hard coded noalign lookahead fails on it! I mistakenly added this for a while.
\setvalue{\??tabulatealigning\v!normal}{0}
\setvalue{\??tabulatealigning\v!right }{1}
@@ -1877,27 +1861,6 @@
\installcorenamespace{tabulatenobreak}
-% \def\tabl_tabulate_break_state_set
-% {%\writestatus{SET}{\the\c_tabl_tabulate_noflines}%
-% \expandafter\glet\csname\??tabulatenobreak\the\c_tabl_tabulate_noflines\endcsname\conditionaltrue}
-%
-% \def\tabl_tabulate_break_state_reset
-% {\ifcsname\??tabulatenobreak\the\c_tabl_tabulate_noflines\endcsname
-% %\writestatus{RESET}{\the\c_tabl_tabulate_noflines}%
-% \expandafter\glet\csname\??tabulatenobreak\the\c_tabl_tabulate_noflines\endcsname\undefined
-% \fi}
-%
-% \def\tabl_tabulate_break_state_allowbreak
-% {\ifcsname\??tabulatenobreak\the\c_tabl_tabulate_noflines\endcsname
-% %\writestatus{TRUE}{\the\c_tabl_tabulate_noflines}%
-% \else
-% %\writestatus{FALSE}{\the\c_tabl_tabulate_noflines}%
-% \tabl_tabulate_break_allow % needed with pbreak prevention
-% \fi}
-%
-% \let\tabl_tabulate_break_allow\allowbreak
-% \let\tabl_tabulate_break_no \nobreak
-
\def\tabl_tabulate_break_allow{\directvpenalty\zerocount}
\def\tabl_tabulate_break_maybe{\directvpenalty\zerocount}
\def\tabl_tabulate_break_no {\directvpenalty\plustenthousand} % ,order:2}}
@@ -1916,11 +1879,6 @@
\unexpanded\def\tabl_tabulate_RQ_first{\tabl_tabulate_column_equal \zerocount\plusone}
\unexpanded\def\tabl_tabulate_HQ_first{\tabl_tabulate_column_equal \zerocount\plustwo}
-%unexpanded\def\tabl_tabulate_NG_first{\NC\tabl_tabulate_charalign}
-%unexpanded\def\tabl_tabulate_NG_first{\NC}
-%unexpanded\def\tabl_tabulate_NN_first{\NC\tabl_tabulate_digits} % new, undocumented, test first
-%unexpanded\def\tabl_tabulate_ND_first{\NC\tabl_tabulate_digits} % same, for old times sake
-
\unexpanded\def\tabl_tabulate_NG_first{\tabl_tabulate_column_normal\zerocount\zerocount}
\unexpanded\def\tabl_tabulate_NN_first{\tabl_tabulate_column_normal\zerocount\zerocount\tabl_tabulate_digits} % new, undocumented, test first
\unexpanded\def\tabl_tabulate_ND_first{\tabl_tabulate_column_normal\zerocount\zerocount\tabl_tabulate_digits} % same, for old times sake
@@ -1967,8 +1925,6 @@
%D The following shortcut is handy for tables where one needs bold headers:
-%unexpanded\def\tabl_tabulate_BC_first{\NC\let\fontstyle\globalfontstyle\bf}
-
\unexpanded\def\tabl_tabulate_BC_first
{\tabl_tabulate_column_normal\plusone\zerocount
\let\fontstyle\globalfontstyle
@@ -2155,15 +2111,6 @@
\tabl_tabulate_nobreak_inject
\stoptabulatenoalign}
-% \unexpanded\def\tabl_tabulate_ML_second_indeed
-% {\tabl_tabulate_column_rule_separator_inject
-% \tabl_tabulate_hrule_inject
-% \vskip-\p_rulethickness\relax
-% \tabl_tabulate_hrule_inject
-% \tabl_tabulate_break_no
-% \tabl_tabulate_column_rule_separator_inject
-% \stoptabulatenoalign}
-
\def\spac_vspacing_no_topskip % use grouped
{\attribute\skipcategoryattribute\plusten}
@@ -2286,13 +2233,12 @@
\def\tabulateautorule{\HR}%
\def\tabulateautoline{\HL} % no longer different (to be looked into)
-% When support for vertical rules we needed a way to pick up the
-% specification for the final rule and a \type {|{}} interface was
-% chosen. As a result parsing had to become more complex and I was
-% not in the mood for messing up the code too much. Therefore from
-% now on the preamble is split by \LUA. There are definitely more
-% places where we can use \LUA\ code (for instance in alignment of
-% numbers. The repeat parser is replace at the \LUA\ end as well.
+%D When support for vertical rules we needed a way to pick up the specification for
+%D the final rule and a \type {|{}} interface was chosen. As a result parsing had to
+%D become more complex and I was not in the mood for messing up the code too much.
+%D Therefore from now on the preamble is split by \LUA. There are definitely more
+%D places where we can use \LUA\ code (for instance in alignment of numbers. The
+%D repeat parser is replace at the \LUA\ end as well.
\let\tabl_tabulate_flush_collected \empty
\let\tabl_tabulate_flush_collected_indeed\empty
@@ -2314,7 +2260,7 @@
\def\tabl_tabulate_process
{\c_tabl_tabulate_pass\plusone
\tabl_tabulate_check_full_content
- \edef\v_tabl_tabulate_align{\executeifdefined{\??tabulatealigning\p_align}0}%
+ \edef\v_tabl_tabulate_align{\ifcsname\??tabulatealigning\p_align\endcsname\lastnamedcs\else0\fi}%
\s_tabl_tabulate_first.5\d_tabl_tabulate_unit
\s_tabl_tabulate_last\s_tabl_tabulate_first
\s_tabl_tabulate_pre\zeropoint
@@ -2336,11 +2282,16 @@
\else
\donetrue
\fi\fi
- \ifdone
- \global\c_tabl_tabulate_repeathead\executeifdefined{\??tabulateheader\tabulationparameter\c!header}\zerocount
- \else
- \global\c_tabl_tabulate_repeathead\zerocount
- \fi
+ \global\c_tabl_tabulate_repeathead
+ \ifdone
+ \ifcsname\??tabulateheader\tabulationparameter\c!header\endcsname
+ \lastnamedcs
+ \else
+ \zerocount
+ \fi
+ \else
+ \zerocount
+ \fi
%
\the\t_tabl_tabulate_initializers_first % collect more here
%
@@ -2349,7 +2300,6 @@
\t_tabl_tabulate_preamble
{\aligntab
\tabl_tabulate_flush_indent
-% \global\advance\c_tabl_tabulate_noflines\plusone
\strut
\alignmark\alignmark
\tabskip\d_tabl_tabulate_margin
@@ -2361,7 +2311,6 @@
\t_tabl_tabulate_preamble
{\aligntab
\tabl_tabulate_flush_indent
-% \global\advance\c_tabl_tabulate_noflines\plusone
\strut
\alignmark\alignmark
\aligntab
@@ -2375,7 +2324,6 @@
\c_tabl_tabulate_has_rule_spec_last \zerocount
\clf_presettabulate{\detokenizedtabulationparameter\c!format}%
%
- % \edef\totaltabulatecolumns{\the\numexpr3*\c_tabl_tabulate_columns+\plusfour}%
\d_tabl_tabulate_width\zeropoint
\tabl_tabulate_initialize_boxes\c_tabl_tabulate_columns
\toksapp\t_tabl_tabulate_preamble{%
@@ -2404,12 +2352,12 @@
{\notesenabledfalse
\d_tabl_tabulate_indent\zeropoint
\settrialtypesetting % very important
-\anch_backgrounds_text_level_start
+ \anch_backgrounds_text_level_start
\expandafter\halign\expandafter{\the\t_tabl_tabulate_preamble\crcr\tabl_tabulate_insert_content\crcr}}%
-\anch_backgrounds_text_level_stop
-\ifcase\c_anch_backgrounds_text_state\else
- \global\settrue\tablehaspositions
-\fi
+ \anch_backgrounds_text_level_stop
+ \ifcase\c_anch_backgrounds_text_state\else
+ \global\settrue\tablehaspositions
+ \fi
\ifnum\c_tabl_tabulate_nofauto>\zerocount
% so, even if the natural size is larger, in the final run, we force the calculated width
\d_tabl_tabulate_width\dimexpr\hsize-\wd\scratchbox-\d_tabl_tabulate_width_p-\d_tabl_tabulate_width_w\relax
@@ -2449,12 +2397,20 @@
\dostarttaggedchained\t!tabulate\empty\??tabulation
\dostarttagged\t!tabulaterow\empty
\setfalse\inhibitmargindata % new per 2012.06.13 ... really needed
- % \everycr\expandafter{\the\everycr\noalign{\the\t_tabl_tabulate_every_real_row}\dostoptagged\dostarttagged\t!tabulaterow\empty}%
- \toksapp\everycr{\noalign{\the\t_tabl_tabulate_every_real_row}\dostoptagged\dostarttagged\t!tabulaterow\empty}%
- \expandafter\halign\expandafter{\the\t_tabl_tabulate_preamble\crcr\tabl_tabulate_insert_content\crcr}%
+ \toksapp\everycr{%
+ \noalign{\the\t_tabl_tabulate_every_real_row}%
+ \dostoptagged
+ \dostarttagged\t!tabulaterow\empty
+ }%
+ % we are in sync but just to be sure:
+ \synchronizedisplaydirection
+ \synchronizeinlinedirection
+ \halign
+ \usedirectionparameterreverse\tabulateparameter
+ \expandafter{\the\t_tabl_tabulate_preamble\crcr\tabl_tabulate_insert_content\crcr}%
\dostoptagged
\dostoptagged
- \ifhmode\par\prevdepth\strutdp\fi % nog eens beter, temporary hack
+ \ifhmode\par\prevdepth\strutdp\fi % temporary hack
\ifx\p_distance\v!grid
\vskip-\strutdp % experimental tm-prikkels
\fi
@@ -2731,9 +2687,9 @@
%D \stopwhatever
%D \stoptyping
-%D This is needed because we sometimes use the english command in
-%D tracing macros. In fact, most detailed tracing macros that
-%D are done with \LUA\ only work in the english interface anyway.
+%D This is needed because we sometimes use the english command in tracing macros. In
+%D fact, most detailed tracing macros that are done with \LUA\ only work in the
+%D english interface anyway.
% \definetabulate[tabulate] \setuptabulate[tabulate][\c!format=\v!none] % so no \v! here
@@ -3043,16 +2999,16 @@
\ignorespaces}
\appendtoks
- \let\NL\tabl_tabulate_NL_first % NC with Line
- \let\ND\tabl_tabulate_ND_first % NC with Default Line
- \let\LB\tabl_tabulate_LB_first % BC with Line
- \let\DB\tabl_tabulate_DB_first % BC with Default Line
- \let\NF\tabl_tabulate_NF_first % NC with Filler
- \let\NP\tabl_tabulate_NP_first % NC with Predefined Filler
- \let\FB\tabl_tabulate_FB_first % BC with Filler
- \let\PB\tabl_tabulate_PB_first % BC with Predefined Filler
- \let\NA\tabl_tabulate_NA_first % NC with Auto Line
- \let\BA\tabl_tabulate_BA_first % NC with Auto Line
+ \let\NL\tabl_tabulate_NL_first % NC with Line
+ \let\ND\tabl_tabulate_ND_first % NC with Default Line
+ \let\LB\tabl_tabulate_LB_first % BC with Line
+ \let\DB\tabl_tabulate_DB_first % BC with Default Line
+ \let\NF\tabl_tabulate_NF_first % NC with Filler
+ \let\NP\tabl_tabulate_NP_first % NC with Predefined Filler
+ \let\FB\tabl_tabulate_FB_first % BC with Filler
+ \let\PB\tabl_tabulate_PB_first % BC with Predefined Filler
+ \let\NA\tabl_tabulate_NA_first % NC with Auto Line
+ \let\BA\tabl_tabulate_BA_first % NC with Auto Line
\to \t_tabl_tabulate_initializers_first
\appendtoks
diff --git a/Master/texmf-dist/tex/context/base/mkiv/tabl-tbl.mkxl b/Master/texmf-dist/tex/context/base/mkiv/tabl-tbl.mkxl
new file mode 100644
index 00000000000..dc8ae0214c4
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/tabl-tbl.mkxl
@@ -0,0 +1,3022 @@
+%D \module
+%D [ file=core-tbl,
+%D version=1998.11.03,
+%D title=\CONTEXT\ Table Macros,
+%D subtitle=Text Flow Tabulation,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Table Macros / Tabulation}
+
+\unprotect
+
+\registerctxluafile{tabl-tbl}{} % experiment
+
+%D I can probably reimplement this using a \LUATEX\ combination but it does not pay
+%D of in development time. If I need something else I will write it from scratch
+%D anyway. This module looks a bit complex which is a consequence of it dealing with
+%D paragraphs being split over pages and that there are several passes over the data
+%D set. We can probably do some cleanup (combine/split).
+%D
+%D Caching the preamble does not save much (compared to other bits and pieces of
+%D \CONTEXT). There are not that many ways to deal with preambles and this is just
+%D one of them. The keys are somewhat similar to those of the \TABLE\ package.
+
+% |p2|p3| 2:3 -> spanning (maybe)
+%
+% In-text tabbing environment
+%
+% \starttabulate[| separated template] % eg [|l|p|] or [|l|p|p|]
+% \NC ... \NC ... \NC\NR
+% \stoptabulate
+%
+% with: two pass auto width calculation when no p-width
+% specified, even with multiple p's, see examples.
+%
+% TaBlE compatible specifications:
+%
+% l align column/paragraph left
+% r align column/paragraph right
+% c align column/paragraph center
+% p p(dimen) of automatisch als alleen p
+% w column width
+% f font#1
+% A {alignmentoptions}
+% B bold
+% I italic
+% S slanted
+% T type
+% R roman
+% m math
+% M display math
+% h hook (inner level or par lines)
+% b before (may be command#1)
+% a after
+% i i<n> skip left of column
+% j i<n> skip right of column
+% k i<n> skip around column
+% d digits (~)
+%
+% C [LMRT] {color} % T is text color
+%
+% | {color,n}
+%
+% s setups
+%
+% g g{char} align at char
+% . align at .
+% , align at ,
+%
+% Still to be done
+%
+% N math numbers (best hook into existing digits mechanism)
+% n numbers (best hook into existing digits mechanism)
+% Q math numbers (best hook into existing digits mechanism)
+% q numbers (best hook into existing digits mechanism)
+% ~ \hskip.5em
+% | check
+%
+% nesting
+%
+% 10 evt auto stack; dan wel andere signal dan void nodig
+%
+% present but not yet 100% ok
+%
+% \TL [width,color] bottom hrule
+% \FL [width,color] first hrule
+% \ML [width,color] mid hrule (with auto split)
+% \LL [width,color] bottom hrule
+% \BL [width,color] last hrule
+%
+% \HL [width,color] top rule
+% \VL [width,color]
+%
+% \CC \CL \CM \CR color
+%
+% \EQ \RQ \HQ equal (raw, hook)
+% \NC \RC \HC normal (raw, hook)
+%
+% \NR checked break
+% \NB no break
+%
+% \HR : rule with lineheight
+%
+% \autotabulaterule : with lineheight, not first/last
+% \autotabulateline : spaced, not first/last
+% \tabulaterule : with lineheight
+% \tabulateline : spaced
+%
+% tricky: align scans ahead, over # and expands ones before
+% while doing
+%
+% new:
+%
+% \starttabulate[|cg{.}|cg{,}|cg{,}|]
+% \NC period \NC comma \NC comma \NC\NR
+% \NG 100.000,00 \NG 100.000,00 \NG 100,00 \NC\NR
+% \NG 10.000,00 \NG 10.000,00 \NG 1000,00 \NC\NR
+% \NG 100,00 \NG 100,00 \NG 10,00 \NC\NR
+% \NG 10 \NG 10 \NG 0,00 \NC\NR
+% \stoptabulate
+%
+% \starttabulate[|c.|c,|c,|]
+% \NC period \NC comma \NC comma \NC\NR
+% \NG 100.000,00 \NG 100.000,00 \NG 100,00 \NC\NR
+% \NG 10.000,00 \NG 10.000,00 \NG 1000,00 \NC\NR
+% \NG 100,00 \NG 100,00 \NG 10,00 \NC\NR
+% \NG 10 \NG 10 \NG 0,00 \NC\NR
+% \stoptabulate
+
+% nice demo (for BG)
+%
+% \starttabulate[|r|b{$\star$}|ra{\percent}|b{=}|r|]
+% \NC 500 \NC \NC 60 \NC \NC 300 \NC \NR
+% \NC 500 \NC \NC 55 \NC \NC 275 \NC \NR
+% \NC 500 \NC \NC 50 \NC \NC 250 \NC \NR
+% \NC 500 \NC \NC 45 \NC \NC 225 \NC \NR
+% \NC 500 \NC \NC 40 \NC \NC 200 \NC \NR
+% \NC 500 \NC \NC 35 \NC \NC 175 \NC \NR
+% \NC 500 \NC \NC 30 \NC \NC 150 \NC \NR
+% \NC 500 \NC \NC 25 \NC \NC 125 \NC \NR
+% \NC 500 \NC \NC 20 \NC \NC 100 \NC \NR
+% \stoptabulate
+
+\newtoks \t_tabl_tabulate_preamble
+\newtoks \t_tabl_tabulate_before
+\newtoks \t_tabl_tabulate_after
+\newtoks \t_tabl_tabulate_bmath
+\newtoks \t_tabl_tabulate_emath
+\newtoks \t_tabl_tabulate_font
+\newtoks \t_tabl_tabulate_settings
+\newtoks \t_tabl_tabulate_dummy
+\newtoks \t_tabl_tabulate_every_row
+\newtoks \t_tabl_tabulate_every_after_row
+\newtoks \t_tabl_tabulate_every_real_row
+
+\newtoks \t_tabl_tabulate_initializers_first
+\newtoks \t_tabl_tabulate_initializers_second
+
+\newcount \c_tabl_tabulate_nofauto
+\newcount \c_tabl_tabulate_columns
+\newcount \c_tabl_tabulate_column
+\newcount \c_tabl_tabulate_plines_min
+\newcount \c_tabl_tabulate_plines_max
+\newcount \c_tabl_tabulate_max_colorcolumn
+\newcount \c_tabl_tabulate_max_vrulecolumn
+\newcount \c_tabl_tabulate_repeathead
+\newcount \c_tabl_tabulate_noflines
+\newcount \c_tabl_tabulate_totalnoflines
+\newcount \c_tabl_tabulate_minusnoflines
+\newcount \c_tabl_tabulate_align
+\newcount \c_tabl_tabulate_nofrealrows
+\newcount \c_tabl_tabulate_autocolor
+
+\newcount \c_tabl_tabulate_nofcolumns % set at the lua end by parser
+\newcount \c_tabl_tabulate_has_rule_spec_first % set at the lua end by parser (for the moment a count)
+\newcount \c_tabl_tabulate_has_rule_spec_last % set at the lua end by parser (for the moment a count)
+
+\newconditional \c_tabl_tabulate_nopbreak
+\newconditional \c_tabl_tabulate_firstflushed
+\newconditional \c_tabl_tabulate_equal
+\newconditional \c_tabl_tabulate_split \settrue\c_tabl_tabulate_split
+\newconditional \c_tabl_tabulate_automode
+\newconditional \c_tabl_tabulate_handlepbreak \settrue\c_tabl_tabulate_handlepbreak
+\newconditional \c_tabl_tabulate_autorulespacing \settrue\c_tabl_tabulate_autorulespacing
+\newconditional \c_tabl_tabulate_someamble
+\newconditional \c_tabl_tabulate_tolerant_break
+\newconditional \c_tabl_tabulate_splitoff_whitespace
+\newconditional \c_tabl_tabulate_pwidth_set
+\newconditional \c_tabl_tabulate_reshape
+
+\newdimen \d_tabl_tabulate_width_p
+\newdimen \d_tabl_tabulate_width_w
+\newdimen \d_tabl_tabulate_width
+\newdimen \d_tabl_tabulate_unit
+\newdimen \d_tabl_tabulate_height_p_max
+\newdimen \d_tabl_tabulate_vrulethickness_default
+\newdimen \d_tabl_tabulate_hrulethickness_default
+\newdimen \d_tabl_tabulate_vrulethickness
+\newdimen \d_tabl_tabulate_hrulethickness % not used
+\newdimen \d_tabl_tabulate_vrulethickness_local
+\newdimen \d_tabl_tabulate_hrulethickness_local
+\newdimen \d_tabl_tabulate_indent
+\newdimen \d_tabl_tabulate_splitoff_betweenskip
+\newdimen \d_tabl_tabulate_margin
+
+\newskip \s_tabl_tabulate_pre
+\newskip \s_tabl_tabulate_post
+\newskip \s_tabl_tabulate_first
+\newskip \s_tabl_tabulate_last
+\newskip \s_tabl_tabulate_separator
+
+\newbox \b_tabl_tabulate
+
+\newconstant \c_tabl_tabulate_pass
+\newconstant \c_tabl_tabulate_type
+\newconstant \c_tabl_tabulate_kind % 1=strong 2=equals
+\newconstant \c_tabl_tabulate_splitlinemode \c_tabl_tabulate_splitlinemode\plusone
+\newconstant \c_tabl_tabulate_colorspan
+\newconstant \c_tabl_tabulate_localcolorspan
+\newconstant \c_tabl_tabulate_modus
+
+\let\tabulatesplitlinemode\c_tabl_tabulate_splitlinemode % temp hack, we need an interface
+
+\let \m_tabl_tabulate_separator_factor \empty % fraction
+
+\newtoks \everytabulatepar % where used ?
+\newtoks \everytabulate % public ?
+
+\unexpanded\def\tolerantTABLEbreaktrue {\settrue \c_tabl_tabulate_tolerant_break} % used in styles !
+\unexpanded\def\handletabulatepbreakfalse{\setfalse\c_tabl_tabulate_handlepbreak } % depricated
+
+\def\noftabulaterows{\number\c_tabl_tabulate_noflines} % handy for testing if a table is empty
+
+\installcorenamespace{tabulatebox}
+\installcorenamespace{tabulatesetup}
+\installcorenamespace{tabulatehook}
+\installcorenamespace{tabulatesplit}
+\installcorenamespace{tabulateseparator}
+\installcorenamespace{tabulatecolor}
+\installcorenamespace{tabulateheader}
+\installcorenamespace{tabulatealigning}
+\installcorenamespace{tabulatepreamble}
+\installcorenamespace{tabulatevrule}
+
+\installcorenamespace{tabulatehead}
+\installcorenamespace{tabulatefoot}
+\installcorenamespace{tabulatenext}
+
+\prependtoks
+ \global\c_tabl_tabulate_nofrealrows\zerocount
+\to \t_tabl_tabulate_initializers_first
+
+\prependtoks
+ \global\c_tabl_tabulate_nofrealrows\zerocount
+\to \t_tabl_tabulate_initializers_second
+
+\prependtoks
+ \global\advance\c_tabl_tabulate_nofrealrows\plusone
+\to \t_tabl_tabulate_every_real_row
+
+\def\b_tabl_tabulate_current#1%
+ {\csname\??tabulatebox\number#1\endcsname} % beware, a synonym
+
+\def\tabl_tabulate_initialize_boxes#1%
+ {\scratchcounter#1\relax
+ \tabl_tabulate_initialize_boxes_step}
+
+\def\tabl_tabulate_initialize_boxes_step
+ {\ifnum\scratchcounter>\zerocount
+ \tabl_tabulate_initialize_box\scratchcounter
+ \advance\scratchcounter\minusone
+ \expandafter\tabl_tabulate_initialize_boxes_step
+ \fi}
+
+\def\tabl_tabulate_initialize_box#1% also used elsewhere
+ {\ifcsname\??tabulatebox\number#1\endcsname
+ \tabl_tabulate_initialize_box_yes
+ \else
+ \tabl_tabulate_initialize_box_nop#1%
+ \fi}
+
+\def\tabl_tabulate_initialize_box_yes {\global \setbox\lastnamedcs\emptybox}
+\def\tabl_tabulate_initialize_box_nop#1{\expandafter\newbox\csname\??tabulatebox\number#1\endcsname}
+
+\tabl_tabulate_initialize_boxes{16} % not really needed
+
+\let\initializetablebox \tabl_tabulate_initialize_box % used elsewhere, will change
+\let\initializetableboxes\tabl_tabulate_initialize_boxes % used elsewhere, will change
+\let\tablebox \b_tabl_tabulate_current
+
+% 0 = NC column next EQ equal column
+% 1 = RC column raw RQ equal column raw
+% 2 = HC column hook HQ equal column hook
+
+% handy helper
+
+\def\tabulatenoalign % public ?
+ {\noalign
+ \bgroup
+ \let\noalign\relax
+ \let\tabulatenoalign\relax
+ \let\next=}
+
+\def\starttabulatenoalign % public ?
+ {\tabulatenoalign\bgroup}
+
+\let\stoptabulatenoalign\egroup
+
+% [|lg{.}|] => \NG 12.34 \NC
+
+\def\tabl_tabulate_nobreak_inject_tracer
+ {\red % maybe use the fast color switcher here
+ \hrule\s!height.5\linewidth\s!depth.5\linewidth
+ \par
+ \kern-\linewidth
+ \tabl_tabulate_break_no}
+
+\installtextracker
+ {tables.tabulate.breaks}
+ {\let\tabl_tabulate_break_no_tracer\tabl_tabulate_nobreak_inject_tracer}
+ {\let\tabl_tabulate_break_no_tracer\donothing}
+
+\let\tabl_tabulate_break_no_tracer\donothing
+
+\def\tabl_tabulate_nobreak_inject_indeed
+ {\tabl_tabulate_break_no
+ \tabl_tabulate_break_no_tracer}
+
+\def\tabl_tabulate_nobreak_inject
+ {\tabulatenoalign{\tabl_tabulate_nobreak_inject_indeed}}
+
+\unexpanded\def\tabl_tabulate_hook_check
+ {\ifnum\c_tabl_tabulate_type<\plustwo
+ \glet\tabl_tabulate_hook\tabl_tabulate_hook_nop
+ \else
+ \glet\tabl_tabulate_hook\tabl_tabulate_hook_yes
+ \fi}
+
+\unexpanded\def\tabl_tabulate_setups_check
+ {\begincsname\??tabulatesetup\the\c_tabl_tabulate_column\endcsname}
+
+\unexpanded\def\tabl_tabulate_entry_before{\ignorespaces\tabl_tabulate_hook}
+\unexpanded\def\tabl_tabulate_entry_after {\unskip\unskip\ifmmode\else\endgraf\fi}
+
+\unexpanded\def\tabl_tabulate_shaped_par_begin
+ {\dowithnextboxcs\tabl_tabulate_shaped_par_finish\vbox\bgroup}
+
+\def\tabl_tabulate_shaped_par_finish
+ {\clf_doreshapeframedbox\nextbox\relax
+ \ifvmode\unvbox\else\box\fi\nextbox}
+
+\let\tabl_tabulate_shaped_par_end\egroup
+
+\ifdefined\dotagtabulatecell \else \let\dotagtabulatecell \relax \fi
+\ifdefined\dotagtabulatesignal \else \let\dotagtabulatesignal\relax \fi
+
+\unexpanded\def\tabl_tabulate_check_local_color_first#1#2%
+ {\relax}
+
+\unexpanded\def\tabl_tabulate_check_local_color_second#1#2%
+ {\relax
+ \ifx\m_tabl_tabulate_color_local\empty
+ \xdef\m_tabl_tabulate_color{#1}%
+ \else
+ \glet\m_tabl_tabulate_color\m_tabl_tabulate_color_local
+ \glet\m_tabl_tabulate_color_local\empty
+ \fi
+ \ifcase\c_tabl_tabulate_localcolorspan
+ \global\c_tabl_tabulate_colorspan#2\relax
+ \else
+ \global\c_tabl_tabulate_colorspan\c_tabl_tabulate_localcolorspan
+ \global\c_tabl_tabulate_localcolorspan\zerocount
+ \fi}
+
+\unexpanded\def\tabl_tabulate_check_local_vrule_thickness#1%
+ {\relax
+ \ifcase\d_tabl_tabulate_vrulethickness_local
+ \global\d_tabl_tabulate_vrulethickness#1\relax
+ \else
+ \global\d_tabl_tabulate_vrulethickness\d_tabl_tabulate_vrulethickness_local
+ \global\d_tabl_tabulate_vrulethickness_local\zeropoint
+ \fi}
+
+\unexpanded\def\tabl_tabulate_check_local_vrule_color_first#1%
+ {\relax}
+
+\unexpanded\def\tabl_tabulate_check_local_vrule_color_second#1%
+ {\relax
+ \ifx\m_tabl_tabulate_vrule_color_local\empty
+ \xdef\m_tabl_tabulate_vrule_color{#1}%
+ \else
+ \glet\m_tabl_tabulate_vrule_color\m_tabl_tabulate_vrule_color_local
+ \glet\m_tabl_tabulate_vrule_color_local\empty
+ \fi}
+
+\let\tabl_tabulate_check_local_color \gobbletwoarguments
+\let\tabl_tabulate_check_local_vrule_color\gobbleoneargument
+
+\appendtoks
+ \let\tabl_tabulate_check_local_color \tabl_tabulate_check_local_color_first
+ \let\tabl_tabulate_check_local_vrule_color\tabl_tabulate_check_local_vrule_color_first
+\to \t_tabl_tabulate_initializers_first
+
+\appendtoks
+ \let\tabl_tabulate_check_local_color \tabl_tabulate_check_local_color_second
+ \let\tabl_tabulate_check_local_vrule_color\tabl_tabulate_check_local_vrule_color_second
+\to \t_tabl_tabulate_initializers_second
+
+% \unexpanded % we can expand this one
+\def\tabl_tabulate_inject_pre_skip#1%
+ {\ifdim#1>\zeropoint
+ \kern#1\relax % was \hskip
+ \orelse\ifnum\c_tabl_tabulate_column=\zerocount
+ \ifconditional\c_tabl_tabulate_autorulespacing
+ \ifcase\c_tabl_tabulate_has_rule_spec_first\else
+ \kern\s_tabl_tabulate_first\relax % was \hskip
+ \fi
+ \fi
+ \fi}
+
+% \unexpanded % we can expand this one
+\def\tabl_tabulate_inject_post_skip#1%
+ {\ifdim#1>\zeropoint
+ \kern#1\relax % was \hskip
+ \orelse\ifnum\c_tabl_tabulate_columns=\c_tabl_tabulate_nofcolumns
+ \ifconditional\c_tabl_tabulate_autorulespacing
+ \ifcase\c_tabl_tabulate_has_rule_spec_last\else
+ \kern\s_tabl_tabulate_last\relax % was \hskip
+ \fi
+ \fi
+ \fi}
+
+\let\tabl_tabulate_hook_b\donothing
+\let\tabl_tabulate_hook_e\donothing
+
+\let\tabl_tabulate_hook_g\donothing
+
+\def\tabl_tabulate_set_preamble_step#1#2% only makes sense for many tabulates
+ {\etoksapp\t_tabl_tabulate_preamble{%
+ \tabl_tabulate_check_local_vrule_thickness\constantdimenargument\d_tabl_tabulate_vrulethickness
+ \tabl_tabulate_check_local_vrule_color\constantemptyargument\m_tabl_tabulate_vrule_color
+ \tabl_tabulate_check_local_color\constantemptyargument\m_tabl_tabulate_color\constantnumberargument\c_tabl_tabulate_colorspan
+ \tabl_tabulate_color_side_right
+ \aligntab
+ \tabl_tabulate_column_vrule_inject
+ \tabl_tabulate_color_side_left
+ \tabl_tabulate_inject_pre_skip{\the\dimexpr\s_tabl_tabulate_pre}% get rid of plus
+ \alignmark\alignmark
+ \aligntab
+ \tabl_tabulate_color_side_both
+ \global\c_tabl_tabulate_colorspan\zerocount
+ \global\c_tabl_tabulate_column\constantnumber\c_tabl_tabulate_columns
+ \tabl_tabulate_hook_g
+ \tabl_tabulate_setups_check % unexpandable
+ \tabl_tabulate_hook_check % unexpandable
+ \ifzeropt\d_tabl_tabulate_width
+ \ifcase\c_tabl_tabulate_modus\else
+ \settrue\c_tabl_tabulate_automode
+ \fi
+ \else
+ \ifcase\c_tabl_tabulate_modus
+ \hbox to
+ \else
+ \hsize
+ \fi
+ \the\d_tabl_tabulate_width
+ \fi
+ \bgroup
+ \tabl_tabulate_bbskip
+ \bgroup % we cannot combine the if because a cell may have only one ##
+ \tabl_tabulate_hook_b
+ \c_tabl_tabulate_align\constantnumber\c_tabl_tabulate_align % needed in tag passing
+ \ifx\m_tabl_tabulate_alignment\empty \else
+ \spac_align_use_now{\m_tabl_tabulate_alignment}%
+ \fi
+ \noexpand\dostarttagged\noexpand\t!tabulatecell\noexpand\empty
+ \noexpand\dotagtabulatecell
+ \noexpand#1%
+ \ifconditional\c_tabl_tabulate_reshape
+ \tabl_tabulate_shaped_par_begin
+ \fi
+ \dotagtabulatesignal % empty cells .. todo (can be removed as soon as build)
+ \noexpand\ifnum\noexpand\c_tabl_tabulate_type=\plusone\noexpand\else
+ \the\t_tabl_tabulate_bmath % maybe later? can interfere with char 0
+ \the\t_tabl_tabulate_font
+ \the\t_tabl_tabulate_settings
+ \the\t_tabl_tabulate_before
+ \ifx\m_tabl_tabulate_text_color\empty
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\dofastcoloractivation
+ \fi\m_tabl_tabulate_text_color
+ \noexpand\fi
+ % grouping needs to be outside macros (or expandable), nice test
+ % example \NC \string \aligntab \NC which will fail otherwise (mk)
+ \bgroup
+ \tabl_tabulate_entry_before
+ \alignmark\alignmark
+ \tabl_tabulate_entry_after
+ \egroup
+ \noexpand\ifnum\noexpand\c_tabl_tabulate_type=\plusone\noexpand\else
+ \the\t_tabl_tabulate_after
+ \the\t_tabl_tabulate_emath
+ \noexpand\fi
+ \ifconditional\c_tabl_tabulate_reshape
+ \tabl_tabulate_shaped_par_end
+ \fi
+ \noexpand#2%
+ \tabl_tabulate_hook_e
+ \egroup
+ \egroup
+ \aligntab
+ \noexpand\dostoptagged
+ \tabl_tabulate_inject_post_skip{\the\dimexpr\s_tabl_tabulate_post}% get rid of plus
+ \alignmark\alignmark
+ }%
+ \toksapp\t_tabl_tabulate_dummy{\NC}%
+ \s_tabl_tabulate_pre.5\d_tabl_tabulate_unit\relax
+ \ifnum\c_tabl_tabulate_columns<\numexpr\c_tabl_tabulate_nofcolumns-\plusone\relax
+ \s_tabl_tabulate_post\s_tabl_tabulate_pre
+ \else
+ \s_tabl_tabulate_post\zeropoint
+ \fi
+ %\let\gettabulateexit\dogettabulateexit % still needed ?
+ \d_tabl_tabulate_width\zeropoint}
+
+\unexpanded\def\installtabulatepreambleoption#1#2%
+ {\setvalue{\??tabulatepreamble\string#1}{#2}}%
+
+\installtabulatepreambleoption{x}{\c_tabl_tabulate_align\zerocount
+ \tabl_tabulate_set_preamble} % internal
+\installtabulatepreambleoption{l}{\c_tabl_tabulate_align\plusone
+ \tabl_tabulate_set_preamble}
+\installtabulatepreambleoption{r}{\c_tabl_tabulate_align\plustwo
+ \tabl_tabulate_set_preamble}
+\installtabulatepreambleoption{c}{\c_tabl_tabulate_align\plusthree
+ \tabl_tabulate_set_preamble}
+\installtabulatepreambleoption{p}{\tabl_tabulate_set_paragraph}
+\installtabulatepreambleoption{s}{\tabl_tabulate_set_setups}
+\installtabulatepreambleoption{w}{\tabl_tabulate_set_width}
+\installtabulatepreambleoption{f}{\tabl_tabulate_set_font}
+\installtabulatepreambleoption{B}{\t_tabl_tabulate_font{\bf}%
+ \tabl_tabulate_set_preamble}
+\installtabulatepreambleoption{I}{\t_tabl_tabulate_font{\it}%
+ \tabl_tabulate_set_preamble}
+\installtabulatepreambleoption{S}{\t_tabl_tabulate_font{\sl}%
+ \tabl_tabulate_set_preamble}
+\installtabulatepreambleoption{T}{\t_tabl_tabulate_font{\tt}%
+ \tabl_tabulate_set_preamble}
+\installtabulatepreambleoption{R}{\t_tabl_tabulate_font{\rm}%
+ \tabl_tabulate_set_preamble}
+\installtabulatepreambleoption{m}{\t_tabl_tabulate_bmath{\normalstartimath}%
+ \t_tabl_tabulate_emath{\normalstopimath}%
+ \tabl_tabulate_set_preamble}
+\installtabulatepreambleoption{M}{\t_tabl_tabulate_bmath{\normalstartimath\displaystyle}%
+ \t_tabl_tabulate_emath{\normalstopimath}%
+ \tabl_tabulate_set_preamble}
+\installtabulatepreambleoption{h}{\tabl_tabulate_set_hook}
+\installtabulatepreambleoption{b}{\tabl_tabulate_set_before}
+\installtabulatepreambleoption{a}{\tabl_tabulate_set_after}
+\installtabulatepreambleoption{i}{\tabl_tabulate_set_preskip}
+\installtabulatepreambleoption{j}{\tabl_tabulate_set_posskip}
+\installtabulatepreambleoption{k}{\tabl_tabulate_set_preposskip}
+\installtabulatepreambleoption{e}{\toksapp\t_tabl_tabulate_settings{\global\settrue\c_tabl_tabulate_equal}%
+ \tabl_tabulate_set_preamble}
+\installtabulatepreambleoption{g}{\tabl_tabulate_set_align}
+\installtabulatepreambleoption{.}{\tabl_tabulate_set_align.}
+\installtabulatepreambleoption{,}{\tabl_tabulate_set_align,}
+\installtabulatepreambleoption{C}{\tabl_tabulate_set_color_span}
+\installtabulatepreambleoption{d}{\toksapp\t_tabl_tabulate_settings{\fixedspaces}%
+ \tabl_tabulate_set_preamble}
+\installtabulatepreambleoption{ }{\tabl_tabulate_set_preamble}
+\installtabulatepreambleoption{A}{\tabl_tabulate_set_alignment}
+
+%D We no longer deal with \type {~} here but map it onto \type {d} instead. Of
+%D course we could prefix a key with \type {\meaning} instead, which works ok (and
+%D is needed in order to pseudo expand \type {\next}, but is ugly at the same time.
+%D The type {d} stands for digitspace.
+
+%D \starttyping
+%D \installtabulatepreambleoption{~}{...} % see 'd'
+%D \stoptyping
+%D
+%D Also, as there is always a key, we no longer do some after assigment or future
+%D let but just pick up the key.
+
+% \installtabulatepreambleoption \s!unknown %
+% {\writestatus{tabulate}{unknown preamble key [\normalmeaning\next]}%
+% \tabl_tabulate_set_preamble}
+%
+% \def\tabl_tabulate_set_preamble
+% {\afterassignment\dosettabulatepreamble\let\next=}
+%
+% \def\dosettabulatepreamble
+% {\ifx\next\relax \else
+% \csname\??tabulatepreamble
+% \ifcsname\??tabulatepreamble\next\endcsname\next\else\s!unknown\fi
+% \expandafter\endcsname
+% \fi}
+
+\installtabulatepreambleoption\relax
+ {} % finished
+
+\def\tabl_tabulate_set_preamble#1%
+ {\ifcsname\??tabulatepreamble\string#1\endcsname
+ %\expandafter\tabl_tabulate_set_preamble_yes
+ \expandafter\expandafter\expandafter\lastnamedcs\expandafter\gobbleoneargument
+ \else
+ \expandafter\tabl_tabulate_set_preamble_nop
+ \fi{#1}}
+
+\def\tabl_tabulate_set_preamble_yes#1%
+ {\csname\??tabulatepreamble\string#1\expandafter\endcsname}
+
+\def\tabl_tabulate_set_preamble_nop#1%
+ {\writestatus{tabulate}{unknown preamble key: #1}%
+ \tabl_tabulate_set_preamble}
+
+\def\tabl_tabulate_set_preskip#1%
+ {\doifelsenumber{#1}%
+ {\s_tabl_tabulate_pre#1\d_tabl_tabulate_unit\tabl_tabulate_set_preamble }%
+ {\s_tabl_tabulate_pre.5\d_tabl_tabulate_unit\tabl_tabulate_set_preamble#1}}
+
+\def\tabl_tabulate_set_posskip#1%
+ {\doifelsenumber{#1}%
+ {\s_tabl_tabulate_post#1\d_tabl_tabulate_unit\tabl_tabulate_set_preamble }%
+ {\s_tabl_tabulate_post.5\d_tabl_tabulate_unit\tabl_tabulate_set_preamble#1}}
+
+\def\tabl_tabulate_set_preposskip#1%
+ {\doifelsenumber{#1}%
+ {\s_tabl_tabulate_pre#1\d_tabl_tabulate_unit\s_tabl_tabulate_post\s_tabl_tabulate_pre\tabl_tabulate_set_preamble }%
+ {\s_tabl_tabulate_pre.5\d_tabl_tabulate_unit\s_tabl_tabulate_post\s_tabl_tabulate_pre\tabl_tabulate_set_preamble#1}}
+
+\def\tabl_tabulate_set_setups#1%
+ {\setvalue{\??tabulatesetup\the\c_tabl_tabulate_columns}{\setups[#1]}%
+ \tabl_tabulate_set_preamble}
+
+\def\tabl_tabulate_set_hook#1%
+ {\setvalue{\??tabulatehook\the\c_tabl_tabulate_columns}{#1}%
+ \tabl_tabulate_set_preamble}
+
+% begin of character align plugin
+
+\newconditional\c_tabl_auto_align_mode % reset later
+
+\def\tabl_tabulate_hook_g % partly expanded
+ {\ifconditional\c_tabl_auto_align_mode
+ \signalcharacteralign\c_tabl_tabulate_column{\c_tabl_tabulate_noflines+\plusone}%
+ \typo_charalign_adapt_font
+ \fi}
+
+\def\tabl_tabulate_set_align#1%
+ {\global\settrue\c_tabl_auto_align_mode
+ \setcharacteralign\c_tabl_tabulate_columns{#1}%
+ \tabl_tabulate_set_preamble}
+
+% end of character align plugin
+
+\def\tabl_tabulate_set_before#1%
+ {\t_tabl_tabulate_before{#1}%
+ \tabl_tabulate_set_preamble}
+
+\def\tabl_tabulate_set_after#1%
+ {\t_tabl_tabulate_after{#1}%
+ \tabl_tabulate_set_preamble}
+
+\def\tabl_tabulate_set_font#1%
+ {\t_tabl_tabulate_font{#1}%
+ \tabl_tabulate_set_preamble}
+
+\def\tabl_tabulate_pickup_width
+ {\doifelsenextparenthesis\tabl_tabulate_set_width_indeed\tabl_tabulate_set_preamble}
+
+\def\tabl_tabulate_set_width
+ {\setfalse\c_tabl_tabulate_pwidth_set
+ \c_tabl_tabulate_modus\zerocount
+ \tabl_tabulate_pickup_width}
+
+\def\tabl_tabulate_set_alignment#1%
+ {\edef\m_tabl_tabulate_alignment{#1}%
+ \spac_align_use_later\m_tabl_tabulate_alignment
+ \tabl_tabulate_set_preamble}
+
+\def\tabl_tabulate_set_paragraph
+ {\doifelsenextparenthesis
+ {\c_tabl_tabulate_modus\plusone
+ \settrue\c_tabl_tabulate_pwidth_set
+ \tabl_tabulate_pickup_width}
+ {\c_tabl_tabulate_modus\plustwo
+ \setfalse\c_tabl_tabulate_pwidth_set
+ \tabl_tabulate_set_preamble}}
+
+% \startbuffer
+% \toplinebox{\framed[width=3cm,height=2cm]{tufte}}
+% \stopbuffer
+% \starttabulate[|p(fixed)|p|]
+% \dorecurse{100}{\NC \getbuffer \NC test \par test \par \NC \NR}
+% \stoptabulate
+% \starttabulate[|p(fit)|p|]
+% \dorecurse{100}{\NC \getbuffer \NC test \par test \par \NC \NR}
+% \stoptabulate
+
+\def\tabl_tabulate_set_width_indeed(#1)%
+ {\processallactionsinset % can be made faster
+ [#1]%
+ [ \v!fit=>\c_tabl_tabulate_modus\plusthree,
+ \v!fixed=>\c_tabl_tabulate_modus\plusthree
+ \settrue\c_tabl_tabulate_nopbreak,
+ \v!auto=>\c_tabl_tabulate_modus\plusthree
+ \settrue\c_tabl_tabulate_reshape,
+ \s!unknown=>\d_tabl_tabulate_width#1\relax]%
+ \ifconditional\c_tabl_tabulate_pwidth_set
+ \global\advance\d_tabl_tabulate_width_p\d_tabl_tabulate_width % accumulated parwidth
+ \fi
+ \tabl_tabulate_set_preamble}
+
+% faster but seldom used
+%
+% \installcorenamespace{tabulatewidth}
+%
+% \setvalue{\??tabulatewidth\v!fit }{\c_tabl_tabulate_modus\plusthree}
+% \setvalue{\??tabulatewidth\v!fixed}{\c_tabl_tabulate_modus\plusthree\settrue\c_tabl_tabulate_nopbreak}
+% \setvalue{\??tabulatewidth\v!auto }{\c_tabl_tabulate_modus\plusthree\settrue\c_tabl_tabulate_reshape}
+%
+% \def\tabl_tabulate_set_width_step#1%
+% {\ifcsname\??tabulatewidth#1\endcsname
+% \lastnamedcs
+% \else
+% \d_tabl_tabulate_width#1\relax
+% \fi}
+%
+% \def\tabl_tabulate_set_width_indeed(#1)%
+% {\rawprocesscommacommand[#1]\tabl_tabulate_set_width_step
+% \ifconditional\c_tabl_tabulate_pwidth_set
+% \global\advance\d_tabl_tabulate_width_p\d_tabl_tabulate_width % accumulated parwidth
+% \fi
+% \tabl_tabulate_set_preamble}
+%
+\def\tabl_tabulate_set_raggedright {\ifnum\c_tabl_tabulate_type=\plusone \else\raggedright \fi}
+\def\tabl_tabulate_set_raggedcenter{\ifnum\c_tabl_tabulate_type=\plusone \else\raggedcenter\fi}
+\def\tabl_tabulate_set_raggedleft {\ifnum\c_tabl_tabulate_type=\plusone \else\raggedleft \fi}
+\def\tabl_tabulate_set_notragged {\ifnum\c_tabl_tabulate_type=\plusone \else\notragged \fi}
+\def\tabl_tabulate_set_hss {\ifnum\c_tabl_tabulate_type=\plusone \else\hss \fi} % never change this to a fill
+
+\def\tabl_tabulate_bskip_raggedright {\tabl_tabulate_bskip\tabl_tabulate_set_raggedright }
+\def\tabl_tabulate_bskip_raggedleft {\tabl_tabulate_bskip\tabl_tabulate_set_raggedleft }
+\def\tabl_tabulate_bskip_raggedcenter{\tabl_tabulate_bskip\tabl_tabulate_set_raggedcenter}
+
+\def\tabl_tabulate_set_width_normal
+ {\ifcase\c_tabl_tabulate_align\relax
+ \tabl_tabulate_set_preamble_step\empty \tabl_tabulate_set_hss \or
+ \tabl_tabulate_set_preamble_step\empty \tabl_tabulate_set_hss \or
+ \tabl_tabulate_set_preamble_step\tabl_tabulate_set_hss\empty \or
+ \tabl_tabulate_set_preamble_step\tabl_tabulate_set_hss\tabl_tabulate_set_hss \fi}
+
+\def\tabl_tabulate_set_width_fixed
+ {\ifcase\c_tabl_tabulate_align\relax
+ \tabl_tabulate_set_preamble_step\tabl_tabulate_bskip \tabl_tabulate_eskip \or
+ \tabl_tabulate_set_preamble_step\tabl_tabulate_bskip_raggedright \tabl_tabulate_eskip \or
+ \tabl_tabulate_set_preamble_step\tabl_tabulate_bskip_raggedleft \tabl_tabulate_eskip \or
+ \tabl_tabulate_set_preamble_step\tabl_tabulate_bskip_raggedcenter\tabl_tabulate_eskip \fi}
+
+\def\tabl_tabulate_set_width_auto
+ {\global\advance\c_tabl_tabulate_nofauto\plusone
+ \ifcase\c_tabl_tabulate_align\relax
+ \tabl_tabulate_set_preamble_step\tabl_tabulate_bskip \tabl_tabulate_eskip \or
+ \tabl_tabulate_set_preamble_step\tabl_tabulate_bskip_raggedright \tabl_tabulate_eskip \or
+ \tabl_tabulate_set_preamble_step\tabl_tabulate_bskip_raggedleft \tabl_tabulate_eskip \or
+ \tabl_tabulate_set_preamble_step\tabl_tabulate_bskip_raggedcenter\tabl_tabulate_eskip \fi}
+
+\def\tabl_tabulate_set_width_simple
+ {\tabl_tabulate_set_preamble_step\tabl_tabulate_xbskip\tabl_tabulate_xeskip}
+
+% \def\tabl_tabulate_set_color_span#1#2%
+% {\xdef\m_tabl_tabulate_color{#2}%
+% \global\c_tabl_tabulate_colorspan\if#1L\plusone\else\if#1M\plustwo\else\if#1R\plusthree\else\zerocount\fi\fi\fi\relax
+% \tabl_tabulate_set_preamble}
+
+\installcorenamespace{tabulatecolorspec}
+
+\setvalue{\??tabulatecolorspec C}#1{\xdef\m_tabl_tabulate_color {#1}\global\c_tabl_tabulate_colorspan\zerocount}
+\setvalue{\??tabulatecolorspec L}#1{\xdef\m_tabl_tabulate_color {#1}\global\c_tabl_tabulate_colorspan\plusone }
+\setvalue{\??tabulatecolorspec M}#1{\xdef\m_tabl_tabulate_color {#1}\global\c_tabl_tabulate_colorspan\plustwo }
+\setvalue{\??tabulatecolorspec R}#1{\xdef\m_tabl_tabulate_color {#1}\global\c_tabl_tabulate_colorspan\plusthree}
+\setvalue{\??tabulatecolorspec T}#1{\xdef\m_tabl_tabulate_text_color{#1}}
+
+\def\tabl_tabulate_set_color_span#1#2%
+ {\csname\??tabulatecolorspec#1\endcsname{#2}%
+ \tabl_tabulate_set_preamble}
+
+\def\tabl_tabulate_set_vrule_command#1%
+ {\doifelsenumber{#1}
+ {\global\d_tabl_tabulate_vrulethickness#1\d_tabl_tabulate_vrulethickness_default}
+ {\xdef\m_tabl_tabulate_vrule_color{#1}}}
+
+\def\tabl_tabulate_set_entry#1#2% rulespec template
+ {\c_tabl_tabulate_align\v_tabl_tabulate_align
+ \c_tabl_tabulate_modus\zerocount
+ \setfalse\c_tabl_tabulate_pwidth_set
+ \setfalse\c_tabl_tabulate_reshape
+ \t_tabl_tabulate_before\emptytoks
+ \t_tabl_tabulate_after\emptytoks
+ \t_tabl_tabulate_bmath\emptytoks
+ \t_tabl_tabulate_emath\emptytoks
+ \t_tabl_tabulate_font\emptytoks
+ \t_tabl_tabulate_settings\emptytoks
+ \glet\m_tabl_tabulate_alignment\empty
+ \glet\m_tabl_tabulate_color\empty
+ \glet\m_tabl_tabulate_text_color\empty
+ \glet\m_tabl_tabulate_vrule_color\empty
+ \global\c_tabl_tabulate_colorspan\zerocount
+ \global\setfalse\c_tabl_auto_align_mode
+ \global\advance\c_tabl_tabulate_columns\plusone
+ \expandafter\let\csname\??tabulatesetup\the\c_tabl_tabulate_columns\endcsname\donothing % here ?
+ \edef\currenttabulationtrulespec{#1}%
+ \ifx\currenttabulationtrulespec\empty
+ \global\d_tabl_tabulate_vrulethickness\zeropoint
+ \else
+ \global\d_tabl_tabulate_vrulethickness\d_tabl_tabulate_vrulethickness_default
+ \rawprocesscommalist[#1]\tabl_tabulate_set_vrule_command
+ \fi
+ \tabl_tabulate_set_preamble#2\relax\relax % permits i without n
+ \ifcase\c_tabl_tabulate_modus\relax
+ \tabl_tabulate_set_width_normal
+ \or % fixed width
+ \tabl_tabulate_set_width_fixed
+ \or % auto width
+ \tabl_tabulate_set_width_auto
+ \or % simple
+ \tabl_tabulate_set_width_simple
+ \fi}
+
+\def\tabl_tabulate_set_last_entry#1% rulespec
+ {\glet\m_tabl_tabulate_color\empty
+ \glet\m_tabl_tabulate_vrule_color\empty
+ \edef\currenttabulationtrulespec{#1}%
+ \ifx\currenttabulationtrulespec\empty
+ \global\d_tabl_tabulate_vrulethickness\zeropoint
+ \else
+ \global\d_tabl_tabulate_vrulethickness\d_tabl_tabulate_vrulethickness_default
+ \rawprocesscommalist[#1]\tabl_tabulate_set_vrule_command
+ \fi
+ \etoksapp\t_tabl_tabulate_preamble{%
+ \tabl_tabulate_check_local_vrule_thickness\constantdimenargument\d_tabl_tabulate_vrulethickness
+ \tabl_tabulate_check_local_vrule_color\constantemptyargument\m_tabl_tabulate_vrule_color
+ \tabl_tabulate_column_vrule_inject}}
+
+\let\settabulateentry \tabl_tabulate_set_entry % used at the lua end
+\let\settabulatelastentry\tabl_tabulate_set_last_entry % used at the lua end
+
+\def\tabl_tabulate_normalize_splitline
+ {\ifcase\c_tabl_tabulate_splitlinemode
+ % nothing
+ \or
+ \ht\b_tabl_tabulate\strutht
+ \dp\b_tabl_tabulate\strutdp
+ \or
+ \ifdim\ht\b_tabl_tabulate<\strutht
+ \ht\b_tabl_tabulate\strutht
+ \fi
+ \ifdim\dp\b_tabl_tabulate<\strutdp
+ \dp\b_tabl_tabulate\strutdp
+ \fi
+ \fi}
+
+\def\tabl_tabulate_whitespace
+ {\ifdim\d_tabl_tabulate_splitoff_betweenskip>\zeropoint
+ \vskip\d_tabl_tabulate_splitoff_betweenskip
+ \global\d_tabl_tabulate_splitoff_betweenskip\zeropoint
+ \fi}
+
+\def\tabl_tabulate_check_whitespace
+ {\setbox\scratchbox\vpack
+ {\splitdiscards
+ \unskip
+ \ifdim\lastskip>\d_tabl_tabulate_splitoff_betweenskip
+ \global\d_tabl_tabulate_splitoff_betweenskip\lastskip
+ \fi}}
+
+\installtexdirective
+ {tabulate.linenumbers}
+ {\def\tabl_tabulate_check_linenumbers{\page_postprocessors_linenumbers_deepbox\b_tabl_tabulate}}
+ {\let\tabl_tabulate_check_linenumbers\relax}
+
+\let\tabl_tabulate_check_linenumbers\relax
+
+\def\tabl_tabulate_splitoff_box
+ {\dontcomplain
+ \global\setbox\b_tabl_tabulate\vsplit\b_tabl_tabulate_current\c_tabl_tabulate_column to \lineheight % % % global ? % % %
+ \setbox\b_tabl_tabulate\vbox
+ {\unvbox\b_tabl_tabulate}%
+ \ifconditional\c_tabl_tabulate_splitoff_whitespace
+ \tabl_tabulate_check_whitespace
+ \fi
+ \tabl_tabulate_color_repeat % needs to end up in a cell
+ \setbox\b_tabl_tabulate\hpack to \wd\b_tabl_tabulate
+ {\hss\tabl_tabulate_hook_yes{\box\b_tabl_tabulate}\hss}%
+ \tabl_tabulate_normalize_splitline
+ \tabl_tabulate_check_linenumbers
+ \box\b_tabl_tabulate}
+
+\unexpanded\def\tabl_tabulate_hook_nop
+ {}
+
+\let\tabl_tabulate_hook\tabl_tabulate_hook_nop
+
+\def\tabl_tabulate_hook_yes{\begincsname\??tabulatehook\the\c_tabl_tabulate_column\endcsname}
+
+\def\tabl_tabulate_pheight_reset
+ {\global\c_tabl_tabulate_plines_min\plusone
+ \ifdim\d_tabl_tabulate_height_p_max>\zeropoint
+ \getnoflines\d_tabl_tabulate_height_p_max
+ \global\c_tabl_tabulate_plines_max\noflines
+ \else
+ \global\c_tabl_tabulate_plines_max\zerocount
+ \fi
+ \global\d_tabl_tabulate_height_p_max\zeropoint}
+
+\def\tabl_tabulate_pheight_set
+ {\scratchdimen\ht\b_tabl_tabulate_current\c_tabl_tabulate_column\relax
+ \ifdim\scratchdimen>\d_tabl_tabulate_height_p_max
+ \global\d_tabl_tabulate_height_p_max\scratchdimen
+ \fi}
+
+\def\tabl_tabulate_pbreak_inject
+ {\ifconditional\c_tabl_tabulate_handlepbreak
+ \ifconditional\c_tabl_tabulate_nopbreak
+ \tabl_tabulate_nobreak_inject
+ \orelse\ifnum\c_tabl_tabulate_plines_max>\plusone
+ \ifnum\c_tabl_tabulate_plines_min=\plusone
+ \tabl_tabulate_nobreak_inject
+ \fi
+ \global\advance\c_tabl_tabulate_plines_min\plusone
+ \ifnum\c_tabl_tabulate_plines_min=\c_tabl_tabulate_plines_max\relax
+ \tabl_tabulate_nobreak_inject
+ \fi
+ \fi
+ \fi}
+
+\def\tabl_tabulate_pbreak_check
+ {\starttabulatenoalign
+ \tabl_tabulate_pbreak_inject
+ \ifconditional\c_tabl_tabulate_splitoff_whitespace
+ \tabl_tabulate_whitespace
+ \fi
+ \stoptabulatenoalign}
+
+%D \startbuffer
+%D \starttabulate[|c|p|p|]
+%D \NC \bf Alpha \NC \bf Beta \NC \bf Gamma \NC\NR
+%D \NC 1 \NC right indeed \NC definitely wrong \NC\NR
+%D \NC 2 \NC \thinrules[n=3] \NC \thinrules[n=3] \NC\NR
+%D \NC 3 \NC oh yes \NC simply no \NC\NR
+%D \NC 4 \NC very true \NC as false as can be \NC\NR
+%D \NC 5 \NC \thinrules[n=5] \NC \thinrules[n=5] \NC\NR
+%D \NC 6 \NC \thinrules[n=3] \NC \thinrules[n=4] \NC\NR
+%D \stoptabulate
+%D \stopbuffer
+%D
+%D \typebuffer {\tracetabulatetrue\getbuffer}
+%D
+%D \startbuffer
+%D \starttabulate[|c|p|p|]
+%D \NC \bf Alpha \NC \bf Beta \NC \bf Gamma \NC\NR
+%D \NC 1 \NC right indeed \NC definitely wrong \NC\NR
+%D \NC 2 \NC oh yes \NC simply no \NC\NR
+%D \NC 3 \NC very true \NC as false as can be \NC\NR
+%D \NC 4 \NC the whole truth \NC but the truth \NC\NR
+%D \stoptabulate
+%D \stopbuffer
+%D
+%D \typebuffer {\tracetabulatetrue\getbuffer}
+
+%D Because we want to be compatible we use an indirect way to implement the
+%D definers. The next examples demonstrate the difference:
+%D
+%D \starttyping
+%D \definetabulate[test][|l|c|r|]
+%D \definetabulate[test][two][|r|c|l|]
+%D
+%D \definetabulation[more][format={|l|c|r|}]
+%D \definetabulation[more:two][format={|r|c|l|}]
+%D
+%D \starttest
+%D \NC t \NC t \NC t \NC \NR
+%D \NC te \NC te \NC te \NC \NR
+%D \NC tes \NC tes \NC tes \NC \NR
+%D \NC test \NC test \NC test \NC \NR
+%D \stoptest
+%D
+%D \starttest[two]
+%D \NC t \NC t \NC t \NC \NR
+%D \NC te \NC te \NC te \NC \NR
+%D \NC tes \NC tes \NC tes \NC \NR
+%D \NC test \NC test \NC test \NC \NR
+%D \stoptest
+%D \startmore
+%D \NC t \NC t \NC t \NC \NR
+%D \NC te \NC te \NC te \NC \NR
+%D \NC tes \NC tes \NC tes \NC \NR
+%D \NC test \NC test \NC test \NC \NR
+%D \stopmore
+%D
+%D \startmore[two]
+%D \NC t \NC t \NC t \NC \NR
+%D \NC te \NC te \NC te \NC \NR
+%D \NC tes \NC tes \NC tes \NC \NR
+%D \NC test \NC test \NC test \NC \NR
+%D \stopmore
+%D \stoptyping
+
+\installcorenamespace {tabulation}
+
+\installcommandhandler \??tabulation {tabulation} \??tabulation
+
+\setuptabulation
+ [\c!unit=1em,
+ EQ={:},
+ \c!format={|l|p|},
+ \c!frame=\v!off,
+ %\c!bodyfont=,
+ \c!rule=\v!normal,
+ %\c!rulecolor=,
+ \c!rulethickness=\linewidth,
+ %\c!inner=,
+ \c!before=\blank,
+ \c!after=\blank,
+ \c!distance={\v!depth,\v!medium},
+ \c!align=\v!normal,
+ \c!margin=\!!zeropoint,
+ \c!split=\v!auto,
+ \c!header=\v!yes,
+ %\c!title=,
+ \c!indenting=\v!no]
+
+\unexpanded\def\definetabulate
+ {\dotripleempty\tabl_tabulate_define}
+
+\def\tabl_tabulate_define[#1][#2][#3]%
+ {\ifthirdargument
+ % [tag] [sub] [template]
+ \ifcsname\namedtabulationhash{#1}\s!check\endcsname \else
+ \definetabulation[#1][\c!format={#3},\s!check=]%
+ \fi
+ \definetabulation[#1:#2][#1][\c!format={#3},\s!check=]%
+ \orelse\ifsecondargument
+ % [tag] [template]
+ \definetabulation[#1][\c!format={#2},\s!check=]%
+ \else
+ % [tag]
+ \definetabulation[#1][\c!format={|l|p|},\s!check=]%
+ \fi}
+
+\unexpanded\def\setuptabulate
+ {\dotripleempty\tabl_tabulate_setup}
+
+\def\tabl_tabulate_setup[#1][#2][#3]%
+ {\ifthirdargument
+ % [tag] [sub] [settings]
+ \setuptabulation[#1:#2][#3]%
+ \orelse\ifsecondargument
+ % [tag] [settings]
+ \setuptabulation[#1][#2]%
+ \else
+ % [tag]
+ \setuptabulation[#1]%
+ \fi}
+
+\appendtoks
+ \setuevalue{\e!start\currenttabulation}{\tabl_start_defined[\currenttabulation]}%
+ \letvalue{\e!stop\currenttabulation}\relax
+ \letvalue{\??tabulatehead\currenttabulation}\empty
+ \letvalue{\??tabulatefoot\currenttabulation}\empty
+\to \everydefinetabulation
+
+\let\tabulateparameter\tabulationparameter % will stay for a while
+\def\currenttabulate {\currenttabulation} % will stay for a while
+
+% Here begins the implementation.
+
+\let\tabl_tabulate_insert_head\empty
+\let\tabl_tabulate_insert_body\empty
+\let\tabl_tabulate_insert_foot\empty
+
+\def\tabl_tabulate_insert_head_content
+ {\tabulatenoalign{\global\settrue\c_tabl_tabulate_someamble}%
+ \begincsname\??tabulatehead\currenttabulation\endcsname
+ \tabulatenoalign{\global\setfalse\c_tabl_tabulate_someamble}}%
+
+\def\tabl_tabulate_insert_foot_content
+ {\tabulatenoalign{\global\settrue\c_tabl_tabulate_someamble}%
+ \begincsname\??tabulatefoot\currenttabulation\endcsname
+ \tabulatenoalign{\global\setfalse\c_tabl_tabulate_someamble}}%
+
+\def\tabl_tabulate_check_full_content % - needed, else confusion with \c!header
+ {\ifcsname\??tabulatehead\currenttabulation\endcsname
+ %\expandafter\ifx\csname\??tabulatehead\currenttabulation\endcsname\empty
+ \expandafter\ifx\lastnamedcs\empty
+ \let\tabl_tabulate_insert_head\empty
+ \else
+ \let\tabl_tabulate_insert_head\tabl_tabulate_insert_head_content
+ \fi
+ \else
+ \let\tabl_tabulate_insert_head\empty
+ \fi
+ \ifcsname\??tabulatefoot\currenttabulation\endcsname
+ \expandafter\ifx\csname\??tabulatefoot\currenttabulation\endcsname\empty
+ %\expandafter\ifx\lastnamedcs\empty
+ \let\tabl_tabulate_insert_foot\empty
+ \else
+ \let\tabl_tabulate_insert_foot\tabl_tabulate_insert_foot_content
+ \fi
+ \else
+ \let\tabl_tabulate_insert_foot\empty
+ \fi}
+
+\def\tabl_tabulate_insert_content
+ {\tabl_tabulate_insert_head
+ \ifcase\c_tabl_tabulate_repeathead \else
+ \tabulatenoalign{\penalty\zerocount}% added 7/5/2014 WS mail
+ \fi
+ \tabl_tabulate_insert_body
+ \tabl_tabulate_insert_foot
+ \tabl_tabulate_remove_funny_line}
+
+\def\tabl_tabulate_remove_funny_line
+ {\ifhmode
+ \strut\crcr
+ \tabulatenoalign{\kern-\lineheight}%
+ \fi}
+
+% todo: make footer synonym to tail
+
+\setuvalue{\e!start\v!tabulatehead}{\doifelsenextoptionalcs\tabl_tabulate_start_head_yes\tabl_tabulate_start_head_nop}
+\setuvalue{\e!start\v!tabulatetail}{\doifelsenextoptionalcs\tabl_tabulate_start_foot_yes\tabl_tabulate_start_foot_nop}
+
+\let\m_tabl_tabulate_data\empty
+
+\def\tabl_tabulate_start_head_yes[#1]%
+ {\processcontent{\e!stop\v!tabulatehead}\m_tabl_tabulate_data{\letvalue{\??tabulatehead#1}\m_tabl_tabulate_data}}
+
+\def\tabl_tabulate_start_foot_yes[#1]%
+ {\processcontent{\e!stop\v!tabulatetail}\m_tabl_tabulate_data{\letvalue{\??tabulatefoot#1}\m_tabl_tabulate_data}}
+
+\def\tabl_tabulate_start_head_nop{\tabl_tabulate_start_head_yes[\v!tabulate]}
+\def\tabl_tabulate_start_foot_nop{\tabl_tabulate_start_foot_yes[\v!tabulate]}
+
+\unexpanded\def\tabl_start_defined[#1]%
+ {\bgroup
+ \edef\currenttabulationparent{#1}%
+ \let\currenttabulation\currenttabulationparent
+ \edef\p_format{\tabulationparameter\c!format}%
+ \ifx\p_format\v!none
+ % this is special case: we need to define the generic english
+ % \starttabulate in other interfaces as well
+ \expandafter\dodoubleempty \expandafter\tabl_start_regular
+ \else
+ \expandafter\dodoubleargument\expandafter\tabl_start_defined_indeed
+ \fi}
+
+\def\tabl_start_defined_indeed
+ {\iffirstargument
+ \ifsecondargument
+ \doubleexpandafter\tabl_start_defined_two
+ \else
+ \doubleexpandafter\tabl_start_defined_one
+ \fi
+ \else
+ \singleexpandafter\tabl_start_defined_zero
+ \fi}
+
+\def\tabl_start_defined_one[#1][#2]%
+ {\ifcondition\validassignment{#1}%
+ \setuptabulation[\currenttabulation][#1]%
+ \else
+ \edef\currenttabulation{\currenttabulation:#1}%
+ \fi
+ \tabl_tabulate_start_building}
+
+\def\tabl_start_defined_two[#1][#2]%
+ {\edef\currenttabulation{\currenttabulation:#1}%
+ \setuptabulation[\currenttabulation][#2]%
+ \tabl_tabulate_start_building}
+
+\def\tabl_start_defined_zero[#1][#2]%
+ {\tabl_tabulate_start_building}
+
+% \definetabulate[\v!tabulate][|l|p|] % we need to get rid of this one
+
+\unexpanded\setuvalue{\e!start\v!tabulate}%
+ {\bgroup % whole thing
+ \let\currenttabulationparent\empty
+ \dodoubleempty\tabl_start_regular}
+
+\def\tabl_start_regular
+ {\let\currenttabulation\currenttabulationparent
+ \ifsecondargument
+ \expandafter\tabl_start_regular_two
+ \else
+ \expandafter\tabl_start_regular_one
+ \fi}
+
+\def\tabl_default_format{|l|p|}
+
+\def\tabl_start_regular_one[#1][#2]%
+ {\ifcondition\validassignment{#1}%
+ \lettabulationparameter\c!format\tabl_default_format
+ \setupcurrenttabulation[#1]%
+ \else
+ \def\p_format{#1}%
+ \ifx\p_format\empty
+ \def\p_format{|l|p|}%
+ \fi
+ \lettabulationparameter\c!format\p_format
+ \fi
+ \tabl_tabulate_start_building}
+
+\def\tabl_start_regular_two[#1][#2]%
+ {\def\p_format{#1}%
+ \ifx\p_format\empty
+ \let\p_format\tabl_default_format
+ \fi
+ \lettabulationparameter\c!format\p_format
+ \setupcurrenttabulation[#2]%
+ \tabl_tabulate_start_building}
+
+\letvalue{\e!stop\v!tabulate }\relax
+\letvalue{\e!stop\v!tabulatehead}\relax
+\letvalue{\e!stop\v!tabulatetail}\relax
+
+\unexpanded\def\tabl_tabulate_start_ignore
+ {\em Nested tabulate is not (yet) supported.\relax
+ \expandafter\gobbleuntil\csname\ifconditional\c_tabl_generic stoptabulate\else\e!stop\v!tabulate\fi\endcsname}
+
+\appendtoks
+ \letvalue{\e!start\v!tabulate}\tabl_tabulate_start_ignore % only the main one
+\to \everytabulate
+
+\setvalue{\??tabulatesplit\v!yes }{\settrue\c_tabl_tabulate_split}
+\setvalue{\??tabulatesplit\v!repeat}{\settrue\c_tabl_tabulate_split}
+\setvalue{\??tabulatesplit\v!no }{\setfalse\c_tabl_tabulate_split}
+\setvalue{\??tabulatesplit\v!auto }{\ifinsidefloat\ifinsidesplitfloat\else\setfalse\c_tabl_tabulate_split\fi\fi}
+
+% todo: spacing around tabulate when bodyfont is set
+
+% \let\tabl_tabulate_inside_before \relax
+% \let\tabl_tabulate_inside_after \relax
+% \let\tabl_tabulate_inside_inbetween\relax
+%
+% \def\tabl_tabulate_outside_before
+% {\whitespace
+% \tabulationparameter\c!before}
+%
+% \def\tabl_tabulate_outside_after
+% {\tabulationparameter\c!after}
+
+% \showboxes
+%
+% \startcombination
+% {\insidefloattrue \starttabulate[|||] \NC test \NC test \NC \NR \stoptabulate} {}
+% {\insidefloattrue \starttabulate[|||] \NC test \NC test \NC \NR \stoptabulate} {}
+% \stopcombination
+%
+% \startcombination
+% {\vbox{\starttabulate[|||] \NC test \NC test \NC \NR \stoptabulate}} {}
+% {\vbox{\starttabulate[|||] \NC test \NC test \NC \NR \stoptabulate}} {}
+% \stopcombination
+%
+% \startcombination
+% {\starttabulate[|||] \NC test \NC test \NC \NR \stoptabulate} {}
+% {\starttabulate[|||] \NC test \NC test \NC \NR \stoptabulate} {}
+% \stopcombination
+
+\let\tabl_tabulate_inside_after \relax
+\let\tabl_tabulate_outside_after \relax
+\let\tabl_tabulate_inside_inbetween \relax
+\let\tabl_tabulate_outside_inbetween\relax
+
+\unexpanded\def\tabl_tabulate_inside_before
+ {\ifhmode\par\fi
+ \ifhmode
+ \ifinsidesplitfloat
+ \let\tabl_tabulate_inside_after\relax
+ \else
+ \vbox\bgroup
+ \let\tabl_tabulate_inside_after\egroup
+ \fi
+ \else
+ \let\tabl_tabulate_inside_after\relax
+ \fi}
+
+\unexpanded\def\tabl_tabulate_outside_before
+ {\ifhmode\par\fi
+ \ifhmode
+ \vbox\bgroup
+ \let\tabl_tabulate_outside_after \egroup
+ \let\tabl_tabulate_outside_inbetween\relax
+ \orelse\ifinner
+ \let\tabl_tabulate_outside_after \relax
+ \let\tabl_tabulate_outside_inbetween\relax
+ \else
+ \whitespace
+ \tabulationparameter\c!before
+ \relax
+ \let\tabl_tabulate_outside_after \tabl_tabulate_outside_after_indeed
+ \let\tabl_tabulate_outside_inbetween\tabl_tabulate_outside_inbetween_indeed
+ \fi}
+
+\def\tabl_tabulate_outside_after_indeed
+ {\tabulationparameter\c!after}
+
+\def\tabl_tabulate_outside_inbetween_indeed
+ {\doifempty{\tabulationparameter\c!after}
+ {\vskip\strutdp
+ \verticalstrut
+ \vskip-\struttotal}}
+
+\def\tabl_tabulate_inside_inbetween % needs checking
+ {\doifempty{\tabulationparameter\c!after}
+ {\vskip\strutdp
+ \verticalstrut
+ \vskip-\struttotal}}
+
+\unexpanded\def\tabl_tabulate_start_building
+ {\ifinsidefloat
+ \tabl_tabulate_inside_before
+ \else
+ \tabl_tabulate_outside_before
+ \fi
+ \bgroup % settings
+ %
+ \t_tabl_tabulate_preamble\emptytoks
+ \t_tabl_tabulate_dummy \emptytoks
+ %
+ \resetcharacteralign
+ %
+ \edef\p_distance {\tabulationparameter\c!distance}%
+ \edef\p_align {\tabulationparameter\c!align}%
+ \edef\p_line {\tabulationparameter\c!rule}%
+ \edef\p_rulecolor {\tabulationparameter\c!rulecolor}%
+ \edef\p_rulethickness{\tabulationparameter\c!rulethickness}%
+ \edef\p_bodyfont {\tabulationparameter\c!bodyfont}
+ \edef\p_indenting {\tabulationparameter\c!indenting}%
+ \edef\p_keeptogether {\tabulationparameter\c!keeptogether}%
+ \edef\p_blank {\tabulationparameter\c!blank}%
+ %
+ \ifx\p_keeptogether\v!no
+ \settrue \c_tabl_tabulate_tolerant_break
+ %\setfalse\c_tabl_tabulate_handlepbreak
+ \else
+ \setfalse\c_tabl_tabulate_tolerant_break
+ %\settrue \c_tabl_tabulate_handlepbreak
+ \fi
+ %
+ \settrue\c_tabl_tabulate_split
+ \begincsname\??tabulatesplit\tabulationparameter\c!split\endcsname
+ %
+ \let\m_tabl_tabulate_blank_default\p_blank
+ %
+ \d_tabl_tabulate_unit\tabulationparameter\c!unit
+ \d_tabl_tabulate_margin\tabulationparameter\c!margin
+ \let\m_tabl_tabulate_vrule_color_default\p_rulecolor
+ \let\m_tabl_tabulate_hrule_color_default\p_rulecolor
+ \d_tabl_tabulate_vrulethickness_default\p_rulethickness
+ \d_tabl_tabulate_hrulethickness_default\p_rulethickness
+ \ifx\p_bodyfont\empty\else
+ \switchtobodyfont[\p_bodyfont]%
+ \fi
+ \postponenotes % new, to be tested / will be configurable
+ \widowpenalty\zerocount % otherwise lines are not broken
+ \clubpenalty \zerocount % but overlap in funny ways
+ \the\everytabulate
+ \tabulationparameter\c!inner
+ \d_tabl_tabulate_indent\dimexpr\leftskip+\hangindent\ifx\p_indenting\v!yes+\parindent\fi\relax
+ \global\c_tabl_tabulate_column\zerocount
+ \processcontent
+ {\ifconditional\c_tabl_generic stoptabulate\else\e!stop\ifx\currenttabulationparent\empty\v!tabulate\else\currenttabulationparent\fi\fi}
+ \tabl_tabulate_insert_body
+ \tabl_tabulate_process}
+
+\def\tabulateEQ
+ {\ifconditional\c_tabl_tabulate_firstflushed\else
+ \dostarttaggedchained\t!ignore\empty\empty
+ \dostarttagged\t!ignore\empty
+ \tabulationparameter{EQ}%
+ \dostoptagged
+ \dostoptagged
+ \fi
+ \global\setfalse\c_tabl_tabulate_equal}
+
+% The next ones will be token registers
+
+\let\tabulatenormalpos\relax % hooks, todo
+\let\tabulateequalpos \relax % hooks, todo
+
+% color columns
+
+\let\m_tabl_tabulate_color_previous \empty
+\let\m_tabl_tabulate_color \empty
+\let\m_tabl_tabulate_text_color \empty
+\let\m_tabl_tabulate_color_local \empty
+\let\m_tabl_tabulate_vrule_color \empty
+\let\m_tabl_tabulate_vrule_color_local \empty
+\let\m_tabl_tabulate_vrule_color_default\empty % used local
+\let\m_tabl_tabulate_hrule_color_default\empty % used local
+\let\m_tabl_tabulate_blank_default \empty
+
+\appendtoks
+ \glet\m_tabl_tabulate_color_previous \empty
+ \glet\m_tabl_tabulate_color \empty
+ \glet\m_tabl_tabulate_text_color \empty
+ \glet\m_tabl_tabulate_color_local \empty
+ \glet\m_tabl_tabulate_vrule_color \empty
+ \glet\m_tabl_tabulate_vrule_color_local \empty
+ \global \d_tabl_tabulate_vrulethickness_local\zeropoint
+\to \t_tabl_tabulate_every_row
+
+\unexpanded\def\tabl_tabulate_color_side_right_second
+ {\ifx\m_tabl_tabulate_color_previous\empty \else
+ \tabl_tabulate_color_set\m_tabl_tabulate_color_previous
+ \glet\m_tabl_tabulate_color_previous\empty
+ \fi}
+
+\unexpanded\def\tabl_tabulate_color_side_left_second
+ {\ifx\m_tabl_tabulate_color\empty \else
+ \ifcase\c_tabl_tabulate_colorspan
+ \or
+ \tabl_tabulate_color_set\m_tabl_tabulate_color
+ \or
+ \tabl_tabulate_color_set\m_tabl_tabulate_color
+ \fi
+ \fi}
+
+\unexpanded\def\tabl_tabulate_color_side_both_second
+ {\ifx\m_tabl_tabulate_color\empty \else
+ \tabl_tabulate_color_set\m_tabl_tabulate_color
+ \ifcase\c_tabl_tabulate_colorspan
+ %\glet\m_tabl_tabulate_color_previous\empty
+ \or
+ \glet\m_tabl_tabulate_color_previous\empty
+ \or
+ \glet\m_tabl_tabulate_color_previous\m_tabl_tabulate_color
+ \or
+ \glet\m_tabl_tabulate_color_previous\m_tabl_tabulate_color
+ \fi
+ \fi}
+
+\let\tabl_tabulate_color_side_right \relax
+\let\tabl_tabulate_color_side_left \relax
+\let\tabl_tabulate_color_side_both \relax
+
+\appendtoks
+ \let\tabl_tabulate_color_side_right\tabl_tabulate_color_side_right_second
+ \let\tabl_tabulate_color_side_left \tabl_tabulate_color_side_left_second
+ \let\tabl_tabulate_color_side_both \tabl_tabulate_color_side_both_second
+\to \t_tabl_tabulate_initializers_second
+
+\def\tabl_tabulate_set_color_column#1% overloaded
+ {\unskip
+ \doifelsefastoptionalcheck{\tabl_tabulate_set_color_column_yes#1}{\tabl_tabulate_set_color_column_nop#1}}
+
+\def\tabl_tabulate_set_color_column_nop
+ {\tabl_tabulate_column_normal\zerocount}
+
+\def\tabl_tabulate_set_color_column_yes#1[#2]%
+ {\xdef\m_tabl_tabulate_color_local{#2}%
+ \tabl_tabulate_column_normal\zerocount#1}
+
+% normal columns:
+
+\def\tabl_tabulate_column_normal#1#2%
+ {\unskip
+ \aligntab
+ \ifconditional\c_tabl_tabulate_equal\tabulateequalpos\else\tabulatenormalpos\fi
+ \ifnum\c_tabl_tabulate_column>\c_tabl_tabulate_max_vrulecolumn\else
+ \tabl_tabulate_column_vrule_setup
+ \fi
+ \aligntab
+ \global\c_tabl_tabulate_kind#1%
+ \global\c_tabl_tabulate_type#2%
+ \aligntab}
+
+% equal columns
+
+\def\tabl_tabulate_column_equal#1#2%
+ {\unskip
+ \aligntab
+ \tabulateequalpos
+ \aligntab
+ \global\c_tabl_tabulate_kind#1%
+ \global\c_tabl_tabulate_type#2%
+ \aligntab}
+
+% ruled columns
+
+\def\tabl_tabulate_column_vruled_preset
+ {\glet\m_tabl_tabulate_vrule_color_local\m_tabl_tabulate_vrule_color_default
+ \global\d_tabl_tabulate_vrulethickness_local\d_tabl_tabulate_vrulethickness_default}
+
+\def\tabl_tabulate_column_vruled#1#2%
+ {\unskip % 0-n
+ %\ifnum\c_tabl_tabulate_column=\plusone
+ % \global\c_tabl_tabulate_has_rule_spec_first\plusone
+ %\orelse\ifnum\c_tabl_tabulate_column=\c_tabl_tabulate_nofcolumns
+ % \global\c_tabl_tabulate_has_rule_spec_last\plusone
+ %\fi
+ \ifnum\c_tabl_tabulate_column>\c_tabl_tabulate_max_vrulecolumn
+ \global\c_tabl_tabulate_max_vrulecolumn\c_tabl_tabulate_column
+ \fi
+ \doifelsefastoptionalcheck{\tabl_tabulate_column_vruled_yes#1#2}{\tabl_tabulate_column_vruled_nop#1#2}}
+
+\def\tabl_tabulate_column_vrule_setup
+ {\begincsname\??tabulatevrule\the\c_tabl_tabulate_column\endcsname}
+
+\def\tabl_tabulate_column_vruled_nop
+ {\expandafter\glet\csname\??tabulatevrule\the\c_tabl_tabulate_column\endcsname\tabl_tabulate_column_vruled_preset
+ \tabl_tabulate_column_normal}
+
+\def\tabl_tabulate_column_vruled_step#1%
+ {\doifelsenumber{#1}
+ {\global\d_tabl_tabulate_vrulethickness_local#1\d_tabl_tabulate_vrulethickness_default}
+ {\xdef\m_tabl_tabulate_vrule_color_local{#1}}}
+
+\def\tabl_tabulate_column_vruled_yes#1#2[#3]%
+ {\expandafter\gdef\csname\??tabulatevrule\the\c_tabl_tabulate_column\endcsname
+ {\tabl_tabulate_column_vruled_preset
+ \rawprocesscommalist[#3]\tabl_tabulate_column_vruled_step}%
+ \tabl_tabulate_column_normal#1#2}
+
+\def\tabl_tabulate_vrule_reset
+ {\ifcase\c_tabl_tabulate_max_vrulecolumn\else
+ \tabl_tabulate_vrule_reset_indeed
+ \fi}
+
+\def\tabl_tabulate_vrule_reset_indeed
+ {\dofastloopcs\c_tabl_tabulate_max_vrulecolumn\tabl_tabulate_vrule_reset_step
+ \global\c_tabl_tabulate_max_vrulecolumn\zerocount}
+
+\def\tabl_tabulate_vrule_reset_step % undefined or relax
+ {\expandafter\glet\csname\??tabulatevrule\the\fastloopindex\endcsname\undefined}
+
+\appendtoks
+ \tabl_tabulate_vrule_reset
+\to \t_tabl_tabulate_every_after_row
+
+% sometimes more efficient:
+%
+% \def\tabl_tabulate_column_vruled_yes#1#2[#3]%
+% {\rawprocesscommalist[#3]\tabl_tabulate_column_vruled_step
+% \expandafter\xdef\csname\??tabulatevrule\the\c_tabl_tabulate_column\endcsname
+% {\global\d_tabl_tabulate_vrulethickness_local\the\d_tabl_tabulate_vrulethickness_default
+% \noexpand\xdef\noexpand\m_tabl_tabulate_vrule_color_local{\m_tabl_tabulate_vrule_color_local}}%
+% \tabl_tabulate_column_normal#1#2}
+
+\def\tabl_tabulate_column_vruled_normal
+ {\vrule\s!width\d_tabl_tabulate_vrulethickness\relax}
+
+\def\tabl_tabulate_column_vruled_colored
+ {\dousecolorparameter\m_tabl_tabulate_vrule_color
+ \vrule\s!width\d_tabl_tabulate_vrulethickness\relax}
+
+\unexpanded\def\tabl_tabulate_column_vrule_inject_first
+ {\ifcase\d_tabl_tabulate_vrulethickness\else
+ \tabl_tabulate_column_vruled_normal % could be a skip instead
+ \fi
+ \global\d_tabl_tabulate_vrulethickness\zeropoint} % nils second one
+
+\unexpanded\def\tabl_tabulate_column_vrule_inject_second
+ {\ifcase\d_tabl_tabulate_vrulethickness\else
+ \ifx\m_tabl_tabulate_vrule_color\empty
+ \tabl_tabulate_column_vruled_normal
+ \else
+ \tabl_tabulate_column_vruled_colored
+ \fi
+ \fi
+ \global\d_tabl_tabulate_vrulethickness\zeropoint} % nils second one
+
+\let\tabl_tabulate_column_vrule_inject\relax
+
+\appendtoks
+ \let\tabl_tabulate_column_vrule_inject\tabl_tabulate_column_vrule_inject_first
+\to \t_tabl_tabulate_initializers_first
+
+\appendtoks
+ \let\tabl_tabulate_column_vrule_inject\tabl_tabulate_column_vrule_inject_second
+\to \t_tabl_tabulate_initializers_second
+
+% auto columns
+
+\def\tabl_tabulate_column_inject_auto
+ {\tabl_tabulate_column_normal\zerocount\zerocount
+ \ifnum\c_tabl_tabulate_column>\c_tabl_tabulate_columns\relax
+ \expandafter\NR
+ \else
+ \expandafter\ignorespaces % interferes with the more tricky hooks
+ \fi}
+
+\unexpanded\def\setquicktabulate#1% see \startlegend \startgiven (for the moment still public)
+ {\let#1\tabl_tabulate_column_inject_auto
+ \let\\\tabl_tabulate_column_inject_auto} % brrr, will go
+
+\setvalue{\??tabulateseparator\v!blank }{\s_tabl_tabulate_separator\bigskipamount}
+\setvalue{\??tabulateseparator\v!depth }{\s_tabl_tabulate_separator\strutdp}
+\setvalue{\??tabulateseparator\v!small }{\def\m_tabl_tabulate_separator_factor{.25}}
+\setvalue{\??tabulateseparator\v!medium}{\def\m_tabl_tabulate_separator_factor{.5}}
+\setvalue{\??tabulateseparator\v!big }{}
+\setvalue{\??tabulateseparator\v!none }{\s_tabl_tabulate_separator\zeropoint\let\m_tabl_tabulate_separator_factor\zerocount}
+\setvalue{\??tabulateseparator\v!grid }{\s_tabl_tabulate_separator\zeropoint\let\m_tabl_tabulate_separator_factor\zerocount}
+
+\def\tabl_tabulate_column_rule_separator_step#1%
+ {\ifcsname\??tabulateseparator#1\endcsname
+ \lastnamedcs
+ \else
+ \s_tabl_tabulate_separator#1\relax
+ \fi}
+
+\def\tabl_tabulate_column_rule_separator_inject % can be sped up (will do when used frequently)
+ {\bgroup
+ \s_tabl_tabulate_separator\strutdp
+ \ifx\p_distance\empty\else
+ \let\m_tabl_tabulate_separator_factor\plusone
+ \processcommacommand[\p_distance]\tabl_tabulate_column_rule_separator_step
+ \s_tabl_tabulate_separator\m_tabl_tabulate_separator_factor\s_tabl_tabulate_separator
+ \fi
+ % someamble: footer or header: unfortunately a skip can trigger a page break (weird
+ % as we have lots of nobreaks)
+ % \ifconditional\c_tabl_tabulate_someamble\kern\else\vskip\fi\s_tabl_tabulate_separator % new
+ % \directvspacing{\the\s_tabl_tabulate_separator}% new
+ \directvskip\s_tabl_tabulate_separator
+ \egroup}
+
+\def\tabl_tabulate_hrule_spec_ignore#1%
+ {%\glet\currenttabulationlocalhrulecolor\empty
+ %\global\d_tabl_tabulate_hrulethickness_local\d_tabl_tabulate_hrulethickness_default
+ \doifelsefastoptionalcheck#1#1}
+
+\def\tabl_tabulate_hrule_spec_pickup#1%
+ {\glet\currenttabulationlocalhrulecolor\m_tabl_tabulate_hrule_color_default
+ \global\d_tabl_tabulate_hrulethickness_local\d_tabl_tabulate_hrulethickness_default
+ \doifelsefastoptionalcheck{\tabl_tabulate_hrule_preset#1}#1}
+
+\def\tabl_tabulate_hrule_preset_step#1%
+ {\doifelsenumber{#1}
+ {\global\d_tabl_tabulate_hrulethickness_local#1\d_tabl_tabulate_hrulethickness_default}
+ {\xdef\currenttabulationlocalhrulecolor{#1}}}
+
+\def\tabl_tabulate_hrule_preset#1[#2]%
+ {\rawprocesscommalist[#2]\tabl_tabulate_hrule_preset_step
+ #1}
+
+\def\tabl_tabulate_hrule_inject_normal
+ {\autorule
+ \s!height.5\d_tabl_tabulate_hrulethickness_local
+ \s!depth .5\d_tabl_tabulate_hrulethickness_local
+ \s!left \d_tabl_tabulate_indent
+ \relax}
+
+\def\tabl_tabulate_hrule_inject_colored
+ {\dousecolorparameter\currenttabulationlocalhrulecolor
+ \tabl_tabulate_hrule_inject_normal}
+
+\unexpanded\def\tabl_tabulate_hrule_inject_first
+ {\ifcase\d_tabl_tabulate_hrulethickness_local\else
+ \tabl_tabulate_hrule_inject_normal
+ \fi}
+
+\unexpanded\def\tabl_tabulate_hrule_inject_second
+ {\ifcase\d_tabl_tabulate_hrulethickness_local\else
+ \ifx\currenttabulationlocalhrulecolor\empty
+ \tabl_tabulate_hrule_inject_normal
+ \else
+ \tabl_tabulate_hrule_inject_colored
+ \fi
+ \fi}
+
+\let\tabl_tabulate_hrule_inject\relax
+
+\appendtoks
+ \let\tabl_tabulate_hrule_inject\tabl_tabulate_hrule_inject_first
+\to \t_tabl_tabulate_initializers_first
+
+\appendtoks
+ \let\tabl_tabulate_hrule_inject\tabl_tabulate_hrule_inject_second
+\to \t_tabl_tabulate_initializers_second
+
+%D Color:
+
+% \starttabulate[||p||]
+% \NC test \NC test \NC test \NC \NR
+% \NC test \CC[green] \input tufte \CC[yellow] test \NC \NR
+% \NC test \NC test \NC test \NC \NR
+% \NC test \NC test \NC test \NC \NR
+% \NC test \NC test \NC test \NC \NR
+% \NC test \NC test \NC test \NC \NR
+% \CC[blue] test \CC[red] test \NC test \NC \NR
+% \NC test \NC test \NC test \NC \NR
+% \NC test \NC test \NC test \NC \NR
+% \NC test \NC test \NC test \NC \NR
+% \NC test \NC test \CC[gray] test \NC \NR
+% \NC test \NC test \NC test \NC \NR
+% \NC test \NC test \NC test \NC \NR
+% \CC[blue] test \NC test \NC test \NC \NR
+% \NC test \NC test \NC test \NC \NR
+% \NC test \NC test \CC[magenta] test \NC \NR
+% \NC test \NC test \NC test \NC \NR
+% \NC test \CC[cyan] \dorecurse{10}{\input ward }\NC test \NC \NR
+% \NC test \NC test \NC test \NC \NR
+% \NC test \CC[yellow] test \NC test \NC \NR
+% \stoptabulate
+
+\unexpanded\def\tabl_tabulate_color_set#1% we could store the attributes at the cost of a lua call
+ {\begingroup
+ \clf_enablebackgroundalign % was \node_backgrounds_align_initialize
+ \glet\tabl_tabulate_color_repeat\tabl_tabulate_color_repeat_second
+ \global\settrue\c_tabl_tabulate_has_colors
+ \ifnum\c_tabl_tabulate_column>\c_tabl_tabulate_max_colorcolumn
+ \global\c_tabl_tabulate_max_colorcolumn\c_tabl_tabulate_column
+ \fi
+ \expandafter\xdef\csname\??tabulatecolor\the\c_tabl_tabulate_column\endcsname{#1}%
+ \hpack \thealignbackgroundcolorattr{#1}{}% pack ?
+ \endgroup}
+
+\def\tabl_tabulate_color_repeat_second % for split off lines
+ {\begingroup
+ \scratchcounter\numexpr\c_tabl_tabulate_column-\plusone\relax % ugly !
+ \ifcsname\??tabulatecolor\the\scratchcounter\endcsname
+ % \hbox \thealignbackgroundcolorattr{\csname\??tabulatecolor\the\scratchcounter\endcsname}{}% pack ?
+ \hpack \expandafter\thealignbackgroundcolorattr\expandafter{\lastnamedcs}{}% pack ?
+ \fi
+ \endgroup}
+
+\let\tabl_tabulate_color_repeat\relax
+
+\appendtoks
+ \let\tabl_tabulate_color_repeat\relax
+\to \everytabulate
+
+\def\tabl_tabulate_color_reset
+ {\ifcase\c_tabl_tabulate_max_colorcolumn\else
+ \tabl_tabulate_color_reset_indeed
+ \fi}
+
+% \def\tabl_tabulate_color_reset_indeed
+% {\dorecurse\c_tabl_tabulate_max_colorcolumn{\letgvalue{\??tabulatecolor\recurselevel}\undefined}} % slow
+
+\def\tabl_tabulate_color_reset_indeed
+ {\dofastloopcs\c_tabl_tabulate_max_colorcolumn\tabl_tabulate_color_reset_step}
+
+\def\tabl_tabulate_color_reset_step % undefined or empty?
+ {\expandafter\glet\csname\??tabulatecolor\number\fastloopindex\endcsname\undefined}
+
+\appendtoks
+ \tabl_tabulate_color_reset
+\to \t_tabl_tabulate_every_after_row
+
+% \def\tabl_tabulate_register_par_options_indeed
+% {\iftrialtypesetting \else
+% \registerparoptions
+% \ifinsidefloat
+% % that is, an unbreakable one
+% \glet\tabl_tabulate_register_par_options\empty
+% \else
+% % unsafe in crossing pages, at each b...
+% % \glet\tabl_tabulate_register_par_options\empty
+% \fi
+% \fi}
+%
+% \appendtoks
+% \glet\tabl_tabulate_register_par_options\tabl_tabulate_register_par_options_indeed
+% \to \everytabulate
+
+\def\tabl_tabulate_register_par_options_first % maybe track here if needed
+ {}
+
+\def\tabl_tabulate_register_par_options_second
+ {\registerparoptions
+ \ifinsidefloat
+ % that is, an unbreakable one
+ \glet\tabl_tabulate_register_par_options\empty
+ \else
+ % unsafe in crossing pages, at each b...
+ % \glet\tabl_tabulate_register_par_options\empty
+ \fi}
+
+\let\tabl_tabulate_register_par_options\relax
+
+\appendtoks
+ \let\tabl_tabulate_register_par_options\tabl_tabulate_register_par_options_first
+\to \t_tabl_tabulate_initializers_first
+
+\appendtoks
+ \let\tabl_tabulate_register_par_options\tabl_tabulate_register_par_options_second
+\to \t_tabl_tabulate_initializers_second
+
+\appendtoks
+ \tabl_tabulate_register_par_options
+\to \t_tabl_tabulate_every_row
+
+\def\tabl_tabulate_flush_indent_indeed
+ {\hbox to \d_tabl_tabulate_indent % pack ?
+ {% we now have a local hsize, and since we want to
+ % register positional info (i.e. real hsizes) we
+ % need to reconstitute the original hsize
+ \advance\hsize\d_tabl_tabulate_indent
+ % this is indeed rather messy and took a few hours
+ % to dis/uncover
+ \the\t_tabl_tabulate_every_row
+ \hss}}
+
+\def\tabl_tabulate_flush_indent
+ {\ifnum\c_tabl_tabulate_column=\zerocount
+ \tabl_tabulate_flush_indent_indeed
+ \fi}
+
+\def\tabl_tabulate_digits{\digits}
+
+%D Beware, we cannot use \type {\unexpanded} on \type {\HL} cum suis, since \TEX's
+%D hard coded noalign lookahead fails on it! I mistakenly added this for a while.
+
+\setvalue{\??tabulatealigning\v!normal}{0}
+\setvalue{\??tabulatealigning\v!right }{1}
+\setvalue{\??tabulatealigning\v!left }{2}
+\setvalue{\??tabulatealigning\v!middle}{3}
+
+\setvalue{\??tabulateheader\v!repeat}{\plusone}
+\setvalue{\??tabulateheader\v!text }{\plustwo}
+
+\unexpanded\def\tabl_tabulate_bskip_first {\setbox\b_tabl_tabulate\vbox\bgroup\glet\tabl_tabulate_hook\tabl_tabulate_hook_nop}
+\unexpanded\def\tabl_tabulate_eskip_first {\par\egroup\glet\tabl_tabulate_hook\tabl_tabulate_hook_yes}
+\unexpanded\def\tabl_tabulate_xbskip_first{\hpack\bgroup\vbox\bgroup\glet\tabl_tabulate_hook\tabl_tabulate_hook_nop}
+\unexpanded\def\tabl_tabulate_xeskip_first{\par\egroup\egroup\glet\tabl_tabulate_hook\tabl_tabulate_hook_yes}
+
+\let\tabl_tabulate_bbskip\relax
+\let\tabl_tabulate_eeskip\relax
+\let\tabl_tabulate_bskip \relax
+\let\tabl_tabulate_eskip \relax
+\let\tabl_tabulate_xbskip\relax
+\let\tabl_tabulate_xeskip\relax
+
+\appendtoks
+ \let\tabl_tabulate_bbskip\relax
+ %\let\tabl_tabulate_eeskip\relax % adapted by bskip
+ \let\tabl_tabulate_bskip \tabl_tabulate_bskip_first
+ \let\tabl_tabulate_eskip \tabl_tabulate_eskip_first
+ \let\tabl_tabulate_xbskip\tabl_tabulate_xbskip_first
+ \let\tabl_tabulate_xeskip\tabl_tabulate_xeskip_first
+\to \t_tabl_tabulate_initializers_first
+
+\def\tabl_tabulate_baselinecorrection % keep an eye on this one
+ {\def\dobaselinecorrection{\vskip\dimexpr-\prevdepth+\strutdp+\strutdp\relax}% todo: mkiv
+ \baselinecorrection}
+
+% some hack to prevent an allowbreak ... actually we could set up a system then
+% that is dealt with atthe lua end in the skip handler: turn penalties with attributes
+% values into other penalties that get removed
+
+\installcorenamespace{tabulatenobreak}
+
+\def\tabl_tabulate_break_allow{\directvpenalty\zerocount}
+\def\tabl_tabulate_break_maybe{\directvpenalty\zerocount}
+\def\tabl_tabulate_break_no {\directvpenalty\plustenthousand} % ,order:2}}
+
+\let\tabl_tabulate_break_state_set \relax
+\let\tabl_tabulate_break_state_reset \relax
+\let\tabl_tabulate_break_state_allowbreak\tabl_tabulate_break_maybe
+
+% so far
+
+\unexpanded\def\tabl_tabulate_VL_first{\tabl_tabulate_column_vruled\zerocount\zerocount}
+\unexpanded\def\tabl_tabulate_NC_first{\tabl_tabulate_column_normal\zerocount\zerocount}
+\unexpanded\def\tabl_tabulate_RC_first{\tabl_tabulate_column_normal\zerocount\plusone}
+\unexpanded\def\tabl_tabulate_HC_first{\tabl_tabulate_column_normal\zerocount\plustwo}
+\unexpanded\def\tabl_tabulate_EQ_first{\tabl_tabulate_column_equal \plustwo \zerocount}
+\unexpanded\def\tabl_tabulate_RQ_first{\tabl_tabulate_column_equal \zerocount\plusone}
+\unexpanded\def\tabl_tabulate_HQ_first{\tabl_tabulate_column_equal \zerocount\plustwo}
+
+\unexpanded\def\tabl_tabulate_NG_first{\tabl_tabulate_column_normal\zerocount\zerocount}
+\unexpanded\def\tabl_tabulate_NN_first{\tabl_tabulate_column_normal\zerocount\zerocount\tabl_tabulate_digits} % new, undocumented, test first
+\unexpanded\def\tabl_tabulate_ND_first{\tabl_tabulate_column_normal\zerocount\zerocount\tabl_tabulate_digits} % same, for old times sake
+
+\unexpanded\def\tabl_tabulate_NR_first {\tabl_tabulate_NR_common\conditionaltrue \tabl_tabulate_check_penalties} % next row
+\unexpanded\def\tabl_tabulate_NB_first {\tabl_tabulate_NR_common\conditionaltrue \tabl_tabulate_nobreak_inject } % next row no break
+
+\unexpanded\def\tabl_tabulate_NR_second{\tabl_tabulate_NR_common\conditionalfalse\tabl_tabulate_check_penalties} % next row
+\unexpanded\def\tabl_tabulate_NB_second{\tabl_tabulate_NR_common\conditionalfalse\tabl_tabulate_nobreak_inject } % next row no break
+
+\unexpanded\def\tabl_tabulate_CC_first{\global\c_tabl_tabulate_localcolorspan\zerocount\tabl_tabulate_set_color_column\zerocount}
+\unexpanded\def\tabl_tabulate_CL_first{\global\c_tabl_tabulate_localcolorspan\plusone \tabl_tabulate_set_color_column\zerocount}
+\unexpanded\def\tabl_tabulate_CM_first{\global\c_tabl_tabulate_localcolorspan\plustwo \tabl_tabulate_set_color_column\zerocount}
+\unexpanded\def\tabl_tabulate_CR_first{\global\c_tabl_tabulate_localcolorspan\plusthree\tabl_tabulate_set_color_column\zerocount}
+
+%D Sort of special:
+%D
+%D \startbuffer
+%D \startitemize[n]
+%D \starttabulate[|||||]
+%D \NC p \NC \itemtag \NC q \NC r \NC \NR
+%D \NC p \NC \itemtag \NC q \NC r \NC \NR
+%D \NC p \NC \itemtag \NC q \NC r \NC \NR
+%D \NC p \NC \itemtag \NC q \NC r \NC \NR
+%D \stoptabulate
+%D \stopitemize
+%D
+%D \startitemize[n]
+%D \starttabulate[|||||]
+%D \NI b \NC c \NC d \NC \NR
+%D \NC a \NI c \NC d \NC \NR
+%D \NC a \NC b \NI d \NC \NR
+%D \NC a \NC b \NC c \NI \NR
+%D \stoptabulate
+%D \stopitemize
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+\unexpanded\def\tabl_tabulate_NI_first{\doifelsefastoptionalcheck\tabl_tbl_NI_yes\tabl_tbl_NI_nop}
+
+\def\tabl_tbl_NI_yes[#1]{\NC \itemtag[#1]\NC}
+\def\tabl_tbl_NI_nop {\NC \itemtag \NC}
+
+%D The following shortcut is handy for tables where one needs bold headers:
+
+\unexpanded\def\tabl_tabulate_BC_first
+ {\tabl_tabulate_column_normal\plusone\zerocount
+ \let\fontstyle\globalfontstyle
+ \bf}
+
+\appendtoks
+ \let\VL\tabl_tabulate_VL_first
+ \let\NC\tabl_tabulate_NC_first
+ \let\BC\tabl_tabulate_BC_first
+ \let\RC\tabl_tabulate_RC_first
+ \let\HC\tabl_tabulate_HC_first
+ \let\EQ\tabl_tabulate_EQ_first
+ \let\RQ\tabl_tabulate_RQ_first
+ \let\HQ\tabl_tabulate_HQ_first
+ \let\NG\tabl_tabulate_NG_first
+ \let\NN\tabl_tabulate_NN_first
+ \let\ND\tabl_tabulate_ND_first
+ \let\NR\tabl_tabulate_NR_first
+ \let\NB\tabl_tabulate_NB_first
+ \let\CC\tabl_tabulate_CC_first
+ \let\CL\tabl_tabulate_CL_first
+ \let\CM\tabl_tabulate_CM_first
+ \let\CR\tabl_tabulate_CR_first
+ \let\NI\tabl_tabulate_NI_first
+\to \t_tabl_tabulate_initializers_first
+
+\appendtoks
+ \let\NR\tabl_tabulate_NR_second
+ \let\NB\tabl_tabulate_NB_second
+\to \t_tabl_tabulate_initializers_second
+
+\appendtoks
+ \let\SR\NR
+ \let\FR\NR
+ \let\MR\NR
+ \let\LR\NR
+ \let\AR\NR
+\to \t_tabl_tabulate_initializers_first
+
+\unexpanded\def\tabl_tabulate_NR_common#1#2%
+ {\global\advance\c_tabl_tabulate_noflines\plusone
+ \global\setfalse\c_tabl_tabulate_firstflushed
+ \global\setfalse\c_tabl_tabulate_equal
+ \global\c_tabl_tabulate_column\zerocount
+ \ifconditional#1\relax
+ \tabl_tabulate_break_state_reset
+ \fi
+ \tabl_tabulate_pheight_reset
+ \unskip\unskip\crcr\tabl_tabulate_flush_collected
+ % can we omit the next one in the first run? probably
+ \starttabulatenoalign
+ \the\t_tabl_tabulate_every_after_row
+ #2%
+ \stoptabulatenoalign}
+
+\def\tabl_tabulate_check_penalties
+ {\ifconditional\c_tabl_tabulate_tolerant_break\else
+ \ifnum\c_tabl_tabulate_totalnoflines=\plusone
+ % \tabl_tabulate_break_allow
+ \else
+ \ifconditional\c_tabl_tabulate_someamble \ifcase\c_tabl_tabulate_repeathead \else
+ \tabl_tabulate_break_allow
+ \fi \fi
+ \ifnum\c_tabl_tabulate_noflines=\plusone
+ \tabl_tabulate_nobreak_inject
+ \orelse\ifnum\c_tabl_tabulate_noflines=\c_tabl_tabulate_minusnoflines
+ \ifnum\c_tabl_tabulate_plines_max<\plustwo
+ \tabl_tabulate_nobreak_inject
+ \else
+ \tabl_tabulate_break_allow % needed with pbreak prevention
+ \fi
+ \else
+ \tabl_tabulate_break_state_allowbreak
+ \fi
+ \fi
+ \fi
+ \global\setfalse\c_tabl_tabulate_firstflushed}
+
+\unexpanded\def\tabl_tabulate_bbskip_second_split_yes
+ {\ifvoid\b_tabl_tabulate_current\c_tabl_tabulate_column
+ \ifx\tabl_tabulate_flush_collected_indeed\empty\else
+ \setbox0\hbox
+ \fi
+ \fi}
+
+\unexpanded\def\tabl_tabulate_eskip_second
+ {\par\egroup
+ \tabl_tabulate_pheight_set
+ \glet\tabl_tabulate_hook\tabl_tabulate_hook_yes
+ \tabl_tabulate_splitoff_box}
+
+\unexpanded\def\tabl_tabulate_bskip_second_split_yes
+ {\ifvoid\b_tabl_tabulate_current\c_tabl_tabulate_column
+ % first line
+ \global\setbox\b_tabl_tabulate_current\c_tabl_tabulate_column\vbox
+ \bgroup
+ \glet\tabl_tabulate_hook\tabl_tabulate_hook_nop
+ \ifconditional\c_tabl_tabulate_automode\hsize\d_tabl_tabulate_width\fi
+ % \begstrut % interferes with pre-\pars
+ % evt: \appendtoks\begstrut\to\everypar
+ \ignorespaces
+ \let\tabl_tabulate_eskip\tabl_tabulate_eskip_second
+ \else
+ % successive lines
+ \let\tabl_tabulate_eskip\empty
+ \dontcomplain
+ \glet\tabl_tabulate_hook\tabl_tabulate_hook_yes
+ \expandafter\tabl_tabulate_splitoff_box
+ \fi}
+
+\unexpanded\def\tabl_tabulate_xbskip_second{\tabl_tabulate_bskip}
+\unexpanded\def\tabl_tabulate_xeskip_second{\tabl_tabulate_eskip}
+
+\unexpanded\def\tabl_tabulate_flush_second_indeed
+ {\glet\tabl_tabulate_flush_collected_indeed\empty
+ \global\c_tabl_tabulate_column\zerocount
+ \tabl_tabulate_pbreak_check
+ \dofastloopcs\c_tabl_tabulate_columns\tabl_tabulate_flush_second_step
+ \global\settrue\c_tabl_tabulate_firstflushed}
+
+\unexpanded\def\tabl_tabulate_flush_second_step
+ {\ifvoid\b_tabl_tabulate_current\fastloopindex\else
+ \gdef\tabl_tabulate_flush_collected_indeed{\the\t_tabl_tabulate_dummy}%
+ \fi}
+
+\def\tabl_tabulate_flush_second
+ {\tabulatenoalign{\tabl_tabulate_flush_second_indeed}%
+ \tabl_tabulate_flush_collected_indeed}
+
+\unexpanded\def\tabl_tabulate_bskip_second_split_nop
+ {\vtop\bgroup
+ \ifconditional\c_tabl_tabulate_automode\hsize\d_tabl_tabulate_width\fi
+ % \begstrut % interferes with pre-\pars
+ % evt: \appendtoks\begstrut\to\everypar
+ \ignorespaces}
+
+\unexpanded\def\tabl_tabulate_eskip_second_split_nop % vertical strut added august 2003
+ {\par\verticalstrut
+ \vskip-\struttotal
+ \egroup}
+
+% \let\tabl_tabulate_eskip \relax % adapted by bskip
+% \let\tabl_tabulate_eeskip\relax % adapted by bskip
+
+\appendtoks
+ \let\tabl_tabulate_xbskip\tabl_tabulate_xbskip_second
+ \let\tabl_tabulate_xeskip\tabl_tabulate_xeskip_second
+ \ifconditional\c_tabl_tabulate_split
+ \let\tabl_tabulate_bskip \tabl_tabulate_bskip_second_split_yes
+ \let\tabl_tabulate_bbskip\tabl_tabulate_bbskip_second_split_yes
+ \else
+ \let\tabl_tabulate_bskip \tabl_tabulate_bskip_second_split_nop
+ \let\tabl_tabulate_eskip \tabl_tabulate_eskip_second_split_nop
+ \fi
+\to \t_tabl_tabulate_initializers_second
+
+% see ***
+%
+% \enabletrackers[nodes.page_vspacing]
+% \starttext
+% \starttabulate[||] \dorecurse{100}{\NC Eins \NC \NR \HL} \stoptabulate
+% \stoptext
+
+\def\tabl_tabulate_XX_none
+ {\starttabulatenoalign
+ \tabl_tabulate_break_state_set
+ \tabl_tabulate_hrule_spec_ignore
+ \stoptabulatenoalign}
+
+\def\tabl_tabulate_FL_second{\starttabulatenoalign\tabl_tabulate_hrule_spec_pickup\tabl_tabulate_FL_second_indeed}
+\def\tabl_tabulate_ML_second{\starttabulatenoalign\tabl_tabulate_hrule_spec_pickup\tabl_tabulate_ML_second_indeed}
+\def\tabl_tabulate_LL_second{\starttabulatenoalign\tabl_tabulate_hrule_spec_pickup\tabl_tabulate_LL_second_indeed}
+\def\tabl_tabulate_TL_second{\starttabulatenoalign\tabl_tabulate_hrule_spec_pickup\tabl_tabulate_TL_second_indeed}
+\def\tabl_tabulate_BL_second{\starttabulatenoalign\tabl_tabulate_hrule_spec_pickup\tabl_tabulate_BL_second_indeed}
+
+\unexpanded\def\tabl_tabulate_FL_second_indeed
+ {\ifinsidefloat\else
+ \doifempty{\tabulationparameter\c!before}\tabl_tabulate_baselinecorrection % no expansion
+ \fi
+ \tabl_tabulate_hrule_inject
+ \tabl_tabulate_nobreak_inject
+ \tabl_tabulate_column_rule_separator_inject
+ \prevdepth\strutdp
+ \tabl_tabulate_nobreak_inject
+ \stoptabulatenoalign}
+
+\def\spac_vspacing_no_topskip % use grouped
+ {\attribute\skipcategoryattribute\plusten}
+
+\unexpanded\def\tabl_tabulate_ML_second_indeed
+ {\tabl_tabulate_break_no
+ \tabl_tabulate_column_rule_separator_inject
+ \tabl_tabulate_break_no
+ \tabl_tabulate_hrule_inject
+ \vskip-\p_rulethickness\relax
+ \begingroup
+ \spac_vspacing_no_topskip
+ \tabl_tabulate_hrule_inject
+ \endgroup
+ \tabl_tabulate_break_no
+ \tabl_tabulate_column_rule_separator_inject
+ \stoptabulatenoalign}
+
+\unexpanded\def\tabl_tabulate_LL_second_indeed
+ {\tabl_tabulate_nobreak_inject
+ \tabl_tabulate_column_rule_separator_inject
+ \tabl_tabulate_nobreak_inject
+ \tabl_tabulate_hrule_inject
+ \ifinsidefloat
+ \tabl_tabulate_inside_inbetween
+ \else
+ \tabl_tabulate_outside_inbetween
+ \fi
+ \stoptabulatenoalign}
+
+\unexpanded\def\tabl_tabulate_TL_second_indeed
+ {\tabl_tabulate_nobreak_inject
+ \tabl_tabulate_column_rule_separator_inject
+ \tabl_tabulate_nobreak_inject
+ \tabl_tabulate_hrule_inject
+ \tabl_tabulate_nobreak_inject
+ \tabl_tabulate_column_rule_separator_inject
+ %\prevdepth\strutdp % todo, might differ between TL and BL
+ \tabl_tabulate_nobreak_inject
+ \stoptabulatenoalign}
+
+\let\tabl_tabulate_BL_second_indeed\tabl_tabulate_TL_second_indeed
+
+\def\tabl_tabulate_HL_second
+ {\csname
+ \ifnum\c_tabl_tabulate_noflines=\zerocount F\orelse
+ \ifnum\c_tabl_tabulate_noflines=\c_tabl_tabulate_totalnoflines L\else
+ M\fi
+ L\endcsname}
+
+\appendtoks
+ \let\FL\tabl_tabulate_XX_none
+ \let\ML\tabl_tabulate_XX_none
+ \let\LL\tabl_tabulate_XX_none
+ \let\TL\tabl_tabulate_XX_none
+ \let\BL\tabl_tabulate_XX_none
+ \let\HL\tabl_tabulate_XX_none
+ \let\HR\tabl_tabulate_XX_none
+\to \t_tabl_tabulate_initializers_first
+
+\appendtoks
+ \let\FL\tabl_tabulate_FL_second
+ \let\ML\tabl_tabulate_ML_second
+ \let\LL\tabl_tabulate_LL_second
+ \let\TL\tabl_tabulate_TL_second
+ \let\BL\tabl_tabulate_BL_second
+ \let\HL\tabl_tabulate_HL_second
+ \let\HR\tabl_tabulate_HL_second
+\to \t_tabl_tabulate_initializers_second
+
+% \def\tabulatedoHRfive % horizontal rule line (break untested)
+% {\starttabulatenoalign
+% \glet\dotabulateautoline\dotabulatelinerule
+% %\ifcase#1\or % todo: check what this does
+% \ifnum\noftabulatelines=\zerocount
+% \glet\dotabulateautoline\donothing
+% \else\ifnum\noftabulatelines=\totalnoftabulatelines
+% \glet\dotabulateautoline\donothing
+% \fi\fi
+% %\fi
+% \dotabulatenobreak
+% \stoptabulatenoalign
+% \dotabulateautoline
+% \starttabulatenoalign
+% \tabl_tabulate_break_no
+% \ifx\dotabulateautoline\dotabulatelinerule\kern-\lineheight\fi
+% \ifnum\noftabulatelines=\totalnoftabulatelines
+% \expandafter\dotabulatenobreak
+% \else
+% \expandafter\tabl_tabulate_break_allow
+% \fi
+% \stoptabulatenoalign
+% \dotabulateautoline
+% \starttabulatenoalign
+% \dotabulatenobreak
+% \stoptabulatenoalign}
+
+% \dorecurse{10}{
+% \starttabulate[|l|]
+% \FL
+% \NC first line, bound to next rule \NC \NR
+% \TL
+% \NC bound to previous rule \NC \NR
+% \NC some line \NC \NR
+% \NC some line \NC \NR
+% \NC some line \NC \NR
+% \NC bound to next rule \NC \NR
+% \ML
+% \NC bound to previous rule \NC \NR
+% \NC bound to next rule \NC \NR
+% \BL
+% \NC last line, bound to previous rule \NC \NR
+% \LL
+% \stoptabulate
+% }
+
+% This needs checking:
+
+\def\tabulaterule {\HR} % a rule with lineheight
+\def\tabulateline {\HL} % just a spaced rule
+\def\tabulateautorule{\HR}%
+\def\tabulateautoline{\HL} % no longer different (to be looked into)
+
+%D When support for vertical rules we needed a way to pick up the specification for
+%D the final rule and a \type {|{}} interface was chosen. As a result parsing had to
+%D become more complex and I was not in the mood for messing up the code too much.
+%D Therefore from now on the preamble is split by \LUA. There are definitely more
+%D places where we can use \LUA\ code (for instance in alignment of numbers. The
+%D repeat parser is replace at the \LUA\ end as well.
+
+\let\tabl_tabulate_flush_collected \empty
+\let\tabl_tabulate_flush_collected_indeed\empty
+
+\let\v_tabl_tabulate_align\!!zerocount
+
+\def\tabl_tabulate_check_side_float % new per 29-07-2016
+ {\ifdefined\page_sides_check_floats_indeed
+ \page_sides_check_floats_indeed
+ \ifdim\hangindent>\zeropoint
+ \advance\d_tabl_tabulate_indent\hangindent
+ \fi
+ \fi}
+
+\def\tabl_tabulate_set_local_hsize
+ {\setlocalhsize
+ \hsize\localhsize}
+
+\def\tabl_tabulate_process
+ {\c_tabl_tabulate_pass\plusone
+ \tabl_tabulate_check_full_content
+ \edef\v_tabl_tabulate_align{\ifcsname\??tabulatealigning\p_align\endcsname\lastnamedcs\else0\fi}%
+ \s_tabl_tabulate_first.5\d_tabl_tabulate_unit
+ \s_tabl_tabulate_last\s_tabl_tabulate_first
+ \s_tabl_tabulate_pre\zeropoint
+ \s_tabl_tabulate_post\s_tabl_tabulate_first % was: \zeropoint
+ \global\c_tabl_tabulate_columns\zerocount
+ \global\c_tabl_tabulate_nofauto\zerocount
+ \global\c_tabl_tabulate_noflines\zerocount
+ \c_tabl_tabulate_totalnoflines\zerocount
+ \c_tabl_tabulate_minusnoflines\zerocount
+ \global\d_tabl_tabulate_width_p\zeropoint
+ \global\d_tabl_tabulate_width_w\zeropoint
+ \global\setfalse\c_tabl_tabulate_equal
+ \tabl_tabulate_pheight_reset
+ \tabskip\zeropoint
+ \ifinsidesplitfloat
+ \donetrue
+ \orelse\ifinsidefloat
+ \donefalse
+ \else
+ \donetrue
+ \fi
+ \global\c_tabl_tabulate_repeathead
+ \ifdone
+ \ifcsname\??tabulateheader\tabulationparameter\c!header\endcsname
+ \lastnamedcs
+ \else
+ \zerocount
+ \fi
+ \else
+ \zerocount
+ \fi
+ %
+ \the\t_tabl_tabulate_initializers_first % collect more here
+ %
+ \glet\tabl_tabulate_flush_collected\empty
+ \ifdim\d_tabl_tabulate_margin>\zeropoint
+ \t_tabl_tabulate_preamble
+ {\aligntab
+ \tabl_tabulate_flush_indent
+% \global\advance\c_tabl_tabulate_noflines\plusone
+ \strut
+ \alignmark\alignmark
+ \tabskip\d_tabl_tabulate_margin
+ \strut
+ \aligntab
+ \alignmark\alignmark
+ \tabskip\zeropoint}%
+ \else
+ \t_tabl_tabulate_preamble
+ {\aligntab
+ \tabl_tabulate_flush_indent
+% \global\advance\c_tabl_tabulate_noflines\plusone
+ \strut
+ \alignmark\alignmark
+ \aligntab
+ \alignmark\alignmark
+ \tabskip\zeropoint}%
+ \fi
+ \d_tabl_tabulate_width\zeropoint
+ % these counters are set at the lua end
+ \c_tabl_tabulate_nofcolumns \zerocount
+ \c_tabl_tabulate_has_rule_spec_first\zerocount
+ \c_tabl_tabulate_has_rule_spec_last \zerocount
+ \clf_presettabulate{\detokenizedtabulationparameter\c!format}%
+ %
+ % \edef\totaltabulatecolumns{\the\numexpr3*\c_tabl_tabulate_columns+\plusfour}%
+ \d_tabl_tabulate_width\zeropoint
+ \tabl_tabulate_initialize_boxes\c_tabl_tabulate_columns
+ \toksapp\t_tabl_tabulate_preamble{%
+ \aligntab\alignmark\alignmark
+ \global\advance\c_tabl_tabulate_column\plusone % maybe just set it already
+ }%
+ \toksapp\t_tabl_tabulate_dummy{%
+ \NC\unskip\unskip\crcr\tabl_tabulate_flush_collected % no count
+ }%
+ \global\c_tabl_tabulate_column\zerocount
+ \tabl_tabulate_pheight_reset
+ \glet\tabl_tabulate_hook\tabl_tabulate_hook_yes
+ \ifx\p_indenting\v!no
+ \forgetparindent
+ \fi
+ \ifinsidefloat
+ \d_tabl_tabulate_indent\zeropoint
+ \else
+ \tabl_tabulate_check_side_float
+ \tabl_tabulate_set_local_hsize
+ \fi
+ \dontcomplain
+ \forgetall % hm, interference with preceding \forgetparindent probably bug, to be solved
+ \everypar\everytabulatepar
+ \setbox\scratchbox\vbox % outside \if because of line counting
+ {\notesenabledfalse
+ \d_tabl_tabulate_indent\zeropoint
+ \settrialtypesetting % very important
+ \anch_backgrounds_text_level_start
+ \expandafter\halign\expandafter{\the\t_tabl_tabulate_preamble\crcr\tabl_tabulate_insert_content\crcr}}%
+ \anch_backgrounds_text_level_stop
+ \ifcase\c_anch_backgrounds_text_state\else
+ \global\settrue\tablehaspositions
+ \fi
+ \ifnum\c_tabl_tabulate_nofauto>\zerocount
+ % so, even if the natural size is larger, in the final run, we force the calculated width
+ \d_tabl_tabulate_width\dimexpr\hsize-\wd\scratchbox-\d_tabl_tabulate_width_p-\d_tabl_tabulate_width_w\relax
+ \ifnum\c_tabl_tabulate_nofauto>\zerocount
+ \divide\d_tabl_tabulate_width \c_tabl_tabulate_nofauto\relax
+ \fi
+ \fi
+ \setbox\scratchbox\emptybox % free memory
+ \ifconditional\c_tabl_tabulate_split
+ \splittopskip\strutht
+ \glet\tabl_tabulate_flush_collected_indeed\empty
+ \glet\tabl_tabulate_flush_collected\tabl_tabulate_flush_second
+ \fi
+ \c_tabl_tabulate_totalnoflines\c_tabl_tabulate_noflines
+ \c_tabl_tabulate_minusnoflines\numexpr\c_tabl_tabulate_noflines+\minusone\relax
+ \global\c_tabl_tabulate_noflines\zerocount
+ %
+ \c_tabl_tabulate_pass\plustwo % final pass
+ \the\t_tabl_tabulate_initializers_second % collect more here
+ %
+ \ifx\p_line\v!line
+ \let\HL\HR
+ \let\tabulateautoline\tabulateautorule
+ \let\tabulateline\tabulaterule
+ \fi
+ %
+ \ifcase\c_tabl_tabulate_repeathead
+ \ifinsidesplitfloat
+ \global\setbox\b_tabl_tabulate\vbox \bgroup
+ \else
+ \startframedcontent[\tabulationparameter\c!frame]%
+ \fi
+ \else
+ \global\setbox\b_tabl_tabulate\vbox \bgroup
+ \fi
+ %
+ \dostarttaggedchained\t!tabulate\empty\??tabulation
+ \dostarttagged\t!tabulaterow\empty
+ \setfalse\inhibitmargindata % new per 2012.06.13 ... really needed
+ % \everycr\expandafter{\the\everycr\noalign{\the\t_tabl_tabulate_every_real_row}\dostoptagged\dostarttagged\t!tabulaterow\empty}%
+ \toksapp\everycr{\noalign{\the\t_tabl_tabulate_every_real_row}\dostoptagged\dostarttagged\t!tabulaterow\empty}%
+ \expandafter\halign\expandafter{\the\t_tabl_tabulate_preamble\crcr\tabl_tabulate_insert_content\crcr}%
+ \dostoptagged
+ \dostoptagged
+ \ifhmode\par\prevdepth\strutdp\fi % nog eens beter, temporary hack
+ \ifx\p_distance\v!grid
+ \vskip-\strutdp % experimental tm-prikkels
+ \fi
+ %
+ \ifcase\c_tabl_tabulate_repeathead
+ \ifinsidesplitfloat
+ \egroup % box
+ \egroup % settings
+ \tabl_split_box\b_tabl_tabulate
+ \else
+ \stopframedcontent
+ \egroup
+ \fi
+ \else
+ \egroup % box
+ \egroup % settings
+ \tabl_split_box\b_tabl_tabulate
+ \fi
+ %
+ \ifinsidefloat
+ \tabl_tabulate_inside_after
+ \else
+ \tabl_tabulate_outside_after
+ \fi
+ \egroup} % whole thing
+
+% \egroup
+
+% \setuptabulate[split=yes,header=text,title=Vervolg van Tabel]
+%
+% % \starttabulatehead
+% % \NC test \NC hans\NC \NR
+% % \stoptabulatehead
+%
+% \starttabulate
+% \NC test \NC \input tufte \relax \NC \NR
+% \NC test \NC \input knuth \relax \NC \NR
+% \NC test \NC \input knuth \relax \NC \NR
+% \NC test \NC \input tufte \relax \NC \NR
+% \NC test \NC \input tufte \relax \NC \NR
+% \NC test \NC \input tufte \relax \NC \NR
+% \stoptabulate
+
+\def\tabl_split_box#1% #1 <> 0/2 / derived from the one in core-ntb.tex
+ {\ifinsidesplitfloat
+ \tabl_split_box_indeed#1%
+ \orelse\ifinsidefloat
+ \unvbox#1%
+ \else
+ \tabl_split_box_indeed#1%
+ \fi}
+
+\def\tabl_split_box_indeed#1%
+ {\resettsplit
+ \def\tsplitminimumfreelines{2}%
+ \def\tsplitminimumfreespace{0pt}%
+ \setbox\tsplitcontent\box#1%
+ \ifcase\c_tabl_tabulate_repeathead\or
+ \setbox\tsplithead\vsplit\tsplitcontent to \lineheight
+ \setbox\tsplithead\vbox{\unvbox\tsplithead}%
+ \or
+ \setbox\tsplithead\vbox{\hbox{\strut\tabulationparameter\c!title}}%
+ \fi
+ \handletsplit}
+
+%D \starttyping
+%D \setuptabulate[split=no,rule=line]
+%D
+%D \starttabulate
+%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule
+%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule
+%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule
+%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule
+%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule
+%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule
+%D \stoptabulate
+%D \stoptyping
+
+%D Spacing:
+%
+% \starttabulate
+% \NC text \NC text \NC \NR
+% \TB[small]
+% \NC text \NC text \NC \NR
+% \TB[4*big]
+% \NC text \NC text \NC \NR
+% \stoptabulate
+
+\def\tabl_tabulate_TB
+ {\starttabulatenoalign
+ \dosingleempty\tabl_tabulate_TB_indeed}
+
+\def\tabl_tabulate_TB_indeed[#1]%
+ {\iffirstargument
+ \blank[#1]
+ \orelse\ifx\m_tabl_tabulate_blank_default\empty
+ \blank
+ \else
+ \blank[\m_tabl_tabulate_blank_default]%
+ \fi
+ \stoptabulatenoalign}
+
+% to be tested:
+%
+% \def\tabl_tabulate_TB
+% {\starttabulatenoalign
+% \doiffastoptionalcheckelse\tabl_tabulate_TB_yes\tabl_tabulate_TB_nop}
+%
+% \def\tabl_tabulate_TB_yes[#1]%
+% {\blank[#1]
+% \stoptabulatenoalign}
+%
+% \def\tabl_tabulate_TB_nop[#1]%
+% {\blank
+% \stoptabulatenoalign}
+
+\appendtoks
+ \let\TB\tabl_tabulate_TB
+\to \everytabulate
+
+% %D Between alignment lines certain rules apply, and even a simple test can mess
+% %D up a table, which is why we have a special test facilityL
+% %D
+% %D \startbuffer
+% %D \starttabulate[|l|p|]
+% %D \NC 1test \NC test \NC \NR
+% %D \tableifelse{\doifelse{a}{a}}{\NC Xtest \NC test \NC \NR}{}%
+% %D \stoptabulate
+% %D \stopbuffer
+% %D
+% %D \typebuffer \getbuffer
+%
+% \def\tableifelse#1% should be tabulatenoalign then
+% {\tablenoalign
+% {#1%
+% {\aftergroup \firstoftwoarguments}%
+% {\aftergroup\secondoftwoarguments}}}
+%
+% \def\tableiftextelse#1{\tableifelse{\doiftextelse{#1}}}
+
+%D Some new trickery:
+%D
+%D \startbuffer
+%D \settrue\c_tabl_tabulate_splitoff_whitespace
+%D
+%D \starttabulate[|p(2cm)|p(2cm)|p(2cm)|]
+%D \NC test 1a \NC test 2a \NC test 3a
+%D \par
+%D test 3b \NC \NR
+%D \NC test 1a \NC test 2a \NC test 3a
+%D \blank[line]
+%D test 3b \NC \NR
+%D \NC test 1a \NC test 2a \NC test 3a
+%D \blank[halfline]
+%D test 3b
+%D \blank[halfline]
+%D test 3c \NC \NR
+%D \NC \blank \NC \blank \NC \blank \NC \NR
+%D \NC test 1a \NC test 2a \NC test 3a
+%D \blank[halfline]
+%D test 3b
+%D \blank[halfline]
+%D test 3c \NC \NR
+%D \NC \blank \NC \blank \NC \NC \NR
+%D \NC test 1a
+%D \par
+%D test 1b
+%D \par
+%D test 1b \NC test 2a
+%D \par
+%D test 2b
+%D \par
+%D test 2b \NC test 3a \NC \NR
+%D \NC test 1a
+%D \blank
+%D test 1b
+%D \par
+%D test 1b \NC test 2a
+%D \par
+%D test 2b
+%D \blank
+%D test 2b \NC test 3a \NC \NR
+%D \stoptabulate
+%D \stopbuffer
+%D
+%D \typebuffer \start \getbuffer \stop
+
+% \starttabulatie[|mc|]
+% \NC \digits{100.000,00} \NC\NR
+% \NC \digits{@10.000,00} \NC\NR
+% \NC \digits{@@@.100,00} \NC\NR
+% \NC \digits{@@@.@10,@@} \NC\NR
+% \NC \digits{@@@.@@1,@@} \NC\NR
+% \stoptabulatie
+%
+% \starttabulatie[|mc|]
+% \ND 100.000,00 \NC\NR
+% \ND @10.000,00 \NC\NR
+% \ND @@@.100,00 \NC\NR
+% \ND @@@.@10,@@ \NC\NR
+% \ND @@@.@@1,@@ \NC\NR
+% \stoptabulatie
+%
+% \starttabulatie[|c|]
+% \ND $100.000,00$ \NC\NR
+% \ND $@10.000,00$ \NC\NR
+% \ND $@@@.100,00$ \NC\NR
+% \ND $@@@.@10,@@$ \NC\NR
+% \ND $@@@.@@1,@@$ \NC\NR
+% \stoptabulatie
+%
+% \starttabulatie[|c|]
+% \NC $\digits 100.000,00 $ \NC\NR
+% \NC $\digits @10.000,00 $ \NC\NR
+% \NC $\digits @@@.100,00 $ \NC\NR
+% \NC $\digits @@@.@10,@@ $ \NC\NR
+% \NC $\digits @@@.@@1,@@ $ \NC\NR
+% \stoptabulatie
+%
+% \starttabulatie[|c|]
+% \NC \digits $100.000,00$ \NC\NR
+% \NC \digits $@10.000,00$ \NC\NR
+% \NC \digits $@@@.100,00$ \NC\NR
+% \NC \digits $@@@.@10,@@$ \NC\NR
+% \NC \digits $@@@.@@1,@@$ \NC\NR
+% \stoptabulatie
+
+%D Predefined categories (moved from core-mis):
+
+\definetabulate
+ [\v!legend]
+ [|emj1|i1|mR|]
+
+\setuptabulate
+ [\v!legend]
+ [\c!unit=.75em,\c!inner=\setquicktabulate\leg,EQ={=}]
+
+\definetabulate
+ [\v!legend][\v!two]
+ [|emj1|emk1|i1|mR|]
+
+\definetabulate
+ [\v!fact]
+ [|R|ecmj1|i1mR|]
+
+\setuptabulate
+ [\v!fact]
+ [\c!unit=.75em,\c!inner=\setquicktabulate\fact,EQ={=}]
+
+%D Another example:
+%D
+%D \starttyping
+%D \definetabulate
+%D [whatever]
+%D [|l|r|]
+%D
+%D \definetabulate
+%D [whatever][else]
+%D [|l|c|r|]
+%D
+%D \startwhatever
+%D \NC l \NC r \NC \NR
+%D \NC left \NC right \NC \NR
+%D \stopwhatever
+%D
+%D \startwhatever[else]
+%D \NC l \NC m \NC r \NC \NR
+%D \NC left \NC middle \NC right \NC \NR
+%D \stopwhatever
+%D
+%D \startwhatever[else][format={|c|c|c|c|}]
+%D \NC l \NC m \NC m \NC r \NC \NR
+%D \NC left \NC middle \NC middle \NC right \NC \NR
+%D \stopwhatever
+%D \stoptyping
+
+%D This is needed because we sometimes use the english command in tracing macros. In
+%D fact, most detailed tracing macros that are done with \LUA\ only work in the
+%D english interface anyway.
+
+% \definetabulate[tabulate] \setuptabulate[tabulate][\c!format=\v!none] % so no \v! here
+
+\newconditional\c_tabl_generic
+
+\unexpanded\setuvalue{starttabulate}%
+ {\bgroup % whole thing
+ \settrue\c_tabl_generic
+ \let\currenttabulationparent\empty
+ \dodoubleempty\tabl_start_regular}
+
+\letvalue{stoptabulate}\relax
+
+%D The following helpers are just there because we also have them at the \LUA\ end:
+%D
+%D \startbuffer
+%D \starttabulate[|l|c|r|]
+%D \tabulaterow {a,b,c}
+%D \tabulaterowbold{aa,bb,cc}
+%D \tabulaterowtype{aaa,bbb,ccc}
+%D \tabulaterowtyp {aaaa,bbbb,cccc}
+%D \stoptabulate
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+\def\tabl_tabulate_compact_row#1#2%
+ {\NC\tabl_tabulate_compact_step#1#2,\end,}
+
+\def\tabl_tabulate_compact_step#1#2#3,%
+ {\ifx#2\end
+ \NR
+ \expandafter\gobbleoneargument
+ \else
+ #1{#2#3}\NC
+ \expandafter\tabl_tabulate_compact_step
+ \fi#1}
+
+\unexpanded\def\tabulaterow {\tabl_tabulate_compact_row\relax}
+\unexpanded\def\tabulaterowbold{\tabl_tabulate_compact_row\bold}
+\unexpanded\def\tabulaterowtype{\tabl_tabulate_compact_row\type}
+\unexpanded\def\tabulaterowtyp {\tabl_tabulate_compact_row\typ}
+
+%D Here we plug in a row background feature. As we only have support for
+%D \type {frame=name} we can use these variables.
+%D
+%D \starttyping
+%D \startuseMPgraphic{foo}
+%D fill unitsquare
+%D xyscaled (RuleWidth,RuleHeight+RuleDepth) enlarged (ExHeight/4,ExHeight/8)
+%D randomized ExHeight
+%D shifted (-ExHeight/8,ExHeight/16)
+%D withcolor RuleColor ;
+%D \stopuseMPgraphic
+%D
+%D \setuptabulate % wel only have frame=name so we can use these:
+%D [background=foo,
+%D backgroundcolor=darkred,
+%D foregroundcolor=white]
+%D
+%D \definelinefiller[foo][mp=foo,color=darkgreen]
+%D \definelinefiller[bar][mp=foo,color=darkred]
+%D
+%D \starttabulate[|||]
+%D \DB foo \BC bar \BC \NR
+%D \NC foo \NC bar \NC \NR
+%D \NC foo \NC bar \NC \NR
+%D \NC foo \NC bar \NC \NR
+%D \NC foo \NC bar \NC \NR
+%D \stoptabulate
+%D
+%D \starttabulate[|||]
+%D \PB foo \BC bar \BC \NR
+%D \NC foo \NC bar \NC \NR
+%D \NC foo \NC bar \NC \NR
+%D \NC foo \NC bar \NC \NR
+%D \NC foo \NC bar \NC \NR
+%D \stoptabulate
+%D
+%D \starttabulate[|||]
+%D \FB[bar] foo \BC bar \BC \NR
+%D \NC foo \NC bar \NC \NR
+%D \NC foo \NC bar \NC \NR
+%D \NC foo \NC bar \NC \NR
+%D \NC foo \NC bar \NC \NR
+%D \stoptabulate
+%D
+%D \startnarrower
+%D \starttabulate[|||]
+%D \DB foo \DB bar \BC \NR
+%D \NC foo \NC bar \NC \NR
+%D \NC foo \NC bar \NC \NR
+%D \NC foo \NC bar \NC \NR
+%D \NC foo \NC bar \NC \NR
+%D \stoptabulate
+%D \stopnarrower
+%D
+%D \starttabulate[|||]
+%D \BC foo \BC bar \BC \NR
+%D \NL[magenta] foo \NC bar \NC \NR
+%D \NL[yellow] foo \NC bar \NC \NR
+%D \NL[cyan] foo \NC bar \NC \NR
+%D \NL[gray] foo \NC bar \NC \NR
+%D \stoptabulate
+%D
+%D \starttabulate
+%D \NL[red] foo \NC bar \NC \NR
+%D \NL[green] foo \NL[red] bar \NC \NR
+%D \NC foo \NC bar \NC \NR
+%D \NL[blue] foo \NC \input tufte \NC \NR
+%D \NL[gray] foo \NC bar \NC \NR
+%D \NL[yellow] foo \NC bar \NC \NR
+%D \stoptabulate
+%D \stoptyping
+
+% \setuptabulate
+% [\c!background=,
+% \c!backgroundcolor=,
+% \c!foregroundcolor=,
+% \c!foregroundstyle=]
+
+\let\m_table_current_row_background \empty
+\let\m_table_current_row_background_default \empty
+\let\m_table_current_row_background_filler \empty
+\let\m_table_current_row_background_defaultfiller\empty
+\let\m_table_current_row_background_auto \empty
+
+\unexpanded\def\tabl_register_row_background#1%
+ {\xdef\m_table_current_row_background{#1}}
+
+\unexpanded\def\tabl_register_row_background_filler#1%
+ {\xdef\m_table_current_row_background_filler{#1}}
+
+\unexpanded\def\tabl_synchronize_row_background
+ {\iftrialtypesetting\else
+ \ifx\m_table_current_row_background_filler\empty
+ \ifx\m_table_current_row_background\empty
+ % nothing
+ \tabl_synchronize_row_background_dummy
+ \else
+ \tabl_synchronize_row_background_indeed\m_table_current_row_background
+ \fi
+ \else
+ \tabl_synchronize_row_background_filler_indeed\m_table_current_row_background_filler
+ \fi
+ \fi}
+
+\unexpanded\def\tabl_synchronize_row_background_dummy
+ {\iftrialtypesetting\else
+ \begingroup
+ %\clf_setbackgroundrowdata\numexpr\c_tabl_tabulate_nofrealrows+\minusone\relax\zerocount\zeropoint
+ \clf_setbackgroundrowdata\c_tabl_tabulate_nofrealrows\zerocount\zeropoint
+ \endgroup
+ \fi}
+
+\unexpanded\def\tabl_synchronize_row_background_indeed#1%
+ {\iftrialtypesetting\else
+ \begingroup
+ \clf_enablebackgroundalign % can be moved into \clf_setbackgroundrowdata
+ \dousecolorparameter{#1}%
+ \setbox\scratchbox\hpack{}%
+ %\clf_setbackgroundrowdata\numexpr\c_tabl_tabulate_nofrealrows+\minusone\relax\scratchbox\d_tabl_tabulate_indent
+ \clf_setbackgroundrowdata\c_tabl_tabulate_nofrealrows\scratchbox\d_tabl_tabulate_indent
+ \endgroup
+ \fi}
+
+\unexpanded\def\tabl_synchronize_row_background_filler_indeed#1%
+ {\iftrialtypesetting\else
+ \begingroup
+ \clf_enablebackgroundalign % can be moved into \clf_setbackgroundrowdata
+ \node_linefiller_set{#1}%
+ \setbox\scratchbox\hpack{}%
+ %\clf_setbackgroundrowdata\numexpr\c_tabl_tabulate_nofrealrows+\minusone\relax\scratchbox\d_tabl_tabulate_indent
+ \clf_setbackgroundrowdata\c_tabl_tabulate_nofrealrows\scratchbox\d_tabl_tabulate_indent
+ \endgroup
+ \fi}
+
+\appendtoks
+ \glet\m_table_current_row_background\empty
+ \glet\m_table_current_row_background_filler\empty
+ \global\c_tabl_tabulate_nofrealrows\zerocount
+ \global\c_tabl_tabulate_autocolor\zerocount
+ \clf_resetbackgroundrowdata
+\to \t_tabl_tabulate_initializers_first
+
+\appendtoks
+ \glet\m_table_current_row_background\empty
+ \glet\m_table_current_row_background_filler\empty
+ \global\c_tabl_tabulate_nofrealrows\zerocount
+ \global\c_tabl_tabulate_autocolor\zerocount
+ \clf_resetbackgroundrowdata
+\to \t_tabl_tabulate_initializers_second
+
+\appendtoks
+ \tabl_synchronize_row_background
+\to \t_tabl_tabulate_every_real_row
+
+\appendtoks
+ \glet\m_table_current_row_background\empty
+ \glet\m_table_current_row_background_filler\empty
+\to \t_tabl_tabulate_every_after_row
+
+\unexpanded\def\tabl_tabulate_NL_first[#1]%
+ {\tabl_tabulate_column_normal\zerocount\zerocount\relax
+ \ifcase\c_tabl_tabulate_column\or
+ \tabl_register_row_background{#1}%
+ \fi
+ \ignorespaces}
+
+\unexpanded\def\tabl_tabulate_ND_first
+ {\tabl_tabulate_column_normal\zerocount\zerocount\relax
+ \ifcase\c_tabl_tabulate_column\or
+ \tabl_register_row_background\m_table_current_row_background_default
+ \fi
+ \ignorespaces}
+
+\unexpanded\def\tabl_tabulate_LB_first[#1]%
+ {\tabl_tabulate_column_normal\plusone\zerocount\relax
+ \ifcase\c_tabl_tabulate_column\or
+ \tabl_register_row_background{#1}%
+ \fi
+ \usetabulationstyleandcolor\c!foregroundstyle\c!foregroundcolor
+ \ignorespaces}
+
+\unexpanded\def\tabl_tabulate_DB_first
+ {\tabl_tabulate_column_normal\plusone\zerocount\relax
+ \ifcase\c_tabl_tabulate_column\or
+ \tabl_register_row_background\m_table_current_row_background_default
+ \fi
+ \let\fontstyle\globalfontstyle
+ \usetabulationstyleandcolor\c!foregroundstyle\c!foregroundcolor
+ \ignorespaces}
+
+\unexpanded\def\tabl_tabulate_NF_first[#1]%
+ {\tabl_tabulate_column_normal\zerocount\zerocount\relax
+ \ifcase\c_tabl_tabulate_column\or
+ \tabl_register_row_background_filler{#1}%
+ \fi
+ \ignorespaces}
+
+\unexpanded\def\tabl_tabulate_NP_first
+ {\tabl_tabulate_column_normal\zerocount\zerocount\relax
+ \ifcase\c_tabl_tabulate_column\or
+ \tabl_register_row_background_filler\m_table_current_row_background_default_filler
+ \fi
+ \ignorespaces}
+
+\unexpanded\def\tabl_tabulate_FB_first[#1]%
+ {\tabl_tabulate_column_normal\plusone\zerocount\relax
+ \ifcase\c_tabl_tabulate_column\or
+ \tabl_register_row_background_filler{#1}%
+ \fi
+ \usetabulationstyleandcolor\c!foregroundstyle\c!foregroundcolor
+ \ignorespaces}
+
+\unexpanded\def\tabl_tabulate_PB_first
+ {\tabl_tabulate_column_normal\plusone\zerocount\relax
+ \ifcase\c_tabl_tabulate_column\or
+ \tabl_register_row_background_filler\m_table_current_row_background_default_filler
+ \fi
+ \let\fontstyle\globalfontstyle
+ \usetabulationstyleandcolor\c!foregroundstyle\c!foregroundcolor
+ \ignorespaces}
+
+\unexpanded\def\tabl_tabulate_BC_first % overloaded
+ {\tabl_tabulate_column_normal\plusone\zerocount
+ \let\fontstyle\globalfontstyle
+ \ifx\m_table_current_row_background\empty
+ \ifx\m_table_current_row_background_filler\empty
+ \usetabulationstyleandcolor\c!headstyle\c!headcolor
+ \else
+ \usetabulationstyleandcolor\c!foregroundstyle\c!foregroundcolor
+ \fi
+ \else
+ \usetabulationstyleandcolor\c!foregroundstyle\c!foregroundcolor
+ \fi}
+
+\unexpanded\def\tabl_tabulate_A_first
+ {\global\advance\c_tabl_tabulate_autocolor\plusone
+ \edef\m_table_current_row_background_auto{\tabulateparameter{\c!backgroundcolor:\number\c_tabl_tabulate_autocolor}}%
+ \ifx\m_table_current_row_background_auto\empty
+ \global\c_tabl_tabulate_autocolor\plusone
+ \edef\m_table_current_row_background_auto{\tabulateparameter{\c!backgroundcolor:\number\c_tabl_tabulate_autocolor}}%
+ \fi
+ \ifx\m_table_current_row_background_auto\empty
+ \let\m_table_current_row_background_auto\empty % \m_table_current_row_background_default
+ \fi
+ \tabl_register_row_background{\m_table_current_row_background_auto}}
+
+\unexpanded\def\tabl_tabulate_NA_first
+ {\tabl_tabulate_column_normal\zerocount\zerocount\relax
+ \iftrialtypesetting\else
+ \ifcase\c_tabl_tabulate_column\or
+ \tabl_tabulate_A_first
+ \fi
+ \fi
+ \ignorespaces}
+
+\unexpanded\def\tabl_tabulate_BA_first
+ {\tabl_tabulate_column_normal\plusone\zerocount\relax
+ \iftrialtypesetting\else
+ \ifcase\c_tabl_tabulate_column\or
+ \tabl_tabulate_A_first
+ \fi
+ \fi
+ \usetabulationstyleandcolor\c!foregroundstyle\c!foregroundcolor
+ \ignorespaces}
+
+\appendtoks
+ \let\NL\tabl_tabulate_NL_first % NC with Line
+ \let\ND\tabl_tabulate_ND_first % NC with Default Line
+ \let\LB\tabl_tabulate_LB_first % BC with Line
+ \let\DB\tabl_tabulate_DB_first % BC with Default Line
+ \let\NF\tabl_tabulate_NF_first % NC with Filler
+ \let\NP\tabl_tabulate_NP_first % NC with Predefined Filler
+ \let\FB\tabl_tabulate_FB_first % BC with Filler
+ \let\PB\tabl_tabulate_PB_first % BC with Predefined Filler
+ \let\NA\tabl_tabulate_NA_first % NC with Auto Line
+ \let\BA\tabl_tabulate_BA_first % NC with Auto Line
+\to \t_tabl_tabulate_initializers_first
+
+\appendtoks
+ \edef\m_table_current_row_background_default {\tabulateparameter\c!backgroundcolor}%
+ \edef\m_table_current_row_background_default_filler{\tabulateparameter\c!background}%
+ \let \m_table_current_row_background_auto \empty
+\to \everytabulate
+
+\setuptabulate
+ [\c!headcolor=,
+ \c!headstyle=\bf,
+ \c!backgroundcolor=\tabulationparameter\c!rulecolor,
+ \c!foregroundcolor=,
+ \c!foregroundstyle=\tabulationparameter\c!headstyle]
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/tabl-tsp.mkiv b/Master/texmf-dist/tex/context/base/mkiv/tabl-tsp.mkiv
index e0ddce38a58..c5858fec109 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/tabl-tsp.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/tabl-tsp.mkiv
@@ -187,7 +187,11 @@
\bgroup
\forcelocalfloats
\setuplocalfloats[\c!before=,\c!after=,\c!inbetween=]%
+ % This controls samepage resetting too but it also messes up the numbering
+ % so I need another fix.
+% \settrialtypesetting
\splitfloatcommand{\hbox to #1{\strut}}% dummy line
+% \resettrialtypesetting
\setbox\scratchbox\vbox{\flushlocalfloats}% \vpack ?
\getnoflines{\ht\scratchbox}%
\resetlocalfloats
diff --git a/Master/texmf-dist/tex/context/base/mkiv/tabl-xtb.lua b/Master/texmf-dist/tex/context/base/mkiv/tabl-xtb.lua
index c9d50638e67..2ff87e21abe 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/tabl-xtb.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/tabl-xtb.lua
@@ -26,7 +26,7 @@ this mechamism will be improved so that it can replace its older cousin.
-- todo: use linked list instead of r/c array
-- todo: we can use the sum of previously forced widths for column spans
-local tonumber, next, rawget = tonumber, next, rawget
+local tonumber, next = tonumber, next
local commands = commands
local context = context
@@ -478,36 +478,50 @@ end
function xtables.initialize_construct()
local r = data.currentrow
local c = data.currentcolumn + 1
+ local settings = data.settings
local rows = data.rows
local row = rows[r]
while row[c].span do -- can also be previous row ones
c = c + 1
end
data.currentcolumn = c
- local widths = data.widths
- local heights = data.heights
- local depths = data.depths
+ local widths = data.widths
+ local heights = data.heights
+ local depths = data.depths
+ local distances = data.distances
--
local drc = row[c]
local wd = drc.wd
local ht = drc.ht
local dp = drc.dp
+ local nx = drc.nx - 1
+ local ny = drc.ny - 1
--
local width = widths[c]
local height = heights[r]
local depth = depths[r] -- problem: can be the depth of a one liner
--
- for x=1,drc.nx-1 do
- width = width + widths[c+x]
+ local total = height + depth
+ --
+ if nx > 0 then
+ for x=1,nx do
+ width = width + widths[c+x] + distances[c+x-1]
+ end
+ local distance = settings.columndistance
+ if distance ~= 0 then
+ width = width + nx * distance
+ end
end
--
- local total = height + depth
- local ny = drc.ny
- if ny > 1 then
- for y=1,ny-1 do
+ if ny > 0 then
+ for y=1,ny do
local nxt = r + y
total = total + heights[nxt] + depths[nxt]
end
+ local distance = settings.rowdistance
+ if distance ~= 0 then
+ total = total + ny * distance
+ end
end
--
texsetdimen("d_tabl_x_width",width)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/tabl-xtb.mkvi b/Master/texmf-dist/tex/context/base/mkiv/tabl-xtb.mkvi
index 1483043316d..e8279589276 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/tabl-xtb.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/tabl-xtb.mkvi
@@ -498,9 +498,16 @@
\unexpanded\def\stopxcell
{\tabl_x_stop_cell}
+% \unexpanded\def\dummyxcell
+% {\tabl_x_start_cell_nop
+% \tabl_x_stop_cell}
+
\unexpanded\def\dummyxcell
- {\tabl_x_start_cell_nop
- \tabl_x_stop_cell}
+ {\begingroup
+ \let\inheritedxtableframed\relax
+ \tabl_x_start_cell_nop
+ \tabl_x_stop_cell
+ \endgroup}
% \unexpanded\def\tabl_x_begin_of_cell
% {%\inhibitblank % already in framed
diff --git a/Master/texmf-dist/tex/context/base/mkiv/toks-ini.lua b/Master/texmf-dist/tex/context/base/mkiv/toks-ini.lua
index 2c85a575477..eef26574e0e 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/toks-ini.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/toks-ini.lua
@@ -36,18 +36,27 @@ local scan_argument = token.scan_argument
local scan_tokenlist = token.scan_tokenlist
local scan_int = token.scan_int
local scan_code = token.scan_code
+local scan_token_code = token.scan_token_code
local scan_dimen = token.scan_dimen
local scan_glue = token.scan_glue
local scan_keyword = token.scan_keyword
local scan_keyword_cs = token.scan_keyword_cs or scan_keyword
local scan_token = token.scan_token
+local scan_box = token.scan_box
local scan_word = token.scan_word
+local scan_key = token.scan_key
+local scan_value = token.scan_value
+local scan_char = token.scan_char
local scan_number = token.scan_number
local scan_csname = token.scan_csname
local scan_real = token.scan_real
local scan_float = token.scan_float
local get_next = token.get_next
+local get_next_token = token.get_next_token
+local skip_next = token.skip_next
+local peek_next_char = token.peek_next_char
+local is_next_char = token.is_next_char
local set_macro = token.set_macro
local get_macro = token.get_macro
@@ -61,14 +70,6 @@ local new_token = token.new
local is_defined = token.is_defined
local is_token = token.is_token
-if not is_defined then
-
- is_defined = function(name)
- return get_cmdname(create_token(name)) ~= "undefined_cs"
- end
-
-end
-
tokens.new = new_token
tokens.create = create_token
tokens.istoken = is_token
@@ -104,14 +105,10 @@ local bits = {
tokens.bits = bits
-local space_bits = bits.space
-
-- words are space or \relax terminated and the trailing space is gobbled; a word
--- can contain any non-space letter/other
-
-local t = { } -- small optimization, a shared variable that is not reset
+-- can contain any non-space letter/other (see archive for implementation in lua)
-if scan_word then
+if not scan_number then
scan_number = function(base)
local s = scan_word()
@@ -124,70 +121,8 @@ if scan_word then
end
end
-else
-
- scan_word = function()
- local n = 0
- while true do
- local c = scan_code()
- if c then
- n = n + 1
- t[n] = utfchar(c)
- elseif scan_code(space_bits) then
- if n > 0 then
- break
- end
- elseif n > 0 then
- break
- else
- return
- end
- end
- return concat(t,"",1,n)
- end
-
- -- so we gobble the space (like scan_int) (number has to be space or non-char terminated
- -- as we accept 0xabcd and such so there is no clear separator for a keyword
-
- scan_number = function(base)
- local n = 0
- while true do
- local c = scan_code()
- if c then
- n = n + 1
- t[n] = char(c)
- elseif scan_code(space_bits) then
- if n > 0 then
- break
- end
- elseif n > 0 then
- break
- else
- return
- end
- end
- local s = concat(t,"",1,n)
- if base then
- return tonumber(s,base)
- else
- return tonumber(s)
- end
- end
-
end
--- -- the next one cannot handle \iftrue true\else false\fi
---
--- local function scan_boolean()
--- if scan_keyword("true") then
--- return true
--- elseif scan_keyword("false") then
--- return false
--- else
--- return nil
--- end
--- end
-
local function scan_boolean()
local kw = scan_word()
if kw == "true" then
@@ -199,24 +134,33 @@ local function scan_boolean()
end
end
-if not scan_csname then
+local function scan_verbatim()
+ return scan_argument(false)
+end
+
+if not scan_box then
+
+ local scan_list = token.scan_list
+ local put_next = token.put_next
- scan_csname = function()
- local t = get_next()
- local n = t.csname
- return n ~= "" and n or nil
+ scan_box = function(s)
+ if s == "hbox" or s == "vbox" or s == "vtop" then
+ put_next(create_token(s))
+ end
end
-end
+ token.scan_box = scan_box
-local function scan_verbatim()
- return scan_argument(false)
end
tokens.scanners = { -- these expand
token = scan_token,
toks = scan_toks,
tokens = scan_toks,
+ box = scan_box,
+ hbox = function() return scan_box("hbox") end,
+ vbox = function() return scan_box("vbox") end,
+ vtop = function() return scan_box("vtop") end,
dimen = scan_dimen,
dimension = scan_dimen,
glue = scan_glue,
@@ -230,12 +174,19 @@ tokens.scanners = { -- these expand
tokenlist = scan_tokenlist,
verbatim = scan_verbatim,
code = scan_code,
+ tokencode = scan_token_code,
word = scan_word,
+ key = scan_key,
+ value = scan_value,
+ char = scan_char,
number = scan_number,
boolean = scan_boolean,
keyword = scan_keyword,
keywordcs = scan_keyword_cs,
csname = scan_csname,
+ peek = peek_next_char,
+ skip = skip_next,
+ ischar = is_next_char,
}
tokens.getters = { -- these don't expand
@@ -307,6 +258,7 @@ if setinspector then
active = t.active,
expandable = t.expandable,
protected = t.protected,
+ frozen = t.frozen,
mode = t.mode,
index = t.index,
cmdname = cmdname,
diff --git a/Master/texmf-dist/tex/context/base/mkiv/toks-scn.lua b/Master/texmf-dist/tex/context/base/mkiv/toks-scn.lua
index 297ef71212a..2d20d5a8b31 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/toks-scn.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/toks-scn.lua
@@ -29,6 +29,7 @@ local scannumber = scanners.number
local scankeyword = scanners.keyword
local scankeywordcs = scanners.keywordcs
local scanword = scanners.word
+local scankey = scanners.key
local scancode = scanners.code
local scanboolean = scanners.boolean
local scandimen = scanners.dimen
@@ -144,6 +145,26 @@ scanners.list = scanlist
scanners.table = scantable
scanners.conditional = scanconditional
+function scanners.whd()
+ local width, height, depth
+ while true do
+ if scankeyword("width") then
+ width = scandimen()
+ elseif scankeyword("height") then
+ height = scandimen()
+ elseif scankeyword("depth") then
+ depth = scandimen()
+ else
+ break
+ end
+ end
+ if width or height or depth then
+ return width or 0, height or 0, depth or 0
+ else
+ -- we inherit
+ end
+end
+
local shortcuts = {
tokens = tokens,
bits = tokenbits,
@@ -160,10 +181,15 @@ local shortcuts = {
scankeyword = scankeyword,
scankeywordcs = scankeywordcs,
scanword = scanword,
+ -- scankey = scankey,
scancode = scancode,
scanboolean = scanboolean,
scandimen = scandimen,
scandimension = scandimen,
+ scanbox = scanners.box,
+ scanhbox = scanners.hbox,
+ scanvbox = scanners.vbox,
+ scanvtop = scanners.vtop,
scanconditional = scanconditional,
scanopen = scanopen,
scanclose = scanclose,
diff --git a/Master/texmf-dist/tex/context/base/mkiv/trac-ctx.lua b/Master/texmf-dist/tex/context/base/mkiv/trac-ctx.lua
index 33637fd66d9..6681be51c5f 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/trac-ctx.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/trac-ctx.lua
@@ -70,3 +70,17 @@ implement {
install(texdirectives,directives.register,tag,enable,disable)
end,
}
+
+-- this one might move
+
+interfaces.implement {
+ name = "unsupportedcs",
+ public = true,
+ actions = function()
+ logs.newline()
+ logs.report("fatal error","unsupported cs \\%s",tokens.scanners.csname())
+ logs.newline()
+ luatex.abort()
+ end
+}
+
diff --git a/Master/texmf-dist/tex/context/base/mkiv/trac-deb.lua b/Master/texmf-dist/tex/context/base/mkiv/trac-deb.lua
index 95f3052fe6f..71055eafac9 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/trac-deb.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/trac-deb.lua
@@ -6,11 +6,14 @@ if not modules then modules = { } end modules ['trac-deb'] = {
license = "see context related readme files"
}
-local lpeg, status = lpeg, status
+-- This is an old mechanism, a result of some experiments in the early days of
+-- luatex and mkiv, but still nice anyway.
-local lpegmatch = lpeg.match
+local status = status
+
+local tonumber, tostring, type = tonumber, tostring, type
local format, concat, match, find, gsub = string.format, table.concat, string.match, string.find, string.gsub
-local tonumber, tostring = tonumber, tostring
+local lpegmatch = lpeg.match
-- maybe tracers -> tracers.tex (and tracers.lua for current debugger)
@@ -31,11 +34,33 @@ local strings = tracers.strings
local texgetdimen = tex.getdimen
local texgettoks = tex.gettoks
local texgetcount = tex.getcount
+local texgethelp = tex.gethelptext or function() end
+local fatalerror = tex.fatalerror
local implement = interfaces.implement
+-- this is used in lmx files but needs to be redone
+
strings.undefined = "undefined"
+function tracers.dimen(name)
+ local d = texgetdimen(name)
+ return d and number.topoints(d) or strings.undefined
+end
+
+function tracers.count(name)
+ return texgetcount(name) or strings.undefined
+end
+
+function tracers.toks(name,limit)
+ local t = texgettoks(name)
+ return t and string.limit(t,tonumber(limit) or 40) or strings.undefined
+end
+
+function tracers.primitive(name)
+ return tex[name] or strings.undefined
+end
+
lists.scratch = {
0, 2, 4, 6, 8
}
@@ -58,15 +83,15 @@ local types = {
}
local splitboth = lpeg.splitat(":")
-local splittype = lpeg.firstofsplit(":")
-local splitname = lpeg.secondofsplit(":")
function tracers.type(csname)
- return lpegmatch(splittype,csname)
+ local tag, name = lpegmatch(splitboth,csname)
+ return tag or ""
end
function tracers.name(csname)
- return lpegmatch(splitname,csname) or csname
+ local tag, name = lpegmatch(splitboth,csname)
+ return name or csname
end
function tracers.cs(csname)
@@ -78,30 +103,14 @@ function tracers.cs(csname)
end
end
-function tracers.dimen(name)
- local d = texgetdimen(name)
- return d and number.topoints(d) or strings.undefined
-end
-
-function tracers.count(name)
- return texgetcount(name) or strings.undefined
-end
-
-function tracers.toks(name,limit)
- local t = texgettoks(name)
- return t and string.limit(t,tonumber(limit) or 40) or strings.undefined
-end
-
-function tracers.primitive(name)
- return tex[name] or strings.undefined
-end
-
function tracers.knownlist(name)
local l = lists[name]
return l and #l > 0
end
local savedluaerror = nil
+local usescitelexer = nil
+local quitonerror = true
local function errorreporter(luaerror)
local category = luaerror and "lua error" or "tex error"
@@ -121,41 +130,46 @@ function tracers.showlines(filename,linenumber,offset,luaerrorline)
end
end
end
- local lines = data and string.splitlines(data)
- if lines and #lines > 0 then
- if luaerrorline and luaerrorline > 0 then
- -- lua error: linenumber points to last line
- local start = "\\startluacode"
- local stop = "\\stopluacode"
- local n = linenumber
- for i=n,1,-1 do
- local line = lines[i]
- if not line then
- break
- elseif find(line,start) then
- n = i + luaerrorline - 1
- if n <= linenumber then
- linenumber = n
+ local scite = usescitelexer and require("util-sci")
+ if scite then
+ return utilities.scite.tohtml(data,"tex",linenumber or true,false)
+ else
+ local lines = data and string.splitlines(data)
+ if lines and #lines > 0 then
+ if luaerrorline and luaerrorline > 0 then
+ -- lua error: linenumber points to last line
+ local start = "\\startluacode"
+ local stop = "\\stopluacode"
+ local n = linenumber
+ for i=n,1,-1 do
+ local line = lines[i]
+ if not line then
+ break
+ elseif find(line,start) then
+ n = i + luaerrorline - 1
+ if n <= linenumber then
+ linenumber = n
+ end
+ break
end
- break
end
end
- end
- offset = tonumber(offset) or 10
- linenumber = tonumber(linenumber) or 10
- local start = math.max(linenumber - offset,1)
- local stop = math.min(linenumber + offset,#lines)
- if stop > #lines then
- return "<linenumber past end of file>"
- else
- local result, fmt = { }, "%" .. #tostring(stop) .. "d %s %s"
- for n=start,stop do
- result[#result+1] = format(fmt,n,n == linenumber and ">>" or " ",lines[n])
+ offset = tonumber(offset) or 10
+ linenumber = tonumber(linenumber) or 10
+ local start = math.max(linenumber - offset,1)
+ local stop = math.min(linenumber + offset,#lines)
+ if stop > #lines then
+ return "<linenumber past end of file>"
+ else
+ local result, fmt = { }, "%" .. #tostring(stop) .. "d %s %s"
+ for n=start,stop do
+ result[#result+1] = format(fmt,n,n == linenumber and ">>" or " ",lines[n])
+ end
+ return concat(result,"\n")
end
- return concat(result,"\n")
+ else
+ return "<empty file>"
end
- else
- return "<empty file>"
end
end
@@ -169,7 +183,7 @@ end
-- todo: \starttext bla \blank[foo] bla \stoptext
local nop = function() end
-local resetmessages = status.resetmessages() or nop
+local resetmessages = status.resetmessages or nop
local function processerror(offset)
-- print("[[ last tex error: " .. tostring(status.lasterrorstring or "<unset>") .. " ]]")
@@ -178,12 +192,11 @@ local function processerror(offset)
-- print("[[ last location : " .. tostring(status.lastwarninglocation or "<unset>") .. " ]]")
-- print("[[ last context : " .. tostring(status.lasterrorcontext or "<unset>") .. " ]]")
- local inputstack = resolvers.inputstack
- local filename = inputstack[#inputstack] or status.filename
+ local filename = status.filename
local linenumber = tonumber(status.linenumber) or 0
local lastcontext = status.lasterrorcontext
local lasttexerror = status.lasterrorstring or "?"
- local lastluaerror = status.lastluaerrorstring or lasttexerror
+ local lastluaerror = status.lastluaerrorstring or "?" -- lasttexerror
local luaerrorline = match(lastluaerror,[[lua%]?:.-(%d+)]]) or (lastluaerror and find(lastluaerror,"?:0:",1,true) and 0)
local lastmpserror = match(lasttexerror,[[^.-mp%serror:%s*(.*)$]])
resetmessages()
@@ -194,69 +207,108 @@ local function processerror(offset)
offset = tonumber(offset) or 10,
lasttexerror = lasttexerror,
lastmpserror = lastmpserror,
- lastluaerror = lastluaerror,
+ lastluaerror = lastluaerror, -- can be the same as lasttexerror
luaerrorline = luaerrorline,
lastcontext = lastcontext,
+ lasttexhelp = tex.gethelptext and tex.gethelptext() or nil,
}
end
-- so one can overload the printer if (really) needed
+if fatalerror then
+ callback.register("terminal_input",function(what)
+ if what == "*" then
+ fatalerror("some kind of input expected, file ends too soon, quitting now")
+ else
+ fatalerror("bad input, quitting now")
+ end
+ end)
+else
+ -- tex.print("\\nonstopmode")
+end
+
+directives.register("system.quitonerror",function(v)
+ quitonerror = toboolean(v)
+ -- tex.print("\\errorstopmode")
+end)
+
+directives.register("system.usescitelexer",function(v)
+ usescitelexer = toboolean(v)
+end)
+
+local busy = false
+
function tracers.printerror(specification)
- local filename = specification.filename
- local linenumber = specification.linenumber
- local lasttexerror = specification.lasttexerror
- local lastmpserror = specification.lastmpserror
- local lastluaerror = specification.lastluaerror
- local lastcontext = specification.lasterrorcontext
- local luaerrorline = specification.luaerrorline
- local errortype = specification.errortype
- local offset = specification.offset
- local report = errorreporter(luaerrorline)
- if not filename then
- report("error not related to input file: %s ...",lasttexerror)
- elseif type(filename) == "number" then
- report("error on line %s of filehandle %s: %s ...",linenumber,lasttexerror)
- else
- report_nl()
- if luaerrorline then
- if linenumber == 0 or not filename or filename == "" then
- print("\nfatal lua error:\n\n",lastluaerror,"\n")
- os.exit(1)
- return
+ if not busy then
+ busy = true
+ local filename = specification.filename
+ local linenumber = specification.linenumber
+ local lasttexerror = specification.lasttexerror
+ local lastmpserror = specification.lastmpserror
+ local lastluaerror = specification.lastluaerror
+ local lastcontext = specification.lasterrorcontext
+ local luaerrorline = specification.luaerrorline
+ local errortype = specification.errortype
+ local offset = specification.offset
+ local report = errorreporter(luaerrorline)
+ if not filename then
+ report("error not related to input file:")
+ report(" tex: %s",lasttexerror or "-")
+ report(" lua: %s",lastluaerror or "-")
+ report(" mps: %s",lastmpserror or "-")
+ elseif type(filename) == "number" then
+ report("error on line %s of filehandle %s: %s ...",linenumber,lasttexerror)
+ else
+ report_nl()
+ if luaerrorline then
+ if linenumber == 0 or not filename or filename == "" then
+ print("\nfatal lua error:\n\n",lastluaerror,"\n")
+ luatex.abort()
+ return
+ else
+ report("lua error on line %s in file %s:\n\n%s",linenumber,filename,lastluaerror)
+ end
+ elseif lastmpserror then
+ report("mp error on line %s in file %s:\n\n%s",linenumber,filename,lastmpserror)
else
- report("lua error on line %s in file %s:\n\n%s",linenumber,filename,lastluaerror)
+ report("tex error on line %s in file %s: %s",linenumber,filename,lasttexerror)
+ if lastcontext then
+ report_nl()
+ report_str(lastcontext)
+ report_nl()
+ elseif tex.show_context then
+ report_nl()
+ tex.show_context()
+ end
end
- elseif lastmpserror then
- report("mp error on line %s in file %s:\n\n%s",linenumber,filename,lastmpserror)
- else
- report("tex error on line %s in file %s: %s",linenumber,filename,lasttexerror)
- if lastcontext then
+ report_nl()
+ report_str(tracers.showlines(filename,linenumber,offset,tonumber(luaerrorline)))
+ report_nl()
+ end
+ local errname = file.addsuffix(tex.jobname .. "-error","log")
+ if quitonerror then
+ table.save(errname,specification)
+ local help = specification.lasttexhelp
+ if help and #help > 0 then
report_nl()
- report_str(lastcontext)
+ report_str(help)
report_nl()
- elseif tex.show_context then
report_nl()
- tex.show_context()
end
+ luatex.abort()
end
- report_nl()
- report_str(tracers.showlines(filename,linenumber,offset,tonumber(luaerrorline)))
- report_nl()
+ busy = false
end
end
+luatex.wrapup(function() os.remove(file.addsuffix(tex.jobname .. "-error","log")) end)
+
local function processwarning(offset)
- -- local inputstack = resolvers.inputstack
- -- local filename = inputstack[#inputstack] or status.filename
- -- local linenumber = tonumber(status.linenumber) or 0
local lastwarning = status.lastwarningstring or "?"
local lastlocation = status.lastwarningtag or "?"
resetmessages()
tracers.printwarning {
- -- filename = filename,
- -- linenumber = linenumber,
- -- offset = tonumber(offset) or 10,
lastwarning = lastwarning ,
lastlocation = lastlocation,
}
@@ -272,7 +324,7 @@ directives.register("system.errorcontext", function(v)
register('show_error_message', nop)
register('show_warning_message',function() processwarning(v) end)
register('show_error_hook', function() processerror(v) end)
- register('show_lua_error_hook', nop)
+ register('show_lua_error_hook', function() processerror(v) end)
else
register('show_error_message', nil)
register('show_error_hook', nil)
@@ -288,20 +340,27 @@ lmx = lmx or { }
lmx.htmfile = function(name) return environment.jobname .. "-status.html" end
lmx.lmxfile = function(name) return resolvers.findfile(name,'tex') end
+local function reportback(lmxname,default,variables)
+ if lmxname == false then
+ return variables
+ else
+ local name = lmx.show(type(lmxname) == "string" and lmxname or default,variables)
+ if name then
+ logs.report("context report","file: %s",name)
+ end
+ end
+end
+
function lmx.showdebuginfo(lmxname)
local variables = {
['title'] = 'ConTeXt Debug Information',
['color-background-one'] = lmx.get('color-background-green'),
['color-background-two'] = lmx.get('color-background-blue'),
}
- if lmxname == false then
- return variables
- else
- lmx.show(lmxname or 'context-debug.lmx',variables)
- end
+ reportback(lmxname,"context-debug.lmx",variables)
end
-function lmx.showerror(lmxname)
+local function showerror(lmxname)
local filename, linenumber, errorcontext = status.filename, tonumber(status.linenumber) or 0, ""
if not filename then
filename, errorcontext = 'unknown', 'error in filename'
@@ -319,15 +378,18 @@ function lmx.showerror(lmxname)
['filename'] = filename,
['errorcontext'] = errorcontext,
}
- if lmxname == false then
- return variables
- else
- lmx.show(lmxname or 'context-error.lmx',variables)
- end
+ reportback(lmxname,"context-error.lmx",variables)
+ luatex.abort()
end
-function lmx.overloaderror()
- callback.register('show_error_hook', function() lmx.showerror() end) -- prevents arguments being passed
+lmx.showerror = showerror
+
+function lmx.overloaderror(v)
+ if v == "scite" then
+ usescitelexer = true
+ end
+ callback.register('show_error_hook', function() showerror() end) -- prevents arguments being passed
+ callback.register('show_lua_error_hook', function() showerror() end) -- prevents arguments being passed
end
directives.register("system.showerror", lmx.overloaderror)
@@ -367,6 +429,8 @@ directives.register("system.showerror", lmx.overloaderror)
-- end
-- end)
+local implement = interfaces.implement
+
implement { name = "showtrackers", actions = trackers.show }
implement { name = "enabletrackers", actions = trackers.enable, arguments = "string" }
implement { name = "disabletrackers", actions = trackers.disable, arguments = "string" }
diff --git a/Master/texmf-dist/tex/context/base/mkiv/trac-exp.lua b/Master/texmf-dist/tex/context/base/mkiv/trac-exp.lua
index 5879f1b7bad..e25110999f2 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/trac-exp.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/trac-exp.lua
@@ -64,7 +64,7 @@ function exporters.man(specification,...)
end
--
result[#result+1] = formatters['.TH "%s" "1" "%s" "version %s" "%s"'](name,os.date("01-01-%Y"),version,detail)
- result[#result+1] = formatters[".SH NAME\n.B %s"](name)
+ result[#result+1] = formatters[".SH NAME\n %s - %s"](name,detail) -- KB/TL wants 'detail' in this line too
result[#result+1] = formatters[".SH SYNOPSIS\n.B %s [\n.I OPTIONS ...\n.B ] [\n.I FILENAMES\n.B ]"](runner)
result[#result+1] = formatters[".SH DESCRIPTION\n.B %s"](detail)
--
diff --git a/Master/texmf-dist/tex/context/base/mkiv/trac-inf.lua b/Master/texmf-dist/tex/context/base/mkiv/trac-inf.lua
index a7823c251b5..40dfe854e15 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/trac-inf.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/trac-inf.lua
@@ -29,7 +29,7 @@ statistics.threshold = 0.01
local statusinfo, n, registered, timers = { }, 0, { }, { }
setmetatableindex(timers,function(t,k)
- local v = { timing = 0, loadtime = 0 }
+ local v = { timing = 0, loadtime = 0, offset = 0 }
t[k] = v
return v
end)
@@ -39,48 +39,58 @@ local function hastiming(instance)
end
local function resettiming(instance)
- timers[instance or "notimer"] = { timing = 0, loadtime = 0 }
+ timers[instance or "notimer"] = { timing = 0, loadtime = 0, offset = 0 }
end
local ticks = clock
local seconds = function(n) return n or 0 end
--- if FFISUPPORTED and ffi and os.type == "windows" then
---
--- local okay, kernel = pcall(ffi.load,"kernel32")
---
--- if kernel then
---
--- local tonumber = ffi.number or tonumber
---
--- ffi.cdef[[
--- int QueryPerformanceFrequency(int64_t *lpFrequency);
--- int QueryPerformanceCounter(int64_t *lpPerformanceCount);
--- ]]
---
--- local target = ffi.new("__int64[1]")
---
--- ticks = function()
--- if kernel.QueryPerformanceCounter(target) == 1 then
--- return tonumber(target[0])
--- else
--- return 0
--- end
--- end
---
--- local target = ffi.new("__int64[1]")
---
--- seconds = function(ticks)
--- if kernel.QueryPerformanceFrequency(target) == 1 then
--- return ticks / tonumber(target[0])
--- else
--- return 0
--- end
--- end
---
--- end
---
--- end
+if lua.getpreciseticks then
+
+ ticks = lua.getpreciseticks
+ seconds = lua.getpreciseseconds
+
+elseif FFISUPPORTED and ffi and os.type == "windows" then
+
+ local okay, kernel = pcall(ffi.load,"kernel32")
+
+ if kernel then
+
+ local tonumber = ffi.number or tonumber
+
+ ffi.cdef[[
+ int QueryPerformanceFrequency(int64_t *lpFrequency);
+ int QueryPerformanceCounter(int64_t *lpPerformanceCount);
+ ]]
+
+ local target = ffi.new("__int64[1]")
+
+ ticks = function()
+ if kernel.QueryPerformanceCounter(target) == 1 then
+ return tonumber(target[0])
+ else
+ return 0
+ end
+ end
+
+ local target = ffi.new("__int64[1]")
+
+ seconds = function(ticks)
+ if kernel.QueryPerformanceFrequency(target) == 1 then
+ return ticks / tonumber(target[0])
+ else
+ return 0
+ end
+ end
+
+ end
+
+else
+
+ -- excessive timing costs some 1-2 percent runtime
+
+end
+
local function starttiming(instance,reset)
local timer = timers[instance or "notimer"]
@@ -118,12 +128,27 @@ local function stoptiming(instance)
return 0
end
+local function benchmarktimer(instance)
+ local timer = timers[instance or "notimer"]
+ local it = timer.timing
+ if it > 1 then
+ timer.timing = it - 1
+ else
+ local starttime = timer.starttime
+ if starttime and starttime > 0 then
+ timer.offset = ticks() - starttime
+ else
+ timer.offset = 0
+ end
+ end
+end
+
local function elapsed(instance)
if type(instance) == "number" then
return instance
else
local timer = timers[instance or "notimer"]
- return timer and seconds(timer.loadtime) or 0
+ return timer and seconds(timer.loadtime - 2*(timer.offset or 0)) or 0
end
end
@@ -138,7 +163,7 @@ local function currenttime(instance)
else
local starttime = timer.starttime
if starttime and starttime > 0 then
- return seconds(timer.loadtime + ticks() - starttime)
+ return seconds(timer.loadtime + ticks() - starttime - 2*(timer.offset or 0))
end
end
return 0
@@ -168,6 +193,7 @@ statistics.elapsed = elapsed
statistics.elapsedtime = elapsedtime
statistics.elapsedindeed = elapsedindeed
statistics.elapsedseconds = elapsedseconds
+statistics.benchmarktimer = benchmarktimer
-- general function .. we might split this module
@@ -193,10 +219,17 @@ function statistics.show()
-- register("luatex banner", function()
-- return lower(status.banner)
-- end)
- register("used engine", function()
- return format("%s version %s with functionality level %s, banner: %s",
- LUATEXENGINE, LUATEXVERSION, LUATEXFUNCTIONALITY, lower(status.banner))
- end)
+ if LUATEXENGINE == "luametatex" then
+ register("used engine", function()
+ return format("%s version %s, functionality level %s, format id %s",
+ LUATEXENGINE, LUATEXVERSION, LUATEXFUNCTIONALITY, LUATEXFORMATID)
+ end)
+ else
+ register("used engine", function()
+ return format("%s version %s with functionality level %s, banner: %s",
+ LUATEXENGINE, LUATEXVERSION, LUATEXFUNCTIONALITY, lower(status.banner))
+ end)
+ end
register("control sequences", function()
return format("%s of %s + %s", status.cs_count, status.hash_size,status.hash_extra)
end)
@@ -239,7 +272,11 @@ end
function statistics.memused() -- no math.round yet -)
local round = math.round or math.floor
- return format("%s MB (ctx: %s MB)",round(collectgarbage("count")/1000), round(status.luastate_bytes/1000000))
+ return format("%s MB, ctx: %s MB, max: %s MB)",
+ round(collectgarbage("count")/1000),
+ round(status.luastate_bytes/1000000),
+ status.luastate_bytes_max and round(status.luastate_bytes_max/1000000) or "unknown"
+ )
end
starttiming(statistics)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/trac-lmx.lua b/Master/texmf-dist/tex/context/base/mkiv/trac-lmx.lua
index c7f94961878..a531a76d671 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/trac-lmx.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/trac-lmx.lua
@@ -684,8 +684,9 @@ end
lmx.make = lmxmake
function lmx.show(name,variables)
+ -- todo: pcall
local htmfile = lmxmake(name,variables)
- lmx.popupfile(htmfile)
+ -- lmx.popupfile(htmfile)
return htmfile
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/trac-log.lua b/Master/texmf-dist/tex/context/base/mkiv/trac-log.lua
index e76c9f6849e..bb154067f70 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/trac-log.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/trac-log.lua
@@ -114,17 +114,34 @@ local direct, subdirect, writer, pushtarget, poptarget, setlogfile, settimedlog,
-- we don't want this overhead for single messages (not that there are that
-- many; we could have a special weak table)
+local function ansisupported(specification)
+ if specification ~= "ansi" and specification ~= "ansilog" then
+ return false
+ elseif os and os.enableansi then
+ return os.enableansi()
+ else
+ return false
+ end
+end
+
if runningtex and texio then
if texio.setescape then
texio.setescape(0) -- or (false)
end
- if arg then
+ if arg and ansisupported then
-- we're don't have environment.arguments yet
for k, v in next, arg do -- k can be negative !
if v == "--ansi" or v == "--c:ansi" then
- variant = "ansi"
+ if ansisupported("ansi") then
+ variant = "ansi"
+ end
+ break
+ elseif v == "--ansilog" or v == "--c:ansilog" then
+ if ansisupported("ansilog") then
+ variant = "ansilog"
+ end
break
end
end
@@ -246,6 +263,11 @@ if runningtex and texio then
}
}
+ variants.ansilog = {
+ formats = variants.ansi.formats,
+ targets = variants.default.targets,
+ }
+
logs.flush = io.flush
writer = function(...)
@@ -368,6 +390,9 @@ if runningtex and texio then
t = specification.targets
f = specification.formats or specification
else
+ if not ansisupported(specification) then
+ specification = "default"
+ end
local v = variants[specification]
if v then
t = v.targets
@@ -394,8 +419,8 @@ if runningtex and texio then
subdirect_nop = f.subdirect_nop
status_yes = f.status_yes
status_nop = f.status_nop
- if variant == "ansi" then
- useluawrites() -- because tex escapes ^^
+ if variant == "ansi" or variant == "ansilog" then
+ useluawrites() -- because tex escapes ^^, not needed in lmtx
end
settarget(whereto)
end
@@ -511,6 +536,9 @@ else
if type(specification) == "table" then
f = specification.formats or specification
else
+ if not ansisupported(specification) then
+ specification = "default"
+ end
local v = variants[specification]
if v then
f = v.formats
@@ -817,38 +845,6 @@ local nesting = 0
local verbose = false
local hasscheme = url.hasscheme
-function logs.show_open(name)
- -- if hasscheme(name) ~= "virtual" then
- -- if verbose then
- -- nesting = nesting + 1
- -- report_files("level %s, opening %s",nesting,name)
- -- else
- -- write(formatters["(%s"](name)) -- tex adds a space
- -- end
- -- end
-end
-
-function logs.show_close(name)
- -- if hasscheme(name) ~= "virtual" then
- -- if verbose then
- -- report_files("level %s, closing %s",nesting,name)
- -- nesting = nesting - 1
- -- else
- -- write(")") -- tex adds a space
- -- end
- -- end
-end
-
-function logs.show_load(name)
- -- if hasscheme(name) ~= "virtual" then
- -- if verbose then
- -- report_files("level %s, loading %s",nesting+1,name)
- -- else
- -- write(formatters["(%s)"](name))
- -- end
- -- end
-end
-
-- there may be scripts out there using this:
local simple = logs.reporter("comment")
@@ -946,6 +942,15 @@ logs.reporters = reporters
logs.exporters = exporters
function logs.application(t)
+ --
+ local arguments = environment and environment.arguments
+ if arguments then
+ local ansi = arguments.ansi or arguments.ansilog
+ if ansi then
+ logs.setformatters(arguments.ansi and "ansi" or "ansilog")
+ end
+ end
+ --
t.name = t.name or "unknown"
t.banner = t.banner
t.moreinfo = moreinfo
@@ -1039,8 +1044,8 @@ end
-- this is somewhat slower but prevents out-of-order messages when print is mixed
-- with texio.write
-io.stdout:setvbuf('no')
-io.stderr:setvbuf('no')
+-- io.stdout:setvbuf('no')
+-- io.stderr:setvbuf('no')
-- windows: > nul 2>&1
-- unix : > null 2>&1
diff --git a/Master/texmf-dist/tex/context/base/mkiv/trac-set.lua b/Master/texmf-dist/tex/context/base/mkiv/trac-set.lua
index 6311d638296..960c4ef84a6 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/trac-set.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/trac-set.lua
@@ -9,8 +9,9 @@ if not modules then modules = { } end modules ['trac-set'] = { -- might become u
-- maybe this should be util-set.lua
local type, next, tostring, tonumber = type, next, tostring, tonumber
+local print = print
local concat, sortedhash = table.concat, table.sortedhash
-local format, find, lower, gsub, topattern = string.format, string.find, string.lower, string.gsub, string.topattern
+local formatters, find, lower, gsub, topattern = string.formatters, string.find, string.lower, string.gsub, string.topattern
local is_boolean = string.is_boolean
local settings_to_hash = utilities.parsers.settings_to_hash
local allocate = utilities.storage.allocate
@@ -30,11 +31,11 @@ local data = { }
-- The sorting is needed to get a predictable setters in case of *.
local trace_initialize = false -- only for testing during development
+local frozen = true -- this needs checking
function setters.initialize(filename,name,values) -- filename only for diagnostics
local setter = data[name]
if setter then
- frozen = true -- don't permitoverload
-- trace_initialize = true
local data = setter.data
if data then
@@ -254,8 +255,8 @@ end
local enable, disable, register, list, show = setters.enable, setters.disable, setters.register, setters.list, setters.show
-function setters.report(setter,...)
- print(format("%-15s : %s\n",setter.name,format(...)))
+function setters.report(setter,fmt,...)
+ print(formatters["%-15s : %s\n"](setter.name,formatters[fmt](...)))
end
local function default(setter,name)
@@ -278,7 +279,7 @@ function setters.new(name) -- we could use foo:bar syntax (but not used that oft
disable = function(...) disable (setter,...) end,
reset = function(...) reset (setter,...) end, -- can be dangerous
register = function(...) register(setter,...) end,
- list = function(...) list (setter,...) end,
+ list = function(...) return list (setter,...) end,
show = function(...) show (setter,...) end,
default = function(...) return default (setter,...) end,
value = function(...) return value (setter,...) end,
diff --git a/Master/texmf-dist/tex/context/base/mkiv/trac-tex.mkiv b/Master/texmf-dist/tex/context/base/mkiv/trac-tex.mkiv
index 4c2db68f327..c69f3febb93 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/trac-tex.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/trac-tex.mkiv
@@ -32,11 +32,38 @@
\unexpanded\def\enabletextracers [#1]{\processcommalist[#1]\syst_textracers_enable }
\unexpanded\def\disabletextracers[#1]{\processcommalist[#1]\syst_textracers_disable}
-\def\syst_textracers_enable #1{\csname enabletracer#1\endcsname}
-\def\syst_textracers_disable#1{\csname disabletracer#1\endcsname}
+\def\syst_textracers_enable #1{\begincsname enabletracer#1\endcsname}
+\def\syst_textracers_disable#1{\begincsname disabletracer#1\endcsname}
% The next one is for Taco, although we can use directives as well:
\unexpanded\def\nomkivstatistics{\enabledirectives[system.nostatistics]}
+%D This is not really a tracker but for decades it lived in my \type {cont-loc}
+%D file. I moved it here because I wanted someone else to use it. This macro is not
+%D really useful for users. I kept the \LUA\ variant in \type {cont-loc.mkiv}.
+
+\installcorenamespace{profilemacrocount}
+\installcorenamespace{profilemacromacro}
+
+\newtoks\t_syst_profile
+
+\appendtoks
+ \the\t_syst_profile
+\to \everystoptext
+
+\unexpanded\def\profilemacro#1% an oldie, but modernized a bit
+ {\edef\p_name{\csstring#1}%
+ \ifcsname\??profilemacrocount\p_name\endcsname \else
+ \expandafter\newcount\csname\??profilemacrocount\p_name\endcsname
+ \expandafter\let\csname\??profilemacromacro\p_name\endcsname#1%
+ \xtoksapp\t_syst_profile
+ {\writestatus
+ {profile}%
+ {\string#1: \noexpand\the\csname\??profilemacrocount\p_name\endcsname}}%
+ \unexpanded\xdef#1%
+ {\global\advance\csname\??profilemacrocount\p_name\endcsname\plusone
+ \expandafter\noexpand\csname\??profilemacromacro\p_name\endcsname}%
+ \fi}
+
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/trac-vis.lua b/Master/texmf-dist/tex/context/base/mkiv/trac-vis.lua
index 4dc3bd03b02..e592b7d0c98 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/trac-vis.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/trac-vis.lua
@@ -7,10 +7,10 @@ if not modules then modules = { } end modules ['trac-vis'] = {
}
local node, nodes, attributes, fonts, tex = node, nodes, attributes, fonts, tex
-local type, tonumber, next = type, tonumber, next
+local type, tonumber, next, rawget = type, tonumber, next, rawget
local gmatch = string.gmatch
local formatters = string.formatters
-local compactfloat = number.compactfloat
+local round = math.round
-- This module started out in the early days of mkiv and luatex with visualizing
-- kerns related to fonts. In the process of cleaning up the visual debugger code it
@@ -388,11 +388,12 @@ local c_skip_b = "trace:m"
local c_glyph = "trace:o"
local c_ligature = "trace:s"
local c_white = "trace:w"
-local c_math = "trace:r"
+local c_math = "trace:s"
local c_origin = "trace:o"
local c_discretionary = "trace:d"
local c_expansion = "trace:o"
local c_depth = "trace:o"
+local c_indent = "trace:s"
local c_positive_d = "trace:db"
local c_negative_d = "trace:dr"
@@ -510,11 +511,11 @@ local glyphexpansion do
glyphexpansion = function(head,current)
local extra = getexpansion(current)
- if extra ~= 0 then
+ if extra and extra ~= 0 then
extra = extra / 1000
local info = f_cache[extra]
if not info then
- local text = hpack_string(compactfloat(extra,"%.1f"),usedfont)
+ local text = hpack_string(round(extra),usedfont)
local rule = new_rule(emwidth/fraction,exheight,2*exheight)
local list = getlist(text)
if extra > 0 then
@@ -548,7 +549,7 @@ local kernexpansion do
extra = extra / 1000
local info = f_cache[extra]
if not info then
- local text = hpack_string(compactfloat(extra,"%.1f"),usedfont)
+ local text = hpack_string(round(extra),usedfont)
local rule = new_rule(emwidth/fraction,exheight,4*exheight)
local list = getlist(text)
if extra > 0 then
@@ -779,12 +780,7 @@ local ruledbox do
setlink(info,next)
end
if prev and prev > 0 then
- -- if getid(prev) == gluespec_code then
- -- report_visualize("ignoring invalid prev")
- -- -- weird, how can this happen, an inline glue-spec, probably math
- -- else
- setlink(prev,info)
- -- end
+ setlink(prev,info)
end
if head == current then
return info, info
@@ -863,22 +859,25 @@ end
local ruledglue do
- local gluecodes = nodes.gluecodes
- local leadercodes = nodes.gluecodes
+ local gluecodes = nodes.gluecodes
+ local leadercodes = nodes.gluecodes
- local userskip_code = gluecodes.userskip
- local spaceskip_code = gluecodes.spaceskip
- local xspaceskip_code = gluecodes.xspaceskip
- local leftskip_code = gluecodes.leftskip
- local rightskip_code = gluecodes.rightskip
+ local userskip_code = gluecodes.userskip
+ local spaceskip_code = gluecodes.spaceskip
+ local xspaceskip_code = gluecodes.xspaceskip
+ local leftskip_code = gluecodes.leftskip
+ local rightskip_code = gluecodes.rightskip
+ local parfillskip_code = gluecodes.parfillskip
+ local indentskip_code = gluecodes.indentskip
+ local correctionskip_code = gluecodes.correctionskip
- local cleaders_code = leadercodes.cleaders
+ local cleaders_code = leadercodes.cleaders
local g_cache_v = caches["vglue"]
local g_cache_h = caches["hglue"]
local tags = {
- -- [gluecodes.userskip] = "US",
+ -- [userskip_code] = "US",
[gluecodes.lineskip] = "LS",
[gluecodes.baselineskip] = "BS",
[gluecodes.parskip] = "PS",
@@ -886,23 +885,29 @@ local ruledglue do
[gluecodes.belowdisplayskip] = "DB",
[gluecodes.abovedisplayshortskip] = "SA",
[gluecodes.belowdisplayshortskip] = "SB",
- [gluecodes.leftskip] = "LS",
- [gluecodes.rightskip] = "RS",
[gluecodes.topskip] = "TS",
[gluecodes.splittopskip] = "ST",
[gluecodes.tabskip] = "AS",
- [gluecodes.spaceskip] = "SP",
- [gluecodes.xspaceskip] = "XS",
- [gluecodes.parfillskip] = "PF",
+ [gluecodes.lefthangskip] = "LH",
+ [gluecodes.righthangskip] = "RH",
[gluecodes.thinmuskip] = "MS",
[gluecodes.medmuskip] = "MM",
[gluecodes.thickmuskip] = "ML",
+ [gluecodes.intermathskip] = "IM",
+ [gluecodes.mathskip] = "MT",
[leadercodes.leaders] = "NL",
[leadercodes.cleaders] = "CL",
[leadercodes.xleaders] = "XL",
[leadercodes.gleaders] = "GL",
-- true = "VS",
-- false = "HS",
+ [leftskip_code] = "LS",
+ [rightskip_code] = "RS",
+ [spaceskip_code] = "SP",
+ [xspaceskip_code] = "XS",
+ [parfillskip_code] = "PF",
+ [indentskip_code] = "IN",
+ [correctionskip_code] = "CS",
}
-- we sometimes pass previous as we can have issues in math (not watertight for all)
@@ -919,6 +924,8 @@ local ruledglue do
info = sometext(amount,l_glue,c_space)
elseif subtype == leftskip_code or subtype == rightskip_code then
info = sometext(amount,l_glue,c_skip_a)
+ elseif subtype == parfillskip_code or subtype == indentskip_code or subtype == correctionskip_code then
+ info = sometext(amount,l_glue,c_indent)
elseif subtype == userskip_code then
if width > 0 then
info = sometext(amount,l_glue,c_positive)
@@ -996,12 +1003,12 @@ local ruledkern do
local k_cache_v = caches["vkern"]
local k_cache_h = caches["hkern"]
- ruledkern = function(head,current,vertical)
+ ruledkern = function(head,current,vertical,mk)
local kern = getkern(current)
local cache = vertical and k_cache_v or k_cache_h
local info = cache[kern]
if not info then
- local amount = formatters["%s:%0.3f"](vertical and "VK" or "HK",kern*pt_factor)
+ local amount = formatters["%s:%0.3f"](vertical and "VK" or (mk and "MK") or "HK",kern*pt_factor)
if kern > 0 then
info = sometext(amount,l_kern,c_positive)
elseif kern < 0 then
@@ -1113,6 +1120,7 @@ do
local math_code = nodecodes.math
local hlist_code = nodecodes.hlist
local vlist_code = nodecodes.vlist
+ local marginkern_code = nodecodes.marginkern
local kerncodes = nodes.kerncodes
local fontkern_code = kerncodes.fontkern
@@ -1330,6 +1338,10 @@ do
if trace_math then
head, current = math(head,current)
end
+ elseif id == marginkern_code then
+ if trace_kern then
+ head, current = ruledkern(head,current,vertical,true)
+ end
end
goto next
::list::
diff --git a/Master/texmf-dist/tex/context/base/mkiv/type-ini.lua b/Master/texmf-dist/tex/context/base/mkiv/type-ini.lua
index cd5b32d3e6c..a2e19725ed0 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/type-ini.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/type-ini.lua
@@ -25,14 +25,7 @@ local p_strip = Cs((P("type-") * (P("imp-")^0))^0/"" * P(1)^0)
local report = logs.reporter("fonts","typescripts")
local function action(name,foundname)
- -- context.startreadingfile()
- -- context.unprotect()
- -- context.pushendofline()
- -- context.input(foundname)
- -- context.popendofline()
- -- context.protect()
- -- context.stopreadingfile()
- context.loadfoundtypescriptfile(foundname)
+ context.loadfoundtypescriptfile(name,foundname)
end
local patterns = {
@@ -81,7 +74,7 @@ local patterns = {
-- elseif name_two == name then
-- report("unknown library %a",name_one)
-- else
--- commands.uselibrary {
+-- resolvers.uselibrary {
-- name = name_two,
-- patterns = patterns,
-- action = action,
diff --git a/Master/texmf-dist/tex/context/base/mkiv/type-ini.mklx b/Master/texmf-dist/tex/context/base/mkiv/type-ini.mklx
new file mode 100644
index 00000000000..5470c9016ce
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/type-ini.mklx
@@ -0,0 +1,618 @@
+%D \module
+%D [ file=type-ini,
+%D version=2001.03.05,
+%D title=\CONTEXT\ Typescript Macros,
+%D subtitle=Initialization,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Typescript Macros / Initialization}
+
+\registerctxluafile{type-ini}{}
+
+%D The default fontclass is empty. We could demand always using fontclasses, and
+%D then make the calling macros simplier (always assume fontclass) but apart from
+%D downward compatibility issues, it would make global, class spanning definitions a
+%D pain. Some day we will introduce a default class.
+%D
+%D The \type {type-ini} and \type {font-ini} modules come as a pair and have mutual
+%D dependencies.
+%D
+%D At some point we will only store in memory so some code can go away.
+
+\unprotect
+
+\definesystemvariable {ts} % TypeScript / for the moment we keep this one
+
+\newcount \c_font_typescripts_n_of_preloaded
+\newconditional\c_font_typescripts_quit
+\newtoks \c_font_typescripts_document
+\newconditional\c_font_typescripts_preload
+\newconditional\c_font_typescripts_first_pass \settrue\c_font_typescripts_first_pass
+
+\newif \iftypescriptfound % will become a mode
+\newif \iftracetypescripts
+
+\newtoks \everybeforedefinetypeface
+\newtoks \everyafterdefinetypeface
+
+\let\typescriptfiles \empty
+\let\currenttypescripts\empty
+\let\currenttypefile \empty
+
+\installmacrostack\currenttypefile
+
+\let\typescriptone \empty % public, used in typescripts
+\let\typescripttwo \empty % public, used in typescripts
+\let\typescriptthree\empty % public, used in typescripts
+
+\installmacrostack\typescriptone
+\installmacrostack\typescripttwo
+\installmacrostack\typescriptthree
+
+\let\fontclassstyle \empty
+
+\installmacrostack\fontclassstyle
+
+\let\m_font_typescripts_one \empty
+\let\m_font_typescripts_two \empty
+\let\m_font_typescripts_three\empty
+\let\m_font_typescripts_check\empty
+\let\m_font_typescripts_match\empty
+
+\installmacrostack\m_font_typescripts_one
+\installmacrostack\m_font_typescripts_two
+\installmacrostack\m_font_typescripts_three
+
+\let\t_font_typescripts\relax % uses as synonym
+
+\installcorenamespace{typescriptcache}
+\installcorenamespace{typescriptfiles}
+\installcorenamespace{typescriptonce}
+\installcorenamespace{typescriptsynonyms}
+\installcorenamespace{typescriptprefix}
+\installcorenamespace{typescriptinheritances}
+\installcorenamespace{typescriptdefaultstyles}
+\installcorenamespace{typescriptrelatives}
+
+\definesystemvariable{ts} % TypeScript
+
+% tricky ... here we push/pop ... so \let
+
+\let\typescriptmethod\plusone % 1: empty==all==true 2: empty==false
+\let\typescriptstate \plustwo % 1: process 2: store
+
+\installmacrostack\typescriptmethod
+\installmacrostack\typescriptstate
+
+\unexpanded\def\starttypescriptcollection
+ {\dosingleempty\font_typescripts_collection_start}
+
+\def\font_typescripts_collection_start[#tag]%
+ {}
+
+\let\stoptypescriptcollection\relax
+
+\unexpanded\def\usetypescriptfile[#filename]%
+ {\doifelse{#filename}\v!reset
+ {\let\typescriptfiles\empty}
+ {\splitfilename{#filename}%
+ \addtocommalist\splitoffbase\typescriptfiles}}
+
+\unexpanded\def\usetypescript {\dotripleempty\font_typescripts_use_one}
+\unexpanded\def\usetypescriptexact{\dotripleempty\font_typescripts_use_two}
+
+\def\font_typescripts_use_one{\let\typescriptmethod\plusone\font_typescripts_use}
+\def\font_typescripts_use_two{\let\typescriptmethod\plustwo\font_typescripts_use}
+
+\installmacrostack\stoptypescript
+
+\unexpanded\def\font_typescripts_use[#one][#two][#three]%
+ {\push_macro_m_font_typescripts_one
+ \push_macro_m_font_typescripts_two
+ \push_macro_m_font_typescripts_three
+ \edef\m_font_typescripts_one {\truetypescript{#one}}%
+ \edef\m_font_typescripts_two {\truetypescript{#two}}%
+ \edef\m_font_typescripts_three{\truetypescript{#three}}%
+ \push_macro_typescriptone
+ \push_macro_typescripttwo
+ \push_macro_typescriptthree
+ \push_macro_typescriptmethod
+ \push_macro_typescriptstate
+ \push_macro_stoptypescript
+ \typescriptfoundfalse
+ \let\typescriptstate\plusone % why
+ \iftracetypescripts
+ \writestatus\m!fonts{request: [\m_font_typescripts_one] [\m_font_typescripts_two] [\m_font_typescripts_three]}%
+ \fi
+ \ifhmode
+ \font_typescripts_use_inline
+ \else
+ \font_typescripts_use_display
+ \fi
+ \setfalse\c_font_typescripts_first_pass
+ \pop_macro_stoptypescript
+ \pop_macro_typescriptstate
+ \pop_macro_typescriptmethod
+ \pop_macro_typescriptthree
+ \pop_macro_typescripttwo
+ \pop_macro_typescriptone
+ \pop_macro_m_font_typescripts_three
+ \pop_macro_m_font_typescripts_two
+ \pop_macro_m_font_typescripts_one}
+
+\def\font_typescripts_use_display
+ {\processcommacommand[\typescriptfiles]\font_typescripts_load_file
+ \the\c_font_typescripts_document}
+
+\let\font_typescripts_use_inline\font_typescripts_use_display
+
+\unexpanded\def\preloadtypescripts
+ {\ifproductionrun\settrue\c_font_typescripts_preload\fi}
+
+\prependtoks
+ \preloadtypescripts
+\to \everyjob
+
+\unexpanded\def\loadtypescriptfile[#1]%
+ {\push_macro_typescriptstate
+ \let\typescriptstate\plustwo % assumes 2 at the outer level
+ \clf_loadtypescriptfile{#1}%
+ \pop_macro_typescriptstate}
+
+\unexpanded\def\loadfoundtypescriptfile#1#2% name foundname / not a user command
+ {\startreadingfile
+ \unprotect
+ \pushendofline
+ \input{#2}%
+ \popendofline
+ \protect
+ \stopreadingfile}
+
+\unexpanded\def\quittypescriptscanning
+ {\settrue\c_font_typescripts_quit} % public
+
+\def\font_typescripts_start_store#definitions\stoptypescript
+ {\global\advance\c_font_typescripts_n_of_preloaded\plusone
+ \expandafter\normalgdef\csname\??typescriptcache\the\c_font_typescripts_n_of_preloaded\endcsname
+ {\starttypescript#definitions\stoptypescript}%
+ \gtoksapp\t_font_typescripts\expandafter
+ {\csname\??typescriptcache\the\c_font_typescripts_n_of_preloaded\endcsname}}
+
+\def\font_typescripts_collection_start_store#definitions\stoptypescriptcollection
+ {\global\advance\c_font_typescripts_n_of_preloaded\plusone
+ \expandafter\normalgdef\csname\??typescriptcache\the\c_font_typescripts_n_of_preloaded\endcsname
+ {\starttypescriptcollection#definitions\stoptypescriptcollection}%
+ \gtoksapp\t_font_typescripts\expandafter
+ {\csname\??typescriptcache\the\c_font_typescripts_n_of_preloaded\endcsname}}
+
+\def\font_typescripts_load_file#filename%
+ {\setfalse\c_font_typescripts_quit
+ \push_macro_currenttypefile
+ \def\currenttypefile{#filename}%
+ \ifconditional\c_font_typescripts_preload
+ \font_typescript_process_typescript_file_and_store
+ \else
+ \font_typescript_process_typescript_file
+ \fi
+ \pop_macro_currenttypefile
+ \ifconditional\c_font_typescripts_quit
+ \quitcommalist
+ \setfalse\c_font_typescripts_quit
+ \fi}
+
+\def\font_typescript_process_typescript_file_and_store
+ {\expandafter\let\expandafter\t_font_typescripts\csname\??typescriptfiles\currenttypefile\endcsname
+ \ifx\t_font_typescripts\relax
+ \font_typescript_process_typescript_store_indeed
+ \fi
+ \the\t_font_typescripts}
+
+\def\font_typescript_process_typescript_store_indeed
+ {\newtoks\t_font_typescripts % is \relaxed elsewhere
+ \begingroup
+ \let\starttypescript \font_typescripts_start_store
+ \let\starttypescriptcollection\font_typescripts_collection_start_store
+ \font_typescript_process_typescript_file
+ \endgroup
+ \expandafter\let\csname\??typescriptfiles\currenttypefile\endcsname\t_font_typescripts}
+
+\def\font_typescript_process_typescript_file
+ {\clf_doprocesstypescriptfile{\currenttypefile}}
+
+\unexpanded\def\usetypescriptonce
+ {\dotripleempty\font_typescripts_use_once}
+
+\def\font_typescripts_use_once[#one][#two][#three]%
+ {\ifcsname\??typescriptonce#one:#two:#three\endcsname
+ \writestatus\m!fonts{once (#one) (#two) (#three)}%
+ \else
+ \expandafter\let\csname\??typescriptonce#one:#two:#three\endcsname\relax
+ \font_typescripts_use[#one][#two][#three]%
+ \fi}
+
+% \definetypescriptsynonym[lbr][cmr]
+
+\unexpanded\def\definetypescriptsynonym
+ {\dodoubleempty\font_typescripts_synonym_define}
+
+\def\font_typescripts_synonym_define[#name][#synonym]%
+ {\ifsecondargument\setevalue{\??typescriptsynonyms#name}{#synonym}\fi}
+
+\def\truetypescript#name% recursive so no \lastnamedcs
+ {\ifcsname\??typescriptsynonyms#name\endcsname
+ %\expandafter\truetypescript\csname\??typescriptsynonyms#name\endcsname
+ \expandafter\truetypescript\lastnamedcs
+ \else
+ #name%
+ \fi}
+
+% script [serif] [default] [size]
+% script [serif] [computer-modern] [size]
+% script [serif] [computer-modern] [ec]
+% script [serif] [computer-modern] [name]
+% script [serif] [computer-modern] [special]
+
+\prependtoks
+ \settrue\c_font_typescripts_first_pass
+\to \everyjob
+
+\unexpanded\def\starttypescript
+ {\ifcase\typescriptstate
+ % 0 = skip
+ \expandafter\font_typescripts_start_gobble
+ \or
+ % 1 = process
+ \expandafter\font_typescripts_start_process
+ \or
+ % 2 = store
+ \expandafter\font_typescripts_start_document
+ \else
+ % ? = skip
+ \expandafter\font_typescripts_start_gobble
+ \fi}
+
+\def\font_typescripts_start_gobble#definitions\stoptypescript{}
+
+\def\font_typescripts_start_document#definitions\stoptypescript
+ {\toksapp\c_font_typescripts_document{\starttypescript#definitions\stoptypescript}}
+
+\def\font_typescripts_start_process % could be a faster \doifelsenextoptionalif needed
+ {\let\typescriptone \m_font_typescripts_one
+ \let\typescripttwo \m_font_typescripts_two
+ \let\typescriptthree\m_font_typescripts_three
+ \let\m_font_typescripts_match\empty
+ \doifelsenextoptionalcs\font_typescripts_start_process_one\font_typescripts_start_process_all}
+
+\def\font_typescripts_start_process_all % could be a \let
+ {\ifconditional\c_font_typescripts_first_pass
+ \expandafter\font_typescripts_start_process_indeed
+ \else
+ % skip this since it may do unwanted resets, like
+ % setting symbolic font names to unknown, especially
+ % in run time user type scripts
+ \expandafter\font_typescripts_start_gobble
+ \fi}
+
+\def\font_typescripts_show_match
+ {\writestatus\m!fonts{match:\ifx\currenttypefile\relax\space *\fi \m_font_typescripts_match}}
+
+\def\font_typescripts_start_process_yes
+ {\ifdone
+ \typescriptfoundtrue
+ \iftracetypescripts\font_typescripts_show_match\fi
+ \expandafter\font_typescripts_start_process_indeed
+ \else
+ \expandafter\font_typescripts_start_gobble
+ \fi}
+
+\def\font_typescripts_start_process_one
+ {\font_typescripts_check\m_font_typescripts_one\typescriptone\font_typescripts_start_process_again_one}
+
+\def\font_typescripts_start_process_two
+ {\font_typescripts_check\m_font_typescripts_two\typescripttwo\font_typescripts_start_process_again_two}
+
+\def\font_typescripts_start_process_three
+ {\font_typescripts_check\m_font_typescripts_three\typescriptthree\font_typescripts_start_process_again_three}
+
+\def\font_typescripts_start_process_again_one
+ {\doifelsenextoptionalcs\font_typescripts_start_process_two\font_typescripts_start_process_yes}
+
+\def\font_typescripts_start_process_again_two
+ {\doifelsenextoptionalcs\font_typescripts_start_process_three\font_typescripts_start_process_yes}
+
+\let\font_typescripts_start_process_again_three\font_typescripts_start_process_yes
+
+\def\font_typescripts_start_process_indeed
+ {\push_macro_fontclass}
+
+\unexpanded\def\stoptypescript
+ {\pop_macro_fontclass}
+
+\def\font_typescripts_check#asked#target#followup[#value]% script use value next
+ {\donefalse
+ \edef\m_font_typescripts_check{#value}%
+ \ifx\m_font_typescripts_check\empty % no longer needed / met
+ \ifcase\typescriptmethod\or\donetrue\fi
+ \orelse\ifx#asked\s!all
+ \donetrue
+ \orelse\ifx\m_font_typescripts_check\s!all
+ \donetrue
+ \orelse\ifx#asked\m_font_typescripts_check % saves 10% trace so probably faster too
+ \donetrue
+ \let#target\m_font_typescripts_check
+ \else
+ \doifelsecommon\m_font_typescripts_check#asked\donetrue\donefalse
+ \ifdone
+ \let#target\commalistelement
+ \fi
+ \fi
+ \ifdone
+ \iftracetypescripts\extendtypescriptmatch\fi
+ \expandafter#followup%
+ \else
+ \expandafter\font_typescripts_start_gobble
+ \fi}
+
+\def\extendtypescriptmatch
+ {\edef\m_font_typescripts_match{\m_font_typescripts_match\space[\m_font_typescripts_check]}}
+
+%D Map files will go away in \LUATEX, but till that happens we use stripped down
+%D support for loading them.
+
+\unexpanded\def\loadmapfile{\dosingleempty\font_map_load_file}
+\unexpanded\def\loadmapline{\dodoubleempty\font_map_load_line}
+
+\def\font_map_load_file[#filename]%
+ {\clf_loadmapfile{#filename}}
+
+\def\font_map_load_line[#kind][#data]%
+ {\clf_loadmapline{#kind}{#data}}
+
+\unexpanded\def\forgetmapfiles
+ {\clf_resetmapfiles}
+
+% \prependtoks
+% \loadmapfile[mkiv-base.map]% can't we preload this one?
+% \to \everystarttext
+
+%D A handy shortcut:
+
+% \definetypescriptprefix[serif][Serif]
+% \definetypescriptprefix[sans] [Sans]
+% \definetypescriptprefix[mono] [Mono]
+%
+% \starttypescript [serif,sans,mono] [handling,hanging,hz] [pure,normal,hz,quality]
+% \setupfontsynonym [\typescriptprefix\typescriptone] [handling=\typescriptthree]
+% \stoptypescript
+
+\unexpanded\def\definetypescriptprefix
+ {\dodoubleargument\font_typescripts_define_prefix}
+
+\def\font_typescripts_define_prefix[#name][#prefix]%
+ {\setgvalue{\??typescriptprefix#name}{#prefix}} % made global
+
+\def\typescriptprefix#name%
+ %{\ifcsname\??typescriptprefix#name\endcsname\csname\??typescriptprefix#name\endcsname\else#name\fi}
+ {\ifcsname\??typescriptprefix#name\endcsname\lastnamedcs\else#name\fi}
+
+% defining typefaces:
+%
+% \definetypeface [joke] [rm]
+% \definetypeface [joke] [rm] [settings]
+% \definetypeface [joke] [rm] [serif] [lucida]
+% \definetypeface [joke] [rm] [serif] [lucida] [size]
+% \definetypeface [joke] [rm] [serif] [lucida] [size] [settings]
+% \definetypeface [joke] [specification]
+
+\unexpanded\def\definetypeface
+ {\dosixtupleargument\font_typefaces_define}
+
+\appendtoks
+ \font_helpers_reset_fontclass_math_families\fontclass
+\to \everybeforedefinetypeface
+
+%D This hooks into the font switcher:
+
+\settrue\autotypescripts
+
+\unexpanded\def\trycurrentfontclass#typeface%
+ {\ifconditional\autotypescripts
+ \usetypescript[#typeface]%
+ \ifcsname\??fontclassyes#typeface\endcsname
+ \edef\fontclass{#typeface}%
+ \else
+ \iftracetypescripts\writestatus\m!fonts{auto load typescript file 1: [#typeface]}\fi
+ \usetypescriptfile[#typeface]%
+ \usetypescript[#typeface]%
+ \ifcsname\??fontclassyes#typeface\endcsname
+ \edef\fontclass{#typeface}%
+ \else
+ % todo: message
+ \letvalueempty{\??fontclassnop#typeface}%
+ \fi
+ \fi
+ \else
+ % todo: message
+ \letvalueempty{\??fontclassnop#typeface}%
+ \fi}
+
+%D Now we define:
+
+\def\font_typefaces_define
+ {\iffifthargument
+ \expandafter\font_typefaces_define_a
+ \orelse\iffourthargument
+ \expandafter\font_typefaces_define_b
+ \orelse\ifthirdargument
+ \expandafter\font_typefaces_define_c
+ \else
+ \expandafter\font_typefaces_define_d
+ \fi}
+
+\def\font_typefaces_define_a[#name][#style][#fontshape][#fontname][#fontsize][#settings]%
+ {\iftracetypescripts\writestatus\m!fonts{define: [#name] [#style] [#fontshape] [#fontname]}\fi
+ \font_typefaces_define_indeed[#name][#style]%
+ \font_typefaces_defining_start{#name}{#style}{#settings}%
+ \font_typescripts_use_one[#fontshape][#fontname][\s!name]% [\s!name,\s!default]%
+ \iftypescriptfound
+ % we're okay
+ \orelse\ifconditional\autotypescripts
+ \iftracetypescripts\writestatus\m!fonts{auto load typescript file 2: [#fontname]}\fi
+ \usetypescriptfile[#fontname]%
+ \font_typescripts_use_one[#fontshape][#fontname][\s!name]% [\s!name,\s!default]%
+ \fi
+ \font_typescripts_use_one[#fontshape][#fontsize][\s!size]%
+ \font_typefaces_defining_stop}
+
+\def\font_typefaces_define_b[#name][#style][#fontshape][#fontname][#dummya][#dummyb]%
+ {\font_typefaces_define_a[#name][#style][#fontshape][#fontname][\s!default][#dummyb]}
+
+\def\font_typefaces_define_c[#name][#style][#dummya][#dummyb][#dummyc][#dummyd]%
+ {\font_typefaces_define_indeed[#name][#style]}
+
+\def\font_typefaces_define_d[#name][#specification][#dummya][#dummyb][#dummyc][#dummyd]% use definitions in lfg file
+ {\clf_definetypeface{#name}{#specification}}
+
+\def\font_typefaces_define_indeed[#name][#style]% saveguard against redefinition
+ {\doifsomething{#name}
+ {\ifcsname\??typescriptdefaultstyles#name\endcsname \else
+ \registerfontclass{#name}%
+ \setxvalue{\??typescriptdefaultstyles#name}{#style}%
+ \fi
+ \ifcsname#name\endcsname \else
+ \setugvalue{#name}{\switchtotypeface[#name][#style]}%
+ \fi}}
+
+\def\font_typefaces_defining_start#name#style#settings%
+ {\let\@@tsrscale \!!plusone % as we push/pop
+ \let\@@tsfeatures \empty
+ \let\@@tsfallbacks \empty
+ \let\@@tsgoodies \empty
+ \let\@@tsdirection \empty
+ \let\@@tsdesignsize\empty
+ \geteparameters[\??ts][#settings]% todo raw
+ \push_macro_fontclass
+ \push_macro_fontclassstyle
+ \setcurrentfontclass{#name}%
+ \savefontclassparameters{#style}\@@tsrscale\@@tsfeatures\@@tsfallbacks\@@tsgoodies\@@tsdesignsize\@@tsdirection
+ \the\everybeforedefinetypeface}
+
+\def\tsvar#key#default% undocumented and unofficial
+ {\expandafter\ifx\csname\??ts#key\endcsname\empty
+ #default%
+ \else
+ \csname\??ts#key\endcsname
+ \fi}
+
+\def\font_typefaces_defining_stop
+ {\the\everyafterdefinetypeface
+ \pop_macro_fontclassstyle
+ \pop_macro_fontclass}
+
+\def\dofastdefinetypeface#name#style#fontshape#fontsize#settings% called from the lua end (via case d)
+ {\font_typefaces_define_indeed[#name][#style]%
+ \font_typefaces_defining_start{#name}{#style}{#settings}%
+ \font_typescripts_use_one[#fontshape][#fontsize][\s!size]%
+ \font_typefaces_defining_stop}
+
+\unexpanded\def\setuptypeface% [class] [settings]
+ {\dodoubleempty\font_typefaces_setup}
+
+\unexpanded\def\switchtotypeface% [class] [settings]
+ {\dodoubleempty\font_typefaces_switch}
+
+\def\font_typefaces_setup[#class][#settings]%
+ {\setcurrentfontclass{#class}%
+ \let\globalfontclass\fontclass
+ \ifsecondargument
+ \setupbodyfont[#settings]%
+ \orelse\ifx\fontclass\empty
+ \setupbodyfont[\s!rm]%
+ \orelse\ifcsname\??typescriptdefaultstyles\fontclass\endcsname
+ %\setupbodyfont[\csname\??typescriptdefaultstyles\fontclass\endcsname]%
+ \expandafter\setupbodyfont\expandafter[\lastnamedcs]%
+ \else
+ \setupbodyfont[\s!rm]%
+ \fi
+ \ifmmode\mr\else\tf\fi} % needed ?
+
+\def\font_typefaces_switch[#class][#settings]%
+ {\setcurrentfontclass{#class}%
+ \let\globalfontclass\globalfontclass
+ \ifsecondargument
+ \switchtobodyfont[#settings]%
+ \orelse\ifx\fontclass\empty
+ \switchtobodyfont[\s!rm]%
+ \orelse\ifcsname\??typescriptdefaultstyles\fontclass\endcsname
+ %\switchtobodyfont[\csname\??typescriptdefaultstyles\fontclass\endcsname]%
+ \expandafter\switchtobodyfont\expandafter[\lastnamedcs]%
+ \else
+ \switchtobodyfont[\s!rm]%
+ \fi
+ \ifmmode\mr\else\tf\fi} % needed ?
+
+%D For Taco:
+%D
+%D \starttyping
+%D \inherittypeface[palatino][rm][postscript]
+%D \inherittypeface[palatino][rm][\fontclass]
+%D \inherittypeface[palatino][rm] % == \fontclass
+%D \inherittypeface[palatino] % == [rm,ss,tt,mm]
+%D \stoptyping
+
+\unexpanded\def\inherittypeface
+ {\dotripleempty\font_typescripts_inherit_indeed}
+
+\def\font_typescripts_inherit_indeed[#name][#styles][#parentclass]%
+ {\doifelsenothing{#styles}
+ {\font_typescripts_inherit_indeed[#name][\s!rm,\s!ss,\s!tt,\s!mm][\fontclass]}
+ {\doifnot{#name}{#parentclass}
+ {\glet\font_typescripts_inherit_check\font_typescripts_inherit_check_indeed
+ \def\font_typescripts_inherit_check_step#style{\setevalue{\??typescriptinheritances#name:#style}{#parentclass}}%
+ \processcommalist[#styles]\font_typescripts_inherit_check_step}}}
+
+\let\font_typescripts_inherit_check_step\relax
+
+%D This hooks into the font mechanism with:
+
+\def\font_typescripts_inherit_check_indeed#name% called often
+ {\ifcsname\??typescriptinheritances\fontclass:#name\endcsname
+ %\expandafter\let\expandafter\fontclass\csname\??typescriptinheritances\fontclass:#name\endcsname
+ \expandafter\let\expandafter\fontclass\lastnamedcs
+ \fi}
+
+\let\font_typescripts_inherit_check\gobbleoneargument
+
+% not yet:
+%
+% \def\font_helpers_check_relative_font_id
+% {\ifcsname\??typescriptrelatives\fontclass\endcsname
+% \expandafter\let\expandafter\relativefontid\csname\??typescriptrelatives\fontclass\endcsname
+% \else
+% \expandafter\normalxdef\csname\??typescriptrelatives\fontclass\endcsname{\the\lastfontid}%
+% \let\relativefontid\minusone
+% \fi}
+
+\def\v_font_string_d % default fontstyle (expands to \s!Serif in font-ini)
+ {\expandafter\ifx\csname\??typescriptdefaultstyles\fontclass\endcsname\s!rm \s!Serif \else
+ \expandafter\ifx\csname\??typescriptdefaultstyles\fontclass\endcsname\s!ss \s!Sans \else
+ \expandafter\ifx\csname\??typescriptdefaultstyles\fontclass\endcsname\s!tt \s!Mono \else
+ \s!Serif \fi\fi\fi}
+
+\unexpanded\def\font_helpers_set_fontstyle_of_fontclass
+ {\ifx\fontclass\empty
+ \let\fontstyle\s!rm
+ \orelse\ifcsname\??typescriptdefaultstyles\fontclass\endcsname
+ %\edef\fontstyle{\csname\??typescriptdefaultstyles\fontclass\endcsname}%
+ \edef\fontstyle{\lastnamedcs}%
+ \else
+ \let\fontstyle\s!rm
+ \fi}
+
+\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/type-ini.mkvi b/Master/texmf-dist/tex/context/base/mkiv/type-ini.mkvi
index ac5f6af2f95..ff89c7a8fe4 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/type-ini.mkvi
+++ b/Master/texmf-dist/tex/context/base/mkiv/type-ini.mkvi
@@ -15,13 +15,13 @@
\registerctxluafile{type-ini}{}
-%D The default fontclass is empty. We could demand always using fontclasses,
-%D and then make the calling macros simplier (always assume fontclass) but
-%D apart from downward compatibility issues, it would make global, class
-%D spanning definitions a pain. Some day we will introduce a default class.
+%D The default fontclass is empty. We could demand always using fontclasses, and
+%D then make the calling macros simplier (always assume fontclass) but apart from
+%D downward compatibility issues, it would make global, class spanning definitions a
+%D pain. Some day we will introduce a default class.
%D
-%D The \type {type-ini} and \type {font-ini} modules come as a pair and have
-%D mutual dependencies.
+%D The \type {type-ini} and \type {font-ini} modules come as a pair and have mutual
+%D dependencies.
%D
%D At some point we will only store in memory so some code can go away.
@@ -183,8 +183,8 @@
\preloadtypescripts
\to \everyjob
-% The next will change .. we can load a file inside a typescript but as the state is
-% 1 then, it doesn't get stored without doing that explicitly
+%D The next will change .. we can load a file inside a typescript but as the state is
+%D 1 then, it doesn't get stored without doing that explicitly
\unexpanded\def\loadtypescriptfile[#1]%
{\push_macro_typescriptstate
@@ -192,11 +192,11 @@
\clf_loadtypescriptfile{#1}%
\pop_macro_typescriptstate}
-\unexpanded\def\loadfoundtypescriptfile#1%
+\unexpanded\def\loadfoundtypescriptfile#1#2% name foundname / not a user command
{\startreadingfile
\unprotect
\pushendofline
- \input{#1}%
+ \input{#2}%
\popendofline
\protect
\stopreadingfile}
@@ -386,11 +386,34 @@
\expandafter\font_typescripts_start_gobble
\fi}
+% \def\font_typescripts_check#asked#target#followup[#value]% script use value next
+% {\donefalse
+% \edef\m_font_typescripts_check{#value}%
+% \ifx\m_font_typescripts_check\empty % no longer needed / met
+% \ifcase\typescriptmethod\or\donetrue\fi
+% \else\ifx#asked\s!all
+% \donetrue
+% \else\ifx\m_font_typescripts_check\s!all
+% \donetrue
+% \else\ifx#asked\m_font_typescripts_check % saves 10% trace so probably faster too
+% \donetrue
+% \let#target\m_font_typescripts_check
+% \else\ifcondition\hascommonargumentcondition\m_font_typescripts_check#asked%
+% \donetrue
+% \let#target\commalistelement
+% \fi\fi\fi\fi\fi
+% \ifdone
+% \iftracetypescripts\extendtypescriptmatch\fi
+% \expandafter#followup%
+% \else
+% \expandafter\font_typescripts_start_gobble
+% \fi}
+
\def\extendtypescriptmatch
{\edef\m_font_typescripts_match{\m_font_typescripts_match\space[\m_font_typescripts_check]}}
-%D Map files will go away in \LUATEX, but till that happens we
-%D use stripped down support for loading them.
+%D Map files will go away in \LUATEX, but till that happens we use stripped down
+%D support for loading them.
\unexpanded\def\loadmapfile{\dosingleempty\font_map_load_file}
\unexpanded\def\loadmapline{\dodoubleempty\font_map_load_line}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/type-set.mkiv b/Master/texmf-dist/tex/context/base/mkiv/type-set.mkiv
index c6b0c8841fc..68cd939d769 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/type-set.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/type-set.mkiv
@@ -25,11 +25,13 @@
% but ... let's make sure that newlines are gone
- \loadfoundtypescriptfile{type-def.mkiv}
- \loadfoundtypescriptfile{type-lua.mkiv}
- \loadfoundtypescriptfile{type-siz.mkiv}
- \loadfoundtypescriptfile{type-fbk.mkiv}
- \loadfoundtypescriptfile{type-imp-latinmodern.mkiv}
+ % beware: these are low level calls, so not user commands !
+
+ \loadfoundtypescriptfile\empty{type-def.mkiv}
+ \loadfoundtypescriptfile\empty{type-lua.mkiv}
+ \loadfoundtypescriptfile\empty{type-siz.mkiv}
+ \loadfoundtypescriptfile\empty{type-fbk.mkiv}
+ \loadfoundtypescriptfile\empty{type-imp-latinmodern.mkiv}
% and not:
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-bld.lua b/Master/texmf-dist/tex/context/base/mkiv/typo-bld.lua
index 55d74281f50..6874d385a9b 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-bld.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-bld.lua
@@ -36,6 +36,11 @@ local texsetattribute = tex.setattribute
local texnest = tex.nest
local texlists = tex.lists
+local texget = tex.get
+local texset = tex.set
+
+local texgetdimen = tex.getdimen
+
local nodes = nodes
local nodeidstostring = nodes.idstostring
local nodepool = nodes.pool
@@ -43,7 +48,12 @@ local new_baselineskip = nodepool.baselineskip
local new_lineskip = nodepool.lineskip
local insert_node_before = nodes.insert_before
local hpack_node = nodes.hpack
-local count_nodes = nodes.countall
+
+local nuts = nodes.nuts
+local tonode = nodes.tonode
+local tonut = nodes.tonut
+local count_nodes = nuts.countall
+local getattr = nuts.getattr
local starttiming = statistics.starttiming
local stoptiming = statistics.stoptiming
@@ -114,7 +124,7 @@ function constructors.handler(head,followed_by_display)
if type(head) == "boolean" then
return head
else
- local attribute = head[a_parbuilder] -- or mainconstructor
+ local attribute = getattr(head,a_parbuilder) -- or mainconstructor
if attribute then
local method = names[attribute]
if method then
@@ -143,11 +153,11 @@ function parbuilders.constructors.methods.oneline(head,followed_by_display)
-- when needed we will turn this into a helper
local t = texnest[texnest.ptr]
local h = hpack_node(head)
- local d = tex.baselineskip.width - t.prevdepth - h.height
+ local d = texget("baselineskip",false) - t.prevdepth - h.height
t.prevdepth = h.depth
t.prevgraf = 1
- if d < tex.lineskiplimit then
- return insert_node_before(h,h,new_lineskip(tex.lineskip))
+ if d < texget("lineskiplimit") then
+ return insert_node_before(h,h,new_lineskip(texget("lineskip",false))) -- no stretch etc
else
return insert_node_before(h,h,new_baselineskip(d))
end
@@ -167,7 +177,9 @@ local function processor(head,followed_by_display)
-- todo: not again in otr so we need to flag
if enabled then
starttiming(parbuilders)
- local head = actions(head,followed_by_display)
+ head = tonut(head)
+ head = actions(head,followed_by_display)
+ head = tonode(head)
stoptiming(parbuilders)
return head
else
@@ -195,6 +207,7 @@ function builders.vpack_filter(head,groupcode,size,packtype,maxdepth,direction)
local done = false
if head then
starttiming(builders)
+ head = tonut(head)
if trace_vbox_builder then
local before = count_nodes(head)
head, done = vboxactions(head,groupcode,size,packtype,maxdepth,direction)
@@ -203,6 +216,7 @@ function builders.vpack_filter(head,groupcode,size,packtype,maxdepth,direction)
else
head, done = vboxactions(head,groupcode)
end
+ head = tonode(head)
stoptiming(builders)
end
return head, done
@@ -216,14 +230,12 @@ local pageactions = nodes.tasks.actions("mvlbuilders")
local function report(groupcode,head)
report_page_builder("trigger: %s",groupcode)
- report_page_builder(" vsize : %p",tex.vsize)
- report_page_builder(" pagegoal : %p",tex.pagegoal)
- report_page_builder(" pagetotal: %p",tex.pagetotal)
+ report_page_builder(" vsize : %p",texget("vsize"))
+ report_page_builder(" pagegoal : %p",texget("pagegoal"))
+ report_page_builder(" pagetotal: %p",texget("pagetotal"))
report_page_builder(" list : %s",head and nodeidstostring(head) or "<empty>")
end
--- use tex.[sg]etlist
-
-- check why box is called before after_linebreak .. maybe make categories and
-- call 'm less
@@ -243,7 +255,7 @@ function builders.buildpage_filter(groupcode)
head, done = pageactions(head,groupcode)
stoptiming(builders)
-- -- doesn't work here (not passed on?)
- -- tex.pagegoal = tex.vsize - tex.dimen.d_page_floats_inserted_top - tex.dimen.d_page_floats_inserted_bottom
+ -- texset("pagegoal,texget("vsize") - texgetdimen("d_page_floats_inserted_top") - texgetdimen("d_page_floats_inserted_bottom")
texlists.contrib_head = head or nil -- needs checking
-- tex.setlist("contrib_head",head,head and nodes.tail(head))
return done and head or true -- no return value needed
@@ -365,34 +377,3 @@ trackers.register("builders.hpack.overflow",function(v)
show = v
registercallback("hpack_quality",(report or show) and hpack_quality or nil,"check hpack quality")
end)
-
--- local ignoredepth = - 65536000
---
--- registercallback(
--- "append_to_vlist_filter",
--- function(box,location,prevdepth,mirrored),
--- if prevdepth > ignoredepth then
--- local b = tex.baselineskip
--- local d = b.width - prevdepth
--- local g = nil
--- if mirrored then
--- d = d - box.depth
--- else
--- d = d - box.height
--- end
--- if d < tex.lineskiplimit then
--- g = nodes.pool.glue()
--- g.spec = tex.lineskip
--- else
--- g = nodes.pool.baselineskip(d)
--- end
--- g.next = box
--- box.prev = g
--- return g, mirrored and box.height or box.depth
--- else
--- return box, mirrored and box.height or box.depth
--- end
--- end,
--- "experimental prevdepth checking"
--- )
-
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-brk.lua b/Master/texmf-dist/tex/context/base/mkiv/typo-brk.lua
index 76e50ce1859..d670c53196f 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-brk.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-brk.lua
@@ -265,7 +265,7 @@ function breakpoints.handler(head)
-- for now we collect but when found ok we can move the handler here
-- although it saves nothing in terms of performance
local lang = getlang(current)
- local smap = lang and lang >= 0 and lang < 0x7FFF and (cmap[numbers[lang]] or cmap[""])
+ local smap = lang and lang >= 0 and lang < 0x7FFF and (cmap[languages.numbers[lang]] or cmap[""])
if smap then
local skip = smap.skip
local start = current
@@ -314,17 +314,17 @@ function breakpoints.handler(head)
return head
end
-- we have hits
- local numbers = languages.numbers
+ -- local numbers = languages.numbers
for i=1,#done do
local data = done[i]
local start = data[1]
local stop = data[2]
local cmap = data[3]
local smap = data[4]
--- -- we do a sanity check for language
--- local lang = getlang(start)
--- local smap = lang and lang >= 0 and lang < 0x7FFF and (cmap[numbers[lang]] or cmap[""])
--- if smap then
+ -- we do a sanity check for language
+ -- local lang = getlang(start)
+ -- local smap = lang and lang >= 0 and lang < 0x7FFF and (cmap[numbers[lang]] or cmap[""])
+ -- if smap then
local nleft = smap.nleft
local cleft = 0
local prev = getprev(start)
@@ -392,7 +392,7 @@ function breakpoints.handler(head)
head, start = method(head,start,stop,smap,kern)
end
end
--- end
+ -- end
end
end
return head
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-cap.lua b/Master/texmf-dist/tex/context/base/mkiv/typo-cap.lua
index 7e8003c620f..c1666a9f119 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-cap.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-cap.lua
@@ -315,6 +315,9 @@ register(variables.camel, camel) -- 10
register(variables.cap, variables.capital) -- clone
register(variables.Cap, variables.Capital) -- clone
+-- This can be more clever: when we unset we can actually use the same attr ref if
+-- needed. Using properties to block further usage is not faster.
+
function cases.handler(head) -- not real fast but also not used on much data
local start = head
local lastfont = { }
@@ -341,9 +344,10 @@ function cases.handler(head) -- not real fast but also not used on much data
end
local action = actions[n] -- map back to low number
if action then
- start = action(start,attr,lastfont,n,count)
+ local quit
+ start, quit = action(start,attr,lastfont,n,count)
if trace_casing then
- report_casing("case trigger %a, instance %a, fontid %a, result %a",n,m,id,ok)
+ report_casing("case trigger %a, instance %a, fontid %a, result %a",n,m,id,quit and "-" or "+")
end
elseif trace_casing then
report_casing("unknown case trigger %a",n)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-chr.lua b/Master/texmf-dist/tex/context/base/mkiv/typo-chr.lua
index 15d14c8601b..7a0f1fd7521 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-chr.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-chr.lua
@@ -99,8 +99,8 @@ local wordboundary_code = boundarycodes.word
local texgetnest = tex.getnest -- to be used
local texsetcount = tex.setcount
-local flush_node = node.flush_node
-local flush_list = node.flush_list
+local flush_node = nodes.flush_node
+local flush_list = nodes.flush_list
local settexattribute = tex.setattribute
local punctuation = characters.is_punctuation
@@ -175,7 +175,7 @@ local function pickup(head,tail,str)
while true do
local prev = first.prev
if prev and prev[a_marked] == attr then
- if prev.id == localpar_code then -- and prev.subtype == 0
+ if prev.id == localpar_code then -- and start_of_par(prev)
break
else
first = prev
@@ -188,6 +188,14 @@ local function pickup(head,tail,str)
end
end
+local function found(str)
+ local list = texgetnest()
+ if list then
+ local tail = list.tail
+ return tail and tail[a_marked] == marked[str]
+ end
+end
+
local actions = {
remove = function(specification)
local list = texgetnest()
@@ -254,6 +262,12 @@ interfaces.implement {
arguments = "string",
}
+interfaces.implement {
+ name = "doifelsemarkedcontent",
+ actions = function(str) ctx_doifelse(found(str)) end,
+ arguments = "string",
+}
+
-- We just put these here.
interfaces.implement {
@@ -284,6 +298,8 @@ interfaces.implement {
-- end,
-- }
+-- not needed in lmtx ...
+
interfaces.implement {
name = "lastnodeid",
actions = function()
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-chr.mkiv b/Master/texmf-dist/tex/context/base/mkiv/typo-chr.mkiv
index 365c79e5154..a648d4588c6 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-chr.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-chr.mkiv
@@ -1,4 +1,3 @@
-
%D \module
%D [ file=typo-chr,
%D version=2015.01.01, % or about that time
@@ -79,6 +78,9 @@
\def\typo_marked_remove[#1]%
{\clf_pickupmarkedcontent action{remove}mark{#1}\relax}
+\unexpanded\def\doifelsemarkedcontent#1%
+ {\clf_doifelsemarkedcontent{#1}}
+
%D A few helpers (put here for convenience):
%D
%D \starttyping
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-del.mkiv b/Master/texmf-dist/tex/context/base/mkiv/typo-del.mkiv
index 2ce98841e19..9320c37ee6f 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-del.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-del.mkiv
@@ -674,22 +674,29 @@
\dostoptagged}
\def\typo_delimited_nextleft_symbol#1%
- {\localleftbox\bgroup
+ {\let\typo_delimited_reset_next_symbol\typo_delimited_reset_next_symbol_indeed
+ \localleftbox\bgroup
\swapmacros\leftboundarycharacter\rightboundarycharacter
\boundarycharactermode\plusone
\typo_delimited_left_symbol#1%
\egroup}
\def\typo_delimited_nextright_symbol#1%
- {\localrightbox\bgroup
+ {\let\typo_delimited_reset_next_symbol\typo_delimited_reset_next_symbol_indeed
+ \localrightbox\bgroup
\swapmacros\leftboundarycharacter\rightboundarycharacter
\boundarycharactermode\plusone
\typo_delimited_right_symbol#1%
\egroup}
+\unexpanded\def\typo_delimited_reset_next_symbol_indeed
+ {\localleftbox {}%
+ \localrightbox{}}%
+
+\let\typo_delimited_reset_next_symbol\relax
+
\appendtoks
- \localleftbox {}%
- \localrightbox{}%
+ \typo_delimited_reset_next_symbol
\to \everyforgetall
% \starttext
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-dha.lua b/Master/texmf-dist/tex/context/base/mkiv/typo-dha.lua
index c0bbdc39668..9a6e39f42a2 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-dha.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-dha.lua
@@ -65,6 +65,7 @@ local insert_node_before = nuts.insert_before
local insert_node_after = nuts.insert_after
local remove_node = nuts.remove
local end_of_math = nuts.end_of_math
+local start_of_par = nuts.start_of_par
local nodepool = nuts.pool
@@ -331,7 +332,7 @@ local function process(start)
end
textdir = autodir
setprop(current,"direction",true)
- elseif id == localpar_code and getsubtype(current) == 0 then
+ elseif id == localpar_code and start_of_par(current) then
local direction = getdirection(current)
if direction == righttoleft_code then
autodir = -1
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-drp.lua b/Master/texmf-dist/tex/context/base/mkiv/typo-drp.lua
index 9a59891e103..50eb765f221 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-drp.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-drp.lua
@@ -6,7 +6,7 @@ if not modules then modules = { } end modules ['typo-drp'] = {
license = "see context related readme files"
}
--- This ons is sensitive for order (e.g. when combined with first line
+-- This one is sensitive for order (e.g. when combined with first line
-- processing.
-- todo: use isglyph
@@ -28,6 +28,7 @@ local enableaction = tasks.enableaction
local disableaction = tasks.disableaction
local nuts = nodes.nuts
+local tonut = nodes.tonut
local getnext = nuts.getnext
local getprev = nuts.getprev
@@ -36,6 +37,9 @@ local getid = nuts.getid
local getattr = nuts.getattr
local getwhd = nuts.getwhd
+local getprop = nuts.getprop
+local setprop = nuts.setprop
+
local setattr = nuts.setattr
local setlink = nuts.setlink
local setprev = nuts.setprev
@@ -45,6 +49,8 @@ local setchar = nuts.setchar
local setwhd = nuts.setwhd
local setkern = nuts.setkern
local setoffsets = nuts.setoffsets
+local setglyphdata = nuts.setglyphdata
+local setattr = nuts.setattr
local hpack_nodes = nuts.hpack
@@ -56,6 +62,7 @@ local new_kern = nodepool.kern
local insert_before = nuts.insert_before
local insert_after = nuts.insert_after
local remove_node = nuts.remove
+local start_of_par = nuts.start_of_par
local nextnode = nuts.traversers.node
local nextglyph = nuts.traversers.glyph
@@ -69,7 +76,6 @@ local v_last = variables.last
local texget = tex.get
local texset = tex.set
-local texsetattribute = tex.setattribute
local unsetvalue = attributes.unsetvalue
local glyph_code = nodecodes.glyph
@@ -88,16 +94,16 @@ local a_colormodel = attributes.private('colormodel')
local category = characters.category
-local settings = nil
-
-function initials.set(specification)
- settings = specification or { }
- settings.enabled = true
+local function set(par,specification)
enableaction("processors","typesetters.initials.handler")
if trace_initials then
report_initials("enabling initials")
end
- texsetattribute(a_initial,1)
+ setprop(par,a_initial,specification)
+end
+
+function initials.set(specification)
+ nuts.setparproperty(set,specification)
end
interfaces.implement {
@@ -122,256 +128,224 @@ interfaces.implement {
}
}
--- dropped caps experiment (will be done properly when luatex
--- stores the state in the local par node) .. btw, search still
--- works with dropped caps, as does an export
-
--- we need a 'par' attribute and in fact for dropped caps we don't need
--- need an attribute ... dropit will become s state counter (or end up
--- in the localpar user data
-
--- for the moment, each paragraph gets a number as id (attribute) ..problem
--- with nesting .. or anyhow, needed for tagging anyway
-
-- todo: prevent linebreak .. but normally a initial ends up at the top of
-- a page so this has a low priority
actions[v_default] = function(head,setting)
- local id = getid(head)
- if id == localpar_code then -- and getsubtype(head) == 0
- -- begin of par
- local first = getnext(head)
- local indent = false
- -- parbox .. needs to be set at 0
- if first and getid(first) == hlist_code then
- first = getnext(first)
- indent = true
- end
- -- we need to skip over kerns and glues (signals)
- while first and getid(first) ~= glyph_code do
- first = getnext(first)
- end
- if first and getid(first) == glyph_code then
- local ma = setting.ma or 0
- local ca = setting.ca
- local ta = setting.ta
- local last = first
- local distance = setting.distance or 0
- local voffset = setting.voffset or 0
- local hoffset = setting.hoffset or 0
- local parindent = texget("parindent")
- local baseline = texget("baselineskip",false)
- local lines = tonumber(setting.n) or 0
- local dynamic = setting.dynamic
- local font = setting.font
- local method = settings_to_hash(setting.method)
- local length = tonumber(setting.m) or 1
- --
- -- 1 char | n chars | skip first quote | ignore punct | keep punct
- --
- if getattr(first,a_initial) then
- for current in nextnode, getnext(first) do
- if getattr(current,a_initial) then
- last = current
- else
- break
- end
- end
- elseif method[v_auto] then
- local char = getchar(first)
- local kind = category(char)
- if kind == "po" or kind == "pi" then
- if method[v_first] then
- -- remove quote etc before initial
- local next = getnext(first)
- if not next then
- -- don't start with a quote or so
- return head
- end
- last = nil
- for current in nextglyph, next do
- head, first = remove_node(head,first,true)
- first = current
- last = first
- break
- end
- if not last then
- -- no following glyph or so
- return head
- end
- else
- -- keep quote etc with initial
- local next = getnext(first)
- if not next then
- -- don't start with a quote or so
- return head
- end
- for current in nextglyph, next do
- last = current
- break
- end
- if last == first then
- return head
- end
- end
- elseif kind == "pf" then
- -- error: final quote
+ -- begin of par
+ local first = getnext(head)
+ local indent = false
+ -- parbox .. needs to be set at 0
+ if first and getid(first) == hlist_code then
+ first = getnext(first)
+ indent = true
+ end
+ -- we need to skip over kerns and glues (signals)
+ while first and getid(first) ~= glyph_code do
+ first = getnext(first)
+ end
+ if first and getid(first) == glyph_code then
+ local ma = setting.ma or 0
+ local ca = setting.ca
+ local ta = setting.ta
+ local last = first
+ local distance = setting.distance or 0
+ local voffset = setting.voffset or 0
+ local hoffset = setting.hoffset or 0
+ local parindent = texget("parindent")
+ local baseline = texget("baselineskip",false)
+ local lines = tonumber(setting.n) or 0
+ local dynamic = setting.dynamic
+ local font = setting.font
+ local method = settings_to_hash(setting.method)
+ local length = tonumber(setting.m) or 1
+ --
+ -- 1 char | n chars | skip first quote | ignore punct | keep punct
+ --
+ if getattr(first,a_initial) then
+ for current in nextnode, getnext(first) do
+ if getattr(current,a_initial) then
+ last = current
else
- -- okay
+ break
end
- -- maybe also: get all A. B. etc
- local next = getnext(first)
- if next then
- for current, char in nextglyph, next do
- local kind = category(char)
- if kind == "po" then
- if method[v_last] then
- -- remove period etc after initial
- remove_node(head,current,true)
- else
- -- keep period etc with initial
- last = current
- end
- end
- break
+ end
+ elseif method[v_auto] then
+ local char = getchar(first)
+ local kind = category(char)
+ if kind == "po" or kind == "pi" then
+ if method[v_first] then
+ -- remove quote etc before initial
+ local next = getnext(first)
+ if not next then
+ -- don't start with a quote or so
+ return head
end
- end
- else
- for current in nextglyph, first do
- last = current
- if length <= 1 then
+ last = nil
+ for current in nextglyph, next do
+ head, first = remove_node(head,first,true)
+ first = current
+ last = first
break
- else
- length = length - 1
end
- end
- end
- local current = first
- while true do
- local id = getid(current)
- if id == kern_code then
- setkern(current,0)
- elseif id == glyph_code then
- local next = getnext(current)
- if font then
- setfont(current,font)
+ if not last then
+ -- no following glyph or so
+ return head
end
- if dynamic > 0 then
- setattr(current,0,dynamic)
+ else
+ -- keep quote etc with initial
+ local next = getnext(first)
+ if not next then
+ -- don't start with a quote or so
+ return head
end
--- apply font
-
--- local g = nuts.copy(current)
--- g.subtype = 0
--- nodes.handlers.characters(g)
--- nodes.handlers.protectglyphs(g)
--- setchar(current,g.char)
--- nuts.flush_node(g)
-
- -- can be a helper
- if ca and ca > 0 then
- setattr(current,a_colormodel,ma == 0 and 1 or ma)
- setattr(current,a_color,ca)
+ for current in nextglyph, next do
+ last = current
+ break
end
- if ta and ta > 0 then
- setattr(current,a_transparency,ta)
+ if last == first then
+ return head
end
- --
- end
- if current == last then
- break
- else
- current = getnext(current)
end
+ elseif kind == "pf" then
+ -- error: final quote
+ else
+ -- okay
end
- -- We pack so that successive handling cannot touch the dropped cap. Packaging
- -- in a hlist is also needed because we cannot locally adapt e.g. parindent (not
- -- yet stored in with localpar).
- local prev = getprev(first)
- local next = getnext(last)
- --
- setprev(first)
- setnext(last)
- local dropper = hpack_nodes(first)
- local width, height, depth = getwhd(dropper)
- setwhd(dropper,0,0,0)
- --
- setlink(prev,dropper)
- setlink(dropper,next)
- --
+ -- maybe also: get all A. B. etc
+ local next = getnext(first)
if next then
- local current = next
- while current do
- local id = getid(current)
- if id == glue_code or id == kern_code then
- local next = getnext(current)
- -- remove_node(current,current,true) -- created an invalid next link and dangling remains
- remove_node(head,current,true)
- current = next
- else
- break
+ for current, char in nextglyph, next do
+ local kind = category(char)
+ if kind == "po" then
+ if method[v_last] then
+ -- remove period etc after initial
+ remove_node(head,current,true)
+ else
+ -- keep period etc with initial
+ last = current
+ end
end
+ break
end
end
- --
- local hoffset = width + hoffset + distance + (indent and parindent or 0)
+ else
for current in nextglyph, first do
- setoffsets(current,-hoffset,-voffset) -- no longer - height here
- if current == last then
+ last = current
+ if length <= 1 then
break
+ else
+ length = length - 1
end
end
- --
- first = dropper
- --
- if setting.location == v_margin then
- -- okay
- else
- if lines == 0 then -- safeguard, not too precise
- lines = ceil((height+voffset) / baseline)
+ end
+ local current = first
+ while true do
+ local id = getid(current)
+ if id == kern_code then
+ setkern(current,0)
+ elseif id == glyph_code then
+ local next = getnext(current)
+ if font then
+ setfont(current,font)
end
- -- We cannot set parshape yet ... when we can I'll add a slope
- -- option (positive and negative, in emwidth).
- local hangafter = - lines
- local hangindent = width + distance
- if trace_initials then
- report_initials("setting hangafter to %i and hangindent to %p",hangafter,hangindent)
+ if dynamic > 0 then
+ setglyphdata(current,dynamic)
end
- texset("hangafter",hangafter)
- texset("hangindent",hangindent)
+ -- can be a helper
+ if ca and ca > 0 then
+ setattr(current,a_colormodel,ma == 0 and 1 or ma)
+ setattr(current,a_color,ca)
+ end
+ if ta and ta > 0 then
+ setattr(current,a_transparency,ta)
+ end
+ --
end
- if indent then
- insert_after(first,first,new_kern(-parindent))
+ if current == last then
+ break
+ else
+ current = getnext(current)
end
end
+ -- We pack so that successive handling cannot touch the dropped cap. Packaging
+ -- in a hlist is also needed because we cannot locally adapt e.g. parindent (not
+ -- yet stored in with localpar).
+ local prev = getprev(first)
+ local next = getnext(last)
+ --
+ setprev(first)
+ setnext(last)
+ local dropper = hpack_nodes(first)
+ local width, height, depth = getwhd(dropper)
+ setwhd(dropper,0,0,0)
+ --
+ setlink(prev,dropper)
+ setlink(dropper,next)
+ --
+ if next then
+ local current = next
+ while current do
+ local id = getid(current)
+ if id == glue_code or id == kern_code then
+ local next = getnext(current)
+ -- remove_node(current,current,true) -- created an invalid next link and dangling remains
+ remove_node(head,current,true)
+ current = next
+ else
+ break
+ end
+ end
+ end
+ --
+ local hoffset = width + hoffset + distance + (indent and parindent or 0)
+ for current in nextglyph, first do
+ setoffsets(current,-hoffset,-voffset) -- no longer - height here
+ if current == last then
+ break
+ end
+ end
+ --
+ first = dropper
+ --
+ if setting.location == v_margin then
+ -- okay
+ else
+ if lines == 0 then -- safeguard, not too precise
+ lines = ceil((height+voffset) / baseline)
+ end
+ -- We cannot set parshape yet ... when we can I'll add a slope
+ -- option (positive and negative, in emwidth).
+ local hangafter = - lines
+ local hangindent = width + distance
+ if trace_initials then
+ report_initials("setting hangafter to %i and hangindent to %p",hangafter,hangindent)
+ end
+ texset("hangafter",hangafter)
+ texset("hangindent",hangindent)
+ end
+ if indent then
+ insert_after(first,first,new_kern(-parindent))
+ end
end
return head
end
+-- we can count ... when all done, we can disable ...
+
function initials.handler(head)
- local start = head
- local attr = nil
- while start do
- attr = getattr(start,a_initial)
- if attr then
- break
- elseif getid(start) == glyph then
- break
- else
- start = getnext(start)
- end
- end
- if attr then
- -- here as we can process nested boxes first so we need to keep state
- disableaction("processors","typesetters.initials.handler")
- -- texsetattribute(attribute,unsetvalue)
- local alternative = settings.alternative or v_default
- local action = actions[alternative] or actions[v_default]
- if action then
- if trace_initials then
- report_initials("processing initials, alternative %a",alternative)
+ if getid(head) == localpar_code and start_of_par(head) then
+ local settings = getprop(head,a_initial)
+ if settings then
+ disableaction("processors","typesetters.initials.handler")
+ local alternative = settings.alternative or v_default
+ local action = actions[alternative] or actions[v_default]
+ if action then
+ if trace_initials then
+ report_initials("processing initials, alternative %a",alternative)
+ end
+ return action(head,settings)
end
- return action(head,settings)
end
end
return head
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-drp.mkiv b/Master/texmf-dist/tex/context/base/mkiv/typo-drp.mkiv
index 18392510803..25b006b2f0f 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-drp.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-drp.mkiv
@@ -88,35 +88,31 @@
\begingroup
\edef\currentinitial{#1}%
\setupcurrentinitial[#2]%
- \scratchcounter \initialparameter\c!n\relax
- \scratchdistance\initialparameter\c!distance\relax
- \scratchhoffset \initialparameter\c!hoffset \relax
- \edef\p_voffset{\initialparameter\c!voffset}%
- \scratchvoffset\dimexpr\ifx\p_voffset\v!line\scratchcounter\lineheight-\lineheight\else\p_voffset\fi\relax
\resetfontfeature % might be needed in more places
\doifelsenothing{\initialparameter\c!style}
{\definedfont[\initialparameter\s!font]}
{\useinitialstyleparameter\c!style}%
\useinitialcolorparameter\c!color
- \edef\p_text{\initialparameter\c!text}% optional
+ \edef\p_voffset{\initialparameter\c!voffset}%
+ \scratchcounter \initialparameter\c!n\relax
+ \scratchvoffset\dimexpr\ifx\p_voffset\v!line\scratchcounter\lineheight-\lineheight\else\p_voffset\fi\relax
\clf_setinitial
location {\initialparameter\c!location}%
enabled true\space
n \scratchcounter
m \numexpr\initialparameter\c!m\relax
method {\initialparameter\c!method}%
- distance \scratchdistance
- hoffset \scratchhoffset
+ distance \dimexpr\initialparameter\c!distance\relax
+ hoffset \dimexpr\initialparameter\c!hoffset\relax
voffset \scratchvoffset
ma \attribute\colormodelattribute
ca \attribute\colorattribute
ta \attribute\transparencyattribute
font \fontid\font
- dynamic \attribute\zerocount % it's a bit over the top to support this here
+ dynamic \font_dynamic_value % it's a bit over the top to support this here
\relax
- \stopluacode
- \kern\zeropoint % we need a node
- \p_text
+ \attribute\initialattribute\plusone
+ \initialparameter\c!text
\endgroup
\glet\typo_initial_handle\relax}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-dua.lua b/Master/texmf-dist/tex/context/base/mkiv/typo-dua.lua
index 3db5f510ac1..0cec0e08e1e 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-dua.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-dua.lua
@@ -85,6 +85,7 @@ local setdirection = nuts.setdirection
local remove_node = nuts.remove
local insert_node_after = nuts.insert_after
local insert_node_before = nuts.insert_before
+local start_of_par = nuts.start_of_par
local nodepool = nuts.pool
local new_direction = nodepool.direction
@@ -336,7 +337,7 @@ local function get_baselevel(head,list,size,direction)
-- This is an adapted version:
if direction == lefttoright_code or direction == righttoleft_code then
return direction, true
- elseif getid(head) == localpar_code and getsubtype(head) == 0 then
+ elseif getid(head) == localpar_code and start_of_par(head) then
direction = getdirection(head)
if direction == lefttoright_code or direction == righttoleft_code then
return direction, true
@@ -774,7 +775,7 @@ local function apply_to_list(list,size,head,pardir)
enddir = false
end
elseif begindir then
- if id == localpar_code and getsubtype(current) == 0 then
+ if id == localpar_code and start_of_par(current) then
-- localpar should always be the 1st node
local d = new_direction(begindir)
-- setprop(d,"directions",true)
@@ -816,7 +817,7 @@ local function apply_to_list(list,size,head,pardir)
end
local function process(head,direction,only_one,where)
- -- This is an adapted version:
+ -- This is an adapted version:
local list, size = build_list(head)
local baselevel, dirfound = get_baselevel(head,list,size,direction)
if not dirfound and trace_details then
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-dub.lua b/Master/texmf-dist/tex/context/base/mkiv/typo-dub.lua
index f27e4047660..f1bd38fcc5d 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-dub.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-dub.lua
@@ -73,6 +73,7 @@ local setattrlist = nuts.setattrlist
local remove_node = nuts.remove
local insert_node_after = nuts.insert_after
local insert_node_before = nuts.insert_before
+local start_of_par = nuts.start_of_par
local nodepool = nuts.pool
local new_direction = nodepool.direction
@@ -397,7 +398,7 @@ end
local function get_baselevel(head,list,size,direction)
if direction == lefttoright_code or direction == righttoleft_code then
return direction, true
- elseif getid(head) == localpar_code and getsubtype(head) == 0 then
+ elseif getid(head) == localpar_code and start_of_par(head) then
direction = getdirection(head)
if direction == lefttoright_code or direction == righttoleft_code then
return direction, true
@@ -907,7 +908,7 @@ local function apply_to_list(list,size,head,pardir)
enddir = false
end
elseif begindir then
- if id == localpar_code and getsubtype(current) == 0 then
+ if id == localpar_code and start_of_par(current) then
-- localpar should always be the 1st node
local d = new_direction(begindir)
-- setprop(d,"directions",true)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-duc.lua b/Master/texmf-dist/tex/context/base/mkiv/typo-duc.lua
index f91fc4d647d..d4c56e3008d 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-duc.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-duc.lua
@@ -77,6 +77,7 @@ local properties = nodes.properties.data
local remove_node = nuts.remove
local insert_node_after = nuts.insert_after
local insert_node_before = nuts.insert_before
+local start_of_par = nuts.start_of_par
local nodepool = nuts.pool
local new_direction = nodepool.direction
@@ -412,7 +413,7 @@ end
local function get_baselevel(head,list,size,direction)
if direction == lefttoright_code or direction == righttoleft_code then
return direction, true
- elseif getid(head) == localpar_code and getsubtype(head) == 0 then
+ elseif getid(head) == localpar_code and start_of_par(head) then
direction = getdirection(head)
if direction == lefttoright_code or direction == righttoleft_code then
return direction, true
@@ -954,7 +955,7 @@ local function apply_to_list(list,size,head,pardir)
enddir = false
end
elseif begindir then
- if id == localpar_code and getsubtype(current) == 0 then
+ if id == localpar_code and start_of_par(current) then
-- localpar should always be the 1st node
head, current = insert_node_after(head,current,new_direction(begindir))
begindir = nil
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-fln.lua b/Master/texmf-dist/tex/context/base/mkiv/typo-fln.lua
index 0489807327c..6cca9248049 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-fln.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-fln.lua
@@ -47,12 +47,16 @@ local getdisc = nuts.getdisc
local setdisc = nuts.setdisc
local setlink = nuts.setlink
local setfont = nuts.setfont
+local setglyphdata = nuts.setglyphdata
+local getprop = nuts.getprop
+local setprop = nuts.setprop
local nodecodes = nodes.nodecodes
local glyph_code = nodecodes.glyph
local disc_code = nodecodes.disc
local kern_code = nodecodes.kern
local glue_code = nodecodes.glue
+local localpar_code = nodecodes.localpar
local spaceskip_code = nodes.gluecodes.spaceskip
@@ -67,6 +71,7 @@ local insert_node_after = nuts.insert_after
local remove_node = nuts.remove
local getdimensions = nuts.dimensions
local hpack_node_list = nuts.hpack
+local start_of_par = nuts.start_of_par
local nodepool = nuts.pool
local newpenalty = nodepool.penalty
@@ -81,26 +86,23 @@ local a_color = attributes.private('color')
local a_transparency = attributes.private('transparency')
local a_colormodel = attributes.private('colormodel')
-local texsetattribute = tex.setattribute
-local unsetvalue = attributes.unsetvalue
+local texget = tex.get
local variables = interfaces.variables
local v_default = variables.default
local v_line = variables.line
local v_word = variables.word
------ is_letter = characters.is_letter
------ categories = characters.categories
-
-local settings = nil
-
-function firstlines.set(specification)
- settings = specification or { }
+local function set(par,specification)
enableaction("processors","typesetters.firstlines.handler")
if trace_firstlines then
report_firstlines("enabling firstlines")
end
- texsetattribute(a_firstline,1)
+ setprop(par,a_firstline,specification)
+end
+
+function firstlines.set(specification)
+ nuts.setparproperty(set,specification)
end
implement {
@@ -120,25 +122,24 @@ implement {
}
actions[v_line] = function(head,setting)
- -- local attribute = fonts.specifiers.contextnumber(setting.feature) -- was experimental
local dynamic = setting.dynamic
local font = setting.font
local noflines = setting.n or 1
local ma = setting.ma or 0
local ca = setting.ca
local ta = setting.ta
- local hangafter = tex.hangafter
- local hangindent = tex.hangindent
- local parindent = tex.parindent
+ local hangafter = texget("hangafter")
+ local hangindent = texget("hangindent")
+ local parindent = texget("parindent")
local nofchars = 0
local n = 0
local temp = copy_node_list(head)
local linebreaks = { }
- local function set(head)
+ set = function(head)
for g in nextglyph, head do
if dynamic > 0 then
- setattr(g,0,dynamic)
+ setglyphdata(g,dynamic)
end
setfont(g,font)
end
@@ -163,7 +164,7 @@ actions[v_line] = function(head,setting)
local list = temp
local prev = temp
for i=1,noflines do
- local hsize = tex.hsize - tex.leftskip.width - tex.rightskip.width
+ local hsize = texget("hsize") - texget("leftskip",false) - texget("rightskip",false)
if i == 1 then
hsize = hsize - parindent
end
@@ -234,7 +235,7 @@ actions[v_line] = function(head,setting)
local function update(start)
if dynamic > 0 then
- setattr(start,0,dynamic)
+ setglyphdata(start,dynamic)
end
setfont(start,font)
if ca and ca > 0 then
@@ -348,7 +349,7 @@ actions[v_word] = function(head,setting)
setattr(start,a_transparency,ta)
end
if dynamic > 0 then
- setattr(start,0,dynamic)
+ setglyphdata(start,dynamic)
end
setfont(start,font)
elseif id == disc_code then
@@ -369,29 +370,18 @@ end
actions[v_default] = actions[v_line]
function firstlines.handler(head)
- local start = head
- local attr = nil
- while start do
- attr = getattr(start,a_firstline)
- if attr then
- break
- elseif getid(start) == glyph_code then
- break
- else
- start = getnext(start)
- end
- end
- if attr then
- -- here as we can process nested boxes first so we need to keep state
- disableaction("processors","typesetters.firstlines.handler")
- -- texsetattribute(attribute,unsetvalue)
- local alternative = settings.alternative or v_default
- local action = actions[alternative] or actions[v_default]
- if action then
- if trace_firstlines then
- report_firstlines("processing firstlines, alternative %a",alternative)
+ if getid(head) == localpar_code and start_of_par(head) then
+ local settings = getprop(head,a_firstline)
+ if settings then
+ disableaction("processors","typesetters.firstlines.handler")
+ local alternative = settings.alternative or v_default
+ local action = actions[alternative] or actions[v_default]
+ if action then
+ if trace_firstlines then
+ report_firstlines("processing firstlines, alternative %a",alternative)
+ end
+ return action(head,settings)
end
- return action(head,settings)
end
end
return head
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-fln.mkiv b/Master/texmf-dist/tex/context/base/mkiv/typo-fln.mkiv
index 533c197cd10..6cca39f91c2 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-fln.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-fln.mkiv
@@ -86,9 +86,9 @@
ta \attribute\transparencyattribute
n \numexpr\firstlineparameter\c!n\relax
font \fontid\font
- dynamic \attribute\zerocount
+ dynamic \font_dynamic_value
\relax
- \kern\zeropoint % we need a node
+% \kern\zeropoint % we need a node
% \hskip\zeropoint\s!plus\emwidth\relax % can be an option
\endgroup
\glet\typo_firstline_handle\relax}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-inj.mkiv b/Master/texmf-dist/tex/context/base/mkiv/typo-inj.mkiv
index 3b77379b352..633d430e437 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-inj.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-inj.mkiv
@@ -73,8 +73,8 @@
\setuxvalue{typo_injectors_check_#1}{\noexpand\clf_checkinjector{#1}}}
\unexpanded\def\dotestinjector#1% only for testing outside unprotect
- {\csname typo_injectors_check_#1\endcsname
- \csname typo_injectors_mark_#1\endcsname}
+ {\begincsname typo_injectors_check_#1\endcsname
+ \begincsname typo_injectors_mark_#1\endcsname}
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-itc.lua b/Master/texmf-dist/tex/context/base/mkiv/typo-itc.lua
index 2683eecc3e1..64701abcc6c 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-itc.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-itc.lua
@@ -383,6 +383,8 @@ local function texthandler(head)
postinserted = nil
postitalic = 0
updated = false
+ replacefont = nil
+ postfont = nil
pre, post, replace, pretail, posttail, replacetail = getdisc(current,true)
if replace then
local current = replacetail
@@ -390,29 +392,32 @@ local function texthandler(head)
local char, id = isglyph(current)
if char then
local font = id
- local data = italicsdata[font]
- if data then
- local attr = forcedvariant or getattr(current,a_italics)
- if attr and attr > 0 then
- local cd = data[char]
- if not cd then
- -- this really can happen
- replaceitalic = 0
- else
- replaceitalic = cd.italic
- if not replaceitalic then
- replaceitalic = setitalicinfont(font,char) -- calculated once
- -- replaceitalic = 0
- end
- if replaceitalic ~= 0 then
- lastfont = font
- lastattr = attr
- replacechar = char
- replacehead = replace
- updated = true
+ if font ~= lastfont then
+ local data = italicsdata[font]
+ if data then
+ local attr = forcedvariant or getattr(current,a_italics)
+ if attr and attr > 0 then
+ local cd = data[char]
+ if not cd then
+ -- this really can happen
+ replaceitalic = 0
+ else
+ replaceitalic = cd.italic
+ if not replaceitalic then
+ replaceitalic = setitalicinfont(font,char) -- calculated once
+ -- replaceitalic = 0
+ end
+ if replaceitalic ~= 0 then
+ lastfont = font
+ lastattr = attr
+ replacechar = char
+ replacehead = replace
+ updated = true
+ end
end
end
end
+ replacefont = font
end
break
else
@@ -426,29 +431,32 @@ local function texthandler(head)
local char, id = isglyph(current)
if char then
local font = id
- local data = italicsdata[font]
- if data then
- local attr = forcedvariant or getattr(current,a_italics)
- if attr and attr > 0 then
- local cd = data[char]
- if not cd then
- -- this really can happen
- -- postitalic = 0
- else
- postitalic = cd.italic
- if not postitalic then
- postitalic = setitalicinfont(font,char) -- calculated once
- -- postitalic = 0
- end
- if postitalic ~= 0 then
- lastfont = font
- lastattr = attr
- postchar = char
- posthead = post
- updated = true
+ if font ~= lastfont then
+ local data = italicsdata[font]
+ if data then
+ local attr = forcedvariant or getattr(current,a_italics)
+ if attr and attr > 0 then
+ local cd = data[char]
+ if not cd then
+ -- this really can happen
+ -- postitalic = 0
+ else
+ postitalic = cd.italic
+ if not postitalic then
+ postitalic = setitalicinfont(font,char) -- calculated once
+ -- postitalic = 0
+ end
+ if postitalic ~= 0 then
+ lastfont = font
+ lastattr = attr
+ postchar = char
+ posthead = post
+ updated = true
+ end
end
end
end
+ postfont = font
end
break
else
@@ -456,6 +464,9 @@ local function texthandler(head)
end
end
end
+ if replacefont or postfont then
+ lastfont = replacefont or postfont
+ end
if updated then
setdisc(current,pre,post,replace)
end
@@ -520,7 +531,7 @@ local function texthandler(head)
else
if replaceitalic ~= 0 then
if trace_italics then
- report_italics("inserting %p between %s italic %C and whatever",replaceritalic,"replace",replacechar)
+ report_italics("inserting %p between %s italic %C and whatever",replaceitalic,"replace",replacechar)
end
insert_node_after(replacehead,replace,correction_kern(replaceitalic,current))
previnserted = nil
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-krn.lua b/Master/texmf-dist/tex/context/base/mkiv/typo-krn.lua
index c26004a49df..f4f1215e1c4 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-krn.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-krn.lua
@@ -40,8 +40,9 @@ local getchar = nuts.getchar
local getdisc = nuts.getdisc
local getglue = nuts.getglue
local getkern = nuts.getkern
+local getglyphdata = nuts.getglyphdata
+
local isglyph = nuts.isglyph
-local setchar = nuts.setchar
local setfield = nuts.setfield
local getattr = nuts.getattr
@@ -51,12 +52,12 @@ local setlink = nuts.setlink
local setdisc = nuts.setdisc
local setglue = nuts.setglue
local setkern = nuts.setkern
+local setchar = nuts.setchar
+local setglue = nuts.setglue -- todo
local texsetattribute = tex.setattribute
local unsetvalue = attributes.unsetvalue
-local setglue = nuts.setglue -- todo
-
local new_kern = nodepool.kern
local new_glue = nodepool.glue
@@ -109,8 +110,8 @@ local kerns = typesetters.kerns or { }
typesetters.kerns = kerns
local report = logs.reporter("kerns")
-local trace_ligatures = false trackers.register("typesetters.kerns.ligatures", function(v) trace_ligatures = v end)
-local trace_ligatures_d = false trackers.register("typesetters.kerns.ligatures.detail",function(v) trace_ligatures_d = v end)
+local trace_ligatures = false trackers.register("typesetters.kerns.ligatures", function(v) trace_ligatures = v end)
+local trace_ligatures_d = false trackers.register("typesetters.kerns.ligatures.details", function(v) trace_ligatures_d = v end)
kerns.mapping = kerns.mapping or { }
kerns.factors = kerns.factors or { }
@@ -139,7 +140,7 @@ local gluefactor = 4 -- assumes quad = .5 enspace
function kerns.keepligature(n) -- might become default
local f = getfont(n)
- local a = getattr(n,0) or 0
+ local a = getglyphdata(n) or 0
if trace_ligatures then
local c = getchar(n)
local d = fontdescriptions[f][c].name
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-lin.lua b/Master/texmf-dist/tex/context/base/mkiv/typo-lin.lua
index 8393ea65b34..15e543c52e5 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-lin.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-lin.lua
@@ -129,6 +129,8 @@ local noflines = 0
-- This is the third version, a mix between immediate (prestice lines) and delayed
-- as we don't want anchors that are not used.
+-- I will make a better variant once lmtx is stable i.e. less clutter.
+
local function finalize(prop,key) -- delayed calculations
local line = prop.line
local hsize = prop.hsize
@@ -410,14 +412,13 @@ end
local latelua = nodepool.latelua
local setposition = jobpositions.setspec
-local t_anchor = { x = true, c = true } -- needs checking
local function setanchor(h_anchor)
return latelua {
action = setposition,
name = "md:h",
index = h_anchor,
- value = t_anchor, -- really shared ?
+ value = { x = true, c = true },
}
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-mar.lua b/Master/texmf-dist/tex/context/base/mkiv/typo-mar.lua
index ce8375eeaf7..7e69162a900 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-mar.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-mar.lua
@@ -59,8 +59,6 @@ local v_paragraph = variables.paragraph
local v_line = variables.line
local nuts = nodes.nuts
-local nodepool = nuts.pool
-
local tonode = nuts.tonode
local hpack_nodes = nuts.hpack
@@ -82,7 +80,6 @@ local setshift = nuts.setshift
local getwidth = nuts.getwidth
local setwidth = nuts.setwidth
local getheight = nuts.getheight
-local getprop = nuts.getprop
local setattrlist = nuts.setattrlist
@@ -103,9 +100,8 @@ local userdefined_code = whatsitcodes.userdefined
local nodepool = nuts.pool
-local new_usernode = nodepool.usernode
local new_hlist = nodepool.hlist
-
+local new_usernode = nodepool.usernode
local latelua = nodepool.latelua
local texgetdimen = tex.getdimen
@@ -459,7 +455,8 @@ local function sa(specification) -- maybe l/r keys ipv left/right keys
end
p.p = true
p.y = true
- setposition('md:v',tag,p)
+ -- maybe settobesaved first
+ setposition("md:v",tag,p)
cache[tag] = nil -- do this later, per page a cleanup
end
end
@@ -592,7 +589,7 @@ local function inject(parent,head,candidate)
elseif previous == current then
firstonstack = false
elseif ap and ac and ap.p == ac.p then
- local distance = ap.y - ac.y
+ local distance = (ap.y or 0) - (ac.y or 0)
if trace_margindata then
report_margindata("distance %p",distance)
end
@@ -683,7 +680,7 @@ local function inject(parent,head,candidate)
setwidth(box,0) -- not needed when wrapped
--
if isstacked then
- setlink(box,addtoanchor(v_anchor,nofinjected))
+ setlink(box,addtoanchor(v_anchors,nofinjected))
box = new_hlist(box)
-- set height / depth ?
end
@@ -736,7 +733,7 @@ local function flushinline(parent,head)
-- for now we also check for inline+yes/continue, maybe someday no such check
-- will happen; we can assume most inlines are one line heigh; also this
-- together feature can become optional
- registertogether(tonode(parent),room) -- !! tonode
+ registertogether(parent,room)
end
end
end
@@ -771,7 +768,7 @@ local function flushed(scope,parent) -- current is hlist
continue = continue or con
nofstored = nofstored - 1
if room then
- registertogether(tonode(parent),room) -- !! tonode
+ registertogether(parent,room)
end
else
break
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-ovl.lua b/Master/texmf-dist/tex/context/base/mkiv/typo-ovl.lua
index 09cf5e12955..25b1a0178f1 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-ovl.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-ovl.lua
@@ -12,7 +12,7 @@ if not modules then modules = { } end modules ['typo-ovl'] = {
-- we have hardly any private code. For convenience I hooked it into the existing
-- replacement module (as it used the same code anyway). I did some cleanup.
-local next = next
+local next, type = next, type
local context = context
@@ -34,6 +34,8 @@ local setattrlist = nuts.setattrlist
local getfield = nuts.getfield
local setfont = nuts.setfont
+local nextnode = nuts.traversers.node
+
local unsetvalue = attributes.unsetvalue
local prvattribute = attributes.private
@@ -90,9 +92,9 @@ end
attributes.tooverloads = tooverloads
function attributes.applyoverloads(specification,start,stop)
- local current = tonut(start)
+ local start = tonut(start)
local processor = specification.processor
- local overloads = specification.processor or getattr(current,a_overloads)
+ local overloads = specification.processor or getattr(start,a_overloads)
if overloads and overloads ~= unsetvalue then
overloads = t_overloads[overloads]
if not overloads then
@@ -107,14 +109,18 @@ function attributes.applyoverloads(specification,start,stop)
local newlist = nil
local newfont = overloads.font
- local function apply()
+ local function apply(current)
local a = getattrlist(current)
if a == oldlist then
setattrlist(current,newlist)
else
oldlist = getattrlist(current)
for k, v in next, overloads do
- setattr(current,k,v)
+ if type(v) == "number" then
+ setattr(current,k,v)
+ else
+ -- can be: ["font"] = number
+ end
end
newlist = current -- getattrlist(current)
end
@@ -123,12 +129,11 @@ function attributes.applyoverloads(specification,start,stop)
end
end
- while current do
- local id = getid(current)
+ for current, id in nextnode, start do
if id == glyph_code then
- apply()
+ apply(current)
elseif id == disc_code then
- apply()
+ apply(current)
if pre then
while pre do
if getid(pre) == glyph_code then
@@ -157,7 +162,6 @@ function attributes.applyoverloads(specification,start,stop)
if current == last then
break
end
- current = getnext(current)
end
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-pag.lua b/Master/texmf-dist/tex/context/base/mkiv/typo-pag.lua
index 05513e20c39..ea4b1574caf 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-pag.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-pag.lua
@@ -108,93 +108,94 @@ function parbuilders.registertogether(line,specification) -- might change
end
end
-local function keeptogether(start,a)
- if start then
- local specification = cache[a]
- if a then
- local current = getnext(start)
- local previous = start
- local total = getdepth(previous)
- local slack = specification.slack
- local threshold = specification.depth - slack
+local function keeptogether(start,a,specification)
+ local current = getnext(start)
+ local previous = start
+ local total = getdepth(previous)
+ local slack = specification.slack
+ local threshold = specification.depth - slack
+ if trace_keeptogether then
+ report_keeptogether("%s, index %s, total %p, threshold %p, slack %p","list",a,total,threshold,slack)
+ end
+ while current do
+ local id = getid(current)
+ if id == vlist_code or id == hlist_code then
+ local wd, ht, dp = getwhd(current)
+ total = total + ht + dp
+ if trace_keeptogether then
+ report_keeptogether("%s, index %s, total %p, threshold %p","list",a,total,threshold)
+ end
+ if total <= threshold then
+ if getid(previous) == penalty_code then
+ setpenalty(previous,10000)
+ else
+ insert_node_after(head,previous,new_penalty(10000))
+ end
+ else
+ break
+ end
+ elseif id == glue_code then
+ -- hm, breakpoint, maybe turn this into kern
+ total = total + getwidth(current)
if trace_keeptogether then
- report_keeptogether("%s, index %s, total %p, threshold %p, slack %p","list",a,total,threshold,slack)
+ report_keeptogether("%s, index %s, total %p, threshold %p","glue",a,total,threshold)
end
- while current do
- local id = getid(current)
- if id == vlist_code or id == hlist_code then
- local wd, ht, dp = getwhd(current)
- total = total + ht + dp
- if trace_keeptogether then
- report_keeptogether("%s, index %s, total %p, threshold %p","list",a,total,threshold)
- end
- if total <= threshold then
- if getid(previous) == penalty_code then
- setpenalty(previous,10000)
- else
- insert_node_after(head,previous,new_penalty(10000))
- end
- else
- break
- end
- elseif id == glue_code then
- -- hm, breakpoint, maybe turn this into kern
- total = total + getwidth(current)
- if trace_keeptogether then
- report_keeptogether("%s, index %s, total %p, threshold %p","glue",a,total,threshold)
- end
- if total <= threshold then
- if getid(previous) == penalty_code then
- setpenalty(previous,10000)
- else
- insert_node_after(head,previous,new_penalty(10000))
- end
- else
- break
- end
- elseif id == kern_code then
- total = total + getkern(current)
- if trace_keeptogether then
- report_keeptogether("%s, index %s, total %s, threshold %s","kern",a,total,threshold)
- end
- if total <= threshold then
- if getid(previous) == penalty_code then
- setpenalty(previous,10000)
- else
- insert_node_after(head,previous,new_penalty(10000))
- end
- else
- break
- end
- elseif id == penalty_code then
- if total <= threshold then
- if getid(previous) == penalty_code then
- setpenalty(previous,10000)
- end
- setpenalty(current,10000)
- else
- break
- end
+ if total <= threshold then
+ if getid(previous) == penalty_code then
+ setpenalty(previous,10000)
+ else
+ insert_node_after(head,previous,new_penalty(10000))
end
- previous = current
- current = getnext(current)
+ else
+ break
+ end
+ elseif id == kern_code then
+ total = total + getkern(current)
+ if trace_keeptogether then
+ report_keeptogether("%s, index %s, total %s, threshold %s","kern",a,total,threshold)
+ end
+ if total <= threshold then
+ if getid(previous) == penalty_code then
+ setpenalty(previous,10000)
+ else
+ insert_node_after(head,previous,new_penalty(10000))
+ end
+ else
+ break
+ end
+ elseif id == penalty_code then
+ if total <= threshold then
+ if getid(previous) == penalty_code then
+ setpenalty(previous,10000)
+ end
+ setpenalty(current,10000)
+ else
+ break
end
end
+ previous = current
+ current = getnext(current)
end
end
-- also look at first non glue/kern node e.g for a dropped caps
function parbuilders.keeptogether(head)
- local done = false
+ local done = false -- can go
local current = head
while current do
if getid(current) == hlist_code then
local a = takeattr(current,a_keeptogether)
if a and a > 0 then
- keeptogether(current,a)
- cache[a] = nil
- done = true
+ local specification = cache[a]
+ if specification then
+ keeptogether(current,a,specification)
+ -- this is tricky ... we need a better resetter, maybe some
+ -- injected latelua or a gc method on a property (interesting
+ -- experiment)
+ cache[a] = nil
+ done = true
+ end
end
end
current = getnext(current)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-par.mkiv b/Master/texmf-dist/tex/context/base/mkiv/typo-par.mkiv
index 066dc6a6973..fae07b235c9 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-par.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-par.mkiv
@@ -23,7 +23,8 @@
\unprotect
-\registerctxluafile{node-ltp}{optimize}
+% \registerctxluafile{node-ltp}{optimize}
+\registerctxluafile{node-ltp}{}
\registerctxluafile{trac-par}{}
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-scr.mkiv b/Master/texmf-dist/tex/context/base/mkiv/typo-scr.mkiv
index 0dfd111ae33..f2b4b0d041d 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-scr.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-scr.mkiv
@@ -138,18 +138,21 @@
{\dontleavehmode
\runninghbox\bgroup
\edef\currentlowhigh{#1}%
- \dosingleempty} % #2
+ \dosingleempty} % #2
\unexpanded\def\typo_scripts_lowhigh_indeed[#1]#2#3% todo: align .. [#1] is compatible hack
{\dostarttagged\t!subsup\currentlowhigh
+ \scratchdimen\lowhighparameter\c!distance\relax
\setbox\plusfour\hpack{\typo_scripts_lowhigh_low_high\lower\c!down\t!sub{#2}}%
\setbox\plussix \hpack{\typo_scripts_lowhigh_low_high\raise\c!up \t!sup{#3}}%
- \doif{#1}{\v!left}
- {\ifdim\wd\plusfour<\wd\plussix
- \setbox\plusfour\hpack to \wd\plussix {\hss\box\plusfour}%
- \else
- \setbox\plussix \hpack to \wd\plusfour{\hss\box\plussix }%
- \fi}%
+ \edef\p_align{#1}%
+ \ifx\p_align\v!left
+ \ifdim\wd\plusfour<\wd\plussix
+ \setbox\plusfour\hpack to \wd\plussix {\hss\box\plusfour}%
+ \else
+ \setbox\plussix \hpack to \wd\plusfour{\hss\box\plussix }%
+ \fi
+ \fi
\ifdim\wd\plusfour<\wd\plussix
\wd\plusfour\zeropoint
\box\plusfour
@@ -163,9 +166,7 @@
\egroup}
\def\typo_scripts_lowhigh_low_high#1#2#3#4%
- {\dontleavehmode
- \begingroup
- \kern\lowhighparameter\c!distance\relax
+ {\kern\scratchdimen
\setbox\scratchbox\hpack\bgroup
#1\lowhighparameter#2\hbox\bgroup
\ifx\fontsize\empty
@@ -184,8 +185,7 @@
\egroup
\ht\scratchbox\strutht
\dp\scratchbox\strutdp
- \box\scratchbox
- \endgroup}
+ \box\scratchbox}
\unexpanded\def\typo_scripts_highlow_indeed[#1]#2#3%
{\typo_scripts_lowhigh_indeed[#1]{#3}{#2}}
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-sus.lua b/Master/texmf-dist/tex/context/base/mkiv/typo-sus.lua
index 6c02b929167..bb5b03912ce 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-sus.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-sus.lua
@@ -72,6 +72,7 @@ local a_characters = attributes.private("characters")
local a_suspecting = attributes.private('suspecting')
local a_suspect = attributes.private('suspect')
local texsetattribute = tex.setattribute
+local unsetvalue = attributes.unsetvalue
local enabled = false
local enableaction = nodes.tasks.enableaction
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-tal.lua b/Master/texmf-dist/tex/context/base/mkiv/typo-tal.lua
index 8cf29832971..ff10fb12103 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-tal.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-tal.lua
@@ -205,6 +205,24 @@ function characteralign.handler(head,where)
local method = dataset.method
-- we can think of constraints
if method == v_number then
+
+ local function bothdigit(current) -- this could become a helper
+ local prev, next = getboth(current)
+ if next and prev and getid(next) == glyph_code and getid(prev) == glyph_code then
+ local pchar = getchar(prev)
+ local nchar = getchar(next)
+ local pdata = fontcharacters[getfont(prev)][pchar]
+ local ndata = fontcharacters[getfont(next)][nchar]
+ local punicode = pdata and pdata.unicode or pchar -- we ignore tables
+ local nunicode = ndata and ndata.unicode or nchar -- we ignore tables
+ if punicode and nunicode and categories[punicode] == "nd" and categories[nunicode] == "nd" then
+ return true
+ else
+ return false
+ end
+ end
+ end
+
while current do
local char, id = isglyph(current)
if char then
@@ -266,10 +284,9 @@ function characteralign.handler(head,where)
elseif (b_start or a_start) and id == glue_code then
-- maybe only in number mode
-- somewhat inefficient
- local prev, next = getboth(current)
- if next and prev and getid(next) == glyph_code and getid(prev) == glyph_code then -- too much checking
+ if bothdigit(current) then
local width = fontcharacters[getfont(b_start or a_start)][separator or period].width
- setglue(current,width)
+ setglue(current,width,0,0)
setattr(current,a_character,punctuationspace)
if a_start then
a_stop = current
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-tal.mkiv b/Master/texmf-dist/tex/context/base/mkiv/typo-tal.mkiv
index 7170578d17d..33e071e7537 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-tal.mkiv
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-tal.mkiv
@@ -269,4 +269,38 @@
\typo_charalign_adapt_font_indeed
\fi}
+%D Another example:
+%D
+%D \starttyping
+%D \setupTABLE[c][2][alignmentcharacter={number->,},aligncharacter=yes,align={flushleft}]
+%D \bTABLE
+%D \bTR \bTD 1 \eTD \bTD 125 cm \eTD \eTR
+%D \bTR \bTD 2 \eTD \bTD 1 125,80 cm \eTD \eTR
+%D \bTR \bTD 6 \eTD \bTD 1 125,80 $\pi^2$ \eTD \eTR
+%D \bTR \bTD 7 \eTD \bTD 129,3 \unit{square centimeter} \eTD \eTR
+%D \eTABLE
+%D
+%D \setupTABLE[c][2][alignmentcharacter={number->,},aligncharacter=yes,align={flushleft}]
+%D \bTABLE
+%D \bTR \bTD 1 \eTD \bTD 125 cm \eTD \eTR
+%D \bTR \bTD 2 \eTD \bTD 1 125,80 cm \eTD \eTR
+%D \bTR \bTD 6 \eTD \bTD 1 125,80 $\pi^2$ \eTD \eTR
+%D \bTR \bTD 7 \eTD \bTD 129,3 \unit{square centimeter} \eTD \eTR
+%D \eTABLE
+%D
+%D \setupTABLE[c][2][alignmentcharacter={number->,},aligncharacter=yes,align={middle}]
+%D \bTABLE
+%D \bTR \bTD 1 \eTD \bTD 125 \eTD \eTR
+%D \bTR \bTD 6 \eTD \bTD 1 125,80 \eTD \eTR
+%D \bTR \bTD 7 \eTD \bTD 129,3 \eTD \eTR
+%D \eTABLE
+%D
+%D \setupTABLE[c][2][alignmentcharacter={text->,},aligncharacter=yes,align={middle}]
+%D \bTABLE
+%D \bTR \bTD 1 \eTD \bTD 125 \eTD \eTR
+%D \bTR \bTD 6 \eTD \bTD 1 125,80 \eTD \eTR
+%D \bTR \bTD 7 \eTD \bTD 129,3 \eTD \eTR
+%D \eTABLE
+%D \stoptyping
+
\protect \endinput
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-wrp.lua b/Master/texmf-dist/tex/context/base/mkiv/typo-wrp.lua
index 9fb5441526c..f2ca43b56ef 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/typo-wrp.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/typo-wrp.lua
@@ -32,7 +32,7 @@ local getprev = nuts.getprev
local getid = nuts.getid
local getsubtype = nuts.getsubtype
local getpenalty = nuts.getpenalty
-local remove = nuts.remove
+local remove_node = nuts.remove
local enableaction = nodes.tasks.enableaction
@@ -66,7 +66,7 @@ local function remove_dangling_crlf(head,tail)
if trace_wrappers then
report("removing a probably unwanted end-of-par break in line %s (guess)",tex.inputlineno)
end
- remove(head,tail,true)
+ remove_node(head,tail,true)
return head, tail
end
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/util-deb.lua b/Master/texmf-dist/tex/context/base/mkiv/util-deb.lua
index 6932e8804d3..bd94b6d01ed 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/util-deb.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/util-deb.lua
@@ -30,7 +30,15 @@ local names = { }
local initialize = false
-if not (FFISUPPORTED and ffi) then
+if lua.getpreciseticks then
+
+ initialize = function()
+ ticks = lua.getpreciseticks
+ seconds = lua.getpreciseseconds
+ initialize = false
+ end
+
+elseif not (FFISUPPORTED and ffi) then
-- we have no precise timer
diff --git a/Master/texmf-dist/tex/context/base/mkiv/util-dim.lua b/Master/texmf-dist/tex/context/base/mkiv/util-dim.lua
index fd9351a28fb..76b5fd20bb3 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/util-dim.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/util-dim.lua
@@ -397,18 +397,22 @@ function dimen(a)
end
function string.todimen(str) -- maybe use tex.sp when available
- if type(str) == "number" then
+ local t = type(str)
+ if t == "number" then
return str
else
local k = known[str]
if not k then
- local value, unit = lpegmatch(dimenpair,str)
- if value and unit then
- k = value/unit -- to be considered: round
+ if t == "string" then
+ local value, unit = lpegmatch(dimenpair,str)
+ if value and unit then
+ k = value/unit -- to be considered: round
+ else
+ k = 0
+ end
else
k = 0
end
- -- print(str,value,unit)
known[str] = k
end
return k
diff --git a/Master/texmf-dist/tex/context/base/mkiv/util-jsn.lua b/Master/texmf-dist/tex/context/base/mkiv/util-jsn.lua
index acbf160904d..8da35189793 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/util-jsn.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/util-jsn.lua
@@ -20,155 +20,412 @@ if not modules then modules = { } end modules ['util-jsn'] = {
local P, V, R, S, C, Cc, Cs, Ct, Cf, Cg = lpeg.P, lpeg.V, lpeg.R, lpeg.S, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cf, lpeg.Cg
local lpegmatch = lpeg.match
local format, gsub = string.format, string.gsub
+local formatters = string.formatters
local utfchar = utf.char
-local concat = table.concat
+local concat, sortedkeys = table.concat, table.sortedkeys
local tonumber, tostring, rawset, type, next = tonumber, tostring, rawset, type, next
local json = utilities.json or { }
utilities.json = json
--- \\ \/ \b \f \n \r \t \uHHHH
-
-local lbrace = P("{")
-local rbrace = P("}")
-local lparent = P("[")
-local rparent = P("]")
-local comma = P(",")
-local colon = P(":")
-local dquote = P('"')
-
-local whitespace = lpeg.patterns.whitespace
-local optionalws = whitespace^0
-
-local escapes = {
- ["b"] = "\010",
- ["f"] = "\014",
- ["n"] = "\n",
- ["r"] = "\r",
- ["t"] = "\t",
-}
+do
--- todo: also handle larger utf16
+ -- \\ \/ \b \f \n \r \t \uHHHH
-local escape_un = P("\\u")/"" * (C(R("09","AF","af")^-4) / function(s)
- return utfchar(tonumber(s,16))
-end)
+ local lbrace = P("{")
+ local rbrace = P("}")
+ local lparent = P("[")
+ local rparent = P("]")
+ local comma = P(",")
+ local colon = P(":")
+ local dquote = P('"')
-local escape_bs = P([[\]]) / "" * (P(1) / escapes) -- if not found then P(1) is returned i.e. the to be escaped char
+ local whitespace = lpeg.patterns.whitespace
+ local optionalws = whitespace^0
-local jstring = dquote * Cs((escape_un + escape_bs + (1-dquote))^0) * dquote
-local jtrue = P("true") * Cc(true)
-local jfalse = P("false") * Cc(false)
-local jnull = P("null") * Cc(nil)
-local jnumber = (1-whitespace-rparent-rbrace-comma)^1 / tonumber
+ local escapes = {
+ ["b"] = "\010",
+ ["f"] = "\014",
+ ["n"] = "\n",
+ ["r"] = "\r",
+ ["t"] = "\t",
+ }
-local key = jstring
+ -- todo: also handle larger utf16
-local jsonconverter = { "value",
- hash = lbrace * Cf(Ct("") * (V("pair") * (comma * V("pair"))^0 + optionalws),rawset) * rbrace,
- pair = Cg(optionalws * key * optionalws * colon * V("value")),
- array = Ct(lparent * (V("value") * (comma * V("value"))^0 + optionalws) * rparent),
--- value = optionalws * (jstring + V("hash") + V("array") + jtrue + jfalse + jnull + jnumber + #rparent) * optionalws,
- value = optionalws * (jstring + V("hash") + V("array") + jtrue + jfalse + jnull + jnumber) * optionalws,
-}
+ local escape_un = P("\\u")/"" * (C(R("09","AF","af")^-4) / function(s)
+ return utfchar(tonumber(s,16))
+ end)
+
+ local escape_bs = P([[\]]) / "" * (P(1) / escapes) -- if not found then P(1) is returned i.e. the to be escaped char
+
+ local jstring = dquote * Cs((escape_un + escape_bs + (1-dquote))^0) * dquote
+ local jtrue = P("true") * Cc(true)
+ local jfalse = P("false") * Cc(false)
+ local jnull = P("null") * Cc(nil)
+ local jnumber = (1-whitespace-rparent-rbrace-comma)^1 / tonumber
+
+ local key = jstring
+
+ local jsonconverter = { "value",
+ hash = lbrace * Cf(Ct("") * (V("pair") * (comma * V("pair"))^0 + optionalws),rawset) * rbrace,
+ pair = Cg(optionalws * key * optionalws * colon * V("value")),
+ array = Ct(lparent * (V("value") * (comma * V("value"))^0 + optionalws) * rparent),
+ -- value = optionalws * (jstring + V("hash") + V("array") + jtrue + jfalse + jnull + jnumber + #rparent) * optionalws,
+ value = optionalws * (jstring + V("hash") + V("array") + jtrue + jfalse + jnull + jnumber) * optionalws,
+ }
+
+ -- local jsonconverter = { "value",
+ -- hash = lbrace * Cf(Ct("") * (V("pair") * (comma * V("pair"))^0 + optionalws),rawset) * rbrace,
+ -- pair = Cg(optionalws * V("string") * optionalws * colon * V("value")),
+ -- array = Ct(lparent * (V("value") * (comma * V("value"))^0 + optionalws) * rparent),
+ -- string = jstring,
+ -- value = optionalws * (V("string") + V("hash") + V("array") + jtrue + jfalse + jnull + jnumber) * optionalws,
+ -- }
+
+ -- lpeg.print(jsonconverter) -- size 181
--- local jsonconverter = { "value",
--- hash = lbrace * Cf(Ct("") * (V("pair") * (comma * V("pair"))^0 + optionalws),rawset) * rbrace,
--- pair = Cg(optionalws * V("string") * optionalws * colon * V("value")),
--- array = Ct(lparent * (V("value") * (comma * V("value"))^0 + optionalws) * rparent),
--- string = jstring,
--- value = optionalws * (V("string") + V("hash") + V("array") + jtrue + jfalse + jnull + jnumber) * optionalws,
--- }
+ function json.tolua(str)
+ return lpegmatch(jsonconverter,str)
+ end
--- lpeg.print(jsonconverter) -- size 181
+ function json.load(filename)
+ local data = io.loaddata(filename)
+ if data then
+ return lpegmatch(jsonconverter,data)
+ end
+ end
-function json.tolua(str)
- return lpegmatch(jsonconverter,str)
end
-local escaper
+do
-local function tojson(value,t,n) -- we could optimize #t
- local kind = type(value)
- if kind == "table" then
- local done = false
- local size = #value
- if size == 0 then
- for k, v in next, value do
- if done then
- n = n + 1 ; t[n] = ","
+ -- It's pretty bad that JSON doesn't allow the trailing comma ... it's a
+ -- typical example of a spec that then forces all generators to check for
+ -- this. It's a way to make sure programmers keep jobs.
+
+ local escaper
+
+ local f_start_hash = formatters[ '%w{' ]
+ local f_start_array = formatters[ '%w[' ]
+ local f_start_hash_new = formatters[ "\n" .. '%w{' ]
+ local f_start_array_new = formatters[ "\n" .. '%w[' ]
+ local f_start_hash_key = formatters[ "\n" .. '%w"%s" : {' ]
+ local f_start_array_key = formatters[ "\n" .. '%w"%s" : [' ]
+
+ local f_stop_hash = formatters[ "\n" .. '%w}' ]
+ local f_stop_array = formatters[ "\n" .. '%w]' ]
+
+ local f_key_val_seq = formatters[ "\n" .. '%w"%s" : %s' ]
+ local f_key_val_str = formatters[ "\n" .. '%w"%s" : "%s"' ]
+ local f_key_val_num = f_key_val_seq
+ local f_key_val_yes = formatters[ "\n" .. '%w"%s" : true' ]
+ local f_key_val_nop = formatters[ "\n" .. '%w"%s" : false' ]
+ local f_key_val_null = formatters[ "\n" .. '%w"%s" : null' ]
+
+ local f_val_num = formatters[ "\n" .. '%w%s' ]
+ local f_val_str = formatters[ "\n" .. '%w"%s"' ]
+ local f_val_yes = formatters[ "\n" .. '%wtrue' ]
+ local f_val_nop = formatters[ "\n" .. '%wfalse' ]
+ local f_val_null = formatters[ "\n" .. '%wnull' ]
+ local f_val_empty = formatters[ "\n" .. '%w{ }' ]
+ local f_val_seq = f_val_num
+
+ -- no empty tables because unknown if table or hash
+
+ local t = { }
+ local n = 0
+
+ local function is_simple_table(tt) -- also used in util-tab so maybe public
+ local l = #tt
+ if l > 0 then
+ for i=1,l do
+ if type(tt[i]) == "table" then
+ return false
+ end
+ end
+ local nn = n
+ n = n + 1 t[n] = "[ "
+ for i=1,l do
+ if i > 1 then
+ n = n + 1 t[n] = ", "
+ end
+ local v = tt[i]
+ local tv = type(v)
+ if tv == "number" then
+ n = n + 1 t[n] = v
+ elseif tv == "string" then
+ n = n + 1 t[n] = '"'
+ n = n + 1 t[n] = lpegmatch(escaper,v) or v
+ n = n + 1 t[n] = '"'
+ elseif tv == "boolean" then
+ n = n + 1 t[n] = v and "true" or "false"
+ elseif v then
+ n = n + 1 t[n] = tostring(v)
+ else
+ n = n + 1 t[n] = "null"
+ end
+ end
+ n = n + 1 t[n] = " ]"
+ local s = concat(t,"",nn+1,n)
+ n = nn
+ return s
+ end
+ return false
+ end
+
+ local function tojsonpp(root,name,depth,level,size)
+ if root then
+ local indexed = size > 0
+ n = n + 1
+ if level == 0 then
+ if indexed then
+ t[n] = f_start_array(depth)
+ else
+ t[n] = f_start_hash(depth)
+ end
+ elseif name then
+ if tn == "string" then
+ name = lpegmatch(escaper,name) or name
+ elseif tn ~= "number" then
+ name = tostring(name)
+ end
+ if indexed then
+ t[n] = f_start_array_key(depth,name)
+ else
+ t[n] = f_start_hash_key(depth,name)
+ end
+ else
+ if indexed then
+ t[n] = f_start_array_new(depth)
else
- n = n + 1 ; t[n] = "{"
- done = true
+ t[n] = f_start_hash_new(depth)
end
- n = n + 1 ; t[n] = format("%q:",k)
- t, n = tojson(v,t,n)
end
- if done then
- n = n + 1 ; t[n] = "}"
+ depth = depth + 1
+ if indexed then -- indexed
+ for i=1,size do
+ if i > 1 then
+ n = n + 1 t[n] = ","
+ end
+ local v = root[i]
+ local tv = type(v)
+ if tv == "number" then
+ n = n + 1 t[n] = f_val_num(depth,v)
+ elseif tv == "string" then
+ v = lpegmatch(escaper,v) or v
+ n = n + 1 t[n] = f_val_str(depth,v)
+ elseif tv == "table" then
+ if next(v) then
+ local st = is_simple_table(v)
+ if st then
+ n = n + 1 t[n] = f_val_seq(depth,st)
+ else
+ tojsonpp(v,nil,depth,level+1,#v)
+ end
+ else
+ n = n + 1
+ t[n] = f_val_empty(depth)
+ end
+ elseif tv == "boolean" then
+ n = n + 1
+ if v then
+ t[n] = f_val_yes(depth,v)
+ else
+ t[n] = f_val_nop(depth,v)
+ end
+ else
+ n = n + 1
+ t[n] = f_val_null(depth)
+ end
+ end
+ elseif next(root) then
+ local sk = sortedkeys(root)
+ for i=1,#sk do
+ if i > 1 then
+ n = n + 1 t[n] = ","
+ end
+ local k = sk[i]
+ local v = root[k]
+ local tv = type(v)
+ local tk = type(k)
+ if tv == "number" then
+ if tk == "number" then
+ n = n + 1 t[n] = f_key_val_num(depth,k,v)
+ elseif tk == "string" then
+ k = lpegmatch(escaper,k) or k
+ n = n + 1 t[n] = f_key_val_num(depth,k,v)
+ end
+ elseif tv == "string" then
+ if tk == "number" then
+ v = lpegmatch(escaper,v) or v
+ n = n + 1 t[n] = f_key_val_str(depth,k,v)
+ elseif tk == "string" then
+ k = lpegmatch(escaper,k) or k
+ v = lpegmatch(escaper,v) or v
+ n = n + 1 t[n] = f_key_val_str(depth,k,v)
+ end
+ elseif tv == "table" then
+ local l = #v
+ if l > 0 then
+ local st = is_simple_table(v)
+ if not st then
+ tojsonpp(v,k,depth,level+1,l)
+ elseif tk == "number" then
+ n = n + 1 t[n] = f_key_val_seq(depth,k,st)
+ elseif tk == "string" then
+ k = lpegmatch(escaper,k) or k
+ n = n + 1 t[n] = f_key_val_seq(depth,k,st)
+ end
+ elseif next(v) then
+ tojsonpp(v,k,depth,level+1,0)
+ end
+ elseif tv == "boolean" then
+ if tk == "number" then
+ n = n + 1
+ if v then
+ t[n] = f_key_val_yes(depth,k)
+ else
+ t[n] = f_key_val_nop(depth,k)
+ end
+ elseif tk == "string" then
+ k = lpegmatch(escaper,k) or k
+ n = n + 1
+ if v then
+ t[n] = f_key_val_yes(depth,k)
+ else
+ t[n] = f_key_val_nop(depth,k)
+ end
+ end
+ else
+ if tk == "number" then
+ n = n + 1
+ t[n] = f_key_val_null(depth,k)
+ elseif tk == "string" then
+ k = lpegmatch(escaper,k) or k
+ n = n + 1
+ t[n] = f_key_val_null(depth,k)
+ end
+ end
+ end
+ end
+ n = n + 1
+ if indexed then
+ t[n] = f_stop_array(depth-1)
else
- n = n + 1 ; t[n] = "{}"
+ t[n] = f_stop_hash(depth-1)
end
- elseif size == 1 then
- -- we can optimize for non tables
- n = n + 1 ; t[n] = "["
- t, n = tojson(value[1],t,n)
- n = n + 1 ; t[n] = "]"
- else
- for i=1,size do
+ end
+ end
+
+ local function tojson(value,n)
+ local kind = type(value)
+ if kind == "table" then
+ local done = false
+ local size = #value
+ if size == 0 then
+ for k, v in next, value do
+ if done then
+ -- n = n + 1 ; t[n] = ","
+ n = n + 1 ; t[n] = ',"'
+ else
+ -- n = n + 1 ; t[n] = "{"
+ n = n + 1 ; t[n] = '{"'
+ done = true
+ end
+ n = n + 1 ; t[n] = lpegmatch(escaper,k) or k
+ n = n + 1 ; t[n] = '":'
+ t, n = tojson(v,n)
+ end
if done then
- n = n + 1 ; t[n] = ","
+ n = n + 1 ; t[n] = "}"
else
- n = n + 1 ; t[n] = "["
- done = true
+ n = n + 1 ; t[n] = "{}"
end
- t, n = tojson(value[i],t,n)
+ elseif size == 1 then
+ -- we can optimize for non tables
+ n = n + 1 ; t[n] = "["
+ t, n = tojson(value[1],n)
+ n = n + 1 ; t[n] = "]"
+ else
+ for i=1,size do
+ if done then
+ n = n + 1 ; t[n] = ","
+ else
+ n = n + 1 ; t[n] = "["
+ done = true
+ end
+ t, n = tojson(value[i],n)
+ end
+ n = n + 1 ; t[n] = "]"
end
- n = n + 1 ; t[n] = "]"
+ elseif kind == "string" then
+ n = n + 1 ; t[n] = '"'
+ n = n + 1 ; t[n] = lpegmatch(escaper,value) or value
+ n = n + 1 ; t[n] = '"'
+ elseif kind == "number" then
+ n = n + 1 ; t[n] = value
+ elseif kind == "boolean" then
+ n = n + 1 ; t[n] = tostring(value)
+ else
+ n = n + 1 ; t[n] = "null"
end
- elseif kind == "string" then
- n = n + 1 ; t[n] = '"'
- n = n + 1 ; t[n] = lpegmatch(escaper,value) or value
- n = n + 1 ; t[n] = '"'
- elseif kind == "number" then
- n = n + 1 ; t[n] = value
- elseif kind == "boolean" then
- n = n + 1 ; t[n] = tostring(value)
+ return t, n
end
- return t, n
-end
-function json.tostring(value)
- -- todo optimize for non table
- local kind = type(value)
- if kind == "table" then
- if not escaper then
- local escapes = {
- ["\\"] = "\\u005C",
- ["\""] = "\\u0022",
- }
- for i=0,0x20 do
- escapes[utfchar(i)] = format("\\u%04X",i)
- end
- escaper = Cs( (
- (R('\0\x20') + S('\"\\')) / escapes
- + P(1)
- )^1 )
+ -- escaping keys can become an option
+
+ local function jsontostring(value,pretty)
+ -- todo optimize for non table
+ local kind = type(value)
+ if kind == "table" then
+ if not escaper then
+ local escapes = {
+ ["\\"] = "\\u005C",
+ ["\""] = "\\u0022",
+ }
+ for i=0,0x1F do
+ escapes[utfchar(i)] = format("\\u%04X",i)
+ end
+ escaper = Cs( (
+ (R('\0\x20') + S('\"\\')) / escapes
+ + P(1)
+ )^1 )
+ end
+ -- local to the closure (saves wrapping and local functions)
+ t = { }
+ n = 0
+ if pretty then
+ tojsonpp(value,name,0,0,#value)
+ value = concat(t,"",1,n)
+ else
+ t, n = tojson(value,0)
+ value = concat(t,"",1,n)
+ end
+ t = nil
+ n = 0
+ return value
+ elseif kind == "string" or kind == "number" then
+ return lpegmatch(escaper,value) or value
+ else
+ return tostring(value)
end
- return concat((tojson(value,{},0)))
- elseif kind == "string" or kind == "number" then
- return lpegmatch(escaper,value) or value
- else
- return tostring(value)
end
+
+ json.tostring = jsontostring
+
+ function json.tojson(value)
+ return jsontostring(value,true)
+ end
+
end
--- local tmp = [[ { "t" : "foobar", "a" : true, "b" : [ 123 , 456E-10, { "a" : true, "b" : [ 123 , 456 ] } ] } ]]
+-- local tmp = [[ { "t\nt t" : "foo bar", "a" : true, "b" : [ 123 , 456E-10, { "a" : true, "b" : [ 123 , 456 ] } ] } ]]
-- tmp = json.tolua(tmp)
-- inspect(tmp)
--- tmp = json.tostring(tmp)
+-- tmp = json.tostring(tmp,true)
-- inspect(tmp)
-- tmp = json.tolua(tmp)
-- inspect(tmp)
@@ -176,13 +433,6 @@ end
-- inspect(tmp)
-- inspect(json.tostring(true))
-function json.load(filename)
- local data = io.loaddata(filename)
- if data then
- return lpegmatch(jsonconverter,data)
- end
-end
-
-- local s = [[\foo"bar"]]
-- local j = json.tostring { s = s }
-- local l = json.tolua(j)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/util-lib.lua b/Master/texmf-dist/tex/context/base/mkiv/util-lib.lua
index fb65a566e24..a49507c6060 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/util-lib.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/util-lib.lua
@@ -120,7 +120,8 @@ local function locate(required,version,trace,report,action)
-- initialize a few variables
local required_name = required_base .. "." .. os.libsuffix
local version = type(version) == "string" and version ~= "" and version or false
- local engine = "luatex" -- environment.ownmain or false
+-- local engine = "luatex" -- environment.ownmain or false
+ local engine = environment.ownmain or false
--
if trace and not done then
local list = expandpaths("lib") -- fresh, no reuse
@@ -240,6 +241,8 @@ local function locate(required,version,trace,report,action)
return library or nil
end
+resolvers.locatelib = locate -- for now
+
do
local report_swiglib = logs.reporter("swiglib")
@@ -458,3 +461,53 @@ ffilib("libmysql","5.6.14")
-- Watch out, the last one is less explicit and lacks the swiglib prefix.
]]--
+
+do
+
+ local isfile = lfs.isfile
+ local report = logs.reporter("resolvers","lib")
+ local trace = false
+
+ trackers.register("resolvers.lib", function(v) trace = v end)
+
+ local function action(filename)
+ return isfile(filename) and filename or false
+ end
+
+ function resolvers.findlib(required) -- todo: cache
+ local list = directives.value("system.librarynames" )
+ local only = nameonly(required)
+ if type(list) == "table" then
+ list = list[only]
+ if type(list) == "table" then
+ if trace then
+ report("using lookup list for library %a: % | t",only,list)
+ end
+ else
+ list = { only }
+ end
+ else
+ list = { only }
+ end
+ for i=1,#list do
+ local name = list[i]
+ local found = locate(name,false,trace,report,action)
+ if found then
+ return found
+ end
+ end
+ local getpaths = resolvers.expandedpathlistfromvariable
+ if getpaths then
+ local list = getpaths("PATH")
+ local base = addsuffix(only,os.libsuffix)
+ for i=1,#list do
+ local full = joinfile(list[i],base)
+ local found = locate(full,false,trace,report,action)
+ if found then
+ return found
+ end
+ end
+ end
+ end
+
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/util-lua.lua b/Master/texmf-dist/tex/context/base/mkiv/util-lua.lua
index 1199301f42f..fb4088e7b66 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/util-lua.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/util-lua.lua
@@ -28,16 +28,24 @@ luautilities.nofstrippedbytes = 0
local strippedchunks = { } -- allocate()
luautilities.strippedchunks = strippedchunks
+if not LUATEXENGINE then
+ --- probably mtxrun ...
+ LUATEXENGINE = status.luatex_engine and string.lower(status.luatex_engine)
+ JITSUPPORTED = LUATEXENGINE == "luajittex" or jit
+ CONTEXTLMTXMODE = CONTEXTLMTXMODE or (LUATEXENGINE == "luametatex" and 1) or 0
+end
+
luautilities.suffixes = {
tma = "tma",
- tmc = jit and "tmb" or "tmc",
+ tmc = (CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 and "tmd") or (jit and "tmb") or "tmc",
lua = "lua",
- luc = jit and "lub" or "luc",
+ luc = (CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 and "lud") or (jit and "lub") or "luc",
lui = "lui",
luv = "luv",
luj = "luj",
tua = "tua",
- tuc = "tuc",
+ -- tuc = "tuc",
+ tuc = (CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 and "tud") or (jit and "tub") or "tuc",
}
-- environment.loadpreprocessedfile can be set to a preprocessor
diff --git a/Master/texmf-dist/tex/context/base/mkiv/util-pck.lua b/Master/texmf-dist/tex/context/base/mkiv/util-pck.lua
index 83b85cd9486..6af53f9eba2 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/util-pck.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/util-pck.lua
@@ -10,6 +10,7 @@ if not modules then modules = { } end modules ['util-pck'] = {
local next, tostring, type = next, tostring, type
local sort, concat = table.sort, table.concat
+local format = string.format
local sortedhashkeys, sortedkeys, tohash = table.sortedhashkeys, table.sortedkeys, table.tohash
utilities = utilities or { }
@@ -17,14 +18,17 @@ utilities.packers = utilities.packers or { }
local packers = utilities.packers
packers.version = 1.01
+local fmt_kv = JITSUPPORTED and "%s=%s" or "%s=%q"
+local fmt_kt = JITSUPPORTED and "%s={%s}" or "%s={%q}"
+
local function hashed(t)
local s, ns = { }, 0
for k, v in next, t do
ns = ns + 1
if type(v) == "table" then
- s[ns] = k .. "={" .. hashed(v) .. "}"
+ s[ns] = format(fmt_kt,k,hashed(v))
else
- s[ns] = k .. "=" .. tostring(v)
+ s[ns] = format(fmt_kv,k,v)
end
end
sort(s)
@@ -35,7 +39,7 @@ local function simplehashed(t)
local s, ns = { }, 0
for k, v in next, t do
ns = ns + 1
- s[ns] = k .. "=" .. v
+ s[ns] = format(fmt_kv,k,v)
end
sort(s)
return concat(s,",")
@@ -55,7 +59,6 @@ local function pack(t,keys,skip,hash,index)
local k = sk[i]
if not skip or not skip[k] then
local v = t[k]
- --
if type(v) == "table" then
pack(v,keys,skip,hash,index)
if keys[k] then
diff --git a/Master/texmf-dist/tex/context/base/mkiv/util-sac.lua b/Master/texmf-dist/tex/context/base/mkiv/util-sac.lua
index 976989a77ab..47c753ab18b 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/util-sac.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/util-sac.lua
@@ -43,6 +43,8 @@ function streams.size(f)
return f and f[3] or 0
end
+streams.getsize = streams.size
+
function streams.setposition(f,i)
if f[4] then
-- zerobased
@@ -261,9 +263,9 @@ function streams.readfixed2(f)
f[2] = j + 1
local a, b = byte(f[1],i,j)
if a >= 0x80 then
- tonumber((a - 0x100) .. "." .. b)
+ return tonumber((a - 0x100) .. "." .. b) or 0
else
- tonumber((a ) .. "." .. b)
+ return tonumber((a ) .. "." .. b) or 0
end
end
@@ -273,9 +275,9 @@ function streams.readfixed4(f)
f[2] = j + 1
local a, b, c, d = byte(f[1],i,j)
if a >= 0x80 then
- tonumber((0x100 * a + b - 0x10000) .. "." .. (0x100 * c + d))
+ return tonumber((0x100 * a + b - 0x10000) .. "." .. (0x100 * c + d)) or 0
else
- tonumber((0x100 * a + b ) .. "." .. (0x100 * c + d))
+ return tonumber((0x100 * a + b ) .. "." .. (0x100 * c + d)) or 0
end
end
@@ -364,16 +366,16 @@ if sio and sio.readcardinal2 then
f[2] = i + 4
return readinteger4(f[1],i)
end
- -- function streams.readfixed2(f) -- needs recent luatex
- -- local i = f[2]
- -- f[2] = i + 2
- -- return readfixed2(f[1],i)
- -- end
- -- function streams.readfixed4(f) -- needs recent luatex
- -- local i = f[2]
- -- f[2] = i + 4
- -- return readfixed4(f[1],i)
- -- end
+ function streams.readfixed2(f) -- needs recent luatex
+ local i = f[2]
+ f[2] = i + 2
+ return readfixed2(f[1],i)
+ end
+ function streams.readfixed4(f) -- needs recent luatex
+ local i = f[2]
+ f[2] = i + 4
+ return readfixed4(f[1],i)
+ end
function streams.read2dot4(f)
local i = f[2]
f[2] = i + 2
@@ -485,3 +487,58 @@ else
end
end
+
+-- For practical reasons we put this here. It's less efficient but ok when we don't
+-- have much access.
+
+do
+
+ local files = utilities.files
+
+ if files then
+
+ local openfile = files.open
+ local openstream = streams.open
+ local openstring = streams.openstring
+
+ local setmetatable = setmetatable
+
+ function io.newreader(str,method)
+ local f, m
+ if method == "string" then
+ f = openstring(str)
+ m = streams
+ elseif method == "stream" then
+ f = openstream(str)
+ m = streams
+ else
+ f = openfile(str,"rb")
+ m = files
+ end
+ if f then
+ local t = { }
+ setmetatable(t, {
+ __index = function(t,k)
+ local r = m[k]
+ if k == "close" then
+ if f then
+ m.close(f)
+ f = nil
+ end
+ return function() end
+ elseif r then
+ local v = function(_,a,b) return r(f,a,b) end
+ t[k] = v
+ return v
+ else
+ print("unknown key",k)
+ end
+ end
+ } )
+ return t
+ end
+ end
+
+ end
+
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/util-sbx.lua b/Master/texmf-dist/tex/context/base/mkiv/util-sbx.lua
index 57c57687067..cd282009e0a 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/util-sbx.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/util-sbx.lua
@@ -241,6 +241,10 @@ table.setmetatableindex(validators,function(t,k)
return readable
end)
+-- function validators.verbose(s)
+-- return s
+-- end
+
function validators.string(s,finalized)
-- can be used to prevent filename checking (todo: only when registered)
if finalized and suspicious(s) then
@@ -307,8 +311,8 @@ end
-- runners can be strings or tables
--
-- os.execute : string
--- os.exec : string or table with program in [0|1]
--- os.spawn : string or table with program in [0|1]
+-- os.exec : string or table with program in [0|1] -- no longer there
+-- os.spawn : string or table with program in [0|1] -- no longer there
--
-- our execute: registered program with specification
@@ -318,39 +322,56 @@ local reported = { }
local function validcommand(name,program,template,checkers,defaults,variables,reporter,strict)
if validbinaries ~= false and (validbinaries == true or validbinaries[program]) then
+ local binpath = nil
if variables then
for variable, value in next, variables do
- local checker = validators[checkers[variable]]
- if checker then
- value = checker(unquoted(value),strict)
- if value then
- variables[variable] = optionalquoted(value)
+ local chktype = checkers[variable]
+ if chktype == "verbose" then
+ -- for now, we will have a "flags" checker
+ else
+ local checker = validators[chktype]
+ if checker then
+ value = checker(unquoted(value),strict)
+ if value then
+ variables[variable] = optionalquoted(value)
+ else
+ report("variable %a with value %a fails the check",variable,value)
+ return
+ end
else
- report("variable %a with value %a fails the check",variable,value)
+ report("variable %a has no checker",variable)
return
end
- else
- report("variable %a has no checker",variable)
- return
end
end
for variable, default in next, defaults do
local value = variables[variable]
if not value or value == "" then
- local checker = validators[checkers[variable]]
- if checker then
- default = checker(unquoted(default),strict)
- if default then
- variables[variable] = optionalquoted(default)
- else
- report("variable %a with default %a fails the check",variable,default)
- return
+ local chktype = checkers[variable]
+ if chktype == "verbose" then
+ -- for now, we will have a "flags" checker
+ else
+ local checker = validators[chktype]
+ if checker then
+ default = checker(unquoted(default),strict)
+ if default then
+ variables[variable] = optionalquoted(default)
+ else
+ report("variable %a with default %a fails the check",variable,default)
+ return
+ end
end
end
end
end
+ binpath = variables.binarypath
+ end
+ if type(binpath) == "string" and binpath ~= "" then
+ -- this works on the console but not from e.g. scite
+ -- program = '"' .. binpath .. "/" .. program .. '"'
+ program = binpath .. "/" .. program
end
- local command = program .. " " .. replace(template,variables)
+ local command = program .. " " .. replace(template,variables)
if reporter then
reporter("executing runner %a: %s",name,command)
elseif trace then
@@ -387,7 +408,8 @@ local runners = {
if trace then
report("execute: %s",command)
end
- return osexecute(command)
+ local okay = osexecute(command)
+ return okay
end
end,
pipeto = function(...)
@@ -422,7 +444,7 @@ function sandbox.registerrunner(specification)
return
end
if validrunners[name] then
- report("invalid name, runner %a already defined")
+ report("invalid name, runner %a already defined",name)
return
end
local program = specification.program
@@ -609,8 +631,8 @@ end
if os then
overload(os.execute, binaryrunner, "os.execute")
- overload(os.spawn, dummyrunner, "os.spawn")
- overload(os.exec, dummyrunner, "os.exec")
+ overload(os.spawn, dummyrunner, "os.spawn") -- no longer there
+ overload(os.exec, dummyrunner, "os.exec") -- no longer there
overload(os.resultof, binaryrunner, "os.resultof")
overload(os.pipeto, binaryrunner, "os.pipeto")
overload(os.rename, filehandlertwo,"os.rename")
@@ -637,16 +659,7 @@ end
-- these are used later on
if zip then
- zip.open = register(zip.open, filehandlerone,"zip.open")
-end
-
-if fontloader then
- fontloader.open = register(fontloader.open,filehandlerone,"fontloader.open")
- fontloader.info = register(fontloader.info,filehandlerone,"fontloader.info")
-end
-
-if epdf then
- epdf.open = register(epdf.open, filehandlerone,"epdf.open")
+ zip.open = register(zip.open, filehandlerone,"zip.open")
end
sandbox.registerroot = registerroot
diff --git a/Master/texmf-dist/tex/context/base/mkiv/util-sci.lua b/Master/texmf-dist/tex/context/base/mkiv/util-sci.lua
index fe28635a386..778991ea69d 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/util-sci.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/util-sci.lua
@@ -18,10 +18,10 @@ utilities.scite = scite
local report = logs.reporter("scite")
do
- local lexerroot = "c:/data/system/scite/wscite/context/lexers"
- if not lexerroot then
- lexerroot = file.dirname(resolvers.find_file("scite-context-lexer.lua"))
- end
+-- local lexerroot = "c:/data/system/scite/wscite/context/lexers"
+-- if not lexerroot then
+ lexerroot = file.dirname(resolvers.findfile("scite-context-lexer.lua"))
+-- end
if lfs.isdir(lexerroot) then
package.extraluapath(lexerroot)
package.extraluapath(lexerroot.."/themes")
@@ -33,14 +33,28 @@ do
end
local knownlexers = {
- tex = "tex", mkiv = "tex", mkvi = "tex", mkxi = "tex", mkix = "tex", mkii = "tex", cld = "tex",
- lua = "lua", lfg = "lua", lus = "lua",
- mp = "mps", mpiv = "mps", mpii = "mps",
- w = "web", ww = "web",
- c = "cpp", h = "cpp", cpp = "cpp", hpp = "cpp", cxx = "cpp", hxx = "cpp",
- xml = "xml", lmx = "xml", ctx = "xml", xsl = "xml", xsd = "xml", rlx = "xml", css = "xml", dtd = "xml",
- bib = "bibtex",
- rme = "txt",
+ tex = "tex",
+ mkiv = "tex", mkvi = "tex",
+ mkxl = "tex", mklx = "tex",
+ mkxi = "tex", mkix = "tex",
+ mkii = "tex",
+ bib = "bibtex",
+ cld = "tex",
+ lua = "lua", lmt = "lua",
+ lfg = "lua", lus = "lua", luv = "lua",
+ mp = "mps",
+ mpiv = "mps",
+ mpxl = "mps",
+ mpii = "mps",
+ w = "web", ww = "web",
+ c = "cpp", h = "cpp",
+ cpp = "cpp", hpp = "cpp",
+ cxx = "cpp", hxx = "cpp",
+ xml = "xml", xsl = "xml", xsd = "xml", dtd = "xml",
+ lmx = "xml", ctx = "xml", rlx = "xml",
+ css = "xml",
+ rme = "txt",
+ txt = "txt",
-- todo: pat/hyp ori
}
@@ -70,13 +84,15 @@ scite.loadedlexers = loadedlexers
scite.knownlexers = knownlexers
scite.loadscitelexer = loadscitelexer
-local f_fore_bold = formatters['.%s { display: inline ; font-weight: bold ; color: #%02X%02X%02X ; }']
-local f_fore_none = formatters['.%s { display: inline ; font-weight: normal ; color: #%02X%02X%02X ; }']
-local f_none_bold = formatters['.%s { display: inline ; font-weight: bold ; }']
-local f_none_none = formatters['.%s { display: inline ; font-weight: normal ; }']
+local f_fore_bold = formatters['.%s { display:inline; font-weight:bold; color:#%02X%02X%02X; }']
+local f_fore_none = formatters['.%s { display:inline; font-weight:normal; color:#%02X%02X%02X; }']
+local f_none_bold = formatters['.%s { display:inline; font-weight:bold; }']
+local f_none_none = formatters['.%s { display:inline; font-weight:normal; }']
local f_div_class = formatters['<div class="%s">%s</div>']
local f_linenumber = formatters['<div class="linenumber">%s</div>\n']
-local f_div_number = formatters['.linenumber { display: inline-block ; font-weight: normal ; width: %sem ; margin-right: 2em ; padding-right: .25em ; text-align: right ; background-color: #C7C7C7 ; }']
+local f_lineerror = formatters['<div class="linenumber lineerror">%s</div>\n']
+local f_div_number = formatters['.linenumber { display:inline-block; font-weight:normal; width:%sem; margin-right:2em; padding-right:.25em; text-align:right; color:#000000; }'] -- background-color:#C7C7C7;
+local s_div_error = '.lineerror { font-weight:bold; color:#FFFFFF; background-color:#000000; }'
local replacer_regular = lpeg.replacer {
["<"] = "&lt;",
@@ -85,6 +101,7 @@ local replacer_regular = lpeg.replacer {
}
local linenumber = 0
+local lineerror = 0
local linenumbers = { }
local replacer_numbered = lpeg.replacer {
@@ -93,7 +110,7 @@ local replacer_numbered = lpeg.replacer {
["&"] = "&amp;",
[lpeg.patterns.newline] = function()
linenumber = linenumber + 1
- linenumbers[linenumber] = f_linenumber(linenumber)
+ linenumbers[linenumber] = (linenumber == lineerror and f_lineerror or f_linenumber)(linenumber)
return "\n"
end,
}
@@ -139,6 +156,7 @@ local function exportstyled(lexer,text,numbered)
local b = 0
linenumber = 0
linenumbers = { }
+ lineerror = tonumber(numbered) or 0
local replacer = numbered and replacer_numbered or replacer_regular
local n = #result
for i=1,n,2 do
@@ -155,12 +173,11 @@ local function exportstyled(lexer,text,numbered)
end
start = position
end
- buffer = concat(buffer)
- return buffer, concat(linenumbers)
+ return concat(buffer), concat(linenumbers)
end
local function exportcsslinenumber()
- return f_div_number(#tostring(linenumber)/2+1)
+ return f_div_number(#tostring(linenumber)/2+1) .. "\n" .. s_div_error
end
local htmlfile = utilities.templates.replacer([[
@@ -174,7 +191,7 @@ local htmlfile = utilities.templates.replacer([[
%numberstyles%
--></style>
<body>
- <table style="padding:0; margin:0;">
+ <table style="padding:0; margin:0; background-color:#FFFFFF;">
<tr>
<td><pre>%linenumbers%</pre></td>
<td><pre>%lexedcontent%</pre></td>
@@ -184,15 +201,30 @@ local htmlfile = utilities.templates.replacer([[
</html>
]])
+local htmlblob = utilities.templates.replacer([[
+<style type="text/css"><!--
+%lexingstyles%
+%numberstyles%
+--></style>
+<table style="padding:0; margin:0; background-color:#FFFFFF;">
+ <tr>
+ <td><pre>%linenumbers%</pre></td>
+ <td><pre>%lexedcontent%</pre></td>
+ </tr>
+</table>
+]])
+
function scite.tohtml(data,lexname,numbered,title)
local source, lines = exportstyled(loadedlexers[lexname],data or "",numbered)
- return htmlfile {
- lexedcontent = source, -- before numberstyles
- lexingstyles = exportcsslexing(),
- numberstyles = exportcsslinenumber(),
- title = title or "context source file",
- linenumbers = lines,
- }
+ if source then
+ return (title == false and htmlblob or htmlfile) {
+ lexedcontent = source, -- before numberstyles
+ lexingstyles = exportcsslexing(),
+ numberstyles = exportcsslinenumber(),
+ title = title or "context source file",
+ linenumbers = lines,
+ }
+ end
end
local function maketargetname(name)
diff --git a/Master/texmf-dist/tex/context/base/mkiv/util-seq.lua b/Master/texmf-dist/tex/context/base/mkiv/util-seq.lua
index e7a503fafcd..35839f2302c 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/util-seq.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/util-seq.lua
@@ -29,13 +29,13 @@ local formatters = string.formatters
local replacer = utilities.templates.replacer
local trace_used = false
-local trace_detail = false
+local trace_details = false
local report = logs.reporter("sequencer")
local usedcount = 0
local usednames = { }
-trackers.register("sequencers.used", function(v) trace_used = true end)
-trackers.register("sequencers.detail",function(v) trace_detail = true end)
+trackers.register("sequencers.used", function(v) trace_used = v end)
+trackers.register("sequencers.details", function(v) trace_details = v end)
local sequencers = { }
utilities.sequencers = sequencers
@@ -369,7 +369,7 @@ function sequencers.nodeprocessor(t,nofarguments)
local steps = 0
usedcount = usedcount + 1
--
- if trace_detail then
+ if trace_details then
naliases = naliases + 1
aliases[naliases] = formatters["local report = logs.reporter('sequencer',%q)"](name)
ncalls = ncalls + 1
@@ -383,12 +383,12 @@ function sequencers.nodeprocessor(t,nofarguments)
local action = actions[i]
if not askip[action] then
steps = steps + 1
- if trace_used or trace_detail then
+ if trace_used or trace_details then
local action = tostring(action)
report("%02i: category %a, group %a, action %a",usedcount,name,group,action)
usednames[action] = true
end
- if trace_detail then
+ if trace_details then
ncalls = ncalls + 1
calls[ncalls] = formatters[ [[report(" step %a, action %a")]] ](steps,tostring(action))
end
@@ -407,7 +407,7 @@ function sequencers.nodeprocessor(t,nofarguments)
if steps == 0 then
processor = templates.default or construct { }
else
- if trace_detail then
+ if trace_details then
ncalls = ncalls + 1
calls[ncalls] = [[report("stop")]]
end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/util-sha.lua b/Master/texmf-dist/tex/context/base/mkiv/util-sha.lua
index d84e46975fa..ea722073318 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/util-sha.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/util-sha.lua
@@ -38,9 +38,12 @@ end
--
-- On short strings 256 seems faster than 512 while on a megabyte blob 512 wins
-- from 256 (64 bit internals).
+--
+-- Using the stream reader we can probably speed up the following code a bit
+-- because it's faster than unpack.
-local packstring, unpackstring = string.pack, string.unpack
-local unpack, setmetatable = unpack, setmetatable
+local packstring, unpackstring, formatstring = string.pack, string.unpack, string.format
+local repstring = string.rep
local constants256 = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
@@ -72,31 +75,6 @@ local constants512 = {
0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817,
}
--- Not really needed, but more in tune with md5. In fact, as we use the mtxlib
--- helpers I might as well assume more.
-
-local tohex, toHEX
-
-if lpeg then local lpegpatterns = lpeg.patterns if lpegpatterns then
-
- local lpegmatch = lpeg.match
- local bytestohex = lpegpatterns.bytestohex
- local bytestoHEX = lpegpatterns.bytestoHEX
-
- tohex = function(s) return lpegmatch(bytestohex,s) end
- toHEX = function(s) return lpegmatch(bytestoHEX,s) end
-
-end end
-
-if not tohex then
-
- local format, byte, gsub = string.format, string.byte, string.gsub
-
- tohex = function(s) return (gsub(s,".",function(c) return format("%02X",byte(c)) end)) end
- toHEX = function(s) return (gsub(s,".",function(c) return format("%02X",byte(c)) end)) end
-
-end
-
local prepare = { }
if utilities and utilities.strings then
@@ -112,13 +90,11 @@ if utilities and utilities.strings then
else
- local rep = string.rep
-
prepare[256] = function(str,len)
- return str .. "\128" .. rep("\0",-(1 + 8 + len) % 64) .. packstring(">I8", 8 * len)
+ return str .. "\128" .. repstring("\0",-(1 + 8 + len) % 64) .. packstring(">I8", 8 * len)
end
prepare[512] = function(str,len)
- return str .. "\128" .. rep("\0",-(1 + 16 + len) % 128) .. packstring(">I16", 8 * len)
+ return str .. "\128" .. repstring("\0",-(1 + 16 + len) % 128) .. packstring(">I16", 8 * len)
end
end
@@ -162,9 +138,10 @@ local list = { } -- some 5% faster
digest[256] = function(str,i,hash)
- for i=1,#str,64 do
+ local hash1, hash2, hash3, hash4 = hash[1], hash[2], hash[3], hash[4]
+ local hash5, hash6, hash7, hash8 = hash[5], hash[6], hash[7], hash[8]
- -- local w = { unpackstring(">I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4",str,i) }
+ for i=1,#str,64 do
list[ 1], list[ 2], list[ 3], list[ 4], list[ 5], list[ 6], list[ 7], list[ 8],
list[ 9], list[10], list[11], list[12], list[13], list[14], list[15], list[16] =
@@ -183,7 +160,7 @@ digest[256] = function(str,i,hash)
& 0xffffffff
end
- local a, b, c, d, e, f, g, h = -- unpack(hash)
+ local a, b, c, d, e, f, g, h =
hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7], hash[8]
for i=1,64 do
@@ -208,23 +185,27 @@ digest[256] = function(str,i,hash)
a = (t1 + t2) & 0xffffffff
end
- hash[1] = (hash[1] + a) & 0xffffffff
- hash[2] = (hash[2] + b) & 0xffffffff
- hash[3] = (hash[3] + c) & 0xffffffff
- hash[4] = (hash[4] + d) & 0xffffffff
- hash[5] = (hash[5] + e) & 0xffffffff
- hash[6] = (hash[6] + f) & 0xffffffff
- hash[7] = (hash[7] + g) & 0xffffffff
- hash[8] = (hash[8] + h) & 0xffffffff
+ hash1 = (hash1 + a) & 0xffffffff
+ hash2 = (hash2 + b) & 0xffffffff
+ hash3 = (hash3 + c) & 0xffffffff
+ hash4 = (hash4 + d) & 0xffffffff
+ hash5 = (hash5 + e) & 0xffffffff
+ hash6 = (hash6 + f) & 0xffffffff
+ hash7 = (hash7 + g) & 0xffffffff
+ hash8 = (hash8 + h) & 0xffffffff
end
+
+ return hash1, hash2, hash3, hash4, hash5, hash6, hash7, hash8
+
end
digest[512] = function(str,i,hash)
- for i=1,#str,128 do
+ local hash1, hash2, hash3, hash4 = hash[1], hash[2], hash[3], hash[4]
+ local hash5, hash6, hash7, hash8 = hash[5], hash[6], hash[7], hash[8]
- -- local w = { unpackstring(">I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4",str,i) }
+ for i=1,#str,128 do
list[ 1], list[ 2], list[ 3], list[ 4], list[ 5], list[ 6], list[ 7], list[ 8],
list[ 9], list[10], list[11], list[12], list[13], list[14], list[15], list[16] =
@@ -243,7 +224,7 @@ digest[512] = function(str,i,hash)
-- & 0xffffffffffffffff
end
- local a, b, c, d, e, f, g, h = -- unpack(hash)
+ local a, b, c, d, e, f, g, h =
hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7], hash[8]
for i=1,80 do
@@ -268,70 +249,159 @@ digest[512] = function(str,i,hash)
a = (t1 + t2) -- & 0xffffffffffffffff
end
- hash[1] = (hash[1] + a) -- & 0xffffffffffffffff
- hash[2] = (hash[2] + b) -- & 0xffffffffffffffff
- hash[3] = (hash[3] + c) -- & 0xffffffffffffffff
- hash[4] = (hash[4] + d) -- & 0xffffffffffffffff
- hash[5] = (hash[5] + e) -- & 0xffffffffffffffff
- hash[6] = (hash[6] + f) -- & 0xffffffffffffffff
- hash[7] = (hash[7] + g) -- & 0xffffffffffffffff
- hash[8] = (hash[8] + h) -- & 0xffffffffffffffff
+ hash1 = (hash1 + a) -- & 0xffffffffffffffff
+ hash2 = (hash2 + b) -- & 0xffffffffffffffff
+ hash3 = (hash3 + c) -- & 0xffffffffffffffff
+ hash4 = (hash4 + d) -- & 0xffffffffffffffff
+ hash5 = (hash5 + e) -- & 0xffffffffffffffff
+ hash6 = (hash6 + f) -- & 0xffffffffffffffff
+ hash7 = (hash7 + g) -- & 0xffffffffffffffff
+ hash8 = (hash8 + h) -- & 0xffffffffffffffff
end
+
+ return hash1, hash2, hash3, hash4, hash5, hash6, hash7, hash8
+
end
digest[224] = digest[256]
digest[384] = digest[512]
-local finalize = {
- [224] = function(hash,tohex) local s = packstring(">I4I4I4I4I4I4I4", unpack(hash)) return tohex and tohex(s) or s end, -- # 56
- [256] = function(hash,tohex) local s = packstring(">I4I4I4I4I4I4I4I4",unpack(hash)) return tohex and tohex(s) or s end, -- # 64
- [384] = function(hash,tohex) local s = packstring(">I8I8I8I8I8I8", unpack(hash)) return tohex and tohex(s) or s end, -- # 96
- [512] = function(hash,tohex) local s = packstring(">I8I8I8I8I8I8I8I8",unpack(hash)) return tohex and tohex(s) or s end, -- # 128
-}
-
local hash = { }
-local function hashed(str,method,tohex)
+local function hashed(str,method,convert,pattern)
local s = prepare[method](str,#str)
local h = initialize[method](hash)
- digest[method](s,i,h)
- return finalize[method](h,tohex)
+ return convert(pattern,digest[method](s,i,h))
end
local sha2 = {
- digest224 = function(str) return hashed(str,224) end,
- digest256 = function(str) return hashed(str,256) end,
- digest384 = function(str) return hashed(str,384) end,
- digest512 = function(str) return hashed(str,512) end,
- hash224 = function(str) return hashed(str,224,tohex) end,
- hash256 = function(str) return hashed(str,256,tohex) end,
- hash384 = function(str) return hashed(str,384,tohex) end,
- hash512 = function(str) return hashed(str,512,tohex) end,
- HASH224 = function(str) return hashed(str,224,toHEX) end,
- HASH256 = function(str) return hashed(str,256,toHEX) end,
- HASH384 = function(str) return hashed(str,384,toHEX) end,
- HASH512 = function(str) return hashed(str,512,toHEX) end,
+ digest224 = function(str) return hashed(str,224,packstring,">I4I4I4I4I4I4I4") end,
+ digest256 = function(str) return hashed(str,256,packstring,">I4I4I4I4I4I4I4I4") end,
+ digest384 = function(str) return hashed(str,384,packstring,">I8I8I8I8I8I8") end,
+ digest512 = function(str) return hashed(str,512,packstring,">I8I8I8I8I8I8I8I8") end,
+ hash224 = function(str) return hashed(str,224,formatstring,"%0x04%0x04%0x04%0x04%0x04%0x04%0x04") end,
+ hash256 = function(str) return hashed(str,256,formatstring,"%0x04%0x04%0x04%0x04%0x04%0x04%0x04%0x04") end,
+ hash384 = function(str) return hashed(str,384,formatstring,"%0x08%0x08%0x08%0x08%0x08%0x08") end,
+ hash512 = function(str) return hashed(str,512,formatstring,"%0x08%0x08%0x08%0x08%0x08%0x08%0x08%0x08") end,
+ HASH224 = function(str) return hashed(str,224,formatstring,"%0X04%0X04%0X04%0X04%0X04%0X04%0X04") end,
+ HASH256 = function(str) return hashed(str,256,formatstring,"%0X04%0X04%0X04%0X04%0X04%0X04%0X04%0X04") end,
+ HASH384 = function(str) return hashed(str,384,formatstring,"%0X08%0X08%0X08%0X08%0X08%0X08") end,
+ HASH512 = function(str) return hashed(str,512,formatstring,"%0X08%0X08%0X08%0X08%0X08%0X08%0X08%0X08") end,
}
--- local setmetatableindex = table.setmetatableindex
+-- The wikipedia provides the code:
+--
+-- https://en.wikipedia.org/wiki/SHA-1
+--
+-- and (nor being in th emood to writ it myself) a bit of googling gave a decent
+-- starting point:
+--
+-- https://github.com/gdyr/LuaSHA1/blob/master/sha1.lua
--
--- if setmetatableindex then
--- sha2.hashed = setmetatableindex(function(t,k)
--- local v = digest[k] and function(str) return hashed(str,k,tohex) end or false
--- t[k] = v
--- return v
--- end)
--- sha2.HASHED = setmetatableindex(function(t,k)
--- local v = digest[k] and function(str) return hashed(str,k,toHEX) end or false
--- t[k] = v
--- return v
--- end)
--- end
+-- and after that it was just a matter of optimizing the code a bit. I just put
+-- it here as reference as we probably don't use it. We could use a repeater as
+-- we do with sha2.
+
+local function digest(str)
+
+ local h1 = 0x67452301
+ local h2 = 0xEFCDAB89
+ local h3 = 0x98BADCFE
+ local h4 = 0x10325476
+ local h5 = 0xC3D2E1F0
+
+ local len = #str
+ local list = { } -- we can even move this outside the function
+
+ str = str .. "\128" .. repstring("\0", (120 - ((len + 1) % 64)) % 64) .. packstring(">I8", 8 * len)
+
+ for i=1,#str,64 do
+
+ list[ 1], list[ 2], list[ 3], list[ 4], list[ 5], list[ 6], list[ 7], list[ 8],
+ list[ 9], list[10], list[11], list[12], list[13], list[14], list[15], list[16] =
+ unpackstring(">I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4",str,i)
+
+ for i=17,80 do
+ local v = list[i-3] ~ list[i-8] ~ list[i-14] ~ list[i-16]
+ list[i] = ((v << 1) | (v >> 31)) & 0xFFFFFFFF
+ end
+
+ local a, b, c, d, e = h1, h2, h3, h4, h5
+
+ for i=1,20 do
+ local f = (b & c) | ((~b) & d)
+ local r = (a << 5) | (a >> 27)
+ local s = (f + r + e + 0x5A827999 + list[i]) & 0xFFFFFFFF
+ e = d
+ d = c
+ c = (b << 30) | (b >> 2)
+ b = a
+ a = s
+ end
+
+ for i=21,40 do
+ local f = b ~ c ~ d
+ local r = (a << 5) | (a >> 27)
+ local s = (f + r + e + 0x6ED9EBA1 + list[i]) & 0xFFFFFFFF
+ e = d
+ d = c
+ c = (b << 30) | (b >> 2)
+ b = a
+ a = s
+ end
+
+ for i=41,60 do
+ local f = (b & c) | (b & d) | (c & d)
+ local r = (a << 5) | (a >> 27)
+ local s = (f + r + e + 0x8F1BBCDC + list[i]) & 0xFFFFFFFF
+ e = d
+ d = c
+ c = (b << 30) | (b >> 2)
+ b = a
+ a = s
+ end
+
+ for i=61,80 do
+ local f = b ~ c ~ d
+ local r = (a << 5) | (a >> 27)
+ local s = (f + r + e + 0xCA62C1D6 + list[i]) & 0xFFFFFFFF
+ e = d
+ d = c
+ c = (b << 30) | (b >> (32 - 30))
+ b = a
+ a = s
+ end
+
+ h1 = (h1 + a) & 0xFFFFFFFF
+ h2 = (h2 + b) & 0xFFFFFFFF
+ h3 = (h3 + c) & 0xFFFFFFFF
+ h4 = (h4 + d) & 0xFFFFFFFF
+ h5 = (h5 + e) & 0xFFFFFFFF
+
+ end
+
+ return h1, h2, h3, h4, h5
+
+end
+
+-- A similar wrapper as we use for sha2:
+
+local sha1 = {
+ digest = function(str)
+ return packstring(">I4I4I4I4I4",digest(str))
+ end,
+ hash = function(str)
+ return formatstring("%08x%08x%08x%08x%08x",digest(str))
+ end,
+ HASH = function(str)
+ return formatstring("%08X%08X%08X%08X%08X",digest(str))
+ end,
+}
if utilities then
utilities.sha2 = sha2
+ utilities.sha1 = sha1
end
return sha2
-
diff --git a/Master/texmf-dist/tex/context/base/mkiv/util-soc-imp-copas.lua b/Master/texmf-dist/tex/context/base/mkiv/util-soc-imp-copas.lua
index 3e66e588838..1268613d122 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/util-soc-imp-copas.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/util-soc-imp-copas.lua
@@ -50,6 +50,8 @@ local copas = {
report = report,
+ trace = false,
+
}
local function statushandler(status, ...)
@@ -60,7 +62,9 @@ local function statushandler(status, ...)
if type(err) == "table" then
err = err[1]
end
- report("error: %s",tostring(err))
+ if copas.trace then
+ report("error: %s",tostring(err))
+ end
return nil, err
end
@@ -76,7 +80,9 @@ function socket.newtry(finalizer)
if not status then
local detail = select(2,...)
pcall(finalizer,detail)
- report("error: %s",tostring(detail))
+ if copas.trace then
+ report("error: %s",tostring(detail))
+ end
return
end
return ...
diff --git a/Master/texmf-dist/tex/context/base/mkiv/util-sql-imp-ffi.lua b/Master/texmf-dist/tex/context/base/mkiv/util-sql-imp-ffi.lua
index 3731933f1e1..f440695023d 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/util-sql-imp-ffi.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/util-sql-imp-ffi.lua
@@ -66,9 +66,6 @@ ffi.cdef [[
void *extension;
} MYSQL_field;
- void free(void*ptr);
- void * malloc(size_t size);
-
MYSQL_instance * mysql_init (
MYSQL_instance *mysql
);
@@ -153,7 +150,7 @@ ffi.cdef [[
); */
]]
-
+-- trackers.enable("*lib*")
local sql = utilities.sql
----- mysql = ffi.load(os.name == "windows" and "libmysql" or "libmysqlclient")
----- mysql = ffilib(os.name == "windows" and "libmysql" or "libmysqlclient")
diff --git a/Master/texmf-dist/tex/context/base/mkiv/util-sql-imp-sqlite.lua b/Master/texmf-dist/tex/context/base/mkiv/util-sql-imp-sqlite.lua
index cf4a3a8b04d..a88035f683a 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/util-sql-imp-sqlite.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/util-sql-imp-sqlite.lua
@@ -66,6 +66,7 @@ ffi.cdef [[
const char *sqlite3_errmsg (
sqlite3*
);
+
]]
local ffi_tostring = ffi.string
diff --git a/Master/texmf-dist/tex/context/base/mkiv/util-sql.lua b/Master/texmf-dist/tex/context/base/mkiv/util-sql.lua
index d01a2267cf6..36f3eab1935 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/util-sql.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/util-sql.lua
@@ -60,7 +60,7 @@ if not modules then modules = { } end modules ['util-sql'] = {
local format, match = string.format, string.match
local random = math.random
-local rawset, setmetatable, getmetatable, load, type = rawset, setmetatable, getmetatable, load, type
+local rawset, rawget, setmetatable, getmetatable, load, type = rawset, rawget, setmetatable, getmetatable, load, type
local P, S, V, C, Cs, Ct, Cc, Cg, Cf, patterns, lpegmatch = lpeg.P, lpeg.S, lpeg.V, lpeg.C, lpeg.Cs, lpeg.Ct, lpeg.Cc, lpeg.Cg, lpeg.Cf, lpeg.patterns, lpeg.match
local concat = table.concat
@@ -109,16 +109,43 @@ local defaults = { __index =
},
}
-setmetatableindex(sql.methods,function(t,k)
- if type(k) == "string" then
- report_state("start loading method %a",k)
- require("util-sql-imp-"..k)
- report_state("loading method %a done",k)
- return rawget(t,k)
- else
- report_state("invalid method %a",tostring(k))
- end
-end)
+if optional then
+
+ local methods = {
+ ffi = "mysql",
+ library = "mysql",
+ swiglib = "mysql",
+ postgress = "postgress",
+ sqlite = "sqlite",
+ sqlite3 = "sqlite",
+ }
+
+ setmetatableindex(sql.methods,function(t,k)
+ local m = methods[k]
+ if m then
+ report_state("start loading method %a as %a",k,m)
+ require("libs-imp-" .. m)
+ report_state("loading method %a done",k)
+ return rawget(t,m)
+ else
+ report_state("invalid method %a",tostring(k))
+ end
+ end)
+
+else
+
+ setmetatableindex(sql.methods,function(t,k)
+ if type(k) == "string" then
+ report_state("start loading method %a",k)
+ require("util-sql-imp-" .. k)
+ report_state("loading method %a done",k)
+ return rawget(t,k)
+ else
+ report_state("invalid method %a",tostring(k))
+ end
+ end)
+
+end
-- converters
diff --git a/Master/texmf-dist/tex/context/base/mkiv/util-sta.lua b/Master/texmf-dist/tex/context/base/mkiv/util-sta.lua
index 7819395f69c..9ca1c67e9ad 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/util-sta.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/util-sta.lua
@@ -81,6 +81,8 @@ end
function stacker.new(name)
+ -- to be sped up, mmaybe foo:bar syntax here but then quite some access
+
local report = logs.reporter("stacker",name or nil)
local s
@@ -93,6 +95,7 @@ function stacker.new(name)
local hashing = true
local function push(...)
+ -- todo check if more than 1 argument
for i=1,select("#",...) do
insert(stack,(select(i,...))) -- watch the ()
end
@@ -153,8 +156,12 @@ function stacker.new(name)
local function resolve_step(ti) -- keep track of changes outside function !
-- todo: optimize for n=1 etc
+ if not top then
+ -- report("messed op stacker %a",name)
+ return
+ end
local result = nil
- local noftop = top and #top or 0
+ local noftop = #top
if ti > 0 then
local current = list[ti]
if current then
diff --git a/Master/texmf-dist/tex/context/base/mkiv/util-str.lua b/Master/texmf-dist/tex/context/base/mkiv/util-str.lua
index a04b2083586..4d23f88b7e8 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/util-str.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/util-str.lua
@@ -584,6 +584,26 @@ local template = [[
return function(%s) return %s end
]]
+-- this might move
+
+local pattern = Cs(Cc('"') * (
+ (1-S('"\\\n\r'))^1
+ + P('"') / '\\"'
+ + P('\\') / '\\\\'
+ + P('\n') / '\\n'
+ + P('\r') / '\\r'
+)^0 * Cc('"'))
+
+patterns.escapedquotes = pattern
+
+function string.escapedquotes(s)
+ return lpegmatch(pattern,s)
+end
+
+-- print(string.escapedquotes('1\\23\n"'))
+
+-- but for now here
+
local preamble = ""
local environment = {
@@ -609,10 +629,11 @@ local environment = {
formattednumber = number.formatted,
sparseexponent = number.sparseexponent,
formattedfloat = number.formattedfloat,
- stripzero = lpeg.patterns.stripzero,
- stripzeros = lpeg.patterns.stripzeros,
+ stripzero = patterns.stripzero,
+ stripzeros = patterns.stripzeros,
+ escapedquotes = string.escapedquotes,
- FORMAT = string.f9,
+ FORMAT = string.f6,
}
-- -- --
@@ -680,16 +701,22 @@ local format_left = function(f)
end
end
-local format_q = function()
+local format_q = JITSUPPORTED and function()
n = n + 1
-- lua 5.3 has a different q than lua 5.2 (which does a tostring on numbers)
-- return format("(a%s ~= nil and format('%%q',a%s) or '')",n,n)
return format("(a%s ~= nil and format('%%q',tostring(a%s)) or '')",n,n)
+ -- return format("(a%s ~= nil and escapedquotes(tostring(a%s)) or '')",n,n)
+end or function()
+ n = n + 1
+ return format("(a%s ~= nil and format('%%q',a%s) or '')",n,n)
end
-local format_Q = function() -- can be optimized
+
+local format_Q = function() -- fast escaping
n = n + 1
- return format("format('%%q',tostring(a%s))",n)
+-- return format("format('%%q',tostring(a%s))",n)
+ return format("escapedquotes(tostring(a%s))",n)
end
local format_i = function(f)
@@ -885,7 +912,7 @@ local format_L = function()
return format("(a%s and 'TRUE' or 'FALSE')",n)
end
-local format_n = function() -- strips leading and trailing zeros and removes .0
+local format_n = function() -- strips leading and trailing zeros and removes .0, beware: can produce e notation
n = n + 1
return format("((a%s %% 1 == 0) and format('%%i',a%s) or tostring(a%s))",n,n,n)
end
@@ -915,13 +942,30 @@ end
-- end
-- end
-local format_N = function(f) -- strips leading and trailing zeros
- n = n + 1
- -- stripzero (singular) as we only have a number
- if not f or f == "" then
- f = ".9"
- end -- always a leading number !
- return format("(((a%s %% 1 == 0) and format('%%i',a%s)) or lpegmatch(stripzero,format('%%%sf',a%s)))",n,n,f,n)
+local format_N if environment.FORMAT then
+
+ format_N = function(f)
+ n = n + 1
+ if not f or f == "" then
+ return format("FORMAT(a%s,'%%.9f')",n)
+ elseif f == ".6" or f == "0.6" then
+ return format("FORMAT(a%s)",n)
+ else
+ return format("FORMAT(a%s,'%%%sf')",n,f)
+ end
+ end
+
+else
+
+ format_N = function(f) -- strips leading and trailing zeros
+ n = n + 1
+ -- stripzero (singular) as we only have a number
+ if not f or f == "" then
+ f = ".9"
+ end -- always a leading number !
+ return format("(((a%s %% 1 == 0) and format('%%i',a%s)) or lpegmatch(stripzero,format('%%%sf',a%s)))",n,n,f,n)
+ end
+
end
local format_a = function(f)
@@ -1328,9 +1372,9 @@ patterns.luaquoted = Cs(Cc('"') * ((1-S('"\n'))^1 + P('"')/'\\"' + P('\n')/'\\n"
-- escaping by lpeg is faster for strings without quotes, slower on a string with quotes, but
-- faster again when other q-escapables are found (the ones we don't need to escape)
-add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],{ xmlescape = lpeg.patterns.xmlescape })
-add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape = lpeg.patterns.texescape })
-add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape = lpeg.patterns.luaescape })
+add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],{ xmlescape = patterns.xmlescape })
+add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape = patterns.texescape })
+add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape = patterns.luaescape })
-- -- yes or no:
--
@@ -1408,3 +1452,31 @@ local f_16_16 = formatters["%0.5N"]
function number.to16dot16(n)
return f_16_16(n/65536.0)
end
+
+--
+
+if not string.explode then
+
+ local tsplitat = lpeg.tsplitat
+
+ local p_utf = patterns.utf8character
+ local p_check = C(p_utf) * (P("+") * Cc(true))^0
+ local p_split = Ct(C(p_utf)^0)
+ local p_space = Ct((C(1-P(" ")^1) + P(" ")^1)^0)
+
+ function string.explode(str,symbol)
+ if symbol == "" then
+ return lpegmatch(p_split,str)
+ elseif symbol then
+ local a, b = lpegmatch(p_check,symbol)
+ if b then
+ return lpegmatch(tsplitat(P(a)^1),str)
+ else
+ return lpegmatch(tsplitat(a),str)
+ end
+ else
+ return lpegmatch(p_space,str)
+ end
+ end
+
+end
diff --git a/Master/texmf-dist/tex/context/base/mkiv/util-tab.lua b/Master/texmf-dist/tex/context/base/mkiv/util-tab.lua
index 2f425cca384..4dafb2acd65 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/util-tab.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/util-tab.lua
@@ -314,86 +314,177 @@ end
-- best keep [%q] keys (as we have some in older applications i.e. saving user data (otherwise
-- we also need to check for reserved words)
-local f_hashed_string = formatters["[%q]=%q,"]
-local f_hashed_number = formatters["[%q]=%s,"]
-local f_hashed_boolean = formatters["[%q]=%l,"]
-local f_hashed_table = formatters["[%q]="]
-
-local f_indexed_string = formatters["[%s]=%q,"]
-local f_indexed_number = formatters["[%s]=%s,"]
-local f_indexed_boolean = formatters["[%s]=%l,"]
-local f_indexed_table = formatters["[%s]="]
-
-local f_ordered_string = formatters["%q,"]
-local f_ordered_number = formatters["%s,"]
-local f_ordered_boolean = formatters["%l,"]
-
-function table.fastserialize(t,prefix)
-
- -- prefix should contain the =
- -- not sorted
- -- only number and string indices (currently)
-
- local r = { type(prefix) == "string" and prefix or "return" }
- local m = 1
- local function fastserialize(t,outer) -- no mixes
- local n = #t
- m = m + 1
- r[m] = "{"
- if n > 0 then
- for i=0,n do
- local v = t[i]
- local tv = type(v)
- if tv == "string" then
- m = m + 1 r[m] = f_ordered_string(v)
- elseif tv == "number" then
- m = m + 1 r[m] = f_ordered_number(v)
- elseif tv == "table" then
- fastserialize(v)
- elseif tv == "boolean" then
- m = m + 1 r[m] = f_ordered_boolean(v)
+if JITSUPPORTED then
+
+ local f_hashed_string = formatters["[%Q]=%Q,"]
+ local f_hashed_number = formatters["[%Q]=%s,"]
+ local f_hashed_boolean = formatters["[%Q]=%l,"]
+ local f_hashed_table = formatters["[%Q]="]
+
+ local f_indexed_string = formatters["[%s]=%Q,"]
+ local f_indexed_number = formatters["[%s]=%s,"]
+ local f_indexed_boolean = formatters["[%s]=%l,"]
+ local f_indexed_table = formatters["[%s]="]
+
+ local f_ordered_string = formatters["%Q,"]
+ local f_ordered_number = formatters["%s,"]
+ local f_ordered_boolean = formatters["%l,"]
+
+ function table.fastserialize(t,prefix) -- todo, move local function out
+
+ -- prefix should contain the =
+ -- not sorted
+ -- only number and string indices (currently)
+
+ local r = { type(prefix) == "string" and prefix or "return" }
+ local m = 1
+ local function fastserialize(t,outer) -- no mixes
+ local n = #t
+ m = m + 1
+ r[m] = "{"
+ if n > 0 then
+ local v = t[0]
+ if v then
+ local tv = type(v)
+ if tv == "string" then
+ m = m + 1 r[m] = f_indexed_string(0,v)
+ elseif tv == "number" then
+ m = m + 1 r[m] = f_indexed_number(0,v)
+ elseif tv == "table" then
+ m = m + 1 r[m] = f_indexed_table(0)
+ fastserialize(v)
+ m = m + 1 r[m] = f_indexed_table(0)
+ elseif tv == "boolean" then
+ m = m + 1 r[m] = f_indexed_boolean(0,v)
+ end
+ end
+ for i=1,n do
+ local v = t[i]
+ local tv = type(v)
+ if tv == "string" then
+ m = m + 1 r[m] = f_ordered_string(v)
+ elseif tv == "number" then
+ m = m + 1 r[m] = f_ordered_number(v)
+ elseif tv == "table" then
+ fastserialize(v)
+ elseif tv == "boolean" then
+ m = m + 1 r[m] = f_ordered_boolean(v)
+ end
end
end
- end
- for k, v in next, t do
- local tk = type(k)
- if tk == "number" then
- if k > n or k < 0 then
+ -- hm, can't we avoid this ... lua should have a way to check if there
+ -- is a hash part
+ for k, v in next, t do
+ local tk = type(k)
+ if tk == "number" then
+ if k > n or k < 0 then
+ local tv = type(v)
+ if tv == "string" then
+ m = m + 1 r[m] = f_indexed_string(k,v)
+ elseif tv == "number" then
+ m = m + 1 r[m] = f_indexed_number(k,v)
+ elseif tv == "table" then
+ m = m + 1 r[m] = f_indexed_table(k)
+ fastserialize(v)
+ elseif tv == "boolean" then
+ m = m + 1 r[m] = f_indexed_boolean(k,v)
+ end
+ end
+ else
local tv = type(v)
if tv == "string" then
- m = m + 1 r[m] = f_indexed_string(k,v)
+ m = m + 1 r[m] = f_hashed_string(k,v)
elseif tv == "number" then
- m = m + 1 r[m] = f_indexed_number(k,v)
+ m = m + 1 r[m] = f_hashed_number(k,v)
elseif tv == "table" then
- m = m + 1 r[m] = f_indexed_table(k)
+ m = m + 1 r[m] = f_hashed_table(k)
fastserialize(v)
elseif tv == "boolean" then
- m = m + 1 r[m] = f_indexed_boolean(k,v)
+ m = m + 1 r[m] = f_hashed_boolean(k,v)
end
end
+ end
+ m = m + 1
+ if outer then
+ r[m] = "}"
else
- local tv = type(v)
- if tv == "string" then
- m = m + 1 r[m] = f_hashed_string(k,v)
- elseif tv == "number" then
- m = m + 1 r[m] = f_hashed_number(k,v)
- elseif tv == "table" then
- m = m + 1 r[m] = f_hashed_table(k)
- fastserialize(v)
- elseif tv == "boolean" then
- m = m + 1 r[m] = f_hashed_boolean(k,v)
- end
+ r[m] = "},"
end
+ return r
end
- m = m + 1
- if outer then
- r[m] = "}"
- else
- r[m] = "},"
+ return concat(fastserialize(t,true))
+ end
+
+else
+
+ local f_v = formatters["[%q]=%q,"]
+ local f_t = formatters["[%q]="]
+ local f_q = formatters["%q,"]
+
+ function table.fastserialize(t,prefix) -- todo, move local function out
+ local r = { type(prefix) == "string" and prefix or "return" }
+ local m = 1
+ local function fastserialize(t,outer) -- no mixes
+ local n = #t
+ m = m + 1
+ r[m] = "{"
+ if n > 0 then
+ local v = t[0]
+ if v then
+ m = m + 1
+ r[m] = "[0]='"
+ if type(v) == "table" then
+ fastserialize(v)
+ else
+ r[m] = format("%q,",v)
+ end
+ end
+ for i=1,n do
+ local v = t[i]
+ m = m + 1
+ if type(v) == "table" then
+ r[m] = format("[%i]=",i)
+ fastserialize(v)
+ else
+ r[m] = format("[%i]=%q,",i,v)
+ end
+ end
+ end
+ -- hm, can't we avoid this ... lua should have a way to check if there
+ -- is a hash part
+ for k, v in next, t do
+ local tk = type(k)
+ if tk == "number" then
+ if k > n or k < 0 then
+ m = m + 1
+ if type(v) == "table" then
+ r[m] = format("[%i]=",k)
+ fastserialize(v)
+ else
+ r[m] = format("[%i]=%q,",k,v)
+ end
+ end
+ else
+ m = m + 1
+ if type(v) == "table" then
+ r[m] = format("[%q]=",k)
+ fastserialize(v)
+ else
+ r[m] = format("[%q]=%q,",k,v)
+ end
+ end
+ end
+ m = m + 1
+ if outer then
+ r[m] = "}"
+ else
+ r[m] = "},"
+ end
+ return r
end
- return r
+ return concat(fastserialize(t,true))
end
- return concat(fastserialize(t,true))
+
end
function table.deserialize(str)
@@ -411,7 +502,7 @@ function table.deserialize(str)
return code
end
--- inspect(table.fastserialize { a = 1, b = { 4, { 5, 6 } }, c = { d = 7, e = 'f"g\nh' } })
+-- inspect(table.fastserialize { a = 1, b = { [0]=4, { 5, 6 } }, c = { d = 7, e = 'f"g\nh' } })
function table.load(filename,loader)
if filename then
@@ -517,35 +608,35 @@ end
-- husayni.tma : 0.28 -> 0.19
local f_start_key_idx = formatters["%w{"]
-local f_start_key_num = formatters["%w[%s]={"]
+local f_start_key_num = JITSUPPORTED and formatters["%w[%s]={"] or formatters["%w[%q]={"]
local f_start_key_str = formatters["%w[%q]={"]
local f_start_key_boo = formatters["%w[%l]={"]
local f_start_key_nop = formatters["%w{"]
local f_stop = formatters["%w},"]
-local f_key_num_value_num = formatters["%w[%s]=%s,"]
-local f_key_str_value_num = formatters["%w[%q]=%s,"]
-local f_key_boo_value_num = formatters["%w[%l]=%s,"]
+local f_key_num_value_num = JITSUPPORTED and formatters["%w[%s]=%s,"] or formatters["%w[%s]=%q,"]
+local f_key_str_value_num = JITSUPPORTED and formatters["%w[%Q]=%s,"] or formatters["%w[%Q]=%q,"]
+local f_key_boo_value_num = JITSUPPORTED and formatters["%w[%l]=%s,"] or formatters["%w[%l]=%q,"]
-local f_key_num_value_str = formatters["%w[%s]=%q,"]
-local f_key_str_value_str = formatters["%w[%q]=%q,"]
-local f_key_boo_value_str = formatters["%w[%l]=%q,"]
+local f_key_num_value_str = JITSUPPORTED and formatters["%w[%s]=%Q,"] or formatters["%w[%q]=%Q,"]
+local f_key_str_value_str = formatters["%w[%Q]=%Q,"]
+local f_key_boo_value_str = formatters["%w[%l]=%Q,"]
-local f_key_num_value_boo = formatters["%w[%s]=%l,"]
-local f_key_str_value_boo = formatters["%w[%q]=%l,"]
+local f_key_num_value_boo = JITSUPPORTED and formatters["%w[%s]=%l,"] or formatters["%w[%q]=%l,"]
+local f_key_str_value_boo = formatters["%w[%Q]=%l,"]
local f_key_boo_value_boo = formatters["%w[%l]=%l,"]
-local f_key_num_value_not = formatters["%w[%s]={},"]
-local f_key_str_value_not = formatters["%w[%q]={},"]
+local f_key_num_value_not = JITSUPPORTED and formatters["%w[%s]={},"] or formatters["%w[%q]={},"]
+local f_key_str_value_not = formatters["%w[%Q]={},"]
local f_key_boo_value_not = formatters["%w[%l]={},"]
-local f_key_num_value_seq = formatters["%w[%s]={ %, t },"]
-local f_key_str_value_seq = formatters["%w[%q]={ %, t },"]
+local f_key_num_value_seq = JITSUPPORTED and formatters["%w[%s]={ %, t },"] or formatters["%w[%q]={ %, t },"]
+local f_key_str_value_seq = formatters["%w[%Q]={ %, t },"]
local f_key_boo_value_seq = formatters["%w[%l]={ %, t },"]
-local f_val_num = formatters["%w%s,"]
-local f_val_str = formatters["%w%q,"]
+local f_val_num = JITSUPPORTED and formatters["%w%s,"] or formatters["%w%q,"]
+local f_val_str = formatters["%w%Q,"]
local f_val_boo = formatters["%w%l,"]
local f_val_not = formatters["%w{},"]
local f_val_seq = formatters["%w{ %, t },"]
@@ -554,11 +645,9 @@ local f_fin_seq = formatters[" %, t }"]
local f_table_return = formatters["return {"]
local f_table_name = formatters["%s={"]
local f_table_direct = formatters["{"]
-local f_table_entry = formatters["[%q]={"]
+local f_table_entry = formatters["[%Q]={"]
local f_table_finish = formatters["}"]
------ f_string = formatters["%q"]
-
local spaces = utilities.strings.newrepeater(" ")
local original_serialize = table.serialize -- the extensive one, the one we started with
diff --git a/Master/texmf-dist/tex/context/base/mkiv/util-tpl.lua b/Master/texmf-dist/tex/context/base/mkiv/util-tpl.lua
index 5e75a151b92..318f2efc3b0 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/util-tpl.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/util-tpl.lua
@@ -20,6 +20,8 @@ local tostring, next = tostring, next
local format, sub, byte = string.format, string.sub, string.byte
local P, C, R, Cs, Cc, Carg, lpegmatch, lpegpatterns = lpeg.P, lpeg.C, lpeg.R, lpeg.Cs, lpeg.Cc, lpeg.Carg, lpeg.match, lpeg.patterns
+local formatters = string.formatters
+
-- todo: make installable template.new
local replacer
@@ -133,34 +135,42 @@ local function replaceoptional(l,m,r,t,how,recurse)
return v and v ~= "" and lpegmatch(replacer,r,1,t,how or "lua",recurse or false) or ""
end
-local single = P("%") -- test %test% test : resolves test
-local double = P("%%") -- test 10%% test : %% becomes %
-local lquoted = P("%[") -- test '%[test]%' test : resolves to test with escaped "'s
-local rquoted = P("]%") --
-local lquotedq = P("%(") -- test %(test)% test : resolves to 'test' with escaped "'s
-local rquotedq = P(")%") --
-
-local escape = double / '%%'
-local nosingle = single / ''
-local nodouble = double / ''
-local nolquoted = lquoted / ''
-local norquoted = rquoted / ''
-local nolquotedq = lquotedq / ''
-local norquotedq = rquotedq / ''
-
-local noloptional = P("%?") / ''
-local noroptional = P("?%") / ''
-local nomoptional = P(":") / ''
-
-
-local args = Carg(1) * Carg(2) * Carg(3)
-local key = nosingle * ((C((1-nosingle )^1) * args) / replacekey ) * nosingle
-local quoted = nolquotedq * ((C((1-norquotedq )^1) * args) / replacekeyquoted ) * norquotedq
-local unquoted = nolquoted * ((C((1-norquoted )^1) * args) / replacekeyunquoted) * norquoted
-local optional = noloptional * ((C((1-nomoptional)^1) * nomoptional * C((1-noroptional)^1) * args) / replaceoptional) * noroptional
-local any = P(1)
+local function replaceformatted(l,m,r,t,how,recurse)
+ local v = t[r]
+ return v and formatters[l](v)
+end
- replacer = Cs((unquoted + quoted + escape + optional + key + any)^0)
+local single = P("%") -- test %test% test : resolves test
+local double = P("%%") -- test 10%% test : %% becomes %
+local lquoted = P("%[") -- test '%[test]%' test : resolves to test with escaped "'s
+local rquoted = P("]%") --
+local lquotedq = P("%(") -- test %(test)% test : resolves to 'test' with escaped "'s
+local rquotedq = P(")%") --
+
+local escape = double / '%%'
+local nosingle = single / ''
+local nodouble = double / ''
+local nolquoted = lquoted / ''
+local norquoted = rquoted / ''
+local nolquotedq = lquotedq / ''
+local norquotedq = rquotedq / ''
+
+local nolformatted = P(":") / "%%"
+local norformatted = P(":") / ""
+
+local noloptional = P("%?") / ''
+local noroptional = P("?%") / ''
+local nomoptional = P(":") / ''
+
+local args = Carg(1) * Carg(2) * Carg(3)
+local key = nosingle * ((C((1-nosingle)^1) * args) / replacekey) * nosingle
+local quoted = nolquotedq * ((C((1-norquotedq)^1) * args) / replacekeyquoted) * norquotedq
+local unquoted = nolquoted * ((C((1-norquoted)^1) * args) / replacekeyunquoted) * norquoted
+local optional = noloptional * ((C((1-nomoptional)^1) * nomoptional * C((1-noroptional)^1) * args) / replaceoptional) * noroptional
+local formatted = nosingle * ((Cs(nolformatted * (1-norformatted )^1) * norformatted * C((1-nosingle)^1) * args) / replaceformatted) * nosingle
+local any = P(1)
+
+ replacer = Cs((unquoted + quoted + formatted + escape + optional + key + any)^0)
local function replace(str,mapping,how,recurse)
if mapping and str then
@@ -171,12 +181,16 @@ local function replace(str,mapping,how,recurse)
end
-- print(replace("test '%[x]%' test",{ x = [[a 'x'  a]] }))
+-- print(replace("test '%x%' test",{ x = [[a "x"  a]] }))
+-- print(replace([[test "%[x]%" test]],{ x = [[a "x"  a]] }))
-- print(replace("test '%[x]%' test",{ x = true }))
-- print(replace("test '%[x]%' test",{ x = [[a 'x'  a]], y = "oeps" },'sql'))
-- print(replace("test '%[x]%' test",{ x = [[a '%y%'  a]], y = "oeps" },'sql',true))
-- print(replace([[test %[x]% test]],{ x = [[a "x"  a]]}))
-- print(replace([[test %(x)% test]],{ x = [[a "x"  a]]}))
-- print(replace([[convert %?x: -x "%x%" ?% %?y: -y "%y%" ?%]],{ x = "yes" }))
+-- print(replace("test %:0.3N:x% test",{ x = 123.45 }))
+-- print(replace("test %:0.3N:x% test",{ x = 12345 }))
templates.replace = replace
diff --git a/Master/texmf-dist/tex/context/base/mkiv/util-zip.lua b/Master/texmf-dist/tex/context/base/mkiv/util-zip.lua
new file mode 100644
index 00000000000..f87e391a181
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkiv/util-zip.lua
@@ -0,0 +1,563 @@
+if not modules then modules = { } end modules ['util-zip'] = {
+ version = 1.001,
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- This module is mostly meant for relative simple zip and unzip tasks. We can read
+-- and write zip files but with limitations. Performance is quite good and it makes
+-- us independent of zip tools, which (for some reason) are not always installed.
+--
+-- This is an lmtx module and at some point will be lmtx only but for a while we
+-- keep some hybrid functionality.
+
+local type, tostring, tonumber = type, tostring, tonumber
+local sort = table.sort
+
+local find, format, sub, gsub = string.find, string.format, string.sub, string.gsub
+local osdate, ostime, osclock = os.date, os.time, os.clock
+local ioopen = io.open
+local loaddata, savedata = io.loaddata, io.savedata
+local filejoin, isdir, dirname, mkdirs = file.join, lfs.isdir, file.dirname, dir.mkdirs
+
+local files = utilities.files
+local openfile = files.open
+local closefile = files.close
+local readstring = files.readstring
+local readcardinal2 = files.readcardinal2le
+local readcardinal4 = files.readcardinal4le
+local setposition = files.setposition
+local getposition = files.getposition
+
+local band = bit32.band
+local rshift = bit32.rshift
+local lshift = bit32.lshift
+
+local decompress, expandsize, calculatecrc
+
+-- if flate then
+--
+-- decompress = flate.flate_decompress
+-- calculatecrc = flate.update_crc32
+--
+-- else
+
+ local zlibdecompress = zlib.decompress
+ local zlibexpandsize = zlib.expandsize
+ local zlibchecksum = zlib.crc32
+
+ decompress = function(source)
+ return zlibdecompress(source,-15) -- auto
+ end
+
+ expandsize = zlibexpandsize and function(source,targetsize)
+ return zlibexpandsize(source,targetsize,-15) -- auto
+ end or decompress
+
+ calculatecrc = function(buffer,initial)
+ return zlibchecksum(initial or 0,buffer)
+ end
+
+-- end
+
+local zipfiles = { }
+utilities.zipfiles = zipfiles
+
+local openzipfile, closezipfile, unzipfile, foundzipfile, getziphash, getziplist do
+
+ function openzipfile(name)
+ return {
+ name = name,
+ handle = openfile(name,0),
+ }
+ end
+
+ local function collect(z)
+ if not z.list then
+ local list = { }
+ local hash = { }
+ local position = 0
+ local index = 0
+ local handle = z.handle
+ while true do
+ setposition(handle,position)
+ local signature = readstring(handle,4)
+ if signature == "PK\3\4" then
+ -- [local file header 1]
+ -- [encryption header 1]
+ -- [file data 1]
+ -- [data descriptor 1]
+ local version = readcardinal2(handle)
+ local flag = readcardinal2(handle)
+ local method = readcardinal2(handle)
+ local filetime = readcardinal2(handle)
+ local filedate = readcardinal2(handle)
+ local crc32 = readcardinal4(handle)
+ local compressed = readcardinal4(handle)
+ local uncompressed = readcardinal4(handle)
+ local namelength = readcardinal2(handle)
+ local extralength = readcardinal2(handle)
+ local filename = readstring(handle,namelength)
+ local descriptor = band(flag,8) ~= 0
+ local encrypted = band(flag,1) ~= 0
+ local acceptable = method == 0 or method == 8
+ -- 30 bytes of header including the signature
+ local skipped = 0
+ local size = 0
+ if encrypted then
+ size = readcardinal2(handle)
+ skipbytes(size)
+ skipped = skipped + size + 2
+ skipbytes(8)
+ skipped = skipped + 8
+ size = readcardinal2(handle)
+ skipbytes(size)
+ skipped = skipped + size + 2
+ size = readcardinal4(handle)
+ skipbytes(size)
+ skipped = skipped + size + 4
+ size = readcardinal2(handle)
+ skipbytes(size)
+ skipped = skipped + size + 2
+ end
+ position = position + 30 + namelength + extralength + skipped
+ if descriptor then
+ setposition(handle,position + compressed)
+ crc32 = readcardinal4(handle)
+ compressed = readcardinal4(handle)
+ uncompressed = readcardinal4(handle)
+ end
+ if acceptable then
+ index = index + 1
+ local data = {
+ filename = filename,
+ index = index,
+ position = position,
+ method = method,
+ compressed = compressed,
+ uncompressed = uncompressed,
+ crc32 = crc32,
+ encrypted = encrypted,
+ }
+ hash[filename] = data
+ list[index] = data
+ else
+ -- maybe a warning when encrypted
+ end
+ position = position + compressed
+ else
+ break
+ end
+ z.list = list
+ z.hash = hash
+ end
+ end
+ end
+
+ function getziplist(z)
+ local list = z.list
+ if not list then
+ collect(z)
+ end
+ return z.list
+ end
+
+ function getziphash(z)
+ local hash = z.hash
+ if not hash then
+ collect(z)
+ end
+ return z.hash
+ end
+
+ function foundzipfile(z,name)
+ return getziphash(z)[name]
+ end
+
+ function closezipfile(z)
+ local f = z.handle
+ if f then
+ closefile(f)
+ z.handle = nil
+ end
+ end
+
+ function unzipfile(z,filename,check)
+ local hash = z.hash
+ if not hash then
+ hash = zipfiles.hash(z)
+ end
+ local data = hash[filename] -- normalize
+ if not data then
+ -- lower and cleanup
+ -- only name
+ end
+ if data then
+ local handle = z.handle
+ local position = data.position
+ local compressed = data.compressed
+ if compressed > 0 then
+ setposition(handle,position)
+ local result = readstring(handle,compressed)
+ if data.method == 8 then
+ if expandsize then
+ result = expandsize(result,data.uncompressed)
+ else
+ result = decompress(result)
+ end
+ end
+ if check and data.crc32 ~= calculatecrc(result) then
+ print("checksum mismatch")
+ return ""
+ end
+ return result
+ else
+ return ""
+ end
+ end
+ end
+
+ zipfiles.open = openzipfile
+ zipfiles.close = closezipfile
+ zipfiles.unzip = unzipfile
+ zipfiles.hash = getziphash
+ zipfiles.list = getziplist
+ zipfiles.found = foundzipfile
+
+end
+
+if xzip then -- flate then do
+
+ local writecardinal1 = files.writebyte
+ local writecardinal2 = files.writecardinal2le
+ local writecardinal4 = files.writecardinal4le
+
+ local logwriter = logs.writer
+
+ local globpattern = dir.globpattern
+-- local compress = flate.flate_compress
+-- local checksum = flate.update_crc32
+ local compress = xzip.compress
+ local checksum = xzip.crc32
+
+ -- local function fromdostime(dostime,dosdate)
+ -- return ostime {
+ -- year = (dosdate >> 9) + 1980, -- 25 .. 31
+ -- month = (dosdate >> 5) & 0x0F, -- 21 .. 24
+ -- day = (dosdate ) & 0x1F, -- 16 .. 20
+ -- hour = (dostime >> 11) , -- 11 .. 15
+ -- min = (dostime >> 5) & 0x3F, -- 5 .. 10
+ -- sec = (dostime ) & 0x1F, -- 0 .. 4
+ -- }
+ -- end
+ --
+ -- local function todostime(time)
+ -- local t = osdate("*t",time)
+ -- return
+ -- ((t.year - 1980) << 9) + (t.month << 5) + t.day,
+ -- (t.hour << 11) + (t.min << 5) + (t.sec >> 1)
+ -- end
+
+ local function fromdostime(dostime,dosdate)
+ return ostime {
+ year = rshift(dosdate, 9) + 1980, -- 25 .. 31
+ month = band(rshift(dosdate, 5), 0x0F), -- 21 .. 24
+ day = band( (dosdate ), 0x1F), -- 16 .. 20
+ hour = band(rshift(dostime,11) ), -- 11 .. 15
+ min = band(rshift(dostime, 5), 0x3F), -- 5 .. 10
+ sec = band( (dostime ), 0x1F), -- 0 .. 4
+ }
+ end
+
+ local function todostime(time)
+ local t = osdate("*t",time)
+ return
+ lshift(t.year - 1980, 9) + lshift(t.month,5) + t.day,
+ lshift(t.hour ,11) + lshift(t.min ,5) + rshift(t.sec,1)
+ end
+
+ local function openzip(filename,level,comment,verbose)
+ local f = ioopen(filename,"wb")
+ if f then
+ return {
+ filename = filename,
+ handle = f,
+ list = { },
+ level = tonumber(level) or 3,
+ comment = tostring(comment),
+ verbose = verbose,
+ uncompressed = 0,
+ compressed = 0,
+ }
+ end
+ end
+
+ local function writezip(z,name,data,level,time)
+ local f = z.handle
+ local list = z.list
+ local level = tonumber(level) or z.level or 3
+ local method = 8
+ local zipped = compress(data,level)
+ local checksum = checksum(data)
+ local verbose = z.verbose
+ --
+ if not zipped then
+ method = 0
+ zipped = data
+ end
+ --
+ local start = f:seek()
+ local compressed = #zipped
+ local uncompressed = #data
+ --
+ z.compressed = z.compressed + compressed
+ z.uncompressed = z.uncompressed + uncompressed
+ --
+ if verbose then
+ local pct = 100 * compressed/uncompressed
+ if pct >= 100 then
+ logwriter(format("%10i %s",uncompressed,name))
+ else
+ logwriter(format("%10i %02.1f %s",uncompressed,pct,name))
+ end
+ end
+ --
+ f:write("\x50\x4b\x03\x04") -- PK.. 0x04034b50
+ --
+ writecardinal2(f,0) -- minimum version
+ writecardinal2(f,0) -- flag
+ writecardinal2(f,method) -- method
+ writecardinal2(f,0) -- time
+ writecardinal2(f,0) -- date
+ writecardinal4(f,checksum) -- crc32
+ writecardinal4(f,compressed) -- compressed
+ writecardinal4(f,uncompressed) -- uncompressed
+ writecardinal2(f,#name) -- namelength
+ writecardinal2(f,0) -- extralength
+ --
+ f:write(name) -- name
+ f:write(zipped)
+ --
+ list[#list+1] = { #zipped, #data, name, checksum, start, time or 0 }
+ end
+
+ local function closezip(z)
+ local f = z.handle
+ local list = z.list
+ local comment = z.comment
+ local verbose = z.verbose
+ local count = #list
+ local start = f:seek()
+ --
+ for i=1,count do
+ local l = list[i]
+ local compressed = l[1]
+ local uncompressed = l[2]
+ local name = l[3]
+ local checksum = l[4]
+ local start = l[5]
+ local time = l[6]
+ local date, time = todostime(time)
+ f:write('\x50\x4b\x01\x02')
+ writecardinal2(f,0) -- version made by
+ writecardinal2(f,0) -- version needed to extract
+ writecardinal2(f,0) -- flags
+ writecardinal2(f,8) -- method
+ writecardinal2(f,time) -- time
+ writecardinal2(f,date) -- date
+ writecardinal4(f,checksum) -- crc32
+ writecardinal4(f,compressed) -- compressed
+ writecardinal4(f,uncompressed) -- uncompressed
+ writecardinal2(f,#name) -- namelength
+ writecardinal2(f,0) -- extralength
+ writecardinal2(f,0) -- commentlength
+ writecardinal2(f,0) -- nofdisks -- ?
+ writecardinal2(f,0) -- internal attr (type)
+ writecardinal4(f,0) -- external attr (mode)
+ writecardinal4(f,start) -- local offset
+ f:write(name) -- name
+ end
+ --
+ local stop = f:seek()
+ local size = stop - start
+ --
+ f:write('\x50\x4b\x05\x06')
+ writecardinal2(f,0) -- disk
+ writecardinal2(f,0) -- disks
+ writecardinal2(f,count) -- entries
+ writecardinal2(f,count) -- entries
+ writecardinal4(f,size) -- dir size
+ writecardinal4(f,start) -- dir offset
+ if type(comment) == "string" and comment ~= "" then
+ writecardinal2(f,#comment) -- comment length
+ f:write(comment) -- comemnt
+ else
+ writecardinal2(f,0)
+ end
+ --
+ if verbose then
+ local compressed = z.compressed
+ local uncompressed = z.uncompressed
+ local filename = z.filename
+ --
+ local pct = 100 * compressed/uncompressed
+ logwriter("")
+ if pct >= 100 then
+ logwriter(format("%10i %s",uncompressed,filename))
+ else
+ logwriter(format("%10i %02.1f %s",uncompressed,pct,filename))
+ end
+ end
+ --
+ f:close()
+ end
+
+ local function zipdir(zipname,path,level,verbose)
+ if type(zipname) == "table" then
+ verbose = zipname.verbose
+ level = zipname.level
+ path = zipname.path
+ zipname = zipname.zipname
+ end
+ if not zipname or zipname == "" then
+ return
+ end
+ if not path or path == "" then
+ path = "."
+ end
+ if not isdir(path) then
+ return
+ end
+ path = gsub(path,"\\+","/")
+ path = gsub(path,"/+","/")
+ local list = { }
+ local count = 0
+ globpattern(path,"",true,function(name,size,time)
+ count = count + 1
+ list[count] = { name, time }
+ end)
+ sort(list,function(a,b)
+ return a[1] < b[1]
+ end)
+ local zipf = openzip(zipname,level,comment,verbose)
+ if zipf then
+ local p = #path + 2
+ for i=1,count do
+ local li = list[i]
+ local name = li[1]
+ local time = li[2]
+ local data = loaddata(name)
+ local name = sub(name,p,#name)
+ writezip(zipf,name,data,level,time,verbose)
+ end
+ closezip(zipf)
+ end
+ end
+
+ local function unzipdir(zipname,path,verbose)
+ if type(zipname) == "table" then
+ verbose = zipname.verbose
+ path = zipname.path
+ zipname = zipname.zipname
+ end
+ if not zipname or zipname == "" then
+ return
+ end
+ if not path or path == "" then
+ path = "."
+ end
+ local z = openzipfile(zipname)
+ if z then
+ local list = getziplist(z)
+ if list then
+ local total = 0
+ local count = #list
+ local step = number.idiv(count,10)
+ local done = 0
+ local steps = verbose == "steps"
+ local time = steps and osclock()
+ for i=1,count do
+ local l = list[i]
+ local n = l.filename
+ local d = unzipfile(z,n) -- true for check
+ if d then
+ local p = filejoin(path,n)
+ if mkdirs(dirname(p)) then
+ if steps then
+ total = total + #d
+ done = done + 1
+ if done >= step then
+ done = 0
+ logwriter(format("%4i files of %4i done, %10i bytes, %0.3f seconds",i,count,total,osclock()-time))
+ end
+ elseif verbose then
+ logwriter(n)
+ end
+ savedata(p,d)
+ end
+ else
+ logwriter(format("problem with file %s",n))
+ end
+ end
+ if steps then
+ logwriter(format("%4i files of %4i done, %10i bytes, %0.3f seconds",count,count,total,osclock()-time))
+ end
+ closezipfile(z)
+ return true
+ else
+ closezipfile(z)
+ end
+ end
+ end
+
+ zipfiles.zipdir = zipdir
+ zipfiles.unzipdir = unzipdir
+
+end
+
+zipfiles.gunzipfile = gzip.load
+
+-- if flate then
+--
+-- local streams = utilities.streams
+-- local openfile = streams.open
+-- local closestream = streams.close
+-- local setposition = streams.setposition
+-- local getsize = streams.size
+-- local readcardinal4 = streams.readcardinal4le
+-- local getstring = streams.getstring
+-- local decompress = flate.gz_decompress
+--
+-- -- id1=1 id2=1 method=1 flags=1 mtime=4(le) extra=1 os=1
+-- -- flags:8 comment=...<nul> flags:4 name=...<nul> flags:2 extra=...<nul> flags:1 crc=2
+-- -- data:?
+-- -- crc=4 size=4
+--
+-- function zipfiles.gunzipfile(filename)
+-- local strm = openfile(filename)
+-- if strm then
+-- setposition(strm,getsize(strm) - 4 + 1)
+-- local size = readcardinal4(strm)
+-- local data = decompress(getstring(strm),size)
+-- closestream(strm)
+-- return data
+-- end
+-- end
+--
+-- elseif gzip then
+--
+-- local openfile = gzip.open
+--
+-- function zipfiles.gunzipfile(filename)
+-- local g = openfile(filename,"rb")
+-- if g then
+-- local d = g:read("*a")
+-- d:close()
+-- return d
+-- end
+-- end
+--
+-- end
+
+return zipfiles