summaryrefslogtreecommitdiff
path: root/tex
diff options
context:
space:
mode:
Diffstat (limited to 'tex')
-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
235 files changed, 20335 insertions, 21883 deletions
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)