summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--context/data/scite/cont-cs-scite.properties2
-rw-r--r--context/data/scite/cont-de-scite.properties2
-rw-r--r--context/data/scite/cont-fr-scite.properties2
-rw-r--r--context/data/scite/cont-it-scite.properties2
-rw-r--r--context/data/scite/cont-nl-scite.properties2
-rw-r--r--context/data/scite/cont-pe-scite.properties2
-rw-r--r--context/data/scite/cont-ro-scite.properties2
-rw-r--r--metapost/context/base/mp-mlib.mp11
-rw-r--r--scripts/context/lua/mtx-context.lua532
-rw-r--r--scripts/context/lua/mtx-fonts.lua2
-rw-r--r--scripts/context/lua/mtx-interface.lua2
-rw-r--r--scripts/context/lua/mtx-server-ctx-fonttest.lua14
-rw-r--r--scripts/context/lua/mtxrun.lua99
-rw-r--r--scripts/context/stubs/mswin/mtxrun.lua99
-rwxr-xr-xscripts/context/stubs/unix/mtxrun99
-rw-r--r--tex/context/base/anch-pgr.mkiv41
-rw-r--r--tex/context/base/attr-col.lua10
-rw-r--r--tex/context/base/attr-lay.lua2
-rw-r--r--tex/context/base/attr-lay.mkiv9
-rw-r--r--tex/context/base/back-exp.lua2
-rw-r--r--tex/context/base/back-ini.lua194
-rw-r--r--tex/context/base/back-pdf.mkiv12
-rw-r--r--tex/context/base/bibl-tra.lua2
-rw-r--r--tex/context/base/blob-ini.lua40
-rw-r--r--tex/context/base/buff-ver.lua12
-rw-r--r--tex/context/base/buff-ver.mkiv2
-rw-r--r--tex/context/base/chem-str.lua22
-rw-r--r--tex/context/base/cldf-int.lua12
-rw-r--r--tex/context/base/colo-ext.mkiv2
-rw-r--r--tex/context/base/colo-icc.lua6
-rw-r--r--tex/context/base/colo-ini.lua38
-rw-r--r--tex/context/base/colo-ini.mkiv20
-rw-r--r--tex/context/base/cont-new.mkii2
-rw-r--r--tex/context/base/cont-new.mkiv2
-rw-r--r--tex/context/base/context.mkii2
-rw-r--r--tex/context/base/context.mkiv30
-rw-r--r--tex/context/base/context.todo4
-rw-r--r--tex/context/base/core-con.lua4
-rw-r--r--tex/context/base/core-ini.mkiv2
-rw-r--r--tex/context/base/core-mis.mkiv66
-rw-r--r--tex/context/base/data-ctx.lua36
-rw-r--r--tex/context/base/data-res.lua38
-rw-r--r--tex/context/base/data-tex.lua12
-rw-r--r--tex/context/base/font-afm.lua912
-rw-r--r--tex/context/base/font-age.lua13
-rw-r--r--tex/context/base/font-agl.lua4
-rw-r--r--tex/context/base/font-aux.lua105
-rw-r--r--tex/context/base/font-chk.lua15
-rw-r--r--tex/context/base/font-cid.lua100
-rw-r--r--tex/context/base/font-clr.lua31
-rw-r--r--tex/context/base/font-col.lua8
-rw-r--r--tex/context/base/font-con.lua1175
-rw-r--r--tex/context/base/font-ctx.lua810
-rw-r--r--tex/context/base/font-def.lua336
-rw-r--r--tex/context/base/font-dum.lua354
-rw-r--r--tex/context/base/font-enc.lua42
-rw-r--r--tex/context/base/font-enh.lua235
-rw-r--r--tex/context/base/font-ext.lua401
-rw-r--r--tex/context/base/font-fbk.lua282
-rw-r--r--tex/context/base/font-gds.lua170
-rw-r--r--tex/context/base/font-ini.lua110
-rw-r--r--tex/context/base/font-ini.mkiv172
-rw-r--r--tex/context/base/font-log.lua77
-rw-r--r--tex/context/base/font-lua.lua23
-rw-r--r--tex/context/base/font-map.lua86
-rw-r--r--tex/context/base/font-mis.lua33
-rw-r--r--tex/context/base/font-ota.lua169
-rw-r--r--tex/context/base/font-otb.lua783
-rw-r--r--tex/context/base/font-otc.lua157
-rw-r--r--tex/context/base/font-otd.lua209
-rw-r--r--tex/context/base/font-otf.lua2066
-rw-r--r--tex/context/base/font-oth.lua56
-rw-r--r--tex/context/base/font-oti.lua92
-rw-r--r--tex/context/base/font-otn.lua1341
-rw-r--r--tex/context/base/font-otp.lua778
-rw-r--r--tex/context/base/font-ott.lua1353
-rw-r--r--tex/context/base/font-pat.lua4
-rw-r--r--tex/context/base/font-syn.lua7
-rw-r--r--tex/context/base/font-tfm.lua841
-rw-r--r--tex/context/base/font-vf.lua214
-rw-r--r--tex/context/base/font-xtx.lua100
-rw-r--r--tex/context/base/grph-inc.lua1
-rw-r--r--tex/context/base/java-imp-ans.mkiv33
-rw-r--r--tex/context/base/java-imp-fld.mkiv33
-rw-r--r--tex/context/base/java-ini.lua2
-rw-r--r--tex/context/base/l-dimen.lua22
-rw-r--r--tex/context/base/l-lpeg.lua2
-rw-r--r--tex/context/base/l-table.lua19
-rw-r--r--tex/context/base/lang-txt.lua45
-rw-r--r--tex/context/base/lpdf-ano.lua53
-rw-r--r--tex/context/base/lpdf-col.lua42
-rw-r--r--tex/context/base/lpdf-fld.lua715
-rw-r--r--tex/context/base/lpdf-fmt.lua20
-rw-r--r--tex/context/base/lpdf-ini.lua50
-rw-r--r--tex/context/base/lpdf-mis.lua56
-rw-r--r--tex/context/base/lpdf-ren.lua24
-rw-r--r--tex/context/base/lpdf-wid.lua472
-rw-r--r--tex/context/base/lpdf-xmp.lua13
-rw-r--r--tex/context/base/luat-mac.lua140
-rw-r--r--tex/context/base/lxml-tex.lua15
-rw-r--r--tex/context/base/m-barcodes.mkiv2
-rw-r--r--tex/context/base/m-chart.mkiv37
-rw-r--r--tex/context/base/m-fields.mkiv70
-rw-r--r--tex/context/base/m-newmat.tex269
-rw-r--r--tex/context/base/m-obsolete.tex2
-rw-r--r--tex/context/base/m-punk.mkiv58
-rw-r--r--tex/context/base/math-dim.lua4
-rw-r--r--tex/context/base/math-ext.lua65
-rw-r--r--tex/context/base/math-frc.mkii195
-rw-r--r--tex/context/base/math-frc.mkiv195
-rw-r--r--tex/context/base/math-ini.lua139
-rw-r--r--tex/context/base/math-ini.mkiv4
-rw-r--r--tex/context/base/math-noa.lua114
-rw-r--r--tex/context/base/math-vfu.lua240
-rw-r--r--tex/context/base/meta-imp-dum.mkiv42
-rw-r--r--tex/context/base/mlib-pps.lua35
-rw-r--r--tex/context/base/mlib-pps.mkiv8
-rw-r--r--tex/context/base/mult-aux.mkiv104
-rw-r--r--tex/context/base/mult-chk.lua22
-rw-r--r--tex/context/base/mult-de.mkii8
-rw-r--r--tex/context/base/mult-def.lua42
-rw-r--r--tex/context/base/mult-en.mkii8
-rw-r--r--tex/context/base/mult-fr.mkii8
-rw-r--r--tex/context/base/mult-it.mkii8
-rw-r--r--tex/context/base/mult-nl.mkii8
-rw-r--r--tex/context/base/mult-pe.mkii8
-rw-r--r--tex/context/base/mult-ro.mkii8
-rw-r--r--tex/context/base/mult-sys.mkiv35
-rw-r--r--tex/context/base/node-aux.lua2
-rw-r--r--tex/context/base/node-dum.lua140
-rw-r--r--tex/context/base/node-fnt.lua77
-rw-r--r--tex/context/base/node-ini.mkiv2
-rw-r--r--tex/context/base/node-inj.lua40
-rw-r--r--tex/context/base/node-ref.lua35
-rw-r--r--tex/context/base/node-rul.lua52
-rw-r--r--tex/context/base/node-rul.mkiv145
-rw-r--r--tex/context/base/node-spl.lua52
-rw-r--r--tex/context/base/node-tra.lua34
-rw-r--r--tex/context/base/pack-lyr.mkiv23
-rw-r--r--tex/context/base/pack-mis.mkvi84
-rw-r--r--tex/context/base/pack-rul.mkiv278
-rw-r--r--tex/context/base/page-bck.mkiv2
-rw-r--r--tex/context/base/page-flt.lua2
-rw-r--r--tex/context/base/page-imp.mkii360
-rw-r--r--tex/context/base/page-imp.mkiv365
-rw-r--r--tex/context/base/page-lay.mkiv55
-rw-r--r--tex/context/base/page-run.mkiv4
-rw-r--r--tex/context/base/page-set.mkiv27
-rw-r--r--tex/context/base/ppchtex.mkiv28
-rw-r--r--tex/context/base/s-fnt-10.mkiv103
-rw-r--r--tex/context/base/s-fnt-23.mkiv35
-rw-r--r--tex/context/base/s-fnt-25.mkiv13
-rw-r--r--tex/context/base/s-fnt-29.mkiv6
-rw-r--r--tex/context/base/scrn-bar.mkiv400
-rw-r--r--tex/context/base/scrn-bar.mkvi405
-rw-r--r--tex/context/base/scrn-but.lua19
-rw-r--r--tex/context/base/scrn-but.mkiv127
-rw-r--r--tex/context/base/scrn-but.mkvi984
-rw-r--r--tex/context/base/scrn-fld.lua76
-rw-r--r--tex/context/base/scrn-fld.mkiv687
-rw-r--r--tex/context/base/scrn-fld.mkvi965
-rw-r--r--tex/context/base/scrn-hlp.lua120
-rw-r--r--tex/context/base/scrn-hlp.mkiv179
-rw-r--r--tex/context/base/scrn-hlp.mkvi162
-rw-r--r--tex/context/base/scrn-ini.lua21
-rw-r--r--tex/context/base/scrn-ini.mkvi178
-rw-r--r--tex/context/base/scrn-int.lua114
-rw-r--r--tex/context/base/scrn-int.mkiv613
-rw-r--r--tex/context/base/scrn-men.mkiv629
-rw-r--r--tex/context/base/scrn-nav.mkiv258
-rw-r--r--tex/context/base/scrn-pag.lua27
-rw-r--r--tex/context/base/scrn-pag.mkvi180
-rw-r--r--tex/context/base/scrn-ref.lua65
-rw-r--r--tex/context/base/scrn-ref.mkvi90
-rw-r--r--tex/context/base/scrn-wid.lua194
-rw-r--r--tex/context/base/scrn-wid.mkvi700
-rw-r--r--tex/context/base/scrp-cjk.lua27
-rw-r--r--tex/context/base/scrp-ini.lua23
-rw-r--r--tex/context/base/sort-ini.lua4
-rw-r--r--tex/context/base/spac-ali.mkiv86
-rw-r--r--tex/context/base/spac-grd.mkiv19
-rw-r--r--tex/context/base/spac-hor.mkiv4
-rw-r--r--tex/context/base/spac-ver.mkiv246
-rw-r--r--tex/context/base/status-files.pdfbin23456 -> 23535 bytes
-rw-r--r--tex/context/base/strc-blk.lua5
-rw-r--r--tex/context/base/strc-des.mkiv2
-rw-r--r--tex/context/base/strc-doc.mkiv2
-rw-r--r--tex/context/base/strc-itm.mkiv46
-rw-r--r--tex/context/base/strc-lst.mkiv8
-rw-r--r--tex/context/base/strc-num.lua4
-rw-r--r--tex/context/base/strc-ref.lua145
-rw-r--r--tex/context/base/strc-ref.mkiv197
-rw-r--r--tex/context/base/strc-sec.mkiv8
-rw-r--r--tex/context/base/strc-syn.mkiv6
-rw-r--r--tex/context/base/supp-fil.lua2
-rw-r--r--tex/context/base/symb-ini.lua24
-rw-r--r--tex/context/base/syst-aux.mkiv43
-rw-r--r--tex/context/base/tabl-ntb.mkiv1
-rw-r--r--tex/context/base/trac-tex.lua29
-rw-r--r--tex/context/base/type-ini.mkiv6
-rw-r--r--tex/context/base/type-otf.mkiv2
-rw-r--r--tex/context/base/typo-brk.lua6
-rw-r--r--tex/context/base/typo-brk.mkiv2
-rw-r--r--tex/context/base/typo-cap.lua6
-rw-r--r--tex/context/base/typo-dig.lua10
-rw-r--r--tex/context/base/typo-dir.lua6
-rw-r--r--tex/context/base/typo-krn.lua7
-rw-r--r--tex/context/base/typo-mar.lua15
-rw-r--r--tex/context/base/typo-mar.mkiv8
-rw-r--r--tex/context/base/typo-rep.lua40
-rw-r--r--tex/context/base/typo-rep.mkiv2
-rw-r--r--tex/context/base/typo-spa.lua5
-rw-r--r--tex/context/base/util-mrg.lua10
-rw-r--r--tex/context/base/util-prs.lua7
-rw-r--r--tex/context/base/util-tab.lua24
-rw-r--r--tex/context/base/x-cals.lua6
-rw-r--r--tex/context/base/x-css.lua12
-rw-r--r--tex/context/base/x-mathml.lua2
-rw-r--r--tex/context/fonts/asana-math.lfg33
-rw-r--r--tex/context/fonts/cambria-math.lfg6
-rw-r--r--tex/context/fonts/lm-math.lfg10
-rw-r--r--tex/context/fonts/lucida-math.lfg4
-rw-r--r--tex/context/fonts/xits-math.lfg8
-rw-r--r--tex/context/interface/cont-cs.xml4
-rw-r--r--tex/context/interface/cont-de.xml4
-rw-r--r--tex/context/interface/cont-fr.xml4
-rw-r--r--tex/context/interface/cont-it.xml4
-rw-r--r--tex/context/interface/cont-nl.xml4
-rw-r--r--tex/context/interface/cont-pe.xml4
-rw-r--r--tex/context/interface/cont-ro.xml4
-rw-r--r--tex/context/interface/keys-cs.xml8
-rw-r--r--tex/context/interface/keys-de.xml8
-rw-r--r--tex/context/interface/keys-en.xml8
-rw-r--r--tex/context/interface/keys-fr.xml8
-rw-r--r--tex/context/interface/keys-it.xml8
-rw-r--r--tex/context/interface/keys-nl.xml8
-rw-r--r--tex/context/interface/keys-pe.xml8
-rw-r--r--tex/context/interface/keys-ro.xml8
-rw-r--r--tex/generic/context/luatex-basics-gen.lua (renamed from tex/context/base/luat-dum.lua)31
-rw-r--r--tex/generic/context/luatex-basics-nod.lua95
-rw-r--r--tex/generic/context/luatex-fonts-cbk.lua68
-rw-r--r--tex/generic/context/luatex-fonts-def.lua97
-rw-r--r--tex/generic/context/luatex-fonts-demo-vf-1.lua14
-rw-r--r--tex/generic/context/luatex-fonts-enc.lua28
-rw-r--r--tex/generic/context/luatex-fonts-ext.lua276
-rw-r--r--tex/generic/context/luatex-fonts-lua.lua33
-rw-r--r--tex/generic/context/luatex-fonts-merged.lua13123
-rw-r--r--tex/generic/context/luatex-fonts-syn.lua83
-rw-r--r--tex/generic/context/luatex-fonts-tfm.lua38
-rw-r--r--tex/generic/context/luatex-fonts.lua132
250 files changed, 20827 insertions, 22263 deletions
diff --git a/context/data/scite/cont-cs-scite.properties b/context/data/scite/cont-cs-scite.properties
index ddf42aacd..5c9cc3354 100644
--- a/context/data/scite/cont-cs-scite.properties
+++ b/context/data/scite/cont-cs-scite.properties
@@ -1 +1 @@
-keywordclass.macros.context.cs=CAP Cap Caps MESIC Rimskecislice SLOVA SLOVO Slova Slovo VSEDNIDEN Znak Znaky aktualnicislonadpisu aktualnidatum appendix barva bilemisto bublinkovanapoveda bypassblocks cap cernalinka cernelinky chapter chem cisla cislonadpisu citace citovat completecombinedlist completelistoffloats completelistofsorts completelistofsynonyms completeregister coupledregister crlf datum definebodyfontDEF definebodyfontREF definedfont definefontfeature definefonthandling definetype definetypeface definuj definujbarvu definujblok definujbloksekce definujbuffer definujfont definujformatodkazu definujinterakcnimenu definujinterakcnimenu definujkombinovanyseznam definujkonverzi definujlogo definujnadpis definujobrazeksymbol definujodkaz definujodsazovani definujodstavce definujopis definujoramovani definujoramovanytext definujpaletu definujplvouciobjekt definujpodpole definujpole definujpopis definujpopisek definujprekryv definujpreskok definujprofil definujprogram definujprostredizakladnihofontu definujrejstrik definujsablonutabulky definujsekci definujseznam definujseznamodkazu definujskupinubarev definujstartstop definujsymbol definujsynonumumfontu definujsynonyma definujtabelaci definujtext definujtrideni definujupravu definujvelikostpapiru definujverzi definujvycet definujvystup definujzakladnifont definujzasobnikpoli definujznaceni description dodrzujprofil dodrzujverzi dodrzujverziprofilu dvoustrannypapir emptylines enumeration externiobraz footnotetext forceblocks framedtext hl hlavnijazyk indentation ininner inouter instalacejazyka interakcnilista interakcnitlacitka jazyk jdidolu jdina jdinabox klonujpole komentar konvertujcislo kopirujpole korekcebilehomista labeling listsymbol loadsorts loadsynonyms mapfontsize marginalnilinka marginalnitext matematika mediaeval meritko mesic mezera mrizka nadpis nadruhyokraj name naokraj nastavbarvu nastavbarvy nastavbilamista nastavblok nastavbloksekce nastavbuffer nastavcernelinky nastavcislonadpisu nastavcislostrany nastavcislovani nastavcislovaniodstavcu nastavcislovaniradku nastavcislovanistran nastavcitaci nastavdefinicipoznamekpodcarou nastavdeleniplvoucichobjektu nastavdelitko nastavdolnitexty nastavexterniobrazy nastavhorejsek nastavhornitexty nastavinterakci nastavinterakcnilistu nastavinterakcnimenu nastavinterakcniobrazovku nastavjazyk nastavkapitalky nastavkombinovanyseznam nastavkomentar nastavlegendu nastavmarginalie nastavmarginalniblok nastavmarginalnilinky nastavmeziradkovoumezeru nastavnadpis nastavnadpisy nastavodkazovani nastavodsazeni nastavodsazovani nastavodstavce nastavopis nastavoramovanetexty nastavoramovani nastavorez nastavotoceni nastavpaletu nastavplvouciobjekt nastavplvouciobjekty nastavpodcislostrany nastavpodtrzeni nastavpole nastavpolozky nastavpopisek nastavpopisky nastavpopisy nastavpozadi nastavpozadi nastavpoznamkypodcarou nastavprechodstrany nastavpreskok nastavprofily nastavprogramy nastavprostredizakladnihofontu nastavpublikace nastavradkovani nastavradky nastavrastr nastavrejstrik nastavrovnice nastavsadusymbolu nastavsekci nastavseznam nastavseznamodkazu nastavsirkucary nastavsloupce nastavspodek nastavspojeni nastavsynchronizaci nastavsynchronizacnilistu nastavsynonyma nastavsystem nastavtab nastavtabelaci nastavtabulky nastavtenkelinky nastavtext nastavtexthlavicky nastavtextovelinky nastavtextpopisku nastavtexttexty nastavtextyupati nastavtextyzahlavi nastavtlacitka nastavtoleranci nastavtrideni nastavtype nastavumisteniprotejsku nastavumistovani nastavupati nastavupravu nastavurl nastavusporadani nastavvelikostpapiru nastavverze nastavvsechnapole nastavvycty nastavvyplnovelinky nastavvyplnoveradky nastavvystup nastavvzhled nastavzahlavi nastavzakladnifont nastavzarovnani nastavznaceni nastavzuzeni nastrane nejakyradek nekde nextsection nivy nizky nocap nop obrazovka odkaz odkaz odkaznadatum odkaznastranu odkaznatext odsazovani okr opis opissoubor oramovani oref orez otocit overbar overbars overstrike overstrikes oznacverzi paragraph parovastrana part pis placefloat placelistoffloats placelistofsorts placelistofsynonyms placereferencelist pol pole polozka polozky popisky porovnejpaletu porovnejskupinubarev pozadi pozice poznamka poznamkapodcarou pref prelozit premistinamrizku prepninazakladnifont preskoc prizpusobivepole prizpusobvzhled program propojeneznaceni propojenydokument propojenyrejstrik publikace ran ref register reservefloat reset resettextcontent resetznaceni rimskecislice rozdelplvouciobjekt rozpojeneznaceni roztazene schovejbloky section sedabarva seeregister settextcontent setupfonthandling setupfontsynonym setupforms setupinterlinespace2 setupitemgroup setuplistalternative setuppaper setupstrut sloupec slovovpravo sort spodek stanovcharakteristickuseznamu stanovcislonadpisu startalignment startbarva startbuffer startbuffer startcitace startcolumns startcombination startdescription startdocument startenumeration startfakt startfigure startfloattext startformula startframedtext starthiding startinteraktivnimenu startitemgroup startkomentar startkomponenta startlegend startline startlinecorrection startlinenumbering startlines startlocal startlocalenvironment startlocalfootnotes startmakeup startmarginalnilinka startmarginblock startnamemakeup startnarrower startopposite startoverlay startoverview startparagraph startpositioning startpostponing startpozadi startprodukt startprofile startprojekt startprostredi startregister startsymbolset startsynchronization starttable starttables starttabulate starttextovalinka starttyping startunpacked startverze startzhustene stopalignment stopbarva stopbuffer stopbuffer stopcitace stopcolumns stopcombination stopdescription stopdocument stopenumeration stopfakt stopfigure stopfloattext stopformula stopframedtext stophiding stopinteraktivnimenu stopitemgroup stopkomentar stopkomponenta stoplegend stopline stoplinecorrection stoplinenumbering stoplines stoplocal stoplocalenvironment stoplocalfootnotes stopmakeup stopmarginalnilinka stopmarginblock stopnamemakeup stopnarrower stopopposite stopoverlay stopoverview stopparagraph stoppositioning stoppostponing stoppozadi stopprodukt stopprofile stopprojekt stopprostredi stopsymbolset stopsynchronization stoptable stoptables stoptabulate stoptextovalinka stoptyping stopunpacked stopverze stopzhustene strana sub subject subsection subsubject subsubsection subsubsubject sym symbol synchronizacnilista synchronizovat synonym tab tecky tenkalinka tenkelinky tex texthlavicky textovalinka textpopisku title tlacitko tref tvrdemezery typebuffer typstrany ukazbarvu ukazexterniobrazy ukazmrizku ukaznastaveni ukazpaletu ukazpodpery ukazpole ukazpostredizakladnihofontu ukazramecek ukazsadusymbolu ukazskupinubarev ukazupravu ukazvytisk ukazvzhled ukazzakladnifont umistikombinovanyseznam umistikombinovanyseznam umistilegendu umistiloga umistilokalnipoznamkypodcarou umistinadsebe umistinamrizku umistipodrovnici umistipoznamkypodcarou umistirejstrik umistirejstrik umistirovnici umistiseznam umistivedlesebe umistizalozky underbar underbars usedirectory usetypescript usetypescriptfile uzijURL uzijbloky uzijexternidokument uzijexterniobraz uzijexternisoubor uzijexternisoubory uzijexternizvuk uzijkodovani uzijmodul uzijodkazy uzijprikazy uzijspeciality uzijsymbol verze vl vlasovalinka vlevo vpravo vradku vsedniden vyberbloky vyberpapir vyberverzi vyplnenytext vyplnovelinky vyplnovepole vyplnovyradek vysoky zablokujinterakcnimenu zachovejbloky zadnamezera zadnebilemisto zadnedalsibloky zadnedalsisoubory zadnehorniadolniradky zadneodsazovani zadnezahlaviaupati zadneznaceni zadnyseznam zalozka zapisdorejstriku zapisdoseznamu zapisdoseznamuodkazu zapismeziseznam zaramovani zarovnanonastred zarovnanovlevo zarovnanovpravo zasobnikpoli zaznamovepole zhustene ziskejbuffer ziskejznaceni zlomek znaceni znak znaky zpracujbloky zpracujstranu zrcadlit zref \ No newline at end of file
+keywordclass.macros.context.cs=CAP Cap Caps MESIC Rimskecislice SLOVA SLOVO Slova Slovo VSEDNIDEN Znak Znaky aktualnicislonadpisu aktualnidatum appendix barva bilemisto bublinkovanapoveda bypassblocks cap cernalinka cernelinky chapter chem cisla cislonadpisu citace citovat comment completecombinedlist completelistoffloats completelistofsorts completelistofsynonyms completeregister coupledregister crlf datum definebodyfontDEF definebodyfontREF definedfont definefontfeature definefonthandling definetype definetypeface definuj definujbarvu definujblok definujbloksekce definujbuffer definujfont definujformatodkazu definujinterakcnimenu definujinterakcnimenu definujkombinovanyseznam definujkonverzi definujlogo definujnadpis definujobrazeksymbol definujodkaz definujodsazovani definujodstavce definujopis definujoramovani definujoramovanytext definujpaletu definujplvouciobjekt definujpodpole definujpole definujpopis definujpopisek definujprekryv definujpreskok definujprofil definujprogram definujprostredizakladnihofontu definujrejstrik definujsablonutabulky definujsekci definujseznam definujseznamodkazu definujskupinubarev definujstartstop definujsymbol definujsynonumumfontu definujsynonyma definujtabelaci definujtext definujtrideni definujupravu definujvelikostpapiru definujverzi definujvycet definujvystup definujzakladnifont definujzasobnikpoli definujznaceni description dodrzujprofil dodrzujverzi dodrzujverziprofilu dvoustrannypapir emptylines enumeration externiobraz footnotetext forceblocks framedtext hl hlavnijazyk indentation ininner inouter instalacejazyka interakcnilista interakcnitlacitka jazyk jdidolu jdina jdinabox klonujpole konvertujcislo kopirujpole korekcebilehomista labeling listsymbol loadsorts loadsynonyms mapfontsize marginalnilinka marginalnitext matematika mediaeval meritko mesic mezera mrizka nadpis nadruhyokraj name naokraj nastavbarvu nastavbarvy nastavbilamista nastavblok nastavbloksekce nastavbuffer nastavcernelinky nastavcislonadpisu nastavcislostrany nastavcislovani nastavcislovaniodstavcu nastavcislovaniradku nastavcislovanistran nastavcitaci nastavdefinicipoznamekpodcarou nastavdeleniplvoucichobjektu nastavdelitko nastavdolnitexty nastavexterniobrazy nastavhorejsek nastavhornitexty nastavinterakci nastavinterakcnilistu nastavinterakcnimenu nastavinterakcniobrazovku nastavjazyk nastavkapitalky nastavkombinovanyseznam nastavkomentar nastavlegendu nastavmarginalie nastavmarginalniblok nastavmarginalnilinky nastavmeziradkovoumezeru nastavnadpis nastavnadpisy nastavodkazovani nastavodsazeni nastavodsazovani nastavodstavce nastavopis nastavoramovanetexty nastavoramovani nastavorez nastavotoceni nastavpaletu nastavplvouciobjekt nastavplvouciobjekty nastavpodcislostrany nastavpodtrzeni nastavpole nastavpolozky nastavpopisek nastavpopisky nastavpopisy nastavpozadi nastavpozadi nastavpoznamkypodcarou nastavprechodstrany nastavpreskok nastavprofily nastavprogramy nastavprostredizakladnihofontu nastavpublikace nastavradkovani nastavradky nastavrastr nastavrejstrik nastavrovnice nastavsadusymbolu nastavsekci nastavseznam nastavseznamodkazu nastavsirkucary nastavsloupce nastavspodek nastavspojeni nastavsynchronizaci nastavsynchronizacnilistu nastavsynonyma nastavsystem nastavtab nastavtabelaci nastavtabulky nastavtenkelinky nastavtext nastavtexthlavicky nastavtextovelinky nastavtextpopisku nastavtexttexty nastavtextyupati nastavtextyzahlavi nastavtlacitka nastavtoleranci nastavtrideni nastavtype nastavumisteniprotejsku nastavumistovani nastavupati nastavupravu nastavurl nastavusporadani nastavvelikostpapiru nastavverze nastavvsechnapole nastavvycty nastavvyplnovelinky nastavvyplnoveradky nastavvystup nastavvzhled nastavzahlavi nastavzakladnifont nastavzarovnani nastavznaceni nastavzuzeni nastrane nejakyradek nekde nextsection nivy nizky nocap nop obrazovka odkaz odkaz odkaznadatum odkaznastranu odkaznatext odsazovani okr opis opissoubor oramovani oref orez otocit overbar overbars overstrike overstrikes oznacverzi paragraph parovastrana part pis placefloat placelistoffloats placelistofsorts placelistofsynonyms placereferencelist pol pole polozka polozky popisky porovnejpaletu porovnejskupinubarev pozadi pozice poznamka poznamkapodcarou pref prelozit premistinamrizku prepninazakladnifont preskoc prizpusobivepole prizpusobvzhled program propojeneznaceni propojenydokument propojenyrejstrik publikace ran ref register reservefloat reset resettextcontent resetznaceni rimskecislice rozdelplvouciobjekt rozpojeneznaceni roztazene schovejbloky section sedabarva seeregister settextcontent setupfonthandling setupfontsynonym setupforms setupinterlinespace2 setupitemgroup setuplistalternative setuppaper setupstrut sloupec slovovpravo sort spodek stanovcharakteristickuseznamu stanovcislonadpisu startalignment startbarva startbuffer startbuffer startcitace startcolumns startcombination startcomment startdescription startdocument startenumeration startfakt startfigure startfloattext startformula startframedtext starthiding startinteraktivnimenu startitemgroup startkomponenta startlegend startline startlinecorrection startlinenumbering startlines startlocal startlocalenvironment startlocalfootnotes startmakeup startmarginalnilinka startmarginblock startnamemakeup startnarrower startopposite startoverlay startoverview startparagraph startpositioning startpostponing startpozadi startprodukt startprofile startprojekt startprostredi startregister startsymbolset startsynchronization starttable starttables starttabulate starttextovalinka starttyping startunpacked startverze startzhustene stopalignment stopbarva stopbuffer stopbuffer stopcitace stopcolumns stopcombination stopcomment stopdescription stopdocument stopenumeration stopfakt stopfigure stopfloattext stopformula stopframedtext stophiding stopinteraktivnimenu stopitemgroup stopkomponenta stoplegend stopline stoplinecorrection stoplinenumbering stoplines stoplocal stoplocalenvironment stoplocalfootnotes stopmakeup stopmarginalnilinka stopmarginblock stopnamemakeup stopnarrower stopopposite stopoverlay stopoverview stopparagraph stoppositioning stoppostponing stoppozadi stopprodukt stopprofile stopprojekt stopprostredi stopsymbolset stopsynchronization stoptable stoptables stoptabulate stoptextovalinka stoptyping stopunpacked stopverze stopzhustene strana sub subject subsection subsubject subsubsection subsubsubject sym symbol synchronizacnilista synchronizovat synonym tab tecky tenkalinka tenkelinky tex texthlavicky textovalinka textpopisku title tlacitko tref tvrdemezery typebuffer typstrany ukazbarvu ukazexterniobrazy ukazmrizku ukaznastaveni ukazpaletu ukazpodpery ukazpole ukazpostredizakladnihofontu ukazramecek ukazsadusymbolu ukazskupinubarev ukazupravu ukazvytisk ukazvzhled ukazzakladnifont umistikombinovanyseznam umistikombinovanyseznam umistilegendu umistiloga umistilokalnipoznamkypodcarou umistinadsebe umistinamrizku umistipodrovnici umistipoznamkypodcarou umistirejstrik umistirejstrik umistirovnici umistiseznam umistivedlesebe umistizalozky underbar underbars usedirectory usetypescript usetypescriptfile uzijURL uzijbloky uzijexternidokument uzijexterniobraz uzijexternisoubor uzijexternisoubory uzijexternizvuk uzijkodovani uzijmodul uzijodkazy uzijprikazy uzijspeciality uzijsymbol verze vl vlasovalinka vlevo vpravo vradku vsedniden vyberbloky vyberpapir vyberverzi vyplnenytext vyplnovelinky vyplnovepole vyplnovyradek vysoky zablokujinterakcnimenu zachovejbloky zadnamezera zadnebilemisto zadnedalsibloky zadnedalsisoubory zadnehorniadolniradky zadneodsazovani zadnezahlaviaupati zadneznaceni zadnyseznam zalozka zapisdorejstriku zapisdoseznamu zapisdoseznamuodkazu zapismeziseznam zaramovani zarovnanonastred zarovnanovlevo zarovnanovpravo zasobnikpoli zaznamovepole zhustene ziskejbuffer ziskejznaceni zlomek znaceni znak znaky zpracujbloky zpracujstranu zrcadlit zref \ No newline at end of file
diff --git a/context/data/scite/cont-de-scite.properties b/context/data/scite/cont-de-scite.properties
index b0e05b91a..249fc6a59 100644
--- a/context/data/scite/cont-de-scite.properties
+++ b/context/data/scite/cont-de-scite.properties
@@ -1 +1 @@
-keywordclass.macros.context.de=Buchstabe Buchstaben CAP Cap Caps MONAT Roemischezahlen WOCHENTAG WOERTER WORT Woerter Wort amgitterausrichten amgitterneuausrichten appendix aufseite ausfuellfeld ausfuelltext ausschnitt bearbeitebloecke bearbeiteseite behaltebloecke bei benutzekodierung benutzespezielles beschrifteversion beschriftung bestimmekopfnummer bestimmelistencharakeristika bildschirm blanko bookmark bruch buchstabe buchstaben but bypassblocks cap chapter chem completecombinedlist completelistoffloats completelistofsorts completelistofsynonyms completeregister coupledregister crlf datum definebodyfontDEF definebodyfontREF definedfont definefontfeature definefonthandling defineoutput defineschriftsynonym definetype definetypeface definiereabbsymbol definiereabsaetze definiereabschnitt definiereabschnittsblock definierebeschreibung definierebeschreibungen definierebeschriftung definiereblanko definiereblock definiereeinzug definierefarbe definierefarbengruppe definierefeld definierefeldstapel definierefliesstext definierefliesstextumgebung definieregleitobjekt definiereinteraktionsmenue definiereinteraktionsmenue definierekonversion definierelabel definiereliste definierelogo definieren definierenummerierung definiereoverlay definierepalette definierepapierformat definiereprofil definiereprogramme definierepuffer definierereferenz definierereferenzformat definierereferenzliste definiereregister definiereschrift definieresortieren definierestartstop definieresubfeld definieresymbol definieresynonyme definieretabellenvorlage definieretabulator definieretext definieretippen definiereueberschrift definiereumbruch definiereumrahmt definiereumrahmtertext definiereversion definierezusammengestellteliste description doppelseite doppelseitigespapier drehen duennelinie duennerumriss einezeile einziehen emptylines entknuepfebeschriftung enumeration externeabbildung farbe feld feldstapel festesspatium folgeprofil folgeprofilversion folgeversion footnotetext forceblocks format framedtext fussnote gefuelltesrechteck gefuelltezeile gestreckt gitter graufarbe haarlinie hauptsprache heutigesdatum heutigeskopfnummer hintergrund hl hoch holebeschriftung holepuffer imlinken imrechten imumriss in inaktiviereinteraktionsmenue inanderermarginale indentation ininner inmarginalie inouter installieresprache interaktionsbalken interaktionsknopfe inzeile irgendwo its keinebeschriftung keinebloeckemehr keinedateienmehr keinekopfundfusszeilen keineliste keinspatium keinzeilenobenundunten keinzwischenraum kleinerdurchschuss klonierefeld knopf kommentar konvertierezahl kopf kopfnummer kopierefeld korrigierezwischenraum labeling labels labeltext linksbuendig listsymbol loadsorts loadsynonyms mapfontsize mar marginallinie marginaltext mathematik mediaeval monat nachunten name nextsection nichteinziehen nocap nop notiz overbar overbars overstrike overstrikes paragraph part passelayoutan passendfeld placefloat placelistoffloats placelistofsorts placelistofsynonyms placereferencelist platzierebookmarks platziereformel platzierefussnoten platzierelegende platziereliste platzierelogo platzierelokalefussnoten platzierenebeneinander platziereregister platziereregister platziereuntereinander platziereunterformel platzierezusammengestellteliste platzierezusammengestellteliste pos position posten programm publikation punkt ran rechteck rechtecke rechtsbuendig ref referenz register registrierefelder reservefloat resettextcontent roemischezahlen ruecksetzten ruecksetztenbeschriftung schreibezumregister schreibezurliste schreibezurreferenzliste schreibezwischenliste section seeregister seite seitenreferenz seitentyp settext setupfonthandling setupfontsynonym setupforms setupinterlinespace2 setupitemgroup setuplistalternative setuppaper setupstrut showsymbolset sort spalte spatium spiegeln sprache startalignment startbuffer startbuffer startcolumns startcombination startdescription startdocument startenumeration startfarbe startfigure startfloattext startformula startframedtext startgeg starthiding starthintergrund startinteraktionsmenue startitemgroup startkleinerdurchschuss startkommentar startkomponente startlegend startline startlinecorrection startlinenumbering startlines startlocal startlocalenvironment startlocalfootnotes startmakeup startmarginallinie startmarginblock startnamemakeup startnarrower startopposite startoverlay startoverview startparagraph startpositioning startpostponing startprodukt startprofile startprojekt startregister startsymbolset startsynchronization starttable starttables starttabulate starttextlinie starttyping startumgebung startunpacked startversion startzitat stelleabsaetzeein stelleabsatznummerierungein stelleabschnittein stelleabschnittsblockein stelleanordnenein stelleausgabeein stelleausrichtungein stelleausschnittein stellebeschreibungein stellebeschriftungein stellebilderunterschriftein stellebildunterschriftein stellebindestrichein stelleblankoein stelleblockein stelledrehenein stelleduennerumrissein stelleeinziehenein stelleeinzuegein stelleengerein stelleexterneabbildungenein stellefarbeein stellefarbenein stellefeldein stellefelderin stellefliesstextein stellefliesstextumgebungein stelleformelnein stellefussnotendefinitionein stellefussnotenein stellefusszeileein stellefusszeilentextein stellegefuelltesrechteckein stellegefuelltezeileein stellegegenueberplatzierenein stellegleitobjekteein stellegleitobjektein stellehintergruendeein stellehintergrundein stelleinmarginalieein stelleinteraktionein stelleinteraktionsbalkenein stelleinteraktionsbildschirmein stelleinteraktionsmenueein stelleknopfein stellekombinationein stellekommentarein stellekopfzahlein stellekopfzeileein stellekopfzeilentextein stellelabeltextein stellelayoutein stellelegendeein stellelinienbreiteein stellelisteein stellemarginalblockein stellemarginallinieein stellenobenein stellenummerierungein stellepaletteein stellepapierformatein stelleplatziegeteiltegleitobjekt stellepositionierenein stellepostenein stelleprofilein stelleprogrammein stellepublikationein stellepufferein stellerasterein stellerechteckein stellereferenzierenein stellereferenzlisteein stelleregisterein stelleseitennummerein stelleseitennummeriernungein stelleseitenuebergangein stellesortierenein stellespaltenein stellespatiumein stellespracheein stellesymbolsetein stellesynchronisationein stellesynchronisationsbalkenein stellesynonymein stellesystemein stelletabein stelletabellenein stelletabulatorein stelletextein stelletextobenein stelletexttexteein stelletextumrissein stelletextuntenein stelletipein stelletippenein stelletoleranzein stelleueberschriftein stelleueberschriftenein stelleueberschrifttextein stelleumbruchein stelleumrahmtein stelleumrahmtetexteein stelleuntenein stelleunterseitennummerein stelleunterstreichenein stelleurlein stelleversalienein stelleversionein stellezeilenabstandein stellezeilenein stellezeilennumerierungein stellezitierenein stellezusammengestelltelisteein stellezwischenraumein stopalignment stopbuffer stopbuffer stopcolumns stopcombination stopdescription stopdocument stopenumeration stopfarbe stopfigure stopfloattext stopformula stopframedtext stopgeg stophiding stophintergrund stopinteraktionsmenue stopitemgroup stopkleinerdurchschuss stopkommentar stopkomponente stoplegend stopline stoplinecorrection stoplinenumbering stoplines stoplocal stoplocalenvironment stoplocalfootnotes stopmakeup stopmarginallinie stopmarginblock stopnamemakeup stopnarrower stopopposite stopoverlay stopoverview stopparagraph stoppositioning stoppostponing stopprodukt stopprofile stopprojekt stopsymbolset stopsynchronization stoptable stoptables stoptabulate stoptextlinie stoptyping stopumgebung stopunpacked stopversion stopzitat sub subject subsection subsubject subsubsection subsubsubject sym symbol synchronisationsbalken synchronisieren synonym tab teilegleitobjekt tex textlinie textreferenz tief tiho tip tippedatei tippen tippepuffer title tooltip ueber ueberschrifttext uebersetzten umrahmt underbar underbars usedirectory usetypescript usetypescriptfile verbergebloecke vergleichefarbengruppe vergleichepalette verknuepfebeschriftung verknuepfedokument verknuepfregister version verweis verweisdatum verwendeURL verwendebefehl verwendebloecke verwendeexteresdokument verwendeexterneabbildung verwendeexternedatei verwendeexternedateien verwendeexternestonstueck verwendemodul verwendereferenzen verwendesymbole vl von waehlebloeckeaus waehlepapieraus waehleversionaus wechselezumfliesstext wochentag wortrechts zeigedruck zeigeeinstellungen zeigeexterneabbildungen zeigefarbe zeigefarbengruppe zeigefelder zeigefliesstext zeigefliesstextumgebung zeigegitter zeigelayout zeigepalette zeigerahmen zeigestruts zeigeumbruch zentriert ziffern zitat zitieren zu zurbox zwischenraum \ No newline at end of file
+keywordclass.macros.context.de=Buchstabe Buchstaben CAP Cap Caps MONAT Roemischezahlen WOCHENTAG WOERTER WORT Woerter Wort amgitterausrichten amgitterneuausrichten appendix aufseite ausfuellfeld ausfuelltext ausschnitt bearbeitebloecke bearbeiteseite behaltebloecke bei benutzekodierung benutzespezielles beschrifteversion beschriftung bestimmekopfnummer bestimmelistencharakeristika bildschirm blanko bookmark bruch buchstabe buchstaben but bypassblocks cap chapter chem comment completecombinedlist completelistoffloats completelistofsorts completelistofsynonyms completeregister coupledregister crlf datum definebodyfontDEF definebodyfontREF definedfont definefontfeature definefonthandling defineoutput defineschriftsynonym definetype definetypeface definiereabbsymbol definiereabsaetze definiereabschnitt definiereabschnittsblock definierebeschreibung definierebeschreibungen definierebeschriftung definiereblanko definiereblock definiereeinzug definierefarbe definierefarbengruppe definierefeld definierefeldstapel definierefliesstext definierefliesstextumgebung definieregleitobjekt definiereinteraktionsmenue definiereinteraktionsmenue definierekonversion definierelabel definiereliste definierelogo definieren definierenummerierung definiereoverlay definierepalette definierepapierformat definiereprofil definiereprogramme definierepuffer definierereferenz definierereferenzformat definierereferenzliste definiereregister definiereschrift definieresortieren definierestartstop definieresubfeld definieresymbol definieresynonyme definieretabellenvorlage definieretabulator definieretext definieretippen definiereueberschrift definiereumbruch definiereumrahmt definiereumrahmtertext definiereversion definierezusammengestellteliste description doppelseite doppelseitigespapier drehen duennelinie duennerumriss einezeile einziehen emptylines entknuepfebeschriftung enumeration externeabbildung farbe feld feldstapel festesspatium folgeprofil folgeprofilversion folgeversion footnotetext forceblocks format framedtext fussnote gefuelltesrechteck gefuelltezeile gestreckt gitter graufarbe haarlinie hauptsprache heutigesdatum heutigeskopfnummer hintergrund hl hoch holebeschriftung holepuffer imlinken imrechten imumriss in inaktiviereinteraktionsmenue inanderermarginale indentation ininner inmarginalie inouter installieresprache interaktionsbalken interaktionsknopfe inzeile irgendwo its keinebeschriftung keinebloeckemehr keinedateienmehr keinekopfundfusszeilen keineliste keinspatium keinzeilenobenundunten keinzwischenraum kleinerdurchschuss klonierefeld knopf konvertierezahl kopf kopfnummer kopierefeld korrigierezwischenraum labeling labels labeltext linksbuendig listsymbol loadsorts loadsynonyms mapfontsize mar marginallinie marginaltext mathematik mediaeval monat nachunten name nextsection nichteinziehen nocap nop notiz overbar overbars overstrike overstrikes paragraph part passelayoutan passendfeld placefloat placelistoffloats placelistofsorts placelistofsynonyms placereferencelist platzierebookmarks platziereformel platzierefussnoten platzierelegende platziereliste platzierelogo platzierelokalefussnoten platzierenebeneinander platziereregister platziereregister platziereuntereinander platziereunterformel platzierezusammengestellteliste platzierezusammengestellteliste pos position posten programm publikation punkt ran rechteck rechtecke rechtsbuendig ref referenz register registrierefelder reservefloat resettextcontent roemischezahlen ruecksetzten ruecksetztenbeschriftung schreibezumregister schreibezurliste schreibezurreferenzliste schreibezwischenliste section seeregister seite seitenreferenz seitentyp settext setupfonthandling setupfontsynonym setupforms setupinterlinespace2 setupitemgroup setuplistalternative setuppaper setupstrut showsymbolset sort spalte spatium spiegeln sprache startalignment startbuffer startbuffer startcolumns startcombination startcomment startdescription startdocument startenumeration startfarbe startfigure startfloattext startformula startframedtext startgeg starthiding starthintergrund startinteraktionsmenue startitemgroup startkleinerdurchschuss startkomponente startlegend startline startlinecorrection startlinenumbering startlines startlocal startlocalenvironment startlocalfootnotes startmakeup startmarginallinie startmarginblock startnamemakeup startnarrower startopposite startoverlay startoverview startparagraph startpositioning startpostponing startprodukt startprofile startprojekt startregister startsymbolset startsynchronization starttable starttables starttabulate starttextlinie starttyping startumgebung startunpacked startversion startzitat stelleabsaetzeein stelleabsatznummerierungein stelleabschnittein stelleabschnittsblockein stelleanordnenein stelleausgabeein stelleausrichtungein stelleausschnittein stellebeschreibungein stellebeschriftungein stellebilderunterschriftein stellebildunterschriftein stellebindestrichein stelleblankoein stelleblockein stelledrehenein stelleduennerumrissein stelleeinziehenein stelleeinzuegein stelleengerein stelleexterneabbildungenein stellefarbeein stellefarbenein stellefeldein stellefelderin stellefliesstextein stellefliesstextumgebungein stelleformelnein stellefussnotendefinitionein stellefussnotenein stellefusszeileein stellefusszeilentextein stellegefuelltesrechteckein stellegefuelltezeileein stellegegenueberplatzierenein stellegleitobjekteein stellegleitobjektein stellehintergruendeein stellehintergrundein stelleinmarginalieein stelleinteraktionein stelleinteraktionsbalkenein stelleinteraktionsbildschirmein stelleinteraktionsmenueein stelleknopfein stellekombinationein stellekommentarein stellekopfzahlein stellekopfzeileein stellekopfzeilentextein stellelabeltextein stellelayoutein stellelegendeein stellelinienbreiteein stellelisteein stellemarginalblockein stellemarginallinieein stellenobenein stellenummerierungein stellepaletteein stellepapierformatein stelleplatziegeteiltegleitobjekt stellepositionierenein stellepostenein stelleprofilein stelleprogrammein stellepublikationein stellepufferein stellerasterein stellerechteckein stellereferenzierenein stellereferenzlisteein stelleregisterein stelleseitennummerein stelleseitennummeriernungein stelleseitenuebergangein stellesortierenein stellespaltenein stellespatiumein stellespracheein stellesymbolsetein stellesynchronisationein stellesynchronisationsbalkenein stellesynonymein stellesystemein stelletabein stelletabellenein stelletabulatorein stelletextein stelletextobenein stelletexttexteein stelletextumrissein stelletextuntenein stelletipein stelletippenein stelletoleranzein stelleueberschriftein stelleueberschriftenein stelleueberschrifttextein stelleumbruchein stelleumrahmtein stelleumrahmtetexteein stelleuntenein stelleunterseitennummerein stelleunterstreichenein stelleurlein stelleversalienein stelleversionein stellezeilenabstandein stellezeilenein stellezeilennumerierungein stellezitierenein stellezusammengestelltelisteein stellezwischenraumein stopalignment stopbuffer stopbuffer stopcolumns stopcombination stopcomment stopdescription stopdocument stopenumeration stopfarbe stopfigure stopfloattext stopformula stopframedtext stopgeg stophiding stophintergrund stopinteraktionsmenue stopitemgroup stopkleinerdurchschuss stopkomponente stoplegend stopline stoplinecorrection stoplinenumbering stoplines stoplocal stoplocalenvironment stoplocalfootnotes stopmakeup stopmarginallinie stopmarginblock stopnamemakeup stopnarrower stopopposite stopoverlay stopoverview stopparagraph stoppositioning stoppostponing stopprodukt stopprofile stopprojekt stopsymbolset stopsynchronization stoptable stoptables stoptabulate stoptextlinie stoptyping stopumgebung stopunpacked stopversion stopzitat sub subject subsection subsubject subsubsection subsubsubject sym symbol synchronisationsbalken synchronisieren synonym tab teilegleitobjekt tex textlinie textreferenz tief tiho tip tippedatei tippen tippepuffer title tooltip ueber ueberschrifttext uebersetzten umrahmt underbar underbars usedirectory usetypescript usetypescriptfile verbergebloecke vergleichefarbengruppe vergleichepalette verknuepfebeschriftung verknuepfedokument verknuepfregister version verweis verweisdatum verwendeURL verwendebefehl verwendebloecke verwendeexteresdokument verwendeexterneabbildung verwendeexternedatei verwendeexternedateien verwendeexternestonstueck verwendemodul verwendereferenzen verwendesymbole vl von waehlebloeckeaus waehlepapieraus waehleversionaus wechselezumfliesstext wochentag wortrechts zeigedruck zeigeeinstellungen zeigeexterneabbildungen zeigefarbe zeigefarbengruppe zeigefelder zeigefliesstext zeigefliesstextumgebung zeigegitter zeigelayout zeigepalette zeigerahmen zeigestruts zeigeumbruch zentriert ziffern zitat zitieren zu zurbox zwischenraum \ No newline at end of file
diff --git a/context/data/scite/cont-fr-scite.properties b/context/data/scite/cont-fr-scite.properties
index 606be2efa..5ecccf961 100644
--- a/context/data/scite/cont-fr-scite.properties
+++ b/context/data/scite/cont-fr-scite.properties
@@ -1 +1 @@
-keywordclass.macros.context.fr=CAP Cap Caps Caractere Caracteres Chiffresromains JOURSEMAINE MOIS MOT MOTS Mot Mots a adaptedisposition ajustechamp alaligne alapage aligneadroite aligneagauche aligneaumilieu appendix arriereplan baha barreinteraction barresynchronisation bas bouton boutonsinteraction but cacheblocs cap caractere caracteres champ changepolicecorps chapter chem chiffresromains citation citer clip clonechamp colonne commentaire comparegroupecouleur comparepalette completecombinedlist completelistoffloats completelistofsorts completelistofsynonyms completeregistre composeenalinea concernant convertitnumero copitchamp corrigeespaceblanc couleur couleurgrise coupledocument coupledregister couplemarquage couplepapier coupleregistre crlf dactylographier dans dansautremarge dansdroite dansgauche dansmarge date datecourante daterecommandation de decouplemarquage definebodyfontDEF definebodyfontREF definedfont definefontfeature definefonthandling defineframed defineframedtext definetypeface definit definitbloc definitblocsection definitbuffer definitchamp definitcompoalinea definitconversion definitcouleur definitdactylo definitdemarrestoppe definitdescription definitenumeration definitenvironnementpolicecorps definitetiquette definitflottant definitformatreference definitgroupecouleur definitliste definitlisteimbriquee definitlistereference definitlogo definitmakeup definitmarquage definitmenuinteraction definitmenuinteraction definitnotepdp definitpalette definitparagraphes definitpilechamp definitpolice definitpolicecorps definitprofil definitprogramme definitreference definitregistre definitrevetement definitsection definitsortie definitsouschamp definitsymbole definitsymbolefigure definitsynonymepolice definitsynonymes definittabulation definittaillepapier definittete definittexte definittrametableau definittri definittype definitversion definitvide definitvide demarreciter deplacesurgrille description determinecaracteristiqueliste determinenumerotete echelle ecran ecritdansliste ecritdanslistereference ecritentreliste ecritregistre el element elements emptylines enumeration espace espaceblanc espacesfixes etiquettes etire fichierdactylo figureexterne forceblocs fraction framed framedtext gardeblocs grille groupe haut hl indentation inframed inhibemenuinteraction ininner inouter installelangue joursemaine labeling labeltexte langue langueprincipale ligneh lignenoire ligneregleetexte lignesnoires listesymbole loadsorts loadsynonyms logchamp mapfontsize mar margereglee marquage marquageversion marquepage mathematique mediaeval mois montrecadre montrechamps montrecouleur montredisposition montreedition montreenvironnementpolicecorps montrefiguresexternes montregrille montregroupecouleur montrejeusymboles montremakeup montrepalette montrepolicecorps montrereglages montrestruts motdroit name nextsection nocap nop note notepdp numeros numerotete numerotetecourant obtientmarquage oriente overbar overbars overstrike overstrikes page pagedouble paragraph part pasplusdeblocs pasplusdefichiers periodes pilechamp placecoteacote placeflottant placeformule placelegende placelesunsaudessusdesautres placeliste placelisteinmbriquee placelisteinmbriquee placelistereference placelistoffloats placelistofsorts placelistofsynonyms placelogos placemarquespages placenotespdp placenotespdplocales placeregistre placeregistre placesousformule placesurgrille position prendbuffer programme publication qqpart ran raz razmarquage recommandation ref reference referencepage referencetexte reflete register reglealignement reglealineas reglearrangement reglearriereplan reglearriereplans reglebarreinteraction reglebarresynchronisation reglebloc regleblocmarge regleblocsection regleboutons reglebuffer reglecapitales reglechamp reglechamps regleclipping reglecolonnes reglecombinaisons reglecommentaire reglecompoetroite reglecomposeenalinea reglecouleur reglecouleurs regledactylo regledansmarge regledescriptions regledisposition regleecraninteraction regleecrans regleelements regleencadre regleentete regleenumerations regleenvironnementpolicecorps regleepaisseurligne regleespaceblanc regleespacement regleespacementinterligne reglefiguresexternes regleflottant regleflottants regleformulaires regleformules regleinf regleinteraction regleintitule regleintitules reglejeusymboles reglelabeltexte reglelangue reglelegende reglelignes reglelignesnoires reglelignesreglestexte regleliste reglelisteimbriquee reglelistereference reglemakeup reglemargereglee reglemarquage reglemarquagehyphenation reglemenuinteraction reglenotepdp reglenumeropage reglenumerotation reglenumerotationligne reglenumerotationpage reglenumerotationparagraphe reglenumerotete regleoriente reglepalette reglepapier regleparagraphes reglepdp regleplacementopposition reglepolicecorps reglepositionnement regleprofils regleprogrammes reglepublications reglereferencage regleregistre regleremplitligne regleremplitlignesreglees reglesection regleseparationflottant reglesortie reglesouslignage reglesousnumeropage reglestrut reglesup reglesynchronisation reglesynonymes reglesysteme regletab regletableaux regletabulation regletaillepapier regletete regletetes regletexte regletextesentete regletextesinf regletextespdp regletextessup regletextestexte regletextetete regletolerance regletraitsfins regletransitionspage regletri regletype regleurl regleversions remplitchamp remplitligne remplitlignesreglees remplittexte reservefloat resettextcontent sansalinea sansespace sansespaceblanc sanslignesenteteetpdp sanslignessupetinf sansliste sansmarquage sauteblocs section seeregister selectionneblocs selectionnepapier selectionneversion separeflottant settext setupfonthandling setupfontsynonym setupframedtexts setupinterlinespace2 setupitemgroup setuplistalternative sort startalignment startarriereplan startbuffer startbuffer startcitation startcolumns startcombination startcommentaire startcomposant startcouleur startdescription startdocument startenumeration startenvironement startfait startfigure startfloattext startformula startframedtext startgroupe starthiding startitemgroup startlegend startligneregleetexte startline startlinecorrection startlinenumbering startlines startlocal startlocalenvironment startlocalfootnotes startmakeup startmargereglee startmarginblock startmenuinteraction startnamemakeup startnarrower startopposite startoverlay startoverview startparagraph startpositioning startpostponing startproduit startprofile startprojet startregister startsymbolset startsynchronization starttable starttables starttabulate starttyping startunpacked startversion stopalignment stoparriereplan stopbuffer stopbuffer stopcitation stopcolumns stopcombination stopcommentaire stopcomposant stopcouleur stopdescription stopdocument stopenumeration stopenvironement stopfait stopfigure stopfloattext stopformula stopframedtext stopgroupe stophiding stopitemgroup stoplegend stopligneregleetexte stopline stoplinecorrection stoplinenumbering stoplines stoplocal stoplocalenvironment stoplocalfootnotes stopmakeup stopmargereglee stopmarginblock stopmenuinteraction stopnamemakeup stopnarrower stopopposite stopoverlay stopoverview stopparagraph stoppositioning stoppostponing stopproduit stopprofile stopprojet stopsymbolset stopsynchronization stoptable stoptables stoptabulate stoptyping stopunpacked stopversion sub subject subsection subsubject subsubsection subsubsubject suggestion suivantprofil suivantversion suivantversionprofil sym symbole synchronise synonym tab tapebuffer tapepage tete tex textemarge textenotepdp textetete title traduire traiteblocs traitepage traitfin traitsfins typ underbar underbars uneligne usedirectory usetypescript usetypescriptfile utiliseURL utiliseblocs utilisecommandes utilisedocumentexterne utiliseencodage utilisefichierexterne utilisefichiersexternes utilisefigureexterne utilisemodule utilisepsiteaudioexterne utilisereferences utilisespecialites utilisesymboles va vaalaboite vaenbas version vide vl \ No newline at end of file
+keywordclass.macros.context.fr=CAP Cap Caps Caractere Caracteres Chiffresromains JOURSEMAINE MOIS MOT MOTS Mot Mots a adaptedisposition ajustechamp alaligne alapage aligneadroite aligneagauche aligneaumilieu appendix arriereplan baha barreinteraction barresynchronisation bas bouton boutonsinteraction but cacheblocs cap caractere caracteres champ changepolicecorps chapter chem chiffresromains citation citer clip clonechamp colonne comment comparegroupecouleur comparepalette completecombinedlist completelistoffloats completelistofsorts completelistofsynonyms completeregistre composeenalinea concernant convertitnumero copitchamp corrigeespaceblanc couleur couleurgrise coupledocument coupledregister couplemarquage couplepapier coupleregistre crlf dactylographier dans dansautremarge dansdroite dansgauche dansmarge date datecourante daterecommandation de decouplemarquage definebodyfontDEF definebodyfontREF definedfont definefontfeature definefonthandling defineframed defineframedtext definetypeface definit definitbloc definitblocsection definitbuffer definitchamp definitcompoalinea definitconversion definitcouleur definitdactylo definitdemarrestoppe definitdescription definitenumeration definitenvironnementpolicecorps definitetiquette definitflottant definitformatreference definitgroupecouleur definitliste definitlisteimbriquee definitlistereference definitlogo definitmakeup definitmarquage definitmenuinteraction definitmenuinteraction definitnotepdp definitpalette definitparagraphes definitpilechamp definitpolice definitpolicecorps definitprofil definitprogramme definitreference definitregistre definitrevetement definitsection definitsortie definitsouschamp definitsymbole definitsymbolefigure definitsynonymepolice definitsynonymes definittabulation definittaillepapier definittete definittexte definittrametableau definittri definittype definitversion definitvide definitvide demarreciter deplacesurgrille description determinecaracteristiqueliste determinenumerotete echelle ecran ecritdansliste ecritdanslistereference ecritentreliste ecritregistre el element elements emptylines enumeration espace espaceblanc espacesfixes etiquettes etire fichierdactylo figureexterne forceblocs fraction framed framedtext gardeblocs grille groupe haut hl indentation inframed inhibemenuinteraction ininner inouter installelangue joursemaine labeling labeltexte langue langueprincipale ligneh lignenoire ligneregleetexte lignesnoires listesymbole loadsorts loadsynonyms logchamp mapfontsize mar margereglee marquage marquageversion marquepage mathematique mediaeval mois montrecadre montrechamps montrecouleur montredisposition montreedition montreenvironnementpolicecorps montrefiguresexternes montregrille montregroupecouleur montrejeusymboles montremakeup montrepalette montrepolicecorps montrereglages montrestruts motdroit name nextsection nocap nop note notepdp numeros numerotete numerotetecourant obtientmarquage oriente overbar overbars overstrike overstrikes page pagedouble paragraph part pasplusdeblocs pasplusdefichiers periodes pilechamp placecoteacote placeflottant placeformule placelegende placelesunsaudessusdesautres placeliste placelisteinmbriquee placelisteinmbriquee placelistereference placelistoffloats placelistofsorts placelistofsynonyms placelogos placemarquespages placenotespdp placenotespdplocales placeregistre placeregistre placesousformule placesurgrille position prendbuffer programme publication qqpart ran raz razmarquage recommandation ref reference referencepage referencetexte reflete register reglealignement reglealineas reglearrangement reglearriereplan reglearriereplans reglebarreinteraction reglebarresynchronisation reglebloc regleblocmarge regleblocsection regleboutons reglebuffer reglecapitales reglechamp reglechamps regleclipping reglecolonnes reglecombinaisons reglecommentaire reglecompoetroite reglecomposeenalinea reglecouleur reglecouleurs regledactylo regledansmarge regledescriptions regledisposition regleecraninteraction regleecrans regleelements regleencadre regleentete regleenumerations regleenvironnementpolicecorps regleepaisseurligne regleespaceblanc regleespacement regleespacementinterligne reglefiguresexternes regleflottant regleflottants regleformulaires regleformules regleinf regleinteraction regleintitule regleintitules reglejeusymboles reglelabeltexte reglelangue reglelegende reglelignes reglelignesnoires reglelignesreglestexte regleliste reglelisteimbriquee reglelistereference reglemakeup reglemargereglee reglemarquage reglemarquagehyphenation reglemenuinteraction reglenotepdp reglenumeropage reglenumerotation reglenumerotationligne reglenumerotationpage reglenumerotationparagraphe reglenumerotete regleoriente reglepalette reglepapier regleparagraphes reglepdp regleplacementopposition reglepolicecorps reglepositionnement regleprofils regleprogrammes reglepublications reglereferencage regleregistre regleremplitligne regleremplitlignesreglees reglesection regleseparationflottant reglesortie reglesouslignage reglesousnumeropage reglestrut reglesup reglesynchronisation reglesynonymes reglesysteme regletab regletableaux regletabulation regletaillepapier regletete regletetes regletexte regletextesentete regletextesinf regletextespdp regletextessup regletextestexte regletextetete regletolerance regletraitsfins regletransitionspage regletri regletype regleurl regleversions remplitchamp remplitligne remplitlignesreglees remplittexte reservefloat resettextcontent sansalinea sansespace sansespaceblanc sanslignesenteteetpdp sanslignessupetinf sansliste sansmarquage sauteblocs section seeregister selectionneblocs selectionnepapier selectionneversion separeflottant settext setupfonthandling setupfontsynonym setupframedtexts setupinterlinespace2 setupitemgroup setuplistalternative sort startalignment startarriereplan startbuffer startbuffer startcitation startcolumns startcombination startcomment startcomposant startcouleur startdescription startdocument startenumeration startenvironement startfait startfigure startfloattext startformula startframedtext startgroupe starthiding startitemgroup startlegend startligneregleetexte startline startlinecorrection startlinenumbering startlines startlocal startlocalenvironment startlocalfootnotes startmakeup startmargereglee startmarginblock startmenuinteraction startnamemakeup startnarrower startopposite startoverlay startoverview startparagraph startpositioning startpostponing startproduit startprofile startprojet startregister startsymbolset startsynchronization starttable starttables starttabulate starttyping startunpacked startversion stopalignment stoparriereplan stopbuffer stopbuffer stopcitation stopcolumns stopcombination stopcomment stopcomposant stopcouleur stopdescription stopdocument stopenumeration stopenvironement stopfait stopfigure stopfloattext stopformula stopframedtext stopgroupe stophiding stopitemgroup stoplegend stopligneregleetexte stopline stoplinecorrection stoplinenumbering stoplines stoplocal stoplocalenvironment stoplocalfootnotes stopmakeup stopmargereglee stopmarginblock stopmenuinteraction stopnamemakeup stopnarrower stopopposite stopoverlay stopoverview stopparagraph stoppositioning stoppostponing stopproduit stopprofile stopprojet stopsymbolset stopsynchronization stoptable stoptables stoptabulate stoptyping stopunpacked stopversion sub subject subsection subsubject subsubsection subsubsubject suggestion suivantprofil suivantversion suivantversionprofil sym symbole synchronise synonym tab tapebuffer tapepage tete tex textemarge textenotepdp textetete title traduire traiteblocs traitepage traitfin traitsfins typ underbar underbars uneligne usedirectory usetypescript usetypescriptfile utiliseURL utiliseblocs utilisecommandes utilisedocumentexterne utiliseencodage utilisefichierexterne utilisefichiersexternes utilisefigureexterne utilisemodule utilisepsiteaudioexterne utilisereferences utilisespecialites utilisesymboles va vaalaboite vaenbas version vide vl \ No newline at end of file
diff --git a/context/data/scite/cont-it-scite.properties b/context/data/scite/cont-it-scite.properties
index da5df2400..699cd0f1e 100644
--- a/context/data/scite/cont-it-scite.properties
+++ b/context/data/scite/cont-it-scite.properties
@@ -1 +1 @@
-keywordclass.macros.context.it=CAP Cap Caps GIORNOSETTIMANA Lettera Lettere MESE Numeriromani PAROLA PAROLE Parola Parole accoppiacarta accoppiadocumento accoppiamarcatura accoppiapagina accoppiaregistro adattacampo adattalayout al allineacentro allineadestra allineasinistra ap apagina appendix barrainterazione barrasincronizzazione bastablocchi bastafile cambiaafontdeltesto campi camporiempimento cap capello chapter chim circondato citazione clip clonacampo colonna colore coloregrigio commento completecombinedlist completelistoffloats completelistofsorts completelistofsynonyms completeregister confrontagruppocolori confrontatavolozza convertinumero copiacampo correggispaziobianco coupledregister crlf da daqualcheparte data datadioggi datareferral definebodyfontDEF definebodyfontREF definedfont definefontfeature definefonthandling definetypeface definisci definisciambientefontdeltesto definisciblocco definiscibloccosezione definiscibuffer definiscicampo definiscicapoversi definiscicolore definisciconversione definiscidescrizione definiscidimensionicarta definiscielenco definiscielencocombinato definiscienumerazione definiscietichetta definiscifigurasimbolo definiscifont definiscifontdeltesto definisciformatoriferimento definiscigruppocolori definisciincorniciato definisciiniziatermina definiscilistariferimenti definiscilogo definiscimakeup definiscimarcatura definiscimenuinterazione definiscimenuinterazione definiscimodellotabella definiscioggettomobile definisciordinamento definiscioutput definisciprofilo definisciprogramma definisciregistro definiscirientro definisciriferimento definiscirigovuoto definiscisezione definiscisimbolo definiscisinonimi definiscisinonimofont definiscisottocampo definiscisovrapposizione definiscistackcampi definiscitabulato definiscitavolozza definiscitesta definiscitesto definiscitestoincorniciato definiscitype definiscityping definisciversion description determinacarattersticheelenco determinanumerotesta disabilitamenuinterazione el elaborablocchi elaborapagina elementi elemento emptylines enumeration etichette figuraesterna fondo forzablocchi framedtext frazione giornosettimana griglia hl impaccato impostaallineamento impostaambientefontdeltesto impostaampiezzariga impostabarrainterazione impostabarrasincronizzazione impostablocchimargine impostablocco impostabloccosezione impostabuffer impostacampi impostacampo impostacapoversi impostacaption impostacaptions impostacima impostaclippling impostacolonne impostacolore impostacolori impostacombinazioni impostacommento impostadefinizionenotepdp impostadescrizioni impostadimensionicarta impostaelementi impostaelenco impostaelencocombinato impostaenumerazioni impostafigureesterne impostafondo impostafontdeltesto impostaforms impostaformule impostaincorniciato impostainmargine impostainstestazione impostainterazione impostainterlinea impostalayout impostalegenda impostalineemargine impostalineenere impostalineeriempimento impostalineesottili impostalineetesto impostalingua impostalistariferimenti impostamaiuscole impostamakeup impostamarcatura impostamenuinterazione impostamenzione impostanotepdp impostanumerazione impostanumerazionecapoversi impostanumerazionepagina impostanumerazionerighe impostanumeropagina impostanumerosottopagina impostanumerotesta impostaoggettimobili impostaoggettomobile impostaordinamento impostaoutput impostaparranging impostapdp impostapiustretto impostaposizionamento impostaposizionamentoopposti impostaprofili impostaprogrammi impostapubblicazioni impostapulsanti impostaregistro impostarientri impostarientro impostariferimento impostarighe impostarigheriempimento impostarigovuoto impostarotazione impostaschermi impostaschermointerazione impostasegnosillabazione impostasetsimboli impostasezione impostasfondi impostasfondo impostasincronizzazione impostasinonimi impostasistema impostasottolinea impostaspaziatura impostaspaziobianco impostaspezzamentooggettomobile impostastrut impostatab impostatabelle impostatabulato impostatavolozza impostatesta impostateste impostatesticima impostatestifondo impostatestiincorniciati impostatestiintestazioni impostatestipdp impostatesto impostatestoetichette impostatestointestazioni impostatestotesti impostatolleranza impostatransizionepagina impostatype impostatyping impostaurl impostaversioni in inaltromargine incorniciato indentation indestra ininner inmargine inouter inriga insinistra installalingua intorno labeling lettera lettere lineamargine lineanera lineasottile lineatesto lineenere lineeriempimento lineesottili lingua linguaprincipale listsymbol loadsorts loadsynonyms logcampi mapfontsize mar marcatura marcaversione matematica mediaeval menzione mese mettielenco mettielencocombinato mettielencocombinato mettifiancoafianco mettiformula mettiingriglia mettilegenda mettiloghi mettinotepdp mettinotepdplocali mettiregistro mettiregistro mettisegnalibro mettisottoformula mettiunosullaltro mostraambientefontdeltesto mostracampi mostracolore mostracornice mostrafiguresterne mostrafontdeltesto mostragriglia mostragruppocolori mostraimpostazioni mostralyout mostramakeup mostrasetsimboli mostrastampa mostrastruts mostratavolozza name nascondiblocchi nextsection nienteelenco nientelineecimafondo nientelineintestazionepdp nientemarcatura nienterientro nientespazio nientespaziobianco nocap nop nota notapdp numeri numeriromani numerotesta numerotestacorrente overbar overbars overstrike overstrikes pagina paragraph paroladestra part ped pedap placefloat placelistoffloats placelistofsorts placelistofsynonyms placereferencelist posizione prendibuffer prendimarcatura programma pubblicazione pulsante pulsantinterazione punti qualcheriga ran referral register reimposta reimpostamarcatura reservefloat resettextcontent rientro rif riferimento riferimentopagina riferimentotesto riflessione rigariempimento rigovuoto ruota saltablocchi scala schermo scrividentroelenco scriviinelenco scriviinlistariferimenti scriviinregistro section seeregister segnalibro seguiprofilo seguiversione seguiversioneprofilo selezionablocchi selezionacarta selezionaversione separamarcatura settext setupfonthandling setupfontsynonym setupinterlinespace2 setupitemgroup setuplistalternative setuppaper sfondo sim simbolo sincronizza sort spazifissi spazio spaziobianco spezzaoggettomobile spostaagriglia stackcampi startalignment startambiente startbuffer startbuffer startcitazione startcolore startcolumns startcombination startcommento startcomponenet startdescription startdocument startenumeration startfatto startfigure startfloattext startformula startframedtext starthiding startimpaccato startitemgroup startlegend startline startlineamargine startlineatesto startlinecorrection startlinenumbering startlines startlocal startlocalenvironment startlocalfootnotes startmakeup startmarginblock startmenuinterattivo startnamemakeup startnarrower startopposite startoverlay startoverview startparagraph startpositioning startpostponing startprodotto startprofile startprogetto startregister startsfondo startsymbolset startsynchronization starttable starttables starttabulate starttyping startunpacked startversione stirato stopalignment stopambiente stopbuffer stopbuffer stopcitazione stopcolore stopcolumns stopcombination stopcommento stopcomponenet stopdescription stopdocument stopenumeration stopfatto stopfigure stopfloattext stopformula stopframedtext stophiding stopimpaccato stopitemgroup stoplegend stopline stoplineamargine stoplineatesto stoplinecorrection stoplinenumbering stoplines stoplocal stoplocalenvironment stoplocalfootnotes stopmakeup stopmarginblock stopmenuinterattivo stopnamemakeup stopnarrower stopopposite stopoverlay stopoverview stopparagraph stoppositioning stoppostponing stopprodotto stopprofile stopprogetto stopsfondo stopsymbolset stopsynchronization stoptable stoptables stoptabulate stoptyping stopunpacked stopversione sub subject subsection subsubject subsubsection subsubsubject synonym tab testa testoetichetta testoinmargine testoinstestazioni testonotapdp testoriempimento tex tieniblocchi tipopagina title tooltip traduci typ type typebuffer typefile underbar underbars usaURL usablocco usacodifica usacolonnasonoraesterna usacomandi usadocumentoesterno usafiguraesterna usafileesterni usafileesterno usamodulo usariferimenti usasimboli usaspecialita usedirectory usetypescript usetypescriptfile vaia vaiabox vaigiu versione vl \ No newline at end of file
+keywordclass.macros.context.it=CAP Cap Caps GIORNOSETTIMANA Lettera Lettere MESE Numeriromani PAROLA PAROLE Parola Parole accoppiacarta accoppiadocumento accoppiamarcatura accoppiapagina accoppiaregistro adattacampo adattalayout al allineacentro allineadestra allineasinistra ap apagina appendix barrainterazione barrasincronizzazione bastablocchi bastafile cambiaafontdeltesto campi camporiempimento cap capello chapter chim circondato citazione clip clonacampo colonna colore coloregrigio comment completecombinedlist completelistoffloats completelistofsorts completelistofsynonyms completeregister confrontagruppocolori confrontatavolozza convertinumero copiacampo correggispaziobianco coupledregister crlf da daqualcheparte data datadioggi datareferral definebodyfontDEF definebodyfontREF definedfont definefontfeature definefonthandling definetypeface definisci definisciambientefontdeltesto definisciblocco definiscibloccosezione definiscibuffer definiscicampo definiscicapoversi definiscicolore definisciconversione definiscidescrizione definiscidimensionicarta definiscielenco definiscielencocombinato definiscienumerazione definiscietichetta definiscifigurasimbolo definiscifont definiscifontdeltesto definisciformatoriferimento definiscigruppocolori definisciincorniciato definisciiniziatermina definiscilistariferimenti definiscilogo definiscimakeup definiscimarcatura definiscimenuinterazione definiscimenuinterazione definiscimodellotabella definiscioggettomobile definisciordinamento definiscioutput definisciprofilo definisciprogramma definisciregistro definiscirientro definisciriferimento definiscirigovuoto definiscisezione definiscisimbolo definiscisinonimi definiscisinonimofont definiscisottocampo definiscisovrapposizione definiscistackcampi definiscitabulato definiscitavolozza definiscitesta definiscitesto definiscitestoincorniciato definiscitype definiscityping definisciversion description determinacarattersticheelenco determinanumerotesta disabilitamenuinterazione el elaborablocchi elaborapagina elementi elemento emptylines enumeration etichette figuraesterna fondo forzablocchi framedtext frazione giornosettimana griglia hl impaccato impostaallineamento impostaambientefontdeltesto impostaampiezzariga impostabarrainterazione impostabarrasincronizzazione impostablocchimargine impostablocco impostabloccosezione impostabuffer impostacampi impostacampo impostacapoversi impostacaption impostacaptions impostacima impostaclippling impostacolonne impostacolore impostacolori impostacombinazioni impostacommento impostadefinizionenotepdp impostadescrizioni impostadimensionicarta impostaelementi impostaelenco impostaelencocombinato impostaenumerazioni impostafigureesterne impostafondo impostafontdeltesto impostaforms impostaformule impostaincorniciato impostainmargine impostainstestazione impostainterazione impostainterlinea impostalayout impostalegenda impostalineemargine impostalineenere impostalineeriempimento impostalineesottili impostalineetesto impostalingua impostalistariferimenti impostamaiuscole impostamakeup impostamarcatura impostamenuinterazione impostamenzione impostanotepdp impostanumerazione impostanumerazionecapoversi impostanumerazionepagina impostanumerazionerighe impostanumeropagina impostanumerosottopagina impostanumerotesta impostaoggettimobili impostaoggettomobile impostaordinamento impostaoutput impostaparranging impostapdp impostapiustretto impostaposizionamento impostaposizionamentoopposti impostaprofili impostaprogrammi impostapubblicazioni impostapulsanti impostaregistro impostarientri impostarientro impostariferimento impostarighe impostarigheriempimento impostarigovuoto impostarotazione impostaschermi impostaschermointerazione impostasegnosillabazione impostasetsimboli impostasezione impostasfondi impostasfondo impostasincronizzazione impostasinonimi impostasistema impostasottolinea impostaspaziatura impostaspaziobianco impostaspezzamentooggettomobile impostastrut impostatab impostatabelle impostatabulato impostatavolozza impostatesta impostateste impostatesticima impostatestifondo impostatestiincorniciati impostatestiintestazioni impostatestipdp impostatesto impostatestoetichette impostatestointestazioni impostatestotesti impostatolleranza impostatransizionepagina impostatype impostatyping impostaurl impostaversioni in inaltromargine incorniciato indentation indestra ininner inmargine inouter inriga insinistra installalingua intorno labeling lettera lettere lineamargine lineanera lineasottile lineatesto lineenere lineeriempimento lineesottili lingua linguaprincipale listsymbol loadsorts loadsynonyms logcampi mapfontsize mar marcatura marcaversione matematica mediaeval menzione mese mettielenco mettielencocombinato mettielencocombinato mettifiancoafianco mettiformula mettiingriglia mettilegenda mettiloghi mettinotepdp mettinotepdplocali mettiregistro mettiregistro mettisegnalibro mettisottoformula mettiunosullaltro mostraambientefontdeltesto mostracampi mostracolore mostracornice mostrafiguresterne mostrafontdeltesto mostragriglia mostragruppocolori mostraimpostazioni mostralyout mostramakeup mostrasetsimboli mostrastampa mostrastruts mostratavolozza name nascondiblocchi nextsection nienteelenco nientelineecimafondo nientelineintestazionepdp nientemarcatura nienterientro nientespazio nientespaziobianco nocap nop nota notapdp numeri numeriromani numerotesta numerotestacorrente overbar overbars overstrike overstrikes pagina paragraph paroladestra part ped pedap placefloat placelistoffloats placelistofsorts placelistofsynonyms placereferencelist posizione prendibuffer prendimarcatura programma pubblicazione pulsante pulsantinterazione punti qualcheriga ran referral register reimposta reimpostamarcatura reservefloat resettextcontent rientro rif riferimento riferimentopagina riferimentotesto riflessione rigariempimento rigovuoto ruota saltablocchi scala schermo scrividentroelenco scriviinelenco scriviinlistariferimenti scriviinregistro section seeregister segnalibro seguiprofilo seguiversione seguiversioneprofilo selezionablocchi selezionacarta selezionaversione separamarcatura settext setupfonthandling setupfontsynonym setupinterlinespace2 setupitemgroup setuplistalternative setuppaper sfondo sim simbolo sincronizza sort spazifissi spazio spaziobianco spezzaoggettomobile spostaagriglia stackcampi startalignment startambiente startbuffer startbuffer startcitazione startcolore startcolumns startcombination startcomment startcomponenet startdescription startdocument startenumeration startfatto startfigure startfloattext startformula startframedtext starthiding startimpaccato startitemgroup startlegend startline startlineamargine startlineatesto startlinecorrection startlinenumbering startlines startlocal startlocalenvironment startlocalfootnotes startmakeup startmarginblock startmenuinterattivo startnamemakeup startnarrower startopposite startoverlay startoverview startparagraph startpositioning startpostponing startprodotto startprofile startprogetto startregister startsfondo startsymbolset startsynchronization starttable starttables starttabulate starttyping startunpacked startversione stirato stopalignment stopambiente stopbuffer stopbuffer stopcitazione stopcolore stopcolumns stopcombination stopcomment stopcomponenet stopdescription stopdocument stopenumeration stopfatto stopfigure stopfloattext stopformula stopframedtext stophiding stopimpaccato stopitemgroup stoplegend stopline stoplineamargine stoplineatesto stoplinecorrection stoplinenumbering stoplines stoplocal stoplocalenvironment stoplocalfootnotes stopmakeup stopmarginblock stopmenuinterattivo stopnamemakeup stopnarrower stopopposite stopoverlay stopoverview stopparagraph stoppositioning stoppostponing stopprodotto stopprofile stopprogetto stopsfondo stopsymbolset stopsynchronization stoptable stoptables stoptabulate stoptyping stopunpacked stopversione sub subject subsection subsubject subsubsection subsubsubject synonym tab testa testoetichetta testoinmargine testoinstestazioni testonotapdp testoriempimento tex tieniblocchi tipopagina title tooltip traduci typ type typebuffer typefile underbar underbars usaURL usablocco usacodifica usacolonnasonoraesterna usacomandi usadocumentoesterno usafiguraesterna usafileesterni usafileesterno usamodulo usariferimenti usasimboli usaspecialita usedirectory usetypescript usetypescriptfile vaia vaiabox vaigiu versione vl \ No newline at end of file
diff --git a/context/data/scite/cont-nl-scite.properties b/context/data/scite/cont-nl-scite.properties
index 688c8a7c0..a36e8f475 100644
--- a/context/data/scite/cont-nl-scite.properties
+++ b/context/data/scite/cont-nl-scite.properties
@@ -1 +1 @@
-keywordclass.macros.context.nl=CAP Cap Caps Letter Letters MAAND Romeins WEEKDAG WOORD WOORDEN Woord Woorden about achtergrond appendix bepaalkopnummer bepaallijstkenmerken blanko blokje blokjes blokkeerinteractiemenu bookmark breuk but button cap chapter chem cijfers citaat citeer clip commentaar completecombinedlist completelistoffloats completelistofsorts completelistofsynonyms converteernummer copieerveld corrigeerwitruimte coupledregister crlf datum definebodyfontDEF definebodyfontREF definedfont definefontfeature definefonthandling definetypeface definieer definieeralineas definieerbeeldmerk definieerblanko definieerblok definieerbuffer definieerconversie definieerfiguursymbool definieerfont definieerfontsynoniem definieerinteractiemenu definieerinteractiemenu definieerkadertekst definieerkleur definieerkleurgroep definieerkop definieerkorps definieerkorpsomgeving definieerlijst definieermarkering definieeromlijnd definieeropmaak definieeroverlay definieerpalet definieerpapierformaat definieerplaatsblok definieerprofiel definieerprogramma definieerreferentie definieerreferentieformaat definieerreferentielijst definieerregister definieersamengesteldelijst definieersectie definieersectieblok definieersorteren definieerstartstop definieersubveld definieersymbool definieersynoniemen definieertabelvorm definieertabulatie definieertekst definieertype definieertypen definieeruitvoer definieerveld definieerveldstapel definieerversie description doordefinieren doorlabelen doornummeren doorspringen dunnelijn dunnelijnen eenregel enumeration ergens externfiguur forceerblokken framedtext gebruikURL gebruikblokken gebruikcommandos gebruikexterndocument gebruikexternefile gebruikexternefiles gebruikexternfiguur gebruikexterngeluidsfragment gebruikmodule gebruikreferenties gebruikspecials gebruiksymbolen gebruiktypescript gebruiktypescriptfile geenblokkenmeer geenbovenenonderregels geenfilesmeer geenhoofdenvoetregels geenlijst geenmarkering geenspatie geenwitruimte grijskleur haalbuffer haalmarkering haarlijn handhaafblokken hl hoofdtaal hoog huidigedatum huidigekopnummer in inanderemarge inbinnen inbuiten indentation inlijnd inlinker inmarge inrechter inregel inspringen installeertaal interactiebalk interactiebuttons invullijnen invulregel invultekst invulveld items its kantlijn kenmerk kenmerkdatum kleur kloonveld kolom kop kopnummer koppeldocument koppelmarkering koppelpagina koppelpapier koppelregister koptekst laag labeling labels labeltekst laho legeregels letter letters lijstsymbool loadsorts loadsynonyms maand mapfontsize mar margetekst markeer markeerversie mediaeval naar naarbox name nextsection nietinspringen nocap noot nop omlaag omlijnd ontkoppelmarkering op opelkaar oppagina overbar overbars overstrike overstrikes pagina paginareferentie paragraph part paslayoutaan passeerblokken passendveld plaatsbeeldmerken plaatsbookmarks plaatsformule plaatslegenda plaatslijst plaatslokalevoetnoten plaatsnaastelkaar plaatsonderelkaar plaatsopgrid plaatsplaatsblok plaatsreferentielijst plaatsregister plaatsregister plaatssamengesteldelijst plaatssamengesteldelijst plaatssubformule plaatsvoetnoten placelistoffloats placelistofsorts placelistofsynonyms positioneer programma publicatie punten ran ref referentie regellinks regelmidden regelrechts register registreervelden reservefloat reset resetmarkering resettextcontent romeins rooster roteer schaal scherm schrijfnaarlijst schrijfnaarreferentielijst schrijfnaarregister schrijftussenlijst section seeregister selecteerblokken selecteerpapier selecteerversie setupfonthandling setupfontsynonym setupinterlinespace2 setuplistalternative som soortpagina sort spatie spiegel splitsplaatsblok startachtergrond startalignment startbuffer startbuffer startcitaat startcolumns startcombination startcommentaar startdescription startdocument startenumeration startfigure startfloattext startformula startframedtext startgeg starthiding startinteractiemenu startitemgroup startkantlijn startkleur startlegend startline startlinecorrection startlinenumbering startlines startlocal startlocalenvironment startlocalfootnotes startmakeup startmarginblock startnamemakeup startnarrower startomgeving startonderdeel startopelkaar startopposite startoverlay startoverview startparagraph startpositioning startpostponing startprodukt startprofile startprojekt startregister startsymbolset startsynchronization starttable starttables starttabulate starttekstlijn starttyping startunpacked startversie stelachtergrondenin stelachtergrondin stelalineasin stelarrangerenin stelblankoin stelblokin stelblokjesin stelblokkopjein stelblokkopjesin stelbovenin stelboventekstenin stelbufferin stelbuttonsin stelciterenin stelclipin stelcombinatiesin stelcommentaarin steldoordefinierenin steldoornummerenin steldoorspringenin steldunnelijnenin stelexternefigurenin stelformulesin stelformulierenin stelhoofdin stelhoofdtekstenin stelinmargein stelinspringenin stelinteractiebalkin stelinteractiein stelinteractiemenuin stelinteractieschermin stelinterliniein stelinvullijnenin stelinvulregelsin stelitemgroepin stelitemsin stelkadertekstenin stelkantlijnin stelkapitalenin stelkleurenin stelkleurin stelkolommenin stelkopin stelkopnummerin stelkoppeltekenin stelkoppenin stelkoptekstin stelkorpsin stelkorpsomgevingin stellabeltekstin stellayoutin stellegendain stellijndiktein stellijstin stelmargeblokkenin stelmarkeringin stelnaastplaatsenin stelnummerenin stelomlijndin stelonderin stelonderstrepenin stelondertekstenin stelopmaakin stelpaginanummerin stelpaginanummeringin stelpaginaovergangenin stelpaletin stelpapierformaatin stelpapierin stelparagraafnummerenin stelplaatsblokin stelplaatsblokkenin stelplaatsbloksplitsenin stelpositionerenin stelprofielenin stelprogrammasin stelpublicatiesin stelrastersin stelreferentielijstin stelrefererenin stelregelnummerenin stelregelsin stelregisterin stelroterenin stelsamengesteldelijstin stelsectieblokin stelsectiein stelsmallerin stelsorterenin stelspatieringin stelstrutin stelsubpaginanummerin stelsymboolsetin stelsynchronisatiebalkin stelsynchronisatiein stelsynoniemenin stelsysteemin steltaalin steltabellenin steltabin steltabulatiein steltekstin steltekstinhoudin steltekstlijnenin stelteksttekstenin steltolerantiein steltypein steltypenin steluitlijnenin steluitvoerin stelurlin stelveldenin stelveldin stelversiesin stelvoetin stelvoetnootdefinitiein stelvoetnotenin stelvoettekstenin stelwitruimtein stopachtergrond stopalignment stopbuffer stopbuffer stopcitaat stopcolumns stopcombination stopcommentaar stopdescription stopdocument stopenumeration stopfigure stopfloattext stopformula stopframedtext stopgeg stophiding stopinteractiemenu stopitemgroup stopkantlijn stopkleur stoplegend stopline stoplinecorrection stoplinenumbering stoplines stoplocal stoplocalenvironment stoplocalfootnotes stopmakeup stopmarginblock stopnamemakeup stopnarrower stopomgeving stoponderdeel stopopelkaar stopopposite stopoverlay stopoverview stopparagraph stoppositioning stoppostponing stopprodukt stopprofile stopprojekt stopsymbolset stopsynchronization stoptable stoptables stoptabulate stoptekstlijn stoptyping stopunpacked stopversie sub subject subsection subsubject subsubsection subsubsubject suggestie switchnaarkorps sym symbool synchronisatiebalk synchroniseer synonym taal tab tekstlijn tekstreferentie tex title toonexternefiguren toongrid tooninstellingen toonkader toonkleur toonkleurgroep toonkorps toonkorpsomgeving toonlayout toonopmaak toonpalet toonprint toonstruts toonsymboolset toonvelden typ type typebuffer typefile uit uitgerekt underbar underbars usecodering usedirectory vastespaties veld veldstapel verbergblokken vergelijkkleurgroep vergelijkpalet verplaatsopgrid versie vertaal verwerkblokken verwerkpagina vl voetnoot voetnoottekst volgprofiel volgprofielversie volgversie volledigregister weekdag wiskunde witruimte woordrechts \ No newline at end of file
+keywordclass.macros.context.nl=CAP Cap Caps Letter Letters MAAND Romeins WEEKDAG WOORD WOORDEN Woord Woorden about achtergrond appendix bepaalkopnummer bepaallijstkenmerken blanko blokje blokjes blokkeerinteractiemenu bookmark breuk but button cap chapter chem cijfers citaat citeer clip comment completecombinedlist completelistoffloats completelistofsorts completelistofsynonyms converteernummer copieerveld corrigeerwitruimte coupledregister crlf datum definebodyfontDEF definebodyfontREF definedfont definefontfeature definefonthandling definetypeface definieer definieeralineas definieerbeeldmerk definieerblanko definieerblok definieerbuffer definieerconversie definieerfiguursymbool definieerfont definieerfontsynoniem definieerinteractiemenu definieerinteractiemenu definieerkadertekst definieerkleur definieerkleurgroep definieerkop definieerkorps definieerkorpsomgeving definieerlijst definieermarkering definieeromlijnd definieeropmaak definieeroverlay definieerpalet definieerpapierformaat definieerplaatsblok definieerprofiel definieerprogramma definieerreferentie definieerreferentieformaat definieerreferentielijst definieerregister definieersamengesteldelijst definieersectie definieersectieblok definieersorteren definieerstartstop definieersubveld definieersymbool definieersynoniemen definieertabelvorm definieertabulatie definieertekst definieertype definieertypen definieeruitvoer definieerveld definieerveldstapel definieerversie description doordefinieren doorlabelen doornummeren doorspringen dunnelijn dunnelijnen eenregel enumeration ergens externfiguur forceerblokken framedtext gebruikURL gebruikblokken gebruikcommandos gebruikexterndocument gebruikexternefile gebruikexternefiles gebruikexternfiguur gebruikexterngeluidsfragment gebruikmodule gebruikreferenties gebruikspecials gebruiksymbolen gebruiktypescript gebruiktypescriptfile geenblokkenmeer geenbovenenonderregels geenfilesmeer geenhoofdenvoetregels geenlijst geenmarkering geenspatie geenwitruimte grijskleur haalbuffer haalmarkering haarlijn handhaafblokken hl hoofdtaal hoog huidigedatum huidigekopnummer in inanderemarge inbinnen inbuiten indentation inlijnd inlinker inmarge inrechter inregel inspringen installeertaal interactiebalk interactiebuttons invullijnen invulregel invultekst invulveld items its kantlijn kenmerk kenmerkdatum kleur kloonveld kolom kop kopnummer koppeldocument koppelmarkering koppelpagina koppelpapier koppelregister koptekst laag labeling labels labeltekst laho legeregels letter letters lijstsymbool loadsorts loadsynonyms maand mapfontsize mar margetekst markeer markeerversie mediaeval naar naarbox name nextsection nietinspringen nocap noot nop omlaag omlijnd ontkoppelmarkering op opelkaar oppagina overbar overbars overstrike overstrikes pagina paginareferentie paragraph part paslayoutaan passeerblokken passendveld plaatsbeeldmerken plaatsbookmarks plaatsformule plaatslegenda plaatslijst plaatslokalevoetnoten plaatsnaastelkaar plaatsonderelkaar plaatsopgrid plaatsplaatsblok plaatsreferentielijst plaatsregister plaatsregister plaatssamengesteldelijst plaatssamengesteldelijst plaatssubformule plaatsvoetnoten placelistoffloats placelistofsorts placelistofsynonyms positioneer programma publicatie punten ran ref referentie regellinks regelmidden regelrechts register registreervelden reservefloat reset resetmarkering resettextcontent romeins rooster roteer schaal scherm schrijfnaarlijst schrijfnaarreferentielijst schrijfnaarregister schrijftussenlijst section seeregister selecteerblokken selecteerpapier selecteerversie setupfonthandling setupfontsynonym setupinterlinespace2 setuplistalternative som soortpagina sort spatie spiegel splitsplaatsblok startachtergrond startalignment startbuffer startbuffer startcitaat startcolumns startcombination startcomment startdescription startdocument startenumeration startfigure startfloattext startformula startframedtext startgeg starthiding startinteractiemenu startitemgroup startkantlijn startkleur startlegend startline startlinecorrection startlinenumbering startlines startlocal startlocalenvironment startlocalfootnotes startmakeup startmarginblock startnamemakeup startnarrower startomgeving startonderdeel startopelkaar startopposite startoverlay startoverview startparagraph startpositioning startpostponing startprodukt startprofile startprojekt startregister startsymbolset startsynchronization starttable starttables starttabulate starttekstlijn starttyping startunpacked startversie stelachtergrondenin stelachtergrondin stelalineasin stelarrangerenin stelblankoin stelblokin stelblokjesin stelblokkopjein stelblokkopjesin stelbovenin stelboventekstenin stelbufferin stelbuttonsin stelciterenin stelclipin stelcombinatiesin stelcommentaarin steldoordefinierenin steldoornummerenin steldoorspringenin steldunnelijnenin stelexternefigurenin stelformulesin stelformulierenin stelhoofdin stelhoofdtekstenin stelinmargein stelinspringenin stelinteractiebalkin stelinteractiein stelinteractiemenuin stelinteractieschermin stelinterliniein stelinvullijnenin stelinvulregelsin stelitemgroepin stelitemsin stelkadertekstenin stelkantlijnin stelkapitalenin stelkleurenin stelkleurin stelkolommenin stelkopin stelkopnummerin stelkoppeltekenin stelkoppenin stelkoptekstin stelkorpsin stelkorpsomgevingin stellabeltekstin stellayoutin stellegendain stellijndiktein stellijstin stelmargeblokkenin stelmarkeringin stelnaastplaatsenin stelnummerenin stelomlijndin stelonderin stelonderstrepenin stelondertekstenin stelopmaakin stelpaginanummerin stelpaginanummeringin stelpaginaovergangenin stelpaletin stelpapierformaatin stelpapierin stelparagraafnummerenin stelplaatsblokin stelplaatsblokkenin stelplaatsbloksplitsenin stelpositionerenin stelprofielenin stelprogrammasin stelpublicatiesin stelrastersin stelreferentielijstin stelrefererenin stelregelnummerenin stelregelsin stelregisterin stelroterenin stelsamengesteldelijstin stelsectieblokin stelsectiein stelsmallerin stelsorterenin stelspatieringin stelstrutin stelsubpaginanummerin stelsymboolsetin stelsynchronisatiebalkin stelsynchronisatiein stelsynoniemenin stelsysteemin steltaalin steltabellenin steltabin steltabulatiein steltekstin steltekstinhoudin steltekstlijnenin stelteksttekstenin steltolerantiein steltypein steltypenin steluitlijnenin steluitvoerin stelurlin stelveldenin stelveldin stelversiesin stelvoetin stelvoetnootdefinitiein stelvoetnotenin stelvoettekstenin stelwitruimtein stopachtergrond stopalignment stopbuffer stopbuffer stopcitaat stopcolumns stopcombination stopcomment stopdescription stopdocument stopenumeration stopfigure stopfloattext stopformula stopframedtext stopgeg stophiding stopinteractiemenu stopitemgroup stopkantlijn stopkleur stoplegend stopline stoplinecorrection stoplinenumbering stoplines stoplocal stoplocalenvironment stoplocalfootnotes stopmakeup stopmarginblock stopnamemakeup stopnarrower stopomgeving stoponderdeel stopopelkaar stopopposite stopoverlay stopoverview stopparagraph stoppositioning stoppostponing stopprodukt stopprofile stopprojekt stopsymbolset stopsynchronization stoptable stoptables stoptabulate stoptekstlijn stoptyping stopunpacked stopversie sub subject subsection subsubject subsubsection subsubsubject suggestie switchnaarkorps sym symbool synchronisatiebalk synchroniseer synonym taal tab tekstlijn tekstreferentie tex title toonexternefiguren toongrid tooninstellingen toonkader toonkleur toonkleurgroep toonkorps toonkorpsomgeving toonlayout toonopmaak toonpalet toonprint toonstruts toonsymboolset toonvelden typ type typebuffer typefile uit uitgerekt underbar underbars usecodering usedirectory vastespaties veld veldstapel verbergblokken vergelijkkleurgroep vergelijkpalet verplaatsopgrid versie vertaal verwerkblokken verwerkpagina vl voetnoot voetnoottekst volgprofiel volgprofielversie volgversie volledigregister weekdag wiskunde witruimte woordrechts \ No newline at end of file
diff --git a/context/data/scite/cont-pe-scite.properties b/context/data/scite/cont-pe-scite.properties
index a17695725..c89f52b8f 100644
--- a/context/data/scite/cont-pe-scite.properties
+++ b/context/data/scite/cont-pe-scite.properties
@@ -1 +1 @@
-keywordclass.macros.context.pe=CAP Cap Caps Character Characters MONTH Romannumerals WEEKDAY WORD WORDS Word Words appendix cap chapter chem completecombinedlist completelistoffloats completelistofsorts completelistofsynonyms coupledregister crlf definebodyfontDEF definebodyfontREF definedfont definefontfeature definefonthandling definetypeface description enumeration framedtext indentation its labeling loadsorts loadsynonyms mapfontsize mediaeval name nextsection nocap overbar overbars overstrike overstrikes paragraph part placelistoffloats placelistofsorts placelistofsynonyms ran register reservefloat resettextcontent section seeregister setupcapitals setupfonthandling setupfontsynonym setupinterlinespace2 setuplistalternative setupurl sort startalignment startbuffer startbuffer startcolumns startcombination startdescription startdocument startenumeration startfigure startfloattext startformula startframedtext starthiding startitemgroup startlegend startline startlinecorrection startlinenumbering startlines startlocal startlocalenvironment startlocalfootnotes startmakeup startmarginblock startnamemakeup startnarrower startopposite startoverlay startoverview startparagraph startpositioning startpostponing startprofile startregister startsymbolset startsynchronization starttable starttables starttabulate starttyping startunpacked startتوضیح startتولید startحقیقت startخط‌حاشیه startخط‌متن startرنگ startفشرده startمحیط startمنوی‌پانل startمولفه startنسخه startنقل‌قول startپروژه startپس‌زمینه stopalignment stopbuffer stopbuffer stopcolumns stopcombination stopdescription stopdocument stopenumeration stopfigure stopfloattext stopformula stopframedtext stophiding stopitemgroup stoplegend stopline stoplinecorrection stoplinenumbering stoplines stoplocal stoplocalenvironment stoplocalfootnotes stopmakeup stopmarginblock stopnamemakeup stopnarrower stopopposite stopoverlay stopoverview stopparagraph stoppositioning stoppostponing stopprofile stopsymbolset stopsynchronization stoptable stoptables stoptabulate stoptyping stopunpacked stopتوضیح stopتولید stopحقیقت stopخط‌حاشیه stopخط‌متن stopرنگ stopفشرده stopمحیط stopمنوی‌پانل stopمولفه stopنسخه stopنقل‌قول stopپروژه stopپس‌زمینه sub subject subsection subsubject subsubsection subsubsubject synonym title tooltip typ underbar underbars useURL usedirectory آیتم آیتمها آینه اجباربلوکها از ازکارانداختن‌منوی‌پانل استفاده‌بلوکها استفاده‌دستخط‌تایپ استفاده‌رمزینه استفاده‌شکل‌خارجی استفاده‌فرمانها استفاده‌قطعه‌موزیک‌خارجی استفاده‌مدول استفاده‌مرجعها استفاده‌نمادها استفاده‌نوشتارخارجی استفاده‌ویژگیها استفاده‌پرونده‌خارجی استفاده‌پرونده‌دستخط‌تایپ استفاده‌پرونده‌های‌خارجی اعدادلاتین اما انتخاب‌برگ انتخاب‌بلوکها انتخاب‌نسخه انتقال‌به‌توری بارگذاری‌آرایش بارگذاری‌آیتمها بارگذاری‌ارجاع بارگذاری‌اندازه‌برگ بارگذاری‌باریکتر بارگذاری‌بافر بارگذاری‌بالا بارگذاری‌بخش بارگذاری‌بردباری بارگذاری‌برنامه‌ها بارگذاری‌برگ بارگذاری‌بست بارگذاری‌بلوک بارگذاری‌بلوکهای‌حاشیه بارگذاری‌بلوک‌بخش بارگذاری‌تایپ بارگذاری‌تایپ‌کردن بارگذاری‌تب بارگذاری‌ترتیب بارگذاری‌ترتیب بارگذاری‌ترکیب‌ها بارگذاری‌تطابق بارگذاری‌تعریف‌پانوشت بارگذاری‌تنظیم بارگذاری‌ته‌برگ بارگذاری‌تورفتگی بارگذاری‌تورفتگیها بارگذاری‌توضیح بارگذاری‌ثبت بارگذاری‌جدولها بارگذاری‌جدول‌بندی بارگذاری‌خالی بارگذاری‌خروجی بارگذاری‌خطها بارگذاری‌خطهای‌حاشیه بارگذاری‌خطهای‌سیاه بارگذاری‌خطهای‌متن بارگذاری‌خطها‌ی‌نازک بارگذاری‌درج‌درخطها بارگذاری‌درج‌مخالف بارگذاری‌درون‌حاشیه بارگذاری‌دوران بارگذاری‌دکمه‌ها بارگذاری‌راهنما بارگذاری‌رنگ بارگذاری‌رنگها بارگذاری‌زبان بارگذاری‌ستونها بارگذاری‌سر بارگذاری‌سربرگ بارگذاری‌سرها بارگذاری‌سیستم بارگذاری‌شرح بارگذاری‌شرح بارگذاری‌شرحها بارگذاری‌شماره‌زیرصفحه بارگذاری‌شماره‌سر بارگذاری‌شماره‌صفحه بارگذاری‌شماره‌گذاری بارگذاری‌شماره‌گذاریها بارگذاری‌شماره‌گذاری‌صفحه بارگذاری‌شماره‌گذاری‌پاراگراف بارگذاری‌شماره‌‌گذاری‌خط بارگذاری‌شناور بارگذاری‌شناورها بارگذاری‌شکافتن‌شناورها بارگذاری‌شکلهای‌خارجی بارگذاری‌طرح بارگذاری‌طرح‌بندی بارگذاری‌عرض‌خط بارگذاری‌فاصله‌بین‌خط بارگذاری‌فرمولها بارگذاری‌فضای‌سفید بارگذاری‌فضا‌گذاری بارگذاری‌قالبی بارگذاری‌قلم‌متن بارگذاری‌لوح بارگذاری‌لیست بارگذاری‌لیست‌ترکیبی بارگذاری‌لیست‌مرجع بارگذاری‌مترادفها بارگذاری‌متن بارگذاری‌متنهای‌بالا بارگذاری‌متن‌سر بارگذاری‌متن‌سربرگ بارگذاری‌متن‌قالبی بارگذاری‌متن‌متنها بارگذاری‌متن‌پانوشت بارگذاری‌متن‌پایین بارگذاری‌مجموعه‌نماد بارگذاری‌محیط‌قلم‌متن بارگذاری‌منوی‌پانل بارگذاری‌مکان‌گذاری بارگذاری‌میدان بارگذاری‌میدانها بارگذاری‌میله‌تطابق بارگذاری‌میله‌زیر بارگذاری‌میله‌پانل بارگذاری‌نسخه‌ها بارگذاری‌نشانه‌شکستن بارگذاری‌نشانه‌گذاری بارگذاری‌نشرها بارگذاری‌نقل بارگذاری‌پاراگرافها بارگذاری‌پانل بارگذاری‌پانوشتها بارگذاری‌پایین بارگذاری‌پرده‌ها بارگذاری‌پرده‌پانل بارگذاری‌پروفایلها بارگذاری‌پرکردن‌خطها بارگذاری‌پس‌زمینه بارگذاری‌پس‌زمینه‌ها بارگذاری‌چیدن بارگذاری‌گذارصفحه بارگذاری‌گروه‌آیتم بازنشانی بازنشانی‌نشانه‌گذاری باگذاری‌متن‌برچسب بدون‌بلوکهای‌بیشتر بدون‌تورفتگی بدون‌خط‌بالاوپایین بدون‌خط‌سروته‌برگ بدون‌فایلهای‌بیشتر بدون‌فضا بدون‌فضای‌سفید بدون‌لیست بدون‌نشانه‌گذاری برنامه بروبه بروبه‌جعبه بروپایین برچسبها بلند بلوکهای‌پردازش بلوکها‌پنهان بنویس‌بین‌لیست بنویس‌درثبت بنویس‌درلیست‌مرجع بنویس‌در‌لیست تاریخ تاریخ‌جاری تاریخ‌رجوع تایپ تایپ‌بافر تایپ‌پرونده تب ترجمه تطابق تعریف تعریف‌آرایش تعریف‌آرم تعریف‌الگوی‌جدول تعریف‌اندازه‌برگ تعریف‌بافر تعریف‌بخش تعریف‌برنامه تعریف‌برچسب تعریف‌بلوک تعریف‌بلوک‌بخش تعریف‌تایپ تعریف‌تایپ‌کردن تعریف‌تبدیل تعریف‌ترتیب تعریف‌توده‌میدان تعریف‌تورفتگی تعریف‌ثبت تعریف‌جدول‌بندی تعریف‌خالی تعریف‌خروجی تعریف‌رنگ تعریف‌زیرمیدان تعریف‌سر تعریف‌شرح تعریف‌شروع‌پایان تعریف‌شماره‌بندی تعریف‌شمایل‌مرجع تعریف‌شناور تعریف‌قالبی تعریف‌قلم تعریف‌قلم‌متن تعریف‌لوح تعریف‌لیست تعریف‌لیست‌ترکیبی تعریف‌لیست‌مرجع تعریف‌مترادفها تعریف‌مترادف‌قلم تعریف‌متن تعریف‌متن‌قالبی تعریف‌محیط‌قلم‌بدنه تعریف‌مرجع تعریف‌منوی‌پانل تعریف‌منوی‌پانل تعریف‌میدان تعریف‌نسخه تعریف‌نشانه‌گذاری تعریف‌نماد تعریف‌نمادشکل تعریف‌پاراگرافها تعریف‌پروفایل تعریف‌پوشش تعریف‌گروه‌رنگ تعیین‌شماره‌سر تعیین‌محتوای‌متن تعیین‌مشخصات‌لیست تغییربه‌قلم‌بدنه تنظیم‌راست تنظیم‌طرح‌بندی تنظیم‌وسط تورفتگی توری توضیح تک ثبت‌زوج ثبت‌کامل جداسازی‌نشانه‌گذاری حاش حرف حرفها حفظ‌بلوکها خالی خطهای‌سیاه خطهای‌نازک خطها‌خالی خط‌حاشیه خط‌سیاه خط‌متن خط‌مو خط‌نازک خ‌ا خ‌ع در درج‌آرمها درج‌ثبت درج‌ثبت درج‌درخط درج‌درخطها درج‌درمتن درج‌درمیدان درج‌در‌بالای‌یکدیگر درج‌در‌توری درج‌راهنما درج‌زیرفرمول درج‌شناور درج‌فرمول درج‌لیست درج‌لیست‌مختلط درج‌لیست‌مختلط درج‌لیست‌مرجع درج‌پانوشتها درج‌پانوشتهای‌موضعی درج‌چوب‌خط درج‌کنار‌به‌کنار درحاشیه درحاشیه‌دیگر درخارجی درخط درداخلی درراست درصفحه درقالبی درمورد درون درچپ دریافت‌بافر دریافت‌نشانه دوران دکمه دکمه‌پانل رج رجوع رنگ رنگ‌خاکستری روزهفته ریاضی زبان زبان‌اصلی ستون سر شماره‌سر شماره‌سرجاری شماره‌مبدل شماره‌ها شکافتن‌شناور شکل‌خارجی صفحه صفحه‌زوج صفحه‌پردازش عبوربلوکها فشرده فضا فضاهای‌ثابت فضای‌سفید فضای‌سفیدصحیح قالبی لوح‌مقایسه ماه متن‌برچسب متن‌حاشیه متن‌سر متن‌پانوشت مرجع مرجع‌صفحه مرجع‌متن مقایسه‌گروه‌رنگ مقیاس منفی مکان میدان میدانهای‌گزارش میدان‌شبیه‌سازی میدان‌پشته میدان‌کپی میله‌تطابق میله‌پانل نسخه نسخه‌نشانه نشانه‌گذاری نشانه‌گذاری‌زوج نشر نصب‌زبان نقطه‌ها نقل نقل‌قول نم نماد نمادلیست نمایش‌آرایش نمایش‌بارگذاریها نمایش‌بستها نمایش‌توری نمایش‌رنگ نمایش‌شکلهای‌خارجی نمایش‌طرح‌بندی نمایش‌قالب نمایش‌قلم‌بدنه نمایش‌لوح نمایش‌مجموعه‌علامت نمایش‌محیط‌قلم‌بدنه نمایش‌میدانها نمایش‌چاپ نمایش‌گروه‌رنگ نوشتارزوج نوع‌صفحه پابا پانوشت پایین پرده پرکردن‌میدان پس‌زمینه پیروی‌نسخه پیروی‌نسخه‌پروفایل پیروی‌پروفایل چوبخط چپ‌چین کاغذزوج کسر کشیده کلمه‌راست گیره یادداشت یک‌جا یک‌خط \ No newline at end of file
+keywordclass.macros.context.pe=CAP Cap Caps Character Characters MONTH Romannumerals WEEKDAY WORD WORDS Word Words appendix cap chapter chem comment completecombinedlist completelistoffloats completelistofsorts completelistofsynonyms coupledregister crlf definebodyfontDEF definebodyfontREF definedfont definefontfeature definefonthandling definetypeface description enumeration framedtext indentation its labeling loadsorts loadsynonyms mapfontsize mediaeval name nextsection nocap overbar overbars overstrike overstrikes paragraph part placelistoffloats placelistofsorts placelistofsynonyms ran register reservefloat resettextcontent section seeregister setupcapitals setupfonthandling setupfontsynonym setupinterlinespace2 setuplistalternative setupurl sort startalignment startbuffer startbuffer startcolumns startcombination startcomment startdescription startdocument startenumeration startfigure startfloattext startformula startframedtext starthiding startitemgroup startlegend startline startlinecorrection startlinenumbering startlines startlocal startlocalenvironment startlocalfootnotes startmakeup startmarginblock startnamemakeup startnarrower startopposite startoverlay startoverview startparagraph startpositioning startpostponing startprofile startregister startsymbolset startsynchronization starttable starttables starttabulate starttyping startunpacked startتولید startحقیقت startخط‌حاشیه startخط‌متن startرنگ startفشرده startمحیط startمنوی‌پانل startمولفه startنسخه startنقل‌قول startپروژه startپس‌زمینه stopalignment stopbuffer stopbuffer stopcolumns stopcombination stopcomment stopdescription stopdocument stopenumeration stopfigure stopfloattext stopformula stopframedtext stophiding stopitemgroup stoplegend stopline stoplinecorrection stoplinenumbering stoplines stoplocal stoplocalenvironment stoplocalfootnotes stopmakeup stopmarginblock stopnamemakeup stopnarrower stopopposite stopoverlay stopoverview stopparagraph stoppositioning stoppostponing stopprofile stopsymbolset stopsynchronization stoptable stoptables stoptabulate stoptyping stopunpacked stopتولید stopحقیقت stopخط‌حاشیه stopخط‌متن stopرنگ stopفشرده stopمحیط stopمنوی‌پانل stopمولفه stopنسخه stopنقل‌قول stopپروژه stopپس‌زمینه sub subject subsection subsubject subsubsection subsubsubject synonym title tooltip typ underbar underbars useURL usedirectory آیتم آیتمها آینه اجباربلوکها از ازکارانداختن‌منوی‌پانل استفاده‌بلوکها استفاده‌دستخط‌تایپ استفاده‌رمزینه استفاده‌شکل‌خارجی استفاده‌فرمانها استفاده‌قطعه‌موزیک‌خارجی استفاده‌مدول استفاده‌مرجعها استفاده‌نمادها استفاده‌نوشتارخارجی استفاده‌ویژگیها استفاده‌پرونده‌خارجی استفاده‌پرونده‌دستخط‌تایپ استفاده‌پرونده‌های‌خارجی اعدادلاتین اما انتخاب‌برگ انتخاب‌بلوکها انتخاب‌نسخه انتقال‌به‌توری بارگذاری‌آرایش بارگذاری‌آیتمها بارگذاری‌ارجاع بارگذاری‌اندازه‌برگ بارگذاری‌باریکتر بارگذاری‌بافر بارگذاری‌بالا بارگذاری‌بخش بارگذاری‌بردباری بارگذاری‌برنامه‌ها بارگذاری‌برگ بارگذاری‌بست بارگذاری‌بلوک بارگذاری‌بلوکهای‌حاشیه بارگذاری‌بلوک‌بخش بارگذاری‌تایپ بارگذاری‌تایپ‌کردن بارگذاری‌تب بارگذاری‌ترتیب بارگذاری‌ترتیب بارگذاری‌ترکیب‌ها بارگذاری‌تطابق بارگذاری‌تعریف‌پانوشت بارگذاری‌تنظیم بارگذاری‌ته‌برگ بارگذاری‌تورفتگی بارگذاری‌تورفتگیها بارگذاری‌توضیح بارگذاری‌ثبت بارگذاری‌جدولها بارگذاری‌جدول‌بندی بارگذاری‌خالی بارگذاری‌خروجی بارگذاری‌خطها بارگذاری‌خطهای‌حاشیه بارگذاری‌خطهای‌سیاه بارگذاری‌خطهای‌متن بارگذاری‌خطها‌ی‌نازک بارگذاری‌درج‌درخطها بارگذاری‌درج‌مخالف بارگذاری‌درون‌حاشیه بارگذاری‌دوران بارگذاری‌دکمه‌ها بارگذاری‌راهنما بارگذاری‌رنگ بارگذاری‌رنگها بارگذاری‌زبان بارگذاری‌ستونها بارگذاری‌سر بارگذاری‌سربرگ بارگذاری‌سرها بارگذاری‌سیستم بارگذاری‌شرح بارگذاری‌شرح بارگذاری‌شرحها بارگذاری‌شماره‌زیرصفحه بارگذاری‌شماره‌سر بارگذاری‌شماره‌صفحه بارگذاری‌شماره‌گذاری بارگذاری‌شماره‌گذاریها بارگذاری‌شماره‌گذاری‌صفحه بارگذاری‌شماره‌گذاری‌پاراگراف بارگذاری‌شماره‌‌گذاری‌خط بارگذاری‌شناور بارگذاری‌شناورها بارگذاری‌شکافتن‌شناورها بارگذاری‌شکلهای‌خارجی بارگذاری‌طرح بارگذاری‌طرح‌بندی بارگذاری‌عرض‌خط بارگذاری‌فاصله‌بین‌خط بارگذاری‌فرمولها بارگذاری‌فضای‌سفید بارگذاری‌فضا‌گذاری بارگذاری‌قالبی بارگذاری‌قلم‌متن بارگذاری‌لوح بارگذاری‌لیست بارگذاری‌لیست‌ترکیبی بارگذاری‌لیست‌مرجع بارگذاری‌مترادفها بارگذاری‌متن بارگذاری‌متنهای‌بالا بارگذاری‌متن‌سر بارگذاری‌متن‌سربرگ بارگذاری‌متن‌قالبی بارگذاری‌متن‌متنها بارگذاری‌متن‌پانوشت بارگذاری‌متن‌پایین بارگذاری‌مجموعه‌نماد بارگذاری‌محیط‌قلم‌متن بارگذاری‌منوی‌پانل بارگذاری‌مکان‌گذاری بارگذاری‌میدان بارگذاری‌میدانها بارگذاری‌میله‌تطابق بارگذاری‌میله‌زیر بارگذاری‌میله‌پانل بارگذاری‌نسخه‌ها بارگذاری‌نشانه‌شکستن بارگذاری‌نشانه‌گذاری بارگذاری‌نشرها بارگذاری‌نقل بارگذاری‌پاراگرافها بارگذاری‌پانل بارگذاری‌پانوشتها بارگذاری‌پایین بارگذاری‌پرده‌ها بارگذاری‌پرده‌پانل بارگذاری‌پروفایلها بارگذاری‌پرکردن‌خطها بارگذاری‌پس‌زمینه بارگذاری‌پس‌زمینه‌ها بارگذاری‌چیدن بارگذاری‌گذارصفحه بارگذاری‌گروه‌آیتم بازنشانی بازنشانی‌نشانه‌گذاری باگذاری‌متن‌برچسب بدون‌بلوکهای‌بیشتر بدون‌تورفتگی بدون‌خط‌بالاوپایین بدون‌خط‌سروته‌برگ بدون‌فایلهای‌بیشتر بدون‌فضا بدون‌فضای‌سفید بدون‌لیست بدون‌نشانه‌گذاری برنامه بروبه بروبه‌جعبه بروپایین برچسبها بلند بلوکهای‌پردازش بلوکها‌پنهان بنویس‌بین‌لیست بنویس‌درثبت بنویس‌درلیست‌مرجع بنویس‌در‌لیست تاریخ تاریخ‌جاری تاریخ‌رجوع تایپ تایپ‌بافر تایپ‌پرونده تب ترجمه تطابق تعریف تعریف‌آرایش تعریف‌آرم تعریف‌الگوی‌جدول تعریف‌اندازه‌برگ تعریف‌بافر تعریف‌بخش تعریف‌برنامه تعریف‌برچسب تعریف‌بلوک تعریف‌بلوک‌بخش تعریف‌تایپ تعریف‌تایپ‌کردن تعریف‌تبدیل تعریف‌ترتیب تعریف‌توده‌میدان تعریف‌تورفتگی تعریف‌ثبت تعریف‌جدول‌بندی تعریف‌خالی تعریف‌خروجی تعریف‌رنگ تعریف‌زیرمیدان تعریف‌سر تعریف‌شرح تعریف‌شروع‌پایان تعریف‌شماره‌بندی تعریف‌شمایل‌مرجع تعریف‌شناور تعریف‌قالبی تعریف‌قلم تعریف‌قلم‌متن تعریف‌لوح تعریف‌لیست تعریف‌لیست‌ترکیبی تعریف‌لیست‌مرجع تعریف‌مترادفها تعریف‌مترادف‌قلم تعریف‌متن تعریف‌متن‌قالبی تعریف‌محیط‌قلم‌بدنه تعریف‌مرجع تعریف‌منوی‌پانل تعریف‌منوی‌پانل تعریف‌میدان تعریف‌نسخه تعریف‌نشانه‌گذاری تعریف‌نماد تعریف‌نمادشکل تعریف‌پاراگرافها تعریف‌پروفایل تعریف‌پوشش تعریف‌گروه‌رنگ تعیین‌شماره‌سر تعیین‌محتوای‌متن تعیین‌مشخصات‌لیست تغییربه‌قلم‌بدنه تنظیم‌راست تنظیم‌طرح‌بندی تنظیم‌وسط تورفتگی توری تک ثبت‌زوج ثبت‌کامل جداسازی‌نشانه‌گذاری حاش حرف حرفها حفظ‌بلوکها خالی خطهای‌سیاه خطهای‌نازک خطها‌خالی خط‌حاشیه خط‌سیاه خط‌متن خط‌مو خط‌نازک خ‌ا خ‌ع در درج‌آرمها درج‌ثبت درج‌ثبت درج‌درخط درج‌درخطها درج‌درمتن درج‌درمیدان درج‌در‌بالای‌یکدیگر درج‌در‌توری درج‌راهنما درج‌زیرفرمول درج‌شناور درج‌فرمول درج‌لیست درج‌لیست‌مختلط درج‌لیست‌مختلط درج‌لیست‌مرجع درج‌پانوشتها درج‌پانوشتهای‌موضعی درج‌چوب‌خط درج‌کنار‌به‌کنار درحاشیه درحاشیه‌دیگر درخارجی درخط درداخلی درراست درصفحه درقالبی درمورد درون درچپ دریافت‌بافر دریافت‌نشانه دوران دکمه دکمه‌پانل رج رجوع رنگ رنگ‌خاکستری روزهفته ریاضی زبان زبان‌اصلی ستون سر شماره‌سر شماره‌سرجاری شماره‌مبدل شماره‌ها شکافتن‌شناور شکل‌خارجی صفحه صفحه‌زوج صفحه‌پردازش عبوربلوکها فشرده فضا فضاهای‌ثابت فضای‌سفید فضای‌سفیدصحیح قالبی لوح‌مقایسه ماه متن‌برچسب متن‌حاشیه متن‌سر متن‌پانوشت مرجع مرجع‌صفحه مرجع‌متن مقایسه‌گروه‌رنگ مقیاس منفی مکان میدان میدانهای‌گزارش میدان‌شبیه‌سازی میدان‌پشته میدان‌کپی میله‌تطابق میله‌پانل نسخه نسخه‌نشانه نشانه‌گذاری نشانه‌گذاری‌زوج نشر نصب‌زبان نقطه‌ها نقل نقل‌قول نم نماد نمادلیست نمایش‌آرایش نمایش‌بارگذاریها نمایش‌بستها نمایش‌توری نمایش‌رنگ نمایش‌شکلهای‌خارجی نمایش‌طرح‌بندی نمایش‌قالب نمایش‌قلم‌بدنه نمایش‌لوح نمایش‌مجموعه‌علامت نمایش‌محیط‌قلم‌بدنه نمایش‌میدانها نمایش‌چاپ نمایش‌گروه‌رنگ نوشتارزوج نوع‌صفحه پابا پانوشت پایین پرده پرکردن‌میدان پس‌زمینه پیروی‌نسخه پیروی‌نسخه‌پروفایل پیروی‌پروفایل چوبخط چپ‌چین کاغذزوج کسر کشیده کلمه‌راست گیره یادداشت یک‌جا یک‌خط \ No newline at end of file
diff --git a/context/data/scite/cont-ro-scite.properties b/context/data/scite/cont-ro-scite.properties
index 47fd2b9c3..3f9cc57e1 100644
--- a/context/data/scite/cont-ro-scite.properties
+++ b/context/data/scite/cont-ro-scite.properties
@@ -1 +1 @@
-keywordclass.macros.context.ro=CAP CUVANT CUVINTE Cap Caps Cuvant Cuvinte LUNA Litera Litere Numereromane ZIDINSAPTAMANA adapteazaaspect adubuffer adumarcaje afiseazaaspect afiseazacampuri afiseazaculoare afiseazafiguriexterne afiseazafonttext afiseazagrid afiseazagrupculoare afiseazamakeup afiseazamediufonttext afiseazapaleta afiseazarama afiseazasetari afiseazasetsimboluri afiseazastruts afiseazatiparire aliniat aliniatcentru aliniatdreapta aliniatstanga appendix ascundeblocuri barainteractiune barasincronizare blanc but butoaneinteractiune buton camp campumplere cap chapter chem citat clip cloneazacamp coloana comentariu comparagrupculoare comparapaleta completecombinedlist completelistoffloats completelistofsorts completelistofsynonyms completeregister convertestenumar copiazacamp corecteazaspatiualb coupledregister crlf culoare culoaregri cupleazadocument cupleazamarcaje cupleazaregistru cuvantdreapta data datacurenta datareferit decupleazamarcaje definebodyfontDEF definebodyfontREF definedfont definefontfeature definefonthandling defineste definestealiat definesteantet definesteblanc definestebloc definesteblocsectiune definestebuffer definestecamp definesteconversie definesteculoare definestedescriere definestedimensiunehartie definesteenumerare definesteeticheta definestefloat definestefont definestefonttext definesteformatreferinte definestegrupculori definesteinconjurare definestelista definestelistacombinata definestelistareferinte definestelogo definestemakeup definestemarcaje definestemediulfonttext definestemeniuinteractiune definestemeniuinteractiune definesteoutput definesteoverlay definestepaleta definesteparagraf definesteprofil definesteprogram definestereferinte definesteregistru definestesablontabel definestesectiune definestesimbol definestesimbolfigura definestesinonim definestesinonimfont definestesortare definestestartstop definestestivacampuri definestesubcamp definestetabulatori definestetext definestetexteinconjurate definestetextinconjurat definestetyping definesteversiune definetype definetypeface description despre determinacaracteristicilelistei determinanumartitlu dezactiveazameniuinteractiune din dute dutebox ecran el element element emptylines enumeration etichete faraaliniat farafisiere faraliniiantetsisubsol faraliniisussijos faralista faramarcaje faraspatiu faraspatiualb figuraexterna firdepar folosesteURL folosestebloc folosestecodificarea folosestecomenzi folosestedocumentextern folosestefiguraexterna folosestefisiereexterne folosestefisierextern folosestemodul folosestemuzicaexterna folosestereferinte folosestesimboluri folosestespeciale footnotetext forteazablocuri fractie framed framedtext fundal gatablocuri grid hartiedubla hl impachetat impartefloat in inalt inaltamargine indentation indreapta inframed ininner injos inlinie inouter instalarelimba instanga intins jos jossus la labeling lapagina limba limbaprincipala liniemargine linieneagra liniesubtire linieumplere liniinegre liniisubtiri listsymbol litera litere loadsorts loadsynonyms logcampuri luna mapfontsize mar marcaje marcheazaversiune marginal matematica mediaeval minicitat mutapegrid name nextsection nocap nop nota notasubsol numartitlu numartitlucurent numere numereromane olinie overbar overbars overstrike overstrikes pagina paginadubla paragraph part pastreazablocuri placefloat placelistoffloats placelistofsorts placelistofsynonyms placereferencelist plaseazapegrid plaseazasemnecarte potrivestecamp pozitie proceseazabloc proceseazapagina program publicatie puncte punedeasuprafiecareia punefatainfata puneformula punelegenda punelista punelistacombinata punelistacombinata punelogouri punenotesubsol punenotesubsollocale puneregistru puneregistru punesubformula ran ref referinta referintapagina referintatext referit reflexie register reservefloat reset reseteazamarcaje resettextcontent riglatext rigleumplere roteste saripesteblocuri scala scriebuffer scrieinlista scrieinlistareferinte scrieinregistru scrieintreliste section seeregister selecteazablocuri selecteazahartie selecteazaversiune semncarte setarebarasincronizare setarelimba setareoutput setarepozitie setaresincronizare seteazaaliniat seteazaaliniate seteazaalinierea seteazaantet seteazaaranjareapag seteazaaspect seteazabarainteractiune seteazablanc seteazabloc seteazablocsectiune seteazablocurimarginale seteazabuffer seteazabutoane seteazacamp seteazacampuri seteazaclipping seteazacoloane seteazacombinari seteazacomentariu seteazaculoare seteazaculori seteazadefinireanotasubsol seteazadescriere seteazadimensiunihartie seteazaecrane seteazaecraninteractiune seteazaelemente seteazaenumerare seteazafiguriexterne seteazafloat seteazafloats seteazafonttext seteazaformulare seteazaformule seteazafundal seteazafundaluri seteazagrosimelinie seteazaimpartireafloat seteazainconjurat seteazaingust seteazainteractiunea seteazajos seteazalegenda seteazalegenda seteazalegendele seteazaliniesilabe seteazaliniesubtire seteazalinii seteazaliniimargine seteazaliniinegre seteazaliniiumplere seteazalista seteazalistacombinata seteazalistareferinte seteazamajuscule seteazamakeup seteazamarcaje seteazamarginal seteazamediulfonttext seteazameniuinteractiune seteazaminicitat seteazanotasubsol seteazanumarpagina seteazanumarsubpagina seteazanumartitlu seteazanumerotare seteazanumerotarelinii seteazanumerotarepagina seteazanumerotareparagrafe seteazapaleta seteazaparagrafe seteazaplasareaopozita seteazaprofile seteazaprograme seteazapublicatii seteazareferinte seteazaregistru seteazarigletext seteazarigleumplere seteazarotare seteazasectiune seteazasimbol seteazasinonime seteazasistem seteazasortare seteazaspatiu seteazaspatiualb seteazaspatiuinterliniar seteazastrut seteazasublinie seteazasubsol seteazasus seteazatab seteazatabele seteazatabulatori seteazatext seteazatexteantet seteazatextejos seteazatextesubsol seteazatextesus seteazatextetext seteazatexteticheta seteazatexttitlu seteazatitlu seteazatitluri seteazatoleranta seteazatranzitiepagina seteazatype seteazatyping seteazaurl seteazaversiuni settextcontent setupfonthandling setupfontsynonym setupinterlinespace2 setupitemgroup setuplistalternative setuppaper sim simbol sincronizeaza sort spatiifixate spatiu spatiualb startalignment startbuffer startbuffer startcitat startcolumns startcombination startcomentariu startcomponenta startculoare startdescription startdocument startenumeration startfact startfigure startfloattext startformula startframedtext startfundal starthiding startimpachetat startitemgroup startlegend startline startlinecorrection startlinenumbering startlines startliniemargine startlocal startlocalenvironment startlocalfootnotes startmakeup startmarginblock startmediu startmeniuinteractiune startnamemakeup startnarrower startopposite startoverlay startoverview startparagraph startpositioning startpostponing startprodus startprofile startproiect startregister startriglatext startsymbolset startsynchronization starttable starttables starttabulate starttyping startunpacked startversiune stivacampuri stopalignment stopbuffer stopbuffer stopcitat stopcolumns stopcombination stopcomentariu stopcomponenta stopculoare stopdescription stopdocument stopenumeration stopfact stopfigure stopfloattext stopformula stopframedtext stopfundal stophiding stopimpachetat stopitemgroup stoplegend stopline stoplinecorrection stoplinenumbering stoplines stopliniemargine stoplocal stoplocalenvironment stoplocalfootnotes stopmakeup stopmarginblock stopmediu stopmeniuinteractiune stopnamemakeup stopnarrower stopopposite stopoverlay stopoverview stopparagraph stoppositioning stoppostponing stopprodus stopprofile stopproiect stopriglatext stopsymbolset stopsynchronization stoptable stoptables stoptabulate stoptyping stopunpacked stopversiune sub subject subsection subsubject subsubsection subsubsubject synonym tab tex texteticheta textmarginal texttitlu textumplere tippagina title titlu tooltip traduce trecilafonttext typ type typefile underbar underbars undeva urmeazaprofil urmeazaversiune urmeazaversiuneprofil usedirectory usetypescript usetypescriptfile versiune vl zidinsaptamana \ No newline at end of file
+keywordclass.macros.context.ro=CAP CUVANT CUVINTE Cap Caps Cuvant Cuvinte LUNA Litera Litere Numereromane ZIDINSAPTAMANA adapteazaaspect adubuffer adumarcaje afiseazaaspect afiseazacampuri afiseazaculoare afiseazafiguriexterne afiseazafonttext afiseazagrid afiseazagrupculoare afiseazamakeup afiseazamediufonttext afiseazapaleta afiseazarama afiseazasetari afiseazasetsimboluri afiseazastruts afiseazatiparire aliniat aliniatcentru aliniatdreapta aliniatstanga appendix ascundeblocuri barainteractiune barasincronizare blanc but butoaneinteractiune buton camp campumplere cap chapter chem citat clip cloneazacamp coloana comment comparagrupculoare comparapaleta completecombinedlist completelistoffloats completelistofsorts completelistofsynonyms completeregister convertestenumar copiazacamp corecteazaspatiualb coupledregister crlf culoare culoaregri cupleazadocument cupleazamarcaje cupleazaregistru cuvantdreapta data datacurenta datareferit decupleazamarcaje definebodyfontDEF definebodyfontREF definedfont definefontfeature definefonthandling defineste definestealiat definesteantet definesteblanc definestebloc definesteblocsectiune definestebuffer definestecamp definesteconversie definesteculoare definestedescriere definestedimensiunehartie definesteenumerare definesteeticheta definestefloat definestefont definestefonttext definesteformatreferinte definestegrupculori definesteinconjurare definestelista definestelistacombinata definestelistareferinte definestelogo definestemakeup definestemarcaje definestemediulfonttext definestemeniuinteractiune definestemeniuinteractiune definesteoutput definesteoverlay definestepaleta definesteparagraf definesteprofil definesteprogram definestereferinte definesteregistru definestesablontabel definestesectiune definestesimbol definestesimbolfigura definestesinonim definestesinonimfont definestesortare definestestartstop definestestivacampuri definestesubcamp definestetabulatori definestetext definestetexteinconjurate definestetextinconjurat definestetyping definesteversiune definetype definetypeface description despre determinacaracteristicilelistei determinanumartitlu dezactiveazameniuinteractiune din dute dutebox ecran el element element emptylines enumeration etichete faraaliniat farafisiere faraliniiantetsisubsol faraliniisussijos faralista faramarcaje faraspatiu faraspatiualb figuraexterna firdepar folosesteURL folosestebloc folosestecodificarea folosestecomenzi folosestedocumentextern folosestefiguraexterna folosestefisiereexterne folosestefisierextern folosestemodul folosestemuzicaexterna folosestereferinte folosestesimboluri folosestespeciale footnotetext forteazablocuri fractie framed framedtext fundal gatablocuri grid hartiedubla hl impachetat impartefloat in inalt inaltamargine indentation indreapta inframed ininner injos inlinie inouter instalarelimba instanga intins jos jossus la labeling lapagina limba limbaprincipala liniemargine linieneagra liniesubtire linieumplere liniinegre liniisubtiri listsymbol litera litere loadsorts loadsynonyms logcampuri luna mapfontsize mar marcaje marcheazaversiune marginal matematica mediaeval minicitat mutapegrid name nextsection nocap nop nota notasubsol numartitlu numartitlucurent numere numereromane olinie overbar overbars overstrike overstrikes pagina paginadubla paragraph part pastreazablocuri placefloat placelistoffloats placelistofsorts placelistofsynonyms placereferencelist plaseazapegrid plaseazasemnecarte potrivestecamp pozitie proceseazabloc proceseazapagina program publicatie puncte punedeasuprafiecareia punefatainfata puneformula punelegenda punelista punelistacombinata punelistacombinata punelogouri punenotesubsol punenotesubsollocale puneregistru puneregistru punesubformula ran ref referinta referintapagina referintatext referit reflexie register reservefloat reset reseteazamarcaje resettextcontent riglatext rigleumplere roteste saripesteblocuri scala scriebuffer scrieinlista scrieinlistareferinte scrieinregistru scrieintreliste section seeregister selecteazablocuri selecteazahartie selecteazaversiune semncarte setarebarasincronizare setarelimba setareoutput setarepozitie setaresincronizare seteazaaliniat seteazaaliniate seteazaalinierea seteazaantet seteazaaranjareapag seteazaaspect seteazabarainteractiune seteazablanc seteazabloc seteazablocsectiune seteazablocurimarginale seteazabuffer seteazabutoane seteazacamp seteazacampuri seteazaclipping seteazacoloane seteazacombinari seteazacomentariu seteazaculoare seteazaculori seteazadefinireanotasubsol seteazadescriere seteazadimensiunihartie seteazaecrane seteazaecraninteractiune seteazaelemente seteazaenumerare seteazafiguriexterne seteazafloat seteazafloats seteazafonttext seteazaformulare seteazaformule seteazafundal seteazafundaluri seteazagrosimelinie seteazaimpartireafloat seteazainconjurat seteazaingust seteazainteractiunea seteazajos seteazalegenda seteazalegenda seteazalegendele seteazaliniesilabe seteazaliniesubtire seteazalinii seteazaliniimargine seteazaliniinegre seteazaliniiumplere seteazalista seteazalistacombinata seteazalistareferinte seteazamajuscule seteazamakeup seteazamarcaje seteazamarginal seteazamediulfonttext seteazameniuinteractiune seteazaminicitat seteazanotasubsol seteazanumarpagina seteazanumarsubpagina seteazanumartitlu seteazanumerotare seteazanumerotarelinii seteazanumerotarepagina seteazanumerotareparagrafe seteazapaleta seteazaparagrafe seteazaplasareaopozita seteazaprofile seteazaprograme seteazapublicatii seteazareferinte seteazaregistru seteazarigletext seteazarigleumplere seteazarotare seteazasectiune seteazasimbol seteazasinonime seteazasistem seteazasortare seteazaspatiu seteazaspatiualb seteazaspatiuinterliniar seteazastrut seteazasublinie seteazasubsol seteazasus seteazatab seteazatabele seteazatabulatori seteazatext seteazatexteantet seteazatextejos seteazatextesubsol seteazatextesus seteazatextetext seteazatexteticheta seteazatexttitlu seteazatitlu seteazatitluri seteazatoleranta seteazatranzitiepagina seteazatype seteazatyping seteazaurl seteazaversiuni settextcontent setupfonthandling setupfontsynonym setupinterlinespace2 setupitemgroup setuplistalternative setuppaper sim simbol sincronizeaza sort spatiifixate spatiu spatiualb startalignment startbuffer startbuffer startcitat startcolumns startcombination startcomment startcomponenta startculoare startdescription startdocument startenumeration startfact startfigure startfloattext startformula startframedtext startfundal starthiding startimpachetat startitemgroup startlegend startline startlinecorrection startlinenumbering startlines startliniemargine startlocal startlocalenvironment startlocalfootnotes startmakeup startmarginblock startmediu startmeniuinteractiune startnamemakeup startnarrower startopposite startoverlay startoverview startparagraph startpositioning startpostponing startprodus startprofile startproiect startregister startriglatext startsymbolset startsynchronization starttable starttables starttabulate starttyping startunpacked startversiune stivacampuri stopalignment stopbuffer stopbuffer stopcitat stopcolumns stopcombination stopcomment stopcomponenta stopculoare stopdescription stopdocument stopenumeration stopfact stopfigure stopfloattext stopformula stopframedtext stopfundal stophiding stopimpachetat stopitemgroup stoplegend stopline stoplinecorrection stoplinenumbering stoplines stopliniemargine stoplocal stoplocalenvironment stoplocalfootnotes stopmakeup stopmarginblock stopmediu stopmeniuinteractiune stopnamemakeup stopnarrower stopopposite stopoverlay stopoverview stopparagraph stoppositioning stoppostponing stopprodus stopprofile stopproiect stopriglatext stopsymbolset stopsynchronization stoptable stoptables stoptabulate stoptyping stopunpacked stopversiune sub subject subsection subsubject subsubsection subsubsubject synonym tab tex texteticheta textmarginal texttitlu textumplere tippagina title titlu tooltip traduce trecilafonttext typ type typefile underbar underbars undeva urmeazaprofil urmeazaversiune urmeazaversiuneprofil usedirectory usetypescript usetypescriptfile versiune vl zidinsaptamana \ No newline at end of file
diff --git a/metapost/context/base/mp-mlib.mp b/metapost/context/base/mp-mlib.mp
index cedfa9f7b..e812df61e 100644
--- a/metapost/context/base/mp-mlib.mp
+++ b/metapost/context/base/mp-mlib.mp
@@ -406,14 +406,21 @@ enddef ;
% fi ;
% enddef ;
+def withmask primary filename =
+ withprescript "fg_mask=" & filename
+enddef ;
+
def externalfigure primary filename =
- if true :
- draw rawtextext("\externalfigure[" & filename & "]")
+ if false :
+ rawtextext("\externalfigure[" & filename & "]")
else :
image (
addto currentpicture doublepath unitsquare
withprescript "fg_name=" & filename ;
)
+% unitsquare
+% withpen pencircle scaled 0
+% withprescript "fg_name=" & filename
fi
enddef ;
diff --git a/scripts/context/lua/mtx-context.lua b/scripts/context/lua/mtx-context.lua
index 39712af7e..36e3efb6b 100644
--- a/scripts/context/lua/mtx-context.lua
+++ b/scripts/context/lua/mtx-context.lua
@@ -117,334 +117,334 @@ function io.copydata(fromfile,tofile)
io.savedata(tofile,io.loaddata(fromfile) or "")
end
--- ctx
-
-ctxrunner = { }
-
-do
-
- function ctxrunner.filtered(str,method)
- str = tostring(str)
- if method == 'name' then str = file.removesuffix(file.basename(str))
- elseif method == 'path' then str = file.dirname(str)
- elseif method == 'suffix' then str = file.extname(str)
- elseif method == 'nosuffix' then str = file.removesuffix(str)
- elseif method == 'nopath' then str = file.basename(str)
- elseif method == 'base' then str = file.basename(str)
- -- elseif method == 'full' then
- -- elseif method == 'complete' then
- -- elseif method == 'expand' then -- str = file.expandpath(str)
- end
- return str:gsub("\\","/")
+-- ctx (will become util-ctx)
+
+local ctxrunner = { }
+
+function ctxrunner.filtered(str,method)
+ str = tostring(str)
+ if method == 'name' then str = file.removesuffix(file.basename(str))
+ elseif method == 'path' then str = file.dirname(str)
+ elseif method == 'suffix' then str = file.extname(str)
+ elseif method == 'nosuffix' then str = file.removesuffix(str)
+ elseif method == 'nopath' then str = file.basename(str)
+ elseif method == 'base' then str = file.basename(str)
+-- elseif method == 'full' then
+-- elseif method == 'complete' then
+-- elseif method == 'expand' then -- str = file.expandpath(str)
end
+ return str:gsub("\\","/")
+end
- function ctxrunner.substitute(e,str)
- local attributes = e.at
- if str and attributes then
- if attributes['method'] then
- str = ctxrunner.filtered(str,attributes['method'])
- end
- if str == "" and attributes['default'] then
- str = attributes['default']
- end
+function ctxrunner.substitute(e,str)
+ local attributes = e.at
+ if str and attributes then
+ if attributes['method'] then
+ str = ctxrunner.filtered(str,attributes['method'])
+ end
+ if str == "" and attributes['default'] then
+ str = attributes['default']
end
- return str
end
+ return str
+end
- function ctxrunner.reflag(flags)
- local t = { }
- for _, flag in next, flags do
- local key, value = match(flag,"^(.-)=(.+)$")
- if key and value then
- t[key] = value
- else
- t[flag] = true
- end
+function ctxrunner.reflag(flags)
+ local t = { }
+ for _, flag in next, flags do
+ local key, value = match(flag,"^(.-)=(.+)$")
+ if key and value then
+ t[key] = value
+ else
+ t[flag] = true
end
- return t
end
+ return t
+end
- function ctxrunner.substitute(str)
- return str
- end
+function ctxrunner.substitute(str)
+ return str
+end
- function ctxrunner.justtext(str)
- str = xml.unescaped(tostring(str))
- str = xml.cleansed(str)
- str = str:gsub("\\+",'/')
- str = str:gsub("%s+",' ')
- return str
- end
+function ctxrunner.justtext(str)
+ str = xml.unescaped(tostring(str))
+ str = xml.cleansed(str)
+ str = str:gsub("\\+",'/')
+ str = str:gsub("%s+",' ')
+ return str
+end
- function ctxrunner.new()
- return {
- ctxname = "",
- jobname = "",
- xmldata = nil,
- suffix = "prep",
- locations = { '..', '../..' },
- variables = { },
- messages = { },
- environments = { },
- modules = { },
- filters = { },
- flags = { },
- modes = { },
- prepfiles = { },
- paths = { },
- }
- end
+function ctxrunner.new()
+ return {
+ ctxname = "",
+ jobname = "",
+ xmldata = nil,
+ suffix = "prep",
+ locations = { '..', '../..' },
+ variables = { },
+ messages = { },
+ environments = { },
+ modules = { },
+ filters = { },
+ flags = { },
+ modes = { },
+ prepfiles = { },
+ paths = { },
+ }
+end
- function ctxrunner.savelog(ctxdata,ctlname)
- local function yn(b)
- if b then return 'yes' else return 'no' end
- end
- if not ctlname or ctlname == "" or ctlname == ctxdata.jobname then
- if ctxdata.jobname then
- ctlname = file.replacesuffix(ctxdata.jobname,'ctl')
- elseif ctxdata.ctxname then
- ctlname = file.replacesuffix(ctxdata.ctxname,'ctl')
- else
- report("invalid ctl name: %s",ctlname or "?")
- return
- end
+function ctxrunner.savelog(ctxdata,ctlname)
+ local function yn(b)
+ if b then return 'yes' else return 'no' end
+ end
+ if not ctlname or ctlname == "" or ctlname == ctxdata.jobname then
+ if ctxdata.jobname then
+ ctlname = file.replacesuffix(ctxdata.jobname,'ctl')
+ elseif ctxdata.ctxname then
+ ctlname = file.replacesuffix(ctxdata.ctxname,'ctl')
+ else
+ report("invalid ctl name: %s",ctlname or "?")
+ return
end
- local prepfiles = ctxdata.prepfiles
- if prepfiles and next(prepfiles) then
- report("saving logdata in: %s",ctlname)
- f = io.open(ctlname,'w')
- if f then
- f:write("<?xml version='1.0' standalone='yes'?>\n\n")
- f:write(format("<ctx:preplist local='%s'>\n",yn(ctxdata.runlocal)))
- local sorted = table.sortedkeys(prepfiles)
- for i=1,#sorted do
- local name = sorted[i]
- f:write(format("\t<ctx:prepfile done='%s'>%s</ctx:prepfile>\n",yn(prepfiles[name]),name))
- end
- f:write("</ctx:preplist>\n")
- f:close()
+ end
+ local prepfiles = ctxdata.prepfiles
+ if prepfiles and next(prepfiles) then
+ report("saving logdata in: %s",ctlname)
+ f = io.open(ctlname,'w')
+ if f then
+ f:write("<?xml version='1.0' standalone='yes'?>\n\n")
+ f:write(format("<ctx:preplist local='%s'>\n",yn(ctxdata.runlocal)))
+ local sorted = table.sortedkeys(prepfiles)
+ for i=1,#sorted do
+ local name = sorted[i]
+ f:write(format("\t<ctx:prepfile done='%s'>%s</ctx:prepfile>\n",yn(prepfiles[name]),name))
end
- else
- report("nothing prepared, no ctl file saved")
- os.remove(ctlname)
+ f:write("</ctx:preplist>\n")
+ f:close()
end
+ else
+ report("nothing prepared, no ctl file saved")
+ os.remove(ctlname)
end
+end
- function ctxrunner.register_path(ctxdata,path)
- -- test if exists
- ctxdata.paths[ctxdata.paths+1] = path
- end
+function ctxrunner.register_path(ctxdata,path)
+ -- test if exists
+ ctxdata.paths[ctxdata.paths+1] = path
+end
- function ctxrunner.trace(ctxdata)
- print(table.serialize(ctxdata.messages))
- print(table.serialize(ctxdata.flags))
- print(table.serialize(ctxdata.environments))
- print(table.serialize(ctxdata.modules))
- print(table.serialize(ctxdata.filters))
- print(table.serialize(ctxdata.modes))
- print(xml.tostring(ctxdata.xmldata))
- end
+function ctxrunner.trace(ctxdata)
+ print(table.serialize(ctxdata.messages))
+ print(table.serialize(ctxdata.flags))
+ print(table.serialize(ctxdata.environments))
+ print(table.serialize(ctxdata.modules))
+ print(table.serialize(ctxdata.filters))
+ print(table.serialize(ctxdata.modes))
+ print(xml.tostring(ctxdata.xmldata))
+end
- function ctxrunner.manipulate(ctxdata,ctxname,defaultname)
+function ctxrunner.manipulate(ctxdata,ctxname,defaultname)
- if not ctxdata.jobname or ctxdata.jobname == "" then
- return
- end
+ if not ctxdata.jobname or ctxdata.jobname == "" then
+ return
+ end
- ctxdata.ctxname = ctxname or file.removesuffix(ctxdata.jobname) or ""
+ ctxdata.ctxname = ctxname or file.removesuffix(ctxdata.jobname) or ""
- if ctxdata.ctxname == "" then
- return
- end
+ if ctxdata.ctxname == "" then
+ return
+ end
- ctxdata.jobname = file.addsuffix(ctxdata.jobname,'tex')
- ctxdata.ctxname = file.addsuffix(ctxdata.ctxname,'ctx')
+ ctxdata.jobname = file.addsuffix(ctxdata.jobname,'tex')
+ ctxdata.ctxname = file.addsuffix(ctxdata.ctxname,'ctx')
- report("jobname: %s",ctxdata.jobname)
- report("ctxname: %s",ctxdata.ctxname)
+ report("jobname: %s",ctxdata.jobname)
+ report("ctxname: %s",ctxdata.ctxname)
- -- mtxrun should resolve kpse: and file:
+ -- mtxrun should resolve kpse: and file:
- local usedname = ctxdata.ctxname
- local found = lfs.isfile(usedname)
+ local usedname = ctxdata.ctxname
+ local found = lfs.isfile(usedname)
- if not found then
- for _, path in next, ctxdata.locations do
- local fullname = file.join(path,ctxdata.ctxname)
- if lfs.isfile(fullname) then
- usedname, found = fullname, true
- break
- end
+ -- no futher test if qualified path
+
+ if not found then
+ for _, path in next, ctxdata.locations do
+ local fullname = file.join(path,ctxdata.ctxname)
+ if lfs.isfile(fullname) then
+ usedname, found = fullname, true
+ break
end
end
+ end
+ if not found then
usedname = resolvers.findfile(ctxdata.ctxname,"tex")
found = usedname ~= ""
+ end
- if not found and defaultname and defaultname ~= "" and lfs.isfile(defaultname) then
- usedname, found = defaultname, true
- end
+ if not found and defaultname and defaultname ~= "" and lfs.isfile(defaultname) then
+ usedname, found = defaultname, true
+ end
- if not found then
- return
- end
+ if not found then
+ return
+ end
- ctxdata.xmldata = xml.load(usedname)
+ ctxdata.xmldata = xml.load(usedname)
- if not ctxdata.xmldata then
- return
- else
- -- test for valid, can be text file
- end
+ if not ctxdata.xmldata then
+ return
+ else
+ -- test for valid, can be text file
+ end
- xml.include(ctxdata.xmldata,'ctx:include','name', table.append({'.', file.dirname(ctxdata.ctxname)},ctxdata.locations))
+ xml.include(ctxdata.xmldata,'ctx:include','name', table.append({'.', file.dirname(ctxdata.ctxname)},ctxdata.locations))
- ctxdata.variables['job'] = ctxdata.jobname
+ ctxdata.variables['job'] = ctxdata.jobname
- ctxdata.flags = xml.collect_texts(ctxdata.xmldata,"/ctx:job/ctx:flags/ctx:flag",true)
- ctxdata.environments = xml.collect_texts(ctxdata.xmldata,"/ctx:job/ctx:process/ctx:resources/ctx:environment",true)
- ctxdata.modules = xml.collect_texts(ctxdata.xmldata,"/ctx:job/ctx:process/ctx:resources/ctx:module",true)
- ctxdata.filters = xml.collect_texts(ctxdata.xmldata,"/ctx:job/ctx:process/ctx:resources/ctx:filter",true)
- ctxdata.modes = xml.collect_texts(ctxdata.xmldata,"/ctx:job/ctx:process/ctx:resources/ctx:mode",true)
- ctxdata.messages = xml.collect_texts(ctxdata.xmldata,"ctx:message",true)
+ ctxdata.flags = xml.collect_texts(ctxdata.xmldata,"/ctx:job/ctx:flags/ctx:flag",true)
+ ctxdata.environments = xml.collect_texts(ctxdata.xmldata,"/ctx:job/ctx:process/ctx:resources/ctx:environment",true)
+ ctxdata.modules = xml.collect_texts(ctxdata.xmldata,"/ctx:job/ctx:process/ctx:resources/ctx:module",true)
+ ctxdata.filters = xml.collect_texts(ctxdata.xmldata,"/ctx:job/ctx:process/ctx:resources/ctx:filter",true)
+ ctxdata.modes = xml.collect_texts(ctxdata.xmldata,"/ctx:job/ctx:process/ctx:resources/ctx:mode",true)
+ ctxdata.messages = xml.collect_texts(ctxdata.xmldata,"ctx:message",true)
- ctxdata.flags = ctxrunner.reflag(ctxdata.flags)
+ ctxdata.flags = ctxrunner.reflag(ctxdata.flags)
- local messages = ctxdata.messages
- for i=1,#messages do
- report("ctx comment: %s", xml.tostring(messages[i]))
- end
+ local messages = ctxdata.messages
+ for i=1,#messages do
+ report("ctx comment: %s", xml.tostring(messages[i]))
+ end
- for r, d, k in xml.elements(ctxdata.xmldata,"ctx:value[@name='job']") do
- d[k] = ctxdata.variables['job'] or ""
- end
+ for r, d, k in xml.elements(ctxdata.xmldata,"ctx:value[@name='job']") do
+ d[k] = ctxdata.variables['job'] or ""
+ end
- local commands = { }
- for e in xml.collected(ctxdata.xmldata,"/ctx:job/ctx:preprocess/ctx:processors/ctx:processor") do
- commands[e.at and e.at['name'] or "unknown"] = e
- end
+ local commands = { }
+ for e in xml.collected(ctxdata.xmldata,"/ctx:job/ctx:preprocess/ctx:processors/ctx:processor") do
+ commands[e.at and e.at['name'] or "unknown"] = e
+ end
- local suffix = xml.filter(ctxdata.xmldata,"/ctx:job/ctx:preprocess/attribute('suffix')") or ctxdata.suffix
- local runlocal = xml.filter(ctxdata.xmldata,"/ctx:job/ctx:preprocess/ctx:processors/attribute('local')")
+ local suffix = xml.filter(ctxdata.xmldata,"/ctx:job/ctx:preprocess/attribute('suffix')") or ctxdata.suffix
+ local runlocal = xml.filter(ctxdata.xmldata,"/ctx:job/ctx:preprocess/ctx:processors/attribute('local')")
- runlocal = toboolean(runlocal)
+ runlocal = toboolean(runlocal)
- for files in xml.collected(ctxdata.xmldata,"/ctx:job/ctx:preprocess/ctx:files") do
- for pattern in xml.collected(files,"ctx:file") do
+ for files in xml.collected(ctxdata.xmldata,"/ctx:job/ctx:preprocess/ctx:files") do
+ for pattern in xml.collected(files,"ctx:file") do
- preprocessor = pattern.at['processor'] or ""
+ preprocessor = pattern.at['processor'] or ""
- if preprocessor ~= "" then
+ if preprocessor ~= "" then
- ctxdata.variables['old'] = ctxdata.jobname
- for r, d, k in xml.elements(ctxdata.xmldata,"ctx:value") do
- local ek = d[k]
- local ekat = ek.at['name']
- if ekat == 'old' then
- d[k] = ctxrunner.substitute(ctxdata.variables[ekat] or "")
- end
+ ctxdata.variables['old'] = ctxdata.jobname
+ for r, d, k in xml.elements(ctxdata.xmldata,"ctx:value") do
+ local ek = d[k]
+ local ekat = ek.at['name']
+ if ekat == 'old' then
+ d[k] = ctxrunner.substitute(ctxdata.variables[ekat] or "")
end
+ end
- pattern = ctxrunner.justtext(xml.tostring(pattern))
+ pattern = ctxrunner.justtext(xml.tostring(pattern))
- local oldfiles = dir.glob(pattern)
+ local oldfiles = dir.glob(pattern)
- local pluspath = false
- if #oldfiles == 0 then
- -- message: no files match pattern
- local paths = ctxdata.paths
- for i=1,#paths do
- local p = paths[i]
- local oldfiles = dir.glob(path.join(p,pattern))
- if #oldfiles > 0 then
- pluspath = true
- break
- end
+ local pluspath = false
+ if #oldfiles == 0 then
+ -- message: no files match pattern
+ local paths = ctxdata.paths
+ for i=1,#paths do
+ local p = paths[i]
+ local oldfiles = dir.glob(path.join(p,pattern))
+ if #oldfiles > 0 then
+ pluspath = true
+ break
end
end
- if #oldfiles == 0 then
- -- message: no old files
- else
- for i=1,#oldfiles do
- local oldfile = oldfiles[i]
- local newfile = oldfile .. "." .. suffix -- addsuffix will add one only
- if ctxdata.runlocal then
- newfile = file.basename(newfile)
- end
- if oldfile ~= newfile and file.needsupdate(oldfile,newfile) then
- -- message: oldfile needs preprocessing
- -- os.remove(newfile)
- local splitted = preprocessor:split(',')
- for i=1,#splitted do
- local pp = splitted[i]
- local command = commands[pp]
- if command then
- command = xml.copy(command)
- local suf = (command.at and command.at['suffix']) or ctxdata.suffix
- if suf then
- newfile = oldfile .. "." .. suf
- end
- if ctxdata.runlocal then
- newfile = file.basename(newfile)
- end
- for r, d, k in xml.elements(command,"ctx:old") do
- d[k] = ctxrunner.substitute(oldfile)
- end
- for r, d, k in xml.elements(command,"ctx:new") do
- d[k] = ctxrunner.substitute(newfile)
- end
- ctxdata.variables['old'] = oldfile
- ctxdata.variables['new'] = newfile
- for r, d, k in xml.elements(command,"ctx:value") do
- local ek = d[k]
- local ekat = ek.at and ek.at['name']
- if ekat then
- d[k] = ctxrunner.substitute(ctxdata.variables[ekat] or "")
- end
- end
- -- potential optimization: when mtxrun run internal
- command = xml.content(command)
- command = ctxrunner.justtext(command)
- report("command: %s",command)
- local result = os.spawn(command) or 0
- -- somehow we get the wrong return value
- if result > 0 then
- report("error, return code: %s",result)
- end
- if ctxdata.runlocal then
- oldfile = file.basename(oldfile)
+ end
+ if #oldfiles == 0 then
+ -- message: no old files
+ else
+ for i=1,#oldfiles do
+ local oldfile = oldfiles[i]
+ local newfile = oldfile .. "." .. suffix -- addsuffix will add one only
+ if ctxdata.runlocal then
+ newfile = file.basename(newfile)
+ end
+ if oldfile ~= newfile and file.needsupdate(oldfile,newfile) then
+ -- message: oldfile needs preprocessing
+ -- os.remove(newfile)
+ local splitted = preprocessor:split(',')
+ for i=1,#splitted do
+ local pp = splitted[i]
+ local command = commands[pp]
+ if command then
+ command = xml.copy(command)
+ local suf = (command.at and command.at['suffix']) or ctxdata.suffix
+ if suf then
+ newfile = oldfile .. "." .. suf
+ end
+ if ctxdata.runlocal then
+ newfile = file.basename(newfile)
+ end
+ for r, d, k in xml.elements(command,"ctx:old") do
+ d[k] = ctxrunner.substitute(oldfile)
+ end
+ for r, d, k in xml.elements(command,"ctx:new") do
+ d[k] = ctxrunner.substitute(newfile)
+ end
+ ctxdata.variables['old'] = oldfile
+ ctxdata.variables['new'] = newfile
+ for r, d, k in xml.elements(command,"ctx:value") do
+ local ek = d[k]
+ local ekat = ek.at and ek.at['name']
+ if ekat then
+ d[k] = ctxrunner.substitute(ctxdata.variables[ekat] or "")
end
end
+ -- potential optimization: when mtxrun run internal
+ command = xml.content(command)
+ command = ctxrunner.justtext(command)
+ report("command: %s",command)
+ local result = os.spawn(command) or 0
+ -- somehow we get the wrong return value
+ if result > 0 then
+ report("error, return code: %s",result)
+ end
+ if ctxdata.runlocal then
+ oldfile = file.basename(oldfile)
+ end
end
- if lfs.isfile(newfile) then
- file.syncmtimes(oldfile,newfile)
- ctxdata.prepfiles[oldfile] = true
- else
- report("error, check target location of new file: %s", newfile)
- ctxdata.prepfiles[oldfile] = false
- end
+ end
+ if lfs.isfile(newfile) then
+ file.syncmtimes(oldfile,newfile)
+ ctxdata.prepfiles[oldfile] = true
else
- report("old file needs no preprocessing")
- ctxdata.prepfiles[oldfile] = lfs.isfile(newfile)
+ report("error, check target location of new file: %s", newfile)
+ ctxdata.prepfiles[oldfile] = false
end
+ else
+ report("old file needs no preprocessing")
+ ctxdata.prepfiles[oldfile] = lfs.isfile(newfile)
end
end
end
end
end
+ end
- ctxrunner.savelog(ctxdata)
+ ctxrunner.savelog(ctxdata)
- end
+end
- function ctxrunner.preppedfile(ctxdata,filename)
- if ctxdata.prepfiles[file.basename(filename)] then
- return filename .. ".prep"
- else
- return filename
- end
+function ctxrunner.preppedfile(ctxdata,filename)
+ if ctxdata.prepfiles[file.basename(filename)] then
+ return filename .. ".prep"
+ else
+ return filename
end
-
end
-- rest
@@ -575,7 +575,6 @@ function scripts.context.multipass.makeoptionfile(jobname,ctxdata,kindofrun,curr
setalways("%% styles and modules")
--
setalways("\\startsetups *runtime:modules")
- setvalues("filter" , "\\useXMLfilter[%s]", true)
setvalues("usemodule" , "\\usemodule[%s]", true)
setvalues("environment" , "\\environment %s ", true)
if ctxdata then
@@ -875,9 +874,9 @@ function scripts.context.run(ctxdata,filename)
--~ end
--~ end
-local directives = environment.directives
-local trackers = environment.trackers
-local experiments = environment.experiments
+ local directives = environment.directives
+ local trackers = environment.trackers
+ local experiments = environment.experiments
--
if type(directives) == "string" then
@@ -1214,7 +1213,7 @@ local persistent_runfiles = {
}
local special_runfiles = {
- "-mpgraph*", "-mprun*"
+ "-mpgraph*", "-mprun*", "-temp-*"
}
local function purge_file(dfile,cfile)
@@ -1324,6 +1323,7 @@ function scripts.context.touch()
if environment.argument("expert") then
touchfiles("mkii")
touchfiles("mkiv")
+ touchfiles("mkvi")
end
end
@@ -1355,7 +1355,7 @@ function scripts.context.modules(pattern)
if not done[base] then
done[base] = true
local suffix = file.suffix(base)
- if suffix == "tex" or suffix == "mkiv" then
+ if suffix == "tex" or suffix == "mkiv" or suffix == "mkvi" then
local prefix = match(base,"^([xmst])%-")
if prefix then
v = resolvers.findfile(base) -- so that files on my dev path are seen
diff --git a/scripts/context/lua/mtx-fonts.lua b/scripts/context/lua/mtx-fonts.lua
index 0c315bc91..795fbe891 100644
--- a/scripts/context/lua/mtx-fonts.lua
+++ b/scripts/context/lua/mtx-fonts.lua
@@ -173,7 +173,7 @@ local function showfeatures(tag,specification)
report("subfont : %s",subfont(specification.subfont))
report("fweight : %s",fontweight(specification.fontweight))
-- maybe more
- local features = fonts.get_features(specification.filename,specification.format)
+ local features = fonts.helpers.getfeatures(specification.filename,specification.format)
if features then
for what, v in table.sortedhash(features) do
local data = features[what]
diff --git a/scripts/context/lua/mtx-interface.lua b/scripts/context/lua/mtx-interface.lua
index 91ae16ce3..954cb4498 100644
--- a/scripts/context/lua/mtx-interface.lua
+++ b/scripts/context/lua/mtx-interface.lua
@@ -333,7 +333,7 @@ end
function scripts.interface.preprocess()
require("luat-mac.lua")
- local newsuffix = environment.argument("suffix") or "tex"
+ local newsuffix = environment.argument("suffix") or "log"
local force = environment.argument("force")
for i=1,#environment.files do
local oldname = environment.files[i]
diff --git a/scripts/context/lua/mtx-server-ctx-fonttest.lua b/scripts/context/lua/mtx-server-ctx-fonttest.lua
index d2d41fa39..b30cf0175 100644
--- a/scripts/context/lua/mtx-server-ctx-fonttest.lua
+++ b/scripts/context/lua/mtx-server-ctx-fonttest.lua
@@ -155,12 +155,12 @@ local function showfeatures(f)
report("processing font '%s'",f)
local features = cache[f]
if features == nil then
- features = fonts.get_features(resolvers.findfile(f))
+ features = fonts.helpers.getfeatures(resolvers.findfile(f))
if not features then
report("building cache for '%s'",f)
io.savedata(file.join(temppath,file.addsuffix(tempname,"tex")),format(process_templates.cache,f,f))
os.execute(format("mtxrun --path=%s --script context --once --batchmode %s",temppath,tempname))
- features = fonts.get_features(f)
+ features = fonts.helpers.getfeatures(f)
end
cache[f] = features or false
report("caching info of '%s'",f)
@@ -305,7 +305,7 @@ local function edit_font(currentfont,detail,tempname)
local sorted = table.sortedkeys(htmldata.scripts)
for k=1,#sorted do
local v = sorted[k]
- local s = fonts.otf.tables.scripts[v] or v
+ local s = fonts.handlers.otf.tables.scripts[v] or v
if detail and v == detail.script then
scripts[#scripts+1] = format("<input title='%s' id='s-%s' type='radio' name='script' value='%s' onclick='check_script()' checked='checked'/>&nbsp;<span id='t-s-%s'>%s</span>",s,v,v,v,v)
else
@@ -315,7 +315,7 @@ local function edit_font(currentfont,detail,tempname)
local sorted = table.sortedkeys(htmldata.languages)
for k=1,#sorted do
local v = sorted[k]
- local l = fonts.otf.tables.languages[v] or v
+ local l = fonts.handlers.otf.tables.languages[v] or v
if detail and v == detail.language then
languages[#languages+1] = format("<input title='%s' id='l-%s' type='radio' name='language' value='%s' onclick='check_language()' checked='checked'/>&nbsp;<span id='t-l-%s'>%s</span>",l,v,v,v,v)
else
@@ -325,7 +325,7 @@ local function edit_font(currentfont,detail,tempname)
local sorted = table.sortedkeys(htmldata.features)
for k=1,#sorted do
local v = sorted[k]
- local f = fonts.otf.tables.features[v] or v
+ local f = fonts.handlers.otf.tables.features[v] or v
if detail and detail["f-"..v] then
features[#features+1] = format("<input title='%s' id='f-%s' type='checkbox' name='f-%s' onclick='check_feature()' checked='checked'/>&nbsp;<span id='t-f-%s'>%s</span>",f,v,v,v,v)
else
@@ -408,7 +408,7 @@ end
local function show_font(currentfont,detail)
local specification = get_specification(currentfont)
- local features = fonts.get_features(specification.filename)
+ local features = fonts.helpers.getfeatures(specification.filename)
local result = { }
result[#result+1] = format("<h1>names</h1>",what)
result[#result+1] = "<table>"
@@ -446,7 +446,7 @@ local function show_font(currentfont,detail)
else
done = true
end
- local title = fonts.otf.tables.features[f] or ""
+ local title = fonts.handlers.otf.tables.features[f] or ""
result[#result+1] = format("<tr><td width='50%%'>%s&nbsp;&nbsp;</td><td><tt>%s&nbsp;&nbsp;</tt></td><td><tt>%s&nbsp;&nbsp;</tt></td><td><tt>%s&nbsp;&nbsp;</tt></td></tr>",title,f,s,concat(table.sortedkeys(ss)," "))
end
end
diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua
index 0d9e071fe..38412f1e1 100644
--- a/scripts/context/lua/mtxrun.lua
+++ b/scripts/context/lua/mtxrun.lua
@@ -658,6 +658,7 @@ function lpeg.is_lpeg(p)
end
+
end -- of closure
do -- create closure to overcome 200 locals limit
@@ -757,24 +758,24 @@ local function compare(a,b)
end
local function sortedkeys(tab)
- local srt, kind, s = { }, 0, 0 -- 0=unknown 1=string, 2=number 3=mixed
+ local srt, category, s = { }, 0, 0 -- 0=unknown 1=string, 2=number 3=mixed
for key,_ in next, tab do
s = s + 1
srt[s] = key
- if kind == 3 then
+ if category == 3 then
-- no further check
else
local tkey = type(key)
if tkey == "string" then
- kind = (kind == 2 and 3) or 1
+ category = (category == 2 and 3) or 1
elseif tkey == "number" then
- kind = (kind == 1 and 3) or 2
+ category = (category == 1 and 3) or 2
else
- kind = 3
+ category = 3
end
end
end
- if kind == 0 or kind == 3 then
+ if category == 0 or category == 3 then
sort(srt,compare)
else
sort(srt)
@@ -940,6 +941,13 @@ end
table.fastcopy = fastcopy
table.copy = copy
+function table.derive(parent)
+ local child = { }
+ if parent then
+ setmetatable(child,{ __index = parent })
+ end
+ return child
+end
function table.tohash(t,value)
local h = { }
@@ -3640,7 +3648,7 @@ local tables = utilities.tables
local format, gmatch = string.format, string.gmatch
local concat, insert, remove = table.concat, table.insert, table.remove
-local setmetatable = setmetatable
+local setmetatable, tonumber, tostring = setmetatable, tonumber, tostring
function tables.definetable(target) -- defines undefined tables
local composed, t, n = nil, { }, 0
@@ -3711,6 +3719,28 @@ function table.setemptymetatable(t)
setmetatable(t,_empty_table_)
end
+-- experimental
+
+local function toxml(t,d,result)
+ for k, v in table.sortedpairs(t) do
+ if type(v) == "table" then
+ result[#result+1] = format("%s<%s>",d,k)
+ toxml(v,d.." ",result)
+ result[#result+1] = format("%s</%s>",d,k)
+ elseif tonumber(k) then
+ result[#result+1] = format("%s<entry n='%s'>%s</entry>",d,k,v,k)
+ else
+ result[#result+1] = format("%s<%s>%s</%s>",d,k,tostring(v),k)
+ end
+ end
+end
+
+function table.toxml(t,name)
+ local result = { "<?xml version='1.0' standalone='yes' ?>" }
+ toxml( { [name or "root"] = t }, "", result)
+ return concat(result,"\n")
+end
+
end -- of closure
@@ -3823,13 +3853,13 @@ local gsub, format = string.gsub, string.format
local concat = table.concat
local type, next = type, next
-utilities = utilities or {}
-utilities.merger = utilities.merger or { } -- maybe mergers
-utilities.report = logs and logs.reporter("system") or print
+utilities = utilities or {}
+utilities.merger = utilities.merger or { } -- maybe mergers
+utilities.report = logs and logs.reporter("system") or print
-local merger = utilities.merger
+local merger = utilities.merger
-merger.strip_comment = true
+merger.strip_comment = true
local m_begin_merge = "begin library merge"
local m_end_merge = "end library merge"
@@ -4171,7 +4201,8 @@ end
function parsers.settings_to_set(str,t) -- tohash? -- todo: lpeg -- duplicate anyway
t = t or { }
- for s in gmatch(str,"%s*([^, ]+)") do -- space added
+-- for s in gmatch(str,"%s*([^, ]+)") do -- space added
+ for s in gmatch(str,"[^, ]+") do -- space added
t[s] = true
end
return t
@@ -4214,6 +4245,10 @@ function parsers.getparameters(self,class,parentclass,settings)
parsers.settings_to_hash(settings,sc)
end
+function parsers.listitem(str)
+ return gmatch(str,"[^, ]+")
+end
+
end -- of closure
@@ -11108,8 +11143,8 @@ local function load_configuration_files()
local variables = data.variables or { }
local warning = false
for k, v in next, data do
- local kind = type(v)
- if kind == "table" then
+ local variant = type(v)
+ if variant == "table" then
initializesetter(filename,k,v)
elseif variables[k] == nil then
if trace_locating and not warning then
@@ -11381,7 +11416,7 @@ function resolvers.registerextrapath(paths,subpaths)
end
end
elseif subpaths and subpaths ~= "" then
- for i=1,n do
+ for i=1,oldn do
-- we gmatch each step again, not that fast, but used seldom
for s in gmatch(subpaths,"[^,]+") do
local ps = ep[i] .. "/" .. s
@@ -11550,29 +11585,29 @@ local function collect_files(names)
local blobroot = files.__path__ or blobpath
if type(blobfile) == 'string' then
if not dname or find(blobfile,dname) then
- local kind = hash.type
- -- local search = filejoin(blobpath,blobfile,bname)
- local search = filejoin(blobroot,blobfile,bname)
- local result = methodhandler('concatinators',hash.type,blobroot,blobfile,bname)
+ local variant = hash.type
+ -- local search = filejoin(blobpath,blobfile,bname)
+ local search = filejoin(blobroot,blobfile,bname)
+ local result = methodhandler('concatinators',hash.type,blobroot,blobfile,bname)
if trace_detail then
- report_resolving("match: kind '%s', search '%s', result '%s'",kind,search,result)
+ report_resolving("match: variant '%s', search '%s', result '%s'",variant,search,result)
end
noffiles = noffiles + 1
- filelist[noffiles] = { kind, search, result }
+ filelist[noffiles] = { variant, search, result }
end
else
for kk=1,#blobfile do
local vv = blobfile[kk]
if not dname or find(vv,dname) then
- local kind = hash.type
- -- local search = filejoin(blobpath,vv,bname)
- local search = filejoin(blobroot,vv,bname)
- local result = methodhandler('concatinators',hash.type,blobroot,vv,bname)
+ local variant = hash.type
+ -- local search = filejoin(blobpath,vv,bname)
+ local search = filejoin(blobroot,vv,bname)
+ local result = methodhandler('concatinators',hash.type,blobroot,vv,bname)
if trace_detail then
- report_resolving("match: kind '%s', search '%s', result '%s'",kind,search,result)
+ report_resolving("match: variant '%s', search '%s', result '%s'",variant,search,result)
end
noffiles = noffiles + 1
- filelist[noffiles] = { kind, search, result }
+ filelist[noffiles] = { variant, search, result }
end
end
end
@@ -11950,14 +11985,14 @@ function resolvers.findgivenfile(filename)
return findgivenfiles(filename,false)[1] or ""
end
-local function doit(path,blist,bname,tag,kind,result,allresults)
+local function doit(path,blist,bname,tag,variant,result,allresults)
local done = false
- if blist and kind then
+ if blist and variant then
local resolve = resolvers.resolve -- added
if type(blist) == 'string' then
-- make function and share code
if find(lower(blist),path) then
- local full = methodhandler('concatinators',kind,tag,blist,bname) or ""
+ local full = methodhandler('concatinators',variant,tag,blist,bname) or ""
result[#result+1] = resolve(full)
done = true
end
@@ -11965,7 +12000,7 @@ local function doit(path,blist,bname,tag,kind,result,allresults)
for kk=1,#blist do
local vv = blist[kk]
if find(lower(vv),path) then
- local full = methodhandler('concatinators',kind,tag,vv,bname) or ""
+ local full = methodhandler('concatinators',variant,tag,vv,bname) or ""
result[#result+1] = resolve(full)
done = true
if not allresults then break end
diff --git a/scripts/context/stubs/mswin/mtxrun.lua b/scripts/context/stubs/mswin/mtxrun.lua
index 0d9e071fe..38412f1e1 100644
--- a/scripts/context/stubs/mswin/mtxrun.lua
+++ b/scripts/context/stubs/mswin/mtxrun.lua
@@ -658,6 +658,7 @@ function lpeg.is_lpeg(p)
end
+
end -- of closure
do -- create closure to overcome 200 locals limit
@@ -757,24 +758,24 @@ local function compare(a,b)
end
local function sortedkeys(tab)
- local srt, kind, s = { }, 0, 0 -- 0=unknown 1=string, 2=number 3=mixed
+ local srt, category, s = { }, 0, 0 -- 0=unknown 1=string, 2=number 3=mixed
for key,_ in next, tab do
s = s + 1
srt[s] = key
- if kind == 3 then
+ if category == 3 then
-- no further check
else
local tkey = type(key)
if tkey == "string" then
- kind = (kind == 2 and 3) or 1
+ category = (category == 2 and 3) or 1
elseif tkey == "number" then
- kind = (kind == 1 and 3) or 2
+ category = (category == 1 and 3) or 2
else
- kind = 3
+ category = 3
end
end
end
- if kind == 0 or kind == 3 then
+ if category == 0 or category == 3 then
sort(srt,compare)
else
sort(srt)
@@ -940,6 +941,13 @@ end
table.fastcopy = fastcopy
table.copy = copy
+function table.derive(parent)
+ local child = { }
+ if parent then
+ setmetatable(child,{ __index = parent })
+ end
+ return child
+end
function table.tohash(t,value)
local h = { }
@@ -3640,7 +3648,7 @@ local tables = utilities.tables
local format, gmatch = string.format, string.gmatch
local concat, insert, remove = table.concat, table.insert, table.remove
-local setmetatable = setmetatable
+local setmetatable, tonumber, tostring = setmetatable, tonumber, tostring
function tables.definetable(target) -- defines undefined tables
local composed, t, n = nil, { }, 0
@@ -3711,6 +3719,28 @@ function table.setemptymetatable(t)
setmetatable(t,_empty_table_)
end
+-- experimental
+
+local function toxml(t,d,result)
+ for k, v in table.sortedpairs(t) do
+ if type(v) == "table" then
+ result[#result+1] = format("%s<%s>",d,k)
+ toxml(v,d.." ",result)
+ result[#result+1] = format("%s</%s>",d,k)
+ elseif tonumber(k) then
+ result[#result+1] = format("%s<entry n='%s'>%s</entry>",d,k,v,k)
+ else
+ result[#result+1] = format("%s<%s>%s</%s>",d,k,tostring(v),k)
+ end
+ end
+end
+
+function table.toxml(t,name)
+ local result = { "<?xml version='1.0' standalone='yes' ?>" }
+ toxml( { [name or "root"] = t }, "", result)
+ return concat(result,"\n")
+end
+
end -- of closure
@@ -3823,13 +3853,13 @@ local gsub, format = string.gsub, string.format
local concat = table.concat
local type, next = type, next
-utilities = utilities or {}
-utilities.merger = utilities.merger or { } -- maybe mergers
-utilities.report = logs and logs.reporter("system") or print
+utilities = utilities or {}
+utilities.merger = utilities.merger or { } -- maybe mergers
+utilities.report = logs and logs.reporter("system") or print
-local merger = utilities.merger
+local merger = utilities.merger
-merger.strip_comment = true
+merger.strip_comment = true
local m_begin_merge = "begin library merge"
local m_end_merge = "end library merge"
@@ -4171,7 +4201,8 @@ end
function parsers.settings_to_set(str,t) -- tohash? -- todo: lpeg -- duplicate anyway
t = t or { }
- for s in gmatch(str,"%s*([^, ]+)") do -- space added
+-- for s in gmatch(str,"%s*([^, ]+)") do -- space added
+ for s in gmatch(str,"[^, ]+") do -- space added
t[s] = true
end
return t
@@ -4214,6 +4245,10 @@ function parsers.getparameters(self,class,parentclass,settings)
parsers.settings_to_hash(settings,sc)
end
+function parsers.listitem(str)
+ return gmatch(str,"[^, ]+")
+end
+
end -- of closure
@@ -11108,8 +11143,8 @@ local function load_configuration_files()
local variables = data.variables or { }
local warning = false
for k, v in next, data do
- local kind = type(v)
- if kind == "table" then
+ local variant = type(v)
+ if variant == "table" then
initializesetter(filename,k,v)
elseif variables[k] == nil then
if trace_locating and not warning then
@@ -11381,7 +11416,7 @@ function resolvers.registerextrapath(paths,subpaths)
end
end
elseif subpaths and subpaths ~= "" then
- for i=1,n do
+ for i=1,oldn do
-- we gmatch each step again, not that fast, but used seldom
for s in gmatch(subpaths,"[^,]+") do
local ps = ep[i] .. "/" .. s
@@ -11550,29 +11585,29 @@ local function collect_files(names)
local blobroot = files.__path__ or blobpath
if type(blobfile) == 'string' then
if not dname or find(blobfile,dname) then
- local kind = hash.type
- -- local search = filejoin(blobpath,blobfile,bname)
- local search = filejoin(blobroot,blobfile,bname)
- local result = methodhandler('concatinators',hash.type,blobroot,blobfile,bname)
+ local variant = hash.type
+ -- local search = filejoin(blobpath,blobfile,bname)
+ local search = filejoin(blobroot,blobfile,bname)
+ local result = methodhandler('concatinators',hash.type,blobroot,blobfile,bname)
if trace_detail then
- report_resolving("match: kind '%s', search '%s', result '%s'",kind,search,result)
+ report_resolving("match: variant '%s', search '%s', result '%s'",variant,search,result)
end
noffiles = noffiles + 1
- filelist[noffiles] = { kind, search, result }
+ filelist[noffiles] = { variant, search, result }
end
else
for kk=1,#blobfile do
local vv = blobfile[kk]
if not dname or find(vv,dname) then
- local kind = hash.type
- -- local search = filejoin(blobpath,vv,bname)
- local search = filejoin(blobroot,vv,bname)
- local result = methodhandler('concatinators',hash.type,blobroot,vv,bname)
+ local variant = hash.type
+ -- local search = filejoin(blobpath,vv,bname)
+ local search = filejoin(blobroot,vv,bname)
+ local result = methodhandler('concatinators',hash.type,blobroot,vv,bname)
if trace_detail then
- report_resolving("match: kind '%s', search '%s', result '%s'",kind,search,result)
+ report_resolving("match: variant '%s', search '%s', result '%s'",variant,search,result)
end
noffiles = noffiles + 1
- filelist[noffiles] = { kind, search, result }
+ filelist[noffiles] = { variant, search, result }
end
end
end
@@ -11950,14 +11985,14 @@ function resolvers.findgivenfile(filename)
return findgivenfiles(filename,false)[1] or ""
end
-local function doit(path,blist,bname,tag,kind,result,allresults)
+local function doit(path,blist,bname,tag,variant,result,allresults)
local done = false
- if blist and kind then
+ if blist and variant then
local resolve = resolvers.resolve -- added
if type(blist) == 'string' then
-- make function and share code
if find(lower(blist),path) then
- local full = methodhandler('concatinators',kind,tag,blist,bname) or ""
+ local full = methodhandler('concatinators',variant,tag,blist,bname) or ""
result[#result+1] = resolve(full)
done = true
end
@@ -11965,7 +12000,7 @@ local function doit(path,blist,bname,tag,kind,result,allresults)
for kk=1,#blist do
local vv = blist[kk]
if find(lower(vv),path) then
- local full = methodhandler('concatinators',kind,tag,vv,bname) or ""
+ local full = methodhandler('concatinators',variant,tag,vv,bname) or ""
result[#result+1] = resolve(full)
done = true
if not allresults then break end
diff --git a/scripts/context/stubs/unix/mtxrun b/scripts/context/stubs/unix/mtxrun
index 0d9e071fe..38412f1e1 100755
--- a/scripts/context/stubs/unix/mtxrun
+++ b/scripts/context/stubs/unix/mtxrun
@@ -658,6 +658,7 @@ function lpeg.is_lpeg(p)
end
+
end -- of closure
do -- create closure to overcome 200 locals limit
@@ -757,24 +758,24 @@ local function compare(a,b)
end
local function sortedkeys(tab)
- local srt, kind, s = { }, 0, 0 -- 0=unknown 1=string, 2=number 3=mixed
+ local srt, category, s = { }, 0, 0 -- 0=unknown 1=string, 2=number 3=mixed
for key,_ in next, tab do
s = s + 1
srt[s] = key
- if kind == 3 then
+ if category == 3 then
-- no further check
else
local tkey = type(key)
if tkey == "string" then
- kind = (kind == 2 and 3) or 1
+ category = (category == 2 and 3) or 1
elseif tkey == "number" then
- kind = (kind == 1 and 3) or 2
+ category = (category == 1 and 3) or 2
else
- kind = 3
+ category = 3
end
end
end
- if kind == 0 or kind == 3 then
+ if category == 0 or category == 3 then
sort(srt,compare)
else
sort(srt)
@@ -940,6 +941,13 @@ end
table.fastcopy = fastcopy
table.copy = copy
+function table.derive(parent)
+ local child = { }
+ if parent then
+ setmetatable(child,{ __index = parent })
+ end
+ return child
+end
function table.tohash(t,value)
local h = { }
@@ -3640,7 +3648,7 @@ local tables = utilities.tables
local format, gmatch = string.format, string.gmatch
local concat, insert, remove = table.concat, table.insert, table.remove
-local setmetatable = setmetatable
+local setmetatable, tonumber, tostring = setmetatable, tonumber, tostring
function tables.definetable(target) -- defines undefined tables
local composed, t, n = nil, { }, 0
@@ -3711,6 +3719,28 @@ function table.setemptymetatable(t)
setmetatable(t,_empty_table_)
end
+-- experimental
+
+local function toxml(t,d,result)
+ for k, v in table.sortedpairs(t) do
+ if type(v) == "table" then
+ result[#result+1] = format("%s<%s>",d,k)
+ toxml(v,d.." ",result)
+ result[#result+1] = format("%s</%s>",d,k)
+ elseif tonumber(k) then
+ result[#result+1] = format("%s<entry n='%s'>%s</entry>",d,k,v,k)
+ else
+ result[#result+1] = format("%s<%s>%s</%s>",d,k,tostring(v),k)
+ end
+ end
+end
+
+function table.toxml(t,name)
+ local result = { "<?xml version='1.0' standalone='yes' ?>" }
+ toxml( { [name or "root"] = t }, "", result)
+ return concat(result,"\n")
+end
+
end -- of closure
@@ -3823,13 +3853,13 @@ local gsub, format = string.gsub, string.format
local concat = table.concat
local type, next = type, next
-utilities = utilities or {}
-utilities.merger = utilities.merger or { } -- maybe mergers
-utilities.report = logs and logs.reporter("system") or print
+utilities = utilities or {}
+utilities.merger = utilities.merger or { } -- maybe mergers
+utilities.report = logs and logs.reporter("system") or print
-local merger = utilities.merger
+local merger = utilities.merger
-merger.strip_comment = true
+merger.strip_comment = true
local m_begin_merge = "begin library merge"
local m_end_merge = "end library merge"
@@ -4171,7 +4201,8 @@ end
function parsers.settings_to_set(str,t) -- tohash? -- todo: lpeg -- duplicate anyway
t = t or { }
- for s in gmatch(str,"%s*([^, ]+)") do -- space added
+-- for s in gmatch(str,"%s*([^, ]+)") do -- space added
+ for s in gmatch(str,"[^, ]+") do -- space added
t[s] = true
end
return t
@@ -4214,6 +4245,10 @@ function parsers.getparameters(self,class,parentclass,settings)
parsers.settings_to_hash(settings,sc)
end
+function parsers.listitem(str)
+ return gmatch(str,"[^, ]+")
+end
+
end -- of closure
@@ -11108,8 +11143,8 @@ local function load_configuration_files()
local variables = data.variables or { }
local warning = false
for k, v in next, data do
- local kind = type(v)
- if kind == "table" then
+ local variant = type(v)
+ if variant == "table" then
initializesetter(filename,k,v)
elseif variables[k] == nil then
if trace_locating and not warning then
@@ -11381,7 +11416,7 @@ function resolvers.registerextrapath(paths,subpaths)
end
end
elseif subpaths and subpaths ~= "" then
- for i=1,n do
+ for i=1,oldn do
-- we gmatch each step again, not that fast, but used seldom
for s in gmatch(subpaths,"[^,]+") do
local ps = ep[i] .. "/" .. s
@@ -11550,29 +11585,29 @@ local function collect_files(names)
local blobroot = files.__path__ or blobpath
if type(blobfile) == 'string' then
if not dname or find(blobfile,dname) then
- local kind = hash.type
- -- local search = filejoin(blobpath,blobfile,bname)
- local search = filejoin(blobroot,blobfile,bname)
- local result = methodhandler('concatinators',hash.type,blobroot,blobfile,bname)
+ local variant = hash.type
+ -- local search = filejoin(blobpath,blobfile,bname)
+ local search = filejoin(blobroot,blobfile,bname)
+ local result = methodhandler('concatinators',hash.type,blobroot,blobfile,bname)
if trace_detail then
- report_resolving("match: kind '%s', search '%s', result '%s'",kind,search,result)
+ report_resolving("match: variant '%s', search '%s', result '%s'",variant,search,result)
end
noffiles = noffiles + 1
- filelist[noffiles] = { kind, search, result }
+ filelist[noffiles] = { variant, search, result }
end
else
for kk=1,#blobfile do
local vv = blobfile[kk]
if not dname or find(vv,dname) then
- local kind = hash.type
- -- local search = filejoin(blobpath,vv,bname)
- local search = filejoin(blobroot,vv,bname)
- local result = methodhandler('concatinators',hash.type,blobroot,vv,bname)
+ local variant = hash.type
+ -- local search = filejoin(blobpath,vv,bname)
+ local search = filejoin(blobroot,vv,bname)
+ local result = methodhandler('concatinators',hash.type,blobroot,vv,bname)
if trace_detail then
- report_resolving("match: kind '%s', search '%s', result '%s'",kind,search,result)
+ report_resolving("match: variant '%s', search '%s', result '%s'",variant,search,result)
end
noffiles = noffiles + 1
- filelist[noffiles] = { kind, search, result }
+ filelist[noffiles] = { variant, search, result }
end
end
end
@@ -11950,14 +11985,14 @@ function resolvers.findgivenfile(filename)
return findgivenfiles(filename,false)[1] or ""
end
-local function doit(path,blist,bname,tag,kind,result,allresults)
+local function doit(path,blist,bname,tag,variant,result,allresults)
local done = false
- if blist and kind then
+ if blist and variant then
local resolve = resolvers.resolve -- added
if type(blist) == 'string' then
-- make function and share code
if find(lower(blist),path) then
- local full = methodhandler('concatinators',kind,tag,blist,bname) or ""
+ local full = methodhandler('concatinators',variant,tag,blist,bname) or ""
result[#result+1] = resolve(full)
done = true
end
@@ -11965,7 +12000,7 @@ local function doit(path,blist,bname,tag,kind,result,allresults)
for kk=1,#blist do
local vv = blist[kk]
if find(lower(vv),path) then
- local full = methodhandler('concatinators',kind,tag,vv,bname) or ""
+ local full = methodhandler('concatinators',variant,tag,vv,bname) or ""
result[#result+1] = resolve(full)
done = true
if not allresults then break end
diff --git a/tex/context/base/anch-pgr.mkiv b/tex/context/base/anch-pgr.mkiv
index 7c3ffdf43..afa881933 100644
--- a/tex/context/base/anch-pgr.mkiv
+++ b/tex/context/base/anch-pgr.mkiv
@@ -1243,47 +1243,6 @@
% % \setnewconstant\margincontentmethod \plusthree % textmethod % beware: 1 = old method
% % \setnewconstant\marginpagecheckmethod \plusone % splitmethod
-%D For a right menu, a sequence of calls to \type
-%D {right_menu_button} is generated.
-%D
-%D \starttyping
-%D right_menu_button (n, p, s=0/1/2, x, y, w, h, d) ;
-%D \stoptyping
-%D
-%D Here, n is the number of the button, s a status variable,
-%D while the rest is positional info. The status variable is
-%D 0, 1 or~2: not found, found and found but current page.
-
-% 0=not found 1=found 2=current page
-
-% geen leeg
-
-\newtoks\MPmenutoks
-
-\def\MPmenubuttons#1{\the\MPmenutoks}
-
-\appendtoks \global\MPmenutoks\emptytoks \to \everyshipout
-
-\newconstant\currentamrealpagemode % 0=notfound 1=found 2=currentpage
-
-\def\domenuitemposition#1#2#3%
- {\doifelsevalue{\??am#1\c!position}\v!yes
- {\doglobal\increment\currentamposition
- \doifreferencefoundelse{#2}% 0=not found, 1=same page, >1=elsewhere
- {\currentamrealpagemode\ifnum\currentreferencerealpage=\realpageno\plusone\else\plustwo\fi}%
- {\currentamrealpagemode\plustwo}%
- \expanded % \doglobal\appendetoks
- {\doglobal\noexpand\appendtoks
- #1_menu_button(\number\currentamposition,\the\currentamrealpagemode,\MPpos{#1:\currentamposition}) ;
- \to \MPmenutoks}%
- \hpos{#1:\currentamposition}{#3}}
- {#3}}
-
-\def\dowholemenuposition#1%
- {\ifnum\currentamposition>0
- \dowithnextbox{\hpos{menu:#1:\the\realpageno}{\flushnextbox}}\hbox
- \fi}
-
%D \macros
%D {GFC, GTC, GSC}
%D
diff --git a/tex/context/base/attr-col.lua b/tex/context/base/attr-col.lua
index fd69fb682..acabe62ac 100644
--- a/tex/context/base/attr-col.lua
+++ b/tex/context/base/attr-col.lua
@@ -269,17 +269,17 @@ local function reviver(data,n)
d = { gray, gray, gray, gray }
report_attributes("unable to revive color %s",n or "?")
else
- local kind = colors.forcedmodel(v[1])
- if kind == 2 then
+ local model = colors.forcedmodel(v[1])
+ if model == 2 then
local gray= graycolor(v[2])
d = { gray, gray, gray, gray }
- elseif kind == 3 then
+ elseif model == 3 then
local gray, rgb, cmyk = graycolor(v[2]), rgbcolor(v[3],v[4],v[5]), cmykcolor(v[6],v[7],v[8],v[9])
d = { rgb, gray, rgb, cmyk }
- elseif kind == 4 then
+ elseif model == 4 then
local gray, rgb, cmyk = graycolor(v[2]), rgbcolor(v[3],v[4],v[5]), cmykcolor(v[6],v[7],v[8],v[9])
d = { cmyk, gray, rgb, cmyk }
- elseif kind == 5 then
+ elseif model == 5 then
local spot = spotcolor(v[10],v[11],v[12],v[13])
-- d = { spot, gray, rgb, cmyk }
d = { spot, spot, spot, spot }
diff --git a/tex/context/base/attr-lay.lua b/tex/context/base/attr-lay.lua
index 5e60fbed3..32812785a 100644
--- a/tex/context/base/attr-lay.lua
+++ b/tex/context/base/attr-lay.lua
@@ -175,3 +175,5 @@ function viewerlayers.define(settings)
codeinjections.defineviewerlayer(settings)
end
end
+
+commands.defineviewerlayer = viewerlayers.define
diff --git a/tex/context/base/attr-lay.mkiv b/tex/context/base/attr-lay.mkiv
index efc9f4514..efea95bc9 100644
--- a/tex/context/base/attr-lay.mkiv
+++ b/tex/context/base/attr-lay.mkiv
@@ -44,11 +44,11 @@
\def\dodefineviewerlayer[#1][#2]% document wide properties
{\begingroup
\getparameters[\??lr][#2]%
- \ctxlua{attributes.viewerlayers.define{
+ \ctxcommand{defineviewerlayer{
tag = "#1",
title = "\@@lrtitle",
visible = "\@@lrstate",
- kind = 0, % 1 == frozen
+ editable = "\v!yes",
printable = "\@@lrprintable",
}}%
\doif\@@lrmethod\v!command
@@ -73,11 +73,11 @@
% layout components are implemented rather directly (speed)
\def\doinitializelayoutcomponent#1#2%
- {\ctxlua{backends.codeinjections.defineviewerlayer{% this will move to the lua end i.e be merged with register
+ {\ctxcommand{defineviewerlayer{% this will move to the lua end i.e be merged with register
tag = "#1:#2",
title = "#1 #2",
visible = "\v!start",
- kind = 0, % 1 == frozen
+ editable = "\v!yes",
printable = "\v!yes"
}}%
\edef\layoutcomponentboxattribute{attr \viewerlayerattribute \ctxlua{tex.write(attributes.viewerlayers.register('#1:#2',true))}\relax}%
@@ -101,5 +101,4 @@
\let\setlayoutcomponentattribute \dosetlayoutcomponentattribute
\let\resetlayoutcomponentattribute\doresetlayoutcomponentattribute}
-
\protect \endinput
diff --git a/tex/context/base/back-exp.lua b/tex/context/base/back-exp.lua
index d5bdc2b91..b9cfcefd4 100644
--- a/tex/context/base/back-exp.lua
+++ b/tex/context/base/back-exp.lua
@@ -57,7 +57,7 @@ local attributes = attributes
local variables = interfaces.variables
local tasks = nodes.tasks
-local fontchar = fonts.characters
+local fontchar = fonts.hashes.characters
local languagenames = languages.numbers
local nodecodes = nodes.nodecodes
diff --git a/tex/context/base/back-ini.lua b/tex/context/base/back-ini.lua
index 4e990aa38..5cabc16ac 100644
--- a/tex/context/base/back-ini.lua
+++ b/tex/context/base/back-ini.lua
@@ -6,10 +6,9 @@ if not modules then modules = { } end modules ['back-ini'] = {
license = "see context related readme files"
}
--- I need to check what is actually needed, maybe some can become
--- locals.
+local setmetatable = setmetatable
-backends = backends or { }
+backends = backends or { }
local backends = backends
local trace_backend = false trackers.register("backend.initializers", function(v) trace_finalizers = v end)
@@ -20,143 +19,35 @@ local function nothing() return nil end
backends.nothing = nothing
-backends.nodeinjections = {
-
- rgbcolor = nothing,
- cmykcolor = nothing,
- graycolor = nothing,
- spotcolor = nothing,
-
- transparency = nothing,
-
- overprint = nothing,
- knockout = nothing,
-
- positive = nothing,
- negative = nothing,
-
- effect = nothing,
-
- startlayer = nothing,
- stoplayer = nothing,
- switchlayer = nothing,
-
- reference = nothing,
- destination = nothing,
-
- addtags = nothing,
-
- insertu3d = nothing,
- insertswf = nothing,
- insertmovie = nothing,
- insertsound = nothing,
-
- injectbitmap = nothing,
-
-}
-
-backends.codeinjections = {
-
- prerollreference = nothing,
-
- presetsymbol = nothing,
- presetsymbollist = nothing,
- registersymbol = nothing,
- registeredsymbol = nothing,
-
- registercomment = nothing,
-
- embedfile = nothing,
- attachfile = nothing,
- attachmentid = nothing,
-
- adddocumentinfo = nothing,
- setupidentity = nothing,
- setupcanvas = nothing,
-
- setpagetransition = nothing,
-
- defineviewerlayer = nothing,
- useviewerlayer = nothing,
-
- addbookmarks = nothing,
-
- addtransparencygroup = nothing,
-
- typesetfield = nothing,
- doiffieldelse = nothing,
- doiffieldgroupelse = nothing,
- doiffieldsetelse = nothing,
- definefield = nothing,
- clonefield = nothing,
- definefieldset = nothing,
- setfieldcalculationset = nothing,
- getfieldgroup = nothing,
- getfieldset = nothing,
- setformsmethod = nothing,
- getdefaultfieldvalue = nothing,
-
- flushpageactions = nothing,
- flushdocumentactions = nothing,
-
- insertrenderingwindow = nothing,
- processrendering = nothing,
-
- setfigurecolorspace = nothing,
- setfigurealternative = nothing,
- setfiguremask = nothing,
-
- enabletags = nothing,
-
- mergereferences = nothing,
- mergeviewerlayers = nothing,
-
- setformat = nothing,
- getformatoption = nothing,
- supportedformats = nothing,
-
- -- called in tex
-
- finalizepage = nothing, -- will go when we have a hook at the lua end
-
- finishreference = nothing,
-
- getoutputfilename = nothing,
-
+local mt = {
+ __index = function(t,k)
+ t[k] = nothing
+ return nothing
+ end
}
-backends.registrations = {
-
- grayspotcolor = nothing,
- rgbspotcolor = nothing,
- cmykspotcolor = nothing,
-
- grayindexcolor = nothing,
- rgbindexcolor = nothing,
- cmykindexcolor = nothing,
-
- spotcolorname = nothing,
-
- transparency = nothing,
+local nodeinjections = { } setmetatable(nodeinjections, mt)
+local codeinjections = { } setmetatable(codeinjections, mt)
+local registrations = { } setmetatable(registrations, mt)
+local tables = { }
+local defaults = {
+ nodeinjections = nodeinjections,
+ codeinjections = codeinjections,
+ registrations = registrations,
+ tables = tables,
}
-local comment = { "comment", "" }
+backends.defaults = defaults
-backends.tables = {
- vfspecials = {
- red = comment,
- green = comment,
- blue = comment,
- black = comment,
- startslant = comment,
- stopslant = comment,
- }
-}
+backends.nodeinjections = { } setmetatable(backends.nodeinjections, { __index = nodeinjections })
+backends.codeinjections = { } setmetatable(backends.codeinjections, { __index = codeinjections })
+backends.registrations = { } setmetatable(backends.registrations, { __index = registrations })
+backends.tables = { } setmetatable(backends.tables, { __index = tables })
backends.current = "unknown"
-function backends.install(what) -- these can become metatables
+function backends.install(what)
if type(what) == "string" then
local backend = backends[what]
if backend then
@@ -164,32 +55,10 @@ function backends.install(what) -- these can become metatables
report_backend("initializing backend %s (%s)",what,backend.comment or "no comment")
end
backends.current = what
- for _, category in next, { "nodeinjections", "codeinjections", "registrations", "tables" } do
- local plugin = backend[category]
- local whereto = backends[category]
- if plugin then
- for name, meaning in next, whereto do
- if plugin[name] then
- whereto[name] = plugin[name]
- -- report_backend("installing function %s in category %s of %s",name,category,what)
- elseif trace_backend then
- report_backend("no function %s in category %s of %s",name,category,what)
- end
- end
- elseif trace_backend then
- report_backend("no category %s in %s",category,what)
- end
- -- extra checks
- for k, v in next, whereto do
- if not plugin[k] then
- report_backend("entry %s in %s is not set",k,category)
- end
- end
- for k, v in next, plugin do
- if not whereto[k] then
- report_backend("entry %s in %s is not used",k,category)
- end
- end
+ for category, default in next, defaults do
+ local target, plugin = backends[category], backend[category]
+ setmetatable(plugin, { __index = default })
+ setmetatable(target, { __index = plugin })
end
elseif trace_backend then
report_backend("no backend named %s",what)
@@ -205,3 +74,14 @@ statistics.register("used backend", function()
return nil
end
end)
+
+local comment = { "comment", "" }
+
+tables.vfspecials = {
+ red = comment,
+ green = comment,
+ blue = comment,
+ black = comment,
+ startslant = comment,
+ stopslant = comment,
+}
diff --git a/tex/context/base/back-pdf.mkiv b/tex/context/base/back-pdf.mkiv
index 392dc8984..5b7de128d 100644
--- a/tex/context/base/back-pdf.mkiv
+++ b/tex/context/base/back-pdf.mkiv
@@ -56,11 +56,19 @@
\setjobsuffix{pdf}
-%D PDF/X:
+%D PDF/X (matbe combine the two lua calls)
+
+\setupbackend
+ [xmpfile=]
+
+\appendtoks
+ \doifsomething{\backendparameter{xmpfile}}
+ {\ctxcommand{setxmpfile("\backendparameter{xmpfile}")}}%
+\to \everysetupbackend
\appendtoks
\doifsomething{\backendparameter\c!format}
- {\ctxlua{backends.codeinjections.setformat {
+ {\ctxcommand{setformat {
format = "\backendparameter\c!format",
level = "\backendparameter\c!level",
option = "\backendparameter\c!option",
diff --git a/tex/context/base/bibl-tra.lua b/tex/context/base/bibl-tra.lua
index 55d541fdc..e0eaf64b3 100644
--- a/tex/context/base/bibl-tra.lua
+++ b/tex/context/base/bibl-tra.lua
@@ -132,7 +132,7 @@ function hacks.resolve(prefix,block,reference) -- maybe already feed it split
if subset then
local result, nofresult, done = { }, 0, { }
block = tonumber(block)
- for rest in gmatch(reference,"([^,%s]+)") do
+ for rest in gmatch(reference,"[^, ]+") do
local blk, tag, found = block, nil, nil
if block then
tag = blk .. ":" .. rest
diff --git a/tex/context/base/blob-ini.lua b/tex/context/base/blob-ini.lua
index 623325040..48cf4e393 100644
--- a/tex/context/base/blob-ini.lua
+++ b/tex/context/base/blob-ini.lua
@@ -23,13 +23,17 @@ if not modules then modules = { } end modules ['blob-ini'] = {
-- collapse or new pars
-- interline spacing etc
+-- blob.char
+-- blob.line
+-- blob.paragraph
+-- blob.page
+
local type = type
+local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns
local report_blobs = logs.reporter("blobs")
-local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns
-
-local fontdata = fonts.identifiers
+local fontdata = fonts.hashes.identifiers
local nodepool = nodes.pool
@@ -68,14 +72,14 @@ function blobs.new()
end
function blobs.append(t,str) -- will be link nodes.link
- local kind = type(str)
+ local typ = type(str)
local dummy = nil
- if kind == "number" then
+ if typ == "number" then
str = tostring(str)
- kind = "string"
+ typ = "string"
end
local list = t.list
- if kind == "string" then
+ if typ == "string" then
local pars = lpegmatch(ctxtextcapture,str)
local noflist = #list
for p=1,#pars do
@@ -131,3 +135,25 @@ function blobs.write(t)
end
end
end
+
+
+-- blob.char
+-- blob.line: head, tail
+-- blob.paragraph
+-- blob.page
+
+--~ local lineblob = {
+--~ type = "line",
+--~ head = false,
+--~ tail = false,
+--~ pack = false,
+--~ properties = { },
+--~ end
+
+--~ local parblob = {
+--~ type = "line",
+--~ head = false,
+--~ tail = false,
+--~ pack = false,
+--~ properties = { },
+--~ end
diff --git a/tex/context/base/buff-ver.lua b/tex/context/base/buff-ver.lua
index 392c323be..a1f98ab0a 100644
--- a/tex/context/base/buff-ver.lua
+++ b/tex/context/base/buff-ver.lua
@@ -194,17 +194,17 @@ end
local fallback = context.verbatim
-local function makepattern(visualizer,kind,pattern)
+local function makepattern(visualizer,replacement,pattern)
if not pattern then
- report_visualizers("error in visualizer: %s",kind)
+ report_visualizers("error in visualizer: %s",replacement)
return patterns.alwaystrue
else
- if type(visualizer) == "table" and type(kind) == "string" then
- kind = visualizer[kind] or fallback
+ if type(visualizer) == "table" and type(replacement) == "string" then
+ replacement = visualizer[replacement] or fallback
else
- kind = fallback
+ replacement = fallback
end
- return (C(pattern) * CargOne) / kind
+ return (C(pattern) * CargOne) / replacement
end
end
diff --git a/tex/context/base/buff-ver.mkiv b/tex/context/base/buff-ver.mkiv
index d92a5d07e..ab1d0cb23 100644
--- a/tex/context/base/buff-ver.mkiv
+++ b/tex/context/base/buff-ver.mkiv
@@ -304,7 +304,7 @@
{\dontleavehmode
\bgroup
\edef\currenttype{#1}%
- \dolettypeparameter\v!lines\v!hyphenated
+ \lettypeparameter\v!lines\v!hyphenated
\let\specialobeyedspace\specialstretchedspace
\doifnextoptionalelse\redotype\dodotype}
diff --git a/tex/context/base/chem-str.lua b/tex/context/base/chem-str.lua
index 44849c067..1a6ed4dc2 100644
--- a/tex/context/base/chem-str.lua
+++ b/tex/context/base/chem-str.lua
@@ -161,7 +161,7 @@ function chemicals.define(name,spec,text)
}
end
-local metacode, kind, keys, bonds, max, txt, textsize, rot, pstack
+local metacode, variant, keys, bonds, max, txt, textsize, rot, pstack
local molecule = chemicals.molecule -- or use lpegmatch(chemicals.moleculeparser,...)
local function fetch(txt)
@@ -226,7 +226,7 @@ local function process(spec,text,n,rulethickness,rulecolor,offset)
else
local rep, operation, special, index, upto, set, text = lpegmatch(pattern,s)
if operation == "pb" then
- insert(pstack,kind)
+ insert(pstack,variant)
m = m + 1 ; metacode[m] = syntax.pb.direct
if keys[special] == "text" and index then
if keys["c"..special] == "text" then -- can be option: auto ...
@@ -236,19 +236,19 @@ local function process(spec,text,n,rulethickness,rulecolor,offset)
end
end
elseif operation == "save" then
- insert(pstack,kind)
+ insert(pstack,variant)
m = m + 1 ; metacode[m] = syntax.save.direct
elseif operation == "pe" or operation == "restore" then
- kind = remove(pstack)
- local ss = syntax[kind]
+ variant = remove(pstack)
+ local ss = syntax[variant]
local prev = bonds or 6
keys, bonds, max, rot = ss.keys, ss.n, ss.max, 1
m = m + 1 ; metacode[m] = syntax[operation].direct
m = m + 1 ; metacode[m] = format("chem_set(%s,%s) ;",prev,bonds)
elseif operation == "front" then
- if syntax[kind .. "_front"] then
- kind = kind .. "_front"
- local ss = syntax[kind]
+ if syntax[variant .. "_front"] then
+ variant = variant .. "_front"
+ local ss = syntax[variant]
local prev = bonds or 6
keys, bonds, max, rot = ss.keys, ss.n, ss.max, 1
m = m + 1 ; metacode[m] = format("chem_set(%s,%s) ;",prev,bonds)
@@ -271,7 +271,7 @@ local function process(spec,text,n,rulethickness,rulecolor,offset)
end
elseif ss.keys then
local prev = bonds or 6
- kind, keys, bonds, max, rot = s, ss.keys, ss.n, ss.max, 1
+ variant, keys, bonds, max, rot = s, ss.keys, ss.n, ss.max, 1
m = m + 1 ; metacode[m] = format("chem_set(%s,%s) ;",prev,bonds)
end
else
@@ -308,7 +308,7 @@ local function process(spec,text,n,rulethickness,rulecolor,offset)
end
end
elseif what == "text" then
- local align = syntax[kind].align
+ local align = syntax[variant].align
align = align and align[operation]
align = align and align[rot]
if set then
@@ -440,7 +440,7 @@ function chemicals.start(settings)
l/25, r/25, t/25, b/25, scale,
tostring(settings.axis == variables.on), tostring(width), tostring(height), tostring(offset)
) }
- kind, keys, bonds, stack, rot, pstack = "six", { }, 6, { }, 1, { }
+ variant, keys, bonds, stack, rot, pstack = "six", { }, 6, { }, 1, { }
end
function chemicals.stop()
diff --git a/tex/context/base/cldf-int.lua b/tex/context/base/cldf-int.lua
index e2fff18dc..4e2e7b0e6 100644
--- a/tex/context/base/cldf-int.lua
+++ b/tex/context/base/cldf-int.lua
@@ -75,8 +75,8 @@ function mkiv.define(name,specification) -- name is optional
texsprint(ctxcatcodes,"\\def",mkivdo)
for i=1,na do
local a = arguments[i]
- local kind = a[1]
- if kind == "option" then
+ local variant = a[1]
+ if variant == "option" then
texsprint(ctxcatcodes,"[#",i,"]")
if not done then
opt = opt + 1
@@ -93,12 +93,12 @@ function mkiv.define(name,specification) -- name is optional
end
for i=1,na do
local a = arguments[i]
- local kind = a[2]
- if kind == "list" then
+ local variant = a[2]
+ if variant == "list" then
texsprint(ctxcatcodes,",mkiv.a([[#",i,"]])")
- elseif kind == "hash" then
+ elseif variant == "hash" then
texsprint(ctxcatcodes,",mkiv.h([[#",i,"]])")
- elseif kind == "number" then
+ elseif variant == "number" then
texsprint(ctxcatcodes,",mkiv.n([[#",i,"]])")
else
texsprint(ctxcatcodes,",[[#",i,"]]")
diff --git a/tex/context/base/colo-ext.mkiv b/tex/context/base/colo-ext.mkiv
index 343b062af..771974d4d 100644
--- a/tex/context/base/colo-ext.mkiv
+++ b/tex/context/base/colo-ext.mkiv
@@ -77,7 +77,7 @@
% A goodie that replaces the startMPcolor hackery
-%\definecolor[red-t] [r=1,t=0.5,a=1]
+% \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]
diff --git a/tex/context/base/colo-icc.lua b/tex/context/base/colo-icc.lua
index 2ce34e8cd..904d42143 100644
--- a/tex/context/base/colo-icc.lua
+++ b/tex/context/base/colo-icc.lua
@@ -90,8 +90,8 @@ function colors.iccprofile(filename,verbose)
for tag, spec in next, tags do
if tag then
local offset, length = spec.offset, spec.length
- local kind = readstring(f,offset,4)
- if kind == "text" or kind == "desc" then
+ local variant = readstring(f,offset,4)
+ if variant == "text" or variant == "desc" then
local str = readstring(f,length-4)
tags[tag] = {
data = str,
@@ -99,7 +99,7 @@ function colors.iccprofile(filename,verbose)
}
else
if verbose then
- report_colors("ignoring tag '%s' or type '%s' in profile '%s'",tag,kind,fullname)
+ report_colors("ignoring tag '%s' or type '%s' in profile '%s'",tag,variant,fullname)
end
tags[tag] = nil
end
diff --git a/tex/context/base/colo-ini.lua b/tex/context/base/colo-ini.lua
index 75cee7b23..635a13ec5 100644
--- a/tex/context/base/colo-ini.lua
+++ b/tex/context/base/colo-ini.lua
@@ -209,16 +209,16 @@ local function do_registerspotcolor(parent,name,parentnumber,e,f,d,p)
if not registered[parentnumber] then
local v = colors.values[parentnumber]
if v then
- local kind = colors.default -- else problems with shading etc
- if kind == 1 then kind = v[1] end
+ local model = colors.default -- else problems with shading etc
+ if model == 1 then model = v[1] end
if e and e ~= "" then
registrations.spotcolorname(parent,e) -- before registration of the color
end
- if kind == 2 then -- name noffractions names p's r g b
+ if model == 2 then -- name noffractions names p's r g b
registrations.grayspotcolor(parent,f,d,p,v[2])
- elseif kind == 3 then
+ elseif model == 3 then
registrations.rgbspotcolor (parent,f,d,p,v[3],v[4],v[5])
- elseif kind == 4 then
+ elseif model == 4 then
registrations.cmykspotcolor(parent,f,d,p,v[6],v[7],v[8],v[9])
end
end
@@ -230,13 +230,13 @@ local function do_registermultitonecolor(parent,name,parentnumber,e,f,d,p) -- sa
if not registered[parentnumber] then
local v = colors.values[parentnumber]
if v then
- local kind = colors.default -- else problems with shading etc
- if kind == 1 then kind = v[1] end
- if kind == 2 then
+ local model = colors.default -- else problems with shading etc
+ if model == 1 then model = v[1] end
+ if model == 2 then
registrations.grayindexcolor(parent,f,d,p,v[2])
- elseif kind == 3 then
+ elseif model == 3 then
registrations.rgbindexcolor (parent,f,d,p,v[3],v[4],v[5])
- elseif kind == 4 then
+ elseif model == 4 then
registrations.cmykindexcolor(parent,f,d,p,v[6],v[7],v[8],v[9])
end
end
@@ -551,7 +551,7 @@ function colors.defineintermediatecolor(name,fraction,c_one,c_two,a_one,a_two,sp
if one then
if two then
local csone, cstwo = one[1], two[1]
- if csone == cstwo then
+ -- if csone == cstwo then
-- actually we can set all 8 values at once here but this is cleaner as we avoid
-- problems with weighted gray conversions and work with original values
local ca
@@ -565,7 +565,7 @@ function colors.defineintermediatecolor(name,fraction,c_one,c_two,a_one,a_two,sp
ca = register_color(name,'gray',f(one,two,2,fraction))
end
definecolor(name,ca,global,freeze)
- end
+ -- end
else
local csone = one[1]
local ca
@@ -627,13 +627,13 @@ commands.definemultitonecolor = colors.definemultitonecolor
commands.definetransparency = colors.definetransparency
commands.defineintermediatecolor = colors.defineintermediatecolor
-function commands.spotcolorname (a) context(colors.spotcolorname (a)) end
-function commands.spotcolorparent (a) context(colors.spotcolorparent (a)) end
-function commands.spotcolorvalue (a) context(colors.spotcolorvalue (a)) end
-function commands.colorcomponents (a) context(colors.colorcomponents (a)) end
-function commands.transparencycomponents(a) context(colors.transparencycomponents(a)) end
-function commands.formatcolor (a) context(colors.formatcolor (a)) end
-function commands.formatgray (a) context(colors.formatgray (a)) end
+function commands.spotcolorname (a) context(colors.spotcolorname (a)) end
+function commands.spotcolorparent (a) context(colors.spotcolorparent (a)) end
+function commands.spotcolorvalue (a) context(colors.spotcolorvalue (a)) end
+function commands.colorcomponents (a) context(colors.colorcomponents (a)) end
+function commands.transparencycomponents(a) context(colors.transparencycomponents(a)) end
+function commands.formatcolor (...) context(colors.formatcolor (...)) end
+function commands.formatgray (...) context(colors.formatgray (...)) end
function commands.mpcolor(model,ca,ta,default)
context(colors.mpcolor(model,ca,ta,default))
diff --git a/tex/context/base/colo-ini.mkiv b/tex/context/base/colo-ini.mkiv
index b842337a9..24627b68c 100644
--- a/tex/context/base/colo-ini.mkiv
+++ b/tex/context/base/colo-ini.mkiv
@@ -140,15 +140,15 @@
%D \showsetup{color}
%D \showsetup{graycolor}
- \def\switchtocolor [#1]{\csname#1\endcsname}
+\unexpanded\def\switchtocolor [#1]{\csname#1\endcsname}
\unexpanded\def\color [#1]{\groupedcommand{\doactivatecolor{#1}}{}}
\unexpanded\def\startcolor [#1]{\begingroup\doactivatecolor{#1}}
\unexpanded\def\stopcolor {\endgroup}
\unexpanded\def\graycolor [#1]{\groupedcommand{\dosetcolormodel{gray}\getvalue{#1}}{}}
\unexpanded\def\colored [#1]{\groupedcommand{\definecolor[@colored@][#1]\doactivatecolor{@colored@}}{}}
\unexpanded\def\fastcolored [#1]#2{\begingroup\dodefinefastcolor[@colored@][#1]\doactivatecolor{@colored@}#2\endgroup}
- \def\predefinecolor [#1]{\flushatshipout{\hbox{\color[#1]{}}}}
- \def\predefineindexcolor[#1]{\flushatshipout{\hbox{\color[#1]{}}}}
+\unexpanded\def\predefinecolor [#1]{\flushatshipout{\hbox{\color[#1]{}}}}
+\unexpanded\def\predefineindexcolor[#1]{\flushatshipout{\hbox{\color[#1]{}}}}
% some of this will go away
@@ -156,11 +156,17 @@
\unexpanded\def\stopcolorpage {\stopcolor}
\unexpanded\def\startraster [#1]{\dosetrastercolor{#1}}
\unexpanded\def\stopraster {}
- \def\raster [#1]{\groupedcommand{\dosetrastercolor{#1}}{}}
- \def\faststartcolor [#1]{\doactivatecolor{#1}}
- \def\faststopcolor {}
+\unexpanded\def\raster [#1]{\groupedcommand{\dosetrastercolor{#1}}{}}
+\unexpanded\def\faststartcolor [#1]{\doactivatecolor{#1}}
+\unexpanded\def\faststopcolor {}
\unexpanded\def\dosetcolorattribute#1#2{\ifcsname#1#2\endcsname\doactivatecolor{\csname#1#2\endcsname}\fi}
+\def\getcolorattributevalue#1#2% color macro (obsolete again, we have a better method)
+ {\begingroup
+ \doactivatecolor{#1}%
+ \normalexpanded{\endgroup\edef\noexpand#2%
+ {\ifnum\attribute\colorattribute=\attributeunsetvalue\else\number\attribute\colorattribute\fi}}}
+
\let\grey\graycolor
%D Stacking:
@@ -749,7 +755,7 @@
\letvalueempty{(cs:-}
\letvalueempty{(ts:-}
-\def\doactivatecolor#1% : in currentpalet, maybe not, ugly
+\def\doactivatecolor#1% : in currentpalet, maybe not, ugly (some day at the lua end)
{\def\currentcolorname{#1}%
\ifcsname(cs:\currentpalet#1)\endcsname
\csname(cs:\currentpalet#1)\endcsname
diff --git a/tex/context/base/cont-new.mkii b/tex/context/base/cont-new.mkii
index c5ffe80c9..dd6fb1bf7 100644
--- a/tex/context/base/cont-new.mkii
+++ b/tex/context/base/cont-new.mkii
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\newcontextversion{2011.02.25 22:03}
+\newcontextversion{2011.03.25 18:03}
%D This file is loaded at runtime, thereby providing an
%D excellent place for hacks, patches, extensions and new
diff --git a/tex/context/base/cont-new.mkiv b/tex/context/base/cont-new.mkiv
index b47ff0ef2..7a4533c56 100644
--- a/tex/context/base/cont-new.mkiv
+++ b/tex/context/base/cont-new.mkiv
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\newcontextversion{2011.02.25 22:03}
+\newcontextversion{2011.03.25 18:03}
%D This file is loaded at runtime, thereby providing an
%D excellent place for hacks, patches, extensions and new
diff --git a/tex/context/base/context.mkii b/tex/context/base/context.mkii
index 9d4a81588..c9f510415 100644
--- a/tex/context/base/context.mkii
+++ b/tex/context/base/context.mkii
@@ -20,7 +20,7 @@
%D your styles an modules.
\edef\contextformat {\jobname}
-\edef\contextversion{2011.02.25 22:03}
+\edef\contextversion{2011.03.25 18:03}
%D For those who want to use this:
diff --git a/tex/context/base/context.mkiv b/tex/context/base/context.mkiv
index 1906ffea4..cba0f10f5 100644
--- a/tex/context/base/context.mkiv
+++ b/tex/context/base/context.mkiv
@@ -20,7 +20,7 @@
%D your styles an modules.
\edef\contextformat {\jobname}
-\edef\contextversion{2011.02.25 22:03}
+\edef\contextversion{2011.03.25 18:03}
%D For those who want to use this:
@@ -37,7 +37,8 @@
\def\loadcorefile#1{\normalinput#1\relax}
\def\loadmarkfile#1{\normalinput#1.\mksuffix\relax}
\def\loadmkiifile#1{}
-\def\loadmkivfile#1{\normalinput#1\relax}
+\def\loadmkivfile#1{\normalinput#1.mkiv\relax}
+\def\loadmkvifile#1{\normalinput#1.mkvi\relax}
%D First we load the system modules. These implement a lot of
%D manipulation macros. We start with setting up some basic \TEX\
@@ -134,7 +135,7 @@
\loadmarkfile{trac-tex}
\loadmarkfile{trac-deb}
-\loadmarkfile{blob-ini} % not to be used, we only use a helper
+%loadmarkfile{blob-ini} % not to be used, we only use a helper
\loadmarkfile{supp-box}
@@ -183,6 +184,7 @@
\loadmarkfile{sort-ini}
+\loadmkvifile{pack-mis}
\loadmarkfile{pack-rul}
\loadmarkfile{lxml-ini}
@@ -216,7 +218,9 @@
\loadmarkfile{anch-pos}
-\loadmarkfile{scrn-nav}
+\loadmkvifile{scrn-ini}
+\loadmkvifile{scrn-ref}
+
\loadmarkfile{pack-obj}
\loadmarkfile{strc-itm}
@@ -268,10 +272,11 @@
\loadmarkfile{page-sel} % optional
\loadmarkfile{page-com} % optional
-\loadmarkfile{scrn-int}
-\loadmarkfile{scrn-men}
-\loadmarkfile{scrn-but}
-\loadmarkfile{scrn-bar}
+\loadmkvifile{scrn-pag}
+\loadmkvifile{scrn-wid}
+\loadmkvifile{scrn-but}
+\loadmkvifile{scrn-bar}
+
\loadmarkfile{strc-bkm} % bookmarks
\loadmarkfile{tabl-com}
@@ -287,8 +292,8 @@
\loadmarkfile{java-ini}
-\loadmarkfile{scrn-fld}
-\loadmarkfile{scrn-hlp}
+\loadmkvifile{scrn-fld}
+\loadmkvifile{scrn-hlp}
\loadmarkfile{char-enc}
\loadmarkfile{font-ini}
@@ -298,6 +303,8 @@
\loadmarkfile{font-col}
\loadmarkfile{font-gds}
+\loadmarkfile{blob-ini} % not to be used, we only use a helper
+
\loadmarkfile{typo-cln}
\loadmarkfile{typo-spa}
\loadmarkfile{typo-krn}
@@ -315,9 +322,6 @@
\loadmarkfile{scrp-ini}
\loadmarkfile{prop-ini} % only for downward compatibility
-%loadmarkfile{prop-lay}
-%loadmarkfile{prop-neg}
-%loadmarkfile{prop-eff}
\loadmarkfile{mlib-ctx}
diff --git a/tex/context/base/context.todo b/tex/context/base/context.todo
new file mode 100644
index 000000000..111243f96
--- /dev/null
+++ b/tex/context/base/context.todo
@@ -0,0 +1,4 @@
+% marginrules
+
+% consistently use label/name/tag
+% consistently use type/kind
diff --git a/tex/context/base/core-con.lua b/tex/context/base/core-con.lua
index ea1f6635d..3ad9f6c98 100644
--- a/tex/context/base/core-con.lua
+++ b/tex/context/base/core-con.lua
@@ -142,7 +142,9 @@ local function chrs(n,m,t)
chrs(floor((n-1)/26),m,t)
n = (n-1)%26 + 1
end
- t[#t+1] = utfchar(n+m)
+ if n ~= 0 then
+ t[#t+1] = utfchar(n+m)
+ end
if n <= 26 then
return concat(t)
end
diff --git a/tex/context/base/core-ini.mkiv b/tex/context/base/core-ini.mkiv
index 34e20d3f1..c823c9594 100644
--- a/tex/context/base/core-ini.mkiv
+++ b/tex/context/base/core-ini.mkiv
@@ -28,7 +28,7 @@
\appendtoks \showparagraphnumber \to \everypar
\appendtoks \restoreinterlinepenalty \to \everypar
%appendtoks \flushmargincontents \to \everypar
-\appendtoks \flushcommentanchors \to \everypar
+%appendtoks \flushcommentanchors \to \everypar
\appendtoks \flushnotes \to \everypar
\appendtoks \synchronizenotes \to \everypar
\appendtoks \OTRSETshowstatus \to \everypar
diff --git a/tex/context/base/core-mis.mkiv b/tex/context/base/core-mis.mkiv
index 2214d77c1..06ee5b617 100644
--- a/tex/context/base/core-mis.mkiv
+++ b/tex/context/base/core-mis.mkiv
@@ -196,72 +196,6 @@
\c!inbetween={\blank[\v!medium]},
\c!after=\blank]
-% \definieerplaats[naam][instellingen]
-% \stelplaatsin[naam][instellingen]
-% \plaats<naam>[[instellingen]]
-%
-% - still undocumented and also not in setupb yet
-% - kan ook intern/direct (scheelt duplicatie), zie \framedtext
-
-\def\dodefineplacement[#1][#2]%
- {\getparameters
- [\??pl#1]
- [\c!left=\hss,
- \c!right=\hss,
- \c!linecorrection=\v!off,
- \c!depthcorrection=\v!off,
- \c!margin=\v!standard,
- \c!grid=\v!middle,
- %\c!before=,
- %\c!after=,
- #2]%
- \setvalue{\e!place#1}{\doplacement[\??pl#1]}}
-
-\unexpanded\def\defineplacement
- {\dodoubleempty\dodefineplacement}
-
-\unexpanded\def\setupplacement
- {\dodoubleempty\dosetupplacement}
-
-\def\dosetupplacement[#1]%
- {\dodoubleempty\getparameters[\??pl#1]}
-
-\def\doplacement
- {\dodoubleempty\dodoplacement}
-
-\def\dodoplacement[#1][#2]% correctie moet mooier
- {\bgroup
- \dowithnextboxcontent
- {\forgetall}
- {\setlocalhsize
- \getparameters[#1][#2]%
- \getvalue{#1\c!before}%
- \begingroup
- \disableparpositions
- \setbox\nextbox\hbox to \localhsize
- {\getvalue{#1\c!left}%
- \flushnextbox
- \getvalue{#1\c!right}}%
- \ifinsidefloat \else
- \addlocalbackgroundtobox\nextbox
- \fi
- \ifgridsnapping
- \doifundefined{#1\c!grid}{\letvalue{#1\c!grid}\v!middle}%
- % unchecked
- \doifinset{\getvalue{#1\c!margin}}{\v!standard,\v!yes}\noindent
- \snaptogrid[\getvalue{#1\c!grid}]\hbox{\flushnextbox}%
- \else
- \doifvalue{#1\c!linecorrection}\v!on \startbaselinecorrection
- \doifinset{\getvalue{#1\c!margin}}{\v!standard,\v!yes}\noindent
- \flushnextbox
- \doifvalue{#1\c!depthcorrection}\v!on\baselinecorrection
- \doifvalue{#1\c!linecorrection }\v!on\stopbaselinecorrection
- \fi
- \endgroup
- \getvalue{#1\c!after}%
- \egroup}
- \vbox}
-
% Te zijner tijd [plaats=boven,onder,midden] implementeren,
% in dat geval moet eerst de maximale hoogte worden bepaald.
%
diff --git a/tex/context/base/data-ctx.lua b/tex/context/base/data-ctx.lua
index adf334d8e..345e9c741 100644
--- a/tex/context/base/data-ctx.lua
+++ b/tex/context/base/data-ctx.lua
@@ -6,38 +6,4 @@ if not modules then modules = { } end modules ['data-ctx'] = {
license = "see context related readme files"
}
-local format = string.format
-
-local report_dump = logs.reporter("resolvers","dump")
-
-local resolvers = resolvers
-
-local function saveusedfilesin_trees()
- local jobname = environment.jobname
- if not jobname or jobname == "" then jobname = "luatex" end
- local filename = file.replacesuffix(jobname,'jlg')
- local f = io.open(filename,'w')
- if f then
- f:write("<?xml version='1.0' standalone='yes'?>\n")
- f:write("<rl:job>\n")
- f:write(format("\t<rl:jobname>%s</rl:jobname>\n",jobname))
- f:write(format("\t<rl:contextversion>%s</rl:contextversion>\n",environment.version))
- local found = resolvers.instance.foundintrees
- local sorted = table.sortedkeys(found)
- if #sorted > 0 then
- f:write("\t<rl:files>\n")
- for k=1,#sorted do
- local v = sorted[k]
- f:write(format("\t\t<rl:file n='%s'>%s</rl:file>\n",found[v],v))
- end
- f:write("\t</rl:files>\n")
- else
- f:write("\t<rl:files/>\n")
- end
- f:write("</rl:job>\n")
- f:close()
- report_dump("saving used tree files in '%s'",filename)
- end
-end
-
-directives.register("system.dumpfiles", function() saveusedfilesintrees() end)
+-- empty
diff --git a/tex/context/base/data-res.lua b/tex/context/base/data-res.lua
index 7d4e102fe..82066a90e 100644
--- a/tex/context/base/data-res.lua
+++ b/tex/context/base/data-res.lua
@@ -320,8 +320,8 @@ local function load_configuration_files()
local variables = data.variables or { }
local warning = false
for k, v in next, data do
- local kind = type(v)
- if kind == "table" then
+ local variant = type(v)
+ if variant == "table" then
initializesetter(filename,k,v)
elseif variables[k] == nil then
if trace_locating and not warning then
@@ -593,7 +593,7 @@ function resolvers.registerextrapath(paths,subpaths)
end
end
elseif subpaths and subpaths ~= "" then
- for i=1,n do
+ for i=1,oldn do
-- we gmatch each step again, not that fast, but used seldom
for s in gmatch(subpaths,"[^,]+") do
local ps = ep[i] .. "/" .. s
@@ -762,29 +762,29 @@ local function collect_files(names)
local blobroot = files.__path__ or blobpath
if type(blobfile) == 'string' then
if not dname or find(blobfile,dname) then
- local kind = hash.type
- -- local search = filejoin(blobpath,blobfile,bname)
- local search = filejoin(blobroot,blobfile,bname)
- local result = methodhandler('concatinators',hash.type,blobroot,blobfile,bname)
+ local variant = hash.type
+ -- local search = filejoin(blobpath,blobfile,bname)
+ local search = filejoin(blobroot,blobfile,bname)
+ local result = methodhandler('concatinators',hash.type,blobroot,blobfile,bname)
if trace_detail then
- report_resolving("match: kind '%s', search '%s', result '%s'",kind,search,result)
+ report_resolving("match: variant '%s', search '%s', result '%s'",variant,search,result)
end
noffiles = noffiles + 1
- filelist[noffiles] = { kind, search, result }
+ filelist[noffiles] = { variant, search, result }
end
else
for kk=1,#blobfile do
local vv = blobfile[kk]
if not dname or find(vv,dname) then
- local kind = hash.type
- -- local search = filejoin(blobpath,vv,bname)
- local search = filejoin(blobroot,vv,bname)
- local result = methodhandler('concatinators',hash.type,blobroot,vv,bname)
+ local variant = hash.type
+ -- local search = filejoin(blobpath,vv,bname)
+ local search = filejoin(blobroot,vv,bname)
+ local result = methodhandler('concatinators',hash.type,blobroot,vv,bname)
if trace_detail then
- report_resolving("match: kind '%s', search '%s', result '%s'",kind,search,result)
+ report_resolving("match: variant '%s', search '%s', result '%s'",variant,search,result)
end
noffiles = noffiles + 1
- filelist[noffiles] = { kind, search, result }
+ filelist[noffiles] = { variant, search, result }
end
end
end
@@ -1453,14 +1453,14 @@ function resolvers.findgivenfile(filename)
return findgivenfiles(filename,false)[1] or ""
end
-local function doit(path,blist,bname,tag,kind,result,allresults)
+local function doit(path,blist,bname,tag,variant,result,allresults)
local done = false
- if blist and kind then
+ if blist and variant then
local resolve = resolvers.resolve -- added
if type(blist) == 'string' then
-- make function and share code
if find(lower(blist),path) then
- local full = methodhandler('concatinators',kind,tag,blist,bname) or ""
+ local full = methodhandler('concatinators',variant,tag,blist,bname) or ""
result[#result+1] = resolve(full)
done = true
end
@@ -1468,7 +1468,7 @@ local function doit(path,blist,bname,tag,kind,result,allresults)
for kk=1,#blist do
local vv = blist[kk]
if find(lower(vv),path) then
- local full = methodhandler('concatinators',kind,tag,vv,bname) or ""
+ local full = methodhandler('concatinators',variant,tag,vv,bname) or ""
result[#result+1] = resolve(full)
done = true
if not allresults then break end
diff --git a/tex/context/base/data-tex.lua b/tex/context/base/data-tex.lua
index fddd04bcc..14148b20e 100644
--- a/tex/context/base/data-tex.lua
+++ b/tex/context/base/data-tex.lua
@@ -60,17 +60,17 @@ function helpers.textopener(tag,filename,filehandle)
filehandle:close()
end
if type(lines) == "string" then
- local kind = utffiletype(lines)
+ local coding = utffiletype(lines)
if trace_locating then
- report_tex("%s opener, '%s' opened using method '%s'",tag,filename,kind)
+ report_tex("%s opener, '%s' opened using method '%s'",tag,filename,coding)
end
- if kind == "utf-16-be" then
+ if coding == "utf-16-be" then
lines = unicode.utf16_to_utf8_be(lines)
- elseif kind == "utf-16-le" then
+ elseif coding == "utf-16-le" then
lines = unicode.utf16_to_utf8_le(lines)
- elseif kind == "utf-32-be" then
+ elseif coding == "utf-32-be" then
lines = unicode.utf32_to_utf8_be(lines)
- elseif kind == "utf-32-le" then
+ elseif coding == "utf-32-le" then
lines = unicode.utf32_to_utf8_le(lines)
else -- utf8 or unknown
if textfileactions.dirty then -- maybe use autocompile
diff --git a/tex/context/base/font-afm.lua b/tex/context/base/font-afm.lua
index e9450f88d..8d35be9d6 100644
--- a/tex/context/base/font-afm.lua
+++ b/tex/context/base/font-afm.lua
@@ -24,39 +24,49 @@ local trace_defining = false trackers.register("fonts.defining", function(v) tr
local report_afm = logs.reporter("fonts","afm loading")
-local next, type = next, type
+local next, type, tonumber = next, type, tonumber
local format, match, gmatch, lower, gsub, strip = string.format, string.match, string.gmatch, string.lower, string.gsub, string.strip
-local lpegmatch = lpeg.match
local abs = math.abs
+local P, S, C, R, lpegmatch = lpeg.P, lpeg.S, lpeg.C, lpeg.R, lpeg.match
-local findbinfile = resolvers.findbinfile
+local fonts = fonts
+local afm = { }
+local pfb = { }
+fonts.handlers.afm = afm
+fonts.handlers.pfb = pfb
-local fonts = fonts
-fonts.afm = fonts.afm or { }
+afm.version = 1.410 -- incrementing this number one up will force a re-cache
+afm.cache = containers.define("fonts", "afm", afm.version, true)
+afm.autoprefixed = true -- this will become false some day (catches texnansi-blabla.*)
-local afm = fonts.afm
-local tfm = fonts.tfm
+afm.syncspace = true -- when true, nicer stretch values
+afm.addligatures = true -- best leave this set to true
+afm.addtexligatures = true -- best leave this set to true
+afm.addkerns = true -- best leave this set to true
--- so far
+local definers = fonts.definers
+local readers = fonts.readers
+local constructors = fonts.constructors
-afm.version = 1.403 -- incrementing this number one up will force a re-cache
-afm.syncspace = true -- when true, nicer stretch values
-afm.addligatures = true -- best leave this set to true
-afm.addtexligatures = true -- best leave this set to true
-afm.addkerns = true -- best leave this set to true
-afm.cache = containers.define("fonts", "afm", afm.version, true)
+local findbinfile = resolvers.findbinfile
-local definers = fonts.definers
-local readers = fonts.tfm.readers
+local afmfeatures = constructors.newfeatures("afm")
+local registerafmfeature = afmfeatures.register
-local afmfeatures = {
- aux = { },
- data = { },
- list = { },
- default = { },
-}
+local function setmode(tfmdata,value)
+ if value then
+ tfmdata.properties.mode = lower(value)
+ end
+end
-afm.features = afmfeatures
+registerafmfeature {
+ name = "mode",
+ description = "mode",
+ initializers = {
+ base = setmode,
+ node = setmode,
+ }
+}
--[[ldx--
<p>We start with the basic reader which we give a name similar to the
@@ -79,42 +89,46 @@ built in <l n='tfm'/> and <l n='otf'/> reader.</p>
--~ Comment DELIM 2390 1010
--~ Comment AXISHEIGHT 250
-local P, S, C = lpeg.P, lpeg.S, lpeg.C
-
-local c = P("Comment")
-local s = S(" \t")
-local l = S("\n\r")
-local w = C((1 - l)^1)
-local n = C((lpeg.R("09") + S("."))^1) / tonumber * s^0
-
-local fd = { }
-
-local pattern = ( c * s^1 * (
- ("CODINGSCHEME" * s^1 * w ) / function(a) end +
- ("DESIGNSIZE" * s^1 * n * w ) / function(a) fd[ 1] = a end +
- ("CHECKSUM" * s^1 * n * w ) / function(a) fd[ 2] = a end +
- ("SPACE" * s^1 * n * "plus" * n * "minus" * n) / function(a,b,c) fd[ 3], fd[ 4], fd[ 5] = a, b, c end +
- ("QUAD" * s^1 * n ) / function(a) fd[ 6] = a end +
- ("EXTRASPACE" * s^1 * n ) / function(a) fd[ 7] = a end +
- ("NUM" * s^1 * n * n * n ) / function(a,b,c) fd[ 8], fd[ 9], fd[10] = a, b, c end +
- ("DENOM" * s^1 * n * n ) / function(a,b ) fd[11], fd[12] = a, b end +
- ("SUP" * s^1 * n * n * n ) / function(a,b,c) fd[13], fd[14], fd[15] = a, b, c end +
- ("SUB" * s^1 * n * n ) / function(a,b) fd[16], fd[17] = a, b end +
- ("SUPDROP" * s^1 * n ) / function(a) fd[18] = a end +
- ("SUBDROP" * s^1 * n ) / function(a) fd[19] = a end +
- ("DELIM" * s^1 * n * n ) / function(a,b) fd[20], fd[21] = a, b end +
- ("AXISHEIGHT" * s^1 * n ) / function(a) fd[22] = a end +
- (1-l)^0
-) + (1-c)^1)^0
+local comment = P("Comment")
+local spacing = S(" \t")^1
+local lineend = S("\n\r")
+local words = C((1 - lineend)^1)
+local number = C((R("09") + S("."))^1) / tonumber * spacing^0
+local data = lpeg.Carg(1)
+
+local pattern = ( -- needs testing ... not used anyway as we no longer need math afm's
+ comment * spacing *
+ (
+ data * (
+ ("CODINGSCHEME" * spacing * words ) / function(fd,a) end +
+ ("DESIGNSIZE" * spacing * number * words ) / function(fd,a) fd[ 1] = a end +
+ ("CHECKSUM" * spacing * number * words ) / function(fd,a) fd[ 2] = a end +
+ ("SPACE" * spacing * number * "plus" * number * "minus" * number) / function(fd,a,b,c) fd[ 3], fd[ 4], fd[ 5] = a, b, c end +
+ ("QUAD" * spacing * number ) / function(fd,a) fd[ 6] = a end +
+ ("EXTRASPACE" * spacing * number ) / function(fd,a) fd[ 7] = a end +
+ ("NUM" * spacing * number * number * number ) / function(fd,a,b,c) fd[ 8], fd[ 9], fd[10] = a, b, c end +
+ ("DENOM" * spacing * number * number ) / function(fd,a,b ) fd[11], fd[12] = a, b end +
+ ("SUP" * spacing * number * number * number ) / function(fd,a,b,c) fd[13], fd[14], fd[15] = a, b, c end +
+ ("SUB" * spacing * number * number ) / function(fd,a,b) fd[16], fd[17] = a, b end +
+ ("SUPDROP" * spacing * number ) / function(fd,a) fd[18] = a end +
+ ("SUBDROP" * spacing * number ) / function(fd,a) fd[19] = a end +
+ ("DELIM" * spacing * number * number ) / function(fd,a,b) fd[20], fd[21] = a, b end +
+ ("AXISHEIGHT" * spacing * number ) / function(fd,a) fd[22] = a end
+ )
+ + (1-lineend)^0
+ )
+ + (1-comment)^1
+)^0
local function scan_comment(str)
- fd = { }
- lpegmatch(pattern,str)
+ local fd = { }
+ lpegmatch(pattern,str,1,fd)
return fd
end
-- On a rainy day I will rewrite this in lpeg ... or we can use the (slower) fontloader
--- as in now supports afm/pfb loading.
+-- as in now supports afm/pfb loading but it's not too bad to have different methods
+-- for testing approaches.
local keys = { }
@@ -136,35 +150,35 @@ end
local function get_charmetrics(data,charmetrics,vector)
local characters = data.characters
- local chr, str, ind = { }, "", 0
+ local chr, ind = { }, 0
for k,v in gmatch(charmetrics,"([%a]+) +(.-) *;") do
if k == 'C' then
- if str ~= "" then characters[str] = chr end
- chr = { }
- str = ""
v = tonumber(v)
if v < 0 then
- ind = ind + 1
+ ind = ind + 1 -- ?
else
ind = v
end
- chr.index = ind
+ chr = {
+ index = ind
+ }
elseif k == 'WX' then
- chr.width = v
+ chr.width = tonumber(v)
elseif k == 'N' then
- str = v
+ characters[v] = chr
elseif k == 'B' then
local llx, lly, urx, ury = match(v,"^ *(.-) +(.-) +(.-) +(.-)$")
chr.boundingbox = { tonumber(llx), tonumber(lly), tonumber(urx), tonumber(ury) }
elseif k == 'L' then
local plus, becomes = match(v,"^(.-) +(.-)$")
- if not chr.ligatures then chr.ligatures = { } end
- chr.ligatures[plus] = becomes
+ local ligatures = chr.ligatures
+ if ligatures then
+ ligatures[plus] = becomes
+ else
+ chr.ligatures = { [plus] = becomes }
+ end
end
end
- if str ~= "" then
- characters[str] = chr
- end
end
local function get_kernpairs(data,kernpairs)
@@ -172,32 +186,37 @@ local function get_kernpairs(data,kernpairs)
for one, two, value in gmatch(kernpairs,"KPX +(.-) +(.-) +(.-)\n") do
local chr = characters[one]
if chr then
- if not chr.kerns then chr.kerns = { } end
- chr.kerns[two] = tonumber(value)
+ local kerns = chr.kerns
+ if kerns then
+ kerns[two] = tonumber(value)
+ else
+ chr.kerns = { [two] = tonumber(value) }
+ end
end
end
end
local function get_variables(data,fontmetrics)
for key, rest in gmatch(fontmetrics,"(%a+) *(.-)[\n\r]") do
- if keys[key] then keys[key](data,rest) end
+ local keyhandler = keys[key]
+ if keyhandler then
+ keyhandler(data,rest)
+ end
end
end
local function get_indexes(data,pfbname)
- data.luatex.filename = resolvers.unresolve(pfbname) -- no shortcut
+ data.resources.filename = resolvers.unresolve(pfbname) -- no shortcut
local pfbblob = fontloader.open(pfbname)
if pfbblob then
local characters = data.characters
local pfbdata = fontloader.to_table(pfbblob)
- --~ print(table.serialize(pfbdata))
if pfbdata then
local glyphs = pfbdata.glyphs
if glyphs then
if trace_loading then
report_afm("getting index data from %s",pfbname)
end
- -- local offset = (glyphs[0] and glyphs[0] != .notdef) or 0
for index, glyph in next, glyphs do
local name = glyph.name
if name then
@@ -224,14 +243,27 @@ end
local function readafm(filename)
local ok, afmblob, size = resolvers.loadbinfile(filename) -- has logging
--- local ok, afmblob = true, file.readdata(filename)
if ok and afmblob then
local data = {
- characters = { },
- metadata = {
- version = version or '0', -- hm
+ resources = {
+ filename = resolvers.unresolve(filename),
+ version = afm.version,
+ creator = "context mkiv",
+ },
+ properties = {
+ italic_correction = false,
+ },
+ goodies = {
+ },
+ metadata = {
filename = file.removesuffix(file.basename(filename))
- }
+ },
+ characters = {
+ -- a temporary store
+ },
+ descriptions = {
+ -- the final store
+ },
}
afmblob = gsub(afmblob,"StartCharMetrics(.-)EndCharMetrics", function(charmetrics)
if trace_loading then
@@ -256,7 +288,6 @@ local function readafm(filename)
data.fontdimens = scan_comment(fontmetrics) -- todo: all lpeg, no time now
return ""
end)
- data.luatex = { }
return data
else
if trace_loading then
@@ -272,7 +303,7 @@ by adding ligatures and kern information to the afm derived data. That
way we can set them faster when defining a font.</p>
--ldx]]--
-local addkerns, addligatures, addtexligatures, unify -- we will implement these later
+local addkerns, addligatures, addtexligatures, unify, normalize -- we will implement these later
function afm.load(filename)
-- hm, for some reasons not resolved yet
@@ -291,14 +322,13 @@ function afm.load(filename)
local pfbsize, pfbtime = 0, 0
if pfbname ~= "" then
local attr = lfs.attributes(pfbname)
- pfbsize, pfbtime = attr.size or 0, attr.modification or 0
+ pfbsize = attr.size or 0
+ pfbtime = attr.modification or 0
end
- if not data or data.verbose ~= fonts.verbose
- or data.size ~= size or data.time ~= time or data.pfbsize ~= pfbsize or data.pfbtime ~= pfbtime then
+ if not data or data.size ~= size or data.time ~= time or data.pfbsize ~= pfbsize or data.pfbtime ~= pfbtime then
report_afm( "reading %s",filename)
data = readafm(filename)
if data then
- -- data.luatex = data.luatex or { }
if pfbname ~= "" then
get_indexes(data,pfbname)
elseif trace_loading then
@@ -318,13 +348,13 @@ function afm.load(filename)
report_afm( "add extra kerns")
addkerns(data)
end
+ normalize(data)
report_afm( "add tounicode data")
- fonts.map.addtounicode(data,filename)
+ fonts.mappings.addtounicode(data,filename)
data.size = size
data.time = time
data.pfbsize = pfbsize
data.pfbtime = pfbtime
- data.verbose = fonts.verbose
report_afm("saving: %s in cache",name)
data = containers.write(afm.cache, name, data)
data = containers.read(afm.cache,name)
@@ -336,17 +366,16 @@ function afm.load(filename)
end
end
-local uparser = fonts.map.makenameparser()
+local uparser = fonts.mappings.makenameparser()
unify = function(data, filename)
- local unicodevector = fonts.enc.agl.unicodes -- loaded runtime in context
- local glyphs, indices, unicodes, names = { }, { }, { }, { }
- local verbose, private = fonts.verbose, fonts.privateoffset
+ local unicodevector = fonts.encodings.agl.unicodes -- loaded runtime in context
+ local unicodes, names = { }, { }
+ local private = constructors.privateoffset
+ local descriptions = data.descriptions
for name, blob in next, data.characters do
local code = unicodevector[name] -- or characters.name_to_unicode[name]
if not code then
- -- local u = match(name,"^uni(%x+)$")
- -- code = u and tonumber(u,16)
code = lpegmatch(uparser,name)
if not code then
code = private
@@ -356,33 +385,42 @@ unify = function(data, filename)
end
local index = blob.index
unicodes[name] = code
- indices[code] = index
- glyphs[index] = blob
names[name] = index
blob.name = name
- if verbose then
- local bu = blob.unicode
- if not bu then
- blob.unicode = code
- elseif type(bu) == "table" then
- bu[#bu+1] = code
- else
- blob.unicode = { bu, code }
+ descriptions[code] = {
+ boundingbox = blob.boundingbox,
+ width = blob.width,
+ kerns = blob.kerns,
+ index = index,
+ name = name,
+ }
+ end
+ for unicode, description in next, descriptions do
+ local kerns = description.kerns
+ if kerns then
+ local krn = { }
+ for name, kern in next, kerns do
+ local unicode = unicodes[name]
+ if unicode then
+ krn[unicode] = kern
+ else
+ print(unicode,name)
+ end
end
- else
- blob.index = nil
+ description.kerns = krn
end
end
- data.glyphs = glyphs
data.characters = nil
- local luatex = data.luatex
- local filename = luatex.filename or file.removesuffix(file.basename(filename))
- luatex.filename = resolvers.unresolve(filename) -- no shortcut
- luatex.unicodes = unicodes -- name to unicode
- luatex.indices = indices -- unicode to index
- luatex.marks = { } -- todo
- luatex.names = names -- name to index
- luatex.private = private
+ local resources = data.resources
+ local filename = resources.filename or file.removesuffix(file.basename(filename))
+ resources.filename = resolvers.unresolve(filename) -- no shortcut
+ resources.unicodes = unicodes -- name to unicode
+ resources.marks = { } -- todo
+ resources.names = names -- name to index
+ resources.private = private
+end
+
+normalize = function(data)
end
--[[ldx--
@@ -397,8 +435,8 @@ is that a character can be in an encoding twice but is hashed
once.</p>
--ldx]]--
-local ligatures = { -- okay, nowadays we could parse the name
- ['f'] = {
+local ligatures = { -- okay, nowadays we could parse the name but type 1 fonts
+ ['f'] = { -- don't have that many ligatures anyway
{ 'f', 'ff' },
{ 'i', 'fi' },
{ 'l', 'fl' },
@@ -445,18 +483,20 @@ local texligatures = {
}
}
-local addthem = function(afmdata,ligatures)
- local glyphs, luatex = afmdata.glyphs, afmdata.luatex
- local indices, unicodes, names = luatex.indices, luatex.unicodes, luatex.names
+local addthem = function(rawdata,ligatures)
+ local descriptions = rawdata.descriptions
+ local resources = rawdata.resources
+ local unicodes = resources.unicodes
+ local names = resources.names
for ligname, ligdata in next, ligatures do
- local one = glyphs[names[ligname]]
+ local one = descriptions[unicodes[ligname]]
if one then
for _, pair in next, ligdata do
- local two, three = pair[1], pair[2]
- if two and three and names[two] and names[three] then
+ local two, three = unicodes[pair[1]], unicodes[pair[2]]
+ if two and three then
local ol = one.ligatures
if ol then
- if not ol[two] then -- was one.ligatures ... bug
+ if not ol[two] then
ol[two] = three
end
else
@@ -468,8 +508,8 @@ local addthem = function(afmdata,ligatures)
end
end
-addligatures = function(afmdata) addthem(afmdata,ligatures ) end
-addtexligatures = function(afmdata) addthem(afmdata,texligatures) end
+addligatures = function(rawdata) addthem(rawdata,ligatures ) end
+addtexligatures = function(rawdata) addthem(rawdata,texligatures) end
--[[ldx--
<p>We keep the extra kerns in separate kerning tables so that we can use
@@ -479,7 +519,11 @@ them selectively.</p>
-- This is rather old code (from the beginning when we had only tfm). If
-- we unify the afm data (now we have names all over the place) then
-- we can use shcodes but there will be many more looping then. But we
--- could get rid of the tables in char-cmp then.
+-- could get rid of the tables in char-cmp then. Als, in the generic version
+-- we don't use the character database. (Ok, we can have a context specific
+-- variant).
+
+-- we can make them numbers
local left = {
AEligature = "A", aeligature = "a",
@@ -620,44 +664,67 @@ local both = {
}
-addkerns = function(afmdata) -- using shcodes is not robust here
- local glyphs = afmdata.glyphs
- local names = afmdata.luatex.names
+addkerns = function(rawdata) -- using shcodes is not robust here
+ local descriptions = rawdata.descriptions
+ local resources = rawdata.resources
+ local unicodes = resources.unicodes
local function do_it_left(what)
- for index, glyph in next, glyphs do
- local kerns = glyph.kerns
+ for unicode, description in next, descriptions do
+ local kerns = description.kerns
if kerns then
- local extrakerns = glyph.extrakerns or { }
+ local extrakerns
for complex, simple in next, what do
- if names[complex] then
+ complex = unicodes[complex]
+ simple = unicodes[simple]
+ if complex and simple then
local ks = kerns[simple]
if ks and not kerns[complex] then
- extrakerns[complex] = ks
+ if extrakerns then
+ extrakerns[complex] = ks
+ else
+ extrakerns = { [complex] = ks }
+ end
end
end
end
- if next(extrakerns) then
- glyph.extrakerns = extrakerns
+ if extrakerns then
+ description.extrakerns = extrakerns
end
end
end
end
local function do_it_copy(what)
for complex, simple in next, what do
- local c = glyphs[names[complex]]
- if c then -- optional
- local s = glyphs[names[simple]]
- if s then
- if not c.kerns then
- c.extrakerns = s.kerns or { }
- end
- if s.extrakerns then
- local extrakerns = c.extrakerns or { }
- for k, v in next, s.extrakerns do
- extrakerns[k] = v
+ complex = unicodes[complex]
+ simple = unicodes[simple]
+ if complex and simple then
+ local complexdescription = descriptions[complex]
+ if complexdescription then -- optional
+ local simpledescription = descriptions[complex]
+ if simpledescription then
+ local extrakerns
+ local kerns = simpledescription.kerns
+ if kerns then
+ for unicode, kern in next, kerns do
+ if extrakerns then
+ extrakerns[unicode] = kern
+ else
+ extrakerns = { [unicode] = kern }
+ end
+ end
end
- if next(extrakerns) then
- s.extrakerns = extrakerns
+ local extrakerns = simpledescription.extrakerns
+ if extrakerns then
+ for unicode, kern in next, extrakerns do
+ if extrakerns then
+ extrakerns[unicode] = kern
+ else
+ extrakerns = { [unicode] = kern }
+ end
+ end
+ end
+ if extrakerns then
+ complexdescription.extrakerns = extrakerns
end
end
end
@@ -676,24 +743,21 @@ end
<p>The copying routine looks messy (and is indeed a bit messy).</p>
--ldx]]--
--- once we have otf sorted out (new format) we can try to make the afm
--- cache similar to it (similar tables)
-
local function adddimensions(data) -- we need to normalize afm to otf i.e. indexed table instead of name
if data then
- for index, glyph in next, data.glyphs do
- local bb = glyph.boundingbox
+ for unicode, description in next, data.descriptions do
+ local bb = description.boundingbox
if bb then
local ht, dp = bb[4], -bb[2]
if ht == 0 or ht < 0 then
-- no need to set it and no negative heights, nil == 0
else
- glyph.height = ht
+ description.height = ht
end
if dp == 0 or dp < 0 then
-- no negative depths and no negative depths, nil == 0
else
- glyph.depth = dp
+ description.depth = dp
end
end
end
@@ -701,115 +765,124 @@ local function adddimensions(data) -- we need to normalize afm to otf i.e. index
end
local function copytotfm(data)
- if data then
- local glyphs = data.glyphs
- if glyphs then
- local metadata, luatex = data.metadata, data.luatex
- local unicodes, indices = luatex.unicodes, luatex.indices
- local characters, parameters, descriptions = { }, { }, { }
- local mode = data.mode or "base"
- -- todo : merge into tfm
- for u, i in next, indices do
- local d = glyphs[i]
- characters[u] = { }
- descriptions[u] = d
+ if data and data.descriptions then
+ local metadata = data.metadata
+ local resources = data.resources
+ local properties = table.derive(data.properties)
+ local descriptions = table.derive(data.descriptions)
+ local goodies = table.derive(data.goodies)
+ local characters = { }
+ local parameters = { }
+ local unicodes = resources.unicodes
+ --
+ for unicode, description in next, data.descriptions do -- use parent table
+ characters[unicode] = { }
+ end
+ --
+ local filename = constructors.checkedfilename(resources)
+ local fontname = metadata.fontname or metadata.fullname
+ local fullname = metadata.fullname or metadata.fontname
+ local endash = unicodes['space']
+ local emdash = unicodes['emdash']
+ local spacer = "space"
+ local spaceunits = 500
+ --
+ local monospaced = metadata.isfixedpitch
+ local charwidth = metadata.charwidth
+ local italicangle = metadata.italicangle
+ local charxheight = metadata.xheight and metadata.xheight > 0 and metadata.xheight
+ properties.monospaced = monospaced
+ parameters.italicangle = italicangle
+ parameters.charwidth = charwidth
+ parameters.charxheight = charxheight
+ -- same as otf
+ if properties.monospaced then
+ if descriptions[endash] then
+ spaceunits, spacer = descriptions[endash].width, "space"
end
- local filename = fonts.tfm.checkedfilename(luatex) -- was metadata.filename
- local fontname = metadata.fontname or metadata.fullname
- local fullname = metadata.fullname or metadata.fontname
- local endash, emdash, spacer, spaceunits = unicodes['space'], unicodes['emdash'], "space", 500
- -- same as otf
- if metadata.isfixedpitch 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 metadata.charwidth then
- spaceunits, spacer = metadata.charwidth, "charwidth"
- end
- else
- if descriptions[endash] then
- spaceunits, spacer = descriptions[endash].width, "space"
- end
- if not spaceunits and metadata.charwidth then
- spaceunits, spacer = metadata.charwidth, "charwidth"
- end
+ if not spaceunits and descriptions[emdash] then
+ spaceunits, spacer = descriptions[emdash].width, "emdash"
end
- spaceunits = tonumber(spaceunits)
- if spaceunits < 200 then
- -- todo: warning
+ if not spaceunits and charwidth then
+ spaceunits, spacer = charwidth, "charwidth"
end
- --
- parameters.slant = 0
- parameters.space = spaceunits
- parameters.space_stretch = 500
- parameters.space_shrink = 333
- parameters.x_height = 400
- parameters.quad = 1000
- local italicangle = data.metadata.italicangle
- if italicangle then
- parameters.slant = parameters.slant - math.round(math.tan(italicangle*math.pi/180))
+ else
+ if descriptions[endash] then
+ spaceunits, spacer = descriptions[endash].width, "space"
end
- if metadata.isfixedpitch then
- parameters.space_stretch = 0
- parameters.space_shrink = 0
- elseif afm.syncspace then
- parameters.space_stretch = spaceunits/2
- parameters.space_shrink = spaceunits/3
+ if not spaceunits and charwidth then
+ spaceunits, spacer = charwidth, "charwidth"
end
- parameters.extra_space = parameters.space_shrink
- if metadata.xheight and metadata.xheight > 0 then
- parameters.x_height = metadata.xheight
- else
- -- same as otf
- local x = unicodes['x']
+ end
+ spaceunits = tonumber(spaceunits)
+ if spaceunits < 200 then
+ -- todo: warning
+ end
+ --
+ parameters.slant = 0
+ parameters.space = spaceunits
+ parameters.space_stretch = 500
+ parameters.space_shrink = 333
+ parameters.x_height = 400
+ parameters.quad = 1000
+ --
+ if italicangle then
+ parameters.italicangle = italicangle
+ parameters.italicfactor = math.cos(math.rad(90+italicangle))
+ parameters.slant = - math.round(math.tan(italicangle*math.pi/180))
+ end
+ if monospaced then
+ parameters.space_stretch = 0
+ parameters.space_shrink = 0
+ elseif afm.syncspace then
+ parameters.space_stretch = spaceunits/2
+ parameters.space_shrink = spaceunits/3
+ end
+ parameters.extra_space = parameters.space_shrink
+ if charxheight then
+ parameters.x_height = charxheight
+ else
+ -- same as otf
+ local x = unicodes['x']
+ if x then
+ local x = descriptions[x]
if x then
- local x = descriptions[x]
- if x then
- parameters.x_height = x.height
- end
- end
- --
- end
- local fd = data.fontdimens
- if fd and fd[8] and fd[9] and fd[10] then -- math
- for k,v in next, fd do
- parameters[k] = v
+ parameters.x_height = x.height
end
end
--
- if next(characters) then
- return {
- characters = characters,
- parameters = parameters,
- descriptions = descriptions,
- indices = indices,
- unicodes = unicodes,
- luatex = luatex,
- encodingbytes = 2,
- mode = mode,
- filename = filename,
- fontname = fontname,
- fullname = fullname,
- psname = fullname, -- in otf: tfm.fontname or tfm.fullname
- name = filename or fullname or fontname,
- format = fonts.fontformat(filename,"type1"),
- type = 'real',
- units = 1000,
- direction = 0,
- boundarychar_label = 0,
- boundarychar = 65536,
- --~ false_boundarychar = 65536, -- produces invalid tfm in luatex
- designsize = (metadata.designsize or 10)*65536,
- spacer = spacer,
- ascender = abs(metadata.ascender or 0),
- descender = abs(metadata.descender or 0),
- italicangle = italicangle,
- }
+ end
+ local fd = data.fontdimens
+ if fd and fd[8] and fd[9] and fd[10] then -- math
+ for k,v in next, fd do
+ parameters[k] = v
end
end
+ --
+ parameters.designsize = (metadata.designsize or 10)*65536
+ parameters.ascender = abs(metadata.ascender or 0)
+ parameters.descender = abs(metadata.descender or 0)
+ parameters.units = 1000
+ --
+ properties.spacer = spacer
+ properties.encodingbytes = 2
+ properties.format = fonts.formats[filename] or "type1"
+ properties.filename = filename
+ properties.fontname = fontname
+ properties.fullname = fullname
+ properties.psname = fullname
+ properties.name = filename or fullname or fontname
+ --
+ if next(characters) then
+ return {
+ characters = characters,
+ descriptions = descriptions,
+ parameters = parameters,
+ resources = resources,
+ properties = properties,
+ goodies = goodies,
+ }
+ end
end
return nil
end
@@ -821,79 +894,16 @@ to treat this fontformat like any other and handle features in a
more configurable way.</p>
--ldx]]--
-local function register_feature(name,default)
- afmfeatures.list[#afmfeatures.list+1] = name
- afmfeatures.default[name] = default
-end
-
-afmfeatures.register = register_feature
-
-local function setfeatures(tfmdata)
- local shared = tfmdata.shared
- local afmdata = shared.afmdata
- local features = shared.features
- if features and next(features) then
- local mode = tfmdata.mode or features.mode or "base"
- local initializers = fonts.initializers
- local fi = initializers[mode]
- local fiafm = fi and fi.afm
- if fiafm then
- local lists = {
- fonts.triggers,
- afmfeatures.list,
- fonts.manipulators,
- }
- for l=1,3 do
- local list = lists[l]
- if list then
- for i=1,#list do
- local f = list[i]
- local value = features[f]
- if value and fiafm[f] then -- brr
- if trace_features then
- report_afm("initializing feature %s to %s for mode %s for font %s",f,tostring(value),mode or 'unknown',tfmdata.name or 'unknown')
- end
- fiafm[f](tfmdata,value)
- mode = tfmdata.mode or features.mode or "base"
- fiafm = initializers[mode].afm
- end
- end
- end
- end
- end
- local fm = fonts.methods[mode]
- local fmafm = fm and fm.afm
- if fmafm then
- local lists = {
- afmfeatures.list,
- }
- local sp = shared.processors
- for l=1,1 do
- local list = lists[l]
- if list then
- for i=1,#list do
- local f = list[i]
- if features[f] and fmafm[f] then -- brr
- if not sp then
- sp = { fmafm[f] }
- shared.processors = sp
- else
- sp[#sp+1] = fmafm[f]
- end
- end
- end
- end
- end
- end
+function afm.setfeatures(tfmdata,features)
+ local okay = constructors.initializefeatures("afm",tfmdata,features,trace_features,report_afm)
+ if okay then
+ return constructors.collectprocessors("afm",tfmdata,features,trace_features,report_afm)
+ else
+ return { } -- will become false
end
end
local function checkfeatures(specification)
- local features, done = definers.check(specification.features.normal,afmfeatures.default)
- if done then
- specification.features.normal = features
- tfm.hashinstance(specification,true)
- end
end
local function afmtotfm(specification)
@@ -908,34 +918,37 @@ local function afmtotfm(specification)
if trace_loading then
report_afm("fallback from afm to tfm for %s",afmname)
end
- afmname = ""
+ return -- just that
end
end
- if afmname == "" then
- return nil
- else
- checkfeatures(specification)
+ if afmname ~= "" then
+ -- weird, isn't this already done then?
+ local features = constructors.checkedfeatures("afm",specification.features.normal)
+ specification.features.normal = features
+ constructors.hashinstance(specification,true) -- also weird here
+ --
specification = definers.resolve(specification) -- new, was forgotten
- local features = specification.features.normal
local cache_id = specification.hash
- local tfmdata = containers.read(tfm.cache, cache_id) -- cache with features applied
+ local tfmdata = containers.read(constructors.cache, cache_id) -- cache with features applied
if not tfmdata then
- local afmdata = afm.load(afmname)
- if afmdata and next(afmdata) then
- adddimensions(afmdata)
- tfmdata = copytotfm(afmdata)
+ local rawdata = afm.load(afmname)
+ if rawdata and next(rawdata) then
+ adddimensions(rawdata)
+ tfmdata = copytotfm(rawdata)
if tfmdata and next(tfmdata) then
local shared = tfmdata.shared
- local unique = tfmdata.unique
- if not shared then shared = { } tfmdata.shared = shared end
- if not unique then unique = { } tfmdata.unique = unique end
- shared.afmdata, shared.features = afmdata, features
- setfeatures(tfmdata)
+ if not shared then
+ shared = { }
+ tfmdata.shared = shared
+ end
+ shared.rawdata = rawdata
+ shared.features = features
+ shared.processes = afm.setfeatures(tfmdata,features)
end
elseif trace_loading then
report_afm("no (valid) afm file found with name %s",afmname)
end
- tfmdata = containers.write(tfm.cache,cache_id,tfmdata)
+ tfmdata = containers.write(constructors.cache,cache_id,tfmdata)
end
return tfmdata
end
@@ -949,33 +962,15 @@ those cases, but now that we can handle <l n='opentype'/> directly we no longer
need this features.</p>
--ldx]]--
--- tfm.default_encoding = 'unicode'
---
--- function tfm.setnormalfeature(specification,name,value)
--- if specification and name then
--- local features = specification.features
--- if not features then
--- features = { }
--- specification.features = features
--- end
--- local normalfeatures = features.normal
--- if normalfeatures then
--- normalfeatures[name] = value
--- else
--- features.normal = { [name] = value }
--- end
--- end
--- end
-
local function read_from_afm(specification)
- local tfmtable = afmtotfm(specification)
- if tfmtable then
- tfmtable.name = specification.name
- tfmtable = tfm.scale(tfmtable, specification.size, specification.relativeid)
- local afmdata = tfmtable.shared.afmdata
- fonts.logger.save(tfmtable,'afm',specification)
+ local tfmdata = afmtotfm(specification)
+ if tfmdata then
+ tfmdata.properties.name = specification.name
+ tfmdata = constructors.scale(tfmdata, specification)
+ constructors.applymanipulators("afm",tfmdata,specification.features.normal,trace_features,report_afm)
+ fonts.loggers.register(tfmdata,'afm',specification)
end
- return tfmtable
+ return tfmdata
end
--[[ldx--
@@ -983,40 +978,34 @@ end
those that make sense for this format.</p>
--ldx]]--
-local function prepare_ligatures(tfmdata,ligatures,value)
+local function prepareligatures(tfmdata,ligatures,value)
if value then
- local afmdata = tfmdata.shared.afmdata
- local luatex = afmdata.luatex
- local unicodes = luatex.unicodes
local descriptions = tfmdata.descriptions
- for u, chr in next, tfmdata.characters do
- local d = descriptions[u]
- local l = d[ligatures]
- if l then
- local ligatures = chr.ligatures
- if not ligatures then
- ligatures = { }
- chr.ligatures = ligatures
+ for unicode, character in next, tfmdata.characters do
+ local description = descriptions[unicode]
+ local dligatures = description.ligatures
+ if dligatures then
+ local cligatures = character.ligatures
+ if not cligatures then
+ cligatures = { }
+ character.ligatures = cligatures
end
- for k, v in next, l do
- local uk, uv = unicodes[k], unicodes[v]
- if uk and uv then
- ligatures[uk] = {
- char = uv,
- type = 0
- }
- end
+ for unicode, ligature in next, dligatures do
+ cligatures[unicode] = {
+ char = ligature,
+ type = 0
+ }
end
end
end
end
end
-local function prepare_kerns(tfmdata,kerns,value)
+local function preparekerns(tfmdata,kerns,value)
if value then
- local afmdata = tfmdata.shared.afmdata
- local luatex = afmdata.luatex
- local unicodes = luatex.unicodes
+ local rawdata = tfmdata.shared.rawdata
+ local resources = rawdata.resources
+ local unicodes = resources.unicodes
local descriptions = tfmdata.descriptions
for u, chr in next, tfmdata.characters do
local d = descriptions[u]
@@ -1038,66 +1027,70 @@ local function prepare_kerns(tfmdata,kerns,value)
end
end
--- hm, register?
-
-local base_initializers = fonts.initializers.base.afm
-local node_initializers = fonts.initializers.node.afm
-local common_initializers = fonts.initializers.common
-
-local function ligatures (tfmdata,value) prepare_ligatures(tfmdata,'ligatures', value) end
-local function texligatures(tfmdata,value) prepare_ligatures(tfmdata,'texligatures',value) end
-local function kerns (tfmdata,value) prepare_kerns (tfmdata,'kerns', value) end
-local function extrakerns (tfmdata,value) prepare_kerns (tfmdata,'extrakerns', value) end
-
-register_feature('liga') -- was true
-register_feature('kern') -- was true
-register_feature('extrakerns') -- needed?
-
-base_initializers.ligatures = ligatures
-node_initializers.ligatures = ligatures
-base_initializers.texligatures = texligatures
-node_initializers.texligatures = texligatures
-base_initializers.kern = kerns
-node_initializers.kerns = kerns
-node_initializers.extrakerns = extrakerns
-base_initializers.extrakerns = extrakerns
-
-base_initializers.liga = ligatures
-node_initializers.liga = ligatures
-base_initializers.tlig = texligatures
-node_initializers.tlig = texligatures
-base_initializers.trep = tfm.replacements
-node_initializers.trep = tfm.replacements
-
-register_feature('tlig') -- was true -- todo: also proper features for afm
-register_feature('trep') -- was true -- todo: also proper features for afm
-
--- tfm features
-
-base_initializers.equaldigits = common_initializers.equaldigits
-node_initializers.equaldigits = common_initializers.equaldigits
-base_initializers.lineheight = common_initializers.lineheight
-node_initializers.lineheight = common_initializers.lineheight
-
--- vf features
-
-base_initializers.compose = common_initializers.compose
-node_initializers.compose = common_initializers.compose
-
--- afm specific, obsolete
---
--- register_feature('encoding')
---
--- base_initializers.encoding = common_initializers.encoding
--- node_initializers.encoding = common_initializers.encoding
---
--- base_initializers.onum = common_initializers.oldstyle
--- base_initializers.smcp = common_initializers.smallcaps
--- base_initializers.fkcp = common_initializers.fakecaps
---
--- register_feature('onum',false)
--- register_feature('smcp',false)
--- register_feature('fkcp',false)
+local list = {
+ -- [0x0022] = 0x201D,
+ [0x0027] = 0x2019,
+ -- [0x0060] = 0x2018,
+}
+
+local function texreplacements(tfmdata,value)
+ local descriptions = tfmdata.descriptions
+ local characters = tfmdata.characters
+ for k, v in next, list do
+ characters [k] = characters [v] -- we forget about kerns
+ descriptions[k] = descriptions[v] -- we forget about kerns
+ end
+end
+
+local function ligatures (tfmdata,value) prepareligatures(tfmdata,'ligatures', value) end
+local function texligatures(tfmdata,value) prepareligatures(tfmdata,'texligatures',value) end
+local function kerns (tfmdata,value) preparekerns (tfmdata,'kerns', value) end
+local function extrakerns (tfmdata,value) preparekerns (tfmdata,'extrakerns', value) end
+
+registerafmfeature {
+ name = "liga",
+ description = "traditional ligatures",
+ initializers = {
+ base = ligatures,
+ node = ligatures,
+ }
+}
+
+registerafmfeature {
+ name = "kern",
+ description = "intercharacter kerning",
+ initializers = {
+ base = kerns,
+ node = kerns,
+ }
+}
+
+registerafmfeature {
+ name = "extrakerns",
+ description = "additional intercharacter kerning",
+ initializers = {
+ base = extrakerns,
+ node = extrakerns,
+ }
+}
+
+registerafmfeature {
+ name = 'tlig',
+ description = 'tex ligatures',
+ initializers = {
+ base = texligatures,
+ node = texligatures,
+ }
+}
+
+registerafmfeature {
+ name = 'trep',
+ description = 'tex replacements',
+ initializers = {
+ base = texreplacements,
+ node = texreplacements,
+ }
+}
-- readers
@@ -1111,9 +1104,9 @@ local function check_afm(specification,fullname)
if foundname == "" then
foundname = fonts.names.getfilename(fullname,"afm")
end
- if foundname == "" and tfm.autoprefixedafm then
+ if foundname == "" and afm.autoprefixed then
local encoding, shortname = match(fullname,"^(.-)%-(.*)$") -- context: encoding-name.*
- if encoding and shortname and fonts.enc.known[encoding] then
+ if encoding and shortname and fonts.encodings.known[encoding] then
shortname = findbinfile(shortname,'afm') or "" -- just to be sure
if shortname ~= "" then
foundname = shortname
@@ -1124,34 +1117,35 @@ local function check_afm(specification,fullname)
end
end
if foundname ~= "" then
- specification.filename, specification.format = foundname, "afm"
+ specification.filename = foundname
+ specification.format = "afm"
return read_from_afm(specification)
end
end
function readers.afm(specification,method)
- local fullname, tfmtable = specification.filename or "", nil
+ local fullname, tfmdata = specification.filename or "", nil
if fullname == "" then
local forced = specification.forced or ""
if forced ~= "" then
- tfmtable = check_afm(specification,specification.name .. "." .. forced)
+ tfmdata = check_afm(specification,specification.name .. "." .. forced)
end
- if not tfmtable then
+ if not tfmdata then
method = method or definers.method or "afm or tfm"
if method == "tfm" then
- tfmtable = check_tfm(specification,specification.name)
+ tfmdata = check_tfm(specification,specification.name)
elseif method == "afm" then
- tfmtable = check_afm(specification,specification.name)
+ tfmdata = check_afm(specification,specification.name)
elseif method == "tfm or afm" then
- tfmtable = check_tfm(specification,specification.name) or check_afm(specification,specification.name)
+ tfmdata = check_tfm(specification,specification.name) or check_afm(specification,specification.name)
else -- method == "afm or tfm" or method == "" then
- tfmtable = check_afm(specification,specification.name) or check_tfm(specification,specification.name)
+ tfmdata = check_afm(specification,specification.name) or check_tfm(specification,specification.name)
end
end
else
- tfmtable = check_afm(specification,fullname)
+ tfmdata = check_afm(specification,fullname)
end
- return tfmtable
+ return tfmdata
end
function readers.pfb(specification,method) -- only called when forced
diff --git a/tex/context/base/font-age.lua b/tex/context/base/font-age.lua
index 5c19d41b1..741bb475a 100644
--- a/tex/context/base/font-age.lua
+++ b/tex/context/base/font-age.lua
@@ -1,16 +1,17 @@
-if not modules then modules = { } end modules ['font-map'] = {
+if not modules then modules = { } end modules ['font-age'] = {
version = 1.001,
- comment = "companion to font-ini.mkiv",
+ comment = "companion to font-gee.lua",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "derived from http://www.adobe.com/devnet/opentype/archives/glyphlist.txt",
original = "Adobe Glyph List, version 2.0, September 20, 2002",
}
-fonts = fonts or { }
-fonts.enc = fonts.enc or { }
-fonts.enc.agl = fonts.enc.agl or { }
+if context then
+ texio.write_nl("fatal error: this module is not for context")
+ os.exit()
+end
-fonts.enc.agl.unicodes = { -- generated
+return { -- generated
["A"]=65,
["AE"]=198,
["AEacute"]=508,
diff --git a/tex/context/base/font-agl.lua b/tex/context/base/font-agl.lua
index 45aae9507..a81d3503c 100644
--- a/tex/context/base/font-agl.lua
+++ b/tex/context/base/font-agl.lua
@@ -274,9 +274,9 @@ end
-- We load this table only when needed. We coul duse a loading mechanism
-- return the table but there are no more vectors like this so why bother.
-fonts.enc = fonts.enc or { }
+fonts.encodings = fonts.encodings or { }
-fonts.enc.agl = {
+fonts.encodings.agl = {
names = names, -- unicode -> name
unicodes = unicodes, -- name -> unicode
extras = extras, -- merged into the other two
diff --git a/tex/context/base/font-aux.lua b/tex/context/base/font-aux.lua
new file mode 100644
index 000000000..a3e717b44
--- /dev/null
+++ b/tex/context/base/font-aux.lua
@@ -0,0 +1,105 @@
+if not modules then modules = { } end modules ['font-aux'] = {
+ 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 number = tonumber
+local wrap, yield = coroutine.wrap, coroutine.yield
+
+local fonts, font = fonts, font
+
+local iterators = { }
+fonts.interators = iterators
+
+local currentfont = font.current
+local identifiers = fonts.hashes.identifiers
+local sortedkeys = table.sortedkeys
+
+-- for unicode, character in fonts.iterators.characters () do print(k,v) end
+-- for unicode, description in fonts.iterators.descriptions() do print(k,v) end
+-- for index, glyph in fonts.iterators.glyphs () do print(k,v) end
+
+
+local function checkeddata(data) -- beware, nullfont is the fallback in identifiers
+ local t = type(data)
+ if t == "table" then
+ return data
+ elseif t ~= "number" then
+ data = currentfont()
+ end
+ return identifiers[data] -- has nullfont as fallback
+end
+
+function iterators.characters(data)
+ data = checkeddata(data)
+ local characters = data.characters
+ if characters then
+ local collected = sortedkeys(characters)
+ return wrap(function()
+ for c=1,#collected do
+ local cc = collected[c]
+ local dc = characters[cc]
+ if dc then
+ yield(cc,dc)
+ end
+ end
+ end)
+ else
+ return wrap(function() end)
+ end
+end
+
+function iterators.descriptions(data)
+ data = checkeddata(data)
+ local characters = data.characters
+ local descriptions = data.descriptions
+ if characters and descriptions then
+ local collected = sortedkeys(characters)
+ return wrap(function()
+ for c=1,#collected do
+ local cc = collected[c]
+ local dc = descriptions[cc]
+ if dc then
+ yield(cc,dc)
+ end
+ end
+ end)
+ else
+ return wrap(function() end)
+ end
+end
+
+local function getindices(data)
+ data = checkeddata(data)
+ local indices = { }
+ local characters = data.characters
+ if characters then
+ for unicode, character in next, characters do
+ indices[character.index or unicode] = unicode
+ end
+ end
+ return indices
+end
+
+function iterators.glyphs(data)
+ data = checkeddata(data)
+ local descriptions = data.descriptions
+ if descriptions then
+ local indices = getindices(data)
+ local collected = sortedkeys(indices)
+ return wrap(function()
+ for c=1,#collected do
+ local cc = collected[c]
+ local dc = descriptions[indices[cc]]
+ if dc then
+ yield(cc,dc)
+ end
+ end
+ end)
+ else
+ return wrap(function() end)
+ end
+end
diff --git a/tex/context/base/font-chk.lua b/tex/context/base/font-chk.lua
index d6a0cdcc8..819586532 100644
--- a/tex/context/base/font-chk.lua
+++ b/tex/context/base/font-chk.lua
@@ -7,6 +7,7 @@ if not modules then modules = { } end modules ['font-chk'] = {
}
-- possible optimization: delayed initialization of vectors
+-- move to the nodes namespace
local report_fonts = logs.reporter("fonts","checking")
@@ -15,7 +16,7 @@ local fonts = fonts
fonts.checkers = fonts.checkers or { }
local checkers = fonts.checkers
-local fontdata = fonts.identifiers
+local fontdata = fonts.hashes.identifiers
local is_character = characters.is_character
local chardata = characters.data
local tasks = nodes.tasks
@@ -30,7 +31,9 @@ local remove_node = nodes.remove
checkers.enabled = false
checkers.delete = false
-local function registermessage(font,char,message)
+-- to tfmdata.properties ?
+
+local function onetimemessage(font,char,message)
local tfmdata = fontdata[font]
local shared = tfmdata.shared
local messages = shared.messages
@@ -44,12 +47,12 @@ local function registermessage(font,char,message)
messages[message] = category
end
if not category[char] then
- report_fonts("char U+%04X in font '%s' with id %s: %s",char,tfmdata.fullname,font,message)
+ report_fonts("char U+%04X in font '%s' with id %s: %s",char,tfmdata.properties.fullname,font,message)
category[char] = true
end
end
-fonts.registermessage = registermessage
+fonts.loggers.onetimemessage = onetimemessage
function checkers.missing(head)
if checkers.enabled then
@@ -61,9 +64,9 @@ function checkers.missing(head)
end
if not characters[char] and is_character[chardata[char].category] then
if checkers.delete then
- registermessage(font,char,"missing (will be deleted)")
+ onetimemessage(font,char,"missing (will be deleted)")
else
- registermessage(font,char,"missing")
+ onetimemessage(font,char,"missing")
end
if not found then
found = { n }
diff --git a/tex/context/base/font-cid.lua b/tex/context/base/font-cid.lua
index a9bd3c56e..4a4c4d209 100644
--- a/tex/context/base/font-cid.lua
+++ b/tex/context/base/font-cid.lua
@@ -8,18 +8,19 @@ if not modules then modules = { } end modules ['font-cid'] = {
local format, match, lower = string.format, string.match, string.lower
local tonumber = tonumber
-local lpegmatch = lpeg.match
+local P, S, R, C, V, lpegmatch = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.match
-local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
+local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
local report_otf = logs.reporter("fonts","otf loading")
-local fonts = fonts
+local fonts = fonts
-fonts.cid = fonts.cid or { }
-local cid = fonts.cid
-cid.map = cid.map or { }
-cid.max = cid.max or 10
+local cid = { }
+fonts.cid = cid
+
+local cidmap = { }
+local cidmax = 10
-- original string parser: 0.109, lpeg parser: 0.036 seconds for Adobe-CNS1-4.cidmap
--
@@ -28,8 +29,6 @@ cid.max = cid.max or 10
-- 1..95 0020
-- 99 3000
-local P, S, R, C = lpeg.P, lpeg.S, lpeg.R, lpeg.C
-
local number = C(R("09","af","AF")^1)
local space = S(" \n\r\t")
local spaces = space^0
@@ -37,7 +36,7 @@ local period = P(".")
local periods = period * period
local name = P("/") * C((1-space)^1)
-local unicodes, names = { }, { }
+local unicodes, names = { }, { } -- we could use Carg now
local function do_one(a,b)
unicodes[tonumber(a)] = tonumber(b,16)
@@ -55,15 +54,15 @@ local function do_name(a,b)
names[tonumber(a)] = b
end
-local grammar = lpeg.P { "start",
- start = number * spaces * number * lpeg.V("series"),
- series = (spaces * (lpeg.V("one") + lpeg.V("range") + lpeg.V("named")) )^1,
+local grammar = P { "start",
+ start = number * spaces * number * V("series"),
+ series = (spaces * (V("one") + V("range") + V("named")))^1,
one = (number * spaces * number) / do_one,
range = (number * periods * number * spaces * number) / do_range,
named = (number * spaces * name) / do_name
}
-function cid.load(filename)
+local function loadcidfile(filename)
local data = io.loaddata(filename)
if data then
unicodes, names = { }, { }
@@ -77,75 +76,90 @@ function cid.load(filename)
unicodes = unicodes,
names = names
}
- else
- return nil
end
end
+cid.loadfile = loadcidfile -- we use the frozen variant
+
local template = "%s-%s-%s.cidmap"
local function locate(registry,ordering,supplement)
local filename = format(template,registry,ordering,supplement)
local hashname = lower(filename)
- local cidmap = cid.map[hashname]
- if not cidmap then
+ local found = cidmap[hashname]
+ if not found then
if trace_loading then
report_otf("checking cidmap, registry: %s, ordering: %s, supplement: %s, filename: %s",registry,ordering,supplement,filename)
end
local fullname = resolvers.findfile(filename,'cid') or ""
if fullname ~= "" then
- cidmap = cid.load(fullname)
- if cidmap then
+ found = loadcidfile(fullname)
+ if found then
if trace_loading then
report_otf("using cidmap file %s",filename)
end
- cid.map[hashname] = cidmap
- cidmap.usedname = file.basename(filename)
- return cidmap
+ cidmap[hashname] = found
+ found.usedname = file.basename(filename)
end
end
end
- return cidmap
+ return found
end
-function cid.getmap(registry,ordering,supplement)
- -- cf Arthur R. we can safely scan upwards since cids are downward compatible
- local supplement = tonumber(supplement)
+-- cf Arthur R. we can safely scan upwards since cids are downward compatible
+
+function cid.getmap(specification)
+ if not specification then
+ report_otf("invalid cidinfo specification (table expected)")
+ return
+ end
+ local registry = specification.registry
+ local ordering = specification.ordering
+ local supplement = specification.supplement
+ -- check for already loaded file
+ local filename = format(registry,ordering,supplement)
+ local found = cidmap[lower(filename)]
+ if found then
+ return found
+ end
if trace_loading then
report_otf("needed cidmap, registry: %s, ordering: %s, supplement: %s",registry,ordering,supplement)
end
- local cidmap = locate(registry,ordering,supplement)
- if not cidmap then
+ found = locate(registry,ordering,supplement)
+ if not found then
+ local supnum = tonumber(supplement)
local cidnum = nil
-- next highest (alternatively we could start high)
- if supplement < cid.max then
- for supplement=supplement+1,cid.max do
- local c = locate(registry,ordering,supplement)
+ if supnum < cidmax then
+ for s=supnum+1,cidmax do
+ local c = locate(registry,ordering,s)
if c then
- cidmap, cidnum = c, supplement
+ found, cidnum = c, s
break
end
end
end
-- next lowest (least worse fit)
- if not cidmap and supplement > 0 then
- for supplement=supplement-1,0,-1 do
- local c = locate(registry,ordering,supplement)
+ if not found and supnum > 0 then
+ for s=supnum-1,0,-1 do
+ local c = locate(registry,ordering,s)
if c then
- cidmap, cidnum = c, supplement
+ found, cidnum = c, s
break
end
end
end
- -- prevent further lookups
- if cidmap and cidnum > 0 then
+ -- prevent further lookups -- somewhat tricky
+ registry = lower(registry)
+ ordering = lower(ordering)
+ if found and cidnum > 0 then
for s=0,cidnum-1 do
- filename = format(template,registry,ordering,s)
- if not cid.map[filename] then
- cid.map[filename] = cidmap -- copy of ref
+ local filename = format(template,registry,ordering,s)
+ if not cidmap[filename] then
+ cidmap[filename] = found
end
end
end
end
- return cidmap
+ return found
end
diff --git a/tex/context/base/font-clr.lua b/tex/context/base/font-clr.lua
deleted file mode 100644
index 7d19aadd5..000000000
--- a/tex/context/base/font-clr.lua
+++ /dev/null
@@ -1,31 +0,0 @@
-if not modules then modules = { } end modules ['font-clr'] = {
- 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"
-}
-
--- moved from ini ... will become inline
-
-fonts.colors = fonts.colors or { } -- dummy in ini
-local colors = fonts.colors
-
-local set_attribute = node.set_attribute
-local unset_attribute = node.unset_attribute
-
-local attribute = attributes.private('color')
-local mapping = attributes and attributes.list[attribute] or { }
-
-function colors.set(n,c)
- local mc = mapping[c]
- if not mc then
- unset_attribute(n,attribute)
- else
- set_attribute(n,attribute,mc)
- end
-end
-
-function colors.reset(n)
- unset_attribute(n,attribute)
-end
diff --git a/tex/context/base/font-col.lua b/tex/context/base/font-col.lua
index 4b888d6cb..bf24737ba 100644
--- a/tex/context/base/font-col.lua
+++ b/tex/context/base/font-col.lua
@@ -28,7 +28,7 @@ local definitions = collections.definitions
collections.vectors = collections.vectors or { }
local vectors = collections.vectors
-local fontdata = fonts.identifiers
+local fontdata = fonts.hashes.identifiers
local glyph = node.id('glyph')
@@ -67,7 +67,7 @@ function collections.define(name,font,ranges,details)
end
details = settings_to_hash(details)
-- todo, combine per font start/stop as arrays
- for s in gmatch(ranges,"([^, ]+)") do
+ for s in gmatch(ranges,"[^, ]+") do
local start, stop, description = characters.getrange(s)
if start and stop then
if trace_collecting then
@@ -162,7 +162,7 @@ function collections.prepare(name)
local d = definitions[name]
if d then
if trace_collecting then
- local filename = file.basename(fontdata[current].filename or "?")
+ local filename = file.basename(fontdata[current].properties.filename or "?")
report_fonts("def: applying collection %s to %s (file: %s)",name,current,filename)
end
list = { }
@@ -181,7 +181,7 @@ function collections.prepare(name)
context.doclonefontstagetwo(name) -- preparing clone vectors
context.dostopcloningfonts()
elseif trace_collecting then
- local filename = file.basename(fontdata[current].filename or "?")
+ local filename = file.basename(fontdata[current].properties.filename or "?")
report_fonts("def: error in applying collection %s to %s (file: %s)",name,current,filename)
end
end
diff --git a/tex/context/base/font-con.lua b/tex/context/base/font-con.lua
new file mode 100644
index 000000000..230136929
--- /dev/null
+++ b/tex/context/base/font-con.lua
@@ -0,0 +1,1175 @@
+if not modules then modules = { } end modules ['font-con'] = {
+ 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 utf = unicode.utf8
+
+local next, tostring, setmetatable, rawget = next, tostring, setmetatable, rawget
+local format, match, lower, gsub = string.format, string.match, string.lower, string.gsub
+local utfbyte = utf.byte
+local sort, insert, concat, sortedkeys, serialize, fastcopy = table.sort, table.insert, table.concat, table.sortedkeys, table.serialize, table.fastcopy
+
+local allocate = utilities.storage.allocate
+
+local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
+local trace_scaling = false trackers.register("fonts.scaling" , function(v) trace_scaling = v end)
+
+local report_defining = logs.reporter("fonts","defining")
+
+-- watch out: no negative depths and negative eights permitted in regular fonts
+
+--[[ldx--
+<p>Here we only implement a few helper functions.</p>
+--ldx]]--
+
+local fonts = fonts
+local constructors = { }
+fonts.constructors = constructors
+local handlers = { }
+fonts.handlers = handlers
+
+local specifiers = fonts.specifiers
+local contextsetups = specifiers.contextsetups
+local contextnumbers = specifiers.contextnumbers
+
+-- will be directives
+
+constructors.sharebasekerns = false -- true (.5 sec slower on mk but brings down mem from 410M to 310M, beware: then script/lang share too)
+constructors.dontembed = allocate()
+constructors.mathactions = { }
+constructors.autocleanup = true
+constructors.namemode = "fullpath" -- will be a function
+
+constructors.version = 1.01
+constructors.cache = containers.define("fonts", "constructors", constructors.version, false)
+
+constructors.privateoffset = 0xF0000 -- 0x10FFFF
+
+-- This might become an interface;
+
+local designsizes = allocate()
+constructors.designsizes = designsizes
+local loadedfonts = allocate()
+constructors.loadedfonts = loadedfonts
+
+--[[ldx--
+<p>We need to normalize the scale factor (in scaled points). This has to
+do with the fact that <l n='tex'/> uses a negative multiple of 1000 as
+a signal for a font scaled based on the design size.</p>
+--ldx]]--
+
+local factors = {
+ pt = 65536.0,
+ bp = 65781.8,
+}
+
+function constructors.setfactor(f)
+ constructors.factor = factors[f or 'pt'] or factors.pt
+end
+
+constructors.setfactor()
+
+function constructors.scaled(scaledpoints, designsize) -- handles designsize in sp as well
+ if scaledpoints < 0 then
+ if designsize then
+ local factor = constructors.factor
+ if designsize > factor then -- or just 1000 / when? mp?
+ return (- scaledpoints/1000) * designsize -- sp's
+ else
+ return (- scaledpoints/1000) * designsize * factor
+ end
+ else
+ return (- scaledpoints/1000) * 10 * factor
+ end
+ else
+ return scaledpoints
+ end
+end
+
+--[[ldx--
+<p>Beware, the boundingbox is passed as reference so we may not overwrite it
+in the process; numbers are of course copies. Here 65536 equals 1pt. (Due to
+excessive memory usage in CJK fonts, we no longer pass the boundingbox.)</p>
+--ldx]]--
+
+-- the following hack costs a bit of runtime but safes memory
+--
+-- basekerns are scaled and will be hashed by table id
+-- sharedkerns are unscaled and are be hashed by concatenated indexes
+
+--~ function constructors.check_base_kerns(tfmdata)
+--~ if constructors.sharebasekerns then
+--~ local sharedkerns = tfmdata.sharedkerns
+--~ if sharedkerns then
+--~ local basekerns = { }
+--~ tfmdata.basekerns = basekerns
+--~ return sharedkerns, basekerns
+--~ end
+--~ end
+--~ return nil, nil
+--~ end
+
+--~ function constructors.prepare_base_kerns(tfmdata)
+--~ if constructors.sharebasekerns and not tfmdata.sharedkerns then
+--~ local sharedkerns = { }
+--~ tfmdata.sharedkerns = sharedkerns
+--~ for u, chr in next, tfmdata.characters do
+--~ local kerns = chr.kerns
+--~ if kerns then
+--~ local hash = concat(sortedkeys(kerns), " ")
+--~ local base = sharedkerns[hash]
+--~ if not base then
+--~ sharedkerns[hash] = kerns
+--~ else
+--~ chr.kerns = base
+--~ end
+--~ end
+--~ end
+--~ end
+--~ end
+
+-- we can cache scaled characters when we are in node mode and don't have
+-- protruding and expansion: hash == fullname @ size @ protruding @ expansion
+-- but in practice (except from mk) the otf hash will be enough already so it
+-- makes no sense to mess up the code now
+
+-- The scaler is only used for otf and afm and virtual fonts. If
+-- a virtual font has italic correction make sure to set the
+-- italic_correction flag. Some more flags will be added in
+-- the future.
+
+--[[ldx--
+<p>The reason why the scaler was originally split, is that for a while we experimented
+with a helper function. However, in practice the <l n='api'/> calls are too slow to
+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 soem 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
+end
+
+-- experimental, sharing kerns (unscaled and scaled) saves memory
+-- local sharedkerns, basekerns = constructors.check_base_kerns(tfmdata)
+-- loop over descriptions (afm and otf have descriptions, tfm not)
+-- there is no need (yet) to assign a value to chr.tonunicode
+
+-- constructors.prepare_base_kerns(tfmdata) -- optimalization
+
+-- we have target.name=metricfile and target.fullname=RealName and target.filename=diskfilename
+-- when collapsing fonts, luatex looks as both target.name and target.fullname as ttc files
+-- can have multiple subfonts
+
+function constructors.calculatescale(tfmdata,scaledpoints)
+ local parameters = tfmdata.parameters
+ if scaledpoints < 0 then
+ scaledpoints = (- scaledpoints/1000) * (tfmdata.designsize or parameters.designsize) -- already in sp
+ end
+ return scaledpoints, scaledpoints / (parameters.units or 1000) -- delta
+end
+
+function constructors.scale(tfmdata,specification)
+ local target = { } -- the new table
+ --
+ if tonumber(specification) then
+ specification = { size = specification }
+ end
+ --
+ local scaledpoints = specification.size
+ local relativeid = specification.relativeid
+ --
+ local properties = tfmdata.properties or { }
+ local goodies = tfmdata.goodies or { }
+ local resources = tfmdata.resources or { }
+ local descriptions = tfmdata.descriptions or { } -- bad news if empty
+ local characters = tfmdata.characters or { } -- bad news if empty
+ local changed = tfmdata.changed or { } -- for base mode
+ local shared = tfmdata.shared or { }
+ local parameters = tfmdata.parameters or { }
+ local mathparameters = tfmdata.mathparameters or { }
+ local MathConstants = tfmdata.mathconstants or { }
+ --
+ local targetcharacters = { }
+ local targetdescriptions = table.derive(descriptions)
+ local targetparameters = table.derive(parameters)
+ local targetmathparameters = table.derive(mathparameters)
+ local targetproperties = table.derive(properties)
+ local targetgoodies = table.derive(goodies)
+ target.characters = targetcharacters
+ target.descriptions = targetdescriptions
+ target.parameters = targetparameters
+ target.mathparameters = targetmathparameters
+ target.properties = targetproperties
+ target.goodies = targetgoodies
+ target.shared = shared
+ target.resources = resources
+ target.unscaled = tfmdata -- the original unscaled one (temp)
+ --
+ -- specification.mathsize : 1=text 2=script 3=scriptscript
+ -- specification.textsize : natural (text)size
+ -- parameters.mathsize : 1=text 2=script 3=scriptscript >1000 enforced size (feature value other than yes)
+ --
+ local mathsize = tonumber(specification.mathsize) or 0
+ local textsize = tonumber(specification.textsize) or scaledpoints
+ local forcedsize = tonumber(parameters.mathsize ) or 0
+ if (mathsize == 2 or forcedsize == 2) and parameters.scriptpercentage then
+ scaledpoints = parameters.scriptpercentage * textsize / 100
+ elseif (mathsize == 3 or forcedsize == 3) and parameters.scriptscriptpercentage then
+ scaledpoints = parameters.scriptscriptpercentage * textsize / 100
+ elseif forcedsize > 1000 then -- safeguard
+ scaledpoints = forcedsize
+ end
+ --
+ local tounicode = resources.tounicode
+ local defaultwidth = resources.defaultwidth or 0
+ local defaultheight = resources.defaultheight or 0
+ local defaultdepth = resources.defaultdepth or 0
+ local units = parameters.units or 1000
+ --
+ if target.fonts then
+ target.fonts = fastcopy(target.fonts) -- maybe we virtualize more afterwards
+ end
+ --
+ -- boundary keys are no longer needed as we now have a string 'right_boundary'
+ -- that can be used in relevant tables (kerns and ligatures) ... not that I ever
+ -- used them
+ --
+ -- boundarychar_label = 0, -- not needed
+ -- 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
+ --
+ local askedscaledpoints = scaledpoints
+ local scaledpoints, delta = constructors.calculatescale(tfmdata,scaledpoints) -- no shortcut, dan be redefined
+ --
+ local hdelta = delta
+ local vdelta = delta
+ --
+ target.designsize = parameters.designsize -- not really needed so it muight become obsolete
+ target.units_per_em = units -- just a trigger for the backend (does luatex use this? if not it will go)
+ --
+ local direction = properties.direction or tfmdata.direction or 0 -- pointless, as we don't use omf fonts at all
+ target.direction = direction
+ properties.direction = direction
+ --
+ target.size = scaledpoints
+ --
+ target.encodingbytes = properties.encodingbytes or 1
+ target.embedding = properties.embedding or "subset"
+ target.tounicode = 1
+ target.cidinfo = properties.cidinfo
+ target.format = properties.format
+ --
+ local fontname = properties.fontname or tfmdata.fontname -- for the moment we fall back on
+ local fullname = properties.fullname or tfmdata.fullname -- names in the tfmdata although
+ local filename = properties.filename or tfmdata.filename -- that is not the right place to
+ local psname = properties.psname or tfmdata.psname -- pass them
+ local name = properties.name or tfmdata.name
+ --
+ if not psname or psname == "" then
+ -- name used in pdf file as well as for selecting subfont in ttc/dfont
+ psname = fontname or (fullname and fonts.names.cleanname(fullname))
+ end
+ target.fontname = fontname
+ target.fullname = fullname
+ target.filename = filename
+ target.psname = psname
+ target.name = name
+ --
+ properties.fontname = fontname
+ properties.fullname = fullname
+ properties.filename = filename
+ properties.psname = psname
+ properties.name = name
+ -- expansion (hz)
+ local expansion = parameters.expansion
+ if expansion then
+ target.stretch = expansion.stretch
+ target.shrink = expansion.shrink
+ target.step = expansion.step
+ target.auto_expand = expansion.auto
+ end
+ -- protrusion
+ local protrusion = parameters.protrusion
+ if protrusion then
+ target.auto_protrude = protrusion.auto
+ end
+ -- widening
+ local extend_factor = parameters.extend_factor or 0
+ if extend_factor ~= 0 and extend_factor ~= 1 then
+ hdelta = hdelta * extend_factor
+ target.extend = extend_factor * 1000 -- extent ?
+ else
+ target.extend = 1000 -- extent ?
+ end
+ -- slanting
+ local slant_factor = parameters.slant_factor or 0
+ if slant_factor ~= 0 then
+ target.slant = slant_factor * 1000
+ else
+ target.slant = 0
+ end
+ --
+ targetparameters.hfactor = hdelta
+ targetparameters.vfactor = vdelta
+ targetparameters.factor = delta
+ targetparameters.size = scaledpoints
+ targetparameters.units = units
+ targetparameters.scaledpoints = askedscaledpoints
+ --
+ local isvirtual = properties.virtualized or tfmdata.type == "virtual"
+ local hasquality = target.auto_expand or target.auto_protrude
+ local hasitalic = properties.italic_correction
+ local stackmath = not properties.no_stackmath
+ local nonames = properties.noglyphnames
+ local nodemode = properties.mode == "node"
+ --
+ if changed and not next(changed) then
+ changed = false
+ end
+ --
+ target.type = isvirtual and "virtual" or "real"
+ -- more extensive test
+ local hasmath = (properties.math or next(mathparameters) or next(MathConstants)) and true
+ if hasmath then
+ properties.has_math = true
+ target.nomath = false
+ target.MathConstants = MathConstants
+ target.mathconstants = MathConstants
+ else
+ properties.has_math = false
+ target.nomath = true
+ target.mathparameters = nil -- nop
+ end
+ -- this will move to some subtable so that it is copied at once
+ target.postprocessors = tfmdata.postprocessors
+ --
+ local targetslant = (parameters.slant or parameters[1] or 0)
+ local targetspace = (parameters.space or parameters[2] or 0)*hdelta
+ local targetspace_stretch = (parameters.space_stretch or parameters[3] or 0)*hdelta
+ local targetspace_shrink = (parameters.space_shrink or parameters[4] or 0)*hdelta
+ local targetx_height = (parameters.x_height or parameters[5] or 0)*vdelta
+ local targetquad = (parameters.quad or parameters[6] or 0)*hdelta
+ local targetextra_space = (parameters.extra_space or parameters[7] or 0)*hdelta
+ --
+ targetparameters.slant = targetslant
+ targetparameters.space = targetspace
+ targetparameters.space_stretch = targetspace_stretch
+ targetparameters.space_shrink = targetspace_shrink
+ targetparameters.x_height = targetx_height
+ targetparameters.quad = targetquad
+ targetparameters.extra_space = targetextra_space
+ --
+ local ascender = parameters.ascender
+ if ascender then
+ targetparameters.ascender = delta * ascender
+ end
+ local descender = parameters.descender
+ if descender then
+ targetparameters.descender = delta * descender
+ end
+ --
+ if hasmath then
+ local ma = constructors.mathactions
+ local ta = type(ma)
+ if ta == "function" then -- context
+ ma(target,tfmdata)
+ elseif ta == "table" then -- generic (we keep the deltas)
+ for i=1,#ma do
+ ma[i](target,tfmdata,delta,hdelta,vdelta)
+ end
+ end
+ if not targetparameters[13] then targetparameters[13] = .86*targetx_height end -- mathsupdisplay
+ if not targetparameters[14] then targetparameters[14] = .86*targetx_height end -- mathsupnormal
+ if not targetparameters[15] then targetparameters[15] = .86*targetx_height end -- mathsupcramped
+ if not targetparameters[16] then targetparameters[16] = .48*targetx_height end -- mathsubnormal
+ if not targetparameters[17] then targetparameters[17] = .48*targetx_height end -- mathsubcombined
+ if not targetparameters[22] then targetparameters[22] = 0 end -- mathaxisheight
+ if target.MathConstants then target.MathConstants.AccentBaseHeight = nil end -- safeguard
+ if trace_defining then
+ report_defining("math enabled for: name '%s', fullname: '%s', filename: '%s'",
+ name or "noname",fullname or "nofullname",filename or "nofilename")
+ end
+ else
+ if trace_defining then
+ report_defining("math disabled for: name '%s', fullname: '%s', filename: '%s'",
+ name or "noname",fullname or "nofullname",filename or "nofilename")
+ end
+ end
+ --
+ targetparameters.xheight = targetparameters.xheight or parameters.x_height
+ targetparameters.extraspace = targetparameters.extraspace or parameters.extra_space
+ targetparameters.spacestretch = targetparameters.spacestretch or parameters.space_stretch
+ targetparameters.spaceshrink = targetparameters.spaceshrink or parameters.space_shrink
+ --
+ local protrusionfactor = (targetquad ~= 0 and 1000/targetquad) or 0
+ local scaledwidth = defaultwidth * hdelta
+ local scaledheight = defaultheight * vdelta
+ local scaleddepth = defaultdepth * vdelta
+ --
+ local sharedkerns = { }
+ --
+ for unicode, character in next, characters do
+ local chr, description, index
+ if changed then
+ -- basemode hack
+ local c = changed[unicode]
+ if c then
+ description = descriptions[c] or character
+ character = characters[c] or character
+ index = description.index or c
+ else
+ description = descriptions[unicode] or character
+ index = description.index or unicode
+ end
+ else
+ description = descriptions[unicode] or character
+ index = description.index or unicode
+ end
+ local width = description.width
+ local height = description.height
+ local depth = description.depth
+ if width then width = hdelta*width else width = scaledwidth end
+ if height then height = vdelta*height else height = scaledheight end
+ -- if depth then depth = vdelta*depth else depth = scaleddepth end
+ if depth and depth ~= 0 then
+ depth = delta*depth
+ if nonames then
+ chr = {
+ index = index,
+ height = height,
+ depth = depth,
+ width = width,
+ }
+ else
+ chr = {
+ name = description.name,
+ index = index,
+ height = height,
+ depth = depth,
+ width = width,
+ }
+ end
+ else
+ -- this saves a little bit of memory time and memory, esp for big cjk fonts
+ if nonames then
+ chr = {
+ index = index,
+ height = height,
+ width = width,
+ }
+ else
+ chr = {
+ name = description.name,
+ index = index,
+ height = height,
+ width = width,
+ }
+ end
+ end
+ -- if trace_scaling then
+ -- report_defining("t=%s, u=%s, i=%s, n=%s c=%s",k,chr.tounicode or "",index or 0,description.name or '-',description.class or '-')
+ -- end
+ if tounicode then
+ local tu = tounicode[index] -- nb: index!
+ if tu then
+ chr.tounicode = tu
+ end
+ end
+ if hasquality then
+ -- we could move these calculations elsewhere (saves calculations)
+ local ve = character.expansion_factor
+ if ve then
+ chr.expansion_factor = ve*1000 -- expansionfactor, hm, can happen elsewhere
+ end
+ local vl = character.left_protruding
+ if vl then
+ chr.left_protruding = protrusionfactor*width*vl
+ end
+ local vr = character.right_protruding
+ if vr then
+ chr.right_protruding = protrusionfactor*width*vr
+ end
+ end
+ -- todo: hasitalic
+ if hasitalic then
+ local vi = description.italic or character.italic
+ if vi and vi ~= 0 then
+ chr.italic = vi*hdelta
+ end
+ end
+ -- to be tested
+ if hasmath then
+ -- todo, just operate on descriptions.math
+ local vn = character.next
+ if vn then
+ chr.next = vn
+ -- if character.vert_variants or character.horiz_variants then
+ -- report_defining("glyph 0x%05X has combination of next, vert_variants and horiz_variants",index)
+ -- end
+ else
+ local vv = character.vert_variants
+ if vv then
+ local t = { }
+ for i=1,#vv do
+ local vvi = vv[i]
+ t[i] = {
+ ["start"] = (vvi["start"] or 0)*vdelta,
+ ["end"] = (vvi["end"] or 0)*vdelta,
+ ["advance"] = (vvi["advance"] or 0)*vdelta,
+ ["extender"] = vvi["extender"],
+ ["glyph"] = vvi["glyph"],
+ }
+ end
+ chr.vert_variants = t
+ else
+ local hv = character.horiz_variants
+ if hv then
+ local t = { }
+ for i=1,#hv do
+ local hvi = hv[i]
+ t[i] = {
+ ["start"] = (hvi["start"] or 0)*hdelta,
+ ["end"] = (hvi["end"] or 0)*hdelta,
+ ["advance"] = (hvi["advance"] or 0)*hdelta,
+ ["extender"] = hvi["extender"],
+ ["glyph"] = hvi["glyph"],
+ }
+ end
+ chr.horiz_variants = t
+ end
+ end
+ end
+ local va = character.top_accent
+ if va then
+ chr.top_accent = vdelta*va
+ end
+ if stackmath then
+ local mk = character.mathkerns -- not in math ?
+ if mk then
+ local kerns = { }
+ local v = mk.top_right if v then local k = { } for i=1,#v do local vi = v[i]
+ k[i] = { height = vdelta*vi.height, kern = vdelta*vi.kern }
+ end kerns.top_right = k end
+ local v = mk.top_left if v then local k = { } for i=1,#v do local vi = v[i]
+ k[i] = { height = vdelta*vi.height, kern = vdelta*vi.kern }
+ end kerns.top_left = k end
+ local v = mk.bottom_left if v then local k = { } for i=1,#v do local vi = v[i]
+ k[i] = { height = vdelta*vi.height, kern = vdelta*vi.kern }
+ end kerns.bottom_left = k end
+ local v = mk.bottom_right if v then local k = { } for i=1,#v do local vi = v[i]
+ k[i] = { height = vdelta*vi.height, kern = vdelta*vi.kern }
+ end kerns.bottom_right = k end
+ chr.mathkern = kerns -- singular -> should be patched in luatex !
+ end
+ end
+ end
+ if not nodemode then
+ local vk = character.kerns
+ if vk then
+ -- if sharedkerns then
+ -- local base = basekerns[vk] -- hashed by table id, not content
+ -- if not base then
+ -- base = {}
+ -- for k,v in next, vk do base[k] = v*hdelta end
+ -- basekerns[vk] = base
+ -- end
+ -- chr.kerns = base
+ -- else
+ -- local tt = {}
+ -- for k,v in next, vk do tt[k] = v*hdelta end
+ -- chr.kerns = tt
+ -- end
+ local s = sharedkerns[vk]
+ if not s then
+ s = { }
+ for k,v in next, vk do s[k] = v*hdelta end
+ sharedkerns[vk] = s
+ end
+ chr.kerns = s
+ end
+ local vl = character.ligatures
+ if vl then
+ if true then
+ chr.ligatures = vl -- shared
+ else
+ local tt = { }
+ for i,l in next, vl do
+ tt[i] = l
+ end
+ chr.ligatures = tt
+ end
+ end
+ end
+ if isvirtual then
+ local vc = character.commands
+ if vc then
+ -- we assume non scaled commands here
+ -- tricky .. we need to scale pseudo math glyphs too
+ -- which is why we deal with rules too
+ local ok = false
+ for i=1,#vc do
+ local key = vc[i][1]
+ if key == "right" or key == "down" then
+ ok = true
+ break
+ end
+ end
+ if ok then
+ local tt = { }
+ for i=1,#vc do
+ local ivc = vc[i]
+ local key = ivc[1]
+ if key == "right" then
+ tt[i] = { key, ivc[2]*hdelta }
+ elseif key == "down" then
+ tt[i] = { key, ivc[2]*vdelta }
+ elseif key == "rule" then
+ tt[i] = { key, ivc[2]*vdelta, ivc[3]*hdelta }
+ else -- not comment
+ tt[i] = ivc -- shared since in cache and untouched
+ end
+ end
+ chr.commands = tt
+ else
+ chr.commands = vc
+ end
+ chr.index = nil
+ end
+ end
+ targetcharacters[unicode] = chr
+ end
+ return target
+end
+
+function constructors.finalize(tfmdata)
+ if tfmdata.properties and tfmdata.properties.finalized then
+ return
+ end
+ --
+ if not tfmdata.characters then
+ return nil
+ end
+ --
+ if not tfmdata.goodies then
+ tfmdata.goodies = { } -- context specific
+ end
+ --
+ local parameters = tfmdata.parameters
+ if not parameters then
+ return nil
+ end
+ --
+ if not parameters.expansion then
+ parameters.expansion = {
+ stretch = tfmdata.stretch or 0,
+ shrink = tfmdata.shrink or 0,
+ step = tfmdata.step or 0,
+ auto = tfmdata.auto_expand or false,
+ }
+ end
+ --
+ if not parameters.protrusion then
+ parameters.protrusion = {
+ auto = auto_protrude
+ }
+ end
+ --
+ if not parameters.size then
+ parameters.size = tfmdata.size
+ end
+ --
+ if not parameters.extend_factor then
+ parameters.extend_factor = tfmdata.extend or 0
+ end
+ --
+ if not parameters.slant_factor then
+ parameters.slant_factor = tfmdata.slant or 0
+ end
+ --
+ if not parameters.designsize then
+ parameters.designsize = tfmdata.designsize or 655360
+ end
+ --
+ if not parameters.units then
+ parameters.units = tfmdata.units_per_em or 1000
+ end
+ --
+ if not tfmdata.descriptions then
+ local descriptions = { } -- yes or no
+ setmetatable(descriptions, { __index = function(t,k) local v = { } t[k] = v return v end })
+ tfmdata.descriptions = descriptions
+ end
+ --
+ local properties = tfmdata.properties
+ if not properties then
+ properties = { }
+ tfmdata.properties = properties
+ end
+ --
+ if not properties.virtualized then
+ properties.virtualized = tfmdata.type == "virtual"
+ end
+ --
+ if not tfmdata.properties then
+ tfmdata.properties = {
+ fontname = tfmdata.fontname,
+ filename = tfmdata.filename,
+ fullname = tfmdata.fullname,
+ name = tfmdata.name,
+ psname = tfmdata.psname,
+ --
+ encodingbytes = tfmdata.encodingbytes or 1,
+ embedding = tfmdata.embedding or "subset",
+ tounicode = tfmdata.tounicode or 1,
+ cidinfo = tfmdata.cidinfo or nil,
+ format = tfmdata.format or "type1",
+ direction = tfmdata.direction or 0,
+ }
+ end
+ if not tfmdata.resources then
+ tfmdata.resources = { }
+ end
+ if not tfmdata.shared then
+ tfmdata.shared = { }
+ end
+ --
+ -- tfmdata.fonts
+ -- tfmdata.unscaled
+ -- tfmdata.mathconstants
+ --
+ if not properties.has_math then
+ properties.has_math = not tfmdata.nomath
+ end
+ --
+ tfmdata.MathConstants = nil
+ tfmdata.postprocessors = nil
+ --
+ tfmdata.fontname = nil
+ tfmdata.filename = nil
+ tfmdata.fullname = nil
+ tfmdata.name = nil -- most tricky part
+ tfmdata.psname = nil
+ --
+ tfmdata.encodingbytes = nil
+ tfmdata.embedding = nil
+ tfmdata.tounicode = nil
+ tfmdata.cidinfo = nil
+ tfmdata.format = nil
+ tfmdata.direction = nil
+ tfmdata.type = nil
+ tfmdata.nomath = nil
+ tfmdata.designsize = nil
+ --
+ tfmdata.size = nil
+ tfmdata.stretch = nil
+ tfmdata.shrink = nil
+ tfmdata.step = nil
+ tfmdata.auto_expand = nil
+ tfmdata.auto_protrude = nil
+ tfmdata.extend = nil
+ tfmdata.slant = nil
+ tfmdata.units_per_em = nil
+ --
+ properties.finalized = true
+ --
+ return tfmdata
+end
+
+--[[ldx--
+<p>A unique hash value is generated by:</p>
+--ldx]]--
+
+local hashmethods = { }
+constructors.hashmethods = hashmethods
+
+function constructors.hashfeatures(specification) -- will be overloaded
+ local features = specification.features
+ if features then
+ local t, tn = { }, 0
+ for category, list in next, features do
+ if next(list) then
+ local hasher = hashmethods[category]
+ if hasher then
+ local hash = hasher(list)
+ if hash then
+ tn = tn + 1
+ t[tn] = category .. ":" .. hash
+ end
+ end
+ end
+ end
+ if tn > 0 then
+ return concat(t," & ")
+ end
+ end
+ return "unknown"
+end
+
+hashmethods.normal = function(list)
+ local s = { }
+ local n = 0
+ for k, v in next, list do
+ if k ~= "number" and k ~= "features" then -- I need to figure this out, features
+ n = n + 1
+ s[n] = k
+ end
+ 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
+
+--[[ldx--
+<p>In principle we can share tfm tables when we are in node for a font, but then
+we need to define a font switch as an id/attr switch which is no fun, so in that
+case users can best use dynamic features ... so, we will not use that speedup. Okay,
+when we get rid of base mode we can optimize even further by sharing, but then we
+loose our testcases for <l n='luatex'/>.</p>
+--ldx]]--
+
+function constructors.hashinstance(specification,force)
+ local hash, size, fallbacks = specification.hash, specification.size, specification.fallbacks
+ if force or not hash then
+ hash = constructors.hashfeatures(specification)
+ specification.hash = hash
+ end
+ if size < 1000 and designsizes[hash] then
+ size = math.round(constructors.scaled(size,designsizes[hash]))
+ specification.size = size
+ end
+ -- local mathsize = specification.mathsize or 0
+ -- if mathsize > 0 then
+ -- local textsize = specification.textsize
+ -- if fallbacks then
+ -- return hash .. ' @ ' .. tostring(size) .. ' [ ' .. tostring(mathsize) .. ' : ' .. tostring(textsize) .. ' ] @ ' .. fallbacks
+ -- else
+ -- return hash .. ' @ ' .. tostring(size) .. ' [ ' .. tostring(mathsize) .. ' : ' .. tostring(textsize) .. ' ]'
+ -- end
+ -- else
+ if fallbacks then
+ return hash .. ' @ ' .. tostring(size) .. ' @ ' .. fallbacks
+ else
+ return hash .. ' @ ' .. tostring(size)
+ end
+ -- end
+end
+
+function constructors.setname(tfmdata,specification) -- todo: get specification from tfmdata
+ if constructors.namemode == "specification" then
+ -- not to be used in context !
+ local specname = specification.specification
+ if specname then
+ tfmdata.properties.name = specname
+ if trace_defining then
+ report_otf("overloaded fontname: '%s'",specname)
+ end
+ end
+ end
+end
+
+function constructors.checkedfilename(data)
+ local foundfilename = data.foundfilename
+ if not foundfilename then
+ local askedfilename = data.filename or ""
+ if askedfilename ~= "" then
+ askedfilename = resolvers.resolve(askedfilename) -- no shortcut
+ foundfilename = resolvers.findbinfile(askedfilename,"") or ""
+ if foundfilename == "" then
+ report_defining("source file '%s' is not found",askedfilename)
+ foundfilename = resolvers.findbinfile(file.basename(askedfilename),"") or ""
+ if foundfilename ~= "" then
+ report_defining("using source file '%s' (cache mismatch)",foundfilename)
+ end
+ end
+ end
+ data.foundfilename = foundfilename
+ end
+ return foundfilename
+end
+
+local formats = allocate()
+fonts.formats = formats
+
+setmetatable(formats, {
+ __index = function(t,k)
+ local l = lower(k)
+ if rawget(t,k) then
+ t[k] = l
+ return l
+ end
+ return rawget(t,file.extname(l))
+ end
+} )
+
+local locations = { }
+
+local function setindeed(mode,target,group,name,action,position)
+ local t = target[mode]
+ if not t then
+ report_defining("fatal error in setting feature '%s', group '%s', mode '%s'",name or "?",group or "?",mode)
+ os.exit()
+ elseif position then
+ -- todo: remove existing
+ insert(t, position, { name = name, action = action })
+ else
+ for i=1,#t do
+ local ti = t[i]
+ if ti.name == name then
+ ti.action = action
+ return
+ end
+ end
+ insert(t, { name = name, action = action })
+ end
+end
+
+local function set(group,name,target,source)
+ target = target[group]
+ if not target then
+ report_defining("fatal target error in setting feature '%s', group '%s'",name or "?",group or "?")
+ os.exit()
+ end
+ local source = source[group]
+ if not source then
+ report_defining("fatal source error in setting feature '%s', group '%s'",name or "?",group or "?")
+ os.exit()
+ end
+ local node = source.node
+ local base = source.base
+ local position = source.position
+ if node then
+ setindeed("node",target,group,name,node,position)
+ end
+ if base then
+ setindeed("base",target,group,name,base,position)
+ end
+end
+
+local function register(where,specification)
+ local name = specification.name
+ if name and name ~= "" then
+ local default = specification.default
+ local description = specification.description
+ local initializers = specification.initializers
+ local processors = specification.processors
+ local manipulators = specification.manipulators
+ local modechecker = specification.modechecker
+ if default then
+ where.defaults[name] = default
+ end
+ if description and description ~= "" then
+ where.descriptions[name] = description
+ end
+ if initializers then
+ set('initializers',name,where,specification)
+ end
+ if processors then
+ set('processors', name,where,specification)
+ end
+ if manipulators then
+ set('manipulators',name,where,specification)
+ end
+ if modechecker then
+ where.modechecker = modechecker
+ end
+ end
+end
+
+constructors.registerfeature = register
+
+function constructors.getfeatureaction(what,where,mode,name)
+ what = handlers[what].features
+ if what then
+ where = what[where]
+ if where then
+ mode = where[mode]
+ if mode then
+ for i=1,#mode do
+ local m = mode[i]
+ if m.name == name then
+ return m.action
+ end
+ end
+ end
+ end
+ end
+end
+
+function constructors.newfeatures(what)
+ local features = handlers[what].features
+ if not features then
+ local tables = handlers[what].tables -- can be preloaded
+ features = {
+ defaults = { },
+ descriptions = tables and tables.features or { },
+ initializers = { base = { }, node = { } },
+ processors = { base = { }, node = { } },
+ manipulators = { base = { }, node = { } },
+ }
+ features.register = function(specification) return register(features,specification) end
+ handlers[what].features = features -- will also become hidden
+ end
+ return features
+end
+
+--[[ldx--
+<p>We need to check for default features. For this we provide
+a helper function.</p>
+--ldx]]--
+
+function constructors.checkedfeatures(what,features)
+ if features and next(features) then
+ local done = false
+ for key, value in next, handlers[what].features.defaults do
+ if features[key] == nil then
+ features[key] = value
+ done = true
+ end
+ end
+ return features, done -- done signals a change
+ else
+ return fastcopy(defaults), true
+ end
+end
+
+-- before scaling
+
+function constructors.initializefeatures(what,tfmdata,features,trace,report)
+ if features and next(features) then
+ local properties = tfmdata.properties or { } -- brrr
+ local whathandler = handlers[what]
+ local whatfeatures = whathandler.features
+ local whatinitializers = whatfeatures.initializers
+ local whatmodechecker = whatfeatures.modechecker
+ local mode = properties.mode or (whatmodechecker and whatmodechecker(tfmdata,features)) or features.mode or "base"
+ properties.mode = mode -- also status
+ local done = { }
+ while true do
+ local redo = false
+ local initializers = whatfeatures.initializers[mode]
+ if initializers then
+ for i=1,#initializers do
+ local step = initializers[i]
+ local feature = step.name
+ local value = features[feature]
+ if not value then
+ -- disabled
+ elseif done[feature] then
+ -- already done
+ else
+ local action = step.action
+ if trace then
+ report("initializing feature %s to %s for mode %s for font %s",feature,
+ tostring(value),mode or 'unknown', tfmdata.properties.fullname or 'unknown')
+ end
+ action(tfmdata,value,features) -- can set mode (e.g. goodies) so it can trigger a restart
+ if mode ~= properties.mode then
+ mode = properties.mode
+ redo = true
+ end
+ done[feature] = true
+ end
+ if redo then
+ break
+ end
+ end
+ if not redo then
+ break
+ end
+ else
+ break
+ end
+ end
+ properties.mode = mode -- to be sure
+ return true
+ else
+ return false
+ end
+end
+
+-- while typesetting
+
+function constructors.collectprocessors(what,tfmdata,features,trace,report)
+ local processes, nofprocesses = { }, 0
+ if features and next(features) then
+ local properties = tfmdata.properties
+ local whathandler = handlers[what]
+ local whatfeatures = whathandler.features
+ local whatprocessors = whatfeatures.processors
+ local processors = whatprocessors[properties.mode]
+ if processors then
+ for i=1,#processors do
+ local step = processors[i]
+ local feature = step.name
+ if features[feature] then
+ local action = step.action
+ if trace then
+ report("installing feature processor %s for mode %s for font %s",feature,
+ mode or 'unknown', tfmdata.properties.fullname or 'unknown')
+ end
+ if action then
+ nofprocesses = nofprocesses + 1
+ processes[nofprocesses] = action
+ end
+ end
+ end
+ end
+ end
+ return processes
+end
+
+-- after scaling
+
+function constructors.applymanipulators(what,tfmdata,features,trace,report)
+ if features and next(features) then
+ local properties = tfmdata.properties
+ local whathandler = handlers[what]
+ local whatfeatures = whathandler.features
+ local whatmanipulators = whatfeatures.manipulators
+ local manipulators = whatmanipulators[properties.mode]
+ if manipulators then
+ for i=1,#manipulators do
+ local step = manipulators[i]
+ local feature = step.name
+ local value = features[feature]
+ if value then
+ local action = step.action
+ if trace then
+ report("applying feature manipulator %s for mode %s for font %s",feature,
+ mode or 'unknown', tfmdata.properties.fullname or 'unknown')
+ end
+ if action then
+ action(tfmdata,feature,value)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/tex/context/base/font-ctx.lua b/tex/context/base/font-ctx.lua
index 4a88d3527..9b1dc03ec 100644
--- a/tex/context/base/font-ctx.lua
+++ b/tex/context/base/font-ctx.lua
@@ -6,32 +6,45 @@ if not modules then modules = { } end modules ['font-ctx'] = {
license = "see context related readme files"
}
--- needs a cleanup: merge of replace, lang/script etc
+-- split in definition and specifiers (as these need to come before goodies)
-local texcount, texsetcount, write_nl = tex.count, tex.setcount, texio.write_nl
+local texcount, texsetcount = tex.count, tex.setcount
local format, gmatch, match, find, lower, gsub, byte = string.format, string.gmatch, string.match, string.find, string.lower, string.gsub, string.byte
-local concat, serialize = table.concat, table.serialize
+local concat, serialize, sort = table.concat, table.serialize, table.sort
local settings_to_hash, hash_to_string = utilities.parsers.settings_to_hash, utilities.parsers.hash_to_string
local formatcolumns = utilities.formatters.formatcolumns
local tostring, next, type = tostring, next, type
-local lpegmatch = lpeg.match
+local utfchar, utfbyte = utf.char, utf.byte
local round = math.round
-local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
-local trace_usage = false trackers.register("fonts.usage", function(v) trace_usage = v end)
-local trace_mapfiles = false trackers.register("fonts.mapfiles", function(v) trace_mapfiles = v end)
-
-local report_defining = logs.reporter("fonts","defining")
-local report_status = logs.reporter("fonts","status")
-local report_mapfiles = logs.reporter("fonts","mapfiles")
-
-local fonts = fonts
-local tfm = fonts.tfm
-local definers = fonts.definers
-local specifiers = definers.specifiers
-local currentfont = font.current
-local texattribute = tex.attribute
+local P, S, C, Cc, Cf, Cg, Ct, lpegmatch = lpeg.P, lpeg.S, lpeg.C, lpeg.Cc, lpeg.Cf, lpeg.Cg, lpeg.Ct, lpeg.match
+
+local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
+local trace_usage = false trackers.register("fonts.usage", function(v) trace_usage = v end)
+local trace_mapfiles = false trackers.register("fonts.mapfiles", function(v) trace_mapfiles = v end)
+local trace_automode = false trackers.register("fonts.automode", function(v) trace_automode = v end)
+
+local report_defining = logs.reporter("fonts","defining")
+local report_status = logs.reporter("fonts","status")
+local report_mapfiles = logs.reporter("fonts","mapfiles")
+
+local fonts = fonts
+local handlers = fonts.handlers
+local otf = handlers.otf -- brrr
+local names = fonts.names
+local definers = fonts.definers
+local specifiers = fonts.specifiers
+local constructors = fonts.constructors
+local loggers = fonts.loggers
+local helpers = fonts.helpers
+local hashes = fonts.hashes
+local fontdata = hashes.identifiers
+local currentfont = font.current
+local texattribute = tex.attribute
+
+local otffeatures = fonts.constructors.newfeatures("otf")
+local registerotffeature = otffeatures.register
specifiers.contextsetups = specifiers.contextsetups or { }
specifiers.contextnumbers = specifiers.contextnumbers or { }
@@ -43,49 +56,20 @@ local numbers = specifiers.contextnumbers
local merged = specifiers.contextmerged
local synonyms = specifiers.synonyms
-local triggers = fonts.triggers
-local names = fonts.names
+storage.register("fonts/setups" , setups , "fonts.specifiers.contextsetups" )
+storage.register("fonts/numbers", numbers, "fonts.specifiers.contextnumbers")
+storage.register("fonts/merged", merged, "fonts.specifiers.contextmerged")
+storage.register("fonts/synonyms", synonyms, "fonts.specifiers.synonyms")
-local allocate, mark = utilities.storage.allocate, utilities.storage.mark
+constructors.resolvevirtualtoo = true -- context specific (due to resolver)
-fonts.internalized = allocate() -- internal tex numbers
-
-fonts.characters = mark(fonts.characters or { }) -- chardata
-fonts.csnames = mark(fonts.csnames or { }) -- namedata
-fonts.quads = mark(fonts.quads or { }) -- quaddata
-fonts.xheights = mark(fonts.xheights or { }) -- xheightdata
-
-local fontdata = fonts.identifiers
-local chardata = fonts.characters
-local quaddata = fonts.quads
-local xheightdata = fonts.xheights
-
-fonts.ids = fontdata -- we keep this one for a while (as it is used in mk etc)
-
--- todo: give parameters at the lua end a metatable
-
---~ function parameters(t,k)
---~ local v = 0
---~ if k == "x_height" then v = t.xheight
---~ elseif k == "space_stretch" then v = t.spacestretch
---~ elseif k == "space_shrink" then v = t.spaceshrink
---~ elseif k == "extra_space" then v = t.extraspace
---~ elseif k == 1 then v = t.slant
---~ elseif k == 2 then v = t.space
---~ elseif k == 3 then v = t.spacestretch
---~ elseif k == 4 then v = t.spaceshrink
---~ elseif k == 5 then v = t.xheight
---~ elseif k == 6 then v = t.quad
---~ elseif k == 7 then v = t.extraspace
---~ end
---~ t[k] = v
---~ return v
---~ end
+local allocate, mark = utilities.storage.allocate, utilities.storage.mark
local nulldata = {
name = "nullfont",
characters = { },
descriptions = { },
+ properties = { },
parameters = { -- lmromanregular @ 12pt
slant = 0, -- 1
space = 256377, -- 2
@@ -99,14 +83,14 @@ local nulldata = {
function definers.resetnullfont()
-- resetting is needed because tikz misuses nullfont
- local p = nulldata.parameters
- p.slant = 0 -- 1
- p.space = 0 -- 2
- p.spacestretch = 0 -- 3
- p.spaceshrink = 0 -- 4
- p.xheight = 0 -- 5
- p.quad = 0 -- 6
- p.extraspace = 0 -- 7
+ local parameters = nulldata.parameters
+ parameters.slant = 0 -- 1
+ parameters.space = 0 -- 2
+ parameters.spacestretch = 0 -- 3
+ parameters.spaceshrink = 0 -- 4
+ parameters.xheight = 0 -- 5
+ parameters.quad = 0 -- 6
+ parameters.extraspace = 0 -- 7
definers.resetnullfont = function() end
end
@@ -114,75 +98,102 @@ setmetatablekey(fontdata, "__index", function(t,k)
return nulldata
end)
+local chardata = allocate() -- chardata
+local csnames = allocate() -- namedata
+local quaddata = allocate() -- quaddata
+local xheightdata = allocate() -- xheightdata
+
+hashes.characters = chardata
+hashes.quads = quaddata
+hashes.xheights = xheightdata
+
setmetatablekey(chardata, "__index", function(t,k)
local characters = fontdata[k].characters
- chardata[k] = characters
+ t[k] = characters
return characters
end)
setmetatablekey(quaddata, "__index", function(t,k)
local parameters = fontdata[k].parameters
local quad = parameters and parameters.quad or 0
- quaddata[k] = quad
+ t[k] = quad
return quad
end)
setmetatablekey(xheightdata, "__index", function(t,k)
local parameters = fontdata[k].parameters
local xheight = parameters and parameters.xheight or 0
- xheightdata[k] = xheight
+ t[k] = xheight
return quad
end)
--- local function enhancetfmdata(tfmdata)
--- local characters = tfmdata.characters
--- local parameters = tfmdata.parameters
--- local shared = tfmdata.shared
--- setmetatablekey(chardata, "__index", function(t,k)
--- if type(k) == "number" then
--- return characters[k]
--- else
--- -- t[k] = v -- can be option
--- return parameters[k] or shared[k]
--- end
--- return v
--- end)
--- end
-
--- Here we overload the registration code.
-
-function definers.registered(hash)
- local id = fonts.internalized[hash]
- return id, id and fontdata[id]
-end
-
-function definers.register(tfmdata,id)
- if tfmdata and id then
- local hash = tfmdata.hash
- if not fonts.internalized[hash] then
- fonts.internalized[hash] = id
- if trace_defining then
- report_defining("registering font, id: %s, hash: %s",id or "?",hash or "?")
+-- this cannot be a feature initializer as there is no auto namespace
+-- so we never enter the loop then
+
+local function modechecker(tfmdata,features) -- we cannot adapt features as they are shared!
+ local mode = features.mode
+ if mode == "auto" then
+ local script = features.script
+ local language = features.language
+ local rawdata = tfmdata.shared.rawdata
+ local sequences = rawdata and rawdata.resources.sequences
+ if script and language and sequences and #sequences > 0 then
+ for feature, value in next, features do
+ if value then
+ local found = false
+ for i=1,#sequences do
+ local features = sequences[i].features
+ if features then
+ local scripts = features[feature]
+ if scripts then
+ local languages = scripts[script]
+ if languages and languages[language] then
+ if found then
+ features.mode = "node"
+ if trace_automode then
+ report_defining("forcing node mode due to features %s, script %s, language %s",feature,script,language)
+ end
+ return "node"
+ else
+ found = true
+ end
+ end
+ end
+ end
+ end
+ end
end
- -- enhancetfmdata(tfmdata)
- local characters = tfmdata.characters
- local parameters = tfmdata.parameters
- fontdata[id] = tfmdata
- -- chardata [id] = characters
- -- quaddata [id] = parameters and parameters.quad or 0
- -- xheightdata[id] = parameters and parameters.xheight or 0
- --
- tfmdata.mathconstants = tfmdata.mathconstants or tfmdata.MathMonstants
- --
- parameters.xheight = parameters.xheight or parameters.x_height
- parameters.extraspace = parameters.extraspace or parameters.extra_space
- parameters.spacestretch = parameters.spacestretch or parameters.space_stretch
- parameters.spaceshrink = parameters.spaceshrink or parameters.space_shrink
end
+ return "base"
+ else
+ return mode
end
end
--- End of overload.
+registerotffeature {
+ -- we only set the checker and leave other settings of the mode
+ -- feature as they are
+ name = "mode",
+ modechecker = modechecker,
+}
+
+-- -- default = true anyway
+--
+-- local normalinitializer = constructors.getfeatureaction("otf","initializers","node","analyze")
+--
+-- local function analyzeinitializer(tfmdata,value,features) -- attr
+-- if value == "auto" and features then
+-- value = features.init or features.medi or features.fina or features.isol or false
+-- end
+-- return normalinitializer(tfmdata,value,features)
+-- end
+--
+-- registerotffeature {
+-- name = "analyze",
+-- initializers = {
+-- node = analyzeinitializer,
+-- },
+-- }
--[[ldx--
<p>So far we haven't really dealt with features (or whatever we want
@@ -197,25 +208,45 @@ name*context specification
</code>
--ldx]]--
+-- currently fonts are scaled while constructing the font, so we
+-- have to do scaling of commands in the vf at that point using e.g.
+-- "local scale = g.parameters.factor or 1" after all, we need to
+-- work with copies anyway and scaling needs to be done at some point;
+-- however, when virtual tricks are used as feature (makes more
+-- sense) we scale the commands in fonts.constructors.scale (and set the
+-- factor there)
+
+local loadfont = definers.loadfont
+
+function definers.loadfont(specification,size,id) -- overloads the one in font-def
+ local variants = definers.methods.variants
+ local virtualfeatures = specification.features.virtual
+ if virtualfeatures and virtualfeatures.preset then
+ local variant = variants[virtualfeatures.preset]
+ if variant then
+ return variant(specification,size,id)
+ end
+ else
+ local tfmdata = loadfont(specification,size,id)
+ -- constructors.checkvirtualid(tfmdata,id)
+ return tfmdata
+ end
+end
+
local function predefined(specification)
+ local variants = definers.methods.variants
local detail = specification.detail
- if detail ~= "" and definers.methods.variants[detail] then
- specification.features.vtf = { preset = detail }
+ if detail ~= "" and variants[detail] then
+ specification.features.virtual = { preset = detail }
end
return specification
end
definers.registersplit("@", predefined,"virtual")
-storage.register("fonts/setups" , setups , "fonts.definers.specifiers.contextsetups" )
-storage.register("fonts/numbers", numbers, "fonts.definers.specifiers.contextnumbers")
-storage.register("fonts/merged", merged, "fonts.definers.specifiers.contextmerged")
-storage.register("fonts/synonyms", synonyms, "fonts.definers.specifiers.synonyms")
-
-local normalize_meanings = fonts.otf.meanings.normalize
-local default_features = fonts.otf.features.default
+local normalize_features = otffeatures.normalize -- should be general
-local function presetcontext(name,parent,features) -- currently otf only
+local function presetcontext(name,parent,features) -- will go to con and shared
if features == "" and find(parent,"=") then
features = parent
parent = ""
@@ -223,9 +254,9 @@ local function presetcontext(name,parent,features) -- currently otf only
if features == "" then
features = { }
elseif type(features) == "string" then
- features = normalize_meanings(settings_to_hash(features))
+ features = normalize_features(settings_to_hash(features))
else
- features = normalize_meanings(features)
+ features = normalize_features(features)
end
-- todo: synonyms, and not otf bound
if parent ~= "" then
@@ -243,10 +274,18 @@ local function presetcontext(name,parent,features) -- currently otf only
-- these are auto set so in order to prevent redundant definitions
-- we need to preset them (we hash the features and adding a default
-- setting during initialization may result in a different hash)
- for k,v in next, triggers do
- if features[v] == nil then -- not false !
- local vv = default_features[v]
- if vv then features[v] = vv end
+--~ for k,v in next, triggers do
+--~ if features[v] == nil then -- not false !
+--~ local vv = default_features[v]
+--~ if vv then features[v] = vv end
+--~ end
+--~ end
+ for feature,value in next, features do
+ if value == nil then -- not false !
+ local default = default_features[feature]
+ if default ~= nil then
+ features[feature] = default
+ end
end
end
-- sparse 'm so that we get a better hash and less test (experimental
@@ -362,9 +401,30 @@ specifiers.contextnumber = contextnumber
specifiers.mergecontext = mergecontext
specifiers.registercontext = registercontext
+-- 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
+ 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
+
+-- end of redefine
+
local cache = { } -- concat might be less efficient than nested tables
-function fonts.withset(name,what)
+local function withset(name,what)
local zero = texattribute[0]
local hash = zero .. "+" .. name .. "*" .. what
local done = cache[hash]
@@ -375,7 +435,7 @@ function fonts.withset(name,what)
texattribute[0] = done
end
-function fonts.withfnt(name,what)
+local function withfnt(name,what)
local font = currentfont()
local hash = font .. "*" .. name .. "*" .. what
local done = cache[hash]
@@ -440,7 +500,7 @@ end
specifiers.splitcontext = splitcontext
function specifiers.contexttostring(name,kind,separator,yes,no,strict,omit) -- not used
- return hash_to_string(table.merged(fonts[kind].features.default or {},setups[name] or {}),separator,yes,no,strict,omit)
+ return hash_to_string(table.merged(handlers[kind].features.defaults or {},setups[name] or {}),separator,yes,no,strict,omit)
end
local function starred(features) -- no longer fallbacks here
@@ -455,9 +515,27 @@ end
definers.registersplit('*',starred,"featureset")
--- define (two steps)
+-- sort of xetex mode, but without [] and / as we have file: and name: etc
+
+local space = P(" ")
+local separator = S(";,")
+local equal = P("=")
+local spaces = space^0
+local sometext = C((1-equal-space-separator)^1)
+local truevalue = P("+") * spaces * sometext * Cc(true) -- "yes"
+local falsevalue = P("-") * spaces * sometext * Cc(false) -- "no"
+local keyvalue = sometext * spaces * equal * spaces * sometext
+local somevalue = sometext * spaces * Cc(true) -- "yes"
+local pattern = Cf(Ct("") * (space + separator + Cg(keyvalue + falsevalue + truevalue + somevalue))^0, rawset)
+
+local function colonized(specification)
+ specification.features.normal = normalize_features(lpegmatch(pattern,specification.specification))
+ return specification
+end
-local P, C, Cc = lpeg.P, lpeg.C, lpeg.Cc
+definers.registersplit(":",colonized,"direct")
+
+-- define (two steps)
local space = P(" ")
local spaces = space^0
@@ -475,7 +553,7 @@ local scale_scaled = P("scaled") * Cc(4) * spaces * dimension -- value
local sizepattern = spaces * (scale_at + scale_sa + scale_mo + scale_scaled + scale_none)
local splitpattern = spaces * value * spaces * rest
-local specification --
+local specification -- still needed as local ?
local getspecification = definers.getspecification
@@ -564,7 +642,7 @@ function definers.stage_two(global,cs,str,size,classfeatures,fontfeatures,classf
local tfmdata = definers.read(specification,size) -- id not yet known
local cs = specification.cs
if cs then
- fonts.csnames[cs] = tfmdata -- new (beware: locals can be forgotten)
+ csnames[cs] = tfmdata -- new (beware: locals can be forgotten)
end
if not tfmdata then
report_defining("unable to define %s as \\%s",name,cs)
@@ -577,21 +655,22 @@ function definers.stage_two(global,cs,str,size,classfeatures,fontfeatures,classf
end
tex.definefont(global,cs,tfmdata)
-- resolved (when designsize is used):
- setsomefontsize(fontdata[tfmdata].size .. "sp")
+ setsomefontsize(fontdata[tfmdata].parameters.size .. "sp")
texsetcount("global","lastfontid",tfmdata)
else
-- local t = os.clock(t)
local id = font.define(tfmdata)
-- print(name,os.clock()-t)
- tfmdata.id = id
+ tfmdata.properties.id = id
definers.register(tfmdata,id) -- to be sure, normally already done
tex.definefont(global,cs,id)
- tfm.cleanuptable(tfmdata)
+ constructors.cleanuptable(tfmdata)
+ constructors.finalize(tfmdata)
if trace_defining then
report_defining("defining %s with id %s as \\%s (features: %s/%s, fallbacks: %s/%s)",name,id,cs,classfeatures,fontfeatures,classfallbacks,fontfallbacks)
end
-- resolved (when designsize is used):
- setsomefontsize((tfmdata.size or 655360) .. "sp")
+ setsomefontsize((tfmdata.parameters.size or 655360) .. "sp")
--~ if specification.fallbacks then
--~ fonts.collections.prepare(specification.fallbacks)
--~ end
@@ -647,12 +726,13 @@ function definers.define(specification)
return tfmdata, fontdata[tfmdata]
else
local id = font.define(tfmdata)
- tfmdata.id = id
+ tfmdata.properties.id = id
definers.register(tfmdata,id)
if specification.cs then
tex.definefont(specification.global,specification.cs,id)
end
- tfm.cleanuptable(tfmdata)
+ constructors.cleanuptable(tfmdata)
+ constructors.finalize(tfmdata)
return id, tfmdata
end
statistics.stoptiming(fonts)
@@ -665,94 +745,32 @@ experiments.register("fonts.autorscale", function(v)
enable_auto_r_scale = v
end)
-local calculatescale = fonts.tfm.calculatescale
-
-- Not ok, we can best use a database for this. The problem is that we
-- have delayed definitions and so we never know what style is taken
-- as start.
-function fonts.tfm.calculatescale(tfmtable, scaledpoints, relativeid)
- local scaledpoints, delta, units = calculatescale(tfmtable,scaledpoints)
+local calculatescale = constructors.calculatescale
+
+function constructors.calculatescale(tfmdata,scaledpoints,relativeid)
+ local scaledpoints, delta = calculatescale(tfmdata,scaledpoints)
--~ if enable_auto_r_scale and relativeid then -- for the moment this is rather context specific
--~ local relativedata = fontdata[relativeid]
---~ local rfmtable = relativedata and relativedata.unscaled and relativedata.unscaled
---~ local id_x_height = rfmtable and rfmtable.parameters and rfmtable.parameters.x_height
---~ local tf_x_height = tfmtable and tfmtable.parameters and tfmtable.parameters.x_height
+--~ local rfmdata = relativedata and relativedata.unscaled and relativedata.unscaled
+--~ local id_x_height = rfmdata and rfmdata.parameters and rfmdata.parameters.x_height
+--~ local tf_x_height = tfmdata and tfmdata.parameters and tfmdata.parameters.x_height
--~ if id_x_height and tf_x_height then
--~ local rscale = id_x_height/tf_x_height
--~ delta = rscale * delta
--~ scaledpoints = rscale * scaledpoints
--~ end
--~ end
- return scaledpoints, delta, units
+ return scaledpoints, delta
end
---~ table.insert(readers.sequence,1,'vtf')
-
---~ function readers.vtf(specification)
---~ if specification.features.vtf and specification.features.vtf.preset then
---~ return tfm.make(specification)
---~ else
---~ return nil
---~ end
---~ end
-
--- we need a place for this .. outside the generic scope
-
-local dimenfactors = number.dimenfactors
-
-function fonts.dimenfactor(unit,tfmdata)
- if unit == "ex" then
- return (tfmdata and tfmdata.parameters.x_height) or 655360
- elseif unit == "em" then
- return (tfmdata and tfmdata.parameters.em_height) or 655360
- else
- return dimenfactors[unit] or unit
- end
-end
-
-function fonts.cleanname(name)
- context(names.cleanname(name))
-end
-
-local p, f = 1, "%0.1fpt" -- normally this value is changed only once
-
-local stripper = lpeg.patterns.stripzeros
-
-function fonts.nbfs(amount,precision)
- if precision ~= p then
- p = precision
- f = "%0." .. p .. "fpt"
- end
- context(lpegmatch(stripper,format(f,amount/65536)))
-end
-
--- for the moment here, this will become a chain of extras that is
--- hooked into the ctx registration (or scaler or ...)
-
-local function digitwidth(font) -- max(quad/2,wd(0..9))
- local tfmtable = fontdata[font]
- local parameters = tfmtable.parameters
- local width = parameters.digitwidth
- if not width then
- width = round(parameters.quad/2) -- maybe tex.scale
- local characters = tfmtable.characters
- for i=48,57 do
- local wd = round(characters[i].width)
- if wd > width then
- width = wd
- end
- end
- parameters.digitwidth = width
- end
- return width
-end
-
-fonts.getdigitwidth = digitwidth
-fonts.setdigitwidth = digitwidth
-
-- soon to be obsolete:
+local mappings = fonts.mappings
+
local loaded = { -- prevent loading (happens in cont-sys files)
["original-base.map" ] = true,
["original-ams-base.map" ] = true,
@@ -760,7 +778,7 @@ local loaded = { -- prevent loading (happens in cont-sys files)
["original-public-lm.map"] = true,
}
-function fonts.map.loadfile(name)
+function mappings.loadfile(name)
name = file.addsuffix(name,"map")
if not loaded[name] then
if trace_mapfiles then
@@ -774,7 +792,7 @@ end
local loaded = { -- prevent double loading
}
-function fonts.map.loadline(how,line)
+function mappings.loadline(how,line)
if line then
how = how .. " " .. line
elseif how == "" then
@@ -789,109 +807,49 @@ function fonts.map.loadline(how,line)
end
end
-function fonts.map.reset()
+function mappings.reset()
pdf.mapfile("")
end
-fonts.map.reset() -- resets the default file
+mappings.reset() -- resets the default file
-- we need an 'do after the banner hook'
--- pdf.mapfile("mkiv-base.map") -- loads the default file
-
-local nounicode = byte("?")
-
-local function nametoslot(name,all) -- maybe some day rawdata
- local tfmdata = fontdata[currentfont()]
- local shared = tfmdata and tfmdata.shared
- local fntdata = shared and (shared.otfdata or shared.afmdata)
- if fntdata then
- local unicode = fntdata.luatex.unicodes[name]
- if not unicode then
- return nounicode
- elseif type(unicode) == "number" then
- return unicode
- elseif all then
- return unicode
- else
- return unicode[1]
- end
- end
- return nounicode
-end
-
-fonts.nametoslot = nametoslot
-
-function fonts.char(n,all) -- todo: afm en tfm
- if type(n) == "string" then
- n = nametoslot(n,all)
- end
- -- if type(n) == "number" then
- if n then
- context.char(n)
+-- => commands
+
+function nametoslot(name)
+ local t = type(name)
+ if t == "string" then
+ local tfmdata = fonts.hashes.identifiers[currentfont()]
+ local shared = tfmdata and tfmdata.shared
+ local fntdata = shared and shared.rawdata
+ return fntdata and fntdata.resources.unicodes[name]
+ elseif t == "number" then
+ return n
end
end
--- this will become obsolete:
-
-fonts.otf.nametoslot = nametoslot
-fonts.afm.nametoslot = nametoslot
-
-fonts.otf.char = fonts.char
-fonts.afm.char = fonts.char
+helpers.nametoslot = nametoslot
-- this will change ...
-function fonts.showchardata(n)
- local tfmdata = fontdata[currentfont()]
- if tfmdata then
- if type(n) == "string" then
- n = utf.byte(n)
- end
- local chr = tfmdata.characters[n]
- if chr then
- write_nl(format("%s @ %s => U%04X => %s => ",tfmdata.fullname,tfmdata.size,n,utf.char(n)) .. serialize(chr,false))
- end
- end
-end
-
-function fonts.showfontparameters()
- local tfmdata = fontdata[currentfont()]
- if tfmdata then
- local parameters, mathconstants = tfmdata.parameters, tfmdata.MathConstants
- local hasparameters, hasmathconstants = parameters and next(parameters), mathconstants and next(mathconstants)
- if hasparameters then
- write_nl(format("%s @ %s => parameters => ",tfmdata.fullname,tfmdata.size) .. serialize(parameters,false))
- end
- if hasmathconstants then
- write_nl(format("%s @ %s => math constants => ",tfmdata.fullname,tfmdata.size) .. serialize(mathconstants,false))
- end
- if not hasparameters and not hasmathconstants then
- write_nl(format("%s @ %s => no parameters and/or mathconstants",tfmdata.fullname,tfmdata.size))
- end
- end
-end
-
-function fonts.reportdefinedfonts()
+function loggers.reportdefinedfonts()
if trace_usage then
local t, tn = { }, 0
for id, data in table.sortedhash(fontdata) do
+ local properties = data.properties or { }
+ local parameters = data.parameters or { }
tn = tn + 1
t[tn] = {
- format("%03i",id),
- format("%09i",data.size or 0),
- data.type or "real",
- (data.mode or "base") .. "mode",
- data.auto_expand and "expanded" or "",
- data.auto_protrude and "protruded" or "",
- data.has_math and "math" or "",
- data.extend_factor and "extended" or "",
- data.slant_factor and "slanted" or "",
- data.name or "",
- data.psname or "",
- data.fullname or "",
- data.hash or "",
+ format("%03i",id or 0),
+ format("%09i",parameters.size or 0),
+ properties.type or "real",
+ properties.format or "unknown",
+ properties.name or "",
+ properties.psname or "",
+ properties.fullname or "",
}
+report_status("%s: %s",properties.name,concat(table.sortedkeys(data)," "))
end
formatcolumns(t," ")
report_status()
@@ -903,9 +861,9 @@ function fonts.reportdefinedfonts()
end
end
-luatex.registerstopactions(fonts.reportdefinedfonts)
+luatex.registerstopactions(loggers.reportdefinedfonts)
-function fonts.reportusedfeatures()
+function loggers.reportusedfeatures()
-- numbers, setups, merged
if trace_usage then
local t, n = { }, #numbers
@@ -927,7 +885,11 @@ function fonts.reportusedfeatures()
end
end
-luatex.registerstopactions(fonts.reportusedfeatures)
+luatex.registerstopactions(loggers.reportusedfeatures)
+
+statistics.register("fonts load time", function()
+ return statistics.elapsedseconds(fonts)
+end)
-- experimental mechanism for Mojca:
--
@@ -997,11 +959,255 @@ end
-- interfaces
+function commands.fontchar(n)
+ n = nametoslot(n)
+ if n then
+ context.char(n)
+ end
+end
+
function commands.doifelsecurrentfonthasfeature(name) -- can be made faster with a supportedfeatures hash
local f = fontdata[currentfont()]
f = f and f.shared
- f = f and f.otfdata
- f = f and f.luatex
+ f = f and f.rawdata
+ f = f and f.resources
f = f and f.features
commands.doifelse(f and (f.gpos[name] or f.gsub[name]))
end
+
+local p, f = 1, "%0.1fpt" -- normally this value is changed only once
+
+local stripper = lpeg.patterns.stripzeros
+
+function commands.nbfs(amount,precision)
+ if precision ~= p then
+ p = precision
+ f = "%0." .. p .. "fpt"
+ end
+ context(lpegmatch(stripper,format(f,amount/65536)))
+end
+
+function commands.featureattribute(tag)
+ tex.write(contextnumber(tag))
+end
+
+function commands.setfontfeature(tag)
+ texattribute[0] = contextnumber(tag)
+end
+
+function commands.resetfontfeature()
+ texattribute[0] = 0
+end
+
+function commands.addfs(tag) withset(tag, 1) end
+function commands.subfs(tag) withset(tag,-1) end
+function commands.addff(tag) withfnt(tag, 2) end
+function commands.subff(tag) withfnt(tag,-2) end
+
+-- function commands.addfontfeaturetoset (tag) withset(tag, 1) end
+-- function commands.subtractfontfeaturefromset (tag) withset(tag,-1) end
+-- function commands.addfontfeaturetofont (tag) withfnt(tag, 2) end
+-- function commands.subtractfontfeaturefromfont(tag) withfnt(tag,-2) end
+
+function commands.cleanfontname (name) context(names.cleanname(name)) end
+
+function commands.fontlookupinitialize (name) names.lookup(name) end
+function commands.fontlookupnoffound () context(names.noflookups()) end
+function commands.fontlookupgetkeyofindex(key,index) context(names.getlookupkey(key,index)) end
+function commands.fontlookupgetkey (key) context(names.getlookupkey(key)) end
+
+-- this might move to a runtime module:
+
+function commands.showchardata(n)
+ local tfmdata = fontdata[currentfont()]
+ if tfmdata then
+ if type(n) == "string" then
+ n = utfbyte(n)
+ end
+ local chr = tfmdata.characters[n]
+ if chr then
+ report_status("%s @ %s => U%04X => %s => %s",tfmdata.properties.fullname,tfmdata.parameters.size,n,utfchar(n),serialize(chr,false))
+ end
+ end
+end
+
+function commands.showfontparameters()
+ local tfmdata = fontdata[currentfont()]
+ if tfmdata then
+ local parameters = tfmdata.parameters
+ local mathconstants = tfmdata.MathConstants
+ local properties = tfmdata.properties
+ local hasparameters = parameters and next(parameters)
+ local hasmathconstants = mathconstants and next(mathconstants)
+ if hasparameters then
+ report_status("%s @ %s => parameters => %s",properties.fullname,parameters.size,serialize(parameters,false))
+ end
+ if hasmathconstants then
+ report_status("%s @ %s => math constants => %s",properties.fullname,parameters.size,serialize(mathconstants,false))
+ end
+ if not hasparameters and not hasmathconstants then
+ report_status("%s @ %s => no parameters and/or mathconstants",properties.fullname,parameters.size)
+ end
+ end
+end
+
+-- for the moment here, this will become a chain of extras that is
+-- hooked into the ctx registration (or scaler or ...)
+
+local dimenfactors = number.dimenfactors
+
+function helpers.dimenfactor(unit,tfmdata) -- could be a method of a font instance
+ if unit == "ex" then
+ return (tfmdata and tfmdata.parameters.x_height) or 655360
+ elseif unit == "em" then
+ return (tfmdata and tfmdata.parameters.em_width) or 655360
+ else
+ return dimenfactors[unit] or unit
+ end
+end
+
+local function digitwidth(font) -- max(quad/2,wd(0..9))
+ local tfmdata = fontdata[font]
+ local parameters = tfmdata.parameters
+ local width = parameters.digitwidth
+ if not width then
+ width = round(parameters.quad/2) -- maybe tex.scale
+ local characters = tfmdata.characters
+ for i=48,57 do
+ local wd = round(characters[i].width)
+ if wd > width then
+ width = wd
+ end
+ end
+ parameters.digitwidth = width
+ end
+ return width
+end
+
+helpers.getdigitwidth = digitwidth
+helpers.setdigitwidth = digitwidth
+
+--
+
+function helpers.getparameters(tfmdata)
+ local p = { }
+ local m = p
+ local parameters = tfmdata.parameters
+ while true do
+ for k, v in next, parameters do
+ m[k] = v
+ end
+ parameters = getmetatable(parameters)
+ parameters = parameters and parameters.__index
+ if type(parameters) == "table" then
+ m = { }
+ p.metatable = m
+ else
+ break
+ end
+ end
+ return p
+end
+
+if environment.initex then
+
+ local function names(t)
+ local nt = #t
+ if nt > 0 then
+ local n = { }
+ for i=1,nt do
+ n[i] = t[i].name
+ end
+ return concat(n," ")
+ else
+ return "-"
+ end
+ end
+
+ statistics.register("font processing", function()
+ local l = { }
+ for what, handler in table.sortedpairs(handlers) do
+ local features = handler.features
+ if features then
+ local t = { }
+ t[#t+1] = "["
+ t[#t+1] = what
+ t[#t+1] = format("(base initializers: %s)",names(features.initializers.base))
+ t[#t+1] = format("(base processors: %s)", names(features.processors .base))
+ t[#t+1] = format("(base manipulators: %s)",names(features.manipulators.base))
+ t[#t+1] = format("(node initializers: %s)",names(features.initializers.node))
+ t[#t+1] = format("(node processors: %s)", names(features.processors .node))
+ t[#t+1] = format("(node manipulators: %s)",names(features.manipulators.node))
+ t[#t+1] = "]"
+ l[#l+1] = concat(t, " ")
+ end
+ end
+ return concat(l, " | ")
+ end)
+
+end
+
+-- redefinition
+
+local quads = hashes.quads
+local xheights = hashes.xheights
+local currentfont = font.current
+local texdimen = tex.dimen
+
+setmetatable(number.dimenfactors, {
+ __index = function(t,k)
+ if k == "ex" then
+ return xheigths[currentfont()]
+ elseif k == "em" then
+ return quads[currentfont()]
+ elseif k == "%" then
+ return dimen.hsize/100
+ else
+ -- error("wrong dimension: " .. (s or "?")) -- better a message
+ return false
+ end
+ end
+} )
+
+--[[ldx--
+<p>Before a font is passed to <l n='tex'/> we scale it. Here we also need
+to scale virtual characters.</p>
+--ldx]]--
+
+-- function constructors.getvirtualid(tfmdata)
+-- -- since we don't know the id yet, we use 0 as signal
+-- local tf = tfmdata.fonts
+-- if not tf then
+-- local properties = tfmdata.properties
+-- if properties then
+-- properties.virtualized = true
+-- else
+-- tfmdata.properties = { virtualized = true }
+-- end
+-- tf = { }
+-- tfmdata.fonts = tf
+-- end
+-- local ntf = #tf + 1
+-- tf[ntf] = { id = 0 }
+-- return ntf
+-- end
+--
+-- function constructors.checkvirtualid(tfmdata, id) -- will go
+-- local properties = tfmdata.properties
+-- if tfmdata and tfmdata.type == "virtual" or (properties and properties.virtualized) then
+-- local vfonts = tfmdata.fonts
+-- if not vffonts or #vfonts == 0 then
+-- if properties then
+-- properties.virtualized = false
+-- end
+-- tfmdata.fonts = nil
+-- else
+-- for f=1,#vfonts do
+-- local fnt = vfonts[f]
+-- if fnt.id and fnt.id == 0 then
+-- fnt.id = id
+-- end
+-- end
+-- end
+-- end
+-- end
diff --git a/tex/context/base/font-def.lua b/tex/context/base/font-def.lua
index 3a09b6664..ec9a059df 100644
--- a/tex/context/base/font-def.lua
+++ b/tex/context/base/font-def.lua
@@ -27,44 +27,32 @@ default loader that only handles <l n='tfm'/>.</p>
--ldx]]--
local fonts = fonts
-local tfm = fonts.tfm
-local vf = fonts.vf
-
-fonts.used = allocate()
-
-tfm.readers = tfm.readers or { }
-tfm.fonts = allocate()
-
-local readers = tfm.readers
-local sequence = allocate { 'otf', 'ttf', 'afm', 'tfm', 'lua' }
-readers.sequence = sequence
-
-tfm.version = 1.01
-tfm.cache = containers.define("fonts", "tfm", tfm.version, false) -- better in font-tfm
-tfm.autoprefixedafm = true -- this will become false some day (catches texnansi-blabla.*)
-
-fonts.definers = fonts.definers or { }
+local fontdata = fonts.hashes.identifiers
+local readers = fonts.readers
local definers = fonts.definers
+local specifiers = fonts.specifiers
+local constructors = fonts.constructors
-definers.specifiers = definers.specifiers or { }
-local specifiers = definers.specifiers
+readers.sequence = allocate { 'otf', 'ttf', 'afm', 'tfm', 'lua' } -- dfont ttc
-specifiers.variants = allocate()
-local variants = specifiers.variants
+local variants = allocate()
+specifiers.variants = variants
-definers.method = "afm or tfm" -- afm, tfm, afm or tfm, tfm or afm
definers.methods = definers.methods or { }
-local findbinfile = resolvers.findbinfile
+local internalized = allocate() -- internal tex numbers (private)
+
+
+local loadedfonts = constructors.loadedfonts
+local designsizes = constructors.designsizes
--[[ldx--
<p>We hardly gain anything when we cache the final (pre scaled)
-<l n='tfm'/> table. But it can be handy for debugging.</p>
+<l n='tfm'/> table. But it can be handy for debugging, so we no
+longer carry this code along. Also, we now have quite some reference
+to other tables so we would end up with lots of catches.</p>
--ldx]]--
-fonts.version = 1.05
-fonts.cache = containers.define("fonts", "def", fonts.version, false)
-
--[[ldx--
<p>We can prefix a font specification by <type>name:</type> or
<type>file:</type>. The first case will result in a lookup in the
@@ -163,84 +151,6 @@ function definers.analyze(specification, size)
end
--[[ldx--
-<p>A unique hash value is generated by:</p>
---ldx]]--
-
-local sortedhashkeys = table.sortedhashkeys
-
-function tfm.hashfeatures(specification)
- local features = specification.features
- if features then
- local t, tn = { }, 0
- local normal = features.normal
- if normal and next(normal) then
- local f = sortedhashkeys(normal)
- for i=1,#f do
- local v = f[i]
- if v ~= "number" and v ~= "features" then -- i need to figure this out, features
- tn = tn + 1
- t[tn] = v .. '=' .. tostring(normal[v])
- end
- end
- end
- local vtf = features.vtf
- if vtf and next(vtf) then
- local f = sortedhashkeys(vtf)
- for i=1,#f do
- local v = f[i]
- tn = tn + 1
- t[tn] = v .. '=' .. tostring(vtf[v])
- end
- end
- -- if specification.mathsize then
- -- tn = tn + 1
- -- t[tn] = "mathsize=" .. specification.mathsize
- -- end
- if tn > 0 then
- return concat(t,"+")
- end
- end
- return "unknown"
-end
-
-fonts.designsizes = allocate()
-
---[[ldx--
-<p>In principle we can share tfm tables when we are in node for a font, but then
-we need to define a font switch as an id/attr switch which is no fun, so in that
-case users can best use dynamic features ... so, we will not use that speedup. Okay,
-when we get rid of base mode we can optimize even further by sharing, but then we
-loose our testcases for <l n='luatex'/>.</p>
---ldx]]--
-
-function tfm.hashinstance(specification,force)
- local hash, size, fallbacks = specification.hash, specification.size, specification.fallbacks
- if force or not hash then
- hash = tfm.hashfeatures(specification)
- specification.hash = hash
- end
- if size < 1000 and fonts.designsizes[hash] then
- size = math.round(tfm.scaled(size,fonts.designsizes[hash]))
- specification.size = size
- end
- -- local mathsize = specification.mathsize or 0
- -- if mathsize > 0 then
- -- local textsize = specification.textsize
- -- if fallbacks then
- -- return hash .. ' @ ' .. tostring(size) .. ' [ ' .. tostring(mathsize) .. ' : ' .. tostring(textsize) .. ' ] @ ' .. fallbacks
- -- else
- -- return hash .. ' @ ' .. tostring(size) .. ' [ ' .. tostring(mathsize) .. ' : ' .. tostring(textsize) .. ' ]'
- -- end
- -- else
- if fallbacks then
- return hash .. ' @ ' .. tostring(size) .. ' @ ' .. fallbacks
- else
- return hash .. ' @ ' .. tostring(size)
- end
- -- end
-end
-
---[[ldx--
<p>We can resolve the filename using the next function:</p>
--ldx]]--
@@ -310,7 +220,7 @@ function definers.resolve(specification)
end
end
--
- specification.hash = lower(specification.name .. ' @ ' .. tfm.hashfeatures(specification))
+ specification.hash = lower(specification.name .. ' @ ' .. constructors.hashfeatures(specification))
if specification.sub and specification.sub ~= "" then
specification.hash = specification.sub .. ' @ ' .. specification.hash
end
@@ -333,26 +243,48 @@ features (esp in virtual fonts) so let's not do that now.</p>
specification yet.</p>
--ldx]]--
-function tfm.read(specification)
- local hash = tfm.hashinstance(specification)
- local tfmtable = tfm.fonts[hash] -- hashes by size !
- if not tfmtable then
+-- not in context, at least not now:
+--
+-- function definers.applypostprocessors(tfmdata)
+-- local postprocessors = tfmdata.postprocessors
+-- if postprocessors then
+-- for i=1,#postprocessors do
+-- local extrahash = postprocessors[i](tfmdata) -- after scaling etc
+-- if type(extrahash) == "string" and extrahash ~= "" then
+-- -- e.g. a reencoding needs this
+-- extrahash = gsub(lower(extrahash),"[^a-z]","-")
+-- tfmdata.properties.fullname = format("%s-%s",tfmdata.properties.fullname,extrahash)
+-- end
+-- end
+-- end
+-- return tfmdata
+-- end
+
+function definers.applypostprocessors(tfmdata)
+ return tfmdata
+end
+
+function definers.loadfont(specification)
+ local hash = constructors.hashinstance(specification)
+ local tfmdata = loadedfonts[hash] -- hashes by size !
+ if not tfmdata then
local forced = specification.forced or ""
if forced ~= "" then
local reader = readers[lower(forced)]
- tfmtable = reader and reader(specification)
- if not tfmtable then
+ tfmdata = reader and reader(specification)
+ if not tfmdata then
report_defining("forced type %s of %s not found",forced,specification.name)
end
else
- for s=1,#sequence do -- reader sequence
+ local sequence = readers.sequence -- can be overloaded so only a shortcut here
+ for s=1,#sequence do
local reader = sequence[s]
- if readers[reader] then -- not really needed
+ if readers[reader] then -- we skip not loaded readers
if trace_defining then
report_defining("trying (reader sequence driven) type %s for %s with file %s",reader,specification.name,specification.filename or "unknown")
end
- tfmtable = readers[reader](specification)
- if tfmtable then
+ tfmdata = readers[reader](specification)
+ if tfmdata then
break
else
specification.filename = nil
@@ -360,82 +292,56 @@ function tfm.read(specification)
end
end
end
- if tfmtable then
+ if tfmdata then
+ local properties = tfmdata.properties
+ local embedding
if directive_embedall then
- tfmtable.embedding = "full"
- elseif tfmtable.filename and fonts.dontembed[tfmtable.filename] then
- tfmtable.embedding = "no"
+ embedding = "full"
+ elseif properties.filename and constructors.dontembed[properties.filename] then
+ embedding = "no"
else
- tfmtable.embedding = "subset"
+ embedding = "subset"
end
- -- fonts.goodies.postprocessors.apply(tfmdata) -- only here
- local postprocessors = tfmtable.postprocessors
- if postprocessors then
- for i=1,#postprocessors do
- local extrahash = postprocessors[i](tfmtable) -- after scaling etc
- if type(extrahash) == "string" and extrahash ~= "" then
- -- e.g. a reencoding needs this
- extrahash = gsub(lower(extrahash),"[^a-z]","-")
- tfmtable.fullname = format("%s-%s",tfmtable.fullname,extrahash)
- end
- end
+ if properties then
+ properties.embedding = embedding
+ else
+ tfmdata.properties = { embedding = embedding }
end
- --
- tfm.fonts[hash] = tfmtable
- fonts.designsizes[specification.hash] = tfmtable.designsize -- we only know this for sure after loading once
- --~ tfmtable.mode = specification.features.normal.mode or "base"
+ tfmdata = definers.applypostprocessors(tfmdata)
+ loadedfonts[hash] = tfmdata
+ designsizes[specification.hash] = tfmdata.parameters.designsize
end
end
- if not tfmtable then
+ if not tfmdata then
report_defining("font with asked name '%s' is not found using lookup '%s'",specification.name,specification.lookup)
end
- return tfmtable
+ return tfmdata
end
--[[ldx--
<p>For virtual fonts we need a slightly different approach:</p>
--ldx]]--
-function tfm.readanddefine(name,size) -- no id
+function constructors.readanddefine(name,size) -- no id -- maybe a dummy first
local specification = definers.analyze(name,size)
local method = specification.method
if method and variants[method] then
specification = variants[method](specification)
end
specification = definers.resolve(specification)
- local hash = tfm.hashinstance(specification)
+ local hash = constructors.hashinstance(specification)
local id = definers.registered(hash)
if not id then
- local tfmdata = tfm.read(specification)
+ local tfmdata = definers.loadfont(specification)
if tfmdata then
- tfmdata.hash = hash
+ tfmdata.properties.hash = hash
id = font.define(tfmdata)
definers.register(tfmdata,id)
- tfm.cleanuptable(tfmdata)
else
id = 0 -- signal
end
end
- return fonts.identifiers[id], id
-end
-
---[[ldx--
-<p>We need to check for default features. For this we provide
-a helper function.</p>
---ldx]]--
-
-function definers.check(features,defaults) -- nb adapts features !
- local done = false
- if features and next(features) then
- for k,v in next, defaults do
- if features[k] == nil then
- features[k], done = v, true
- end
- end
- else
- features, done = table.fastcopy(defaults), true
- end
- return features, done -- done signals a change
+ return fontdata[id], id
end
--[[ldx--
@@ -457,42 +363,24 @@ function definers.current() -- or maybe current
return lastdefined
end
-function definers.register(tfmdata,id) -- will be overloaded
+function definers.registered(hash)
+ local id = internalized[hash]
+ return id, id and fontdata[id]
+end
+
+function definers.register(tfmdata,id)
if tfmdata and id then
- local hash = tfmdata.hash
+ local hash = tfmdata.properties.hash
if not internalized[hash] then
+ internalized[hash] = id
if trace_defining then
report_defining("registering font, id: %s, hash: %s",id or "?",hash or "?")
end
- fonts.identifiers[id] = tfmdata
- internalized[hash] = id
+ fontdata[id] = tfmdata
end
end
end
-function definers.registered(hash) -- will be overloaded
- local id = internalized[hash]
- return id, id and fonts.identifiers[id]
-end
-
-local cache_them = false
-
-function tfm.make(specification)
- -- currently fonts are scaled while constructing the font, so we
- -- have to do scaling of commands in the vf at that point using
- -- e.g. "local scale = g.factor or 1" after all, we need to work
- -- with copies anyway and scaling needs to be done at some point;
- -- however, when virtual tricks are used as feature (makes more
- -- sense) we scale the commands in fonts.tfm.scale (and set the
- -- factor there)
- local fvm = definers.methods.variants[specification.features.vtf.preset]
- if fvm then
- return fvm(specification)
- else
- return nil
- end
-end
-
function definers.read(specification,size,id) -- id can be optional, name can already be table
statistics.starttiming(fonts)
if type(specification) == "string" then
@@ -503,26 +391,13 @@ function definers.read(specification,size,id) -- id can be optional, name can al
specification = variants[method](specification)
end
specification = definers.resolve(specification)
- local hash = tfm.hashinstance(specification)
- if cache_them then
- local tfmdata = containers.read(fonts.cache,hash) -- for tracing purposes
- end
+ local hash = constructors.hashinstance(specification)
local tfmdata = definers.registered(hash) -- id
if not tfmdata then
- if specification.features.vtf and specification.features.vtf.preset then
- tfmdata = tfm.make(specification)
- else
- tfmdata = tfm.read(specification)
- if tfmdata then
- tfm.checkvirtualid(tfmdata)
- end
- end
- if cache_them then
- tfmdata = containers.write(fonts.cache,hash,tfmdata) -- for tracing purposes
- end
+ tfmdata = definers.loadfont(specification) -- can be overloaded
if tfmdata then
- tfmdata.hash = hash
- tfmdata.cache = "no"
+--~ constructors.checkvirtualid(tfmdata) -- interferes
+ tfmdata.properties.hash = hash
if id then
definers.register(tfmdata,id)
end
@@ -532,46 +407,25 @@ function definers.read(specification,size,id) -- id can be optional, name can al
if not tfmdata then -- or id?
report_defining( "unknown font %s, loading aborted",specification.name)
elseif trace_defining and type(tfmdata) == "table" then
+ constructors.finalize(tfmdata)
+ -- local properties = tfmdata.properties or { }
+ -- local parameters = tfmdata.parameters or { }
report_defining("using %s font with id %s, name:%s size:%s bytes:%s encoding:%s fullname:%s filename:%s",
- tfmdata.type or "unknown",
- id or "?",
- tfmdata.name or "?",
- tfmdata.size or "default",
- tfmdata.encodingbytes or "?",
- tfmdata.encodingname or "unicode",
- tfmdata.fullname or "?",
- file.basename(tfmdata.filename or "?"))
+ properties.type or "unknown",
+ id or "?",
+ properties.name or "?",
+ parameters.size or "default",
+ properties.encodingbytes or "?",
+ properties.encodingname or "unicode",
+ properties.fullname or "?",
+ file.basename(properties.filename or "?"))
end
statistics.stoptiming(fonts)
return tfmdata
end
-function vf.find(name)
- name = file.removesuffix(file.basename(name))
- if tfm.resolvevirtualtoo then
- local format = fonts.logger.format(name)
- if format == 'tfm' or format == 'ofm' then
- if trace_defining then
- report_defining("locating vf for %s",name)
- end
- return findbinfile(name,"ovf")
- else
- if trace_defining then
- report_defining("vf for %s is already taken care of",name)
- end
- return nil -- ""
- end
- else
- if trace_defining then
- report_defining("locating vf for %s",name)
- end
- return findbinfile(name,"ovf")
- end
-end
-
--[[ldx--
-<p>We overload both the <l n='tfm'/> and <l n='vf'/> readers.</p>
+<p>We overload the <l n='tfm'/> reader.</p>
--ldx]]--
-callbacks.register('define_font' , definers.read, "definition of fonts (tfmtable preparation)")
-callbacks.register('find_vf_file', vf.find, "locating virtual fonts, insofar needed") -- not that relevant any more
+callbacks.register('define_font' , definers.read, "definition of fonts (tfmdata preparation)")
diff --git a/tex/context/base/font-dum.lua b/tex/context/base/font-dum.lua
deleted file mode 100644
index 54b631d55..000000000
--- a/tex/context/base/font-dum.lua
+++ /dev/null
@@ -1,354 +0,0 @@
-if not modules then modules = { } end modules ['font-dum'] = {
- version = 1.001,
- comment = "companion to luatex-*.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-fonts = fonts or { }
-
--- general
-
-fonts.otf.pack = false -- only makes sense in context
-fonts.tfm.resolvevirtualtoo = false -- context specific (due to resolver)
-fonts.tfm.fontnamemode = "specification" -- somehow latex needs this (changed name!)
-
--- readers
-
-fonts.tfm.readers = fonts.tfm.readers or { }
-fonts.tfm.readers.sequence = { 'otf', 'ttf', 'tfm', 'lua' }
-fonts.tfm.readers.afm = nil
-
--- define
-
-fonts.definers = fonts.definers or { }
-fonts.definers.specifiers = fonts.definers.specifiers or { }
-
-fonts.definers.specifiers.colonizedpreference = "name" -- is "file" in context
-
-function fonts.definers.getspecification(str)
- return "", str, "", ":", str
-end
-
-fonts.definers.registersplit("",fonts.definers.specifiers.variants[":"]) -- we add another one for catching lone [names]
-
--- logger
-
-fonts.logger = fonts.logger or { }
-
-function fonts.logger.save()
-end
-
--- names
---
--- Watch out, the version number is the same as the one used in
--- the mtx-fonts.lua function scripts.fonts.names as we use a
--- simplified font database in the plain solution and by using
--- a different number we're less dependent on context.
-
-fonts.names = fonts.names or { }
-
-fonts.names.version = 1.001 -- not the same as in context
-fonts.names.basename = "luatex-fonts-names.lua"
-fonts.names.new_to_old = { }
-fonts.names.old_to_new = { }
-
-local data, loaded = nil, false
-
-local fileformats = { "lua", "tex", "other text files" }
-
-function fonts.names.resolve(name,sub)
- if not loaded then
- local basename = fonts.names.basename
- if basename and basename ~= "" then
- for i=1,#fileformats do
- local format = fileformats[i]
- local foundname = resolvers.findfile(basename,format) or ""
- if foundname ~= "" then
- data = dofile(foundname)
- break
- end
- end
- end
- loaded = true
- end
- if type(data) == "table" and data.version == fonts.names.version then
- local condensed = string.gsub(string.lower(name),"[^%a%d]","")
- local found = data.mappings and data.mappings[condensed]
- if found then
- local fontname, filename, subfont = found[1], found[2], found[3]
- if subfont then
- return filename, fontname
- else
- return filename, false
- end
- else
- return name, false -- fallback to filename
- end
- end
-end
-
-fonts.names.resolvespec = fonts.names.resolve -- only supported in mkiv
-
-function fonts.names.getfilename(askedname,suffix) -- only supported in mkiv
- return ""
-end
-
--- For the moment we put this (adapted) pseudo feature here.
-
-table.insert(fonts.triggers,"itlc")
-
-local function itlc(tfmdata,value)
- if value then
- -- the magic 40 and it formula come from Dohyun Kim
- local metadata = tfmdata.shared.otfdata.metadata
- if metadata then
- local italicangle = metadata.italicangle
- if italicangle and italicangle ~= 0 then
- local uwidth = (metadata.uwidth or 40)/2
- for unicode, d in next, tfmdata.descriptions do
- local it = d.boundingbox[3] - d.width + uwidth
- if it ~= 0 then
- d.italic = it
- end
- end
- tfmdata.has_italic = true
- end
- end
- end
-end
-
-fonts.initializers.base.otf.itlc = itlc
-fonts.initializers.node.otf.itlc = itlc
-
--- slant and extend
-
-function fonts.initializers.common.slant(tfmdata,value)
- value = tonumber(value)
- if not value then
- value = 0
- elseif value > 1 then
- value = 1
- elseif value < -1 then
- value = -1
- end
- tfmdata.slant_factor = value
-end
-
-function fonts.initializers.common.extend(tfmdata,value)
- value = tonumber(value)
- if not value then
- value = 0
- elseif value > 10 then
- value = 10
- elseif value < -10 then
- value = -10
- end
- tfmdata.extend_factor = value
-end
-
-table.insert(fonts.triggers,"slant")
-table.insert(fonts.triggers,"extend")
-
-fonts.initializers.base.otf.slant = fonts.initializers.common.slant
-fonts.initializers.node.otf.slant = fonts.initializers.common.slant
-fonts.initializers.base.otf.extend = fonts.initializers.common.extend
-fonts.initializers.node.otf.extend = fonts.initializers.common.extend
-
--- expansion and protrusion
-
-fonts.protrusions = fonts.protrusions or { }
-fonts.protrusions.setups = fonts.protrusions.setups or { }
-
-local setups = fonts.protrusions.setups
-
-function fonts.initializers.common.protrusion(tfmdata,value)
- if value then
- local setup = setups[value]
- if setup then
- local factor, left, right = setup.factor or 1, setup.left or 1, setup.right or 1
- local emwidth = tfmdata.parameters.quad
- tfmdata.auto_protrude = true
- for i, chr in next, tfmdata.characters do
- local v, pl, pr = setup[i], nil, nil
- if v then
- pl, pr = v[1], v[2]
- end
- if pl and pl ~= 0 then chr.left_protruding = left *pl*factor end
- if pr and pr ~= 0 then chr.right_protruding = right*pr*factor end
- end
- end
- end
-end
-
-fonts.expansions = fonts.expansions or { }
-fonts.expansions.setups = fonts.expansions.setups or { }
-
-local setups = fonts.expansions.setups
-
-function fonts.initializers.common.expansion(tfmdata,value)
- if value then
- local setup = setups[value]
- if setup then
- local stretch, shrink, step, factor = setup.stretch or 0, setup.shrink or 0, setup.step or 0, setup.factor or 1
- tfmdata.stretch, tfmdata.shrink, tfmdata.step, tfmdata.auto_expand = stretch * 10, shrink * 10, step * 10, true
- for i, chr in next, tfmdata.characters do
- local v = setup[i]
- if v and v ~= 0 then
- chr.expansion_factor = v*factor
- else -- can be option
- chr.expansion_factor = factor
- end
- end
- end
- end
-end
-
-table.insert(fonts.manipulators,"protrusion")
-table.insert(fonts.manipulators,"expansion")
-
-fonts.initializers.base.otf.protrusion = fonts.initializers.common.protrusion
-fonts.initializers.node.otf.protrusion = fonts.initializers.common.protrusion
-fonts.initializers.base.otf.expansion = fonts.initializers.common.expansion
-fonts.initializers.node.otf.expansion = fonts.initializers.common.expansion
-
--- left over
-
-function fonts.registermessage()
-end
-
--- example vectors
-
-local byte = string.byte
-
-fonts.expansions.setups['default'] = {
-
- stretch = 2, shrink = 2, step = .5, factor = 1,
-
- [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,
-}
-
-fonts.protrusions.setups['default'] = {
-
- factor = 1, left = 1, right = 1,
-
- [0x002C] = { 0, 1 }, -- comma
- [0x002E] = { 0, 1 }, -- period
- [0x003A] = { 0, 1 }, -- colon
- [0x003B] = { 0, 1 }, -- semicolon
- [0x002D] = { 0, 1 }, -- hyphen
- [0x2013] = { 0, 0.50 }, -- endash
- [0x2014] = { 0, 0.33 }, -- emdash
- [0x3001] = { 0, 1 }, -- ideographic comma 、
- [0x3002] = { 0, 1 }, -- ideographic full stop 。
- [0x060C] = { 0, 1 }, -- arabic comma ،
- [0x061B] = { 0, 1 }, -- arabic semicolon ؛
- [0x06D4] = { 0, 1 }, -- arabic full stop ۔
-
-}
-
--- normalizer
-
-fonts.otf.meanings = fonts.otf.meanings or { }
-
-fonts.otf.meanings.normalize = fonts.otf.meanings.normalize or function(t)
- if t.rand then
- t.rand = "random"
- end
-end
-
--- needed (different in context)
-
-function fonts.otf.scriptandlanguage(tfmdata)
- return tfmdata.script, tfmdata.language
-end
-
--- bonus
-
-function fonts.otf.nametoslot(name)
- local tfmdata = fonts.identifiers[font.current()]
- if tfmdata and tfmdata.shared then
- local otfdata = tfmdata.shared.otfdata
- local unicode = otfdata.luatex.unicodes[name]
- return unicode and (type(unicode) == "number" and unicode or unicode[1])
- end
-end
-
-function fonts.otf.char(n)
- if type(n) == "string" then
- n = fonts.otf.nametoslot(n)
- end
- if type(n) == "number" then
- tex.sprint("\\char" .. n)
- end
-end
-
--- another one:
-
-fonts.strippables = table.tohash {
- 0x000AD, 0x017B4, 0x017B5, 0x0200B, 0x0200C, 0x0200D, 0x0200E, 0x0200F, 0x0202A, 0x0202B,
- 0x0202C, 0x0202D, 0x0202E, 0x02060, 0x02061, 0x02062, 0x02063, 0x0206A, 0x0206B, 0x0206C,
- 0x0206D, 0x0206E, 0x0206F, 0x0FEFF, 0x1D173, 0x1D174, 0x1D175, 0x1D176, 0x1D177, 0x1D178,
- 0x1D179, 0x1D17A, 0xE0001, 0xE0020, 0xE0021, 0xE0022, 0xE0023, 0xE0024, 0xE0025, 0xE0026,
- 0xE0027, 0xE0028, 0xE0029, 0xE002A, 0xE002B, 0xE002C, 0xE002D, 0xE002E, 0xE002F, 0xE0030,
- 0xE0031, 0xE0032, 0xE0033, 0xE0034, 0xE0035, 0xE0036, 0xE0037, 0xE0038, 0xE0039, 0xE003A,
- 0xE003B, 0xE003C, 0xE003D, 0xE003E, 0xE003F, 0xE0040, 0xE0041, 0xE0042, 0xE0043, 0xE0044,
- 0xE0045, 0xE0046, 0xE0047, 0xE0048, 0xE0049, 0xE004A, 0xE004B, 0xE004C, 0xE004D, 0xE004E,
- 0xE004F, 0xE0050, 0xE0051, 0xE0052, 0xE0053, 0xE0054, 0xE0055, 0xE0056, 0xE0057, 0xE0058,
- 0xE0059, 0xE005A, 0xE005B, 0xE005C, 0xE005D, 0xE005E, 0xE005F, 0xE0060, 0xE0061, 0xE0062,
- 0xE0063, 0xE0064, 0xE0065, 0xE0066, 0xE0067, 0xE0068, 0xE0069, 0xE006A, 0xE006B, 0xE006C,
- 0xE006D, 0xE006E, 0xE006F, 0xE0070, 0xE0071, 0xE0072, 0xE0073, 0xE0074, 0xE0075, 0xE0076,
- 0xE0077, 0xE0078, 0xE0079, 0xE007A, 0xE007B, 0xE007C, 0xE007D, 0xE007E, 0xE007F,
-}
-
--- \font\test=file:somefont:reencode=mymessup
---
--- fonts.enc.reencodings.mymessup = {
--- [109] = 110, -- m
--- [110] = 109, -- n
--- }
-
-fonts.enc = fonts.enc or {}
-local reencodings = { }
-fonts.enc.reencodings = reencodings
-
-local function specialreencode(tfmdata,value)
- -- we forget about kerns as we assume symbols and we
- -- could issue a message if ther are kerns but it's
- -- a hack anyway so we odn't care too much here
- local encoding = value and reencodings[value]
- if encoding then
- local temp = { }
- local char = tfmdata.characters
- for k, v in next, encoding do
- temp[k] = char[v]
- end
- for k, v in next, temp do
- char[k] = temp[k]
- end
- -- if we use the font otherwise luatex gets confused so
- -- we return an additional hash component for fullname
- return string.format("reencoded:%s",value)
- end
-end
-
-local function reencode(tfmdata,value)
- tfmdata.postprocessors = tfmdata.postprocessors or { }
- table.insert(tfmdata.postprocessors,
- function(tfmdata)
- return specialreencode(tfmdata,value)
- end
- )
-end
-
-table.insert(fonts.manipulators,"reencode")
-fonts.initializers.base.otf.reencode = reencode
diff --git a/tex/context/base/font-enc.lua b/tex/context/base/font-enc.lua
index ad1c2ec64..7e62b1eec 100644
--- a/tex/context/base/font-enc.lua
+++ b/tex/context/base/font-enc.lua
@@ -15,15 +15,14 @@ local match, gmatch, gsub = string.match, string.gmatch, string.gsub
them in tables. But we may do so some day, for consistency.</p>
--ldx]]--
-fonts.enc = fonts.enc or { }
-local enc = fonts.enc
-
local report_encoding = logs.reporter("fonts","encoding")
-enc.version = 1.03
-enc.cache = containers.define("fonts", "enc", fonts.enc.version, true)
+local encodings = { }
+fonts.encodings = encodings
-enc.known = utilities.storage.allocate { -- sort of obsolete
+encodings.version = 1.03
+encodings.cache = containers.define("fonts", "enc", fonts.encodings.version, true)
+encodings.known = utilities.storage.allocate { -- sort of obsolete
texnansi = true,
ec = true,
qx = true,
@@ -34,8 +33,8 @@ enc.known = utilities.storage.allocate { -- sort of obsolete
unicode = true,
}
-function enc.is_known(encoding)
- return containers.is_valid(enc.cache,encoding)
+function encodings.is_known(encoding)
+ return containers.is_valid(encodings.cache,encoding)
end
--[[ldx--
@@ -57,16 +56,16 @@ Latin Modern or <l n='tex'> Gyre) come in OpenType variants too, so these
will be used.</p>
--ldx]]--
-local enccodes = characters.enccodes
+local enccodes = characters.enccodes or { }
-function enc.load(filename)
+function encodings.load(filename)
local name = file.removesuffix(filename)
- local data = containers.read(enc.cache,name)
+ local data = containers.read(encodings.cache,name)
if data then
return data
end
if name == "unicode" then
- data = enc.make_unicode_vector() -- special case, no tex file for this
+ data = encodings.make_unicode_vector() -- special case, no tex file for this
end
if data then
return data
@@ -102,7 +101,7 @@ function enc.load(filename)
hash = hash,
unicodes = unicodes
}
- return containers.write(enc.cache, name, data)
+ return containers.write(encodings.cache, name, data)
end
--[[ldx--
@@ -112,12 +111,13 @@ one.</p>
-- maybe make this a function:
-function enc.make_unicode_vector()
+function encodings.make_unicode_vector()
local vector, hash = { }, { }
for code, v in next, characters.data do
local name = v.adobename
if name then
- vector[code], hash[name] = name, code
+ vector[code] = name
+ hash[name] = code
else
vector[code] = '.notdef'
end
@@ -125,21 +125,21 @@ function enc.make_unicode_vector()
for name, code in next, characters.synonyms do
vector[code], hash[name] = name, code
end
- return containers.write(enc.cache, 'unicode', { name='unicode', tag='unicode', vector=vector, hash=hash })
+ return containers.write(encodings.cache, 'unicode', { name='unicode', tag='unicode', vector=vector, hash=hash })
end
-if not enc.agl then
+if not encodings.agl then
-- We delay delay loading this rather big vector that is only needed when a
-- font is loaded for caching. Once we're further along the route we can also
-- delay it in the generic version (which doesn't use this file).
- enc.agl = { }
+ encodings.agl = { }
- setmetatable(enc.agl, { __index = function(t,k)
+ setmetatable(encodings.agl, { __index = function(t,k)
report_encoding("loading (extended) adobe glyph list")
- dofile(resolvers.findfile("font-agl.lua"))
- return rawget(enc.agl,k)
+ dofile(resolvers.findfile("font-age.lua"))
+ return rawget(encodings.agl,k)
end })
end
diff --git a/tex/context/base/font-enh.lua b/tex/context/base/font-enh.lua
index 34cdd9264..3e3535f87 100644
--- a/tex/context/base/font-enh.lua
+++ b/tex/context/base/font-enh.lua
@@ -6,172 +6,56 @@ if not modules then modules = { } end modules ['font-enh'] = {
license = "see context related readme files"
}
--- todo: optimize a bit
+local next = next
-local next, match = next, string.match
+local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
+local report_defining = logs.reporter("fonts","defining")
-local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
+local fonts = fonts
+local constructors = fonts.constructors
-local report_defining = logs.reporter("fonts","defining")
+local tfmfeatures = constructors.newfeatures("tfm")
+local registertfmfeature = tfmfeatures.register
--- tfmdata has also fast access to indices and unicodes
--- to be checked: otf -> tfm -> tfmscaled
---
--- watch out: no negative depths and negative eights permitted in regular fonts
+local fontencodings = fonts.encodings
+fontencodings.remappings = fontencodings.remappings or { }
---[[ldx--
-<p>Here we only implement a few helper functions.</p>
---ldx]]--
-
-local fonts = fonts
-local tfm = fonts.tfm
-
---[[ldx--
-<p>The next function encapsulates the standard <l n='tfm'/> loader as
-supplied by <l n='luatex'/>.</p>
---ldx]]--
-
--- auto complete font with missing composed characters
-
--- tfm features, experimental
-
-tfm.features = tfm.features or { }
-tfm.features.list = tfm.features.list or { }
-tfm.features.default = tfm.features.default or { }
-
-local initializers = fonts.initializers
-local triggers = fonts.triggers
-local manipulators = fonts.manipulators
-local featurelist = tfm.features.list
-local defaultfeaturelist = tfm.features.default
-
-table.insert(manipulators,"compose")
-
-function initializers.common.compose(tfmdata,value)
- if value then
- fonts.vf.aux.compose_characters(tfmdata)
- end
-end
-
-function tfm.enhance(tfmdata,specification)
- -- we don't really share tfm data because we always reload
- -- but this is more in sycn with afm and such
- local features = (specification.features and specification.features.normal ) or { }
- tfmdata.shared = tfmdata.shared or { }
- tfmdata.shared.features = features
- -- tfmdata.shared.tfmdata = tfmdata -- circular
- tfmdata.filename = specification.name
- if not features.encoding then
- local name, size = specification.name, specification.size
- local encoding, filename = match(name,"^(.-)%-(.*)$") -- context: encoding-name.*
- if filename and encoding and fonts.enc.known[encoding] then
- features.encoding = encoding
- end
- end
- tfm.setfeatures(tfmdata)
-end
-
-function tfm.setfeatures(tfmdata)
- -- todo: no local functions
- local shared = tfmdata.shared
--- local tfmdata = shared.tfmdata
- local features = shared.features
- if features and next(features) then
- local mode = tfmdata.mode or features.mode or "base"
- local fi = initializers[mode]
- if fi and fi.tfm then
- local function initialize(list) -- using tex lig and kerning
- if list then
- -- fi adapts !
- for i=1,#list do
- local f = list[i]
- local value = features[f]
- if value then
- local fitfmf = fi.tfm[f] -- brr
- if fitfmf then
- if tfm.trace_features then
- report_defining("initializing feature %s to %s for mode %s for font %s",f,tostring(value),mode or 'unknown',tfmdata.name or 'unknown')
- end
- fitfmf(tfmdata,value)
- mode = tfmdata.mode or features.mode or "base"
- fi = initializers[mode]
- end
- end
- end
- end
- end
- initialize(triggers)
- initialize(featurelist)
- initialize(manipulators)
- end
- local fm = fonts.methods[mode]
- if fm then
- local fmtfm = fm.tfm
- if fmtfm then
- local function register(list) -- node manipulations
- if list then
- local sp = shared.processors
- local ns = sp and #sp
- for i=1,#list do
- local f = list[i]
- if features[f] then
- local fmtfmf = fmtfm[f]
- if not fmtfmf then
- -- brr
- elseif not sp then
- sp = { fmtfmf }
- ns = 1
- shared.processors = sp
- else
- ns = ns + 1
- sp[ns] = fmtfmf
- end
- end
- end
- end
- end
- register(featurelist)
- end
- end
- end
-end
-
-function tfm.features.register(name,default)
- featurelist[#tfm.features.list+1] = name
- defaultfeaturelist[name] = default
-end
-
-function tfm.reencode(tfmdata,encoding)
- if encoding and fonts.enc.known[encoding] then
- local data = fonts.enc.load(encoding)
+local function reencode(tfmdata,encoding)
+ if encoding and fontencodings.known[encoding] then
+ local data = fontencodings.load(encoding)
if data then
- local characters, original, vector = tfmdata.characters, { }, data.vector
- tfmdata.encoding = encoding -- not needed
- for k, v in next, characters do
- v.name, v.index, original[k] = vector[k], k, v
+ tfmdata.properties.encoding = encoding
+ local characters = tfmdata.characters
+ local original = { }
+ local vector = data.vector
+ for unicode, character in next, characters do
+ character.name = vector[unicode]
+ character.index = unicode, character
+ original[unicode] = character
end
- for k,v in next, data.unicodes do
- if k ~= v then
+ for newcode, oldcode in next, data.unicodes do
+ if newcode ~= oldcode then
if trace_defining then
- report_defining("reencoding U+%04X to U+%04X",k,v)
+ report_defining("reencoding U+%04X to U+%04X",newcode,oldcode)
end
- characters[k] = original[v]
+ characters[newcode] = original[oldcode]
end
end
end
end
end
-tfm.features.register('reencode')
-
-initializers.base.tfm.reencode = tfm.reencode
-initializers.node.tfm.reencode = tfm.reencode
-
-fonts.enc = fonts.enc or { }
-fonts.enc.remappings = fonts.enc.remappings or { }
+registertfmfeature {
+ name = "reencode",
+ description = "reencode",
+ manipulators = {
+ base = reencode,
+ node = reencode,
+ }
+}
-function tfm.remap(tfmdata,remapping)
- local vector = remapping and fonts.enc.remappings[remapping]
+local function remap(tfmdata,remapping)
+ local vector = remapping and fontencodings.remappings[remapping]
if vector then
local characters, original = tfmdata.characters, { }
for k, v in next, characters do
@@ -187,41 +71,22 @@ function tfm.remap(tfmdata,remapping)
c.index = k
end
end
- tfmdata.encodingbytes = 2
- tfmdata.format = tfmdata.format or 'type1'
+ local properties = tfmdata.properties
+ if not properties then
+ properties = { }
+ tfmdata.properties = properties
+ else
+ properties.encodingbytes = 2
+ properties.format = properties.format or 'type1'
+ end
end
end
-tfm.features.register('remap')
-
-initializers.base.tfm.remap = tfm.remap
-initializers.node.tfm.remap = tfm.remap
-
---~ obsolete
---~
---~ function tfm.enhance(tfmdata,specification)
---~ local name, size = specification.name, specification.size
---~ local encoding, filename = match(name,"^(.-)%-(.*)$") -- context: encoding-name.*
---~ if filename and encoding and fonts.enc.known[encoding] then
---~ local data = fonts.enc.load(encoding)
---~ if data then
---~ local characters = tfmdata.characters
---~ tfmdata.encoding = encoding
---~ local vector = data.vector
---~ local original = { }
---~ for k, v in next, characters do
---~ v.name = vector[k]
---~ v.index = k
---~ original[k] = v
---~ end
---~ for k,v in next, data.unicodes do
---~ if k ~= v then
---~ if trace_defining then
---~ report_defining("mapping %s onto %s",k,v)
---~ end
---~ characters[k] = original[v]
---~ end
---~ end
---~ end
---~ end
---~ end
+registertfmfeature {
+ name = "remap",
+ description = "remap",
+ manipulators = {
+ base = remap,
+ node = remap,
+ }
+}
diff --git a/tex/context/base/font-ext.lua b/tex/context/base/font-ext.lua
index 16a0008cc..acabdb465 100644
--- a/tex/context/base/font-ext.lua
+++ b/tex/context/base/font-ext.lua
@@ -20,95 +20,21 @@ local trace_expansion = false trackers.register("fonts.expansion", function(v
local report_expansions = logs.reporter("fonts","expansions")
local report_protrusions = logs.reporter("fonts","protrusions")
-commands = commands or { }
-
--[[ldx--
<p>When we implement functions that deal with features, most of them
will depend of the font format. Here we define the few that are kind
of neutral.</p>
--ldx]]--
-local fonts = fonts
-
-fonts.triggers = fonts.triggers or { }
-local triggers = fonts.triggers
-
-fonts.methods = fonts.methods or { }
-local methods = fonts.methods
-
-fonts.manipulators = fonts.manipulators or { }
-local manipulators = fonts.manipulators
-
-fonts.initializers = fonts.initializers or { }
-local initializers = fonts.initializers
-initializers.common = initializers.common or { }
-
-local otf = fonts.otf
-
---[[ldx--
-<p>This feature will remove inter-digit kerns.</p>
---ldx]]--
-
--- old code, no kerns set at this point, so this has to be done afterwards
---
--- table.insert(triggers,"equaldigits")
---
--- function initializers.common.equaldigits(tfmdata,value)
--- if value then
--- local chr = tfmdata.characters
--- for i = utfbyte('0'), utfbyte('9') do
--- local c = chr[i]
--- if c then
--- c.kerns = nil
--- end
--- end
--- end
--- end
+local fonts = fonts
+local handlers = fonts.handlers
+local otf = handlers.otf
---[[ldx--
-<p>This feature will give all glyphs an equal height and/or depth. Valid
-values are <type>none</type>, <type>height</type>, <type>depth</type> and
-<type>both</type>.</p>
---ldx]]--
+local otffeatures = fonts.constructors.newfeatures("otf")
+local registerotffeature = otffeatures.register
--- old code, no dimensions set at this point, so this has to be done afterwards
---
--- table.insert(triggers,"lineheight")
---
--- function initializers.common.lineheight(tfmdata,value)
--- if value and type(value) == "string" then
--- if value == "none" then
--- for _,v in next, tfmdata.characters do
--- v.height, v.depth = 0, 0
--- end
--- else
--- local ascender, descender = tfmdata.ascender, tfmdata.descender
--- if ascender and descender then
--- local ht, dp = ascender or 0, descender or 0
--- if value == "height" then
--- dp = 0
--- elseif value == "depth" then
--- ht = 0
--- end
--- if ht > 0 then
--- if dp > 0 then
--- for _,v in next, tfmdata.characters do
--- v.height, v.depth = ht, dp
--- end
--- else
--- for _,v in next, tfmdata.characters do
--- v.height = ht
--- end
--- end
--- elseif dp > 0 then
--- for _,v in next, tfmdata.characters do
--- v.depth = dp
--- end
--- end
--- end
--- end
--- end
--- end
+local afmfeatures = fonts.constructors.newfeatures("afm")
+local registerafmfeature = afmfeatures.register
-- -- -- -- -- --
-- shared
@@ -116,11 +42,10 @@ values are <type>none</type>, <type>height</type>, <type>depth</type> and
local function get_class_and_vector(tfmdata,value,where) -- "expansions"
local g_where = tfmdata.goodies and tfmdata.goodies[where]
- local f_where = fonts[where]
+ local f_where = handlers[where]
local g_classes = g_where and g_where.classes
local f_classes = f_where and f_where.classes
local class = (g_classes and g_classes[value]) or (f_classes and f_classes[value])
---~ print(value,class,f_where,f_classes)
if class then
local class_vector = class.vector
local g_vectors = g_where and g_where.vectors
@@ -169,17 +94,26 @@ vectors['default'] = {
vectors['quality'] = vectors['default'] -- metatable ?
-function initializers.common.expansion(tfmdata,value)
+local function initializeexpansion(tfmdata,value)
if value then
local class, vector = get_class_and_vector(tfmdata,value,"expansions")
if class then
if vector then
- local stretch, shrink, step, factor = class.stretch or 0, class.shrink or 0, class.step or 0, class.factor or 1
+ local stretch = class.stretch or 0
+ local shrink = class.shrink or 0
+ local step = class.step or 0
+ local factor = class.factor or 1
if trace_expansion then
report_expansions("setting class %s, vector: %s, factor: %s, stretch: %s, shrink: %s, step: %s",
value,class.vector,factor,stretch,shrink,step)
end
- tfmdata.stretch, tfmdata.shrink, tfmdata.step, tfmdata.auto_expand = stretch * 10, shrink * 10, step * 10, true
+ tfmdata.parameters.expansion = {
+ stretch = 10 * stretch,
+ shrink = 10 * shrink,
+ step = 10 * step,
+ factor = factor,
+ auto = true,
+ }
local data = characters and characters.data
for i, chr in next, tfmdata.characters do
local v = vector[i]
@@ -211,13 +145,23 @@ function initializers.common.expansion(tfmdata,value)
end
end
-table.insert(manipulators,"expansion")
-
-initializers.base.otf.expansion = initializers.common.expansion
-initializers.node.otf.expansion = initializers.common.expansion
+registerotffeature {
+ name = "expansion",
+ description = "apply hz optimization",
+ initializers = {
+ base = initializeexpansion,
+ node = initializeexpansion,
+ }
+}
-initializers.base.afm.expansion = initializers.common.expansion
-initializers.node.afm.expansion = initializers.common.expansion
+registerafmfeature {
+ name = "expansion",
+ description = "apply hz optimization",
+ initializers = {
+ base = initializeexpansion,
+ node = initializeexpansion,
+ }
+}
fonts.goodies.register("expansions", function(...) return fonts.goodies.report("expansions", trace_expansion, ...) end)
@@ -374,10 +318,13 @@ classes['double'] = { -- for testing opbd
}
local function map_opbd_onto_protrusion(tfmdata,value,opbd)
- local characters, descriptions = tfmdata.characters, tfmdata.descriptions
- local otfdata = tfmdata.shared.otfdata
- local singles = otfdata.shared.featuredata.gpos_single
- local script, language = tfmdata.script, tfmdata.language
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local properties = tfmdata.properties
+ local rawdata = tfmdata.shared.rawdata
+ local lookuphash = rawdata.lookuphash
+ local script = properties.script
+ local language = properties.language
local done, factor, left, right = false, 1, 1, 1
local class = classes[value]
if class then
@@ -388,11 +335,11 @@ local function map_opbd_onto_protrusion(tfmdata,value,opbd)
factor = tonumber(value) or 1
end
if opbd ~= "right" then
- local validlookups, lookuplist = otf.collectlookups(otfdata,"lfbd",script,language)
+ local validlookups, lookuplist = otf.collectlookups(rawdata,"lfbd",script,language)
if validlookups then
for i=1,#lookuplist do
local lookup = lookuplist[i]
- local data = singles[lookup]
+ local data = lookuphash[lookup]
if data then
if trace_protrusion then
report_protrusions("setting left using lfbd lookup '%s'",lookup)
@@ -411,11 +358,11 @@ local function map_opbd_onto_protrusion(tfmdata,value,opbd)
end
end
if opbd ~= "left" then
- local validlookups, lookuplist = otf.collectlookups(otfdata,"rtbd",script,language)
+ local validlookups, lookuplist = otf.collectlookups(rawdata,"rtbd",script,language)
if validlookups then
for i=1,#lookuplist do
local lookup = lookuplist[i]
- local data = singles[lookup]
+ local data = lookuphash[lookup]
if data then
if trace_protrusion then
report_protrusions("setting right using rtbd lookup '%s'",lookup)
@@ -441,7 +388,7 @@ end
-- only has some kerns for digits. So, consider this feature not
-- supported till we have a proper test font.
-function initializers.common.protrusion(tfmdata,value)
+local function initializeprotrusion(tfmdata,value)
if value then
local opbd = tfmdata.shared.features.opbd
if opbd then
@@ -460,7 +407,12 @@ function initializers.common.protrusion(tfmdata,value)
end
local data = characters.data
local emwidth = tfmdata.parameters.quad
- tfmdata.auto_protrude = true
+ tfmdata.parameters.protrusion = {
+ factor = factor,
+ left = left,
+ right = right,
+ auto = true,
+ }
for i, chr in next, tfmdata.characters do
local v, pl, pr = vector[i], nil, nil
if v then
@@ -500,61 +452,80 @@ function initializers.common.protrusion(tfmdata,value)
end
end
-table.insert(manipulators,"protrusion")
-
-initializers.base.otf.protrusion = initializers.common.protrusion
-initializers.node.otf.protrusion = initializers.common.protrusion
+registerotffeature {
+ name = "protrusion",
+ description = "shift characters into the left and or right margin",
+ initializers = {
+ base = initializeprotrusion,
+ node = initializeprotrusion,
+ }
+}
-initializers.base.afm.protrusion = initializers.common.protrusion
-initializers.node.afm.protrusion = initializers.common.protrusion
+registerafmfeature {
+ name = "protrusion",
+ description = "shift characters into the left and or right margin",
+ initializers = {
+ base = initializeprotrusion,
+ node = initializeprotrusion,
+ }
+}
fonts.goodies.register("protrusions", function(...) return fonts.goodies.report("protrusions", trace_protrusion, ...) end)
-- -- --
-function initializers.common.nostackmath(tfmdata,value)
- tfmdata.ignore_stack_math = value
+local function initializenostackmath(tfmdata,value)
+ tfmdata.properties.no_stackmath = value and true
end
-table.insert(manipulators,"nostackmath")
-
-initializers.base.otf.nostackmath = initializers.common.nostackmath
-initializers.node.otf.nostackmath = initializers.common.nostackmath
-
-table.insert(triggers,"itlc")
+registerotffeature {
+ name = "nostackmath",
+ description = "disable math stacking mechanism",
+ initializers = {
+ base = initializenostackmath,
+ node = initializenostackmath,
+ }
+}
-function initializers.common.itlc(tfmdata,value)
+local function initializeitlc(tfmdata,value)
if value then
-- the magic 40 and it formula come from Dohyun Kim
- local fontdata = tfmdata.shared.otfdata or tfmdata.shared.afmdata
- local metadata = fontdata and fontdata.metadata
- if metadata then
- local italicangle = metadata.italicangle
- if italicangle and italicangle ~= 0 then
- local uwidth = (metadata.uwidth or 40)/2
- for unicode, d in next, tfmdata.descriptions do
- local it = d.boundingbox[3] - d.width + uwidth
- if it ~= 0 then
- d.italic = it
- end
+ local parameters = tfmdata.parameters
+ local italicangle = parameters.italicangle
+ if italicangle and italicangle ~= 0 then
+ local uwidth = (parameters.uwidth or 40)/2
+ for unicode, d in next, tfmdata.descriptions do
+ local it = d.boundingbox[3] - d.width + uwidth
+ if it ~= 0 then
+ d.italic = it
end
- tfmdata.has_italic = true
end
+ tfmdata.properties.italic_correction = true
end
end
end
-initializers.base.otf.itlc = initializers.common.itlc
-initializers.node.otf.itlc = initializers.common.itlc
+registerotffeature {
+ name = "itlc",
+ description = "italic correction",
+ initializers = {
+ base = initializeitlc,
+ node = initializeitlc,
+ }
+}
-initializers.base.afm.itlc = initializers.common.itlc
-initializers.node.afm.itlc = initializers.common.itlc
+registerafmfeature {
+ name = "itlc",
+ description = "italic correction",
+ initializers = {
+ base = initializeitlc,
+ node = initializeitlc,
+ }
+}
-- slanting
-table.insert(triggers,"slant")
-
-function initializers.common.slant(tfmdata,value)
+local function initializeslant(tfmdata,value)
value = tonumber(value)
if not value then
value = 0
@@ -563,18 +534,28 @@ function initializers.common.slant(tfmdata,value)
elseif value < -1 then
value = -1
end
- tfmdata.slant_factor = value
+ tfmdata.parameters.slant_factor = value
end
-initializers.base.otf.slant = initializers.common.slant
-initializers.node.otf.slant = initializers.common.slant
-
-initializers.base.afm.slant = initializers.common.slant
-initializers.node.afm.slant = initializers.common.slant
+registerotffeature {
+ name = "slant",
+ description = "slant glyphs",
+ initializers = {
+ base = initializeslant,
+ node = initializeslant,
+ }
+}
-table.insert(triggers,"extend")
+registerafmfeature {
+ name = "slant",
+ description = "slant glyphs",
+ initializers = {
+ base = initializeslant,
+ node = initializeslant,
+ }
+}
-function initializers.common.extend(tfmdata,value)
+local function initializeextend(tfmdata,value)
value = tonumber(value)
if not value then
value = 0
@@ -583,58 +564,90 @@ function initializers.common.extend(tfmdata,value)
elseif value < -10 then
value = -10
end
- tfmdata.extend_factor = value
+ tfmdata.parameters.extend_factor = value
end
-initializers.base.otf.extend = initializers.common.extend
-initializers.node.otf.extend = initializers.common.extend
-
-initializers.base.afm.extend = initializers.common.extend
-initializers.node.afm.extend = initializers.common.extend
-
--- historic stuff, move from font-ota
-
-local delete_node = nodes.delete
-local fontdata = fonts.identifiers
-
-local nodecodes = nodes.nodecodes
-local glyph_code = nodecodes.glyph
-
-fonts.strippables = fonts.strippables or { -- just a placeholder
- [0x200C] = true, -- zwnj
- [0x200D] = true, -- zwj
+registerotffeature {
+ name = "extend",
+ description = "scale glyphs horizontally",
+ initializers = {
+ base = initializeextend,
+ node = initializeextend,
+ }
}
-local strippables = fonts.strippables
-
-local function processformatters(head,font)
- local how = fontdata[font].shared.features.formatters
- if how == nil or how == "strip" then -- nil when forced
- local current, done = head, false
- while current do
- if current.id == glyph_code and current.subtype<256 and current.font == font then
- local char = current.char
- if strippables[char] then
- head, current = delete_node(head,current)
- done = true
- else
- current = current.next
- end
- else
- current = current.next
- end
- end
- return head, done
- else
- return head, false
- end
-end
-
-methods.node.otf.formatters = processformatters
-methods.base.otf.formatters = processformatters
-
-otf.tables.features['formatters'] = 'Hide Formatting Characters'
-
-otf.features.register("formatters")
+registerafmfeature {
+ name = "extend",
+ description = "scale glyphs horizontally",
+ initializers = {
+ base = initializeextend,
+ node = initializeextend,
+ }
+}
-table.insert(manipulators,"formatters") -- at end
+-- -- historic stuff, move from font-ota (handled differently, typo-rep)
+--
+-- local delete_node = nodes.delete
+-- local fontdata = fonts.hashes.identifiers
+--
+-- local nodecodes = nodes.nodecodes
+-- local glyph_code = nodecodes.glyph
+--
+-- local strippables = allocate()
+-- fonts.strippables = strippables
+--
+-- strippables.joiners = table.tohash {
+-- 0x200C, -- zwnj
+-- 0x200D, -- zwj
+-- }
+--
+-- strippables.all = table.tohash {
+-- 0x000AD, 0x017B4, 0x017B5, 0x0200B, 0x0200C, 0x0200D, 0x0200E, 0x0200F, 0x0202A, 0x0202B,
+-- 0x0202C, 0x0202D, 0x0202E, 0x02060, 0x02061, 0x02062, 0x02063, 0x0206A, 0x0206B, 0x0206C,
+-- 0x0206D, 0x0206E, 0x0206F, 0x0FEFF, 0x1D173, 0x1D174, 0x1D175, 0x1D176, 0x1D177, 0x1D178,
+-- 0x1D179, 0x1D17A, 0xE0001, 0xE0020, 0xE0021, 0xE0022, 0xE0023, 0xE0024, 0xE0025, 0xE0026,
+-- 0xE0027, 0xE0028, 0xE0029, 0xE002A, 0xE002B, 0xE002C, 0xE002D, 0xE002E, 0xE002F, 0xE0030,
+-- 0xE0031, 0xE0032, 0xE0033, 0xE0034, 0xE0035, 0xE0036, 0xE0037, 0xE0038, 0xE0039, 0xE003A,
+-- 0xE003B, 0xE003C, 0xE003D, 0xE003E, 0xE003F, 0xE0040, 0xE0041, 0xE0042, 0xE0043, 0xE0044,
+-- 0xE0045, 0xE0046, 0xE0047, 0xE0048, 0xE0049, 0xE004A, 0xE004B, 0xE004C, 0xE004D, 0xE004E,
+-- 0xE004F, 0xE0050, 0xE0051, 0xE0052, 0xE0053, 0xE0054, 0xE0055, 0xE0056, 0xE0057, 0xE0058,
+-- 0xE0059, 0xE005A, 0xE005B, 0xE005C, 0xE005D, 0xE005E, 0xE005F, 0xE0060, 0xE0061, 0xE0062,
+-- 0xE0063, 0xE0064, 0xE0065, 0xE0066, 0xE0067, 0xE0068, 0xE0069, 0xE006A, 0xE006B, 0xE006C,
+-- 0xE006D, 0xE006E, 0xE006F, 0xE0070, 0xE0071, 0xE0072, 0xE0073, 0xE0074, 0xE0075, 0xE0076,
+-- 0xE0077, 0xE0078, 0xE0079, 0xE007A, 0xE007B, 0xE007C, 0xE007D, 0xE007E, 0xE007F,
+-- }
+--
+-- strippables[true] = strippables.joiners
+--
+-- local function processformatters(head,font)
+-- local subset = fontdata[font].shared.features.formatters
+-- local vector = subset and strippables[subset]
+-- if vector then
+-- local current, done = head, false
+-- while current do
+-- if current.id == glyph_code and current.subtype<256 and current.font == font then
+-- local char = current.char
+-- if vector[char] then
+-- head, current = delete_node(head,current)
+-- done = true
+-- else
+-- current = current.next
+-- end
+-- else
+-- current = current.next
+-- end
+-- end
+-- return head, done
+-- else
+-- return head, false
+-- end
+-- end
+--
+-- registerotffeature {
+-- name = "formatters",
+-- description = "hide formatting characters",
+-- methods = {
+-- base = processformatters,
+-- node = processformatters,
+-- }
+-- }
diff --git a/tex/context/base/font-fbk.lua b/tex/context/base/font-fbk.lua
index 586af127b..d5cec59c9 100644
--- a/tex/context/base/font-fbk.lua
+++ b/tex/context/base/font-fbk.lua
@@ -12,6 +12,8 @@ local utfbyte, utfchar = utf.byte, utf.char
local trace_combining = false trackers.register("fonts.combining", function(v) trace_combining = v end)
local trace_combining_all = false trackers.register("fonts.combining.all", function(v) trace_combining_all = v end)
+local force_combining = false -- just for demo purposes (see mk)
+
trackers.register("fonts.composing", "fonts.combining")
local report_combining = logs.reporter("fonts","combining")
@@ -22,66 +24,59 @@ local allocate = utilities.storage.allocate
<p>This is very experimental code!</p>
--ldx]]--
-local fonts = fonts
-local vf = fonts.vf
-local tfm = fonts.tfm
-
-fonts.fallbacks = allocate()
-local fallbacks = fonts.fallbacks
-local commands = vf.aux.combine.commands
-
-local push, pop = { "push" }, { "pop" }
-
-commands["enable-tracing"] = function(g,v)
- trace_combining = true
-end
-
-commands["disable-tracing"] = function(g,v)
- trace_combining = false
-end
+local fonts = fonts
+local handlers = fonts.handlers
+local constructors = fonts.constructors
+local vf = handlers.vf
+local commands = vf.combiner.commands
-commands["set-tracing"] = function(g,v)
- if v[2] == nil then
- trace_combining = true
- else
- trace_combining = v[2]
- end
-end
+local otffeatures = constructors.newfeatures("otf")
+local registerotffeature = otffeatures.register
--- maybe store llx etc instead of bbox in tfm blob / more efficient
+local afmfeatures = constructors.newfeatures("afm")
+local registerafmfeature = afmfeatures.register
-local force_composed = false
+local unicodecharacters = characters.data
+local unicodefallbacks = characters.fallbacks
-local cache = { } -- we could make these weak
-local fraction = 0.15 -- 30 units for lucida
+local push = vf.predefined.push
+local pop = vf.predefined.pop
+local force_composed = false
+local cache = { } -- we could make these weak
+local fraction = 0.15 -- 30 units for lucida
-function vf.aux.compose_characters(g) -- todo: scaling depends on call location
+local function composecharacters(tfmdata)
-- this assumes that slot 1 is self, there will be a proper self some day
- local chars, descs = g.characters, g.descriptions
- local Xdesc, xdesc = descs[utfbyte("X")], descs[utfbyte("x")]
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local parameters = tfmdata.parameters
+ local properties = tfmdata.properties
+ local Xdesc = descriptions[utfbyte("X")]
+ local xdesc = descriptions[utfbyte("x")]
if Xdesc and xdesc then
- local scale = g.factor or 1
+ local scale = parameters.factor or 1
local deltaxheight = scale * (Xdesc.boundingbox[4] - xdesc.boundingbox[4])
local extraxheight = fraction * deltaxheight -- maybe use compose value
- -- local cap_ury = scale*xdesc.boundingbox[4]
- local ita_cor = cos(rad(90+(g.italicangle or 0)))
- local fallbacks = characters.fallbacks
- local vfspecials = backends.tables.vfspecials
+ local italicfactor = parameters.italicfactor or 0
+ local vfspecials = backends.tables.vfspecials --brr
local red, green, blue, black
if trace_combining then
- red, green, blue, black = vfspecials.red, vfspecials.green, vfspecials.blue, vfspecials.black
+ red = vfspecials.red
+ green = vfspecials.green
+ blue = vfspecials.blue
+ black = vfspecials.black
end
- local compose = fonts.goodies.getcompositions(g)
+ local compose = fonts.goodies.getcompositions(tfmdata)
if compose and trace_combining then
report_combining("using compose information from goodies file")
end
local done = false
- for i,c in next, characters.data do -- loop over all characters ... not that efficient but a specials hash takes memory
- if force_composed or not chars[i] then
+ for i,c in next, unicodecharacters do -- loop over all characters ... not that efficient but a specials hash takes memory
+ if force_combining or not characters[i] then
local s = c.specials
if s and s[1] == 'char' then
local chr = s[2]
- local charschr = chars[chr]
+ local charschr = characters[chr]
if charschr then
local cc = c.category
if cc == 'll' or cc == 'lu' or cc == 'lt' then -- characters.is_letter[cc]
@@ -92,7 +87,7 @@ function vf.aux.compose_characters(g) -- todo: scaling depends on call location
t[k] = v
end
end
- local charsacc = chars[acc]
+ local charsacc = characters[acc]
--~ local ca = charsacc.category
--~ if ca == "mn" then
--~ -- mark nonspacing
@@ -102,8 +97,8 @@ function vf.aux.compose_characters(g) -- todo: scaling depends on call location
--~ -- mark enclosing
--~ else
if not charsacc then -- fallback accents
- acc = fallbacks[acc]
- charsacc = acc and chars[acc]
+ acc = unicodefallbacks[acc]
+ charsacc = acc and characters[acc]
end
local chr_t = cache[chr]
if not chr_t then
@@ -119,15 +114,15 @@ function vf.aux.compose_characters(g) -- todo: scaling depends on call location
acc_t = {"slot", 1, acc}
cache[acc] = acc_t
end
- local cb = descs[chr].boundingbox
- local ab = descs[acc].boundingbox
+ local cb = descriptions[chr].boundingbox
+ local ab = descriptions[acc].boundingbox
-- todo: adapt height
if cb and ab then
-- can be sped up for scale == 1
local c_llx, c_lly, c_urx, c_ury = scale*cb[1], scale*cb[2], scale*cb[3], scale*cb[4]
local a_llx, a_lly, a_urx, a_ury = scale*ab[1], scale*ab[2], scale*ab[3], scale*ab[4]
local dx = (c_urx - a_urx - a_llx + c_llx)/2
- local dd = (c_urx - c_llx)*ita_cor
+ local dd = (c_urx - c_llx)*italicfactor
if a_ury < 0 then
if trace_combining then
t.commands = { push, {"right", dx-dd}, red, acc_t, black, pop, chr_t }
@@ -135,7 +130,6 @@ function vf.aux.compose_characters(g) -- todo: scaling depends on call location
t.commands = { push, {"right", dx-dd}, acc_t, pop, chr_t }
end
elseif c_ury > a_lly then -- messy test
- -- local dy = cap_ury - a_lly
local dy
if compose then
-- experimental: we could use sx but all that testing
@@ -187,180 +181,78 @@ function vf.aux.compose_characters(g) -- todo: scaling depends on call location
t.commands = { chr_t } -- else index mess
end
done = true
- chars[i] = t
+ characters[i] = t
local d = { }
- for k, v in next, descs[chr] do
+ for k, v in next, descriptions[chr] do
d[k] = v
end
- -- d.name = c.adobename or "unknown" -- TOO TRICKY ! CAN CLASH WITH THE SUBSETTER
- -- d.unicode = i
- descs[i] = d
+ descriptions[i] = d
end
end
end
end
end
if done then
- g.type = "virtual" -- for the moment, to be sure
- g.virtualized = true
+ properties.virtualized = true
end
end
end
-commands["complete-composed-characters"] = function(g,v)
- vf.aux.compose_characters(g)
-end
+registerotffeature {
+ name = "compose",
+ description = "additional composed characters",
+ manipulators = {
+ base = composecharacters,
+ node = composecharacters,
+ }
+}
--- {'special', 'pdf: q ' .. s .. ' 0 0 '.. s .. ' 0 0 cm'},
--- {'special', 'pdf: q 1 0 0 1 ' .. -w .. ' ' .. -h .. ' cm'},
--- {'special', 'pdf: /Fm\XX\space Do'},
--- {'special', 'pdf: Q'},
--- {'special', 'pdf: Q'},
+registerafmfeature {
+ name = "compose",
+ description = "additional composed characters",
+ manipulators = {
+ base = composecharacters,
+ node = composecharacters,
+ }
+}
-local force_fallback = false
+vf.helpers.composecharacters = composecharacters
-commands["fake-character"] = function(g,v) -- g, nr, fallback_id
- local index, fallback = v[2], v[3]
- if (force_fallback or not g.characters[index]) and fallbacks[fallback] then
- g.characters[index], g.descriptions[index] = fallbacks[fallback](g)
- end
-end
+-- This installs the builder into the regular virtual font builder,
+-- which only makes sense as demo.
-commands["enable-force"] = function(g,v)
- force_composed = true
- force_fallback = true
+commands["compose.trace.enable"] = function()
+ trace_combining = true
end
-commands["disable-force"] = function(g,v)
- force_composed = false
- force_fallback = false
+commands["compose.trace.disable"] = function()
+ trace_combining = false
end
-local install = fonts.definers.methods.install
-
--- these are just examples used in the manuals, so they will end up in
--- modules eventually
+commands["compose.force.enable"] = function()
+ force_combining = true
+end
-fallbacks['textcent'] = function (g)
- local c = utfbyte("c")
- local t = table.fastcopy(g.characters[c],true)
- local a = - tan(rad(g.italicangle or 0))
- local vfspecials = backends.tables.vfspecials
- local green, black
- if trace_combining then
- green, black = vfspecials.green, vfspecials.black
- end
- local startslant, stopslant = vfspecials.startslant, vfspecials.stopslant
- local quad = g.parameters.quad
- if a == 0 then
- if trace_combining then
- t.commands = {
- push, {"slot", 1, c}, pop,
- {"right", .5*t.width},
- {"down", .2*t.height},
- green,
- {"rule", 1.4*t.height, .02*quad},
- black,
- }
- else
- t.commands = {
- push, {"slot", 1, c}, pop,
- {"right", .5*t.width},
- {"down", .2*t.height},
- {"rule", 1.4*t.height, .02*quad},
- }
- end
- else
- if trace_combining then
- t.commands = {
- push,
- {"right", .5*t.width-.025*quad},
- {"down", .2*t.height},
- startslant(a),
- green,
- {"rule", 1.4*t.height, .025*quad},
- black,
- stopslant,
- pop,
- {"slot", 1, c} -- last else problems with cm
- }
- else
- t.commands = {
- push,
- {"right", .5*t.width-.025*quad},
- {"down", .2*t.height},
- startslant(a),
- {"rule", 1.4*t.height, .025*quad},
- stopslant,
- pop,
- {"slot", 1, c} -- last else problems with cm
- }
- end
- end
- -- somehow the width is messed up now
- -- todo: set height
- t.height = 1.2*t.height
- t.depth = 0.2*t.height
- g.virtualized = true
- local d = g.descriptions
- return t, d and d[c]
+commands["compose.force.disable"] = function()
+ force_combining = false
end
-fallbacks['texteuro'] = function (g)
- local c = utfbyte("C")
- local t = table.fastcopy(g.characters[c],true)
- local d = cos(rad(90+(g.italicangle)))
- local vfspecials = backends.tables.vfspecials
- local green, black
- if trace_combining then
- green, black = vfspecials.green, vfspecials.black
- end
- local quad = g.parameters.quad
- t.width = 1.05*t.width
- if trace_combining then
- t.commands = {
- {"right", .05*t.width},
- push, {"slot", 1, c}, pop,
- {"right", .5*t.width*d},
- {"down", -.5*t.height},
- green,
- {"rule", .05*quad, .4*quad},
- black,
- }
+commands["compose.trace.set"] = function(g,v)
+ if v[2] == nil then
+ trace_combining = true
else
- t.commands = {
- {"right", .05*t.width},
- push, {"slot", 1, c}, pop,
- {"right", .5*t.width*d},
- {"down", -.5*t.height},
- {"rule", .05*quad, .4*quad},
- }
+ trace_combining = v[2]
end
- g.virtualized = true
- return t, g.descriptions[c]
end
+commands["compose.apply"] = function(g,v)
+ composecharacters(g)
+end
-install("fallback", { -- todo: auto-fallback with loop over data.characters
- { "fake-character", 0x00A2, 'textcent' },
- { "fake-character", 0x20AC, 'texteuro' }
-})
-
-install("demo-2", {
- { "enable-tracing" },
- { "enable-force" },
- { "initialize" },
- { "include-method", "fallback" },
- { "complete-composed-characters" },
- { "disable-tracing" },
- { "disable-force" },
-})
-
-install("demo-3", {
- { "enable-tracing" },
- { "initialize" },
- { "complete-composed-characters" },
- { "disable-tracing" },
-})
+-- vf builder
--- end of examples
+-- {'special', 'pdf: q ' .. s .. ' 0 0 '.. s .. ' 0 0 cm'},
+-- {'special', 'pdf: q 1 0 0 1 ' .. -w .. ' ' .. -h .. ' cm'},
+-- {'special', 'pdf: /Fm\XX\space Do'},
+-- {'special', 'pdf: Q'},
+-- {'special', 'pdf: Q'},
diff --git a/tex/context/base/font-gds.lua b/tex/context/base/font-gds.lua
index f5c5a3127..c2ff92fbf 100644
--- a/tex/context/base/font-gds.lua
+++ b/tex/context/base/font-gds.lua
@@ -6,30 +6,32 @@ if not modules then modules = { } end modules ['font-gds'] = {
license = "see context related readme files"
}
+-- depends on ctx
+
local type, next = type, next
local gmatch = string.gmatch
-local trace_goodies = false trackers.register("fonts.goodies", function(v) trace_goodies = v end)
+local fonts, nodes, attributes, node = fonts, nodes, attributes, node
-local report_fonts = logs.reporter("fonts","goodies")
+local trace_goodies = false trackers.register("fonts.goodies", function(v) trace_goodies = v end)
+local report_fonts = logs.reporter("fonts","goodies")
-local allocate = utilities.storage.allocate
+local allocate = utilities.storage.allocate
--- goodies=name,colorscheme=,featureset=
---
--- goodies=auto
+local otffeatures = fonts.constructors.newfeatures("otf")
+local registerotffeature = otffeatures.register
-local fonts, nodes, attributes = fonts, nodes, attributes
-local node = node
+local fontgoodies = { }
+fonts.goodies = fontgoodies
-fonts.goodies = fonts.goodies or { }
-local fontgoodies = fonts.goodies
+local typefaces = allocate()
+fonts.typefaces = typefaces
-fontgoodies.data = allocate() -- fontgoodies.data or { }
-local data = fontgoodies.data
+local data = allocate()
+fontgoodies.data = fontgoodies.data
-fontgoodies.list = fontgoodies.list or { } -- no allocate as we want to see what is there
-local list = fontgoodies.list
+local list = { }
+fontgoodies.list = list -- no allocate as we want to see what is there
function fontgoodies.report(what,trace,goodies)
if trace_goodies or trace then
@@ -71,7 +73,7 @@ local function getgoodies(filename) -- maybe a merge is better
return goodies
end
-function fontgoodies.register(name,fnc)
+function fontgoodies.register(name,fnc) -- will be a proper sequencer
list[name] = fnc
end
@@ -79,10 +81,12 @@ fontgoodies.get = getgoodies
-- register goodies file
-local presetcontext = fonts.definers.specifiers.presetcontext
-
local function setgoodies(tfmdata,value)
- local goodies = tfmdata.goodies or { } -- future versions might store goodies in the cached instance
+ local goodies = tfmdata.goodies
+ if not goodies then -- actually an error
+ goodies = { }
+ tfmdata.goodies = goodies
+ end
for filename in gmatch(value,"[^, ]+") do
-- we need to check for duplicates
local ok = getgoodies(filename)
@@ -90,7 +94,6 @@ local function setgoodies(tfmdata,value)
goodies[#goodies+1] = ok
end
end
- tfmdata.goodies = goodies -- shared ?
end
-- this will be split into good-* files and this file might become good-ini.lua
@@ -120,13 +123,13 @@ local function flattenedfeatures(t,tt)
return tt
end
-fonts.flattenedfeatures = flattenedfeatures
+-- fonts.features.flattened = flattenedfeatures
function fontgoodies.prepare_features(goodies,name,set)
if set then
local ff = flattenedfeatures(set)
local fullname = goodies.name .. "::" .. name
- local n, s = presetcontext(fullname,"",ff)
+ local n, s = fonts.specifiers.presetcontext(fullname,"",ff)
goodies.featuresets[name] = s -- set
if trace_goodies then
report_fonts("feature set '%s' gets number %s and name '%s'",name,n,fullname)
@@ -154,6 +157,7 @@ local function setfeatureset(tfmdata,set)
local goodies = tfmdata.goodies -- shared ?
if goodies then
local features = tfmdata.shared.features
+ local properties = tfmdata.properties
local what
for i=1,#goodies do
-- last one counts
@@ -166,7 +170,7 @@ local function setfeatureset(tfmdata,set)
features[feature] = value
end
end
- tfmdata.mode = features.mode or tfmdata.mode
+ properties.mode = features.mode or properties.mode
end
end
end
@@ -207,7 +211,7 @@ end
-- fontgoodies.postprocessors = fontgoodies.postprocessors or { }
-- local postprocessors = fontgoodies.postprocessors
-
+--
-- function postprocessors.apply(tfmdata)
-- local postprocessors = tfmdata.postprocessors
-- if postprocessors then
@@ -216,12 +220,17 @@ end
-- end
-- end
-- end
+--
+-- function definers.applypostprocessors(tfmdata)
+-- fonts.goodies.postprocessors.apply(tfmdata) -- only here
+-- return tfmdata
+-- end
-- colorschemes
-fontgoodies.colorschemes = fontgoodies.colorschemes or { }
-local colorschemes = fontgoodies.colorschemes
-colorschemes.data = colorschemes.data or { }
+local colorschemes = { }
+fontgoodies.colorschemes = colorschemes
+colorschemes.data = { }
local function setcolorscheme(tfmdata,scheme)
if type(scheme) == "string" then
@@ -237,7 +246,7 @@ local function setcolorscheme(tfmdata,scheme)
if what then
-- this is font bound but we can share them if needed
-- just as we could hash the conversions (per font)
- local hash, reverse = tfmdata.luatex.unicodes, { }
+ local hash, reverse = tfmdata.resources.unicodes, { }
for i=1,#what do
local w = what[i]
for j=1,#w do
@@ -248,16 +257,16 @@ local function setcolorscheme(tfmdata,scheme)
end
end
end
- tfmdata.colorscheme = reverse
+ tfmdata.properties.colorscheme = reverse
return
end
end
end
- tfmdata.colorscheme = false
+ tfmdata.properties.colorscheme = false
end
-local fontdata = fonts.identifiers
-local fcs = fonts.colors.set
+local fontdata = fonts.hashes.identifiers
+local setnodecolor = nodes.tracers.colors.set
local has_attribute = node.has_attribute
local traverse_id = node.traverse_id
local a_colorscheme = attributes.private('colorscheme')
@@ -271,13 +280,13 @@ function colorschemes.coloring(head)
if a then
local f = n.font
if f ~= lastfont then
- lastscheme, lastfont = fontdata[f].colorscheme, f
+ lastscheme, lastfont = fontdata[f].properties.colorscheme, f
end
if lastscheme then
local sc = lastscheme[n.char]
if sc then
done = true
- fcs(n,"colorscheme:"..a..":"..sc) -- slow
+ setnodecolor(n,"colorscheme:"..a..":"..sc) -- slow
end
end
end
@@ -292,44 +301,43 @@ end
-- installation (collected to keep the overview) -- also for type 1
-fonts.otf.tables.features['goodies'] = 'Goodies on top of built in features'
-fonts.otf.tables.features['featureset'] = 'Goodie Feature Set'
-fonts.otf.tables.features['colorscheme'] = 'Goodie Color Scheme'
-fonts.otf.tables.features['postprocessor'] = 'Goodie Postprocessor'
-
-fonts.otf.features.register('goodies')
-fonts.otf.features.register('featureset')
-fonts.otf.features.register('colorscheme')
-fonts.otf.features.register('postprocessor')
-
-table.insert(fonts.triggers, 1, "goodies")
-table.insert(fonts.triggers, 2, "featureset") -- insert after
-table.insert(fonts.triggers, "colorscheme")
-table.insert(fonts.triggers, "postprocessor")
-
-local base_initializers = fonts.initializers.base.otf
-local node_initializers = fonts.initializers.node.otf
-
-base_initializers.goodies = setgoodies
-node_initializers.goodies = setgoodies
-
-base_initializers.featureset = setfeatureset
-node_initializers.featureset = setfeatureset
-
-base_initializers.colorscheme = setcolorscheme
-node_initializers.colorscheme = setcolorscheme
-
-base_initializers.postprocessor = setpostprocessor
-node_initializers.postprocessor = setpostprocessor
+registerotffeature {
+ name = "goodies",
+ description = "goodies on top of built in features",
+ initializers = {
+ position = 1,
+ base = setgoodies,
+ node = setgoodies,
+ }
+}
-local base_initializers = fonts.initializers.base.afm
-local node_initializers = fonts.initializers.node.afm
+registerotffeature {
+ name = "featureset",
+ description = "goodie feature set",
+ initializers = {
+ position = 2,
+ base = setfeatureset,
+ node = setfeatureset,
+ }
+}
-base_initializers.goodies = setgoodies
-node_initializers.goodies = setgoodies
+registerotffeature {
+ name = "colorscheme",
+ description = "goodie color scheme",
+ initializers = {
+ base = setcolorscheme,
+ node = setcolorscheme,
+ }
+}
-base_initializers.postprocessor = setpostprocessor
-node_initializers.postprocessor = setpostprocessor
+registerotffeature {
+ name = "postprocessor",
+ description = "goodie postprocessor",
+ initializers = {
+ base = setpostprocessor,
+ node = setpostprocessor,
+ }
+}
-- experiment, we have to load the definitions immediately as they precede
-- the definition so they need to be initialized in the typescript
@@ -337,23 +345,23 @@ node_initializers.postprocessor = setpostprocessor
local function initialize(goodies)
local mathgoodies = goodies.mathematics
if mathgoodies then
- local virtuals = mathgoodies.virtuals
- local mapfiles = mathgoodies.mapfiles
- local maplines = mathgoodies.maplines
- local variables = mathgoodies.variables
+ local virtuals = mathgoodies.virtuals
+ local mapfiles = mathgoodies.mapfiles
+ local maplines = mathgoodies.maplines
if virtuals then
for name, specification in next, virtuals do
- mathematics.makefont(name,specification,variables)
+ -- beware, they are all constructed
+ mathematics.makefont(name,specification,goodies)
end
end
if mapfiles then
for i=1,#mapfiles do
- fonts.map.loadfile(mapfiles[i]) -- todo: backend function
+ fonts.mappings.loadfile(mapfiles[i]) -- todo: backend function
end
end
if maplines then
for i=1,#maplines do
- fonts.map.loadline(maplines[i]) -- todo: backend function
+ fonts.mappings.loadline(maplines[i]) -- todo: backend function
end
end
end
@@ -382,7 +390,7 @@ local function initialize(goodies)
end
end
-fonts.goodies.register("files", initialize)
+fontgoodies.register("files", initialize)
-- some day we will have a define command and then we can also do some
-- proper tracing
@@ -408,7 +416,7 @@ local function initialize(goodies)
end
end
-fonts.goodies.register("typefaces", initialize)
+fontgoodies.register("typefaces", initialize)
local function initialize(goodies)
local typefaces = goodies.typefaces
@@ -420,12 +428,12 @@ local function initialize(goodies)
end
end
-fonts.goodies.register("typefaces", initialize)
+fontgoodies.register("typefaces", initialize)
local compositions = { }
-function fonts.goodies.getcompositions(tfmdata)
- return compositions[file.nameonly(tfmdata.filename or "")]
+function fontgoodies.getcompositions(tfmdata)
+ return compositions[file.nameonly(tfmdata.properties.filename or "")]
end
local function initialize(goodies)
@@ -437,7 +445,7 @@ local function initialize(goodies)
end
end
-fonts.goodies.register("compositions", initialize)
+fontgoodies.register("compositions", initialize)
-- The following file (husayni.lfg) is the experimental setup that we used
-- for Idris font. For the moment we don't store this in the cache and quite
diff --git a/tex/context/base/font-ini.lua b/tex/context/base/font-ini.lua
index df534c6ad..8eeba0ce7 100644
--- a/tex/context/base/font-ini.lua
+++ b/tex/context/base/font-ini.lua
@@ -6,16 +6,14 @@ if not modules then modules = { } end modules ['font-ini'] = {
license = "see context related readme files"
}
--- The font code will be upgraded and reorganized so that we have a
--- leaner generic code base and can do more tuning for context.
+-- basemethods -> can also be in list
+-- presetcontext -> defaults
+-- hashfeatures -> ctx version
--[[ldx--
<p>Not much is happening here.</p>
--ldx]]--
-local utf = unicode.utf8
-local format, serialize = string.format, table.serialize
-local write_nl = texio.write_nl
local lower = string.lower
local allocate, mark = utilities.storage.allocate, utilities.storage.mark
@@ -23,96 +21,18 @@ local report_defining = logs.reporter("fonts","defining")
fontloader.totable = fontloader.to_table
--- vtf comes first
--- fix comes last
+fonts = fonts or { } -- already defined in context
+local fonts = fonts
-fonts = fonts or { }
+-- some of these might move to where they are used first:
--- beware, some already defined
+fonts.hashes = { identifiers = allocate() }
+fonts.analyzers = { } -- not needed here
+fonts.readers = { }
+fonts.tables = { }
+fonts.definers = { methods = { } }
+fonts.specifiers = fonts.specifiers or { } -- in format !
+fonts.loggers = { register = function() end }
+fonts.helpers = { }
-fonts.identifiers = mark(fonts.identifiers or { }) -- fontdata
------.characters = mark(fonts.characters or { }) -- chardata
------.csnames = mark(fonts.csnames or { }) -- namedata
------.quads = mark(fonts.quads or { }) -- quaddata
-
---~ fonts.identifiers[0] = { -- nullfont
---~ characters = { },
---~ descriptions = { },
---~ name = "nullfont",
---~ }
-
-fonts.tfm = fonts.tfm or { }
-fonts.vf = fonts.vf or { }
-fonts.afm = fonts.afm or { }
-fonts.pfb = fonts.pfb or { }
-fonts.otf = fonts.otf or { }
-
-fonts.privateoffset = 0xF0000 -- 0x10FFFF
-fonts.verbose = false -- more verbose cache tables (will move to context namespace)
-
-fonts.methods = fonts.methods or {
- base = { tfm = { }, afm = { }, otf = { }, vtf = { }, fix = { } },
- node = { tfm = { }, afm = { }, otf = { }, vtf = { }, fix = { } },
-}
-
-fonts.initializers = fonts.initializers or {
- base = { tfm = { }, afm = { }, otf = { }, vtf = { }, fix = { } },
- node = { tfm = { }, afm = { }, otf = { }, vtf = { }, fix = { } }
-}
-
-fonts.triggers = fonts.triggers or {
- 'mode',
- 'language',
- 'script',
- 'strategy',
-}
-
-fonts.processors = fonts.processors or {
-}
-
-fonts.analyzers = fonts.analyzers or {
- useunicodemarks = false,
-}
-
-fonts.manipulators = fonts.manipulators or {
-}
-
-fonts.tracers = fonts.tracers or {
-}
-
-fonts.typefaces = fonts.typefaces or {
-}
-
-fonts.definers = fonts.definers or { }
-fonts.definers.specifiers = fonts.definers.specifiers or { }
-fonts.definers.specifiers.synonyms = fonts.definers.specifiers.synonyms or { }
-
--- tracing
-
-if not fonts.colors then
-
- fonts.colors = allocate {
- set = function() end,
- reset = function() end,
- }
-
-end
-
--- format identification
-
-fonts.formats = allocate()
-
-function fonts.fontformat(filename,default)
- local extname = lower(file.extname(filename))
- local format = fonts.formats[extname]
- if format then
- return format
- else
- report_defining("unable to determine font format for '%s'",filename)
- return default
- end
-end
-
--- readers
-
-fonts.tfm.readers = fonts.tfm.readers or { }
+fonts.tracers = { } -- for the moment till we have move to moduledata
diff --git a/tex/context/base/font-ini.mkiv b/tex/context/base/font-ini.mkiv
index 781f79ad4..69a00450b 100644
--- a/tex/context/base/font-ini.mkiv
+++ b/tex/context/base/font-ini.mkiv
@@ -58,38 +58,50 @@
\writestatus{loading}{ConTeXt Font Macros / Initialization}
\registerctxluafile{font-ini}{1.001}
-\registerctxluafile{font-clr}{1.001}
-\registerctxluafile{node-fnt}{1.001} % here
+\registerctxluafile{font-log}{1.001}
+\registerctxluafile{font-con}{1.001}
\registerctxluafile{font-enc}{1.001}
%registerctxluafile{font-agl}{1.001} % loaded when needed, saves 100K in format
+\registerctxluafile{font-cid}{1.001} % cid maps
\registerctxluafile{font-map}{1.001}
\registerctxluafile{font-syn}{1.001}
-\registerctxluafile{font-log}{1.001}
+
\registerctxluafile{font-tfm}{1.001}
-\registerctxluafile{font-enh}{1.001}
+
\registerctxluafile{font-afm}{1.001}
-\registerctxluafile{font-lua}{1.001}
-\registerctxluafile{font-cid}{1.001} % cid maps
-\registerctxluafile{font-ott}{1.001} % otf tables
-\registerctxluafile{font-otf}{1.001} % otf main
-\registerctxluafile{font-otd}{1.001} % otf dynamics
+
\registerctxluafile{font-oti}{1.001} % otf initialization
+\registerctxluafile{font-ott}{1.001} % otf tables (first)
+\registerctxluafile{font-otf}{1.001} % otf main
\registerctxluafile{font-otb}{1.001} % otf main base
+\registerctxluafile{node-inj}{1.001} % we might split it off
\registerctxluafile{font-otn}{1.001} % otf main node
+\registerctxluafile{font-otd}{1.001} % otf dynamics (does an overload)
\registerctxluafile{font-ota}{1.001} % otf analyzers (needs dynamics)
\registerctxluafile{font-otp}{1.001} % otf pack
\registerctxluafile{font-otc}{1.001} % otf context
\registerctxluafile{font-oth}{1.001} % otf helpers
+
+\registerctxluafile{font-pat}{1.001} % patchers
+
+\registerctxluafile{node-fnt}{1.001} % here
+
+\registerctxluafile{font-lua}{1.001}
+
\registerctxluafile{font-vf} {1.001}
+\registerctxluafile{font-enh}{1.001}
+
+\registerctxluafile{font-gds}{1.001} % currently only otf
+
\registerctxluafile{font-def}{1.001}
\registerctxluafile{font-ctx}{1.001} % after def as it overloads
-\registerctxluafile{font-xtx}{1.001}
-\registerctxluafile{font-gds}{1.001}
-\registerctxluafile{font-fbk}{1.001}
+
\registerctxluafile{font-ext}{1.001}
-\registerctxluafile{font-pat}{1.001}
+\registerctxluafile{font-fbk}{1.001}
\registerctxluafile{font-chk}{1.001}
+\registerctxluafile{font-aux}{1.001}
+
\unprotect
% \def\fontrange#1%
@@ -169,9 +181,11 @@
\let\thedefinedfont\relax
\def\dodefinedfont[#1]%
- {\iffirstargument\definefont[thedefinedfont][#1]\fi % we can speed this one up
+ {\setfalse\inheritfromfontclass
+ \iffirstargument\definefont[thedefinedfont][#1]\fi % we can speed this one up
\thedefinedfont
- \the\everydefinedfont}
+ \the\everydefinedfont
+ \settrue\inheritfromfontclass}
\unexpanded\def\definedfont
{\dosingleempty\dodefinedfont}
@@ -687,6 +701,8 @@
\let\relativefontid\empty
+\newconditional\inheritfromfontclass % used in \definefont and \definedfont
+
\unexpanded\def\lowleveldefinefont#1#2% #2 = cs
{% we can now set more at the lua end
\ctxlua{fonts.definers.stage_one("\luaescapestring{#1}")}% the escapestring catches at \somedimen
@@ -726,14 +742,14 @@
"#2", % cs, trailing % is gone
"\somefontfile",
\number\scaledfontsize,
- "\@@fontclassfeatures",
+ "\ifconditional\inheritfromfontclass\@@fontclassfeatures\fi",
"\@@fontfeatures",
- "\@@fontclassfallbacks",
+ "\ifconditional\inheritfromfontclass\@@fontclassfallbacks\fi",
"\@@fontfallbacks",
0\currentmathsize,
\number\dimexpr\textface\relax,
"\relativefontid", % experiment
- "\@@fontclassgoodies", % experiment (not yet used)
+ "\ifconditional\inheritfromfontclass\@@fontclassgoodies\fi", % experiment (not yet used)
"\@@fontgoodies" % experiment
)}%
% \edef\somefontspec{at \somefontsize}% we need the resolved designsize (for fallbacks)
@@ -1167,7 +1183,8 @@
\def\newfontidentifier{*\fontclass\lastfontidentifier\fontstyle\fontsize*}
\def\dododefinefont#1#2%
- {\edef\lastfontidentifier{#1}%
+ {\setfalse\inheritfromfontclass
+ \edef\lastfontidentifier{#1}%
\let\localrelativefontsize\defaultrelativefontsize
\let\localabsolutefontsize\fontbody
\lowleveldefinefont{#2}\rawfontidentifier
@@ -1175,7 +1192,8 @@
\autofontsizefalse
\setfontcharacteristics
\the\everyfontswitch
- \let\rawfontidentifier\oldrawfontidentifier}
+ \let\rawfontidentifier\oldrawfontidentifier
+ \settrue\inheritfromfontclass}
\def\xxdododefinefont#1#2#3#4% \autofontsizetrue is set by calling routine
{\edef\lastfontidentifier{#3}%
@@ -1969,10 +1987,10 @@
% \s!pt}}
\def\normalizebodyfontsize#1\to#2%
- {\edef#2{\ctxlua{fonts.nbfs(\number\dimexpr#1\relax,\number\fontdigits)}}}
+ {\edef#2{\ctxcommand{nbfs(\number\dimexpr#1\relax,\number\fontdigits)}}}
\def\thenormalizedbodyfontsize#1%
- {\ctxlua{fonts.nbfs(\number\dimexpr#1\relax,\number\fontdigits)}}
+ {\ctxcommand{nbfs(\number\dimexpr#1\relax,\number\fontdigits)}}
\edef\normalizedglobalbodyfontsize{\thenormalizedbodyfontsize\bodyfontsize}
\edef\normalizedlocalbodyfontsize {\thenormalizedbodyfontsize\bodyfontsize}
@@ -2825,10 +2843,6 @@
% \installfontfeature[otf][tlig]
% \installfontfeature[otf][trep]
-%D tricky but ok:
-
-\appendtoks\ctxlua{fonts.tfm.cleanup()}\to\everyshipout
-
%D Todo:
% \def\os{\groupedcommand{\setfontfeature{oldstyle}}{}}
@@ -2840,54 +2854,79 @@
\def\dodefinefontfeature[#1][#2][#3]%
{\global\expandafter\chardef\csname\??fq=#1\endcsname % beware () needed as we get two values returned
- \ctxlua{tex.write((fonts.definers.specifiers.presetcontext("#1","#2","#3")))}\relax}
+ \ctxsprint{((fonts.specifiers.presetcontext("#1","#2","#3")))}\relax}
\definefontfeature
[default]
- [%mode=node,
- liga=yes,kern=yes,tlig=yes,trep=yes] % texligatures=yes,texquotes=yes
+ [mode=auto, % was nothing
+ liga=yes,
+ kern=yes,
+ tlig=yes,
+ trep=yes] % texligatures=yes,texquotes=yes
\definefontfeature
[smallcaps]
- [%mode=node,liga=yes,
- smcp=yes,kern=yes,tlig=yes,trep=yes] % texligatures=yes,texquotes=yes
+ [mode=auto, % was nothing
+ smcp=yes,
+ kern=yes,
+ tlig=yes,
+ trep=yes] % texligatures=yes,texquotes=yes
\definefontfeature
[oldstyle]
- [%mode=node,
- onum=yes,liga=yes,kern=yes,tlig=yes,trep=yes] % texligatures=yes,texquotes=yes
+ [mode=auto, % was nothing
+ onum=yes,
+ liga=yes,
+ kern=yes,
+ tlig=yes,
+ trep=yes] % texligatures=yes,texquotes=yes
\definefontfeature % == default unless redefined
[ligatures]
- [%mode=node,
- liga=yes,kern=yes,tlig=yes,trep=yes]
+ [mode=auto, % was nothing
+ liga=yes,
+ kern=yes,
+ tlig=yes,
+ trep=yes]
\definefontfeature % can be used for type1 fonts
[complete]
- [liga=yes,kern=yes,compose=yes,tlig=yes,trep=yes]
+ [mode=auto, % was nothing
+ liga=yes,
+ kern=yes,
+ compose=yes,
+ tlig=yes,
+ trep=yes]
\definefontfeature
- [arabic] % this will become obsolete
+ [none]
+ [mode=none,
+ features=no]
+
+\definefontfeature % might move
+ [arabic]
[mode=node,language=dflt,script=arab,ccmp=yes,
init=yes,medi=yes,fina=yes,isol=yes,
liga=yes,dlig=yes,rlig=yes,clig=yes,calt=yes,
mark=yes,mkmk=yes,kern=yes,curs=yes]
-\definefontfeature
+\definefontfeature % might move
[simplearabic]
[mode=node,language=dflt,script=arab,
init=yes,medi=yes,fina=yes,calt=yes,
rlig=yes,curs=yes,mark=yes,mkmk=yes]
-\definefontfeature
- [none]
- [mode=none,features=no]
+% math:
\definefontfeature
[virtualmath]
- [mode=base,liga=yes,kern=yes,tlig=yes,trep=yes,language=dflt,script=math]
-
-% for the moment here, this will change but we need it for mk.tex
+ [mode=base,
+ liga=yes,
+ kern=yes,
+ tlig=yes,
+ trep=yes,
+ language=dflt,
+ script=math]
\definefontfeature[math-text] [virtualmath][mathalternates=yes,ssty=no]
\definefontfeature[math-script] [virtualmath][mathalternates=yes,ssty=1,mathsize=yes]
@@ -2903,10 +2942,7 @@
%D Also new, handy for manuals:
-\unexpanded\def\fontchar#1{\ctxlua{fonts.char("#1")}}
-
-\let\otfchar\fontchar % will disappear, for compatibility only
-\let\afmchar\fontchar % will disappear, for compatibility only
+\unexpanded\def\fontchar#1{\ctxcommand{fontchar("#1")}}
%D: We cannot yet inherit because no colors are predefined.
@@ -2942,7 +2978,7 @@
{\dodoubleargument\dofontfeatureslist}
\def\dofontfeatureslist[#1][#2]% todo: arg voor type
- {\ctxsprint{fonts.definers.specifiers.contexttostring("#1","otf","\luaescapestring{#2}","yes","no",true,{"number"})}}
+ {\ctxsprint{fonts.specifiers.contexttostring("#1","otf","\luaescapestring{#2}","yes","no",true,{"number"})}}
\attribute\zerocount\zerocount % first in list, so fast match
@@ -2963,14 +2999,24 @@
%
% \typebuffer \getbuffer
-\def\featureattribute#1{\ctxlua{tex.sprint(fonts.definers.specifiers.contextnumber("#1"))}}
-\def\setfontfeature #1{\edef\currentfeature{#1}\attribute\zerocount\featureattribute{#1}\relax}
-\def\resetfontfeature#1{\let\currentfeature\empty\attribute\zerocount\zerocount} % initial value
+% \unexpanded\def\featureattribute#1{\ctxsprint{fonts.specifiers.contextnumber("#1"))}}
+% \unexpanded\def\setfontfeature #1{\edef\currentfeature{#1}\attribute\zerocount\featureattribute{#1}\relax}
+% \unexpanded\def\resetfontfeature#1{\let\currentfeature\empty\attribute\zerocount\zerocount} % initial value
+
+% \def\addfontfeaturetoset #1{\ctxlua{fonts.withset("#1", 1)}} % merge
+% \def\subtractfontfeaturefromset #1{\ctxlua{fonts.withset("#1",-1)}} % merge
+% \def\addfontfeaturetofont #1{\ctxlua{fonts.withfnt("#1", 2)}} % overload
+% \def\subtractfontfeaturefromfont#1{\ctxlua{fonts.withfnt("#1",-2)}} % overload
+
+\unexpanded\def\featureattribute#1{\ctxcommand{featureattribute("#1")}}
+\unexpanded\def\setfontfeature #1{\ctxcommand{setfontfeature("#1")}\edef\currentfeature{#1}}
+\unexpanded\def\resetfontfeature#1{\ctxcommand{resetfontfeature()}\let\currentfeature\empty} % initial value
+\unexpanded\def\resetfontfeature#1{\attribute\zerocount\zerocount\let\currentfeature\empty} % initial value
-\def\addfontfeaturetoset #1{\ctxlua{fonts.withset("#1", 1)}} % merge
-\def\subtractfontfeaturefromset #1{\ctxlua{fonts.withset("#1",-1)}} % merge
-\def\addfontfeaturetofont #1{\ctxlua{fonts.withfnt("#1", 2)}} % overload
-\def\subtractfontfeaturefromfont#1{\ctxlua{fonts.withfnt("#1",-2)}} % overload
+\unexpanded\def\addfontfeaturetoset #1{\ctxcommand{addfs("#1")}} % merge
+\unexpanded\def\subtractfontfeaturefromset #1{\ctxcommand{subfs("#1")}} % merge
+\unexpanded\def\addfontfeaturetofont #1{\ctxcommand{addff("#1")}} % overload
+\unexpanded\def\subtractfontfeaturefromfont#1{\ctxcommand{subff("#1")}} % overload
\let\setff\setfontfeature
\let\addfs\addfontfeaturetoset
@@ -4303,8 +4349,8 @@
%D goodies:
-\def\showchardata#1{\ctxlua{fonts.showchardata("#1")}}
-\def\showfontdata {\ctxlua{fonts.showfontparameters()}}
+\unexpanded\def\showchardata#1{\ctxcommand{showchardata("#1")}}
+\unexpanded\def\showfontdata {\ctxcommand{showfontparameters()}}
%D some low level helpers
%D
@@ -4325,11 +4371,11 @@
% we can also move the lookups to the fonts.namespace (of commands)
-\def\dolookupfontbyspec #1{\ctxlua{fonts.names.lookup("#1")}}
-\def\dolookupnoffound {\ctxlua{tex.write(fonts.names.noflookups())}}
-\def\dolookupgetkeyofindex#1#2{\ctxlua{tex.write(fonts.names.getlookupkey("#1",#2))}}
-\def\dolookupgetkey #1{\ctxlua{tex.write(fonts.names.getlookupkey("#1"))}}
-\def\cleanfontname #1{\ctxlua{fonts.cleanname("#1")}}
+\def\dolookupfontbyspec #1{\ctxcommand{fontlookupinitialize("#1")}}
+\def\dolookupnoffound {\ctxcommand{fontlookupnoffound()}}
+\def\dolookupgetkeyofindex#1#2{\ctxcommand{fontlookupgetkeyofindex("#1",#2))}}
+\def\dolookupgetkey #1{\ctxcommand{fontlookupgetkey("#1")}}
+\def\cleanfontname #1{\ctxcommand{cleanfontname("#1")}}
% \doifelsecurrentfonthasfeature{smcp}{YES}{NO}
% \doifelsecurrentfonthasfeature{crap}{YES}{NO}
diff --git a/tex/context/base/font-log.lua b/tex/context/base/font-log.lua
index 0dbde8e39..5f18c52cb 100644
--- a/tex/context/base/font-log.lua
+++ b/tex/context/base/font-log.lua
@@ -8,13 +8,16 @@ if not modules then modules = { } end modules ['font-log'] = {
local next, format, lower, concat = next, string.format, string.lower, table.concat
-local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
-
+local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
local report_defining = logs.reporter("fonts","defining")
-local fonts = fonts
-fonts.logger = fonts.logger or { }
-local logger = fonts.logger
+local basename = file.basename
+
+local fonts = fonts
+local loggers = { }
+fonts.loggers = loggers
+local usedfonts = utilities.storage.allocate()
+----- loadedfonts = utilities.storage.allocate()
--[[ldx--
<p>The following functions are used for reporting about the fonts
@@ -23,41 +26,55 @@ we now have several readers it may be handy to know what reader is
used for which font.</p>
--ldx]]--
-function logger.save(tfmtable,source,specification) -- save file name in spec here ! ! ! ! ! !
- if tfmtable and specification and specification.specification then
- local name = lower(specification.name)
- if trace_defining and not fonts.used[name] then
- report_defining("registering %s as %s (used: %s)",file.basename(specification.name),source,file.basename(specification.filename))
+function loggers.onetimemessage(font,char,message,reporter)
+ local tfmdata = fonts.hashes.identifiers[font]
+ local shared = tfmdata.shared
+ local messages = shared.messages
+ if not messages then
+ messages = { }
+ shared.messages = messages
+ end
+ local category = messages[message]
+ if not category then
+ category = { }
+ messages[message] = category
+ end
+ if not category[char] then
+ if not reporter then
+ reporter = report_defining
end
- specification.source = source
- fonts.loaded[lower(specification.specification)] = specification
- -- fonts.used[name] = source
- fonts.used[lower(specification.filename or specification.name)] = source
+ reporter("char U+%04X in font '%s' with id %s: %s",char,tfmdata.properties.fullname,font,message)
+ category[char] = true
end
end
-function logger.report(complete)
- local t, n = { }, 0
- for name, used in table.sortedhash(fonts.used) do
- n = n + 1
- if complete then
- t[n] = used .. "->" .. file.basename(name)
- else
- t[n] = file.basename(name)
+function loggers.register(tfmdata,source,specification) -- save file name in spec here ! ! ! ! ! !
+ if tfmdata and specification and specification.specification then
+ local name = lower(specification.name)
+ if trace_defining and not fonts.used[name] then
+ report_defining("registering %s as %s (used: %s)",file.basename(specification.name),source,file.basename(specification.filename))
end
+ specification.source = source
+ -- loadedfonts[lower(specification.specification)] = specification
+ usedfonts[lower(specification.filename or specification.name)] = source
end
- return t
end
-function logger.format(name)
- return fonts.used[name] or "unknown"
+function loggers.format(name) -- should be avoided
+ return usedfonts[name] or "unknown"
end
statistics.register("loaded fonts", function()
- if next(fonts.used) then
- local t = logger.report()
- return (#t > 0 and format("%s files: %s",#t,concat(t," "))) or "none"
- else
- return nil
+ if next(usedfonts) then
+ local t, n = { }, 0
+ for name, used in table.sortedhash(usedfonts) do
+ n = n + 1
+ if complete then
+ t[n] = used .. "->" .. basename(name)
+ else
+ t[n] = basename(name)
+ end
+ end
+ return (n > 0 and format("%s files: %s",n,concat(t," "))) or "none"
end
end)
diff --git a/tex/context/base/font-lua.lua b/tex/context/base/font-lua.lua
index a6fcc1642..48ce3c2f5 100644
--- a/tex/context/base/font-lua.lua
+++ b/tex/context/base/font-lua.lua
@@ -8,11 +8,13 @@ if not modules then modules = { } end modules ['font-lua'] = {
local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
-local report_lua = logs.reporter("fonts","lua loading")
+local report_lua = logs.reporter("fonts","lua loading")
-fonts.formats.lua = "lua"
+local fonts = fonts
+local readers = fonts.readers
+fonts.formats.lua = "lua"
-local readers = fonts.tfm.readers
+-- we could add support for features here
local function check_lua(specification,fullname)
-- standard tex file lookup
@@ -24,22 +26,21 @@ local function check_lua(specification,fullname)
end
end
+readers.check_lua = check_lua
+
function readers.lua(specification)
local original = specification.specification
if trace_defining then
report_lua("using lua reader for '%s'",original)
end
- local fullname, tfmtable = specification.filename or "", nil
+ local fullname = specification.filename or ""
if fullname == "" then
local forced = specification.forced or ""
if forced ~= "" then
- tfmtable = check_lua(specification,specification.name .. "." .. forced)
- end
- if not tfmtable then
- tfmtable = check_lua(specification,specification.name)
+ fullname = specification.name .. "." .. forced
+ else
+ fullname = specification.name
end
- else
- tfmtable = check_lua(specification,fullname)
end
- return tfmtable
+ return check_lua(specification,fullname)
end
diff --git a/tex/context/base/font-map.lua b/tex/context/base/font-map.lua
index 26b22b678..0733f245c 100644
--- a/tex/context/base/font-map.lua
+++ b/tex/context/base/font-map.lua
@@ -6,15 +6,18 @@ if not modules then modules = { } end modules ['font-map'] = {
license = "see context related readme files"
}
-local utf = unicode.utf8
local match, format, find, concat, gsub, lower = string.match, string.format, string.find, table.concat, string.gsub, string.lower
-local lpegmatch = lpeg.match
+local P, R, S, C, Ct, Cc, lpegmatch = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Ct, lpeg.Cc, lpeg.match
local utfbyte = utf.byte
-local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
-local trace_unimapping = false trackers.register("otf.unimapping", function(v) trace_unimapping = v end)
+local trace_loading = false trackers.register("fonts.loading", function(v) trace_loading = v end)
+local trace_mapping = false trackers.register("fonts.mapping", function(v) trace_unimapping = v end)
-local report_otf = logs.reporter("fonts","otf loading")
+local report_fonts = logs.reporter("fonts","loading") -- not otf only
+
+local fonts = fonts
+local mappings = { }
+fonts.mappings = mappings
--[[ldx--
<p>Eventually this code will disappear because map files are kind
@@ -22,23 +25,18 @@ of obsolete. Some code may move to runtime or auxiliary modules.</p>
<p>The name to unciode related code will stay of course.</p>
--ldx]]--
-local fonts = fonts
-fonts.map = fonts.map or { }
-
local function loadlumtable(filename) -- will move to font goodies
local lumname = file.replacesuffix(file.basename(filename),"lum")
local lumfile = resolvers.findfile(lumname,"map") or ""
if lumfile ~= "" and lfs.isfile(lumfile) then
- if trace_loading or trace_unimapping then
- report_otf("enhance: loading %s ",lumfile)
+ if trace_loading or trace_mapping then
+ report_fonts("enhance: loading %s ",lumfile)
end
lumunic = dofile(lumfile)
return lumunic, lumfile
end
end
-local P, R, S, C, Ct, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Ct, lpeg.Cc
-
local hex = R("AF","09")
local hexfour = (hex*hex*hex*hex) / function(s) return tonumber(s,16) end
local hexsix = (hex^1) / function(s) return tonumber(s,16) end
@@ -65,8 +63,8 @@ local function makenameparser(str)
end
end
---~ local parser = fonts.map.makenameparser("Japan1")
---~ local parser = fonts.map.makenameparser()
+--~ local parser = mappings.makenameparser("Japan1")
+--~ local parser = mappings.makenameparser()
--~ local function test(str)
--~ local b, a = lpegmatch(parser,str)
--~ print((a and table.serialize(b)) or b)
@@ -107,7 +105,7 @@ end
--~
--~ local cache = { }
--~
---~ function fonts.map.tounicode16(unicode)
+--~ function mappings.tounicode16(unicode)
--~ local s = cache[unicode]
--~ if not s then
--~ if unicode < 0x10000 then
@@ -120,10 +118,10 @@ end
--~ return s
--~ end
-fonts.map.loadlumtable = loadlumtable
-fonts.map.makenameparser = makenameparser
-fonts.map.tounicode16 = tounicode16
-fonts.map.tounicode16sequence = tounicode16sequence
+mappings.loadlumtable = loadlumtable
+mappings.makenameparser = makenameparser
+mappings.tounicode16 = tounicode16
+mappings.tounicode16sequence = tounicode16sequence
local separator = S("_.")
local other = C((1 - separator)^1)
@@ -135,8 +133,11 @@ local ligsplitter = Ct(other * (separator * other)^0)
--~ print(table.serialize(lpegmatch(ligsplitter,"such_so_more")))
--~ print(table.serialize(lpegmatch(ligsplitter,"such_so_more.that")))
-fonts.map.addtounicode = function(data,filename)
- local unicodes = data.luatex and data.luatex.unicodes
+function mappings.addtounicode(data,filename)
+ local resources = data.resources
+ local properties = data.properties
+ local descriptions = data.descriptions
+ local unicodes = resources.unicodes
if not unicodes then
return
end
@@ -146,28 +147,35 @@ fonts.map.addtounicode = function(data,filename)
unicodes['zwj'] = unicodes['zwj'] or 0x200D
unicodes['zwnj'] = unicodes['zwnj'] or 0x200C
-- the tounicode mapping is sparse and only needed for alternatives
- local tounicode, originals, ns, nl, private, unknown = { }, { }, 0, 0, fonts.privateoffset, format("%04X",utfbyte("?"))
- data.luatex.tounicode, data.luatex.originals = tounicode, originals
+ local private = fonts.constructors.privateoffset
+ local unknown = format("%04X",utfbyte("?"))
+ local unicodevector = fonts.encodings.agl.unicodes -- loaded runtime in context
+ local tounicode = { }
+ local originals = { }
+ resources.tounicode = tounicode
+ resources.originals = originals
local lumunic, uparser, oparser
+ local cidinfo, cidnames, cidcodes, usedmap
if false then -- will become an option
lumunic = loadlumtable(filename)
lumunic = lumunic and lumunic.tounicode
end
- local cidinfo, cidnames, cidcodes = data.cidinfo
- local usedmap = cidinfo and cidinfo.usedname
- usedmap = usedmap and lower(usedmap)
- usedmap = usedmap and fonts.cid.map[usedmap]
+ --
+ cidinfo = properties.cidinfo
+ usedmap = cidinfo and fonts.cid.getmap(cidinfo)
+ --
if usedmap then
- oparser = usedmap and makenameparser(cidinfo.ordering)
+ oparser = usedmap and makenameparser(cidinfo.ordering)
cidnames = usedmap.names
cidcodes = usedmap.unicodes
end
uparser = makenameparser()
- local unicodevector = fonts.enc.agl.unicodes -- loaded runtime in context
- for index, glyph in next, data.glyphs do
- local name, unic = glyph.name, glyph.unicode or -1 -- play safe
+ local ns, nl = 0, 0
+ for unic, glyph in next, descriptions do
+ local index = glyph.index
+ local name = glyph.name
if unic == -1 or unic >= private or (unic >= 0xE000 and unic <= 0xF8FF) or unic == 0xFFFE or unic == 0xFFFF then
- local unicode = (lumunic and lumunic[name]) or unicodevector[name]
+ local unicode = lumunic and lumunic[name] or unicodevector[name]
if unicode then
originals[index], tounicode[index], ns = unicode, tounicode16(unicode), ns + 1
end
@@ -258,17 +266,19 @@ fonts.map.addtounicode = function(data,filename)
end
end
end
- if trace_unimapping then
- for index, glyph in table.sortedhash(data.glyphs) do
- local toun, name, unic = tounicode[index], glyph.name, glyph.unicode or -1 -- play safe
+ if trace_mapping then
+ for unic, glyph in table.sortedhash(descriptions) do
+ local name = glyph.name
+ local index = glyph.index
+ local toun = tounicode[index]
if toun then
- report_otf("internal: 0x%05X, name: %s, unicode: 0x%05X, tounicode: %s",index,name,unic,toun)
+ report_fonts("internal: 0x%05X, name: %s, unicode: 0x%05X, tounicode: %s",index,name,unic,toun)
else
- report_otf("internal: 0x%05X, name: %s, unicode: 0x%05X",index,name,unic)
+ report_fonts("internal: 0x%05X, name: %s, unicode: 0x%05X",index,name,unic)
end
end
end
if trace_loading and (ns > 0 or nl > 0) then
- report_otf("enhance: %s tounicode entries added (%s ligatures)",nl+ns, ns)
+ report_fonts("enhance: %s tounicode entries added (%s ligatures)",nl+ns, ns)
end
end
diff --git a/tex/context/base/font-mis.lua b/tex/context/base/font-mis.lua
index 954135be1..979288913 100644
--- a/tex/context/base/font-mis.lua
+++ b/tex/context/base/font-mis.lua
@@ -1,6 +1,6 @@
if not modules then modules = { } end modules ['font-mis'] = {
version = 1.001,
- comment = "companion to luatex-fonts.tex",
+ comment = "companion to mtx-fonts",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
@@ -9,12 +9,23 @@ if not modules then modules = { } end modules ['font-mis'] = {
local next = next
local lower, strip = string.lower, string.strip
-fonts.otf = fonts.otf or { }
+-- also used in other scripts so we need to check some tables:
-fonts.otf.version = fonts.otf.version or 2.710
-fonts.otf.cache = containers.define("fonts", "otf", fonts.otf.version, true)
+fonts = fonts or { }
-function fonts.otf.loadcached(filename,format,sub)
+fonts.helpers = fonts.helpers or { }
+local helpers = fonts.helpers
+
+fonts.handlers = fonts.handlers or { }
+local handlers = fonts.handlers
+
+handlers.otf = handlers.otf or { }
+local otf = handlers.otf
+
+otf.version = otf.version or 2.710
+otf.cache = otf.cache or containers.define("fonts", "otf", otf.version, true)
+
+function otf.loadcached(filename,format,sub)
-- no recache when version mismatch
local name = file.basename(file.removesuffix(filename))
if sub == "" then sub = false end
@@ -23,9 +34,9 @@ function fonts.otf.loadcached(filename,format,sub)
hash = hash .. "-" .. sub
end
hash = containers.cleanname(hash)
- local data = containers.read(fonts.otf.cache, hash)
+ local data = containers.read(otf.cache, hash)
if data and not data.verbose then
- fonts.otf.enhancers.unpack(data)
+ otf.enhancers.unpack(data)
return data
else
return nil
@@ -34,14 +45,14 @@ end
local featuregroups = { "gsub", "gpos" }
-function fonts.get_features(name,t,script,language)
+function fonts.helpers.getfeatures(name,t,script,language) -- maybe per font type
local t = lower(t or (name and file.extname(name)) or "")
if t == "otf" or t == "ttf" or t == "ttc" or t == "dfont" then
local filename = resolvers.findfile(name,t) or ""
if filename ~= "" then
- local data = fonts.otf.loadcached(filename)
- if data and data.luatex and data.luatex.features then
- return data.luatex.features
+ local data = otf.loadcached(filename)
+ if data and data.resources and data.resources.features then
+ return data.resources.features
else
local ff = fontloader.open(filename)
if ff then
diff --git a/tex/context/base/font-ota.lua b/tex/context/base/font-ota.lua
index f972d289f..8ca9d8e6a 100644
--- a/tex/context/base/font-ota.lua
+++ b/tex/context/base/font-ota.lua
@@ -13,50 +13,110 @@ local type, tostring, match, format, concat = type, tostring, string.match, stri
if not trackers then trackers = { register = function() end } end
local trace_analyzing = false trackers.register("otf.analyzing", function(v) trace_analyzing = v end)
-local trace_cjk = false trackers.register("cjk.injections", function(v) trace_cjk = v end)
-
-trackers.register("cjk.analyzing","otf.analyzing")
local fonts, nodes = fonts, nodes
local node = node
-local otf = fonts.otf
-local tfm = fonts.tfm
+local otf = fonts.handlers.otf
+
+local analyzers = fonts.analyzers
+local initializers = { }
+local methods = { }
+
+analyzers.initializers = initializers
+analyzers.methods = methods
+analyzers.useunicodemarks = false
-fonts.analyzers = fonts.analyzers or { }
-local analyzers = fonts.analyzers
+local nodecodes = nodes.nodecodes
+local glyph_code = nodecodes.glyph
-analyzers.initializers = analyzers.initializers or { node = { otf = { } } }
-analyzers.methods = analyzers.methods or { node = { otf = { } } }
+local set_attribute = node.set_attribute
+local has_attribute = node.has_attribute
+local traverse_id = node.traverse_id
+local traverse_node_list = node.traverse
-local initializers = analyzers.initializers
-local methods = analyzers.methods
+local fontdata = fonts.hashes.identifiers
+local state = attributes.private('state')
+local categories = characters and characters.categories or { } -- sorry, only in context
-local nodecodes = nodes.nodecodes
-local glyph_code = nodecodes.glyph
+local tracers = nodes.tracers
+local colortracers = tracers and tracers.colors
+local setnodecolor = colortracers and colortracers.set or function() end
+local resetnodecolor = colortracers and colortracers.reset or function() end
-local set_attribute = node.set_attribute
-local has_attribute = node.has_attribute
-local traverse_id = node.traverse_id
-local traverse_node_list = node.traverse
+local otffeatures = fonts.constructors.newfeatures("otf")
+local registerotffeature = otffeatures.register
-local fontdata = fonts.identifiers
-local state = attributes.private('state')
-local categories = characters and characters.categories or { } -- sorry, only in context
+--[[ldx--
+<p>Analyzers run per script and/or language and are needed in order to
+process features right.</p>
+--ldx]]--
-local fontscolors = fonts.colors
-local fcs = (fontscolors and fontscolors.set) or function() end
-local fcr = (fontscolors and fontscolors.reset) or function() end
+-- todo: analyzers per script/lang, cross font, so we need an font id hash -> script
+-- e.g. latin -> hyphenate, arab -> 1/2/3 analyze -- its own namespace
+-- an example analyzer (should move to font-ota.lua)
+
+local state = attributes.private('state')
+
+function analyzers.setstate(head,font)
+ local useunicodemarks = analyzers.useunicodemarks
+ local tfmdata = fontdata[font]
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local first, last, current, n, done = nil, nil, head, 0, false -- maybe make n boolean
+ while current do
+ local id = current.id
+ if id == glyph_code and current.font == font then
+ local char = current.char
+ local d = descriptions[char]
+ if d then
+ if d.class == "mark" or (useunicodemarks and categories[char] == "mn") then
+ done = true
+ set_attribute(current,state,5) -- mark
+ elseif n == 0 then
+ first, last, n = current, current, 1
+ set_attribute(current,state,1) -- init
+ else
+ last, n = current, n+1
+ set_attribute(current,state,2) -- medi
+ end
+ else -- finish
+ if first and first == last then
+ set_attribute(last,state,4) -- isol
+ elseif last then
+ set_attribute(last,state,3) -- fina
+ end
+ first, last, n = nil, nil, 0
+ end
+ elseif id == disc_code then
+ -- always in the middle
+ set_attribute(current,state,2) -- midi
+ last = current
+ else -- finish
+ if first and first == last then
+ set_attribute(last,state,4) -- isol
+ elseif last then
+ set_attribute(last,state,3) -- fina
+ end
+ first, last, n = nil, nil, 0
+ end
+ current = current.next
+ end
+ if first and first == last then
+ set_attribute(last,state,4) -- isol
+ elseif last then
+ set_attribute(last,state,3) -- fina
+ end
+ return head, done
+end
-- in the future we will use language/script attributes instead of the
-- font related value, but then we also need dynamic features which is
-- somewhat slower; and .. we need a chain of them
-local scriptandlanguage = otf.scriptandlanguage
-
-function fonts.initializers.node.otf.analyze(tfmdata,value,attr)
- local script, language = otf.scriptandlanguage(tfmdata,attr)
+local function analyzeinitializer(tfmdata,value) -- attr
+ local script, language = otf.scriptandlanguage(tfmdata) -- attr
local action = initializers[script]
if action then
if type(action) == "function" then
@@ -68,10 +128,9 @@ function fonts.initializers.node.otf.analyze(tfmdata,value,attr)
end
end
end
- return nil
end
-function fonts.methods.node.otf.analyze(head,font,attr)
+local function analyzeprocessor(head,font,attr)
local tfmdata = fontdata[font]
local script, language = otf.scriptandlanguage(tfmdata,attr)
local action = methods[script]
@@ -88,12 +147,22 @@ function fonts.methods.node.otf.analyze(head,font,attr)
return head, false
end
-otf.features.register("analyze",true) -- we always analyze
-table.insert(fonts.triggers,"analyze") -- we need a proper function for doing this
+registerotffeature {
+ name = "analyze",
+ description = "analysis of (for instance) character classes",
+ default = true,
+ initializers = {
+ node = analyzeinitializer,
+ },
+ processors = {
+ position = 1,
+ node = analyzeprocessor,
+ }
+}
-- latin
-analyzers.methods.latn = analyzers.aux.setstate
+methods.latn = analyzers.setstate
-- this info eventually will go into char-def
@@ -175,10 +244,10 @@ local function warning(current,what)
end
end
-function analyzers.methods.nocolor(head,font,attr)
+function methods.nocolor(head,font,attr)
for n in traverse_id(glyph_code,head) do
if not font or n.font == font then
- fcr(n)
+ resetnodecolor(n)
end
end
return head, true
@@ -190,22 +259,22 @@ local function finish(first,last)
local fc = first.char
if isol_fina_medi_init[fc] or isol_fina[fc] then
set_attribute(first,state,4) -- isol
- if trace_analyzing then fcs(first,"font:isol") end
+ if trace_analyzing then setnodecolor(first,"font:isol") end
else
warning(first,"isol")
set_attribute(first,state,0) -- error
- if trace_analyzing then fcr(first) end
+ if trace_analyzing then resetnodecolor(first) end
end
else
local lc = last.char
if isol_fina_medi_init[lc] or isol_fina[lc] then -- why isol here ?
-- if laststate == 1 or laststate == 2 or laststate == 4 then
set_attribute(last,state,3) -- fina
- if trace_analyzing then fcs(last,"font:fina") end
+ if trace_analyzing then setnodecolor(last,"font:fina") end
else
warning(last,"fina")
set_attribute(last,state,0) -- error
- if trace_analyzing then fcr(last) end
+ if trace_analyzing then resetnodecolor(last) end
end
end
first, last = nil, nil
@@ -214,21 +283,21 @@ local function finish(first,last)
local fc = first.char
if isol_fina_medi_init[fc] or isol_fina[fc] then
set_attribute(first,state,4) -- isol
- if trace_analyzing then fcs(first,"font:isol") end
+ if trace_analyzing then setnodecolor(first,"font:isol") end
else
warning(first,"isol")
set_attribute(first,state,0) -- error
- if trace_analyzing then fcr(first) end
+ if trace_analyzing then resetnodecolor(first) end
end
first = nil
end
return first, last
end
-function analyzers.methods.arab(head,font,attr) -- maybe make a special version with no trace
+function methods.arab(head,font,attr) -- maybe make a special version with no trace
local useunicodemarks = analyzers.useunicodemarks
local tfmdata = fontdata[font]
- local marks = tfmdata.marks
+ local marks = tfmdata.resources.marks
local first, last, current, done = nil, nil, head, false
while current do
if current.id == glyph_code and current.subtype<256 and current.font == font and not has_attribute(current,state) then
@@ -236,20 +305,20 @@ function analyzers.methods.arab(head,font,attr) -- maybe make a special version
local char = current.char
if marks[char] or (useunicodemarks and categories[char] == "mn") then
set_attribute(current,state,5) -- mark
- if trace_analyzing then fcs(current,"font:mark") end
+ if trace_analyzing then setnodecolor(current,"font:mark") end
elseif isol[char] then -- can be zwj or zwnj too
first, last = finish(first,last)
set_attribute(current,state,4) -- isol
- if trace_analyzing then fcs(current,"font:isol") end
+ if trace_analyzing then setnodecolor(current,"font:isol") end
first, last = nil, nil
elseif not first then
if isol_fina_medi_init[char] then
set_attribute(current,state,1) -- init
- if trace_analyzing then fcs(current,"font:init") end
+ if trace_analyzing then setnodecolor(current,"font:init") end
first, last = first or current, current
elseif isol_fina[char] then
set_attribute(current,state,4) -- isol
- if trace_analyzing then fcs(current,"font:isol") end
+ if trace_analyzing then setnodecolor(current,"font:isol") end
first, last = nil, nil
else -- no arab
first, last = finish(first,last)
@@ -257,18 +326,18 @@ function analyzers.methods.arab(head,font,attr) -- maybe make a special version
elseif isol_fina_medi_init[char] then
first, last = first or current, current
set_attribute(current,state,2) -- medi
- if trace_analyzing then fcs(current,"font:medi") end
+ if trace_analyzing then setnodecolor(current,"font:medi") end
elseif isol_fina[char] then
if not has_attribute(last,state,1) then
-- tricky, we need to check what last may be !
set_attribute(last,state,2) -- medi
- if trace_analyzing then fcs(last,"font:medi") end
+ if trace_analyzing then setnodecolor(last,"font:medi") end
end
set_attribute(current,state,3) -- fina
- if trace_analyzing then fcs(current,"font:fina") end
+ if trace_analyzing then setnodecolor(current,"font:fina") end
first, last = nil, nil
elseif char >= 0x0600 and char <= 0x06FF then
- if trace_analyzing then fcs(current,"font:rest") end
+ if trace_analyzing then setnodecolor(current,"font:rest") end
first, last = finish(first,last)
else --no
first, last = finish(first,last)
diff --git a/tex/context/base/font-otb.lua b/tex/context/base/font-otb.lua
index 8ee39b8c5..d4019b31d 100644
--- a/tex/context/base/font-otb.lua
+++ b/tex/context/base/font-otb.lua
@@ -5,33 +5,31 @@ if not modules then modules = { } end modules ['font-otb'] = {
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
}
-
local concat = table.concat
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 = type, next, tonumber, tostring
local lpegmatch = lpeg.match
+local utfchar = utf.char
+
+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 fonts = fonts
-local otf = fonts.otf
-local tfm = fonts.tfm
+local report_prepare = logs.reporter("fonts","otf prepare")
-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 fonts = fonts
+local otf = fonts.handlers.otf
-local report_prepare = logs.reporter("fonts","otf prepare")
+local otffeatures = fonts.constructors.newfeatures("otf")
+local registerotffeature = otffeatures.register
local wildcard = "*"
local default = "dflt"
-local split_at_space = lpeg.Ct(lpeg.splitat(" ")) -- no trailing or multiple spaces anyway
-
-local pcache, fcache = { }, { } -- could be weak
-
local function gref(descriptions,n)
if type(n) == "number" then
local name = descriptions[n].name
@@ -42,22 +40,10 @@ local function gref(descriptions,n)
end
elseif n then
local num, nam = { }, { }
- for i=1,#n do
+ for i=2,#n do -- first is likely a key
local ni = n[i]
- -- ! ! ! could be a helper ! ! !
- if type(ni) == "table" then
- local nnum, nnam = { }, { }
- for j=1,#ni do
- local nj = ni[j]
- nnum[j] = format("U+%04X",nj)
- nnam[j] = descriptions[nj].name or "?"
- end
- num[i] = concat(nnum,"|")
- nam[i] = concat(nnam,"|")
- else
- num[i] = format("U+%04X",ni)
- nam[i] = descriptions[ni].name or "?"
- end
+ num[i] = format("U+%04X",ni)
+ nam[i] = descriptions[ni].name or "?"
end
return format("%s (%s)",concat(num," "), concat(nam," "))
else
@@ -65,324 +51,531 @@ local function gref(descriptions,n)
end
end
-local function cref(kind,lookupname)
+local function cref(feature,lookupname)
if lookupname then
- return format("feature %s, lookup %s",kind,lookupname)
+ return format("feature %s, lookup %s",feature,lookupname)
else
- return format("feature %s",kind)
+ return format("feature %s",feature)
end
end
-local function resolve_ligatures(tfmdata,ligatures,kind)
- kind = kind or "unknown"
- local unicodes = tfmdata.unicodes
- local characters = tfmdata.characters
- local descriptions = tfmdata.descriptions
- local changed = tfmdata.changed
- local done = { }
- while true do
- local ok = false
- for k,v in next, ligatures do
- local lig = v[1]
- if not done[lig] then
- local ligs = lpegmatch(split_at_space,lig)
- if #ligs == 2 then
- local uc = v[2]
- local c, f, s = characters[uc], ligs[1], ligs[2]
- local uft, ust = unicodes[f] or 0, unicodes[s] or 0
- if not uft or not ust then
- report_prepare("%s: unicode problem with base ligature %s = %s + %s",cref(kind),gref(descriptions,uc),gref(descriptions,uft),gref(descriptions,ust))
- -- some kind of error
- else
- if type(uft) == "number" then uft = { uft } end
- if type(ust) == "number" then ust = { ust } end
- for ufi=1,#uft do
- local uf = uft[ufi]
- for usi=1,#ust do
- local us = ust[usi]
- if changed[uf] or changed[us] then
- if trace_baseinit and trace_ligatures then
- report_prepare("%s: base ligature %s + %s ignored",cref(kind),gref(descriptions,uf),gref(descriptions,us))
- end
- else
- local first, second = characters[uf], us
- if first and second then
- local t = first.ligatures
- if not t then
- t = { }
- first.ligatures = t
- end
- if type(uc) == "number" then
- t[second] = { type = 0, char = uc }
- else
- t[second] = { type = 0, char = uc[1] } -- can this still happen?
- end
- if trace_baseinit and trace_ligatures then
- report_prepare("%s: base ligature %s + %s => %s",cref(kind),gref(descriptions,uf),gref(descriptions,us),gref(descriptions,uc))
- end
- end
+local basemethods = { }
+local basemethod = "<unset>"
+
+local function applybasemethod(what,...)
+ local m = basemethods[basemethod][what]
+ if m then
+ return m(...)
+ end
+end
+
+-- We need to make sure that luatex sees the difference between
+-- base fonts that have different glyphs in the same slots in fonts
+-- that have the same fullname (or filename). LuaTeX will merge fonts
+-- eventually (and subset later on). If needed we can use a more
+-- verbose name as long as we don't use <()<>[]{}/%> and the length
+-- is < 128.
+
+local basehash, basehashes, applied = { }, 1, { }
+
+local function registerbasehash(tfmdata)
+ local properties = tfmdata.properties
+ local hash = concat(applied," ")
+ local base = basehash[hash]
+ if not base then
+ basehashes = basehashes + 1
+ base = basehashes
+ basehash[hash] = base
+ end
+ properties.basehash = base
+ properties.fullname = properties.fullname .. "-" .. base
+ -- report_prepare("fullname base hash: '%s', featureset '%s'",tfmdata.properties.fullname,hash)
+ applied = { }
+end
+
+local function registerbasefeature(feature,value)
+ applied[#applied+1] = feature .. "=" .. tostring(value)
+end
+
+-- The original basemode ligature builder used the names of components
+-- and did some expression juggling to get the chain right. The current
+-- variant starts with unicodes but still uses names to make the chain.
+-- This is needed because we have to create intermediates when needed
+-- but use predefined snippets when available. To some extend the
+-- current builder is more stupid but I don't worry that much about it
+-- as ligatures are rather predicatable.
+--
+-- Personally I think that an ff + i == ffi rule as used in for instance
+-- latin modern is pretty weird as no sane person will key that in and
+-- expect a glyph for that ligature plus the following character. Anyhow,
+-- as we need to deal with this, we do, but no guarantes are given.
+--
+-- latin modern dejavu
+--
+-- f+f 102 102 102 102
+-- f+i 102 105 102 105
+-- f+l 102 108 102 108
+-- f+f+i 102 102 105
+-- f+f+l 102 102 108 102 102 108
+-- ff+i 64256 105 64256 105
+-- ff+l 64256 108
+--
+-- As you can see here, latin modern is less complete than dejavu but
+-- in practice one will not notice it.
+--
+-- The while loop is needed because we need to resolve for instance
+-- pseudo names like hyphen_hyphen to endash so in practice we end
+-- up with a bit too many definitions but the overhead is neglectable.
+--
+-- Todo: if changed[first] or changed[second] then ... end
+
+local trace = false
+
+local function finalize_ligatures(tfmdata,ligatures)
+ local nofligatures = #ligatures
+ if nofligatures > 0 then
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local resources = tfmdata.resources
+ local unicodes = resources.unicodes
+ local private = resources.private
+ local alldone = false
+ while not alldone do
+ local done = 0
+ for i=1,nofligatures do
+ local ligature = ligatures[i]
+ if ligature then
+ local unicode, lookupdata = ligature[1], ligature[2]
+ if trace then
+ print("BUILDING",concat(lookupdata," "),unicode)
+ end
+ local size = #lookupdata
+ local firstcode = lookupdata[1] -- [2]
+ local firstdata = characters[firstcode]
+ local okay = false
+ if firstdata then
+ local firstname = "ctx_" .. firstcode
+ for i=1,size-1 do -- for i=2,size-1 do
+ local firstdata = characters[firstcode]
+ if not firstdata then
+ firstcode = private
+ if trace then
+ print(" DEFINING",firstname,firstcode)
+ end
+ unicodes[firstname] = firstcode
+ firstdata = { intermediate = true, ligatures = { } }
+ characters[firstcode] = firstdata
+ descriptions[firstcode] = { name = firstname }
+ private = private + 1
+ end
+ local target
+ local secondcode = lookupdata[i+1]
+ local secondname = firstname .. "_" .. secondcode
+ if i == size - 1 then
+ target = unicode
+ if not unicodes[secondname] then
+ unicodes[secondname] = unicode -- map final ligature onto intermediates
+ end
+ okay = true
+ else
+ target = unicodes[secondname]
+ if not target then
+ break
end
end
+ if trace then
+ print("CODES",firstname,firstcode,secondname,secondcode,target)
+ end
+ local firstligs = firstdata.ligatures
+ if firstligs then
+ firstligs[secondcode] = { char = target }
+ else
+ firstdata.ligatures = { [secondcode] = { char = target } }
+ end
+ firstcode = target
+ firstname = secondname
end
end
- ok, done[lig] = true, descriptions[uc].name
+ if okay then
+ ligatures[i] = false
+ done = done + 1
+ end
end
end
+ alldone = done == 0
end
- if ok then
- -- done has "a b c" = "a_b_c" and ligatures the already set ligatures: "a b" = 123
- -- and here we add extras (f i i = fi + i and alike)
- --
- -- we could use a hash for fnc and pattern
- --
- -- this might be interfering !
- for d,n in next, done do
- local pattern = pcache[d] if not pattern then pattern = "^(" .. d .. ") " pcache[d] = pattern end
- local fnc = fcache[n] if not fnc then fnc = function() return n .. " " end fcache[n] = fnc end
- for k,v in next, ligatures do
- v[1] = gsub(v[1],pattern,fnc)
- end
+ if trace then
+ for k, v in next, characters do
+ if v.ligatures then table.print(v,k) end
end
- else
- break
end
+ tfmdata.resources.private = private
end
end
-local splitter = lpeg.splitat(" ")
-
-local function prepare_base_substitutions(tfmdata,kind,value) -- we can share some code with the node features
- if value then
- local otfdata = tfmdata.shared.otfdata
- local validlookups, lookuplist = otf.collectlookups(otfdata,kind,tfmdata.script,tfmdata.language)
- if validlookups then
- local ligatures = { }
- local unicodes = tfmdata.unicodes -- names to unicodes
- local indices = tfmdata.indices
- local characters = tfmdata.characters
- local descriptions = tfmdata.descriptions
- local changed = tfmdata.changed
- --
- local actions = {
- substitution = function(p,lookup,k,glyph,unicode)
- local pv = p[2] -- p.variant
- if pv then
- local upv = unicodes[pv]
- if upv then
- if type(upv) == "table" then -- zero change that table
- upv = upv[1]
- end
- if characters[upv] then
- if trace_baseinit and trace_singles then
- report_prepare("%s: base substitution %s => %s",cref(kind,lookup),gref(descriptions,k),gref(descriptions,upv))
- end
- changed[k] = upv
- end
- end
- end
- end,
- alternate = function(p,lookup,k,glyph,unicode)
- local pc = p[2] -- p.components
- if pc then
- -- a bit optimized ugliness
- if value == 1 then
- pc = lpegmatch(splitter,pc)
- elseif value == 2 then
- local a, b = lpegmatch(splitter,pc)
- pc = b or a
- else
- pc = { lpegmatch(splitter,pc) }
- pc = pc[value] or pc[#pc]
- end
- if pc then
- local upc = unicodes[pc]
- if upc then
- if type(upc) == "table" then -- zero change that table
- upc = upc[1]
- end
- if characters[upc] then
- if trace_baseinit and trace_alternatives then
- report_prepare("%s: base alternate %s %s => %s",cref(kind,lookup),tostring(value),gref(descriptions,k),gref(descriptions,upc))
- end
- changed[k] = upc
- end
- end
- end
- end
- end,
- ligature = function(p,lookup,k,glyph,unicode)
- local pc = p[2]
- if pc then
- if trace_baseinit and trace_ligatures then
- local upc = { lpegmatch(splitter,pc) }
- for i=1,#upc do upc[i] = unicodes[upc[i]] end
- -- we assume that it's no table
- report_prepare("%s: base ligature %s => %s",cref(kind,lookup),gref(descriptions,upc),gref(descriptions,k))
- end
- ligatures[#ligatures+1] = { pc, k }
- end
- end,
- }
- --
- for k,c in next, characters do
- local glyph = descriptions[k]
- local lookups = glyph.slookups
- if lookups then
- for l=1,#lookuplist do
- local lookup = lookuplist[l]
- local p = lookups[lookup]
- if p then
- local a = actions[p[1]]
- if a then
- a(p,lookup,k,glyph,unicode)
- end
- end
+local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplist)
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local resources = tfmdata.resources
+ local changed = tfmdata.changed
+ local unicodes = resources.unicodes
+ local lookuphash = resources.lookuphash
+ local lookuptypes = resources.lookuptypes
+
+ local ligatures = { }
+
+ local actions = {
+ substitution = function(lookupdata,lookupname,description,unicode)
+ if trace_baseinit and trace_singles then
+ report_prepare("%s: base substitution %s => %s",cref(feature,lookupname),
+ gref(descriptions,unicode),gref(descriptions,replacement))
+ end
+ changed[unicode] = lookupdata
+ end,
+ alternate = function(lookupdata,lookupname,description,unicode)
+ local replacement = lookupdata[value] or lookupdata[#lookupdata]
+ if trace_baseinit and trace_alternatives then
+ report_prepare("%s: base alternate %s %s => %s",cref(feature,lookupname),
+ tostring(value),gref(descriptions,unicode),gref(descriptions,replacement))
+ end
+ changed[unicode] = replacement
+ end,
+ ligature = function(lookupdata,lookupname,description,unicode)
+ if trace_baseinit and trace_alternatives then
+ report_prepare("%s: base ligature %s %s => %s",cref(feature,lookupname),
+ tostring(value),gref(descriptions,lookupdata),gref(descriptions,unicode))
+ end
+ ligatures[#ligatures+1] = { unicode, lookupdata }
+ end,
+ }
+
+ for unicode, character in next, characters do
+ local description = descriptions[unicode]
+ local lookups = description.slookups
+ if lookups then
+ for l=1,#lookuplist do
+ local lookupname = lookuplist[l]
+ local lookupdata = lookups[lookupname]
+ if lookupdata then
+ local lookuptype = lookuptypes[lookupname]
+ local action = actions[lookuptype]
+ if action then
+ action(lookupdata,lookupname,description,unicode)
end
end
- local lookups = glyph.mlookups
- if lookups then
- for l=1,#lookuplist do
- local lookup = lookuplist[l]
- local ps = lookups[lookup]
- if ps then
- for i=1,#ps do
- local p = ps[i]
- local a = actions[p[1]]
- if a then
- a(p,lookup,k,glyph,unicode)
- end
- end
+ end
+ end
+ local lookups = description.mlookups
+ if lookups then
+ for l=1,#lookuplist do
+ local lookupname = lookuplist[l]
+ local lookuplist = lookups[lookupname]
+ if lookuplist then
+ local lookuptype = lookuptypes[lookupname]
+ local action = actions[lookuptype]
+ if action then
+ for i=1,#lookuplist do
+ action(lookuplist[i],lookupname,description,unicode)
end
end
end
end
- resolve_ligatures(tfmdata,ligatures,kind)
end
- else
- tfmdata.ligatures = tfmdata.ligatures or { } -- left over from what ?
end
+
+ finalize_ligatures(tfmdata,ligatures)
end
-local function preparebasekerns(tfmdata,kind,value) -- todo what kind of kerns, currently all
- if value then
- local otfdata = tfmdata.shared.otfdata
- local validlookups, lookuplist = otf.collectlookups(otfdata,kind,tfmdata.script,tfmdata.language)
- if validlookups then
- local unicodes = tfmdata.unicodes -- names to unicodes
- local indices = tfmdata.indices
- local characters = tfmdata.characters
- local descriptions = tfmdata.descriptions
- local sharedkerns = { }
- for u, chr in next, characters do
- local d = descriptions[u]
- if d then
- local dk = d.kerns -- shared
- if dk then
- local s = sharedkerns[dk]
- if s == false then
- -- skip
- elseif s then
- chr.kerns = s
- else
- local t, done = chr.kerns or { }, false
- for l=1,#lookuplist do
- local lookup = lookuplist[l]
- local kerns = dk[lookup]
- if kerns then
- for k, v in next, kerns do
- if v ~= 0 and not t[k] then -- maybe no 0 test here
- t[k], done = v, true
- if trace_baseinit and trace_kerns then
- report_prepare("%s: base kern %s + %s => %s",cref(kind,lookup),gref(descriptions,u),gref(descriptions,k),v)
- end
- end
- end
+local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist) -- todo what kind of kerns, currently all
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local resources = tfmdata.resources
+ local unicodes = resources.unicodes
+ local sharedkerns = { }
+ local traceindeed = trace_baseinit and trace_kerns
+ for unicode, character in next, characters do
+ local description = descriptions[unicode]
+ local rawkerns = description.kerns -- shared
+ if rawkerns then
+ local s = sharedkerns[rawkerns]
+ if s == false then
+ -- skip
+ elseif s then
+ character.kerns = s
+ else
+ local newkerns = character.kerns
+ local done = false
+ for l=1,#lookuplist do
+ local lookup = lookuplist[l]
+ local kerns = rawkerns[lookup]
+ if kerns then
+ for otherunicode, value in next, kerns do
+ if value == 0 then
+ -- maybe no 0 test here
+ elseif not newkerns then
+ newkerns = { [otherunicode] = value }
+ done = true
+ if traceindeed then
+ report_prepare("%s: base kern %s + %s => %s",cref(feature,lookup),
+ gref(descriptions,unicode),gref(descriptions,otherunicode),value)
+ end
+ elseif not newkerns[otherunicode] then -- first wins
+ newkerns[otherunicode] = value
+ done = true
+ if traceindeed then
+ report_prepare("%s: base kern %s + %s => %s",cref(feature,lookup),
+ gref(descriptions,unicode),gref(descriptions,otherunicode),value)
end
- end
- if done then
- sharedkerns[dk] = t
- chr.kerns = t -- no empty assignments
- else
- sharedkerns[dk] = false
end
end
end
end
+ if done then
+ sharedkerns[rawkerns] = newkerns
+ character.kerns = newkerns -- no empty assignments
+ else
+ sharedkerns[rawkerns] = false
+ end
end
end
end
end
--- In principle we could register each feature individually which was
--- what we did in earlier versions. However, after the rewrite it
--- made more sense to collect them in an overall features initializer
--- just as with the node variant. There it was needed because we need
--- to do complete mixed runs and not run featurewise (as we did before).
-
-local supported_gsub = {
- 'liga', 'dlig', 'rlig', 'hlig',
- 'pnum', 'onum', 'tnum', 'lnum',
- 'zero',
- 'smcp', 'cpsp', 'c2sc', 'ornm', 'aalt',
- 'hwid', 'fwid',
- 'ssty', 'rtlm', -- math
--- 'tlig', 'trep',
+basemethods.independent = {
+ preparesubstitutions = preparesubstitutions,
+ preparepositionings = preparepositionings,
}
-local supported_gpos = {
- 'kern'
-}
+local function makefake(tfmdata,name,present)
+ local resources = tfmdata.resources
+ local private = resources.private
+ local character = { intermediate = true, ligatures = { } }
+ resources.unicodes[name] = private
+ tfmdata.characters[private] = character
+ tfmdata.descriptions[private] = { name = name }
+ resources.private = private + 1
+ present[name] = private
+ return character
+end
+
+local function make_1(present,tree,name)
+ for k, v in next, tree do
+ if k == "ligature" then
+ present[name] = v
+ else
+ make_1(present,v,name .. "_" .. k)
+ end
+ end
+end
+
+local function make_2(present,tfmdata,characters,tree,name,preceding,unicode,done,lookupname)
+ for k, v in next, tree do
+ if k == "ligature" then
+ local character = characters[preceding]
+ if not character then
+ if trace_baseinit then
+ report_prepare("weird ligature in lookup %s: 0x%04X (%s), preceding 0x%04X (%s)",lookupname,v,utfchar(v),preceding,utfchar(preceding))
+ end
+ character = makefake(tfmdata,name,present)
+ end
+ local ligatures = character.ligatures
+ if ligatures then
+ ligatures[unicode] = { char = v }
+ else
+ character.ligatures = { [unicode] = { char = v } }
+ end
+ if done then
+ local d = done[lookupname]
+ if not d then
+ done[lookupname] = { "dummy", v }
+ else
+ d[#d+1] = v
+ end
+ end
+ else
+ local code = present[name] or unicode
+ local name = name .. "_" .. k
+ make_2(present,tfmdata,characters,v,name,code,k,done,lookupname)
+ end
+ end
+end
+
+local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplist)
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local resources = tfmdata.resources
+ local changed = tfmdata.changed
+ local lookuphash = resources.lookuphash
+ local lookuptypes = resources.lookuptypes
+
+ local ligatures = { }
+
+ for l=1,#lookuplist do
+ local lookupname = lookuplist[l]
+ local lookupdata = lookuphash[lookupname]
+ local lookuptype = lookuptypes[lookupname]
+ for unicode, data in next, lookupdata do
+ if lookuptype == "substitution" then
+ if trace_baseinit and trace_singles then
+ report_prepare("%s: base substitution %s => %s",cref(feature,lookupname),
+ gref(descriptions,unicode),gref(descriptions,data))
+ end
+ changed[unicode] = data
+ elseif lookuptype == "alternate" then
+ local replacement = data[value] or data[#data]
+ if trace_baseinit and trace_alternatives then
+ report_prepare("%s: base alternate %s %s => %s",cref(feature,lookupname),
+ tostring(value),gref(descriptions,unicode),gref(descriptions,replacement))
+ end
+ changed[unicode] = replacement
+ elseif lookuptype == "ligature" then
+ ligatures[#ligatures+1] = { unicode, data, lookupname }
+ end
+ end
+ end
+
+ local nofligatures = #ligatures
+
+ if nofligatures > 0 then
+
+ local characters = tfmdata.characters
+ local present = { }
+ local done = trace_baseinit and trace_ligatures and { }
+
+ for i=1,nofligatures do
+ local ligature = ligatures[i]
+ local unicode, tree = ligature[1], ligature[2]
+ make_1(present,tree,"ctx_"..unicode)
+ end
+
+ for i=1,nofligatures do
+ local ligature = ligatures[i]
+ local unicode, tree, lookupname = ligature[1], ligature[2], ligature[3]
+ make_2(present,tfmdata,characters,tree,"ctx_"..unicode,unicode,unicode,done,lookupname)
+ end
+
+ if done then
+ for lookupname, list in next, done do
+ report_prepare("%s: base ligatures %s => %s",cref(feature,lookupname),
+ tostring(value),gref(descriptions,done))
+ end
+ end
+
+ end
-function otf.features.registerbasesubstitution(tag)
- supported_gsub[#supported_gsub+1] = tag
end
-function otf.features.registerbasekern(tag)
- supported_gsub[#supported_gpos+1] = tag
+
+local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist)
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local resources = tfmdata.resources
+ local lookuphash = resources.lookuphash
+ local traceindeed = trace_baseinit and trace_kerns
+
+ -- check out this sharedkerns trickery
+
+ for l=1,#lookuplist do
+ local lookupname = lookuplist[l]
+ local lookupdata = lookuphash[lookupname]
+ for unicode, data in next, lookupdata do
+ local character = characters[unicode]
+ local kerns = character.kerns
+ if not kerns then
+ kerns = { }
+ character.kerns = kerns
+ end
+ if traceindeed then
+ for otherunicode, kern in next, data do
+ if not kerns[otherunicode] and kern ~= 0 then
+ kerns[otherunicode] = kern
+ report_prepare("%s: base kern %s + %s => %s",cref(feature,lookup),
+ gref(descriptions,unicode),gref(descriptions,otherunicode),kern)
+ end
+ end
+ else
+ for otherunicode, kern in next, data do
+ if not kerns[otherunicode] and kern ~= 0 then
+ kerns[otherunicode] = kern
+ end
+ end
+ end
+ end
+ end
+
+end
+
+local function initializehashes(tfmdata)
+ nodeinitializers.features(tfmdata)
end
-local basehash, basehashes = { }, 1
+basemethods.shared = {
+ initializehashes = initializehashes,
+ preparesubstitutions = preparesubstitutions,
+ preparepositionings = preparepositionings,
+}
+
+basemethod = "independent"
-function fonts.initializers.base.otf.features(tfmdata,value)
+local function featuresinitializer(tfmdata,value)
if true then -- value then
- -- not shared
local t = trace_preparing and os.clock()
local features = tfmdata.shared.features
if features then
- local h = { }
- for f=1,#supported_gsub do
- local feature = supported_gsub[f]
- local value = features[feature]
- prepare_base_substitutions(tfmdata,feature,value)
- if value then
- h[#h+1] = feature .. "=" .. tostring(value)
+ applybasemethod("initializehashes",tfmdata)
+ local collectlookups = otf.collectlookups
+ local rawdata = tfmdata.shared.rawdata
+ local properties = tfmdata.properties
+ local script = properties.script
+ local language = properties.language
+ local basesubstitutions = rawdata.resources.features.gsub
+ local basepositionings = rawdata.resources.features.gpos
+ if basesubstitutions then
+ for feature, data in next, basesubstitutions do
+ local value = features[feature]
+ if value then
+ local validlookups, lookuplist = collectlookups(rawdata,feature,script,language)
+ if validlookups then
+ applybasemethod("preparesubstitutions",tfmdata,feature,value,validlookups,lookuplist)
+ registerbasefeature(feature,value)
+ end
+ end
end
end
- for f=1,#supported_gpos do
- local feature = supported_gpos[f]
- local value = features[feature]
- preparebasekerns(tfmdata,feature,features[feature])
- if value then
- h[#h+1] = feature .. "=" .. tostring(value)
+ if basepositions then
+ for feature, data in next, basepositions do
+ local value = features[feature]
+ if value then
+ local validlookups, lookuplist = collectlookups(rawdata,feature,script,language)
+ if validlookups then
+ applybasemethod("preparepositionings",tfmdata,feature,features[feature],validlookups,lookuplist)
+ registerbasefeature(feature,value)
+ end
+ end
end
end
- local hash = concat(h," ")
- local base = basehash[hash]
- if not base then
- basehashes = basehashes + 1
- base = basehashes
- basehash[hash] = base
- end
- -- We need to make sure that luatex sees the difference between
- -- base fonts that have different glyphs in the same slots in fonts
- -- that have the same fullname (or filename). LuaTeX will merge fonts
- -- eventually (and subset later on). If needed we can use a more
- -- verbose name as long as we don't use <()<>[]{}/%> and the length
- -- is < 128.
- tfmdata.fullname = tfmdata.fullname .. "-" .. base -- tfmdata.psname is the original
- --~ report_prepare("fullname base hash: '%s', featureset '%s'",tfmdata.fullname,hash)
+ registerbasehash(tfmdata)
end
if trace_preparing then
- report_prepare("preparation time is %0.3f seconds for %s",os.clock()-t,tfmdata.fullname or "?")
+ report_prepare("preparation time is %0.3f seconds for %s",os.clock()-t,tfmdata.properties.fullname or "?")
end
end
end
+
+registerotffeature {
+ name = "features",
+ description = "features",
+ default = true,
+ initializers = {
+ position = 1,
+ base = featuresinitializer,
+ }
+}
+
+-- independent : collect lookups independently (takes more runtime ... neglectable)
+-- shared : shares lookups with node mode (takes more memory ... noticeable)
+
+directives.register("fonts.otf.loader.basemethod", function(v)
+ if basemethods[v] then
+ basemethod = v
+ end
+end)
diff --git a/tex/context/base/font-otc.lua b/tex/context/base/font-otc.lua
index 93b942f9a..50433e3cc 100644
--- a/tex/context/base/font-otc.lua
+++ b/tex/context/base/font-otc.lua
@@ -8,21 +8,17 @@ if not modules then modules = { } end modules ['font-otc'] = {
local format, insert = string.format, table.insert
local type, next = type, next
+local lpegmatch = lpeg.match
-- we assume that the other otf stuff is loaded already
-local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
+local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
+local report_otf = logs.reporter("fonts","otf loading")
-local fonts = fonts
-local otf = fonts.otf
-
-local report_otf = logs.reporter("fonts","otf loading")
-
--- instead of "script = "DFLT", langs = { 'dflt' }" we now use wildcards (we used to
--- have always); some day we can write a "force always when true" trick for other
--- features as well
---
--- we could have a tnum variant as well
+local fonts = fonts
+local otf = fonts.handlers.otf
+local otffeatures = fonts.constructors.newfeatures("otf")
+local registerotffeature = otffeatures.register
-- In the userdata interface we can not longer tweak the loaded font as
-- conveniently as before. For instance, instead of pushing extra data in
@@ -115,76 +111,81 @@ local extra_features = { -- maybe just 1..n so that we prescribe order
}
local function enhancedata(data,filename,raw)
- local luatex = data.luatex
- local lookups = luatex.lookups
- local sequences = luatex.sequences
- local glyphs = data.glyphs
- local indices = luatex.indices
- local gsubfeatures = luatex.features.gsub
- for kind, specifications in next, extra_features do
- if gsub and gsub[kind] then
+ local descriptions = data.descriptions
+ local resources = data.resources
+ local lookups = resources.lookups
+ local gsubfeatures = resources.features.gsub
+ local sequences = resources.sequences
+ local fontfeatures = resources.features
+ local unicodes = resources.unicodes
+ local lookuptypes = resources.lookuptypes
+ local splitter = lpeg.splitter(" ",unicodes)
+ for feature, specifications in next, extra_features do
+ if gsub and gsub[feature] then
-- already present
else
local done = 0
for s=1,#specifications do
- local added = false
local specification = specifications[s]
- local features, subtables = specification.features, specification.subtables
- local name, type, flags = specification.name, specification.type, specification.flags
- local full = subtables[1]
- local list = extra_lists[kind][s]
- if type == "gsub_ligature" then
- -- inefficient loop
- for unicode, index in next, indices do
- local glyph = glyphs[index]
- local ligature = list[glyph.name]
- if ligature then
- if glyph.slookups then
- glyph.slookups [full] = { "ligature", ligature, glyph.name }
+ local askedfeatures = specification.features
+ local subtables = specification.subtables
+ local featurename = specification.name
+ local featuretype = specification.type
+ local featureflags = specification.flags
+ local full = subtables[1]
+ local list = extra_lists[feature][s]
+ local added = false
+ if featuretype == "gsub_ligature" then
+ lookuptypes[full] = "ligature"
+ for name, ligature in next, list do
+ local unicode = unicodes[name]
+ local description = descriptions[unicode]
+ if description then
+ local slookups = description.slookups
+ if slookups then
+ slookups[full] = { lpegmatch(splitter,ligature) }
else
- glyph.slookups = { [full] = { "ligature", ligature, glyph.name } }
+ description.slookups = { [full] = { lpegmatch(splitter,ligature) } }
end
- done, added = done+1, true
+ done, added = done + 1, true
end
end
- elseif type == "gsub_single" then
- -- inefficient loop
- for unicode, index in next, indices do
- local glyph = glyphs[index]
- local r = list[unicode]
- if r then
- local replacement = indices[r]
- if replacement and glyphs[replacement] then
- if glyph.slookups then
- glyph.slookups [full] = { "substitution", glyphs[replacement].name }
- else
- glyph.slookups = { [full] = { "substitution", glyphs[replacement].name } }
- end
- done, added = done+1, true
+ elseif featuretype == "gsub_single" then
+ lookuptypes[full] = "substitution"
+ for name, replacement in next, list do
+ local unicode = unicodes[name]
+ local description = descriptions[unicode]
+ if description then
+ local slookups = description.slookups
+ if slookups then
+ slookups[full] = unicodes[replacement]
+ else
+ description.slookups = { [full] = unicodes[replacement] }
end
+ done, added = done + 1, true
end
end
end
if added then
sequences[#sequences+1] = {
chain = 0,
- features = { [kind] = features },
- flags = flags,
- name = name,
+ features = { [feature] = askedfeatures },
+ flags = featureflags,
+ name = featurename,
subtables = subtables,
- type = type,
+ type = featuretype,
}
-- register in metadata (merge as there can be a few)
if not gsubfeatures then
- gsubfeatures = { }
- luatex.features.gsub = gsubfeatures
+ gsubfeatures = { }
+ fontfeatures.gsub = gsubfeatures
end
- local k = gsubfeatures[kind]
+ local k = gsubfeatures[feature]
if not k then
k = { }
- gsubfeatures[kind] = k
+ gsubfeatures[feature] = k
end
- for script, languages in next, features do
+ for script, languages in next, askedfeatures do
local kk = k[script]
if not kk then
kk = { }
@@ -196,10 +197,8 @@ local function enhancedata(data,filename,raw)
end
end
end
- if done > 0 then
- if trace_loading then
- report_otf("enhance: registering %s feature (%s glyphs affected)",kind,done)
- end
+ if done > 0 and trace_loading then
+ report_otf("enhance: registering %s feature (%s glyphs affected)",feature,done)
end
end
end
@@ -207,30 +206,18 @@ end
otf.enhancers.register("check extra features",enhancedata)
-local features = otf.tables.features
-
-features['tlig'] = 'TeX Ligatures'
-features['trep'] = 'TeX Replacements'
-features['anum'] = 'Arabic Digits'
-
-local registerbasesubstitution = otf.features.registerbasesubstitution
-
-registerbasesubstitution('tlig')
-registerbasesubstitution('trep')
-registerbasesubstitution('anum')
-
--- the functionality is defined elsewhere
-
-local initializers = fonts.initializers
-local common_initializers = initializers.common
-local base_initializers = initializers.base.otf
-local node_initializers = initializers.node.otf
+registerotffeature {
+ name = 'tlig',
+ description = 'tex ligatures',
+}
-base_initializers.equaldigits = common_initializers.equaldigits
-node_initializers.equaldigits = common_initializers.equaldigits
+registerotffeature {
+ name = 'trep',
+ description = 'tex replacements',
+}
-base_initializers.lineheight = common_initializers.lineheight
-node_initializers.lineheight = common_initializers.lineheight
+registerotffeature {
+ name = 'anum',
+ description = 'arabic digits',
+}
-base_initializers.compose = common_initializers.compose
-node_initializers.compose = common_initializers.compose
diff --git a/tex/context/base/font-otd.lua b/tex/context/base/font-otd.lua
index 475481643..59c050e10 100644
--- a/tex/context/base/font-otd.lua
+++ b/tex/context/base/font-otd.lua
@@ -6,32 +6,49 @@ if not modules then modules = { } end modules ['font-otd'] = {
license = "see context related readme files"
}
-local trace_dynamics = false trackers.register("otf.dynamics", function(v) trace_dynamics = v end)
+local match = string.match
-local report_otf = logs.reporter("fonts","otf loading")
+local trace_dynamics = false trackers.register("otf.dynamics", function(v) trace_dynamics = v end)
+local trace_applied = false trackers.register("otf.applied", function(v) trace_applied = v end)
-local fonts = fonts
-local otf = fonts.otf
-local fontdata = fonts.identifiers
+local report_otf = logs.reporter("fonts","otf loading")
+local report_process = logs.reporter("fonts","otf process")
-otf.features = otf.features or { }
-otf.features.default = otf.features.default or { }
+local fonts = fonts
+local otf = fonts.handlers.otf
+local fontdata = fonts.hashes.identifiers
+local definers = fonts.definers
+local constructors = fonts.constructors
+local specifiers = fonts.specifiers
-local definers = fonts.definers
-local contextsetups = definers.specifiers.contextsetups
-local contextnumbers = definers.specifiers.contextnumbers
+local contextsetups = specifiers.contextsetups
+local contextnumbers = specifiers.contextnumbers
+local contextmerged = specifiers.contextmerged
--- todo: dynamics namespace
+local otffeatures = fonts.constructors.newfeatures("otf")
+local registerotffeature = otffeatures.register
-local a_to_script = { }
-local a_to_language = { }
+local fontdynamics = { }
+fonts.hashes.dynamics = fontdynamics
-function otf.setdynamics(font,dynamics,attribute)
+local a_to_script = { }
+local a_to_language = { }
+
+setmetatable(fontdynamics, { __index =
+ function(t,font)
+ local d = fontdata[font].shared.dynamics or false
+ t[font] = d
+ return d
+ end
+})
+
+function otf.setdynamics(font,attribute)
local features = contextsetups[contextnumbers[attribute]] -- can be moved to caller
if features then
+ local dynamics = fontdynamics[font]
local script = features.script or 'dflt'
local language = features.language or 'dflt'
- local ds = dynamics[script]
+ local ds = dynamics[script] -- can be metatable magic (less testing)
if not ds then
ds = { }
dynamics[script] = ds
@@ -42,50 +59,160 @@ function otf.setdynamics(font,dynamics,attribute)
ds[language] = dsl
end
local dsla = dsl[attribute]
- if dsla then
- -- if trace_dynamics then
- -- report_otf("using dynamics %s: attribute %s, script %s, language %s",contextnumbers[attribute],attribute,script,language)
- -- end
- return dsla
- else
+ if not dsla then
local tfmdata = fontdata[font]
a_to_script [attribute] = script
a_to_language[attribute] = language
-- we need to save some values
- local saved = {
- script = tfmdata.script,
- language = tfmdata.language,
- mode = tfmdata.mode,
- features = tfmdata.shared.features
- }
- tfmdata.mode = "node"
- tfmdata.dynamics = true -- handy for tracing
- tfmdata.language = language
- tfmdata.script = script
- tfmdata.shared.features = { }
+ local properties = tfmdata.properties
+ local shared = tfmdata.shared
+ local s_script = properties.script
+ local s_language = properties.language
+ local s_mode = properties.mode
+ local s_features = shared.features
+ properties.mode = "node"
+ properties.language = language
+ properties.script = script
+ properties.dynamics = true -- handy for tracing
+ shared.features = { }
-- end of save
- local set = definers.check(features,otf.features.default)
+ local set = constructors.checkedfeatures("otf",features)
dsla = otf.setfeatures(tfmdata,set)
if trace_dynamics then
report_otf("setting dynamics %s: attribute %s, script %s, language %s, set: %s",contextnumbers[attribute],attribute,script,language,table.sequenced(set))
end
-- we need to restore some values
- tfmdata.script = saved.script
- tfmdata.language = saved.language
- tfmdata.mode = saved.mode
- tfmdata.shared.features = saved.features
+ properties.script = s_script
+ properties.language = s_language
+ properties.mode = s_mode
+ shared.features = s_features
-- end of restore
dynamics[script][language][attribute] = dsla -- cache
- return dsla
+ elseif trace_dynamics then
+ -- report_otf("using dynamics %s: attribute %s, script %s, language %s",contextnumbers[attribute],attribute,script,language)
end
+ return dsla
end
- return nil -- { }
end
function otf.scriptandlanguage(tfmdata,attr)
+ local properties = tfmdata.properties
if attr and attr > 0 then
- return a_to_script[attr] or tfmdata.script, a_to_language[attr] or tfmdata.language
+ return a_to_script[attr] or properties.script or "dflt", a_to_language[attr] or properties.language or "dflt"
else
- return tfmdata.script, tfmdata.language
+ return properties.script or "dflt", properties.language or "dflt"
end
end
+
+-- we reimplement the dataset resolver
+
+local special_attributes = {
+ init = 1,
+ medi = 2,
+ fina = 3,
+ isol = 4
+}
+
+local resolved = { } -- we only resolve a font,script,language,attribute pair once
+local wildcard = "*"
+local default = "dflt"
+
+local function initialize(sequence,script,language,s_enabled,a_enabled,attr,dynamic)
+ local features = sequence.features
+ if features then
+ for kind, scripts in next, features do
+ local s_e = s_enabled and s_enabled[kind]
+ local a_e = a_enabled and a_enabled[kind]
+ local e_e = s_e or a_e
+ if e_e then
+ local languages = scripts[script] or scripts[wildcard]
+ if languages then
+ local valid, what = false
+ -- not languages[language] or languages[default] or languages[wildcard] because we want tracing
+ -- only first attribute match check, so we assume simple fina's
+ -- default can become a font feature itself
+ if languages[language] then
+ valid = true
+ what = language
+ -- elseif languages[default] then
+ -- valid = true
+ -- what = default
+ elseif languages[wildcard] then
+ valid = true
+ what = wildcard
+ end
+ if valid then
+ local attribute = special_attributes[kind] or false
+ if a_e and dynamic < 0 then
+ valid = false
+ end
+ if trace_applied then
+ local typ, action = match(sequence.type,"(.*)_(.*)") -- brrr
+ report_process(
+ "%s font: %03i, dynamic: %03i, kind: %s, lookup: %3i, script: %-4s, language: %-4s (%-4s), type: %s, action: %s, name: %s",
+ (valid and "+") or "-",font,attr or 0,kind,s,script,language,what,typ,action,sequence.name)
+ end
+ return { valid, attribute, sequence.chain or 0, kind }
+ end
+ end
+ end
+ end
+ return false -- { valid, attribute, chain, "generic" } -- false anyway, could be flag instead of table
+ else
+ return false -- { false, false, chain } -- indirect lookup, part of chain (todo: make this a separate table)
+ end
+end
+
+function otf.dataset(tfmdata,sequences,font,attr)
+
+ local shared = tfmdata.shared
+ local properties = tfmdata.properties
+
+ local script, language, s_enabled, a_enabled, dynamic
+
+ if attr and attr ~= 0 then
+ local features = contextsetups[contextnumbers[attr]] -- could be a direct list
+ language = features.language or "dflt"
+ script = features.script or "dflt"
+ a_enabled = features
+ dynamic = contextmerged[attr] or 0
+ if dynamic == 2 or dynamic == -2 then
+ -- font based
+ s_enabled = shared.features
+ end
+ else
+ language = properties.language or "dflt"
+ script = properties.script or "dflt"
+ s_enabled = shared.features -- can be made local to the resolver
+ dynamic = 0
+ end
+
+ local res = resolved[font]
+ if not res then
+ res = { }
+ resolved[font] = res
+ end
+ local rs = res[script]
+ if not rs then
+ rs = { }
+ res[script] = rs
+ end
+ local rl = rs[language]
+ if not rl then
+ rl = { }
+ rs[language] = rl
+ end
+ local ra = rl[attr]
+ if ra == nil then -- attr can be false
+ ra = { }
+ rl[attr] = ra
+ setmetatable(ra, { __index = function(t,k)
+ local v = initialize(sequences[k],script,language,s_enabled,a_enabled,attr,dynamic)
+ t[k] = v
+ return v
+ end})
+ end
+
+ return ra
+
+end
diff --git a/tex/context/base/font-otf.lua b/tex/context/base/font-otf.lua
index c974d89c8..d5de04f90 100644
--- a/tex/context/base/font-otf.lua
+++ b/tex/context/base/font-otf.lua
@@ -10,6 +10,7 @@ if not modules then modules = { } end modules ['font-otf'] = {
-- anchor_classes vs kernclasses
-- modification/creationtime in subfont is runtime dus zinloos
-- to_table -> totable
+-- ascent descent
local utf = unicode.utf8
@@ -19,93 +20,71 @@ local type, next, tonumber, tostring = type, next, tonumber, tostring
local abs = math.abs
local getn = table.getn
local lpegmatch = lpeg.match
-local reversed, concat = table.reversed, table.concat
+local reversed, concat, remove = table.reversed, table.concat, table.remove
local ioflush = io.flush
-
-local allocate = utilities.storage.allocate
-
-local trace_private = false trackers.register("otf.private", function(v) trace_private = v end)
-local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
-local trace_features = false trackers.register("otf.features", function(v) trace_features = v end)
-local trace_dynamics = false trackers.register("otf.dynamics", function(v) trace_dynamics = v end)
-local trace_sequences = false trackers.register("otf.sequences", function(v) trace_sequences = v end)
-local trace_math = false trackers.register("otf.math", function(v) trace_math = v end)
-local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
-
-local report_otf = logs.reporter("fonts","otf loading")
-
-local starttiming, stoptiming, elapsedtime = statistics.starttiming, statistics.stoptiming, statistics.elapsedtime
-
-local findbinfile = resolvers.findbinfile
-
-local fonts = fonts
-
-fonts.otf = fonts.otf or { }
-local otf = fonts.otf
-local tfm = fonts.tfm
-
-local fontdata = fonts.identifiers
-local chardata = characters and characters.data -- not used
-
--- todo: probably first time so local first
-
-otf.features = otf.features or { }
-local features = otf.features
-features.list = features.list or { }
-local featurelist = features.list
-features.default = features.default or { }
-local defaultfeatures = features.default
-
-otf.enhancers = allocate()
-local enhancers = otf.enhancers
-enhancers.patches = { }
-local patches = enhancers.patches
-
-local definers = fonts.definers
-local readers = fonts.tfm.readers
-
-otf.glists = { "gsub", "gpos" }
-
-otf.version = 2.710 -- beware: also sync font-mis.lua
-otf.cache = containers.define("fonts", "otf", otf.version, true)
-
-local loadmethod = "table" -- table, mixed, sparse
-local forceload = false
-local cleanup = 0
-local usemetatables = false -- .4 slower on mk but 30 M less mem so we might change the default -- will be directive
-local packdata = true
-local syncspace = true
-local forcenotdef = false
-
-local wildcard = "*"
-local default = "dflt"
-
-local fontloaderfields = fontloader.fields
-local mainfields = nil
-local glyphfields = nil -- not used yet
-
-directives.register("fonts.otf.loader.method", function(v)
- if v == "sparse" and fontloaderfields then
- loadmethod = "sparse"
- elseif v == "mixed" then
- loadmethod = "mixed"
- elseif v == "table" then
- loadmethod = "table"
- else
- loadmethod = "table"
- report_otf("no loader method '%s', using '%s' instead",v,loadmethod)
- end
-end)
-
-directives.register("fonts.otf.loader.cleanup",function(v)
- cleanup = tonumber(v) or (v and 1) or 0
-end)
-
-directives.register("fonts.otf.loader.force", function(v) forceload = v end)
-directives.register("fonts.otf.loader.usemetatables", function(v) usemetatables = v end)
-directives.register("fonts.otf.loader.pack", function(v) packdata = v end)
-directives.register("fonts.otf.loader.syncspace", function(v) syncspace = v end)
-directives.register("fonts.otf.loader.forcenotdef", function(v) forcenotdef = v end)
+local fastcopy = table.fastcopy
+
+local allocate = utilities.storage.allocate
+local registertracker = trackers.register
+local registerdirective = directives.register
+local starttiming = statistics.starttiming
+local stoptiming = statistics.stoptiming
+local elapsedtime = statistics.elapsedtime
+local findbinfile = resolvers.findbinfile
+
+local trace_private = false registertracker("otf.private", function(v) trace_private = v end)
+local trace_loading = false registertracker("otf.loading", function(v) trace_loading = v end)
+local trace_features = false registertracker("otf.features", function(v) trace_features = v end)
+local trace_dynamics = false registertracker("otf.dynamics", function(v) trace_dynamics = v end)
+local trace_sequences = false registertracker("otf.sequences", function(v) trace_sequences = v end)
+local trace_markwidth = false registertracker("otf.markwidth", function(v) trace_markwidth = v end)
+local trace_defining = false registertracker("fonts.defining", function(v) trace_defining = v end)
+
+local report_otf = logs.reporter("fonts","otf loading")
+
+local fonts = fonts
+local otf = fonts.handlers.otf
+
+otf.glists = { "gsub", "gpos" }
+
+otf.version = 2.710 -- beware: also sync font-mis.lua
+otf.cache = containers.define("fonts", "otf", otf.version, true)
+
+local fontdata = fonts.hashes.identifiers
+local chardata = characters and characters.data -- not used
+
+local otffeatures = fonts.constructors.newfeatures("otf")
+local registerotffeature = otffeatures.register
+
+local enhancers = allocate()
+otf.enhancers = enhancers
+local patches = { }
+enhancers.patches = patches
+
+local definers = fonts.definers
+local readers = fonts.readers
+local constructors = fonts.constructors
+
+local forceload = false
+local cleanup = 0 -- mk: 0=885M 1=765M 2=735M (regular run 730M)
+local usemetatables = false -- .4 slower on mk but 30 M less mem so we might change the default -- will be directive
+local packdata = true
+local syncspace = true
+local forcenotdef = false
+
+local wildcard = "*"
+local default = "dflt"
+
+local fontloaderfields = fontloader.fields
+local mainfields = nil
+local glyphfields = nil -- not used yet
+
+registerdirective("fonts.otf.loader.cleanup", function(v) cleanup = tonumber(v) or (v and 1) or 0 end)
+registerdirective("fonts.otf.loader.force", function(v) forceload = v end)
+registerdirective("fonts.otf.loader.usemetatables", function(v) usemetatables = v end)
+registerdirective("fonts.otf.loader.pack", function(v) packdata = v end)
+registerdirective("fonts.otf.loader.syncspace", function(v) syncspace = v end)
+registerdirective("fonts.otf.loader.forcenotdef", function(v) forcenotdef = v end)
local function load_featurefile(raw,featurefile)
if featurefile and featurefile ~= "" then
@@ -116,19 +95,19 @@ local function load_featurefile(raw,featurefile)
end
end
-local function showfeatureorder(otfdata,filename)
- local sequences = otfdata.luatex.sequences
+local function showfeatureorder(rawdata,filename)
+ local sequences = rawdata.resources.sequences
if sequences and #sequences > 0 then
if trace_loading then
report_otf("font %s has %s sequences",filename,#sequences)
report_otf(" ")
end
for nos=1,#sequences do
- local sequence = sequences[nos]
- local typ = sequence.type or "no-type"
- local name = sequence.name or "no-name"
+ local sequence = sequences[nos]
+ local typ = sequence.type or "no-type"
+ local name = sequence.name or "no-name"
local subtables = sequence.subtables or { "no-subtables" }
- local features = sequence.features
+ local features = sequence.features
if trace_loading then
report_otf("%3i %-15s %-20s [%s]",nos,name,typ,concat(subtables,","))
end
@@ -160,25 +139,6 @@ end
<p>We start with a lot of tables and related functions.</p>
--ldx]]--
-local global_fields = table.tohash {
- "metadata",
- "lookups",
- "glyphs",
- "subfonts",
- "luatex",
- "pfminfo",
- "cidinfo",
- "tables",
- "names",
- "unicodes",
- "names",
- -- "math",
- "anchor_classes",
- "kern_classes",
- "gpos",
- "gsub"
-}
-
local valid_fields = table.tohash {
-- "anchor_classes",
"ascent",
@@ -194,32 +154,32 @@ local valid_fields = table.tohash {
"extrema_bound",
"familyname",
"fontname",
+ "fontname",
"fontstyle_id",
"fontstyle_name",
"fullname",
-- "glyphs",
"hasvmetrics",
- "head_optimized_for_cleartype",
+ -- "head_optimized_for_cleartype",
"horiz_base",
"issans",
"isserif",
"italicangle",
-- "kerns",
-- "lookups",
- -- "luatex",
"macstyle",
-- "modificationtime",
"onlybitmaps",
"origname",
"os2_version",
- -- "pfminfo",
+ "pfminfo",
-- "private",
"serifcheck",
"sfd_version",
-- "size",
"strokedfont",
"strokewidth",
- "subfonts",
+ -- "subfonts",
"table_version",
-- "tables",
-- "ttf_tab_saved",
@@ -231,7 +191,6 @@ local valid_fields = table.tohash {
"use_typo_metrics",
"uwidth",
-- "validation_state",
- "verbose",
"version",
"vert_base",
"weight",
@@ -258,43 +217,47 @@ local ordered_enhancers = {
"reorganize glyph lookups",
"reorganize glyph anchors",
+ "merge kern classes",
+
"reorganize features",
"reorganize subtables",
"check glyphs",
"check metadata",
- "check math parameters",
"check extra features", -- after metadata
+
+ "cleanup tables",
}
--[[ldx--
<p>Here we go.</p>
--ldx]]--
-local actions = { }
-
-patches.before = allocate()
-patches.after = allocate()
+local actions = allocate()
+local before = allocate()
+local after = allocate()
-local before = patches.before
-local after = patches.after
+patches.before = before
+patches.after = after
-local function enhance(name,data,filename,raw,verbose)
+local function enhance(name,data,filename,raw)
local enhancer = actions[name]
if enhancer then
- if verbose then
+ if trace_loading then
report_otf("enhance: %s (%s)",name,filename)
ioflush()
end
enhancer(data,filename,raw)
- else
- report_otf("enhance: %s is undefined",name)
+ elseif trace_loading then
+ -- report_otf("enhance: %s is undefined",name)
end
end
-function enhancers.apply(data,filename,raw,verbose)
+function enhancers.apply(data,filename,raw)
local basename = file.basename(lower(filename))
- report_otf("start enhancing: %s",filename)
+ if trace_loading then
+ report_otf("start enhancing: %s",filename)
+ end
ioflush() -- we want instant messages
for e=1,#ordered_enhancers do
local enhancer = ordered_enhancers[e]
@@ -306,7 +269,7 @@ function enhancers.apply(data,filename,raw,verbose)
end
end
end
- enhance(enhancer,data,filename,raw,verbose)
+ enhance(enhancer,data,filename,raw)
local a = after[enhancer]
if a then
for pattern, action in next, a do
@@ -317,7 +280,9 @@ function enhancers.apply(data,filename,raw,verbose)
end
ioflush() -- we want instant messages
end
- report_otf("stop enhancing")
+ if trace_loading then
+ report_otf("stop enhancing")
+ end
ioflush() -- we want instant messages
end
@@ -345,11 +310,14 @@ end
function otf.load(filename,format,sub,featurefile)
local name = file.basename(file.removesuffix(filename))
local attr = lfs.attributes(filename)
- local size, time = attr and attr.size or 0, attr and attr.modification or 0
+ local size = attr and attr.size or 0
+ local time = attr and attr.modification or 0
if featurefile then
name = name .. "@" .. file.removesuffix(file.basename(featurefile))
end
- if sub == "" then sub = false end
+ if sub == "" then
+ sub = false
+ end
local hash = name
if sub then
hash = hash .. "-" .. sub
@@ -366,8 +334,8 @@ function otf.load(filename,format,sub,featurefile)
local attr = lfs.attributes(name)
featurefiles[#featurefiles+1] = {
name = name,
- size = attr.size or 0,
- time = attr.modification or 0,
+ size = size,
+ time = time,
}
end
end
@@ -376,7 +344,7 @@ function otf.load(filename,format,sub,featurefile)
end
end
local data = containers.read(otf.cache,hash)
- local reload = not data or data.verbose ~= fonts.verbose or data.size ~= size or data.time ~= time
+ local reload = not data or data.size ~= size or data.time ~= time
if forceload then
report_otf("loading: forced reload due to hard coded flag")
reload = true
@@ -404,7 +372,7 @@ function otf.load(filename,format,sub,featurefile)
end
if reload then
report_otf("loading: %s (hash: %s)",filename,hash)
- local fontdata, messages, rawdata
+ local fontdata, messages
if sub then
fontdata, messages = fontloader.open(filename,sub)
else
@@ -430,51 +398,66 @@ function otf.load(filename,format,sub,featurefile)
load_featurefile(fontdata,featurefiles[i].name)
end
end
- report_otf("loading method: %s",loadmethod)
- if loadmethod == "sparse" then
- rawdata = fontdata
- else
- rawdata = fontloader.to_table(fontdata)
- fontloader.close(fontdata)
- end
- if rawdata then
- data = { }
- starttiming(data)
- local verboseindeed = verbose ~= nil and verbose or trace_loading
- report_otf("file size: %s", size)
- enhancers.apply(data,filename,rawdata,verboseindeed)
- if packdata and not fonts.verbose then
- enhance("pack",data,filename,nil,verboseindeed)
- end
- data.size = size
- data.time = time
- data.format = format
- if featurefiles then
- data.featuredata = featurefiles
- end
- data.verbose = fonts.verbose
- report_otf("saving in cache: %s",filename)
- data = containers.write(otf.cache, hash, data)
+ local unicodes = {
+ -- names to unicodes
+ }
+ local splitter = lpeg.splitter(" ",unicodes)
+ data = {
+ size = size,
+ time = time,
+ format = format,
+ featuredata = featurefiles,
+ resources = {
+ filename = resolvers.unresolve(filename), -- no shortcut
+ version = otf.version,
+ creator = "context mkiv",
+ unicodes = unicodes,
+ indices = {
+ -- unicodes to names
+ },
+ lookuptypes = {
+ },
+ },
+ metadata = {
+ -- raw metadata, not to be used
+ },
+ properties = {
+ -- normalized metadata
+ },
+ descriptions = {
+ },
+ goodies = {
+ },
+ helpers = {
+ tounicodelist = splitter,
+ tounicodetable = lpeg.Ct(splitter),
+ },
+ }
+ starttiming(data)
+ report_otf("file size: %s", size)
+ enhancers.apply(data,filename,fontdata)
+ if packdata then
if cleanup > 0 then
collectgarbage("collect")
end
- stoptiming(data)
- if elapsedtime then -- not in generic
- report_otf("preprocessing and caching took %s seconds",elapsedtime(data))
- end
- data = containers.read(otf.cache, hash) -- this frees the old table and load the sparse one
- if cleanup > 1 then
- collectgarbage("collect")
- end
- else
- data = nil
- report_otf("loading failed (table conversion error)")
+ enhance("pack",data,filename,nil)
end
- if loadmethod == "sparse" then
- fontloader.close(fontdata)
- if cleanup > 2 then
- -- collectgarbage("collect")
- end
+ report_otf("saving in cache: %s",filename)
+ data = containers.write(otf.cache, hash, data)
+ if cleanup > 1 then
+ collectgarbage("collect")
+ end
+ stoptiming(data)
+ if elapsedtime then -- not in generic
+ report_otf("preprocessing and caching took %s seconds",elapsedtime(data))
+ end
+ fontloader.close(fontdata) -- free memory
+ if cleanup > 3 then
+ collectgarbage("collect")
+ end
+ data = containers.read(otf.cache, hash) -- this frees the old table and load the sparse one
+ if cleanup > 2 then
+ collectgarbage("collect")
end
else
data = nil
@@ -510,35 +493,42 @@ local mt = {
end
}
+actions["prepare tables"] = function(data,filename,raw)
+ data.properties.italic_correction = false
+end
+
actions["add dimensions"] = function(data,filename)
-- todo: forget about the width if it's the defaultwidth (saves mem)
-- we could also build the marks hash here (instead of storing it)
if data then
- local luatex = data.luatex
- local defaultwidth = luatex.defaultwidth or 0
- local defaultheight = luatex.defaultheight or 0
- local defaultdepth = luatex.defaultdepth or 0
+ local descriptions = data.descriptions
+ local resources = data.resources
+ local defaultwidth = resources.defaultwidth or 0
+ local defaultheight = resources.defaultheight or 0
+ local defaultdepth = resources.defaultdepth or 0
if usemetatables then
- for _, d in next, data.glyphs do
+ for _, d in next, descriptions do
local wd = d.width
if not wd then
d.width = defaultwidth
- elseif wd ~= 0 and d.class == "mark" then
- d.width = -wd
+ elseif trace_markwidth and wd ~= 0 and d.class == "mark" then
+ report_otf("mark with width %s (%s) in %s",wd,d.name or "<noname>",file.basename(filename))
+ -- d.width = -wd
end
setmetatable(d,mt)
end
else
- for _, d in next, data.glyphs do
+ for _, d in next, descriptions do
local bb, wd = d.boundingbox, d.width
if not wd then
d.width = defaultwidth
- elseif wd ~= 0 and d.class == "mark" then
- d.width = -wd
- end
- if forcenotdef and not d.name then
- d.name = ".notdef"
+ elseif trace_markwidth and wd ~= 0 and d.class == "mark" then
+ report_otf("mark with width %s (%s) in %s",wd,d.name or "<noname>",file.basename(filename))
+ -- d.width = -wd
end
+ -- if forcenotdef and not d.name then
+ -- d.name = ".notdef"
+ -- end
if bb then
local ht, dp = bb[4], -bb[2]
if ht == 0 or ht < 0 then
@@ -557,16 +547,6 @@ actions["add dimensions"] = function(data,filename)
end
end
-actions["prepare tables"] = function(data,filename,raw)
- local luatex = {
- filename = resolvers.unresolve(filename), -- no shortcut
- version = otf.version,
- creator = "context mkiv",
- }
- data.luatex = luatex
- data.metadata = { }
-end
-
local function somecopy(old) -- fast one
if old then
local new = { }
@@ -603,192 +583,220 @@ end
-- table cronstruction can save some mem
actions["prepare glyphs"] = function(data,filename,raw)
- -- we can also move the names to data.luatex.names which might
- -- save us some more memory (at the cost of harder tracing)
- local rawglyphs = raw.glyphs
- local glyphs, udglyphs
- if loadmethod == "sparse" then
- glyphs, udglyphs = { }, { }
- elseif loadmethod == "mixed" then
- glyphs, udglyphs = { }, rawglyphs
- else
- glyphs, udglyphs = rawglyphs, rawglyphs
- end
- data.glyphs, data.udglyphs = glyphs, udglyphs
- local subfonts = raw.subfonts
- if subfonts then
- if data.glyphs and next(data.glyphs) then
- report_otf("replacing existing glyph table due to subfonts")
- end
- local cidinfo = raw.cidinfo
- if cidinfo.registry then
- local cidmap, cidname = fonts.cid.getmap(cidinfo.registry,cidinfo.ordering,cidinfo.supplement)
+ local rawglyphs = raw.glyphs
+ local rawsubfonts = raw.subfonts
+ local rawcidinfo = raw.cidinfo
+ local criterium = constructors.privateoffset
+ local private = criterium
+ local resources = data.resources
+ local metadata = data.metadata
+ local properties = data.properties
+ local descriptions = data.descriptions
+ local unicodes = resources.unicodes -- name to unicode
+ local indices = resources.indices -- index to unicode
+
+ if rawsubfonts then
+
+ metadata.subfonts = { }
+ properties.cidinfo = rawcidinfo
+
+ if rawcidinfo.registry then
+ local cidmap = fonts.cid.getmap(rawcidinfo)
if cidmap then
- cidinfo.usedname = cidmap.usedname
- local uni_to_int, int_to_uni, nofnames, nofunicodes = { }, { }, 0, 0
- local unicodes, names = cidmap.unicodes, cidmap.names
- for cidindex=1,#subfonts do
- local subfont = subfonts[cidindex]
- if loadmethod == "sparse" then
- local rawglyphs = subfont.glyphs
- for index=0,subfont.glyphmax - 1 do
- local g = rawglyphs[index]
- if g then
- local unicode, name = unicodes[index], names[index]
- if unicode then
- uni_to_int[unicode] = index
- int_to_uni[index] = unicode
- nofunicodes = nofunicodes + 1
- elseif name then
- nofnames = nofnames + 1
- end
- udglyphs[index] = g
- glyphs[index] = {
- width = g.width,
- italic = g.italic_correction,
- boundingbox = g.boundingbox,
- class = g.class,
- name = g.name or name or "unknown", -- uniXXXX
- cidindex = cidindex,
- unicode = unicode,
- }
+ rawcidinfo.usedname = cidmap.usedname
+ local nofnames, nofunicodes = 0, 0
+ local cidunicodes, cidnames = cidmap.unicodes, cidmap.names
+ for cidindex=1,#rawsubfonts do
+ local subfont = rawsubfonts[cidindex]
+ local cidglyphs = subfont.glyphs
+ metadata.subfonts[cidindex] = somecopy(subfont)
+ for index=0,subfont.glyphmax - 1 do
+ local glyph = cidglyphs[index]
+ if glyph then
+ local unicode = glyph.unicode
+ local name = glyph.name or cidnames[index]
+ if not unicode or unicode == -1 or unicode >= criterium then
+ unicode = cidunicodes[index]
end
- end
- -- If we had more userdata, we would need more of this
- -- and it would start working against us in terms of
- -- convenience and speed.
- subfont = somecopy(subfont)
- subfont.glyphs = nil
- subfont[cidindex] = subfont
- elseif loadmethod == "mixed" then
- for index, g in next, subfont.glyphs do
- local unicode, name = unicodes[index], names[index]
- if unicode then
- uni_to_int[unicode] = index
- int_to_uni[index] = unicode
- nofunicodes = nofunicodes + 1
- elseif name then
+ if not unicode or unicode == -1 or unicode >= criterium then
+ if not name then
+ name = format("u%06X",private)
+ end
+ unicode = private
+ unicodes[name] = private
+ if trace_private then
+ report_otf("enhance: glyph %s at index U+%04X is moved to private unicode slot U+%04X",name,index,private)
+ end
+ private = private + 1
nofnames = nofnames + 1
+ else
+ if not name then
+ name = format("u%06X",unicode)
+ end
+ unicodes[name] = unicode
+ nofunicodes = nofunicodes + 1
end
- udglyphs[index] = g
- glyphs[index] = {
- width = g.width,
- italic = g.italic_correction,
- boundingbox = g.boundingbox,
- class = g.class,
- name = g.name or name or "unknown", -- uniXXXX
+ indices[unicode] = index -- each index in unique (at least now)
+
+ local description = {
+ -- width = glyph.width,
+ boundingbox = glyph.boundingbox,
+ name = glyph.name or name or "unknown", -- uniXXXX
cidindex = cidindex,
- unicode = unicode,
+ index = index,
+ glyph = glyph,
}
+
+ descriptions[unicode] = description
end
- subfont.glyphs = nil
- else
- for index, g in next, subfont.glyphs do
- local unicode, name = unicodes[index], names[index]
- if unicode then
- uni_to_int[unicode] = index
- int_to_uni[index] = unicode
- nofunicodes = nofunicodes + 1
- g.unicode = unicode
- elseif name then
- nofnames = nofnames + 1
- end
- g.cidindex = cidindex
- glyphs[index] = g
- end
- subfont.glyphs = nil
end
end
if trace_loading then
report_otf("cid font remapped, %s unicode points, %s symbolic names, %s glyphs",nofunicodes, nofnames, nofunicodes+nofnames)
end
- data.map = data.map or { }
- data.map.map = uni_to_int
- data.map.backmap = int_to_uni
elseif trace_loading then
report_otf("unable to remap cid font, missing cid file for %s",filename)
end
- data.subfonts = subfonts
elseif trace_loading then
report_otf("font %s has no glyphs",filename)
end
+
else
- if loadmethod == "sparse" then
- -- we get fields from the userdata glyph table and create
- -- a minimal entry first
- for index=0,raw.glyphmax - 1 do
- local g = rawglyphs[index]
- if g then
- udglyphs[index] = g
- glyphs[index] = {
- width = g.width,
- italic = g.italic_correction,
- boundingbox = g.boundingbox,
- class = g.class,
- name = g.name,
- unicode = g.unicode,
- }
+
+ for index=0,raw.glyphmax-1 do
+ local glyph = rawglyphs[index]
+ if glyph then
+ local unicode = glyph.unicode
+ local name = glyph.name
+ if not unicode or unicode == -1 or unicode >= criterium then
+ unicode = private
+ unicodes[name] = private
+ if trace_private then
+ report_otf("enhance: glyph %s at index U+%04X is moved to private unicode slot U+%04X",name,index,private)
+ end
+ private = private + 1
+ else
+ unicodes[name] = unicode
end
- end
- elseif loadmethod == "mixed" then
- -- we get fields from the totable glyph table and copy to the
- -- final glyph table so first we create a minimal entry
- for index, g in next, rawglyphs do
- udglyphs[index] = g
- glyphs[index] = {
- width = g.width,
- italic = g.italic_correction,
- boundingbox = g.boundingbox,
- class = g.class,
- name = g.name,
- unicode = g.unicode,
+ indices[unicode] = index
+ if not name then
+ name = format("u%06X",unicode)
+ end
+
+ descriptions[unicode] = {
+ -- width = glyph.width,
+ boundingbox = glyph.boundingbox,
+ name = name,
+ index = index,
+ glyph = glyph,
}
end
- else
- -- we use the totable glyph table directly and manipulate the
- -- entries in this (also final) table
end
- data.map = raw.map
+
end
- data.cidinfo = raw.cidinfo -- hack
+
+ resources.private = private
+
end
--- watch copy of cidinfo: we can best make some more copies to data
+-- the next one is still messy but will get better when we have
+-- flattened map/enc tables in the font loader
+
+actions["prepare unicodes"] = function(data,filename,raw)
+ local descriptions = data.descriptions
+ local resources = data.resources
+ local properties = data.properties
+ local unicodes = resources.unicodes -- name to unicode
+ local indices = resources.indices -- index to unicodes
+
+ -- begin of messy (not needed whwn cidmap)
+
+ local mapdata = raw.map or { }
+ local unicodetoindex = mapdata and mapdata.map or { }
+ -- local encname = lower(data.enc_name or raw.enc_name or mapdata.enc_name or "")
+ local encname = lower(data.enc_name or mapdata.enc_name or "")
+ local criterium = 0xFFFF -- for instance cambria has a lot of mess up there
+
+ -- end of messy
+
+ if find(encname,"unicode") then -- unicodebmp, unicodefull, ...
+ if trace_loading then
+ report_otf("using embedded unicode map '%s'",encname)
+ end
+ local multiples, nofmultiples = { }, 0
+ for unicode, index in next, unicodetoindex do
+ if unicode <= criterium and not descriptions[unicode] then
+ local parent = indices[index]
+ local description = descriptions[parent]
+ if description then
+ local c = fastcopy(description)
+ c.comment = format("copy of 0x%04X", parent)
+ descriptions[unicode] = c
+ local name = c.name
+ if not unicodes[name] then
+ unicodes[name] = unicode
+ end
+ nofmultiples = nofmultiples + 1
+ multiples[nofmultiples] = name -- we can save duplicates if needed
+ else
+ -- make it a notdef
+ report_otf("weird unicode 0x%04X at index 0x%04X",unicode,index)
+ end
+ end
+ end
+ if trace_loading then
+ if nofmultiples > 0 then
+ report_otf("%s glyphs are reused: %s",nofmultiples,concat(multiples," "))
+ else
+ report_otf("no glyphs are reused")
+ end
+ end
+ elseif properties.cidinfo then
+ report_otf("warning: no unicode map, used cidmap '%s'",properties.cidinfo.usedname or "?")
+ else
+ report_otf("warning: non unicode map '%s', only using glyph unicode data",encname or "whatever")
+ end
+
+ if mapdata then
+ mapdata.map = { } -- clear some memory
+ end
+end
+
+-- class : nil base mark ligature component (maybe we don't need it in description)
+-- boundingbox: split into ht/dp takes more memory (larger tables and less sharing)
actions["analyze glyphs"] = function(data,filename,raw) -- maybe integrate this in the previous
- local glyphs = data.glyphs
- -- collect info
- local has_italic, widths, marks = false, { }, { }
- for index, glyph in next, glyphs do
- local italic = glyph.italic_correction
+ local descriptions = data.descriptions
+ local resources = data.resources
+ local metadata = data.metadata
+ local properties = data.properties
+ local italic_correction = false
+ local widths = { }
+ local marks = { }
+ for unicode, description in next, descriptions do
+ local glyph = description.glyph
if not italic then
-- skip
elseif italic == 0 then
- glyph.italic_correction = nil
- glyph.italic = nil
+ -- skip
else
- glyph.italic_correction = nil
- glyph.italic = italic
- has_italic = true
+ description.italic = italic
+ italic_correction = true
end
local width = glyph.width
widths[width] = (widths[width] or 0) + 1
local class = glyph.class
- local unicode = glyph.unicode
- if class == "mark" then
- marks[unicode] = true
- -- elseif chardata[unicode].category == "mn" then
- -- marks[unicode] = true
- -- glyph.class = "mark"
+ if class then
+ if class == "mark" then
+ marks[unicode] = true
+ end
+ description.class = class
end
- local a = glyph.altuni if a then glyph.altuni = nil end
- local d = glyph.dependents if d then glyph.dependents = nil end
- local v = glyph.vwidth if v then glyph.vwidth = nil end
end
-- flag italic
- data.metadata.has_italic = has_italic
+ properties.italic_correction = italic_correction
-- flag marks
- data.luatex.marks = marks
+ resources.marks = marks
-- share most common width for cjk fonts
local wd, most = 0, 1
for k,v in next, widths do
@@ -800,43 +808,41 @@ actions["analyze glyphs"] = function(data,filename,raw) -- maybe integrate this
if trace_loading then
report_otf("most common width: %s (%s times), sharing (cjk font)",wd,most)
end
- for index, glyph in next, glyphs do
- if glyph.width == wd then
- glyph.width = nil
+ for unicode, description in next, descriptions do
+ if description.width == wd then
+ -- description.width = nil
+ else
+ description.width = description.glyph.width
end
end
- data.luatex.defaultwidth = wd
+ resources.defaultwidth = wd
+ else
+ for unicode, description in next, descriptions do
+ description.width = description.glyph.width
+ end
end
end
actions["reorganize mark classes"] = function(data,filename,raw)
local mark_classes = raw.mark_classes
if mark_classes then
- local luatex = data.luatex
- local unicodes = luatex.unicodes
- local reverse = { }
- luatex.markclasses = reverse
+ local resources = data.resources
+ local unicodes = resources.unicodes
+ local markclasses = { }
+ resources.markclasses = markclasses -- reversed
for name, class in next, mark_classes do
local t = { }
for s in gmatch(class,"[^ ]+") do
- local us = unicodes[s]
- if type(us) == "table" then
- for u=1,#us do
- t[us[u]] = true
- end
- else
- t[us] = true
- end
+ t[unicodes[s]] = true
end
- reverse[name] = t
+ markclasses[name] = t
end
- data.mark_classes = nil -- when using table
end
end
actions["reorganize features"] = function(data,filename,raw) -- combine with other
local features = { }
- data.luatex.features = features
+ data.resources.features = features
for k, what in next, otf.glists do
local dw = raw[what]
if dw then
@@ -849,7 +855,11 @@ actions["reorganize features"] = function(data,filename,raw) -- combine with oth
for i=1,#dfeatures do
local df = dfeatures[i]
local tag = strip(lower(df.tag))
- local ft = f[tag] if not ft then ft = {} f[tag] = ft end
+ local ft = f[tag]
+ if not ft then
+ ft = { }
+ f[tag] = ft
+ end
local dscripts = df.scripts
for i=1,#dscripts do
local d = dscripts[i]
@@ -868,25 +878,34 @@ actions["reorganize features"] = function(data,filename,raw) -- combine with oth
end
actions["reorganize anchor classes"] = function(data,filename,raw)
- local classes = raw.anchor_classes -- anchor classes not in final table
- local luatex = data.luatex
- local anchor_to_lookup, lookup_to_anchor = { }, { }
- luatex.anchor_to_lookup, luatex.lookup_to_anchor = anchor_to_lookup, lookup_to_anchor
+ local resources = data.resources
+ local anchor_to_lookup = { }
+ local lookup_to_anchor = { }
+ resources.anchor_to_lookup = anchor_to_lookup
+ resources.lookup_to_anchor = lookup_to_anchor
+ local classes = raw.anchor_classes -- anchor classes not in final table
if classes then
for c=1,#classes do
- local class = classes[c]
- local anchor = class.name
+ local class = classes[c]
+ local anchor = class.name
local lookups = class.lookup
if type(lookups) ~= "table" then
lookups = { lookups }
end
local a = anchor_to_lookup[anchor]
- if not a then a = { } anchor_to_lookup[anchor] = a end
+ if not a then
+ a = { }
+ anchor_to_lookup[anchor] = a
+ end
for l=1,#lookups do
local lookup = lookups[l]
local l = lookup_to_anchor[lookup]
- if not l then l = { } lookup_to_anchor[lookup] = l end
- l[anchor] = true
+ if l then
+ l[anchor] = true
+ else
+ l = { [anchor] = true }
+ lookup_to_anchor[lookup] = l
+ end
a[lookup] = true
end
end
@@ -894,13 +913,16 @@ actions["reorganize anchor classes"] = function(data,filename,raw)
end
actions["prepare tounicode"] = function(data,filename,raw)
- fonts.map.addtounicode(data,filename)
+ fonts.mappings.addtounicode(data,filename)
end
actions["reorganize subtables"] = function(data,filename,raw)
- local luatex = data.luatex
- local sequences, lookups = { }, { }
- luatex.sequences, luatex.lookups = sequences, lookups
+ local resources = data.resources
+ local sequences = { }
+ local lookups = { }
+ local chainedfeatures = { }
+ resources.sequences = sequences
+ resources.lookups = lookups
for _, what in next, otf.glists do
local dw = raw[what]
if dw then
@@ -915,9 +937,7 @@ actions["reorganize subtables"] = function(data,filename,raw)
if subtables then
local t = { }
for s=1,#subtables do
- local subtable = subtables[s]
- local name = subtable.name
- t[#t+1] = name
+ t[s] = subtables[s].name
end
subtables = t
end
@@ -931,7 +951,7 @@ actions["reorganize subtables"] = function(data,filename,raw)
}
markclass = flags.mark_class
if markclass then
- markclass = luatex.markclasses[markclass]
+ markclass = resources.markclasses[markclass]
end
flags = t
end
@@ -980,138 +1000,165 @@ actions["reorganize subtables"] = function(data,filename,raw)
end
end
--- the next one is still messy but will get better when we have
--- flattened map/enc tables in the font loader
+-- test this:
+--
+-- for _, what in next, otf.glists do
+-- raw[what] = nil
+-- end
-actions["prepare unicodes"] = function(data,filename,raw)
- local luatex = data.luatex
- local indices, unicodes, multiples, internals= { }, { }, { }, { }
- local mapdata = data.map or raw.map -- map already moved
- local mapmap
- if not mapdata then
- report_otf("no mapdata in '%s'",filename)
- mapmap = { }
- mapdata = { map = mapmap }
- data.map = mapdata
- elseif not mapdata.map then
- report_otf("no map in mapdata of '%s'",filename)
- mapmap = { }
- mapdata.map = mapmap
- else
- mapmap = mapdata.map
- end
- local encname = lower(data.enc_name or raw.enc_name or mapdata.enc_name or "")
- local criterium = fonts.privateoffset
- local private = criterium
- local glyphs = data.glyphs
- -- todo: nofmultiples
- for index, glyph in next, glyphs do
- if index > 0 then
- local name = glyph.name -- really needed ?
- if name then
- local unicode = glyph.unicode
- if not unicode or unicode == -1 or unicode >= criterium then
- glyph.unicode = private
- indices[private] = index
- unicodes[name] = private
- internals[index] = true
- if trace_private then
- report_otf("enhance: glyph %s at index U+%04X is moved to private unicode slot U+%04X",name,index,private)
- end
- private = private + 1
- else
- indices[unicode] = index
- unicodes[name] = unicode
- end
- -- maybe deal with altuni here in the future but first we need
- -- to encounter a proper font that sets them; we have to wait till
- -- a next luatex binary as currently the unicode numbers can be out
- -- of bounds
- if false then
- local altuni = glyph.altuni
- if altuni then
- local un = { unicodes[name] }
- for i=1,#altuni do
- local unicode = altuni[i].unicode
- multiples[#multiples+1] = name
- un[i+1] = unicode
- indices[unicode] = index -- maybe check for duplicates
- end
- unicodes[name] = un
- end
- end
- else
- -- message that something is wrong
- end
- end
- end
- -- beware: the indices table is used to initialize the tfm table
- if find(encname,"unicode") then -- unicodebmp, unicodefull, ...
- if trace_loading then
- report_otf("using embedded unicode map '%s'",encname)
- end
- -- ok -- we can also consider using the altuni
- for unicode, index in next, mapmap do
- if not internals[index] then
- local name = glyphs[index].name
- if name then
- local un = unicodes[name]
- if not un then
- unicodes[name] = unicode -- or 0
- elseif type(un) == "number" then -- tonumber(un)
- if un ~= unicode then
- multiples[#multiples+1] = name
- unicodes[name] = { un, unicode }
- indices[unicode] = index
- end
- else
- local ok = false
- for u=1,#un do
- if un[u] == unicode then
- ok = true
- break
- end
- end
- if not ok then
- multiples[#multiples+1] = name
- un[#un+1] = unicode
- indices[unicode] = index
- end
- end
- end
- end
- end
- else
- report_otf("warning: non unicode map '%s', only using glyph unicode data",encname or "whatever")
+actions["prepare lookups"] = function(data,filename,raw)
+ local lookups = raw.lookups
+ if lookups then
+ data.lookups = lookups
end
- if trace_loading then
- if #multiples > 0 then
- report_otf("%s glyphs are reused: %s",#multiples, concat(multiples," "))
- else
- report_otf("no glyphs are reused")
+end
+
+local function t_uncover(splitter,cache,covers)
+ local result = { }
+ for n=1,#covers do
+ local cover = covers[n]
+ local uncovered = cache[cover]
+ if not uncovered then
+ uncovered = lpegmatch(splitter,cover)
+ cache[cover] = uncovered
end
+ result[n] = uncovered
end
- luatex.indices = indices
- luatex.unicodes = unicodes
- luatex.private = private
+ return result
end
-actions["prepare lookups"] = function(data,filename,raw)
- local lookups = raw.lookups
- if lookups then
- data.lookups = lookups
+local function s_uncover(splitter,cache,cover)
+ if cover == "" then
+ return nil
+ else
+ local uncovered = cache[cover]
+ if not uncovered then
+ uncovered = lpegmatch(splitter,cover)
+ cache[cover] = uncovered
+ end
+ return uncovered
end
end
actions["reorganize lookups"] = function(data,filename,raw)
-- we prefer the before lookups in a normal order
if data.lookups then
- for _, v in next, data.lookups do
- if v.rules then
- for _, vv in next, v.rules do
- local c = vv.coverage
- if c and c.before then
- c.before = reversed(c.before)
+ local splitter = data.helpers.tounicodetable
+ local cache = { }
+ for _, lookup in next, data.lookups do
+ local rules = lookup.rules
+ if rules then
+ local format = lookup.format
+ if format == "class" then
+ local before_class = lookup.before_class
+ if before_class then
+ before_class = t_uncover(splitter,cache,reversed(before_class))
+ end
+ local current_class = lookup.current_class
+ if current_class then
+ current_class = t_uncover(splitter,cache,current_class)
+ end
+ local after_class = lookup.after_class
+ if after_class then
+ after_class = t_uncover(splitter,cache,after_class)
+ end
+ for i=1,#rules do
+ local rule = rules[i]
+ local class = rule.class
+ local before = class.before
+ if before then
+ for i=1,#before do
+ before[i] = before_class[before[i]] or { }
+ end
+ rule.before = before
+ end
+ local current = class.current
+ local lookups = rule.lookups
+ if current then
+ for i=1,#current do
+ current[i] = current_class[current[i]] or { }
+ if lookups and not lookups[i] then
+ lookups[i] = false
+ end
+ end
+ rule.current = current
+ end
+ local after = class.after
+ if after then
+ for i=1,#after do
+ after[i] = after_class[after[i]] or { }
+ end
+ rule.after = after
+ end
+ rule.class = nil
+ end
+ lookup.before_class = nil
+ lookup.current_class = nil
+ lookup.after_class = nil
+ lookup.format = "coverage"
+ elseif format == "coverage" then
+ for i=1,#rules do
+ local rule = rules[i]
+ local coverage = rule.coverage
+ if coverage then
+ local before = coverage.before
+ if before then
+ rule.before = t_uncover(splitter,cache,reversed(before))
+ end
+ local current = coverage.current
+ if current then
+ rule.current = t_uncover(splitter,cache,current)
+ end
+ local after = coverage.after
+ if after then
+ rule.after = t_uncover(splitter,cache,after)
+ end
+ rule.coverage = nil
+ end
+ end
+ elseif format == "reversecoverage" then
+ for i=1,#rules do
+ local rule = rules[i]
+ local reversecoverage = rule.reversecoverage
+ if reversecoverage then
+ local before = reversecoverage.before
+ if before then
+ rule.before = t_uncover(splitter,cache,reversed(before))
+ end
+ local current = reversecoverage.current
+ if current then
+ rule.current = t_uncover(splitter,cache,current)
+ end
+ local after = reversecoverage.after
+ if after then
+ rule.after = t_uncover(splitter,cache,after)
+ end
+ local replacements = reversecoverage.replacements
+ if replacements then
+ rule.replacements = s_uncover(splitter,cache,replacements)
+ end
+ rule.reversecoverage = nil
+ end
+ end
+ elseif format == "glyphs" then
+ for i=1,#rules do
+ local rule = rules[i]
+ local glyphs = rule.glyphs
+ if glyphs then
+ local fore = glyphs.fore
+ if fore then
+ rule.fore = s_uncover(splitter,cache,fore)
+ end
+ local back = glyphs.back
+ if back then
+ rule.back = s_uncover(splitter,cache,back)
+ end
+ local names = glyphs.names
+ if names then
+ rule.names = s_uncover(splitter,cache,names)
+ end
+ rule.glyphs = nil
+ end
end
end
end
@@ -1119,144 +1166,152 @@ actions["reorganize lookups"] = function(data,filename,raw)
end
end
+-- to be checked italic_correction
+
actions["analyze math"] = function(data,filename,raw)
if raw.math then
-data.metadata.math = raw.math
- -- we move the math stuff into a math subtable because we then can
- -- test faster in the tfm copy
- local glyphs, udglyphs = data.glyphs, data.udglyphs
- local unicodes = data.luatex.unicodes
- for index, udglyph in next, udglyphs do
- local mk = udglyph.mathkern
- local hv = udglyph.horiz_variants
- local vv = udglyph.vert_variants
- if mk or hv or vv then
- local glyph = glyphs[index]
+ data.metadata.math = raw.math
+ local unicodes = data.resources.unicodes
+ local splitter = data.helpers.tounicodetable
+ for unicode, description in next, data.descriptions do
+ local glyph = description.glyph
+ local mathkerns = glyph.mathkern -- singular
+ local horiz_variants = glyph.horiz_variants
+ local vert_variants = glyph.vert_variants
+ local top_accent = glyph.top_accent
+ if mathkerns or horiz_variants or vert_variants or top_accent then
local math = { }
- glyph.math = math
- if mk then
- for k, v in next, mk do
+ if top_accent then
+ math.top_accent = top_accent
+ end
+ if mathkerns then
+ for k, v in next, mathkerns do
if not next(v) then
- mk[k] = nil
+ mathkerns[k] = nil
+ else
+ for k, v in next, v do
+ if v == 0 then
+ k[v] = nil -- height / kern can be zero
+ end
+ end
end
end
- math.kerns = mk
+ math.kerns = mathkerns
end
- if hv then
- math.horiz_variants = hv.variants
- local p = hv.parts
- if p and #p > 0 then
- for i=1,#p do
- local pi = p[i]
+ if horiz_variants then
+ local variants = horiz_variants.variants
+ if variants then -- use splitter
+ local glyphs = lpegmatch(splitter,variants)
+ for i=1,#glyphs do
+ if glyphs[i] == u then
+ remove(glyphs,i)
+ break
+ end
+ end
+ math.horiz_variants = glyphs
+ end
+ local parts = horiz_variants.parts
+ if parts and #parts > 0 then
+ for i=1,#parts do
+ local pi = parts[i]
pi.glyph = unicodes[pi.component] or 0
+ pi.component = nil
end
- math.horiz_parts = p
+ math.horiz_parts = parts
end
- local ic = hv.italic_correction
- if ic and ic ~= 0 then
- math.horiz_italic_correction = ic
+ local italic_correction = horiz_variants.italic_correction
+ if italic_correction and italic_correction ~= 0 then
+ math.horiz_italic_correction = italic_correction
end
end
- if vv then
- local uc = unicodes[index]
- math.vert_variants = vv.variants
- local p = vv.parts
- if p and #p > 0 then
- for i=1,#p do
- local pi = p[i]
+ if vert_variants then
+ local variants = vert_variants.variants
+ if variants then
+ local glyphs = lpegmatch(splitter,variants)
+ for i=1,#glyphs do
+ if glyphs[i] == u then
+ remove(glyphs,i)
+ break
+ end
+ end
+ math.vert_variants = glyphs
+ end
+ local p = vert_variants.parts
+ if parts and #parts > 0 then
+ for i=1,#parts do
+ local pi = parts[i]
pi.glyph = unicodes[pi.component] or 0
+ pi.component = nil
end
- math.vert_parts = p
+ math.vert_parts = parts
end
- local ic = vv.italic_correction
- if ic and ic ~= 0 then
- math.vert_italic_correction = ic
+ local italic_correction = vert_variants.italic_correction
+ if italic_correction and italic_correction ~= 0 then
+ math.vert_italic_correction = italic_correction
end
end
- local ic = glyph.italic_correction
- if ic then
- if ic ~= 0 then
- math.italic_correction = ic
- end
+ local italic_correction = description.italic
+ if italic_correction and italic_correction ~= 0 then
+ math.italic_correction = italic_correction
end
+ description.math = math
end
end
end
end
actions["reorganize glyph kerns"] = function(data,filename,raw)
- local luatex = data.luatex
- local udglyphs, glyphs, mapmap, unicodes = data.udglyphs, data.glyphs, luatex.indices, luatex.unicodes
- local mkdone = false
- local function do_it(lookup,first_unicode,extrakerns) -- can be moved inline but seldom used
- local glyph = glyphs[mapmap[first_unicode]]
- if glyph then
- local kerns = glyph.kerns
- if not kerns then
- kerns = { } -- unicode indexed !
- glyph.kerns = kerns
- end
- local lookupkerns = kerns[lookup]
- if not lookupkerns then
- lookupkerns = { }
- kerns[lookup] = lookupkerns
- end
- for second_unicode, kern in next, extrakerns do
- lookupkerns[second_unicode] = kern
- end
- elseif trace_loading then
- report_otf("no glyph data for U+%04X", first_unicode)
- end
- end
- for index, udglyph in next, data.udglyphs do
- local kerns = udglyph.kerns
+ local descriptions = data.descriptions
+ local resources = data.resources
+ local unicodes = resources.unicodes
+ for unicode, description in next, descriptions do
+ local kerns = description.glyph.kerns
if kerns then
- local glyph = glyphs[index]
local newkerns = { }
- for k,v in next, kerns do
- local vc, vo, vl = v.char, v.off, v.lookup
- if vc and vo and vl then -- brrr, wrong! we miss the non unicode ones
- local uvc = unicodes[vc]
- if not uvc then
- if trace_loading then
- report_otf("problems with unicode %s of kern %s at glyph %s",vc,k,index)
- end
- else
- if type(vl) ~= "table" then
- vl = { vl }
- end
- for l=1,#vl do
- local vll = vl[l]
- local mkl = newkerns[vll]
- if not mkl then
- mkl = { }
- newkerns[vll] = mkl
- end
- if type(uvc) == "table" then
- for u=1,#uvc do
- mkl[uvc[u]] = vo
+ for k, kern in next, kerns do
+ local name = kern.char
+ local offset = kern.off
+ local lookup = kern.lookup
+ if name and offset and lookup then
+ local unicode = unicodes[name]
+ if unicode then
+ if type(lookup) == "table" then
+ for l=1,#lookup do
+ local lookup = lookup[l]
+ local lookupkerns = newkerns[lookup]
+ if lookupkerns then
+ lookupkerns[unicode] = offset
+ else
+ newkerns[lookup] = { [unicode] = offset }
end
+ end
+ else
+ local lookupkerns = newkerns[lookup]
+ if lookupkerns then
+ lookupkerns[unicode] = offset
else
- mkl[uvc] = vo
+ newkerns[lookup] = { [unicode] = offset }
end
end
+ elseif trace_loading then
+ report_otf("problems with unicode %s of kern %s of glyph 0x%04X",name,k,unicode)
end
end
end
- glyph.kerns = newkerns -- udglyph.kerns = nil when in mixed mode
- mkdone = true
+ description.kerns = newkerns
end
end
- if trace_loading and mkdone then
- report_otf("replacing 'kerns' tables by a new 'kerns' tables")
- end
- local dgpos = raw.gpos
- if dgpos then
- local separator = lpeg.P(" ")
- local other = ((1 - separator)^0) / unicodes
- local splitter = lpeg.Ct(other * (separator * other)^0)
- for gp=1,#dgpos do
- local gpos = dgpos[gp]
+end
+
+actions["merge kern classes"] = function(data,filename,raw)
+ local gposlist = raw.gpos
+ if gposlist then
+ local descriptions = data.descriptions
+ local resources = data.resources
+ local unicodes = resources.unicodes
+ local splitter = data.helpers.tounicodetable
+ for gp=1,#gposlist do
+ local gpos = gposlist[gp]
local subtables = gpos.subtables
if subtables then
for s=1,#subtables do
@@ -1266,56 +1321,71 @@ actions["reorganize glyph kerns"] = function(data,filename,raw)
local split = { } -- saves time
for k=1,#kernclass do
local kcl = kernclass[k]
- local firsts, seconds, offsets, lookups = kcl.firsts, kcl.seconds, kcl.offsets, kcl.lookup -- singular
+ local firsts = kcl.firsts
+ local seconds = kcl.seconds
+ local offsets = kcl.offsets
+ local lookups = kcl.lookup -- singular
if type(lookups) ~= "table" then
lookups = { lookups }
end
- local maxfirsts, maxseconds = getn(firsts), getn(seconds)
- -- here we could convert split into a list of unicodes which is a bit
- -- faster but as this is only done when caching it does not save us much
- for _, s in next, firsts do
+ -- we can check the max in the loop
+ -- local maxseconds = getn(seconds)
+ for n, s in next, firsts do
split[s] = split[s] or lpegmatch(splitter,s)
end
- for _, s in next, seconds do
+ local maxseconds = 0
+ for n, s in next, seconds do
+ if n > maxseconds then
+ maxseconds = n
+ end
split[s] = split[s] or lpegmatch(splitter,s)
end
for l=1,#lookups do
local lookup = lookups[l]
- for fk=1,#firsts do
+ for fk=1,#firsts do -- maxfirsts ?
local fv = firsts[fk]
local splt = split[fv]
if splt then
- local kerns, baseoffset = { }, (fk-1) * maxseconds
- for sk=2,maxseconds do
- local sv = seconds[sk]
+ local extrakerns = { }
+ local baseoffset = (fk-1) * maxseconds
+ -- for sk=2,maxseconds do
+ -- local sv = seconds[sk]
+ for sk, sv in next, seconds do
local splt = split[sv]
- if splt then
+ if splt then -- redundant test
local offset = offsets[baseoffset + sk]
if offset then
for i=1,#splt do
- local second_unicode = splt[i]
- if tonumber(second_unicode) then
- kerns[second_unicode] = offset
- else for s=1,#second_unicode do
- kerns[second_unicode[s]] = offset
- end end
+ extrakerns[splt[i]] = offset
end
end
end
end
for i=1,#splt do
local first_unicode = splt[i]
- if tonumber(first_unicode) then
- do_it(lookup,first_unicode,kerns)
- else for f=1,#first_unicode do
- do_it(lookup,first_unicode[f],kerns)
- end end
+ local description = descriptions[first_unicode]
+ if description then
+ local kerns = description.kerns
+ if not kerns then
+ kerns = { } -- unicode indexed !
+ description.kerns = kerns
+ end
+ local lookupkerns = kerns[lookup]
+ if not lookupkerns then
+ lookupkerns = { }
+ kerns[lookup] = lookupkerns
+ end
+ for second_unicode, kern in next, extrakerns do
+ lookupkerns[second_unicode] = kern
+ end
+ elseif trace_loading then
+ report_otf("no glyph data for U+%04X", first_unicode)
+ end
end
end
end
end
end
- subtable.comment = "The kernclass table is merged into kerns in the indexed glyph tables."
subtable.kernclass = { }
end
end
@@ -1325,112 +1395,37 @@ actions["reorganize glyph kerns"] = function(data,filename,raw)
end
actions["check glyphs"] = function(data,filename,raw)
- local verbose = fonts.verbose
- local int_to_uni = data.luatex.unicodes
- for k, v in next, data.glyphs do
- if verbose then
- local code = int_to_uni[k]
- -- looks like this is done twice ... bug?
- if code then
- local vu = v.unicode
- if not vu then
- v.unicode = code
- elseif type(vu) == "table" then
- if vu[#vu] == code then
- -- weird
- else
- vu[#vu+1] = code
- end
- elseif vu ~= code then
- v.unicode = { vu, code }
- end
- end
- else
- v.unicode = nil
- v.index = nil
- end
- -- only needed on non sparse/mixed mode
- if v.math then
- if v.mathkern then v.mathkern = nil end
- if v.horiz_variant then v.horiz_variant = nil end
- if v.vert_variants then v.vert_variants = nil end
- end
- --
+ for unicode, description in next, data.descriptions do
+ description.glyph = nil
end
- data.luatex.comment = "Glyph tables have their original index. When present, kern tables are indexed by unicode."
end
+-- future versions will remove _
+
actions["check metadata"] = function(data,filename,raw)
local metadata = data.metadata
- metadata.method = loadmethod
- if loadmethod == "sparse" then
- for _, k in next, mainfields do
- if valid_fields[k] then
- local v = raw[k]
- if global_fields[k] then
- if not data[k] then
- data[k] = v
- end
- else
- if not metadata[k] then
- metadata[k] = v
- end
- end
+ for _, k in next, mainfields do
+ if valid_fields[k] then
+ local v = raw[k]
+ if not metadata[k] then
+ metadata[k] = v
end
end
- else
- for k, v in next, raw do
- if valid_fields[k] then
- if global_fields[k] then
- if not data[k] then
- data[v] = v
- end
- else
- if not metadata[k] then
- metadata[k] = v
- end
- end
- end
- end
- end
- local pfminfo = raw.pfminfo
- if pfminfo then
- data.pfminfo = pfminfo
- metadata.isfixedpitch = metadata.isfixedpitch or (pfminfo.panose and pfminfo.panose.proportion == "Monospaced")
- metadata.charwidth = pfminfo and pfminfo.avgwidth
end
+ -- metadata.pfminfo = raw.pfminfo -- not already done?
local ttftables = metadata.ttf_tables
if ttftables then
for i=1,#ttftables do
ttftables[i].data = "deleted"
end
end
- metadata.xuid = nil
- data.udglyphs = nil
- data.map = nil
end
-local private_mathparameters = {
- "FractionDelimiterSize",
- "FractionDelimiterDisplayStyleSize",
-}
-
-actions["check math parameters"] = function(data,filename,raw)
- local mathdata = data.metadata.math
- if mathdata then
- for m=1,#private_mathparameters do
- local pmp = private_mathparameters[m]
- if not mathdata[pmp] then
- if trace_loading then
- report_otf("setting math parameter '%s' to 0", pmp)
- end
- mathdata[pmp] = 0
- end
- end
- end
+actions["cleanup tables"] = function(data,filename,raw)
+ data.resources.indices = nil -- not needed
+ data.helpers = nil
end
-
-- kern: ttf has a table with kerns
--
-- Weird, as maxfirst and maxseconds can have holes, first seems to be indexed, but
@@ -1438,272 +1433,239 @@ end
-- unpredictable alternatively we could force an [1] if not set (maybe I will do that
-- anyway).
+-- we can share { } as it is never set
+
+--- ligatures have an extra specification.char entry that we don't use
+
actions["reorganize glyph lookups"] = function(data,filename,raw)
- local glyphs = data.glyphs
- for index, udglyph in next, data.udglyphs do
- local lookups = udglyph.lookups
+ local resources = data.resources
+ local unicodes = resources.unicodes
+ local descriptions = data.descriptions
+ local splitter = data.helpers.tounicodelist
+
+ local lookuptypes = resources.lookuptypes
+
+ for unicode, description in next, descriptions do
+ local lookups = description.glyph.lookups
if lookups then
- local glyph = glyphs[index]
- local l = { }
- for kk, vv in next, lookups do
- local aa = { }
- l[kk] = aa
- for kkk=1,#vv do
- local vvv = vv[kkk]
- local s = vvv.specification
- local t = vvv.type
- -- #aa+1
- if t == "ligature" then
- aa[kkk] = { "ligature", s.components, s.char }
- elseif t == "alternate" then
- aa[kkk] = { "alternate", s.components }
- elseif t == "substitution" then
- aa[kkk] = { "substitution", s.variant }
- elseif t == "multiple" then
- aa[kkk] = { "multiple", s.components }
- elseif t == "position" then
- aa[kkk] = { "position", { s.x or 0, s.y or 0, s.h or 0, s.v or 0 } }
- elseif t == "pair" then
- -- maybe flatten this one
- local one, two, paired = s.offsets[1], s.offsets[2], s.paired or ""
+ for tag, lookuplist in next, lookups do
+ for l=1,#lookuplist do
+ local lookup = lookuplist[l]
+ local specification = lookup.specification
+ local lookuptype = lookup.type
+ local lt = lookuptypes[tag]
+ if not lt then
+ lookuptypes[tag] = lookuptype
+ elseif lt ~= lookuptype then
+ report_otf("conflicting lookuptypes: %s => %s and %s",tag,lt,lookuptype)
+ end
+ if lookuptype == "ligature" then
+ lookuplist[l] = { lpegmatch(splitter,specification.components) }
+ elseif lookuptype == "alternate" then
+ lookuplist[l] = { lpegmatch(splitter,specification.components) }
+ elseif lookuptype == "substitution" then
+ lookuplist[l] = unicodes[specification.variant]
+ elseif lookuptype == "multiple" then
+ lookuplist[l] = { lpegmatch(splitter,specification.components) }
+ elseif lookuptype == "position" then
+ lookuplist[l] = {
+ specification.x or 0,
+ specification.y or 0,
+ specification.h or 0,
+ specification.v or 0
+ }
+ elseif lookuptype == "pair" then
+ local one = specification.offsets[1]
+ local two = specification.offsets[2]
+ local paired = unicodes[specification.paired]
if one then
if two then
- aa[kkk] = { "pair", paired, { one.x or 0, one.y or 0, one.h or 0, one.v or 0 }, { two.x or 0, two.y or 0, two.h or 0, two.v or 0 } }
+ lookuplist[l] = { paired, { one.x or 0, one.y or 0, one.h or 0, one.v or 0 }, { two.x or 0, two.y or 0, two.h or 0, two.v or 0 } }
else
- aa[kkk] = { "pair", paired, { one.x or 0, one.y or 0, one.h or 0, one.v or 0 } }
+ lookuplist[l] = { paired, { one.x or 0, one.y or 0, one.h or 0, one.v or 0 } }
end
else
if two then
- aa[kkk] = { "pair", paired, { }, { two.x or 0, two.y or 0, two.h or 0, two.v or 0} } -- maybe nil instead of { }
+ lookuplist[l] = { paired, { }, { two.x or 0, two.y or 0, two.h or 0, two.v or 0} } -- maybe nil instead of { }
else
- aa[kkk] = { "pair", paired }
+ lookuplist[l] = { paired }
end
end
end
end
end
- -- we could combine this
local slookups, mlookups
- for kk, vv in next, l do
- if #vv == 1 then
- if not slookups then
- slookups = { }
- glyph.slookups = slookups
+ for tag, lookuplist in next, lookups do
+ if #lookuplist == 1 then
+ if slookups then
+ slookups[tag] = lookuplist[1]
+ else
+ slookups = { [tag] = lookuplist[1] }
end
- slookups[kk] = vv[1]
else
- if not mlookups then
- mlookups = { }
- glyph.mlookups = mlookups
+ if mlookups then
+ mlookups[tag] = lookuplist
+ else
+ mlookups = { [tag] = lookuplist }
end
- mlookups[kk] = vv
end
end
- glyph.lookups = nil -- when using table
+ if slookups then
+ description.slookups = slookups
+ end
+ if mlookups then
+ description.mlookups = mlookups
+ end
end
end
+
end
-actions["reorganize glyph anchors"] = function(data,filename,raw)
- local glyphs = data.glyphs
- for index, udglyph in next, data.udglyphs do
- local anchors = udglyph.anchors
+actions["reorganize glyph anchors"] = function(data,filename,raw) -- when we replace inplace we safe entries
+ local descriptions = data.descriptions
+ for unicode, description in next, descriptions do
+ local anchors = description.glyph.anchors
if anchors then
- local glyph = glyphs[index]
- local a = { }
- glyph.anchors = a
- for kk, vv in next, anchors do
- local aa = { }
- a[kk] = aa
- for kkk, vvv in next, vv do
- if vvv.x or vvv.y then
- aa[kkk] = { vvv.x , vvv.y }
- else
- local aaa = { }
- aa[kkk] = aaa
- for kkkk=1,#vvv do
- local vvvv = vvv[kkkk]
- aaa[kkkk] = { vvvv.x, vvvv.y }
+ for class, data in next, anchors do
+ if class == "baselig" then
+ for tag, specification in next, data do
+ for i=1,#specification do
+ local si = specification[i]
+ specification[i] = { si.x or 0, si.y or 0 }
end
end
+ else
+ for tag, specification in next, data do
+ data[tag] = { specification.x or 0, specification.y or 0 }
+ end
end
end
+ description.anchors = anchors
end
end
end
---~ actions["check extra features"] = function(data,filename,raw)
---~ -- later, ctx only
---~ end
-
--- -- -- -- -- --
--- -- -- -- -- --
-
-function features.register(name,default,description)
- featurelist[#featurelist+1] = name
- defaultfeatures[name] = default
- if description and description ~= "" then
- fonts.otf.tables.features[name] = description
- end
-end
-
--- for context this will become a task handler
-
-local lists = { -- why local
- fonts.triggers,
- fonts.processors,
- fonts.manipulators,
-}
+-- modes: node, base, none
function otf.setfeatures(tfmdata,features)
- local processes = { }
- if features and next(features) then
- local mode = tfmdata.mode or features.mode or "base"
- local initializers = fonts.initializers
- local fi = initializers[mode]
- if fi then
- local fiotf = fi.otf
- if fiotf then
- local done = { }
- for l=1,#lists do
- local list = lists[l]
- if list then
- for i=1,#list do
- local f = list[i]
- local value = features[f]
- if value and fiotf[f] then -- brr
- if not done[f] then -- so, we can move some to triggers
- if trace_features then
- report_otf("initializing feature %s to %s for mode %s for font %s",f,tostring(value),mode or 'unknown', tfmdata.fullname or 'unknown')
- end
- fiotf[f](tfmdata,value) -- can set mode (no need to pass otf)
- mode = tfmdata.mode or features.mode or "base"
- local im = initializers[mode]
- if im then
- fiotf = initializers[mode].otf
- end
- done[f] = true
- end
- end
- end
- end
- end
- end
- end
-tfmdata.mode = mode
- local fm = fonts.methods[mode] -- todo: zonder node/mode otf/...
- if fm then
- local fmotf = fm.otf
- if fmotf then
- for l=1,#lists do
- local list = lists[l]
- if list then
- for i=1,#list do
- local f = list[i]
- if fmotf[f] then -- brr
- if trace_features then
- report_otf("installing feature handler %s for mode %s for font %s",f,mode or 'unknown', tfmdata.fullname or 'unknown')
- end
- processes[#processes+1] = fmotf[f]
- end
- end
- end
- end
- end
- else
- -- message
- end
+ local okay = constructors.initializefeatures("otf",tfmdata,features,trace_features,report_otf)
+ if okay then
+ return constructors.collectprocessors("otf",tfmdata,features,trace_features,report_otf)
+ else
+ return { } -- will become false
end
- return processes, features
end
--- the first version made a top/mid/not extensible table, now we just pass on the variants data
--- and deal with it in the tfm scaler (there is no longer an extensible table anyway)
-
--- we cannot share descriptions as virtual fonts might extend them (ok, we could
--- use a cache with a hash
+-- the first version made a top/mid/not extensible table, now we just
+-- pass on the variants data and deal with it in the tfm scaler (there
+-- is no longer an extensible table anyway)
+--
+-- we cannot share descriptions as virtual fonts might extend them (ok,
+-- we could use a cache with a hash
+--
+-- we already assing an empty tabel to characters as we can add for
+-- instance protruding info and loop over characters; one is not supposed
+-- to change descriptions and if one does so one should make a copy!
-local function copytotfm(data,cache_id) -- we can save a copy when we reorder the tma to unicode (nasty due to one->many)
+local function copytotfm(data,cache_id)
if data then
- local glyphs, pfminfo, metadata = data.glyphs or { }, data.pfminfo or { }, data.metadata or { }
- local luatex = data.luatex
- local unicodes = luatex.unicodes -- names to unicodes
- local indices = luatex.indices
- local mode = data.mode or "base"
- local characters, parameters, mathparameters, descriptions = { }, { }, { }, { }
- local designsize = metadata.designsize or metadata.design_size or 100
+ local metadata = data.metadata
+ local resources = data.resources
+ local properties = table.derive(data.properties)
+ local descriptions = table.derive(data.descriptions)
+ local goodies = table.derive(data.goodies)
+ local characters = { }
+ local parameters = { }
+ local mathparameters = { }
+ --
+ local pfminfo = metadata.pfminfo or { }
+ local resources = data.resources
+ local unicodes = resources.unicodes
+ -- local mode = data.mode or "base"
+ local spaceunits = 500
+ local spacer = "space"
+ local designsize = metadata.designsize or metadata.design_size or 100
+ local mathspecs = metadata.math
+ --
if designsize == 0 then
designsize = 100
end
- local spaceunits, spacer = 500, "space"
- -- indices maps from unicodes to indices
- -- this wil stay as we can manipulate indices
- -- beforehand
- for u, i in next, indices do
- characters[u] = { } -- we need this because for instance we add protruding info and loop over characters
- descriptions[u] = glyphs[i]
- end
- -- math
- if metadata.math then
- -- parameters
- for name, value in next, metadata.math do
+ if mathspecs then
+ for name, value in next, mathspecs do
mathparameters[name] = value
end
- -- we could use a subset
- for u, char in next, characters do
- local d = descriptions[u]
+ end
+ for unicode, _ in next, data.descriptions do -- use parent table
+ characters[unicode] = { }
+ end
+ if mathspecs then
+ -- we could move this to the scaler but not that much is saved
+ -- and this is cleaner
+ for unicode, character in next, characters do
+ local d = descriptions[unicode]
local m = d.math
- -- we have them shared because that packs nicer
- -- we could prepare the variants and keep 'm in descriptions
if m then
- local variants, parts, c = m.horiz_variants, m.horiz_parts, char
+ -- watch out: luatex uses horiz_variants for the parts
+ local variants, parts = m.horiz_variants, m.horiz_parts
if variants then
- for n in gmatch(variants,"[^ ]+") do
- local un = unicodes[n]
- if un and u ~= un then
- c.next = un
- c = characters[un]
- end
- end
+ local c = character
+ for i=1,#variants do
+ local un = variants[i]
+ c.next = un
+ c = characters[un]
+ end -- c is now last in chain
c.horiz_variants = parts
elseif parts then
- c.horiz_variants = parts
+ character.horiz_variants = parts
end
- local variants, parts, c = m.vert_variants, m.vert_parts, char
+ local variants, parts = m.vert_variants, m.vert_parts
if variants then
- for n in gmatch(variants,"[^ ]+") do
- local un = unicodes[n]
- if un and u ~= un then
- c.next = un
- c = characters[un]
- end
+ local c = character
+ for i=1,#variants do
+ local un = variants[i]
+ c.next = un
+ c = characters[un]
end -- c is now last in chain
c.vert_variants = parts
elseif parts then
- c.vert_variants = parts
+ character.vert_variants = parts
end
local italic_correction = m.vert_italic_correction
if italic_correction then
- c.vert_italic_correction = italic_correction
+ character.vert_italic_correction = italic_correction -- was c.
+ end
+ local top_accent = m.top_accent
+ if top_accent then
+ character.top_accent = top_accent
end
local kerns = m.kerns
if kerns then
- char.mathkerns = kerns
+ character.mathkerns = kerns
end
end
end
end
-- end math
- local space, emdash = 0x20, 0x2014 -- unicodes['space'], unicodes['emdash']
- if metadata.isfixedpitch then
+ local monospaced = metadata.isfixedpitch or (pfminfo.panose and pfminfo.panose.proportion == "Monospaced")
+ local charwidth = pfminfo.avgwidth -- or unset
+ local italicangle = metadata.italicangle
+ local charxheight = pfminfo.os2_xheight and pfminfo.os2_xheight > 0 and pfminfo.os2_xheight
+ properties.monospaced = monospaced
+ parameters.italicangle = italicangle
+ parameters.charwidth = charwidth
+ parameters.charxheight = charxheight
+ --
+ local space = 0x0020 -- unicodes['space'], unicodes['emdash']
+ local emdash = 0x2014 -- unicodes['space'], unicodes['emdash']
+ if monospaced then
if descriptions[space] then
spaceunits, spacer = descriptions[space].width, "space"
end
if not spaceunits and descriptions[emdash] then
spaceunits, spacer = descriptions[emdash].width, "emdash"
end
- if not spaceunits and metadata.charwidth then
- spaceunits, spacer = metadata.charwidth, "charwidth"
+ if not spaceunits and charwidth then
+ spaceunits, spacer = charwidth, "charwidth"
end
else
if descriptions[space] then
@@ -1712,20 +1674,17 @@ local function copytotfm(data,cache_id) -- we can save a copy when we reorder th
if not spaceunits and descriptions[emdash] then
spaceunits, spacer = descriptions[emdash].width/2, "emdash/2"
end
- if not spaceunits and metadata.charwidth then
- spaceunits, spacer = metadata.charwidth, "charwidth"
+ if not spaceunits and charwidth then
+ spaceunits, spacer = charwidth, "charwidth"
end
end
spaceunits = tonumber(spaceunits) or 500 -- brrr
-- we need a runtime lookup because of running from cdrom or zip, brrr (shouldn't we use the basename then?)
- local filename = fonts.tfm.checkedfilename(luatex)
+ local filename = constructors.checkedfilename(resources)
local fontname = metadata.fontname
local fullname = metadata.fullname or fontname
- local cidinfo = data.cidinfo -- or { }
local units = metadata.units_per_em or 1000
--
- cidinfo.registry = cidinfo and cidinfo.registry or "" -- weird here, fix upstream
- --
parameters.slant = 0
parameters.space = spaceunits -- 3.333 (cmr10)
parameters.space_stretch = units/2 -- 500 -- 1.666 (cmr10)
@@ -1735,11 +1694,12 @@ local function copytotfm(data,cache_id) -- we can save a copy when we reorder th
if spaceunits < 2*units/5 then
-- todo: warning
end
- local italicangle = metadata.italicangle
- if italicangle then -- maybe also in afm _
- parameters.slant = parameters.slant - math.round(math.tan(italicangle*math.pi/180))
+ if italicangle then
+ parameters.italicangle = italicangle
+ parameters.italicfactor = math.cos(math.rad(90+italicangle))
+ parameters.slant = - math.round(math.tan(italicangle*math.pi/180))
end
- if metadata.isfixedpitch then
+ if monospaced then
parameters.space_stretch = 0
parameters.space_shrink = 0
elseif syncspace then --
@@ -1747,8 +1707,8 @@ local function copytotfm(data,cache_id) -- we can save a copy when we reorder th
parameters.space_shrink = spaceunits/3
end
parameters.extra_space = parameters.space_shrink -- 1.111 (cmr10)
- if pfminfo.os2_xheight and pfminfo.os2_xheight > 0 then
- parameters.x_height = pfminfo.os2_xheight
+ if charxheight then
+ parameters.x_height = charxheight
else
local x = 0x78 -- unicodes['x']
if x then
@@ -1759,150 +1719,109 @@ local function copytotfm(data,cache_id) -- we can save a copy when we reorder th
end
end
--
- local fileformat = data.format or fonts.fontformat(filename,"opentype")
- if units > 1000 then
- fileformat = "truetype"
- end
+ parameters.designsize = (designsize/10)*65536
+ parameters.ascender = abs(metadata.ascent or 0)
+ parameters.descender = abs(metadata.descent or 0)
+ parameters.units = units
+ --
+ properties.space = spacer
+ properties.encodingbytes = 2
+ properties.format = data.format or fonts.formats[filename] or "opentype"
+ properties.noglyphnames = true
+ properties.filename = filename
+ properties.fontname = fontname
+ properties.fullname = fullname
+ properties.psname = fontname or fullname
+ properties.name = filename or fullname
+ --
+ -- properties.name = specification.name
+ -- properties.sub = specification.sub
return {
- characters = characters,
- parameters = parameters,
- mathparameters = mathparameters,
- descriptions = descriptions,
- indices = indices,
- unicodes = unicodes,
- type = "real",
- direction = 0,
- boundarychar_label = 0,
- boundarychar = 65536,
- designsize = (designsize/10)*65536,
- encodingbytes = 2,
- mode = mode,
- filename = filename,
- fontname = fontname,
- fullname = fullname,
- psname = fontname or fullname,
- name = filename or fullname,
- units = units,
- format = fileformat,
- cidinfo = cidinfo,
- ascender = abs(metadata.ascent or 0),
- descender = abs(metadata.descent or 0),
- spacer = spacer,
- italicangle = italicangle,
+ characters = characters,
+ descriptions = descriptions,
+ parameters = parameters,
+ mathparameters = mathparameters,
+ resources = resources,
+ properties = properties,
+ goodies = goodies,
}
- else
- return nil
end
end
local function otftotfm(specification)
- local name = specification.name
- local sub = specification.sub
- local filename = specification.filename
- local format = specification.format
- local features = specification.features.normal
local cache_id = specification.hash
- local tfmdata = containers.read(tfm.cache,cache_id)
---~ print(cache_id)
+ local tfmdata = containers.read(constructors.cache,cache_id)
if not tfmdata then
- local otfdata = otf.load(filename,format,sub,features and features.featurefile)
- if otfdata and next(otfdata) then
- otfdata.shared = otfdata.shared or {
- featuredata = { },
- anchorhash = { },
- initialized = false,
- }
- tfmdata = copytotfm(otfdata,cache_id)
+ local name = specification.name
+ local sub = specification.sub
+ local filename = specification.filename
+ local format = specification.format
+ local features = specification.features.normal
+ local rawdata = otf.load(filename,format,sub,features and features.featurefile)
+ if rawdata and next(rawdata) then
+ rawdata.lookuphash = { }
+ tfmdata = copytotfm(rawdata,cache_id)
if tfmdata and next(tfmdata) then
- tfmdata.unique = tfmdata.unique or { }
- tfmdata.shared = tfmdata.shared or { } -- combine
- local shared = tfmdata.shared
- shared.otfdata = otfdata
- shared.features = features -- default
- shared.dynamics = { }
- shared.processes = { }
- shared.setdynamics = otf.setdynamics -- fast access and makes other modules independent
- -- this will be done later anyway, but it's convenient to have
- -- them already for fast access
- tfmdata.luatex = otfdata.luatex
- tfmdata.indices = otfdata.luatex.indices
- tfmdata.unicodes = otfdata.luatex.unicodes
- tfmdata.marks = otfdata.luatex.marks
- tfmdata.originals = otfdata.luatex.originals
- tfmdata.changed = { }
- tfmdata.has_italic = otfdata.metadata.has_italic
- if not tfmdata.language then tfmdata.language = 'dflt' end
- if not tfmdata.script then tfmdata.script = 'dflt' end
- -- at this moment no characters are assinged yet, only empty slots
- shared.processes, shared.features = otf.setfeatures(tfmdata,definers.check(features,defaultfeatures))
+ -- at this moment no characters are assigned yet, only empty slots
+ local features = constructors.checkedfeatures("otf",features)
+ local shared = tfmdata.shared
+ if not shared then
+ shared = { }
+ tfmdata.shared = shared
+ end
+ shared.rawdata = rawdata
+ shared.features = features -- default
+ shared.dynamics = { }
+ shared.processes = { }
+ tfmdata.changed = { }
+ shared.features = features
+ shared.processes = otf.setfeatures(tfmdata,features)
end
end
- containers.write(tfm.cache,cache_id,tfmdata)
+ containers.write(constructors.cache,cache_id,tfmdata)
end
return tfmdata
end
-features.register('mathsize')
-
-local function read_from_otf(specification) -- wrong namespace
- local tfmtable = otftotfm(specification)
- if tfmtable then
- local otfdata = tfmtable.shared.otfdata
- tfmtable.name = specification.name
- tfmtable.sub = specification.sub
- local s = specification.size
- local m = otfdata.metadata.math
- if m then
- -- this will move to a function
- local f = specification.features
- if f then
- local f = f.normal
- if f and f.mathsize then
- local mathsize = specification.mathsize or 0
- if mathsize == 2 then
- local p = m.ScriptPercentScaleDown
- if p then
- local ps = p * specification.textsize / 100
- if trace_math then
- report_otf("asked script size: %s, used: %s (%2.2f %%)",s,ps,(ps/s)*100)
- end
- s = ps
- end
- elseif mathsize == 3 then
- local p = m.ScriptScriptPercentScaleDown
- if p then
- local ps = p * specification.textsize / 100
- if trace_math then
- report_otf("asked scriptscript size: %s, used: %s (%2.2f %%)",s,ps,(ps/s)*100)
- end
- s = ps
- end
- end
- end
- end
- end
- tfmtable = tfm.scale(tfmtable,s,specification.relativeid)
- if tfm.fontnamemode == "specification" then
- -- not to be used in context !
- local specname = specification.specification
- if specname then
- tfmtable.name = specname
- if trace_defining then
- report_otf("overloaded fontname: '%s'",specname)
- end
- end
- end
- fonts.logger.save(tfmtable,file.extname(specification.filename),specification)
+local function read_from_otf(specification)
+ local tfmdata = otftotfm(specification)
+ if tfmdata then
+ -- this late ? .. needs checking
+ tfmdata.properties.name = specification.name
+ tfmdata.properties.sub = specification.sub
+ --
+ tfmdata = constructors.scale(tfmdata,specification)
+ constructors.applymanipulators("otf",tfmdata,specification.features.normal,trace_features,report_otf)
+ constructors.setname(tfmdata,specification) -- only otf?
+ fonts.loggers.register(tfmdata,file.extname(specification.filename),specification)
+ end
+ return tfmdata
+end
+
+local function checkmathsize(tfmdata,mathsize)
+ local mathdata = tfmdata.shared.rawdata.metadata.math
+ local mathsize = tonumber(mathsize)
+ if mathdata then -- we cannot use mathparameters as luatex will complain
+ local parameters = tfmdata.parameters
+ parameters.scriptpercentage = mathdata.ScriptPercentScaleDown
+ parameters.scriptscriptpercentage = mathdata.ScriptScriptPercentScaleDown
+ parameters.mathsize = mathsize
end
---~ print(tfmtable.fullname)
- return tfmtable
end
+registerotffeature {
+ name = "mathsize",
+ description = "apply mathsize as specified in the font",
+ initializers = {
+ base = checkmathsize,
+ node = checkmathsize,
+ }
+}
+
-- helpers
-function otf.collectlookups(otfdata,kind,script,language)
- -- maybe store this in the font
- local sequences = otfdata.luatex.sequences
+function otf.collectlookups(rawdata,kind,script,language)
+ local sequences = rawdata.resources.sequences
if sequences then
local featuremap, featurelist = { }, { }
for s=1,#sequences do
@@ -1933,42 +1852,23 @@ end
-- readers
-fonts.formats.dfont = "truetype"
-fonts.formats.ttc = "truetype"
-fonts.formats.ttf = "truetype"
-fonts.formats.otf = "opentype"
-
local function check_otf(forced,specification,suffix,what)
local name = specification.name
if forced then
name = file.addsuffix(name,suffix,true)
end
- local fullname, tfmtable = findbinfile(name,suffix) or "", nil -- one shot
- -- if false then -- can be enabled again when needed
- -- if fullname == "" then
- -- local fb = fonts.names.old_to_new[name]
- -- if fb then
- -- fullname = findbinfile(fb,suffix) or ""
- -- end
- -- end
- -- if fullname == "" then
- -- local fb = fonts.names.new_to_old[name]
- -- if fb then
- -- fullname = findbinfile(fb,suffix) or ""
- -- end
- -- end
- -- end
+ local fullname, tfmdata = findbinfile(name,suffix) or "", nil -- one shot
if fullname == "" then
fullname = fonts.names.getfilename(name,suffix)
end
if fullname ~= "" then
specification.filename, specification.format = fullname, what -- hm, so we do set the filename, then
- tfmtable = read_from_otf(specification) -- we need to do it for all matches / todo
+ tfmdata = read_from_otf(specification) -- we need to do it for all matches / todo
end
- return tfmtable
+ return tfmdata
end
-function readers.opentype(specification,suffix,what)
+local function opentypereader(specification,suffix,what)
local forced = specification.forced or ""
if forced == "otf" then
return check_otf(true,specification,forced,"opentype")
@@ -1979,7 +1879,23 @@ function readers.opentype(specification,suffix,what)
end
end
-function readers.otf (specification) return readers.opentype(specification,"otf","opentype") end
-function readers.ttf (specification) return readers.opentype(specification,"ttf","truetype") end
-function readers.ttc (specification) return readers.opentype(specification,"ttf","truetype") end -- !!
-function readers.dfont(specification) return readers.opentype(specification,"ttf","truetype") end -- !!
+readers.opentype = opentypereader
+
+local formats = fonts.formats
+
+formats.otf = "opentype"
+formats.ttf = "truetype"
+formats.ttc = "truetype"
+formats.dfont = "truetype"
+
+function readers.otf (specification) return opentypereader(specification,"otf",formats.otf ) end
+function readers.ttf (specification) return opentypereader(specification,"ttf",formats.ttf ) end
+function readers.ttc (specification) return opentypereader(specification,"ttf",formats.ttc ) end
+function readers.dfont(specification) return opentypereader(specification,"ttf",formats.dfont) end
+
+-- this will be overloaded
+
+function otf.scriptandlanguage(tfmdata,attr)
+ local properties = tfmdata.properties
+ return properties.script or "dflt", properties.language or "dflt"
+end
diff --git a/tex/context/base/font-oth.lua b/tex/context/base/font-oth.lua
index d1a68d809..59dca31d9 100644
--- a/tex/context/base/font-oth.lua
+++ b/tex/context/base/font-oth.lua
@@ -6,34 +6,40 @@ if not modules then modules = { } end modules ['font-oth'] = {
license = "see context related readme files"
}
-local lpegmatch = lpeg.match
-local splitter = lpeg.Ct(lpeg.splitat(" "))
+local fonts = fonts
+local otf = fonts.handlers.otf
-local collectlookups = fonts.otf.collectlookups
+-- todo: use nodemode data is available
--- For the moment there is no need to cache this but this might
--- happen when I get the feeling that there is a performance
--- penalty involved.
-
-function fonts.otf.getalternate(tfmdata,k,kind,value)
+function otf.getalternate(tfmdata,k,kind,value) -- just initialize nodemode and use that (larger mem print)
if value then
- local shared = tfmdata.shared
- local otfdata = shared and shared.otfdata
- if otfdata then
- local validlookups, lookuplist = collectlookups(otfdata,kind,tfmdata.script,tfmdata.language)
- if validlookups then
- local lookups = tfmdata.descriptions[k].slookups -- we assume only slookups (we can always extend)
- if lookups then
- local unicodes = tfmdata.unicodes -- names to unicodes
- local choice = tonumber(value)
- for l=1,#lookuplist do
- local lookup = lookuplist[l]
- local p = lookups[lookup]
- if p then
- local pc = p[2] -- p.components
- if pc then
- pc = lpegmatch(splitter,pc)
- return unicodes[pc[choice] or pc[#pc]]
+ local description = tfmdata.descriptions[k]
+ if description then
+ local slookups = description.slookups -- we assume only slookups (we can always extend)
+ if slookups then
+ local shared = tfmdata.shared
+ local rawdata = shared and shared.rawdata
+ if rawdata then
+ local lookuptypes = rawdata.resources.lookuptypes
+ if lookuptypes then
+ local properties = tfmdata.properties
+ -- we could cache these
+ local validlookups, lookuplist = otf.collectlookups(rawdata,kind,properties.script,properties.language)
+ if validlookups then
+ local choice = tonumber(value) or 1 -- no random here (yet)
+ for l=1,#lookuplist do
+ local lookup = lookuplist[l]
+ local found = slookups[lookup]
+ if found then
+ local lookuptype = lookuptypes[lookup]
+ if lookuptype == "substitution" then
+ return found
+ elseif lookuptype == "alternate" then
+ return found[choice] or found[#found]
+ else
+ -- ignore
+ end
+ end
end
end
end
diff --git a/tex/context/base/font-oti.lua b/tex/context/base/font-oti.lua
index e531ba8b2..d6853db31 100644
--- a/tex/context/base/font-oti.lua
+++ b/tex/context/base/font-oti.lua
@@ -8,51 +8,85 @@ if not modules then modules = { } end modules ['font-oti'] = {
local lower = string.lower
-local fonts = fonts
+local allocate = utilities.storage.allocate
-local otf = fonts.otf
-local initializers = fonts.initializers
+local fonts = fonts
+local otf = { }
+fonts.handlers.otf = otf
-local languages = otf.tables.languages
-local scripts = otf.tables.scripts
+local otffeatures = fonts.constructors.newfeatures("otf")
+local registerotffeature = otffeatures.register
-local function set_language(tfmdata,value)
+registerotffeature {
+ name = "features",
+ description = "initialization of feature handler",
+ default = true,
+}
+
+-- these are later hooked into node and base initializaters
+
+local otftables = otf.tables -- not always defined
+
+local function setmode(tfmdata,value)
if value then
- value = lower(value)
- if languages[value] then
- tfmdata.language = value
- end
+ tfmdata.properties.mode = lower(value)
end
end
-local function set_script(tfmdata,value)
+local function setlanguage(tfmdata,value)
if value then
- value = lower(value)
- if scripts[value] then
- tfmdata.script = value
+ local cleanvalue = lower(value)
+ local languages = otftables and otftables.languages
+ local properties = tfmdata.properties
+ if not languages then
+ properties.language = cleanvalue
+ elseif languages[value] then
+ properties.language = cleanvalue
+ else
+ properties.language = "dflt"
end
end
end
-local function set_mode(tfmdata,value)
+local function setscript(tfmdata,value)
if value then
- tfmdata.mode = lower(value)
+ local cleanvalue = lower(value)
+ local scripts = otftables and otftables.scripts
+ local properties = tfmdata.properties
+ if not scripts then
+ properties.script = cleanvalue
+ elseif scripts[value] then
+ properties.script = cleanvalue
+ else
+ properties.script = "dflt"
+ end
end
end
-local base_initializers = initializers.base.otf
-local node_initializers = initializers.node.otf
-
-base_initializers.language = set_language
-base_initializers.script = set_script
-base_initializers.mode = set_mode
-base_initializers.method = set_mode
+registerotffeature {
+ name = "mode",
+ description = "mode",
+ initializers = {
+ base = setmode,
+ node = setmode,
+ }
+}
-node_initializers.language = set_language
-node_initializers.script = set_script
-node_initializers.mode = set_mode
-node_initializers.method = set_mode
+registerotffeature {
+ name = "language",
+ description = "language",
+ initializers = {
+ base = setlanguage,
+ node = setlanguage,
+ }
+}
-otf.features.register("features",true) -- we always do features
-table.insert(fonts.processors,"features") -- we need a proper function for doing this
+registerotffeature {
+ name = "script",
+ description = "script",
+ initializers = {
+ base = setscript,
+ node = setscript,
+ }
+}
diff --git a/tex/context/base/font-otn.lua b/tex/context/base/font-otn.lua
index 6c5ba12c8..38d01dec0 100644
--- a/tex/context/base/font-otn.lua
+++ b/tex/context/base/font-otn.lua
@@ -10,14 +10,6 @@ if not modules then modules = { } end modules ['font-otn'] = {
-- much functionality could only be implemented thanks to the husayni font
-- of Idris Samawi Hamid to who we dedicate this module.
--- I'm in the process of cleaning up the code (which happens in another
--- file) so don't rely on things staying the same.
-
--- some day when we can jit this, we can use more functions
-
--- we can use more lpegs when lpeg is extended with function args and so
--- resolving to unicode does not gain much
-
-- in retrospect it always looks easy but believe it or not, it took a lot
-- of work to get proper open type support done: buggy fonts, fuzzy specs,
-- special made testfonts, many skype sessions between taco, idris and me,
@@ -32,10 +24,7 @@ if not modules then modules = { } end modules ['font-otn'] = {
-- alternative loop quitters
-- check cursive and r2l
-- find out where ignore-mark-classes went
--- remove unused tables
--- slide tail (always glue at the end so only needed once
-- default features (per language, script)
--- cleanup kern(class) code, remove double info
-- handle positions (we need example fonts)
-- handle gpos_single (we might want an extra width field in glyph nodes because adding kerns might interfere)
@@ -111,6 +100,8 @@ results in different tables.</p>
-- gpos_context ok --
-- gpos_contextchain ok --
--
+-- todo: contextpos and contextsub and class stuff
+--
-- actions:
--
-- handler : actions triggered by lookup
@@ -120,16 +111,20 @@ results in different tables.</p>
-- remark: the 'not implemented yet' variants will be done when we have fonts that use them
-- remark: we need to check what to do with discretionaries
+-- We used to have independent hashes for lookups but as the tags are unique
+-- we now use only one hash. If needed we can have multiple again but in that
+-- case I will probably prefix (i.e. rename) the lookups in the cached font file.
+
local concat, insert, remove = table.concat, 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 = type, next, tonumber, tostring
local lpegmatch = lpeg.match
local random = math.random
-local logs, trackers, fonts, nodes, attributes = logs, trackers, fonts, nodes, attributes
+local logs, trackers, nodes, attributes = logs, trackers, nodes, attributes
-local otf = fonts.otf
-local tfm = fonts.tfm
+local fonts = fonts
+local otf = fonts.handlers.otf
local trace_lookups = false trackers.register("otf.lookups", function(v) trace_lookups = v end)
local trace_singles = false trackers.register("otf.singles", function(v) trace_singles = v end)
@@ -164,93 +159,82 @@ trackers.register("otf.injections","nodes.injections")
trackers.register("*otf.sample","otf.steps,otf.actions,otf.analyzing")
-local insert_node_after = node.insert_after
-local delete_node = nodes.delete
-local copy_node = node.copy
-local find_node_tail = node.tail or node.slide
-local set_attribute = node.set_attribute
-local has_attribute = node.has_attribute
+local insert_node_after = node.insert_after
+local delete_node = nodes.delete
+local copy_node = node.copy
+local find_node_tail = node.tail or node.slide
+local set_attribute = node.set_attribute
+local has_attribute = node.has_attribute
+
+local zwnj = 0x200C
+local zwj = 0x200D
+local wildcard = "*"
+local default = "dflt"
-local zwnj = 0x200C
-local zwj = 0x200D
-local wildcard = "*"
-local default = "dflt"
+local nodecodes = nodes.nodecodes
+local whatcodes = nodes.whatcodes
+local glyphcodes = nodes.glyphcodes
-local split_at_space = lpeg.Ct(lpeg.splitat(" ")) -- no trailing or multiple spaces anyway
+local glyph_code = nodecodes.glyph
+local glue_code = nodecodes.glue
+local disc_code = nodecodes.disc
+local whatsit_code = nodecodes.whatsit
-local nodecodes = nodes.nodecodes
-local whatcodes = nodes.whatcodes
-local glyphcodes = nodes.glyphcodes
+local dir_code = whatcodes.dir
+local localpar_code = whatcodes.localpar
-local glyph_code = nodecodes.glyph
-local glue_code = nodecodes.glue
-local disc_code = nodecodes.disc
-local whatsit_code = nodecodes.whatsit
+local ligature_code = glyphcodes.ligature
-local dir_code = whatcodes.dir
-local localpar_code = whatcodes.localpar
+local privateattribute = attributes.private
-local ligature_code = glyphcodes.ligature
+local state = privateattribute('state')
+local markbase = privateattribute('markbase')
+local markmark = privateattribute('markmark')
+local markdone = privateattribute('markdone')
+local cursbase = privateattribute('cursbase')
+local curscurs = privateattribute('curscurs')
+local cursdone = privateattribute('cursdone')
+local kernpair = privateattribute('kernpair')
-local state = attributes.private('state')
-local markbase = attributes.private('markbase')
-local markmark = attributes.private('markmark')
-local markdone = attributes.private('markdone')
-local cursbase = attributes.private('cursbase')
-local curscurs = attributes.private('curscurs')
-local cursdone = attributes.private('cursdone')
-local kernpair = attributes.private('kernpair')
+local injections = nodes.injections
+local setmark = injections.setmark
+local setcursive = injections.setcursive
+local setkern = injections.setkern
+local setpair = injections.setpair
-local injections = nodes.injections
-local setmark = injections.setmark
-local setcursive = injections.setcursive
-local setkern = injections.setkern
-local setpair = injections.setpair
+local markonce = true
+local cursonce = true
+local kernonce = true
-local markonce = true
-local cursonce = true
-local kernonce = true
+local fonthashes = fonts.hashes
+local fontdata = fonthashes.identifiers
-local fontdata = fonts.identifiers
+local otffeatures = fonts.constructors.newfeatures("otf")
+local registerotffeature = otffeatures.register
-otf.features.process = { }
+local onetimemessage = fonts.loggers.onetimemessage
-- we share some vars here, after all, we have no nested lookups and
-- less code
-local tfmdata = false
-local otfdata = false
-local characters = false
-local descriptions = false
-local marks = false
-local indices = false
-local unicodes = false
-local currentfont = false
-local lookuptable = false
-local anchorlookups = false
-local handlers = { }
-local rlmode = 0
-local featurevalue = false
-
--- we cheat a bit and assume that a font,attr combination are kind of ranged
-
-local specifiers = fonts.definers.specifiers
-local contextsetups = specifiers.contextsetups
-local contextnumbers = specifiers.contextnumbers
-local contextmerged = specifiers.contextmerged
+local tfmdata = false
+local characters = false
+local descriptions = false
+local resources = false
+local marks = false
+local currentfont = false
+local lookuptable = false
+local anchorlookups = false
+local lookuptypes = false
+local handlers = { }
+local rlmode = 0
+local featurevalue = false
-- we cannot optimize with "start = first_glyph(head)" because then we don't
-- know which rlmode we're in which messes up cursive handling later on
--
-- head is always a whatsit so we can safely assume that head is not changed
-local special_attributes = {
- init = 1,
- medi = 2,
- fina = 3,
- isol = 4
-}
-
-- we use this for special testing and documentation
local checkstep = (nodes and nodes.tracers and nodes.tracers.steppers.check) or function() end
@@ -263,6 +247,7 @@ local function logprocess(...)
end
report_direct(...)
end
+
local function logwarning(...)
report_direct(...)
end
@@ -282,9 +267,11 @@ local function gref(n)
local num, nam = { }, { }
for i=1,#n do
local ni = n[i]
- local di = descriptions[ni]
- num[i] = format("U+%04X",ni)
- nam[i] = di and di.name or "?"
+ if tonumber(di) then -- later we will start at 2
+ local di = descriptions[ni]
+ num[i] = format("U+%04X",ni)
+ nam[i] = di and di.name or "?"
+ end
end
return format("%s (%s)",concat(num," "), concat(nam," "))
end
@@ -327,84 +314,72 @@ local function markstoligature(kind,lookupname,start,stop,char)
end
local function toligature(kind,lookupname,start,stop,char,markflag,discfound) -- brr head
- if start ~= stop then
---~ if discfound then
---~ local lignode = copy_node(start)
---~ lignode.font = start.font
---~ lignode.char = char
---~ lignode.subtype = ligature_code
---~ start = node.do_ligature_n(start, stop, lignode)
---~ if start.id == disc_code then
---~ local prev = start.prev
---~ start = start.next
---~ end
- if discfound then
- -- print("start->stop",nodes.tosequence(start,stop))
- local lignode = copy_node(start)
- lignode.font, lignode.char, lignode.subtype = start.font, char, ligature_code
- local next, prev = stop.next, start.prev
- stop.next = nil
- lignode = node.do_ligature_n(start, stop, lignode)
- prev.next = lignode
- if next then
- next.prev = lignode
- end
- lignode.next, lignode.prev = next, prev
- start = lignode
- -- print("start->end",nodes.tosequence(start))
- else -- start is the ligature
- local deletemarks = markflag ~= "mark"
- local n = copy_node(start)
- local current
- current, start = insert_node_after(start,start,n)
- local snext = stop.next
- current.next = snext
- if snext then
- snext.prev = current
- end
- start.prev, stop.next = nil, nil
- current.char, current.subtype, current.components = char, ligature_code, start
- local head = current
- if deletemarks then
- if trace_marks then
- while start do
- if marks[start.char] then
- logwarning("%s: remove mark %s",pref(kind,lookupname),gref(start.char))
- end
- start = start.next
- end
- end
- else
- local i = 0
+ if start == stop then
+ start.char = char
+ elseif discfound then
+ -- print("start->stop",nodes.tosequence(start,stop))
+ local lignode = copy_node(start)
+ lignode.font, lignode.char, lignode.subtype = start.font, char, ligature_code
+ local next, prev = stop.next, start.prev
+ stop.next = nil
+ lignode = node.do_ligature_n(start, stop, lignode)
+ prev.next = lignode
+ if next then
+ next.prev = lignode
+ end
+ lignode.next, lignode.prev = next, prev
+ start = lignode
+ -- print("start->end",nodes.tosequence(start))
+ else -- start is the ligature
+ local deletemarks = markflag ~= "mark"
+ local n = copy_node(start)
+ local current
+ current, start = insert_node_after(start,start,n)
+ local snext = stop.next
+ current.next = snext
+ if snext then
+ snext.prev = current
+ end
+ start.prev, stop.next = nil, nil
+ current.char, current.subtype, current.components = char, ligature_code, start
+ local head = current
+ if deletemarks then
+ if trace_marks then
while start do
if marks[start.char] then
- set_attribute(start,markdone,i)
- if trace_marks then
- logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i)
- end
- head, current = insert_node_after(head,current,copy_node(start))
- else
- i = i + 1
+ logwarning("%s: remove mark %s",pref(kind,lookupname),gref(start.char))
end
start = start.next
end
- start = current.next
- while start and start.id == glyph_code do
- if marks[start.char] then
- set_attribute(start,markdone,i)
- if trace_marks then
- logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i)
- end
- else
- break
+ end
+ else
+ local i = 0
+ while start do
+ if marks[start.char] then
+ set_attribute(start,markdone,i)
+ if trace_marks then
+ logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i)
end
- start = start.next
+ head, current = insert_node_after(head,current,copy_node(start))
+ else
+ i = i + 1
end
+ start = start.next
+ end
+ start = current.next
+ while start and start.id == glyph_code do
+ if marks[start.char] then
+ set_attribute(start,markdone,i)
+ if trace_marks then
+ logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i)
+ end
+ else
+ break
+ end
+ start = start.next
end
- return head
end
- else
- start.char = char
+ return head
end
return start
end
@@ -447,6 +422,30 @@ local function alternative_glyph(start,alternatives,kind,chainname,chainlookupna
return choice, value
end
+local function multiple_glyphs(start,multiple)
+ local nofmultiples = #multiple
+ if nofmultiples > 0 then
+ start.char = multiple[1]
+ if nofmultiples > 1 then
+ local sn = start.next
+ for k=2,nofmultiples do -- todo: use insert_node
+ local n = copy_node(start)
+ n.char = multiple[k]
+ n.next = sn
+ n.prev = start
+ if sn then
+ sn.prev = n
+ end
+ start.next = n
+ start = n
+ end
+ end
+ return start, true
+ else
+ return start, false
+ end
+end
+
function handlers.gsub_alternate(start,kind,lookupname,alternative,sequence)
local choice, index = alternative_glyph(start,alternative,kind,lookupname)
if trace_alternatives then
@@ -460,22 +459,7 @@ function handlers.gsub_multiple(start,kind,lookupname,multiple)
if trace_multiples then
logprocess("%s: replacing %s by multiple %s",pref(kind,lookupname),gref(start.char),gref(multiple))
end
- start.char = multiple[1]
- if #multiple > 1 then
- for k=2,#multiple do
- local n = copy_node(start)
- n.char = multiple[k]
- local sn = start.next
- n.next = sn
- n.prev = start
- if sn then
- sn.prev = n
- end
- start.next = n
- start = n
- end
- end
- return start, true
+ return multiple_glyphs(start,multiple)
end
function handlers.gsub_ligature(start,kind,lookupname,ligature,sequence) --or maybe pass lookup ref
@@ -484,17 +468,12 @@ function handlers.gsub_ligature(start,kind,lookupname,ligature,sequence) --or ma
if marks[startchar] then
while s do
local id = s.id
- if id == glyph_code and s.subtype<256 then
- if s.font == currentfont then
- local char = s.char
- local lg = ligature[1][char]
- if not lg then
- break
- else
- stop = s
- ligature = lg
- s = s.next
- end
+ if id == glyph_code and s.subtype<256 and s.font == currentfont then
+ local lg = ligature[s.char]
+ if lg then
+ stop = s
+ ligature = lg
+ s = s.next
else
break
end
@@ -502,13 +481,14 @@ function handlers.gsub_ligature(start,kind,lookupname,ligature,sequence) --or ma
break
end
end
- if stop and ligature[2] then
+ if stop then
+ local lig = ligature.ligature
if trace_ligatures then
local stopchar = stop.char
- start = markstoligature(kind,lookupname,start,stop,ligature[2])
+ start = markstoligature(kind,lookupname,start,stop,lig)
logprocess("%s: replacing %s upto %s by ligature %s",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char))
else
- start = markstoligature(kind,lookupname,start,stop,ligature[2])
+ start = markstoligature(kind,lookupname,start,stop,lig)
end
return start, true
end
@@ -522,13 +502,13 @@ function handlers.gsub_ligature(start,kind,lookupname,ligature,sequence) --or ma
if skipmark and marks[char] then
s = s.next
else
- local lg = ligature[1][char]
- if not lg then
- break
- else
+ local lg = ligature[char]
+ if lg then
stop = s
ligature = lg
s = s.next
+ else
+ break
end
end
else
@@ -541,13 +521,14 @@ function handlers.gsub_ligature(start,kind,lookupname,ligature,sequence) --or ma
break
end
end
- if stop and ligature[2] then
+ if stop then
+ local lig = ligature.ligature
if trace_ligatures then
local stopchar = stop.char
- start = toligature(kind,lookupname,start,stop,ligature[2],skipmark,discfound)
+ start = toligature(kind,lookupname,start,stop,lig,skipmark,discfound)
logprocess("%s: replacing %s upto %s by ligature %s",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char))
else
- start = toligature(kind,lookupname,start,stop,ligature[2],skipmark,discfound)
+ start = toligature(kind,lookupname,start,stop,lig,skipmark,discfound)
end
return start, true
end
@@ -594,7 +575,7 @@ function handlers.gpos_mark2base(start,kind,lookupname,markanchors,sequence)
if al[anchor] then
local ma = markanchors[anchor]
if ma then
- local dx, dy, bound = setmark(start,base,tfmdata.factor,rlmode,ba,ma)
+ local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma)
if trace_marks then
logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%s,%s)",
pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
@@ -609,7 +590,7 @@ function handlers.gpos_mark2base(start,kind,lookupname,markanchors,sequence)
end
else -- if trace_bugs then
-- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar))
- fonts.registermessage(currentfont,basechar,"no base anchors")
+ onetimemessage(currentfont,basechar,"no base anchors",report_fonts)
end
elseif trace_bugs then
logwarning("%s: prev node is no char",pref(kind,lookupname))
@@ -662,7 +643,7 @@ function handlers.gpos_mark2ligature(start,kind,lookupname,markanchors,sequence)
if ma then
ba = ba[index]
if ba then
- local dx, dy, bound = setmark(start,base,tfmdata.factor,rlmode,ba,ma,index)
+ local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,index)
if trace_marks then
logprocess("%s, anchor %s, index %s, bound %s: anchoring mark %s to baselig %s at index %s => (%s,%s)",
pref(kind,lookupname),anchor,index,bound,gref(markchar),gref(basechar),index,dx,dy)
@@ -679,7 +660,7 @@ function handlers.gpos_mark2ligature(start,kind,lookupname,markanchors,sequence)
end
else -- if trace_bugs then
-- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar))
- fonts.registermessage(currentfont,basechar,"no base anchors")
+ onetimemessage(currentfont,basechar,"no base anchors",report_fonts)
end
elseif trace_bugs then
logwarning("%s: prev node is no char",pref(kind,lookupname))
@@ -709,7 +690,7 @@ function handlers.gpos_mark2mark(start,kind,lookupname,markanchors,sequence)
if al[anchor] then
local ma = markanchors[anchor]
if ma then
- local dx, dy, bound = setmark(start,base,tfmdata.factor,rlmode,ba,ma)
+ local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma)
if trace_marks then
logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%s,%s)",
pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
@@ -725,7 +706,7 @@ function handlers.gpos_mark2mark(start,kind,lookupname,markanchors,sequence)
end
else -- if trace_bugs then
-- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar))
- fonts.registermessage(currentfont,basechar,"no base anchors")
+ onetimemessage(currentfont,basechar,"no base anchors",report_fonts)
end
elseif trace_bugs then
logwarning("%s: prev node is no mark",pref(kind,lookupname))
@@ -767,7 +748,7 @@ function handlers.gpos_cursive(start,kind,lookupname,exitanchors,sequence) -- to
if al[anchor] then
local exit = exitanchors[anchor]
if exit then
- local dx, dy, bound = setcursive(start,nxt,tfmdata.factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
+ local dx, dy, bound = setcursive(start,nxt,tfmdata.parameters.factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
if trace_cursive then
logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode)
end
@@ -780,7 +761,7 @@ function handlers.gpos_cursive(start,kind,lookupname,exitanchors,sequence) -- to
end
else -- if trace_bugs then
-- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(startchar))
- fonts.registermessage(currentfont,startchar,"no entry anchors")
+ onetimemessage(currentfont,startchar,"no entry anchors",report_fonts)
end
break
end
@@ -797,7 +778,8 @@ end
function handlers.gpos_single(start,kind,lookupname,kerns,sequence)
local startchar = start.char
- local dx, dy, w, h = setpair(start,tfmdata.factor,rlmode,sequence.flags[4],kerns,characters[startchar])
+ local kerns = kerns[start.char]
+ local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar])
if trace_kerns then
logprocess("%s: shifting single %s by (%s,%s) and correction (%s,%s)",pref(kind,lookupname),gref(startchar),dx,dy,w,h)
end
@@ -812,7 +794,8 @@ function handlers.gpos_pair(start,kind,lookupname,kerns,sequence)
return start, false
else
local prev, done = start, false
- local factor = tfmdata.factor
+ local factor = tfmdata.parameters.factor
+ local lookuptype = lookuptypes[lookupname]
while snext and snext.id == glyph_code and snext.subtype<256 and snext.font == currentfont do
local nextchar = snext.char
local krn = kerns[nextchar]
@@ -824,8 +807,8 @@ function handlers.gpos_pair(start,kind,lookupname,kerns,sequence)
if not krn then
-- skip
elseif type(krn) == "table" then
- if krn[1] == "pair" then
- local a, b = krn[3], krn[4]
+ if lookuptype == "pair" then -- probably not needed
+ local a, b = krn[2], krn[3]
if a and #a > 0 then
local startchar = start.char
local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar])
@@ -840,18 +823,18 @@ function handlers.gpos_pair(start,kind,lookupname,kerns,sequence)
logprocess("%s: shifting second of pair %s and %s by (%s,%s) and correction (%s,%s)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
end
end
- else
+ else -- wrong ... position has different entries
report_process("%s: check this out (old kern stuff)",pref(kind,lookupname))
- local a, b = krn[3], krn[7]
- if a and a ~= 0 then
- local k = setkern(snext,factor,rlmode,a)
- if trace_kerns then
- logprocess("%s: inserting first kern %s between %s and %s",pref(kind,lookupname),k,gref(prev.char),gref(nextchar))
- end
- end
- if b and b ~= 0 then
- logwarning("%s: ignoring second kern xoff %s",pref(kind,lookupname),b*factor)
- end
+ -- local a, b = krn[2], krn[6]
+ -- if a and a ~= 0 then
+ -- local k = setkern(snext,factor,rlmode,a)
+ -- if trace_kerns then
+ -- logprocess("%s: inserting first kern %s between %s and %s",pref(kind,lookupname),k,gref(prev.char),gref(nextchar))
+ -- end
+ -- end
+ -- if b and b ~= 0 then
+ -- logwarning("%s: ignoring second kern xoff %s",pref(kind,lookupname),b*factor)
+ -- end
end
done = true
elseif krn ~= 0 then
@@ -885,37 +868,31 @@ end
local logwarning = report_subchain
--- ['coverage']={
--- ['after']={ "r" },
--- ['before']={ "q" },
--- ['current']={ "a", "b", "c" },
--- },
--- ['lookups']={ "ls_l_1", "ls_l_1", "ls_l_1" },
-
-function chainmores.chainsub(start,stop,kind,chainname,currentcontext,cache,lookuplist,chainlookupname,n)
+function chainmores.chainsub(start,stop,kind,chainname,currentcontext,lookuphash,lookuplist,chainlookupname,n)
logprocess("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname))
return start, false
end
-- handled later:
--
--- function chainmores.gsub_single(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
--- return chainprocs.gsub_single(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+-- function chainmores.gsub_single(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,n)
+-- return chainprocs.gsub_single(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,n)
-- end
-function chainmores.gsub_multiple(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+function chainmores.gsub_multiple(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,n)
logprocess("%s: gsub_multiple not yet supported",cref(kind,chainname,chainlookupname))
return start, false
end
-function chainmores.gsub_alternate(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+
+function chainmores.gsub_alternate(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,n)
logprocess("%s: gsub_alternate not yet supported",cref(kind,chainname,chainlookupname))
return start, false
end
-- handled later:
--
--- function chainmores.gsub_ligature(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
--- return chainprocs.gsub_ligature(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+-- function chainmores.gsub_ligature(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,n)
+-- return chainprocs.gsub_ligature(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,n)
-- end
local function logprocess(...)
@@ -930,7 +907,7 @@ local logwarning = report_chain
-- We could share functions but that would lead to extra function calls with many
-- arguments, redundant tests and confusing messages.
-function chainprocs.chainsub(start,stop,kind,chainname,currentcontext,cache,lookuplist,chainlookupname)
+function chainprocs.chainsub(start,stop,kind,chainname,currentcontext,lookuphash,lookuplist,chainlookupname)
logwarning("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname))
return start, false
end
@@ -939,7 +916,7 @@ end
-- in a bit weird way. There is no lookup and the replacement comes from the lookup
-- itself. It is meant mostly for dealing with Urdu.
-function chainprocs.reversesub(start,stop,kind,chainname,currentcontext,cache,replacements)
+function chainprocs.reversesub(start,stop,kind,chainname,currentcontext,lookuphash,replacements)
local char = start.char
local replacement = replacements[char]
if replacement then
@@ -985,18 +962,21 @@ end
match.</p>
--ldx]]--
-function chainprocs.gsub_single(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,chainindex)
+function chainprocs.gsub_single(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex)
-- todo: marks ?
if not chainindex then
- delete_till_stop(start,stop) -- ,currentlookup.flags[1])
+ delete_till_stop(start,stop) -- ,currentlookup.flags[1]
end
local current = start
local subtables = currentlookup.subtables
+if #subtables > 1 then
+ log_warning("todo: check if we need to loop over the replacements: %s",concat(subtables," "))
+end
while current do
if current.id == glyph_code then
local currentchar = current.char
local lookupname = subtables[1]
- local replacement = cache.gsub_single[lookupname]
+ local replacement = lookuphash[lookupname]
if not replacement then
if trace_bugs then
logwarning("%s: no single hits",cref(kind,chainname,chainlookupname,lookupname,chainindex))
@@ -1031,12 +1011,12 @@ chainmores.gsub_single = chainprocs.gsub_single
the match.</p>
--ldx]]--
-function chainprocs.gsub_multiple(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+function chainprocs.gsub_multiple(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
delete_till_stop(start,stop)
local startchar = start.char
local subtables = currentlookup.subtables
local lookupname = subtables[1]
- local replacements = cache.gsub_multiple[lookupname]
+ local replacements = lookuphash[lookupname]
if not replacements then
if trace_bugs then
logwarning("%s: no multiple hits",cref(kind,chainname,chainlookupname,lookupname))
@@ -1051,21 +1031,7 @@ function chainprocs.gsub_multiple(start,stop,kind,chainname,currentcontext,cache
if trace_multiples then
logprocess("%s: replacing %s by multiple characters %s",cref(kind,chainname,chainlookupname,lookupname),gref(startchar),gref(replacements))
end
- local sn = start.next
- for k=1,#replacements do
- if k == 1 then
- start.char = replacements[k]
- else
- local n = copy_node(start) -- maybe delete the components and such
- n.char = replacements[k]
- n.next, n.prev = sn, start
- if sn then
- sn.prev = n
- end
- start.next, start = n, n
- end
- end
- return start, true
+ return multiple_glyphs(start,replacements)
end
end
return start, false
@@ -1075,7 +1041,7 @@ end
<p>Here we replace start by new glyph. First we delete the rest of the match.</p>
--ldx]]--
-function chainprocs.gsub_alternate(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+function chainprocs.gsub_alternate(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
-- todo: marks ?
delete_till_stop(start,stop)
local current = start
@@ -1084,7 +1050,7 @@ function chainprocs.gsub_alternate(start,stop,kind,chainname,currentcontext,cach
if current.id == glyph_code then
local currentchar = current.char
local lookupname = subtables[1]
- local alternatives = cache.gsub_alternate[lookupname]
+ local alternatives = lookuphash[lookupname]
if not alternatives then
if trace_bugs then
logwarning("%s: no alternative hits",cref(kind,chainname,chainlookupname,lookupname))
@@ -1119,11 +1085,11 @@ this function (move code inline and handle the marks by a separate function). We
assume rather stupid ligatures (no complex disc nodes).</p>
--ldx]]--
-function chainprocs.gsub_ligature(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,chainindex)
+function chainprocs.gsub_ligature(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex)
local startchar = start.char
local subtables = currentlookup.subtables
local lookupname = subtables[1]
- local ligatures = cache.gsub_ligature[lookupname]
+ local ligatures = lookuphash[lookupname]
if not ligatures then
if trace_bugs then
logwarning("%s: no ligature hits",cref(kind,chainname,chainlookupname,lookupname,chainindex))
@@ -1146,21 +1112,21 @@ function chainprocs.gsub_ligature(start,stop,kind,chainname,currentcontext,cache
if marks[schar] then -- marks
s = s.next
else
- local lg = ligatures[1][schar]
- if not lg then
- break
- else
+ local lg = ligatures[schar]
+ if lg then
ligatures, last, nofreplacements = lg, s, nofreplacements + 1
if s == stop then
break
else
s = s.next
end
+ else
+ break
end
end
end
end
- local l2 = ligatures[2]
+ local l2 = ligatures.ligature
if l2 then
if chainindex then
stop = last
@@ -1188,12 +1154,12 @@ end
chainmores.gsub_ligature = chainprocs.gsub_ligature
-function chainprocs.gpos_mark2base(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+function chainprocs.gpos_mark2base(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
local markchar = start.char
if marks[markchar] then
local subtables = currentlookup.subtables
local lookupname = subtables[1]
- local markanchors = cache.gpos_mark2base[lookupname]
+ local markanchors = lookuphash[lookupname]
if markanchors then
markanchors = markanchors[markchar]
end
@@ -1226,7 +1192,7 @@ function chainprocs.gpos_mark2base(start,stop,kind,chainname,currentcontext,cach
if al[anchor] then
local ma = markanchors[anchor]
if ma then
- local dx, dy, bound = setmark(start,base,tfmdata.factor,rlmode,ba,ma)
+ local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma)
if trace_marks then
logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%s,%s)",
cref(kind,chainname,chainlookupname,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
@@ -1252,12 +1218,12 @@ function chainprocs.gpos_mark2base(start,stop,kind,chainname,currentcontext,cach
return start, false
end
-function chainprocs.gpos_mark2ligature(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+function chainprocs.gpos_mark2ligature(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
local markchar = start.char
if marks[markchar] then
local subtables = currentlookup.subtables
local lookupname = subtables[1]
- local markanchors = cache.gpos_mark2ligature[lookupname]
+ local markanchors = lookuphash[lookupname]
if markanchors then
markanchors = markanchors[markchar]
end
@@ -1299,7 +1265,7 @@ function chainprocs.gpos_mark2ligature(start,stop,kind,chainname,currentcontext,
if ma then
ba = ba[index]
if ba then
- local dx, dy, bound = setmark(start,base,tfmdata.factor,rlmode,ba,ma,index)
+ local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,index)
if trace_marks then
logprocess("%s, anchor %s, bound %s: anchoring mark %s to baselig %s at index %s => (%s,%s)",
cref(kind,chainname,chainlookupname,lookupname),anchor,a or bound,gref(markchar),gref(basechar),index,dx,dy)
@@ -1326,7 +1292,7 @@ function chainprocs.gpos_mark2ligature(start,stop,kind,chainname,currentcontext,
return start, false
end
-function chainprocs.gpos_mark2mark(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+function chainprocs.gpos_mark2mark(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
local markchar = start.char
if marks[markchar] then
--~ local alreadydone = markonce and has_attribute(start,markmark)
@@ -1334,7 +1300,7 @@ function chainprocs.gpos_mark2mark(start,stop,kind,chainname,currentcontext,cach
-- local markanchors = descriptions[markchar].anchors markanchors = markanchors and markanchors.mark
local subtables = currentlookup.subtables
local lookupname = subtables[1]
- local markanchors = cache.gpos_mark2mark[lookupname]
+ local markanchors = lookuphash[lookupname]
if markanchors then
markanchors = markanchors[markchar]
end
@@ -1351,7 +1317,7 @@ function chainprocs.gpos_mark2mark(start,stop,kind,chainname,currentcontext,cach
if al[anchor] then
local ma = markanchors[anchor]
if ma then
- local dx, dy, bound = setmark(start,base,tfmdata.factor,rlmode,ba,ma)
+ local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma)
if trace_marks then
logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%s,%s)",
cref(kind,chainname,chainlookupname,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
@@ -1382,13 +1348,13 @@ end
-- ! ! ! untested ! ! !
-function chainprocs.gpos_cursive(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+function chainprocs.gpos_cursive(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
local alreadydone = cursonce and has_attribute(start,cursbase)
if not alreadydone then
local startchar = start.char
local subtables = currentlookup.subtables
local lookupname = subtables[1]
- local exitanchors = cache.gpos_cursive[lookupname]
+ local exitanchors = lookuphash[lookupname]
if exitanchors then
exitanchors = exitanchors[startchar]
end
@@ -1417,7 +1383,7 @@ function chainprocs.gpos_cursive(start,stop,kind,chainname,currentcontext,cache,
if al[anchor] then
local exit = exitanchors[anchor]
if exit then
- local dx, dy, bound = setcursive(start,nxt,tfmdata.factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
+ local dx, dy, bound = setcursive(start,nxt,tfmdata.parameters.factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
if trace_cursive then
logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode)
end
@@ -1430,7 +1396,7 @@ function chainprocs.gpos_cursive(start,stop,kind,chainname,currentcontext,cache,
end
else -- if trace_bugs then
-- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(startchar))
- fonts.registermessage(currentfont,startchar,"no entry anchors")
+ onetimemessage(currentfont,startchar,"no entry anchors",report_fonts)
end
break
end
@@ -1447,16 +1413,16 @@ function chainprocs.gpos_cursive(start,stop,kind,chainname,currentcontext,cache,
return start, false
end
-function chainprocs.gpos_single(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,chainindex,sequence)
- -- untested
+function chainprocs.gpos_single(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence)
+ -- untested .. needs checking for the new model
local startchar = start.char
local subtables = currentlookup.subtables
local lookupname = subtables[1]
- local kerns = cache.gpos_single[lookupname]
+ local kerns = lookuphash[lookupname]
if kerns then
kerns = kerns[startchar]
if kerns then
- local dx, dy, w, h = setpair(start,tfmdata.factor,rlmode,sequence.flags[4],kerns,characters[startchar])
+ local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar])
if trace_kerns then
logprocess("%s: shifting single %s by (%s,%s) and correction (%s,%s)",cref(kind,chainname,chainlookupname),gref(startchar),dx,dy,w,h)
end
@@ -1467,19 +1433,20 @@ end
-- when machines become faster i will make a shared function
-function chainprocs.gpos_pair(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,chainindex,sequence)
+function chainprocs.gpos_pair(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence)
-- logwarning("%s: gpos_pair not yet supported",cref(kind,chainname,chainlookupname))
local snext = start.next
if snext then
local startchar = start.char
local subtables = currentlookup.subtables
local lookupname = subtables[1]
- local kerns = cache.gpos_pair[lookupname]
+ local kerns = lookuphash[lookupname]
if kerns then
kerns = kerns[startchar]
if kerns then
+ local lookuptype = lookuptypes[lookupname]
local prev, done = start, false
- local factor = tfmdata.factor
+ local factor = tfmdata.parameters.factor
while snext and snext.id == glyph_code and snext.subtype<256 and snext.font == currentfont do
local nextchar = snext.char
local krn = kerns[nextchar]
@@ -1490,8 +1457,8 @@ function chainprocs.gpos_pair(start,stop,kind,chainname,currentcontext,cache,cur
if not krn then
-- skip
elseif type(krn) == "table" then
- if krn[1] == "pair" then
- local a, b = krn[3], krn[4]
+ if lookuptype == "pair" then
+ local a, b = krn[2], krn[3]
if a and #a > 0 then
local startchar = start.char
local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar])
@@ -1508,7 +1475,7 @@ function chainprocs.gpos_pair(start,stop,kind,chainname,currentcontext,cache,cur
end
else
report_process("%s: check this out (old kern stuff)",cref(kind,chainname,chainlookupname))
- local a, b = krn[3], krn[7]
+ local a, b = krn[2], krn[6]
if a and a ~= 0 then
local k = setkern(snext,factor,rlmode,a)
if trace_kerns then
@@ -1553,7 +1520,7 @@ local function show_skip(kind,chainname,char,ck,class)
end
end
-local function normal_handle_contextchain(start,kind,chainname,contexts,sequence,cache)
+local function normal_handle_contextchain(start,kind,chainname,contexts,sequence,lookuphash)
-- local rule, lookuptype, sequence, f, l, lookups = ck[1], ck[2] ,ck[3], ck[4], ck[5], ck[6]
local flags, done = sequence.flags, false
local skipmark, skipligature, skipbase = flags[1], flags[2], flags[3]
@@ -1754,35 +1721,11 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
local chainlookup = lookuptable[chainlookupname]
local cp = chainprocs[chainlookup.type]
if cp then
- start, done = cp(start,last,kind,chainname,ck,cache,chainlookup,chainlookupname,nil,sequence)
+ start, done = cp(start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence)
else
logprocess("%s: %s is not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)
end
else
- -- actually this needs a more complex treatment for which we will use chainmores
---~ local i = 1
---~ repeat
---~ local chainlookupname = chainlookups[i]
---~ local chainlookup = lookuptable[chainlookupname]
---~ local cp = chainmores[chainlookup.type]
---~ if cp then
---~ local ok, n
---~ start, ok, n = cp(start,last,kind,chainname,ck,cache,chainlookup,chainlookupname,i,sequence)
---~ -- messy since last can be changed !
---~ if ok then
---~ done = true
---~ start = start.next
---~ if n then
---~ -- skip next one(s) if ligature
---~ i = i + n - 1
---~ end
---~ end
---~ else
---~ logprocess("%s: multiple subchains for %s are not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)
---~ end
---~ i = i + 1
---~ until i > nofchainlookups
-
local i = 1
repeat
if skipped then
@@ -1806,7 +1749,7 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
local cp = chainmores[chainlookup.type]
if cp then
local ok, n
- start, ok, n = cp(start,last,kind,chainname,ck,cache,chainlookup,chainlookupname,i,sequence)
+ start, ok, n = cp(start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,i,sequence)
-- messy since last can be changed !
if ok then
done = true
@@ -1826,7 +1769,7 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
else
local replacements = ck[7]
if replacements then
- start, done = chainprocs.reversesub(start,last,kind,chainname,ck,cache,replacements) -- sequence
+ start, done = chainprocs.reversesub(start,last,kind,chainname,ck,lookuphash,replacements) -- sequence
else
done = true -- can be meant to be skipped
if trace_contexts then
@@ -1891,122 +1834,120 @@ local function report_missing_cache(typ,lookup)
local t = f[typ] if not t then t = { } f[typ] = t end
if not t[lookup] then
t[lookup] = true
- logwarning("missing cache for lookup %s of type %s in font %s (%s)",lookup,typ,currentfont,tfmdata.fullname)
+ logwarning("missing cache for lookup %s of type %s in font %s (%s)",lookup,typ,currentfont,tfmdata.properties.fullname)
end
end
local resolved = { } -- we only resolve a font,script,language pair once
-- todo: pass all these 'locals' in a table
---
--- dynamics will be isolated some day ... for the moment we catch attribute zero
--- not being set
-function fonts.methods.node.otf.features(head,font,attr)
- if trace_steps then
- checkstep(head)
- end
- tfmdata = fontdata[font]
- local shared = tfmdata.shared
- otfdata = shared.otfdata
- local luatex = otfdata.luatex
- descriptions = tfmdata.descriptions
- characters = tfmdata.characters
- indices = tfmdata.indices
- unicodes = tfmdata.unicodes
- marks = tfmdata.marks
- anchorlookups = luatex.lookup_to_anchor
- currentfont = font
- rlmode = 0
- local featuredata = otfdata.shared.featuredata -- can be made local to closure
- local sequences = luatex.sequences
- lookuptable = luatex.lookups
- local done = false
- local script, language, s_enabled, a_enabled, dyn
- local attribute_driven = attr and attr ~= 0
- if attribute_driven then
- local features = contextsetups[contextnumbers[attr]] -- could be a direct list
- dyn = contextmerged[attr] or 0
- language, script = features.language or "dflt", features.script or "dflt"
- a_enabled = features -- shared.features -- can be made local to the resolver
- if dyn == 2 or dyn == -2 then
- -- font based
- s_enabled = shared.features
+local lookuphashes = { }
+
+setmetatable(lookuphashes, { __index =
+ function(t,font)
+ local lookuphash = fontdata[font].resources.lookuphash
+ if not lookuphash or not next(lookuphash) then
+ lookuphash = false
end
- else
- language, script = tfmdata.language or "dflt", tfmdata.script or "dflt"
- s_enabled = shared.features -- can be made local to the resolver
- dyn = 0
+ t[font] = lookuphash
+ return lookuphash
end
- -- we can save some runtime by caching feature tests
- local res = resolved[font] if not res then res = { } resolved[font] = res end
- local rs = res [script] if not rs then rs = { } res [script] = rs end
- local rl = rs [language] if not rl then rl = { } rs [language] = rl end
- local ra = rl [attr] if ra == nil then ra = { } rl [attr] = ra end -- attr can be false
- -- sequences always > 1 so no need for optimization
- for s=1,#sequences do
- local pardir, txtdir, success = 0, { }, false
- local sequence = sequences[s]
- local r = ra[s] -- cache
- if r == nil then
- --
- -- this bit will move to font-ctx and become a function
- ---
- local chain = sequence.chain or 0
- local features = sequence.features
- if not features then
- -- indirect lookup, part of chain (todo: make this a separate table)
- r = false -- { false, false, chain }
- else
- local valid, attribute, kind, what = false, false
- for k,v in next, features do
- -- we can quit earlier but for the moment we want the tracing
- local s_e = s_enabled and s_enabled[k]
- local a_e = a_enabled and a_enabled[k]
- if s_e or a_e then
- local l = v[script] or v[wildcard]
- if l then
- -- not l[language] or l[default] or l[wildcard] because we want tracing
- -- only first attribute match check, so we assume simple fina's
- -- default can become a font feature itself
- if l[language] then
- valid, what = s_e or a_e, language
- -- elseif l[default] then
- -- valid, what = true, default
- elseif l[wildcard] then
- valid, what = s_e or a_e, wildcard
- end
- if valid then
- kind, attribute = k, special_attributes[k] or false
- if a_e and dyn < 0 then
- valid = false
- end
- if trace_applied then
- local typ, action = match(sequence.type,"(.*)_(.*)")
- report_process(
- "%s font: %03i, dynamic: %03i, kind: %s, lookup: %3i, script: %-4s, language: %-4s (%-4s), type: %s, action: %s, name: %s",
- (valid and "+") or "-",font,attr or 0,kind,s,script,language,what,typ,action,sequence.name)
- end
- break
- end
- end
- end
- end
- if valid then
- r = { valid, attribute, chain, kind }
- else
- r = false -- { valid, attribute, chain, "generic" } -- false anyway, could be flag instead of table
+})
+
+-- fonts.hashes.lookups = lookuphashes
+
+local special_attributes = {
+ init = 1,
+ medi = 2,
+ fina = 3,
+ isol = 4
+}
+
+local function initialize(sequence,script,language,enabled)
+ local features = sequence.features
+ if features then
+ for kind, scripts in next, features do
+ local valid = enabled[kind]
+ if valid then
+ local languages = scripts[script] or scripts[wildcard]
+ if languages and (languages[language] or languages[wildcard]) then
+ return { valid, special_attributes[kind] or false, sequence.chain or 0, kind }
end
end
- ra[s] = r
end
- featurevalue = r and r[1] -- todo: pass to function instead of using a global
+ end
+ return false
+end
+
+function otf.dataset(ftfmdata,sequences,font) -- generic variant, overloaded in context
+ local shared = tfmdata.shared
+ local properties = tfmdata.properties
+ local language = properties.language or "dflt"
+ local script = properties.script or "dflt"
+ local enabled = shared.features
+ local res = resolved[font]
+ if not res then
+ res = { }
+ resolved[font] = res
+ end
+ local rs = res[script]
+ if not rs then
+ rs = { }
+ res[script] = rs
+ end
+ local rl = rs[language]
+ if not rl then
+ rl = { }
+ rs[language] = rl
+ setmetatable(rl, { __index = function(t,k)
+ local v = enabled and initialize(sequences[k],script,language,enabled)
+ t[k] = v
+ return v
+ end})
+ end
+ return rl
+end
+
+local function featuresprocessor(head,font,attr)
+
+ local lookuphash = lookuphashes[font] -- we can also check sequences here
+
+ if not lookuphash then
+ return head, false
+ end
+
+ if trace_steps then
+ checkstep(head)
+ end
+
+ tfmdata = fontdata[font]
+ descriptions = tfmdata.descriptions
+ characters = tfmdata.characters
+ resources = tfmdata.resources
+
+ marks = resources.marks
+ anchorlookups = resources.lookup_to_anchor
+ lookuptable = resources.lookups
+ lookuptypes = resources.lookuptypes
+
+ currentfont = font
+ rlmode = 0
+
+ local sequences = resources.sequences
+ local done = false
+ local datasets = otf.dataset(tfmdata,sequences,font,attr)
+
+ for s=1,#sequences do
+ local pardir, txtdir, success = 0, { }, false -- we could reuse txtdir and use a top pointer
+ local sequence = sequences[s]
+ local dataset = datasets[s] -- cache
+ featurevalue = dataset and dataset[1] -- todo: pass to function instead of using a global
if featurevalue then
- local attribute, chain, typ, subtables = r[2], r[3], sequence.type, sequence.subtables
+ local attribute, chain, typ, subtables = dataset[2], dataset[3], sequence.type, sequence.subtables
if chain < 0 then
-- this is a limited case, no special treatments like 'init' etc
local handler = handlers[typ]
- local thecache = featuredata[typ] or { }
-- we need to get rid of this slide !
local start = find_node_tail(head) -- slow (we can store tail because there's always a skip at the end): todo
while start do
@@ -2022,11 +1963,11 @@ function fonts.methods.node.otf.features(head,font,attr)
if a then
for i=1,#subtables do
local lookupname = subtables[i]
- local lookupcache = thecache[lookupname]
+ local lookupcache = lookuphash[lookupname]
if lookupcache then
local lookupmatch = lookupcache[start.char]
if lookupmatch then
- start, success = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,i)
+ start, success = handler(start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
if success then
break
end
@@ -2049,12 +1990,11 @@ function fonts.methods.node.otf.features(head,font,attr)
else
local handler = handlers[typ]
local ns = #subtables
- local thecache = featuredata[typ] or { }
local start = head -- local ?
rlmode = 0 -- to be checked ?
if ns == 1 then
local lookupname = subtables[1]
- local lookupcache = thecache[lookupname]
+ local lookupcache = lookuphash[lookupname]
if not lookupcache then
report_missing_cache(typ,lookupname)
else
@@ -2073,7 +2013,7 @@ function fonts.methods.node.otf.features(head,font,attr)
if lookupmatch then
-- sequence kan weg
local ok
- start, ok = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,1)
+ start, ok = handler(start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
if ok then
success = true
end
@@ -2155,13 +2095,13 @@ function fonts.methods.node.otf.features(head,font,attr)
if a then
for i=1,ns do
local lookupname = subtables[i]
- local lookupcache = thecache[lookupname]
+ local lookupcache = lookuphash[lookupname]
if lookupcache then
local lookupmatch = lookupcache[start.char]
if lookupmatch then
-- we could move all code inline but that makes things even more unreadable
local ok
- start, ok = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,i)
+ start, ok = handler(start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
if ok then
success = true
break
@@ -2246,305 +2186,156 @@ function fonts.methods.node.otf.features(head,font,attr)
return head, done
end
-otf.features.prepare = { }
-
--- we used to share code in the following functions but that costs a lot of
--- memory due to extensive calls to functions (easily hundreds of thousands per
--- document)
-
-local function split(replacement,original,cache,unicodes)
- -- we can cache this too, but not the same (although unicode is a unique enough hash)
- local o, t, n, no = { }, { }, 0, 0
- for s in gmatch(original,"[^ ]+") do
- local us = unicodes[s]
- no = no + 1
- if type(us) == "number" then -- tonumber(us)
- o[no] = us
- else
- o[no] = us[1]
- end
- end
- for s in gmatch(replacement,"[^ ]+") do
- n = n + 1
- local us = unicodes[s]
- if type(us) == "number" then -- tonumber(us)
- t[o[n]] = us
- else
- t[o[n]] = us[1]
- end
+local function generic(lookupdata,lookupname,unicode,lookuphash)
+ local target = lookuphash[lookupname]
+ if target then
+ target[unicode] = lookupdata
+ else
+ lookuphash[lookupname] = { [unicode] = lookupdata }
end
- return t
end
-local function uncover(covers,result,cache,unicodes)
- -- lpeg hardly faster (.005 sec on mk)
- local nofresults = #result
- for n=1,#covers do
- local c = covers[n]
- local cc = cache[c]
- nofresults = nofresults + 1
- if not cc then
- local t = { }
- for s in gmatch(c,"[^ ]+") do
- local us = unicodes[s]
- if type(us) == "number" then
- t[us] = true
- else
- for i=1,#us do
- t[us[i]] = true
- end
- end
+local action = {
+
+ substitution = generic,
+ multiple = generic,
+ alternate = generic,
+ position = generic,
+
+ ligature = function(lookupdata,lookupname,unicode,lookuphash)
+ local target = lookuphash[lookupname]
+ if not target then
+ target = { }
+ lookuphash[lookupname] = target
+ end
+ for i=1,#lookupdata do
+ local li = lookupdata[i]
+ local tu = target[li]
+ if not tu then
+ tu = { }
+ target[li] = tu
end
- cache[c] = t
- result[nofresults] = t
+ target = tu
+ end
+ target.ligature = unicode
+ end,
+
+ pair = function(lookupdata,lookupname,unicode,lookuphash)
+ local target = lookuphash[lookupname]
+ if not target then
+ target = { }
+ lookuphash[lookupname] = target
+ end
+ local others = target[unicode]
+ local paired = lookupdata[1]
+ if others then
+ others[paired] = lookupdata
else
- result[nofresults] = cc
+ others = { [paired] = lookupdata }
+ target[unicode] = others
end
- end
-end
+ end,
+
+}
local function prepare_lookups(tfmdata)
- local otfdata = tfmdata.shared.otfdata
- local featuredata = otfdata.shared.featuredata
- local anchor_to_lookup = otfdata.luatex.anchor_to_lookup
- local lookup_to_anchor = otfdata.luatex.lookup_to_anchor
- --
- local multiple = featuredata.gsub_multiple
- local alternate = featuredata.gsub_alternate
- local single = featuredata.gsub_single
- local ligature = featuredata.gsub_ligature
- local pair = featuredata.gpos_pair
- local position = featuredata.gpos_single
- local kerns = featuredata.gpos_pair
- local mark = featuredata.gpos_mark2mark
- local cursive = featuredata.gpos_cursive
- --
- local unicodes = tfmdata.unicodes -- names to unicodes
- local indices = tfmdata.indices
- local descriptions = tfmdata.descriptions
- --
- -- we can change the otf table after loading but then we need to adapt base mode
- -- as well (no big deal)
- --
- local action = {
- substitution = function(p,lookup,glyph,unicode)
- local old, new = unicode, unicodes[p[2]]
- if type(new) == "table" then
- new = new[1]
- end
- local s = single[lookup]
- if not s then s = { } single[lookup] = s end
- s[old] = new
- --~ if trace_lookups then
- --~ report_prepare("lookup %s: substitution %s => %s",lookup,old,new)
- --~ end
- end,
- multiple = function (p,lookup,glyph,unicode)
- local old, new, nnew = unicode, { }, 0
- local m = multiple[lookup]
- if not m then m = { } multiple[lookup] = m end
- m[old] = new
- for pc in gmatch(p[2],"[^ ]+") do
- local upc = unicodes[pc]
- nnew = nnew + 1
- if type(upc) == "number" then
- new[nnew] = upc
- else
- new[nnew] = upc[1]
- end
- end
- --~ if trace_lookups then
- --~ report_prepare("lookup %s: multiple %s => %s",lookup,old,concat(new," "))
- --~ end
- end,
- alternate = function(p,lookup,glyph,unicode)
- local old, new, nnew = unicode, { }, 0
- local a = alternate[lookup]
- if not a then a = { } alternate[lookup] = a end
- a[old] = new
- for pc in gmatch(p[2],"[^ ]+") do
- local upc = unicodes[pc]
- nnew = nnew + 1
- if type(upc) == "number" then
- new[nnew] = upc
- else
- new[nnew] = upc[1]
- end
- end
- --~ if trace_lookups then
- --~ report_prepare("lookup %s: alternate %s => %s",lookup,old,concat(new,"|"))
- --~ end
- end,
- ligature = function (p,lookup,glyph,unicode)
- --~ if trace_lookups then
- --~ report_prepare("lookup %s: ligature %s => %s",lookup,p[2],glyph.name)
- --~ end
- local first = true
- local t = ligature[lookup]
- if not t then t = { } ligature[lookup] = t end
- for s in gmatch(p[2],"[^ ]+") do
- if first then
- local u = unicodes[s]
- if not u then
- report_prepare("lookup %s: ligature %s => %s ignored due to invalid unicode",lookup,p[2],glyph.name)
- break
- elseif type(u) == "number" then
- if not t[u] then
- t[u] = { { } }
- end
- t = t[u]
- else
- local tt = t
- local tu
- for i=1,#u do
- local u = u[i]
- if i==1 then
- if not t[u] then
- t[u] = { { } }
- end
- tu = t[u]
- t = tu
- else
- if not t[u] then
- tt[u] = tu
- end
- end
- end
- end
- first = false
- else
- s = unicodes[s]
- local t1 = t[1]
- if not t1[s] then
- t1[s] = { { } }
- end
- t = t1[s]
- end
- end
- t[2] = unicode
- end,
- position = function(p,lookup,glyph,unicode)
- -- not used
- local s = position[lookup]
- if not s then s = { } position[lookup] = s end
- s[unicode] = p[2] -- direct pointer to kern spec
- end,
- pair = function(p,lookup,glyph,unicode)
- local s = pair[lookup]
- if not s then s = { } pair[lookup] = s end
- local others = s[unicode]
- if not others then others = { } s[unicode] = others end
- -- todo: fast check for space
- local two = p[2]
- local upc = unicodes[two]
- if not upc then
- for pc in gmatch(two,"[^ ]+") do
- local upc = unicodes[pc]
- if type(upc) == "number" then
- others[upc] = p -- direct pointer to main table
- else
- for i=1,#upc do
- others[upc[i]] = p -- direct pointer to main table
- end
- end
- end
- elseif type(upc) == "number" then
- others[upc] = p -- direct pointer to main table
- else
- for i=1,#upc do
- others[upc[i]] = p -- direct pointer to main table
- end
- end
- --~ if trace_lookups then
- --~ report_prepare("lookup %s: pair for U+%04X",lookup,unicode)
- --~ end
- end,
- }
- --
- for unicode, glyph in next, descriptions do
- local lookups = glyph.slookups
+
+ local rawdata = tfmdata.shared.rawdata
+ local resources = rawdata.resources
+ local lookuphash = resources.lookuphash
+ local anchor_to_lookup = resources.anchor_to_lookup
+ local lookup_to_anchor = resources.lookup_to_anchor
+ local lookuptypes = resources.lookuptypes
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+
+ -- we cannot free the entries in the descriptions as sometimes we access
+ -- then directly (for instance anchors) ... selectively freeing does save
+ -- much memory as it's only a reference to a table and the slot in the
+ -- description hash is not freed anyway
+
+ for unicode, character in next, characters do -- we cannot loop over descriptions !
+
+ local description = descriptions[unicode]
+
+ local lookups = description.slookups
if lookups then
- for lookup, p in next, lookups do
- action[p[1]](p,lookup,glyph,unicode)
+ for lookupname, lookupdata in next, lookups do
+ action[lookuptypes[lookupname]](lookupdata,lookupname,unicode,lookuphash)
end
end
- local lookups = glyph.mlookups
+
+ local lookups = description.mlookups
if lookups then
- for lookup, whatever in next, lookups do
- for i=1,#whatever do -- normaly one
- local p = whatever[i]
- action[p[1]](p,lookup,glyph,unicode)
+ for lookupname, lookuplist in next, lookups do
+ local lookuptype = lookuptypes[lookupname]
+ for l=1,#lookuplist do
+ local lookupdata = lookuplist[l]
+ action[lookuptype](lookupdata,lookupname,unicode,lookuphash)
end
end
end
- local list = glyph.kerns
+
+ local list = description.kerns
if list then
- for lookup, krn in next, list do
- local k = kerns[lookup]
- if not k then k = { } kerns[lookup] = k end
- k[unicode] = krn -- ref to glyph, saves lookup
- --~ if trace_lookups then
- --~ report_prepare("lookup %s: kern for U+%04X",lookup,unicode)
- --~ end
+ for lookup, krn in next, list do -- ref to glyph, saves lookup
+ local target = lookuphash[lookup]
+ if target then
+ target[unicode] = krn
+ else
+ lookuphash[lookup] = { [unicode] = krn }
+ end
end
end
- local oanchor = glyph.anchors
- if oanchor then
- for typ, anchors in next, oanchor do -- types
- if typ == "mark" then
- for name, anchor in next, anchors do
- local lookups = anchor_to_lookup[name]
- if lookups then
- for lookup, _ in next, lookups do
- local f = mark[lookup]
- if not f then f = { } mark[lookup] = f end
- f[unicode] = anchors -- ref to glyph, saves lookup
- --~ if trace_lookups then
- --~ report_prepare("lookup %s: mark anchor %s for U+%04X",lookup,name,unicode)
- --~ end
- end
- end
- end
- elseif typ == "cexit" then -- or entry?
+
+ local list = description.anchors
+ if list then
+ for typ, anchors in next, list do -- types
+ if typ == "mark" or typ == "cexit" then -- or entry?
for name, anchor in next, anchors do
local lookups = anchor_to_lookup[name]
if lookups then
for lookup, _ in next, lookups do
- local f = cursive[lookup]
- if not f then f = { } cursive[lookup] = f end
- f[unicode] = anchors -- ref to glyph, saves lookup
- --~ if trace_lookups then
- --~ report_prepare("lookup %s: exit anchor %s for U+%04X",lookup,name,unicode)
- --~ end
+ local target = lookuphash[lookup]
+ if target then
+ target[unicode] = anchors
+ else
+ lookuphash[lookup] = { [unicode] = anchors }
+ end
end
end
end
end
end
end
+
+ end
+
+end
+
+local function split(replacement,original)
+ local result = { }
+ for i=1,#replacement do
+ result[original[i]] = replacement[i]
end
+ return result
end
--- local cache = { }
-luatex = luatex or {} -- this has to change ... we need a better one
+local function uncover(covers,result) -- will change (we can store this in the raw table)
+ local nofresults = #result
+ for n=1,#covers do
+ nofresults = nofresults + 1
+ result[nofresults] = covers[n]
+ end
+end
local function prepare_contextchains(tfmdata)
- local otfdata = tfmdata.shared.otfdata
- local lookups = otfdata.lookups
+ local rawdata = tfmdata.shared.rawdata
+ local resources = rawdata.resources
+ local lookuphash = resources.lookuphash
+ local lookups = rawdata.lookups
if lookups then
- local featuredata = otfdata.shared.featuredata
- local contextchain = featuredata.gsub_contextchain -- shared with gpos
- local reversecontextchain = featuredata.gsub_reversecontextchain -- shared with gpos
- local characters = tfmdata.characters
- local unicodes = tfmdata.unicodes
- local indices = tfmdata.indices
- local cache = luatex.covers
- if not cache then
- cache = { }
- luatex.covers = cache
- end
- --
- for lookupname, lookupdata in next, otfdata.lookups do
+ for lookupname, lookupdata in next, rawdata.lookups do
local lookuptype = lookupdata.type
if not lookuptype then
report_prepare("missing lookuptype for %s",lookupname)
@@ -2552,39 +2343,37 @@ local function prepare_contextchains(tfmdata)
local rules = lookupdata.rules
if rules then
local fmt = lookupdata.format
- -- contextchain[lookupname][unicode]
- if fmt == "coverage" then
+ -- lookuphash[lookupname][unicode]
+ if fmt == "coverage" then -- or fmt == "class" (converted into "coverage")
if lookuptype ~= "chainsub" and lookuptype ~= "chainpos" then
+ -- todo: dejavu-serif has one (but i need to see what use it has)
report_prepare("unsupported coverage %s for %s",lookuptype,lookupname)
else
- local contexts = contextchain[lookupname]
+ local contexts = lookuphash[lookupname]
if not contexts then
contexts = { }
- contextchain[lookupname] = contexts
+ lookuphash[lookupname] = contexts
end
local t, nt = { }, 0
for nofrules=1,#rules do -- does #rules>1 happen often?
local rule = rules[nofrules]
- local coverage = rule.coverage
- if coverage and coverage.current then
- local current, before, after, sequence = coverage.current, coverage.before, coverage.after, { }
- if before then
- uncover(before,sequence,cache,unicodes)
- end
- local start = #sequence + 1
- uncover(current,sequence,cache,unicodes)
- local stop = #sequence
- if after then
- uncover(after,sequence,cache,unicodes)
- end
- if sequence[1] then
- nt = nt + 1
- t[nt] = { nofrules, lookuptype, sequence, start, stop, rule.lookups }
- for unic, _ in next, sequence[start] do
- local cu = contexts[unic]
- if not cu then
- contexts[unic] = t
- end
+ local current, before, after, sequence = rule.current, rule.before, rule.after, { }
+ if before then
+ uncover(before,sequence)
+ end
+ local start = #sequence + 1
+ uncover(current,sequence)
+ local stop = #sequence
+ if after then
+ uncover(after,sequence)
+ end
+ if sequence[1] then
+ nt = nt + 1
+ t[nt] = { nofrules, lookuptype, sequence, start, stop, rule.lookups }
+ for unic, _ in next, sequence[start] do
+ local cu = contexts[unic]
+ if not cu then
+ contexts[unic] = t
end
end
end
@@ -2594,79 +2383,69 @@ local function prepare_contextchains(tfmdata)
if lookuptype ~= "reversesub" then
report_prepare("unsupported reverse coverage %s for %s",lookuptype,lookupname)
else
- local contexts = reversecontextchain[lookupname]
+ local contexts = lookuphash[lookupname]
if not contexts then
contexts = { }
- reversecontextchain[lookupname] = contexts
+ lookuphash[lookupname] = contexts
end
local t, nt = { }, 0
for nofrules=1,#rules do
local rule = rules[nofrules]
- local reversecoverage = rule.reversecoverage
- if reversecoverage and reversecoverage.current then
- local current, before, after, replacements, sequence = reversecoverage.current, reversecoverage.before, reversecoverage.after, reversecoverage.replacements, { }
- if before then
- uncover(before,sequence,cache,unicodes)
- end
- local start = #sequence + 1
- uncover(current,sequence,cache,unicodes)
- local stop = #sequence
- if after then
- uncover(after,sequence,cache,unicodes)
- end
- if replacements then
- replacements = split(replacements,current[1],cache,unicodes)
- end
- if sequence[1] then
- -- this is different from normal coverage, we assume only replacements
- nt = nt + 1
- t[nt] = { nofrules, lookuptype, sequence, start, stop, rule.lookups, replacements }
- for unic, _ in next, sequence[start] do
- local cu = contexts[unic]
- if not cu then
- contexts[unic] = t
- end
+ local current, before, after, replacements, sequence = rule.current, rule.before, rule.after, rule.replacements, { }
+ if before then
+ uncover(before,sequence)
+ end
+ local start = #sequence + 1
+ uncover(current,sequence)
+ local stop = #sequence
+ if after then
+ uncover(after,sequence)
+ end
+ if replacements then
+ replacements = split(replacements,current[1])
+ end
+ if sequence[1] then
+ -- this is different from normal coverage, we assume only replacements
+ nt = nt + 1
+ t[nt] = { nofrules, lookuptype, sequence, start, stop, rule.lookups, replacements }
+ for unic, _ in next, sequence[start] do
+ local cu = contexts[unic]
+ if not cu then
+ contexts[unic] = t
end
end
end
end
end
- elseif fmt == "glyphs" then
+ elseif fmt == "glyphs" then --maybe just make then before = { fore } and share with coverage
if lookuptype ~= "chainsub" and lookuptype ~= "chainpos" then
report_prepare("unsupported coverage %s for %s",lookuptype,lookupname)
else
- local contexts = contextchain[lookupname]
+ local contexts = lookuphash[lookupname]
if not contexts then
contexts = { }
- contextchain[lookupname] = contexts
+ lookuphash[lookupname] = contexts
end
local t, nt = { }, 0
for nofrules=1,#rules do
- -- nearly the same as coverage so we could as well rename it
local rule = rules[nofrules]
- local glyphs = rule.glyphs
- if glyphs and glyphs.names then
- local fore, back, names, sequence = glyphs.fore, glyphs.back, glyphs.names, { }
- if fore and fore ~= "" then
- fore = lpegmatch(split_at_space,fore)
- uncover(fore,sequence,cache,unicodes)
- end
- local start = #sequence + 1
- names = lpegmatch(split_at_space,names)
- uncover(names,sequence,cache,unicodes)
- local stop = #sequence
- if back and back ~= "" then
- back = lpegmatch(split_at_space,back)
- uncover(back,sequence,cache,unicodes)
- end
- if sequence[1] then
- nt = nt + 1
- t[nt] = { nofrules, lookuptype, sequence, start, stop, rule.lookups }
- for unic, _ in next, sequence[start] do
- local cu = contexts[unic]
- if not cu then
- contexts[unic] = t
- end
+ local current, before, after, sequence = rule.names, rule.fore, rule.back, { }
+ if before then
+ uncover(before,sequence)
+ end
+ local start = #sequence + 1
+ uncover(current,sequence)
+ local stop = #sequence
+ if after then
+ uncover(after,sequence)
+ end
+ if sequence[1] then
+ nt = nt + 1
+ t[nt] = { nofrules, lookuptype, sequence, start, stop, rule.lookups }
+ for unic, _ in next, sequence[start] do
+ local cu = contexts[unic]
+ if not cu then
+ contexts[unic] = t
end
end
end
@@ -2679,34 +2458,36 @@ local function prepare_contextchains(tfmdata)
end
end
-function fonts.initializers.node.otf.features(tfmdata,value)
+-- we can consider lookuphash == false (initialized but empty) vs lookuphash == table
+
+local function featuresinitializer(tfmdata,value)
if true then -- value then
- if not tfmdata.shared.otfdata.shared.initialized then
- local t = trace_preparing and os.clock()
- local otfdata = tfmdata.shared.otfdata
- local featuredata = otfdata.shared.featuredata
- -- caches
- featuredata.gsub_multiple = { }
- featuredata.gsub_alternate = { }
- featuredata.gsub_single = { }
- featuredata.gsub_ligature = { }
- featuredata.gsub_contextchain = { }
- featuredata.gsub_reversecontextchain = { }
- featuredata.gpos_pair = { }
- featuredata.gpos_single = { }
- featuredata.gpos_mark2base = { }
- featuredata.gpos_mark2ligature = featuredata.gpos_mark2base
- featuredata.gpos_mark2mark = featuredata.gpos_mark2base
- featuredata.gpos_cursive = { }
- featuredata.gpos_contextchain = featuredata.gsub_contextchain
- featuredata.gpos_reversecontextchain = featuredata.gsub_reversecontextchain
- --
+ -- beware we need to use the topmost properties table
+ local rawdata = tfmdata.shared.rawdata
+ local properties = rawdata.properties
+ if not properties.initialized then
+ local starttime = trace_preparing and os.clock()
+ local resources = rawdata.resources
+ resources.lookuphash = resources.lookuphash or { }
prepare_contextchains(tfmdata)
prepare_lookups(tfmdata)
- otfdata.shared.initialized = true
+ properties.initialized = true
if trace_preparing then
- report_prepare("preparation time is %0.3f seconds for %s",os.clock()-t,tfmdata.fullname or "?")
+ report_prepare("preparation time is %0.3f seconds for %s",os.clock()-starttime,tfmdata.properties.fullname or "?")
end
end
end
end
+
+registerotffeature {
+ name = "features",
+ description = "features",
+ default = true,
+ initializers = {
+ position = 1,
+ node = featuresinitializer,
+ },
+ processors = {
+ node = featuresprocessor,
+ }
+}
diff --git a/tex/context/base/font-otp.lua b/tex/context/base/font-otp.lua
index 221c127f2..55ddd539e 100644
--- a/tex/context/base/font-otp.lua
+++ b/tex/context/base/font-otp.lua
@@ -8,31 +8,39 @@ if not modules then modules = { } end modules ['font-otp'] = {
-- todo: pack math (but not that much to share)
-local next, type, tostring = next, type, tostring
+local next, type = next, type
local sort, concat = table.sort, table.concat
local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
+local report_otf = logs.reporter("fonts","otf loading")
-local report_otf = logs.reporter("fonts","otf loading")
+-- also used in other scripts so we need to check some tables:
-fonts = fonts or { } -- this module is also used in mtxrun
-local fonts = fonts
-fonts.otf = fonts.otf or { } -- this module is also used in mtxrun
-local otf = fonts.otf
+fonts = fonts or { }
+fonts.handlers = fonts.handlers or { }
+local handlers = fonts.handlers
+handlers.otf = handlers.otf or { }
+local otf = handlers.otf
+otf.enhancers = otf.enhancers or { }
+local enhancers = otf.enhancers
+otf.glists = otf.glists or { "gsub", "gpos" }
+local glists = otf.glists
-otf.enhancers = otf.enhancers or { }
-local enhancers = otf.enhancers
-otf.glists = otf.glists or { "gsub", "gpos" } -- these can be extended so no local here
+local criterium = 1
+local threshold = 0
-local criterium, threshold, tabstr = 1, 0, table.serialize
-
-local function tabstr(t) -- hashed from core-uti / experiment
- local s = { }
+local function tabstr(t)
+ local s, n = { }, 0
for k, v in next, t do
+ n = n + 1
if type(v) == "table" then
- s[#s+1] = k .. "={" .. tabstr(v) .. "}"
+ s[n] = k .. "={" .. tabstr(v) .. "}"
+ elseif v == true then
+ s[n] = k .. "=true"
+ elseif v then
+ s[n] = k .. "=" .. v
else
- s[#s+1] = k .. "=" .. tostring(v)
+ s[n] = k .. "=false"
end
end
sort(s)
@@ -43,12 +51,14 @@ local function packdata(data)
if data then
local h, t, c = { }, { }, { }
local hh, tt, cc = { }, { }, { }
- local function pack_1(v)
+ local nt, ntt = 0, 0
+ local function pack_1(v,indexed)
-- v == table
- local tag = tabstr(v)
+ local tag = indexed and concat(v," ") or tabstr(v)
local ht = h[tag]
if not ht then
- ht = #t+1
+ nt = nt + 1
+ ht = nt
t[ht] = v
h[tag] = ht
c[ht] = 1
@@ -57,7 +67,7 @@ local function packdata(data)
end
return ht
end
- local function pack_2(v)
+ local function pack_2(v,indexed)
-- v == number
if c[v] <= criterium then
return t[v]
@@ -65,7 +75,8 @@ local function packdata(data)
-- compact hash
local hv = hh[v]
if not hv then
- hv = #tt+1
+ ntt = ntt + 1
+ hv = ntt
tt[hv] = t[v]
hh[v] = hv
cc[hv] = c[v]
@@ -74,12 +85,12 @@ local function packdata(data)
end
end
local function success(stage,pass)
- if #t == 0 then
+ if nt == 0 then
if trace_loading then
report_otf("pack quality: nothing to pack")
end
return false
- elseif #t >= threshold then
+ elseif nt >= threshold then
local one, two, rest = 0, 0, 0
if pass == 1 then
for k,v in next, c do
@@ -93,9 +104,9 @@ local function packdata(data)
end
else
for k,v in next, cc do
- if v >20 then
+ if v > 20 then
rest = rest + 1
- elseif v >10 then
+ elseif v > 10 then
two = two + 1
else
one = one + 1
@@ -109,152 +120,151 @@ local function packdata(data)
return true
else
if trace_loading then
- report_otf("pack quality: stage %s, pass %s, %s packed, aborting pack (threshold: %s)", stage, pass, #t, threshold)
+ report_otf("pack quality: stage %s, pass %s, %s packed, aborting pack (threshold: %s)", stage, pass, nt, threshold)
end
return false
end
end
+ local resources = data.resources
+ local lookuptypes = resources.lookuptypes
for pass=1,2 do
local pack = (pass == 1 and pack_1) or pack_2
- for k, v in next, data.glyphs do
- v.boundingbox = pack(v.boundingbox)
- local l = v.slookups
- if l then
- for k,v in next, l do
- l[k] = pack(v)
- end
- end
- local l = v.mlookups
- if l then
- for k,v in next, l do
- for kk=1,#v do
- local vkk = v[kk]
- local what = vkk[1]
- if what == "pair" then
- local t = vkk[3] if t then vkk[3] = pack(t) end
- local t = vkk[4] if t then vkk[4] = pack(t) end
- elseif what == "position" then
- local t = vkk[2] if t then vkk[2] = pack(t) end
+ for unicode, description in next, data.descriptions do
+ local boundingbox = description.boundingbox
+ if boundingbox then
+ description.boundingbox = pack(boundingbox,true)
+ end
+ local slookups = description.slookups
+ if slookups then
+ for tag, slookup in next, slookups do
+ local what = lookuptypes[tag]
+ if what == "pair" then
+ local t = slookup[2] if t then slookup[2] = pack(t,true) end
+ local t = slookup[3] if t then slookup[3] = pack(t,true) end
+ elseif what ~= "substitution" then
+ slookups[tag] = pack(slookup)
+ end
+ end
+ end
+ local mlookups = description.mlookups
+ if mlookups then
+ for tag, mlookup in next, mlookups do
+ local what = lookuptypes[tag]
+ if what == "pair" then
+ for i=1,#mlookup do
+ local lookup = mlookup[i]
+ local t = lookup[2] if t then lookup[2] = pack(t,true) end
+ local t = lookup[3] if t then lookup[3] = pack(t,true) end
+ end
+ elseif what ~= "substitution" then
+ for i=1,#mlookup do
+ mlookup[i] = pack(mlookup[i]) -- true
end
- -- v[kk] = pack(vkk)
end
end
end
- local m = v.kerns
- if m then
- for k,v in next, m do
- m[k] = pack(v)
+ local kerns = description.kerns
+ if kerns then
+ for tag, kern in next, kerns do
+ kerns[tag] = pack(kern)
end
end
- local m = v.math
- if m then
- local mk = m.kerns
- if mk then
- for k,v in next, mk do
- mk[k] = pack(v)
+ local math = description.math
+ if math then
+ local kerns = math.kerns
+ if kerns then
+ for tag, kern in next, kerns do
+ kerns[tag] = pack(kern)
end
end
end
- local a = v.anchors
- if a then
- for k,v in next, a do
- if k == "baselig" then
- for kk, vv in next, v do
- for kkk=1,#vv do
- vv[kkk] = pack(vv[kkk])
+ local anchors = description.anchors
+ if anchors then
+ for what, anchor in next, anchors do
+ if what == "baselig" then
+ for _, a in next, anchor do
+ for k=1,#a do
+ a[k] = pack(a[k])
end
end
else
- for kk, vv in next, v do
- v[kk] = pack(vv)
+ for k, v in next, anchor do
+ anchor[k] = pack(v)
end
end
end
end
end
- if data.lookups then
- for k, v in next, data.lookups do
- if v.rules then
- for kk, vv in next, v.rules do
- local l = vv.lookups
- if l then
- vv.lookups = pack(l)
- end
- local c = vv.coverage
- if c then
- local cc = c.before if cc then c.before = pack(cc) end
- local cc = c.after if cc then c.after = pack(cc) end
- local cc = c.current if cc then c.current = pack(cc) end
- end
- local c = vv.reversecoverage
- if c then
- local cc = c.before if cc then c.before = pack(cc) end
- local cc = c.after if cc then c.after = pack(cc) end
- local cc = c.current if cc then c.current = pack(cc) end
- end
- -- no need to pack vv.glyphs
- local c = vv.glyphs
- if c then
- if c.fore == "" then c.fore = nil end
- if c.back == "" then c.back = nil end
- end
+ local lookups = data.lookups
+ if lookups then
+ for _, lookup in next, lookups do
+ local rules = lookup.rules
+ if rules then
+ for i=1,#rules do -- was next loop
+ local rule = rules[i]
+ local r = rule.before if r then for i=1,#r do r[i] = pack(r[i],true) end end
+ local r = rule.after if r then for i=1,#r do r[i] = pack(r[i],true) end end
+ local r = rule.current if r then for i=1,#r do r[i] = pack(r[i],true) end end
+ local r = rule.replacements if r then rule.replacements = pack(r, true) end
+ local r = rule.fore if r then rule.fore = pack(r, true) end
+ local r = rule.back if r then rule.back = pack(r, true) end
+ local r = rule.names if r then rule.names = pack(r, true) end
+ local r = rule.lookups if r then rule.lookups = pack(r) end
end
end
end
end
- if data.luatex then
- local la = data.luatex.anchor_to_lookup
- if la then
- for lookup, ldata in next, la do
- la[lookup] = pack(ldata)
- end
+ local anchor_to_lookup = resources.anchor_to_lookup
+ if anchor_to_lookup then
+ for anchor, lookup in next, anchor_to_lookup do
+ anchor_to_lookup[anchor] = pack(lookup)
end
- local la = data.luatex.lookup_to_anchor
- if la then
- for lookup, ldata in next, la do
- la[lookup] = pack(ldata)
- end
+ end
+ local lookup_to_anchor = resources.lookup_to_anchor
+ if lookup_to_anchor then
+ for lookup, anchor in next, lookup_to_anchor do
+ lookup_to_anchor[lookup] = pack(anchor)
end
- local ls = data.luatex.sequences
- if ls then
- for feature, fdata in next, ls do
- local flags = fdata.flags
- if flags then
- fdata.flags = pack(flags)
- end
- local subtables = fdata.subtables
- if subtables then
- fdata.subtables = pack(subtables)
- end
- local features = fdata.features
- if features then
- for script, sdata in next, features do
- features[script] = pack(sdata)
- end
+ end
+ local sequences = resources.sequences
+ if sequences then
+ for feature, sequence in next, sequences do
+ local flags = sequence.flags
+ if flags then
+ sequence.flags = pack(flags)
+ end
+ local subtables = sequence.subtables
+ if subtables then
+ sequence.subtables = pack(subtables)
+ end
+ local features = sequence.features
+ if features then
+ for script, feature in next, features do
+ features[script] = pack(feature)
end
end
end
- local ls = data.luatex.lookups
- if ls then
- for lookup, fdata in next, ls do
- local flags = fdata.flags
- if flags then
- fdata.flags = pack(flags)
- end
- local subtables = fdata.subtables
- if subtables then
- fdata.subtables = pack(subtables)
- end
+ end
+ local lookups = resources.lookups
+ if lookups then
+ for name, lookup in next, lookups do
+ local flags = lookup.flags
+ if flags then
+ lookup.flags = pack(flags)
+ end
+ local subtables = lookup.subtables
+ if subtables then
+ lookup.subtables = pack(subtables)
end
end
- local lf = data.luatex.features
- if lf then
- for _, g in next, otf.glists do
- local gl = lf[g]
- if gl then
- for feature, spec in next, gl do
- gl[feature] = pack(spec)
- end
+ end
+ local features = resources.features
+ if features then
+ for _, what in next, glists do
+ local list = features[what]
+ if list then
+ for feature, spec in next, list do
+ list[feature] = pack(spec)
end
end
end
@@ -263,242 +273,404 @@ local function packdata(data)
return
end
end
- if #t > 0 then
+ if nt > 0 then
for pass=1,2 do
local pack = (pass == 1 and pack_1) or pack_2
- for k, v in next, data.glyphs do
- local m = v.kerns
- if m then
- v.kerns = pack(m)
- end
- local m = v.math
- if m then
- local mk = m.kerns
- if mk then
- m.kerns = pack(mk)
+ for unicode, description in next, data.descriptions do
+ local kerns = description.kerns
+ if kerns then
+ description.kerns = pack(kerns)
+ end
+ local math = description.math
+ if math then
+ local kerns = math.kerns
+ if kerns then
+ math.kerns = pack(kerns)
end
end
- local a = v.anchors
- if a then
- v.anchors = pack(a)
+ local anchors = description.anchors
+ if anchors then
+ description.anchors = pack(anchors)
+ end
+ local mlookups = description.mlookups
+ if mlookups then
+ for tag, mlookup in next, mlookups do
+ mlookups[tag] = pack(mlookup)
+ end
end
- local l = v.mlookups
- if l then
- for k,v in next, l do
- for kk=1,#v do
- v[kk] = pack(v[kk])
+ end
+ local lookups = data.lookups
+ if lookups then
+ for _, lookup in next, lookups do
+ local rules = lookup.rules
+ if rules then
+ for i=1,#rules do -- was next loop
+ local rule = rules[i]
+ local r = rule.before if r then rule.before = pack(r) end
+ local r = rule.after if r then rule.after = pack(r) end
+ local r = rule.current if r then rule.current = pack(r) end
end
end
end
end
- local ls = data.luatex.sequences
- if ls then
- for feature, fdata in next, ls do
- fdata.features = pack(fdata.features)
+ local sequences = resources.sequences
+ if sequences then
+ for feature, sequence in next, sequences do
+ sequence.features = pack(sequence.features)
end
end
if not success(2,pass) then
---~ return
+ -- return
end
end
+
+ for pass=1,2 do
+ local pack = (pass == 1 and pack_1) or pack_2
+ for unicode, description in next, data.descriptions do
+ local slookups = description.slookups
+ if slookups then
+ description.slookups = pack(slookups)
+ end
+ local mlookups = description.mlookups
+ if mlookups then
+ description.mlookups = pack(mlookups)
+ end
+ end
+ end
+
end
end
end
+local unpacked_mt = {
+ __index =
+ function(t,k)
+ t[k] = false
+ return k -- next time true
+ end
+}
+
local function unpackdata(data)
if data then
- local t = data.tables
- if t then
+ local tables = data.tables
+ if tables then
+ local resources = data.resources
+ local lookuptypes = resources.lookuptypes
local unpacked = { }
- for k, v in next, data.glyphs do
- local tv = t[v.boundingbox] if tv then v.boundingbox = tv end
- local l = v.slookups
- if l then
- for k,v in next, l do
- local tv = t[v] if tv then l[k] = tv end
- end
- end
- local l = v.mlookups
- if l then
- for k,v in next, l do
- for i=1,#v do
- local vi = v[i]
- local tv = t[vi]
- if tv then
- v[i] = tv
- if unpacked[tv] then
- vi = false
- else
- unpacked[tv], vi = true, tv
+ setmetatable(unpacked,unpacked_mt)
+ for unicode, description in next, data.descriptions do
+ local tv = tables[description.boundingbox]
+ if tv then
+ description.boundingbox = tv
+ end
+ local slookups = description.slookups
+ if slookups then
+ local tv = tables[slookups]
+ if tv then
+ description.slookups = tv
+ slookups = unpacked[tv]
+ end
+ if slookups then
+ for tag, lookup in next, slookups do
+ local what = lookuptypes[tag]
+ if what == "pair" then
+ local tv = tables[lookup[2]]
+ if tv then
+ lookup[2] = tv
+ end
+ local tv = tables[lookup[3]]
+ if tv then
+ lookup[3] = tv
+ end
+ elseif what ~= "substitution" then
+ local tv = tables[lookup]
+ if tv then
+ slookups[tag] = tv
end
end
- if vi then
- local what = vi[1]
+ end
+ end
+ end
+ local mlookups = description.mlookups
+ if mlookups then
+ local tv = tables[mlookups]
+ if tv then
+ description.mlookups = tv
+ mlookups = unpacked[tv]
+ end
+ if mlookups then
+ for tag, list in next, mlookups do
+ local tv = tables[list]
+ if tv then
+ mlookups[tag] = tv
+ list = unpacked[tv]
+ end
+ if list then
+ local what = lookuptypes[tag]
if what == "pair" then
- local tv = t[vi[3]] if tv then vi[3] = tv end
- local tv = t[vi[4]] if tv then vi[4] = tv end
- elseif what == "position" then
- local tv = t[vi[2]] if tv then vi[2] = tv end
+ for i=1,#list do
+ local lookup = list[i]
+ local tv = tables[lookup[2]]
+ if tv then
+ lookup[2] = tv
+ end
+ local tv = tables[lookup[3]]
+ if tv then
+ lookup[3] = tv
+ end
+ end
+ elseif what ~= "substitution" then
+ for i=1,#list do
+ local tv = tables[list[i]]
+ if tv then
+ list[i] = tv
+ end
+ end
end
end
end
end
end
- local m = v.kerns
- if m then
- local tm = t[m]
+ local kerns = description.kerns
+ if kerns then
+ local tm = tables[kerns]
if tm then
- v.kerns = tm
- if unpacked[tm] then
- m = false
- else
- unpacked[tm], m = true, tm
- end
+ description.kerns = tm
+ kerns = unpacked[tm]
end
- if m then
- for k,v in next, m do
- local tv = t[v] if tv then m[k] = tv end
+ if kerns then
+ for k, kern in next, kerns do
+ local tv = tables[kern]
+ if tv then
+ kerns[k] = tv
+ end
end
end
end
- local m = v.math
- if m then
- local mk = m.kerns
- if mk then
- local tm = t[mk]
+ local math = description.math
+ if math then
+ local kerns = math.kerns
+ if kerns then
+ local tm = tables[kerns]
if tm then
- m.kerns = tm
- if unpacked[tm] then
- mk = false
- else
- unpacked[tm], mk = true, tm
- end
+ math.kerns = tm
+ kerns = unpacked[tm]
end
- if mk then
- for k,v in next, mk do
- local tv = t[v] if tv then mk[k] = tv end
+ if kerns then
+ for k, kern in next, kerns do
+ local tv = tables[kern]
+ if tv then
+ kerns[k] = tv
+ end
end
end
end
end
- local a = v.anchors
- if a then
- local ta = t[a]
+ local anchors = description.anchors
+ if anchors then
+ local ta = tables[anchors]
if ta then
- v.anchors = ta
- if not unpacked[ta] then
- unpacked[ta], a = true, ta
- else
- a = false
- end
+ description.anchors = ta
+ anchors = unpacked[ta]
end
- if a then
- for k,v in next, a do
- if k == "baselig" then
- for kk, vv in next, v do
- for kkk=1,#vv do
- local tv = t[vv[kkk]] if tv then vv[kkk] = tv end
+ if anchors then
+ for tag, anchor in next, anchors do
+ if tag == "baselig" then
+ for _, list in next, anchor do
+ for i=1,#list do
+ local tv = tables[list[i]]
+ if tv then
+ list[i] = tv
+ end
end
end
else
- for kk, vv in next, v do
- local tv = t[vv] if tv then v[kk] = tv end
+ for a, data in next, anchor do
+ local tv = tables[data]
+ if tv then
+ anchor[a] = tv
+ end
end
end
end
end
end
end
- if data.lookups then
- for k, v in next, data.lookups do
- local r = v.rules
- if r then
- for kk, vv in next, r do
- local l = vv.lookups
- if l then
- local tv = t[l] if tv then vv.lookups = tv end
+ local lookups = data.lookups
+ if lookups then
+ for _, lookup in next, lookups do
+ local rules = lookup.rules
+ if rules then
+ for i=1,#rules do -- was next loop
+ local rule = rules[i]
+ local before = rule.before
+ if before then
+ local tv = tables[before]
+ if tv then
+ rule.before = tv
+ before = unpacked[tv]
+ end
+ if before then
+ for i=1,#before do
+ local tv = tables[before[i]]
+ if tv then
+ before[i] = tv
+ end
+ end
+ end
end
- local c = vv.coverage
- if c then
- local cc = c.before if cc then local tv = t[cc] if tv then c.before = tv end end
- cc = c.after if cc then local tv = t[cc] if tv then c.after = tv end end
- cc = c.current if cc then local tv = t[cc] if tv then c.current = tv end end
+ local after = rule.after
+ if after then
+ local tv = tables[after]
+ if tv then
+ rule.after = tv
+ after = unpacked[tv]
+ end
+ if after then
+ for i=1,#after do
+ local tv = tables[after[i]]
+ if tv then
+ after[i] = tv
+ end
+ end
+ end
+ end
+ local current = rule.current
+ if current then
+ local tv = tables[current]
+ if tv then
+ rule.current = tv
+ current = unpacked[tv]
+ end
+ if current then
+ for i=1,#current do
+ local tv = tables[current[i]]
+ if tv then
+ current[i] = tv
+ end
+ end
+ end
end
- local c = vv.reversecoverage
- if c then
- local cc = c.before if cc then local tv = t[cc] if tv then c.before = tv end end
- cc = c.after if cc then local tv = t[cc] if tv then c.after = tv end end
- cc = c.current if cc then local tv = t[cc] if tv then c.current = tv end end
+ local replacements = rule.replacements
+ if replacements then
+ local tv = tables[replacements]
+ if tv then
+ rule.replacements = tv
+ end
+ end
+ local fore = rule.fore
+ if fore then
+ local tv = tables[fore]
+ if tv then
+ rule.fore = tv
+ end
+ end
+ local back = rule.back
+ if back then
+ local tv = tables[back]
+ if tv then
+ rule.back = tv
+ end
+ end
+ local names = rule.names
+ if names then
+ local tv = tables[names]
+ if tv then
+ rule.names = tv
+ end
+ end
+ local lookups = rule.lookups
+ if lookups then
+ local tv = tables[lookups]
+ if tv then
+ rule.lookups = tv
+ end
end
- -- no need to unpack vv.glyphs
end
end
end
end
- local luatex = data.luatex
- if luatex then
- local la = luatex.anchor_to_lookup
- if la then
- for lookup, ldata in next, la do
- local tv = t[ldata] if tv then la[lookup] = tv end
- end
- end
- local la = luatex.lookup_to_anchor
- if la then
- for lookup, ldata in next, la do
- local tv = t[ldata] if tv then la[lookup] = tv end
- end
- end
- local ls = luatex.sequences
- if ls then
- for feature, fdata in next, ls do
- local flags = fdata.flags
- if flags then
- local tv = t[flags] if tv then fdata.flags = tv end
+ local anchor_to_lookup = resources.anchor_to_lookup
+ if anchor_to_lookup then
+ for anchor, lookup in next, anchor_to_lookup do
+ local tv = tables[lookup]
+ if tv then
+ anchor_to_lookup[anchor] = tv
+ end
+ end
+ end
+ local lookup_to_anchor = resources.lookup_to_anchor
+ if lookup_to_anchor then
+ for lookup, anchor in next, lookup_to_anchor do
+ local tv = tables[anchor]
+ if tv then
+ lookup_to_anchor[lookup] = tv
+ end
+ end
+ end
+ local ls = resources.sequences
+ if ls then
+ for _, feature in next, ls do
+ local flags = feature.flags
+ if flags then
+ local tv = tables[flags]
+ if tv then
+ feature.flags = tv
+ end
+ end
+ local subtables = feature.subtables
+ if subtables then
+ local tv = tables[subtables]
+ if tv then
+ feature.subtables = tv
end
- local subtables = fdata.subtables
- if subtables then
- local tv = t[subtables] if tv then fdata.subtables = tv end
+ end
+ local features = feature.features
+ if features then
+ local tv = tables[features]
+ if tv then
+ feature.features = tv
+ features = unpacked[tv]
end
- local features = fdata.features
if features then
- local tv = t[features]
- if tv then
- fdata.features = tv
- if not unpacked[tv] then
- unpacked[tv], features = true, tv
- else
- features = false
- end
- end
- if features then
- for script, sdata in next, features do
- local tv = t[sdata] if tv then features[script] = tv end
+ for script, data in next, features do
+ local tv = tables[data]
+ if tv then
+ features[script] = tv
end
end
end
end
end
- local ls = luatex.lookups
- if ls then
- for lookups, fdata in next, ls do
- local flags = fdata.flags
- if flags then
- local tv = t[flags] if tv then fdata.flags = tv end
+ end
+ local lookups = resources.lookups
+ if lookups then
+ for _, lookup in next, lookups do
+ local flags = lookup.flags
+ if flags then
+ local tv = tables[flags]
+ if tv then
+ lookup.flags = tv
end
- local subtables = fdata.subtables
- if subtables then
- local tv = t[subtables] if tv then fdata.subtables = tv end
+ end
+ local subtables = lookup.subtables
+ if subtables then
+ local tv = tables[subtables]
+ if tv then
+ lookup.subtables = tv
end
end
end
- local lf = luatex.features
- if lf then
- for _, g in next, otf.glists do
- local gl = lf[g]
- if gl then
- for feature, spec in next, gl do
- local tv = t[spec] if tv then gl[feature] = tv end
+ end
+ local features = resources.features
+ if features then
+ for _, what in next, glists do
+ local feature = features[what]
+ if feature then
+ for tag, spec in next, feature do
+ local tv = tables[spec]
+ if tv then
+ feature[tag] = tv
end
end
end
@@ -514,6 +686,8 @@ if otf.enhancers.register then
otf.enhancers.register( "pack", packdata)
otf.enhancers.register("unpack",unpackdata)
+-- todo: directive
+
end
otf.enhancers.unpack = unpackdata -- used elsewhere
diff --git a/tex/context/base/font-ott.lua b/tex/context/base/font-ott.lua
index ec915b878..1dbf626ca 100644
--- a/tex/context/base/font-ott.lua
+++ b/tex/context/base/font-ott.lua
@@ -6,683 +6,728 @@ if not modules then modules = { } end modules ['font-otf'] = {
license = "see context related readme files"
}
-local type, next, tonumber, tostring = type, next, tonumber, tostring
-local gsub, lower, format = string.gsub, string.lower, string.format
+local type, next, tonumber, tostring, rawget, setmetatable = type, next, tonumber, tostring, rawget, setmetatable
+local gsub, lower, format, match = string.gsub, string.lower, string.format, string.match
local is_boolean = string.is_boolean
local allocate = utilities.storage.allocate
-fonts = fonts or { } -- needed for font server
local fonts = fonts
-fonts.otf = fonts.otf or { }
-local otf = fonts.otf
+local otf = fonts.handlers.otf
-otf.tables = otf.tables or { }
-local tables = otf.tables
+local tables = { }
+otf.tables = tables
-otf.meanings = otf.meanings or { }
-local meanings = otf.meanings
+local otffeatures = fonts.constructors.newfeatures("otf")
+local registerotffeature = otffeatures.register
local scripts = allocate {
- ['dflt'] = 'Default',
-
- ['arab'] = 'Arabic',
- ['armn'] = 'Armenian',
- ['bali'] = 'Balinese',
- ['beng'] = 'Bengali',
- ['bopo'] = 'Bopomofo',
- ['brai'] = 'Braille',
- ['bugi'] = 'Buginese',
- ['buhd'] = 'Buhid',
- ['byzm'] = 'Byzantine Music',
- ['cans'] = 'Canadian Syllabics',
- ['cher'] = 'Cherokee',
- ['copt'] = 'Coptic',
- ['cprt'] = 'Cypriot Syllabary',
- ['cyrl'] = 'Cyrillic',
- ['deva'] = 'Devanagari',
- ['dsrt'] = 'Deseret',
- ['ethi'] = 'Ethiopic',
- ['geor'] = 'Georgian',
- ['glag'] = 'Glagolitic',
- ['goth'] = 'Gothic',
- ['grek'] = 'Greek',
- ['gujr'] = 'Gujarati',
- ['guru'] = 'Gurmukhi',
- ['hang'] = 'Hangul',
- ['hani'] = 'CJK Ideographic',
- ['hano'] = 'Hanunoo',
- ['hebr'] = 'Hebrew',
- ['ital'] = 'Old Italic',
- ['jamo'] = 'Hangul Jamo',
- ['java'] = 'Javanese',
- ['kana'] = 'Hiragana and Katakana',
- ['khar'] = 'Kharosthi',
- ['khmr'] = 'Khmer',
- ['knda'] = 'Kannada',
- ['lao' ] = 'Lao',
- ['latn'] = 'Latin',
- ['limb'] = 'Limbu',
- ['linb'] = 'Linear B',
- ['math'] = 'Mathematical Alphanumeric Symbols',
- ['mlym'] = 'Malayalam',
- ['mong'] = 'Mongolian',
- ['musc'] = 'Musical Symbols',
- ['mymr'] = 'Myanmar',
- ['nko' ] = "N'ko",
- ['ogam'] = 'Ogham',
- ['orya'] = 'Oriya',
- ['osma'] = 'Osmanya',
- ['phag'] = 'Phags-pa',
- ['phnx'] = 'Phoenician',
- ['runr'] = 'Runic',
- ['shaw'] = 'Shavian',
- ['sinh'] = 'Sinhala',
- ['sylo'] = 'Syloti Nagri',
- ['syrc'] = 'Syriac',
- ['tagb'] = 'Tagbanwa',
- ['tale'] = 'Tai Le',
- ['talu'] = 'Tai Lu',
- ['taml'] = 'Tamil',
- ['telu'] = 'Telugu',
- ['tfng'] = 'Tifinagh',
- ['tglg'] = 'Tagalog',
- ['thaa'] = 'Thaana',
- ['thai'] = 'Thai',
- ['tibt'] = 'Tibetan',
- ['ugar'] = 'Ugaritic Cuneiform',
- ['xpeo'] = 'Old Persian Cuneiform',
- ['xsux'] = 'Sumero-Akkadian Cuneiform',
- ['yi' ] = 'Yi',
+ ['arab'] = 'arabic',
+ ['armn'] = 'armenian',
+ ['bali'] = 'balinese',
+ ['beng'] = 'bengali',
+ ['bopo'] = 'bopomofo',
+ ['brai'] = 'braille',
+ ['bugi'] = 'buginese',
+ ['buhd'] = 'buhid',
+ ['byzm'] = 'byzantine music',
+ ['cans'] = 'canadian syllabics',
+ ['cher'] = 'cherokee',
+ ['copt'] = 'coptic',
+ ['cprt'] = 'cypriot syllabary',
+ ['cyrl'] = 'cyrillic',
+ ['deva'] = 'devanagari',
+ ['dsrt'] = 'deseret',
+ ['ethi'] = 'ethiopic',
+ ['geor'] = 'georgian',
+ ['glag'] = 'glagolitic',
+ ['goth'] = 'gothic',
+ ['grek'] = 'greek',
+ ['gujr'] = 'gujarati',
+ ['guru'] = 'gurmukhi',
+ ['hang'] = 'hangul',
+ ['hani'] = 'cjk ideographic',
+ ['hano'] = 'hanunoo',
+ ['hebr'] = 'hebrew',
+ ['ital'] = 'old italic',
+ ['jamo'] = 'hangul jamo',
+ ['java'] = 'javanese',
+ ['kana'] = 'hiragana and katakana',
+ ['khar'] = 'kharosthi',
+ ['khmr'] = 'khmer',
+ ['knda'] = 'kannada',
+ ['lao' ] = 'lao',
+ ['latn'] = 'latin',
+ ['limb'] = 'limbu',
+ ['linb'] = 'linear b',
+ ['math'] = 'mathematical alphanumeric symbols',
+ ['mlym'] = 'malayalam',
+ ['mong'] = 'mongolian',
+ ['musc'] = 'musical symbols',
+ ['mymr'] = 'myanmar',
+ ['nko' ] = "n'ko",
+ ['ogam'] = 'ogham',
+ ['orya'] = 'oriya',
+ ['osma'] = 'osmanya',
+ ['phag'] = 'phags-pa',
+ ['phnx'] = 'phoenician',
+ ['runr'] = 'runic',
+ ['shaw'] = 'shavian',
+ ['sinh'] = 'sinhala',
+ ['sylo'] = 'syloti nagri',
+ ['syrc'] = 'syriac',
+ ['tagb'] = 'tagbanwa',
+ ['tale'] = 'tai le',
+ ['talu'] = 'tai lu',
+ ['taml'] = 'tamil',
+ ['telu'] = 'telugu',
+ ['tfng'] = 'tifinagh',
+ ['tglg'] = 'tagalog',
+ ['thaa'] = 'thaana',
+ ['thai'] = 'thai',
+ ['tibt'] = 'tibetan',
+ ['ugar'] = 'ugaritic cuneiform',
+ ['xpeo'] = 'old persian cuneiform',
+ ['xsux'] = 'sumero-akkadian cuneiform',
+ ['yi' ] = 'yi',
}
local languages = allocate {
- ['dflt'] = 'Default',
-
- ['aba'] = 'Abaza',
- ['abk'] = 'Abkhazian',
- ['ady'] = 'Adyghe',
- ['afk'] = 'Afrikaans',
- ['afr'] = 'Afar',
- ['agw'] = 'Agaw',
- ['als'] = 'Alsatian',
- ['alt'] = 'Altai',
- ['amh'] = 'Amharic',
- ['ara'] = 'Arabic',
- ['ari'] = 'Aari',
- ['ark'] = 'Arakanese',
- ['asm'] = 'Assamese',
- ['ath'] = 'Athapaskan',
- ['avr'] = 'Avar',
- ['awa'] = 'Awadhi',
- ['aym'] = 'Aymara',
- ['aze'] = 'Azeri',
- ['bad'] = 'Badaga',
- ['bag'] = 'Baghelkhandi',
- ['bal'] = 'Balkar',
- ['bau'] = 'Baule',
- ['bbr'] = 'Berber',
- ['bch'] = 'Bench',
- ['bcr'] = 'Bible Cree',
- ['bel'] = 'Belarussian',
- ['bem'] = 'Bemba',
- ['ben'] = 'Bengali',
- ['bgr'] = 'Bulgarian',
- ['bhi'] = 'Bhili',
- ['bho'] = 'Bhojpuri',
- ['bik'] = 'Bikol',
- ['bil'] = 'Bilen',
- ['bkf'] = 'Blackfoot',
- ['bli'] = 'Balochi',
- ['bln'] = 'Balante',
- ['blt'] = 'Balti',
- ['bmb'] = 'Bambara',
- ['bml'] = 'Bamileke',
- ['bos'] = 'Bosnian',
- ['bre'] = 'Breton',
- ['brh'] = 'Brahui',
- ['bri'] = 'Braj Bhasha',
- ['brm'] = 'Burmese',
- ['bsh'] = 'Bashkir',
- ['bti'] = 'Beti',
- ['cat'] = 'Catalan',
- ['ceb'] = 'Cebuano',
- ['che'] = 'Chechen',
- ['chg'] = 'Chaha Gurage',
- ['chh'] = 'Chattisgarhi',
- ['chi'] = 'Chichewa',
- ['chk'] = 'Chukchi',
- ['chp'] = 'Chipewyan',
- ['chr'] = 'Cherokee',
- ['chu'] = 'Chuvash',
- ['cmr'] = 'Comorian',
- ['cop'] = 'Coptic',
- ['cos'] = 'Corsican',
- ['cre'] = 'Cree',
- ['crr'] = 'Carrier',
- ['crt'] = 'Crimean Tatar',
- ['csl'] = 'Church Slavonic',
- ['csy'] = 'Czech',
- ['dan'] = 'Danish',
- ['dar'] = 'Dargwa',
- ['dcr'] = 'Woods Cree',
- ['deu'] = 'German',
- ['dgr'] = 'Dogri',
- ['div'] = 'Divehi',
- ['djr'] = 'Djerma',
- ['dng'] = 'Dangme',
- ['dnk'] = 'Dinka',
- ['dri'] = 'Dari',
- ['dun'] = 'Dungan',
- ['dzn'] = 'Dzongkha',
- ['ebi'] = 'Ebira',
- ['ecr'] = 'Eastern Cree',
- ['edo'] = 'Edo',
- ['efi'] = 'Efik',
- ['ell'] = 'Greek',
- ['eng'] = 'English',
- ['erz'] = 'Erzya',
- ['esp'] = 'Spanish',
- ['eti'] = 'Estonian',
- ['euq'] = 'Basque',
- ['evk'] = 'Evenki',
- ['evn'] = 'Even',
- ['ewe'] = 'Ewe',
- ['fan'] = 'French Antillean',
- ['far'] = 'Farsi',
- ['fin'] = 'Finnish',
- ['fji'] = 'Fijian',
- ['fle'] = 'Flemish',
- ['fne'] = 'Forest Nenets',
- ['fon'] = 'Fon',
- ['fos'] = 'Faroese',
- ['fra'] = 'French',
- ['fri'] = 'Frisian',
- ['frl'] = 'Friulian',
- ['fta'] = 'Futa',
- ['ful'] = 'Fulani',
- ['gad'] = 'Ga',
- ['gae'] = 'Gaelic',
- ['gag'] = 'Gagauz',
- ['gal'] = 'Galician',
- ['gar'] = 'Garshuni',
- ['gaw'] = 'Garhwali',
- ['gez'] = "Ge'ez",
- ['gil'] = 'Gilyak',
- ['gmz'] = 'Gumuz',
- ['gon'] = 'Gondi',
- ['grn'] = 'Greenlandic',
- ['gro'] = 'Garo',
- ['gua'] = 'Guarani',
- ['guj'] = 'Gujarati',
- ['hai'] = 'Haitian',
- ['hal'] = 'Halam',
- ['har'] = 'Harauti',
- ['hau'] = 'Hausa',
- ['haw'] = 'Hawaiin',
- ['hbn'] = 'Hammer-Banna',
- ['hil'] = 'Hiligaynon',
- ['hin'] = 'Hindi',
- ['hma'] = 'High Mari',
- ['hnd'] = 'Hindko',
- ['ho'] = 'Ho',
- ['hri'] = 'Harari',
- ['hrv'] = 'Croatian',
- ['hun'] = 'Hungarian',
- ['hye'] = 'Armenian',
- ['ibo'] = 'Igbo',
- ['ijo'] = 'Ijo',
- ['ilo'] = 'Ilokano',
- ['ind'] = 'Indonesian',
- ['ing'] = 'Ingush',
- ['inu'] = 'Inuktitut',
- ['iri'] = 'Irish',
- ['irt'] = 'Irish Traditional',
- ['isl'] = 'Icelandic',
- ['ism'] = 'Inari Sami',
- ['ita'] = 'Italian',
- ['iwr'] = 'Hebrew',
- ['jan'] = 'Japanese',
- ['jav'] = 'Javanese',
- ['jii'] = 'Yiddish',
- ['jud'] = 'Judezmo',
- ['jul'] = 'Jula',
- ['kab'] = 'Kabardian',
- ['kac'] = 'Kachchi',
- ['kal'] = 'Kalenjin',
- ['kan'] = 'Kannada',
- ['kar'] = 'Karachay',
- ['kat'] = 'Georgian',
- ['kaz'] = 'Kazakh',
- ['keb'] = 'Kebena',
- ['kge'] = 'Khutsuri Georgian',
- ['kha'] = 'Khakass',
- ['khk'] = 'Khanty-Kazim',
- ['khm'] = 'Khmer',
- ['khs'] = 'Khanty-Shurishkar',
- ['khv'] = 'Khanty-Vakhi',
- ['khw'] = 'Khowar',
- ['kik'] = 'Kikuyu',
- ['kir'] = 'Kirghiz',
- ['kis'] = 'Kisii',
- ['kkn'] = 'Kokni',
- ['klm'] = 'Kalmyk',
- ['kmb'] = 'Kamba',
- ['kmn'] = 'Kumaoni',
- ['kmo'] = 'Komo',
- ['kms'] = 'Komso',
- ['knr'] = 'Kanuri',
- ['kod'] = 'Kodagu',
- ['koh'] = 'Korean Old Hangul',
- ['kok'] = 'Konkani',
- ['kon'] = 'Kikongo',
- ['kop'] = 'Komi-Permyak',
- ['kor'] = 'Korean',
- ['koz'] = 'Komi-Zyrian',
- ['kpl'] = 'Kpelle',
- ['kri'] = 'Krio',
- ['krk'] = 'Karakalpak',
- ['krl'] = 'Karelian',
- ['krm'] = 'Karaim',
- ['krn'] = 'Karen',
- ['krt'] = 'Koorete',
- ['ksh'] = 'Kashmiri',
- ['ksi'] = 'Khasi',
- ['ksm'] = 'Kildin Sami',
- ['kui'] = 'Kui',
- ['kul'] = 'Kulvi',
- ['kum'] = 'Kumyk',
- ['kur'] = 'Kurdish',
- ['kuu'] = 'Kurukh',
- ['kuy'] = 'Kuy',
- ['kyk'] = 'Koryak',
- ['lad'] = 'Ladin',
- ['lah'] = 'Lahuli',
- ['lak'] = 'Lak',
- ['lam'] = 'Lambani',
- ['lao'] = 'Lao',
- ['lat'] = 'Latin',
- ['laz'] = 'Laz',
- ['lcr'] = 'L-Cree',
- ['ldk'] = 'Ladakhi',
- ['lez'] = 'Lezgi',
- ['lin'] = 'Lingala',
- ['lma'] = 'Low Mari',
- ['lmb'] = 'Limbu',
- ['lmw'] = 'Lomwe',
- ['lsb'] = 'Lower Sorbian',
- ['lsm'] = 'Lule Sami',
- ['lth'] = 'Lithuanian',
- ['ltz'] = 'Luxembourgish',
- ['lub'] = 'Luba',
- ['lug'] = 'Luganda',
- ['luh'] = 'Luhya',
- ['luo'] = 'Luo',
- ['lvi'] = 'Latvian',
- ['maj'] = 'Majang',
- ['mak'] = 'Makua',
- ['mal'] = 'Malayalam Traditional',
- ['man'] = 'Mansi',
- ['map'] = 'Mapudungun',
- ['mar'] = 'Marathi',
- ['maw'] = 'Marwari',
- ['mbn'] = 'Mbundu',
- ['mch'] = 'Manchu',
- ['mcr'] = 'Moose Cree',
- ['mde'] = 'Mende',
- ['men'] = "Me'en",
- ['miz'] = 'Mizo',
- ['mkd'] = 'Macedonian',
- ['mle'] = 'Male',
- ['mlg'] = 'Malagasy',
- ['mln'] = 'Malinke',
- ['mlr'] = 'Malayalam Reformed',
- ['mly'] = 'Malay',
- ['mnd'] = 'Mandinka',
- ['mng'] = 'Mongolian',
- ['mni'] = 'Manipuri',
- ['mnk'] = 'Maninka',
- ['mnx'] = 'Manx Gaelic',
- ['moh'] = 'Mohawk',
- ['mok'] = 'Moksha',
- ['mol'] = 'Moldavian',
- ['mon'] = 'Mon',
- ['mor'] = 'Moroccan',
- ['mri'] = 'Maori',
- ['mth'] = 'Maithili',
- ['mts'] = 'Maltese',
- ['mun'] = 'Mundari',
- ['nag'] = 'Naga-Assamese',
- ['nan'] = 'Nanai',
- ['nas'] = 'Naskapi',
- ['ncr'] = 'N-Cree',
- ['ndb'] = 'Ndebele',
- ['ndg'] = 'Ndonga',
- ['nep'] = 'Nepali',
- ['new'] = 'Newari',
- ['ngr'] = 'Nagari',
- ['nhc'] = 'Norway House Cree',
- ['nis'] = 'Nisi',
- ['niu'] = 'Niuean',
- ['nkl'] = 'Nkole',
- ['nko'] = "N'ko",
- ['nld'] = 'Dutch',
- ['nog'] = 'Nogai',
- ['nor'] = 'Norwegian',
- ['nsm'] = 'Northern Sami',
- ['nta'] = 'Northern Tai',
- ['nto'] = 'Esperanto',
- ['nyn'] = 'Nynorsk',
- ['oci'] = 'Occitan',
- ['ocr'] = 'Oji-Cree',
- ['ojb'] = 'Ojibway',
- ['ori'] = 'Oriya',
- ['oro'] = 'Oromo',
- ['oss'] = 'Ossetian',
- ['paa'] = 'Palestinian Aramaic',
- ['pal'] = 'Pali',
- ['pan'] = 'Punjabi',
- ['pap'] = 'Palpa',
- ['pas'] = 'Pashto',
- ['pgr'] = 'Polytonic Greek',
- ['pil'] = 'Pilipino',
- ['plg'] = 'Palaung',
- ['plk'] = 'Polish',
- ['pro'] = 'Provencal',
- ['ptg'] = 'Portuguese',
- ['qin'] = 'Chin',
- ['raj'] = 'Rajasthani',
- ['rbu'] = 'Russian Buriat',
- ['rcr'] = 'R-Cree',
- ['ria'] = 'Riang',
- ['rms'] = 'Rhaeto-Romanic',
- ['rom'] = 'Romanian',
- ['roy'] = 'Romany',
- ['rsy'] = 'Rusyn',
- ['rua'] = 'Ruanda',
- ['rus'] = 'Russian',
- ['sad'] = 'Sadri',
- ['san'] = 'Sanskrit',
- ['sat'] = 'Santali',
- ['say'] = 'Sayisi',
- ['sek'] = 'Sekota',
- ['sel'] = 'Selkup',
- ['sgo'] = 'Sango',
- ['shn'] = 'Shan',
- ['sib'] = 'Sibe',
- ['sid'] = 'Sidamo',
- ['sig'] = 'Silte Gurage',
- ['sks'] = 'Skolt Sami',
- ['sky'] = 'Slovak',
- ['sla'] = 'Slavey',
- ['slv'] = 'Slovenian',
- ['sml'] = 'Somali',
- ['smo'] = 'Samoan',
- ['sna'] = 'Sena',
- ['snd'] = 'Sindhi',
- ['snh'] = 'Sinhalese',
- ['snk'] = 'Soninke',
- ['sog'] = 'Sodo Gurage',
- ['sot'] = 'Sotho',
- ['sqi'] = 'Albanian',
- ['srb'] = 'Serbian',
- ['srk'] = 'Saraiki',
- ['srr'] = 'Serer',
- ['ssl'] = 'South Slavey',
- ['ssm'] = 'Southern Sami',
- ['sur'] = 'Suri',
- ['sva'] = 'Svan',
- ['sve'] = 'Swedish',
- ['swa'] = 'Swadaya Aramaic',
- ['swk'] = 'Swahili',
- ['swz'] = 'Swazi',
- ['sxt'] = 'Sutu',
- ['syr'] = 'Syriac',
- ['tab'] = 'Tabasaran',
- ['taj'] = 'Tajiki',
- ['tam'] = 'Tamil',
- ['tat'] = 'Tatar',
- ['tcr'] = 'TH-Cree',
- ['tel'] = 'Telugu',
- ['tgn'] = 'Tongan',
- ['tgr'] = 'Tigre',
- ['tgy'] = 'Tigrinya',
- ['tha'] = 'Thai',
- ['tht'] = 'Tahitian',
- ['tib'] = 'Tibetan',
- ['tkm'] = 'Turkmen',
- ['tmn'] = 'Temne',
- ['tna'] = 'Tswana',
- ['tne'] = 'Tundra Nenets',
- ['tng'] = 'Tonga',
- ['tod'] = 'Todo',
- ['trk'] = 'Turkish',
- ['tsg'] = 'Tsonga',
- ['tua'] = 'Turoyo Aramaic',
- ['tul'] = 'Tulu',
- ['tuv'] = 'Tuvin',
- ['twi'] = 'Twi',
- ['udm'] = 'Udmurt',
- ['ukr'] = 'Ukrainian',
- ['urd'] = 'Urdu',
- ['usb'] = 'Upper Sorbian',
- ['uyg'] = 'Uyghur',
- ['uzb'] = 'Uzbek',
- ['ven'] = 'Venda',
- ['vit'] = 'Vietnamese',
- ['wa' ] = 'Wa',
- ['wag'] = 'Wagdi',
- ['wcr'] = 'West-Cree',
- ['wel'] = 'Welsh',
- ['wlf'] = 'Wolof',
- ['xbd'] = 'Tai Lue',
- ['xhs'] = 'Xhosa',
- ['yak'] = 'Yakut',
- ['yba'] = 'Yoruba',
- ['ycr'] = 'Y-Cree',
- ['yic'] = 'Yi Classic',
- ['yim'] = 'Yi Modern',
- ['zhh'] = 'Chinese Hong Kong',
- ['zhp'] = 'Chinese Phonetic',
- ['zhs'] = 'Chinese Simplified',
- ['zht'] = 'Chinese Traditional',
- ['znd'] = 'Zande',
- ['zul'] = 'Zulu'
+ ['aba'] = 'abaza',
+ ['abk'] = 'abkhazian',
+ ['ady'] = 'adyghe',
+ ['afk'] = 'afrikaans',
+ ['afr'] = 'afar',
+ ['agw'] = 'agaw',
+ ['als'] = 'alsatian',
+ ['alt'] = 'altai',
+ ['amh'] = 'amharic',
+ ['ara'] = 'arabic',
+ ['ari'] = 'aari',
+ ['ark'] = 'arakanese',
+ ['asm'] = 'assamese',
+ ['ath'] = 'athapaskan',
+ ['avr'] = 'avar',
+ ['awa'] = 'awadhi',
+ ['aym'] = 'aymara',
+ ['aze'] = 'azeri',
+ ['bad'] = 'badaga',
+ ['bag'] = 'baghelkhandi',
+ ['bal'] = 'balkar',
+ ['bau'] = 'baule',
+ ['bbr'] = 'berber',
+ ['bch'] = 'bench',
+ ['bcr'] = 'bible cree',
+ ['bel'] = 'belarussian',
+ ['bem'] = 'bemba',
+ ['ben'] = 'bengali',
+ ['bgr'] = 'bulgarian',
+ ['bhi'] = 'bhili',
+ ['bho'] = 'bhojpuri',
+ ['bik'] = 'bikol',
+ ['bil'] = 'bilen',
+ ['bkf'] = 'blackfoot',
+ ['bli'] = 'balochi',
+ ['bln'] = 'balante',
+ ['blt'] = 'balti',
+ ['bmb'] = 'bambara',
+ ['bml'] = 'bamileke',
+ ['bos'] = 'bosnian',
+ ['bre'] = 'breton',
+ ['brh'] = 'brahui',
+ ['bri'] = 'braj bhasha',
+ ['brm'] = 'burmese',
+ ['bsh'] = 'bashkir',
+ ['bti'] = 'beti',
+ ['cat'] = 'catalan',
+ ['ceb'] = 'cebuano',
+ ['che'] = 'chechen',
+ ['chg'] = 'chaha gurage',
+ ['chh'] = 'chattisgarhi',
+ ['chi'] = 'chichewa',
+ ['chk'] = 'chukchi',
+ ['chp'] = 'chipewyan',
+ ['chr'] = 'cherokee',
+ ['chu'] = 'chuvash',
+ ['cmr'] = 'comorian',
+ ['cop'] = 'coptic',
+ ['cos'] = 'corsican',
+ ['cre'] = 'cree',
+ ['crr'] = 'carrier',
+ ['crt'] = 'crimean tatar',
+ ['csl'] = 'church slavonic',
+ ['csy'] = 'czech',
+ ['dan'] = 'danish',
+ ['dar'] = 'dargwa',
+ ['dcr'] = 'woods cree',
+ ['deu'] = 'german',
+ ['dgr'] = 'dogri',
+ ['div'] = 'divehi',
+ ['djr'] = 'djerma',
+ ['dng'] = 'dangme',
+ ['dnk'] = 'dinka',
+ ['dri'] = 'dari',
+ ['dun'] = 'dungan',
+ ['dzn'] = 'dzongkha',
+ ['ebi'] = 'ebira',
+ ['ecr'] = 'eastern cree',
+ ['edo'] = 'edo',
+ ['efi'] = 'efik',
+ ['ell'] = 'greek',
+ ['eng'] = 'english',
+ ['erz'] = 'erzya',
+ ['esp'] = 'spanish',
+ ['eti'] = 'estonian',
+ ['euq'] = 'basque',
+ ['evk'] = 'evenki',
+ ['evn'] = 'even',
+ ['ewe'] = 'ewe',
+ ['fan'] = 'french antillean',
+ ['far'] = 'farsi',
+ ['fin'] = 'finnish',
+ ['fji'] = 'fijian',
+ ['fle'] = 'flemish',
+ ['fne'] = 'forest nenets',
+ ['fon'] = 'fon',
+ ['fos'] = 'faroese',
+ ['fra'] = 'french',
+ ['fri'] = 'frisian',
+ ['frl'] = 'friulian',
+ ['fta'] = 'futa',
+ ['ful'] = 'fulani',
+ ['gad'] = 'ga',
+ ['gae'] = 'gaelic',
+ ['gag'] = 'gagauz',
+ ['gal'] = 'galician',
+ ['gar'] = 'garshuni',
+ ['gaw'] = 'garhwali',
+ ['gez'] = "ge'ez",
+ ['gil'] = 'gilyak',
+ ['gmz'] = 'gumuz',
+ ['gon'] = 'gondi',
+ ['grn'] = 'greenlandic',
+ ['gro'] = 'garo',
+ ['gua'] = 'guarani',
+ ['guj'] = 'gujarati',
+ ['hai'] = 'haitian',
+ ['hal'] = 'halam',
+ ['har'] = 'harauti',
+ ['hau'] = 'hausa',
+ ['haw'] = 'hawaiin',
+ ['hbn'] = 'hammer-banna',
+ ['hil'] = 'hiligaynon',
+ ['hin'] = 'hindi',
+ ['hma'] = 'high mari',
+ ['hnd'] = 'hindko',
+ ['ho'] = 'ho',
+ ['hri'] = 'harari',
+ ['hrv'] = 'croatian',
+ ['hun'] = 'hungarian',
+ ['hye'] = 'armenian',
+ ['ibo'] = 'igbo',
+ ['ijo'] = 'ijo',
+ ['ilo'] = 'ilokano',
+ ['ind'] = 'indonesian',
+ ['ing'] = 'ingush',
+ ['inu'] = 'inuktitut',
+ ['iri'] = 'irish',
+ ['irt'] = 'irish traditional',
+ ['isl'] = 'icelandic',
+ ['ism'] = 'inari sami',
+ ['ita'] = 'italian',
+ ['iwr'] = 'hebrew',
+ ['jan'] = 'japanese',
+ ['jav'] = 'javanese',
+ ['jii'] = 'yiddish',
+ ['jud'] = 'judezmo',
+ ['jul'] = 'jula',
+ ['kab'] = 'kabardian',
+ ['kac'] = 'kachchi',
+ ['kal'] = 'kalenjin',
+ ['kan'] = 'kannada',
+ ['kar'] = 'karachay',
+ ['kat'] = 'georgian',
+ ['kaz'] = 'kazakh',
+ ['keb'] = 'kebena',
+ ['kge'] = 'khutsuri georgian',
+ ['kha'] = 'khakass',
+ ['khk'] = 'khanty-kazim',
+ ['khm'] = 'khmer',
+ ['khs'] = 'khanty-shurishkar',
+ ['khv'] = 'khanty-vakhi',
+ ['khw'] = 'khowar',
+ ['kik'] = 'kikuyu',
+ ['kir'] = 'kirghiz',
+ ['kis'] = 'kisii',
+ ['kkn'] = 'kokni',
+ ['klm'] = 'kalmyk',
+ ['kmb'] = 'kamba',
+ ['kmn'] = 'kumaoni',
+ ['kmo'] = 'komo',
+ ['kms'] = 'komso',
+ ['knr'] = 'kanuri',
+ ['kod'] = 'kodagu',
+ ['koh'] = 'korean old hangul',
+ ['kok'] = 'konkani',
+ ['kon'] = 'kikongo',
+ ['kop'] = 'komi-permyak',
+ ['kor'] = 'korean',
+ ['koz'] = 'komi-zyrian',
+ ['kpl'] = 'kpelle',
+ ['kri'] = 'krio',
+ ['krk'] = 'karakalpak',
+ ['krl'] = 'karelian',
+ ['krm'] = 'karaim',
+ ['krn'] = 'karen',
+ ['krt'] = 'koorete',
+ ['ksh'] = 'kashmiri',
+ ['ksi'] = 'khasi',
+ ['ksm'] = 'kildin sami',
+ ['kui'] = 'kui',
+ ['kul'] = 'kulvi',
+ ['kum'] = 'kumyk',
+ ['kur'] = 'kurdish',
+ ['kuu'] = 'kurukh',
+ ['kuy'] = 'kuy',
+ ['kyk'] = 'koryak',
+ ['lad'] = 'ladin',
+ ['lah'] = 'lahuli',
+ ['lak'] = 'lak',
+ ['lam'] = 'lambani',
+ ['lao'] = 'lao',
+ ['lat'] = 'latin',
+ ['laz'] = 'laz',
+ ['lcr'] = 'l-cree',
+ ['ldk'] = 'ladakhi',
+ ['lez'] = 'lezgi',
+ ['lin'] = 'lingala',
+ ['lma'] = 'low mari',
+ ['lmb'] = 'limbu',
+ ['lmw'] = 'lomwe',
+ ['lsb'] = 'lower sorbian',
+ ['lsm'] = 'lule sami',
+ ['lth'] = 'lithuanian',
+ ['ltz'] = 'luxembourgish',
+ ['lub'] = 'luba',
+ ['lug'] = 'luganda',
+ ['luh'] = 'luhya',
+ ['luo'] = 'luo',
+ ['lvi'] = 'latvian',
+ ['maj'] = 'majang',
+ ['mak'] = 'makua',
+ ['mal'] = 'malayalam traditional',
+ ['man'] = 'mansi',
+ ['map'] = 'mapudungun',
+ ['mar'] = 'marathi',
+ ['maw'] = 'marwari',
+ ['mbn'] = 'mbundu',
+ ['mch'] = 'manchu',
+ ['mcr'] = 'moose cree',
+ ['mde'] = 'mende',
+ ['men'] = "me'en",
+ ['miz'] = 'mizo',
+ ['mkd'] = 'macedonian',
+ ['mle'] = 'male',
+ ['mlg'] = 'malagasy',
+ ['mln'] = 'malinke',
+ ['mlr'] = 'malayalam reformed',
+ ['mly'] = 'malay',
+ ['mnd'] = 'mandinka',
+ ['mng'] = 'mongolian',
+ ['mni'] = 'manipuri',
+ ['mnk'] = 'maninka',
+ ['mnx'] = 'manx gaelic',
+ ['moh'] = 'mohawk',
+ ['mok'] = 'moksha',
+ ['mol'] = 'moldavian',
+ ['mon'] = 'mon',
+ ['mor'] = 'moroccan',
+ ['mri'] = 'maori',
+ ['mth'] = 'maithili',
+ ['mts'] = 'maltese',
+ ['mun'] = 'mundari',
+ ['nag'] = 'naga-assamese',
+ ['nan'] = 'nanai',
+ ['nas'] = 'naskapi',
+ ['ncr'] = 'n-cree',
+ ['ndb'] = 'ndebele',
+ ['ndg'] = 'ndonga',
+ ['nep'] = 'nepali',
+ ['new'] = 'newari',
+ ['ngr'] = 'nagari',
+ ['nhc'] = 'norway house cree',
+ ['nis'] = 'nisi',
+ ['niu'] = 'niuean',
+ ['nkl'] = 'nkole',
+ ['nko'] = "n'ko",
+ ['nld'] = 'dutch',
+ ['nog'] = 'nogai',
+ ['nor'] = 'norwegian',
+ ['nsm'] = 'northern sami',
+ ['nta'] = 'northern tai',
+ ['nto'] = 'esperanto',
+ ['nyn'] = 'nynorsk',
+ ['oci'] = 'occitan',
+ ['ocr'] = 'oji-cree',
+ ['ojb'] = 'ojibway',
+ ['ori'] = 'oriya',
+ ['oro'] = 'oromo',
+ ['oss'] = 'ossetian',
+ ['paa'] = 'palestinian aramaic',
+ ['pal'] = 'pali',
+ ['pan'] = 'punjabi',
+ ['pap'] = 'palpa',
+ ['pas'] = 'pashto',
+ ['pgr'] = 'polytonic greek',
+ ['pil'] = 'pilipino',
+ ['plg'] = 'palaung',
+ ['plk'] = 'polish',
+ ['pro'] = 'provencal',
+ ['ptg'] = 'portuguese',
+ ['qin'] = 'chin',
+ ['raj'] = 'rajasthani',
+ ['rbu'] = 'russian buriat',
+ ['rcr'] = 'r-cree',
+ ['ria'] = 'riang',
+ ['rms'] = 'rhaeto-romanic',
+ ['rom'] = 'romanian',
+ ['roy'] = 'romany',
+ ['rsy'] = 'rusyn',
+ ['rua'] = 'ruanda',
+ ['rus'] = 'russian',
+ ['sad'] = 'sadri',
+ ['san'] = 'sanskrit',
+ ['sat'] = 'santali',
+ ['say'] = 'sayisi',
+ ['sek'] = 'sekota',
+ ['sel'] = 'selkup',
+ ['sgo'] = 'sango',
+ ['shn'] = 'shan',
+ ['sib'] = 'sibe',
+ ['sid'] = 'sidamo',
+ ['sig'] = 'silte gurage',
+ ['sks'] = 'skolt sami',
+ ['sky'] = 'slovak',
+ ['sla'] = 'slavey',
+ ['slv'] = 'slovenian',
+ ['sml'] = 'somali',
+ ['smo'] = 'samoan',
+ ['sna'] = 'sena',
+ ['snd'] = 'sindhi',
+ ['snh'] = 'sinhalese',
+ ['snk'] = 'soninke',
+ ['sog'] = 'sodo gurage',
+ ['sot'] = 'sotho',
+ ['sqi'] = 'albanian',
+ ['srb'] = 'serbian',
+ ['srk'] = 'saraiki',
+ ['srr'] = 'serer',
+ ['ssl'] = 'south slavey',
+ ['ssm'] = 'southern sami',
+ ['sur'] = 'suri',
+ ['sva'] = 'svan',
+ ['sve'] = 'swedish',
+ ['swa'] = 'swadaya aramaic',
+ ['swk'] = 'swahili',
+ ['swz'] = 'swazi',
+ ['sxt'] = 'sutu',
+ ['syr'] = 'syriac',
+ ['tab'] = 'tabasaran',
+ ['taj'] = 'tajiki',
+ ['tam'] = 'tamil',
+ ['tat'] = 'tatar',
+ ['tcr'] = 'th-cree',
+ ['tel'] = 'telugu',
+ ['tgn'] = 'tongan',
+ ['tgr'] = 'tigre',
+ ['tgy'] = 'tigrinya',
+ ['tha'] = 'thai',
+ ['tht'] = 'tahitian',
+ ['tib'] = 'tibetan',
+ ['tkm'] = 'turkmen',
+ ['tmn'] = 'temne',
+ ['tna'] = 'tswana',
+ ['tne'] = 'tundra nenets',
+ ['tng'] = 'tonga',
+ ['tod'] = 'todo',
+ ['trk'] = 'turkish',
+ ['tsg'] = 'tsonga',
+ ['tua'] = 'turoyo aramaic',
+ ['tul'] = 'tulu',
+ ['tuv'] = 'tuvin',
+ ['twi'] = 'twi',
+ ['udm'] = 'udmurt',
+ ['ukr'] = 'ukrainian',
+ ['urd'] = 'urdu',
+ ['usb'] = 'upper sorbian',
+ ['uyg'] = 'uyghur',
+ ['uzb'] = 'uzbek',
+ ['ven'] = 'venda',
+ ['vit'] = 'vietnamese',
+ ['wa' ] = 'wa',
+ ['wag'] = 'wagdi',
+ ['wcr'] = 'west-cree',
+ ['wel'] = 'welsh',
+ ['wlf'] = 'wolof',
+ ['xbd'] = 'tai lue',
+ ['xhs'] = 'xhosa',
+ ['yak'] = 'yakut',
+ ['yba'] = 'yoruba',
+ ['ycr'] = 'y-cree',
+ ['yic'] = 'yi classic',
+ ['yim'] = 'yi modern',
+ ['zhh'] = 'chinese hong kong',
+ ['zhp'] = 'chinese phonetic',
+ ['zhs'] = 'chinese simplified',
+ ['zht'] = 'chinese traditional',
+ ['znd'] = 'zande',
+ ['zul'] = 'zulu'
}
local features = allocate {
- ['aalt'] = 'Access All Alternates',
- ['abvf'] = 'Above-Base Forms',
- ['abvm'] = 'Above-Base Mark Positioning',
- ['abvs'] = 'Above-Base Substitutions',
- ['afrc'] = 'Alternative Fractions',
- ['akhn'] = 'Akhands',
- ['blwf'] = 'Below-Base Forms',
- ['blwm'] = 'Below-Base Mark Positioning',
- ['blws'] = 'Below-Base Substitutions',
- ['c2pc'] = 'Petite Capitals From Capitals',
- ['c2sc'] = 'Small Capitals From Capitals',
- ['calt'] = 'Contextual Alternates',
- ['case'] = 'Case-Sensitive Forms',
- ['ccmp'] = 'Glyph Composition/Decomposition',
- ['cjct'] = 'Conjunct Forms',
- ['clig'] = 'Contextual Ligatures',
- ['cpsp'] = 'Capital Spacing',
- ['cswh'] = 'Contextual Swash',
- ['curs'] = 'Cursive Positioning',
- ['dflt'] = 'Default Processing',
- ['dist'] = 'Distances',
- ['dlig'] = 'Discretionary Ligatures',
- ['dnom'] = 'Denominators',
- ['dtls'] = 'Dotless Forms', -- math
- ['expt'] = 'Expert Forms',
- ['falt'] = 'Final glyph Alternates',
- ['fin2'] = 'Terminal Forms #2',
- ['fin3'] = 'Terminal Forms #3',
- ['fina'] = 'Terminal Forms',
- ['flac'] = 'Flattened Accents Over Capitals', -- math
- ['frac'] = 'Fractions',
- ['fwid'] = 'Full Width',
- ['half'] = 'Half Forms',
- ['haln'] = 'Halant Forms',
- ['halt'] = 'Alternate Half Width',
- ['hist'] = 'Historical Forms',
- ['hkna'] = 'Horizontal Kana Alternates',
- ['hlig'] = 'Historical Ligatures',
- ['hngl'] = 'Hangul',
- ['hojo'] = 'Hojo Kanji Forms',
- ['hwid'] = 'Half Width',
- ['init'] = 'Initial Forms',
- ['isol'] = 'Isolated Forms',
- ['ital'] = 'Italics',
- ['jalt'] = 'Justification Alternatives',
- ['jp04'] = 'JIS2004 Forms',
- ['jp78'] = 'JIS78 Forms',
- ['jp83'] = 'JIS83 Forms',
- ['jp90'] = 'JIS90 Forms',
- ['kern'] = 'Kerning',
- ['lfbd'] = 'Left Bounds',
- ['liga'] = 'Standard Ligatures',
- ['ljmo'] = 'Leading Jamo Forms',
- ['lnum'] = 'Lining Figures',
- ['locl'] = 'Localized Forms',
- ['mark'] = 'Mark Positioning',
- ['med2'] = 'Medial Forms #2',
- ['medi'] = 'Medial Forms',
- ['mgrk'] = 'Mathematical Greek',
- ['mkmk'] = 'Mark to Mark Positioning',
- ['mset'] = 'Mark Positioning via Substitution',
- ['nalt'] = 'Alternate Annotation Forms',
- ['nlck'] = 'NLC Kanji Forms',
- ['nukt'] = 'Nukta Forms',
- ['numr'] = 'Numerators',
- ['onum'] = 'Old Style Figures',
- ['opbd'] = 'Optical Bounds',
- ['ordn'] = 'Ordinals',
- ['ornm'] = 'Ornaments',
- ['palt'] = 'Proportional Alternate Width',
- ['pcap'] = 'Petite Capitals',
- ['pnum'] = 'Proportional Figures',
- ['pref'] = 'Pre-base Forms',
- ['pres'] = 'Pre-base Substitutions',
- ['pstf'] = 'Post-base Forms',
- ['psts'] = 'Post-base Substitutions',
- ['pwid'] = 'Proportional Widths',
- ['qwid'] = 'Quarter Widths',
- ['rand'] = 'Randomize',
- ['rkrf'] = 'Rakar Forms',
- ['rlig'] = 'Required Ligatures',
- ['rphf'] = 'Reph Form',
- ['rtbd'] = 'Right Bounds',
- ['rtla'] = 'Right-To-Left Alternates',
- ['rtlm'] = 'Right To Left Math', -- math
- ['ruby'] = 'Ruby Notation Forms',
- ['salt'] = 'Stylistic Alternates',
- ['sinf'] = 'Scientific Inferiors',
- ['size'] = 'Optical Size',
- ['smcp'] = 'Small Capitals',
- ['smpl'] = 'Simplified Forms',
- ['ss01'] = 'Stylistic Set 1',
- ['ss02'] = 'Stylistic Set 2',
- ['ss03'] = 'Stylistic Set 3',
- ['ss04'] = 'Stylistic Set 4',
- ['ss05'] = 'Stylistic Set 5',
- ['ss06'] = 'Stylistic Set 6',
- ['ss07'] = 'Stylistic Set 7',
- ['ss08'] = 'Stylistic Set 8',
- ['ss09'] = 'Stylistic Set 9',
- ['ss10'] = 'Stylistic Set 10',
- ['ss11'] = 'Stylistic Set 11',
- ['ss12'] = 'Stylistic Set 12',
- ['ss13'] = 'Stylistic Set 13',
- ['ss14'] = 'Stylistic Set 14',
- ['ss15'] = 'Stylistic Set 15',
- ['ss16'] = 'Stylistic Set 16',
- ['ss17'] = 'Stylistic Set 17',
- ['ss18'] = 'Stylistic Set 18',
- ['ss19'] = 'Stylistic Set 19',
- ['ss20'] = 'Stylistic Set 20',
- ['ssty'] = 'Script Style', -- math
- ['subs'] = 'Subscript',
- ['sups'] = 'Superscript',
- ['swsh'] = 'Swash',
- ['titl'] = 'Titling',
- ['tjmo'] = 'Trailing Jamo Forms',
- ['tnam'] = 'Traditional Name Forms',
- ['tnum'] = 'Tabular Figures',
- ['trad'] = 'Traditional Forms',
- ['twid'] = 'Third Widths',
- ['unic'] = 'Unicase',
- ['valt'] = 'Alternate Vertical Metrics',
- ['vatu'] = 'Vattu Variants',
- ['vert'] = 'Vertical Writing',
- ['vhal'] = 'Alternate Vertical Half Metrics',
- ['vjmo'] = 'Vowel Jamo Forms',
- ['vkna'] = 'Vertical Kana Alternates',
- ['vkrn'] = 'Vertical Kerning',
- ['vpal'] = 'Proportional Alternate Vertical Metrics',
- ['vrt2'] = 'Vertical Rotation',
- ['zero'] = 'Slashed Zero',
+ ['aalt'] = 'access all alternates',
+ ['abvf'] = 'above-base forms',
+ ['abvm'] = 'above-base mark positioning',
+ ['abvs'] = 'above-base substitutions',
+ ['afrc'] = 'alternative fractions',
+ ['akhn'] = 'akhands',
+ ['blwf'] = 'below-base forms',
+ ['blwm'] = 'below-base mark positioning',
+ ['blws'] = 'below-base substitutions',
+ ['c2pc'] = 'petite capitals from capitals',
+ ['c2sc'] = 'small capitals from capitals',
+ ['calt'] = 'contextual alternates',
+ ['case'] = 'case-sensitive forms',
+ ['ccmp'] = 'glyph composition/decomposition',
+ ['cjct'] = 'conjunct forms',
+ ['clig'] = 'contextual ligatures',
+ ['cpsp'] = 'capital spacing',
+ ['cswh'] = 'contextual swash',
+ ['curs'] = 'cursive positioning',
+ ['dflt'] = 'default processing',
+ ['dist'] = 'distances',
+ ['dlig'] = 'discretionary ligatures',
+ ['dnom'] = 'denominators',
+ ['dtls'] = 'dotless forms', -- math
+ ['expt'] = 'expert forms',
+ ['falt'] = 'final glyph alternates',
+ ['fin2'] = 'terminal forms #2',
+ ['fin3'] = 'terminal forms #3',
+ ['fina'] = 'terminal forms',
+ ['flac'] = 'flattened accents over capitals', -- math
+ ['frac'] = 'fractions',
+ ['fwid'] = 'full width',
+ ['half'] = 'half forms',
+ ['haln'] = 'halant forms',
+ ['halt'] = 'alternate half width',
+ ['hist'] = 'historical forms',
+ ['hkna'] = 'horizontal kana alternates',
+ ['hlig'] = 'historical ligatures',
+ ['hngl'] = 'hangul',
+ ['hojo'] = 'hojo kanji forms',
+ ['hwid'] = 'half width',
+ ['init'] = 'initial forms',
+ ['isol'] = 'isolated forms',
+ ['ital'] = 'italics',
+ ['jalt'] = 'justification alternatives',
+ ['jp04'] = 'jis2004 forms',
+ ['jp78'] = 'jis78 forms',
+ ['jp83'] = 'jis83 forms',
+ ['jp90'] = 'jis90 forms',
+ ['kern'] = 'kerning',
+ ['lfbd'] = 'left bounds',
+ ['liga'] = 'standard ligatures',
+ ['ljmo'] = 'leading jamo forms',
+ ['lnum'] = 'lining figures',
+ ['locl'] = 'localized forms',
+ ['mark'] = 'mark positioning',
+ ['med2'] = 'medial forms #2',
+ ['medi'] = 'medial forms',
+ ['mgrk'] = 'mathematical greek',
+ ['mkmk'] = 'mark to mark positioning',
+ ['mset'] = 'mark positioning via substitution',
+ ['nalt'] = 'alternate annotation forms',
+ ['nlck'] = 'nlc kanji forms',
+ ['nukt'] = 'nukta forms',
+ ['numr'] = 'numerators',
+ ['onum'] = 'old style figures',
+ ['opbd'] = 'optical bounds',
+ ['ordn'] = 'ordinals',
+ ['ornm'] = 'ornaments',
+ ['palt'] = 'proportional alternate width',
+ ['pcap'] = 'petite capitals',
+ ['pnum'] = 'proportional figures',
+ ['pref'] = 'pre-base forms',
+ ['pres'] = 'pre-base substitutions',
+ ['pstf'] = 'post-base forms',
+ ['psts'] = 'post-base substitutions',
+ ['pwid'] = 'proportional widths',
+ ['qwid'] = 'quarter widths',
+ ['rand'] = 'randomize',
+ ['rkrf'] = 'rakar forms',
+ ['rlig'] = 'required ligatures',
+ ['rphf'] = 'reph form',
+ ['rtbd'] = 'right bounds',
+ ['rtla'] = 'right-to-left alternates',
+ ['rtlm'] = 'right to left math', -- math
+ ['ruby'] = 'ruby notation forms',
+ ['salt'] = 'stylistic alternates',
+ ['sinf'] = 'scientific inferiors',
+ ['size'] = 'optical size',
+ ['smcp'] = 'small capitals',
+ ['smpl'] = 'simplified forms',
+ ['ss01'] = 'stylistic set 1',
+ ['ss02'] = 'stylistic set 2',
+ ['ss03'] = 'stylistic set 3',
+ ['ss04'] = 'stylistic set 4',
+ ['ss05'] = 'stylistic set 5',
+ ['ss06'] = 'stylistic set 6',
+ ['ss07'] = 'stylistic set 7',
+ ['ss08'] = 'stylistic set 8',
+ ['ss09'] = 'stylistic set 9',
+ ['ss10'] = 'stylistic set 10',
+ ['ss11'] = 'stylistic set 11',
+ ['ss12'] = 'stylistic set 12',
+ ['ss13'] = 'stylistic set 13',
+ ['ss14'] = 'stylistic set 14',
+ ['ss15'] = 'stylistic set 15',
+ ['ss16'] = 'stylistic set 16',
+ ['ss17'] = 'stylistic set 17',
+ ['ss18'] = 'stylistic set 18',
+ ['ss19'] = 'stylistic set 19',
+ ['ss20'] = 'stylistic set 20',
+ ['ssty'] = 'script style', -- math
+ ['subs'] = 'subscript',
+ ['sups'] = 'superscript',
+ ['swsh'] = 'swash',
+ ['titl'] = 'titling',
+ ['tjmo'] = 'trailing jamo forms',
+ ['tnam'] = 'traditional name forms',
+ ['tnum'] = 'tabular figures',
+ ['trad'] = 'traditional forms',
+ ['twid'] = 'third widths',
+ ['unic'] = 'unicase',
+ ['valt'] = 'alternate vertical metrics',
+ ['vatu'] = 'vattu variants',
+ ['vert'] = 'vertical writing',
+ ['vhal'] = 'alternate vertical half metrics',
+ ['vjmo'] = 'vowel jamo forms',
+ ['vkna'] = 'vertical kana alternates',
+ ['vkrn'] = 'vertical kerning',
+ ['vpal'] = 'proportional alternate vertical metrics',
+ ['vrt2'] = 'vertical rotation',
+ ['zero'] = 'slashed zero',
- ['trep'] = 'Traditional TeX Replacements',
- ['tlig'] = 'Traditional TeX Ligatures',
+ ['trep'] = 'traditional tex replacements',
+ ['tlig'] = 'traditional tex ligatures',
+
+ ['ss'] = 'stylistic set %s',
}
local baselines = allocate {
- ['hang'] = 'Hanging baseline',
- ['icfb'] = 'Ideographic character face bottom edge baseline',
- ['icft'] = 'Ideographic character face tope edige baseline',
- ['ideo'] = 'Ideographic em-box bottom edge baseline',
- ['idtp'] = 'Ideographic em-box top edge baseline',
- ['math'] = 'Mathmatical centered baseline',
- ['romn'] = 'Roman baseline'
+ ['hang'] = 'hanging baseline',
+ ['icfb'] = 'ideographic character face bottom edge baseline',
+ ['icft'] = 'ideographic character face tope edige baseline',
+ ['ideo'] = 'ideographic em-box bottom edge baseline',
+ ['idtp'] = 'ideographic em-box top edge baseline',
+ ['math'] = 'mathmatical centered baseline',
+ ['romn'] = 'roman baseline'
}
+tables.scripts = scripts
+tables.languages = languages
+tables.features = features
+tables.baselines = baselines
-local function swap(h) -- can be a tables.swap when we get a better name
+if otffeatures.features then
+ for k, v in next, otffeatures.features do
+ features[k] = v
+ end
+ otffeatures.features = features
+end
+
+local function swapped(h)
local r = { }
for k, v in next, h do
- r[v] = lower(gsub(k," ",""))
+ r[gsub(v,"[^a-z0-9]","")] = k -- is already lower
end
return r
end
-local verbosescripts = allocate(swap(scripts ))
-local verboselanguages = allocate(swap(languages))
-local verbosefeatures = allocate(swap(features ))
+local verbosescripts = allocate(swapped(scripts ))
+local verboselanguages = allocate(swapped(languages))
+local verbosefeatures = allocate(swapped(features ))
+local verbosebaselines = allocate(swapped(baselines))
+
+-- lets forget about trailing spaces
-tables.scripts = scripts
-tables.languages = languages
-tables.features = features
-tables.baselines = baselines
+local function resolve(t,k)
+ if k then
+ k = gsub(lower(k),"[^a-z0-9]","")
+ local v = rawget(t,k)
+ if v then
+ return v
+ end
+ end
+ return "dflt"
+end
+
+setmetatable(verbosescripts, { __index = resolve })
+setmetatable(verboselanguages, { __index = resolve })
+setmetatable(verbosefeatures, { __index = resolve })
+setmetatable(verbosebaselines, { __index = resolve })
-tables.verbosescripts = verbosescripts
-tables.verboselanguages = verboselanguages
-tables.verbosefeatures = verbosefeatures
+local function resolve(t,k)
+ if k then
+ k = lower(k)
+ local v = rawget(t,k) or rawget(t,gsub(k," ",""))
+ if v then
+ return v
+ end
+ end
+ return "dflt"
+end
-for k, v in next, verbosefeatures do
- local stripped = gsub(k,"%-"," ")
- verbosefeatures[stripped] = v
- local stripped = gsub(k,"[^a-zA-Z0-9]","")
- verbosefeatures[stripped] = v
+local function assign(t,k,v)
+ -- forget about it
end
-for k, v in next, verbosefeatures do
- verbosefeatures[lower(k)] = v
+
+setmetatable(scripts, { __index = resolve, __newindex = assign })
+setmetatable(languages, { __index = resolve, __newindex = assign })
+setmetatable(baselines, { __index = resolve, __newindex = assign })
+
+local function resolve(t,k)
+ if k then
+ k = lower(k)
+ local v = rawget(t,k)
+ if v then
+ return v
+ end
+ k = gsub(k," ","")
+ local v = rawget(t,k)
+ if v then
+ return v
+ end
+ local tag, dd = match(k,"(..)(%d+)")
+ if tag and dd then
+ local v = rawget(t,tag)
+ if v then
+ return format(v,tonumber(dd))
+ end
+ end
+ end
+ return "dflt"
end
-local function resolve(tab,id)
- if tab and id then
- id = lower(id)
- return tab[id] or tab[gsub(id," ","")] or tab['dflt'] or ''
- else
- return "unknown"
+local function assign(t,k,v)
+ if k then
+ v = lower(v)
+ rawset(t,k,v)
+ rawset(features,gsub(v,"[^a-z0-9]",""),k)
end
end
-function meanings.script (id) return resolve(scripts, id) end
-function meanings.language(id) return resolve(languages,id) end
-function meanings.feature (id) return resolve(features, id) end
-function meanings.baseline(id) return resolve(baselines,id) end
+setmetatable(features, { __index = resolve, __newindex = assign })
local checkers = {
rand = function(v)
@@ -690,26 +735,24 @@ local checkers = {
end
}
-meanings.checkers = checkers
-
-function meanings.normalize(features)
+function otf.features.normalize(features) -- no longer 'lang'
if features then
local h = { }
for k,v in next, features do
k = lower(k)
- if k == "language" or k == "lang" then
- v = gsub(lower(v),"[^a-z0-9%-]","")
- if not languages[v] then
- h.language = verboselanguages[v] or "dflt"
- else
+ if k == "language" then
+ v = gsub(lower(v),"[^a-z0-9]","")
+ if rawget(languages,v) then
h.language = v
+ else
+ h.language = rawget(verboselanguages,v) or "dflt"
end
elseif k == "script" then
- v = gsub(lower(v),"[^a-z0-9%-]","")
- if not scripts[v] then
- h.script = verbosescripts[v] or "dflt"
- else
+ v = gsub(lower(v),"[^a-z0-9]","")
+ if rawget(scripts,v) then
h.script = v
+ else
+ h.script = rawget(verbosescripts,v) or "dflt"
end
else
if type(v) == "string" then
@@ -720,7 +763,9 @@ function meanings.normalize(features)
v = b
end
end
- k = verbosefeatures[k] or k
+ if not rawget(features,k) then
+ k = rawget(verbosefeatures,k) or k
+ end
local c = checkers[k]
h[k] = c and c(v) or v
end
@@ -729,6 +774,8 @@ function meanings.normalize(features)
end
end
+--~ table.print(otf.features.normalize({ language = "dutch", liga = "yes", ss99 = true, aalt = 3, abcd = "yes" } ))
+
-- When I feel the need ...
--~ tables.aat = {
diff --git a/tex/context/base/font-pat.lua b/tex/context/base/font-pat.lua
index 8748f0ed1..b91502c74 100644
--- a/tex/context/base/font-pat.lua
+++ b/tex/context/base/font-pat.lua
@@ -12,7 +12,9 @@ local match, lower = string.match, string.lower
-- so for them we get it from the name
-- reporter moved to elsewhere
-local patches = fonts.otf.enhancers.patches
+local fonts = fonts
+local otf = fonts.handlers.otf
+local patches = otf.enhancers.patches
local register = patches.register
local report = patches.report
diff --git a/tex/context/base/font-syn.lua b/tex/context/base/font-syn.lua
index 8f85b8582..1d444cdc7 100644
--- a/tex/context/base/font-syn.lua
+++ b/tex/context/base/font-syn.lua
@@ -33,11 +33,10 @@ using a table that has keys filtered from the font related files.</p>
local texsprint = (tex and tex.sprint) or print
-fonts = fonts or { } -- this module is also used in mtxrun
-local fonts = fonts
+fonts = fonts or { } -- also used elsewhere
-fonts.names = fonts.names or { }
-local names = fonts.names
+local names = { }
+fonts.names = names
names.filters = names.filters or { }
local filters = names.filters
diff --git a/tex/context/base/font-tfm.lua b/tex/context/base/font-tfm.lua
index 5e841b24c..8f0a99d5a 100644
--- a/tex/context/base/font-tfm.lua
+++ b/tex/context/base/font-tfm.lua
@@ -6,808 +6,137 @@ if not modules then modules = { } end modules ['font-tfm'] = {
license = "see context related readme files"
}
-local utf = unicode.utf8
+local next = next
+local match = string.match
-local next, format, match, lower, gsub = next, string.format, string.match, string.lower, string.gsub
-local concat, sortedkeys, utfbyte, serialize = table.concat, table.sortedkeys, utf.byte, table.serialize
+local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
+local trace_features = false trackers.register("tfm.features", function(v) trace_features = v end)
-local allocate = utilities.storage.allocate
+local report_defining = logs.reporter("fonts","defining")
+local report_tfm = logs.reporter("fonts","tfm loading")
-local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
-local trace_scaling = false trackers.register("fonts.scaling" , function(v) trace_scaling = v end)
+local fonts = fonts
+local handlers = fonts.handlers
+local readers = fonts.readers
+local constructors = fonts.constructors
+local encodings = fonts.encodings
-local report_defining = logs.reporter("fonts","defining")
+local tfm = { }
+handlers.tfm = tfm
--- tfmdata has also fast access to indices and unicodes
--- to be checked: otf -> tfm -> tfmscaled
---
--- watch out: no negative depths and negative eights permitted in regular fonts
+constructors.resolvevirtualtoo = false -- wil be set in font-ctx.lua
---[[ldx--
-<p>Here we only implement a few helper functions.</p>
---ldx]]--
-
-local fonts = fonts
-local tfm = fonts.tfm
-
-fonts.loaded = allocate()
-fonts.dontembed = allocate()
-fonts.triggers = fonts.triggers or { } -- brrr
-fonts.initializers = fonts.initializers or { }
-fonts.initializers.common = fonts.initializers.common or { }
-
-local set_attribute = node.set_attribute
-local findbinfile = resolvers.findbinfile
+local findbinfile = resolvers.findbinfile
-local readers = fonts.tfm.readers
-local fontdata = fonts.identifiers
-local nodecodes = nodes.nodecodes
+local tfmfeatures = fonts.constructors.newfeatures("tfm")
+local registertfmfeature = tfmfeatures.register
-local disc_code = nodecodes.disc
-local glyph_code = nodecodes.glyph
+fonts.formats.tfm = "type1" -- we need to have at least a value here
--[[ldx--
<p>The next function encapsulates the standard <l n='tfm'/> loader as
supplied by <l n='luatex'/>.</p>
--ldx]]--
-tfm.resolvevirtualtoo = true -- false
-tfm.sharebasekerns = false -- true (.5 sec slower on mk but brings down mem from 410M to 310M, beware: then script/lang share too)
-tfm.mathactions = { }
-tfm.fontnamemode = "fullpath"
-
-tfm.enhance = tfm.enhance or function() end
-
-local function read_from_tfm(specification)
- local fname, tfmdata = specification.filename or "", nil
- if fname ~= "" then
- if trace_defining then
- report_defining("loading tfm file %s at size %s",fname,specification.size)
- end
- tfmdata = font.read_tfm(fname,specification.size) -- not cached, fast enough
- if tfmdata then
- tfmdata.descriptions = tfmdata.descriptions or { }
- if tfm.resolvevirtualtoo then
- fonts.logger.save(tfmdata,file.extname(fname),specification) -- strange, why here
- fname = findbinfile(specification.name, 'ovf')
- if fname and fname ~= "" then
- local vfdata = font.read_vf(fname,specification.size) -- not cached, fast enough
- if vfdata then
- local chars = tfmdata.characters
- for k,v in next, vfdata.characters do
- chars[k].commands = v.commands
- end
- tfmdata.type = 'virtual'
- tfmdata.fonts = vfdata.fonts
- end
- end
- end
- tfm.enhance(tfmdata,specification)
- end
- elseif trace_defining then
- report_defining("loading tfm with name %s fails",specification.name)
- end
- return tfmdata
-end
+-- this might change: not scaling and then apply features and do scaling in the
+-- usual way with dummy descriptions but on the other hand .. we no longer use
+-- tfm so why bother
---[[ldx--
-<p>We need to normalize the scale factor (in scaled points). This has to
-do with the fact that <l n='tex'/> uses a negative multiple of 1000 as
-a signal for a font scaled based on the design size.</p>
---ldx]]--
+-- ofm directive blocks local path search unless set; btw, in context we
+-- don't support ofm files anyway as this format is obsolete
-local factors = {
- pt = 65536.0,
- bp = 65781.8,
-}
-
-function tfm.setfactor(f)
- tfm.factor = factors[f or 'pt'] or factors.pt
-end
-
-tfm.setfactor()
-
-function tfm.scaled(scaledpoints, designsize) -- handles designsize in sp as well
- if scaledpoints < 0 then
- if designsize then
- if designsize > tfm.factor then -- or just 1000 / when? mp?
- return (- scaledpoints/1000) * designsize -- sp's
- else
- return (- scaledpoints/1000) * designsize * tfm.factor
- end
- else
- return (- scaledpoints/1000) * 10 * tfm.factor
- end
+function tfm.setfeatures(tfmdata,features)
+ local okay = constructors.initializefeatures("tfm",tfmdata,features,trace_features,report_tfm)
+ if okay then
+ return constructors.collectprocessors("tfm",tfmdata,features,trace_features,report_tfm)
else
- return scaledpoints
+ return { } -- will become false
end
end
---[[ldx--
-<p>Before a font is passed to <l n='tex'/> we scale it. Here we also need
-to scale virtual characters.</p>
---ldx]]--
-
---~ function tfm.getvirtualid(tfmdata)
---~ -- since we don't know the id yet, we use 0 as signal
---~ local tf = tfmdata.fonts
---~ if not tf then
---~ tfmdata.type = "virtual"
---~ tfmdata.fonts = { { id = 0 } }
---~ return 1
---~ else
---~ local ntf = #tf + 1
---~ tf[ntf] = { id = 0 }
---~ return ntf
---~ end
---~ end
-
-function tfm.getvirtualid(tfmdata)
- -- since we don't know the id yet, we use 0 as signal
- local tf = tfmdata.fonts
- if not tf then
- tf = { }
- tfmdata.type = "virtual"
- tfmdata.fonts = tf
- end
- local ntf = #tf + 1
- tf[ntf] = { id = 0 }
- return ntf
-end
-
-function tfm.checkvirtualid(tfmdata, id)
- if tfmdata and tfmdata.type == "virtual" then
- if not tfmdata.fonts or #tfmdata.fonts == 0 then
- tfmdata.type, tfmdata.fonts = "real", nil
- else
- local vfonts = tfmdata.fonts
- for f=1,#vfonts do
- local fnt = vfonts[f]
- if fnt.id and fnt.id == 0 then
- fnt.id = id
- end
- end
- end
- end
-end
-
---[[ldx--
-<p>Beware, the boundingbox is passed as reference so we may not overwrite it
-in the process; numbers are of course copies. Here 65536 equals 1pt. (Due to
-excessive memory usage in CJK fonts, we no longer pass the boundingbox.)</p>
---ldx]]--
-
-fonts.trace_scaling = false
-
--- the following hack costs a bit of runtime but safes memory
---
--- basekerns are scaled and will be hashed by table id
--- sharedkerns are unscaled and are be hashed by concatenated indexes
-
---~ function tfm.check_base_kerns(tfmdata)
---~ if tfm.sharebasekerns then
---~ local sharedkerns = tfmdata.sharedkerns
---~ if sharedkerns then
---~ local basekerns = { }
---~ tfmdata.basekerns = basekerns
---~ return sharedkerns, basekerns
---~ end
---~ end
---~ return nil, nil
---~ end
-
---~ function tfm.prepare_base_kerns(tfmdata)
---~ if tfm.sharebasekerns and not tfmdata.sharedkerns then
---~ local sharedkerns = { }
---~ tfmdata.sharedkerns = sharedkerns
---~ for u, chr in next, tfmdata.characters do
---~ local kerns = chr.kerns
---~ if kerns then
---~ local hash = concat(sortedkeys(kerns), " ")
---~ local base = sharedkerns[hash]
---~ if not base then
---~ sharedkerns[hash] = kerns
---~ else
---~ chr.kerns = base
---~ end
---~ end
---~ end
---~ end
---~ end
-
--- we can have cache scaled characters when we are in node mode and don't have
--- protruding and expansion: hash == fullname @ size @ protruding @ expansion
--- but in practice (except from mk) the otf hash will be enough already so it
--- makes no sense to mess up the code now
-
-local charactercache = { }
-
--- The scaler is only used for otf and afm and virtual fonts. If
--- a virtual font has italic correction make sure to set the
--- has_italic flag. Some more flags will be added in the future.
-
---[[ldx--
-<p>The reason why the scaler was originally split, is that for a while we experimented
-with a helper function. However, in practice the <l n='api'/> calls are too slow to
-make this profitable and the <l n='lua'/> based variant was just faster. A days
-wasted day but an experience richer.</p>
---ldx]]--
-
-tfm.autocleanup = true
-
-local lastfont = nil
-
--- 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
---
--- 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
-
--- we don't need the glyph data as we can use the description .. but we will
--- have to wait till we can access the internal tfm table efficiently in which
--- case characters will become a metatable afterwards
-
-function tfm.cleanuptable(tfmdata) -- we need a cleanup callback, now we miss the last one
- if tfm.autocleanup then -- ok, we can hook this into everyshipout or so ... todo
- if tfmdata.type == 'virtual' or tfmdata.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
- else
- -- for k, v in next, tfmdata.characters do
- -- if v.kerns then v.kerns = nil end
- -- end
- end
- end
-end
-
-function tfm.cleanup(tfmdata) -- we need a cleanup callback, now we miss the last one
-end
-
-function tfm.calculatescale(tfmtable, scaledpoints)
- if scaledpoints < 0 then
- scaledpoints = (- scaledpoints/1000) * tfmtable.designsize -- already in sp
- end
- local units = tfmtable.units or 1000
- local delta = scaledpoints/units -- brr, some open type fonts have 2048
- return scaledpoints, delta, units
-end
-
-function tfm.scale(tfmtable, scaledpoints, relativeid)
- -- tfm.prepare_base_kerns(tfmtable) -- optimalization
- local t = { } -- the new table
- local scaledpoints, delta, units = tfm.calculatescale(tfmtable, scaledpoints, relativeid)
- -- is just a trigger for the backend
- t.units_per_em = units or 1000
- --
- local hdelta, vdelta = delta, delta
- -- unicoded unique descriptions shared cidinfo characters changed parameters indices
- for k,v in next, tfmtable do
- if type(v) == "table" then
- -- print(k)
- else
- t[k] = v
- end
- end
- local extend_factor = tfmtable.extend_factor or 0
- if extend_factor ~= 0 and extend_factor ~= 1 then
- hdelta = hdelta * extend_factor
- t.extend = extend_factor * 1000
- else
- t.extend = 1000
- end
- local slant_factor = tfmtable.slant_factor or 0
- if slant_factor ~= 0 then
- t.slant = slant_factor * 1000
- else
- t.slant = 0
- end
- -- status
- local isvirtual = tfmtable.type == "virtual" or tfmtable.virtualized
- local hasmath = (tfmtable.mathparameters ~= nil and next(tfmtable.mathparameters) ~= nil) or (tfmtable.MathConstants ~= nil and next(tfmtable.MathConstants) ~= nil)
- local nodemode = tfmtable.mode == "node"
- local hasquality = tfmtable.auto_expand or tfmtable.auto_protrude
- local hasitalic = tfmtable.has_italic
- local descriptions = tfmtable.descriptions or { }
- --
- if hasmath then
- t.has_math = true -- this will move to elsewhere
- end
- --
- t.parameters = { }
- t.characters = { }
- t.MathConstants = { }
- -- fast access
- t.unscaled = tfmtable -- the original unscaled one (temp)
- t.unicodes = tfmtable.unicodes
- t.indices = tfmtable.indices
- t.marks = tfmtable.marks
- -- this will move to some subtable so that it is copied at once
- t.goodies = tfmtable.goodies
- t.colorscheme = tfmtable.colorscheme
- t.postprocessors = tfmtable.postprocessors
- --
- -- t.embedding = tfmtable.embedding
- t.descriptions = descriptions
- if tfmtable.fonts then
- t.fonts = table.fastcopy(tfmtable.fonts) -- hm also at the end
- end
- local tp = t.parameters
- local mp = t.mathparameters
- local tfmp = tfmtable.parameters -- let's check for indexes
- --
- tp.slant = (tfmp.slant or tfmp[1] or 0)
- tp.space = (tfmp.space or tfmp[2] or 0)*hdelta
- tp.space_stretch = (tfmp.space_stretch or tfmp[3] or 0)*hdelta
- tp.space_shrink = (tfmp.space_shrink or tfmp[4] or 0)*hdelta
- tp.x_height = (tfmp.x_height or tfmp[5] or 0)*vdelta
- tp.quad = (tfmp.quad or tfmp[6] or 0)*hdelta
- tp.extra_space = (tfmp.extra_space or tfmp[7] or 0)*hdelta
- local protrusionfactor = (tp.quad ~= 0 and 1000/tp.quad) or 0
- local tc = t.characters
- local characters = tfmtable.characters
- local nameneeded = not tfmtable.shared.otfdata --hack
- local changed = tfmtable.changed or { } -- for base mode
- local ischanged = changed and next(changed)
- local indices = tfmtable.indices
- local luatex = tfmtable.luatex
- local tounicode = luatex and luatex.tounicode
- local defaultwidth = luatex and luatex.defaultwidth or 0
- local defaultheight = luatex and luatex.defaultheight or 0
- local defaultdepth = luatex and luatex.defaultdepth or 0
- -- experimental, sharing kerns (unscaled and scaled) saves memory
- -- local sharedkerns, basekerns = tfm.check_base_kerns(tfmtable)
- -- loop over descriptions (afm and otf have descriptions, tfm not)
- -- there is no need (yet) to assign a value to chr.tonunicode
- local scaledwidth = defaultwidth * hdelta
- local scaledheight = defaultheight * vdelta
- local scaleddepth = defaultdepth * vdelta
- local stackmath = tfmtable.ignore_stack_math ~= true
- local private = fonts.privateoffset
- local sharedkerns = { }
- for k,v in next, characters do
- local chr, description, index
- if ischanged then
- -- basemode hack
- local c = changed[k]
- if c then
- description = descriptions[c] or v
- v = characters[c] or v
- index = (indices and indices[c]) or c
- else
- description = descriptions[k] or v
- index = (indices and indices[k]) or k
- end
- else
- description = descriptions[k] or v
- index = (indices and indices[k]) or k
- end
- local width = description.width
- local height = description.height
- local depth = description.depth
- if width then width = hdelta*width else width = scaledwidth end
- if height then height = vdelta*height else height = scaledheight end
- -- if depth then depth = vdelta*depth else depth = scaleddepth end
- if depth and depth ~= 0 then
- depth = delta*depth
- if nameneeded then
- chr = {
- name = description.name,
- index = index,
- height = height,
- depth = depth,
- width = width,
- }
- else
- chr = {
- index = index,
- height = height,
- depth = depth,
- width = width,
- }
- end
- else
- -- this saves a little bit of memory time and memory, esp for big cjk fonts
- if nameneeded then
- chr = {
- name = description.name,
- index = index,
- height = height,
- width = width,
- }
- else
- chr = {
- index = index,
- height = height,
- width = width,
- }
- end
- end
- -- if trace_scaling then
- -- report_defining("t=%s, u=%s, i=%s, n=%s c=%s",k,chr.tounicode or "",index or 0,description.name or '-',description.class or '-')
- -- end
- if tounicode then
- local tu = tounicode[index] -- nb: index!
- if tu then
- chr.tounicode = tu
- end
- end
- if hasquality then
- -- we could move these calculations elsewhere (saves calculations)
- local ve = v.expansion_factor
- if ve then
- chr.expansion_factor = ve*1000 -- expansionfactor, hm, can happen elsewhere
- end
- local vl = v.left_protruding
- if vl then
- chr.left_protruding = protrusionfactor*width*vl
- end
- local vr = v.right_protruding
- if vr then
- chr.right_protruding = protrusionfactor*width*vr
- end
- end
- -- todo: hasitalic
- if hasitalic then
- local vi = description.italic or v.italic
- if vi and vi ~= 0 then
- chr.italic = vi*hdelta
- end
- end
- -- to be tested
- if hasmath then
- -- todo, just operate on descriptions.math
- local vn = v.next
- if vn then
- chr.next = vn
- --~ if v.vert_variants or v.horiz_variants then
- --~ report_defining("glyph 0x%05X has combination of next, vert_variants and horiz_variants",index)
- --~ end
- else
- local vv = v.vert_variants
- if vv then
- local t = { }
- for i=1,#vv do
- local vvi = vv[i]
- t[i] = {
- ["start"] = (vvi["start"] or 0)*vdelta,
- ["end"] = (vvi["end"] or 0)*vdelta,
- ["advance"] = (vvi["advance"] or 0)*vdelta,
- ["extender"] = vvi["extender"],
- ["glyph"] = vvi["glyph"],
- }
- end
- chr.vert_variants = t
- --~ local ic = v.vert_italic_correction
- --~ if ic then
- --~ chr.italic = ic * hdelta
- --~ print(format("0x%05X -> %s",k,chr.italic))
- --~ end
- else
- local hv = v.horiz_variants
- if hv then
- local t = { }
- for i=1,#hv do
- local hvi = hv[i]
- t[i] = {
- ["start"] = (hvi["start"] or 0)*hdelta,
- ["end"] = (hvi["end"] or 0)*hdelta,
- ["advance"] = (hvi["advance"] or 0)*hdelta,
- ["extender"] = hvi["extender"],
- ["glyph"] = hvi["glyph"],
- }
- end
- chr.horiz_variants = t
+local function read_from_tfm(specification)
+ local filename = specification.filename
+ local size = specification.size
+ if trace_defining then
+ report_defining("loading tfm file %s at size %s",filename,size)
+ end
+ local tfmdata = font.read_tfm(filename,size) -- not cached, fast enough
+ if tfmdata then
+ local features = specification.features and specification.features.normal or { }
+ local properties = tfmdata.properties or { }
+ local parameters = tfmdata.parameters or { }
+ local shared = tfmdata.shared or { }
+ properties.name = tfmdata.name
+ properties.fontname = tfmdata.fontname
+ properties.psname = tfmdata.psname
+ properties.filename = specification.filename
+ parameters.size = size
+ shared.rawdata = { }
+ shared.features = features
+ shared.processes = next(features) and tfm.setfeatures(tfmdata,features) or nil
+ --
+ tfmdata.properties = properties
+ tfmdata.parameters = parameters
+ tfmdata.shared = shared
+ --
+ if constructors.resolvevirtualtoo then
+ fonts.loggers.register(tfmdata,file.extname(filename),specification) -- strange, why here
+ local vfname = findbinfile(specification.name, 'ovf')
+ if vfname and vfname ~= "" then
+ local vfdata = font.read_vf(vfname,size) -- not cached, fast enough
+ if vfdata then
+ local chars = tfmdata.characters
+ for k,v in next, vfdata.characters do
+ chars[k].commands = v.commands
end
- end
- end
- local vt = description.top_accent
- if vt then
- chr.top_accent = vdelta*vt
- end
- if stackmath then
- local mk = v.mathkerns
- if mk then
- local kerns = { }
- local v = mk.top_right if v then local k = { } for i=1,#v do local vi = v[i]
- k[i] = { height = vdelta*vi.height, kern = vdelta*vi.kern }
- end kerns.top_right = k end
- local v = mk.top_left if v then local k = { } for i=1,#v do local vi = v[i]
- k[i] = { height = vdelta*vi.height, kern = vdelta*vi.kern }
- end kerns.top_left = k end
- local v = mk.bottom_left if v then local k = { } for i=1,#v do local vi = v[i]
- k[i] = { height = vdelta*vi.height, kern = vdelta*vi.kern }
- end kerns.bottom_left = k end
- local v = mk.bottom_right if v then local k = { } for i=1,#v do local vi = v[i]
- k[i] = { height = vdelta*vi.height, kern = vdelta*vi.kern }
- end kerns.bottom_right = k end
- chr.mathkern = kerns -- singular
+ properties.virtualized = true
+ tfmdata.fonts = vfdata.fonts
end
end
end
- if not nodemode then
- local vk = v.kerns
- if vk then
- --~ if sharedkerns then
- --~ local base = basekerns[vk] -- hashed by table id, not content
- --~ if not base then
- --~ base = {}
- --~ for k,v in next, vk do base[k] = v*hdelta end
- --~ basekerns[vk] = base
- --~ end
- --~ chr.kerns = base
- --~ else
- --~ local tt = {}
- --~ for k,v in next, vk do tt[k] = v*hdelta end
- --~ chr.kerns = tt
- --~ end
- local s = sharedkerns[vk]
- if not s then
- s = { }
- for k,v in next, vk do s[k] = v*hdelta end
- sharedkerns[vk] = s
- end
- chr.kerns = s
- end
- local vl = v.ligatures
- if vl then
- if true then
- chr.ligatures = vl -- shared
- else
- local tt = { }
- for i,l in next, vl do
- tt[i] = l
- end
- chr.ligatures = tt
- end
- end
+ --
+ if next(features) then
+ constructors.applymanipulators("tfm",tfmdata,specification.features.normal,trace_features,report_tfm)
end
- if isvirtual then
- local vc = v.commands
- if vc then
- -- we assume non scaled commands here
- -- tricky .. we need to scale pseudo math glyphs too
- -- which is why we deal with rules too
- local ok = false
- for i=1,#vc do
- local key = vc[i][1]
- if key == "right" or key == "down" then
- ok = true
- break
- end
- end
- if ok then
- local tt = { }
- for i=1,#vc do
- local ivc = vc[i]
- local key = ivc[1]
- if key == "right" then
- tt[i] = { key, ivc[2]*hdelta }
- elseif key == "down" then
- tt[i] = { key, ivc[2]*vdelta }
- elseif key == "rule" then
- tt[i] = { key, ivc[2]*vdelta, ivc[3]*hdelta }
- else -- not comment
- tt[i] = ivc -- shared since in cache and untouched
- end
- end
- chr.commands = tt
- else
- chr.commands = vc
- end
- chr.index = nil
+ if not features.encoding then
+ local encoding, filename = match(properties.filename,"^(.-)%-(.*)$") -- context: encoding-name.*
+ if filename and encoding and encodings.known[encoding] then
+ features.encoding = encoding
end
end
- tc[k] = chr
- end
- -- t.encodingbytes, t.filename, t.fullname, t.name: elsewhere
- t.size = scaledpoints
- t.factor = delta
- t.hfactor = hdelta
- t.vfactor = vdelta
- if t.fonts then
- t.fonts = table.fastcopy(t.fonts) -- maybe we virtualize more afterwards
- end
- if hasmath then
- -- mathematics.extras.copy(t) -- can be done elsewhere if needed
- local ma = tfm.mathactions
- for i=1,#ma do
- ma[i](t,tfmtable,delta,hdelta,vdelta) -- what delta?
- end
- end
- -- needed for \high cum suis
- local tpx = tp.x_height
- if hasmath then
- if not tp[13] then tp[13] = .86*tpx end -- mathsupdisplay
- if not tp[14] then tp[14] = .86*tpx end -- mathsupnormal
- if not tp[15] then tp[15] = .86*tpx end -- mathsupcramped
- if not tp[16] then tp[16] = .48*tpx end -- mathsubnormal
- if not tp[17] then tp[17] = .48*tpx end -- mathsubcombined
- if not tp[22] then tp[22] = 0 end -- mathaxisheight
- if t.MathConstants then t.MathConstants.AccentBaseHeight = nil end -- safeguard
- end
- t.tounicode = 1
- t.cidinfo = tfmtable.cidinfo
- -- we have t.name=metricfile and t.fullname=RealName and t.filename=diskfilename
- -- when collapsing fonts, luatex looks as both t.name and t.fullname as ttc files
- -- can have multiple subfonts
- if hasmath then
- if trace_defining then
- report_defining("math enabled for: name '%s', fullname: '%s', filename: '%s'",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename")
- end
- else
- if trace_defining then
- report_defining("math disabled for: name '%s', fullname: '%s', filename: '%s'",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename")
- end
- t.nomath, t.MathConstants = true, nil
+ --
+ return tfmdata
end
- if not t.psname then
- -- name used in pdf file as well as for selecting subfont in ttc/dfont
- t.psname = t.fontname or (t.fullname and fonts.names.cleanname(t.fullname))
- end
- if trace_defining then
- report_defining("used for accessing (sub)font: '%s'",t.psname or "nopsname")
- report_defining("used for subsetting: '%s'",t.fontname or "nofontname")
- end
- -- this will move up (side effect of merging split call)
- t.factor = delta
- t.ascender = delta*(tfmtable.ascender or 0)
- t.descender = delta*(tfmtable.descender or 0)
- t.shared = tfmtable.shared or { }
- t.unique = table.fastcopy(tfmtable.unique or {})
- tfm.cleanup(t)
- -- print(t.fontname,table.serialize(t.MathConstants))
- return t
-end
-
---[[ldx--
-<p>Analyzers run per script and/or language and are needed in order to
-process features right.</p>
---ldx]]--
-
-fonts.analyzers = fonts.analyzers or { }
-local analyzers = fonts.analyzers
-
-analyzers.aux = analyzers.aux or { }
-analyzers.methods = analyzers.methods or { }
-analyzers.initializers = analyzers.initializers or { }
-
--- todo: analyzers per script/lang, cross font, so we need an font id hash -> script
--- e.g. latin -> hyphenate, arab -> 1/2/3 analyze
-
--- an example analyzer (should move to font-ota.lua)
-
-local state = attributes.private('state')
-
-function analyzers.aux.setstate(head,font)
- local useunicodemarks = analyzers.useunicodemarks
- local tfmdata = fontdata[font]
- local characters = tfmdata.characters
- local descriptions = tfmdata.descriptions
- local first, last, current, n, done = nil, nil, head, 0, false -- maybe make n boolean
- while current do
- local id = current.id
- if id == glyph_code and current.font == font then
- local char = current.char
- local d = descriptions[char]
- if d then
- if d.class == "mark" or (useunicodemarks and categories[char] == "mn") then
- done = true
- set_attribute(current,state,5) -- mark
- elseif n == 0 then
- first, last, n = current, current, 1
- set_attribute(current,state,1) -- init
- else
- last, n = current, n+1
- set_attribute(current,state,2) -- medi
- end
- else -- finish
- if first and first == last then
- set_attribute(last,state,4) -- isol
- elseif last then
- set_attribute(last,state,3) -- fina
- end
- first, last, n = nil, nil, 0
- end
- elseif id == disc_code then
- -- always in the middle
- set_attribute(current,state,2) -- midi
- last = current
- else -- finish
- if first and first == last then
- set_attribute(last,state,4) -- isol
- elseif last then
- set_attribute(last,state,3) -- fina
- end
- first, last, n = nil, nil, 0
- end
- current = current.next
- end
- if first and first == last then
- set_attribute(last,state,4) -- isol
- elseif last then
- set_attribute(last,state,3) -- fina
- end
- return head, done
-end
-
-function tfm.replacements(tfm,value)
- -- tfm.characters[0x0022] = table.fastcopy(tfm.characters[0x201D])
- -- tfm.characters[0x0027] = table.fastcopy(tfm.characters[0x2019])
- -- tfm.characters[0x0060] = table.fastcopy(tfm.characters[0x2018])
- -- tfm.characters[0x0022] = tfm.characters[0x201D]
- tfm.characters[0x0027] = tfm.characters[0x2019]
- -- tfm.characters[0x0060] = tfm.characters[0x2018]
-end
-
--- checking
-
-function tfm.checkedfilename(metadata,whatever)
- local foundfilename = metadata.foundfilename
- if not foundfilename then
- local askedfilename = metadata.filename or ""
- if askedfilename ~= "" then
- askedfilename = resolvers.resolve(askedfilename) -- no shortcut
- foundfilename = findbinfile(askedfilename,"") or ""
- if foundfilename == "" then
- report_defining("source file '%s' is not found",askedfilename)
- foundfilename = findbinfile(file.basename(askedfilename),"") or ""
- if foundfilename ~= "" then
- report_defining("using source file '%s' (cache mismatch)",foundfilename)
- end
- end
- elseif whatever then
- report_defining("no source file for '%s'",whatever)
- foundfilename = ""
- end
- metadata.foundfilename = foundfilename
- -- report_defining("using source file '%s'",foundfilename)
- end
- return foundfilename
end
--- status info
-
-statistics.register("fonts load time", function()
- return statistics.elapsedseconds(fonts)
-end)
-
--- readers
-
-fonts.formats.tfm = "type1" -- we need to have at least a value here
-
-local function check_tfm(specification,fullname)
- -- ofm directive blocks local path search unless set; btw, in context we
- -- don't support ofm files anyway as this format is obsolete
- local foundname = findbinfile(fullname, 'tfm') or "" -- just to be sure
+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 "" -- bonus for usage outside context
+ foundname = findbinfile(fullname, 'ofm') or "" -- not needed in context
end
if foundname == "" then
foundname = fonts.names.getfilename(fullname,"tfm")
end
if foundname ~= "" then
- specification.filename, specification.format = foundname, "ofm"
+ specification.filename = foundname
+ specification.format = "ofm"
return read_from_tfm(specification)
+ elseif trace_defining then
+ report_defining("loading tfm with name %s fails",specification.name)
end
end
readers.check_tfm = check_tfm
function readers.tfm(specification)
- local fullname, tfmtable = specification.filename or "", nil
+ local fullname = specification.filename or ""
if fullname == "" then
local forced = specification.forced or ""
if forced ~= "" then
- tfmtable = check_tfm(specification,specification.name .. "." .. forced)
- end
- if not tfmtable then
- tfmtable = check_tfm(specification,specification.name)
+ fullname = specification.name .. "." .. forced
+ else
+ fullname = specification.name
end
- else
- tfmtable = check_tfm(specification,fullname)
end
- return tfmtable
+ return check_tfm(specification,fullname)
end
diff --git a/tex/context/base/font-vf.lua b/tex/context/base/font-vf.lua
index 455646a22..8eab88b40 100644
--- a/tex/context/base/font-vf.lua
+++ b/tex/context/base/font-vf.lua
@@ -14,27 +14,79 @@ changes. This will change.</p>
local next = next
local fastcopy = table.fastcopy
-local allocate = utilities.storage.allocate
+local allocate = utilities.storage.allocate
+
+local fonts = fonts
+local constructors = fonts.constructors
+local vf = { }
+fonts.handlers.vf = vf
+
+-- general code
+
+function vf.find(name)
+ name = file.removesuffix(file.basename(name))
+ if constructors.resolvevirtualtoo then
+ local format = fonts.loggers.format(name)
+ if format == 'tfm' or format == 'ofm' then
+ if trace_defining then
+ report_defining("locating vf for %s",name)
+ end
+ return findbinfile(name,"ovf")
+ else
+ if trace_defining then
+ report_defining("vf for %s is already taken care of",name)
+ end
+ return nil -- ""
+ end
+ else
+ if trace_defining then
+ report_defining("locating vf for %s",name)
+ end
+ return findbinfile(name,"ovf")
+ end
+end
-local fonts = fonts
-local vf = fonts.vf
-local tfm = fonts.tfm
+--[[ldx--
+<p>We overload the <l n='vf'/> reader.</p>
+--ldx]]--
+
+callbacks.register('find_vf_file', vf.find, "locating virtual fonts, insofar needed") -- not that relevant any more
-fonts.definers = fonts.definers or { }
-local definers = fonts.definers
+-- specific code (will move to other module)
-definers.methods = definers.methods or { }
-local methods = definers.methods
+local definers = fonts.definers
+local methods = definers.methods
-methods.variants = allocate()
-local variants = methods.variants
+local variants = allocate()
+local combinations = { }
+local combiner = { }
+local whatever = allocate() -- can be used to store data
+local predefined = allocate() -- can be used to store data
+local helpers = allocate() -- can be used to store data
-vf.combinations = vf.combinations or { }
-vf.aux = vf.aux or { }
-vf.aux.combine = vf.aux.combine or { }
-local combine = vf.aux.combine
+methods.variants = variants -- todo .. wrong namespace
+vf.combinations = combinations
+vf.combiner = combiner
+vf.whatever = whatever
+vf.helpers = helpers
+vf.predefined = predefined
-local chardata = characters.data
+setmetatable(whatever, { __index = function(t,k) local v = { } t[k] = v return v end })
+
+predefined.dummy = { "comment" }
+predefined.push = { "push" }
+predefined.pop = { "pop" }
+
+local function checkparameters(g,f)
+ if f and g and not g.parameters and #g.fonts > 0 then
+ local p = { }
+ for k,v in next, f.parameters do
+ p[k] = v
+ end
+ g.parameters = p
+ setmetatable(p, getmetatable(f.parameters))
+ end
+end
function methods.install(tag, rules)
vf.combinations[tag] = rules
@@ -44,7 +96,7 @@ function methods.install(tag, rules)
end
local function combine_load(g,name)
- return tfm.readanddefine(name or g.specification.name,g.specification.size)
+ return constructors.readanddefine(name or g.specification.name,g.specification.size)
end
local function combine_assign(g, name, from, to, start, force)
@@ -66,26 +118,20 @@ local function combine_assign(g, name, from, to, start, force)
end
start = start + 1
end
- if not g.parameters and #g.fonts > 0 then -- share this code !
- g.parameters = fastcopy(f.parameters)
- g.italicangle = f.italicangle
- g.ascender = f.ascender
- g.descender = f.descender
- g.factor = f.factor -- brrr
- end
+ checkparameters(g,f)
end
end
local function combine_process(g,list)
if list then
for _,v in next, list do
- (combine.commands[v[1]] or nop)(g,v)
+ (combiner.commands[v[1]] or nop)(g,v)
end
end
end
local function combine_names(g,name,force)
- local f, id = tfm.readanddefine(name,g.specification.size)
+ local f, id = constructors.readanddefine(name,g.specification.size)
if f and id then
local fc, gc = f.characters, g.characters
local fd, gd = f.descriptions, g.descriptions
@@ -98,13 +144,7 @@ local function combine_names(g,name,force)
gd[i] = fd[i]
end
end
- if not g.parameters and #g.fonts > 0 then -- share this code !
- g.parameters = fastcopy(f.parameters)
- g.italicangle = f.italicangle
- g.ascender = f.ascender
- g.descender = f.descender
- g.factor = f.factor -- brrr
- end
+ checkparameters(g,f)
end
end
@@ -124,111 +164,39 @@ local combine_feature = function(g,v)
end
end
---~ combine.load = combine_load
---~ combine.assign = combine_assign
---~ combine.process = combine_process
---~ combine.names = combine_names
---~ combine.feature = combine_feature
+--~ combiner.load = combine_load
+--~ combiner.assign = combine_assign
+--~ combiner.process = combine_process
+--~ combiner.names = combine_names
+--~ combiner.feature = combine_feature
-combine.commands = allocate {
- ["initialize"] = function(g,v) combine_assign (g,g.name) end,
- ["include-method"] = function(g,v) combine_process (g,vf.combinations[v[2]]) end, -- name
+combiner.commands = allocate {
+ ["initialize"] = function(g,v) combine_assign (g,g.properties.name) end,
+ ["include-method"] = function(g,v) combine_process (g,combinations[v[2]]) end, -- name
-- ["copy-parameters"] = function(g,v) combine_parameters(g,v[2]) end, -- name
["copy-range"] = function(g,v) combine_assign (g,v[2],v[3],v[4],v[5],true) end, -- name, from-start, from-end, to-start
["copy-char"] = function(g,v) combine_assign (g,v[2],v[3],v[3],v[4],true) end, -- name, from, to
["fallback-range"] = function(g,v) combine_assign (g,v[2],v[3],v[4],v[5],false) end, -- name, from-start, from-end, to-start
["fallback-char"] = function(g,v) combine_assign (g,v[2],v[3],v[3],v[4],false) end, -- name, from, to
["copy-names"] = function(g,v) combine_names (g,v[2],true) end,
- ["fallback_names"] = function(g,v) combine_names (g,v[2],false) end,
+ ["fallback-names"] = function(g,v) combine_names (g,v[2],false) end,
["feature"] = combine_feature,
}
function vf.combine(specification,tag)
local g = {
name = specification.name,
- -- type = 'virtual',
- virtualized = true,
- fonts = { },
- characters = { },
- descriptions = { },
+ properties = {
+ virtualized = true,
+ },
+ fonts = {
+ },
+ characters = {
+ },
+ descriptions = {
+ },
specification = fastcopy(specification),
}
- combine_process(g,vf.combinations[tag])
+ combine_process(g,combinations[tag])
return g
end
-
--- simple example with features
-
-methods.install(
- "ligatures", {
- { "feature", "liga" } ,
- { "feature", "dlig" } ,
- { "initialize" } ,
- }
-)
-
---~ methods.install (
---~ "ligatures-x", {
---~ { "feature", "liga" } ,
---~ { "feature", "dlig" } ,
---~ { "initialize" } ,
---~ { "lineheight" }
---~ }
---~ )
-
---~ methods.install(
---~ "lmsymbol10", {
---~ { "fallback_names", "lmsy10.afm" } ,
---~ { "fallback_names", "msam10.afm" } ,
---~ { "fallback_names", "msbm10.afm" }
---~ }
---~ )
---~ \font\TestFont=dummy@lmsymbol10 at 24pt
-
--- docu case
-
---~ methods.install(
---~ "weird", {
---~ { "copy-range", "lmroman10-regular" } ,
---~ { "copy-char", "lmroman10-regular", 65, 66 } ,
---~ { "copy-range", "lmsans10-regular", 0x0100, 0x01FF } ,
---~ { "copy-range", "lmtypewriter10-regular", 0x0200, 0xFF00 } ,
---~ { "fallback-range", "lmtypewriter10-regular", 0x0000, 0x0200 }
---~ }
---~ )
-
--- demo case -> move to module
-
--- todo: interface tables in back-ini
-
-variants["demo-1"] = function(specification)
- local name = specification.name -- symbolic name
- local size = specification.size -- given size
- local f, id = tfm.readanddefine('lmroman10-regular',size)
- if f and id then
- local capscale, digscale = 0.85, 0.75
- -- f.name, f.type = name, 'virtual'
- f.name, f.virtualized = name, true
- f.fonts = {
- { id = id },
- { name = 'lmsans10-regular' , size = size*capscale }, -- forced extra name
- { name = 'lmtypewriter10-regular', size = size*digscale } -- forced extra name
- }
- local characters, descriptions = f.characters, f.descriptions
- local vfspecials = backends.tables.vfspecials
- local red, green, blue, black = vfspecials.red, vfspecials.green, vfspecials.blue, vfspecials.black
- for u,v in next, characters do
- local category = chardata[u].category
- if category == 'lu' then
- v.width = capscale*v.width
- v.commands = { red, { 'slot', 2, u }, black }
- elseif category == 'nd' then
- v.width = digscale*v.width
- v.commands = { blue, { 'slot', 3, u }, black }
- else
- v.commands = { green, { 'slot', 1, u }, black }
- end
- end
- end
- return f
-end
diff --git a/tex/context/base/font-xtx.lua b/tex/context/base/font-xtx.lua
deleted file mode 100644
index 505e08583..000000000
--- a/tex/context/base/font-xtx.lua
+++ /dev/null
@@ -1,100 +0,0 @@
-if not modules then modules = { } end modules ['font-xtx'] = {
- 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 texsprint, count = tex.sprint, tex.count
-local format, concat, gmatch, match, find, lower = string.format, table.concat, string.gmatch, string.match, string.find, string.lower
-local tostring, next = tostring, next
-local lpegmatch = lpeg.match
-
-local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
-
---[[ldx--
-<p>Choosing a font by name and specififying its size is only part of the
-game. In order to prevent complex commands, <l n='xetex'/> introduced
-a method to pass feature information as part of the font name. At the
-risk of introducing nasty parsing and compatinility problems, this
-syntax was expanded over time.</p>
-
-<p>For the sake of users who have defined fonts using that syntax, we
-will support it, but we will provide additional methods as well.
-Normally users will not use this direct way, but use a more abstract
-interface.</p>
-
-<p>The next one is the official one. However, in the plain
-variant we need to support the crappy [] specification as
-well and that does not work too well with the general design
-of the specifier.</p>
---ldx]]--
-
-local fonts = fonts
-local definers = fonts.definers
-local specifiers = definers.specifiers
-local normalize_meanings = fonts.otf.meanings.normalize
-
-local list = { }
-
-specifiers.colonizedpreference = "file"
-
-local function issome () list.lookup = specifiers.colonizedpreference end
-local function isfile () list.lookup = 'file' end
-local function isname () list.lookup = 'name' end
-local function thename(s) list.name = s end
-local function issub (v) list.sub = v end
-local function iscrap (s) list.crap = string.lower(s) end
-local function istrue (s) list[s] = 'yes' end
-local function isfalse(s) list[s] = 'no' end
-local function iskey (k,v) list[k] = v end
-
-local function istrue (s) list[s] = true end
-local function isfalse(s) list[s] = false end
-
-local P, S, R, C = lpeg.P, lpeg.S, lpeg.R, lpeg.C
-
-local spaces = P(" ")^0
-local namespec = (1-S("/:("))^0 -- was: (1-S("/: ("))^0
-local crapspec = spaces * P("/") * (((1-P(":"))^0)/iscrap) * spaces
-local filename = (P("file:")/isfile * (namespec/thename)) + (P("[") * P(true)/isname * (((1-P("]"))^0)/thename) * P("]"))
-local fontname = (P("name:")/isname * (namespec/thename)) + P(true)/issome * (namespec/thename)
-local sometext = (R("az","AZ","09") + S("+-."))^1
-local truevalue = P("+") * spaces * (sometext/istrue)
-local falsevalue = P("-") * spaces * (sometext/isfalse)
-local keyvalue = (C(sometext) * spaces * P("=") * spaces * C(sometext))/iskey
-local somevalue = sometext/istrue
-local subvalue = P("(") * (C(P(1-S("()"))^1)/issub) * P(")") -- for Kim
-local option = spaces * (keyvalue + falsevalue + truevalue + somevalue) * spaces
-local options = P(":") * spaces * (P(";")^0 * option)^0
-local pattern = (filename + fontname) * subvalue^0 * crapspec^0 * options^0
-
-local function colonized(specification) -- xetex mode
- list = { }
- lpegmatch(pattern,specification.specification)
- -- for k, v in next, list do
- -- list[k] = is_boolean(v)
- -- if type(list[a]) == "nil" then
- -- list[k] = v
- -- end
- -- end
- list.crap = nil -- style not supported, maybe some day
- if list.name then
- specification.name = list.name
- list.name = nil
- end
- if list.lookup then
- specification.lookup = list.lookup
- list.lookup = nil
- end
- if list.sub then
- specification.sub = list.sub
- list.sub = nil
- end
- -- specification.features.normal = list
- specification.features.normal = normalize_meanings(list)
- return specification
-end
-
-definers.registersplit(":",colonized,"cryptic")
diff --git a/tex/context/base/grph-inc.lua b/tex/context/base/grph-inc.lua
index 83b395f2e..bb29e6142 100644
--- a/tex/context/base/grph-inc.lua
+++ b/tex/context/base/grph-inc.lua
@@ -228,7 +228,6 @@ function figures.setpaths(locationset,pathlist)
last_locationset = locationset
end
if h[iv["global"]] then
- -- for s in gmatch(pathlist,",* *([^,]+)") do
local list = settings_to_array(pathlist)
for i=1,#list do
local s = list[i]
diff --git a/tex/context/base/java-imp-ans.mkiv b/tex/context/base/java-imp-ans.mkiv
deleted file mode 100644
index cc63266e2..000000000
--- a/tex/context/base/java-imp-ans.mkiv
+++ /dev/null
@@ -1,33 +0,0 @@
-%D \module
-%D [ file=java-ans,
-%D version=1998.06.01,
-%D title=\CONTEXT\ JavaScript Macros,
-%D subtitle=Answer Analization,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-% event.target.display = display.hidden
-
-\startJSpreamble{Do_Check_Answer} used later
-
- function Do_Check_Answer(field,value) {
- if (event.value.toLowerCase() == value.toLowerCase()) {
- event.target.hidden = true ;
- }
- return("\040") // funny, "" does not work
- }
-
-\stopJSpreamble
-
-% needs to be done better in mkiv:
-
-\startJScode{Check_Answer} uses {Do_Check_Answer}
- event.value = Do_Check_Answer(JS_S_1, JS_S_2) ;
-\stopJScode
-
-\endinput
diff --git a/tex/context/base/java-imp-fld.mkiv b/tex/context/base/java-imp-fld.mkiv
index c0c229aba..2186368bb 100644
--- a/tex/context/base/java-imp-fld.mkiv
+++ b/tex/context/base/java-imp-fld.mkiv
@@ -25,6 +25,9 @@
%D
%D Probably a \UNICODE\ issue. Beware, in \MKIV\ we have a
%D different escaping of \type {\\}.
+%D
+%D Watch out: cf. the latest pdf specification we've changed
+%D On into Yes.
\startluasetups javascript:pdfencoding
local verbatim = context.verbatim
@@ -161,7 +164,7 @@ function Do_Vide_Field(Name, Closable) {
v.hidden = false ;
if (Closable) {
v.readonly = false ;
- v.value = "On" ;
+ v.value = "Yes" ;
}
this.dirty = false ;
}
@@ -203,7 +206,7 @@ function Toggle_Hide(Name) {
function Field_On(Name) {
v = this.getField(Name) ;
if (v) {
- v.value = "On" ;
+ v.value = "Yes" ;
this.dirty = false ;
}
}
@@ -219,10 +222,10 @@ function Field_Off(Name) {
function Toggle_Value(Name) {
var v = this.getField(Name) ;
if (v) {
- if (v.value == "On") {
+ if (v.value == "Yes") {
v.value = "Off" ;
} else {
- v.value = "On" ;
+ v.value = "Yes" ;
}
}
this.dirty = false ;
@@ -241,7 +244,7 @@ function Flip_Fields(Name) {
v = this.getField(Names[i]) ;
if (v) {
v.hidden = !v.hidden ;
- v.value = "On" ;
+ v.value = "Yes" ;
}
}
}
@@ -282,7 +285,7 @@ function Set_Fields(FieldSet) {
if (!v) {
break ;
} else {
- v.value = "On" ;
+ v.value = "Yes" ;
}
i++ ;
}
@@ -292,7 +295,7 @@ function Set_Field(FieldSet, FieldName) {
Reset_Fields(FieldSet) ;
v = this.getField(FieldSet+":"+FieldName) ;
if (v) {
- v.value = "On" ;
+ v.value = "Yes" ;
}
}
@@ -309,7 +312,7 @@ function Walk_Field(FieldSet) {
while (true) {
v = this.getField(FieldSet+":"+i) ;
if (v) {
- if (v.value=="On") {
+ if (v.value=="Yes") {
v.value = "Off" ;
var ii = i ;
ii++ ;
@@ -318,7 +321,7 @@ function Walk_Field(FieldSet) {
v = this.getField(FieldSet+":"+1) ;
}
if (v) {
- v.value = "On" ;
+ v.value = "Yes" ;
}
break ;
}
@@ -351,7 +354,7 @@ function Do_Next_Auto_Walk_Field(FieldSet) {
if (fieldset) {
var v = this.getField(FieldSet + ":" + fieldset.number) ;
if (v) {
- if (v.value == "On") {
+ if (v.value == "Yes") {
v.value = "Off" ;
}
}
@@ -362,7 +365,7 @@ function Do_Next_Auto_Walk_Field(FieldSet) {
v = this.getField(FieldSet + ":" + fieldset.number) ;
}
if (v) {
- v.value = "On" ;
+ v.value = "Yes" ;
}
}
}
@@ -444,14 +447,14 @@ function Previous_Walk_Field(FieldSet) {
if (fieldset.number>0) {
var v = this.getField(FieldSet + ":" + fieldset.number) ;
if (v) {
- if (v.value == "On") {
+ if (v.value == "Yes") {
v.value = "Off" ;
}
}
fieldset.number-- ;
v = this.getField(FieldSet + ":" + fieldset.number) ;
if (v) {
- v.value = "On" ;
+ v.value = "Yes" ;
}
}
}
@@ -468,14 +471,14 @@ function Next_Walk_Field(FieldSet) {
if (v) {
var v = this.getField(FieldSet + ":" + fieldset.number) ;
if (v) {
- if (v.value == "On") {
+ if (v.value == "Yes") {
v.value = "Off" ;
}
}
fieldset.number++ ;
v = this.getField(FieldSet + ":" + fieldset.number) ;
if (v) {
- v.value = "On" ;
+ v.value = "Yes" ;
}
}
}
diff --git a/tex/context/base/java-ini.lua b/tex/context/base/java-ini.lua
index 7872031a8..b3b066678 100644
--- a/tex/context/base/java-ini.lua
+++ b/tex/context/base/java-ini.lua
@@ -87,7 +87,7 @@ function javascripts.setpreamble(name,script) -- now later
end
end
-function javascripts.addtopreamble(name,script) -- now later
+function javascripts.addtopreamble(name,script)
if name and name ~= "" then
local p = preambled[name]
if p then
diff --git a/tex/context/base/l-dimen.lua b/tex/context/base/l-dimen.lua
index 1c557bc49..f8a999cc9 100644
--- a/tex/context/base/l-dimen.lua
+++ b/tex/context/base/l-dimen.lua
@@ -324,25 +324,9 @@ is loaded, the relevant tables that hold the functions needed may not
yet be available.</p>
--ldx]]--
-function dimensions.texify() -- todo: %
- local fti, fc = fonts and fonts.identifiers, font and font.current
- if fti and fc then
- dimenfactors["ex"] = function() return fti[fc()].ex_height end
- dimenfactors["em"] = function() return fti[fc()].quad end
- -- dimenfactors["%"] = function() return tex.dimen.hsize/100 end
- else
- dimenfactors["ex"] = 1/65536* 4 -- 4pt
- dimenfactors["em"] = 1/65536*10 -- 10pt
- -- dimenfactors["%"] = 1/65536* 4 -- 400pt/100
- end
-end
-
---[[ldx--
-<p>In order to set the defaults we call this function now. At some point
-the macro package needs to make sure the function is called again.</p>
---ldx]]--
-
-dimensions.texify()
+ dimenfactors["ex"] = 4 * 1/65536 -- 4pt
+ dimenfactors["em"] = 10 * 1/65536 -- 10pt
+-- dimenfactors["%"] = 4 * 1/65536 -- 400pt/100
--[[ldx--
<p>The previous code is rather efficient (also thanks to <l n='lpeg'/>) but we
diff --git a/tex/context/base/l-lpeg.lua b/tex/context/base/l-lpeg.lua
index b20bc8853..ce0cc67ef 100644
--- a/tex/context/base/l-lpeg.lua
+++ b/tex/context/base/l-lpeg.lua
@@ -537,3 +537,5 @@ end
function lpeg.is_lpeg(p)
return p and lpegtype(p) == "pattern"
end
+
+--~ Cf(Ct("") * (Cg(C(...) * "=" * Cs(...)))^0, rawset)
diff --git a/tex/context/base/l-table.lua b/tex/context/base/l-table.lua
index 0189c887c..727d80df7 100644
--- a/tex/context/base/l-table.lua
+++ b/tex/context/base/l-table.lua
@@ -93,24 +93,24 @@ local function compare(a,b)
end
local function sortedkeys(tab)
- local srt, kind, s = { }, 0, 0 -- 0=unknown 1=string, 2=number 3=mixed
+ local srt, category, s = { }, 0, 0 -- 0=unknown 1=string, 2=number 3=mixed
for key,_ in next, tab do
s = s + 1
srt[s] = key
- if kind == 3 then
+ if category == 3 then
-- no further check
else
local tkey = type(key)
if tkey == "string" then
- kind = (kind == 2 and 3) or 1
+ category = (category == 2 and 3) or 1
elseif tkey == "number" then
- kind = (kind == 1 and 3) or 2
+ category = (category == 1 and 3) or 2
else
- kind = 3
+ category = 3
end
end
end
- if kind == 0 or kind == 3 then
+ if category == 0 or category == 3 then
sort(srt,compare)
else
sort(srt)
@@ -276,6 +276,13 @@ end
table.fastcopy = fastcopy
table.copy = copy
+function table.derive(parent)
+ local child = { }
+ if parent then
+ setmetatable(child,{ __index = parent })
+ end
+ return child
+end
function table.tohash(t,value)
local h = { }
diff --git a/tex/context/base/lang-txt.lua b/tex/context/base/lang-txt.lua
index 8b245ff12..3ba2d478c 100644
--- a/tex/context/base/lang-txt.lua
+++ b/tex/context/base/lang-txt.lua
@@ -27,7 +27,7 @@ if not modules then modules = { } end modules ['lang-txt'] = {
-- fi Finish ...
-- fr French Daniel Flipo, Arthur Reutenauer
-- gr Greek Apostolos Syropoulos, Thomas Schmitz
--- hr Croatian Željko Vrba, Richard Gabriel
+-- hr Croatian Željko Vrba, Richard Gabriel, Vedran Miletić
-- hu Hungarian ...
-- it Italian Giuseppe Bilotta, Luigi Scarso
-- ja Japanese Richard Gabriel
@@ -71,30 +71,35 @@ data.labels={
arccos={
labels={
en="arccos",
+ hr="arc\\sixperemspace cos",
pl="arc\\sixperemspace cos",
},
},
arcctg={
labels={
en="arccot",
+ hr="arc\\sixperemspace ctg",
pl="arc\\sixperemspace ctg",
},
},
arcsin={
labels={
en="arcsin",
+ hr="arc\\sixperemspace sin",
pl="arc\\sixperemspace sin",
},
},
arctan={
labels={
en="arctan",
+ hr="arc\\sixperemspace tg",
pl="arc\\sixperemspace tg",
},
},
arctg={
labels={
en="arctan",
+ hr="arc\\sixperemspace tg",
pl="arc\\sixperemspace tg",
},
},
@@ -116,6 +121,7 @@ data.labels={
cot={
labels={
en="cot",
+ hr="ctg",
pl="ctg",
},
},
@@ -132,6 +138,7 @@ data.labels={
ctg={
labels={
en="cot",
+ hr="ctg",
pl="ctg",
},
},
@@ -158,6 +165,7 @@ data.labels={
gcd={
labels={
en="gcd",
+ hr="nzd",
nl="ggd",
},
},
@@ -184,6 +192,7 @@ data.labels={
lcm={
labels={
en="lcm",
+ hr="nzv",
nl="kgv",
},
},
@@ -265,6 +274,7 @@ data.labels={
tan={
labels={
en="tan",
+ hr="tg",
pl="tg",
},
},
@@ -276,6 +286,7 @@ data.labels={
tg={
labels={
en="tan",
+ hr="tg",
pl="tg",
},
},
@@ -293,7 +304,7 @@ data.labels={
fi="",
fr="",
gr="",
- hr="",
+ hr="i",
hu="",
it="",
la="",
@@ -403,7 +414,7 @@ data.labels={
fi="",
fr="",
gr="",
- hr="",
+ hr="tra",
hu="",
it="",
la="",
@@ -510,7 +521,7 @@ data.labels={
fi="",
fr="",
gr="",
- hr="",
+ hr="kol",
hu="",
it="",
la="",
@@ -550,7 +561,7 @@ data.labels={
hu=",. fejezet:",
it="",
ja={"第","章"},
- kr={"제", "장"},
+ kr={"제","장"},
la="",
lt="",
nb="",
@@ -581,7 +592,7 @@ data.labels={
fi="",
fr="",
gr="",
- hr="",
+ hr=" (nastavak)",
hu="",
it="",
la="",
@@ -653,7 +664,7 @@ data.labels={
fi="",
fr="",
gr="",
- hr="",
+ hr="pro",
hu="",
it="",
la="",
@@ -725,7 +736,7 @@ data.labels={
fi="",
fr="",
gr="",
- hr="",
+ hr="velj",
hu="",
it="",
la="",
@@ -1013,7 +1024,7 @@ data.labels={
fi="",
fr="",
gr="",
- hr="",
+ hr="sij",
hu="",
it="",
la="",
@@ -1086,7 +1097,7 @@ data.labels={
fi="",
fr="",
gr="",
- hr="",
+ hr="srp",
hu="",
it="",
la="",
@@ -1158,7 +1169,7 @@ data.labels={
fi="",
fr="",
gr="",
- hr="",
+ hr="lip",
hu="",
it="",
la="",
@@ -1303,7 +1314,7 @@ data.labels={
fi="",
fr="",
gr="",
- hr="",
+ hr="ožu",
hu="",
it="",
la="",
@@ -1376,7 +1387,7 @@ data.labels={
fi="",
fr="",
gr="",
- hr="",
+ hr="svi",
hu="",
it="",
la="",
@@ -1485,7 +1496,7 @@ data.labels={
fi="",
fr="",
gr="",
- hr="",
+ hr="stu",
hu="",
it="",
la="",
@@ -1556,7 +1567,7 @@ data.labels={
fi="",
fr="",
gr="",
- hr="",
+ hr="lis",
hu="",
it="",
la="",
@@ -1810,7 +1821,7 @@ data.labels={
fi="",
fr="",
gr="",
- hr="",
+ hr="ruj",
hu="",
it="",
la="",
@@ -2365,7 +2376,7 @@ data.labels={
fi="Vertauskuva",
fr="Logos",
gr="Λογότυπα",
- hr="Znakovi",
+ hr="Logotipi",
hu="Fejlécek",
it="Logotipi",
ja="理性",
diff --git a/tex/context/base/lpdf-ano.lua b/tex/context/base/lpdf-ano.lua
index 60711044e..9f452c34d 100644
--- a/tex/context/base/lpdf-ano.lua
+++ b/tex/context/base/lpdf-ano.lua
@@ -70,6 +70,8 @@ local pdf_t = pdfconstant("T")
local pdf_fit = pdfconstant("Fit")
local pdf_named = pdfconstant("Named")
+-- todo: 3dview
+
local pdf_border = pdfarray { 0, 0, 0 }
local getinnermethod = references.getinnermethod
@@ -130,19 +132,13 @@ local function link(url,filename,destination,page,actions)
NewWindow = (actions.newwindow and true) or nil,
}
elseif destination and destination ~= "" then
- local p = references.checkedpage(actions.n,page)
return pdfdictionary { -- can be cached
S = pdf_goto,
D = destination,
}
- elseif page and page ~= "" then
- local p = references.checkedpage(actions.n,page)
+ else
+ local p = tonumber(page)
if p and p > 0 then
- --~ return gotopagedestination(p)
- --~ return pdfdictionary { -- can be cached
- --~ S = pdf_goto,
- --~ D = pagedestination(p),
- --~ }
return pdfdictionary { -- can be cached
S = pdf_goto,
D = pdfarray {
@@ -151,7 +147,7 @@ local function link(url,filename,destination,page,actions)
}
}
else
- report_reference("invalid page reference: %s",page or "?")
+ report_reference("invalid page reference: %s",tostring(page))
end
end
return false
@@ -302,9 +298,9 @@ local lln = latelua_node() if node.has_field(lln,'string') then
directives.register("refences.sharelinks", function(v)
if v then
- backends.nodeinjections.reference, backends.codeinjections.finishreference = use_shared_annotations()
+ nodeinjections.reference, codeinjections.finishreference = use_shared_annotations()
else
- backends.nodeinjections.reference, backends.codeinjections.finishreference = use_normal_annotations()
+ nodeinjections.reference, codeinjections.finishreference = use_normal_annotations()
end
end)
@@ -409,26 +405,32 @@ function specials.internal(var,actions) -- better resolve in strc-ref
end
end
+-- realpage already resolved
+
specials.i = specials.internal
local pages = references.pages
-function specials.page(var,actions) -- better resolve in strc-ref
+function specials.page(var,actions)
local file = var.f
---~ table.print(var)
if file then
file = references.checkedfile(file)
return link(nil,file,nil,var.operation,actions)
else
- local p = references.pages[var.operation]
- if type(p) == "function" then -- double
- p = p()
+ local p = var.r
+ if not p then -- todo: call special from reference code
+ p = pages[var.operation]
+ if type(p) == "function" then -- double
+ p = p()
+ else
+ p = tonumber(references.realpageofpage(tonumber(o)))
+ end
end
return link(nil,nil,nil,p or var.operation,actions)
end
end
-function specials.realpage(var,actions) -- better resolve in strc-ref
+function specials.realpage(var,actions)
local file = var.f
if file then
file = references.checkedfile(file)
@@ -439,15 +441,16 @@ function specials.realpage(var,actions) -- better resolve in strc-ref
end
function specials.userpage(var,actions)
- local p = references.realpageofpage(tonumber(var.operation or 0))
- if p then
- local file = var.f
- if file then
- -- file = references.checkedfile(file)
- -- return link(nil,file,nil,p,actions)
- else
- return link(nil,nil,nil,p,actions)
+ local file = var.f
+ if file then
+ file = references.checkedfile(file)
+ return link(nil,file,nil,var.operation,actions)
+ else
+ local p = var.r
+ if not p then -- todo: call special from reference code
+ p = tonumber(references.realpageofpage(var.operation))
end
+ return link(nil,nil,nil,p,actions)
end
end
diff --git a/tex/context/base/lpdf-col.lua b/tex/context/base/lpdf-col.lua
index a8e35dc74..dc40e555c 100644
--- a/tex/context/base/lpdf-col.lua
+++ b/tex/context/base/lpdf-col.lua
@@ -100,7 +100,28 @@ function lpdf.colorvalue(model,ca,default)
end
end
-function lpdf.fdfcolor(model,ca,default)
+--~ function lpdf.fdfcolor(model,ca,default)
+--~ local cv = colorsvalue(ca)
+--~ if cv then
+--~ if model == 1 then
+--~ model = cv[1]
+--~ end
+--~ model = forcedmodel(model)
+--~ if model == 2 then
+--~ return format("[%s]",cv[2])
+--~ elseif model == 3 then
+--~ return format("[%s %s %s]",cv[3],cv[4],cv[5])
+--~ elseif model == 4 then
+--~ return format("[%s %s %s %s]",cv[6],cv[7],cv[8],cv[9])
+--~ elseif model == 4 then
+--~ return format("[%s]",cv[13])
+--~ end
+--~ else
+--~ return format("[%s]",default or 0)
+--~ end
+--~ end
+
+function lpdf.colorvalues(model,ca,default)
local cv = colorsvalue(ca)
if cv then
if model == 1 then
@@ -108,16 +129,25 @@ function lpdf.fdfcolor(model,ca,default)
end
model = forcedmodel(model)
if model == 2 then
- return format("[%s]",cv[2])
+ return cv[2]
elseif model == 3 then
- return format("[%s %s %s]",cv[3],cv[4],cv[5])
+ return cv[3], cv[4], cv[5]
elseif model == 4 then
- return format("[%s %s %s %s]",cv[6],cv[7],cv[8],cv[9])
+ return cv[6], cv[7], cv[8], cv[9]
elseif model == 4 then
- return format("[%s]",cv[13])
+ return cv[13]
end
else
- return format("[%s]",default or 0)
+ return default or 0
+ end
+end
+
+function lpdf.transparencyvalue(ta,default)
+ local tv = transparenciesvalue(ta)
+ if tv then
+ return tv[2]
+ else
+ return default or 1
end
end
diff --git a/tex/context/base/lpdf-fld.lua b/tex/context/base/lpdf-fld.lua
index f59ef2d3e..12f8a9f46 100644
--- a/tex/context/base/lpdf-fld.lua
+++ b/tex/context/base/lpdf-fld.lua
@@ -6,15 +6,25 @@ if not modules then modules = { } end modules ['lpdf-fld'] = {
license = "see context related readme files"
}
--- cleaned up, e.g. no longer older viewers
--- always kids so no longer explicit main / clone / copy
--- some optimizations removed (will come bakc if needed)
+-- 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 their appearences
+-- need to be synchronized in the case of children but e.g. acrobat
+-- 10 does not retain the state and forces a check symbol. If you
+-- make a file in acrobat then it has MK entries that seem to overload
+-- the already present appearance streams (they're probably only meant for
+-- printing) as it looks like the viewer has some fallback on (auto
+-- generated) MK behaviour built in. So ... hard to test. Unfortunately
+-- not even the default appearance is generated. This will probably be
+-- solved at some point.
local gmatch, lower, format = string.gmatch, string.lower, string.format
local lpegmatch = lpeg.match
+local utfchar = utf.char
local bpfactor, todimen = number.dimenfactors.bp, string.todimen
-local trace_fields = false trackers.register("widgets.fields", function(v) trace_fields = v end)
+local trace_fields = false trackers.register("backends.fields", function(v) trace_fields = v end)
local report_fields = logs.reporter("backend","fields")
@@ -26,9 +36,11 @@ local context = context
local references = structures.references
local settings_to_array = utilities.parsers.settings_to_array
-local nodeinjections = backends.pdf.nodeinjections
-local codeinjections = backends.pdf.codeinjections
-local registrations = backends.pdf.registrations
+local pdfbackend = backends.pdf
+
+local nodeinjections = pdfbackend.nodeinjections
+local codeinjections = pdfbackend.codeinjections
+local registrations = pdfbackend.registrations
local registeredsymbol = codeinjections.registeredsymbol
@@ -48,11 +60,24 @@ local pdfreserveobject = lpdf.reserveobject
local pdfreserveannotation = lpdf.reserveannotation
local pdfaction = lpdf.action
+local hpack_node = node.hpack
+
local nodepool = nodes.pool
local pdfannotation_node = nodepool.pdfannotation
-local submitoutputformat = 0 -- 0=unknown 1=HTML 2=FDF 3=XML => not yet used, needs to be checked
+local submitoutputformat = 0 -- 0=unknown 1=HTML 2=FDF 3=XML => not yet used, needs to be checked
+
+local pdf_widget = pdfconstant("Widget")
+local pdf_tx = pdfconstant("Tx")
+local pdf_ch = pdfconstant("Ch")
+local pdf_btn = pdfconstant("Btn")
+local pdf_yes = pdfconstant("Yes")
+local pdf_off = pdfconstant("Off")
+local pdf_p = pdfconstant("P") -- None Invert Outline Push
+local pdf_n = pdfconstant("N") -- None Invert Outline Push
+--
+local pdf_no_rect = pdfarray { 0, 0, 0, 0 }
local splitter = lpeg.splitat("=>")
@@ -61,7 +86,7 @@ local formats = {
}
function codeinjections.setformsmethod(name)
- submitoutputformat = formats[lower(name)] or 3
+ submitoutputformat = formats[lower(name)] or formats.xml
end
local flag = {
@@ -128,11 +153,6 @@ local function fieldplus(specification)
return n
end
--- local function checked(what)
--- local set, bug = references.identify("",what)
--- return not bug and #set > 0 and lpdf.action(set)
--- end
-
local function checked(what)
local set, bug = references.identify("",what)
if not bug and #set > 0 then
@@ -141,26 +161,12 @@ local function checked(what)
end
end
--- a dedicated hash is faster, but maybe overkill
-
---~ local cache = { }
---~
---~ local function checked(what)
---~ local set, bug = references.identify("",what)
---~ if not bug and #set > 0 then
---~ local r = cache[set]
---~ if not r then
---~ r = pdfreference(pdfimmediateobject(pdfaction(set)))
---~ cache[set] = r
---~ end
---~ return r
---~ end
---~ end
-
local function fieldactions(specification) -- share actions
local d, a = { }, nil
- a = specification.mousedown if a and a ~= "" then d.D = checked(a) end
- a = specification.mouseup if a and a ~= "" then d.U = checked(a) end
+ a = specification.mousedown
+ or specification.clickin if a and a ~= "" then d.D = checked(a) end
+ a = specification.mouseup
+ or specification.clickout if a and a ~= "" then d.U = checked(a) end
a = specification.regionin if a and a ~= "" then d.E = checked(a) end -- Enter
a = specification.regionout if a and a ~= "" then d.X = checked(a) end -- eXit
a = specification.afterkey if a and a ~= "" then d.K = checked(a) end
@@ -169,8 +175,8 @@ local function fieldactions(specification) -- share actions
a = specification.calculate if a and a ~= "" then d.C = checked(a) end
a = specification.focusin if a and a ~= "" then d.Fo = checked(a) end
a = specification.focusout if a and a ~= "" then d.Bl = checked(a) end
- -- a = specification.openpage if a and a ~= "" then d.PO = checked(a) end
- -- a = specification.closepage if a and a ~= "" then d.PC = checked(a) end
+ a = specification.openpage if a and a ~= "" then d.PO = checked(a) end
+ a = specification.closepage if a and a ~= "" then d.PC = checked(a) end
-- a = specification.visiblepage if a and a ~= "" then d.PV = checked(a) end
-- a = specification.invisiblepage if a and a ~= "" then d.PI = checked(a) end
return next(d) and pdfdictionary(d)
@@ -220,6 +226,9 @@ local fontnames = {
sl = "Courier-Oblique",
bi = "Courier-BoldOblique",
bs = "Courier-BoldOblique",
+ },
+ symbol = {
+ dingbats = "ZapfDingbats",
}
}
@@ -240,7 +249,9 @@ local function fieldsurrounding(specification)
end
local tag = fontstyle .. fontalternative
fontsize = todimen(fontsize)
- local fontcode = format("%0.4f Tf",(fontsize and (bpfactor * fontsize)) or 12)
+ fontsize = (fontsize and (bpfactor * fontsize)) or 12
+ fontraise = 0.1 * fontsize -- todo: figure out what the natural one is and compensate for strutdp
+ local fontcode = format("%0.4f Tf %0.4f Ts",fontsize,fontraise)
local colorcode = lpdf.color(3,colorvalue) -- we force an rgb color space
if trace_fields then
report_fields("fontcode : %s %s @ %s => %s => %s",fontstyle,fontalternative,fontsize,tag,fontcode)
@@ -274,16 +285,6 @@ local function registerfonts()
end
end
--- cache
-
-local function fieldattributes(specification)
---~ return pdfarray {
---~ -- BG = -- backgroundcolor
---~ -- BC = -- framecolor
---~ }
- return nil
-end
-
-- symbols
local function fieldappearances(specification)
@@ -303,16 +304,18 @@ local function fieldappearances(specification)
else
n, r, d = v[1], v[2], v[3]
end
- local appearance = pdfdictionary { -- cache this one
+ local appearance = pdfdictionary {
N = registeredsymbol(n), R = registeredsymbol(r), D = registeredsymbol(d),
}
return pdfshareobjectreference(appearance)
end
+local YesorOn = "Yes" -- somehow On is not always working out well any longer (why o why this change)
+
local function fieldstates(specification,forceyes,values,default)
-- we don't use Opt here (too messy for radio buttons)
local values, default = values or specification.values, default or specification.default
- if not values then
+ if not values or values == "" then
-- error
return
end
@@ -354,14 +357,14 @@ local function fieldstates(specification,forceyes,values,default)
offvalue = offn
end
if forceyes == true then
- forceyes = forceyes and "On" -- spec likes Yes more but we've used On for ages now
+ forceyes = forceyes and YesorOn -- spec likes Yes more but we've used On for ages now
else
-- false or string
end
if default == yesn then
default = pdfconstant(forceyes or yesn)
else
- default = pdfconstant("Off")
+ default = pdf_off
end
local appearance = pdfdictionary { -- maybe also cache components
N = pdfdictionary { [forceyes or yesn] = registeredsymbol(yesn), Off = registeredsymbol(offn) },
@@ -369,7 +372,20 @@ local function fieldstates(specification,forceyes,values,default)
D = pdfdictionary { [forceyes or yesd] = registeredsymbol(yesd), Off = registeredsymbol(offd) }
}
local appearanceref = pdfshareobjectreference(appearance)
- return appearanceref, default
+ return appearanceref, default, yesvalue
+end
+
+local function fielddefault(field)
+ local default = field.default
+ if not default or default == "" then
+ local values = settings_to_array(field.values)
+ default = values[1]
+ end
+ if not default or default == "" then
+ return pdf_off
+ else
+ return pdfconstant(default)
+ end
end
local function fieldoptions(specification)
@@ -390,21 +406,32 @@ local function fieldoptions(specification)
end
end
-local function radiodefault(parent,field,forceyes)
- local default, values = parent.default, parent.values
- if not default or default == "" then
- values = settings_to_array(values)
- default = values[1]
+local mapping = {
+ -- acrobat compliant (messy, probably some pdfdoc encoding interference here)
+ check = "4", -- 0x34
+ circle = "l", -- 0x6C
+ cross = "8", -- 0x38
+ diamond = "u", -- 0x75
+ square = "n", -- 0x6E
+ star = "H", -- 0x48
+}
+
+local function todingbat(n)
+ if n and n ~= "" then
+ return mapping[n] or ""
end
- local name = field.name
- local fieldvalues = settings_to_array(field.values)
- local yes, off = fieldvalues[1], fieldvalues[2] or fieldvalues[1]
- if not default then
- return pdfconstant((forceyes and "On") or yes)
- elseif default == name then
- return pdfconstant((forceyes and "On") or default)
- else
- return pdfconstant("Off")
+end
+
+local function fieldrendering(specification)
+ local bvalue = tonumber(specification.backgroundcolorvalue)
+ local fvalue = tonumber(specification.framecolorvalue)
+ local svalue = specification.fontsymbol
+ if bvalue or fvalue or svalue then
+ return pdfdictionary {
+ BG = bvalue and pdfarray { lpdf.colorvalues(3,bvalue) } or nil,
+ BC = fvalue and pdfarray { lpdf.colorvalues(3,fvalue) } or nil,
+ CA = svalue and pdfstring (svalue) or nil,
+ }
end
end
@@ -472,9 +499,7 @@ function codeinjections.getdefaultfieldvalue(name)
default = a or symbol
end
end
- if default then
- context(default)
- end
+ return default
end
end
@@ -482,12 +507,12 @@ function codeinjections.definefield(specification)
local n = specification.name
local f = fields[n]
if not f then
- local kind = specification.kind
- if not kind then
+ local fieldtype = specification.type
+ if not fieldtype then
if trace_fields then
report_fields("invalid definition of '%s': unknown type",n)
end
- elseif kind == "radio" then
+ elseif fieldtype == "radio" then
local values = specification.values
if values and values ~= "" then
values = settings_to_array(values)
@@ -501,7 +526,7 @@ function codeinjections.definefield(specification)
elseif trace_fields then
report_fields("invalid definition of radio '%s': missing values",n)
end
- elseif kind == "sub" then
+ elseif fieldtype == "sub" then
-- not in main field list !
local radio = radios[n]
if radio then
@@ -517,10 +542,10 @@ function codeinjections.definefield(specification)
report_fields("invalid definition of radio sub '%s': no parent",n)
end
predefinesymbols(specification)
- elseif kind == "text" or kind == "line" then
+ elseif fieldtype == "text" or fieldtype == "line" then
fields[n] = specification
if trace_fields then
- report_fields("defining '%s' as %s",n,kind)
+ report_fields("defining '%s' as %s",n,fieldtype)
end
if specification.values ~= "" and specification.default == "" then
specification.default, specification.values = specification.values, nil
@@ -528,7 +553,7 @@ function codeinjections.definefield(specification)
else
fields[n] = specification
if trace_fields then
- report_fields("defining '%s' as %s",n,kind)
+ report_fields("defining '%s' as %s",n,fieldtype)
end
predefinesymbols(specification)
end
@@ -537,67 +562,67 @@ function codeinjections.definefield(specification)
end
end
-function codeinjections.clonefield(specification)
- local p, c, v = specification.parent, specification.children, specification.variant
+function codeinjections.clonefield(specification) -- obsolete
+ local p, c, v = specification.parent, specification.children, specification.alternative
if not p or not c then
if trace_fields then
- report_fields("invalid clone: children: '%s', parent '%s', variant: '%s'",p or "?",c or "?", v or "?")
+ report_fields("invalid clone: children: '%s', parent '%s', alternative: '%s'",p or "?",c or "?", v or "?")
end
- else
- for n in gmatch(c,"[^, ]+") do
- local f, r, c, x = fields[n], radios[n], clones[n], fields[p]
- if f or r or c then
- if trace_fields then
- report_fields("already cloned: child: '%s', parent '%s', variant: '%s'",p or "?",n or "?", v or "?")
- end
- elseif x then
- if trace_fields then
- report_fields("invalid clone: child: '%s', variant: '%s', no parent",n or "?", v or "?")
- end
- else
- if trace_fields then
- report_fields("cloning: child: '%s', parent '%s', variant: '%s'",p or "?",n or "?", v or "?")
- end
- clones[n] = specification
- predefinesymbols(specification)
+ return
+ end
+ local x = fields[p]
+ if not x then
+ if trace_fields then
+ report_fields("cloning: unknown parent '%s'",p)
+ end
+ return
+ end
+ for n in gmatch(c,"[^, ]+") do
+ local f, r, c = fields[n], radios[n], clones[n]
+ if f or r or c then
+ if trace_fields then
+ report_fields("already cloned: child: '%s', parent '%s', alternative: '%s'",p,n, v or "?")
end
+ else
+ if trace_fields then
+ report_fields("cloning: child: '%s', parent '%s', alternative: '%s'",p,n, v or "?")
+ end
+ clones[n] = specification
+ predefinesymbols(specification)
end
end
end
-function codeinjections.getfieldgroup(name)
+function codeinjections.getfieldcategory(name)
local f = fields[name] or radios[name] or clones[name]
if f then
- local g = f.group
+ local g = f.category
if not g or g == "" then
- local v, p, k = f.variant, f.parent, f.kind
+ local v, p, t = f.alternative, f.parent, f.type
if v == "clone" or v == "copy" then
f = fields[p] or radios[p]
- g = f and f.group
- elseif k == "sub" then
+ g = f and f.category
+ elseif t == "sub" then
f = fields[p]
- g = f and f.group
+ g = f and f.category
end
end
- if g then
- context(g)
- end
+ return g
end
end
--
-function codeinjections.doiffieldgroupelse(name)
- local f = fields[name] or radios[name] or clones[name]
- commands.testcase(f and f.group)
+function codeinjections.validfieldcategory(name)
+ return fields[name] or radios[name] or clones[name]
end
-function codeinjections.doiffieldsetelse(tag)
- commands.testcase(fieldsets[tag])
+function codeinjections.validfieldset(name)
+ return fieldsets[tag]
end
-function codeinjections.doiffieldelse(name)
- commands.testcase(fields[name])
+function codeinjections.validfield(name)
+ return fields[name]
end
--
@@ -630,14 +655,21 @@ local function finishfields()
for name, field in next, fields do
local kids = field.kids
if kids then
- pdfflushobject(field.kobj,kids)
+ pdfflushobject(field.kidsnum,kids)
+ end
+ local opt = field.opt
+ if opt then
+ pdfflushobject(field.optnum,opt)
end
- local pobj = field.pobj
end
for name, field in next, radios do
local kids = field.kids
if kids then
- pdfflushobject(field.kobj,kids)
+ pdfflushobject(field.kidsnum,kids)
+ end
+ local opt = field.opt
+ if opt then
+ pdfflushobject(field.optnum,opt)
end
end
if #collected > 0 then
@@ -659,300 +691,367 @@ end
lpdf.registerdocumentfinalizer(finishfields,"form fields")
-local pdf_widget = pdfconstant("Widget")
-local pdf_tx = pdfconstant("Tx")
-local pdf_ch = pdfconstant("Ch")
-local pdf_btn = pdfconstant("Btn")
-local pdf_yes = pdfconstant("Yes")
-local pdf_p = pdfconstant("P") -- None Invert Outline Push
-local pdf_n = pdfconstant("N") -- None Invert Outline Push
---
-local pdf_no_rect = pdfarray { 0, 0, 0, 0 }
-
local methods = { }
-function codeinjections.typesetfield(name,specification)
+function nodeinjections.typesetfield(name,specification)
local field = fields[name] or radios[name] or clones[name]
if not field then
report_fields( "unknown child '%s'",name)
-- unknown field
return
end
- local variant, parent = field.variant, field.parent
- if variant == "copy" or variant == "clone" then -- only in clones
+ local alternative, parent = field.alternative, field.parent
+ if alternative == "copy" or alternative == "clone" then -- only in clones
field = fields[parent] or radios[parent]
end
- local method = methods[field.kind]
+ local method = methods[field.type]
if method then
- method(name,specification,variant)
+ return method(name,specification,alternative)
else
- report_fields( "unknown method '%s' for child '%s'",field.kind,name)
+ report_fields( "unknown method '%s' for child '%s'",field.type,name)
end
end
--- can be optional multipass optimization (share objects)
-
-local function save_parent(field,specification,d)
- local kn = pdfreserveobject()
- d.Kids = pdfreference(kn)
- field.kobj = kn
+local function save_parent(field,specification,d,hasopt)
+ local kidsnum = pdfreserveobject()
+ d.Kids = pdfreference(kidsnum)
+ field.kidsnum = kidsnum
field.kids = pdfarray()
- local pn = pdfflushobject(d)
- field.pobj = pn
- collected[#collected+1] = pdfreference(pn)
+ if hasopt then
+ local optnum = pdfreserveobject()
+ d.Opt = pdfreference(optnum)
+ field.optnum = optnum
+ field.opt = pdfarray()
+ end
+ local pnum = pdfflushobject(d)
+ field.pobj = pnum
+ collected[#collected+1] = pdfreference(pnum)
end
-local function save_kid(field,specification,d)
---~ local kn = pdfreserveobject()
+local function save_kid(field,specification,d,optname)
local kn = pdfreserveannotation()
field.kids[#field.kids+1] = pdfreference(kn)
- node.write(pdfannotation_node(specification.width,specification.height,0,d(),kn))
+ if optname then
+ field.opt[#field.opt+1] = optname
+ end
+ local width, height, depth = specification.width or 0, specification.height or 0, specification.depth
+ local box = hpack_node(pdfannotation_node(width,height,depth,d(),kn))
+ box.width, box.height, box.depth = width, height, depth -- redundant
+ return box
end
-function methods.line(name,specification,variant,extras)
- local field = fields[name]
- if variant == "copy" or variant == "clone" then
- report_fields("todo: clones of text fields")
- end
- local kind = field.kind
- if not field.pobj then
- if trace_fields then
- report_fields("using parent text '%s'",name)
+local function makelineparent(field,specification)
+ local text = pdfunicode(field.default)
+ local length = tonumber(specification.length or 0) or 0
+ local d = pdfdictionary {
+ Subtype = pdf_widget,
+ T = pdfunicode(specification.title),
+ F = fieldplus(specification),
+ Ff = fieldflag(specification),
+ OC = fieldlayer(specification),
+ DA = fieldsurrounding(specification),
+ AA = fieldactions(specification),
+ FT = pdf_tx,
+ Q = fieldalignment(specification),
+ MaxLen = length == 0 and 1000 or length,
+ DV = text,
+ V = text,
+ }
+ save_parent(field,specification,d)
+end
+
+local function makelinechild(name,specification)
+ local field, parent = clones[name], nil
+ if field then
+ parent = fields[field.parent]
+ if not parent.pobj then
+ if trace_fields then
+ report_fields("forcing parent text '%s'",parent.name)
+ end
+ makelineparent(parent,specification)
end
- if extras then
- enhance(specification,extras)
+ else
+ parent = fields[name]
+ field = parent
+ if not parent.pobj then
+ if trace_fields then
+ report_fields("using parent text '%s'",name)
+ end
+ makelineparent(parent,specification)
end
- local text = pdfunicode(field.default)
- local d = pdfdictionary {
- Subtype = pdf_widget,
- T = pdfunicode(specification.title),
- F = fieldplus(specification),
- Ff = fieldflag(specification),
- OC = fieldlayer(specification),
- DA = fieldsurrounding(specification),
- AA = fieldactions(specification),
- FT = pdf_tx,
- Q = fieldalignment(specification),
- MaxLen = (specification.length == 0 and 1000) or specification.length,
- DV = text,
- V = text,
- }
- save_parent(field,specification,d)
- field.specification = specification
end
- specification = field.specification or { } -- todo: radio spec
if trace_fields then
report_fields("using child text '%s'",name)
end
local d = pdfdictionary {
Subtype = pdf_widget,
- Parent = pdfreference(field.pobj),
+ Parent = pdfreference(parent.pobj),
F = fieldplus(specification),
- DA = fieldattributes(specification),
OC = fieldlayer(specification),
DA = fieldsurrounding(specification),
AA = fieldactions(specification),
+ MK = fieldrendering(specification),
Q = fieldalignment(specification),
}
- save_kid(field,specification,d)
+ return save_kid(parent,specification,d)
end
-function methods.text(name,specification,variant)
- methods.line(name,specification,variant,"MultiLine")
+function methods.line(name,specification)
+ return makelinechild(name,specification)
end
-function methods.choice(name,specification,variant,extras)
- local field = fields[name]
- if variant == "copy" or variant == "clone" then
- report_fields("todo: clones of choice fields")
- end
- local kind = field.kind
- local d
- if not field.pobj then
- if trace_fields then
- report_fields("using parent choice '%s'",name)
+function methods.text(name,specification)
+ return makelinechine(name,enhance(specification,"MultiLine"))
+end
+
+local function makechoiceparent(field,specification)
+ local d = pdfdictionary {
+ Subtype = pdf_widget,
+ T = pdfunicode(specification.title),
+ F = fieldplus(specification),
+ Ff = fieldflag(specification),
+ OC = fieldlayer(specification),
+ AA = fieldactions(specification),
+ FT = pdf_ch,
+ Opt = fieldoptions(field), -- todo
+ }
+ save_parent(field,specification,d)
+end
+
+local function makechoicechild(name,specification)
+ local field, parent = clones[name], nil
+ if field then
+ parent = fields[field.parent]
+ if not parent.pobj then
+ if trace_fields then
+ report_fields("forcing parent choice '%s'",parent.name)
+ end
+ makechoiceparent(parent,specification,extras)
end
- if extras then
- enhance(specification,extras)
+ else
+ parent = fields[name]
+ field = parent
+ if not parent.pobj then
+ if trace_fields then
+ report_fields("using parent choice '%s'",name)
+ end
+ makechoiceparent(parent,specification,extras)
end
- local d = pdfdictionary {
- Subtype = pdf_widget,
- T = pdfunicode(specification.title),
- F = fieldplus(specification),
- Ff = fieldflag(specification),
- OC = fieldlayer(specification),
- AA = fieldactions(specification),
- FT = pdf_ch,
- Opt = fieldoptions(field),
- }
- save_parent(field,specification,d)
- field.specification = specification
end
- specification = field.specification or { }
if trace_fields then
report_fields("using child choice '%s'",name)
end
local d = pdfdictionary {
Subtype = pdf_widget,
- Parent = pdfreference(field.pobj),
+ Parent = pdfreference(parent.pobj),
F = fieldplus(specification),
- DA = fieldattributes(specification),
OC = fieldlayer(specification),
AA = fieldactions(specification),
}
- save_kid(field,specification,d)
+ return save_kid(parent,specification,d) -- do opt here
end
-function methods.popup(name,specification,variant)
- methods.choice(name,specification,variant,"PopUp")
+function methods.choice(name,specification)
+ return makechoicechild(name,specification)
end
-function methods.combo(name,specification,variant)
- methods.choice(name,specification,variant,"PopUp,Edit")
+
+function methods.popup(name,specification)
+ return makechoicechild(name,enhance(specification,"PopUp"))
end
--- Probably no default appearance needed for first kid and no javascripts for the
--- parent ... I will look into it when I have to make a complex document.
+function methods.combo(name,specification)
+ return makechoicechild(name,enhance(specification,"PopUp,Edit"))
+end
-function methods.check(name,specification,variant)
- -- no /Opt because (1) it's messy - see pdf spec, (2) it discouples kids and
- -- contrary to radio there is no way to associate then
- local field = fields[name]
- if variant == "copy" or variant == "clone" then
- report_fields("todo: clones of check fields")
- end
- local kind = field.kind
- local appearance, default = fieldstates(field,true)
- if not field.pobj then
- if trace_fields then
- report_fields("using parent check '%s'",name)
+local function makecheckparent(field,specification)
+ local d = pdfdictionary {
+ T = pdfunicode(specification.title),
+ F = fieldplus(specification),
+ Ff = fieldflag(specification),
+ OC = fieldlayer(specification),
+ AA = fieldactions(specification),
+ FT = pdf_btn,
+ V = fielddefault(field),
+ }
+ save_parent(field,specification,d,true)
+end
+
+local function makecheckchild(name,specification)
+ local field, parent = clones[name], nil
+ if field then
+ parent = fields[field.parent]
+ if not parent.pobj then
+ if trace_fields then
+ report_fields("forcing parent check '%s'",parent.name)
+ end
+ makecheckparent(parent,specification,extras)
+ end
+ else
+ parent = fields[name]
+ field = parent
+ if not parent.pobj then
+ if trace_fields then
+ report_fields("using parent check '%s'",name)
+ end
+ makecheckparent(parent,specification,extras)
end
- local d = pdfdictionary {
- Subtype = pdf_widget,
- T = pdfunicode(specification.title),
- F = fieldplus(specification),
- Ff = fieldflag(specification),
- OC = fieldlayer(specification),
- AA = fieldactions(specification),
- FT = pdf_btn,
- DV = default,
- V = default,
- AS = default,
- AP = appearance,
- H = pdf_n,
- }
- save_parent(field,specification,d)
- field.specification = specification
end
- specification = field.specification or { } -- todo: radio spec
if trace_fields then
report_fields("using child check '%s'",name)
end
local d = pdfdictionary {
Subtype = pdf_widget,
- Parent = pdfreference(field.pobj),
+ Parent = pdfreference(parent.pobj),
F = fieldplus(specification),
- DA = fieldattributes(specification),
OC = fieldlayer(specification),
AA = fieldactions(specification),
- DV = default,
- V = default,
- AS = default,
- AP = appearance,
H = pdf_n,
}
- save_kid(field,specification,d)
+ local fontsymbol = specification.fontsymbol
+ 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)
+ else
+ local appearance, default, value = fieldstates(field,true)
+ d.AS = default
+ d.AP = appearance
+ return save_kid(parent,specification,d,value)
+ end
end
-function methods.push(name,specification,variant)
- local field = fields[name]
- if variant == "copy" or variant == "clone" then
- report_fields("todo: clones of push fields")
- end
- local kind = field.kind
- if not field.pobj then
- if trace_fields then
- report_fields("using parent push '%s'",name)
+function methods.check(name,specification)
+ return makecheckchild(name,specification)
+end
+
+local function makepushparent(field,specification) -- check if we can share with the previous
+ local d = pdfdictionary {
+ Subtype = pdf_widget,
+ T = pdfunicode(specification.title),
+ F = fieldplus(specification),
+ Ff = fieldflag(specification),
+ OC = fieldlayer(specification),
+ AA = fieldactions(specification),
+ FT = pdf_btn,
+ AP = fieldappearances(field),
+ H = pdf_p,
+ }
+ save_parent(field,specification,d)
+end
+
+local function makepushchild(name,specification)
+ local field, parent = clones[name], nil
+ if field then
+ parent = fields[field.parent]
+ if not parent.pobj then
+ if trace_fields then
+ report_fields("forcing parent push '%s'",parent.name)
+ end
+ makepushparent(parent,specification)
+ end
+ else
+ parent = fields[name]
+ field = parent
+ if not parent.pobj then
+ if trace_fields then
+ report_fields("using parent push '%s'",name)
+ end
+ makepushparent(parent,specification)
end
- enhance(specification,"PushButton")
- local d = pdfdictionary {
- Subtype = pdf_widget,
- T = pdfunicode(specification.title),
- F = fieldplus(specification),
- Ff = fieldflag(specification),
- OC = fieldlayer(specification),
- AA = fieldactions(specification),
- FT = pdf_btn,
- AP = fieldappearances(field),
- H = pdf_p,
- }
- save_parent(field,specification,d)
- field.specification = specification
end
- specification = field.specification or { } -- todo: radio spec
if trace_fields then
report_fields("using child push '%s'",name)
end
+ local fontsymbol = specification.fontsymbol
local d = pdfdictionary {
Subtype = pdf_widget,
Parent = pdfreference(field.pobj),
F = fieldplus(specification),
- DA = fieldattributes(specification),
OC = fieldlayer(specification),
AA = fieldactions(specification),
- AP = fieldappearances(field),
H = pdf_p,
}
- save_kid(field,specification,d)
+ if fontsymbol and fontsymbol ~= "" then
+ specification.fontsymbol = todingbat(fontsymbol)
+ specification.fontstyle = "symbol"
+ specification.fontalternative = "dingbats"
+ d.DA = fieldsurrounding(specification)
+ d.MK = fieldrendering(specification)
+ else
+ d.AP = fieldappearances(field)
+ end
+ return save_kid(parent,specification,d)
+end
+
+function methods.push(name,specification)
+ return makepushchild(name,enhance(specification,"PushButton"))
+end
+
+local function makeradioparent(field,specification)
+ specification = enhance(specification,"Radio,RadiosInUnison")
+ local d = pdfdictionary {
+ T = field.name,
+ FT = pdf_btn,
+ F = fieldplus(specification),
+ Ff = fieldflag(specification),
+ H = pdf_n,
+ V = fielddefault(field),
+ }
+ save_parent(field,specification,d,true)
end
-function methods.sub(name,specification,variant)
- local field = radios[name] or fields[name] or clones[name] -- fields in case of a clone, maybe use dedicated clones
- local values
- if variant == "copy" or variant == "clone" then
- name = field.parent
- values = field.values -- clone only, copy has nil so same as parent
+local function makeradiochild(name,specification)
+ local field, parent = clones[name], nil
+ if field then
+ field = radios[field.parent]
+ parent = fields[field.parent]
+ if not parent.pobj then
+ if trace_fields then
+ report_fields("forcing parent radio '%s'",parent.name)
+ end
+ makeradioparent(parent,parent)
+ end
field = radios[name]
else
- values = field.values
- end
- local parent = fields[field.parent]
- if not parent then
- return
- end
- local appearance = fieldstates(field,name,values) -- we need to force the 'On' name
- local default = radiodefault(parent,field)
- if not parent.pobj then
- if trace_fields then
- report_fields("using parent '%s' of radio '%s' with values '%s' and default '%s'",parent.name,name,parent.values or "?",parent.default or "?")
+ field = radios[name]
+ parent = fields[field.parent]
+ if not parent.pobj then
+ if trace_fields then
+ report_fields("using parent radio '%s'",name)
+ end
+ makeradioparent(parent,parent)
end
- local specification = parent.specification or { }
- -- enhance(specification,"Radio,RadiosInUnison")
- enhance(specification,"RadiosInUnison") -- maybe also PushButton as acrobat does
- local d = pdfdictionary {
- Subtype = pdf_widget,
- T = parent.name,
- FT = pdf_btn,
- Rect = pdf_no_rect,
- F = fieldplus(specification),
- Ff = fieldflag(specification),
- H = pdf_n,
- V = default,
- }
- save_parent(parent,specification,d)
end
if trace_fields then
- report_fields("using child radio '%s' with values '%s'",name,values or "?")
+ report_fields("using child radio '%s' with values '%s' and default '%s'",name,field.values or "?",field.default or "?")
end
+ local fontsymbol = specification.fontsymbol
local d = pdfdictionary {
Subtype = pdf_widget,
Parent = pdfreference(parent.pobj),
F = fieldplus(specification),
- DA = fieldattributes(specification),
OC = fieldlayer(specification),
AA = fieldactions(specification),
- AS = default,
- AP = appearance,
H = pdf_n,
}
- save_kid(parent,specification,d)
+ 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)
+ else
+ local appearance, default, value = fieldstates(field,true) -- false is also ok
+ d.AS = default -- needed ?
+ d.AP = appearance
+ return save_kid(parent,specification,d,value)
+ end
+end
+
+function methods.sub(name,specification)
+ return makeradiochild(name,enhance(specification,"Radio,RadiosInUnison"))
end
diff --git a/tex/context/base/lpdf-fmt.lua b/tex/context/base/lpdf-fmt.lua
index 8250ce775..197e24ce9 100644
--- a/tex/context/base/lpdf-fmt.lua
+++ b/tex/context/base/lpdf-fmt.lua
@@ -17,7 +17,8 @@ local report_backend = logs.reporter("backend","profiles")
local backends, lpdf = backends, lpdf
-local codeinjections = backends.pdf.codeinjections -- normally it is registered
+local codeinjections = backends.pdf.codeinjections
+
local variables = interfaces.variables
local viewerlayers = attributes.viewerlayers
local colors = attributes.colors
@@ -626,10 +627,6 @@ end
lpdf.registerdocumentfinalizer(flushoutputintents,2,"output intents")
-directives.register("backend.format", function(v)
- codeinjections.setformat(v)
-end)
-
function codeinjections.setformat(s)
local format, level, profile, intent, option, filename =
s.format or "", s.level or "", s.profile or "", s.intent or "", s.option or "", s.file or ""
@@ -713,6 +710,19 @@ function codeinjections.setformat(s)
end
end
+directives.register("backend.format", function(v) -- table !
+ local tv = type(v)
+ if tv == "table" then
+ codeinjections.setformat(v)
+ elseif tv == "string" then
+ codeinjections.setformat { format = v }
+ end
+end)
+
+function commands.setformat(s)
+ codeinjections.setformat(s)
+end
+
function codeinjections.getformatoption(key)
return formatspecification and formatspecification[key]
end
diff --git a/tex/context/base/lpdf-ini.lua b/tex/context/base/lpdf-ini.lua
index c8291ff99..206e44688 100644
--- a/tex/context/base/lpdf-ini.lua
+++ b/tex/context/base/lpdf-ini.lua
@@ -389,25 +389,23 @@ end
function lpdf.flushobject(name,data)
if data then
- name = names[name] or name
- if name then
- if trace_objects then
- if trace_detail then
- report_objects("flushing data to reserved object with name '%s' -> %s",name,tostring(data))
- else
- report_objects("flushing data to reserved object with name '%s'",name)
- end
+ local named = names[name]
+ if named then
+ if not trace_objects then
+ elseif trace_detail then
+ report_objects("flushing data to reserved object with name '%s' -> %s",name,tostring(data))
+ else
+ report_objects("flushing data to reserved object with name '%s'",name)
end
- return pdfimmediateobject(name,tostring(data))
+ return pdfimmediateobject(named,tostring(data))
else
- if trace_objects then
- if trace_detail then
- report_objects("flushing data to reserved object with number %s -> %s",name,tostring(data))
- else
- report_objects("flushing data to reserved object with number %s",name)
- end
+ if not trace_objects then
+ elseif trace_detail then
+ report_objects("flushing data to reserved object with number %s -> %s",name,tostring(data))
+ else
+ report_objects("flushing data to reserved object with number %s",name)
end
- return pdfimmediateobject(tostring(data))
+ return pdfimmediateobject(name,tostring(data))
end
else
if trace_objects and trace_detail then
@@ -688,36 +686,36 @@ function lpdf.id()
return format("%s.%s",tex.jobname,timestamp)
end
-function lpdf.checkedkey(t,key,kind)
+function lpdf.checkedkey(t,key,variant)
local pn = t[key]
if pn then
local tn = type(pn)
- if tn == kind then
- if kind == "string" then
+ if tn == variant then
+ if variant == "string" then
return pn ~= "" and pn
- elseif kind == "table" then
+ elseif variant == "table" then
return next(pn) and pn
else
return pn
end
- elseif tn == "string" and kind == "number" then
+ elseif tn == "string" and variant == "number" then
return tonumber(pn)
end
end
end
-function lpdf.checkedvalue(value,kind) -- code not shared
+function lpdf.checkedvalue(value,variant) -- code not shared
if value then
local tv = type(value)
- if tv == kind then
- if kind == "string" then
+ if tv == variant then
+ if variant == "string" then
return value ~= "" and value
- elseif kind == "table" then
+ elseif variant == "table" then
return next(value) and value
else
return value
end
- elseif tv == "string" and kind == "number" then
+ elseif tv == "string" and variant == "number" then
return tonumber(value)
end
end
diff --git a/tex/context/base/lpdf-mis.lua b/tex/context/base/lpdf-mis.lua
index 39d7fbae8..d28439c26 100644
--- a/tex/context/base/lpdf-mis.lua
+++ b/tex/context/base/lpdf-mis.lua
@@ -109,12 +109,20 @@ end
local openpage, closepage, opendocument, closedocument
-function codeinjections.flushdocumentactions(open,close)
- opendocument, closedocument = open, close
+function codeinjections.registerdocumentopenaction(open)
+ opendocument = open
end
-function codeinjections.flushpageactions(open,close)
- openpage, closepage = open, close
+function codeinjections.registerdocumentcloseaction(close)
+ closedocument = close
+end
+
+function codeinjections.flushpageopenaction(open)
+ openpage = open
+end
+
+function codeinjections.flushpagecloseaction(close)
+ closepage = close
end
local function flushdocumentactions()
@@ -139,30 +147,41 @@ local function flushpageactions()
end
end
-lpdf.registerpagefinalizer(flushpageactions,"page actions")
+lpdf.registerpagefinalizer (flushpageactions, "page actions")
lpdf.registerdocumentfinalizer(flushdocumentactions,"document actions")
---- info
+--- info : this can change and move elsewhere
+
+local identity = { }
function codeinjections.setupidentity(specification)
- local title = specification.title or ""
- if title ~= "" then
- lpdf.addtoinfo("Title", pdfunicode(title), title)
+ for k, v in next, specification do
+ if v ~= "" then
+ identity[k] = v
+ end
end
- local subject = specification.subject or ""
- if subject ~= "" then
- lpdf.addtoinfo("Subject", pdfunicode(subject), subject)
+end
+
+local function setupidentity()
+ local title = identity.title
+ if not title or title == "" then
+ title = tex.jobname
end
- local author = specification.author or ""
+ lpdf.addtoinfo("Title", pdfunicode(title), title)
+ local subtitle = identity.subtitle or ""
+ if subtitle ~= "" then
+ lpdf.addtoinfo("Subject", pdfunicode(subtitle), subtitle)
+ end
+ local author = identity.author or ""
if author ~= "" then
lpdf.addtoinfo("Author", pdfunicode(author), author) -- '/Author' in /Info, 'Creator' in XMP
end
- local creator = specification.creator or ""
+ local creator = identity.creator or ""
if creator ~= "" then
lpdf.addtoinfo("Creator", pdfunicode(creator), creator) -- '/Creator' in /Info, 'CreatorTool' in XMP
end
lpdf.addtoinfo("CreationDate", pdfstring(lpdf.pdftimestamp(lpdf.timestamp())))
- local date = specification.date or ""
+ local date = identity.date or ""
local pdfdate = lpdf.pdftimestamp(date)
if pdfdate then
lpdf.addtoinfo("ModDate", pdfstring(pdfdate), date)
@@ -172,15 +191,18 @@ function codeinjections.setupidentity(specification)
date = lpdf.timestamp()
lpdf.addtoinfo("ModDate", pdfstring(lpdf.pdftimestamp(date)), date)
end
- local keywords = specification.keywords or ""
+ local keywords = identity.keywords or ""
if keywords ~= "" then
keywords = string.gsub(keywords, "[%s,]+", " ")
lpdf.addtoinfo("Keywords",pdfunicode(keywords), keywords)
end
local id = lpdf.id()
lpdf.addtoinfo("ID", pdfstring(id), id) -- needed for pdf/x
+ setupidentity = function() end
end
+lpdf.registerpagefinalizer(setupidentity,"identity")
+
local function flushjavascripts()
local t = interactions.javascripts.flushpreambles()
if #t > 0 then
@@ -279,7 +301,7 @@ local function pagespecification()
local pageheight = tex.pdfpageheight
local box = pdfarray { -- can be cached
boxvalue(leftoffset),
- boxvalue(pageheight-topoffset-height),
+ boxvalue(pageheight+topoffset-height),
boxvalue(width-leftoffset),
boxvalue(pageheight-topoffset),
}
diff --git a/tex/context/base/lpdf-ren.lua b/tex/context/base/lpdf-ren.lua
index 404c45e11..2fc1bf23c 100644
--- a/tex/context/base/lpdf-ren.lua
+++ b/tex/context/base/lpdf-ren.lua
@@ -26,6 +26,14 @@ local executers = references.executers
local variables = interfaces.variables
+local v_no = variables.no
+local v_yes = variables.yes
+local v_start = variables.start
+local v_stop = variables.stop
+local v_reset = variables.reset
+local v_auto = variables.auto
+local v_random = variables.random
+
local pdfconstant = lpdf.constant
local pdfdictionary = lpdf.dictionary
local pdfarray = lpdf.array
@@ -73,8 +81,8 @@ local function useviewerlayer(name)
local nd = pdfdictionary {
Type = pdf_ocg,
Name = specification.title or "unknown",
- Intent = ((specification.kind > 0) and pdf_design) or nil, -- disable layer hiding by user
- Usage = ((specification.printable == variables.no) and lpdf_usage) or nil , -- printable or not
+ Intent = ((specification.editable ~= v_no) and pdf_design) or nil, -- disable layer hiding by user
+ Usage = ((specification.printable == v_no) and lpdf_usage) or nil, -- printable or not
}
cache[#cache+1] = { nn, nd }
pdfln[tag] = nr -- was n
@@ -87,7 +95,7 @@ local function useviewerlayer(name)
cache[#cache+1] = { dn, dd }
pdfld[tag] = dr
textlayers[#textlayers+1] = nr
- if specification.visible == variables.start then
+ if specification.visible == v_start then
videlayers[#videlayers+1] = nr
else
hidelayers[#hidelayers+1] = nr
@@ -212,17 +220,19 @@ local last = 0
function codeinjections.setpagetransition(specification)
local n, delay = specification.n, specification.delay
- if n == variables.auto then
+ if not n or n == "" then
+ return -- let's forget about it
+ elseif n == v_auto then
if last >= #pagetransitions then
last = 0
end
n = last + 1
- elseif n == variables.stop then
+ elseif n == v_stop then
return
- elseif n == variables.reset then
+ elseif n == v_reset then
last = 0
return
- elseif n == variables.random then
+ elseif n == v_random then
n = math.random(1,#pagetransitions)
else
n = tonumber(n)
diff --git a/tex/context/base/lpdf-wid.lua b/tex/context/base/lpdf-wid.lua
index d0e441c26..48beacfd8 100644
--- a/tex/context/base/lpdf-wid.lua
+++ b/tex/context/base/lpdf-wid.lua
@@ -6,112 +6,152 @@ if not modules then modules = { } end modules ['lpdf-wid'] = {
license = "see context related readme files"
}
-local gmatch, gsub, find = string.gmatch, string.gsub, string.find
+local gmatch, gsub, find, lower, format = string.gmatch, string.gsub, string.find, string.lower, string.format
local texbox, texcount = tex.box, tex.count
local settings_to_array = utilities.parsers.settings_to_array
local settings_to_hash = utilities.parsers.settings_to_hash
-local report_media = logs.reporter("backend","media")
+local report_media = logs.reporter("backend","media")
+local report_attachment = logs.reporter("backend","attachment")
local backends, lpdf, nodes = backends, lpdf, nodes
-local nodeinjections = backends.pdf.nodeinjections
-local codeinjections = backends.pdf.codeinjections
-local registrations = backends.pdf.registrations
+local nodeinjections = backends.pdf.nodeinjections
+local codeinjections = backends.pdf.codeinjections
+local registrations = backends.pdf.registrations
-local executers = structures.references.executers
-local variables = interfaces.variables
+local executers = structures.references.executers
+local variables = interfaces.variables
-local pdfconstant = lpdf.constant
-local pdfdictionary = lpdf.dictionary
-local pdfarray = lpdf.array
-local pdfreference = lpdf.reference
-local pdfunicode = lpdf.unicode
-local pdfstring = lpdf.string
-local pdfcolorspec = lpdf.colorspec
-local pdfflushobject = lpdf.flushobject
-local pdfreserveannotation = lpdf.reserveannotation
-local pdfreserveobject = lpdf.reserveobject
-local pdfimmediateobject = lpdf.immediateobject
-local pdfpagereference = lpdf.pagereference
+local v_hidden = variables.hidden
+local v_normal = variables.normal
+local v_auto = variables.auto
+local v_embed = variables.embed
+local v_unknown = variables.unknown
-local nodepool = nodes.pool
+local pdfconstant = lpdf.constant
+local pdfdictionary = lpdf.dictionary
+local pdfarray = lpdf.array
+local pdfreference = lpdf.reference
+local pdfunicode = lpdf.unicode
+local pdfstring = lpdf.string
+local pdfcolorspec = lpdf.colorspec
+local pdfflushobject = lpdf.flushobject
+local pdfreserveannotation = lpdf.reserveannotation
+local pdfreserveobject = lpdf.reserveobject
+local pdfimmediateobject = lpdf.immediateobject
+local pdfpagereference = lpdf.pagereference
+local pdfshareobjectreference = lpdf.shareobjectreference
-local pdfannotation_node = nodepool.pdfannotation
+local nodepool = nodes.pool
-local hpack_node, write_node = node.hpack, node.write
+local pdfannotation_node = nodepool.pdfannotation
-local pdf_border = pdfarray { 0, 0, 0 } -- can be shared
+local hpack_node = node.hpack
+local write_node = node.write
+
+local pdf_border = pdfarray { 0, 0, 0 } -- can be shared
-- symbols
local presets = { } -- xforms
-function codeinjections.registersymbol(name,n)
+local function registersymbol(name,n)
presets[name] = pdfreference(n)
end
-function codeinjections.registeredsymbol(name)
+local function registeredsymbol(name)
return presets[name]
end
-function codeinjections.presetsymbol(symbol)
+local function presetsymbol(symbol)
if not presets[symbol] then
context.predefinesymbol { symbol }
end
end
-function codeinjections.presetsymbollist(list)
+local function presetsymbollist(list)
if list then
for symbol in gmatch(list,"[^, ]+") do
- codeinjections.presetsymbol(symbol)
+ presetsymbol(symbol)
end
end
end
+codeinjections.registersymbol = registersymbol
+codeinjections.registeredsymbol = registeredsymbol
+codeinjections.presetsymbol = presetsymbol
+codeinjections.presetsymbollist = presetsymbollist
+
-- comments
-local symbols = {
- New = pdfconstant("Insert"),
- Insert = pdfconstant("Insert"),
- Balloon = pdfconstant("Comment"),
+-- local symbols = {
+-- Addition = pdfconstant("NewParagraph"),
+-- Attachment = pdfconstant("Attachment"),
+-- Balloon = pdfconstant("Comment"),
+-- Check = pdfconstant("Check Mark"),
+-- CheckMark = pdfconstant("Check Mark"),
+-- Circle = pdfconstant("Circle"),
+-- Cross = pdfconstant("Cross"),
+-- CrossHairs = pdfconstant("Cross Hairs"),
+-- Graph = pdfconstant("Graph"),
+-- InsertText = pdfconstant("Insert Text"),
+-- New = pdfconstant("Insert"),
+-- Paperclip = pdfconstant("Paperclip"),
+-- RightArrow = pdfconstant("Right Arrow"),
+-- RightPointer = pdfconstant("Right Pointer"),
+-- Star = pdfconstant("Star"),
+-- Tag = pdfconstant("Tag"),
+-- Text = pdfconstant("Note"),
+-- TextNote = pdfconstant("Text Note"),
+-- UpArrow = pdfconstant("Up Arrow"),
+-- UpLeftArrow = pdfconstant("Up-Left Arrow"),
+-- }
+
+local attachment_symbols = {
+ Graph = pdfconstant("GraphPushPin"),
+ Paperclip = pdfconstant("PaperclipTag"),
+ Pushpin = pdfconstant("PushPin"),
+}
+
+attachment_symbols.PushPin = attachment_symbols.Pushpin
+attachment_symbols.Default = attachment_symbols.Pushpin
+
+local comment_symbols = {
Comment = pdfconstant("Comment"),
- Text = pdfconstant("Note"),
- Addition = pdfconstant("NewParagraph"),
- NewParagraph = pdfconstant("NewParagraph"),
Help = pdfconstant("Help"),
- Paragraph = pdfconstant("Paragraph"),
+ Insert = pdfconstant("Insert"),
Key = pdfconstant("Key"),
- Graph = pdfconstant("Graph"),
- Paperclip = pdfconstant("Paperclip"),
- Attachment = pdfconstant("Attachment"),
- Tag = pdfconstant("Tag"),
+ Newparagraph = pdfconstant("NewParagraph"),
+ Note = pdfconstant("Note"),
+ Paragraph = pdfconstant("Paragraph"),
}
-symbols[variables.normal] = pdfconstant("Note")
+comment_symbols.NewParagraph = Newparagraph
+comment_symbols.Default = Note
-local nofcomments, usepopupcomments, stripleading = 0, true, true
-
-local function analyzesymbol(symbol)
+local function analyzesymbol(symbol,collection)
if not symbol or symbol == "" then
- return symbols.normal, nil
- elseif symbols[symbol] then
- return symbols[symbol], nil
+ return collection.Default, nil
+ elseif collection[symbol] then
+ return collection[symbol], nil
else
+ local setn, setr, setd
local set = settings_to_array(symbol)
- local normal, down = set[1], set[2]
- if normal then
- normal = codeinjections.registeredsymbol(down or normal)
- end
- if down then
- down = codeinjections.registeredsymbol(normal)
- end
- if down or normal then
- return nil, pdfdictionary {
- N = normal,
- D = down,
- }
+ if #set == 1 then
+ setn, setr, setd = set[1], set[1], set[1]
+ elseif #set == 2 then
+ setn, setr, setd = set[1], set[1], set[2]
+ else
+ setn, setr, setd = set[1], set[2], set[3]
end
+ local appearance = pdfdictionary {
+ N = setn and registeredsymbol(setn),
+ R = setr and registeredsymbol(setr),
+ D = setd and registeredsymbol(setd),
+ }
+ local appearanceref = pdfshareobjectreference(appearance)
+ return nil, appearanceref
end
end
@@ -119,67 +159,34 @@ local function analyzelayer(layer)
-- todo: (specification.layer ~= "" and pdfreference(specification.layer)) or nil, -- todo: ref to layer
end
-function codeinjections.registercomment(specification)
- nofcomments = nofcomments + 1
- local text = buffers.collectcontent(specification.buffer)
- text = string.strip(text)
- if stripleading then -- maybe just strip all leading and trailing spacing
- text = gsub(text,"[\n\r] *","\n")
- end
- local name, appearance = analyzesymbol(specification.symbol)
- local d = pdfdictionary {
- Subtype = pdfconstant("Text"),
- Open = specification.open,
- Contents = pdfunicode(text),
- T = (specification.title ~= "" and pdfunicode(specification.title)) or nil,
- C = pdfcolorspec(specification.colormodel,specification.colorvalue),
- OC = analyzelayer(specification.layer),
- Name = name,
- AP = appearance,
- }
- --
- -- watch the nice feed back to tex hack
- --
- -- we can consider replacing nodes by user nodes that do a latelua
- -- so that we get rid of all annotation whatsits
- if usepopupcomments then
- local nd = pdfreserveannotation()
- local nc = pdfreserveannotation()
- local c = pdfdictionary {
- Subtype = pdfconstant("Popup"),
- Parent = pdfreference(nd),
- }
- d.Popup = pdfreference(nc)
- texbox["commentboxone"] = hpack_node(pdfannotation_node(0,0,0,d(),nd)) -- current dir
- texbox["commentboxtwo"] = hpack_node(pdfannotation_node(specification.width,specification.height,0,c(),nc)) -- current dir
- else
- texbox["commentboxone"] = hpack_node(pdfannotation_node(0,0,0,d())) -- current dir
- texbox["commentboxtwo"] = nil
- end
+local function analyzecolor(colorvalue,colormodel)
+ local cvalue = colorvalue and tonumber(colorvalue)
+ local cmodel = colormodel and tonumber(colormodel) or 3
+ return cvalue and pdfarray { lpdf.colorvalues(cmodel,cvalue) } or nil
end
---
+local function analyzetransparency(transparencyvalue)
+ local tvalue = transparencyvalue and tonumber(transparencyvalue)
+ return tvalue and lpdf.transparencyvalue(tvalue) or nil
+end
-local nofattachments, attachments, filestreams, referenced = 0, { }, { }, { }
+-- Attachments
--- todo: hash and embed once
+local nofattachments, attachments, filestreams, referenced = 0, { }, { }, { }
local ignorereferenced = true -- fuzzy pdf spec .. twice in attachment list, can become an option
local function flushembeddedfiles()
if next(filestreams) then
local e = pdfarray()
- for name, reference in next, filestreams do
- if reference then
- if ignorereferenced and referenced[name] then
- reference = nil
- end
- if reference then
- e[#e+1] = pdfstring(name)
- e[#e+1] = reference -- already a reference
- end
+ for tag, reference in next, filestreams do
+ if not reference then
+ report_attachment("unreferenced file: tag '%s'",tag)
+ elseif referenced[name] == "hidden" then
+ e[#e+1] = pdfstring(tag)
+ e[#e+1] = reference -- already a reference
else
- -- we can issue a message
+ -- messy spec ... when annot not in named else twice in menu list acrobat
end
end
lpdf.addtonames("EmbeddedFiles",pdfreference(pdfflushobject(pdfdictionary{ Names = e })))
@@ -188,78 +195,201 @@ end
lpdf.registerdocumentfinalizer(flushembeddedfiles,"embeddedfiles")
-function codeinjections.embedfile(filename)
- local r = filestreams[filename]
- if r == false then
- return nil
- elseif r then
- return r
- elseif not lfs.isfile(filename) then
- interfaces.showmessage("interactions",5,filename)
- filestreams[filename] = false
- return nil
+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
+ if filename == "" then
+ filename = nil
+ 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
+ end
else
- local basename = file.basename(filename)
- local a = pdfdictionary { Type = pdfconstant("EmbeddedFile") }
- local f = pdfimmediateobject("streamfile",filename,a())
- local d = pdfdictionary {
- Type = pdfconstant("Filespec"),
- F = pdfstring(newname or basename),
- UF = pdfstring(newname or basename),
- EF = pdfdictionary { F = pdfreference(f) },
- }
- local r = pdfreference(pdfflushobject(d))
- filestreams[filename] = r
- return r
+ if not filename then
+ return nil
+ end
+ local r = filestreams[hash]
+ if r == false then
+ return nil
+ elseif r then
+ return r
+ elseif not lfs.isfile(filename) then
+ filestreams[filename] = false
+ return nil
+ end
end
+ local basename = file.basename(filename)
+ local savename = file.addsuffix(name ~= "" and name or basename,"txt") -- else no valid file
+ local a = pdfdictionary { Type = pdfconstant("EmbeddedFile") }
+ local f
+ if data then
+ f = pdfimmediateobject("stream",data,a())
+ specification.data = true -- signal that still data but already flushed
+ else
+ f = pdfimmediateobject("streamfile",filename,a())
+ end
+ local d = pdfdictionary {
+ Type = pdfconstant("Filespec"),
+ F = pdfstring(savename),
+ UF = pdfstring(savename),
+ EF = pdfdictionary { F = pdfreference(f) },
+ Desc = title ~= "" and pdfunicode(title) or nil,
+ }
+ local r = pdfreference(pdfflushobject(d))
+ filestreams[hash] = r
+ return r
end
-function codeinjections.attachfile(specification)
- local attachment = interactions.attachments.attachment(specification.label)
- if not attachment then
- -- todo: message
- return
- end
- local filename = attachment.filename
- if not filename or filename == "" then
- -- todo: message
- return
+function nodeinjections.attachfile(specification)
+ local registered = specification.registered or "<unset>"
+ local data = specification.data
+ local hash
+ if data then
+ hash = md5.HEX(data)
+ else
+ local filename = specification.file
+ if not filename or filename == "" then
+ report_attachment("missing file specification: registered '%s', using registered instead",registered)
+ filename = registered
+ specification.file = registered
+ end
+ if not lfs.isfile(filename) then
+ report_attachment("invalid file specification: registered '%s', filename '%s'",registered,filename)
+ return
+ end
+ hash = filename
end
- referenced[filename] = true
+ specification.hash = hash
nofattachments = nofattachments + 1
- local label = attachment.label or ""
- local title = attachment.title or ""
- local newname = attachment.newname or ""
- if label == "" then label = filename end
- if title == "" then title = label end
- if newname == "" then newname = filename end
- local aref = attachments[label]
+ 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 == "" then
+ author = title
+ title = ""
+ end
+ if author == "" then
+ author = v_unknown
+ end
+ if title == "" then
+ title = registered
+ end
+ local aref = attachments[registered]
if not aref then
- aref = codeinjections.embedfile(filename,newname)
- attachments[label] = aref
+ aref = codeinjections.embedfile(specification)
+ attachments[registered] = aref
+ end
+ if not aref then
+ report_attachment("skipping: registered '%s'",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(format("attachment:%s",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, height, depth = specification.width or 0, specification.height or 0, specification.depth
+ local box = hpack_node(pdfannotation_node(width,height,depth,d()))
+ box.width, box.height, box.depth = width, height, depth
+ return box
end
- local name, appearance = analyzesymbol(specification.symbol)
- local d = pdfdictionary {
- Subtype = pdfconstant("FileAttachment"),
- FS = aref,
- Contents = pdfunicode(title),
- Name = name,
- AP = appearance,
- OC = analyzelayer(specification.layer),
- C = pdfcolorspec(specification.colormodel,specification.colorvalue),
- }
- -- as soon as we can ask for the dimensions of an xform we can
- -- use them here
- local width = specification.width or 0
- local height = specification.height or 0
- local depth = specification.depth or 0
- write_node(pdfannotation_node(width,height,depth,d())) -- somehow the dimensions come out wrong
end
-function codeinjections.attachmentid(filename)
+function codeinjections.attachmentid(filename) -- not used in context
return filestreams[filename]
end
+local nofcomments, usepopupcomments, stripleading = 0, false, true
+
+function nodeinjections.comment(specification)
+ nofcomments = nofcomments + 1
+ local text = string.strip(specification.data or "")
+ if stripleading then
+ text = gsub(text,"[\n\r] *","\n")
+ end
+ local name, appearance = analyzesymbol(specification.symbol,comment_symbols)
+ local tag = specification.tag or "" -- this is somewhat messy as recent
+ local title = specification.title or "" -- versions of acrobat see the title
+ local subtitle = specification.subtitle or "" -- as author
+ local author = specification.author or ""
+ if author == "" then
+ if title == "" then
+ title = tag
+ end
+ else
+ if subtitle == "" then
+ subtitle = title
+ elseif title ~= "" then
+ subtitle = subtitle .. ", " .. title
+ end
+ title = author
+ end
+ local d = pdfdictionary {
+ Subtype = pdfconstant("Text"),
+ -- Open = specification.open, -- now options
+ Contents = pdfunicode(text),
+ T = title ~= "" and pdfunicode(title) or nil,
+ Subj = subtitle ~= "" and pdfunicode(subtitle) or nil,
+ C = analyzecolor(specification.colorvalue,specification.colormodel),
+ CA = analyzetransparency(specification.transparencyvalue),
+ OC = analyzelayer(specification.layer),
+ Name = name,
+ NM = pdfstring(format("comment:%s",nofcomments)),
+ AP = appearance,
+ }
+ local width, height, depth = specification.width or 0, specification.height or 0, specification.depth
+ local box
+ if usepopupcomments then
+ -- rather useless as we can hide/vide
+ local nd = pdfreserveannotation()
+ local nc = pdfreserveannotation()
+ local c = pdfdictionary {
+ Subtype = pdfconstant("Popup"),
+ Parent = pdfreference(nd),
+ }
+ d.Popup = pdfreference(nc)
+ box = hpack_node(
+ pdfannotation_node(0,0,0,d(),nd),
+ pdfannotation_node(width,height,depth,c(),nc)
+ )
+ else
+ box = hpack_node(pdfannotation_node(width,height,depth,d()))
+ end
+ box.width, box.height, box.depth = width, height, depth -- redundant
+ return box
+end
+
-- rendering stuff
--
-- object_1 -> <</Type /Rendition /S /MR /C << /Type /MediaClip ... >> >>
@@ -308,7 +438,7 @@ local function insertrenderingwindow(specification)
local label = specification.label
--~ local openpage = specification.openpage
--~ local closepage = specification.closepage
- if specification.options == variables.auto then
+ if specification.options == v_auto then
if openpageaction then
-- \handlereferenceactions{\v!StartRendering{#2}}
end
@@ -384,7 +514,7 @@ local function insertrendering(specification)
}
if isurl then
descriptor.FS = pdfconstant("URL")
- elseif options[variables.embed] then
+ elseif options[v_embed] then
descriptor.EF = codeinjections.embedfile(filename)
end
local clip = pdfdictionary {
@@ -430,7 +560,7 @@ function codeinjections.processrendering(label)
local specification = interactions.renderings.rendering(label)
if not specification then
-- error
- elseif specification.kind == "external" then
+ elseif specification.type == "external" then
insertrendering(specification)
else
insertrenderingobject(specification)
diff --git a/tex/context/base/lpdf-xmp.lua b/tex/context/base/lpdf-xmp.lua
index 160a5ece1..c9bead8a5 100644
--- a/tex/context/base/lpdf-xmp.lua
+++ b/tex/context/base/lpdf-xmp.lua
@@ -14,7 +14,9 @@ local trace_xmp = false trackers.register("backend.xmp", function(v) trace_xmp
local report_xmp = logs.reporter("backend","xmp")
-local lpdf = lpdf
+local backends, lpdf = backends, lpdf
+
+local codeinjections = backends.pdf.codeinjections -- normally it is registered
local pdfdictionary = lpdf.dictionary
local pdfconstant = lpdf.constant
@@ -77,11 +79,7 @@ local mapping = {
local xmp, xmpfile, xmpname = nil, nil, "lpdf-pdx.xml"
-function lpdf.setxmpfile(name)
- -- xmpfile = resolvers.findctxfile(name) or ""
- -- if xmpfile == "" then
- -- xmpfile = nil
- -- end
+local function setxmpfile(name)
if xmp then
report_xmp("discarding loaded file '%s'",xmpfile)
xmp = nil
@@ -89,6 +87,9 @@ function lpdf.setxmpfile(name)
xmpfile = name ~= "" and name
end
+codeinjections.setxmpfile = setxmpfile
+commands.setxmpfile = setxmpfile
+
local function valid_xmp()
if not xmp then
-- local xmpfile = xmpfile or resolvers.findfile(xmpname) or ""
diff --git a/tex/context/base/luat-mac.lua b/tex/context/base/luat-mac.lua
index 1b9e09951..775e8a3b5 100644
--- a/tex/context/base/luat-mac.lua
+++ b/tex/context/base/luat-mac.lua
@@ -6,13 +6,15 @@ if not modules then modules = { } end modules ['luat-mac'] = {
license = "see context related readme files"
}
-local P, V, S, R, C, Cs, Cmt = lpeg.P, lpeg.V, lpeg.S, lpeg.R, lpeg.C, lpeg.Cs, lpeg.Cmt
+local P, V, S, R, C, Cs, Cmt, Carg = lpeg.P, lpeg.V, lpeg.S, lpeg.R, lpeg.C, lpeg.Cs, lpeg.Cmt, lpeg.Carg
local lpegmatch, patterns = lpeg.match, lpeg.patterns
local insert, remove = table.insert, table.remove
local rep, sub = string.rep, string.sub
local setmetatable = setmetatable
+local pushtarget, poptarget = logs.pushtarget, logs.poptarget
+
local report_macros = logs.reporter("interface","macros")
local stack, top, n, hashes = { }, nil, 0, { }
@@ -37,8 +39,17 @@ local function set(s)
end
local function get(s)
- local m = top and top[s] or s
- return m
+ if not top then
+ report_macros("keeping #%s, no stack",s)
+ return "#" .. s -- can be lua
+ end
+ local m = top[s]
+ if m then
+ return m
+ else
+ report_macros("keeping #%s, not on stack",s)
+ return "#" .. s -- quite likely an error
+ end
end
local function push()
@@ -64,24 +75,44 @@ local spaces = space^1
local newline = patterns.newline
local nobrace = 1 - leftbrace - rightbrace
-local longleft = leftbrace -- P("(")
-local longright = rightbrace -- P(")")
-local nolong = 1 - longleft - longright
-
-local name = R("AZ","az")^1 -- @?! -- utf?
-local longname = (longleft/"") * (nolong^1) * (longright/"")
-local variable = P("#") * Cs(name + longname)
-local escapedname = escape * name
-local definer = escape * (P("def") + P("egdx") * P("def"))
-local startcode = P("\\starttexdefinition")
-local stopcode = P("\\stoptexdefinition")
-local anything = patterns.anything
-local always = patterns.alwaysmatched
-
-local pushlocal = always / push
-local poplocal = always / pop
-local declaration = variable / set
-local identifier = variable / get
+local longleft = leftbrace -- P("(")
+local longright = rightbrace -- P(")")
+local nolong = 1 - longleft - longright
+
+local name = R("AZ","az")^1
+local csname = (R("AZ","az") + S("@?!_"))^1
+local longname = (longleft/"") * (nolong^1) * (longright/"")
+local variable = P("#") * Cs(name + longname)
+local escapedname = escape * csname
+local definer = escape * (P("def") + P("egx") * P("def")) -- tex
+local setter = escape * P("set") * (P("u")^-1 * P("egx")^-1) * P("value") -- context specific
+--- + escape * P("install") * (1-P("handler"))^1 * P("handler") -- context specific
+local startcode = P("\\starttexdefinition") -- context specific
+local stopcode = P("\\stoptexdefinition") -- context specific
+local anything = patterns.anything
+local always = patterns.alwaysmatched
+
+-- The comment nilling can become an option but it nicely compensates the Lua
+-- parsing here with less parsing at the TeX end. We keep lines so the errors
+-- get reported all right, but comments are never seen there anyway. We keep
+-- comment that starts inline as it can be something special with a % (at some
+-- point we can do that as well, esp if we never use \% or `% somewhere
+-- unpredictable). We need to skip comments anyway. Hm, too tricky, this
+-- stripping as we can have Lua code etc.
+
+local commenttoken = P("%")
+local crorlf = S("\n\r")
+local commentline = commenttoken * ((Carg(1) * C((1-crorlf)^0))/function(strip,s) return strip and "" or s end)
+local commentline = commenttoken * ((1-crorlf)^0)
+local leadingcomment = (commentline * crorlf^1)^1
+local furthercomment = (crorlf^1 * commentline)^1
+
+local pushlocal = always / push
+local poplocal = always / pop
+local declaration = variable / set
+local identifier = variable / get
+
+local argument = leftbrace * ((identifier + (1-rightbrace))^0) * rightbrace
local function matcherror(str,pos)
report_macros("runaway definition at: %s",sub(str,pos-30,pos))
@@ -93,7 +124,7 @@ local grammar = { "converter",
* spaces
* name
* spaces
- * (declaration + (1 - newline - space))^0
+ * (declaration + furthercomment + (1 - newline - space))^0
* V("texbody")
* stopcode
* poplocal,
@@ -105,20 +136,33 @@ local grammar = { "converter",
definition = pushlocal
* definer
* escapedname
- * (declaration + (1-leftbrace))^0
+ * (declaration + furthercomment + commentline + (1-leftbrace))^0
+ * V("braced")
+ * poplocal,
+ setcode = pushlocal
+ * setter
+ * argument
+ * (declaration + furthercomment + commentline + (1-leftbrace))^0
* V("braced")
* poplocal,
braced = leftbrace
* ( V("definition")
+ identifier
+ + V("setcode")
+ V("texcode")
+ V("braced")
+ + furthercomment
+ nobrace
)^0
-- * rightbrace^-1, -- the -1 catches errors
* (rightbrace + Cmt(always,matcherror)),
- pattern = V("definition") + V("texcode") + anything,
+ pattern = leadingcomment
+ + V("definition")
+ + V("setcode")
+ + V("texcode")
+ + furthercomment
+ + anything,
converter = V("pattern")^1,
}
@@ -132,8 +176,8 @@ local checker = P("%") * (1 - newline - P("macros"))^0
local macros = { } resolvers.macros = macros
-function macros.preprocessed(str)
- return lpegmatch(parser,str)
+function macros.preprocessed(str,strip)
+ return lpegmatch(parser,str,1,strip)
end
function macros.convertfile(oldname,newname) -- beware, no testing on oldname == newname
@@ -148,7 +192,11 @@ end
function macros.processmkvi(str,filename)
if (filename and file.suffix(filename) == "mkvi") or lpegmatch(checker,str) == "mkvi" then
- return lpegmatch(parser,str) or str
+ local result = lpegmatch(parser,str,1,true) or str
+ pushtarget("log")
+ report_macros("processed file '%s', delta %s",filename,#str-#result)
+ poptarget("log")
+ return result
else
return str
end
@@ -160,9 +208,17 @@ if resolvers.schemes then
local hashed = url.hashed(name)
local path = hashed.path
if path and path ~= "" then
- local data = resolvers.loadtexfile(path)
- data = lpegmatch(parser,data) or ""
- io.savedata(cachename,data)
+ local str = resolvers.loadtexfile(path)
+ if file.suffix(path) == "mkvi" or lpegmatch(checker,str) == "mkvi" then
+ -- already done automatically
+ io.savedata(cachename,str)
+ else
+ local result = lpegmatch(parser,str,1,true) or str
+ pushtarget("log")
+ report_macros("processed scheme '%s', delta %s",filename,#str-#result)
+ poptarget("log")
+ io.savedata(cachename,result)
+ end
end
return cachename
end
@@ -174,12 +230,32 @@ if resolvers.schemes then
end
+--~ print(macros.preprocessed([[\def\bla#bla{bla#{bla}}]]))
+--~ print(macros.preprocessed([[\def\bla#bla{#{bla}bla}]]))
--~ print(macros.preprocessed([[\def\blä#{blá}{blà:#{blá}}]]))
--~ print(macros.preprocessed([[\def\blä#bla{blà:#bla}]]))
---~ print(macros.preprocessed([[\def\bla#bla{bla:#bla}]]))
+--~ print(macros.preprocessed([[\setvalue{xx}#bla{blà:#bla}]]))
+--~ print(macros.preprocessed([[\def\foo#bar{\setvalue{xx#bar}{#bar}}]]))
+--~ print(macros.preprocessed([[\def\bla#bla{bla:#{bla}}]]))
+--~ print(macros.preprocessed([[\def\bla_bla#bla{bla:#bla}]]))
--~ print(macros.preprocessed([[\def\test#oeps{test:#oeps}]]))
+--~ print(macros.preprocessed([[\def\test_oeps#oeps{test:#oeps}]]))
--~ print(macros.preprocessed([[\def\test#oeps{test:#{oeps}}]]))
--~ print(macros.preprocessed([[\def\test#{oeps:1}{test:#{oeps:1}}]]))
--~ print(macros.preprocessed([[\def\test#{oeps}{test:#oeps}]]))
---~ macros.preprocessed([[\def\test#{oeps}{test:#oeps \halign{##\cr #oeps\cr}]])
+--~ print(macros.preprocessed([[\def\test#{oeps}{test:#oeps \halign{##\cr #oeps\cr}]]))
--~ print(macros.preprocessed([[\def\test#{oeps}{test:#oeps \halign{##\cr #oeps\cr}}]]))
+--~ print(macros.preprocessed([[% test
+--~ \def\test#oeps{#oeps} % {test}
+--~ % test
+--~
+--~ % test
+--~ two
+--~ %test]]))
+--~ print(macros.preprocessed([[
+--~ \def\scrn_button_make_normal#namespace#current#currentparameter#text%
+--~ {\ctxlua{structures.references.injectcurrentset(nil,nil)}%
+--~ % \hbox attr \referenceattribute \lastreferenceattribute {\localframed[#namespace:#current]{#text}}}
+--~ \hbox attr \referenceattribute \lastreferenceattribute {\directlocalframed[#namespace:#current]{#text}}}
+--~ ]]))
+
diff --git a/tex/context/base/lxml-tex.lua b/tex/context/base/lxml-tex.lua
index b4cbbbdd3..26a8b2996 100644
--- a/tex/context/base/lxml-tex.lua
+++ b/tex/context/base/lxml-tex.lua
@@ -482,17 +482,16 @@ end
local pihandlers = { } xml.pihandlers = pihandlers
-local kind = P("context-") * C((1-P("-"))^1) * P("-directive")
-local space = S(" \n\r")
-local spaces = space^0
-local class = C((1-space)^0)
-local key = class
-local value = C(P(1-(space * -1))^0)
+local category = P("context-") * C((1-P("-"))^1) * P("-directive")
+local space = S(" \n\r")
+local spaces = space^0
+local class = C((1-space)^0)
+local key = class
+local value = C(P(1-(space * -1))^0)
-local parser = kind * spaces * class * spaces * key * spaces * value
+local parser = category * spaces * class * spaces * key * spaces * value
pihandlers[#pihandlers+1] = function(str)
--- local kind, class, key, value = lpegmatch(parser,str)
if str then
local a, b, c, d = lpegmatch(parser,str)
if d then
diff --git a/tex/context/base/m-barcodes.mkiv b/tex/context/base/m-barcodes.mkiv
index fa230ba57..fd98cec75 100644
--- a/tex/context/base/m-barcodes.mkiv
+++ b/tex/context/base/m-barcodes.mkiv
@@ -1,5 +1,5 @@
%D \module
-%D [ file=m-pstricks,
+%D [ file=m-barcodes,
%D version=2010.03.14,
%D title=\CONTEXT\ Extra Modules,
%D subtitle=Barcodes,
diff --git a/tex/context/base/m-chart.mkiv b/tex/context/base/m-chart.mkiv
index 6b947b23f..114e7d553 100644
--- a/tex/context/base/m-chart.mkiv
+++ b/tex/context/base/m-chart.mkiv
@@ -1051,17 +1051,20 @@
%D A hook into the help system.
+% \def\showFLOWhelp#1%
+% {\doifhelpinfo\FLOWhelp
+% {\setbox#1=\hbox
+% {\setbox\scratchbox=\hbox{\lower\@@FLOWdy\hbox
+% {\helpbutton
+% [\c!width=\wd0,\c!color=,\c!height=\@@FLOWdy,\c!frame=\v!no]%
+% [\FLOWhelp]}}%
+% \smashbox\scratchbox
+% \setbox#1=\vbox
+% {\forgetall\offinterlineskip\box#1\box\scratchbox}%
+% \box#1}}}
+
\def\showFLOWhelp#1%
- {\doifhelpinfo\FLOWhelp
- {\setbox#1=\hbox
- {\setbox\scratchbox=\hbox{\lower\@@FLOWdy\hbox
- {\helpbutton
- [\c!width=\wd0,\c!color=,\c!height=\@@FLOWdy,\c!frame=\v!no]%
- [\FLOWhelp]}}%
- \smashbox\scratchbox
- \setbox#1=\vbox
- {\forgetall\offinterlineskip\box#1\box\scratchbox}%
- \box#1}}}
+ {}
%D The next section is dedicated to splitting up charts.
@@ -2317,20 +2320,6 @@
\def\FLOWchart%
{\dodoubleempty\doFLOWchart}
-%D A hook into the help system.
-
-\def\showFLOWhelp#1%
- {\doifhelpinfo\FLOWhelp
- {\setbox#1=\hbox
- {\setbox\scratchbox=\hbox{\lower\@@FLOWdy\hbox
- {\helpbutton
- [\c!width=\wd0,\c!color=,\c!height=\@@FLOWdy,\c!frame=\v!no]%
- [\FLOWhelp]}}%
- \smashbox\scratchbox
- \setbox#1=\vbox
- {\forgetall\offinterlineskip\box#1\box\scratchbox}%
- \box#1}}}
-
%D The next section is dedicated to splitting up charts.
\def\getFLOWsize[#1]%
diff --git a/tex/context/base/m-fields.mkiv b/tex/context/base/m-fields.mkiv
new file mode 100644
index 000000000..cd840f377
--- /dev/null
+++ b/tex/context/base/m-fields.mkiv
@@ -0,0 +1,70 @@
+%D \module
+%D [ file=m-fields,
+%D version=2010.03.14,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=Fields,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA]
+%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 A rather old example of field usage is the following. It
+%D makes no sense to have this in the core.
+%D
+%D \starttyping
+%D before \fillinfield[oeps]{whatever} after
+%D \stoptyping
+
+\startJSpreamble{FillInField} used later
+ function CheckFillInField(right) {
+ if (event.value.toLowerCase() == right.toLowerCase()) {
+ event.target.hidden = true ;
+ }
+ event.value = ""
+ }
+\stopJSpreamble
+
+\newcount\noffillinfields
+
+\definefieldcategory
+ [fillinfield]
+ [\c!n=1024,
+ \c!height=\strutht,
+ \c!depth=\strutdp,
+ \c!align=\v!middle,
+ \c!color=red,
+ \c!fieldframecolor=blue,
+ \c!fieldbackgroundcolor=\s!white,
+ \c!validate=JS(CheckFillInField{\therightanswer})]
+
+\def\fillinfield
+ {\dosingleempty\dofillinfield}
+
+\def\dofillinfield[#1]#2%
+ {\dontleavehmode
+ \hbox
+ {\forgetall
+ \global\advance\noffillinfields\plusone
+ \edef\currentfillinfieldname{fillinfield:\number\noffillinfields}%
+ \useJSscripts[ans]%
+ \definefieldbody
+ [\currentfillinfieldname]
+ [\c!type=\v!line,
+ \c!category=fillinfield]%
+ \doifelsenothing{#1}
+ {\def\therightanswer{#2}}
+ {\def\therightanswer{#1}}%
+ \setbox0\hbox{\strut#2}%
+ \setbox2\hbox{\strut\therightanswer}%
+ \dimen0=\dimexpr\ifdim\wd0>\wd2 \wd0 \else \wd2 \fi + .2em\relax
+ \hbox to \wd0
+ {\wd0\zeropoint
+ \box0
+ \hss\fieldbody[\currentfillinfieldname][\c!width=\dimen0]\hss}}}
+
+\protect \endinput
diff --git a/tex/context/base/m-newmat.tex b/tex/context/base/m-newmat.tex
index 08ce33b4c..3fb75df5d 100644
--- a/tex/context/base/m-newmat.tex
+++ b/tex/context/base/m-newmat.tex
@@ -11,6 +11,12 @@
%C therefore copyrighted by \PRAGMA. See licen-en.pdf for
%C details.
+\unprotect
+
+%D Code has been integrated.
+
+\protect \endinput
+
%D This module collects macros that \TEX\ users kind of expect
%D to be available when typesetting math. Most of them
%D originate in the \AMS\ macro packages. We have taken the
@@ -19,269 +25,6 @@
%D derived from AMS math modules) and adapted|/|extended by
%D Hans Hagen.
-%D Here we will add code on demand. So, just let us know what
-%D should go in here.
-
-%M \usemodule[newmat]
-
-\unprotect
-
-%D \macros
-%D {qedsymbol}
-%D
-%D [HH] The general Quod Erat Domonstrandum symbol is defined
-%D in such a way that we can configure it. Because this symbol
-%D is also used in text mode, we make it a normal text symbol
-%D with special behavior.
-
-\def\qedsymbol#1%
- {\ifhmode
- \unskip~\hfill#1\par
- \else\ifmmode
- \eqno#1\relax % Do we really need the \eqno here?
- \else
- \leavevmode\hbox{}\hfill#1\par
- \fi\fi}
-
-\definesymbol [qed] [\qedsymbol{\mathematics{\square}}]
-
-%D \macros
-%D {QED}
-%D
-%D [HH] For compatbility reasons we also provide the \type
-%D {\QED} command. In case this command is overloaded, we still
-%D have the symbol available. \symbol[qed]
-
-\def\QED{\symbol[qed]}
-
-%D \macros
-%D {genfrac}
-%D
-%D [TH] The definition of \type {\genfrac} \& co. is not
-%D trivial, because it allows some flexibility. This is
-%D supposed to be a user||level command, but will fail quite
-%D desparately if called outside math mode (\CONTEXT\ redefines
-%D \type {\over})
-%D
-%D [HH] We clean up this macro a bit and (try) to make it
-%D understandable. The expansion is needed for generating
-%D the second argument to \type {\dogenfrac}, which is to
-%D be a control sequence like \type {\over}.
-
-\unexpanded\def\genfrac#1#2#3#4%
- {\edef\!!stringa
- {#1#2}%
- \expanded
- {\dogenfrac{#4}%
- \csname
- \ifx @#3@%
- \ifx\!!stringa\empty
- \strippedcsname\normalover
- \else
- \strippedcsname\normaloverwithdelims
- \fi
- \else
- \ifx\!!stringa\empty
- \strippedcsname\normalabove
- \else
- \strippedcsname\normalabovewithdelims
- \fi
- \fi
- \endcsname}%
- {#1#2#3}}
-
-\def\dogenfrac#1#2#3#4#5%
- {{#1{\begingroup#4\endgroup#2#3\relax#5}}}
-
-%D \macros
-%D {dfrac, tfrac, frac, dbinom, tbinom, binom}
-%D
-%D [TH] No need to make these \type {\unexpanded} as well.
-
-%\def\dfrac {\genfrac\empty\empty\empty\displaystyle}
-%\def\tfrac {\genfrac\empty\empty\empty\textstyle}
-%\def\frac {\genfrac\empty\empty\empty\donothing}
-
-\def\dfrac {\genfrac\empty\empty{}\displaystyle}
-\def\tfrac {\genfrac\empty\empty{}\textstyle}
-\def\frac {\genfrac\empty\empty{}\donothing}
-
-\def\dbinom{\genfrac()\zeropoint\displaystyle}
-\def\tbinom{\genfrac()\zeropoint\textstyle}
-\def\binom {\genfrac()\zeropoint\donothing}
-
-\def\xfrac {\genfrac\empty\empty{}\scriptstyle}
-\def\xxfrac{\genfrac\empty\empty{}\scriptscriptstyle}
-
-%D Better:
-
-\unexpanded\def\frac#1#2{\mathematics{\genfrac\empty\empty{}\donothing{#1}{#2}}}
-
-%D [HH] This shows up as:
-%D
-%D \startbuffer
-%D $\dfrac {1}{2} \tfrac {1}{2} \frac {1}{2}$
-%D $\dbinom{1}{2} \tbinom{1}{2} \binom{1}{2}$
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D \getbuffer
-
-%D \macros
-%D {text}
-%D
-%D [TH] \type {\text} is a command to typeset more or less
-%D ordinary text inside of super- and sub|-|scripts. It has to
-%D do a full font switch to get the sides right, so it will be
-%D quite slow. \type {\text} kind of replaces \CONTEXT's \type
-%D {\mathstyle} command.
-
-%D [HH] This macro is now also moved to the core, but we
-%D keep it here as well for completeness.
-%D
-%D \starttyping
-%D \unexpanded\def\mathtext
-%D {\mathortext\domathtext\hbox} % {\ifmmode\@EA\dotext\else\@EA\hbox\fi}
-%D
-%D \def\domathtext#1%
-%D {\mathchoice
-%D {\dodomathtext\displaystyle\textface {#1}}%
-%D {\dodomathtext\textstyle \textface {#1}}%
-%D {\dodomathtext\textstyle \scriptface {#1}}%
-%D {\dodomathtext\textstyle \scriptscriptface{#1}}}
-%D
-%D \def\dodomathtext#1#2#3% no \everymath !
-%D %{\hbox{\everymath{#1}\switchtobodyfont [#2]#3}} % 15 sec
-%D {\hbox{\everymath{#1}\setcurrentfontbody{#2}#3}} % 3 sec (no math)
-%D \stoptyping
-
-%D [HH] We use the following indirectness because \type {\text}
-%D is a natural candidate for user macros (actually, it is
-%D used in some modules).
-%D
-%D \starttyping
-%D \let\text\mathtext
-%D \stoptyping
-
-%D [HH] Actually, the font switch is not that slow when
-%D typefaces are used. If needed this macro can be sped up.
-%D
-%D \startbuffer
-%D ordinary text $x^{\text{extra ordinary text}}$
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D \getbuffer
-
-%D \macros
-%D {mathhexbox}
-%D
-%D [TH] \type {\mathhexbox} is also user||level (already
-%D defined in Plain \TEX). It allows to get a math character
-%D inserted as if it was a text character.
-
-\gdef\mathhexbox#1#2#3{\mathtext{$\mathsurround\zeropoint\mathchar"#1#2#3$}}
-
-%D \macros
-%D {boxed}
-%D
-%D [HH] Another macro that users expect (slightly adapted):
-
-\def\boxed
- {\ifmmode\expandafter\mframed\else\expandafter\framed\fi}
-
-%D \macros
-%D {cfrac}
-%D
-%D [HH] Now let us see what this one does:
-%D
-%D \startbuffer
-%D $\cfrac{12}{3} \cfrac[l]{12}{3} \cfrac[c]{12}{3} \cfrac[r]{12}{3}$
-%D $\cfrac{1}{23} \cfrac[l]{1}{23} \cfrac[c]{1}{23} \cfrac[r]{1}{23}$
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D \getbuffer
-
-\definecomplexorsimple\cfrac
-
-\def\simplecfrac
- {\complexcfrac[c]}
-
-\def\complexcfrac[#1]#2#3%
- {{\displaystyle
- \frac
- {\strut\ifx r#1\hfill\fi#2\ifx l#1\hfill\fi}%
- {#3}}%
- \kern-\nulldelimiterspace}
-
-%D [HH] The next alternative is nicer:
-
-\def\simplecfrac {\docfrac[cc]}
-\def\complexcfrac[#1]{\docfrac[#1cc]}
-
-\def\docfrac[#1#2#3]#4#5%
- {{\displaystyle
- \frac
- {\strut
- \ifx r#1\hfill\fi#4\ifx l#1\hfill\fi}%
- {\ifx r#2\hfill\fi#5\ifx l#2\hfill\fi}%
- \kern-\nulldelimiterspace}}
-
-%D [HH] Now we can align every combination we want:
-%D
-%D \startbuffer
-%D $\cfrac{12}{3} \cfrac[l]{12}{3} \cfrac[c]{12}{3} \cfrac[r]{12}{3}$
-%D $\cfrac{1}{23} \cfrac[l]{1}{23} \cfrac[c]{1}{23} \cfrac[r]{1}{23}$
-%D $\cfrac[cl]{12}{3} \cfrac[cc]{12}{3} \cfrac[cr]{12}{3}$
-%D $\cfrac[lc]{1}{23} \cfrac[cc]{1}{23} \cfrac[rc]{1}{23}$
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D \getbuffer
-
-%D \macros
-%D {splitfrac, splitdfrac}
-%D
-%D Occasionally one needs to typeset multi||line fractions.
-%D These commands use \tex{genfrac} to create such fractions.
-%D
-%D \startbuffer
-%D \startformula
-%D a=\frac{
-%D \splitfrac{xy + xy + xy + xy + xy}
-%D {+ xy + xy + xy + xy}
-%D }
-%D {z}
-%D =\frac{
-%D \splitdfrac{xy + xy + xy + xy + xy}
-%D {+ xy + xy + xy + xy}
-%D }
-%D {z}
-%D \stopformula
-%D \stopbuffer
-%D
-%D \typebuffer \getbuffer
-%D
-%D These macros are based on Michael J.~Downes posting on
-%D comp.text.tex on 2001/12/06
-
-\def\splitfrac#1#2%
- {\genfrac\empty\empty\zeropoint\textstyle%
- {\textstyle#1\quad\hfill}%
- {\textstyle\hfill\quad\mathstrut#2}}
-
-\def\splitdfrac#1#2%
- {\genfrac\empty\empty\zeropoint\displaystyle%
- {#1\quad\hfill}
- {\hfill\quad\mathstrut #2}}
-
-\protect \endinput
-
%D \macros
%D {startsubarray,substack,startsmallmatrix}
%D
diff --git a/tex/context/base/m-obsolete.tex b/tex/context/base/m-obsolete.tex
index a97002cf6..2d4518181 100644
--- a/tex/context/base/m-obsolete.tex
+++ b/tex/context/base/m-obsolete.tex
@@ -1,5 +1,5 @@
\unprotect
-\writestatus\m!systems{skipping obsolete module}
+\writestatus\m!system{skipping obsolete module}
\protect \endinput
diff --git a/tex/context/base/m-punk.mkiv b/tex/context/base/m-punk.mkiv
index dc7692144..71158d2a6 100644
--- a/tex/context/base/m-punk.mkiv
+++ b/tex/context/base/m-punk.mkiv
@@ -19,7 +19,7 @@
\startluacode
local concat = table.concat
local chardata = characters.data
-local fontdata = fonts.identifiers
+local fontdata = fonts.hashes.identifiers
fonts.mp = fonts.mp or { }
@@ -53,11 +53,11 @@ local flusher = {
local cd = chardata[n]
if inline then
descriptions[n] = {
- -- unicode = n,
- name = cd and cd.adobename,
- width = w*100,
- height = h*100,
- depth = d*100,
+ -- unicode = n,
+ name = cd and cd.adobename,
+ width = w*100,
+ height = h*100,
+ depth = d*100,
boundingbox = { 0, -d, w, h },
}
characters[n] = {
@@ -100,7 +100,8 @@ function metapost.characters.process(mpxformat, name, instances, scalefactor)
metapost.setoutercolor(2) -- no outer color and no reset either
lists = { }
for i=1,instances do
- characters, descriptions = { }, { }
+ characters = { }
+ descriptions = { }
metapost.process(
mpxformat,
{
@@ -112,26 +113,23 @@ function metapost.characters.process(mpxformat, name, instances, scalefactor)
flusher
)
lists[i] = {
- designsize = 655360,
- name = string.format("%s-%03i",hash,i),
- parameters = {
- slant = 0,
- space = 333 * scalefactor,
- space_stretch = 166.5 * scalefactor,
- space_shrink = 111 * scalefactor,
- x_height = 431 * scalefactor,
- quad =1000 * scalefactor,
- extra_space = 0
- },
- ["type"] = "virtual",
- characters = characters,
+ characters = characters,
descriptions = descriptions,
- -- embedding = "subset",
- -- mkiv:
- spacer = "space",
- unit = 1000,
- shared = { },
- unique = { },
+ parameters = {
+ designsize = 655360,
+ slant = 0,
+ space = 333 * scalefactor,
+ space_stretch = 166.5 * scalefactor,
+ space_shrink = 111 * scalefactor,
+ x_height = 431 * scalefactor,
+ quad = 1000 * scalefactor,
+ extra_space = 0,
+ },
+ properties = {
+ name = string.format("%s-%03i",hash,i),
+ virtualized = true,
+ spacer = "space",
+ }
}
end
metapost.reset(mpxformat) -- saves memory
@@ -143,23 +141,23 @@ function metapost.characters.process(mpxformat, name, instances, scalefactor)
return lists
end
-function fonts.vf.aux.combine.commands.metafont(g,v)
+function fonts.handlers.vf.combiner.commands.metafont(g,v)
local size = g.specification.size
local data = metapost.characters.process(v[2],v[3],v[4],size/655360)
local list, t = { }, { }
for d=1,#data do
t = data[d]
- t = fonts.tfm.scale(t, -1000)
+ t = fonts.constructors.scale(t, -1000)
local id = font.nextid()
t.fonts = { { id = id } }
fontdata[id] = t
- fonts.vf.aux.compose_characters(t)
+ fonts.handlers.vf.helpers.composecharacters(t)
list[d] = font.define(t)
end
for k, v in next, t do
g[k] = v -- kind of replace, when not present, make nil
end
- g.virtualized = true
+ g.properties.virtualized = true
g.variants = list
end
diff --git a/tex/context/base/math-dim.lua b/tex/context/base/math-dim.lua
index 604d390da..1d3f93ad3 100644
--- a/tex/context/base/math-dim.lua
+++ b/tex/context/base/math-dim.lua
@@ -6,8 +6,8 @@ if not modules then modules = { } end modules ['math-dim'] = {
license = "see context related readme files"
}
--- Beware: only Taco really understands in depth what these dimensions do so
--- if you run into problems ...
+-- Beware: only Taco and Ulrik really understands in depth what these dimensions
+-- do so if you run into problems ask on the context list.
-- The radical_rule value is also used as a trigger. In luatex the accent
-- placement happens either the opentype way (using top_accent cum suis) or the
diff --git a/tex/context/base/math-ext.lua b/tex/context/base/math-ext.lua
index 75c6e4b26..ac994ea35 100644
--- a/tex/context/base/math-ext.lua
+++ b/tex/context/base/math-ext.lua
@@ -29,51 +29,48 @@ function extras.add(unicode,t)
end
end
-function extras.copy(tfmdata)
- local mathparameters = tfmdata.mathparameters
- local MathConstants = tfmdata.MathConstants
- if (mathparameters and next(mathparameters)) or (MathConstants and next(MathConstants)) then
- local characters = tfmdata.characters
- for unicode, extradesc in next, mathdata do
- -- always, because in an intermediate step we can have a non math font
- local extrachar = characters[unicode]
- local nextinsize = extradesc.nextinsize
- if nextinsize then
- for i=1,#nextinsize do
- local nextslot = nextinsize[i]
- local nextbase = characters[nextslot]
- if nextbase then
- local nextnext = nextbase and nextbase.next
- if nextnext then
- local nextchar = characters[nextnext]
- if nextchar then
- if trace_virtual then
- report_math("extra U+%04X in %s at %s maps on U+%04X (class: %s, name: %s)",unicode,file.basename(tfmdata.fullname),tfmdata.size,nextslot,extradesc.mathclass or "?",extradesc.mathname or "?")
- end
- characters[unicode] = nextchar
- break
+function extras.copy(target,original)
+ local characters = target.characters
+ local properties = target.properties
+ local parameters = target.parameters
+ for unicode, extradesc in next, mathdata do
+ -- always, because in an intermediate step we can have a non math font
+ local extrachar = characters[unicode]
+ local nextinsize = extradesc.nextinsize
+ if nextinsize then
+ for i=1,#nextinsize do
+ local nextslot = nextinsize[i]
+ local nextbase = characters[nextslot]
+ if nextbase then
+ local nextnext = nextbase and nextbase.next
+ if nextnext then
+ local nextchar = characters[nextnext]
+ if nextchar then
+ if trace_virtual then
+ report_math("extra U+%04X in %s at %s maps on U+%04X (class: %s, name: %s)",unicode,
+ file.basename(properties.fullname),parameters.size,nextslot,extradesc.mathclass or "?",extradesc.mathname or "?")
end
+ characters[unicode] = nextchar
+ break
end
end
end
- if not characters[unicode] then -- can be set in previous loop
- for i=1,#nextinsize do
- local nextslot = nextinsize[i]
- local nextbase = characters[nextslot]
- if nextbase then
- characters[unicode] = nextbase -- still ok?
- break
- end
+ end
+ if not characters[unicode] then -- can be set in previous loop
+ for i=1,#nextinsize do
+ local nextslot = nextinsize[i]
+ local nextbase = characters[nextslot]
+ if nextbase then
+ characters[unicode] = nextbase -- still ok?
+ break
end
end
end
end
- else
- -- let's not waste time on non-math
end
end
-table.insert(fonts.tfm.mathactions,extras.copy)
+utilities.sequencers.appendaction(mathactions,"system","mathematics.extras.copy")
-- 0xFE302 -- 0xFE320 for accents
diff --git a/tex/context/base/math-frc.mkii b/tex/context/base/math-frc.mkii
index fa319bc4a..767c5ec5c 100644
--- a/tex/context/base/math-frc.mkii
+++ b/tex/context/base/math-frc.mkii
@@ -15,7 +15,8 @@
\unprotect
-\def\exmthfont#1{\symbolicsizedfont#1\plusone{MathExtension}}
+\unexpanded\def\exmthfont#1%
+ {\symbolicsizedfont#1\plusone{MathExtension}}
\def\domthfrac#1#2#3#4#5#6#7%
{\begingroup
@@ -49,18 +50,204 @@
\rlap{\raise\dimexpr\ht2-\ht4\relax\copy4}\copy0}}}%
\endgroup}
-\def\mthfrac#1#2#3#4#5{\mathchoice
+\unexpanded\def\mthfrac#1#2#3#4#5{\mathchoice
{\domthfrac\displaystyle \textface {#1}{#2}{#3}{#4}{#5}}
{\domthfrac\textstyle \textface {#1}{#2}{#3}{#4}{#5}}
{\domthfrac\scriptstyle \scriptface {#1}{#2}{#3}{#4}{#5}}
{\domthfrac\scriptscriptstyle\scriptscriptface{#1}{#2}{#3}{#4}{#5}}}
-\def\mthsqrt#1#2#3{\mathchoice
+\unexpanded\def\mthsqrt#1#2#3{\mathchoice
{\domthsqrt\displaystyle \textface {#1}{#2}{#3}}
{\domthsqrt\textstyle \textface {#1}{#2}{#3}}
{\domthsqrt\scriptstyle \textface {#1}{#2}{#3}}
{\domthsqrt\scriptscriptstyle\textface {#1}{#2}{#3}}}
-% temp here
+%D Moved from math-new.tex (not that new anyway:
+
+%D \macros
+%D {genfrac}
+%D
+%D [TH] The definition of \type {\genfrac} \& co. is not
+%D trivial, because it allows some flexibility. This is
+%D supposed to be a user||level command, but will fail quite
+%D desparately if called outside math mode (\CONTEXT\ redefines
+%D \type {\over})
+%D
+%D [HH] We clean up this macro a bit and (try) to make it
+%D understandable. The expansion is needed for generating
+%D the second argument to \type {\dogenfrac}, which is to
+%D be a control sequence like \type {\over}.
+
+\unexpanded\def\genfrac#1#2#3#4%
+ {\edef\!!stringa
+ {#1#2}%
+ \expanded
+ {\dogenfrac{#4}%
+ \csname
+ \ifx @#3@%
+ \ifx\!!stringa\empty
+ \strippedcsname\normalover
+ \else
+ \strippedcsname\normaloverwithdelims
+ \fi
+ \else
+ \ifx\!!stringa\empty
+ \strippedcsname\normalabove
+ \else
+ \strippedcsname\normalabovewithdelims
+ \fi
+ \fi
+ \endcsname}%
+ {#1#2#3}}
+
+\def\dogenfrac#1#2#3#4#5%
+ {{#1{\begingroup#4\endgroup#2#3\relax#5}}}
+
+%D \macros
+%D {dfrac, tfrac, frac, dbinom, tbinom, binom}
+%D
+%D \startbuffer
+%D $\dfrac {1}{2} \tfrac {1}{2} \frac {1}{2}$
+%D $\dbinom{1}{2} \tbinom{1}{2} \binom{1}{2}$
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+
+\unexpanded\def\dfrac {\genfrac\empty\empty{}\displaystyle}
+\unexpanded\def\tfrac {\genfrac\empty\empty{}\textstyle}
+\unexpanded\def\frac {\genfrac\empty\empty{}\donothing}
+
+\unexpanded\def\dbinom{\genfrac()\zeropoint\displaystyle}
+\unexpanded\def\tbinom{\genfrac()\zeropoint\textstyle}
+\unexpanded\def\binom {\genfrac()\zeropoint\donothing}
+
+\unexpanded\def\xfrac {\genfrac\empty\empty{}\scriptstyle}
+\unexpanded\def\xxfrac{\genfrac\empty\empty{}\scriptscriptstyle}
+
+\unexpanded\def\frac#1#2{\mathematics{\genfrac\empty\empty{}\donothing{#1}{#2}}}
+
+%D \macros
+%D {cfrac}
+%D
+%D \startbuffer
+%D $\cfrac{12}{3} \cfrac[l]{12}{3} \cfrac[c]{12}{3} \cfrac[r]{12}{3}$
+%D $\cfrac{1}{23} \cfrac[l]{1}{23} \cfrac[c]{1}{23} \cfrac[r]{1}{23}$
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D Now we can align every combination we want:
+%D
+%D \startbuffer
+%D $\cfrac{12}{3} \cfrac[l]{12}{3} \cfrac[c]{12}{3} \cfrac[r]{12}{3}$
+%D $\cfrac{1}{23} \cfrac[l]{1}{23} \cfrac[c]{1}{23} \cfrac[r]{1}{23}$
+%D $\cfrac[cl]{12}{3} \cfrac[cc]{12}{3} \cfrac[cr]{12}{3}$
+%D $\cfrac[lc]{1}{23} \cfrac[cc]{1}{23} \cfrac[rc]{1}{23}$
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+
+\definecomplexorsimple\cfrac
+
+\def\simplecfrac {\docfrac[cc]}
+\def\complexcfrac[#1]{\docfrac[#1cc]}
+
+\def\docfrac[#1#2#3]#4#5%
+ {{\displaystyle
+ \frac
+ {\strut
+ \ifx r#1\hfill\fi#4\ifx l#1\hfill\fi}%
+ {\ifx r#2\hfill\fi#5\ifx l#2\hfill\fi}%
+ \kern-\nulldelimiterspace}}
+
+%D \macros
+%D {splitfrac, splitdfrac}
+%D
+%D Occasionally one needs to typeset multi||line fractions.
+%D These commands use \tex{genfrac} to create such fractions.
+%D
+%D \startbuffer
+%D \startformula
+%D a=\frac{
+%D \splitfrac{xy + xy + xy + xy + xy}
+%D {+ xy + xy + xy + xy}
+%D }
+%D {z}
+%D =\frac{
+%D \splitdfrac{xy + xy + xy + xy + xy}
+%D {+ xy + xy + xy + xy}
+%D }
+%D {z}
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D These macros are based on Michael J.~Downes posting on
+%D comp.text.tex on 2001/12/06
+
+\unexpanded\def\splitfrac#1#2%
+ {\genfrac\empty\empty\zeropoint\textstyle%
+ {\textstyle#1\quad\hfill}%
+ {\textstyle\hfill\quad\mathstrut#2}}
+
+\unexpanded\def\splitdfrac#1#2%
+ {\genfrac\empty\empty\zeropoint\displaystyle%
+ {#1\quad\hfill}
+ {\hfill\quad\mathstrut #2}}
+
+%D For thee moment here, but it might move:
+
+%D \macros
+%D {qedsymbol}
+%D
+%D [HH] The general Quod Erat Domonstrandum symbol is defined
+%D in such a way that we can configure it. Because this symbol
+%D is also used in text mode, we make it a normal text symbol
+%D with special behavior.
+
+\unexpanded\def\qedsymbol#1%
+ {\ifhmode
+ \unskip~\hfill#1\par
+ \else\ifmmode
+ \eqno#1\relax % Do we really need the \eqno here?
+ \else
+ \leavevmode\hbox{}\hfill#1\par
+ \fi\fi}
+
+\definesymbol [qed] [\qedsymbol{\mathematics{\square}}]
+
+%D \macros
+%D {QED}
+%D
+%D [HH] For compatbility reasons we also provide the \type
+%D {\QED} command. In case this command is overloaded, we still
+%D have the symbol available. \symbol[qed]
+
+\unexpanded\def\QED{\symbol[qed]}
+
+%D \macros
+%D {mathhexbox}
+%D
+%D [TH] \type {\mathhexbox} is also user||level (already
+%D defined in Plain \TEX). It allows to get a math character
+%D inserted as if it was a text character.
+
+\unexpanded\def\mathhexbox#1#2#3%
+ {\mathtext{$\mathsurround\zeropoint\mathchar"#1#2#3$}}
+
+%D \macros
+%D {boxed}
+%D
+%D [HH] Another macro that users expect (slightly adapted):
+
+\unexpanded\def\boxed
+ {\ifmmode\expandafter\mframed\else\expandafter\framed\fi}
\protect \endinput
diff --git a/tex/context/base/math-frc.mkiv b/tex/context/base/math-frc.mkiv
index 9ef2cc6cf..f6331126f 100644
--- a/tex/context/base/math-frc.mkiv
+++ b/tex/context/base/math-frc.mkiv
@@ -160,7 +160,8 @@
% to be checked:
-\def\exmthfont#1{\symbolicsizedfont#1\plusone{MathExtension}}
+\unexpanded\def\exmthfont#1%
+ {\symbolicsizedfont#1\plusone{MathExtension}}
\def\domthfrac#1#2#3#4#5#6#7%
{\begingroup
@@ -194,18 +195,204 @@
\rlap{\raise\dimexpr\ht2-\ht4\relax\copy4}\copy0}}}%
\endgroup}
-\def\mthfrac#1#2#3#4#5{\mathchoice
+\unexpanded\def\mthfrac#1#2#3#4#5{\mathchoice
{\domthfrac\displaystyle \textface {#1}{#2}{#3}{#4}{#5}}
{\domthfrac\textstyle \textface {#1}{#2}{#3}{#4}{#5}}
{\domthfrac\scriptstyle \scriptface {#1}{#2}{#3}{#4}{#5}}
{\domthfrac\scriptscriptstyle\scriptscriptface{#1}{#2}{#3}{#4}{#5}}}
-\def\mthsqrt#1#2#3{\mathchoice
+\unexpanded\def\mthsqrt#1#2#3{\mathchoice
{\domthsqrt\displaystyle \textface {#1}{#2}{#3}}
{\domthsqrt\textstyle \textface {#1}{#2}{#3}}
{\domthsqrt\scriptstyle \textface {#1}{#2}{#3}}
{\domthsqrt\scriptscriptstyle\textface {#1}{#2}{#3}}}
-% temp here
+%D Moved from math-new.tex (not that new anyway):
+
+%D \macros
+%D {genfrac}
+%D
+%D [TH] The definition of \type {\genfrac} \& co. is not
+%D trivial, because it allows some flexibility. This is
+%D supposed to be a user||level command, but will fail quite
+%D desparately if called outside math mode (\CONTEXT\ redefines
+%D \type {\over})
+%D
+%D [HH] We clean up this macro a bit and (try) to make it
+%D understandable. The expansion is needed for generating
+%D the second argument to \type {\dogenfrac}, which is to
+%D be a control sequence like \type {\over}.
+
+\unexpanded\def\genfrac#1#2#3#4%
+ {\edef\!!stringa
+ {#1#2}%
+ \expanded
+ {\dogenfrac{#4}%
+ \csname
+ \ifx @#3@%
+ \ifx\!!stringa\empty
+ \strippedcsname\normalover
+ \else
+ \strippedcsname\normaloverwithdelims
+ \fi
+ \else
+ \ifx\!!stringa\empty
+ \strippedcsname\normalabove
+ \else
+ \strippedcsname\normalabovewithdelims
+ \fi
+ \fi
+ \endcsname}%
+ {#1#2#3}}
+
+\def\dogenfrac#1#2#3#4#5%
+ {{#1{\begingroup#4\endgroup#2#3\relax#5}}}
+
+%D \macros
+%D {dfrac, tfrac, frac, dbinom, tbinom, binom}
+%D
+%D \startbuffer
+%D $\dfrac {1}{2} \tfrac {1}{2} \frac {1}{2}$
+%D $\dbinom{1}{2} \tbinom{1}{2} \binom{1}{2}$
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+
+\unexpanded\def\dfrac {\genfrac\empty\empty{}\displaystyle}
+\unexpanded\def\tfrac {\genfrac\empty\empty{}\textstyle}
+\unexpanded\def\frac {\genfrac\empty\empty{}\donothing}
+
+\unexpanded\def\dbinom{\genfrac()\zeropoint\displaystyle}
+\unexpanded\def\tbinom{\genfrac()\zeropoint\textstyle}
+\unexpanded\def\binom {\genfrac()\zeropoint\donothing}
+
+\unexpanded\def\xfrac {\genfrac\empty\empty{}\scriptstyle}
+\unexpanded\def\xxfrac{\genfrac\empty\empty{}\scriptscriptstyle}
+
+\unexpanded\def\frac#1#2{\mathematics{\genfrac\empty\empty{}\donothing{#1}{#2}}}
+
+%D \macros
+%D {cfrac}
+%D
+%D \startbuffer
+%D $\cfrac{12}{3} \cfrac[l]{12}{3} \cfrac[c]{12}{3} \cfrac[r]{12}{3}$
+%D $\cfrac{1}{23} \cfrac[l]{1}{23} \cfrac[c]{1}{23} \cfrac[r]{1}{23}$
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D Now we can align every combination we want:
+%D
+%D \startbuffer
+%D $\cfrac{12}{3} \cfrac[l]{12}{3} \cfrac[c]{12}{3} \cfrac[r]{12}{3}$
+%D $\cfrac{1}{23} \cfrac[l]{1}{23} \cfrac[c]{1}{23} \cfrac[r]{1}{23}$
+%D $\cfrac[cl]{12}{3} \cfrac[cc]{12}{3} \cfrac[cr]{12}{3}$
+%D $\cfrac[lc]{1}{23} \cfrac[cc]{1}{23} \cfrac[rc]{1}{23}$
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+
+\definecomplexorsimple\cfrac
+
+\def\simplecfrac {\docfrac[cc]}
+\def\complexcfrac[#1]{\docfrac[#1cc]}
+
+\def\docfrac[#1#2#3]#4#5%
+ {{\displaystyle
+ \frac
+ {\strut
+ \ifx r#1\hfill\fi#4\ifx l#1\hfill\fi}%
+ {\ifx r#2\hfill\fi#5\ifx l#2\hfill\fi}%
+ \kern-\nulldelimiterspace}}
+
+%D \macros
+%D {splitfrac, splitdfrac}
+%D
+%D Occasionally one needs to typeset multi||line fractions.
+%D These commands use \tex{genfrac} to create such fractions.
+%D
+%D \startbuffer
+%D \startformula
+%D a=\frac{
+%D \splitfrac{xy + xy + xy + xy + xy}
+%D {+ xy + xy + xy + xy}
+%D }
+%D {z}
+%D =\frac{
+%D \splitdfrac{xy + xy + xy + xy + xy}
+%D {+ xy + xy + xy + xy}
+%D }
+%D {z}
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D These macros are based on Michael J.~Downes posting on
+%D comp.text.tex on 2001/12/06
+
+\unexpanded\def\splitfrac#1#2%
+ {\genfrac\empty\empty\zeropoint\textstyle%
+ {\textstyle#1\quad\hfill}%
+ {\textstyle\hfill\quad\mathstrut#2}}
+
+\unexpanded\def\splitdfrac#1#2%
+ {\genfrac\empty\empty\zeropoint\displaystyle%
+ {#1\quad\hfill}
+ {\hfill\quad\mathstrut #2}}
+
+%D For thee moment here, but it might move:
+
+%D \macros
+%D {qedsymbol}
+%D
+%D [HH] The general Quod Erat Domonstrandum symbol is defined
+%D in such a way that we can configure it. Because this symbol
+%D is also used in text mode, we make it a normal text symbol
+%D with special behavior.
+
+\unexpanded\def\qedsymbol#1%
+ {\ifhmode
+ \unskip~\hfill#1\par
+ \else\ifmmode
+ \eqno#1\relax % Do we really need the \eqno here?
+ \else
+ \leavevmode\hbox{}\hfill#1\par
+ \fi\fi}
+
+\definesymbol [qed] [\qedsymbol{\mathematics{\square}}]
+
+%D \macros
+%D {QED}
+%D
+%D [HH] For compatbility reasons we also provide the \type
+%D {\QED} command. In case this command is overloaded, we still
+%D have the symbol available. \symbol[qed]
+
+\unexpanded\def\QED{\symbol[qed]}
+
+%D \macros
+%D {mathhexbox}
+%D
+%D [TH] \type {\mathhexbox} is also user||level (already
+%D defined in Plain \TEX). It allows to get a math character
+%D inserted as if it was a text character.
+
+\unexpanded\def\mathhexbox#1#2#3%
+ {\mathtext{$\mathsurround\zeropoint\mathchar"#1#2#3$}}
+
+%D \macros
+%D {boxed}
+%D
+%D [HH] Another macro that users expect (slightly adapted):
+
+\unexpanded\def\boxed
+ {\ifmmode\expandafter\mframed\else\expandafter\framed\fi}
\protect \endinput
diff --git a/tex/context/base/math-ini.lua b/tex/context/base/math-ini.lua
index c34e39bea..b211f7dd2 100644
--- a/tex/context/base/math-ini.lua
+++ b/tex/context/base/math-ini.lua
@@ -367,30 +367,135 @@ function mathematics.big(tfmdata,unicode,n)
return unicode
end
--- plugins
+-- plugins (will be proper handler, once we have separated generic from context)
-local hvars = table.tohash {
- --~ "RadicalKernBeforeDegree",
- --~ "RadicalKernAfterDegree",
+local sequencers = utilities.sequencers
+local appendgroup = sequencers.appendgroup
+local appendaction = sequencers.appendaction
+local mathprocessor = nil
+
+local mathactions = sequencers.reset {
+ arguments = "target,original,directives",
}
-function mathematics.scaleparameters(t,tfmtable,delta,hdelta,vdelta)
- local mathparameters = tfmtable.mathparameters
+function fonts.constructors.mathactions(original,target,directives)
+ if mathactions.dirty then -- maybe use autocompile
+ mathprocessor = sequencers.compile(mathactions)
+ end
+ mathprocessor(original,target,directives or {})
+end
+
+appendgroup(mathactions,"before") -- user
+appendgroup(mathactions,"system") -- private
+appendgroup(mathactions,"after" ) -- user
+
+function mathematics.initializeparameters(target,original,directives)
+ local mathparameters = original.mathparameters
if mathparameters and next(mathparameters) then
- delta = delta or 1
- hdelta, vdelta = hdelta or delta, vdelta or delta
local _, mp = mathematics.dimensions(mathparameters)
- for name, value in next, mp do
- if name == "RadicalDegreeBottomRaisePercent" then
- mp[name] = value
- elseif hvars[name] then
- mp[name] = hdelta * value
- else
- mp[name] = vdelta * value
+ target.mathparameters = mp -- for ourselves
+ target.MathConstants = mp -- for luatex
+ end
+end
+
+sequencers.appendaction(mathactions,"system","mathematics.initializeparameters")
+
+local how = {
+ -- RadicalKernBeforeDegree = "horizontal",
+ -- RadicalKernAfterDegree = "horizontal",
+ RadicalDegreeBottomRaisePercent = "unscaled"
+}
+
+function mathematics.scaleparameters(target,original,directives)
+ if not directives.disablescaling then
+ local mathparameters = target.mathparameters
+ if mathparameters and next(mathparameters) then
+ local parameters = target.parameters
+ local factor = parameters.factor
+ local hfactor = parameters.hfactor
+ local vfactor = parameters.vfactor
+ for name, value in next, mathparameters do
+ local h = how[name]
+ if h == "unscaled" then
+ mathparameters[name] = value
+ elseif h == "horizontal" then
+ mathparameters[name] = value * hfactor
+ elseif h == "vertical"then
+ mathparameters[name] = value * vfactor
+ else
+ mathparameters[name] = value * factor
+ end
+ end
+ end
+ end
+end
+
+sequencers.appendaction(mathactions,"system","mathematics.scaleparameters")
+
+function mathematics.checkaccentbaseheight(target,original,directives)
+ local MathConstants = target.MathConstants
+ if MathConstants then
+ MathConstants.AccentBaseHeight = nil -- safeguard
+ end
+end
+
+sequencers.appendaction(mathactions,"system","mathematics.checkaccentbaseheight")
+
+function mathematics.checkprivateparameters(target,original,directives)
+ local MathConstants = target.MathConstants
+ if MathConstants then
+ if not MathConstants.FractionDelimiterSize then
+ MathConstants.FractionDelimiterSize = 0
+ end
+ if not MathConstants.FractionDelimiterDisplayStyleSize then
+ MathConstants.FractionDelimiterDisplayStyleSize = 0
+ end
+ end
+end
+
+sequencers.appendaction(mathactions,"system","mathematics.checkprivateparameters")
+
+function mathematics.overloadparameters(target,original,directives)
+ local mathparameters = target.mathparameters
+ if mathparameters and next(mathparameters) then
+ local goodies = target.goodies
+ if goodies then
+ for i=1,#goodies do
+ local goodie = goodies[i]
+ local mathematics = goodie.mathematics
+ local parameters = mathematics and mathematics.parameters
+ if parameters then
+ if trace_defining then
+ report_math("overloading math parameters in '%s' @ %s",target.properties.fullname,target.parameters.size)
+ end
+ for name, value in next, parameters do
+ local tvalue = type(value)
+ if tvalue == "string" then
+ report_math("comment for math parameter '%s': %s",name,value)
+ else
+ local oldvalue = mathparameters[name]
+ local newvalue = oldvalue
+ if oldvalue then
+ if tvalue == "number" then
+ newvalue = value
+ elseif tvalue == "function" then
+ newvalue = value(oldvalue,target,original)
+ elseif not tvalue then
+ newvalue = nil
+ end
+ if trace_defining and oldvalue ~= newvalue then
+ report_math("overloading math parameter '%s': %s => %s",name,tostring(oldvalue),tostring(newvalue))
+ end
+ else
+ report_math("invalid math parameter '%s'",name)
+ end
+ mathparameters[name] = newvalue
+ end
+ end
+ end
end
end
- t.MathConstants = mp
end
end
-table.insert(fonts.tfm.mathactions,mathematics.scaleparameters)
+sequencers.appendaction(mathactions,"system","mathematics.overloadparameters")
diff --git a/tex/context/base/math-ini.mkiv b/tex/context/base/math-ini.mkiv
index ce487702d..43e091969 100644
--- a/tex/context/base/math-ini.mkiv
+++ b/tex/context/base/math-ini.mkiv
@@ -498,8 +498,8 @@
\appendtoks
\doifelse{\mathematicsparameter\v!compact}\v!yes
- {\ctxlua{fonts.vf.math.optional=true}}
- {\ctxlua{fonts.vf.math.optional=false}}%
+ {\ctxlua{fonts.handlers.vf.math.optional=true}}
+ {\ctxlua{fonts.handlers.vf.math.optional=false}}%
\to \everysetupmathematics
\setupmathematics
diff --git a/tex/context/base/math-noa.lua b/tex/context/base/math-noa.lua
index 6736181e6..8c9676ca4 100644
--- a/tex/context/base/math-noa.lua
+++ b/tex/context/base/math-noa.lua
@@ -22,51 +22,57 @@ local utfchar, utfbyte = utf.char, utf.byte
local fonts, nodes, node, mathematics = fonts, nodes, node, mathematics
-local set_attribute = node.set_attribute
-local has_attribute = node.has_attribute
-local mlist_to_hlist = node.mlist_to_hlist
-local font_of_family = node.family_font
-local fontdata = fonts.identifiers
+local otf = fonts.handlers.otf
+local otffeatures = fonts.constructors.newfeatures("otf")
+local registerotffeature = otffeatures.register
-noads = noads or { }
-local noads = noads
+local trace_remapping = false trackers.register("math.remapping", function(v) trace_remapping = v end)
+local trace_processing = false trackers.register("math.processing", function(v) trace_processing = v end)
+local trace_analyzing = false trackers.register("math.analyzing", function(v) trace_analyzing = v end)
-noads.processors = noads.processors or { }
-local processors = noads.processors
+local report_processing = logs.reporter("mathematics","processing")
+local report_remapping = logs.reporter("mathematics","remapping")
-noads.handlers = noads.handlers or { }
-local handlers = noads.handlers
+local set_attribute = node.set_attribute
+local has_attribute = node.has_attribute
+local mlist_to_hlist = node.mlist_to_hlist
+local font_of_family = node.family_font
-local tasks = nodes.tasks
+local fonthashes = fonts.hashes
+local fontdata = fonthashes.identifiers
-local trace_remapping = false trackers.register("math.remapping", function(v) trace_remapping = v end)
-local trace_processing = false trackers.register("math.processing", function(v) trace_processing = v end)
-local trace_analyzing = false trackers.register("math.analyzing", function(v) trace_analyzing = v end)
+noads = noads or { } -- todo: only here
+local noads = noads
-local report_processing = logs.reporter("mathematics","processing")
-local report_remapping = logs.reporter("mathematics","remapping")
+noads.processors = noads.processors or { }
+local processors = noads.processors
-local nodecodes = nodes.nodecodes
-local noadcodes = nodes.noadcodes
+noads.handlers = noads.handlers or { }
+local handlers = noads.handlers
-local noad_ord = noadcodes.ord
-local noad_rel = noadcodes.rel
-local noad_punct = noadcodes.punct
+local tasks = nodes.tasks
-local math_noad = nodecodes.noad -- attr nucleus sub sup
-local math_accent = nodecodes.accent -- attr nucleus sub sup accent
-local math_radical = nodecodes.radical -- attr nucleus sub sup left degree
-local math_fraction = nodecodes.fraction -- attr nucleus sub sup left right
-local math_box = nodecodes.subbox -- attr list
-local math_sub = nodecodes.submlist -- attr list
-local math_char = nodecodes.mathchar -- attr fam char
-local math_textchar = nodecodes.mathtextchar -- attr fam char
-local math_delim = nodecodes.delim -- attr small_fam small_char large_fam large_char
-local math_style = nodecodes.style -- attr style
-local math_choice = nodecodes.choice -- attr display text script scriptscript
-local math_fence = nodecodes.fence -- attr subtype
+local nodecodes = nodes.nodecodes
+local noadcodes = nodes.noadcodes
-local left_fence_code = 1
+local noad_ord = noadcodes.ord
+local noad_rel = noadcodes.rel
+local noad_punct = noadcodes.punct
+
+local math_noad = nodecodes.noad -- attr nucleus sub sup
+local math_accent = nodecodes.accent -- attr nucleus sub sup accent
+local math_radical = nodecodes.radical -- attr nucleus sub sup left degree
+local math_fraction = nodecodes.fraction -- attr nucleus sub sup left right
+local math_box = nodecodes.subbox -- attr list
+local math_sub = nodecodes.submlist -- attr list
+local math_char = nodecodes.mathchar -- attr fam char
+local math_textchar = nodecodes.mathtextchar -- attr fam char
+local math_delim = nodecodes.delim -- attr small_fam small_char large_fam large_char
+local math_style = nodecodes.style -- attr style
+local math_choice = nodecodes.choice -- attr display text script scriptscript
+local math_fence = nodecodes.fence -- attr subtype
+
+local left_fence_code = 1
local function process(start,what,n,parent)
if n then n = n + 1 else n = 0 end
@@ -147,7 +153,7 @@ local function report_remap(tag,id,old,new,extra)
end
local remapalphabets = mathematics.remapalphabets
-local fcs = fonts.colors.set
+local setnodecolor = nodes.tracers.colors.set
-- we can have a global famdata == fonts.famdata
@@ -168,7 +174,7 @@ local fcs = fonts.colors.set
--~ report_remap("fallback",id,char,newchar)
--~ end
--~ if trace_analyzing then
---~ fcs(pointer,"font:isol")
+--~ setnodecolor(pointer,"font:isol")
--~ end
--~ pointer.char = newchar
--~ return true
@@ -206,7 +212,7 @@ processors.relocate[math_char] = function(pointer)
report_remap("char",id,char,newchar)
end
if trace_analyzing then
- fcs(pointer,"font:isol")
+ setnodecolor(pointer,"font:isol")
end
pointer.char = newchar
return true
@@ -220,19 +226,19 @@ processors.relocate[math_char] = function(pointer)
-- return checked(pointer)
end
if trace_analyzing then
- fcs(pointer,"font:medi")
+ setnodecolor(pointer,"font:medi")
end
end
processors.relocate[math_textchar] = function(pointer)
if trace_analyzing then
- fcs(pointer,"font:init")
+ setnodecolor(pointer,"font:init")
end
end
processors.relocate[math_delim] = function(pointer)
if trace_analyzing then
- fcs(pointer,"font:fina")
+ setnodecolor(pointer,"font:fina")
end
end
@@ -390,11 +396,12 @@ function noads.handlers.collapse(head,style,penalties)
return true
end
--- math alternates
+-- math alternates: (in xits lgf: $ABC$ $\cal ABC$ $\mathalternate{cal}\cal ABC$)
-function fonts.initializers.common.mathalternates(tfmdata)
+local function initializemathalternates(tfmdata)
local goodies = tfmdata.goodies
if goodies then
+ local shared = tfmdata.shared
for i=1,#goodies do
-- first one counts
-- we can consider sharing the attributes ... todo (only once scan)
@@ -407,23 +414,24 @@ function fonts.initializers.common.mathalternates(tfmdata)
v.attribute = lastattribute
attributes[lastattribute] = v
end
- tfmdata.shared.mathalternates = alternates -- to be checked if shared is ok here
- tfmdata.shared.mathalternatesattributes = attributes -- to be checked if shared is ok here
+ shared.mathalternates = alternates -- to be checked if shared is ok here
+ shared.mathalternatesattributes = attributes -- to be checked if shared is ok here
return
end
end
end
end
-fonts.otf.tables.features['mathalternates'] = 'Additional math alternative shapes'
-
-fonts.otf.features.register('mathalternates') -- true
-table.insert(fonts.triggers,"mathalternates")
-
-fonts.initializers.base.otf.mathalternates = fonts.initializers.common.mathalternates
-fonts.initializers.node.otf.mathalternates = fonts.initializers.common.mathalternates
+registerotffeature {
+ name = "mathalternates",
+ description = "additional math alternative shapes",
+ initializers = {
+ base = initializemathalternates,
+ node = initializemathalternates,
+ }
+}
-local getalternate = fonts.otf.getalternate
+local getalternate = otf.getalternate
local mathalternate = attributes.private("mathalternate")
diff --git a/tex/context/base/math-vfu.lua b/tex/context/base/math-vfu.lua
index e072fe83b..b13f1804e 100644
--- a/tex/context/base/math-vfu.lua
+++ b/tex/context/base/math-vfu.lua
@@ -20,16 +20,16 @@ local report_virtual = logs.reporter("fonts","virtual math")
local fonts, nodes, mathematics = fonts, nodes, mathematics
-local mathencodings = utilities.storage.allocate { }
+local allocate = utilities.storage.allocate
-fonts.enc.math = mathencodings -- better is then: fonts.enc.vectors
+local mathencodings = allocate()
+fonts.encodings.math = mathencodings -- better is then: fonts.encodings.vectors
+local vfmath = allocate()
+fonts.handlers.vf.math = vfmath
-local shared = { }
+vfmath.optional = false
-fonts.vf.math = fonts.vf.math or { }
-local vfmath = fonts.vf.math
-
-vfmath.optional = false
+local shared = { }
--~ local push, pop, back = { "push" }, { "pop" }, { "slot", 1, 0x2215 }
@@ -293,9 +293,10 @@ local function stack(main,characters,id,size,unicode,u1,d12,u2)
end
end
-function vfmath.alas(main,id,size,variables)
+function vfmath.alas(main,id,size)
local characters = main.characters
local shared = main.shared
+ local variables = main.goodies.mathematics and main.goodies.mathematics.variables or { }
local joinrelfactor = variables.joinrelfactor or 3
for i=0x7A,0x7D do
make(main,characters,id,size,i,1)
@@ -342,36 +343,6 @@ end
local unique = 0 -- testcase: \startTEXpage \math{!\text{-}\text{-}\text{-}} \stopTEXpage
-function fonts.basecopy(tfmtable,name)
- local characters, parameters, fullname = tfmtable.characters, tfmtable.parameters, tfmtable.fullname
- local t, c, p = { }, { }, { }
- for k, v in next, tfmtable do
- t[k] = v
- end
- if characters then
- for k, v in next, characters do
- c[k] = v
- end
- t.characters = c
- else
- report_virtual("font %s has no characters",name)
- end
- if parameters then
- for k, v in next, parameters do
- p[k] = v
- end
- t.parameters = p
- else
- report_virtual("font %s has no parameters",name)
- end
- -- tricky ... what if fullname does not exist
- if fullname then
- unique = unique + 1
- t.fullname = fullname .. "-" .. unique
- end
- return t
-end
-
local reported = { }
local reverse = { } -- index -> unicode
@@ -387,11 +358,14 @@ setmetatable ( reverse, { __index = function(t,name)
return r
end } )
-function vfmath.define(specification,set,variables)
- variables = variables or { }
+local mathdirectives = {
+ disablescaling = true
+}
+
+function vfmath.define(specification,set,goodies)
local name = specification.name -- symbolic name
local size = specification.size -- given size
- local fnt, lst, main = { }, { }, nil
+ local loaded, fontlist, main = { }, { }, nil
local start = (trace_virtual or trace_timings) and os.clock()
local okset, n = { }, 0
for s=1,#set do
@@ -402,16 +376,20 @@ function vfmath.define(specification,set,variables)
report_virtual("loading font %s subfont %s with name %s at %s is skipped",name,s,ssname,size)
end
else
- if ss.features then ssname = ssname .. "*" .. ss.features end
- if ss.main then main = s end
- local f, id = fonts.tfm.readanddefine(ssname,size)
+ if ss.features then
+ ssname = ssname .. "*" .. ss.features
+ end
+ if ss.main then
+ main = s
+ end
+ local f, id = fonts.constructors.readanddefine(ssname,size)
if not f then
report_virtual("loading font %s subfont %s with name %s at %s is skipped, not found",name,s,ssname,size)
else
n = n + 1
okset[n] = ss
- fnt[n] = f
- lst[n] = { id = id, size = size }
+ loaded[n] = f
+ fontlist[n] = { id = id, size = size }
if not shared[s] then shared[n] = { } end
if trace_virtual then
report_virtual("loading font %s subfont %s with name %s at %s as id %s using encoding %s",name,s,ssname,size,id,ss.vector or "none")
@@ -442,55 +420,117 @@ function vfmath.define(specification,set,variables)
end
end
end
- -- beware, fnt[1] is already passed to tex (we need to make a simple copy then .. todo)
- main = fonts.basecopy(fnt[1],name)
- main.name, main.fonts, main.virtualized, main.mathparameters = name, lst, true, { }
- local characters, descriptions = main.characters, main.descriptions
- local mp = main.parameters
- if mp then
- mp.x_height = mp.x_height or 0
+ -- beware, loaded[1] is already passed to tex (we need to make a simple copy then .. todo)
+ local parent = loaded[1] -- a text font
+ local characters = { }
+ local parameters = { }
+ local mathparameters = { }
+ local descriptions = { }
+ local metadata = { }
+ local properties = { }
+ local goodies = { }
+ local main = {
+ metadata = metadata,
+ properties = properties,
+ characters = characters,
+ descriptions = descriptions,
+ parameters = parameters,
+ mathparameters = mathparameters,
+ fonts = fontlist,
+ goodies = goodies,
+ }
+ --
+ --
+ for key, value in next, parent do
+ if type(value) ~= "table" then
+ main[key] = value
+ end
+ end
+ --
+ if parent.characters then
+ for unicode, character in next, parent.characters do
+ characters[unicode] = character
+ end
+ else
+ report_virtual("font %s has no characters",name)
+ end
+ --
+ if parent.parameters then
+ for key, value in next, parent.parameters do
+ parameters[key] = value
+ end
+ else
+ report_virtual("font %s has no parameters",name)
+ end
+ --
+ local description = { name = "<unset>" }
+ setmetatable(descriptions, { __index = function() return description end })
+ --
+ if parent.properties then
+ setmetatable(properties, { __index = parent.properties })
+ end
+ --
+ if parent.goodies then
+ setmetatable(goodies, { __index = parent.goodies })
end
+ --
+ properties.virtualized = true
+ properties.italic_correction = true
+ properties.has_math = true
+ --
+ local fullname = properties.fullname -- parent via mt
+ if fullname then
+ unique = unique + 1
+ properties.fullname = fullname .. "-" .. unique
+ end
+ --
+ -- we need to set some values in main as well (still?)
+ --
+ main.fullname = properties.fullname
+ main.type = "virtual"
+ main.nomath = false
+ --
+ parameters.x_height = parameters.x_height or 0
+ --
local already_reported = false
for s=1,n do
- local ss, fs = okset[s], fnt[s]
+ local ss, fs = okset[s], loaded[s]
if not fs then
-- skip, error
elseif ss.optional and vfmath.optional then
-- skip, redundant
else
- local mm, fp = main.mathparameters, fs.parameters
- if mm and fp and mp then
- if ss.extension then
- mm.math_x_height = fp.x_height or 0 -- math_x_height height of x
- mm.default_rule_thickness = fp[ 8] or 0 -- default_rule_thickness thickness of \over bars
- mm.big_op_spacing1 = fp[ 9] or 0 -- big_op_spacing1 minimum clearance above a displayed op
- mm.big_op_spacing2 = fp[10] or 0 -- big_op_spacing2 minimum clearance below a displayed op
- mm.big_op_spacing3 = fp[11] or 0 -- big_op_spacing3 minimum baselineskip above displayed op
- mm.big_op_spacing4 = fp[12] or 0 -- big_op_spacing4 minimum baselineskip below displayed op
- mm.big_op_spacing5 = fp[13] or 0 -- big_op_spacing5 padding above and below displayed limits
- -- report_virtual("loading and virtualizing font %s at size %s, setting ex parameters",name,size)
- elseif ss.parameters then
- mp.x_height = fp.x_height or mp.x_height
- mm.x_height = mm.x_height or fp.x_height or 0 -- x_height height of x
- mm.num1 = fp[ 8] or 0 -- num1 numerator shift-up in display styles
- mm.num2 = fp[ 9] or 0 -- num2 numerator shift-up in non-display, non-\atop
- mm.num3 = fp[10] or 0 -- num3 numerator shift-up in non-display \atop
- mm.denom1 = fp[11] or 0 -- denom1 denominator shift-down in display styles
- mm.denom2 = fp[12] or 0 -- denom2 denominator shift-down in non-display styles
- mm.sup1 = fp[13] or 0 -- sup1 superscript shift-up in uncramped display style
- mm.sup2 = fp[14] or 0 -- sup2 superscript shift-up in uncramped non-display
- mm.sup3 = fp[15] or 0 -- sup3 superscript shift-up in cramped styles
- mm.sub1 = fp[16] or 0 -- sub1 subscript shift-down if superscript is absent
- mm.sub2 = fp[17] or 0 -- sub2 subscript shift-down if superscript is present
- mm.sup_drop = fp[18] or 0 -- sup_drop superscript baseline below top of large box
- mm.sub_drop = fp[19] or 0 -- sub_drop subscript baseline below bottom of large box
- mm.delim1 = fp[20] or 0 -- delim1 size of \atopwithdelims delimiters in display styles
- mm.delim2 = fp[21] or 0 -- delim2 size of \atopwithdelims delimiters in non-displays
- mm.axis_height = fp[22] or 0 -- axis_height height of fraction lines above the baseline
- -- report_virtual("loading and virtualizing font %s at size %s, setting sy parameters",name,size)
- end
- else
+ local newparameters = fs.parameters
+ if not newparameters then
report_virtual("font %s, no parameters set",name)
+ elseif ss.extension then
+ mathparameters.math_x_height = newparameters.x_height or 0 -- math_x_height : height of x
+ mathparameters.default_rule_thickness = newparameters[ 8] or 0 -- default_rule_thickness : thickness of \over bars
+ mathparameters.big_op_spacing1 = newparameters[ 9] or 0 -- big_op_spacing1 : minimum clearance above a displayed op
+ mathparameters.big_op_spacing2 = newparameters[10] or 0 -- big_op_spacing2 : minimum clearance below a displayed op
+ mathparameters.big_op_spacing3 = newparameters[11] or 0 -- big_op_spacing3 : minimum baselineskip above displayed op
+ mathparameters.big_op_spacing4 = newparameters[12] or 0 -- big_op_spacing4 : minimum baselineskip below displayed op
+ mathparameters.big_op_spacing5 = newparameters[13] or 0 -- big_op_spacing5 : padding above and below displayed limits
+ -- report_virtual("loading and virtualizing font %s at size %s, setting ex parameters",name,size)
+ elseif ss.parameters then
+ mathparameters.x_height = newparameters.x_height or mathparameters.x_height
+ mathparameters.x_height = mathparameters.x_height or fp.x_height or 0 -- x_height : height of x
+ mathparameters.num1 = newparameters[ 8] or 0 -- num1 : numerator shift-up in display styles
+ mathparameters.num2 = newparameters[ 9] or 0 -- num2 : numerator shift-up in non-display, non-\atop
+ mathparameters.num3 = newparameters[10] or 0 -- num3 : numerator shift-up in non-display \atop
+ mathparameters.denom1 = newparameters[11] or 0 -- denom1 : denominator shift-down in display styles
+ mathparameters.denom2 = newparameters[12] or 0 -- denom2 : denominator shift-down in non-display styles
+ mathparameters.sup1 = newparameters[13] or 0 -- sup1 : superscript shift-up in uncramped display style
+ mathparameters.sup2 = newparameters[14] or 0 -- sup2 : superscript shift-up in uncramped non-display
+ mathparameters.sup3 = newparameters[15] or 0 -- sup3 : superscript shift-up in cramped styles
+ mathparameters.sub1 = newparameters[16] or 0 -- sub1 : subscript shift-down if superscript is absent
+ mathparameters.sub2 = newparameters[17] or 0 -- sub2 : subscript shift-down if superscript is present
+ mathparameters.sup_drop = newparameters[18] or 0 -- sup_drop : superscript baseline below top of large box
+ mathparameters.sub_drop = newparameters[19] or 0 -- sub_drop : subscript baseline below bottom of large box
+ mathparameters.delim1 = newparameters[20] or 0 -- delim1 : size of \atopwithdelims delimiters in display styles
+ mathparameters.delim2 = newparameters[21] or 0 -- delim2 : size of \atopwithdelims delimiters in non-displays
+ mathparameters.axis_height = newparameters[22] or 0 -- axis_height : height of fraction lines above the baseline
+ -- report_virtual("loading and virtualizing font %s at size %s, setting sy parameters",name,size)
end
local vectorname = ss.vector
if vectorname then
@@ -503,7 +543,7 @@ function vfmath.define(specification,set,variables)
for unicode, index in next, vector do
local fci = fc[index]
if not fci then
- local fontname = fs.name or "unknown"
+ local fontname = fs.properties.name or "unknown"
local rf = reported[fontname]
if not rf then rf = { } reported[fontname] = rf end
local rv = rf[vectorname]
@@ -672,26 +712,30 @@ function vfmath.define(specification,set,variables)
mathematics.extras.copy(main) --not needed here (yet)
end
end
- lst[#lst+1] = { id = font.nextid(), size = size }
- if mp then -- weak catch
- vfmath.alas(main,#lst,size,variables)
+ --
+ fontlist[#fontlist+1] = {
+ id = font.nextid(),
+ size = size,
+ }
+ --
+ if mathparameters then -- weak catch ? ? ?
+ vfmath.alas(main,#fontlist,size)
end
+ --
mathematics.addfallbacks(main)
+ --
if trace_virtual or trace_timings then
report_virtual("loading and virtualizing font %s at size %s took %0.3f seconds",name,size,os.clock()-start)
end
- main.has_italic = true
- main.type = "virtual" -- not needed
- mathematics.scaleparameters(main,main,1)
- main.nomath = false
- -- table.print(characters[0x222B])
- -- table.print(main.MathConstants)
+ --
+ fonts.constructors.mathactions(main,main,mathdirectives)
+ --
return main
end
-function mathematics.makefont(name, set, variables)
+function mathematics.makefont(name,set,goodies)
fonts.definers.methods.variants[name] = function(specification)
- return vfmath.define(specification,set,variables)
+ return vfmath.define(specification,set,goodies)
end
end
diff --git a/tex/context/base/meta-imp-dum.mkiv b/tex/context/base/meta-imp-dum.mkiv
index bc19f3c5f..60ab0a41d 100644
--- a/tex/context/base/meta-imp-dum.mkiv
+++ b/tex/context/base/meta-imp-dum.mkiv
@@ -34,26 +34,50 @@
% fractions like reduction
% June 22, 2003, this definition was patched to adapt itself
-% to transparent colors
+% 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{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) ;
+ 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) ;
- cc := r[.5c,b] ;
- fill p withcolor if t : transparent(1,.5,cc) else : cc fi ;
+ fill p withcolor r[.5c,b] ;
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 ;
+ withcolor r[c randomized(.3,.9),b] ;
endfor ;
clip currentpicture to p ;
\stopuseMPgraphic
diff --git a/tex/context/base/mlib-pps.lua b/tex/context/base/mlib-pps.lua
index a8cdf7275..e1f85e804 100644
--- a/tex/context/base/mlib-pps.lua
+++ b/tex/context/base/mlib-pps.lua
@@ -19,7 +19,7 @@ local lpegmatch = lpeg.match
local texbox = tex.box
local copy_list, free_list = node.copy_list, node.flush_list
-local Cs, Cf, C, Cg, Ct, P, S, V = lpeg.Cs, lpeg.Cf, lpeg.C, lpeg.Cg, lpeg.Ct, lpeg.P, lpeg.S, lpeg.V
+local Cs, Cf, C, Cg, Ct, P, S, V, Carg = lpeg.Cs, lpeg.Cf, lpeg.C, lpeg.Cg, lpeg.Ct, lpeg.P, lpeg.S, lpeg.V, lpeg.Carg
local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming
@@ -95,9 +95,9 @@ end
--~
-local specificationsplitter = lpeg.Ct(lpeg.splitat(" "))
-local colorsplitter = lpeg.Ct(lpeg.splitter(":",tonumber)) -- no need for :
-local domainsplitter = lpeg.Ct(lpeg.splitter(" ",tonumber))
+local specificationsplitter = Ct(lpeg.splitat(" "))
+local colorsplitter = Ct(lpeg.splitter(":",tonumber)) -- no need for :
+local domainsplitter = Ct(lpeg.splitter(" ",tonumber))
local centersplitter = domainsplitter
local coordinatesplitter = domainsplitter
@@ -821,24 +821,23 @@ end
local function fg_process(object,prescript,before,after)
local fg_name = prescript.fg_name
if fg_name then
- -- now uses textext
- local op = object.path
- local first, second, fourth = op[1], op[2], op[4]
- local tx, ty = first.x_coord , first.y_coord
- local sx, sy = second.x_coord - tx, fourth.y_coord - ty
- local rx, ry = second.y_coord - ty, fourth.x_coord - tx
- if sx == 0 then sx = 0.00001 end
- if sy == 0 then sy = 0.00001 end
- object.path = nil
+ before[#before+1] = format("q %f %f %f %f %f %f cm",cm(object))
before[#before+1] = function()
- context.MPLIBfigure(sx,rx,ry,sy,tx,ty,fg_name)
+ context.MPLIBfigure(fg_name,prescript.fg_mask or "")
end
+ before[#before+1] = "Q"
+ object.path = false
object.grouped = true
end
end
-- color and transparency
+local value = Cs ( (
+ (Carg(1) * C((1-P(","))^1)) / function(a,b) return format("%0.3f",a * tonumber(b)) end
+ + P(","))^1
+)
+
local function tr_process(object,prescript,before,after)
local cs = object.color
if cs and #cs > 0 then
@@ -853,8 +852,12 @@ local function tr_process(object,prescript,before,after)
if sp_name then
local sp_fractions = prescript.sp_fractions or 1
local sp_components = prescript.sp_components or ""
- local sp_value = prescript.sp_value or 1
- sp_value = tonumber(sp_value) * cs[1]
+ local sp_value = prescript.sp_value or "1"
+ local cf = cs[1]
+ if cf ~= 1 then
+ -- beware, we do scale the spotcolors but not the alternative representation
+ sp_value = lpeg.match(value,sp_value,1,cf) or sp_value
+ end
before[#before+1], after[#after+1] = spotcolorconverter(sp_name,sp_fractions,sp_components,sp_value)
else
before[#before+1], after[#after+1] = colorconverter(cs)
diff --git a/tex/context/base/mlib-pps.mkiv b/tex/context/base/mlib-pps.mkiv
index d131e9117..357f85b1a 100644
--- a/tex/context/base/mlib-pps.mkiv
+++ b/tex/context/base/mlib-pps.mkiv
@@ -33,12 +33,10 @@
\newbox \MPtextbox
\newtoks\everyMPLIBsettext
-\def\MPLIBfigure#1#2#3#4#5#6#7% todo: move Q q to lua
- {\setbox\scratchbox\hbox{\externalfigure[#7]}%
+\def\MPLIBfigure#1#2%
+ {\setbox\scratchbox\hbox{\externalfigure[#1][\c!mask=#2]}%
\ctxlua{metapost.edefsxsy(\number\wd\scratchbox,\number\ht\scratchbox,0)}%
- \pdfliteral direct{q #1 #2 #3 #4 #5 #6 cm}% no direct
- \vbox to \zeropoint{\vss\hbox to \zeropoint{\scale[sx=\sx,sy=\sy]{\box\scratchbox}\hss}}%
- \pdfliteral direct{Q}}
+ \vbox to \zeropoint{\vss\hbox to \zeropoint{\scale[\c!sx=\sx,\c!sy=\sy]{\box\scratchbox}\hss}}}
\def\MPLIBsettext#1% #2%
{\dowithnextbox{\ctxlua{metapost.settext(\number\nextbox,#1)}}\hbox}
diff --git a/tex/context/base/mult-aux.mkiv b/tex/context/base/mult-aux.mkiv
index 473a18e08..4087180c0 100644
--- a/tex/context/base/mult-aux.mkiv
+++ b/tex/context/base/mult-aux.mkiv
@@ -52,23 +52,26 @@
%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
-\unexpanded\def\doinstallparameterhandler#1#2#3#4#5#6#7#8#9%
- {\def#3##1{\csname#4{#1#2}{##1}\endcsname}%
+\unexpanded\def\doinstallparameterhandler#1#2#3#4#5#6#7%
+ {\ifx#2\relax\let#2\empty\fi
+ \def#3##1{\csname#4{#1#2}{##1}\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\s!empty\else#4{##1}{##2}\fi}%
\def#6##1##2{\csname#4{#1##1}{##2}\endcsname}%
- \def#7##1{\detokenize\expandafter\expandafter\expandafter{\csname#1##1\endcsname}}% always root
- \def#8{\dosetvalue{#1}}% ##1 {##2} (braces are mandate)
- \def#9{\doletvalue{#1}}}% ##1 ##2
+ \def#7##1{\detokenize\expandafter\expandafter\expandafter{\csname#1##1\endcsname}}} % always root
\unexpanded\def\installparameterhandler#1#2%
- {%\message{\detokenize{#1}/\detokenize{#2}}%
- \normalexpanded
+ {\normalexpanded
{\doinstallparameterhandler
{\noexpand#1}% \??aa
\expandafter\noexpand\csname current#2\endcsname
@@ -76,12 +79,11 @@
\expandafter\noexpand\csname do#2parameter\endcsname
\expandafter\noexpand\csname do#2parentparameter\endcsname
\expandafter\noexpand\csname named#2parameter\endcsname
- \expandafter\noexpand\csname detokenized#2parameter\endcsname
- \expandafter\noexpand\csname doset#2parameter\endcsname
- \expandafter\noexpand\csname dolet#2parameter\endcsname}}
+ \expandafter\noexpand\csname detokenized#2parameter\endcsname}}
\unexpanded\def\doinstallparameterhashhandler#1#2#3#4#5%
- {\def#3##1{#4{#1#2}{##1}}%
+ {\ifx#2\relax\let#2\empty\fi
+ \def#3##1{#4{#1#2}{##1}}%
\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}}
@@ -94,6 +96,21 @@
\expandafter\noexpand\csname do#2parameterhash\endcsname
\expandafter\noexpand\csname do#2parentparameterhash\endcsname}}
+\unexpanded\def\doinstallparametersethandler#1#2#3#4#5%
+ {\ifx#2\relax\let#2\empty\fi
+ \def#3{\dosetvalue{#1#2}}% ##1 {##2} (braces are mandate)
+ \def#4{\doletvalue{#1#2}}% ##1 ##2
+ \def#5{\doletvalue{#1#2}\empty}}% ##1
+
+\unexpanded\def\installparametersethandler#1#2%
+ {\normalexpanded
+ {\doinstallparametersethandler
+ {\noexpand#1}% \??aa
+ \expandafter\noexpand\csname current#2\endcsname
+ \expandafter\noexpand\csname set#2parameter\endcsname
+ \expandafter\noexpand\csname let#2parameter\endcsname
+ \expandafter\noexpand\csname reset#2parameter\endcsname}}
+
\unexpanded\def\doinstallattributehandler#1#2#3% #1 not used here
{\def#2##1##2% style color
{\edef\fontattributehash {#3{##1}}%
@@ -108,23 +125,32 @@
\expandafter\noexpand\csname doset#2attributes\endcsname
\expandafter\noexpand\csname #2parameterhash\endcsname}}
-\unexpanded\def\doinstalldefinehandler#1#2#3#4#5#6#7%
- {\unexpanded\def#2{\dotripleempty#5}%
+\let\definehandlerparent\empty
+
+\unexpanded\def\doinstalldefinehandler#1#2#3#4#5#6#7#8%
+ {\ifx#4\relax\let#4\empty\fi
+ \unexpanded\def#2{\dotripleempty#5}%
\newtoks#6%
\newtoks#7%
- \def#5[##1][##2][##3]% [child][parent][settings]
- {\edef#4{##1}% % [child] [settings]
- \the#6% predefine % [child][parent]
- \ifthirdargument % [child]
+ \def#5[##1][##2][##3]% [child][parent][settings] | [child][settings] | [child][parent] | [child]
+ {\let\saveddefinewhatever#4%
+ \edef#4{##1}%
+ \the#6% predefine
+ \ifthirdargument
+ \edef#8{##2}%
\getparameters[#1#4][\s!parent=#1##2,##3]%
\else\ifsecondargument
\doifassignmentelse{##2}
- {\getparameters[#1#4][\s!parent=#3,##2]}
- {\getparameters[#1#4][\s!parent=#1##2]}%
+ {\let#8\empty
+ \getparameters[#1#4][\s!parent=#3,##2]}
+ {\edef#8{##2}%
+ \getparameters[#1#4][\s!parent=#1##2]}%
\else
+ \let#8\empty
\getparameters[#1#4][\s!parent=#3]%
\fi\fi
- \the#7}}
+ \the#7%
+ \let#4\saveddefinewhatever}}
\unexpanded\def\installdefinehandler#1#2#3%
{\normalexpanded
@@ -135,13 +161,17 @@
\expandafter\noexpand\csname current#2\endcsname
\expandafter\noexpand\csname d@define#2\endcsname
\expandafter\noexpand\csname everypreset#2\endcsname
- \expandafter\noexpand\csname everydefine#2\endcsname}}
+ \expandafter\noexpand\csname everydefine#2\endcsname
+ \expandafter\noexpand\csname current#2parent\endcsname}}
-\unexpanded\def\doinstallsetuphandler#1#2#3#4#5%
- {\unexpanded\def#2{\dodoubleempty#4}%
+\unexpanded\def\doinstallsetuphandler#1#2#3#4#5#6%
+ {\ifx#3\relax\let#3\empty\fi
+ \unexpanded\def#2{\dodoubleempty#4}%
+ \unexpanded\def#6{\getparameters[#1#3]}%
\newtoks#5%
\def#4[##1][##2]% maybe helper
- {\ifsecondargument
+ {\let\savedsetupwhatever#3%
+ \ifsecondargument
\def\docommand####1% we will have a simple one as well
{\edef#3{####1}%
\getparameters[#1#3][##2]%
@@ -151,7 +181,8 @@
\let#3\empty
\getparameters[#1][##1]%
\the#5%
- \fi}}
+ \fi
+ \let#3\savedsetupwhatever}}
\unexpanded\def\installsetuphandler#1#2%
{\normalexpanded
@@ -160,11 +191,13 @@
\expandafter\noexpand\csname setup#2\endcsname
\expandafter\noexpand\csname current#2\endcsname
\expandafter\noexpand\csname d@setup#2\endcsname
- \expandafter\noexpand\csname everysetup#2\endcsname}}
+ \expandafter\noexpand\csname everysetup#2\endcsname
+ \expandafter\noexpand\csname setupcurrent#2\endcsname}}
\unexpanded\def\installcommandhandler#1#2#3% \??self name \??parent (can be \??self)
{\installparameterhandler {#1}{#2}%
\installparameterhashhandler{#1}{#2}%
+ \installparametersethandler {#1}{#2}%
\installdefinehandler {#1}{#2}{#3}%
\installsetuphandler {#1}{#2}%
\installattributehandler {#1}{#2}}
@@ -216,5 +249,20 @@
\def\listnamespaces
{\ctxlua{interfaces.namespaces.list()}}
+%D Helper:
+%D
+%D \starttyping
+%D \showparentchain{@@am}{left}
+%D \stoptyping
+
+\def\doshowparentchain#1%
+ {#1 => %
+ \ifcsname#1\s!parent\endcsname
+ \expandafter\doshowparentchain\csname#1\s!parent\endcsname
+ \fi}
+
+\def\showparentchain#1#2%
+ {\writestatus\m!system{chain: [ \doshowparentchain{#1#2}]}}
+
\protect
diff --git a/tex/context/base/mult-chk.lua b/tex/context/base/mult-chk.lua
index efe17db34..4b1ba12ee 100644
--- a/tex/context/base/mult-chk.lua
+++ b/tex/context/base/mult-chk.lua
@@ -22,14 +22,14 @@ interfaces.syntax = allocate {
test = { keys = table.tohash { "a","b","c","d","e","f","g" } }
}
-function interfaces.invalidkey(kind,key)
- report_interface("invalid key '%s' for '%s' in line %s",key,kind,tex.inputlineno)
+function interfaces.invalidkey(category,key)
+ report_interface("invalid key '%s' for '%s' in line %s",key,category,tex.inputlineno)
end
-function interfaces.setvalidkeys(kind,list)
- local s = interfaces.syntax[kind]
+function interfaces.setvalidkeys(category,list)
+ local s = interfaces.syntax[category]
if not s then
- interfaces.syntax[kind] = {
+ interfaces.syntax[category] = {
keys = settings_to_set(list)
}
else
@@ -37,10 +37,10 @@ function interfaces.setvalidkeys(kind,list)
end
end
-function interfaces.addvalidkeys(kind,list)
- local s = interfaces.syntax[kind]
+function interfaces.addvalidkeys(category,list)
+ local s = interfaces.syntax[category]
if not s then
- interfaces.syntax[kind] = {
+ interfaces.syntax[category] = {
keys = settings_to_set(list)
}
else
@@ -50,11 +50,11 @@ end
-- weird code, looks incomplete ... probbably an experiment
-local prefix, kind, keys
+local prefix, category, keys
local function set(key,value)
if keys and not keys[key] then
- interfaces.invalidkey(kind,key)
+ interfaces.invalidkey(category,key)
else
context.setsomevalue(prefix,key,value)
end
@@ -64,7 +64,7 @@ local pattern = make_settings_to_hash_pattern(set,"tolerant")
function interfaces.getcheckedparameters(k,p,s)
if s and s ~= "" then
- prefix, kind = p, k
+ prefix, category = p, k
keys = k and k ~= "" and interfaces.syntax[k].keys
lpegmatch(pattern,s)
end
diff --git a/tex/context/base/mult-de.mkii b/tex/context/base/mult-de.mkii
index 494df52bd..1ac862210 100644
--- a/tex/context/base/mult-de.mkii
+++ b/tex/context/base/mult-de.mkii
@@ -75,6 +75,7 @@
\setinterfacevariable{april}{April}
\setinterfacevariable{atmargin}{amrand}
\setinterfacevariable{atpage}{aufseite}
+\setinterfacevariable{attachment}{attachment}
\setinterfacevariable{august}{August}
\setinterfacevariable{author}{autor}
\setinterfacevariable{auto}{auto}
@@ -525,6 +526,7 @@
\setinterfaceconstant{after}{nach}
\setinterfaceconstant{afterhead}{nachkopf}
\setinterfaceconstant{afterkey}{nachtaste}
+\setinterfaceconstant{aftersection}{aftersection}
\setinterfaceconstant{align}{ausrichtung}
\setinterfaceconstant{aligncharacter}{aligncharacter}
\setinterfaceconstant{alignmentcharacter}{alignmentcharacter}
@@ -563,6 +565,7 @@
\setinterfaceconstant{balance}{ausgleichen}
\setinterfaceconstant{before}{vor}
\setinterfaceconstant{beforehead}{vorkopf}
+\setinterfaceconstant{beforesection}{beforesection}
\setinterfaceconstant{bet}{bet}
\setinterfaceconstant{big}{gross}
\setinterfaceconstant{blank}{blanko}
@@ -577,6 +580,7 @@
\setinterfaceconstant{bottomoffset}{untenoffset}
\setinterfaceconstant{bottomspace}{bottomspace}
\setinterfaceconstant{bottomstate}{untenstatus}
+\setinterfaceconstant{buffer}{buffer}
\setinterfaceconstant{cache}{cache}
\setinterfaceconstant{calculate}{berechnen}
\setinterfaceconstant{category}{category}
@@ -587,6 +591,7 @@
\setinterfaceconstant{clipoffset}{clipoffset}
\setinterfaceconstant{closeaction}{schliessenaktion}
\setinterfaceconstant{closecommand}{closecommand}
+\setinterfaceconstant{closepage}{closepage}
\setinterfaceconstant{closepageaction}{closepageaction}
\setinterfaceconstant{closesymbol}{closesymbol}
\setinterfaceconstant{color}{farbe}
@@ -811,6 +816,7 @@
\setinterfaceconstant{oddmargin}{ungeraderand}
\setinterfaceconstant{offset}{offset}
\setinterfaceconstant{openaction}{oeffenaktion}
+\setinterfaceconstant{openpage}{openpage}
\setinterfaceconstant{openpageaction}{openpageaction}
\setinterfaceconstant{option}{option}
\setinterfaceconstant{order}{order}
@@ -1006,6 +1012,7 @@
\setinterfaceconstant{urlalternative}{urlalternative}
\setinterfaceconstant{urlspace}{urlspatium}
\setinterfaceconstant{validate}{validieren}
+\setinterfaceconstant{values}{values}
\setinterfaceconstant{vcommand}{vbefehl}
\setinterfaceconstant{veroffset}{kopfoffset}
\setinterfaceconstant{vfil}{vfil}
@@ -1098,7 +1105,6 @@
\setinterfacecommand{colorbar}{farbbalken}
\setinterfacecommand{colorvalue}{farbewert}
\setinterfacecommand{column}{spalte}
-\setinterfacecommand{comment}{kommentar}
\setinterfacecommand{comparecolorgroup}{vergleichefarbengruppe}
\setinterfacecommand{comparepalet}{vergleichepalette}
\setinterfacecommand{completepagenumber}{completepagenumber}
diff --git a/tex/context/base/mult-def.lua b/tex/context/base/mult-def.lua
index a119c00c0..ad8618c09 100644
--- a/tex/context/base/mult-def.lua
+++ b/tex/context/base/mult-def.lua
@@ -430,16 +430,6 @@ return {
["pe"]="ستون",
["ro"]="coloana",
},
- ["comment"]={
- ["cs"]="komentar",
- ["de"]="kommentar",
- ["en"]="comment",
- ["fr"]="commentaire",
- ["it"]="commento",
- ["nl"]="commentaar",
- ["pe"]="توضیح",
- ["ro"]="comentariu",
- },
["comparecolorgroup"]={
["cs"]="porovnejskupinubarev",
["de"]="vergleichefarbengruppe",
@@ -6579,6 +6569,14 @@ return {
["maybeyear"]={
["en"]="maybeyear",
},
+--["group"]={
+-- ["en"]="group",
+-- ["nl"]="groep",
+--},
+ ["values"]={
+ ["en"]="values",
+ ["nl"]="waarden",
+ },
["action"]={
["cs"]="akce",
["de"]="aktion",
@@ -6619,6 +6617,10 @@ return {
["pe"]="بعدازسر",
["ro"]="dupatitlu",
},
+ ["aftersection"]={
+ ["en"]="aftersection",
+ ["nl"]="nasectie",
+ },
["afterkey"]={
["cs"]="klavesapo",
["de"]="nachtaste",
@@ -6897,6 +6899,10 @@ return {
["pe"]="قبل‌از",
["ro"]="inainte",
},
+ ["beforesection"]={
+ ["en"]="beforesection",
+ ["nl"]="voorsectie",
+ },
["beforehead"]={
["cs"]="predhlavickou",
["de"]="vorkopf",
@@ -7033,6 +7039,10 @@ return {
["pe"]="وضعیت‌پایین",
["ro"]="starejos",
},
+ ["buffer"]={
+ ["en"]="buffer",
+ ["nl"]="buffer",
+ },
["cache"]={
["cs"]="cache",
["de"]="cache",
@@ -7137,6 +7147,10 @@ return {
["pe"]="بستن‌عمل‌صفحه",
["ro"]="actiuneinchiderepagina",
},
+ ["closepage"]={
+ ["en"]="closepage",
+ ["nl"]="sluitpagina",
+ },
["closesymbol"]={
["cs"]="closesymbol",
["de"]="closesymbol",
@@ -9121,6 +9135,10 @@ return {
["pe"]="عمل‌صفحه‌باز",
["ro"]="actiunedeschiderepagina",
},
+ ["openpage"]={
+ ["en"]="openpage",
+ ["nl"]="openpagina",
+ },
["option"]={
["cs"]="volba",
["de"]="option",
@@ -12011,6 +12029,10 @@ return {
["pe"]="آوریل",
["ro"]="aprilie",
},
+ ["attachment"]={
+ ["en"]="attachment",
+ ["nl"]="aanhangsel",
+ },
["atmargin"]={
["cs"]="naokraji",
["de"]="amrand",
diff --git a/tex/context/base/mult-en.mkii b/tex/context/base/mult-en.mkii
index 1fc61060c..cbb3bad57 100644
--- a/tex/context/base/mult-en.mkii
+++ b/tex/context/base/mult-en.mkii
@@ -75,6 +75,7 @@
\setinterfacevariable{april}{April}
\setinterfacevariable{atmargin}{atmargin}
\setinterfacevariable{atpage}{atpage}
+\setinterfacevariable{attachment}{attachment}
\setinterfacevariable{august}{August}
\setinterfacevariable{author}{author}
\setinterfacevariable{auto}{auto}
@@ -525,6 +526,7 @@
\setinterfaceconstant{after}{after}
\setinterfaceconstant{afterhead}{afterhead}
\setinterfaceconstant{afterkey}{afterkey}
+\setinterfaceconstant{aftersection}{aftersection}
\setinterfaceconstant{align}{align}
\setinterfaceconstant{aligncharacter}{aligncharacter}
\setinterfaceconstant{alignmentcharacter}{alignmentcharacter}
@@ -563,6 +565,7 @@
\setinterfaceconstant{balance}{balance}
\setinterfaceconstant{before}{before}
\setinterfaceconstant{beforehead}{beforehead}
+\setinterfaceconstant{beforesection}{beforesection}
\setinterfaceconstant{bet}{bet}
\setinterfaceconstant{big}{big}
\setinterfaceconstant{blank}{blank}
@@ -577,6 +580,7 @@
\setinterfaceconstant{bottomoffset}{bottomoffset}
\setinterfaceconstant{bottomspace}{bottomspace}
\setinterfaceconstant{bottomstate}{bottomstate}
+\setinterfaceconstant{buffer}{buffer}
\setinterfaceconstant{cache}{cache}
\setinterfaceconstant{calculate}{calculate}
\setinterfaceconstant{category}{category}
@@ -587,6 +591,7 @@
\setinterfaceconstant{clipoffset}{clipoffset}
\setinterfaceconstant{closeaction}{closeaction}
\setinterfaceconstant{closecommand}{closecommand}
+\setinterfaceconstant{closepage}{closepage}
\setinterfaceconstant{closepageaction}{closepageaction}
\setinterfaceconstant{closesymbol}{closesymbol}
\setinterfaceconstant{color}{color}
@@ -811,6 +816,7 @@
\setinterfaceconstant{oddmargin}{oddmargin}
\setinterfaceconstant{offset}{offset}
\setinterfaceconstant{openaction}{openaction}
+\setinterfaceconstant{openpage}{openpage}
\setinterfaceconstant{openpageaction}{openpageaction}
\setinterfaceconstant{option}{option}
\setinterfaceconstant{order}{order}
@@ -1006,6 +1012,7 @@
\setinterfaceconstant{urlalternative}{urlalternative}
\setinterfaceconstant{urlspace}{urlspace}
\setinterfaceconstant{validate}{validate}
+\setinterfaceconstant{values}{values}
\setinterfaceconstant{vcommand}{vcommand}
\setinterfaceconstant{veroffset}{veroffset}
\setinterfaceconstant{vfil}{vfil}
@@ -1098,7 +1105,6 @@
\setinterfacecommand{colorbar}{colorbar}
\setinterfacecommand{colorvalue}{colorvalue}
\setinterfacecommand{column}{column}
-\setinterfacecommand{comment}{comment}
\setinterfacecommand{comparecolorgroup}{comparecolorgroup}
\setinterfacecommand{comparepalet}{comparepalet}
\setinterfacecommand{completepagenumber}{completepagenumber}
diff --git a/tex/context/base/mult-fr.mkii b/tex/context/base/mult-fr.mkii
index f5c75dec4..e86f13c8b 100644
--- a/tex/context/base/mult-fr.mkii
+++ b/tex/context/base/mult-fr.mkii
@@ -75,6 +75,7 @@
\setinterfacevariable{april}{avril}
\setinterfacevariable{atmargin}{alamarge}
\setinterfacevariable{atpage}{alapage}
+\setinterfacevariable{attachment}{attachment}
\setinterfacevariable{august}{aout}
\setinterfacevariable{author}{auteur}
\setinterfacevariable{auto}{auto}
@@ -525,6 +526,7 @@
\setinterfaceconstant{after}{apres}
\setinterfaceconstant{afterhead}{aprestete}
\setinterfaceconstant{afterkey}{aprescle}
+\setinterfaceconstant{aftersection}{aftersection}
\setinterfaceconstant{align}{alignement}
\setinterfaceconstant{aligncharacter}{caracterealigne}
\setinterfaceconstant{alignmentcharacter}{alignementcaractere}
@@ -563,6 +565,7 @@
\setinterfaceconstant{balance}{equilibre}
\setinterfaceconstant{before}{avant}
\setinterfaceconstant{beforehead}{avanttete}
+\setinterfaceconstant{beforesection}{beforesection}
\setinterfaceconstant{bet}{bet}
\setinterfaceconstant{big}{grand}
\setinterfaceconstant{blank}{vide}
@@ -577,6 +580,7 @@
\setinterfaceconstant{bottomoffset}{decalageinf}
\setinterfaceconstant{bottomspace}{espaceinf}
\setinterfaceconstant{bottomstate}{etatinf}
+\setinterfaceconstant{buffer}{buffer}
\setinterfaceconstant{cache}{cache}
\setinterfaceconstant{calculate}{calculer}
\setinterfaceconstant{category}{category}
@@ -587,6 +591,7 @@
\setinterfaceconstant{clipoffset}{clipoffset}
\setinterfaceconstant{closeaction}{actionfermeture}
\setinterfaceconstant{closecommand}{closecommand}
+\setinterfaceconstant{closepage}{closepage}
\setinterfaceconstant{closepageaction}{actionfermeturepage}
\setinterfaceconstant{closesymbol}{closesymbol}
\setinterfaceconstant{color}{couleur}
@@ -811,6 +816,7 @@
\setinterfaceconstant{oddmargin}{margepaire}
\setinterfaceconstant{offset}{offset}
\setinterfaceconstant{openaction}{actionouverture}
+\setinterfaceconstant{openpage}{openpage}
\setinterfaceconstant{openpageaction}{actionouverturepage}
\setinterfaceconstant{option}{option}
\setinterfaceconstant{order}{order}
@@ -1006,6 +1012,7 @@
\setinterfaceconstant{urlalternative}{alternativeurl}
\setinterfaceconstant{urlspace}{espaceurl}
\setinterfaceconstant{validate}{valider}
+\setinterfaceconstant{values}{values}
\setinterfaceconstant{vcommand}{vcommande}
\setinterfaceconstant{veroffset}{veroffset}
\setinterfaceconstant{vfil}{vfil}
@@ -1098,7 +1105,6 @@
\setinterfacecommand{colorbar}{barrecouleur}
\setinterfacecommand{colorvalue}{valeurcouleur}
\setinterfacecommand{column}{colonne}
-\setinterfacecommand{comment}{commentaire}
\setinterfacecommand{comparecolorgroup}{comparegroupecouleur}
\setinterfacecommand{comparepalet}{comparepalette}
\setinterfacecommand{completepagenumber}{completenumeropage}
diff --git a/tex/context/base/mult-it.mkii b/tex/context/base/mult-it.mkii
index a31cb9689..f88b5f49b 100644
--- a/tex/context/base/mult-it.mkii
+++ b/tex/context/base/mult-it.mkii
@@ -75,6 +75,7 @@
\setinterfacevariable{april}{aprile}
\setinterfacevariable{atmargin}{almargine}
\setinterfacevariable{atpage}{apagina}
+\setinterfacevariable{attachment}{attachment}
\setinterfacevariable{august}{agosto}
\setinterfacevariable{author}{autore}
\setinterfacevariable{auto}{auto}
@@ -525,6 +526,7 @@
\setinterfaceconstant{after}{dopo}
\setinterfaceconstant{afterhead}{dopotesta}
\setinterfaceconstant{afterkey}{dopotasto}
+\setinterfaceconstant{aftersection}{aftersection}
\setinterfaceconstant{align}{allinea}
\setinterfaceconstant{aligncharacter}{allineacarattere}
\setinterfaceconstant{alignmentcharacter}{carattereallineamento}
@@ -563,6 +565,7 @@
\setinterfaceconstant{balance}{bilanciamento}
\setinterfaceconstant{before}{prima}
\setinterfaceconstant{beforehead}{primaditesta}
+\setinterfaceconstant{beforesection}{beforesection}
\setinterfaceconstant{bet}{bet}
\setinterfaceconstant{big}{grande}
\setinterfaceconstant{blank}{rigovuoto}
@@ -577,6 +580,7 @@
\setinterfaceconstant{bottomoffset}{offsetfondo}
\setinterfaceconstant{bottomspace}{spaziofondo}
\setinterfaceconstant{bottomstate}{statofondo}
+\setinterfaceconstant{buffer}{buffer}
\setinterfaceconstant{cache}{cache}
\setinterfaceconstant{calculate}{calcola}
\setinterfaceconstant{category}{category}
@@ -587,6 +591,7 @@
\setinterfaceconstant{clipoffset}{clipoffset}
\setinterfaceconstant{closeaction}{azionechiudi}
\setinterfaceconstant{closecommand}{closecommand}
+\setinterfaceconstant{closepage}{closepage}
\setinterfaceconstant{closepageaction}{azionechiudipagina}
\setinterfaceconstant{closesymbol}{closesymbol}
\setinterfaceconstant{color}{colore}
@@ -811,6 +816,7 @@
\setinterfaceconstant{oddmargin}{marginedispari}
\setinterfaceconstant{offset}{offset}
\setinterfaceconstant{openaction}{azioneapri}
+\setinterfaceconstant{openpage}{openpage}
\setinterfaceconstant{openpageaction}{azioneapripagina}
\setinterfaceconstant{option}{opzione}
\setinterfaceconstant{order}{order}
@@ -1006,6 +1012,7 @@
\setinterfaceconstant{urlalternative}{alternativaurl}
\setinterfaceconstant{urlspace}{spaziourl}
\setinterfaceconstant{validate}{verifica}
+\setinterfaceconstant{values}{values}
\setinterfaceconstant{vcommand}{vcomando}
\setinterfaceconstant{veroffset}{veroffset}
\setinterfaceconstant{vfil}{vfil}
@@ -1098,7 +1105,6 @@
\setinterfacecommand{colorbar}{barracolori}
\setinterfacecommand{colorvalue}{valorecolore}
\setinterfacecommand{column}{colonna}
-\setinterfacecommand{comment}{commento}
\setinterfacecommand{comparecolorgroup}{confrontagruppocolori}
\setinterfacecommand{comparepalet}{confrontatavolozza}
\setinterfacecommand{completepagenumber}{numeropaginacompleto}
diff --git a/tex/context/base/mult-nl.mkii b/tex/context/base/mult-nl.mkii
index 8fef745f8..68768df57 100644
--- a/tex/context/base/mult-nl.mkii
+++ b/tex/context/base/mult-nl.mkii
@@ -75,6 +75,7 @@
\setinterfacevariable{april}{april}
\setinterfacevariable{atmargin}{opmarge}
\setinterfacevariable{atpage}{oppagina}
+\setinterfacevariable{attachment}{aanhangsel}
\setinterfacevariable{august}{augustus}
\setinterfacevariable{author}{auteur}
\setinterfacevariable{auto}{auto}
@@ -525,6 +526,7 @@
\setinterfaceconstant{after}{na}
\setinterfaceconstant{afterhead}{kopna}
\setinterfaceconstant{afterkey}{natoets}
+\setinterfaceconstant{aftersection}{nasectie}
\setinterfaceconstant{align}{uitlijnen}
\setinterfaceconstant{aligncharacter}{karakteruitlijnen}
\setinterfaceconstant{alignmentcharacter}{uitlijnkarakter}
@@ -563,6 +565,7 @@
\setinterfaceconstant{balance}{balanceren}
\setinterfaceconstant{before}{voor}
\setinterfaceconstant{beforehead}{kopvoor}
+\setinterfaceconstant{beforesection}{voorsectie}
\setinterfaceconstant{bet}{bet}
\setinterfaceconstant{big}{groot}
\setinterfaceconstant{blank}{blanko}
@@ -577,6 +580,7 @@
\setinterfaceconstant{bottomoffset}{onderoffset}
\setinterfaceconstant{bottomspace}{bodemwit}
\setinterfaceconstant{bottomstate}{onderstatus}
+\setinterfaceconstant{buffer}{buffer}
\setinterfaceconstant{cache}{cache}
\setinterfaceconstant{calculate}{bereken}
\setinterfaceconstant{category}{categorie}
@@ -587,6 +591,7 @@
\setinterfaceconstant{clipoffset}{clipoffset}
\setinterfaceconstant{closeaction}{sluitactie}
\setinterfaceconstant{closecommand}{sluitcommando}
+\setinterfaceconstant{closepage}{sluitpagina}
\setinterfaceconstant{closepageaction}{sluitpaginaactie}
\setinterfaceconstant{closesymbol}{sluitsymbool}
\setinterfaceconstant{color}{kleur}
@@ -811,6 +816,7 @@
\setinterfaceconstant{oddmargin}{onevenmarge}
\setinterfaceconstant{offset}{offset}
\setinterfaceconstant{openaction}{openactie}
+\setinterfaceconstant{openpage}{openpagina}
\setinterfaceconstant{openpageaction}{openpaginaactie}
\setinterfaceconstant{option}{optie}
\setinterfaceconstant{order}{order}
@@ -1006,6 +1012,7 @@
\setinterfaceconstant{urlalternative}{urlvariant}
\setinterfaceconstant{urlspace}{urlspatie}
\setinterfaceconstant{validate}{valideer}
+\setinterfaceconstant{values}{waarden}
\setinterfaceconstant{vcommand}{vcommando}
\setinterfaceconstant{veroffset}{kopoffset}
\setinterfaceconstant{vfil}{vfil}
@@ -1098,7 +1105,6 @@
\setinterfacecommand{colorbar}{kleurenbalk}
\setinterfacecommand{colorvalue}{kleurwaarde}
\setinterfacecommand{column}{kolom}
-\setinterfacecommand{comment}{commentaar}
\setinterfacecommand{comparecolorgroup}{vergelijkkleurgroep}
\setinterfacecommand{comparepalet}{vergelijkpalet}
\setinterfacecommand{completepagenumber}{volledigepaginanummer}
diff --git a/tex/context/base/mult-pe.mkii b/tex/context/base/mult-pe.mkii
index e003e15a9..66c7529c5 100644
--- a/tex/context/base/mult-pe.mkii
+++ b/tex/context/base/mult-pe.mkii
@@ -75,6 +75,7 @@
\setinterfacevariable{april}{آوریل}
\setinterfacevariable{atmargin}{درحاشیه}
\setinterfacevariable{atpage}{درصفحه}
+\setinterfacevariable{attachment}{attachment}
\setinterfacevariable{august}{آگوست}
\setinterfacevariable{author}{author}
\setinterfacevariable{auto}{خودکار}
@@ -525,6 +526,7 @@
\setinterfaceconstant{after}{بعداز}
\setinterfaceconstant{afterhead}{بعدازسر}
\setinterfaceconstant{afterkey}{بعدازکلید}
+\setinterfaceconstant{aftersection}{aftersection}
\setinterfaceconstant{align}{تنظیم}
\setinterfaceconstant{aligncharacter}{حرف‌تنظیم}
\setinterfaceconstant{alignmentcharacter}{حرف‌تنظیم‌کردن}
@@ -563,6 +565,7 @@
\setinterfaceconstant{balance}{تعادل}
\setinterfaceconstant{before}{قبل‌از}
\setinterfaceconstant{beforehead}{قبل‌ازسر}
+\setinterfaceconstant{beforesection}{beforesection}
\setinterfaceconstant{bet}{bet}
\setinterfaceconstant{big}{بزرگ}
\setinterfaceconstant{blank}{خالی}
@@ -577,6 +580,7 @@
\setinterfaceconstant{bottomoffset}{آفست‌پایین}
\setinterfaceconstant{bottomspace}{فضای‌پایین}
\setinterfaceconstant{bottomstate}{وضعیت‌پایین}
+\setinterfaceconstant{buffer}{buffer}
\setinterfaceconstant{cache}{میانگیر}
\setinterfaceconstant{calculate}{محاسبه}
\setinterfaceconstant{category}{category}
@@ -587,6 +591,7 @@
\setinterfaceconstant{clipoffset}{آفست‌کلیپ}
\setinterfaceconstant{closeaction}{بستن‌کنش}
\setinterfaceconstant{closecommand}{بستن‌فرمان}
+\setinterfaceconstant{closepage}{closepage}
\setinterfaceconstant{closepageaction}{بستن‌عمل‌صفحه}
\setinterfaceconstant{closesymbol}{بستن‌نماد}
\setinterfaceconstant{color}{رنگ}
@@ -811,6 +816,7 @@
\setinterfaceconstant{oddmargin}{حاشیه‌فرد}
\setinterfaceconstant{offset}{آفست}
\setinterfaceconstant{openaction}{عمل‌باز}
+\setinterfaceconstant{openpage}{openpage}
\setinterfaceconstant{openpageaction}{عمل‌صفحه‌باز}
\setinterfaceconstant{option}{گزینه}
\setinterfaceconstant{order}{order}
@@ -1006,6 +1012,7 @@
\setinterfaceconstant{urlalternative}{urlalternative}
\setinterfaceconstant{urlspace}{urlspace}
\setinterfaceconstant{validate}{تاییداعتبار}
+\setinterfaceconstant{values}{values}
\setinterfaceconstant{vcommand}{vcommand}
\setinterfaceconstant{veroffset}{آفست‌عم}
\setinterfaceconstant{vfil}{vfil}
@@ -1098,7 +1105,6 @@
\setinterfacecommand{colorbar}{میله‌رنگ}
\setinterfacecommand{colorvalue}{مقداررنگ}
\setinterfacecommand{column}{ستون}
-\setinterfacecommand{comment}{توضیح}
\setinterfacecommand{comparecolorgroup}{مقایسه‌گروه‌رنگ}
\setinterfacecommand{comparepalet}{لوح‌مقایسه}
\setinterfacecommand{completepagenumber}{شماره‌صفحه‌کامل}
diff --git a/tex/context/base/mult-ro.mkii b/tex/context/base/mult-ro.mkii
index 88491aade..4455a5100 100644
--- a/tex/context/base/mult-ro.mkii
+++ b/tex/context/base/mult-ro.mkii
@@ -75,6 +75,7 @@
\setinterfacevariable{april}{aprilie}
\setinterfacevariable{atmargin}{lamargine}
\setinterfacevariable{atpage}{lapagina}
+\setinterfacevariable{attachment}{attachment}
\setinterfacevariable{august}{august}
\setinterfacevariable{author}{autor}
\setinterfacevariable{auto}{auto}
@@ -525,6 +526,7 @@
\setinterfaceconstant{after}{dupa}
\setinterfaceconstant{afterhead}{dupatitlu}
\setinterfaceconstant{afterkey}{dupatasta}
+\setinterfaceconstant{aftersection}{aftersection}
\setinterfaceconstant{align}{aliniere}
\setinterfaceconstant{aligncharacter}{aliniazacaracter}
\setinterfaceconstant{alignmentcharacter}{alierecaracter}
@@ -563,6 +565,7 @@
\setinterfaceconstant{balance}{balanta}
\setinterfaceconstant{before}{inainte}
\setinterfaceconstant{beforehead}{inaintetitlu}
+\setinterfaceconstant{beforesection}{beforesection}
\setinterfaceconstant{bet}{bet}
\setinterfaceconstant{big}{mare}
\setinterfaceconstant{blank}{blanc}
@@ -577,6 +580,7 @@
\setinterfaceconstant{bottomoffset}{offsetjos}
\setinterfaceconstant{bottomspace}{spatiujos}
\setinterfaceconstant{bottomstate}{starejos}
+\setinterfaceconstant{buffer}{buffer}
\setinterfaceconstant{cache}{cache}
\setinterfaceconstant{calculate}{calculeaza}
\setinterfaceconstant{category}{category}
@@ -587,6 +591,7 @@
\setinterfaceconstant{clipoffset}{clipoffset}
\setinterfaceconstant{closeaction}{actiuneinchidere}
\setinterfaceconstant{closecommand}{closecommand}
+\setinterfaceconstant{closepage}{closepage}
\setinterfaceconstant{closepageaction}{actiuneinchiderepagina}
\setinterfaceconstant{closesymbol}{closesymbol}
\setinterfaceconstant{color}{culoare}
@@ -811,6 +816,7 @@
\setinterfaceconstant{oddmargin}{margineimpara}
\setinterfaceconstant{offset}{offset}
\setinterfaceconstant{openaction}{actiunedeschidere}
+\setinterfaceconstant{openpage}{openpage}
\setinterfaceconstant{openpageaction}{actiunedeschiderepagina}
\setinterfaceconstant{option}{optiune}
\setinterfaceconstant{order}{order}
@@ -1006,6 +1012,7 @@
\setinterfaceconstant{urlalternative}{urlalternativ}
\setinterfaceconstant{urlspace}{spatiuurl}
\setinterfaceconstant{validate}{verifica}
+\setinterfaceconstant{values}{values}
\setinterfaceconstant{vcommand}{comandav}
\setinterfaceconstant{veroffset}{veroffset}
\setinterfaceconstant{vfil}{vfil}
@@ -1098,7 +1105,6 @@
\setinterfacecommand{colorbar}{baraculoare}
\setinterfacecommand{colorvalue}{valoareculoare}
\setinterfacecommand{column}{coloana}
-\setinterfacecommand{comment}{comentariu}
\setinterfacecommand{comparecolorgroup}{comparagrupculoare}
\setinterfacecommand{comparepalet}{comparapaleta}
\setinterfacecommand{completepagenumber}{completeazanumarpagina}
diff --git a/tex/context/base/mult-sys.mkiv b/tex/context/base/mult-sys.mkiv
index 564e3d0f4..4e3138c86 100644
--- a/tex/context/base/mult-sys.mkiv
+++ b/tex/context/base/mult-sys.mkiv
@@ -518,8 +518,9 @@
\definesystemvariable {et} % EffecT
\definesystemvariable {ex} % ExterneFiguren
\definesystemvariable {fa} % font feature
+\definesystemvariable {fb} % FieldBody
\definesystemvariable {fc} % FramedContent
-\definesystemvariable {fd} % FielD
+\definesystemvariable {fd} % FielDgroup
\definesystemvariable {fe} % FoxetExtensions
\definesystemvariable {ff} % FontFile
\definesystemvariable {fg} % FiGuurmaten
@@ -585,8 +586,10 @@
\definesystemvariable {ly} % LaYout
\definesystemvariable {ma} % MargeAchtergrond
\definesystemvariable {mb} % MargeBlokken
+\definesystemvariable {mc} % MarginCategory
\definesystemvariable {md} % MoDule
\definesystemvariable {me} % MultilingualElement (tags)
+\definesystemvariable {mf} % MarginFramed
\definesystemvariable {mg} % Metapost paGe
\definesystemvariable {mh} % MultilingualHead
\definesystemvariable {mk} % MarKering
@@ -676,12 +679,12 @@
\definesystemvariable {tk} % Teksten
\definesystemvariable {tl} % TekstLijnen
\definesystemvariable {tm} % TypesynonyM
-\definesystemvariable {tp} % TyPen
-\definesystemvariable {tx} % TeXtflow
\definesystemvariable {to} % TOlerance
+\definesystemvariable {tp} % TyPen
\definesystemvariable {tr} % TRacer
\definesystemvariable {ts} % TypeScript
\definesystemvariable {tt} % TabulaTe
+\definesystemvariable {tx} % TeXtflow
\definesystemvariable {ty} % TYpe
\definesystemvariable {uc} % Unicode
\definesystemvariable {ui} % UItvoer
@@ -692,10 +695,16 @@
\definesystemvariable {vn} % VoetNoten
\definesystemvariable {vs} % VSpacing
\definesystemvariable {vt} % VerTical
-\definesystemvariable {wr} % WitRuimte
\definesystemvariable {wl} % WordList
+\definesystemvariable {wr} % WitRuimte
\definesystemvariable {xf} % XML File
\definesystemvariable {xl} % lxml (mkiv)
+\definesystemvariable {wl} % WidgetLabel
+\definesystemvariable {wc} % WidgetContent
+\definesystemvariable {wt} % WidgetTotal
+\definesystemvariable {ws} % WidgetStack
+\definesystemvariable {wh} % WidgetHelp
+\definesystemvariable {wp} % WidgetPopuphelp
\definesystemvariable {xm} % xml (mkiv)
\definesystemvariable {xp} % XML Processing
\definesystemvariable {xy} % schaal
@@ -802,20 +811,20 @@
\definefileconstant {encodingprefix} {enco-}
\definefileconstant {filterprefix} {filt-}
\definefileconstant {fontprefix} {font-}
-\definefileconstant {handlingprefix} {hand-}
-\definefileconstant {javascriptprefix} {java-}
-\definefileconstant {languageprefix} {lang-}
+%definefileconstant {handlingprefix} {hand-}
+%definefileconstant {javascriptprefix} {java-}
+%definefileconstant {languageprefix} {lang-}
\definefileconstant {mathprefix} {math-}
\definefileconstant {metapostprefix} {meta-}
-\definefileconstant {regimeprefix} {regi-}
-\definefileconstant {specialprefix} {spec-}
+%definefileconstant {regimeprefix} {regi-}
+%definefileconstant {specialprefix} {spec-}
\definefileconstant {symbolprefix} {symb-}
\definefileconstant {typeprefix} {type-}
\definefileconstant {xtagprefix} {xtag-}
-\definefileconstant {propprefix} {prop-}
-\definefileconstant {unicprefix} {unic-}
-\definefileconstant {sortprefix} {sort-}
-\definefileconstant {prettyprefix} {pret-}
+%definefileconstant {propprefix} {prop-}
+%definefileconstant {unicprefix} {unic-}
+%definefileconstant {sortprefix} {sort-}
+%definefileconstant {prettyprefix} {pret-}
\definefileconstant {moduleprefix} {m-}
\definefileconstant {styleprefix} {s-}
diff --git a/tex/context/base/node-aux.lua b/tex/context/base/node-aux.lua
index 51293e78a..e6f698950 100644
--- a/tex/context/base/node-aux.lua
+++ b/tex/context/base/node-aux.lua
@@ -241,7 +241,7 @@ local function tonodes(str,fnt,attr) -- (str,template_glyph) -- moved from blob-
if space then
n = copy_node(space)
elseif fonts then -- depedency
- local parameters = fonts.identifiers[fnt].parameters
+ local parameters = fonts.hashes.identifiers[fnt].parameters
space = new_glue(parameters.space,parameters.space_stretch,parameters.space_shrink)
n = space
end
diff --git a/tex/context/base/node-dum.lua b/tex/context/base/node-dum.lua
deleted file mode 100644
index 512748151..000000000
--- a/tex/context/base/node-dum.lua
+++ /dev/null
@@ -1,140 +0,0 @@
-if not modules then modules = { } end modules ['node-dum'] = {
- version = 1.001,
- comment = "companion to luatex-*.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-nodes = nodes or { }
-fonts = fonts or { }
-attributes = attributes or { }
-
-nodes.pool = nodes.pool or { }
-nodes.handlers = nodes.handlers or { }
-
-local nodecodes = { } for k,v in next, node.types () do nodecodes[string.gsub(v,"_","")] = k end
-local whatcodes = { } for k,v in next, node.whatsits() do whatcodes[string.gsub(v,"_","")] = k end
-local glyphcodes = { [0] = "character", "glyph", "ligature", "ghost", "left", "right" }
-
-nodes.nodecodes = nodecodes
-nodes.whatcodes = whatcodes
-nodes.whatsitcodes = whatcodes
-nodes.glyphcodes = glyphcodes
-
-local traverse_id = node.traverse_id
-local free_node = node.free
-local remove_node = node.remove
-local new_node = node.new
-
-local glyph_code = nodecodes.glyph
-
-function nodes.simple_font_handler(head)
--- lang.hyphenate(head)
- head = nodes.handlers.characters(head)
- nodes.injections.handler(head)
- nodes.handlers.protectglyphs(head)
- head = node.ligaturing(head)
- head = node.kerning(head)
- return head
-end
-
-if tex.attribute[0] ~= 0 then
-
- texio.write_nl("log","!")
- texio.write_nl("log","! Attribute 0 is reserved for ConTeXt's font feature management and has to be")
- texio.write_nl("log","! set to zero. Also, some attributes in the range 1-255 are used for special")
- texio.write_nl("log","! purposes so setting them at the TeX end might break the font handler.")
- texio.write_nl("log","!")
-
- tex.attribute[0] = 0 -- else no features
-
-end
-
-nodes.handlers.protectglyphs = node.protect_glyphs
-nodes.handlers.unprotectglyphs = node.unprotect_glyphs
-
-function nodes.handlers.characters(head)
- local fontdata = fonts.identifiers
- if fontdata then
- local usedfonts, done, prevfont = { }, false, nil
- for n in traverse_id(glyph_code,head) do
- local font = n.font
- if font ~= prevfont then
- prevfont = font
- local used = usedfonts[font]
- if not used then
- local tfmdata = fontdata[font] --
- if tfmdata then
- local shared = tfmdata.shared -- we need to check shared, only when same features
- if shared then
- local processors = shared.processes
- if processors and #processors > 0 then
- usedfonts[font] = processors
- done = true
- end
- end
- end
- end
- end
- end
- if done then
- for font, processors in next, usedfonts do
- for i=1,#processors do
- local h, d = processors[i](head,font,0)
- head, done = h or head, done or d
- end
- end
- end
- return head, true
- else
- return head, false
- end
-end
-
--- helper
-
-function nodes.pool.kern(k)
- local n = new_node("kern",1)
- n.kern = k
- return n
-end
-
-function nodes.remove(head, current, free_too)
- local t = current
- head, current = remove_node(head,current)
- if t then
- if free_too then
- free_node(t)
- t = nil
- else
- t.next, t.prev = nil, nil
- end
- end
- return head, current, t
-end
-
-function nodes.delete(head,current)
- return nodes.remove(head,current,true)
-end
-
-nodes.before = node.insert_before
-nodes.after = node.insert_after
-
--- attributes
-
-attributes.unsetvalue = -0x7FFFFFFF
-
-local numbers, last = { }, 127
-
-function attributes.private(name)
- local number = numbers[name]
- if not number then
- if last < 255 then
- last = last + 1
- end
- number = last
- numbers[name] = number
- end
- return number
-end
diff --git a/tex/context/base/node-fnt.lua b/tex/context/base/node-fnt.lua
index 8348e05c3..23cf0c04d 100644
--- a/tex/context/base/node-fnt.lua
+++ b/tex/context/base/node-fnt.lua
@@ -16,18 +16,18 @@ local trace_fontrun = false trackers.register("nodes.fontrun", function(v
local report_fonts = logs.reporter("fonts","processing")
-local nodes, node = nodes, node
+local nodes, node, fonts = nodes, node, fonts
-fonts = fonts or { }
-fonts.tfm = fonts.tfm or { }
-fonts.identifiers = fonts.identifiers or { }
+local fonthashes = fonts.hashes
+local fontdata = fonthashes.identifiers
+
+local otf = fonts.handlers.otf
local traverse_id = node.traverse_id
local has_attribute = node.has_attribute
local starttiming = statistics.starttiming
local stoptiming = statistics.stoptiming
local nodecodes = nodes.nodecodes
-local fontdata = fonts.identifiers
local handlers = nodes.handlers
local glyph_code = nodecodes.glyph
@@ -44,6 +44,37 @@ local glyph_code = nodecodes.glyph
local run = 0
+local setfontdynamics = { }
+local fontprocesses = { }
+
+setmetatable(setfontdynamics, { __index =
+ function(t,font)
+ local tfmdata = fontdata[font]
+ local shared = tfmdata.shared
+ local v = shared and shared.dynamics and otf.setdynamics or false
+ t[font] = v
+ return v
+ end
+})
+
+setmetatable(fontprocesses, { __index =
+ function(t,font)
+ local tfmdata = fontdata[font]
+ local shared = tfmdata.shared -- we need to check shared, only when same features
+ local processes = shared and shared.processes
+ if processes and #processes > 0 then
+ t[font] = processes
+ return processes
+ else
+ t[font] = false
+ return false
+ end
+ end
+})
+
+fonts.hashes.setdynamics = setfontdynamics
+fonts.hashes.processes = fontprocesses
+
function handlers.characters(head)
-- either next or not, but definitely no already processed list
starttiming(nodes)
@@ -57,7 +88,8 @@ function handlers.characters(head)
local n = head
while n do
if n.id == glyph_code then
- local font, attr = n.font, has_attribute(n,0) or 0
+ local font = n.font
+ local attr = has_attribute(n,0) or 0
report_fonts("font %03i, dynamic %03i, glyph %s",font,attr,utf.char(n.char))
else
report_fonts("[%s]",nodecodes[n.id])
@@ -75,35 +107,22 @@ function handlers.characters(head)
attrfonts[font] = used
end
if not used[attr] then
- -- we do some testing outside the function
- local tfmdata = fontdata[font]
- local shared = tfmdata.shared
- if shared then
- local dynamics = shared.dynamics
- if dynamics then
- local d = shared.setdynamics(font,dynamics,attr)
- if d then
- used[attr] = d
- a = a + 1
- end
+ local sd = setfontdynamics[font]
+ if sd then -- always true ?
+ local d = sd(font,attr) -- can we cache this one?
+ if d then
+ used[attr] = d
+ a = a + 1
end
end
end
else
local used = usedfonts[font]
if not used then
- local tfmdata = fontdata[font]
- if tfmdata then
- local shared = tfmdata.shared -- we need to check shared, only when same features
- if shared then
- local processors = shared.processes
- if processors and #processors > 0 then
- usedfonts[font] = processors
- u = u + 1
- end
- end
- else
- -- probably nullfont
+ local fp = fontprocesses[font]
+ if fp then
+ usedfonts[font] = fp
+ u = u + 1
end
end
end
diff --git a/tex/context/base/node-ini.mkiv b/tex/context/base/node-ini.mkiv
index 3bc258ce6..8d048122f 100644
--- a/tex/context/base/node-ini.mkiv
+++ b/tex/context/base/node-ini.mkiv
@@ -29,7 +29,7 @@
\registerctxluafile{node-shp}{1.001}
\registerctxluafile{node-ser}{1.001}
\registerctxluafile{node-ext}{1.001}
-\registerctxluafile{node-inj}{1.001} % we might split it off
+%registerctxluafile{node-inj}{1.001} % we might split it off
\registerctxluafile{node-typ}{1.001} % experimental
\registerctxluafile{node-acc}{1.001} % experimental
diff --git a/tex/context/base/node-inj.lua b/tex/context/base/node-inj.lua
index bf6a60987..80360b47b 100644
--- a/tex/context/base/node-inj.lua
+++ b/tex/context/base/node-inj.lua
@@ -6,8 +6,6 @@ if not modules then modules = { } end modules ['node-inj'] = {
license = "see context related readme files"
}
--- tricky ... fonts.identifiers is not yet defined .. to be solved (maybe general tex ini)
-
-- This is very experimental (this will change when we have luatex > .50 and
-- a few pending thingies are available. Also, Idris needs to make a few more
-- test fonts. Btw, future versions of luatex will have extended glyph properties
@@ -21,14 +19,12 @@ local report_injections = logs.reporter("nodes","injections")
local attributes, nodes, node = attributes, nodes, node
-fonts = fonts or { }
-fonts.tfm = fonts.tfm or { }
-fonts.identifiers = fonts.identifiers or { }
+fonts = fonts
+local fontdata = fonts.hashes.identifiers
nodes.injections = nodes.injections or { }
local injections = nodes.injections
-local fontdata = fonts.identifiers
local nodecodes = nodes.nodecodes
local glyph_code = nodecodes.glyph
local nodepool = nodes.pool
@@ -180,10 +176,11 @@ end
-- todo: reuse tables (i.e. no collection), but will be extra fields anyway
-- todo: check for attribute
+-- we can have a fast test on a font being processed, so we can check faster for marks etc
+
function injections.handler(head,where,keep)
local has_marks, has_cursives, has_kerns = next(marks), next(cursives), next(kerns)
if has_marks or has_cursives then
---~ if has_marks or has_cursives or has_kerns then
if trace_injections then
trace(head)
end
@@ -191,18 +188,19 @@ function injections.handler(head,where,keep)
local done, ky, rl, valid, cx, wx, mk, nofvalid = false, { }, { }, { }, { }, { }, { }, 0
if has_kerns then -- move outside loop
local nf, tm = nil, nil
- for n in traverse_id(glyph_code,head) do
+ for n in traverse_id(glyph_code,head) do -- only needed for relevant fonts
if n.subtype < 256 then
nofvalid = nofvalid + 1
valid[nofvalid] = n
if n.font ~= nf then
nf = n.font
- tm = fontdata[nf].marks
+ tm = fontdata[nf].resources.marks
+ end
+ if tm then
+ mk[n] = tm[n.char]
end
- mk[n] = tm[n.char]
local k = has_attribute(n,kernpair)
if k then
---~ unset_attribute(k,kernpair)
local kk = kerns[k]
if kk then
local x, y, w, h = kk[2] or 0, kk[3] or 0, kk[4] or 0, kk[5] or 0
@@ -226,9 +224,11 @@ function injections.handler(head,where,keep)
valid[nofvalid] = n
if n.font ~= nf then
nf = n.font
- tm = fontdata[nf].marks
+ tm = fontdata[nf].resources.marks
+ end
+ if tm then
+ mk[n] = tm[n.char]
end
- mk[n] = tm[n.char]
end
end
end
@@ -322,12 +322,18 @@ function injections.handler(head,where,keep)
if d then
local rlmode = d[3]
if rlmode and rlmode > 0 then
- -- new per 2010-10-06
+ -- new per 2010-10-06, width adapted per 2010-02-03
+ -- we used to negate the width of marks because in tfm
+ -- that makes sense but we no longer do that so as a
+ -- consequence the sign of p.width was changed (we need
+ -- to keep an eye on it as we don't have that many fonts
+ -- that enter this branch .. i'm still not sure if this
+ -- one is right
local k = wx[p]
- if k then -- maybe (d[1] - p.width) and/or + k[2]
- n.xoffset = p.xoffset - (p.width - d[1]) - k[2]
+ if k then
+ n.xoffset = p.xoffset + p.width + d[1] - k[2]
else
- n.xoffset = p.xoffset - (p.width - d[1])
+ n.xoffset = p.xoffset + p.width + d[1]
end
else
local k = wx[p]
diff --git a/tex/context/base/node-ref.lua b/tex/context/base/node-ref.lua
index c54614359..fbf528629 100644
--- a/tex/context/base/node-ref.lua
+++ b/tex/context/base/node-ref.lua
@@ -220,7 +220,11 @@ local function inject_areas(head,attribute,make,stack,done,skip,parent,pardir,tx
elseif id == glue_code and current.subtype == leftskip_code then -- any glue at the left?
--
elseif id == hlist_code or id == vlist_code then
- if not reference and r and (not skip or r > skip) then
+-- somehow reference is true so teh following fails (second one not done) in
+-- test \goto{test}[page(2)] test \gotobox{test}[page(2)]
+-- so let's wait till this fails again
+-- if not reference and r and (not skip or r > skip) then -- > or ~=
+ if r and (not skip or r > skip) then -- > or ~=
inject_list(id,current,r,make,stack,pardir,txtdir)
end
if r then
@@ -241,7 +245,7 @@ local function inject_areas(head,attribute,make,stack,done,skip,parent,pardir,tx
elseif r == reference then
last = current
elseif (done[reference] or 0) == 0 then -- or id == glue_code and current.subtype == right_skip_code
- if not skip or r > skip 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
@@ -552,33 +556,6 @@ local function checkboth(open,close)
return open, close
end
--- expansion is temp hack
-
-local opendocument, closedocument, openpage, closepage
-
-local function check(what)
- if what and what ~= "" then
- local set, bug = references.identify("",what)
- return not bug and #set > 0 and set
- end
-end
-
-function references.checkopendocumentactions (open) opendocument = check(open) end
-function references.checkclosedocumentactions(close) closedocument = check(close) end
-function references.checkopenpageactions (open) openpage = check(open) end
-function references.checkclosepageactions (close) closepage = check(close) end
-
-function references.flushdocumentactions()
- if opendocument or closedocument then
- codeinjections.flushdocumentactions(opendocument,closedocument) -- backend
- end
-end
-function references.flushpageactions()
- if openpage or closepage then
- codeinjections.flushpageactions(openpage,closepage) -- backend
- end
-end
-
-- end temp hack
statistics.register("interactive elements", function()
diff --git a/tex/context/base/node-rul.lua b/tex/context/base/node-rul.lua
index deb5b4341..4cbd1ad0c 100644
--- a/tex/context/base/node-rul.lua
+++ b/tex/context/base/node-rul.lua
@@ -60,31 +60,39 @@ end
-- todo: order and maybe other dimensions
-local trace_ruled = false trackers.register("nodes.rules", function(v) trace_ruled = v end)
+local floor = math.floor
+
+local trace_ruled = false trackers.register("nodes.rules", function(v) trace_ruled = v end)
local report_ruled = logs.reporter("nodes","rules")
-local floor = math.floor
-local n_tostring, n_tosequence = nodes.idstostring, nodes.tosequence
-
-local a_ruled = attributes.private('ruled')
-local a_color = attributes.private('color')
-local a_transparency = attributes.private('transparency')
-local a_colorspace = attributes.private('colormodel')
-
-local insert_before, insert_after, striprange = node.insert_before, node.insert_after, nodes.striprange
-local list_dimensions, has_attribute, set_attribute = node.dimensions, node.has_attribute, node.set_attribute
-local hpack_nodes = node.hpack
-local dimenfactor = fonts.dimenfactor
-local texwrite = tex.write
-
-local fontdata = fonts.identifiers
-local variables = interfaces.variables
-
-local nodecodes = nodes.nodecodes
-local skipcodes = nodes.skipcodes
-local whatcodes = nodes.whatcodes
-local kerncodes = nodes.kerncodes
+local n_tostring = nodes.idstostring
+local n_tosequence = nodes.tosequence
+
+local a_ruled = attributes.private('ruled')
+local a_color = attributes.private('color')
+local a_transparency = attributes.private('transparency')
+local a_colorspace = attributes.private('colormodel')
+
+local texwrite = tex.write
+
+local insert_before = node.insert_before
+local insert_after = node.insert_after
+local striprange = nodes.striprange
+local list_dimensions = node.dimensions
+local has_attribute = node.has_attribute
+local set_attribute = node.set_attribute
+
+local hpack_nodes = node.hpack
+
+local fontdata = fonts.hashes.identifiers
+local variables = interfaces.variables
+local dimenfactor = fonts.helpers.dimenfactor
+
+local nodecodes = nodes.nodecodes
+local skipcodes = nodes.skipcodes
+local whatcodes = nodes.whatcodes
+local kerncodes = nodes.kerncodes
local glyph_code = nodecodes.glyph
local disc_code = nodecodes.disc
diff --git a/tex/context/base/node-rul.mkiv b/tex/context/base/node-rul.mkiv
index 8e6aa5790..54d0c22f1 100644
--- a/tex/context/base/node-rul.mkiv
+++ b/tex/context/base/node-rul.mkiv
@@ -55,6 +55,9 @@
%D
%D \showsetup{setupunderbar}
+%D todo: mkvi this file ... no redefine, just pass all parameters, too messy now
+%D (due to grouping) so better hash settings at the lua end
+
\unprotect
%definesystemattribute[ruled]
@@ -62,41 +65,39 @@
\registerctxluafile{node-rul}{1.001}
-\newtoks\checkalldefinedbars
+\installcommandhandler \??on {bar} \??on
-\def\barparameter #1{\csname\dobarparameter\currentbar#1\endcsname}
-\def\dobarparameter #1#2{\ifcsname\??on#1#2\endcsname\??on#1#2\else\expandafter\dobarparentparameter\csname\??on#1\s!parent\endcsname#2\fi}
-\def\dobarparentparameter#1#2{\ifx#1\relax\s!empty\else\dobarparameter#1#2\fi}
+\newtoks\checkalldefinedbars
-\unexpanded\def\definebar
- {\dotripleempty\dodefinebar}
+\let\setupbars\setupbar
-\def\dodefinebar[#1][#2][#3]%
- {\ifthirdargument
- \getparameters[\??on#1][\s!parent=#2,#3]%
+\appendtoks
+ \ifsecondargument
+ \dodefinebarindeed\currentbar
\else
- \getparameters[\??on#1][\s!parent=,#2]%
+ \the\checkalldefinedbars
\fi
- %
- %\setvalue{\??on:#1}{0}%
- %
- \ifcsname\??on:#1:c\endcsname
- \csname\??on:#1:c\endcsname\zerocount
+\to \everysetupbar
+
+\appendtoks
+ \ifcsname\??on:\currentbar:c\endcsname
+ \csname\??on:\currentbar:c\endcsname\zerocount
\else
- \expandafter\newcount\csname\??on:#1:c\endcsname
+ \expandafter\newcount\csname\??on:\currentbar:c\endcsname
\fi
- \normalexpanded{\checkalldefinedbars{\noexpand\doredefinebar{#1}\the\checkalldefinedbars}}%
- \dodefinebarindeed{#1}%
- \setuvalue{#1}{\doruled{#1}}}
+ \normalexpanded{\checkalldefinedbars{\doredefinebar{\currentbar}\the\checkalldefinedbars}}%
+ \dodefinebarindeed\currentbar
+ \setuevalue\currentbar{\doruled{\currentbar}}%
+\to \everydefinebar
-\def\dodefinebarindeed#1%
- {\bgroup
- \def\currentbar{#1}%
+\unexpanded\def\dodefinebarindeed#1%
+ {\begingroup
+ \edef\currentbar{#1}%
\doifsomethingelse{\barparameter\c!color}
{\donetrue\colored[\barparameter\c!color]}
{\donefalse}%
\normalexpanded
- {\egroup
+ {\endgroup
\scratchcounter\ctxlua{nodes.rules.define {
method = \barparameter\c!method,
offset = \barparameter\c!offset,
@@ -114,7 +115,7 @@
\let\doredefinebar\dodefinebarindeed
-\def\doruled#1%
+\unexpanded\def\doruled#1%
{\groupedcommand{\dodoruled{#1}}\relax}
\def\dodoruled
@@ -123,7 +124,7 @@
\dodoruled}
\def\dodoruledindeed#1% maybe reverse the 1000
- {\advance\csname\??on:#1:c\endcsname\plusone
+ {\advance\csname\??on:#1:c\endcsname\plusone % local ?
\scratchcounter\csname\??on:#1:c\endcsname
\attribute\ruledattribute\numexpr
1000*\scratchcounter
@@ -151,18 +152,6 @@
{\csname\??on:s:\number\currentbarnesting\endcsname
\global\advance\currentbarnesting\minusone}
-\unexpanded\def\setupbars
- {\dodoubleempty\dosetupbars}
-
-\def\dosetupbars[#1][#2]% not that efficient
- {\ifsecondargument
- \getparameters[\??on#1][#2]%
- \dodefinebarindeed{#1}%
- \else
- \getparameters[\??on][#1]%
- \the\checkalldefinedbars
- \fi}
-
\setupbars
[\c!method=0, % new: 0=center nested, 1=stack nested
\c!continue=\v!no,
@@ -199,49 +188,36 @@
%D This will move: (a bit duplicated)
-\newtoks\checkalldefinedshifts
-
-\def\shiftparameter #1{\csname\doshiftparameter\currentshift#1\endcsname}
-\def\shiftparameterhash#1{\doshiftparameterhash{\??ra\currentshift}#1}
+\installcommandhandler \??ra {shift} \??ra
-\def\doshiftparameter #1#2{\ifcsname\??ra#1#2\endcsname\??ra#1#2\else\expandafter\doshiftparentparameter\csname\??ra#1\s!parent\endcsname#2\fi}
-\def\doshiftparameterhash#1#2{\ifcsname#1#2\endcsname#1\else\expandafter\doshiftparentparameterhash\csname#1\s!parent\endcsname#2\fi}
-
-\def\doshiftparentparameter #1#2{\ifx#1\relax\s!empty\else\doshiftparameter #1#2\fi}
-\def\doshiftparentparameterhash#1#2{\ifx#1\relax \else\doshiftparameterhash#1#2\fi}
-
-\def\dosetshiftattributes#1#2% style color
- {\edef\fontattributehash {\shiftparameterhash#1}%
- \edef\colorattributehash{\shiftparameterhash#2}%
- \ifx\fontattributehash \empty\else\dosetfontattribute \fontattributehash #1\fi
- \ifx\colorattributehash\empty\else\dosetcolorattribute\colorattributehash#2\fi}
+\newtoks\checkalldefinedshifts
-\unexpanded\def\defineshift
- {\dotripleempty\dodefineshift}
+\let\setupshifts\setupshift
-\def\dodefineshift[#1][#2][#3]%
- {\ifthirdargument
- \getparameters[\??ra#1][\s!parent=#2,#3]%
+\appendtoks
+ \ifsecondargument
+ \dodefineshiftindeed\currentshift
\else
- \getparameters[\??ra#1][\s!parent=,#2]%
+ \the\checkalldefinedshifts
\fi
- %
- %\setvalue{\??ra:#1}{0}%
- %
- \ifcsname\??ra:#1:c\endcsname
- \csname\??ra:#1:c\endcsname\zerocount
+\to \everysetupshift
+
+\appendtoks
+ \ifcsname\??ra:\currentshift:c\endcsname
+ \csname\??ra:\currentshift:c\endcsname\zerocount
\else
- \expandafter\newcount\csname\??ra:#1:c\endcsname
+ \expandafter\newcount\csname\??ra:\currentshift:c\endcsname
\fi
- \normalexpanded{\checkalldefinedshifts{\noexpand\doredefineshift{#1}\the\checkalldefinedshifts}}%
- \dodefineshiftindeed{#1}%
- \setuvalue{#1}{\doshifted{#1}}}
+ \normalexpanded{\checkalldefinedshifts{\doredefineshift{\currentshift}\the\checkalldefinedshifts}}%
+ \dodefineshiftindeed{\currentshift}%
+ \setuevalue\currentshift{\doshifted{\currentshift}}%
+\to \everydefineshift
-\def\dodefineshiftindeed#1%
- {\bgroup
- \def\currentshift{#1}%
+\unexpanded\def\dodefineshiftindeed#1%
+ {\begingroup
+ \edef\currentshift{#1}%
\normalexpanded
- {\egroup
+ {\endgroup
\scratchcounter\ctxlua{nodes.shifts.define {
method = \shiftparameter\c!method,
continue = "\shiftparameter\c!continue",
@@ -252,23 +228,14 @@
\let\doredefineshift\dodefineshiftindeed
-\def\doshifted#1%
- {\groupedcommand{\dodoshifted{#1}}\relax}
+% \unexpanded\def\doshifted#1%
+% {\groupedcommand{\dodoshifted{#1}}\relax}
\def\dodoshifted
{\ctxlua{nodes.shifts.enable()}%
\glet\dodoshifted\dodoshiftedindeed
\dodoshifted}
-% \def\dodoshiftedindeed#1%
-% {\def\currentshift{#1}%
-% \advance\csname\??ra:#1:c\endcsname\plusone
-% \scratchcounter\csname\??ra:#1:c\endcsname
-% \attribute\shiftedattribute\numexpr1000*\scratchcounter
-% +\csname\??ra#1\ifcsname\??ra#1:\number\scratchcounter\s!parent\endcsname:\number\scratchcounter\fi:a\endcsname
-% \setupalign[\shiftparameter\c!align]%
-% \dosetshiftattributes\c!style\c!color}
-
\def\dostartisolation{\char0 }
\def\dostopisolation {\char0 }
\def\doisolator {\char0 }
@@ -291,7 +258,7 @@
\dosetshiftattributes\c!style\c!color
\dosetupisolatedalign{\shiftparameter\c!align}}
-\def\doshifted#1%
+\unexpanded\def\doshifted#1%
{\doisolatedgroupedalign{\dodoshifted{#1}}{}}
\unexpanded\def\startshift[#1]%
@@ -301,18 +268,6 @@
\unexpanded\def\stopshift
{\endgroup}
-\unexpanded\def\setupshifts
- {\dodoubleempty\dosetupshifts}
-
-\def\dosetupshifts[#1][#2]% not that efficient
- {\ifsecondargument
- \getparameters[\??ra#1][#2]%
- \dodefineshiftindeed{#1}%
- \else
- \getparameters[\??ra][#1]%
- \the\checkalldefinedshifts
- \fi}
-
\setupshifts
[\c!method=0,
\c!continue=\v!no,
diff --git a/tex/context/base/node-spl.lua b/tex/context/base/node-spl.lua
index c609f4150..ddb4a26a8 100644
--- a/tex/context/base/node-spl.lua
+++ b/tex/context/base/node-spl.lua
@@ -22,9 +22,6 @@ local gmatch, concat, format, remove = string.gmatch, table.concat, string.forma
local next, tostring, tonumber = next, tostring, tonumber
local utfchar = utf.char
local random = math.random
-local variables = interfaces.variables
-local settings_to_array, settings_to_hash = utilities.parsers.settings_to_array, utilities.parsers.settings_to_hash
-local fcs = fonts.colors.set
local trace_split = false trackers.register("builders.paragraphs.solutions.splitters.splitter", function(v) trace_split = v end)
local trace_optimize = false trackers.register("builders.paragraphs.solutions.splitters.optimizer", function(v) trace_optimize = v end)
@@ -37,6 +34,11 @@ local report_optimizers = logs.reporter("nodes","optimizers")
local nodes, node = nodes, node
+local variables = interfaces.variables
+
+local settings_to_array = utilities.parsers.settings_to_array
+local settings_to_hash = utilities.parsers.settings_to_hash
+
local find_node_tail = node.tail or node.slide
local free_node = node.free
local free_nodelist = node.flush_list
@@ -53,6 +55,8 @@ local insert_node_before = node.insert_before
local insert_node_after = node.insert_after
local repack_hlist = nodes.repack_hlist
+local setnodecolor = nodes.tracers.colors.set
+
local nodecodes = nodes.nodecodes
local whatsitcodes = nodes.whatsitcodes
@@ -76,7 +80,9 @@ local starttiming = statistics.starttiming
local stoptiming = statistics.stoptiming
local process_characters = nodes.handlers.characters
local inject_kerns = nodes.injections.handler
-local fontdata = fonts.identifiers
+local fontdata = fonts.hashes.identifiers
+local setfontdynamics = fonts.hashes.setdynamics
+local fontprocesses = fonts.hashes.processes
local parbuilders = builders.paragraphs
parbuilders.solutions = parbuilders.solutions or { }
@@ -112,7 +118,7 @@ function splitters.setup(setups)
criterium = tonumber(setups.criterium) or criterium
end
-local contextsetups = fonts.definers.specifiers.contextsetups
+local contextsetups = fonts.specifiers.contextsetups
local function convert(featuresets,name,set,what)
local list, numbers, nofnumbers = set[what], { }, 0
@@ -333,29 +339,35 @@ local function doit(word,list,best,width,badness,line,set,listdir)
end
elseif set == "less" then
for n in traverse_nodes(first) do
- fcs(n,"font:isol")
+ setnodecolor(n,"font:isol")
set_attribute(n,0,featurenumber)
end
else
for n in traverse_nodes(first) do
- fcs(n,"font:medi")
+ setnodecolor(n,"font:medi")
set_attribute(n,0,featurenumber)
end
end
local font = found.font
- local dynamics = found.dynamics
- local shared = fontdata[font].shared
- if not dynamics then -- we cache this
- dynamics = shared.dynamics
- found.dynamics = dynamics
- end
- local processors = found[featurenumber]
- if not processors then -- we cache this too
- processors = shared.setdynamics(font,dynamics,featurenumber)
- found[featurenumber] = processors
- end
- for i=1,#processors do -- often more than 1
- first = processors[i](first,font,featurenumber) -- we can make a special one that already passes the dynamics
+ -- local dynamics = found.dynamics
+ -- local shared = fontdata[font].shared
+ -- if not dynamics then -- we cache this
+ -- dynamics = shared.dynamics
+ -- found.dynamics = dynamics
+ -- end
+ -- local processors = found[featurenumber]
+ -- if not processors then -- we cache this too
+ -- processors = fonts.handlers.otf.setdynamics(font,featurenumber)
+ -- found[featurenumber] = processors
+ -- end
+ local setdynamics = setfontdynamics[font]
+ if setdynamics then
+ local processes = setdynamics(font,featurenumber)
+ for i=1,#processes do -- often more than 1
+ first = processes[i](first,font,featurenumber)
+ end
+ else
+ report_solutions("fatal error, no dynamics for font %s",font)
end
first = inject_kerns(first)
local h = word[2].next -- head of current word
diff --git a/tex/context/base/node-tra.lua b/tex/context/base/node-tra.lua
index 8b393df48..84d772670 100644
--- a/tex/context/base/node-tra.lua
+++ b/tex/context/base/node-tra.lua
@@ -24,13 +24,6 @@ nodes = nodes or { }
local fonts, nodes, node, context = fonts, nodes, node, context
-fonts.tfm = fonts.tfm or { }
-fonts.identifiers = fonts.identifiers or { }
-fonts.characters = fonts.characters or { }
-
-local fontdata = fonts.identifiers
-local fontchar = fonts.characters
-
nodes.tracers = nodes.tracers or { }
local tracers = nodes.tracers
@@ -77,6 +70,7 @@ local nodepool = nodes.pool
local new_glyph = nodepool.glyph
function char_tracers.collect(head,list,tag,n)
+ local fontdata = fonts.hashes.identifiers
n = n or 0
local ok, fn = false, nil
while head do
@@ -236,6 +230,7 @@ end
function step_tracers.features()
-- we cannot use first_glyph here as it only finds characters with subtype < 256
+ local fontdata = fonts.hashes.identifiers
local f = collection[1]
while f do
if f.id == glyph_code then
@@ -265,12 +260,14 @@ function step_tracers.features()
end
function tracers.fontchar(font,char)
+ local fontchar = fonts.hashes.characters
local n = new_glyph()
n.font, n.char, n.subtype = font, char, 256
context(n)
end
function step_tracers.codes(i,command)
+ local fontdata = fonts.hashes.identifiers
local c = collection[i]
while c do
local id = c.id
@@ -581,6 +578,7 @@ local threshold = 65536
local function toutf(list,result,nofresult,stopcriterium)
if list then
+ local fontchar = fonts.hashes.characters
for n in traverse_nodes(list) do
local id = n.id
if id == glyph_code then
@@ -656,3 +654,25 @@ number.points = points
--~ local shrink_unit = (shrink_order ~= 0) and ("fi".. string.rep("l",shrink_order)) or "sp"
--~ return string.format("%ssp+ %ssp - %ssp",s.width,s.stretch,stretch_unit,s.shrink,shrink_unit)
--~ end
+
+local colors = { }
+tracers.colors = colors
+
+local set_attribute = node.set_attribute
+local unset_attribute = node.unset_attribute
+
+local attribute = attributes.private('color')
+local mapping = attributes.list[attribute] or { }
+
+function colors.set(n,c)
+ local mc = mapping[c]
+ if not mc then
+ unset_attribute(n,attribute)
+ else
+ set_attribute(n,attribute,mc)
+ end
+end
+
+function colors.reset(n)
+ unset_attribute(n,attribute)
+end
diff --git a/tex/context/base/pack-lyr.mkiv b/tex/context/base/pack-lyr.mkiv
index 8335a07b9..5242b56de 100644
--- a/tex/context/base/pack-lyr.mkiv
+++ b/tex/context/base/pack-lyr.mkiv
@@ -140,15 +140,6 @@
\def\setlayer
{\dotripleempty\dosetlayer}
-% \def\dosetlayer[#1][#2][#3]% #4 == box do \fi is ok
-% {\doifelsevalue{\??ll#1\c!state}\v!stop
-% {\dowithnextbox\donothing\hbox}
-% {\ifthirdargument
-% \dodosetlayer[#1][#2][#3]%
-% \else
-% \dodosetlayer[#1][][#2]%
-% \fi}}
-
\def\dosetlayer[#1][#2][#3]% #4 == box do \fi is ok
{\doifelsevalue{\??ll#1\c!state}\v!stop
{\dowithnextbox\donothing\hbox}
@@ -424,20 +415,6 @@
% todo: setups before flush, handy hook
-% \unexpanded\def\flushlayer[#1]%
-% {\doifelsevalue{\??ll#1\c!state}\v!next
-% {\letgvalue{\??ll#1\c!state}\v!start} % dangerous, stack-built-up
-% {\doifelsevalue{\??ll#1\c!state}\v!continue
-% {\letgvalue{\??ll#1\c!state}\v!repeat} % dangerous, stack-built-up
-% {\doifelsevalue{\??ll#1\c!doublesided}\v!yes
-% {\doifundefinedelse{\@@layerbox#1}%
-% {\dodoflushlayerA[#1]}
-% {\doifbothsidesoverruled
-% {\dodoflushlayerB\v!left [#1]}% left
-% {\dodoflushlayerB\v!right[#1]}% right
-% {\dodoflushlayerB\v!left [#1]}}}% left
-% {\dodoflushlayerA[#1]}}}}
-
\unexpanded\def\flushlayer[#1]% quite core, so optimized
{\begingroup
\forgetall
diff --git a/tex/context/base/pack-mis.mkvi b/tex/context/base/pack-mis.mkvi
new file mode 100644
index 000000000..ab6d2b334
--- /dev/null
+++ b/tex/context/base/pack-mis.mkvi
@@ -0,0 +1,84 @@
+%D \module
+%D [ file=pack-mis, % moved from e.g. core-mis
+%D version=1998.01.29,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Miscelaneous,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%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 Packing Macros / Misc Commands}
+
+\unprotect
+
+% a quite old mechanism already (but inheritance added)
+%
+% \defineplacement[name][settings]
+% \setupplacement [name][settings]
+% \placement [name][settings]
+% \place<name> [settings]
+
+\installcommandhandler \??pl {placement} \??pl
+
+\appendtoks
+ \setuevalue{\e!place\currentplacement}{\pack_placement{\currentplacement}}%
+\to \everydefineplacement
+
+\setupplacement
+ [\c!left=\hss,
+ \c!right=\hss,
+ \c!linecorrection=\v!off,
+ \c!depthcorrection=\v!off,
+ \c!grid=\v!middle,
+ %\c!before=,
+ %\c!after=,
+ \c!margin=\v!standard]
+
+\unexpanded\def\placement[#tag]%
+ {\pack_placement{#tag}}
+
+\unexpanded\def\pack_placement#tag%
+ {\bgroup
+ \edef\currentplacement{#tag}%
+ \dosingleempty\pack_placement_indeed}
+
+\def\pack_placement_indeed[#settings]% set test can be sped up but non critical
+ {\iffirstargument
+ \setupcurrentplacement[#settings]%
+ \fi
+ \dowithnextboxcontent{\forgetall}{\pack_placement_flush\egroup}\vbox}
+
+\def\pack_placement_flush
+ {\setlocalhsize
+ \placementparameter\c!before
+ \begingroup
+ \disableparpositions
+ \setbox\nextbox\hbox to \localhsize
+ {\placementparameter\c!left
+ \flushnextbox
+ \placementparameter\c!right}%
+ \ifinsidefloat \else
+ \addlocalbackgroundtobox\nextbox
+ \fi
+ \ifgridsnapping
+ \doifinset{\placementparameter\c!margin}{\v!standard,\v!yes}\noindent % unchecked
+ \doifelsenothing{\placementparameter\c!grid}
+ {\snaptogrid[\v!middle]}
+ {\snaptogrid[\placementparameter\c!grid]}%
+ \hbox{\flushnextbox}%
+ \else
+ \doif{\placementparameter\c!linecorrection}\v!on \startbaselinecorrection
+ \doifinset{\placementparameter\c!margin}{\v!standard,\v!yes}\noindent
+ \flushnextbox
+ \doif{\placementparameter\c!depthcorrection}\v!on\baselinecorrection
+ \doif{\placementparameter\c!linecorrection }\v!on\stopbaselinecorrection
+ \fi
+ \endgroup
+ \placementparameter\c!after}
+
+\protect \endinput
+
diff --git a/tex/context/base/pack-rul.mkiv b/tex/context/base/pack-rul.mkiv
index 053b217c5..d6299a292 100644
--- a/tex/context/base/pack-rul.mkiv
+++ b/tex/context/base/pack-rul.mkiv
@@ -328,6 +328,16 @@
\box\scratchbox
\egroup}
+%D \macros
+%D {overlayfakebox}
+
+\def\overlayfakebox
+ {\hbox
+ {\setbox\scratchbox\emptyhbox
+ \wd\scratchbox\overlaywidth
+ \ht\scratchbox\overlayheight
+ \box\scratchbox}}
+
%D The empty case is:
\let\executeoverlay\gobblesevenarguments
@@ -2146,10 +2156,12 @@
%D
%D \showsetup{blackrule}
-\def\complexblackrule[#1]%
+\definecomplexorsimple\blackrule
+
+\unexpanded\def\complexblackrule[#1]%
{\hbox\bgroup\getparameters[\??bj][#1]\domakeblackrule\egroup}
-\def\simpleblackrule
+\unexpanded\def\simpleblackrule
{\hbox\bgroup\domakeblackrule\egroup}
\def\domakeblackrule
@@ -2163,8 +2175,6 @@
\!!depth \@@bjdepth
\stopcolor}
-\definecomplexorsimple\blackrule
-
%D \macros
%D {blackrules}
%D
@@ -2686,77 +2696,124 @@
%D
%D The next definition shows the defaults.
-\def\dodefineframedtext[#1][#2]%
- {\presetlocalframed[\??kd#1]%
- \getparameters[\??kd#1]
- [\c!width=0.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!foregroundcolor=,
- \c!foregroundstyle=,
- \c!background=,
- \c!backgroundcolor=,
- \c!backgroundscreen=\@@rsscreen,
- \c!linecorrection=\v!on,
- \c!depthcorrection=\v!on,
- \c!margin=\v!standard,
- \c!orientation=,
- \c!indenting=,
- #2]%
- \setuvalue{\e!start#1}{\dostartframedtext[#1]}%
- \setuvalue{\e!stop #1}{\dostopframedtext }%
- \setuvalue {#1}{\doframedtext [#1]}}
-
-\unexpanded\def\defineframedtext
- {\dodoubleempty\dodefineframedtext}
+\installcommandhandler \??kd {framedtext} \??kd
-%D We define the general (and original) case by just saying:
+\let\setupframedtexts\setupframedtext
-\defineframedtext[\v!framedtext]
+\presetlocalframed[\??kd]
-%D We need several steps before the actual job is done,
-%D because we have to handle an optional identifier (and
-%D because these commands evolved out of a single case).
+\setupframedtext
+ [\c!width=0.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!backgroundscreen=\@@rsscreen,
+ \c!linecorrection=\v!on,
+ \c!depthcorrection=\v!on,
+ \c!margin=\v!standard]
-\def\framedtextparameter#1#2% todo: currentframedtext
- {\csname\??kd#1#2\endcsname}
+\appendtoks
+ \setuevalue{\e!start\currentframedtext}{\dostartframedtext{\currentframedtext}}%
+ \setuevalue{\e!stop \currentframedtext}{\dostopframedtext }%
+ \setuevalue {\currentframedtext}{\doframedtext {\currentframedtext}}%
+\to \everydefineframedtext
-\def\dosetupframedtexts[#1][#2]%
- {\ifsecondargument
- \def\docommand##1{\getparameters[\??kd##1][#2]}%
- \processcommacommand[#1]\docommand % new, #1 may be macro
- \else
- \getparameters[\??kd\v!framedtext][#1]%
- \fi}
+\unexpanded\def\dostartframedtext#1%
+ {\bgroup
+ \edef\currentframedtext{#1}%
+ \dodoubleempty\dodostartframedtext}
-\unexpanded\def\setupframedtexts
- {\dodoubleempty\dosetupframedtexts}
+\def\dodostartframedtext[#1][#2]%
+ {\doifassignmentelse{#1}
+ {\dododostartframedtext[][#1]}
+ {\dododostartframedtext[#1][#2]}}
-\def\dostartframedtext
- {\bgroup\dotripleempty\dodostartframedtext}
+\def\dododostartframedtext[#1][#2]% #2 only passed to framed, not to framedtext
+ {\setupframedtexts[\currentframedtext][#2]%
+ \doifsomething{#1}{\setframedtextparameter\c!location{#1}}% does not listen to #3
+ \setfalse\framedtextlocationnone
+ % somewhat messy ... needs to be redone
+ \processaction % \v!low en \v!depth are already taken !
+ [\framedtextparameter\c!location]
+ [ \v!left=>\letframedtextparameter\c!left \relax
+ \letframedtextparameter\c!right\hfill,
+ \v!right=>\letframedtextparameter\c!left \hfill
+ \letframedtextparameter\c!right\relax,
+ \v!middle=>\letframedtextparameter\c!left \hfill
+ \letframedtextparameter\c!right\hfill,
+ \v!none=>\letframedtextparameter\c!left \relax % new
+ \letframedtextparameter\c!right\relax % new
+ \settrue\framedtextlocationnone]%
+ \resetframedtextparameter\c!location
+ % removed 06/2001
+ % \forgetparindent
+ % added 06/2001 [see demo-bbv]
+ \localhsize\hsize \checkframedtext
+ % so far
+ \setbox\framebox\vbox
+ \startboxedcontent
+ \hsize\localhsize
+ % \insidefloattrue % ? better
+ \normalexpanded{\noexpand\switchtobodyfont[\framedtextparameter\c!bodyfont]}%
+ \startcolor[\framedtextparameter\c!color]%
+ \localframed[\??kd\currentframedtext][\c!strut=\v!no]% todo: use delayedstrut
+ \bgroup
+ \let\\=\endgraf
+ \framedtextparameter\c!inner % oud spul
+ \doif{\framedtextparameter\c!depthcorrection}\v!on\doftstartdepthcorrection
+ \doinhibitblank % \blank[\v!disable]% plaatst signal
+ \setupindenting[\framedtextparameter\c!indenting]%
+ %\doconvertfont{\framedtextparameter\c!style}\empty} %%%%% todo: attr setter
+ \dosetframedtextattributes\c!style\c!color}
-\def\dodostartframedtext[#1][#2][#3]%
- {\doifassignmentelse{#2}
- {\dododostartframedtext[#1][][#2]}
- {\dododostartframedtext[#1][#2][#3]}}
+%D The \type {none} option is handy for nested usage, as
+%D in the presentation styles, where we don't want
+%D interference.
+
+\defineplacement[\??kd][\s!parent=\??kd\currentframedtext]
+
+\unexpanded\def\dostopframedtext % no \baselinecorrection, see faq docs
+ {\endgraf
+ \removelastskip
+ \doif{\framedtextparameter\c!depthcorrection}\v!on\doftstopdepthcorrection
+ \stopboxedcontent
+ \stopcolor
+ \ifconditional\framedtextlocationnone
+ \egroup
+ \box\framebox
+ \else\ifinsidefloat
+ \egroup
+ \box\framebox
+ \else
+ \egroup
+ \placement[\??kd][\c!depthcorrection=\v!off]{\box\framebox}%
+ \fi\fi
+ \egroup}
+
+%D We define the general (and original) case by just saying:
\setfalse\framedtextlocationnone
@@ -2793,64 +2850,6 @@
% \donegbotbaselinecorrection
\verticalstrut}
-\def\dododostartframedtext[#1][#2][#3]% #3 only passed to framed, not to framedtext
- {\doifsomething{#2}{\setvalue{\??kd#1\c!location}{#2}}% does not listen to #3
- \setfalse\framedtextlocationnone
- \processaction % \v!low en \v!depth are already taken !
- [\framedtextparameter{#1}\c!location]
- [ \v!left=>\letvalue{\??kd#1\c!left }\relax
- \letvalue{\??kd#1\c!right}\hfill,
- \v!right=>\letvalue{\??kd#1\c!left }\hfill
- \letvalue{\??kd#1\c!right}\relax,
- \v!middle=>\letvalue{\??kd#1\c!left }\hfill
- \letvalue{\??kd#1\c!right}\hfill,
- \v!none=>\letvalue{\??kd#1\c!left }\relax % new
- \letvalue{\??kd#1\c!right}\relax % new
- \settrue\framedtextlocationnone]%
- \letvalueempty{\??kd#1\c!location}%
- % removed 06/2001
- % \forgetparindent
- % added 06/2001 [see demo-bbv]
- \localhsize\hsize \checkframedtext
- % so far
- \setbox\framebox\vbox
- \startboxedcontent
- \hsize\localhsize
- % \insidefloattrue % ? better
- \normalexpanded{\noexpand\switchtobodyfont[\framedtextparameter{#1}\c!bodyfont]}%
- \startcolor[\framedtextparameter{#1}\c!color]%
- \localframed[\??kd#1][\c!strut=\v!no,#3]% todo: use delayedstrut
- \bgroup
- \let\\=\endgraf
- \framedtextparameter{#1}\c!inner % oud spul
- \doifvalue{\??kd#1\c!depthcorrection}\v!on\doftstartdepthcorrection
- \doinhibitblank % \blank[\v!disable]% plaatst signal
- \setupindenting[\framedtextparameter{#1}\c!indenting]%
- \doconvertfont{\framedtextparameter{#1}\c!style}\empty
- \def\dostopframedtext{\dodostopframedtext{#1}{#2}}}
-
-%D The \type {none} option is handy for nested usage, as
-%D in the presentation styles, where we don't want
-%D interference.
-
-\def\dodostopframedtext#1#2% % no \baselinecorrection, see faq docs
- {\endgraf
- \removelastskip
- \doifvalue{\??kd#1\c!depthcorrection}\v!on\doftstopdepthcorrection
- \stopboxedcontent
- \stopcolor
- \ifconditional\framedtextlocationnone
- \egroup
- \box\framebox
- \else\ifinsidefloat
- \egroup
- \box\framebox
- \else
- \egroup
- \doplacement[\??kd#1][\c!depthcorrection=\v!off]{\box\framebox}%
- \fi\fi
- \egroup}
-
%D Placement can be ignored:
%D
%D \starttyping
@@ -2869,17 +2868,19 @@
%D The simple brace (or group) delimited case is typeset
%D slightly different and is not aligned.
-\def\doframedtext
- {\bgroup\dodoubleempty\dodoframedtext}
+\unexpanded\def\doframedtext#1%
+ {\bgroup
+ \edef\currentframedtext{#1}%
+ \dosingleempty\dodoframedtext}
-\def\dodoframedtext[#1][#2]% beware!
- {\normalexpanded{\noexpand\switchtobodyfont[\getvalue{\??kd#1\c!bodyfont}]}%
- \localframed[\??kd#1][\c!strut=\v!no,#2]%
+\def\dodoframedtext[#1]% beware!
+ {\normalexpanded{\noexpand\switchtobodyfont[\\framedtextparameter\c!bodyfont]}%
+ \localframed[\??kd\currentframedtext][\c!strut=\v!no,#1]%
\bgroup
\blank[\v!disable]%
\let\\=\endgraf
- \getvalue{\??kd#1\c!inner}% % kleur naar outer level
- \dostartattributes{\??kd#1}\c!style\c!color\empty
+ \framedtextparameter\c!inner
+ \dosetframedtextattributes\c!style\c!color
\bgroup
\aftergroup\docloseframedtext
\let\next=}
@@ -2890,6 +2891,8 @@
\egroup
\egroup}
+\defineframedtext[\v!framedtext]
+
%D \macros
%D {defineframed}
%D
@@ -2902,17 +2905,6 @@
%D also simplified the \type {\setupframed} command. There are
%D certainly more places where such improvements can be made.
-% \unexpanded\def\defineframed
-% {\dodoubleempty\dodefineframed}
-%
-% \def\dodefineframed[#1][#2]%
-% {\iffirstargument
-% \setuvalue{#1}{\dodoubleempty\doframed[#2]}%
-% \fi}
-%
-% \def\doframed[#1][#2]%
-% {\framed[#1,#2]}
-
\def\defineframed
{\dodoubleempty\dodefineframed}
diff --git a/tex/context/base/page-bck.mkiv b/tex/context/base/page-bck.mkiv
index ddea18c5f..81392f5af 100644
--- a/tex/context/base/page-bck.mkiv
+++ b/tex/context/base/page-bck.mkiv
@@ -296,7 +296,7 @@
\box#1}%
\fi}
-\newdimen\pagebackgroundhoffset
+\newdimen\pagebackgroundhoffset % THESE WILL BECOME OBSOLETE
\newdimen\pagebackgroundvoffset
\newdimen\pagebackgrounddepth
\newdimen\pagebackgroundoffset
diff --git a/tex/context/base/page-flt.lua b/tex/context/base/page-flt.lua
index 67e2e5b6f..b691dbd45 100644
--- a/tex/context/base/page-flt.lua
+++ b/tex/context/base/page-flt.lua
@@ -10,7 +10,7 @@ if not modules then modules = { } end modules ['page-flt'] = {
local insert, remove = table.insert, table.remove
local find = string.find
-local setdimen, setbox, setcount, texbox = tex.setdimen, tex.setbox, tex.setcount, tex.box
+local setdimen, setcount, texbox = tex.setdimen, tex.setcount, tex.box
local copy_node_list = node.copy_list
diff --git a/tex/context/base/page-imp.mkii b/tex/context/base/page-imp.mkii
index 11ef561e2..4c22d4d2d 100644
--- a/tex/context/base/page-imp.mkii
+++ b/tex/context/base/page-imp.mkii
@@ -3,7 +3,7 @@
%D version=1998.01.15,
%D title=\CONTEXT\ Page Macros,
%D subtitle=Pagebody Building (Imposition),
-%D author=Hans Hagen,
+%D author=Hans Hagen & Willi Egger,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
%C
@@ -806,6 +806,364 @@
\setuppaper
[\c!width =\dimexpr\printpaperwidth -2\dimexpr\@@ppbackspace\relax\relax,
\c!height=\dimexpr\printpaperheight-2\dimexpr\@@pptopspace \relax\relax]
+
+%D Might be used if a printer is printing from a rol or creating mini-books from A4:
+%D This section has 16 pages. The folding scheme is first a Z-fold and at the end
+%D a final fold in the spine.
+%D Coding: [2*8*Z]
+
+\installpagearrangement 2*8*Z
+ {\dosetuparrangement{2}{4}{8}{3}{5}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageSIXTEENZ\poparrangedpagesAB\relax}
+
+\def\pusharrangedpageSIXTEENZ#1%
+ {\doglobal\increment\arrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}010\arrangedpageA % 1
+ \or \handlearrangedpageXandY{#1}000\arrangedpageB % 2
+ \or \handlearrangedpageXandY{#1}101\arrangedpageB % 3
+ \or \handlearrangedpageXandY{#1}111\arrangedpageA % 4
+ \or \handlearrangedpageXandY{#1}012\arrangedpageA % 5
+ \or \handlearrangedpageXandY{#1}002\arrangedpageB % 6
+ \or \handlearrangedpageXandY{#1}103\arrangedpageB % 7
+ \or \handlearrangedpageXandY{#1}113\arrangedpageA % 8
+ \or \handlearrangedpageXandY{#1}103\arrangedpageA % 9
+ \or \handlearrangedpageXandY{#1}113\arrangedpageB % 10
+ \or \handlearrangedpageXandY{#1}012\arrangedpageB % 11
+ \or \handlearrangedpageXandY{#1}002\arrangedpageA % 12
+ \or \handlearrangedpageXandY{#1}101\arrangedpageA % 13
+ \or \handlearrangedpageXandY{#1}111\arrangedpageB % 14
+ \or \handlearrangedpageXandY{#1}010\arrangedpageB % 15
+ \or \handlearrangedpageXandY{#1}000\arrangedpageA % 16
+ \poparrangedpages
+ \fi}
+
+%D Another Z-folded section with 12 pages
+%D Coding: [2*6*Z]
+
+\installpagearrangement 2*6*Z
+ {\dosetuparrangement{2}{3}{6}{3}{4}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageTWELVEZ\poparrangedpagesAB\relax}
+
+\def\pusharrangedpageTWELVEZ#1%
+ {\doglobal\increment\arrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}010\arrangedpageA % 1: rotation (0=upright),x (0=first column),y (0=first row)
+ \or \handlearrangedpageXandY{#1}000\arrangedpageB % 2
+ \or \handlearrangedpageXandY{#1}101\arrangedpageB % 3
+ \or \handlearrangedpageXandY{#1}111\arrangedpageA % 4
+ \or \handlearrangedpageXandY{#1}012\arrangedpageA % 5
+ \or \handlearrangedpageXandY{#1}002\arrangedpageB % 6
+ \or \handlearrangedpageXandY{#1}012\arrangedpageB % 7
+ \or \handlearrangedpageXandY{#1}002\arrangedpageA % 8
+ \or \handlearrangedpageXandY{#1}101\arrangedpageA % 9
+ \or \handlearrangedpageXandY{#1}111\arrangedpageB % 10
+ \or \handlearrangedpageXandY{#1}010\arrangedpageB % 11
+ \or \handlearrangedpageXandY{#1}000\arrangedpageA % 12
+ \poparrangedpages
+ \fi}
+
+%D For Heinz' special greeting cards folding. This scheme is also used for the PocketDiary (module):
+%D Coding: [1*8]
+
+\installpagearrangement 1*8
+ {\dosetuparrangement{4}{2}{8}{5}{3} % X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageEIGHTSINGLESIDEDFOLDED\poparrangedpagesTWO\relax}
+
+\def\pusharrangedpageEIGHTSINGLESIDEDFOLDED#1%
+ {\doglobal\increment\arrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}010\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}020\arrangedpageA % 2
+ \or \handlearrangedpageXandY{#1}030\arrangedpageA % 3
+ \or \handlearrangedpageXandY{#1}131\arrangedpageA % 4
+ \or \handlearrangedpageXandY{#1}121\arrangedpageA % 5
+ \or \handlearrangedpageXandY{#1}111\arrangedpageA % 6
+ \or \handlearrangedpageXandY{#1}101\arrangedpageA % 7
+ \or \handlearrangedpageXandY{#1}000\arrangedpageA % 8
+ \poparrangedpages
+ \fi}
+
+%D This is not a section. \CONTEXT\ places 4 pages on a sheet of paper, singlesided
+%D Coding: [1*4]
+
+\installpagearrangement 1*4
+ {\dosetuparrangement{2}{2}{4}{3}{3} % X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageFOURSINGLESIDEDFOLDED\poparrangedpagesTWO\relax}
+
+\def\pusharrangedpageFOURSINGLESIDEDFOLDED#1%
+ {\doglobal\increment\arrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}100\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}001\arrangedpageA % 2
+ \or \handlearrangedpageXandY{#1}011\arrangedpageA % 3
+ \or \handlearrangedpageXandY{#1}110\arrangedpageA % 4
+ \poparrangedpages
+ \fi}
+
+%D This imposition scheme was requested by Hraban Ramm, by Willi Egger 21-07-2003
+%D Coding: [3SIDE]
+
+\installpagearrangement 3SIDE
+ {\dosetuparrangement{3}{1}{3}{4}{2}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageTHREESIDE\poparrangedpagesAB\relax}
+
+\def\pusharrangedpageTHREESIDE#1% Willi's approach
+ {\doglobal\increment\arrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}000\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}010\arrangedpageA % 2
+ \or \handlearrangedpageXandY{#1}020\arrangedpageA % 3
+ \or \handlearrangedpageXandY{#1}000\arrangedpageB % 4
+ \or \handlearrangedpageXandY{#1}010\arrangedpageB % 5
+ \or \handlearrangedpageXandY{#1}020\arrangedpageB % 6
+ \poparrangedpages
+ \fi}
+
+%D FLYER in three parts and 6 pages 22-10-2010
+%D Coding: [TRYPTICHON]
+
+\installpagearrangement TRYPTICHON
+ {\dosetuparrangement{3}{1}{3}{4}{2}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageFOLDERSIX\poparrangedpagesAB\relax}
+
+\def\pusharrangedpageFOLDERSIX#1% Willi's approach
+ {\doglobal\increment\arrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}020\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}000\arrangedpageB % 2
+ \or \handlearrangedpageXandY{#1}010\arrangedpageB % 3
+ \or \handlearrangedpageXandY{#1}020\arrangedpageB % 4
+ \or \handlearrangedpageXandY{#1}000\arrangedpageA % 5
+ \or \handlearrangedpageXandY{#1}010\arrangedpageA % 6
+ \poparrangedpages
+ \fi}
+
+%D FLYER in Z-fold with 8 pages 22-01-2010
+%D Coding: [ZFLYER-8]
+
+\installpagearrangement ZFLYER-8
+ {\dosetuparrangement{4}{1}{4}{5}{2}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageZFOLDEREIGHT\poparrangedpagesAB\relax}
+
+\def\pusharrangedpageZFOLDEREIGHT#1% Willi's approach
+ {\doglobal\increment\arrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}030\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}000\arrangedpageB % 2
+ \or \handlearrangedpageXandY{#1}010\arrangedpageB % 3
+ \or \handlearrangedpageXandY{#1}020\arrangedpageB % 4
+ \or \handlearrangedpageXandY{#1}030\arrangedpageB % 5
+ \or \handlearrangedpageXandY{#1}000\arrangedpageA % 6
+ \or \handlearrangedpageXandY{#1}010\arrangedpageA % 7
+ \or \handlearrangedpageXandY{#1}020\arrangedpageA % 8
+ \poparrangedpages
+ \fi}
+
+%D FLYER in Z-fold with 10 pages 04-08-2010
+%D Coding: [ZFLYER-10]
+
+\installpagearrangement ZFLYER-10
+ {\dosetuparrangement{5}{1}{5}{6}{2}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageZFLYERTEN\poparrangedpagesAB\relax}
+
+\def\pusharrangedpageZFLYERTEN#1% Willi's approach
+ {\doglobal\increment\arrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}040\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}000\arrangedpageB % 2
+ \or \handlearrangedpageXandY{#1}010\arrangedpageB % 3
+ \or \handlearrangedpageXandY{#1}020\arrangedpageB % 4
+ \or \handlearrangedpageXandY{#1}030\arrangedpageB % 5
+ \or \handlearrangedpageXandY{#1}040\arrangedpageB % 6
+ \or \handlearrangedpageXandY{#1}000\arrangedpageA % 7
+ \or \handlearrangedpageXandY{#1}010\arrangedpageA % 8
+ \or \handlearrangedpageXandY{#1}020\arrangedpageA % 9
+ \or \handlearrangedpageXandY{#1}030\arrangedpageA % 10
+ \poparrangedpages
+ \fi}
+
+
+%D FLYER in Z-fold with 12 pages 04-08-2010
+%D Coding: [ZFLYER-12]
+
+\installpagearrangement ZFLYER-12
+ {\dosetuparrangement{6}{1}{6}{7}{2}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageZFLYERTWELVE\poparrangedpagesAB\relax}
+
+\def\pusharrangedpageZFLYERTWELVE#1% Willi's approach
+ {\doglobal\increment\arrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}050\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}000\arrangedpageB % 2
+ \or \handlearrangedpageXandY{#1}010\arrangedpageB % 3
+ \or \handlearrangedpageXandY{#1}020\arrangedpageB % 4
+ \or \handlearrangedpageXandY{#1}030\arrangedpageB % 5
+ \or \handlearrangedpageXandY{#1}040\arrangedpageB % 6
+ \or \handlearrangedpageXandY{#1}050\arrangedpageB % 7
+ \or \handlearrangedpageXandY{#1}000\arrangedpageA % 8
+ \or \handlearrangedpageXandY{#1}010\arrangedpageA % 9
+ \or \handlearrangedpageXandY{#1}020\arrangedpageA % 10
+ \or \handlearrangedpageXandY{#1}030\arrangedpageA % 11
+ \or \handlearrangedpageXandY{#1}040\arrangedpageA % 12
+ \poparrangedpages
+ \fi}
+
+%D FLYER folded as a map with 6 pages per side.
+%D Coding: [MAPFLYER-12]
+
+\installpagearrangement MAPFLYER-12
+ {\dosetuparrangement{3}{2}{6}{4}{2}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageMFOLDERTWELVE\poparrangedpagesAB\relax}
+
+\def\pusharrangedpageMFOLDERTWELVE#1% Willi's approach
+ {\doglobal\increment\arrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}020\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}000\arrangedpageB % 2
+ \or \handlearrangedpageXandY{#1}001\arrangedpageB % 3
+ \or \handlearrangedpageXandY{#1}010\arrangedpageB % 4
+ \or \handlearrangedpageXandY{#1}011\arrangedpageB % 5
+ \or \handlearrangedpageXandY{#1}020\arrangedpageB % 6
+ \or \handlearrangedpageXandY{#1}021\arrangedpageB % 7
+ \or \handlearrangedpageXandY{#1}000\arrangedpageA % 8
+ \or \handlearrangedpageXandY{#1}001\arrangedpageA % 9
+ \or \handlearrangedpageXandY{#1}010\arrangedpageA % 10
+ \or \handlearrangedpageXandY{#1}011\arrangedpageA % 11
+ \or \handlearrangedpageXandY{#1}021\arrangedpageA % 12
+ \poparrangedpages
+ \fi}
+
+%D FLYER folded as double window with 4 pages per side.
+%D Coding: [DOUBLEWINDOW]
+
+\installpagearrangement DOUBLEWINDOW
+ {\dosetuparrangement{4}{1}{4}{5}{2}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageDOUBLEWINDOWEIGHT\poparrangedpagesAB\relax}
+
+\def\pusharrangedpageDOUBLEWINDOWEIGHT#1% Willi's approach
+ {\doglobal\increment\arrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}020\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}030\arrangedpageA % 2
+ \or \handlearrangedpageXandY{#1}000\arrangedpageB % 3
+ \or \handlearrangedpageXandY{#1}010\arrangedpageB % 4
+ \or \handlearrangedpageXandY{#1}020\arrangedpageB % 5
+ \or \handlearrangedpageXandY{#1}030\arrangedpageB % 6
+ \or \handlearrangedpageXandY{#1}000\arrangedpageA % 7
+ \or \handlearrangedpageXandY{#1}010\arrangedpageA % 8
+ \poparrangedpages
+ \fi}
+
+%D Imposition as requested by Jan Pohanka 26-08-2010, 4 pages, two verso, two recto,
+%D uneven pages upright and down, even pages top and rotated 180.
+%D Implementation with 2 pages for conference-name-display
+%D Coding: [1*2-Conference]
+
+\installpagearrangement 1*2-Conference
+ {\dosetuparrangement{1}{2}{4}{3}{2}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageCONFERENCE2\poparrangedpagesAB\relax}
+
+\def\pusharrangedpageCONFERENCE2#1%
+ {\doglobal\increment\arrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}001\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}100\arrangedpageA % 2
+ \poparrangedpages
+ \fi}
+
+%D Implementation with 4 pages for conference-name-display
+%D Coding: [1*4-Conference]
+
+\installpagearrangement 1*4-Conference
+ {\dosetuparrangement{1}{2}{4}{3}{2}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageCONFERENCE4\poparrangedpagesAB\relax}
+
+\def\pusharrangedpageCONFERENCE4#1%
+ {\doglobal\increment\arrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}001\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}100\arrangedpageA % 2
+ \or \handlearrangedpageXandY{#1}011\arrangedpageB % 3
+ \or \handlearrangedpageXandY{#1}110\arrangedpageB % 4
+ \poparrangedpages
+ \fi}
+
+% There should be arrangements for section made of heavy and thick paper. i.e. the heavier the paper
+% the fewer pages per section:
+% Section with 8 pages put on to sheets of paper. Each sheet carries recto 2 and verso 2 pages.
+% Coding: [2*2*2]
+
+\installpagearrangement 2*2*2
+ {\dosetuparrangement{2}{1}{2}{3}{2}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageEIGHTTWO\poparrangedpagesAtoD\relax}
+
+\def\pusharrangedpageEIGHTWO#1%
+ {\doglobal\increment\arrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}010\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}000\arrangedpageB % 2
+ \or \handlearrangedpageXandY{#1}010\arrangedpageC % 3
+ \or \handlearrangedpageXandY{#1}000\arrangedpageD % 4
+ \or \handlearrangedpageXandY{#1}010\arrangedpageD % 5
+ \or \handlearrangedpageXandY{#1}000\arrangedpageC % 6
+ \or \handlearrangedpageXandY{#1}010\arrangedpageB % 7
+ \or \handlearrangedpageXandY{#1}000\arrangedpageA % 8
+ \poparrangedpages
+ \fi}
+
+% Section with 12 pages, built from three sheets of paper.
+% Each sheet carries 2 pages recto and verso.
+% Coding: [2*2*3]
+
+\def\poparrangedpagesAtoF
+ {\ifnum\arrangedpageN>\zerocount
+ \paperwidth \arrangedpageX\paperwidth
+ \paperheight\arrangedpageY\paperheight
+ \outputarrangedbox\arrangedpageA
+ \outputarrangedbox\arrangedpageB
+ \outputarrangedbox\arrangedpageC
+ \outputarrangedbox\arrangedpageD
+ \outputarrangedbox\arrangedpageE
+ \outputarrangedbox\arrangedpageF
+ \global\arrangedpageN\zerocount
+ \fi}
+\installpagearrangement 2*2*3
+ {\dosetuparrangement{2}{1}{2}{3}{2}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageTWELVETWO\poparrangedpagesAtoD\relax}
+
+\def\pusharrangedpageTWELVETWO#1%
+ {\doglobal\increment\arrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}010\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}000\arrangedpageB % 2
+ \or \handlearrangedpageXandY{#1}010\arrangedpageC % 3
+ \or \handlearrangedpageXandY{#1}000\arrangedpageD % 4
+ \or \handlearrangedpageXandY{#1}010\arrangedpageE % 5
+ \or \handlearrangedpageXandY{#1}000\arrangedpageF % 6
+ \or \handlearrangedpageXandY{#1}010\arrangedpageF % 7
+ \or \handlearrangedpageXandY{#1}000\arrangedpageE % 8
+ \or \handlearrangedpageXandY{#1}010\arrangedpageD % 9
+ \or \handlearrangedpageXandY{#1}000\arrangedpageC % 10
+ \or \handlearrangedpageXandY{#1}010\arrangedpageB % 11
+ \or \handlearrangedpageXandY{#1}000\arrangedpageA % 12
+ \poparrangedpages
+ \fi}
% \definepageshift[test][horizontal][10pt,20pt,30pt,40pt,50pt]
% \definepageshift[test][vertical] [10pt,20pt,30pt,40pt,50pt]
diff --git a/tex/context/base/page-imp.mkiv b/tex/context/base/page-imp.mkiv
index cc48b9359..e01202c81 100644
--- a/tex/context/base/page-imp.mkiv
+++ b/tex/context/base/page-imp.mkiv
@@ -3,7 +3,7 @@
%D version=1998.01.15,
%D title=\CONTEXT\ Page Macros,
%D subtitle=Pagebody Building (Imposition),
-%D author=Hans Hagen,
+%D author=Hans Hagen & Willi Egger,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
%C
@@ -738,6 +738,365 @@
\or \handlearrangedpageXandY{#1}001\arrangedpageA % 16
\poparrangedpages
\fi}
+
+%D Might be used if a printer is printing from a rol or creating mini-books from A4:
+%D This section has 16 pages. The folding scheme is first a Z-fold and at the end
+%D a final fold in the spine.
+%D Coding: [2*8*Z]
+
+\installpagearrangement 2*8*Z
+ {\dosetuparrangement{2}{4}{8}{3}{5}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageSIXTEENZ\poparrangedpagesAB\relax}
+
+
+\def\pusharrangedpageSIXTEENZ#1%
+ {\advancearrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}010\arrangedpageA % 1
+ \or \handlearrangedpageXandY{#1}000\arrangedpageB % 2
+ \or \handlearrangedpageXandY{#1}101\arrangedpageB % 3
+ \or \handlearrangedpageXandY{#1}111\arrangedpageA % 4
+ \or \handlearrangedpageXandY{#1}012\arrangedpageA % 5
+ \or \handlearrangedpageXandY{#1}002\arrangedpageB % 6
+ \or \handlearrangedpageXandY{#1}103\arrangedpageB % 7
+ \or \handlearrangedpageXandY{#1}113\arrangedpageA % 8
+ \or \handlearrangedpageXandY{#1}103\arrangedpageA % 9
+ \or \handlearrangedpageXandY{#1}113\arrangedpageB % 10
+ \or \handlearrangedpageXandY{#1}012\arrangedpageB % 11
+ \or \handlearrangedpageXandY{#1}002\arrangedpageA % 12
+ \or \handlearrangedpageXandY{#1}101\arrangedpageA % 13
+ \or \handlearrangedpageXandY{#1}111\arrangedpageB % 14
+ \or \handlearrangedpageXandY{#1}010\arrangedpageB % 15
+ \or \handlearrangedpageXandY{#1}000\arrangedpageA % 16
+ \poparrangedpages
+ \fi}
+
+%D Another Z-folded section with 12 pages
+%D Coding: [2*6*Z]
+
+\installpagearrangement 2*6*Z
+ {\dosetuparrangement{2}{3}{6}{3}{4}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageTWELVEZ\poparrangedpagesAB\relax}
+
+\def\pusharrangedpageTWELVEZ#1%
+ {\advancearrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}010\arrangedpageA % 1: rotation (0=upright),x (0=first column),y (0=first row)
+ \or \handlearrangedpageXandY{#1}000\arrangedpageB % 2
+ \or \handlearrangedpageXandY{#1}101\arrangedpageB % 3
+ \or \handlearrangedpageXandY{#1}111\arrangedpageA % 4
+ \or \handlearrangedpageXandY{#1}012\arrangedpageA % 5
+ \or \handlearrangedpageXandY{#1}002\arrangedpageB % 6
+ \or \handlearrangedpageXandY{#1}012\arrangedpageB % 7
+ \or \handlearrangedpageXandY{#1}002\arrangedpageA % 8
+ \or \handlearrangedpageXandY{#1}101\arrangedpageA % 9
+ \or \handlearrangedpageXandY{#1}111\arrangedpageB % 10
+ \or \handlearrangedpageXandY{#1}010\arrangedpageB % 11
+ \or \handlearrangedpageXandY{#1}000\arrangedpageA % 12
+ \poparrangedpages
+ \fi}
+
+%D For Heinz' special greeting cards folding. This scheme is also used for the PocketDiary (module):
+%D Coding: [1*8]
+
+\installpagearrangement 1*8
+ {\dosetuparrangement{4}{2}{8}{5}{3}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageEIGHTSINGLESIDEDFOLDED\poparrangedpagesTWO\relax}
+
+\def\pusharrangedpageEIGHTSINGLESIDEDFOLDED#1%
+ {\advancearrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}010\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}020\arrangedpageA % 2
+ \or \handlearrangedpageXandY{#1}030\arrangedpageA % 3
+ \or \handlearrangedpageXandY{#1}131\arrangedpageA % 4
+ \or \handlearrangedpageXandY{#1}121\arrangedpageA % 5
+ \or \handlearrangedpageXandY{#1}111\arrangedpageA % 6
+ \or \handlearrangedpageXandY{#1}101\arrangedpageA % 7
+ \or \handlearrangedpageXandY{#1}000\arrangedpageA % 8
+ \poparrangedpages
+ \fi}
+
+%D This is not a section. \CONTEXT\ places 4 pages on a sheet of paper, singlesided
+%D Coding: [1*4]
+
+\installpagearrangement 1*4
+ {\dosetuparrangement{2}{2}{4}{3}{3}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageFOURSINGLESIDEDFOLDED\poparrangedpagesTWO\relax}
+
+\def\pusharrangedpageFOURSINGLESIDEDFOLDED#1%
+ {\advancearrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}100\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}001\arrangedpageA % 2
+ \or \handlearrangedpageXandY{#1}011\arrangedpageA % 3
+ \or \handlearrangedpageXandY{#1}110\arrangedpageA % 4
+ \poparrangedpages
+ \fi}
+
+%D This imposition scheme was requested by Hraban Ramm, by Willi Egger 21-07-2003
+%D Coding: [3SIDE]
+
+\installpagearrangement 3SIDE
+ {\dosetuparrangement{3}{1}{3}{4}{2}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageTHREESIDE\poparrangedpagesAB\relax}
+
+\def\pusharrangedpageTHREESIDE#1% Willi's approach
+ {\advancearrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}000\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}010\arrangedpageA % 2
+ \or \handlearrangedpageXandY{#1}020\arrangedpageA % 3
+ \or \handlearrangedpageXandY{#1}000\arrangedpageB % 4
+ \or \handlearrangedpageXandY{#1}010\arrangedpageB % 5
+ \or \handlearrangedpageXandY{#1}020\arrangedpageB % 6
+ \poparrangedpages
+ \fi}
+
+%D FLYER in three parts and 6 pages 22-10-2010
+%D Coding: [TRYPTICHON]
+
+\installpagearrangement TRYPTICHON
+ {\dosetuparrangement{3}{1}{3}{4}{2}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageFLYERSIX\poparrangedpagesAB\relax}
+
+\def\pusharrangedpageFLYERSIX#1% Willi's approach
+ {\advancearrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}020\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}000\arrangedpageB % 2
+ \or \handlearrangedpageXandY{#1}010\arrangedpageB % 3
+ \or \handlearrangedpageXandY{#1}020\arrangedpageB % 4
+ \or \handlearrangedpageXandY{#1}000\arrangedpageA % 5
+ \or \handlearrangedpageXandY{#1}010\arrangedpageA % 6
+ \poparrangedpages
+ \fi}
+
+%D FLYER in Z-fold with 8 pages 22-01-2010
+%D Coding: [ZFLYER-8]
+
+\installpagearrangement ZFLYER-8
+ {\dosetuparrangement{4}{1}{4}{5}{2}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageZFLYEREIGHT\poparrangedpagesAB\relax}
+
+\def\pusharrangedpageZFLYEREIGHT#1% Willi's approach
+ {\advancearrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}030\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}000\arrangedpageB % 2
+ \or \handlearrangedpageXandY{#1}010\arrangedpageB % 3
+ \or \handlearrangedpageXandY{#1}020\arrangedpageB % 4
+ \or \handlearrangedpageXandY{#1}030\arrangedpageB % 5
+ \or \handlearrangedpageXandY{#1}000\arrangedpageA % 6
+ \or \handlearrangedpageXandY{#1}010\arrangedpageA % 7
+ \or \handlearrangedpageXandY{#1}020\arrangedpageA % 8
+ \poparrangedpages
+ \fi}
+
+%D FLYER in Z-fold with 10 pages 04-08-2010
+%D Coding: [ZFLYER-10]
+
+\installpagearrangement ZFLYER-10
+ {\dosetuparrangement{5}{1}{5}{6}{2}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageZFLYERTEN\poparrangedpagesAB\relax}
+
+\def\pusharrangedpageZFLYERTEN#1% Willi's approach
+ {\advancearrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}040\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}000\arrangedpageB % 2
+ \or \handlearrangedpageXandY{#1}010\arrangedpageB % 3
+ \or \handlearrangedpageXandY{#1}020\arrangedpageB % 4
+ \or \handlearrangedpageXandY{#1}030\arrangedpageB % 5
+ \or \handlearrangedpageXandY{#1}040\arrangedpageB % 6
+ \or \handlearrangedpageXandY{#1}000\arrangedpageA % 7
+ \or \handlearrangedpageXandY{#1}010\arrangedpageA % 8
+ \or \handlearrangedpageXandY{#1}020\arrangedpageA % 9
+ \or \handlearrangedpageXandY{#1}030\arrangedpageA % 10
+ \poparrangedpages
+ \fi}
+
+%D FLYER in Z-fold with 12 pages 04-08-2010
+%D Coding: [ZFLYER-12]
+
+\installpagearrangement ZFLYER-12
+ {\dosetuparrangement{6}{1}{6}{7}{2}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageZFLYERTWELVE\poparrangedpagesAB\relax}
+
+\def\pusharrangedpageZFLYERTWELVE#1% Willi's approach
+ {\advancearrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}050\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}000\arrangedpageB % 2
+ \or \handlearrangedpageXandY{#1}010\arrangedpageB % 3
+ \or \handlearrangedpageXandY{#1}020\arrangedpageB % 4
+ \or \handlearrangedpageXandY{#1}030\arrangedpageB % 5
+ \or \handlearrangedpageXandY{#1}040\arrangedpageB % 6
+ \or \handlearrangedpageXandY{#1}050\arrangedpageB % 7
+ \or \handlearrangedpageXandY{#1}000\arrangedpageA % 8
+ \or \handlearrangedpageXandY{#1}010\arrangedpageA % 9
+ \or \handlearrangedpageXandY{#1}020\arrangedpageA % 10
+ \or \handlearrangedpageXandY{#1}030\arrangedpageA % 11
+ \or \handlearrangedpageXandY{#1}040\arrangedpageA % 12
+ \poparrangedpages
+ \fi}
+
+%D FLYER folded as a map with 6 pages per side.
+%D Coding: [MAPFLYER-12]
+
+\installpagearrangement MAPFLYER-12
+ {\dosetuparrangement{3}{2}{6}{4}{3}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageMFLYERTWELVE\poparrangedpagesAB\relax}
+
+\def\pusharrangedpageMFLYERTWELVE#1% Willi's approach
+ {\advancearrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}020\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}000\arrangedpageB % 2
+ \or \handlearrangedpageXandY{#1}001\arrangedpageB % 3
+ \or \handlearrangedpageXandY{#1}010\arrangedpageB % 4
+ \or \handlearrangedpageXandY{#1}011\arrangedpageB % 5
+ \or \handlearrangedpageXandY{#1}020\arrangedpageB % 6
+ \or \handlearrangedpageXandY{#1}021\arrangedpageB % 7
+ \or \handlearrangedpageXandY{#1}000\arrangedpageA % 8
+ \or \handlearrangedpageXandY{#1}001\arrangedpageA % 9
+ \or \handlearrangedpageXandY{#1}010\arrangedpageA % 10
+ \or \handlearrangedpageXandY{#1}011\arrangedpageA % 11
+ \or \handlearrangedpageXandY{#1}021\arrangedpageA % 12
+ \poparrangedpages
+ \fi}
+
+%D FLYER folded as double window with 4 pages per side.
+%D Coding: [DOUBLEWINDOW]
+
+\installpagearrangement DOUBLEWINDOW
+ {\dosetuparrangement{4}{1}{4}{5}{2}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageDOUBLEWINDOWEIGHT\poparrangedpagesAB\relax}
+
+\def\pusharrangedpageDOUBLEWINDOWEIGHT#1% Willi's approach
+ {\advancearrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}020\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}030\arrangedpageA % 2
+ \or \handlearrangedpageXandY{#1}000\arrangedpageB % 3
+ \or \handlearrangedpageXandY{#1}010\arrangedpageB % 4
+ \or \handlearrangedpageXandY{#1}020\arrangedpageB % 5
+ \or \handlearrangedpageXandY{#1}030\arrangedpageB % 6
+ \or \handlearrangedpageXandY{#1}000\arrangedpageA % 7
+ \or \handlearrangedpageXandY{#1}010\arrangedpageA % 8
+ \poparrangedpages
+ \fi}
+
+%D Imposition as requested by Jan Pohanka 26-08-2010, 4 pages, two verso, two recto,
+%D uneven pages upright and down, even pages top and rotated 180.
+%D Implementation with 2 pages for conference-name-display
+%D Coding: [1*2-Conference]
+
+\installpagearrangement 1*2-Conference
+ {\dosetuparrangement{1}{2}{4}{3}{2}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageCONFERENCE2\poparrangedpagesAB\relax}
+
+\def\pusharrangedpageCONFERENCE2#1%
+ {\advancearrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}001\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}100\arrangedpageA % 2
+ \poparrangedpages
+ \fi}
+
+%D Implementation with 4 pages for conference-name-display
+%D Coding: [1*4-Conference]
+
+\installpagearrangement 1*4-Conference
+ {\dosetuparrangement{1}{2}{4}{3}{2}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageCONFERENCE4\poparrangedpagesAB\relax}
+
+\def\pusharrangedpageCONFERENCE4#1%
+ {\advancearrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}001\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}100\arrangedpageA % 2
+ \or \handlearrangedpageXandY{#1}011\arrangedpageB % 3
+ \or \handlearrangedpageXandY{#1}110\arrangedpageB % 4
+ \poparrangedpages
+ \fi}
+
+%D There should be arrangements for sections made of heavy and thick paper. i.e. the heavier the paper
+%D the fewer pages per section:
+%D Section with 8 pages put on to sheets of paper. Each sheet carries recto 2 and verso 2 pages.
+%D Coding: [2*2*2]
+
+\installpagearrangement 2*2*2
+ {\dosetuparrangement{2}{1}{2}{3}{2}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageEIGHTTWO\poparrangedpagesAtoD\relax}
+
+\def\pusharrangedpageEIGHTTWO#1%
+ {\advancearrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}010\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}000\arrangedpageB % 2
+ \or \handlearrangedpageXandY{#1}010\arrangedpageC % 3
+ \or \handlearrangedpageXandY{#1}000\arrangedpageD % 4
+ \or \handlearrangedpageXandY{#1}010\arrangedpageD % 5
+ \or \handlearrangedpageXandY{#1}000\arrangedpageC % 6
+ \or \handlearrangedpageXandY{#1}010\arrangedpageB % 7
+ \or \handlearrangedpageXandY{#1}000\arrangedpageA % 8
+ \poparrangedpages
+ \fi}
+
+%D Section with 12 pages, built from three sheets of paper.
+%D Each sheet carries 2 pages recto and verso.
+%D Coding: [2*2*3]
+
+\def\poparrangedpagesAtoF
+ {\ifnum\arrangedpageN>\zerocount
+ \paperwidth \arrangedpageX\paperwidth
+ \paperheight\arrangedpageY\paperheight
+ \outputarrangedbox\arrangedpageA
+ \outputarrangedbox\arrangedpageB
+ \outputarrangedbox\arrangedpageC
+ \outputarrangedbox\arrangedpageD
+ \outputarrangedbox\arrangedpageE
+ \outputarrangedbox\arrangedpageF
+ \global\arrangedpageN\zerocount
+ \fi}
+
+\installpagearrangement 2*2*3
+ {\dosetuparrangement{2}{1}{2}{3}{2}% X,Y,Total,hcutmarks,vcutmarks
+ \pusharrangedpageTWELVETWO\poparrangedpagesAtoF\relax}
+
+\def\pusharrangedpageTWELVETWO#1%
+ {\advancearrangedpageN
+ \reportarrangedpage\arrangedpageN
+ \ifcase\arrangedpageN
+ \or \handlearrangedpageXandY{#1}010\arrangedpageA % 1 rot,hskip,vskip
+ \or \handlearrangedpageXandY{#1}000\arrangedpageB % 2
+ \or \handlearrangedpageXandY{#1}010\arrangedpageC % 3
+ \or \handlearrangedpageXandY{#1}000\arrangedpageD % 4
+ \or \handlearrangedpageXandY{#1}010\arrangedpageE % 5
+ \or \handlearrangedpageXandY{#1}000\arrangedpageF % 6
+ \or \handlearrangedpageXandY{#1}010\arrangedpageF % 7
+ \or \handlearrangedpageXandY{#1}000\arrangedpageE % 8
+ \or \handlearrangedpageXandY{#1}010\arrangedpageD % 9
+ \or \handlearrangedpageXandY{#1}000\arrangedpageC % 10
+ \or \handlearrangedpageXandY{#1}010\arrangedpageB % 11
+ \or \handlearrangedpageXandY{#1}000\arrangedpageA % 12
+ \poparrangedpages
+ \fi}
% % handy for stickers etc, this way we can treat them as page
%
@@ -861,8 +1220,8 @@
\def\dosetuppageshift[#1][#2][#3]% page|paper horizontal vertical
{\ifthirdargument % paper=arrange
- \edef\hpageshifts{\ifcsname\??pt\v!horizontal:#2\endcsname\csname\??pt\v!horizontal:#2\endcsname}%
- \edef\vpageshifts{\ifcsname\??pt\v!vertical :#3\endcsname\csname\??pt\v!vertical :#3\endcsname}%
+ \edef\hpageshifts{\ifcsname\??pt\v!horizontal:#2\endcsname\csname\??pt\v!horizontal:#2\endcsname\fi}%
+ \edef\vpageshifts{\ifcsname\??pt\v!vertical :#3\endcsname\csname\??pt\v!vertical :#3\endcsname\fi}%
\doifelse{#1}\v!page {\let\shiftprintpagebox\shiftpagebox}{\let\shiftprintpagebox\gobbleoneargument}%
\doifelse{#1}\v!paper{\let\shiftpaperpagebox\shiftpagebox}{\let\shiftpaperpagebox\gobbleoneargument}%
\else\ifsecondargument
diff --git a/tex/context/base/page-lay.mkiv b/tex/context/base/page-lay.mkiv
index 6cc8afc9c..a8150cc51 100644
--- a/tex/context/base/page-lay.mkiv
+++ b/tex/context/base/page-lay.mkiv
@@ -13,13 +13,6 @@
\writestatus{loading}{ConTeXt Page Macros / Layout Specification}
-%D This module is now etex dependent.
-
-% to be translated into english
-
-% hoofdhoogte wordt bij status=hoog niet aangepast op outer
-% level, wel binnen bepaalde berekeningen
-
%D Before you start wondering why some of the page related
%D modules skip upward or left in order to place elements, you
%D must realize that the reference point is the top left
@@ -323,7 +316,7 @@
{\doifelsenothing{#2}
{\expanded{\dodosetuppapersize
[\executeifdefined{\??pp:1:#1}{#1}]%
- [\executeifdefined{\??pp:2:#1}{}]}}
+ [\executeifdefined{\??pp:2:#1}{\v!default}]}}
{\doifassignmentelse{#2}
{\getparameters[\??pp\executeifdefined{\??pp:1:#1}{#1}][#2]}
{\expanded{\dodosetuppapersize
@@ -1231,6 +1224,24 @@
%D since they could change while going to a new page,
%D depending on the current font setting.
+\setuppaper % (size) % only used in XY imposition
+ [\c!width=\zeropoint,
+ \c!height=\zeropoint,
+ \c!topspace=\zeropoint,
+ \c!backspace=\zeropoint,
+ \c!dx=\zeropoint,
+ \c!dy=\zeropoint,
+ \c!nx=1,
+ \c!ny=1,
+ \c!method=\v!normal]
+
+\setuppapersize
+ [\c!option=\v!max,
+ \c!top=,
+ \c!bottom=\vss,
+ \c!left=,
+ \c!right=\hss]
+
\setuplayout
[ \c!topspace=.08417508418\paperheight, % 2.5cm
\c!top=\zeropoint,
@@ -1266,7 +1277,7 @@
\c!style=,
\c!color=,
\c!marking=\v!off,
- \c!location=, % \v!singlesided, but empty is signal
+ \c!location=\v!middle, % \v!singlesided, but unset is signal
\c!scale=1,
\c!sx=1,
\c!sy=1,
@@ -1287,27 +1298,6 @@
%D First we define a whole range of (DIN) papersizes,
%D of which the A-series makes most sense. We enable checking.
-%D We also set some of the parameters that will be used when
-%D positioning the typeset paper onto the print paper.
-
-\setuppaper % (size) % only used in XY imposition
- [\c!width=\zeropoint,
- \c!height=\zeropoint,
- \c!topspace=\zeropoint,
- \c!backspace=\zeropoint,
- \c!dx=\zeropoint,
- \c!dy=\zeropoint,
- \c!nx=1,
- \c!ny=1,
- \c!method=\v!normal]
-
-\setuppapersize
- [\c!option=\v!max,
- \c!top=,
- \c!bottom=\vss,
- \c!left=,
- \c!right=\hss]
-
\definepapersize [A0] [\c!width=841mm,\c!height=1189mm]
\definepapersize [A1] [\c!width=594mm,\c!height=841mm]
\definepapersize [A2] [\c!width=420mm,\c!height=594mm]
@@ -1436,6 +1426,11 @@
%D come after the first layout specification (already done).
\definepapersize
+ [\v!default]
+ [ \c!width=\paperwidth,
+ \c!height=\paperheight]
+
+\definepapersize
[samesized]
[ \c!width=\paperwidth,
\c!height=\paperheight]
diff --git a/tex/context/base/page-run.mkiv b/tex/context/base/page-run.mkiv
index 1c7595b03..0ea18dfbf 100644
--- a/tex/context/base/page-run.mkiv
+++ b/tex/context/base/page-run.mkiv
@@ -183,7 +183,9 @@ end
[#1]
\else
\showframe
- [\v!header,\v!text,\v!footer]
+ [\v!top,\v!header,
+ \v!text,
+ \v!footer,\v!bottom]
[\v!leftedge,\v!leftmargin,
\v!text,
\v!rightmargin,\v!rightedge]
diff --git a/tex/context/base/page-set.mkiv b/tex/context/base/page-set.mkiv
index 8b689b284..8c3566bc0 100644
--- a/tex/context/base/page-set.mkiv
+++ b/tex/context/base/page-set.mkiv
@@ -2412,7 +2412,7 @@
\def\dodefinecolumnsetspan[#1][#2]%
{%\ifsecondargument
- \defineframedtext
+ \defineframedtext % we can have a parent
[cs:#1]
[\c!frame=\v!off,
\c!before=,
@@ -2466,7 +2466,7 @@
\c!depthcorrection=\v!off,
#2]%
% determine widths
- \!!countc\framedtextparameter{cs:#1}\c!n
+ \!!countc\namedframedtextparameter{cs:#1}\c!n
% \!!countd\numexpr(\nofcolumns-\mofcolumns+\plusone)%
\!!countd\nofcolumns
% n <= n of columns
@@ -2474,7 +2474,7 @@
\advance\!!countd -\mofcolumns
\advance\!!countd \plusone
% n <= n of available columns (alternative a)
- \doif{\framedtextparameter{cs:#1}\c!alternative}\v!a
+ \doif{\namedframedtextparameter{cs:#1}\c!alternative}\v!a
{\ifnum\!!countc>\!!countd \!!countc\!!countd \fi}%
% here it all starts
\setcolumnsetspanhsize\mofcolumns\!!countc % a/b used
@@ -2483,7 +2483,7 @@
\dostartframedtext[cs:#1][\v!none]% geen nils placement
% spoils spacing : \vskip-\struttotal\par\verticalstrut\par
\ifnum\columnsetlevel>\zerocount
- \framedtextparameter{cs:#1}\c!before
+ \namedframedtextparameter{cs:#1}\c!before
\fi
\unexpanded\def\stopcolumnsetspan{\dostopcolumnsetspan{#1}}}
@@ -2493,8 +2493,8 @@
\kern-2\struttotal
\verticalstrut
\ifnum\columnsetlevel>\zerocount
- \doifsomething{\framedtextparameter{cs:#1}\c!after}
- {\framedtextparameter{cs:#1}\c!after
+ \doifsomething{\namedframedtextparameter{cs:#1}\c!after}
+ {\namedframedtextparameter{cs:#1}\c!after
\kern\zeropoint}% otherwise blanks disappear, better be a switch
\else
\endgraf
@@ -2503,8 +2503,7 @@
\egroup
\setbox\scratchbox\frozenhbox to \hsize
{\dontcomplain
- \alignedline{\framedtextparameter{cs:#1}\c!location}\v!middle
- {\lower\strutdepth\box\scratchbox}}%
+ \alignedline{\namedframedtextparameter{cs:#1}\c!location}\v!middle{\lower\strutdepth\box\scratchbox}}%
\dp\scratchbox\zeropoint % else wrong snap insidefloat
%
% to be tested first (strange in grid mode)
@@ -2512,7 +2511,7 @@
% \setbox\scratchbox\frozenhbox to \hsize
% {\dontcomplain
% \alignstrutmode\zerocount
-% \alignedline{\framedtextparameter{cs:#1}\c!plaats}\v!midden
+% \alignedline{\namedframedtextparameter{cs:#1}\c!plaats}\v!midden
% {\box\scratchbox}}%
%
\ifinsidefloat
@@ -2520,24 +2519,24 @@
\else\ifnum\columnsetlevel>\zerocount
% we only set \columnsetspacing when asked for, else bottom problems
% don't change this any more (test naw)
- \columnslotspacing\framedtextparameter{cs:#1}\c!nlines\relax
+ \columnslotspacing\namedframedtextparameter{cs:#1}\c!nlines\relax
% todo: nboven/onder
%\OTRSETstoreincolumnslotHERE\scratchbox
- \edef\floatmethod{\framedtextparameter{cs:#1}\c!default}%
+ \edef\floatmethod{\namedframedtextparameter{cs:#1}\c!default}%
\@EA\uppercasestring\floatmethod\to\floatmethod
% todo : \v!here -> here enzovoorts
\OTRSETstoreincolumnslot\floatmethod\scratchbox
% watch out: no \dochecknextindentation{tag}
- \checknextindentation[\framedtextparameter{cs:#1}\c!indentnext]%
+ \checknextindentation[\namedframedtextparameter{cs:#1}\c!indentnext]%
\else
% of course we needed a one-column fall back for tm; brrr, the box has now too
% much height (try \ruledvbox); don't change this without testing techniek
\scratchdimen\ht\scratchbox
\advance\scratchdimen-\strutdp
\ht\scratchbox\scratchdimen
- \framedtextparameter{cs:#1}\c!before
+ \namedframedtextparameter{cs:#1}\c!before
\snaptogrid\vbox{\box\scratchbox}%
- \framedtextparameter{cs:#1}\c!after
+ \namedframedtextparameter{cs:#1}\c!after
\fi\fi
\egroup
\endgraf}
diff --git a/tex/context/base/ppchtex.mkiv b/tex/context/base/ppchtex.mkiv
index e6c1f2495..1162c1fcf 100644
--- a/tex/context/base/ppchtex.mkiv
+++ b/tex/context/base/ppchtex.mkiv
@@ -285,22 +285,10 @@
% regels iets verder uit elkaar gezet. Jammer. Italic fonts
% hebben grotere cijfers en vallen min of meer uit de boot.
-\newif\ifloweredsubscripts
-
-% Due to some upward incompatibality of LaTeX to LaTeX2.09
-% and/or LaTeX2e we had to force \@@dochemicalstyle. Otherwise
-% some weird \nullfont error comes up.
-
-\def\beginlatexmathmodehack
- {\ifmmode
- \let\endlatexmathmodehack=\relax
- \else
- \def\endlatexmathmodehack{$}$\@@dochemicalstyle\empty
- \fi}
+\newif\ifloweredsubscripts % this will be redone in the mkiv ways
\def\setsubscripts
- {\beginlatexmathmodehack
- \def\dosetsubscript##1##2##3%
+ {\def\dosetsubscript##1##2##3%
{\dimen0=##3\fontexheight##2%
\setxvalue{@@\string##1\string##2}{\the##1##2\relax}%
##1##2=\dimen0\relax}%
@@ -311,12 +299,10 @@
%dodosetsubscript\mathsupnormal {?}%
\dodosetsubscript\mathsubnormal {.7}%
\dodosetsubscript\mathsubcombined{.7}%
- \global\loweredsubscriptstrue
- \endlatexmathmodehack}
+ \global\loweredsubscriptstrue}
\def\resetsubscripts
{\ifloweredsubscripts
- \beginlatexmathmodehack
\def\doresetsubscript##1##2%
{\dimen0=\getvalue{@@\string##1\string##2}\relax
##1##2=\dimen0}%
@@ -328,7 +314,6 @@
\dodoresetsubscript\mathsubnormal
\dodoresetsubscript\mathsubcombined
\global\loweredsubscriptsfalse
- \endlatexmathmodehack
\fi}
\ifx\Umathchar\undefined \else
@@ -392,11 +377,8 @@
\def\dowithchemical%
{}
-\doifdefinedelse{@@iastate}
- {\def\localgotochemical#1#2{\naarbox{#2}[#1]}%
- \def\localthisischemical#1{\pagereference[#1]}}
- {\def\localgotochemical#1{}%
- \def\localthisischemical#1{}}
+\def\localgotochemical#1#2{\gotobox{#2}[#1]}
+\def\localthisischemical#1{\pagereference[#1]}
% eind van experiment
diff --git a/tex/context/base/s-fnt-10.mkiv b/tex/context/base/s-fnt-10.mkiv
index a8ef90c5e..c76574d6d 100644
--- a/tex/context/base/s-fnt-10.mkiv
+++ b/tex/context/base/s-fnt-10.mkiv
@@ -14,31 +14,25 @@
\startluacode
local format, sprint = string.format, tex.sprint
-function fonts.otf.show_all()
- local tfmdata = fonts.identifiers[font.current()]
+local fontdata = fonts.hashes.identifiers
+
+function fonts.handlers.otf.show_all()
+ local tfmdata = fontdata[font.current()]
if tfmdata and tfmdata.shared then
local NC, NR, char = context.NC, context.NR, context.char
- local otfdata = tfmdata.shared.otfdata
- if otfdata and otfdata.luatex then
- local unicodes = otfdata.luatex.unicodes
- context.starttabulate { "|l|r|c|" }
- for i, name in ipairs(table.sortedkeys(unicodes)) do
- local unicode = unicodes[name]
- if unicode >= 0 then
- NC() context(name) NC() context(unicode) NC() char(unicode) NC() NR()
- end
- end
- context.stoptabulate()
+ context.starttabulate { "|l|r|c|" }
+ for unicode, description in fonts.iterators.characters(tfmdata) do
+ NC() context(description.name) NC() context(unicode) NC() char(unicode) NC() NR()
end
+ context.stoptabulate()
end
end
function fonts.show_all()
- local tfmdata = fonts.identifiers[font.current()]
+ local tfmdata = fontdata[font.current()]
if tfmdata then
local NC, NR, HL, char, bold, tttf = context.NC, context.NR, context.HL, context.char, context.bold, context.tttf
- local chars = tfmdata.characters
- local descs = tfmdata.descriptions or { }
+ local descriptions = tfmdata.descriptions or { }
local data = characters.data
-- context.setuptabulate { header = "repeat" }
context.starttabulatehead()
@@ -51,47 +45,44 @@ function fonts.show_all()
NC() NR()
context.stoptabulatehead()
context.starttabulate { "|l|c|l|p|p|p|" }
- for k, unicode in ipairs(table.sortedkeys(chars)) do
--- for unicode, _ in table.sortedpairs(chars) do
- if unicode >= 0 then
- local chr, des, dat = chars[unicode], descs[unicode], data[unicode]
- local index = chr.index or 0
- local cname = (dat and dat.contextname) or ""
- local aname = (dat and dat.adobename) or ""
- local gname = (des and des.name) or ""
- local mname = dat and dat.mathname
- if type(mname) ~= "string" then
- mname = ""
- end
- local mspec = dat and dat.mathspec
- if mspec then
- for m=1,#mspec do
- local n = mspec[m].name
- if n then
- if mname == "" then
- mname = n
- else
- mname = mname .. " " .. n
- end
+ for unicode, chr in fonts.iterators.characters(tfmdata) do
+ local des, dat = descriptions[unicode], data[unicode]
+ local index = chr.index or 0
+ local cname = (dat and dat.contextname) or ""
+ local aname = (dat and dat.adobename) or ""
+ local gname = (des and des.name) or ""
+ local mname = dat and dat.mathname
+ if type(mname) ~= "string" then
+ mname = ""
+ end
+ local mspec = dat and dat.mathspec
+ if mspec then
+ for m=1,#mspec do
+ local n = mspec[m].name
+ if n then
+ if mname == "" then
+ mname = n
+ else
+ mname = mname .. " " .. n
end
end
end
- if mname ~= "" then
- mname = "m: " .. mname
- if cname ~= "" then
- cname = cname .. " " .. mname
- else
- cname = mname
- end
+ end
+ if mname ~= "" then
+ mname = "m: " .. mname
+ if cname ~= "" then
+ cname = cname .. " " .. mname
+ else
+ cname = mname
end
- NC() tttf() context("U+%05X",unicode)
- NC() char(unicode)
- NC() tttf() context("%05X",index)
- NC() tttf() context(gname)
- NC() tttf() context(aname)
- NC() tttf() context(cname)
- NC() NR()
end
+ NC() tttf() context("U+%05X",unicode)
+ NC() char(unicode)
+ NC() tttf() context("%05X",index)
+ NC() tttf() context(gname)
+ NC() tttf() context(aname)
+ NC() tttf() context(cname)
+ NC() NR()
end
context.stoptabulate()
else
@@ -100,7 +91,7 @@ function fonts.show_all()
end
function fonts.show_glyphs()
- local tfmdata = fonts.identifiers[font.current()]
+ local tfmdata = fontdata[font.current()]
if tfmdata then
for k, v in ipairs(table.sortedkeys(tfmdata.characters)) do
if v >=0 then
@@ -148,11 +139,11 @@ end
\page
\egroup}
-\doifnotmode{demo} {\endinput}
+% \doifnotmode{demo} {\endinput}
\starttext
-% \ShowCompleteFont{name:dejavusansmono}{10pt}{1}
+\ShowCompleteFont{name:dejavusansmono}{10pt}{1}
% \ShowCompleteFont{name:dejavuserif}{10pt}{2}
% \ShowCompleteFont{name:officinasansbookitcregular}{10pt}{2}
% \ShowCompleteFont{name:officinaserifbookitcregular}{10pt}{2}
@@ -171,6 +162,6 @@ end
% \ShowCompleteFont{name:palatinosansinformalcombold}{20pt}{2}
% \ShowCompleteFont{name:palatinonovaregular}{11pt}{2}
-\ShowCompleteFont{pirat.ttf}{12pt}{1}
+% \ShowCompleteFont{pirat.ttf}{12pt}{1}
\stoptext
diff --git a/tex/context/base/s-fnt-23.mkiv b/tex/context/base/s-fnt-23.mkiv
index 35973d27e..8714d9b50 100644
--- a/tex/context/base/s-fnt-23.mkiv
+++ b/tex/context/base/s-fnt-23.mkiv
@@ -14,10 +14,15 @@
% last_data was written wrong so it needs checking
\startluacode
+ local fontdata = fonts.hashes.identifiers
+ local otfhandler = fonts.handlers.otf --- will be moduledata
+
local last_data = nil
+
local format = string.format
- function fonts.otf.show_shape(n)
- local tfmdata = fonts.identifiers[font.current()]
+
+ function otfhandler.show_shape(n)
+ local tfmdata = fontdata[font.current()]
last_data = tfmdata
local charnum = tonumber(n)
if not charnum then
@@ -25,8 +30,9 @@
end
local c = tfmdata.characters[charnum]
local d = tfmdata.descriptions[charnum]
+ local parameters = tfmdata.parameters
if d then
- local factor = (tfmdata.size/tfmdata.units)*((7200/7227)/65536)
+ local factor = (parameters.size/parameters.units)*((7200/7227)/65536)
local llx, lly, urx, ury = unpack(d.boundingbox)
llx, lly, urx, ury = llx*factor, lly*factor, urx*factor, ury*factor
local width, italic = (d.width or 0)*factor, (d.italic or 0)*factor
@@ -193,22 +199,21 @@
context("no such shape: %s",n)
end
end
- function fonts.otf.show_all_shapes(start,stop)
- local tfmdata = fonts.identifiers[font.current()]
+ function otfhandler.show_all_shapes(start,stop)
+ local tfmdata = fontdata[font.current()]
last_data = tfmdata
start, stop = start or "\\startTEXpage\\gobbleoneargument", stop or "\\stopTEXpage"
- local unicodes, indices, descriptions = tfmdata.unicodes, tfmdata.indices, tfmdata.descriptions
- for _, unicode in next, table.sortedkeys(descriptions) do
- local d = descriptions[unicode]
- local name = d.name
+ local unicodes, descriptions = tfmdata.unicodes, tfmdata.descriptions
+ for unicode, description in fonts.iterators.descriptions(tfmdata) do
+ local name = description.name
context("%s{%s}%%",start,unicode)
context("\\writestatus{glyph}{U+%04X -> %s}%%",unicode,name)
- fonts.otf.show_shape(unicode)
+ otfhandler.show_shape(unicode)
context(stop)
end
end
- function fonts.otf.show_shape_field(unicode,name)
- local tfmdata = last_data or fonts.identifiers[font.current()]
+ function otfhandler.show_shape_field(unicode,name)
+ local tfmdata = last_data or fontdata[font.current()]
local d = tfmdata.descriptions[unicode]
if d then
if name == "unicode" then
@@ -227,7 +232,7 @@
[state=start]
\def\GetGlyphField#1#2%
- {\ctxlua{fonts.otf.show_shape_field(#1,"#2")}}
+ {\ctxlua{fonts.handlers.otf.show_shape_field(#1,"#2")}}
\def\StartShowGlyphShape#1%
{\startTEXpage
@@ -243,14 +248,14 @@
{\begingroup
\definedfont[#1 at #2]%
\obeyMPboxdepth
- \ctxlua{fonts.otf.show_shape("#3")}%
+ \ctxlua{fonts.handlers.otf.show_shape("#3")}%
\endgroup}
\def\ShowAllGlyphShapes#1#2% name size
{\begingroup
\nonknuthmode
\definedfont[#1 at #2]%
- \ctxlua{fonts.otf.show_all_shapes("\\StartShowGlyphShape","\\StopShowGlyphShape")}%
+ \ctxlua{fonts.handlers.otf.show_all_shapes("\\StartShowGlyphShape","\\StopShowGlyphShape")}%
\endgroup}
\setupcolors
diff --git a/tex/context/base/s-fnt-25.mkiv b/tex/context/base/s-fnt-25.mkiv
index fc78ddfda..36d28bfeb 100644
--- a/tex/context/base/s-fnt-25.mkiv
+++ b/tex/context/base/s-fnt-25.mkiv
@@ -12,7 +12,7 @@
%C details.
\def\enableshowmathfontvirtual
- {\ctxlua{fonts.tfm.auto_cleanup=false}}
+ {\ctxlua{fonts.constructors.autocleanup=false}}
\def\showmathfontcharacters
{\dodoubleempty\doshowmathfontcharacters}
@@ -78,16 +78,19 @@
local concat = table.concat
local format, lower = string.format, string.lower
+local fontdata = fonts.hashes.identifiers
+
function document.showmathfont(id,slot)
local data = characters.data
- local tfmdata = fonts.identifiers[id]
+ local tfmdata = fontdata[id]
local characters = tfmdata.characters
local sorted = (slot and { slot }) or table.sortedkeys(characters)
- local virtual, names = tfmdata.type == "virtual", { }
+ local virtual, names = tfmdata.properties.type == "virtual", { }
if virtual then
for k, v in ipairs(tfmdata.fonts) do
- local name = fonts.identifiers[v.id].name
- names[k] = (name and file.basename(name)) or v.id
+ local id = v.properties.id
+ local name = fontdata[id].properties.name
+ names[k] = (name and file.basename(name)) or id
end
end
local round = math.round
diff --git a/tex/context/base/s-fnt-29.mkiv b/tex/context/base/s-fnt-29.mkiv
index 86f40e2f8..0b63635b2 100644
--- a/tex/context/base/s-fnt-29.mkiv
+++ b/tex/context/base/s-fnt-29.mkiv
@@ -13,11 +13,13 @@
\startluacode
+ local fontdata = fonts.hashes.identifiers
+
function fonts.tracers.shapes() -- todo: ranges
local NC, NR = context.NC, context.NR
local char = context.char
- local chrs = fonts.identifiers[font.current()].characters
- -- local desc = fonts.identifiers[font.current()].descriptions
+ local chrs = fontdata[font.current()].characters
+ -- local desc = fontdata[font.current()].descriptions
context.starttabulate { "|l|c|c|c|c|l|" }
context.FL()
NC() context("unicode")
diff --git a/tex/context/base/scrn-bar.mkiv b/tex/context/base/scrn-bar.mkiv
deleted file mode 100644
index 75261b42e..000000000
--- a/tex/context/base/scrn-bar.mkiv
+++ /dev/null
@@ -1,400 +0,0 @@
-%D \module
-%D [ file=scrn-bar, % was part of scrn-int
-%D version=1995.01.01,
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Progress Bars,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%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 Screen Macros / Progress Bars}
-
-\unprotect
-
-%D The code is a bit upgraded to \MKIV\ but the output is mostly the same.
-%D In retrospect this shoul dhave been a module.
-
-% todo: replace blackrule by stupid rules
-
-% \setupinteraction[state=start]
-% \setupsubpagenumber[state=start]
-%
-% \startsetups bars
-% \vbox
-% {\hsize 5cm
-% \hbox{\interactionbar[a]}\blank
-% \hbox{\interactionbar[b]}\blank
-% \hbox{\interactionbar[c]}\blank
-% \hbox{\interactionbar[d]}\blank
-% \hbox{\interactionbar[e]}\blank
-% \hbox{\interactionbar[f]}\blank
-% \hbox{\interactionbar[g]}\blank
-% }
-% \stopsetups
-%
-% \setupheadertexts[\setups{bars}]
-%
-% \starttext
-% \dorecurse{10}{test \page }
-% \stoptext
-
-\presetlocalframed[\??ib]
-
-%D First the usual definition code.
-
-\let\currentinteractionbar\empty
-
-\def\setinteractionbarparameter#1#2#3{\@EA\def\csname\??ib#1#2\endcsname{#3}}
-\def\letinteractionbarparameter #1#2{\@EA\let\csname\??ib#1#2\endcsname}
-
-\def\interactionbarparameter #1{\csname\dointeractionbarparameter{\??ib\currentinteractionbar}#1\endcsname}
-\def\namedinteractionbarparameter#1#2{\csname\dointeractionbarparameter{\??ib#1}#2\endcsname}
-\def\interactionbarparameterhash #1{\dointeractionbarparameterhash {\??ib\currentinteractionbar}#1}
-
-\def\dointeractionbarparameter #1#2{\ifcsname#1#2\endcsname#1#2\else\expandafter\dointeractionbarparentparameter \csname#1\s!parent\endcsname#2\fi}
-\def\dointeractionbarparameterhash#1#2{\ifcsname#1#2\endcsname #1\else\expandafter\dointeractionbarparentparameterhash\csname#1\s!parent\endcsname#2\fi}
-
-\def\dointeractionbarparentparameter #1#2{\ifx#1\relax\s!empty\else\dointeractionbarparameter #1#2\fi}
-\def\dointeractionbarparentparameterhash#1#2{\ifx#1\relax \else\dointeractionbarparameterhash#1#2\fi}
-
-\unexpanded\def\defineinteractionbar{\dodoubleargument\dodefineinteractionbar}
-\unexpanded\def\setupinteractionbar {\dodoubleempty \dosetupinteractionbar}
-\def\interactionbar {\dodoubleempty \dointeractionbar}
-
-\def\dosetupinteractionbar[#1][#2]%
- {\ifsecondargument
- \getparameters[\??ib#1][#2]%
- \else
- \getparameters[\??ib][#1]%
- \fi}
-
-\def\dodefineinteractionbar[#1][#2]%
- {\getparameters
- [\??ib#1]%
- [\s!parent=\??ib,%
-% \c!foregroundcolor=\interactionbarparameter\c!color,%
-% \c!foregroundstyle=\interactionbarparameter\c!style,%
- #2]}
-
-\def\dointeractionbar[#1][#2]%
- {\iflocation
- \begingroup
- \doifnot{#1}\v!reset % obsolete, no caching any more
- {\doifassignmentelse{#1}
- {\getparameters[\??ib][#1]%
- \edef\currentinteractionbar{\interactionbarparameter\c!alternative}}%
- {\edef\currentinteractionbar{#1}%
- \ifsecondargument\getparameters[\??ib#1][#2]\fi}%
- \doif{\interactionbarparameter\c!state}\v!start
- {\interactionbarparameter\c!command}}%
- \endgroup
- \fi}
-
-\newdimen\interactionbarwidth
-\newdimen\interactionbarheight
-\newdimen\interactionbardepth
-\newdimen\interactionbardistance
-
-%D Interaction buttons, in fact a row of tiny buttons, are
-%D typically only used for navigational purposed. The next
-%D macro builds such a row based on a specification list.
-%D
-%D \startbuffer
-%D \interactionbuttons[width=\hsize][page,PreviousJump,ExitViewer]
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D gives
-%D
-%D \getbuffer
-%D
-%D Apart from individual entries, one can use \type{page} and
-%D \type {subpage} as shortcuts to their four associated buttons.
-%D The symbols are derived from the symbols linked to the
-%D entries.
-
-\def\interactionbuttons
- {\dodoubleempty\dointeractionbuttons}
-
-\def\dointeractionbuttons[#1][#2]% er is een verdeel macro \horizontalfractions
- {\iflocation
- \begingroup
- % beware, is already set \let\currentinteractionbar\empty
- \doif{\interactionbarparameter\c!state}\v!stop\locationfalse
- \iflocation
- \ifsecondargument
- \let\menuparameter\interactionbarparameter
- \setupinteractionbar[#1]%
- \interactionbarwidth\interactionbarparameter\c!width
- \ifdim\interactionbarwidth=\zeropoint
- \interactionbarwidth1.5\emwidth
- \fi
- \doifnothing\@@ibheight{\letinteractionbarparameter\c!height\v!broad}%
- \doifnothing\@@ibdepth {\letinteractionbarparameter\c!depth\!!zeropoint}%%%
- \setbox2\hbox{\localframed[\??ib\currentinteractionbar][\c!background=]{\symbol[\@@iasymbolset][\v!previouspage]}}%
- \!!heighta\ht2 % needed because we default to nothing
- \setupinteractionbar[\c!strut=\v!no]%
- \setinteractionparameter\c!width\!!zeropoint
- \!!counta\zerocount % new, was 1
- \processallactionsinset
- [#2]
- [ \v!page=>\advance\!!counta 4,
- \v!subpage=>\advance\!!counta 4,
- \s!unknown=>\advance\!!counta 1]%
- \ifdim\interactionbarwidth=\zeropoint
- \!!widtha\dimexpr2\emwidth+\interactionbardistance\relax
- \!!widthb\dimexpr\!!counta\!!widtha-\interactionbardistance\relax
- \else
- \!!widtha\interactionbarwidth
- \!!widthb\dimexpr\!!counta\interactionbardistance-\interactionbardistance\relax
- \advance\!!widtha -\!!widthb
- \divide\!!widtha \!!counta
- \!!widthb\interactionbarwidth
- \fi
- \hbox to \!!widthb
- {\setnostrut
- \processallactionsinset
- [#2]
- [ \v!page=>\interactionbargotox\v!firstpage \interactionbargotox\v!nextpage \interactionbargotox\v!previouspage \interactionbargotox\v!lastpage,
- \v!subpage=>\interactionbargotox\v!firstsubpage\interactionbargotox\v!nextsubpage\interactionbargotox\v!previoussubpage\interactionbargotox\v!lastsubpage,
- \s!unknown=>\interactionbargotox\commalistelement]%
- \unskip}%
- \else
- \interactionbuttons[][#1]%
- \fi
- \fi
- \endgroup
- \fi}
-
-\def\interactionbargotox#1%
- {\normalexpanded{\noexpand\dodocomplexbutton
-% {\??ib\currentinteractionbar}%
- {\??ib}%
- [\c!height=\the\!!heighta,\c!width=\the\!!widtha]%
- {\noexpand\symbol[\@@iasymbolset][#1]}%
- [#1]}%
- \hss}
-
-\def\interactionbara
- {\iflocation
- \interactionbarwidth \interactionbarparameter\c!width
- \interactionbardistance\interactionbarparameter\c!distance
- \interactionbarheight \interactionbarparameter\c!height
- \interactionbardepth \interactionbarparameter\c!depth
- \noindent\hbox to \interactionbarwidth \bgroup
- \dontcomplain
- \setupblackrules[\c!height=\v!max,\c!depth=\v!max]%
- \!!widthb\dimexpr\interactionbarwidth-4\emwidth\relax
- \processaction
- [\interactionbarparameter\c!step]
- [ \v!small=>\scratchcounter 20,
- \v!medium=>\scratchcounter 10,
- \v!big=>\scratchcounter 5,
- \s!unknown=>\scratchcounter 10]%
- \!!widtha\dimexpr\!!widthb/\scratchcounter\relax
- \setupblackrules[\c!width=\!!widtha]%
- \setbox\scratchbox\hbox to \interactionbarwidth
- {\hskip2\emwidth
- \setbox\scratchbox\hbox{\blackrule[\c!color=\interactionbarparameter\c!backgroundcolor]}%
- \dorecurse\scratchcounter
- {\hss\normalexpanded{\directgotodumbbox{\copy\scratchbox}[page(\the\numexpr\recurselevel*\lastpage/\scratchcounter\relax)]}}%
- \hss
- \hskip2\emwidth}%
- \wd\scratchbox\zeropoint
- \box \scratchbox
- \setupblackrules[\c!width=\emwidth]%
- \normalexpanded{\directgotospecbox\noexpand\interactionbarparameter{\blackrule}[\v!firstpage]}%
- \hskip\emwidth
- \ifnum\realpageno>\plusone
- \hskip\zeropoint\!!plus\numexpr\realpageno-\plustwo\relax \s!sp\relax % cm gives overflow
- \normalexpanded{\directgotospecbox\noexpand\interactionbarparameter{\blackrule}[\v!previouspage)]}%
- \fi
- \normalexpanded{\directgotospecbox\noexpand\interactionbarparameter{\blackrule}[page(\number\realpageno)]}% todo: \v!currentpage
- \ifnum\realpageno<\lastpage\relax
- \normalexpanded{\directgotospecbox\noexpand\interactionbarparameter{\blackrule}[\v!nextpage]}%
- \hskip\zeropoint\!!plus\numexpr\lastpage-\realpageno-\plusone\relax \s!sp\relax % cm gives overflow
- \fi
- \hskip\emwidth
- \normalexpanded{\directgotospecbox\noexpand\interactionbarparameter{\blackrule}[\v!lastpage]}%
- \egroup
- \fi}
-
-\def\interactionbarb
- {\ifnum\lastpage>\firstpage\relax
- \interactionbuttons[\v!firstpage,\v!previouspage,\v!nextpage,\v!lastpage]%
- \fi}
-
-\def\interactionbarc
- {\iflocation \ifnum\lastpage>\plusone
- \interactionbarwidth\interactionbarparameter\c!width
- \hbox to \interactionbarwidth
- {\setupblackrules[\c!height=\interactionbarparameter\c!height,\c!depth=\interactionbarparameter\c!depth,\c!width=\emwidth]%
- \scratchdimen\dimexpr(\interactionbarwidth-4\emwidth)/\numexpr\lastpage+\minusone\relax\relax
- \!!widtha\numexpr\realpageno+\minusone\relax\scratchdimen
- \!!widthb\numexpr\lastpage-\realpageno\relax\scratchdimen
- \directgotospecbox\interactionbarparameter{\blackrule}[\v!firstpage]%
- \hss
- \directgotospecbox\interactionbarparameter{\blackrule[\c!width=\!!widtha]}[\v!previouspage]%
- \blackrule[\c!color=\interactionbarparameter\c!contrastcolor]%
- \directgotospecbox\interactionbarparameter{\blackrule[\c!width=\!!widthb]}[\v!nextpage]%
- \hss
- \directgotospecbox\interactionbarparameter{\blackrule}[\v!lastpage]}%
- \fi \fi}
-
-\unexpanded\def\@@commoninteractionbargotoa#1%
- {\symbol[\ifcase#1\v!previous\or\v!somewhere\or\v!next\fi]}
-
-\unexpanded\def\@@commoninteractionbargotob#1%
- {\vrule\!!height\interactionbarheight\!!depth\interactionbardepth\!!width\!!widtha\relax}
-
-\unexpanded\def\@@commoninteractionbargotoc#1%
- {\symbol[\ifcase#1\v!previous\or\v!somewhere\or\v!somewhere\or\v!somewhere\or\v!next\fi}
-
-\unexpanded\def\@@commoninteractionbargotod#1%
- {\vrule \!!width\!!widtha \ifcase#1%
- \!!height \interactionbarheight \!!depth \interactionbardepth \or
- \!!height.5\interactionbarheight \!!depth.5\interactionbardepth \or
- \!!height \interactionbarheight \!!depth \interactionbardepth \or
- \!!height.5\interactionbarheight \!!depth.5\interactionbardepth \else
- \!!height \interactionbarheight \!!depth \interactionbardepth \fi}
-
-\newconstant\interactionbarwhatmode
-
-\unexpanded\def\@@commoninteractionbarx#1%
- {\doifelse{\interactionbarparameter\c!symbol}\v!yes
- {\setupsymbolset[\@@iasymbolset]%
- \let\dogotox\@@commoninteractionbargotoa}
- {\let\dogotox\@@commoninteractionbargotob}%
- \dorecurse\nofsubpages
- {\scratchcounter\numexpr\recurselevel+\firstsubpage+\minusone\relax
- \interactionbarwhatmode
- \ifnum\scratchcounter<\realpageno \zerocount \else
- \ifnum\scratchcounter=\realpageno \plusone \else
- \plustwo \fi\fi
- \normalexpanded{\directgotospecbox\noexpand\interactionbarparameter{\dogotox\interactionbarwhatmode}[page(\the\scratchcounter)]}%
- #1}%
- \unskip}
-
-\def\interactionbard
- {\iflocation \ifnum\nofsubpages>\plusone \doif{\structurecounterparameter\s!subpage\c!state}\v!start{%
- \interactionbarwidth \interactionbarparameter\c!width
- \interactionbardistance\interactionbarparameter\c!distance
- \interactionbarheight \interactionbarparameter\c!height
- \interactionbardepth \interactionbarparameter\c!depth
- \!!widtha\interactionbarwidth
- \noindent\hbox{\@@commoninteractionbarx{\hskip\interactionbardistance}}%
- }\fi \fi}
-
-\def\interactionbare
- {\iflocation \ifnum\nofsubpages>\plusone \doif{\structurecounterparameter\s!subpage\c!state}\v!start{%
- \begingroup
- \interactionbarwidth \interactionbarparameter\c!width
- \interactionbardistance\interactionbarparameter\c!distance
- \interactionbarheight \interactionbarparameter\c!height
- \interactionbardepth \interactionbarparameter\c!depth
- \!!widthb\dimexpr\nofsubpages\interactionbardistance-\interactionbardistance\relax % (n-1)
- \!!widtha\dimexpr(\interactionbarwidth-\!!widthb)/\nofsubpages\relax
- \ifdim\!!widtha<\interactionbardistance
- \interactionbarf
- \else
- \noindent\hbox to \interactionbarwidth{\@@commoninteractionbarx{\hss}\unskip}%
- \fi
- \endgroup
- }\fi\fi}
-
-\def\interactionbarf
- {\iflocation \ifnum\nofsubpages>\plusone \doif{\structurecounterparameter\s!subpage\c!state}\v!start{%
- \interactionbarwidth \interactionbarparameter\c!width
- \interactionbardistance\interactionbarparameter\c!distance
- \interactionbarheight \interactionbarparameter\c!height
- \interactionbardepth \interactionbarparameter\c!depth
- \noindent \hbox to \interactionbarwidth \bgroup
- \doloop
- {\!!countc\numexpr(\nofsubpages/\recurselevel)+\plusone\relax % rounding
- \!!widthb\interactionbardistance
- \multiply\!!widthb \!!countc
- \advance\!!widthb -\interactionbardistance
- \!!widtha\interactionbarwidth
- \advance\!!widtha -\!!widthb
- \divide\!!widtha \!!countc
- \ifdim\!!widtha<\interactionbardistance\else
- \!!countb\recurselevel
- \exitloop
- \fi}%
- \ifnum\!!countc>\plusone
- % this is not that well tested
- \advance\!!countc \minustwo
- \!!widtha-\interactionbardistance
- \!!widtha\!!countc\!!widtha
- \advance\!!widtha \interactionbarwidth
- \advance\!!countc \plusone
- \divide\!!widtha \!!countc
- \fi
- \doifelse{\interactionbarparameter\c!symbol}\v!yes
- {\setupsymbolset[\@@iasymbolset]%
- \let\dogotox\@@commoninteractionbargotoc}%
- {\let\dogotox\@@commoninteractionbargotod}%
- \!!countc\numexpr\realpageno-\plustwo\relax
- \!!countd\numexpr\realpageno+\plustwo\relax
- \ifnum\!!countc<\plusone \!!countc\plusone \fi
- \!!countf\zerocount
- \dostepwiserecurse\firstsubpage\lastsubpage\plusone
- {\!!doneafalse
- \advance\!!countf \plusone
- \ifnum\recurselevel=\firstsubpage\relax \!!doneatrue \fi
- \ifnum\recurselevel=\lastsubpage \relax \!!doneatrue \fi
- \interactionbarwhatmode \if!!donea
- \ifnum\recurselevel<\realpageno \zerocount \else
- \ifnum\recurselevel>\realpageno \plustwo \else
- \plusfour \fi\fi
- \else \ifnum\!!countf=\!!countb
- \ifnum\recurselevel<\realpageno \plusone \else
- \ifnum\recurselevel>\realpageno \plusthree \else
- \plustwo \fi\fi
- \fi \fi
- \normalexpanded{\directgotospecbox\noexpand\interactionbarparameter{\dogotox\interactionbarwhatmode}[page(\recurselevel)]}%
- \hss
- \!!countf\zerocount}%
- \unskip
- \egroup
- }\fi\fi}
-
-\def\interactionbarg
- {\iflocation \ifnum\lastsubpage>\firstsubpage\relax % no test for state?
- \interactionbuttons[\v!firstsubpage,\v!previoussubpage,\v!nextsubpage,\v!lastsubpage]%
- \fi \fi}
-
-\setupinteractionbar
- [\c!state=\v!start,
- \c!alternative=a,
- \c!symbol=\v!no,
- \c!width=10\emwidth,
- \c!height=.5\emwidth,
- \c!depth=\zeropoint,
- \c!distance=.5\emwidth,
- \c!step=\v!medium,
- \c!foregroundcolor=\interactionbarparameter\c!color,
- \c!foregroundstyle=\interactionbarparameter\c!style,
- \c!color=\@@iacolor,
- \c!contrastcolor=\@@iacontrastcolor,
- \c!style=,
- \c!frame=\v!on,
- \c!background=color,
- \c!backgroundcolor=gray,
- \c!samepage=\v!yes,
- \c!unknownreference=\v!yes]
-
-\defineinteractionbar[a][\c!command=\interactionbara]
-\defineinteractionbar[b][\c!command=\interactionbarb,\c!height=\v!broad]
-\defineinteractionbar[c][\c!command=\interactionbarc,\c!height=\v!max,\c!depth=\v!max]
-\defineinteractionbar[d][\c!command=\interactionbard,\c!width=.5\emwidth]
-\defineinteractionbar[e][\c!command=\interactionbare]
-\defineinteractionbar[f][\c!command=\interactionbarf]
-\defineinteractionbar[g][\c!command=\interactionbarg,\c!height=\v!broad]
-
-\protect \endinput
diff --git a/tex/context/base/scrn-bar.mkvi b/tex/context/base/scrn-bar.mkvi
new file mode 100644
index 000000000..4605f1d2e
--- /dev/null
+++ b/tex/context/base/scrn-bar.mkvi
@@ -0,0 +1,405 @@
+%D \module
+%D [ file=scrn-bar, % was part of scrn-int
+%D version=1995.01.01,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Progress Bars,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%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 Screen Macros / Progress Bars}
+
+\unprotect
+
+%D The code is a bit upgraded to \MKIV\ but the output is mostly the
+%D same. In retrospect this should have been a module. We can move
+%D some definitions to scrn-run-bar.mkiv if needed. We can also make
+%D the code a bit more efficient.
+
+% todo: replace blackrule by stupid rules
+
+%D \starttyping
+%D \setupinteraction
+%D [state=start]
+%D
+%D \setupsubpagenumber
+%D [state=start]
+%D
+%D \setuplayout
+%D [middle]
+%D
+%D \setuppapersize
+%D [S4][S4]
+%D
+%D \startsetups bars
+%D \ruledvbox to \textheight \bgroup
+%D a \ruledhbox{\interactionbar[a]}\vss
+%D b \ruledhbox{\interactionbar[b]}\vss
+%D c \ruledhbox{\interactionbar[c]}\vss
+%D d \ruledhbox{\interactionbar[d]}\vss
+%D e \ruledhbox{\interactionbar[e]}\vss
+%D f \ruledhbox{\interactionbar[f]}\vss
+%D g \ruledhbox{\interactionbar[g]}\vss
+%D \egroup
+%D \stopsetups
+%D
+%D \setuptexttexts[\setups{bars}]
+%D
+%D \starttext
+%D \dorecurse {12} {
+%D \startstandardmakeup
+%D \stopstandardmakeup
+%D }
+%D \stoptext
+%D \stoptyping
+
+\installcommandhandler \??ib {interactionbar} \??ib
+
+\presetlocalframed[\??ib]
+
+\unexpanded\def\interactionbar
+ {\dodoubleempty\scrn_bar_direct}
+
+\def\scrn_bar_direct[#tag][#settings]% somewhat messy
+ {\iflocation
+ \begingroup
+ \doifassignmentelse{#tag}
+ {\getparameters[\??ib][#tag]%
+ \edef\currentinteractionbar{\interactionbarparameter\c!alternative}}%
+ {\edef\currentinteractionbar{#tag}%
+ \ifsecondargument\getparameters[\??ib#tag][#settings]\fi}%
+ \doif{\interactionbarparameter\c!state}\v!start
+ {\interactionbarparameter\c!command}%
+ \endgroup
+ \fi}
+
+\newdimen\scrn_bar_width
+\newdimen\scrn_bar_height
+\newdimen\scrn_bar_depth
+\newdimen\scrn_bar_distance
+
+%D Interaction buttons, in fact a row of tiny buttons, are
+%D typically only used for navigational purposed. The next
+%D macro builds such a row based on a specification list.
+%D
+%D \startbuffer
+%D \interactionbuttons[width=\hsize][page,PreviousJump,ExitViewer]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D gives
+%D
+%D \getbuffer
+%D
+%D Apart from individual entries, one can use \type{page} and
+%D \type {subpage} as shortcuts to their four associated buttons.
+%D The symbols are derived from the symbols linked to the
+%D entries.
+
+\unexpanded\def\interactionbuttons
+ {\dodoubleempty\scrn_bar_buttons}
+
+\def\scrn_bar_buttons
+ {\iflocation
+ \expandafter\scrn_bar_buttons_status
+ \else
+ \expandafter\scrn_bar_buttons_ignore
+ \fi}
+
+\def\scrn_bar_buttons_status[#settings][#list]%
+ {\doif{\interactionbarparameter\c!state}\v!start
+ {\ifsecondargument
+ \scrn_bar_buttons_indeed[#settings][#list]%
+ \else
+ \scrn_bar_buttons_indeed[][#settings]%
+ \fi}}
+
+\def\scrn_bar_buttons_ignore[#settings][#list]% \gobbletwooptionals
+ {}
+
+\def\scrn_bar_buttons_indeed[#settings][#list]%
+ {\begingroup
+ %\let\menuparameter\interactionbarparameter
+ \setupinteractionbar[#settings]%
+ \scrn_bar_width\interactionbarparameter\c!width
+ \ifdim\scrn_bar_width=\zeropoint
+ \scrn_bar_width1.5\emwidth
+ \fi
+ \doifnothing{\interactionbarparameter\c!height}{\letinteractionbarparameter\c!height\v!broad}%
+ \doifnothing{\interactionbarparameter\c!depth }{\letinteractionbarparameter\c!depth\!!zeropoint}%%%
+ \setbox2\hbox{\localframed[\??ib\currentinteractionbar][\c!background=]{\symbol[\interactionparameter\c!symbolset][\v!previouspage]}}%
+ \!!heighta\ht2 % needed because we default to nothing
+ \setupinteractionbar[\c!strut=\v!no]%
+ \letinteractionparameter\c!width\zeropoint
+ \!!counta\zerocount % new, was 1
+ \processallactionsinset
+ [#list]
+ [ \v!page=>\advance\!!counta 4,
+ \v!subpage=>\advance\!!counta 4,
+ \s!unknown=>\advance\!!counta 1]%
+ \ifdim\scrn_bar_width=\zeropoint
+ \!!widtha\dimexpr2\emwidth+\scrn_bar_distance\relax
+ \!!widthb\dimexpr\!!counta\!!widtha-\scrn_bar_distance\relax
+ \else
+ \!!widtha\scrn_bar_width
+ \!!widthb\dimexpr\!!counta\scrn_bar_distance-\scrn_bar_distance\relax
+ \advance\!!widtha -\!!widthb
+ \divide\!!widtha \!!counta
+ \!!widthb\scrn_bar_width
+ \fi
+ \hbox to \!!widthb
+ {\setnostrut
+ \startsymbolset[\interactionparameter\c!symbolset]%
+ \processallactionsinset
+ [#list]
+ [ \v!page=>\scrn_bar_goto\v!firstpage
+ \scrn_bar_goto\v!nextpage
+ \scrn_bar_goto\v!previouspage
+ \scrn_bar_goto\v!lastpage,
+ \v!subpage=>\scrn_bar_goto\v!firstsubpage
+ \scrn_bar_goto\v!nextsubpage
+ \scrn_bar_goto\v!previoussubpage
+ \scrn_bar_goto\v!lastsubpage,
+ \s!unknown=>\scrn_bar_goto\commalistelement]%
+ \unskip
+ \stopsymbolset}%
+ \endgroup}
+
+\def\scrn_bar_goto#action%
+ {\button
+ [\c!height=\the\!!heighta,\c!width=\the\!!widtha]%
+ {\symbol[#action]}% we could expand this one once only
+ [#action]%
+ \hss}
+
+\def\scrn_bar_alternative_a
+ {\scrn_bar_width \interactionbarparameter\c!width
+ \scrn_bar_distance\interactionbarparameter\c!distance
+ \scrn_bar_height \interactionbarparameter\c!height
+ \scrn_bar_depth \interactionbarparameter\c!depth
+ \noindent\hbox to \scrn_bar_width \bgroup
+ \dontcomplain
+ \setupblackrules[\c!height=\v!max,\c!depth=\v!max]%
+ \!!widthb\dimexpr\scrn_bar_width-4\emwidth\relax
+ \processaction
+ [\interactionbarparameter\c!step]
+ [ \v!small=>\scratchcounter 20,
+ \v!medium=>\scratchcounter 10,
+ \v!big=>\scratchcounter 5,
+ \s!unknown=>\scratchcounter 10]%
+ \!!widtha\dimexpr\!!widthb/\scratchcounter\relax
+ \setupblackrules[\c!width=\!!widtha]%
+ \setbox\scratchbox\hbox to \scrn_bar_width
+ {\hskip2\emwidth
+ \setbox\scratchbox\hbox{\blackrule[\c!color=\interactionbarparameter\c!backgroundcolor]}%
+ \dorecurse\scratchcounter
+ {\hss\normalexpanded{\directgotodumbbox{\copy\scratchbox}[page(\the\numexpr\recurselevel*\lastpage/\scratchcounter\relax)]}}%
+ \hss
+ \hskip2\emwidth}%
+ \wd\scratchbox\zeropoint
+ \box \scratchbox
+ \setupblackrules[\c!width=\emwidth]%
+ \normalexpanded{\directgotospecbox\noexpand\interactionbarparameter{\blackrule}[\v!firstpage]}%
+ \hskip\emwidth
+ \ifnum\realpageno>\plusone
+ \hskip\zeropoint\!!plus\numexpr\realpageno-\plustwo\relax \s!sp\relax % cm gives overflow
+ \normalexpanded{\directgotospecbox\noexpand\interactionbarparameter{\blackrule}[\v!previouspage)]}%
+ \fi
+ \normalexpanded{\directgotospecbox\noexpand\interactionbarparameter{\blackrule}[page(\number\realpageno)]}% todo: \v!currentpage
+ \ifnum\realpageno<\lastpage\relax
+ \normalexpanded{\directgotospecbox\noexpand\interactionbarparameter{\blackrule}[\v!nextpage]}%
+ \hskip\zeropoint\!!plus\numexpr\lastpage-\realpageno-\plusone\relax \s!sp\relax % cm gives overflow
+ \fi
+ \hskip\emwidth
+ \normalexpanded{\directgotospecbox\noexpand\interactionbarparameter{\blackrule}[\v!lastpage]}%
+ \egroup}
+
+\def\scrn_bar_alternative_b
+ {\ifnum\lastpage>\firstpage\relax
+ \interactionbuttons[\v!firstpage,\v!previouspage,\v!nextpage,\v!lastpage]%
+ \fi}
+
+\def\scrn_bar_alternative_c
+ {\ifnum\lastpage>\plusone
+ \scrn_bar_width\interactionbarparameter\c!width
+ \hbox to \scrn_bar_width
+ {\setupblackrules[\c!height=\interactionbarparameter\c!height,\c!depth=\interactionbarparameter\c!depth,\c!width=\emwidth]%
+ \scratchdimen\dimexpr(\scrn_bar_width-4\emwidth)/\numexpr\lastpage+\minusone\relax\relax
+ \!!widtha\numexpr\realpageno+\minusone\relax\scratchdimen
+ \!!widthb\numexpr\lastpage-\realpageno\relax\scratchdimen
+ \directgotospecbox\interactionbarparameter{\blackrule}[\v!firstpage]%
+ \hss
+ \directgotospecbox\interactionbarparameter{\blackrule[\c!width=\!!widtha]}[\v!previouspage]%
+ \blackrule[\c!color=\interactionbarparameter\c!contrastcolor]%
+ \directgotospecbox\interactionbarparameter{\blackrule[\c!width=\!!widthb]}[\v!nextpage]%
+ \hss
+ \directgotospecbox\interactionbarparameter{\blackrule}[\v!lastpage]}%
+ \fi}
+
+\unexpanded\def\scrn_bar_goto_a#whereto%
+ {\symbol[\ifcase#whereto\v!previous\or\v!somewhere\or\v!next\fi]}
+
+\unexpanded\def\scrn_bar_goto_b#whereto%
+ {\vrule\!!height\scrn_bar_height\!!depth\scrn_bar_depth\!!width\!!widtha\relax}
+
+\unexpanded\def\scrn_bar_goto_c#whereto%
+ {\symbol[\ifcase#whereto\v!previous\or\v!somewhere\or\v!somewhere\or\v!somewhere\or\v!next\fi}
+
+\unexpanded\def\scrn_bar_goto_d#whereto%
+ {\vrule \!!width\!!widtha \ifcase#whereto%
+ \!!height \scrn_bar_height \!!depth \scrn_bar_depth \or
+ \!!height.5\scrn_bar_height \!!depth.5\scrn_bar_depth \or
+ \!!height \scrn_bar_height \!!depth \scrn_bar_depth \or
+ \!!height.5\scrn_bar_height \!!depth.5\scrn_bar_depth \else
+ \!!height \scrn_bar_height \!!depth \scrn_bar_depth \fi}
+
+\newconstant\scrn_bar_mode
+
+\unexpanded\def\scrn_bar_goto_x#command%
+ {\doifelse{\interactionbarparameter\c!symbol}\v!yes
+ {\setupsymbolset[\interactionparameter\c!symbolset]%
+ \let\scrn_bar_goto_indeed\scrn_bar_goto_a}
+ {\let\scrn_bar_goto_indeed\scrn_bar_goto_b}%
+ \dorecurse\nofsubpages
+ {\scratchcounter\numexpr\recurselevel+\firstsubpage+\minusone\relax
+ \scrn_bar_mode
+ \ifnum\scratchcounter<\realpageno \zerocount \else
+ \ifnum\scratchcounter=\realpageno \plusone \else
+ \plustwo \fi\fi
+ \normalexpanded{\directgotospecbox\noexpand\interactionbarparameter{\scrn_bar_goto_indeed\scrn_bar_mode}[page(\the\scratchcounter)]}%
+ #command}%
+ \unskip}
+
+\def\scrn_bar_alternative_d
+ {\ifnum\nofsubpages>\plusone \doif{\structurecounterparameter\s!subpage\c!state}\v!start{%
+ \scrn_bar_width \interactionbarparameter\c!width
+ \scrn_bar_distance\interactionbarparameter\c!distance
+ \scrn_bar_height \interactionbarparameter\c!height
+ \scrn_bar_depth \interactionbarparameter\c!depth
+ \!!widtha\scrn_bar_width
+ \noindent\hbox{\scrn_bar_goto_x{\hskip\scrn_bar_distance}}%
+ }\fi}
+
+\def\scrn_bar_alternative_e
+ {\ifnum\nofsubpages>\plusone \doif{\structurecounterparameter\s!subpage\c!state}\v!start{%
+ \scrn_bar_width \interactionbarparameter\c!width
+ \scrn_bar_distance\interactionbarparameter\c!distance
+ \scrn_bar_height \interactionbarparameter\c!height
+ \scrn_bar_depth \interactionbarparameter\c!depth
+ \!!widthb\dimexpr\nofsubpages\scrn_bar_distance-\scrn_bar_distance\relax % (n-1)
+ \!!widtha\dimexpr(\scrn_bar_width-\!!widthb)/\nofsubpages\relax
+ \ifdim\!!widtha<\scrn_bar_distance
+ \scrn_bar_alternative_f
+ \else
+ \noindent\hbox to \scrn_bar_width{\scrn_bar_goto_x{\hss}\unskip}%
+ \fi
+ }\fi}
+
+\def\scrn_bar_alternative_f
+ {\ifnum\nofsubpages>\plusone \doif{\structurecounterparameter\s!subpage\c!state}\v!start{%
+ \scrn_bar_width \interactionbarparameter\c!width
+ \scrn_bar_distance\interactionbarparameter\c!distance
+ \scrn_bar_height \interactionbarparameter\c!height
+ \scrn_bar_depth \interactionbarparameter\c!depth
+ \noindent \hbox to \scrn_bar_width \bgroup
+ \doloop
+ {\!!countc\numexpr(\nofsubpages/\recurselevel)+\plusone\relax % rounding
+ \!!widthb\scrn_bar_distance
+ \multiply\!!widthb \!!countc
+ \advance\!!widthb -\scrn_bar_distance
+ \!!widtha\scrn_bar_width
+ \advance\!!widtha -\!!widthb
+ \divide\!!widtha \!!countc
+ \ifdim\!!widtha<\scrn_bar_distance\else
+ \!!countb\recurselevel
+ \exitloop
+ \fi}%
+ \ifnum\!!countc>\plusone
+ % this is not that well tested
+ \advance\!!countc \minustwo
+ \!!widtha-\scrn_bar_distance
+ \!!widtha\!!countc\!!widtha
+ \advance\!!widtha \scrn_bar_width
+ \advance\!!countc \plusone
+ \divide\!!widtha \!!countc
+ \fi
+ \doifelse{\interactionbarparameter\c!symbol}\v!yes
+ {\setupsymbolset[\interactionparameter\c!symbolset]%
+ \let\scrn_bar_goto_indeed\scrn_bar_goto_c}%
+ {\let\scrn_bar_goto_indeed\scrn_bar_goto_d}%
+ \!!countc\numexpr\realpageno-\plustwo\relax
+ \!!countd\numexpr\realpageno+\plustwo\relax
+ \ifnum\!!countc<\plusone \!!countc\plusone \fi
+ \!!countf\zerocount
+ \dostepwiserecurse\firstsubpage\lastsubpage\plusone
+ {\!!doneafalse
+ \advance\!!countf \plusone
+ \ifnum\recurselevel=\firstsubpage\relax \!!doneatrue \fi
+ \ifnum\recurselevel=\lastsubpage \relax \!!doneatrue \fi
+ \scrn_bar_mode
+ \if!!donea
+ \ifnum\recurselevel<\realpageno
+ \zerocount
+ \else\ifnum\recurselevel>\realpageno
+ \plustwo
+ \else
+ \plusfour
+ \fi\fi
+ \else
+ \ifnum\!!countf=\!!countb
+ \ifnum\recurselevel<\realpageno
+ \plusone
+ \else\ifnum\recurselevel>\realpageno
+ \plusthree
+ \else
+ \plustwo
+ \fi\fi
+ \else
+ \plusthree
+ \fi
+ \fi
+ \normalexpanded{\directgotospecbox\noexpand\interactionbarparameter{\scrn_bar_goto_indeed\scrn_bar_mode}[page(\recurselevel)]}%
+ \hss
+ \!!countf\zerocount}%
+ \unskip
+ \egroup
+ }\fi}
+
+\def\scrn_bar_alternative_g
+ {\ifnum\lastsubpage>\firstsubpage\relax % no test for state?
+ \interactionbuttons[\v!firstsubpage,\v!previoussubpage,\v!nextsubpage,\v!lastsubpage]%
+ \fi}
+
+\setupinteractionbar
+ [\c!state=\v!start,
+ \c!alternative=a,
+ \c!symbol=\v!no,
+ \c!width=10\emwidth,
+ \c!height=.5\emwidth,
+ \c!depth=\zeropoint,
+ \c!distance=.5\emwidth,
+ \c!step=\v!medium,
+ \c!foregroundcolor=\interactionbarparameter\c!color,
+ \c!foregroundstyle=\interactionbarparameter\c!style,
+ \c!color=\interactionparameter\c!color,
+ \c!contrastcolor=\interactionparameter\c!contrastcolor,
+ \c!style=,
+ \c!frame=\v!on,
+ \c!background=color,
+ \c!backgroundcolor=gray,
+ \c!samepage=\v!yes]
+
+\defineinteractionbar[a][\c!command=\scrn_bar_alternative_a]
+\defineinteractionbar[b][\c!command=\scrn_bar_alternative_b,\c!height=\v!broad]
+\defineinteractionbar[c][\c!command=\scrn_bar_alternative_c,\c!height=\v!max,\c!depth=\v!max]
+\defineinteractionbar[d][\c!command=\scrn_bar_alternative_d,\c!width=.5\emwidth]
+\defineinteractionbar[e][\c!command=\scrn_bar_alternative_e]
+\defineinteractionbar[f][\c!command=\scrn_bar_alternative_f]
+\defineinteractionbar[g][\c!command=\scrn_bar_alternative_g,\c!height=\v!broad]
+
+\protect \endinput
diff --git a/tex/context/base/scrn-but.lua b/tex/context/base/scrn-but.lua
new file mode 100644
index 000000000..b5b0a8ae4
--- /dev/null
+++ b/tex/context/base/scrn-but.lua
@@ -0,0 +1,19 @@
+if not modules then modules = { } end modules ['scrn-but'] = {
+ version = 1.001,
+ comment = "companion to scrn-but.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+
+function commands.registerbuttons(tag,register,language)
+ local data = sorters.definitions[language]
+ local orders = daya and data.orders or sorters.definitions.default.orders
+ local tag = tag == "" and { "" } or { tag }
+ for i=1,#orders do
+ local order = orders[i]
+ context.menubutton(tag,format("%s:%s",register,order),order)
+ end
+end
diff --git a/tex/context/base/scrn-but.mkiv b/tex/context/base/scrn-but.mkiv
deleted file mode 100644
index 569909b50..000000000
--- a/tex/context/base/scrn-but.mkiv
+++ /dev/null
@@ -1,127 +0,0 @@
-%D \module
-%D [ file=scrn-but, % moved code
-%D version=1995.01.01,
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Interaction,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%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 Screen Macros / Buttons}
-
-\unprotect
-
-%D Buttons are just what their names says: things that can be
-%D clicked (pushed) on. They are similar to \type{\goto},
-%D except that the text argument is not interpreted.
-%D Furthermore one can apply anything to them that can be done
-%D with \type{\framed}.
-%D
-%D \startbuffer
-%D \button[width=3cm,height=1.5cm]{Exit}[ExitViewer]
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D gives
-%D
-%D \getbuffer
-%D
-%D This command is formally specified as:
-%D
-%D \showsetup{button}
-%D
-%D The characteristics can be set with:
-%D
-%D \showsetup{setupbuttons}
-
-\unexpanded\def\setupbuttons
- {\dodoubleargument\getparameters[\??bt]}
-
-\definecomplexorsimpleempty\button
-
-\def\complexbutton
- {\docomplexbutton\??bt}
-
-\presetlocalframed[\??bt]
-
-\def\buttonparameter#1{\csname\??bt#1\endcsname} % simple version
-
-\long\def\docomplexbutton#1[#2]#3#4% get rid of possible space before [#4]
- {\dodocomplexbutton#1[#2]{#3}#4} % #4 == [
-
-\def\buttonframed{\dodoubleempty\localframed[\??bt]} % goodie
-
-% #3=none is obsolete, just use empty=yes
-
-\long\def\dodocomplexbutton#1[#2]#3[#4]% #3 can contain [] -> {#3} later
- {\begingroup
- \let\menuparameter\buttonparameter
- \doif{\buttonparameter\c!state}\v!stop\locationfalse
- \iflocation
- \setlocationboxyes#1[#2]{#3}[#4]%
- \fi
- \endgroup}
-
-%D \macros
-%D {overlaybutton}
-%D
-%D For converience we provide:
-%D
-%D \starttyping
-%D \overlaybutton[reference]
-%D \stoptyping
-%D
-%D This command can be used to define overlays an/or can be
-%D used in the whatevertext areas, like:
-%D
-%D \starttyping
-%D \defineoverlay[PrevPage][\overlaybutton{PrevPage}]
-%D \setupbackgrounds[page][background=PrevPage]
-%D \setuptexttexts[\overlaybutton{NextPage}]
-%D \stoptyping
-%D
-%D For practical reasons, this macro accepts square brackets
-%D as well as braces.
-
-\definecomplexorsimple\overlaybutton
-
-\def\simpleoverlaybutton#1%
- {\complexoverlaybutton[#1]}
-
-\def\complexoverlaybutton[#1]%
- {\iflocation
- \gotobox{\overlayfakebox}[#1]%
- \fi}
-
-\def\overlayfakebox
- {\hbox
- {\setbox\scratchbox\emptyhbox
- \wd\scratchbox\overlaywidth
- \ht\scratchbox\overlayheight
- \box\scratchbox}}
-
-%D Done.
-
-\setupbuttons
- [\c!state=\v!start,
- \c!width=\v!fit,
- \c!height=\v!broad,
- \c!offset=0.25em,
- \c!frame=\v!on,
- \c!background=,
- \c!backgroundcolor=,
- \c!foregroundstyle=\buttonparameter\c!style,
- \c!foregroundcolor=\buttonparameter\c!color,
- \c!style=\@@iastyle,
- \c!color=\@@iacolor,
- \c!contrastcolor=\@@iacontrastcolor,
- \c!samepage=\v!yes,
- \c!unknownreference=\v!yes,
- \c!distance=\zeropoint] % for menubuttons
-
-\protect \endinput
diff --git a/tex/context/base/scrn-but.mkvi b/tex/context/base/scrn-but.mkvi
new file mode 100644
index 000000000..c2d4900e6
--- /dev/null
+++ b/tex/context/base/scrn-but.mkvi
@@ -0,0 +1,984 @@
+%D \module
+%D [ file=scrn-but, % moved code
+%D version=1995.01.01,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Interaction,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% \restorestandardblank
+% better namespace for pos
+
+\writestatus{loading}{ConTeXt Screen Macros / Buttons}
+
+\registerctxluafile{scrn-but}{1.001}
+
+\unprotect
+
+%D Buttons are just what their names says: things that can be
+%D clicked (pushed) on. They are similar to \type{\goto},
+%D except that the text argument is not interpreted.
+%D Furthermore one can apply anything to them that can be done
+%D with \type{\framed}.
+%D
+%D \startbuffer
+%D \button[width=3cm,height=1.5cm]{Exit}[ExitViewer]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D gives
+%D
+%D \getbuffer
+%D
+%D This command is formally specified as:
+%D
+%D \showsetup{button}
+%D
+%D The characteristics can be set with:
+%D
+%D \showsetup{setupbuttons}
+
+\installcommandhandler \??bt {button} \??bt
+
+\let\setupbuttons\setupbutton
+
+\presetlocalframed[\??bt]
+
+\appendtoks
+ \setuevalue\currentbutton{\scrn_button_direct{\currentbutton}}%
+ \setevalue{\??bt:\currentbutton\s!parent}{\??bt\currentbutton}% framed
+\to \everydefinebutton
+
+\unexpanded\def\scrn_button_direct#tag%
+ {\begingroup
+ \edef\currentbutton{#tag}%
+ \doifelselocation
+ {\dosingleempty\scrn_button_direct_status}%
+ {\dosingleempty\scrn_button_direct_ignore}}
+
+\def\scrn_button_direct_status
+ {\doifelse{\buttonparameter\c!state}\v!start
+ \scrn_button_direct_indeed
+ \scrn_button_direct_ignore}
+
+%\def\buttonframed{\dodoubleempty\localframed[\??bt]} % goodie
+
+% empty=yes
+%
+% \button[settings]{}[action] % normally used at the tex end
+
+\def\scrn_button_direct_indeed[#settings]#text[#action]%
+ {\iffirstargument
+ \setupbuttons[\currentbutton][#settings]%
+ \fi
+ \scrn_button_make\??bt\currentbutton\buttonparameter{#text}{#action}%
+ \endgroup}
+
+\def\scrn_button_direct_ignore[#settings]#text[#destination]%
+ {\endgroup}
+
+\definebutton[button] % english
+
+\setupbuttons
+ [\c!state=\v!start,
+ \c!width=\v!fit,
+ \c!height=\v!broad,
+ \c!offset=0.25em,
+ \c!frame=\v!on,
+ \c!background=,
+ \c!backgroundcolor=,
+ \c!foregroundstyle=\buttonparameter\c!style,
+ \c!foregroundcolor=\buttonparameter\c!color,
+ \c!style=\interactionparameter\c!style,
+ \c!color=\interactionparameter\c!color,
+ \c!contrastcolor=\interactionparameter\c!contrastcolor,
+ \c!samepage=\v!yes,
+ \c!unknownreference=\v!yes,
+ \c!distance=\zeropoint] % for menubuttons
+
+%D \macros
+%D {overlaybutton}
+%D
+%D For converience we provide:
+%D
+%D \starttyping
+%D \overlaybutton[reference]
+%D \stoptyping
+%D
+%D This command can be used to define overlays an/or can be
+%D used in the whatevertext areas, like:
+%D
+%D \starttyping
+%D \defineoverlay[PrevPage][\overlaybutton{PrevPage}]
+%D \setupbackgrounds[page][background=PrevPage]
+%D \setuptexttexts[\overlaybutton{NextPage}]
+%D \stoptyping
+%D
+%D For practical reasons, this macro accepts square brackets
+%D as well as braces.
+
+\unexpanded\def\overlaybutton
+ {\dosingleempty\scrn_button_overlay}
+
+\def\scrn_button_overlay[#1]%
+ {\iffirstargument
+ \scrn_button_overlay_indeed{#1}%
+ \else
+ \expandafter\scrn_button_overlay_indeed
+ \fi}
+
+\def\scrn_button_overlay_indeed#1%
+ {\iflocation
+ \gotobox{\overlayfakebox}[#1]%
+ \fi}
+
+%D The renderers:
+
+\expandafter\let\csname\??bt:\c!location:\v!yes \endcsname\zerocount
+\expandafter\let\csname\??bt:\c!location:\v!empty \endcsname\plusone
+\expandafter\let\csname\??bt:\c!location:\v!no \endcsname\plustwo
+\expandafter\let\csname\??bt:\c!location:\v!none \endcsname\plusthree
+\expandafter\let\csname\??bt:\c!location:\v!normal \endcsname\plusone % default
+\expandafter\let\csname\??bt:\c!location:\s!default\endcsname\plusone % default
+\expandafter\let\csname\??bt:\c!location:\s!empty \endcsname\plusone % default
+
+\newconditional\scrn_button_skipped
+
+\def\scrn_button_make#namespace#current#currentparameter#text#action%
+ {\begingroup
+ \attribute\referenceattribute\attributeunsetvalue
+ \global\setfalse\scrn_button_skipped
+ \chardef\locationboxpagestate\csname\??bt:\c!location:#currentparameter\c!samepage\endcsname
+ \doifreferencefoundelse{#action}\scrn_button_make_yes\scrn_button_make_nop
+ {#namespace}{#current}{#currentparameter}{#text}%
+ \endgroup}
+
+\def\scrn_button_make_yes
+ {\analyzecurrentreference % needed as we act on the state
+ \ifcase\referencepagestate
+ \expandafter\scrn_button_make_normal % no state : something else than a page reference
+ \or
+ \ifcase\locationboxpagestate\relax
+ \expandafter\expandafter\expandafter\scrn_button_make_contrast % same page: yes: same page or not ... todo
+ \or
+ \expandafter\expandafter\expandafter\scrn_button_make_empty % same page: empty but frame: no click
+ \or
+ \expandafter\expandafter\expandafter\scrn_button_make_nothing % same page: empty no frame: no
+ \else
+ \expandafter\expandafter\expandafter\scrn_button_make_skipped % same page: nothing at all
+ \fi
+ \else
+ \ifcase\locationboxpagestate\relax
+ \expandafter\expandafter\expandafter\scrn_button_make_normal % other page: yes: same page or not ... todo
+ \or
+ \expandafter\expandafter\expandafter\scrn_button_make_normal % other page: empty but frame: no click
+ \or
+ \expandafter\expandafter\expandafter\scrn_button_make_normal % other page: empty no frame: no
+ \else
+ \expandafter\expandafter\expandafter\scrn_button_make_skipped % other page: nothing at all
+ \fi%
+ \fi}
+
+\def\scrn_button_make_nop
+ {\ifcase\locationboxpagestate\relax
+ \expandafter\scrn_button_make_framed
+ \or
+ \expandafter\scrn_button_make_empty
+ \or
+ \expandafter\scrn_button_make_nothing
+ \or
+ \expandafter\scrn_button_make_skipped
+ \fi}
+
+\def\scrn_button_make_framed#namespace#current#currentparameter#text%
+ {\directlocalframed[#namespace:#current]{\ignorespaces#text\removeunwantedspaces}}
+
+\def\scrn_button_make_skipped#namespace#current#currentparameter#text%
+ {\global\settrue\scrn_button_skipped}
+
+\def\scrn_button_make_normal#namespace#current#currentparameter#text%
+ {\ctxlua{structures.references.injectcurrentset(nil,nil)}%
+ \hbox attr \referenceattribute \lastreferenceattribute
+ {\directlocalframed
+ [#namespace:#current]%
+ {\ignorespaces#text\removeunwantedspaces}}}
+
+\def\scrn_button_make_contrast#namespace#current#currentparameter#text%
+ {\ctxlua{structures.references.injectcurrentset(nil,nil)}%
+ \hbox attr \referenceattribute \lastreferenceattribute
+ {\localframedwithsettings
+ [#namespace:#current]%
+ [\c!foregroundcolor=#currentparameter\c!contrastcolor]%
+ {\ignorespaces#text\removeunwantedspaces}}}
+
+\def\scrn_button_make_empty#namespace#current#currentparameter#text%
+ {\localframedwithsettings
+ [#namespace:#current]%
+ [\c!empty=\v!yes]%
+ {\ignorespaces#text\removeunwantedspaces}}
+
+\def\scrn_button_make_nothing#namespace#current#currentparameter#text%
+ {\localframedwithsettings
+ [#namespace:#current]%
+ [\c!empty=\v!yes,\c!frame=,\c!background=]%
+ {\ignorespaces#text\removeunwantedspaces}}
+
+%D Menus:
+%D
+%D \starttyping
+%D \setuppapersize
+%D [S6][S6]
+%D
+%D \setuplayout
+%D [backspace=6cm, cutspace=6cm,
+%D leftedge=3cm, rightedge=3cm,
+%D leftmargin=1cm, rightmargin=1cm,
+%D margindistance=5mm, edgedistance=5mm,
+%D topspace=4cm, bottomspace=4cm,
+%D header=0pt, footer=0pt,
+%D top=1cm, bottom=1cm,
+%D topdistance=5mm, bottomdistance=5mm,
+%D width=middle, height=middle]
+%D
+%D \setupinteraction
+%D [state=start,
+%D menu=on]
+%D
+%D \setupinteractionmenu
+%D [right]
+%D [state=start,background=color,frame=off,backgroundcolor=red,color=white,contrastcolor=blue]
+%D \setupinteractionmenu
+%D [left]
+%D [state=start,background=color,frame=off,backgroundcolor=green,color=white]
+%D \setupinteractionmenu
+%D [top]
+%D [state=start,background=color,frame=off,backgroundcolor=blue,color=white]
+%D \setupinteractionmenu
+%D [bottom]
+%D [state=start,background=color,frame=off,backgroundcolor=yellow,color=white]
+%D
+%D \setupinteractionmenu
+%D [left]
+%D [state=local]
+%D \setupinteractionmenu
+%D [bottom]
+%D [state=local]
+%D
+%D \startinteractionmenu[right]
+%D \startbut [page(2)] Page 2 \stopbut
+%D \startbut [page(1)] Page 1 \stopbut
+%D \includemenu[left]
+%D \includemenu[bottom]
+%D \stopinteractionmenu
+%D
+%D \startinteractionmenu[left]
+%D \startbut [page(1)] Page 1 \stopbut
+%D \startbut [page(2)] Page 2 \stopbut
+%D \stopinteractionmenu
+%D
+%D \startinteractionmenu[top]
+%D \startbut [page(1)] Page 1 \stopbut
+%D \startbut [page(2)] Page 2 \stopbut
+%D \stopinteractionmenu
+%D
+%D \startinteractionmenu[bottom]
+%D \startbut [page(2)] Page 2 \stopbut
+%D \startbut [page(1)] Page 1 \stopbut
+%D \stopinteractionmenu
+%D \stoptyping
+%D
+%D \starttyping
+%D \startinteractionmenu[rechts]
+%D \startbut [eerste] eerste \stopbut
+%D \starttxt hello world \stoptxt
+%D \startbut [tweede] tweede \stopbut
+%D \startnop \stopnop
+%D \startbut [tweede] tweede \stopbut
+%D \startrul whow \stoprul
+%D \startbut [tweede] tweede \stopbut
+%D \startraw hello world \stopraw
+%D \startbut [tweede] tweede \stopbut
+%D \startcom \vfill \stopcom
+%D \startbut [derde] derde \stopbut
+%D \stopinteractionmenu
+%D \stoptyping
+%D
+%D \starttyping
+%D \setupinteractionmenu[right][samepage=yes, unknownreference=yes]
+%D \setupinteractionmenu[right][samepage=empty,unknownreference=empty]
+%D \setupinteractionmenu[right][samepage=no, unknownreference=no]
+%D \setupinteractionmenu[right][samepage=none, unknownreference=none]
+%D \stoptyping
+
+\installcommandhandler \??am {interactionmenu} \??am
+
+\let\setupinteractionmenus\setupinteractionmenu
+
+\presetlocalframed[\??am]
+
+\let\scrn_menu_action\relax
+
+\let\scrn_menu_define_original\defineinteractionmenu
+
+\unexpanded\def\defineinteractionmenu
+ {\dotripleempty\scrn_menu_define}
+
+\def\scrn_menu_define[#tag][#category][#settings]% category reflects location, settings can be parent
+ {\ifthirdargument
+ \doifassignmentelse{#settings}%
+ {\scrn_menu_define_original[#tag][#category][\c!category=#category,#settings]}% child definition
+ {\scrn_menu_define_original[#tag][#settings][\c!category=#category]}% % child definition
+ \scrn_menu_register{#tag}{#category}%
+ \setevalue{\??am:#tag\s!parent}{\??am#tag}% framed
+ \else\ifsecondargument
+ \doifassignmentelse{#category}%
+ {\scrn_menu_define_original[#tag][#category]% % root definition
+ \setevalue{\??am:#tag\s!parent}{\??am}}% framed
+ {\scrn_menu_define_original[#tag][#category][\c!category=#category]% % child definition
+ \scrn_menu_register{#tag}{#category}%
+ \setevalue{\??am:#tag\s!parent}{\??am#tag}}% framed
+ \else
+ \scrn_menu_define_original[#tag]% % root definition
+ \setevalue{\??am:#tag\s!parent}{\??am}% framed
+ \fi\fi}
+
+\def\scrn_menu_register#tag#category%
+ {\ifcsname\??am:t:#category\endcsname \else
+ \expandafter\newtoks \csname\??am:t:#category\endcsname
+ \expandafter\setfalse\csname\??am:c:#category\endcsname
+ \fi
+ \normalexpanded{\csname\??am:t:#category\endcsname{\the\csname\??am:t:#category\endcsname\scrn_menu_action{#tag}}}}
+
+\def\scrn_menu_actions#category%
+ {\the\csname\??am:t:#category\endcsname}
+
+%D Fill menus:
+
+\normalexpanded{\long\def\expandafter\noexpand\csname\e!start\v!interactionmenu\endcsname[#tag]#content\expandafter\noexpand\csname\e!stop\v!interactionmenu\endcsname}%
+ {\def\currentinteractionmenu{#tag}%
+ \expandafter\settrue\csname\??am:c:\interactionmenuparameter\c!category\endcsname
+ \setinteractionmenuparameter\c!menu{#content}}
+
+\def\resetinteractionmenu[#tag]%
+ {\def\currentinteractionmenu{#tag}%
+ \resetinteractionmenuparameter\c!menu}
+
+%D Placement of menus:
+%D
+%D The offset mechanism is not the same as in in \MKII. There we
+%D adapted automatically to offsets in the text backgrounds. Here we
+%D have a bit more (but manual) control.
+%D
+%D \starttyping
+%D \setupbackgrounds
+%D [text][text]
+%D [background=color,backgroundcolor=gray,backgroundoffset=2mm]
+%D
+%D \setupbackgrounds
+%D [text]
+%D [rightedge,leftedge]
+%D [background=color,backgroundcolor=gray]
+%D
+%D \setupbackgrounds
+%D [top,bottom]
+%D [text]
+%D [background=color,backgroundcolor=gray]
+%D
+%D \setupinteractionmenu
+%D [right]
+%D [topoffset=0mm,bottomoffset=0mm]
+%D
+%D \setupinteractionmenu
+%D [top]
+%D [topoffset=2mm,bottomoffset=2mm,rightoffset=2mm,leftoffset=2mm]
+%D \stoptyping
+%D
+%D The no longer hard coded text areas offset compensation makes tuning
+%D easier. After all, menus need some setup anyway.
+
+\newbox \scrn_menu_box
+
+\newdimen\scrn_menu_next_distance
+\newdimen\scrn_menu_final_width
+\newdimen\scrn_menu_final_height
+\newdimen\scrn_menu_used_width
+\newdimen\scrn_menu_used_height
+\newdimen\scrn_menu_asked_width
+\newdimen\scrn_menu_asked_height
+\newdimen\scrn_menu_offset_top
+\newdimen\scrn_menu_offset_bottom
+\newdimen\scrn_menu_offset_left
+\newdimen\scrn_menu_offset_right
+
+\def\scrn_menu_set_used
+ {\scrn_menu_offset_left \interactionmenuparameter\c!leftoffset
+ \scrn_menu_offset_right \interactionmenuparameter\c!rightoffset
+ \scrn_menu_offset_top \interactionmenuparameter\c!topoffset
+ \scrn_menu_offset_bottom\interactionmenuparameter\c!bottomoffset
+ \scrn_menu_asked_width \interactionmenuparameter\c!maxwidth
+ \scrn_menu_asked_height \interactionmenuparameter\c!maxheight
+ \scrn_menu_used_width\dimexpr
+ \scrn_menu_asked_width + \scrn_menu_offset_left + \scrn_menu_offset_right
+ \relax
+ \scrn_menu_used_height\dimexpr
+ \scrn_menu_asked_height + \scrn_menu_offset_top + \scrn_menu_offset_bottom
+ \relax}
+
+\def\scrn_menu_set_final
+ {\scrn_menu_final_width \namedinteractionmenuparameter\askedinteractionmenulocation\c!maxwidth
+ \scrn_menu_final_height\namedinteractionmenuparameter\askedinteractionmenulocation\c!maxheight}
+
+\def\scrn_menu_apply_final
+ {\wd\scrn_menu_box\scrn_menu_final_width
+ \ht\scrn_menu_box\scrn_menu_final_height
+ \dp\scrn_menu_box\zeropoint}
+
+\def\scrn_menu_apply_used
+ {\ifdim\scrn_menu_offset_left=\zeropoint \else
+ \setbox\scrn_menu_box\hbox{\hskip-\scrn_menu_offset_left \box\scrn_menu_box}%
+ \fi
+ \ifdim\scrn_menu_offset_bottom=\zeropoint \else
+ \setbox\scrn_menu_box\hbox{\lower \scrn_menu_offset_bottom \box\scrn_menu_box}%
+ \fi
+ \wd\scrn_menu_box\scrn_menu_asked_width
+ \ht\scrn_menu_box\scrn_menu_asked_height
+ \dp\scrn_menu_box\zeropoint}
+
+\setvalue{scrn_menu_align_\v!right }{\let\scrn_menu_left_align\raggedright}
+\setvalue{scrn_menu_align_\v!left }{\let\scrn_menu_left_align\raggedleft}
+\setvalue{scrn_menu_align_\v!flushright}{\let\scrn_menu_left_align\raggedleft}
+\setvalue{scrn_menu_align_\v!flushleft }{\let\scrn_menu_left_align\raggedright}
+\setvalue{scrn_menu_align_\v!middle }{\let\scrn_menu_left_align\raggedcenter}
+\setvalue{scrn_menu_align_\v!low }{\let\scrn_menu_top_align\vss\let\scrn_menu_bottom_align\relax}
+\setvalue{scrn_menu_align_\v!high }{\let\scrn_menu_top_align\relax\let\scrn_menu_bottom_align\vss}
+\setvalue{scrn_menu_align_\v!lohi }{\let\scrn_menu_top_align\vss\let\scrn_menu_bottom_align\vss}
+
+\let\scrn_menu_left_align \relax
+\let\scrn_menu_right_align \relax
+\let\scrn_menu_top_align \relax
+\let\scrn_menu_bottom_align\relax
+
+\def\scrn_menu_set_align
+ {\csname scrn_menu_align_\interactionmenuparameter\c!itemalign\endcsname}
+
+%D Hook into the pagebuilder (as less testing as possible):
+
+\def\scrn_menu_insert
+ {\iflocation
+ \expandafter\scrn_menu_insert_checked
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\def\scrn_menu_insert_checked#location%
+ {\ifconditional\csname\??am:c:#location\endcsname
+ \scrn_menu_insert_indeed{#location}%
+ \fi}
+
+\def\scrn_menu_insert_indeed#location%
+ {\begingroup
+ \edef\askedinteractionmenulocation{#location}%
+ \scrn_menu_set_final
+ \ifcase\scrn_menu_final_width \else \ifcase\scrn_menu_final_height \else
+ \forgetall
+ \global\scrn_menu_next_distance\zeropoint
+ \let\scrn_menu_action\scrn_menu_package_indeed
+ \the\everysetmenucommands
+ \csname\??am:\c!menu:\namedinteractionmenuparameter\askedinteractionmenulocation\c!alternative\endcsname
+ \fi \fi
+ \endgroup}
+
+%D This calls: % can be \c!command for vertical/horizontal
+
+\setvalue{\??am:\c!menu:\v!vertical}% all menus
+ {\let\scrn_menu_packager\scrn_menu_packager_vertical
+ \setbox\scrn_menu_box\hbox{\scrn_menu_actions\askedinteractionmenulocation}%
+ \scrn_menu_apply_final
+ \box\scrn_menu_box}
+
+\setvalue{\??am:\c!menu:\v!horizontal}% all menus
+ {\let\scrn_menu_packager\scrn_menu_packager_horizontal
+ \setbox\scrn_menu_box\vbox{\scrn_menu_actions\askedinteractionmenulocation}%
+ \scrn_menu_apply_final
+ \box\scrn_menu_box}
+
+% stop : skipped
+% start: processed
+% local: skipped but can be included
+% empty: processed but invisible
+
+\unexpanded\def\scrn_menu_package_indeed#tag% one menu
+ {\begingroup
+ \edef\currentinteractionmenu{#tag}%
+ \edef\currentinteractionmenustate{\interactionmenuparameter\c!state}%
+ \ifx\currentinteractionmenustate\v!start
+ \scrn_menu_packager
+ \else\ifx\currentinteractionmenustate\v!empty
+ \scrn_menu_packager
+ \fi\fi
+ \endgroup}
+
+%D With the packager being one of:
+
+\def\scrn_menu_packager_vertical
+ {\scrn_menu_set_used
+ \hskip\scrn_menu_next_distance
+ \setbox\scrn_menu_box\hbox to \scrn_menu_used_width
+ {\ifx\currentinteractionmenustate\v!empty \else
+ \interactionmenuparameter\c!left
+ \scrn_menu_package_vertical{\interactionmenuparameter\c!menu}%
+ \interactionmenuparameter\c!right
+ \fi}%
+ \edef\currentinteractionmenudistance{\interactionmenuparameter\c!distance}%
+ \ifx\currentinteractionmenudistance\v!overlay
+ \global\scrn_menu_next_distance\zeropoint
+ \wd\scrn_menu_box\zeropoint
+ \else
+ \global\scrn_menu_next_distance\currentinteractionmenudistance
+ \scrn_menu_apply_used
+ \fi
+ \box\scrn_menu_box}
+
+\def\scrn_menu_packager_horizontal
+ {\scrn_menu_set_used
+ \vskip\scrn_menu_next_distance
+ \scrn_menu_set_align
+ \setbox\scrn_menu_box\vbox to \scrn_menu_used_height
+ {\ifx\currentinteractionmenustate\v!none \else
+ \scrn_menu_top_align
+ \interactionmenuparameter\c!before
+ \scrn_menu_package_horizontal{\interactionmenuparameter\c!menu}%
+ \interactionmenuparameter\c!after
+ \scrn_menu_bottom_align
+ \fi}%
+ \edef\currentinteractionmenudistance{\interactionmenuparameter\c!distance}%
+ \ifx\currentinteractionmenudistance\v!overlay
+ \global\scrn_menu_next_distance\zeropoint
+ \offinterlineskip
+ \dp\scrn_menu_box\zeropoint
+ \ht\scrn_menu_box\zeropoint
+ \else
+ \global\scrn_menu_next_distance\currentinteractionmenudistance
+ \scrn_menu_apply_used
+ \fi
+ \box\scrn_menu_box}
+
+%D For a right menu, a sequence of calls to \type
+%D {right_menu_button} is generated.
+%D
+%D \starttyping
+%D right_menu_button (n, p, s=0/1/2, x, y, w, h, d) ;
+%D \stoptyping
+%D
+%D Here, n is the number of the button, s a status variable,
+%D while the rest is positional info. The status variable is
+%D 0, 1 or~2: not found, found and found but current page.
+
+\newcount \scrn_menu_position
+\newconstant \scrn_menu_page_mode % 0=notfound 1=found 2=currentpage
+\newconditional\scrn_menu_positioning
+\newtoks \scrn_menu_mp_data
+
+\def\scrn_menu_button_mp_template
+ {\askedinteractionmenulocation_menu_button(%
+ \number\scrn_menu_position,%
+ \number\scrn_menu_page_mode,%
+ \MPpos{\askedinteractionmenulocation:\number\scrn_menu_position}%
+ );}
+
+\def\MPmenubuttons#1{\the\scrn_menu_mp_data}
+
+\appendtoks
+ \global\scrn_menu_mp_data\emptytoks
+\to \everyshipout
+
+\def\scrn_menu_whole_position % cannot happen in previous due to align
+ {\setbox\scrn_menu_box\hbox \bgroup
+ \hpos{menu:\askedinteractionmenulocation:\the\realpageno}{\box\scrn_menu_box}%
+ \egroup}
+
+% removed: \restorestandardblank (vspacing) ... should happen elsewhere
+
+\def\scrn_menu_package_vertical#content%
+ {\begingroup
+ \global\scrn_menu_position\zerocount
+ \def\scrn_menu_between_action_indeed{\interactionmenuparameter\c!inbetween}%
+ \doifelse{\interactionmenuparameter\c!position}\v!yes\settrue\setfalse\scrn_menu_positioning
+ \scrn_menu_set_align
+ \setbox\scrn_menu_box\vbox to \scrn_menu_used_height \bgroup
+ \hsize\scrn_menu_used_width
+ \scrn_menu_left_align
+ \interactionmenuparameter\c!before\relax
+ \ignorespaces#content\unskip
+ \interactionmenuparameter\c!after
+ \scrn_menu_right_align
+ \egroup
+ \ifconditional\scrn_menu_positioning
+ \scrn_menu_whole_position
+ \fi
+ \box\scrn_menu_box
+ \endgroup}
+
+\def\scrn_menu_package_horizontal#content%
+ {\begingroup
+ \global\scrn_menu_position\zerocount
+ \def\scrn_menu_between_action_indeed{\interactionmenuparameter\c!middle}%
+ \doifelse{\interactionmenuparameter\c!position}\v!yes\settrue\setfalse\scrn_menu_positioning
+ \setbox\scrn_menu_box\hbox to \scrn_menu_used_width \bgroup
+ \interactionmenuparameter\c!left\relax
+ \ignorespaces#content\unskip
+ \interactionmenuparameter\c!right
+ \egroup
+ \ifconditional\scrn_menu_positioning
+ \scrn_menu_whole_position
+ \fi
+ \box\scrn_menu_box
+ \endgroup}
+
+\def\scrn_menu_action_start
+ {\dontleavehmode
+ \begingroup}
+
+\def\scrn_menu_action_stop
+ {\ifconditional\scrn_button_skipped \else
+ \scrn_menu_between_action_indeed
+ \fi
+ \endgroup
+ \ignorespaces}
+
+\unexpanded\def\scrn_menu_raw_start[#action]#text\stopraw
+ {\scrn_menu_action_start
+ \gotobox{\ignorespaces#text\unskip}[#action]%
+ \scrn_menu_action_stop}
+
+\unexpanded\def\scrn_menu_but_start[#action]#text\stopbut
+ {\scrn_menu_action_start
+ \ifconditional\scrn_menu_positioning
+ \expandafter\scrn_button_make_position
+ \else
+ \expandafter\scrn_button_make
+ \fi\??am\currentinteractionmenu\interactionmenuparameter{#text}{#action}%
+ \scrn_menu_action_stop}
+
+\def\scrn_button_make_position#namespace#current#currentparameter#text#action%
+ {\global\advance\scrn_menu_position\plusone
+ \doifreferencefoundelse{#action}% 0=not found, 1=same page, >1=elsewhere
+ {\scrn_menu_page_mode\ifnum\currentreferencerealpage=\realpageno\plusone\else\plustwo\fi}%
+ {\scrn_menu_page_mode\plustwo}%
+ \doglobal\appendetoks
+ \scrn_menu_button_mp_template
+ \to \scrn_menu_mp_data
+ \hpos
+ {\askedinteractionmenulocation:\number\scrn_menu_position}%
+ {\scrn_button_make{#namespace}{#current}{#currentparameter}{#text}{#action}}}
+
+\unexpanded\def\scrn_menu_got_start[#action]#text\stopgot
+ {\scrn_menu_action_start
+ \setupbuttons[\currentinteractionmenu][\c!frame=\v!off,\c!background=]%
+ \scrn_button_make\??am\currentinteractionmenu\interactionmenuparameter{#text}{#action}%
+ \scrn_menu_action_stop}
+
+\unexpanded\def\scrn_menu_nop_start#text\stopnop
+ {\scrn_menu_action_start
+ \localframedwithsettings
+ [\??am:\currentinteractionmenu]%
+ [\c!frame=\v!off,\c!background=,\c!empty=\v!yes]%
+ {\ignorespaces#text\removeunwantedspaces}%
+ \scrn_menu_action_stop}
+
+\unexpanded\def\scrn_menu_txt_start#text\stoptxt
+ {\scrn_menu_action_start
+ \localframedwithsettings
+ [\??am:\currentinteractionmenu]%
+ [\c!frame=\v!off,\c!background=]%
+ {\ignorespaces#text\removeunwantedspaces}%
+ \scrn_menu_action_stop}
+
+\unexpanded\def\scrn_menu_rul_start#text\stoprul
+ {\scrn_menu_action_start
+ \directlocalframed
+ [\??am:\currentinteractionmenu]%
+ {\ignorespaces#text\removeunwantedspaces}%
+ \scrn_menu_action_stop}
+
+\unexpanded\def\scrn_menu_com_start#text\stopcom
+ {\ignorespaces#text\removeunwantedspaces
+ \ignorespaces}
+
+\unexpanded\def\scrn_menu_raw#content\\{\scrn_menu_raw_start#content\stopraw} \let\stopraw\relax
+\unexpanded\def\scrn_menu_but#content\\{\scrn_menu_but_start#content\stopbut} \let\stopbut\relax
+\unexpanded\def\scrn_menu_got#content\\{\scrn_menu_got_start#content\stopgot} \let\stopgot\relax
+\unexpanded\def\scrn_menu_nop#content\\{\scrn_menu_nop_start#content\stopnop} \let\stopnop\relax
+\unexpanded\def\scrn_menu_txt#content\\{\scrn_menu_nop_start#content\stoptxt} \let\stoptxt\relax
+\unexpanded\def\scrn_menu_rul#content\\{\scrn_menu_rul_start#content\stoprul} \let\stoprul\relax
+\unexpanded\def\scrn_menu_com#content\\{\scrn_menu_com_start#content\stopcom} \let\stopcom\relax
+
+\newtoks\everysetmenucommands % public
+
+\appendtoks
+ \let\raw\scrn_menu_raw \let\startraw\scrn_menu_raw_start
+ \let\but\scrn_menu_but \let\startbut\scrn_menu_but_start
+ \let\got\scrn_menu_got \let\startgot\scrn_menu_got_start
+ \let\nop\scrn_menu_nop \let\startnop\scrn_menu_nop_start
+ \let\txt\scrn_menu_txt \let\starttxt\scrn_menu_txt_start
+ \let\rul\scrn_menu_rul \let\startrul\scrn_menu_rul_start
+ \let\com\scrn_menu_com \let\startcom\scrn_menu_com_start
+\to \everysetmenucommands
+
+%D Sometimes handy:
+%D
+%D \starttyping
+%D \setupinteractionmenu
+%D [left]
+%D [state=local]
+%D
+%D \startinteractionmenu[right]
+%D ...
+%D \includemenu[left]
+%D ...
+%D \stopinteractionmenu
+%D \stoptyping
+
+\unexpanded\def\includemenu[#tag]%
+ {\begingroup
+ \edef\currentinteractionmenu{#tag}%
+ \doif{\interactionmenuparameter\c!state}\v!local
+ {\letinteractionmenuparameter\c!state\v!start
+ \setinteractionmenuparameter\s!parent{\??am\askedinteractionmenulocation}% nice hack
+ \interactionmenuparameter\c!menu}%
+ \endgroup}
+
+%D Direct call (todo):
+
+\unexpanded\def\interactionmenu
+ {\dodoubleempty\scrn_menu_interaction_menu}
+
+\def\scrn_menu_interaction_menu[#tag][#settings]%
+ {\begingroup
+ \setupinteractionmenu[#tag][#settings]%
+% \edef\currentinteractionmenu {#tag}%
+% \edef\askedinteractionmenulocation {\interactionmenuparameter\c!category}%
+% \edef\askedinteractionmenualternative{\interactionmenuparameter\c!alternative}%
+% \def\scrn_menu_actions#dummy{\scrn_menu_package_indeed\currentinteractionmenu}%
+% \csname\??am:\c!menu:\askedinteractionmenualternative\endcsname
+ \scrn_menu_insert{#tag}%
+ \endgroup}
+
+%D Plugin handler:
+
+\unexpanded\def\scrn_menu_insert_content_indeed
+ {\iflocation % here as we can have a fast turn-off
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\let\scrn_menu_insert_content_ignore\gobbleoneargument
+
+\appendtoks
+ \doifelse{\interactionparameter\c!menu}\v!on
+ {\let\scrn_menu_insert_content\scrn_menu_insert_content_indeed}%
+ {\let\scrn_menu_insert_content\scrn_menu_insert_content_ignore}%
+\to \everysetupinteraction
+
+%D Plugs into the page builder:
+
+\unexpanded\def\scrn_menu_leftedge
+ {\hbox to \leftedgewidth \bgroup
+ \hsize\leftedgewidth
+ %\csname\??tk\v!leftedge\c!left\endcsname
+ \scrn_menu_insert\v!left
+ %\csname\??tk\v!leftedge\c!right\endcsname
+ \egroup
+ \hskip-\leftedgewidth}
+
+\unexpanded\def\scrn_menu_rightedge
+ {\hbox to \rightedgewidth \bgroup
+ \hsize\rightedgewidth
+ %\csname\??tk\v!rightedge\c!left\endcsname
+ \scrn_menu_insert\v!right
+ %\csname\??tk\v!rightedge\c!right\endcsname
+ \egroup
+ \hskip-\rightedgewidth}
+
+\unexpanded\def\scrn_menu_top % uses \??tk
+ {\vbox to \topheight \bgroup
+ \vsize\topheight
+ %\csname\??tk\v!top\c!before\endcsname
+ \scrn_menu_insert\v!top
+ %\csname\??tk\v!top\c!after\endcsname
+ \kern\zeropoint
+ \egroup
+ \vskip-\topheight}
+
+\unexpanded\def\scrn_menu_bottom % uses \??tk
+ {\vbox to \bottomheight \bgroup
+ \vsize\bottomheight
+ %\csname\??tk\v!bottom\c!before\endcsname
+ \scrn_menu_insert\v!bottom
+ %\csname\??tk\v!bottom\c!after\endcsname
+ \kern\zeropoint
+ \egroup
+ \vskip-\bottomheight}
+
+\appendtoks \scrn_menu_insert_content\scrn_menu_leftedge \to \leftedgetextcontent
+\appendtoks \scrn_menu_insert_content\scrn_menu_rightedge \to \rightedgetextcontent
+\appendtoks \scrn_menu_insert_content\scrn_menu_top \to \toptextcontent
+\appendtoks \scrn_menu_insert_content\scrn_menu_bottom \to \bottomtextcontent
+
+%D Initialization (root definitions, main builders):
+
+\defineinteractionmenu [\v!vertical] [\c!alternative=\v!vertical]
+\defineinteractionmenu [\v!horizontal] [\c!alternative=\v!horizontal]
+
+%D Initialization (parent definitions, 4 area builders):
+
+\defineinteractionmenu [\v!right ] [\v!right ] [\v!vertical ]
+\defineinteractionmenu [\v!left ] [\v!left ] [\v!vertical ]
+\defineinteractionmenu [\v!top ] [\v!top ] [\v!horizontal]
+\defineinteractionmenu [\v!bottom] [\v!bottom] [\v!horizontal]
+
+\setupinteraction
+ [\c!menu=\v!off]
+
+\setupinteractionmenu
+ [\c!offset=.25em,
+ \c!position=\v!no,
+ \c!frame=\v!on,
+ \c!maxwidth=\hsize,
+ \c!maxheight=\vsize,
+ \c!background=,
+ \c!backgroundcolor=,
+ \c!foregroundstyle=\interactionmenuparameter\c!style,
+ \c!foregroundcolor=\interactionmenuparameter\c!color,
+ \c!style=\interactionparameter\c!style,
+ \c!color=\interactionparameter\c!color,
+ \c!contrastcolor=\interactionparameter\c!contrastcolor,
+ \c!state=\v!start,
+ \c!samepage=\v!yes,
+ \c!unknownreference=\v!empty,
+ \c!distance=\bodyfontsize,
+ \c!topoffset=\zeropoint,
+ \c!bottomoffset=\zeropoint,
+ \c!leftoffset=\zeropoint,
+ \c!rightoffset=\zeropoint]
+
+\setupinteractionmenu
+ [\v!vertical] % not really a menu
+ [\c!inbetween=\blank,
+ \c!before=,
+ \c!after=\vfil,
+ %\c!width=\v!fit,
+ \c!height=\v!broad]
+
+\setupinteractionmenu
+ [\v!horizontal] % not really a menu
+ [\c!middle=\hfil,
+ %\c!left=\hss,
+ %\c!right=\hss,
+ \c!width=\v!fit,
+ \c!height=\v!broad]
+
+\setupinteractionmenu
+ [\v!left]
+ [\c!itemalign=\v!flushright,
+ \c!maxwidth=\leftedgewidth,
+ \c!maxheight=\makeupheight]
+
+\setupinteractionmenu
+ [\v!right]
+ [\c!itemalign=\v!flushleft,
+ \c!maxwidth=\rightedgewidth,
+ \c!maxheight=\makeupheight]
+
+\setupinteractionmenu
+ [\v!top]
+ [\c!itemalign=\v!high,
+ \c!maxwidth=\makeupwidth,
+ \c!maxheight=\topheight]
+
+\setupinteractionmenu
+ [\v!bottom]
+ [\c!itemalign=\v!low,
+ \c!maxwidth=\makeupwidth,
+ \c!maxheight=\bottomheight]
+
+%D Lists:
+
+\setvalue{\@@dodolistelement\v!left }{\def\dosomelistelement{\scrn_menu_list_element\v!left }}
+\setvalue{\@@dodolistelement\v!right }{\def\dosomelistelement{\scrn_menu_list_element\v!right }}
+\setvalue{\@@dodolistelement\v!top }{\def\dosomelistelement{\scrn_menu_list_element\v!top }}
+\setvalue{\@@dodolistelement\v!bottom}{\def\dosomelistelement{\scrn_menu_list_element\v!bottom}}
+
+\def\scrn_menu_list_element#1#2#3#4#5#6#7%
+ {\startbut[internal(#3)]
+ \limitatetext{#5}{\namedlistparameter{#2}\c!maxwidth}\unknown%
+ \stopbut}
+
+%D Sometimes handy:
+
+\unexpanded\def\menubutton % tag settings text action
+ {\dodoubleempty\scrn_menu_menu_button}
+
+\def\scrn_button_direct_status
+ {\doifelse{\buttonparameter\c!state}\v!start
+ {\dosingleempty\scrn_button_direct_indeed}%
+ {\dosingleempty\scrn_button_direct_ignore}}
+
+\def\scrn_menu_menu_button
+ {\iflocation
+ \expandafter\scrn_menu_menu_button_indeed
+ \else
+ \expandafter\scrn_menu_menu_button_ignore
+ \fi}
+
+\def\scrn_menu_menu_button_indeed[#menutag][#settings]#text[#action]%
+ {\ifsecondargument
+ \scrn_menu_menu_button_a
+ {#menutag}{#settings}{#text}{#action}%
+ \else
+ \doifassignmentelse{#menutag}\scrn_menu_menu_button_b\scrn_menu_menu_button_c{#menutag}{#text}{#action}%
+ \fi}
+
+\def\scrn_menu_menu_button_ignore[#menutag][#settings]#text[#action]%
+ {}
+
+\def\scrn_menu_menu_button_a#tag#settings#text#action%
+ {\doif{\interactionmenuparameter\c!state}\v!start
+ {\dontleavehmode \begingroup
+ \setupinteractionmenu[#tag][#settings]%
+ \scrn_button_make\??am{#tag}\menuparameter{#text}{#action}%
+ \endgroup}}
+
+\def\scrn_menu_menu_button_b#settings#text#action%
+ {\doif{\buttonparameter\c!state}\v!start
+ {\dontleavehmode \begingroup
+ \setupbuttons[#settings]%
+ \scrn_button_make\??bt\empty\buttonparameter{#text}{#action}%
+ \endgroup}}
+
+\def\scrn_menu_menu_button_c#tag#text#action%
+ {\doif{\interactionmenuparameter\c!state}\v!start
+ {\dontleavehmode \begingroup
+ \scrn_button_make\??am{#tag}\menuparameter{#text}{#action}%
+ \endgroup}}
+
+%D Untested:
+
+\unexpanded\def\registermenubuttons
+ {\dodoubleempty\scrn_menu_register_menu_buttons}
+
+\def\scrn_menu_register_menu_buttons[#menu][#register]%
+ {\ifsecondargument
+ \ctxcommand{registerbuttons("menu","#register","\currentlanguage")}
+ \else
+ \ctxcommand{registerbuttons("","#menu","\currentlanguage")}
+ \fi}
+
+\protect \endinput
diff --git a/tex/context/base/scrn-fld.lua b/tex/context/base/scrn-fld.lua
new file mode 100644
index 000000000..439de13b3
--- /dev/null
+++ b/tex/context/base/scrn-fld.lua
@@ -0,0 +1,76 @@
+if not modules then modules = { } end modules ['scrn-fld'] = {
+ version = 1.001,
+ comment = "companion to scrn-fld.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- we should move some code from lpdf-fld to here
+
+local fields = { }
+interactions.fields = fields
+
+local codeinjections = backends.codeinjections
+local nodeinjections = backends.nodeinjections
+
+local function define(specification)
+ codeinjections.definefield(specification)
+end
+
+local function defineset(name,set)
+ codeinjections.definefield(name,set)
+end
+
+local function clone(specification)
+ codeinjections.clonefield(specification)
+end
+
+local function insert(name,specification)
+ return nodeinjections.typesetfield(name,specification)
+end
+
+fields.define = define
+fields.defineset = defineset
+fields.clone = clone
+fields.insert = insert
+
+commands.definefield = define
+commands.definefieldset = defineset
+commands.clonefield = clone
+
+function commands.insertfield(name,specification)
+ tex.box["scrn_field_box_body"] = insert(name,specification)
+end
+
+-- (for the monent) only tex interface
+
+function commands.getfieldcategory(name)
+ local g = codeinjections.getfieldcategory(name)
+ if g then
+ context(g)
+ end
+end
+
+function commands.getdefaultfieldvalue(name)
+ local d = codeinjections.getdefaultfieldvalue(name)
+ if d then
+ context(d)
+ end
+end
+
+function commands.setformsmethod(method)
+ codeinjections.setformsmethod(method)
+end
+
+function commands.doiffieldcategoryelse(name)
+ commands.testcase(codeinjections.validfieldcategory(name))
+end
+
+function commands.doiffieldsetelse(tag)
+ commands.testcase(codeinjections.validfieldset(name))
+end
+
+function commands.doiffieldelse(name)
+ commands.testcase(codeinjections.validfield(name))
+end
diff --git a/tex/context/base/scrn-fld.mkiv b/tex/context/base/scrn-fld.mkiv
deleted file mode 100644
index 7fc88a39f..000000000
--- a/tex/context/base/scrn-fld.mkiv
+++ /dev/null
@@ -1,687 +0,0 @@
-%D \module
-%D [ file=scrn-fld,
-%D version=1997.05.18,
-%D title=\CONTEXT\ Screen Macros,
-%D subtitle=Fields,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%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 Screen Macros / Fields}
-
-\unprotect
-
-%D First we hook fields into the (viewer based) layering mechanism
-%D (implemented as properties).
-
-\appendtoks
- \doif\@@iafieldlayer\v!auto{\def\@@iafieldlayer{\currentviewerlayer}}%
-\to \everysetupinteraction
-
-\setupinteraction
- [\c!fieldlayer=\v!auto] % auto by default
-
-%D \starttyping
-%D \definefield [name] [type] [group] [values] [default]
-%D
-%D \definefield [WWWW] [text] [textsetup] [default text]
-%D \definefield [XXXX] [push] [pushsetup] [yes,no] [yes]
-%D \definefield [XXXX] [check] [checksetup] [yes,no] [yes]
-%D \definefield [YYYY] [combo] [combosetup] [a,b,c,d] [b]
-%D \definefield [ZZZZ] [radio] [radiosetup] [W,X,Y,Z] [Y]
-%D
-%D \definesubfield [W] [subsetup] [p,q]
-%D \definesubfield [X,Y] [subsetup] [p,r]
-%D \definesubfield [Z] [subsetup] [y,z]
-%D
-%D evt \definemainfield ... wanneer geplaatst voor subs gegeven
-%D
-%D \clonefield [XXXX] [XX,YY] [mysetup] [on,off]
-%D \clonefield [Z] [AA,BB] [somesetup] [true,false]
-%D \clonefield [Z] [CC,DD] [anothersetup]
-%D
-%D \copyfield [XXXX] [PP,QQ,RR]
-%D
-%D \field[XXXX]
-%D \fitfield[XXXX]
-%D \stoptyping
-
-%D Internal command, linked to \type{\definesymbol}.
-
-\def\dogetfieldsymbol#1%
- {\getobject{SYM}{#1}}
-
-\def\dopresetfieldsymbol#1%
- {\doifobjectfoundelse{SYM}{#1}
- {}
- {\settightobject{SYM}{#1}\hbox{\symbol[#1]}%
- \flushatshipout
- {\setbox0\hbox{\hskip-\maxdimen\getobject{SYM}{#1}}%
- \smashbox0\box0}}}
-
-\def\presetfieldsymbols[#1]% slow
- {\def\dopresetfieldsymbols##1{\processcommalist[##1]\dopresetfieldsymbol}%
- \@EA\processcommalist\@EA[#1]\dopresetfieldsymbols}
-
-\unexpanded\def\definedefaultsymbols
- {\definesymbol[defaultyes][\mathematics{\times}]%
- \definesymbol[defaultno ][\mathematics{\cdot }]}
-
-\def\resetfieldsymbol[#1]% for experimental usage only
- {\resetobject{SYM}{#1}}
-
-%D The interface to the specials. DEFAULT NOG ANDERS
-
-\def\typesetfield
- {\bgroup
- \dosetfontattribute\??fd\c!style
- \ctxlua{backends.codeinjections.typesetfield("\currentfieldname", {
- title = "\currentfieldname",
- width = \number\dimexpr\@@fdwidth\relax,
- height = \number\dimexpr\@@fdheight\relax,
- align = "\@@fdalign",
- length = tonumber("\@@fdn") or 0,
- style = "\@@fdstyle",
- fontstyle = "\fontstyle",
- fontalternative = "\fontalternative",
- fontsize = "\fontbody",
- color = "\@@fdcolor",
- colorvalue = \thecolorattribute\@@fdcolor,
- backgroundcolor = "\@@fdfieldbackgroundcolor",
- framecolor = "\@@fdfieldframecolor",
- layer = "\@@fdfieldlayer",
- options = "\@@fdoption",
- align = "\@@fdalign",
- clickin = "\@@fdclickin",
- clickout = "\@@fdclickout",
- regionin = "\@@fdregionin",
- regionout = "\@@fdregionout",
- afterkey = "\@@fdafterkey",
- format = "\@@fdformat",
- validate = "\@@fdvalidate",
- calculate = "\@@fdcalculate",
- focusin = "\@@fdfocusin",
- focusout = "\@@fdfocusout",
- }) }%
- \egroup}
-
-\unexpanded\def\definefieldset {\dodoubleargument\dodefinefieldset}
-\unexpanded\def\definefield {\doquintupleempty\dodefinefield}
-\unexpanded\def\definemainfield{\doquintupleempty\dodefinefield} % redundant
-\unexpanded\def\definesubfield {\dotripleempty \dodefinesubfield}
-\unexpanded\def\clonefield {\doquadrupleempty\doclonefield}
-\unexpanded\def\copyfield {\dodoubleempty \docopyfield}
-\unexpanded\def\field {\dodoubleempty \donormalfield}
-\unexpanded\def\fitfield {\dodoubleempty \dofitfield}
-\unexpanded\def\setupfield {\doquintupleempty\dosetupfield}
-\unexpanded\def\setupfields {\doquadrupleempty\dosetupfields}
-
-% misc
-
-% \appendtoks\ctxlua{backends.codeinjections.finishfields()}\to\everylastshipout
-
-% testing
-
-\def\doiffieldelse #1{\ctxlua{backends.codeinjections.doiffieldelse("#1")}}
-\def\doiffieldgroupelse#1{\ctxlua{backends.codeinjections.doiffieldgroupelse("#1")}}
-
-% definition
-
-\def\dodefinefield[#1][#2][#3][#4][#5]% [name] [kind] [group] [values] [default] | [name] [kind] [group] [default]
- {\ctxlua{backends.codeinjections.definefield{ variant="normal", name="#1", kind="#2", group="#3", values=\!!bs#4\!!es, default=\!!bs#5\!!es }}}
-
-\def\dodefinesubfield[#1][#2][#3]% [name] [group] [values]
- {\ctxlua{backends.codeinjections.definefield{ variant="normal", name="#1", kind="sub", group="#2", values=\!!bs#3\!!es }}}
-
-\def\doclonefield[#1][#2][#3][#4]% [parent] [children] [group] [values]
- {\ctxlua{backends.codeinjections.clonefield{ variant="clone", parent="#1", children="#2", group="#3", values=\!!bs#4\!!es }}}
-
-\def\docopyfield[#1][#2]% [parent] [children]
- {\ctxlua{backends.codeinjections.clonefield{ variant="copy", parent="#1", children="#2" }}}
-
-\def\dodefinefieldset[#1][#2]%
- {\ctxlua{backends.codeinjections.definefieldset("#1","#2")}}
-
-% usage
-%
-% \iftrialtypesetting
-%
-% just a default setup
-
-\def\loadfieldscripts{\useJSscripts[fld]\globallet\loadfieldscripts\relax}
-
-\def\donormalfield{\doprocessfield\dohandlefield}
-\def\dofitfield {\doprocessfield\dohandlefitfield}
-
-\def\dosetupfieldindeed#1#2[#3]% [#4][#5][#6][#7]%
- {#1[#2]} % [#4][#5][#6][#7]}
-
-\def\doprocessfield#1[#2][#3]% \method [name] [label]
- {\dontleavehmode
- \begingroup
- \loadfieldscripts
- \edef\currentfieldname {#2}%
- \edef\currentfieldlabel{#3}%
- \edef\currentfieldgroup{\ctxlua{backends.codeinjections.getfieldgroup("#2")}}%
- \ifx\currentfieldlabel\empty
- \let\currentfieldlabel\currentfieldname
- \fi
- \ifx\currentfieldgroup\empty
- #1[#2][\v!label,\v!frame,\v!horizontal][][][]%
- \else
- \def\dosetupfield{\dosetupfieldindeed{#1}{#2}}%
- \getvalue{\??fd::\currentfieldgroup}%
- \fi
- \endgroup}
-
-% setups
-
-\def\dosetupfield[#1][#2][#3][#4][#5]%
- {\iffifthargument
- \def\docommand##1{\dodosetupfield[##1][#2][#3][#4][#5]}%
- \processcommalist[#1]\docommand
- \else\ifthirdargument
- \def\docommand##1{\dodosetupfield[##1][#2][][][#3]}%
- \processcommalist[#1]\docommand
- \else\ifsecondargument
- \doifelse{#2}\v!reset
- {\def\docommand##1{\donosetupfield[#1][][][][]}}
- {\def\docommand##1{\dodosetupfield[##1][][][][#2]}}%
- \processcommalist[#1]\docommand
- \else\iffirstargument
- \def\docommand##1{\dodosetupfield[##1][][][][]}%
- \processcommalist[#1]\docommand
- \else
- \writestatus\m!fields{provide either 1, 2, 3 or 5 arguments}%
- \fi\fi\fi\fi}
-
-\def\normaldodosetupfield[#1][#2][#3][#4][#5]%
- {\ifcsname\??fd::#1\endcsname
- \pushmacro\dosetupfield
- \def\dosetupfield[##1][##2][##3][##4][##5]{\setvalue{\??fd::#1}{\dosetupfield[#1][##2,#2][##3,#3][##4,#4][##5,#5]}}%
- \getvalue{\??fd::#1}%
- \popmacro\dosetupfield
- \else
- \setvalue{\??fd::#1}{\dosetupfield[#1][#2][#3][#4][#5]}%
- \fi}
-
-\let\dodosetupfield\normaldodosetupfield
-
-\def\donosetupfield[#1][#2][#3][#4][#5]%
- {\setvalue{\??fd::#1}{\dosetupfield[#1][#2][#3][#4][#5]}}
-
-\def\dosetupfields[#1][#2][#3][#4]%
- {\ifsecondargument
- \def\dodosetupfield[##1][##2][##3][##4][##5]%
- {\ifcsname\??fd::##1\endcsname
- \def\dosetupfield[####1][####2][####3][####4][####5]%
- {\setvalue{\??fd::##1}{\dosetupfield[##1][#1,####2,##2][#2,####3,##3][#3,####4,##4][#4,####5,##5]}}%
- \getvalue{\??fd::##1}%
- \else
- \setvalue{\??fd::##1}{\dosetupfield[##1][#1,##2][#2,##3][#3,##4][#4,##5]}%
- \fi}%
- \else\iffirstargument
- \doifelse{#1}\v!reset
- {\resetfields}
- {\setupfields[][][][#1]}% checken
- \else
- \writestatus\m!fields{provide either 1 or 4 arguments}%
- \fi\fi}
-
-\def\resetfields
- {\let\dodosetupfield\normaldodosetupfield}
-
-% \setupfields[\v!reset]
-
-% opties: veld, label, kader, vertikaal/horizontaal
-
-\newif\ifShowFieldLabel
-\newif\ifShowFieldFrame
-\newif\ifVerticalField
-\newif\ifHorizontalField
-
-% way to slow/complicated, we need some simple alternative
-% as well
-
-\def\dohandlefield[#1][#2][#3][#4][#5]%
- {\presetlocalframed[\??fd]%
- \processallactionsinset
- [#2]
- [ \v!reset=>\ShowFieldLabelfalse\ShowFieldFramefalse\HorizontalFieldfalse\VerticalFieldfalse,
- \v!label=>\ShowFieldLabeltrue,
- \v!frame=>\ShowFieldFrametrue,
- \v!horizontal=>\HorizontalFieldtrue,
- \v!vertical=>\VerticalFieldtrue]%
- \ifVerticalField
- \getparameters[\??fd][\c!distance=\zeropoint,\c!inbetween=\vskip\@@localoffset,\c!align=\v!right,\c!width=20em]%
- \else\ifHorizontalField
- \getparameters[\??fd][\c!distance=\@@localoffset,\c!inbetween=,\c!align=\c!left,\c!height=10ex]%
- \else
- \getparameters[\??fd][\c!distance=\zeropoint,\c!inbetween=,\c!align=\c!left]%
- \fi\fi
- \getparameters[\??fd][\c!n=,\c!before=,\c!after=\vss,\c!style=,\c!color=,#3]%
- \ifShowFieldFrame
- \localframed[\??fd][\c!strut=\v!no,\c!align=]\bgroup
- \else
- \vbox\bgroup
- \fi
- \dontcomplain
- \ifShowFieldLabel
- \setbox0\hbox
- {\reshapeframeboxtrue % else wrong dimensions
- \framed
- [\c!style=,\c!color=,\c!align=\c!right,#4]
- {\currentfieldlabel}}%
- \fi
- \setbox2\hbox
- {\reshapeframeboxtrue % else wrong dimensions
- \ifVerticalField
- \setupframed[\c!height=6ex,\c!width=\hsize]%
- \else\ifHorizontalField
- \setupframed[\c!height=\vsize,\c!width=20em]%
- \else
- \setupframed[\c!height=2cm,\c!width=2cm]%
- \fi\fi
- \framed
- [\c!align=\v!right,\c!strut=\v!no,#5]
- {\getparameters
- [\??fd]
- [\c!color=,\c!style=,\c!align=\v!right,\c!option=,
- \c!clickin=,\c!clickout=,\c!regionin=,\c!regionout=,
- \c!afterkey=,\c!format=,\c!validate=,\c!calculate=,
- \c!focusin=,\c!focusout=,
- \c!fieldoffset=-\framedoffset,\c!fieldbackgroundcolor=,
- \c!fieldframecolor=,\c!fieldlayer=\@@iafieldlayer,#5]%
- \scratchdimen\framedwidth \edef\@@fdwidth {\the\scratchdimen}%
- \scratchdimen\framedheight\edef\@@fdheight{\the\scratchdimen}%
- \vfill
- \hbox{\lower\@@fdfieldoffset\hbox{\typesetfield}}
- \vss}}%
- \ifShowFieldLabel
- \ifVerticalField
- \vbox
- {\copy0
- \@@fdinbetween
- \copy2}%
- \else
- \hbox
- {\vbox \ifdim\ht2>\ht0 to \ht2 \fi
- {\@@fdbefore
- \copy0
- \@@fdafter}%
- \hskip\@@fddistance
- \vbox \ifdim\ht0>\ht2 to \ht0 \fi
- {\@@fdbefore
- \box2
- \@@fdafter}}%
- \fi
- \else
- \box2
- \fi
- \egroup}
-
-\setnewconstant\fitfieldmode\plusone % 3 = best
-
-\def\dohandlefitfield[#1][#2][#3][#4][#5]% alleen check
- {\presetlocalframed[\??fd]%
- \localframed
- [\??fd]
- [\c!n=1024, % beware: weblink plug in truncates
- \c!strut=\v!no,\c!color=,\c!style=,\c!option=,
- \c!clickin=,\c!clickout=,\c!regionin=,\c!regionout=,
- \c!focusin=,\c!focusout=,
- \c!afterkey=,\c!format=,\c!validate=,\c!calculate=,
- \c!fieldoffset=\zeropoint,\c!fieldbackgroundcolor=,
- \c!fieldframecolor=,\c!fieldlayer=\@@iafieldlayer,#5,\c!align=]
- {\edef\defaultfield{\ctxlua{backends.codeinjections.getdefaultfieldvalue("#1")}}%
- % \dopresetsymbol\defaultfield
- \setbox\scratchbox\hbox{\symbol[\defaultfield]}%
- \edef\@@fdwidth {\the\wd\scratchbox}%
- \ifcase\fitfieldmode
- \edef\@@fdheight{\the\ht\scratchbox}%
- \typesetfield
- \or % 1 = ignore depth (original, assumed no depth, actually a bug)
- \edef\@@fdheight{\the\ht\scratchbox}%
- \vbox to \ht\scratchbox{\vfill\hbox to \wd\scratchbox{\typesetfield\hfill}\vss}%
- \or % 2 = add depth to height, but no depth in result
- \edef\@@fdheight{\the\htdp\scratchbox}%
- \vbox to \ht\scratchbox{\vfill\hbox to \wd\scratchbox{\typesetfield\hfill}\vss}%
- \or % 3 = add depth to height, and apply depth to result
- \edef\@@fdheight{\the\htdp\scratchbox}%
- \hbox to \wd\scratchbox{\lower\dp\scratchbox\hbox{\typesetfield}\hfill}%
- \fi}}
-
-%D Common stuff
-
-\newcount\nofsystemfields
-
-\def\nextsystemfield
- {\global\advance\nofsystemfields\plusone
- \def\currentsystemfield{sys::\number\nofsystemfields}}
-
-%D An example:
-
-\def\fillinfield
- {\dosingleempty\dofillinfield}
-
-\def\dofillinfield[#1]#2%
- {\dontleavehmode
- \hbox
- {\forgetall
- \setupfields[\v!reset]%
- \nextsystemfield
- \useJSscripts[ans]%
- \doifelsenothing{#1}
- {\def\therightanswer{#2}}
- {\def\therightanswer{#1}}%
- \setbox0\hbox{#2}%
- \setbox2\hbox{\therightanswer}%
- \dimen0=\ifdim\wd0>\wd2 \wd0 \else \wd2 \fi
- \advance\dimen0 .2em
- \definefield
- [\currentsystemfield][line][systemfield]%
- \setupfield
- [systemfield]
- [\c!n=1024, % beware: weblink plugin truncates
- \c!location=\v!low,\c!strut=\v!yes,\c!fieldoffset=\zeropoint,
- \c!height=1.2\openlineheight,\c!width=\dimen0,\c!offset=\v!overlay,
- \c!style=,\c!align=\v!middle,\c!frame=\v!off,
- \c!color=red,\c!fieldbackgroundcolor=\s!white,\c!fieldframecolor=blue,
- \c!validate=JS(Check_Answer{\currentsystemfield,\therightanswer})]%
- \switchtobodyfont
- [\c!small]%
- \hbox to \wd0
- {\copy0\hskip-\wd0\hss\field[\currentsystemfield]\hss}}}
-
-%D and another one:
-
-\def\tooltip
- {\dosingleempty\dotooltip}
-
-\def\dotooltip[#1]#2#3%
- {\dontleavehmode
- \begingroup
- \setupfields[\v!reset]%
- \useJSscripts[fld]%
- \setbox0\hbox
- {\dontcomplain
- \nextsystemfield
- \setbox0\hbox{#2}%
- \definesymbol
- [\currentsystemfield:txt]
- [{\inframed[\c!frame=\v!off,\c!background=\v!screen]{#3}}]%
- \setbox2\hbox{\symbol[\currentsystemfield:txt]}%
- \definefield
- [\currentsystemfield:txt][check]
- [dummy][\currentsystemfield:txt][\currentsystemfield:txt]%
- \setupfield
- [dummy]
- [\c!frame=\v!off,
- \c!regionout=JS(Hide_Field{\currentsystemfield:txt}),
- \c!option=\v!hidden]%
- \hbox to \zeropoint
- {\dimen0\wd2\advance\dimen0 -\wd0
- \doifelse{#1}\v!left
- {\hskip-\dimen0}
- {\doif{#1}\v!middle
- {\hskip-.5\dimen0}}%
- \lower\openlineheight\hbox to \zeropoint
- {\fitfield[\currentsystemfield:txt]}}%
- \dimen0=\ifdim\wd0=\zeropoint 3em\else\wd0\fi
- \definesymbol
- [\currentsystemfield:but]
- [{\framed[\c!height=2ex,\c!width=\dimen0,\c!frame=\v!off]{}}]%
- \definefield
- [\currentsystemfield:but][push]
- [dummy][\currentsystemfield:but][\currentsystemfield:but]%
- \setupfield
- [dummy]
- [\c!frame=\v!off,
- \c!option=,
- \c!regionin=JS(Vide_Field{\currentsystemfield:txt}),
- \c!regionout=JS(Hide_Field{\currentsystemfield:txt}),
- \c!fieldlayer=\@@iafieldlayer]%
- \lower2ex\hbox to \zeropoint
- {\fitfield[\currentsystemfield:but]}%
- #2}%
- \ht0\strutht\dp0\strutdp\box0
- \endgroup}
-
-%D And one more:
-
-\unexpanded\def\definefieldstack
- {\dotripleargument\dodefinefieldstack}
-
-\def\dodefinefieldstack[#1][#2][#3]% name, symbols, settings
- {\ifcsname fieldstack:#1\endcsname \else
- \setgvalue{fieldstack:#1}{\dodofieldstack[#1][#2][#3]}%
- \fi}
-
-\def\fieldstack
- {\dotripleempty\dofieldstack}
-
-\def\dofieldstack[#1][#2][#3]%
- {\ifsecondargument
- \dodefinefieldstack[#1][#2][#3]\fieldstack[#1]%
- \else
- \getvalue {fieldstack:#1}%
- \setgvalue{fieldstack:#1}{[#1]}%
- \fi}
-
-\def\dodofieldstack[#1][#2][#3]% start=n, 0 == leeg
- {\dontleavehmode
- \begingroup
- \getparameters[\??fd][\c!start=1,#3]%
- \setupfields[\v!reset]%
- % \definesymbol[\v!empty][]%
- \useJSscripts[fld][FieldStack]%
- \newcounter\stackedfieldnumber
- \def\dododofieldstack##1%
- {\increment\stackedfieldnumber
- \ifnum\stackedfieldnumber=\@@fdstart\relax
- \definefield[#1:\stackedfieldnumber][check][#1][##1,\empty][##1]% \v!empty fails
- \else
- \definefield[#1:\stackedfieldnumber][check][#1][##1,\empty][\empty]% \v!empty fails
- \fi}%
- \processcommalist[#2]\dododofieldstack
- \setupfield[#1][\v!reset]% added
- \setupfield[#1][\c!option=\v!readonly,#3]% #3 swapped
- \newcounter\stackedfieldnumber
- \def\dododofieldstack##1%
- {\doglobal\increment\stackedfieldnumber
- \fitfield[#1:\stackedfieldnumber]\egroup\bgroup}%
- \startoverlay
- \bgroup
- \globalprocesscommalist[#2]\dododofieldstack
- \egroup
- \stopoverlay
- \endgroup}
-
-%D When submitting a form, we need to tell the driver module
-%D that we want \FDF\ or \HTML.
-
-\newtoks\everysetupforms
-
-\unexpanded\def\setupforms{\dosingleempty\dosetupforms}
-
-\def\dosetupforms[#1]
- {\getparameters[\??fr][#1]%
- \the\everysetupforms}
-
-\appendtoks
- \ctxlua{backends.codeinjections.setformsmethod("@@frmethod")}%
-\to \everysetupforms
-
-\setupforms
- [\c!method=XML] % no need for everyjob initialization as this is the default
-
-%D Goodie: (unchecked in \MKIV)
-
-\unexpanded\def\definepushbutton % name optional setup
- {\dodoubleempty\dodefinepushbutton}
-
-\def\dodefinepushbutton[#1][#2]% name setup
- {\dododefinepushbutton{#1}{n}{push}%
- \dododefinepushbutton{#1}{r}{\symbol[psym:#1:n]}%
- \dododefinepushbutton{#1}{d}{\symbol[psym:#1:r]}%
- \setvalue{pushbutton:#1}{\dohandlepushbutton{#1}{#2}}}
-
-\def\dododefinepushbutton#1#2#3%
- {\doifsymboldefinedelse{psym:#1:#2}%
- \donothing{\definesymbol[psym:#1:#2][{#3}]}}
-
-\unexpanded\def\definepushsymbol
- {\dotripleargument\dodefinepushsymbol}
-
-\def\dodefinepushsymbol[#1][#2]% [#3]
- {\definesymbol[psym:#1:#2]}
-
-\def\dopushbutton[#1][#2]%
- {\executeifdefined{pushbutton:#1}\gobbleoneargument{#2}}
-
-\def\pushbutton
- {\dodoubleargument\dopushbutton}
-
-\def\dohandlepushbutton#1#2#3% identifier setup script
- {\bgroup
- \nextsystemfield
- \setupfield
- [pushbutton]
- [\c!frame=\v!overlay,
- \c!offset=\v!overlay,
- \c!clickout=#3,#2]%
- \definefield
- [\currentsystemfield]
- [push]
- [pushbutton]
- [psym:#1:n,psym:#1:r,psym:#1:d]%
- \fitfield
- [\currentsystemfield]%
- \egroup}
-
-% \def\menu@psh
-% {\dodoubleargument\domenu@psh}
-%
-% \def\domenu@psh[#1][#2]#3\\%
-% {\txt\pushbutton[#1][#2]\\}%
-%
-%\appendtoks \let\psh\do@@ampsh \to \everysetmenucommands
-
-\unexpanded\def\menu@psh{\txt\pushbutton}
-
-\appendtoks \let\psh\menu@psh \to \everysetmenucommands
-
-% \definepushbutton [reset]
-%
-% \definepushsymbol [reset] [n] [\uniqueMPgraphic{whatever}{color=green}]
-% \definepushsymbol [reset] [r] [\uniqueMPgraphic{whatever}{color=white}]
-%
-% \startinteractionmenu[bottom]
-% \psh [reset] [JS(reset_something)] \\
-% \stopinteractionmenu
-
-%D Another goodie: (unchecked in \MKIV)
-
-% \definecolor[rollover:n][red]
-% \definecolor[rollover:r][green]
-% \definecolor[rollover:d][blue]
-
-\definepalet
- [rollover]
- [n=red,
- r=green,
- d=blue]
-
-\newcounter\nofrollovers
-\newcounter\nofrollbuttons
-
-\def\dorollbutton[#1][#2]#3[#4]%
- {\dontleavehmode
- \bgroup
- \doglobal\increment\nofrollovers
- \doglobal\increment\nofrollbuttons
- \unexpanded\def\dosetlocationbox[##1]##2[##3]%
- {\getparameters[##1][##3]%
- \definecolor[rollover][rollover:##2]%
- \doifelse{##2}{n}{\doifelsevalue{##1\c!alternative}\v!hidden\phantom\hbox}\hbox
- {\localframed[##1]
- [\c!framecolor=rollover,\c!backgroundcolor=rollover,\c!color=rollover]%
- {\dolocationattributes{##1}\c!style\c!color{#3}}}}%
- \iffirstargument
- \ifsecondargument
- \def\setlocationbox##1{\dosetlocationbox[\??am#1]{##1}[#2]}%
- \else
- \doifassignmentelse{#1}
- {\def\setlocationbox##1{\dosetlocationbox[\??bt]{##1}[#1]}}
- {\def\setlocationbox##1{\dosetlocationbox[\??am#1]{##1}[]}}%
- \fi
- \else
- \def\setlocationbox##1{\dosetlocationbox[\??bt]{##1}[]}%
- \fi
- % todo: share symbols, tricky since different dimensions
- \definesymbol[rsym:\nofrollovers:n][\setlocationbox n]%
- \definesymbol[rsym:\nofrollovers:r][\setlocationbox r]%
- \definesymbol[rsym:\nofrollovers:d][\setlocationbox d]%
- \setupfield
- [rollbutton]
- [\c!frame=\v!off,
- \c!offset=\v!overlay,
- \c!clickout={#4}]%
- \definefield
- [roll:\nofrollbuttons][push][rollbutton]
- [rsym:\nofrollovers:n,%
- rsym:\nofrollovers:r,%
- rsym:\nofrollovers:d]%
- \fitfield[roll:\nofrollbuttons]%
- \egroup}
-
-\unexpanded\def\rollbutton
- {\dodoubleempty\dorollbutton}
-
-\def\menu@rob[#1]#2\\%
- {\txt\rollbutton[\currentmenu]{\ignorespaces#2\unskip}[#1]\\}%
-
-\appendtoks \let\rob\menu@rob \to \everysetmenucommands
-
-% calls:
-% {..} [JS..]
-% [left] {..} [JS..]
-% [a=b] {..} [JS..]
-% [left] [a=b] {..} [JS..]
-%
-% \setupbuttons[offset=0pt,frame=off] % alternative=hidden
-%
-% \rollbutton {Manuals} [JS(Goto_File{show-man.pdf})]
-% \rollbutton {Articles} [JS(Goto_File{show-art.pdf})]
-% \rollbutton {Papers} [JS(Goto_File{show-pap.pdf})]
-% \rollbutton {Presentations} [JS(Goto_File{show-pre.pdf})]
-% \rollbutton {Resources} [JS(Goto_File{show-res.pdf})]
-%
-% \rob [JS(...)] bla bla \\
-
-\unexpanded\def\overlayrollbutton
- {\dodoubleargument\dooverlayrollbutton}
-
-\def\dooverlayrollbutton[#1][#2]%
- {\bgroup
- \nextsystemfield
- \setupfield
- [overlayrollbutton]
- [\c!frame=\v!off,\c!offset=\v!overlay,\c!regionin={#1},\c!regionout={#2}]%
- \definesymbol
- [\currentsystemfield]
- [{\framed[\c!frame=\v!off,\c!width=\overlaywidth,\c!height=\overlayheight]{}}]%
- \definefield
- [\currentsystemfield][push][overlayrollbutton][\currentsystemfield][\currentsystemfield]%
- \fitfield[\currentsystemfield]%
- \egroup}
-
-% \defineoverlay
-% [ShowMenu]
-% [{\overlayrollbutton[VideLayer{navigation}][HideLayer{navigation}]}]
-
-\protect \endinput
diff --git a/tex/context/base/scrn-fld.mkvi b/tex/context/base/scrn-fld.mkvi
new file mode 100644
index 000000000..ae2e5541f
--- /dev/null
+++ b/tex/context/base/scrn-fld.mkvi
@@ -0,0 +1,965 @@
+%D \module
+%D [ file=scrn-fld,
+%D version=1997.05.18,
+%D title=\CONTEXT\ Screen Macros,
+%D subtitle=Fields,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% There is still some leftover code from mkii, where we need to
+% be sparse with hash entries and so have a somewhat complex
+% setup mechanism.
+
+% interaction checking
+
+\writestatus{loading}{ConTeXt Screen Macros / Fields}
+
+\unprotect
+
+\registerctxluafile{scrn-fld}{1.001}
+
+%D In \MKII\ we had to cheat a bit with setups in order not to run
+%D out of memory with thousands of fields, which we happen to need at
+%D that time. In \MKIV\ we can store some data at the \LUA\ end and
+%D use a somewhat slower but quite okay inheritance mechanism. For
+%D this reason we now have split definitions, although the old method
+%D is still somewhat supported. The clone and copy commands are
+%D somewhat obsolete for several reasons: we can now use inheritance
+%D and autocloning has been supported for a while. In most cases
+%D cloning (especially with check boxes) the acrobat browser is not
+%D stable enough with respect to appearance handling.
+%D
+%D A fieldcategory is nothing more than a collection of settings.
+%D
+%D \starttyping
+%D \definefieldcategory
+%D [all-email]
+%D [height=1cm,
+%D width=14cm,
+%D style=sstf]
+%D \stoptyping
+%D
+%D A definition can refer to this category:
+%D
+%D \starttyping
+%D \definefieldbody [email] [type=line,category=all-email,default=pragma@wxs.nl]
+%D \stoptyping
+%D
+%D A copy of a field is made as follows:
+%D
+%D \starttyping
+%D \definefieldbody [xmail] [email]
+%D \stoptyping
+%D
+%D You can also be more specific:
+%D
+%D \starttyping
+%D \definefieldbody[buttona][type=check,values={one,two}]
+%D \definefieldbody[buttonb][type=check,values={three,four}]
+%D \definefieldbody[buttonc][buttona][values={three,four}]
+%D \stoptyping
+%D
+%D Actually typesetting a field happens this way:
+%D
+%D \starttyping
+%D \fieldbody [Email]
+%D \fieldbody [Email] [width=6cm]
+%D \fieldbody [eMAIL]
+%D \fieldbody [eMAIL] [width=7cm]
+%D
+%D \fieldbody [buttona]
+%D \fieldbody [buttona]
+%D \fieldbody [buttonb]
+%D \fieldbody [buttonb]
+%D \fieldbody [buttonc]
+%D \fieldbody [buttonc]
+%D \stoptyping
+%D
+%D So, you can call up a field many times and quite some parameters
+%D can be set.
+%D
+%D Because there are persistent problems with acrobat rendering
+%D associated appearance streams (some messy /MK interferende) we
+%D also support native (built-in dingbat) symbols: check, circle,
+%D cross, diamond, square and star.
+%D
+%D \starttyping
+%D \definefield[test1][check]
+%D \definefield[test2][check]
+%D
+%D \fieldbody[test1][width=1em,height=\strutht,depth=\strutdp,symbol=check]
+%D \fieldbody[test1][width=1em,height=\strutht,depth=\strutdp,symbol=circle]
+%D \fieldbody[test2][width=1em,height=\strutht,depth=\strutdp,symbol=square]
+%D \stoptyping
+%D
+%D When submitting a form, we need to tell the driver module
+%D that we want \FDF\ or \HTML.
+
+\newtoks\everysetupforms
+
+\unexpanded\def\setupforms
+ {\dosingleempty\scrn_forms_setup}
+
+\def\scrn_forms_setup[#settings]
+ {\getparameters[\??fr][#settings]%
+ \the\everysetupforms}
+
+\appendtoks
+ \ctxcommand{setformsmethod("@@frmethod")}%
+\to \everysetupforms
+
+\setupforms
+ [\c!method=XML] % no need for everyjob initialization as this is the default
+
+%D We need to initialize symbols in a special way so that they
+%D can be used as rendering for a widget.
+
+\unexpanded\def\presetfieldsymbols[#list]% slow
+ {\processcommacommand[#list]\scrn_symbols_preset}
+
+\def\scrn_symbols_preset#set%
+ {\processcommalist[#set]\scrn_symbols_preset_indeed}%
+
+\def\scrn_symbols_preset_indeed#tag%
+ {\doifobjectfoundelse{SYM}{#tag}
+ {}
+ {\settightobject{SYM}{#tag}\hbox{\symbol[#tag]}%
+ \flushatshipout
+ {\setbox0\hbox{\hskip-\maxdimen\getobject{SYM}{#tag}}%
+ \smashbox0\box0}}}
+
+\let\dosetfieldsymbol\scrn_symbols_preset_indeed
+
+\def\dogetfieldsymbol#tag%
+ {\getobject{SYM}{#tag}}
+
+\unexpanded\def\definedefaultsymbols % used ?
+ {\definesymbol[defaultyes][\mathematics{\times}]%
+ \definesymbol[defaultno ][\mathematics{\cdot }]}
+
+% \def\resetfieldsymbol[#tag]% for experimental usage only
+% {\resetobject{SYM}{#tag}}
+
+%D Now comes the real code:
+
+\installcommandhandler \??fd {fieldcategory} \??fd
+\installcommandhandler \??fb {fieldbody} \??fb
+
+\newbox\scrn_field_box_body
+
+\setupfieldcategory
+ [\c!alternative=\v!normal, % normal clone copy
+ \c!type=\v!line, % line text ...
+ \c!width=5em,
+ \c!height=1em,
+ \c!depth=\zeropoint,
+ \c!align=\v!flushleft,
+ \c!option=\v!printable, % maybe we need a globaloptions and marge them
+ \c!n=1024]
+
+\def\scrn_field_check_category
+ {\edef\currentfieldbodycategory{\fieldbodyparameter\c!category}%
+ \ifx\currentfieldbodycategory\empty
+ \setevalue{\??fb\currentfieldbody\s!parent}{\??fd}%
+ \else
+ \setevalue{\??fb\currentfieldbody\s!parent}{\??fd\currentfieldbodycategory}%
+ \fi}
+
+\appendtoks % we cannot use parent .. maybe s!parent has to change
+ \ifx\currentfieldbodyparent\empty
+ \scrn_field_check_category
+ \ctxcommand{definefield{
+ name = "\currentfieldbody",
+ alternative = "normal",
+ type = "\fieldbodyparameter\c!type",
+ category = "\fieldbodyparameter\c!category",
+ values = \!!bs\fieldbodyparameter\c!values\!!es,
+ default = \!!bs\fieldbodyparameter\c!default\!!es
+ }}%
+ \else
+ \ctxcommand{clonefield{
+ children = "\currentfieldbody",
+ alternative = "clone",
+ parent = "\currentfieldbodyparent",
+ category = "\fieldbodyparameter\c!category",
+ values = \!!bs\fieldbodyparameter\c!values\!!es,
+ default = \!!bs\fieldbodyparameter\c!default\!!es
+ }}%
+ \fi
+\to \everydefinefieldbody
+
+\unexpanded\def\fieldbody
+ {\dodoubleempty\scrn_field_body}
+
+\def\scrn_field_body[#tag][#settings]%
+ {\iflocation
+ \hbox\bgroup
+ \edef\currentfieldbody{#tag}%
+ \ifsecondargument
+ \setupfieldbody[#tag][#settings]%
+ \fi
+ \scrn_field_body_typeset
+ \box\scrn_field_box_body
+ \egroup
+ \fi}
+
+\def\scrn_field_body_typeset % todo: fieldsymbol (checkfields /MK mess)
+ {\edef\currentfieldframecolor{\fieldbodyparameter\c!fieldframecolor}%
+ \ifx\currentfieldframecolor\empty\else
+ \getcolorattributevalue\currentfieldframecolor\currentfieldframecolorvalue
+ \fi
+ \edef\currentfieldbackgroundcolor{\fieldbodyparameter\c!fieldbackgroundcolor}%
+ \ifx\currentfieldbackgroundcolor\empty\else
+ \getcolorattributevalue\currentfieldbackgroundcolor\currentfieldbackgroundcolorvalue
+ \fi
+ \dosetfieldbodyattributes\c!style\c!color
+ \ctxcommand{insertfield("\currentfieldbody", {
+ title = "\currentfieldbody",
+ width = \number\dimexpr\fieldbodyparameter\c!width \relax,
+ height = \number\dimexpr\fieldbodyparameter\c!height\relax,
+ depth = \number\dimexpr\fieldbodyparameter\c!depth \relax,
+ align = "\fieldbodyparameter\c!align",
+ length = "\fieldbodyparameter\c!n",
+ style = "\fieldbodyparameter\c!style",
+ fontstyle = "\fontstyle",
+ fontalternative = "\fontalternative",
+ fontsize = "\fontbody",
+ fontsymbol = "\fieldbodyparameter\c!symbol",
+ color = "\fieldbodyparameter\c!color",
+ colorvalue = \number\attribute\colorattribute,
+ \ifx\currentfieldbackgroundcolor\empty \else
+ backgroundcolor = "\currentfieldbackgroundcolor",
+ backgroundcolorvalue = "\currentfieldbackgroundcolorvalue",
+ \fi
+ \ifx\currentfieldframecolor\empty \else
+ framecolor = "\currentfieldframecolor",
+ framecolorvalue = "\currentfieldframecolorvalue",
+ \fi
+ layer = "\fieldbodyparameter\c!fieldlayer",
+ options = "\fieldbodyparameter\c!option",
+ align = "\fieldbodyparameter\c!align",
+ clickin = "\fieldbodyparameter\c!clickin",
+ clickout = "\fieldbodyparameter\c!clickout",
+ regionin = "\fieldbodyparameter\c!regionin",
+ regionout = "\fieldbodyparameter\c!regionout",
+ afterkey = "\fieldbodyparameter\c!afterkey",
+ format = "\fieldbodyparameter\c!format",
+ validate = "\fieldbodyparameter\c!validate",
+ calculate = "\fieldbodyparameter\c!calculate",
+ focusin = "\fieldbodyparameter\c!focusin",
+ focusout = "\fieldbodyparameter\c!focusout",
+ openpage = "\fieldbodyparameter\c!openpage",
+ closepage = "\fieldbodyparameter\c!closepage",
+ })}}
+
+%D The sets are used in grouped calculations.
+%D
+%D [name] [set]
+
+\unexpanded\def\definefieldbodyset
+ {\dodoubleempty\scrn_field_define_set}
+
+\def\scrn_field_define_set[#tag][#list]%
+ {\ctxcommand{definefieldset("#tag","#list")}}
+
+\let\dodefinefieldset\definefieldbodyset % compatibility
+
+%D A few testing macros:
+
+\def\doiffieldbodyelse #tag{\ctxcommand{doiffieldelse("#tag")}}
+\def\doiffieldcategoryelse#tag{\ctxcommand{doiffieldcategoryelse("#tag")}}
+
+\let\doiffieldelse\doiffieldbodyelse % compatibility
+
+%D We still support the traditional method of defining fields:
+%D
+%D \starttyping
+%D \definefield [name] [type] [category] [values] [default]
+%D
+%D \definefield [WWWW] [text] [textsetup] [default text]
+%D \definefield [XXXX] [push] [pushsetup] [yes,no] [yes]
+%D \definefield [XXXX] [check] [checksetup] [yes,no] [yes]
+%D \definefield [YYYY] [combo] [combosetup] [a,b,c,d] [b]
+%D \definefield [ZZZZ] [radio] [radiosetup] [W,X,Y,Z] [Y]
+%D
+%D \definesubfield [W] [subsetup] [p,q]
+%D \definesubfield [X,Y] [subsetup] [p,r]
+%D \definesubfield [Z] [subsetup] [y,z]
+%D
+%D evt \definemainfield ... wanneer geplaatst voor subs gegeven
+%D
+%D \clonefield [XXXX] [XX,YY] [mysetup] [on,off]
+%D \clonefield [Z] [AA,BB] [somesetup] [true,false]
+%D \clonefield [Z] [CC,DD] [anothersetup]
+%D
+%D \copyfield [XXXX] [PP,QQ,RR]
+%D \stoptyping
+%D
+%D Keep in mind that you can also use \type {\definefieldbody} to
+%D achieve the same.
+
+\unexpanded\def\definefield {\doquintupleempty\scrn_field_define_field}
+\unexpanded\def\definesubfield{\dotripleempty \scrn_field_define_subfield}
+\unexpanded\def\clonefield {\doquadrupleempty\scrn_field_clone_field}
+\unexpanded\def\copyfield {\dodoubleempty \scrn_field_copy_field}
+
+\let\definemainfield\definefield % obsolete !
+
+\def\scrn_field_define_field[#tag][#type][#category][#values][#default]%
+ {\definefieldbody[#tag][\c!type=#type,\c!category=#category,\c!values={#values},\c!default={#default}]}
+
+\def\scrn_field_define_subfield[#tag][#category][#values]%
+ {\definefieldbody[#tag][\c!type=sub,\c!category=#category,\c!values={#values}]}
+
+\def\scrn_field_clone_field[#parent][#tag][#category][#values]%
+ {\definefieldbody[#tag][#parent][\c!category=#category,\c!values={#values}]}
+
+\def\scrn_field_copy_field[#parent][#tag]%
+ {\definefieldbody[#tag][#parent]}
+
+%D We hook fields into the (viewer based) layering mechanism
+%D (implemented as properties).
+
+\appendtoks
+ \doifelse{\interactionparameter\c!fieldlayer}\v!auto
+ {\setupfieldcategory[\c!fieldlayer=\currentviewerlayer]}%
+ {\setupfieldcategory[\c!fieldlayer=]}%
+\to \everysetupinteraction
+
+\setupinteraction
+ [\c!fieldlayer=\v!auto] % auto by default
+
+%D The \type {\fieldbody} is the more bare one. One step further goes
+%D \type {\fitfield}, in fact it (now) uses a dedicated instance of
+%D framed: \type {fitfieldframed}.
+%D
+%D \starttyping
+%D \ruledhbox{\fieldbody[Email][height=\strutht,depth=\strutdp,style=normal]}
+%D \ruledhbox{\fitfield[Email][height=\strutht,depth=\strutdp,style=normal]}
+%D \ruledhbox{\fitfield[buttona]}
+%D \stoptyping
+
+\newbox\scrn_field_box_fit_symbol
+
+\defineframed
+ [fitfieldframed]
+ [\c!strut=\v!no,
+ \c!frame=off,
+ \c!offset=\v!overlay,
+ \c!align=]
+
+\unexpanded\def\fitfield
+ {\dodoubleempty\scrn_field_fit}
+
+\def\scrn_field_fit[#tag][#settings]%
+ {\iflocation
+ \begingroup
+ \edef\currentdefaultfieldvalue{\ctxcommand{getdefaultfieldvalue("#tag")}}%
+ \setbox\scrn_field_box_fit_symbol\hbox{\symbol[\currentdefaultfieldvalue]}%
+ \fitfieldframed[#tag]
+ {\fieldbody[#tag]
+ [\c!width=\wd\scrn_field_box_fit_symbol,
+ \c!height=\ht\scrn_field_box_fit_symbol,
+ \c!depth=\dp\scrn_field_box_fit_symbol,
+ #settings]}%
+ \endgroup
+ \fi}
+
+%D The traditional field command does some labeling and
+%D boxing:
+
+\installparameterhandler \??wl {fieldlabelframed}
+\installparameterhandler \??wc {fieldcontentframed}
+\installparameterhandler \??wt {fieldtotalframed}
+
+\installsetuphandler \??wl {fieldlabelframed}
+\installsetuphandler \??wc {fieldcontentframed}
+\installsetuphandler \??wt {fieldtotalframed}
+
+\unexpanded\def\setupfield {\doquintupleempty\scrn_field_setup_field}
+\unexpanded\def\setupfields{\doquadrupleempty\scrn_field_setup_fields}
+
+% \presetlocalframed[\??wl]
+% \presetlocalframed[\??wc]
+% \presetlocalframed[\??wt]
+
+\setupfieldcontentframed
+ [\c!align=\v!flushleft,
+ \c!strut=\v!no,
+ \s!parent=\??ol]
+
+\setupfieldcontentframed % independent
+ [\c!alternative=\v!normal,
+ \c!type=\v!line,
+ \c!width=5em,
+ \c!height=1em,
+ \c!depth=\zeropoint,
+ \c!align=\v!flushleft,
+ \c!option=\v!printable,
+ \c!n=1024]
+
+\setupfieldlabelframed
+ [\c!style=,
+ \c!color=,
+ \c!align=\v!flushleft,
+ \s!parent=\??ol]
+
+\setupfieldtotalframed
+ [%\c!alternative={\v!label,\v!frame,\v!horizontal},
+ \c!strut=\v!no,
+ \c!align=,
+ \s!parent=\??ol]
+
+\def\scrn_field_setup_field[#tag][#variant][#totalsettings][#labelsettings][#fieldsettings]%
+ {\iffifthargument
+ \definefieldcategory[#tag][\s!parent=\??wc#tag,#fieldsettings]
+ \setupfieldtotalframed [#tag][\s!parent=\??wt,\c!alternative={#variant},#totalsettings]%
+ \setupfieldlabelframed [#tag][\s!parent=\??wl,#labelsettings]%
+ \setupfieldcontentframed[#tag][\s!parent=\??wc,#fieldsettings]%
+ \else\iffourthargument
+ \definefieldcategory[#tag][\s!parent=\??wc#tag,#labelsettings]
+ \setupfieldtotalframed [#tag][\s!parent=\??wt,\c!alternative={#variant},#totalsettings]%
+ \setupfieldlabelframed [#tag][\s!parent=\??wl]%
+ \setupfieldcontentframed[#tag][\s!parent=\??wc,#labelsettings]%
+ \else\ifthirdargument
+ \definefieldcategory[#tag][\s!parent=\??wc#tag,#totalsettings]
+ \setupfieldtotalframed [#tag][\s!parent=\??wt,\c!alternative={#variant}]%
+ \setupfieldlabelframed [#tag][\s!parent=\??wl]%
+ \setupfieldcontentframed[#tag][\s!parent=\??wc,#totalsettings]%
+ \else\ifsecondargument
+ \definefieldcategory[#tag][\s!parent=\??wc#tag,#variant]
+ \setupfieldtotalframed [#tag][\s!parent=\??wt]%
+ \setupfieldlabelframed [#tag][\s!parent=\??wl]%
+ \setupfieldcontentframed[#tag][\s!parent=\??wc,#variant]%
+ \fi\fi\fi\fi}
+
+\def\scrn_field_setup_fields[#tag][#totalsettings][#labelsettings][#fieldsettings]
+ {\iffourthargument
+ \definefieldcategory[#tag][\s!parent=\??wc#tag,#fieldsettings]
+ \setupfieldtotalframed [#tag][\s!parent=\??wt,#totalsettings]%
+ \setupfieldlabelframed [#tag][\s!parent=\??wl,#labelsettings]%
+ \setupfieldcontentframed[#tag][\s!parent=\??wc,#fieldsettings]%
+ \else\ifthirdargument
+ \definefieldcategory[#tag][\s!parent=\??wc#tag,#fieldsettings]
+ \setupfieldtotalframed [#tag][\s!parent=\??wt,#totalsettings]%
+ \setupfieldlabelframed [#tag][\s!parent=\??wl]%
+ \setupfieldcontentframed[#tag][\s!parent=\??wc,#labelsettings]%
+ \else\ifsecondargument
+ \definefieldcategory[#tag][\s!parent=\??wc#tag,#fieldsettings]
+ \setupfieldtotalframed [#tag][\s!parent=\??wt]%
+ \setupfieldlabelframed [#tag][\s!parent=\??wl]%
+ \setupfieldcontentframed[#tag][\s!parent=\??wc,#totalsettings]%
+ \fi\fi\fi}
+
+\let\resetfields\relax % no longer supported
+
+\def\scrn_field_load_scripts{\useJSscripts[fld]\globallet\scrn_field_load_scripts\relax}
+
+\newconditional\fieldlabelshown
+\newconditional\fieldframeshown
+\newconditional\fieldisvertical
+\newconditional\fieldishorizontal
+
+\unexpanded\def\field
+ {\dodoubleempty\scrn_field_direct}
+
+\def\scrn_field_direct[#tag][#label]%
+ {\iflocation
+ \dontleavehmode
+ \begingroup
+ \scrn_field_load_scripts
+ \edef\currentfieldbody {#tag}%
+ \edef\currentfieldlabel {#label}%
+ \edef\currentfieldcategory{\ctxcommand{getfieldcategory("#tag")}}%
+ \ifx\currentfieldlabel\empty
+ \let\currentfieldlabel\currentfieldbody
+ \fi
+ \ifx\currentfieldcategory\empty
+ \setupfieldtotalframed [\currentfieldbody][\s!parent=\??wt]%
+ \setupfieldlabelframed [\currentfieldbody][\s!parent=\??wl]%
+ \setupfieldcontentframed[\currentfieldbody][\s!parent=\??wc]%
+ \definefieldcategory [\currentfieldbody]%
+ \setupfieldbody [\currentfieldbody][\c!category=\currentfieldbody]%
+ \let\currentfieldcategory\currentfieldbody
+ \fi
+ \let\currentfieldtotalframed \currentfieldcategory
+ \let\currentfieldlabelframed \currentfieldcategory
+ \let\currentfieldcontentframed\currentfieldcategory
+ \scrn_field_analyze_setups
+ \ifconditional\fieldframeshown
+ \localframed[\??wt\currentfieldcategory]\bgroup
+ \else
+ \vbox\bgroup
+ \fi
+ \dontcomplain
+ \ifconditional\fieldlabelshown
+ \scrn_field_set_label_box
+ \fi
+ \scrn_field_set_content_box
+ \ifconditional\fieldlabelshown
+ \ifconditional\fieldisvertical
+ \scrn_field_flush_vertical
+ \else
+ \scrn_field_flush_horizontal
+ \fi
+ \else
+ \scrn_field_flush_content
+ \fi
+ \egroup
+ \endgroup
+ \fi}
+
+% opties: veld, label, kader, vertikaal/horizontaal
+
+\newbox\scrn_field_box_label
+\newbox\scrn_field_box_content
+
+% lower framedoffset
+
+\def\scrn_field_set_label_box
+ {\setbox\scrn_field_box_label\hbox
+ {\reshapeframeboxtrue % else wrong dimensions % still needed?
+ \localframed
+ [\??wl\currentfieldcategory]
+ {\currentfieldlabel}}}
+
+% \c!fieldoffset=-\framedoffset,\c!fieldbackgroundcolor=,
+% \hbox{\lower\@@fdfieldoffset\hbox{\typesetfield}}
+
+\def\scrn_field_set_content_box
+ {\setbox\scrn_field_box_content\hbox
+ {\reshapeframeboxtrue % else wrong dimensions (to be checked)
+ \ifconditional\fieldisvertical
+ \setupfieldcontentframed[\c!height=6ex,\c!width=\hsize]%
+ \else\ifconditional\fieldishorizontal
+ \setupfieldcontentframed[\c!height=\vsize,\c!width=20em]%
+ \else
+ \setupfieldcontentframed[\c!height=2cm,\c!width=2cm]%
+ \fi\fi
+ \localframed % lower framedoffset
+ [\??wc\currentfieldcategory]
+ {\fieldbody
+ [\currentfieldbody]
+ [\c!width=\framedwidth,\c!height=\framedheight]}}}
+
+\def\scrn_field_flush_vertical
+ {\vbox
+ {\copy\scrn_field_box_label
+ \fieldtotalframedparameter\c!inbetween
+ \copy\scrn_field_box_content}}
+
+\def\scrn_field_flush_horizontal
+ {\hbox
+ {\vbox \ifdim\ht\scrn_field_box_content>\ht\scrn_field_box_label to \ht\scrn_field_box_content \fi
+ {\fieldtotalframedparameter\c!before
+ \copy\scrn_field_box_label
+ \fieldtotalframedparameter\c!after}%
+ \hskip\fieldtotalframedparameter\c!distance
+ \vbox \ifdim\ht\scrn_field_box_label>\ht\scrn_field_box_content to \ht\scrn_field_box_label \fi
+ {\fieldtotalframedparameter\c!before
+ \box\scrn_field_box_content
+ \fieldtotalframedparameter\c!after}}}
+
+\def\scrn_field_flush_content
+ {\box\scrn_field_box_content}
+
+\def\scrn_field_analyze_setups
+ {\setfalse\fieldlabelshown
+ \setfalse\fieldframeshown
+ \setfalse\fieldishorizontal
+ \setfalse\fieldisvertical
+ \normalexpanded{\processallactionsinset[\fieldtotalframedparameter\c!alternative]}
+ [ \v!reset=>\setfalse\fieldlabelshown
+ \setfalse\fieldframeshown
+ \setfalse\fieldishorizontal
+ \setfalse\fieldisvertical,
+ \v!label=>\settrue\fieldlabelshown,
+ \v!frame=>\settrue\fieldframeshown,
+ \v!horizontal=>\settrue\fieldishorizontal,
+ \v!vertical=>\settrue\fieldisvertical]%
+ \ifconditional\fieldisvertical
+ \setupfieldtotalframed[\c!distance=\zeropoint,\c!inbetween=\vskip\@@localoffset,\c!align=\v!right,\c!width=20em]%
+ \else\ifconditional\fieldishorizontal
+ \setupfieldtotalframed[\c!distance=\@@localoffset,\c!inbetween=,\c!align=\c!left,\c!height=10ex]%
+ \else
+ \setupfieldtotalframed[\c!distance=\zeropoint,\c!inbetween=,\c!align=\c!left]%
+ \fi\fi
+ \setupfieldtotalframed[\c!n=,\c!before=,\c!after=\vss,\c!style=,\c!color=]}
+
+%D Common stuff (obsolete)
+
+\newcount\scrn_field_system_n
+
+\def\nextsystemfield
+ {\global\advance\scrn_field_system_n\plusone
+ \def\currentsystemfield{sys::\number\scrn_field_system_n}}
+
+%D \CONTEXT\ had tooltips right from the moment that it
+%D supported fields. Due to the at that moment somewhat
+%D limited \PDF\ specification, they were implemented
+%D using \JAVASCRIPT, but nowadays more kind of actions
+%D are supported, so we can do without. The \MKIV\ version
+%D also supports definition of tooltips and configuration.
+%D
+%D \starttyping
+%D before \tooltip[right]{inbetween}{a very nice tip} after\par
+%D before \tooltip[align=normal]{inbetween}{a very\\nice tip} after\par
+%D before \tooltip[middle]{inbetween}{a very nice tip} after\par
+%D before \tooltip[left]{inbetween}{a very nice tip} after\par
+%D \stoptyping
+
+\newbox \scrn_tooltip_box_anchor
+\newbox \scrn_tooltip_box_text
+\newcount\scrn_tooltip_n
+
+\installcommandhandler \??wh {tooltip} \??wh
+
+\setuptooltip
+ [\c!location=\v!right,
+ \c!frame=\v!off,
+ \c!offset=.1ex,
+ \c!background=\v!color,
+ \c!backgroundcolor=gray]
+
+\presetlocalframed[\??wh]
+
+\appendtoks
+ \setuevalue\currenttooltip{\scrn_tooltip_direct{\currenttooltip}}%
+\to \everydefinetooltip
+
+\unexpanded\def\scrn_tooltip_direct#tag%
+ {\def\currenttooltip{#tag}%
+ \doifelselocation
+ {\dosingleempty\scrn_tooltip_indeed}
+ {\dosingleempty\scrn_tooltip_ignore}}
+
+\def\scrn_tooltip_ignore[#settings]#anchortext#tiptext%
+ {#anchortext}
+
+\def\scrn_tooltip_indeed[#settings]#anchortext#tiptext% a more modern aproach (push buttons)
+ {\dontleavehmode \hbox \bgroup
+ \dontcomplain
+ \global\advance\scrn_tooltip_n\plusone
+ \edef\currenttooltipname{tooltip:\number\scrn_tooltip_n}%
+ \setbox\scrn_tooltip_box_anchor\hbox
+ {\strut#anchortext}%
+ \doifassignmentelse{#settings}
+ {\setuptooltip[\currenttooltip][#settings]}%
+ {\setuptooltip[\currenttooltip][\c!location=#settings]}%
+ \setbox\scrn_tooltip_box_text\hbox
+ {\localframed[\??wh\currenttooltip][\c!location=]{#tiptext}}%
+ \definesymbol
+ [\currenttooltipname:txt]
+ [\copy\scrn_tooltip_box_text]%
+ \definefieldbody
+ [\currenttooltipname:txt]
+ [\c!type=push,
+ \c!width=\wd\scrn_tooltip_box_text,
+ \c!height=\ht\scrn_tooltip_box_text,
+ \c!depth=\dp\scrn_tooltip_box_text,
+ \c!option=\v!hidden,
+ \c!values=\currenttooltipname:txt]%
+ \setbox\scrn_tooltip_box_text\hbox
+ {\fieldbody[\currenttooltipname:txt]}%
+ \setbox\scrn_tooltip_box_text\hbox
+ {\strut\lower\dimexpr.25ex+\ht\scrn_tooltip_box_text\relax\box\scrn_tooltip_box_text}%
+ \edef\currenttooltiplocation{\tooltipparameter\c!location}%
+ \ifx\currenttooltiplocation\v!left
+ \hsmashed{\hskip\wd\scrn_tooltip_box_anchor\llap{\box\scrn_tooltip_box_text}}%
+ \else\ifx\currenttooltiplocation\v!middle
+ \hsmashed to \wd\scrn_tooltip_box_anchor{\hss\box\scrn_tooltip_box_text\hss}%
+ \else
+ \hsmashed{\box\scrn_tooltip_box_text}%
+ \fi\fi
+ \definesymbol
+ [\currenttooltipname:but]
+ [\hphantom{\copy\scrn_tooltip_box_anchor}]%
+ \definefieldbody
+ [\currenttooltipname:but]
+ [\c!type=push,
+ \c!regionin=action(show{\currenttooltipname:txt}),
+ \c!regionout=action(hide{\currenttooltipname:txt}),
+ \c!width=\wd\scrn_tooltip_box_anchor,
+ \c!height=\ht\scrn_tooltip_box_anchor,
+ \c!depth=\dp\scrn_tooltip_box_anchor]%
+ \hsmashed{\fieldbody[\currenttooltipname:but]}%
+ \egroup
+ #anchortext}% when hyphenated the text wil stick out ... such are fields and we cannot use a link here
+
+\definetooltip[tooltip]
+
+%D From messages on the mailing list we can conclude that
+%D fieldstacks are used so we keep them in the core:
+%D
+%D \starttyping
+%D \definesymbol[one] [one]
+%D \definesymbol[two] [two]
+%D \definesymbol[three][three]
+%D
+%D \definefieldstack[mine][one,two,three]
+%D \fieldstack[mine]
+%D \fieldstack[mine]
+%D
+%D \goto{walk field}[Walk{mine}]
+%D \stoptyping
+
+\unexpanded\def\definefieldstack
+ {\dotripleargument\scrn_fieldstack_define}
+
+\def\scrn_fieldstack_define[#tag][#symbols][#settings]%
+ {\ifcsname scrn_fieldstack:#tag\endcsname \else
+ \setgvalue{scrn_fieldstack:#tag}{\scrn_fieldstack_construct[#tag][#symbols][#settings]}%
+ \fi}
+
+\unexpanded\def\fieldstack
+ {\dotripleempty\scrn_fieldstack_direct}
+
+\def\scrn_fieldstack_direct[#tag][#symbols][#settings]%
+ {\ifsecondargument
+ \scrn_fieldstack_define[#tag][#symbols][#settings]%
+ \fi
+ \getvalue{scrn_fieldstack:#tag}}
+
+\newbox\scrn_fieldstack_box
+
+\def\scrn_fieldstack_add#tag#settings#symbol%
+ {\advance\scratchcounter\plusone
+ \edef\currentfieldstackname{#tag:\number\scratchcounter}%
+ \ifnum\scratchcounter=\@@fdstart\relax
+ \definefieldbody[\currentfieldstackname][\c!type=check,\c!values={#symbol,\empty},\c!default={#symbol}]%
+ \else
+ \definefieldbody[\currentfieldstackname][\c!type=check,\c!values={#symbol,\empty},\c!default=]%
+ \fi
+ \setbox\scrn_fieldstack_box\hbox{\symbol[#symbol]}%
+ \setcollector
+ [fieldstack]
+ {\fieldbody
+ [\currentfieldstackname]
+ [\c!option=\v!readonly,
+ \c!width=\wd\scrn_fieldstack_box,
+ \c!height=\ht\scrn_fieldstack_box,
+ \c!depth=\dp\scrn_fieldstack_box,
+ #settings]}}
+
+\def\scrn_fieldstack_construct[#tag][#symbols][#settings]% start=n, 0 == leeg
+ {\iflocation
+ \dontleavehmode
+ \begingroup
+ \getparameters[\??fd][\c!start=1,#settings]%
+ \scrn_field_load_scripts
+ \definecollector
+ [fieldstack]%
+ [\c!corner=\v!middle,
+ \c!location=\v!middle]%
+ \scratchcounter\zerocount
+ \processcommalist[#symbols]{\scrn_fieldstack_add{#tag}{#settings}}%
+ \flushcollector[fieldstack]%
+ \endgroup
+ \fi}
+
+%D Another goodie. Two actions can be hookes into an overlay.
+%D
+%D \starttyping
+%D \defineviewerlayer[test]
+%D
+%D \startviewerlayer[test]Hide Me\stopviewerlayer
+%D
+%D \defineoverlay
+%D [WithTest]
+%D [{\overlayrollbutton[HideLayer{test}][VideLayer{test}]}]
+%D
+%D \framed[background=WithTest]{toggle}
+%D \stoptyping
+
+\newcount\scrn_rollbutton_n
+
+\unexpanded\def\overlayrollbutton
+ {\dodoubleargument\scrn_rollbutton_overlay}
+
+\def\scrn_rollbutton_overlay[#regionin][#regionout]%
+ {\iflocation
+ \bgroup
+ \global\advance\scrn_rollbutton_n\plusone
+ \definesymbol
+ [rollbutton:\number\scrn_rollbutton_n]
+ [{\framed[\c!frame=\v!off,\c!width=\overlaywidth,\c!height=\overlayheight]{}}]%
+ \definefieldbody
+ [rollbutton:\number\scrn_rollbutton_n]
+ [\c!type=push,
+ \c!regionin={#regionin},
+ \c!regionout={#regionout},
+ \c!values=\currentsystemfield,
+ \c!default=\currentsystemfield]%
+ \fitfield[\currentsystemfield]%
+ \egroup
+ \fi}
+
+\protect \endinput
+
+%D I will redo these when I need them.
+
+% \definepushbutton [reset]
+%
+% \definepushsymbol [reset] [n] [\uniqueMPgraphic{whatever}{color=green}]
+% \definepushsymbol [reset] [r] [\uniqueMPgraphic{whatever}{color=white}]
+%
+% \startinteractionmenu[bottom]
+% \psh [reset] [JS(reset_something)] \\
+% \stopinteractionmenu
+
+\newcount\scrn_pushbutton_n
+
+\unexpanded\def\definepushbutton % name optional setup
+ {\dodoubleempty\scrn_pushbutton_define}
+
+\def\scrn_pushbutton_define[#tag][#settings]%
+ {\scrn_pushbutton_define_variant{#tag}{n}{push}%
+ \scrn_pushbutton_define_variant{#tag}{r}{\symbol[pushsymbol:#tag:n]}%
+ \scrn_pushbutton_define_variant{#tag}{d}{\symbol[pushsymbol:#tag:r]}%
+ \setvalue{pushbutton:#tag}{\scrn_pushbutton_handle{#tag}{#settings}}}
+
+\def\scrn_pushbutton_define_variant#tag#variant#content%
+ {\doifsymboldefinedelse{pushsymbol:#tag:#variant}
+ \donothing
+ {\definesymbol[pushsymbol:#tag:#variant][{#content}]}}
+
+\def\scrn_pushbutton_handle#tag#settings#reference%
+ {\bgroup
+ \global\advance\scrn_pushbutton_n\plusone
+ \setupfield
+ [pushbutton]
+ [\c!frame=\v!overlay,
+ \c!offset=\v!overlay,
+ \c!clickout={#reference},
+ #settings]%
+ \definefield
+ [pushbutton:\number\scrn_pushbutton_n]%
+ [push]
+ [pushbutton]
+ [pushsymbol:#tag:n,pushsymbol:#tag:r,pushsymbol:#tag:d]%
+ \fitfield
+ [pushbutton:\number\scrn_pushbutton_n]%
+ \egroup}
+
+\unexpanded\def\definepushsymbol
+ {\dotripleargument\scrn_pushsymbol_define}
+
+\def\scrn_pushsymbol_define[#tag][#variant]% [#reference]
+ {\definesymbol[pushsymbol:#tag:#variant]}
+
+\def\pushbutton
+ {\dodoubleargument\scrn_pushbutton_direct}
+
+\def\scrn_pushbutton_direct[#tag][#variant]%
+ {\executeifdefined{pushbutton:#tag}\gobbleoneargument{#variant}}
+
+%D We plug into the menu system
+
+\unexpanded\def\scrn_menu_psh_start[#reference]#text\stoppsh
+ {\starttxt\pushbutton[\currentmenu][#reference]\stoptxt}
+
+\unexpanded\def\scrn_menu_psh_direct[#reference]#text\\
+ {\scrn_menu_psh_start[#reference]\stoprob}
+
+\appendtoks
+ \let\startpsh\scrn_menu_psh_start
+ \let\stoppsh \relax
+ \let\psh \scrn_menu_psh_direct
+\everysetmenucommands
+
+%D Another goodie: (unchecked in \MKIV)
+
+% calls:
+% {..} [JS..]
+% [left] {..} [JS..]
+% [a=b] {..} [JS..]
+% [left] [a=b] {..} [JS..]
+%
+% \setupbuttons[offset=0pt,frame=off] % alternative=hidden
+%
+% \rollbutton {Manuals} [JS(Goto_File{show-man.pdf})]
+% \rollbutton {Articles} [JS(Goto_File{show-art.pdf})]
+% \rollbutton {Papers} [JS(Goto_File{show-pap.pdf})]
+% \rollbutton {Presentations} [JS(Goto_File{show-pre.pdf})]
+% \rollbutton {Resources} [JS(Goto_File{show-res.pdf})]
+%
+% \rob [JS(...)] bla bla \\
+
+% \definecolor[rollover:n][red]
+% \definecolor[rollover:r][green]
+% \definecolor[rollover:d][blue]
+
+\definepalet
+ [rollover]
+ [n=red,
+ r=green,
+ d=blue]
+
+\newcount\scrn_rollbutton_n_button
+\newcount\scrn_rollbutton_n_symbol
+
+\unexpanded\def\rollbutton
+ {\dodoubleempty\scrn_rollbutton}
+
+\def\scrn_rollbutton[#tag][#settings]#text[#reference]%
+ {\dontleavehmode
+ \bgroup
+ \doglobal\advance\scrn_rollbutton_n_button
+ \doglobal\advance\scrn_rollbutton_n_symbol
+ \iffirstargument
+ \ifsecondargument
+ \getparameters[\??am#tag][#settings]%
+ \def\scrn_rollbutton_symbol{\scrn_rollbutton_symbol_indeed{\??am#tag}{#text}}%
+ \else
+ \doifassignmentelse{#tag}
+ {\getparameters[\??bt][#tag]%
+ \def\scrn_rollbutton_symbol{\scrn_rollbutton_symbol_indeed{\??bt}{#text}}}
+ {\def\scrn_rollbutton_symbol{\scrn_rollbutton_symbol_indeed{\??am#tag}{#text}}}%
+ \fi
+ \else
+ \def\scrn_rollbutton_symbol{\set_location_box_indeed_indeed{\??bt}{#text}}%
+ \fi
+ % todo: share symbols, tricky since different dimensions
+ \definesymbol[rollsymbol:\number\scrn_rollbutton_n_symbol:n][\scrn_rollbutton_symbol{n}]%
+ \definesymbol[rollsymbol:\number\scrn_rollbutton_n_symbol:r][\scrn_rollbutton_symbol{r}]%
+ \definesymbol[rollsymbol:\number\scrn_rollbutton_n_symbol:d][\scrn_rollbutton_symbol{d}]%
+ \setupfield
+ [rollbutton]
+ [\c!frame=\v!off,
+ \c!offset=\v!overlay,
+ \c!clickout={#reference}]%
+ \definefield
+ [rollbutton:\number\scrn_rollbutton_n_button][push][rollbutton]
+ [rollsymbol:\number\scrn_rollbutton_n_symbol:n,%
+ rollsymbol:\number\scrn_rollbutton_n_symbol:r,%
+ rollsymbol:\number\scrn_rollbutton_n_symbol:d]%
+ \fitfield[rollbutton:\number\scrn_rollbutton_n_button]%
+ \egroup}
+
+\unexpanded\def\scrn_rollbutton_symbol_indeed#namespace#text#what%
+ {\definecolor[rollover][rollover:#what]%
+ \doifelse{#what}{n}{\doifelsevalue{#namespace\c!alternative}\v!hidden\phantom\hbox}\hbox
+ {\localframed[#namespace]
+ [\c!framecolor=rollover,\c!backgroundcolor=rollover,\c!color=rollover]%
+ {\dolocationattributes{#namespace}\c!style\c!color{#text}}}}%
+
+%D We plug into the menu system
+
+\unexpanded\def\scrn_menu_rob_start[#reference]#text\stoprob
+ {\starttxt\rollbutton[\currentmenu]{\ignorespaces#text\unskip}[#reference]\stoptxt}
+
+\unexpanded\def\scrn_menu_rob_direct[#reference]#text\\
+ {\scrn_menu_rob_start[#reference]#text\stoprob}
+
+\appendtoks
+ \let\startrob\scrn_menu_rob_start
+ \let\stoprob \relax
+ \let\rob \scrn_menu_rob_direct
+\everysetmenucommands
+
+\protect \endinput
diff --git a/tex/context/base/scrn-hlp.lua b/tex/context/base/scrn-hlp.lua
new file mode 100644
index 000000000..81d68840b
--- /dev/null
+++ b/tex/context/base/scrn-hlp.lua
@@ -0,0 +1,120 @@
+if not modules then modules = { } end modules ['scrn-hlp'] = {
+ version = 1.001,
+ comment = "companion to scrn-hlp.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+
+local help = { }
+interactions.help = help
+
+local a_help = attributes.private("help")
+
+local has_attribute = node.has_attribute
+local copy_nodelist = node.copy_list
+local hpack_nodelist = node.hpack
+
+local register_list = nodes.pool.register
+
+local nodecodes = nodes.nodecodes
+
+local hlist_code = nodecodes.hlist
+local vlist_code = nodecodes.vlist
+
+local data, references = { }, { }
+
+local helpscript = [[
+ function Hide_All_Help(prefix) {
+ var n = 0
+ while (true) {
+ n += 1 ;
+ v = this.getField(prefix + n) ;
+ if (v) {
+ v.hidden = true ;
+ this.dirty = false ;
+ } else {
+ return ;
+ }
+ }
+ }
+]]
+
+local template = "javascript(Hide_All_Help{help:}),action(show{help:%s})"
+
+function help.register(number,name,box)
+ if helpscript then
+ interactions.javascripts.setpreamble("HelpTexts",helpscript)
+ helpscript = false
+ end
+ local b = copy_nodelist(tex.box[box])
+ register_list(b)
+ data[number] = b
+ if name and name ~= "" then
+ references[name] = number
+ structures.references.define("",name,format(template,number))
+ end
+end
+
+local function collect(head,used)
+ while head do
+ local id = head.id
+ if id == hlist_code then
+ local a = has_attribute(head,a_help)
+ if a then
+ if not used then
+ used = { a }
+ else
+ used[#used+1] = a
+ end
+ else
+ used = collect(head.list,used)
+ end
+ elseif id == vlist_code then
+ used = collect(head.list,used)
+ end
+ head = head.next
+ end
+ return used
+end
+
+function help.collect(box)
+ if next(data) then
+ return collect(tex.box[box].list)
+ end
+end
+
+commands.registerhelp = help.register
+
+function commands.collecthelp(box)
+ local used = help.collect(box)
+ if used then
+ local done = { }
+ context.startoverlay()
+ for i=1,#used do
+ local d = data[used[i]]
+ if d and not done[d] then
+ local box = hpack_nodelist(copy_nodelist(d))
+ context(false,box)
+ done[d] = true
+ else
+ -- error
+ end
+ end
+ context.stopoverlay()
+ end
+end
+
+function help.reference(name)
+ return references[name] or tonumber(name) or 0
+end
+
+function commands.helpreference(name)
+ context(references[name] or tonumber(name) or 0)
+end
+
+function commands.helpaction(name)
+ context(template,references[name] or tonumber(name) or 0)
+end
diff --git a/tex/context/base/scrn-hlp.mkiv b/tex/context/base/scrn-hlp.mkiv
deleted file mode 100644
index 4eaa340ca..000000000
--- a/tex/context/base/scrn-hlp.mkiv
+++ /dev/null
@@ -1,179 +0,0 @@
-%D \module
-%D [ file=scrn-hlp,
-%D version=1998.10.10,
-%D title=\CONTEXT\ Screen Macros,
-%D subtitle=Help (Experimental),
-%D author={Hans Hagen \& Ton Otten},
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%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 : dedicated vide/hide voor helps
-
-\writestatus{loading}{ConTeXt Screen Macros / Help popups}
-
-%D This is an experimental and private module, so the interface
-%D and functionality can change. Pieces of code will be moved
-%D to other modules. More features are possible but will be
-%D interfaces later. See m-chart for an application as well
-%D as the second tno-tpd manual (graphic in margin, click
-%D on it, pop up big one, use menu with hides, as well as
-%D background, etc. etc.
-
-\unprotect
-
-\defineframedtext
- [\v!helptext]
-
-\setupframedtexts
- [\v!helptext]
- [\c!width=.75\textwidth,
- \c!align=\v!normal,
- \c!frame=\v!off,
- \c!background=\v!screen]
-
-\newcounter \nofhelpdataentries
-\newconditional \somehelpdatadefined
-
-\let\getpagehelpdata \relax
-\let\synchronizepagehelpdata\relax
-
-\appendtoks \getpagehelpdata \to \beforeeverypage
-\appendtoks \synchronizepagehelpdata \to \aftereverypage
-
-% will be proper state variable
-
-\let\pagehelpdata\empty
-
-\def\dontresetpagedata
- {\let\synchronizepagehelpdataindeed\relax}
-
-\def\resetpagehelpdata
- {\iflocation
- \let\synchronizepagehelpdataindeed\resetpagehelpdata
- \global\let\pagehelpdata\empty
- \resetreference[HideHelp]%
- \fi}
-
-\let\synchronizepagehelpdataindeed\resetpagehelpdata
-
-\resetreference[HideHelp]
-
-\def\getpagehelpdataindeed
- {\iflocation\ifcase\nofhelpdataentries\else
- \dogetpagehelpdataindeed
- \fi\fi}
-
-\def\dogetpagehelpdataindeed
- {\let\pagehelpdata\empty
- \ifconditional\somehelpdatadefined
- \definetwopasslist{hlp:\realfolio}%
- \doloop
- {\gettwopassdata{hlp:\realfolio}%
- \iftwopassdatafound
- \addtocommalist\twopassdata\pagehelpdata
- \else
- \exitloop
- \fi}%
- \fi
- \ifx\pagehelpdata\empty \else
- \useJSscripts[fld]%
- \definereference[HideHelp][JS(Hide_Fields)]% for the moment
- \fi}
-
-\def\setpagehelpdata[#1]%
- {\iflocation\expanded{\dosetpagehelpdata{#1}}\fi}
-
-\def\dosetpagehelpdata#1%
- {\doglobal\increment\nofhelpdataentries
- \global\let\getpagehelpdata\getpagehelpdataindeed
- \global\let\synchronizepagehelpdata\synchronizepagehelpdataindeed
- \savetwopassdata{hlp:\realfolio}{\nofhelpdataentries}{#1}}
-
-\setvalue{\e!start\v!helptext}[#1]%
- {\iflocation
- \global\settrue\somehelpdatadefined
- \setvalue{\e!stop\v!helptext}%
- %{\definesymbol[helpinfo:#1][{\doframedtext[\v!helptext]{\getbuffer[\v!helptext]}}]%
- % \dopresetfieldsymbol{helpinfo:#1}}%
- {\definesymbol[\v!helptext:#1][{\doframedtext[\v!helptext]{\getbuffer[\v!helptext]}}]%
- \dopresetfieldsymbol{\v!helptext:#1}}%
- \else
- \letvalue{\e!stop\v!helptext}\relax
- \fi
- \dostartbuffer[\v!helptext][\e!start\v!helptext][\e!stop\v!helptext]}
-
-\long\def\helptext[#1]#2%
- {\iflocation
- \global\settrue\somehelpdatadefined
- %\definesymbol[helpinfo:#1][{\doframedtext[\v!helptext]{#2}}]%
- %\dopresetfieldsymbol{helpinfo:#1}%
- \definesymbol[\v!helptext:#1][{\doframedtext[\v!helptext]{#2}}]%
- \dopresetfieldsymbol{\v!helptext:#1}%
- \fi}
-
-\let\definehelptext\helptext % for backward compabilities sake
-
-\def\dohelpdata#1%
- {\setbox\scratchbox\hbox
- {\startoverlay
- {\box\scratchbox}
- %{\definemainfield[help:#1][check][helpsetup][helpinfo:#1][helpinfo:#1]%
- {\definemainfield[help:#1][check][helpsetup][\v!helptext:#1][\v!helptext:#1]%
- \fitfield[help:#1]}
- \stopoverlay}}
-
-\def\helpdata
- {\iflocation
- \bgroup
- %\getpagehelpdata
- \ifx\pagehelpdata\empty \else
- \setupfields[\v!reset]%
- \setupfield
- [helpsetup]
- [\c!width=\v!fit,
- \c!height=\v!fit,
- \c!frame=\v!off,
- \c!clickin=JS(Hide_Fields),
- \c!option={\v!readonly,\v!hidden}]%
- \setbox\scratchbox\emptybox
- \processcommacommand[\pagehelpdata]\dohelpdata
- \box\scratchbox
- \fi
- \egroup
- \fi}
-
-\def\helpbutton % also gobble spaces between [][]
- {\dodoubleempty\dohelpbutton}
-
-\def\dohelpbutton
- {\ifsecondargument
- \expandafter\donohelpbutton
- \else
- \expandafter\dodohelpbutton
- \fi}
-
-\def\dodohelpbutton[#1][#2]#3[#4]% #2 is space gobbling dummy
- {\iflocation
- \setpagehelpdata[#4]%
- \useJSscripts[fld]%
- \button[#1]{#3}[JS(Vide_Hide_Fields{help:#4})]%
- \fi}
-
-\def\donohelpbutton[#1][#2]%
- {\dodohelpbutton[#1][]{}[#2]}
-
-\def\doifhelpinfo#1#2%
- {\iflocation
- \doifsymboldefinedelse{helpinfo:#1}{#2}\donothing
- \fi}
-
-\def\doifelsehelpinfo#1#2#3%
- {\iflocation
- \doifsymboldefinedelse{helpinfo:#1}{#2}{#3}%
- \fi}
-
-\protect \endinput
diff --git a/tex/context/base/scrn-hlp.mkvi b/tex/context/base/scrn-hlp.mkvi
new file mode 100644
index 000000000..d97824300
--- /dev/null
+++ b/tex/context/base/scrn-hlp.mkvi
@@ -0,0 +1,162 @@
+%D \module
+%D [ file=scrn-hlp,
+%D version=1998.10.10,
+%D title=\CONTEXT\ Screen Macros,
+%D subtitle=Help (Experimental),
+%D author={Hans Hagen \& Ton Otten},
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%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 Screen Macros / Help popups}
+
+%D As this functionality was in the core and as I don't know
+%D how often it is used, we'll keep it around. However, it is
+%D upgraded and usage has changed a bit. We also use some
+%D \LUA\ magic in order to avoid multiple passes.
+
+\registerctxluafile{scrn-hlp}{1.001}
+
+%D Using help boils down to plugging the placement macro
+%D someplace visible, like:
+%D
+%D \starttyping
+%D \setuptexttexts[\centerbox{\placehelp}]
+%D \stoptyping
+%D
+%D When this is done, the following should work out okay:
+%D
+%D \starttyping
+%D test \helptext{word}{tip top 1 is somewhat longer} test
+%D test \helptext{word}{tip top 2} test
+%D
+%D \starthelptext[oeps]
+%D \input tufte
+%D \stophelptext
+%D
+%D test test \showhelp{some help}[oeps] test
+%D test test \button[location=depth]{\helpsignal{oeps}OEPS}[oeps] test
+%D
+%D test test \button[location=depth]{next}[page(2)] test
+%D
+%D \page
+%D
+%D test \helptext{word}{tip top one} test
+%D test \helptext{word}{tip top two} test
+%D \stoptyping
+%D
+%D Currently you need to use the signal in custom macros but
+%D that might change at some point.
+
+\unprotect
+
+% also status
+
+\newbox \scrn_help_box
+\newcount\scrn_help_n
+
+\definesystemattribute[help][public]
+
+\installcommandhandler \??wp {help} \??wp
+
+\setuphelp
+ [\c!frame=\v!off,
+ \c!align=\v!normal,
+ \c!background=\v!color,
+ \c!backgroundcolor=gray]
+
+\presetlocalframed[\??wp]
+
+\appendtoks
+ \setuevalue \currenthelp {\scrn_help_argument{\currenthelp}}%
+ \setuevalue{\e!start\currenthelp}{\scrn_help_start {\currenthelp}}%
+ \setuevalue{\e!stop \currenthelp}{\scrn_help_stop }%
+\to \everydefinehelp
+
+\unexpanded\def\scrn_help_argument#category%
+ {\def\currenthelp{#category}%
+ \global\advance\scrn_help_n\plusone
+ \edef\currenthelpname{help:\number\scrn_help_n}%
+ \doifelselocation
+ {\dosingleempty\scrn_help_argument_indeed}
+ {\dosingleempty\scrn_help_argument_ignore}}
+
+\def\scrn_help_argument_indeed[#reference]#text#target%
+ {\edef\currenthelpreference{#reference}%
+ \dontleavehmode \hbox \bgroup
+ \dontcomplain
+ \setbox\scrn_help_box\hbox{\strut#text}%
+ \doregisterhelp{#target}%
+ \egroup % can be usernode instead
+ \goto
+ {\helpsignal{\number\scrn_help_n}#target}%
+ [\helpaction{\number\scrn_help_n}]}
+
+\def\scrn_help_argument_ignore[#reference]#text#target%
+ {#target}
+
+\unexpanded\def\scrn_help_start#category%
+ {\def\currenthelp{#category}%
+ \global\advance\scrn_help_n\plusone
+ \edef\currenthelpname{help:\number\scrn_help_n}%
+ \dosingleempty\scrn_help_start_indeed}
+
+\def\scrn_help_start_indeed[#reference]%
+ {\edef\currenthelpreference{#reference}%
+ \dostartbuffer[\currenthelp][\e!start\currenthelp][\e!stop\currenthelp]}
+
+\unexpanded\def\scrn_help_stop
+ {\iflocation
+ \scrn_help_register{\getbuffer[\currenthelp]}%
+ \fi}
+
+\def\scrn_help_register#text%
+ {\setbox\scrn_help_box\hbox
+ {\localframed[\??wp\currenthelp]{#text}}%
+ \definesymbol
+ [\currenthelpname]
+ [\copy\scrn_help_box]%
+ \definefieldbody
+ [\currenthelpname]
+ [\c!type=push,
+ \c!width=\wd\scrn_help_box,
+ \c!height=\ht\scrn_help_box,
+ \c!depth=\dp\scrn_help_box,
+ \c!option=\v!hidden,
+ \c!clickin=action(hide{\currenthelpname}),
+ \c!closepage=action(hide{\currenthelpname}),
+ \c!values=\currenthelpname]%
+ \setbox\scrn_help_box\hbox
+ {\fieldbody[\currenthelpname]}%
+ \ctxcommand{registerhelp(\number\scrn_help_n,"\currenthelpreference",\number\scrn_help_box)}}
+
+\def\doifelsehelp
+ {\ifcase\scrn_help_n
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\def\placehelp % was \helpdata
+ {\ifinpagebody\ifcase\scrn_help_n\else
+ \ctxcommand{collecthelp(255)}% rather hard coded ... bad
+ \fi\fi}
+
+\def\helpreference#category%
+ {\ctxcommand{helpreference("#category")}}
+
+\def\helpaction#category%
+ {\ctxcommand{helpaction("#category")}}
+
+\unexpanded\def\helpsignal#category%
+ {\hbox attr \helpattribute \helpreference{#category}{}}
+
+\unexpanded\def\showhelp#target[#category]%
+ {\goto{\helpsignal{#category}#target}[#category]}
+
+\definehelp[\v!helptext]
+
+\protect \endinput
diff --git a/tex/context/base/scrn-ini.lua b/tex/context/base/scrn-ini.lua
new file mode 100644
index 000000000..76696eed0
--- /dev/null
+++ b/tex/context/base/scrn-ini.lua
@@ -0,0 +1,21 @@
+if not modules then modules = { } end modules ['scrn-int'] = {
+ version = 1.001,
+ comment = "companion to scrn-int.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+interactions = { }
+interactions.general = interactions.general or { }
+local general = interactions.general
+
+local codeinjections = backends.codeinjections
+
+local function setupidentity(specification)
+ codeinjections.setupidentity(specification)
+end
+
+general.setupidentity = setupidentity
+
+commands.setupidentity = setupidentity
diff --git a/tex/context/base/scrn-ini.mkvi b/tex/context/base/scrn-ini.mkvi
new file mode 100644
index 000000000..860c696c0
--- /dev/null
+++ b/tex/context/base/scrn-ini.mkvi
@@ -0,0 +1,178 @@
+%D \module
+%D [ file=scrn-ini,
+%D version=2011.02.27,
+%D title=\CONTEXT\ Interaction Macros,
+%D subtitle=Initialization,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%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 Interaction Macros / Initialization}
+
+\unprotect
+
+\registerctxluafile{scrn-ini}{1.001}
+
+%D There is no interaction at all unless enabled by saying:
+%D
+%D \starttyping
+%D \setupinteraction[state=start]
+%D \stoptyping
+%D
+%D The other settings are:
+%D
+%D \showsetup{setupinteraction}
+
+\installcommandhandler\??ia{interaction}\??ia
+
+\let\currentinteraction\empty
+
+\appendtoks
+ \doifelse{\interactionparameter\c!state}\v!start
+ {\locationtrue \setsystemmode \v!interaction}%
+ {\locationfalse \resetsystemmode\v!interaction}%
+\to \everysetupinteraction
+
+\def\doifelselocation
+ {\iflocation
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\setupinteraction
+ [\c!state=\v!stop]
+
+\appendtoks
+ \setupinteraction % todo: remember info at the lua end (already possible)
+\to \everyjob
+
+% it makes no sense to create an environment as we will seldom have structured
+% interactionso a general start-stop will do
+%
+% \appendtoks
+% \setuevalue \currentinteraction {\scrn_interaction_direct{\currentinteraction}}%
+% \setuevalue{\e!start\currentinteraction}{\scrn_interaction_start {\currentinteraction}}%
+% \setuevalue{\e!stop \currentinteraction}{\scrn_interaction_stop }%
+% \to \everydefineinteraction
+%
+% \unexpanded\def\scrn_interaction_direct#1%
+% {\edef\currentinteraction{#1}}
+%
+% \unexpanded\def\scrn_interaction_start#1%
+% {\pushmacro\currentinteraction
+% \edef\currentinteraction{#1}}
+%
+% \unexpanded\def\scrn_interaction_stop
+% {\popmacro\currentinteraction}
+%
+% \unexpanded\def\setinteraction[#1]%
+% {\def\currentinteraction{#1}}
+%
+% \defineinteraction[\v!interaction]
+
+\unexpanded\def\startinteraction[#1]%
+ {\pushmacro\currentinteraction
+ \edef\currentinteraction{#1}}
+
+\unexpanded\def\stopinteraction
+ {\popmacro\currentinteraction}
+
+\unexpanded\def\setinteraction[#1]%
+ {\def\currentinteraction{#1}}
+
+%D As long as there a natural feeling of what can be considered
+%D hyper active or not, we have to tell users where they can
+%D possibly click. We've already seen a few macros that deal
+%D with this visualization, something we definitely do not let
+%D up to the viewer. One way of telling is using a distinctive
+%D typeface, another way is using color.
+%D
+%D There are two colors involved: one for normal hyperlinks,
+%D and one for those that point to the currentpage, the
+%D contrast color.
+
+\definecolor [interactioncolor] [r=0, g=.6, b=0]
+\definecolor [interactioncontrastcolor] [r=.8, g=0, b=0]
+
+%D The next few macros are responsible for highlighting hyper
+%D links. The first one, \type{\showlocation}, is used in those
+%D situations where the typeface is handled by the calling
+%D macro.
+
+%D When we're dealing with pure page references, contrast
+%D colors are used when we are already at the page mentioned.
+
+\def\setlocationcolor#1% not grouped !
+ {\ifnum\referencepagestate=\plusone
+ \edef\askedcontrastcolor{\csname#1\c!contrastcolor\endcsname}%
+ \ifx\askedcontrastcolor\empty
+ \dosetcolorattribute{#1}\c!color
+ \else
+ \dosetcolorattribute{#1}\c!contrastcolor
+ \fi
+ \else % we could just set and if > 0 set again
+ \dosetcolorattribute{#1}\c!color
+ \fi}
+
+\def\setlocationfont#1%
+ {\dosetfontattribute{#1}\c!style}
+
+\def\setlocationattributes#1%
+ {\ifnum\referencepagestate=\plusone
+ \edef\askedcontrastcolor{\csname#1\c!contrastcolor\endcsname}%
+ \ifx\askedcontrastcolor\empty
+ \dosetcolorattribute{#1}\c!color
+ \else
+ \dosetcolorattribute{#1}\c!contrastcolor
+ \fi
+ \else % we could just set and if > 0 set again
+ \dosetcolorattribute{#1}\c!color
+ \fi
+ \dosetfontattribute{#1}\c!style}
+
+\def\setlocationcolorspec#1% \resolver
+ {\ifnum\referencepagestate=\plusone
+ \edef\askedcontrastcolor{#1\c!contrastcolor}%
+ \ifx\askedcontrastcolor\empty
+ \doactivatecolor{#1\c!color}%
+ \else
+ \doactivatecolor\askedcontrastcolor
+ \fi
+ \else
+ \doactivatecolor{#1\c!color}%
+ \fi}
+
+\setupinteraction
+ [\c!style=\v!bold,
+ \c!color=interactioncolor,
+ \c!contrastcolor=interactioncontrastcolor]
+
+%D Identity
+
+\def\scrn_identity_synchronize
+ {\ctxcommand{setupidentity{
+ title = \!!bs\interactionparameter\c!title\!!es,
+ subtitle = \!!bs\interactionparameter\c!subtitle\!!es,
+ author = \!!bs\interactionparameter\c!author\!!es,
+ creator = \!!bs ConTeXt - \contextversion\!!es,
+ date = \!!bs\interactionparameter\c!date\!!es,
+ keywords = \!!bs\interactionparameter\c!keyword\!!es,
+ }}}
+
+\appendtoks
+ \scrn_identity_synchronize
+\to \everysetupinteraction
+
+\setupinteraction
+ [\c!title=,
+ \c!subtitle=,
+ \c!author=,
+ \c!keyword=,
+ \c!date=]
+
+\protect \endinput
diff --git a/tex/context/base/scrn-int.lua b/tex/context/base/scrn-int.lua
deleted file mode 100644
index 7bb1a7a66..000000000
--- a/tex/context/base/scrn-int.lua
+++ /dev/null
@@ -1,114 +0,0 @@
-if not modules then modules = { } end modules ['scrn-int'] = {
- version = 1.001,
- comment = "companion to scrn-int.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-interactions = interactions or { }
-local interactions = interactions
-
-interactions.attachments = interactions.attachments or { }
-interactions.soundclips = interactions.soundclips or { }
-interactions.renderings = interactions.renderings or { }
-interactions.linkedlists = interactions.linkedlists or { }
-
-local attachments = interactions.attachments
-local soundclips = interactions.soundclips
-local renderings = interactions.renderings
-local linkedlists = interactions.linkedlists
-
-local jobpasses = job.passes
-
-function attachments.register(specification)
- if specification.label then
- specification.filename = specification.filename or specification.label
- specification.newname = specification.newname or specification.filename
- specification.title = specification.title or specification.filename
- specification.newname = file.addsuffix(specification.newname,file.extname(specification.filename))
- attachments[specification.label] = specification
- return specification
- end
-end
-
-function attachments.attachment(label)
- local at = attachments[label]
- if not at then
- interfaces.showmessage("interactions",6,label)
- return attachments.register { label = label }
- else
- return at
- end
-end
-
-function attachments.var(label,key)
- local at = attachments[label]
- context(at and at[key] or "")
-end
-
-function soundclips.register(specification)
- if specification.label then
- specification.filename = specification.filename or specification.label
- soundclips[specification.label] = specification
- return specification
- end
-end
-
-function soundclips.soundclip(label)
- local sc = soundclips[label]
- if not sc then
- -- todo: message
- return soundclips.register { label = label }
- else
- return sc
- end
-end
-
-function renderings.register(specification)
- if specification.label then
- renderings[specification.label] = specification
- return specification
- end
-end
-
-function renderings.rendering(label)
- local rn = renderings[label]
- if not rn then
- -- todo: message
- return renderings.register { label = label }
- else
- return rn
- end
-end
-
-function renderings.var(label,key)
- local rn = renderings[label]
- context(rn and rn[key] or "")
-end
-
--- linked lists
-
-function linkedlists.define(name)
- -- no need
-end
-
-function linkedlists.add(name)
- local tobesaved = jobpasses.gettobesaved(name)
- local collected = jobpasses.getcollected(name) or { }
- local currentlink = #tobesaved + 1
- local noflinks = #collected
- tobesaved[currentlink] = 0
- local f = collected[1] or 0
- local l = collected[noflinks] or 0
- local p = collected[currentlink-1] or f
- local n = collected[currentlink+1] or l
- context.setlinkproperties(currentlink,noflinks,f,p,n,l)
-end
-
-function linkedlists.enhance(name,n)
- local ll = jobpasses.gettobesaved(name)
- if ll then
- ll[n] = texcount.realpageno
- end
-end
diff --git a/tex/context/base/scrn-int.mkiv b/tex/context/base/scrn-int.mkiv
deleted file mode 100644
index cc25f48b2..000000000
--- a/tex/context/base/scrn-int.mkiv
+++ /dev/null
@@ -1,613 +0,0 @@
-%D \module
-%D [ file=scrn-int,
-%D version=1995.01.01,
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Interaction,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%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 Screen Macros / Interaction}
-
-\registerctxluafile{scrn-int}{1.001}
-
-\unprotect
-
-%D This is an update of \MKII\ code. In the process profiles and versions
-%D were removed as I never used them (although they were kind of cool at
-%D that time).
-
-% a bit complex due to papercomment (see imposition code)
-
-\newtoks\everysetupinteractionscreen
-
-\unexpanded\def\setupinteractionscreen
- {\dosingleempty\dosetupinteractionscreen}
-
-\def\dosetupinteractionscreen[#1]%
- {\getparameters[\??sc][#1]%
- \the\everysetupinteractionscreen}
-
-\def\synchronizepaperdimensionssimple % simple version
- {\bgroup
- \ifx\@@ppleft \empty
- \ifx\@@ppright \empty
- \ifx\@@pptop \empty
- \ifx\@@ppbottom \empty
- \ifx\@@pcstate\v!start
- \locationfalse\fi\else
- \locationfalse\fi\else
- \locationfalse\fi\else
- \locationfalse\fi\else
- \locationfalse\fi
- \iflocation % without screen settings
- \ctxlua{backends.codeinjections.setupcanvas {
- paperwidth = \number\paperwidth,
- paperheight = \number\paperheight
- }}%
- \else
- \ctxlua{backends.codeinjections.setupcanvas {
- paperwidth = \number\printpaperwidth,
- paperheight = \number\printpaperheight
- }}%
- \fi
- \egroup}
-
-\def\synchronizepaperdimensionscomplex % complex version
- {\bgroup
- \edef\@@scwidth {\@@scwidth}%
- \edef\@@scheight{\@@scheight}%
- \ifx\@@scwidth\v!fit
- \!!widtha\leftcombitotal
- \ifdim\backspace>\!!widtha\ifdim\backspace>\zeropoint\relax
- \advance\backspace -\!!widtha
- \fi\fi
- \advance\!!widtha\dimexpr\rightcombitotal+2\dimexpr\@@scbackspace+\@@schoroffset\relax\relax
- \else\ifx\@@scwidth\v!max
- \!!widtha\printpaperwidth
- \else
- \!!widtha\@@scwidth
- \fi\fi
- \ifx\@@scheight\v!fit
- \!!heighta\dimexpr\topheight+\topdistance\relax
- \ifdim\topspace>\!!heighta\ifdim\topspace>\zeropoint\relax
- \advance\topspace -\!!heighta
- \fi\fi
- \advance\!!heighta\dimexpr\makeupheight+\bottomdistance+\bottomheight+2\dimexpr\@@sctopspace+\@@scveroffset\relax\relax
- \else\ifx\@@scheight\v!max
- \!!heighta\printpaperheight
- \else
- \!!heighta\@@scheight
- \fi\fi
- \doif\@@scdelay\v!none{\let\@@scdelay\zerocountervalue}%
- \ifdim\!!widtha>\paperwidth\ifdim\!!widtha>\zeropoint
- \paperwidth\!!widtha
- \fi\fi
- \ifdim\!!heighta>\paperheight\ifdim\!!heighta>\zeropoint
- \paperheight\!!heighta
- \fi\fi
- \ctxlua{backends.codeinjections.setupcanvas {
- mode = "\@@scoption",
- % doublesided = \ifsinglesided false\else\ifdoublesided true\else false\fi\fi,
- singlesided = \ifsinglesided true\else false\fi,
- doublesided = \ifdoublesided true\else false\fi,
- leftoffset = \number\dimexpr\backoffset\relax,
- topoffset = \number\dimexpr\topoffset \relax,
- width = \number\dimexpr\!!widtha \relax,
- height = \number\dimexpr\!!heighta \relax,
- paperwidth = \number\paperwidth,
- paperheight = \number\paperheight
- }}%
- \egroup}
-
-\let\synchronizepaperdimensions \synchronizepaperdimensionscomplex
-
-\appendtoks
- \ifproductionrun
- \doifelse\@@pcstate\v!start
- {\let\synchronizepaperdimensions\synchronizepaperdimensionssimple}
- {\let\synchronizepaperdimensions\synchronizepaperdimensionscomplex}%
- \fi
-\to \everysetupinteractionscreen
-
-\appendtoks \synchronizepaperdimensions \to \everyshipout
-
-%D The next mechanism, linked lists, is quite old and
-%D is \MKIV'd for completeness. I will finish the
-%D confuguration part when I need it.
-
-% todo: a kind of button that gets a tag passed (\??tk)
-
-% \starttext
-% \setupinteraction[state=start]
-% \definelinkedlist[demo]
-% \dorecurse{10}{\linkedlistelement[demo]{link \recurselevel} \page}
-% \stoptext
-
-\def\linkedlistparameter #1{\csname\dolinkedlistparameter{\??lk\currentlinkedlist}#1\endcsname}
-\def\dolinkedlistparameter #1#2{\ifcsname#1#2\endcsname#1#2\else\expandafter\dolinkedlistparentparameter\csname#1\s!parent\endcsname#2\fi}
-\def\dolinkedlistparentparameter#1#2{\ifx#1\relax\s!empty\else\dolinkedlistparameter#1#2\fi}
-
-\unexpanded\def\definelinkedlist{\dodoubleargument\dodefinelinkedlist}
-\unexpanded\def\setuplinkedlist {\dodoubleargument\dosetuplinkedlist }
-\unexpanded\def\setuplinkedlists{\dosingleargument\dosetuplinkedlists}
-
-\def\dodefinelinkedlist[#1][#2]%
- {\ctxlua{interactions.linkedlists.define("#1")}%
- \getparameters[\??lk#1][\s!parent=\??lk,#2]}
-
-\def\dosetuplinkedlist[#1][#2]%
- {\getparameters[\??lk#1][#2]}
-
-\def\dosetuplinkedlists[#1]%
- {\getparameters[\??lk][#1]}
-
-\def\setlinkproperties#1#2#3#4#5#6%
- {\def\currentlink {#1}%
- \def\noflinks {#2}%
- \def\firstlink {#3}%
- \def\previouslink{#4}%
- \def\nextlink {#5}%
- \def\lastlink {#6}}
-
-\def\linkedlistelement[#1]#2% currently no view support
- {\dontleavehmode\hbox\bgroup
- #2%
- \iflocation
- \edef\currentlinkedlist{#1}%
- \ifcsname\??lk\currentlinkedlist\s!parent\endcsname
- \hskip\linkedlistparameter\c!distance
- \ctxlua{interactions.linklists.add("\currentlinkedlist")}%
- \expanded{\ctxlatelua{interactions.linklists.enhance("\currentlinkedlist",\currentlink)}}%
- \dogotosomepage {\??lk\currentlinkedlist}\gotobegincharacter \firstlink
- \ifnum\noflinks>\plustwo
- \dogotosomepage{\??lk\currentlinkedlist}\gobackwardcharacter\previouslink
- \dogotosomepage{\??lk\currentlinkedlist}\goforwardcharacter \nextlink
- \fi
- \dogotosomepage {\??lk\currentlinkedlist}\gotoendcharacter \lastlink
- \else
- \writestatus\m!interactions{no such linked list: \currentlinkedlist}%
- \fi
- \fi
- \egroup}
-
-\setuplinkedlists
- [\c!distance=.25em,
- \c!width=\v!fit,
- \c!location=\v!low,
- \c!color=\@@iacolor,
- \c!frame=\v!off,
- \c!background=,
- \c!backgroundcolor=]
-
-\def\koppeling {\linkedlistelement}
-\def\stelkoppelingenin {\setuplinkedlists}
-\def\definieerkoppeling{\definelinkedlist}
-
-%D Conditional page breaks:
-
-\def\screen
- {\dosingleempty\doscreen}
-
-\def\doscreen[#1]%
- {\iflocation\page[#1]\fi}
-
-%D Page transitions:
-
-\let\askedpagetransitions\empty
-
-\unexpanded\def\setuppagetransitions
- {\dosingleempty\dosetuppagetransitions}
-
-\def\dosetuppagetransitions[#1]%
- {\edef\askedpagetransitions{#1}}
-
-\def\setpagetransition
- {\iflocation \ifx\askedpagetransitions\empty \else
- \ctxlua{backends.codeinjections.setpagetransition{ n = "\askedpagetransitions", delay = "\@@scdelay" }}%
- \fi \fi}
-
-\prependtoks \setpagetransition \to \everyshipout
-
-\setuppagetransitions
- [\v!reset]
-
-%D Comments:
-
-\newbox\commentcollection
-\newbox\commentbox
-\newbox\commentboxone
-\newbox\commentboxtwo
-
-\def\raisedcommentanchors#1#2{#1{\hbox{\raise\strutht#2}}}
-
-\setvalue{\??cc:\c!location:\v!inmargin }{\raisedcommentanchors\inmargin }
-\setvalue{\??cc:\c!location:\v!leftedge }{\raisedcommentanchors\inleftedge }
-\setvalue{\??cc:\c!location:\v!rightedge }{\raisedcommentanchors\inrightedge }
-\setvalue{\??cc:\c!location:\v!leftmargin }{\raisedcommentanchors\inleftmargin }
-\setvalue{\??cc:\c!location:\v!rightmargin}{\raisedcommentanchors\inrightmargin}
-
-\let\flushcommentanchors\relax
-
-\def\doflushcommentanchors
- {\global\let\flushcommentanchors\relax
- \ifvoid\commentbox\else\dodoflushcommentanchors\fi} % in everypar so indirect
-
-\def\dodoflushcommentanchors
- {\executeifdefined{\??cc:\c!location:\@@cclocation}\hbox{\box\commentbox}}
-
-\unexpanded\def\setupcomment
- {\dodoubleargument\getparameters[\??cc]}
-
-\unexpanded\def\placecomments{\box\commentcollection} % when option=buffer
-
-\def\doinsertcomment#1%
- {\begingroup
- \doifelse\@@ccoption\v!max{\let\@@ccopen\s!true}{\let\@@ccopen\s!false}%
- \ctxlua{backends.codeinjections.presetsymbollist("\@@ccsymbol")}%
- % in between predefined symbols are dealt with
- \ctxlua{backends.codeinjections.registercomment {
- title = "\@@cctitle",
- width = \number\dimexpr\@@ccwidth \relax,
- height = \number\dimexpr\@@ccheight\relax,
- colormodel = \number\currentcolormodel,
- colorvalue = \thecolorattribute{\@@cccolor},
- open = \@@ccopen,
- symbol = "\@@ccsymbol",
- buffer = "#1",
- layer = "\@@cctextlayer"
- }}%
- \box\commentboxone
- \doif\@@ccoption\v!buffer
- {\setbox\scratchbox\vbox to \@@ccheight{\forgetall\vss\box\commentboxtwo}%
- \wd\scratchbox\@@ccwidth
- \global\setbox\commentcollection\vbox
- {\startoverlay{\box\commentcollection}{\box\scratchbox}\stopoverlay}}%
- \endgroup}
-
-\setvalue{\e!start\v!comment}{\dodoubleempty\dostartcomment}
-
-\def\dostartcomment[#1][#2]%
- {\bgroup
- \doifassignmentelse{#1}{\getparameters[\??cc][#1]}{\getparameters[\??cc][\c!title=#1,#2]}%
- \dostartbuffer[\v!comment\v!buffer][\v!comment\v!buffer][\e!start\v!comment][\e!stop\v!comment]}
-
-\unexpanded\def\stopcomment
- {\doif\@@ccstate\v!start
- {\global\let\flushcommentanchors\doflushcommentanchors
- \global\setbox\commentbox\frozenhbox
- {\hbox to \zeropoint{\struttedbox{\tbox{\doinsertcomment{\v!comment\v!buffer}}}\hss}%
- \hskip\ifvoid\commentbox\@@ccmargin\else\@@ccdistance\fi
- \box\commentbox}}%
- \egroup}
-
-\def\comment
- {\dodoubleempty\docomment}
-
-\def\docomment[#1][#2]#3%
- {\doif\@@ccstate\v!start
- {\hbox to \zeropoint
- {\doifassignmentelse{#1}{\getparameters[\??cc][#1]}{\getparameters[\??cc][\c!title=#1,#2]}%
- \hskip-\@@ccmargin
- \ctxlua{buffers.assign("\v!comment\v!buffer", \!!bs\detokenize{#3}\!!es)}%
- \struttedbox{\tbox{\doinsertcomment{\v!comment\v!buffer}}\hss}}}%
- \ignorespaces}
-
-% test
-%
-% \startcomment
-% hello beautiful\\world
-% \stopcomment
-%
-% test
-%
-% \startcomment[hello]
-% hello << eerste >>
-% beautiful
-% world
-% \stopcomment
-%
-% test
-%
-% \startcomment[hello][color=green,width=10cm,height=3cm]
-% hello \leftguillemot\ \'e\'erste \rightguillemot\
-% beautiful
-% world
-% \stopcomment
-%
-% test
-%
-% \startcomment[hello][color=red,width=4cm,height=3cm]
-% hello \leftguillemot\ \'e\'erste \rightguillemot\ test
-%
-% beautiful
-%
-% world
-% \stopcomment
-%
-% test
-%
-% \startcomment[symbol=Balloon]
-% Do we want this kind of rubish? And, why isn't this and
-% some more features related to text annotations so poorly
-% (actually not) documented? Anyhow, by providing this
-% functionality we demonstrate that \pdfTeX\ can do it. By
-% the way, it's funny that when in Acrobat we scale up the
-% text, the symbols scale down.
-% \stopcomment
-%
-% test
-%
-% \definesymbol [comment-normal][{\externalfigure[cow.pdf]}]
-% \definesymbol [comment-down] [{\externalfigure[cow.pdf]}]
-%
-% \def\CowSymbol#1#2%
-% {\scale
-% [\c!height=#1]
-% {\startMPcode
-% loadfigure "koe.mp" number 1 ;
-% refill currentpicture withcolor #2 ;
-% \stopMPcode}}
-%
-% \definesymbol [comment-normal]
-% [\CowSymbol{4ex}{red}]
-%
-% \definesymbol [comment-down]
-% [\CowSymbol{4ex}{green}]
-%
-% \setupcomment
-% [\c!symbol={comment-normal,comment-down},
-% \c!option=\v!buffer]
-%
-% \startcomment[hello]
-% oeps
-% \stopcomment
-%
-% test
-%
-% \setupcomment
-% [\c!symbol=normal,
-% \c!option=max,width=10cm]
-%
-% \startcomment[hello]
-% oeps
-% \stopcomment
-%
-% test
-
-\setupcomment
- [\c!state=\v!start,
- \c!margin=2.5em,
- \c!distance=1em,
- \c!width=.3\textwidth,
- \c!height=.2\textheight,
- \c!color=\@@iacolor,
- \c!title=,
- \c!space=\v!no,
- \c!symbol=\v!normal,
- \c!location=\v!inmargin,
- \c!option=,
- \c!textlayer=]
-
-%D Attachments:
-
-% \setupinteraction[state=start]
-%
-% \useattachment[test.tex]
-% \useattachment[whatever][test.tex]
-% \useattachment[whatever][newname][test.tex]
-% \useattachment[whatever][title][newname][test.tex]
-%
-% % \setupattachments[\c!symbol={symbol-normal,symbol-down}]
-%
-% \starttext \attachment[whatever] \stoptext
-
-\def\useattachment
- {\doquadrupleempty\douseattachment}
-
-\def\douseattachment[#1][#2][#3][#4]% tag title newname filename
- {\iffourthargument
- \dodouseattachment{#1}{#2}{#3}{#4}%
- \else\ifthirdargument
- \dodouseattachment{#1}{#2}{#2}{#3}%
- \else\ifsecondargument
- \dodouseattachment{#1}{#2}{#2}{#2}%
- \else
- \dodouseattachment{#1}{#1}{#1}{#1}%
- \fi\fi\fi}
-
-\def\dodouseattachment#1#2#3#4% tag title newname filename
- {\ctxlua{interactions.attachments.register{label="#1",title="#2",newname="#3",filename="#4"}}}
-
-\def\attachment
- {\dodoubleempty\doattachment}
-
-\def\doattachment[#1][#2]% [tag] [settings]
- {\iflocation
- \doif\@@atstate\v!start
- {\bgroup
- \setupattachments[#2]%
- \ctxlua{backends.codeinjections.presetsymbollist("\@@atsymbol")}%
- % we cannot yet ask for the wd/ht/dp of an xform else we could use those
- \setbox\scratchbox\hbox{\symbol[\lastpredefinedsymbol]}%
- \doif\@@atwidth \v!fit{\edef\@@atwidth {\the\wd\scratchbox}}%
- \doif\@@atheight\v!fit{\edef\@@atheight{\the\ht\scratchbox}}%
- \doif\@@atdepth \v!fit{\edef\@@atdepth {\the\dp\scratchbox}}%
- %
- \setbox\scratchbox\hbox
- {\getvalue{\??at:\@@atalternative}{\ctxlua{backends.codeinjections.attachfile{
- label = "#1",
- width = \number\dimexpr\@@atwidth \relax,
- height = \number\dimexpr\@@atheight\relax,
- depth = \number\dimexpr\@@atdepth \relax,
- color = "\@@atcolor",
- symbol = "\@@atsymbol",
- layer = "\@@attextlayer",
- }}}}%
- \wd\scratchbox\@@atwidth
- \ht\scratchbox\@@atheight
- \dp\scratchbox\@@atdepth
- \box\scratchbox
- \egroup}%
- \fi}
-
-\setvalue{\??at:\v!high}#1{\struttedbox{\tbox{#1}}}
-
-\unexpanded\def\setupattachments
- {\dodoubleempty\getparameters[\??at]}
-
-\setupattachments
- [\c!state=\v!start,
- \c!color=\@@iacolor,
- \c!textlayer=,
- \c!width=\v!fit,
- \c!height=\v!fit,
- \c!depth=\v!fit,
- \c!alternative=\v!high,
- \c!symbol=]
-
-%D Defining sound tracks:
-%D
-%D \starttyping
-%D \useexternalsoundtrack[label][file]
-%D \stoptyping
-%D
-%D associated actions: StartSound StopSound PauseSound ResumeSound
-%D
-%D Todo: like external figures, also search on path,
-%D although, they need to be present ar viewing time, so ...
-
-\def\useexternalsoundtrack
- {\dodoubleargument\douseexternalsoundtrack}
-
-\def\douseexternalsoundtrack[#1][#2]%
- {\ctxlua{interactions.soundclips.register{ label="#1", filename="#2" }}}
-
-\def\checksoundtrack#1% yet untested in mkiv (also move management to lua)
- {\iflocation
- \ctxlua{backends.nodeinjections.insertsound{
- label = "#1",
- repeat = "\@@sdoption", % not entirely ok but works
- }}%
- \fi}
-
-\unexpanded\def\setupexternalsoundtracks
- {\dodoubleargument\getparameters[\??sd]}
-
-\setupexternalsoundtracks
- [\c!option=]
-
-%D Multi Media:
-
-% todo: multiple instances, dus indirect
-
-\let\currentrendering\empty
-
-\definereference[StartCurrentRendering] [\v!StartRendering {\currentrendering}]
-\definereference[StopCurrentRendering] [\v!StopRendering {\currentrendering}]
-\definereference[PauseCurrentRendering] [\v!PauseRendering {\currentrendering}]
-\definereference[ResumeCurrentRendering][\v!ResumeRendering{\currentrendering}]
-
-\newcounter\nofexternalrenderings
-
-\def\useexternalrendering{\doquadrupleempty\douseexternalrendering}
-\def\setinternalrendering{\dodoubleempty \dosetinternalrendering}
-
-\def\douseexternalrendering[#1][#2][#3][#4]% tag mime file options
- {\ctxlua{interactions.renderings.register {
- kind = "external",
- label = "#1",
- mime = "#2",
- filename = "#3",
- options = "#4",
- }}}
-
-\def\dosetinternalrendering[#1][#2]% tag options {content}
- {\bgroup
- \dowithnextbox
- {\ctxlua{interactions.renderings.register {
- kind = "internal",
- label = "#1",
- mime = "IRO",
- filename = "#1",
- options = "#2",
- }}%
- \let\objectoffset\zeropoint
- \setobject{IRO}{#1}\hbox{\box\nextbox}%
- \egroup}%
- \hbox}
-
-\def\renderingtype #1{\ctxlua{interactions.renderings.var("#1","kind")}}
-\def\renderingoptions#1{\ctxlua{interactions.renderings.var("#1","options")}}
-
-\def\renderingwidth {8cm}
-\def\renderingheight {6cm}
-
-\unexpanded\def\definerenderingwindow
- {\dodoubleempty\dodefinerenderingwindow}
-
-\def\dodefinerenderingwindow[#1][#2]%
- {\presetlocalframed[\??rw#1]%
- \getparameters
- [\??rw#1]%
- [\c!openpageaction=,\c!closepageaction=,%
- \c!width=\renderingwidth,\c!height=\renderingheight,%
- #2]}
-
-\unexpanded\def\setuprenderingwindow
- {\dodoubleargument\dosetuprenderingwindow}
-
-\def\dosetuprenderingwindow[#1]%
- {\getparameters[\??rw#1]}
-
-\unexpanded\def\placerenderingwindow
- {\dodoubleempty\doplacerenderingwindow}
-
-\def\doplacerenderingwindow[#1][#2]%
- {\bgroup
- \edef\currentrendering{\ifsecondargument#2\else#1\fi}%
- \doifelse{\renderingtype\currentrendering}{internal} % an object
- {\getobjectdimensions{IRO}\currentrendering
- \edef\renderingheight{\the\dimexpr\objectheight+\objectdepth\relax}%
- \edef\renderingwidth{\objectwidth}%
- \dogetobjectreferencepage{IRO}\currentrendering\renderingpage}%
- {\def\renderingheight{\vsize}%
- \def\renderingwidth{\hsize}%
- \def\renderingpage{\realpageno}}%
- % create fall back if needed
- \ifcsname\??rw#1\c!width\endcsname
- \def\currentrenderingwindow{#1}%
- \else
- \let\currentrenderingwindow\s!default
- \definerenderingwindow[\currentrenderingwindow]%
- \fi
-% todo
-% \handlereferenceactions{\getvalue{\??rw\currentrenderingwindow\c!openpageaction }}\dosetuprenderingopenpageaction
-% \handlereferenceactions{\getvalue{\??rw\currentrenderingwindow\c!closepageaction}}\dosetuprenderingclosepageaction
- \localframed
- [\??rw\currentrenderingwindow][\c!offset=\v!overlay]%
- {\vfill
- \ctxlua{backends.codeinjections.insertrenderingwindow {
- label = "\currentrendering",
- width = \number\dimexpr\renderingwidth\relax,
- height = \number\dimexpr\renderingheight\relax,
- options = "\renderingoptions\currentrendering",
- page = \number\renderingpage,
- }}\hfill}%
- \egroup}
-
-\setupinteractionscreen
- [\c!width=\printpaperwidth,
- \c!height=\printpaperheight,
- \c!horoffset=\!!zeropoint,
- \c!veroffset=\!!zeropoint,
- \c!backspace=\backspace,
- \c!topspace=\topspace,
- \c!option=\v!auto,
- \c!delay=\v!none]
-
-\protect \endinput
diff --git a/tex/context/base/scrn-men.mkiv b/tex/context/base/scrn-men.mkiv
deleted file mode 100644
index 1e987f098..000000000
--- a/tex/context/base/scrn-men.mkiv
+++ /dev/null
@@ -1,629 +0,0 @@
-%D \module
-%D [ file=scrn-bar, % was part of scrn-int
-%D version=1995.01.01,
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Menus,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%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 Screen Macros / Menus}
-
-\unprotect
-
-% \startinteractionmenu[rechts]
-% \but [eerste] eerste \\
-% \txt hello world \\
-% \but [tweede] tweede \\
-% \nop \\
-% \but [tweede] tweede \\
-% \rul whow \\
-% \but [tweede] tweede \\
-% \raw hello world \\
-% \but [tweede] tweede \\
-% \com \vfill \\
-% \but [derde] derde \\
-% \stopinteractionmenu
-
-% \setupinteraction[menu=on,state=start]
-%
-% \defineinteractionmenuclass[test] [vertical]
-% \defineinteractionmenuclass[another][horizontal]
-%
-% \defineinteractionmenu[test] [left][state=start,width=4cm]
-% \defineinteractionmenu[another][top] [state=start,height=1cm]
-%
-% \startinteractionmenu[test]
-% \but [firstpage] test-a \\
-% \but [nextpage] test-b \\
-% \stopinteractionmenu
-%
-% \startinteractionmenu[another]
-% \but [firstpage] test-a \\
-% \but [nextpage] test-b \\
-% \stopinteractionmenu
-%
-% \setupheadertexts[{\interactionmenu[another]}]
-%
-% \starttext
-%
-% test \interactionmenu[test] \page
-% test \interactionmenu[test] \page
-%
-% \stoptext
-
-% ja : kader/achtergrond met tekst
-% leeg : kader/achtergrond maar geen tekst
-% nee : alleen ruimte reserveren
-% geen : helemaal weglaten
-%
-% \setupinteractionmenu[right][samepage=yes, unknownreference=yes]
-% \setupinteractionmenu[right][samepage=empty,unknownreference=empty]
-% \setupinteractionmenu[right][samepage=no, unknownreference=no]
-% \setupinteractionmenu[right][samepage=none, unknownreference=none]
-%
-% \startinteractionmenu[right]
-% \but [firstpage] first \\
-% \but [lastpage] last \\
-% \but [somepage] crap \\
-% \stopinteractionmenu
-
-%D Define menus:
-
-\def\setmenuparameter#1#2#3{\@EA\def\csname\??am#1:#2\endcsname{#3}}
-\def\letmenuparameter #1#2{\@EA\let\csname\??am#1:#2\endcsname}
-
-\def\menuparameter #1{\csname\domenuparameter{\??am\currentmenu:}#1\endcsname}
-\def\namedmenuparameter#1#2{\csname\domenuparameter{\??am #1:}#2\endcsname}
-\def\menuparameterhash #1{\domenuparameterhash {\??am\currentmenu:}#1}
-
-\def\domenuparameter #1#2{\ifcsname#1#2\endcsname#1#2\else\expandafter\domenuparentparameter \csname#1\s!parent\endcsname#2\fi}
-\def\domenuparameterhash#1#2{\ifcsname#1#2\endcsname #1\else\expandafter\domenuparentparameterhash\csname#1\s!parent\endcsname#2\fi}
-
-\def\domenuparentparameter #1#2{\ifx#1\relax\s!empty\else\domenuparameter #1#2\fi}
-\def\domenuparentparameterhash#1#2{\ifx#1\relax \else\domenuparameterhash#1#2\fi}
-
-\unexpanded\def\defineinteractionmenu
- {\dotripleempty\dodefineinteractionmenu}
-
-\def\dodefineinteractionmenu[#1][#2][#3]% [name] [location] [settings|parent] % right right vertical
- {\ifsecondargument
- \ifcsname\??am:\c!list:#2\endcsname \else
- \letvalueempty{\??am:\c!list:#2}%
- \fi
- \normalexpanded{\noexpand\addtocommalist{#1}\@EA\noexpand\csname\??am:\c!list:#2\endcsname}%
- \setvalue{\@@dodolistelement#1}{\def\dosomelistelement{\dodomenulistelement{#1}}}%
- \ifthirdargument
- \presetlocalframed[\??am#1:]%
- \doifassignmentelse{#3}
- {\doifelse{#1}{#2}
- {\getparameters[\??am#1:][\c!location=#2,\c!menu=,\s!parent=\??am,#3]}
- {\getparameters[\??am#1:][\c!location=#2,\c!menu=,\s!parent=\??am#2:,#3]}}%
- {\doifelsenothing{#3}
- {\getparameters[\??am#1:][\c!location=#2,\c!menu=,\s!parent=\??am]}
- {\getparameters[\??am#1:][\c!location=#2,\c!menu=,\s!parent=\??am#3:]}}%
- \else
- \getparameters[\??am#1:][\c!location=#2,\c!menu=,\s!parent=\??am#2:]%
- \fi
- \else
- \getparameters[\??am#1:][\s!parent=\??am]% simple cloning, like vertical
- \fi}
-
-\def\currentmenulist{\ifcsname\??am:\c!list:\currentmenu\endcsname\csname\??am:\c!list:\currentmenu\endcsname\fi}
-
-%D Setup menus:
-
-\unexpanded\def\setupinteractionmenu
- {\dodoubleargument\dosetupinteractionmenu}
-
-\def\dosetupinteractionmenu[#1][#2]%
- {\def\docommand##1{\getparameters[\??am##1:][#2]}%
- \processcommalist[#1]\docommand}
-
-\unexpanded\def\setupinteractionmenus[#1]%
- {\getparameters[\??am][#1]}
-
-%D Fill menus:
-
-\normalexpanded{\long\def\expandafter\noexpand\csname\e!start\v!interactionmenu\endcsname[#1]#2\expandafter\noexpand\csname\e!stop\v!interactionmenu\endcsname}%
- {\long\setmenuparameter{#1}\c!menu{\dointeractionmenu{#1}{#2}}}
-
-\def\resetinteractionmenu[#1]%
- {\letmenuparameter{#1}\c!menu\empty}
-
-%D Check if menus permitted:
-
-\newif\iflocationmenupermitted
-
-\def\testinteractionmenu
- {\iflocation
- \doifelse\@@iamenu\v!on
- {\doifelse{\menuparameter\c!state}\v!start
- {\global\locationmenupermittedtrue}
- {\global\locationmenupermittedfalse}}
- {\global\locationmenupermittedfalse}%
- \else
- \global\locationmenupermittedfalse
- \fi}
-
-%D Placement of menus:
-
-\def\interactionmenus[#1]% location
- {\iflocation
- \csname\??am:\c!menu:#1\endcsname
- \fi}
-
-\setvalue{\??am:\c!menu :\v!left }{\horizontalinteractionmenu\v!left \leftedgewidth }
-\setvalue{\??am:\c!menu :\v!right }{\horizontalinteractionmenu\v!right \rightedgewidth}
-\setvalue{\??am:\c!menu :\v!top }{\verticalinteractionmenu \v!top \topheight }
-\setvalue{\??am:\c!menu :\v!bottom}{\verticalinteractionmenu \v!bottom\bottomheight }
-
-\setvalue{\??am:\c!command:\v!right }{\@@amvbox{}\rightedgewidth}
-\setvalue{\??am:\c!command:\v!left }{\@@amvbox{}\leftedgewidth }
-\setvalue{\??am:\c!command:\v!top }{\@@amhbox{}\topheight }
-\setvalue{\??am:\c!command:\v!bottom}{\@@amhbox{}\bottomheight }
-
-\def\dointeractionmenu#1#2%
- {\edef\currentmenu{#1}%
- \getvalue{\??am:\c!command:\menuparameter\c!location}\currentmenu{#2}}
-
-\unexpanded\def\interactionmenu[#1]%
- {\def\currentmenu{#1}%
- \menuparameter\c!menu}
-
-\newdimen \intermenudistance
-\newdimen \finalmenuwidth
-\newdimen \finalmenuheight
-
-\newcounter\currentamposition % better \currentmenuposition
-\newtoks \everysetmenucommands
-
-\def\horizontalinteractionmenu#1#2% location vhsize before/after
- {\ifdim#2>\zeropoint
- \edef\currentmenu{#1}%
- \finalmenuwidth#2\relax
- \horizontalinteractionmenuindeed
- \fi}
-
-\def\verticalinteractionmenu#1#2%
- {\ifdim#2>\zeropoint
- \edef\currentmenu{#1}%
- \finalmenuheight#2\relax
- \verticalinteractionmenuindeed
- \fi}
-
-\def\horizontalinteractionmenuindeed
- {\global\intermenudistance\zeropoint
- \setbox\scratchbox\hbox
- {\processcommacommand[\currentmenulist]\somehorizontalinteractionmenu}%
- \wd\scratchbox\finalmenuwidth\relax
- \box\scratchbox}
-
-\def\verticalinteractionmenuindeed
- {\global\intermenudistance\zeropoint
- \setbox\scratchbox\vbox
- {\processcommacommand[\currentmenulist]\someverticalinteractionmenu}%
- \ht\scratchbox\finalmenuheight
- \dp\scratchbox\zeropoint
- \box\scratchbox}
-
-\def\somehorizontalinteractionmenu#1%
- {\begingroup
- \edef\currentmenu{#1}%
- \doifnot{\menuparameter\c!state}\v!none
- {\hskip\intermenudistance
- \setbox\scratchbox\hbox to \finalmenuwidth
- {\menuparameter\c!left
- \interactionmenu[#1]%
- \menuparameter\c!right}%
- \doifelse{\menuparameter\c!distance}\v!overlay
- {\global\intermenudistance\zeropoint
- \wd\scratchbox\zeropoint}%
- {\global\intermenudistance\menuparameter\c!distance}%
- \box\scratchbox}%
- \endgroup}
-
-\def\someverticalinteractionmenu#1%
- {\begingroup
- \edef\currentmenu{#1}%
- \doifnot{\menuparameter\c!state}\v!none
- {\vskip\intermenudistance
- \setbox\scratchbox\vbox to \finalmenuheight
- {\menuparameter\c!before
- \interactionmenu[#1]%
- \menuparameter\c!after}%
- \doifelse{\menuparameter\c!distance}\v!overlay
- {\global\intermenudistance\zeropoint
- \offinterlineskip
- \dp\scratchbox\zeropoint
- \ht\scratchbox\zeropoint}%
- {\global\intermenudistance\menuparameter\c!distance}%
- \box\scratchbox}%
- \endgroup}
-
-% don't change skipping, this one works! \showcomposition removed
-
-\def\@@amhbox#1#2#3#4% #1 obsolete, #3 is redundant
- {\edef\currentmenu{#3}%
- \testinteractionmenu
- \iflocationmenupermitted
- \begingroup
- \forgetall
- \scratchdimen\dimexpr\makeupwidth+\pagebackgroundhoffset*2-\menuparameter\c!leftoffset-\menuparameter\c!rightoffset\relax
- \setbox\scratchbox\hbox to \scratchdimen
- {\executeamboxcommands{#3}{#4}\c!left\c!middle\c!right}%
- \setbox\scratchbox\hbox{\dowholemenuposition{#3}{\box\scratchbox}}% cannot happen in previous due to align
- \wd\scratchbox\makeupwidth % geen \ht=#2 setting (yet)
- \hskip\dimexpr-\pagebackgroundhoffset+\menuparameter\c!leftoffset\relax
- \box\scratchbox
- \endgroup
- \fi}
-
-\def\@@amvbox#1#2#3#4% #1 obsolete, #3 is redundant
- {\edef\currentmenu{#3}%
- \testinteractionmenu
- \iflocationmenupermitted
- \bgroup
- \forgetall
- \scratchdimen\dimexpr\textheight+\pagebackgroundvoffset*2+\pagebackgrounddepth-\menuparameter\c!topoffset-\menuparameter\c!bottomoffset\relax
- \setbox\scratchbox\vbox to \scratchdimen
- {\restorestandardblank % todo: vspacing
- \hsize#2\relax
- \executeamboxcommands{#3}{#4}\c!before\c!inbetween\c!after}%
- % strange: when we mnake this a hbox the content disappears
- \setbox\scratchbox\vbox{\dowholemenuposition{#3}{\box\scratchbox}}% cannot happen in previous due to align
- \setbox\scratchbox\vbox
- {\ht\scratchbox\zeropoint
- \vskip\dimexpr-\pagebackgroundvoffset+\menuparameter\c!topoffset\relax
- \box\scratchbox
- \vskip\pagebackgroundvoffset}% overbodig
- \ht\scratchbox\textheight
- \wd\scratchbox#2\relax
- \box\scratchbox
- \egroup
- \fi}
-
-\def\executeamboxcommands#1#2#3#4#5%
- {\begingroup
- \edef\currentmenu{#1}%
- \menuparameter#3\relax
- \setamboxcommands{#1}{#4}%
- \ignorespaces#2\unskip
- \menuparameter#5\relax
- \endgroup}
-
-\def\setamboxcommands#1#2%
- {\edef\currentmenu{#1}%
- \edef\betweenmenu{#2}%
- \doglobal\newcounter\currentamposition
- \the\everysetmenucommands}
-
-\def\addsomemenuitem#1%
- {\dontleavehmode
- \begingroup
- \ignorespaces#1\unskip\relax
- \ifconditional\skippedmenuitem \else
- \menuparameter\betweenmenu
- \fi
- \endgroup
- \ignorespaces}
-
-%D This can save complicated menu macros when one want to
-%D keep control over parts of a menu (i.e.\ turn them on and
-%D off). We could have achieved something similar with modes.
-
-\def\local@@ambox#1#2#3#4% don't change skipping, this one works!
- {\begingroup
- \edef\currentmenu{#3}%
- \iflocationmenupermitted
- \executeamboxcommands{#3}{#4}\c!before\c!inbetween\c!after
- \fi
- \endgroup}
-
-\def\includemenu[#1]%
- {\begingroup
- \edef\currentmenu{#1}%
- \doif{\menuparameter\c!state}\v!local
- {\letmenuparameter\currentmenu\c!state\v!start
- \let\@@amvbox\local@@ambox
- \let\@@amhbox\local@@ambox
- \menuparameter\c!menu}%
- \endgroup}
-
-%D The menu commands:
-
-% to be redone, using parent inheritance instead
-
-% ja : kader/achtergrond met tekst
-% leeg : kader/achtergrond maar geen tekst
-% nee : alleen ruimte reserveren
-% geen : helemaal weglaten
-
-\newconditional\skippedmenuitem
-\newconditional\usemenuclick
-
-\def\dosetlocationboxcontent#1[#2]#3[#4]% to be checked
- {\global\setfalse\skippedmenuitem
- \setbox\locationbox\hbox{\localframed[#1][#2]{#3}}%
- \ifconditional\usemenuclick
- \gotobox{\box\locationbox}[#4]%
- \else
- \box\locationbox
- \fi}
-
-\def\dosetlocationboxempty#1[%
- {\dosetlocationboxcontent{#1}[\c!empty=\v!yes,}
-
-\def\dosetlocationboxno#1[%
- {\dosetlocationboxcontent{#1}[\c!empty=\v!yes,\c!frame=,\c!background=,}
-
-\def\dosetlocationboxnone#1[#2]#3[#4]%
- {\global\settrue\skippedmenuitem}
-
-% make two sub macros
-
-% \dosetfontattribute {#1}{#2}%
-% \dosetcolorattribute{#1}{#3}%
-
-\def\locboxyesinject
- {\ctxlua{structures.references.injectcurrentset(nil,nil)}}
-
-\def\locboxyesnormal#1#2#3%
- {\hbox attr \referenceattribute \lastreferenceattribute {\localframed[#1][#2]{#3}}}
-
-\def\locboxyescontrast#1#2#3%
- {\hbox attr \referenceattribute \lastreferenceattribute {\localframed[#1][#2,\c!color=\menuparameter\c!contrastcolor]{#3}}}
-
-\def\locboxyesempty#1#2#3%
- {\localframed[#1][\c!empty=\v!yes,#2]{#3}}
-
-\def\locboxyesnothing#1#2#3%
- {\localframed[#1][\c!empty=\v!yes,\c!frame=,\c!background=,#2]{#1}}
-
-\def\setlocationboxyes#1[#2]#3[#4]% needs to be split as the attr is not applicable to the box
- {\begingroup
- \settrue\usemenuclick
- \global\setfalse\skippedmenuitem
- \attribute\referenceattribute\attributeunsetvalue
- \doifreferencefoundelse{#4}
- {\analyzecurrentreference % we need to act on the state
- \ifcase\referencepagestate
- % something else than a page reference
- \locboxyesinject
- \locboxyesnormal{#1}{#2}{#3}%
- \else
- \ifcase\csname\??am:\c!location:\menuparameter\c!samepage\endcsname\relax
- % yes: same page or not ... todo
- \locboxyesinject
- \ifnum\referencepagestate=\plusone % same page
- \locboxyescontrast{#1}{#2}{#3}%
- \else % elsewhere
- \locboxyesnormal{#1}{#2}{#3}%
- \fi
- \or
- % empty but frame: no click
- \ifnum\referencepagestate=\plusone % same page
- \locboxyesempty{#1}{#2}{#3}
- \else % elsewhere
- \locboxyesinject
- \locboxyesnormal{#1}{#2}{#3}%
- \fi
- \or
- % empty no frame: no
- \ifnum\referencepagestate=\plusone % same page
- \locboxyesnothing{#1}{#2}{#3}%
- \else % elsewhere
- \locboxyesinject
- \locboxyesnormal{#1}{#2}{#3}%
- \fi
- \or
- % nothing at all
- \global\settrue\skippedmenuitem
- \fi
- \fi}%
- {\ifcase\csname\??am:\c!location:\menuparameter\c!unknownreference\endcsname\relax
- \localframed[#1][#2]{#3}%
- \or
- \locboxyesempty{#1}{#2}{#3}
- \or
- \locboxyesnothing{#1}{#2}{#3}%
- \or
- \global\skippedmenuitemtrue
- \fi}%
- \endgroup}
-
-\def\setlocationboxraw#1[#2]#3[#4]%
- {\localframed[#1][#2]{#3}}
-
-\def\setlocationnop#1[#2]#3%
- {\localframed[#1][#2]{#3}}
-
-\def\menu@raw[#1]#2\\%
- {\addsomemenuitem{\gotobox{\ignorespaces#2\unskip}[#1]}}
-
-\def\menu@but[#1]#2\\%
- {\addsomemenuitem{\domenuitemposition\currentmenu{#1}{\setlocationboxyes{\??am\currentmenu:}[]{\ignorespaces#2\unskip}[#1]}}}
-
-\def\menu@got[#1]#2\\%
- {\addsomemenuitem{\setlocationboxyes{\??am\currentmenu:}[\c!frame=\v!off,\c!background=]{\ignorespaces#2\unskip}[#1]}}
-
-\def\menu@nop#1\\%
- {\addsomemenuitem{\setlocationboxraw{\??am\currentmenu:}[\c!frame=\v!off,\c!background=,\c!empty=\v!yes]{\ignorespaces#1\unskip}[]}}
-
-\def\menu@txt#1\\%
- {\addsomemenuitem{\localframed[\??am\currentmenu:][\c!frame=\v!off,\c!background=]{\ignorespaces#1\unskip}}}
-
-\def\menu@rul#1\\%
- {\addsomemenuitem{\localframed[\??am\currentmenu:][]{\ignorespaces#1\unskip}}}
-
-\def\menu@com#1\\%
- {\ignorespaces#1\unskip\ignorespaces}
-
-\appendtoks
- \let\raw\menu@raw \let\but\menu@but \let\got\menu@got \let\nop\menu@nop
- \let\txt\menu@txt \let\rul\menu@rul \let\com\menu@com
-\to \everysetmenucommands
-
-\ifdefined\domenuitemposition \else \let\domenuitemposition \gobbletwoarguments \fi
-\ifdefined\dowholemenuposition \else \let\dowholemenuposition\gobbleoneargument \fi
-
-%D We also need an explicit position control some day. I'll
-%D do that when I need it. [The stacking order.]
-
-% [name] [location]
-% [name] [location] [pars]
-
-\expandafter\let\csname\??am:\c!location:\v!yes \endcsname\zerocount
-\expandafter\let\csname\??am:\c!location:\v!empty \endcsname\plusone
-\expandafter\let\csname\??am:\c!location:\v!no \endcsname\plustwo
-\expandafter\let\csname\??am:\c!location:\v!none \endcsname\plusthree
-\expandafter\let\csname\??am:\c!location:\v!normal \endcsname\plusone % default
-\expandafter\let\csname\??am:\c!location:\s!default\endcsname\plusone % default
-\expandafter\let\csname\??am:\c!location:\s!empty \endcsname\plusone % default
-
-\def\dodomenulistelement#1#2#3#4#5#6#7%
- {\addsomemenuitem{\domenuitemposition\currentmenu{internal(#3)}%
- {\setlocationboxyes{\??am\currentmenu:}[]{\limitatetext{#5}{\namedlistparameter{#2}\c!maxwidth}{\unknown}}[internal(#3)]}}}
-
-\unexpanded\def\menubutton
- {\dodoubleempty\domenubutton}
-
-\def\domenubutton[#1]%
- {\iffirstargument
- \ifsecondargument
- \@EAEAEA\domenubuttonB
- \else
- \doifassignmentelse{#1}
- {\@EAEAEA\domenubuttonC}
- {\@EAEAEA\domenubuttonD}%
- \fi
- \else
- \@EA\domenubuttonA
- \fi[#1]}
-
-\def\domenubuttonA[#1][#2]#3[#4]{\setlocationboxyes \??bt[]{#3}[#4]} % normal button, no parameters
-\def\domenubuttonB[#1][#2]#3[#4]{\setlocationboxyes{\??am#1:}[#2]{#3}[#4]} % menu button, with parameters
-\def\domenubuttonC[#1][#2]#3[#4]{\setlocationboxyes \??bt[#1]{#3}[#4]} % normal button, with parameters
-\def\domenubuttonD[#1][#2]#3[#4]{\setlocationboxyes {\??am#1:}[]{#3}[#4]} % menu button, no parameters
-
-\def\menubox
- {\dodoubleempty\domenubox}
-
-\def\domenubox[#1][#2]#3%
- {\bgroup
- \let\setlocationboxyes\setlocationboxraw
- \domenubutton[#1][#2]#3[]%
- \egroup}
-
-% jammer, tussen/midden had erin gemoeten; \c!commando toevoegen
-
-\def\registermenucommand#1%
- {{\textonly\noindent#1\space}} % no math switching
-
-\def\doregistermenubuttons[#1][#2]% [menu id] [register]
- {\bgroup
- \ifsecondargument
- \setupinteractionmenu[#1][\c!unknownreference=\v!yes,\c!samepage=\v!yes]%
- \def\docommand##1{\registermenucommand{\menubutton[#1]{##1}[#2:##1]}}%
- \else
- \def\docommand##1{\registermenucommand{\button[\c!unknownreference=\v!yes,\c!samepage=\v!yes]{##1}[#1:##1]}}%
- \fi
- \handletokens abcdefghijklmnopqrstuvwxyz\with\docommand % moet anders
- \egroup}
-
-\def\registermenubuttons
- {\dodoubleempty\doregistermenubuttons}
-
-\defineinteractionmenu [\v!vertical] % we happen to know that this works out ok (just a setup set)
-\defineinteractionmenu [\v!horizontal] % we happen to know that this works out ok (just a setup set)
-
-\defineinteractionmenu [\v!right ] [\v!right ] [\v!vertical ] % we share a setup set
-\defineinteractionmenu [\v!left ] [\v!left ] [\v!vertical ] % we share a setup set
-\defineinteractionmenu [\v!top ] [\v!top ] [\v!horizontal] % we share a setup set
-\defineinteractionmenu [\v!bottom] [\v!bottom] [\v!horizontal] % we share a setup set
-
-\setupinteractionmenus
- [\c!offset=.25em,
- \c!position=\v!no,
- \c!frame=\v!on,
- \c!background=,
- \c!backgroundcolor=,
- \c!foregroundstyle=\menuparameter\c!style,
- \c!foregroundcolor=\menuparameter\c!color,
- \c!style=\@@iastyle,
- \c!color=\@@iacolor,
- \c!contrastcolor=\@@iacontrastcolor,
- \c!state=\v!start,
- \c!samepage=\v!yes,
- \c!unknownreference=\v!empty,
- \c!distance=\bodyfontsize, % 12pt
- \c!topoffset=\zeropoint,
- \c!bottomoffset=\zeropoint,
- \c!leftoffset=\zeropoint,
- \c!rightoffset=\zeropoint]
-
-\setupinteractionmenu
- [\v!vertical] % not really a menu
- [\c!before=,
- \c!after=\vfil,
- \c!inbetween=\blank,
- \c!left=\hss,
- \c!right=\hss,
- \c!height=\v!broad]
-
-\setupinteractionmenu
- [\v!horizontal] % not really a menu
- [\c!before=\vss,
- \c!after=\vss,
- \c!middle=\hfil,
- \c!width=\v!fit,
- \c!height=\v!broad]
-
-\setupinteractionmenu[\v!left ][\c!width=\leftedgewidth ]
-\setupinteractionmenu[\v!right ][\c!width=\rightedgewidth]
-% \setupinteractionmenu[\v!top ] [\c!height=\topheight ]
-% \setupinteractionmenu[\v!bottom] [\c!height=\bottomheight ]
-
-\unexpanded\def\placeleftedgetextblock % Is \hss/\hsize really needed here? (check outer level and settings)
- {\hbox to \leftedgewidth{\hsize\leftedgewidth\hss\interactionmenus[\v!left]}}
-
-\unexpanded\def\placerightedgetextblock % Is \hss/\hsize really needed here? (check outer level and settings)
- {\hbox to \rightedgewidth{\hsize\rightedgewidth\interactionmenus[\v!right]\hss}}
-
-\unexpanded\def\placetoptextblock
- {\vbox to \topheight
- {\vsize\topheight
- \csname\??tk\v!top\c!before\endcsname
- \interactionmenus[\v!top]%
- \csname\??tk\v!top\c!after\endcsname
- \kern\zeropoint}}
-
-\unexpanded\def\placebottomtextblock
- {\vbox to \bottomheight
- {\vsize\bottomheight
- \csname\??tk\v!bottom\c!before\endcsname
- \interactionmenus[\v!bottom]%
- \csname\??tk\v!bottom\c!after\endcsname
- \kern\zeropoint}}
-
-\ifdefined\leftedgetextcontent
-
- \appendtoks \iflocation\placeleftedgetextblock \hskip-\leftedgewidth \fi\to \leftedgetextcontent
- \appendtoks \iflocation\placerightedgetextblock \hskip-\rightedgewidth \fi\to \rightedgetextcontent
- \appendtoks \iflocation\placetoptextblock \vskip-\topheight \fi\to \toptextcontent
- \appendtoks \iflocation\placebottomtextblock \vskip-\bottomheight \fi\to \bottomtextcontent
-
-\fi
-
-%D Enable and disable menus \unknown\ obsolete:
-
-\def\gobbletwoparameters[#1][#2]{}
-
-\def\disableinteractionmenu{\dodoubleempty\gobbletwoparameters}
-\def\enableinteractionmenu {\dodoubleempty\gobbletwoparameters}
-
-\protect \endinput
diff --git a/tex/context/base/scrn-nav.mkiv b/tex/context/base/scrn-nav.mkiv
deleted file mode 100644
index 7b8fbdfa7..000000000
--- a/tex/context/base/scrn-nav.mkiv
+++ /dev/null
@@ -1,258 +0,0 @@
-%D \module
-%D [ file=scrn-nav,
-%D version=1998.01.15,
-%D title=\CONTEXT\ Screen Macros,
-%D subtitle=Navigation,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%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 Screen Macros / Navigation}
-
-\unprotect
-
-%D Support for interactive document is very present in
-%D \CONTEXT\ and interwoven in many modules. This means that in
-%D this module, where we deal with some common navigational
-%D features, there will be quite some forward references.
-%D
-%D The current support in \MKIV\ is mostly the same as in
-%D \MKII\ and the old files have some more detailed
-%D (sometimes historic) information.
-
-%D There is no interaction at all unless enabled by saying:
-%D
-%D \starttyping
-%D \setupinteraction[state=start]
-%D \stoptyping
-%D
-%D The other settings are:
-%D
-%D \showsetup{setupinteraction}
-
-% use with care, no checking done
-
-\def\setinteractionparameter#1#2%
- {\expandafter\def\csname\??ia#1\endcsname{#2}}
-
-\def\resetinteractionparameter#1%
- {\expandafter\let\csname\??ia#1\endcsname\empty}
-
-\newtoks\everysetupinteraction
-
-\unexpanded\def\setupinteraction
- {\dosingleargument\dodosetupinteraction}
-
-\def\dodosetupinteraction[#1]% % \dosetupinteraction == special
- {\getparameters[\??ia][#1]%
- \the\everysetupinteraction}
-
-% todo, move partial append to where the action happens
-
-\appendtoks
- \doifelse\@@iastate\v!start
- {\iflocation\else
- \showmessage\m!interactions2{(page mode: \@@iapage)}%
- \global\locationtrue
- \fi}%
- {\iflocation
- \showmessage\m!interactions3{(page mode: \@@iapage)}%
- \global\locationfalse
- \fi}%
- \iflocation
- \setsystemmode \v!interaction
- \else
- \resetsystemmode\v!interaction
- \fi
- \doifsomething\@@iacalculate
- {\doregistercalculationset\@@iacalculate}%
- \doifelse\@@iastrut \v!yes \settrue \setfalse \uselocationstrut
- \doifelse\@@iaclick \v!yes \settrue \setfalse \highlighthyperlinks
- \doifelse\@@iadisplay\v!new \settrue \setfalse \gotonewwindow
- \doifnot \@@iapage \v!no \dosetpagedestinations
-\to \everysetupinteraction
-
-\def\dosetpagedestinations
- {\ctxlua{structures.references.setinnermethod("\@@iapage")}}
-
-\def\synchronizebackendidentity
- {\ctxlua{backends.codeinjections.setupidentity{
- title = \!!bs\@@iatitle\!!es,
- subject = \!!bs\@@iasubtitle\!!es,
- author = \!!bs\@@iaauthor\!!es,
- creator = \!!bs ConTeXt - \contextversion\!!es,
- date = \!!bs\@@iadate\!!es,
- keywords = \!!bs\@@iakeyword\!!es,
- }}}
-
-\appendtoks
- \synchronizebackendidentity
-\to \everyfirstshipout
-
-%D We have to make sure of some settings:
-
-\def\dolocationstartup
- {\iflocation
- \donefalse
- \ifx\@@iaopenaction\empty \else \donetrue
- \ctxlua{structures.references.checkopendocumentactions("\@@iaopenaction")}%
- \ctxlua{structures.references.expandcurrent()}%
- \fi
- \ifx\@@iacloseaction\empty \else \donetrue
- \ctxlua{structures.references.checkclosedocumentactions("\@@iacloseaction")}%
- \ctxlua{structures.references.expandcurrent()}%
- \fi
- \ifdone
- \ctxlua{structures.references.flushdocumentactions()}%
- \fi
- \global\let\dolocationstartup\relax
- \fi}
-
-\def\dolocationpagecheck
- {\iflocation
- \donefalse
- \ifx\@@iaopenpageaction\empty \else \donetrue
- \ctxlua{structures.references.checkopenpageactions("\@@iaopenpageaction")}%
- \ctxlua{structures.references.expandcurrent()}%
- \fi
- \ifx\@@iaclosepageaction\empty \else \donetrue
- \ctxlua{structures.references.checkclosepageactions("\@@iaclosepageaction")}%
- \ctxlua{structures.references.expandcurrent()}%
- \fi
- \ifdone
- \ctxlua{structures.references.flushpageactions()}%
- \fi
- \fi}
-
-\appendtoks \dolocationstartup \to \everyshipout
-\appendtoks \dolocationpagecheck \to \everyshipout
-
-%D As long as there a natural feeling of what can be considered
-%D hyper active or not, we have to tell users where they can
-%D possibly click. We've already seen a few macros that deal
-%D with this visualization, something we definitely do not let
-%D up to the viewer. One way of telling is using a distinctive
-%D typeface, another way is using color.
-%D
-%D There are two colors involved: one for normal hyperlinks,
-%D and one for those that point to the currentpage, the
-%D contrast color.
-
-\definecolor [interactioncolor] [r=0, g=.6, b=0]
-\definecolor [interactioncontrastcolor] [r=.8, g=0, b=0]
-
-\definecolor [interactiekleur] [interactioncolor]
-\definecolor [interactiecontrastkleur] [interactioncontrastcolor]
-
-%D The next few macros are responsible for highlighting hyper
-%D links. The first one, \type{\showlocation}, is used in those
-%D situations where the typeface is handled by the calling
-%D macro.
-
-%D When we're dealing with pure page references, contrast
-%D colors are used when we are already at the page mentioned.
-
-\def\setlocationcolor#1% not grouped !
- {\ifnum\referencepagestate=\plusone
- \edef\askedcontrastcolor{\csname#1\c!contrastcolor\endcsname}%
- \ifx\askedcontrastcolor\empty
- \dosetcolorattribute{#1}\c!color
- \else
- \dosetcolorattribute{#1}\c!contrastcolor
- \fi
- \else % we could just set and if > 0 set again
- \dosetcolorattribute{#1}\c!color
- \fi}
-
-\def\setlocationfont#1%
- {\dosetfontattribute{#1}\c!style}
-
-\def\setlocationattributes#1%
- {\ifnum\referencepagestate=\plusone
- \edef\askedcontrastcolor{\csname#1\c!contrastcolor\endcsname}%
- \ifx\askedcontrastcolor\empty
- \dosetcolorattribute{#1}\c!color
- \else
- \dosetcolorattribute{#1}\c!contrastcolor
- \fi
- \else % we could just set and if > 0 set again
- \dosetcolorattribute{#1}\c!color
- \fi
- \dosetfontattribute{#1}\c!style}
-
-\def\setlocationcolorspec#1% \resolver
- {\ifnum\referencepagestate=\plusone
- \edef\askedcontrastcolor{#1\c!contrastcolor}%
- \ifx\askedcontrastcolor\empty
- \doactivatecolor{#1\c!color}%
- \else
- \doactivatecolor\askedcontrastcolor
- \fi
- \else
- \doactivatecolor{#1\c!color}%
- \fi}
-
-%D delayed ...
-
-\def\enableinteractivereferences
- {\ifproductionrun
- \ctxlua{structures.references.enableinteraction()}%
- \globallet\enableinteractivereferences\relax
- \fi}
-
-\appendtoks
- \enableinteractivereferences
-\to \everysetupinteraction
-
-%D More tokens are spend when we want both typeface and color
-%D highlighting.
-
-\def\@@iatimestamp
- {\the\normalyear
- \ifnum\normalmonth<10 0\fi\the\normalmonth
- \ifnum\normalday <10 0\fi\the\normalday}
-
-\setupinteraction % start fit page and reset form
- [\c!state=\v!stop,
- \c!page=\v!no,
- \c!click=\v!yes,
- \c!openaction=,
- \c!closeaction=,
- \c!openpageaction=,
- \c!closepageaction=,
- \c!display=\v!normal,
- \c!focus=\v!fit,
- \c!menu=\v!off,
- \c!style=\v!bold,
- \c!calculate=,
- \c!strut=\v!yes,
- \c!split=\v!yes,
- \c!color=interactioncolor,
- \c!contrastcolor=interactioncontrastcolor,
- \c!symbolset=,
- \c!width=1em,
- \c!height=\!!zeropoint,
- \c!depth=\!!zeropoint,
- \c!title=\jobname, % needed for fdf/x
- \c!subtitle=,
- \c!author=,
- \c!keyword=,
- \c!date=\@@iatimestamp]
-
-%D XMP support:
-
-\setupinteraction
- [xmpfile=]
-
-\appendtoks
- % this will move as it is a backend issue
- \doifsomething\@@iaxmpfile
- {\ctxlua{if lpdf then lpdf.setxmpfile("\@@iaxmpfile") end}%
- \globallet\@@iaxmpfile\empty}%
-\to \everysetupinteraction
-
-\protect \endinput
diff --git a/tex/context/base/scrn-pag.lua b/tex/context/base/scrn-pag.lua
new file mode 100644
index 000000000..7003d0285
--- /dev/null
+++ b/tex/context/base/scrn-pag.lua
@@ -0,0 +1,27 @@
+if not modules then modules = { } end modules ['scrn-pag'] = {
+ version = 1.001,
+ comment = "companion to scrn-pag.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+interactions = interactions or { }
+interactions.pages = interactions.pages or { }
+local pages = interactions.pages
+
+local codeinjections = backends.codeinjections
+
+local function setupcanvas(specification)
+ codeinjections.setupcanvas(specification)
+end
+
+local function setpagetransition(specification)
+ codeinjections.setpagetransition(specification)
+end
+
+pages.setupcanvas = setupcanvas
+pages.setpagetransition = setpagetransition
+
+commands.setupcanvas = setupcanvas
+commands.setpagetransition = setpagetransition
diff --git a/tex/context/base/scrn-pag.mkvi b/tex/context/base/scrn-pag.mkvi
new file mode 100644
index 000000000..a5b4d0dfd
--- /dev/null
+++ b/tex/context/base/scrn-pag.mkvi
@@ -0,0 +1,180 @@
+%D \module
+%D [ file=scrn-pag,
+%D version=1998.01.15,
+%D title=\CONTEXT\ Screen Macros,
+%D subtitle=Pages, % moved code
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% pagecomments will be done differently
+
+\writestatus{loading}{ConTeXt Screen Macros / Pages}
+
+\registerctxluafile{scrn-pag}{1.001}
+
+\unprotect
+
+\installparameterhandler \??sc {interactionscreen}
+\installsetuphandler \??sc {interactionscreen}
+
+\def\scrn_canvas_synchronize_simple % this will be done differently (or disappear)
+ {\begingroup
+ \ifx\@@ppleft \empty
+ \ifx\@@ppright \empty
+ \ifx\@@pptop \empty
+ \ifx\@@ppbottom \empty
+ \ifx\@@pcstate\v!start
+ \locationfalse\fi\else
+ \locationfalse\fi\else
+ \locationfalse\fi\else
+ \locationfalse\fi\else
+ \locationfalse\fi
+ \iflocation % without screen settings
+ \ctxcommand{setupcanvas{
+ paperwidth = \number\paperwidth,
+ paperheight = \number\paperheight
+ }}%
+ \else
+ \ctxcommand{setupcanvas{
+ paperwidth = \number\printpaperwidth,
+ paperheight = \number\printpaperheight
+ }}%
+ \fi
+ \endgroup}
+
+\def\scrn_canvas_synchronize_complex
+ {\begingroup
+ \edef\currentinteractionscreenwidth {\interactionscreenparameter\c!width }%
+ \edef\currentinteractionscreenheight{\interactionscreenparameter\c!height}%
+ \ifx\currentinteractionscreenwidth\v!fit
+ \!!widtha\leftcombitotal
+ \ifdim\backspace>\!!widtha
+ \ifdim\backspace>\zeropoint\relax
+ \advance\backspace -\!!widtha
+ \fi
+ \fi
+ \advance\!!widtha\dimexpr
+ \rightcombitotal
+ + 2\dimexpr
+ \interactionscreenparameter\c!backspace
+ + \interactionscreenparameter\c!horoffset
+ \relax
+ \relax
+ \else\ifx\currentinteractionscreenwidth\v!max
+ \!!widtha\printpaperwidth
+ \else
+ \!!widtha\currentinteractionscreenwidth
+ \fi\fi
+ \ifdim\!!widtha>\paperwidth\ifdim\!!widtha>\zeropoint
+ \global\paperwidth\!!widtha
+ \fi\fi
+ \ifx\currentinteractionscreenheight\v!fit
+ \!!heighta\dimexpr\topheight+\topdistance\relax
+ \ifdim\topspace>\!!heighta
+ \ifdim\topspace>\zeropoint\relax
+ \advance\topspace -\!!heighta
+ \fi
+ \fi
+ \advance\!!heighta\dimexpr
+ \makeupheight
+ + \bottomdistance
+ + \bottomheight
+ + 2\dimexpr
+ \interactionscreenparameter\c!topspace
+ + \interactionscreenparameter\c!veroffset
+ \relax
+ \relax
+ \else\ifx\currentinteractionscreenheight\v!max
+ \!!heighta\printpaperheight
+ \else
+ \!!heighta\currentinteractionscreenheight
+ \fi\fi
+ \ifdim\!!heighta>\paperheight\ifdim\!!heighta>\zeropoint
+ \global\paperheight\!!heighta
+ \fi\fi
+ \ctxcommand{setupcanvas{
+ mode = "\interactionscreenparameter\c!option",
+ singlesided = \ifsinglesided true\else false\fi,
+ doublesided = \ifdoublesided true\else false\fi,
+ leftoffset = \number\dimexpr\backoffset\relax,
+ topoffset = \number\dimexpr\topoffset \relax,
+ width = \number\dimexpr\!!widtha \relax,
+ height = \number\dimexpr\!!heighta \relax,
+ paperwidth = \number\paperwidth,
+ paperheight = \number\paperheight
+ }}%
+ \endgroup}
+
+\let\scrn_canvas_synchronize\scrn_canvas_synchronize_complex
+
+\appendtoks
+ \ifproductionrun
+ \doifelse\@@pcstate\v!start
+ {\let\scrn_canvas_synchronize\scrn_canvas_synchronize_simple }
+ {\let\scrn_canvas_synchronize\scrn_canvas_synchronize_complex}%
+ \fi
+\to \everysetupinteractionscreen
+
+\appendtoks
+ \scrn_canvas_synchronize
+\to \everyshipout
+
+\setupinteractionscreen
+ [\c!width=\printpaperwidth,
+ \c!height=\printpaperheight,
+ \c!horoffset=\zeropoint,
+ \c!veroffset=\zeropoint,
+ \c!backspace=\backspace,
+ \c!topspace=\topspace,
+ \c!option=\v!auto]
+
+%D Conditional page breaks:
+
+\unexpanded\def\screen
+ {\dosingleempty\scrn_screen}
+
+\def\scrn_screen[#list]%
+ {\iflocation
+ \page[#list]%
+ \fi}
+
+%D Page transitions:
+
+\let\scrn_transitions_list\empty
+
+\unexpanded\def\setuppagetransitions
+ {\dosingleempty\scrn_transitions_setup}
+
+\def\scrn_transitions_setup[#list]%
+ {\edef\scrn_transitions_list{#list}}
+
+\def\scrn_transitions_set
+ {\iflocation \ifx\scrn_transitions_list\empty \else
+ \scrn_transitions_set_indeed
+ \fi \fi}
+
+\def\scrn_transitions_set_indeed
+ {\begingroup
+ \edef\currentinteractionscreendelay{\interactionscreenparameter\c!delay}%
+ \ctxcommand{setpagetransition{
+ n = "\scrn_transitions_list",
+ delay = "\ifx\currentinteractionscreendelay\v!none 0\else\currentinteractionscreendelay\v!none\fi"
+ }}%
+ \endgroup}
+
+\prependtoks
+ \scrn_transitions_set
+\to \everyshipout
+
+\setupinteractionscreen
+ [\c!delay=\v!none]
+
+\setuppagetransitions
+ [\v!reset]
+
+\protect \endinput
diff --git a/tex/context/base/scrn-ref.lua b/tex/context/base/scrn-ref.lua
new file mode 100644
index 000000000..9609e8aa2
--- /dev/null
+++ b/tex/context/base/scrn-ref.lua
@@ -0,0 +1,65 @@
+if not modules then modules = { } end modules ['scrn-int'] = {
+ version = 1.001,
+ comment = "companion to scrn-int.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+interactions = interactions or { }
+interactions.references = interactions.references or { }
+local references = interactions.references
+
+local codeinjections = backends.codeinjections
+
+local expandcurrent = structures.references.expandcurrent
+local identify = structures.references.identify
+
+local function check(what)
+ if what and what ~= "" then
+ local set, bug = identify("",what)
+ return not bug and #set > 0 and set
+ end
+end
+
+local function setopendocumentaction(open)
+ local opendocument = check(open)
+ if opendocument then
+ codeinjections.registerdocumentopenaction(opendocument)
+ expandcurrent()
+ end
+end
+
+local function setclosedocumentaction(close)
+ local closedocument = check(close)
+ if closedocument then
+ codeinjections.registerdocumentcloseaction(closedocument)
+ expandcurrent()
+ end
+end
+
+local function setopenpageaction(open)
+ local openpage = check(open)
+ if openpage then
+ codeinjections.registerpageopenaction(openpage)
+ expandcurrent()
+ end
+end
+
+local function setclosepageaction(close)
+ local closepage = check(close)
+ if closepage then
+ codeinjections.registerpagecloseaction(openpage)
+ expandcurrent()
+ end
+end
+
+references.setopendocument = setopendocumentaction
+references.setclosedocument = setclosedocumentaction
+references.setopenpage = setopenpageaction
+references.setclosepage = setclosepageaction
+
+commands.setopendocumentaction = setopendocumentaction
+commands.setclosedocumentaction = setclosedocumentaction
+commands.setopenpageaction = setopenpageaction
+commands.setclosepageaction = setclosepageaction
diff --git a/tex/context/base/scrn-ref.mkvi b/tex/context/base/scrn-ref.mkvi
new file mode 100644
index 000000000..8c3f4fb4a
--- /dev/null
+++ b/tex/context/base/scrn-ref.mkvi
@@ -0,0 +1,90 @@
+%D \module
+%D [ file=scrn-ref,
+%D version=1998.01.15,
+%D title=\CONTEXT\ Screen Macros,
+%D subtitle=References, % moved code
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%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 Screen Macros / References}
+
+\registerctxluafile{scrn-ref}{1.001}
+
+\unprotect
+
+\appendtoks
+ \doifsomething{\interactionparameter\c!calculate}{\doregistercalculationset{\interactionparameter\c!calculate}}%
+ \doifelse{\interactionparameter\c!click }\v!yes \settrue \setfalse \highlighthyperlinks
+ \doifelse{\interactionparameter\c!display}\v!new \settrue \setfalse \gotonewwindow
+ \doifnot {\interactionparameter\c!page }\v!no \scrn_reference_enable_page_destinations
+\to \everysetupinteraction
+
+\def\scrn_reference_enable_page_destinations % no reset
+ {\ctxlua{structures.references.setinnermethod("\interactionparameter\c!page")}}
+
+\setupinteraction % start fit page and reset form
+ [\c!page=\v!no,
+ \c!click=\v!yes,
+ \c!display=\v!normal,
+ \c!focus=\v!fit,
+ \c!calculate=,
+ % rendering:
+ \c!width=1em,
+ \c!height=\zeropoint,
+ \c!depth=\zeropoint,
+ \c!symbolset=]
+
+%D We have to make sure of some settings:
+
+\def\scrn_reference_set_text_actions
+ {\iflocation
+ \edef\currentinteractionopenaction {\interactionparameter\c!openaction }%
+ \edef\currentinteractioncloseaction{\interactionparameter\c!closeaction}%
+ \ifx\currentinteractionopenaction\empty \else
+ \ctxcommand{setopendocumentaction("\currentinteractionopenaction")}%
+ \fi
+ \ifx\currentinteractioncloseaction\empty \else
+ \ctxcommand{setclosedocumentaction("\currentinteractioncloseaction")}%
+ \fi
+ \glet\scrn_reference_set_text_actions\relax
+ \fi}
+
+\def\scrn_reference_set_page_actions
+ {\iflocation
+ \edef\currentinteractionopenpageaction {\interactionparameter\c!openpageaction }%
+ \edef\currentinteractionclosepageaction{\interactionparameter\c!closepageaction}%
+ \ifx\currentinteractionopenpageaction\empty \else
+ \ctxcommand{setopenpageaction("\currentinteractionopenpageaction")}%
+ \fi
+ \ifx\currentinteractionclosepageaction\empty \else
+ \ctxcommand{setclosepageaction("\currentinteractionclosepageaction")}%
+ \fi
+ \fi}
+
+\appendtoks \scrn_reference_set_text_actions \to \everyshipout
+\appendtoks \scrn_reference_set_page_actions \to \everyshipout
+
+%D delayed ...
+
+\def\scrn_reference_enable_references
+ {\ifproductionrun
+ \ctxlua{structures.references.enableinteraction()}%
+ \glet\scrn_reference_enable_references\relax
+ \fi}
+
+\appendtoks
+ \scrn_reference_enable_references
+\to \everysetupinteraction
+
+\setupinteraction % start fit page and reset form
+ [\c!openaction=,
+ \c!closeaction=,
+ \c!openpageaction=,
+ \c!closepageaction=]
+
+\protect \endinput
diff --git a/tex/context/base/scrn-wid.lua b/tex/context/base/scrn-wid.lua
new file mode 100644
index 000000000..7b1dd940a
--- /dev/null
+++ b/tex/context/base/scrn-wid.lua
@@ -0,0 +1,194 @@
+if not modules then modules = { } end modules ['scrn-wid'] = {
+ version = 1.001,
+ comment = "companion to scrn-wid.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+interactions = interactions or { }
+local interactions = interactions
+
+local attachments = { }
+local comments = { }
+local soundclips = { }
+local renderings = { }
+local linkedlists = { }
+
+interactions.attachments = attachments
+interactions.soundclips = soundclips
+interactions.renderings = renderings
+interactions.linkedlists = linkedlists
+
+local jobpasses = job.passes
+
+local codeinjections = backends.codeinjections
+local nodeinjections = backends.nodeinjections
+
+local variables = interfaces.variables
+local v_auto = variables.auto
+
+-- Symbols
+
+function commands.presetsymbollist(list)
+ codeinjections.presetsymbollist(list)
+end
+
+-- Attachments
+--
+-- registered : unique id
+-- tag : used at the tex end
+-- file : name that the file has on the filesystem
+-- name : name that the file will get in the output
+-- title : up to the backend
+-- subtitle : up to the backend
+-- author : up to the backend
+-- method : up to the backend (hidden == no rendering)
+
+local nofautoattachments, lastregistered = 0, nil
+
+local function checkregistered(specification)
+ local registered = specification.registered
+ if not registered or registered == "" or registered == v_auto then
+ nofautoattachments = nofautoattachments + 1
+ lastregistered = "attachment-" .. nofautoattachments
+ specification.registered = lastregistered
+ return lastregistered
+ else
+ return registered
+ end
+end
+
+local function checkbuffer(specification)
+ local buffer = specification.buffer
+ if buffer ~= "" then
+ specification.data = buffers.getcontent(buffer) or "<no data>"
+ end
+end
+
+function attachments.register(specification)
+ checkregistered(specification)
+ checkbuffer(specification)
+ attachments[lastregistered] = specification
+ return specification
+end
+
+function attachments.insert(specification)
+ local registered = checkregistered(specification)
+ local r = attachments[registered]
+ if r then
+ for k, v in next, r do
+ local s = specification[k]
+ if s == "" then
+ specification[k] = v
+ end
+ end
+ end
+ checkbuffer(specification)
+ return nodeinjections.attachfile(specification)
+end
+
+commands.registerattachment = attachments.register
+
+function commands.insertattachment(specification)
+ tex.box["scrn_attachment_box_link"] = attachments.insert(specification)
+end
+
+-- Comment
+
+function comments.insert(specification)
+ local buffer = specification.buffer
+ if buffer ~= "" then
+ specification.data = buffers.getcontent(buffer) or ""
+ end
+ return nodeinjections.comment(specification)
+end
+
+function commands.insertcomment(specification)
+ tex.box["scrn_comment_box_link"] = comments.insert(specification)
+end
+
+-- Soundclips
+
+function soundclips.register(specification)
+ local tag = specification.tag
+ if tag and tag ~= "" then
+ local filename = specification.file
+ if not filename or filename == "" then
+ filename = tag
+ specification.file = filename
+ end
+ soundclips[tag] = specification
+ return specification
+ end
+end
+
+function soundclips.insert(tag)
+ local sc = soundclips[tag]
+ if not sc then
+ -- todo: message
+ return soundclips.register { tag = tag }
+ else
+ return sc
+ end
+end
+
+commands.registersoundclip = soundclips.register
+commands.insertsoundclip = soundclips.insert
+
+-- Renderings
+
+function renderings.register(specification)
+ if specification.label then
+ renderings[specification.label] = specification
+ return specification
+ end
+end
+
+function renderings.rendering(label)
+ local rn = renderings[label]
+ if not rn then
+ -- todo: message
+ return renderings.register { label = label }
+ else
+ return rn
+ end
+end
+
+function renderings.var(label,key)
+ local rn = renderings[label]
+ context(rn and rn[key] or "")
+end
+
+-- Rendering:
+
+function commands.insertrenderingwindow(specification)
+ codeinjections.insertrenderingwindow(specification)
+end
+
+-- Linkedlists (only a context interface)
+
+function commands.definelinkedlist(tag)
+ -- no need
+end
+
+function commands.enhancelinkedlist(tag,n)
+ local ll = jobpasses.gettobesaved(tag)
+ if ll then
+ ll[n] = texcount.realpageno
+ end
+end
+
+function commands.addlinklistelement(tag)
+ local tobesaved = jobpasses.gettobesaved(tag)
+ local collected = jobpasses.getcollected(tag) or { }
+ local currentlink = #tobesaved + 1
+ local noflinks = #collected
+ tobesaved[currentlink] = 0
+ local f = collected[1] or 0
+ local l = collected[noflinks] or 0
+ local p = collected[currentlink-1] or f
+ local n = collected[currentlink+1] or l
+ context.setlinkedlistproperties(currentlink,noflinks,f,p,n,l)
+ -- context.ctxlatelua(function() commands.enhancelinkedlist(tag,currentlink) end)
+end
diff --git a/tex/context/base/scrn-wid.mkvi b/tex/context/base/scrn-wid.mkvi
new file mode 100644
index 000000000..4674dea28
--- /dev/null
+++ b/tex/context/base/scrn-wid.mkvi
@@ -0,0 +1,700 @@
+%D \module
+%D [ file=scrn-int,
+%D version=2011.02.27, % moved from scrn-int
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Widgets,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%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 Interaction Macros / Widgets}
+
+\registerctxluafile{scrn-wid}{1.001}
+
+\unprotect
+
+%D Attachments (mkiv upgraded):
+%D
+%D As usual in \CONTEXT\ we separate the general definition (frontend)
+%D and the rendering (backend).
+
+% old but stil valid method:
+%
+% \useattachment[test.tex]
+% \useattachment[whatever][test.tex]
+% \useattachment[whatever][newname][test.tex]
+% \useattachment[whatever][title][newname][test.tex]
+%
+% new method:
+%
+% \registerattachment[sometag][specification] % name file author title subtitle
+%
+% \attachment[sometag][extra specs]
+% \attachment[test.tex]
+% \attachment[file=test.tex]
+% \attachment[file=test.tex,method=hidden]
+% \attachment[name=newname,file=test.tex]
+% \attachment[title=mytitle,name=newname,file=test.tex]
+%
+% indirect
+%
+% \defineattachment[whatever5][file=test.tex] \attachment[whatever5][method=hidden]
+% \defineattachment[whatever5][file=test.tex,method=hidden] \attachment[whatever5]
+%
+% direct (no definitions)
+%
+% \attachment[test][file=oeps.tex,title=Oeps,author=Hans,subtitle=TeX File,method=hidden]
+% \attachment[label=test,file=oeps.tex,title=Oeps,author=Hans,subtitle=TeX File,method=hidden]
+%
+% autolabel:
+%
+% \attachment[file=oeps.tex,title=Oeps,author=Hans,subtitle=TeX File,method=hidden]
+%
+% % \setupattachments[\c!symbol={symbol-normal,symbol-down}]
+
+% startattachment -> temp file
+
+\newbox\scrn_attachment_box_collect
+\newbox\scrn_attachment_box_link
+\newbox\scrn_attachment_box_symbol
+
+\installcommandhandler\??at{attachment}\??at
+
+\let\setupattachments\setupattachment % convenience and compatibility
+
+\setupattachment
+ [\c!state=\v!start,
+ \c!color=\interactionparameter\c!color,
+ %\c!textlayer=,
+ %\c!symbol=,
+ %\c!title=,
+ %\c!subtitle=,
+ %\c!file=, % input filename
+ %\c!name=, % new filename
+ %\c!author=,
+ %\c!method=, % \v!hidden = not in menu
+ %\c!buffer=
+ \c!symbol=,
+ \c!distance=1em,
+ \c!width=\v!fit,
+ \c!height=\v!fit,
+ \c!depth=\v!fit,
+ \c!location=\v!high]
+
+\unexpanded\def\registerattachment
+ {\dodoubleempty\scrn_attachment_register}
+
+\def\scrn_attachment_register[#tag][#settings]% we save (globally) at the lua end
+ {\ifsecondargument
+ \begingroup
+ \def\currentattachment{_}%
+ \setupattachment[_][#settings,\s!parent=\??at]%
+ \ctxcommand{registerattachment{
+ tag = "#tag",
+ title = "\attachmentparameter\c!title",
+ subtitle = "\attachmentparameter\c!subtitle",
+ author = "\attachmentparameter\c!author",
+ file = "\attachmentparameter\c!file",
+ name = "\attachmentparameter\c!name",
+ buffer = "\attachmentparameter\c!buffer",
+ }}%
+ \endgroup
+ \fi}
+
+\appendtoks
+ \setuevalue \currentattachment {\scrn_attachment_direct{\currentattachment}}%
+ \setuevalue{\e!start\currentattachment}{\scrn_attachment_start {\currentattachment}}%
+ \setuevalue{\e!stop \currentattachment}{\scrn_attachment_stop }%
+\to \everydefineattachment
+
+\unexpanded\def\scrn_attachment_direct#tag%
+ {\edef\currentattachment{#tag}%
+ \doifelselocation
+ {\dodoubleempty\scrn_attachment_direct_status}
+ {\dodoubleempty\scrn_attachment_direct_ignore}}
+
+\def\scrn_attachment_direct_status
+ {\doifelse{\attachmentparameter\c!state}\v!start
+ \scrn_attachment_direct_indeed
+ \scrn_attachment_direct_ignore}
+
+\def\scrn_attachment_direct_indeed[#registered][#settings]%
+ {\bgroup
+ \doifelsenothing{#registered}
+ {\scrn_attachment_inject[\v!auto][]}
+ {\doifassignmentelse{#registered}
+ {\scrn_attachment_inject[\v!auto][#registered]}
+ {\scrn_attachment_inject[#registered][#settings]}}%
+ \egroup}
+
+\def\scrn_attachment_direct_ignore[#tag][#settings]%
+ {}
+
+\unexpanded\def\scrn_attachment_start#tag%
+ {\edef\currentattachment{#tag}%
+ \doifelselocation
+ {\dodoubleempty\scrn_attachment_start_indeed}
+ {\dodoubleempty\scrn_attachment_start_ignore}}
+
+\unexpanded\def\scrn_attachment_stop
+ {}
+
+\def\scrn_attachment_start_indeed
+ {\doif{\attachmentparameter\c!state}\v!start
+ {\scrn_attachment_start_indeed}
+ {\scrn_attachment_start_ignore}}
+
+\def\scrn_attachment_start_indeed[#registered][#settings]%
+ {\bgroup
+ \doifelsenothing{#registered}
+ {\def\scrn_attachment_stop{\scrn_attachment_inject[\v!auto][\c!buffer=\v!attachment]\egroup}}%
+ {\doifassignmentelse{#registered}
+ {\def\scrn_attachment_stop{\scrn_attachment_inject[\v!auto][\c!buffer=\v!attachment,#registered]\egroup}}%
+ {\def\scrn_attachment_stop{\scrn_attachment_inject[#registered][\c!buffer=\v!attachment,#settings]\egroup}}}%
+ \dostartbuffer[\v!attachment][\e!start\currentattachment][\e!stop\currentattachment]}
+
+\def\scrn_attachment_start_ignore
+ {\expandafter\gobbleuntil\csname\e!stop\currentattachment\endcsname}
+
+\def\scrn_attachment_inject[#registered][#settings]%
+ {\edef\currentattachmentregistered{#registered}%
+ \setupattachment[\currentattachment][#settings]%
+ \expandcheckedcsname{scrn_attachment_method_}{\attachmentparameter\c!method}\v!normal}
+
+\setvalue{scrn_attachment_method_\v!normal}%
+ {\edef\currentattachmentsymbol{\attachmentparameter\c!symbol}%
+ \edef\currentattachmentwidth {\attachmentparameter\c!width }%
+ \edef\currentattachmentheight{\attachmentparameter\c!height}%
+ \edef\currentattachmentdepth {\attachmentparameter\c!depth }%
+ \ifx\currentattachmentsymbol\empty
+ \ifx\currentattachmentwidth \v!fit\edef\currentattachmentwidth {.5em}\fi
+ \ifx\currentattachmentheight\v!fit\edef\currentattachmentheight{.5em}\fi
+ \ifx\currentattachmentdepth \v!fit\let \currentattachmentdepth \zeropoint\fi
+ \else
+ \ctxcommand{presetsymbollist("\attachmentparameter\c!symbol")}%
+ % we cannot yet ask for the wd/ht/dp of an xform else we could use those
+ \setbox\scrn_attachment_box_symbol\hbox{\symbol[\lastpredefinedsymbol]}%
+ \ifx\currentattachmentwidth \v!fit\edef\currentattachmentwidth {\wd\scrn_attachment_box_symbol}\fi
+ \ifx\currentattachmentheight\v!fit\edef\currentattachmentheight{\ht\scrn_attachment_box_symbol}\fi
+ \ifx\currentattachmentdepth \v!fit\edef\currentattachmentdepth {\dp\scrn_attachment_box_symbol}\fi
+ \fi
+ \ctxcommand{insertattachment{
+ tag = "\currentattachment",
+ registered = "\currentattachmentregistered",
+ width = \number\dimexpr\currentattachmentwidth \relax,
+ height = \number\dimexpr\currentattachmentheight\relax,
+ depth = \number\dimexpr\currentattachmentdepth \relax,
+ color = "\attachmentparameter\c!color",
+ colormodel = \number\currentcolormodel,
+ colorvalue = \thecolorattribute{\attachmentparameter\c!color},
+ transparencyvalue = \thetransparencyattribute{\attachmentparameter\c!color},
+ symbol = "\currentattachmentsymbol",
+ layer = "\attachmentparameter\c!textlayer",
+ % these will be overloaded by registered when available
+ title = "\attachmentparameter\c!title",
+ subtitle = "\attachmentparameter\c!subtitle",
+ author = "\attachmentparameter\c!author",
+ file = "\attachmentparameter\c!file",
+ name = "\attachmentparameter\c!name",
+ buffer = "\attachmentparameter\c!buffer",
+ }}%
+ \setbox\scrn_attachment_box_link\hbox{\scrn_attachment_place}%
+ \wd\scrn_attachment_box_link\currentattachmentwidth
+ \ht\scrn_attachment_box_link\currentattachmentheight
+ \dp\scrn_attachment_box_link\currentattachmentdepth
+ \box\scrn_attachment_box_link}
+
+\setvalue{scrn_attachment_method_\v!hidden}%
+ {\ctxcommand{insertattachment{
+ tag = "\currentattachment",
+ registered = "\currentattachmentregistered",
+ method = "\v!hidden"
+ }}}
+
+\def\scrn_attachment_place
+ {\executeifdefined
+ {\??at:\c!location:\attachmentparameter\c!location}\hbox
+ {\box\scrn_attachment_box_link}}
+
+\setvalue{\??at:\c!location:\v!inmargin }{\inmargin }
+\setvalue{\??at:\c!location:\v!leftedge }{\inleftedge }
+\setvalue{\??at:\c!location:\v!rightedge }{\inrightedge }
+\setvalue{\??at:\c!location:\v!leftmargin }{\inleftmargin }
+\setvalue{\??at:\c!location:\v!rightmargin}{\inrightmargin}
+\setvalue{\??at:\c!location:\v!high }{\high}
+\setvalue{\??at:\c!location:\v!none }{\scrn_attachment_collect}
+
+\def\scrn_attachment_collect#content%
+ {\global\setbox\scrn_attachment_box_collect\hbox\bgroup
+ \ifvoid\scrn_attachment_box_collect\else
+ \box\scrn_attachment_box_collect
+ \hskip\attachmentparameter\c!distance
+ \fi
+ #content%
+ \egroup}
+
+\unexpanded\def\placeattachments
+ {\ifvoid\scrn_attachment_box_collect\else
+ \box\scrn_attachment_box_collect
+ \fi}
+
+\defineattachment[attachment]
+
+% \ifx\currentinterface\defaultinterface \else
+% \defineattachment[\v!attachment]
+% \fi
+
+% backward compatible:
+
+\unexpanded\def\useattachment
+ {\doquadrupleempty\scrn_attachment_use}
+
+\def\scrn_attachmen_use[#tag][#title][#name][#file]%
+ {\iffourthargument
+ \registerattachment[#tag][title=#title,name=#name,file=#file]%
+ \else\ifthirdargument
+ \registerattachment[#tag][title=#title,name=#title,file=#name]%
+ \else\ifsecondargument
+ \registerattachment[#tag][title=#title,name=#title,file=#title]%
+ \else
+ \registerattachment[#tag][title=#title,name=#tag,file=#tag]%
+ \fi\fi\fi}
+
+%D Comments:
+
+% test
+%
+% \startcomment
+% hello beautiful\\world
+% \stopcomment
+%
+% test
+%
+% \startcomment[hello]
+% hello << eerste >>
+% beautiful
+% world
+% \stopcomment
+%
+% test
+%
+% \startcomment[hello][color=green,width=10cm,height=3cm]
+% hello
+% beautiful
+% world
+% \stopcomment
+%
+% test
+%
+% \startcomment[hello][color=red,width=4cm,height=3cm]
+% hello
+%
+% beautiful
+%
+% world
+% \stopcomment
+%
+% test
+%
+% \startcomment[symbol=Balloon]
+% Do we want this kind of rubish?
+% \stopcomment
+%
+% test
+%
+% \definesymbol [comment-normal][{\externalfigure[cow.pdf]}]
+% \definesymbol [comment-down] [{\externalfigure[cow.pdf]}]
+%
+% \def\CowSymbol#1#2%
+% {\scale
+% [\c!height=#1]
+% {\startMPcode
+% loadfigure "koe.mp" number 1 ;
+% refill currentpicture withcolor #2 ;
+% \stopMPcode}}
+%
+% \definesymbol [comment-normal]
+% [\CowSymbol{4ex}{red}]
+%
+% \definesymbol [comment-down]
+% [\CowSymbol{4ex}{green}]
+%
+% \setupcomment
+% [\c!symbol={comment-normal,comment-down},
+% \c!option=\v!buffer]
+%
+% \startcomment[hello]
+% oeps
+% \stopcomment
+%
+% test
+%
+% \setupcomment
+% [\c!symbol=normal,
+% \c!option=max,width=10cm]
+%
+% \startcomment[hello]
+% oeps
+% \stopcomment
+%
+% test
+
+\installcommandhandler\??cc{comment}\??cc
+
+\newbox\scrn_comment_box_collect
+\newbox\scrn_comment_box_rendering
+\newbox\scrn_comment_box_link
+\newbox\scrn_comment_box_symbol
+
+\setupcomment
+ [\c!state=\v!start,
+ \c!distance=1em,
+ \c!color=\interactionparameter\c!color,
+ \c!space=\v!no,
+ \c!symbol=,
+ %\c!title=,
+ %\c!option=,
+ %\c!textlayer=,
+ \c!width=\v!fit,
+ \c!height=\v!fit,
+ \c!depth=\v!fit,
+ \c!nx=40,
+ \c!ny=10,
+ \c!location=\v!high]
+
+\presetlocalframed[\??cc]
+
+\appendtoks
+ \setuevalue \currentcomment {\scrn_comment_argument{\currentcomment}}%
+ \setuevalue{\e!start\currentcomment}{\scrn_comment_start {\currentcomment}}%
+ \setuevalue{\e!stop \currentcomment}{\scrn_comment_stop }%
+\to \everydefinecomment
+
+\unexpanded\def\scrn_comment_argument#category%
+ {\def\currentcomment{#category}%
+ \doifelselocation
+ {\dodoubleempty\scrn_comment_argument_status}
+ {\dodoubleempty\scrn_comment_argument_ignore}}
+
+\def\scrn_comment_argument_status
+ {\doifelse{\commentparameter\c!state}\v!start
+ \scrn_comment_argument_indeed
+ \scrn_comment_argument_ignore}
+
+\def\scrn_comment_argument_indeed[#title][#settings]#text%
+ {\doifassignmentelse{#title}
+ {\setupcomment[\currentcomment][#title]}
+ {\setupcomment[\currentcomment][\c!title=#title,#settings]}%
+ \ctxlua{buffers.assign("\v!comment",\!!bs\detokenize{#text}\!!es)}%
+ \scrn_comment_inject
+ \ignorespaces}
+
+\def\scrn_comment_argument_ignore[#title][#settings]#text%
+ {\ignorespaces}
+
+\unexpanded\def\scrn_comment_start#category%
+ {\def\currentcomment{#category}%
+ \doifelselocation
+ {\dodoubleempty\scrn_comment_start_indeed}
+ {\dodoubleempty\scrn_comment_start_ignore}}
+
+\def\scrn_comment_start_indeed
+ {\doifelse{\commentparameter\c!state}\v!start
+ {\scrn_comment_start_indeed}
+ {\scrn_comment_start_ignore}}
+
+\def\scrn_comment_start_indeed[#title][#settings]%
+ {\bgroup
+ \doifassignmentelse{#title}
+ {\setupcomment[\currentcomment][#title]}
+ {\setupcomment[\currentcomment][\c!title=#title,#settings]}%
+ \def\scrn_comment_stop{\scrn_comment_inject\egroup}%
+ \dostartbuffer[\v!comment][\e!start\currentcomment][\e!stop\currentcomment]}
+
+\def\scrn_comment_start_ignore
+ {\expandafter\gobbleuntil\csname\e!stop\currentcomment\endcsname}
+
+\unexpanded\def\scrn_comment_stop
+ {}
+
+\def\scrn_comment_inject
+ {\expandcheckedcsname{scrn_comment_method_}{\commentparameter\c!method}\v!normal}
+
+%D Beware: comments symbols don't scale in acrobat (cf. spec but somewhat
+%D weird, esp because for instance attachment symbols do scale).
+
+\setvalue{scrn_comment_method_\v!normal}%
+ {\edef\currentcommentsymbol{\commentparameter\c!symbol}%
+ \edef\currentcommentwidth {\commentparameter\c!width }%
+ \edef\currentcommentheight{\commentparameter\c!height}%
+ \edef\currentcommentdepth {\commentparameter\c!depth }%
+ \ifx\currentcommentsymbol\empty
+ \ifx\currentcommentwidth \v!fit\edef\currentcommentwidth {.5em}\fi
+ \ifx\currentcommentheight\v!fit\edef\currentcommentheight{.5em}\fi
+ \ifx\currentcommentdepth \v!fit\let \currentcommentdepth \zeropoint\fi
+ \else
+ \ctxcommand{presetsymbollist("\commentparameter\c!symbol")}%
+ % we cannot yet ask for the wd/ht/dp of an xform else we could use those
+ \setbox\scrn_comment_box_symbol\hbox{\symbol[\lastpredefinedsymbol]}%
+ \ifx\currentcommentwidth \v!fit\edef\currentcommentwidth {\wd\scrn_comment_box_symbol}\fi
+ \ifx\currentcommentheight\v!fit\edef\currentcommentheight{\ht\scrn_comment_box_symbol}\fi
+ \ifx\currentcommentdepth \v!fit\edef\currentcommentdepth {\dp\scrn_comment_box_symbol}\fi
+ \fi
+ \ctxcommand{insertcomment{
+ tag = "\currentcomment",
+ title = "\commentparameter\c!title",
+ subtitle = "\commentparameter\c!subtitle",
+ author = "\commentparameter\c!author",
+ width = \number\dimexpr\currentcommentwidth,
+ height = \number\dimexpr\currentcommentheight,
+ depth = \number\dimexpr\currentcommentdepth,
+ nx = \commentparameter\c!nx,
+ ny = \commentparameter\c!ny,
+ colormodel = \number\currentcolormodel,
+ colorvalue = \thecolorattribute{\commentparameter\c!color},
+ transparencyvalue = \thetransparencyattribute{\commentparameter\c!color},
+ option = "\commentparameter\c!option", % todo
+ symbol = "\commentparameter\c!symbol",
+ buffer = "\v!comment",
+ layer = "\commentparameter\c!textlayer"
+ }}%
+ \wd\scrn_comment_box_link\currentcommentwidth
+ \ht\scrn_comment_box_link\currentcommentheight
+ \dp\scrn_comment_box_link\currentcommentdepth
+ \scrn_comment_place}
+
+\setvalue{scrn_comment_method_\v!hidden}%
+ {}
+
+% todo: dedicated margin classes
+
+\def\scrn_comment_place
+ {\executeifdefined
+ {\??cc:\c!location:\commentparameter\c!location}\hbox
+ {\hbox{\box\scrn_comment_box_link}}}
+
+\setvalue{\??cc:\c!location:\v!inmargin }{\inmargin }
+\setvalue{\??cc:\c!location:\v!leftedge }{\inleftedge }
+\setvalue{\??cc:\c!location:\v!rightedge }{\inrightedge }
+\setvalue{\??cc:\c!location:\v!leftmargin }{\inleftmargin }
+\setvalue{\??cc:\c!location:\v!rightmargin}{\inrightmargin}
+\setvalue{\??cc:\c!location:\v!high }{\high}
+\setvalue{\??cc:\c!location:\v!none }{\scrn_comment_collect}
+
+\def\scrn_comment_collect#content%
+ {\global\setbox\scrn_comment_box_collect\hbox\bgroup
+ \ifvoid\scrn_comment_box_collect\else
+ \box\scrn_comment_box_collect
+ \hskip\commentparameter\c!distance
+ \fi
+ #content%
+ \egroup}
+
+\unexpanded\def\placecomments
+ {\ifvoid\scrn_comment_box_collect\else
+ \box\scrn_comment_box_collect
+ \fi}
+
+\definecomment[comment]
+
+% \ifx\currentinterface\defaultinterface \else
+% \definecomment[\v!comment]
+% \fi
+
+%D Soundclips:
+%D
+%D Defining sound tracks:
+%D
+%D \starttyping
+%D \useexternalsoundtrack[label][file]
+%D \stoptyping
+%D
+%D associated actions: StartSound StopSound PauseSound ResumeSound
+%D
+%D Todo: like external figures, also search on path,
+%D although, they need to be present ar viewing time, so ...
+
+\unexpanded\def\useexternalsoundtrack
+ {\dodoubleargument\scrn_soundtrack_indeed}
+
+\def\scrn_soundtrack_indeed[#tag][#filename]%
+ {\ctxcommand{registersoundclip{
+ tag = "#tag",
+ file = "#filename"
+ }}}
+
+\def\checksoundtrack#tag% yet untested in mkiv (also move management to lua)
+ {\iflocation
+ \ctxcommand{insertsoundclip{
+ tag = "#tag",
+ repeat = "\@@sdoption", % not entirely ok but works
+ }}%
+ \fi}
+
+\unexpanded\def\setupexternalsoundtracks
+ {\dodoubleargument\getparameters[\??sd]}
+
+\setupexternalsoundtracks
+ [\c!option=]
+
+%D Renderings (not yet tested in mkvi):
+
+% Todo: multiple instances and inheritance .. will be done when
+% needed i.e. when I see usage.
+
+\let\currentrendering\empty
+
+\definereference[StartCurrentRendering] [\v!StartRendering {\currentrendering}]
+\definereference[StopCurrentRendering] [\v!StopRendering {\currentrendering}]
+\definereference[PauseCurrentRendering] [\v!PauseRendering {\currentrendering}]
+\definereference[ResumeCurrentRendering][\v!ResumeRendering{\currentrendering}]
+
+\def\useexternalrendering{\doquadrupleempty\scrn_rendering_use}
+\def\setinternalrendering{\dodoubleempty \scrn_rendering_set}
+
+\def\scrn_rendering_use[#tag][#mime][#file][#options]%
+ {\ctxlua{interactions.renderings.register {
+ type = "external",
+ label = "#tag",
+ mime = "#mime",
+ filename = "#file",
+ options = "#options",
+ }}}
+
+\def\scrn_rendering_set[#tag][#options]% {content}
+ {\bgroup
+ \dowithnextbox
+ {\ctxlua{interactions.renderings.register {
+ type = "internal",
+ label = "#tag",
+ mime = "IRO", % brrr
+ filename = "#tag",
+ options = "#options",
+ }}%
+ \let\objectoffset\zeropoint
+ \setobject{IRO}{#tag}\hbox{\box\nextbox}%
+ \egroup}%
+ \hbox}
+
+\def\renderingtype #tag{\ctxlua{interactions.renderings.var("#tag","type")}}
+\def\renderingoptions#tag{\ctxlua{interactions.renderings.var("#tag","options")}}
+
+\def\renderingwidth {8cm} % will become private
+\def\renderingheight {6cm} % will become private
+
+\unexpanded\def\definerenderingwindow
+ {\dodoubleempty\scrn_rendering_define_window}
+
+\def\scrn_rendering_define_window[#tag][#settings]%
+ {\presetlocalframed[\??rw#tag]%
+ \getparameters
+ [\??rw#tag]%
+ [\c!openpageaction=,\c!closepageaction=,%
+ \c!width=\renderingwidth,\c!height=\renderingheight,%
+ #settings]}
+
+\unexpanded\def\setuprenderingwindow
+ {\dodoubleargument\scrn_rendering_setup_window}
+
+\def\scrn_rendering_setup_window[#tag]%
+ {\getparameters[\??rw#tag]}
+
+\unexpanded\def\placerenderingwindow
+ {\dodoubleempty\scrn_rendering_place_window}
+
+\def\scrn_rendering_place_window[#window][#rendering]%
+ {\bgroup
+ \edef\currentrendering{\ifsecondargument#rendering\else#window\fi}%
+ \doifelse{\renderingtype\currentrendering}{internal} % an object
+ {\getobjectdimensions{IRO}\currentrendering
+ \edef\renderingheight{\the\dimexpr\objectheight+\objectdepth\relax}%
+ \edef\renderingwidth{\objectwidth}%
+ \dogetobjectreferencepage{IRO}\currentrendering\renderingpage}%
+ {\def\renderingheight{\vsize}%
+ \def\renderingwidth{\hsize}%
+ \def\renderingpage{\realpageno}}%
+ % create fall back if needed
+ \ifcsname\??rw#window\c!width\endcsname
+ \def\currentrenderingwindow{#window}%
+ \else
+ \let\currentrenderingwindow\s!default
+ \scrn_rendering_define_window[\currentrenderingwindow]%
+ \fi
+% todo
+% \handlereferenceactions{\getvalue{\??rw\currentrenderingwindow\c!openpageaction }}\dosetuprenderingopenpageaction
+% \handlereferenceactions{\getvalue{\??rw\currentrenderingwindow\c!closepageaction}}\dosetuprenderingclosepageaction
+ \localframed
+ [\??rw\currentrenderingwindow][\c!offset=\v!overlay]%
+ {\vfill
+ \ctxcommand{insertrenderingwindow {
+ label = "\currentrendering",
+ width = \number\dimexpr\renderingwidth\relax,
+ height = \number\dimexpr\renderingheight\relax,
+ options = "\renderingoptions\currentrendering",
+ page = \number\renderingpage,
+ }}\hfill}%
+ \egroup}
+
+%D Linkedlists (not tested in mkvi):
+
+% %D The next mechanism, linked lists, is quite old and
+% %D is \MKIV'd for completeness. I will finish the
+% %D configuration part when I need it.
+% %D
+% %D \starttyping
+% %D \setupinteraction[state=start]
+% %D \definelinkedlist[demo]
+% %D \dorecurse{10}{\linkedlistelement[demo]{link \recurselevel} \page}
+% %D \stoptyping
+%
+% \installcommandhandler\??lk{linkedlist}\??lk
+%
+% \let\setupbutton\setuplinkedlists\setuplinkedlist
+%
+% \appendtoks
+% \ctxcommand{definelinkedlist("\currentlinkedlist")}%
+% \to \everydefinelinkedlist
+%
+% \def\setlinkedlistproperties#1#2#3#4#5#6%
+% {\def\currentlink {#1}%
+% \def\noflinks {#2}%
+% \def\firstlink {#3}%
+% \def\previouslink{#4}%
+% \def\nextlink {#5}%
+% \def\lastlink {#6}}
+%
+% \def\linkedlistelement[#1]#2% currently no view support
+% {\dontleavehmode\hbox\bgroup
+% #2%
+% \iflocation
+% \edef\currentlinkedlist{#1}%
+% \ifcsname\??lk\currentlinkedlist\s!parent\endcsname
+% \hskip\linkedlistparameter\c!distance
+% \ctxcommand{addlinklistelement("\currentlinkedlist")}%
+% \expanded{\ctxlatelua{commands.enhancelinkedlist("\currentlinkedlist",\currentlink)}}% can also be done at the lua end
+% \dogotosomepage {\??lk\currentlinkedlist}\gotobegincharacter \firstlink
+% \ifnum\noflinks>\plustwo
+% \dogotosomepage{\??lk\currentlinkedlist}\gobackwardcharacter\previouslink
+% \dogotosomepage{\??lk\currentlinkedlist}\goforwardcharacter \nextlink
+% \fi
+% \dogotosomepage {\??lk\currentlinkedlist}\gotoendcharacter \lastlink
+% \else
+% \writestatus\m!interactions{no such linked list: \currentlinkedlist}%
+% \fi
+% \fi
+% \egroup}
+%
+% \setuplinkedlists
+% [\c!distance=.25em,
+% \c!width=\v!fit,
+% \c!location=\v!low,
+% \c!color=\interactionparameter\c!color,
+% \c!frame=\v!off,
+% \c!background=,
+% \c!backgroundcolor=]
+
+\protect \endinput
diff --git a/tex/context/base/scrp-cjk.lua b/tex/context/base/scrp-cjk.lua
index 7c9833bb3..5570532c8 100644
--- a/tex/context/base/scrp-cjk.lua
+++ b/tex/context/base/scrp-cjk.lua
@@ -28,14 +28,15 @@ local a_preproc = attributes.private('preproc')
scripts.cjk = scripts.cjk or { }
-local kindtonumber = scripts.kindtonumber
-local numbertokind = scripts.numbertokind
-local hash = scripts.hash
-local cjk = scripts.cjk
-local numbertodataset = scripts.numbertodataset
+local categorytonumber = scripts.categorytonumber
+local numbertocategory = scripts.numbertocategory
+local hash = scripts.hash
+local cjk = scripts.cjk
+local numbertodataset = scripts.numbertodataset
-local fontdata = fonts.identifiers
-local quaddata = fonts.quads
+local fonthashes = fonts.hashes
+local fontdata = fonthashes.identifiers
+local quaddata = fonthashes.quads
-- raggedleft is controlled by leftskip and we might end up with a situation where
-- the intercharacter spacing interferes with this; the solution is to patch the
@@ -328,12 +329,12 @@ local injectors = { -- [previous] [current]
local function process(head,first,last)
if first ~= last then
- local lastfont, previous, originals, last = nil, "start", nil, nil
+ local lastfont, previous, last = nil, "start", nil
while true do
local upcoming, id = first.next, first.id
if id == glyph_code then
local a = has_attribute(first,a_prestat)
- local current = numbertokind[a]
+ local current = numbertocategory[a]
local action = injectors[previous]
if action then
action = action[current]
@@ -353,7 +354,7 @@ local function process(head,first,last)
local pid, nid = p.id, n.id
if pid == glyph_code and nid == glyph_code then
local pa, na = has_attribute(p,a_prestat), has_attribute(n,a_prestat)
- local pcjk, ncjk = pa and numbertokind[pa], na and numbertokind[na]
+ local pcjk, ncjk = pa and numbertocategory[pa], na and numbertocategory[na]
if not pcjk or not ncjk
or pcjk == "korean" or ncjk == "korean"
or pcjk == "other" or ncjk == "other"
@@ -532,12 +533,12 @@ local injectors = { -- [previous] [current]
local function process(head,first,last)
if first ~= last then
- local lastfont, previous, originals, last = nil, "start", nil, nil
+ local lastfont, previous, last = nil, "start", nil
while true do
local upcoming, id = first.next, first.id
if id == glyph_code then
local a = has_attribute(first,a_prestat)
- local current = numbertokind[a]
+ local current = numbertocategory[a]
local action = injectors[previous]
if action then
action = action[current]
@@ -557,7 +558,7 @@ local function process(head,first,last)
local pid, nid = p.id, n.id
if pid == glyph_code and nid == glyph_code then
local pa, na = has_attribute(p,a_prestat), has_attribute(n,a_prestat)
- local pcjk, ncjk = pa and numbertokind[pa], na and numbertokind[na]
+ local pcjk, ncjk = pa and numbertocategory[pa], na and numbertocategory[na]
if not pcjk or not ncjk
or pcjk == "korean" or ncjk == "korean"
or pcjk == "other" or ncjk == "other"
diff --git a/tex/context/base/scrp-ini.lua b/tex/context/base/scrp-ini.lua
index 846d74d87..543211c36 100644
--- a/tex/context/base/scrp-ini.lua
+++ b/tex/context/base/scrp-ini.lua
@@ -35,10 +35,9 @@ local glue_code = nodecodes.glue
local a_preproc = attributes.private('preproc')
local a_prestat = attributes.private('prestat')
-local fontdata = fonts.identifiers
+local fontdata = fonts.hashes.identifiers
-local fcs = fonts.colors.set -- move this to tracers
-local fcr = fonts.colors.reset
+local setnodecolor = nodes.tracers.colors.set
scripts = scripts or { }
local scripts = scripts
@@ -278,7 +277,7 @@ local scriptcolors = allocate { -- todo: just named colors
scripts.colors = scriptcolors
-local numbertokind = allocate { -- rather bound to cjk ... will be generalized
+local numbertocategory = allocate { -- rather bound to cjk ... will be generalized
"korean",
"chinese",
"full_width_open",
@@ -292,20 +291,18 @@ local numbertokind = allocate { -- rather bound to cjk ... will be generalized
"jamo_final",
}
-local kindtonumber = allocate(table.swapped(numbertokind)) -- could be one table
+local categorytonumber = allocate(table.swapped(numbertocategory)) -- could be one table
-scripts.kindtonumber = kindtonumber
-scripts.numbertokind = numbertokind
-
--- some time i will make a fonts.originals[id]
+scripts.categorytonumber = categorytonumber
+scripts.numbertocategory = numbertocategory
local function colorize(start,stop)
for n in traverse_id(glyph_code,start) do
- local kind = numbertokind[has_attribute(n,a_prestat)]
+ local kind = numbertocategory[has_attribute(n,a_prestat)]
if kind then
local ac = scriptcolors[kind]
if ac then
- fcs(n,ac)
+ setnodecolor(n,ac)
end
end
if n == stop then
@@ -364,14 +361,14 @@ function scripts.preprocess(head)
if normal_process then
local f = start.font
if f ~= lastfont then
- originals = fontdata[f].originals
+ originals = fontdata[f].resources.originals
lastfont = f
end
local c = start.char
if originals then c = originals[c] or c end
local h = hash[c]
if h then
- set_attribute(start,a_prestat,kindtonumber[h])
+ set_attribute(start,a_prestat,categorytonumber[h])
if not first then
first, last = start, start
else
diff --git a/tex/context/base/sort-ini.lua b/tex/context/base/sort-ini.lua
index e8580653a..3ff6f1d96 100644
--- a/tex/context/base/sort-ini.lua
+++ b/tex/context/base/sort-ini.lua
@@ -38,8 +38,12 @@ relatively easy to do.</p>
<p>Todo: investigate what standards and conventions there are and see
how they map onto this mechanism. I've learned that users can come up
with any demand so nothing here is frozen.</p>
+
+<p>In the future index entries will become more clever, i.e. they will
+have language etc properties that then can be used.</p>
]]--
+
local utf = unicode.utf8
local gsub, rep, sub, sort, concat = string.gsub, string.rep, string.sub, table.sort, table.concat
local utfbyte, utfchar = utf.byte, utf.char
diff --git a/tex/context/base/spac-ali.mkiv b/tex/context/base/spac-ali.mkiv
index e93b20c63..297302808 100644
--- a/tex/context/base/spac-ali.mkiv
+++ b/tex/context/base/spac-ali.mkiv
@@ -83,17 +83,6 @@
% To be redone:
-% \def\iobox#1#2#3#% here #3# is not really needed
-% {\vbox\bgroup % we want to return a vbox like the others
-% \hbox\bgroup% we need to pack the signal with the box
-% \signalrightpage
-% \dowithnextboxcontent
-% {\let\\=\endgraf\forgetall\doifrightpageelse#1#2}
-% {\box\nextbox\egroup\egroup}
-% \vbox#3}
-% \def\obox{\iobox\raggedleft \raggedright} % outerbox
-% \def\ibox{\iobox\raggedright\raggedleft} % innerbox
-
\def\ibox#1#2#3%
{\vbox\bgroup
\forgetall
@@ -110,33 +99,6 @@
\doifrightpageelse\raggedleft\raggedright
\let\next}
-% \def\dosetraggedvbox#1% can be more keys
-% {\let\raggedbox\vbox
-% \processfirstactioninset
-% [#1]
-% [ \v!left=>\let\raggedbox\lbox,
-% \v!right=>\let\raggedbox\rbox,
-% \v!middle=>\let\raggedbox\cbox,
-% \v!inner=>\let\raggedbox\ibox,
-% \v!outer=>\let\raggedbox\obox,
-% \v!flushleft=>\let\raggedbox\rbox,
-% \v!flushright=>\let\raggedbox\lbox,
-% \v!center=>\let\raggedbox\cbox,
-% \v!no=>\def\raggedbox{\vbox\bgroup\raggedright\let\next=}]}
-
-% \def\dosetraggedhbox#1% can be more keys
-% {\let\raggedbox\hbox
-% \processaction % slow
-% [#1]
-% [ \v!left=>\def\raggedbox{\doalignedline\v!left },
-% \v!right=>\def\raggedbox{\doalignedline\v!right },
-% \v!middle=>\def\raggedbox{\doalignedline\v!middle},
-% \v!inner=>\def\raggedbox{\doalignedline\v!inner },
-% \v!outer=>\def\raggedbox{\doalignedline\v!outer },
-% \v!flushleft=>\def\raggedbox{\doalignedline\v!right },
-% \v!flushright=>\def\raggedbox{\doalignedline\v!left },
-% \v!center=>\def\raggedbox{\doalignedline\v!middle}]}
-
\def\@@ragged@@command{@@ragged@@c}
\def\@@ragged@@hbox {@@ragged@@h}
\def\@@ragged@@vbox {@@ragged@@v}
@@ -651,7 +613,7 @@
\let\centeraligned\midaligned
-\def\regelbegrensd#1{\limitatetext{#1}{\hsize}{\unknown}} % to be translated
+% \def\regelbegrensd#1{\limitatetext{#1}{\hsize}{\unknown}} % to be translated
% indirecte commando's
@@ -686,12 +648,6 @@
\endgroup}
\hbox}
-% \def\doxcheckline % no vbox so no
-% {\doifrightpageelse\donetrue\donefalse
-% \ifdoublesided
-% \ifdone\signalinnerrealign\else\signalouterrealign\fi
-% \fi}
-
\def\doxcheckline % used for floats so multipass anyway
{\signalrightpage\doifrightpageelse\donetrue\donefalse}
@@ -720,9 +676,6 @@
\def\alignedline#1#2% setting default
{\csname\s!do\v!line\ifcsname\s!do\v!line#1\endcsname#1\else#2\fi\endcsname}
-% \def\woordrechts
-% {\groupedcommand{\hfill\hbox}{\parfillskip\zeropoint}}
-
% beware: \wordright{whatever\kern-\rightskip} should work!
% so, no funny boxing here
@@ -756,12 +709,35 @@
% \simplealignedbox{2cm}{right}{x}
-\setvalue{\s!simple\c!align\v!right }#1#2{\hbox to #1{#2\hss}}
-\setvalue{\s!simple\c!align\v!left }#1#2{\hbox to #1{\hss#2}}
-\setvalue{\s!simple\c!align\v!flushright }#1#2{\hbox to #1{\hss#2}}
-\setvalue{\s!simple\c!align\v!flushleft }#1#2{\hbox to #1{#2\hss}}
-\setvalue{\s!simple\c!align\v!middle }#1#2{\hbox to #1{\hss#2\hss}}
-
-\unexpanded\def\simplealignedbox#1{\executeifdefined{\s!simple\c!align#1}{\getvalue{\s!simple\c!align\v!right}}}
+% \setvalue{\s!simple\c!align\v!right }#1#2{\hbox to #1{#2\hss}}
+% \setvalue{\s!simple\c!align\v!left }#1#2{\hbox to #1{\hss#2}}
+% \setvalue{\s!simple\c!align\v!flushright }#1#2{\hbox to #1{\hss#2}}
+% \setvalue{\s!simple\c!align\v!flushleft }#1#2{\hbox to #1{#2\hss}}
+% \setvalue{\s!simple\c!align\v!middle }#1#2{\hbox to #1{\hss#2\hss}}
+
+% \unexpanded\def\simplealignedbox#1%
+% {\csname\s!simple\c!align\ifcsname\s!simple\c!align#1\endcsname#1\else\v!right\fi\endcsname}
+
+\setvalue{\s!simple:\c!align:\v!right }#1{{#1\hss}}
+\setvalue{\s!simple:\c!align:\v!left }#1{{\hss#1}}
+\setvalue{\s!simple:\c!align:\v!flushright }#1{{\hss#1}}
+\setvalue{\s!simple:\c!align:\v!flushleft }#1{{#1\hss}}
+\setvalue{\s!simple:\c!align:\v!middle }#1{{\hss#1\hss}}
+
+\unexpanded\def\simplealignedbox#1#2%
+ {\hbox to #1\csname\s!simple:\c!align:\ifcsname\s!simple:\c!align:#2\endcsname#2\else\v!right\fi\endcsname}
+
+% \setvalue{spac_align_set_ss_\v!right }#1#2{\let#1\relax\let#2\hss }
+% \setvalue{spac_align_set_ss_\v!left }#1#2{\let#1\hss \let#2\relax}
+% \setvalue{spac_align_set_ss_\v!flushright}#1#2{\let#1\hss \let#2\relax}
+% \setvalue{spac_align_set_ss_\v!flushleft }#1#2{\let#1\relax\let#2\hss }
+% \setvalue{spac_align_set_ss_\v!middle }#1#2{\let#1\hss \let#2\hss }
+% \setvalue{spac_align_set_ss_\v!low }#1#2{\let#1\vss \let#2\relax}
+% \setvalue{spac_align_set_ss_\v!high }#1#2{\let#1\relax\let#2\vss }
+% \setvalue{spac_align_set_ss_\v!lohi }#1#2{\let#1\vss \let#2\vss }
+% \setvalue{spac_align_set_ss_\s!unknown }#1#2{\let#1\relax\let#2\relax}
+
+% \unexpanded\def\spac_align_set_ss#1%
+% {\csname spac_align_set_ss_\ifcsname spac_align_set_ss_#1\endcsname#1\else\s!unknown\fi\endcsname}
\protect \endinput
diff --git a/tex/context/base/spac-grd.mkiv b/tex/context/base/spac-grd.mkiv
index 243e20817..979f56056 100644
--- a/tex/context/base/spac-grd.mkiv
+++ b/tex/context/base/spac-grd.mkiv
@@ -228,7 +228,7 @@
{\ifvmode
\bgroup
\setbaselinecorrections
- \whitespace
+ \whitespace % no longer ok
\nointerlineskip
\dotopbaselinecorrection
\egroup
@@ -246,6 +246,23 @@
\let\forcedbotbaselinecorrection\botbaselinecorrection
+% experiment, todo: proper mkiv mechanism
+
+\def\dotopbaselinecorrection {\blank[\thetopbaselinecorrection ]}
+\def\dobotbaselinecorrection {\blank[\thebotbaselinecorrection ]}
+\def\donegtopbaselinecorrection{\blank[\thenegtopbaselinecorrection]}
+\def\donegbotbaselinecorrection{\blank[\thenegbotbaselinecorrection]}
+
+\def\forcedtopbaselinecorrection
+ {\ifvmode
+ \bgroup
+ \setbaselinecorrections
+ % \vspacing[white]
+ \nointerlineskip
+ \dotopbaselinecorrection
+ \egroup
+\fi}
+
\let\normalstartbaselinecorrection\startbaselinecorrection
\unexpanded\def\startbaselinecorrection
diff --git a/tex/context/base/spac-hor.mkiv b/tex/context/base/spac-hor.mkiv
index fd4febabb..39edaa2ff 100644
--- a/tex/context/base/spac-hor.mkiv
+++ b/tex/context/base/spac-hor.mkiv
@@ -260,7 +260,7 @@
%D \macros
%D {frenchspacing,nonfrenchspacing}
%D
-%D Smehow \type{\frenchspacing} can lead to hyphenation between
+%D Somehow \type{\frenchspacing} can lead to hyphenation between
%D dashes so we now have \type {\newfrenchspacing} (moved from
%D \type {syst-chr}).
@@ -888,7 +888,7 @@
\normalspaces % to be sure
\to \everybeforeoutput
-%D A more robust variant ofthe \MKII\ one:
+%D A more robust variant of the \MKII\ one:
%D
%D \startbuffer
%D bla \TEX\autoinsertnextspace bla
diff --git a/tex/context/base/spac-ver.mkiv b/tex/context/base/spac-ver.mkiv
index fb84e186f..220e1c15c 100644
--- a/tex/context/base/spac-ver.mkiv
+++ b/tex/context/base/spac-ver.mkiv
@@ -78,39 +78,6 @@
\fi
-% \def\presetnormallineheight
-% {\edef\normallineheight{\@@itline}%
-% %done elsewhere : \spacing\!!plusone % new per 10/08/2004, else problems in otr / !! needed
-% \iflocalinterlinespace \else
-% \doifdefined\bodyfontinterlinespecs
-% {\doifsomething\bodyfontinterlinespace
-% {\edef\normallineheight{\bodyfontinterlinespace}}}%
-% \fi}
-
-% \unexpanded\def\setupspecifiedinterlinespace[#1]%
-% {\getparameters[\??it][#1]%
-% \scratchdimen0\@@itheight\points
-% \advance\scratchdimen 0\@@itdepth\points
-% \ifdim\scratchdimen>\onepoint
-% \showmessage\m!layouts{10}{\@@itheight,\@@itdepth}%
-% \let\@@itheight\strutheightfactor
-% \let\@@itdepth \strutdepthfactor
-% \else
-% \let\strutheightfactor\@@itheight
-% \let\strutdepthfactor \@@itdepth
-% \fi
-% \let\minimumstrutheight \@@itminheight
-% \let\minimumstrutdepth \@@itmindepth
-% \let\minimumlinedistance\@@itdistance
-% \let\normallineheight \@@itline % let ! ! ! ! ! ivm ex
-% \doifelse\@@ittop\v!height % new, topskip does more bad than good
-% {\let\topskipfactor \@@itheight}
-% {\let\topskipfactor \@@ittop }%
-% \let\maxdepthfactor \@@itbottom
-% \let\baselinegluefactor \@@itstretch
-% \setfontparameters % redundant, can be \setstrut, test first
-% \updateraggedskips} % yes indeed
-
\def\presetnormallineheight
{\edef\normallineheight{\interlinespaceparameter\c!line}%
%done elsewhere : \spacing\!!plusone % new per 10/08/2004, else problems in otr / !! needed
@@ -150,16 +117,6 @@
\setfontparameters}
\setvalue{\??it::\v!auto }{\let\setrelativeinterlinespace\dosetrelativeinterlinespace}
-% \def\dosetspecifiedrelativeinterlinespace#1%
-% {\assignvalue{#1}\currentrelativeinterlinespace{1.00}{1.25}{1.50}%
-% \spacing\currentrelativeinterlinespace}
-
-% \def\dosetspecifiedrelativeinterlinespace#1% fragile?
-% {\doifdimensionelse{#1}
-% {\setupspecifiedinterlinespace[\c!line=#1]}
-% {\assignvalue{#1}\currentrelativeinterlinespace{1.00}{1.25}{1.50}%
-% \spacing\currentrelativeinterlinespace}}
-
\def\dosetspecifiedrelativeinterlinespace#1% fragile?
{\doifdimenstringelse{#1}
{\setupspecifiedinterlinespace[\c!line=#1]}
@@ -183,15 +140,9 @@
\let\setrelativeinterlinespace\relax
-% \appendtoks \setrelativeinterlinespace \to \everybodyfont
-
\newtoks \everysetupglobalinterlinespace
\newtoks \everysetuplocalinterlinespace
-% \def\complexsetupinterlinespace[#1]% \commalistelement ipv #1
-% {\doifassignmentelse{#1}\setupspecifiedinterlinespace\setuprelativeinterlinespace[#1]%
-% \the\iflocalinterlinespace\everysetuplocalinterlinespace\else\everysetupglobalinterlinespace\fi}
-
\def\interlinespaceparameter #1{\csname\dointerlinespaceparameter{\??it\currentinterlinespace}#1\endcsname}
\def\dointerlinespaceparameter #1#2{\ifcsname#1#2\endcsname#1#2\else\expandafter\dointerlinespaceparentparameter\csname#1\s!parent\endcsname#2\fi}
\def\dointerlinespaceparentparameter#1#2{\ifx#1\relax\s!empty\else\dointerlinespaceparameter#1#2\fi}
@@ -236,23 +187,6 @@
\the\everysetuplocalinterlinespace
\localinterlinespacefalse}
-% \def\dosetupcheckedinterlinespace#1% often a chain
-% {\edef\askedinterlinespace{#1}%
-% \ifx\askedinterlinespace\empty
-% \simplesetupinterlinespace
-% \else
-% \normalexpanded{\noexpand\doifassignmentelse{\askedinterlinespace}%
-% \noexpand\setupspecifiedinterlinespace
-% \noexpand\setuprelativeinterlinespace[\askedinterlinespace]}%
-% \iflocalinterlinespace
-% \the\everysetuplocalinterlinespace
-% \else
-% \localinterlinespacetrue
-% \the\everysetuplocalinterlinespace
-% \localinterlinespacefalse
-% \fi
-% \fi}
-
\def\dosetupcheckedinterlinespace#1% often a chain
{\edef\askedinterlinespace{#1}%
\ifx\askedinterlinespace\empty
@@ -282,29 +216,6 @@
\fi
\fi\fi}
-% \unexpanded\def\setuplocalinterlinespace[#1]%
-% {\localinterlinespacetrue
-% \let\@@saveditheight \@@itheight
-% \let\@@saveditdepth \@@itdepth
-% \let\@@saveditline \@@itline
-% \let\@@saveditminheight\@@itminheight
-% \let\@@saveditmindepth \@@itmindepth
-% \let\@@saveditdistance \@@itdistance
-% \let\@@savedittop \@@ittop
-% \let\@@saveditbottom \@@itbottom
-% \let\@@saveditstretch \@@itstretch
-% \setupinterlinespace[#1]%
-% \let\@@itheight \@@saveditheight
-% \let\@@itdepth \@@saveditdepth
-% \let\@@itline \@@saveditline
-% \let\@@itminheight\@@saveditminheight
-% \let\@@itmindepth \@@saveditmindepth
-% \let\@@itdistance \@@saveditdistance
-% \let\@@ittop \@@savedittop
-% \let\@@itbottom \@@saveditbottom
-% \let\@@itstretch \@@saveditstretch
-% \localinterlinespacefalse}
-
\unexpanded\def\setuplocalinterlinespace[#1]%
{\localinterlinespacetrue
\pushmacro\currentinterlinespace
@@ -537,38 +448,10 @@
\def\dowhitespacemethod#1%
{\ifcsname\??ws\??ws#1\endcsname\csname\??ws\??ws#1\endcsname\else\ctxparskip#1\fi\relax}
-
-% \def\nowhitespace
-% {\ifdim\parskip>\zeropoint\relax
-% \ifdim\lastskip=-\parskip
-% \else
-% \vskip-\parskip
-% \fi
-% \fi}
-%
-% \def\nowhitespaceunlessskip
-% {\ifdim\lastskip>\zeropoint \else
-% \nowhitespace
-% \fi}
-%
-% \def\whitespace
-% {\par
-% \ifdim\parskip>\zeropoint\relax
-% %\ifdim\lastskip>\parskip \else
-% % \removelastskip interferes with blanko blokkeer en klein
-% \vskip\parskip
-% %\fi
-% \fi}
\def\nowhitespace{\vspacing[\v!nowhite]}
\def\whitespace {\vspacing[\v!white]}
-% obsolete:
-%
-% \def\savedcurrentwhitespace{\currentwhitespace}
-% \def\savecurrentwhitespace {\edef\savedcurrentwhitespace{\currentwhitespace}}
-% \def\restorecurrentwhitespace{\edef\currentwhitespace{\savedcurrentwhitespace}}
-
% De onderstaande macro handelt ook de situatie dat er geen
% tekst tussen \start ... \stop is geplaatst. Daartoe wordt de
% laatste skip over de lege tekst heen gehaald. Dit komt goed
@@ -979,7 +862,6 @@
\def\strut{\relax\dontleavehmode\copy\strutbox} % still callbacks for \hbox{\strut}
-
\let\normalstrut\strut
%D Sometimes a capstrut comes in handy
@@ -1121,13 +1003,6 @@
%D why|>| this assignment gives troubles in for instance the
%D visual debugger.
-%D The plain ones:
-
-% \def\offinterlineskip
-% {\baselineskip-\thousandpoint
-% \lineskip\zeropoint
-% \lineskiplimit\maxdimen}
-
\def\offinterlineskip
{\baselineskip-\thousandpoint
\lineskip\zeropoint
@@ -1363,11 +1238,6 @@
\attribute \snapvboxattribute \attribute\snapmethodattribute}%
\fi}
-
-% \appendtoks
-% \dosetupgridsnapping
-% \to \everysetupbodyfont
-
\def\installsnapvalues#1#2% todo: a proper define
{\edef\currentsnapper{#1:#2}%
\ifcsname\currentsnapper\endcsname \else
@@ -1454,11 +1324,6 @@
\global\globalbodyfontstrutheight\strutheight
\global\globalbodyfontstrutdepth \strutdepth}
-% \appendtoks
-% \synchronizegloballinespecs
-% \synchronizelocallinespecs
-% \to \everysetupgridsnapping
-
\appendtoks
\synchronizegloballinespecs
\synchronizelocallinespecs
@@ -1468,10 +1333,6 @@
\synchronizelocallinespecs
\to \everysetuplocalinterlinespace
-% \appendtoks
-% \resetsnapvalues
-% \to \everyforgetall
-
%D Snapping.
\newif\ifgridsnapping
@@ -1557,10 +1418,6 @@
\fi
\gridboxvbox % calculated size
{\getrawnoflines{#3}% \getnoflines{#3}%
-% \ifgridsnapping \else
-% \vskip\topskip
-% \vskip-\strutht
-% \fi
\scratchdimen#2\advance\scratchdimen \lineheight
\dorecurse\noflines
{\strut
@@ -1586,10 +1443,6 @@
\def\fuzzysnappedbox#1#2% \box<n> \unvbox<n>
{#1#2}
-% \def\moveboxontogrid#1#2#3% will become obsolete
-% {\doif{#2}\v!top {\setbox#1\hbox{\snaptogrid[\v!first]\box#1}}%
-% \doif{#2}\v!bottom{\setbox#1\hbox{\snaptogrid[\v!last ]\box#1}}}
-
\def\moveboxontogrid#1#2#3% will become obsolete
{}
@@ -1730,9 +1583,6 @@
\unexpanded\def\definevspacingamount
{\dotripleempty\dodefinevspacingamount}
-% \def\dodefinevspacingamount[#1][#2][#3]%
-% {\ctxlua{builders.vspacing.setskip("#1",\!!bs\detokenize{#2}\!!es,\!!bs\detokenize{#3}\!!es)}}
-
\def\dodefinevspacingamount[#1][#2][#3]% can be combined
{\setvalue{\??vs:#1}{\ifgridsnapping#3\else#2\fi}%
\ctxlua{builders.vspacing.setskip("#1")}}
@@ -1801,16 +1651,6 @@
% category:4 is default
-% \definevspacingamount[\v!big] [\bigskipamount] [\openlineheight]
-% \definevspacingamount[\v!medium] [\medskipamount] [0.50\openlineheight]
-% \definevspacingamount[\v!small] [\smallskipamount] [0.25\openlineheight]
-% \definevspacingamount[\v!line] [\openlineheight] [\openlineheight]
-% \definevspacingamount[\v!halfline][0.50\openlineheight][0.50\openlineheight]
-% \definevspacingamount[\v!formula] [\medskipamount] [0.50\openlineheight]
-% \definevspacingamount[\v!white] [\parskip] [\openlineheight]
-% \definevspacingamount[\v!height] [\strutheight] [\strutheight]
-% \definevspacingamount[\v!depth] [\strutdepth] [\strutdepth]
-
\definevspacingamount[\v!none] [\zeropoint] [\zeropoint]
\definevspacingamount[\v!big] [\bigskipamount] [\bodyfontlineheight]
\definevspacingamount[\v!medium] [\medskipamount] [0.50\bodyfontlineheight]
@@ -1849,26 +1689,6 @@
\dorecurse{10} % todo: other values < 4000
{\expanded{\definevspacing[\v!samepage-\recurselevel][penalty:\the\numexpr4000+250*\recurselevel\relax]}}
-% \setfalse\vspacingenabled
-%
-% \newtoks\everyenablevspacing
-% \newtoks\everydisablevspacing
-%
-% \def\enablevspacing {\the\everyenablevspacing}
-% \def\disablevspacing{\the\everydisablevspacing}
-%
-% \appendtoks
-% \writestatus\m!system{! ! enabling vspacing ! !}%
-% \settrue\vspacingenabled
-% \ctxlua{builders.vspacing.enable()}%
-% \to \everyenablevspacing
-%
-% \appendtoks
-% \writestatus\m!system{! ! disabling vspacing ! !}%
-% \setfalse\vspacingenabled
-% \ctxlua{builders.vspacing.disable()}%
-% \to \everydisablevspacing
-
\let\blank \vspacing
\let\defineblank \definevspacing
\let\defineblankmethod\definevspacingamount
@@ -1937,48 +1757,6 @@
%D \stoplines
%D \stoptyping
-% \unexpanded\def\setuplines
-% {\dodoubleargument\getparameters[\??rg]}
-%
-% \unexpanded\def\startlines
-% {\@@rgbefore
-% \pushmacro\checkindentation
-% \whitespace
-% %\page[\v!preference]} gaat mis na koppen, nieuw: later \nobreak
-% \begingroup
-% \setupindenting[\@@rgindenting]%
-% \typesettinglinestrue
-% \setupwhitespace[\v!none]%
-% \obeylines
-% \ignorespaces
-% \gdef\afterfirstobeyedline % tzt two pass, net als opsomming
-% {\gdef\afterfirstobeyedline
-% {\nobreak
-% \doifnot\@@rgoption\v!packed{\global\let\afterfirstobeyedline\relax}}}%
-% \def\obeyedline
-% {\par
-% \futurelet\next\dobetweenthelines}%
-% \activatespacehandler\@@rgspace
-% \GotoPar}
-%
-% \unexpanded\def\stoplines
-% {\endgroup
-% \popmacro\checkindentation
-% \@@rgafter}
-%
-% \def\dobetweenthelines
-% {\doifmeaningelse\next\obeyedline
-% {\@@rginbetween}
-% {\afterfirstobeyedline}}
-%
-% \setuplines
-% [\c!option=,
-% \c!before=\blank,
-% \c!after=\blank,
-% \c!inbetween=\blank,
-% \c!indenting=\v!no,
-% \c!space=\v!default]
-
%D Contrary to \MKII\ we can now define classes of lines (generalized by
%D Wolfgang). I will probably rewrite bits in \LUA.
@@ -2026,30 +1804,6 @@
{\def\docommand##1{\getparameters[\??rg##1][#2]}%
\processcommacommand[#1]\docommand}}
-% \def\dostartlines[#1]%
-% {\bgroup
-% \edef\currentlines{#1}%
-% \linesparameter\c!before
-% \pushmacro\checkindentation
-% \whitespace
-% \begingroup
-% \dosetlinesattributes\c!style\c!color
-% \setupindenting[\linesparameter\c!indenting]%
-% \setupalign[\linesparameter\c!align]%
-% \typesettinglinestrue
-% \setupwhitespace[\v!none]%
-% \obeylines
-% \ignorespaces
-% \gdef\afterfirstobeyedline % tzt two pass, net als opsomming
-% {\gdef\afterfirstobeyedline
-% {\nobreak
-% \doifnot{\linesparameter\c!option}\v!packed{\global\let\afterfirstobeyedline\relax}}}%
-% \def\obeyedline
-% {\par
-% \futurelet\next\dobetweenthelines}%
-% \activatespacehandler{\linesparameter\c!space}%
-% \GotoPar}
-
\def\dostartlines[#1]%
{\bgroup
\edef\currentlines{#1}%
diff --git a/tex/context/base/status-files.pdf b/tex/context/base/status-files.pdf
index bb84d7da8..9601ad93f 100644
--- a/tex/context/base/status-files.pdf
+++ b/tex/context/base/status-files.pdf
Binary files differ
diff --git a/tex/context/base/strc-blk.lua b/tex/context/base/strc-blk.lua
index 5040c34e5..0c94af5bb 100644
--- a/tex/context/base/strc-blk.lua
+++ b/tex/context/base/strc-blk.lua
@@ -35,7 +35,8 @@ end
job.register('structures.blocks.collected', tobesaved, initializer)
-local printer = (lpeg.patterns.textline/tex.print)^0 -- can be shared
+local printer = (lpeg.patterns.textline/tex.print)^0 -- can be shared
+local listitem = utilities.parsers.listitem
function blocks.print(name,data,hide)
if hide then
@@ -58,7 +59,7 @@ end
function blocks.setstate(state,name,tag)
local all = tag == ""
local tags = not all and settings_to_array(tag)
- for n in gmatch(name,"%s*([^,]+)") do
+ for n in listitem(name) do
local sn = states[n]
if not sn then
-- error
diff --git a/tex/context/base/strc-des.mkiv b/tex/context/base/strc-des.mkiv
index 9cca5e8d4..54eba1eaa 100644
--- a/tex/context/base/strc-des.mkiv
+++ b/tex/context/base/strc-des.mkiv
@@ -902,7 +902,7 @@
userdata = structures.helpers.touserdata(\!!bs\detokenize{#2}\!!es)
}
}}%
- \xdef\currentdescriptionattribute {\ctxlua {tex.write(structures.references.setinternalreference("\referenceprefix","\currentdescriptionreference",\nextinternalreference,"\@@iafocus"))}}%
+ \xdef\currentdescriptionattribute {\ctxlua {tex.write(structures.references.setinternalreference("\referenceprefix","\currentdescriptionreference",\nextinternalreference,"\interactionparameter\c!focus"))}}%
\xdef\currentdescriptionsynchronize{\ctxlatelua{structures.lists.enhance(\currentdescriptionnumberentry)}}%
\fi
\endgroup}
diff --git a/tex/context/base/strc-doc.mkiv b/tex/context/base/strc-doc.mkiv
index 0942de4c3..683d65d2f 100644
--- a/tex/context/base/strc-doc.mkiv
+++ b/tex/context/base/strc-doc.mkiv
@@ -188,7 +188,7 @@
\let\previousstructurecounter\!!zerocount
\def\setstructuresynchronization#1%
- {\xdef\currentstructureattribute {\ctxlua {tex.write(structures.references.setinternalreference("\currentstructurereferenceprefix","\currentstructurereference",\nextinternalreference,"\@@iafocus"))}}%
+ {\xdef\currentstructureattribute {\ctxlua {tex.write(structures.references.setinternalreference("\currentstructurereferenceprefix","\currentstructurereference",\nextinternalreference,"\interactionparameter\c!focus"))}}%
\xdef\currentstructuresynchronize{\ctxlatelua{structures.lists.enhance(#1)}}}
\def\reportcurrentstructure{\ctxlua{structures.sections.reportstructure()}}
diff --git a/tex/context/base/strc-itm.mkiv b/tex/context/base/strc-itm.mkiv
index d0cf8817f..24e343132 100644
--- a/tex/context/base/strc-itm.mkiv
+++ b/tex/context/base/strc-itm.mkiv
@@ -46,7 +46,7 @@
\newcount\noflistelements
\newcount\itemcolumndepth
\newcount\itemdepth
-\newcount\maxitemdepth \maxitemdepth=6
+% \newcount\maxitemdepth \maxitemdepth=6
\newdimen\itemgrouplistwidth
\newdimen\itemgroupaskedwidth
@@ -202,10 +202,11 @@
% so we have:
\def\initializeitemgrouplevel#1%
- {\ifcsname\??op\currentitemgroup#1\s!parent\endcsname
+ {\ifcsname\??op\currentitemgroup\number#1\s!parent\endcsname
% ok
\else
- \setevalue{\??op\currentitemgroup#1\s!parent}{\??op\currentitemgroup}%
+ \setxvalue{\??op\currentitemgroup \c!levels}{\number#1}%
+ \setxvalue{\??op\currentitemgroup\number#1\s!parent}{\??op\currentitemgroup}%
\fi}
\unexpanded\def\defineitemgroup
@@ -215,15 +216,15 @@
{\doifsomething{#1}
{\pushmacro\currentitemgroup
\def\currentitemgroup{#1}%
- \setvalue{\e!start#1}{\startitemgroup[#1]}%
- \setvalue{\e!stop#1}{\stopitemgroup}%
- \setvalue{\e!setup#1\e!endsetup}{\setupitemgroup[#1]}% for old times sake
+ \setuvalue{\e!start#1}{\startitemgroup[#1]}%
+ \setuvalue{\e!stop#1}{\stopitemgroup}%
+ \setuvalue{\e!setup#1\e!endsetup}{\setupitemgroup[#1]}% for old times sake
\doifelsenothing{#2}
{\getparameters[\??op#1][\s!parent=\??oo,#3]}%
{\doifassignmentelse{#2}
{\getparameters[\??op#1][\s!parent=\??oo,#2]}%
{\getparameters[\??op#1][\s!parent=\??op#2,#3]}}%
- \dorecurse\maxitemdepth{\initializeitemgrouplevel\recurselevel}%
+ \dorecurse{\itemparameter\empty\c!levels}{\initializeitemgrouplevel\recurselevel}%
\definestructurecounter[itemgroup:#1]%
\popmacro\currentitemgroup}}
@@ -359,7 +360,7 @@
\getitemparameter\currentitemlevel\c!afterhead
\fi\fi}
-\def\dododododosetupitemgroup[#1][#2]%
+\unexpanded\def\dododododosetupitemgroup[#1][#2]% prevent expansion below
{\doifassignmentelse{#2}%
{\dosetupitemgroupvariable[#1][#2]}%
{\setitemparameter{#1}\c!option{#2}}}%
@@ -367,19 +368,8 @@
\def\dodododosetupitemgroup[#1][#2]%
{\doifsomething{#2}
{\doifelse{#1}\v!each
- {\dorecurse\maxitemdepth{\normalexpanded{\noexpand\dododododosetupitemgroup[\recurselevel]}[#2]}}
- {\normalexpanded{\noexpand\dododododosetupitemgroup[#1]}[#2]}}}
-
-% \def\dododosetupitemgroup[#1][#2]%
-% {\doifelsenothing{#2}
-% {\doifelsenothing{#1}
-% {\dodododosetupitemgroup[\currentitemlevel][#2]}
-% {\dodododosetupitemgroup[#1][#2]}}
-% {\ifcase\currentitemlevel\relax
-% \dodododosetupitemgroup[\v!each][#1]%
-% \else
-% \dodododosetupitemgroup[\currentitemlevel][#1]%
-% \fi}}
+ {\dorecurse{\itemparameter\empty\c!levels}{\normalexpanded{\dododododosetupitemgroup[\recurselevel]}[#2]}}
+ {\normalexpanded{\dododododosetupitemgroup[#1]}[#2]}}}
\def\dododosetupitemgroup[#1][#2]%
{\doifelsenothing{#2}
@@ -538,13 +528,8 @@
\def\dodostartitemgroup[#1]% [#2]%
{\relax % prevents lookahead
- \ifnum\currentitemlevel=\maxitemdepth\relax
- \showmessage\m!layouts9{\number\maxitemdepth}%
- \let\itemincrement\zerocount
- \else
- \let\itemincrement\plusone
- \fi
- \global\advance\itemdepth\itemincrement
+ \global\advance\itemdepth\plusone
+ \initializeitemgrouplevel\itemdepth
\xdef\currentitemlevel{\number\itemdepth}%
\edef\itemgroupoptions{\getitemparameter\currentitemlevel\c!option}%
\ifx\itemgroupoptions\empty
@@ -818,12 +803,12 @@
\fi
\ifconditional\textlistitem % else forgotten
\endgroup
- \global\advance\itemdepth-\itemincrement
+ \global\advance\itemdepth-\plusone
\xdef\currentitemlevel{\number\itemdepth}%
\egroup
\else
\endgroup
- \global\advance\itemdepth-\itemincrement
+ \global\advance\itemdepth-\plusone
\xdef\currentitemlevel{\number\itemdepth}%
\egroup
\par
@@ -1385,6 +1370,7 @@
%\c!inner=,
\c!n=2,
\c!items=4,
+ \c!levels=10,
\c!lefttext=(,
\c!righttext=),
\c!start=1,
diff --git a/tex/context/base/strc-lst.mkiv b/tex/context/base/strc-lst.mkiv
index 50458c4d5..b14297e26 100644
--- a/tex/context/base/strc-lst.mkiv
+++ b/tex/context/base/strc-lst.mkiv
@@ -635,13 +635,7 @@
{\edef\currentlist{#1}%
\edef\currentlistnumber{#3}%
\docurrentlistalternative
- \let\@@iawidth\!!zeropoint % todo: constant or so
-% \begingroup
-% \edef\listelements{\listparameter\c!pageboundaries}%
-% \normalexpanded{\noexpand\doifinset{#3}{\listelements}}
-% {\showmessage\m!system{14}{#3}%
-% \page}%
-% \endgroup
+ \letinteractionparameter\c!width\zeropoint
\dontcomplain
\dosomelistelement{#1}{#2}{#3}{#4}{#5}{#6}}
diff --git a/tex/context/base/strc-num.lua b/tex/context/base/strc-num.lua
index 943e9fd4f..b8a62d152 100644
--- a/tex/context/base/strc-num.lua
+++ b/tex/context/base/strc-num.lua
@@ -6,6 +6,8 @@ if not modules then modules = { } end modules ['strc-num'] = {
license = "see context related readme files"
}
+-- this will be reimplemented
+
local format = string.format
local next, type = next, type
local min, max = math.min, math.max
@@ -117,7 +119,7 @@ local function enhance()
enhance = nil
end
-local function allocate(name,i)
+local function allocate(name,i) -- can be metatable
local cd = counterdata[name]
if not cd then
cd = {
diff --git a/tex/context/base/strc-ref.lua b/tex/context/base/strc-ref.lua
index d97de03ed..eeca38bb6 100644
--- a/tex/context/base/strc-ref.lua
+++ b/tex/context/base/strc-ref.lua
@@ -137,20 +137,6 @@ function references.referredpage(n)
return referred[n] or referred[n] or texcount.realpageno
end
-function references.checkedpage(n,page)
- local r, p = referred[n] or texcount.realpageno, tonumber(page)
- if not p then
- -- sorry
- elseif p > r then
- texcount.referencepagestate = 3
- elseif p < r then
- texcount.referencepagestate = 2
- else
- texcount.referencepagestate = 1
- end
- return p
-end
-
function references.registerpage(n)
if not tobereferred[n] then
if n > maxreferred then
@@ -319,7 +305,7 @@ local function register_from_lists(collected,derived)
if kind and realpage then
local d = derived[prefix] if not d then d = { } derived[prefix] = d end
local t = { kind, i }
- for s in gmatch(reference,"%s*([^,]+)") do
+ for s in gmatch(reference,"[^, ]+") do
if trace_referencing then
report_references("list entry %s provides %s reference '%s' on realpage %s",i,kind,s,realpage)
end
@@ -784,39 +770,67 @@ end
references.currentset = nil
-local b, e = "\\ctxlua{local jc = structures.references.currentset;", "}"
-local o, a = 'jc[%s].operation=[[%s]];', 'jc[%s].arguments=[[%s]];'
+--~ local b, e = "\\ctxlua{local jc = structures.references.currentset;", "}"
+--~ local o, a = 'jc[%s].operation=[[%s]];', 'jc[%s].arguments=[[%s]];'
+--~
+--~ function references.expandcurrent() -- todo: two booleans: o_has_tex& a_has_tex
+--~ local currentset = references.currentset
+--~ if currentset and currentset.has_tex then
+--~ local done = false
+--~ for i=1,#currentset do
+--~ local ci = currentset[i]
+--~ local operation = ci.operation
+--~ if operation then
+--~ if find(operation,"\\") then -- if o_has_tex then
+--~ if not done then
+--~ context(b)
+--~ done = true
+--~ end
+--~ context(o,i,operation)
+--~ end
+--~ end
+--~ local arguments = ci.arguments
+--~ if arguments then
+--~ if find(arguments,"\\") then -- if a_has_tex then
+--~ if not done then
+--~ context(b)
+--~ done = true
+--~ end
+--~ context(a,i,arguments)
+--~ end
+--~ end
+--~ end
+--~ if done then
+--~ context(e)
+--~ end
+--~ end
+--~ end
+
+function commands.setreferenceoperation(k,v)
+ references.currentset.operation[k] = v
+end
+
+function commands.setreferencearguments(k,v)
+ references.currentset.arguments[k] = v
+end
+
+local expandreferenceoperation = context.expandreferenceoperation
+local expandreferencearguments = context.expandreferencearguments
function references.expandcurrent() -- todo: two booleans: o_has_tex& a_has_tex
local currentset = references.currentset
if currentset and currentset.has_tex then
- local done = false
for i=1,#currentset do
local ci = currentset[i]
local operation = ci.operation
- if operation then
- if find(operation,"\\") then -- if o_has_tex then
- if not done then
- context(b)
- done = true
- end
- context(o,i,operation)
- end
+ if operation and find(operation,"\\") then -- if o_has_tex then
+ expandreferenceoperation(i,operation)
end
local arguments = ci.arguments
- if arguments then
- if find(arguments,"\\") then -- if a_has_tex then
- if not done then
- context(b)
- done = true
- end
- context(a,i,arguments)
- end
+ if arguments and find(arguments,"\\") then -- if a_has_tex then
+ expandreferencearguments(i,arguments)
end
end
- if done then
- context(e)
- end
end
end
@@ -1377,17 +1391,31 @@ references.testspecials = references.testspecials or { }
local runners = references.testrunners
local specials = references.testspecials
+local function checkedpagestate(n,page)
+ local r, p = referred[n] or texcount.realpageno, tonumber(page)
+ if not p then
+ return 0
+ elseif p > r then
+ return 3
+ elseif p < r then
+ return 2
+ else
+ return 1
+ end
+end
+
function references.analyze(actions)
actions = actions or references.currentset
if not actions then
actions = { realpage = 0 }
+ texcount.referencepagestate = 0
elseif actions.realpage then
-- already analyzed
+ texcount.referencepagestate = checkedpagestate(actions.n,actions.realpage)
else
-- we store some analysis data alongside the indexed array
-- at this moment only the real reference page is analyzed
-- normally such an analysis happens in the backend code
- texcount.referencepagestate = 0
local nofactions = #actions
if nofactions > 0 then
for i=1,nofactions do
@@ -1397,7 +1425,9 @@ function references.analyze(actions)
what = what(a,actions)
end
end
- references.checkedpage(actions.n,actions.realpage)
+ texcount.referencepagestate = checkedpagestate(actions.n,actions.realpage)
+ else
+ texcount.referencepagestate = 0
end
end
return actions
@@ -1425,7 +1455,7 @@ references.realpageofpage = realpageofpage
--
-references.pages = allocate {
+local pages = allocate {
[variables.firstpage] = function() return counters.record("realpage")["first"] end,
[variables.previouspage] = function() return counters.record("realpage")["previous"] end,
[variables.nextpage] = function() return counters.record("realpage")["next"] end,
@@ -1440,6 +1470,8 @@ references.pages = allocate {
[variables.backward] = function() return counters.record("realpage")["backward"] end,
}
+references.pages = pages
+
-- maybe some day i will merge this in the backend code with a testmode (so each
-- runner then implements a branch)
@@ -1458,6 +1490,8 @@ end
runners["special operation"] = runners["special"]
runners["special operation with arguments"] = runners["special"]
+-- weird, why is this code here and in lpdf-ano
+
function specials.internal(var,actions)
local v = references.internals[tonumber(var.operation)]
local r = v and v.references.realpage
@@ -1468,25 +1502,32 @@ end
specials.i = specials.internal
--- weird, why is this code here and in lpdf-ano
-
-local pages = references.pages
-
-function specials.page(var,actions) -- is this ok?
- local p = pages[var.operation]
+function specials.page(var,actions)
+ local o = var.operation
+ local p = pages[o]
if type(p) == "function" then
p = p()
+ else
+ p = tonumber(realpageofpage(tonumber(o)))
end
if p then
- actions.realpage = p
+ var.r = p
+ actions.realpage = actions.realpage or p -- first wins
end
end
-function specials.realpage(var,actions) -- is this ok?
- actions.realpage = tonumber(var.operation)
+function specials.realpage(var,actions)
+ local p = tonumber(var.operation)
+ if p then
+ var.r = p
+ actions.realpage = actions.realpage or p -- first wins
+ end
end
-
-function specials.userpage(var,actions) -- is this ok?
- actions.realpage = tonumber(realpageofpage(var.operation))
+function specials.userpage(var,actions)
+ local p = tonumber(realpageofpage(var.operation))
+ if p then
+ var.r = p
+ actions.realpage = actions.realpage or p -- first wins
+ end
end
diff --git a/tex/context/base/strc-ref.mkiv b/tex/context/base/strc-ref.mkiv
index ecda0387d..60a02c171 100644
--- a/tex/context/base/strc-ref.mkiv
+++ b/tex/context/base/strc-ref.mkiv
@@ -173,7 +173,7 @@
\ifx\currentreferenceuserdata\empty\else
userdata = structures.helpers.touserdata(\!!bs\detokenize{#3}\!!es)
\fi
- },"\@@iafocus")
+ },"\interactionparameter\c!focus")
}%
% todo: optional
\xdef\currentdestinationattribute{\number\lastdestinationattribute}%
@@ -197,7 +197,7 @@
metadata = { % we could assume page to have no metadata
kind = "\s!page",
},
- },"\@@iafocus")
+ },"\interactionparameter\c!focus")
}%
\xdef\currentdestinationattribute{\number\lastdestinationattribute}%
\else
@@ -454,6 +454,9 @@
\def\expandtexincurrentreference % will happen in lua some time
{\ifcase\referencehastexstate\else\ctxlua{structures.references.expandcurrent()}\fi}
+\def\expandreferenceoperation#1#2{\ctxcommand{setreferenceoperation(#1,\!!bs#2\!!es)}}
+\def\expandreferencearguments#1#2{\ctxcommand{setreferencearguments(#1,\!!bs#2\!!es)}}
+
\def\doifreferencefoundelse#1#2#3%
{\ctxlua{structures.references.doifelse("\referenceprefix","#1",\luaconditional\highlighthyperlinks,\luaconditional\gotonewwindow)}%
{\expandtexincurrentreference#2}%
@@ -891,7 +894,7 @@
\unexpanded\def\referencesymbol
{\hbox{\strut\high
- {\setupsymbolset[\@@iasymbolset]%
+ {\setupsymbolset[\interactionparameter\c!symbolset]%
\symbol
[\ifcase\referencepagestate
\v!somewhere
@@ -1066,11 +1069,11 @@
% but at least aditya can play with it now
\doifsomething{\referenceformatparameter\c!style}
{\dosetfontattribute{\??rf\currentreferenceformat}\c!style
- \let\@@iastyle\empty}%
+ \resetinteractionparameter\c!style}%
\doifsomething{\referenceformatparameter\c!color}
{\dosetcolorattribute{\??rf\currentreferenceformat}\c!color
- \let\@@iacontrastcolor\empty
- \let\@@iacolor \empty}%
+ \resetinteractionparameter\c!contrastcolor
+ \resetinteractionparameter\c!color}%
%
\edef\currentreferenceformatlabel{\referenceformatparameter\c!label}%
\ifx\currentreferenceformatlabel\autoreferencelabeltextflag
@@ -1174,7 +1177,7 @@
\attribute\referenceattribute\attributeunsetvalue
\iflocation
\dostarttagged\t!link\empty
- \ctxlua{structures.references.inject("\referenceprefix","#2",\number\dimexpr\@@iaheight\relax,\number\dimexpr\@@iadepth\relax,\extrareferencearguments)}%
+ \ctxlua{structures.references.inject("\referenceprefix","#2",\number\dimexpr\interactionparameter\c!height\relax,\number\dimexpr\interactionparameter\c!depth\relax,\extrareferencearguments)}%
\dostoptagged
\setlocationattributes\??ia
\attribute\referenceattribute\lastreferenceattribute
@@ -1214,7 +1217,7 @@
\ctxlua{structures.references.doifelse("\referenceprefix","#3",\extrareferencearguments)}%
{\expandtexincurrentreference
\dostarttagged\t!link\empty
- \ctxlua{structures.references.injectcurrentset(\number\dimexpr\@@iaheight\relax,\number\dimexpr\@@iadepth\relax)}%
+ \ctxlua{structures.references.injectcurrentset(\number\dimexpr\interactionparameter\c!height\relax,\number\dimexpr\interactionparameter\c!depth\relax)}%
\dostoptagged
\setlocationattributes\??ia
\global\lastsavedreferenceattribute\lastreferenceattribute
@@ -1592,184 +1595,6 @@
% this will be done differently (when it's needed)
\fi}
-%D Buttons are just what their names says: things that can be
-%D clicked (pushed) on. They are similar to \type{\goto},
-%D except that the text argument is not interpreted.
-%D Furthermore one can apply anything to them that can be done
-%D with \type{\framed}.
-%D
-%D \startbuffer
-%D \button[width=3cm,height=1.5cm]{Exit}[ExitViewer]
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D gives
-%D
-%D \getbuffer
-%D
-%D This command is formally specified as:
-%D
-%D \showsetup{button}
-%D
-%D The characteristics can be set with:
-%D
-%D \showsetup{setupbuttons}
-
-\unexpanded\def\setupbuttons
- {\dodoubleargument\getparameters[\??bt]}
-
-\definecomplexorsimpleempty\button
-
-\def\complexbutton
- {\docomplexbutton\??bt}
-
-\presetlocalframed[\??bt]
-
-\long\def\docomplexbutton#1[#2]#3#4% get rid of possible space before [#4]
- {\dodocomplexbutton#1[#2]{#3}#4} % #4 == [
-
-\def\buttonframed{\dodoubleempty\localframed[\??bt]} % goodie
-
-\long\def\dodocomplexbutton#1[#2]#3[#4]% #3 can contain [] -> {#3} later
- {\begingroup
- \doifvalue{#1\c!state}\v!stop\locationfalse
- \iflocation
- \ConvertConstantAfter\doifelse{#3}\v!none\hphantom\hbox
- {\doifelsenothing{#4}
- {\setlocationboxnop#1[#2]{#3}[#4]}
- {\doifreferencefoundelse{#4} % INEFFICIENT
- {\setlocationboxyes#1[#2]{#3}[#4]}
- {\setlocationboxnop#1[#2]{#3}[#4]}}}%
- \fi
- \endgroup}
-
-\setupbuttons
- [\c!state=\v!start]
-
-%D Interaction buttons, in fact a row of tiny buttons, are
-%D typically only used for navigational purposed. The next
-%D macro builds such a row based on a specification list.
-%D
-%D \startbuffer
-%D \interactionbuttons
-%D [width=\hsize][page,PreviousJump,ExitViewer]
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D gives
-%D
-%D \getbuffer
-%D
-%D Apart from individual entries, one can use \type{page} and
-%D \type {subpage} as shortcuts to their four associated buttons.
-%D The symbols are derived from the symbols linked to the
-%D entries.
-
-% does not work well with for instance SomeRef{whatever}
-
-\def\interactionbuttons
- {\dodoubleempty\dointeractionbuttons}
-
-\def\dointeractionbuttons[#1][#2]% er is een verdeel macro \horizontalfractions
- {\iflocation
- % BUG: fails when frame=off; best is to rewrite this macro
- \bgroup
- \doif\@@ibstate\v!stop\locationfalse
- \iflocation
- \ifsecondargument
- \setupinteractionbar[#1]%
- \checkinteractionbar{1.5em}\v!broad\!!zeropoint % brrrrr
- \setbox2\hbox{\localframed[\??ib][\c!background=]{\symbol[\@@iasymbolset][\v!previouspage]}}%
- \!!heighta\ht2 % needed because we default to nothing
- \setupinteractionbar[\c!strut=\v!no]%
- \setinteractionparameter\c!width\!!zeropoint
- \!!counta\zerocount % new, was 1
- \processallactionsinset
- [#2]
- [ \v!page=>\advance\!!counta 4,
- \v!subpage=>\advance\!!counta 4,
- \s!unknown=>\advance\!!counta 1]%
- \ifdim\@@ibwidth=\zeropoint
- \!!widtha2em
- \advance\!!widtha \@@ibdistance % new
- \!!widthb\!!counta\!!widtha
- \advance\!!widthb -\@@ibdistance % new
- \else
- \!!widtha\@@ibwidth
- \!!widthb\@@ibdistance % new
- \multiply\!!widthb \!!counta % new
- \advance\!!widthb -\@@ibdistance % new
- \advance\!!widtha -\!!widthb % new
- \divide\!!widtha \!!counta
- \!!widthb\@@ibwidth
- \fi
- \def\xgoto##1% clash ?
- {\setnostrut
- \edef\localreference{##1}%
- \normalexpanded{\noexpand\dodocomplexbutton\??ib[\c!height=\the\!!heighta,\c!width=\the\!!widtha]}%
- {\dontleavehmode\symbol[\@@iasymbolset][\localreference]}%
- [\localreference]%
- \hss}%
- \hbox to \!!widthb
- {\processallactionsinset
- [#2]
- [ \v!page=>\xgoto\v!firstpage
- \xgoto\v!nextpage
- \xgoto\v!previouspage
- \xgoto\v!lastpage,
- \v!subpage=>\xgoto\v!firstsubpage
- \xgoto\v!nextsubpage
- \xgoto\v!previoussubpage
- \xgoto\v!lastsubpage,
- \s!unknown=>\xgoto\commalistelement]%
- \unskip}%
- \else
- \interactionbuttons[][#1]%
- \fi
- \fi
- \egroup
- \fi}
-
-%D \macros
-%D {overlaybutton}
-%D
-%D For converience we provide:
-%D
-%D \starttyping
-%D \overlaybutton[reference]
-%D \stoptyping
-%D
-%D This command can be used to define overlays an/or can be
-%D used in the whatevertext areas, like:
-%D
-%D \starttyping
-%D \defineoverlay[PrevPage][\overlaybutton{PrevPage}]
-%D \setupbackgrounds[page][background=PrevPage]
-%D \setuptexttexts[\overlaybutton{NextPage}]
-%D \stoptyping
-%D
-%D For practical reasons, this macro accepts square brackets
-%D as well as braces.
-
-\definecomplexorsimple\overlaybutton
-
-\def\simpleoverlaybutton#1%
- {\complexoverlaybutton[#1]}
-
-\def\complexoverlaybutton[#1]%
- {\iflocation
- \gotobox{\overlayfakebox}[#1]%
- \fi}
-
-\def\overlayfakebox
- {\hbox
- {\setbox\scratchbox\emptyhbox
- \wd\scratchbox\overlaywidth
- \ht\scratchbox\overlayheight
- \box\scratchbox}}
-
%D \macros
%D {dotextprefix}
%D
diff --git a/tex/context/base/strc-sec.mkiv b/tex/context/base/strc-sec.mkiv
index ee5c0ec65..350d971a2 100644
--- a/tex/context/base/strc-sec.mkiv
+++ b/tex/context/base/strc-sec.mkiv
@@ -295,13 +295,15 @@
{\setfalse\currentstructureown
%\globalpushmacro\currentstructurehead
\xdef\currentstructurehead{#1}%
+ \structureheadparameter\c!beforesection
\the\everybeforestructurehead
- \dohandlestructurehead{#1}{#2}{#3}} % name -- -- -- userdata
+ \dohandlestructurehead{#1}{#2}{#3}} % name -- -- -- userdata (we might move the tagged to here)
\unexpanded\def\dostopstructurehead[#1]%
- {%\globalpopmacro\currentstructurehead
+ {\dostoptagged\dostoptagged
+ %\globalpopmacro\currentstructurehead
\xdef\currentstructurehead{#1}% recover
- \dostoptagged\dostoptagged
+ \structureheadparameter\c!aftersection
\the\everyafterstructurehead}
\unexpanded\def\donextstructurehead[#1][#2][#3]%
diff --git a/tex/context/base/strc-syn.mkiv b/tex/context/base/strc-syn.mkiv
index ea551625b..1cb1bb1f6 100644
--- a/tex/context/base/strc-syn.mkiv
+++ b/tex/context/base/strc-syn.mkiv
@@ -343,9 +343,9 @@
% maybe just 'commandset' and then combine
\unexpanded\def\placelistofsorts
- {\dodoubleempty\placelistofsorts}
+ {\dodoubleempty\doplacelistofsorts}
-\unexpanded\def\placelistofsorts[#1][#2]% NOG EEN RUWE VERSIE MAKEN ZONDER WITRUIMTE ETC ETC
+\def\doplacelistofsorts[#1][#2]% NOG EEN RUWE VERSIE MAKEN ZONDER WITRUIMTE ETC ETC
{\begingroup
\def\currentsorting{#1}%
\getparameters[\??so#1][#2]%
@@ -358,7 +358,7 @@
\stoppacked
\endgroup}
-\def\completelistofsorts
+\unexpanded\def\completelistofsorts
{\dodoubleempty\docompletelistofsorts}
\def\docompletelistofsorts[#1][#2]%
diff --git a/tex/context/base/supp-fil.lua b/tex/context/base/supp-fil.lua
index 810e45d9f..91fa446b9 100644
--- a/tex/context/base/supp-fil.lua
+++ b/tex/context/base/supp-fil.lua
@@ -45,7 +45,7 @@ end
local testcase = commands.testcase
function commands.splitfilename(fullname)
- local path, name, base, suffix, kind = '', fullname, fullname, '', 0
+ local path, name, base, suffix = '', fullname, fullname, ''
local p, n = match(fullname,"^(.+)/(.-)$")
if p and n then
path, name, base = p, n, n
diff --git a/tex/context/base/symb-ini.lua b/tex/context/base/symb-ini.lua
index eb4315c62..1bc8ee2aa 100644
--- a/tex/context/base/symb-ini.lua
+++ b/tex/context/base/symb-ini.lua
@@ -6,6 +6,7 @@ if not modules then modules = { } end modules ['symb-ini'] = {
license = "see context related readme files"
}
+
local variables = interfaces.variables
fonts.symbols = fonts.symbols or { }
@@ -15,19 +16,22 @@ local report_symbols = logs.reporter ("fonts","symbols")
local status_symbols = logs.messenger("fonts","symbols")
local patterns = { "symb-imp-%s.mkiv", "symb-imp-%s.tex", "symb-%s.mkiv", "symb-%s.tex" }
+local listitem = utilities.parsers.listitem
function symbols.uselibrary(name)
if name ~= variables.reset then
- commands.uselibrary(name,patterns,function(name,foundname)
- -- context.startnointerference()
- context.startreadingfile()
- context.input(foundname)
- status_symbols("loaded: library '%s'",name)
- context.stopreadingfile()
- -- context.stopnointerference()
- end, function(name)
- report_symbols("unknown: library '%s'",name)
- end)
+ for name in listitem(name) do
+ commands.uselibrary(name,patterns,function(name,foundname)
+ -- context.startnointerference()
+ context.startreadingfile()
+ context.input(foundname)
+ status_symbols("loaded: library '%s'",name)
+ context.stopreadingfile()
+ -- context.stopnointerference()
+ end, function(name)
+ report_symbols("unknown: library '%s'",name)
+ end)
+ end
end
end
diff --git a/tex/context/base/syst-aux.mkiv b/tex/context/base/syst-aux.mkiv
index f9c339dff..0fd453e2d 100644
--- a/tex/context/base/syst-aux.mkiv
+++ b/tex/context/base/syst-aux.mkiv
@@ -195,16 +195,22 @@
%D The next set of macros just do nothing, except that they
%D get rid of a number of arguments.
-\long\def\gobbleoneargument #1{}
-\long\def\gobbletwoarguments #1#2{}
-\long\def\gobblethreearguments #1#2#3{}
-\long\def\gobblefourarguments #1#2#3#4{}
-\long\def\gobblefivearguments #1#2#3#4#5{}
-\long\def\gobblesixarguments #1#2#3#4#5#6{}
-\long\def\gobblesevenarguments #1#2#3#4#5#6#7{}
-\long\def\gobbleeightarguments #1#2#3#4#5#6#7#8{}
-\long\def\gobbleninearguments #1#2#3#4#5#6#7#8#9{}
-\long\def\gobbletenarguments #1{\gobbleninearguments}
+\long\def\gobbleoneargument #1{}
+\long\def\gobbletwoarguments #1#2{}
+\long\def\gobblethreearguments#1#2#3{}
+\long\def\gobblefourarguments #1#2#3#4{}
+\long\def\gobblefivearguments #1#2#3#4#5{}
+\long\def\gobblesixarguments #1#2#3#4#5#6{}
+\long\def\gobblesevenarguments#1#2#3#4#5#6#7{}
+\long\def\gobbleeightarguments#1#2#3#4#5#6#7#8{}
+\long\def\gobbleninearguments #1#2#3#4#5#6#7#8#9{}
+\long\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 \macros
%D {doifnextcharelse}
@@ -1130,7 +1136,7 @@
\fi
\fi}
-\def\processfirstactioninset[#1]%
+\unexpanded\def\processfirstactioninset[#1]%
{\expandedaction\!!stringa{#1}%
\ifx\!!stringa\empty
\expandafter\processaction
@@ -1139,7 +1145,7 @@
\fi
[#1]}
-\def\processfirstactionsinsetindeed[#1]#2[#3]%
+\unexpanded\def\processfirstactionsinsetindeed[#1]#2[#3]%
{\def\p!doprocessaction##1%
{\def\p!dodoprocessaction####1%
{\p!compareprocessactionC[####1][##1]}%
@@ -1165,7 +1171,7 @@
\def\doprocessallactionsinset
{\csname\s!do\the\processlevel\endcsname}
-\def\processallactionsinset[#1]%
+\unexpanded\def\processallactionsinset[#1]%
{\expandedaction\!!stringa{#1}%
\ifx\!!stringa\empty
\expandafter\processaction
@@ -1174,7 +1180,7 @@
\fi
[#1]}
-\def\processallactionsinsetindeed[#1]#2[#3]%
+\unexpanded\def\processallactionsinsetindeed[#1]#2[#3]%
{\advance\processlevel \plusone
\expandafter\def\csname\s!do\the\processlevel\endcsname##1%
{\def\p!dodoprocessaction####1%
@@ -7282,7 +7288,14 @@
%D A variant for \type {\executeifdefined}:
-\def\expandcheckedcsname#1#2#3%
+% \def\expandcheckedcsname#1#2#3%
+% {\csname#1\ifcsname#1#2\endcsname#2\else#3\fi\endcsname}
+
+\def\expandcheckedcsname#1#2% #2 is often a \xxxparameter so let's expand it once
+ {\normalexpanded{\noexpand\doexpandcheckedcsname{#1}{#2}}}
+
+\def\doexpandcheckedcsname#1#2#3%
{\csname#1\ifcsname#1#2\endcsname#2\else#3\fi\endcsname}
+
\protect \endinput
diff --git a/tex/context/base/tabl-ntb.mkiv b/tex/context/base/tabl-ntb.mkiv
index dfdf46510..96b1aabed 100644
--- a/tex/context/base/tabl-ntb.mkiv
+++ b/tex/context/base/tabl-ntb.mkiv
@@ -547,6 +547,7 @@
\lettbltag\maximumrow\currentcol\tblcell
\settblcol\maximumrow\currentcol{\number\tblnx}%
\settblrow\maximumrow\currentcol{\number\tblny}%
+ % the action key will change!
\settblref\maximumrow\currentcol{\ifcsname\@@tbl\c!action\endcsname\csname\@@tbl\c!action\endcsname\fi}%
% save text
\edef\celltag{{\number\maximumrow}{\number\currentcol}}%
diff --git a/tex/context/base/trac-tex.lua b/tex/context/base/trac-tex.lua
index ab9e73e6e..dcfbf965d 100644
--- a/tex/context/base/trac-tex.lua
+++ b/tex/context/base/trac-tex.lua
@@ -8,6 +8,8 @@ if not modules then modules = { } end modules ['trac-hsh'] = {
-- moved from trac-deb.lua
+local format = string.format
+
local texhashtokens = tex.hashtokens
local trackers = trackers
@@ -23,12 +25,12 @@ function trackers.dumphashtofile(filename,delta)
for name, token in next, hash do
if not delta or not saved[name] then
-- token: cmd, chr, csid -- combination cmd,chr determines name
- local kind = command_name(token)
- local dk = list[kind]
+ local category = command_name(token)
+ local dk = list[category]
if not dk then
-- a bit funny names but this sorts better (easier to study)
dk = { names = { }, found = 0, code = token[1] }
- list[kind] = dk
+ list[category] = dk
end
dk.names[name] = { token[2], token[3] }
dk.found = dk.found + 1
@@ -49,3 +51,24 @@ end
directives.register("system.dumphash", function() dump_hash(false) end)
directives.register("system.dumpdelta", function() dump_hash(true ) end)
+
+local report_dump = logs.reporter("resolvers","dump")
+
+local function saveusedfilesintrees(format)
+ local data = {
+ jobname = environment.jobname or "?",
+ version = environment.version or "?",
+ files = table.sortedkeys(resolvers.instance.foundintrees)
+ }
+ local filename = file.replacesuffix(environment.jobname or "context-job",'jlg')
+ if format == "lua" then
+ io.savedata(filename,table.serialize(data,true))
+ else
+ io.savedata(filename,table.toxml(data,"job"))
+ end
+end
+
+directives.register("system.dumpfiles", function(v)
+ luatex.registerstopactions(function() saveusedfilesintrees(v) end)
+end)
+
diff --git a/tex/context/base/type-ini.mkiv b/tex/context/base/type-ini.mkiv
index f4b2b13d9..46b46976d 100644
--- a/tex/context/base/type-ini.mkiv
+++ b/tex/context/base/type-ini.mkiv
@@ -312,9 +312,9 @@
\def\loadmapfile{\dosingleempty\doloadmapfile}
\def\loadmapline{\dodoubleempty\doloadmapline}
-\def\doloadmapfile [#1]{\ctxlua{fonts.map.loadfile("#1")}}
-\def\doloadmapline [#1][#2]{\ctxlua{fonts.map.loadline("#1","#2")}}
-\def\forgetmapfiles {\ctxlua{fonts.map.reset()}}
+\def\doloadmapfile [#1]{\ctxlua{fonts.mappings.loadfile("#1")}}
+\def\doloadmapline [#1][#2]{\ctxlua{fonts.mappings.loadline("#1","#2")}}
+\def\forgetmapfiles {\ctxlua{fonts.mappings.reset()}}
% \appendtoks
% \pdfmapfile{}% somehow does not work at the lua end
diff --git a/tex/context/base/type-otf.mkiv b/tex/context/base/type-otf.mkiv
index 8d6cb1aad..fcfd134f9 100644
--- a/tex/context/base/type-otf.mkiv
+++ b/tex/context/base/type-otf.mkiv
@@ -1460,7 +1460,7 @@
\starttypescript [math] [asana] [name]
\loadfontgoodies[asana-math]
- \definefontsynonym [MathRoman] [AsanaMath] [\s!features=\s!math\mathsizesuffix]
+ \definefontsynonym [MathRoman] [AsanaMath] [\s!features=\s!math\mathsizesuffix,\s!goodies=asana-math]
\stoptypescript
\starttypescript[asana]
diff --git a/tex/context/base/typo-brk.lua b/tex/context/base/typo-brk.lua
index d26f62a07..fe0258bcc 100644
--- a/tex/context/base/typo-brk.lua
+++ b/tex/context/base/typo-brk.lua
@@ -78,13 +78,13 @@ function breakpoints.setreplacement(id,char,language,settings)
end
local left, right, middle = settings.left, settings.right, settings.middle
cmap[language or ""] = {
- kind = tonumber(settings.kind) or 1,
+ type = tonumber(settings.type) or 1,
nleft = tonumber(settings.nleft) or 1,
nright = tonumber(settings.nright) or 1,
left = left ~= "" and left or nil,
right = right ~= "" and right or nil,
middle = middle ~= "" and middle or nil,
- } -- was { kind or 1, before or 1, after or 1 }
+ } -- was { type or 1, before or 1, after or 1 }
end
local function insert_break(head,start,before,after)
@@ -188,7 +188,7 @@ local function process(namespace,attribute,head)
if map[next.char] then
break
elseif m == 1 then
- local method = methods[smap.kind]
+ local method = methods[smap.type]
if method then
head, start = method(head,start,smap)
done = true
diff --git a/tex/context/base/typo-brk.mkiv b/tex/context/base/typo-brk.mkiv
index 8be00fd8a..4c21093ec 100644
--- a/tex/context/base/typo-brk.mkiv
+++ b/tex/context/base/typo-brk.mkiv
@@ -50,7 +50,7 @@
\begingroup
\getparameters[\??bp][\c!type=1,\c!nleft=3,\c!nright=3,\s!language=,\c!left=,\c!right=,\c!middle=,#3]%
\ctxlua{typesetters.breakpoints.setreplacement(\csname\??bp:#1\endcsname, "#2", "\reallanguagetag\@@bplanguage", {
- kind = \@@bptype,
+ type = \@@bptype,
nleft = "\@@bpnleft",
nright = "\@@bpnright",
right = "\@@bpright",
diff --git a/tex/context/base/typo-cap.lua b/tex/context/base/typo-cap.lua
index a8e714a9b..b762589ce 100644
--- a/tex/context/base/typo-cap.lua
+++ b/tex/context/base/typo-cap.lua
@@ -36,8 +36,10 @@ local userskip_code = skipcodes.userskip
local tasks = nodes.tasks
-local fontdata = fonts.identifiers
-local fontchar = fonts.characters
+local fonthashes = fonts.hashes
+local fontdata = fonthashes.identifiers
+local fontchar = fonthashes.characters
+
local chardata = characters.data
typesetters = typesetters or { }
diff --git a/tex/context/base/typo-dig.lua b/tex/context/base/typo-dig.lua
index fbbad96f8..1e4a02fc6 100644
--- a/tex/context/base/typo-dig.lua
+++ b/tex/context/base/typo-dig.lua
@@ -37,11 +37,13 @@ local tasks = nodes.tasks
local new_glue = nodepool.glue
-local fontdata = fonts.identifiers
-local chardata = fonts.characters
-local quaddata = fonts.quads
+local fonthashes = fonts.hashes
+local fontdata = fonthashes.identifiers
+local chardata = fonthashes.characters
+local quaddata = fonthashes.quads
+
local charbase = characters.data
-local getdigitwidth = fonts.getdigitwidth
+local getdigitwidth = fonts.helpers.getdigitwidth
typesetters = typesetters or { }
local typesetters = typesetters
diff --git a/tex/context/base/typo-dir.lua b/tex/context/base/typo-dir.lua
index 49d58239d..54c2e6e98 100644
--- a/tex/context/base/typo-dir.lua
+++ b/tex/context/base/typo-dir.lua
@@ -51,8 +51,10 @@ local new_textdir = nodepool.textdir
local beginmath_code = mathcodes.beginmath
local endmath_code = mathcodes.endmath
-local fontdata = fonts.identifiers
-local fontchar = fonts.characters
+local fonthashes = fonts.hashes
+local fontdata = fonthashes.identifiers
+local chardata = fonthashes.characters
+
local chardata = characters.data
local chardirs = characters.directions -- maybe make a special mirror table
diff --git a/tex/context/base/typo-krn.lua b/tex/context/base/typo-krn.lua
index 597950c6a..a9428439c 100644
--- a/tex/context/base/typo-krn.lua
+++ b/tex/context/base/typo-krn.lua
@@ -46,9 +46,10 @@ local kerning_code = kerncodes.kerning
local userkern_code = kerncodes.userkern
local userskip_code = skipcodes.userskip
-local fontdata = fonts.identifiers
-local chardata = fonts.characters
-local quaddata = fonts.quads
+local fonthashes = fonts.hashes
+local fontdata = fonthashes.identifiers
+local chardata = fonthashes.characters
+local quaddata = fonthashes.quads
typesetters = typesetters or { }
local typesetters = typesetters
diff --git a/tex/context/base/typo-mar.lua b/tex/context/base/typo-mar.lua
index 47734b3ee..6bc985868 100644
--- a/tex/context/base/typo-mar.lua
+++ b/tex/context/base/typo-mar.lua
@@ -6,6 +6,13 @@ if not modules then modules = { } end modules ['typo-mar'] = {
license = "see context related readme files"
}
+-- todo:
+--
+-- * autoleft/right depending on available space (or distance to margin)
+-- * stack across paragraphs, but that is messy and one should reconsider
+-- using margin data then as also vertical spacing kicks in
+-- * floating margin data, with close-to-call anchoring
+
local format = string.format
local insert, remove = table.insert, table.remove
local setmetatable, next = setmetatable, next
@@ -372,7 +379,7 @@ local function inject(parent,head,candidate)
if line ~= 0 then
local delta = line * candidate.lineheight
shift = shift + delta
-offset = offset + delta
+ offset = offset + delta
end
box.shift = shift
box.width = 0
@@ -408,7 +415,8 @@ local function flushinline(parent,head,done)
end
end
elseif id == hlist_code or id == vlist_code then
- -- optional
+ -- optional (but sometimes needed)
+ current.list, done = flushinline(current,current.list,done)
end
current = current.next
end
@@ -471,6 +479,9 @@ local function handler(scope,head,group)
end
current = current.next
end
+ -- if done then
+ -- resetstacked()
+ -- end
return head, done
else
return head, false
diff --git a/tex/context/base/typo-mar.mkiv b/tex/context/base/typo-mar.mkiv
index 4d122204e..aba3ef95a 100644
--- a/tex/context/base/typo-mar.mkiv
+++ b/tex/context/base/typo-mar.mkiv
@@ -286,7 +286,7 @@
\definemargindata [inmargin] [\v!left] [\c!margin=\c!margin,\c!width=\leftmarginwidth, \c!align=\v!flushright]
\definemargindata [inother] [\v!right] [\c!margin=\c!margin,\c!width=\rightmarginwidth,\c!align=\v!flushleft]
-\definemargindata [margintext] [\v!left] % keep it a bit separated from inleft and inmargin
+\definemargindata [margintext] [\v!left] [\c!margin=\c!margin,\c!width=\leftmarginwidth, \c!align=\v!flushright]
\setupmarginframed [\v!left ] [\c!method=\v!first,\c!align=\v!flushright,\s!parent=\??mf] % we could autoparent when no define yet
\setupmarginframed [\v!right] [\c!method=\v!first,\c!align=\v!flushleft, \s!parent=\??mf]
@@ -328,9 +328,9 @@
% \def\dodefineinmargin[#name][#location][#align][#settings]% not completely compatible
% {\definemargindata[#name][\c!location=#location,\c!align=#align,#settings]%
% \definemarginframed[#name][#location][\c!align=#align,#settings]}
-%
-% \let\setupinmargin\setupmargindata
-%
+
+\let\setupinmargin\setupmargindata
+
% The following is too dangerous:
%
% \unexpanded\def\setupinmargin
diff --git a/tex/context/base/typo-rep.lua b/tex/context/base/typo-rep.lua
index 78243229a..5ecff5586 100644
--- a/tex/context/base/typo-rep.lua
+++ b/tex/context/base/typo-rep.lua
@@ -25,7 +25,7 @@ local has_attribute = node.has_attribute
local chardata = characters.data
local collected = false
local attribute = attributes.private("stripping")
-local fontdata = fonts.identifiers
+local fontdata = fonts.hashes.identifiers
local tasks = nodes.tasks
local nodecodes = nodes.nodecodes
@@ -102,41 +102,3 @@ function nodes.stripping.enable()
tasks.enableaction("processors","nodes.handlers.stripping")
function nodes.stripping.enable() end
end
-
--- bonus:
-
-local initializers, methods = fonts.initializers, fonts.methods
-
-local function processformatters(head,font)
- local how = fontdata[font].shared.features.formatters -- slow
- if how == nil or how == "strip" then -- nil when forced
- local current, done = head, false
- while current do
- if current.id == glyph_code and current.subtype<256 and current.font == font then
- local char = current.char
- local what = glyphs[char]
- if what then
- head, current = process(what,head,current,char)
- done = true
- else -- handling of spacing etc has to be done elsewhere
- current = current.next
- end
- else
- current = current.next
- end
- end
- return head, done
- else
- return head, false
- end
-end
-
-function initializers.common.formatters(tfmdata,value)
- if initialize then initialize() end
-end
-
-initializers.base.otf.formatters = initializers.common.formatters
-initializers.node.otf.formatters = initializers.common.formatters
-
-methods.node.otf.formatters = processformatters
-methods.base.otf.formatters = processformatters
diff --git a/tex/context/base/typo-rep.mkiv b/tex/context/base/typo-rep.mkiv
index 89999c3c7..75902d7be 100644
--- a/tex/context/base/typo-rep.mkiv
+++ b/tex/context/base/typo-rep.mkiv
@@ -48,6 +48,6 @@
% maybe .. this might disappear, but is handy for testing
\def\forcecharacterstripping % secret command
- {\ctxlua{fonts.otf.features.register("formatters",true)}}
+ {\ctxlua{fonts.handlers.otf.features.register("formatters",true)}}
\protect \endinput
diff --git a/tex/context/base/typo-spa.lua b/tex/context/base/typo-spa.lua
index 310384aa8..e81a59bda 100644
--- a/tex/context/base/typo-spa.lua
+++ b/tex/context/base/typo-spa.lua
@@ -25,8 +25,9 @@ local insert_node_before = node.insert_before
local insert_node_after = node.insert_after
local remove_node = nodes.remove
-local fontdata = fonts.identifiers
-local quaddata = fonts.quads
+local fonthashes = fonts.hashes
+local fontdata = fonthashes.identifiers
+local quaddata = fonthashes.quads
local texattribute = tex.attribute
diff --git a/tex/context/base/util-mrg.lua b/tex/context/base/util-mrg.lua
index 3d8e79d93..acf04fead 100644
--- a/tex/context/base/util-mrg.lua
+++ b/tex/context/base/util-mrg.lua
@@ -12,13 +12,13 @@ local gsub, format = string.gsub, string.format
local concat = table.concat
local type, next = type, next
-utilities = utilities or {}
-utilities.merger = utilities.merger or { } -- maybe mergers
-utilities.report = logs and logs.reporter("system") or print
+utilities = utilities or {}
+utilities.merger = utilities.merger or { } -- maybe mergers
+utilities.report = logs and logs.reporter("system") or print
-local merger = utilities.merger
+local merger = utilities.merger
-merger.strip_comment = true
+merger.strip_comment = true
local m_begin_merge = "begin library merge"
local m_end_merge = "end library merge"
diff --git a/tex/context/base/util-prs.lua b/tex/context/base/util-prs.lua
index a369552dc..617dc0c78 100644
--- a/tex/context/base/util-prs.lua
+++ b/tex/context/base/util-prs.lua
@@ -178,7 +178,8 @@ end
function parsers.settings_to_set(str,t) -- tohash? -- todo: lpeg -- duplicate anyway
t = t or { }
- for s in gmatch(str,"%s*([^, ]+)") do -- space added
+-- for s in gmatch(str,"%s*([^, ]+)") do -- space added
+ for s in gmatch(str,"[^, ]+") do -- space added
t[s] = true
end
return t
@@ -220,3 +221,7 @@ function parsers.getparameters(self,class,parentclass,settings)
end
parsers.settings_to_hash(settings,sc)
end
+
+function parsers.listitem(str)
+ return gmatch(str,"[^, ]+")
+end
diff --git a/tex/context/base/util-tab.lua b/tex/context/base/util-tab.lua
index ea440e736..f8422c626 100644
--- a/tex/context/base/util-tab.lua
+++ b/tex/context/base/util-tab.lua
@@ -12,7 +12,7 @@ local tables = utilities.tables
local format, gmatch = string.format, string.gmatch
local concat, insert, remove = table.concat, table.insert, table.remove
-local setmetatable = setmetatable
+local setmetatable, tonumber, tostring = setmetatable, tonumber, tostring
function tables.definetable(target) -- defines undefined tables
local composed, t, n = nil, { }, 0
@@ -82,3 +82,25 @@ local _empty_table_ = { __index = function(t,k) return "" end }
function table.setemptymetatable(t)
setmetatable(t,_empty_table_)
end
+
+-- experimental
+
+local function toxml(t,d,result)
+ for k, v in table.sortedpairs(t) do
+ if type(v) == "table" then
+ result[#result+1] = format("%s<%s>",d,k)
+ toxml(v,d.." ",result)
+ result[#result+1] = format("%s</%s>",d,k)
+ elseif tonumber(k) then
+ result[#result+1] = format("%s<entry n='%s'>%s</entry>",d,k,v,k)
+ else
+ result[#result+1] = format("%s<%s>%s</%s>",d,k,tostring(v),k)
+ end
+ end
+end
+
+function table.toxml(t,name)
+ local result = { "<?xml version='1.0' standalone='yes' ?>" }
+ toxml( { [name or "root"] = t }, "", result)
+ return concat(result,"\n")
+end
diff --git a/tex/context/base/x-cals.lua b/tex/context/base/x-cals.lua
index 0ccbaab54..904dc39c9 100644
--- a/tex/context/base/x-cals.lua
+++ b/tex/context/base/x-cals.lua
@@ -13,9 +13,9 @@ local n_todimen, s_todimen = number.todimen, string.todimen
-- there is room for speedups as well as cleanup (using context functions)
-local cals = { }
-local moduledata = moduledata or { }
-moduledata.cals = cals
+local cals = { }
+moduledata.cals = cals
+lxml.mathml = cals -- for the moment
cals.ignore_widths = false
cals.shrink_widths = false
diff --git a/tex/context/base/x-css.lua b/tex/context/base/x-css.lua
index da21fd21b..1bf559d66 100644
--- a/tex/context/base/x-css.lua
+++ b/tex/context/base/x-css.lua
@@ -73,14 +73,16 @@ css.padding = padding
-- print(padding("10pt 20pt 30pt",pixel,hsize,exheight,emwidth))
-- print(padding("10pt 20pt 30pt 40pt",pixel,hsize,exheight,emwidth))
-local fontidentifiers = fonts.identifiers
local currentfont = font.current
-local texdimen = tex.dimen
+local texdimen = tex.dimen
+local hashes = fonts.hashes
+local quads = hashes.quads
+local xheights = hashes.xheights
local function padding(str)
- local fnt = fontidentifiers[currentfont()]
- local exheight = fnt.ex_height
- local emwidth = fnt.quad
+ local font = currentfont()
+ local exheight = xheights[font]
+ local emwidth = quads[font]
local hsize = texdimen.hsize/100
local pixel = emwidth/100
return padding(str,pixel,hsize,exheight,emwidth)
diff --git a/tex/context/base/x-mathml.lua b/tex/context/base/x-mathml.lua
index 654925f7a..434aefc55 100644
--- a/tex/context/base/x-mathml.lua
+++ b/tex/context/base/x-mathml.lua
@@ -17,8 +17,8 @@ local utfcharacters, utfvalues = string.utfcharacters, string.utfvalues
local lpegmatch = lpeg.match
local mathml = { }
-local moduledata = moduledata = { }
moduledata.mathml = mathml
+lxml.mathml = mathml -- for the moment
-- an alternative is to remap to private codes, where we can have
-- different properties .. to be done; this will move and become
diff --git a/tex/context/fonts/asana-math.lfg b/tex/context/fonts/asana-math.lfg
index 160b310f5..f845ca4de 100644
--- a/tex/context/fonts/asana-math.lfg
+++ b/tex/context/fonts/asana-math.lfg
@@ -1,7 +1,7 @@
-- This patch code is moved from font-pat.lua to this goodies
--- files as it does not belomg in the core code.
+-- files as it does not belong in the core code.
-local patches = fonts.otf.enhancers.patches
+local patches = fonts.handlers.otf.enhancers.patches
local function patch(data,filename,threshold)
local m = data.metadata.math
@@ -16,10 +16,37 @@ end
patches.register("after","check math parameters","asana",function(data,filename) patch(data,filename,1350) end)
+local function less(value,target,original) return 0.25 * value end
+
return {
- name = "lm-asana",
+ name = "asana-math",
version = "1.00",
comment = "Goodies that complement asana.",
author = "Hans Hagen",
copyright = "ConTeXt development team",
+ mathematics = {
+ parameters = {
+ -- StackBottomDisplayStyleShiftDown = 0,
+ -- StackBottomShiftDown = 0,
+ -- StackDisplayStyleGapMin = 0,
+ -- StackGapMin = 0,
+ -- StackTopDisplayStyleShiftUp = 0,
+ -- StackTopShiftUp = 0,
+ -- StretchStackBottomShiftDown = 0,
+ -- StretchStackGapAboveMin = 0,
+ -- StretchStackGapBelowMin = 0,
+ -- StretchStackTopShiftUp = 0,
+ StackBottomDisplayStyleShiftDown = less,
+ StackBottomShiftDown = less,
+ StackDisplayStyleGapMin = less,
+ StackGapMin = less,
+ StackTopDisplayStyleShiftUp = less,
+ StackTopShiftUp = less,
+ StretchStackBottomShiftDown = less,
+ StretchStackGapAboveMin = less,
+ StretchStackGapBelowMin = less,
+ StretchStackTopShiftUp = less,
+ }
+ }
}
+
diff --git a/tex/context/fonts/cambria-math.lfg b/tex/context/fonts/cambria-math.lfg
index 26972c9e4..3fd15d8a0 100644
--- a/tex/context/fonts/cambria-math.lfg
+++ b/tex/context/fonts/cambria-math.lfg
@@ -1,7 +1,7 @@
-- This patch code is moved from font-pat.lua to this goodies
--- files as it does not belomg in the core code.
+-- files as it does not belong in the core code.
-local patches = fonts.otf.enhancers.patches
+local patches = fonts.handlers.otf.enhancers.patches
local function patch(data,filename,threshold)
local m = data.metadata.math
@@ -18,7 +18,7 @@ patches.register("after","check math parameters","cambria", function(data,filena
patches.register("after","check math parameters","cambmath",function(data,filename) patch(data,filename,2800) end)
return {
- name = "lm-cambria",
+ name = "cambria-math",
version = "1.00",
comment = "Goodies that complement cambria.",
author = "Hans Hagen",
diff --git a/tex/context/fonts/lm-math.lfg b/tex/context/fonts/lm-math.lfg
index 042f3026e..43de0c51e 100644
--- a/tex/context/fonts/lm-math.lfg
+++ b/tex/context/fonts/lm-math.lfg
@@ -1,7 +1,7 @@
-- This patch code is moved from font-pat.lua to this goodies
-- files as it does not belomg in the core code.
-local patches = fonts.otf.enhancers.patches
+local patches = fonts.handlers.otf.enhancers.patches
local function patch(data,filename)
local uni_to_ind = data.map.map
@@ -268,6 +268,12 @@ return {
},
variables = {
joinrelfactor = 3, -- default anyway
- }
+ },
+ parameters = { -- test values
+ -- FactorA = 123.456,
+ -- FactorB = false,
+ -- FactorC = function(value,target,original) return 7.89 * target.factor end,
+ -- FactorD = "Hi There!",
+ },
}
}
diff --git a/tex/context/fonts/lucida-math.lfg b/tex/context/fonts/lucida-math.lfg
index 746d281e0..3341bea95 100644
--- a/tex/context/fonts/lucida-math.lfg
+++ b/tex/context/fonts/lucida-math.lfg
@@ -1,4 +1,4 @@
-local mathencodings = fonts.enc.math
+local mathencodings = fonts.encodings.math
mathencodings["lbr-ma"] = {
[0x025CB] = 0x00, -- circle
@@ -305,7 +305,7 @@ mathencodings["lbr-sy"] = table.merged(mathencodings["tex-sy"],mathencodings["lb
mathencodings["lbr-fraktur"] = { }
-fonts.vf.math.setletters(mathencodings, "lbr-fraktur", 0x1D504, 0x1D51E)
+fonts.handlers.vf.math.setletters(mathencodings, "lbr-fraktur", 0x1D504, 0x1D51E)
return {
name = "lucida-math",
diff --git a/tex/context/fonts/xits-math.lfg b/tex/context/fonts/xits-math.lfg
index 84e569e5f..4151e18a0 100644
--- a/tex/context/fonts/xits-math.lfg
+++ b/tex/context/fonts/xits-math.lfg
@@ -1,7 +1,13 @@
+-- \setupbodyfont[xits]
+--
+-- \starttext
+-- $ABC$ $\cal ABC$ $\mathalternate{cal}\cal ABC$
+-- \stoptext
+
return {
name = "xits-math",
version = "1.00",
- comment = "Goodies that complement xits.",
+ comment = "Goodies that complement xits (by Khaled Hosny).",
author = "Hans Hagen",
copyright = "ConTeXt development team",
mathematics = {
diff --git a/tex/context/interface/cont-cs.xml b/tex/context/interface/cont-cs.xml
index f71e12fdc..a7b246655 100644
--- a/tex/context/interface/cont-cs.xml
+++ b/tex/context/interface/cont-cs.xml
@@ -9634,7 +9634,7 @@
<cd:command name="comment" type="environment">
<cd:sequence>
- <cd:string value="komentar"/>
+ <cd:string value="comment"/>
</cd:sequence>
<cd:arguments>
<cd:keywords n="1" optional="yes">
@@ -9648,7 +9648,7 @@
<cd:command name="comment">
<cd:sequence>
- <cd:string value="komentar"/>
+ <cd:string value="comment"/>
</cd:sequence>
<cd:arguments>
<cd:keywords n="1" optional="yes">
diff --git a/tex/context/interface/cont-de.xml b/tex/context/interface/cont-de.xml
index 17b2480c4..61441dd9c 100644
--- a/tex/context/interface/cont-de.xml
+++ b/tex/context/interface/cont-de.xml
@@ -9634,7 +9634,7 @@
<cd:command name="comment" type="environment">
<cd:sequence>
- <cd:string value="kommentar"/>
+ <cd:string value="comment"/>
</cd:sequence>
<cd:arguments>
<cd:keywords n="1" optional="yes">
@@ -9648,7 +9648,7 @@
<cd:command name="comment">
<cd:sequence>
- <cd:string value="kommentar"/>
+ <cd:string value="comment"/>
</cd:sequence>
<cd:arguments>
<cd:keywords n="1" optional="yes">
diff --git a/tex/context/interface/cont-fr.xml b/tex/context/interface/cont-fr.xml
index da74f6013..615eda784 100644
--- a/tex/context/interface/cont-fr.xml
+++ b/tex/context/interface/cont-fr.xml
@@ -9634,7 +9634,7 @@
<cd:command name="comment" type="environment">
<cd:sequence>
- <cd:string value="commentaire"/>
+ <cd:string value="comment"/>
</cd:sequence>
<cd:arguments>
<cd:keywords n="1" optional="yes">
@@ -9648,7 +9648,7 @@
<cd:command name="comment">
<cd:sequence>
- <cd:string value="commentaire"/>
+ <cd:string value="comment"/>
</cd:sequence>
<cd:arguments>
<cd:keywords n="1" optional="yes">
diff --git a/tex/context/interface/cont-it.xml b/tex/context/interface/cont-it.xml
index 292915a06..5038f13ac 100644
--- a/tex/context/interface/cont-it.xml
+++ b/tex/context/interface/cont-it.xml
@@ -9634,7 +9634,7 @@
<cd:command name="comment" type="environment">
<cd:sequence>
- <cd:string value="commento"/>
+ <cd:string value="comment"/>
</cd:sequence>
<cd:arguments>
<cd:keywords n="1" optional="yes">
@@ -9648,7 +9648,7 @@
<cd:command name="comment">
<cd:sequence>
- <cd:string value="commento"/>
+ <cd:string value="comment"/>
</cd:sequence>
<cd:arguments>
<cd:keywords n="1" optional="yes">
diff --git a/tex/context/interface/cont-nl.xml b/tex/context/interface/cont-nl.xml
index ad038db16..2d53444fb 100644
--- a/tex/context/interface/cont-nl.xml
+++ b/tex/context/interface/cont-nl.xml
@@ -9634,7 +9634,7 @@
<cd:command name="comment" type="environment">
<cd:sequence>
- <cd:string value="commentaar"/>
+ <cd:string value="comment"/>
</cd:sequence>
<cd:arguments>
<cd:keywords n="1" optional="yes">
@@ -9648,7 +9648,7 @@
<cd:command name="comment">
<cd:sequence>
- <cd:string value="commentaar"/>
+ <cd:string value="comment"/>
</cd:sequence>
<cd:arguments>
<cd:keywords n="1" optional="yes">
diff --git a/tex/context/interface/cont-pe.xml b/tex/context/interface/cont-pe.xml
index 929f3c4b5..12a54339d 100644
--- a/tex/context/interface/cont-pe.xml
+++ b/tex/context/interface/cont-pe.xml
@@ -9634,7 +9634,7 @@
<cd:command name="comment" type="environment">
<cd:sequence>
- <cd:string value="توضیح"/>
+ <cd:string value="comment"/>
</cd:sequence>
<cd:arguments>
<cd:keywords n="1" optional="yes">
@@ -9648,7 +9648,7 @@
<cd:command name="comment">
<cd:sequence>
- <cd:string value="توضیح"/>
+ <cd:string value="comment"/>
</cd:sequence>
<cd:arguments>
<cd:keywords n="1" optional="yes">
diff --git a/tex/context/interface/cont-ro.xml b/tex/context/interface/cont-ro.xml
index 14abb248b..b7fa62d59 100644
--- a/tex/context/interface/cont-ro.xml
+++ b/tex/context/interface/cont-ro.xml
@@ -9634,7 +9634,7 @@
<cd:command name="comment" type="environment">
<cd:sequence>
- <cd:string value="comentariu"/>
+ <cd:string value="comment"/>
</cd:sequence>
<cd:arguments>
<cd:keywords n="1" optional="yes">
@@ -9648,7 +9648,7 @@
<cd:command name="comment">
<cd:sequence>
- <cd:string value="comentariu"/>
+ <cd:string value="comment"/>
</cd:sequence>
<cd:arguments>
<cd:keywords n="1" optional="yes">
diff --git a/tex/context/interface/keys-cs.xml b/tex/context/interface/keys-cs.xml
index b03a922fc..16d08fd12 100644
--- a/tex/context/interface/keys-cs.xml
+++ b/tex/context/interface/keys-cs.xml
@@ -78,6 +78,7 @@
<cd:variable name='april' value='duben'/>
<cd:variable name='atmargin' value='naokraji'/>
<cd:variable name='atpage' value='nastrance'/>
+ <cd:variable name='attachment' value='attachment'/>
<cd:variable name='august' value='srpen'/>
<cd:variable name='author' value='autor'/>
<cd:variable name='auto' value='auto'/>
@@ -531,6 +532,7 @@
<cd:constant name='after' value='po'/>
<cd:constant name='afterhead' value='pohlavicce'/>
<cd:constant name='afterkey' value='klavesapo'/>
+ <cd:constant name='aftersection' value='aftersection'/>
<cd:constant name='align' value='zarovnani'/>
<cd:constant name='aligncharacter' value='aligncharacter'/>
<cd:constant name='alignmentcharacter' value='alignmentcharacter'/>
@@ -569,6 +571,7 @@
<cd:constant name='balance' value='rovnovaha'/>
<cd:constant name='before' value='pred'/>
<cd:constant name='beforehead' value='predhlavickou'/>
+ <cd:constant name='beforesection' value='beforesection'/>
<cd:constant name='bet' value='bet'/>
<cd:constant name='big' value='velky'/>
<cd:constant name='blank' value='prazdny'/>
@@ -583,6 +586,7 @@
<cd:constant name='bottomoffset' value='offsetspodku'/>
<cd:constant name='bottomspace' value='bottomspace'/>
<cd:constant name='bottomstate' value='statusspodku'/>
+ <cd:constant name='buffer' value='buffer'/>
<cd:constant name='cache' value='cache'/>
<cd:constant name='calculate' value='pocitat'/>
<cd:constant name='category' value='category'/>
@@ -593,6 +597,7 @@
<cd:constant name='clipoffset' value='clipoffset'/>
<cd:constant name='closeaction' value='zavriakci'/>
<cd:constant name='closecommand' value='closecommand'/>
+ <cd:constant name='closepage' value='closepage'/>
<cd:constant name='closepageaction' value='akcezavrenistranky'/>
<cd:constant name='closesymbol' value='closesymbol'/>
<cd:constant name='color' value='barva'/>
@@ -817,6 +822,7 @@
<cd:constant name='oddmargin' value='lichyokraj'/>
<cd:constant name='offset' value='offset'/>
<cd:constant name='openaction' value='otevriakci'/>
+ <cd:constant name='openpage' value='openpage'/>
<cd:constant name='openpageaction' value='akceotevrenistranky'/>
<cd:constant name='option' value='volba'/>
<cd:constant name='order' value='order'/>
@@ -1012,6 +1018,7 @@
<cd:constant name='urlalternative' value='urlalternativa'/>
<cd:constant name='urlspace' value='prostorurl'/>
<cd:constant name='validate' value='validovat'/>
+ <cd:constant name='values' value='values'/>
<cd:constant name='vcommand' value='vprikaz'/>
<cd:constant name='veroffset' value='offsethlavicky'/>
<cd:constant name='vfil' value='vfil'/>
@@ -1110,7 +1117,6 @@
<cd:command name='colorbar' value='barevnalista'/>
<cd:command name='colorvalue' value='hodnotabarvy'/>
<cd:command name='column' value='sloupec'/>
- <cd:command name='comment' value='komentar'/>
<cd:command name='comparecolorgroup' value='porovnejskupinubarev'/>
<cd:command name='comparepalet' value='porovnejpaletu'/>
<cd:command name='completepagenumber' value='completepagenumber'/>
diff --git a/tex/context/interface/keys-de.xml b/tex/context/interface/keys-de.xml
index cbec2130b..b981d2091 100644
--- a/tex/context/interface/keys-de.xml
+++ b/tex/context/interface/keys-de.xml
@@ -78,6 +78,7 @@
<cd:variable name='april' value='April'/>
<cd:variable name='atmargin' value='amrand'/>
<cd:variable name='atpage' value='aufseite'/>
+ <cd:variable name='attachment' value='attachment'/>
<cd:variable name='august' value='August'/>
<cd:variable name='author' value='autor'/>
<cd:variable name='auto' value='auto'/>
@@ -531,6 +532,7 @@
<cd:constant name='after' value='nach'/>
<cd:constant name='afterhead' value='nachkopf'/>
<cd:constant name='afterkey' value='nachtaste'/>
+ <cd:constant name='aftersection' value='aftersection'/>
<cd:constant name='align' value='ausrichtung'/>
<cd:constant name='aligncharacter' value='aligncharacter'/>
<cd:constant name='alignmentcharacter' value='alignmentcharacter'/>
@@ -569,6 +571,7 @@
<cd:constant name='balance' value='ausgleichen'/>
<cd:constant name='before' value='vor'/>
<cd:constant name='beforehead' value='vorkopf'/>
+ <cd:constant name='beforesection' value='beforesection'/>
<cd:constant name='bet' value='bet'/>
<cd:constant name='big' value='gross'/>
<cd:constant name='blank' value='blanko'/>
@@ -583,6 +586,7 @@
<cd:constant name='bottomoffset' value='untenoffset'/>
<cd:constant name='bottomspace' value='bottomspace'/>
<cd:constant name='bottomstate' value='untenstatus'/>
+ <cd:constant name='buffer' value='buffer'/>
<cd:constant name='cache' value='cache'/>
<cd:constant name='calculate' value='berechnen'/>
<cd:constant name='category' value='category'/>
@@ -593,6 +597,7 @@
<cd:constant name='clipoffset' value='clipoffset'/>
<cd:constant name='closeaction' value='schliessenaktion'/>
<cd:constant name='closecommand' value='closecommand'/>
+ <cd:constant name='closepage' value='closepage'/>
<cd:constant name='closepageaction' value='closepageaction'/>
<cd:constant name='closesymbol' value='closesymbol'/>
<cd:constant name='color' value='farbe'/>
@@ -817,6 +822,7 @@
<cd:constant name='oddmargin' value='ungeraderand'/>
<cd:constant name='offset' value='offset'/>
<cd:constant name='openaction' value='oeffenaktion'/>
+ <cd:constant name='openpage' value='openpage'/>
<cd:constant name='openpageaction' value='openpageaction'/>
<cd:constant name='option' value='option'/>
<cd:constant name='order' value='order'/>
@@ -1012,6 +1018,7 @@
<cd:constant name='urlalternative' value='urlalternative'/>
<cd:constant name='urlspace' value='urlspatium'/>
<cd:constant name='validate' value='validieren'/>
+ <cd:constant name='values' value='values'/>
<cd:constant name='vcommand' value='vbefehl'/>
<cd:constant name='veroffset' value='kopfoffset'/>
<cd:constant name='vfil' value='vfil'/>
@@ -1110,7 +1117,6 @@
<cd:command name='colorbar' value='farbbalken'/>
<cd:command name='colorvalue' value='farbewert'/>
<cd:command name='column' value='spalte'/>
- <cd:command name='comment' value='kommentar'/>
<cd:command name='comparecolorgroup' value='vergleichefarbengruppe'/>
<cd:command name='comparepalet' value='vergleichepalette'/>
<cd:command name='completepagenumber' value='completepagenumber'/>
diff --git a/tex/context/interface/keys-en.xml b/tex/context/interface/keys-en.xml
index d5c3f4b8f..43f3048f1 100644
--- a/tex/context/interface/keys-en.xml
+++ b/tex/context/interface/keys-en.xml
@@ -78,6 +78,7 @@
<cd:variable name='april' value='April'/>
<cd:variable name='atmargin' value='atmargin'/>
<cd:variable name='atpage' value='atpage'/>
+ <cd:variable name='attachment' value='attachment'/>
<cd:variable name='august' value='August'/>
<cd:variable name='author' value='author'/>
<cd:variable name='auto' value='auto'/>
@@ -531,6 +532,7 @@
<cd:constant name='after' value='after'/>
<cd:constant name='afterhead' value='afterhead'/>
<cd:constant name='afterkey' value='afterkey'/>
+ <cd:constant name='aftersection' value='aftersection'/>
<cd:constant name='align' value='align'/>
<cd:constant name='aligncharacter' value='aligncharacter'/>
<cd:constant name='alignmentcharacter' value='alignmentcharacter'/>
@@ -569,6 +571,7 @@
<cd:constant name='balance' value='balance'/>
<cd:constant name='before' value='before'/>
<cd:constant name='beforehead' value='beforehead'/>
+ <cd:constant name='beforesection' value='beforesection'/>
<cd:constant name='bet' value='bet'/>
<cd:constant name='big' value='big'/>
<cd:constant name='blank' value='blank'/>
@@ -583,6 +586,7 @@
<cd:constant name='bottomoffset' value='bottomoffset'/>
<cd:constant name='bottomspace' value='bottomspace'/>
<cd:constant name='bottomstate' value='bottomstate'/>
+ <cd:constant name='buffer' value='buffer'/>
<cd:constant name='cache' value='cache'/>
<cd:constant name='calculate' value='calculate'/>
<cd:constant name='category' value='category'/>
@@ -593,6 +597,7 @@
<cd:constant name='clipoffset' value='clipoffset'/>
<cd:constant name='closeaction' value='closeaction'/>
<cd:constant name='closecommand' value='closecommand'/>
+ <cd:constant name='closepage' value='closepage'/>
<cd:constant name='closepageaction' value='closepageaction'/>
<cd:constant name='closesymbol' value='closesymbol'/>
<cd:constant name='color' value='color'/>
@@ -817,6 +822,7 @@
<cd:constant name='oddmargin' value='oddmargin'/>
<cd:constant name='offset' value='offset'/>
<cd:constant name='openaction' value='openaction'/>
+ <cd:constant name='openpage' value='openpage'/>
<cd:constant name='openpageaction' value='openpageaction'/>
<cd:constant name='option' value='option'/>
<cd:constant name='order' value='order'/>
@@ -1012,6 +1018,7 @@
<cd:constant name='urlalternative' value='urlalternative'/>
<cd:constant name='urlspace' value='urlspace'/>
<cd:constant name='validate' value='validate'/>
+ <cd:constant name='values' value='values'/>
<cd:constant name='vcommand' value='vcommand'/>
<cd:constant name='veroffset' value='veroffset'/>
<cd:constant name='vfil' value='vfil'/>
@@ -1110,7 +1117,6 @@
<cd:command name='colorbar' value='colorbar'/>
<cd:command name='colorvalue' value='colorvalue'/>
<cd:command name='column' value='column'/>
- <cd:command name='comment' value='comment'/>
<cd:command name='comparecolorgroup' value='comparecolorgroup'/>
<cd:command name='comparepalet' value='comparepalet'/>
<cd:command name='completepagenumber' value='completepagenumber'/>
diff --git a/tex/context/interface/keys-fr.xml b/tex/context/interface/keys-fr.xml
index 6b0c13b43..d41c6e396 100644
--- a/tex/context/interface/keys-fr.xml
+++ b/tex/context/interface/keys-fr.xml
@@ -78,6 +78,7 @@
<cd:variable name='april' value='avril'/>
<cd:variable name='atmargin' value='alamarge'/>
<cd:variable name='atpage' value='alapage'/>
+ <cd:variable name='attachment' value='attachment'/>
<cd:variable name='august' value='aout'/>
<cd:variable name='author' value='auteur'/>
<cd:variable name='auto' value='auto'/>
@@ -531,6 +532,7 @@
<cd:constant name='after' value='apres'/>
<cd:constant name='afterhead' value='aprestete'/>
<cd:constant name='afterkey' value='aprescle'/>
+ <cd:constant name='aftersection' value='aftersection'/>
<cd:constant name='align' value='alignement'/>
<cd:constant name='aligncharacter' value='caracterealigne'/>
<cd:constant name='alignmentcharacter' value='alignementcaractere'/>
@@ -569,6 +571,7 @@
<cd:constant name='balance' value='equilibre'/>
<cd:constant name='before' value='avant'/>
<cd:constant name='beforehead' value='avanttete'/>
+ <cd:constant name='beforesection' value='beforesection'/>
<cd:constant name='bet' value='bet'/>
<cd:constant name='big' value='grand'/>
<cd:constant name='blank' value='vide'/>
@@ -583,6 +586,7 @@
<cd:constant name='bottomoffset' value='decalageinf'/>
<cd:constant name='bottomspace' value='espaceinf'/>
<cd:constant name='bottomstate' value='etatinf'/>
+ <cd:constant name='buffer' value='buffer'/>
<cd:constant name='cache' value='cache'/>
<cd:constant name='calculate' value='calculer'/>
<cd:constant name='category' value='category'/>
@@ -593,6 +597,7 @@
<cd:constant name='clipoffset' value='clipoffset'/>
<cd:constant name='closeaction' value='actionfermeture'/>
<cd:constant name='closecommand' value='closecommand'/>
+ <cd:constant name='closepage' value='closepage'/>
<cd:constant name='closepageaction' value='actionfermeturepage'/>
<cd:constant name='closesymbol' value='closesymbol'/>
<cd:constant name='color' value='couleur'/>
@@ -817,6 +822,7 @@
<cd:constant name='oddmargin' value='margepaire'/>
<cd:constant name='offset' value='offset'/>
<cd:constant name='openaction' value='actionouverture'/>
+ <cd:constant name='openpage' value='openpage'/>
<cd:constant name='openpageaction' value='actionouverturepage'/>
<cd:constant name='option' value='option'/>
<cd:constant name='order' value='order'/>
@@ -1012,6 +1018,7 @@
<cd:constant name='urlalternative' value='alternativeurl'/>
<cd:constant name='urlspace' value='espaceurl'/>
<cd:constant name='validate' value='valider'/>
+ <cd:constant name='values' value='values'/>
<cd:constant name='vcommand' value='vcommande'/>
<cd:constant name='veroffset' value='veroffset'/>
<cd:constant name='vfil' value='vfil'/>
@@ -1110,7 +1117,6 @@
<cd:command name='colorbar' value='barrecouleur'/>
<cd:command name='colorvalue' value='valeurcouleur'/>
<cd:command name='column' value='colonne'/>
- <cd:command name='comment' value='commentaire'/>
<cd:command name='comparecolorgroup' value='comparegroupecouleur'/>
<cd:command name='comparepalet' value='comparepalette'/>
<cd:command name='completepagenumber' value='completenumeropage'/>
diff --git a/tex/context/interface/keys-it.xml b/tex/context/interface/keys-it.xml
index 77d96aa2d..cc2039fc8 100644
--- a/tex/context/interface/keys-it.xml
+++ b/tex/context/interface/keys-it.xml
@@ -78,6 +78,7 @@
<cd:variable name='april' value='aprile'/>
<cd:variable name='atmargin' value='almargine'/>
<cd:variable name='atpage' value='apagina'/>
+ <cd:variable name='attachment' value='attachment'/>
<cd:variable name='august' value='agosto'/>
<cd:variable name='author' value='autore'/>
<cd:variable name='auto' value='auto'/>
@@ -531,6 +532,7 @@
<cd:constant name='after' value='dopo'/>
<cd:constant name='afterhead' value='dopotesta'/>
<cd:constant name='afterkey' value='dopotasto'/>
+ <cd:constant name='aftersection' value='aftersection'/>
<cd:constant name='align' value='allinea'/>
<cd:constant name='aligncharacter' value='allineacarattere'/>
<cd:constant name='alignmentcharacter' value='carattereallineamento'/>
@@ -569,6 +571,7 @@
<cd:constant name='balance' value='bilanciamento'/>
<cd:constant name='before' value='prima'/>
<cd:constant name='beforehead' value='primaditesta'/>
+ <cd:constant name='beforesection' value='beforesection'/>
<cd:constant name='bet' value='bet'/>
<cd:constant name='big' value='grande'/>
<cd:constant name='blank' value='rigovuoto'/>
@@ -583,6 +586,7 @@
<cd:constant name='bottomoffset' value='offsetfondo'/>
<cd:constant name='bottomspace' value='spaziofondo'/>
<cd:constant name='bottomstate' value='statofondo'/>
+ <cd:constant name='buffer' value='buffer'/>
<cd:constant name='cache' value='cache'/>
<cd:constant name='calculate' value='calcola'/>
<cd:constant name='category' value='category'/>
@@ -593,6 +597,7 @@
<cd:constant name='clipoffset' value='clipoffset'/>
<cd:constant name='closeaction' value='azionechiudi'/>
<cd:constant name='closecommand' value='closecommand'/>
+ <cd:constant name='closepage' value='closepage'/>
<cd:constant name='closepageaction' value='azionechiudipagina'/>
<cd:constant name='closesymbol' value='closesymbol'/>
<cd:constant name='color' value='colore'/>
@@ -817,6 +822,7 @@
<cd:constant name='oddmargin' value='marginedispari'/>
<cd:constant name='offset' value='offset'/>
<cd:constant name='openaction' value='azioneapri'/>
+ <cd:constant name='openpage' value='openpage'/>
<cd:constant name='openpageaction' value='azioneapripagina'/>
<cd:constant name='option' value='opzione'/>
<cd:constant name='order' value='order'/>
@@ -1012,6 +1018,7 @@
<cd:constant name='urlalternative' value='alternativaurl'/>
<cd:constant name='urlspace' value='spaziourl'/>
<cd:constant name='validate' value='verifica'/>
+ <cd:constant name='values' value='values'/>
<cd:constant name='vcommand' value='vcomando'/>
<cd:constant name='veroffset' value='veroffset'/>
<cd:constant name='vfil' value='vfil'/>
@@ -1110,7 +1117,6 @@
<cd:command name='colorbar' value='barracolori'/>
<cd:command name='colorvalue' value='valorecolore'/>
<cd:command name='column' value='colonna'/>
- <cd:command name='comment' value='commento'/>
<cd:command name='comparecolorgroup' value='confrontagruppocolori'/>
<cd:command name='comparepalet' value='confrontatavolozza'/>
<cd:command name='completepagenumber' value='numeropaginacompleto'/>
diff --git a/tex/context/interface/keys-nl.xml b/tex/context/interface/keys-nl.xml
index 9d18c63f8..e1f05f8b1 100644
--- a/tex/context/interface/keys-nl.xml
+++ b/tex/context/interface/keys-nl.xml
@@ -78,6 +78,7 @@
<cd:variable name='april' value='april'/>
<cd:variable name='atmargin' value='opmarge'/>
<cd:variable name='atpage' value='oppagina'/>
+ <cd:variable name='attachment' value='aanhangsel'/>
<cd:variable name='august' value='augustus'/>
<cd:variable name='author' value='auteur'/>
<cd:variable name='auto' value='auto'/>
@@ -531,6 +532,7 @@
<cd:constant name='after' value='na'/>
<cd:constant name='afterhead' value='kopna'/>
<cd:constant name='afterkey' value='natoets'/>
+ <cd:constant name='aftersection' value='nasectie'/>
<cd:constant name='align' value='uitlijnen'/>
<cd:constant name='aligncharacter' value='karakteruitlijnen'/>
<cd:constant name='alignmentcharacter' value='uitlijnkarakter'/>
@@ -569,6 +571,7 @@
<cd:constant name='balance' value='balanceren'/>
<cd:constant name='before' value='voor'/>
<cd:constant name='beforehead' value='kopvoor'/>
+ <cd:constant name='beforesection' value='voorsectie'/>
<cd:constant name='bet' value='bet'/>
<cd:constant name='big' value='groot'/>
<cd:constant name='blank' value='blanko'/>
@@ -583,6 +586,7 @@
<cd:constant name='bottomoffset' value='onderoffset'/>
<cd:constant name='bottomspace' value='bodemwit'/>
<cd:constant name='bottomstate' value='onderstatus'/>
+ <cd:constant name='buffer' value='buffer'/>
<cd:constant name='cache' value='cache'/>
<cd:constant name='calculate' value='bereken'/>
<cd:constant name='category' value='categorie'/>
@@ -593,6 +597,7 @@
<cd:constant name='clipoffset' value='clipoffset'/>
<cd:constant name='closeaction' value='sluitactie'/>
<cd:constant name='closecommand' value='sluitcommando'/>
+ <cd:constant name='closepage' value='sluitpagina'/>
<cd:constant name='closepageaction' value='sluitpaginaactie'/>
<cd:constant name='closesymbol' value='sluitsymbool'/>
<cd:constant name='color' value='kleur'/>
@@ -817,6 +822,7 @@
<cd:constant name='oddmargin' value='onevenmarge'/>
<cd:constant name='offset' value='offset'/>
<cd:constant name='openaction' value='openactie'/>
+ <cd:constant name='openpage' value='openpagina'/>
<cd:constant name='openpageaction' value='openpaginaactie'/>
<cd:constant name='option' value='optie'/>
<cd:constant name='order' value='order'/>
@@ -1012,6 +1018,7 @@
<cd:constant name='urlalternative' value='urlvariant'/>
<cd:constant name='urlspace' value='urlspatie'/>
<cd:constant name='validate' value='valideer'/>
+ <cd:constant name='values' value='waarden'/>
<cd:constant name='vcommand' value='vcommando'/>
<cd:constant name='veroffset' value='kopoffset'/>
<cd:constant name='vfil' value='vfil'/>
@@ -1110,7 +1117,6 @@
<cd:command name='colorbar' value='kleurenbalk'/>
<cd:command name='colorvalue' value='kleurwaarde'/>
<cd:command name='column' value='kolom'/>
- <cd:command name='comment' value='commentaar'/>
<cd:command name='comparecolorgroup' value='vergelijkkleurgroep'/>
<cd:command name='comparepalet' value='vergelijkpalet'/>
<cd:command name='completepagenumber' value='volledigepaginanummer'/>
diff --git a/tex/context/interface/keys-pe.xml b/tex/context/interface/keys-pe.xml
index bf81c052a..219a53059 100644
--- a/tex/context/interface/keys-pe.xml
+++ b/tex/context/interface/keys-pe.xml
@@ -78,6 +78,7 @@
<cd:variable name='april' value='آوریل'/>
<cd:variable name='atmargin' value='درحاشیه'/>
<cd:variable name='atpage' value='درصفحه'/>
+ <cd:variable name='attachment' value='attachment'/>
<cd:variable name='august' value='آگوست'/>
<cd:variable name='author' value='author'/>
<cd:variable name='auto' value='خودکار'/>
@@ -531,6 +532,7 @@
<cd:constant name='after' value='بعداز'/>
<cd:constant name='afterhead' value='بعدازسر'/>
<cd:constant name='afterkey' value='بعدازکلید'/>
+ <cd:constant name='aftersection' value='aftersection'/>
<cd:constant name='align' value='تنظیم'/>
<cd:constant name='aligncharacter' value='حرف‌تنظیم'/>
<cd:constant name='alignmentcharacter' value='حرف‌تنظیم‌کردن'/>
@@ -569,6 +571,7 @@
<cd:constant name='balance' value='تعادل'/>
<cd:constant name='before' value='قبل‌از'/>
<cd:constant name='beforehead' value='قبل‌ازسر'/>
+ <cd:constant name='beforesection' value='beforesection'/>
<cd:constant name='bet' value='bet'/>
<cd:constant name='big' value='بزرگ'/>
<cd:constant name='blank' value='خالی'/>
@@ -583,6 +586,7 @@
<cd:constant name='bottomoffset' value='آفست‌پایین'/>
<cd:constant name='bottomspace' value='فضای‌پایین'/>
<cd:constant name='bottomstate' value='وضعیت‌پایین'/>
+ <cd:constant name='buffer' value='buffer'/>
<cd:constant name='cache' value='میانگیر'/>
<cd:constant name='calculate' value='محاسبه'/>
<cd:constant name='category' value='category'/>
@@ -593,6 +597,7 @@
<cd:constant name='clipoffset' value='آفست‌کلیپ'/>
<cd:constant name='closeaction' value='بستن‌کنش'/>
<cd:constant name='closecommand' value='بستن‌فرمان'/>
+ <cd:constant name='closepage' value='closepage'/>
<cd:constant name='closepageaction' value='بستن‌عمل‌صفحه'/>
<cd:constant name='closesymbol' value='بستن‌نماد'/>
<cd:constant name='color' value='رنگ'/>
@@ -817,6 +822,7 @@
<cd:constant name='oddmargin' value='حاشیه‌فرد'/>
<cd:constant name='offset' value='آفست'/>
<cd:constant name='openaction' value='عمل‌باز'/>
+ <cd:constant name='openpage' value='openpage'/>
<cd:constant name='openpageaction' value='عمل‌صفحه‌باز'/>
<cd:constant name='option' value='گزینه'/>
<cd:constant name='order' value='order'/>
@@ -1012,6 +1018,7 @@
<cd:constant name='urlalternative' value='urlalternative'/>
<cd:constant name='urlspace' value='urlspace'/>
<cd:constant name='validate' value='تاییداعتبار'/>
+ <cd:constant name='values' value='values'/>
<cd:constant name='vcommand' value='vcommand'/>
<cd:constant name='veroffset' value='آفست‌عم'/>
<cd:constant name='vfil' value='vfil'/>
@@ -1110,7 +1117,6 @@
<cd:command name='colorbar' value='میله‌رنگ'/>
<cd:command name='colorvalue' value='مقداررنگ'/>
<cd:command name='column' value='ستون'/>
- <cd:command name='comment' value='توضیح'/>
<cd:command name='comparecolorgroup' value='مقایسه‌گروه‌رنگ'/>
<cd:command name='comparepalet' value='لوح‌مقایسه'/>
<cd:command name='completepagenumber' value='شماره‌صفحه‌کامل'/>
diff --git a/tex/context/interface/keys-ro.xml b/tex/context/interface/keys-ro.xml
index d44c195f1..47c3e6349 100644
--- a/tex/context/interface/keys-ro.xml
+++ b/tex/context/interface/keys-ro.xml
@@ -78,6 +78,7 @@
<cd:variable name='april' value='aprilie'/>
<cd:variable name='atmargin' value='lamargine'/>
<cd:variable name='atpage' value='lapagina'/>
+ <cd:variable name='attachment' value='attachment'/>
<cd:variable name='august' value='august'/>
<cd:variable name='author' value='autor'/>
<cd:variable name='auto' value='auto'/>
@@ -531,6 +532,7 @@
<cd:constant name='after' value='dupa'/>
<cd:constant name='afterhead' value='dupatitlu'/>
<cd:constant name='afterkey' value='dupatasta'/>
+ <cd:constant name='aftersection' value='aftersection'/>
<cd:constant name='align' value='aliniere'/>
<cd:constant name='aligncharacter' value='aliniazacaracter'/>
<cd:constant name='alignmentcharacter' value='alierecaracter'/>
@@ -569,6 +571,7 @@
<cd:constant name='balance' value='balanta'/>
<cd:constant name='before' value='inainte'/>
<cd:constant name='beforehead' value='inaintetitlu'/>
+ <cd:constant name='beforesection' value='beforesection'/>
<cd:constant name='bet' value='bet'/>
<cd:constant name='big' value='mare'/>
<cd:constant name='blank' value='blanc'/>
@@ -583,6 +586,7 @@
<cd:constant name='bottomoffset' value='offsetjos'/>
<cd:constant name='bottomspace' value='spatiujos'/>
<cd:constant name='bottomstate' value='starejos'/>
+ <cd:constant name='buffer' value='buffer'/>
<cd:constant name='cache' value='cache'/>
<cd:constant name='calculate' value='calculeaza'/>
<cd:constant name='category' value='category'/>
@@ -593,6 +597,7 @@
<cd:constant name='clipoffset' value='clipoffset'/>
<cd:constant name='closeaction' value='actiuneinchidere'/>
<cd:constant name='closecommand' value='closecommand'/>
+ <cd:constant name='closepage' value='closepage'/>
<cd:constant name='closepageaction' value='actiuneinchiderepagina'/>
<cd:constant name='closesymbol' value='closesymbol'/>
<cd:constant name='color' value='culoare'/>
@@ -817,6 +822,7 @@
<cd:constant name='oddmargin' value='margineimpara'/>
<cd:constant name='offset' value='offset'/>
<cd:constant name='openaction' value='actiunedeschidere'/>
+ <cd:constant name='openpage' value='openpage'/>
<cd:constant name='openpageaction' value='actiunedeschiderepagina'/>
<cd:constant name='option' value='optiune'/>
<cd:constant name='order' value='order'/>
@@ -1012,6 +1018,7 @@
<cd:constant name='urlalternative' value='urlalternativ'/>
<cd:constant name='urlspace' value='spatiuurl'/>
<cd:constant name='validate' value='verifica'/>
+ <cd:constant name='values' value='values'/>
<cd:constant name='vcommand' value='comandav'/>
<cd:constant name='veroffset' value='veroffset'/>
<cd:constant name='vfil' value='vfil'/>
@@ -1110,7 +1117,6 @@
<cd:command name='colorbar' value='baraculoare'/>
<cd:command name='colorvalue' value='valoareculoare'/>
<cd:command name='column' value='coloana'/>
- <cd:command name='comment' value='comentariu'/>
<cd:command name='comparecolorgroup' value='comparagrupculoare'/>
<cd:command name='comparepalet' value='comparapaleta'/>
<cd:command name='completepagenumber' value='completeazanumarpagina'/>
diff --git a/tex/context/base/luat-dum.lua b/tex/generic/context/luatex-basics-gen.lua
index e0b629248..df5e7e6c4 100644
--- a/tex/context/base/luat-dum.lua
+++ b/tex/generic/context/luatex-basics-gen.lua
@@ -1,4 +1,4 @@
-if not modules then modules = { } end modules ['luat-dum'] = {
+if not modules then modules = { } end modules ['luat-basics-gen'] = {
version = 1.100,
comment = "companion to luatex-*.tex",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
@@ -6,6 +6,11 @@ if not modules then modules = { } end modules ['luat-dum'] = {
license = "see context related readme files"
}
+if context then
+ texio.write_nl("fatal error: this module is not for context")
+ os.exit()
+end
+
local dummyfunction = function() end
local dummyreporter = function(c) return function(...) texio.write(c .. " : " .. string.format(...)) end end
@@ -15,34 +20,42 @@ statistics = {
stoptiming = dummyfunction,
elapsedtime = nil,
}
+
directives = {
register = dummyfunction,
enable = dummyfunction,
disable = dummyfunction,
}
+
trackers = {
register = dummyfunction,
enable = dummyfunction,
disable = dummyfunction,
}
+
experiments = {
register = dummyfunction,
enable = dummyfunction,
disable = dummyfunction,
}
+
storage = { -- probably no longer needed
register = dummyfunction,
shared = { },
}
+
logs = {
new = dummyreporter,
reporter = dummyreporter,
messenger = dummyreporter,
report = dummyfunction,
}
+
callbacks = {
register = function(n,f) return callback.register(n,f) end,
+
}
+
utilities = {
storage = {
allocate = function(t) return t or { } end,
@@ -69,21 +82,21 @@ local remapper = {
fea = "font feature files",
}
-function resolvers.findfile(name,kind)
+function resolvers.findfile(name,fileformat)
name = string.gsub(name,"\\","\/")
- kind = kind and string.lower(kind)
- local found = kpse.find_file(name,(kind and kind ~= "" and (remapper[kind] or kind)) or file.extname(name,"tex"))
+ fileformat = fileformat and string.lower(fileformat)
+ local found = kpse.find_file(name,(fileformat and fileformat ~= "" and (remapper[fileformat] or fileformat)) or file.extname(name,"tex"))
if not found or found == "" then
- found = kpse.find_file(name,"other text file")
+ found = kpse.find_file(name,"other text files")
end
return found
end
-function resolvers.findbinfile(name,kind)
- if not kind or kind == "" then
- kind = file.extname(name) -- string.match(name,"%.([^%.]-)$")
+function resolvers.findbinfile(name,fileformat)
+ if not fileformat or fileformat == "" then
+ fileformat = file.extname(name) -- string.match(name,"%.([^%.]-)$")
end
- return resolvers.findfile(name,(kind and remapper[kind]) or kind)
+ return resolvers.findfile(name,(fileformat and remapper[fileformat]) or fileformat)
end
function resolvers.resolve(s)
diff --git a/tex/generic/context/luatex-basics-nod.lua b/tex/generic/context/luatex-basics-nod.lua
new file mode 100644
index 000000000..151d98a8f
--- /dev/null
+++ b/tex/generic/context/luatex-basics-nod.lua
@@ -0,0 +1,95 @@
+if not modules then modules = { } end modules ['luatex-fonts-nod'] = {
+ version = 1.001,
+ comment = "companion to luatex-fonts.lua",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+if context then
+ texio.write_nl("fatal error: this module is not for context")
+ os.exit()
+end
+
+-- Don't depend on code here as it is only needed to complement the
+-- font handler code.
+
+-- Attributes:
+
+if tex.attribute[0] ~= 0 then
+
+ texio.write_nl("log","!")
+ texio.write_nl("log","! Attribute 0 is reserved for ConTeXt's font feature management and has to be")
+ texio.write_nl("log","! set to zero. Also, some attributes in the range 1-255 are used for special")
+ texio.write_nl("log","! purposes so setting them at the TeX end might break the font handler.")
+ texio.write_nl("log","!")
+
+ tex.attribute[0] = 0 -- else no features
+
+end
+
+attributes = { }
+attributes.unsetvalue = -0x7FFFFFFF
+
+local numbers, last = { }, 127
+
+function attributes.private(name)
+ local number = numbers[name]
+ if not number then
+ if last < 255 then
+ last = last + 1
+ end
+ number = last
+ numbers[name] = number
+ end
+ return number
+end
+
+-- Nodes:
+
+nodes = { }
+nodes.pool = { }
+nodes.handlers = { }
+
+local nodecodes = { } for k,v in next, node.types () do nodecodes[string.gsub(v,"_","")] = k end
+local whatcodes = { } for k,v in next, node.whatsits() do whatcodes[string.gsub(v,"_","")] = k end
+local glyphcodes = { [0] = "character", "glyph", "ligature", "ghost", "left", "right" }
+
+nodes.nodecodes = nodecodes
+nodes.whatcodes = whatcodes
+nodes.whatsitcodes = whatcodes
+nodes.glyphcodes = glyphcodes
+
+local free_node = node.free
+local remove_node = node.remove
+local new_node = node.new
+
+nodes.handlers.protectglyphs = node.protect_glyphs
+nodes.handlers.unprotectglyphs = node.unprotect_glyphs
+
+function nodes.remove(head, current, free_too)
+ local t = current
+ head, current = remove_node(head,current)
+ if t then
+ if free_too then
+ free_node(t)
+ t = nil
+ else
+ t.next, t.prev = nil, nil
+ end
+ end
+ return head, current, t
+end
+
+function nodes.delete(head,current)
+ return nodes.remove(head,current,true)
+end
+
+nodes.before = node.insert_before
+nodes.after = node.insert_after
+
+function nodes.pool.kern(k)
+ local n = new_node("kern",1)
+ n.kern = k
+ return n
+end
diff --git a/tex/generic/context/luatex-fonts-cbk.lua b/tex/generic/context/luatex-fonts-cbk.lua
new file mode 100644
index 000000000..9db94f65e
--- /dev/null
+++ b/tex/generic/context/luatex-fonts-cbk.lua
@@ -0,0 +1,68 @@
+if not modules then modules = { } end modules ['luatex-fonts-cbk'] = {
+ version = 1.001,
+ comment = "companion to luatex-*.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+if context then
+ texio.write_nl("fatal error: this module is not for context")
+ os.exit()
+end
+
+local fonts = fonts
+local nodes = nodes
+
+-- Fonts: (might move to node-gef.lua)
+
+local traverse_id = node.traverse_id
+local glyph_code = nodes.nodecodes.glyph
+
+function nodes.handlers.characters(head)
+ local fontdata = fonts.hashes.identifiers
+ if fontdata then
+ local usedfonts, done, prevfont = { }, false, nil
+ for n in traverse_id(glyph_code,head) do
+ local font = n.font
+ if font ~= prevfont then
+ prevfont = font
+ local used = usedfonts[font]
+ if not used then
+ local tfmdata = fontdata[font] --
+ if tfmdata then
+ local shared = tfmdata.shared -- we need to check shared, only when same features
+ if shared then
+ local processors = shared.processes
+ if processors and #processors > 0 then
+ usedfonts[font] = processors
+ done = true
+ end
+ end
+ end
+ end
+ end
+ end
+ if done then
+ for font, processors in next, usedfonts do
+ for i=1,#processors do
+ local h, d = processors[i](head,font,0)
+ head, done = h or head, done or d
+ end
+ end
+ end
+ return head, true
+ else
+ return head, false
+ end
+end
+
+function nodes.simple_font_handler(head)
+-- lang.hyphenate(head)
+ head = nodes.handlers.characters(head)
+ nodes.injections.handler(head)
+ nodes.handlers.protectglyphs(head)
+ head = node.ligaturing(head)
+ head = node.kerning(head)
+ return head
+end
diff --git a/tex/generic/context/luatex-fonts-def.lua b/tex/generic/context/luatex-fonts-def.lua
new file mode 100644
index 000000000..1d71bf5d5
--- /dev/null
+++ b/tex/generic/context/luatex-fonts-def.lua
@@ -0,0 +1,97 @@
+if not modules then modules = { } end modules ['luatex-font-def'] = {
+ version = 1.001,
+ comment = "companion to luatex-*.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+if context then
+ texio.write_nl("fatal error: this module is not for context")
+ os.exit()
+end
+
+local fonts = fonts
+
+-- A bit of tuning for definitions.
+
+fonts.constructors.namemode = "specification" -- somehow latex needs this (changed name!) => will change into an overload
+
+-- tricky: we sort of bypass the parser and directly feed all into
+-- the sub parser
+
+function fonts.definers.getspecification(str)
+ return "", str, "", ":", str
+end
+
+-- the generic name parser (different from context!)
+
+local list = { }
+
+local function issome () list.lookup = 'name' end -- xetex mode prefers name (not in context!)
+local function isfile () list.lookup = 'file' end
+local function isname () list.lookup = 'name' end
+local function thename(s) list.name = s end
+local function issub (v) list.sub = v end
+local function iscrap (s) list.crap = string.lower(s) end
+local function iskey (k,v) list[k] = v end
+local function istrue (s) list[s] = true end
+local function isfalse(s) list[s] = false end
+
+local P, S, R, C = lpeg.P, lpeg.S, lpeg.R, lpeg.C
+
+local spaces = P(" ")^0
+local namespec = (1-S("/:("))^0 -- was: (1-S("/: ("))^0
+local crapspec = spaces * P("/") * (((1-P(":"))^0)/iscrap) * spaces
+local filename_1 = P("file:")/isfile * (namespec/thename)
+local filename_2 = P("[") * P(true)/isname * (((1-P("]"))^0)/thename) * P("]")
+local fontname_1 = P("name:")/isname * (namespec/thename)
+local fontname_2 = P(true)/issome * (namespec/thename)
+local sometext = (R("az","AZ","09") + S("+-."))^1
+local truevalue = P("+") * spaces * (sometext/istrue)
+local falsevalue = P("-") * spaces * (sometext/isfalse)
+local keyvalue = (C(sometext) * spaces * P("=") * spaces * C(sometext))/iskey
+local somevalue = sometext/istrue
+local subvalue = P("(") * (C(P(1-S("()"))^1)/issub) * P(")") -- for Kim
+local option = spaces * (keyvalue + falsevalue + truevalue + somevalue) * spaces
+local options = P(":") * spaces * (P(";")^0 * option)^0
+
+local pattern = (filename_1 + filename_2 + fontname_1 + fontname_2) * subvalue^0 * crapspec^0 * options^0
+
+local function colonized(specification) -- xetex mode
+ list = { }
+ lpeg.match(pattern,specification.specification)
+ list.crap = nil -- style not supported, maybe some day
+ if list.name then
+ specification.name = list.name
+ list.name = nil
+ end
+ if list.lookup then
+ specification.lookup = list.lookup
+ list.lookup = nil
+ end
+ if list.sub then
+ specification.sub = list.sub
+ list.sub = nil
+ end
+ specification.features.normal = fonts.handlers.otf.features.normalize(list)
+ return specification
+end
+
+fonts.definers.registersplit(":",colonized,"cryptic")
+fonts.definers.registersplit("", colonized,"more cryptic") -- catches \font\text=[names]
+
+function definers.applypostprocessors(tfmdata)
+ local postprocessors = tfmdata.postprocessors
+ if postprocessors then
+ for i=1,#postprocessors do
+ local extrahash = postprocessors[i](tfmdata) -- after scaling etc
+ if type(extrahash) == "string" and extrahash ~= "" then
+ -- e.g. a reencoding needs this
+ extrahash = string.gsub(lower(extrahash),"[^a-z]","-")
+ tfmdata.properties.fullname = format("%s-%s",tfmdata.properties.fullname,extrahash)
+ end
+ end
+ end
+ return tfmdata
+end
diff --git a/tex/generic/context/luatex-fonts-demo-vf-1.lua b/tex/generic/context/luatex-fonts-demo-vf-1.lua
index 31ac4b87b..b9f2a2c76 100644
--- a/tex/generic/context/luatex-fonts-demo-vf-1.lua
+++ b/tex/generic/context/luatex-fonts-demo-vf-1.lua
@@ -1,7 +1,9 @@
+local identifiers = fonts.hashes.identifiers
+
return function(specification)
- local f1, id1 = fonts.tfm.readanddefine('lmroman10-regular', specification.size)
- local f2, id2 = fonts.tfm.readanddefine('lmsans10-regular', specification.size)
- local f3, id3 = fonts.tfm.readanddefine('lmtypewriter10-regular',specification.size)
+ local f1, id1 = fonts.constructors.readanddefine('lmroman10-regular', specification.size)
+ local f2, id2 = fonts.constructors.readanddefine('lmsans10-regular', specification.size)
+ local f3, id3 = fonts.constructors.readanddefine('lmtypewriter10-regular',specification.size)
if f1 and f2 and f3 then
f1.name = specification.name
f1.virtualized = true
@@ -17,9 +19,9 @@ return function(specification)
{ "special", "pdf:0 0 1 rg" },
}
local chars = {
- fonts.identifiers[id1].characters,
- fonts.identifiers[id2].characters,
- fonts.identifiers[id3].characters,
+ identifiers[id1].characters,
+ identifiers[id2].characters,
+ identifiers[id3].characters,
}
for u, v in next, f1.characters do
local n = math.floor(math.random(1,3)+0.5)
diff --git a/tex/generic/context/luatex-fonts-enc.lua b/tex/generic/context/luatex-fonts-enc.lua
new file mode 100644
index 000000000..ac736f2a6
--- /dev/null
+++ b/tex/generic/context/luatex-fonts-enc.lua
@@ -0,0 +1,28 @@
+if not modules then modules = { } end modules ['luatex-font-enc'] = {
+ version = 1.001,
+ comment = "companion to luatex-*.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+if context then
+ texio.write_nl("fatal error: this module is not for context")
+ os.exit()
+end
+
+local fonts = fonts
+fonts.encodings = { }
+fonts.encodings.agl = { }
+
+setmetatable(fonts.encodings.agl, { __index = function(t,k)
+ if k == "unicodes" then
+ texio.write(" <loading (extended) adobe glyph list>")
+ local unicodes = dofile(resolvers.findfile("font-agl.lua"))
+ fonts.encodings.agl = { unicodes = unicodes }
+ return unicodes
+ else
+ return nil
+ end
+end })
+
diff --git a/tex/generic/context/luatex-fonts-ext.lua b/tex/generic/context/luatex-fonts-ext.lua
new file mode 100644
index 000000000..951afcc7e
--- /dev/null
+++ b/tex/generic/context/luatex-fonts-ext.lua
@@ -0,0 +1,276 @@
+if not modules then modules = { } end modules ['luatex-fonts-ext'] = {
+ version = 1.001,
+ comment = "companion to luatex-*.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+if context then
+ texio.write_nl("fatal error: this module is not for context")
+ os.exit()
+end
+
+local fonts = fonts
+local otffeatures = fonts.constructors.newfeatures("otf")
+
+-- A few generic extensions.
+
+local function initializeitlc(tfmdata,value)
+ if value then
+ -- the magic 40 and it formula come from Dohyun Kim
+ local parameters = tfmdata.parameters
+ local italicangle = parameters.italicangle
+ if italicangle and italicangle ~= 0 then
+ local uwidth = (parameters.uwidth or 40)/2
+ for unicode, d in next, tfmdata.descriptions do
+ local it = d.boundingbox[3] - d.width + uwidth
+ if it ~= 0 then
+ d.italic = it
+ end
+ end
+ tfmdata.properties.italic_correction = true
+ end
+ end
+end
+
+otffeatures.register {
+ name = "itlc",
+ description = "italic correction",
+ initializers = {
+ base = initializeitlc,
+ node = initializeitlc,
+ }
+}
+
+-- slant and extend
+
+local function initializeslant(tfmdata,value)
+ value = tonumber(value)
+ if not value then
+ value = 0
+ elseif value > 1 then
+ value = 1
+ elseif value < -1 then
+ value = -1
+ end
+ tfmdata.parameters.slant_factor = value
+end
+
+otffeatures.register {
+ name = "slant",
+ description = "slant glyphs",
+ initializers = {
+ base = initializeslant,
+ node = initializeslant,
+ }
+}
+
+local function initializeextend(tfmdata,value)
+ value = tonumber(value)
+ if not value then
+ value = 0
+ elseif value > 10 then
+ value = 10
+ elseif value < -10 then
+ value = -10
+ end
+ tfmdata.parameters.extend_factor = value
+end
+
+otffeatures.register {
+ name = "extend",
+ description = "scale glyphs horizontally",
+ initializers = {
+ base = initializeextend,
+ node = initializeextend,
+ }
+}
+
+-- expansion and protrusion
+
+fonts.protrusions = fonts.protrusions or { }
+fonts.protrusions.setups = fonts.protrusions.setups or { }
+
+local setups = fonts.protrusions.setups
+
+local function initializeprotrusion(tfmdata,value)
+ if value then
+ local setup = setups[value]
+ if setup then
+ local factor, left, right = setup.factor or 1, setup.left or 1, setup.right or 1
+ local emwidth = tfmdata.parameters.quad
+ tfmdata.parameters.protrusion = {
+ auto = true,
+ }
+ for i, chr in next, tfmdata.characters do
+ local v, pl, pr = setup[i], nil, nil
+ if v then
+ pl, pr = v[1], v[2]
+ end
+ if pl and pl ~= 0 then chr.left_protruding = left *pl*factor end
+ if pr and pr ~= 0 then chr.right_protruding = right*pr*factor end
+ end
+ end
+ end
+end
+
+otffeatures.register {
+ name = "protrusion",
+ description = "shift characters into the left and or right margin",
+ initializers = {
+ base = initializeprotrusion,
+ node = initializeprotrusion,
+ }
+}
+
+fonts.expansions = fonts.expansions or { }
+fonts.expansions.setups = fonts.expansions.setups or { }
+
+local setups = fonts.expansions.setups
+
+local function initializeexpansion(tfmdata,value)
+ if value then
+ local setup = setups[value]
+ if setup then
+ local factor = setup.factor or 1
+ tfmdata.parameters.expansion = {
+ stretch = 10 * (setup.stretch or 0),
+ shrink = 10 * (setup.shrink or 0),
+ step = 10 * (setup.step or 0),
+ auto = true,
+ }
+ for i, chr in next, tfmdata.characters do
+ local v = setup[i]
+ if v and v ~= 0 then
+ chr.expansion_factor = v*factor
+ else -- can be option
+ chr.expansion_factor = factor
+ end
+ end
+ end
+ end
+end
+
+otffeatures.register {
+ name = "expansion",
+ description = "apply hz optimization",
+ initializers = {
+ base = initializeexpansion,
+ node = initializeexpansion,
+ }
+}
+
+-- left over
+
+function fonts.loggers.onetimemessage() end
+
+-- example vectors
+
+local byte = string.byte
+
+fonts.expansions.setups['default'] = {
+
+ stretch = 2, shrink = 2, step = .5, factor = 1,
+
+ [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,
+}
+
+fonts.protrusions.setups['default'] = {
+
+ factor = 1, left = 1, right = 1,
+
+ [0x002C] = { 0, 1 }, -- comma
+ [0x002E] = { 0, 1 }, -- period
+ [0x003A] = { 0, 1 }, -- colon
+ [0x003B] = { 0, 1 }, -- semicolon
+ [0x002D] = { 0, 1 }, -- hyphen
+ [0x2013] = { 0, 0.50 }, -- endash
+ [0x2014] = { 0, 0.33 }, -- emdash
+ [0x3001] = { 0, 1 }, -- ideographic comma 、
+ [0x3002] = { 0, 1 }, -- ideographic full stop 。
+ [0x060C] = { 0, 1 }, -- arabic comma ،
+ [0x061B] = { 0, 1 }, -- arabic semicolon ؛
+ [0x06D4] = { 0, 1 }, -- arabic full stop ۔
+
+}
+
+-- normalizer
+
+fonts.handlers.otf.features.normalize = function(t)
+ if t.rand then
+ t.rand = "random"
+ end
+ return t
+end
+
+-- bonus
+
+function fonts.helpers.nametoslot(name)
+ local t = type(name)
+ if t == "string" then
+ local tfmdata = fonts.hashes.identifiers[currentfont()]
+ local shared = tfmdata and tfmdata.shared
+ local fntdata = shared and shared.rawdata
+ return fntdata and fntdata.resources.unicodes[name]
+ elseif t == "number" then
+ return n
+ end
+end
+
+-- \font\test=file:somefont:reencode=mymessup
+--
+-- fonts.encodings.reencodings.mymessup = {
+-- [109] = 110, -- m
+-- [110] = 109, -- n
+-- }
+
+fonts.encodings = fonts.encodings or { }
+local reencodings = { }
+fonts.encodings.reencodings = reencodings
+
+local function specialreencode(tfmdata,value)
+ -- we forget about kerns as we assume symbols and we
+ -- could issue a message if ther are kerns but it's
+ -- a hack anyway so we odn't care too much here
+ local encoding = value and reencodings[value]
+ if encoding then
+ local temp = { }
+ local char = tfmdata.characters
+ for k, v in next, encoding do
+ temp[k] = char[v]
+ end
+ for k, v in next, temp do
+ char[k] = temp[k]
+ end
+ -- if we use the font otherwise luatex gets confused so
+ -- we return an additional hash component for fullname
+ return string.format("reencoded:%s",value)
+ end
+end
+
+local function reencode(tfmdata,value)
+ tfmdata.postprocessors = tfmdata.postprocessors or { }
+ table.insert(tfmdata.postprocessors,
+ function(tfmdata)
+ return specialreencode(tfmdata,value)
+ end
+ )
+end
+
+otffeatures.register {
+ name = "reencode",
+ description = "reencode characters",
+ manipulators = {
+ base = reencode,
+ node = reencode,
+ }
+}
diff --git a/tex/generic/context/luatex-fonts-lua.lua b/tex/generic/context/luatex-fonts-lua.lua
new file mode 100644
index 000000000..ec3fe38be
--- /dev/null
+++ b/tex/generic/context/luatex-fonts-lua.lua
@@ -0,0 +1,33 @@
+if not modules then modules = { } end modules ['luatex-fonts-lua'] = {
+ version = 1.001,
+ comment = "companion to luatex-*.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+if context then
+ texio.write_nl("fatal error: this module is not for context")
+ os.exit()
+end
+
+local fonts = fonts
+fonts.formats.lua = "lua"
+
+function fonts.readers.lua(specification)
+ local fullname = specification.filename or ""
+ if fullname == "" then
+ local forced = specification.forced or ""
+ if forced ~= "" then
+ fullname = specification.name .. "." .. forced
+ else
+ fullname = specification.name
+ end
+ end
+ local fullname = resolvers.findfile(fullname) or ""
+ if fullname ~= "" then
+ local loader = loadfile(fullname)
+ loader = loader and loader()
+ return loader and loader(specification)
+ end
+end
diff --git a/tex/generic/context/luatex-fonts-merged.lua b/tex/generic/context/luatex-fonts-merged.lua
index ff5ade637..d627f1d4c 100644
--- a/tex/generic/context/luatex-fonts-merged.lua
+++ b/tex/generic/context/luatex-fonts-merged.lua
@@ -1,6 +1,6 @@
-- merged file : luatex-fonts-merged.lua
-- parent file : luatex-fonts.lua
--- merge date : 02/25/11 22:03:53
+-- merge date : 03/25/11 18:03:32
do -- begin closure to overcome local limits and interference
@@ -667,6 +667,8 @@ function lpeg.is_lpeg(p)
return p and lpegtype(p) == "pattern"
end
+--~ Cf(Ct("") * (Cg(C(...) * "=" * Cs(...)))^0, rawset)
+
end -- closure
do -- begin closure to overcome local limits and interference
@@ -864,24 +866,24 @@ local function compare(a,b)
end
local function sortedkeys(tab)
- local srt, kind, s = { }, 0, 0 -- 0=unknown 1=string, 2=number 3=mixed
+ local srt, category, s = { }, 0, 0 -- 0=unknown 1=string, 2=number 3=mixed
for key,_ in next, tab do
s = s + 1
srt[s] = key
- if kind == 3 then
+ if category == 3 then
-- no further check
else
local tkey = type(key)
if tkey == "string" then
- kind = (kind == 2 and 3) or 1
+ category = (category == 2 and 3) or 1
elseif tkey == "number" then
- kind = (kind == 1 and 3) or 2
+ category = (category == 1 and 3) or 2
else
- kind = 3
+ category = 3
end
end
end
- if kind == 0 or kind == 3 then
+ if category == 0 or category == 3 then
sort(srt,compare)
else
sort(srt)
@@ -1047,6 +1049,13 @@ end
table.fastcopy = fastcopy
table.copy = copy
+function table.derive(parent)
+ local child = { }
+ if parent then
+ setmetatable(child,{ __index = parent })
+ end
+ return child
+end
function table.tohash(t,value)
local h = { }
@@ -2355,7 +2364,7 @@ end -- closure
do -- begin closure to overcome local limits and interference
-if not modules then modules = { } end modules ['luat-dum'] = {
+if not modules then modules = { } end modules ['luat-basics-gen'] = {
version = 1.100,
comment = "companion to luatex-*.tex",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
@@ -2363,6 +2372,11 @@ if not modules then modules = { } end modules ['luat-dum'] = {
license = "see context related readme files"
}
+if context then
+ texio.write_nl("fatal error: this module is not for context")
+ os.exit()
+end
+
local dummyfunction = function() end
local dummyreporter = function(c) return function(...) texio.write(c .. " : " .. string.format(...)) end end
@@ -2372,34 +2386,42 @@ statistics = {
stoptiming = dummyfunction,
elapsedtime = nil,
}
+
directives = {
register = dummyfunction,
enable = dummyfunction,
disable = dummyfunction,
}
+
trackers = {
register = dummyfunction,
enable = dummyfunction,
disable = dummyfunction,
}
+
experiments = {
register = dummyfunction,
enable = dummyfunction,
disable = dummyfunction,
}
+
storage = { -- probably no longer needed
register = dummyfunction,
shared = { },
}
+
logs = {
new = dummyreporter,
reporter = dummyreporter,
messenger = dummyreporter,
report = dummyfunction,
}
+
callbacks = {
register = function(n,f) return callback.register(n,f) end,
+
}
+
utilities = {
storage = {
allocate = function(t) return t or { } end,
@@ -2426,21 +2448,21 @@ local remapper = {
fea = "font feature files",
}
-function resolvers.findfile(name,kind)
+function resolvers.findfile(name,fileformat)
name = string.gsub(name,"\\","\/")
- kind = kind and string.lower(kind)
- local found = kpse.find_file(name,(kind and kind ~= "" and (remapper[kind] or kind)) or file.extname(name,"tex"))
+ fileformat = fileformat and string.lower(fileformat)
+ local found = kpse.find_file(name,(fileformat and fileformat ~= "" and (remapper[fileformat] or fileformat)) or file.extname(name,"tex"))
if not found or found == "" then
- found = kpse.find_file(name,"other text file")
+ found = kpse.find_file(name,"other text files")
end
return found
end
-function resolvers.findbinfile(name,kind)
- if not kind or kind == "" then
- kind = file.extname(name) -- string.match(name,"%.([^%.]-)$")
+function resolvers.findbinfile(name,fileformat)
+ if not fileformat or fileformat == "" then
+ fileformat = file.extname(name) -- string.match(name,"%.([^%.]-)$")
end
- return resolvers.findfile(name,(kind and remapper[kind]) or kind)
+ return resolvers.findfile(name,(fileformat and remapper[fileformat]) or fileformat)
end
function resolvers.resolve(s)
@@ -2707,46 +2729,23 @@ end -- closure
do -- begin closure to overcome local limits and interference
-if not modules then modules = { } end modules ['node-dum'] = {
+if not modules then modules = { } end modules ['luatex-fonts-nod'] = {
version = 1.001,
- comment = "companion to luatex-*.tex",
+ comment = "companion to luatex-fonts.lua",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
}
-nodes = nodes or { }
-fonts = fonts or { }
-attributes = attributes or { }
-
-nodes.pool = nodes.pool or { }
-nodes.handlers = nodes.handlers or { }
-
-local nodecodes = { } for k,v in next, node.types () do nodecodes[string.gsub(v,"_","")] = k end
-local whatcodes = { } for k,v in next, node.whatsits() do whatcodes[string.gsub(v,"_","")] = k end
-local glyphcodes = { [0] = "character", "glyph", "ligature", "ghost", "left", "right" }
-
-nodes.nodecodes = nodecodes
-nodes.whatcodes = whatcodes
-nodes.whatsitcodes = whatcodes
-nodes.glyphcodes = glyphcodes
-
-local traverse_id = node.traverse_id
-local free_node = node.free
-local remove_node = node.remove
-local new_node = node.new
+if context then
+ texio.write_nl("fatal error: this module is not for context")
+ os.exit()
+end
-local glyph_code = nodecodes.glyph
+-- Don't depend on code here as it is only needed to complement the
+-- font handler code.
-function nodes.simple_font_handler(head)
--- lang.hyphenate(head)
- head = nodes.handlers.characters(head)
- nodes.injections.handler(head)
- nodes.handlers.protectglyphs(head)
- head = node.ligaturing(head)
- head = node.kerning(head)
- return head
-end
+-- Attributes:
if tex.attribute[0] ~= 0 then
@@ -2760,78 +2759,7 @@ if tex.attribute[0] ~= 0 then
end
-nodes.handlers.protectglyphs = node.protect_glyphs
-nodes.handlers.unprotectglyphs = node.unprotect_glyphs
-
-function nodes.handlers.characters(head)
- local fontdata = fonts.identifiers
- if fontdata then
- local usedfonts, done, prevfont = { }, false, nil
- for n in traverse_id(glyph_code,head) do
- local font = n.font
- if font ~= prevfont then
- prevfont = font
- local used = usedfonts[font]
- if not used then
- local tfmdata = fontdata[font] --
- if tfmdata then
- local shared = tfmdata.shared -- we need to check shared, only when same features
- if shared then
- local processors = shared.processes
- if processors and #processors > 0 then
- usedfonts[font] = processors
- done = true
- end
- end
- end
- end
- end
- end
- if done then
- for font, processors in next, usedfonts do
- for i=1,#processors do
- local h, d = processors[i](head,font,0)
- head, done = h or head, done or d
- end
- end
- end
- return head, true
- else
- return head, false
- end
-end
-
--- helper
-
-function nodes.pool.kern(k)
- local n = new_node("kern",1)
- n.kern = k
- return n
-end
-
-function nodes.remove(head, current, free_too)
- local t = current
- head, current = remove_node(head,current)
- if t then
- if free_too then
- free_node(t)
- t = nil
- else
- t.next, t.prev = nil, nil
- end
- end
- return head, current, t
-end
-
-function nodes.delete(head,current)
- return nodes.remove(head,current,true)
-end
-
-nodes.before = node.insert_before
-nodes.after = node.insert_after
-
--- attributes
-
+attributes = { }
attributes.unsetvalue = -0x7FFFFFFF
local numbers, last = { }, 127
@@ -2848,458 +2776,53 @@ function attributes.private(name)
return number
end
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules = { } end modules ['node-inj'] = {
- version = 1.001,
- comment = "companion to node-ini.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
--- tricky ... fonts.identifiers is not yet defined .. to be solved (maybe general tex ini)
-
--- This is very experimental (this will change when we have luatex > .50 and
--- a few pending thingies are available. Also, Idris needs to make a few more
--- test fonts. Btw, future versions of luatex will have extended glyph properties
--- that can be of help.
-
-local next = next
-
-local trace_injections = false trackers.register("nodes.injections", function(v) trace_injections = v end)
-
-local report_injections = logs.reporter("nodes","injections")
-
-local attributes, nodes, node = attributes, nodes, node
-
-fonts = fonts or { }
-fonts.tfm = fonts.tfm or { }
-fonts.identifiers = fonts.identifiers or { }
-
-nodes.injections = nodes.injections or { }
-local injections = nodes.injections
-
-local fontdata = fonts.identifiers
-local nodecodes = nodes.nodecodes
-local glyph_code = nodecodes.glyph
-local nodepool = nodes.pool
-local newkern = nodepool.kern
-
-local traverse_id = node.traverse_id
-local unset_attribute = node.unset_attribute
-local has_attribute = node.has_attribute
-local set_attribute = node.set_attribute
-local insert_node_before = node.insert_before
-local insert_node_after = node.insert_after
-
-local markbase = attributes.private('markbase')
-local markmark = attributes.private('markmark')
-local markdone = attributes.private('markdone')
-local cursbase = attributes.private('cursbase')
-local curscurs = attributes.private('curscurs')
-local cursdone = attributes.private('cursdone')
-local kernpair = attributes.private('kernpair')
+-- Nodes:
-local cursives = { }
-local marks = { }
-local kerns = { }
+nodes = { }
+nodes.pool = { }
+nodes.handlers = { }
--- currently we do gpos/kern in a bit inofficial way but when we
--- have the extra fields in glyphnodes to manipulate ht/dp/wd
--- explicitly i will provide an alternative; also, we can share
--- tables
+local nodecodes = { } for k,v in next, node.types () do nodecodes[string.gsub(v,"_","")] = k end
+local whatcodes = { } for k,v in next, node.whatsits() do whatcodes[string.gsub(v,"_","")] = k end
+local glyphcodes = { [0] = "character", "glyph", "ligature", "ghost", "left", "right" }
--- for the moment we pass the r2l key ... volt/arabtype tests
-
-function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext)
- local dx, dy = factor*(exit[1]-entry[1]), factor*(exit[2]-entry[2])
- local ws, wn = tfmstart.width, tfmnext.width
- local bound = #cursives + 1
- set_attribute(start,cursbase,bound)
- set_attribute(nxt,curscurs,bound)
- cursives[bound] = { rlmode, dx, dy, ws, wn }
- return dx, dy, bound
-end
+nodes.nodecodes = nodecodes
+nodes.whatcodes = whatcodes
+nodes.whatsitcodes = whatcodes
+nodes.glyphcodes = glyphcodes
-function injections.setpair(current,factor,rlmode,r2lflag,spec,tfmchr)
- local x, y, w, h = factor*spec[1], factor*spec[2], factor*spec[3], factor*spec[4]
- -- dy = y - h
- if x ~= 0 or w ~= 0 or y ~= 0 or h ~= 0 then
- local bound = has_attribute(current,kernpair)
- if bound then
- local kb = kerns[bound]
- -- inefficient but singles have less, but weird anyway, needs checking
- kb[2], kb[3], kb[4], kb[5] = (kb[2] or 0) + x, (kb[3] or 0) + y, (kb[4] or 0)+ w, (kb[5] or 0) + h
- else
- bound = #kerns + 1
- set_attribute(current,kernpair,bound)
- kerns[bound] = { rlmode, x, y, w, h, r2lflag, tfmchr.width }
- end
- return x, y, w, h, bound
- end
- return x, y, w, h -- no bound
-end
+local free_node = node.free
+local remove_node = node.remove
+local new_node = node.new
-function injections.setkern(current,factor,rlmode,x,tfmchr)
- local dx = factor*x
- if dx ~= 0 then
- local bound = #kerns + 1
- set_attribute(current,kernpair,bound)
- kerns[bound] = { rlmode, dx }
- return dx, bound
- else
- return 0, 0
- end
-end
+nodes.handlers.protectglyphs = node.protect_glyphs
+nodes.handlers.unprotectglyphs = node.unprotect_glyphs
-function injections.setmark(start,base,factor,rlmode,ba,ma,index) --ba=baseanchor, ma=markanchor
- local dx, dy = factor*(ba[1]-ma[1]), factor*(ba[2]-ma[2])
- local bound = has_attribute(base,markbase)
- if bound then
- local mb = marks[bound]
- if mb then
- if not index then index = #mb + 1 end
- mb[index] = { dx, dy }
- set_attribute(start,markmark,bound)
- set_attribute(start,markdone,index)
- return dx, dy, bound
+function nodes.remove(head, current, free_too)
+ local t = current
+ head, current = remove_node(head,current)
+ if t then
+ if free_too then
+ free_node(t)
+ t = nil
else
- report_injections("possible problem, U+%04X is base mark without data (id: %s)",base.char,bound)
+ t.next, t.prev = nil, nil
end
- end
- index = index or 1
- bound = #marks + 1
- set_attribute(base,markbase,bound)
- set_attribute(start,markmark,bound)
- set_attribute(start,markdone,index)
- marks[bound] = { [index] = { dx, dy, rlmode } }
- return dx, dy, bound
-end
-
-local function dir(n)
- return (n and n<0 and "r-to-l") or (n and n>0 and "l-to-r") or "unset"
+ end
+ return head, current, t
end
-local function trace(head)
- report_injections("begin run")
- for n in traverse_id(glyph_code,head) do
- if n.subtype < 256 then
- local kp = has_attribute(n,kernpair)
- local mb = has_attribute(n,markbase)
- local mm = has_attribute(n,markmark)
- local md = has_attribute(n,markdone)
- local cb = has_attribute(n,cursbase)
- local cc = has_attribute(n,curscurs)
- report_injections("char U+%05X, font=%s",n.char,n.font)
- if kp then
- local k = kerns[kp]
- if k[3] then
- report_injections(" pairkern: dir=%s, x=%s, y=%s, w=%s, h=%s",dir(k[1]),k[2] or "?",k[3] or "?",k[4] or "?",k[5] or "?")
- else
- report_injections(" kern: dir=%s, dx=%s",dir(k[1]),k[2] or "?")
- end
- end
- if mb then
- report_injections(" markbase: bound=%s",mb)
- end
- if mm then
- local m = marks[mm]
- if mb then
- local m = m[mb]
- if m then
- report_injections(" markmark: bound=%s, index=%s, dx=%s, dy=%s",mm,md or "?",m[1] or "?",m[2] or "?")
- else
- report_injections(" markmark: bound=%s, missing index",mm)
- end
- else
- m = m[1]
- report_injections(" markmark: bound=%s, dx=%s, dy=%s",mm,m[1] or "?",m[2] or "?")
- end
- end
- if cb then
- report_injections(" cursbase: bound=%s",cb)
- end
- if cc then
- local c = cursives[cc]
- report_injections(" curscurs: bound=%s, dir=%s, dx=%s, dy=%s",cc,dir(c[1]),c[2] or "?",c[3] or "?")
- end
- end
- end
- report_injections("end run")
+function nodes.delete(head,current)
+ return nodes.remove(head,current,true)
end
--- todo: reuse tables (i.e. no collection), but will be extra fields anyway
--- todo: check for attribute
+nodes.before = node.insert_before
+nodes.after = node.insert_after
-function injections.handler(head,where,keep)
- local has_marks, has_cursives, has_kerns = next(marks), next(cursives), next(kerns)
- if has_marks or has_cursives then
---~ if has_marks or has_cursives or has_kerns then
- if trace_injections then
- trace(head)
- end
- -- in the future variant we will not copy items but refs to tables
- local done, ky, rl, valid, cx, wx, mk, nofvalid = false, { }, { }, { }, { }, { }, { }, 0
- if has_kerns then -- move outside loop
- local nf, tm = nil, nil
- for n in traverse_id(glyph_code,head) do
- if n.subtype < 256 then
- nofvalid = nofvalid + 1
- valid[nofvalid] = n
- if n.font ~= nf then
- nf = n.font
- tm = fontdata[nf].marks
- end
- mk[n] = tm[n.char]
- local k = has_attribute(n,kernpair)
- if k then
---~ unset_attribute(k,kernpair)
- local kk = kerns[k]
- if kk then
- local x, y, w, h = kk[2] or 0, kk[3] or 0, kk[4] or 0, kk[5] or 0
- local dy = y - h
- if dy ~= 0 then
- ky[n] = dy
- end
- if w ~= 0 or x ~= 0 then
- wx[n] = kk
- end
- rl[n] = kk[1] -- could move in test
- end
- end
- end
- end
- else
- local nf, tm = nil, nil
- for n in traverse_id(glyph_code,head) do
- if n.subtype < 256 then
- nofvalid = nofvalid + 1
- valid[nofvalid] = n
- if n.font ~= nf then
- nf = n.font
- tm = fontdata[nf].marks
- end
- mk[n] = tm[n.char]
- end
- end
- end
- if nofvalid > 0 then
- -- we can assume done == true because we have cursives and marks
- local cx = { }
- if has_kerns and next(ky) then
- for n, k in next, ky do
- n.yoffset = k
- end
- end
- -- todo: reuse t and use maxt
- if has_cursives then
- local p_cursbase, p = nil, nil
- -- since we need valid[n+1] we can also use a "while true do"
- local t, d, maxt = { }, { }, 0
- for i=1,nofvalid do -- valid == glyphs
- local n = valid[i]
- if not mk[n] then
- local n_cursbase = has_attribute(n,cursbase)
- if p_cursbase then
- local n_curscurs = has_attribute(n,curscurs)
- if p_cursbase == n_curscurs then
- local c = cursives[n_curscurs]
- if c then
- local rlmode, dx, dy, ws, wn = c[1], c[2], c[3], c[4], c[5]
- if rlmode >= 0 then
- dx = dx - ws
- else
- dx = dx + wn
- end
- if dx ~= 0 then
- cx[n] = dx
- rl[n] = rlmode
- end
- -- if rlmode and rlmode < 0 then
- dy = -dy
- -- end
- maxt = maxt + 1
- t[maxt] = p
- d[maxt] = dy
- else
- maxt = 0
- end
- end
- elseif maxt > 0 then
- local ny = n.yoffset
- for i=maxt,1,-1 do
- ny = ny + d[i]
- local ti = t[i]
- ti.yoffset = ti.yoffset + ny
- end
- maxt = 0
- end
- if not n_cursbase and maxt > 0 then
- local ny = n.yoffset
- for i=maxt,1,-1 do
- ny = ny + d[i]
- local ti = t[i]
- ti.yoffset = ny
- end
- maxt = 0
- end
- p_cursbase, p = n_cursbase, n
- end
- end
- if maxt > 0 then
- local ny = n.yoffset
- for i=maxt,1,-1 do
- ny = ny + d[i]
- local ti = t[i]
- ti.yoffset = ny
- end
- maxt = 0
- end
- if not keep then
- cursives = { }
- end
- end
- if has_marks then
- for i=1,nofvalid do
- local p = valid[i]
- local p_markbase = has_attribute(p,markbase)
- if p_markbase then
- local mrks = marks[p_markbase]
- for n in traverse_id(glyph_code,p.next) do
- local n_markmark = has_attribute(n,markmark)
- if p_markbase == n_markmark then
- local index = has_attribute(n,markdone) or 1
- local d = mrks[index]
- if d then
- local rlmode = d[3]
- if rlmode and rlmode > 0 then
- -- new per 2010-10-06
- local k = wx[p]
- if k then -- maybe (d[1] - p.width) and/or + k[2]
- n.xoffset = p.xoffset - (p.width - d[1]) - k[2]
- else
- n.xoffset = p.xoffset - (p.width - d[1])
- end
- else
- local k = wx[p]
- if k then
- n.xoffset = p.xoffset - d[1] - k[2]
- else
- n.xoffset = p.xoffset - d[1]
- end
- end
- if mk[p] then
- n.yoffset = p.yoffset + d[2]
- else
- n.yoffset = n.yoffset + p.yoffset + d[2]
- end
- end
- else
- break
- end
- end
- end
- end
- if not keep then
- marks = { }
- end
- end
- -- todo : combine
- if next(wx) then
- for n, k in next, wx do
- -- only w can be nil, can be sped up when w == nil
- local rl, x, w, r2l = k[1], k[2] or 0, k[4] or 0, k[6]
- local wx = w - x
- if r2l then
- if wx ~= 0 then
- insert_node_before(head,n,newkern(wx))
- end
- if x ~= 0 then
- insert_node_after (head,n,newkern(x))
- end
- else
- if x ~= 0 then
- insert_node_before(head,n,newkern(x))
- end
- if wx ~= 0 then
- insert_node_after(head,n,newkern(wx))
- end
- end
- end
- end
- if next(cx) then
- for n, k in next, cx do
- if k ~= 0 then
- local rln = rl[n]
- if rln and rln < 0 then
- insert_node_before(head,n,newkern(-k))
- else
- insert_node_before(head,n,newkern(k))
- end
- end
- end
- end
- if not keep then
- kerns = { }
- end
- return head, true
- elseif not keep then
- kerns, cursives, marks = { }, { }, { }
- end
- elseif has_kerns then
- if trace_injections then
- trace(head)
- end
- for n in traverse_id(glyph_code,head) do
- if n.subtype < 256 then
- local k = has_attribute(n,kernpair)
- if k then
- local kk = kerns[k]
- if kk then
- local rl, x, y, w = kk[1], kk[2] or 0, kk[3], kk[4]
- if y and y ~= 0 then
- n.yoffset = y -- todo: h ?
- end
- if w then
- -- copied from above
- local r2l = kk[6]
- local wx = w - x
- if r2l then
- if wx ~= 0 then
- insert_node_before(head,n,newkern(wx))
- end
- if x ~= 0 then
- insert_node_after (head,n,newkern(x))
- end
- else
- if x ~= 0 then
- insert_node_before(head,n,newkern(x))
- end
- if wx ~= 0 then
- insert_node_after(head,n,newkern(wx))
- end
- end
- else
- -- simple (e.g. kernclass kerns)
- if x ~= 0 then
- insert_node_before(head,n,newkern(x))
- end
- end
- end
- end
- end
- end
- if not keep then
- kerns = { }
- end
- return head, true
- else
- -- no tracing needed
- end
- return head, false
+function nodes.pool.kern(k)
+ local n = new_node("kern",1)
+ n.kern = k
+ return n
end
end -- closure
@@ -3314,16 +2837,14 @@ if not modules then modules = { } end modules ['font-ini'] = {
license = "see context related readme files"
}
--- The font code will be upgraded and reorganized so that we have a
--- leaner generic code base and can do more tuning for context.
+-- basemethods -> can also be in list
+-- presetcontext -> defaults
+-- hashfeatures -> ctx version
--[[ldx--
<p>Not much is happening here.</p>
--ldx]]--
-local utf = unicode.utf8
-local format, serialize = string.format, table.serialize
-local write_nl = texio.write_nl
local lower = string.lower
local allocate, mark = utilities.storage.allocate, utilities.storage.mark
@@ -3331,105 +2852,27 @@ local report_defining = logs.reporter("fonts","defining")
fontloader.totable = fontloader.to_table
--- vtf comes first
--- fix comes last
-
-fonts = fonts or { }
-
--- beware, some already defined
-
-fonts.identifiers = mark(fonts.identifiers or { }) -- fontdata
------.characters = mark(fonts.characters or { }) -- chardata
------.csnames = mark(fonts.csnames or { }) -- namedata
------.quads = mark(fonts.quads or { }) -- quaddata
-
---~ fonts.identifiers[0] = { -- nullfont
---~ characters = { },
---~ descriptions = { },
---~ name = "nullfont",
---~ }
-
-fonts.tfm = fonts.tfm or { }
-fonts.vf = fonts.vf or { }
-fonts.afm = fonts.afm or { }
-fonts.pfb = fonts.pfb or { }
-fonts.otf = fonts.otf or { }
-
-fonts.privateoffset = 0xF0000 -- 0x10FFFF
-fonts.verbose = false -- more verbose cache tables (will move to context namespace)
-
-fonts.methods = fonts.methods or {
- base = { tfm = { }, afm = { }, otf = { }, vtf = { }, fix = { } },
- node = { tfm = { }, afm = { }, otf = { }, vtf = { }, fix = { } },
-}
-
-fonts.initializers = fonts.initializers or {
- base = { tfm = { }, afm = { }, otf = { }, vtf = { }, fix = { } },
- node = { tfm = { }, afm = { }, otf = { }, vtf = { }, fix = { } }
-}
-
-fonts.triggers = fonts.triggers or {
- 'mode',
- 'language',
- 'script',
- 'strategy',
-}
-
-fonts.processors = fonts.processors or {
-}
-
-fonts.analyzers = fonts.analyzers or {
- useunicodemarks = false,
-}
-
-fonts.manipulators = fonts.manipulators or {
-}
-
-fonts.tracers = fonts.tracers or {
-}
-
-fonts.typefaces = fonts.typefaces or {
-}
-
-fonts.definers = fonts.definers or { }
-fonts.definers.specifiers = fonts.definers.specifiers or { }
-fonts.definers.specifiers.synonyms = fonts.definers.specifiers.synonyms or { }
-
--- tracing
-
-if not fonts.colors then
-
- fonts.colors = allocate {
- set = function() end,
- reset = function() end,
- }
-
-end
-
--- format identification
-
-fonts.formats = allocate()
+fonts = fonts or { } -- already defined in context
+local fonts = fonts
-function fonts.fontformat(filename,default)
- local extname = lower(file.extname(filename))
- local format = fonts.formats[extname]
- if format then
- return format
- else
- report_defining("unable to determine font format for '%s'",filename)
- return default
- end
-end
+-- some of these might move to where they are used first:
--- readers
+fonts.hashes = { identifiers = allocate() }
+fonts.analyzers = { } -- not needed here
+fonts.readers = { }
+fonts.tables = { }
+fonts.definers = { methods = { } }
+fonts.specifiers = fonts.specifiers or { } -- in format !
+fonts.loggers = { register = function() end }
+fonts.helpers = { }
-fonts.tfm.readers = fonts.tfm.readers or { }
+fonts.tracers = { } -- for the moment till we have move to moduledata
end -- closure
do -- begin closure to overcome local limits and interference
-if not modules then modules = { } end modules ['font-tfm'] = {
+if not modules then modules = { } end modules ['font-con'] = {
version = 1.001,
comment = "companion to font-ini.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
@@ -3437,10 +2880,13 @@ if not modules then modules = { } end modules ['font-tfm'] = {
license = "see context related readme files"
}
+
local utf = unicode.utf8
-local next, format, match, lower, gsub = next, string.format, string.match, string.lower, string.gsub
-local concat, sortedkeys, utfbyte, serialize = table.concat, table.sortedkeys, utf.byte, table.serialize
+local next, tostring, setmetatable, rawget = next, tostring, setmetatable, rawget
+local format, match, lower, gsub = string.format, string.match, string.lower, string.gsub
+local utfbyte = utf.byte
+local sort, insert, concat, sortedkeys, serialize, fastcopy = table.sort, table.insert, table.concat, table.sortedkeys, table.serialize, table.fastcopy
local allocate = utilities.storage.allocate
@@ -3449,77 +2895,41 @@ local trace_scaling = false trackers.register("fonts.scaling" , function(v) tr
local report_defining = logs.reporter("fonts","defining")
--- tfmdata has also fast access to indices and unicodes
--- to be checked: otf -> tfm -> tfmscaled
---
-- watch out: no negative depths and negative eights permitted in regular fonts
--[[ldx--
<p>Here we only implement a few helper functions.</p>
--ldx]]--
-local fonts = fonts
-local tfm = fonts.tfm
+local fonts = fonts
+local constructors = { }
+fonts.constructors = constructors
+local handlers = { }
+fonts.handlers = handlers
-fonts.loaded = allocate()
-fonts.dontembed = allocate()
-fonts.triggers = fonts.triggers or { } -- brrr
-fonts.initializers = fonts.initializers or { }
-fonts.initializers.common = fonts.initializers.common or { }
+local specifiers = fonts.specifiers
+local contextsetups = specifiers.contextsetups
+local contextnumbers = specifiers.contextnumbers
-local set_attribute = node.set_attribute
-local findbinfile = resolvers.findbinfile
+-- will be directives
-local readers = fonts.tfm.readers
-local fontdata = fonts.identifiers
-local nodecodes = nodes.nodecodes
+constructors.sharebasekerns = false -- true (.5 sec slower on mk but brings down mem from 410M to 310M, beware: then script/lang share too)
+constructors.dontembed = allocate()
+constructors.mathactions = { }
+constructors.autocleanup = true
+constructors.namemode = "fullpath" -- will be a function
-local disc_code = nodecodes.disc
-local glyph_code = nodecodes.glyph
+constructors.version = 1.01
+constructors.cache = containers.define("fonts", "constructors", constructors.version, false)
---[[ldx--
-<p>The next function encapsulates the standard <l n='tfm'/> loader as
-supplied by <l n='luatex'/>.</p>
---ldx]]--
+constructors.privateoffset = 0xF0000 -- 0x10FFFF
-tfm.resolvevirtualtoo = true -- false
-tfm.sharebasekerns = false -- true (.5 sec slower on mk but brings down mem from 410M to 310M, beware: then script/lang share too)
-tfm.mathactions = { }
-tfm.fontnamemode = "fullpath"
+-- This might become an interface;
-tfm.enhance = tfm.enhance or function() end
-
-local function read_from_tfm(specification)
- local fname, tfmdata = specification.filename or "", nil
- if fname ~= "" then
- if trace_defining then
- report_defining("loading tfm file %s at size %s",fname,specification.size)
- end
- tfmdata = font.read_tfm(fname,specification.size) -- not cached, fast enough
- if tfmdata then
- tfmdata.descriptions = tfmdata.descriptions or { }
- if tfm.resolvevirtualtoo then
- fonts.logger.save(tfmdata,file.extname(fname),specification) -- strange, why here
- fname = findbinfile(specification.name, 'ovf')
- if fname and fname ~= "" then
- local vfdata = font.read_vf(fname,specification.size) -- not cached, fast enough
- if vfdata then
- local chars = tfmdata.characters
- for k,v in next, vfdata.characters do
- chars[k].commands = v.commands
- end
- tfmdata.type = 'virtual'
- tfmdata.fonts = vfdata.fonts
- end
- end
- end
- tfm.enhance(tfmdata,specification)
- end
- elseif trace_defining then
- report_defining("loading tfm with name %s fails",specification.name)
- end
- return tfmdata
-end
+local designsizes = allocate()
+constructors.designsizes = designsizes
+local loadedfonts = allocate()
+constructors.loadedfonts = loadedfonts
--[[ldx--
<p>We need to normalize the scale factor (in scaled points). This has to
@@ -3532,22 +2942,23 @@ local factors = {
bp = 65781.8,
}
-function tfm.setfactor(f)
- tfm.factor = factors[f or 'pt'] or factors.pt
+function constructors.setfactor(f)
+ constructors.factor = factors[f or 'pt'] or factors.pt
end
-tfm.setfactor()
+constructors.setfactor()
-function tfm.scaled(scaledpoints, designsize) -- handles designsize in sp as well
+function constructors.scaled(scaledpoints, designsize) -- handles designsize in sp as well
if scaledpoints < 0 then
if designsize then
- if designsize > tfm.factor then -- or just 1000 / when? mp?
+ local factor = constructors.factor
+ if designsize > factor then -- or just 1000 / when? mp?
return (- scaledpoints/1000) * designsize -- sp's
else
- return (- scaledpoints/1000) * designsize * tfm.factor
+ return (- scaledpoints/1000) * designsize * factor
end
else
- return (- scaledpoints/1000) * 10 * tfm.factor
+ return (- scaledpoints/1000) * 10 * factor
end
else
return scaledpoints
@@ -3555,68 +2966,18 @@ function tfm.scaled(scaledpoints, designsize) -- handles designsize in sp as wel
end
--[[ldx--
-<p>Before a font is passed to <l n='tex'/> we scale it. Here we also need
-to scale virtual characters.</p>
---ldx]]--
-
---~ function tfm.getvirtualid(tfmdata)
---~ -- since we don't know the id yet, we use 0 as signal
---~ local tf = tfmdata.fonts
---~ if not tf then
---~ tfmdata.type = "virtual"
---~ tfmdata.fonts = { { id = 0 } }
---~ return 1
---~ else
---~ local ntf = #tf + 1
---~ tf[ntf] = { id = 0 }
---~ return ntf
---~ end
---~ end
-
-function tfm.getvirtualid(tfmdata)
- -- since we don't know the id yet, we use 0 as signal
- local tf = tfmdata.fonts
- if not tf then
- tf = { }
- tfmdata.type = "virtual"
- tfmdata.fonts = tf
- end
- local ntf = #tf + 1
- tf[ntf] = { id = 0 }
- return ntf
-end
-
-function tfm.checkvirtualid(tfmdata, id)
- if tfmdata and tfmdata.type == "virtual" then
- if not tfmdata.fonts or #tfmdata.fonts == 0 then
- tfmdata.type, tfmdata.fonts = "real", nil
- else
- local vfonts = tfmdata.fonts
- for f=1,#vfonts do
- local fnt = vfonts[f]
- if fnt.id and fnt.id == 0 then
- fnt.id = id
- end
- end
- end
- end
-end
-
---[[ldx--
<p>Beware, the boundingbox is passed as reference so we may not overwrite it
in the process; numbers are of course copies. Here 65536 equals 1pt. (Due to
excessive memory usage in CJK fonts, we no longer pass the boundingbox.)</p>
--ldx]]--
-fonts.trace_scaling = false
-
-- the following hack costs a bit of runtime but safes memory
--
-- basekerns are scaled and will be hashed by table id
-- sharedkerns are unscaled and are be hashed by concatenated indexes
---~ function tfm.check_base_kerns(tfmdata)
---~ if tfm.sharebasekerns then
+--~ function constructors.check_base_kerns(tfmdata)
+--~ if constructors.sharebasekerns then
--~ local sharedkerns = tfmdata.sharedkerns
--~ if sharedkerns then
--~ local basekerns = { }
@@ -3627,8 +2988,8 @@ fonts.trace_scaling = false
--~ return nil, nil
--~ end
---~ function tfm.prepare_base_kerns(tfmdata)
---~ if tfm.sharebasekerns and not tfmdata.sharedkerns then
+--~ function constructors.prepare_base_kerns(tfmdata)
+--~ if constructors.sharebasekerns and not tfmdata.sharedkerns then
--~ local sharedkerns = { }
--~ tfmdata.sharedkerns = sharedkerns
--~ for u, chr in next, tfmdata.characters do
@@ -3646,16 +3007,15 @@ fonts.trace_scaling = false
--~ end
--~ end
--- we can have cache scaled characters when we are in node mode and don't have
+-- we can cache scaled characters when we are in node mode and don't have
-- protruding and expansion: hash == fullname @ size @ protruding @ expansion
-- but in practice (except from mk) the otf hash will be enough already so it
--- makes no sense to mess up the code now
-
-local charactercache = { }
+-- makes no sense to mess up the code now
-- The scaler is only used for otf and afm and virtual fonts. If
-- a virtual font has italic correction make sure to set the
--- has_italic flag. Some more flags will be added in the future.
+-- italic_correction flag. Some more flags will be added in
+-- the future.
--[[ldx--
<p>The reason why the scaler was originally split, is that for a while we experimented
@@ -3664,156 +3024,302 @@ make this profitable and the <l n='lua'/> based variant was just faster. A days
wasted day but an experience richer.</p>
--ldx]]--
-tfm.autocleanup = true
-
-local lastfont = nil
-
-- 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 soem 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
--- we don't need the glyph data as we can use the description .. but we will
--- have to wait till we can access the internal tfm table efficiently in which
--- case characters will become a metatable afterwards
-
-function tfm.cleanuptable(tfmdata) -- we need a cleanup callback, now we miss the last one
- if tfm.autocleanup then -- ok, we can hook this into everyshipout or so ... todo
- if tfmdata.type == 'virtual' or tfmdata.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
- else
- -- for k, v in next, tfmdata.characters do
- -- if v.kerns then v.kerns = nil end
- -- end
+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
-function tfm.cleanup(tfmdata) -- we need a cleanup callback, now we miss the last one
-end
+-- experimental, sharing kerns (unscaled and scaled) saves memory
+-- local sharedkerns, basekerns = constructors.check_base_kerns(tfmdata)
+-- loop over descriptions (afm and otf have descriptions, tfm not)
+-- there is no need (yet) to assign a value to chr.tonunicode
-function tfm.calculatescale(tfmtable, scaledpoints)
+-- constructors.prepare_base_kerns(tfmdata) -- optimalization
+
+-- we have target.name=metricfile and target.fullname=RealName and target.filename=diskfilename
+-- when collapsing fonts, luatex looks as both target.name and target.fullname as ttc files
+-- can have multiple subfonts
+
+function constructors.calculatescale(tfmdata,scaledpoints)
+ local parameters = tfmdata.parameters
if scaledpoints < 0 then
- scaledpoints = (- scaledpoints/1000) * tfmtable.designsize -- already in sp
+ scaledpoints = (- scaledpoints/1000) * (tfmdata.designsize or parameters.designsize) -- already in sp
end
- local units = tfmtable.units or 1000
- local delta = scaledpoints/units -- brr, some open type fonts have 2048
- return scaledpoints, delta, units
+ return scaledpoints, scaledpoints / (parameters.units or 1000) -- delta
end
-function tfm.scale(tfmtable, scaledpoints, relativeid)
- -- tfm.prepare_base_kerns(tfmtable) -- optimalization
- local t = { } -- the new table
- local scaledpoints, delta, units = tfm.calculatescale(tfmtable, scaledpoints, relativeid)
- -- is just a trigger for the backend
- t.units_per_em = units or 1000
+function constructors.scale(tfmdata,specification)
+ local target = { } -- the new table
--
- local hdelta, vdelta = delta, delta
- -- unicoded unique descriptions shared cidinfo characters changed parameters indices
- for k,v in next, tfmtable do
- if type(v) == "table" then
- -- print(k)
- else
- t[k] = v
- end
+ if tonumber(specification) then
+ specification = { size = specification }
end
- local extend_factor = tfmtable.extend_factor or 0
+ --
+ local scaledpoints = specification.size
+ local relativeid = specification.relativeid
+ --
+ local properties = tfmdata.properties or { }
+ local goodies = tfmdata.goodies or { }
+ local resources = tfmdata.resources or { }
+ local descriptions = tfmdata.descriptions or { } -- bad news if empty
+ local characters = tfmdata.characters or { } -- bad news if empty
+ local changed = tfmdata.changed or { } -- for base mode
+ local shared = tfmdata.shared or { }
+ local parameters = tfmdata.parameters or { }
+ local mathparameters = tfmdata.mathparameters or { }
+ local MathConstants = tfmdata.mathconstants or { }
+ --
+ local targetcharacters = { }
+ local targetdescriptions = table.derive(descriptions)
+ local targetparameters = table.derive(parameters)
+ local targetmathparameters = table.derive(mathparameters)
+ local targetproperties = table.derive(properties)
+ local targetgoodies = table.derive(goodies)
+ target.characters = targetcharacters
+ target.descriptions = targetdescriptions
+ target.parameters = targetparameters
+ target.mathparameters = targetmathparameters
+ target.properties = targetproperties
+ target.goodies = targetgoodies
+ target.shared = shared
+ target.resources = resources
+ target.unscaled = tfmdata -- the original unscaled one (temp)
+ --
+ -- specification.mathsize : 1=text 2=script 3=scriptscript
+ -- specification.textsize : natural (text)size
+ -- parameters.mathsize : 1=text 2=script 3=scriptscript >1000 enforced size (feature value other than yes)
+ --
+ local mathsize = tonumber(specification.mathsize) or 0
+ local textsize = tonumber(specification.textsize) or scaledpoints
+ local forcedsize = tonumber(parameters.mathsize ) or 0
+ if (mathsize == 2 or forcedsize == 2) and parameters.scriptpercentage then
+ scaledpoints = parameters.scriptpercentage * textsize / 100
+ elseif (mathsize == 3 or forcedsize == 3) and parameters.scriptscriptpercentage then
+ scaledpoints = parameters.scriptscriptpercentage * textsize / 100
+ elseif forcedsize > 1000 then -- safeguard
+ scaledpoints = forcedsize
+ end
+ --
+ local tounicode = resources.tounicode
+ local defaultwidth = resources.defaultwidth or 0
+ local defaultheight = resources.defaultheight or 0
+ local defaultdepth = resources.defaultdepth or 0
+ local units = parameters.units or 1000
+ --
+ if target.fonts then
+ target.fonts = fastcopy(target.fonts) -- maybe we virtualize more afterwards
+ end
+ --
+ -- boundary keys are no longer needed as we now have a string 'right_boundary'
+ -- that can be used in relevant tables (kerns and ligatures) ... not that I ever
+ -- used them
+ --
+ -- boundarychar_label = 0, -- not needed
+ -- 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
+ --
+ local askedscaledpoints = scaledpoints
+ local scaledpoints, delta = constructors.calculatescale(tfmdata,scaledpoints) -- no shortcut, dan be redefined
+ --
+ local hdelta = delta
+ local vdelta = delta
+ --
+ target.designsize = parameters.designsize -- not really needed so it muight become obsolete
+ target.units_per_em = units -- just a trigger for the backend (does luatex use this? if not it will go)
+ --
+ local direction = properties.direction or tfmdata.direction or 0 -- pointless, as we don't use omf fonts at all
+ target.direction = direction
+ properties.direction = direction
+ --
+ target.size = scaledpoints
+ --
+ target.encodingbytes = properties.encodingbytes or 1
+ target.embedding = properties.embedding or "subset"
+ target.tounicode = 1
+ target.cidinfo = properties.cidinfo
+ target.format = properties.format
+ --
+ local fontname = properties.fontname or tfmdata.fontname -- for the moment we fall back on
+ local fullname = properties.fullname or tfmdata.fullname -- names in the tfmdata although
+ local filename = properties.filename or tfmdata.filename -- that is not the right place to
+ local psname = properties.psname or tfmdata.psname -- pass them
+ local name = properties.name or tfmdata.name
+ --
+ if not psname or psname == "" then
+ -- name used in pdf file as well as for selecting subfont in ttc/dfont
+ psname = fontname or (fullname and fonts.names.cleanname(fullname))
+ end
+ target.fontname = fontname
+ target.fullname = fullname
+ target.filename = filename
+ target.psname = psname
+ target.name = name
+ --
+ properties.fontname = fontname
+ properties.fullname = fullname
+ properties.filename = filename
+ properties.psname = psname
+ properties.name = name
+ -- expansion (hz)
+ local expansion = parameters.expansion
+ if expansion then
+ target.stretch = expansion.stretch
+ target.shrink = expansion.shrink
+ target.step = expansion.step
+ target.auto_expand = expansion.auto
+ end
+ -- protrusion
+ local protrusion = parameters.protrusion
+ if protrusion then
+ target.auto_protrude = protrusion.auto
+ end
+ -- widening
+ local extend_factor = parameters.extend_factor or 0
if extend_factor ~= 0 and extend_factor ~= 1 then
hdelta = hdelta * extend_factor
- t.extend = extend_factor * 1000
+ target.extend = extend_factor * 1000 -- extent ?
else
- t.extend = 1000
+ target.extend = 1000 -- extent ?
end
- local slant_factor = tfmtable.slant_factor or 0
+ -- slanting
+ local slant_factor = parameters.slant_factor or 0
if slant_factor ~= 0 then
- t.slant = slant_factor * 1000
+ target.slant = slant_factor * 1000
else
- t.slant = 0
- end
- -- status
- local isvirtual = tfmtable.type == "virtual" or tfmtable.virtualized
- local hasmath = (tfmtable.mathparameters ~= nil and next(tfmtable.mathparameters) ~= nil) or (tfmtable.MathConstants ~= nil and next(tfmtable.MathConstants) ~= nil)
- local nodemode = tfmtable.mode == "node"
- local hasquality = tfmtable.auto_expand or tfmtable.auto_protrude
- local hasitalic = tfmtable.has_italic
- local descriptions = tfmtable.descriptions or { }
+ target.slant = 0
+ end
--
- if hasmath then
- t.has_math = true -- this will move to elsewhere
+ targetparameters.hfactor = hdelta
+ targetparameters.vfactor = vdelta
+ targetparameters.factor = delta
+ targetparameters.size = scaledpoints
+ targetparameters.units = units
+ targetparameters.scaledpoints = askedscaledpoints
+ --
+ local isvirtual = properties.virtualized or tfmdata.type == "virtual"
+ local hasquality = target.auto_expand or target.auto_protrude
+ local hasitalic = properties.italic_correction
+ local stackmath = not properties.no_stackmath
+ local nonames = properties.noglyphnames
+ local nodemode = properties.mode == "node"
+ --
+ if changed and not next(changed) then
+ changed = false
end
--
- t.parameters = { }
- t.characters = { }
- t.MathConstants = { }
- -- fast access
- t.unscaled = tfmtable -- the original unscaled one (temp)
- t.unicodes = tfmtable.unicodes
- t.indices = tfmtable.indices
- t.marks = tfmtable.marks
+ target.type = isvirtual and "virtual" or "real"
+ -- more extensive test
+ local hasmath = (properties.math or next(mathparameters) or next(MathConstants)) and true
+ if hasmath then
+ properties.has_math = true
+ target.nomath = false
+ target.MathConstants = MathConstants
+ target.mathconstants = MathConstants
+ else
+ properties.has_math = false
+ target.nomath = true
+ target.mathparameters = nil -- nop
+ end
-- this will move to some subtable so that it is copied at once
- t.goodies = tfmtable.goodies
- t.colorscheme = tfmtable.colorscheme
- t.postprocessors = tfmtable.postprocessors
+ target.postprocessors = tfmdata.postprocessors
+ --
+ local targetslant = (parameters.slant or parameters[1] or 0)
+ local targetspace = (parameters.space or parameters[2] or 0)*hdelta
+ local targetspace_stretch = (parameters.space_stretch or parameters[3] or 0)*hdelta
+ local targetspace_shrink = (parameters.space_shrink or parameters[4] or 0)*hdelta
+ local targetx_height = (parameters.x_height or parameters[5] or 0)*vdelta
+ local targetquad = (parameters.quad or parameters[6] or 0)*hdelta
+ local targetextra_space = (parameters.extra_space or parameters[7] or 0)*hdelta
--
- -- t.embedding = tfmtable.embedding
- t.descriptions = descriptions
- if tfmtable.fonts then
- t.fonts = table.fastcopy(tfmtable.fonts) -- hm also at the end
- end
- local tp = t.parameters
- local mp = t.mathparameters
- local tfmp = tfmtable.parameters -- let's check for indexes
+ targetparameters.slant = targetslant
+ targetparameters.space = targetspace
+ targetparameters.space_stretch = targetspace_stretch
+ targetparameters.space_shrink = targetspace_shrink
+ targetparameters.x_height = targetx_height
+ targetparameters.quad = targetquad
+ targetparameters.extra_space = targetextra_space
--
- tp.slant = (tfmp.slant or tfmp[1] or 0)
- tp.space = (tfmp.space or tfmp[2] or 0)*hdelta
- tp.space_stretch = (tfmp.space_stretch or tfmp[3] or 0)*hdelta
- tp.space_shrink = (tfmp.space_shrink or tfmp[4] or 0)*hdelta
- tp.x_height = (tfmp.x_height or tfmp[5] or 0)*vdelta
- tp.quad = (tfmp.quad or tfmp[6] or 0)*hdelta
- tp.extra_space = (tfmp.extra_space or tfmp[7] or 0)*hdelta
- local protrusionfactor = (tp.quad ~= 0 and 1000/tp.quad) or 0
- local tc = t.characters
- local characters = tfmtable.characters
- local nameneeded = not tfmtable.shared.otfdata --hack
- local changed = tfmtable.changed or { } -- for base mode
- local ischanged = changed and next(changed)
- local indices = tfmtable.indices
- local luatex = tfmtable.luatex
- local tounicode = luatex and luatex.tounicode
- local defaultwidth = luatex and luatex.defaultwidth or 0
- local defaultheight = luatex and luatex.defaultheight or 0
- local defaultdepth = luatex and luatex.defaultdepth or 0
- -- experimental, sharing kerns (unscaled and scaled) saves memory
- -- local sharedkerns, basekerns = tfm.check_base_kerns(tfmtable)
- -- loop over descriptions (afm and otf have descriptions, tfm not)
- -- there is no need (yet) to assign a value to chr.tonunicode
- local scaledwidth = defaultwidth * hdelta
- local scaledheight = defaultheight * vdelta
- local scaleddepth = defaultdepth * vdelta
- local stackmath = tfmtable.ignore_stack_math ~= true
- local private = fonts.privateoffset
- local sharedkerns = { }
- for k,v in next, characters do
+ local ascender = parameters.ascender
+ if ascender then
+ targetparameters.ascender = delta * ascender
+ end
+ local descender = parameters.descender
+ if descender then
+ targetparameters.descender = delta * descender
+ end
+ --
+ if hasmath then
+ local ma = constructors.mathactions
+ local ta = type(ma)
+ if ta == "function" then -- context
+ ma(target,tfmdata)
+ elseif ta == "table" then -- generic (we keep the deltas)
+ for i=1,#ma do
+ ma[i](target,tfmdata,delta,hdelta,vdelta)
+ end
+ end
+ if not targetparameters[13] then targetparameters[13] = .86*targetx_height end -- mathsupdisplay
+ if not targetparameters[14] then targetparameters[14] = .86*targetx_height end -- mathsupnormal
+ if not targetparameters[15] then targetparameters[15] = .86*targetx_height end -- mathsupcramped
+ if not targetparameters[16] then targetparameters[16] = .48*targetx_height end -- mathsubnormal
+ if not targetparameters[17] then targetparameters[17] = .48*targetx_height end -- mathsubcombined
+ if not targetparameters[22] then targetparameters[22] = 0 end -- mathaxisheight
+ if target.MathConstants then target.MathConstants.AccentBaseHeight = nil end -- safeguard
+ if trace_defining then
+ report_defining("math enabled for: name '%s', fullname: '%s', filename: '%s'",
+ name or "noname",fullname or "nofullname",filename or "nofilename")
+ end
+ else
+ if trace_defining then
+ report_defining("math disabled for: name '%s', fullname: '%s', filename: '%s'",
+ name or "noname",fullname or "nofullname",filename or "nofilename")
+ end
+ end
+ --
+ targetparameters.xheight = targetparameters.xheight or parameters.x_height
+ targetparameters.extraspace = targetparameters.extraspace or parameters.extra_space
+ targetparameters.spacestretch = targetparameters.spacestretch or parameters.space_stretch
+ targetparameters.spaceshrink = targetparameters.spaceshrink or parameters.space_shrink
+ --
+ local protrusionfactor = (targetquad ~= 0 and 1000/targetquad) or 0
+ local scaledwidth = defaultwidth * hdelta
+ local scaledheight = defaultheight * vdelta
+ local scaleddepth = defaultdepth * vdelta
+ --
+ local sharedkerns = { }
+ --
+ for unicode, character in next, characters do
local chr, description, index
- if ischanged then
+ if changed then
-- basemode hack
- local c = changed[k]
+ local c = changed[unicode]
if c then
- description = descriptions[c] or v
- v = characters[c] or v
- index = (indices and indices[c]) or c
+ description = descriptions[c] or character
+ character = characters[c] or character
+ index = description.index or c
else
- description = descriptions[k] or v
- index = (indices and indices[k]) or k
+ description = descriptions[unicode] or character
+ index = description.index or unicode
end
else
- description = descriptions[k] or v
- index = (indices and indices[k]) or k
+ description = descriptions[unicode] or character
+ index = description.index or unicode
end
local width = description.width
local height = description.height
@@ -3823,9 +3329,8 @@ function tfm.scale(tfmtable, scaledpoints, relativeid)
-- if depth then depth = vdelta*depth else depth = scaleddepth end
if depth and depth ~= 0 then
depth = delta*depth
- if nameneeded then
+ if nonames then
chr = {
- name = description.name,
index = index,
height = height,
depth = depth,
@@ -3833,6 +3338,7 @@ function tfm.scale(tfmtable, scaledpoints, relativeid)
}
else
chr = {
+ name = description.name,
index = index,
height = height,
depth = depth,
@@ -3841,15 +3347,15 @@ function tfm.scale(tfmtable, scaledpoints, relativeid)
end
else
-- this saves a little bit of memory time and memory, esp for big cjk fonts
- if nameneeded then
+ if nonames then
chr = {
- name = description.name,
index = index,
height = height,
width = width,
}
else
chr = {
+ name = description.name,
index = index,
height = height,
width = width,
@@ -3867,22 +3373,22 @@ function tfm.scale(tfmtable, scaledpoints, relativeid)
end
if hasquality then
-- we could move these calculations elsewhere (saves calculations)
- local ve = v.expansion_factor
+ local ve = character.expansion_factor
if ve then
chr.expansion_factor = ve*1000 -- expansionfactor, hm, can happen elsewhere
end
- local vl = v.left_protruding
+ local vl = character.left_protruding
if vl then
chr.left_protruding = protrusionfactor*width*vl
end
- local vr = v.right_protruding
+ local vr = character.right_protruding
if vr then
chr.right_protruding = protrusionfactor*width*vr
end
end
-- todo: hasitalic
if hasitalic then
- local vi = description.italic or v.italic
+ local vi = description.italic or character.italic
if vi and vi ~= 0 then
chr.italic = vi*hdelta
end
@@ -3890,14 +3396,14 @@ function tfm.scale(tfmtable, scaledpoints, relativeid)
-- to be tested
if hasmath then
-- todo, just operate on descriptions.math
- local vn = v.next
+ local vn = character.next
if vn then
chr.next = vn
- --~ if v.vert_variants or v.horiz_variants then
- --~ report_defining("glyph 0x%05X has combination of next, vert_variants and horiz_variants",index)
- --~ end
+ -- if character.vert_variants or character.horiz_variants then
+ -- report_defining("glyph 0x%05X has combination of next, vert_variants and horiz_variants",index)
+ -- end
else
- local vv = v.vert_variants
+ local vv = character.vert_variants
if vv then
local t = { }
for i=1,#vv do
@@ -3911,13 +3417,8 @@ function tfm.scale(tfmtable, scaledpoints, relativeid)
}
end
chr.vert_variants = t
- --~ local ic = v.vert_italic_correction
- --~ if ic then
- --~ chr.italic = ic * hdelta
- --~ print(format("0x%05X -> %s",k,chr.italic))
- --~ end
else
- local hv = v.horiz_variants
+ local hv = character.horiz_variants
if hv then
local t = { }
for i=1,#hv do
@@ -3934,12 +3435,12 @@ function tfm.scale(tfmtable, scaledpoints, relativeid)
end
end
end
- local vt = description.top_accent
- if vt then
- chr.top_accent = vdelta*vt
+ local va = character.top_accent
+ if va then
+ chr.top_accent = vdelta*va
end
if stackmath then
- local mk = v.mathkerns
+ local mk = character.mathkerns -- not in math ?
if mk then
local kerns = { }
local v = mk.top_right if v then local k = { } for i=1,#v do local vi = v[i]
@@ -3954,26 +3455,26 @@ function tfm.scale(tfmtable, scaledpoints, relativeid)
local v = mk.bottom_right if v then local k = { } for i=1,#v do local vi = v[i]
k[i] = { height = vdelta*vi.height, kern = vdelta*vi.kern }
end kerns.bottom_right = k end
- chr.mathkern = kerns -- singular
+ chr.mathkern = kerns -- singular -> should be patched in luatex !
end
end
end
if not nodemode then
- local vk = v.kerns
+ local vk = character.kerns
if vk then
- --~ if sharedkerns then
- --~ local base = basekerns[vk] -- hashed by table id, not content
- --~ if not base then
- --~ base = {}
- --~ for k,v in next, vk do base[k] = v*hdelta end
- --~ basekerns[vk] = base
- --~ end
- --~ chr.kerns = base
- --~ else
- --~ local tt = {}
- --~ for k,v in next, vk do tt[k] = v*hdelta end
- --~ chr.kerns = tt
- --~ end
+ -- if sharedkerns then
+ -- local base = basekerns[vk] -- hashed by table id, not content
+ -- if not base then
+ -- base = {}
+ -- for k,v in next, vk do base[k] = v*hdelta end
+ -- basekerns[vk] = base
+ -- end
+ -- chr.kerns = base
+ -- else
+ -- local tt = {}
+ -- for k,v in next, vk do tt[k] = v*hdelta end
+ -- chr.kerns = tt
+ -- end
local s = sharedkerns[vk]
if not s then
s = { }
@@ -3982,7 +3483,7 @@ function tfm.scale(tfmtable, scaledpoints, relativeid)
end
chr.kerns = s
end
- local vl = v.ligatures
+ local vl = character.ligatures
if vl then
if true then
chr.ligatures = vl -- shared
@@ -3996,7 +3497,7 @@ function tfm.scale(tfmtable, scaledpoints, relativeid)
end
end
if isvirtual then
- local vc = v.commands
+ local vc = character.commands
if vc then
-- we assume non scaled commands here
-- tricky .. we need to scale pseudo math glyphs too
@@ -4031,218 +3532,555 @@ function tfm.scale(tfmtable, scaledpoints, relativeid)
chr.index = nil
end
end
- tc[k] = chr
+ targetcharacters[unicode] = chr
end
- -- t.encodingbytes, t.filename, t.fullname, t.name: elsewhere
- t.size = scaledpoints
- t.factor = delta
- t.hfactor = hdelta
- t.vfactor = vdelta
- if t.fonts then
- t.fonts = table.fastcopy(t.fonts) -- maybe we virtualize more afterwards
+ return target
+end
+
+function constructors.finalize(tfmdata)
+ if tfmdata.properties and tfmdata.properties.finalized then
+ return
end
- if hasmath then
- -- mathematics.extras.copy(t) -- can be done elsewhere if needed
- local ma = tfm.mathactions
- for i=1,#ma do
- ma[i](t,tfmtable,delta,hdelta,vdelta) -- what delta?
- end
+ --
+ if not tfmdata.characters then
+ return nil
end
- -- needed for \high cum suis
- local tpx = tp.x_height
- if hasmath then
- if not tp[13] then tp[13] = .86*tpx end -- mathsupdisplay
- if not tp[14] then tp[14] = .86*tpx end -- mathsupnormal
- if not tp[15] then tp[15] = .86*tpx end -- mathsupcramped
- if not tp[16] then tp[16] = .48*tpx end -- mathsubnormal
- if not tp[17] then tp[17] = .48*tpx end -- mathsubcombined
- if not tp[22] then tp[22] = 0 end -- mathaxisheight
- if t.MathConstants then t.MathConstants.AccentBaseHeight = nil end -- safeguard
- end
- t.tounicode = 1
- t.cidinfo = tfmtable.cidinfo
- -- we have t.name=metricfile and t.fullname=RealName and t.filename=diskfilename
- -- when collapsing fonts, luatex looks as both t.name and t.fullname as ttc files
- -- can have multiple subfonts
- if hasmath then
- if trace_defining then
- report_defining("math enabled for: name '%s', fullname: '%s', filename: '%s'",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename")
- end
- else
- if trace_defining then
- report_defining("math disabled for: name '%s', fullname: '%s', filename: '%s'",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename")
- end
- t.nomath, t.MathConstants = true, nil
+ --
+ if not tfmdata.goodies then
+ tfmdata.goodies = { } -- context specific
end
- if not t.psname then
- -- name used in pdf file as well as for selecting subfont in ttc/dfont
- t.psname = t.fontname or (t.fullname and fonts.names.cleanname(t.fullname))
+ --
+ local parameters = tfmdata.parameters
+ if not parameters then
+ return nil
end
- if trace_defining then
- report_defining("used for accessing (sub)font: '%s'",t.psname or "nopsname")
- report_defining("used for subsetting: '%s'",t.fontname or "nofontname")
- end
- -- this will move up (side effect of merging split call)
- t.factor = delta
- t.ascender = delta*(tfmtable.ascender or 0)
- t.descender = delta*(tfmtable.descender or 0)
- t.shared = tfmtable.shared or { }
- t.unique = table.fastcopy(tfmtable.unique or {})
- tfm.cleanup(t)
- -- print(t.fontname,table.serialize(t.MathConstants))
- return t
+ --
+ if not parameters.expansion then
+ parameters.expansion = {
+ stretch = tfmdata.stretch or 0,
+ shrink = tfmdata.shrink or 0,
+ step = tfmdata.step or 0,
+ auto = tfmdata.auto_expand or false,
+ }
+ end
+ --
+ if not parameters.protrusion then
+ parameters.protrusion = {
+ auto = auto_protrude
+ }
+ end
+ --
+ if not parameters.size then
+ parameters.size = tfmdata.size
+ end
+ --
+ if not parameters.extend_factor then
+ parameters.extend_factor = tfmdata.extend or 0
+ end
+ --
+ if not parameters.slant_factor then
+ parameters.slant_factor = tfmdata.slant or 0
+ end
+ --
+ if not parameters.designsize then
+ parameters.designsize = tfmdata.designsize or 655360
+ end
+ --
+ if not parameters.units then
+ parameters.units = tfmdata.units_per_em or 1000
+ end
+ --
+ if not tfmdata.descriptions then
+ local descriptions = { } -- yes or no
+ setmetatable(descriptions, { __index = function(t,k) local v = { } t[k] = v return v end })
+ tfmdata.descriptions = descriptions
+ end
+ --
+ local properties = tfmdata.properties
+ if not properties then
+ properties = { }
+ tfmdata.properties = properties
+ end
+ --
+ if not properties.virtualized then
+ properties.virtualized = tfmdata.type == "virtual"
+ end
+ --
+ if not tfmdata.properties then
+ tfmdata.properties = {
+ fontname = tfmdata.fontname,
+ filename = tfmdata.filename,
+ fullname = tfmdata.fullname,
+ name = tfmdata.name,
+ psname = tfmdata.psname,
+ --
+ encodingbytes = tfmdata.encodingbytes or 1,
+ embedding = tfmdata.embedding or "subset",
+ tounicode = tfmdata.tounicode or 1,
+ cidinfo = tfmdata.cidinfo or nil,
+ format = tfmdata.format or "type1",
+ direction = tfmdata.direction or 0,
+ }
+ end
+ if not tfmdata.resources then
+ tfmdata.resources = { }
+ end
+ if not tfmdata.shared then
+ tfmdata.shared = { }
+ end
+ --
+ -- tfmdata.fonts
+ -- tfmdata.unscaled
+ -- tfmdata.mathconstants
+ --
+ if not properties.has_math then
+ properties.has_math = not tfmdata.nomath
+ end
+ --
+ tfmdata.MathConstants = nil
+ tfmdata.postprocessors = nil
+ --
+ tfmdata.fontname = nil
+ tfmdata.filename = nil
+ tfmdata.fullname = nil
+ tfmdata.name = nil -- most tricky part
+ tfmdata.psname = nil
+ --
+ tfmdata.encodingbytes = nil
+ tfmdata.embedding = nil
+ tfmdata.tounicode = nil
+ tfmdata.cidinfo = nil
+ tfmdata.format = nil
+ tfmdata.direction = nil
+ tfmdata.type = nil
+ tfmdata.nomath = nil
+ tfmdata.designsize = nil
+ --
+ tfmdata.size = nil
+ tfmdata.stretch = nil
+ tfmdata.shrink = nil
+ tfmdata.step = nil
+ tfmdata.auto_expand = nil
+ tfmdata.auto_protrude = nil
+ tfmdata.extend = nil
+ tfmdata.slant = nil
+ tfmdata.units_per_em = nil
+ --
+ properties.finalized = true
+ --
+ return tfmdata
end
--[[ldx--
-<p>Analyzers run per script and/or language and are needed in order to
-process features right.</p>
+<p>A unique hash value is generated by:</p>
--ldx]]--
-fonts.analyzers = fonts.analyzers or { }
-local analyzers = fonts.analyzers
-
-analyzers.aux = analyzers.aux or { }
-analyzers.methods = analyzers.methods or { }
-analyzers.initializers = analyzers.initializers or { }
+local hashmethods = { }
+constructors.hashmethods = hashmethods
--- todo: analyzers per script/lang, cross font, so we need an font id hash -> script
--- e.g. latin -> hyphenate, arab -> 1/2/3 analyze
-
--- an example analyzer (should move to font-ota.lua)
-
-local state = attributes.private('state')
-
-function analyzers.aux.setstate(head,font)
- local useunicodemarks = analyzers.useunicodemarks
- local tfmdata = fontdata[font]
- local characters = tfmdata.characters
- local descriptions = tfmdata.descriptions
- local first, last, current, n, done = nil, nil, head, 0, false -- maybe make n boolean
- while current do
- local id = current.id
- if id == glyph_code and current.font == font then
- local char = current.char
- local d = descriptions[char]
- if d then
- if d.class == "mark" or (useunicodemarks and categories[char] == "mn") then
- done = true
- set_attribute(current,state,5) -- mark
- elseif n == 0 then
- first, last, n = current, current, 1
- set_attribute(current,state,1) -- init
- else
- last, n = current, n+1
- set_attribute(current,state,2) -- medi
- end
- else -- finish
- if first and first == last then
- set_attribute(last,state,4) -- isol
- elseif last then
- set_attribute(last,state,3) -- fina
+function constructors.hashfeatures(specification) -- will be overloaded
+ local features = specification.features
+ if features then
+ local t, tn = { }, 0
+ for category, list in next, features do
+ if next(list) then
+ local hasher = hashmethods[category]
+ if hasher then
+ local hash = hasher(list)
+ if hash then
+ tn = tn + 1
+ t[tn] = category .. ":" .. hash
+ end
end
- first, last, n = nil, nil, 0
end
- elseif id == disc_code then
- -- always in the middle
- set_attribute(current,state,2) -- midi
- last = current
- else -- finish
- if first and first == last then
- set_attribute(last,state,4) -- isol
- elseif last then
- set_attribute(last,state,3) -- fina
- end
- first, last, n = nil, nil, 0
end
- current = current.next
+ if tn > 0 then
+ return concat(t," & ")
+ end
end
- if first and first == last then
- set_attribute(last,state,4) -- isol
- elseif last then
- set_attribute(last,state,3) -- fina
+ return "unknown"
+end
+
+hashmethods.normal = function(list)
+ local s = { }
+ local n = 0
+ for k, v in next, list do
+ if k ~= "number" and k ~= "features" then -- I need to figure this out, features
+ n = n + 1
+ s[n] = k
+ end
+ 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
- return head, done
end
-function tfm.replacements(tfm,value)
- -- tfm.characters[0x0022] = table.fastcopy(tfm.characters[0x201D])
- -- tfm.characters[0x0027] = table.fastcopy(tfm.characters[0x2019])
- -- tfm.characters[0x0060] = table.fastcopy(tfm.characters[0x2018])
- -- tfm.characters[0x0022] = tfm.characters[0x201D]
- tfm.characters[0x0027] = tfm.characters[0x2019]
- -- tfm.characters[0x0060] = tfm.characters[0x2018]
+--[[ldx--
+<p>In principle we can share tfm tables when we are in node for a font, but then
+we need to define a font switch as an id/attr switch which is no fun, so in that
+case users can best use dynamic features ... so, we will not use that speedup. Okay,
+when we get rid of base mode we can optimize even further by sharing, but then we
+loose our testcases for <l n='luatex'/>.</p>
+--ldx]]--
+
+function constructors.hashinstance(specification,force)
+ local hash, size, fallbacks = specification.hash, specification.size, specification.fallbacks
+ if force or not hash then
+ hash = constructors.hashfeatures(specification)
+ specification.hash = hash
+ end
+ if size < 1000 and designsizes[hash] then
+ size = math.round(constructors.scaled(size,designsizes[hash]))
+ specification.size = size
+ end
+ -- local mathsize = specification.mathsize or 0
+ -- if mathsize > 0 then
+ -- local textsize = specification.textsize
+ -- if fallbacks then
+ -- return hash .. ' @ ' .. tostring(size) .. ' [ ' .. tostring(mathsize) .. ' : ' .. tostring(textsize) .. ' ] @ ' .. fallbacks
+ -- else
+ -- return hash .. ' @ ' .. tostring(size) .. ' [ ' .. tostring(mathsize) .. ' : ' .. tostring(textsize) .. ' ]'
+ -- end
+ -- else
+ if fallbacks then
+ return hash .. ' @ ' .. tostring(size) .. ' @ ' .. fallbacks
+ else
+ return hash .. ' @ ' .. tostring(size)
+ end
+ -- end
end
--- checking
+function constructors.setname(tfmdata,specification) -- todo: get specification from tfmdata
+ if constructors.namemode == "specification" then
+ -- not to be used in context !
+ local specname = specification.specification
+ if specname then
+ tfmdata.properties.name = specname
+ if trace_defining then
+ report_otf("overloaded fontname: '%s'",specname)
+ end
+ end
+ end
+end
-function tfm.checkedfilename(metadata,whatever)
- local foundfilename = metadata.foundfilename
+function constructors.checkedfilename(data)
+ local foundfilename = data.foundfilename
if not foundfilename then
- local askedfilename = metadata.filename or ""
+ local askedfilename = data.filename or ""
if askedfilename ~= "" then
askedfilename = resolvers.resolve(askedfilename) -- no shortcut
- foundfilename = findbinfile(askedfilename,"") or ""
+ foundfilename = resolvers.findbinfile(askedfilename,"") or ""
if foundfilename == "" then
report_defining("source file '%s' is not found",askedfilename)
- foundfilename = findbinfile(file.basename(askedfilename),"") or ""
+ foundfilename = resolvers.findbinfile(file.basename(askedfilename),"") or ""
if foundfilename ~= "" then
report_defining("using source file '%s' (cache mismatch)",foundfilename)
end
end
- elseif whatever then
- report_defining("no source file for '%s'",whatever)
- foundfilename = ""
end
- metadata.foundfilename = foundfilename
- -- report_defining("using source file '%s'",foundfilename)
+ data.foundfilename = foundfilename
end
return foundfilename
end
--- status info
+local formats = allocate()
+fonts.formats = formats
-statistics.register("fonts load time", function()
- return statistics.elapsedseconds(fonts)
-end)
+setmetatable(formats, {
+ __index = function(t,k)
+ local l = lower(k)
+ if rawget(t,k) then
+ t[k] = l
+ return l
+ end
+ return rawget(t,file.extname(l))
+ end
+} )
--- readers
+local locations = { }
-fonts.formats.tfm = "type1" -- we need to have at least a value here
+local function setindeed(mode,target,group,name,action,position)
+ local t = target[mode]
+ if not t then
+ report_defining("fatal error in setting feature '%s', group '%s', mode '%s'",name or "?",group or "?",mode)
+ os.exit()
+ elseif position then
+ -- todo: remove existing
+ insert(t, position, { name = name, action = action })
+ else
+ for i=1,#t do
+ local ti = t[i]
+ if ti.name == name then
+ ti.action = action
+ return
+ end
+ end
+ insert(t, { name = name, action = action })
+ end
+end
-local function check_tfm(specification,fullname)
- -- ofm directive blocks local path search unless set; btw, in context we
- -- don't support ofm files anyway as this format is obsolete
- local foundname = findbinfile(fullname, 'tfm') or "" -- just to be sure
- if foundname == "" then
- foundname = findbinfile(fullname, 'ofm') or "" -- bonus for usage outside context
+local function set(group,name,target,source)
+ target = target[group]
+ if not target then
+ report_defining("fatal target error in setting feature '%s', group '%s'",name or "?",group or "?")
+ os.exit()
end
- if foundname == "" then
- foundname = fonts.names.getfilename(fullname,"tfm")
+ local source = source[group]
+ if not source then
+ report_defining("fatal source error in setting feature '%s', group '%s'",name or "?",group or "?")
+ os.exit()
end
- if foundname ~= "" then
- specification.filename, specification.format = foundname, "ofm"
- return read_from_tfm(specification)
+ local node = source.node
+ local base = source.base
+ local position = source.position
+ if node then
+ setindeed("node",target,group,name,node,position)
+ end
+ if base then
+ setindeed("base",target,group,name,base,position)
+ end
+end
+
+local function register(where,specification)
+ local name = specification.name
+ if name and name ~= "" then
+ local default = specification.default
+ local description = specification.description
+ local initializers = specification.initializers
+ local processors = specification.processors
+ local manipulators = specification.manipulators
+ local modechecker = specification.modechecker
+ if default then
+ where.defaults[name] = default
+ end
+ if description and description ~= "" then
+ where.descriptions[name] = description
+ end
+ if initializers then
+ set('initializers',name,where,specification)
+ end
+ if processors then
+ set('processors', name,where,specification)
+ end
+ if manipulators then
+ set('manipulators',name,where,specification)
+ end
+ if modechecker then
+ where.modechecker = modechecker
+ end
end
end
-readers.check_tfm = check_tfm
+constructors.registerfeature = register
-function readers.tfm(specification)
- local fullname, tfmtable = specification.filename or "", nil
- if fullname == "" then
- local forced = specification.forced or ""
- if forced ~= "" then
- tfmtable = check_tfm(specification,specification.name .. "." .. forced)
+function constructors.getfeatureaction(what,where,mode,name)
+ what = handlers[what].features
+ if what then
+ where = what[where]
+ if where then
+ mode = where[mode]
+ if mode then
+ for i=1,#mode do
+ local m = mode[i]
+ if m.name == name then
+ return m.action
+ end
+ end
+ end
+ end
+ end
+end
+
+function constructors.newfeatures(what)
+ local features = handlers[what].features
+ if not features then
+ local tables = handlers[what].tables -- can be preloaded
+ features = {
+ defaults = { },
+ descriptions = tables and tables.features or { },
+ initializers = { base = { }, node = { } },
+ processors = { base = { }, node = { } },
+ manipulators = { base = { }, node = { } },
+ }
+ features.register = function(specification) return register(features,specification) end
+ handlers[what].features = features -- will also become hidden
+ end
+ return features
+end
+
+--[[ldx--
+<p>We need to check for default features. For this we provide
+a helper function.</p>
+--ldx]]--
+
+function constructors.checkedfeatures(what,features)
+ if features and next(features) then
+ local done = false
+ for key, value in next, handlers[what].features.defaults do
+ if features[key] == nil then
+ features[key] = value
+ done = true
+ end
end
- if not tfmtable then
- tfmtable = check_tfm(specification,specification.name)
+ return features, done -- done signals a change
+ else
+ return fastcopy(defaults), true
+ end
+end
+
+-- before scaling
+
+function constructors.initializefeatures(what,tfmdata,features,trace,report)
+ if features and next(features) then
+ local properties = tfmdata.properties or { } -- brrr
+ local whathandler = handlers[what]
+ local whatfeatures = whathandler.features
+ local whatinitializers = whatfeatures.initializers
+ local whatmodechecker = whatfeatures.modechecker
+ local mode = properties.mode or (whatmodechecker and whatmodechecker(tfmdata,features)) or features.mode or "base"
+ properties.mode = mode -- also status
+ local done = { }
+ while true do
+ local redo = false
+ local initializers = whatfeatures.initializers[mode]
+ if initializers then
+ for i=1,#initializers do
+ local step = initializers[i]
+ local feature = step.name
+ local value = features[feature]
+ if not value then
+ -- disabled
+ elseif done[feature] then
+ -- already done
+ else
+ local action = step.action
+ if trace then
+ report("initializing feature %s to %s for mode %s for font %s",feature,
+ tostring(value),mode or 'unknown', tfmdata.properties.fullname or 'unknown')
+ end
+ action(tfmdata,value,features) -- can set mode (e.g. goodies) so it can trigger a restart
+ if mode ~= properties.mode then
+ mode = properties.mode
+ redo = true
+ end
+ done[feature] = true
+ end
+ if redo then
+ break
+ end
+ end
+ if not redo then
+ break
+ end
+ else
+ break
+ end
end
+ properties.mode = mode -- to be sure
+ return true
else
- tfmtable = check_tfm(specification,fullname)
+ return false
end
- return tfmtable
end
+-- while typesetting
+
+function constructors.collectprocessors(what,tfmdata,features,trace,report)
+ local processes, nofprocesses = { }, 0
+ if features and next(features) then
+ local properties = tfmdata.properties
+ local whathandler = handlers[what]
+ local whatfeatures = whathandler.features
+ local whatprocessors = whatfeatures.processors
+ local processors = whatprocessors[properties.mode]
+ if processors then
+ for i=1,#processors do
+ local step = processors[i]
+ local feature = step.name
+ if features[feature] then
+ local action = step.action
+ if trace then
+ report("installing feature processor %s for mode %s for font %s",feature,
+ mode or 'unknown', tfmdata.properties.fullname or 'unknown')
+ end
+ if action then
+ nofprocesses = nofprocesses + 1
+ processes[nofprocesses] = action
+ end
+ end
+ end
+ end
+ end
+ return processes
+end
+
+-- after scaling
+
+function constructors.applymanipulators(what,tfmdata,features,trace,report)
+ if features and next(features) then
+ local properties = tfmdata.properties
+ local whathandler = handlers[what]
+ local whatfeatures = whathandler.features
+ local whatmanipulators = whatfeatures.manipulators
+ local manipulators = whatmanipulators[properties.mode]
+ if manipulators then
+ for i=1,#manipulators do
+ local step = manipulators[i]
+ local feature = step.name
+ local value = features[feature]
+ if value then
+ local action = step.action
+ if trace then
+ report("applying feature manipulator %s for mode %s for font %s",feature,
+ mode or 'unknown', tfmdata.properties.fullname or 'unknown')
+ end
+ if action then
+ action(tfmdata,feature,value)
+ end
+ end
+ end
+ end
+ end
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['luatex-font-enc'] = {
+ version = 1.001,
+ comment = "companion to luatex-*.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+if context then
+ texio.write_nl("fatal error: this module is not for context")
+ os.exit()
+end
+
+local fonts = fonts
+fonts.encodings = { }
+fonts.encodings.agl = { }
+
+setmetatable(fonts.encodings.agl, { __index = function(t,k)
+ if k == "unicodes" then
+ texio.write(" <loading (extended) adobe glyph list>")
+ local unicodes = dofile(resolvers.findfile("font-agl.lua"))
+ fonts.encodings.agl = { unicodes = unicodes }
+ return unicodes
+ else
+ return nil
+ end
+end })
+
+
end -- closure
do -- begin closure to overcome local limits and interference
@@ -4257,18 +4095,19 @@ if not modules then modules = { } end modules ['font-cid'] = {
local format, match, lower = string.format, string.match, string.lower
local tonumber = tonumber
-local lpegmatch = lpeg.match
+local P, S, R, C, V, lpegmatch = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.match
-local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
+local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
local report_otf = logs.reporter("fonts","otf loading")
-local fonts = fonts
+local fonts = fonts
+
+local cid = { }
+fonts.cid = cid
-fonts.cid = fonts.cid or { }
-local cid = fonts.cid
-cid.map = cid.map or { }
-cid.max = cid.max or 10
+local cidmap = { }
+local cidmax = 10
-- original string parser: 0.109, lpeg parser: 0.036 seconds for Adobe-CNS1-4.cidmap
--
@@ -4277,8 +4116,6 @@ cid.max = cid.max or 10
-- 1..95 0020
-- 99 3000
-local P, S, R, C = lpeg.P, lpeg.S, lpeg.R, lpeg.C
-
local number = C(R("09","af","AF")^1)
local space = S(" \n\r\t")
local spaces = space^0
@@ -4286,7 +4123,7 @@ local period = P(".")
local periods = period * period
local name = P("/") * C((1-space)^1)
-local unicodes, names = { }, { }
+local unicodes, names = { }, { } -- we could use Carg now
local function do_one(a,b)
unicodes[tonumber(a)] = tonumber(b,16)
@@ -4304,15 +4141,15 @@ local function do_name(a,b)
names[tonumber(a)] = b
end
-local grammar = lpeg.P { "start",
- start = number * spaces * number * lpeg.V("series"),
- series = (spaces * (lpeg.V("one") + lpeg.V("range") + lpeg.V("named")) )^1,
+local grammar = P { "start",
+ start = number * spaces * number * V("series"),
+ series = (spaces * (V("one") + V("range") + V("named")))^1,
one = (number * spaces * number) / do_one,
range = (number * periods * number * spaces * number) / do_range,
named = (number * spaces * name) / do_name
}
-function cid.load(filename)
+local function loadcidfile(filename)
local data = io.loaddata(filename)
if data then
unicodes, names = { }, { }
@@ -4326,1043 +4163,94 @@ function cid.load(filename)
unicodes = unicodes,
names = names
}
- else
- return nil
end
end
+cid.loadfile = loadcidfile -- we use the frozen variant
+
local template = "%s-%s-%s.cidmap"
local function locate(registry,ordering,supplement)
local filename = format(template,registry,ordering,supplement)
local hashname = lower(filename)
- local cidmap = cid.map[hashname]
- if not cidmap then
+ local found = cidmap[hashname]
+ if not found then
if trace_loading then
report_otf("checking cidmap, registry: %s, ordering: %s, supplement: %s, filename: %s",registry,ordering,supplement,filename)
end
local fullname = resolvers.findfile(filename,'cid') or ""
if fullname ~= "" then
- cidmap = cid.load(fullname)
- if cidmap then
+ found = loadcidfile(fullname)
+ if found then
if trace_loading then
report_otf("using cidmap file %s",filename)
end
- cid.map[hashname] = cidmap
- cidmap.usedname = file.basename(filename)
- return cidmap
+ cidmap[hashname] = found
+ found.usedname = file.basename(filename)
end
end
end
- return cidmap
+ return found
end
-function cid.getmap(registry,ordering,supplement)
- -- cf Arthur R. we can safely scan upwards since cids are downward compatible
- local supplement = tonumber(supplement)
+-- cf Arthur R. we can safely scan upwards since cids are downward compatible
+
+function cid.getmap(specification)
+ if not specification then
+ report_otf("invalid cidinfo specification (table expected)")
+ return
+ end
+ local registry = specification.registry
+ local ordering = specification.ordering
+ local supplement = specification.supplement
+ -- check for already loaded file
+ local filename = format(registry,ordering,supplement)
+ local found = cidmap[lower(filename)]
+ if found then
+ return found
+ end
if trace_loading then
report_otf("needed cidmap, registry: %s, ordering: %s, supplement: %s",registry,ordering,supplement)
end
- local cidmap = locate(registry,ordering,supplement)
- if not cidmap then
+ found = locate(registry,ordering,supplement)
+ if not found then
+ local supnum = tonumber(supplement)
local cidnum = nil
-- next highest (alternatively we could start high)
- if supplement < cid.max then
- for supplement=supplement+1,cid.max do
- local c = locate(registry,ordering,supplement)
+ if supnum < cidmax then
+ for s=supnum+1,cidmax do
+ local c = locate(registry,ordering,s)
if c then
- cidmap, cidnum = c, supplement
+ found, cidnum = c, s
break
end
end
end
-- next lowest (least worse fit)
- if not cidmap and supplement > 0 then
- for supplement=supplement-1,0,-1 do
- local c = locate(registry,ordering,supplement)
+ if not found and supnum > 0 then
+ for s=supnum-1,0,-1 do
+ local c = locate(registry,ordering,s)
if c then
- cidmap, cidnum = c, supplement
+ found, cidnum = c, s
break
end
end
end
- -- prevent further lookups
- if cidmap and cidnum > 0 then
+ -- prevent further lookups -- somewhat tricky
+ registry = lower(registry)
+ ordering = lower(ordering)
+ if found and cidnum > 0 then
for s=0,cidnum-1 do
- filename = format(template,registry,ordering,s)
- if not cid.map[filename] then
- cid.map[filename] = cidmap -- copy of ref
+ local filename = format(template,registry,ordering,s)
+ if not cidmap[filename] then
+ cidmap[filename] = found
end
end
end
end
- return cidmap
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules = { } end modules ['font-otf'] = {
- version = 1.001,
- comment = "companion to font-otf.lua (tables)",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-local type, next, tonumber, tostring = type, next, tonumber, tostring
-local gsub, lower, format = string.gsub, string.lower, string.format
-local is_boolean = string.is_boolean
-
-local allocate = utilities.storage.allocate
-
-fonts = fonts or { } -- needed for font server
-local fonts = fonts
-fonts.otf = fonts.otf or { }
-local otf = fonts.otf
-
-otf.tables = otf.tables or { }
-local tables = otf.tables
-
-otf.meanings = otf.meanings or { }
-local meanings = otf.meanings
-
-local scripts = allocate {
- ['dflt'] = 'Default',
-
- ['arab'] = 'Arabic',
- ['armn'] = 'Armenian',
- ['bali'] = 'Balinese',
- ['beng'] = 'Bengali',
- ['bopo'] = 'Bopomofo',
- ['brai'] = 'Braille',
- ['bugi'] = 'Buginese',
- ['buhd'] = 'Buhid',
- ['byzm'] = 'Byzantine Music',
- ['cans'] = 'Canadian Syllabics',
- ['cher'] = 'Cherokee',
- ['copt'] = 'Coptic',
- ['cprt'] = 'Cypriot Syllabary',
- ['cyrl'] = 'Cyrillic',
- ['deva'] = 'Devanagari',
- ['dsrt'] = 'Deseret',
- ['ethi'] = 'Ethiopic',
- ['geor'] = 'Georgian',
- ['glag'] = 'Glagolitic',
- ['goth'] = 'Gothic',
- ['grek'] = 'Greek',
- ['gujr'] = 'Gujarati',
- ['guru'] = 'Gurmukhi',
- ['hang'] = 'Hangul',
- ['hani'] = 'CJK Ideographic',
- ['hano'] = 'Hanunoo',
- ['hebr'] = 'Hebrew',
- ['ital'] = 'Old Italic',
- ['jamo'] = 'Hangul Jamo',
- ['java'] = 'Javanese',
- ['kana'] = 'Hiragana and Katakana',
- ['khar'] = 'Kharosthi',
- ['khmr'] = 'Khmer',
- ['knda'] = 'Kannada',
- ['lao' ] = 'Lao',
- ['latn'] = 'Latin',
- ['limb'] = 'Limbu',
- ['linb'] = 'Linear B',
- ['math'] = 'Mathematical Alphanumeric Symbols',
- ['mlym'] = 'Malayalam',
- ['mong'] = 'Mongolian',
- ['musc'] = 'Musical Symbols',
- ['mymr'] = 'Myanmar',
- ['nko' ] = "N'ko",
- ['ogam'] = 'Ogham',
- ['orya'] = 'Oriya',
- ['osma'] = 'Osmanya',
- ['phag'] = 'Phags-pa',
- ['phnx'] = 'Phoenician',
- ['runr'] = 'Runic',
- ['shaw'] = 'Shavian',
- ['sinh'] = 'Sinhala',
- ['sylo'] = 'Syloti Nagri',
- ['syrc'] = 'Syriac',
- ['tagb'] = 'Tagbanwa',
- ['tale'] = 'Tai Le',
- ['talu'] = 'Tai Lu',
- ['taml'] = 'Tamil',
- ['telu'] = 'Telugu',
- ['tfng'] = 'Tifinagh',
- ['tglg'] = 'Tagalog',
- ['thaa'] = 'Thaana',
- ['thai'] = 'Thai',
- ['tibt'] = 'Tibetan',
- ['ugar'] = 'Ugaritic Cuneiform',
- ['xpeo'] = 'Old Persian Cuneiform',
- ['xsux'] = 'Sumero-Akkadian Cuneiform',
- ['yi' ] = 'Yi',
-}
-
-local languages = allocate {
- ['dflt'] = 'Default',
-
- ['aba'] = 'Abaza',
- ['abk'] = 'Abkhazian',
- ['ady'] = 'Adyghe',
- ['afk'] = 'Afrikaans',
- ['afr'] = 'Afar',
- ['agw'] = 'Agaw',
- ['als'] = 'Alsatian',
- ['alt'] = 'Altai',
- ['amh'] = 'Amharic',
- ['ara'] = 'Arabic',
- ['ari'] = 'Aari',
- ['ark'] = 'Arakanese',
- ['asm'] = 'Assamese',
- ['ath'] = 'Athapaskan',
- ['avr'] = 'Avar',
- ['awa'] = 'Awadhi',
- ['aym'] = 'Aymara',
- ['aze'] = 'Azeri',
- ['bad'] = 'Badaga',
- ['bag'] = 'Baghelkhandi',
- ['bal'] = 'Balkar',
- ['bau'] = 'Baule',
- ['bbr'] = 'Berber',
- ['bch'] = 'Bench',
- ['bcr'] = 'Bible Cree',
- ['bel'] = 'Belarussian',
- ['bem'] = 'Bemba',
- ['ben'] = 'Bengali',
- ['bgr'] = 'Bulgarian',
- ['bhi'] = 'Bhili',
- ['bho'] = 'Bhojpuri',
- ['bik'] = 'Bikol',
- ['bil'] = 'Bilen',
- ['bkf'] = 'Blackfoot',
- ['bli'] = 'Balochi',
- ['bln'] = 'Balante',
- ['blt'] = 'Balti',
- ['bmb'] = 'Bambara',
- ['bml'] = 'Bamileke',
- ['bos'] = 'Bosnian',
- ['bre'] = 'Breton',
- ['brh'] = 'Brahui',
- ['bri'] = 'Braj Bhasha',
- ['brm'] = 'Burmese',
- ['bsh'] = 'Bashkir',
- ['bti'] = 'Beti',
- ['cat'] = 'Catalan',
- ['ceb'] = 'Cebuano',
- ['che'] = 'Chechen',
- ['chg'] = 'Chaha Gurage',
- ['chh'] = 'Chattisgarhi',
- ['chi'] = 'Chichewa',
- ['chk'] = 'Chukchi',
- ['chp'] = 'Chipewyan',
- ['chr'] = 'Cherokee',
- ['chu'] = 'Chuvash',
- ['cmr'] = 'Comorian',
- ['cop'] = 'Coptic',
- ['cos'] = 'Corsican',
- ['cre'] = 'Cree',
- ['crr'] = 'Carrier',
- ['crt'] = 'Crimean Tatar',
- ['csl'] = 'Church Slavonic',
- ['csy'] = 'Czech',
- ['dan'] = 'Danish',
- ['dar'] = 'Dargwa',
- ['dcr'] = 'Woods Cree',
- ['deu'] = 'German',
- ['dgr'] = 'Dogri',
- ['div'] = 'Divehi',
- ['djr'] = 'Djerma',
- ['dng'] = 'Dangme',
- ['dnk'] = 'Dinka',
- ['dri'] = 'Dari',
- ['dun'] = 'Dungan',
- ['dzn'] = 'Dzongkha',
- ['ebi'] = 'Ebira',
- ['ecr'] = 'Eastern Cree',
- ['edo'] = 'Edo',
- ['efi'] = 'Efik',
- ['ell'] = 'Greek',
- ['eng'] = 'English',
- ['erz'] = 'Erzya',
- ['esp'] = 'Spanish',
- ['eti'] = 'Estonian',
- ['euq'] = 'Basque',
- ['evk'] = 'Evenki',
- ['evn'] = 'Even',
- ['ewe'] = 'Ewe',
- ['fan'] = 'French Antillean',
- ['far'] = 'Farsi',
- ['fin'] = 'Finnish',
- ['fji'] = 'Fijian',
- ['fle'] = 'Flemish',
- ['fne'] = 'Forest Nenets',
- ['fon'] = 'Fon',
- ['fos'] = 'Faroese',
- ['fra'] = 'French',
- ['fri'] = 'Frisian',
- ['frl'] = 'Friulian',
- ['fta'] = 'Futa',
- ['ful'] = 'Fulani',
- ['gad'] = 'Ga',
- ['gae'] = 'Gaelic',
- ['gag'] = 'Gagauz',
- ['gal'] = 'Galician',
- ['gar'] = 'Garshuni',
- ['gaw'] = 'Garhwali',
- ['gez'] = "Ge'ez",
- ['gil'] = 'Gilyak',
- ['gmz'] = 'Gumuz',
- ['gon'] = 'Gondi',
- ['grn'] = 'Greenlandic',
- ['gro'] = 'Garo',
- ['gua'] = 'Guarani',
- ['guj'] = 'Gujarati',
- ['hai'] = 'Haitian',
- ['hal'] = 'Halam',
- ['har'] = 'Harauti',
- ['hau'] = 'Hausa',
- ['haw'] = 'Hawaiin',
- ['hbn'] = 'Hammer-Banna',
- ['hil'] = 'Hiligaynon',
- ['hin'] = 'Hindi',
- ['hma'] = 'High Mari',
- ['hnd'] = 'Hindko',
- ['ho'] = 'Ho',
- ['hri'] = 'Harari',
- ['hrv'] = 'Croatian',
- ['hun'] = 'Hungarian',
- ['hye'] = 'Armenian',
- ['ibo'] = 'Igbo',
- ['ijo'] = 'Ijo',
- ['ilo'] = 'Ilokano',
- ['ind'] = 'Indonesian',
- ['ing'] = 'Ingush',
- ['inu'] = 'Inuktitut',
- ['iri'] = 'Irish',
- ['irt'] = 'Irish Traditional',
- ['isl'] = 'Icelandic',
- ['ism'] = 'Inari Sami',
- ['ita'] = 'Italian',
- ['iwr'] = 'Hebrew',
- ['jan'] = 'Japanese',
- ['jav'] = 'Javanese',
- ['jii'] = 'Yiddish',
- ['jud'] = 'Judezmo',
- ['jul'] = 'Jula',
- ['kab'] = 'Kabardian',
- ['kac'] = 'Kachchi',
- ['kal'] = 'Kalenjin',
- ['kan'] = 'Kannada',
- ['kar'] = 'Karachay',
- ['kat'] = 'Georgian',
- ['kaz'] = 'Kazakh',
- ['keb'] = 'Kebena',
- ['kge'] = 'Khutsuri Georgian',
- ['kha'] = 'Khakass',
- ['khk'] = 'Khanty-Kazim',
- ['khm'] = 'Khmer',
- ['khs'] = 'Khanty-Shurishkar',
- ['khv'] = 'Khanty-Vakhi',
- ['khw'] = 'Khowar',
- ['kik'] = 'Kikuyu',
- ['kir'] = 'Kirghiz',
- ['kis'] = 'Kisii',
- ['kkn'] = 'Kokni',
- ['klm'] = 'Kalmyk',
- ['kmb'] = 'Kamba',
- ['kmn'] = 'Kumaoni',
- ['kmo'] = 'Komo',
- ['kms'] = 'Komso',
- ['knr'] = 'Kanuri',
- ['kod'] = 'Kodagu',
- ['koh'] = 'Korean Old Hangul',
- ['kok'] = 'Konkani',
- ['kon'] = 'Kikongo',
- ['kop'] = 'Komi-Permyak',
- ['kor'] = 'Korean',
- ['koz'] = 'Komi-Zyrian',
- ['kpl'] = 'Kpelle',
- ['kri'] = 'Krio',
- ['krk'] = 'Karakalpak',
- ['krl'] = 'Karelian',
- ['krm'] = 'Karaim',
- ['krn'] = 'Karen',
- ['krt'] = 'Koorete',
- ['ksh'] = 'Kashmiri',
- ['ksi'] = 'Khasi',
- ['ksm'] = 'Kildin Sami',
- ['kui'] = 'Kui',
- ['kul'] = 'Kulvi',
- ['kum'] = 'Kumyk',
- ['kur'] = 'Kurdish',
- ['kuu'] = 'Kurukh',
- ['kuy'] = 'Kuy',
- ['kyk'] = 'Koryak',
- ['lad'] = 'Ladin',
- ['lah'] = 'Lahuli',
- ['lak'] = 'Lak',
- ['lam'] = 'Lambani',
- ['lao'] = 'Lao',
- ['lat'] = 'Latin',
- ['laz'] = 'Laz',
- ['lcr'] = 'L-Cree',
- ['ldk'] = 'Ladakhi',
- ['lez'] = 'Lezgi',
- ['lin'] = 'Lingala',
- ['lma'] = 'Low Mari',
- ['lmb'] = 'Limbu',
- ['lmw'] = 'Lomwe',
- ['lsb'] = 'Lower Sorbian',
- ['lsm'] = 'Lule Sami',
- ['lth'] = 'Lithuanian',
- ['ltz'] = 'Luxembourgish',
- ['lub'] = 'Luba',
- ['lug'] = 'Luganda',
- ['luh'] = 'Luhya',
- ['luo'] = 'Luo',
- ['lvi'] = 'Latvian',
- ['maj'] = 'Majang',
- ['mak'] = 'Makua',
- ['mal'] = 'Malayalam Traditional',
- ['man'] = 'Mansi',
- ['map'] = 'Mapudungun',
- ['mar'] = 'Marathi',
- ['maw'] = 'Marwari',
- ['mbn'] = 'Mbundu',
- ['mch'] = 'Manchu',
- ['mcr'] = 'Moose Cree',
- ['mde'] = 'Mende',
- ['men'] = "Me'en",
- ['miz'] = 'Mizo',
- ['mkd'] = 'Macedonian',
- ['mle'] = 'Male',
- ['mlg'] = 'Malagasy',
- ['mln'] = 'Malinke',
- ['mlr'] = 'Malayalam Reformed',
- ['mly'] = 'Malay',
- ['mnd'] = 'Mandinka',
- ['mng'] = 'Mongolian',
- ['mni'] = 'Manipuri',
- ['mnk'] = 'Maninka',
- ['mnx'] = 'Manx Gaelic',
- ['moh'] = 'Mohawk',
- ['mok'] = 'Moksha',
- ['mol'] = 'Moldavian',
- ['mon'] = 'Mon',
- ['mor'] = 'Moroccan',
- ['mri'] = 'Maori',
- ['mth'] = 'Maithili',
- ['mts'] = 'Maltese',
- ['mun'] = 'Mundari',
- ['nag'] = 'Naga-Assamese',
- ['nan'] = 'Nanai',
- ['nas'] = 'Naskapi',
- ['ncr'] = 'N-Cree',
- ['ndb'] = 'Ndebele',
- ['ndg'] = 'Ndonga',
- ['nep'] = 'Nepali',
- ['new'] = 'Newari',
- ['ngr'] = 'Nagari',
- ['nhc'] = 'Norway House Cree',
- ['nis'] = 'Nisi',
- ['niu'] = 'Niuean',
- ['nkl'] = 'Nkole',
- ['nko'] = "N'ko",
- ['nld'] = 'Dutch',
- ['nog'] = 'Nogai',
- ['nor'] = 'Norwegian',
- ['nsm'] = 'Northern Sami',
- ['nta'] = 'Northern Tai',
- ['nto'] = 'Esperanto',
- ['nyn'] = 'Nynorsk',
- ['oci'] = 'Occitan',
- ['ocr'] = 'Oji-Cree',
- ['ojb'] = 'Ojibway',
- ['ori'] = 'Oriya',
- ['oro'] = 'Oromo',
- ['oss'] = 'Ossetian',
- ['paa'] = 'Palestinian Aramaic',
- ['pal'] = 'Pali',
- ['pan'] = 'Punjabi',
- ['pap'] = 'Palpa',
- ['pas'] = 'Pashto',
- ['pgr'] = 'Polytonic Greek',
- ['pil'] = 'Pilipino',
- ['plg'] = 'Palaung',
- ['plk'] = 'Polish',
- ['pro'] = 'Provencal',
- ['ptg'] = 'Portuguese',
- ['qin'] = 'Chin',
- ['raj'] = 'Rajasthani',
- ['rbu'] = 'Russian Buriat',
- ['rcr'] = 'R-Cree',
- ['ria'] = 'Riang',
- ['rms'] = 'Rhaeto-Romanic',
- ['rom'] = 'Romanian',
- ['roy'] = 'Romany',
- ['rsy'] = 'Rusyn',
- ['rua'] = 'Ruanda',
- ['rus'] = 'Russian',
- ['sad'] = 'Sadri',
- ['san'] = 'Sanskrit',
- ['sat'] = 'Santali',
- ['say'] = 'Sayisi',
- ['sek'] = 'Sekota',
- ['sel'] = 'Selkup',
- ['sgo'] = 'Sango',
- ['shn'] = 'Shan',
- ['sib'] = 'Sibe',
- ['sid'] = 'Sidamo',
- ['sig'] = 'Silte Gurage',
- ['sks'] = 'Skolt Sami',
- ['sky'] = 'Slovak',
- ['sla'] = 'Slavey',
- ['slv'] = 'Slovenian',
- ['sml'] = 'Somali',
- ['smo'] = 'Samoan',
- ['sna'] = 'Sena',
- ['snd'] = 'Sindhi',
- ['snh'] = 'Sinhalese',
- ['snk'] = 'Soninke',
- ['sog'] = 'Sodo Gurage',
- ['sot'] = 'Sotho',
- ['sqi'] = 'Albanian',
- ['srb'] = 'Serbian',
- ['srk'] = 'Saraiki',
- ['srr'] = 'Serer',
- ['ssl'] = 'South Slavey',
- ['ssm'] = 'Southern Sami',
- ['sur'] = 'Suri',
- ['sva'] = 'Svan',
- ['sve'] = 'Swedish',
- ['swa'] = 'Swadaya Aramaic',
- ['swk'] = 'Swahili',
- ['swz'] = 'Swazi',
- ['sxt'] = 'Sutu',
- ['syr'] = 'Syriac',
- ['tab'] = 'Tabasaran',
- ['taj'] = 'Tajiki',
- ['tam'] = 'Tamil',
- ['tat'] = 'Tatar',
- ['tcr'] = 'TH-Cree',
- ['tel'] = 'Telugu',
- ['tgn'] = 'Tongan',
- ['tgr'] = 'Tigre',
- ['tgy'] = 'Tigrinya',
- ['tha'] = 'Thai',
- ['tht'] = 'Tahitian',
- ['tib'] = 'Tibetan',
- ['tkm'] = 'Turkmen',
- ['tmn'] = 'Temne',
- ['tna'] = 'Tswana',
- ['tne'] = 'Tundra Nenets',
- ['tng'] = 'Tonga',
- ['tod'] = 'Todo',
- ['trk'] = 'Turkish',
- ['tsg'] = 'Tsonga',
- ['tua'] = 'Turoyo Aramaic',
- ['tul'] = 'Tulu',
- ['tuv'] = 'Tuvin',
- ['twi'] = 'Twi',
- ['udm'] = 'Udmurt',
- ['ukr'] = 'Ukrainian',
- ['urd'] = 'Urdu',
- ['usb'] = 'Upper Sorbian',
- ['uyg'] = 'Uyghur',
- ['uzb'] = 'Uzbek',
- ['ven'] = 'Venda',
- ['vit'] = 'Vietnamese',
- ['wa' ] = 'Wa',
- ['wag'] = 'Wagdi',
- ['wcr'] = 'West-Cree',
- ['wel'] = 'Welsh',
- ['wlf'] = 'Wolof',
- ['xbd'] = 'Tai Lue',
- ['xhs'] = 'Xhosa',
- ['yak'] = 'Yakut',
- ['yba'] = 'Yoruba',
- ['ycr'] = 'Y-Cree',
- ['yic'] = 'Yi Classic',
- ['yim'] = 'Yi Modern',
- ['zhh'] = 'Chinese Hong Kong',
- ['zhp'] = 'Chinese Phonetic',
- ['zhs'] = 'Chinese Simplified',
- ['zht'] = 'Chinese Traditional',
- ['znd'] = 'Zande',
- ['zul'] = 'Zulu'
-}
-
-local features = allocate {
- ['aalt'] = 'Access All Alternates',
- ['abvf'] = 'Above-Base Forms',
- ['abvm'] = 'Above-Base Mark Positioning',
- ['abvs'] = 'Above-Base Substitutions',
- ['afrc'] = 'Alternative Fractions',
- ['akhn'] = 'Akhands',
- ['blwf'] = 'Below-Base Forms',
- ['blwm'] = 'Below-Base Mark Positioning',
- ['blws'] = 'Below-Base Substitutions',
- ['c2pc'] = 'Petite Capitals From Capitals',
- ['c2sc'] = 'Small Capitals From Capitals',
- ['calt'] = 'Contextual Alternates',
- ['case'] = 'Case-Sensitive Forms',
- ['ccmp'] = 'Glyph Composition/Decomposition',
- ['cjct'] = 'Conjunct Forms',
- ['clig'] = 'Contextual Ligatures',
- ['cpsp'] = 'Capital Spacing',
- ['cswh'] = 'Contextual Swash',
- ['curs'] = 'Cursive Positioning',
- ['dflt'] = 'Default Processing',
- ['dist'] = 'Distances',
- ['dlig'] = 'Discretionary Ligatures',
- ['dnom'] = 'Denominators',
- ['dtls'] = 'Dotless Forms', -- math
- ['expt'] = 'Expert Forms',
- ['falt'] = 'Final glyph Alternates',
- ['fin2'] = 'Terminal Forms #2',
- ['fin3'] = 'Terminal Forms #3',
- ['fina'] = 'Terminal Forms',
- ['flac'] = 'Flattened Accents Over Capitals', -- math
- ['frac'] = 'Fractions',
- ['fwid'] = 'Full Width',
- ['half'] = 'Half Forms',
- ['haln'] = 'Halant Forms',
- ['halt'] = 'Alternate Half Width',
- ['hist'] = 'Historical Forms',
- ['hkna'] = 'Horizontal Kana Alternates',
- ['hlig'] = 'Historical Ligatures',
- ['hngl'] = 'Hangul',
- ['hojo'] = 'Hojo Kanji Forms',
- ['hwid'] = 'Half Width',
- ['init'] = 'Initial Forms',
- ['isol'] = 'Isolated Forms',
- ['ital'] = 'Italics',
- ['jalt'] = 'Justification Alternatives',
- ['jp04'] = 'JIS2004 Forms',
- ['jp78'] = 'JIS78 Forms',
- ['jp83'] = 'JIS83 Forms',
- ['jp90'] = 'JIS90 Forms',
- ['kern'] = 'Kerning',
- ['lfbd'] = 'Left Bounds',
- ['liga'] = 'Standard Ligatures',
- ['ljmo'] = 'Leading Jamo Forms',
- ['lnum'] = 'Lining Figures',
- ['locl'] = 'Localized Forms',
- ['mark'] = 'Mark Positioning',
- ['med2'] = 'Medial Forms #2',
- ['medi'] = 'Medial Forms',
- ['mgrk'] = 'Mathematical Greek',
- ['mkmk'] = 'Mark to Mark Positioning',
- ['mset'] = 'Mark Positioning via Substitution',
- ['nalt'] = 'Alternate Annotation Forms',
- ['nlck'] = 'NLC Kanji Forms',
- ['nukt'] = 'Nukta Forms',
- ['numr'] = 'Numerators',
- ['onum'] = 'Old Style Figures',
- ['opbd'] = 'Optical Bounds',
- ['ordn'] = 'Ordinals',
- ['ornm'] = 'Ornaments',
- ['palt'] = 'Proportional Alternate Width',
- ['pcap'] = 'Petite Capitals',
- ['pnum'] = 'Proportional Figures',
- ['pref'] = 'Pre-base Forms',
- ['pres'] = 'Pre-base Substitutions',
- ['pstf'] = 'Post-base Forms',
- ['psts'] = 'Post-base Substitutions',
- ['pwid'] = 'Proportional Widths',
- ['qwid'] = 'Quarter Widths',
- ['rand'] = 'Randomize',
- ['rkrf'] = 'Rakar Forms',
- ['rlig'] = 'Required Ligatures',
- ['rphf'] = 'Reph Form',
- ['rtbd'] = 'Right Bounds',
- ['rtla'] = 'Right-To-Left Alternates',
- ['rtlm'] = 'Right To Left Math', -- math
- ['ruby'] = 'Ruby Notation Forms',
- ['salt'] = 'Stylistic Alternates',
- ['sinf'] = 'Scientific Inferiors',
- ['size'] = 'Optical Size',
- ['smcp'] = 'Small Capitals',
- ['smpl'] = 'Simplified Forms',
- ['ss01'] = 'Stylistic Set 1',
- ['ss02'] = 'Stylistic Set 2',
- ['ss03'] = 'Stylistic Set 3',
- ['ss04'] = 'Stylistic Set 4',
- ['ss05'] = 'Stylistic Set 5',
- ['ss06'] = 'Stylistic Set 6',
- ['ss07'] = 'Stylistic Set 7',
- ['ss08'] = 'Stylistic Set 8',
- ['ss09'] = 'Stylistic Set 9',
- ['ss10'] = 'Stylistic Set 10',
- ['ss11'] = 'Stylistic Set 11',
- ['ss12'] = 'Stylistic Set 12',
- ['ss13'] = 'Stylistic Set 13',
- ['ss14'] = 'Stylistic Set 14',
- ['ss15'] = 'Stylistic Set 15',
- ['ss16'] = 'Stylistic Set 16',
- ['ss17'] = 'Stylistic Set 17',
- ['ss18'] = 'Stylistic Set 18',
- ['ss19'] = 'Stylistic Set 19',
- ['ss20'] = 'Stylistic Set 20',
- ['ssty'] = 'Script Style', -- math
- ['subs'] = 'Subscript',
- ['sups'] = 'Superscript',
- ['swsh'] = 'Swash',
- ['titl'] = 'Titling',
- ['tjmo'] = 'Trailing Jamo Forms',
- ['tnam'] = 'Traditional Name Forms',
- ['tnum'] = 'Tabular Figures',
- ['trad'] = 'Traditional Forms',
- ['twid'] = 'Third Widths',
- ['unic'] = 'Unicase',
- ['valt'] = 'Alternate Vertical Metrics',
- ['vatu'] = 'Vattu Variants',
- ['vert'] = 'Vertical Writing',
- ['vhal'] = 'Alternate Vertical Half Metrics',
- ['vjmo'] = 'Vowel Jamo Forms',
- ['vkna'] = 'Vertical Kana Alternates',
- ['vkrn'] = 'Vertical Kerning',
- ['vpal'] = 'Proportional Alternate Vertical Metrics',
- ['vrt2'] = 'Vertical Rotation',
- ['zero'] = 'Slashed Zero',
-
- ['trep'] = 'Traditional TeX Replacements',
- ['tlig'] = 'Traditional TeX Ligatures',
-}
-
-local baselines = allocate {
- ['hang'] = 'Hanging baseline',
- ['icfb'] = 'Ideographic character face bottom edge baseline',
- ['icft'] = 'Ideographic character face tope edige baseline',
- ['ideo'] = 'Ideographic em-box bottom edge baseline',
- ['idtp'] = 'Ideographic em-box top edge baseline',
- ['math'] = 'Mathmatical centered baseline',
- ['romn'] = 'Roman baseline'
-}
-
-
-local function swap(h) -- can be a tables.swap when we get a better name
- local r = { }
- for k, v in next, h do
- r[v] = lower(gsub(k," ",""))
- end
- return r
-end
-
-local verbosescripts = allocate(swap(scripts ))
-local verboselanguages = allocate(swap(languages))
-local verbosefeatures = allocate(swap(features ))
-
-tables.scripts = scripts
-tables.languages = languages
-tables.features = features
-tables.baselines = baselines
-
-tables.verbosescripts = verbosescripts
-tables.verboselanguages = verboselanguages
-tables.verbosefeatures = verbosefeatures
-
-for k, v in next, verbosefeatures do
- local stripped = gsub(k,"%-"," ")
- verbosefeatures[stripped] = v
- local stripped = gsub(k,"[^a-zA-Z0-9]","")
- verbosefeatures[stripped] = v
-end
-for k, v in next, verbosefeatures do
- verbosefeatures[lower(k)] = v
-end
-
-local function resolve(tab,id)
- if tab and id then
- id = lower(id)
- return tab[id] or tab[gsub(id," ","")] or tab['dflt'] or ''
- else
- return "unknown"
- end
+ return found
end
-function meanings.script (id) return resolve(scripts, id) end
-function meanings.language(id) return resolve(languages,id) end
-function meanings.feature (id) return resolve(features, id) end
-function meanings.baseline(id) return resolve(baselines,id) end
-
-local checkers = {
- rand = function(v)
- return v and "random"
- end
-}
-
-meanings.checkers = checkers
-
-function meanings.normalize(features)
- if features then
- local h = { }
- for k,v in next, features do
- k = lower(k)
- if k == "language" or k == "lang" then
- v = gsub(lower(v),"[^a-z0-9%-]","")
- if not languages[v] then
- h.language = verboselanguages[v] or "dflt"
- else
- h.language = v
- end
- elseif k == "script" then
- v = gsub(lower(v),"[^a-z0-9%-]","")
- if not scripts[v] then
- h.script = verbosescripts[v] or "dflt"
- else
- h.script = v
- end
- else
- if type(v) == "string" then
- local b = is_boolean(v)
- if type(b) == "nil" then
- v = tonumber(v) or lower(v)
- else
- v = b
- end
- end
- k = verbosefeatures[k] or k
- local c = checkers[k]
- h[k] = c and c(v) or v
- end
- end
- return h
- end
-end
-
--- When I feel the need ...
-
---~ tables.aat = {
---~ [ 0] = {
---~ name = "allTypographicFeaturesType",
---~ [ 0] = "allTypeFeaturesOnSelector",
---~ [ 1] = "allTypeFeaturesOffSelector",
---~ },
---~ [ 1] = {
---~ name = "ligaturesType",
---~ [0 ] = "requiredLigaturesOnSelector",
---~ [1 ] = "requiredLigaturesOffSelector",
---~ [2 ] = "commonLigaturesOnSelector",
---~ [3 ] = "commonLigaturesOffSelector",
---~ [4 ] = "rareLigaturesOnSelector",
---~ [5 ] = "rareLigaturesOffSelector",
---~ [6 ] = "logosOnSelector ",
---~ [7 ] = "logosOffSelector ",
---~ [8 ] = "rebusPicturesOnSelector",
---~ [9 ] = "rebusPicturesOffSelector",
---~ [10] = "diphthongLigaturesOnSelector",
---~ [11] = "diphthongLigaturesOffSelector",
---~ [12] = "squaredLigaturesOnSelector",
---~ [13] = "squaredLigaturesOffSelector",
---~ [14] = "abbrevSquaredLigaturesOnSelector",
---~ [15] = "abbrevSquaredLigaturesOffSelector",
---~ },
---~ [ 2] = {
---~ name = "cursiveConnectionType",
---~ [ 0] = "unconnectedSelector",
---~ [ 1] = "partiallyConnectedSelector",
---~ [ 2] = "cursiveSelector ",
---~ },
---~ [ 3] = {
---~ name = "letterCaseType",
---~ [ 0] = "upperAndLowerCaseSelector",
---~ [ 1] = "allCapsSelector ",
---~ [ 2] = "allLowerCaseSelector",
---~ [ 3] = "smallCapsSelector ",
---~ [ 4] = "initialCapsSelector",
---~ [ 5] = "initialCapsAndSmallCapsSelector",
---~ },
---~ [ 4] = {
---~ name = "verticalSubstitutionType",
---~ [ 0] = "substituteVerticalFormsOnSelector",
---~ [ 1] = "substituteVerticalFormsOffSelector",
---~ },
---~ [ 5] = {
---~ name = "linguisticRearrangementType",
---~ [ 0] = "linguisticRearrangementOnSelector",
---~ [ 1] = "linguisticRearrangementOffSelector",
---~ },
---~ [ 6] = {
---~ name = "numberSpacingType",
---~ [ 0] = "monospacedNumbersSelector",
---~ [ 1] = "proportionalNumbersSelector",
---~ },
---~ [ 7] = {
---~ name = "appleReserved1Type",
---~ },
---~ [ 8] = {
---~ name = "smartSwashType",
---~ [ 0] = "wordInitialSwashesOnSelector",
---~ [ 1] = "wordInitialSwashesOffSelector",
---~ [ 2] = "wordFinalSwashesOnSelector",
---~ [ 3] = "wordFinalSwashesOffSelector",
---~ [ 4] = "lineInitialSwashesOnSelector",
---~ [ 5] = "lineInitialSwashesOffSelector",
---~ [ 6] = "lineFinalSwashesOnSelector",
---~ [ 7] = "lineFinalSwashesOffSelector",
---~ [ 8] = "nonFinalSwashesOnSelector",
---~ [ 9] = "nonFinalSwashesOffSelector",
---~ },
---~ [ 9] = {
---~ name = "diacriticsType",
---~ [ 0] = "showDiacriticsSelector",
---~ [ 1] = "hideDiacriticsSelector",
---~ [ 2] = "decomposeDiacriticsSelector",
---~ },
---~ [10] = {
---~ name = "verticalPositionType",
---~ [ 0] = "normalPositionSelector",
---~ [ 1] = "superiorsSelector ",
---~ [ 2] = "inferiorsSelector ",
---~ [ 3] = "ordinalsSelector ",
---~ },
---~ [11] = {
---~ name = "fractionsType",
---~ [ 0] = "noFractionsSelector",
---~ [ 1] = "verticalFractionsSelector",
---~ [ 2] = "diagonalFractionsSelector",
---~ },
---~ [12] = {
---~ name = "appleReserved2Type",
---~ },
---~ [13] = {
---~ name = "overlappingCharactersType",
---~ [ 0] = "preventOverlapOnSelector",
---~ [ 1] = "preventOverlapOffSelector",
---~ },
---~ [14] = {
---~ name = "typographicExtrasType",
---~ [0 ] = "hyphensToEmDashOnSelector",
---~ [1 ] = "hyphensToEmDashOffSelector",
---~ [2 ] = "hyphenToEnDashOnSelector",
---~ [3 ] = "hyphenToEnDashOffSelector",
---~ [4 ] = "unslashedZeroOnSelector",
---~ [5 ] = "unslashedZeroOffSelector",
---~ [6 ] = "formInterrobangOnSelector",
---~ [7 ] = "formInterrobangOffSelector",
---~ [8 ] = "smartQuotesOnSelector",
---~ [9 ] = "smartQuotesOffSelector",
---~ [10] = "periodsToEllipsisOnSelector",
---~ [11] = "periodsToEllipsisOffSelector",
---~ },
---~ [15] = {
---~ name = "mathematicalExtrasType",
---~ [ 0] = "hyphenToMinusOnSelector",
---~ [ 1] = "hyphenToMinusOffSelector",
---~ [ 2] = "asteriskToMultiplyOnSelector",
---~ [ 3] = "asteriskToMultiplyOffSelector",
---~ [ 4] = "slashToDivideOnSelector",
---~ [ 5] = "slashToDivideOffSelector",
---~ [ 6] = "inequalityLigaturesOnSelector",
---~ [ 7] = "inequalityLigaturesOffSelector",
---~ [ 8] = "exponentsOnSelector",
---~ [ 9] = "exponentsOffSelector",
---~ },
---~ [16] = {
---~ name = "ornamentSetsType",
---~ [ 0] = "noOrnamentsSelector",
---~ [ 1] = "dingbatsSelector ",
---~ [ 2] = "piCharactersSelector",
---~ [ 3] = "fleuronsSelector ",
---~ [ 4] = "decorativeBordersSelector",
---~ [ 5] = "internationalSymbolsSelector",
---~ [ 6] = "mathSymbolsSelector",
---~ },
---~ [17] = {
---~ name = "characterAlternativesType",
---~ [ 0] = "noAlternatesSelector",
---~ },
---~ [18] = {
---~ name = "designComplexityType",
---~ [ 0] = "designLevel1Selector",
---~ [ 1] = "designLevel2Selector",
---~ [ 2] = "designLevel3Selector",
---~ [ 3] = "designLevel4Selector",
---~ [ 4] = "designLevel5Selector",
---~ },
---~ [19] = {
---~ name = "styleOptionsType",
---~ [ 0] = "noStyleOptionsSelector",
---~ [ 1] = "displayTextSelector",
---~ [ 2] = "engravedTextSelector",
---~ [ 3] = "illuminatedCapsSelector",
---~ [ 4] = "titlingCapsSelector",
---~ [ 5] = "tallCapsSelector ",
---~ },
---~ [20] = {
---~ name = "characterShapeType",
---~ [0 ] = "traditionalCharactersSelector",
---~ [1 ] = "simplifiedCharactersSelector",
---~ [2 ] = "jis1978CharactersSelector",
---~ [3 ] = "jis1983CharactersSelector",
---~ [4 ] = "jis1990CharactersSelector",
---~ [5 ] = "traditionalAltOneSelector",
---~ [6 ] = "traditionalAltTwoSelector",
---~ [7 ] = "traditionalAltThreeSelector",
---~ [8 ] = "traditionalAltFourSelector",
---~ [9 ] = "traditionalAltFiveSelector",
---~ [10] = "expertCharactersSelector",
---~ },
---~ [21] = {
---~ name = "numberCaseType",
---~ [ 0] = "lowerCaseNumbersSelector",
---~ [ 1] = "upperCaseNumbersSelector",
---~ },
---~ [22] = {
---~ name = "textSpacingType",
---~ [ 0] = "proportionalTextSelector",
---~ [ 1] = "monospacedTextSelector",
---~ [ 2] = "halfWidthTextSelector",
---~ [ 3] = "normallySpacedTextSelector",
---~ },
---~ [23] = {
---~ name = "transliterationType",
---~ [ 0] = "noTransliterationSelector",
---~ [ 1] = "hanjaToHangulSelector",
---~ [ 2] = "hiraganaToKatakanaSelector",
---~ [ 3] = "katakanaToHiraganaSelector",
---~ [ 4] = "kanaToRomanizationSelector",
---~ [ 5] = "romanizationToHiraganaSelector",
---~ [ 6] = "romanizationToKatakanaSelector",
---~ [ 7] = "hanjaToHangulAltOneSelector",
---~ [ 8] = "hanjaToHangulAltTwoSelector",
---~ [ 9] = "hanjaToHangulAltThreeSelector",
---~ },
---~ [24] = {
---~ name = "annotationType",
---~ [ 0] = "noAnnotationSelector",
---~ [ 1] = "boxAnnotationSelector",
---~ [ 2] = "roundedBoxAnnotationSelector",
---~ [ 3] = "circleAnnotationSelector",
---~ [ 4] = "invertedCircleAnnotationSelector",
---~ [ 5] = "parenthesisAnnotationSelector",
---~ [ 6] = "periodAnnotationSelector",
---~ [ 7] = "romanNumeralAnnotationSelector",
---~ [ 8] = "diamondAnnotationSelector",
---~ },
---~ [25] = {
---~ name = "kanaSpacingType",
---~ [ 0] = "fullWidthKanaSelector",
---~ [ 1] = "proportionalKanaSelector",
---~ },
---~ [26] = {
---~ name = "ideographicSpacingType",
---~ [ 0] = "fullWidthIdeographsSelector",
---~ [ 1] = "proportionalIdeographsSelector",
---~ },
---~ [103] = {
---~ name = "cjkRomanSpacingType",
---~ [ 0] = "halfWidthCJKRomanSelector",
---~ [ 1] = "proportionalCJKRomanSelector",
---~ [ 2] = "defaultCJKRomanSelector",
---~ [ 3] = "fullWidthCJKRomanSelector",
---~ },
---~ }
-
end -- closure
do -- begin closure to overcome local limits and interference
@@ -5375,15 +4263,18 @@ if not modules then modules = { } end modules ['font-map'] = {
license = "see context related readme files"
}
-local utf = unicode.utf8
local match, format, find, concat, gsub, lower = string.match, string.format, string.find, table.concat, string.gsub, string.lower
-local lpegmatch = lpeg.match
+local P, R, S, C, Ct, Cc, lpegmatch = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Ct, lpeg.Cc, lpeg.match
local utfbyte = utf.byte
-local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
-local trace_unimapping = false trackers.register("otf.unimapping", function(v) trace_unimapping = v end)
+local trace_loading = false trackers.register("fonts.loading", function(v) trace_loading = v end)
+local trace_mapping = false trackers.register("fonts.mapping", function(v) trace_unimapping = v end)
-local report_otf = logs.reporter("fonts","otf loading")
+local report_fonts = logs.reporter("fonts","loading") -- not otf only
+
+local fonts = fonts
+local mappings = { }
+fonts.mappings = mappings
--[[ldx--
<p>Eventually this code will disappear because map files are kind
@@ -5391,23 +4282,18 @@ of obsolete. Some code may move to runtime or auxiliary modules.</p>
<p>The name to unciode related code will stay of course.</p>
--ldx]]--
-local fonts = fonts
-fonts.map = fonts.map or { }
-
local function loadlumtable(filename) -- will move to font goodies
local lumname = file.replacesuffix(file.basename(filename),"lum")
local lumfile = resolvers.findfile(lumname,"map") or ""
if lumfile ~= "" and lfs.isfile(lumfile) then
- if trace_loading or trace_unimapping then
- report_otf("enhance: loading %s ",lumfile)
+ if trace_loading or trace_mapping then
+ report_fonts("enhance: loading %s ",lumfile)
end
lumunic = dofile(lumfile)
return lumunic, lumfile
end
end
-local P, R, S, C, Ct, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Ct, lpeg.Cc
-
local hex = R("AF","09")
local hexfour = (hex*hex*hex*hex) / function(s) return tonumber(s,16) end
local hexsix = (hex^1) / function(s) return tonumber(s,16) end
@@ -5434,8 +4320,8 @@ local function makenameparser(str)
end
end
---~ local parser = fonts.map.makenameparser("Japan1")
---~ local parser = fonts.map.makenameparser()
+--~ local parser = mappings.makenameparser("Japan1")
+--~ local parser = mappings.makenameparser()
--~ local function test(str)
--~ local b, a = lpegmatch(parser,str)
--~ print((a and table.serialize(b)) or b)
@@ -5476,7 +4362,7 @@ end
--~
--~ local cache = { }
--~
---~ function fonts.map.tounicode16(unicode)
+--~ function mappings.tounicode16(unicode)
--~ local s = cache[unicode]
--~ if not s then
--~ if unicode < 0x10000 then
@@ -5489,10 +4375,10 @@ end
--~ return s
--~ end
-fonts.map.loadlumtable = loadlumtable
-fonts.map.makenameparser = makenameparser
-fonts.map.tounicode16 = tounicode16
-fonts.map.tounicode16sequence = tounicode16sequence
+mappings.loadlumtable = loadlumtable
+mappings.makenameparser = makenameparser
+mappings.tounicode16 = tounicode16
+mappings.tounicode16sequence = tounicode16sequence
local separator = S("_.")
local other = C((1 - separator)^1)
@@ -5504,8 +4390,11 @@ local ligsplitter = Ct(other * (separator * other)^0)
--~ print(table.serialize(lpegmatch(ligsplitter,"such_so_more")))
--~ print(table.serialize(lpegmatch(ligsplitter,"such_so_more.that")))
-fonts.map.addtounicode = function(data,filename)
- local unicodes = data.luatex and data.luatex.unicodes
+function mappings.addtounicode(data,filename)
+ local resources = data.resources
+ local properties = data.properties
+ local descriptions = data.descriptions
+ local unicodes = resources.unicodes
if not unicodes then
return
end
@@ -5515,28 +4404,35 @@ fonts.map.addtounicode = function(data,filename)
unicodes['zwj'] = unicodes['zwj'] or 0x200D
unicodes['zwnj'] = unicodes['zwnj'] or 0x200C
-- the tounicode mapping is sparse and only needed for alternatives
- local tounicode, originals, ns, nl, private, unknown = { }, { }, 0, 0, fonts.privateoffset, format("%04X",utfbyte("?"))
- data.luatex.tounicode, data.luatex.originals = tounicode, originals
+ local private = fonts.constructors.privateoffset
+ local unknown = format("%04X",utfbyte("?"))
+ local unicodevector = fonts.encodings.agl.unicodes -- loaded runtime in context
+ local tounicode = { }
+ local originals = { }
+ resources.tounicode = tounicode
+ resources.originals = originals
local lumunic, uparser, oparser
+ local cidinfo, cidnames, cidcodes, usedmap
if false then -- will become an option
lumunic = loadlumtable(filename)
lumunic = lumunic and lumunic.tounicode
end
- local cidinfo, cidnames, cidcodes = data.cidinfo
- local usedmap = cidinfo and cidinfo.usedname
- usedmap = usedmap and lower(usedmap)
- usedmap = usedmap and fonts.cid.map[usedmap]
+ --
+ cidinfo = properties.cidinfo
+ usedmap = cidinfo and fonts.cid.getmap(cidinfo)
+ --
if usedmap then
- oparser = usedmap and makenameparser(cidinfo.ordering)
+ oparser = usedmap and makenameparser(cidinfo.ordering)
cidnames = usedmap.names
cidcodes = usedmap.unicodes
end
uparser = makenameparser()
- local unicodevector = fonts.enc.agl.unicodes -- loaded runtime in context
- for index, glyph in next, data.glyphs do
- local name, unic = glyph.name, glyph.unicode or -1 -- play safe
+ local ns, nl = 0, 0
+ for unic, glyph in next, descriptions do
+ local index = glyph.index
+ local name = glyph.name
if unic == -1 or unic >= private or (unic >= 0xE000 and unic <= 0xF8FF) or unic == 0xFFFE or unic == 0xFFFF then
- local unicode = (lumunic and lumunic[name]) or unicodevector[name]
+ local unicode = lumunic and lumunic[name] or unicodevector[name]
if unicode then
originals[index], tounicode[index], ns = unicode, tounicode16(unicode), ns + 1
end
@@ -5627,18 +4523,20 @@ fonts.map.addtounicode = function(data,filename)
end
end
end
- if trace_unimapping then
- for index, glyph in table.sortedhash(data.glyphs) do
- local toun, name, unic = tounicode[index], glyph.name, glyph.unicode or -1 -- play safe
+ if trace_mapping then
+ for unic, glyph in table.sortedhash(descriptions) do
+ local name = glyph.name
+ local index = glyph.index
+ local toun = tounicode[index]
if toun then
- report_otf("internal: 0x%05X, name: %s, unicode: 0x%05X, tounicode: %s",index,name,unic,toun)
+ report_fonts("internal: 0x%05X, name: %s, unicode: 0x%05X, tounicode: %s",index,name,unic,toun)
else
- report_otf("internal: 0x%05X, name: %s, unicode: 0x%05X",index,name,unic)
+ report_fonts("internal: 0x%05X, name: %s, unicode: 0x%05X",index,name,unic)
end
end
end
if trace_loading and (ns > 0 or nl > 0) then
- report_otf("enhance: %s tounicode entries added (%s ligatures)",nl+ns, ns)
+ report_fonts("enhance: %s tounicode entries added (%s ligatures)",nl+ns, ns)
end
end
@@ -5646,52 +4544,230 @@ end -- closure
do -- begin closure to overcome local limits and interference
-if not modules then modules = { } end modules ['font-lua'] = {
+if not modules then modules = { } end modules ['luatex-fonts-syn'] = {
version = 1.001,
- comment = "companion to font-ini.mkiv",
+ comment = "companion to luatex-*.tex",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
}
-local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
+if context then
+ texio.write_nl("fatal error: this module is not for context")
+ os.exit()
+end
-local report_lua = logs.reporter("fonts","lua loading")
+-- Generic font names support.
+--
+-- Watch out, the version number is the same as the one used in
+-- the mtx-fonts.lua function scripts.fonts.names as we use a
+-- simplified font database in the plain solution and by using
+-- a different number we're less dependent on context.
+--
+-- mtxrun --script font --reload --simple
+--
+-- The format of the file is as follows:
+--
+-- return {
+-- ["version"] = 1.001,
+-- ["mappings"] = {
+-- ["somettcfontone"] = { "Some TTC Font One", "SomeFontA.ttc", 1 },
+-- ["somettcfonttwo"] = { "Some TTC Font Two", "SomeFontA.ttc", 2 },
+-- ["somettffont"] = { "Some TTF Font", "SomeFontB.ttf" },
+-- ["someotffont"] = { "Some OTF Font", "SomeFontC.otf" },
+-- },
+-- }
-fonts.formats.lua = "lua"
+local fonts = fonts
+fonts.names = fonts.names or { }
-local readers = fonts.tfm.readers
+fonts.names.version = 1.001 -- not the same as in context
+fonts.names.basename = "luatex-fonts-names.lua"
+fonts.names.new_to_old = { }
+fonts.names.old_to_new = { }
-local function check_lua(specification,fullname)
- -- standard tex file lookup
- local fullname = resolvers.findfile(fullname) or ""
- if fullname ~= "" then
- local loader = loadfile(fullname)
- loader = loader and loader()
- return loader and loader(specification)
+local data, loaded = nil, false
+
+local fileformats = { "lua", "tex", "other text files" }
+
+function fonts.names.resolve(name,sub)
+ if not loaded then
+ local basename = fonts.names.basename
+ if basename and basename ~= "" then
+ for i=1,#fileformats do
+ local format = fileformats[i]
+ local foundname = resolvers.findfile(basename,format) or ""
+ if foundname ~= "" then
+ data = dofile(foundname)
+ texio.write("<font database loaded: ",foundname,">")
+ break
+ end
+ end
+ end
+ loaded = true
+ end
+ if type(data) == "table" and data.version == fonts.names.version then
+ local condensed = string.gsub(string.lower(name),"[^%a%d]","")
+ local found = data.mappings and data.mappings[condensed]
+ if found then
+ local fontname, filename, subfont = found[1], found[2], found[3]
+ if subfont then
+ return filename, fontname
+ else
+ return filename, false
+ end
+ else
+ return name, false -- fallback to filename
+ end
end
end
-function readers.lua(specification)
- local original = specification.specification
- if trace_defining then
- report_lua("using lua reader for '%s'",original)
- end
- local fullname, tfmtable = specification.filename or "", nil
+fonts.names.resolvespec = fonts.names.resolve -- only supported in mkiv
+
+function fonts.names.getfilename(askedname,suffix) -- only supported in mkiv
+ return ""
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['luatex-fonts-tfm'] = {
+ version = 1.001,
+ comment = "companion to luatex-*.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+if context then
+ texio.write_nl("fatal error: this module is not for context")
+ os.exit()
+end
+
+local fonts = fonts
+local tfm = { }
+fonts.handlers.tfm = tfm
+fonts.formats.tfm = "type1" -- we need to have at least a value here
+
+function fonts.readers.tfm(specification)
+ local fullname = specification.filename or ""
if fullname == "" then
local forced = specification.forced or ""
if forced ~= "" then
- tfmtable = check_lua(specification,specification.name .. "." .. forced)
+ fullname = specification.name .. "." .. forced
+ else
+ fullname = specification.name
+ end
+ end
+ local foundname = resolvers.findbinfile(fullname, 'tfm') or ""
+ if foundname == "" then
+ foundname = resolvers.findbinfile(fullname, 'ofm') or ""
+ end
+ if foundname ~= "" then
+ specification.filename = foundname
+ specification.format = "ofm"
+ return font.read_tfm(specification.filename,specification.size)
+ end
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['font-oti'] = {
+ 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 lower = string.lower
+
+local allocate = utilities.storage.allocate
+
+local fonts = fonts
+local otf = { }
+fonts.handlers.otf = otf
+
+local otffeatures = fonts.constructors.newfeatures("otf")
+local registerotffeature = otffeatures.register
+
+registerotffeature {
+ name = "features",
+ description = "initialization of feature handler",
+ default = true,
+}
+
+-- these are later hooked into node and base initializaters
+
+local otftables = otf.tables -- not always defined
+
+local function setmode(tfmdata,value)
+ if value then
+ tfmdata.properties.mode = lower(value)
+ end
+end
+
+local function setlanguage(tfmdata,value)
+ if value then
+ local cleanvalue = lower(value)
+ local languages = otftables and otftables.languages
+ local properties = tfmdata.properties
+ if not languages then
+ properties.language = cleanvalue
+ elseif languages[value] then
+ properties.language = cleanvalue
+ else
+ properties.language = "dflt"
end
- if not tfmtable then
- tfmtable = check_lua(specification,specification.name)
+ end
+end
+
+local function setscript(tfmdata,value)
+ if value then
+ local cleanvalue = lower(value)
+ local scripts = otftables and otftables.scripts
+ local properties = tfmdata.properties
+ if not scripts then
+ properties.script = cleanvalue
+ elseif scripts[value] then
+ properties.script = cleanvalue
+ else
+ properties.script = "dflt"
end
- else
- tfmtable = check_lua(specification,fullname)
end
- return tfmtable
end
+registerotffeature {
+ name = "mode",
+ description = "mode",
+ initializers = {
+ base = setmode,
+ node = setmode,
+ }
+}
+
+registerotffeature {
+ name = "language",
+ description = "language",
+ initializers = {
+ base = setlanguage,
+ node = setlanguage,
+ }
+}
+
+registerotffeature {
+ name = "script",
+ description = "script",
+ initializers = {
+ base = setscript,
+ node = setscript,
+ }
+}
+
+
end -- closure
do -- begin closure to overcome local limits and interference
@@ -5708,6 +4784,7 @@ if not modules then modules = { } end modules ['font-otf'] = {
-- anchor_classes vs kernclasses
-- modification/creationtime in subfont is runtime dus zinloos
-- to_table -> totable
+-- ascent descent
local utf = unicode.utf8
@@ -5717,93 +4794,71 @@ local type, next, tonumber, tostring = type, next, tonumber, tostring
local abs = math.abs
local getn = table.getn
local lpegmatch = lpeg.match
-local reversed, concat = table.reversed, table.concat
+local reversed, concat, remove = table.reversed, table.concat, table.remove
local ioflush = io.flush
+local fastcopy = table.fastcopy
+
+local allocate = utilities.storage.allocate
+local registertracker = trackers.register
+local registerdirective = directives.register
+local starttiming = statistics.starttiming
+local stoptiming = statistics.stoptiming
+local elapsedtime = statistics.elapsedtime
+local findbinfile = resolvers.findbinfile
+
+local trace_private = false registertracker("otf.private", function(v) trace_private = v end)
+local trace_loading = false registertracker("otf.loading", function(v) trace_loading = v end)
+local trace_features = false registertracker("otf.features", function(v) trace_features = v end)
+local trace_dynamics = false registertracker("otf.dynamics", function(v) trace_dynamics = v end)
+local trace_sequences = false registertracker("otf.sequences", function(v) trace_sequences = v end)
+local trace_markwidth = false registertracker("otf.markwidth", function(v) trace_markwidth = v end)
+local trace_defining = false registertracker("fonts.defining", function(v) trace_defining = v end)
+
+local report_otf = logs.reporter("fonts","otf loading")
-local allocate = utilities.storage.allocate
-
-local trace_private = false trackers.register("otf.private", function(v) trace_private = v end)
-local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
-local trace_features = false trackers.register("otf.features", function(v) trace_features = v end)
-local trace_dynamics = false trackers.register("otf.dynamics", function(v) trace_dynamics = v end)
-local trace_sequences = false trackers.register("otf.sequences", function(v) trace_sequences = v end)
-local trace_math = false trackers.register("otf.math", function(v) trace_math = v end)
-local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
-
-local report_otf = logs.reporter("fonts","otf loading")
-
-local starttiming, stoptiming, elapsedtime = statistics.starttiming, statistics.stoptiming, statistics.elapsedtime
-
-local findbinfile = resolvers.findbinfile
-
-local fonts = fonts
-
-fonts.otf = fonts.otf or { }
-local otf = fonts.otf
-local tfm = fonts.tfm
-
-local fontdata = fonts.identifiers
-local chardata = characters and characters.data -- not used
-
--- todo: probably first time so local first
-
-otf.features = otf.features or { }
-local features = otf.features
-features.list = features.list or { }
-local featurelist = features.list
-features.default = features.default or { }
-local defaultfeatures = features.default
-
-otf.enhancers = allocate()
-local enhancers = otf.enhancers
-enhancers.patches = { }
-local patches = enhancers.patches
-
-local definers = fonts.definers
-local readers = fonts.tfm.readers
+local fonts = fonts
+local otf = fonts.handlers.otf
-otf.glists = { "gsub", "gpos" }
+otf.glists = { "gsub", "gpos" }
-otf.version = 2.710 -- beware: also sync font-mis.lua
-otf.cache = containers.define("fonts", "otf", otf.version, true)
+otf.version = 2.710 -- beware: also sync font-mis.lua
+otf.cache = containers.define("fonts", "otf", otf.version, true)
-local loadmethod = "table" -- table, mixed, sparse
-local forceload = false
-local cleanup = 0
-local usemetatables = false -- .4 slower on mk but 30 M less mem so we might change the default -- will be directive
-local packdata = true
-local syncspace = true
-local forcenotdef = false
+local fontdata = fonts.hashes.identifiers
+local chardata = characters and characters.data -- not used
-local wildcard = "*"
-local default = "dflt"
+local otffeatures = fonts.constructors.newfeatures("otf")
+local registerotffeature = otffeatures.register
-local fontloaderfields = fontloader.fields
-local mainfields = nil
-local glyphfields = nil -- not used yet
+local enhancers = allocate()
+otf.enhancers = enhancers
+local patches = { }
+enhancers.patches = patches
-directives.register("fonts.otf.loader.method", function(v)
- if v == "sparse" and fontloaderfields then
- loadmethod = "sparse"
- elseif v == "mixed" then
- loadmethod = "mixed"
- elseif v == "table" then
- loadmethod = "table"
- else
- loadmethod = "table"
- report_otf("no loader method '%s', using '%s' instead",v,loadmethod)
- end
-end)
-
-directives.register("fonts.otf.loader.cleanup",function(v)
- cleanup = tonumber(v) or (v and 1) or 0
-end)
-
-directives.register("fonts.otf.loader.force", function(v) forceload = v end)
-directives.register("fonts.otf.loader.usemetatables", function(v) usemetatables = v end)
-directives.register("fonts.otf.loader.pack", function(v) packdata = v end)
-directives.register("fonts.otf.loader.syncspace", function(v) syncspace = v end)
-directives.register("fonts.otf.loader.forcenotdef", function(v) forcenotdef = v end)
+local definers = fonts.definers
+local readers = fonts.readers
+local constructors = fonts.constructors
+
+local forceload = false
+local cleanup = 0 -- mk: 0=885M 1=765M 2=735M (regular run 730M)
+local usemetatables = false -- .4 slower on mk but 30 M less mem so we might change the default -- will be directive
+local packdata = true
+local syncspace = true
+local forcenotdef = false
+
+local wildcard = "*"
+local default = "dflt"
+
+local fontloaderfields = fontloader.fields
+local mainfields = nil
+local glyphfields = nil -- not used yet
+
+registerdirective("fonts.otf.loader.cleanup", function(v) cleanup = tonumber(v) or (v and 1) or 0 end)
+registerdirective("fonts.otf.loader.force", function(v) forceload = v end)
+registerdirective("fonts.otf.loader.usemetatables", function(v) usemetatables = v end)
+registerdirective("fonts.otf.loader.pack", function(v) packdata = v end)
+registerdirective("fonts.otf.loader.syncspace", function(v) syncspace = v end)
+registerdirective("fonts.otf.loader.forcenotdef", function(v) forcenotdef = v end)
local function load_featurefile(raw,featurefile)
if featurefile and featurefile ~= "" then
@@ -5814,19 +4869,19 @@ local function load_featurefile(raw,featurefile)
end
end
-local function showfeatureorder(otfdata,filename)
- local sequences = otfdata.luatex.sequences
+local function showfeatureorder(rawdata,filename)
+ local sequences = rawdata.resources.sequences
if sequences and #sequences > 0 then
if trace_loading then
report_otf("font %s has %s sequences",filename,#sequences)
report_otf(" ")
end
for nos=1,#sequences do
- local sequence = sequences[nos]
- local typ = sequence.type or "no-type"
- local name = sequence.name or "no-name"
+ local sequence = sequences[nos]
+ local typ = sequence.type or "no-type"
+ local name = sequence.name or "no-name"
local subtables = sequence.subtables or { "no-subtables" }
- local features = sequence.features
+ local features = sequence.features
if trace_loading then
report_otf("%3i %-15s %-20s [%s]",nos,name,typ,concat(subtables,","))
end
@@ -5858,25 +4913,6 @@ end
<p>We start with a lot of tables and related functions.</p>
--ldx]]--
-local global_fields = table.tohash {
- "metadata",
- "lookups",
- "glyphs",
- "subfonts",
- "luatex",
- "pfminfo",
- "cidinfo",
- "tables",
- "names",
- "unicodes",
- "names",
- -- "math",
- "anchor_classes",
- "kern_classes",
- "gpos",
- "gsub"
-}
-
local valid_fields = table.tohash {
-- "anchor_classes",
"ascent",
@@ -5892,32 +4928,32 @@ local valid_fields = table.tohash {
"extrema_bound",
"familyname",
"fontname",
+ "fontname",
"fontstyle_id",
"fontstyle_name",
"fullname",
-- "glyphs",
"hasvmetrics",
- "head_optimized_for_cleartype",
+ -- "head_optimized_for_cleartype",
"horiz_base",
"issans",
"isserif",
"italicangle",
-- "kerns",
-- "lookups",
- -- "luatex",
"macstyle",
-- "modificationtime",
"onlybitmaps",
"origname",
"os2_version",
- -- "pfminfo",
+ "pfminfo",
-- "private",
"serifcheck",
"sfd_version",
-- "size",
"strokedfont",
"strokewidth",
- "subfonts",
+ -- "subfonts",
"table_version",
-- "tables",
-- "ttf_tab_saved",
@@ -5929,7 +4965,6 @@ local valid_fields = table.tohash {
"use_typo_metrics",
"uwidth",
-- "validation_state",
- "verbose",
"version",
"vert_base",
"weight",
@@ -5956,43 +4991,47 @@ local ordered_enhancers = {
"reorganize glyph lookups",
"reorganize glyph anchors",
+ "merge kern classes",
+
"reorganize features",
"reorganize subtables",
"check glyphs",
"check metadata",
- "check math parameters",
"check extra features", -- after metadata
+
+ "cleanup tables",
}
--[[ldx--
<p>Here we go.</p>
--ldx]]--
-local actions = { }
+local actions = allocate()
+local before = allocate()
+local after = allocate()
-patches.before = allocate()
-patches.after = allocate()
+patches.before = before
+patches.after = after
-local before = patches.before
-local after = patches.after
-
-local function enhance(name,data,filename,raw,verbose)
+local function enhance(name,data,filename,raw)
local enhancer = actions[name]
if enhancer then
- if verbose then
+ if trace_loading then
report_otf("enhance: %s (%s)",name,filename)
ioflush()
end
enhancer(data,filename,raw)
- else
- report_otf("enhance: %s is undefined",name)
+ elseif trace_loading then
+ -- report_otf("enhance: %s is undefined",name)
end
end
-function enhancers.apply(data,filename,raw,verbose)
+function enhancers.apply(data,filename,raw)
local basename = file.basename(lower(filename))
- report_otf("start enhancing: %s",filename)
+ if trace_loading then
+ report_otf("start enhancing: %s",filename)
+ end
ioflush() -- we want instant messages
for e=1,#ordered_enhancers do
local enhancer = ordered_enhancers[e]
@@ -6004,7 +5043,7 @@ function enhancers.apply(data,filename,raw,verbose)
end
end
end
- enhance(enhancer,data,filename,raw,verbose)
+ enhance(enhancer,data,filename,raw)
local a = after[enhancer]
if a then
for pattern, action in next, a do
@@ -6015,7 +5054,9 @@ function enhancers.apply(data,filename,raw,verbose)
end
ioflush() -- we want instant messages
end
- report_otf("stop enhancing")
+ if trace_loading then
+ report_otf("stop enhancing")
+ end
ioflush() -- we want instant messages
end
@@ -6043,11 +5084,14 @@ end
function otf.load(filename,format,sub,featurefile)
local name = file.basename(file.removesuffix(filename))
local attr = lfs.attributes(filename)
- local size, time = attr and attr.size or 0, attr and attr.modification or 0
+ local size = attr and attr.size or 0
+ local time = attr and attr.modification or 0
if featurefile then
name = name .. "@" .. file.removesuffix(file.basename(featurefile))
end
- if sub == "" then sub = false end
+ if sub == "" then
+ sub = false
+ end
local hash = name
if sub then
hash = hash .. "-" .. sub
@@ -6064,8 +5108,8 @@ function otf.load(filename,format,sub,featurefile)
local attr = lfs.attributes(name)
featurefiles[#featurefiles+1] = {
name = name,
- size = attr.size or 0,
- time = attr.modification or 0,
+ size = size,
+ time = time,
}
end
end
@@ -6074,7 +5118,7 @@ function otf.load(filename,format,sub,featurefile)
end
end
local data = containers.read(otf.cache,hash)
- local reload = not data or data.verbose ~= fonts.verbose or data.size ~= size or data.time ~= time
+ local reload = not data or data.size ~= size or data.time ~= time
if forceload then
report_otf("loading: forced reload due to hard coded flag")
reload = true
@@ -6102,7 +5146,7 @@ function otf.load(filename,format,sub,featurefile)
end
if reload then
report_otf("loading: %s (hash: %s)",filename,hash)
- local fontdata, messages, rawdata
+ local fontdata, messages
if sub then
fontdata, messages = fontloader.open(filename,sub)
else
@@ -6128,51 +5172,66 @@ function otf.load(filename,format,sub,featurefile)
load_featurefile(fontdata,featurefiles[i].name)
end
end
- report_otf("loading method: %s",loadmethod)
- if loadmethod == "sparse" then
- rawdata = fontdata
- else
- rawdata = fontloader.to_table(fontdata)
- fontloader.close(fontdata)
- end
- if rawdata then
- data = { }
- starttiming(data)
- local verboseindeed = verbose ~= nil and verbose or trace_loading
- report_otf("file size: %s", size)
- enhancers.apply(data,filename,rawdata,verboseindeed)
- if packdata and not fonts.verbose then
- enhance("pack",data,filename,nil,verboseindeed)
- end
- data.size = size
- data.time = time
- data.format = format
- if featurefiles then
- data.featuredata = featurefiles
- end
- data.verbose = fonts.verbose
- report_otf("saving in cache: %s",filename)
- data = containers.write(otf.cache, hash, data)
+ local unicodes = {
+ -- names to unicodes
+ }
+ local splitter = lpeg.splitter(" ",unicodes)
+ data = {
+ size = size,
+ time = time,
+ format = format,
+ featuredata = featurefiles,
+ resources = {
+ filename = resolvers.unresolve(filename), -- no shortcut
+ version = otf.version,
+ creator = "context mkiv",
+ unicodes = unicodes,
+ indices = {
+ -- unicodes to names
+ },
+ lookuptypes = {
+ },
+ },
+ metadata = {
+ -- raw metadata, not to be used
+ },
+ properties = {
+ -- normalized metadata
+ },
+ descriptions = {
+ },
+ goodies = {
+ },
+ helpers = {
+ tounicodelist = splitter,
+ tounicodetable = lpeg.Ct(splitter),
+ },
+ }
+ starttiming(data)
+ report_otf("file size: %s", size)
+ enhancers.apply(data,filename,fontdata)
+ if packdata then
if cleanup > 0 then
collectgarbage("collect")
end
- stoptiming(data)
- if elapsedtime then -- not in generic
- report_otf("preprocessing and caching took %s seconds",elapsedtime(data))
- end
- data = containers.read(otf.cache, hash) -- this frees the old table and load the sparse one
- if cleanup > 1 then
- collectgarbage("collect")
- end
- else
- data = nil
- report_otf("loading failed (table conversion error)")
+ enhance("pack",data,filename,nil)
end
- if loadmethod == "sparse" then
- fontloader.close(fontdata)
- if cleanup > 2 then
- -- collectgarbage("collect")
- end
+ report_otf("saving in cache: %s",filename)
+ data = containers.write(otf.cache, hash, data)
+ if cleanup > 1 then
+ collectgarbage("collect")
+ end
+ stoptiming(data)
+ if elapsedtime then -- not in generic
+ report_otf("preprocessing and caching took %s seconds",elapsedtime(data))
+ end
+ fontloader.close(fontdata) -- free memory
+ if cleanup > 3 then
+ collectgarbage("collect")
+ end
+ data = containers.read(otf.cache, hash) -- this frees the old table and load the sparse one
+ if cleanup > 2 then
+ collectgarbage("collect")
end
else
data = nil
@@ -6208,35 +5267,42 @@ local mt = {
end
}
+actions["prepare tables"] = function(data,filename,raw)
+ data.properties.italic_correction = false
+end
+
actions["add dimensions"] = function(data,filename)
-- todo: forget about the width if it's the defaultwidth (saves mem)
-- we could also build the marks hash here (instead of storing it)
if data then
- local luatex = data.luatex
- local defaultwidth = luatex.defaultwidth or 0
- local defaultheight = luatex.defaultheight or 0
- local defaultdepth = luatex.defaultdepth or 0
+ local descriptions = data.descriptions
+ local resources = data.resources
+ local defaultwidth = resources.defaultwidth or 0
+ local defaultheight = resources.defaultheight or 0
+ local defaultdepth = resources.defaultdepth or 0
if usemetatables then
- for _, d in next, data.glyphs do
+ for _, d in next, descriptions do
local wd = d.width
if not wd then
d.width = defaultwidth
- elseif wd ~= 0 and d.class == "mark" then
- d.width = -wd
+ elseif trace_markwidth and wd ~= 0 and d.class == "mark" then
+ report_otf("mark with width %s (%s) in %s",wd,d.name or "<noname>",file.basename(filename))
+ -- d.width = -wd
end
setmetatable(d,mt)
end
else
- for _, d in next, data.glyphs do
+ for _, d in next, descriptions do
local bb, wd = d.boundingbox, d.width
if not wd then
d.width = defaultwidth
- elseif wd ~= 0 and d.class == "mark" then
- d.width = -wd
- end
- if forcenotdef and not d.name then
- d.name = ".notdef"
+ elseif trace_markwidth and wd ~= 0 and d.class == "mark" then
+ report_otf("mark with width %s (%s) in %s",wd,d.name or "<noname>",file.basename(filename))
+ -- d.width = -wd
end
+ -- if forcenotdef and not d.name then
+ -- d.name = ".notdef"
+ -- end
if bb then
local ht, dp = bb[4], -bb[2]
if ht == 0 or ht < 0 then
@@ -6255,16 +5321,6 @@ actions["add dimensions"] = function(data,filename)
end
end
-actions["prepare tables"] = function(data,filename,raw)
- local luatex = {
- filename = resolvers.unresolve(filename), -- no shortcut
- version = otf.version,
- creator = "context mkiv",
- }
- data.luatex = luatex
- data.metadata = { }
-end
-
local function somecopy(old) -- fast one
if old then
local new = { }
@@ -6301,192 +5357,220 @@ end
-- table cronstruction can save some mem
actions["prepare glyphs"] = function(data,filename,raw)
- -- we can also move the names to data.luatex.names which might
- -- save us some more memory (at the cost of harder tracing)
- local rawglyphs = raw.glyphs
- local glyphs, udglyphs
- if loadmethod == "sparse" then
- glyphs, udglyphs = { }, { }
- elseif loadmethod == "mixed" then
- glyphs, udglyphs = { }, rawglyphs
- else
- glyphs, udglyphs = rawglyphs, rawglyphs
- end
- data.glyphs, data.udglyphs = glyphs, udglyphs
- local subfonts = raw.subfonts
- if subfonts then
- if data.glyphs and next(data.glyphs) then
- report_otf("replacing existing glyph table due to subfonts")
- end
- local cidinfo = raw.cidinfo
- if cidinfo.registry then
- local cidmap, cidname = fonts.cid.getmap(cidinfo.registry,cidinfo.ordering,cidinfo.supplement)
+ local rawglyphs = raw.glyphs
+ local rawsubfonts = raw.subfonts
+ local rawcidinfo = raw.cidinfo
+ local criterium = constructors.privateoffset
+ local private = criterium
+ local resources = data.resources
+ local metadata = data.metadata
+ local properties = data.properties
+ local descriptions = data.descriptions
+ local unicodes = resources.unicodes -- name to unicode
+ local indices = resources.indices -- index to unicode
+
+ if rawsubfonts then
+
+ metadata.subfonts = { }
+ properties.cidinfo = rawcidinfo
+
+ if rawcidinfo.registry then
+ local cidmap = fonts.cid.getmap(rawcidinfo)
if cidmap then
- cidinfo.usedname = cidmap.usedname
- local uni_to_int, int_to_uni, nofnames, nofunicodes = { }, { }, 0, 0
- local unicodes, names = cidmap.unicodes, cidmap.names
- for cidindex=1,#subfonts do
- local subfont = subfonts[cidindex]
- if loadmethod == "sparse" then
- local rawglyphs = subfont.glyphs
- for index=0,subfont.glyphmax - 1 do
- local g = rawglyphs[index]
- if g then
- local unicode, name = unicodes[index], names[index]
- if unicode then
- uni_to_int[unicode] = index
- int_to_uni[index] = unicode
- nofunicodes = nofunicodes + 1
- elseif name then
- nofnames = nofnames + 1
- end
- udglyphs[index] = g
- glyphs[index] = {
- width = g.width,
- italic = g.italic_correction,
- boundingbox = g.boundingbox,
- class = g.class,
- name = g.name or name or "unknown", -- uniXXXX
- cidindex = cidindex,
- unicode = unicode,
- }
+ rawcidinfo.usedname = cidmap.usedname
+ local nofnames, nofunicodes = 0, 0
+ local cidunicodes, cidnames = cidmap.unicodes, cidmap.names
+ for cidindex=1,#rawsubfonts do
+ local subfont = rawsubfonts[cidindex]
+ local cidglyphs = subfont.glyphs
+ metadata.subfonts[cidindex] = somecopy(subfont)
+ for index=0,subfont.glyphmax - 1 do
+ local glyph = cidglyphs[index]
+ if glyph then
+ local unicode = glyph.unicode
+ local name = glyph.name or cidnames[index]
+ if not unicode or unicode == -1 or unicode >= criterium then
+ unicode = cidunicodes[index]
end
- end
- -- If we had more userdata, we would need more of this
- -- and it would start working against us in terms of
- -- convenience and speed.
- subfont = somecopy(subfont)
- subfont.glyphs = nil
- subfont[cidindex] = subfont
- elseif loadmethod == "mixed" then
- for index, g in next, subfont.glyphs do
- local unicode, name = unicodes[index], names[index]
- if unicode then
- uni_to_int[unicode] = index
- int_to_uni[index] = unicode
- nofunicodes = nofunicodes + 1
- elseif name then
+ if not unicode or unicode == -1 or unicode >= criterium then
+ if not name then
+ name = format("u%06X",private)
+ end
+ unicode = private
+ unicodes[name] = private
+ if trace_private then
+ report_otf("enhance: glyph %s at index U+%04X is moved to private unicode slot U+%04X",name,index,private)
+ end
+ private = private + 1
nofnames = nofnames + 1
+ else
+ if not name then
+ name = format("u%06X",unicode)
+ end
+ unicodes[name] = unicode
+ nofunicodes = nofunicodes + 1
end
- udglyphs[index] = g
- glyphs[index] = {
- width = g.width,
- italic = g.italic_correction,
- boundingbox = g.boundingbox,
- class = g.class,
- name = g.name or name or "unknown", -- uniXXXX
+ indices[unicode] = index -- each index in unique (at least now)
+
+ local description = {
+ -- width = glyph.width,
+ boundingbox = glyph.boundingbox,
+ name = glyph.name or name or "unknown", -- uniXXXX
cidindex = cidindex,
- unicode = unicode,
+ index = index,
+ glyph = glyph,
}
+
+ descriptions[unicode] = description
end
- subfont.glyphs = nil
- else
- for index, g in next, subfont.glyphs do
- local unicode, name = unicodes[index], names[index]
- if unicode then
- uni_to_int[unicode] = index
- int_to_uni[index] = unicode
- nofunicodes = nofunicodes + 1
- g.unicode = unicode
- elseif name then
- nofnames = nofnames + 1
- end
- g.cidindex = cidindex
- glyphs[index] = g
- end
- subfont.glyphs = nil
end
end
if trace_loading then
report_otf("cid font remapped, %s unicode points, %s symbolic names, %s glyphs",nofunicodes, nofnames, nofunicodes+nofnames)
end
- data.map = data.map or { }
- data.map.map = uni_to_int
- data.map.backmap = int_to_uni
elseif trace_loading then
report_otf("unable to remap cid font, missing cid file for %s",filename)
end
- data.subfonts = subfonts
elseif trace_loading then
report_otf("font %s has no glyphs",filename)
end
+
else
- if loadmethod == "sparse" then
- -- we get fields from the userdata glyph table and create
- -- a minimal entry first
- for index=0,raw.glyphmax - 1 do
- local g = rawglyphs[index]
- if g then
- udglyphs[index] = g
- glyphs[index] = {
- width = g.width,
- italic = g.italic_correction,
- boundingbox = g.boundingbox,
- class = g.class,
- name = g.name,
- unicode = g.unicode,
- }
+
+ for index=0,raw.glyphmax-1 do
+ local glyph = rawglyphs[index]
+ if glyph then
+ local unicode = glyph.unicode
+ local name = glyph.name
+ if not unicode or unicode == -1 or unicode >= criterium then
+ unicode = private
+ unicodes[name] = private
+ if trace_private then
+ report_otf("enhance: glyph %s at index U+%04X is moved to private unicode slot U+%04X",name,index,private)
+ end
+ private = private + 1
+ else
+ unicodes[name] = unicode
end
- end
- elseif loadmethod == "mixed" then
- -- we get fields from the totable glyph table and copy to the
- -- final glyph table so first we create a minimal entry
- for index, g in next, rawglyphs do
- udglyphs[index] = g
- glyphs[index] = {
- width = g.width,
- italic = g.italic_correction,
- boundingbox = g.boundingbox,
- class = g.class,
- name = g.name,
- unicode = g.unicode,
+ indices[unicode] = index
+ if not name then
+ name = format("u%06X",unicode)
+ end
+
+ descriptions[unicode] = {
+ -- width = glyph.width,
+ boundingbox = glyph.boundingbox,
+ name = name,
+ index = index,
+ glyph = glyph,
}
end
- else
- -- we use the totable glyph table directly and manipulate the
- -- entries in this (also final) table
end
- data.map = raw.map
+
end
- data.cidinfo = raw.cidinfo -- hack
+
+ resources.private = private
+
end
--- watch copy of cidinfo: we can best make some more copies to data
+-- the next one is still messy but will get better when we have
+-- flattened map/enc tables in the font loader
+
+actions["prepare unicodes"] = function(data,filename,raw)
+ local descriptions = data.descriptions
+ local resources = data.resources
+ local properties = data.properties
+ local unicodes = resources.unicodes -- name to unicode
+ local indices = resources.indices -- index to unicodes
+
+ -- begin of messy (not needed whwn cidmap)
+
+ local mapdata = raw.map or { }
+ local unicodetoindex = mapdata and mapdata.map or { }
+ -- local encname = lower(data.enc_name or raw.enc_name or mapdata.enc_name or "")
+ local encname = lower(data.enc_name or mapdata.enc_name or "")
+ local criterium = 0xFFFF -- for instance cambria has a lot of mess up there
+
+ -- end of messy
+
+ if find(encname,"unicode") then -- unicodebmp, unicodefull, ...
+ if trace_loading then
+ report_otf("using embedded unicode map '%s'",encname)
+ end
+ local multiples, nofmultiples = { }, 0
+ for unicode, index in next, unicodetoindex do
+ if unicode <= criterium and not descriptions[unicode] then
+ local parent = indices[index]
+ local description = descriptions[parent]
+ if description then
+ local c = fastcopy(description)
+ c.comment = format("copy of 0x%04X", parent)
+ descriptions[unicode] = c
+ local name = c.name
+ if not unicodes[name] then
+ unicodes[name] = unicode
+ end
+ nofmultiples = nofmultiples + 1
+ multiples[nofmultiples] = name -- we can save duplicates if needed
+ else
+ -- make it a notdef
+ report_otf("weird unicode 0x%04X at index 0x%04X",unicode,index)
+ end
+ end
+ end
+ if trace_loading then
+ if nofmultiples > 0 then
+ report_otf("%s glyphs are reused: %s",nofmultiples,concat(multiples," "))
+ else
+ report_otf("no glyphs are reused")
+ end
+ end
+ elseif properties.cidinfo then
+ report_otf("warning: no unicode map, used cidmap '%s'",properties.cidinfo.usedname or "?")
+ else
+ report_otf("warning: non unicode map '%s', only using glyph unicode data",encname or "whatever")
+ end
+
+ if mapdata then
+ mapdata.map = { } -- clear some memory
+ end
+end
+
+-- class : nil base mark ligature component (maybe we don't need it in description)
+-- boundingbox: split into ht/dp takes more memory (larger tables and less sharing)
actions["analyze glyphs"] = function(data,filename,raw) -- maybe integrate this in the previous
- local glyphs = data.glyphs
- -- collect info
- local has_italic, widths, marks = false, { }, { }
- for index, glyph in next, glyphs do
- local italic = glyph.italic_correction
+ local descriptions = data.descriptions
+ local resources = data.resources
+ local metadata = data.metadata
+ local properties = data.properties
+ local italic_correction = false
+ local widths = { }
+ local marks = { }
+ for unicode, description in next, descriptions do
+ local glyph = description.glyph
if not italic then
-- skip
elseif italic == 0 then
- glyph.italic_correction = nil
- glyph.italic = nil
+ -- skip
else
- glyph.italic_correction = nil
- glyph.italic = italic
- has_italic = true
+ description.italic = italic
+ italic_correction = true
end
local width = glyph.width
widths[width] = (widths[width] or 0) + 1
local class = glyph.class
- local unicode = glyph.unicode
- if class == "mark" then
- marks[unicode] = true
- -- elseif chardata[unicode].category == "mn" then
- -- marks[unicode] = true
- -- glyph.class = "mark"
+ if class then
+ if class == "mark" then
+ marks[unicode] = true
+ end
+ description.class = class
end
- local a = glyph.altuni if a then glyph.altuni = nil end
- local d = glyph.dependents if d then glyph.dependents = nil end
- local v = glyph.vwidth if v then glyph.vwidth = nil end
end
-- flag italic
- data.metadata.has_italic = has_italic
+ properties.italic_correction = italic_correction
-- flag marks
- data.luatex.marks = marks
+ resources.marks = marks
-- share most common width for cjk fonts
local wd, most = 0, 1
for k,v in next, widths do
@@ -6498,43 +5582,41 @@ actions["analyze glyphs"] = function(data,filename,raw) -- maybe integrate this
if trace_loading then
report_otf("most common width: %s (%s times), sharing (cjk font)",wd,most)
end
- for index, glyph in next, glyphs do
- if glyph.width == wd then
- glyph.width = nil
+ for unicode, description in next, descriptions do
+ if description.width == wd then
+ -- description.width = nil
+ else
+ description.width = description.glyph.width
end
end
- data.luatex.defaultwidth = wd
+ resources.defaultwidth = wd
+ else
+ for unicode, description in next, descriptions do
+ description.width = description.glyph.width
+ end
end
end
actions["reorganize mark classes"] = function(data,filename,raw)
local mark_classes = raw.mark_classes
if mark_classes then
- local luatex = data.luatex
- local unicodes = luatex.unicodes
- local reverse = { }
- luatex.markclasses = reverse
+ local resources = data.resources
+ local unicodes = resources.unicodes
+ local markclasses = { }
+ resources.markclasses = markclasses -- reversed
for name, class in next, mark_classes do
local t = { }
for s in gmatch(class,"[^ ]+") do
- local us = unicodes[s]
- if type(us) == "table" then
- for u=1,#us do
- t[us[u]] = true
- end
- else
- t[us] = true
- end
+ t[unicodes[s]] = true
end
- reverse[name] = t
+ markclasses[name] = t
end
- data.mark_classes = nil -- when using table
end
end
actions["reorganize features"] = function(data,filename,raw) -- combine with other
local features = { }
- data.luatex.features = features
+ data.resources.features = features
for k, what in next, otf.glists do
local dw = raw[what]
if dw then
@@ -6547,7 +5629,11 @@ actions["reorganize features"] = function(data,filename,raw) -- combine with oth
for i=1,#dfeatures do
local df = dfeatures[i]
local tag = strip(lower(df.tag))
- local ft = f[tag] if not ft then ft = {} f[tag] = ft end
+ local ft = f[tag]
+ if not ft then
+ ft = { }
+ f[tag] = ft
+ end
local dscripts = df.scripts
for i=1,#dscripts do
local d = dscripts[i]
@@ -6566,25 +5652,34 @@ actions["reorganize features"] = function(data,filename,raw) -- combine with oth
end
actions["reorganize anchor classes"] = function(data,filename,raw)
- local classes = raw.anchor_classes -- anchor classes not in final table
- local luatex = data.luatex
- local anchor_to_lookup, lookup_to_anchor = { }, { }
- luatex.anchor_to_lookup, luatex.lookup_to_anchor = anchor_to_lookup, lookup_to_anchor
+ local resources = data.resources
+ local anchor_to_lookup = { }
+ local lookup_to_anchor = { }
+ resources.anchor_to_lookup = anchor_to_lookup
+ resources.lookup_to_anchor = lookup_to_anchor
+ local classes = raw.anchor_classes -- anchor classes not in final table
if classes then
for c=1,#classes do
- local class = classes[c]
- local anchor = class.name
+ local class = classes[c]
+ local anchor = class.name
local lookups = class.lookup
if type(lookups) ~= "table" then
lookups = { lookups }
end
local a = anchor_to_lookup[anchor]
- if not a then a = { } anchor_to_lookup[anchor] = a end
+ if not a then
+ a = { }
+ anchor_to_lookup[anchor] = a
+ end
for l=1,#lookups do
local lookup = lookups[l]
local l = lookup_to_anchor[lookup]
- if not l then l = { } lookup_to_anchor[lookup] = l end
- l[anchor] = true
+ if l then
+ l[anchor] = true
+ else
+ l = { [anchor] = true }
+ lookup_to_anchor[lookup] = l
+ end
a[lookup] = true
end
end
@@ -6592,13 +5687,16 @@ actions["reorganize anchor classes"] = function(data,filename,raw)
end
actions["prepare tounicode"] = function(data,filename,raw)
- fonts.map.addtounicode(data,filename)
+ fonts.mappings.addtounicode(data,filename)
end
actions["reorganize subtables"] = function(data,filename,raw)
- local luatex = data.luatex
- local sequences, lookups = { }, { }
- luatex.sequences, luatex.lookups = sequences, lookups
+ local resources = data.resources
+ local sequences = { }
+ local lookups = { }
+ local chainedfeatures = { }
+ resources.sequences = sequences
+ resources.lookups = lookups
for _, what in next, otf.glists do
local dw = raw[what]
if dw then
@@ -6613,9 +5711,7 @@ actions["reorganize subtables"] = function(data,filename,raw)
if subtables then
local t = { }
for s=1,#subtables do
- local subtable = subtables[s]
- local name = subtable.name
- t[#t+1] = name
+ t[s] = subtables[s].name
end
subtables = t
end
@@ -6629,7 +5725,7 @@ actions["reorganize subtables"] = function(data,filename,raw)
}
markclass = flags.mark_class
if markclass then
- markclass = luatex.markclasses[markclass]
+ markclass = resources.markclasses[markclass]
end
flags = t
end
@@ -6678,138 +5774,165 @@ actions["reorganize subtables"] = function(data,filename,raw)
end
end
--- the next one is still messy but will get better when we have
--- flattened map/enc tables in the font loader
+-- test this:
+--
+-- for _, what in next, otf.glists do
+-- raw[what] = nil
+-- end
-actions["prepare unicodes"] = function(data,filename,raw)
- local luatex = data.luatex
- local indices, unicodes, multiples, internals= { }, { }, { }, { }
- local mapdata = data.map or raw.map -- map already moved
- local mapmap
- if not mapdata then
- report_otf("no mapdata in '%s'",filename)
- mapmap = { }
- mapdata = { map = mapmap }
- data.map = mapdata
- elseif not mapdata.map then
- report_otf("no map in mapdata of '%s'",filename)
- mapmap = { }
- mapdata.map = mapmap
- else
- mapmap = mapdata.map
- end
- local encname = lower(data.enc_name or raw.enc_name or mapdata.enc_name or "")
- local criterium = fonts.privateoffset
- local private = criterium
- local glyphs = data.glyphs
- -- todo: nofmultiples
- for index, glyph in next, glyphs do
- if index > 0 then
- local name = glyph.name -- really needed ?
- if name then
- local unicode = glyph.unicode
- if not unicode or unicode == -1 or unicode >= criterium then
- glyph.unicode = private
- indices[private] = index
- unicodes[name] = private
- internals[index] = true
- if trace_private then
- report_otf("enhance: glyph %s at index U+%04X is moved to private unicode slot U+%04X",name,index,private)
- end
- private = private + 1
- else
- indices[unicode] = index
- unicodes[name] = unicode
- end
- -- maybe deal with altuni here in the future but first we need
- -- to encounter a proper font that sets them; we have to wait till
- -- a next luatex binary as currently the unicode numbers can be out
- -- of bounds
- if false then
- local altuni = glyph.altuni
- if altuni then
- local un = { unicodes[name] }
- for i=1,#altuni do
- local unicode = altuni[i].unicode
- multiples[#multiples+1] = name
- un[i+1] = unicode
- indices[unicode] = index -- maybe check for duplicates
- end
- unicodes[name] = un
- end
- end
- else
- -- message that something is wrong
- end
- end
- end
- -- beware: the indices table is used to initialize the tfm table
- if find(encname,"unicode") then -- unicodebmp, unicodefull, ...
- if trace_loading then
- report_otf("using embedded unicode map '%s'",encname)
- end
- -- ok -- we can also consider using the altuni
- for unicode, index in next, mapmap do
- if not internals[index] then
- local name = glyphs[index].name
- if name then
- local un = unicodes[name]
- if not un then
- unicodes[name] = unicode -- or 0
- elseif type(un) == "number" then -- tonumber(un)
- if un ~= unicode then
- multiples[#multiples+1] = name
- unicodes[name] = { un, unicode }
- indices[unicode] = index
- end
- else
- local ok = false
- for u=1,#un do
- if un[u] == unicode then
- ok = true
- break
- end
- end
- if not ok then
- multiples[#multiples+1] = name
- un[#un+1] = unicode
- indices[unicode] = index
- end
- end
- end
- end
- end
- else
- report_otf("warning: non unicode map '%s', only using glyph unicode data",encname or "whatever")
+actions["prepare lookups"] = function(data,filename,raw)
+ local lookups = raw.lookups
+ if lookups then
+ data.lookups = lookups
end
- if trace_loading then
- if #multiples > 0 then
- report_otf("%s glyphs are reused: %s",#multiples, concat(multiples," "))
- else
- report_otf("no glyphs are reused")
+end
+
+local function t_uncover(splitter,cache,covers)
+ local result = { }
+ for n=1,#covers do
+ local cover = covers[n]
+ local uncovered = cache[cover]
+ if not uncovered then
+ uncovered = lpegmatch(splitter,cover)
+ cache[cover] = uncovered
end
+ result[n] = uncovered
end
- luatex.indices = indices
- luatex.unicodes = unicodes
- luatex.private = private
+ return result
end
-actions["prepare lookups"] = function(data,filename,raw)
- local lookups = raw.lookups
- if lookups then
- data.lookups = lookups
+local function s_uncover(splitter,cache,cover)
+ if cover == "" then
+ return nil
+ else
+ local uncovered = cache[cover]
+ if not uncovered then
+ uncovered = lpegmatch(splitter,cover)
+ cache[cover] = uncovered
+ end
+ return uncovered
end
end
actions["reorganize lookups"] = function(data,filename,raw)
-- we prefer the before lookups in a normal order
if data.lookups then
- for _, v in next, data.lookups do
- if v.rules then
- for _, vv in next, v.rules do
- local c = vv.coverage
- if c and c.before then
- c.before = reversed(c.before)
+ local splitter = data.helpers.tounicodetable
+ local cache = { }
+ for _, lookup in next, data.lookups do
+ local rules = lookup.rules
+ if rules then
+ local format = lookup.format
+ if format == "class" then
+ local before_class = lookup.before_class
+ if before_class then
+ before_class = t_uncover(splitter,cache,reversed(before_class))
+ end
+ local current_class = lookup.current_class
+ if current_class then
+ current_class = t_uncover(splitter,cache,current_class)
+ end
+ local after_class = lookup.after_class
+ if after_class then
+ after_class = t_uncover(splitter,cache,after_class)
+ end
+ for i=1,#rules do
+ local rule = rules[i]
+ local class = rule.class
+ local before = class.before
+ if before then
+ for i=1,#before do
+ before[i] = before_class[before[i]] or { }
+ end
+ rule.before = before
+ end
+ local current = class.current
+ local lookups = rule.lookups
+ if current then
+ for i=1,#current do
+ current[i] = current_class[current[i]] or { }
+ if lookups and not lookups[i] then
+ lookups[i] = false
+ end
+ end
+ rule.current = current
+ end
+ local after = class.after
+ if after then
+ for i=1,#after do
+ after[i] = after_class[after[i]] or { }
+ end
+ rule.after = after
+ end
+ rule.class = nil
+ end
+ lookup.before_class = nil
+ lookup.current_class = nil
+ lookup.after_class = nil
+ lookup.format = "coverage"
+ elseif format == "coverage" then
+ for i=1,#rules do
+ local rule = rules[i]
+ local coverage = rule.coverage
+ if coverage then
+ local before = coverage.before
+ if before then
+ rule.before = t_uncover(splitter,cache,reversed(before))
+ end
+ local current = coverage.current
+ if current then
+ rule.current = t_uncover(splitter,cache,current)
+ end
+ local after = coverage.after
+ if after then
+ rule.after = t_uncover(splitter,cache,after)
+ end
+ rule.coverage = nil
+ end
+ end
+ elseif format == "reversecoverage" then
+ for i=1,#rules do
+ local rule = rules[i]
+ local reversecoverage = rule.reversecoverage
+ if reversecoverage then
+ local before = reversecoverage.before
+ if before then
+ rule.before = t_uncover(splitter,cache,reversed(before))
+ end
+ local current = reversecoverage.current
+ if current then
+ rule.current = t_uncover(splitter,cache,current)
+ end
+ local after = reversecoverage.after
+ if after then
+ rule.after = t_uncover(splitter,cache,after)
+ end
+ local replacements = reversecoverage.replacements
+ if replacements then
+ rule.replacements = s_uncover(splitter,cache,replacements)
+ end
+ rule.reversecoverage = nil
+ end
+ end
+ elseif format == "glyphs" then
+ for i=1,#rules do
+ local rule = rules[i]
+ local glyphs = rule.glyphs
+ if glyphs then
+ local fore = glyphs.fore
+ if fore then
+ rule.fore = s_uncover(splitter,cache,fore)
+ end
+ local back = glyphs.back
+ if back then
+ rule.back = s_uncover(splitter,cache,back)
+ end
+ local names = glyphs.names
+ if names then
+ rule.names = s_uncover(splitter,cache,names)
+ end
+ rule.glyphs = nil
+ end
end
end
end
@@ -6817,144 +5940,152 @@ actions["reorganize lookups"] = function(data,filename,raw)
end
end
+-- to be checked italic_correction
+
actions["analyze math"] = function(data,filename,raw)
if raw.math then
-data.metadata.math = raw.math
- -- we move the math stuff into a math subtable because we then can
- -- test faster in the tfm copy
- local glyphs, udglyphs = data.glyphs, data.udglyphs
- local unicodes = data.luatex.unicodes
- for index, udglyph in next, udglyphs do
- local mk = udglyph.mathkern
- local hv = udglyph.horiz_variants
- local vv = udglyph.vert_variants
- if mk or hv or vv then
- local glyph = glyphs[index]
+ data.metadata.math = raw.math
+ local unicodes = data.resources.unicodes
+ local splitter = data.helpers.tounicodetable
+ for unicode, description in next, data.descriptions do
+ local glyph = description.glyph
+ local mathkerns = glyph.mathkern -- singular
+ local horiz_variants = glyph.horiz_variants
+ local vert_variants = glyph.vert_variants
+ local top_accent = glyph.top_accent
+ if mathkerns or horiz_variants or vert_variants or top_accent then
local math = { }
- glyph.math = math
- if mk then
- for k, v in next, mk do
+ if top_accent then
+ math.top_accent = top_accent
+ end
+ if mathkerns then
+ for k, v in next, mathkerns do
if not next(v) then
- mk[k] = nil
+ mathkerns[k] = nil
+ else
+ for k, v in next, v do
+ if v == 0 then
+ k[v] = nil -- height / kern can be zero
+ end
+ end
end
end
- math.kerns = mk
+ math.kerns = mathkerns
end
- if hv then
- math.horiz_variants = hv.variants
- local p = hv.parts
- if p and #p > 0 then
- for i=1,#p do
- local pi = p[i]
+ if horiz_variants then
+ local variants = horiz_variants.variants
+ if variants then -- use splitter
+ local glyphs = lpegmatch(splitter,variants)
+ for i=1,#glyphs do
+ if glyphs[i] == u then
+ remove(glyphs,i)
+ break
+ end
+ end
+ math.horiz_variants = glyphs
+ end
+ local parts = horiz_variants.parts
+ if parts and #parts > 0 then
+ for i=1,#parts do
+ local pi = parts[i]
pi.glyph = unicodes[pi.component] or 0
+ pi.component = nil
end
- math.horiz_parts = p
+ math.horiz_parts = parts
end
- local ic = hv.italic_correction
- if ic and ic ~= 0 then
- math.horiz_italic_correction = ic
+ local italic_correction = horiz_variants.italic_correction
+ if italic_correction and italic_correction ~= 0 then
+ math.horiz_italic_correction = italic_correction
end
end
- if vv then
- local uc = unicodes[index]
- math.vert_variants = vv.variants
- local p = vv.parts
- if p and #p > 0 then
- for i=1,#p do
- local pi = p[i]
+ if vert_variants then
+ local variants = vert_variants.variants
+ if variants then
+ local glyphs = lpegmatch(splitter,variants)
+ for i=1,#glyphs do
+ if glyphs[i] == u then
+ remove(glyphs,i)
+ break
+ end
+ end
+ math.vert_variants = glyphs
+ end
+ local p = vert_variants.parts
+ if parts and #parts > 0 then
+ for i=1,#parts do
+ local pi = parts[i]
pi.glyph = unicodes[pi.component] or 0
+ pi.component = nil
end
- math.vert_parts = p
+ math.vert_parts = parts
end
- local ic = vv.italic_correction
- if ic and ic ~= 0 then
- math.vert_italic_correction = ic
+ local italic_correction = vert_variants.italic_correction
+ if italic_correction and italic_correction ~= 0 then
+ math.vert_italic_correction = italic_correction
end
end
- local ic = glyph.italic_correction
- if ic then
- if ic ~= 0 then
- math.italic_correction = ic
- end
+ local italic_correction = description.italic
+ if italic_correction and italic_correction ~= 0 then
+ math.italic_correction = italic_correction
end
+ description.math = math
end
end
end
end
actions["reorganize glyph kerns"] = function(data,filename,raw)
- local luatex = data.luatex
- local udglyphs, glyphs, mapmap, unicodes = data.udglyphs, data.glyphs, luatex.indices, luatex.unicodes
- local mkdone = false
- local function do_it(lookup,first_unicode,extrakerns) -- can be moved inline but seldom used
- local glyph = glyphs[mapmap[first_unicode]]
- if glyph then
- local kerns = glyph.kerns
- if not kerns then
- kerns = { } -- unicode indexed !
- glyph.kerns = kerns
- end
- local lookupkerns = kerns[lookup]
- if not lookupkerns then
- lookupkerns = { }
- kerns[lookup] = lookupkerns
- end
- for second_unicode, kern in next, extrakerns do
- lookupkerns[second_unicode] = kern
- end
- elseif trace_loading then
- report_otf("no glyph data for U+%04X", first_unicode)
- end
- end
- for index, udglyph in next, data.udglyphs do
- local kerns = udglyph.kerns
+ local descriptions = data.descriptions
+ local resources = data.resources
+ local unicodes = resources.unicodes
+ for unicode, description in next, descriptions do
+ local kerns = description.glyph.kerns
if kerns then
- local glyph = glyphs[index]
local newkerns = { }
- for k,v in next, kerns do
- local vc, vo, vl = v.char, v.off, v.lookup
- if vc and vo and vl then -- brrr, wrong! we miss the non unicode ones
- local uvc = unicodes[vc]
- if not uvc then
- if trace_loading then
- report_otf("problems with unicode %s of kern %s at glyph %s",vc,k,index)
- end
- else
- if type(vl) ~= "table" then
- vl = { vl }
- end
- for l=1,#vl do
- local vll = vl[l]
- local mkl = newkerns[vll]
- if not mkl then
- mkl = { }
- newkerns[vll] = mkl
- end
- if type(uvc) == "table" then
- for u=1,#uvc do
- mkl[uvc[u]] = vo
+ for k, kern in next, kerns do
+ local name = kern.char
+ local offset = kern.off
+ local lookup = kern.lookup
+ if name and offset and lookup then
+ local unicode = unicodes[name]
+ if unicode then
+ if type(lookup) == "table" then
+ for l=1,#lookup do
+ local lookup = lookup[l]
+ local lookupkerns = newkerns[lookup]
+ if lookupkerns then
+ lookupkerns[unicode] = offset
+ else
+ newkerns[lookup] = { [unicode] = offset }
end
+ end
+ else
+ local lookupkerns = newkerns[lookup]
+ if lookupkerns then
+ lookupkerns[unicode] = offset
else
- mkl[uvc] = vo
+ newkerns[lookup] = { [unicode] = offset }
end
end
+ elseif trace_loading then
+ report_otf("problems with unicode %s of kern %s of glyph 0x%04X",name,k,unicode)
end
end
end
- glyph.kerns = newkerns -- udglyph.kerns = nil when in mixed mode
- mkdone = true
+ description.kerns = newkerns
end
end
- if trace_loading and mkdone then
- report_otf("replacing 'kerns' tables by a new 'kerns' tables")
- end
- local dgpos = raw.gpos
- if dgpos then
- local separator = lpeg.P(" ")
- local other = ((1 - separator)^0) / unicodes
- local splitter = lpeg.Ct(other * (separator * other)^0)
- for gp=1,#dgpos do
- local gpos = dgpos[gp]
+end
+
+actions["merge kern classes"] = function(data,filename,raw)
+ local gposlist = raw.gpos
+ if gposlist then
+ local descriptions = data.descriptions
+ local resources = data.resources
+ local unicodes = resources.unicodes
+ local splitter = data.helpers.tounicodetable
+ for gp=1,#gposlist do
+ local gpos = gposlist[gp]
local subtables = gpos.subtables
if subtables then
for s=1,#subtables do
@@ -6964,56 +6095,71 @@ actions["reorganize glyph kerns"] = function(data,filename,raw)
local split = { } -- saves time
for k=1,#kernclass do
local kcl = kernclass[k]
- local firsts, seconds, offsets, lookups = kcl.firsts, kcl.seconds, kcl.offsets, kcl.lookup -- singular
+ local firsts = kcl.firsts
+ local seconds = kcl.seconds
+ local offsets = kcl.offsets
+ local lookups = kcl.lookup -- singular
if type(lookups) ~= "table" then
lookups = { lookups }
end
- local maxfirsts, maxseconds = getn(firsts), getn(seconds)
- -- here we could convert split into a list of unicodes which is a bit
- -- faster but as this is only done when caching it does not save us much
- for _, s in next, firsts do
+ -- we can check the max in the loop
+ -- local maxseconds = getn(seconds)
+ for n, s in next, firsts do
split[s] = split[s] or lpegmatch(splitter,s)
end
- for _, s in next, seconds do
+ local maxseconds = 0
+ for n, s in next, seconds do
+ if n > maxseconds then
+ maxseconds = n
+ end
split[s] = split[s] or lpegmatch(splitter,s)
end
for l=1,#lookups do
local lookup = lookups[l]
- for fk=1,#firsts do
+ for fk=1,#firsts do -- maxfirsts ?
local fv = firsts[fk]
local splt = split[fv]
if splt then
- local kerns, baseoffset = { }, (fk-1) * maxseconds
- for sk=2,maxseconds do
- local sv = seconds[sk]
+ local extrakerns = { }
+ local baseoffset = (fk-1) * maxseconds
+ -- for sk=2,maxseconds do
+ -- local sv = seconds[sk]
+ for sk, sv in next, seconds do
local splt = split[sv]
- if splt then
+ if splt then -- redundant test
local offset = offsets[baseoffset + sk]
if offset then
for i=1,#splt do
- local second_unicode = splt[i]
- if tonumber(second_unicode) then
- kerns[second_unicode] = offset
- else for s=1,#second_unicode do
- kerns[second_unicode[s]] = offset
- end end
+ extrakerns[splt[i]] = offset
end
end
end
end
for i=1,#splt do
local first_unicode = splt[i]
- if tonumber(first_unicode) then
- do_it(lookup,first_unicode,kerns)
- else for f=1,#first_unicode do
- do_it(lookup,first_unicode[f],kerns)
- end end
+ local description = descriptions[first_unicode]
+ if description then
+ local kerns = description.kerns
+ if not kerns then
+ kerns = { } -- unicode indexed !
+ description.kerns = kerns
+ end
+ local lookupkerns = kerns[lookup]
+ if not lookupkerns then
+ lookupkerns = { }
+ kerns[lookup] = lookupkerns
+ end
+ for second_unicode, kern in next, extrakerns do
+ lookupkerns[second_unicode] = kern
+ end
+ elseif trace_loading then
+ report_otf("no glyph data for U+%04X", first_unicode)
+ end
end
end
end
end
end
- subtable.comment = "The kernclass table is merged into kerns in the indexed glyph tables."
subtable.kernclass = { }
end
end
@@ -7023,112 +6169,37 @@ actions["reorganize glyph kerns"] = function(data,filename,raw)
end
actions["check glyphs"] = function(data,filename,raw)
- local verbose = fonts.verbose
- local int_to_uni = data.luatex.unicodes
- for k, v in next, data.glyphs do
- if verbose then
- local code = int_to_uni[k]
- -- looks like this is done twice ... bug?
- if code then
- local vu = v.unicode
- if not vu then
- v.unicode = code
- elseif type(vu) == "table" then
- if vu[#vu] == code then
- -- weird
- else
- vu[#vu+1] = code
- end
- elseif vu ~= code then
- v.unicode = { vu, code }
- end
- end
- else
- v.unicode = nil
- v.index = nil
- end
- -- only needed on non sparse/mixed mode
- if v.math then
- if v.mathkern then v.mathkern = nil end
- if v.horiz_variant then v.horiz_variant = nil end
- if v.vert_variants then v.vert_variants = nil end
- end
- --
+ for unicode, description in next, data.descriptions do
+ description.glyph = nil
end
- data.luatex.comment = "Glyph tables have their original index. When present, kern tables are indexed by unicode."
end
+-- future versions will remove _
+
actions["check metadata"] = function(data,filename,raw)
local metadata = data.metadata
- metadata.method = loadmethod
- if loadmethod == "sparse" then
- for _, k in next, mainfields do
- if valid_fields[k] then
- local v = raw[k]
- if global_fields[k] then
- if not data[k] then
- data[k] = v
- end
- else
- if not metadata[k] then
- metadata[k] = v
- end
- end
- end
- end
- else
- for k, v in next, raw do
- if valid_fields[k] then
- if global_fields[k] then
- if not data[k] then
- data[v] = v
- end
- else
- if not metadata[k] then
- metadata[k] = v
- end
- end
+ for _, k in next, mainfields do
+ if valid_fields[k] then
+ local v = raw[k]
+ if not metadata[k] then
+ metadata[k] = v
end
end
end
- local pfminfo = raw.pfminfo
- if pfminfo then
- data.pfminfo = pfminfo
- metadata.isfixedpitch = metadata.isfixedpitch or (pfminfo.panose and pfminfo.panose.proportion == "Monospaced")
- metadata.charwidth = pfminfo and pfminfo.avgwidth
- end
+ -- metadata.pfminfo = raw.pfminfo -- not already done?
local ttftables = metadata.ttf_tables
if ttftables then
for i=1,#ttftables do
ttftables[i].data = "deleted"
end
end
- metadata.xuid = nil
- data.udglyphs = nil
- data.map = nil
end
-local private_mathparameters = {
- "FractionDelimiterSize",
- "FractionDelimiterDisplayStyleSize",
-}
-
-actions["check math parameters"] = function(data,filename,raw)
- local mathdata = data.metadata.math
- if mathdata then
- for m=1,#private_mathparameters do
- local pmp = private_mathparameters[m]
- if not mathdata[pmp] then
- if trace_loading then
- report_otf("setting math parameter '%s' to 0", pmp)
- end
- mathdata[pmp] = 0
- end
- end
- end
+actions["cleanup tables"] = function(data,filename,raw)
+ data.resources.indices = nil -- not needed
+ data.helpers = nil
end
-
-- kern: ttf has a table with kerns
--
-- Weird, as maxfirst and maxseconds can have holes, first seems to be indexed, but
@@ -7136,272 +6207,239 @@ end
-- unpredictable alternatively we could force an [1] if not set (maybe I will do that
-- anyway).
+-- we can share { } as it is never set
+
+--- ligatures have an extra specification.char entry that we don't use
+
actions["reorganize glyph lookups"] = function(data,filename,raw)
- local glyphs = data.glyphs
- for index, udglyph in next, data.udglyphs do
- local lookups = udglyph.lookups
+ local resources = data.resources
+ local unicodes = resources.unicodes
+ local descriptions = data.descriptions
+ local splitter = data.helpers.tounicodelist
+
+ local lookuptypes = resources.lookuptypes
+
+ for unicode, description in next, descriptions do
+ local lookups = description.glyph.lookups
if lookups then
- local glyph = glyphs[index]
- local l = { }
- for kk, vv in next, lookups do
- local aa = { }
- l[kk] = aa
- for kkk=1,#vv do
- local vvv = vv[kkk]
- local s = vvv.specification
- local t = vvv.type
- -- #aa+1
- if t == "ligature" then
- aa[kkk] = { "ligature", s.components, s.char }
- elseif t == "alternate" then
- aa[kkk] = { "alternate", s.components }
- elseif t == "substitution" then
- aa[kkk] = { "substitution", s.variant }
- elseif t == "multiple" then
- aa[kkk] = { "multiple", s.components }
- elseif t == "position" then
- aa[kkk] = { "position", { s.x or 0, s.y or 0, s.h or 0, s.v or 0 } }
- elseif t == "pair" then
- -- maybe flatten this one
- local one, two, paired = s.offsets[1], s.offsets[2], s.paired or ""
+ for tag, lookuplist in next, lookups do
+ for l=1,#lookuplist do
+ local lookup = lookuplist[l]
+ local specification = lookup.specification
+ local lookuptype = lookup.type
+ local lt = lookuptypes[tag]
+ if not lt then
+ lookuptypes[tag] = lookuptype
+ elseif lt ~= lookuptype then
+ report_otf("conflicting lookuptypes: %s => %s and %s",tag,lt,lookuptype)
+ end
+ if lookuptype == "ligature" then
+ lookuplist[l] = { lpegmatch(splitter,specification.components) }
+ elseif lookuptype == "alternate" then
+ lookuplist[l] = { lpegmatch(splitter,specification.components) }
+ elseif lookuptype == "substitution" then
+ lookuplist[l] = unicodes[specification.variant]
+ elseif lookuptype == "multiple" then
+ lookuplist[l] = { lpegmatch(splitter,specification.components) }
+ elseif lookuptype == "position" then
+ lookuplist[l] = {
+ specification.x or 0,
+ specification.y or 0,
+ specification.h or 0,
+ specification.v or 0
+ }
+ elseif lookuptype == "pair" then
+ local one = specification.offsets[1]
+ local two = specification.offsets[2]
+ local paired = unicodes[specification.paired]
if one then
if two then
- aa[kkk] = { "pair", paired, { one.x or 0, one.y or 0, one.h or 0, one.v or 0 }, { two.x or 0, two.y or 0, two.h or 0, two.v or 0 } }
+ lookuplist[l] = { paired, { one.x or 0, one.y or 0, one.h or 0, one.v or 0 }, { two.x or 0, two.y or 0, two.h or 0, two.v or 0 } }
else
- aa[kkk] = { "pair", paired, { one.x or 0, one.y or 0, one.h or 0, one.v or 0 } }
+ lookuplist[l] = { paired, { one.x or 0, one.y or 0, one.h or 0, one.v or 0 } }
end
else
if two then
- aa[kkk] = { "pair", paired, { }, { two.x or 0, two.y or 0, two.h or 0, two.v or 0} } -- maybe nil instead of { }
+ lookuplist[l] = { paired, { }, { two.x or 0, two.y or 0, two.h or 0, two.v or 0} } -- maybe nil instead of { }
else
- aa[kkk] = { "pair", paired }
+ lookuplist[l] = { paired }
end
end
end
end
end
- -- we could combine this
local slookups, mlookups
- for kk, vv in next, l do
- if #vv == 1 then
- if not slookups then
- slookups = { }
- glyph.slookups = slookups
+ for tag, lookuplist in next, lookups do
+ if #lookuplist == 1 then
+ if slookups then
+ slookups[tag] = lookuplist[1]
+ else
+ slookups = { [tag] = lookuplist[1] }
end
- slookups[kk] = vv[1]
else
- if not mlookups then
- mlookups = { }
- glyph.mlookups = mlookups
+ if mlookups then
+ mlookups[tag] = lookuplist
+ else
+ mlookups = { [tag] = lookuplist }
end
- mlookups[kk] = vv
end
end
- glyph.lookups = nil -- when using table
+ if slookups then
+ description.slookups = slookups
+ end
+ if mlookups then
+ description.mlookups = mlookups
+ end
end
end
+
end
-actions["reorganize glyph anchors"] = function(data,filename,raw)
- local glyphs = data.glyphs
- for index, udglyph in next, data.udglyphs do
- local anchors = udglyph.anchors
+actions["reorganize glyph anchors"] = function(data,filename,raw) -- when we replace inplace we safe entries
+ local descriptions = data.descriptions
+ for unicode, description in next, descriptions do
+ local anchors = description.glyph.anchors
if anchors then
- local glyph = glyphs[index]
- local a = { }
- glyph.anchors = a
- for kk, vv in next, anchors do
- local aa = { }
- a[kk] = aa
- for kkk, vvv in next, vv do
- if vvv.x or vvv.y then
- aa[kkk] = { vvv.x , vvv.y }
- else
- local aaa = { }
- aa[kkk] = aaa
- for kkkk=1,#vvv do
- local vvvv = vvv[kkkk]
- aaa[kkkk] = { vvvv.x, vvvv.y }
+ for class, data in next, anchors do
+ if class == "baselig" then
+ for tag, specification in next, data do
+ for i=1,#specification do
+ local si = specification[i]
+ specification[i] = { si.x or 0, si.y or 0 }
end
end
+ else
+ for tag, specification in next, data do
+ data[tag] = { specification.x or 0, specification.y or 0 }
+ end
end
end
+ description.anchors = anchors
end
end
end
---~ actions["check extra features"] = function(data,filename,raw)
---~ -- later, ctx only
---~ end
-
--- -- -- -- -- --
--- -- -- -- -- --
-
-function features.register(name,default,description)
- featurelist[#featurelist+1] = name
- defaultfeatures[name] = default
- if description and description ~= "" then
- fonts.otf.tables.features[name] = description
- end
-end
-
--- for context this will become a task handler
-
-local lists = { -- why local
- fonts.triggers,
- fonts.processors,
- fonts.manipulators,
-}
+-- modes: node, base, none
function otf.setfeatures(tfmdata,features)
- local processes = { }
- if features and next(features) then
- local mode = tfmdata.mode or features.mode or "base"
- local initializers = fonts.initializers
- local fi = initializers[mode]
- if fi then
- local fiotf = fi.otf
- if fiotf then
- local done = { }
- for l=1,#lists do
- local list = lists[l]
- if list then
- for i=1,#list do
- local f = list[i]
- local value = features[f]
- if value and fiotf[f] then -- brr
- if not done[f] then -- so, we can move some to triggers
- if trace_features then
- report_otf("initializing feature %s to %s for mode %s for font %s",f,tostring(value),mode or 'unknown', tfmdata.fullname or 'unknown')
- end
- fiotf[f](tfmdata,value) -- can set mode (no need to pass otf)
- mode = tfmdata.mode or features.mode or "base"
- local im = initializers[mode]
- if im then
- fiotf = initializers[mode].otf
- end
- done[f] = true
- end
- end
- end
- end
- end
- end
- end
-tfmdata.mode = mode
- local fm = fonts.methods[mode] -- todo: zonder node/mode otf/...
- if fm then
- local fmotf = fm.otf
- if fmotf then
- for l=1,#lists do
- local list = lists[l]
- if list then
- for i=1,#list do
- local f = list[i]
- if fmotf[f] then -- brr
- if trace_features then
- report_otf("installing feature handler %s for mode %s for font %s",f,mode or 'unknown', tfmdata.fullname or 'unknown')
- end
- processes[#processes+1] = fmotf[f]
- end
- end
- end
- end
- end
- else
- -- message
- end
+ local okay = constructors.initializefeatures("otf",tfmdata,features,trace_features,report_otf)
+ if okay then
+ return constructors.collectprocessors("otf",tfmdata,features,trace_features,report_otf)
+ else
+ return { } -- will become false
end
- return processes, features
end
--- the first version made a top/mid/not extensible table, now we just pass on the variants data
--- and deal with it in the tfm scaler (there is no longer an extensible table anyway)
-
--- we cannot share descriptions as virtual fonts might extend them (ok, we could
--- use a cache with a hash
+-- the first version made a top/mid/not extensible table, now we just
+-- pass on the variants data and deal with it in the tfm scaler (there
+-- is no longer an extensible table anyway)
+--
+-- we cannot share descriptions as virtual fonts might extend them (ok,
+-- we could use a cache with a hash
+--
+-- we already assing an empty tabel to characters as we can add for
+-- instance protruding info and loop over characters; one is not supposed
+-- to change descriptions and if one does so one should make a copy!
-local function copytotfm(data,cache_id) -- we can save a copy when we reorder the tma to unicode (nasty due to one->many)
+local function copytotfm(data,cache_id)
if data then
- local glyphs, pfminfo, metadata = data.glyphs or { }, data.pfminfo or { }, data.metadata or { }
- local luatex = data.luatex
- local unicodes = luatex.unicodes -- names to unicodes
- local indices = luatex.indices
- local mode = data.mode or "base"
- local characters, parameters, mathparameters, descriptions = { }, { }, { }, { }
- local designsize = metadata.designsize or metadata.design_size or 100
+ local metadata = data.metadata
+ local resources = data.resources
+ local properties = table.derive(data.properties)
+ local descriptions = table.derive(data.descriptions)
+ local goodies = table.derive(data.goodies)
+ local characters = { }
+ local parameters = { }
+ local mathparameters = { }
+ --
+ local pfminfo = metadata.pfminfo or { }
+ local resources = data.resources
+ local unicodes = resources.unicodes
+ -- local mode = data.mode or "base"
+ local spaceunits = 500
+ local spacer = "space"
+ local designsize = metadata.designsize or metadata.design_size or 100
+ local mathspecs = metadata.math
+ --
if designsize == 0 then
designsize = 100
end
- local spaceunits, spacer = 500, "space"
- -- indices maps from unicodes to indices
- -- this wil stay as we can manipulate indices
- -- beforehand
- for u, i in next, indices do
- characters[u] = { } -- we need this because for instance we add protruding info and loop over characters
- descriptions[u] = glyphs[i]
- end
- -- math
- if metadata.math then
- -- parameters
- for name, value in next, metadata.math do
+ if mathspecs then
+ for name, value in next, mathspecs do
mathparameters[name] = value
end
- -- we could use a subset
- for u, char in next, characters do
- local d = descriptions[u]
+ end
+ for unicode, _ in next, data.descriptions do -- use parent table
+ characters[unicode] = { }
+ end
+ if mathspecs then
+ -- we could move this to the scaler but not that much is saved
+ -- and this is cleaner
+ for unicode, character in next, characters do
+ local d = descriptions[unicode]
local m = d.math
- -- we have them shared because that packs nicer
- -- we could prepare the variants and keep 'm in descriptions
if m then
- local variants, parts, c = m.horiz_variants, m.horiz_parts, char
+ -- watch out: luatex uses horiz_variants for the parts
+ local variants, parts = m.horiz_variants, m.horiz_parts
if variants then
- for n in gmatch(variants,"[^ ]+") do
- local un = unicodes[n]
- if un and u ~= un then
- c.next = un
- c = characters[un]
- end
- end
+ local c = character
+ for i=1,#variants do
+ local un = variants[i]
+ c.next = un
+ c = characters[un]
+ end -- c is now last in chain
c.horiz_variants = parts
elseif parts then
- c.horiz_variants = parts
+ character.horiz_variants = parts
end
- local variants, parts, c = m.vert_variants, m.vert_parts, char
+ local variants, parts = m.vert_variants, m.vert_parts
if variants then
- for n in gmatch(variants,"[^ ]+") do
- local un = unicodes[n]
- if un and u ~= un then
- c.next = un
- c = characters[un]
- end
+ local c = character
+ for i=1,#variants do
+ local un = variants[i]
+ c.next = un
+ c = characters[un]
end -- c is now last in chain
c.vert_variants = parts
elseif parts then
- c.vert_variants = parts
+ character.vert_variants = parts
end
local italic_correction = m.vert_italic_correction
if italic_correction then
- c.vert_italic_correction = italic_correction
+ character.vert_italic_correction = italic_correction -- was c.
+ end
+ local top_accent = m.top_accent
+ if top_accent then
+ character.top_accent = top_accent
end
local kerns = m.kerns
if kerns then
- char.mathkerns = kerns
+ character.mathkerns = kerns
end
end
end
end
-- end math
- local space, emdash = 0x20, 0x2014 -- unicodes['space'], unicodes['emdash']
- if metadata.isfixedpitch then
+ local monospaced = metadata.isfixedpitch or (pfminfo.panose and pfminfo.panose.proportion == "Monospaced")
+ local charwidth = pfminfo.avgwidth -- or unset
+ local italicangle = metadata.italicangle
+ local charxheight = pfminfo.os2_xheight and pfminfo.os2_xheight > 0 and pfminfo.os2_xheight
+ properties.monospaced = monospaced
+ parameters.italicangle = italicangle
+ parameters.charwidth = charwidth
+ parameters.charxheight = charxheight
+ --
+ local space = 0x0020 -- unicodes['space'], unicodes['emdash']
+ local emdash = 0x2014 -- unicodes['space'], unicodes['emdash']
+ if monospaced then
if descriptions[space] then
spaceunits, spacer = descriptions[space].width, "space"
end
if not spaceunits and descriptions[emdash] then
spaceunits, spacer = descriptions[emdash].width, "emdash"
end
- if not spaceunits and metadata.charwidth then
- spaceunits, spacer = metadata.charwidth, "charwidth"
+ if not spaceunits and charwidth then
+ spaceunits, spacer = charwidth, "charwidth"
end
else
if descriptions[space] then
@@ -7410,20 +6448,17 @@ local function copytotfm(data,cache_id) -- we can save a copy when we reorder th
if not spaceunits and descriptions[emdash] then
spaceunits, spacer = descriptions[emdash].width/2, "emdash/2"
end
- if not spaceunits and metadata.charwidth then
- spaceunits, spacer = metadata.charwidth, "charwidth"
+ if not spaceunits and charwidth then
+ spaceunits, spacer = charwidth, "charwidth"
end
end
spaceunits = tonumber(spaceunits) or 500 -- brrr
-- we need a runtime lookup because of running from cdrom or zip, brrr (shouldn't we use the basename then?)
- local filename = fonts.tfm.checkedfilename(luatex)
+ local filename = constructors.checkedfilename(resources)
local fontname = metadata.fontname
local fullname = metadata.fullname or fontname
- local cidinfo = data.cidinfo -- or { }
local units = metadata.units_per_em or 1000
--
- cidinfo.registry = cidinfo and cidinfo.registry or "" -- weird here, fix upstream
- --
parameters.slant = 0
parameters.space = spaceunits -- 3.333 (cmr10)
parameters.space_stretch = units/2 -- 500 -- 1.666 (cmr10)
@@ -7433,11 +6468,12 @@ local function copytotfm(data,cache_id) -- we can save a copy when we reorder th
if spaceunits < 2*units/5 then
-- todo: warning
end
- local italicangle = metadata.italicangle
- if italicangle then -- maybe also in afm _
- parameters.slant = parameters.slant - math.round(math.tan(italicangle*math.pi/180))
+ if italicangle then
+ parameters.italicangle = italicangle
+ parameters.italicfactor = math.cos(math.rad(90+italicangle))
+ parameters.slant = - math.round(math.tan(italicangle*math.pi/180))
end
- if metadata.isfixedpitch then
+ if monospaced then
parameters.space_stretch = 0
parameters.space_shrink = 0
elseif syncspace then --
@@ -7445,8 +6481,8 @@ local function copytotfm(data,cache_id) -- we can save a copy when we reorder th
parameters.space_shrink = spaceunits/3
end
parameters.extra_space = parameters.space_shrink -- 1.111 (cmr10)
- if pfminfo.os2_xheight and pfminfo.os2_xheight > 0 then
- parameters.x_height = pfminfo.os2_xheight
+ if charxheight then
+ parameters.x_height = charxheight
else
local x = 0x78 -- unicodes['x']
if x then
@@ -7457,150 +6493,109 @@ local function copytotfm(data,cache_id) -- we can save a copy when we reorder th
end
end
--
- local fileformat = data.format or fonts.fontformat(filename,"opentype")
- if units > 1000 then
- fileformat = "truetype"
- end
+ parameters.designsize = (designsize/10)*65536
+ parameters.ascender = abs(metadata.ascent or 0)
+ parameters.descender = abs(metadata.descent or 0)
+ parameters.units = units
+ --
+ properties.space = spacer
+ properties.encodingbytes = 2
+ properties.format = data.format or fonts.formats[filename] or "opentype"
+ properties.noglyphnames = true
+ properties.filename = filename
+ properties.fontname = fontname
+ properties.fullname = fullname
+ properties.psname = fontname or fullname
+ properties.name = filename or fullname
+ --
+ -- properties.name = specification.name
+ -- properties.sub = specification.sub
return {
- characters = characters,
- parameters = parameters,
- mathparameters = mathparameters,
- descriptions = descriptions,
- indices = indices,
- unicodes = unicodes,
- type = "real",
- direction = 0,
- boundarychar_label = 0,
- boundarychar = 65536,
- designsize = (designsize/10)*65536,
- encodingbytes = 2,
- mode = mode,
- filename = filename,
- fontname = fontname,
- fullname = fullname,
- psname = fontname or fullname,
- name = filename or fullname,
- units = units,
- format = fileformat,
- cidinfo = cidinfo,
- ascender = abs(metadata.ascent or 0),
- descender = abs(metadata.descent or 0),
- spacer = spacer,
- italicangle = italicangle,
+ characters = characters,
+ descriptions = descriptions,
+ parameters = parameters,
+ mathparameters = mathparameters,
+ resources = resources,
+ properties = properties,
+ goodies = goodies,
}
- else
- return nil
end
end
local function otftotfm(specification)
- local name = specification.name
- local sub = specification.sub
- local filename = specification.filename
- local format = specification.format
- local features = specification.features.normal
local cache_id = specification.hash
- local tfmdata = containers.read(tfm.cache,cache_id)
---~ print(cache_id)
+ local tfmdata = containers.read(constructors.cache,cache_id)
if not tfmdata then
- local otfdata = otf.load(filename,format,sub,features and features.featurefile)
- if otfdata and next(otfdata) then
- otfdata.shared = otfdata.shared or {
- featuredata = { },
- anchorhash = { },
- initialized = false,
- }
- tfmdata = copytotfm(otfdata,cache_id)
+ local name = specification.name
+ local sub = specification.sub
+ local filename = specification.filename
+ local format = specification.format
+ local features = specification.features.normal
+ local rawdata = otf.load(filename,format,sub,features and features.featurefile)
+ if rawdata and next(rawdata) then
+ rawdata.lookuphash = { }
+ tfmdata = copytotfm(rawdata,cache_id)
if tfmdata and next(tfmdata) then
- tfmdata.unique = tfmdata.unique or { }
- tfmdata.shared = tfmdata.shared or { } -- combine
- local shared = tfmdata.shared
- shared.otfdata = otfdata
- shared.features = features -- default
- shared.dynamics = { }
- shared.processes = { }
- shared.setdynamics = otf.setdynamics -- fast access and makes other modules independent
- -- this will be done later anyway, but it's convenient to have
- -- them already for fast access
- tfmdata.luatex = otfdata.luatex
- tfmdata.indices = otfdata.luatex.indices
- tfmdata.unicodes = otfdata.luatex.unicodes
- tfmdata.marks = otfdata.luatex.marks
- tfmdata.originals = otfdata.luatex.originals
- tfmdata.changed = { }
- tfmdata.has_italic = otfdata.metadata.has_italic
- if not tfmdata.language then tfmdata.language = 'dflt' end
- if not tfmdata.script then tfmdata.script = 'dflt' end
- -- at this moment no characters are assinged yet, only empty slots
- shared.processes, shared.features = otf.setfeatures(tfmdata,definers.check(features,defaultfeatures))
- end
- end
- containers.write(tfm.cache,cache_id,tfmdata)
+ -- at this moment no characters are assigned yet, only empty slots
+ local features = constructors.checkedfeatures("otf",features)
+ local shared = tfmdata.shared
+ if not shared then
+ shared = { }
+ tfmdata.shared = shared
+ end
+ shared.rawdata = rawdata
+ shared.features = features -- default
+ shared.dynamics = { }
+ shared.processes = { }
+ tfmdata.changed = { }
+ shared.features = features
+ shared.processes = otf.setfeatures(tfmdata,features)
+ end
+ end
+ containers.write(constructors.cache,cache_id,tfmdata)
end
return tfmdata
end
-features.register('mathsize')
-
-local function read_from_otf(specification) -- wrong namespace
- local tfmtable = otftotfm(specification)
- if tfmtable then
- local otfdata = tfmtable.shared.otfdata
- tfmtable.name = specification.name
- tfmtable.sub = specification.sub
- local s = specification.size
- local m = otfdata.metadata.math
- if m then
- -- this will move to a function
- local f = specification.features
- if f then
- local f = f.normal
- if f and f.mathsize then
- local mathsize = specification.mathsize or 0
- if mathsize == 2 then
- local p = m.ScriptPercentScaleDown
- if p then
- local ps = p * specification.textsize / 100
- if trace_math then
- report_otf("asked script size: %s, used: %s (%2.2f %%)",s,ps,(ps/s)*100)
- end
- s = ps
- end
- elseif mathsize == 3 then
- local p = m.ScriptScriptPercentScaleDown
- if p then
- local ps = p * specification.textsize / 100
- if trace_math then
- report_otf("asked scriptscript size: %s, used: %s (%2.2f %%)",s,ps,(ps/s)*100)
- end
- s = ps
- end
- end
- end
- end
- end
- tfmtable = tfm.scale(tfmtable,s,specification.relativeid)
- if tfm.fontnamemode == "specification" then
- -- not to be used in context !
- local specname = specification.specification
- if specname then
- tfmtable.name = specname
- if trace_defining then
- report_otf("overloaded fontname: '%s'",specname)
- end
- end
- end
- fonts.logger.save(tfmtable,file.extname(specification.filename),specification)
+local function read_from_otf(specification)
+ local tfmdata = otftotfm(specification)
+ if tfmdata then
+ -- this late ? .. needs checking
+ tfmdata.properties.name = specification.name
+ tfmdata.properties.sub = specification.sub
+ --
+ tfmdata = constructors.scale(tfmdata,specification)
+ constructors.applymanipulators("otf",tfmdata,specification.features.normal,trace_features,report_otf)
+ constructors.setname(tfmdata,specification) -- only otf?
+ fonts.loggers.register(tfmdata,file.extname(specification.filename),specification)
+ end
+ return tfmdata
+end
+
+local function checkmathsize(tfmdata,mathsize)
+ local mathdata = tfmdata.shared.rawdata.metadata.math
+ local mathsize = tonumber(mathsize)
+ if mathdata then -- we cannot use mathparameters as luatex will complain
+ local parameters = tfmdata.parameters
+ parameters.scriptpercentage = mathdata.ScriptPercentScaleDown
+ parameters.scriptscriptpercentage = mathdata.ScriptScriptPercentScaleDown
+ parameters.mathsize = mathsize
end
---~ print(tfmtable.fullname)
- return tfmtable
end
+registerotffeature {
+ name = "mathsize",
+ description = "apply mathsize as specified in the font",
+ initializers = {
+ base = checkmathsize,
+ node = checkmathsize,
+ }
+}
+
-- helpers
-function otf.collectlookups(otfdata,kind,script,language)
- -- maybe store this in the font
- local sequences = otfdata.luatex.sequences
+function otf.collectlookups(rawdata,kind,script,language)
+ local sequences = rawdata.resources.sequences
if sequences then
local featuremap, featurelist = { }, { }
for s=1,#sequences do
@@ -7631,42 +6626,23 @@ end
-- readers
-fonts.formats.dfont = "truetype"
-fonts.formats.ttc = "truetype"
-fonts.formats.ttf = "truetype"
-fonts.formats.otf = "opentype"
-
local function check_otf(forced,specification,suffix,what)
local name = specification.name
if forced then
name = file.addsuffix(name,suffix,true)
end
- local fullname, tfmtable = findbinfile(name,suffix) or "", nil -- one shot
- -- if false then -- can be enabled again when needed
- -- if fullname == "" then
- -- local fb = fonts.names.old_to_new[name]
- -- if fb then
- -- fullname = findbinfile(fb,suffix) or ""
- -- end
- -- end
- -- if fullname == "" then
- -- local fb = fonts.names.new_to_old[name]
- -- if fb then
- -- fullname = findbinfile(fb,suffix) or ""
- -- end
- -- end
- -- end
+ local fullname, tfmdata = findbinfile(name,suffix) or "", nil -- one shot
if fullname == "" then
fullname = fonts.names.getfilename(name,suffix)
end
if fullname ~= "" then
specification.filename, specification.format = fullname, what -- hm, so we do set the filename, then
- tfmtable = read_from_otf(specification) -- we need to do it for all matches / todo
+ tfmdata = read_from_otf(specification) -- we need to do it for all matches / todo
end
- return tfmtable
+ return tfmdata
end
-function readers.opentype(specification,suffix,what)
+local function opentypereader(specification,suffix,what)
local forced = specification.forced or ""
if forced == "otf" then
return check_otf(true,specification,forced,"opentype")
@@ -7677,561 +6653,1071 @@ function readers.opentype(specification,suffix,what)
end
end
-function readers.otf (specification) return readers.opentype(specification,"otf","opentype") end
-function readers.ttf (specification) return readers.opentype(specification,"ttf","truetype") end
-function readers.ttc (specification) return readers.opentype(specification,"ttf","truetype") end -- !!
-function readers.dfont(specification) return readers.opentype(specification,"ttf","truetype") end -- !!
+readers.opentype = opentypereader
+
+local formats = fonts.formats
+
+formats.otf = "opentype"
+formats.ttf = "truetype"
+formats.ttc = "truetype"
+formats.dfont = "truetype"
+
+function readers.otf (specification) return opentypereader(specification,"otf",formats.otf ) end
+function readers.ttf (specification) return opentypereader(specification,"ttf",formats.ttf ) end
+function readers.ttc (specification) return opentypereader(specification,"ttf",formats.ttc ) end
+function readers.dfont(specification) return opentypereader(specification,"ttf",formats.dfont) end
+
+-- this will be overloaded
+
+function otf.scriptandlanguage(tfmdata,attr)
+ local properties = tfmdata.properties
+ return properties.script or "dflt", properties.language or "dflt"
+end
end -- closure
do -- begin closure to overcome local limits and interference
-if not modules then modules = { } end modules ['font-otd'] = {
+if not modules then modules = { } end modules ['font-otb'] = {
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 concat = table.concat
+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 = type, next, tonumber, tostring
+local lpegmatch = lpeg.match
+local utfchar = utf.char
-local trace_dynamics = false trackers.register("otf.dynamics", function(v) trace_dynamics = v end)
-
-local report_otf = logs.reporter("fonts","otf loading")
-
-local fonts = fonts
-local otf = fonts.otf
-local fontdata = fonts.identifiers
+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)
-otf.features = otf.features or { }
-otf.features.default = otf.features.default or { }
+local report_prepare = logs.reporter("fonts","otf prepare")
-local definers = fonts.definers
-local contextsetups = definers.specifiers.contextsetups
-local contextnumbers = definers.specifiers.contextnumbers
+local fonts = fonts
+local otf = fonts.handlers.otf
--- todo: dynamics namespace
+local otffeatures = fonts.constructors.newfeatures("otf")
+local registerotffeature = otffeatures.register
-local a_to_script = { }
-local a_to_language = { }
+local wildcard = "*"
+local default = "dflt"
-function otf.setdynamics(font,dynamics,attribute)
- local features = contextsetups[contextnumbers[attribute]] -- can be moved to caller
- if features then
- local script = features.script or 'dflt'
- local language = features.language or 'dflt'
- local ds = dynamics[script]
- if not ds then
- ds = { }
- dynamics[script] = ds
- end
- local dsl = ds[language]
- if not dsl then
- dsl = { }
- ds[language] = dsl
- end
- local dsla = dsl[attribute]
- if dsla then
- -- if trace_dynamics then
- -- report_otf("using dynamics %s: attribute %s, script %s, language %s",contextnumbers[attribute],attribute,script,language)
- -- end
- return dsla
+local function gref(descriptions,n)
+ if type(n) == "number" then
+ local name = descriptions[n].name
+ if name then
+ return format("U+%04X (%s)",n,name)
else
- local tfmdata = fontdata[font]
- a_to_script [attribute] = script
- a_to_language[attribute] = language
- -- we need to save some values
- local saved = {
- script = tfmdata.script,
- language = tfmdata.language,
- mode = tfmdata.mode,
- features = tfmdata.shared.features
- }
- tfmdata.mode = "node"
- tfmdata.dynamics = true -- handy for tracing
- tfmdata.language = language
- tfmdata.script = script
- tfmdata.shared.features = { }
- -- end of save
- local set = definers.check(features,otf.features.default)
- dsla = otf.setfeatures(tfmdata,set)
- if trace_dynamics then
- report_otf("setting dynamics %s: attribute %s, script %s, language %s, set: %s",contextnumbers[attribute],attribute,script,language,table.sequenced(set))
- end
- -- we need to restore some values
- tfmdata.script = saved.script
- tfmdata.language = saved.language
- tfmdata.mode = saved.mode
- tfmdata.shared.features = saved.features
- -- end of restore
- dynamics[script][language][attribute] = dsla -- cache
- return dsla
- end
- end
- return nil -- { }
+ return format("U+%04X")
+ end
+ elseif n then
+ local num, nam = { }, { }
+ for i=2,#n do -- first is likely a key
+ local ni = n[i]
+ num[i] = format("U+%04X",ni)
+ nam[i] = descriptions[ni].name or "?"
+ end
+ return format("%s (%s)",concat(num," "), concat(nam," "))
+ else
+ return "?"
+ end
end
-function otf.scriptandlanguage(tfmdata,attr)
- if attr and attr > 0 then
- return a_to_script[attr] or tfmdata.script, a_to_language[attr] or tfmdata.language
+local function cref(feature,lookupname)
+ if lookupname then
+ return format("feature %s, lookup %s",feature,lookupname)
else
- return tfmdata.script, tfmdata.language
+ return format("feature %s",feature)
end
end
-end -- closure
+local basemethods = { }
+local basemethod = "<unset>"
-do -- begin closure to overcome local limits and interference
+local function applybasemethod(what,...)
+ local m = basemethods[basemethod][what]
+ if m then
+ return m(...)
+ end
+end
-if not modules then modules = { } end modules ['font-oti'] = {
- 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"
-}
+-- We need to make sure that luatex sees the difference between
+-- base fonts that have different glyphs in the same slots in fonts
+-- that have the same fullname (or filename). LuaTeX will merge fonts
+-- eventually (and subset later on). If needed we can use a more
+-- verbose name as long as we don't use <()<>[]{}/%> and the length
+-- is < 128.
-local lower = string.lower
+local basehash, basehashes, applied = { }, 1, { }
-local fonts = fonts
+local function registerbasehash(tfmdata)
+ local properties = tfmdata.properties
+ local hash = concat(applied," ")
+ local base = basehash[hash]
+ if not base then
+ basehashes = basehashes + 1
+ base = basehashes
+ basehash[hash] = base
+ end
+ properties.basehash = base
+ properties.fullname = properties.fullname .. "-" .. base
+ -- report_prepare("fullname base hash: '%s', featureset '%s'",tfmdata.properties.fullname,hash)
+ applied = { }
+end
+
+local function registerbasefeature(feature,value)
+ applied[#applied+1] = feature .. "=" .. tostring(value)
+end
+
+-- The original basemode ligature builder used the names of components
+-- and did some expression juggling to get the chain right. The current
+-- variant starts with unicodes but still uses names to make the chain.
+-- This is needed because we have to create intermediates when needed
+-- but use predefined snippets when available. To some extend the
+-- current builder is more stupid but I don't worry that much about it
+-- as ligatures are rather predicatable.
+--
+-- Personally I think that an ff + i == ffi rule as used in for instance
+-- latin modern is pretty weird as no sane person will key that in and
+-- expect a glyph for that ligature plus the following character. Anyhow,
+-- as we need to deal with this, we do, but no guarantes are given.
+--
+-- latin modern dejavu
+--
+-- f+f 102 102 102 102
+-- f+i 102 105 102 105
+-- f+l 102 108 102 108
+-- f+f+i 102 102 105
+-- f+f+l 102 102 108 102 102 108
+-- ff+i 64256 105 64256 105
+-- ff+l 64256 108
+--
+-- As you can see here, latin modern is less complete than dejavu but
+-- in practice one will not notice it.
+--
+-- The while loop is needed because we need to resolve for instance
+-- pseudo names like hyphen_hyphen to endash so in practice we end
+-- up with a bit too many definitions but the overhead is neglectable.
+--
+-- Todo: if changed[first] or changed[second] then ... end
+
+local trace = false
+
+local function finalize_ligatures(tfmdata,ligatures)
+ local nofligatures = #ligatures
+ if nofligatures > 0 then
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local resources = tfmdata.resources
+ local unicodes = resources.unicodes
+ local private = resources.private
+ local alldone = false
+ while not alldone do
+ local done = 0
+ for i=1,nofligatures do
+ local ligature = ligatures[i]
+ if ligature then
+ local unicode, lookupdata = ligature[1], ligature[2]
+ if trace then
+ print("BUILDING",concat(lookupdata," "),unicode)
+ end
+ local size = #lookupdata
+ local firstcode = lookupdata[1] -- [2]
+ local firstdata = characters[firstcode]
+ local okay = false
+ if firstdata then
+ local firstname = "ctx_" .. firstcode
+ for i=1,size-1 do -- for i=2,size-1 do
+ local firstdata = characters[firstcode]
+ if not firstdata then
+ firstcode = private
+ if trace then
+ print(" DEFINING",firstname,firstcode)
+ end
+ unicodes[firstname] = firstcode
+ firstdata = { intermediate = true, ligatures = { } }
+ characters[firstcode] = firstdata
+ descriptions[firstcode] = { name = firstname }
+ private = private + 1
+ end
+ local target
+ local secondcode = lookupdata[i+1]
+ local secondname = firstname .. "_" .. secondcode
+ if i == size - 1 then
+ target = unicode
+ if not unicodes[secondname] then
+ unicodes[secondname] = unicode -- map final ligature onto intermediates
+ end
+ okay = true
+ else
+ target = unicodes[secondname]
+ if not target then
+ break
+ end
+ end
+ if trace then
+ print("CODES",firstname,firstcode,secondname,secondcode,target)
+ end
+ local firstligs = firstdata.ligatures
+ if firstligs then
+ firstligs[secondcode] = { char = target }
+ else
+ firstdata.ligatures = { [secondcode] = { char = target } }
+ end
+ firstcode = target
+ firstname = secondname
+ end
+ end
+ if okay then
+ ligatures[i] = false
+ done = done + 1
+ end
+ end
+ end
+ alldone = done == 0
+ end
+ if trace then
+ for k, v in next, characters do
+ if v.ligatures then table.print(v,k) end
+ end
+ end
+ tfmdata.resources.private = private
+ end
+end
-local otf = fonts.otf
-local initializers = fonts.initializers
+local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplist)
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local resources = tfmdata.resources
+ local changed = tfmdata.changed
+ local unicodes = resources.unicodes
+ local lookuphash = resources.lookuphash
+ local lookuptypes = resources.lookuptypes
-local languages = otf.tables.languages
-local scripts = otf.tables.scripts
+ local ligatures = { }
-local function set_language(tfmdata,value)
- if value then
- value = lower(value)
- if languages[value] then
- tfmdata.language = value
+ local actions = {
+ substitution = function(lookupdata,lookupname,description,unicode)
+ if trace_baseinit and trace_singles then
+ report_prepare("%s: base substitution %s => %s",cref(feature,lookupname),
+ gref(descriptions,unicode),gref(descriptions,replacement))
+ end
+ changed[unicode] = lookupdata
+ end,
+ alternate = function(lookupdata,lookupname,description,unicode)
+ local replacement = lookupdata[value] or lookupdata[#lookupdata]
+ if trace_baseinit and trace_alternatives then
+ report_prepare("%s: base alternate %s %s => %s",cref(feature,lookupname),
+ tostring(value),gref(descriptions,unicode),gref(descriptions,replacement))
+ end
+ changed[unicode] = replacement
+ end,
+ ligature = function(lookupdata,lookupname,description,unicode)
+ if trace_baseinit and trace_alternatives then
+ report_prepare("%s: base ligature %s %s => %s",cref(feature,lookupname),
+ tostring(value),gref(descriptions,lookupdata),gref(descriptions,unicode))
+ end
+ ligatures[#ligatures+1] = { unicode, lookupdata }
+ end,
+ }
+
+ for unicode, character in next, characters do
+ local description = descriptions[unicode]
+ local lookups = description.slookups
+ if lookups then
+ for l=1,#lookuplist do
+ local lookupname = lookuplist[l]
+ local lookupdata = lookups[lookupname]
+ if lookupdata then
+ local lookuptype = lookuptypes[lookupname]
+ local action = actions[lookuptype]
+ if action then
+ action(lookupdata,lookupname,description,unicode)
+ end
+ end
+ end
+ end
+ local lookups = description.mlookups
+ if lookups then
+ for l=1,#lookuplist do
+ local lookupname = lookuplist[l]
+ local lookuplist = lookups[lookupname]
+ if lookuplist then
+ local lookuptype = lookuptypes[lookupname]
+ local action = actions[lookuptype]
+ if action then
+ for i=1,#lookuplist do
+ action(lookuplist[i],lookupname,description,unicode)
+ end
+ end
+ end
+ end
end
end
+
+ finalize_ligatures(tfmdata,ligatures)
end
-local function set_script(tfmdata,value)
- if value then
- value = lower(value)
- if scripts[value] then
- tfmdata.script = value
+local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist) -- todo what kind of kerns, currently all
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local resources = tfmdata.resources
+ local unicodes = resources.unicodes
+ local sharedkerns = { }
+ local traceindeed = trace_baseinit and trace_kerns
+ for unicode, character in next, characters do
+ local description = descriptions[unicode]
+ local rawkerns = description.kerns -- shared
+ if rawkerns then
+ local s = sharedkerns[rawkerns]
+ if s == false then
+ -- skip
+ elseif s then
+ character.kerns = s
+ else
+ local newkerns = character.kerns
+ local done = false
+ for l=1,#lookuplist do
+ local lookup = lookuplist[l]
+ local kerns = rawkerns[lookup]
+ if kerns then
+ for otherunicode, value in next, kerns do
+ if value == 0 then
+ -- maybe no 0 test here
+ elseif not newkerns then
+ newkerns = { [otherunicode] = value }
+ done = true
+ if traceindeed then
+ report_prepare("%s: base kern %s + %s => %s",cref(feature,lookup),
+ gref(descriptions,unicode),gref(descriptions,otherunicode),value)
+ end
+ elseif not newkerns[otherunicode] then -- first wins
+ newkerns[otherunicode] = value
+ done = true
+ if traceindeed then
+ report_prepare("%s: base kern %s + %s => %s",cref(feature,lookup),
+ gref(descriptions,unicode),gref(descriptions,otherunicode),value)
+ end
+ end
+ end
+ end
+ end
+ if done then
+ sharedkerns[rawkerns] = newkerns
+ character.kerns = newkerns -- no empty assignments
+ else
+ sharedkerns[rawkerns] = false
+ end
+ end
end
end
end
-local function set_mode(tfmdata,value)
- if value then
- tfmdata.mode = lower(value)
+basemethods.independent = {
+ preparesubstitutions = preparesubstitutions,
+ preparepositionings = preparepositionings,
+}
+
+local function makefake(tfmdata,name,present)
+ local resources = tfmdata.resources
+ local private = resources.private
+ local character = { intermediate = true, ligatures = { } }
+ resources.unicodes[name] = private
+ tfmdata.characters[private] = character
+ tfmdata.descriptions[private] = { name = name }
+ resources.private = private + 1
+ present[name] = private
+ return character
+end
+
+local function make_1(present,tree,name)
+ for k, v in next, tree do
+ if k == "ligature" then
+ present[name] = v
+ else
+ make_1(present,v,name .. "_" .. k)
+ end
+ end
+end
+
+local function make_2(present,tfmdata,characters,tree,name,preceding,unicode,done,lookupname)
+ for k, v in next, tree do
+ if k == "ligature" then
+ local character = characters[preceding]
+ if not character then
+ if trace_baseinit then
+ report_prepare("weird ligature in lookup %s: 0x%04X (%s), preceding 0x%04X (%s)",lookupname,v,utfchar(v),preceding,utfchar(preceding))
+ end
+ character = makefake(tfmdata,name,present)
+ end
+ local ligatures = character.ligatures
+ if ligatures then
+ ligatures[unicode] = { char = v }
+ else
+ character.ligatures = { [unicode] = { char = v } }
+ end
+ if done then
+ local d = done[lookupname]
+ if not d then
+ done[lookupname] = { "dummy", v }
+ else
+ d[#d+1] = v
+ end
+ end
+ else
+ local code = present[name] or unicode
+ local name = name .. "_" .. k
+ make_2(present,tfmdata,characters,v,name,code,k,done,lookupname)
+ end
+ end
+end
+
+local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplist)
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local resources = tfmdata.resources
+ local changed = tfmdata.changed
+ local lookuphash = resources.lookuphash
+ local lookuptypes = resources.lookuptypes
+
+ local ligatures = { }
+
+ for l=1,#lookuplist do
+ local lookupname = lookuplist[l]
+ local lookupdata = lookuphash[lookupname]
+ local lookuptype = lookuptypes[lookupname]
+ for unicode, data in next, lookupdata do
+ if lookuptype == "substitution" then
+ if trace_baseinit and trace_singles then
+ report_prepare("%s: base substitution %s => %s",cref(feature,lookupname),
+ gref(descriptions,unicode),gref(descriptions,data))
+ end
+ changed[unicode] = data
+ elseif lookuptype == "alternate" then
+ local replacement = data[value] or data[#data]
+ if trace_baseinit and trace_alternatives then
+ report_prepare("%s: base alternate %s %s => %s",cref(feature,lookupname),
+ tostring(value),gref(descriptions,unicode),gref(descriptions,replacement))
+ end
+ changed[unicode] = replacement
+ elseif lookuptype == "ligature" then
+ ligatures[#ligatures+1] = { unicode, data, lookupname }
+ end
+ end
+ end
+
+ local nofligatures = #ligatures
+
+ if nofligatures > 0 then
+
+ local characters = tfmdata.characters
+ local present = { }
+ local done = trace_baseinit and trace_ligatures and { }
+
+ for i=1,nofligatures do
+ local ligature = ligatures[i]
+ local unicode, tree = ligature[1], ligature[2]
+ make_1(present,tree,"ctx_"..unicode)
+ end
+
+ for i=1,nofligatures do
+ local ligature = ligatures[i]
+ local unicode, tree, lookupname = ligature[1], ligature[2], ligature[3]
+ make_2(present,tfmdata,characters,tree,"ctx_"..unicode,unicode,unicode,done,lookupname)
+ end
+
+ if done then
+ for lookupname, list in next, done do
+ report_prepare("%s: base ligatures %s => %s",cref(feature,lookupname),
+ tostring(value),gref(descriptions,done))
+ end
+ end
+
+ end
+
+end
+
+local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist)
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local resources = tfmdata.resources
+ local lookuphash = resources.lookuphash
+ local traceindeed = trace_baseinit and trace_kerns
+
+ -- check out this sharedkerns trickery
+
+ for l=1,#lookuplist do
+ local lookupname = lookuplist[l]
+ local lookupdata = lookuphash[lookupname]
+ for unicode, data in next, lookupdata do
+ local character = characters[unicode]
+ local kerns = character.kerns
+ if not kerns then
+ kerns = { }
+ character.kerns = kerns
+ end
+ if traceindeed then
+ for otherunicode, kern in next, data do
+ if not kerns[otherunicode] and kern ~= 0 then
+ kerns[otherunicode] = kern
+ report_prepare("%s: base kern %s + %s => %s",cref(feature,lookup),
+ gref(descriptions,unicode),gref(descriptions,otherunicode),kern)
+ end
+ end
+ else
+ for otherunicode, kern in next, data do
+ if not kerns[otherunicode] and kern ~= 0 then
+ kerns[otherunicode] = kern
+ end
+ end
+ end
+ end
end
+
+end
+
+local function initializehashes(tfmdata)
+ nodeinitializers.features(tfmdata)
end
-local base_initializers = initializers.base.otf
-local node_initializers = initializers.node.otf
+basemethods.shared = {
+ initializehashes = initializehashes,
+ preparesubstitutions = preparesubstitutions,
+ preparepositionings = preparepositionings,
+}
+
+basemethod = "independent"
-base_initializers.language = set_language
-base_initializers.script = set_script
-base_initializers.mode = set_mode
-base_initializers.method = set_mode
+local function featuresinitializer(tfmdata,value)
+ if true then -- value then
+ local t = trace_preparing and os.clock()
+ local features = tfmdata.shared.features
+ if features then
+ applybasemethod("initializehashes",tfmdata)
+ local collectlookups = otf.collectlookups
+ local rawdata = tfmdata.shared.rawdata
+ local properties = tfmdata.properties
+ local script = properties.script
+ local language = properties.language
+ local basesubstitutions = rawdata.resources.features.gsub
+ local basepositionings = rawdata.resources.features.gpos
+ if basesubstitutions then
+ for feature, data in next, basesubstitutions do
+ local value = features[feature]
+ if value then
+ local validlookups, lookuplist = collectlookups(rawdata,feature,script,language)
+ if validlookups then
+ applybasemethod("preparesubstitutions",tfmdata,feature,value,validlookups,lookuplist)
+ registerbasefeature(feature,value)
+ end
+ end
+ end
+ end
+ if basepositions then
+ for feature, data in next, basepositions do
+ local value = features[feature]
+ if value then
+ local validlookups, lookuplist = collectlookups(rawdata,feature,script,language)
+ if validlookups then
+ applybasemethod("preparepositionings",tfmdata,feature,features[feature],validlookups,lookuplist)
+ registerbasefeature(feature,value)
+ end
+ end
+ end
+ end
+ registerbasehash(tfmdata)
+ end
+ if trace_preparing then
+ report_prepare("preparation time is %0.3f seconds for %s",os.clock()-t,tfmdata.properties.fullname or "?")
+ end
+ end
+end
-node_initializers.language = set_language
-node_initializers.script = set_script
-node_initializers.mode = set_mode
-node_initializers.method = set_mode
+registerotffeature {
+ name = "features",
+ description = "features",
+ default = true,
+ initializers = {
+ position = 1,
+ base = featuresinitializer,
+ }
+}
-otf.features.register("features",true) -- we always do features
-table.insert(fonts.processors,"features") -- we need a proper function for doing this
+-- independent : collect lookups independently (takes more runtime ... neglectable)
+-- shared : shares lookups with node mode (takes more memory ... noticeable)
+directives.register("fonts.otf.loader.basemethod", function(v)
+ if basemethods[v] then
+ basemethod = v
+ end
+end)
end -- closure
do -- begin closure to overcome local limits and interference
-if not modules then modules = { } end modules ['font-otb'] = {
+if not modules then modules = { } end modules ['node-inj'] = {
version = 1.001,
- comment = "companion to font-ini.mkiv",
+ comment = "companion to node-ini.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
}
-local concat = table.concat
-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 = type, next, tonumber, tostring
-local lpegmatch = lpeg.match
+-- This is very experimental (this will change when we have luatex > .50 and
+-- a few pending thingies are available. Also, Idris needs to make a few more
+-- test fonts. Btw, future versions of luatex will have extended glyph properties
+-- that can be of help.
-local fonts = fonts
-local otf = fonts.otf
-local tfm = fonts.tfm
+local next = next
-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 trace_injections = false trackers.register("nodes.injections", function(v) trace_injections = v end)
-local report_prepare = logs.reporter("fonts","otf prepare")
+local report_injections = logs.reporter("nodes","injections")
-local wildcard = "*"
-local default = "dflt"
+local attributes, nodes, node = attributes, nodes, node
-local split_at_space = lpeg.Ct(lpeg.splitat(" ")) -- no trailing or multiple spaces anyway
+fonts = fonts
+local fontdata = fonts.hashes.identifiers
-local pcache, fcache = { }, { } -- could be weak
+nodes.injections = nodes.injections or { }
+local injections = nodes.injections
-local function gref(descriptions,n)
- if type(n) == "number" then
- local name = descriptions[n].name
- if name then
- return format("U+%04X (%s)",n,name)
+local nodecodes = nodes.nodecodes
+local glyph_code = nodecodes.glyph
+local nodepool = nodes.pool
+local newkern = nodepool.kern
+
+local traverse_id = node.traverse_id
+local unset_attribute = node.unset_attribute
+local has_attribute = node.has_attribute
+local set_attribute = node.set_attribute
+local insert_node_before = node.insert_before
+local insert_node_after = node.insert_after
+
+local markbase = attributes.private('markbase')
+local markmark = attributes.private('markmark')
+local markdone = attributes.private('markdone')
+local cursbase = attributes.private('cursbase')
+local curscurs = attributes.private('curscurs')
+local cursdone = attributes.private('cursdone')
+local kernpair = attributes.private('kernpair')
+
+local cursives = { }
+local marks = { }
+local kerns = { }
+
+-- currently we do gpos/kern in a bit inofficial way but when we
+-- have the extra fields in glyphnodes to manipulate ht/dp/wd
+-- explicitly i will provide an alternative; also, we can share
+-- tables
+
+-- for the moment we pass the r2l key ... volt/arabtype tests
+
+function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext)
+ local dx, dy = factor*(exit[1]-entry[1]), factor*(exit[2]-entry[2])
+ local ws, wn = tfmstart.width, tfmnext.width
+ local bound = #cursives + 1
+ set_attribute(start,cursbase,bound)
+ set_attribute(nxt,curscurs,bound)
+ cursives[bound] = { rlmode, dx, dy, ws, wn }
+ return dx, dy, bound
+end
+
+function injections.setpair(current,factor,rlmode,r2lflag,spec,tfmchr)
+ local x, y, w, h = factor*spec[1], factor*spec[2], factor*spec[3], factor*spec[4]
+ -- dy = y - h
+ if x ~= 0 or w ~= 0 or y ~= 0 or h ~= 0 then
+ local bound = has_attribute(current,kernpair)
+ if bound then
+ local kb = kerns[bound]
+ -- inefficient but singles have less, but weird anyway, needs checking
+ kb[2], kb[3], kb[4], kb[5] = (kb[2] or 0) + x, (kb[3] or 0) + y, (kb[4] or 0)+ w, (kb[5] or 0) + h
else
- return format("U+%04X")
- end
- elseif n then
- local num, nam = { }, { }
- for i=1,#n do
- local ni = n[i]
- -- ! ! ! could be a helper ! ! !
- if type(ni) == "table" then
- local nnum, nnam = { }, { }
- for j=1,#ni do
- local nj = ni[j]
- nnum[j] = format("U+%04X",nj)
- nnam[j] = descriptions[nj].name or "?"
- end
- num[i] = concat(nnum,"|")
- nam[i] = concat(nnam,"|")
- else
- num[i] = format("U+%04X",ni)
- nam[i] = descriptions[ni].name or "?"
- end
+ bound = #kerns + 1
+ set_attribute(current,kernpair,bound)
+ kerns[bound] = { rlmode, x, y, w, h, r2lflag, tfmchr.width }
end
- return format("%s (%s)",concat(num," "), concat(nam," "))
- else
- return "?"
+ return x, y, w, h, bound
end
+ return x, y, w, h -- no bound
end
-local function cref(kind,lookupname)
- if lookupname then
- return format("feature %s, lookup %s",kind,lookupname)
+function injections.setkern(current,factor,rlmode,x,tfmchr)
+ local dx = factor*x
+ if dx ~= 0 then
+ local bound = #kerns + 1
+ set_attribute(current,kernpair,bound)
+ kerns[bound] = { rlmode, dx }
+ return dx, bound
else
- return format("feature %s",kind)
+ return 0, 0
end
end
-local function resolve_ligatures(tfmdata,ligatures,kind)
- kind = kind or "unknown"
- local unicodes = tfmdata.unicodes
- local characters = tfmdata.characters
- local descriptions = tfmdata.descriptions
- local changed = tfmdata.changed
- local done = { }
- while true do
- local ok = false
- for k,v in next, ligatures do
- local lig = v[1]
- if not done[lig] then
- local ligs = lpegmatch(split_at_space,lig)
- if #ligs == 2 then
- local uc = v[2]
- local c, f, s = characters[uc], ligs[1], ligs[2]
- local uft, ust = unicodes[f] or 0, unicodes[s] or 0
- if not uft or not ust then
- report_prepare("%s: unicode problem with base ligature %s = %s + %s",cref(kind),gref(descriptions,uc),gref(descriptions,uft),gref(descriptions,ust))
- -- some kind of error
+function injections.setmark(start,base,factor,rlmode,ba,ma,index) --ba=baseanchor, ma=markanchor
+ local dx, dy = factor*(ba[1]-ma[1]), factor*(ba[2]-ma[2])
+ local bound = has_attribute(base,markbase)
+ if bound then
+ local mb = marks[bound]
+ if mb then
+ if not index then index = #mb + 1 end
+ mb[index] = { dx, dy }
+ set_attribute(start,markmark,bound)
+ set_attribute(start,markdone,index)
+ return dx, dy, bound
+ else
+ report_injections("possible problem, U+%04X is base mark without data (id: %s)",base.char,bound)
+ end
+ end
+ index = index or 1
+ bound = #marks + 1
+ set_attribute(base,markbase,bound)
+ set_attribute(start,markmark,bound)
+ set_attribute(start,markdone,index)
+ marks[bound] = { [index] = { dx, dy, rlmode } }
+ return dx, dy, bound
+end
+
+local function dir(n)
+ return (n and n<0 and "r-to-l") or (n and n>0 and "l-to-r") or "unset"
+end
+
+local function trace(head)
+ report_injections("begin run")
+ for n in traverse_id(glyph_code,head) do
+ if n.subtype < 256 then
+ local kp = has_attribute(n,kernpair)
+ local mb = has_attribute(n,markbase)
+ local mm = has_attribute(n,markmark)
+ local md = has_attribute(n,markdone)
+ local cb = has_attribute(n,cursbase)
+ local cc = has_attribute(n,curscurs)
+ report_injections("char U+%05X, font=%s",n.char,n.font)
+ if kp then
+ local k = kerns[kp]
+ if k[3] then
+ report_injections(" pairkern: dir=%s, x=%s, y=%s, w=%s, h=%s",dir(k[1]),k[2] or "?",k[3] or "?",k[4] or "?",k[5] or "?")
+ else
+ report_injections(" kern: dir=%s, dx=%s",dir(k[1]),k[2] or "?")
+ end
+ end
+ if mb then
+ report_injections(" markbase: bound=%s",mb)
+ end
+ if mm then
+ local m = marks[mm]
+ if mb then
+ local m = m[mb]
+ if m then
+ report_injections(" markmark: bound=%s, index=%s, dx=%s, dy=%s",mm,md or "?",m[1] or "?",m[2] or "?")
else
- if type(uft) == "number" then uft = { uft } end
- if type(ust) == "number" then ust = { ust } end
- for ufi=1,#uft do
- local uf = uft[ufi]
- for usi=1,#ust do
- local us = ust[usi]
- if changed[uf] or changed[us] then
- if trace_baseinit and trace_ligatures then
- report_prepare("%s: base ligature %s + %s ignored",cref(kind),gref(descriptions,uf),gref(descriptions,us))
- end
- else
- local first, second = characters[uf], us
- if first and second then
- local t = first.ligatures
- if not t then
- t = { }
- first.ligatures = t
- end
- if type(uc) == "number" then
- t[second] = { type = 0, char = uc }
- else
- t[second] = { type = 0, char = uc[1] } -- can this still happen?
- end
- if trace_baseinit and trace_ligatures then
- report_prepare("%s: base ligature %s + %s => %s",cref(kind),gref(descriptions,uf),gref(descriptions,us),gref(descriptions,uc))
- end
- end
- end
- end
- end
+ report_injections(" markmark: bound=%s, missing index",mm)
end
- ok, done[lig] = true, descriptions[uc].name
+ else
+ m = m[1]
+ report_injections(" markmark: bound=%s, dx=%s, dy=%s",mm,m[1] or "?",m[2] or "?")
end
end
- end
- if ok then
- -- done has "a b c" = "a_b_c" and ligatures the already set ligatures: "a b" = 123
- -- and here we add extras (f i i = fi + i and alike)
- --
- -- we could use a hash for fnc and pattern
- --
- -- this might be interfering !
- for d,n in next, done do
- local pattern = pcache[d] if not pattern then pattern = "^(" .. d .. ") " pcache[d] = pattern end
- local fnc = fcache[n] if not fnc then fnc = function() return n .. " " end fcache[n] = fnc end
- for k,v in next, ligatures do
- v[1] = gsub(v[1],pattern,fnc)
- end
+ if cb then
+ report_injections(" cursbase: bound=%s",cb)
+ end
+ if cc then
+ local c = cursives[cc]
+ report_injections(" curscurs: bound=%s, dir=%s, dx=%s, dy=%s",cc,dir(c[1]),c[2] or "?",c[3] or "?")
end
- else
- break
end
end
+ report_injections("end run")
end
-local splitter = lpeg.splitat(" ")
+-- todo: reuse tables (i.e. no collection), but will be extra fields anyway
+-- todo: check for attribute
+
+-- we can have a fast test on a font being processed, so we can check faster for marks etc
-local function prepare_base_substitutions(tfmdata,kind,value) -- we can share some code with the node features
- if value then
- local otfdata = tfmdata.shared.otfdata
- local validlookups, lookuplist = otf.collectlookups(otfdata,kind,tfmdata.script,tfmdata.language)
- if validlookups then
- local ligatures = { }
- local unicodes = tfmdata.unicodes -- names to unicodes
- local indices = tfmdata.indices
- local characters = tfmdata.characters
- local descriptions = tfmdata.descriptions
- local changed = tfmdata.changed
- --
- local actions = {
- substitution = function(p,lookup,k,glyph,unicode)
- local pv = p[2] -- p.variant
- if pv then
- local upv = unicodes[pv]
- if upv then
- if type(upv) == "table" then -- zero change that table
- upv = upv[1]
+function injections.handler(head,where,keep)
+ local has_marks, has_cursives, has_kerns = next(marks), next(cursives), next(kerns)
+ if has_marks or has_cursives then
+ if trace_injections then
+ trace(head)
+ end
+ -- in the future variant we will not copy items but refs to tables
+ local done, ky, rl, valid, cx, wx, mk, nofvalid = false, { }, { }, { }, { }, { }, { }, 0
+ if has_kerns then -- move outside loop
+ local nf, tm = nil, nil
+ for n in traverse_id(glyph_code,head) do -- only needed for relevant fonts
+ if n.subtype < 256 then
+ nofvalid = nofvalid + 1
+ valid[nofvalid] = n
+ if n.font ~= nf then
+ nf = n.font
+ tm = fontdata[nf].resources.marks
+ end
+ if tm then
+ mk[n] = tm[n.char]
+ end
+ local k = has_attribute(n,kernpair)
+ if k then
+ local kk = kerns[k]
+ if kk then
+ local x, y, w, h = kk[2] or 0, kk[3] or 0, kk[4] or 0, kk[5] or 0
+ local dy = y - h
+ if dy ~= 0 then
+ ky[n] = dy
end
- if characters[upv] then
- if trace_baseinit and trace_singles then
- report_prepare("%s: base substitution %s => %s",cref(kind,lookup),gref(descriptions,k),gref(descriptions,upv))
- end
- changed[k] = upv
+ if w ~= 0 or x ~= 0 then
+ wx[n] = kk
end
+ rl[n] = kk[1] -- could move in test
end
end
- end,
- alternate = function(p,lookup,k,glyph,unicode)
- local pc = p[2] -- p.components
- if pc then
- -- a bit optimized ugliness
- if value == 1 then
- pc = lpegmatch(splitter,pc)
- elseif value == 2 then
- local a, b = lpegmatch(splitter,pc)
- pc = b or a
- else
- pc = { lpegmatch(splitter,pc) }
- pc = pc[value] or pc[#pc]
- end
- if pc then
- local upc = unicodes[pc]
- if upc then
- if type(upc) == "table" then -- zero change that table
- upc = upc[1]
- end
- if characters[upc] then
- if trace_baseinit and trace_alternatives then
- report_prepare("%s: base alternate %s %s => %s",cref(kind,lookup),tostring(value),gref(descriptions,k),gref(descriptions,upc))
+ end
+ end
+ else
+ local nf, tm = nil, nil
+ for n in traverse_id(glyph_code,head) do
+ if n.subtype < 256 then
+ nofvalid = nofvalid + 1
+ valid[nofvalid] = n
+ if n.font ~= nf then
+ nf = n.font
+ tm = fontdata[nf].resources.marks
+ end
+ if tm then
+ mk[n] = tm[n.char]
+ end
+ end
+ end
+ end
+ if nofvalid > 0 then
+ -- we can assume done == true because we have cursives and marks
+ local cx = { }
+ if has_kerns and next(ky) then
+ for n, k in next, ky do
+ n.yoffset = k
+ end
+ end
+ -- todo: reuse t and use maxt
+ if has_cursives then
+ local p_cursbase, p = nil, nil
+ -- since we need valid[n+1] we can also use a "while true do"
+ local t, d, maxt = { }, { }, 0
+ for i=1,nofvalid do -- valid == glyphs
+ local n = valid[i]
+ if not mk[n] then
+ local n_cursbase = has_attribute(n,cursbase)
+ if p_cursbase then
+ local n_curscurs = has_attribute(n,curscurs)
+ if p_cursbase == n_curscurs then
+ local c = cursives[n_curscurs]
+ if c then
+ local rlmode, dx, dy, ws, wn = c[1], c[2], c[3], c[4], c[5]
+ if rlmode >= 0 then
+ dx = dx - ws
+ else
+ dx = dx + wn
+ end
+ if dx ~= 0 then
+ cx[n] = dx
+ rl[n] = rlmode
end
- changed[k] = upc
+ -- if rlmode and rlmode < 0 then
+ dy = -dy
+ -- end
+ maxt = maxt + 1
+ t[maxt] = p
+ d[maxt] = dy
+ else
+ maxt = 0
end
end
+ elseif maxt > 0 then
+ local ny = n.yoffset
+ for i=maxt,1,-1 do
+ ny = ny + d[i]
+ local ti = t[i]
+ ti.yoffset = ti.yoffset + ny
+ end
+ maxt = 0
end
- end
- end,
- ligature = function(p,lookup,k,glyph,unicode)
- local pc = p[2]
- if pc then
- if trace_baseinit and trace_ligatures then
- local upc = { lpegmatch(splitter,pc) }
- for i=1,#upc do upc[i] = unicodes[upc[i]] end
- -- we assume that it's no table
- report_prepare("%s: base ligature %s => %s",cref(kind,lookup),gref(descriptions,upc),gref(descriptions,k))
- end
- ligatures[#ligatures+1] = { pc, k }
- end
- end,
- }
- --
- for k,c in next, characters do
- local glyph = descriptions[k]
- local lookups = glyph.slookups
- if lookups then
- for l=1,#lookuplist do
- local lookup = lookuplist[l]
- local p = lookups[lookup]
- if p then
- local a = actions[p[1]]
- if a then
- a(p,lookup,k,glyph,unicode)
+ if not n_cursbase and maxt > 0 then
+ local ny = n.yoffset
+ for i=maxt,1,-1 do
+ ny = ny + d[i]
+ local ti = t[i]
+ ti.yoffset = ny
end
+ maxt = 0
end
+ p_cursbase, p = n_cursbase, n
end
end
- local lookups = glyph.mlookups
- if lookups then
- for l=1,#lookuplist do
- local lookup = lookuplist[l]
- local ps = lookups[lookup]
- if ps then
- for i=1,#ps do
- local p = ps[i]
- local a = actions[p[1]]
- if a then
- a(p,lookup,k,glyph,unicode)
- end
- end
- end
+ if maxt > 0 then
+ local ny = n.yoffset
+ for i=maxt,1,-1 do
+ ny = ny + d[i]
+ local ti = t[i]
+ ti.yoffset = ny
end
+ maxt = 0
+ end
+ if not keep then
+ cursives = { }
end
end
- resolve_ligatures(tfmdata,ligatures,kind)
- end
- else
- tfmdata.ligatures = tfmdata.ligatures or { } -- left over from what ?
- end
-end
-
-local function preparebasekerns(tfmdata,kind,value) -- todo what kind of kerns, currently all
- if value then
- local otfdata = tfmdata.shared.otfdata
- local validlookups, lookuplist = otf.collectlookups(otfdata,kind,tfmdata.script,tfmdata.language)
- if validlookups then
- local unicodes = tfmdata.unicodes -- names to unicodes
- local indices = tfmdata.indices
- local characters = tfmdata.characters
- local descriptions = tfmdata.descriptions
- local sharedkerns = { }
- for u, chr in next, characters do
- local d = descriptions[u]
- if d then
- local dk = d.kerns -- shared
- if dk then
- local s = sharedkerns[dk]
- if s == false then
- -- skip
- elseif s then
- chr.kerns = s
- else
- local t, done = chr.kerns or { }, false
- for l=1,#lookuplist do
- local lookup = lookuplist[l]
- local kerns = dk[lookup]
- if kerns then
- for k, v in next, kerns do
- if v ~= 0 and not t[k] then -- maybe no 0 test here
- t[k], done = v, true
- if trace_baseinit and trace_kerns then
- report_prepare("%s: base kern %s + %s => %s",cref(kind,lookup),gref(descriptions,u),gref(descriptions,k),v)
- end
+ if has_marks then
+ for i=1,nofvalid do
+ local p = valid[i]
+ local p_markbase = has_attribute(p,markbase)
+ if p_markbase then
+ local mrks = marks[p_markbase]
+ for n in traverse_id(glyph_code,p.next) do
+ local n_markmark = has_attribute(n,markmark)
+ if p_markbase == n_markmark then
+ local index = has_attribute(n,markdone) or 1
+ local d = mrks[index]
+ if d then
+ local rlmode = d[3]
+ if rlmode and rlmode > 0 then
+ -- new per 2010-10-06, width adapted per 2010-02-03
+ -- we used to negate the width of marks because in tfm
+ -- that makes sense but we no longer do that so as a
+ -- consequence the sign of p.width was changed (we need
+ -- to keep an eye on it as we don't have that many fonts
+ -- that enter this branch .. i'm still not sure if this
+ -- one is right
+ local k = wx[p]
+ if k then
+ n.xoffset = p.xoffset + p.width + d[1] - k[2]
+ else
+ n.xoffset = p.xoffset + p.width + d[1]
+ end
+ else
+ local k = wx[p]
+ if k then
+ n.xoffset = p.xoffset - d[1] - k[2]
+ else
+ n.xoffset = p.xoffset - d[1]
end
end
+ if mk[p] then
+ n.yoffset = p.yoffset + d[2]
+ else
+ n.yoffset = n.yoffset + p.yoffset + d[2]
+ end
end
- end
- if done then
- sharedkerns[dk] = t
- chr.kerns = t -- no empty assignments
else
- sharedkerns[dk] = false
+ break
end
end
end
end
+ if not keep then
+ marks = { }
+ end
end
- end
- end
-end
-
--- In principle we could register each feature individually which was
--- what we did in earlier versions. However, after the rewrite it
--- made more sense to collect them in an overall features initializer
--- just as with the node variant. There it was needed because we need
--- to do complete mixed runs and not run featurewise (as we did before).
-
-local supported_gsub = {
- 'liga', 'dlig', 'rlig', 'hlig',
- 'pnum', 'onum', 'tnum', 'lnum',
- 'zero',
- 'smcp', 'cpsp', 'c2sc', 'ornm', 'aalt',
- 'hwid', 'fwid',
- 'ssty', 'rtlm', -- math
--- 'tlig', 'trep',
-}
-
-local supported_gpos = {
- 'kern'
-}
-
-function otf.features.registerbasesubstitution(tag)
- supported_gsub[#supported_gsub+1] = tag
-end
-function otf.features.registerbasekern(tag)
- supported_gsub[#supported_gpos+1] = tag
-end
-
-local basehash, basehashes = { }, 1
-
-function fonts.initializers.base.otf.features(tfmdata,value)
- if true then -- value then
- -- not shared
- local t = trace_preparing and os.clock()
- local features = tfmdata.shared.features
- if features then
- local h = { }
- for f=1,#supported_gsub do
- local feature = supported_gsub[f]
- local value = features[feature]
- prepare_base_substitutions(tfmdata,feature,value)
- if value then
- h[#h+1] = feature .. "=" .. tostring(value)
+ -- todo : combine
+ if next(wx) then
+ for n, k in next, wx do
+ -- only w can be nil, can be sped up when w == nil
+ local rl, x, w, r2l = k[1], k[2] or 0, k[4] or 0, k[6]
+ local wx = w - x
+ if r2l then
+ if wx ~= 0 then
+ insert_node_before(head,n,newkern(wx))
+ end
+ if x ~= 0 then
+ insert_node_after (head,n,newkern(x))
+ end
+ else
+ if x ~= 0 then
+ insert_node_before(head,n,newkern(x))
+ end
+ if wx ~= 0 then
+ insert_node_after(head,n,newkern(wx))
+ end
+ end
end
end
- for f=1,#supported_gpos do
- local feature = supported_gpos[f]
- local value = features[feature]
- preparebasekerns(tfmdata,feature,features[feature])
- if value then
- h[#h+1] = feature .. "=" .. tostring(value)
+ if next(cx) then
+ for n, k in next, cx do
+ if k ~= 0 then
+ local rln = rl[n]
+ if rln and rln < 0 then
+ insert_node_before(head,n,newkern(-k))
+ else
+ insert_node_before(head,n,newkern(k))
+ end
+ end
end
end
- local hash = concat(h," ")
- local base = basehash[hash]
- if not base then
- basehashes = basehashes + 1
- base = basehashes
- basehash[hash] = base
+ if not keep then
+ kerns = { }
end
- -- We need to make sure that luatex sees the difference between
- -- base fonts that have different glyphs in the same slots in fonts
- -- that have the same fullname (or filename). LuaTeX will merge fonts
- -- eventually (and subset later on). If needed we can use a more
- -- verbose name as long as we don't use <()<>[]{}/%> and the length
- -- is < 128.
- tfmdata.fullname = tfmdata.fullname .. "-" .. base -- tfmdata.psname is the original
- --~ report_prepare("fullname base hash: '%s', featureset '%s'",tfmdata.fullname,hash)
+ return head, true
+ elseif not keep then
+ kerns, cursives, marks = { }, { }, { }
end
- if trace_preparing then
- report_prepare("preparation time is %0.3f seconds for %s",os.clock()-t,tfmdata.fullname or "?")
+ elseif has_kerns then
+ if trace_injections then
+ trace(head)
+ end
+ for n in traverse_id(glyph_code,head) do
+ if n.subtype < 256 then
+ local k = has_attribute(n,kernpair)
+ if k then
+ local kk = kerns[k]
+ if kk then
+ local rl, x, y, w = kk[1], kk[2] or 0, kk[3], kk[4]
+ if y and y ~= 0 then
+ n.yoffset = y -- todo: h ?
+ end
+ if w then
+ -- copied from above
+ local r2l = kk[6]
+ local wx = w - x
+ if r2l then
+ if wx ~= 0 then
+ insert_node_before(head,n,newkern(wx))
+ end
+ if x ~= 0 then
+ insert_node_after (head,n,newkern(x))
+ end
+ else
+ if x ~= 0 then
+ insert_node_before(head,n,newkern(x))
+ end
+ if wx ~= 0 then
+ insert_node_after(head,n,newkern(wx))
+ end
+ end
+ else
+ -- simple (e.g. kernclass kerns)
+ if x ~= 0 then
+ insert_node_before(head,n,newkern(x))
+ end
+ end
+ end
+ end
+ end
+ end
+ if not keep then
+ kerns = { }
end
+ return head, true
+ else
+ -- no tracing needed
end
+ return head, false
end
end -- closure
@@ -8250,14 +7736,6 @@ if not modules then modules = { } end modules ['font-otn'] = {
-- much functionality could only be implemented thanks to the husayni font
-- of Idris Samawi Hamid to who we dedicate this module.
--- I'm in the process of cleaning up the code (which happens in another
--- file) so don't rely on things staying the same.
-
--- some day when we can jit this, we can use more functions
-
--- we can use more lpegs when lpeg is extended with function args and so
--- resolving to unicode does not gain much
-
-- in retrospect it always looks easy but believe it or not, it took a lot
-- of work to get proper open type support done: buggy fonts, fuzzy specs,
-- special made testfonts, many skype sessions between taco, idris and me,
@@ -8272,10 +7750,7 @@ if not modules then modules = { } end modules ['font-otn'] = {
-- alternative loop quitters
-- check cursive and r2l
-- find out where ignore-mark-classes went
--- remove unused tables
--- slide tail (always glue at the end so only needed once
-- default features (per language, script)
--- cleanup kern(class) code, remove double info
-- handle positions (we need example fonts)
-- handle gpos_single (we might want an extra width field in glyph nodes because adding kerns might interfere)
@@ -8351,6 +7826,8 @@ results in different tables.</p>
-- gpos_context ok --
-- gpos_contextchain ok --
--
+-- todo: contextpos and contextsub and class stuff
+--
-- actions:
--
-- handler : actions triggered by lookup
@@ -8360,16 +7837,20 @@ results in different tables.</p>
-- remark: the 'not implemented yet' variants will be done when we have fonts that use them
-- remark: we need to check what to do with discretionaries
+-- We used to have independent hashes for lookups but as the tags are unique
+-- we now use only one hash. If needed we can have multiple again but in that
+-- case I will probably prefix (i.e. rename) the lookups in the cached font file.
+
local concat, insert, remove = table.concat, 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 = type, next, tonumber, tostring
local lpegmatch = lpeg.match
local random = math.random
-local logs, trackers, fonts, nodes, attributes = logs, trackers, fonts, nodes, attributes
+local logs, trackers, nodes, attributes = logs, trackers, nodes, attributes
-local otf = fonts.otf
-local tfm = fonts.tfm
+local fonts = fonts
+local otf = fonts.handlers.otf
local trace_lookups = false trackers.register("otf.lookups", function(v) trace_lookups = v end)
local trace_singles = false trackers.register("otf.singles", function(v) trace_singles = v end)
@@ -8404,93 +7885,82 @@ trackers.register("otf.injections","nodes.injections")
trackers.register("*otf.sample","otf.steps,otf.actions,otf.analyzing")
-local insert_node_after = node.insert_after
-local delete_node = nodes.delete
-local copy_node = node.copy
-local find_node_tail = node.tail or node.slide
-local set_attribute = node.set_attribute
-local has_attribute = node.has_attribute
+local insert_node_after = node.insert_after
+local delete_node = nodes.delete
+local copy_node = node.copy
+local find_node_tail = node.tail or node.slide
+local set_attribute = node.set_attribute
+local has_attribute = node.has_attribute
-local zwnj = 0x200C
-local zwj = 0x200D
-local wildcard = "*"
-local default = "dflt"
+local zwnj = 0x200C
+local zwj = 0x200D
+local wildcard = "*"
+local default = "dflt"
-local split_at_space = lpeg.Ct(lpeg.splitat(" ")) -- no trailing or multiple spaces anyway
+local nodecodes = nodes.nodecodes
+local whatcodes = nodes.whatcodes
+local glyphcodes = nodes.glyphcodes
-local nodecodes = nodes.nodecodes
-local whatcodes = nodes.whatcodes
-local glyphcodes = nodes.glyphcodes
+local glyph_code = nodecodes.glyph
+local glue_code = nodecodes.glue
+local disc_code = nodecodes.disc
+local whatsit_code = nodecodes.whatsit
-local glyph_code = nodecodes.glyph
-local glue_code = nodecodes.glue
-local disc_code = nodecodes.disc
-local whatsit_code = nodecodes.whatsit
+local dir_code = whatcodes.dir
+local localpar_code = whatcodes.localpar
-local dir_code = whatcodes.dir
-local localpar_code = whatcodes.localpar
+local ligature_code = glyphcodes.ligature
-local ligature_code = glyphcodes.ligature
+local privateattribute = attributes.private
-local state = attributes.private('state')
-local markbase = attributes.private('markbase')
-local markmark = attributes.private('markmark')
-local markdone = attributes.private('markdone')
-local cursbase = attributes.private('cursbase')
-local curscurs = attributes.private('curscurs')
-local cursdone = attributes.private('cursdone')
-local kernpair = attributes.private('kernpair')
+local state = privateattribute('state')
+local markbase = privateattribute('markbase')
+local markmark = privateattribute('markmark')
+local markdone = privateattribute('markdone')
+local cursbase = privateattribute('cursbase')
+local curscurs = privateattribute('curscurs')
+local cursdone = privateattribute('cursdone')
+local kernpair = privateattribute('kernpair')
-local injections = nodes.injections
-local setmark = injections.setmark
-local setcursive = injections.setcursive
-local setkern = injections.setkern
-local setpair = injections.setpair
+local injections = nodes.injections
+local setmark = injections.setmark
+local setcursive = injections.setcursive
+local setkern = injections.setkern
+local setpair = injections.setpair
+
+local markonce = true
+local cursonce = true
+local kernonce = true
-local markonce = true
-local cursonce = true
-local kernonce = true
+local fonthashes = fonts.hashes
+local fontdata = fonthashes.identifiers
-local fontdata = fonts.identifiers
+local otffeatures = fonts.constructors.newfeatures("otf")
+local registerotffeature = otffeatures.register
-otf.features.process = { }
+local onetimemessage = fonts.loggers.onetimemessage
-- we share some vars here, after all, we have no nested lookups and
-- less code
-local tfmdata = false
-local otfdata = false
-local characters = false
-local descriptions = false
-local marks = false
-local indices = false
-local unicodes = false
-local currentfont = false
-local lookuptable = false
-local anchorlookups = false
-local handlers = { }
-local rlmode = 0
-local featurevalue = false
-
--- we cheat a bit and assume that a font,attr combination are kind of ranged
-
-local specifiers = fonts.definers.specifiers
-local contextsetups = specifiers.contextsetups
-local contextnumbers = specifiers.contextnumbers
-local contextmerged = specifiers.contextmerged
+local tfmdata = false
+local characters = false
+local descriptions = false
+local resources = false
+local marks = false
+local currentfont = false
+local lookuptable = false
+local anchorlookups = false
+local lookuptypes = false
+local handlers = { }
+local rlmode = 0
+local featurevalue = false
-- we cannot optimize with "start = first_glyph(head)" because then we don't
-- know which rlmode we're in which messes up cursive handling later on
--
-- head is always a whatsit so we can safely assume that head is not changed
-local special_attributes = {
- init = 1,
- medi = 2,
- fina = 3,
- isol = 4
-}
-
-- we use this for special testing and documentation
local checkstep = (nodes and nodes.tracers and nodes.tracers.steppers.check) or function() end
@@ -8503,6 +7973,7 @@ local function logprocess(...)
end
report_direct(...)
end
+
local function logwarning(...)
report_direct(...)
end
@@ -8522,9 +7993,11 @@ local function gref(n)
local num, nam = { }, { }
for i=1,#n do
local ni = n[i]
- local di = descriptions[ni]
- num[i] = format("U+%04X",ni)
- nam[i] = di and di.name or "?"
+ if tonumber(di) then -- later we will start at 2
+ local di = descriptions[ni]
+ num[i] = format("U+%04X",ni)
+ nam[i] = di and di.name or "?"
+ end
end
return format("%s (%s)",concat(num," "), concat(nam," "))
end
@@ -8567,84 +8040,72 @@ local function markstoligature(kind,lookupname,start,stop,char)
end
local function toligature(kind,lookupname,start,stop,char,markflag,discfound) -- brr head
- if start ~= stop then
---~ if discfound then
---~ local lignode = copy_node(start)
---~ lignode.font = start.font
---~ lignode.char = char
---~ lignode.subtype = ligature_code
---~ start = node.do_ligature_n(start, stop, lignode)
---~ if start.id == disc_code then
---~ local prev = start.prev
---~ start = start.next
---~ end
- if discfound then
- -- print("start->stop",nodes.tosequence(start,stop))
- local lignode = copy_node(start)
- lignode.font, lignode.char, lignode.subtype = start.font, char, ligature_code
- local next, prev = stop.next, start.prev
- stop.next = nil
- lignode = node.do_ligature_n(start, stop, lignode)
- prev.next = lignode
- if next then
- next.prev = lignode
- end
- lignode.next, lignode.prev = next, prev
- start = lignode
- -- print("start->end",nodes.tosequence(start))
- else -- start is the ligature
- local deletemarks = markflag ~= "mark"
- local n = copy_node(start)
- local current
- current, start = insert_node_after(start,start,n)
- local snext = stop.next
- current.next = snext
- if snext then
- snext.prev = current
- end
- start.prev, stop.next = nil, nil
- current.char, current.subtype, current.components = char, ligature_code, start
- local head = current
- if deletemarks then
- if trace_marks then
- while start do
- if marks[start.char] then
- logwarning("%s: remove mark %s",pref(kind,lookupname),gref(start.char))
- end
- start = start.next
- end
- end
- else
- local i = 0
+ if start == stop then
+ start.char = char
+ elseif discfound then
+ -- print("start->stop",nodes.tosequence(start,stop))
+ local lignode = copy_node(start)
+ lignode.font, lignode.char, lignode.subtype = start.font, char, ligature_code
+ local next, prev = stop.next, start.prev
+ stop.next = nil
+ lignode = node.do_ligature_n(start, stop, lignode)
+ prev.next = lignode
+ if next then
+ next.prev = lignode
+ end
+ lignode.next, lignode.prev = next, prev
+ start = lignode
+ -- print("start->end",nodes.tosequence(start))
+ else -- start is the ligature
+ local deletemarks = markflag ~= "mark"
+ local n = copy_node(start)
+ local current
+ current, start = insert_node_after(start,start,n)
+ local snext = stop.next
+ current.next = snext
+ if snext then
+ snext.prev = current
+ end
+ start.prev, stop.next = nil, nil
+ current.char, current.subtype, current.components = char, ligature_code, start
+ local head = current
+ if deletemarks then
+ if trace_marks then
while start do
if marks[start.char] then
- set_attribute(start,markdone,i)
- if trace_marks then
- logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i)
- end
- head, current = insert_node_after(head,current,copy_node(start))
- else
- i = i + 1
+ logwarning("%s: remove mark %s",pref(kind,lookupname),gref(start.char))
end
start = start.next
end
- start = current.next
- while start and start.id == glyph_code do
- if marks[start.char] then
- set_attribute(start,markdone,i)
- if trace_marks then
- logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i)
- end
- else
- break
+ end
+ else
+ local i = 0
+ while start do
+ if marks[start.char] then
+ set_attribute(start,markdone,i)
+ if trace_marks then
+ logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i)
+ end
+ head, current = insert_node_after(head,current,copy_node(start))
+ else
+ i = i + 1
+ end
+ start = start.next
+ end
+ start = current.next
+ while start and start.id == glyph_code do
+ if marks[start.char] then
+ set_attribute(start,markdone,i)
+ if trace_marks then
+ logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i)
end
- start = start.next
+ else
+ break
end
+ start = start.next
end
- return head
end
- else
- start.char = char
+ return head
end
return start
end
@@ -8687,6 +8148,30 @@ local function alternative_glyph(start,alternatives,kind,chainname,chainlookupna
return choice, value
end
+local function multiple_glyphs(start,multiple)
+ local nofmultiples = #multiple
+ if nofmultiples > 0 then
+ start.char = multiple[1]
+ if nofmultiples > 1 then
+ local sn = start.next
+ for k=2,nofmultiples do -- todo: use insert_node
+ local n = copy_node(start)
+ n.char = multiple[k]
+ n.next = sn
+ n.prev = start
+ if sn then
+ sn.prev = n
+ end
+ start.next = n
+ start = n
+ end
+ end
+ return start, true
+ else
+ return start, false
+ end
+end
+
function handlers.gsub_alternate(start,kind,lookupname,alternative,sequence)
local choice, index = alternative_glyph(start,alternative,kind,lookupname)
if trace_alternatives then
@@ -8700,22 +8185,7 @@ function handlers.gsub_multiple(start,kind,lookupname,multiple)
if trace_multiples then
logprocess("%s: replacing %s by multiple %s",pref(kind,lookupname),gref(start.char),gref(multiple))
end
- start.char = multiple[1]
- if #multiple > 1 then
- for k=2,#multiple do
- local n = copy_node(start)
- n.char = multiple[k]
- local sn = start.next
- n.next = sn
- n.prev = start
- if sn then
- sn.prev = n
- end
- start.next = n
- start = n
- end
- end
- return start, true
+ return multiple_glyphs(start,multiple)
end
function handlers.gsub_ligature(start,kind,lookupname,ligature,sequence) --or maybe pass lookup ref
@@ -8724,17 +8194,12 @@ function handlers.gsub_ligature(start,kind,lookupname,ligature,sequence) --or ma
if marks[startchar] then
while s do
local id = s.id
- if id == glyph_code and s.subtype<256 then
- if s.font == currentfont then
- local char = s.char
- local lg = ligature[1][char]
- if not lg then
- break
- else
- stop = s
- ligature = lg
- s = s.next
- end
+ if id == glyph_code and s.subtype<256 and s.font == currentfont then
+ local lg = ligature[s.char]
+ if lg then
+ stop = s
+ ligature = lg
+ s = s.next
else
break
end
@@ -8742,13 +8207,14 @@ function handlers.gsub_ligature(start,kind,lookupname,ligature,sequence) --or ma
break
end
end
- if stop and ligature[2] then
+ if stop then
+ local lig = ligature.ligature
if trace_ligatures then
local stopchar = stop.char
- start = markstoligature(kind,lookupname,start,stop,ligature[2])
+ start = markstoligature(kind,lookupname,start,stop,lig)
logprocess("%s: replacing %s upto %s by ligature %s",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char))
else
- start = markstoligature(kind,lookupname,start,stop,ligature[2])
+ start = markstoligature(kind,lookupname,start,stop,lig)
end
return start, true
end
@@ -8762,13 +8228,13 @@ function handlers.gsub_ligature(start,kind,lookupname,ligature,sequence) --or ma
if skipmark and marks[char] then
s = s.next
else
- local lg = ligature[1][char]
- if not lg then
- break
- else
+ local lg = ligature[char]
+ if lg then
stop = s
ligature = lg
s = s.next
+ else
+ break
end
end
else
@@ -8781,13 +8247,14 @@ function handlers.gsub_ligature(start,kind,lookupname,ligature,sequence) --or ma
break
end
end
- if stop and ligature[2] then
+ if stop then
+ local lig = ligature.ligature
if trace_ligatures then
local stopchar = stop.char
- start = toligature(kind,lookupname,start,stop,ligature[2],skipmark,discfound)
+ start = toligature(kind,lookupname,start,stop,lig,skipmark,discfound)
logprocess("%s: replacing %s upto %s by ligature %s",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char))
else
- start = toligature(kind,lookupname,start,stop,ligature[2],skipmark,discfound)
+ start = toligature(kind,lookupname,start,stop,lig,skipmark,discfound)
end
return start, true
end
@@ -8834,7 +8301,7 @@ function handlers.gpos_mark2base(start,kind,lookupname,markanchors,sequence)
if al[anchor] then
local ma = markanchors[anchor]
if ma then
- local dx, dy, bound = setmark(start,base,tfmdata.factor,rlmode,ba,ma)
+ local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma)
if trace_marks then
logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%s,%s)",
pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
@@ -8849,7 +8316,7 @@ function handlers.gpos_mark2base(start,kind,lookupname,markanchors,sequence)
end
else -- if trace_bugs then
-- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar))
- fonts.registermessage(currentfont,basechar,"no base anchors")
+ onetimemessage(currentfont,basechar,"no base anchors",report_fonts)
end
elseif trace_bugs then
logwarning("%s: prev node is no char",pref(kind,lookupname))
@@ -8902,7 +8369,7 @@ function handlers.gpos_mark2ligature(start,kind,lookupname,markanchors,sequence)
if ma then
ba = ba[index]
if ba then
- local dx, dy, bound = setmark(start,base,tfmdata.factor,rlmode,ba,ma,index)
+ local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,index)
if trace_marks then
logprocess("%s, anchor %s, index %s, bound %s: anchoring mark %s to baselig %s at index %s => (%s,%s)",
pref(kind,lookupname),anchor,index,bound,gref(markchar),gref(basechar),index,dx,dy)
@@ -8919,7 +8386,7 @@ function handlers.gpos_mark2ligature(start,kind,lookupname,markanchors,sequence)
end
else -- if trace_bugs then
-- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar))
- fonts.registermessage(currentfont,basechar,"no base anchors")
+ onetimemessage(currentfont,basechar,"no base anchors",report_fonts)
end
elseif trace_bugs then
logwarning("%s: prev node is no char",pref(kind,lookupname))
@@ -8949,7 +8416,7 @@ function handlers.gpos_mark2mark(start,kind,lookupname,markanchors,sequence)
if al[anchor] then
local ma = markanchors[anchor]
if ma then
- local dx, dy, bound = setmark(start,base,tfmdata.factor,rlmode,ba,ma)
+ local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma)
if trace_marks then
logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%s,%s)",
pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
@@ -8965,7 +8432,7 @@ function handlers.gpos_mark2mark(start,kind,lookupname,markanchors,sequence)
end
else -- if trace_bugs then
-- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar))
- fonts.registermessage(currentfont,basechar,"no base anchors")
+ onetimemessage(currentfont,basechar,"no base anchors",report_fonts)
end
elseif trace_bugs then
logwarning("%s: prev node is no mark",pref(kind,lookupname))
@@ -9007,7 +8474,7 @@ function handlers.gpos_cursive(start,kind,lookupname,exitanchors,sequence) -- to
if al[anchor] then
local exit = exitanchors[anchor]
if exit then
- local dx, dy, bound = setcursive(start,nxt,tfmdata.factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
+ local dx, dy, bound = setcursive(start,nxt,tfmdata.parameters.factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
if trace_cursive then
logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode)
end
@@ -9020,7 +8487,7 @@ function handlers.gpos_cursive(start,kind,lookupname,exitanchors,sequence) -- to
end
else -- if trace_bugs then
-- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(startchar))
- fonts.registermessage(currentfont,startchar,"no entry anchors")
+ onetimemessage(currentfont,startchar,"no entry anchors",report_fonts)
end
break
end
@@ -9037,7 +8504,8 @@ end
function handlers.gpos_single(start,kind,lookupname,kerns,sequence)
local startchar = start.char
- local dx, dy, w, h = setpair(start,tfmdata.factor,rlmode,sequence.flags[4],kerns,characters[startchar])
+ local kerns = kerns[start.char]
+ local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar])
if trace_kerns then
logprocess("%s: shifting single %s by (%s,%s) and correction (%s,%s)",pref(kind,lookupname),gref(startchar),dx,dy,w,h)
end
@@ -9052,7 +8520,8 @@ function handlers.gpos_pair(start,kind,lookupname,kerns,sequence)
return start, false
else
local prev, done = start, false
- local factor = tfmdata.factor
+ local factor = tfmdata.parameters.factor
+ local lookuptype = lookuptypes[lookupname]
while snext and snext.id == glyph_code and snext.subtype<256 and snext.font == currentfont do
local nextchar = snext.char
local krn = kerns[nextchar]
@@ -9064,8 +8533,8 @@ function handlers.gpos_pair(start,kind,lookupname,kerns,sequence)
if not krn then
-- skip
elseif type(krn) == "table" then
- if krn[1] == "pair" then
- local a, b = krn[3], krn[4]
+ if lookuptype == "pair" then -- probably not needed
+ local a, b = krn[2], krn[3]
if a and #a > 0 then
local startchar = start.char
local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar])
@@ -9080,18 +8549,18 @@ function handlers.gpos_pair(start,kind,lookupname,kerns,sequence)
logprocess("%s: shifting second of pair %s and %s by (%s,%s) and correction (%s,%s)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
end
end
- else
+ else -- wrong ... position has different entries
report_process("%s: check this out (old kern stuff)",pref(kind,lookupname))
- local a, b = krn[3], krn[7]
- if a and a ~= 0 then
- local k = setkern(snext,factor,rlmode,a)
- if trace_kerns then
- logprocess("%s: inserting first kern %s between %s and %s",pref(kind,lookupname),k,gref(prev.char),gref(nextchar))
- end
- end
- if b and b ~= 0 then
- logwarning("%s: ignoring second kern xoff %s",pref(kind,lookupname),b*factor)
- end
+ -- local a, b = krn[2], krn[6]
+ -- if a and a ~= 0 then
+ -- local k = setkern(snext,factor,rlmode,a)
+ -- if trace_kerns then
+ -- logprocess("%s: inserting first kern %s between %s and %s",pref(kind,lookupname),k,gref(prev.char),gref(nextchar))
+ -- end
+ -- end
+ -- if b and b ~= 0 then
+ -- logwarning("%s: ignoring second kern xoff %s",pref(kind,lookupname),b*factor)
+ -- end
end
done = true
elseif krn ~= 0 then
@@ -9125,37 +8594,31 @@ end
local logwarning = report_subchain
--- ['coverage']={
--- ['after']={ "r" },
--- ['before']={ "q" },
--- ['current']={ "a", "b", "c" },
--- },
--- ['lookups']={ "ls_l_1", "ls_l_1", "ls_l_1" },
-
-function chainmores.chainsub(start,stop,kind,chainname,currentcontext,cache,lookuplist,chainlookupname,n)
+function chainmores.chainsub(start,stop,kind,chainname,currentcontext,lookuphash,lookuplist,chainlookupname,n)
logprocess("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname))
return start, false
end
-- handled later:
--
--- function chainmores.gsub_single(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
--- return chainprocs.gsub_single(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+-- function chainmores.gsub_single(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,n)
+-- return chainprocs.gsub_single(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,n)
-- end
-function chainmores.gsub_multiple(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+function chainmores.gsub_multiple(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,n)
logprocess("%s: gsub_multiple not yet supported",cref(kind,chainname,chainlookupname))
return start, false
end
-function chainmores.gsub_alternate(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+
+function chainmores.gsub_alternate(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,n)
logprocess("%s: gsub_alternate not yet supported",cref(kind,chainname,chainlookupname))
return start, false
end
-- handled later:
--
--- function chainmores.gsub_ligature(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
--- return chainprocs.gsub_ligature(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+-- function chainmores.gsub_ligature(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,n)
+-- return chainprocs.gsub_ligature(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,n)
-- end
local function logprocess(...)
@@ -9170,7 +8633,7 @@ local logwarning = report_chain
-- We could share functions but that would lead to extra function calls with many
-- arguments, redundant tests and confusing messages.
-function chainprocs.chainsub(start,stop,kind,chainname,currentcontext,cache,lookuplist,chainlookupname)
+function chainprocs.chainsub(start,stop,kind,chainname,currentcontext,lookuphash,lookuplist,chainlookupname)
logwarning("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname))
return start, false
end
@@ -9179,7 +8642,7 @@ end
-- in a bit weird way. There is no lookup and the replacement comes from the lookup
-- itself. It is meant mostly for dealing with Urdu.
-function chainprocs.reversesub(start,stop,kind,chainname,currentcontext,cache,replacements)
+function chainprocs.reversesub(start,stop,kind,chainname,currentcontext,lookuphash,replacements)
local char = start.char
local replacement = replacements[char]
if replacement then
@@ -9225,18 +8688,21 @@ end
match.</p>
--ldx]]--
-function chainprocs.gsub_single(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,chainindex)
+function chainprocs.gsub_single(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex)
-- todo: marks ?
if not chainindex then
- delete_till_stop(start,stop) -- ,currentlookup.flags[1])
+ delete_till_stop(start,stop) -- ,currentlookup.flags[1]
end
local current = start
local subtables = currentlookup.subtables
+if #subtables > 1 then
+ log_warning("todo: check if we need to loop over the replacements: %s",concat(subtables," "))
+end
while current do
if current.id == glyph_code then
local currentchar = current.char
local lookupname = subtables[1]
- local replacement = cache.gsub_single[lookupname]
+ local replacement = lookuphash[lookupname]
if not replacement then
if trace_bugs then
logwarning("%s: no single hits",cref(kind,chainname,chainlookupname,lookupname,chainindex))
@@ -9271,12 +8737,12 @@ chainmores.gsub_single = chainprocs.gsub_single
the match.</p>
--ldx]]--
-function chainprocs.gsub_multiple(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+function chainprocs.gsub_multiple(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
delete_till_stop(start,stop)
local startchar = start.char
local subtables = currentlookup.subtables
local lookupname = subtables[1]
- local replacements = cache.gsub_multiple[lookupname]
+ local replacements = lookuphash[lookupname]
if not replacements then
if trace_bugs then
logwarning("%s: no multiple hits",cref(kind,chainname,chainlookupname,lookupname))
@@ -9291,21 +8757,7 @@ function chainprocs.gsub_multiple(start,stop,kind,chainname,currentcontext,cache
if trace_multiples then
logprocess("%s: replacing %s by multiple characters %s",cref(kind,chainname,chainlookupname,lookupname),gref(startchar),gref(replacements))
end
- local sn = start.next
- for k=1,#replacements do
- if k == 1 then
- start.char = replacements[k]
- else
- local n = copy_node(start) -- maybe delete the components and such
- n.char = replacements[k]
- n.next, n.prev = sn, start
- if sn then
- sn.prev = n
- end
- start.next, start = n, n
- end
- end
- return start, true
+ return multiple_glyphs(start,replacements)
end
end
return start, false
@@ -9315,7 +8767,7 @@ end
<p>Here we replace start by new glyph. First we delete the rest of the match.</p>
--ldx]]--
-function chainprocs.gsub_alternate(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+function chainprocs.gsub_alternate(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
-- todo: marks ?
delete_till_stop(start,stop)
local current = start
@@ -9324,7 +8776,7 @@ function chainprocs.gsub_alternate(start,stop,kind,chainname,currentcontext,cach
if current.id == glyph_code then
local currentchar = current.char
local lookupname = subtables[1]
- local alternatives = cache.gsub_alternate[lookupname]
+ local alternatives = lookuphash[lookupname]
if not alternatives then
if trace_bugs then
logwarning("%s: no alternative hits",cref(kind,chainname,chainlookupname,lookupname))
@@ -9359,11 +8811,11 @@ this function (move code inline and handle the marks by a separate function). We
assume rather stupid ligatures (no complex disc nodes).</p>
--ldx]]--
-function chainprocs.gsub_ligature(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,chainindex)
+function chainprocs.gsub_ligature(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex)
local startchar = start.char
local subtables = currentlookup.subtables
local lookupname = subtables[1]
- local ligatures = cache.gsub_ligature[lookupname]
+ local ligatures = lookuphash[lookupname]
if not ligatures then
if trace_bugs then
logwarning("%s: no ligature hits",cref(kind,chainname,chainlookupname,lookupname,chainindex))
@@ -9386,21 +8838,21 @@ function chainprocs.gsub_ligature(start,stop,kind,chainname,currentcontext,cache
if marks[schar] then -- marks
s = s.next
else
- local lg = ligatures[1][schar]
- if not lg then
- break
- else
+ local lg = ligatures[schar]
+ if lg then
ligatures, last, nofreplacements = lg, s, nofreplacements + 1
if s == stop then
break
else
s = s.next
end
+ else
+ break
end
end
end
end
- local l2 = ligatures[2]
+ local l2 = ligatures.ligature
if l2 then
if chainindex then
stop = last
@@ -9428,12 +8880,12 @@ end
chainmores.gsub_ligature = chainprocs.gsub_ligature
-function chainprocs.gpos_mark2base(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+function chainprocs.gpos_mark2base(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
local markchar = start.char
if marks[markchar] then
local subtables = currentlookup.subtables
local lookupname = subtables[1]
- local markanchors = cache.gpos_mark2base[lookupname]
+ local markanchors = lookuphash[lookupname]
if markanchors then
markanchors = markanchors[markchar]
end
@@ -9466,7 +8918,7 @@ function chainprocs.gpos_mark2base(start,stop,kind,chainname,currentcontext,cach
if al[anchor] then
local ma = markanchors[anchor]
if ma then
- local dx, dy, bound = setmark(start,base,tfmdata.factor,rlmode,ba,ma)
+ local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma)
if trace_marks then
logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%s,%s)",
cref(kind,chainname,chainlookupname,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
@@ -9492,12 +8944,12 @@ function chainprocs.gpos_mark2base(start,stop,kind,chainname,currentcontext,cach
return start, false
end
-function chainprocs.gpos_mark2ligature(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+function chainprocs.gpos_mark2ligature(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
local markchar = start.char
if marks[markchar] then
local subtables = currentlookup.subtables
local lookupname = subtables[1]
- local markanchors = cache.gpos_mark2ligature[lookupname]
+ local markanchors = lookuphash[lookupname]
if markanchors then
markanchors = markanchors[markchar]
end
@@ -9539,7 +8991,7 @@ function chainprocs.gpos_mark2ligature(start,stop,kind,chainname,currentcontext,
if ma then
ba = ba[index]
if ba then
- local dx, dy, bound = setmark(start,base,tfmdata.factor,rlmode,ba,ma,index)
+ local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,index)
if trace_marks then
logprocess("%s, anchor %s, bound %s: anchoring mark %s to baselig %s at index %s => (%s,%s)",
cref(kind,chainname,chainlookupname,lookupname),anchor,a or bound,gref(markchar),gref(basechar),index,dx,dy)
@@ -9566,7 +9018,7 @@ function chainprocs.gpos_mark2ligature(start,stop,kind,chainname,currentcontext,
return start, false
end
-function chainprocs.gpos_mark2mark(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+function chainprocs.gpos_mark2mark(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
local markchar = start.char
if marks[markchar] then
--~ local alreadydone = markonce and has_attribute(start,markmark)
@@ -9574,7 +9026,7 @@ function chainprocs.gpos_mark2mark(start,stop,kind,chainname,currentcontext,cach
-- local markanchors = descriptions[markchar].anchors markanchors = markanchors and markanchors.mark
local subtables = currentlookup.subtables
local lookupname = subtables[1]
- local markanchors = cache.gpos_mark2mark[lookupname]
+ local markanchors = lookuphash[lookupname]
if markanchors then
markanchors = markanchors[markchar]
end
@@ -9591,7 +9043,7 @@ function chainprocs.gpos_mark2mark(start,stop,kind,chainname,currentcontext,cach
if al[anchor] then
local ma = markanchors[anchor]
if ma then
- local dx, dy, bound = setmark(start,base,tfmdata.factor,rlmode,ba,ma)
+ local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma)
if trace_marks then
logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%s,%s)",
cref(kind,chainname,chainlookupname,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
@@ -9622,13 +9074,13 @@ end
-- ! ! ! untested ! ! !
-function chainprocs.gpos_cursive(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+function chainprocs.gpos_cursive(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
local alreadydone = cursonce and has_attribute(start,cursbase)
if not alreadydone then
local startchar = start.char
local subtables = currentlookup.subtables
local lookupname = subtables[1]
- local exitanchors = cache.gpos_cursive[lookupname]
+ local exitanchors = lookuphash[lookupname]
if exitanchors then
exitanchors = exitanchors[startchar]
end
@@ -9657,7 +9109,7 @@ function chainprocs.gpos_cursive(start,stop,kind,chainname,currentcontext,cache,
if al[anchor] then
local exit = exitanchors[anchor]
if exit then
- local dx, dy, bound = setcursive(start,nxt,tfmdata.factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
+ local dx, dy, bound = setcursive(start,nxt,tfmdata.parameters.factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
if trace_cursive then
logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode)
end
@@ -9670,7 +9122,7 @@ function chainprocs.gpos_cursive(start,stop,kind,chainname,currentcontext,cache,
end
else -- if trace_bugs then
-- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(startchar))
- fonts.registermessage(currentfont,startchar,"no entry anchors")
+ onetimemessage(currentfont,startchar,"no entry anchors",report_fonts)
end
break
end
@@ -9687,16 +9139,16 @@ function chainprocs.gpos_cursive(start,stop,kind,chainname,currentcontext,cache,
return start, false
end
-function chainprocs.gpos_single(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,chainindex,sequence)
- -- untested
+function chainprocs.gpos_single(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence)
+ -- untested .. needs checking for the new model
local startchar = start.char
local subtables = currentlookup.subtables
local lookupname = subtables[1]
- local kerns = cache.gpos_single[lookupname]
+ local kerns = lookuphash[lookupname]
if kerns then
kerns = kerns[startchar]
if kerns then
- local dx, dy, w, h = setpair(start,tfmdata.factor,rlmode,sequence.flags[4],kerns,characters[startchar])
+ local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar])
if trace_kerns then
logprocess("%s: shifting single %s by (%s,%s) and correction (%s,%s)",cref(kind,chainname,chainlookupname),gref(startchar),dx,dy,w,h)
end
@@ -9707,19 +9159,20 @@ end
-- when machines become faster i will make a shared function
-function chainprocs.gpos_pair(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,chainindex,sequence)
+function chainprocs.gpos_pair(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence)
-- logwarning("%s: gpos_pair not yet supported",cref(kind,chainname,chainlookupname))
local snext = start.next
if snext then
local startchar = start.char
local subtables = currentlookup.subtables
local lookupname = subtables[1]
- local kerns = cache.gpos_pair[lookupname]
+ local kerns = lookuphash[lookupname]
if kerns then
kerns = kerns[startchar]
if kerns then
+ local lookuptype = lookuptypes[lookupname]
local prev, done = start, false
- local factor = tfmdata.factor
+ local factor = tfmdata.parameters.factor
while snext and snext.id == glyph_code and snext.subtype<256 and snext.font == currentfont do
local nextchar = snext.char
local krn = kerns[nextchar]
@@ -9730,8 +9183,8 @@ function chainprocs.gpos_pair(start,stop,kind,chainname,currentcontext,cache,cur
if not krn then
-- skip
elseif type(krn) == "table" then
- if krn[1] == "pair" then
- local a, b = krn[3], krn[4]
+ if lookuptype == "pair" then
+ local a, b = krn[2], krn[3]
if a and #a > 0 then
local startchar = start.char
local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar])
@@ -9748,7 +9201,7 @@ function chainprocs.gpos_pair(start,stop,kind,chainname,currentcontext,cache,cur
end
else
report_process("%s: check this out (old kern stuff)",cref(kind,chainname,chainlookupname))
- local a, b = krn[3], krn[7]
+ local a, b = krn[2], krn[6]
if a and a ~= 0 then
local k = setkern(snext,factor,rlmode,a)
if trace_kerns then
@@ -9793,7 +9246,7 @@ local function show_skip(kind,chainname,char,ck,class)
end
end
-local function normal_handle_contextchain(start,kind,chainname,contexts,sequence,cache)
+local function normal_handle_contextchain(start,kind,chainname,contexts,sequence,lookuphash)
-- local rule, lookuptype, sequence, f, l, lookups = ck[1], ck[2] ,ck[3], ck[4], ck[5], ck[6]
local flags, done = sequence.flags, false
local skipmark, skipligature, skipbase = flags[1], flags[2], flags[3]
@@ -9994,35 +9447,11 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
local chainlookup = lookuptable[chainlookupname]
local cp = chainprocs[chainlookup.type]
if cp then
- start, done = cp(start,last,kind,chainname,ck,cache,chainlookup,chainlookupname,nil,sequence)
+ start, done = cp(start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence)
else
logprocess("%s: %s is not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)
end
else
- -- actually this needs a more complex treatment for which we will use chainmores
---~ local i = 1
---~ repeat
---~ local chainlookupname = chainlookups[i]
---~ local chainlookup = lookuptable[chainlookupname]
---~ local cp = chainmores[chainlookup.type]
---~ if cp then
---~ local ok, n
---~ start, ok, n = cp(start,last,kind,chainname,ck,cache,chainlookup,chainlookupname,i,sequence)
---~ -- messy since last can be changed !
---~ if ok then
---~ done = true
---~ start = start.next
---~ if n then
---~ -- skip next one(s) if ligature
---~ i = i + n - 1
---~ end
---~ end
---~ else
---~ logprocess("%s: multiple subchains for %s are not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)
---~ end
---~ i = i + 1
---~ until i > nofchainlookups
-
local i = 1
repeat
if skipped then
@@ -10046,7 +9475,7 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
local cp = chainmores[chainlookup.type]
if cp then
local ok, n
- start, ok, n = cp(start,last,kind,chainname,ck,cache,chainlookup,chainlookupname,i,sequence)
+ start, ok, n = cp(start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,i,sequence)
-- messy since last can be changed !
if ok then
done = true
@@ -10066,7 +9495,7 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
else
local replacements = ck[7]
if replacements then
- start, done = chainprocs.reversesub(start,last,kind,chainname,ck,cache,replacements) -- sequence
+ start, done = chainprocs.reversesub(start,last,kind,chainname,ck,lookuphash,replacements) -- sequence
else
done = true -- can be meant to be skipped
if trace_contexts then
@@ -10131,122 +9560,120 @@ local function report_missing_cache(typ,lookup)
local t = f[typ] if not t then t = { } f[typ] = t end
if not t[lookup] then
t[lookup] = true
- logwarning("missing cache for lookup %s of type %s in font %s (%s)",lookup,typ,currentfont,tfmdata.fullname)
+ logwarning("missing cache for lookup %s of type %s in font %s (%s)",lookup,typ,currentfont,tfmdata.properties.fullname)
end
end
local resolved = { } -- we only resolve a font,script,language pair once
-- todo: pass all these 'locals' in a table
---
--- dynamics will be isolated some day ... for the moment we catch attribute zero
--- not being set
-function fonts.methods.node.otf.features(head,font,attr)
+local lookuphashes = { }
+
+setmetatable(lookuphashes, { __index =
+ function(t,font)
+ local lookuphash = fontdata[font].resources.lookuphash
+ if not lookuphash or not next(lookuphash) then
+ lookuphash = false
+ end
+ t[font] = lookuphash
+ return lookuphash
+ end
+})
+
+-- fonts.hashes.lookups = lookuphashes
+
+local special_attributes = {
+ init = 1,
+ medi = 2,
+ fina = 3,
+ isol = 4
+}
+
+local function initialize(sequence,script,language,enabled)
+ local features = sequence.features
+ if features then
+ for kind, scripts in next, features do
+ local valid = enabled[kind]
+ if valid then
+ local languages = scripts[script] or scripts[wildcard]
+ if languages and (languages[language] or languages[wildcard]) then
+ return { valid, special_attributes[kind] or false, sequence.chain or 0, kind }
+ end
+ end
+ end
+ end
+ return false
+end
+
+function otf.dataset(ftfmdata,sequences,font) -- generic variant, overloaded in context
+ local shared = tfmdata.shared
+ local properties = tfmdata.properties
+ local language = properties.language or "dflt"
+ local script = properties.script or "dflt"
+ local enabled = shared.features
+ local res = resolved[font]
+ if not res then
+ res = { }
+ resolved[font] = res
+ end
+ local rs = res[script]
+ if not rs then
+ rs = { }
+ res[script] = rs
+ end
+ local rl = rs[language]
+ if not rl then
+ rl = { }
+ rs[language] = rl
+ setmetatable(rl, { __index = function(t,k)
+ local v = enabled and initialize(sequences[k],script,language,enabled)
+ t[k] = v
+ return v
+ end})
+ end
+ return rl
+end
+
+local function featuresprocessor(head,font,attr)
+
+ local lookuphash = lookuphashes[font] -- we can also check sequences here
+
+ if not lookuphash then
+ return head, false
+ end
+
if trace_steps then
checkstep(head)
end
- tfmdata = fontdata[font]
- local shared = tfmdata.shared
- otfdata = shared.otfdata
- local luatex = otfdata.luatex
- descriptions = tfmdata.descriptions
- characters = tfmdata.characters
- indices = tfmdata.indices
- unicodes = tfmdata.unicodes
- marks = tfmdata.marks
- anchorlookups = luatex.lookup_to_anchor
- currentfont = font
- rlmode = 0
- local featuredata = otfdata.shared.featuredata -- can be made local to closure
- local sequences = luatex.sequences
- lookuptable = luatex.lookups
- local done = false
- local script, language, s_enabled, a_enabled, dyn
- local attribute_driven = attr and attr ~= 0
- if attribute_driven then
- local features = contextsetups[contextnumbers[attr]] -- could be a direct list
- dyn = contextmerged[attr] or 0
- language, script = features.language or "dflt", features.script or "dflt"
- a_enabled = features -- shared.features -- can be made local to the resolver
- if dyn == 2 or dyn == -2 then
- -- font based
- s_enabled = shared.features
- end
- else
- language, script = tfmdata.language or "dflt", tfmdata.script or "dflt"
- s_enabled = shared.features -- can be made local to the resolver
- dyn = 0
- end
- -- we can save some runtime by caching feature tests
- local res = resolved[font] if not res then res = { } resolved[font] = res end
- local rs = res [script] if not rs then rs = { } res [script] = rs end
- local rl = rs [language] if not rl then rl = { } rs [language] = rl end
- local ra = rl [attr] if ra == nil then ra = { } rl [attr] = ra end -- attr can be false
- -- sequences always > 1 so no need for optimization
+
+ tfmdata = fontdata[font]
+ descriptions = tfmdata.descriptions
+ characters = tfmdata.characters
+ resources = tfmdata.resources
+
+ marks = resources.marks
+ anchorlookups = resources.lookup_to_anchor
+ lookuptable = resources.lookups
+ lookuptypes = resources.lookuptypes
+
+ currentfont = font
+ rlmode = 0
+
+ local sequences = resources.sequences
+ local done = false
+ local datasets = otf.dataset(tfmdata,sequences,font,attr)
+
for s=1,#sequences do
- local pardir, txtdir, success = 0, { }, false
+ local pardir, txtdir, success = 0, { }, false -- we could reuse txtdir and use a top pointer
local sequence = sequences[s]
- local r = ra[s] -- cache
- if r == nil then
- --
- -- this bit will move to font-ctx and become a function
- ---
- local chain = sequence.chain or 0
- local features = sequence.features
- if not features then
- -- indirect lookup, part of chain (todo: make this a separate table)
- r = false -- { false, false, chain }
- else
- local valid, attribute, kind, what = false, false
- for k,v in next, features do
- -- we can quit earlier but for the moment we want the tracing
- local s_e = s_enabled and s_enabled[k]
- local a_e = a_enabled and a_enabled[k]
- if s_e or a_e then
- local l = v[script] or v[wildcard]
- if l then
- -- not l[language] or l[default] or l[wildcard] because we want tracing
- -- only first attribute match check, so we assume simple fina's
- -- default can become a font feature itself
- if l[language] then
- valid, what = s_e or a_e, language
- -- elseif l[default] then
- -- valid, what = true, default
- elseif l[wildcard] then
- valid, what = s_e or a_e, wildcard
- end
- if valid then
- kind, attribute = k, special_attributes[k] or false
- if a_e and dyn < 0 then
- valid = false
- end
- if trace_applied then
- local typ, action = match(sequence.type,"(.*)_(.*)")
- report_process(
- "%s font: %03i, dynamic: %03i, kind: %s, lookup: %3i, script: %-4s, language: %-4s (%-4s), type: %s, action: %s, name: %s",
- (valid and "+") or "-",font,attr or 0,kind,s,script,language,what,typ,action,sequence.name)
- end
- break
- end
- end
- end
- end
- if valid then
- r = { valid, attribute, chain, kind }
- else
- r = false -- { valid, attribute, chain, "generic" } -- false anyway, could be flag instead of table
- end
- end
- ra[s] = r
- end
- featurevalue = r and r[1] -- todo: pass to function instead of using a global
+ local dataset = datasets[s] -- cache
+ featurevalue = dataset and dataset[1] -- todo: pass to function instead of using a global
if featurevalue then
- local attribute, chain, typ, subtables = r[2], r[3], sequence.type, sequence.subtables
+ local attribute, chain, typ, subtables = dataset[2], dataset[3], sequence.type, sequence.subtables
if chain < 0 then
-- this is a limited case, no special treatments like 'init' etc
local handler = handlers[typ]
- local thecache = featuredata[typ] or { }
-- we need to get rid of this slide !
local start = find_node_tail(head) -- slow (we can store tail because there's always a skip at the end): todo
while start do
@@ -10262,11 +9689,11 @@ function fonts.methods.node.otf.features(head,font,attr)
if a then
for i=1,#subtables do
local lookupname = subtables[i]
- local lookupcache = thecache[lookupname]
+ local lookupcache = lookuphash[lookupname]
if lookupcache then
local lookupmatch = lookupcache[start.char]
if lookupmatch then
- start, success = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,i)
+ start, success = handler(start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
if success then
break
end
@@ -10289,12 +9716,11 @@ function fonts.methods.node.otf.features(head,font,attr)
else
local handler = handlers[typ]
local ns = #subtables
- local thecache = featuredata[typ] or { }
local start = head -- local ?
rlmode = 0 -- to be checked ?
if ns == 1 then
local lookupname = subtables[1]
- local lookupcache = thecache[lookupname]
+ local lookupcache = lookuphash[lookupname]
if not lookupcache then
report_missing_cache(typ,lookupname)
else
@@ -10313,7 +9739,7 @@ function fonts.methods.node.otf.features(head,font,attr)
if lookupmatch then
-- sequence kan weg
local ok
- start, ok = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,1)
+ start, ok = handler(start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
if ok then
success = true
end
@@ -10395,13 +9821,13 @@ function fonts.methods.node.otf.features(head,font,attr)
if a then
for i=1,ns do
local lookupname = subtables[i]
- local lookupcache = thecache[lookupname]
+ local lookupcache = lookuphash[lookupname]
if lookupcache then
local lookupmatch = lookupcache[start.char]
if lookupmatch then
-- we could move all code inline but that makes things even more unreadable
local ok
- start, ok = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,i)
+ start, ok = handler(start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
if ok then
success = true
break
@@ -10486,305 +9912,156 @@ function fonts.methods.node.otf.features(head,font,attr)
return head, done
end
-otf.features.prepare = { }
+local function generic(lookupdata,lookupname,unicode,lookuphash)
+ local target = lookuphash[lookupname]
+ if target then
+ target[unicode] = lookupdata
+ else
+ lookuphash[lookupname] = { [unicode] = lookupdata }
+ end
+end
+
+local action = {
--- we used to share code in the following functions but that costs a lot of
--- memory due to extensive calls to functions (easily hundreds of thousands per
--- document)
+ substitution = generic,
+ multiple = generic,
+ alternate = generic,
+ position = generic,
-local function split(replacement,original,cache,unicodes)
- -- we can cache this too, but not the same (although unicode is a unique enough hash)
- local o, t, n, no = { }, { }, 0, 0
- for s in gmatch(original,"[^ ]+") do
- local us = unicodes[s]
- no = no + 1
- if type(us) == "number" then -- tonumber(us)
- o[no] = us
- else
- o[no] = us[1]
+ ligature = function(lookupdata,lookupname,unicode,lookuphash)
+ local target = lookuphash[lookupname]
+ if not target then
+ target = { }
+ lookuphash[lookupname] = target
end
- end
- for s in gmatch(replacement,"[^ ]+") do
- n = n + 1
- local us = unicodes[s]
- if type(us) == "number" then -- tonumber(us)
- t[o[n]] = us
- else
- t[o[n]] = us[1]
+ for i=1,#lookupdata do
+ local li = lookupdata[i]
+ local tu = target[li]
+ if not tu then
+ tu = { }
+ target[li] = tu
+ end
+ target = tu
end
- end
- return t
-end
+ target.ligature = unicode
+ end,
-local function uncover(covers,result,cache,unicodes)
- -- lpeg hardly faster (.005 sec on mk)
- local nofresults = #result
- for n=1,#covers do
- local c = covers[n]
- local cc = cache[c]
- nofresults = nofresults + 1
- if not cc then
- local t = { }
- for s in gmatch(c,"[^ ]+") do
- local us = unicodes[s]
- if type(us) == "number" then
- t[us] = true
- else
- for i=1,#us do
- t[us[i]] = true
- end
- end
- end
- cache[c] = t
- result[nofresults] = t
+ pair = function(lookupdata,lookupname,unicode,lookuphash)
+ local target = lookuphash[lookupname]
+ if not target then
+ target = { }
+ lookuphash[lookupname] = target
+ end
+ local others = target[unicode]
+ local paired = lookupdata[1]
+ if others then
+ others[paired] = lookupdata
else
- result[nofresults] = cc
+ others = { [paired] = lookupdata }
+ target[unicode] = others
end
- end
-end
+ end,
+
+}
local function prepare_lookups(tfmdata)
- local otfdata = tfmdata.shared.otfdata
- local featuredata = otfdata.shared.featuredata
- local anchor_to_lookup = otfdata.luatex.anchor_to_lookup
- local lookup_to_anchor = otfdata.luatex.lookup_to_anchor
- --
- local multiple = featuredata.gsub_multiple
- local alternate = featuredata.gsub_alternate
- local single = featuredata.gsub_single
- local ligature = featuredata.gsub_ligature
- local pair = featuredata.gpos_pair
- local position = featuredata.gpos_single
- local kerns = featuredata.gpos_pair
- local mark = featuredata.gpos_mark2mark
- local cursive = featuredata.gpos_cursive
- --
- local unicodes = tfmdata.unicodes -- names to unicodes
- local indices = tfmdata.indices
- local descriptions = tfmdata.descriptions
- --
- -- we can change the otf table after loading but then we need to adapt base mode
- -- as well (no big deal)
- --
- local action = {
- substitution = function(p,lookup,glyph,unicode)
- local old, new = unicode, unicodes[p[2]]
- if type(new) == "table" then
- new = new[1]
- end
- local s = single[lookup]
- if not s then s = { } single[lookup] = s end
- s[old] = new
- --~ if trace_lookups then
- --~ report_prepare("lookup %s: substitution %s => %s",lookup,old,new)
- --~ end
- end,
- multiple = function (p,lookup,glyph,unicode)
- local old, new, nnew = unicode, { }, 0
- local m = multiple[lookup]
- if not m then m = { } multiple[lookup] = m end
- m[old] = new
- for pc in gmatch(p[2],"[^ ]+") do
- local upc = unicodes[pc]
- nnew = nnew + 1
- if type(upc) == "number" then
- new[nnew] = upc
- else
- new[nnew] = upc[1]
- end
- end
- --~ if trace_lookups then
- --~ report_prepare("lookup %s: multiple %s => %s",lookup,old,concat(new," "))
- --~ end
- end,
- alternate = function(p,lookup,glyph,unicode)
- local old, new, nnew = unicode, { }, 0
- local a = alternate[lookup]
- if not a then a = { } alternate[lookup] = a end
- a[old] = new
- for pc in gmatch(p[2],"[^ ]+") do
- local upc = unicodes[pc]
- nnew = nnew + 1
- if type(upc) == "number" then
- new[nnew] = upc
- else
- new[nnew] = upc[1]
- end
- end
- --~ if trace_lookups then
- --~ report_prepare("lookup %s: alternate %s => %s",lookup,old,concat(new,"|"))
- --~ end
- end,
- ligature = function (p,lookup,glyph,unicode)
- --~ if trace_lookups then
- --~ report_prepare("lookup %s: ligature %s => %s",lookup,p[2],glyph.name)
- --~ end
- local first = true
- local t = ligature[lookup]
- if not t then t = { } ligature[lookup] = t end
- for s in gmatch(p[2],"[^ ]+") do
- if first then
- local u = unicodes[s]
- if not u then
- report_prepare("lookup %s: ligature %s => %s ignored due to invalid unicode",lookup,p[2],glyph.name)
- break
- elseif type(u) == "number" then
- if not t[u] then
- t[u] = { { } }
- end
- t = t[u]
- else
- local tt = t
- local tu
- for i=1,#u do
- local u = u[i]
- if i==1 then
- if not t[u] then
- t[u] = { { } }
- end
- tu = t[u]
- t = tu
- else
- if not t[u] then
- tt[u] = tu
- end
- end
- end
- end
- first = false
- else
- s = unicodes[s]
- local t1 = t[1]
- if not t1[s] then
- t1[s] = { { } }
- end
- t = t1[s]
- end
- end
- t[2] = unicode
- end,
- position = function(p,lookup,glyph,unicode)
- -- not used
- local s = position[lookup]
- if not s then s = { } position[lookup] = s end
- s[unicode] = p[2] -- direct pointer to kern spec
- end,
- pair = function(p,lookup,glyph,unicode)
- local s = pair[lookup]
- if not s then s = { } pair[lookup] = s end
- local others = s[unicode]
- if not others then others = { } s[unicode] = others end
- -- todo: fast check for space
- local two = p[2]
- local upc = unicodes[two]
- if not upc then
- for pc in gmatch(two,"[^ ]+") do
- local upc = unicodes[pc]
- if type(upc) == "number" then
- others[upc] = p -- direct pointer to main table
- else
- for i=1,#upc do
- others[upc[i]] = p -- direct pointer to main table
- end
- end
- end
- elseif type(upc) == "number" then
- others[upc] = p -- direct pointer to main table
- else
- for i=1,#upc do
- others[upc[i]] = p -- direct pointer to main table
- end
- end
- --~ if trace_lookups then
- --~ report_prepare("lookup %s: pair for U+%04X",lookup,unicode)
- --~ end
- end,
- }
- --
- for unicode, glyph in next, descriptions do
- local lookups = glyph.slookups
+
+ local rawdata = tfmdata.shared.rawdata
+ local resources = rawdata.resources
+ local lookuphash = resources.lookuphash
+ local anchor_to_lookup = resources.anchor_to_lookup
+ local lookup_to_anchor = resources.lookup_to_anchor
+ local lookuptypes = resources.lookuptypes
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+
+ -- we cannot free the entries in the descriptions as sometimes we access
+ -- then directly (for instance anchors) ... selectively freeing does save
+ -- much memory as it's only a reference to a table and the slot in the
+ -- description hash is not freed anyway
+
+ for unicode, character in next, characters do -- we cannot loop over descriptions !
+
+ local description = descriptions[unicode]
+
+ local lookups = description.slookups
if lookups then
- for lookup, p in next, lookups do
- action[p[1]](p,lookup,glyph,unicode)
+ for lookupname, lookupdata in next, lookups do
+ action[lookuptypes[lookupname]](lookupdata,lookupname,unicode,lookuphash)
end
end
- local lookups = glyph.mlookups
+
+ local lookups = description.mlookups
if lookups then
- for lookup, whatever in next, lookups do
- for i=1,#whatever do -- normaly one
- local p = whatever[i]
- action[p[1]](p,lookup,glyph,unicode)
+ for lookupname, lookuplist in next, lookups do
+ local lookuptype = lookuptypes[lookupname]
+ for l=1,#lookuplist do
+ local lookupdata = lookuplist[l]
+ action[lookuptype](lookupdata,lookupname,unicode,lookuphash)
end
end
end
- local list = glyph.kerns
+
+ local list = description.kerns
if list then
- for lookup, krn in next, list do
- local k = kerns[lookup]
- if not k then k = { } kerns[lookup] = k end
- k[unicode] = krn -- ref to glyph, saves lookup
- --~ if trace_lookups then
- --~ report_prepare("lookup %s: kern for U+%04X",lookup,unicode)
- --~ end
+ for lookup, krn in next, list do -- ref to glyph, saves lookup
+ local target = lookuphash[lookup]
+ if target then
+ target[unicode] = krn
+ else
+ lookuphash[lookup] = { [unicode] = krn }
+ end
end
end
- local oanchor = glyph.anchors
- if oanchor then
- for typ, anchors in next, oanchor do -- types
- if typ == "mark" then
- for name, anchor in next, anchors do
- local lookups = anchor_to_lookup[name]
- if lookups then
- for lookup, _ in next, lookups do
- local f = mark[lookup]
- if not f then f = { } mark[lookup] = f end
- f[unicode] = anchors -- ref to glyph, saves lookup
- --~ if trace_lookups then
- --~ report_prepare("lookup %s: mark anchor %s for U+%04X",lookup,name,unicode)
- --~ end
- end
- end
- end
- elseif typ == "cexit" then -- or entry?
+
+ local list = description.anchors
+ if list then
+ for typ, anchors in next, list do -- types
+ if typ == "mark" or typ == "cexit" then -- or entry?
for name, anchor in next, anchors do
local lookups = anchor_to_lookup[name]
if lookups then
for lookup, _ in next, lookups do
- local f = cursive[lookup]
- if not f then f = { } cursive[lookup] = f end
- f[unicode] = anchors -- ref to glyph, saves lookup
- --~ if trace_lookups then
- --~ report_prepare("lookup %s: exit anchor %s for U+%04X",lookup,name,unicode)
- --~ end
+ local target = lookuphash[lookup]
+ if target then
+ target[unicode] = anchors
+ else
+ lookuphash[lookup] = { [unicode] = anchors }
+ end
end
end
end
end
end
end
+
+ end
+
+end
+
+local function split(replacement,original)
+ local result = { }
+ for i=1,#replacement do
+ result[original[i]] = replacement[i]
end
+ return result
end
--- local cache = { }
-luatex = luatex or {} -- this has to change ... we need a better one
+local function uncover(covers,result) -- will change (we can store this in the raw table)
+ local nofresults = #result
+ for n=1,#covers do
+ nofresults = nofresults + 1
+ result[nofresults] = covers[n]
+ end
+end
local function prepare_contextchains(tfmdata)
- local otfdata = tfmdata.shared.otfdata
- local lookups = otfdata.lookups
+ local rawdata = tfmdata.shared.rawdata
+ local resources = rawdata.resources
+ local lookuphash = resources.lookuphash
+ local lookups = rawdata.lookups
if lookups then
- local featuredata = otfdata.shared.featuredata
- local contextchain = featuredata.gsub_contextchain -- shared with gpos
- local reversecontextchain = featuredata.gsub_reversecontextchain -- shared with gpos
- local characters = tfmdata.characters
- local unicodes = tfmdata.unicodes
- local indices = tfmdata.indices
- local cache = luatex.covers
- if not cache then
- cache = { }
- luatex.covers = cache
- end
- --
- for lookupname, lookupdata in next, otfdata.lookups do
+ for lookupname, lookupdata in next, rawdata.lookups do
local lookuptype = lookupdata.type
if not lookuptype then
report_prepare("missing lookuptype for %s",lookupname)
@@ -10792,39 +10069,37 @@ local function prepare_contextchains(tfmdata)
local rules = lookupdata.rules
if rules then
local fmt = lookupdata.format
- -- contextchain[lookupname][unicode]
- if fmt == "coverage" then
+ -- lookuphash[lookupname][unicode]
+ if fmt == "coverage" then -- or fmt == "class" (converted into "coverage")
if lookuptype ~= "chainsub" and lookuptype ~= "chainpos" then
+ -- todo: dejavu-serif has one (but i need to see what use it has)
report_prepare("unsupported coverage %s for %s",lookuptype,lookupname)
else
- local contexts = contextchain[lookupname]
+ local contexts = lookuphash[lookupname]
if not contexts then
contexts = { }
- contextchain[lookupname] = contexts
+ lookuphash[lookupname] = contexts
end
local t, nt = { }, 0
for nofrules=1,#rules do -- does #rules>1 happen often?
local rule = rules[nofrules]
- local coverage = rule.coverage
- if coverage and coverage.current then
- local current, before, after, sequence = coverage.current, coverage.before, coverage.after, { }
- if before then
- uncover(before,sequence,cache,unicodes)
- end
- local start = #sequence + 1
- uncover(current,sequence,cache,unicodes)
- local stop = #sequence
- if after then
- uncover(after,sequence,cache,unicodes)
- end
- if sequence[1] then
- nt = nt + 1
- t[nt] = { nofrules, lookuptype, sequence, start, stop, rule.lookups }
- for unic, _ in next, sequence[start] do
- local cu = contexts[unic]
- if not cu then
- contexts[unic] = t
- end
+ local current, before, after, sequence = rule.current, rule.before, rule.after, { }
+ if before then
+ uncover(before,sequence)
+ end
+ local start = #sequence + 1
+ uncover(current,sequence)
+ local stop = #sequence
+ if after then
+ uncover(after,sequence)
+ end
+ if sequence[1] then
+ nt = nt + 1
+ t[nt] = { nofrules, lookuptype, sequence, start, stop, rule.lookups }
+ for unic, _ in next, sequence[start] do
+ local cu = contexts[unic]
+ if not cu then
+ contexts[unic] = t
end
end
end
@@ -10834,79 +10109,69 @@ local function prepare_contextchains(tfmdata)
if lookuptype ~= "reversesub" then
report_prepare("unsupported reverse coverage %s for %s",lookuptype,lookupname)
else
- local contexts = reversecontextchain[lookupname]
+ local contexts = lookuphash[lookupname]
if not contexts then
contexts = { }
- reversecontextchain[lookupname] = contexts
+ lookuphash[lookupname] = contexts
end
local t, nt = { }, 0
for nofrules=1,#rules do
local rule = rules[nofrules]
- local reversecoverage = rule.reversecoverage
- if reversecoverage and reversecoverage.current then
- local current, before, after, replacements, sequence = reversecoverage.current, reversecoverage.before, reversecoverage.after, reversecoverage.replacements, { }
- if before then
- uncover(before,sequence,cache,unicodes)
- end
- local start = #sequence + 1
- uncover(current,sequence,cache,unicodes)
- local stop = #sequence
- if after then
- uncover(after,sequence,cache,unicodes)
- end
- if replacements then
- replacements = split(replacements,current[1],cache,unicodes)
- end
- if sequence[1] then
- -- this is different from normal coverage, we assume only replacements
- nt = nt + 1
- t[nt] = { nofrules, lookuptype, sequence, start, stop, rule.lookups, replacements }
- for unic, _ in next, sequence[start] do
- local cu = contexts[unic]
- if not cu then
- contexts[unic] = t
- end
+ local current, before, after, replacements, sequence = rule.current, rule.before, rule.after, rule.replacements, { }
+ if before then
+ uncover(before,sequence)
+ end
+ local start = #sequence + 1
+ uncover(current,sequence)
+ local stop = #sequence
+ if after then
+ uncover(after,sequence)
+ end
+ if replacements then
+ replacements = split(replacements,current[1])
+ end
+ if sequence[1] then
+ -- this is different from normal coverage, we assume only replacements
+ nt = nt + 1
+ t[nt] = { nofrules, lookuptype, sequence, start, stop, rule.lookups, replacements }
+ for unic, _ in next, sequence[start] do
+ local cu = contexts[unic]
+ if not cu then
+ contexts[unic] = t
end
end
end
end
end
- elseif fmt == "glyphs" then
+ elseif fmt == "glyphs" then --maybe just make then before = { fore } and share with coverage
if lookuptype ~= "chainsub" and lookuptype ~= "chainpos" then
report_prepare("unsupported coverage %s for %s",lookuptype,lookupname)
else
- local contexts = contextchain[lookupname]
+ local contexts = lookuphash[lookupname]
if not contexts then
contexts = { }
- contextchain[lookupname] = contexts
+ lookuphash[lookupname] = contexts
end
local t, nt = { }, 0
for nofrules=1,#rules do
- -- nearly the same as coverage so we could as well rename it
local rule = rules[nofrules]
- local glyphs = rule.glyphs
- if glyphs and glyphs.names then
- local fore, back, names, sequence = glyphs.fore, glyphs.back, glyphs.names, { }
- if fore and fore ~= "" then
- fore = lpegmatch(split_at_space,fore)
- uncover(fore,sequence,cache,unicodes)
- end
- local start = #sequence + 1
- names = lpegmatch(split_at_space,names)
- uncover(names,sequence,cache,unicodes)
- local stop = #sequence
- if back and back ~= "" then
- back = lpegmatch(split_at_space,back)
- uncover(back,sequence,cache,unicodes)
- end
- if sequence[1] then
- nt = nt + 1
- t[nt] = { nofrules, lookuptype, sequence, start, stop, rule.lookups }
- for unic, _ in next, sequence[start] do
- local cu = contexts[unic]
- if not cu then
- contexts[unic] = t
- end
+ local current, before, after, sequence = rule.names, rule.fore, rule.back, { }
+ if before then
+ uncover(before,sequence)
+ end
+ local start = #sequence + 1
+ uncover(current,sequence)
+ local stop = #sequence
+ if after then
+ uncover(after,sequence)
+ end
+ if sequence[1] then
+ nt = nt + 1
+ t[nt] = { nofrules, lookuptype, sequence, start, stop, rule.lookups }
+ for unic, _ in next, sequence[start] do
+ local cu = contexts[unic]
+ if not cu then
+ contexts[unic] = t
end
end
end
@@ -10919,38 +10184,40 @@ local function prepare_contextchains(tfmdata)
end
end
-function fonts.initializers.node.otf.features(tfmdata,value)
+-- we can consider lookuphash == false (initialized but empty) vs lookuphash == table
+
+local function featuresinitializer(tfmdata,value)
if true then -- value then
- if not tfmdata.shared.otfdata.shared.initialized then
- local t = trace_preparing and os.clock()
- local otfdata = tfmdata.shared.otfdata
- local featuredata = otfdata.shared.featuredata
- -- caches
- featuredata.gsub_multiple = { }
- featuredata.gsub_alternate = { }
- featuredata.gsub_single = { }
- featuredata.gsub_ligature = { }
- featuredata.gsub_contextchain = { }
- featuredata.gsub_reversecontextchain = { }
- featuredata.gpos_pair = { }
- featuredata.gpos_single = { }
- featuredata.gpos_mark2base = { }
- featuredata.gpos_mark2ligature = featuredata.gpos_mark2base
- featuredata.gpos_mark2mark = featuredata.gpos_mark2base
- featuredata.gpos_cursive = { }
- featuredata.gpos_contextchain = featuredata.gsub_contextchain
- featuredata.gpos_reversecontextchain = featuredata.gsub_reversecontextchain
- --
+ -- beware we need to use the topmost properties table
+ local rawdata = tfmdata.shared.rawdata
+ local properties = rawdata.properties
+ if not properties.initialized then
+ local starttime = trace_preparing and os.clock()
+ local resources = rawdata.resources
+ resources.lookuphash = resources.lookuphash or { }
prepare_contextchains(tfmdata)
prepare_lookups(tfmdata)
- otfdata.shared.initialized = true
+ properties.initialized = true
if trace_preparing then
- report_prepare("preparation time is %0.3f seconds for %s",os.clock()-t,tfmdata.fullname or "?")
+ report_prepare("preparation time is %0.3f seconds for %s",os.clock()-starttime,tfmdata.properties.fullname or "?")
end
end
end
end
+registerotffeature {
+ name = "features",
+ description = "features",
+ default = true,
+ initializers = {
+ position = 1,
+ node = featuresinitializer,
+ },
+ processors = {
+ node = featuresprocessor,
+ }
+}
+
end -- closure
do -- begin closure to overcome local limits and interference
@@ -10970,50 +10237,110 @@ local type, tostring, match, format, concat = type, tostring, string.match, stri
if not trackers then trackers = { register = function() end } end
local trace_analyzing = false trackers.register("otf.analyzing", function(v) trace_analyzing = v end)
-local trace_cjk = false trackers.register("cjk.injections", function(v) trace_cjk = v end)
-
-trackers.register("cjk.analyzing","otf.analyzing")
local fonts, nodes = fonts, nodes
local node = node
-local otf = fonts.otf
-local tfm = fonts.tfm
+local otf = fonts.handlers.otf
-fonts.analyzers = fonts.analyzers or { }
-local analyzers = fonts.analyzers
+local analyzers = fonts.analyzers
+local initializers = { }
+local methods = { }
-analyzers.initializers = analyzers.initializers or { node = { otf = { } } }
-analyzers.methods = analyzers.methods or { node = { otf = { } } }
+analyzers.initializers = initializers
+analyzers.methods = methods
+analyzers.useunicodemarks = false
-local initializers = analyzers.initializers
-local methods = analyzers.methods
+local nodecodes = nodes.nodecodes
+local glyph_code = nodecodes.glyph
-local nodecodes = nodes.nodecodes
-local glyph_code = nodecodes.glyph
+local set_attribute = node.set_attribute
+local has_attribute = node.has_attribute
+local traverse_id = node.traverse_id
+local traverse_node_list = node.traverse
-local set_attribute = node.set_attribute
-local has_attribute = node.has_attribute
-local traverse_id = node.traverse_id
-local traverse_node_list = node.traverse
+local fontdata = fonts.hashes.identifiers
+local state = attributes.private('state')
+local categories = characters and characters.categories or { } -- sorry, only in context
+
+local tracers = nodes.tracers
+local colortracers = tracers and tracers.colors
+local setnodecolor = colortracers and colortracers.set or function() end
+local resetnodecolor = colortracers and colortracers.reset or function() end
+
+local otffeatures = fonts.constructors.newfeatures("otf")
+local registerotffeature = otffeatures.register
+
+--[[ldx--
+<p>Analyzers run per script and/or language and are needed in order to
+process features right.</p>
+--ldx]]--
+
+-- todo: analyzers per script/lang, cross font, so we need an font id hash -> script
+-- e.g. latin -> hyphenate, arab -> 1/2/3 analyze -- its own namespace
-local fontdata = fonts.identifiers
-local state = attributes.private('state')
-local categories = characters and characters.categories or { } -- sorry, only in context
+-- an example analyzer (should move to font-ota.lua)
-local fontscolors = fonts.colors
-local fcs = (fontscolors and fontscolors.set) or function() end
-local fcr = (fontscolors and fontscolors.reset) or function() end
+local state = attributes.private('state')
+function analyzers.setstate(head,font)
+ local useunicodemarks = analyzers.useunicodemarks
+ local tfmdata = fontdata[font]
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local first, last, current, n, done = nil, nil, head, 0, false -- maybe make n boolean
+ while current do
+ local id = current.id
+ if id == glyph_code and current.font == font then
+ local char = current.char
+ local d = descriptions[char]
+ if d then
+ if d.class == "mark" or (useunicodemarks and categories[char] == "mn") then
+ done = true
+ set_attribute(current,state,5) -- mark
+ elseif n == 0 then
+ first, last, n = current, current, 1
+ set_attribute(current,state,1) -- init
+ else
+ last, n = current, n+1
+ set_attribute(current,state,2) -- medi
+ end
+ else -- finish
+ if first and first == last then
+ set_attribute(last,state,4) -- isol
+ elseif last then
+ set_attribute(last,state,3) -- fina
+ end
+ first, last, n = nil, nil, 0
+ end
+ elseif id == disc_code then
+ -- always in the middle
+ set_attribute(current,state,2) -- midi
+ last = current
+ else -- finish
+ if first and first == last then
+ set_attribute(last,state,4) -- isol
+ elseif last then
+ set_attribute(last,state,3) -- fina
+ end
+ first, last, n = nil, nil, 0
+ end
+ current = current.next
+ end
+ if first and first == last then
+ set_attribute(last,state,4) -- isol
+ elseif last then
+ set_attribute(last,state,3) -- fina
+ end
+ return head, done
+end
-- in the future we will use language/script attributes instead of the
-- font related value, but then we also need dynamic features which is
-- somewhat slower; and .. we need a chain of them
-local scriptandlanguage = otf.scriptandlanguage
-
-function fonts.initializers.node.otf.analyze(tfmdata,value,attr)
- local script, language = otf.scriptandlanguage(tfmdata,attr)
+local function analyzeinitializer(tfmdata,value) -- attr
+ local script, language = otf.scriptandlanguage(tfmdata) -- attr
local action = initializers[script]
if action then
if type(action) == "function" then
@@ -11025,10 +10352,9 @@ function fonts.initializers.node.otf.analyze(tfmdata,value,attr)
end
end
end
- return nil
end
-function fonts.methods.node.otf.analyze(head,font,attr)
+local function analyzeprocessor(head,font,attr)
local tfmdata = fontdata[font]
local script, language = otf.scriptandlanguage(tfmdata,attr)
local action = methods[script]
@@ -11045,12 +10371,22 @@ function fonts.methods.node.otf.analyze(head,font,attr)
return head, false
end
-otf.features.register("analyze",true) -- we always analyze
-table.insert(fonts.triggers,"analyze") -- we need a proper function for doing this
+registerotffeature {
+ name = "analyze",
+ description = "analysis of (for instance) character classes",
+ default = true,
+ initializers = {
+ node = analyzeinitializer,
+ },
+ processors = {
+ position = 1,
+ node = analyzeprocessor,
+ }
+}
-- latin
-analyzers.methods.latn = analyzers.aux.setstate
+methods.latn = analyzers.setstate
-- this info eventually will go into char-def
@@ -11132,10 +10468,10 @@ local function warning(current,what)
end
end
-function analyzers.methods.nocolor(head,font,attr)
+function methods.nocolor(head,font,attr)
for n in traverse_id(glyph_code,head) do
if not font or n.font == font then
- fcr(n)
+ resetnodecolor(n)
end
end
return head, true
@@ -11147,22 +10483,22 @@ local function finish(first,last)
local fc = first.char
if isol_fina_medi_init[fc] or isol_fina[fc] then
set_attribute(first,state,4) -- isol
- if trace_analyzing then fcs(first,"font:isol") end
+ if trace_analyzing then setnodecolor(first,"font:isol") end
else
warning(first,"isol")
set_attribute(first,state,0) -- error
- if trace_analyzing then fcr(first) end
+ if trace_analyzing then resetnodecolor(first) end
end
else
local lc = last.char
if isol_fina_medi_init[lc] or isol_fina[lc] then -- why isol here ?
-- if laststate == 1 or laststate == 2 or laststate == 4 then
set_attribute(last,state,3) -- fina
- if trace_analyzing then fcs(last,"font:fina") end
+ if trace_analyzing then setnodecolor(last,"font:fina") end
else
warning(last,"fina")
set_attribute(last,state,0) -- error
- if trace_analyzing then fcr(last) end
+ if trace_analyzing then resetnodecolor(last) end
end
end
first, last = nil, nil
@@ -11171,21 +10507,21 @@ local function finish(first,last)
local fc = first.char
if isol_fina_medi_init[fc] or isol_fina[fc] then
set_attribute(first,state,4) -- isol
- if trace_analyzing then fcs(first,"font:isol") end
+ if trace_analyzing then setnodecolor(first,"font:isol") end
else
warning(first,"isol")
set_attribute(first,state,0) -- error
- if trace_analyzing then fcr(first) end
+ if trace_analyzing then resetnodecolor(first) end
end
first = nil
end
return first, last
end
-function analyzers.methods.arab(head,font,attr) -- maybe make a special version with no trace
+function methods.arab(head,font,attr) -- maybe make a special version with no trace
local useunicodemarks = analyzers.useunicodemarks
local tfmdata = fontdata[font]
- local marks = tfmdata.marks
+ local marks = tfmdata.resources.marks
local first, last, current, done = nil, nil, head, false
while current do
if current.id == glyph_code and current.subtype<256 and current.font == font and not has_attribute(current,state) then
@@ -11193,20 +10529,20 @@ function analyzers.methods.arab(head,font,attr) -- maybe make a special version
local char = current.char
if marks[char] or (useunicodemarks and categories[char] == "mn") then
set_attribute(current,state,5) -- mark
- if trace_analyzing then fcs(current,"font:mark") end
+ if trace_analyzing then setnodecolor(current,"font:mark") end
elseif isol[char] then -- can be zwj or zwnj too
first, last = finish(first,last)
set_attribute(current,state,4) -- isol
- if trace_analyzing then fcs(current,"font:isol") end
+ if trace_analyzing then setnodecolor(current,"font:isol") end
first, last = nil, nil
elseif not first then
if isol_fina_medi_init[char] then
set_attribute(current,state,1) -- init
- if trace_analyzing then fcs(current,"font:init") end
+ if trace_analyzing then setnodecolor(current,"font:init") end
first, last = first or current, current
elseif isol_fina[char] then
set_attribute(current,state,4) -- isol
- if trace_analyzing then fcs(current,"font:isol") end
+ if trace_analyzing then setnodecolor(current,"font:isol") end
first, last = nil, nil
else -- no arab
first, last = finish(first,last)
@@ -11214,18 +10550,18 @@ function analyzers.methods.arab(head,font,attr) -- maybe make a special version
elseif isol_fina_medi_init[char] then
first, last = first or current, current
set_attribute(current,state,2) -- medi
- if trace_analyzing then fcs(current,"font:medi") end
+ if trace_analyzing then setnodecolor(current,"font:medi") end
elseif isol_fina[char] then
if not has_attribute(last,state,1) then
-- tricky, we need to check what last may be !
set_attribute(last,state,2) -- medi
- if trace_analyzing then fcs(last,"font:medi") end
+ if trace_analyzing then setnodecolor(last,"font:medi") end
end
set_attribute(current,state,3) -- fina
- if trace_analyzing then fcs(current,"font:fina") end
+ if trace_analyzing then setnodecolor(current,"font:fina") end
first, last = nil, nil
elseif char >= 0x0600 and char <= 0x06FF then
- if trace_analyzing then fcs(current,"font:rest") end
+ if trace_analyzing then setnodecolor(current,"font:rest") end
first, last = finish(first,last)
else --no
first, last = finish(first,last)
@@ -11243,3991 +10579,40 @@ end -- closure
do -- begin closure to overcome local limits and interference
-if not modules then modules = { } end modules ['font-otc'] = {
+if not modules then modules = { } end modules ['luatex-fonts-lua'] = {
version = 1.001,
- comment = "companion to font-otf.lua (context)",
+ comment = "companion to luatex-*.tex",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
}
-local format, insert = string.format, table.insert
-local type, next = type, next
-
--- we assume that the other otf stuff is loaded already
-
-local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
-
-local fonts = fonts
-local otf = fonts.otf
-
-local report_otf = logs.reporter("fonts","otf loading")
-
--- instead of "script = "DFLT", langs = { 'dflt' }" we now use wildcards (we used to
--- have always); some day we can write a "force always when true" trick for other
--- features as well
---
--- we could have a tnum variant as well
-
--- In the userdata interface we can not longer tweak the loaded font as
--- conveniently as before. For instance, instead of pushing extra data in
--- in the table using the original structure, we now have to operate on
--- the mkiv representation. And as the fontloader interface is modelled
--- after fontforge we cannot change that one too much either.
-
-local extra_lists = {
- tlig = {
- {
- endash = "hyphen hyphen",
- emdash = "hyphen hyphen hyphen",
- -- quotedblleft = "quoteleft quoteleft",
- -- quotedblright = "quoteright quoteright",
- -- quotedblleft = "grave grave",
- -- quotedblright = "quotesingle quotesingle",
- -- quotedblbase = "comma comma",
- },
- },
- trep = {
- {
- -- [0x0022] = 0x201D,
- [0x0027] = 0x2019,
- -- [0x0060] = 0x2018,
- },
- },
- anum = {
- { -- arabic
- [0x0030] = 0x0660,
- [0x0031] = 0x0661,
- [0x0032] = 0x0662,
- [0x0033] = 0x0663,
- [0x0034] = 0x0664,
- [0x0035] = 0x0665,
- [0x0036] = 0x0666,
- [0x0037] = 0x0667,
- [0x0038] = 0x0668,
- [0x0039] = 0x0669,
- },
- { -- persian
- [0x0030] = 0x06F0,
- [0x0031] = 0x06F1,
- [0x0032] = 0x06F2,
- [0x0033] = 0x06F3,
- [0x0034] = 0x06F4,
- [0x0035] = 0x06F5,
- [0x0036] = 0x06F6,
- [0x0037] = 0x06F7,
- [0x0038] = 0x06F8,
- [0x0039] = 0x06F9,
- },
- },
-}
+if context then
+ texio.write_nl("fatal error: this module is not for context")
+ os.exit()
+end
-local extra_features = { -- maybe just 1..n so that we prescribe order
- tlig = {
- {
- features = { ["*"] = { ["*"] = true } },
- name = "ctx_tlig_1",
- subtables = { "ctx_tlig_1_s" },
- type = "gsub_ligature",
- flags = { },
- },
- },
- trep = {
- {
- features = { ["*"] = { ["*"] = true } },
- name = "ctx_trep_1",
- subtables = { "ctx_trep_1_s" },
- type = "gsub_single",
- flags = { },
- },
- },
- anum = {
- {
- features = { arab = { URD = true, dflt = true } },
- name = "ctx_anum_1",
- subtables = { "ctx_anum_1_s" },
- type = "gsub_single",
- flags = { },
- },
- {
- features = { arab = { URD = true } },
- name = "ctx_anum_2",
- subtables = { "ctx_anum_2_s" },
- type = "gsub_single",
- flags = { },
- },
- },
-}
+local fonts = fonts
+fonts.formats.lua = "lua"
-local function enhancedata(data,filename,raw)
- local luatex = data.luatex
- local lookups = luatex.lookups
- local sequences = luatex.sequences
- local glyphs = data.glyphs
- local indices = luatex.indices
- local gsubfeatures = luatex.features.gsub
- for kind, specifications in next, extra_features do
- if gsub and gsub[kind] then
- -- already present
+function fonts.readers.lua(specification)
+ local fullname = specification.filename or ""
+ if fullname == "" then
+ local forced = specification.forced or ""
+ if forced ~= "" then
+ fullname = specification.name .. "." .. forced
else
- local done = 0
- for s=1,#specifications do
- local added = false
- local specification = specifications[s]
- local features, subtables = specification.features, specification.subtables
- local name, type, flags = specification.name, specification.type, specification.flags
- local full = subtables[1]
- local list = extra_lists[kind][s]
- if type == "gsub_ligature" then
- -- inefficient loop
- for unicode, index in next, indices do
- local glyph = glyphs[index]
- local ligature = list[glyph.name]
- if ligature then
- if glyph.slookups then
- glyph.slookups [full] = { "ligature", ligature, glyph.name }
- else
- glyph.slookups = { [full] = { "ligature", ligature, glyph.name } }
- end
- done, added = done+1, true
- end
- end
- elseif type == "gsub_single" then
- -- inefficient loop
- for unicode, index in next, indices do
- local glyph = glyphs[index]
- local r = list[unicode]
- if r then
- local replacement = indices[r]
- if replacement and glyphs[replacement] then
- if glyph.slookups then
- glyph.slookups [full] = { "substitution", glyphs[replacement].name }
- else
- glyph.slookups = { [full] = { "substitution", glyphs[replacement].name } }
- end
- done, added = done+1, true
- end
- end
- end
- end
- if added then
- sequences[#sequences+1] = {
- chain = 0,
- features = { [kind] = features },
- flags = flags,
- name = name,
- subtables = subtables,
- type = type,
- }
- -- register in metadata (merge as there can be a few)
- if not gsubfeatures then
- gsubfeatures = { }
- luatex.features.gsub = gsubfeatures
- end
- local k = gsubfeatures[kind]
- if not k then
- k = { }
- gsubfeatures[kind] = k
- end
- for script, languages in next, features do
- local kk = k[script]
- if not kk then
- kk = { }
- k[script] = kk
- end
- for language, value in next, languages do
- kk[language] = value
- end
- end
- end
- end
- if done > 0 then
- if trace_loading then
- report_otf("enhance: registering %s feature (%s glyphs affected)",kind,done)
- end
- end
+ fullname = specification.name
end
end
+ local fullname = resolvers.findfile(fullname) or ""
+ if fullname ~= "" then
+ local loader = loadfile(fullname)
+ loader = loader and loader()
+ return loader and loader(specification)
+ end
end
-otf.enhancers.register("check extra features",enhancedata)
-
-local features = otf.tables.features
-
-features['tlig'] = 'TeX Ligatures'
-features['trep'] = 'TeX Replacements'
-features['anum'] = 'Arabic Digits'
-
-local registerbasesubstitution = otf.features.registerbasesubstitution
-
-registerbasesubstitution('tlig')
-registerbasesubstitution('trep')
-registerbasesubstitution('anum')
-
--- the functionality is defined elsewhere
-
-local initializers = fonts.initializers
-local common_initializers = initializers.common
-local base_initializers = initializers.base.otf
-local node_initializers = initializers.node.otf
-
-base_initializers.equaldigits = common_initializers.equaldigits
-node_initializers.equaldigits = common_initializers.equaldigits
-
-base_initializers.lineheight = common_initializers.lineheight
-node_initializers.lineheight = common_initializers.lineheight
-
-base_initializers.compose = common_initializers.compose
-node_initializers.compose = common_initializers.compose
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules = { } end modules ['font-map'] = {
- version = 1.001,
- comment = "companion to font-ini.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "derived from http://www.adobe.com/devnet/opentype/archives/glyphlist.txt",
- original = "Adobe Glyph List, version 2.0, September 20, 2002",
-}
-
-fonts = fonts or { }
-fonts.enc = fonts.enc or { }
-fonts.enc.agl = fonts.enc.agl or { }
-
-fonts.enc.agl.unicodes = { -- generated
- ["A"]=65,
- ["AE"]=198,
- ["AEacute"]=508,
- ["AEmacron"]=482,
- ["Aacute"]=193,
- ["Abreve"]=258,
- ["Abreveacute"]=7854,
- ["Abrevecyrillic"]=1232,
- ["Abrevedotbelow"]=7862,
- ["Abrevegrave"]=7856,
- ["Abrevehookabove"]=7858,
- ["Abrevetilde"]=7860,
- ["Acaron"]=461,
- ["Acircle"]=9398,
- ["Acircumflex"]=194,
- ["Acircumflexacute"]=7844,
- ["Acircumflexdotbelow"]=7852,
- ["Acircumflexgrave"]=7846,
- ["Acircumflexhookabove"]=7848,
- ["Acircumflextilde"]=7850,
- ["Adblgrave"]=512,
- ["Adieresis"]=196,
- ["Adieresiscyrillic"]=1234,
- ["Adieresismacron"]=478,
- ["Adotbelow"]=7840,
- ["Adotmacron"]=480,
- ["Agrave"]=192,
- ["Ahookabove"]=7842,
- ["Aiecyrillic"]=1236,
- ["Ainvertedbreve"]=514,
- ["Alpha"]=913,
- ["Alphatonos"]=902,
- ["Amacron"]=256,
- ["Amonospace"]=65313,
- ["Aogonek"]=260,
- ["Aring"]=197,
- ["Aringacute"]=506,
- ["Aringbelow"]=7680,
- ["Atilde"]=195,
- ["Aybarmenian"]=1329,
- ["B"]=66,
- ["Bcircle"]=9399,
- ["Bdotaccent"]=7682,
- ["Bdotbelow"]=7684,
- ["Benarmenian"]=1330,
- ["Beta"]=914,
- ["Bhook"]=385,
- ["Blinebelow"]=7686,
- ["Bmonospace"]=65314,
- ["Btopbar"]=386,
- ["C"]=67,
- ["Caarmenian"]=1342,
- ["Cacute"]=262,
- ["Ccaron"]=268,
- ["Ccedilla"]=199,
- ["Ccedillaacute"]=7688,
- ["Ccircle"]=9400,
- ["Ccircumflex"]=264,
- ["Cdotaccent"]=266,
- ["Chaarmenian"]=1353,
- ["Cheabkhasiancyrillic"]=1212,
- ["Chedescenderabkhasiancyrillic"]=1214,
- ["Chedescendercyrillic"]=1206,
- ["Chedieresiscyrillic"]=1268,
- ["Cheharmenian"]=1347,
- ["Chekhakassiancyrillic"]=1227,
- ["Cheverticalstrokecyrillic"]=1208,
- ["Chi"]=935,
- ["Chook"]=391,
- ["Cmonospace"]=65315,
- ["Coarmenian"]=1361,
- ["D"]=68,
- ["DZ"]=497,
- ["DZcaron"]=452,
- ["Daarmenian"]=1332,
- ["Dafrican"]=393,
- ["Dcaron"]=270,
- ["Dcedilla"]=7696,
- ["Dcircle"]=9401,
- ["Dcircumflexbelow"]=7698,
- ["Ddotaccent"]=7690,
- ["Ddotbelow"]=7692,
- ["Deicoptic"]=1006,
- ["Deltagreek"]=916,
- ["Dhook"]=394,
- ["Digammagreek"]=988,
- ["Dlinebelow"]=7694,
- ["Dmonospace"]=65316,
- ["Dslash"]=272,
- ["Dtopbar"]=395,
- ["Dz"]=498,
- ["Dzcaron"]=453,
- ["Dzeabkhasiancyrillic"]=1248,
- ["E"]=69,
- ["Eacute"]=201,
- ["Ebreve"]=276,
- ["Ecaron"]=282,
- ["Ecedillabreve"]=7708,
- ["Echarmenian"]=1333,
- ["Ecircle"]=9402,
- ["Ecircumflex"]=202,
- ["Ecircumflexacute"]=7870,
- ["Ecircumflexbelow"]=7704,
- ["Ecircumflexdotbelow"]=7878,
- ["Ecircumflexgrave"]=7872,
- ["Ecircumflexhookabove"]=7874,
- ["Ecircumflextilde"]=7876,
- ["Edblgrave"]=516,
- ["Edieresis"]=203,
- ["Edotaccent"]=278,
- ["Edotbelow"]=7864,
- ["Egrave"]=200,
- ["Eharmenian"]=1335,
- ["Ehookabove"]=7866,
- ["Eightroman"]=8551,
- ["Einvertedbreve"]=518,
- ["Eiotifiedcyrillic"]=1124,
- ["Elevenroman"]=8554,
- ["Emacron"]=274,
- ["Emacronacute"]=7702,
- ["Emacrongrave"]=7700,
- ["Emonospace"]=65317,
- ["Endescendercyrillic"]=1186,
- ["Eng"]=330,
- ["Enghecyrillic"]=1188,
- ["Enhookcyrillic"]=1223,
- ["Eogonek"]=280,
- ["Eopen"]=400,
- ["Epsilon"]=917,
- ["Epsilontonos"]=904,
- ["Ereversed"]=398,
- ["Esdescendercyrillic"]=1194,
- ["Esh"]=425,
- ["Eta"]=919,
- ["Etarmenian"]=1336,
- ["Etatonos"]=905,
- ["Eth"]=208,
- ["Etilde"]=7868,
- ["Etildebelow"]=7706,
- ["Ezh"]=439,
- ["Ezhcaron"]=494,
- ["Ezhreversed"]=440,
- ["F"]=70,
- ["Fcircle"]=9403,
- ["Fdotaccent"]=7710,
- ["Feharmenian"]=1366,
- ["Feicoptic"]=996,
- ["Fhook"]=401,
- ["Fiveroman"]=8548,
- ["Fmonospace"]=65318,
- ["Fourroman"]=8547,
- ["G"]=71,
- ["GBsquare"]=13191,
- ["Gacute"]=500,
- ["Gamma"]=915,
- ["Gammaafrican"]=404,
- ["Gangiacoptic"]=1002,
- ["Gbreve"]=286,
- ["Gcaron"]=486,
- ["Gcircle"]=9404,
- ["Gcircumflex"]=284,
- ["Gcommaaccent"]=290,
- ["Gdotaccent"]=288,
- ["Ghadarmenian"]=1346,
- ["Ghemiddlehookcyrillic"]=1172,
- ["Ghestrokecyrillic"]=1170,
- ["Ghook"]=403,
- ["Gimarmenian"]=1331,
- ["Gmacron"]=7712,
- ["Gmonospace"]=65319,
- ["Gsmallhook"]=667,
- ["Gstroke"]=484,
- ["H"]=72,
- ["HPsquare"]=13259,
- ["Haabkhasiancyrillic"]=1192,
- ["Hadescendercyrillic"]=1202,
- ["Hbar"]=294,
- ["Hbrevebelow"]=7722,
- ["Hcedilla"]=7720,
- ["Hcircle"]=9405,
- ["Hcircumflex"]=292,
- ["Hdieresis"]=7718,
- ["Hdotaccent"]=7714,
- ["Hdotbelow"]=7716,
- ["Hmonospace"]=65320,
- ["Hoarmenian"]=1344,
- ["Horicoptic"]=1000,
- ["Hzsquare"]=13200,
- ["I"]=73,
- ["IJ"]=306,
- ["Iacute"]=205,
- ["Ibreve"]=300,
- ["Icaron"]=463,
- ["Icircle"]=9406,
- ["Icircumflex"]=206,
- ["Idblgrave"]=520,
- ["Idieresis"]=207,
- ["Idieresisacute"]=7726,
- ["Idieresiscyrillic"]=1252,
- ["Idotaccent"]=304,
- ["Idotbelow"]=7882,
- ["Iebrevecyrillic"]=1238,
- ["Ifraktur"]=8465,
- ["Igrave"]=204,
- ["Ihookabove"]=7880,
- ["Iinvertedbreve"]=522,
- ["Imacron"]=298,
- ["Imacroncyrillic"]=1250,
- ["Imonospace"]=65321,
- ["Iniarmenian"]=1339,
- ["Iogonek"]=302,
- ["Iota"]=921,
- ["Iotaafrican"]=406,
- ["Iotadieresis"]=938,
- ["Iotatonos"]=906,
- ["Istroke"]=407,
- ["Itilde"]=296,
- ["Itildebelow"]=7724,
- ["Izhitsadblgravecyrillic"]=1142,
- ["J"]=74,
- ["Jaarmenian"]=1345,
- ["Jcircle"]=9407,
- ["Jcircumflex"]=308,
- ["Jheharmenian"]=1355,
- ["Jmonospace"]=65322,
- ["K"]=75,
- ["KBsquare"]=13189,
- ["KKsquare"]=13261,
- ["Kabashkircyrillic"]=1184,
- ["Kacute"]=7728,
- ["Kadescendercyrillic"]=1178,
- ["Kahookcyrillic"]=1219,
- ["Kappa"]=922,
- ["Kastrokecyrillic"]=1182,
- ["Kaverticalstrokecyrillic"]=1180,
- ["Kcaron"]=488,
- ["Kcircle"]=9408,
- ["Kcommaaccent"]=310,
- ["Kdotbelow"]=7730,
- ["Keharmenian"]=1364,
- ["Kenarmenian"]=1343,
- ["Kheicoptic"]=998,
- ["Khook"]=408,
- ["Klinebelow"]=7732,
- ["Kmonospace"]=65323,
- ["Koppacyrillic"]=1152,
- ["Koppagreek"]=990,
- ["Ksicyrillic"]=1134,
- ["L"]=76,
- ["LJ"]=455,
- ["Lacute"]=313,
- ["Lambda"]=923,
- ["Lcaron"]=317,
- ["Lcircle"]=9409,
- ["Lcircumflexbelow"]=7740,
- ["Lcommaaccent"]=315,
- ["Ldotaccent"]=319,
- ["Ldotbelow"]=7734,
- ["Ldotbelowmacron"]=7736,
- ["Liwnarmenian"]=1340,
- ["Lj"]=456,
- ["Llinebelow"]=7738,
- ["Lmonospace"]=65324,
- ["Lslash"]=321,
- ["M"]=77,
- ["MBsquare"]=13190,
- ["Macute"]=7742,
- ["Mcircle"]=9410,
- ["Mdotaccent"]=7744,
- ["Mdotbelow"]=7746,
- ["Menarmenian"]=1348,
- ["Mmonospace"]=65325,
- ["Mturned"]=412,
- ["Mu"]=924,
- ["N"]=78,
- ["NJ"]=458,
- ["Nacute"]=323,
- ["Ncaron"]=327,
- ["Ncircle"]=9411,
- ["Ncircumflexbelow"]=7754,
- ["Ncommaaccent"]=325,
- ["Ndotaccent"]=7748,
- ["Ndotbelow"]=7750,
- ["Nhookleft"]=413,
- ["Nineroman"]=8552,
- ["Nj"]=459,
- ["Nlinebelow"]=7752,
- ["Nmonospace"]=65326,
- ["Nowarmenian"]=1350,
- ["Ntilde"]=209,
- ["Nu"]=925,
- ["O"]=79,
- ["OE"]=338,
- ["Oacute"]=211,
- ["Obarredcyrillic"]=1256,
- ["Obarreddieresiscyrillic"]=1258,
- ["Obreve"]=334,
- ["Ocaron"]=465,
- ["Ocenteredtilde"]=415,
- ["Ocircle"]=9412,
- ["Ocircumflex"]=212,
- ["Ocircumflexacute"]=7888,
- ["Ocircumflexdotbelow"]=7896,
- ["Ocircumflexgrave"]=7890,
- ["Ocircumflexhookabove"]=7892,
- ["Ocircumflextilde"]=7894,
- ["Odblgrave"]=524,
- ["Odieresis"]=214,
- ["Odieresiscyrillic"]=1254,
- ["Odotbelow"]=7884,
- ["Ograve"]=210,
- ["Oharmenian"]=1365,
- ["Ohookabove"]=7886,
- ["Ohorn"]=416,
- ["Ohornacute"]=7898,
- ["Ohorndotbelow"]=7906,
- ["Ohorngrave"]=7900,
- ["Ohornhookabove"]=7902,
- ["Ohorntilde"]=7904,
- ["Ohungarumlaut"]=336,
- ["Oi"]=418,
- ["Oinvertedbreve"]=526,
- ["Omacron"]=332,
- ["Omacronacute"]=7762,
- ["Omacrongrave"]=7760,
- ["Omega"]=8486,
- ["Omegacyrillic"]=1120,
- ["Omegagreek"]=937,
- ["Omegaroundcyrillic"]=1146,
- ["Omegatitlocyrillic"]=1148,
- ["Omegatonos"]=911,
- ["Omicron"]=927,
- ["Omicrontonos"]=908,
- ["Omonospace"]=65327,
- ["Oneroman"]=8544,
- ["Oogonek"]=490,
- ["Oogonekmacron"]=492,
- ["Oopen"]=390,
- ["Oslash"]=216,
- ["Ostrokeacute"]=510,
- ["Otcyrillic"]=1150,
- ["Otilde"]=213,
- ["Otildeacute"]=7756,
- ["Otildedieresis"]=7758,
- ["P"]=80,
- ["Pacute"]=7764,
- ["Pcircle"]=9413,
- ["Pdotaccent"]=7766,
- ["Peharmenian"]=1354,
- ["Pemiddlehookcyrillic"]=1190,
- ["Phi"]=934,
- ["Phook"]=420,
- ["Pi"]=928,
- ["Piwrarmenian"]=1363,
- ["Pmonospace"]=65328,
- ["Psi"]=936,
- ["Psicyrillic"]=1136,
- ["Q"]=81,
- ["Qcircle"]=9414,
- ["Qmonospace"]=65329,
- ["R"]=82,
- ["Raarmenian"]=1356,
- ["Racute"]=340,
- ["Rcaron"]=344,
- ["Rcircle"]=9415,
- ["Rcommaaccent"]=342,
- ["Rdblgrave"]=528,
- ["Rdotaccent"]=7768,
- ["Rdotbelow"]=7770,
- ["Rdotbelowmacron"]=7772,
- ["Reharmenian"]=1360,
- ["Rfraktur"]=8476,
- ["Rho"]=929,
- ["Rinvertedbreve"]=530,
- ["Rlinebelow"]=7774,
- ["Rmonospace"]=65330,
- ["Rsmallinverted"]=641,
- ["Rsmallinvertedsuperior"]=694,
- ["S"]=83,
- ["SF010000"]=9484,
- ["SF020000"]=9492,
- ["SF030000"]=9488,
- ["SF040000"]=9496,
- ["SF050000"]=9532,
- ["SF060000"]=9516,
- ["SF070000"]=9524,
- ["SF080000"]=9500,
- ["SF090000"]=9508,
- ["SF100000"]=9472,
- ["SF110000"]=9474,
- ["SF190000"]=9569,
- ["SF200000"]=9570,
- ["SF210000"]=9558,
- ["SF220000"]=9557,
- ["SF230000"]=9571,
- ["SF240000"]=9553,
- ["SF250000"]=9559,
- ["SF260000"]=9565,
- ["SF270000"]=9564,
- ["SF280000"]=9563,
- ["SF360000"]=9566,
- ["SF370000"]=9567,
- ["SF380000"]=9562,
- ["SF390000"]=9556,
- ["SF400000"]=9577,
- ["SF410000"]=9574,
- ["SF420000"]=9568,
- ["SF430000"]=9552,
- ["SF440000"]=9580,
- ["SF450000"]=9575,
- ["SF460000"]=9576,
- ["SF470000"]=9572,
- ["SF480000"]=9573,
- ["SF490000"]=9561,
- ["SF500000"]=9560,
- ["SF510000"]=9554,
- ["SF520000"]=9555,
- ["SF530000"]=9579,
- ["SF540000"]=9578,
- ["Sacute"]=346,
- ["Sacutedotaccent"]=7780,
- ["Sampigreek"]=992,
- ["Scaron"]=352,
- ["Scarondotaccent"]=7782,
- ["Scedilla"]=350,
- ["Schwa"]=399,
- ["Schwacyrillic"]=1240,
- ["Schwadieresiscyrillic"]=1242,
- ["Scircle"]=9416,
- ["Scircumflex"]=348,
- ["Scommaaccent"]=536,
- ["Sdotaccent"]=7776,
- ["Sdotbelow"]=7778,
- ["Sdotbelowdotaccent"]=7784,
- ["Seharmenian"]=1357,
- ["Sevenroman"]=8550,
- ["Shaarmenian"]=1351,
- ["Sheicoptic"]=994,
- ["Shhacyrillic"]=1210,
- ["Shimacoptic"]=1004,
- ["Sigma"]=931,
- ["Sixroman"]=8549,
- ["Smonospace"]=65331,
- ["Stigmagreek"]=986,
- ["T"]=84,
- ["Tau"]=932,
- ["Tbar"]=358,
- ["Tcaron"]=356,
- ["Tcircle"]=9417,
- ["Tcircumflexbelow"]=7792,
- ["Tcommaaccent"]=354,
- ["Tdotaccent"]=7786,
- ["Tdotbelow"]=7788,
- ["Tedescendercyrillic"]=1196,
- ["Tenroman"]=8553,
- ["Tetsecyrillic"]=1204,
- ["Theta"]=920,
- ["Thook"]=428,
- ["Thorn"]=222,
- ["Threeroman"]=8546,
- ["Tiwnarmenian"]=1359,
- ["Tlinebelow"]=7790,
- ["Tmonospace"]=65332,
- ["Toarmenian"]=1337,
- ["Tonefive"]=444,
- ["Tonesix"]=388,
- ["Tonetwo"]=423,
- ["Tretroflexhook"]=430,
- ["Twelveroman"]=8555,
- ["Tworoman"]=8545,
- ["U"]=85,
- ["Uacute"]=218,
- ["Ubreve"]=364,
- ["Ucaron"]=467,
- ["Ucircle"]=9418,
- ["Ucircumflex"]=219,
- ["Ucircumflexbelow"]=7798,
- ["Udblgrave"]=532,
- ["Udieresis"]=220,
- ["Udieresisacute"]=471,
- ["Udieresisbelow"]=7794,
- ["Udieresiscaron"]=473,
- ["Udieresiscyrillic"]=1264,
- ["Udieresisgrave"]=475,
- ["Udieresismacron"]=469,
- ["Udotbelow"]=7908,
- ["Ugrave"]=217,
- ["Uhookabove"]=7910,
- ["Uhorn"]=431,
- ["Uhornacute"]=7912,
- ["Uhorndotbelow"]=7920,
- ["Uhorngrave"]=7914,
- ["Uhornhookabove"]=7916,
- ["Uhorntilde"]=7918,
- ["Uhungarumlaut"]=368,
- ["Uhungarumlautcyrillic"]=1266,
- ["Uinvertedbreve"]=534,
- ["Ukcyrillic"]=1144,
- ["Umacron"]=362,
- ["Umacroncyrillic"]=1262,
- ["Umacrondieresis"]=7802,
- ["Umonospace"]=65333,
- ["Uogonek"]=370,
- ["Upsilon"]=933,
- ["Upsilonacutehooksymbolgreek"]=979,
- ["Upsilonafrican"]=433,
- ["Upsilondieresis"]=939,
- ["Upsilondieresishooksymbolgreek"]=980,
- ["Upsilonhooksymbol"]=978,
- ["Upsilontonos"]=910,
- ["Uring"]=366,
- ["Ustraightcyrillic"]=1198,
- ["Ustraightstrokecyrillic"]=1200,
- ["Utilde"]=360,
- ["Utildeacute"]=7800,
- ["Utildebelow"]=7796,
- ["V"]=86,
- ["Vcircle"]=9419,
- ["Vdotbelow"]=7806,
- ["Vewarmenian"]=1358,
- ["Vhook"]=434,
- ["Vmonospace"]=65334,
- ["Voarmenian"]=1352,
- ["Vtilde"]=7804,
- ["W"]=87,
- ["Wacute"]=7810,
- ["Wcircle"]=9420,
- ["Wcircumflex"]=372,
- ["Wdieresis"]=7812,
- ["Wdotaccent"]=7814,
- ["Wdotbelow"]=7816,
- ["Wgrave"]=7808,
- ["Wmonospace"]=65335,
- ["X"]=88,
- ["Xcircle"]=9421,
- ["Xdieresis"]=7820,
- ["Xdotaccent"]=7818,
- ["Xeharmenian"]=1341,
- ["Xi"]=926,
- ["Xmonospace"]=65336,
- ["Y"]=89,
- ["Yacute"]=221,
- ["Ycircle"]=9422,
- ["Ycircumflex"]=374,
- ["Ydieresis"]=376,
- ["Ydotaccent"]=7822,
- ["Ydotbelow"]=7924,
- ["Yerudieresiscyrillic"]=1272,
- ["Ygrave"]=7922,
- ["Yhook"]=435,
- ["Yhookabove"]=7926,
- ["Yiarmenian"]=1349,
- ["Yiwnarmenian"]=1362,
- ["Ymonospace"]=65337,
- ["Ytilde"]=7928,
- ["Yusbigcyrillic"]=1130,
- ["Yusbigiotifiedcyrillic"]=1132,
- ["Yuslittlecyrillic"]=1126,
- ["Yuslittleiotifiedcyrillic"]=1128,
- ["Z"]=90,
- ["Zaarmenian"]=1334,
- ["Zacute"]=377,
- ["Zcaron"]=381,
- ["Zcircle"]=9423,
- ["Zcircumflex"]=7824,
- ["Zdotaccent"]=379,
- ["Zdotbelow"]=7826,
- ["Zedescendercyrillic"]=1176,
- ["Zedieresiscyrillic"]=1246,
- ["Zeta"]=918,
- ["Zhearmenian"]=1338,
- ["Zhebrevecyrillic"]=1217,
- ["Zhedescendercyrillic"]=1174,
- ["Zhedieresiscyrillic"]=1244,
- ["Zlinebelow"]=7828,
- ["Zmonospace"]=65338,
- ["Zstroke"]=437,
- ["a"]=97,
- ["aabengali"]=2438,
- ["aacute"]=225,
- ["aadeva"]=2310,
- ["aagujarati"]=2694,
- ["aagurmukhi"]=2566,
- ["aamatragurmukhi"]=2622,
- ["aarusquare"]=13059,
- ["aavowelsignbengali"]=2494,
- ["aavowelsigndeva"]=2366,
- ["aavowelsigngujarati"]=2750,
- ["abbreviationmarkarmenian"]=1375,
- ["abbreviationsigndeva"]=2416,
- ["abengali"]=2437,
- ["abopomofo"]=12570,
- ["abreve"]=259,
- ["abreveacute"]=7855,
- ["abrevecyrillic"]=1233,
- ["abrevedotbelow"]=7863,
- ["abrevegrave"]=7857,
- ["abrevehookabove"]=7859,
- ["abrevetilde"]=7861,
- ["acaron"]=462,
- ["acircle"]=9424,
- ["acircumflex"]=226,
- ["acircumflexacute"]=7845,
- ["acircumflexdotbelow"]=7853,
- ["acircumflexgrave"]=7847,
- ["acircumflexhookabove"]=7849,
- ["acircumflextilde"]=7851,
- ["acute"]=180,
- ["acutebelowcmb"]=791,
- ["acutecomb"]=769,
- ["acutedeva"]=2388,
- ["acutelowmod"]=719,
- ["acutetonecmb"]=833,
- ["adblgrave"]=513,
- ["addakgurmukhi"]=2673,
- ["adeva"]=2309,
- ["adieresis"]=228,
- ["adieresiscyrillic"]=1235,
- ["adieresismacron"]=479,
- ["adotbelow"]=7841,
- ["adotmacron"]=481,
- ["ae"]=230,
- ["aeacute"]=509,
- ["aekorean"]=12624,
- ["aemacron"]=483,
- ["afii10017"]=1040,
- ["afii10018"]=1041,
- ["afii10019"]=1042,
- ["afii10020"]=1043,
- ["afii10021"]=1044,
- ["afii10022"]=1045,
- ["afii10023"]=1025,
- ["afii10024"]=1046,
- ["afii10025"]=1047,
- ["afii10026"]=1048,
- ["afii10027"]=1049,
- ["afii10028"]=1050,
- ["afii10029"]=1051,
- ["afii10030"]=1052,
- ["afii10031"]=1053,
- ["afii10032"]=1054,
- ["afii10033"]=1055,
- ["afii10034"]=1056,
- ["afii10035"]=1057,
- ["afii10036"]=1058,
- ["afii10037"]=1059,
- ["afii10038"]=1060,
- ["afii10039"]=1061,
- ["afii10040"]=1062,
- ["afii10041"]=1063,
- ["afii10042"]=1064,
- ["afii10043"]=1065,
- ["afii10044"]=1066,
- ["afii10045"]=1067,
- ["afii10046"]=1068,
- ["afii10047"]=1069,
- ["afii10048"]=1070,
- ["afii10049"]=1071,
- ["afii10050"]=1168,
- ["afii10051"]=1026,
- ["afii10052"]=1027,
- ["afii10053"]=1028,
- ["afii10054"]=1029,
- ["afii10055"]=1030,
- ["afii10056"]=1031,
- ["afii10057"]=1032,
- ["afii10058"]=1033,
- ["afii10059"]=1034,
- ["afii10060"]=1035,
- ["afii10061"]=1036,
- ["afii10062"]=1038,
- ["afii10065"]=1072,
- ["afii10145"]=1039,
- ["afii10146"]=1122,
- ["afii10147"]=1138,
- ["afii10148"]=1140,
- ["afii299"]=8206,
- ["afii300"]=8207,
- ["afii301"]=8205,
- ["afii57534"]=1749,
- ["afii61573"]=8236,
- ["afii61574"]=8237,
- ["afii61575"]=8238,
- ["agrave"]=224,
- ["agujarati"]=2693,
- ["agurmukhi"]=2565,
- ["ahiragana"]=12354,
- ["ahookabove"]=7843,
- ["aibengali"]=2448,
- ["aibopomofo"]=12574,
- ["aideva"]=2320,
- ["aiecyrillic"]=1237,
- ["aigujarati"]=2704,
- ["aigurmukhi"]=2576,
- ["aimatragurmukhi"]=2632,
- ["ainarabic"]=1593,
- ["ainfinalarabic"]=65226,
- ["aininitialarabic"]=65227,
- ["ainmedialarabic"]=65228,
- ["ainvertedbreve"]=515,
- ["aivowelsignbengali"]=2504,
- ["aivowelsigndeva"]=2376,
- ["aivowelsigngujarati"]=2760,
- ["akatakana"]=12450,
- ["akatakanahalfwidth"]=65393,
- ["akorean"]=12623,
- ["alefarabic"]=1575,
- ["alefdageshhebrew"]=64304,
- ["aleffinalarabic"]=65166,
- ["alefhamzaabovearabic"]=1571,
- ["alefhamzaabovefinalarabic"]=65156,
- ["alefhamzabelowarabic"]=1573,
- ["alefhamzabelowfinalarabic"]=65160,
- ["alefhebrew"]=1488,
- ["aleflamedhebrew"]=64335,
- ["alefmaddaabovearabic"]=1570,
- ["alefmaddaabovefinalarabic"]=65154,
- ["alefmaksuraarabic"]=1609,
- ["alefmaksurafinalarabic"]=65264,
- ["alefpatahhebrew"]=64302,
- ["alefqamatshebrew"]=64303,
- ["aleph"]=8501,
- ["allequal"]=8780,
- ["alpha"]=945,
- ["alphatonos"]=940,
- ["amacron"]=257,
- ["amonospace"]=65345,
- ["ampersand"]=38,
- ["ampersandmonospace"]=65286,
- ["amsquare"]=13250,
- ["anbopomofo"]=12578,
- ["angbopomofo"]=12580,
- ["angkhankhuthai"]=3674,
- ["angle"]=8736,
- ["anglebracketleft"]=12296,
- ["anglebracketleftvertical"]=65087,
- ["anglebracketright"]=12297,
- ["anglebracketrightvertical"]=65088,
- ["angleleft"]=9001,
- ["angleright"]=9002,
- ["angstrom"]=8491,
- ["anoteleia"]=903,
- ["anudattadeva"]=2386,
- ["anusvarabengali"]=2434,
- ["anusvaradeva"]=2306,
- ["anusvaragujarati"]=2690,
- ["aogonek"]=261,
- ["apaatosquare"]=13056,
- ["aparen"]=9372,
- ["apostrophearmenian"]=1370,
- ["apostrophemod"]=700,
- ["apple"]=63743,
- ["approaches"]=8784,
- ["approxequal"]=8776,
- ["approxequalorimage"]=8786,
- ["araeaekorean"]=12686,
- ["araeakorean"]=12685,
- ["arc"]=8978,
- ["arighthalfring"]=7834,
- ["aring"]=229,
- ["aringacute"]=507,
- ["aringbelow"]=7681,
- ["arrowboth"]=8596,
- ["arrowdashdown"]=8675,
- ["arrowdashleft"]=8672,
- ["arrowdashright"]=8674,
- ["arrowdashup"]=8673,
- ["arrowdbldown"]=8659,
- ["arrowdblup"]=8657,
- ["arrowdown"]=8595,
- ["arrowdownleft"]=8601,
- ["arrowdownright"]=8600,
- ["arrowdownwhite"]=8681,
- ["arrowheaddownmod"]=709,
- ["arrowheadleftmod"]=706,
- ["arrowheadrightmod"]=707,
- ["arrowheadupmod"]=708,
- ["arrowleft"]=8592,
- ["arrowleftdbl"]=8656,
- ["arrowleftdblstroke"]=8653,
- ["arrowleftoverright"]=8646,
- ["arrowleftwhite"]=8678,
- ["arrowright"]=8594,
- ["arrowrightdblstroke"]=8655,
- ["arrowrightheavy"]=10142,
- ["arrowrightoverleft"]=8644,
- ["arrowrightwhite"]=8680,
- ["arrowtableft"]=8676,
- ["arrowtabright"]=8677,
- ["arrowup"]=8593,
- ["arrowupdn"]=8597,
- ["arrowupdownbase"]=8616,
- ["arrowupleft"]=8598,
- ["arrowupleftofdown"]=8645,
- ["arrowupright"]=8599,
- ["arrowupwhite"]=8679,
- ["asciicircum"]=94,
- ["asciicircummonospace"]=65342,
- ["asciitilde"]=126,
- ["asciitildemonospace"]=65374,
- ["ascript"]=593,
- ["ascriptturned"]=594,
- ["asmallhiragana"]=12353,
- ["asmallkatakana"]=12449,
- ["asmallkatakanahalfwidth"]=65383,
- ["asterisk"]=42,
- ["asteriskarabic"]=1645,
- ["asteriskmath"]=8727,
- ["asteriskmonospace"]=65290,
- ["asterisksmall"]=65121,
- ["asterism"]=8258,
- ["asymptoticallyequal"]=8771,
- ["at"]=64,
- ["atilde"]=227,
- ["atmonospace"]=65312,
- ["atsmall"]=65131,
- ["aturned"]=592,
- ["aubengali"]=2452,
- ["aubopomofo"]=12576,
- ["audeva"]=2324,
- ["augujarati"]=2708,
- ["augurmukhi"]=2580,
- ["aulengthmarkbengali"]=2519,
- ["aumatragurmukhi"]=2636,
- ["auvowelsignbengali"]=2508,
- ["auvowelsigndeva"]=2380,
- ["auvowelsigngujarati"]=2764,
- ["avagrahadeva"]=2365,
- ["aybarmenian"]=1377,
- ["ayinaltonehebrew"]=64288,
- ["ayinhebrew"]=1506,
- ["b"]=98,
- ["babengali"]=2476,
- ["backslash"]=92,
- ["backslashmonospace"]=65340,
- ["badeva"]=2348,
- ["bagujarati"]=2732,
- ["bagurmukhi"]=2604,
- ["bahiragana"]=12400,
- ["bahtthai"]=3647,
- ["bakatakana"]=12496,
- ["barmonospace"]=65372,
- ["bbopomofo"]=12549,
- ["bcircle"]=9425,
- ["bdotaccent"]=7683,
- ["bdotbelow"]=7685,
- ["beamedsixteenthnotes"]=9836,
- ["because"]=8757,
- ["becyrillic"]=1073,
- ["beharabic"]=1576,
- ["behfinalarabic"]=65168,
- ["behinitialarabic"]=65169,
- ["behiragana"]=12409,
- ["behmedialarabic"]=65170,
- ["behmeeminitialarabic"]=64671,
- ["behmeemisolatedarabic"]=64520,
- ["behnoonfinalarabic"]=64621,
- ["bekatakana"]=12505,
- ["benarmenian"]=1378,
- ["beta"]=946,
- ["betasymbolgreek"]=976,
- ["betdageshhebrew"]=64305,
- ["bethebrew"]=1489,
- ["betrafehebrew"]=64332,
- ["bhabengali"]=2477,
- ["bhadeva"]=2349,
- ["bhagujarati"]=2733,
- ["bhagurmukhi"]=2605,
- ["bhook"]=595,
- ["bihiragana"]=12403,
- ["bikatakana"]=12499,
- ["bilabialclick"]=664,
- ["bindigurmukhi"]=2562,
- ["birusquare"]=13105,
- ["blackcircle"]=9679,
- ["blackdiamond"]=9670,
- ["blackleftpointingtriangle"]=9664,
- ["blacklenticularbracketleft"]=12304,
- ["blacklenticularbracketleftvertical"]=65083,
- ["blacklenticularbracketright"]=12305,
- ["blacklenticularbracketrightvertical"]=65084,
- ["blacklowerlefttriangle"]=9699,
- ["blacklowerrighttriangle"]=9698,
- ["blackrightpointingtriangle"]=9654,
- ["blacksmallsquare"]=9642,
- ["blackstar"]=9733,
- ["blackupperlefttriangle"]=9700,
- ["blackupperrighttriangle"]=9701,
- ["blackuppointingsmalltriangle"]=9652,
- ["blank"]=9251,
- ["blinebelow"]=7687,
- ["block"]=9608,
- ["bmonospace"]=65346,
- ["bobaimaithai"]=3610,
- ["bohiragana"]=12412,
- ["bokatakana"]=12508,
- ["bparen"]=9373,
- ["bqsquare"]=13251,
- ["braceleft"]=123,
- ["braceleftmonospace"]=65371,
- ["braceleftsmall"]=65115,
- ["braceleftvertical"]=65079,
- ["braceright"]=125,
- ["bracerightmonospace"]=65373,
- ["bracerightsmall"]=65116,
- ["bracerightvertical"]=65080,
- ["bracketleft"]=91,
- ["bracketleftmonospace"]=65339,
- ["bracketright"]=93,
- ["bracketrightmonospace"]=65341,
- ["breve"]=728,
- ["brevebelowcmb"]=814,
- ["brevecmb"]=774,
- ["breveinvertedbelowcmb"]=815,
- ["breveinvertedcmb"]=785,
- ["breveinverteddoublecmb"]=865,
- ["bridgebelowcmb"]=810,
- ["bridgeinvertedbelowcmb"]=826,
- ["brokenbar"]=166,
- ["bstroke"]=384,
- ["btopbar"]=387,
- ["buhiragana"]=12406,
- ["bukatakana"]=12502,
- ["bullet"]=8226,
- ["bulletoperator"]=8729,
- ["bullseye"]=9678,
- ["c"]=99,
- ["caarmenian"]=1390,
- ["cabengali"]=2458,
- ["cacute"]=263,
- ["cadeva"]=2330,
- ["cagujarati"]=2714,
- ["cagurmukhi"]=2586,
- ["calsquare"]=13192,
- ["candrabindubengali"]=2433,
- ["candrabinducmb"]=784,
- ["candrabindudeva"]=2305,
- ["candrabindugujarati"]=2689,
- ["capslock"]=8682,
- ["careof"]=8453,
- ["caron"]=711,
- ["caronbelowcmb"]=812,
- ["caroncmb"]=780,
- ["carriagereturn"]=8629,
- ["cbopomofo"]=12568,
- ["ccaron"]=269,
- ["ccedilla"]=231,
- ["ccedillaacute"]=7689,
- ["ccircle"]=9426,
- ["ccircumflex"]=265,
- ["ccurl"]=597,
- ["cdotaccent"]=267,
- ["cdsquare"]=13253,
- ["cedilla"]=184,
- ["cedillacmb"]=807,
- ["cent"]=162,
- ["centigrade"]=8451,
- ["centmonospace"]=65504,
- ["chaarmenian"]=1401,
- ["chabengali"]=2459,
- ["chadeva"]=2331,
- ["chagujarati"]=2715,
- ["chagurmukhi"]=2587,
- ["chbopomofo"]=12564,
- ["cheabkhasiancyrillic"]=1213,
- ["checkmark"]=10003,
- ["checyrillic"]=1095,
- ["chedescenderabkhasiancyrillic"]=1215,
- ["chedescendercyrillic"]=1207,
- ["chedieresiscyrillic"]=1269,
- ["cheharmenian"]=1395,
- ["chekhakassiancyrillic"]=1228,
- ["cheverticalstrokecyrillic"]=1209,
- ["chi"]=967,
- ["chieuchacirclekorean"]=12919,
- ["chieuchaparenkorean"]=12823,
- ["chieuchcirclekorean"]=12905,
- ["chieuchkorean"]=12618,
- ["chieuchparenkorean"]=12809,
- ["chochangthai"]=3594,
- ["chochanthai"]=3592,
- ["chochingthai"]=3593,
- ["chochoethai"]=3596,
- ["chook"]=392,
- ["cieucacirclekorean"]=12918,
- ["cieucaparenkorean"]=12822,
- ["cieuccirclekorean"]=12904,
- ["cieuckorean"]=12616,
- ["cieucparenkorean"]=12808,
- ["cieucuparenkorean"]=12828,
- ["circleot"]=8857,
- ["circlepostalmark"]=12342,
- ["circlewithlefthalfblack"]=9680,
- ["circlewithrighthalfblack"]=9681,
- ["circumflex"]=710,
- ["circumflexbelowcmb"]=813,
- ["circumflexcmb"]=770,
- ["clear"]=8999,
- ["clickalveolar"]=450,
- ["clickdental"]=448,
- ["clicklateral"]=449,
- ["clickretroflex"]=451,
- ["clubsuitblack"]=9827,
- ["clubsuitwhite"]=9831,
- ["cmcubedsquare"]=13220,
- ["cmonospace"]=65347,
- ["cmsquaredsquare"]=13216,
- ["coarmenian"]=1409,
- ["colon"]=58,
- ["colonmonospace"]=65306,
- ["colonsign"]=8353,
- ["colonsmall"]=65109,
- ["colontriangularhalfmod"]=721,
- ["colontriangularmod"]=720,
- ["comma"]=44,
- ["commaabovecmb"]=787,
- ["commaaboverightcmb"]=789,
- ["commaarabic"]=1548,
- ["commaarmenian"]=1373,
- ["commamonospace"]=65292,
- ["commareversedabovecmb"]=788,
- ["commareversedmod"]=701,
- ["commasmall"]=65104,
- ["commaturnedabovecmb"]=786,
- ["commaturnedmod"]=699,
- ["congruent"]=8773,
- ["contourintegral"]=8750,
- ["control"]=8963,
- ["controlACK"]=6,
- ["controlBEL"]=7,
- ["controlBS"]=8,
- ["controlCAN"]=24,
- ["controlCR"]=13,
- ["controlDC1"]=17,
- ["controlDC2"]=18,
- ["controlDC3"]=19,
- ["controlDC4"]=20,
- ["controlDEL"]=127,
- ["controlDLE"]=16,
- ["controlEM"]=25,
- ["controlENQ"]=5,
- ["controlEOT"]=4,
- ["controlESC"]=27,
- ["controlETB"]=23,
- ["controlETX"]=3,
- ["controlFF"]=12,
- ["controlFS"]=28,
- ["controlGS"]=29,
- ["controlHT"]=9,
- ["controlLF"]=10,
- ["controlNAK"]=21,
- ["controlRS"]=30,
- ["controlSI"]=15,
- ["controlSO"]=14,
- ["controlSOT"]=2,
- ["controlSTX"]=1,
- ["controlSUB"]=26,
- ["controlSYN"]=22,
- ["controlUS"]=31,
- ["controlVT"]=11,
- ["copyright"]=169,
- ["cornerbracketleft"]=12300,
- ["cornerbracketlefthalfwidth"]=65378,
- ["cornerbracketleftvertical"]=65089,
- ["cornerbracketright"]=12301,
- ["cornerbracketrighthalfwidth"]=65379,
- ["cornerbracketrightvertical"]=65090,
- ["corporationsquare"]=13183,
- ["cosquare"]=13255,
- ["coverkgsquare"]=13254,
- ["cparen"]=9374,
- ["cruzeiro"]=8354,
- ["cstretched"]=663,
- ["curlyand"]=8911,
- ["curlyor"]=8910,
- ["currency"]=164,
- ["d"]=100,
- ["daarmenian"]=1380,
- ["dabengali"]=2470,
- ["dadarabic"]=1590,
- ["dadeva"]=2342,
- ["dadfinalarabic"]=65214,
- ["dadinitialarabic"]=65215,
- ["dadmedialarabic"]=65216,
- ["dageshhebrew"]=1468,
- ["dagger"]=8224,
- ["daggerdbl"]=8225,
- ["dagujarati"]=2726,
- ["dagurmukhi"]=2598,
- ["dahiragana"]=12384,
- ["dakatakana"]=12480,
- ["dalarabic"]=1583,
- ["daletdageshhebrew"]=64307,
- ["dalettserehebrew"]=1491,
- ["dalfinalarabic"]=65194,
- ["dammalowarabic"]=1615,
- ["dammatanarabic"]=1612,
- ["danda"]=2404,
- ["dargalefthebrew"]=1447,
- ["dasiapneumatacyrilliccmb"]=1157,
- ["dblanglebracketleft"]=12298,
- ["dblanglebracketleftvertical"]=65085,
- ["dblanglebracketright"]=12299,
- ["dblanglebracketrightvertical"]=65086,
- ["dblarchinvertedbelowcmb"]=811,
- ["dblarrowleft"]=8660,
- ["dblarrowright"]=8658,
- ["dbldanda"]=2405,
- ["dblgravecmb"]=783,
- ["dblintegral"]=8748,
- ["dbllowlinecmb"]=819,
- ["dbloverlinecmb"]=831,
- ["dblprimemod"]=698,
- ["dblverticalbar"]=8214,
- ["dblverticallineabovecmb"]=782,
- ["dbopomofo"]=12553,
- ["dbsquare"]=13256,
- ["dcaron"]=271,
- ["dcedilla"]=7697,
- ["dcircle"]=9427,
- ["dcircumflexbelow"]=7699,
- ["ddabengali"]=2465,
- ["ddadeva"]=2337,
- ["ddagujarati"]=2721,
- ["ddagurmukhi"]=2593,
- ["ddalarabic"]=1672,
- ["ddalfinalarabic"]=64393,
- ["dddhadeva"]=2396,
- ["ddhabengali"]=2466,
- ["ddhadeva"]=2338,
- ["ddhagujarati"]=2722,
- ["ddhagurmukhi"]=2594,
- ["ddotaccent"]=7691,
- ["ddotbelow"]=7693,
- ["decimalseparatorpersian"]=1643,
- ["decyrillic"]=1076,
- ["degree"]=176,
- ["dehihebrew"]=1453,
- ["dehiragana"]=12391,
- ["deicoptic"]=1007,
- ["dekatakana"]=12487,
- ["deleteleft"]=9003,
- ["deleteright"]=8998,
- ["delta"]=948,
- ["deltaturned"]=397,
- ["denominatorminusonenumeratorbengali"]=2552,
- ["dezh"]=676,
- ["dhabengali"]=2471,
- ["dhadeva"]=2343,
- ["dhagujarati"]=2727,
- ["dhagurmukhi"]=2599,
- ["dhook"]=599,
- ["dialytikatonoscmb"]=836,
- ["diamond"]=9830,
- ["diamondsuitwhite"]=9826,
- ["dieresis"]=168,
- ["dieresisbelowcmb"]=804,
- ["dieresiscmb"]=776,
- ["dieresistonos"]=901,
- ["dihiragana"]=12386,
- ["dikatakana"]=12482,
- ["dittomark"]=12291,
- ["divide"]=247,
- ["divides"]=8739,
- ["divisionslash"]=8725,
- ["djecyrillic"]=1106,
- ["dlinebelow"]=7695,
- ["dlsquare"]=13207,
- ["dmacron"]=273,
- ["dmonospace"]=65348,
- ["dnblock"]=9604,
- ["dochadathai"]=3598,
- ["dodekthai"]=3604,
- ["dohiragana"]=12393,
- ["dokatakana"]=12489,
- ["dollar"]=36,
- ["dollarmonospace"]=65284,
- ["dollarsmall"]=65129,
- ["dong"]=8363,
- ["dorusquare"]=13094,
- ["dotaccent"]=729,
- ["dotaccentcmb"]=775,
- ["dotbelowcomb"]=803,
- ["dotkatakana"]=12539,
- ["dotlessi"]=305,
- ["dotlessjstrokehook"]=644,
- ["dotmath"]=8901,
- ["dottedcircle"]=9676,
- ["downtackbelowcmb"]=798,
- ["downtackmod"]=725,
- ["dparen"]=9375,
- ["dtail"]=598,
- ["dtopbar"]=396,
- ["duhiragana"]=12389,
- ["dukatakana"]=12485,
- ["dz"]=499,
- ["dzaltone"]=675,
- ["dzcaron"]=454,
- ["dzcurl"]=677,
- ["dzeabkhasiancyrillic"]=1249,
- ["dzecyrillic"]=1109,
- ["dzhecyrillic"]=1119,
- ["e"]=101,
- ["eacute"]=233,
- ["earth"]=9793,
- ["ebengali"]=2447,
- ["ebopomofo"]=12572,
- ["ebreve"]=277,
- ["ecandradeva"]=2317,
- ["ecandragujarati"]=2701,
- ["ecandravowelsigndeva"]=2373,
- ["ecandravowelsigngujarati"]=2757,
- ["ecaron"]=283,
- ["ecedillabreve"]=7709,
- ["echarmenian"]=1381,
- ["echyiwnarmenian"]=1415,
- ["ecircle"]=9428,
- ["ecircumflex"]=234,
- ["ecircumflexacute"]=7871,
- ["ecircumflexbelow"]=7705,
- ["ecircumflexdotbelow"]=7879,
- ["ecircumflexgrave"]=7873,
- ["ecircumflexhookabove"]=7875,
- ["ecircumflextilde"]=7877,
- ["ecyrillic"]=1108,
- ["edblgrave"]=517,
- ["edeva"]=2319,
- ["edieresis"]=235,
- ["edotaccent"]=279,
- ["edotbelow"]=7865,
- ["eegurmukhi"]=2575,
- ["eematragurmukhi"]=2631,
- ["efcyrillic"]=1092,
- ["egrave"]=232,
- ["egujarati"]=2703,
- ["eharmenian"]=1383,
- ["ehbopomofo"]=12573,
- ["ehiragana"]=12360,
- ["ehookabove"]=7867,
- ["eibopomofo"]=12575,
- ["eight"]=56,
- ["eightbengali"]=2542,
- ["eightcircle"]=9319,
- ["eightcircleinversesansserif"]=10129,
- ["eightdeva"]=2414,
- ["eighteencircle"]=9329,
- ["eighteenparen"]=9349,
- ["eighteenperiod"]=9369,
- ["eightgujarati"]=2798,
- ["eightgurmukhi"]=2670,
- ["eighthackarabic"]=1640,
- ["eighthangzhou"]=12328,
- ["eightideographicparen"]=12839,
- ["eightinferior"]=8328,
- ["eightmonospace"]=65304,
- ["eightparen"]=9339,
- ["eightperiod"]=9359,
- ["eightpersian"]=1784,
- ["eightroman"]=8567,
- ["eightsuperior"]=8312,
- ["eightthai"]=3672,
- ["einvertedbreve"]=519,
- ["eiotifiedcyrillic"]=1125,
- ["ekatakana"]=12456,
- ["ekatakanahalfwidth"]=65396,
- ["ekonkargurmukhi"]=2676,
- ["ekorean"]=12628,
- ["elcyrillic"]=1083,
- ["element"]=8712,
- ["elevencircle"]=9322,
- ["elevenparen"]=9342,
- ["elevenperiod"]=9362,
- ["elevenroman"]=8570,
- ["ellipsis"]=8230,
- ["ellipsisvertical"]=8942,
- ["emacron"]=275,
- ["emacronacute"]=7703,
- ["emacrongrave"]=7701,
- ["emcyrillic"]=1084,
- ["emdash"]=8212,
- ["emdashvertical"]=65073,
- ["emonospace"]=65349,
- ["emphasismarkarmenian"]=1371,
- ["emptyset"]=8709,
- ["enbopomofo"]=12579,
- ["encyrillic"]=1085,
- ["endash"]=8211,
- ["endashvertical"]=65074,
- ["endescendercyrillic"]=1187,
- ["eng"]=331,
- ["engbopomofo"]=12581,
- ["enghecyrillic"]=1189,
- ["enhookcyrillic"]=1224,
- ["enspace"]=8194,
- ["eogonek"]=281,
- ["eokorean"]=12627,
- ["eopen"]=603,
- ["eopenclosed"]=666,
- ["eopenreversed"]=604,
- ["eopenreversedclosed"]=606,
- ["eopenreversedhook"]=605,
- ["eparen"]=9376,
- ["epsilon"]=949,
- ["epsilontonos"]=941,
- ["equal"]=61,
- ["equalmonospace"]=65309,
- ["equalsmall"]=65126,
- ["equalsuperior"]=8316,
- ["equivalence"]=8801,
- ["erbopomofo"]=12582,
- ["ercyrillic"]=1088,
- ["ereversed"]=600,
- ["ereversedcyrillic"]=1101,
- ["escyrillic"]=1089,
- ["esdescendercyrillic"]=1195,
- ["esh"]=643,
- ["eshcurl"]=646,
- ["eshortdeva"]=2318,
- ["eshortvowelsigndeva"]=2374,
- ["eshreversedloop"]=426,
- ["eshsquatreversed"]=645,
- ["esmallhiragana"]=12359,
- ["esmallkatakana"]=12455,
- ["esmallkatakanahalfwidth"]=65386,
- ["estimated"]=8494,
- ["eta"]=951,
- ["etarmenian"]=1384,
- ["etatonos"]=942,
- ["eth"]=240,
- ["etilde"]=7869,
- ["etildebelow"]=7707,
- ["etnahtalefthebrew"]=1425,
- ["eturned"]=477,
- ["eukorean"]=12641,
- ["euro"]=8364,
- ["evowelsignbengali"]=2503,
- ["evowelsigndeva"]=2375,
- ["evowelsigngujarati"]=2759,
- ["exclam"]=33,
- ["exclamarmenian"]=1372,
- ["exclamdbl"]=8252,
- ["exclamdown"]=161,
- ["exclammonospace"]=65281,
- ["ezh"]=658,
- ["ezhcaron"]=495,
- ["ezhcurl"]=659,
- ["ezhreversed"]=441,
- ["ezhtail"]=442,
- ["f"]=102,
- ["fadeva"]=2398,
- ["fagurmukhi"]=2654,
- ["fahrenheit"]=8457,
- ["fathalowarabic"]=1614,
- ["fathatanarabic"]=1611,
- ["fbopomofo"]=12552,
- ["fcircle"]=9429,
- ["fdotaccent"]=7711,
- ["feharabic"]=1601,
- ["feharmenian"]=1414,
- ["fehfinalarabic"]=65234,
- ["fehinitialarabic"]=65235,
- ["fehmedialarabic"]=65236,
- ["feicoptic"]=997,
- ["ff"]=64256,
- ["ffi"]=64259,
- ["ffl"]=64260,
- ["fi"]=64257,
- ["fifteencircle"]=9326,
- ["fifteenparen"]=9346,
- ["fifteenperiod"]=9366,
- ["figuredash"]=8210,
- ["filledbox"]=9632,
- ["filledrect"]=9644,
- ["finalkafdageshhebrew"]=64314,
- ["finalkafshevahebrew"]=1498,
- ["finalmemhebrew"]=1501,
- ["finalnunhebrew"]=1503,
- ["finalpehebrew"]=1507,
- ["finaltsadihebrew"]=1509,
- ["firsttonechinese"]=713,
- ["fisheye"]=9673,
- ["fitacyrillic"]=1139,
- ["five"]=53,
- ["fivebengali"]=2539,
- ["fivecircle"]=9316,
- ["fivecircleinversesansserif"]=10126,
- ["fivedeva"]=2411,
- ["fiveeighths"]=8541,
- ["fivegujarati"]=2795,
- ["fivegurmukhi"]=2667,
- ["fivehackarabic"]=1637,
- ["fivehangzhou"]=12325,
- ["fiveideographicparen"]=12836,
- ["fiveinferior"]=8325,
- ["fivemonospace"]=65301,
- ["fiveparen"]=9336,
- ["fiveperiod"]=9356,
- ["fivepersian"]=1781,
- ["fiveroman"]=8564,
- ["fivesuperior"]=8309,
- ["fivethai"]=3669,
- ["fl"]=64258,
- ["florin"]=402,
- ["fmonospace"]=65350,
- ["fmsquare"]=13209,
- ["fofanthai"]=3615,
- ["fofathai"]=3613,
- ["fongmanthai"]=3663,
- ["four"]=52,
- ["fourbengali"]=2538,
- ["fourcircle"]=9315,
- ["fourcircleinversesansserif"]=10125,
- ["fourdeva"]=2410,
- ["fourgujarati"]=2794,
- ["fourgurmukhi"]=2666,
- ["fourhackarabic"]=1636,
- ["fourhangzhou"]=12324,
- ["fourideographicparen"]=12835,
- ["fourinferior"]=8324,
- ["fourmonospace"]=65300,
- ["fournumeratorbengali"]=2551,
- ["fourparen"]=9335,
- ["fourperiod"]=9355,
- ["fourpersian"]=1780,
- ["fourroman"]=8563,
- ["foursuperior"]=8308,
- ["fourteencircle"]=9325,
- ["fourteenparen"]=9345,
- ["fourteenperiod"]=9365,
- ["fourthai"]=3668,
- ["fourthtonechinese"]=715,
- ["fparen"]=9377,
- ["fraction"]=8260,
- ["franc"]=8355,
- ["g"]=103,
- ["gabengali"]=2455,
- ["gacute"]=501,
- ["gadeva"]=2327,
- ["gafarabic"]=1711,
- ["gaffinalarabic"]=64403,
- ["gafinitialarabic"]=64404,
- ["gafmedialarabic"]=64405,
- ["gagujarati"]=2711,
- ["gagurmukhi"]=2583,
- ["gahiragana"]=12364,
- ["gakatakana"]=12460,
- ["gamma"]=947,
- ["gammalatinsmall"]=611,
- ["gammasuperior"]=736,
- ["gangiacoptic"]=1003,
- ["gbopomofo"]=12557,
- ["gbreve"]=287,
- ["gcaron"]=487,
- ["gcircle"]=9430,
- ["gcircumflex"]=285,
- ["gcommaaccent"]=291,
- ["gdotaccent"]=289,
- ["gecyrillic"]=1075,
- ["gehiragana"]=12370,
- ["gekatakana"]=12466,
- ["geometricallyequal"]=8785,
- ["gereshaccenthebrew"]=1436,
- ["gereshhebrew"]=1523,
- ["gereshmuqdamhebrew"]=1437,
- ["germandbls"]=223,
- ["gershayimaccenthebrew"]=1438,
- ["gershayimhebrew"]=1524,
- ["getamark"]=12307,
- ["ghabengali"]=2456,
- ["ghadarmenian"]=1394,
- ["ghadeva"]=2328,
- ["ghagujarati"]=2712,
- ["ghagurmukhi"]=2584,
- ["ghainarabic"]=1594,
- ["ghainfinalarabic"]=65230,
- ["ghaininitialarabic"]=65231,
- ["ghainmedialarabic"]=65232,
- ["ghemiddlehookcyrillic"]=1173,
- ["ghestrokecyrillic"]=1171,
- ["gheupturncyrillic"]=1169,
- ["ghhadeva"]=2394,
- ["ghhagurmukhi"]=2650,
- ["ghook"]=608,
- ["ghzsquare"]=13203,
- ["gihiragana"]=12366,
- ["gikatakana"]=12462,
- ["gimarmenian"]=1379,
- ["gimeldageshhebrew"]=64306,
- ["gimelhebrew"]=1490,
- ["gjecyrillic"]=1107,
- ["glottalinvertedstroke"]=446,
- ["glottalstop"]=660,
- ["glottalstopinverted"]=662,
- ["glottalstopmod"]=704,
- ["glottalstopreversed"]=661,
- ["glottalstopreversedmod"]=705,
- ["glottalstopreversedsuperior"]=740,
- ["glottalstopstroke"]=673,
- ["glottalstopstrokereversed"]=674,
- ["gmacron"]=7713,
- ["gmonospace"]=65351,
- ["gohiragana"]=12372,
- ["gokatakana"]=12468,
- ["gparen"]=9378,
- ["gpasquare"]=13228,
- ["grave"]=96,
- ["gravebelowcmb"]=790,
- ["gravecomb"]=768,
- ["gravedeva"]=2387,
- ["gravelowmod"]=718,
- ["gravemonospace"]=65344,
- ["gravetonecmb"]=832,
- ["greater"]=62,
- ["greaterequal"]=8805,
- ["greaterequalorless"]=8923,
- ["greatermonospace"]=65310,
- ["greaterorequivalent"]=8819,
- ["greaterorless"]=8823,
- ["greateroverequal"]=8807,
- ["greatersmall"]=65125,
- ["gscript"]=609,
- ["gstroke"]=485,
- ["guhiragana"]=12368,
- ["guillemotleft"]=171,
- ["guillemotright"]=187,
- ["guilsinglleft"]=8249,
- ["guilsinglright"]=8250,
- ["gukatakana"]=12464,
- ["guramusquare"]=13080,
- ["gysquare"]=13257,
- ["h"]=104,
- ["haabkhasiancyrillic"]=1193,
- ["habengali"]=2489,
- ["hadescendercyrillic"]=1203,
- ["hadeva"]=2361,
- ["hagujarati"]=2745,
- ["hagurmukhi"]=2617,
- ["haharabic"]=1581,
- ["hahfinalarabic"]=65186,
- ["hahinitialarabic"]=65187,
- ["hahiragana"]=12399,
- ["hahmedialarabic"]=65188,
- ["haitusquare"]=13098,
- ["hakatakana"]=12495,
- ["hakatakanahalfwidth"]=65418,
- ["halantgurmukhi"]=2637,
- ["hamzasukunarabic"]=1569,
- ["hangulfiller"]=12644,
- ["hardsigncyrillic"]=1098,
- ["harpoonleftbarbup"]=8636,
- ["harpoonrightbarbup"]=8640,
- ["hasquare"]=13258,
- ["hatafpatahwidehebrew"]=1458,
- ["hatafqamatswidehebrew"]=1459,
- ["hatafsegolwidehebrew"]=1457,
- ["hbar"]=295,
- ["hbopomofo"]=12559,
- ["hbrevebelow"]=7723,
- ["hcedilla"]=7721,
- ["hcircle"]=9431,
- ["hcircumflex"]=293,
- ["hdieresis"]=7719,
- ["hdotaccent"]=7715,
- ["hdotbelow"]=7717,
- ["heartsuitblack"]=9829,
- ["heartsuitwhite"]=9825,
- ["hedageshhebrew"]=64308,
- ["hehaltonearabic"]=1729,
- ["heharabic"]=1607,
- ["hehebrew"]=1492,
- ["hehfinalaltonearabic"]=64423,
- ["hehfinalarabic"]=65258,
- ["hehhamzaabovefinalarabic"]=64421,
- ["hehhamzaaboveisolatedarabic"]=64420,
- ["hehinitialaltonearabic"]=64424,
- ["hehinitialarabic"]=65259,
- ["hehiragana"]=12408,
- ["hehmedialaltonearabic"]=64425,
- ["hehmedialarabic"]=65260,
- ["heiseierasquare"]=13179,
- ["hekatakana"]=12504,
- ["hekatakanahalfwidth"]=65421,
- ["hekutaarusquare"]=13110,
- ["henghook"]=615,
- ["herutusquare"]=13113,
- ["hethebrew"]=1495,
- ["hhook"]=614,
- ["hhooksuperior"]=689,
- ["hieuhacirclekorean"]=12923,
- ["hieuhaparenkorean"]=12827,
- ["hieuhcirclekorean"]=12909,
- ["hieuhkorean"]=12622,
- ["hieuhparenkorean"]=12813,
- ["hihiragana"]=12402,
- ["hikatakana"]=12498,
- ["hikatakanahalfwidth"]=65419,
- ["hiriqwidehebrew"]=1460,
- ["hlinebelow"]=7830,
- ["hmonospace"]=65352,
- ["hoarmenian"]=1392,
- ["hohipthai"]=3627,
- ["hohiragana"]=12411,
- ["hokatakana"]=12507,
- ["hokatakanahalfwidth"]=65422,
- ["holamwidehebrew"]=1465,
- ["honokhukthai"]=3630,
- ["hookcmb"]=777,
- ["hookpalatalizedbelowcmb"]=801,
- ["hookretroflexbelowcmb"]=802,
- ["hoonsquare"]=13122,
- ["horicoptic"]=1001,
- ["horizontalbar"]=8213,
- ["horncmb"]=795,
- ["hotsprings"]=9832,
- ["house"]=8962,
- ["hparen"]=9379,
- ["hsuperior"]=688,
- ["hturned"]=613,
- ["huhiragana"]=12405,
- ["huiitosquare"]=13107,
- ["hukatakana"]=12501,
- ["hukatakanahalfwidth"]=65420,
- ["hungarumlaut"]=733,
- ["hungarumlautcmb"]=779,
- ["hv"]=405,
- ["hyphen"]=45,
- ["hyphenmonospace"]=65293,
- ["hyphensmall"]=65123,
- ["hyphentwo"]=8208,
- ["i"]=105,
- ["iacute"]=237,
- ["iacyrillic"]=1103,
- ["ibengali"]=2439,
- ["ibopomofo"]=12583,
- ["ibreve"]=301,
- ["icaron"]=464,
- ["icircle"]=9432,
- ["icircumflex"]=238,
- ["icyrillic"]=1110,
- ["idblgrave"]=521,
- ["ideographearthcircle"]=12943,
- ["ideographfirecircle"]=12939,
- ["ideographicallianceparen"]=12863,
- ["ideographiccallparen"]=12858,
- ["ideographiccentrecircle"]=12965,
- ["ideographicclose"]=12294,
- ["ideographiccomma"]=12289,
- ["ideographiccommaleft"]=65380,
- ["ideographiccongratulationparen"]=12855,
- ["ideographiccorrectcircle"]=12963,
- ["ideographicearthparen"]=12847,
- ["ideographicenterpriseparen"]=12861,
- ["ideographicexcellentcircle"]=12957,
- ["ideographicfestivalparen"]=12864,
- ["ideographicfinancialcircle"]=12950,
- ["ideographicfinancialparen"]=12854,
- ["ideographicfireparen"]=12843,
- ["ideographichaveparen"]=12850,
- ["ideographichighcircle"]=12964,
- ["ideographiciterationmark"]=12293,
- ["ideographiclaborcircle"]=12952,
- ["ideographiclaborparen"]=12856,
- ["ideographicleftcircle"]=12967,
- ["ideographiclowcircle"]=12966,
- ["ideographicmedicinecircle"]=12969,
- ["ideographicmetalparen"]=12846,
- ["ideographicmoonparen"]=12842,
- ["ideographicnameparen"]=12852,
- ["ideographicperiod"]=12290,
- ["ideographicprintcircle"]=12958,
- ["ideographicreachparen"]=12867,
- ["ideographicrepresentparen"]=12857,
- ["ideographicresourceparen"]=12862,
- ["ideographicrightcircle"]=12968,
- ["ideographicsecretcircle"]=12953,
- ["ideographicselfparen"]=12866,
- ["ideographicsocietyparen"]=12851,
- ["ideographicspace"]=12288,
- ["ideographicspecialparen"]=12853,
- ["ideographicstockparen"]=12849,
- ["ideographicstudyparen"]=12859,
- ["ideographicsunparen"]=12848,
- ["ideographicsuperviseparen"]=12860,
- ["ideographicwaterparen"]=12844,
- ["ideographicwoodparen"]=12845,
- ["ideographiczero"]=12295,
- ["ideographmetalcircle"]=12942,
- ["ideographmooncircle"]=12938,
- ["ideographnamecircle"]=12948,
- ["ideographsuncircle"]=12944,
- ["ideographwatercircle"]=12940,
- ["ideographwoodcircle"]=12941,
- ["ideva"]=2311,
- ["idieresis"]=239,
- ["idieresisacute"]=7727,
- ["idieresiscyrillic"]=1253,
- ["idotbelow"]=7883,
- ["iebrevecyrillic"]=1239,
- ["iecyrillic"]=1077,
- ["ieungacirclekorean"]=12917,
- ["ieungaparenkorean"]=12821,
- ["ieungcirclekorean"]=12903,
- ["ieungkorean"]=12615,
- ["ieungparenkorean"]=12807,
- ["igrave"]=236,
- ["igujarati"]=2695,
- ["igurmukhi"]=2567,
- ["ihiragana"]=12356,
- ["ihookabove"]=7881,
- ["iibengali"]=2440,
- ["iicyrillic"]=1080,
- ["iideva"]=2312,
- ["iigujarati"]=2696,
- ["iigurmukhi"]=2568,
- ["iimatragurmukhi"]=2624,
- ["iinvertedbreve"]=523,
- ["iishortcyrillic"]=1081,
- ["iivowelsignbengali"]=2496,
- ["iivowelsigndeva"]=2368,
- ["iivowelsigngujarati"]=2752,
- ["ij"]=307,
- ["ikatakana"]=12452,
- ["ikatakanahalfwidth"]=65394,
- ["ikorean"]=12643,
- ["iluyhebrew"]=1452,
- ["imacron"]=299,
- ["imacroncyrillic"]=1251,
- ["imageorapproximatelyequal"]=8787,
- ["imatragurmukhi"]=2623,
- ["imonospace"]=65353,
- ["increment"]=8710,
- ["infinity"]=8734,
- ["iniarmenian"]=1387,
- ["integral"]=8747,
- ["integralbt"]=8993,
- ["integraltp"]=8992,
- ["intersection"]=8745,
- ["intisquare"]=13061,
- ["invbullet"]=9688,
- ["invsmileface"]=9787,
- ["iocyrillic"]=1105,
- ["iogonek"]=303,
- ["iota"]=953,
- ["iotadieresis"]=970,
- ["iotadieresistonos"]=912,
- ["iotalatin"]=617,
- ["iotatonos"]=943,
- ["iparen"]=9380,
- ["irigurmukhi"]=2674,
- ["ismallhiragana"]=12355,
- ["ismallkatakana"]=12451,
- ["ismallkatakanahalfwidth"]=65384,
- ["issharbengali"]=2554,
- ["istroke"]=616,
- ["iterationhiragana"]=12445,
- ["iterationkatakana"]=12541,
- ["itilde"]=297,
- ["itildebelow"]=7725,
- ["iubopomofo"]=12585,
- ["iucyrillic"]=1102,
- ["ivowelsignbengali"]=2495,
- ["ivowelsigndeva"]=2367,
- ["ivowelsigngujarati"]=2751,
- ["izhitsacyrillic"]=1141,
- ["izhitsadblgravecyrillic"]=1143,
- ["j"]=106,
- ["jaarmenian"]=1393,
- ["jabengali"]=2460,
- ["jadeva"]=2332,
- ["jagujarati"]=2716,
- ["jagurmukhi"]=2588,
- ["jbopomofo"]=12560,
- ["jcaron"]=496,
- ["jcircle"]=9433,
- ["jcircumflex"]=309,
- ["jcrossedtail"]=669,
- ["jdotlessstroke"]=607,
- ["jecyrillic"]=1112,
- ["jeemarabic"]=1580,
- ["jeemfinalarabic"]=65182,
- ["jeeminitialarabic"]=65183,
- ["jeemmedialarabic"]=65184,
- ["jeharabic"]=1688,
- ["jehfinalarabic"]=64395,
- ["jhabengali"]=2461,
- ["jhadeva"]=2333,
- ["jhagujarati"]=2717,
- ["jhagurmukhi"]=2589,
- ["jheharmenian"]=1403,
- ["jis"]=12292,
- ["jmonospace"]=65354,
- ["jparen"]=9381,
- ["jsuperior"]=690,
- ["k"]=107,
- ["kabashkircyrillic"]=1185,
- ["kabengali"]=2453,
- ["kacute"]=7729,
- ["kacyrillic"]=1082,
- ["kadescendercyrillic"]=1179,
- ["kadeva"]=2325,
- ["kafarabic"]=1603,
- ["kafdageshhebrew"]=64315,
- ["kaffinalarabic"]=65242,
- ["kafhebrew"]=1499,
- ["kafinitialarabic"]=65243,
- ["kafmedialarabic"]=65244,
- ["kafrafehebrew"]=64333,
- ["kagujarati"]=2709,
- ["kagurmukhi"]=2581,
- ["kahiragana"]=12363,
- ["kahookcyrillic"]=1220,
- ["kakatakana"]=12459,
- ["kakatakanahalfwidth"]=65398,
- ["kappa"]=954,
- ["kappasymbolgreek"]=1008,
- ["kapyeounmieumkorean"]=12657,
- ["kapyeounphieuphkorean"]=12676,
- ["kapyeounpieupkorean"]=12664,
- ["kapyeounssangpieupkorean"]=12665,
- ["karoriisquare"]=13069,
- ["kasmallkatakana"]=12533,
- ["kasquare"]=13188,
- ["kasraarabic"]=1616,
- ["kasratanarabic"]=1613,
- ["kastrokecyrillic"]=1183,
- ["katahiraprolongmarkhalfwidth"]=65392,
- ["kaverticalstrokecyrillic"]=1181,
- ["kbopomofo"]=12558,
- ["kcalsquare"]=13193,
- ["kcaron"]=489,
- ["kcircle"]=9434,
- ["kcommaaccent"]=311,
- ["kdotbelow"]=7731,
- ["keharmenian"]=1412,
- ["kehiragana"]=12369,
- ["kekatakana"]=12465,
- ["kekatakanahalfwidth"]=65401,
- ["kenarmenian"]=1391,
- ["kesmallkatakana"]=12534,
- ["kgreenlandic"]=312,
- ["khabengali"]=2454,
- ["khacyrillic"]=1093,
- ["khadeva"]=2326,
- ["khagujarati"]=2710,
- ["khagurmukhi"]=2582,
- ["khaharabic"]=1582,
- ["khahfinalarabic"]=65190,
- ["khahinitialarabic"]=65191,
- ["khahmedialarabic"]=65192,
- ["kheicoptic"]=999,
- ["khhadeva"]=2393,
- ["khhagurmukhi"]=2649,
- ["khieukhacirclekorean"]=12920,
- ["khieukhaparenkorean"]=12824,
- ["khieukhcirclekorean"]=12906,
- ["khieukhkorean"]=12619,
- ["khieukhparenkorean"]=12810,
- ["khokhaithai"]=3586,
- ["khokhonthai"]=3589,
- ["khokhuatthai"]=3587,
- ["khokhwaithai"]=3588,
- ["khomutthai"]=3675,
- ["khook"]=409,
- ["khorakhangthai"]=3590,
- ["khzsquare"]=13201,
- ["kihiragana"]=12365,
- ["kikatakana"]=12461,
- ["kikatakanahalfwidth"]=65399,
- ["kiroguramusquare"]=13077,
- ["kiromeetorusquare"]=13078,
- ["kirosquare"]=13076,
- ["kiyeokacirclekorean"]=12910,
- ["kiyeokaparenkorean"]=12814,
- ["kiyeokcirclekorean"]=12896,
- ["kiyeokkorean"]=12593,
- ["kiyeokparenkorean"]=12800,
- ["kiyeoksioskorean"]=12595,
- ["kjecyrillic"]=1116,
- ["klinebelow"]=7733,
- ["klsquare"]=13208,
- ["kmcubedsquare"]=13222,
- ["kmonospace"]=65355,
- ["kmsquaredsquare"]=13218,
- ["kohiragana"]=12371,
- ["kohmsquare"]=13248,
- ["kokaithai"]=3585,
- ["kokatakana"]=12467,
- ["kokatakanahalfwidth"]=65402,
- ["kooposquare"]=13086,
- ["koppacyrillic"]=1153,
- ["koreanstandardsymbol"]=12927,
- ["koroniscmb"]=835,
- ["kparen"]=9382,
- ["kpasquare"]=13226,
- ["ksicyrillic"]=1135,
- ["ktsquare"]=13263,
- ["kturned"]=670,
- ["kuhiragana"]=12367,
- ["kukatakana"]=12463,
- ["kukatakanahalfwidth"]=65400,
- ["kvsquare"]=13240,
- ["kwsquare"]=13246,
- ["l"]=108,
- ["labengali"]=2482,
- ["lacute"]=314,
- ["ladeva"]=2354,
- ["lagujarati"]=2738,
- ["lagurmukhi"]=2610,
- ["lakkhangyaothai"]=3653,
- ["lamaleffinalarabic"]=65276,
- ["lamalefhamzaabovefinalarabic"]=65272,
- ["lamalefhamzaaboveisolatedarabic"]=65271,
- ["lamalefhamzabelowfinalarabic"]=65274,
- ["lamalefhamzabelowisolatedarabic"]=65273,
- ["lamalefisolatedarabic"]=65275,
- ["lamalefmaddaabovefinalarabic"]=65270,
- ["lamalefmaddaaboveisolatedarabic"]=65269,
- ["lamarabic"]=1604,
- ["lambda"]=955,
- ["lambdastroke"]=411,
- ["lameddageshhebrew"]=64316,
- ["lamedholamhebrew"]=1500,
- ["lamfinalarabic"]=65246,
- ["lamhahinitialarabic"]=64714,
- ["lamjeeminitialarabic"]=64713,
- ["lamkhahinitialarabic"]=64715,
- ["lamlamhehisolatedarabic"]=65010,
- ["lammedialarabic"]=65248,
- ["lammeemhahinitialarabic"]=64904,
- ["lammeeminitialarabic"]=64716,
- ["lammeemkhahinitialarabic"]=65247,
- ["largecircle"]=9711,
- ["lbar"]=410,
- ["lbelt"]=620,
- ["lbopomofo"]=12556,
- ["lcaron"]=318,
- ["lcircle"]=9435,
- ["lcircumflexbelow"]=7741,
- ["lcommaaccent"]=316,
- ["ldotaccent"]=320,
- ["ldotbelow"]=7735,
- ["ldotbelowmacron"]=7737,
- ["leftangleabovecmb"]=794,
- ["lefttackbelowcmb"]=792,
- ["less"]=60,
- ["lessequal"]=8804,
- ["lessequalorgreater"]=8922,
- ["lessmonospace"]=65308,
- ["lessorequivalent"]=8818,
- ["lessorgreater"]=8822,
- ["lessoverequal"]=8806,
- ["lesssmall"]=65124,
- ["lezh"]=622,
- ["lfblock"]=9612,
- ["lhookretroflex"]=621,
- ["lira"]=8356,
- ["liwnarmenian"]=1388,
- ["lj"]=457,
- ["ljecyrillic"]=1113,
- ["lladeva"]=2355,
- ["llagujarati"]=2739,
- ["llinebelow"]=7739,
- ["llladeva"]=2356,
- ["llvocalicbengali"]=2529,
- ["llvocalicdeva"]=2401,
- ["llvocalicvowelsignbengali"]=2531,
- ["llvocalicvowelsigndeva"]=2403,
- ["lmiddletilde"]=619,
- ["lmonospace"]=65356,
- ["lmsquare"]=13264,
- ["lochulathai"]=3628,
- ["logicaland"]=8743,
- ["logicalnot"]=172,
- ["logicalor"]=8744,
- ["lolingthai"]=3621,
- ["lowlinecenterline"]=65102,
- ["lowlinecmb"]=818,
- ["lowlinedashed"]=65101,
- ["lozenge"]=9674,
- ["lparen"]=9383,
- ["lslash"]=322,
- ["lsquare"]=8467,
- ["luthai"]=3622,
- ["lvocalicbengali"]=2444,
- ["lvocalicdeva"]=2316,
- ["lvocalicvowelsignbengali"]=2530,
- ["lvocalicvowelsigndeva"]=2402,
- ["lxsquare"]=13267,
- ["m"]=109,
- ["mabengali"]=2478,
- ["macron"]=175,
- ["macronbelowcmb"]=817,
- ["macroncmb"]=772,
- ["macronlowmod"]=717,
- ["macronmonospace"]=65507,
- ["macute"]=7743,
- ["madeva"]=2350,
- ["magujarati"]=2734,
- ["magurmukhi"]=2606,
- ["mahapakhlefthebrew"]=1444,
- ["mahiragana"]=12414,
- ["maichattawathai"]=3659,
- ["maiekthai"]=3656,
- ["maihanakatthai"]=3633,
- ["maitaikhuthai"]=3655,
- ["maithothai"]=3657,
- ["maitrithai"]=3658,
- ["maiyamokthai"]=3654,
- ["makatakana"]=12510,
- ["makatakanahalfwidth"]=65423,
- ["mansyonsquare"]=13127,
- ["maqafhebrew"]=1470,
- ["mars"]=9794,
- ["masoracirclehebrew"]=1455,
- ["masquare"]=13187,
- ["mbopomofo"]=12551,
- ["mbsquare"]=13268,
- ["mcircle"]=9436,
- ["mcubedsquare"]=13221,
- ["mdotaccent"]=7745,
- ["mdotbelow"]=7747,
- ["meemarabic"]=1605,
- ["meemfinalarabic"]=65250,
- ["meeminitialarabic"]=65251,
- ["meemmedialarabic"]=65252,
- ["meemmeeminitialarabic"]=64721,
- ["meemmeemisolatedarabic"]=64584,
- ["meetorusquare"]=13133,
- ["mehiragana"]=12417,
- ["meizierasquare"]=13182,
- ["mekatakana"]=12513,
- ["mekatakanahalfwidth"]=65426,
- ["memdageshhebrew"]=64318,
- ["memhebrew"]=1502,
- ["menarmenian"]=1396,
- ["merkhakefulalefthebrew"]=1446,
- ["merkhalefthebrew"]=1445,
- ["mhook"]=625,
- ["mhzsquare"]=13202,
- ["middledotkatakanahalfwidth"]=65381,
- ["mieumacirclekorean"]=12914,
- ["mieumaparenkorean"]=12818,
- ["mieumcirclekorean"]=12900,
- ["mieumkorean"]=12609,
- ["mieumpansioskorean"]=12656,
- ["mieumparenkorean"]=12804,
- ["mieumpieupkorean"]=12654,
- ["mieumsioskorean"]=12655,
- ["mihiragana"]=12415,
- ["mikatakana"]=12511,
- ["mikatakanahalfwidth"]=65424,
- ["minus"]=8722,
- ["minusbelowcmb"]=800,
- ["minuscircle"]=8854,
- ["minusmod"]=727,
- ["minusplus"]=8723,
- ["minute"]=8242,
- ["miribaarusquare"]=13130,
- ["mirisquare"]=13129,
- ["mlonglegturned"]=624,
- ["mlsquare"]=13206,
- ["mmcubedsquare"]=13219,
- ["mmonospace"]=65357,
- ["mmsquaredsquare"]=13215,
- ["mohiragana"]=12418,
- ["mohmsquare"]=13249,
- ["mokatakana"]=12514,
- ["mokatakanahalfwidth"]=65427,
- ["molsquare"]=13270,
- ["momathai"]=3617,
- ["moverssquare"]=13223,
- ["moverssquaredsquare"]=13224,
- ["mparen"]=9384,
- ["mpasquare"]=13227,
- ["mssquare"]=13235,
- ["mturned"]=623,
- ["mu1"]=181,
- ["muasquare"]=13186,
- ["muchgreater"]=8811,
- ["muchless"]=8810,
- ["mufsquare"]=13196,
- ["mugreek"]=956,
- ["mugsquare"]=13197,
- ["muhiragana"]=12416,
- ["mukatakana"]=12512,
- ["mukatakanahalfwidth"]=65425,
- ["mulsquare"]=13205,
- ["multiply"]=215,
- ["mumsquare"]=13211,
- ["munahlefthebrew"]=1443,
- ["musicalnote"]=9834,
- ["musicalnotedbl"]=9835,
- ["musicflatsign"]=9837,
- ["musicsharpsign"]=9839,
- ["mussquare"]=13234,
- ["muvsquare"]=13238,
- ["muwsquare"]=13244,
- ["mvmegasquare"]=13241,
- ["mvsquare"]=13239,
- ["mwmegasquare"]=13247,
- ["mwsquare"]=13245,
- ["n"]=110,
- ["nabengali"]=2472,
- ["nabla"]=8711,
- ["nacute"]=324,
- ["nadeva"]=2344,
- ["nagujarati"]=2728,
- ["nagurmukhi"]=2600,
- ["nahiragana"]=12394,
- ["nakatakana"]=12490,
- ["nakatakanahalfwidth"]=65413,
- ["nasquare"]=13185,
- ["nbopomofo"]=12555,
- ["ncaron"]=328,
- ["ncircle"]=9437,
- ["ncircumflexbelow"]=7755,
- ["ncommaaccent"]=326,
- ["ndotaccent"]=7749,
- ["ndotbelow"]=7751,
- ["nehiragana"]=12397,
- ["nekatakana"]=12493,
- ["nekatakanahalfwidth"]=65416,
- ["nfsquare"]=13195,
- ["ngabengali"]=2457,
- ["ngadeva"]=2329,
- ["ngagujarati"]=2713,
- ["ngagurmukhi"]=2585,
- ["ngonguthai"]=3591,
- ["nhiragana"]=12435,
- ["nhookleft"]=626,
- ["nhookretroflex"]=627,
- ["nieunacirclekorean"]=12911,
- ["nieunaparenkorean"]=12815,
- ["nieuncieuckorean"]=12597,
- ["nieuncirclekorean"]=12897,
- ["nieunhieuhkorean"]=12598,
- ["nieunkorean"]=12596,
- ["nieunpansioskorean"]=12648,
- ["nieunparenkorean"]=12801,
- ["nieunsioskorean"]=12647,
- ["nieuntikeutkorean"]=12646,
- ["nihiragana"]=12395,
- ["nikatakana"]=12491,
- ["nikatakanahalfwidth"]=65414,
- ["nikhahitthai"]=3661,
- ["nine"]=57,
- ["ninebengali"]=2543,
- ["ninecircle"]=9320,
- ["ninecircleinversesansserif"]=10130,
- ["ninedeva"]=2415,
- ["ninegujarati"]=2799,
- ["ninegurmukhi"]=2671,
- ["ninehackarabic"]=1641,
- ["ninehangzhou"]=12329,
- ["nineideographicparen"]=12840,
- ["nineinferior"]=8329,
- ["ninemonospace"]=65305,
- ["nineparen"]=9340,
- ["nineperiod"]=9360,
- ["ninepersian"]=1785,
- ["nineroman"]=8568,
- ["ninesuperior"]=8313,
- ["nineteencircle"]=9330,
- ["nineteenparen"]=9350,
- ["nineteenperiod"]=9370,
- ["ninethai"]=3673,
- ["nj"]=460,
- ["njecyrillic"]=1114,
- ["nkatakana"]=12531,
- ["nkatakanahalfwidth"]=65437,
- ["nlegrightlong"]=414,
- ["nlinebelow"]=7753,
- ["nmonospace"]=65358,
- ["nmsquare"]=13210,
- ["nnabengali"]=2467,
- ["nnadeva"]=2339,
- ["nnagujarati"]=2723,
- ["nnagurmukhi"]=2595,
- ["nnnadeva"]=2345,
- ["nohiragana"]=12398,
- ["nokatakana"]=12494,
- ["nokatakanahalfwidth"]=65417,
- ["nonbreakingspace"]=160,
- ["nonenthai"]=3603,
- ["nonuthai"]=3609,
- ["noonarabic"]=1606,
- ["noonfinalarabic"]=65254,
- ["noonghunnaarabic"]=1722,
- ["noonghunnafinalarabic"]=64415,
- ["nooninitialarabic"]=65255,
- ["noonjeeminitialarabic"]=64722,
- ["noonjeemisolatedarabic"]=64587,
- ["noonmedialarabic"]=65256,
- ["noonmeeminitialarabic"]=64725,
- ["noonmeemisolatedarabic"]=64590,
- ["noonnoonfinalarabic"]=64653,
- ["notcontains"]=8716,
- ["notelementof"]=8713,
- ["notequal"]=8800,
- ["notgreater"]=8815,
- ["notgreaternorequal"]=8817,
- ["notgreaternorless"]=8825,
- ["notidentical"]=8802,
- ["notless"]=8814,
- ["notlessnorequal"]=8816,
- ["notparallel"]=8742,
- ["notprecedes"]=8832,
- ["notsubset"]=8836,
- ["notsucceeds"]=8833,
- ["notsuperset"]=8837,
- ["nowarmenian"]=1398,
- ["nparen"]=9385,
- ["nssquare"]=13233,
- ["nsuperior"]=8319,
- ["ntilde"]=241,
- ["nu"]=957,
- ["nuhiragana"]=12396,
- ["nukatakana"]=12492,
- ["nukatakanahalfwidth"]=65415,
- ["nuktabengali"]=2492,
- ["nuktadeva"]=2364,
- ["nuktagujarati"]=2748,
- ["nuktagurmukhi"]=2620,
- ["numbersign"]=35,
- ["numbersignmonospace"]=65283,
- ["numbersignsmall"]=65119,
- ["numeralsigngreek"]=884,
- ["numeralsignlowergreek"]=885,
- ["numero"]=8470,
- ["nundageshhebrew"]=64320,
- ["nunhebrew"]=1504,
- ["nvsquare"]=13237,
- ["nwsquare"]=13243,
- ["nyabengali"]=2462,
- ["nyadeva"]=2334,
- ["nyagujarati"]=2718,
- ["nyagurmukhi"]=2590,
- ["o"]=111,
- ["oacute"]=243,
- ["oangthai"]=3629,
- ["obarred"]=629,
- ["obarredcyrillic"]=1257,
- ["obarreddieresiscyrillic"]=1259,
- ["obengali"]=2451,
- ["obopomofo"]=12571,
- ["obreve"]=335,
- ["ocandradeva"]=2321,
- ["ocandragujarati"]=2705,
- ["ocandravowelsigndeva"]=2377,
- ["ocandravowelsigngujarati"]=2761,
- ["ocaron"]=466,
- ["ocircle"]=9438,
- ["ocircumflex"]=244,
- ["ocircumflexacute"]=7889,
- ["ocircumflexdotbelow"]=7897,
- ["ocircumflexgrave"]=7891,
- ["ocircumflexhookabove"]=7893,
- ["ocircumflextilde"]=7895,
- ["ocyrillic"]=1086,
- ["odblgrave"]=525,
- ["odeva"]=2323,
- ["odieresis"]=246,
- ["odieresiscyrillic"]=1255,
- ["odotbelow"]=7885,
- ["oe"]=339,
- ["oekorean"]=12634,
- ["ogonek"]=731,
- ["ogonekcmb"]=808,
- ["ograve"]=242,
- ["ogujarati"]=2707,
- ["oharmenian"]=1413,
- ["ohiragana"]=12362,
- ["ohookabove"]=7887,
- ["ohorn"]=417,
- ["ohornacute"]=7899,
- ["ohorndotbelow"]=7907,
- ["ohorngrave"]=7901,
- ["ohornhookabove"]=7903,
- ["ohorntilde"]=7905,
- ["ohungarumlaut"]=337,
- ["oi"]=419,
- ["oinvertedbreve"]=527,
- ["okatakana"]=12458,
- ["okatakanahalfwidth"]=65397,
- ["okorean"]=12631,
- ["olehebrew"]=1451,
- ["omacron"]=333,
- ["omacronacute"]=7763,
- ["omacrongrave"]=7761,
- ["omdeva"]=2384,
- ["omega"]=969,
- ["omegacyrillic"]=1121,
- ["omegalatinclosed"]=631,
- ["omegaroundcyrillic"]=1147,
- ["omegatitlocyrillic"]=1149,
- ["omegatonos"]=974,
- ["omgujarati"]=2768,
- ["omicron"]=959,
- ["omicrontonos"]=972,
- ["omonospace"]=65359,
- ["one"]=49,
- ["onebengali"]=2535,
- ["onecircle"]=9312,
- ["onecircleinversesansserif"]=10122,
- ["onedeva"]=2407,
- ["onedotenleader"]=8228,
- ["oneeighth"]=8539,
- ["onegujarati"]=2791,
- ["onegurmukhi"]=2663,
- ["onehackarabic"]=1633,
- ["onehalf"]=189,
- ["onehangzhou"]=12321,
- ["oneideographicparen"]=12832,
- ["oneinferior"]=8321,
- ["onemonospace"]=65297,
- ["onenumeratorbengali"]=2548,
- ["oneparen"]=9332,
- ["oneperiod"]=9352,
- ["onepersian"]=1777,
- ["onequarter"]=188,
- ["oneroman"]=8560,
- ["onesuperior"]=185,
- ["onethai"]=3665,
- ["onethird"]=8531,
- ["oogonek"]=491,
- ["oogonekmacron"]=493,
- ["oogurmukhi"]=2579,
- ["oomatragurmukhi"]=2635,
- ["oopen"]=596,
- ["oparen"]=9386,
- ["option"]=8997,
- ["ordfeminine"]=170,
- ["ordmasculine"]=186,
- ["oshortdeva"]=2322,
- ["oshortvowelsigndeva"]=2378,
- ["oslash"]=248,
- ["osmallhiragana"]=12361,
- ["osmallkatakana"]=12457,
- ["osmallkatakanahalfwidth"]=65387,
- ["ostrokeacute"]=511,
- ["otcyrillic"]=1151,
- ["otilde"]=245,
- ["otildeacute"]=7757,
- ["otildedieresis"]=7759,
- ["oubopomofo"]=12577,
- ["overline"]=8254,
- ["overlinecenterline"]=65098,
- ["overlinecmb"]=773,
- ["overlinedashed"]=65097,
- ["overlinedblwavy"]=65100,
- ["overlinewavy"]=65099,
- ["ovowelsignbengali"]=2507,
- ["ovowelsigndeva"]=2379,
- ["ovowelsigngujarati"]=2763,
- ["p"]=112,
- ["paampssquare"]=13184,
- ["paasentosquare"]=13099,
- ["pabengali"]=2474,
- ["pacute"]=7765,
- ["padeva"]=2346,
- ["pagedown"]=8671,
- ["pageup"]=8670,
- ["pagujarati"]=2730,
- ["pagurmukhi"]=2602,
- ["pahiragana"]=12401,
- ["paiyannoithai"]=3631,
- ["pakatakana"]=12497,
- ["palatalizationcyrilliccmb"]=1156,
- ["palochkacyrillic"]=1216,
- ["pansioskorean"]=12671,
- ["paragraph"]=182,
- ["parallel"]=8741,
- ["parenleft"]=40,
- ["parenleftaltonearabic"]=64830,
- ["parenleftinferior"]=8333,
- ["parenleftmonospace"]=65288,
- ["parenleftsmall"]=65113,
- ["parenleftsuperior"]=8317,
- ["parenleftvertical"]=65077,
- ["parenright"]=41,
- ["parenrightaltonearabic"]=64831,
- ["parenrightinferior"]=8334,
- ["parenrightmonospace"]=65289,
- ["parenrightsmall"]=65114,
- ["parenrightsuperior"]=8318,
- ["parenrightvertical"]=65078,
- ["partialdiff"]=8706,
- ["paseqhebrew"]=1472,
- ["pashtahebrew"]=1433,
- ["pasquare"]=13225,
- ["patahwidehebrew"]=1463,
- ["pazerhebrew"]=1441,
- ["pbopomofo"]=12550,
- ["pcircle"]=9439,
- ["pdotaccent"]=7767,
- ["pecyrillic"]=1087,
- ["pedageshhebrew"]=64324,
- ["peezisquare"]=13115,
- ["pefinaldageshhebrew"]=64323,
- ["peharabic"]=1662,
- ["peharmenian"]=1402,
- ["pehebrew"]=1508,
- ["pehfinalarabic"]=64343,
- ["pehinitialarabic"]=64344,
- ["pehiragana"]=12410,
- ["pehmedialarabic"]=64345,
- ["pekatakana"]=12506,
- ["pemiddlehookcyrillic"]=1191,
- ["perafehebrew"]=64334,
- ["percent"]=37,
- ["percentarabic"]=1642,
- ["percentmonospace"]=65285,
- ["percentsmall"]=65130,
- ["period"]=46,
- ["periodarmenian"]=1417,
- ["periodcentered"]=183,
- ["periodhalfwidth"]=65377,
- ["periodmonospace"]=65294,
- ["periodsmall"]=65106,
- ["perispomenigreekcmb"]=834,
- ["perpendicular"]=8869,
- ["perthousand"]=8240,
- ["peseta"]=8359,
- ["pfsquare"]=13194,
- ["phabengali"]=2475,
- ["phadeva"]=2347,
- ["phagujarati"]=2731,
- ["phagurmukhi"]=2603,
- ["phi"]=966,
- ["phieuphacirclekorean"]=12922,
- ["phieuphaparenkorean"]=12826,
- ["phieuphcirclekorean"]=12908,
- ["phieuphkorean"]=12621,
- ["phieuphparenkorean"]=12812,
- ["philatin"]=632,
- ["phinthuthai"]=3642,
- ["phisymbolgreek"]=981,
- ["phook"]=421,
- ["phophanthai"]=3614,
- ["phophungthai"]=3612,
- ["phosamphaothai"]=3616,
- ["pi"]=960,
- ["pieupacirclekorean"]=12915,
- ["pieupaparenkorean"]=12819,
- ["pieupcieuckorean"]=12662,
- ["pieupcirclekorean"]=12901,
- ["pieupkiyeokkorean"]=12658,
- ["pieupkorean"]=12610,
- ["pieupparenkorean"]=12805,
- ["pieupsioskiyeokkorean"]=12660,
- ["pieupsioskorean"]=12612,
- ["pieupsiostikeutkorean"]=12661,
- ["pieupthieuthkorean"]=12663,
- ["pieuptikeutkorean"]=12659,
- ["pihiragana"]=12404,
- ["pikatakana"]=12500,
- ["pisymbolgreek"]=982,
- ["piwrarmenian"]=1411,
- ["plus"]=43,
- ["plusbelowcmb"]=799,
- ["pluscircle"]=8853,
- ["plusminus"]=177,
- ["plusmod"]=726,
- ["plusmonospace"]=65291,
- ["plussmall"]=65122,
- ["plussuperior"]=8314,
- ["pmonospace"]=65360,
- ["pmsquare"]=13272,
- ["pohiragana"]=12413,
- ["pointingindexdownwhite"]=9759,
- ["pointingindexleftwhite"]=9756,
- ["pointingindexrightwhite"]=9758,
- ["pointingindexupwhite"]=9757,
- ["pokatakana"]=12509,
- ["poplathai"]=3611,
- ["postalmark"]=12306,
- ["postalmarkface"]=12320,
- ["pparen"]=9387,
- ["precedes"]=8826,
- ["prescription"]=8478,
- ["primemod"]=697,
- ["primereversed"]=8245,
- ["product"]=8719,
- ["projective"]=8965,
- ["prolongedkana"]=12540,
- ["propellor"]=8984,
- ["proportion"]=8759,
- ["proportional"]=8733,
- ["psi"]=968,
- ["psicyrillic"]=1137,
- ["psilipneumatacyrilliccmb"]=1158,
- ["pssquare"]=13232,
- ["puhiragana"]=12407,
- ["pukatakana"]=12503,
- ["pvsquare"]=13236,
- ["pwsquare"]=13242,
- ["q"]=113,
- ["qadeva"]=2392,
- ["qadmahebrew"]=1448,
- ["qafarabic"]=1602,
- ["qaffinalarabic"]=65238,
- ["qafinitialarabic"]=65239,
- ["qafmedialarabic"]=65240,
- ["qamatswidehebrew"]=1464,
- ["qarneyparahebrew"]=1439,
- ["qbopomofo"]=12561,
- ["qcircle"]=9440,
- ["qhook"]=672,
- ["qmonospace"]=65361,
- ["qofdageshhebrew"]=64327,
- ["qoftserehebrew"]=1511,
- ["qparen"]=9388,
- ["quarternote"]=9833,
- ["qubutswidehebrew"]=1467,
- ["question"]=63,
- ["questionarabic"]=1567,
- ["questionarmenian"]=1374,
- ["questiondown"]=191,
- ["questiongreek"]=894,
- ["questionmonospace"]=65311,
- ["quotedbl"]=34,
- ["quotedblbase"]=8222,
- ["quotedblleft"]=8220,
- ["quotedblmonospace"]=65282,
- ["quotedblprime"]=12318,
- ["quotedblprimereversed"]=12317,
- ["quotedblright"]=8221,
- ["quoteleft"]=8216,
- ["quotereversed"]=8219,
- ["quoteright"]=8217,
- ["quoterightn"]=329,
- ["quotesinglbase"]=8218,
- ["quotesingle"]=39,
- ["quotesinglemonospace"]=65287,
- ["r"]=114,
- ["raarmenian"]=1404,
- ["rabengali"]=2480,
- ["racute"]=341,
- ["radeva"]=2352,
- ["radical"]=8730,
- ["radoverssquare"]=13230,
- ["radoverssquaredsquare"]=13231,
- ["radsquare"]=13229,
- ["rafehebrew"]=1471,
- ["ragujarati"]=2736,
- ["ragurmukhi"]=2608,
- ["rahiragana"]=12425,
- ["rakatakana"]=12521,
- ["rakatakanahalfwidth"]=65431,
- ["ralowerdiagonalbengali"]=2545,
- ["ramiddlediagonalbengali"]=2544,
- ["ramshorn"]=612,
- ["ratio"]=8758,
- ["rbopomofo"]=12566,
- ["rcaron"]=345,
- ["rcircle"]=9441,
- ["rcommaaccent"]=343,
- ["rdblgrave"]=529,
- ["rdotaccent"]=7769,
- ["rdotbelow"]=7771,
- ["rdotbelowmacron"]=7773,
- ["referencemark"]=8251,
- ["registered"]=174,
- ["reharmenian"]=1408,
- ["rehfinalarabic"]=65198,
- ["rehiragana"]=12428,
- ["rehyehaleflamarabic"]=1585,
- ["rekatakana"]=12524,
- ["rekatakanahalfwidth"]=65434,
- ["reshdageshhebrew"]=64328,
- ["reshtserehebrew"]=1512,
- ["reversedtilde"]=8765,
- ["reviamugrashhebrew"]=1431,
- ["revlogicalnot"]=8976,
- ["rfishhook"]=638,
- ["rfishhookreversed"]=639,
- ["rhabengali"]=2525,
- ["rhadeva"]=2397,
- ["rho"]=961,
- ["rhook"]=637,
- ["rhookturned"]=635,
- ["rhookturnedsuperior"]=693,
- ["rhosymbolgreek"]=1009,
- ["rhotichookmod"]=734,
- ["rieulacirclekorean"]=12913,
- ["rieulaparenkorean"]=12817,
- ["rieulcirclekorean"]=12899,
- ["rieulhieuhkorean"]=12608,
- ["rieulkiyeokkorean"]=12602,
- ["rieulkiyeoksioskorean"]=12649,
- ["rieulkorean"]=12601,
- ["rieulmieumkorean"]=12603,
- ["rieulpansioskorean"]=12652,
- ["rieulparenkorean"]=12803,
- ["rieulphieuphkorean"]=12607,
- ["rieulpieupkorean"]=12604,
- ["rieulpieupsioskorean"]=12651,
- ["rieulsioskorean"]=12605,
- ["rieulthieuthkorean"]=12606,
- ["rieultikeutkorean"]=12650,
- ["rieulyeorinhieuhkorean"]=12653,
- ["rightangle"]=8735,
- ["righttackbelowcmb"]=793,
- ["righttriangle"]=8895,
- ["rihiragana"]=12426,
- ["rikatakana"]=12522,
- ["rikatakanahalfwidth"]=65432,
- ["ring"]=730,
- ["ringbelowcmb"]=805,
- ["ringcmb"]=778,
- ["ringhalfleft"]=703,
- ["ringhalfleftarmenian"]=1369,
- ["ringhalfleftbelowcmb"]=796,
- ["ringhalfleftcentered"]=723,
- ["ringhalfright"]=702,
- ["ringhalfrightbelowcmb"]=825,
- ["ringhalfrightcentered"]=722,
- ["rinvertedbreve"]=531,
- ["rittorusquare"]=13137,
- ["rlinebelow"]=7775,
- ["rlongleg"]=636,
- ["rlonglegturned"]=634,
- ["rmonospace"]=65362,
- ["rohiragana"]=12429,
- ["rokatakana"]=12525,
- ["rokatakanahalfwidth"]=65435,
- ["roruathai"]=3619,
- ["rparen"]=9389,
- ["rrabengali"]=2524,
- ["rradeva"]=2353,
- ["rragurmukhi"]=2652,
- ["rreharabic"]=1681,
- ["rrehfinalarabic"]=64397,
- ["rrvocalicbengali"]=2528,
- ["rrvocalicdeva"]=2400,
- ["rrvocalicgujarati"]=2784,
- ["rrvocalicvowelsignbengali"]=2500,
- ["rrvocalicvowelsigndeva"]=2372,
- ["rrvocalicvowelsigngujarati"]=2756,
- ["rtblock"]=9616,
- ["rturned"]=633,
- ["rturnedsuperior"]=692,
- ["ruhiragana"]=12427,
- ["rukatakana"]=12523,
- ["rukatakanahalfwidth"]=65433,
- ["rupeemarkbengali"]=2546,
- ["rupeesignbengali"]=2547,
- ["ruthai"]=3620,
- ["rvocalicbengali"]=2443,
- ["rvocalicdeva"]=2315,
- ["rvocalicgujarati"]=2699,
- ["rvocalicvowelsignbengali"]=2499,
- ["rvocalicvowelsigndeva"]=2371,
- ["rvocalicvowelsigngujarati"]=2755,
- ["s"]=115,
- ["sabengali"]=2488,
- ["sacute"]=347,
- ["sacutedotaccent"]=7781,
- ["sadarabic"]=1589,
- ["sadeva"]=2360,
- ["sadfinalarabic"]=65210,
- ["sadinitialarabic"]=65211,
- ["sadmedialarabic"]=65212,
- ["sagujarati"]=2744,
- ["sagurmukhi"]=2616,
- ["sahiragana"]=12373,
- ["sakatakana"]=12469,
- ["sakatakanahalfwidth"]=65403,
- ["sallallahoualayhewasallamarabic"]=65018,
- ["samekhdageshhebrew"]=64321,
- ["samekhhebrew"]=1505,
- ["saraaathai"]=3634,
- ["saraaethai"]=3649,
- ["saraaimaimalaithai"]=3652,
- ["saraaimaimuanthai"]=3651,
- ["saraamthai"]=3635,
- ["saraathai"]=3632,
- ["saraethai"]=3648,
- ["saraiithai"]=3637,
- ["saraithai"]=3636,
- ["saraothai"]=3650,
- ["saraueethai"]=3639,
- ["sarauethai"]=3638,
- ["sarauthai"]=3640,
- ["sarauuthai"]=3641,
- ["sbopomofo"]=12569,
- ["scaron"]=353,
- ["scarondotaccent"]=7783,
- ["scedilla"]=351,
- ["schwa"]=601,
- ["schwacyrillic"]=1241,
- ["schwadieresiscyrillic"]=1243,
- ["schwahook"]=602,
- ["scircle"]=9442,
- ["scircumflex"]=349,
- ["scommaaccent"]=537,
- ["sdotaccent"]=7777,
- ["sdotbelow"]=7779,
- ["sdotbelowdotaccent"]=7785,
- ["seagullbelowcmb"]=828,
- ["second"]=8243,
- ["secondtonechinese"]=714,
- ["section"]=167,
- ["seenarabic"]=1587,
- ["seenfinalarabic"]=65202,
- ["seeninitialarabic"]=65203,
- ["seenmedialarabic"]=65204,
- ["segoltahebrew"]=1426,
- ["segolwidehebrew"]=1462,
- ["seharmenian"]=1405,
- ["sehiragana"]=12379,
- ["sekatakana"]=12475,
- ["sekatakanahalfwidth"]=65406,
- ["semicolon"]=59,
- ["semicolonarabic"]=1563,
- ["semicolonmonospace"]=65307,
- ["semicolonsmall"]=65108,
- ["semivoicedmarkkana"]=12444,
- ["semivoicedmarkkanahalfwidth"]=65439,
- ["sentisquare"]=13090,
- ["sentosquare"]=13091,
- ["seven"]=55,
- ["sevenbengali"]=2541,
- ["sevencircle"]=9318,
- ["sevencircleinversesansserif"]=10128,
- ["sevendeva"]=2413,
- ["seveneighths"]=8542,
- ["sevengujarati"]=2797,
- ["sevengurmukhi"]=2669,
- ["sevenhackarabic"]=1639,
- ["sevenhangzhou"]=12327,
- ["sevenideographicparen"]=12838,
- ["seveninferior"]=8327,
- ["sevenmonospace"]=65303,
- ["sevenparen"]=9338,
- ["sevenperiod"]=9358,
- ["sevenpersian"]=1783,
- ["sevenroman"]=8566,
- ["sevensuperior"]=8311,
- ["seventeencircle"]=9328,
- ["seventeenparen"]=9348,
- ["seventeenperiod"]=9368,
- ["seventhai"]=3671,
- ["shaarmenian"]=1399,
- ["shabengali"]=2486,
- ["shacyrillic"]=1096,
- ["shaddadammaarabic"]=64609,
- ["shaddadammatanarabic"]=64606,
- ["shaddafathaarabic"]=64608,
- ["shaddafathatanarabic"]=1617,
- ["shaddakasraarabic"]=64610,
- ["shaddakasratanarabic"]=64607,
- ["shadedark"]=9619,
- ["shadelight"]=9617,
- ["shademedium"]=9618,
- ["shadeva"]=2358,
- ["shagujarati"]=2742,
- ["shagurmukhi"]=2614,
- ["shalshelethebrew"]=1427,
- ["shbopomofo"]=12565,
- ["shchacyrillic"]=1097,
- ["sheenarabic"]=1588,
- ["sheenfinalarabic"]=65206,
- ["sheeninitialarabic"]=65207,
- ["sheenmedialarabic"]=65208,
- ["sheicoptic"]=995,
- ["sheqelhebrew"]=8362,
- ["shevawidehebrew"]=1456,
- ["shhacyrillic"]=1211,
- ["shimacoptic"]=1005,
- ["shindageshhebrew"]=64329,
- ["shindageshshindothebrew"]=64300,
- ["shindageshsindothebrew"]=64301,
- ["shindothebrew"]=1473,
- ["shinhebrew"]=1513,
- ["shinshindothebrew"]=64298,
- ["shinsindothebrew"]=64299,
- ["shook"]=642,
- ["sigma"]=963,
- ["sigmafinal"]=962,
- ["sigmalunatesymbolgreek"]=1010,
- ["sihiragana"]=12375,
- ["sikatakana"]=12471,
- ["sikatakanahalfwidth"]=65404,
- ["siluqlefthebrew"]=1469,
- ["sindothebrew"]=1474,
- ["siosacirclekorean"]=12916,
- ["siosaparenkorean"]=12820,
- ["sioscieuckorean"]=12670,
- ["sioscirclekorean"]=12902,
- ["sioskiyeokkorean"]=12666,
- ["sioskorean"]=12613,
- ["siosnieunkorean"]=12667,
- ["siosparenkorean"]=12806,
- ["siospieupkorean"]=12669,
- ["siostikeutkorean"]=12668,
- ["six"]=54,
- ["sixbengali"]=2540,
- ["sixcircle"]=9317,
- ["sixcircleinversesansserif"]=10127,
- ["sixdeva"]=2412,
- ["sixgujarati"]=2796,
- ["sixgurmukhi"]=2668,
- ["sixhackarabic"]=1638,
- ["sixhangzhou"]=12326,
- ["sixideographicparen"]=12837,
- ["sixinferior"]=8326,
- ["sixmonospace"]=65302,
- ["sixparen"]=9337,
- ["sixperiod"]=9357,
- ["sixpersian"]=1782,
- ["sixroman"]=8565,
- ["sixsuperior"]=8310,
- ["sixteencircle"]=9327,
- ["sixteencurrencydenominatorbengali"]=2553,
- ["sixteenparen"]=9347,
- ["sixteenperiod"]=9367,
- ["sixthai"]=3670,
- ["slash"]=47,
- ["slashmonospace"]=65295,
- ["slong"]=383,
- ["slongdotaccent"]=7835,
- ["smonospace"]=65363,
- ["sofpasuqhebrew"]=1475,
- ["softhyphen"]=173,
- ["softsigncyrillic"]=1100,
- ["sohiragana"]=12381,
- ["sokatakana"]=12477,
- ["sokatakanahalfwidth"]=65407,
- ["soliduslongoverlaycmb"]=824,
- ["solidusshortoverlaycmb"]=823,
- ["sorusithai"]=3625,
- ["sosalathai"]=3624,
- ["sosothai"]=3595,
- ["sosuathai"]=3626,
- ["space"]=32,
- ["spadesuitblack"]=9824,
- ["spadesuitwhite"]=9828,
- ["sparen"]=9390,
- ["squarebelowcmb"]=827,
- ["squarecc"]=13252,
- ["squarecm"]=13213,
- ["squarediagonalcrosshatchfill"]=9641,
- ["squarehorizontalfill"]=9636,
- ["squarekg"]=13199,
- ["squarekm"]=13214,
- ["squarekmcapital"]=13262,
- ["squareln"]=13265,
- ["squarelog"]=13266,
- ["squaremg"]=13198,
- ["squaremil"]=13269,
- ["squaremm"]=13212,
- ["squaremsquared"]=13217,
- ["squareorthogonalcrosshatchfill"]=9638,
- ["squareupperlefttolowerrightfill"]=9639,
- ["squareupperrighttolowerleftfill"]=9640,
- ["squareverticalfill"]=9637,
- ["squarewhitewithsmallblack"]=9635,
- ["srsquare"]=13275,
- ["ssabengali"]=2487,
- ["ssadeva"]=2359,
- ["ssagujarati"]=2743,
- ["ssangcieuckorean"]=12617,
- ["ssanghieuhkorean"]=12677,
- ["ssangieungkorean"]=12672,
- ["ssangkiyeokkorean"]=12594,
- ["ssangnieunkorean"]=12645,
- ["ssangpieupkorean"]=12611,
- ["ssangsioskorean"]=12614,
- ["ssangtikeutkorean"]=12600,
- ["sterling"]=163,
- ["sterlingmonospace"]=65505,
- ["strokelongoverlaycmb"]=822,
- ["strokeshortoverlaycmb"]=821,
- ["subset"]=8834,
- ["subsetnotequal"]=8842,
- ["subsetorequal"]=8838,
- ["succeeds"]=8827,
- ["suchthat"]=8715,
- ["suhiragana"]=12377,
- ["sukatakana"]=12473,
- ["sukatakanahalfwidth"]=65405,
- ["sukunarabic"]=1618,
- ["summation"]=8721,
- ["sun"]=9788,
- ["superset"]=8835,
- ["supersetnotequal"]=8843,
- ["supersetorequal"]=8839,
- ["svsquare"]=13276,
- ["syouwaerasquare"]=13180,
- ["t"]=116,
- ["tabengali"]=2468,
- ["tackdown"]=8868,
- ["tackleft"]=8867,
- ["tadeva"]=2340,
- ["tagujarati"]=2724,
- ["tagurmukhi"]=2596,
- ["taharabic"]=1591,
- ["tahfinalarabic"]=65218,
- ["tahinitialarabic"]=65219,
- ["tahiragana"]=12383,
- ["tahmedialarabic"]=65220,
- ["taisyouerasquare"]=13181,
- ["takatakana"]=12479,
- ["takatakanahalfwidth"]=65408,
- ["tatweelarabic"]=1600,
- ["tau"]=964,
- ["tavdageshhebrew"]=64330,
- ["tavhebrew"]=1514,
- ["tbar"]=359,
- ["tbopomofo"]=12554,
- ["tcaron"]=357,
- ["tccurl"]=680,
- ["tcheharabic"]=1670,
- ["tchehfinalarabic"]=64379,
- ["tchehmedialarabic"]=64381,
- ["tchehmeeminitialarabic"]=64380,
- ["tcircle"]=9443,
- ["tcircumflexbelow"]=7793,
- ["tcommaaccent"]=355,
- ["tdieresis"]=7831,
- ["tdotaccent"]=7787,
- ["tdotbelow"]=7789,
- ["tecyrillic"]=1090,
- ["tedescendercyrillic"]=1197,
- ["teharabic"]=1578,
- ["tehfinalarabic"]=65174,
- ["tehhahinitialarabic"]=64674,
- ["tehhahisolatedarabic"]=64524,
- ["tehinitialarabic"]=65175,
- ["tehiragana"]=12390,
- ["tehjeeminitialarabic"]=64673,
- ["tehjeemisolatedarabic"]=64523,
- ["tehmarbutaarabic"]=1577,
- ["tehmarbutafinalarabic"]=65172,
- ["tehmedialarabic"]=65176,
- ["tehmeeminitialarabic"]=64676,
- ["tehmeemisolatedarabic"]=64526,
- ["tehnoonfinalarabic"]=64627,
- ["tekatakana"]=12486,
- ["tekatakanahalfwidth"]=65411,
- ["telephone"]=8481,
- ["telephoneblack"]=9742,
- ["telishagedolahebrew"]=1440,
- ["telishaqetanahebrew"]=1449,
- ["tencircle"]=9321,
- ["tenideographicparen"]=12841,
- ["tenparen"]=9341,
- ["tenperiod"]=9361,
- ["tenroman"]=8569,
- ["tesh"]=679,
- ["tetdageshhebrew"]=64312,
- ["tethebrew"]=1496,
- ["tetsecyrillic"]=1205,
- ["tevirlefthebrew"]=1435,
- ["thabengali"]=2469,
- ["thadeva"]=2341,
- ["thagujarati"]=2725,
- ["thagurmukhi"]=2597,
- ["thalarabic"]=1584,
- ["thalfinalarabic"]=65196,
- ["thanthakhatthai"]=3660,
- ["theharabic"]=1579,
- ["thehfinalarabic"]=65178,
- ["thehinitialarabic"]=65179,
- ["thehmedialarabic"]=65180,
- ["thereexists"]=8707,
- ["therefore"]=8756,
- ["theta"]=952,
- ["thetasymbolgreek"]=977,
- ["thieuthacirclekorean"]=12921,
- ["thieuthaparenkorean"]=12825,
- ["thieuthcirclekorean"]=12907,
- ["thieuthkorean"]=12620,
- ["thieuthparenkorean"]=12811,
- ["thirteencircle"]=9324,
- ["thirteenparen"]=9344,
- ["thirteenperiod"]=9364,
- ["thonangmonthothai"]=3601,
- ["thook"]=429,
- ["thophuthaothai"]=3602,
- ["thorn"]=254,
- ["thothahanthai"]=3607,
- ["thothanthai"]=3600,
- ["thothongthai"]=3608,
- ["thothungthai"]=3606,
- ["thousandcyrillic"]=1154,
- ["thousandsseparatorpersian"]=1644,
- ["three"]=51,
- ["threebengali"]=2537,
- ["threecircle"]=9314,
- ["threecircleinversesansserif"]=10124,
- ["threedeva"]=2409,
- ["threeeighths"]=8540,
- ["threegujarati"]=2793,
- ["threegurmukhi"]=2665,
- ["threehackarabic"]=1635,
- ["threehangzhou"]=12323,
- ["threeideographicparen"]=12834,
- ["threeinferior"]=8323,
- ["threemonospace"]=65299,
- ["threenumeratorbengali"]=2550,
- ["threeparen"]=9334,
- ["threeperiod"]=9354,
- ["threepersian"]=1779,
- ["threequarters"]=190,
- ["threeroman"]=8562,
- ["threesuperior"]=179,
- ["threethai"]=3667,
- ["thzsquare"]=13204,
- ["tihiragana"]=12385,
- ["tikatakana"]=12481,
- ["tikatakanahalfwidth"]=65409,
- ["tikeutacirclekorean"]=12912,
- ["tikeutaparenkorean"]=12816,
- ["tikeutcirclekorean"]=12898,
- ["tikeutkorean"]=12599,
- ["tikeutparenkorean"]=12802,
- ["tilde"]=732,
- ["tildebelowcmb"]=816,
- ["tildecomb"]=771,
- ["tildedoublecmb"]=864,
- ["tildeoperator"]=8764,
- ["tildeoverlaycmb"]=820,
- ["tildeverticalcmb"]=830,
- ["timescircle"]=8855,
- ["tipehalefthebrew"]=1430,
- ["tippigurmukhi"]=2672,
- ["titlocyrilliccmb"]=1155,
- ["tiwnarmenian"]=1407,
- ["tlinebelow"]=7791,
- ["tmonospace"]=65364,
- ["toarmenian"]=1385,
- ["tohiragana"]=12392,
- ["tokatakana"]=12488,
- ["tokatakanahalfwidth"]=65412,
- ["tonebarextrahighmod"]=741,
- ["tonebarextralowmod"]=745,
- ["tonebarhighmod"]=742,
- ["tonebarlowmod"]=744,
- ["tonebarmidmod"]=743,
- ["tonefive"]=445,
- ["tonesix"]=389,
- ["tonetwo"]=424,
- ["tonos"]=900,
- ["tonsquare"]=13095,
- ["topatakthai"]=3599,
- ["tortoiseshellbracketleft"]=12308,
- ["tortoiseshellbracketleftsmall"]=65117,
- ["tortoiseshellbracketleftvertical"]=65081,
- ["tortoiseshellbracketright"]=12309,
- ["tortoiseshellbracketrightsmall"]=65118,
- ["tortoiseshellbracketrightvertical"]=65082,
- ["totaothai"]=3605,
- ["tpalatalhook"]=427,
- ["tparen"]=9391,
- ["trademark"]=8482,
- ["tretroflexhook"]=648,
- ["triagdn"]=9660,
- ["triaglf"]=9668,
- ["triagrt"]=9658,
- ["triagup"]=9650,
- ["ts"]=678,
- ["tsadidageshhebrew"]=64326,
- ["tsadihebrew"]=1510,
- ["tsecyrillic"]=1094,
- ["tserewidehebrew"]=1461,
- ["tshecyrillic"]=1115,
- ["ttabengali"]=2463,
- ["ttadeva"]=2335,
- ["ttagujarati"]=2719,
- ["ttagurmukhi"]=2591,
- ["tteharabic"]=1657,
- ["ttehfinalarabic"]=64359,
- ["ttehinitialarabic"]=64360,
- ["ttehmedialarabic"]=64361,
- ["tthabengali"]=2464,
- ["tthadeva"]=2336,
- ["tthagujarati"]=2720,
- ["tthagurmukhi"]=2592,
- ["tturned"]=647,
- ["tuhiragana"]=12388,
- ["tukatakana"]=12484,
- ["tukatakanahalfwidth"]=65410,
- ["tusmallhiragana"]=12387,
- ["tusmallkatakana"]=12483,
- ["tusmallkatakanahalfwidth"]=65391,
- ["twelvecircle"]=9323,
- ["twelveparen"]=9343,
- ["twelveperiod"]=9363,
- ["twelveroman"]=8571,
- ["twentycircle"]=9331,
- ["twentyparen"]=9351,
- ["twentyperiod"]=9371,
- ["two"]=50,
- ["twobengali"]=2536,
- ["twocircle"]=9313,
- ["twocircleinversesansserif"]=10123,
- ["twodeva"]=2408,
- ["twodotleader"]=8229,
- ["twodotleadervertical"]=65072,
- ["twogujarati"]=2792,
- ["twogurmukhi"]=2664,
- ["twohackarabic"]=1634,
- ["twohangzhou"]=12322,
- ["twoideographicparen"]=12833,
- ["twoinferior"]=8322,
- ["twomonospace"]=65298,
- ["twonumeratorbengali"]=2549,
- ["twoparen"]=9333,
- ["twoperiod"]=9353,
- ["twopersian"]=1778,
- ["tworoman"]=8561,
- ["twostroke"]=443,
- ["twosuperior"]=178,
- ["twothai"]=3666,
- ["twothirds"]=8532,
- ["u"]=117,
- ["uacute"]=250,
- ["ubar"]=649,
- ["ubengali"]=2441,
- ["ubopomofo"]=12584,
- ["ubreve"]=365,
- ["ucaron"]=468,
- ["ucircle"]=9444,
- ["ucircumflex"]=251,
- ["ucircumflexbelow"]=7799,
- ["ucyrillic"]=1091,
- ["udattadeva"]=2385,
- ["udblgrave"]=533,
- ["udeva"]=2313,
- ["udieresis"]=252,
- ["udieresisacute"]=472,
- ["udieresisbelow"]=7795,
- ["udieresiscaron"]=474,
- ["udieresiscyrillic"]=1265,
- ["udieresisgrave"]=476,
- ["udieresismacron"]=470,
- ["udotbelow"]=7909,
- ["ugrave"]=249,
- ["ugujarati"]=2697,
- ["ugurmukhi"]=2569,
- ["uhiragana"]=12358,
- ["uhookabove"]=7911,
- ["uhorn"]=432,
- ["uhornacute"]=7913,
- ["uhorndotbelow"]=7921,
- ["uhorngrave"]=7915,
- ["uhornhookabove"]=7917,
- ["uhorntilde"]=7919,
- ["uhungarumlaut"]=369,
- ["uhungarumlautcyrillic"]=1267,
- ["uinvertedbreve"]=535,
- ["ukatakana"]=12454,
- ["ukatakanahalfwidth"]=65395,
- ["ukcyrillic"]=1145,
- ["ukorean"]=12636,
- ["umacron"]=363,
- ["umacroncyrillic"]=1263,
- ["umacrondieresis"]=7803,
- ["umatragurmukhi"]=2625,
- ["umonospace"]=65365,
- ["underscore"]=95,
- ["underscoredbl"]=8215,
- ["underscoremonospace"]=65343,
- ["underscorevertical"]=65075,
- ["underscorewavy"]=65103,
- ["union"]=8746,
- ["universal"]=8704,
- ["uogonek"]=371,
- ["uparen"]=9392,
- ["upblock"]=9600,
- ["upperdothebrew"]=1476,
- ["upsilon"]=965,
- ["upsilondieresis"]=971,
- ["upsilondieresistonos"]=944,
- ["upsilonlatin"]=650,
- ["upsilontonos"]=973,
- ["uptackbelowcmb"]=797,
- ["uptackmod"]=724,
- ["uragurmukhi"]=2675,
- ["uring"]=367,
- ["ushortcyrillic"]=1118,
- ["usmallhiragana"]=12357,
- ["usmallkatakana"]=12453,
- ["usmallkatakanahalfwidth"]=65385,
- ["ustraightcyrillic"]=1199,
- ["ustraightstrokecyrillic"]=1201,
- ["utilde"]=361,
- ["utildeacute"]=7801,
- ["utildebelow"]=7797,
- ["uubengali"]=2442,
- ["uudeva"]=2314,
- ["uugujarati"]=2698,
- ["uugurmukhi"]=2570,
- ["uumatragurmukhi"]=2626,
- ["uuvowelsignbengali"]=2498,
- ["uuvowelsigndeva"]=2370,
- ["uuvowelsigngujarati"]=2754,
- ["uvowelsignbengali"]=2497,
- ["uvowelsigndeva"]=2369,
- ["uvowelsigngujarati"]=2753,
- ["v"]=118,
- ["vadeva"]=2357,
- ["vagujarati"]=2741,
- ["vagurmukhi"]=2613,
- ["vakatakana"]=12535,
- ["vavdageshhebrew"]=64309,
- ["vavhebrew"]=1493,
- ["vavholamhebrew"]=64331,
- ["vavvavhebrew"]=1520,
- ["vavyodhebrew"]=1521,
- ["vcircle"]=9445,
- ["vdotbelow"]=7807,
- ["vecyrillic"]=1074,
- ["veharabic"]=1700,
- ["vehfinalarabic"]=64363,
- ["vehinitialarabic"]=64364,
- ["vehmedialarabic"]=64365,
- ["vekatakana"]=12537,
- ["venus"]=9792,
- ["verticalbar"]=124,
- ["verticallineabovecmb"]=781,
- ["verticallinebelowcmb"]=809,
- ["verticallinelowmod"]=716,
- ["verticallinemod"]=712,
- ["vewarmenian"]=1406,
- ["vhook"]=651,
- ["vikatakana"]=12536,
- ["viramabengali"]=2509,
- ["viramadeva"]=2381,
- ["viramagujarati"]=2765,
- ["visargabengali"]=2435,
- ["visargadeva"]=2307,
- ["visargagujarati"]=2691,
- ["vmonospace"]=65366,
- ["voarmenian"]=1400,
- ["voicediterationhiragana"]=12446,
- ["voicediterationkatakana"]=12542,
- ["voicedmarkkana"]=12443,
- ["voicedmarkkanahalfwidth"]=65438,
- ["vokatakana"]=12538,
- ["vparen"]=9393,
- ["vtilde"]=7805,
- ["vturned"]=652,
- ["vuhiragana"]=12436,
- ["vukatakana"]=12532,
- ["w"]=119,
- ["wacute"]=7811,
- ["waekorean"]=12633,
- ["wahiragana"]=12431,
- ["wakatakana"]=12527,
- ["wakatakanahalfwidth"]=65436,
- ["wakorean"]=12632,
- ["wasmallhiragana"]=12430,
- ["wasmallkatakana"]=12526,
- ["wattosquare"]=13143,
- ["wavedash"]=12316,
- ["wavyunderscorevertical"]=65076,
- ["wawarabic"]=1608,
- ["wawfinalarabic"]=65262,
- ["wawhamzaabovearabic"]=1572,
- ["wawhamzaabovefinalarabic"]=65158,
- ["wbsquare"]=13277,
- ["wcircle"]=9446,
- ["wcircumflex"]=373,
- ["wdieresis"]=7813,
- ["wdotaccent"]=7815,
- ["wdotbelow"]=7817,
- ["wehiragana"]=12433,
- ["weierstrass"]=8472,
- ["wekatakana"]=12529,
- ["wekorean"]=12638,
- ["weokorean"]=12637,
- ["wgrave"]=7809,
- ["whitebullet"]=9702,
- ["whitecircle"]=9675,
- ["whitecircleinverse"]=9689,
- ["whitecornerbracketleft"]=12302,
- ["whitecornerbracketleftvertical"]=65091,
- ["whitecornerbracketright"]=12303,
- ["whitecornerbracketrightvertical"]=65092,
- ["whitediamond"]=9671,
- ["whitediamondcontainingblacksmalldiamond"]=9672,
- ["whitedownpointingsmalltriangle"]=9663,
- ["whitedownpointingtriangle"]=9661,
- ["whiteleftpointingsmalltriangle"]=9667,
- ["whiteleftpointingtriangle"]=9665,
- ["whitelenticularbracketleft"]=12310,
- ["whitelenticularbracketright"]=12311,
- ["whiterightpointingsmalltriangle"]=9657,
- ["whiterightpointingtriangle"]=9655,
- ["whitesmallsquare"]=9643,
- ["whitesmilingface"]=9786,
- ["whitesquare"]=9633,
- ["whitestar"]=9734,
- ["whitetelephone"]=9743,
- ["whitetortoiseshellbracketleft"]=12312,
- ["whitetortoiseshellbracketright"]=12313,
- ["whiteuppointingsmalltriangle"]=9653,
- ["whiteuppointingtriangle"]=9651,
- ["wihiragana"]=12432,
- ["wikatakana"]=12528,
- ["wikorean"]=12639,
- ["wmonospace"]=65367,
- ["wohiragana"]=12434,
- ["wokatakana"]=12530,
- ["wokatakanahalfwidth"]=65382,
- ["won"]=8361,
- ["wonmonospace"]=65510,
- ["wowaenthai"]=3623,
- ["wparen"]=9394,
- ["wring"]=7832,
- ["wsuperior"]=695,
- ["wturned"]=653,
- ["wynn"]=447,
- ["x"]=120,
- ["xabovecmb"]=829,
- ["xbopomofo"]=12562,
- ["xcircle"]=9447,
- ["xdieresis"]=7821,
- ["xdotaccent"]=7819,
- ["xeharmenian"]=1389,
- ["xi"]=958,
- ["xmonospace"]=65368,
- ["xparen"]=9395,
- ["xsuperior"]=739,
- ["y"]=121,
- ["yaadosquare"]=13134,
- ["yabengali"]=2479,
- ["yacute"]=253,
- ["yadeva"]=2351,
- ["yaekorean"]=12626,
- ["yagujarati"]=2735,
- ["yagurmukhi"]=2607,
- ["yahiragana"]=12420,
- ["yakatakana"]=12516,
- ["yakatakanahalfwidth"]=65428,
- ["yakorean"]=12625,
- ["yamakkanthai"]=3662,
- ["yasmallhiragana"]=12419,
- ["yasmallkatakana"]=12515,
- ["yasmallkatakanahalfwidth"]=65388,
- ["yatcyrillic"]=1123,
- ["ycircle"]=9448,
- ["ycircumflex"]=375,
- ["ydieresis"]=255,
- ["ydotaccent"]=7823,
- ["ydotbelow"]=7925,
- ["yeharabic"]=1610,
- ["yehbarreearabic"]=1746,
- ["yehbarreefinalarabic"]=64431,
- ["yehfinalarabic"]=65266,
- ["yehhamzaabovearabic"]=1574,
- ["yehhamzaabovefinalarabic"]=65162,
- ["yehhamzaaboveinitialarabic"]=65163,
- ["yehhamzaabovemedialarabic"]=65164,
- ["yehinitialarabic"]=65267,
- ["yehmedialarabic"]=65268,
- ["yehmeeminitialarabic"]=64733,
- ["yehmeemisolatedarabic"]=64600,
- ["yehnoonfinalarabic"]=64660,
- ["yehthreedotsbelowarabic"]=1745,
- ["yekorean"]=12630,
- ["yen"]=165,
- ["yenmonospace"]=65509,
- ["yeokorean"]=12629,
- ["yeorinhieuhkorean"]=12678,
- ["yerahbenyomolefthebrew"]=1450,
- ["yericyrillic"]=1099,
- ["yerudieresiscyrillic"]=1273,
- ["yesieungkorean"]=12673,
- ["yesieungpansioskorean"]=12675,
- ["yesieungsioskorean"]=12674,
- ["yetivhebrew"]=1434,
- ["ygrave"]=7923,
- ["yhook"]=436,
- ["yhookabove"]=7927,
- ["yiarmenian"]=1397,
- ["yicyrillic"]=1111,
- ["yikorean"]=12642,
- ["yinyang"]=9775,
- ["yiwnarmenian"]=1410,
- ["ymonospace"]=65369,
- ["yoddageshhebrew"]=64313,
- ["yodhebrew"]=1497,
- ["yodyodhebrew"]=1522,
- ["yodyodpatahhebrew"]=64287,
- ["yohiragana"]=12424,
- ["yoikorean"]=12681,
- ["yokatakana"]=12520,
- ["yokatakanahalfwidth"]=65430,
- ["yokorean"]=12635,
- ["yosmallhiragana"]=12423,
- ["yosmallkatakana"]=12519,
- ["yosmallkatakanahalfwidth"]=65390,
- ["yotgreek"]=1011,
- ["yoyaekorean"]=12680,
- ["yoyakorean"]=12679,
- ["yoyakthai"]=3618,
- ["yoyingthai"]=3597,
- ["yparen"]=9396,
- ["ypogegrammeni"]=890,
- ["ypogegrammenigreekcmb"]=837,
- ["yr"]=422,
- ["yring"]=7833,
- ["ysuperior"]=696,
- ["ytilde"]=7929,
- ["yturned"]=654,
- ["yuhiragana"]=12422,
- ["yuikorean"]=12684,
- ["yukatakana"]=12518,
- ["yukatakanahalfwidth"]=65429,
- ["yukorean"]=12640,
- ["yusbigcyrillic"]=1131,
- ["yusbigiotifiedcyrillic"]=1133,
- ["yuslittlecyrillic"]=1127,
- ["yuslittleiotifiedcyrillic"]=1129,
- ["yusmallhiragana"]=12421,
- ["yusmallkatakana"]=12517,
- ["yusmallkatakanahalfwidth"]=65389,
- ["yuyekorean"]=12683,
- ["yuyeokorean"]=12682,
- ["yyabengali"]=2527,
- ["yyadeva"]=2399,
- ["z"]=122,
- ["zaarmenian"]=1382,
- ["zacute"]=378,
- ["zadeva"]=2395,
- ["zagurmukhi"]=2651,
- ["zaharabic"]=1592,
- ["zahfinalarabic"]=65222,
- ["zahinitialarabic"]=65223,
- ["zahiragana"]=12374,
- ["zahmedialarabic"]=65224,
- ["zainarabic"]=1586,
- ["zainfinalarabic"]=65200,
- ["zakatakana"]=12470,
- ["zaqefgadolhebrew"]=1429,
- ["zaqefqatanhebrew"]=1428,
- ["zarqahebrew"]=1432,
- ["zayindageshhebrew"]=64310,
- ["zayinhebrew"]=1494,
- ["zbopomofo"]=12567,
- ["zcaron"]=382,
- ["zcircle"]=9449,
- ["zcircumflex"]=7825,
- ["zcurl"]=657,
- ["zdotaccent"]=380,
- ["zdotbelow"]=7827,
- ["zecyrillic"]=1079,
- ["zedescendercyrillic"]=1177,
- ["zedieresiscyrillic"]=1247,
- ["zehiragana"]=12380,
- ["zekatakana"]=12476,
- ["zero"]=48,
- ["zerobengali"]=2534,
- ["zerodeva"]=2406,
- ["zerogujarati"]=2790,
- ["zerogurmukhi"]=2662,
- ["zerohackarabic"]=1632,
- ["zeroinferior"]=8320,
- ["zeromonospace"]=65296,
- ["zeropersian"]=1776,
- ["zerosuperior"]=8304,
- ["zerothai"]=3664,
- ["zerowidthjoiner"]=65279,
- ["zerowidthnonjoiner"]=8204,
- ["zerowidthspace"]=8203,
- ["zeta"]=950,
- ["zhbopomofo"]=12563,
- ["zhearmenian"]=1386,
- ["zhebrevecyrillic"]=1218,
- ["zhecyrillic"]=1078,
- ["zhedescendercyrillic"]=1175,
- ["zhedieresiscyrillic"]=1245,
- ["zihiragana"]=12376,
- ["zikatakana"]=12472,
- ["zinorhebrew"]=1454,
- ["zlinebelow"]=7829,
- ["zmonospace"]=65370,
- ["zohiragana"]=12382,
- ["zokatakana"]=12478,
- ["zparen"]=9397,
- ["zretroflexhook"]=656,
- ["zstroke"]=438,
- ["zuhiragana"]=12378,
- ["zukatakana"]=12474,
-
- -- extras
-
- ["Dcroat"]=272,
- ["Delta"]=8710,
- ["Euro"]=8364,
- ["H18533"]=9679,
- ["H18543"]=9642,
- ["H18551"]=9643,
- ["H22073"]=9633,
- ["Ldot"]=319,
- ["Oslashacute"]=510,
- ["SF10000"]=9484,
- ["SF20000"]=9492,
- ["SF30000"]=9488,
- ["SF40000"]=9496,
- ["SF50000"]=9532,
- ["SF60000"]=9516,
- ["SF70000"]=9524,
- ["SF80000"]=9500,
- ["SF90000"]=9508,
- ["Upsilon1"]=978,
- ["afii10066"]=1073,
- ["afii10067"]=1074,
- ["afii10068"]=1075,
- ["afii10069"]=1076,
- ["afii10070"]=1077,
- ["afii10071"]=1105,
- ["afii10072"]=1078,
- ["afii10073"]=1079,
- ["afii10074"]=1080,
- ["afii10075"]=1081,
- ["afii10076"]=1082,
- ["afii10077"]=1083,
- ["afii10078"]=1084,
- ["afii10079"]=1085,
- ["afii10080"]=1086,
- ["afii10081"]=1087,
- ["afii10082"]=1088,
- ["afii10083"]=1089,
- ["afii10084"]=1090,
- ["afii10085"]=1091,
- ["afii10086"]=1092,
- ["afii10087"]=1093,
- ["afii10088"]=1094,
- ["afii10089"]=1095,
- ["afii10090"]=1096,
- ["afii10091"]=1097,
- ["afii10092"]=1098,
- ["afii10093"]=1099,
- ["afii10094"]=1100,
- ["afii10095"]=1101,
- ["afii10096"]=1102,
- ["afii10097"]=1103,
- ["afii10098"]=1169,
- ["afii10099"]=1106,
- ["afii10100"]=1107,
- ["afii10101"]=1108,
- ["afii10102"]=1109,
- ["afii10103"]=1110,
- ["afii10104"]=1111,
- ["afii10105"]=1112,
- ["afii10106"]=1113,
- ["afii10107"]=1114,
- ["afii10108"]=1115,
- ["afii10109"]=1116,
- ["afii10110"]=1118,
- ["afii10193"]=1119,
- ["afii10194"]=1123,
- ["afii10195"]=1139,
- ["afii10196"]=1141,
- ["afii10846"]=1241,
- ["afii208"]=8213,
- ["afii57381"]=1642,
- ["afii57388"]=1548,
- ["afii57392"]=1632,
- ["afii57393"]=1633,
- ["afii57394"]=1634,
- ["afii57395"]=1635,
- ["afii57396"]=1636,
- ["afii57397"]=1637,
- ["afii57398"]=1638,
- ["afii57399"]=1639,
- ["afii57400"]=1640,
- ["afii57401"]=1641,
- ["afii57403"]=1563,
- ["afii57407"]=1567,
- ["afii57409"]=1569,
- ["afii57410"]=1570,
- ["afii57411"]=1571,
- ["afii57412"]=1572,
- ["afii57413"]=1573,
- ["afii57414"]=1574,
- ["afii57415"]=1575,
- ["afii57416"]=1576,
- ["afii57417"]=1577,
- ["afii57418"]=1578,
- ["afii57419"]=1579,
- ["afii57420"]=1580,
- ["afii57421"]=1581,
- ["afii57422"]=1582,
- ["afii57423"]=1583,
- ["afii57424"]=1584,
- ["afii57425"]=1585,
- ["afii57426"]=1586,
- ["afii57427"]=1587,
- ["afii57428"]=1588,
- ["afii57429"]=1589,
- ["afii57430"]=1590,
- ["afii57431"]=1591,
- ["afii57432"]=1592,
- ["afii57433"]=1593,
- ["afii57434"]=1594,
- ["afii57440"]=1600,
- ["afii57441"]=1601,
- ["afii57442"]=1602,
- ["afii57443"]=1603,
- ["afii57444"]=1604,
- ["afii57445"]=1605,
- ["afii57446"]=1606,
- ["afii57448"]=1608,
- ["afii57449"]=1609,
- ["afii57450"]=1610,
- ["afii57451"]=1611,
- ["afii57452"]=1612,
- ["afii57453"]=1613,
- ["afii57454"]=1614,
- ["afii57455"]=1615,
- ["afii57456"]=1616,
- ["afii57457"]=1617,
- ["afii57458"]=1618,
- ["afii57470"]=1607,
- ["afii57505"]=1700,
- ["afii57506"]=1662,
- ["afii57507"]=1670,
- ["afii57508"]=1688,
- ["afii57509"]=1711,
- ["afii57511"]=1657,
- ["afii57512"]=1672,
- ["afii57513"]=1681,
- ["afii57514"]=1722,
- ["afii57519"]=1746,
- ["afii57636"]=8362,
- ["afii57645"]=1470,
- ["afii57658"]=1475,
- ["afii57664"]=1488,
- ["afii57665"]=1489,
- ["afii57666"]=1490,
- ["afii57667"]=1491,
- ["afii57668"]=1492,
- ["afii57669"]=1493,
- ["afii57670"]=1494,
- ["afii57671"]=1495,
- ["afii57672"]=1496,
- ["afii57673"]=1497,
- ["afii57674"]=1498,
- ["afii57675"]=1499,
- ["afii57676"]=1500,
- ["afii57677"]=1501,
- ["afii57678"]=1502,
- ["afii57679"]=1503,
- ["afii57680"]=1504,
- ["afii57681"]=1505,
- ["afii57682"]=1506,
- ["afii57683"]=1507,
- ["afii57684"]=1508,
- ["afii57685"]=1509,
- ["afii57686"]=1510,
- ["afii57687"]=1511,
- ["afii57688"]=1512,
- ["afii57689"]=1513,
- ["afii57690"]=1514,
- ["afii57716"]=1520,
- ["afii57717"]=1521,
- ["afii57718"]=1522,
- ["afii57793"]=1460,
- ["afii57794"]=1461,
- ["afii57795"]=1462,
- ["afii57796"]=1467,
- ["afii57797"]=1464,
- ["afii57798"]=1463,
- ["afii57799"]=1456,
- ["afii57800"]=1458,
- ["afii57801"]=1457,
- ["afii57802"]=1459,
- ["afii57803"]=1474,
- ["afii57804"]=1473,
- ["afii57806"]=1465,
- ["afii57807"]=1468,
- ["afii57839"]=1469,
- ["afii57841"]=1471,
- ["afii57842"]=1472,
- ["afii57929"]=700,
- ["afii61248"]=8453,
- ["afii61289"]=8467,
- ["afii61352"]=8470,
- ["afii61664"]=8204,
- ["afii63167"]=1645,
- ["afii64937"]=701,
- ["arrowdblboth"]=8660,
- ["arrowdblleft"]=8656,
- ["arrowdblright"]=8658,
- ["arrowupdnbse"]=8616,
- ["bar"]=124,
- ["circle"]=9675,
- ["circlemultiply"]=8855,
- ["circleplus"]=8853,
- ["club"]=9827,
- ["colonmonetary"]=8353,
- ["dcroat"]=273,
- ["dkshade"]=9619,
- ["existential"]=8707,
- ["female"]=9792,
- ["gradient"]=8711,
- ["heart"]=9829,
- ["hookabovecomb"]=777,
- ["invcircle"]=9689,
- ["ldot"]=320,
- ["longs"]=383,
- ["ltshade"]=9617,
- ["male"]=9794,
- ["mu"]=181,
- ["napostrophe"]=329,
- ["notelement"]=8713,
- ["omega1"]=982,
- ["openbullet"]=9702,
- ["orthogonal"]=8735,
- ["oslashacute"]=511,
- ["phi1"]=981,
- ["propersubset"]=8834,
- ["propersuperset"]=8835,
- ["reflexsubset"]=8838,
- ["reflexsuperset"]=8839,
- ["shade"]=9618,
- ["sigma1"]=962,
- ["similar"]=8764,
- ["smileface"]=9786,
- ["spacehackarabic"]=32,
- ["spade"]=9824,
- ["theta1"]=977,
- ["twodotenleader"]=8229,
-}
-
end -- closure
do -- begin closure to overcome local limits and interference
@@ -15261,44 +10646,32 @@ default loader that only handles <l n='tfm'/>.</p>
--ldx]]--
local fonts = fonts
-local tfm = fonts.tfm
-local vf = fonts.vf
-
-fonts.used = allocate()
-
-tfm.readers = tfm.readers or { }
-tfm.fonts = allocate()
-
-local readers = tfm.readers
-local sequence = allocate { 'otf', 'ttf', 'afm', 'tfm', 'lua' }
-readers.sequence = sequence
-
-tfm.version = 1.01
-tfm.cache = containers.define("fonts", "tfm", tfm.version, false) -- better in font-tfm
-tfm.autoprefixedafm = true -- this will become false some day (catches texnansi-blabla.*)
-
-fonts.definers = fonts.definers or { }
+local fontdata = fonts.hashes.identifiers
+local readers = fonts.readers
local definers = fonts.definers
+local specifiers = fonts.specifiers
+local constructors = fonts.constructors
-definers.specifiers = definers.specifiers or { }
-local specifiers = definers.specifiers
+readers.sequence = allocate { 'otf', 'ttf', 'afm', 'tfm', 'lua' } -- dfont ttc
-specifiers.variants = allocate()
-local variants = specifiers.variants
+local variants = allocate()
+specifiers.variants = variants
-definers.method = "afm or tfm" -- afm, tfm, afm or tfm, tfm or afm
definers.methods = definers.methods or { }
-local findbinfile = resolvers.findbinfile
+local internalized = allocate() -- internal tex numbers (private)
+
+
+local loadedfonts = constructors.loadedfonts
+local designsizes = constructors.designsizes
--[[ldx--
<p>We hardly gain anything when we cache the final (pre scaled)
-<l n='tfm'/> table. But it can be handy for debugging.</p>
+<l n='tfm'/> table. But it can be handy for debugging, so we no
+longer carry this code along. Also, we now have quite some reference
+to other tables so we would end up with lots of catches.</p>
--ldx]]--
-fonts.version = 1.05
-fonts.cache = containers.define("fonts", "def", fonts.version, false)
-
--[[ldx--
<p>We can prefix a font specification by <type>name:</type> or
<type>file:</type>. The first case will result in a lookup in the
@@ -15397,84 +10770,6 @@ function definers.analyze(specification, size)
end
--[[ldx--
-<p>A unique hash value is generated by:</p>
---ldx]]--
-
-local sortedhashkeys = table.sortedhashkeys
-
-function tfm.hashfeatures(specification)
- local features = specification.features
- if features then
- local t, tn = { }, 0
- local normal = features.normal
- if normal and next(normal) then
- local f = sortedhashkeys(normal)
- for i=1,#f do
- local v = f[i]
- if v ~= "number" and v ~= "features" then -- i need to figure this out, features
- tn = tn + 1
- t[tn] = v .. '=' .. tostring(normal[v])
- end
- end
- end
- local vtf = features.vtf
- if vtf and next(vtf) then
- local f = sortedhashkeys(vtf)
- for i=1,#f do
- local v = f[i]
- tn = tn + 1
- t[tn] = v .. '=' .. tostring(vtf[v])
- end
- end
- -- if specification.mathsize then
- -- tn = tn + 1
- -- t[tn] = "mathsize=" .. specification.mathsize
- -- end
- if tn > 0 then
- return concat(t,"+")
- end
- end
- return "unknown"
-end
-
-fonts.designsizes = allocate()
-
---[[ldx--
-<p>In principle we can share tfm tables when we are in node for a font, but then
-we need to define a font switch as an id/attr switch which is no fun, so in that
-case users can best use dynamic features ... so, we will not use that speedup. Okay,
-when we get rid of base mode we can optimize even further by sharing, but then we
-loose our testcases for <l n='luatex'/>.</p>
---ldx]]--
-
-function tfm.hashinstance(specification,force)
- local hash, size, fallbacks = specification.hash, specification.size, specification.fallbacks
- if force or not hash then
- hash = tfm.hashfeatures(specification)
- specification.hash = hash
- end
- if size < 1000 and fonts.designsizes[hash] then
- size = math.round(tfm.scaled(size,fonts.designsizes[hash]))
- specification.size = size
- end
- -- local mathsize = specification.mathsize or 0
- -- if mathsize > 0 then
- -- local textsize = specification.textsize
- -- if fallbacks then
- -- return hash .. ' @ ' .. tostring(size) .. ' [ ' .. tostring(mathsize) .. ' : ' .. tostring(textsize) .. ' ] @ ' .. fallbacks
- -- else
- -- return hash .. ' @ ' .. tostring(size) .. ' [ ' .. tostring(mathsize) .. ' : ' .. tostring(textsize) .. ' ]'
- -- end
- -- else
- if fallbacks then
- return hash .. ' @ ' .. tostring(size) .. ' @ ' .. fallbacks
- else
- return hash .. ' @ ' .. tostring(size)
- end
- -- end
-end
-
---[[ldx--
<p>We can resolve the filename using the next function:</p>
--ldx]]--
@@ -15544,7 +10839,7 @@ function definers.resolve(specification)
end
end
--
- specification.hash = lower(specification.name .. ' @ ' .. tfm.hashfeatures(specification))
+ specification.hash = lower(specification.name .. ' @ ' .. constructors.hashfeatures(specification))
if specification.sub and specification.sub ~= "" then
specification.hash = specification.sub .. ' @ ' .. specification.hash
end
@@ -15567,26 +10862,48 @@ features (esp in virtual fonts) so let's not do that now.</p>
specification yet.</p>
--ldx]]--
-function tfm.read(specification)
- local hash = tfm.hashinstance(specification)
- local tfmtable = tfm.fonts[hash] -- hashes by size !
- if not tfmtable then
+-- not in context, at least not now:
+--
+-- function definers.applypostprocessors(tfmdata)
+-- local postprocessors = tfmdata.postprocessors
+-- if postprocessors then
+-- for i=1,#postprocessors do
+-- local extrahash = postprocessors[i](tfmdata) -- after scaling etc
+-- if type(extrahash) == "string" and extrahash ~= "" then
+-- -- e.g. a reencoding needs this
+-- extrahash = gsub(lower(extrahash),"[^a-z]","-")
+-- tfmdata.properties.fullname = format("%s-%s",tfmdata.properties.fullname,extrahash)
+-- end
+-- end
+-- end
+-- return tfmdata
+-- end
+
+function definers.applypostprocessors(tfmdata)
+ return tfmdata
+end
+
+function definers.loadfont(specification)
+ local hash = constructors.hashinstance(specification)
+ local tfmdata = loadedfonts[hash] -- hashes by size !
+ if not tfmdata then
local forced = specification.forced or ""
if forced ~= "" then
local reader = readers[lower(forced)]
- tfmtable = reader and reader(specification)
- if not tfmtable then
+ tfmdata = reader and reader(specification)
+ if not tfmdata then
report_defining("forced type %s of %s not found",forced,specification.name)
end
else
- for s=1,#sequence do -- reader sequence
+ local sequence = readers.sequence -- can be overloaded so only a shortcut here
+ for s=1,#sequence do
local reader = sequence[s]
- if readers[reader] then -- not really needed
+ if readers[reader] then -- we skip not loaded readers
if trace_defining then
report_defining("trying (reader sequence driven) type %s for %s with file %s",reader,specification.name,specification.filename or "unknown")
end
- tfmtable = readers[reader](specification)
- if tfmtable then
+ tfmdata = readers[reader](specification)
+ if tfmdata then
break
else
specification.filename = nil
@@ -15594,82 +10911,56 @@ function tfm.read(specification)
end
end
end
- if tfmtable then
+ if tfmdata then
+ local properties = tfmdata.properties
+ local embedding
if directive_embedall then
- tfmtable.embedding = "full"
- elseif tfmtable.filename and fonts.dontembed[tfmtable.filename] then
- tfmtable.embedding = "no"
+ embedding = "full"
+ elseif properties.filename and constructors.dontembed[properties.filename] then
+ embedding = "no"
else
- tfmtable.embedding = "subset"
+ embedding = "subset"
end
- -- fonts.goodies.postprocessors.apply(tfmdata) -- only here
- local postprocessors = tfmtable.postprocessors
- if postprocessors then
- for i=1,#postprocessors do
- local extrahash = postprocessors[i](tfmtable) -- after scaling etc
- if type(extrahash) == "string" and extrahash ~= "" then
- -- e.g. a reencoding needs this
- extrahash = gsub(lower(extrahash),"[^a-z]","-")
- tfmtable.fullname = format("%s-%s",tfmtable.fullname,extrahash)
- end
- end
+ if properties then
+ properties.embedding = embedding
+ else
+ tfmdata.properties = { embedding = embedding }
end
- --
- tfm.fonts[hash] = tfmtable
- fonts.designsizes[specification.hash] = tfmtable.designsize -- we only know this for sure after loading once
- --~ tfmtable.mode = specification.features.normal.mode or "base"
+ tfmdata = definers.applypostprocessors(tfmdata)
+ loadedfonts[hash] = tfmdata
+ designsizes[specification.hash] = tfmdata.parameters.designsize
end
end
- if not tfmtable then
+ if not tfmdata then
report_defining("font with asked name '%s' is not found using lookup '%s'",specification.name,specification.lookup)
end
- return tfmtable
+ return tfmdata
end
--[[ldx--
<p>For virtual fonts we need a slightly different approach:</p>
--ldx]]--
-function tfm.readanddefine(name,size) -- no id
+function constructors.readanddefine(name,size) -- no id -- maybe a dummy first
local specification = definers.analyze(name,size)
local method = specification.method
if method and variants[method] then
specification = variants[method](specification)
end
specification = definers.resolve(specification)
- local hash = tfm.hashinstance(specification)
+ local hash = constructors.hashinstance(specification)
local id = definers.registered(hash)
if not id then
- local tfmdata = tfm.read(specification)
+ local tfmdata = definers.loadfont(specification)
if tfmdata then
- tfmdata.hash = hash
+ tfmdata.properties.hash = hash
id = font.define(tfmdata)
definers.register(tfmdata,id)
- tfm.cleanuptable(tfmdata)
else
id = 0 -- signal
end
end
- return fonts.identifiers[id], id
-end
-
---[[ldx--
-<p>We need to check for default features. For this we provide
-a helper function.</p>
---ldx]]--
-
-function definers.check(features,defaults) -- nb adapts features !
- local done = false
- if features and next(features) then
- for k,v in next, defaults do
- if features[k] == nil then
- features[k], done = v, true
- end
- end
- else
- features, done = table.fastcopy(defaults), true
- end
- return features, done -- done signals a change
+ return fontdata[id], id
end
--[[ldx--
@@ -15691,42 +10982,24 @@ function definers.current() -- or maybe current
return lastdefined
end
-function definers.register(tfmdata,id) -- will be overloaded
+function definers.registered(hash)
+ local id = internalized[hash]
+ return id, id and fontdata[id]
+end
+
+function definers.register(tfmdata,id)
if tfmdata and id then
- local hash = tfmdata.hash
+ local hash = tfmdata.properties.hash
if not internalized[hash] then
+ internalized[hash] = id
if trace_defining then
report_defining("registering font, id: %s, hash: %s",id or "?",hash or "?")
end
- fonts.identifiers[id] = tfmdata
- internalized[hash] = id
+ fontdata[id] = tfmdata
end
end
end
-function definers.registered(hash) -- will be overloaded
- local id = internalized[hash]
- return id, id and fonts.identifiers[id]
-end
-
-local cache_them = false
-
-function tfm.make(specification)
- -- currently fonts are scaled while constructing the font, so we
- -- have to do scaling of commands in the vf at that point using
- -- e.g. "local scale = g.factor or 1" after all, we need to work
- -- with copies anyway and scaling needs to be done at some point;
- -- however, when virtual tricks are used as feature (makes more
- -- sense) we scale the commands in fonts.tfm.scale (and set the
- -- factor there)
- local fvm = definers.methods.variants[specification.features.vtf.preset]
- if fvm then
- return fvm(specification)
- else
- return nil
- end
-end
-
function definers.read(specification,size,id) -- id can be optional, name can already be table
statistics.starttiming(fonts)
if type(specification) == "string" then
@@ -15737,26 +11010,13 @@ function definers.read(specification,size,id) -- id can be optional, name can al
specification = variants[method](specification)
end
specification = definers.resolve(specification)
- local hash = tfm.hashinstance(specification)
- if cache_them then
- local tfmdata = containers.read(fonts.cache,hash) -- for tracing purposes
- end
+ local hash = constructors.hashinstance(specification)
local tfmdata = definers.registered(hash) -- id
if not tfmdata then
- if specification.features.vtf and specification.features.vtf.preset then
- tfmdata = tfm.make(specification)
- else
- tfmdata = tfm.read(specification)
- if tfmdata then
- tfm.checkvirtualid(tfmdata)
- end
- end
- if cache_them then
- tfmdata = containers.write(fonts.cache,hash,tfmdata) -- for tracing purposes
- end
+ tfmdata = definers.loadfont(specification) -- can be overloaded
if tfmdata then
- tfmdata.hash = hash
- tfmdata.cache = "no"
+--~ constructors.checkvirtualid(tfmdata) -- interferes
+ tfmdata.properties.hash = hash
if id then
definers.register(tfmdata,id)
end
@@ -15766,116 +11026,82 @@ function definers.read(specification,size,id) -- id can be optional, name can al
if not tfmdata then -- or id?
report_defining( "unknown font %s, loading aborted",specification.name)
elseif trace_defining and type(tfmdata) == "table" then
+ constructors.finalize(tfmdata)
+ -- local properties = tfmdata.properties or { }
+ -- local parameters = tfmdata.parameters or { }
report_defining("using %s font with id %s, name:%s size:%s bytes:%s encoding:%s fullname:%s filename:%s",
- tfmdata.type or "unknown",
- id or "?",
- tfmdata.name or "?",
- tfmdata.size or "default",
- tfmdata.encodingbytes or "?",
- tfmdata.encodingname or "unicode",
- tfmdata.fullname or "?",
- file.basename(tfmdata.filename or "?"))
+ properties.type or "unknown",
+ id or "?",
+ properties.name or "?",
+ parameters.size or "default",
+ properties.encodingbytes or "?",
+ properties.encodingname or "unicode",
+ properties.fullname or "?",
+ file.basename(properties.filename or "?"))
end
statistics.stoptiming(fonts)
return tfmdata
end
-function vf.find(name)
- name = file.removesuffix(file.basename(name))
- if tfm.resolvevirtualtoo then
- local format = fonts.logger.format(name)
- if format == 'tfm' or format == 'ofm' then
- if trace_defining then
- report_defining("locating vf for %s",name)
- end
- return findbinfile(name,"ovf")
- else
- if trace_defining then
- report_defining("vf for %s is already taken care of",name)
- end
- return nil -- ""
- end
- else
- if trace_defining then
- report_defining("locating vf for %s",name)
- end
- return findbinfile(name,"ovf")
- end
-end
-
--[[ldx--
-<p>We overload both the <l n='tfm'/> and <l n='vf'/> readers.</p>
+<p>We overload the <l n='tfm'/> reader.</p>
--ldx]]--
-callbacks.register('define_font' , definers.read, "definition of fonts (tfmtable preparation)")
-callbacks.register('find_vf_file', vf.find, "locating virtual fonts, insofar needed") -- not that relevant any more
+callbacks.register('define_font' , definers.read, "definition of fonts (tfmdata preparation)")
end -- closure
do -- begin closure to overcome local limits and interference
-if not modules then modules = { } end modules ['font-xtx'] = {
+if not modules then modules = { } end modules ['luatex-font-def'] = {
version = 1.001,
- comment = "companion to font-ini.mkiv",
+ comment = "companion to luatex-*.tex",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
}
-local texsprint, count = tex.sprint, tex.count
-local format, concat, gmatch, match, find, lower = string.format, table.concat, string.gmatch, string.match, string.find, string.lower
-local tostring, next = tostring, next
-local lpegmatch = lpeg.match
+if context then
+ texio.write_nl("fatal error: this module is not for context")
+ os.exit()
+end
-local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
+local fonts = fonts
---[[ldx--
-<p>Choosing a font by name and specififying its size is only part of the
-game. In order to prevent complex commands, <l n='xetex'/> introduced
-a method to pass feature information as part of the font name. At the
-risk of introducing nasty parsing and compatinility problems, this
-syntax was expanded over time.</p>
-
-<p>For the sake of users who have defined fonts using that syntax, we
-will support it, but we will provide additional methods as well.
-Normally users will not use this direct way, but use a more abstract
-interface.</p>
-
-<p>The next one is the official one. However, in the plain
-variant we need to support the crappy [] specification as
-well and that does not work too well with the general design
-of the specifier.</p>
---ldx]]--
+-- A bit of tuning for definitions.
-local fonts = fonts
-local definers = fonts.definers
-local specifiers = definers.specifiers
-local normalize_meanings = fonts.otf.meanings.normalize
+fonts.constructors.namemode = "specification" -- somehow latex needs this (changed name!) => will change into an overload
-local list = { }
+-- tricky: we sort of bypass the parser and directly feed all into
+-- the sub parser
-specifiers.colonizedpreference = "file"
+function fonts.definers.getspecification(str)
+ return "", str, "", ":", str
+end
-local function issome () list.lookup = specifiers.colonizedpreference end
-local function isfile () list.lookup = 'file' end
-local function isname () list.lookup = 'name' end
-local function thename(s) list.name = s end
-local function issub (v) list.sub = v end
-local function iscrap (s) list.crap = string.lower(s) end
-local function istrue (s) list[s] = 'yes' end
-local function isfalse(s) list[s] = 'no' end
-local function iskey (k,v) list[k] = v end
+-- the generic name parser (different from context!)
-local function istrue (s) list[s] = true end
-local function isfalse(s) list[s] = false end
+local list = { }
+
+local function issome () list.lookup = 'name' end -- xetex mode prefers name (not in context!)
+local function isfile () list.lookup = 'file' end
+local function isname () list.lookup = 'name' end
+local function thename(s) list.name = s end
+local function issub (v) list.sub = v end
+local function iscrap (s) list.crap = string.lower(s) end
+local function iskey (k,v) list[k] = v end
+local function istrue (s) list[s] = true end
+local function isfalse(s) list[s] = false end
local P, S, R, C = lpeg.P, lpeg.S, lpeg.R, lpeg.C
local spaces = P(" ")^0
local namespec = (1-S("/:("))^0 -- was: (1-S("/: ("))^0
local crapspec = spaces * P("/") * (((1-P(":"))^0)/iscrap) * spaces
-local filename = (P("file:")/isfile * (namespec/thename)) + (P("[") * P(true)/isname * (((1-P("]"))^0)/thename) * P("]"))
-local fontname = (P("name:")/isname * (namespec/thename)) + P(true)/issome * (namespec/thename)
+local filename_1 = P("file:")/isfile * (namespec/thename)
+local filename_2 = P("[") * P(true)/isname * (((1-P("]"))^0)/thename) * P("]")
+local fontname_1 = P("name:")/isname * (namespec/thename)
+local fontname_2 = P(true)/issome * (namespec/thename)
local sometext = (R("az","AZ","09") + S("+-."))^1
local truevalue = P("+") * spaces * (sometext/istrue)
local falsevalue = P("-") * spaces * (sometext/isfalse)
@@ -15884,17 +11110,12 @@ local somevalue = sometext/istrue
local subvalue = P("(") * (C(P(1-S("()"))^1)/issub) * P(")") -- for Kim
local option = spaces * (keyvalue + falsevalue + truevalue + somevalue) * spaces
local options = P(":") * spaces * (P(";")^0 * option)^0
-local pattern = (filename + fontname) * subvalue^0 * crapspec^0 * options^0
+
+local pattern = (filename_1 + filename_2 + fontname_1 + fontname_2) * subvalue^0 * crapspec^0 * options^0
local function colonized(specification) -- xetex mode
list = { }
- lpegmatch(pattern,specification.specification)
- -- for k, v in next, list do
- -- list[k] = is_boolean(v)
- -- if type(list[a]) == "nil" then
- -- list[k] = v
- -- end
- -- end
+ lpeg.match(pattern,specification.specification)
list.crap = nil -- style not supported, maybe some day
if list.name then
specification.name = list.name
@@ -15908,18 +11129,33 @@ local function colonized(specification) -- xetex mode
specification.sub = list.sub
list.sub = nil
end
- -- specification.features.normal = list
- specification.features.normal = normalize_meanings(list)
+ specification.features.normal = fonts.handlers.otf.features.normalize(list)
return specification
end
-definers.registersplit(":",colonized,"cryptic")
+fonts.definers.registersplit(":",colonized,"cryptic")
+fonts.definers.registersplit("", colonized,"more cryptic") -- catches \font\text=[names]
+
+function definers.applypostprocessors(tfmdata)
+ local postprocessors = tfmdata.postprocessors
+ if postprocessors then
+ for i=1,#postprocessors do
+ local extrahash = postprocessors[i](tfmdata) -- after scaling etc
+ if type(extrahash) == "string" and extrahash ~= "" then
+ -- e.g. a reencoding needs this
+ extrahash = string.gsub(lower(extrahash),"[^a-z]","-")
+ tfmdata.properties.fullname = format("%s-%s",tfmdata.properties.fullname,extrahash)
+ end
+ end
+ end
+ return tfmdata
+end
end -- closure
do -- begin closure to overcome local limits and interference
-if not modules then modules = { } end modules ['font-dum'] = {
+if not modules then modules = { } end modules ['luatex-fonts-ext'] = {
version = 1.001,
comment = "companion to luatex-*.tex",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
@@ -15927,125 +11163,46 @@ if not modules then modules = { } end modules ['font-dum'] = {
license = "see context related readme files"
}
-fonts = fonts or { }
-
--- general
-
-fonts.otf.pack = false -- only makes sense in context
-fonts.tfm.resolvevirtualtoo = false -- context specific (due to resolver)
-fonts.tfm.fontnamemode = "specification" -- somehow latex needs this (changed name!)
-
--- readers
-
-fonts.tfm.readers = fonts.tfm.readers or { }
-fonts.tfm.readers.sequence = { 'otf', 'ttf', 'tfm', 'lua' }
-fonts.tfm.readers.afm = nil
-
--- define
-
-fonts.definers = fonts.definers or { }
-fonts.definers.specifiers = fonts.definers.specifiers or { }
-
-fonts.definers.specifiers.colonizedpreference = "name" -- is "file" in context
-
-function fonts.definers.getspecification(str)
- return "", str, "", ":", str
-end
-
-fonts.definers.registersplit("",fonts.definers.specifiers.variants[":"]) -- we add another one for catching lone [names]
-
--- logger
-
-fonts.logger = fonts.logger or { }
-
-function fonts.logger.save()
-end
-
--- names
---
--- Watch out, the version number is the same as the one used in
--- the mtx-fonts.lua function scripts.fonts.names as we use a
--- simplified font database in the plain solution and by using
--- a different number we're less dependent on context.
-
-fonts.names = fonts.names or { }
-
-fonts.names.version = 1.001 -- not the same as in context
-fonts.names.basename = "luatex-fonts-names.lua"
-fonts.names.new_to_old = { }
-fonts.names.old_to_new = { }
-
-local data, loaded = nil, false
-
-local fileformats = { "lua", "tex", "other text files" }
-
-function fonts.names.resolve(name,sub)
- if not loaded then
- local basename = fonts.names.basename
- if basename and basename ~= "" then
- for i=1,#fileformats do
- local format = fileformats[i]
- local foundname = resolvers.findfile(basename,format) or ""
- if foundname ~= "" then
- data = dofile(foundname)
- break
- end
- end
- end
- loaded = true
- end
- if type(data) == "table" and data.version == fonts.names.version then
- local condensed = string.gsub(string.lower(name),"[^%a%d]","")
- local found = data.mappings and data.mappings[condensed]
- if found then
- local fontname, filename, subfont = found[1], found[2], found[3]
- if subfont then
- return filename, fontname
- else
- return filename, false
- end
- else
- return name, false -- fallback to filename
- end
- end
-end
-
-fonts.names.resolvespec = fonts.names.resolve -- only supported in mkiv
-
-function fonts.names.getfilename(askedname,suffix) -- only supported in mkiv
- return ""
+if context then
+ texio.write_nl("fatal error: this module is not for context")
+ os.exit()
end
--- For the moment we put this (adapted) pseudo feature here.
+local fonts = fonts
+local otffeatures = fonts.constructors.newfeatures("otf")
-table.insert(fonts.triggers,"itlc")
+-- A few generic extensions.
-local function itlc(tfmdata,value)
+local function initializeitlc(tfmdata,value)
if value then
-- the magic 40 and it formula come from Dohyun Kim
- local metadata = tfmdata.shared.otfdata.metadata
- if metadata then
- local italicangle = metadata.italicangle
- if italicangle and italicangle ~= 0 then
- local uwidth = (metadata.uwidth or 40)/2
- for unicode, d in next, tfmdata.descriptions do
- local it = d.boundingbox[3] - d.width + uwidth
- if it ~= 0 then
- d.italic = it
- end
+ local parameters = tfmdata.parameters
+ local italicangle = parameters.italicangle
+ if italicangle and italicangle ~= 0 then
+ local uwidth = (parameters.uwidth or 40)/2
+ for unicode, d in next, tfmdata.descriptions do
+ local it = d.boundingbox[3] - d.width + uwidth
+ if it ~= 0 then
+ d.italic = it
end
- tfmdata.has_italic = true
end
+ tfmdata.properties.italic_correction = true
end
end
end
-fonts.initializers.base.otf.itlc = itlc
-fonts.initializers.node.otf.itlc = itlc
+otffeatures.register {
+ name = "itlc",
+ description = "italic correction",
+ initializers = {
+ base = initializeitlc,
+ node = initializeitlc,
+ }
+}
-- slant and extend
-function fonts.initializers.common.slant(tfmdata,value)
+local function initializeslant(tfmdata,value)
value = tonumber(value)
if not value then
value = 0
@@ -16054,10 +11211,19 @@ function fonts.initializers.common.slant(tfmdata,value)
elseif value < -1 then
value = -1
end
- tfmdata.slant_factor = value
+ tfmdata.parameters.slant_factor = value
end
-function fonts.initializers.common.extend(tfmdata,value)
+otffeatures.register {
+ name = "slant",
+ description = "slant glyphs",
+ initializers = {
+ base = initializeslant,
+ node = initializeslant,
+ }
+}
+
+local function initializeextend(tfmdata,value)
value = tonumber(value)
if not value then
value = 0
@@ -16066,31 +11232,34 @@ function fonts.initializers.common.extend(tfmdata,value)
elseif value < -10 then
value = -10
end
- tfmdata.extend_factor = value
+ tfmdata.parameters.extend_factor = value
end
-table.insert(fonts.triggers,"slant")
-table.insert(fonts.triggers,"extend")
-
-fonts.initializers.base.otf.slant = fonts.initializers.common.slant
-fonts.initializers.node.otf.slant = fonts.initializers.common.slant
-fonts.initializers.base.otf.extend = fonts.initializers.common.extend
-fonts.initializers.node.otf.extend = fonts.initializers.common.extend
+otffeatures.register {
+ name = "extend",
+ description = "scale glyphs horizontally",
+ initializers = {
+ base = initializeextend,
+ node = initializeextend,
+ }
+}
-- expansion and protrusion
fonts.protrusions = fonts.protrusions or { }
fonts.protrusions.setups = fonts.protrusions.setups or { }
-local setups = fonts.protrusions.setups
+local setups = fonts.protrusions.setups
-function fonts.initializers.common.protrusion(tfmdata,value)
+local function initializeprotrusion(tfmdata,value)
if value then
local setup = setups[value]
if setup then
local factor, left, right = setup.factor or 1, setup.left or 1, setup.right or 1
local emwidth = tfmdata.parameters.quad
- tfmdata.auto_protrude = true
+ tfmdata.parameters.protrusion = {
+ auto = true,
+ }
for i, chr in next, tfmdata.characters do
local v, pl, pr = setup[i], nil, nil
if v then
@@ -16103,17 +11272,31 @@ function fonts.initializers.common.protrusion(tfmdata,value)
end
end
+otffeatures.register {
+ name = "protrusion",
+ description = "shift characters into the left and or right margin",
+ initializers = {
+ base = initializeprotrusion,
+ node = initializeprotrusion,
+ }
+}
+
fonts.expansions = fonts.expansions or { }
fonts.expansions.setups = fonts.expansions.setups or { }
local setups = fonts.expansions.setups
-function fonts.initializers.common.expansion(tfmdata,value)
+local function initializeexpansion(tfmdata,value)
if value then
local setup = setups[value]
if setup then
- local stretch, shrink, step, factor = setup.stretch or 0, setup.shrink or 0, setup.step or 0, setup.factor or 1
- tfmdata.stretch, tfmdata.shrink, tfmdata.step, tfmdata.auto_expand = stretch * 10, shrink * 10, step * 10, true
+ local factor = setup.factor or 1
+ tfmdata.parameters.expansion = {
+ stretch = 10 * (setup.stretch or 0),
+ shrink = 10 * (setup.shrink or 0),
+ step = 10 * (setup.step or 0),
+ auto = true,
+ }
for i, chr in next, tfmdata.characters do
local v = setup[i]
if v and v ~= 0 then
@@ -16126,18 +11309,18 @@ function fonts.initializers.common.expansion(tfmdata,value)
end
end
-table.insert(fonts.manipulators,"protrusion")
-table.insert(fonts.manipulators,"expansion")
-
-fonts.initializers.base.otf.protrusion = fonts.initializers.common.protrusion
-fonts.initializers.node.otf.protrusion = fonts.initializers.common.protrusion
-fonts.initializers.base.otf.expansion = fonts.initializers.common.expansion
-fonts.initializers.node.otf.expansion = fonts.initializers.common.expansion
+otffeatures.register {
+ name = "expansion",
+ description = "apply hz optimization",
+ initializers = {
+ base = initializeexpansion,
+ node = initializeexpansion,
+ }
+}
-- left over
-function fonts.registermessage()
-end
+function fonts.loggers.onetimemessage() end
-- example vectors
@@ -16179,68 +11362,37 @@ fonts.protrusions.setups['default'] = {
-- normalizer
-fonts.otf.meanings = fonts.otf.meanings or { }
-
-fonts.otf.meanings.normalize = fonts.otf.meanings.normalize or function(t)
+fonts.handlers.otf.features.normalize = function(t)
if t.rand then
t.rand = "random"
end
-end
-
--- needed (different in context)
-
-function fonts.otf.scriptandlanguage(tfmdata)
- return tfmdata.script, tfmdata.language
+ return t
end
-- bonus
-function fonts.otf.nametoslot(name)
- local tfmdata = fonts.identifiers[font.current()]
- if tfmdata and tfmdata.shared then
- local otfdata = tfmdata.shared.otfdata
- local unicode = otfdata.luatex.unicodes[name]
- return unicode and (type(unicode) == "number" and unicode or unicode[1])
+function fonts.helpers.nametoslot(name)
+ local t = type(name)
+ if t == "string" then
+ local tfmdata = fonts.hashes.identifiers[currentfont()]
+ local shared = tfmdata and tfmdata.shared
+ local fntdata = shared and shared.rawdata
+ return fntdata and fntdata.resources.unicodes[name]
+ elseif t == "number" then
+ return n
end
end
-function fonts.otf.char(n)
- if type(n) == "string" then
- n = fonts.otf.nametoslot(n)
- end
- if type(n) == "number" then
- tex.sprint("\\char" .. n)
- end
-end
-
--- another one:
-
-fonts.strippables = table.tohash {
- 0x000AD, 0x017B4, 0x017B5, 0x0200B, 0x0200C, 0x0200D, 0x0200E, 0x0200F, 0x0202A, 0x0202B,
- 0x0202C, 0x0202D, 0x0202E, 0x02060, 0x02061, 0x02062, 0x02063, 0x0206A, 0x0206B, 0x0206C,
- 0x0206D, 0x0206E, 0x0206F, 0x0FEFF, 0x1D173, 0x1D174, 0x1D175, 0x1D176, 0x1D177, 0x1D178,
- 0x1D179, 0x1D17A, 0xE0001, 0xE0020, 0xE0021, 0xE0022, 0xE0023, 0xE0024, 0xE0025, 0xE0026,
- 0xE0027, 0xE0028, 0xE0029, 0xE002A, 0xE002B, 0xE002C, 0xE002D, 0xE002E, 0xE002F, 0xE0030,
- 0xE0031, 0xE0032, 0xE0033, 0xE0034, 0xE0035, 0xE0036, 0xE0037, 0xE0038, 0xE0039, 0xE003A,
- 0xE003B, 0xE003C, 0xE003D, 0xE003E, 0xE003F, 0xE0040, 0xE0041, 0xE0042, 0xE0043, 0xE0044,
- 0xE0045, 0xE0046, 0xE0047, 0xE0048, 0xE0049, 0xE004A, 0xE004B, 0xE004C, 0xE004D, 0xE004E,
- 0xE004F, 0xE0050, 0xE0051, 0xE0052, 0xE0053, 0xE0054, 0xE0055, 0xE0056, 0xE0057, 0xE0058,
- 0xE0059, 0xE005A, 0xE005B, 0xE005C, 0xE005D, 0xE005E, 0xE005F, 0xE0060, 0xE0061, 0xE0062,
- 0xE0063, 0xE0064, 0xE0065, 0xE0066, 0xE0067, 0xE0068, 0xE0069, 0xE006A, 0xE006B, 0xE006C,
- 0xE006D, 0xE006E, 0xE006F, 0xE0070, 0xE0071, 0xE0072, 0xE0073, 0xE0074, 0xE0075, 0xE0076,
- 0xE0077, 0xE0078, 0xE0079, 0xE007A, 0xE007B, 0xE007C, 0xE007D, 0xE007E, 0xE007F,
-}
-
-- \font\test=file:somefont:reencode=mymessup
--
--- fonts.enc.reencodings.mymessup = {
+-- fonts.encodings.reencodings.mymessup = {
-- [109] = 110, -- m
-- [110] = 109, -- n
-- }
-fonts.enc = fonts.enc or {}
-local reencodings = { }
-fonts.enc.reencodings = reencodings
+fonts.encodings = fonts.encodings or { }
+local reencodings = { }
+fonts.encodings.reencodings = reencodings
local function specialreencode(tfmdata,value)
-- we forget about kerns as we assume symbols and we
@@ -16271,7 +11423,86 @@ local function reencode(tfmdata,value)
)
end
-table.insert(fonts.manipulators,"reencode")
-fonts.initializers.base.otf.reencode = reencode
+otffeatures.register {
+ name = "reencode",
+ description = "reencode characters",
+ manipulators = {
+ base = reencode,
+ node = reencode,
+ }
+}
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['luatex-fonts-cbk'] = {
+ version = 1.001,
+ comment = "companion to luatex-*.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+if context then
+ texio.write_nl("fatal error: this module is not for context")
+ os.exit()
+end
+
+local fonts = fonts
+local nodes = nodes
+
+-- Fonts: (might move to node-gef.lua)
+
+local traverse_id = node.traverse_id
+local glyph_code = nodes.nodecodes.glyph
+
+function nodes.handlers.characters(head)
+ local fontdata = fonts.hashes.identifiers
+ if fontdata then
+ local usedfonts, done, prevfont = { }, false, nil
+ for n in traverse_id(glyph_code,head) do
+ local font = n.font
+ if font ~= prevfont then
+ prevfont = font
+ local used = usedfonts[font]
+ if not used then
+ local tfmdata = fontdata[font] --
+ if tfmdata then
+ local shared = tfmdata.shared -- we need to check shared, only when same features
+ if shared then
+ local processors = shared.processes
+ if processors and #processors > 0 then
+ usedfonts[font] = processors
+ done = true
+ end
+ end
+ end
+ end
+ end
+ end
+ if done then
+ for font, processors in next, usedfonts do
+ for i=1,#processors do
+ local h, d = processors[i](head,font,0)
+ head, done = h or head, done or d
+ end
+ end
+ end
+ return head, true
+ else
+ return head, false
+ end
+end
+
+function nodes.simple_font_handler(head)
+-- lang.hyphenate(head)
+ head = nodes.handlers.characters(head)
+ nodes.injections.handler(head)
+ nodes.handlers.protectglyphs(head)
+ head = node.ligaturing(head)
+ head = node.kerning(head)
+ return head
+end
end -- closure
diff --git a/tex/generic/context/luatex-fonts-syn.lua b/tex/generic/context/luatex-fonts-syn.lua
new file mode 100644
index 000000000..36a74d0f4
--- /dev/null
+++ b/tex/generic/context/luatex-fonts-syn.lua
@@ -0,0 +1,83 @@
+if not modules then modules = { } end modules ['luatex-fonts-syn'] = {
+ version = 1.001,
+ comment = "companion to luatex-*.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+if context then
+ texio.write_nl("fatal error: this module is not for context")
+ os.exit()
+end
+
+-- Generic font names support.
+--
+-- Watch out, the version number is the same as the one used in
+-- the mtx-fonts.lua function scripts.fonts.names as we use a
+-- simplified font database in the plain solution and by using
+-- a different number we're less dependent on context.
+--
+-- mtxrun --script font --reload --simple
+--
+-- The format of the file is as follows:
+--
+-- return {
+-- ["version"] = 1.001,
+-- ["mappings"] = {
+-- ["somettcfontone"] = { "Some TTC Font One", "SomeFontA.ttc", 1 },
+-- ["somettcfonttwo"] = { "Some TTC Font Two", "SomeFontA.ttc", 2 },
+-- ["somettffont"] = { "Some TTF Font", "SomeFontB.ttf" },
+-- ["someotffont"] = { "Some OTF Font", "SomeFontC.otf" },
+-- },
+-- }
+
+local fonts = fonts
+fonts.names = fonts.names or { }
+
+fonts.names.version = 1.001 -- not the same as in context
+fonts.names.basename = "luatex-fonts-names.lua"
+fonts.names.new_to_old = { }
+fonts.names.old_to_new = { }
+
+local data, loaded = nil, false
+
+local fileformats = { "lua", "tex", "other text files" }
+
+function fonts.names.resolve(name,sub)
+ if not loaded then
+ local basename = fonts.names.basename
+ if basename and basename ~= "" then
+ for i=1,#fileformats do
+ local format = fileformats[i]
+ local foundname = resolvers.findfile(basename,format) or ""
+ if foundname ~= "" then
+ data = dofile(foundname)
+ texio.write("<font database loaded: ",foundname,">")
+ break
+ end
+ end
+ end
+ loaded = true
+ end
+ if type(data) == "table" and data.version == fonts.names.version then
+ local condensed = string.gsub(string.lower(name),"[^%a%d]","")
+ local found = data.mappings and data.mappings[condensed]
+ if found then
+ local fontname, filename, subfont = found[1], found[2], found[3]
+ if subfont then
+ return filename, fontname
+ else
+ return filename, false
+ end
+ else
+ return name, false -- fallback to filename
+ end
+ end
+end
+
+fonts.names.resolvespec = fonts.names.resolve -- only supported in mkiv
+
+function fonts.names.getfilename(askedname,suffix) -- only supported in mkiv
+ return ""
+end
diff --git a/tex/generic/context/luatex-fonts-tfm.lua b/tex/generic/context/luatex-fonts-tfm.lua
new file mode 100644
index 000000000..b9bb1bd0f
--- /dev/null
+++ b/tex/generic/context/luatex-fonts-tfm.lua
@@ -0,0 +1,38 @@
+if not modules then modules = { } end modules ['luatex-fonts-tfm'] = {
+ version = 1.001,
+ comment = "companion to luatex-*.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+if context then
+ texio.write_nl("fatal error: this module is not for context")
+ os.exit()
+end
+
+local fonts = fonts
+local tfm = { }
+fonts.handlers.tfm = tfm
+fonts.formats.tfm = "type1" -- we need to have at least a value here
+
+function fonts.readers.tfm(specification)
+ local fullname = specification.filename or ""
+ if fullname == "" then
+ local forced = specification.forced or ""
+ if forced ~= "" then
+ fullname = specification.name .. "." .. forced
+ else
+ fullname = specification.name
+ end
+ end
+ local foundname = resolvers.findbinfile(fullname, 'tfm') or ""
+ if foundname == "" then
+ foundname = resolvers.findbinfile(fullname, 'ofm') or ""
+ end
+ if foundname ~= "" then
+ specification.filename = foundname
+ specification.format = "ofm"
+ return font.read_tfm(specification.filename,specification.size)
+ end
+end
diff --git a/tex/generic/context/luatex-fonts.lua b/tex/generic/context/luatex-fonts.lua
index c96dada77..84d79a63f 100644
--- a/tex/generic/context/luatex-fonts.lua
+++ b/tex/generic/context/luatex-fonts.lua
@@ -6,8 +6,58 @@ if not modules then modules = { } end modules ['luatex-fonts'] = {
license = "see context related readme files"
}
+-- The following code isolates the generic ConTeXt code from already
+-- defined or to be defined namespaces.
+
+-- todo: all global namespaces in called modules will get local shortcuts
+
+utf = unicode.utf8
+
+if not generic_context then
+
+ generic_context = { }
+
+end
+
+if not generic_context.push_namespaces then
+
+ function generic_context.push_namespaces()
+ texio.write(" <push namespace>")
+ local normalglobal = { }
+ for k, v in next, _G do
+ normalglobal[k] = v
+ end
+ return normalglobal
+ end
+
+ function generic_context.pop_namespaces(normalglobal,isolate)
+ if normalglobal then
+ texio.write(" <pop namespace>")
+ for k, v in next, _G do
+ if not normalglobal[k] then
+ generic_context[k] = v
+ if isolate then
+ _G[k] = nil
+ end
+ end
+ end
+ for k, v in next, normalglobal do
+ _G[k] = v
+ end
+ -- just to be sure:
+ setmetatable(generic_context,_G)
+ else
+ texio.write(" <fatal error: invalid pop of generic_context>")
+ os.exit()
+ end
+ end
+
+end
+
+local whatever = generic_context.push_namespaces()
+
-- We keep track of load time by storing the current time. That
--- way we cannot be accused of slowing down luading too much.
+-- way we cannot be accused of slowing down loading too much.
--
-- Please don't update to this version without proper testing. It
-- might be that this version lags behind stock context and the only
@@ -58,7 +108,8 @@ if fonts then
texio.write_nl("log", "! if you have ConTeXt installed you can try to delete the file")
texio.write_nl("log", "! 'luatex-font-merged.lua' as I might then use the possibly")
texio.write_nl("log", "! updated libraries. The merged version is not supported as it")
- texio.write_nl("log", "! is a frozen instance.")
+ texio.write_nl("log", "! is a frozen instance. Problems can be reported to the ConTeXt")
+ texio.write_nl("log", "! mailing list.")
texio.write_nl("log", "!")
end
@@ -83,24 +134,20 @@ else
-- lack of other modules.
-- First we load a few helper modules. This is about the miminum
- -- needed to let the font modules do theuir work.
+ -- needed to let the font modules do their work. Don't depend on
+ -- their functions as we might strip them in future versions of
+ -- this generic variant.
- loadmodule('luat-dum.lua') -- not used in context at all
- loadmodule('data-con.lua') -- maybe some day we don't need this one
+ loadmodule('luatex-basics-gen.lua')
+ loadmodule('data-con.lua')
- -- We do need some basic node support although the following
- -- modules contain a little bit of code that is not used. It's
- -- not worth weeding. Beware, in node-dum some functions use
- -- fonts.* tables, not that nice but I don't want two dummy
- -- files. Some day I will sort this out (no problem in context).
+ -- We do need some basic node support. The code in there is not for
+ -- general use as it might change.
- loadmodule('node-dum.lua')
- loadmodule('node-inj.lua') -- will be replaced (luatex >= .70)
+ loadmodule('luatex-basics-nod.lua')
-- Now come the font modules that deal with traditional TeX fonts
- -- as well as open type fonts. We don't load the afm related code
- -- from font-enc.lua and font-afm.lua as only ConTeXt deals with
- -- it.
+ -- as well as open type fonts. We only support OpenType fonts here.
--
-- The font database file (if used at all) must be put someplace
-- visible for kpse and is not shared with ConTeXt. The mtx-fonts
@@ -108,37 +155,58 @@ else
-- option).
loadmodule('font-ini.lua')
- loadmodule('font-tfm.lua') -- will be split (we may need font-log)
+ loadmodule('font-con.lua')
+ loadmodule('luatex-fonts-enc.lua') -- will load font-age on demand
loadmodule('font-cid.lua')
- loadmodule('font-ott.lua') -- might be split
- loadmodule('font-map.lua') -- for loading lum file (will be stripped)
- loadmodule('font-lua.lua')
- loadmodule('font-otf.lua')
- loadmodule('font-otd.lua')
+ loadmodule('font-map.lua') -- for loading lum file (will be stripped)
+ loadmodule('luatex-fonts-syn.lua') -- deals with font names (synonyms)
+ loadmodule('luatex-fonts-tfm.lua')
loadmodule('font-oti.lua')
+ loadmodule('font-otf.lua')
loadmodule('font-otb.lua')
+ loadmodule('node-inj.lua') -- will be replaced (luatex >= .70)
loadmodule('font-otn.lua')
loadmodule('font-ota.lua')
- loadmodule('font-otc.lua')
- loadmodule('font-age.lua') -- special for this variant
+ loadmodule('luatex-fonts-lua.lua')
loadmodule('font-def.lua')
- loadmodule('font-xtx.lua')
- loadmodule('font-dum.lua')
+ loadmodule('luatex-fonts-def.lua')
+ loadmodule('luatex-fonts-ext.lua') -- some extensions
+
+ -- We need to plug into a callback and the following module implements
+ -- the handlers. Actual plugging in happens later.
+
+ loadmodule('luatex-fonts-cbk.lua')
end
resolvers.loadmodule = loadmodule
-- In order to deal with the fonts we need to initialize some
--- callbacks. One can overload them later on if needed.
+-- callbacks. One can overload them later on if needed. First
+-- a bit of abstraction.
+
+generic_context.callback_ligaturing = false
+generic_context.callback_kerning = false
+generic_context.callback_pre_linebreak_filter = nodes.simple_font_handler
+generic_context.callback_hpack_filter = nodes.simple_font_handler
+generic_context.callback_define_font = fonts.definers.read
+
+-- The next ones can be done at a different moment if needed. You can create
+-- a generic_context namespace and set no_callbacks_yet to true, load this
+-- module, and enable the callbacks later.
+
+if not generic_context.no_callbacks_yet then
-callback.register('ligaturing', false)
-callback.register('kerning', false)
-callback.register('pre_linebreak_filter', nodes.simple_font_handler)
-callback.register('hpack_filter', nodes.simple_font_handler)
-callback.register('define_font' , fonts.definers.read)
-callback.register('find_vf_file', nil) -- reset to normal
+ callback.register('ligaturing', generic_context.callback_ligaturing)
+ callback.register('kerning', generic_context.callback_kerning)
+ callback.register('pre_linebreak_filter', generic_context.callback_pre_linebreak_filter)
+ callback.register('hpack_filter', generic_context.callback_hpack_filter)
+ callback.register('define_font' , generic_context.callback_define_font)
+
+end
-- We're done.
texio.write(string.format(" <luatex-fonts.lua loaded in %0.3f seconds>", os.gettimeofday()-starttime))
+
+generic_context.pop_namespaces(whatever)