From 25fcad7435f56cdce2658336909f4da6a65589c0 Mon Sep 17 00:00:00 2001 From: Hans Hagen Date: Fri, 13 Apr 2018 15:51:39 +0200 Subject: 2018-04-13 15:02:00 --- tex/context/base/mkii/cont-new.mkii | 2 +- tex/context/base/mkii/context.mkii | 2 +- tex/context/base/mkii/mult-nl.mkii | 7 +- tex/context/base/mkiv/anch-bck.mkvi | 4 +- tex/context/base/mkiv/back-exp.lua | 14 +- tex/context/base/mkiv/buff-ini.mkiv | 24 - tex/context/base/mkiv/catc-ini.mkiv | 161 +- tex/context/base/mkiv/char-act.mkiv | 36 +- tex/context/base/mkiv/cldf-ini.lua | 8 +- tex/context/base/mkiv/cont-new.mkiv | 2 +- tex/context/base/mkiv/context.mkiv | 4 +- tex/context/base/mkiv/font-cft.lua | 10 + tex/context/base/mkiv/font-chk.lua | 39 +- tex/context/base/mkiv/font-col.lua | 31 +- tex/context/base/mkiv/font-con.lua | 64 +- tex/context/base/mkiv/font-ctx.lua | 347 +++- tex/context/base/mkiv/font-def.lua | 1 + tex/context/base/mkiv/font-dsp.lua | 34 +- tex/context/base/mkiv/font-enh.lua | 16 +- tex/context/base/mkiv/font-ext.lua | 1856 -------------------- tex/context/base/mkiv/font-fbk.lua | 260 +-- tex/context/base/mkiv/font-fea.mkvi | 10 +- tex/context/base/mkiv/font-imp-dimensions.lua | 113 ++ tex/context/base/mkiv/font-imp-effects.lua | 397 +++++ tex/context/base/mkiv/font-imp-italics.lua | 147 ++ tex/context/base/mkiv/font-imp-ligatures.lua | 136 ++ tex/context/base/mkiv/font-imp-math.lua | 79 + tex/context/base/mkiv/font-imp-notused.lua | 166 ++ tex/context/base/mkiv/font-imp-properties.lua | 128 ++ tex/context/base/mkiv/font-imp-quality.lua | 477 +++++ tex/context/base/mkiv/font-imp-reorder.lua | 172 ++ tex/context/base/mkiv/font-imp-tex.lua | 144 ++ tex/context/base/mkiv/font-imp-tracing.lua | 171 ++ tex/context/base/mkiv/font-imp-unicode.lua | 80 + tex/context/base/mkiv/font-ini.mkvi | 10 +- tex/context/base/mkiv/font-lib.mkvi | 21 +- tex/context/base/mkiv/font-map.lua | 105 +- tex/context/base/mkiv/font-mat.mkvi | 30 +- tex/context/base/mkiv/font-nod.lua | 13 +- tex/context/base/mkiv/font-ocl.lua | 59 +- tex/context/base/mkiv/font-otc.lua | 299 +--- tex/context/base/mkiv/font-otj.lua | 4 + tex/context/base/mkiv/font-ott.lua | 22 +- tex/context/base/mkiv/font-pre.mkiv | 30 +- tex/context/base/mkiv/font-prv.lua | 74 + tex/context/base/mkiv/font-shp.lua | 10 +- tex/context/base/mkiv/font-tfm.lua | 5 +- tex/context/base/mkiv/font-vfc.lua | 98 ++ tex/context/base/mkiv/font-vir.lua | 8 +- tex/context/base/mkiv/l-file.lua | 38 +- tex/context/base/mkiv/l-lpeg.lua | 31 +- tex/context/base/mkiv/l-os.lua | 35 +- tex/context/base/mkiv/l-table.lua | 16 +- tex/context/base/mkiv/lang-ini.mkiv | 7 +- tex/context/base/mkiv/lang-lab.mkiv | 12 +- tex/context/base/mkiv/lpdf-ano.lua | 84 +- tex/context/base/mkiv/lpdf-tag.lua | 8 +- tex/context/base/mkiv/luat-cod.lua | 15 + tex/context/base/mkiv/lxml-css.lua | 135 +- tex/context/base/mkiv/lxml-lpt.lua | 4 +- tex/context/base/mkiv/lxml-tex.lua | 6 +- tex/context/base/mkiv/math-ext.lua | 25 +- tex/context/base/mkiv/math-fbk.lua | 161 +- tex/context/base/mkiv/math-ini.mkiv | 39 +- tex/context/base/mkiv/math-noa.lua | 31 +- tex/context/base/mkiv/math-tag.lua | 3 +- tex/context/base/mkiv/math-vfu.lua | 266 +-- tex/context/base/mkiv/meta-blb.lua | 305 ++++ tex/context/base/mkiv/meta-blb.mkiv | 50 + tex/context/base/mkiv/meta-imp-txt.mkiv | 54 +- tex/context/base/mkiv/mlib-lua.lua | 61 +- tex/context/base/mkiv/mlib-pdf.lua | 3 +- tex/context/base/mkiv/mlib-pps.lua | 37 +- tex/context/base/mkiv/mult-low.lua | 4 +- tex/context/base/mkiv/mult-prm.lua | 2 + tex/context/base/mkiv/node-aux.lua | 12 +- tex/context/base/mkiv/node-met.lua | 22 +- tex/context/base/mkiv/node-nut.lua | 30 +- tex/context/base/mkiv/node-shp.lua | 3 +- tex/context/base/mkiv/node-tra.lua | 6 +- tex/context/base/mkiv/publ-ini.lua | 4 +- tex/context/base/mkiv/spac-ver.lua | 9 +- tex/context/base/mkiv/status-files.pdf | Bin 26044 -> 26098 bytes tex/context/base/mkiv/status-lua.pdf | Bin 255106 -> 256761 bytes tex/context/base/mkiv/strc-doc.mkiv | 10 + tex/context/base/mkiv/strc-mar.lua | 3 +- tex/context/base/mkiv/strc-num.mkiv | 8 +- tex/context/base/mkiv/strc-ref.lua | 36 +- tex/context/base/mkiv/strc-ref.mkvi | 422 ++--- tex/context/base/mkiv/supp-box.lua | 7 + tex/context/base/mkiv/supp-box.mkiv | 5 + tex/context/base/mkiv/syst-aux.mkiv | 57 +- tex/context/base/mkiv/syst-ini.mkiv | 394 +++-- tex/context/base/mkiv/trac-inf.lua | 21 +- tex/context/base/mkiv/trac-log.lua | 52 +- tex/context/base/mkiv/trac-vis.lua | 3 +- tex/context/base/mkiv/trac-vis.mkiv | 5 + tex/context/base/mkiv/util-lua.lua | 4 +- tex/context/base/mkiv/util-prs.lua | 25 +- tex/context/base/mkiv/util-sto.lua | 10 + tex/context/fonts/mkiv/type-imp-cambria.mkiv | 11 +- tex/context/fonts/mkiv/type-imp-dejavu.mkiv | 5 +- tex/context/fonts/mkiv/type-imp-latinmodern.mkiv | 4 +- tex/context/fonts/mkiv/type-imp-modernlatin.mkiv | 56 +- tex/context/fonts/mkiv/type-imp-texgyre.mkiv | 17 +- tex/context/interface/mkii/keys-nl.xml | 7 +- tex/context/interface/mkiv/context-en.xml | 80 + tex/context/interface/mkiv/i-context.pdf | Bin 846253 -> 847282 bytes tex/context/interface/mkiv/i-fonts.xml | 24 +- tex/context/interface/mkiv/i-readme.pdf | Bin 61030 -> 61034 bytes tex/context/interface/mkiv/i-visualizer.xml | 6 +- tex/context/interface/mkiv/i-xml.xml | 28 + tex/generic/context/luatex/luatex-basics-gen.lua | 171 +- tex/generic/context/luatex/luatex-core.lua | 66 +- tex/generic/context/luatex/luatex-fonts-ext.lua | 242 +-- tex/generic/context/luatex/luatex-fonts-lig.lua | 2 +- tex/generic/context/luatex/luatex-fonts-merged.lua | 1415 ++++++++++----- tex/generic/context/luatex/luatex-fonts.lua | 88 +- 118 files changed, 6378 insertions(+), 4354 deletions(-) delete mode 100644 tex/context/base/mkiv/font-ext.lua create mode 100644 tex/context/base/mkiv/font-imp-dimensions.lua create mode 100644 tex/context/base/mkiv/font-imp-effects.lua create mode 100644 tex/context/base/mkiv/font-imp-italics.lua create mode 100644 tex/context/base/mkiv/font-imp-ligatures.lua create mode 100644 tex/context/base/mkiv/font-imp-math.lua create mode 100644 tex/context/base/mkiv/font-imp-notused.lua create mode 100644 tex/context/base/mkiv/font-imp-properties.lua create mode 100644 tex/context/base/mkiv/font-imp-quality.lua create mode 100644 tex/context/base/mkiv/font-imp-reorder.lua create mode 100644 tex/context/base/mkiv/font-imp-tex.lua create mode 100644 tex/context/base/mkiv/font-imp-tracing.lua create mode 100644 tex/context/base/mkiv/font-imp-unicode.lua create mode 100644 tex/context/base/mkiv/font-prv.lua create mode 100644 tex/context/base/mkiv/font-vfc.lua create mode 100644 tex/context/base/mkiv/meta-blb.lua create mode 100644 tex/context/base/mkiv/meta-blb.mkiv (limited to 'tex') diff --git a/tex/context/base/mkii/cont-new.mkii b/tex/context/base/mkii/cont-new.mkii index d8599af1a..734fea0b7 100644 --- a/tex/context/base/mkii/cont-new.mkii +++ b/tex/context/base/mkii/cont-new.mkii @@ -11,7 +11,7 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\newcontextversion{2018.04.03 22:22} +\newcontextversion{2018.04.13 14:53} %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/mkii/context.mkii b/tex/context/base/mkii/context.mkii index 31663439f..22b2f44c9 100644 --- a/tex/context/base/mkii/context.mkii +++ b/tex/context/base/mkii/context.mkii @@ -20,7 +20,7 @@ %D your styles an modules. \edef\contextformat {\jobname} -\edef\contextversion{2018.04.03 22:22} +\edef\contextversion{2018.04.13 14:53} %D For those who want to use this: diff --git a/tex/context/base/mkii/mult-nl.mkii b/tex/context/base/mkii/mult-nl.mkii index ba7c5a42c..be6df5d07 100644 --- a/tex/context/base/mkii/mult-nl.mkii +++ b/tex/context/base/mkii/mult-nl.mkii @@ -185,6 +185,7 @@ \setinterfacevariable{extremestretch}{extremestretch} \setinterfacevariable{fact}{gegeven} \setinterfacevariable{february}{februari} +\setinterfacevariable{field}{veld} \setinterfacevariable{figure}{figuur} \setinterfacevariable{figures}{figuren} \setinterfacevariable{file}{file} @@ -794,7 +795,7 @@ \setinterfaceconstant{family}{soort} \setinterfaceconstant{features}{features} \setinterfaceconstant{fences}{fences} -\setinterfaceconstant{field}{field} +\setinterfaceconstant{field}{veld} \setinterfaceconstant{fieldbackgroundcolor}{veldachtergrondkleur} \setinterfaceconstant{fieldframecolor}{veldkaderkleur} \setinterfaceconstant{fieldlayer}{veldlaag} @@ -849,6 +850,7 @@ \setinterfaceconstant{headerstate}{hoofdstatus} \setinterfaceconstant{headlabel}{koplabel} \setinterfaceconstant{headnumber}{kopnummer} +\setinterfaceconstant{headseparator}{kopscheider} \setinterfaceconstant{headstyle}{kopletter} \setinterfaceconstant{height}{hoogte} \setinterfaceconstant{hfactor}{hfactor} @@ -1075,6 +1077,7 @@ \setinterfaceconstant{preview}{preview} \setinterfaceconstant{previous}{vorige} \setinterfaceconstant{previousnumber}{vorigenummer} +\setinterfaceconstant{print}{print} \setinterfaceconstant{printable}{printbaar} \setinterfaceconstant{process}{proces} \setinterfaceconstant{profile}{profile} @@ -1160,8 +1163,10 @@ \setinterfaceconstant{sidemethod}{zijmethode} \setinterfaceconstant{sidespaceafter}{zijnawit} \setinterfaceconstant{sidespacebefore}{zijvoorwit} +\setinterfaceconstant{sidespaceinbetween}{zijtussenwit} \setinterfaceconstant{sidethreshold}{sidethreshold} \setinterfaceconstant{sign}{teken} +\setinterfaceconstant{simplecommand}{simpelcommando} \setinterfaceconstant{size}{formaat} \setinterfaceconstant{slantedfeatures}{slantedfeatures} \setinterfaceconstant{slantedfont}{slantedfont} diff --git a/tex/context/base/mkiv/anch-bck.mkvi b/tex/context/base/mkiv/anch-bck.mkvi index 348ea0ad1..911b1bca2 100644 --- a/tex/context/base/mkiv/anch-bck.mkvi +++ b/tex/context/base/mkiv/anch-bck.mkvi @@ -474,13 +474,13 @@ \strc_floats_mark_as_free \plustwo \d_page_sides_leftskip - \d_strc_floats_margin + \d_page_sides_margin \d_page_sides_topskip \d_page_sides_bottomskip \or % rightside \strc_floats_mark_as_free \plusthree - \d_strc_floats_margin + \d_page_sides_margin \d_page_sides_rightskip \d_page_sides_topskip \d_page_sides_bottomskip diff --git a/tex/context/base/mkiv/back-exp.lua b/tex/context/base/mkiv/back-exp.lua index b18679fa2..26efe6aad 100644 --- a/tex/context/base/mkiv/back-exp.lua +++ b/tex/context/base/mkiv/back-exp.lua @@ -118,6 +118,7 @@ local tonut = nuts.tonut local getnext = nuts.getnext local getsubtype = nuts.getsubtype local getfont = nuts.getfont +local getchar = nuts.getchar local getdisc = nuts.getdisc local getcomponents = nuts.getcomponents local getlist = nuts.getlist @@ -167,7 +168,7 @@ local currentparagraph = nil local noftextblocks = 0 -local hyphencode = 0xAD +----- hyphencode = 0xAD local hyphen = utfchar(0xAD) -- todo: also emdash etc local tagsplitter = structurestags.patterns.splitter ----- colonsplitter = lpeg.splitat(":") @@ -2748,9 +2749,12 @@ end local function collectresults(head,list,pat,pap) -- is last used (we also have currentattribute) local p - for n in traverse_nodes(head) do - local c, id = isglyph(n) -- 14: image, 8: literal (mp) - if c then +-- for n in traverse_nodes(head) do +-- local c, id = isglyph(n) -- 14: image, 8: literal (mp) +-- if c then + for n, id in traverse_nodes(head) do + if id == glyph_code then + local c = getchar(n) local at = getattr(n,a_tagged) or pat if not at then -- we need to tag the pagebody stuff as being valid skippable @@ -2855,7 +2859,7 @@ local function collectresults(head,list,pat,pap) -- is last used (we also have c elseif id == disc_code then -- probably too late local pre, post, replace = getdisc(n) if keephyphens then - if pre and not getnext(pre) and isglyph(pre) == hyphencode then + if pre and not getnext(pre) and isglyph(pre) == 0xAD then -- hyphencode then nofcurrentcontent = nofcurrentcontent + 1 currentcontent[nofcurrentcontent] = hyphen end diff --git a/tex/context/base/mkiv/buff-ini.mkiv b/tex/context/base/mkiv/buff-ini.mkiv index 1a5ce4591..6baf752cd 100644 --- a/tex/context/base/mkiv/buff-ini.mkiv +++ b/tex/context/base/mkiv/buff-ini.mkiv @@ -274,28 +274,4 @@ \def\getbufferdata[#1]{\buff_get_stored_indeed{#1}} -%D This is a weird one, moved from cont-new. Do we really need it? If not -%D it will go away. - -\bgroup \permitcircumflexescape - -\obeylines % don't remove %'s ! - -\gdef\collapsedspace#1% - {\ifx#1^^M% - \expandafter\collapsedspace - \else - \space - \expandafter#1% - \fi} - -\unexpanded\gdef\collapsespaces - {\prependtoksonce\relax\to\everyeof% - \ignorelines% - \ignoretabs% - \let\obeyedspace\collapsedspace% - \obeyspaces} - -\egroup - \protect \endinput diff --git a/tex/context/base/mkiv/catc-ini.mkiv b/tex/context/base/mkiv/catc-ini.mkiv index 471e4d1c8..215ec14e1 100644 --- a/tex/context/base/mkiv/catc-ini.mkiv +++ b/tex/context/base/mkiv/catc-ini.mkiv @@ -23,58 +23,110 @@ %D \MKII\ file. There is some overlap in code with \MKII\ but we take that %D for granted. Also, in \MKIV\ less active characters are used. -\setnewconstant\escapecatcode 0 -\setnewconstant\begingroupcatcode 1 -\setnewconstant\endgroupcatcode 2 -\setnewconstant\mathshiftcatcode 3 -\setnewconstant\alignmentcatcode 4 -\setnewconstant\endoflinecatcode 5 -\setnewconstant\parametercatcode 6 -\setnewconstant\superscriptcatcode 7 -\setnewconstant\subscriptcatcode 8 -\setnewconstant\ignorecatcode 9 -\setnewconstant\spacecatcode 10 -\setnewconstant\lettercatcode 11 -\setnewconstant\othercatcode 12 % finally obsolete: \let\other \othercatcode -\setnewconstant\activecatcode 13 % finally obsolete: \let\active\activecatcode -\setnewconstant\commentcatcode 14 -\setnewconstant\invalidcatcode 15 - -\setnewconstant\tabasciicode 9 -\setnewconstant\newlineasciicode 10 % don't confuse this one with \endoflineasciicode -\setnewconstant\formfeedasciicode 12 -\setnewconstant\endoflineasciicode 13 % somewhat messy but this can be the active \par -\setnewconstant\endoffileasciicode 26 -\setnewconstant\spaceasciicode 32 -\setnewconstant\exclamationmarkasciicode 33 % ! used in namespace protection -\setnewconstant\doublequoteasciicode 34 % " -\setnewconstant\hashasciicode 35 -\setnewconstant\dollarasciicode 36 -\setnewconstant\commentasciicode 37 -\setnewconstant\ampersandasciicode 38 -\setnewconstant\singlequoteasciicode 39 % ' -\setnewconstant\primeasciicode 39 % ' -\setnewconstant\hyphenasciicode 45 -\setnewconstant\forwardslashasciicode 47 % / -\setnewconstant\colonasciicode 58 -\setnewconstant\lessthanasciicode 60 % < used as alternative verbatim { -\setnewconstant\morethanasciicode 62 % > used as alternative verbatim } -\setnewconstant\questionmarkasciicode 63 % ? used in namespace protection -\setnewconstant\atsignasciicode 64 % @ used in namespace protection -\setnewconstant\backslashasciicode 92 % `\\ -\setnewconstant\circumflexasciicode 94 -\setnewconstant\underscoreasciicode 95 -\setnewconstant\leftbraceasciicode 123 % `\{ -\setnewconstant\barasciicode 124 % `\| -\setnewconstant\rightbraceasciicode 125 % `\} -\setnewconstant\tildeasciicode 126 % `\~ -\setnewconstant\delasciicode 127 +% \normalprotected\def\setnewconstantfromchar#1% +% {\expandafter\ifdefined\expandafter#1\expandafter +% \let\expandafter#1\expandafter\undefined\expandafter\fi\expandafter +% \newcount\expandafter#1\expandafter#1\the#1\relax} +% +% \normalprotected\def\setnewconstantfromchar#1% +% {\begingroup +% \scratchcounter#1% +% \edef\!!stringa{\meaning#1}% +% \chardef#1\scratchcounter +% \edef\!!stringb{\meaning#1}% +% \normalexpanded{\endgroup +% \ifx\!!stringa\!!stringb +% \let#1\noexpand\undefined +% \newcount#1% +% \fi +% #1\the\scratchcounter\relax}} +% +% \normalprotected\def\setnewconstantfromchar#1% +% {\begingroup +% \edef\!!stringa{\meaning#1}% +% \expandafter\chardef\expandafter#1\the#1% +% \edef\!!stringb{\meaning#1}% +% \normalexpanded{\endgroup +% \ifx\!!stringa\!!stringb +% \let#1\noexpand\undefined +% \newcount#1% +% \fi +% #1\the#1\relax}} +% +% \normalprotected\def\setnewconstantfromchar#1% +% {\scratchcounter#1\let#1\undefined\newcount#1#1\scratchcounter} + +\def\promote#1{\scratchcounter#1\let#1\undefined\newcount#1#1\scratchcounter} + +\promote\escapecatcode +\promote\begingroupcatcode +\promote\endgroupcatcode +\promote\mathshiftcatcode +\promote\alignmentcatcode +\promote\endoflinecatcode +\promote\parametercatcode +\promote\superscriptcatcode +\promote\subscriptcatcode +\promote\ignorecatcode +\promote\spacecatcode +\promote\lettercatcode +\promote\othercatcode +\promote\activecatcode +\promote\commentcatcode +\promote\invalidcatcode + +\promote\tabasciicode +\promote\newlineasciicode +\promote\formfeedasciicode +\promote\endoflineasciicode +\promote\endoffileasciicode +\promote\spaceasciicode +\promote\exclamationmarkasciicode +\promote\doublequoteasciicode +\promote\hashasciicode +\promote\dollarasciicode +\promote\commentasciicode +\promote\ampersandasciicode +\promote\singlequoteasciicode +\promote\primeasciicode +\promote\hyphenasciicode +\promote\forwardslashasciicode +\promote\colonasciicode +\promote\lessthanasciicode +\promote\morethanasciicode +\promote\questionmarkasciicode +\promote\atsignasciicode +\promote\backslashasciicode +\promote\circumflexasciicode +\promote\underscoreasciicode +\promote\leftbraceasciicode +\promote\barasciicode +\promote\rightbraceasciicode +\promote\tildeasciicode +\promote\delasciicode + +\let\promote\undefined + +% \begingroup +% +% \catcode\tabasciicode \activecatcode +% \catcode\formfeedasciicode \activecatcode +% \catcode\endoflineasciicode\activecatcode +% +% \letcharcode\tabasciicode \relax +% \letcharcode\newlineasciicode \relax +% \letcharcode\formfeedasciicode \relax +% \letcharcode\endoflineasciicode\relax +% +% \xdef\activetabtoken {\Uchar\tabasciicode } % \gdef\activetabtoken {^^I} +% \xdef\outputnewlinechar {\Uchar\newlineasciicode } % \gdef\outputnewlinechar {^^J} +% \xdef\activeformfeedtoken {\Uchar\formfeedasciicode } % \gdef\activeformfeedtoken {^^L} +% \xdef\activeendoflinetoken{\Uchar\endoflineasciicode} % \gdef\activeendoflinetoken{^^M} +% +% \endgroup \begingroup - \catcode \tabasciicode \activecatcode \gdef\activetabtoken {^^I} - \gdef\outputnewlinechar {^^J} - \catcode \formfeedasciicode \activecatcode \gdef\activeformfeedtoken {^^L} - \catcode \endoflineasciicode \activecatcode \gdef\activeendoflinetoken{^^M} + \letcharcode\newlineasciicode\relax \xdef\outputnewlinechar{\Uchar\newlineasciicode} \endgroup % \endlinechar = \endoflineasciicode % appended to input lines @@ -82,10 +134,17 @@ % rather special and used in writing to file: \let\par\outputnewlinechar +% \normalprotected\def\initializenewlinechar % operating system dependent +% {\begingroup +% \newlinechar\newlineasciicode +% \xdef\outputnewlinechar{^^J}% +% \endgroup} + \normalprotected\def\initializenewlinechar % operating system dependent {\begingroup + \letcharcode\newlineasciicode\relax \newlinechar\newlineasciicode - \xdef\outputnewlinechar{^^J}% + \xdef\outputnewlinechar{\Uchar\newlineasciicode}% \endgroup} %D We predefine some prefixes ahead of syst-aux and mult-sys. diff --git a/tex/context/base/mkiv/char-act.mkiv b/tex/context/base/mkiv/char-act.mkiv index 7d7268c8b..6b2ca51e2 100644 --- a/tex/context/base/mkiv/char-act.mkiv +++ b/tex/context/base/mkiv/char-act.mkiv @@ -44,11 +44,14 @@ \unexpanded\def\controlspace{\hbox{\asciispacechar}} % rather tex, we need the unicode value \unexpanded\def\normalspaces{\catcode\spaceasciicode\spacecatcode} -\bgroup - \catcode\spaceasciicode\activecatcode - \unexpanded\gdef\obeyspaces{\catcode\spaceasciicode\activecatcode\def {\obeyedspace}} - \unexpanded\gdef\setcontrolspaces{\catcode\spaceasciicode\activecatcode\def {\controlspace}} -\egroup +% \bgroup +% \catcode\spaceasciicode\activecatcode +% \unexpanded\gdef\obeyspaces {\catcode\spaceasciicode\activecatcode\def {\obeyedspace }} +% \unexpanded\gdef\setcontrolspaces{\catcode\spaceasciicode\activecatcode\def {\controlspace}} +% \egroup + +\unexpanded\def\obeyspaces {\catcode\spaceasciicode\activecatcode\letcharcode\spaceasciicode\obeyedspace } +\unexpanded\def\setcontrolspaces{\catcode\spaceasciicode\activecatcode\letcharcode\spaceasciicode\controlspace} %D \macros %D {obeytabs, obeylines, obeypages,ignoretabs, ignorelines, ignorepages} @@ -59,17 +62,28 @@ %D \NEWPAGE\ character locally, we redefine the meaning of %D this (often already) active character. -\expandafter\def\activeformfeedtoken{\par} +% \expandafter\def\activeformfeedtoken{\par} + +\letcharcode\formfeedasciicode\par %D The following indirect definitions enable us to implement %D all kind of \type{\obeyed} handlers. -\unexpanded\def\obeytabs {\catcode\tabasciicode \activecatcode\expandafter\def\activetabtoken {\obeyedtab }} -\unexpanded\def\obeylines {\catcode\endoflineasciicode\activecatcode\expandafter\def\activeendoflinetoken{\obeyedline}} -\unexpanded\def\obeypages {\catcode\formfeedasciicode \activecatcode\expandafter\def\activeformfeedtoken {\obeyedpage}} +% \unexpanded\def\obeytabs {\catcode\tabasciicode \activecatcode\expandafter\def\activetabtoken {\obeyedtab }} +% \unexpanded\def\obeylines {\catcode\endoflineasciicode\activecatcode\expandafter\def\activeendoflinetoken{\obeyedline}} +% \unexpanded\def\obeypages {\catcode\formfeedasciicode \activecatcode\expandafter\def\activeformfeedtoken {\obeyedpage}} + +% \unexpanded\def\ignoretabs {\catcode\tabasciicode \activecatcode\expandafter\def\activetabtoken {\obeyedspace}} +% \unexpanded\def\ignorelines{\catcode\endoflineasciicode\activecatcode\expandafter\def\activeendoflinetoken{\obeyedspace}} +% \unexpanded\def\ignorepages{\catcode\formfeedasciicode \ignorecatcode} +% \unexpanded\def\ignoreeofs {\catcode\endoffileasciicode\ignorecatcode} + +\unexpanded\def\obeytabs {\catcode\tabasciicode \activecatcode\letcharcode\tabasciicode \obeyedtab } +\unexpanded\def\obeylines {\catcode\endoflineasciicode\activecatcode\letcharcode\endoflineasciicode\obeyedline} +\unexpanded\def\obeypages {\catcode\formfeedasciicode \activecatcode\letcharcode\formfeedasciicode \obeyedpage} -\unexpanded\def\ignoretabs {\catcode\tabasciicode \activecatcode\expandafter\def\activetabtoken {\obeyedspace}} -\unexpanded\def\ignorelines{\catcode\endoflineasciicode\activecatcode\expandafter\def\activeendoflinetoken{\obeyedspace}} +\unexpanded\def\ignoretabs {\catcode\tabasciicode \activecatcode\letcharcode\tabasciicode \obeyedspace} +\unexpanded\def\ignorelines{\catcode\endoflineasciicode\activecatcode\letcharcode\endoflineasciicode\obeyedspace} \unexpanded\def\ignorepages{\catcode\formfeedasciicode \ignorecatcode} \unexpanded\def\ignoreeofs {\catcode\endoffileasciicode\ignorecatcode} diff --git a/tex/context/base/mkiv/cldf-ini.lua b/tex/context/base/mkiv/cldf-ini.lua index 8cd6408d3..86dec0209 100644 --- a/tex/context/base/mkiv/cldf-ini.lua +++ b/tex/context/base/mkiv/cldf-ini.lua @@ -690,7 +690,7 @@ local function writer(parent,command,...) -- already optimized before call -- for i=1,#t do -- local ti = t[i] for i=1,select("#",...) do - local ti = (select(i,...)) + local ti = select(i,...) if direct then local typ = type(ti) if typ == "string" or typ == "number" then @@ -798,7 +798,7 @@ end -- local function prtwriter(command,...) -- already optimized before call -- flush(prtcatcodes,command) -- for i=1,select("#",...) do --- local ti = (select(i,...)) +-- local ti = select(i,...) -- if ti == nil then -- -- nothing -- elseif ti == "" then @@ -1179,7 +1179,7 @@ do -- snippets for i=1,select("#",...) do nofcollected = nofcollected + 1 - collected[nofcollected] = (select(i,...)) + collected[nofcollected] = select(i,...) end end @@ -1187,7 +1187,7 @@ do -- -- lines -- for i=1,select("#",...) do -- n = n + 1 - -- t[n] = (select(i,...)) + -- t[n] = select(i,...) -- n = n + 1 -- t[n] = "\r" -- end diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv index acb618a43..61c9a1493 100644 --- a/tex/context/base/mkiv/cont-new.mkiv +++ b/tex/context/base/mkiv/cont-new.mkiv @@ -11,7 +11,7 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\newcontextversion{2018.04.03 22:22} +\newcontextversion{2018.04.13 14:53} %D This file is loaded at runtime, thereby providing an excellent place for %D hacks, patches, extensions and new features. diff --git a/tex/context/base/mkiv/context.mkiv b/tex/context/base/mkiv/context.mkiv index 7795c5a17..00fd83ea8 100644 --- a/tex/context/base/mkiv/context.mkiv +++ b/tex/context/base/mkiv/context.mkiv @@ -42,7 +42,7 @@ %D has to match \type {YYYY.MM.DD HH:MM} format. \edef\contextformat {\jobname} -\edef\contextversion{2018.04.03 22:22} +\edef\contextversion{2018.04.13 14:53} \edef\contextkind {beta} %D For those who want to use this: @@ -568,8 +568,10 @@ \loadmarkfile{mlib-pdf} \loadmarkfile{mlib-pps} \loadmarkfile{meta-pdf} +\loadmarkfile{meta-blb} \loadmarkfile{grph-epd} + \loadmarkfile{cont-run} % the main runner (used in cont-yes.mkiv) \setupcurrentlanguage[\defaultlanguagetag] diff --git a/tex/context/base/mkiv/font-cft.lua b/tex/context/base/mkiv/font-cft.lua index 83227ca4a..2e1610f17 100644 --- a/tex/context/base/mkiv/font-cft.lua +++ b/tex/context/base/mkiv/font-cft.lua @@ -248,6 +248,16 @@ do mathitalics = t_boolean, textitalics = t_boolean, finalized = t_boolean, + effect = { + effect = t_cardinal, + width = t_float, + factor = t_float, + hfactor = t_float, + vfactor = t_float, + wdelta = t_float, + hdelta = t_float, + ddelta = t_float, + } }, parameters = { mathsize = t_cardinal, diff --git a/tex/context/base/mkiv/font-chk.lua b/tex/context/base/mkiv/font-chk.lua index 3613432c1..4e7bf939b 100644 --- a/tex/context/base/mkiv/font-chk.lua +++ b/tex/context/base/mkiv/font-chk.lua @@ -196,7 +196,10 @@ local variants = allocate { { tag = "yellow", r = .6, g = .6, b = 0 }, } -local pdf_blob = "pdf: q %.6F 0 0 %.6F 0 0 cm %s %s %s rg %s %s %s RG 10 M 1 j 1 J 0.05 w %s Q" +-- bah .. low level pdf ... should be a rule or plugged in + +----- pdf_blob = "pdf: q %.6F 0 0 %.6F 0 0 cm %s %s %s rg %s %s %s RG 10 M 1 j 1 J 0.05 w %s Q" +local pdf_blob = "q %.6F 0 0 %.6F 0 0 cm %s %s %s rg %s %s %s RG 10 M 1 j 1 J 0.05 w %s Q" local cache = { } -- saves some tables but not that impressive @@ -235,8 +238,8 @@ local function addmissingsymbols(tfmdata) -- we can have an alternative with rul width = size*fake.width, height = size*fake.height, depth = size*fake.depth, - -- bah .. low level pdf ... should be a rule or plugged in - commands = { { "special", formatters[pdf_blob](scale,scale,r,g,b,r,g,b,fake.code) } } + -- commands = { { "special", formatters[pdf_blob](scale,scale,r,g,b,r,g,b,fake.code) } } + commands = { { "pdf", formatters[pdf_blob](scale,scale,r,g,b,r,g,b,fake.code) } } } cache[hash] = char end @@ -390,7 +393,6 @@ checkers.getmissing = getmissing do local reported = true - local tracked = false callback.register("glyph_not_found",function(font,char) if font > 0 then @@ -408,7 +410,6 @@ do trackers.register("fonts.missing", function(v) if v then enableaction("processors","fonts.checkers.missing") - tracked = true else disableaction("processors","fonts.checkers.missing") end @@ -419,27 +420,25 @@ do end) logs.registerfinalactions(function() --- if tracked then - local collected, details = getmissing() - if next(collected) then + local collected, details = getmissing() + if next(collected) then + for filename, list in sortedhash(details) do + logs.startfilelogging(report,"missing characters",filename) + for u, v in sortedhash(list) do + report("%4i %U %c %s",v,u,u,chardata[u].description) + end + logs.stopfilelogging() + end + if logs.loggingerrors() then for filename, list in sortedhash(details) do - logs.startfilelogging(report,"missing characters",filename) + logs.starterrorlogging(report,"missing characters",filename) for u, v in sortedhash(list) do report("%4i %U %c %s",v,u,u,chardata[u].description) end - logs.stopfilelogging() - end - if logs.loggingerrors() then - for filename, list in sortedhash(details) do - logs.starterrorlogging(report,"missing characters",filename) - for u, v in sortedhash(list) do - report("%4i %U %c %s",v,u,u,chardata[u].description) - end - logs.stoperrorlogging() - end + logs.stoperrorlogging() end end --- end + end end) end diff --git a/tex/context/base/mkiv/font-col.lua b/tex/context/base/mkiv/font-col.lua index 7bbaf31cb..8aad4d7d5 100644 --- a/tex/context/base/mkiv/font-col.lua +++ b/tex/context/base/mkiv/font-col.lua @@ -47,22 +47,22 @@ collections.definitions = definitions local vectors = collections.vectors or { } collections.vectors = vectors -local fonthashes = fonts.hashes -local fonthelpers = fonts.helpers - -local fontdata = fonthashes.identifiers -local fontquads = fonthashes.quads -local chardata = fonthashes.characters -local propdata = fonthashes.properties - -local addprivate = fonthelpers.addprivate -local hasprivate = fonthelpers.hasprivate +local helpers = fonts.helpers +local charcommand = helpers.commands.char +local rightcommand = helpers.commands.right +local addprivate = helpers.addprivate +local hasprivate = helpers.hasprivate +local fontpatternhassize = helpers.fontpatternhassize + +local hashes = fonts.hashes +local fontdata = hashes.identifiers +local fontquads = hashes.quads +local chardata = hashes.characters +local propdata = hashes.properties local currentfont = font.current local addcharacters = font.addcharacters -local fontpatternhassize = fonts.helpers.fontpatternhassize - local implement = interfaces.implement local list = { } @@ -284,13 +284,16 @@ local function monoslot(font,char,parent,factor) local width = factor * fontquads[parent] local character = characters[char] if character then + -- runtime patching of the font (can only be new characters) + -- instead of messing with existing dimensions local data = { + -- no features so a simple copy width = width, height = character.height, depth = character.depth, commands = { - { "right", (width - character.width or 0)/2 }, - { "slot", 0, char } + rightcommand[(width - character.width or 0)/2], + charcommand[char], } } local u = addprivate(tfmdata, privatename, data) diff --git a/tex/context/base/mkiv/font-con.lua b/tex/context/base/mkiv/font-con.lua index add646da1..73e9ffe22 100644 --- a/tex/context/base/mkiv/font-con.lua +++ b/tex/context/base/mkiv/font-con.lua @@ -98,6 +98,24 @@ function constructors.getprivate(tfmdata) return private end +function constructors.setmathparameter(tfmdata,name,value) + local m = tfmdata.mathparameters + local c = tfmdata.MathConstants + if m then + m[name] = value + end + if c and c ~= m then + c[name] = value + end +end + +function constructors.getmathparameter(tfmdata,name) + local p = tfmdata.mathparameters or tfmdata.MathConstants + if p then + return p[name] + end +end + --[[ldx--

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 @@ -477,20 +495,28 @@ function constructors.scale(tfmdata,specification) target.shrink = expansion.shrink target.step = expansion.step end + -- slanting + local slantfactor = parameters.slantfactor or 0 + if slantfactor ~= 0 then + target.slant = slantfactor * 1000 + else + target.slant = 0 + end -- widening local extendfactor = parameters.extendfactor or 0 if extendfactor ~= 0 and extendfactor ~= 1 then hdelta = hdelta * extendfactor - target.extend = extendfactor * 1000 -- extent ? + target.extend = extendfactor * 1000 else target.extend = 1000 -- extent ? end - -- slanting - local slantfactor = parameters.slantfactor or 0 - if slantfactor ~= 0 then - target.slant = slantfactor * 1000 + -- squeezing + local squeezefactor = parameters.squeezefactor or 0 + if squeezefactor ~= 0 and squeezefactor ~= 1 then + vdelta = vdelta * squeezefactor + target.squeeze = squeezefactor * 1000 else - target.slant = 0 + target.squeeze = 1000 -- extent ? end -- effects local mode = parameters.mode or 0 @@ -499,7 +525,7 @@ function constructors.scale(tfmdata,specification) end local width = parameters.width or 0 if width ~= 0 then - target.width = width + target.width = width * delta * 1000 / 655360 end -- targetparameters.factor = delta @@ -947,12 +973,16 @@ function constructors.finalize(tfmdata) parameters.width = 0 end -- + if not parameters.slantfactor then + parameters.slantfactor = tfmdata.slant or 0 + end + -- if not parameters.extendfactor then parameters.extendfactor = tfmdata.extend or 0 end -- - if not parameters.slantfactor then - parameters.slantfactor = tfmdata.slant or 0 + if not parameters.squeezefactor then + parameters.squeezefactor = tfmdata.squeeze or 0 end -- local designsize = parameters.designsize @@ -1043,8 +1073,9 @@ function constructors.finalize(tfmdata) tfmdata.stretch = nil tfmdata.shrink = nil tfmdata.step = nil - tfmdata.extend = nil tfmdata.slant = nil + tfmdata.extend = nil + tfmdata.squeeze = nil tfmdata.mode = nil tfmdata.width = nil tfmdata.units = nil @@ -1097,7 +1128,18 @@ hashmethods.normal = function(list) -- no need to add to hash (maybe we need a skip list) else n = n + 1 - s[n] = k .. '=' .. tostring(v) + if type(v) == "table" then + -- table.sequenced + local t = { } + local m = 0 + for k, v in next, v do + m = m + 1 + t[m] = k .. '=' .. tostring(v) + end + s[n] = k .. '={' .. concat(t,",") .. "}" + else + s[n] = k .. '=' .. tostring(v) + end end end if n > 0 then diff --git a/tex/context/base/mkiv/font-ctx.lua b/tex/context/base/mkiv/font-ctx.lua index 87885f64f..68191143b 100644 --- a/tex/context/base/mkiv/font-ctx.lua +++ b/tex/context/base/mkiv/font-ctx.lua @@ -12,21 +12,23 @@ if not modules then modules = { } end modules ['font-ctx'] = { -- Todo: make a proper 'next id' mechanism (register etc) or wait till 'true' -- in virtual fonts indices is implemented. -local context, commands = context, commands +local tostring, next, type, rawget, tonumber = tostring, next, type, rawget, tonumber local format, gmatch, match, find, lower, upper, gsub, byte, topattern = string.format, string.gmatch, string.match, string.find, string.lower, string.upper, string.gsub, string.byte, string.topattern local concat, serialize, sort, fastcopy, mergedtable = table.concat, table.serialize, table.sort, table.fastcopy, table.merged local sortedhash, sortedkeys, sequenced = table.sortedhash, table.sortedkeys, table.sequenced -local settings_to_hash, hash_to_string, settings_to_array = utilities.parsers.settings_to_hash, utilities.parsers.hash_to_string, utilities.parsers.settings_to_array +local parsers = utilities.parsers +local settings_to_hash, settings_to_hash_colon_too, hash_to_string, settings_to_array = parsers.settings_to_hash, parsers.settings_to_hash_colon_too, parsers.hash_to_string, parsers.settings_to_array local formatcolumns = utilities.formatters.formatcolumns local mergehashes = utilities.parsers.mergehashes local formatters = string.formatters local basename = file.basename -local tostring, next, type, rawget, tonumber = tostring, next, type, rawget, tonumber local utfchar, utfbyte = utf.char, utf.byte local round = math.round +local context, commands = context, commands + 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_features = false trackers.register("fonts.features", function(v) trace_features = v end) @@ -66,6 +68,8 @@ local hashes = fonts.hashes local currentfont = font.current local definefont = font.define +local getprivateslot = helpers.getprivateslot + local cleanname = names.cleanname local encodings = fonts.encodings @@ -472,36 +476,40 @@ registerotffeature { -- }, -- } -local beforecopyingcharacters = sequencers.new { - name = "beforecopyingcharacters", - arguments = "target,original", -} +do + + local beforecopyingcharacters = sequencers.new { + name = "beforecopyingcharacters", + arguments = "target,original", + } -appendgroup(beforecopyingcharacters,"before") -- user -appendgroup(beforecopyingcharacters,"system") -- private -appendgroup(beforecopyingcharacters,"after" ) -- user + appendgroup(beforecopyingcharacters,"before") -- user + appendgroup(beforecopyingcharacters,"system") -- private + appendgroup(beforecopyingcharacters,"after" ) -- user -function constructors.beforecopyingcharacters(original,target) - local runner = beforecopyingcharacters.runner - if runner then - runner(original,target) + function constructors.beforecopyingcharacters(original,target) + local runner = beforecopyingcharacters.runner + if runner then + runner(original,target) + end end -end -local aftercopyingcharacters = sequencers.new { - name = "aftercopyingcharacters", - arguments = "target,original", -} + local aftercopyingcharacters = sequencers.new { + name = "aftercopyingcharacters", + arguments = "target,original", + } -appendgroup(aftercopyingcharacters,"before") -- user -appendgroup(aftercopyingcharacters,"system") -- private -appendgroup(aftercopyingcharacters,"after" ) -- user + appendgroup(aftercopyingcharacters,"before") -- user + appendgroup(aftercopyingcharacters,"system") -- private + appendgroup(aftercopyingcharacters,"after" ) -- user -function constructors.aftercopyingcharacters(original,target) - local runner = aftercopyingcharacters.runner - if runner then - runner(original,target) + function constructors.aftercopyingcharacters(original,target) + local runner = aftercopyingcharacters.runner + if runner then + runner(original,target) + end end + end --[[ldx-- @@ -575,6 +583,15 @@ local function presetcontext(name,parent,features) -- will go to con and shared features = { } elseif type(features) == "string" then features = normalize_features(settings_to_hash(features)) + for key, value in next, features do + if type(value) == "string" and find(value,"=") then + local t = settings_to_hash(value) + if next(t) then +-- features[key] = sequenced(normalize_features(t),",") + features[key] = t -- sequenced(normalize_features(t),",") + end + end + end else features = normalize_features(features) end @@ -584,8 +601,8 @@ local function presetcontext(name,parent,features) -- will go to con and shared local s = setups[p] if s then for k, v in next, s do --- no, as then we cannot overload: e.g. math,mathextra --- reverted, so we only take from parent when not set + -- no, as then we cannot overload: e.g. math,mathextra + -- reverted, so we only take from parent when not set if features[k] == nil then features[k] = v end @@ -1299,7 +1316,6 @@ do -- else too many locals local busy = false scanners.definefont_two = function() - local global = scanboolean() -- \ifx\fontclass\empty\s!false\else\s!true\fi local cs = scanstring () -- {#csname}% local str = scanstring () -- \somefontfile @@ -1411,6 +1427,7 @@ do -- else too many locals specification.fallbacks = fontfallbacks end end + -- local tfmdata = definers.read(specification,size) -- id not yet known (size in spec?) -- local lastfontid = 0 @@ -2397,9 +2414,12 @@ do return f and (f.gpos[n] or f.gsub[n]) end + local ctx_doifelse = commands.doifelse + local ctx_doif = commands.doif + implement { name = "doifelsecurrentfonthasfeature", - actions = { constructors.currentfonthasfeature, commands.doifelse }, + actions = { constructors.currentfonthasfeature, ctx_doifelse }, arguments = "string" } @@ -2443,9 +2463,22 @@ do implement { name = "definefontfeature", arguments = "3 strings", - actions = presetcontext + actions = presetcontext, + } + + implement { + name = "doifelsefontfeature", + arguments = "string", + actions = function(name) ctx_doifelse(contextnumber(name) > 1) end, } + implement { + name = "doifunknownfontfeature", + arguments = "string", + actions = function(name) ctx_doif(contextnumber(name) == 0) end, + } + + implement { name = "adaptfontfeature", arguments = "2 strings", @@ -2708,9 +2741,13 @@ implement { arguments = "string", } -local list = storage.shared.bodyfontsizes or { } +local sharedstorage = storage.shared + +local list = sharedstorage.bodyfontsizes or { } +local unknown = sharedstorage.unknownbodyfontsizes or { } -storage.shared.bodyfontsizes = list +sharedstorage.bodyfontsizes = list +sharedstorage.unknownbodyfontsizes = unknown implement { name = "registerbodyfontsize", @@ -2720,6 +2757,17 @@ implement { end } +interfaces.implement { + name = "registerunknownbodysize", + arguments = "string", + actions = function(size) + if not unknown[size] then + interfaces.showmessage("fonts",14,size) + end + unknown[size] = true + end, +} + implement { name = "getbodyfontsizes", arguments = "string", @@ -2873,6 +2921,12 @@ end -- for the font manual +statistics.register("body font sizes", function() + if next(unknown) then + return formatters["defined: % t, undefined: % t"](sortedkeys(list),sortedkeys(unknown)) + end +end) + statistics.register("used fonts",function() if trace_usage then local filename = file.nameonly(environment.jobname) .. "-fonts-usage.lua" @@ -3018,79 +3072,178 @@ end -- for the moment here (and not in font-con.lua): -local identical = table.identical -local copy = table.copy -local fontdata = fonts.hashes.identifiers -local addcharacters = font.addcharacters - --- This helper is mostly meant to add last-resort (virtual) characters --- or runtime generated fonts (so we forget about features and such). It --- will probably take a while before it get used. - -local trace_adding = false -local report_adding = logs.reporter("fonts","add characters") - -trackers.register("fonts.addcharacters",function(v) trace_adding = v end) - -if addcharacters then - - function fonts.constructors.addcharacters(id,list) - local newchar = list.characters - if newchar then - local data = fontdata[id] - local newfont = list.fonts - local oldchar = data.characters - local oldfont = data.fonts - addcharacters(id, { - characters = newchar, - fonts = newfont, - nomath = not data.properties.hasmath, - }) - -- this is just for tracing, as the assignment only uses the fonts list - -- and doesn't store it otherwise - if newfont then - if oldfont then - local oldn = #oldfont - local newn = #newfont - for n=1,newn do - local ok = false - local nf = newfont[n] - for o=1,oldn do - if identical(nf,oldfont[o]) then - ok = true - break +do + + local identical = table.identical + local copy = table.copy + local fontdata = fonts.hashes.identifiers + local addcharacters = font.addcharacters + + -- This helper is mostly meant to add last-resort (virtual) characters + -- or runtime generated fonts (so we forget about features and such). It + -- will probably take a while before it get used. + + local trace_adding = false + local report_adding = logs.reporter("fonts","add characters") + + trackers.register("fonts.addcharacters",function(v) trace_adding = v end) + + if addcharacters then + + function fonts.constructors.addcharacters(id,list) + local newchar = list.characters + if newchar then + local data = fontdata[id] + local newfont = list.fonts + local oldchar = data.characters + local oldfont = data.fonts + addcharacters(id, { + characters = newchar, + fonts = newfont, + nomath = not data.properties.hasmath, + }) + -- this is just for tracing, as the assignment only uses the fonts list + -- and doesn't store it otherwise + if newfont then + if oldfont then + local oldn = #oldfont + local newn = #newfont + for n=1,newn do + local ok = false + local nf = newfont[n] + for o=1,oldn do + if identical(nf,oldfont[o]) then + ok = true + break + end + end + if not ok then + oldn = oldn + 1 + oldfont[oldn] = newfont[i] end end - if not ok then - oldn = oldn + 1 - oldfont[oldn] = newfont[i] - end + else + data.fonts = newfont end - else - data.fonts = newfont end - end - -- this is because we need to know what goes on and also might - -- want to access character data - for u, c in next, newchar do - if trace_adding then - report_adding("adding character %U to font %!font:name!",u,id) + -- this is because we need to know what goes on and also might + -- want to access character data + for u, c in next, newchar do + if trace_adding then + report_adding("adding character %U to font %!font:name!",u,id) + end + oldchar[u] = c end - oldchar[u] = c end end - end -else - function fonts.constructors.addcharacters(id,list) - report_adding("adding characters to %!font:name! is not yet supported",id) + else + function fonts.constructors.addcharacters(id,list) + report_adding("adding characters to %!font:name! is not yet supported",id) + end end + + implement { + name = "addfontpath", + arguments = "string", + actions = function(list) + names.addruntimepath(settings_to_array(list)) + end + } + end -implement { - name = "addfontpath", - arguments = "string", - actions = function(list) - names.addruntimepath(settings_to_array(list)) +-- moved here + +do + + local family_font = node.family_font + local new_glyph = nodes.pool.glyph + local fontproperties = fonts.hashes.properties + + local function getprivateslot(id,name) + if not name then + name = id + id = currentfont() + end + local properties = fontproperties[id] + local privates = properties and properties.privates + return privates and privates[name] end -} + + local function getprivatenode(tfmdata,name) + if type(tfmdata) == "number" then + tfmdata = fontdata[tfmdata] + end + local properties = tfmdata.properties + local font = properties.id + local slot = getprivateslot(font,name) + if slot then + -- todo: set current attribibutes + local char = tfmdata.characters[slot] + local tonode = char.tonode + if tonode then + return tonode(font,char) + else + return new_glyph(font,slot) + end + end + end + + local function getprivatecharornode(tfmdata,name) + if type(tfmdata) == "number" then + tfmdata = fontdata[tfmdata] + end + local properties = tfmdata.properties + local font = properties.id + local slot = getprivateslot(font,name) + if slot then + -- todo: set current attributes + local char = tfmdata.characters[slot] + local tonode = char.tonode + if tonode then + return "node", tonode(tfmdata,char) + else + return "char", slot + end + end + end + + helpers.getprivateslot = getprivateslot + helpers.getprivatenode = getprivatenode + helpers.getprivatecharornode = getprivatecharornode + + implement { + name = "getprivatechar", + arguments = "string", + actions = function(name) + local p = getprivateslot(name) + if p then + context(utfchar(p)) + end + end + } + + implement { + name = "getprivatemathchar", + arguments = "string", + actions = function(name) + local p = getprivateslot(family_font(0),name) + if p then + context(utfchar(p)) + end + end + } + + implement { + name = "getprivateslot", + arguments = "string", + actions = function(name) + local p = getprivateslot(name) + if p then + context(p) + end + end + } + +end diff --git a/tex/context/base/mkiv/font-def.lua b/tex/context/base/mkiv/font-def.lua index 97d25f180..732ce401f 100644 --- a/tex/context/base/mkiv/font-def.lua +++ b/tex/context/base/mkiv/font-def.lua @@ -377,6 +377,7 @@ function definers.loadfont(specification) -- todo: also hash by instance / factors local tfmdata = loadedfonts[hash] -- hashes by size ! if not tfmdata then + -- normally context will not end up here often (if so there is an issue somewhere) local forced = specification.forced or "" if forced ~= "" then local reader = readers[lower(forced)] -- normally forced is already lowered diff --git a/tex/context/base/mkiv/font-dsp.lua b/tex/context/base/mkiv/font-dsp.lua index 02e5a7df6..77b2b7ff0 100644 --- a/tex/context/base/mkiv/font-dsp.lua +++ b/tex/context/base/mkiv/font-dsp.lua @@ -68,7 +68,7 @@ local reversed = table.reversed local sort = table.sort local insert = table.insert local round = math.round -local lpegmatch = lpeg.match +local settings_to_hash_colon_too = table.settings_to_hash_colon_too local setmetatableindex = table.setmetatableindex local formatters = string.formatters @@ -300,30 +300,16 @@ end) -- wght:400,wdth:100,ital:1 --- local names = table.setmetatableindex ( { --- weight = "wght", --- width = "wdth", --- italic = "ital", --- }, "self") - --- todo: spaces in name but not before : - -local pattern = lpeg.Cf ( - lpeg.Ct("") * - lpeg.Cg ( - --(lpeg.R("az")^1/names) * lpeg.S(" :") * - lpeg.C((lpeg.R("az","09")+lpeg.P(" "))^1) * lpeg.S(" :=") * - (lpeg.patterns.number/tonumber) * lpeg.S(" ,")^0 - )^1, rawset -) +local function axistofactors(str) + local t = settings_to_hash_colon_too(str) + for k, v in next, t do + t[k] = tonumber(v) or v -- this also normalizes numbers itself + end + return t +end local hash = table.setmetatableindex(function(t,k) - local v = lpegmatch(pattern,k) - local t = { } - for k, v in sortedhash(v) do - t[#t+1] = k .. "=" .. v - end - v = concat(t,",") + local v = sequenced(axistofactors(k),",") t[k] = v return v end) @@ -341,7 +327,7 @@ function helpers.normalizedaxis(str) end local function axistofactors(str) - return lpegmatch(pattern,str) + return settings_to_hash_colon_too(str) end -- contradicting spec ... (signs) so i'll check it and fix it once we have diff --git a/tex/context/base/mkiv/font-enh.lua b/tex/context/base/mkiv/font-enh.lua index b1fcd9be8..9ec116d47 100644 --- a/tex/context/base/mkiv/font-enh.lua +++ b/tex/context/base/mkiv/font-enh.lua @@ -115,7 +115,7 @@ local registerotffeature = otffeatures.register ----- tosixteen = fonts.mappings.tounicode16 -local function initializeunicoding(tfmdata) +local function initialize(tfmdata) local goodies = tfmdata.goodies local newcoding = nil for i=1,#goodies do @@ -165,18 +165,14 @@ local function initializeunicoding(tfmdata) end end -local unicoding_specification = { +local specification = { name = "unicoding", description = "adapt unicode table", initializers = { - base = initializeunicoding, - node = initializeunicoding, + base = initialize, + node = initialize, }, - -- manipulators = { - -- base = finalizeunicoding, - -- node = finalizeunicoding, - -- } } -registerotffeature(unicoding_specification) -registerafmfeature(unicoding_specification) +registerotffeature(specification) +registerafmfeature(specification) diff --git a/tex/context/base/mkiv/font-ext.lua b/tex/context/base/mkiv/font-ext.lua deleted file mode 100644 index d873dccd4..000000000 --- a/tex/context/base/mkiv/font-ext.lua +++ /dev/null @@ -1,1856 +0,0 @@ -if not modules then modules = { } end modules ['font-ext'] = { - version = 1.001, - comment = "companion to font-ini.mkiv and hand-ini.mkiv", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - -local next, type, tonumber = next, type, tonumber -local byte, find, formatters = string.byte, string.find, string.formatters -local utfchar = utf.char -local sortedhash, sortedkeys, sort = table.sortedhash, table.sortedkeys, table.sort - -local context = context -local fonts = fonts -local utilities = utilities - -local trace_protrusion = false trackers.register("fonts.protrusion", function(v) trace_protrusion = v end) -local trace_expansion = false trackers.register("fonts.expansion", function(v) trace_expansion = v end) - -local report_expansions = logs.reporter("fonts","expansions") -local report_protrusions = logs.reporter("fonts","protrusions") - ---[[ldx-- -

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.

---ldx]]-- - -local handlers = fonts.handlers -local hashes = fonts.hashes -local otf = handlers.otf -local afm = handlers.afm - -local registerotffeature = otf.features.register -local registerafmfeature = afm.features.register - -local fontdata = hashes.identifiers -local fontproperties = hashes.properties - -local constructors = fonts.constructors -local getprivate = constructors.getprivate - -local allocate = utilities.storage.allocate -local settings_to_array = utilities.parsers.settings_to_array -local settings_to_hash = utilities.parsers.settings_to_hash -local getparameters = utilities.parsers.getparameters -local gettexdimen = tex.getdimen -local family_font = node.family_font - -local setmetatableindex = table.setmetatableindex - -local implement = interfaces.implement -local variables = interfaces.variables - - -local v_background = variables.background -local v_frame = variables.frame -local v_empty = variables.empty -local v_none = variables.none - --- -- -- -- -- -- --- shared --- -- -- -- -- -- - -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 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]) - if class then - local class_vector = class.vector - local g_vectors = g_where and g_where.vectors - local f_vectors = f_where and f_where.vectors - local vector = (g_vectors and g_vectors[class_vector]) or (f_vectors and f_vectors[class_vector]) - return class, vector - end -end - --- -- -- -- -- -- --- expansion (hz) --- -- -- -- -- -- - -local expansions = fonts.expansions or allocate() - -fonts.expansions = expansions - -local classes = expansions.classes or allocate() -local vectors = expansions.vectors or allocate() - -expansions.classes = classes -expansions.vectors = vectors - --- beware, pdftex itself uses percentages * 10 --- --- todo: get rid of byte() here - -classes.preset = { stretch = 2, shrink = 2, step = .5, factor = 1 } - -classes['quality'] = { - stretch = 2, shrink = 2, step = .5, vector = 'default', factor = 1 -} - -vectors['default'] = { - [byte('A')] = 0.5, [byte('B')] = 0.7, [byte('C')] = 0.7, [byte('D')] = 0.5, [byte('E')] = 0.7, - [byte('F')] = 0.7, [byte('G')] = 0.5, [byte('H')] = 0.7, [byte('K')] = 0.7, [byte('M')] = 0.7, - [byte('N')] = 0.7, [byte('O')] = 0.5, [byte('P')] = 0.7, [byte('Q')] = 0.5, [byte('R')] = 0.7, - [byte('S')] = 0.7, [byte('U')] = 0.7, [byte('W')] = 0.7, [byte('Z')] = 0.7, - [byte('a')] = 0.7, [byte('b')] = 0.7, [byte('c')] = 0.7, [byte('d')] = 0.7, [byte('e')] = 0.7, - [byte('g')] = 0.7, [byte('h')] = 0.7, [byte('k')] = 0.7, [byte('m')] = 0.7, [byte('n')] = 0.7, - [byte('o')] = 0.7, [byte('p')] = 0.7, [byte('q')] = 0.7, [byte('s')] = 0.7, [byte('u')] = 0.7, - [byte('w')] = 0.7, [byte('z')] = 0.7, - [byte('2')] = 0.7, [byte('3')] = 0.7, [byte('6')] = 0.7, [byte('8')] = 0.7, [byte('9')] = 0.7, -} - -vectors['quality'] = vectors['default'] -- metatable ? - -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 = 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 %a, vector %a, factor %a, stretch %a, shrink %a, step %a", - value,class.vector,factor,stretch,shrink,step) - end - tfmdata.parameters.expansion = { - stretch = 10 * stretch, - shrink = 10 * shrink, - step = 10 * step, - factor = factor, - } - local data = characters and characters.data - for i, chr in next, tfmdata.characters do - local v = vector[i] - if data and not v then -- we could move the data test outside (needed for plain) - local d = data[i] - if d then - local s = d.shcode - if not s then - -- sorry - elseif type(s) == "table" then - v = ((vector[s[1]] or 0) + (vector[s[#s]] or 0)) / 2 - else - v = vector[s] or 0 - end - end - end - if v and v ~= 0 then - chr.expansion_factor = v*factor - else -- can be option - chr.expansion_factor = factor - end - end - elseif trace_expansion then - report_expansions("unknown vector %a in class %a",class.vector,value) - end - elseif trace_expansion then - report_expansions("unknown class %a",value) - end - end -end - -local expansion_specification = { - name = "expansion", - description = "apply hz optimization", - initializers = { - base = initializeexpansion, - node = initializeexpansion, - } -} - -registerotffeature(expansion_specification) -registerafmfeature(expansion_specification) - -fonts.goodies.register("expansions", function(...) return fonts.goodies.report("expansions", trace_expansion, ...) end) - -implement { - name = "setupfontexpansion", - arguments = "2 strings", - actions = function(class,settings) getparameters(classes,class,'preset',settings) end -} - --- -- -- -- -- -- --- protrusion --- -- -- -- -- -- - -fonts.protrusions = allocate() -local protrusions = fonts.protrusions - -protrusions.classes = allocate() -protrusions.vectors = allocate() - -local classes = protrusions.classes -local vectors = protrusions.vectors - --- the values need to be revisioned - -classes.preset = { factor = 1, left = 1, right = 1 } - -classes['pure'] = { - vector = 'pure', factor = 1 -} -classes['punctuation'] = { - vector = 'punctuation', factor = 1 -} -classes['alpha'] = { - vector = 'alpha', factor = 1 -} -classes['quality'] = { - vector = 'quality', factor = 1 -} - -vectors['pure'] = { - - [0x002C] = { 0, 1 }, -- comma - [0x002E] = { 0, 1 }, -- period - [0x003A] = { 0, 1 }, -- colon - [0x003B] = { 0, 1 }, -- semicolon - [0x002D] = { 0, 1 }, -- hyphen - [0x00AD] = { 0, 1 }, -- also 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 ۔ - -} - -vectors['punctuation'] = { - - [0x003F] = { 0, 0.20 }, -- ? - [0x00BF] = { 0, 0.20 }, -- ¿ - [0x0021] = { 0, 0.20 }, -- ! - [0x00A1] = { 0, 0.20 }, -- ¡ - [0x0028] = { 0.05, 0 }, -- ( - [0x0029] = { 0, 0.05 }, -- ) - [0x005B] = { 0.05, 0 }, -- [ - [0x005D] = { 0, 0.05 }, -- ] - [0x002C] = { 0, 0.70 }, -- comma - [0x002E] = { 0, 0.70 }, -- period - [0x003A] = { 0, 0.50 }, -- colon - [0x003B] = { 0, 0.50 }, -- semicolon - [0x002D] = { 0, 0.70 }, -- hyphen - [0x00AD] = { 0, 0.70 }, -- also hyphen - [0x2013] = { 0, 0.30 }, -- endash - [0x2014] = { 0, 0.20 }, -- emdash - [0x060C] = { 0, 0.70 }, -- arabic comma - [0x061B] = { 0, 0.50 }, -- arabic semicolon - [0x06D4] = { 0, 0.70 }, -- arabic full stop - [0x061F] = { 0, 0.20 }, -- ؟ - - -- todo: left and right quotes: .5 double, .7 single - - [0x2039] = { 0.70, 0.70 }, -- left single guillemet ‹ - [0x203A] = { 0.70, 0.70 }, -- right single guillemet › - [0x00AB] = { 0.50, 0.50 }, -- left guillemet « - [0x00BB] = { 0.50, 0.50 }, -- right guillemet » - - [0x2018] = { 0.70, 0.70 }, -- left single quotation mark ‘ - [0x2019] = { 0, 0.70 }, -- right single quotation mark ’ - [0x201A] = { 0.70, 0 }, -- single low-9 quotation mark , - [0x201B] = { 0.70, 0 }, -- single high-reversed-9 quotation mark ‛ - [0x201C] = { 0.50, 0.50 }, -- left double quotation mark “ - [0x201D] = { 0, 0.50 }, -- right double quotation mark ” - [0x201E] = { 0.50, 0 }, -- double low-9 quotation mark „ - [0x201F] = { 0.50, 0 }, -- double high-reversed-9 quotation mark ‟ - -} - -vectors['alpha'] = { - - [byte("A")] = { .05, .05 }, - [byte("F")] = { 0, .05 }, - [byte("J")] = { .05, 0 }, - [byte("K")] = { 0, .05 }, - [byte("L")] = { 0, .05 }, - [byte("T")] = { .05, .05 }, - [byte("V")] = { .05, .05 }, - [byte("W")] = { .05, .05 }, - [byte("X")] = { .05, .05 }, - [byte("Y")] = { .05, .05 }, - - [byte("k")] = { 0, .05 }, - [byte("r")] = { 0, .05 }, - [byte("t")] = { 0, .05 }, - [byte("v")] = { .05, .05 }, - [byte("w")] = { .05, .05 }, - [byte("x")] = { .05, .05 }, - [byte("y")] = { .05, .05 }, - -} - -vectors['quality'] = table.merged( - vectors['punctuation'], - vectors['alpha'] -) - --- As this is experimental code, users should not depend on it. The implications are still --- discussed on the ConTeXt Dev List and we're not sure yet what exactly the spec is (the --- next code is tested with a gyre font patched by / fea file made by Khaled Hosny). The --- double trick should not be needed it proper hanging punctuation is used in which case --- values < 1 can be used. --- --- preferred (in context, usine vectors): --- --- \definefontfeature[whatever][default][mode=node,protrusion=quality] --- --- using lfbd and rtbd, with possibibility to enable only one side : --- --- \definefontfeature[whocares][default][mode=node,protrusion=yes, opbd=yes,script=latn] --- \definefontfeature[whocares][default][mode=node,protrusion=right,opbd=yes,script=latn] --- --- idem, using multiplier --- --- \definefontfeature[whocares][default][mode=node,protrusion=2,opbd=yes,script=latn] --- \definefontfeature[whocares][default][mode=node,protrusion=double,opbd=yes,script=latn] --- --- idem, using named feature file (less frozen): --- --- \definefontfeature[whocares][default][mode=node,protrusion=2,opbd=yes,script=latn,featurefile=texgyrepagella-regularxx.fea] - -classes['double'] = { -- for testing opbd - factor = 2, left = 1, right = 1, -} - -local function map_opbd_onto_protrusion(tfmdata,value,opbd) - local characters = tfmdata.characters - local descriptions = tfmdata.descriptions - local properties = tfmdata.properties - local resources = tfmdata.resources - local rawdata = tfmdata.shared.rawdata - local lookuphash = rawdata.lookuphash - local lookuptags = resources.lookuptags - local script = properties.script - local language = properties.language - local done, factor, left, right = false, 1, 1, 1 - local class = classes[value] - if class then - factor = class.factor or 1 - left = class.left or 1 - right = class.right or 1 - else - factor = tonumber(value) or 1 - end - if opbd ~= "right" then - local validlookups, lookuplist = otf.collectlookups(rawdata,"lfbd",script,language) - if validlookups then - for i=1,#lookuplist do - local lookup = lookuplist[i] - local steps = lookup.steps - if steps then - if trace_protrusion then - report_protrusions("setting left using lfbd") - end - for i=1,#steps do - local step = steps[i] - local coverage = step.coverage - if coverage then - for k, v in next, coverage do - -- local p = - v[3] / descriptions[k].width-- or 1 ~= 0 too but the same - local p = - (v[1] / 1000) * factor * left - characters[k].left_protruding = p - if trace_protrusion then - report_protrusions("lfbd -> %C -> %p",k,p) - end - end - end - end - done = true - end - end - end - end - if opbd ~= "left" then - local validlookups, lookuplist = otf.collectlookups(rawdata,"rtbd",script,language) - if validlookups then - for i=1,#lookuplist do - local lookup = lookuplist[i] - local steps = lookup.steps - if steps then - if trace_protrusion then - report_protrusions("setting right using rtbd") - end - for i=1,#steps do - local step = steps[i] - local coverage = step.coverage - if coverage then - for k, v in next, coverage do - -- local p = v[3] / descriptions[k].width -- or 3 - local p = (v[1] / 1000) * factor * right - characters[k].right_protruding = p - if trace_protrusion then - report_protrusions("rtbd -> %C -> %p",k,p) - end - end - end - end - end - done = true - end - end - end -end - --- The opbd test is just there because it was discussed on the context development list. However, --- the mentioned fxlbi.otf font only has some kerns for digits. So, consider this feature not supported --- till we have a proper test font. - -local function initializeprotrusion(tfmdata,value) - if value then - local opbd = tfmdata.shared.features.opbd - if opbd then - -- possible values: left right both yes no (experimental) - map_opbd_onto_protrusion(tfmdata,value,opbd) - else - local class, vector = get_class_and_vector(tfmdata,value,"protrusions") - if class then - if vector then - local factor = class.factor or 1 - local left = class.left or 1 - local right = class.right or 1 - if trace_protrusion then - report_protrusions("setting class %a, vector %a, factor %a, left %a, right %a", - value,class.vector,factor,left,right) - end - local data = characters.data - local emwidth = tfmdata.parameters.quad - tfmdata.parameters.protrusion = { - factor = factor, - left = left, - right = right, - } - for i, chr in next, tfmdata.characters do - local v, pl, pr = vector[i], nil, nil - if v then - pl, pr = v[1], v[2] - else - local d = data[i] - if d then - local s = d.shcode - if not s then - -- sorry - elseif type(s) == "table" then - local vl, vr = vector[s[1]], vector[s[#s]] - if vl then pl = vl[1] end - if vr then pr = vr[2] end - else - v = vector[s] - if v then - pl, pr = v[1], v[2] - end - end - end - 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 - elseif trace_protrusion then - report_protrusions("unknown vector %a in class %a",class.vector,value) - end - elseif trace_protrusion then - report_protrusions("unknown class %a",value) - end - end - end -end - -local protrusion_specification = { - name = "protrusion", - description = "l/r margin character protrusion", - initializers = { - base = initializeprotrusion, - node = initializeprotrusion, - } -} - -registerotffeature(protrusion_specification) -registerafmfeature(protrusion_specification) - -fonts.goodies.register("protrusions", function(...) return fonts.goodies.report("protrusions", trace_protrusion, ...) end) - -implement { - name = "setupfontprotrusion", - arguments = "2 strings", - actions = function(class,settings) getparameters(classes,class,'preset',settings) end -} - --- -- -- - -local function initializenostackmath(tfmdata,value) - tfmdata.properties.nostackmath = value and true -end - -registerotffeature { - name = "nostackmath", - description = "disable math stacking mechanism", - initializers = { - base = initializenostackmath, - node = initializenostackmath, - } -} - -local function initializerealdimensions(tfmdata,value) - tfmdata.properties.realdimensions = value and true -end - -registerotffeature { - name = "realdimensions", - description = "accept negative dimenions", - initializers = { - base = initializerealdimensions, - node = initializerealdimensions, - } -} - -local function initializeitlc(tfmdata,value) -- hm, always value - if value then - -- the magic 40 and it formula come from Dohyun Kim but we might need another guess - local parameters = tfmdata.parameters - local italicangle = parameters.italicangle - if italicangle and italicangle ~= 0 then - local properties = tfmdata.properties - local factor = tonumber(value) or 1 - properties.hasitalics = true - properties.autoitalicamount = factor * (parameters.uwidth or 40)/2 - end - end -end - -local italic_specification = { - name = "itlc", - description = "italic correction", - initializers = { - base = initializeitlc, - node = initializeitlc, - } -} - -registerotffeature(italic_specification) -registerafmfeature(italic_specification) - -local function initializetextitalics(tfmdata,value) -- yes no delay - tfmdata.properties.textitalics = toboolean(value) -end - -local textitalics_specification = { - name = "textitalics", - description = "use alternative text italic correction", - initializers = { - base = initializetextitalics, - node = initializetextitalics, - } -} - -registerotffeature(textitalics_specification) -registerafmfeature(textitalics_specification) - --- local function initializemathitalics(tfmdata,value) -- yes no delay --- tfmdata.properties.mathitalics = toboolean(value) --- end --- --- local mathitalics_specification = { --- name = "mathitalics", --- description = "use alternative math italic correction", --- initializers = { --- base = initializemathitalics, --- node = initializemathitalics, --- } --- } - --- registerotffeature(mathitalics_specification) --- registerafmfeature(mathitalics_specification) - --- slanting - -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.slantfactor = value -end - -local slant_specification = { - name = "slant", - description = "slant glyphs", - initializers = { - base = initializeslant, - node = initializeslant, - } -} - -registerotffeature(slant_specification) -registerafmfeature(slant_specification) - -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.extendfactor = value -end - -local extend_specification = { - name = "extend", - description = "scale glyphs horizontally", - initializers = { - base = initializeextend, - node = initializeextend, - } -} - -registerotffeature(extend_specification) -registerafmfeature(extend_specification) - --- For Wolfgang Schuster: --- --- \definefontfeature[thisway][default][script=hang,language=zhs,dimensions={2,2,2}] --- \definedfont[file:kozminpr6nregular*thisway] --- --- For the moment we don't mess with the descriptions. - -local function manipulatedimensions(tfmdata,key,value) - if type(value) == "string" and value ~= "" then - local characters = tfmdata.characters - local parameters = tfmdata.parameters - local emwidth = parameters.quad - local exheight = parameters.xheight - local newwidth = false - local newheight = false - local newdepth = false - if value == "strut" then - newheight = gettexdimen("strutht") - newdepth = gettexdimen("strutdp") - elseif value == "mono" then - newwidth = emwidth - else - local spec = settings_to_array(value) - newwidth = tonumber(spec[1]) - newheight = tonumber(spec[2]) - newdepth = tonumber(spec[3]) - if newwidth then newwidth = newwidth * emwidth end - if newheight then newheight = newheight * exheight end - if newdepth then newdepth = newdepth * exheight end - end - if newwidth or newheight or newdepth then - local additions = { } - for unicode, old_c in next, characters do - local oldwidth = old_c.width - local oldheight = old_c.height - local olddepth = old_c.depth - local width = newwidth or oldwidth or 0 - local height = newheight or oldheight or 0 - local depth = newdepth or olddepth or 0 - if oldwidth ~= width or oldheight ~= height or olddepth ~= depth then - local private = getprivate(tfmdata) - local newslot = { "slot", 1, private } -- { "slot", 0, private } - local new_c - local commands = oldwidth ~= width and { - { "right", (width - oldwidth) / 2 }, - newslot, - } or { - newslot, - } - if height > 0 then - if depth > 0 then - new_c = { - width = width, - height = height, - depth = depth, - commands = commands, - } - else - new_c = { - width = width, - height = height, - commands = commands, - } - end - else - if depth > 0 then - new_c = { - width = width, - depth = depth, - commands = commands, - } - else - new_c = { - width = width, - commands = commands, - } - end - end - setmetatableindex(new_c,old_c) - characters[unicode] = new_c - additions[private] = old_c - end - end - for k, v in next, additions do - characters[k] = v - end - -- elseif height > 0 and depth > 0 then - -- for unicode, old_c in next, characters do - -- old_c.height = height - -- old_c.depth = depth - -- end - -- elseif height > 0 then - -- for unicode, old_c in next, characters do - -- old_c.height = height - -- end - -- elseif depth > 0 then - -- for unicode, old_c in next, characters do - -- old_c.depth = depth - -- end - end - end -end - -local dimensions_specification = { - name = "dimensions", - description = "force dimensions", - manipulators = { - base = manipulatedimensions, - node = manipulatedimensions, - } -} - -registerotffeature(dimensions_specification) -registerafmfeature(dimensions_specification) - --------------------------------------------------------------------------------------------------------------- - --- local function fakemonospace(tfmdata) --- local resources = tfmdata.resources --- local gposfeatures = resources.features.gpos --- local characters = tfmdata.characters --- local descriptions = tfmdata.descriptions --- local sequences = resources.sequences --- local coverage = { } --- local units = tfmdata.shared.rawdata.metadata.units --- for k, v in next, characters do --- local w = descriptions[k].width --- local d = units - w --- coverage[k] = { -d/2, 0, units, 0 } --- end --- local f = { dflt = { dflt = true } } --- local s = #sequences + 1 --- local t = { --- features = { fakemono = f }, --- flags = { false, false, false, false }, --- index = s, --- name = "p_s_" .. s, --- nofsteps = 1, --- order = { "fakemono" }, --- skiphash = false, --- type = "gpos_single", --- steps = { --- { --- format = "single", --- coverage = coverage, --- } --- } --- } --- gposfeatures["fakemono"] = f --- sequences[s] = t --- end --- --- fonts.constructors.features.otf.register { --- name = "fakemono", --- description = "fake monospaced", --- initializers = { --- node = fakemonospace, --- }, --- } - --------------------------------------------------------------------------------------------------------------- - --- for zhichu chen (see mailing list archive): we might add a few more variants --- in due time --- --- \definefontfeature[boxed][default][boundingbox=yes] % paleblue --- --- maybe: --- --- \definecolor[DummyColor][s=.75,t=.5,a=1] {\DummyColor test} \nopdfcompression --- --- local gray = { "pdf", "origin", "/Tr1 gs .75 g" } --- local black = { "pdf", "origin", "/Tr0 gs 0 g" } - - --- boundingbox={yes|background|frame|empty|} - -local push = { "push" } -local pop = { "pop" } - ------ gray = { "pdf", "origin", ".75 g .75 G" } ------ black = { "pdf", "origin", "0 g 0 G" } ------ gray = { "pdf", ".75 g" } ------ black = { "pdf", "0 g" } - --- local bp = number.dimenfactors.bp --- --- local downcache = setmetatableindex(function(t,d) --- local v = { "down", d } --- t[d] = v --- return v --- end) --- --- local backcache = setmetatableindex(function(t,h) --- local h = h * bp --- local v = setmetatableindex(function(t,w) --- -- local v = { "rule", h, w } --- local v = { "pdf", "origin", formatters["0 0 %.6F %.6F re F"](w*bp,h) } --- t[w] = v --- return v --- end) --- t[h] = v --- return v --- end) --- --- local forecache = setmetatableindex(function(t,h) --- local h = h * bp --- local v = setmetatableindex(function(t,w) --- local v = { "pdf", "origin", formatters["%.6F w 0 0 %.6F %.6F re S"](0.25*65536*bp,w*bp,h) } --- t[w] = v --- return v --- end) --- t[h] = v --- return v --- end) - -local bp = number.dimenfactors.bp -local r = 16384 * bp -- 65536 // 4 - -local backcache = setmetatableindex(function(t,h) - local h = h * bp - local v = setmetatableindex(function(t,d) - local d = d * bp - local v = setmetatableindex(function(t,w) - local v = { "pdf", "origin", formatters["%.6F w 0 %.6F %.6F %.6F re f"](r,-d,w*bp,h+d) } - t[w] = v - return v - end) - t[d] = v - return v - end) - t[h] = v - return v -end) - -local forecache = setmetatableindex(function(t,h) - local h = h * bp - local v = setmetatableindex(function(t,d) - local d = d * bp - local v = setmetatableindex(function(t,w) - -- the frame goes through the boundingbox - -- local v = { "pdf", "origin", formatters["[] 0 d 0 J %.6F w %.6F %.6F %.6F re S"](r,-d,w*bp,h+d) } - local v = { "pdf", "origin", formatters["[] 0 d 0 J %.6F w %.6F %.6F %.6F %.6F re S"](r,r/2,-d+r/2,w*bp-r,h+d-r) } - t[w] = v - return v - end) - t[d] = v - return v - end) - t[h] = v - return v -end) - -local startcolor = nil -local stopcolor = nil - -local function showboundingbox(tfmdata,key,value) - if value then - if not backcolors then - local vfspecials = backends.pdf.tables.vfspecials - startcolor = vfspecials.startcolor - stopcolor = vfspecials.stopcolor - end - local characters = tfmdata.characters - local additions = { } - local rulecache = backcache - local showchar = true - local color = "palegray" - if type(value) == "string" then - value = settings_to_array(value) - for i=1,#value do - local v = value[i] - if v == v_frame then - rulecache = forecache - elseif v == v_background then - rulecache = backcache - elseif v == v_empty then - showchar = false - elseif v == v_none then - color = nil - else - color = v - end - end - end - local gray = color and startcolor(color) or nil - local black = gray and stopcolor or nil - for unicode, old_c in next, characters do - local private = getprivate(tfmdata) - local width = old_c.width or 0 - local height = old_c.height or 0 - local depth = old_c.depth or 0 - local char = showchar and { "slot", 1, private } or nil -- { "slot", 0, private } - -- local new_c - -- if depth == 0 then - -- new_c = { - -- width = width, - -- height = height, - -- commands = { - -- push, - -- gray, - -- rulecache[height][width], - -- black, - -- pop, - -- char, - -- } - -- } - -- else - -- new_c = { - -- width = width, - -- height = height, - -- depth = depth, - -- commands = { - -- push, - -- downcache[depth], - -- gray, - -- rulecache[height+depth][width], - -- black, - -- pop, - -- char, - -- } - -- } - -- end - local rule = rulecache[height][depth][width] - local new_c = { - width = width, - height = height, - depth = depth, - commands = gray and { - -- push, - gray, - rule, - black, - -- pop, - char, - } or { - rule, - char, - } - } - setmetatableindex(new_c,old_c) - characters[unicode] = new_c - additions[private] = old_c - end - for k, v in next, additions do - characters[k] = v - end - end -end - -registerotffeature { - name = "boundingbox", - description = "show boundingbox", - manipulators = { - base = showboundingbox, - node = showboundingbox, - } -} - --- -- for notosans but not general --- --- do --- --- local v_local = interfaces and interfaces.variables and interfaces.variables["local"] or "local" --- --- local utfbyte = utf.byte --- --- local function initialize(tfmdata,key,value) --- local characters = tfmdata.characters --- local parameters = tfmdata.parameters --- local oldchar = 32 --- local newchar = 32 --- if value == "locl" or value == v_local then --- newchar = fonts.handlers.otf.getsubstitution(tfmdata,oldchar,"locl",true) or oldchar --- elseif value == true then --- -- use normal space --- elseif value then --- newchar = utfbyte(value) --- else --- return --- end --- local newchar = newchar and characters[newchar] --- local newspace = newchar and newchar.width --- if newspace > 0 then --- parameters.space = newspace --- parameters.space_stretch = newspace/2 --- parameters.space_shrink = newspace/3 --- parameters.extra_space = parameters.space_shrink --- end --- end --- --- registerotffeature { --- name = 'space', -- true|false|locl|character --- description = 'space settings', --- manipulators = { --- base = initialize, --- node = initialize, --- } --- } --- --- end - -do - - local P, lpegpatterns, lpegmatch = lpeg.P, lpeg.patterns, lpeg.match - - local amount, stretch, shrink, extra - - local factor = lpegpatterns.unsigned - local space = lpegpatterns.space - local pattern = ( - (factor / function(n) amount = tonumber(n) or amount end) - + (P("+") + P("plus" )) * space^0 * (factor / function(n) stretch = tonumber(n) or stretch end) - + (P("-") + P("minus")) * space^0 * (factor / function(n) shrink = tonumber(n) or shrink end) - + ( P("extra")) * space^0 * (factor / function(n) extra = tonumber(n) or extra end) - + space^1 - )^1 - - local function initialize(tfmdata,key,value) - local characters = tfmdata.characters - local parameters = tfmdata.parameters - if type(value) == "string" then - local emwidth = parameters.quad - amount, stretch, shrink, extra = 0, 0, 0, false - lpegmatch(pattern,value) - if not extra then - if shrink ~= 0 then - extra = shrink - elseif stretch ~= 0 then - extra = stretch - else - extra = amount - end - end - parameters.space = amount * emwidth - parameters.space_stretch = stretch * emwidth - parameters.space_shrink = shrink * emwidth - parameters.extra_space = extra * emwidth - end - end - - -- 1.1 + 1.2 - 1.3 minus 1.4 plus 1.1 extra 1.4 -- last one wins - - registerotffeature { - name = "spacing", - description = "space settings", - manipulators = { - base = initialize, - node = initialize, - } - } - -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, --- } --- } - --- not to be used! experimental code, only needed when testing - -local is_letter = characters.is_letter -local always = true - -local function collapseitalics(tfmdata,key,value) - local threshold = value == true and 100 or tonumber(value) - if threshold and threshold > 0 then - if threshold > 100 then - threshold = 100 - end - for unicode, data in next, tfmdata.characters do - if always or is_letter[unicode] or is_letter[data.unicode] then - local italic = data.italic - if italic and italic ~= 0 then - local width = data.width - if width and width ~= 0 then - local delta = threshold * italic / 100 - data.width = width + delta - data.italic = italic - delta - end - end - end - end - end -end - -local dimensions_specification = { - name = "collapseitalics", - description = "collapse italics", - manipulators = { - base = collapseitalics, - node = collapseitalics, - } -} - -registerotffeature(dimensions_specification) -registerafmfeature(dimensions_specification) - --- a handy helper (might change or be moved to another namespace) - -local nodepool = nodes.pool -local new_glyph = nodepool.glyph - -local helpers = fonts.helpers -local currentfont = font.current - -local currentprivate = 0xE000 -local maximumprivate = 0xEFFF - --- if we run out of space we can think of another range but by sharing we can --- use these privates for mechanisms like alignments-on-character and such - -local sharedprivates = setmetatableindex(function(t,k) - v = currentprivate - if currentprivate < maximumprivate then - currentprivate = currentprivate + 1 - else - -- reuse last slot, todo: warning - end - t[k] = v - return v -end) - -function helpers.addprivate(tfmdata,name,characterdata) - local properties = tfmdata.properties - local characters = tfmdata.characters - local privates = properties.privates - if not privates then - privates = { } - properties.privates = privates - end - if not name then - name = formatters["anonymous_private_0x%05X"](currentprivate) - end - local usedprivate = sharedprivates[name] - privates[name] = usedprivate - characters[usedprivate] = characterdata - return usedprivate -end - -local function getprivateslot(id,name) - if not name then - name = id - id = currentfont() - end - local properties = fontproperties[id] - local privates = properties and properties.privates - return privates and privates[name] -end - -local function getprivatenode(tfmdata,name) - if type(tfmdata) == "number" then - tfmdata = fontdata[tfmdata] - end - local properties = tfmdata.properties - local font = properties.id - local slot = getprivateslot(font,name) - if slot then - -- todo: set current attribibutes - local char = tfmdata.characters[slot] - local tonode = char.tonode - if tonode then - return tonode(font,char) - else - return new_glyph(font,slot) - end - end -end - -local function getprivatecharornode(tfmdata,name) - if type(tfmdata) == "number" then - tfmdata = fontdata[tfmdata] - end - local properties = tfmdata.properties - local font = properties.id - local slot = getprivateslot(font,name) - if slot then - -- todo: set current attributes - local char = tfmdata.characters[slot] - local tonode = char.tonode - if tonode then - return "node", tonode(tfmdata,char) - else - return "char", slot - end - end -end - -helpers.getprivateslot = getprivateslot -helpers.getprivatenode = getprivatenode -helpers.getprivatecharornode = getprivatecharornode - -function helpers.getprivates(tfmdata) - if type(tfmdata) == "number" then - tfmdata = fontdata[tfmdata] - end - local properties = tfmdata.properties - return properties and properties.privates -end - -function helpers.hasprivate(tfmdata,name) - if type(tfmdata) == "number" then - tfmdata = fontdata[tfmdata] - end - local properties = tfmdata.properties - local privates = properties and properties.privates - return privates and privates[name] or false -end - --- relatively new: - -do - - local extraprivates = { } - - function fonts.helpers.addextraprivate(name,f) - extraprivates[#extraprivates+1] = { name, f } - end - - local function addextraprivates(tfmdata) - for i=1,#extraprivates do - local e = extraprivates[i] - local c = e[2](tfmdata) - if c then - fonts.helpers.addprivate(tfmdata, e[1], c) - end - end - end - - constructors.newfeatures.otf.register { - name = "extraprivates", - description = "extra privates", - default = true, - manipulators = { - base = addextraprivates, - node = addextraprivates, - } - } - -end - -implement { - name = "getprivatechar", - arguments = "string", - actions = function(name) - local p = getprivateslot(name) - if p then - context(utfchar(p)) - end - end -} - -implement { - name = "getprivatemathchar", - arguments = "string", - actions = function(name) - local p = getprivateslot(family_font(0),name) - if p then - context(utfchar(p)) - end - end -} - -implement { - name = "getprivateslot", - arguments = "string", - actions = function(name) - local p = getprivateslot(name) - if p then - context(p) - end - end -} - --- requested for latex but not supported unless really needed in context: --- --- registerotffeature { --- name = "ignoremathconstants", --- description = "ignore math constants table", --- initializers = { --- base = function(tfmdata,value) --- if value then --- tfmdata.mathparameters = nil --- end --- end --- } --- } - --- tfmdata.properties.mathnolimitsmode = tonumber(value) or 0 - -do - - local splitter = lpeg.splitat(",",tonumber) - local lpegmatch = lpeg.match - - local function initialize(tfmdata,value) - local mathparameters = tfmdata.mathparameters - if mathparameters then - local sup, sub - if type(value) == "string" then - sup, sub = lpegmatch(splitter,value) - if not sup then - sub, sup = 0, 0 - elseif not sub then - sub, sup = sup, 0 - end - elseif type(value) == "number" then - sup, sub = 0, value - end - mathparameters.NoLimitSupFactor = sup - mathparameters.NoLimitSubFactor = sub - end - end - - registerotffeature { - name = "mathnolimitsmode", - description = "influence nolimits placement", - initializers = { - base = initialize, - node = initialize, - } - } - -end - -do - - local function initialize(tfmdata,value) - local properties = tfmdata.properties - if properties then - properties.identity = value == "vertical" and "vertical" or "horizontal" - end - end - - registerotffeature { - name = "identity", - description = "set font identity", - initializers = { - base = initialize, - node = initialize, - } - } - - local function initialize(tfmdata,value) - local properties = tfmdata.properties - if properties then - properties.writingmode = value == "vertical" and "vertical" or "horizontal" - end - end - - registerotffeature { - name = "writingmode", - description = "set font direction", - initializers = { - base = initialize, - node = initialize, - } - } - -end - -do -- another hack for a crappy font - - local function additalictowidth(tfmdata,key,value) - local characters = tfmdata.characters - local additions = { } - for unicode, old_c in next, characters do - -- maybe check for math - local oldwidth = old_c.width - local olditalic = old_c.italic - if olditalic and olditalic ~= 0 then - local private = getprivate(tfmdata) - local new_c = { - width = oldwidth + olditalic, - height = old_c.height, - depth = old_c.depth, - commands = { - -- { "slot", 1, private }, - -- { "slot", 0, private }, - { "char", private }, - { "right", olditalic }, - }, - } - setmetatableindex(new_c,old_c) - characters[unicode] = new_c - additions[private] = old_c - end - end - for k, v in next, additions do - characters[k] = v - end - end - - registerotffeature { - name = "italicwidths", - description = "add italic to width", - manipulators = { - base = additalictowidth, - -- node = additalictowidth, -- only makes sense for math - } - } - -end - -do - - local tounicode = fonts.mappings.tounicode - - local function check(tfmdata,key,value) - if value == "ligatures" then - local private = fonts.constructors and fonts.constructors.privateoffset or 0xF0000 - local collected = fonts.handlers.otf.readers.getcomponents(tfmdata.shared.rawdata) - if collected and next(collected)then - for unicode, char in next, tfmdata.characters do - if true then -- if unicode >= private or (unicode >= 0xE000 and unicode <= 0xF8FF) then - local u = collected[unicode] - if u then - local n = #u - for i=1,n do - if u[i] > private then - n = 0 - break - end - end - if n > 0 then - if n == 1 then - u = u[1] - end - char.unicode = u - char.tounicode = tounicode(u) - end - end - end - end - end - end - end - - -- forceunicodes=ligatures : aggressive lig resolving (e.g. for emoji) - -- - -- kind of like: \enabletrackers[fonts.mapping.forceligatures] - - registerotffeature { - name = "forceunicodes", - description = "forceunicodes", - manipulators = { - base = check, - node = check, - } - } - -end - -do - - -- This is a rather special test-only feature that I added for the sake of testing - -- Idris's husayni. We wanted to know if uniscribe obeys the order of lookups in a - -- font, in spite of what the description of handling arabic suggests. And indeed, - -- mixed-in lookups of other features (like all these ss* in husayni) are handled - -- the same in context as in uniscribe. If one sets reorderlookups=arab then we sort - -- according to the "assumed" order so e.g. the ss* move to after the standard - -- features. The observed difference in rendering is an indication that uniscribe is - -- quite faithful to the font (while e.g. tests with the hb plugin demonstrate some - -- interference, apart from some hard coded init etc expectations). Anyway, it means - -- that we're okay with the (generic) node processor. A pitfall is that in context - -- we can actually control more, so we can trigger an analyze pass with e.g. - -- dflt/dflt while the libraries depend on the script settings for that. Uniscribe - -- probably also parses the string and when seeing arabic will follow a different - -- code path, although it seems to treat all features equal. - - local trace_reorder = trackers.register("fonts.reorderlookups",function(v) trace_reorder = v end) - local report_reorder = logs.reporter("fonts","reorder") - - local vectors = { } - - vectors.arab = { - gsub = { - ccmp = 1, - isol = 2, - fina = 3, - medi = 4, - init = 5, - rlig = 6, - rclt = 7, - calt = 8, - liga = 9, - dlig = 10, - cswh = 11, - mset = 12, - }, - gpos = { - curs = 1, - kern = 2, - mark = 3, - mkmk = 4, - }, - } - - function otf.reorderlookups(tfmdata,vector) - local order = vectors[vector] - if not order then - return - end - local oldsequences = tfmdata.resources.sequences - if oldsequences then - local sequences = { } - for i=1,#oldsequences do - sequences[i] = oldsequences[i] - end - for i=1,#sequences do - local s = sequences[i] - local features = s.features - local kind = s.type - local index = s.index - if features then - local when - local what - for feature in sortedhash(features) do - if not what then - what = find(kind,"^gsub") and "gsub" or "gpos" - end - local newwhen = order[what][feature] - if not newwhen then - -- skip - elseif not when then - when = newwhen - elseif newwhen < when then - when = newwhen - end - end - s.ondex = s.index - s.index = i - s.what = what == "gsub" and 1 or 2 - s.when = when or 99 - else - s.ondex = s.index - s.index = i - s.what = 1 - s.when = 99 - end - end - sort(sequences,function(a,b) - local what_a = a.what - local what_b = b.what - if what_a ~= what_b then - return a.index < b.index - end - local when_a = a.when - local when_b = b.when - if when_a == when_b then - return a.index < b.index - else - return when_a < when_b - end - end) - local swapped = 0 - for i=1,#sequences do - local sequence = sequences[i] - local features = sequence.features - if features then - local index = sequence.index - if index ~= i then - swapped = swapped + 1 - end - if trace_reorder then - if swapped == 1 then - report_reorder() - report_reorder("start swapping lookups in font %!font:name!",tfmdata) - report_reorder() - report_reorder("gsub order: % t",table.swapped(order.gsub)) - report_reorder("gpos order: % t",table.swapped(order.gpos)) - report_reorder() - end - report_reorder("%03i : lookup %03i, type %s, sorted %2i, moved %s, % t", - i,index,sequence.what == 1 and "gsub" or "gpos",sequence.when or 99, - (index > i and "-") or (index < i and "+") or "=",sortedkeys(features)) - end - end - sequence.what = nil - sequence.when = nil - sequence.index = sequence.ondex - end - if swapped > 0 then - if trace_reorder then - report_reorder() - report_reorder("stop swapping lookups, %i lookups swapped",swapped) - report_reorder() - end --- tfmdata.resources.sequences = sequences - tfmdata.shared.reorderedsequences = sequences - end - end - end - - -- maybe delay till ra is filled - - local function reorderlookups(tfmdata,key,value) - if value then - otf.reorderlookups(tfmdata,value) - end - end - - registerotffeature { - name = "reorderlookups", - description = "reorder lookups", - manipulators = { - base = reorderlookups, - node = reorderlookups, - } - } - -end - --- maybe useful - -local function initializeoutline(tfmdata,value) - value = tonumber(value) - if not value then - value = 0 - else - value = tonumber(value) or 0 - end - if value then - value = value * 1000 - end - tfmdata.parameters.mode = 1 - tfmdata.parameters.width = value -end - -local outline_specification = { - name = "outline", - description = "outline glyphs", - initializers = { - base = initializeoutline, - node = initializeoutline, - } -} - -registerotffeature(outline_specification) -registerafmfeature(outline_specification) - --- definitely ugly - -local report_effect = logs.reporter("fonts","effect") -local trace_effect = false - -trackers.register("fonts.effect", function(v) trace_effect = v end) - -local effects = { - inner = 0, - normal = 0, - outer = 1, - outline = 1, - both = 2, - hidden = 3, -} - -local function initializeeffect(tfmdata,value) - local spec - if type(value) == "number" then - spec = { width = value } - else - spec = settings_to_hash(value) - end - local effect = spec.effect or "both" - local width = tonumber(spec.width) or 0 - local mode = effects[effect] - if not mode then - report_effect("invalid effect %a",effect) - elseif width == 0 and mode == 0 then - report_effect("invalid width %a for effect %a",width,effect) - else - local parameters = tfmdata.parameters - local properties = tfmdata.properties - parameters.mode = mode - parameters.width = width * 1000 - local factor = tonumber(spec.factor) or 0 - local hfactor = tonumber(spec.vfactor) or factor - local vfactor = tonumber(spec.hfactor) or factor - local delta = tonumber(spec.delta) or 1 - local wdelta = tonumber(spec.wdelta) or delta - local hdelta = tonumber(spec.hdelta) or delta - local ddelta = tonumber(spec.ddelta) or hdelta - properties.effect = { - effect = effect, - width = width, - factor = factor, - hfactor = hfactor, - vfactor = vfactor, - wdelta = wdelta, - hdelta = hdelta, - ddelta = ddelta, - } - end -end - -local function manipulateeffect(tfmdata) - local effect = tfmdata.properties.effect - if effect then - local characters = tfmdata.characters - local parameters = tfmdata.parameters - local multiplier = effect.width * 100 - local wdelta = effect.wdelta * parameters.hfactor * multiplier - local hdelta = effect.hdelta * parameters.vfactor * multiplier - local ddelta = effect.ddelta * parameters.vfactor * multiplier - local hshift = wdelta / 2 - local factor = (1 + effect.factor) * parameters.factor - local hfactor = (1 + effect.hfactor) * parameters.hfactor - local vfactor = (1 + effect.vfactor) * parameters.vfactor - for unicode, old_c in next, characters do - local oldwidth = old_c.width - local oldheight = old_c.height - local olddepth = old_c.depth - if oldwidth and oldwidth > 0 then - old_c.width = oldwidth + wdelta - old_c.commands = { - { "right", hshift }, - { "char", unicode }, - } - end - if oldheight and oldheight > 0 then - old_c.height = oldheight + hdelta - end - if olddepth and olddepth > 0 then - old_c.depth = olddepth + ddelta - end - end - parameters.factor = factor - parameters.hfactor = hfactor - parameters.vfactor = vfactor - if trace_effect then - report_effect("applying effect") - report_effect(" effect : %s", effect.effect) - report_effect(" width : %s => %s", effect.width, multiplier) - report_effect(" factor : %s => %s", effect.factor, factor ) - report_effect(" hfactor : %s => %s", effect.hfactor,hfactor) - report_effect(" vfactor : %s => %s", effect.vfactor,vfactor) - report_effect(" wdelta : %s => %s", effect.wdelta, wdelta) - report_effect(" hdelta : %s => %s", effect.hdelta, hdelta) - report_effect(" ddelta : %s => %s", effect.ddelta, ddelta) - end - end -end - -local effect_specification = { - name = "effect", - description = "apply effects to glyphs", - initializers = { - base = initializeeffect, - node = initializeeffect, - }, - manipulators = { - base = manipulateeffect, - node = manipulateeffect, - }, -} - -registerotffeature(effect_specification) -registerafmfeature(effect_specification) diff --git a/tex/context/base/mkiv/font-fbk.lua b/tex/context/base/mkiv/font-fbk.lua index 79ebc3f25..cf500d0ce 100644 --- a/tex/context/base/mkiv/font-fbk.lua +++ b/tex/context/base/mkiv/font-fbk.lua @@ -14,38 +14,38 @@ local next = next

This is very experimental code!

--ldx]]-- -local trace_combining_visualize = false trackers.register("fonts.composing.visualize", function(v) trace_combining_visualize = v end) -local trace_combining_define = false trackers.register("fonts.composing.define", function(v) trace_combining_define = v end) +local trace_visualize = false trackers.register("fonts.composing.visualize", function(v) trace_visualize = v end) +local trace_define = false trackers.register("fonts.composing.define", function(v) trace_define = v end) -trackers.register("fonts.combining", "fonts.composing.define") -- for old times sake (and manuals) -trackers.register("fonts.combining.all", "fonts.composing.*") -- for old times sake (and manuals) - -local report_combining = logs.reporter("fonts","combining") - -local force_combining = false -- just for demo purposes (see mk) +local report = logs.reporter("fonts","combining") local allocate = utilities.storage.allocate local fonts = fonts local handlers = fonts.handlers local constructors = fonts.constructors +local helpers = fonts.helpers local otf = handlers.otf local afm = handlers.afm local registerotffeature = otf.features.register local registerafmfeature = afm.features.register +local addotffeature = otf.addfeature + local unicodecharacters = characters.data local unicodefallbacks = characters.fallbacks -local vf = handlers.vf -local commands = vf.combiner.commands -local push = vf.predefined.push -local pop = vf.predefined.pop +local vfcommands = helpers.commands +local charcommand = vfcommands.char +local rightcommand = vfcommands.right +local downcommand = vfcommands.down +local upcommand = vfcommands.up +local push = vfcommands.push +local pop = vfcommands.pop -local force_composed = false -local cache = { } -- we could make these weak -local fraction = 0.15 -- 30 units for lucida +local force_combining = false -- just for demo purposes (see mk) +local fraction = 0.15 -- 30 units for lucida -- todo: we also need to update the feature hashes ... i'll do that when i'm in the mood -- and/or when i need it @@ -65,15 +65,15 @@ local function composecharacters(tfmdata) local italicfactor = parameters.italicfactor or 0 local vfspecials = backends.tables.vfspecials --brr local red, green, blue, black - if trace_combining_visualize then + if trace_visualize then red = vfspecials.startcolor("red") green = vfspecials.startcolor("green") blue = vfspecials.startcolor("blue") black = vfspecials.stopcolor end local compose = fonts.goodies.getcompositions(tfmdata) - if compose and trace_combining_visualize then - report_combining("using compose information from goodies file") + if compose and trace_visualize then + report("using compose information from goodies file") end local done = false for i, c in next, unicodecharacters do -- loop over all characters ... not that efficient but a specials hash takes memory @@ -105,24 +105,12 @@ local function composecharacters(tfmdata) acc = unicodefallbacks[acc] charsacc = acc and characters[acc] end - local chr_t = cache[chr] - if not chr_t then - -- chr_t = { "slot", 1, chr } - -- chr_t = { "slot", 0, chr } - chr_t = { "char", chr } - cache[chr] = chr_t - end + local chr_t = charcommand[chr] if charsacc then - if trace_combining_define then - report_combining("composed %C, base %C, accent %C",i,chr,acc) - end - local acc_t = cache[acc] - if not acc_t then - -- acc_t = { "slot", 1, acc } - -- acc_t = { "slot", 0, acc } - acc_t = { "char", acc } - cache[acc] = acc_t + if trace_define then + report("composed %C, base %C, accent %C",i,chr,acc) end + local acc_t = charcommand[acc] local cb = descriptions[chr].boundingbox local ab = descriptions[acc].boundingbox -- todo: adapt height @@ -148,26 +136,30 @@ local function composecharacters(tfmdata) local ay = a_anchor.y or 0 local dx = cx - ax local dy = cy - ay - if trace_combining_define then - report_combining("building %C from %C and %C",i,chr,acc) - report_combining(" boundingbox:") - report_combining(" chr: %3i %3i %3i %3i",unpack(cb)) - report_combining(" acc: %3i %3i %3i %3i",unpack(ab)) - report_combining(" anchors:") - report_combining(" chr: %3i %3i",cx,cy) - report_combining(" acc: %3i %3i",ax,ay) - report_combining(" delta:") - report_combining(" %s: %3i %3i",i_anchored,dx,dy) + if trace_define then + report("building %C from %C and %C",i,chr,acc) + report(" boundingbox:") + report(" chr: %3i %3i %3i %3i",unpack(cb)) + report(" acc: %3i %3i %3i %3i",unpack(ab)) + report(" anchors:") + report(" chr: %3i %3i",cx,cy) + report(" acc: %3i %3i",ax,ay) + report(" delta:") + report(" %s: %3i %3i",i_anchored,dx,dy) end - if trace_combining_visualize then - t.commands = { push, {"right", scale*dx}, {"down",-scale*dy}, green, acc_t, black, pop, chr_t } - -- t.commands = { - -- push, {"right", scale*cx}, {"down", -scale*cy}, red, {"rule",10000,10000,10000}, pop, - -- push, {"right", scale*ax}, {"down", -scale*ay}, blue, {"rule",10000,10000,10000}, pop, - -- push, {"right", scale*dx}, {"down", -scale*dy}, green, acc_t, black, pop, chr_t - -- } + local right = rightcommand[scale*dx] + local down = upcommand[scale*dy] + if trace_visualize then + t.commands = { + push, right, down, + green, acc_t, black, + pop, chr_t, + } else - t.commands = { push, {"right", scale*dx}, {"down",-scale*dy}, acc_t, pop, chr_t } + t.commands = { + push, right, down, + acc_t, pop, chr_t, + } end done = true end @@ -179,10 +171,17 @@ local function composecharacters(tfmdata) local dx = (c_urx - a_urx - a_llx + c_llx)/2 local dd = (c_urx - c_llx)*italicfactor if a_ury < 0 then - if trace_combining_visualize then - t.commands = { push, {"right", dx-dd}, red, acc_t, black, pop, chr_t } + local right = rightcommand[dx-dd] + if trace_visualize then + t.commands = { + push, right, red, acc_t, + black, pop, chr_t, + } else - t.commands = { push, {"right", dx-dd}, acc_t, pop, chr_t } + t.commands = { + push, right, acc_t, pop, + chr_t, + } end elseif c_ury > a_lly then -- messy test local dy @@ -214,27 +213,46 @@ local function composecharacters(tfmdata) else dy = - deltaxheight + extraxheight end - if trace_combining_visualize then - t.commands = { push, { "right", dx+dd }, { "down", dy }, green, acc_t, black, pop, chr_t } + local right = rightcommand[dx+dd] + local down = downcommand[dy] + if trace_visualize then + t.commands = { + push, right, down, green, + acc_t, black, pop, chr_t, + } else - t.commands = { push, { "right", dx+dd }, { "down", dy }, acc_t, pop, chr_t } + t.commands = { + push, right, down, acc_t, + pop, chr_t, + } end else - if trace_combining_visualize then - t.commands = { push, { "right", dx+dd }, blue, acc_t, black, pop, chr_t } + local right = rightcommand[dx+dd] + if trace_visualize then + t.commands = { + push, right, blue, acc_t, + black, pop, chr_t, + } else - t.commands = { push, { "right", dx+dd }, acc_t, pop, chr_t } + t.commands = { + push, right, acc_t, pop, + chr_t, + } end end end else - t.commands = { chr_t } -- else index mess + t.commands = { + chr_t, -- else index mess + } end else - if trace_combining_define then - report_combining("%C becomes simplified %C",i,chr) + if trace_define then + report("%C becomes simplified %C",i,chr) end - t.commands = { chr_t } -- else index mess + t.commands = { + chr_t, -- else index mess + } end done = true characters[i] = t @@ -254,7 +272,7 @@ local function composecharacters(tfmdata) end end -local compose_specification = { +local specification = { name = "compose", description = "additional composed characters", manipulators = { @@ -263,75 +281,71 @@ local compose_specification = { } } -registerotffeature(compose_specification) -registerafmfeature(compose_specification) +registerotffeature(specification) +registerafmfeature(specification) -vf.helpers.composecharacters = composecharacters +addotffeature { + name = "char-ligatures", + type = "ligature", + data = characters.splits.char, + order = { "char-ligatures" }, + prepend = true, +} --- This installs the builder into the regular virtual font builder, --- which only makes sense as demo. +addotffeature { + name = "compat-ligatures", + type = "ligature", + data = characters.splits.compat, + order = { "compat-ligatures" }, + prepend = true, +} -commands["compose.trace.enable"] = function() - trace_combining_visualize = true -end +registerotffeature { + name = 'char-ligatures', + description = 'unicode char specials to ligatures', +} -commands["compose.trace.disable"] = function() - trace_combining_visualize = false -end +registerotffeature { + name = 'compat-ligatures', + description = 'unicode compat specials to ligatures', +} -commands["compose.force.enable"] = function() - force_combining = true -end +do -commands["compose.force.disable"] = function() - force_combining = false -end + -- This installs the builder into the regular virtual font builder, + -- which only makes sense as demo. -commands["compose.trace.set"] = function(g,v) - if v[2] == nil then - trace_combining_visualize = true - else - trace_combining_visualize = v[2] - end -end - -commands["compose.apply"] = function(g,v) - composecharacters(g) -end + local vf = handlers.vf + local commands = vf.combiner.commands --- vf builder + vf.helpers.composecharacters = composecharacters --- { "pdf", "origin", "q " .. s .. " 0 0 " .. s .. " 0 0 cm" }, --- { "pdf", "origin", "q 1 0 0 1 " .. -w .. " " .. -h .. " cm" }, --- { "pdf", "origin", "/Fm\XX\space Do" }, --- { "pdf", "origin", "Q" }, --- { "pdf", "origin", "Q" }, + commands["compose.trace.enable"] = function() + trace_visualize = true + end --- new and experimental + commands["compose.trace.disable"] = function() + trace_visualize = false + end -local everywhere = { ["*"] = { ["*"] = true } } -- or: { ["*"] = { "*" } } -local noflags = { } + commands["compose.force.enable"] = function() + force_combining = true + end -local char_specification = { - type = "ligature", - features = everywhere, - data = characters.splits.char, - order = { "char-ligatures" }, - flags = noflags, - prepend = true, -} + commands["compose.force.disable"] = function() + force_combining = false + end -local compat_specification = { - type = "ligature", - features = everywhere, - data = characters.splits.compat, - order = { "compat-ligatures" }, - flags = noflags, - prepend = true, -} + commands["compose.trace.set"] = function(g,v) + if v[2] == nil then + trace_visualize = true + else + trace_visualize = v[2] + end + end -otf.addfeature("char-ligatures", char_specification) -- xlig (extra) -otf.addfeature("compat-ligatures",compat_specification) -- plig (pseudo) + commands["compose.apply"] = function(g,v) + composecharacters(g) + end -registerotffeature { name = 'char-ligatures', description = 'unicode char specials to ligatures' } -registerotffeature { name = 'compat-ligatures', description = 'unicode compat specials to ligatures' } +end diff --git a/tex/context/base/mkiv/font-fea.mkvi b/tex/context/base/mkiv/font-fea.mkvi index 5f65543ab..4a5356090 100644 --- a/tex/context/base/mkiv/font-fea.mkvi +++ b/tex/context/base/mkiv/font-fea.mkvi @@ -368,11 +368,19 @@ % \doifelsecurrentfonthasfeature{crap}{YES}{NO} % \doifelsecurrentfonthasfeature{kern}{YES}{NO} -\def\doifelsecurrentfonthasfeature#feature% +\def\doifelsecurrentfonthasfeature#feature% expandable {\clf_doifelsecurrentfonthasfeature{#feature}} \let\doifcurrentfonthasfeatureelse\doifelsecurrentfonthasfeature +\def\doifelsefontfeature#feature% expandable + {\clf_doifelsefontfeature{#feature}} + +\let\doiffontfeatureelse\doifelsefontfeature + +\def\doifunknownfontfeature#feature% expandable + {\clf_doifunknownfontfeature{#feature}} + % new: \clf_registerlanguagefeatures diff --git a/tex/context/base/mkiv/font-imp-dimensions.lua b/tex/context/base/mkiv/font-imp-dimensions.lua new file mode 100644 index 000000000..e658ef7bb --- /dev/null +++ b/tex/context/base/mkiv/font-imp-dimensions.lua @@ -0,0 +1,113 @@ +if not modules then modules = { } end modules ['font-imp-dimensions'] = { + version = 1.001, + comment = "companion to font-ini.mkiv and hand-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local next, type, tonumber = next, type, tonumber + +local fonts = fonts +local utilities = utilities + +local helpers = fonts.helpers +local prependcommands = helpers.prependcommands +local charcommand = helpers.commands.char +local rightcommand = helpers.commands.right + +local handlers = fonts.handlers +local otf = handlers.otf +local afm = handlers.afm + +local registerotffeature = otf.features.register +local registerafmfeature = afm.features.register + +local settings_to_array = utilities.parsers.settings_to_array +local gettexdimen = tex.getdimen + +-- For Wolfgang Schuster: +-- +-- \definefontfeature[thisway][default][script=hang,language=zhs,dimensions={2,2,2}] +-- \definedfont[file:kozminpr6nregular*thisway] + +local function initialize(tfmdata,key,value) + if type(value) == "string" and value ~= "" then + local characters = tfmdata.characters + local parameters = tfmdata.parameters + local emwidth = parameters.quad + local exheight = parameters.xheight + local newwidth = false + local newheight = false + local newdepth = false + if value == "strut" then + newheight = gettexdimen("strutht") + newdepth = gettexdimen("strutdp") + elseif value == "mono" then + newwidth = emwidth + else + local spec = settings_to_array(value) + newwidth = tonumber(spec[1]) + newheight = tonumber(spec[2]) + newdepth = tonumber(spec[3]) + if newwidth then newwidth = newwidth * emwidth end + if newheight then newheight = newheight * exheight end + if newdepth then newdepth = newdepth * exheight end + end + if newwidth or newheight or newdepth then + for unicode, character in next, characters do + local oldwidth = character.width + local oldheight = character.height + local olddepth = character.depth + local width = newwidth or oldwidth or 0 + local height = newheight or oldheight or 0 + local depth = newdepth or olddepth or 0 + if oldwidth ~= width or oldheight ~= height or olddepth ~= depth then + character.width = width + character.height = height + character.depth = depth + if oldwidth ~= width then + local commands = character.commands + local hshift = rightcommand[(width - oldwidth) / 2] + if commands then + character.commands = prependcommands ( + commands, + hshift + ) + else + character.commands = { + hshift, + charcommand[unicode], + } + end + end + end + end + end + end +end + +local specification = { + name = "dimensions", + description = "force dimensions", + manipulators = { + base = initialize, + node = initialize, + } +} + +registerotffeature(specification) +registerafmfeature(specification) + +local function initialize(tfmdata,value) + tfmdata.properties.realdimensions = value and true +end + +registerotffeature { + name = "realdimensions", + description = "accept negative dimenions", + initializers = { + base = initialize, + node = initialize, + } +} diff --git a/tex/context/base/mkiv/font-imp-effects.lua b/tex/context/base/mkiv/font-imp-effects.lua new file mode 100644 index 000000000..a5e04500c --- /dev/null +++ b/tex/context/base/mkiv/font-imp-effects.lua @@ -0,0 +1,397 @@ +if not modules then modules = { } end modules ['font-imp-effects'] = { + version = 1.001, + comment = "companion to font-ini.mkiv and hand-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- todo: pickup from goodies: if type(effect) then ... + +local next, type, tonumber = next, type, tonumber +local is_boolean = string.is_boolean + +local fonts = fonts + +local handlers = fonts.handlers +local registerotffeature = handlers.otf.features.register +local registerafmfeature = handlers.afm.features.register + +local settings_to_hash = utilities.parsers.settings_to_hash_colon_too + +local helpers = fonts.helpers +local prependcommands = helpers.prependcommands +local charcommand = helpers.commands.char +local rightcommand = helpers.commands.right +local upcommand = helpers.commands.up +local dummycommand = helpers.commands.dummy + +----- constructors = fonts.constructors +----- getmathparameter = constructors.getmathparameter +----- setmathparameter = constructors.setmathparameter + +local report_effect = logs.reporter("fonts","effect") +local report_slant = logs.reporter("fonts","slant") +local report_extend = logs.reporter("fonts","extend") +local report_squeeze = logs.reporter("fonts","squeeze") + +local trace = false + +trackers.register("fonts.effect", function(v) trace = v end) +trackers.register("fonts.slant", function(v) trace = v end) +trackers.register("fonts.extend", function(v) trace = v end) +trackers.register("fonts.squeeze",function(v) trace = v end) + +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 + if trace then + report_slant("applying %0.3f",value) + end + tfmdata.parameters.slantfactor = value +end + +local specification = { + name = "slant", + description = "slant glyphs", + initializers = { + base = initializeslant, + node = initializeslant, + } +} + +registerotffeature(specification) +registerafmfeature(specification) + +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 + if trace then + report_extend("applying %0.3f",value) + end + tfmdata.parameters.extendfactor = value +end + +local specification = { + name = "extend", + description = "scale glyphs horizontally", + initializers = { + base = initializeextend, + node = initializeextend, + } +} + +registerotffeature(specification) +registerafmfeature(specification) + +local function initializesqueeze(tfmdata,value) + value = tonumber(value) + if not value then + value = 0 + elseif value > 10 then + value = 10 + elseif value < -10 then + value = -10 + end + if trace then + report_squeeze("applying %0.3f",value) + end + tfmdata.parameters.squeezefactor = value +end + +local specification = { + name = "squeeze", + description = "scale glyphs vertically", + initializers = { + base = initializesqueeze, + node = initializesqueeze, + } +} + +registerotffeature(specification) +registerafmfeature(specification) + +local effects = { + inner = 0, + normal = 0, + outer = 1, + outline = 1, + both = 2, + hidden = 3, +} + +local function initializeeffect(tfmdata,value) + local spec + if type(value) == "number" then + spec = { width = value } + else + spec = settings_to_hash(value) + end + local effect = spec.effect or "both" + local width = tonumber(spec.width) or 0 + local mode = effects[effect] + if not mode then + report_effect("invalid effect %a",effect) + elseif width == 0 and mode == 0 then + report_effect("invalid width %a for effect %a",width,effect) + else + local parameters = tfmdata.parameters + local properties = tfmdata.properties + parameters.mode = mode + parameters.width = width * 1000 + if is_boolean(spec.auto) == true then + local squeeze = 1 - width/20 + local average = (1 - squeeze) * width * 100 + spec.squeeze = squeeze + spec.extend = 1 + width/2 + spec.wdelta = average + spec.hdelta = average/2 + spec.ddelta = average/2 + spec.vshift = average/2 + end + local factor = tonumber(spec.factor) or 0 + local hfactor = tonumber(spec.hfactor) or factor + local vfactor = tonumber(spec.vfactor) or factor + local delta = tonumber(spec.delta) or 1 + local wdelta = tonumber(spec.wdelta) or delta + local hdelta = tonumber(spec.hdelta) or delta + local ddelta = tonumber(spec.ddelta) or hdelta + local vshift = tonumber(spec.vshift) or 0 + local slant = spec.slant + local extend = spec.extend + local squeeze = spec.squeeze + if slant then + initializeslant(tfmdata,slant) + end + if extend then + initializeextend(tfmdata,extend) + end + if squeeze then + initializesqueeze(tfmdata,squeeze) + end + properties.effect = { + effect = effect, + width = width, + factor = factor, + hfactor = hfactor, + vfactor = vfactor, + wdelta = wdelta, + hdelta = hdelta, + ddelta = ddelta, + vshift = vshift, + slant = tfmdata.parameters.slantfactor, + extend = tfmdata.parameters.extendfactor, + squeeze = tfmdata.parameters.squeezefactor, + } + end +end + +local rules = { + "RadicalRuleThickness", + "OverbarRuleThickness", + "FractionRuleThickness", + "UnderbarRuleThickness", +} + +-- local commands = char.commands +-- if commands then +-- local command = commands[1] +-- if command and command[1] == "right" then +-- commands[1] = rightcommand[command[2]-snap] +-- end +-- end + +local function setmathparameters(tfmdata,characters,mathparameters,dx,dy,squeeze) + if delta ~= 0 then + for i=1,#rules do + local name = rules[i] + local value = mathparameters[name] + if value then + mathparameters[name] = (squeeze or 1) * (value + dx) + end + end + end +end + +local function setmathcharacters(tfmdata,characters,mathparameters,dx,dy,squeeze,wdelta,hdelta,ddelta) + + local function wdpatch(char) + if wsnap ~= 0 then + char.width = char.width + wdelta/2 + end + end + + local function htpatch(char) + if hsnap ~= 0 then + local height = char.height + if height then + char.height = char.height + 2 * dy + end + end + end + + local character = characters[0x221A] + + if character then + local char = character + local next = character.next + wdpatch(char) + htpatch(char) + while next do + char = characters[next] + wdpatch(char) + htpatch(char) + next = char.next + end + if char then + local v = char.vert_variants + if v then + local top = v[#v] + if top then + htpatch(characters[top.glyph]) + end + end + end + end +end + +local function manipulateeffect(tfmdata) + local effect = tfmdata.properties.effect + if effect then + local characters = tfmdata.characters + local parameters = tfmdata.parameters + local mathparameters = tfmdata.mathparameters + local multiplier = effect.width * 100 + local factor = parameters.factor + local hfactor = parameters.hfactor + local vfactor = parameters.vfactor + local wdelta = effect.wdelta * hfactor * multiplier + local hdelta = effect.hdelta * vfactor * multiplier + local ddelta = effect.ddelta * vfactor * multiplier + local vshift = effect.vshift * vfactor * multiplier + local squeeze = effect.squeeze + local hshift = wdelta -- / 2 + local dx = multiplier * vfactor + local dy = vshift + local factor = (1 + effect.factor) * factor + local hfactor = (1 + effect.hfactor) * hfactor + local vfactor = (1 + effect.vfactor) * vfactor + local vshift = vshift ~= 0 and upcommand[vshift] or false + for unicode, character in next, characters do + local oldwidth = character.width + local oldheight = character.height + local olddepth = character.depth + if oldwidth and oldwidth > 0 then + character.width = oldwidth + wdelta + local commands = character.commands + local hshift = rightcommand[hshift] + if vshift then + if commands then + prependcommands ( commands, + hshift, + vshift + ) + else + character.commands = { + hshift, + vshift, + charcommand[unicode] + } + end + else + if commands then + prependcommands ( commands, + hshift + ) + else + character.commands = { + hshift, + charcommand[unicode] + } + end + end + end + if oldheight and oldheight > 0 then + character.height = oldheight + hdelta + end + if olddepth and olddepth > 0 then + character.depth = olddepth + ddelta + end + end + if mathparameters then + setmathparameters(tfmdata,characters,mathparameters,dx,dy,squeeze) + setmathcharacters(tfmdata,characters,mathparameters,dx,dy,squeeze,wdelta,hdelta,ddelta) + end + parameters.factor = factor + parameters.hfactor = hfactor + parameters.vfactor = vfactor + if trace then + report_effect("applying") + report_effect(" effect : %s", effect.effect) + report_effect(" width : %s => %s", effect.width, multiplier) + report_effect(" factor : %s => %s", effect.factor, factor ) + report_effect(" hfactor : %s => %s", effect.hfactor,hfactor) + report_effect(" vfactor : %s => %s", effect.vfactor,vfactor) + report_effect(" wdelta : %s => %s", effect.wdelta, wdelta) + report_effect(" hdelta : %s => %s", effect.hdelta, hdelta) + report_effect(" ddelta : %s => %s", effect.ddelta, ddelta) + end + end +end + +local specification = { + name = "effect", + description = "apply effects to glyphs", + initializers = { + base = initializeeffect, + node = initializeeffect, + }, + manipulators = { + base = manipulateeffect, + node = manipulateeffect, + }, +} + +registerotffeature(specification) +registerafmfeature(specification) + +local function initializeoutline(tfmdata,value) + value = tonumber(value) + if not value then + value = 0 + else + value = tonumber(value) or 0 + end + local parameters = tfmdata.parameters + local properties = tfmdata.properties + parameters.mode = effects.outline + parameters.width = value * 1000 + properties.effect = { + effect = effect, + width = width, + } +end + +local specification = { + name = "outline", + description = "outline glyphs", + initializers = { + base = initializeoutline, + node = initializeoutline, + } +} + +registerotffeature(specification) +registerafmfeature(specification) diff --git a/tex/context/base/mkiv/font-imp-italics.lua b/tex/context/base/mkiv/font-imp-italics.lua new file mode 100644 index 000000000..aace899c5 --- /dev/null +++ b/tex/context/base/mkiv/font-imp-italics.lua @@ -0,0 +1,147 @@ +if not modules then modules = { } end modules ['font-imp-italics'] = { + version = 1.001, + comment = "companion to font-ini.mkiv and hand-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local next = next + +local fonts = fonts +local handlers = fonts.handlers +local registerotffeature = handlers.otf.features.register +local registerafmfeature = handlers.afm.features.register + +local function initialize(tfmdata,key,value) + for unicode, character in next, tfmdata.characters do + local olditalic = character.italic + if olditalic and olditalic ~= 0 then + character.width = character.width + olditalic + character.italic = 0 + end + end +end + +local specification = { + name = "italicwidths", + description = "add italic to width", + manipulators = { + base = initialize, + node = initialize, -- only makes sense for math + } +} + +registerotffeature(specification) +registerafmfeature(specification) + +local function initialize(tfmdata,value) -- hm, always value + if value then + -- the magic 40 and it formula come from Dohyun Kim but we might need another guess + local parameters = tfmdata.parameters + local italicangle = parameters.italicangle + if italicangle and italicangle ~= 0 then + local properties = tfmdata.properties + local factor = tonumber(value) or 1 + properties.hasitalics = true + properties.autoitalicamount = factor * (parameters.uwidth or 40)/2 + end + end +end + +local specification = { + name = "itlc", + description = "italic correction", + initializers = { + base = initialize, + node = initialize, + } +} + +registerotffeature(specification) +registerafmfeature(specification) + +if context then + + local function initialize(tfmdata,value) -- yes no delay + tfmdata.properties.textitalics = toboolean(value) + end + + local specification = { + name = "textitalics", + description = "use alternative text italic correction", + initializers = { + base = initialize, + node = initialize, + } + } + + registerotffeature(specification) + registerafmfeature(specification) + +end + +-- no longer used + +if context then + + -- local function initializemathitalics(tfmdata,value) -- yes no delay + -- tfmdata.properties.mathitalics = toboolean(value) + -- end + -- + -- local specification = { + -- name = "mathitalics", + -- description = "use alternative math italic correction", + -- initializers = { + -- base = initializemathitalics, + -- node = initializemathitalics, + -- } + -- } + -- + -- registerotffeature(specification) + -- registerafmfeature(specification) + +end + +-- -- also not used, only when testing + +if context then + + local letter = characters.is_letter + local always = true + + local function collapseitalics(tfmdata,key,value) + local threshold = value == true and 100 or tonumber(value) + if threshold and threshold > 0 then + if threshold > 100 then + threshold = 100 + end + for unicode, data in next, tfmdata.characters do + if always or letter[unicode] or letter[data.unicode] then + local italic = data.italic + if italic and italic ~= 0 then + local width = data.width + if width and width ~= 0 then + local delta = threshold * italic / 100 + data.width = width + delta + data.italic = italic - delta + end + end + end + end + end + end + + local dimensions_specification = { + name = "collapseitalics", + description = "collapse italics", + manipulators = { + base = collapseitalics, + node = collapseitalics, + } + } + + registerotffeature(dimensions_specification) + registerafmfeature(dimensions_specification) + +end diff --git a/tex/context/base/mkiv/font-imp-ligatures.lua b/tex/context/base/mkiv/font-imp-ligatures.lua new file mode 100644 index 000000000..091eb5d4b --- /dev/null +++ b/tex/context/base/mkiv/font-imp-ligatures.lua @@ -0,0 +1,136 @@ +if not modules then modules = { } end modules ['font-imp-ligatures'] = { + 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 lpegmatch = lpeg.match +local utfsplit = utf.split +local settings_to_array = utilities.parsers.settings_to_array + +local fonts = fonts +local otf = fonts.handlers.otf +local registerotffeature = otf.features.register +local addotffeature = otf.addfeature + +-- This is a quick and dirty hack. + +local lookups = { } +local protect = { } +local revert = { } +local zwjchar = 0x200C +local zwj = { zwjchar } + +addotffeature { + name = "blockligatures", + type = "chainsubstitution", + nocheck = true, -- because there is no 0x200C in the font + prepend = true, -- make sure we do it early + future = true, -- avoid nilling due to no steps yet + lookups = { + { + type = "multiple", + data = lookups, + }, + }, + data = { + rules = protect, + } +} + +addotffeature { + name = "blockligatures", + type = "chainsubstitution", + nocheck = true, -- because there is no 0x200C in the font + append = true, -- this is done late + overload = false, -- we don't want to overload the previous definition + lookups = { + { + type = "ligature", + data = lookups, + }, + }, + data = { + rules = revert, + } +} + +registerotffeature { + name = 'blockligatures', + description = 'block certain ligatures', +} + +local splitter = lpeg.splitat(":") + +local function blockligatures(str) + + local t = settings_to_array(str) + + for i=1,#t do + local ti = t[i] + local before, current, after = lpegmatch(splitter,ti) + if current and after then -- before is returned when no match + -- experimental joke + if before then + before = utfsplit(before) + for i=1,#before do + before[i] = { before[i] } + end + end + if current then + current = utfsplit(current) + end + if after then + after = utfsplit(after) + for i=1,#after do + after[i] = { after[i] } + end + end + else + before = nil + current = utfsplit(ti) + after = nil + end + if #current > 1 then + local one = current[1] + local two = current[2] + lookups[one] = { one, zwjchar } + local one = { one } + local two = { two } + local new = #protect + 1 + protect[new] = { + before = before, + current = { one, two }, + after = after, + lookups = { 1 }, -- not shared ! + } + revert[new] = { + -- before = before, + current = { one, zwj }, + -- after = { two, unpack(after) }, + after = { two }, + lookups = { 1 }, -- not shared ! + } + end + end +end + +-- blockligatures("\0\0") + +otf.helpers.blockligatures = blockligatures + +-- blockligatures("fi,ff") +-- blockligatures("fl") +-- blockligatures("u:fl:age") + +if context then + + interfaces.implement { + name = "blockligatures", + arguments = "string", + actions = blockligatures, + } + +end diff --git a/tex/context/base/mkiv/font-imp-math.lua b/tex/context/base/mkiv/font-imp-math.lua new file mode 100644 index 000000000..3a82c2a9e --- /dev/null +++ b/tex/context/base/mkiv/font-imp-math.lua @@ -0,0 +1,79 @@ +if not modules then modules = { } end modules ['font-imp-math'] = { + version = 1.001, + comment = "companion to font-ini.mkiv and hand-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local next, type, tonumber = next, type, tonumber + +local fonts = fonts +local helpers = fonts.helpers +local registerotffeature = fonts.handlers.otf.features.register + +local setmetatableindex = table.setmetatableindex + +-- requested for latex but not supported unless really needed in context: +-- +-- registerotffeature { +-- name = "ignoremathconstants", +-- description = "ignore math constants table", +-- initializers = { +-- base = function(tfmdata,value) +-- if value then +-- tfmdata.mathparameters = nil +-- end +-- end +-- } +-- } + +-- tfmdata.properties.mathnolimitsmode = tonumber(value) or 0 + +local splitter = lpeg.splitat(",",tonumber) +local lpegmatch = lpeg.match + +local function initialize(tfmdata,value) + local mathparameters = tfmdata.mathparameters + if mathparameters then + local sup, sub + if type(value) == "string" then + sup, sub = lpegmatch(splitter,value) + if not sup then + sub, sup = 0, 0 + elseif not sub then + sub, sup = sup, 0 + end + elseif type(value) == "number" then + sup, sub = 0, value + end + if sup then + mathparameters.NoLimitSupFactor = sup + end + if sub then + mathparameters.NoLimitSubFactor = sub + end + end +end + +registerotffeature { + name = "mathnolimitsmode", + description = "influence nolimits placement", + initializers = { + base = initialize, + node = initialize, + } +} + +local function initialize(tfmdata,value) + tfmdata.properties.nostackmath = value and true +end + +registerotffeature { + name = "nostackmath", + description = "disable math stacking mechanism", + initializers = { + base = initialize, + node = initialize, + } +} diff --git a/tex/context/base/mkiv/font-imp-notused.lua b/tex/context/base/mkiv/font-imp-notused.lua new file mode 100644 index 000000000..1c78db7aa --- /dev/null +++ b/tex/context/base/mkiv/font-imp-notused.lua @@ -0,0 +1,166 @@ +if not modules then modules = { } end modules ['font-imp-notused'] = { + version = 1.001, + comment = "companion to font-ini.mkiv and hand-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- local next = next +-- local utfbyte = utf.byte +-- +-- local fonts = fonts +-- +-- local handlers = fonts.handlers +-- local otf = handlers.otf +-- local afm = handlers.afm +-- +-- local registerotffeature = otf.features.register +-- local registerafmfeature = afm.features.register + +-- local function initialize(tfmdata) +-- local resources = tfmdata.resources +-- local gposfeatures = resources.features.gpos +-- local characters = tfmdata.characters +-- local descriptions = tfmdata.descriptions +-- local sequences = resources.sequences +-- local coverage = { } +-- local units = tfmdata.shared.rawdata.metadata.units +-- for k, v in next, characters do +-- local w = descriptions[k].width +-- local d = units - w +-- coverage[k] = { -d/2, 0, units, 0 } +-- end +-- local f = { dflt = { dflt = true } } +-- local s = #sequences + 1 +-- local t = { +-- features = { fakemono = f }, +-- flags = { false, false, false, false }, +-- index = s, +-- name = "p_s_" .. s, +-- nofsteps = 1, +-- order = { "fakemono" }, +-- skiphash = false, +-- type = "gpos_single", +-- steps = { +-- { +-- format = "single", +-- coverage = coverage, +-- } +-- } +-- } +-- gposfeatures["fakemono"] = f +-- sequences[s] = t +-- end +-- +-- registerotffeature { +-- name = "fakemono", +-- description = "fake monospaced", +-- initializers = { +-- node = initialize, +-- }, +-- } + +-- -- for notosans but not general +-- +-- local v_local = interfaces and interfaces.variables and interfaces.variables["local"] or "local" +-- +-- local function initialize(tfmdata,key,value) +-- local characters = tfmdata.characters +-- local parameters = tfmdata.parameters +-- local oldchar = 32 +-- local newchar = 32 +-- if value == "locl" or value == v_local then +-- newchar = fonts.handlers.otf.getsubstitution(tfmdata,oldchar,"locl",true) or oldchar +-- elseif value == true then +-- -- use normal space +-- elseif value then +-- newchar = utfbyte(value) +-- else +-- return +-- end +-- local newchar = newchar and characters[newchar] +-- local newspace = newchar and newchar.width +-- if newspace > 0 then +-- parameters.space = newspace +-- parameters.space_stretch = newspace/2 +-- parameters.space_shrink = newspace/3 +-- parameters.extra_space = parameters.space_shrink +-- end +-- end +-- +-- registerotffeature { +-- name = 'space', -- true|false|locl|character +-- description = 'space settings', +-- manipulators = { +-- base = initialize, +-- node = initialize, +-- } +-- } + +-- -- 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/mkiv/font-imp-properties.lua b/tex/context/base/mkiv/font-imp-properties.lua new file mode 100644 index 000000000..8cd22af69 --- /dev/null +++ b/tex/context/base/mkiv/font-imp-properties.lua @@ -0,0 +1,128 @@ +if not modules then modules = { } end modules ['font-imp-properties'] = { + version = 1.001, + comment = "companion to font-ini.mkiv and hand-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local next, type, tonumber, select = next, type, tonumber, select +local byte, find, formatters = string.byte, string.find, string.formatters +local utfchar = utf.char +local sortedhash, sortedkeys, sort = table.sortedhash, table.sortedkeys, table.sort +local insert = table.insert + +local context = context +local fonts = fonts +local utilities = utilities + +local helpers = fonts.helpers + +local handlers = fonts.handlers +local hashes = fonts.hashes +local otf = handlers.otf +local afm = handlers.afm + +local registerotffeature = otf.features.register +local registerafmfeature = afm.features.register + +local fontdata = hashes.identifiers +local fontproperties = hashes.properties + +local constructors = fonts.constructors +local getprivate = constructors.getprivate + +local allocate = utilities.storage.allocate +local family_font = node.family_font + +local setmetatableindex = table.setmetatableindex + +local implement = interfaces.implement + +do + + local P, lpegpatterns, lpegmatch = lpeg.P, lpeg.patterns, lpeg.match + + local amount, stretch, shrink, extra + + local factor = lpegpatterns.unsigned + local space = lpegpatterns.space + local pattern = ( + (factor / function(n) amount = tonumber(n) or amount end) + + (P("+") + P("plus" )) * space^0 * (factor / function(n) stretch = tonumber(n) or stretch end) + + (P("-") + P("minus")) * space^0 * (factor / function(n) shrink = tonumber(n) or shrink end) + + ( P("extra")) * space^0 * (factor / function(n) extra = tonumber(n) or extra end) + + space^1 + )^1 + + local function initialize(tfmdata,key,value) + local characters = tfmdata.characters + local parameters = tfmdata.parameters + if type(value) == "string" then + local emwidth = parameters.quad + amount, stretch, shrink, extra = 0, 0, 0, false + lpegmatch(pattern,value) + if not extra then + if shrink ~= 0 then + extra = shrink + elseif stretch ~= 0 then + extra = stretch + else + extra = amount + end + end + parameters.space = amount * emwidth + parameters.space_stretch = stretch * emwidth + parameters.space_shrink = shrink * emwidth + parameters.extra_space = extra * emwidth + end + end + + -- 1.1 + 1.2 - 1.3 minus 1.4 plus 1.1 extra 1.4 -- last one wins + + registerotffeature { + name = "spacing", + description = "space settings", + manipulators = { + base = initialize, + node = initialize, + } + } + +end + +do + + local function initialize(tfmdata,value) + local properties = tfmdata.properties + if properties then + properties.identity = value == "vertical" and "vertical" or "horizontal" + end + end + + registerotffeature { + name = "identity", + description = "set font identity", + initializers = { + base = initialize, + node = initialize, + } + } + + local function initialize(tfmdata,value) + local properties = tfmdata.properties + if properties then + properties.writingmode = value == "vertical" and "vertical" or "horizontal" + end + end + + registerotffeature { + name = "writingmode", + description = "set font direction", + initializers = { + base = initialize, + node = initialize, + } + } + +end diff --git a/tex/context/base/mkiv/font-imp-quality.lua b/tex/context/base/mkiv/font-imp-quality.lua new file mode 100644 index 000000000..dc063f28a --- /dev/null +++ b/tex/context/base/mkiv/font-imp-quality.lua @@ -0,0 +1,477 @@ +if not modules then modules = { } end modules ['font-imp-quality'] = { + version = 1.001, + comment = "companion to font-ini.mkiv and hand-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local next, type, tonumber = next, type, tonumber +local byte = string.byte +local insert = table.insert + +local fonts = fonts +local utilities = utilities + +local handlers = fonts.handlers +local otf = handlers.otf +local afm = handlers.afm +local registerotffeature = otf.features.register +local registerafmfeature = afm.features.register + +local allocate = utilities.storage.allocate +local getparameters = utilities.parsers.getparameters + +local implement = interfaces and interfaces.implement + +local trace_protrusion = false trackers.register("fonts.protrusion", function(v) trace_protrusion = v end) +local trace_expansion = false trackers.register("fonts.expansion", function(v) trace_expansion = v end) + +local report_expansions = logs.reporter("fonts","expansions") +local report_protrusions = logs.reporter("fonts","protrusions") + +-- -- -- -- -- -- +-- shared +-- -- -- -- -- -- + +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 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]) + if class then + local class_vector = class.vector + local g_vectors = g_where and g_where.vectors + local f_vectors = f_where and f_where.vectors + local vector = (g_vectors and g_vectors[class_vector]) or (f_vectors and f_vectors[class_vector]) + return class, vector + end +end + +-- -- -- -- -- -- +-- expansion (hz) +-- -- -- -- -- -- + +local expansions = fonts.expansions or allocate() + +fonts.expansions = expansions + +local classes = expansions.classes or allocate() +local vectors = expansions.vectors or allocate() + +expansions.classes = classes +expansions.vectors = vectors + +-- beware, pdftex itself uses percentages * 10 +-- +-- todo: get rid of byte() here + +classes.preset = { stretch = 2, shrink = 2, step = .5, factor = 1 } + +classes['quality'] = { + stretch = 2, shrink = 2, step = .5, vector = 'default', factor = 1 +} + +vectors['default'] = { + [byte('A')] = 0.5, [byte('B')] = 0.7, [byte('C')] = 0.7, [byte('D')] = 0.5, [byte('E')] = 0.7, + [byte('F')] = 0.7, [byte('G')] = 0.5, [byte('H')] = 0.7, [byte('K')] = 0.7, [byte('M')] = 0.7, + [byte('N')] = 0.7, [byte('O')] = 0.5, [byte('P')] = 0.7, [byte('Q')] = 0.5, [byte('R')] = 0.7, + [byte('S')] = 0.7, [byte('U')] = 0.7, [byte('W')] = 0.7, [byte('Z')] = 0.7, + [byte('a')] = 0.7, [byte('b')] = 0.7, [byte('c')] = 0.7, [byte('d')] = 0.7, [byte('e')] = 0.7, + [byte('g')] = 0.7, [byte('h')] = 0.7, [byte('k')] = 0.7, [byte('m')] = 0.7, [byte('n')] = 0.7, + [byte('o')] = 0.7, [byte('p')] = 0.7, [byte('q')] = 0.7, [byte('s')] = 0.7, [byte('u')] = 0.7, + [byte('w')] = 0.7, [byte('z')] = 0.7, + [byte('2')] = 0.7, [byte('3')] = 0.7, [byte('6')] = 0.7, [byte('8')] = 0.7, [byte('9')] = 0.7, +} + +vectors['quality'] = vectors['default'] -- metatable ? + +local function initialize(tfmdata,value) + if value then + local class, vector = get_class_and_vector(tfmdata,value,"expansions") + if class then + if vector then + 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 %a, vector %a, factor %a, stretch %a, shrink %a, step %a", + value,class.vector,factor,stretch,shrink,step) + end + tfmdata.parameters.expansion = { + stretch = 10 * stretch, + shrink = 10 * shrink, + step = 10 * step, + factor = factor, + } + local data = characters and characters.data + for i, chr in next, tfmdata.characters do + local v = vector[i] + if data and not v then -- we could move the data test outside (needed for plain) + local d = data[i] + if d then + local s = d.shcode + if not s then + -- sorry + elseif type(s) == "table" then + v = ((vector[s[1]] or 0) + (vector[s[#s]] or 0)) / 2 + else + v = vector[s] or 0 + end + end + end + if v and v ~= 0 then + chr.expansion_factor = v*factor + else -- can be option + chr.expansion_factor = factor + end + end + elseif trace_expansion then + report_expansions("unknown vector %a in class %a",class.vector,value) + end + elseif trace_expansion then + report_expansions("unknown class %a",value) + end + end +end + +local specification = { + name = "expansion", + description = "apply hz optimization", + initializers = { + base = initialize, + node = initialize, + } +} + +registerotffeature(specification) +registerafmfeature(specification) + +fonts.goodies.register("expansions", function(...) return fonts.goodies.report("expansions", trace_expansion, ...) end) + +if context then + + implement { + name = "setupfontexpansion", + arguments = "2 strings", + actions = function(class,settings) getparameters(classes,class,'preset',settings) end + } + +end + +-- -- -- -- -- -- +-- protrusion +-- -- -- -- -- -- + +fonts.protrusions = allocate() +local protrusions = fonts.protrusions + +protrusions.classes = allocate() +protrusions.vectors = allocate() + +local classes = protrusions.classes +local vectors = protrusions.vectors + +-- the values need to be revisioned + +classes.preset = { factor = 1, left = 1, right = 1 } + +classes['pure'] = { + vector = 'pure', factor = 1 +} +classes['punctuation'] = { + vector = 'punctuation', factor = 1 +} +classes['alpha'] = { + vector = 'alpha', factor = 1 +} +classes['quality'] = { + vector = 'quality', factor = 1 +} + +vectors['pure'] = { + + [0x002C] = { 0, 1 }, -- comma + [0x002E] = { 0, 1 }, -- period + [0x003A] = { 0, 1 }, -- colon + [0x003B] = { 0, 1 }, -- semicolon + [0x002D] = { 0, 1 }, -- hyphen + [0x00AD] = { 0, 1 }, -- also 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 ۔ + +} + +vectors['punctuation'] = { + + [0x003F] = { 0, 0.20 }, -- ? + [0x00BF] = { 0, 0.20 }, -- ¿ + [0x0021] = { 0, 0.20 }, -- ! + [0x00A1] = { 0, 0.20 }, -- ¡ + [0x0028] = { 0.05, 0 }, -- ( + [0x0029] = { 0, 0.05 }, -- ) + [0x005B] = { 0.05, 0 }, -- [ + [0x005D] = { 0, 0.05 }, -- ] + [0x002C] = { 0, 0.70 }, -- comma + [0x002E] = { 0, 0.70 }, -- period + [0x003A] = { 0, 0.50 }, -- colon + [0x003B] = { 0, 0.50 }, -- semicolon + [0x002D] = { 0, 0.70 }, -- hyphen + [0x00AD] = { 0, 0.70 }, -- also hyphen + [0x2013] = { 0, 0.30 }, -- endash + [0x2014] = { 0, 0.20 }, -- emdash + [0x060C] = { 0, 0.70 }, -- arabic comma + [0x061B] = { 0, 0.50 }, -- arabic semicolon + [0x06D4] = { 0, 0.70 }, -- arabic full stop + [0x061F] = { 0, 0.20 }, -- ؟ + + -- todo: left and right quotes: .5 double, .7 single + + [0x2039] = { 0.70, 0.70 }, -- left single guillemet ‹ + [0x203A] = { 0.70, 0.70 }, -- right single guillemet › + [0x00AB] = { 0.50, 0.50 }, -- left guillemet « + [0x00BB] = { 0.50, 0.50 }, -- right guillemet » + + [0x2018] = { 0.70, 0.70 }, -- left single quotation mark ‘ + [0x2019] = { 0, 0.70 }, -- right single quotation mark ’ + [0x201A] = { 0.70, 0 }, -- single low-9 quotation mark , + [0x201B] = { 0.70, 0 }, -- single high-reversed-9 quotation mark ‛ + [0x201C] = { 0.50, 0.50 }, -- left double quotation mark “ + [0x201D] = { 0, 0.50 }, -- right double quotation mark ” + [0x201E] = { 0.50, 0 }, -- double low-9 quotation mark „ + [0x201F] = { 0.50, 0 }, -- double high-reversed-9 quotation mark ‟ + +} + +vectors['alpha'] = { + + [byte("A")] = { .05, .05 }, + [byte("F")] = { 0, .05 }, + [byte("J")] = { .05, 0 }, + [byte("K")] = { 0, .05 }, + [byte("L")] = { 0, .05 }, + [byte("T")] = { .05, .05 }, + [byte("V")] = { .05, .05 }, + [byte("W")] = { .05, .05 }, + [byte("X")] = { .05, .05 }, + [byte("Y")] = { .05, .05 }, + + [byte("k")] = { 0, .05 }, + [byte("r")] = { 0, .05 }, + [byte("t")] = { 0, .05 }, + [byte("v")] = { .05, .05 }, + [byte("w")] = { .05, .05 }, + [byte("x")] = { .05, .05 }, + [byte("y")] = { .05, .05 }, + +} + +vectors['quality'] = table.merged( + vectors['punctuation'], + vectors['alpha'] +) + +-- As this is experimental code, users should not depend on it. The implications are still +-- discussed on the ConTeXt Dev List and we're not sure yet what exactly the spec is (the +-- next code is tested with a gyre font patched by / fea file made by Khaled Hosny). The +-- double trick should not be needed it proper hanging punctuation is used in which case +-- values < 1 can be used. +-- +-- preferred (in context, usine vectors): +-- +-- \definefontfeature[whatever][default][mode=node,protrusion=quality] +-- +-- using lfbd and rtbd, with possibibility to enable only one side : +-- +-- \definefontfeature[whocares][default][mode=node,protrusion=yes, opbd=yes,script=latn] +-- \definefontfeature[whocares][default][mode=node,protrusion=right,opbd=yes,script=latn] +-- +-- idem, using multiplier +-- +-- \definefontfeature[whocares][default][mode=node,protrusion=2,opbd=yes,script=latn] +-- \definefontfeature[whocares][default][mode=node,protrusion=double,opbd=yes,script=latn] +-- +-- idem, using named feature file (less frozen): +-- +-- \definefontfeature[whocares][default][mode=node,protrusion=2,opbd=yes,script=latn,featurefile=texgyrepagella-regularxx.fea] + +classes['double'] = { -- for testing opbd + factor = 2, left = 1, right = 1, +} + +local function map_opbd_onto_protrusion(tfmdata,value,opbd) + local characters = tfmdata.characters + local descriptions = tfmdata.descriptions + local properties = tfmdata.properties + local resources = tfmdata.resources + local rawdata = tfmdata.shared.rawdata + local lookuphash = rawdata.lookuphash + local lookuptags = resources.lookuptags + local script = properties.script + local language = properties.language + local done, factor, left, right = false, 1, 1, 1 + local class = classes[value] + if class then + factor = class.factor or 1 + left = class.left or 1 + right = class.right or 1 + else + factor = tonumber(value) or 1 + end + if opbd ~= "right" then + local validlookups, lookuplist = otf.collectlookups(rawdata,"lfbd",script,language) + if validlookups then + for i=1,#lookuplist do + local lookup = lookuplist[i] + local steps = lookup.steps + if steps then + if trace_protrusion then + report_protrusions("setting left using lfbd") + end + for i=1,#steps do + local step = steps[i] + local coverage = step.coverage + if coverage then + for k, v in next, coverage do + -- local p = - v[3] / descriptions[k].width-- or 1 ~= 0 too but the same + local p = - (v[1] / 1000) * factor * left + characters[k].left_protruding = p + if trace_protrusion then + report_protrusions("lfbd -> %C -> %p",k,p) + end + end + end + end + done = true + end + end + end + end + if opbd ~= "left" then + local validlookups, lookuplist = otf.collectlookups(rawdata,"rtbd",script,language) + if validlookups then + for i=1,#lookuplist do + local lookup = lookuplist[i] + local steps = lookup.steps + if steps then + if trace_protrusion then + report_protrusions("setting right using rtbd") + end + for i=1,#steps do + local step = steps[i] + local coverage = step.coverage + if coverage then + for k, v in next, coverage do + -- local p = v[3] / descriptions[k].width -- or 3 + local p = (v[1] / 1000) * factor * right + characters[k].right_protruding = p + if trace_protrusion then + report_protrusions("rtbd -> %C -> %p",k,p) + end + end + end + end + end + done = true + end + end + end +end + +-- The opbd test is just there because it was discussed on the context development list. However, +-- the mentioned fxlbi.otf font only has some kerns for digits. So, consider this feature not supported +-- till we have a proper test font. + +local function initialize(tfmdata,value) + if value then + local opbd = tfmdata.shared.features.opbd + if opbd then + -- possible values: left right both yes no (experimental) + map_opbd_onto_protrusion(tfmdata,value,opbd) + else + local class, vector = get_class_and_vector(tfmdata,value,"protrusions") + if class then + if vector then + local factor = class.factor or 1 + local left = class.left or 1 + local right = class.right or 1 + if trace_protrusion then + report_protrusions("setting class %a, vector %a, factor %a, left %a, right %a", + value,class.vector,factor,left,right) + end + local data = characters.data + local emwidth = tfmdata.parameters.quad + tfmdata.parameters.protrusion = { + factor = factor, + left = left, + right = right, + } + for i, chr in next, tfmdata.characters do + local v, pl, pr = vector[i], nil, nil + if v then + pl, pr = v[1], v[2] + else + local d = data[i] + if d then + local s = d.shcode + if not s then + -- sorry + elseif type(s) == "table" then + local vl, vr = vector[s[1]], vector[s[#s]] + if vl then pl = vl[1] end + if vr then pr = vr[2] end + else + v = vector[s] + if v then + pl, pr = v[1], v[2] + end + end + end + 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 + elseif trace_protrusion then + report_protrusions("unknown vector %a in class %a",class.vector,value) + end + elseif trace_protrusion then + report_protrusions("unknown class %a",value) + end + end + end +end + +local specification = { + name = "protrusion", + description = "l/r margin character protrusion", + initializers = { + base = initialize, + node = initialize, + } +} + +registerotffeature(specification) +registerafmfeature(specification) + +fonts.goodies.register("protrusions", function(...) return fonts.goodies.report("protrusions", trace_protrusion, ...) end) + +if context then + + implement { + name = "setupfontprotrusion", + arguments = "2 strings", + actions = function(class,settings) getparameters(classes,class,'preset',settings) end + } + +end diff --git a/tex/context/base/mkiv/font-imp-reorder.lua b/tex/context/base/mkiv/font-imp-reorder.lua new file mode 100644 index 000000000..250aa47c6 --- /dev/null +++ b/tex/context/base/mkiv/font-imp-reorder.lua @@ -0,0 +1,172 @@ +if not modules then modules = { } end modules ['font-imp-reorder'] = { + version = 1.001, + comment = "companion to font-ini.mkiv and hand-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local next = next +local find = string.find +local sortedhash, sortedkeys, sort = table.sortedhash, table.sortedkeys, table.sort + +local fonts = fonts +local otf = fonts.handlers.otf +local registerotffeature = otf.features.register + +-- This is a rather special test-only feature that I added for the sake of testing +-- Idris's husayni. We wanted to know if uniscribe obeys the order of lookups in a +-- font, in spite of what the description of handling arabic suggests. And indeed, +-- mixed-in lookups of other features (like all these ss* in husayni) are handled +-- the same in context as in uniscribe. If one sets reorderlookups=arab then we sort +-- according to the "assumed" order so e.g. the ss* move to after the standard +-- features. The observed difference in rendering is an indication that uniscribe is +-- quite faithful to the font (while e.g. tests with the hb plugin demonstrate some +-- interference, apart from some hard coded init etc expectations). Anyway, it means +-- that we're okay with the (generic) node processor. A pitfall is that in context +-- we can actually control more, so we can trigger an analyze pass with e.g. +-- dflt/dflt while the libraries depend on the script settings for that. Uniscribe +-- probably also parses the string and when seeing arabic will follow a different +-- code path, although it seems to treat all features equal. + +local trace_reorder = trackers.register("fonts.reorderlookups",function(v) trace_reorder = v end) +local report_reorder = logs.reporter("fonts","reorder") + +local vectors = { } + +vectors.arab = { + gsub = { + ccmp = 1, + isol = 2, + fina = 3, + medi = 4, + init = 5, + rlig = 6, + rclt = 7, + calt = 8, + liga = 9, + dlig = 10, + cswh = 11, + mset = 12, + }, + gpos = { + curs = 1, + kern = 2, + mark = 3, + mkmk = 4, + }, +} + +local function compare(a,b) + local what_a = a.what + local what_b = b.what + if what_a ~= what_b then + return a.index < b.index + end + local when_a = a.when + local when_b = b.when + if when_a == when_b then + return a.index < b.index + else + return when_a < when_b + end +end + +function otf.reorderlookups(tfmdata,vector) + local order = vectors[vector] + if not order then + return + end + local oldsequences = tfmdata.resources.sequences + if oldsequences then + local sequences = { } + for i=1,#oldsequences do + sequences[i] = oldsequences[i] + end + for i=1,#sequences do + local s = sequences[i] + local features = s.features + local kind = s.type + local index = s.index + if features then + local when + local what + for feature in sortedhash(features) do + if not what then + what = find(kind,"^gsub") and "gsub" or "gpos" + end + local newwhen = order[what][feature] + if not newwhen then + -- skip + elseif not when then + when = newwhen + elseif newwhen < when then + when = newwhen + end + end + s.ondex = s.index + s.index = i + s.what = what == "gsub" and 1 or 2 + s.when = when or 99 + else + s.ondex = s.index + s.index = i + s.what = 1 + s.when = 99 + end + end + sort(sequences,compare) + local swapped = 0 + for i=1,#sequences do + local sequence = sequences[i] + local features = sequence.features + if features then + local index = sequence.index + if index ~= i then + swapped = swapped + 1 + end + if trace_reorder then + if swapped == 1 then + report_reorder() + report_reorder("start swapping lookups in font %!font:name!",tfmdata) + report_reorder() + report_reorder("gsub order: % t",table.swapped(order.gsub)) + report_reorder("gpos order: % t",table.swapped(order.gpos)) + report_reorder() + end + report_reorder("%03i : lookup %03i, type %s, sorted %2i, moved %s, % t", + i,index,sequence.what == 1 and "gsub" or "gpos",sequence.when or 99, + (index > i and "-") or (index < i and "+") or "=",sortedkeys(features)) + end + end + sequence.what = nil + sequence.when = nil + sequence.index = sequence.ondex + end + if swapped > 0 then + if trace_reorder then + report_reorder() + report_reorder("stop swapping lookups, %i lookups swapped",swapped) + report_reorder() + end + tfmdata.shared.reorderedsequences = sequences + end + end +end + +-- maybe delay till ra is filled + +local function initialize(tfmdata,key,value) + if value then + otf.reorderlookups(tfmdata,value) + end +end + +registerotffeature { + name = "reorderlookups", + description = "reorder lookups", + manipulators = { + base = initialize, + node = initialize, + } +} diff --git a/tex/context/base/mkiv/font-imp-tex.lua b/tex/context/base/mkiv/font-imp-tex.lua new file mode 100644 index 000000000..b4b9a7b69 --- /dev/null +++ b/tex/context/base/mkiv/font-imp-tex.lua @@ -0,0 +1,144 @@ +if not modules then modules = { } end modules ['font-imp-tex'] = { + 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 next = next + +local fonts = fonts +local otf = fonts.handlers.otf +local registerotffeature = otf.features.register +local addotffeature = otf.addfeature + +-- tlig (we need numbers for some fonts so ...) + +local specification = { + type = "ligature", + order = { "tlig" }, + prepend = true, + data = { + -- endash = "hyphen hyphen", + -- emdash = "hyphen hyphen hyphen", + [0x2013] = { 0x002D, 0x002D }, + [0x2014] = { 0x002D, 0x002D, 0x002D }, + -- quotedblleft = "quoteleft quoteleft", + -- quotedblright = "quoteright quoteright", + -- quotedblleft = "grave grave", + -- quotedblright = "quotesingle quotesingle", + -- quotedblbase = "comma comma", + }, +} + +addotffeature("tlig",specification) + +registerotffeature { + -- this makes it a known feature (in tables) + name = "tlig", + description = "tex ligatures", +} + +-- trep + +local specification = { + type = "substitution", + order = { "trep" }, + prepend = true, + data = { + -- [0x0022] = 0x201D, + [0x0027] = 0x2019, + -- [0x0060] = 0x2018, + }, +} + +addotffeature("trep",specification) + +registerotffeature { + -- this makes it a known feature (in tables) + name = "trep", + description = "tex replacements", +} + +-- some day this will be moved to font-imp-scripts.lua + +-- anum + +local anum_arabic = { + [0x0030] = 0x0660, + [0x0031] = 0x0661, + [0x0032] = 0x0662, + [0x0033] = 0x0663, + [0x0034] = 0x0664, + [0x0035] = 0x0665, + [0x0036] = 0x0666, + [0x0037] = 0x0667, + [0x0038] = 0x0668, + [0x0039] = 0x0669, +} + +local anum_persian = { + [0x0030] = 0x06F0, + [0x0031] = 0x06F1, + [0x0032] = 0x06F2, + [0x0033] = 0x06F3, + [0x0034] = 0x06F4, + [0x0035] = 0x06F5, + [0x0036] = 0x06F6, + [0x0037] = 0x06F7, + [0x0038] = 0x06F8, + [0x0039] = 0x06F9, +} + +local function valid(data) + local features = data.resources.features + if features then + for k, v in next, features do + for k, v in next, v do + if v.arab then + return true + end + end + end + end +end + +local specification = { + { + type = "substitution", + features = { arab = { urd = true, dflt = true } }, + order = { "anum" }, + data = anum_arabic, + valid = valid, + }, + { + type = "substitution", + features = { arab = { urd = true } }, + order = { "anum" }, + data = anum_persian, + valid = valid, + }, +} + +addotffeature("anum",specification) + +registerotffeature { + -- this makes it a known feature (in tables) + name = "anum", + description = "arabic digits", +} + +-- -- example: +-- +-- fonts.handlers.otf.addfeature { +-- name = "hangulfix", +-- type = "substitution", +-- features = { ["hang"] = { ["*"] = true } }, +-- data = { +-- [0x1160] = 0x119E, +-- }, +-- order = { "hangulfix" }, +-- flags = { }, +-- prepend = true, +-- }) diff --git a/tex/context/base/mkiv/font-imp-tracing.lua b/tex/context/base/mkiv/font-imp-tracing.lua new file mode 100644 index 000000000..e6de494df --- /dev/null +++ b/tex/context/base/mkiv/font-imp-tracing.lua @@ -0,0 +1,171 @@ +if not modules then modules = { } end modules ['font-imp-tracing'] = { + version = 1.001, + comment = "companion to font-ini.mkiv and hand-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local next, type = next, type +local formatters = string.formatters + +local fonts = fonts + +local handlers = fonts.handlers +local registerotffeature = handlers.otf.features.register +local registerafmfeature = handlers.afm.features.register + +local settings_to_array = utilities.parsers.settings_to_array +local setmetatableindex = table.setmetatableindex + +local helpers = fonts.helpers +local prependcommands = helpers.prependcommands +local charcommand = helpers.commands.char + +local variables = interfaces.variables + +local v_background = variables.background +local v_frame = variables.frame +local v_empty = variables.empty +local v_none = variables.none + +-- for zhichu chen (see mailing list archive): we might add a few more variants +-- in due time +-- +-- \definefontfeature[boxed][default][boundingbox=yes] % paleblue +-- +-- maybe: +-- +-- \definecolor[DummyColor][s=.75,t=.5,a=1] {\DummyColor test} \nopdfcompression +-- +-- local gray = { "pdf", "origin", "/Tr1 gs .75 g" } +-- local black = { "pdf", "origin", "/Tr0 gs 0 g" } + +-- boundingbox={yes|background|frame|empty|} + +local bp = number.dimenfactors.bp +local r = 16384 * bp -- 65536 // 4 +local f_1 = formatters["%.6F w 0 %.6F %.6F %.6F re f"] +local f_2 = formatters["[] 0 d 0 J %.6F w %.6F %.6F %.6F %.6F re S"] + +local backcache = setmetatableindex(function(t,h) + local h = h * bp + local v = setmetatableindex(function(t,d) + local d = d * bp + local v = setmetatableindex(function(t,w) + local v = { "pdf", "origin", f_1(r,-d,w*bp,h+d) } + t[w] = v + return v + end) + t[d] = v + return v + end) + t[h] = v + return v +end) + +local forecache = setmetatableindex(function(t,h) + local h = h * bp + local v = setmetatableindex(function(t,d) + local d = d * bp + local v = setmetatableindex(function(t,w) + -- the frame goes through the boundingbox + local v = { "pdf", "origin", f_2(r,r/2,-d+r/2,w*bp-r,h+d-r) } + t[w] = v + return v + end) + t[d] = v + return v + end) + t[h] = v + return v +end) + +local startcolor = nil +local stopcolor = nil + +local function initialize(tfmdata,key,value) + if value then + if not backcolors then + local vfspecials = backends.pdf.tables.vfspecials + startcolor = vfspecials.startcolor + stopcolor = vfspecials.stopcolor + end + local characters = tfmdata.characters + local rulecache = backcache + local showchar = true + local color = "palegray" + if type(value) == "string" then + value = settings_to_array(value) + for i=1,#value do + local v = value[i] + if v == v_frame then + rulecache = forecache + elseif v == v_background then + rulecache = backcache + elseif v == v_empty then + showchar = false + elseif v == v_none then + color = nil + else + color = v + end + end + end + local gray = color and startcolor(color) or nil + local black = gray and stopcolor or nil + for unicode, character in next, characters do + local width = character.width or 0 + local height = character.height or 0 + local depth = character.depth or 0 + local rule = rulecache[height][depth][width] + if showchar then + local commands = character.commands + if commands then + if gray then + character.commands = prependcommands ( + commands, gray, rule, black + ) + else + character.commands = prependcommands ( + commands, rule + ) + end + else + local char = charcommand[unicode] + if gray then + character.commands = { + gray, rule, black, char + } + else + character.commands = { + rule, char + } + end + end + else + if gray then + character.commands = { + gray, rule, black + } + else + character.commands = { + rule + } + end + end + end + end +end + +local specification = { + name = "boundingbox", + description = "show boundingbox", + manipulators = { + base = initialize, + node = initialize, + } +} + +registerotffeature(specification) +registerafmfeature(specification) diff --git a/tex/context/base/mkiv/font-imp-unicode.lua b/tex/context/base/mkiv/font-imp-unicode.lua new file mode 100644 index 000000000..9e1e3465e --- /dev/null +++ b/tex/context/base/mkiv/font-imp-unicode.lua @@ -0,0 +1,80 @@ +if not modules then modules = { } end modules ['font-imp-unicode'] = { + version = 1.001, + comment = "companion to font-ini.mkiv and hand-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local next = next + +local fonts = fonts +local helpers = fonts.helpers +local constructors = fonts.constructors +local registerotffeature = fonts.handlers.otf.features.register + +local extraprivates = helpers.extraprivates +local addprivate = helpers.addprivate + +local function initialize(tfmdata) + for i=1,#extraprivates do + local e = extraprivates[i] + local c = e[2](tfmdata) + if c then + addprivate(tfmdata, e[1], c) + end + end +end + +constructors.newfeatures.otf.register { + name = "extraprivates", + description = "extra privates", + default = true, + manipulators = { + base = initialize, + node = initialize, + } +} + +local tounicode = fonts.mappings.tounicode + +local function initialize(tfmdata,key,value) + if value == "ligatures" then + local private = fonts.constructors and fonts.constructors.privateoffset or 0xF0000 + local collected = fonts.handlers.otf.readers.getcomponents(tfmdata.shared.rawdata) + if collected and next(collected)then + for unicode, char in next, tfmdata.characters do + local u = collected[unicode] + if u then + local n = #u + for i=1,n do + if u[i] > private then + n = 0 + break + end + end + if n > 0 then + if n == 1 then + u = u[1] + end + char.unicode = u + char.tounicode = tounicode(u) + end + end + end + end + end +end + +-- forceunicodes=ligatures : aggressive lig resolving (e.g. for emoji) +-- +-- kind of like: \enabletrackers[fonts.mapping.forceligatures] + +registerotffeature { + name = "forceunicodes", + description = "forceunicodes", + manipulators = { + base = initialize, + node = initialize, + } +} diff --git a/tex/context/base/mkiv/font-ini.mkvi b/tex/context/base/mkiv/font-ini.mkvi index 693182919..f81d751f3 100644 --- a/tex/context/base/mkiv/font-ini.mkvi +++ b/tex/context/base/mkiv/font-ini.mkvi @@ -1727,7 +1727,8 @@ \font_helpers_process_style_list{\font_helpers_define_unknown_check_definitions{#body}}% \ifconditional\c_font_defining_state \ifconditional\c_font_defining_environment_state\else - \showmessage\m!fonts{14}{#body}% main + %\showmessage\m!fonts{14}{#body}% main + \clf_registerunknownbodysize{#body}% \fi \setfalse\c_font_defining_state \font_helpers_register_fontbody{#body}% @@ -1741,13 +1742,6 @@ \fi \fi} -% \def\font_helpers_define_unknown_check_sizes#body#relativesize% -% {\ifcsname\??fontenvironments\s!default#relativesize\endcsname % fontclass ? -% % how \lastnamedcs here -% \expandafter\normalizebodyfontsize\csname\??fontenvironments#body#relativesize\endcsname{\csname\??fontenvironments\s!default#relativesize\endcsname\dimexpr#body\relax}% -% \settrue\c_font_defining_state -% \fi} - \def\font_helpers_define_unknown_check_sizes#body#relativesize% {\ifcsname\??fontenvironments\s!default#relativesize\endcsname % fontclass ? \expandafter\normalizebodyfontsize\csname\??fontenvironments#body#relativesize\endcsname{\csname\??fontenvironments\s!default#relativesize\endcsname\dimexpr#body\relax}% diff --git a/tex/context/base/mkiv/font-lib.mkvi b/tex/context/base/mkiv/font-lib.mkvi index 24ab68781..7f8601f4e 100644 --- a/tex/context/base/mkiv/font-lib.mkvi +++ b/tex/context/base/mkiv/font-lib.mkvi @@ -26,12 +26,17 @@ % the otf font loader: +% helpers + + \registerctxluafile{font-otr}{optimize} % opentype fontloader \registerctxluafile{font-web}{} % opentype fontloader \registerctxluafile{font-cff}{optimize} % quadratic outlines \registerctxluafile{font-ttf}{optimize} % cubic outlines \registerctxluafile{font-dsp}{optimize} % ... for this one \registerctxluafile{font-hsh}{} % hashes used by context +\registerctxluafile{font-vfc}{} +\registerctxluafile{font-prv}{} % needs hashes \registerctxluafile{font-nod}{} \registerctxluafile{font-oti}{} % otf initialization \registerctxluafile{font-ott}{} % otf tables (first) @@ -87,7 +92,21 @@ \registerctxluafile{font-def}{} \registerctxluafile{font-ctx}{} % after def as it overloads -\registerctxluafile{font-ext}{} +% extensions, order matters + +\registerctxluafile{font-imp-ligatures}{} +\registerctxluafile{font-imp-tex}{} +\registerctxluafile{font-imp-reorder}{} +\registerctxluafile{font-imp-properties}{} +\registerctxluafile{font-imp-unicode}{} +\registerctxluafile{font-imp-math}{} +\registerctxluafile{font-imp-notused}{} +\registerctxluafile{font-imp-effects}{} +\registerctxluafile{font-imp-quality}{} +\registerctxluafile{font-imp-italics}{} +\registerctxluafile{font-imp-dimensions}{} +\registerctxluafile{font-imp-tracing}{} % comes last! + \registerctxluafile{font-fbk}{} \registerctxluafile{font-aux}{} diff --git a/tex/context/base/mkiv/font-map.lua b/tex/context/base/mkiv/font-map.lua index 66cf2db39..b44e20ede 100644 --- a/tex/context/base/mkiv/font-map.lua +++ b/tex/context/base/mkiv/font-map.lua @@ -168,55 +168,84 @@ local function tounicode16sequence(unicodes) return concat(t) end -local function tounicode(unicode) - if type(unicode) == "table" then - local t = { } - for l=1,#unicode do - local u = unicode[l] - if u < 0xD7FF or (u > 0xDFFF and u <= 0xFFFF) then - t[l] = f_single(u) - else - u = u - 0x10000 - t[l] = f_double(rshift(u,10)+0xD800,u%1024+0xDC00) - end - end - return concat(t) - else - if unicode < 0xD7FF or (unicode > 0xDFFF and unicode <= 0xFFFF) then - return f_single(unicode) - else - unicode = unicode - 0x10000 - return f_double(rshift(unicode,10)+0xD800,unicode%1024+0xDC00) - end - end -end - --- no real gain on runs - --- local hash = table.setmetatableindex(function(t,u) --- local v --- if u < 0xD7FF or (u > 0xDFFF and u <= 0xFFFF) then --- v = f_single(u) +-- local function tounicode(unicode) +-- if type(unicode) == "table" then +-- local t = { } +-- for l=1,#unicode do +-- local u = unicode[l] +-- if u < 0xD7FF or (u > 0xDFFF and u <= 0xFFFF) then +-- t[l] = f_single(u) +-- else +-- u = u - 0x10000 +-- t[l] = f_double(rshift(u,10)+0xD800,u%1024+0xDC00) +-- end +-- end +-- return concat(t) -- else --- u = u - 0x10000 --- v = f_double(rshift(u,10)+0xD800,u%1024+0xDC00) +-- if unicode < 0xD7FF or (unicode > 0xDFFF and unicode <= 0xFFFF) then +-- return f_single(unicode) +-- else +-- unicode = unicode - 0x10000 +-- return f_double(rshift(unicode,10)+0xD800,unicode%1024+0xDC00) +-- end -- end --- t[u] = v --- return v --- end) --- --- local function tounicode(unicode,name) +-- end + +local unknown = f_single(0xFFFD) + +-- local function tounicode(unicode) -- if type(unicode) == "table" then -- local t = { } -- for l=1,#unicode do --- t[l] = hash[unicode[l]] +-- t[l] = tounicode(unicode[l]) -- end -- return concat(t) +-- elseif unicode >= 0x00E000 and unicode <= 0x00F8FF then +-- return unknown +-- elseif unicode >= 0x0F0000 and unicode <= 0x0FFFFF then +-- return unknown +-- elseif unicode >= 0x100000 and unicode <= 0x10FFFF then +-- return unknown +-- elseif unicode < 0xD7FF or (unicode > 0xDFFF and unicode <= 0xFFFF) then +-- return f_single(unicode) -- else --- return hash[unicode] +-- unicode = unicode - 0x10000 +-- return f_double(rshift(unicode,10)+0xD800,unicode%1024+0xDC00) -- end -- end +local hash = table.setmetatableindex(function(t,k) + local v + if k >= 0x00E000 and k <= 0x00F8FF then + v = unknown + elseif k >= 0x0F0000 and k <= 0x0FFFFF then + v = unknown + elseif k >= 0x100000 and k <= 0x10FFFF then + v = unknown + elseif k < 0xD7FF or (k > 0xDFFF and k <= 0xFFFF) then + v = f_single(k) + else + v = k - 0x10000 + v = f_double(rshift(k,10)+0xD800,k%1024+0xDC00) + end + t[k] = v + return v +end) + +table.makeweak(hash) + +local function tounicode(unicode,name) + if type(unicode) == "table" then + local t = { } + for l=1,#unicode do + t[l] = hash[unicode[l]] + end + return concat(t) + else + return hash[unicode] + end +end + local function fromunicode16(str) if #str == 4 then return tonumber(str,16) diff --git a/tex/context/base/mkiv/font-mat.mkvi b/tex/context/base/mkiv/font-mat.mkvi index 0134f3fe6..64810d327 100644 --- a/tex/context/base/mkiv/font-mat.mkvi +++ b/tex/context/base/mkiv/font-mat.mkvi @@ -263,12 +263,12 @@ \fi} \def\font_helpers_bidirectional_mathstrategy_nop_changed - {\textfont \c_font_fam_mr_rl\textfont \c_font_fam_mr - \scriptfont \c_font_fam_mr_rl\scriptfont \c_font_fam_mr - \scriptscriptfont\c_font_fam_mr_rl\scriptscriptfont\c_font_fam_mr - \textfont \c_font_fam_mr_lr\textfont \c_font_fam_mr + {\textfont \c_font_fam_mr_lr\textfont \c_font_fam_mr \scriptfont \c_font_fam_mr_lr\scriptfont \c_font_fam_mr - \scriptscriptfont\c_font_fam_mr_lr\scriptscriptfont\c_font_fam_mr} + \scriptscriptfont\c_font_fam_mr_lr\scriptscriptfont\c_font_fam_mr + \textfont \c_font_fam_mr_rl\textfont \c_font_fam_mr + \scriptfont \c_font_fam_mr_rl\scriptfont \c_font_fam_mr + \scriptscriptfont\c_font_fam_mr_rl\scriptscriptfont\c_font_fam_mr} \appendtoks \ifconditional\c_font_bidirectional_mathstrategy @@ -313,12 +313,12 @@ {\textfont \c_font_fam_mb \textfont \c_font_fam_mr \scriptfont \c_font_fam_mb \scriptfont \c_font_fam_mr \scriptscriptfont\c_font_fam_mb \scriptscriptfont\c_font_fam_mr - \textfont \c_font_fam_mb_rl\textfont \c_font_fam_mr_rl - \scriptfont \c_font_fam_mb_rl\scriptfont \c_font_fam_mr_rl - \scriptscriptfont\c_font_fam_mb_rl\scriptscriptfont\c_font_fam_mr_rl \textfont \c_font_fam_mb_lr\textfont \c_font_fam_mr_lr \scriptfont \c_font_fam_mb_lr\scriptfont \c_font_fam_mr_lr - \scriptscriptfont\c_font_fam_mb_lr\scriptscriptfont\c_font_fam_mr_lr} + \scriptscriptfont\c_font_fam_mb_lr\scriptscriptfont\c_font_fam_mr_lr + \textfont \c_font_fam_mb_rl\textfont \c_font_fam_mr_rl + \scriptfont \c_font_fam_mb_rl\scriptfont \c_font_fam_mr_rl + \scriptscriptfont\c_font_fam_mb_rl\scriptscriptfont\c_font_fam_mr_rl} \def\font_helpers_apply_complete_bold_mathstrategy {\ifconditional\c_font_complete_bold_mathstrategy @@ -425,13 +425,16 @@ \ifdefined\mathdefault \else \let\mathdefault\relax \fi +\newconditional\c_math_bold + \unexpanded\def\mr % math regular {\ifmmode \font_helpers_synchronize_math_family_mr \else \font_helpers_set_current_font_alternative\s!mr \fi - \mathdefault} + \mathdefault + \setfalse\c_math_bold} \unexpanded\def\mb % math bold {\ifmmode @@ -439,12 +442,17 @@ \else \font_helpers_set_current_font_alternative\s!mb \fi - \mathdefault} + \mathdefault + \settrue\c_math_bold} \appendtoks \font_helpers_synchronize_math_family % auto bold \to \everymathematics +\appendtoks + \ifconditional\c_math_bold\mb\fi +\to \everymathematics + %D \macros %D {bigmath,nobigmath} %D diff --git a/tex/context/base/mkiv/font-nod.lua b/tex/context/base/mkiv/font-nod.lua index 2670a924b..cdceb98a2 100644 --- a/tex/context/base/mkiv/font-nod.lua +++ b/tex/context/base/mkiv/font-nod.lua @@ -79,7 +79,6 @@ local copy_node_list = nuts.copy_list local hpack_node_list = nuts.hpack local flush_node_list = nuts.flush_list local traverse_nodes = nuts.traverse ------ traverse_id = nuts.traverse_id local protect_glyphs = nuts.protect_glyphs local nodepool = nuts.pool @@ -392,8 +391,7 @@ function step_tracers.codes(i,command,space) if w then context.startcolor(colors[what]) context("%s:",what) - for c in traverse_nodes(w) do - local id = getid(c) + for c, id in traverse_nodes(w) do if id == glyph_code then showchar(c) else @@ -501,9 +499,12 @@ local threshold = 65536 -- 1pt local function toutf(list,result,nofresult,stopcriterium,nostrip) if list then - for n in traverse_nodes(tonut(list)) do - local c, id = isglyph(n) - if c then +-- for n in traverse_nodes(tonut(list)) do +-- local c, id = isglyph(n) +-- if c then + for n, id in traverse_nodes(tonut(list)) do + if id == glyph_code then + local c = getchar(n) local components = getcomponents(n) if components then result, nofresult = toutf(components,result,nofresult,false,true) diff --git a/tex/context/base/mkiv/font-ocl.lua b/tex/context/base/mkiv/font-ocl.lua index b17cf991d..7dfcd129e 100644 --- a/tex/context/base/mkiv/font-ocl.lua +++ b/tex/context/base/mkiv/font-ocl.lua @@ -13,13 +13,20 @@ local round, max = math.round, math.round local sortedkeys, sortedhash = table.sortedkeys, table.sortedhash local setmetatableindex = table.setmetatableindex -local formatters = string.formatters -local tounicode = fonts.mappings.tounicode +local formatters = string.formatters +local tounicode = fonts.mappings.tounicode -local otf = fonts.handlers.otf +local helpers = fonts.helpers -local f_color = formatters["%.3f %.3f %.3f rg"] -local f_gray = formatters["%.3f g"] +local charcommand = helpers.commands.char +local rightcommand = helpers.commands.right +local leftcommand = helpers.commands.left +local downcommand = helpers.commands.down + +local otf = fonts.handlers.otf + +local f_color = formatters["%.3f %.3f %.3f rg"] +local f_gray = formatters["%.3f g"] if context then @@ -136,7 +143,7 @@ end -- -- only shows the first glyph in acrobat and nothing more. No problem with other -- -- renderers. -- --- local function initializecolr(tfmdata,kind,value) -- hm, always value +-- local function initialize(tfmdata,kind,value) -- hm, always value -- if value then -- local resources = tfmdata.resources -- local palettes = resources.colorpalettes @@ -161,11 +168,6 @@ end -- tfmdata.fonts = { -- { id = 0 } -- } --- local widths = setmetatableindex(function(t,k) --- local v = { "right", -k } --- t[k] = v --- return v --- end) -- -- -- local getactualtext = otf.getactualtext -- local default = colorvalues[#colorvalues] @@ -173,12 +175,6 @@ end -- local actualb = { "pdf", "page", b } -- saves tables -- local actuale = { "pdf", "page", e } -- saves tables -- -- --- local cache = setmetatableindex(function(t,k) --- local v = { "char", k } -- could he a weak shared hash --- t[k] = v --- return v --- end) --- -- -- for unicode, character in next, characters do -- local description = descriptions[unicode] -- if description then @@ -187,7 +183,7 @@ end -- local u = description.unicode or characters[unicode].unicode -- local w = character.width or 0 -- local s = #colorlist --- local goback = w ~= 0 and widths[w] or nil -- needs checking: are widths the same +-- local goback = w ~= 0 and leftcommand[w] or nil -- needs checking: are widths the same -- local t = { -- start, -- not u and actualb or { "pdf", "page", (getactualtext(tounicode(u))) } @@ -202,7 +198,7 @@ end -- n = n + 1 t[n] = v -- l = v -- end --- n = n + 1 t[n] = cache[entry.slot] +-- n = n + 1 t[n] = charcommand[entry.slot] -- if s > 1 and i < s and goback then -- n = n + 1 t[n] = goback -- end @@ -221,7 +217,7 @@ end -- -- Here we have no color change in BT .. ET and more q Q pairs but even then acrobat -- -- fails displaying the overlays correctly. Other renderers do it right. -local function initializecolr(tfmdata,kind,value) -- hm, always value +local function initialize(tfmdata,kind,value) -- hm, always value if value then local resources = tfmdata.resources local palettes = resources.colorpalettes @@ -246,11 +242,6 @@ local function initializecolr(tfmdata,kind,value) -- hm, always value tfmdata.fonts = { { id = 0 } } - local widths = setmetatableindex(function(t,k) - local v = { "right", -k } - t[k] = v - return v - end) -- local getactualtext = otf.getactualtext local default = colorvalues[#colorvalues] @@ -258,12 +249,6 @@ local function initializecolr(tfmdata,kind,value) -- hm, always value local actualb = { "pdf", "page", b } -- saves tables local actuale = { "pdf", "page", e } -- saves tables -- - local cache = setmetatableindex(function(t,k) - local v = { "char", k } -- could he a weak shared hash - t[k] = v - return v - end) - -- for unicode, character in next, characters do local description = descriptions[unicode] if description then @@ -272,7 +257,7 @@ local function initializecolr(tfmdata,kind,value) -- hm, always value local u = description.unicode or characters[unicode].unicode local w = character.width or 0 local s = #colorlist - local goback = w ~= 0 and widths[w] or nil -- needs checking: are widths the same + local goback = w ~= 0 and leftcommand[w] or nil -- needs checking: are widths the same local t = { start, -- really needed not u and actualb or { "pdf", "page", (getactualtext(tounicode(u))) } @@ -292,7 +277,7 @@ local function initializecolr(tfmdata,kind,value) -- hm, always value n = n + 1 t[n] = v l = v end - n = n + 1 t[n] = cache[entry.slot] + n = n + 1 t[n] = charcommand[entry.slot] if s > 1 and i < s and goback then n = n + 1 t[n] = goback end @@ -314,8 +299,8 @@ fonts.handlers.otf.features.register { name = "colr", description = "color glyphs", manipulators = { - base = initializecolr, - node = initializecolr, + base = initialize, + node = initialize, } } @@ -436,8 +421,8 @@ local function pdftovirtual(tfmdata,pdfshapes,kind) -- kind = sbix|svg local dp = character.depth or 0 character.commands = { not unicode and actualb or { "pdf", "page", (getactualtext(unicode)) }, - { "down", dp + dy * hfactor }, - { "right", dx * hfactor }, + downcommand[dp + dy * hfactor], + rightcommand[dx * hfactor], -- setcode and { "lua", setcode } or nop, { "image", { filename = name, width = wd, height = ht, depth = dp } }, -- nilcode and { "lua", nilcode } or nop, diff --git a/tex/context/base/mkiv/font-otc.lua b/tex/context/base/mkiv/font-otc.lua index 2bad62d60..fb8bf7c66 100644 --- a/tex/context/base/mkiv/font-otc.lua +++ b/tex/context/base/mkiv/font-otc.lua @@ -6,11 +6,10 @@ if not modules then modules = { } end modules ['font-otc'] = { license = "see context related readme files" } -local format, insert, sortedkeys, tohash = string.format, table.insert, table.sortedkeys, table.tohash +local insert, sortedkeys, sortedhash, tohash = table.insert, table.sortedkeys, table.sortedhash, table.tohash local type, next = type, next local lpegmatch = lpeg.match -local utfbyte, utflen, utfsplit = utf.byte, utf.len, utf.split -local match = string.match +local utfbyte, utflen = utf.byte, utf.len local sortedhash = table.sortedhash -- we assume that the other otf stuff is loaded already @@ -813,177 +812,6 @@ otf.enhancers.enhance = enhance otf.enhancers.register("check extra features",enhance) --- tlig -- - -local tlig = { -- we need numbers for some fonts so ... - -- endash = "hyphen hyphen", - -- emdash = "hyphen hyphen hyphen", - [0x2013] = { 0x002D, 0x002D }, - [0x2014] = { 0x002D, 0x002D, 0x002D }, - -- quotedblleft = "quoteleft quoteleft", - -- quotedblright = "quoteright quoteright", - -- quotedblleft = "grave grave", - -- quotedblright = "quotesingle quotesingle", - -- quotedblbase = "comma comma", -} - -local tlig_specification = { - type = "ligature", - features = everywhere, - data = tlig, - order = { "tlig" }, - flags = noflags, - prepend = true, -} - -otf.addfeature("tlig",tlig_specification) - -registerotffeature { - -- this makes it a known feature (in tables) - name = 'tlig', - description = 'tex ligatures', -} - --- trep - -local trep = { - -- [0x0022] = 0x201D, - [0x0027] = 0x2019, - -- [0x0060] = 0x2018, -} - -local trep_specification = { - type = "substitution", - features = everywhere, - data = trep, - order = { "trep" }, - flags = noflags, - prepend = true, -} - -otf.addfeature("trep",trep_specification) - -registerotffeature { - -- this makes it a known feature (in tables) - name = 'trep', - description = 'tex replacements', -} - --- -- tcom (obsolete, was already not set for a while) - --- if characters.combined then --- --- local tcom = { } --- --- local function initialize() --- characters.initialize() --- for first, seconds in next, characters.combined do --- for second, combination in next, seconds do --- tcom[combination] = { first, second } --- end --- end --- -- return false --- end --- --- local tcom_specification = { --- type = "ligature", --- features = everywhere, --- data = tcom, --- order = { "tcom" }, --- flags = noflags, --- initialize = initialize, --- } --- --- otf.addfeature("tcom",tcom_specification) --- --- registerotffeature { --- name = 'tcom', --- description = 'tex combinations', --- } --- --- end - --- anum - -local anum_arabic = { - [0x0030] = 0x0660, - [0x0031] = 0x0661, - [0x0032] = 0x0662, - [0x0033] = 0x0663, - [0x0034] = 0x0664, - [0x0035] = 0x0665, - [0x0036] = 0x0666, - [0x0037] = 0x0667, - [0x0038] = 0x0668, - [0x0039] = 0x0669, -} - -local anum_persian = { - [0x0030] = 0x06F0, - [0x0031] = 0x06F1, - [0x0032] = 0x06F2, - [0x0033] = 0x06F3, - [0x0034] = 0x06F4, - [0x0035] = 0x06F5, - [0x0036] = 0x06F6, - [0x0037] = 0x06F7, - [0x0038] = 0x06F8, - [0x0039] = 0x06F9, -} - -local function valid(data) - local features = data.resources.features - if features then - for k, v in next, features do - for k, v in next, v do - if v.arab then - return true - end - end - end - end -end - -local anum_specification = { - { - type = "substitution", - features = { arab = { urd = true, dflt = true } }, - order = { "anum" }, - data = anum_arabic, - flags = noflags, -- { }, - valid = valid, - }, - { - type = "substitution", - features = { arab = { urd = true } }, - order = { "anum" }, - data = anum_persian, - flags = noflags, -- { }, - valid = valid, - }, -} - -otf.addfeature("anum",anum_specification) -- todo: only when there is already an arab script feature - -registerotffeature { - -- this makes it a known feature (in tables) - name = 'anum', - description = 'arabic digits', -} - --- maybe: - --- fonts.handlers.otf.addfeature("hangulfix",{ --- type = "substitution", --- features = { ["hang"] = { ["*"] = true } }, --- data = { --- [0x1160] = 0x119E, --- }, --- order = { "hangulfix" }, --- flags = { }, --- prepend = true, --- }) - -- fonts.handlers.otf.features.register { -- name = 'hangulfix', -- description = 'fixes for hangul', @@ -1028,126 +856,3 @@ registerotffeature { -- a = { b = -500 }, -- } -- } - --- This is a quick and dirty hack. - -local lookups = { } -local protect = { } -local revert = { } -local zwjchar = 0x200C -local zwj = { zwjchar } - -otf.addfeature { - name = "blockligatures", - type = "chainsubstitution", - nocheck = true, -- because there is no 0x200C in the font - prepend = true, -- make sure we do it early - future = true, -- avoid nilling due to no steps yet - lookups = { - { - type = "multiple", - data = lookups, - }, - }, - data = { - rules = protect, - } -} - -otf.addfeature { - name = "blockligatures", - type = "chainsubstitution", - nocheck = true, -- because there is no 0x200C in the font - append = true, -- this is done late - overload = false, -- we don't want to overload the previous definition - lookups = { - { - type = "ligature", - data = lookups, - }, - }, - data = { - rules = revert, - } -} - -registerotffeature { - name = 'blockligatures', - description = 'block certain ligatures', -} - -local settings_to_array = utilities.parsers and utilities.parsers.settings_to_array - or function(s) return string.split(s,",") end -- for generic - -local splitter = lpeg.splitat(":") - -local function blockligatures(str) - - local t = settings_to_array(str) - - for i=1,#t do - local ti = t[i] - local before, current, after = lpegmatch(splitter,ti) - if current and after then -- before is returned when no match - -- experimental joke - if before then - before = utfsplit(before) - for i=1,#before do - before[i] = { before[i] } - end - end - if current then - current = utfsplit(current) - end - if after then - after = utfsplit(after) - for i=1,#after do - after[i] = { after[i] } - end - end - else - before = nil - current = utfsplit(ti) - after = nil - end - if #current > 1 then - local one = current[1] - local two = current[2] - lookups[one] = { one, zwjchar } - local one = { one } - local two = { two } - local new = #protect + 1 - protect[new] = { - before = before, - current = { one, two }, - after = after, - lookups = { 1 }, -- not shared ! - } - revert[new] = { - -- before = before, - current = { one, zwj }, - -- after = { two, unpack(after) }, - after = { two }, - lookups = { 1 }, -- not shared ! - } - end - end -end - --- blockligatures("\0\0") - -otf.helpers.blockligatures = blockligatures - --- blockligatures("fi,ff") --- blockligatures("fl") --- blockligatures("u:fl:age") - -if context then - - interfaces.implement { - name = "blockligatures", - arguments = "string", - actions = blockligatures, - } - -end diff --git a/tex/context/base/mkiv/font-otj.lua b/tex/context/base/mkiv/font-otj.lua index 9037939df..45a3acb7d 100644 --- a/tex/context/base/mkiv/font-otj.lua +++ b/tex/context/base/mkiv/font-otj.lua @@ -128,6 +128,10 @@ do if not fontkern then -- generic return n end +end end + +do if not italickern then -- generic + local thekern = nuts.new("kern",3) -- italiccorrection local setkern = nuts.setkern local copy_node = nuts.copy_node diff --git a/tex/context/base/mkiv/font-ott.lua b/tex/context/base/mkiv/font-ott.lua index 59d92f40d..c9e2836d8 100644 --- a/tex/context/base/mkiv/font-ott.lua +++ b/tex/context/base/mkiv/font-ott.lua @@ -8,7 +8,8 @@ if not modules then modules = { } end modules ["font-ott"] = { } local type, next, tonumber, tostring, rawget, rawset = type, next, tonumber, tostring, rawget, rawset -local gsub, lower, format, match = string.gsub, string.lower, string.format, string.match +local gsub, lower, format, match, gmatch, find = string.gsub, string.lower, string.format, string.match, string.gmatch, string.find +local sequenced = table.sequenced local is_boolean = string.is_boolean local setmetatableindex = table.setmetatableindex @@ -1098,9 +1099,9 @@ function otffeatures.normalize(features) h.script = rawget(verbosescripts,v) or (scripts[v] and v) or "dflt" -- auto adds elseif k == "axis" then h[k] = normalizedaxis(value) -if not callbacks.supported.glyph_stream_provider then - h.variableshapes = true -- for the moment -end + if not callbacks.supported.glyph_stream_provider then + h.variableshapes = true -- for the moment + end else local uk = usedfeatures[key] local uv = uk[value] @@ -1113,10 +1114,23 @@ end elseif type(value) == "string" then local b = is_boolean(value) if type(b) == "nil" then + -- we do this elsewhere + -- + -- if find(value,"=") then + -- local t = { } + -- for k, v in gmatch(value,"([^%s,=]+)%s*=%s*([^%s,=]+)") do + -- t[k] = tonumber(v) or v + -- end + -- if next(t) then + -- value = sequenced(t,",") + -- end + -- end uv = lower(value) else uv = b end + elseif type(value) == "table" then + uv = sequenced(t,",") else uv = value end diff --git a/tex/context/base/mkiv/font-pre.mkiv b/tex/context/base/mkiv/font-pre.mkiv index b49bc560e..01e580ac5 100644 --- a/tex/context/base/mkiv/font-pre.mkiv +++ b/tex/context/base/mkiv/font-pre.mkiv @@ -452,9 +452,37 @@ [slanted] [slant=.2] +% \definefontfeature +% [boldened] +% [extend=1.2] + +%D Neat: + +% By eye: +% +% \definefontfeature[boldened-10][effect={width=0.10,delta=1.0,hdelta=0.500,ddelta=0.150,vshift=0.125,extend=1.025,squeeze=0.99250}] +% \definefontfeature[boldened-15][effect={width=0.15,delta=1.0,hdelta=0.500,ddelta=0.150,vshift=0.250,extend=1.050,squeeze=0.98750}] +% \definefontfeature[boldened-20][effect={width=0.20,delta=1.0,hdelta=0.500,ddelta=0.150,vshift=0.375,extend=1.075,squeeze=0.98125}] +% \definefontfeature[boldened-30][effect={width=0.30,delta=1.0,hdelta=0.500,ddelta=0.150,vshift=0.500,extend=1.100,squeeze=0.97500}] +% +% By calculation: +% +% \definefontfeature[boldened-10][effect={width=0.10,delta=1.0,hdelta=0.02500,ddelta=0.02500,vshift=0.02500,extend=1.050,squeeze=0.99500}] +% \definefontfeature[boldened-15][effect={width=0.15,delta=1.0,hdelta=0.05625,ddelta=0.05625,vshift=0.05625,extend=1.075,squeeze=0.99250}] +% \definefontfeature[boldened-20][effect={width=0.20,delta=1.0,hdelta=0.10000,ddelta=0.10000,vshift=0.10000,extend=1.100,squeeze=0.99000}] +% \definefontfeature[boldened-30][effect={width=0.30,delta=1.0,hdelta=0.22500,ddelta=0.22500,vshift=0.22500,extend=1.150,squeeze=0.98500}] +% +% So we can do this: + +\definefontfeature[boldened-10][effect={width=0.10,auto=yes}] +\definefontfeature[boldened-15][effect={width=0.15,auto=yes}] +\definefontfeature[boldened-20][effect={width=0.20,auto=yes}] +\definefontfeature[boldened-25][effect={width=0.25,auto=yes}] +\definefontfeature[boldened-30][effect={width=0.30,auto=yes}] + \definefontfeature [boldened] - [extend=1.2] + [boldened-30] %D Emoji: diff --git a/tex/context/base/mkiv/font-prv.lua b/tex/context/base/mkiv/font-prv.lua new file mode 100644 index 000000000..fef1f3618 --- /dev/null +++ b/tex/context/base/mkiv/font-prv.lua @@ -0,0 +1,74 @@ +if not modules then modules = { } end modules ['font-prv'] = { + version = 1.001, + comment = "companion to font-ini.mkiv and hand-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local type = type +local formatters = string.formatters + +local fonts = fonts +local helpers = fonts.helpers +local fontdata = fonts.hashes.identifiers + +local setmetatableindex = table.setmetatableindex + +local currentprivate = 0xE000 +local maximumprivate = 0xEFFF + +local extraprivates = { } +helpers.extraprivates = extraprivates + +function fonts.helpers.addextraprivate(name,f) + extraprivates[#extraprivates+1] = { name, f } +end + +-- if we run out of space we can think of another range but by sharing we can +-- use these privates for mechanisms like alignments-on-character and such + +local sharedprivates = setmetatableindex(function(t,k) + v = currentprivate + if currentprivate < maximumprivate then + currentprivate = currentprivate + 1 + else + -- reuse last slot, todo: warning + end + t[k] = v + return v +end) + +function helpers.addprivate(tfmdata,name,characterdata) + local properties = tfmdata.properties + local characters = tfmdata.characters + local privates = properties.privates + if not privates then + privates = { } + properties.privates = privates + end + if not name then + name = formatters["anonymous_private_0x%05X"](currentprivate) + end + local usedprivate = sharedprivates[name] + privates[name] = usedprivate + characters[usedprivate] = characterdata + return usedprivate +end + +function helpers.getprivates(tfmdata) + if type(tfmdata) == "number" then + tfmdata = fontdata[tfmdata] + end + local properties = tfmdata.properties + return properties and properties.privates +end + +function helpers.hasprivate(tfmdata,name) + if type(tfmdata) == "number" then + tfmdata = fontdata[tfmdata] + end + local properties = tfmdata.properties + local privates = properties and properties.privates + return privates and privates[name] or false +end diff --git a/tex/context/base/mkiv/font-shp.lua b/tex/context/base/mkiv/font-shp.lua index 75a12ac82..79c015a63 100644 --- a/tex/context/base/mkiv/font-shp.lua +++ b/tex/context/base/mkiv/font-shp.lua @@ -338,7 +338,7 @@ local function segmentstopdf(segments,factor,bt,et) end end -local function addvariableshapes(tfmdata,key,value) +local function initialize(tfmdata,key,value) if value then local shapes = otf.loadoutlinedata(tfmdata) if not shapes then @@ -354,7 +354,9 @@ local function addvariableshapes(tfmdata,key,value) local factor = hfactor / 65536 local getactualtext = otf.getactualtext for unicode, char in next, characters do - if not char.commands then + if char.commands then + -- can't happen as we're doing this before other messing around + else local shape = glyphs[char.index] if shape then local segments = shape.segments @@ -375,8 +377,8 @@ otf.features.register { name = "variableshapes", -- enforced for now description = "variable shapes", manipulators = { - base = addvariableshapes, - node = addvariableshapes, + base = initialize, + node = initialize, } } diff --git a/tex/context/base/mkiv/font-tfm.lua b/tex/context/base/mkiv/font-tfm.lua index 0059e6296..9f78f2c0a 100644 --- a/tex/context/base/mkiv/font-tfm.lua +++ b/tex/context/base/mkiv/font-tfm.lua @@ -21,6 +21,7 @@ local setmetatableindex = table.setmetatableindex local fonts = fonts local handlers = fonts.handlers +local helpers = fonts.helpers local readers = fonts.readers local constructors = fonts.constructors local encodings = fonts.encodings @@ -39,6 +40,8 @@ local registertfmfeature = tfmfeatures.register local tfmenhancers = constructors.enhancers.tfm local registertfmenhancer = tfmenhancers.register +local charcommand = helpers.commands.char + constructors.resolvevirtualtoo = false -- wil be set in font-ctx.lua fonts.formats.tfm = "type1" -- we need to have at least a value here @@ -465,7 +468,7 @@ do if backmap then original.index = backmap[name] else -- probably bitmap - original.commands = { parentfont, { "char", index } } + original.commands = { parentfont, charcommand[index] } -- or "slot" original.oindex = index end done[name] = true diff --git a/tex/context/base/mkiv/font-vfc.lua b/tex/context/base/mkiv/font-vfc.lua new file mode 100644 index 000000000..cac225de6 --- /dev/null +++ b/tex/context/base/mkiv/font-vfc.lua @@ -0,0 +1,98 @@ +if not modules then modules = { } end modules ['font-vfc'] = { + version = 1.001, + comment = "companion to font-ini.mkiv and hand-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local select = select +local insert = table.insert + +local fonts = fonts +local helpers = fonts.helpers + +local setmetatableindex = table.setmetatableindex +local makeweak = table.makeweak + +-- Helpers dealing with virtual fonts: beware, these are final values so +-- don't change the content of tables gotten this way! + +local push = { "push" } +local pop = { "pop" } +local dummy = { "comment" } + +function helpers.prependcommands(commands,...) + insert(commands,1,push) + for i=select("#",...),1,-1 do + local s = select(i,...) + if s then + insert(commands,1,s) + end + end + insert(commands,pop) + return commands +end + +function helpers.appendcommands(commands,...) + insert(commands,1,push) + insert(commands,pop) + for i=1,select("#",...) do + local s = select(i,...) + if s then + insert(commands,s) + end + end + return commands +end + +-- todo: maybe weak +-- todo: maybe indirect so that we can't change them + +local char = setmetatableindex(function(t,k) + local v = { "char", k } + t[k] = v + return v +end) + +local right = setmetatableindex(function(t,k) + local v = { "right", k } + t[k] = v + return v +end) + +local left = setmetatableindex(function(t,k) + local v = { "right", -k } + t[k] = v + return v +end) + +local down = setmetatableindex(function(t,k) + local v = { "down", k } + t[k] = v + return v +end) + +local up = setmetatableindex(function(t,k) + local v = { "down", -k } + t[k] = v + return v +end) + +-- makeweak(char) +-- makeweak(right) +-- makeweak(left) +-- makeweak(up) +-- makeweak(down) + +helpers.commands = utilities.storage.allocate { + char = char, + right = right, + left = left, + down = down, + up = up, + push = push, + pop = pop, + dummy = dummy, +} + diff --git a/tex/context/base/mkiv/font-vir.lua b/tex/context/base/mkiv/font-vir.lua index 03ad7fc85..d65136245 100644 --- a/tex/context/base/mkiv/font-vir.lua +++ b/tex/context/base/mkiv/font-vir.lua @@ -14,7 +14,7 @@ if not modules then modules = { } end modules ['font-vir'] = { -- -- vf.rule vf.special vf.right vf.push vf.down vf.char vf.node vf.fontid vf.pop vf.image vf.nop -local next = next +local next, setmetatable, getmetatable = next, setmetatable, getmetatable local allocate = utilities.storage.allocate local setmetatableindex = table.setmetatableindex @@ -66,11 +66,7 @@ local combinations = { } local combiner = { } local whatever = allocate() local helpers = allocate() -local predefined = allocate { - dummy = { "comment" }, - push = { "push" }, - pop = { "pop" }, -} +local predefined = fonts.helpers.commands methods.variants = variants -- todo .. wrong namespace vf.combinations = combinations diff --git a/tex/context/base/mkiv/l-file.lua b/tex/context/base/mkiv/l-file.lua index 5fec0040f..46b6847d3 100644 --- a/tex/context/base/mkiv/l-file.lua +++ b/tex/context/base/mkiv/l-file.lua @@ -69,35 +69,34 @@ local lpegmatch = lpeg.match local getcurrentdir, attributes = lfs.currentdir, lfs.attributes local checkedsplit = string.checkedsplit --- local patterns = file.patterns or { } --- file.patterns = patterns - local P, R, S, C, Cs, Cp, Cc, Ct = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpeg.Cp, lpeg.Cc, lpeg.Ct -- better this way: -local tricky = S("/\\") * P(-1) +----- tricky = S("/\\") * P(-1) local attributes = lfs.attributes -if sandbox then - sandbox.redefine(lfs.isfile,"lfs.isfile") - sandbox.redefine(lfs.isdir, "lfs.isdir") -end - function lfs.isdir(name) - if lpegmatch(tricky,name) then - return attributes(name,"mode") == "directory" - else - return attributes(name.."/.","mode") == "directory" - end + -- if not lpegmatch(tricky,name) then + -- name = name .. "/." + -- end + return attributes(name,"mode") == "directory" end function lfs.isfile(name) - return attributes(name,"mode") == "file" + local a = attributes(name,"mode") + return a == "file" or a == "link" or nil end function lfs.isfound(name) - return attributes(name,"mode") == "file" and name or nil + local a = attributes(name,"mode") + return (a == "file" or a == "link") and name or nil +end + +if sandbox then + sandbox.redefine(lfs.isfile,"lfs.isfile") + sandbox.redefine(lfs.isdir, "lfs.isdir") + sandbox.redefine(lfs.isfound, "lfs.isfound") end local colon = P(":") @@ -725,3 +724,10 @@ function file.withinbase(path) -- don't go beyond root return true end +-- not used in context but was in luatex once: + +local symlinkattributes = lfs.symlinkattributes + +function lfs.readlink(name) + return symlinkattributes(name,"target") or nil +end diff --git a/tex/context/base/mkiv/l-lpeg.lua b/tex/context/base/mkiv/l-lpeg.lua index a7ebd567d..e3d0ff9c3 100644 --- a/tex/context/base/mkiv/l-lpeg.lua +++ b/tex/context/base/mkiv/l-lpeg.lua @@ -944,7 +944,7 @@ local function make2(t,rest) -- only ascii return p end -function lpeg.utfchartabletopattern(list,insensitive) -- goes to util-lpg +local function utfchartabletopattern(list,insensitive) -- goes to util-lpg local tree = { } local n = #list if n == 0 then @@ -1022,6 +1022,16 @@ function lpeg.utfchartabletopattern(list,insensitive) -- goes to util-lpg return (insensitive and make2 or make1)(tree) end +lpeg.utfchartabletopattern = utfchartabletopattern + +function lpeg.utfreplacer(list,insensitive) + local pattern = Cs((utfchartabletopattern(list,insensitive)/list + utf8character)^0) + return function(str) + return lpegmatch(pattern,str) or str + end +end + + -- local t = { "start", "stoep", "staart", "paard" } -- local p = lpeg.Cs((lpeg.utfchartabletopattern(t)/string.upper + 1)^1) @@ -1209,3 +1219,22 @@ end -- local h = "ADFE0345" -- local b = lpegmatch(patterns.hextobytes,h) -- print(h,b,string.tohex(b),string.toHEX(b)) + +local patterns = { } -- can be made weak + +local function containsws(what) + local p = patterns[what] + if not p then + local p1 = P(what) * (whitespace + P(-1)) * Cc(true) + local p2 = whitespace * P(p1) + p = P(p1) + P(1-p2)^0 * p2 + Cc(false) + patterns[what] = p + end + return p +end + +lpeg.containsws = containsws + +function string.containsws(str,what) + return lpegmatch(patterns[what] or containsws(what),str) +end diff --git a/tex/context/base/mkiv/l-os.lua b/tex/context/base/mkiv/l-os.lua index 9b54c9840..bf13baaa6 100644 --- a/tex/context/base/mkiv/l-os.lua +++ b/tex/context/base/mkiv/l-os.lua @@ -156,7 +156,7 @@ end local launchers = { windows = "start %s", macosx = "open %s", - unix = "$BROWSER %s &> /dev/null &", + unix = "xdg-open %s &> /dev/null &", } function os.launch(str) @@ -234,10 +234,12 @@ elseif os.type == "windows" then -- PROCESSOR_ARCHITECTURE : binary platform -- PROCESSOR_ARCHITEW6432 : OS platform + -- mswin-64 is now win64 + function resolvers.platform(t,k) - local platform, architecture = "", os.getenv("PROCESSOR_ARCHITECTURE") or "" + local architecture = os.getenv("PROCESSOR_ARCHITECTURE") or "" + local platform = "" if find(architecture,"AMD64",1,true) then - -- platform = "mswin-64" platform = "win64" else platform = "mswin" @@ -251,13 +253,17 @@ elseif name == "linux" then function resolvers.platform(t,k) -- we sometimes have HOSTTYPE set so let's check that first - local platform, architecture = "", os.getenv("HOSTTYPE") or resultof("uname -m") or "" - if find(architecture,"x86_64",1,true) then - platform = "linux-64" + local architecture = os.getenv("HOSTTYPE") or resultof("uname -m") or "" + local platform = os.getenv("MTX_PLATFORM") + local musl = find(os.selfdir or "","linuxmusl") + if platform ~= "" then + -- we're done + elseif find(architecture,"x86_64",1,true) then + platform = musl and "linuxmusl" or "linux-64" elseif find(architecture,"ppc",1,true) then platform = "linux-ppc" else - platform = "linux" + platform = musl and "linuxmusl" or "linux" end os.setenv("MTX_PLATFORM",platform) os.platform = platform @@ -277,11 +283,13 @@ elseif name == "macosx" then ]]-- function resolvers.platform(t,k) - -- local platform, architecture = "", os.getenv("HOSTTYPE") or "" + -- local platform = "" + -- local architecture = os.getenv("HOSTTYPE") or "" -- if architecture == "" then -- architecture = resultof("echo $HOSTTYPE") or "" -- end - local platform, architecture = "", resultof("echo $HOSTTYPE") or "" + local architecture = resultof("echo $HOSTTYPE") or "" + local platform = "" if architecture == "" then -- print("\nI have no clue what kind of OSX you're running so let's assume an 32 bit intel.\n") platform = "osx-intel" @@ -300,7 +308,8 @@ elseif name == "macosx" then elseif name == "sunos" then function resolvers.platform(t,k) - local platform, architecture = "", resultof("uname -m") or "" + local architecture = resultof("uname -m") or "" + local platform = "" if find(architecture,"sparc",1,true) then platform = "solaris-sparc" else -- if architecture == 'i86pc' @@ -314,7 +323,8 @@ elseif name == "sunos" then elseif name == "freebsd" then function resolvers.platform(t,k) - local platform, architecture = "", resultof("uname -m") or "" + local architecture = resultof("uname -m") or "" + local platform = "" if find(architecture,"amd64",1,true) then platform = "freebsd-amd64" else @@ -329,7 +339,8 @@ elseif name == "kfreebsd" then function resolvers.platform(t,k) -- we sometimes have HOSTTYPE set so let's check that first - local platform, architecture = "", os.getenv("HOSTTYPE") or resultof("uname -m") or "" + local architecture = os.getenv("HOSTTYPE") or resultof("uname -m") or "" + local platform = "" if find(architecture,"x86_64",1,true) then platform = "kfreebsd-amd64" else diff --git a/tex/context/base/mkiv/l-table.lua b/tex/context/base/mkiv/l-table.lua index 5cd65dd67..788d1511f 100644 --- a/tex/context/base/mkiv/l-table.lua +++ b/tex/context/base/mkiv/l-table.lua @@ -1236,7 +1236,7 @@ function table.reverse(t) -- check with 5.3 ? end end -function table.sequenced(t,sep,simple) -- hash only +local function sequenced(t,sep,simple) if not t then return "" end @@ -1257,17 +1257,27 @@ function table.sequenced(t,sep,simple) -- hash only s[n] = k elseif v and v~= "" then n = n + 1 - s[n] = k .. "=" .. tostring(v) + if type(v) == "table" then + s[n] = k .. "={" .. sequenced(v,sep,simple) .. "}" + else + s[n] = k .. "=" .. tostring(v) + end end else n = n + 1 - s[n] = k .. "=" .. tostring(v) + if type(v) == "table" then + s[n] = k .. "={" .. sequenced(v,sep,simple) .. "}" + else + s[n] = k .. "=" .. tostring(v) + end end end end return concat(s,sep or " | ") end +table.sequenced = sequenced + function table.print(t,...) if type(t) ~= "table" then print(tostring(t)) diff --git a/tex/context/base/mkiv/lang-ini.mkiv b/tex/context/base/mkiv/lang-ini.mkiv index 7c83ae38f..9c7b5641b 100644 --- a/tex/context/base/mkiv/lang-ini.mkiv +++ b/tex/context/base/mkiv/lang-ini.mkiv @@ -548,7 +548,12 @@ % this will move to core-spa ! \appendtoks - \doifelse{\languageparameter\c!spacing}\v!broad\nonfrenchspacing\frenchspacing + \edef\p_spacing{\languageparameter\c!spacing}% + \ifx\p_spacing\v!broad + \nonfrenchspacing + \else + \frenchspacing + \fi \to \everylanguage % \mainlanguage[nl] \setuplanguage[nl][lefthyphen=,righthyphen=?] diff --git a/tex/context/base/mkiv/lang-lab.mkiv b/tex/context/base/mkiv/lang-lab.mkiv index 73637753d..9d73d96e5 100644 --- a/tex/context/base/mkiv/lang-lab.mkiv +++ b/tex/context/base/mkiv/lang-lab.mkiv @@ -277,10 +277,16 @@ \def\lang_labels_text_prefix_copy_pair[#1=#2]% {\lang_labels_text_prefix_copy_pair_indeed{#1}[#2,,]} +% \def\lang_labels_text_prefix_copy_pair_indeed#1[#2,#3]% +% {\expandafter\let +% \csname\??label\currenttextprefixclass:\currenttextprefixtag:#1\expandafter\endcsname +% \csname\??label\currenttextprefixclass:\currenttextprefixtag:#2\endcsname} +% +% this delays the aliasing so that we can switch maillanguage in between + \def\lang_labels_text_prefix_copy_pair_indeed#1[#2,#3]% - {\expandafter\let - \csname\??label\currenttextprefixclass:\currenttextprefixtag:#1\expandafter\endcsname - \csname\??label\currenttextprefixclass:\currenttextprefixtag:#2\endcsname} + {\expandafter\edef\csname\??label\currenttextprefixclass:#1\endcsname + {{\noexpand\csname\??label\currenttextprefixclass:\noexpand\reallanguagetag\noexpand\currentmainlanguage:#2\endcsname}{}}} \definelabelclass [head] [0] % titles \definelabelclass [label] [0] % texts diff --git a/tex/context/base/mkiv/lpdf-ano.lua b/tex/context/base/mkiv/lpdf-ano.lua index 01f015b72..eba4d6060 100644 --- a/tex/context/base/mkiv/lpdf-ano.lua +++ b/tex/context/base/mkiv/lpdf-ano.lua @@ -106,6 +106,31 @@ local pdf_fit = pdfconstant("Fit") local pdf_named = pdfconstant("Named") local autoprefix = "#" +local usedautoprefixes = { } + +local function registerautoprefix(name) + local internal = autoprefix .. name + if usedautoprefixes[internal] == nil then + usedautoprefixes[internal] = false + end + return internal +end + +local function useautoprefix(name) + local internal = autoprefix .. name + usedautoprefixes[internal] = true +end + +local function checkautoprefixes(destinations) + for k, v in next, usedautoprefixes do + if not v then + if trace_destinations then + report_destinations("flushing unused autoprefix %a",k) + end + destinations[k] = nil + end + end +end -- Bah, I hate this kind of features .. anyway, as we have delayed resolving we -- only support a document-wide setup and it has to be set before the first one @@ -193,11 +218,15 @@ local defaultdestination = pdfarray { 0, pdf_fit } -- fit is default (see lpdf-nod) local destinations = { } -- to be used soon +local reported = setmetatableindex("table") local function pdfregisterdestination(name,reference) local d = destinations[name] if d then - report_destinations("ignoring duplicate destination %a with reference %a",name,reference) + if not reported[name][reference] then + report_destinations("ignoring duplicate destination %a with reference %a",name,reference) + reported[name][reference] = true + end else destinations[name] = reference end @@ -222,6 +251,7 @@ end) local function pdfnametree(destinations) local slices = { } + checkautoprefixes(destinations) local sorted = table.sortedkeys(destinations) local size = #sorted @@ -292,7 +322,6 @@ end local function pdfdestinationspecification() if next(destinations) then -- safeguard local r = pdfnametree(destinations) - -- pdfaddtocatalog("Dests",r) pdfaddtonames("Dests",r) if not log_destinations then destinations = nil @@ -459,7 +488,7 @@ function nodeinjections.destination(width,height,depth,names,view) elseif type(name) == "number" then local used = usedinternals[name] usedviews[name] = view - names[n] = autoprefix .. name + names[n] = registerautoprefix(name) doview = true else usedviews[name] = view @@ -479,10 +508,9 @@ function nodeinjections.destination(width,height,depth,names,view) local used = usedinternals[name] if used and used ~= defaultview then usedviews[name] = view - names[n] = autoprefix .. name + names[n] = registerautoprefix(name) doview = true else - -- names[n] = autoprefix .. name names[n] = false end end @@ -504,7 +532,7 @@ local function pdflinkpage(page) end local function pdflinkinternal(internal,page) - local method = references.innermethod + -- local method = references.innermethod if internal then flaginternals[internal] = true -- for bookmarks and so local used = usedinternals[internal] @@ -512,7 +540,7 @@ local function pdflinkinternal(internal,page) return pagereferences[page] else if type(internal) ~= "string" then - internal = autoprefix .. internal + internal = useautoprefix(internal) end return pdfdictionary { S = pdf_goto, @@ -872,16 +900,21 @@ end runners["special operation"] = runners["special"] runners["special operation with arguments"] = runners["special"] +local reported = { } + function specials.internal(var,actions) -- better resolve in strc-ref - local i = tonumber(var.operation) + local o = var.operation + local i = o and tonumber(o) local v = i and references.internals[i] - if not v then - -- error - report_references("no internal reference %a",i or "") - else - flaginternals[i] = true + if v then + flaginternals[i] = true -- also done in pdflinkinternal return pdflinkinternal(i,v.references.realpage) end + local v = i or o or "" + if not reported[v] then + report_references("no internal reference %a",v) + reported[v] = true + end end -- realpage already resolved @@ -946,19 +979,18 @@ end -- sections --- function specials.section(var,actions) --- local sectionname = var.operation --- local destination = var.arguments --- local internal = structures.sections.internalreference(sectionname,destination) --- if internal then --- var.special = "internal" --- var.operation = internal --- var.arguments = nil --- specials.internal(var,actions) --- end --- end - -specials.section = specials.internal -- specials.section just need to have a value as it's checked +function specials.section(var,actions) + -- a bit duplicate + local sectionname = var.arguments + local destination = var.operation + local internal = structures.sections.internalreference(sectionname,destination) + if internal then + var.special = "internal" + var.operation = internal + var.arguments = nil + return specials.internal(var,actions) + end +end -- todo, do this in references namespace ordered instead (this is an experiment) diff --git a/tex/context/base/mkiv/lpdf-tag.lua b/tex/context/base/mkiv/lpdf-tag.lua index f4ecfc8a6..dc7d038fe 100644 --- a/tex/context/base/mkiv/lpdf-tag.lua +++ b/tex/context/base/mkiv/lpdf-tag.lua @@ -324,11 +324,10 @@ function nodeinjections.addtags(head) local last = nil local ranges = { } local range = nil - local head = tonut(head) + local head = tonut(head) local function collectranges(head,list) - for n in traverse_nodes(head) do - local id = getid(n) + for n, id in traverse_nodes(head) do if id == glyph_code then -- maybe also disc local at = getattr(n,a_tagged) @@ -472,8 +471,7 @@ end -- local last, ranges, range = nil, { }, nil -- -- local function collectranges(head,list) --- for n in traverse_nodes(head) do --- local id = getid(n) -- 14: image, 8: literal (mp) +-- for n, id in traverse_nodes(head) do -- if id == glyph_code then -- local at = getattr(n,a_tagged) -- if not at then diff --git a/tex/context/base/mkiv/luat-cod.lua b/tex/context/base/mkiv/luat-cod.lua index 91bb7c2e1..94006d52c 100644 --- a/tex/context/base/mkiv/luat-cod.lua +++ b/tex/context/base/mkiv/luat-cod.lua @@ -187,6 +187,21 @@ end -- a kpse error when disabled. This is an engine issue that will -- be sorted out in due time. +if not lfs.isfile then + + local attributes = lfs.attributes + + function lfs.isdir(name) + return attributes(name,"mode") == "directory" + end + + function lfs.isfile(name) + local a = attributes(name,"mode") + return a == "file" or a == "link" or nil + end + +end + local isfile = lfs.isfile local function source_file(name) diff --git a/tex/context/base/mkiv/lxml-css.lua b/tex/context/base/mkiv/lxml-css.lua index 1787c53df..8d6c42409 100644 --- a/tex/context/base/mkiv/lxml-css.lua +++ b/tex/context/base/mkiv/lxml-css.lua @@ -6,7 +6,7 @@ if not modules then modules = { } end modules ['lxml-css'] = { license = "see context related readme files" } -local tonumber, rawset, type = tonumber, rawset, type +local tonumber, rawset, type, select = tonumber, rawset, type, select local lower, format, find, gmatch = string.lower, string.format, string.find, string.gmatch local topattern, is_empty = string.topattern, string.is_empty local P, S, C, R, Cb, Cg, Carg, Ct, Cc, Cf, Cs = lpeg.P, lpeg.S, lpeg.C, lpeg.R, lpeg.Cb, lpeg.Cg, lpeg.Carg, lpeg.Ct, lpeg.Cc, lpeg.Cf, lpeg.Cs @@ -118,24 +118,33 @@ css.padding = padding -- print(padding("0",pixel,hsize,exheight,emwidth)) --- local currentfont = font.current --- local texget = tex.get --- local hashes = fonts.hashes --- local quads = hashes.quads --- local xheights = hashes.xheights --- --- local function padding(str) --- local font = currentfont() --- local exheight = xheights[font] --- local emwidth = quads[font] --- local hsize = texget("hsize")/100 --- local pixel = emwidth/100 --- return padding(str,pixel,hsize,exheight,emwidth) --- end --- --- function css.simplepadding(str) --- context("%ssp",padding(str,pixel,hsize,exheight,emwidth)) --- end +local context = context + +if context then + + local currentfont = font.current + local texget = tex.get + local hashes = fonts.hashes + local quads = hashes.quads + local xheights = hashes.xheights + + local function todimension(str) + local font = currentfont() + local exheight = xheights[font] + local emwidth = quads[font] + local hsize = texget("hsize")/100 + local pixel = emwidth/100 + return dimension(str,pixel,hsize,exheight,emwidth) + end + + css.todimension = todimension + + function context.cssdimension(str) + -- context("%ssp",todimension(str)) + context(todimension(str) .. "sp") + end + +end local pattern = Cf( Ct("") * ( Cg( @@ -993,3 +1002,91 @@ interfaces.implement { actions = css.mappedstylevalue, arguments = "3 strings", } + +-- more (for mm) + +local containsws = string.containsws +local classsplitter = lpeg.tsplitat(whitespace^1) + +function xml.functions.classes(e,class) -- cache + if class then + local at = e.at + local data = at[class] or at.class + if data then + return lpegmatch(classsplitter,data) or { } + end + end + return { } +end + +-- function xml.functions.hasclass(e,class,name) +-- if class then +-- local at = e.at +-- local data = at[class] or at.class +-- if data then +-- return data == name or containsws(data,name) +-- end +-- end +-- return false +-- end +-- +-- function xml.expressions.hasclass(attribute,name) +-- if attribute then +-- return attribute == name or containsws(attribute,name) +-- end +-- return false +-- end + +function xml.functions.hasclass(e,class,name,more,...) + if class and name then + local at = e.at + local data = at[class] or at.class + if not data or data == "" then + return false + end + if data == name or data == more then + return true + end + if containsws(data,name) then + return true + end + if not more then + return false + end + if containsws(data,more) then + return true + end + for i=1,select("#",...) do + if containsws(data,select(i,...)) then + return true + end + end + end + return false +end + +function xml.expressions.hasclass(data,name,more,...) + if data then + if not data or data == "" then + return false + end + if data == name or data == more then + return true + end + if containsws(data,name) then + return true + end + if not more then + return false + end + if containsws(data,more) then + return true + end + for i=1,select("#",...) do + if containsws(data,select(i,...)) then + return true + end + end + end + return false +end diff --git a/tex/context/base/mkiv/lxml-lpt.lua b/tex/context/base/mkiv/lxml-lpt.lua index bb6fb4568..9cccac120 100644 --- a/tex/context/base/mkiv/lxml-lpt.lua +++ b/tex/context/base/mkiv/lxml-lpt.lua @@ -1592,8 +1592,8 @@ end -- local w = lpeg.patterns.whitespace -- local p = w^0 * lpeg.Cf(lpeg.Ct("") * lpeg.Cg(lpeg.C((1-w)^1) * lpeg.Cc(true) * w^0)^1,rawset) --- function xml.functions.classes(e) -- cache --- local class = e.at.class +-- function xml.functions.classes(e,class) -- cache +-- class = class and e.at[class] or e.at.class -- if class then -- return lpegmatch(p,class) -- else diff --git a/tex/context/base/mkiv/lxml-tex.lua b/tex/context/base/mkiv/lxml-tex.lua index b8280ba9c..eed3b123a 100644 --- a/tex/context/base/mkiv/lxml-tex.lua +++ b/tex/context/base/mkiv/lxml-tex.lua @@ -1997,7 +1997,7 @@ do implement { name = "xmldoifatt", arguments = "3 strings", - actions = function(id,l,v) + actions = function(id,k,v) local e = getid(id) ctx_doif(e and e.at[k] == v or false) end @@ -2006,7 +2006,7 @@ do implement { name = "xmldoifnotatt", arguments = "3 strings", - actions = function(id,l,v) + actions = function(id,k,v) local e = getid(id) ctx_doifnot(e and e.at[k] == v or false) end @@ -2015,7 +2015,7 @@ do implement { name = "xmldoifelseatt", arguments = "3 strings", - actions = function(id,l,v) + actions = function(id,k,v) local e = getid(id) ctx_doifelse(e and e.at[k] == v or false) end diff --git a/tex/context/base/mkiv/math-ext.lua b/tex/context/base/mkiv/math-ext.lua index a4b865713..15a93d62e 100644 --- a/tex/context/base/mkiv/math-ext.lua +++ b/tex/context/base/mkiv/math-ext.lua @@ -7,22 +7,23 @@ if not modules then modules = { } end modules ['math-ext'] = { } local rawget = rawget - -local trace_virtual = false trackers.register("math.virtual", function(v) trace_virtual = v end) - local basename = file.basename +local sortedhash = table.sortedhash + +local mathematics = mathematics +local extras = mathematics.extras or { } +mathematics.extras = extras -local mathematics = mathematics -local characters = characters +local characters = characters +local chardata = characters.data +local mathpairs = characters.mathpairs -local report_math = logs.reporter("mathematics") +local trace_virtual = false +local report_math = logs.reporter("mathematics") -mathematics.extras = mathematics.extras or { } -local extras = mathematics.extras +trackers.register("math.virtual", function(v) trace_virtual = v end) -local mathplus = { } -local chardata = characters.data -local mathpairs = characters.mathpairs +local mathplus = { } -- todo: store them and skip storage if already stored -- todo: make a char-ctx.lua (or is this already side effect of save in format) @@ -47,7 +48,7 @@ function extras.copy(target,original) local characters = target.characters local properties = target.properties local parameters = target.parameters - for unicode in table.sortedhash(mathplus) do + for unicode in sortedhash(mathplus) do local extradesc = chardata[unicode] local nextinsize = extradesc.nextinsize if nextinsize then diff --git a/tex/context/base/mkiv/math-fbk.lua b/tex/context/base/mkiv/math-fbk.lua index 7aa8c437f..0d8fda7d4 100644 --- a/tex/context/base/mkiv/math-fbk.lua +++ b/tex/context/base/mkiv/math-fbk.lua @@ -20,10 +20,22 @@ local sortedhash = table.sortedhash local fallbacks = { } mathematics.fallbacks = fallbacks +local helpers = fonts.helpers +local prependcommands = helpers.prependcommands +local charcommand = helpers.commands.char +local leftcommand = helpers.commands.left +local rightcommand = helpers.commands.right +local upcommand = helpers.commands.up +local downcommand = helpers.commands.down +local dummycommand = helpers.commands.dummy +local popcommand = helpers.commands.pop +local pushcommand = helpers.commands.push + local virtualcharacters = { } -local identifiers = fonts.hashes.identifiers -local lastmathids = fonts.hashes.lastmathids +local hashes = fonts.hashes +local identifiers = hashes.identifiers +local lastmathids = hashes.lastmathids -- we need a trick (todo): if we define scriptscript, script and text in -- that order we could use their id's .. i.e. we could always add a font @@ -151,22 +163,21 @@ local function reference(index,char) if index then return { "slot", index, char } else - return { "char", char } + return charcommand[char] end end -local function raised(data,down) - local replacement = data.replacement - local character = data.scriptdata.characters[replacement] +local function raised(data,replacement,down) + local character = data.scriptdata.characters[replacement] if character then + local size = data.size return { width = character.width, height = character.height, depth = character.depth, commands = { - { "down", down and data.size/4 or -data.size/2 }, -- maybe exheight + down and downcommand[size/4] or upcommand[size/2], reference(data.scriptindex,replacement) - -- { "slot", data.scriptindex or 0, char } -- hm, data.mathrelation.scriptindex } } end @@ -177,33 +188,18 @@ end -- virtualcharacters[0x208A] = 0x2212 -- virtualcharacters[0x208B] = 0x002B -virtualcharacters[0x207A] = function(data) - data.replacement = 0x002B - return raised(data) -end - -virtualcharacters[0x207B] = function(data) - data.replacement = 0x2212 - return raised(data) -end - -virtualcharacters[0x208A] = function(data) - data.replacement = 0x002B - return raised(data,true) -end - -virtualcharacters[0x208B] = function(data) - data.replacement = 0x2212 - return raised(data,true) -end +virtualcharacters[0x207A] = function(data) return raised(data,0x002B) end +virtualcharacters[0x207B] = function(data) return raised(data,0x2212) end +virtualcharacters[0x208A] = function(data) return raised(data,0x002B,true) end +virtualcharacters[0x208B] = function(data) return raised(data,0x2212,true) end -- local function repeated(data,char,n,fraction) -- local character = data.characters[char] -- if character then -- local width = character.width -- local delta = width - character.italic -- width * fraction --- local c = { "char", char } --- local r = { "right", right } +-- local c = charcommand[char] +-- local r = rightcommand[right] -- local commands = { } -- for i=1,n-1 do -- width = width + delta @@ -234,14 +230,9 @@ addextra(0xFE350) -- MATHEMATICAL DOUBLE ARROW LEFT END addextra(0xFE351) -- MATHEMATICAL DOUBLE ARROW MIDDLE PART addextra(0xFE352) -- MATHEMATICAL DOUBLE ARROW RIGHT END -local push = { "push" } -local pop = { "pop" } -local leftarrow = { "char", 0x2190 } -local relbar = { "char", 0x2212 } -local rightarrow = { "char", 0x2192 } --- local leftarrow = { "slot", 0, 0x2190 } --- local relbar = { "slot", 0, 0x2212 } --- local rightarrow = { "slot", 0, 0x2192 } +local leftarrow = charcommand[0x2190] +local relbar = charcommand[0x2212] +local rightarrow = charcommand[0x2192] virtualcharacters[0xFE350] = function(data) -- return combined(data,0x2190,0x2212) -- leftarrow relbar @@ -254,11 +245,11 @@ virtualcharacters[0xFE350] = function(data) height = size, depth = size, commands = { - push, - { "down", size/2 }, + pushcommand, + downcommand[size/2], leftarrow, - pop, - { "down", -size/2 }, + popcommand, + upcommand[size/2], relbar, } } @@ -275,11 +266,11 @@ virtualcharacters[0xFE351] = function(data) height = size, depth = size, commands = { - push, - { "down", size/2 }, + pushcommand, + downcommand[size/2], relbar, - pop, - { "down", -size/2 }, + popcommand, + upcommand[size/2], relbar, } } @@ -297,12 +288,12 @@ virtualcharacters[0xFE352] = function(data) height = size, depth = size, commands = { - push, - { "down", size/2 }, + pushcommand, + downcommand[size/2], relbar, - pop, - { "right", chartwo.width - charone.width }, - { "down", -size/2 }, + popcommand, + rightcommand[chartwo.width - charone.width], + upcommand[size/2], rightarrow, } } @@ -325,10 +316,11 @@ local function accent_to_extensible(target,newchr,original,oldchr,height,depth,s height = height or 0 depth = depth or 0 end - local correction = swap and { "down", (olddata.height or 0) - height } or { "down", olddata.height + (offset or 0)} + local correction = swap and + downcommand[(olddata.height or 0) - height] + or downcommand[olddata.height + (offset or 0)] local newdata = { - commands = { correction, { "slot", 1, oldchr } }, - -- commands = { correction, { "slot", 0, oldchr } }, + commands = { correction, charcommand[oldchr] }, width = olddata.width, height = height, depth = depth, @@ -340,14 +332,12 @@ local function accent_to_extensible(target,newchr,original,oldchr,height,depth,s local oldnextdata = characters[nextglyph] if oldnextdata then local newnextdata = { - commands = { correction, { "slot", 1, nextglyph } }, - -- commands = { correction, { "slot", 0, nextglyph } }, + commands = { correction, charcommand[nextglyph] }, width = oldnextdata.width, height = height, depth = depth, } --- local newnextglyph = addprivate(target,formatters["M-N-%H"](nextglyph),newnextdata) - local newnextglyph = addprivate(target,nil,newnextdata) + local newnextglyph = addprivate(target,formatters["M-N-%H"](nextglyph),newnextdata) newdata.next = newnextglyph local nextnextglyph = oldnextdata.next if nextnextglyph == nextglyph then @@ -372,14 +362,12 @@ local function accent_to_extensible(target,newchr,original,oldchr,height,depth,s local olddata = characters[oldglyph] if olddata then local newdata = { - commands = { correction, { "slot", 1, oldglyph } }, - -- commands = { correction, { "slot", 0, oldglyph } }, + commands = { correction, charcommand[oldglyph] }, width = olddata.width, height = height, depth = depth, } --- hvi.glyph = addprivate(target,formatters["M-H-%H"](oldglyph),newdata) - hvi.glyph = addprivate(target,nil,newdata) + hvi.glyph = addprivate(target,formatters["M-H-%H"](oldglyph),newdata) else report_fallbacks("error in fallback: no valid horiz_variants, slot %X, index %i",oldglyph,i) end @@ -394,14 +382,14 @@ end virtualcharacters[0x203E] = function(data) local target = data.target local height, depth = 0, 0 --- local mathparameters = target.mathparameters --- if mathparameters then --- height = mathparameters.OverbarVerticalGap --- depth = mathparameters.UnderbarVerticalGap --- else + -- local mathparameters = target.mathparameters + -- if mathparameters then + -- height = mathparameters.OverbarVerticalGap + -- depth = mathparameters.UnderbarVerticalGap + -- else height = target.parameters.xheight/4 depth = height --- end + -- end return accent_to_extensible(target,0x203E,data.original,0x0305,height,depth,nil,nil,0x203E) end @@ -431,7 +419,7 @@ local function spacefraction(data,fraction) local width = fraction * data.target.parameters.space return { width = width, - commands = { { "right", width } } + commands = { rightcommand[width] } } end @@ -439,7 +427,7 @@ local function charfraction(data,char) local width = data.target.characters[char].width return { width = width, - commands = { { "right", width } } + commands = { rightcommand[width] } } end @@ -447,7 +435,7 @@ local function quadfraction(data,fraction) local width = fraction * data.target.parameters.quad return { width = width, - commands = { { "right", width } } + commands = { rightcommand[width] } } end @@ -527,9 +515,8 @@ local function smashed(data,unicode,optional) local shift = oldchar.height - height local newchar = { commands = { - { "down", shift }, - { "slot", 0, unicode }, --- { "char", unicode }, + downcommand[shift], + charcommand[unicode], }, height = height, width = oldchar.width, @@ -607,11 +594,11 @@ local function actuarian(data) width = basewidth + 4 * linewidth, unicode = 0x20E7, commands = { - { "right", 2 * linewidth }, - { "down", - baseheight - 3 * linewidth }, + rightcommand[2 * linewidth], + downcommand[- baseheight - 3 * linewidth], { "rule", linewidth, basewidth + 4 * linewidth }, - { "right", -linewidth }, - { "down", baseheight + 4 * linewidth }, + leftcommand[linewidth], + downcommand[baseheight + 4 * linewidth], { "rule", baseheight + 5 * linewidth, linewidth }, }, } @@ -629,11 +616,11 @@ local function equals(data,unicode,snippet,advance,n) -- mathpair needs them unicode = unicode, width = n*basechar.width + (n-1)*advance, commands = { - { "char", snippet }, - { "right", advance }, - { "char", snippet }, - n > 2 and { "right", advance } or nil, - n > 2 and { "char", snippet } or nil, + charcommand[snippet], + rightcommand[advance], + charcommand[snippet], + n > 2 and rightcommand[advance] or nil, + n > 2 and charcommand[snippet] or nil, }, } end @@ -657,11 +644,11 @@ virtualcharacters[0x2980] = function(data) return equals(data,0x2980,0x007C,-1/8 -- height = height, -- we cheat (no time now) -- depth = depth, -- we cheat (no time now) -- commands = { --- { "down", - height/2 }, -- sort of works --- { "char", 0x003D }, --- { "right", -width }, --- { "down", height }, -- sort of works --- { "char", 0x003D }, +-- upcommand[height/2], -- sort of works +-- charcommand[0x003D], +-- leftcommand[width], +-- downcommand[height], -- sort of works +-- charcommand[0x003D], -- }, -- } -- end diff --git a/tex/context/base/mkiv/math-ini.mkiv b/tex/context/base/mkiv/math-ini.mkiv index 17d900d74..9dfc317dd 100644 --- a/tex/context/base/mkiv/math-ini.mkiv +++ b/tex/context/base/mkiv/math-ini.mkiv @@ -1273,9 +1273,13 @@ %D Memory saver: +\def\math_basics_check_compact + {\doifelse{\mathematicsparameter\c!compact}\v!yes + \enabledirectives\disabledirectives[math.virtual.optional]} + \appendtoks \ifx\currentmathematics\empty - \doifelse{\mathematicsparameter\c!compact}\v!yes\enabledirectives\disabledirectives[math.virtual.optional]% + \math_basics_check_compact % less tracing \fi \to \everysetupmathematics @@ -1311,18 +1315,31 @@ %D \HL %D \stoptabulate +% We will use proper constants when we go numbers instead of XXX. + \newconditional\c_math_right_to_left +\installcorenamespace{mathaligndirection} + +\setvalue{\??mathaligndirection r2l}{\settrue\c_math_right_to_left} +\setvalue{\??mathaligndirection\v!righttoleft}{\settrue\c_math_right_to_left} + \appendtoks - \doifelse{\mathematicsparameter\c!align}{r2l}\settrue\setfalse\c_math_right_to_left + \ifcsname\??mathaligndirection\mathematicsparameter\c!align\endcsname + \lastnamedcs + \else + \setfalse\c_math_right_to_left + \fi \to \everyswitchmathematics \unexpanded\def\math_basics_synchronize_direction {\mathdir T\ifconditional\c_math_right_to_left R\else L\fi T} +% Not \everymathematics as it comes too late and I'm not in the mood for a mixed mode +% kludge now (should be a property of beginmath nodes and passed to callbacks). + \appendtoks \math_basics_synchronize_direction -%to \everymathematics % comes too late and I'm not in the mood for a mixed mode kludge now (should be a property of beginmath nodes and passed to callbacks) \to \everyswitchmathematics % experimental (needed for an article) @@ -1337,11 +1354,6 @@ \letvalue{\??mathbidi\v!yes}\math_bidi_enable \letvalue{\??mathbidi\v!no }\math_bidi_disable -% \appendtoks -% \edef\p_bidi{\mathematicsparameter\c!bidi}% -% \csname\??mathbidi\ifcsname\??mathbidi\p_bidi\endcsname\p_bidi\else\v!no\fi\endcsname -% \to \everysetupmathematics - \appendtoks \edef\p_bidi{\mathematicsparameter\c!bidi}% still needed ? \ifcsname\??mathbidi\p_bidi\endcsname\lastnamedcs\else\math_bidi_disable\fi @@ -2468,10 +2480,13 @@ % I need to decide: % -%mathscriptboxmode\zerocount % no kerning -%mathscriptboxmode\plusone % lists -\mathscriptboxmode\plustwo % lists and boxes -%mathscriptboxmode\plusthree % lists and boxes with \boundary=1 (also for testing and demo) +%mathscriptboxmode \zerocount % no kerning +%mathscriptboxmode \plusone % lists +\mathscriptboxmode \plustwo % lists and boxes +\mathscriptcharmode\plusone % lists and boxes +%mathscriptboxmode \plusthree % lists and boxes with \boundary=1 (also for testing and demo) + +\mathrulethicknessmode\plusone \unexpanded\def\mathtext {\mathortext{\math_text_choice_font\relax}\hbox} \unexpanded\def\mathword {\mathortext{\math_text_choice_word\relax}\hbox} diff --git a/tex/context/base/mkiv/math-noa.lua b/tex/context/base/mkiv/math-noa.lua index 529837cfa..20f77411e 100644 --- a/tex/context/base/mkiv/math-noa.lua +++ b/tex/context/base/mkiv/math-noa.lua @@ -101,6 +101,7 @@ local setfam = nuts.setfam local setsubtype = nuts.setsubtype local setattr = nuts.setattr local setattrlist = nuts.setattrlist +local setwidth = nuts.setwidth local getfield = nuts.getfield local getnext = nuts.getnext @@ -211,6 +212,7 @@ local right_fence_code = fencecodes.right -- local sf = setfield local st = setmetatableindex("number") setfield = function(n,f,v) st[f] = st[f] + 1 sf(n,f,v) end mathematics.SETFIELD = st local function process(start,what,n,parent) + if n then n = n + 1 else @@ -456,6 +458,34 @@ do "pseudobold", } + families[math_fraction] = function(pointer,what,n,parent) + local a = getattr(pointer,a_mathfamily) + if a and a >= 0 then + if a > 0 then + setattr(pointer,a_mathfamily,0) + if a > 5 then + a = a - 3 + end + end + setfam(pointer,a) + end + processnested(pointer,families,n+1) + end + + families[math_noad] = function(pointer,what,n,parent) + local a = getattr(pointer,a_mathfamily) + if a and a >= 0 then + if a > 0 then + setattr(pointer,a_mathfamily,0) + if a > 5 then + a = a - 3 + end + end + setfam(pointer,a) + end + processnested(pointer,families,n+1) + end + families[math_char] = function(pointer) if getfam(pointer) == 0 then local a = getattr(pointer,a_mathfamily) @@ -501,7 +531,6 @@ do end end end - families[math_delim] = function(pointer) if getfield(pointer,"small_fam") == 0 then local a = getattr(pointer,a_mathfamily) diff --git a/tex/context/base/mkiv/math-tag.lua b/tex/context/base/mkiv/math-tag.lua index d1ed90d38..9837dec35 100644 --- a/tex/context/base/mkiv/math-tag.lua +++ b/tex/context/base/mkiv/math-tag.lua @@ -287,8 +287,7 @@ else local cache = { } -- we can have nested unboxed mess so best local to runner local keep = nil -- local keep = { } -- win case we might need to move keep outside - for n in traverse_nodes(list) do - local id = getid(n) + for n, id in traverse_nodes(list) do local mth = id == math_code and getsubtype(n) if mth == 0 then -- insert(keep,text) diff --git a/tex/context/base/mkiv/math-vfu.lua b/tex/context/base/mkiv/math-vfu.lua index 4767ffa90..338a4bef7 100644 --- a/tex/context/base/mkiv/math-vfu.lua +++ b/tex/context/base/mkiv/math-vfu.lua @@ -46,9 +46,18 @@ fonts.encodings.math = mathencodings -- better is then: fonts.encodings.vecto local vfmath = allocate() fonts.handlers.vf.math = vfmath +local helpers = fonts.helpers +local vfcommands = helpers.commands +local rightcommand = vfcommands.right +local leftcommand = vfcommands.left +local downcommand = vfcommands.down +local upcommand = vfcommands.up +local push = vfcommands.push +local pop = vfcommands.pop + local shared = { } --- local push, pop, back = { "push" }, { "pop" }, { "slot", 1, 0x2215 } +-- local back = { "slot", 1, 0x2215 } -- -- local function negate(main,characters,id,size,unicode,basecode) -- if not characters[unicode] then @@ -64,8 +73,8 @@ local shared = { } -- commands = { -- { "slot", 1, basecode }, -- push, --- { "down", ht/5}, --- { "right", - wd/2}, +-- downcommand[ht/5], +-- leftcommand[wd/2], -- back, -- push, -- } @@ -139,107 +148,96 @@ local function parent(main,characters,id,size,unicode,first,rule,last) end end -local push, pop, step = { "push" }, { "pop" }, 0.2 -- 0.1 is nicer but gives larger files +local step = 0.2 -- 0.1 is nicer but gives larger files local function make(main,characters,id,size,n,m) local old = 0xFF000 + n - local c = characters[old] + local c = characters[old] if c then - local upslot, dnslot, uprule, dnrule = 0xFF100 + n, 0xFF200 + n, 0xFF300 + m, 0xFF400 + m - local xu = main.parameters.x_height + 0.3*size - local xd = 0.3*size - local w, h, d = c.width, c.height, c.depth + local upslot = 0xFF100 + n + local dnslot = 0xFF200 + n + local uprule = 0xFF300 + m + local dnrule = 0xFF400 + m + local xu = main.parameters.x_height + 0.3*size + local xd = 0.3*size + local w = c.width + local h = c.height + local d = c.depth local thickness = h - d local rulewidth = step*size -- we could use an overlap - local slot = { "slot", id, old } - local rule = { "rule", thickness, rulewidth } - local up = { "down", -xu } - local dn = { "down", xd } - local ht, dp = xu + 3*thickness, 0 + local slot = { "slot", id, old } + local rule = { "rule", thickness, rulewidth } + local up = upcommand[xu] + local dn = downcommand[xd] + local ht = xu + 3*thickness + local dp = 0 if not characters[uprule] then - characters[uprule] = { width = rulewidth, height = ht, depth = dp, commands = { push, up, rule, pop } } + characters[uprule] = { + width = rulewidth, + height = ht, + depth = dp, + commands = { push, up, rule, pop }, + } end - characters[upslot] = { width = w, height = ht, depth = dp, commands = { push, up, slot, pop } } - local ht, dp = 0, xd + 3*thickness + characters[upslot] = { + width = w, + height = ht, + depth = dp, + commands = { push, up, slot, pop }, + } + local ht = 0 + local dp = xd + 3*thickness if not characters[dnrule] then - characters[dnrule] = { width = rulewidth, height = ht, depth = dp, commands = { push, dn, rule, pop } } + characters[dnrule] = { + width = rulewidth, + height = ht, + depth = dp, + commands = { push, dn, rule, pop } + } end - characters[dnslot] = { width = w, height = ht, depth = dp, commands = { push, dn, slot, pop } } + characters[dnslot] = { + width = w, + height = ht, + depth = dp, + commands = { push, dn, slot, pop }, + } end end local function clipped(main,characters,id,size,unicode,original) -- push/pop needed? local minus = characters[original] if minus then - local mu = size/18 - local step = 3*mu + local mu = size/18 + local step = 3*mu local width = minus.width if width > step then width = width - step - step = step / 2 + step = step / 2 else width = width / 2 - step = width + step = width end characters[unicode] = { width = width, height = minus.height, depth = minus.depth, - commands = { push, { "right", -step }, { "slot", id, original }, pop } + commands = { + push, + leftcommand[step], + { "slot", id, original }, + pop, + } } end end --- fails: pdf:page: pdf:direct: ... some funny displacement - --- this does not yet work ... { "scale", 2, 0, 0, 3 } .. commented code --- --- this does not work ... no interpretation going on here --- --- local nodeinjections = backends.nodeinjections --- { "node", nodeinjections.save() }, --- { "node", nodeinjections.transform(.7,0,0,.7) }, --- commands[#commands+1] = { "node", nodeinjections.restore() } - --- local done = { } --- --- local function raise(main,characters,id,size,unicode,private,n,id_of_smaller) -- this is a real fake mess --- local raised = characters[private] --- if raised then --- if not done[unicode] then --- report_virtual("temporary too large %U due to issues in luatex backend",unicode) --- done[unicode] = true --- end --- local up = 0.85 * main.parameters.x_height --- local slot = { "slot", id, private } --- local commands = { --- push, --- { "down", - up }, --- -- { "scale", .7, 0, 0, .7 }, --- slot, --- } --- for i=2,n do --- commands[#commands+1] = slot --- end --- commands[#commands+1] = pop --- characters[unicode] = { --- width = .7 * n * raised.width, --- height = .7 * (raised.height + up), --- depth = .7 * (raised.depth - up), --- commands = commands, --- } --- end --- end - local function raise(main,characters,id,size,unicode,private,n,id_of_smaller) -- this is a real fake mess local raised = fonts.hashes.characters[main.fonts[id_of_smaller].id][private] -- characters[private] if raised then - local up = 0.85 * main.parameters.x_height + local up = 0.85 * main.parameters.x_height local slot = { "slot", id_of_smaller, private } local commands = { - push, - { "down", - up }, - slot, + push, upcommand[up], slot, } for i=2,n do commands[#commands+1] = slot @@ -258,65 +256,85 @@ end local function dots(main,characters,id,size,unicode) local c = characters[0x002E] if c then - local w, h, d = c.width, c.height, c.depth - local mu = size/18 - local right3mu = { "right", 3*mu } - local right1mu = { "right", 1*mu } - local up1size = { "down", -.1*size } - local up4size = { "down", -.4*size } - local up7size = { "down", -.7*size } - local right2muw = { "right", 2*mu + w } - local slot = { "slot", id, 0x002E } + local w = c.width + local h = c.height + local d = c.depth + local mu = size/18 + local right3mu = rightcommand[3*mu] + local right1mu = rightcommand[1*mu] + local up1size = upcommand[.1*size] + local up4size = upcommand[.4*size] + local up7size = upcommand[.7*size] + local right2muw = rightcommand[2*mu + w] + local slot = { "slot", id, 0x002E } if unicode == 0x22EF then local c = characters[0x022C5] if c then - local w, h, d = c.width, c.height, c.depth - local slot = { "slot", id, 0x022C5 } + local width = c.width + local height = c.height + local depth = c.depth + local slot = { "slot", id, 0x022C5 } characters[unicode] = { - width = 3*w + 2*3*mu, height = h, depth = d, - commands = { push, slot, right3mu, slot, right3mu, slot, pop } + width = 3*width + 2*3*mu, + height = height, + depth = depth, + commands = { + push, slot, right3mu, slot, right3mu, slot, pop, + } } end elseif unicode == 0x22EE then -- weird height ! characters[unicode] = { - width = w, height = h+(1.4)*size, depth = 0, - commands = { push, push, slot, pop, up4size, push, slot, pop, up4size, slot, pop } + width = w, + height = h+(1.4)*size, + depth = 0, + commands = { + push, push, slot, pop, up4size, push, slot, pop, up4size, slot, pop, + } } elseif unicode == 0x22F1 then characters[unicode] = { - width = 3*w + 6*size/18, height = 1.5*size, depth = 0, + width = 3*w + 6*size/18, + height = 1.5*size, + depth = 0, commands = { push, - right1mu, - push, up7size, slot, pop, - right2muw, - push, up4size, slot, pop, - right2muw, - push, up1size, slot, pop, - right1mu, + right1mu, + push, up7size, slot, pop, + right2muw, + push, up4size, slot, pop, + right2muw, + push, up1size, slot, pop, + right1mu, pop } } elseif unicode == 0x22F0 then characters[unicode] = { - width = 3*w + 6*size/18, height = 1.5*size, depth = 0, + width = 3*w + 6*size/18, + height = 1.5*size, + depth = 0, commands = { push, - right1mu, - push, up1size, slot, pop, - right2muw, - push, up4size, slot, pop, - right2muw, - push, up7size, slot, pop, - right1mu, + right1mu, + push, up1size, slot, pop, + right2muw, + push, up4size, slot, pop, + right2muw, + push, up7size, slot, pop, + right1mu, pop } } else characters[unicode] = { - width = 3*w + 2*3*mu, height = h, depth = d, - commands = { push, slot, right3mu, slot, right3mu, slot, pop } + width = 3*w + 2*3*mu, + height = h, + depth = d, + commands = { + push, slot, right3mu, slot, right3mu, slot, pop, + } } end end @@ -331,21 +349,23 @@ local function vertbar(main,characters,id,size,parent,scale,unicode) width = cp.width, height = cp.height + sc, depth = cp.depth + sc, + next = cp.next, -- can be extensible commands = { - push, { "down", -sc }, pc, pop, - push, { "down", sc }, pc, pop, + push, upcommand [sc], pc, pop, + push, downcommand[sc], pc, pop, pc, }, - next = cp.next -- can be extensible } cp.next = unicode end end local function jointwo(main,characters,id,size,unicode,u1,d12,u2,what) - local c1, c2 = characters[u1], characters[u2] + local c1 = characters[u1] + local c2 = characters[u2] if c1 and c2 then - local w1, w2 = c1.width, c2.width + local w1 = c1.width + local w2 = c2.width local mu = size/18 characters[unicode] = { width = w1 + w2 - d12 * mu, @@ -353,7 +373,7 @@ local function jointwo(main,characters,id,size,unicode,u1,d12,u2,what) depth = max(c1.depth or 0, c2.depth or 0), commands = { { "slot", id, u1 }, - { "right", -d12*mu } , + leftcommand[d12*mu], { "slot", id, u2 }, }, } @@ -361,19 +381,23 @@ local function jointwo(main,characters,id,size,unicode,u1,d12,u2,what) end local function jointhree(main,characters,id,size,unicode,u1,d12,u2,d23,u3) - local c1, c2, c3 = characters[u1], characters[u2], characters[u3] + local c1 = characters[u1] + local c2 = characters[u2] + local c3 = characters[u3] if c1 and c2 and c3 then - local w1, w2, w3 = c1.width, c2.width, c3.width + local w1 = c1.width + local w2 = c2.width + local w3 = c3.width local mu = size/18 characters[unicode] = { width = w1 + w2 + w3 - d12*mu - d23*mu, height = max(c1.height or 0, c2.height or 0, c3.height or 0), - depth = max(c1.depth or 0, c2.depth or 0, c3.depth or 0), + depth = max(c1.depth or 0, c2.depth or 0, c3.depth or 0), commands = { { "slot", id, u1 }, - { "right", - d12*mu } , + leftcommand[d12*mu], { "slot", id, u2 }, - { "right", - d23*mu }, + leftcommand[d23*mu], { "slot", id, u3 }, } } @@ -383,9 +407,8 @@ end local function stack(main,characters,id,size,unicode,u1,d12,u2) local c1, c2 = characters[u1], characters[u2] if c1 and c2 then - local w1, w2 = c1.width, c2.width - local h1, h2 = c1.height, c2.height - local d1, d2 = c1.depth, c2.depth + local w1, h1, d1 = c1.width, c1.height, c1.depth + local w2, h2, d2 = c2.width, c2.height, c2.depth local mu = size/18 characters[unicode] = { width = w1, @@ -393,8 +416,8 @@ local function stack(main,characters,id,size,unicode,u1,d12,u2) depth = d1, commands = { { "slot", id, u1 }, - { "right", - w1/2 - w2/2 } , - { "down", -h1 + d2 -d12*mu } , + leftcommand[w1/2 + w2/2], + downcommand[-h1 + d2 -d12*mu], { "slot", id, u2 }, } } @@ -407,15 +430,13 @@ local function repeated(main,characters,id,size,unicode,u,n,private,fraction) -- local width = c.width local italic = fraction*width -- c.italic or 0 -- larger ones have funny italics local tc = { "slot", id, u } - local tr = { "right", -italic } -- see hack elsewhere + local tr = leftcommand[italic] -- see hack elsewhere local commands = { } for i=1,n-1 do commands[#commands+1] = tc commands[#commands+1] = tr end commands[#commands+1] = tc --- inspect(c) --- inspect(commands) local next = c.next if next then repeated(main,characters,id,size,private,next,n,private+1,fraction) @@ -623,7 +644,6 @@ local function copy_glyph(main,target,original,unicode,slot) } local newnextglyph = addprivate(main,formatters["M-N-%H"](nextglyph),newnextdata) newdata.next = newnextglyph --- report_virtual("copied next: %X",newdata.next) local nextnextglyph = oldnextdata.next if nextnextglyph == nextglyph then break @@ -649,7 +669,6 @@ local function copy_glyph(main,target,original,unicode,slot) commands = { { "slot", slot, oldglyph } }, } hvi.glyph = addprivate(main,formatters["M-H-%H"](oldglyph),newdata) --- report_virtual("copied h variant: %X at index %i",hvi.glyph,i) end end local vv = olddata.vert_variants @@ -668,7 +687,6 @@ local function copy_glyph(main,target,original,unicode,slot) commands = { { "slot", slot, oldglyph } }, } vvi.glyph = addprivate(main,formatters["M-V-%H"](oldglyph),newdata) --- report_virtual("copied v variant: %X at index %i",vvi.glyph,i) end end return newdata diff --git a/tex/context/base/mkiv/meta-blb.lua b/tex/context/base/mkiv/meta-blb.lua new file mode 100644 index 000000000..202c2850b --- /dev/null +++ b/tex/context/base/mkiv/meta-blb.lua @@ -0,0 +1,305 @@ +if not modules then modules = { } end modules ['meta-blb'] = { + version = 1.001, + comment = "companion to mlib-ctx.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files", +} + +-- This could be integrated in other modules but for me it also serves +-- as an example of usign the plugin mechanism. + +local tonumber = tonumber + +local setmetatableindex = table.setmetatableindex +local insert, remove = table.insert, table.remove + +local topoints = number.topoints +local mpprint = mp.print +local mpinteger = mp.integer +local mppoints = mp.points +local mptriplet = mp.triplet +local mptripletpoints = mp.tripletpoints + +local texsetbox = tex.setbox +local toutf = nodes.toutf +local hpack_nodes = nodes.hpack + +local trace = false +local report = logs.reporter("metapost","blobs") + +trackers.register("metapost.blobs", function(v) trace = v end) + +-- We start with a text that comes from an analyze stage and can end up with +-- one or more results. For practical reasons we store the blobs in one array +-- and work with ranges. + +local allblobs = { } + +local function newcategory(t,k) + if trace then + report("new category %a",k) + end + local v = { + name = k, + text = "", + blobs = { }, + } + t[k] = v + return v +end + +local texblobs = setmetatableindex(newcategory) + +local function blob_raw_reset(category) + -- we need to keep the allblobs + if category then + if trace then + report("reset category %a",category) + end + texblobs[category] = nil + else + if trace then + report("reset all") + end + texblobs = setmetatableindex(newcategory) + end +end + +local function blob_raw_dimensions(i) + local blob = allblobs[i] + if blob then + return blob.width, blob.height, blob.depth + else + return 0, 0, 0 + end +end + +local function blob_raw_content(i) + return allblobs[i] +end + +local function blob_raw_toutf(i) + return toutf(allblobs[i]) +end + +local function blob_raw_wipe(i) + allblobs[i] = false +end + +mp.blob_raw_dimensions = blob_raw_dimensions +mp.blob_raw_content = blob_raw_content +mp.blob_raw_reset = blob_raw_reset +mp.blob_raw_wipe = blob_raw_wipe +mp.blob_raw_toutf = blob_raw_toutf + +function mp.blob_new(category,text) + if trace then + report("category %a, text %a",category,text) + end + texblobs[category].text = text +end + +function mp.blob_add(category,blob) + local tb = texblobs[category].blobs + local tn = #allblobs + 1 + blob = hpack_nodes(blob) + allblobs[tn] = blob + tb[#tb+1] = tn + if trace then + report("category %a, blob %a set, content %a",category,tn,blob_raw_toutf(tn)) + end +end + +function mp.blob_width(category,i) + local index = texblobs[category].blobs[i] + local blob = allblobs[index] + if blob then + mppoints(blob.width or 0) + else + mpinteger(0) + end +end + +function mp.blob_size(category,i) + mpprint(#texblobs[category].blobs or 0) +end + +function mp.blob_index(category,i) + mpprint(texblobs[category].blobs[i] or 0) +end + +function mp.blob_dimensions(category,i) + local index = texblobs[category].blobs[i] + local blob = allblobs[index] + if blob then + mptripletpoints(blob.width,blob.height,blob.depth) + else + mptriplet(0,0,0) + end +end + +local f_f = string.formatters["%F"] +local sxsy = metapost.sxsy +local cm = metapost.cm + +local function injectblob(object,blob) + local sx, rx, ry, sy, tx, ty = cm(object) + local wd, ht, dp = blob_raw_dimensions(blob) + if wd then + object.path = false + object.color = false + object.grouped = true + object.istext = true + return function() + if trace then + report("injecting blob %a, width %p, heigth %p, depth %p, text %a",blob,wd,ht,dp,blob_raw_toutf(blob)) + end + context.MPLIBgetblobscaledcm(blob, + f_f(sx), f_f(rx), f_f(ry), + f_f(sy), f_f(tx), f_f(ty), + sxsy(wd,ht,dp)) + end + end +end + +mp.blob_inject = injectblob + +local function getblob(box,blob) + texsetbox(box,blob_raw_content(blob)) + blob_raw_wipe(blob) +end + +interfaces.implement { + name = "mpgetblob", + actions = getblob, + arguments = { "integer", "integer" }, +} + +-- the plug: + +local function reset() + blob_raw_reset() +end + +local function analyze(object,prescript) + -- nothing +end + +local function process(object,prescript,before,after) + if prescript.tb_stage == "inject" then + local tb_blob = tonumber(prescript.tb_blob) + if tb_blob then + before[#before+1] = injectblob(object,tb_blob) + end + end +end + +metapost.installplugin(reset,analyze,process) + +-- Here follows an example of usage of the above: a more modern +-- version of followokens (in meta-imp-txt.mkiv). + +local nodecodes = nodes.nodecodes +local kerncodes = nodes.kerncodes + +local glue_code = nodecodes.glue +local kern_code = nodecodes.kern +local c_userkern = kerncodes.userkern +local c_fontkern = kerncodes.fontkern +local c_italickern = kerncodes.italickern +local a_fontkern = attributes.private("fontkern") + +local takebox = tex.takebox +local flatten_list = node.flatten_discretionaries +local remove_node = nodes.remove +local flush_node = nodes.flush + +local addblob = mp.blob_add +local newblob = mp.blob_new + +local visible_code = { + [nodecodes.glyph] = true, + [nodecodes.glue] = true, + [nodecodes.hlist] = true, + [nodecodes.vlist] = true, + [nodecodes.rule] = true, +} + +local function initialize(category,box) + local wrap = takebox(box) + if wrap then + local head = wrap.list + local tail = nil + local temp = nil + if head then + local n = { } + local s = 0 + head = flatten_list(head) + local current = head + while current do + local id = current.id + if visible_code[id] then + head, current, tail = remove_node(head,current) + s = s + 1 + n[s] = tail + elseif id == kern_code then + local subtype = current.subtype + if subtype == c_fontkern or subtype == italickern then -- or current[a_fontkern] + head, current, temp = remove_node(head,current) + tail.next = temp + temp.prev = tail + tail = temp + else + head, current, temp = remove_node(head,current) + s = s + 1 + n[s] = temp + end + elseif id == glue_code then + head, current, temp = remove_node(head,current) + s = s + 1 + n[s] = temp + else + current = current.next + end + end + for i=1,s do + n[i] = addblob(category,n[i]) + end + wrap.list = head + end + flush_node(wrap) + end +end + +interfaces.implement { + name = "MPLIBconvertfollowtext", + arguments = { "integer","integer" }, + actions = initialize, +} + +local function reset() + -- nothing +end + +local function analyze(object,prescript) + if prescript.ft_stage == "trial" then + local ft_category = tonumber(prescript.ft_category) + if ft_category then + newblob(ft_category,object.postscript) -- only for tracing + context.MPLIBfollowtext(ft_category,object.postscript) + metapost.getjobdata().multipass = true + end + end +end + +local function process(object,prescript,before,after) + if prescript.ft_stage == "final" then + object.path = false + object.color = false + object.grouped = true + object.istext = true + end +end + +metapost.installplugin(reset,analyze,process) diff --git a/tex/context/base/mkiv/meta-blb.mkiv b/tex/context/base/mkiv/meta-blb.mkiv new file mode 100644 index 000000000..78e2dde3e --- /dev/null +++ b/tex/context/base/mkiv/meta-blb.mkiv @@ -0,0 +1,50 @@ +%D \module +%D [ file=meta-blb, +%D version=2018.04.12, +%D title=\METAPOST\ Graphics, +%D subtitle=Blobs, +%D author=Hans Hagen, +%D date=\ currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\writestatus{loading}{MetaPost Graphics / Blobs} + +\registerctxluafile{meta-blb}{} + +\unprotect + +\unexpanded\def\MPLIBgetblobscaledcm#1#2#3#4#5#6#7#8#9% + {\clf_mpgetblob\MPtextbox#1\relax + \setbox\MPbox\hpack\bgroup + \dotransformnextbox{#2}{#3}{#4}{#5}{#6}{#7}% + \vpack to \zeropoint\bgroup + \vss + \hpack to \zeropoint \bgroup + % \fastsxsy{#8}{#9}{\raise\dp\MPtextbox\box\MPtextbox}% + \fastsxsy{#8}{#9}{\box\MPtextbox}% + \hss + \egroup + \egroup + \egroup + \smashbox\MPbox + \box\MPbox} + +%D An example of usage: + +\definefontfeature[followtext][liga=no] + +\unexpanded\def\MPLIBfollowtext#1#2% + {\begingroup + \scratchcounter#1\relax + \setbox\scratchbox\hbox{\addff{followtext}#2}% + \clf_MPLIBconvertfollowtext\scratchcounter\scratchbox + \endgroup} + +% \def\reversedtext#1% +% {\cldcontext{table.concat(table.reverse(utf.totable(\!!bs#1\!!es)))}} + +\protect \endinput diff --git a/tex/context/base/mkiv/meta-imp-txt.mkiv b/tex/context/base/mkiv/meta-imp-txt.mkiv index e9660b3a7..34e36ae54 100644 --- a/tex/context/base/mkiv/meta-imp-txt.mkiv +++ b/tex/context/base/mkiv/meta-imp-txt.mkiv @@ -203,6 +203,7 @@ \startluacode local nodecodes = nodes.nodecodes + local kerncodes = nodes.kerncodes local visible_code = { [nodecodes.glyph] = true, @@ -212,54 +213,39 @@ [nodecodes.rule] = true, } - local disc_code = nodecodes.disc - local kern_code = nodecodes.kern - - local c_userkern = nodes.kerncodes.userkern + local kern_code = nodecodes.kern + local c_userkern = kerncodes.userkern local a_fontkern = attributes.private("fontkern") local n = nil local s = 0 function mp.follow_reset() - r = nil + n = nil s = 0 end function mp.follow_initialize(b) - if not r then - local l = tex.takebox(b).list - n = { } - s = 0 - while l do - local c = l - l = l.next - local id = c.id - if visible_code[id] then - s = s + 1 - n[s] = c - c.prev = nil - c.next = nil - elseif id == kern_code then - if c.subtype == c_userkern and not c[a_fontkern] then + if not n then + local head = tex.takebox(b).list + if head then + n = { } + s = 0 + head = node.flatten_discretionaries(head) + local current = head + while current do + local id = current.id + if visible_code[id] then s = s + 1 - n[s] = c - c.prev = nil - else - n[s].next = c - c.prev = n[s] - end - c.next = nil - elseif id == disc_code then - local r = c.replace - while r do + head, current, n[s] = nodes.remove(head,current) + elseif id == kern_code and current.subtype == c_userkern and not current[a_fontkern] then s = s + 1 - n[s] = r - r = r.next - r.prev = nil - r.next = nil + head, current, n[s] = nodes.remove(head,current) + else + current = current.next end end + nodes.flush_list(head) end end end diff --git a/tex/context/base/mkiv/mlib-lua.lua b/tex/context/base/mkiv/mlib-lua.lua index 19e731b85..d934e6472 100644 --- a/tex/context/base/mkiv/mlib-lua.lua +++ b/tex/context/base/mkiv/mlib-lua.lua @@ -62,11 +62,16 @@ end local f_code = formatters["%s return mp._f_()"] -local f_numeric = formatters["%.16f"] -local f_integer = formatters["%i"] -local f_pair = formatters["(%.16f,%.16f)"] -local f_triplet = formatters["(%.16f,%.16f,%.16f)"] -local f_quadruple = formatters["(%.16f,%.16f,%.16f,%.16f)"] +local f_numeric = formatters["%.16f"] +local f_integer = formatters["%i"] +local f_pair = formatters["(%.16f,%.16f)"] +local f_triplet = formatters["(%.16f,%.16f,%.16f)"] +local f_quadruple = formatters["(%.16f,%.16f,%.16f,%.16f)"] + +local f_points = formatters["%p"] +local f_pair_pt = formatters["(%p,%p)"] +local f_triplet_pt = formatters["(%p,%p,%p)"] +local f_quadruple_pt = formatters["(%p,%p,%p,%p)"] local function mpprint(...) -- we can optimize for n=1 for i=1,select("#",...) do @@ -156,6 +161,11 @@ function mp.integer(i) buffer[n] = i or "0" end +function mp.points(i) + n = n + 1 + buffer[n] = i and f_points(i) or "0pt" +end + function mp.pair(x,y) n = n + 1 if type(x) == "table" then @@ -165,6 +175,15 @@ function mp.pair(x,y) end end +function mp.pairpoints(x,y) + n = n + 1 + if type(x) == "table" then + buffer[n] = f_pair_pt(x[1],x[2]) + else + buffer[n] = f_pair_pt(x,y) + end +end + function mp.triplet(x,y,z) n = n + 1 if type(x) == "table" then @@ -174,6 +193,15 @@ function mp.triplet(x,y,z) end end +function mp.tripletpoints(x,y,z) + n = n + 1 + if type(x) == "table" then + buffer[n] = f_triplet_pt(x[1],x[2],x[3]) + else + buffer[n] = f_triplet_pt(x,y,z) + end +end + function mp.quadruple(w,x,y,z) n = n + 1 if type(w) == "table" then @@ -183,7 +211,16 @@ function mp.quadruple(w,x,y,z) end end -function mp.path(t,connector,cycle) +function mp.quadruplepoints(w,x,y,z) + n = n + 1 + if type(w) == "table" then + buffer[n] = f_quadruple_pt(w[1],w[2],w[3],w[4]) + else + buffer[n] = f_quadruple_pt(w,x,y,z) + end +end + +local function mppath(f,t,connector,cycle) if type(t) == "table" then local tn = #t if tn > 0 then @@ -194,11 +231,11 @@ function mp.path(t,connector,cycle) connector = "--" end local ti = t[1] - n = n + 1 ; buffer[n] = f_pair(ti[1],ti[2]) + n = n + 1 ; buffer[n] = f(ti[1],ti[2]) for i=2,tn do local ti = t[i] n = n + 1 ; buffer[n] = connector - n = n + 1 ; buffer[n] = f_pair(ti[1],ti[2]) + n = n + 1 ; buffer[n] = f(ti[1],ti[2]) end if cycle then n = n + 1 ; buffer[n] = connector @@ -208,6 +245,14 @@ function mp.path(t,connector,cycle) end end +function mp.path(...) + mppath(f_pair,...) +end + +function mp.pathpoints(...) + mppath(f_pair_pt,...) +end + function mp.size(t) n = n + 1 buffer[n] = type(t) == "table" and f_numeric(#t) or "0" diff --git a/tex/context/base/mkiv/mlib-pdf.lua b/tex/context/base/mkiv/mlib-pdf.lua index 75f810fb3..453d00aef 100644 --- a/tex/context/base/mkiv/mlib-pdf.lua +++ b/tex/context/base/mkiv/mlib-pdf.lua @@ -430,7 +430,7 @@ function metapost.flush(result,flusher,askedfig) startfigure(properties.number,llx,lly,urx,ury,"begin",figure) result[#result+1] = "q" if objects then - resetplugins(result) -- we should move the colorinitializer here +-- resetplugins(result) -- we should move the colorinitializer here local savedpath = nil local savedhtap = nil for o=1,#objects do @@ -640,6 +640,7 @@ function metapost.flush(result,flusher,askedfig) end end metapost.comment = nocomment + resetplugins(result) -- we should move the colorinitializer here end end end diff --git a/tex/context/base/mkiv/mlib-pps.lua b/tex/context/base/mkiv/mlib-pps.lua index bb5ce31e5..1a6aa5e86 100644 --- a/tex/context/base/mkiv/mlib-pps.lua +++ b/tex/context/base/mkiv/mlib-pps.lua @@ -541,6 +541,8 @@ local function sxsy(wd,ht,dp) -- helper for text return (wd ~= 0 and factor/wd) or 0, (hd ~= 0 and factor/hd) or 0 end +metapost.sxsy = sxsy + -- for stock mp we need to declare the booleans first local no_first_run = "boolean mfun_first_run ; mfun_first_run := false ;" @@ -906,14 +908,7 @@ end function metapost.resetplugins(t) -- intialize plugins, before figure if top.plugmode then - outercolormodel = colors.currentmodel() -- currently overloads the one set at the tex end - - -- plugins can have been added - resetter = resetteractions.runner - analyzer = analyzeractions.runner - processor = processoractions.runner - -- let's apply one runner resetter(t) end end @@ -967,6 +962,8 @@ local function cm(object) return 1, 0, 0, 1, 0, 0 -- weird case end +metapost.cm = cm + -- color local function cl_reset(t) @@ -1591,7 +1588,6 @@ function mp.get_outline_text(index) -- maybe we need a more private namespace mp.print(outlinetexts[index] or "draw origin;") end - -- definitions appendaction(resetteractions, "system",ot_reset) @@ -1616,17 +1612,20 @@ appendaction(processoractions,"system",tr_process) -- last, as color can be rese appendaction(processoractions,"system",la_process) --- function metapost.installplugin(reset,analyze,process) --- if reset then --- appendaction(resetteractions,"system",reset) --- end --- if analyze then --- appendaction(analyzeractions,"system",analyze) --- end --- if process then --- appendaction(processoractions,"system",process) --- end --- end +function metapost.installplugin(reset,analyze,process) + if reset then + appendaction(resetteractions,"system",reset) + end + if analyze then + appendaction(analyzeractions,"system",analyze) + end + if process then + appendaction(processoractions,"system",process) + end + resetter = resetteractions .runner + analyzer = analyzeractions .runner + processor = processoractions.runner +end -- we're nice and set them already diff --git a/tex/context/base/mkiv/mult-low.lua b/tex/context/base/mkiv/mult-low.lua index 0acba3b87..be5e90889 100644 --- a/tex/context/base/mkiv/mult-low.lua +++ b/tex/context/base/mkiv/mult-low.lua @@ -197,8 +197,8 @@ return { -- "hglue", "vglue", "hfillneg", "vfillneg", "hfilllneg", "vfilllneg", -- - "ruledhss", "ruledhfil", "ruledhfill", "ruledhfilneg", "ruledhfillneg", "normalhfillneg", - "ruledvss", "ruledvfil", "ruledvfill", "ruledvfilneg", "ruledvfillneg", "normalvfillneg", + "ruledhss", "ruledhfil", "ruledhfill", "ruledhfilll", "ruledhfilneg", "ruledhfillneg", "normalhfillneg", "normalhfilllneg", + "ruledvss", "ruledvfil", "ruledvfill", "ruledvfilll", "ruledvfilneg", "ruledvfillneg", "normalvfillneg", "normalvfilllneg", "ruledhbox", "ruledvbox", "ruledvtop", "ruledvcenter", "ruledmbox", "ruledhpack", "ruledvpack", "ruledtpack", "ruledhskip", "ruledvskip", "ruledkern", "ruledmskip", "ruledmkern", diff --git a/tex/context/base/mkiv/mult-prm.lua b/tex/context/base/mkiv/mult-prm.lua index 1cd5f5810..53c30d7ed 100644 --- a/tex/context/base/mkiv/mult-prm.lua +++ b/tex/context/base/mkiv/mult-prm.lua @@ -298,7 +298,9 @@ return { "mathrulesfam", "mathrulesmode", "mathscriptsmode", + "mathscriptcharmode", "mathscriptboxmode", + "mathrulethicknessmode", "mathstyle", "mathsurroundmode", "mathsurroundskip", diff --git a/tex/context/base/mkiv/node-aux.lua b/tex/context/base/mkiv/node-aux.lua index 84567068b..5e85ead1c 100644 --- a/tex/context/base/mkiv/node-aux.lua +++ b/tex/context/base/mkiv/node-aux.lua @@ -154,9 +154,8 @@ function nodes.repackhlist(list,...) end local function set_attributes(head,attr,value) - for n in traverse_nodes(head) do + for n, id in traverse_nodes(head) do setattr(n,attr,value) - local id = getid(n) if id == hlist_node or id == vlist_node then set_attributes(getlist(n),attr,value) end @@ -164,11 +163,10 @@ local function set_attributes(head,attr,value) end local function set_unset_attributes(head,attr,value) - for n in traverse_nodes(head) do + for n, id in traverse_nodes(head) do if not getattr(n,attr) then setattr(n,attr,value) end - local id = getid(n) if id == hlist_code or id == vlist_code then set_unset_attributes(getlist(n),attr,value) end @@ -176,9 +174,8 @@ local function set_unset_attributes(head,attr,value) end local function unset_attributes(head,attr) - for n in traverse_nodes(head) do + for n, id in traverse_nodes(head) do setattr(n,attr,unsetvalue) - local id = getid(n) if id == hlist_code or id == vlist_code then unset_attributes(getlist(n),attr) end @@ -431,8 +428,7 @@ nodes.link = function(list,currentfont,currentattr,head,tail) end local function locate(start,wantedid,wantedsubtype) - for n in traverse_nodes(start) do - local id = getid(n) + for n, id in traverse_nodes(start) do if id == wantedid then if not wantedsubtype or getsubtype(n) == wantedsubtype then return n diff --git a/tex/context/base/mkiv/node-met.lua b/tex/context/base/mkiv/node-met.lua index 12a9256bc..4141c8b66 100644 --- a/tex/context/base/mkiv/node-met.lua +++ b/tex/context/base/mkiv/node-met.lua @@ -62,6 +62,26 @@ end -- statistics.tracefunction(node, "node", "getfield","setfield") -- statistics.tracefunction(node.direct,"node.direct","getfield","setfield") +if LUATEXFUNCTIONALITY < 6695 then + + local getnext = node.getnext + local getid = node.getid + + local function iterate(h,n) + if n then + local n = getnext(n) + return n, getid(n) + elseif h then + return h, getid(h), getnext(h) + end + end + + function node.traverse(h) + return iterate, h + end + +end + -- We start with some helpers and provide all relevant basic functions in the -- node namespace as well. @@ -163,7 +183,7 @@ local n_setlink = node.setlink or -- always -- not that fast but not used often anyway local h = nil for i=1,select("#",...) do - local n = (select(i,...)) + local n = select(i,...) if not n then -- go on elseif h then diff --git a/tex/context/base/mkiv/node-nut.lua b/tex/context/base/mkiv/node-nut.lua index 3e9a08b48..302ece4bf 100644 --- a/tex/context/base/mkiv/node-nut.lua +++ b/tex/context/base/mkiv/node-nut.lua @@ -143,16 +143,6 @@ nodes.tonut = tonut -- helpers -if not direct.getfam then -- LUATEXVERSION < 1.070 - - local getfield = direct.getfield - local setfield = direct.setfield - - direct.getfam = function(n) return getfield(n,"small_fam") end - direct.setfam = function(n,f) setfield(n,"small_fam",f) end - -end - if not direct.getdirection then local getdir = direct.getdir @@ -184,6 +174,26 @@ if not direct.getdirection then end +if LUATEXFUNCTIONALITY < 6695 then + + local getnext = direct.getnext + local getid = direct.getid + + local function iterate(h,n) + if n then + local n = getnext(n) + return n, getid(n) + elseif h then + return h, getid(h), getnext(h) + end + end + + function direct.traverse(h) + return iterate, h + end + +end + local nuts = nodes.nuts nuts.tostring = direct.tostring diff --git a/tex/context/base/mkiv/node-shp.lua b/tex/context/base/mkiv/node-shp.lua index 2e7a3529a..2c20d9567 100644 --- a/tex/context/base/mkiv/node-shp.lua +++ b/tex/context/base/mkiv/node-shp.lua @@ -192,8 +192,7 @@ local function count(head,data,subcategory) -- no components, pre, post, replace .. can maybe an option .. but -- we use this for optimization so it makes sense to look the the -- main node only - for n in traverse_nodes(tonut(head)) do - local id = getid(n) + for n, id in traverse_nodes(tonut(head)) do local dn = data[nodecodes[id]] -- we could use id and then later convert to nodecodes dn[subcategory] = dn[subcategory] + 1 if id == hlist_code or id == vlist_code then diff --git a/tex/context/base/mkiv/node-tra.lua b/tex/context/base/mkiv/node-tra.lua index f12599866..a2e5a7653 100644 --- a/tex/context/base/mkiv/node-tra.lua +++ b/tex/context/base/mkiv/node-tra.lua @@ -198,8 +198,7 @@ function nodes.idstostring(head,tail) local t = { } local last_id = nil local last_n = 0 - for n in traverse_nodes(head,tail) do -- hm, does not stop at tail - local id = getid(n) + for n, id in traverse_nodes(head,tail) do -- hm, does not stop at tail if id == whatsit_code then id = whatcodes[getsubtype(n)] else @@ -354,8 +353,7 @@ local what = { [0] = "unknown", "line", "box", "indent", "row", "cell" } local function showboxes(n,symbol,depth) depth = depth or 0 symbol = symbol or "." - for n in traverse_nodes(tonut(n)) do - local id = getid(n) + for n, id in traverse_nodes(tonut(n)) do if id == hlist_code or id == vlist_code then local s = getsubtype(n) report_nodes(rep(symbol,depth) .. what[s] or s) diff --git a/tex/context/base/mkiv/publ-ini.lua b/tex/context/base/mkiv/publ-ini.lua index 8497b190f..9dfeda168 100644 --- a/tex/context/base/mkiv/publ-ini.lua +++ b/tex/context/base/mkiv/publ-ini.lua @@ -2325,13 +2325,13 @@ do implement { name = "btxflushlistentry", - arguments = "2 strings", + arguments = { "string", "integer" }, actions = lists.flushentry, } implement { name = "btxflushlisttag", - arguments = "2 strings", + arguments = { "string", "integer" }, actions = lists.flushtag, } diff --git a/tex/context/base/mkiv/spac-ver.lua b/tex/context/base/mkiv/spac-ver.lua index 969a195e1..8f2136f95 100644 --- a/tex/context/base/mkiv/spac-ver.lua +++ b/tex/context/base/mkiv/spac-ver.lua @@ -290,8 +290,7 @@ local function validvbox(parentid,list) end end local done = nil - for n in traverse_nodes(list) do - local id = getid(n) + for n, id in traverse_nodes(list) do if id == vlist_code or id == hlist_code then if done then return nil @@ -326,8 +325,7 @@ local function already_done(parentid,list,a_snapmethod) -- todo: done when only return false end end - for n in traverse_nodes(list) do - local id = getid(n) + for n, id in traverse_nodes(list) do if id == hlist_code or id == vlist_code then -- local a = getattr(n,a_snapmethod) -- if not a then @@ -1917,8 +1915,7 @@ do local flush = false stackhack = true -- todo: only when grid snapping once enabled -- todo: fast check if head = tail - for n in traverse_nodes(newhead) do -- we could just look for glue nodes - local id = getid(n) + for n, id in traverse_nodes(newhead) do -- we could just look for glue nodes if id ~= glue_code then flush = true else diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf index 452af8333..d3b0db503 100644 Binary files a/tex/context/base/mkiv/status-files.pdf and b/tex/context/base/mkiv/status-files.pdf differ diff --git a/tex/context/base/mkiv/status-lua.pdf b/tex/context/base/mkiv/status-lua.pdf index c4928ecb0..87aefae39 100644 Binary files a/tex/context/base/mkiv/status-lua.pdf and b/tex/context/base/mkiv/status-lua.pdf differ diff --git a/tex/context/base/mkiv/strc-doc.mkiv b/tex/context/base/mkiv/strc-doc.mkiv index 805525487..3b4b656d3 100644 --- a/tex/context/base/mkiv/strc-doc.mkiv +++ b/tex/context/base/mkiv/strc-doc.mkiv @@ -29,4 +29,14 @@ \xdef\currentstructureattribute {\the\lastdestinationattribute}% \xdef\currentstructuresynchronize{\strc_lists_inject_enhance{#1}{\the\locationcount}}} +\unexpanded\def\setstructurecomponentsynchronization#1% todo: use ctxcontext + {\clf_setinternalreference + prefix {\currentstructurecomponentreferenceprefix}% + reference {\currentstructurecomponentreference} + internal \locationcount + view {\interactionparameter\c!focus}% + \relax + \xdef\currentstructurecomponentattribute {\the\lastdestinationattribute}% + \xdef\currentstructurecomponentsynchronize{\strc_lists_inject_enhance{#1}{\the\locationcount}}} + \protect \endinput diff --git a/tex/context/base/mkiv/strc-mar.lua b/tex/context/base/mkiv/strc-mar.lua index 24a7fd491..a2cbc2ab2 100644 --- a/tex/context/base/mkiv/strc-mar.lua +++ b/tex/context/base/mkiv/strc-mar.lua @@ -116,8 +116,7 @@ end -- identify range local function sweep(head,first,last) - for n in traverse(head) do - local id = getid(n) + for n, id in traverse(head) do if id == glyph_code then local a = getattr(n,a_marks) if not a then diff --git a/tex/context/base/mkiv/strc-num.mkiv b/tex/context/base/mkiv/strc-num.mkiv index be35e7671..cca66a6f5 100644 --- a/tex/context/base/mkiv/strc-num.mkiv +++ b/tex/context/base/mkiv/strc-num.mkiv @@ -669,11 +669,9 @@ %} \relax \xdef\m_strc_counters_last_registered_index{\the\scratchcounter}% - \clf_setinternalreference - internal \locationcount - \relax - \xdef\m_strc_counters_last_registered_attribute {\the\lastdestinationattribute}% - \xdef\m_strc_counters_last_registered_synchronize{\strc_lists_inject_enhance{\m_strc_counters_last_registered_index}{\the\locationcount}}} + \setstructurecomponentsynchronization\m_strc_counters_last_registered_index + \glet\m_strc_counters_last_registered_attribute \currentstructurecomponentattribute + \glet\m_strc_counters_last_registered_synchronize\currentstructurecomponentsynchronize} \let\m_strc_counters_last_registered_index \relax \let\m_strc_counters_last_registered_attribute \relax diff --git a/tex/context/base/mkiv/strc-ref.lua b/tex/context/base/mkiv/strc-ref.lua index f20d93161..02971c3f9 100644 --- a/tex/context/base/mkiv/strc-ref.lua +++ b/tex/context/base/mkiv/strc-ref.lua @@ -137,6 +137,7 @@ storage.register("structures/references/defined", references.defined, "structure local initializers = { } local finalizers = { } +local somefound = false -- so we don't report missing when we have a fresh start function references.registerinitializer(func) -- we could use a token register instead initializers[#initializers+1] = func @@ -162,6 +163,7 @@ local function initializer() -- can we use a tobesaved as metatable for collecte end end end + somefound = next(collected) end local function finalizer() @@ -370,6 +372,8 @@ implement { arguments = "2 strings", } +local reported = setmetatableindex("table") + function references.set(data) local references = data.references local reference = references.reference @@ -388,10 +392,16 @@ function references.set(data) if ref == "" then -- skip elseif check_duplicates and pd[ref] then - if prefix and prefix ~= "" then - report_references("redundant reference %a in namespace %a",ref,prefix) - else - report_references("redundant reference %a",ref) + if not prefix then + prefix = "" + end + if not reported[prefix][ref] then + if prefix ~= "" then + report_references("redundant reference %a in namespace %a",ref,prefix) + else + report_references("redundant reference %a",ref) + end + reported[prefix][ref] = true end else n = n + 1 @@ -1004,9 +1014,9 @@ local function loadexternalreferences(name,utilitydata) local pages = struc.pages.collected -- pagenumber data -- a bit weird one, as we don't have the externals in the collected for prefix, set in next, external do -if prefix == "" then - prefix = name -- this can clash! -end + if prefix == "" then + prefix = name -- this can clash! + end for reference, data in next, set do if trace_importing then report_importing("registering %a reference, kind %a, name %a, prefix %a, reference %a", @@ -1034,9 +1044,9 @@ end if kind and realpage then references.pagedata = pages[realpage] local prefix = references.prefix or "" -if prefix == "" then - prefix = name -- this can clash! -end + if prefix == "" then + prefix = name -- this can clash! + end local target = external[prefix] if not target then target = { } @@ -1847,7 +1857,9 @@ function references.valid(prefix,reference,specification) local str = f_valid(prefix,reference) local u = unknowns[str] if not u then - interfaces.showmessage("references",1,str) -- 1 = unknown, 4 = illegal + if somefound then + interfaces.showmessage("references",1,str) -- 1 = unknown, 4 = illegal + end unknowns[str] = 1 nofunknowns = nofunknowns + 1 else @@ -1987,7 +1999,7 @@ local function setinternalreference(specification) -- ugly .. later we decide to ignore it when we have a real one -- but for testing we might want to see them all if internal then - if innermethod ~= v_name then -- so page and auto + if innermethod ~= v_name then -- innermethod == v_auto -- we don't want too many #1 #2 #3 etc tn = tn + 1 t[tn] = internal -- when number it's internal diff --git a/tex/context/base/mkiv/strc-ref.mkvi b/tex/context/base/mkiv/strc-ref.mkvi index d0752407c..6d0e369b1 100644 --- a/tex/context/base/mkiv/strc-ref.mkvi +++ b/tex/context/base/mkiv/strc-ref.mkvi @@ -45,19 +45,18 @@ % \definespecial\dosetexecuteJScode % ... -%D This module deals with referencing. In \CONTEXT\ referencing is one of -%D the core features, although at a first glance probably nobody will -%D notice. This is good, because referencing should be as hidden as possible. +%D This module deals with referencing. In \CONTEXT\ referencing is one of the core +%D features, although at a first glance probably nobody will notice. This is good, +%D because referencing should be as hidden as possible. %D -%D Before we start implementing functionality we provide a way to set -%D up this mechanism. +%D Before we start implementing functionality we provide a way to set up this +%D mechanism. %D %D \showsetup{setupreferencing} %D -%D In interactive documents verbose references don't always -%D make sense (what is a page number in an unnumbered -%D document). By setting the \type{interaction} variable, one -%D can influences the way interactive references are set. +%D In interactive documents verbose references don't always make sense (what is a +%D page number in an unnumbered document). By setting the \type{interaction} +%D variable, one can influences the way interactive references are set. \let\referenceprefix\empty @@ -122,9 +121,8 @@ \dosetdirectpagereference\m_strc_references_asked \fi} -%D Actually there is not much difference between a text and a -%D full reference, but it's the concept that counts. The low -%D level implementation is: +%D Actually there is not much difference between a text and a full reference, but +%D it's the concept that counts. The low level implementation is: \newcount\lastreferenceattribute \newcount\lastdestinationattribute @@ -134,8 +132,8 @@ \let\dofinishreference\strc_references_finish % used at lua end -% This is somewhat tricky: we want to keep the reference with the following word but -% that word should also hyphenate. We need to find a better way. +%D This is somewhat tricky: we want to keep the reference with the following word but +%D that word should also hyphenate. We need to find a better way. % 0 = nothing % 1 = bind to following word @@ -502,34 +500,31 @@ %D \macros %D {everyreference} %D -%D For rather tricky purposes, one can assign sanitizing -%D macros to \type{\everyreference} (no longer that relevant). +%D For rather tricky purposes, one can assign sanitizing macros to \type +%D {\everyreference} (no longer that relevant). \newevery \everyreference \relax -%D This is really needed, since for instance Polish has a -%D different alphabet and needs accented entries in registers. +%D This is really needed, since for instance Polish has a different alphabet and +%D needs accented entries in registers. \appendtoks \cleanupfeatures \to \everyreference -%D We did not yet discuss prefixing. Especially in interactive -%D documents, it's not always easy to keep track of duplicate -%D references. The prefix mechanism, which we will describe -%D later on, solves this problem. By (automatically) adding a -%D prefix one keeps references local, but the global ones in -%D view. To enable this feature, we explictly split the prefix -%D from the reference. +%D We did not yet discuss prefixing. Especially in interactive documents, it's not +%D always easy to keep track of duplicate references. The prefix mechanism, which we +%D will describe later on, solves this problem. By (automatically) adding a prefix +%D one keeps references local, but the global ones in view. To enable this feature, +%D we explictly split the prefix from the reference. \let\referenceprefix\empty -%D For a long time the only way to access an external file was -%D to use the file prefix (\type {somefile::}. However, when -%D you split up a document, redefining the references may be -%D such a pain, that another approach is feasible. By setting -%D the \type {autofile} variable to \type {yes} or \type -%D {page}, you can access the reference directly. +%D For a long time the only way to access an external file was to use the file +%D prefix (\type {somefile::}. However, when you split up a document, redefining the +%D references may be such a pain, that another approach is feasible. By setting the +%D \type {autofile} variable to \type {yes} or \type {page}, you can access the +%D reference directly. %D %D \starttabulate[||||] %D \NC filename::tag \NC page(filename::pnum) \NC tag \NC\NR @@ -540,9 +535,9 @@ \unexpanded\def\usereferences[#filename]{} % obsolete -%D As mentioned we will also use the cross reference mechanism -%D for navigational purposes. The main reason for this is that -%D we want to treat both categories alike: +%D As mentioned we will also use the cross reference mechanism for navigational +%D purposes. The main reason for this is that we want to treat both categories +%D alike: %D %D \starttyping %D \goto{go back}[PreviousJump] @@ -553,15 +548,13 @@ %D \type{colofon page} reference is, apart from hyperlinking, a %D rather normal reference. %D -%D We already saw that cross refences are written to and read -%D from a file. The pure navigational ones don't need to be -%D written to file, but both for fast processing and -%D transparant integration, they are saved internally as a sort -%D of reference. We can easily distinguish such system -%D references from real cross reference ones by their tag. +%D We already saw that cross refences are written to and read from a file. The pure +%D navigational ones don't need to be written to file, but both for fast processing +%D and transparant integration, they are saved internally as a sort of reference. We +%D can easily distinguish such system references from real cross reference ones by +%D their tag. %D -%D We also use the odd/even characteristic to determine the -%D page state. +%D We also use the odd/even characteristic to determine the page state. \let\currentrealreference \empty \let\currentpagereference \empty @@ -576,11 +569,10 @@ % % 0 = no page ref, 1=same page, 2=before, 3=after -%D Cross references appear as numbers (figure~1.1, chapter~2) -%D or pagenumbers (page~2, page 3--2), and are called with -%D \type{\in} and \type{\at}. In interactive documents we also -%D have \type{\goto}, \type{\button} and alike. These are more -%D versatile and look like: +%D Cross references appear as numbers (figure~1.1, chapter~2) or pagenumbers +%D (page~2, page 3--2), and are called with \type {\in} and \type {\at}. In +%D interactive documents we also have \type {\goto}, \type {\button} and alike. +%D These are more versatile and look like: %D %D \starttyping %D \goto[reference] @@ -592,23 +584,19 @@ %D \goto[action{argument}] %D \stoptyping %D -%D The first one is a normal reference, the second and third -%D are references to a file or \URL. The brace delimited -%D references for instance refer to a \JAVASCRIPT. The last -%D example shows that we can pass arguments to the actions. +%D The first one is a normal reference, the second and third are references to a +%D file or \URL. The brace delimited references for instance refer to a \JAVASCRIPT. +%D The last example shows that we can pass arguments to the actions. %D -%D Now we've come to the testing step. As we can see below, -%D this macro does bit more than testing: it also resolves -%D the reference. This means that whenever we test for the -%D existance of a reference at an outer level, we have all the -%D relevant properties of that reference avaliable inside the -%D true branche~(\type{#2}). +%D Now we've come to the testing step. As we can see below, this macro does bit more +%D than testing: it also resolves the reference. This means that whenever we test +%D for the existance of a reference at an outer level, we have all the relevant +%D properties of that reference avaliable inside the true branche~(\type {#2}). %D -%D The prefix has to do with localizing references. When a -%D prefix is set, looking for a reference comes to looking for -%D the prefixed one, and when not found, looking for the non -%D prefixed one. Consider for instance the prefix set to -%D \type{sidetrack}. +%D The prefix has to do with localizing references. When a prefix is set, looking +%D for a reference comes to looking for the prefixed one, and when not found, +%D looking for the non prefixed one. Consider for instance the prefix set to \type +%D {sidetrack}. %D %D \starttyping %D \pagereference[important] @@ -625,17 +613,15 @@ %D ...{sidetrack}{important}... %D \stoptyping %D -%D Now when we call for \type{unimportant}, we will indeed get -%D the pagenumber associated to this reference. But when we -%D call for \type{important}, while the prefix is still set, we -%D will get the pagenumber bound to the prefixed one. +%D Now when we call for \type{unimportant}, we will indeed get the pagenumber +%D associated to this reference. But when we call for \type{important}, while the +%D prefix is still set, we will get the pagenumber bound to the prefixed one. %D %D {\em Some day, when processing time and memory are no longer %D performance factors, we will introduce multi||level %D prefixes.} %D -%D Before we start analyzing, I introduce a general -%D definition macro. Consider: +%D Before we start analyzing, I introduce a general definition macro. Consider: %D %D \starttyping %D \goto{do}[JS(My_Script{"test",123}),titlepage] @@ -652,8 +638,7 @@ %D %D \showsetup{definereference} %D -%D We can trace references by setting the next switch to -%D true. +%D We can trace references by setting the next switch to true. \unexpanded\def\definereference {\dodoubleempty\strc_references_define_reference} @@ -673,23 +658,22 @@ %D \goto{somewhere}[JS(somescript),nextpage,JS(anotherscript)] %D \stoptyping %D -%D Actually supporting chains is up to the special driver. Here -%D we only provide the hooks. +%D Actually supporting chains is up to the special driver. Here we only provide the +%D hooks. %D \macros %D {highlighthyperlinks} %D -%D The next switch can be used to make user hyperlinks are -%D not highlighted when clicked on. +%D The next switch can be used to make user hyperlinks are not highlighted when +%D clicked on. \newconditional\highlighthyperlinks \settrue\highlighthyperlinks %D \macros %D {gotonewwindow} %D -%D To make the {\em goto previous jump} feature more -%D convenient when using more than one file, it makes sense -%D to force the viewer to open a new window for each file +%D To make the {\em goto previous jump} feature more convenient when using more than +%D one file, it makes sense to force the viewer to open a new window for each file %D opened. \newconditional\gotonewwindow \setfalse\gotonewwindow @@ -708,13 +692,11 @@ \let\doifreferencefoundelse \doifelsereferencefound -%D The tester only splits the reference in components but does -%D not look into them. The following macro does a preroll and -%D determines for instance the current real reference pagenumber. -%D The \type {\currentrealreference} macro does the same so unless -%D one wants to use the pagestate the next macro seldom needs to -%D be called. - +%D The tester only splits the reference in components but does not look into them. +%D The following macro does a preroll and determines for instance the current real +%D reference pagenumber. The \type {\currentrealreference} macro does the same so +%D unless one wants to use the pagestate the next macro seldom needs to be called. +%D %D The inner case is simple. Only two cases have to be taken %D care of: %D @@ -723,8 +705,8 @@ %D \goto{some text}[prefix:reference] %D \stoptyping %D -%D References to other files however are treated strict or -%D tolerant, depending on their loading and availability: +%D References to other files however are treated strict or tolerant, depending on +%D their loading and availability: %D %D \starttyping %D \useexternaldocument[somefile][filename][a nice description] @@ -734,72 +716,61 @@ %D \goto{unchecked reference}[anotherfile::reference] %D \stoptyping %D -%D An unknown reference is reported on the screen, in the log -%D file and, when enabled, in the left margin of the text. +%D An unknown reference is reported on the screen, in the log file and, when +%D enabled, in the left margin of the text. \let\unknownreference\gobbleoneargument -%D When a reference is not found, we typeset a placeholder -%D (two glyphs are often enough to represent the reference -%D text). +%D When a reference is not found, we typeset a placeholder (two glyphs are often +%D enough to represent the reference text). \def\dummyreference{{\tttf ??}} \def\emptyreference{{\tttf !!}} -%D To prevent repetitive messages concerning a reference -%D being defined, we set such an unknown reference to an empty -%D one after the first encounter. - -%D Apart from cross references supplied by the user, \CONTEXT\ -%D generates cross references itself. Most of them are not -%D saved as a reference, but stored with their source, for -%D instance a list or an index entry. Such automatically -%D generated, for the user invisible, references are called -%D {\em internal references}. The user supplied ones are -%D labeled as {\em external references}. -%D -%D A second important characteristic is that when we want to -%D support different backends (viewers), we need to support -%D named destinations as well as page numbers. I invite readers -%D to take a glance at the special driver modules to understand -%D the fine points of this. As a result we will deal with {\em -%D locations} as well as {\em real page numbers}. We explictly -%D call this pagenumber a real one, because it is independant -%D of the page numbering scheme used in the document. -%D -%D One of the reasons for \CONTEXT\ being the first \TEX\ base -%D macropackage to support sophisticated interactive \PDF\ -%D files, lays in the mere fact that real page numbers are -%D available in most two pass data, like references, list data -%D and index entries. -%D -%D We will speak of \type{thisis...} when we are marking a -%D location, and \type{goto...} when we point to such a -%D location. The latter one can be seen as a hyperlink to the -%D former one. In the next macros one we use constructs like: +%D To prevent repetitive messages concerning a reference being defined, we set such +%D an unknown reference to an empty one after the first encounter. +%D +%D Apart from cross references supplied by the user, \CONTEXT\ generates cross +%D references itself. Most of them are not saved as a reference, but stored with +%D their source, for instance a list or an index entry. Such automatically +%D generated, for the user invisible, references are called {\em internal +%D references}. The user supplied ones are labeled as {\em external references}. +%D +%D A second important characteristic is that when we want to support different +%D backends (viewers), we need to support named destinations as well as page +%D numbers. I invite readers to take a glance at the special driver modules to +%D understand the fine points of this. As a result we will deal with {\em locations} +%D as well as {\em real page numbers}. We explictly call this pagenumber a real one, +%D because it is independant of the page numbering scheme used in the document. +%D +%D One of the reasons for \CONTEXT\ being the first \TEX\ base macropackage to +%D support sophisticated interactive \PDF\ files, lays in the mere fact that real +%D page numbers are available in most two pass data, like references, list data and +%D index entries. +%D +%D We will speak of \type {thisis...} when we are marking a location, and +%D \type {goto...} when we point to such a location. The latter one can be seen as a +%D hyperlink to the former one. In the next macros one we use constructs like: %D %D \starttyping %D \dostart... %D \dostop... %D \stoptyping %D -%D Such macros are used to invoke the relevant specials from -%D the special driver modules (see \type{spec-ini}). The flag -%D \type{\iflocation} signals if we're in interactive mode. +%D The flag \type {\iflocation} signals if we're in interactive mode. \ifdefined\buttonheight \else \newdimen\buttonheight \fi \ifdefined\buttonwidth \else \newdimen\buttonwidth \fi -%D Internal references can best be set using the next few -%D macros. Setting such references to unique values is -%D completely up to the macros that call them. +%D Internal references can best be set using the next few macros. Setting such +%D references to unique values is completely up to the macros that call them. %D %D \starttyping %D \thisissomeinternal{tag}{identifier} %D \gotosomeinternal {tag}{identifier}{pagenumber}{text} %D \stoptyping - -%D We could do this in lua ... +%D +%D We could do this in \LUA\ \unknown \newif \iflocation \newcount\locationcount @@ -845,12 +816,10 @@ \def\gotonextinternal#text#target% {\directgoto{#text}[internal(#target)]} -%D In this module we define three system references: one for -%D handling navigational, viewer specific, commands, another -%D for jumping to special pages, like the first or last one, -%D and a third reference for linking tree like lists, like -%D tables of contents. The latter two adapt themselves to the -%D current state. +%D In this module we define three system references: one for handling navigational, +%D viewer specific, commands, another for jumping to special pages, like the first +%D or last one, and a third reference for linking tree like lists, like tables of +%D contents. The latter two adapt themselves to the current state. %D %D An example of an action is: %D @@ -863,11 +832,10 @@ %D \starttyping %D \goto{some text}[\v!action(PreviousJump] %D \stoptyping - -%D One can also activate an automatic prefix mechanism. By -%D setting the \type{\prefix} variable to \type{+}, the prefix -%D is incremented, when set to \type{-} or empty, the prefix is -%D reset. Other values become the prefix. +%D +%D One can also activate an automatic prefix mechanism. By setting the +%D \type {\prefix} variable to \type {+}, the prefix is incremented, when set to +%D \type {-} or empty, the prefix is reset. Other values become the prefix. \newcount\prefixcounter @@ -892,13 +860,6 @@ \unexpanded\def\setupglobalreferenceprefix[#prefix]% {\xdef\referenceprefix{#prefix}} -% \unexpanded\def\pushreferenceprefix#prefix% -% {\pushmacro\referenceprefix -% \xdef\referenceprefix{#prefix}} % global - -% \unexpanded\def\popreferenceprefix -% {\popmacro\referenceprefix} - \unexpanded\def\globalpushreferenceprefix#prefix% {\xdef\referenceprefix{\clf_pushreferenceprefix{#prefix}}} @@ -935,16 +896,14 @@ \setupreferenceprefix[\referencingparameter\c!prefix] \to \everysetupreferencing -%D We can typeset a reference using \type{\in}, \type{\at} and -%D \type{\about} and goto specific locations using -%D \type{\goto}. The last one does not make that much sense in -%D a paper document. To complicate things, \PLAIN\ \TEX\ also -%D implements an \type {\in} but fortunately that one only -%D makes sense in math mode. +%D We can typeset a reference using \type {\in}, \type {\at} and \type {\about} and +%D goto specific locations using \type {\goto}. The last one does not make that much +%D sense in a paper document. To complicate things, \PLAIN\ \TEX\ also implements an +%D \type {\in} but fortunately that one only makes sense in math mode. %D -%D Typesetting the reference is a bit more complicated than one -%D would at first sight expect. This is due to the fact that we -%D distinguish three (five) alternative calls: +%D Typesetting the reference is a bit more complicated than one would at first sight +%D expect. This is due to the fact that we distinguish three (five) alternative +%D calls: %D %D \placefigure %D [here][three calls] @@ -971,25 +930,11 @@ %D \getbuffer %D \stoplines %D -%D The dual \type{{}} results in a split reference. In a -%D document meant for paper, one is tempted to use the last -%D (most straightforward) alternative. When a document is also -%D meant voor electronic distribution, the former alternatives -%D have preference, because everything between the \type{\in} -%D and~\type{[} becomes active (and when asked for, typeset -%D in a different color and typeface). - -% \unexpanded\def\in {\mathortext\donormalmathin \strc_references_in} -% \unexpanded\def\at {\mathortext\donormalmathat \strc_references_at} -% \unexpanded\def\about{\mathortext\donormalmathabout\strc_references_about} -% \unexpanded\def\from {\mathortext\donormalmathfrom \strc_references_from} -% \unexpanded\def\over {\mathortext\donormalmathover \strc_references_about} - -% \definecommand in {\strc_references_in} -% \definecommand at {\strc_references_at} -% \definecommand about {\strc_references_about} -% \definecommand from {\strc_references_from} -% \definecommand over {\strc_references_about} % needed here, else math problems +%D The dual \type {{}} results in a split reference. In a document meant for paper, +%D one is tempted to use the last (most straightforward) alternative. When a +%D document is also meant voor electronic distribution, the former alternatives have +%D preference, because everything between the \type {\in} and~\type {[} becomes +%D active (and when asked for, typeset in a different color and typeface). \appendtoks \ifdefined\in \let\normalmathin \in \unexpanded\def\in {\mathortext\normalmathin \strc_references_in } \else \let\in \strc_references_in \fi @@ -1009,8 +954,7 @@ \def\currentreferencedefault {\clf_filterreference{default}} \def\currentreferencerealpage{\clf_filterreference{realpage}} -%D The most straightforward way of retrieving references is -%D using \type{\ref}. +%D The most straightforward way of retrieving references is using \type {\ref}. \unexpanded\def\getreference % checking, unexpanded {\dodoubleargument\strc_references_get_reference} @@ -1040,12 +984,11 @@ \referencingparameter\c!right \endgroup} -%D The previously discussed setup macro lets us specify the -%D representation of references. A symbol reference does not -%D show the specific data, like the number of a figure, but -%D shows one of: \hbox {$^\goforwardcharacter$ -%D $^\gobackwardcharacter$ $^\gonowherecharacter$}, depending -%D on the direction to go. +%D The previously discussed setup macro lets us specify the representation of +%D references. A symbol reference does not show the specific data, like the number +%D of a figure, but shows one of: \hbox {$^\goforwardcharacter$ +%D $^\gobackwardcharacter$ $^\gonowherecharacter$}, depending on the direction to +%D go. %D %D \starttyping %D ... \somewhere{backward text}{forward text}[someref] ... @@ -1242,15 +1185,6 @@ \setvalue{\??referencinginteraction\v!symbol}% {\referencesymbol} -% \def\referencesequence -% {\csname\??referencinginteraction -% \ifcsname\??referencinginteraction\referencingparameter\c!interaction\endcsname -% \referencingparameter\c!interaction -% \else -% \v!all -% \fi -% \endcsname} - \def\referencesequence {\ifcsname\??referencinginteraction\referencingparameter\c!interaction\endcsname \expandafter\lastnamedcs @@ -1311,9 +1245,8 @@ %D \macros %D {definereferenceformat} %D -%D The next few macros were made for for David Arnold and Taco -%D Hoekwater. They can be used for predefining reference -%D texts, and thereby stimulate efficiency. +%D The next few macros were made for for David Arnold and Taco Hoekwater. They can +%D be used for predefining reference texts, and thereby stimulate efficiency. %D %D \starttyping %D \definereferenceformat[informula] [left=(,right=),text=formula] @@ -1328,11 +1261,11 @@ %D the \informulas [b] \andformula [for:c] %D \stoptyping %D -%D Instead of a text, one can specify a label, which should -%D be defined with \type {\setuplabeltext}. +%D Instead of a text, one can specify a label, which should be defined with \type +%D {\setuplabeltext}. %D -%D Watch out: the second argument is somewhat special and mostly -%D meant for a suffix to a number: +%D Watch out: the second argument is somewhat special and mostly meant for a suffix +%D to a number: %D %D \startbuffer %D \definereferenceformat [intesta] [left=(,right=),text=Whatever~] @@ -1437,21 +1370,18 @@ % % \definereferenceformat[hellup][text=Hellup ,setups=referenceformat:numberplustext] -%D In interactive documents going to a specific location is not -%D bound to cross references. The \type{\goto} commands can be -%D used to let users access another part of the document. In -%D this respect, interactive tables of contents and registers -%D can be considered goto's. Because in fact a \type{\goto} is -%D just a reference without reference specific data, the -%D previous macros are implemented using the goto -%D functionality. +%D In interactive documents going to a specific location is not bound to cross +%D references. The \type {\goto} commands can be used to let users access another +%D part of the document. In this respect, interactive tables of contents and +%D registers can be considered goto's. Because in fact a \type {\goto} is just a +%D reference without reference specific data, the previous macros are implemented +%D using the goto functionality. %D %D \showsetup{goto} %D -%D One important characteristic is that the first argument of -%D \type{\goto} (and therefore \type{\at} and \type{\in} is -%D split at spaces. This means that, although hyphenation is -%D prevented, long references can cross line endings. +%D One important characteristic is that the first argument of \type {\goto} (and +%D therefore \type {\at} and \type {\in} is split at spaces. This means that, +%D although hyphenation is prevented, long references can cross line endings. % \starttext % \setupinteraction[state=start] @@ -1744,17 +1674,15 @@ {\box\scratchbox}% \endgroup} -%D An reference to another document can be specified as a file -%D or as an \URL. Both are handled by the same mechanism and -%D can be issued by saying something like: +%D An reference to another document can be specified as a file or as an \URL. Both +%D are handled by the same mechanism and can be issued by saying something like: %D %D \starttyping %D \goto[dictionary::the letter a] %D \stoptyping %D -%D One can imagine that many references to such a dictionary -%D are made, so in most cases such a document reference in an -%D indirect one. +%D One can imagine that many references to such a dictionary are made, so in most +%D cases such a document reference in an indirect one. %D %D \showsetup{useexternaldocument} %D @@ -1766,8 +1694,8 @@ %D [The Famous English Dictionary] %D \stoptyping %D -%D The next macro implements these relations, and also take -%D care of loading the document specific references. +%D The next macro implements these relations, and also take care of loading the +%D document specific references. %D %D The \URL\ alternative takes four arguments: %D @@ -1789,9 +1717,8 @@ %D \useURL [id] [url] %D \stoptyping %D -%D This time we don't load the references when no file is -%D specified. This is logical when one keeps in mind that a -%D valid \URL\ can also be a mail address. +%D This time we don't load the references when no file is specified. This is logical +%D when one keeps in mind that a valid \URL\ can also be a mail address. \unexpanded\def\useurl {\doquadrupleempty\strc_references_use_url } % so that they can be used in expanded arguments \unexpanded\def\usefile{\dotripleargument\strc_references_use_file} % so that they can be used in expanded arguments @@ -1814,8 +1741,7 @@ %D \macros %D {url,setupurl} %D -%D We also have: \type{\url} for directly calling the -%D description. So we can say: +%D We also have: \type {\url} for directly calling the description. So we can say: %D %D \starttyping %D \useURL [one] [http://www.test.nl] @@ -1843,8 +1769,8 @@ \hyphenatedurl{\clf_geturl{#label}}% \endgroup} -%D This macro is hooked into a support macro, and thereby -%D \URL's break ok, according to the setting of a switch, +%D This macro is hooked into a support macro, and thereby \URL's break ok, according +%D to the setting of a switch, %D %D \startbuffer %D \useURL @@ -1858,9 +1784,8 @@ %D %D \getbuffer -%D When defining the external source of information, one can -%D also specify a suitable name (the last argument). This name -%D can be called upon with: +%D When defining the external source of information, one can also specify a suitable +%D name (the last argument). This name can be called upon with: %D %D \showsetup{from} %D @@ -1895,9 +1820,8 @@ %D \goto{some text}[identifier::location] %D \stoptyping -%D A special case of references are those to programs. These, -%D very system dependant references are implemented by abusing -%D some of the previous macros. +%D A special case of references are those to programs. These, very system dependant +%D references are implemented by abusing some of the previous macros. %D %D \showsetup{setupprograms} %D \showsetup{defineprogram} @@ -1925,8 +1849,7 @@ \clf_getprogram{#name}% \endgroup} -%D As we can see, we directly use the special reference -%D mechanism, which means that +%D As we can see, we directly use the special reference mechanism, which means that %D %D \starttyping %D \goto{some text}[program(name{args})] @@ -1934,11 +1857,10 @@ %D %D is valid. -%D The next macro provides access to the actual pagenumbers. -%D When documenting and sanitizing the original reference -%D macros, I decided to keep the present meaning as well as to -%D make this meaning available as a special reference method. -%D So now one can use: +%D The next macro provides access to the actual pagenumbers. When documenting and +%D sanitizing the original reference macros, I decided to keep the present meaning +%D as well as to make this meaning available as a special reference method. So now +%D one can use: %D %D \starttyping %D \gotopage{some text}[location] @@ -1967,8 +1889,7 @@ \def\gotopage#text[#target]% {\goto{#text}[\v!page(#target)]} -%D The previous definitions are somewhat obsolete so we don't -%D use it here. +%D The previous definitions are somewhat obsolete so we don't use it here. %D We can cross link documents by using: %D @@ -1980,16 +1901,14 @@ %D \coupledocument[print][somefile][chapter,section] %D \stoptyping %D -%D After which when applicable, we have available the -%D references: +%D After which when applicable, we have available the references: %D %D \starttyping %D \goto{print version}[print::chapter] %D \stoptyping %D -%D and alike. The title placement definition macros have a -%D key \type{file}, which is interpreted as the file to jump -%D to, that is, when one clicks on the title. +%D and alike. The title placement definition macros have a key \type {file}, which +%D is interpreted as the file to jump to, that is, when one clicks on the title. \def\coupledocument {\doquadrupleempty\strc_references_couple_document} @@ -2002,8 +1921,8 @@ %D \macros %D {dotextprefix} %D -%D In previous macros we used \type {\dotextprefix} to -%D generate a space between a label and a number. +%D In previous macros we used \type {\dotextprefix} to generate a space between +%D a label and a number. %D %D \starttyping %D \dotextprefix{text} @@ -2026,9 +1945,8 @@ \fi \endgroup} -%D In the next settings we see some variables that were not -%D used here and that concern the way the pagenumbers refered -%D to are typeset. +%D In the next settings we see some variables that were not used here and that +%D concern the way the pagenumbers refered to are typeset. \setupreferencing [\c!state=\v!start, diff --git a/tex/context/base/mkiv/supp-box.lua b/tex/context/base/mkiv/supp-box.lua index 40047167c..3ea16dcf8 100644 --- a/tex/context/base/mkiv/supp-box.lua +++ b/tex/context/base/mkiv/supp-box.lua @@ -55,6 +55,7 @@ local setdisc = nuts.setdisc local setwidth = nuts.setwidth local setheight = nuts.setheight local setdepth = nuts.setdepth +local setshift = nuts.setshift local flush_node = nuts.flush_node local flush_list = nuts.flush_list @@ -601,4 +602,10 @@ do end } + interfaces.implement { + name = "shiftbox", + arguments = { "integer", "dimension" }, + actions = function(n,d) setshift(getbox(n),d) end, + } + end diff --git a/tex/context/base/mkiv/supp-box.mkiv b/tex/context/base/mkiv/supp-box.mkiv index fb9cbdf5d..5fc34ba74 100644 --- a/tex/context/base/mkiv/supp-box.mkiv +++ b/tex/context/base/mkiv/supp-box.mkiv @@ -2974,6 +2974,11 @@ % \unexpanded\def\tightvbox{\dowithnextbox{\dp\nextbox\zeropoint\box\nextbox}\vbox} % \unexpanded\def\tightvtop{\dowithnextbox{\ht\nextbox\zeropoint\box\nextbox}\vtop} +%D This one keeps dimensions and sets the shift field (and so it's more for testing +%D than for real usage): + +\unexpanded\def\shiftbox{\clf_shiftbox} + \protect \endinput % a bit of test code: diff --git a/tex/context/base/mkiv/syst-aux.mkiv b/tex/context/base/mkiv/syst-aux.mkiv index 77f947753..ee5761af0 100644 --- a/tex/context/base/mkiv/syst-aux.mkiv +++ b/tex/context/base/mkiv/syst-aux.mkiv @@ -491,8 +491,6 @@ %D \type {\def} comes into action. This way the space after \type {\:} becomes a %D delimiter of the longer named \type {\reinspectnextcharacter}. -% try: \expandafter\def\firstofoneargument{\syst_helpers_reinspect_next_character} {...} - \let\next\: \def\:{\let\blankspace= } \: @@ -514,6 +512,31 @@ \let\:\next +%D This is much nicer and works too: + +% \def\firstofoneargument#1{#1} +% +% \expandafter\let\firstofoneargument{\blankspace= } +% +% \expandafter\def\firstofoneargument{\syst_helpers_reinspect_next_character +% } {\let\if_next_blank_space_token\iftrue +% \futurelet\nexttoken\syst_helpers_inspect_next_character} +% +% \expandafter\def\firstofoneargument{\syst_helpers_reinspect_next_optional_character +% } {\let\if_next_blank_space_token\iftrue +% \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} +% +% \expandafter\def\firstofoneargument{\syst_helpers_reinspect_next_bgroup_character +% } {\let\if_next_blank_space_token\iftrue +% \futurelet\nexttoken\syst_helpers_inspect_next_bgroup_character} +% +% \expandafter\def\firstofoneargument{\syst_helpers_reinspect_next_parenthesis_character +% } {\let\if_next_blank_space_token\iftrue +% \futurelet\nexttoken\syst_helpers_inspect_next_parenthesis_character} +% +% \expandafter\def\firstofoneargument{\syst_helpers_ignore_spacing_blankspace +% } {\futurelet\nexttoken\syst_helpers_ignore_spacing} + %D \macros %D {setvalue,setgvalue,setevalue,setxvalue, %D letvalue,letgvalue,getvalue,resetvalue, @@ -3183,17 +3206,25 @@ %D Apart from the prefixes, a few more \type{\expandafters} %D are needed: -\unexpanded\def\newif#1% - {\privatescratchcounter\escapechar - \escapechar\minusone - \expandafter\expandafter\expandafter - \redoglobal\expandafter\expandafter\expandafter - \edef\@if#1{true}{\let\noexpand#1\noexpand\iftrue}% - \expandafter\expandafter\expandafter - \redoglobal\expandafter\expandafter\expandafter - \edef\@if#1{false}{\let\noexpand#1\noexpand\iffalse}% - \dodoglobal\@if#1{false}% - \escapechar\privatescratchcounter} +% \unexpanded\def\newif#1% uses the original plain \@if +% {\privatescratchcounter\escapechar +% \escapechar\minusone +% \expandafter\expandafter\expandafter +% \redoglobal\expandafter\expandafter\expandafter +% \edef\@if#1{true}{\let\noexpand#1\noexpand\iftrue}% +% \expandafter\expandafter\expandafter +% \redoglobal\expandafter\expandafter\expandafter +% \edef\@if#1{false}{\let\noexpand#1\noexpand\iffalse}% +% \dodoglobal\@if#1{false}% +% \escapechar\privatescratchcounter} + +\normalprotected\def\newif#1% see syst-ini.mkiv + {\let\new_if_saved\newif + \let\newif\new_if_check + \expandafter\redoglobal\expandafter\def\csname\expandafter\newif\csstring#1true\endcsname {\let#1\iftrue }% + \expandafter\redoglobal\expandafter\def\csname\expandafter\newif\csstring#1false\endcsname{\let#1\iffalse}% + \dodoglobal\csname\expandafter\newif\csstring#1false\endcsname + \let\newif\new_if_saved} %D Also new: diff --git a/tex/context/base/mkiv/syst-ini.mkiv b/tex/context/base/mkiv/syst-ini.mkiv index 4b5cc616b..c27b832bb 100644 --- a/tex/context/base/mkiv/syst-ini.mkiv +++ b/tex/context/base/mkiv/syst-ini.mkiv @@ -19,51 +19,85 @@ %D Characters can have special states, that can be triggered by setting their %D category coded. Some are preset, others are to be set as soon as possible, %D otherwise we cannot define any useful macros. - -%catcode`\^^@ = 9 % ascii null is ignored -%catcode`\\ = 0 % backslash is TeX escape character - -\catcode`\{ = 1 % left brace is begin-group character -\catcode`\} = 2 % right brace is end-group character -\catcode`\$ = 3 % dollar sign is math shift -\catcode`\& = 4 % ampersand is alignment tab -\catcode`\# = 6 % hash mark is macro parameter character -\catcode`\^ = 7 % circumflex and uparrow are for superscripts -\catcode`\_ = 8 % underline and downarrow are for subscripts -\catcode`\^^I = 10 % ascii tab is a blank space - -%catcode`\^^M = 5 % ascii return is end-line -%catcode`\% = 14 % percent sign is comment character -%catcode`\ = 10 % ascii space is blank space -%catcode`\^^? = 15 % ascii delete is invalid - -\catcode`\~ = 13 % tilde is active -\catcode`\^^L = 13 % ascii form-feed - -%catcode`\A = 11 -%....... -%catcode`\Z = 11 - -%catcode`\a = 11 -%....... -%catcode`\z = 11 - -\def ^^L{\par} -\def\^^M{\ } % control = control -\def\^^I{\ } % same for - -%D In \CONTEXT, we simply ignore end||of||file tokens: - -\catcode`\^^Z=9 +%D +%D First we define a bunch of constants. Normally we would \type {\setconstant} +%D but we're prestine and have no macros defined yet. Abstraction also makes it +%D possible to avoid the \type {^^} in the input. + +\chardef\escapecatcode 0 +\chardef\begingroupcatcode 1 +\chardef\endgroupcatcode 2 +\chardef\mathshiftcatcode 3 +\chardef\alignmentcatcode 4 +\chardef\endoflinecatcode 5 +\chardef\parametercatcode 6 +\chardef\superscriptcatcode 7 +\chardef\subscriptcatcode 8 +\chardef\ignorecatcode 9 +\chardef\spacecatcode 10 +\chardef\lettercatcode 11 +\chardef\othercatcode 12 % finally obsolete: \let\other \othercatcode +\chardef\activecatcode 13 % finally obsolete: \let\active\activecatcode +\chardef\commentcatcode 14 +\chardef\invalidcatcode 15 + +%chardef\zeroasciicode 0 +\chardef\tabasciicode 9 +\chardef\newlineasciicode 10 % don't confuse this one with \endoflineasciicode +\chardef\formfeedasciicode 12 +\chardef\endoflineasciicode 13 % somewhat messy but this can be the active \par +\chardef\endoffileasciicode 26 +\chardef\spaceasciicode 32 +\chardef\exclamationmarkasciicode 33 % ! used in namespace protection +\chardef\doublequoteasciicode 34 % " +\chardef\hashasciicode 35 +\chardef\dollarasciicode 36 +\chardef\commentasciicode 37 +\chardef\ampersandasciicode 38 +\chardef\singlequoteasciicode 39 % ' +\chardef\primeasciicode 39 % ' +\chardef\hyphenasciicode 45 +\chardef\forwardslashasciicode 47 % / +\chardef\colonasciicode 58 +\chardef\lessthanasciicode 60 % < used as alternative verbatim { +\chardef\morethanasciicode 62 % > used as alternative verbatim } +\chardef\questionmarkasciicode 63 % ? used in namespace protection +\chardef\atsignasciicode 64 % @ used in namespace protection +\chardef\backslashasciicode 92 % `\\ +\chardef\circumflexasciicode 94 +\chardef\underscoreasciicode 95 +\chardef\leftbraceasciicode 123 % `\{ +\chardef\barasciicode 124 % `\| +\chardef\rightbraceasciicode 125 % `\} +\chardef\tildeasciicode 126 % `\~ +\chardef\delasciicode 127 + +%catcode\zeroasciicode \ignorecatcode % `\^^@ ascii null is ignored +\catcode\tabasciicode \spacecatcode % `\^^I ascii tab is a blank space +\catcode\formfeedasciicode \activecatcode % `\^^L ascii form-feed (active, set later) +%catcode\endoflineasciicode \endoflinecatcode % `\^^M ascii return is end-line +\catcode\endoffileasciicode \ignorecatcode % `\^^Z endoffile (ignored in ConTeXt) +%catcode\spaceasciicode \spacecatcode % `\ ascii space is blank space +\catcode\hashasciicode \parametercatcode % `\# hash mark is macro parameter character +\catcode\dollarasciicode \mathshiftcatcode % `\$ dollar sign is math shift +%catcode\commentasciicode \commentcatcode % `\% percent sign is comment character +\catcode\ampersandasciicode \alignmentcatcode % `\& ampersand is alignment tab +%catcode\backslashasciicode \escapecatcode % `\\ backslash is TeX escape character +\catcode\circumflexasciicode \superscriptcatcode % `\^ circumflex and uparrow are for superscripts +\catcode\underscoreasciicode \subscriptcatcode % `\_ underline and downarrow are for subscripts +\catcode\leftbraceasciicode \begingroupcatcode % `\{ left brace is begin-group character +\catcode\rightbraceasciicode \endgroupcatcode % `\} right brace is end-group character +\catcode\tildeasciicode \activecatcode % `\~ tilde is active +%catcode\delasciicode \invalidcatcode % `\^^? ascii delete is invalid %D It makes sense to know what engine we're running so let's try to deduce it. -\chardef\unknownengine = 0 -\chardef\pdftexengine = 1 -\chardef\xetexengine = 2 -\chardef\luatexengine = 3 +\chardef\unknownengine 0 +\chardef\pdftexengine 1 +\chardef\xetexengine 2 +\chardef\luatexengine 3 -\chardef\statuswrite = 128 +\chardef\statuswrite 128 \ifx\directlua\undefined \ifx\XeTeXversion\undefined @@ -83,7 +117,7 @@ % for historic reasons we keep some mkii code around \else \immediate\write\statuswrite{>>>} - \immediate\write\statuswrite{>>> only luatex is supported} + \immediate\write\statuswrite{>>> only LuaTeX is supported} \immediate\write\statuswrite{>>>} \let\dump\relax \expandafter\end @@ -108,6 +142,17 @@ tex.enableprimitives("normal",luatexprimitives) } +\def\space{ } +\def\empty{} + +\letcharcode \formfeedasciicode \par % \def ^^L{\par} formfeed +\letcharcode \tildeasciicode \ % tilde +\letcharcode \spaceasciicode \space % space + +\expandafter\def\csname\Uchar\tabasciicode \endcsname {\ } % \def\^^I{\ } tab +\expandafter\def\csname\Uchar\formfeedasciicode \endcsname {\par} % \def\^^L{\par} formfeed +\expandafter\def\csname\Uchar\endoflineasciicode\endcsname {\ } % \def\^^M{\ } return + %D \ETEX\ has a not so handy way of telling you the version number, i.e. the revision %D number has a period in it: @@ -120,15 +165,15 @@ \def\unprotect {\edef\protect - {\catcode`@=\the\catcode`@\relax - \catcode`?=\the\catcode`?\relax - \catcode`!=\the\catcode`!\relax - \catcode`_=\the\catcode`_\relax + {\catcode\atsignasciicode \the\catcode\atsignasciicode \relax + \catcode\exclamationmarkasciicode\the\catcode\exclamationmarkasciicode\relax + \catcode\questionmarkasciicode \the\catcode\questionmarkasciicode \relax + \catcode\underscoreasciicode \the\catcode\underscoreasciicode \relax \let\protect\relax}% - \catcode`@=11 - \catcode`?=11 - \catcode`!=11 - \catcode`_=11 } + \catcode\atsignasciicode \lettercatcode + \catcode\exclamationmarkasciicode\lettercatcode + \catcode\questionmarkasciicode \lettercatcode + \catcode\underscoreasciicode \lettercatcode} \let\protect\relax @@ -212,10 +257,10 @@ % A few traditional allocations (these might go): -\countdef \count@ = 255 % hm, used in \newif .. todo: replace it there -\dimendef \dimen@ = 0 -\dimendef \dimen@i = 1 % global only -\dimendef \dimen@ii = 2 +\countdef \count@ 255 % hm, used in \newif .. todo: replace it there +\dimendef \dimen@ 0 +\dimendef \dimen@i 1 % global only +\dimendef \dimen@ii 2 %D So, effectively we start allocating from 256 and upwards. The inserts sit in the %D range 128 upto 254. Page numbers use the counters 0 upto 9 and the pagebox is @@ -258,8 +303,7 @@ % %D The next definitions are really needed (in \CONTEXT): -%newlinechar=10 \def\outputnewlinechar{\rawcharacter{10}} -\newlinechar=10 \edef\outputnewlinechar{^^J} +\newlinechar\newlineasciicode \edef\outputnewlinechar{\Uchar\newlineasciicode} % {^^J} %D One reason to start high with allocation is that it permits us to allocate %D consecutive ranges more easily, for instance if for \MPLIB\ we want to allocate a @@ -395,19 +439,19 @@ %D More allocations: -\newskip \zeroskip \zeroskip = 0pt plus 0pt minus 0pt -\newdimen \zeropoint \zeropoint = 0pt -\newdimen \onepoint \onepoint = 1pt -\newdimen \halfapoint \halfapoint = 0.5pt -\newdimen \maxdimen \maxdimen = 16383.99999pt -\newcount \maxcount \maxcount = 2147483647 -\newdimen \onebasepoint \onebasepoint = 1bp -\newdimen \scaledpoint \scaledpoint = 1sp -\newdimen \thousandpoint \thousandpoint = 1000pt -\newmuskip\zeromuskip \zeromuskip = 0mu -\newmuskip\onemuskip \onemuskip = 1mu +\newskip \zeroskip \zeroskip 0pt plus 0pt minus 0pt +\newdimen \zeropoint \zeropoint 0pt +\newdimen \onepoint \onepoint 1pt +\newdimen \halfapoint \halfapoint 0.5pt +\newdimen \maxdimen \maxdimen 16383.99999pt +\newcount \maxcount \maxcount 2147483647 +\newdimen \onebasepoint \onebasepoint 1bp +\newdimen \scaledpoint \scaledpoint 1sp +\newdimen \thousandpoint \thousandpoint 1000pt +\newmuskip\zeromuskip \zeromuskip 0mu +\newmuskip\onemuskip \onemuskip 1mu -\newmuskip\muquad \muquad = 18mu +\newmuskip\muquad \muquad 18mu \let\points \onepoint \let\halfpoint\halfapoint @@ -416,32 +460,32 @@ %D And even more: (todo: countdefs 60+) -%newcount \minusone \minusone = -1 -\newcount \minustwo \minustwo = -2 -%chardef \zerocount = 0 -%chardef \plusone = 1 -\chardef \plustwo = 2 -\chardef \plusthree = 3 -\chardef \plusfour = 4 -\chardef \plusfive = 5 -\chardef \plussix = 6 -\chardef \plusseven = 7 -\chardef \pluseight = 8 -\chardef \plusnine = 9 -\chardef \plusten = 10 -\chardef \plussixteen = 16 -\chardef \plushundred = 100 -\chardef \plustwohundred = 200 -\chardef \pluscxxvii = 127 -\chardef \pluscxxviii = 128 -\chardef \pluscclv = 255 -\chardef \pluscclvi = 256 -\chardef \plusthousand = 1000 -\chardef \plustenthousand = 10000 -\chardef \plustwentythousand = 20000 -\chardef \medcard = 32768 -\chardef \maxcard = 65536 % pdftex has less mathchars -\chardef \maxcardminusone = 65535 +%newcount \minusone \minusone -1 +\newcount \minustwo \minustwo -2 +%chardef \zerocount 0 +%chardef \plusone 1 +\chardef \plustwo 2 +\chardef \plusthree 3 +\chardef \plusfour 4 +\chardef \plusfive 5 +\chardef \plussix 6 +\chardef \plusseven 7 +\chardef \pluseight 8 +\chardef \plusnine 9 +\chardef \plusten 10 +\chardef \plussixteen 16 +\chardef \plushundred 100 +\chardef \plustwohundred 200 +\chardef \pluscxxvii 127 +\chardef \pluscxxviii 128 +\chardef \pluscclv 255 +\chardef \pluscclvi 256 +\chardef \plusthousand 1000 +\chardef \plustenthousand 10000 +\chardef \plustwentythousand 20000 +\chardef \medcard 32768 +\chardef \maxcard 65536 % pdftex has less mathchars +\chardef \maxcardminusone 65535 %D \macros %D {doubleexpandafter,tripleexpandafter,expanded,startexpanded} @@ -506,21 +550,47 @@ %D creates \type {\footrue}, \type {\foofalse} to go with \type {\iffoo}. %D \stopnarrower -\normalprotected\def\newif#1% - {\count@\escapechar - \escapechar\minusone - \expandafter\expandafter\expandafter\def\@if #1{true}{\let#1\iftrue }% - \expandafter\expandafter\expandafter\def\@if#1{false}{\let#1\iffalse}% - \@if#1{false}% the condition starts out false - \escapechar\count@} - -\def\@if#1#2% - {\csname\expandafter\if@\string#1#2\endcsname} +% \normalprotected\def\newif#1% +% {\count@\escapechar +% \escapechar\minusone +% \expandafter\expandafter\expandafter\def\new_if #1{true}{\let#1\iftrue }% +% \expandafter\expandafter\expandafter\def\new_if#1{false}{\let#1\iffalse}% +% \new_if#1{false}% the condition starts out false +% \escapechar\count@} +% +% \def\new_if#1#2% +% {\csname\expandafter\if@\string#1#2\endcsname} +% +% \bgroup % `if' is required +% \uccode`1=`i \uccode`2=`f \uppercase{\gdef\if@12{}} +% \egroup -\bgroup % `if' is required +% We use \csstring so there is no need to push/pop escapechar. +% We use different names so that we get a better error message. +% +% \normalprotected\def\newif#1% +% {\let\new_if_saved\newif +% \let\newif\new_if_check +% \expandafter\expandafter\expandafter\def\new_if_cs #1{true}{\let#1\iftrue }% +% \expandafter\expandafter\expandafter\def\new_if_cs#1{false}{\let#1\iffalse}% +% \new_if_cs#1{false}% +% \let\newif\new_if_saved} +% +% \normalprotected\def\new_if_cs#1#2% +% {\csname\expandafter\newif\csstring#1#2\endcsname} +% +% We wrap all into one macro: - \uccode`1=`i \uccode`2=`f \uppercase{\gdef\if@12{}} +\normalprotected\def\newif#1% + {\let\new_if_saved\newif + \let\newif\new_if_check + \expandafter\def\csname\expandafter\newif\csstring#1true\endcsname {\let#1\iftrue }% + \expandafter\def\csname\expandafter\newif\csstring#1false\endcsname{\let#1\iffalse}% + \csname\expandafter\newif\csstring#1false\endcsname + \let\newif\new_if_saved} +\bgroup + \normalexpanded{\gdef\noexpand\new_if_check\string i\string f{}} \egroup %D Let's test this one: @@ -540,26 +610,6 @@ \normalprotected\def\uedef{\normalprotected\edef} \normalprotected\def\uxdef{\normalprotected\xdef} -%D The catcode constants will be redefined in later catcode related modules -%D but they can be used in the same way. - -\chardef\escapecatcode = 0 -\chardef\begingroupcatcode = 1 -\chardef\endgroupcatcode = 2 -\chardef\mathshiftcatcode = 3 -\chardef\alignmentcatcode = 4 -\chardef\endoflinecatcode = 5 -\chardef\parametercatcode = 6 -\chardef\superscriptcatcode = 7 -\chardef\subscriptcatcode = 8 -\chardef\ignorecatcode = 9 -\chardef\spacecatcode = 10 -\chardef\lettercatcode = 11 -\chardef\othercatcode = 12 -\chardef\activecatcode = 13 -\chardef\commentcatcode = 14 -\chardef\invalidcatcode = 15 - %D For a while we keep the following, as systems like tikz need it. Best %D not use that one \CONTEXT. @@ -872,28 +922,28 @@ \let\endgraf\par \let\endline\cr -\def\space{ } -\def\empty{} - \normalprotected\def\null{\hpack{}} %D The following two might be overloaded later on but some modules need then %D earlier. These functionality is reflected in the name and will not change. -\bgroup - \catcode`\^^M=\activecatcode% - \gdef\obeylines{\catcode`\^^M\activecatcode \let^^M\par}% - \global\let^^M\par% -\egroup - -\bgroup - \gdef\obeyspaces{\catcode`\ \activecatcode}% - \obeyspaces\global\let =\space% -\egroup +% \bgroup +% \catcode`\^^M=\activecatcode% +% \gdef\obeylines{\catcode`\^^M\activecatcode \let^^M\par}% +% \global\let^^M\par% +% \egroup +% +% \bgroup +% \gdef\obeyspaces{\catcode`\ \activecatcode}% +% \obeyspaces\global\let =\space% +% \egroup -%D A constant: +\def\obeylines {\catcode\endoflineasciicode\activecatcode\letcharcode\endoflineasciicode\par} +\def\obeyspaces{\catcode\spaceasciicode \activecatcode\letcharcode\spaceasciicode \space} -\let\endoflinetoken=^^M +% %D A constant: +% +% \let\endoflinetoken=^^M %D Also needed might be a simple loop structure and we borrow plain \TEX's one %D as it is often expected to be present and it is about the fastest you can @@ -980,30 +1030,30 @@ % module after which the official interfaces have to be used. This is needed for % modules not made by ctx developers. -\normalprotected\def\pdfliteral {\pdfextension literal } -\normalprotected\def\pdfcolorstack {\pdfextension colorstack } -\normalprotected\def\pdfsetmatrix {\pdfextension setmatrix } -\normalprotected\def\pdfsave {\pdfextension save\relax} -\normalprotected\def\pdfrestore {\pdfextension restore\relax} -\normalprotected\def\pdfobj {\pdfextension obj } -\normalprotected\def\pdfrefobj {\pdfextension refobj } -\normalprotected\def\pdfannot {\pdfextension annot } -\normalprotected\def\pdfstartlink {\pdfextension startlink } -\normalprotected\def\pdfendlink {\pdfextension endlink\relax} -\normalprotected\def\pdfoutline {\pdfextension outline } -\normalprotected\def\pdfdest {\pdfextension dest } -\normalprotected\def\pdfthread {\pdfextension thread } -\normalprotected\def\pdfstartthread {\pdfextension startthread } -\normalprotected\def\pdfendthread {\pdfextension endthread\relax} -\normalprotected\def\pdfinfo {\pdfextension info } -\normalprotected\def\pdfcatalog {\pdfextension catalog } -\normalprotected\def\pdfnames {\pdfextension names } -\normalprotected\def\pdfincludechars {\pdfextension includechars } -\normalprotected\def\pdffontattr {\pdfextension fontattr } -\normalprotected\def\pdfmapfile {\pdfextension mapfile } -\normalprotected\def\pdfmapline {\pdfextension mapline } -\normalprotected\def\pdftrailer {\pdfextension trailer } -\normalprotected\def\pdfglyphtounicode {\pdfextension glyphtounicode } +\normalprotected\def\pdfliteral {\pdfextension literal } +\normalprotected\def\pdfcolorstack {\pdfextension colorstack } +\normalprotected\def\pdfsetmatrix {\pdfextension setmatrix } +\normalprotected\def\pdfsave {\pdfextension save\relax} +\normalprotected\def\pdfrestore {\pdfextension restore\relax} +\normalprotected\def\pdfobj {\pdfextension obj } +\normalprotected\def\pdfrefobj {\pdfextension refobj } +\normalprotected\def\pdfannot {\pdfextension annot } +\normalprotected\def\pdfstartlink {\pdfextension startlink } +\normalprotected\def\pdfendlink {\pdfextension endlink\relax} +\normalprotected\def\pdfoutline {\pdfextension outline } +\normalprotected\def\pdfdest {\pdfextension dest } +\normalprotected\def\pdfthread {\pdfextension thread } +\normalprotected\def\pdfstartthread {\pdfextension startthread } +\normalprotected\def\pdfendthread {\pdfextension endthread\relax} +\normalprotected\def\pdfinfo {\pdfextension info } +\normalprotected\def\pdfcatalog {\pdfextension catalog } +\normalprotected\def\pdfnames {\pdfextension names } +\normalprotected\def\pdfincludechars {\pdfextension includechars } +\normalprotected\def\pdffontattr {\pdfextension fontattr } +\normalprotected\def\pdfmapfile {\pdfextension mapfile } +\normalprotected\def\pdfmapline {\pdfextension mapline } +\normalprotected\def\pdftrailer {\pdfextension trailer } +\normalprotected\def\pdfglyphtounicode {\pdfextension glyphtounicode } % \chardef\pdfnofullbanner = 1 % \chardef\pdfnofilename = 2 @@ -1188,12 +1238,14 @@ \ifdefined\protrusionboundary \else \let\protrusionboundary\boundary \fi \ifdefined\wordboundary \else \let\wordboundary \noboundary \fi -\ifdefined\mathrulesfam \else \newcount\mathrulesfam \fi -\ifdefined\mathrulesmode \else \newcount\mathrulesmode \fi -\ifdefined\mathsurroundmode \else \newcount\mathsurroundmode \fi -\ifdefined\mathitalicsmode \else \newcount\mathitalicsmode \fi -\ifdefined\mathdelimitersmode \else \newcount\mathdelimitersmode \fi -\ifdefined\mathscriptboxmode \else \newcount\mathscriptboxmode \fi +\ifdefined\mathrulesfam \else \newcount\mathrulesfam \fi +\ifdefined\mathrulesmode \else \newcount\mathrulesmode \fi +\ifdefined\mathsurroundmode \else \newcount\mathsurroundmode \fi +\ifdefined\mathitalicsmode \else \newcount\mathitalicsmode \fi +\ifdefined\mathdelimitersmode \else \newcount\mathdelimitersmode \fi +\ifdefined\mathscriptboxmode \else \newcount\mathscriptboxmode \fi +\ifdefined\mathscriptcharmode \else \newcount\mathscriptcharmode \fi +\ifdefined\mathrulethicknessmode \else \newcount\mathrulethicknessmode \fi \ifdefined\hyphenpenaltymode \else \newcount\hyphenpenaltymode \fi \ifdefined\automatichyphenpenalty \else \newcount\automatichyphenpenalty \fi diff --git a/tex/context/base/mkiv/trac-inf.lua b/tex/context/base/mkiv/trac-inf.lua index 439e8b2dc..51893d585 100644 --- a/tex/context/base/mkiv/trac-inf.lua +++ b/tex/context/base/mkiv/trac-inf.lua @@ -123,6 +123,24 @@ local function elapsed(instance) end end +local function currenttime(instance) + if type(instance) == "number" then + return instance + else + local timer = timers[instance or "notimer"] + local it = timer.timing + if it > 1 then + -- whatever + else + local starttime = timer.starttime + if starttime and starttime > 0 then + return seconds(timer.loadtime + ticks() - starttime) + end + end + return 0 + end +end + local function elapsedtime(instance) return format("%0.3f",elapsed(instance)) end @@ -141,6 +159,7 @@ statistics.hastiming = hastiming statistics.resettiming = resettiming statistics.starttiming = starttiming statistics.stoptiming = stoptiming +statistics.currenttime = currenttime statistics.elapsed = elapsed statistics.elapsedtime = elapsedtime statistics.elapsedindeed = elapsedindeed @@ -229,7 +248,7 @@ end function statistics.runtime() stoptiming(statistics) - -- stoptiming(statistics) -- somehow we can start the timer twice, but where + -- stoptiming(statistics) -- somehow we can start the timer twice, but where return statistics.formatruntime(elapsedtime(statistics)) end diff --git a/tex/context/base/mkiv/trac-log.lua b/tex/context/base/mkiv/trac-log.lua index 1471bd4c7..297d053ab 100644 --- a/tex/context/base/mkiv/trac-log.lua +++ b/tex/context/base/mkiv/trac-log.lua @@ -758,7 +758,7 @@ if tex then local report = logs.reporter("pages") -- not needed but saves checking when we grep for it local texgetcount = tex and tex.getcount - local real, user, sub + local real, user, sub = 0, 0, 0 function logs.start_page_number() real = texgetcount("realpageno") @@ -766,47 +766,35 @@ if tex then sub = texgetcount("subpageno") end - local timing = false - local starttime = nil - local lasttime = nil + local timing = false + local lasttime = nil trackers.register("pages.timing", function(v) -- only for myself (diagnostics) - starttime = os.clock() -- todo: use other timer - timing = true + timing = "" end) function logs.stop_page_number() -- the first page can includes the initialization so we omit this in average if timing then - local elapsed, average - local stoptime = os.clock() + local elapsed = statistics.currenttime(statistics) + local average, page if not lasttime or real < 2 then - elapsed = stoptime - average = stoptime - starttime = stoptime + average = elapsed + page = elapsed else - elapsed = stoptime - lasttime - average = (stoptime - starttime) / (real - 1) - end - lasttime = stoptime - if real <= 0 then - report("flushing page, time %0.04f / %0.04f",elapsed,average) - elseif user <= 0 then - report("flushing realpage %s, time %0.04f / %0.04f",real,elapsed,average) - elseif sub <= 0 then - report("flushing realpage %s, userpage %s, time %0.04f / %0.04f",real,user,elapsed,average) - else - report("flushing realpage %s, userpage %s, subpage %s, time %0.04f / %0.04f",real,user,sub,elapsed,average) + average = elapsed / (real - 1) + page = elapsed - lasttime end + lasttime = elapsed + timing = formatters[", total %0.03f, page %0.03f, average %0.03f"](elapsed,page,average) + end + if real <= 0 then + report("flushing page%s",timing) + elseif user <= 0 then + report("flushing realpage %s%s",real,timing) + elseif sub <= 0 then + report("flushing realpage %s, userpage %s%s",real,user,timing) else - if real <= 0 then - report("flushing page") - elseif user <= 0 then - report("flushing realpage %s",real) - elseif sub <= 0 then - report("flushing realpage %s, userpage %s",real,user) - else - report("flushing realpage %s, userpage %s, subpage %s",real,user,sub) - end + report("flushing realpage %s, userpage %s, subpage %s%s",real,user,sub,timing) end logs.flush() end diff --git a/tex/context/base/mkiv/trac-vis.lua b/tex/context/base/mkiv/trac-vis.lua index 0e37752db..91ee1cf7d 100644 --- a/tex/context/base/mkiv/trac-vis.lua +++ b/tex/context/base/mkiv/trac-vis.lua @@ -1433,8 +1433,7 @@ do } local function markfonts(list) - for n in traverse_nodes(list) do - local id = getid(n) + for n, id in traverse_nodes(list) do if id == glyph_code then local font = getfont(n) local okay = used[font] diff --git a/tex/context/base/mkiv/trac-vis.mkiv b/tex/context/base/mkiv/trac-vis.mkiv index a6a3fa5a2..b7e506faf 100644 --- a/tex/context/base/mkiv/trac-vis.mkiv +++ b/tex/context/base/mkiv/trac-vis.mkiv @@ -122,6 +122,11 @@ \unexpanded\def\showfontitalics {\clf_setvisual{italic}} +\unexpanded\def\showglyphdata + {\showglyphs + \showfontkerns + \showfontitalics} + \unexpanded\def\showfontexpansion {\clf_setvisual{expansion}} diff --git a/tex/context/base/mkiv/util-lua.lua b/tex/context/base/mkiv/util-lua.lua index b7de11936..7c5e1bf2a 100644 --- a/tex/context/base/mkiv/util-lua.lua +++ b/tex/context/base/mkiv/util-lua.lua @@ -198,12 +198,12 @@ function luautilities.checkmemory(previous,threshold,trace) -- threshold in MB collectgarbage("collect") local afterwards = collectgarbage("count") if trace or tracememory then - report_mem("previous %i MB, current %i MB, delta %i MB, threshold %i MB, afterwards %i MB", + report_mem("previous %r MB, current %r MB, delta %r MB, threshold %r MB, afterwards %r MB", previous/1024,current/1024,delta/1024,threshold,afterwards) end return afterwards elseif trace or tracememory then - report_mem("previous %i MB, current %i MB, delta %i MB, threshold %i MB", + report_mem("previous %r MB, current %r MB, delta %r MB, threshold %r MB", previous/1024,current/1024,delta/1024,threshold) end end diff --git a/tex/context/base/mkiv/util-prs.lua b/tex/context/base/mkiv/util-prs.lua index 48d59a9f3..891f1096a 100644 --- a/tex/context/base/mkiv/util-prs.lua +++ b/tex/context/base/mkiv/util-prs.lua @@ -31,6 +31,7 @@ utilities.parsers.hashes = hashes local digit = R("09") local space = P(' ') local equal = P("=") +local colon = P(":") local comma = P(",") local lbrace = P("{") local rbrace = P("}") @@ -72,11 +73,13 @@ lpegpatterns.nested = nestedbraces -- no capture lpegpatterns.argument = argument -- argument after e.g. = lpegpatterns.content = content -- rest after e.g = -local value = P(lbrace * C((nobrace + nestedbraces)^0) * rbrace) + C((nestedbraces + (1-comma))^0) +local value = lbrace * C((nobrace + nestedbraces)^0) * rbrace + + C((nestedbraces + (1-comma))^0) local key = C((1-equal-comma)^1) local pattern_a = (space+comma)^0 * (key * equal * value + key * C("")) local pattern_c = (space+comma)^0 * (key * equal * value) +local pattern_d = (space+comma)^0 * (key * (equal+colon) * value + key * C("")) local key = C((1-space-equal-comma)^1) local pattern_b = spaces * comma^0 * spaces * (key * ((spaces * equal * spaces * value) + C(""))) @@ -92,10 +95,12 @@ end local pattern_a_s = (pattern_a/set)^1 local pattern_b_s = (pattern_b/set)^1 local pattern_c_s = (pattern_c/set)^1 +local pattern_d_s = (pattern_d/set)^1 patterns.settings_to_hash_a = pattern_a_s patterns.settings_to_hash_b = pattern_b_s patterns.settings_to_hash_c = pattern_c_s +patterns.settings_to_hash_d = pattern_d_s function parsers.make_settings_to_hash_pattern(set,how) if how == "strict" then @@ -126,6 +131,18 @@ function parsers.settings_to_hash(str,existing) end end +function parsers.settings_to_hash_colon_too(str) + if not str or str == "" then + return { } + elseif type(str) == "table" then + return str + else + hash = { } + lpegmatch(pattern_d_s,str) + return hash + end +end + function parsers.settings_to_hash_tolerant(str,existing) if not str or str == "" then return { } @@ -165,7 +182,7 @@ function parsers.settings_to_hash_strict(str,existing) end local separator = comma * space^0 -local value = P(lbrace * C((nobrace + nestedbraces)^0) * rbrace) +local value = lbrace * C((nobrace + nestedbraces)^0) * rbrace + C((nestedbraces + (1-comma))^0) local pattern = spaces * Ct(value*(separator*value)^0) @@ -210,7 +227,7 @@ function parsers.settings_to_numbers(str) return str end -local value = P(lbrace * C((nobrace + nestedbraces)^0) * rbrace) +local value = lbrace * C((nobrace + nestedbraces)^0) * rbrace + C((nestedbraces + nestedbrackets + nestedparents + (1-comma))^0) local pattern = spaces * Ct(value*(separator*value)^0) @@ -242,7 +259,7 @@ function parsers.groupedsplitat(symbol,withaction) if not pattern then local symbols = S(symbol) local separator = space^0 * symbols * space^0 - local value = P(lbrace * C((nobrace + nestedbraces)^0) * rbrace) + local value = lbrace * C((nobrace + nestedbraces)^0) * rbrace + C((nestedbraces + (1-(space^0*(symbols+P(-1)))))^0) if withaction then local withvalue = Carg(1) * value / function(f,s) return f(s) end diff --git a/tex/context/base/mkiv/util-sto.lua b/tex/context/base/mkiv/util-sto.lua index 5b6915eaf..0da685e9f 100644 --- a/tex/context/base/mkiv/util-sto.lua +++ b/tex/context/base/mkiv/util-sto.lua @@ -196,6 +196,16 @@ function table.getmetatablekey(t,key,value) return m and m[key] end +function table.makeweak(t) + local m = getmetatable(t) + if m then + m.__mode = "v" + else + setmetatable(t,{ __mode = "v" }) + end + return t +end + -- Problem: we have no __next (which is ok as it would probably slow down lua) so -- we cannot loop over the keys. diff --git a/tex/context/fonts/mkiv/type-imp-cambria.mkiv b/tex/context/fonts/mkiv/type-imp-cambria.mkiv index f5679fd92..06781a8d0 100644 --- a/tex/context/fonts/mkiv/type-imp-cambria.mkiv +++ b/tex/context/fonts/mkiv/type-imp-cambria.mkiv @@ -20,6 +20,8 @@ % microsoft: cambria.ttc cambriab.ttf cambriai.ttf cambriaz.ttf % ascender : cambmath.ttf cambria.ttf cambriab.ttf cambriai.ttf cambriaz.ttf + \doifunknownfontfeature {cambria-math-bold} {\definefontfeature[cambria-math-bold][boldened]} + \starttypescript [\s!math,\s!serif] [cambria,cambria-x,cambria-y] % whatever matches \definefontsynonym [CambriaMath] [\s!name:cambriamath] @@ -42,15 +44,18 @@ \starttypescript [\s!math] [cambria,cambria-m,cambria-a] [\s!name] \loadfontgoodies[cambria-math] - \definefontsynonym [\s!MathRoman] [CambriaMath] [\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=cambria-math] + \definefontsynonym [\s!MathRoman] [CambriaMath] [\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=cambria-math] + \definefontsynonym [\s!MathRomanBold] [CambriaMath] [\s!features={\s!math\mathsizesuffix,cambria-math-bold,mathextra},\s!goodies=cambria-math] \stoptypescript \starttypescript [\s!math] [cambria-x] [\s!name] \loadfontgoodies[cambria-math] - \definefontsynonym [\s!MathRoman] [CambriaMath] [\s!features={\s!math,mathextra},\s!goodies=cambria-math] + \definefontsynonym [\s!MathRoman] [CambriaMath] [\s!features={\s!math,mathextra},\s!goodies=cambria-math] + \definefontsynonym [\s!MathRomanBold] [CambriaMath] [\s!features={\s!math,cambria-math-bold,mathextra},\s!goodies=cambria-math] \stoptypescript \starttypescript [\s!math] [cambria-y] [\s!name] \loadfontgoodies[cambria-math] - \definefontsynonym [\s!MathRoman] [CambriaMath] [\s!features={\s!math-nostack\mathsizesuffix,mathextra},\s!goodies=cambria-math] + \definefontsynonym [\s!MathRoman] [CambriaMath] [\s!features={\s!math-nostack\mathsizesuffix,mathextra},\s!goodies=cambria-math] + \definefontsynonym [\s!MathRomanBold] [CambriaMath] [\s!features={\s!math-nostack\mathsizesuffix,cambria-math-bold,mathextra},\s!goodies=cambria-math] \stoptypescript \starttypescript [\s!serif] [cambria,cambria-m,cambria-a] [\s!name] diff --git a/tex/context/fonts/mkiv/type-imp-dejavu.mkiv b/tex/context/fonts/mkiv/type-imp-dejavu.mkiv index 582d8a764..3af9d2d17 100644 --- a/tex/context/fonts/mkiv/type-imp-dejavu.mkiv +++ b/tex/context/fonts/mkiv/type-imp-dejavu.mkiv @@ -15,6 +15,8 @@ \starttypescriptcollection[dejavu] + \doifunknownfontfeature {dejavu-math-bold} {\definefontfeature[dejavu-math-bold][boldened]} + \starttypescript [\s!serif] [dejavu] [\s!name] \setups[\s!font:\s!fallback:\s!serif] \definefontsynonym [\s!Serif] [\s!name:dejavuserif] [\s!features=\s!default,\s!fallbacks=\s!Serif] @@ -41,7 +43,8 @@ \starttypescript [\s!math][dejavu][\s!name] \loadfontgoodies[dejavu-math] - \definefontsynonym[\s!MathRoman][file:texgyredejavu-math][\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=dejavu-math] + \definefontsynonym[\s!MathRoman] [file:texgyredejavu-math][\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=dejavu-math] + \definefontsynonym[\s!MathRomanBold][file:texgyredejavu-math][\s!features={\s!math\mathsizesuffix,dejavu-math-bold,mathextra},\s!goodies=schola-math] \stoptypescript \starttypescript[dejavu] diff --git a/tex/context/fonts/mkiv/type-imp-latinmodern.mkiv b/tex/context/fonts/mkiv/type-imp-latinmodern.mkiv index 63f74027b..cc9559d8b 100644 --- a/tex/context/fonts/mkiv/type-imp-latinmodern.mkiv +++ b/tex/context/fonts/mkiv/type-imp-latinmodern.mkiv @@ -28,6 +28,8 @@ \starttypescriptcollection[latinmodern] + \doifunknownfontfeature {lm-math-bold} {\definefontfeature[lm-math-bold][boldened]} + \starttypescript [\s!serif] [simple] [\s!name] \definefontsynonym [\s!Simple] [\s!file:lmmonoproplt10-regular] [\s!features=\s!default] \stoptypescript @@ -180,7 +182,7 @@ \starttypescript [\s!math] [modern,latin-modern] \loadfontgoodies[lm] \definefontsynonym [LMMathRoman-Regular] [\v!file:latinmodern-math-regular.otf] [\s!features={\s!math\mathsizesuffix,lm-math,mathextra},\s!goodies=lm] - \definefontsynonym [LMMathRoman-Bold] [\v!file:latinmodern-math-regular.otf] [\s!features={\s!math\mathsizesuffix,lm-math,mathextra},\s!goodies=lm] + \definefontsynonym [LMMathRoman-Bold] [\v!file:latinmodern-math-regular.otf] [\s!features={\s!math\mathsizesuffix,lm-math-bold,lm-math,mathextra},\s!goodies=lm] \stoptypescript \starttypescript [modern-designsize-virtual] diff --git a/tex/context/fonts/mkiv/type-imp-modernlatin.mkiv b/tex/context/fonts/mkiv/type-imp-modernlatin.mkiv index a3f4762f1..2494d1af2 100644 --- a/tex/context/fonts/mkiv/type-imp-modernlatin.mkiv +++ b/tex/context/fonts/mkiv/type-imp-modernlatin.mkiv @@ -13,50 +13,52 @@ \starttypescriptcollection[modernlatin] - \definefontfeature[lm-rm-regular][effect={width=0.15,delta=1.00}] - \definefontfeature[lm-rm-bold] [effect={width=0.30,delta=1.00}] - \definefontfeature[lm-ss-regular][effect={width=0.10,delta=1.00}] - \definefontfeature[lm-ss-bold] [effect={width=0.20,delta=1.00}] - \definefontfeature[lm-tt-regular][effect={width=0.20,delta=1.00}] - \definefontfeature[lm-tt-bold] [effect={width=0.30,delta=1.00}] + \doifunknownfontfeature {lm-serif-regular} {\definefontfeature[lm-serif-regular][boldened-15]} + \doifunknownfontfeature {lm-serif-bold} {\definefontfeature[lm-serif-bold] [boldened-30]} + \doifunknownfontfeature {lm-sans-regular} {\definefontfeature[lm-sans-regular] [boldened-10]} + \doifunknownfontfeature {lm-sans-bold} {\definefontfeature[lm-sans-bold] [boldened-20]} + \doifunknownfontfeature {lm-mono-regular} {\definefontfeature[lm-mono-regular] [boldened-20]} + \doifunknownfontfeature {lm-mono-bold} {\definefontfeature[lm-mono-bold] [boldened-30]} + \doifunknownfontfeature {lm-math-regular} {\definefontfeature[lm-math-regular] [boldened-15]} + \doifunknownfontfeature {lm-math-bold} {\definefontfeature[lm-math-bold] [boldened-30]} \starttypescript [\s!serif] [modern-latin] % \loadfontgoodies[lm] - \definefontsynonym [Serif] [\s!file:lmroman10-regular] [\s!features={\s!default,lm-rm-regular}] - \definefontsynonym [SerifItalic] [\s!file:lmroman10-italic] [\s!features={\s!default,lm-rm-regular}] - \definefontsynonym [SerifSlanted] [\s!file:lmromanslant10-regular] [\s!features={\s!default,lm-rm-regular}] - \definefontsynonym [SerifBold] [\s!file:lmroman10-regular] [\s!features={\s!default,lm-rm-bold}] - \definefontsynonym [SerifBoldItalic] [\s!file:lmroman10-italic] [\s!features={\s!default,lm-rm-bold}] - \definefontsynonym [SerifBoldSlanted][\s!file:lmromanslant10-regular] [\s!features={\s!default,lm-rm-bold}] + \definefontsynonym [Serif] [\s!file:lmroman10-regular] [\s!features={\s!default,lm-serif-regular}] + \definefontsynonym [SerifItalic] [\s!file:lmroman10-italic] [\s!features={\s!default,lm-serif-regular}] + \definefontsynonym [SerifSlanted] [\s!file:lmromanslant10-regular] [\s!features={\s!default,lm-serif-regular}] + \definefontsynonym [SerifBold] [\s!file:lmroman10-regular] [\s!features={\s!default,lm-serif-bold}] + \definefontsynonym [SerifBoldItalic] [\s!file:lmroman10-italic] [\s!features={\s!default,lm-serif-bold}] + \definefontsynonym [SerifBoldSlanted][\s!file:lmromanslant10-regular] [\s!features={\s!default,lm-serif-bold}] \stoptypescript \starttypescript [\s!sans] [modern-latin] % \loadfontgoodies[lm] - \definefontsynonym [Sans] [\s!file:lmsans10-regular] [\s!features={\s!default,lm-ss-regular}] - \definefontsynonym [SansItalic] [\s!file:lmsans10-oblique] [\s!features={\s!default,lm-ss-regular}] - \definefontsynonym [SansSlanted] [\s!file:lmsans10-oblique] [\s!features={\s!default,lm-ss-regular}] - \definefontsynonym [SansBold] [\s!file:lmsans10-regular] [\s!features={\s!default,lm-ss-bold}] - \definefontsynonym [SansBoldItalic] [\s!file:lmsans10-oblique] [\s!features={\s!default,lm-ss-bold}] - \definefontsynonym [SansBoldSlanted][\s!file:lmsans10-oblique] [\s!features={\s!default,lm-ss-bold}] + \definefontsynonym [Sans] [\s!file:lmsans10-regular] [\s!features={\s!default,lm-sans-regular}] + \definefontsynonym [SansItalic] [\s!file:lmsans10-oblique] [\s!features={\s!default,lm-sans-regular}] + \definefontsynonym [SansSlanted] [\s!file:lmsans10-oblique] [\s!features={\s!default,lm-sans-regular}] + \definefontsynonym [SansBold] [\s!file:lmsans10-regular] [\s!features={\s!default,lm-sans-bold}] + \definefontsynonym [SansBoldItalic] [\s!file:lmsans10-oblique] [\s!features={\s!default,lm-sans-bold}] + \definefontsynonym [SansBoldSlanted][\s!file:lmsans10-oblique] [\s!features={\s!default,lm-sans-bold}] \stoptypescript \starttypescript [\s!mono] [modern-latin] % \loadfontgoodies[lm] - \definefontsynonym [Mono] [\s!file:lmmono10-regular] [\s!features={\s!default,lm-tt-regular}] - \definefontsynonym [MonoItalic] [\s!file:lmmono10-italic] [\s!features={\s!default,lm-tt-regular}] - \definefontsynonym [MonoSlanted] [\s!file:lmmonoslant10-regular] [\s!features={\s!default,lm-tt-regular}] - \definefontsynonym [MonoBold] [\s!file:lmmono10-regular] [\s!features={\s!default,lm-tt-bold}] - \definefontsynonym [MonoBoldItalic] [\s!file:lmmono10-italic] [\s!features={\s!default,lm-tt-bold}] - \definefontsynonym [MonoBoldSlanted][\s!file:lmmonoslant10-regular] [\s!features={\s!default,lm-tt-bold}] + \definefontsynonym [Mono] [\s!file:lmmono10-regular] [\s!features={\s!default,lm-mono-regular}] + \definefontsynonym [MonoItalic] [\s!file:lmmono10-italic] [\s!features={\s!default,lm-mono-regular}] + \definefontsynonym [MonoSlanted] [\s!file:lmmonoslant10-regular] [\s!features={\s!default,lm-mono-regular}] + \definefontsynonym [MonoBold] [\s!file:lmmono10-regular] [\s!features={\s!default,lm-mono-bold}] + \definefontsynonym [MonoBoldItalic] [\s!file:lmmono10-italic] [\s!features={\s!default,lm-mono-bold}] + \definefontsynonym [MonoBoldSlanted][\s!file:lmmonoslant10-regular] [\s!features={\s!default,lm-mono-bold}] \stoptypescript \starttypescript [\s!math] [modern-latin] \loadfontgoodies[lm] - \definefontsynonym [LMMathRoman-Regular] [\v!file:latinmodern-math-regular.otf] [\s!features={\s!math\mathsizesuffix,lm-math,mathextra},\s!goodies=lm] - \definefontsynonym [LMMathRoman-Bold] [\v!file:latinmodern-math-regular.otf] [\s!features={\s!math\mathsizesuffix,lm-math,mathextra},\s!goodies=lm] + \definefontsynonym [MathRoman] [\v!file:latinmodern-math-regular.otf] [\s!features={\s!math\mathsizesuffix,lm-math,lm-math-regular,mathextra},\s!goodies=lm] + \definefontsynonym [MathRomanBold] [\v!file:latinmodern-math-regular.otf] [\s!features={\s!math\mathsizesuffix,lm-math,lm-math-bold,mathextra},\s!goodies=lm] \stoptypescript - \starttypescript [modern-latin] + \starttypescript [modern-latin,modernlatin] \definetypeface [\typescriptone] [\s!rm] [\s!serif] [modern-latin] [\s!default] \definetypeface [\typescriptone] [\s!ss] [\s!sans] [modern-latin] [\s!default] \definetypeface [\typescriptone] [\s!tt] [\s!mono] [modern-latin] [\s!default] diff --git a/tex/context/fonts/mkiv/type-imp-texgyre.mkiv b/tex/context/fonts/mkiv/type-imp-texgyre.mkiv index 2bec4c2a8..583da77c1 100644 --- a/tex/context/fonts/mkiv/type-imp-texgyre.mkiv +++ b/tex/context/fonts/mkiv/type-imp-texgyre.mkiv @@ -20,6 +20,11 @@ \starttypescriptcollection[texgyre] + \doifunknownfontfeature {pagella-math-bold} {\definefontfeature[pagella-math-bold][boldened]} + \doifunknownfontfeature {schola-math-bold} {\definefontfeature[schola-math-bold] [boldened]} + \doifunknownfontfeature {bonum-math-bold} {\definefontfeature[bonum-math-bold] [boldened]} + \doifunknownfontfeature {termes-math-bold} {\definefontfeature[termes-math-bold] [boldened]} + \definetypescriptprefix [f:pagella] [pagella] \definetypescriptprefix [f:termes] [termes] \definetypescriptprefix [f:heros] [heros] @@ -242,7 +247,8 @@ \starttypescript [\s!math][times,termes][\s!all] % \loadfontgoodies[texgyre] % \definefontsynonym[\s!MathRoman][file:texgyre-termes-math-regular.otf][\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=texgyre] - \definefontsynonym[\s!MathRoman][file:texgyretermes-math.otf][\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=termes-math] + \definefontsynonym[\s!MathRoman] [file:texgyretermes-math.otf][\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=termes-math] + \definefontsynonym[\s!MathRomanBold][file:texgyretermes-math.otf][\s!features={\s!math\mathsizesuffix,termes-math-bold,mathextra},\s!goodies=schola-math] \stoptypescript \stoptypescriptcollection @@ -270,7 +276,8 @@ \starttypescript [\s!math][palatino,pagella][\s!all] % \loadfontgoodies[texgyre] % \definefontsynonym[\s!MathRoman][file:texgyre-pagella-math-regular.otf][\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=texgyre] - \definefontsynonym[\s!MathRoman][file:texgyrepagella-math.otf][\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=pagella-math] + \definefontsynonym[\s!MathRoman] [file:texgyrepagella-math.otf][\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=pagella-math] + \definefontsynonym[\s!MathRomanBold][file:texgyrepagella-math.otf][\s!features={\s!math\mathsizesuffix,pagella-math-bold,mathextra},\s!goodies=schola-math] \stoptypescript \stoptypescriptcollection @@ -282,7 +289,8 @@ \starttypescript [\s!math][bookman,bonum][\s!all] % \loadfontgoodies[texgyre] % \definefontsynonym[\s!MathRoman][file:texgyre-bonum-math-regular.otf][\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=texgyre] - \definefontsynonym[\s!MathRoman][file:texgyrebonum-math.otf][\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=bonum-math] + \definefontsynonym[\s!MathRoman] [file:texgyrebonum-math.otf][\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=bonum-math] + \definefontsynonym[\s!MathRomanBold][file:texgyrebonum-math.otf][\s!features={\s!math\mathsizesuffix,bonum-math-bold,mathextra},\s!goodies=schola-math] \stoptypescript \stoptypescriptcollection @@ -292,7 +300,8 @@ \starttypescript [\s!math][schoolbook,schola][\s!all] % \loadfontgoodies[texgyre] % \definefontsynonym[\s!MathRoman][file:texgyre-schola-math-regular.otf][\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=texgyre] - \definefontsynonym[\s!MathRoman][file:texgyreschola-math.otf][\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=schola-math] + \definefontsynonym[\s!MathRoman] [file:texgyreschola-math.otf][\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=schola-math] + \definefontsynonym[\s!MathRomanBold][file:texgyreschola-math.otf][\s!features={\s!math\mathsizesuffix,schola-math-bold,mathextra},\s!goodies=schola-math] \stoptypescript \stoptypescriptcollection diff --git a/tex/context/interface/mkii/keys-nl.xml b/tex/context/interface/mkii/keys-nl.xml index 212685d44..f493e096f 100644 --- a/tex/context/interface/mkii/keys-nl.xml +++ b/tex/context/interface/mkii/keys-nl.xml @@ -188,6 +188,7 @@ + @@ -800,7 +801,7 @@ - + @@ -855,6 +856,7 @@ + @@ -1081,6 +1083,7 @@ + @@ -1166,8 +1169,10 @@ + + diff --git a/tex/context/interface/mkiv/context-en.xml b/tex/context/interface/mkiv/context-en.xml index 4cfb3c7fe..8d0ae0644 100644 --- a/tex/context/interface/mkiv/context-en.xml +++ b/tex/context/interface/mkiv/context-en.xml @@ -11575,6 +11575,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -44449,6 +44488,8 @@ + + @@ -45671,6 +45712,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tex/context/interface/mkiv/i-context.pdf b/tex/context/interface/mkiv/i-context.pdf index 4ef3011df..16cba5392 100644 Binary files a/tex/context/interface/mkiv/i-context.pdf and b/tex/context/interface/mkiv/i-context.pdf differ diff --git a/tex/context/interface/mkiv/i-fonts.xml b/tex/context/interface/mkiv/i-fonts.xml index 1e6e169a4..9735f8935 100644 --- a/tex/context/interface/mkiv/i-fonts.xml +++ b/tex/context/interface/mkiv/i-fonts.xml @@ -421,7 +421,6 @@ - @@ -430,6 +429,29 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tex/context/interface/mkiv/i-readme.pdf b/tex/context/interface/mkiv/i-readme.pdf index d8b9f44d9..539507938 100644 Binary files a/tex/context/interface/mkiv/i-readme.pdf and b/tex/context/interface/mkiv/i-readme.pdf differ diff --git a/tex/context/interface/mkiv/i-visualizer.xml b/tex/context/interface/mkiv/i-visualizer.xml index daaad28cd..cf9d22e22 100644 --- a/tex/context/interface/mkiv/i-visualizer.xml +++ b/tex/context/interface/mkiv/i-visualizer.xml @@ -148,6 +148,10 @@ + + + + @@ -156,4 +160,4 @@ - \ No newline at end of file + diff --git a/tex/context/interface/mkiv/i-xml.xml b/tex/context/interface/mkiv/i-xml.xml index d09913f7c..1786e1bf6 100644 --- a/tex/context/interface/mkiv/i-xml.xml +++ b/tex/context/interface/mkiv/i-xml.xml @@ -664,6 +664,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tex/generic/context/luatex/luatex-basics-gen.lua b/tex/generic/context/luatex/luatex-basics-gen.lua index 2be55ccea..63a455dbf 100644 --- a/tex/generic/context/luatex/luatex-basics-gen.lua +++ b/tex/generic/context/luatex/luatex-basics-gen.lua @@ -11,6 +11,15 @@ if context then os.exit() end +-- We could load a few more of the general context libraries but it would +-- not make plain / latex users more happy I guess. So, we stick to some +-- placeholders. + +local match, gmatch, gsub, lower = string.match, string.gmatch, string.gsub, string.lower +local formatters, split, format, dump = string.formatters, string.split, string.format, string.dump +local loadfile, type = loadfile, type +local setmetatable, getmetatable, collectgarbage = setmetatable, getmetatable, collectgarbage + local dummyfunction = function() end @@ -18,7 +27,7 @@ local dummyreporter = function(c) return function(f,...) local r = texio.reporter or texio.write_nl if f then - r(c .. " : " .. string.formatters(f,...)) + r(c .. " : " ..formatters(f,...)) else r("") end @@ -66,10 +75,11 @@ callbacks = { register = function(n,f) return callback.register(n,f) end, - } -utilities = utilities or { } utilities.storage = { +utilities = utilities or { } + +utilities.storage = utilities.storage or { allocate = function(t) return t or { } end, @@ -78,6 +88,28 @@ utilities = utilities or { } utilities.storage = { end, } +utilities.parsers = utilities.parsers or { + -- these are less flexible than in context but ok + -- for generic purpose + settings_to_array = function(s) + return split(s,",") + end, + settings_to_hash = function(s) + local t = { } + for k, v in gmatch(s,"([^%s,=]+)=([^%s,]+)") do + t[k] = v + end + return t + end, + settings_to_hash_colon_too = function(s) + local t = { } + for k, v in gmatch(s,"([^%s,=:]+)[=:]([^%s,]+)") do + t[k] = v + end + return t + end, +} + characters = characters or { data = { } } @@ -101,14 +133,14 @@ local remapper = { } function resolvers.findfile(name,fileformat) - name = string.gsub(name,"\\","/") + name = gsub(name,"\\","/") if not fileformat or fileformat == "" then fileformat = file.suffix(name) if fileformat == "" then fileformat = "tex" end end - fileformat = string.lower(fileformat) + fileformat = lower(fileformat) fileformat = remapper[fileformat] or fileformat local found = kpse.find_file(name,fileformat) if not found or found == "" then @@ -117,13 +149,6 @@ function resolvers.findfile(name,fileformat) return found end --- function resolvers.findbinfile(name,fileformat) --- if not fileformat or fileformat == "" then --- fileformat = file.suffix(name) --- end --- return resolvers.findfile(name,(fileformat and remapper[fileformat]) or fileformat) --- end - resolvers.findbinfile = resolvers.findfile function resolvers.loadbinfile(filename,filetype) @@ -191,14 +216,14 @@ do cachepaths = "." end - cachepaths = string.split(cachepaths,os.type == "windows" and ";" or ":") + cachepaths = split(cachepaths,os.type == "windows" and ";" or ":") for i=1,#cachepaths do local cachepath = cachepaths[i] if not lfs.isdir(cachepath) then lfs.mkdirs(cachepath) -- needed for texlive and latex if lfs.isdir(cachepath) then - texio.write(string.format("(created cache path: %s)",cachepath)) + texio.write(format("(created cache path: %s)",cachepath)) end end if file.is_writable(cachepath) then @@ -223,10 +248,10 @@ do texio.write_nl("quiting: fix your readable cache path") os.exit() elseif #readables == 1 and readables[1] == writable then - texio.write(string.format("(using cache: %s)",writable)) + texio.write(format("(using cache: %s)",writable)) else - texio.write(string.format("(using write cache: %s)",writable)) - texio.write(string.format("(using read cache: %s)",table.concat(readables, " "))) + texio.write(format("(using write cache: %s)",writable)) + texio.write(format("(using read cache: %s)",table.concat(readables, " "))) end end @@ -258,75 +283,34 @@ function caches.is_writable(path,name) return fullname and file.is_writable(fullname) end --- function caches.loaddata(paths,name) --- for i=1,#paths do --- local data = false --- local luaname, lucname = makefullname(paths[i],name) --- if lucname and not lfs.isfile(lucname) and type(caches.compile) == "function" then --- -- in case we used luatex and luajittex mixed ... lub or luc file --- texio.write(string.format("(compiling luc: %s)",lucname)) --- data = loadfile(luaname) --- if data then --- data = data() --- end --- if data then --- caches.compile(data,luaname,lucname) --- return data --- end --- end --- if lucname and lfs.isfile(lucname) then -- maybe also check for size --- texio.write(string.format("(load luc: %s)",lucname)) --- data = loadfile(lucname) --- if data then --- data = data() --- end --- if data then --- return data --- else --- texio.write(string.format("(loading failed: %s)",lucname)) --- end --- end --- if luaname and lfs.isfile(luaname) then --- texio.write(string.format("(load lua: %s)",luaname)) --- data = loadfile(luaname) --- if data then --- data = data() --- end --- if data then --- return data --- end --- end --- end --- end - function caches.loaddata(readables,name,writable) for i=1,#readables do local path = readables[i] local loader = false local luaname, lucname = makefullname(path,name) if lfs.isfile(lucname) then - texio.write(string.format("(load luc: %s)",lucname)) + texio.write(format("(load luc: %s)",lucname)) loader = loadfile(lucname) end if not loader and lfs.isfile(luaname) then -- can be different paths when we read a file database from disk local luacrap, lucname = makefullname(writable,name) - texio.write(string.format("(compiling luc: %s)",lucname)) + texio.write(format("(compiling luc: %s)",lucname)) if lfs.isfile(lucname) then loader = loadfile(lucname) end caches.compile(data,luaname,lucname) if lfs.isfile(lucname) then - texio.write(string.format("(load luc: %s)",lucname)) + texio.write(format("(load luc: %s)",lucname)) loader = loadfile(lucname) else - texio.write(string.format("(loading failed: %s)",lucname)) + texio.write(format("(loading failed: %s)",lucname)) end if not loader then - texio.write(string.format("(load lua: %s)",luaname)) + texio.write(format("(load lua: %s)",luaname)) loader = loadfile(luaname) else - texio.write(string.format("(loading failed: %s)",luaname)) + texio.write(format("(loading failed: %s)",luaname)) end end if loader then @@ -341,42 +325,19 @@ end function caches.savedata(path,name,data) local luaname, lucname = makefullname(path,name) if luaname then - texio.write(string.format("(save: %s)",luaname)) + texio.write(format("(save: %s)",luaname)) table.tofile(luaname,data,true) if lucname and type(caches.compile) == "function" then os.remove(lucname) -- better be safe - texio.write(string.format("(save: %s)",lucname)) + texio.write(format("(save: %s)",lucname)) caches.compile(data,luaname,lucname) end end end --- According to KH os.execute is not permitted in plain/latex so there is --- no reason to use the normal context way. So the method here is slightly --- different from the one we have in context. We also use different suffixes --- as we don't want any clashes (sharing cache files is not that handy as --- context moves on faster.) --- --- Beware: serialization might fail on large files (so maybe we should pcall --- this) in which case one should limit the method to luac and enable support --- for execution. - --- function caches.compile(data,luaname,lucname) --- local d = io.loaddata(luaname) --- if not d or d == "" then --- d = table.serialize(data,true) -- slow --- end --- if d and d ~= "" then --- local f = io.open(lucname,'w') --- if f then --- local s = loadstring(d) --- if s then --- f:write(string.dump(s,true)) --- end --- f:close() --- end --- end --- end +-- The method here is slightly different from the one we have in context. We +-- also use different suffixes as we don't want any clashes (sharing cache +-- files is not that handy as context moves on faster.) function caches.compile(data,luaname,lucname) local d = io.loaddata(luaname) @@ -388,23 +349,14 @@ function caches.compile(data,luaname,lucname) if f then local s = loadstring(d) if s then - f:write(string.dump(s,true)) + f:write(dump(s,true)) end f:close() end end end --- - --- function table.setmetatableindex(t,f) --- if type(t) ~= "table" then --- f = f or t --- t = { } --- end --- setmetatable(t,{ __index = f }) --- return t --- end +-- simplfied version: function table.setmetatableindex(t,f) if type(t) ~= "table" then @@ -422,13 +374,24 @@ function table.setmetatableindex(t,f) return t end +function table.makeweak(t) + local m = getmetatable(t) + if m then + m.__mode = "v" + else + setmetatable(t,{ __mode = "v" }) + end + return t +end + + -- helper for plain: arguments = { } if arg then for i=1,#arg do - local k, v = string.match(arg[i],"^%-%-([^=]+)=?(.-)$") + local k, v = match(arg[i],"^%-%-([^=]+)=?(.-)$") if k and v then arguments[k] = v end diff --git a/tex/generic/context/luatex/luatex-core.lua b/tex/generic/context/luatex/luatex-core.lua index 35005d1c8..7fcfb8100 100644 --- a/tex/generic/context/luatex/luatex-core.lua +++ b/tex/generic/context/luatex/luatex-core.lua @@ -1,18 +1,21 @@ -- luatex-core security and io overloads ........... -- if not modules then modules = { } end modules ['luatex-core'] = { --- version = 1.005, +-- version = 1.080, -- comment = 'companion to luatex', -- author = 'Hans Hagen & Luigi Scarso', -- copyright = 'LuaTeX Development Team', -- } -LUATEXCOREVERSION = 1.005 +LUATEXCOREVERSION = 1.080 -- we reflect the luatex version where changes happened -- This file overloads some Lua functions. The readline variants provide the same -- functionality as LuaTeX <= 1.04 and doing it this way permits us to keep the -- original io libraries clean. Performance is probably even a bit better now. +-- We test for functions already being defined so that we don't overload ones that +-- are provided in the startup script. + local type, next, getmetatable, require = type, next, getmetatable, require local find, gsub, format = string.find, string.gsub, string.format @@ -195,16 +198,20 @@ if md5 then local format = string.format local byte = string.byte - function md5.sumhexa(k) - return (gsub(sum(k), ".", function(c) - return format("%02x",byte(c)) - end)) + if not md5.sumhexa then + function md5.sumhexa(k) + return (gsub(sum(k), ".", function(c) + return format("%02x",byte(c)) + end)) + end end - function md5.sumHEXA(k) - return (gsub(sum(k), ".", function(c) - return format("%02X",byte(c)) - end)) + if not md5.sumHEXA then + function md5.sumHEXA(k) + return (gsub(sum(k), ".", function(c) + return format("%02X",byte(c)) + end)) + end end end @@ -369,6 +376,45 @@ do end +do + + local lfsattributes = lfs.attributes + local symlinkattributes = lfs.symlinkattributes + + -- these can now be done using lfs (was dead slow before) + + if not lfs.isfile then + function lfs.isfile(name) + local m = lfsattributes(name,"mode") + return m == "file" or m == "link" + end + end + + if not lfs.isdir then + function lfs.isdir(name) + local m = lfsattributes(name,"mode") + return m == "directory" + end + end + + -- shortnames have also be sort of dropped from kpse + + if not lfs.shortname then + function lfs.shortname(name) + return name + end + end + + -- now there is a target field, so ... + + if not lfs.readlink then + function lfs.readlink(name) + return symlinkattributes(name,"target") or nil + end + end + +end + -- so far if utilities and utilities.merger and utilities.merger.compact then diff --git a/tex/generic/context/luatex/luatex-fonts-ext.lua b/tex/generic/context/luatex/luatex-fonts-ext.lua index 15762d9ba..4f475bf4b 100644 --- a/tex/generic/context/luatex/luatex-fonts-ext.lua +++ b/tex/generic/context/luatex/luatex-fonts-ext.lua @@ -11,85 +11,51 @@ if context then os.exit() end -local fonts = fonts -local otffeatures = fonts.constructors.features.otf -local getprivate = fonts.constructors.getprivate +local byte = string.byte --- A few generic extensions. +local fonts = fonts +local handlers = fonts.handlers +local otf = handlers.otf +local afm = handlers.afm +local registerotffeature = otf.features.register +local registerafmfeature = afm.features.register -local function initializeitlc(tfmdata,value) - if value then - -- the magic 40 and it formula come from Dohyun Kim but we might need another guess - local parameters = tfmdata.parameters - local italicangle = parameters.italicangle - if italicangle and italicangle ~= 0 then - local properties = tfmdata.properties - local factor = tonumber(value) or 1 - properties.hasitalics = true - properties.autoitalicamount = factor * (parameters.uwidth or 40)/2 - end - end -end +-- extra generic stuff -otffeatures.register { - name = "itlc", - description = "italic correction", - initializers = { - base = initializeitlc, - node = initializeitlc, - } -} +function fonts.loggers.onetimemessage() end --- slant and extend +-- done elsewhere +-- +-- loadmodule('font-ext-imp-italic.lua') +-- loadmodule('font-ext-imp-effect.lua') +-- loadmodule('luatex-fonts-lig.lua') -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.slantfactor = value -end +-- protrusion (simplified version) -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.extendfactor = value -end +fonts.protrusions = fonts.protrusions or { } +fonts.protrusions.setups = fonts.protrusions.setups or { } +local setups = fonts.protrusions.setups -otffeatures.register { - name = "extend", - description = "scale glyphs horizontally", - initializers = { - base = initializeextend, - node = initializeextend, - } -} +setups['default'] = { -- demo vector --- expansion and protrusion + factor = 1, + left = 1, + right = 1, -fonts.protrusions = fonts.protrusions or { } -fonts.protrusions.setups = fonts.protrusions.setups or { } + [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 ۔ -local setups = fonts.protrusions.setups +} local function initializeprotrusion(tfmdata,value) if value then @@ -112,7 +78,7 @@ local function initializeprotrusion(tfmdata,value) end end -otffeatures.register { +local specification = { name = "protrusion", description = "shift characters into the left and or right margin", initializers = { @@ -121,10 +87,32 @@ otffeatures.register { } } -fonts.expansions = fonts.expansions or { } -fonts.expansions.setups = fonts.expansions.setups or { } +registerotffeature(specification) +registerafmfeature(specification) -local setups = fonts.expansions.setups +-- expansion (simplified version) + +fonts.expansions = fonts.expansions or { } +fonts.expansions.setups = fonts.expansions.setups or { } +local setups = fonts.expansions.setups + +setups['default'] = { -- demo vector + + 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, +} local function initializeexpansion(tfmdata,value) if value then @@ -149,7 +137,7 @@ local function initializeexpansion(tfmdata,value) end end -otffeatures.register { +local specification = { name = "expansion", description = "apply hz optimization", initializers = { @@ -158,51 +146,12 @@ otffeatures.register { } } --- left over - -function fonts.loggers.onetimemessage() end - --- example vectors - -local byte = string.byte +registerotffeature(specification) +registerafmfeature(specification) -fonts.expansions.setups['default'] = { +-- normalizer (generic only) - 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) +otf.features.normalize = function(t) if t.rand then t.rand = "random" end @@ -230,6 +179,8 @@ end -- [110] = 109, -- n -- } +-- reencoding (generic only) + fonts.encodings = fonts.encodings or { } local reencodings = { } fonts.encodings.reencodings = reencodings @@ -254,7 +205,7 @@ local function specialreencode(tfmdata,value) end end -local function reencode(tfmdata,value) +local function initialize(tfmdata,value) tfmdata.postprocessors = tfmdata.postprocessors or { } table.insert(tfmdata.postprocessors, function(tfmdata) @@ -263,65 +214,28 @@ local function reencode(tfmdata,value) ) end -otffeatures.register { +registerotffeature { name = "reencode", description = "reencode characters", manipulators = { - base = reencode, - node = reencode, + base = initialize, + node = initialize, } } -local function ignore(tfmdata,key,value) +-- math stuff (generic only) + +local function initialize(tfmdata,key,value) if value then tfmdata.mathparameters = nil end end -otffeatures.register { +registerotffeature { name = "ignoremathconstants", description = "ignore math constants table", initializers = { - base = ignore, - node = ignore, - } -} - -local setmetatableindex = table.setmetatableindex - -local function additalictowidth(tfmdata,key,value) - local characters = tfmdata.characters - local additions = { } - for unicode, old_c in next, characters do - -- maybe check for math - local oldwidth = old_c.width - local olditalic = old_c.italic - if olditalic and olditalic ~= 0 then - local private = getprivate(tfmdata) - local new_c = { - width = oldwidth + olditalic, - height = old_c.height, - depth = old_c.depth, - commands = { - { "slot", 1, private }, - { "right", olditalic }, - }, - } - setmetatableindex(new_c,old_c) - characters[unicode] = new_c - additions[private] = old_c - end - end - for k, v in next, additions do - characters[k] = v - end -end - -otffeatures.register { - name = "italicwidths", - description = "add italic to width", - manipulators = { - base = additalictowidth, - -- node = additalictowidth, -- only makes sense for math + base = initialize, + node = initialize, } } diff --git a/tex/generic/context/luatex/luatex-fonts-lig.lua b/tex/generic/context/luatex/luatex-fonts-lig.lua index c5347aa19..4ce126533 100644 --- a/tex/generic/context/luatex/luatex-fonts-lig.lua +++ b/tex/generic/context/luatex/luatex-fonts-lig.lua @@ -2064,4 +2064,4 @@ fonts.handlers.otf.addfeature { ["name"]="collapse", ["prepend"]=true, ["type"]="ligature", -} \ No newline at end of file +} diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index 203ae5bf6..2362be049 100644 --- a/tex/generic/context/luatex/luatex-fonts-merged.lua +++ b/tex/generic/context/luatex/luatex-fonts-merged.lua @@ -1,6 +1,6 @@ -- merged file : c:/data/develop/context/sources/luatex-fonts-merged.lua -- parent file : c:/data/develop/context/sources/luatex-fonts.lua --- merge date : 04/03/18 22:22:05 +-- merge date : 04/13/18 14:53:48 do -- begin closure to overcome local limits and interference @@ -760,7 +760,7 @@ local function make2(t,rest) end return p end -function lpeg.utfchartabletopattern(list,insensitive) +local function utfchartabletopattern(list,insensitive) local tree={} local n=#list if n==0 then @@ -833,6 +833,13 @@ function lpeg.utfchartabletopattern(list,insensitive) end return (insensitive and make2 or make1)(tree) end +lpeg.utfchartabletopattern=utfchartabletopattern +function lpeg.utfreplacer(list,insensitive) + local pattern=Cs((utfchartabletopattern(list,insensitive)/list+utf8character)^0) + return function(str) + return lpegmatch(pattern,str) or str + end +end patterns.containseol=lpeg.finder(eol) local function nextstep(n,step,result) local m=n%step @@ -927,6 +934,21 @@ function string.tobytes(s) return lpegmatch(hextobytes,s) end end +local patterns={} +local function containsws(what) + local p=patterns[what] + if not p then + local p1=P(what)*(whitespace+P(-1))*Cc(true) + local p2=whitespace*P(p1) + p=P(p1)+P(1-p2)^0*p2+Cc(false) + patterns[what]=p + end + return p +end +lpeg.containsws=containsws +function string.containsws(str,what) + return lpegmatch(patterns[what] or containsws(what),str) +end end -- closure @@ -1986,7 +2008,7 @@ function table.reverse(t) return t end end -function table.sequenced(t,sep,simple) +local function sequenced(t,sep,simple) if not t then return "" end @@ -2005,16 +2027,25 @@ function table.sequenced(t,sep,simple) s[n]=k elseif v and v~="" then n=n+1 - s[n]=k.."="..tostring(v) + if type(v)=="table" then + s[n]=k.."={"..sequenced(v,sep,simple).."}" + else + s[n]=k.."="..tostring(v) + end end else n=n+1 - s[n]=k.."="..tostring(v) + if type(v)=="table" then + s[n]=k.."={"..sequenced(v,sep,simple).."}" + else + s[n]=k.."="..tostring(v) + end end end end return concat(s,sep or " | ") end +table.sequenced=sequenced function table.print(t,...) if type(t)~="table" then print(tostring(t)) @@ -2503,24 +2534,22 @@ local lpegmatch=lpeg.match local getcurrentdir,attributes=lfs.currentdir,lfs.attributes local checkedsplit=string.checkedsplit local P,R,S,C,Cs,Cp,Cc,Ct=lpeg.P,lpeg.R,lpeg.S,lpeg.C,lpeg.Cs,lpeg.Cp,lpeg.Cc,lpeg.Ct -local tricky=S("/\\")*P(-1) local attributes=lfs.attributes -if sandbox then - sandbox.redefine(lfs.isfile,"lfs.isfile") - sandbox.redefine(lfs.isdir,"lfs.isdir") -end function lfs.isdir(name) - if lpegmatch(tricky,name) then - return attributes(name,"mode")=="directory" - else - return attributes(name.."/.","mode")=="directory" - end + return attributes(name,"mode")=="directory" end function lfs.isfile(name) - return attributes(name,"mode")=="file" + local a=attributes(name,"mode") + return a=="file" or a=="link" or nil end function lfs.isfound(name) - return attributes(name,"mode")=="file" and name or nil + local a=attributes(name,"mode") + return (a=="file" or a=="link") and name or nil +end +if sandbox then + sandbox.redefine(lfs.isfile,"lfs.isfile") + sandbox.redefine(lfs.isdir,"lfs.isdir") + sandbox.redefine(lfs.isfound,"lfs.isfound") end local colon=P(":") local period=P(".") @@ -2877,6 +2906,10 @@ function file.withinbase(path) end return true end +local symlinkattributes=lfs.symlinkattributes +function lfs.readlink(name) + return symlinkattributes(name,"target") or nil +end end -- closure @@ -4816,13 +4849,17 @@ if context then texio.write_nl("fatal error: this module is not for context") os.exit() end +local match,gmatch,gsub,lower=string.match,string.gmatch,string.gsub,string.lower +local formatters,split,format,dump=string.formatters,string.split,string.format,string.dump +local loadfile,type=loadfile,type +local setmetatable,getmetatable,collectgarbage=setmetatable,getmetatable,collectgarbage local dummyfunction=function() end local dummyreporter=function(c) return function(f,...) local r=texio.reporter or texio.write_nl if f then - r(c.." : "..string.formatters(f,...)) + r(c.." : "..formatters(f,...)) else r("") end @@ -4864,7 +4901,8 @@ callbacks={ return callback.register(n,f) end, } -utilities=utilities or {} utilities.storage={ +utilities=utilities or {} +utilities.storage=utilities.storage or { allocate=function(t) return t or {} end, @@ -4872,6 +4910,25 @@ utilities=utilities or {} utilities.storage={ return t or {} end, } +utilities.parsers=utilities.parsers or { + settings_to_array=function(s) + return split(s,",") + end, + settings_to_hash=function(s) + local t={} + for k,v in gmatch(s,"([^%s,=]+)=([^%s,]+)") do + t[k]=v + end + return t + end, + settings_to_hash_colon_too=function(s) + local t={} + for k,v in gmatch(s,"([^%s,=:]+)[=:]([^%s,]+)") do + t[k]=v + end + return t + end, +} characters=characters or { data={} } @@ -4888,14 +4945,14 @@ local remapper={ enc="enc files", } function resolvers.findfile(name,fileformat) - name=string.gsub(name,"\\","/") + name=gsub(name,"\\","/") if not fileformat or fileformat=="" then fileformat=file.suffix(name) if fileformat=="" then fileformat="tex" end end - fileformat=string.lower(fileformat) + fileformat=lower(fileformat) fileformat=remapper[fileformat] or fileformat local found=kpse.find_file(name,fileformat) if not found or found=="" then @@ -4941,13 +4998,13 @@ do if cachepaths=="" then cachepaths="." end - cachepaths=string.split(cachepaths,os.type=="windows" and ";" or ":") + cachepaths=split(cachepaths,os.type=="windows" and ";" or ":") for i=1,#cachepaths do local cachepath=cachepaths[i] if not lfs.isdir(cachepath) then lfs.mkdirs(cachepath) if lfs.isdir(cachepath) then - texio.write(string.format("(created cache path: %s)",cachepath)) + texio.write(format("(created cache path: %s)",cachepath)) end end if file.is_writable(cachepath) then @@ -4970,10 +5027,10 @@ do texio.write_nl("quiting: fix your readable cache path") os.exit() elseif #readables==1 and readables[1]==writable then - texio.write(string.format("(using cache: %s)",writable)) + texio.write(format("(using cache: %s)",writable)) else - texio.write(string.format("(using write cache: %s)",writable)) - texio.write(string.format("(using read cache: %s)",table.concat(readables," "))) + texio.write(format("(using write cache: %s)",writable)) + texio.write(format("(using read cache: %s)",table.concat(readables," "))) end end function caches.getwritablepath(category,subcategory) @@ -5005,27 +5062,27 @@ function caches.loaddata(readables,name,writable) local loader=false local luaname,lucname=makefullname(path,name) if lfs.isfile(lucname) then - texio.write(string.format("(load luc: %s)",lucname)) + texio.write(format("(load luc: %s)",lucname)) loader=loadfile(lucname) end if not loader and lfs.isfile(luaname) then local luacrap,lucname=makefullname(writable,name) - texio.write(string.format("(compiling luc: %s)",lucname)) + texio.write(format("(compiling luc: %s)",lucname)) if lfs.isfile(lucname) then loader=loadfile(lucname) end caches.compile(data,luaname,lucname) if lfs.isfile(lucname) then - texio.write(string.format("(load luc: %s)",lucname)) + texio.write(format("(load luc: %s)",lucname)) loader=loadfile(lucname) else - texio.write(string.format("(loading failed: %s)",lucname)) + texio.write(format("(loading failed: %s)",lucname)) end if not loader then - texio.write(string.format("(load lua: %s)",luaname)) + texio.write(format("(load lua: %s)",luaname)) loader=loadfile(luaname) else - texio.write(string.format("(loading failed: %s)",luaname)) + texio.write(format("(loading failed: %s)",luaname)) end end if loader then @@ -5039,11 +5096,11 @@ end function caches.savedata(path,name,data) local luaname,lucname=makefullname(path,name) if luaname then - texio.write(string.format("(save: %s)",luaname)) + texio.write(format("(save: %s)",luaname)) table.tofile(luaname,data,true) if lucname and type(caches.compile)=="function" then os.remove(lucname) - texio.write(string.format("(save: %s)",lucname)) + texio.write(format("(save: %s)",lucname)) caches.compile(data,luaname,lucname) end end @@ -5058,7 +5115,7 @@ function caches.compile(data,luaname,lucname) if f then local s=loadstring(d) if s then - f:write(string.dump(s,true)) + f:write(dump(s,true)) end f:close() end @@ -5079,10 +5136,19 @@ function table.setmetatableindex(t,f) end return t end +function table.makeweak(t) + local m=getmetatable(t) + if m then + m.__mode="v" + else + setmetatable(t,{ __mode="v" }) + end + return t +end arguments={} if arg then for i=1,#arg do - local k,v=string.match(arg[i],"^%-%-([^=]+)=?(.-)$") + local k,v=match(arg[i],"^%-%-([^=]+)=?(.-)$") if k and v then arguments[k]=v end @@ -8977,6 +9043,22 @@ function constructors.getprivate(tfmdata) properties.private=private+1 return private end +function constructors.setmathparameter(tfmdata,name,value) + local m=tfmdata.mathparameters + local c=tfmdata.MathConstants + if m then + m[name]=value + end + if c and c~=m then + c[name]=value + end +end +function constructors.getmathparameter(tfmdata,name) + local p=tfmdata.mathparameters or tfmdata.MathConstants + if p then + return p[name] + end +end function constructors.cleanuptable(tfmdata) if constructors.autocleanup and tfmdata.properties.virtualized then for k,v in next,tfmdata.characters do @@ -9233,18 +9315,25 @@ function constructors.scale(tfmdata,specification) target.shrink=expansion.shrink target.step=expansion.step end + local slantfactor=parameters.slantfactor or 0 + if slantfactor~=0 then + target.slant=slantfactor*1000 + else + target.slant=0 + end local extendfactor=parameters.extendfactor or 0 if extendfactor~=0 and extendfactor~=1 then hdelta=hdelta*extendfactor - target.extend=extendfactor*1000 + target.extend=extendfactor*1000 else target.extend=1000 end - local slantfactor=parameters.slantfactor or 0 - if slantfactor~=0 then - target.slant=slantfactor*1000 + local squeezefactor=parameters.squeezefactor or 0 + if squeezefactor~=0 and squeezefactor~=1 then + vdelta=vdelta*squeezefactor + target.squeeze=squeezefactor*1000 else - target.slant=0 + target.squeeze=1000 end local mode=parameters.mode or 0 if mode~=0 then @@ -9252,7 +9341,7 @@ function constructors.scale(tfmdata,specification) end local width=parameters.width or 0 if width~=0 then - target.width=width + target.width=width*delta*1000/655360 end targetparameters.factor=delta targetparameters.hfactor=hdelta @@ -9642,11 +9731,14 @@ function constructors.finalize(tfmdata) if not parameters.width then parameters.width=0 end + if not parameters.slantfactor then + parameters.slantfactor=tfmdata.slant or 0 + end if not parameters.extendfactor then parameters.extendfactor=tfmdata.extend or 0 end - if not parameters.slantfactor then - parameters.slantfactor=tfmdata.slant or 0 + if not parameters.squeezefactor then + parameters.squeezefactor=tfmdata.squeeze or 0 end local designsize=parameters.designsize if designsize then @@ -9722,8 +9814,9 @@ function constructors.finalize(tfmdata) tfmdata.stretch=nil tfmdata.shrink=nil tfmdata.step=nil - tfmdata.extend=nil tfmdata.slant=nil + tfmdata.extend=nil + tfmdata.squeeze=nil tfmdata.mode=nil tfmdata.width=nil tfmdata.units=nil @@ -9764,7 +9857,17 @@ hashmethods.normal=function(list) elseif k=="number" or k=="features" then else n=n+1 - s[n]=k..'='..tostring(v) + if type(v)=="table" then + local t={} + local m=0 + for k,v in next,v do + m=m+1 + t[m]=k..'='..tostring(v) + end + s[n]=k..'={'..concat(t,",").."}" + else + s[n]=k..'='..tostring(v) + end end end if n>0 then @@ -10501,26 +10604,34 @@ local function tounicode16sequence(unicodes) end return concat(t) end -local function tounicode(unicode) +local unknown=f_single(0xFFFD) +local hash=table.setmetatableindex(function(t,k) + local v + if k>=0x00E000 and k<=0x00F8FF then + v=unknown + elseif k>=0x0F0000 and k<=0x0FFFFF then + v=unknown + elseif k>=0x100000 and k<=0x10FFFF then + v=unknown + elseif k<0xD7FF or (k>0xDFFF and k<=0xFFFF) then + v=f_single(k) + else + v=k-0x10000 + v=f_double(rshift(k,10)+0xD800,k%1024+0xDC00) + end + t[k]=v + return v +end) +table.makeweak(hash) +local function tounicode(unicode,name) if type(unicode)=="table" then local t={} for l=1,#unicode do - local u=unicode[l] - if u<0xD7FF or (u>0xDFFF and u<=0xFFFF) then - t[l]=f_single(u) - else - u=u-0x10000 - t[l]=f_double(rshift(u,10)+0xD800,u%1024+0xDC00) - end + t[l]=hash[unicode[l]] end return concat(t) else - if unicode<0xD7FF or (unicode>0xDFFF and unicode<=0xFFFF) then - return f_single(unicode) - else - unicode=unicode-0x10000 - return f_double(rshift(unicode,10)+0xD800,unicode%1024+0xDC00) - end + return hash[unicode] end end local function fromunicode16(str) @@ -10889,6 +11000,84 @@ end -- closure do -- begin closure to overcome local limits and interference +if not modules then modules={} end modules ['font-vfc']={ + version=1.001, + comment="companion to font-ini.mkiv and hand-ini.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" +} +local select=select +local insert=table.insert +local fonts=fonts +local helpers=fonts.helpers +local setmetatableindex=table.setmetatableindex +local makeweak=table.makeweak +local push={ "push" } +local pop={ "pop" } +local dummy={ "comment" } +function helpers.prependcommands(commands,...) + insert(commands,1,push) + for i=select("#",...),1,-1 do + local s=select(i,...) + if s then + insert(commands,1,s) + end + end + insert(commands,pop) + return commands +end +function helpers.appendcommands(commands,...) + insert(commands,1,push) + insert(commands,pop) + for i=1,select("#",...) do + local s=select(i,...) + if s then + insert(commands,s) + end + end + return commands +end +local char=setmetatableindex(function(t,k) + local v={ "char",k } + t[k]=v + return v +end) +local right=setmetatableindex(function(t,k) + local v={ "right",k } + t[k]=v + return v +end) +local left=setmetatableindex(function(t,k) + local v={ "right",-k } + t[k]=v + return v +end) +local down=setmetatableindex(function(t,k) + local v={ "down",k } + t[k]=v + return v +end) +local up=setmetatableindex(function(t,k) + local v={ "down",-k } + t[k]=v + return v +end) +helpers.commands=utilities.storage.allocate { + char=char, + right=right, + left=left, + down=down, + up=up, + push=push, + pop=pop, + dummy=dummy, +} + +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", @@ -15753,7 +15942,7 @@ local reversed=table.reversed local sort=table.sort local insert=table.insert local round=math.round -local lpegmatch=lpeg.match +local settings_to_hash_colon_too=table.settings_to_hash_colon_too local setmetatableindex=table.setmetatableindex local formatters=string.formatters local sortedkeys=table.sortedkeys @@ -15893,18 +16082,15 @@ local lookupflags=setmetatableindex(function(t,k) t[k]=v return v end) -local pattern=lpeg.Cf ( - lpeg.Ct("")*lpeg.Cg ( - lpeg.C((lpeg.R("az","09")+lpeg.P(" "))^1)*lpeg.S(" :=")*(lpeg.patterns.number/tonumber)*lpeg.S(" ,")^0 - )^1,rawset -) -local hash=table.setmetatableindex(function(t,k) - local v=lpegmatch(pattern,k) - local t={} - for k,v in sortedhash(v) do - t[#t+1]=k.."="..v +local function axistofactors(str) + local t=settings_to_hash_colon_too(str) + for k,v in next,t do + t[k]=tonumber(v) or v end - v=concat(t,",") + return t +end +local hash=table.setmetatableindex(function(t,k) + local v=sequenced(axistofactors(k),",") t[k]=v return v end) @@ -15917,7 +16103,7 @@ function helpers.normalizedaxis(str) return hash[str] or str end local function axistofactors(str) - return lpegmatch(pattern,str) + return settings_to_hash_colon_too(str) end local function getaxisscale(segments,minimum,default,maximum,user) if not minimum or not default or not maximum then @@ -22373,6 +22559,8 @@ do if not fontkern then setkern(n,k) return n end +end end +do if not italickern then local thekern=nuts.new("kern",3) local setkern=nuts.setkern local copy_node=nuts.copy_node @@ -29670,6 +29858,11 @@ local sortedkeys,sortedhash=table.sortedkeys,table.sortedhash local setmetatableindex=table.setmetatableindex local formatters=string.formatters local tounicode=fonts.mappings.tounicode +local helpers=fonts.helpers +local charcommand=helpers.commands.char +local rightcommand=helpers.commands.right +local leftcommand=helpers.commands.left +local downcommand=helpers.commands.down local otf=fonts.handlers.otf local f_color=formatters["%.3f %.3f %.3f rg"] local f_gray=formatters["%.3f g"] @@ -29758,7 +29951,7 @@ local pop={ "pdf","page","Q" } if not LUATEXFUNCTIONALITY or LUATEXFUNCTIONALITY<6472 then start={ "nop" } end -local function initializecolr(tfmdata,kind,value) +local function initialize(tfmdata,kind,value) if value then local resources=tfmdata.resources local palettes=resources.colorpalettes @@ -29780,21 +29973,11 @@ local function initializecolr(tfmdata,kind,value) tfmdata.fonts={ { id=0 } } - local widths=setmetatableindex(function(t,k) - local v={ "right",-k } - t[k]=v - return v - end) local getactualtext=otf.getactualtext local default=colorvalues[#colorvalues] local b,e=getactualtext(tounicode(0xFFFD)) local actualb={ "pdf","page",b } local actuale={ "pdf","page",e } - local cache=setmetatableindex(function(t,k) - local v={ "char",k } - t[k]=v - return v - end) for unicode,character in next,characters do local description=descriptions[unicode] if description then @@ -29803,7 +29986,7 @@ local function initializecolr(tfmdata,kind,value) local u=description.unicode or characters[unicode].unicode local w=character.width or 0 local s=#colorlist - local goback=w~=0 and widths[w] or nil + local goback=w~=0 and leftcommand[w] or nil local t={ start, not u and actualb or { "pdf","page",(getactualtext(tounicode(u))) } @@ -29823,7 +30006,7 @@ local function initializecolr(tfmdata,kind,value) n=n+1 t[n]=v l=v end - n=n+1 t[n]=cache[entry.slot] + n=n+1 t[n]=charcommand[entry.slot] if s>1 and i1 then - local one=current[1] - local two=current[2] - lookups[one]={ one,zwjchar } - local one={ one } - local two={ two } - local new=#protect+1 - protect[new]={ - before=before, - current={ one,two }, - after=after, - lookups={ 1 }, - } - revert[new]={ - current={ one,zwj }, - after={ two }, - lookups={ 1 }, - } - end - end -end -otf.helpers.blockligatures=blockligatures -if context then - interfaces.implement { - name="blockligatures", - arguments="string", - actions=blockligatures, - } -end end -- closure @@ -32296,6 +32287,7 @@ local findbinfile=resolvers.findbinfile local setmetatableindex=table.setmetatableindex local fonts=fonts local handlers=fonts.handlers +local helpers=fonts.helpers local readers=fonts.readers local constructors=fonts.constructors local encodings=fonts.encodings @@ -32309,6 +32301,7 @@ local tfmfeatures=constructors.features.tfm local registertfmfeature=tfmfeatures.register local tfmenhancers=constructors.enhancers.tfm local registertfmenhancer=tfmenhancers.register +local charcommand=helpers.commands.char constructors.resolvevirtualtoo=false fonts.formats.tfm="type1" fonts.formats.ofm="type1" @@ -32572,7 +32565,7 @@ do if backmap then original.index=backmap[name] else - original.commands={ parentfont,{ "char",index } } + original.commands={ parentfont,charcommand[index] } original.oindex=index end done[name]=true @@ -33327,70 +33320,34 @@ if context then texio.write_nl("fatal error: this module is not for context") os.exit() end +local byte=string.byte local fonts=fonts -local otffeatures=fonts.constructors.features.otf -local getprivate=fonts.constructors.getprivate -local function initializeitlc(tfmdata,value) - if value then - local parameters=tfmdata.parameters - local italicangle=parameters.italicangle - if italicangle and italicangle~=0 then - local properties=tfmdata.properties - local factor=tonumber(value) or 1 - properties.hasitalics=true - properties.autoitalicamount=factor*(parameters.uwidth or 40)/2 - end - end -end -otffeatures.register { - name="itlc", - description="italic correction", - initializers={ - base=initializeitlc, - node=initializeitlc, - } -} -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.slantfactor=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.extendfactor=value -end -otffeatures.register { - name="extend", - description="scale glyphs horizontally", - initializers={ - base=initializeextend, - node=initializeextend, - } -} +local handlers=fonts.handlers +local otf=handlers.otf +local afm=handlers.afm +local registerotffeature=otf.features.register +local registerafmfeature=afm.features.register +function fonts.loggers.onetimemessage() end fonts.protrusions=fonts.protrusions or {} fonts.protrusions.setups=fonts.protrusions.setups or {} local setups=fonts.protrusions.setups +setups['default']={ + factor=1, + left=1, + right=1, + [0x002C]={ 0,1 }, + [0x002E]={ 0,1 }, + [0x003A]={ 0,1 }, + [0x003B]={ 0,1 }, + [0x002D]={ 0,1 }, + [0x2013]={ 0,0.50 }, + [0x2014]={ 0,0.33 }, + [0x3001]={ 0,1 }, + [0x3002]={ 0,1 }, + [0x060C]={ 0,1 }, + [0x061B]={ 0,1 }, + [0x06D4]={ 0,1 }, +} local function initializeprotrusion(tfmdata,value) if value then local setup=setups[value] @@ -33411,7 +33368,7 @@ local function initializeprotrusion(tfmdata,value) end end end -otffeatures.register { +local specification={ name="protrusion", description="shift characters into the left and or right margin", initializers={ @@ -33419,9 +33376,26 @@ otffeatures.register { node=initializeprotrusion, } } +registerotffeature(specification) +registerafmfeature(specification) fonts.expansions=fonts.expansions or {} fonts.expansions.setups=fonts.expansions.setups or {} local setups=fonts.expansions.setups +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, +} local function initializeexpansion(tfmdata,value) if value then local setup=setups[value] @@ -33444,7 +33418,7 @@ local function initializeexpansion(tfmdata,value) end end end -otffeatures.register { +local specification={ name="expansion", description="apply hz optimization", initializers={ @@ -33452,36 +33426,9 @@ otffeatures.register { node=initializeexpansion, } } -function fonts.loggers.onetimemessage() end -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 }, - [0x002E]={ 0,1 }, - [0x003A]={ 0,1 }, - [0x003B]={ 0,1 }, - [0x002D]={ 0,1 }, - [0x2013]={ 0,0.50 }, - [0x2014]={ 0,0.33 }, - [0x3001]={ 0,1 }, - [0x3002]={ 0,1 }, - [0x060C]={ 0,1 }, - [0x061B]={ 0,1 }, - [0x06D4]={ 0,1 }, -} -fonts.handlers.otf.features.normalize=function(t) +registerotffeature(specification) +registerafmfeature(specification) +otf.features.normalize=function(t) if t.rand then t.rand="random" end @@ -33515,7 +33462,7 @@ local function specialreencode(tfmdata,value) return string.format("reencoded:%s",value) end end -local function reencode(tfmdata,value) +local function initialize(tfmdata,value) tfmdata.postprocessors=tfmdata.postprocessors or {} table.insert(tfmdata.postprocessors, function(tfmdata) @@ -33523,61 +33470,710 @@ local function reencode(tfmdata,value) end ) end -otffeatures.register { +registerotffeature { name="reencode", description="reencode characters", manipulators={ - base=reencode, - node=reencode, + base=initialize, + node=initialize, } } -local function ignore(tfmdata,key,value) +local function initialize(tfmdata,key,value) if value then tfmdata.mathparameters=nil end end -otffeatures.register { +registerotffeature { name="ignoremathconstants", description="ignore math constants table", initializers={ - base=ignore, - node=ignore, + base=initialize, + node=initialize, } } -local setmetatableindex=table.setmetatableindex -local function additalictowidth(tfmdata,key,value) - local characters=tfmdata.characters - local additions={} - for unicode,old_c in next,characters do - local oldwidth=old_c.width - local olditalic=old_c.italic - if olditalic and olditalic~=0 then - local private=getprivate(tfmdata) - local new_c={ - width=oldwidth+olditalic, - height=old_c.height, - depth=old_c.depth, - commands={ - { "slot",1,private }, - { "right",olditalic }, - }, + +end -- closure + +do -- begin closure to overcome local limits and interference + +if not modules then modules={} end modules ['font-imp-tex']={ + 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 next=next +local fonts=fonts +local otf=fonts.handlers.otf +local registerotffeature=otf.features.register +local addotffeature=otf.addfeature +local specification={ + type="ligature", + order={ "tlig" }, + prepend=true, + data={ + [0x2013]={ 0x002D,0x002D }, + [0x2014]={ 0x002D,0x002D,0x002D }, + }, +} +addotffeature("tlig",specification) +registerotffeature { + name="tlig", + description="tex ligatures", +} +local specification={ + type="substitution", + order={ "trep" }, + prepend=true, + data={ + [0x0027]=0x2019, + }, +} +addotffeature("trep",specification) +registerotffeature { + name="trep", + description="tex replacements", +} +local anum_arabic={ + [0x0030]=0x0660, + [0x0031]=0x0661, + [0x0032]=0x0662, + [0x0033]=0x0663, + [0x0034]=0x0664, + [0x0035]=0x0665, + [0x0036]=0x0666, + [0x0037]=0x0667, + [0x0038]=0x0668, + [0x0039]=0x0669, +} +local anum_persian={ + [0x0030]=0x06F0, + [0x0031]=0x06F1, + [0x0032]=0x06F2, + [0x0033]=0x06F3, + [0x0034]=0x06F4, + [0x0035]=0x06F5, + [0x0036]=0x06F6, + [0x0037]=0x06F7, + [0x0038]=0x06F8, + [0x0039]=0x06F9, +} +local function valid(data) + local features=data.resources.features + if features then + for k,v in next,features do + for k,v in next,v do + if v.arab then + return true + end + end + end + end +end +local specification={ + { + type="substitution", + features={ arab={ urd=true,dflt=true } }, + order={ "anum" }, + data=anum_arabic, + valid=valid, + }, + { + type="substitution", + features={ arab={ urd=true } }, + order={ "anum" }, + data=anum_persian, + valid=valid, + }, +} +addotffeature("anum",specification) +registerotffeature { + name="anum", + description="arabic digits", +} + +end -- closure + +do -- begin closure to overcome local limits and interference + +if not modules then modules={} end modules ['font-imp-ligatures']={ + 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 lpegmatch=lpeg.match +local utfsplit=utf.split +local settings_to_array=utilities.parsers.settings_to_array +local fonts=fonts +local otf=fonts.handlers.otf +local registerotffeature=otf.features.register +local addotffeature=otf.addfeature +local lookups={} +local protect={} +local revert={} +local zwjchar=0x200C +local zwj={ zwjchar } +addotffeature { + name="blockligatures", + type="chainsubstitution", + nocheck=true, + prepend=true, + future=true, + lookups={ + { + type="multiple", + data=lookups, + }, + }, + data={ + rules=protect, + } +} +addotffeature { + name="blockligatures", + type="chainsubstitution", + nocheck=true, + append=true, + overload=false, + lookups={ + { + type="ligature", + data=lookups, + }, + }, + data={ + rules=revert, + } +} +registerotffeature { + name='blockligatures', + description='block certain ligatures', +} +local splitter=lpeg.splitat(":") +local function blockligatures(str) + local t=settings_to_array(str) + for i=1,#t do + local ti=t[i] + local before,current,after=lpegmatch(splitter,ti) + if current and after then + if before then + before=utfsplit(before) + for i=1,#before do + before[i]={ before[i] } + end + end + if current then + current=utfsplit(current) + end + if after then + after=utfsplit(after) + for i=1,#after do + after[i]={ after[i] } + end + end + else + before=nil + current=utfsplit(ti) + after=nil + end + if #current>1 then + local one=current[1] + local two=current[2] + lookups[one]={ one,zwjchar } + local one={ one } + local two={ two } + local new=#protect+1 + protect[new]={ + before=before, + current={ one,two }, + after=after, + lookups={ 1 }, + } + revert[new]={ + current={ one,zwj }, + after={ two }, + lookups={ 1 }, } - setmetatableindex(new_c,old_c) - characters[unicode]=new_c - additions[private]=old_c end end - for k,v in next,additions do - characters[k]=v +end +otf.helpers.blockligatures=blockligatures +if context then + interfaces.implement { + name="blockligatures", + arguments="string", + actions=blockligatures, + } +end + +end -- closure + +do -- begin closure to overcome local limits and interference + +if not modules then modules={} end modules ['font-imp-italics']={ + version=1.001, + comment="companion to font-ini.mkiv and hand-ini.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" +} +local next=next +local fonts=fonts +local handlers=fonts.handlers +local registerotffeature=handlers.otf.features.register +local registerafmfeature=handlers.afm.features.register +local function initialize(tfmdata,key,value) + for unicode,character in next,tfmdata.characters do + local olditalic=character.italic + if olditalic and olditalic~=0 then + character.width=character.width+olditalic + character.italic=0 + end end end -otffeatures.register { +local specification={ name="italicwidths", description="add italic to width", manipulators={ - base=additalictowidth, + base=initialize, + node=initialize, + } +} +registerotffeature(specification) +registerafmfeature(specification) +local function initialize(tfmdata,value) + if value then + local parameters=tfmdata.parameters + local italicangle=parameters.italicangle + if italicangle and italicangle~=0 then + local properties=tfmdata.properties + local factor=tonumber(value) or 1 + properties.hasitalics=true + properties.autoitalicamount=factor*(parameters.uwidth or 40)/2 + end + end +end +local specification={ + name="itlc", + description="italic correction", + initializers={ + base=initialize, + node=initialize, + } +} +registerotffeature(specification) +registerafmfeature(specification) +if context then + local function initialize(tfmdata,value) + tfmdata.properties.textitalics=toboolean(value) + end + local specification={ + name="textitalics", + description="use alternative text italic correction", + initializers={ + base=initialize, + node=initialize, + } + } + registerotffeature(specification) + registerafmfeature(specification) +end +if context then +end +if context then + local letter=characters.is_letter + local always=true + local function collapseitalics(tfmdata,key,value) + local threshold=value==true and 100 or tonumber(value) + if threshold and threshold>0 then + if threshold>100 then + threshold=100 + end + for unicode,data in next,tfmdata.characters do + if always or letter[unicode] or letter[data.unicode] then + local italic=data.italic + if italic and italic~=0 then + local width=data.width + if width and width~=0 then + local delta=threshold*italic/100 + data.width=width+delta + data.italic=italic-delta + end + end + end + end + end + end + local dimensions_specification={ + name="collapseitalics", + description="collapse italics", + manipulators={ + base=collapseitalics, + node=collapseitalics, + } + } + registerotffeature(dimensions_specification) + registerafmfeature(dimensions_specification) +end + +end -- closure + +do -- begin closure to overcome local limits and interference + +if not modules then modules={} end modules ['font-imp-effects']={ + version=1.001, + comment="companion to font-ini.mkiv and hand-ini.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" +} +local next,type,tonumber=next,type,tonumber +local is_boolean=string.is_boolean +local fonts=fonts +local handlers=fonts.handlers +local registerotffeature=handlers.otf.features.register +local registerafmfeature=handlers.afm.features.register +local settings_to_hash=utilities.parsers.settings_to_hash_colon_too +local helpers=fonts.helpers +local prependcommands=helpers.prependcommands +local charcommand=helpers.commands.char +local rightcommand=helpers.commands.right +local upcommand=helpers.commands.up +local dummycommand=helpers.commands.dummy +local report_effect=logs.reporter("fonts","effect") +local report_slant=logs.reporter("fonts","slant") +local report_extend=logs.reporter("fonts","extend") +local report_squeeze=logs.reporter("fonts","squeeze") +local trace=false +trackers.register("fonts.effect",function(v) trace=v end) +trackers.register("fonts.slant",function(v) trace=v end) +trackers.register("fonts.extend",function(v) trace=v end) +trackers.register("fonts.squeeze",function(v) trace=v end) +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 + if trace then + report_slant("applying %0.3f",value) + end + tfmdata.parameters.slantfactor=value +end +local specification={ + name="slant", + description="slant glyphs", + initializers={ + base=initializeslant, + node=initializeslant, + } +} +registerotffeature(specification) +registerafmfeature(specification) +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 + if trace then + report_extend("applying %0.3f",value) + end + tfmdata.parameters.extendfactor=value +end +local specification={ + name="extend", + description="scale glyphs horizontally", + initializers={ + base=initializeextend, + node=initializeextend, + } +} +registerotffeature(specification) +registerafmfeature(specification) +local function initializesqueeze(tfmdata,value) + value=tonumber(value) + if not value then + value=0 + elseif value>10 then + value=10 + elseif value<-10 then + value=-10 + end + if trace then + report_squeeze("applying %0.3f",value) + end + tfmdata.parameters.squeezefactor=value +end +local specification={ + name="squeeze", + description="scale glyphs vertically", + initializers={ + base=initializesqueeze, + node=initializesqueeze, + } +} +registerotffeature(specification) +registerafmfeature(specification) +local effects={ + inner=0, + normal=0, + outer=1, + outline=1, + both=2, + hidden=3, +} +local function initializeeffect(tfmdata,value) + local spec + if type(value)=="number" then + spec={ width=value } + else + spec=settings_to_hash(value) + end + local effect=spec.effect or "both" + local width=tonumber(spec.width) or 0 + local mode=effects[effect] + if not mode then + report_effect("invalid effect %a",effect) + elseif width==0 and mode==0 then + report_effect("invalid width %a for effect %a",width,effect) + else + local parameters=tfmdata.parameters + local properties=tfmdata.properties + parameters.mode=mode + parameters.width=width*1000 + if is_boolean(spec.auto)==true then + local squeeze=1-width/20 + local average=(1-squeeze)*width*100 + spec.squeeze=squeeze + spec.extend=1+width/2 + spec.wdelta=average + spec.hdelta=average/2 + spec.ddelta=average/2 + spec.vshift=average/2 + end + local factor=tonumber(spec.factor) or 0 + local hfactor=tonumber(spec.hfactor) or factor + local vfactor=tonumber(spec.vfactor) or factor + local delta=tonumber(spec.delta) or 1 + local wdelta=tonumber(spec.wdelta) or delta + local hdelta=tonumber(spec.hdelta) or delta + local ddelta=tonumber(spec.ddelta) or hdelta + local vshift=tonumber(spec.vshift) or 0 + local slant=spec.slant + local extend=spec.extend + local squeeze=spec.squeeze + if slant then + initializeslant(tfmdata,slant) + end + if extend then + initializeextend(tfmdata,extend) + end + if squeeze then + initializesqueeze(tfmdata,squeeze) + end + properties.effect={ + effect=effect, + width=width, + factor=factor, + hfactor=hfactor, + vfactor=vfactor, + wdelta=wdelta, + hdelta=hdelta, + ddelta=ddelta, + vshift=vshift, + slant=tfmdata.parameters.slantfactor, + extend=tfmdata.parameters.extendfactor, + squeeze=tfmdata.parameters.squeezefactor, + } + end +end +local rules={ + "RadicalRuleThickness", + "OverbarRuleThickness", + "FractionRuleThickness", + "UnderbarRuleThickness", +} +local function setmathparameters(tfmdata,characters,mathparameters,dx,dy,squeeze) + if delta~=0 then + for i=1,#rules do + local name=rules[i] + local value=mathparameters[name] + if value then + mathparameters[name]=(squeeze or 1)*(value+dx) + end + end + end +end +local function setmathcharacters(tfmdata,characters,mathparameters,dx,dy,squeeze,wdelta,hdelta,ddelta) + local function wdpatch(char) + if wsnap~=0 then + char.width=char.width+wdelta/2 + end + end + local function htpatch(char) + if hsnap~=0 then + local height=char.height + if height then + char.height=char.height+2*dy + end + end + end + local character=characters[0x221A] + if character then + local char=character + local next=character.next + wdpatch(char) + htpatch(char) + while next do + char=characters[next] + wdpatch(char) + htpatch(char) + next=char.next + end + if char then + local v=char.vert_variants + if v then + local top=v[#v] + if top then + htpatch(characters[top.glyph]) + end + end + end + end +end +local function manipulateeffect(tfmdata) + local effect=tfmdata.properties.effect + if effect then + local characters=tfmdata.characters + local parameters=tfmdata.parameters + local mathparameters=tfmdata.mathparameters + local multiplier=effect.width*100 + local factor=parameters.factor + local hfactor=parameters.hfactor + local vfactor=parameters.vfactor + local wdelta=effect.wdelta*hfactor*multiplier + local hdelta=effect.hdelta*vfactor*multiplier + local ddelta=effect.ddelta*vfactor*multiplier + local vshift=effect.vshift*vfactor*multiplier + local squeeze=effect.squeeze + local hshift=wdelta + local dx=multiplier*vfactor + local dy=vshift + local factor=(1+effect.factor)*factor + local hfactor=(1+effect.hfactor)*hfactor + local vfactor=(1+effect.vfactor)*vfactor + local vshift=vshift~=0 and upcommand[vshift] or false + for unicode,character in next,characters do + local oldwidth=character.width + local oldheight=character.height + local olddepth=character.depth + if oldwidth and oldwidth>0 then + character.width=oldwidth+wdelta + local commands=character.commands + local hshift=rightcommand[hshift] + if vshift then + if commands then + prependcommands (commands, + hshift, + vshift + ) + else + character.commands={ + hshift, + vshift, + charcommand[unicode] + } + end + else + if commands then + prependcommands (commands, + hshift + ) + else + character.commands={ + hshift, + charcommand[unicode] + } + end + end + end + if oldheight and oldheight>0 then + character.height=oldheight+hdelta + end + if olddepth and olddepth>0 then + character.depth=olddepth+ddelta + end + end + if mathparameters then + setmathparameters(tfmdata,characters,mathparameters,dx,dy,squeeze) + setmathcharacters(tfmdata,characters,mathparameters,dx,dy,squeeze,wdelta,hdelta,ddelta) + end + parameters.factor=factor + parameters.hfactor=hfactor + parameters.vfactor=vfactor + if trace then + report_effect("applying") + report_effect(" effect : %s",effect.effect) + report_effect(" width : %s => %s",effect.width,multiplier) + report_effect(" factor : %s => %s",effect.factor,factor ) + report_effect(" hfactor : %s => %s",effect.hfactor,hfactor) + report_effect(" vfactor : %s => %s",effect.vfactor,vfactor) + report_effect(" wdelta : %s => %s",effect.wdelta,wdelta) + report_effect(" hdelta : %s => %s",effect.hdelta,hdelta) + report_effect(" ddelta : %s => %s",effect.ddelta,ddelta) + end + end +end +local specification={ + name="effect", + description="apply effects to glyphs", + initializers={ + base=initializeeffect, + node=initializeeffect, + }, + manipulators={ + base=manipulateeffect, + node=manipulateeffect, + }, +} +registerotffeature(specification) +registerafmfeature(specification) +local function initializeoutline(tfmdata,value) + value=tonumber(value) + if not value then + value=0 + else + value=tonumber(value) or 0 + end + local parameters=tfmdata.parameters + local properties=tfmdata.properties + parameters.mode=effects.outline + parameters.width=value*1000 + properties.effect={ + effect=effect, + width=width, + } +end +local specification={ + name="outline", + description="outline glyphs", + initializers={ + base=initializeoutline, + node=initializeoutline, } } +registerotffeature(specification) +registerafmfeature(specification) end -- closure @@ -35649,6 +36245,7 @@ fonts.handlers.otf.addfeature { ["prepend"]=true, ["type"]="ligature", } + end -- closure do -- begin closure to overcome local limits and interference diff --git a/tex/generic/context/luatex/luatex-fonts.lua b/tex/generic/context/luatex/luatex-fonts.lua index 5806debd2..b80ea5564 100644 --- a/tex/generic/context/luatex/luatex-fonts.lua +++ b/tex/generic/context/luatex/luatex-fonts.lua @@ -169,13 +169,16 @@ if non_generic_context.luatex_fonts.skip_loading ~= true then else - -- The following helpers are a bit overkill but I don't want to mess up context code for the - -- sake of general generality. Around version 1.0 there will be an official api defined. + -- The following helpers are a bit overkill but I don't want to mess up + -- context code for the sake of general generality. Around version 1.0 + -- there will be an official api defined. -- - -- So, I will strip these libraries and see what is really needed so that we don't have this - -- overhead in the generic modules. The next section is only there for the packager, so stick - -- to using luatex-fonts with luatex-fonts-merged.lua and forget about the rest. The following - -- list might change without prior notice (for instance because we shuffled code around). + -- So, I will strip these libraries and see what is really needed so that + -- we don't have this overhead in the generic modules. The next section + -- is only there for the packager, so stick to using luatex-fonts with + -- luatex-fonts-merged.lua and forget about the rest. The following list + -- might change without prior notice (for instance because we shuffled + -- code around). loadmodule("l-lua.lua") loadmodule("l-lpeg.lua") @@ -193,18 +196,19 @@ if non_generic_context.luatex_fonts.skip_loading ~= true then loadmodule("util-str.lua") loadmodule("util-fil.lua") - -- The following modules contain code that is either not used at all outside context or will - -- fail when enabled due to lack of other modules. + -- The following modules contain code that is either not used at all + -- outside context or will fail when enabled due to lack of other + -- modules. - -- First we load a few helper modules. This is about the miminum 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. + -- First we load a few helper modules. This is about the miminum 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('luatex-basics-gen.lua') loadmodule('data-con.lua') - -- We do need some basic node support. The code in there is not for general use as it might - -- change. + -- We do need some basic node support. The code in there is not for + -- general use as it might change. loadmodule('luatex-basics-nod.lua') @@ -212,25 +216,33 @@ if non_generic_context.luatex_fonts.skip_loading ~= true then loadmodule('luatex-basics-chr.lua') - -- Now come the font modules that deal with traditional tex fonts as well as open type fonts. + -- Now come the font modules that deal with traditional tex fonts as well + -- as open type fonts. -- - -- The font database file (if used at all) must be put someplace visible for kpse and is not - -- shared with context. The mtx-fonts script can be used to generate this file (using the - -- --reload --force --simple option). + -- The font database file (if used at all) must be put someplace visible + -- for kpse and is not shared with context. The mtx-fonts script can be + -- used to generate this file (using the --reload --force --simple option). loadmodule('font-ini.lua') loadmodule('luatex-fonts-mis.lua') loadmodule('font-con.lua') - loadmodule('luatex-fonts-enc.lua') -- will load font-age on demand + loadmodule('luatex-fonts-enc.lua') loadmodule('font-cid.lua') - loadmodule('font-map.lua') -- for loading lum file (will be stripped) + loadmodule('font-map.lua') - -- We use a bit simpler database because using the context one demands loading more helper - -- code and although it is more flexible (more ways to resolve and so) it will never be - -- uses in plain/latex anyway, so let's stick to a simple approach. + -- We use a bit simpler database because using the context one demands + -- loading more helper code and although it is more flexible (more ways + -- to resolve and so) it will never be uses in plain/latex anyway, so + -- let's stick to a simple approach. loadmodule('luatex-fonts-syn.lua') + -- We need some helpers. + + loadmodule('font-vfc.lua') + + -- This is the bulk of opentype code. + loadmodule('font-oti.lua') loadmodule('font-otr.lua') loadmodule('font-cff.lua') @@ -243,29 +255,39 @@ if non_generic_context.luatex_fonts.skip_loading ~= true then loadmodule('font-ota.lua') loadmodule('font-ots.lua') loadmodule('font-osd.lua') - loadmodule('font-ocl.lua') -- svg needs 0.97 (for fix in memstreams) + loadmodule('font-ocl.lua') loadmodule('font-otc.lua') - -- type one code + -- The code for type one fonts. - loadmodule('font-onr.lua') -- was font-afm.lua - loadmodule('font-one.lua') -- was font-afm.lua + loadmodule('font-onr.lua') + loadmodule('font-one.lua') loadmodule('font-afk.lua') - -- traditional code + -- And for traditional TeX fonts. loadmodule('font-tfm.lua') - -- common code + -- Some common code. loadmodule('font-lua.lua') loadmodule('font-def.lua') - loadmodule('font-xtx.lua') -- xetex compatible specifiers (plain/latex only) - loadmodule('luatex-fonts-ext.lua') -- some extensions - loadmodule('luatex-fonts-lig.lua') -- and another one - -- We need to plug into a callback and the following module implements the handlers. Actual - -- plugging in happens later. + -- We support xetex compatible specifiers (plain/latex only). + + loadmodule('font-xtx.lua') + + -- Here come some additional features. + + loadmodule('luatex-fonts-ext.lua') + loadmodule('font-imp-tex.lua') + loadmodule('font-imp-ligatures.lua') + loadmodule('font-imp-italics.lua') + loadmodule('font-imp-effects.lua') + loadmodule('luatex-fonts-lig.lua') + + -- We need to plug into a callback and the following module implements the + -- handlers. Actual plugging in happens later. loadmodule('font-gbn.lua') -- cgit v1.2.3