diff options
Diffstat (limited to 'tex')
213 files changed, 7898 insertions, 5423 deletions
diff --git a/tex/context/base/mkii/cont-new.mkii b/tex/context/base/mkii/cont-new.mkii index 90d6159a1..f08a0cb1c 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{2017.01.27 14:39} +\newcontextversion{2017.02.17 10:17} %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 a1d9a912e..70ca44d90 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{2017.01.27 14:39} +\edef\contextversion{2017.02.17 10:17} %D For those who want to use this: diff --git a/tex/context/base/mkii/mult-cs.mkii b/tex/context/base/mkii/mult-cs.mkii index 9a0247e5f..837a397fb 100644 --- a/tex/context/base/mkii/mult-cs.mkii +++ b/tex/context/base/mkii/mult-cs.mkii @@ -212,6 +212,7 @@ \setinterfacevariable{formulas}{rovnice} \setinterfacevariable{forward}{vpred} \setinterfacevariable{four}{ctyri} +\setinterfacevariable{fractions}{fractions} \setinterfacevariable{frame}{ramecek} \setinterfacevariable{framedtext}{oramovanytext} \setinterfacevariable{friday}{patek} diff --git a/tex/context/base/mkii/mult-de.mkii b/tex/context/base/mkii/mult-de.mkii index 1e9f742ca..ec1fb10f4 100644 --- a/tex/context/base/mkii/mult-de.mkii +++ b/tex/context/base/mkii/mult-de.mkii @@ -212,6 +212,7 @@ \setinterfacevariable{formulas}{formeln} \setinterfacevariable{forward}{vorwaerts} \setinterfacevariable{four}{vier} +\setinterfacevariable{fractions}{fractions} \setinterfacevariable{frame}{rahmen} \setinterfacevariable{framedtext}{umrahmtertext} \setinterfacevariable{friday}{freitag} diff --git a/tex/context/base/mkii/mult-en.mkii b/tex/context/base/mkii/mult-en.mkii index 0af55d772..a4838128b 100644 --- a/tex/context/base/mkii/mult-en.mkii +++ b/tex/context/base/mkii/mult-en.mkii @@ -212,6 +212,7 @@ \setinterfacevariable{formulas}{formulas} \setinterfacevariable{forward}{forward} \setinterfacevariable{four}{four} +\setinterfacevariable{fractions}{fractions} \setinterfacevariable{frame}{frame} \setinterfacevariable{framedtext}{framedtext} \setinterfacevariable{friday}{friday} diff --git a/tex/context/base/mkii/mult-fr.mkii b/tex/context/base/mkii/mult-fr.mkii index 382e7e059..318bfc31c 100644 --- a/tex/context/base/mkii/mult-fr.mkii +++ b/tex/context/base/mkii/mult-fr.mkii @@ -212,6 +212,7 @@ \setinterfacevariable{formulas}{formules} \setinterfacevariable{forward}{avance} \setinterfacevariable{four}{quatre} +\setinterfacevariable{fractions}{fractions} \setinterfacevariable{frame}{cadre} \setinterfacevariable{framedtext}{texteencadre} \setinterfacevariable{friday}{vendredi} diff --git a/tex/context/base/mkii/mult-it.mkii b/tex/context/base/mkii/mult-it.mkii index b59842f89..269d1e545 100644 --- a/tex/context/base/mkii/mult-it.mkii +++ b/tex/context/base/mkii/mult-it.mkii @@ -212,6 +212,7 @@ \setinterfacevariable{formulas}{formule} \setinterfacevariable{forward}{avanti} \setinterfacevariable{four}{quattro} +\setinterfacevariable{fractions}{fractions} \setinterfacevariable{frame}{cornice} \setinterfacevariable{framedtext}{testoincorniciato} \setinterfacevariable{friday}{venerdi} diff --git a/tex/context/base/mkii/mult-nl.mkii b/tex/context/base/mkii/mult-nl.mkii index a88ec0508..30703e4a6 100644 --- a/tex/context/base/mkii/mult-nl.mkii +++ b/tex/context/base/mkii/mult-nl.mkii @@ -212,6 +212,7 @@ \setinterfacevariable{formulas}{formules} \setinterfacevariable{forward}{vooruit} \setinterfacevariable{four}{vier} +\setinterfacevariable{fractions}{fractions} \setinterfacevariable{frame}{kader} \setinterfacevariable{framedtext}{kadertekst} \setinterfacevariable{friday}{vrijdag} diff --git a/tex/context/base/mkii/mult-pe.mkii b/tex/context/base/mkii/mult-pe.mkii index 3203a0ffb..8b300ae73 100644 --- a/tex/context/base/mkii/mult-pe.mkii +++ b/tex/context/base/mkii/mult-pe.mkii @@ -212,6 +212,7 @@ \setinterfacevariable{formulas}{فرمولها} \setinterfacevariable{forward}{بهجلو} \setinterfacevariable{four}{چهار} +\setinterfacevariable{fractions}{fractions} \setinterfacevariable{frame}{قالب} \setinterfacevariable{framedtext}{متنقالبی} \setinterfacevariable{friday}{جمعه} diff --git a/tex/context/base/mkii/mult-ro.mkii b/tex/context/base/mkii/mult-ro.mkii index 41ccfc8ed..26d0cd9c6 100644 --- a/tex/context/base/mkii/mult-ro.mkii +++ b/tex/context/base/mkii/mult-ro.mkii @@ -212,6 +212,7 @@ \setinterfacevariable{formulas}{formule} \setinterfacevariable{forward}{avans} \setinterfacevariable{four}{patru} +\setinterfacevariable{fractions}{fractions} \setinterfacevariable{frame}{incadrat} \setinterfacevariable{framedtext}{textinconjurat} \setinterfacevariable{friday}{vineri} diff --git a/tex/context/base/mkiv/anch-bck.mkvi b/tex/context/base/mkiv/anch-bck.mkvi index 3bd8cfb4b..1bd855203 100644 --- a/tex/context/base/mkiv/anch-bck.mkvi +++ b/tex/context/base/mkiv/anch-bck.mkvi @@ -588,6 +588,19 @@ \includeMPgraphic{mpos:region:anchor} ; \stopMPpositiongraphic +%D For old times sake: + +\startMPpositiongraphic{mpos:box}{fillcolor,linecolor,linewidth} + string tag; tag := "\MPvar{self}" ; + path box ; box := positionbox(tag) ; + + box := box enlarged \MPvar{filloffset} ; + fill box withcolor \MPvar{fillcolor} ; + draw box withcolor \MPvar{linecolor} withpen pencircle scaled \MPvar{linewidth} ; + + positioninregion; +\stopMPpositiongraphic + \startMPpositionmethod{mpos:region} \MPpositiongraphic{mpos:region}{}% \stopMPpositionmethod diff --git a/tex/context/base/mkiv/anch-pgr.lua b/tex/context/base/mkiv/anch-pgr.lua index 468b9eee3..6a2912024 100644 --- a/tex/context/base/mkiv/anch-pgr.lua +++ b/tex/context/base/mkiv/anch-pgr.lua @@ -17,7 +17,7 @@ if not modules then modules = { } end modules ['anch-pgr'] = { -- will discuss this issue. local abs, div, floor, round = math.abs, math.div, math.floor, math.round -local concat, sort, copy = table.concat, table.sort, table.copy +local concat = table.concat local splitter = lpeg.splitat(":") local lpegmatch = lpeg.match @@ -46,7 +46,7 @@ local f_tag_two = formatters["%s:%s"] local f_point = formatters["%p"] local f_pair = formatters["(%p,%p)"] local f_path = formatters["%--t--cycle"] -local f_pair_i = formatters["(%i,%i)"] +local f_pair_i = formatters["(%r,%r)"] -- rounded graphics = graphics or { } local backgrounds = { } @@ -55,7 +55,6 @@ graphics.backgrounds = backgrounds -- -- -- local texsetattribute = tex.setattribute -local texgetcount = tex.getcount local pdfgetpos = pdf.getpos -- why not a generic name ! local a_textbackground = attributes.private("textbackground") @@ -72,8 +71,7 @@ local insert_after = nuts.insert_after local processranges = nodes.processranges -local v_yes = interfaces.variables.yes -local v_always = interfaces.variables.always +local unsetvalue = attributes.unsetvalue local jobpositions = job.positions @@ -107,7 +105,7 @@ local function registerbackground(name) texsetattribute(a_textbackground,n) enabled = true else - texsetattribute(a_textbackground,attributes.unsetvalue) + texsetattribute(a_textbackground,unsetvalue) end end diff --git a/tex/context/base/mkiv/anch-pos.lua b/tex/context/base/mkiv/anch-pos.lua index 72d76301c..848b42d41 100644 --- a/tex/context/base/mkiv/anch-pos.lua +++ b/tex/context/base/mkiv/anch-pos.lua @@ -65,9 +65,7 @@ local getbox = nuts.getbox local getid = nuts.getid local getwhd = nuts.getwhd -local n_flush_node = nodes.flush - -local hlist_code = nodes.listcodes.hlist +----- hlist_code = nodes.listcodes.hlist local find_tail = nuts.tail @@ -783,6 +781,13 @@ function jobpositions.depth(id) return jpi and jpi.d end +function jobpositions.whd(id) + local jpi = collected[id] + if jpi then + return jpi.h, jpi.h, jpi.d + end +end + function jobpositions.leftskip(id) local jpi = collected[id] return jpi and jpi.ls diff --git a/tex/context/base/mkiv/attr-col.lua b/tex/context/base/mkiv/attr-col.lua index 2562eb944..3cd712449 100644 --- a/tex/context/base/mkiv/attr-col.lua +++ b/tex/context/base/mkiv/attr-col.lua @@ -47,11 +47,13 @@ local report_transparencies = logs.reporter("transparencies","support") -- nb. too many "0 g"s local states = attributes.states -local tasks = nodes.tasks local nodeinjections = backends.nodeinjections local registrations = backends.registrations local unsetvalue = attributes.unsetvalue +local enableaction = nodes.tasks.enableaction +local setaction = nodes.tasks.setaction + local registerstorage = storage.register local formatters = string.formatters @@ -170,9 +172,9 @@ end -- http://en.wikipedia.org/wiki/HSI_color_space -- http://nl.wikipedia.org/wiki/HSV_(kleurruimte) --- h /= 60; // sector 0 to 5 +-- h /= 60; // sector 0 to 5 -- i = floor( h ); --- f = h - i; // factorial part of h +-- f = h - i; // factorial part of h local function hsvtorgb(h,s,v) if s > 1 then @@ -437,11 +439,7 @@ attributes.colors.handler = nodes.installattributehandler { } function colors.enable(value) - if value == false or not colors.supported then - tasks.disableaction("shipouts","attributes.colors.handler") - else - tasks.enableaction("shipouts","attributes.colors.handler") - end + setaction("shipouts","attributes.colors.handler",not (value == false or not colors.supported)) end function colors.forcesupport(value) -- can move to attr-div @@ -547,11 +545,7 @@ attributes.transparencies.handler = nodes.installattributehandler { } function transparencies.enable(value) -- nil is enable - if value == false or not transparencies.supported then - tasks.disableaction("shipouts","attributes.transparencies.handler") - else - tasks.enableaction("shipouts","attributes.transparencies.handler") - end + setaction("shipouts","attributes.transparencies.handler",not (value == false or not transparencies.supported)) end function transparencies.forcesupport(value) -- can move to attr-div @@ -610,7 +604,7 @@ colorintents.handler = nodes.installattributehandler { } function colorintents.enable() - tasks.enableaction("shipouts","attributes.colorintents.handler") + enableaction("shipouts","attributes.colorintents.handler") end -- interface diff --git a/tex/context/base/mkiv/attr-eff.lua b/tex/context/base/mkiv/attr-eff.lua index ff41e12de..d04408fb9 100644 --- a/tex/context/base/mkiv/attr-eff.lua +++ b/tex/context/base/mkiv/attr-eff.lua @@ -10,7 +10,7 @@ local attributes, nodes, backends, utilities = attributes, nodes, backends, util local tex = tex local states = attributes.states -local tasks = nodes.tasks +local enableaction = nodes.tasks.enableaction local nodeinjections = backends.nodeinjections local texsetattribute = tex.setattribute local allocate = utilities.storage.allocate @@ -97,7 +97,7 @@ local enabled = false local function enable() if not enabled then - tasks.enableaction("shipouts","attributes.effects.handler") + enableaction("shipouts","attributes.effects.handler") enabled = true end end diff --git a/tex/context/base/mkiv/attr-ini.mkiv b/tex/context/base/mkiv/attr-ini.mkiv index a2d37118b..77959c988 100644 --- a/tex/context/base/mkiv/attr-ini.mkiv +++ b/tex/context/base/mkiv/attr-ini.mkiv @@ -40,6 +40,7 @@ \newtoks \t_attr_list_global \newtoks \t_attr_list_local +\newtoks \t_attr_list_nomath \ifdefined \s!global \else \def\s!global {global} \fi % for metatex % or hard check later \ifdefined \s!public \else \def\s!public {public} \fi % for metatex % or hard check later @@ -63,6 +64,8 @@ \doifelseinset\s!global{#3}% {\appendetoks\csname\??attributecount#2\endcsname\attributeunsetvalue\to\t_attr_list_global}% {\appendetoks\csname\??attributecount#2\endcsname\attributeunsetvalue\to\t_attr_list_local }% + \doifinset\s!nomath{#3}% + {\appendetoks\csname\??attributecount#2\endcsname\attributeunsetvalue\to\t_attr_list_nomath}% % here public means 'visible' so it's not to be confused with 'public' at the lua end \doifinset\s!public{#3}% {\expandafter\let\csname#2\s!attribute\expandafter\endcsname\csname\??attributeid#2\endcsname}% @@ -91,23 +94,27 @@ \unexpanded\def\savecurrentattributes #1{\clf_savecurrentattributes {#1}} \unexpanded\def\restorecurrentattributes#1{\clf_restorecurrentattributes{#1}} -%D For the moment we put this here (later it will move to where it's used): +%D For the moment we put this here. The order of definition matters a bit because +%D performance is better when we put frequently accessed attributes at the front. +%D So, we might move more here. -\definesystemattribute [state] -\definesystemattribute [color] [public] % global +\definesystemattribute [state] % nomath +\definesystemattribute [color] [public] % global \definesystemattribute [colormodel] [public,global] -\definesystemattribute [skip] -\definesystemattribute [penalty] +% \definesystemattribute [skip] +% \definesystemattribute [penalty] \definesystemattribute [transparency] [public] +\definesystemattribute [reference] [public] +\definesystemattribute [destination] [public] +\definesystemattribute [case] [public] +\definesystemattribute [visual] [public,global] +\definesystemattribute [viewerlayer] [public] \definesystemattribute [background] [public] \definesystemattribute [alignbackground] [public] \definesystemattribute [colorintent] [public] \definesystemattribute [negative] [public] \definesystemattribute [effect] [public] -\definesystemattribute [viewerlayer] [public] \definesystemattribute [layoutcomponent] [public] -\definesystemattribute [reference] [public] -\definesystemattribute [destination] [public] \definesystemattribute [internal] [public] \definesystemattribute [ruled] [public] \definesystemattribute [shifted] [public] diff --git a/tex/context/base/mkiv/attr-lay.lua b/tex/context/base/mkiv/attr-lay.lua index 051ff6e10..ff9d1c38f 100644 --- a/tex/context/base/mkiv/attr-lay.lua +++ b/tex/context/base/mkiv/attr-lay.lua @@ -62,7 +62,8 @@ viewerlayers.supported = true viewerlayers.hasorder = true local states = attributes.states -local tasks = nodes.tasks +local enableaction = nodes.tasks.enableaction +local disableaction = nodes.tasks.disableaction local nodeinjections = backends.nodeinjections local codeinjections = backends.codeinjections @@ -146,12 +147,12 @@ local stack, enabled, global = { }, false, false function viewerlayers.enable(value) if value == false or not viewerlayers.supported then if enabled then - tasks.disableaction("shipouts","attributes.viewerlayers.handler") + disableaction("shipouts","attributes.viewerlayers.handler") end enabled = false else if not enabled then - tasks.enableaction("shipouts","attributes.viewerlayers.handler") + enableaction("shipouts","attributes.viewerlayers.handler") end enabled = true end diff --git a/tex/context/base/mkiv/attr-neg.lua b/tex/context/base/mkiv/attr-neg.lua index 1347c3d1a..c20df1d16 100644 --- a/tex/context/base/mkiv/attr-neg.lua +++ b/tex/context/base/mkiv/attr-neg.lua @@ -16,7 +16,7 @@ local commands, context, interfaces = commands, context, interfaces local tex = tex local states = attributes.states -local tasks = nodes.tasks +local enableaction = nodes.tasks.enableaction local nodeinjections = backends.nodeinjections local texsetattribute = tex.setattribute local variables = interfaces.variables @@ -79,7 +79,7 @@ local function register(stamp) end local function enable() - tasks.enableaction("shipouts","attributes.negatives.handler") + enableaction("shipouts","attributes.negatives.handler") end negatives.register = register diff --git a/tex/context/base/mkiv/back-exp.lua b/tex/context/base/mkiv/back-exp.lua index bd87075d0..da7ec202f 100644 --- a/tex/context/base/mkiv/back-exp.lua +++ b/tex/context/base/mkiv/back-exp.lua @@ -118,12 +118,16 @@ local getnext = nuts.getnext local getsubtype = nuts.getsubtype local getfont = nuts.getfont local getdisc = nuts.getdisc +local getcomponents = nuts.getcomponents local getlist = nuts.getlist local getid = nuts.getid local getfield = nuts.getfield local getattr = nuts.getattr local setattr = nuts.setattr -- maybe use properties local isglyph = nuts.isglyph +local getkern = nuts.getkern +local getwidth = nuts.getwidth + local traverse_id = nuts.traverse_id local traverse_nodes = nuts.traverse @@ -544,27 +548,6 @@ local function makebreaknode(attributes) -- maybe no fulltag } end -local function ignorebreaks(di,element,n,fulltag) - local data = di.data - for i=1,#data do - local d = data[i] - if d.content == " " then - d.content = "" - end - end -end - -local function ignorespaces(di,element,n,fulltag) - local data = di.data - for i=1,#data do - local d = data[i] - local c = d.content - if type(c) == "string" then - d.content = lpegmatch(p_stripper,c) - end - end -end - do local fields = { "title", "subtitle", "author", "keywords" } @@ -1719,6 +1702,27 @@ do end end + local function ignorebreaks(di,element,n,fulltag) + local data = di.data + for i=1,#data do + local d = data[i] + if d.content == " " then + d.content = "" + end + end + end + + local function ignorespaces(di,element,n,fulltag) + local data = di.data + for i=1,#data do + local d = data[i] + local c = d.content + if type(c) == "string" then + d.content = lpegmatch(p_stripper,c) + end + end + end + extras.registerpages = ignorebreaks extras.registerseparator = ignorespaces @@ -2549,7 +2553,7 @@ local function collectresults(head,list,pat,pap) -- is last used (we also have c -- report_export("skipping character: %C (no attribute)",n.char) else -- we could add tonunicodes for ligatures (todo) - local components = getfield(n,"components") + local components = getcomponents(n) if components and (not characterdata[c] or overloads[c]) then -- we loose data collectresults(components,nil,at) -- this assumes that components have the same attribute as the glyph ... we should be more tolerant (see math) else @@ -2699,7 +2703,7 @@ local function collectresults(head,list,pat,pap) -- is last used (we also have c else local subtype = getsubtype(n) if subtype == userskip_code then - if getfield(n,"width") > threshold then + if getwidth(n) > threshold then if last and not somespace[currentcontent[nofcurrentcontent]] then local a = getattr(n,a_tagged) or pat if a == last then @@ -2807,7 +2811,7 @@ local function collectresults(head,list,pat,pap) -- is last used (we also have c end end elseif id == kern_code then - local kern = getfield(n,"kern") + local kern = getkern(n) if kern > 0 then local limit = threshold if p and getid(p) == glyph_code then diff --git a/tex/context/base/mkiv/back-ini.lua b/tex/context/base/mkiv/back-ini.lua index fc0074540..fd33d5ddc 100644 --- a/tex/context/base/mkiv/back-ini.lua +++ b/tex/context/base/mkiv/back-ini.lua @@ -16,15 +16,15 @@ if not modules then modules = { } end modules ['back-ini'] = { local next, type = next, type local format = string.format -backends = backends or { } -local backends = backends +backends = backends or { } +local backends = backends -local trace_backend = false trackers.register("backend.initializers", function(v) trace_finalizers = v end) - -local report_backend = logs.reporter("backend","initializing") +local trace_backend = false trackers.register("backend.initializers", function(v) trace_finalizers = v end) +local report_backend = logs.reporter("backend","initializing") local allocate = utilities.storage.allocate local setmetatableindex = table.setmetatableindex +local setaction = nodes.tasks.setaction local function nothing() return nil end @@ -117,7 +117,7 @@ interfaces.implement { name = "setrealspaces", arguments = "string", actions = function(v) - nodes.tasks.setaction("shipouts","nodes.handlers.accessibility",v == interfaces.variables.yes) + setaction("shipouts","nodes.handlers.accessibility",v == interfaces.variables.yes) end } diff --git a/tex/context/base/mkiv/back-pdf.lua b/tex/context/base/mkiv/back-pdf.lua index b6633f091..a3f7ffff7 100644 --- a/tex/context/base/mkiv/back-pdf.lua +++ b/tex/context/base/mkiv/back-pdf.lua @@ -19,6 +19,9 @@ local context = context local scanners = tokens.scanners local scannumber = scanners.number local scankeyword = scanners.keyword +local scandimen = scanners.dimen +local scancount = scanners.count +local scanstring = scanners.string local scanners = interfaces.scanners local implement = interfaces.implement @@ -178,3 +181,136 @@ implement { pdf.setobjcompresslevel(o) end } + +local report = logs.reporter("backend","pdftex primitives") +local trace = false + +scanners.pdfannot = function() + if scankeyword("reserveobjectnum") then + report("\\pdfannot reserveobjectnum is not (yet) supported") + -- if trace then + -- report() + -- report("\\pdfannot: reserved number (not supported yet)") + -- report() + -- end + else + local width = false + local height = false + local depth = false + local data = false + local object = false + local attr = false + -- + if scankeyword("useobjnum") then + object = scancount() + report("\\pdfannot useobjectnum is not (yet) supported") + end + while true do + if scankeyword("width") then + width = scandimen() + elseif scankeyword("height") then + height = scandimen() + elseif scankeyword("depth") then + depth = scandimen() + else + break + end + end + if scankeyword("attr") then + attr = scanstring() + end + data = scanstring() + -- + -- less strict variant: + -- + -- while true do + -- if scankeyword("width") then + -- width = scandimen() + -- elseif scankeyword("height") then + -- height = scandimen() + -- elseif scankeyword("depth") then + -- depth = scandimen() + -- elseif scankeyword("useobjnum") then + -- object = scancount() + -- elseif scankeyword("attr") then + -- attr = scanstring() + -- else + -- data = scanstring() + -- break + -- end + -- end + -- + -- if trace then + -- report() + -- report("\\pdfannot:") + -- report() + -- report(" object: %s",object or "<unset> (not supported yet)") + -- report(" width : %p",width or "<unset>") + -- report(" height: %p",height or "<unset>") + -- report(" depth : %p",depth or "<unset>") + -- report(" attr : %s",attr or "<unset>") + -- report(" data : %s",data or "<unset>") + -- report() + -- end + context(backends.nodeinjections.annotation(width or 0,height or 0,depth or 0,data or "")) + end +end + +scanners.pdfdest = function() + local name = false + local zoom = false + local view = false + local width = false + local height = false + local depth = false + if scankeyword("num") then + report("\\pdfdest num is not (yet) supported") + elseif scankeyword("name") then + name = scanstring() + end + if scankeyword("xyz") then + view = "xyz" + if scankeyword("zoom") then + report("\\pdfdest zoom is ignored") + zoom = scancount() + end + elseif scankeyword("fitbh") then + view = "fitbh" + elseif scankeyword("fitbv") then + view = "fitbv" + elseif scankeyword("fitb") then + view = "fitb" + elseif scankeyword("fith") then + view = "fith" + elseif scankeyword("fitv") then + view = "fitv" + elseif scankeyword("fitr") then + view = "fitr" + while true do + if scankeyword("width") then + width = scandimen() + elseif scankeyword("height") then + height = scandimen() + elseif scankeyword("depth") then + depth = scandimen() + else + break + end + end + elseif scankeyword("fit") then + view = "fit" + end + -- if trace then + -- report() + -- report("\\pdfdest:") + -- report() + -- report(" name : %s",name or "<unset>") + -- report(" view : %s",view or "<unset>") + -- report(" zoom : %s",zoom or "<unset> (not supported)") + -- report(" width : %p",width or "<unset>") + -- report(" height: %p",height or "<unset>") + -- report(" depth : %p",depth or "<unset>") + -- report() + -- end + context(backends.nodeinjections.destination(width or 0,height or 0,depth or 0,{ name or "" },view or "fit")) +end diff --git a/tex/context/base/mkiv/back-pdf.mkiv b/tex/context/base/mkiv/back-pdf.mkiv index 84e58d84c..f59b59c29 100644 --- a/tex/context/base/mkiv/back-pdf.mkiv +++ b/tex/context/base/mkiv/back-pdf.mkiv @@ -52,31 +52,37 @@ %D These are no-ops and don't even intercept what comes next. Maybe some day %D I'll write a parser that maps onto \CONTEXT. -\let\pdfcolorstack \relax -\let\pdfcolorstackinit \relax -\let\pdfannot \relax -\let\pdfstartlink \relax -\let\pdfendlink \relax -\let\pdfoutline \relax -\let\pdfdest \relax -\let\pdfthread \relax -\let\pdfstartthread \relax -\let\pdfendthread \relax -\let\pdffontattr \relax -\let\pdfglyphtounicode \relax +\unexpanded\def\unsupportedpdfprimitive#1% + {\writestatus{error}{the primitive \string#1\space is not supported}} + +\unexpanded\def\pdfcolorstack {\unsupportedpdfprimitive\pdfcolorstack} +\unexpanded\def\pdfcolorstackinit{\unsupportedpdfprimitive\pdfcolorstackinit} +%unexpanded\def\pdfannot {\unsupportedpdfprimitive\pdfannot} +\unexpanded\def\pdfstartlink {\unsupportedpdfprimitive\pdfstartlink} +\unexpanded\def\pdfendlink {\unsupportedpdfprimitive\pdfendlink} +\unexpanded\def\pdfoutline {\unsupportedpdfprimitive\pdfoutline} +%unexpanded\def\pdfdest {\unsupportedpdfprimitive\pdfdest} +\unexpanded\def\pdfthread {\unsupportedpdfprimitive\pdfthread} +\unexpanded\def\pdfstartthread {\unsupportedpdfprimitive\pdfstartthread} +\unexpanded\def\pdfendthread {\unsupportedpdfprimitive\pdfendthread} +\unexpanded\def\pdffontattr {\unsupportedpdfprimitive\pdffontattr} +\unexpanded\def\pdfglyphtounicode{\unsupportedpdfprimitive\pdfglyphtounicode} + +\unexpanded\def\pdfannot{\clf_pdfannot} +\unexpanded\def\pdfdest {\clf_pdfdest} %D Here we do intercept (silently) what gets passed. One should use the %D \CONTEXT\ interfaces instead. -\let\pdfcatalog \relax \newtoks \pdfcatalog -\let\pdfinfo \relax \newtoks \pdfinfo -\let\pdfnames \relax \newtoks \pdfnames -\let\pdftrailer \relax \newtoks \pdftrailer -\let\pdfpageresources \relax \newtoks \pdfpageresources -\let\pdfpageattr \relax \newtoks \pdfpageattr -\let\pdfpagesattr \relax \newtoks \pdfpagesattr -\let\pdfxformattr \relax \newtoks \pdfxformattr -\let\pdfxformresources \relax \newtoks \pdfxformresources +\let\pdfcatalog \relax \newtoks\pdfcatalog +\let\pdfinfo \relax \newtoks\pdfinfo +\let\pdfnames \relax \newtoks\pdfnames +\let\pdftrailer \relax \newtoks\pdftrailer +\let\pdfpageresources \relax \newtoks\pdfpageresources +\let\pdfpageattr \relax \newtoks\pdfpageattr +\let\pdfpagesattr \relax \newtoks\pdfpagesattr +\let\pdfxformattr \relax \newtoks\pdfxformattr +\let\pdfxformresources\relax \newtoks\pdfxformresources %D We use the \LUA\ interface (which then permits more control over %D possible pdf/x extensions). @@ -588,3 +594,14 @@ % \stoptext \protect \endinput + +% \chapter{FIRST} +% +% \goto{bar}[bar] +% +% HERE \pdfannot width 20pt height 20pt depth 20pt {/Subtype /Link /Dest (bar) /Border [1 1 1] /F 4}\par +% HERE \pdfannot width 20pt height 20pt depth 20pt {/Subtype /Link /Dest (foo) /Border [1 1 1] /F 4}\par +% +% \chapter[bar]{SECOND} +% +% THERE \pdfdest name {foo} \par diff --git a/tex/context/base/mkiv/bibl-tra.lua b/tex/context/base/mkiv/bibl-tra.lua index 223554b4d..76171cb7f 100644 --- a/tex/context/base/mkiv/bibl-tra.lua +++ b/tex/context/base/mkiv/bibl-tra.lua @@ -21,7 +21,9 @@ end -- end of hack -local match, gmatch, format, concat, sort = string.match, string.gmatch, string.format, table.concat, table.sort +local gmatch, format = string.gmatch, string.format +local sort = table.sort +local savedata = io.savedata bibtex = bibtex or { } local bibtex = bibtex @@ -61,10 +63,31 @@ local template = [[ \bibdata{%s} ]] -local bibtexbin = environment.arguments.mlbibtex and "mlbibcontext" or "bibtex" +local runners = { + bibtex = sandbox.registerrunner { + name = "bibtex", + method = "execute", + program = "bibtex", + template = [["%filename%"]], + checkers = { + filename = "readable", + } + }, + mlbibtex = sandbox.registerrunner { + name = "mlbibtex", + method = "execute", + program = "mlbibcontext", + template = [["%filename%"]], + checkers = { + filename = "readable", + } + } +} + +local runner = environment.arguments.mlbibtex and runners.mlbibtex or runners.bibtex directives.register("publications.usemlbibtex", function(v) - bibtexbin = v and "mlbibcontext" or "bibtex" + runner = v and runners.mlbibtex or runners.bibtex end) function hacks.process(settings) @@ -74,11 +97,11 @@ function hacks.process(settings) if database ~= "" then local targetfile = file.addsuffix(jobname,"aux") interfaces.showmessage("publications",3,targetfile) - io.savedata(targetfile,format(template,style,database)) + savedata(targetfile,format(template,style,database)) if trace_bibtex then report_tex("processing bibtex file %a using %a",jobname,bibtexbin) end - os.execute(format("%s %q",bibtexbin,jobname)) + runner { filename = jobname } -- purge 'm end end diff --git a/tex/context/base/mkiv/buff-ini.lua b/tex/context/base/mkiv/buff-ini.lua index 876a6944e..2b3270300 100644 --- a/tex/context/base/mkiv/buff-ini.lua +++ b/tex/context/base/mkiv/buff-ini.lua @@ -12,6 +12,7 @@ local sub, format = string.sub, string.format local splitlines, validstring, replacenewlines = string.splitlines, string.valid, string.replacenewlines local P, Cs, patterns, lpegmatch = lpeg.P, lpeg.Cs, lpeg.patterns, lpeg.match local utfchar = utf.char +local nameonly = file.nameonly local totable = string.totable local trace_run = false trackers.register("buffers.run", function(v) trace_run = v end) @@ -486,6 +487,17 @@ implement { local oldhashes = nil local newhashes = nil +local runner = sandbox.registerrunner { + name = "run buffer", + program = "context", + method = "execute", + template = "--purgeall " .. (jit and "--jit" or "") .. " %filename%", + reporter = report_typeset, + checkers = { + filename = "readable", + } +} + local function runbuffer(name,encapsulate) if not oldhashes then oldhashes = job.datasets.getdata("typeset buffers","hashes") or { } @@ -513,7 +525,7 @@ local function runbuffer(name,encapsulate) end -- local hash = md5.hex(content) - local tag = formatters["%s-t-b-%s"](tex.jobname,hash) + local tag = formatters["%s-t-b-%s"](nameonly(tex.jobname),hash) -- make sure we run on the local path -- local filename = addsuffix(tag,"tmp") local resultname = addsuffix(tag,"pdf") @@ -525,9 +537,8 @@ local function runbuffer(name,encapsulate) report_typeset("changes in %a, processing forced",name) end io.savedata(filename,content) - local command = formatters["context --purgeall %s %s"](jit and "--jit" or "",filename) - report_typeset("running: %s\n",command) - os.execute(command) + report_typeset("processing saved buffer %a\n",filename) + runner { filename = filename } end newhashes[hash] = (newhashes[hash] or 0) + 1 report_typeset("no changes in %a, processing skipped",name) diff --git a/tex/context/base/mkiv/cldf-ini.lua b/tex/context/base/mkiv/cldf-ini.lua index 66582ae4f..b0b731866 100644 --- a/tex/context/base/mkiv/cldf-ini.lua +++ b/tex/context/base/mkiv/cldf-ini.lua @@ -100,7 +100,7 @@ local flushdirect = texprint -- lines local report_context = logs.reporter("cld","tex") local report_cld = logs.reporter("cld","stack") -local report_template = logs.reporter("cld","template") +----- report_template = logs.reporter("cld","template") local processlines = true -- experiments.register("context.processlines", function(v) processlines = v end) diff --git a/tex/context/base/mkiv/colo-imp-solarized.mkiv b/tex/context/base/mkiv/colo-imp-solarized.mkiv new file mode 100644 index 000000000..872e6b701 --- /dev/null +++ b/tex/context/base/mkiv/colo-imp-solarized.mkiv @@ -0,0 +1,38 @@ +%D \module +%D [ file=colo-imp-solarized, +%D version=2017.02.10, +%D title=\CONTEXT\ Color Macros, +%D subtitle=Solarized, +%D author=Aditya Mahajan, +%D ] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA, See mreadme.pdf for +%C details. + +%D Colors based on solarized scheme: +%D +%D \hyphenatedurl{http://ethanschoonover.com/solarized} + +\startprotectedcolors + + \definecolor [base03] [h=002b36] + \definecolor [base02] [h=073642] + \definecolor [base01] [h=586e75] + \definecolor [base00] [h=657b83] + \definecolor [base0] [h=839496] + \definecolor [base1] [h=93a1a1] + \definecolor [base2] [h=eee8d5] + \definecolor [base3] [h=fdf6e3] + \definecolor [yellow] [h=b58900] + \definecolor [orange] [h=cb4b16] + \definecolor [red] [h=dc322f] + \definecolor [magenta] [h=d33682] + \definecolor [violet] [h=6c71c4] + \definecolor [blue] [h=268bd2] + \definecolor [cyan] [h=2aa198] + \definecolor [green] [h=859900] + +\stopprotectedcolors + +\endinput diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv index 5b9050d6c..e83b97c3a 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{2017.01.27 14:39} +\newcontextversion{2017.02.17 10:17} %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/cont-run.lua b/tex/context/base/mkiv/cont-run.lua index 0420ed01c..d9dad3f2d 100644 --- a/tex/context/base/mkiv/cont-run.lua +++ b/tex/context/base/mkiv/cont-run.lua @@ -90,7 +90,7 @@ local function logsandbox(details) end end -local ioopen = sandbox.original(io.open) +local ioopen = sandbox.original(io.open) -- dummy call local function logsandboxfiles(name,what,asked,okay) -- we're only interested in permitted access @@ -161,14 +161,13 @@ if sandboxing then -- Nicer would be if we could just disable write 18 and keep os.execute -- which in fact we can do by defining write18 as macro instead of - -- primitive ... todo. + -- primitive ... todo ... well, it has been done now. -- We block some potential escapes from protection. context [[ \let\primitive \relax \let\normalprimitive\relax - \let\normalwrite \relax ]] end diff --git a/tex/context/base/mkiv/context.mkiv b/tex/context/base/mkiv/context.mkiv index e92a39cbd..e8aae9575 100644 --- a/tex/context/base/mkiv/context.mkiv +++ b/tex/context/base/mkiv/context.mkiv @@ -39,7 +39,7 @@ %D up and the dependencies are more consistent. \edef\contextformat {\jobname} -\edef\contextversion{2017.01.27 14:39} +\edef\contextversion{2017.02.17 10:17} \edef\contextkind {beta} %D For those who want to use this: diff --git a/tex/context/base/mkiv/core-con.lua b/tex/context/base/mkiv/core-con.lua index 36f1774e9..10f8fc2ed 100644 --- a/tex/context/base/mkiv/core-con.lua +++ b/tex/context/base/mkiv/core-con.lua @@ -81,6 +81,14 @@ local counters = allocate { 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A }, + ['russian'] = { + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, + 0x0435, 0x0436, 0x0437, 0x0438, 0x043a, + 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, + 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, + 0x044d, 0x044e, 0x044f + }, ['greek'] = { -- this should be the lowercase table -- 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, -- 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, @@ -153,6 +161,7 @@ counters['gr'] = counters['greek'] counters['g'] = counters['greek'] counters['sl'] = counters['slovenian'] counters['es'] = counters['spanish'] +counters['ru'] = counters['russian'] counters['kr'] = counters['korean'] counters['kr-p'] = counters['korean-parenthesis'] counters['kr-c'] = counters['korean-circle'] @@ -172,6 +181,7 @@ counters['koreancirclenumerals'] = counters['korean-circle'] counters['sloveniannumerals'] = counters['slovenian'] counters['spanishnumerals'] = counters['spanish'] +counters['russiannumerals'] = counters['russian'] local decimals = allocate { ['arabic'] = { @@ -589,23 +599,29 @@ converters['A'] = converters.Characters converters['AK'] = converters.Characters -- obsolete converters['KA'] = converters.Characters -- obsolete -function converters.spanishnumerals(n) return alphabetic(n,"es") end -function converters.Spanishnumerals(n) return Alphabetic(n,"es") end -function converters.sloviannumerals(n) return alphabetic(n,"sl") end -function converters.Sloviannumerals(n) return Alphabetic(n,"sl") end +function converters.spanishnumerals (n) return alphabetic(n,"es") end +function converters.Spanishnumerals (n) return Alphabetic(n,"es") end +function converters.sloveniannumerals(n) return alphabetic(n,"sl") end +function converters.Sloveniannumerals(n) return Alphabetic(n,"sl") end +function converters.russiannumerals (n) return alphabetic(n,"ru") end +function converters.Russiannumerals (n) return Alphabetic(n,"ru") end converters['alphabetic:es'] = converters.spanishnumerals converters['alphabetic:sl'] = converters.sloveniannumerals +converters['alphabetic:ru'] = converters.russiannumerals converters['Alphabetic:es'] = converters.Spanishnumerals converters['Alphabetic:sl'] = converters.Sloveniannumerals +converters['Alphabetic:ru'] = converters.Russiannumerals -- bonus converters['a:es'] = converters.spanishnumerals converters['a:sl'] = converters.sloveniannumerals +converters['a:ru'] = converters.russiannumerals converters['A:es'] = converters.Spanishnumerals converters['A:sl'] = converters.Sloveniannumerals +converters['A:ru'] = converters.Russiannumerals -- end of bonus diff --git a/tex/context/base/mkiv/core-con.mkiv b/tex/context/base/mkiv/core-con.mkiv index 8565a3096..a4d358e04 100644 --- a/tex/context/base/mkiv/core-con.mkiv +++ b/tex/context/base/mkiv/core-con.mkiv @@ -739,6 +739,9 @@ \def\spanishnumerals #1{\clf_alphabetic\numexpr#1\relax{es}} \def\spanishNumerals #1{\clf_Alphabetic\numexpr#1\relax{es}} +\def\russiannumerals #1{\clf_alphabetic\numexpr#1\relax{ru}} +\def\russianNumerals #1{\clf_Alphabetic\numexpr#1\relax{ru}} + %defineconversion [\s!sl] [character] [\sloveniannumerals] %defineconversion [\s!sl] [Character] [\slovenianNumerals] %defineconversion [\s!sl] [characters] [\sloveniannumerals] @@ -765,12 +768,28 @@ \defineconversion [\s!es] [AK] [\smallcapped\spanishnumerals] \defineconversion [\s!es] [KA] [\smallcapped\spanishnumerals] +%defineconversion [\s!ru] [character] [\russiannumerals] +%defineconversion [\s!ru] [Character] [\russianNumerals] +%defineconversion [\s!ru] [characters] [\russiannumerals] +%defineconversion [\s!ru] [Characters] [\russianNumerals] + +\defineconversion [\s!ru] [alphabetic] [\russiannumerals] +\defineconversion [\s!ru] [Alphabetic] [\russianNumerals] + +\defineconversion [\s!ru] [a] [\russiannumerals] +\defineconversion [\s!ru] [A] [\russianNumerals] +\defineconversion [\s!ru] [AK] [\smallcapped\russiannumerals] +\defineconversion [\s!ru] [KA] [\smallcapped\russiannumerals] + \defineconversion [sloveniannumerals] [\sloveniannumerals] \defineconversion [slovenianNumerals] [\slovenianNumerals] \defineconversion [spanishnumerals] [\spanishnumerals] \defineconversion [spanishNumerals] [\spanishNumerals] +\defineconversion [russiannumerals] [\russiannumerals] +\defineconversion [russianNumerals] [\russianNumerals] + %D In case a font has no greek (WS): \defineconversion [mathgreek] diff --git a/tex/context/base/mkiv/core-ctx.lua b/tex/context/base/mkiv/core-ctx.lua index 1f22402e6..3362e43b9 100644 --- a/tex/context/base/mkiv/core-ctx.lua +++ b/tex/context/base/mkiv/core-ctx.lua @@ -266,7 +266,12 @@ function ctxrunner.load(ctxname) for i=1,#runners do local command = runners[i] report_prepfiles("command: %s",command) + -- + -- remark: we don't use sandbox.registerrunner here as we cannot predict what + -- gets done here, so just: + -- local result = os.execute(command) or 0 + -- -- if result > 0 then -- report_prepfiles("error, return code: %s",result) -- end diff --git a/tex/context/base/mkiv/core-uti.lua b/tex/context/base/mkiv/core-uti.lua index 10f3ffcdc..a2869e6ea 100644 --- a/tex/context/base/mkiv/core-uti.lua +++ b/tex/context/base/mkiv/core-uti.lua @@ -418,7 +418,7 @@ function statistics.formatruntime(runtime) runtime = tonumber(runtime) local persecond = (runtime > 0) and (shipped/runtime) or pages if pages == 0 then pages = shipped end - -- if jit then + -- if TEXENGINE == "luajittex" then -- local saved = watts_per_core * runtime * kg_per_watt_per_second / speedup_by_other_engine -- local saved = used_wood_factor * runtime -- return format("%s seconds, %i processed pages, %i shipped pages, %.3f pages/second, %f mg tree saved by using luajittex",runtime,pages,shipped,persecond,saved*1000*1000) diff --git a/tex/context/base/mkiv/data-crl.lua b/tex/context/base/mkiv/data-crl.lua index fba5a6230..ec517fba3 100644 --- a/tex/context/base/mkiv/data-crl.lua +++ b/tex/context/base/mkiv/data-crl.lua @@ -8,29 +8,45 @@ if not modules then modules = { } end modules ['data-crl'] = { -- this one is replaced by data-sch.lua -- -local gsub = string.gsub +local gsub = string.gsub +local exists = io.exists local resolvers = resolvers +local finders = resolvers.finders +local openers = resolvers.openers +local loaders = resolvers.loaders -local finders, openers, loaders = resolvers.finders, resolvers.openers, resolvers.loaders +local setfirstwritablefile = caches.setfirstwritablefile -resolvers.curl = resolvers.curl or { } -local curl = resolvers.curl +local curl = resolvers.curl or { } +resolvers.curl = curl +local cached = { } -local cached = { } +local runner = sandbox.registerrunner { + name = "curl resolver", + method = "execute", + program = "curl", + template = "--silent -- insecure --create-dirs --output %cachename% %original%", + checkers = { + cachename = "cache", + original = "url", + } +} local function runcurl(specification) local original = specification.original -- local scheme = specification.scheme local cleanname = gsub(original,"[^%a%d%.]+","-") - local cachename = caches.setfirstwritablefile(cleanname,"curl") + local cachename = setfirstwritablefile(cleanname,"curl") if not cached[original] then - if not io.exists(cachename) then + if not exists(cachename) then cached[original] = cachename - local command = "curl --silent --create-dirs --output " .. cachename .. " " .. original - os.execute(command) + runner { + cachename = cachename, + original = original, + } end - if io.exists(cachename) then + if exists(cachename) then cached[original] = cachename else cached[original] = "" diff --git a/tex/context/base/mkiv/data-sch.lua b/tex/context/base/mkiv/data-sch.lua index d79e0c7ef..23ecdc122 100644 --- a/tex/context/base/mkiv/data-sch.lua +++ b/tex/context/base/mkiv/data-sch.lua @@ -61,12 +61,21 @@ function resolvers.schemes.cleanname(specification) return hash end -local cached, loaded, reused, thresholds, handlers = { }, { }, { }, { }, { } - -local function runcurl(name,cachename) -- we use sockets instead or the curl library when possible - local command = "curl --silent --insecure --create-dirs --output " .. cachename .. " " .. name - os.execute(command) -end +local cached = { } +local loaded = { } +local reused = { } +local thresholds = { } +local handlers = { } +local runner = sandbox.registerrunner { + name = "curl resolver", + method = "execute", + program = "curl", + template = "--silent -- insecure --create-dirs --output %cachename% %original%", + checkers = { + cachename = "cache", + original = "url", + } +} local function fetch(specification) local original = specification.original @@ -89,7 +98,10 @@ local function fetch(specification) report_schemes("fetching %a, protocol %a, method %a",original,scheme,"curl") end logs.flush() - runcurl(original,cachename) + runner { + original = original, + cachename = cachename, + } end end if io.exists(cachename) then @@ -184,10 +196,6 @@ end) local httprequest = http.request local toquery = url.toquery --- local function httprequest(url) --- return os.resultof(format("curl --silent %q", url)) --- end - local function fetchstring(url,data) local q = data and toquery(data) if q then diff --git a/tex/context/base/mkiv/font-col.lua b/tex/context/base/mkiv/font-col.lua index b4c16c660..d7b76a615 100644 --- a/tex/context/base/mkiv/font-col.lua +++ b/tex/context/base/mkiv/font-col.lua @@ -24,7 +24,7 @@ local getfont = nuts.getfont local getchar = nuts.getchar local setfield = nuts.setfield -local setchar = nuts.setchar +local setfont = nuts.setfont local traverse_id = nuts.traverse_id local traverse_char = nuts.traverse_char @@ -35,6 +35,9 @@ local trace_collecting = false trackers.register("fonts.collecting", function local report_fonts = logs.reporter("fonts","collections") +local enableaction = nodes.tasks.enableaction +local disableaction = nodes.tasks.disableaction + local collections = fonts.collections or { } fonts.collections = collections @@ -60,12 +63,12 @@ local function checkenabled() -- a bit ugly but nicer than a fuzzy state while defining math if next(vectors) then if not enabled then - nodes.tasks.enableaction("processors","fonts.collections.process") + enableaction("processors","fonts.collections.process") enabled = true end else if enabled then - nodes.tasks.disableaction("processors","fonts.collections.process") + disableaction("processors","fonts.collections.process") enabled = false end end @@ -272,8 +275,7 @@ function collections.process(head) -- this way we keep feature processing char,font,newchar,newfont,not chardata[newfont][newchar] and " (missing)" or "" ) end - setfield(n,"font",newfont) - setchar(n,newchar) + setfont(n,newfont,newchar) done = true else if trace_collecting then @@ -281,7 +283,7 @@ function collections.process(head) -- this way we keep feature processing font,vect,char,not chardata[vect][char] and " (missing)" or "" ) end - setfield(n,"font",vect) + setfont(n,vect) done = true end end diff --git a/tex/context/base/mkiv/font-ctx.lua b/tex/context/base/mkiv/font-ctx.lua index 7c986f889..f53a4e643 100644 --- a/tex/context/base/mkiv/font-ctx.lua +++ b/tex/context/base/mkiv/font-ctx.lua @@ -961,13 +961,13 @@ local rightparent = (P")") local value = C((leftparent * (1-rightparent)^0 * rightparent + (1-space))^1) local dimension = C((space/"" + P(1))^1) local rest = C(P(1)^0) -local scale_none = Cc(0) -local scale_at = P("at") * Cc(1) * spaces * dimension -- dimension -local scale_sa = P("sa") * Cc(2) * spaces * dimension -- number -local scale_mo = P("mo") * Cc(3) * spaces * dimension -- number -local scale_scaled = P("scaled") * Cc(4) * spaces * dimension -- number -local scale_ht = P("ht") * Cc(5) * spaces * dimension -- dimension -local scale_cp = P("cp") * Cc(6) * spaces * dimension -- dimension +local scale_none = Cc(0) +local scale_at = (P("at") +P("@")) * Cc(1) * spaces * dimension -- dimension +local scale_sa = P("sa") * Cc(2) * spaces * dimension -- number +local scale_mo = P("mo") * Cc(3) * spaces * dimension -- number +local scale_scaled = P("scaled") * Cc(4) * spaces * dimension -- number +local scale_ht = P("ht") * Cc(5) * spaces * dimension -- dimension +local scale_cp = P("cp") * Cc(6) * spaces * dimension -- dimension local specialscale = { [5] = "ht", [6] = "cp" } diff --git a/tex/context/base/mkiv/font-dsp.lua b/tex/context/base/mkiv/font-dsp.lua index 14e3a1d62..2d52c23a9 100644 --- a/tex/context/base/mkiv/font-dsp.lua +++ b/tex/context/base/mkiv/font-dsp.lua @@ -1699,13 +1699,7 @@ do rule.lookups = nil else -- we can have holes in rlookups - -- for index, lookupid in sortedhash(rlookups) do local length = #rlookups --- for index in next, rlookups do --- if index > length then --- length = index --- end --- end for index=1,length do local lookupid = rlookups[index] if lookupid then @@ -1733,6 +1727,7 @@ do sublookuplist[nofsublookups] = copy(h) -- we repack later sublookuphash[lookupid] = nofsublookups sublookupcheck[lookupid] = 1 + h = nofsublookups else report_issue(i,what,sequence,"missing") rule.lookups = nil diff --git a/tex/context/base/mkiv/font-hsh.lua b/tex/context/base/mkiv/font-hsh.lua index efd042fe1..12f7bdfc2 100644 --- a/tex/context/base/mkiv/font-hsh.lua +++ b/tex/context/base/mkiv/font-hsh.lua @@ -31,6 +31,7 @@ local xheights = hashes.xheights or allocate() local csnames = hashes.csnames or allocate() -- namedata local features = hashes.features or allocate() local marks = hashes.marks or allocate() +local classes = hashes.classes or allocate() local italics = hashes.italics or allocate() local lastmathids = hashes.lastmathids or allocate() local dynamics = hashes.dynamics or allocate() @@ -51,6 +52,7 @@ hashes.xheights = xheights hashes.exheights = xheights hashes.csnames = csnames hashes.features = features hashes.marks = marks +hashes.classes = classes hashes.italics = italics hashes.lastmathids = lastmathids hashes.dynamics = dynamics @@ -212,12 +214,23 @@ setmetatableindex(marks, function(t,k) return marks[currentfont()] else local resources = identifiers[k].resources or { } - local marks = resources.marks or { } + local marks = resources.marks or { } t[k] = marks return marks end end) +setmetatableindex(classes, function(t,k) + if k == true then + return classes[currentfont()] + else + local resources = identifiers[k].resources or { } + local classes = resources.classes or { } + t[k] = classes + return classes + end +end) + setmetatableindex(quads, function(t,k) if k == true then return quads[currentfont()] diff --git a/tex/context/base/mkiv/font-inj.lua b/tex/context/base/mkiv/font-inj.lua index cb4fb7226..ccc41d3f3 100644 --- a/tex/context/base/mkiv/font-inj.lua +++ b/tex/context/base/mkiv/font-inj.lua @@ -261,7 +261,7 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) -- r2l local i = rawget(p,injection) if i then if leftkern ~= 0 then - i.leftkern = (i.leftkern or 0) + leftkern + i.leftkern = (i.leftkern or 0) + leftkern end if rightkern ~= 0 then i.rightkern = (i.rightkern or 0) + rightkern diff --git a/tex/context/base/mkiv/font-map.lua b/tex/context/base/mkiv/font-map.lua index e2254f8ca..37a7f03af 100644 --- a/tex/context/base/mkiv/font-map.lua +++ b/tex/context/base/mkiv/font-map.lua @@ -186,6 +186,32 @@ local function tounicode(unicode,name) end end +-- no real gain on runs +-- +-- local hash = setmetatableindex(function(t,u) +-- local v +-- if u < 0xD7FF or (u > 0xDFFF and u <= 0xFFFF) then +-- v = f_single(u) +-- else +-- u = u - 0x10000 +-- v = f_double(floor(u/1024)+0xD800,u%1024+0xDC00) +-- end +-- t[u] = v +-- return v +-- end) +-- +-- local function tounicode(unicode,name) +-- if type(unicode) == "table" then +-- local t = { } +-- for l=1,#unicode do +-- t[l] = hash[u] +-- 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-mps.lua b/tex/context/base/mkiv/font-mps.lua index 0cda202e6..6c441699b 100644 --- a/tex/context/base/mkiv/font-mps.lua +++ b/tex/context/base/mkiv/font-mps.lua @@ -262,6 +262,11 @@ local getsubtype = nuts.getsubtype local getfield = nuts.getfield local getbox = nuts.getbox local getwhd = nuts.getwhd +local getkern = nuts.getkern +local getshift = nuts.getshift +local getwidth = nuts.getwidth +local getheight = nuts.getheight +local getdepth = nuts.getdepth local effective_glue = nuts.effective_glue @@ -339,30 +344,30 @@ function fonts.metapost.boxtomp(n,kind) dx = dx + horizontal(parent,replace,xoffset+dx,yoffset) end elseif id == kern_code then - dx = dx + getfield(current,"kern") * fc + dx = dx + getkern(current) * fc elseif id == glue_code then dx = dx + effective_glue(current,parent) * fc elseif id == hlist_code then local list = getlist(current) if list then - horizontal(current,list,xoffset+dx,yoffset-getfield(current,"shift")*fc) + horizontal(current,list,xoffset+dx,yoffset-getshift(current)*fc) end - dx = dx + getfield(current,"width") * fc + dx = dx + getwidth(current) * fc elseif id == vlist_code then local list = getlist(current) if list then - vertical(current,list,xoffset+dx,yoffset-getfield(current,"shift")*fc) + vertical(current,list,xoffset+dx,yoffset-getshift(current)*fc) end - dx = dx + getfield(current,"width") * fc + dx = dx + getwidth(current) * fc elseif id == rule_code then local wd, ht, dp = getwhd(current) if wd ~= 0 then wd = wd * fc if ht == signal then - ht = getfield(parent,"height") + ht = getheight(parent) end if dp == signal then - dp = getfield(parent,"depth") + dp = getdepth(parent) end local hd = (ht + dp) * fc if hd ~= 0 and getsubtype(current) == normal_rule then @@ -377,7 +382,7 @@ function fonts.metapost.boxtomp(n,kind) end vertical = function(parent,current,xoffset,yoffset) - local dy = getfield(parent,"height") * fc + local dy = getheight(parent) * fc while current do local id = getid(current) if id == hlist_code then @@ -385,18 +390,19 @@ function fonts.metapost.boxtomp(n,kind) dy = dy - ht * fc local list = getlist(current) if list then - horizontal(current,list,xoffset+getfield(current,"shift")*fc,yoffset+dy) + horizontal(current,list,xoffset+getshift(current)*fc,yoffset+dy) end - dy = dy - ht * fc + dy = dy - dp * fc elseif id == vlist_code then - dy = dy - getfield(current,"height") * fc + local wd, ht, dp = getwhd(current) + dy = dy - ht * fc local list = getlist(current) if list then - vertical(current,list,xoffset+getfield(current,"shift")*fc,yoffset+dy) + vertical(current,list,xoffset+getshift(current)*fc,yoffset+dy) end - dy = dy - getfield(current,"depth") * fc + dy = dy - dp * fc elseif id == kern_code then - dy = dy - getfield(current,"kern") * fc + dy = dy - getkern(current) * fc elseif id == glue_code then dy = dy - effective_glue(current,parent) * fc elseif id == rule_code then @@ -404,7 +410,7 @@ function fonts.metapost.boxtomp(n,kind) local hd = (ht + dp) * fc if hd ~= 0 then if wd == signal then - wd = getfield(parent,"width") * fc + wd = getwidth(parent) * fc else wd = wd * fc end diff --git a/tex/context/base/mkiv/font-nod.lua b/tex/context/base/mkiv/font-nod.lua index 41fc215b1..2b70ee104 100644 --- a/tex/context/base/mkiv/font-nod.lua +++ b/tex/context/base/mkiv/font-nod.lua @@ -63,7 +63,11 @@ local getsubtype = nuts.getsubtype local getchar = nuts.getchar local getlist = nuts.getlist local getdisc = nuts.getdisc +local getcomponents = nuts.getcomponents local isglyph = nuts.isglyph +local getkern = nuts.getkern +local getdir = nuts.getdir +local getwidth = nuts.getwidth local setfield = nuts.setfield local setbox = nuts.setbox @@ -388,7 +392,7 @@ function step_tracers.codes(i,command,space) if id == glyph_code then showchar(c) elseif id == dir_code or id == localpar_code then - context("[%s]",getfield(c,"dir")) + context("[%s]",getdir(c)) elseif id == disc_code then local pre, post, replace = getdisc(c) if pre or post or replace then @@ -476,7 +480,7 @@ local function toutf(list,result,nofresult,stopcriterium,nostrip) for n in traverse_nodes(tonut(list)) do local c, id = isglyph(n) if c then - local components = getfield(n,"components") + local components = getcomponents(n) if components then result, nofresult = toutf(components,result,nofresult,false,true) elseif c > 0 then @@ -518,12 +522,12 @@ local function toutf(list,result,nofresult,stopcriterium,nostrip) -- end result, nofresult = toutf(getlist(n),result,nofresult,false,true) elseif id == glue_code then - if nofresult > 0 and result[nofresult] ~= " " and getfield(n,"width") > threshold then + if nofresult > 0 and result[nofresult] ~= " " and getwidth(n) > threshold then nofresult = nofresult + 1 result[nofresult] = " " end elseif id == kern_code then - if nofresult > 0 and result[nofresult] ~= " " and getfield(n,"kern") > threshold then + if nofresult > 0 and result[nofresult] ~= " " and getkern(n) > threshold then nofresult = nofresult + 1 result[nofresult] = " " end diff --git a/tex/context/base/mkiv/font-ocl.lua b/tex/context/base/mkiv/font-ocl.lua index 65a1c6342..824f09125 100644 --- a/tex/context/base/mkiv/font-ocl.lua +++ b/tex/context/base/mkiv/font-ocl.lua @@ -261,77 +261,66 @@ do end - -- function otfsvg.topdf(svgshapes) - -- local svgfile = "temp-otf-svg-shape.svg" - -- local pdffile = "temp-otf-svg-shape.pdf" - -- local command = "inkscape " .. svgfile .. " --export-pdf=" .. pdffile - -- local testrun = false - -- local pdfshapes = { } - -- local nofshapes = #svgshapes - -- local filterglyph = otfsvg.filterglyph - -- report_svg("processing %i svg containers",nofshapes) - -- statistics.starttiming() - -- for i=1,nofshapes do - -- local entry = svgshapes[i] - -- for index=entry.first,entry.last do - -- local data = filterglyph(entry,index) - -- savedata(svgfile,tostring(data)) - -- if data and data ~= "" then - -- report_svg("processing svg shape of glyph %i in container %i",index,i) - -- os.execute(command) - -- pdfshapes[index] = loaddata(pdffile) - -- end - -- end - -- if testrun and i > testrun then - -- report_svg("quiting test run") - -- break - -- end - -- end - -- remove(svgfile) - -- statistics.stoptiming() - -- report_svg("conversion time: %0.3f",statistics.elapsedtime()) - -- return pdfshapes - -- end + local runner = sandbox and sandbox.registerrunner { + name = "otfsvg", + program = "inkscape", + method = "pipeto", + template = "--shell > temp-otf-svg-shape.log", + reporter = report_svg, + } + + if notrunner then + -- + -- poor mans variant for generic: + -- + runner = function() + return io.open("inkscape --shell > temp-otf-svg-shape.log","w") + end + end function otfsvg.topdf(svgshapes) - local inkscape = io.popen("inkscape --shell > temp-otf-svg-shape.log","w") - local pdfshapes = { } - local nofshapes = #svgshapes - local f_svgfile = formatters["temp-otf-svg-shape-%i.svg"] - local f_pdffile = formatters["temp-otf-svg-shape-%i.pdf"] - local f_convert = formatters["%s --export-pdf=%s\n"] - local filterglyph = otfsvg.filterglyph - report_svg("processing %i svg containers",nofshapes) - statistics.starttiming() - for i=1,nofshapes do - local entry = svgshapes[i] - for index=entry.first,entry.last do - local data = filterglyph(entry,index) - if data and data ~= "" then - local svgfile = f_svgfile(index) - local pdffile = f_pdffile(index) - savedata(svgfile,data) - inkscape:write(f_convert(svgfile,pdffile)) - pdfshapes[index] = true + local pdfshapes = { } + local inkscape = runner() + if inkscape then + local nofshapes = #svgshapes + local f_svgfile = formatters["temp-otf-svg-shape-%i.svg"] + local f_pdffile = formatters["temp-otf-svg-shape-%i.pdf"] + local f_convert = formatters["%s --export-pdf=%s\n"] + local filterglyph = otfsvg.filterglyph + local nofdone = 0 + report_svg("processing %i svg containers",nofshapes) + statistics.starttiming() + for i=1,nofshapes do + local entry = svgshapes[i] + for index=entry.first,entry.last do + local data = filterglyph(entry,index) + if data and data ~= "" then + local svgfile = f_svgfile(index) + local pdffile = f_pdffile(index) + savedata(svgfile,data) + inkscape:write(f_convert(svgfile,pdffile)) + pdfshapes[index] = true + nofdone = nofdone + 1 + if nofdone % 100 == 0 then + report_svg("%i shapes processed",nofdone) + end + end end end - end - inkscape:write("quit\n") - -- while inkscape:read("*a") do - -- os.sleep(0.1) - -- end - inkscape:close() - report_svg("processing %i pdf results",nofshapes) - for index in next, pdfshapes do - local svgfile = f_svgfile(index) - local pdffile = f_pdffile(index) - pdfshapes[index] = loaddata(pdffile) - remove(svgfile) - remove(pdffile) - end - statistics.stoptiming() - if statistics.elapsedseconds then - report_svg("svg conversion time %s",statistics.elapsedseconds()) + inkscape:write("quit\n") + inkscape:close() + report_svg("processing %i pdf results",nofshapes) + for index in next, pdfshapes do + local svgfile = f_svgfile(index) + local pdffile = f_pdffile(index) + pdfshapes[index] = loaddata(pdffile) + remove(svgfile) + remove(pdffile) + end + statistics.stoptiming() + if statistics.elapsedseconds then + report_svg("svg conversion time %s",statistics.elapsedseconds()) + end end return pdfshapes end diff --git a/tex/context/base/mkiv/font-osd.lua b/tex/context/base/mkiv/font-osd.lua index b67cc9241..ca20f6782 100644 --- a/tex/context/base/mkiv/font-osd.lua +++ b/tex/context/base/mkiv/font-osd.lua @@ -1140,6 +1140,7 @@ function handlers.devanagari_reorder_matras(head,start) -- no leak head = remove_node(head,start) setlink(start,next) setlink(current,start) + -- setlink(current,start,next) -- maybe start = startnext break end @@ -1199,6 +1200,7 @@ function handlers.devanagari_reorder_reph(head,start) head = remove_node(head,start) setlink(start,next) setlink(current,start) + -- setlink(current,start,next) -- maybe start = startnext startattr = getprop(start,a_syllabe) break @@ -1216,9 +1218,9 @@ function handlers.devanagari_reorder_reph(head,start) if getprop(current,a_state) == s_pstf then -- post-base startnext = getnext(start) head = remove_node(head,start) - local prev = getprev(current) - setlink(prev,start) + setlink(getprev(current),start) setlink(start,current) + -- setlink(getprev(current),start,current) -- maybe start = startnext startattr = getprop(start,a_syllabe) break @@ -1250,9 +1252,9 @@ function handlers.devanagari_reorder_reph(head,start) if c then startnext = getnext(start) head = remove_node(head,start) - local prev = getprev(c) - setlink(prev,start) + setlink(getprev(c),start) setlink(start,c) + -- setlink(getprev(c),start,c) -- maybe -- end start = startnext startattr = getprop(start,a_syllabe) @@ -1274,9 +1276,9 @@ function handlers.devanagari_reorder_reph(head,start) if start ~= current then startnext = getnext(start) head = remove_node(head,start) - local next = getnext(current) - setlink(start,next) + setlink(start,getnext(current)) setlink(current,start) + -- setlink(current,start,getnext(current)) -- maybe start = startnext end end @@ -1320,6 +1322,7 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start) removenode(start,start) setlink(start,next) setlink(current,start) + -- setlink(current,start,next) -- maybe start = startnext break end @@ -1337,9 +1340,9 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start) if not consonant[char] and getprop(current,a_state) then -- main startnext = getnext(start) removenode(start,start) - local prev = getprev(current) - setlink(prev,start) + setlink(getprev(current),start) setlink(start,current) + -- setlink(getprev(current),start,current) -- maybe start = startnext break end @@ -1690,9 +1693,9 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) -- maybe do a pa end start = current end - local prev = getprev(halfpos) - setlink(prev,current) + setlink(getprev(halfpos),current) setlink(current,halfpos) + -- setlink(getprev(halfpos),current,halfpos) -- maybe halfpos = current elseif above_mark[char] then -- After main consonant target = basepos @@ -1721,9 +1724,9 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) -- maybe do a pa if current == stop then stop = prev end - local next = getnext(target) - setlink(current,next) + setlink(current,getnext(target)) setlink(target,current) + -- setlink(target,current,getnext(target)) -- maybe end end end @@ -1750,8 +1753,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) -- maybe do a pa if stop == next then stop = current end - local prev = getprev(c) - setlink(prev,next) + setlink(getprev(c),next) local nextnext = getnext(next) setnext(current,nextnext) local nextnextnext = getnext(nextnext) diff --git a/tex/context/base/mkiv/font-ota.lua b/tex/context/base/mkiv/font-ota.lua index b8944e0c0..232c2586a 100644 --- a/tex/context/base/mkiv/font-ota.lua +++ b/tex/context/base/mkiv/font-ota.lua @@ -32,7 +32,6 @@ local a_state = attributes.private('state') local nuts = nodes.nuts local tonut = nuts.tonut -local getfield = nuts.getfield local getnext = nuts.getnext local getprev = nuts.getprev local getprev = nuts.getprev diff --git a/tex/context/base/mkiv/font-otf.lua b/tex/context/base/mkiv/font-otf.lua index 09e810857..1db80272e 100644 --- a/tex/context/base/mkiv/font-otf.lua +++ b/tex/context/base/mkiv/font-otf.lua @@ -24,7 +24,6 @@ local gmatch, gsub, find, match, lower, strip = string.gmatch, string.gsub, stri local type, next, tonumber, tostring = type, next, tonumber, tostring local abs = math.abs local reversed, concat, insert, remove, sortedkeys = table.reversed, table.concat, table.insert, table.remove, table.sortedkeys -local ioflush = io.flush local fastcopy, tohash, derivetable, copy = table.fastcopy, table.tohash, table.derive, table.copy local formatters = string.formatters local P, R, S, C, Ct, lpegmatch = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Ct, lpeg.match diff --git a/tex/context/base/mkiv/font-otj.lua b/tex/context/base/mkiv/font-otj.lua index 68cf608ec..fdee3513f 100644 --- a/tex/context/base/mkiv/font-otj.lua +++ b/tex/context/base/mkiv/font-otj.lua @@ -16,12 +16,9 @@ if not modules then modules = { } end modules ['font-otj'] = { -- cleaner to have an identification pass here. Also, I need to keep tracing in mind so -- being too clever here is dangerous. --- The subtype test is not needed as there will be no (new) properties set, given that we --- reset the properties. - -- As we have a rawget on properties we don't need one on injections. --- The use_advance code is just a test and is meant for testing and manuals. There is no +-- The use_advance code was just a test and is meant for testing and manuals. There is no -- performance (or whatever) gain and using kerns is somewhat cleaner (at least for now). -- Maybe: subtype fontkern when pure kerns. @@ -38,10 +35,6 @@ local trace_marks = false registertracker("fonts.injections.marks", fun local trace_cursive = false registertracker("fonts.injections.cursive", function(v) trace_cursive = v end) local trace_spaces = false registertracker("fonts.injections.spaces", function(v) trace_spaces = v end) --- use_advance is just an experiment: it makes copying glyphs (instead of new_glyph) dangerous - -local use_advance = false directives.register("fonts.injections.advance", function(v) use_advance = v end) - local report_injections = logs.reporter("fonts","injections") local report_spaces = logs.reporter("fonts","spaces") @@ -80,14 +73,18 @@ local getnext = nuts.getnext local getprev = nuts.getprev local getid = nuts.getid local getfont = nuts.getfont -local getsubtype = nuts.getsubtype local getchar = nuts.getchar +local getoffsets = nuts.getoffsets local getboth = nuts.getboth - -local ischar = nuts.is_char - local getdisc = nuts.getdisc local setdisc = nuts.setdisc +local setoffsets = nuts.setoffsets +local ischar = nuts.is_char +local getkern = nuts.getkern +local setkern = nuts.setkern +local setlink = nuts.setlink +local setwidth = nuts.setwidth +local getwidth = nuts.getwidth local traverse_id = nuts.traverse_id local traverse_char = nuts.traverse_char @@ -137,7 +134,7 @@ end -- if tp then -- tp.injections = si -- else --- propertydata[target] = { +-- properties[target] = { -- injections = si, -- } -- end @@ -169,7 +166,7 @@ function injections.copy(target,source) if tp then tp.injections = si else - propertydata[target] = { + properties[target] = { injections = si, } end @@ -527,11 +524,12 @@ local function show_result(head) while current do local id = getid(current) if id == glyph_code then - report_injections("char: %C, width %p, xoffset %p, yoffset %p", - getchar(current),getfield(current,"width"),getfield(current,"xoffset"),getfield(current,"yoffset")) + local w = getwidth(current) + local x, y = getoffsets(current) + report_injections("char: %C, width %p, xoffset %p, yoffset %p",getchar(current),w,x,y) skipping = false elseif id == kern_code then - report_injections("kern: %p",getfield(current,"kern")) + report_injections("kern: %p",getkern(current)) skipping = false elseif not skipping then report_injections() @@ -566,76 +564,65 @@ local function inject_kerns_only(head,where) local posttail = nil -- saves a lookup local replacetail = nil -- saves a lookup while current do - local id = getid(current) local next = getnext(current) - if id == glyph_code then - if getsubtype(current) < 256 then - local p = rawget(properties,current) - if p then - -- local i = rawget(p,"injections") - local i = p.injections - if i then - -- left|glyph|right - local leftkern = i.leftkern - if leftkern and leftkern ~= 0 then - if use_advance then - setfield(current,"xoffset",leftkern) - setfield(current,"xadvance",leftkern) - else - insert_node_before(head,current,newkern(leftkern)) + local char, id = ischar(current) + if char then + local p = rawget(properties,current) + if p then + -- local i = rawget(p,"injections") + local i = p.injections + if i then + -- left|glyph|right + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + insert_node_before(head,current,newkern(leftkern)) + end + end + if prevdisc then + local done = false + if post then + -- local i = rawget(p,"postinjections") + local i = p.postinjections + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + setlink(posttail,newkern(leftkern)) + done = true end end end - if prevdisc then - local done = false - if post then - -- local i = rawget(p,"postinjections") - local i = p.postinjections - if i then - local leftkern = i.leftkern - if leftkern and leftkern ~= 0 then - if use_advance then - setfield(post,"xadvance",leftkern) - else - insert_node_after(post,posttail,newkern(leftkern)) - done = true - end - end + if replace then + -- local i = rawget(p,"replaceinjections") + local i = p.replaceinjections + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + setlink(replacetail,newkern(leftkern)) + done = true end end - if replace then - -- local i = rawget(p,"replaceinjections") - local i = p.replaceinjections - if i then - local leftkern = i.leftkern - if leftkern and leftkern ~= 0 then - if use_advance then - setfield(replace,"xadvance",leftkern) - else - insert_node_after(replace,replacetail,newkern(leftkern)) - done = true - end - end - end - else - -- local i = rawget(p,"emptyinjections") - local i = p.emptyinjections - if i then - -- glyph|disc|glyph (special case) - local leftkern = i.leftkern - if leftkern and leftkern ~= 0 then - setfield(prev,"replace",newkern(leftkern)) -- maybe also leftkern - end + else + -- local i = rawget(p,"emptyinjections") + local i = p.emptyinjections + if i then + -- glyph|disc|glyph (special case) + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + setfield(prev,"replace",newkern(leftkern)) -- maybe also leftkern end end - if done then - setdisc(prevdisc,pre,post,replace) - end + end + if done then + setdisc(prevdisc,pre,post,replace) end end end prevdisc = nil prevglyph = current + elseif char == false then + -- other font + prevdisc = nil + prevglyph = current elseif id == disc_code then pre, post, replace, pretail, posttail, replacetail = getdisc(current,true) local done = false @@ -649,13 +636,8 @@ local function inject_kerns_only(head,where) if i then local leftkern = i.leftkern if leftkern and leftkern ~= 0 then - if use_advance then - setfield(pre,"xoffset",leftkern) - setfield(pre,"xadvance",leftkern) - else - pre = insert_node_before(pre,n,newkern(leftkern)) - done = true - end + pre = insert_node_before(pre,n,newkern(leftkern)) + done = true end end end @@ -671,13 +653,8 @@ local function inject_kerns_only(head,where) if i then local leftkern = i.leftkern if leftkern and leftkern ~= 0 then - if use_advance then - setfield(post,"xoffset",leftkern) - setfield(post,"xadvance",leftkern) - else - post = insert_node_before(post,n,newkern(leftkern)) - done = true - end + post = insert_node_before(post,n,newkern(leftkern)) + done = true end end end @@ -693,13 +670,8 @@ local function inject_kerns_only(head,where) if i then local leftkern = i.leftkern if leftkern and leftkern ~= 0 then - if use_advance then - setfield(replace,"xoffset",leftkern) - setfield(replace,"xadvance",leftkern) - else - replace = insert_node_before(replace,n,newkern(leftkern)) - done = true - end + replace = insert_node_before(replace,n,newkern(leftkern)) + done = true end end end @@ -743,87 +715,88 @@ local function inject_pairs_only(head,where) local posttail = nil -- saves a lookup local replacetail = nil -- saves a lookup while current do - local id = getid(current) local next = getnext(current) - if id == glyph_code then - if getsubtype(current) < 256 then - local p = rawget(properties,current) - if p then - -- local i = rawget(p,"injections") - local i = p.injections + local char, id = ischar(current) + if char then + local p = rawget(properties,current) + if p then + -- local i = rawget(p,"injections") + local i = p.injections + if i then + -- left|glyph|right + local yoffset = i.yoffset + if yoffset and yoffset ~= 0 then + setoffsets(current,false,yoffset) + end + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + head = insert_node_before(head,current,newkern(leftkern)) + end + local rightkern = i.rightkern + if rightkern and rightkern ~= 0 then + insert_node_after(head,current,newkern(rightkern)) + end + else + -- local i = rawget(p,"emptyinjections") + local i = p.emptyinjections if i then - -- left|glyph|right - local yoffset = i.yoffset - if yoffset and yoffset ~= 0 then - setfield(current,"yoffset",yoffset) - end - local leftkern = i.leftkern - if leftkern and leftkern ~= 0 then - head = insert_node_before(head,current,newkern(leftkern)) - end + -- glyph|disc|glyph (special case) +-- is this okay? local rightkern = i.rightkern if rightkern and rightkern ~= 0 then - insert_node_after(head,current,newkern(rightkern)) - end - else - -- local i = rawget(p,"emptyinjections") - local i = p.emptyinjections - if i then - -- glyph|disc|glyph (special case) --- is this okay? - local rightkern = i.rightkern - if rightkern and rightkern ~= 0 then - if next and getid(next) == disc_code then - if replace then - -- error, we expect an empty one - else - setfield(next,"replace",newkern(rightkern)) -- maybe also leftkern - end + if next and getid(next) == disc_code then + if replace then + -- error, we expect an empty one + else + setfield(next,"replace",newkern(rightkern)) -- maybe also leftkern end end end end - if prevdisc then - local done = false - if post then - -- local i = rawget(p,"postinjections") - local i = p.postinjections - if i then - local leftkern = i.leftkern - if leftkern and leftkern ~= 0 then - insert_node_after(post,posttail,newkern(leftkern)) - done = true - end + end + if prevdisc then + local done = false + if post then + -- local i = rawget(p,"postinjections") + local i = p.postinjections + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + setlink(posttail,newkern(leftkern)) + done = true end end - if replace then - -- local i = rawget(p,"replaceinjections") - local i = p.replaceinjections - if i then - local leftkern = i.leftkern - if leftkern and leftkern ~= 0 then - insert_node_after(replace,replacetail,newkern(leftkern)) - done = true - end - end - else - local i = p.emptyinjections - if i then --- new .. okay? - local leftkern = i.leftkern - if leftkern and leftkern ~= 0 then - setfield(prev,"replace",newkern(leftkern)) -- maybe also leftkern - end + end + if replace then + -- local i = rawget(p,"replaceinjections") + local i = p.replaceinjections + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + setlink(replacetail,newkern(leftkern)) + done = true end end - if done then - setdisc(prevdisc,pre,post,replace) + else + local i = p.emptyinjections + if i then + -- new .. okay? + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + setfield(prev,"replace",newkern(leftkern)) -- maybe also leftkern + end end end + if done then + setdisc(prevdisc,pre,post,replace) + end end end prevdisc = nil prevglyph = current + elseif char == false then + prevdisc = nil + prevglyph = current elseif id == disc_code then pre, post, replace, pretail, posttail, replacetail = getdisc(current,true) local done = false @@ -837,7 +810,7 @@ local function inject_pairs_only(head,where) if i then local yoffset = i.yoffset if yoffset and yoffset ~= 0 then - setfield(n,"yoffset",yoffset) + setoffsets(n,false,yoffset) end local leftkern = i.leftkern if leftkern and leftkern ~= 0 then @@ -863,7 +836,7 @@ local function inject_pairs_only(head,where) if i then local yoffset = i.yoffset if yoffset and yoffset ~= 0 then - setfield(n,"yoffset",yoffset) + setoffsets(n,false,yoffset) end local leftkern = i.leftkern if leftkern and leftkern ~= 0 then @@ -889,7 +862,7 @@ local function inject_pairs_only(head,where) if i then local yoffset = i.yoffset if yoffset and yoffset ~= 0 then - setfield(n,"yoffset",yoffset) + setoffsets(n,false,yoffset) end local leftkern = i.leftkern if leftkern and leftkern ~= 0 then @@ -958,30 +931,9 @@ local function inject_pairs_only(head,where) return tonode(head), true end --- local function showoffset(n,flag) --- local ox = getfield(n,"xoffset") --- local oy = getfield(n,"yoffset") --- if flag then --- if ox == 0 then --- setcolor(n,oy == 0 and "darkgray" or "darkgreen") --- else --- setcolor(n,oy == 0 and "darkblue" or "darkred") --- end --- else --- if ox == 0 then --- setcolor(n,oy == 0 and "gray" or "green") --- else --- setcolor(n,oy == 0 and "blue" or "red") --- end --- end --- end - local function showoffset(n,flag) - local o = getfield(n,"xoffset") - if o == 0 then - o = getfield(n,"yoffset") - end - if o ~= 0 then + local x, y = getoffsets(n) + if x ~= 0 or y ~= 0 then setcolor(n,flag and "darkred" or "darkgreen") else resetcolor(n) @@ -1021,7 +973,8 @@ local function inject_everything(head,where) -- move out -- local function processmark(p,n,pn) -- p = basenode - local px = getfield(p,"xoffset") + local px, py = getoffsets(p) + local nx, ny = getoffsets(n) local ox = 0 local rightkern = nil local pp = rawget(properties,p) @@ -1039,7 +992,7 @@ local function inject_everything(head,where) -- report_injections("r2l case 1: %p",ox) else -- kern(x) glyph(p) kern(w-x) mark(n) - -- ox = px - getfield(p,"width") + pn.markx - pp.leftkern + -- ox = px - getwidth(p) + pn.markx - pp.leftkern -- -- According to Kai we don't need to handle leftkern here but I'm -- pretty sure I've run into a case where it was needed so maybe @@ -1062,12 +1015,12 @@ local function inject_everything(head,where) -- ox = px - pn.markx -- -- report_injections("r2l case 3: %p",ox) -- else - -- -- ox = px - getfield(p,"width") + pn.markx + -- -- ox = px - getwidth(p) + pn.markx ox = px - pn.markx -- report_injections("l2r case 3: %p",ox) -- end if pn.checkmark then - local wn = getfield(n,"width") -- in arial marks have widths + local wn = getwidth(n) -- in arial marks have widths if wn ~= 0 then wn = wn/2 if trace_injections then @@ -1084,167 +1037,168 @@ local function inject_everything(head,where) end end end - local oy = getfield(n,"yoffset") + getfield(p,"yoffset") + pn.marky - setfield(n,"xoffset",ox) - setfield(n,"yoffset",oy) + local oy = ny + py + pn.marky + setoffsets(n,ox,oy) if trace_marks then showoffset(n,true) end end -- todo: marks in disc while current do - local id = getid(current) local next = getnext(current) - if id == glyph_code then - if getsubtype(current) < 256 then - local p = rawget(properties,current) - if p then - -- local i = rawget(p,"injections") - local i = p.injections - if i then - local pm = i.markbasenode - if pm then - nofmarks = nofmarks + 1 - marks[nofmarks] = current - else - local yoffset = i.yoffset - if yoffset and yoffset ~= 0 then - setfield(current,"yoffset",yoffset) - end - if hascursives then - local cursivex = i.cursivex - if cursivex then - if cursiveanchor then - if cursivex ~= 0 then - i.leftkern = (i.leftkern or 0) + cursivex - end - if maxc == 0 then - minc = 1 - maxc = 1 - glyphs[1] = cursiveanchor - else - maxc = maxc + 1 - glyphs[maxc] = cursiveanchor - end - properties[cursiveanchor].cursivedy = i.cursivey -- cursiveprops - last = current + local char, id = ischar(current) + if char then + local p = rawget(properties,current) + if p then + -- local i = rawget(p,"injections") + local i = p.injections + if i then + local pm = i.markbasenode + if pm then + nofmarks = nofmarks + 1 + marks[nofmarks] = current + else + local yoffset = i.yoffset + if yoffset and yoffset ~= 0 then + setoffsets(current,false,yoffset) + end + if hascursives then + local cursivex = i.cursivex + if cursivex then + if cursiveanchor then + if cursivex ~= 0 then + i.leftkern = (i.leftkern or 0) + cursivex + end + if maxc == 0 then + minc = 1 + maxc = 1 + glyphs[1] = cursiveanchor else - maxc = 0 + maxc = maxc + 1 + glyphs[maxc] = cursiveanchor + end + properties[cursiveanchor].cursivedy = i.cursivey -- cursiveprops + last = current + else + maxc = 0 + end + elseif maxc > 0 then + local nx, ny = getoffsets(current) + for i=maxc,minc,-1 do + local ti = glyphs[i] + ny = ny + properties[ti].cursivedy + setoffsets(ti,false,ny) -- why not add ? + if trace_cursive then + showoffset(ti) end - elseif maxc > 0 then - local ny = getfield(current,"yoffset") + end + maxc = 0 + cursiveanchor = nil + end + if i.cursiveanchor then + cursiveanchor = current -- no need for both now + else + if maxc > 0 then + local nx, ny = getoffsets(current) for i=maxc,minc,-1 do local ti = glyphs[i] ny = ny + properties[ti].cursivedy - setfield(ti,"yoffset",ny) -- why not add ? + setoffsets(ti,false,ny) -- why not add ? if trace_cursive then showoffset(ti) end end maxc = 0 - cursiveanchor = nil - end - if i.cursiveanchor then - cursiveanchor = current -- no need for both now - else - if maxc > 0 then - local ny = getfield(current,"yoffset") - for i=maxc,minc,-1 do - local ti = glyphs[i] - ny = ny + properties[ti].cursivedy - setfield(ti,"yoffset",ny) -- why not add ? - if trace_cursive then - showoffset(ti) - end - end - maxc = 0 - end - cursiveanchor = nil end - end - -- left|glyph|right - local leftkern = i.leftkern - if leftkern and leftkern ~= 0 then - insert_node_before(head,current,newkern(leftkern)) - end - local rightkern = i.rightkern - if rightkern and rightkern ~= 0 then - insert_node_after(head,current,newkern(rightkern)) + cursiveanchor = nil end end - else - -- local i = rawget(p,"emptyinjections") - local i = p.emptyinjections - if i then - -- glyph|disc|glyph (special case) - -- okay? - local rightkern = i.rightkern - if rightkern and rightkern ~= 0 then - if next and getid(next) == disc_code then - if replace then - -- error, we expect an empty one - else - setfield(next,"replace",newkern(rightkern)) -- maybe also leftkern - end + -- left|glyph|right + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + insert_node_before(head,current,newkern(leftkern)) + end + local rightkern = i.rightkern + if rightkern and rightkern ~= 0 then + insert_node_after(head,current,newkern(rightkern)) + end + end + else + -- local i = rawget(p,"emptyinjections") + local i = p.emptyinjections + if i then + -- glyph|disc|glyph (special case) + -- okay? + local rightkern = i.rightkern + if rightkern and rightkern ~= 0 then + if next and getid(next) == disc_code then + if replace then + -- error, we expect an empty one + else + setfield(next,"replace",newkern(rightkern)) -- maybe also leftkern end end end end - if prevdisc then - if p then - local done = false - if post then - -- local i = rawget(p,"postinjections") - local i = p.postinjections - if i then - local leftkern = i.leftkern - if leftkern and leftkern ~= 0 then - insert_node_after(post,posttail,newkern(leftkern)) - done = true - end + end + if prevdisc then + if p then + local done = false + if post then + -- local i = rawget(p,"postinjections") + local i = p.postinjections + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + setlink(posttail,newkern(leftkern)) + done = true end end - if replace then - -- local i = rawget(p,"replaceinjections") - local i = p.replaceinjections - if i then - local leftkern = i.leftkern - if leftkern and leftkern ~= 0 then - insert_node_after(replace,replacetail,newkern(leftkern)) - done = true - end - end - else - -- local i = rawget(p,"emptyinjections") - local i = p.emptyinjections - if i then - local leftkern = i.leftkern - if leftkern and leftkern ~= 0 then - setfield(prev,"replace",newkern(leftkern)) -- maybe also leftkern - end + end + if replace then + -- local i = rawget(p,"replaceinjections") + local i = p.replaceinjections + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + setlink(replacetail,newkern(leftkern)) + done = true end end - if done then - setdisc(prevdisc,pre,post,replace) + else + -- local i = rawget(p,"emptyinjections") + local i = p.emptyinjections + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + setfield(prev,"replace",newkern(leftkern)) -- maybe also leftkern + end end end - end - else - -- cursive - if hascursives and maxc > 0 then - local ny = getfield(current,"yoffset") - for i=maxc,minc,-1 do - local ti = glyphs[i] - ny = ny + properties[ti].cursivedy - setfield(ti,"yoffset",getfield(ti,"yoffset") + ny) -- can be mark + if done then + setdisc(prevdisc,pre,post,replace) end - maxc = 0 - cursiveanchor = nil end end + else + -- cursive + if hascursives and maxc > 0 then + local nx, ny = getoffsets(current) + for i=maxc,minc,-1 do + local ti = glyphs[i] + ny = ny + properties[ti].cursivedy + local xi, yi = getoffsets(ti) + setoffsets(ti,xi,yi + ny) -- can be mark, we could use properties + end + maxc = 0 + cursiveanchor = nil + end end prevdisc = nil prevglyph = current + elseif char == false then + prevdisc = nil + prevglyph = current elseif id == disc_code then pre, post, replace, pretail, posttail, replacetail = getdisc(current,true) local done = false @@ -1258,7 +1212,7 @@ local function inject_everything(head,where) if i then local yoffset = i.yoffset if yoffset and yoffset ~= 0 then - setfield(n,"yoffset",yoffset) + setoffsets(n,false,yoffset) end local leftkern = i.leftkern if leftkern and leftkern ~= 0 then @@ -1290,7 +1244,7 @@ local function inject_everything(head,where) if i then local yoffset = i.yoffset if yoffset and yoffset ~= 0 then - setfield(n,"yoffset",yoffset) + setoffsets(n,false,yoffset) end local leftkern = i.leftkern if leftkern and leftkern ~= 0 then @@ -1322,7 +1276,7 @@ local function inject_everything(head,where) if i then local yoffset = i.yoffset if yoffset and yoffset ~= 0 then - setfield(n,"yoffset",yoffset) + setoffsets(n,false,yoffset) end local leftkern = i.leftkern if leftkern and leftkern ~= 0 then @@ -1390,11 +1344,11 @@ local function inject_everything(head,where) end -- cursive if hascursives and maxc > 0 then - local ny = getfield(last,"yoffset") + local nx, ny = getoffsets(last) for i=maxc,minc,-1 do local ti = glyphs[i] ny = ny + properties[ti].cursivedy - setfield(ti,"yoffset",ny) -- why not add ? + setoffsets(ti,false,ny) -- why not add ? if trace_cursive then showoffset(ti) end @@ -1470,9 +1424,9 @@ end injections.getthreshold = getthreshold -function injections.isspace(n,threshold) - if getid(n) == glue_code then - local w = getfield(n,"width") +function injections.isspace(n,threshold,id) + if (id or getid(n)) == glue_code then + local w = getwidth(n) if threshold and w > threshold then -- was >= return 32 end @@ -1531,32 +1485,32 @@ local function injectspaces(head) end end if leftkern then - local old = getfield(n,"width") + local old = getwidth(n) if old > threshold then if rightkern then local new = old + (leftkern + rightkern) * factor if trace_spaces then report_spaces("%C [%p -> %p] %C",prevchar,old,new,nextchar) end - setfield(n,"width",new) + setwidth(n,new) leftkern = false else local new = old + leftkern * factor if trace_spaces then report_spaces("%C [%p -> %p]",prevchar,old,new) end - setfield(n,"width",new) + setwidth(n,new) end end leftkern = false elseif rightkern then - local old = getfield(n,"width") + local old = getwidth(n) if old > threshold then local new = old + rightkern * factor if trace_spaces then report_spaces("[%p -> %p] %C",nextchar,old,new) end - setfield(n,"width",new) + setwidth(n,new) end rightkern = false end diff --git a/tex/context/base/mkiv/font-otl.lua b/tex/context/base/mkiv/font-otl.lua index d4eaed763..4b97a90a2 100644 --- a/tex/context/base/mkiv/font-otl.lua +++ b/tex/context/base/mkiv/font-otl.lua @@ -23,7 +23,7 @@ if not modules then modules = { } end modules ['font-otl'] = { -- todo: less tounicodes -local gmatch, find, match, lower, strip = string.gmatch, string.find, string.match, string.lower, string.strip +local lower = string.lower local type, next, tonumber, tostring, unpack = type, next, tonumber, tostring, unpack local abs = math.abs local derivetable = table.derive @@ -127,26 +127,26 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone hash = hash .. "-" .. sub end hash = containers.cleanname(hash) - local featurefiles - if featurefile then - featurefiles = { } - for s in gmatch(featurefile,"[^,]+") do - local name = resolvers.findfile(file.addsuffix(s,'fea'),'fea') or "" - if name == "" then - report_otf("loading error, no featurefile %a",s) - else - local attr = lfs.attributes(name) - featurefiles[#featurefiles+1] = { - name = name, - size = attr and attr.size or 0, - time = attr and attr.modification or 0, - } - end - end - if #featurefiles == 0 then - featurefiles = nil - end - end + -- local featurefiles + -- if featurefile then + -- featurefiles = { } + -- for s in gmatch(featurefile,"[^,]+") do + -- local name = resolvers.findfile(file.addsuffix(s,'fea'),'fea') or "" + -- if name == "" then + -- report_otf("loading error, no featurefile %a",s) + -- else + -- local attr = lfs.attributes(name) + -- featurefiles[#featurefiles+1] = { + -- name = name, + -- size = attr and attr.size or 0, + -- time = attr and attr.modification or 0, + -- } + -- end + -- end + -- if #featurefiles == 0 then + -- featurefiles = nil + -- end + -- end local data = containers.read(otf.cache,hash) local reload = not data or data.size ~= size or data.time ~= time or data.tableversion ~= otfreaders.tableversion if forceload then @@ -252,6 +252,21 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone end -- data.metadata.math = data.resources.mathconstants + -- + -- delayed tables (experiment) + -- + local classes = data.resources.classes + if not classes then + local descriptions = data.descriptions + classes = setmetatableindex(function(t,k) + local d = descriptions[k] + local v = (d and d.class or "base") or false + t[k] = v + return v + end) + data.resources.classes = classes + end + -- end return data diff --git a/tex/context/base/mkiv/font-ots.lua b/tex/context/base/mkiv/font-ots.lua index 1f8421481..4d8c0fcdd 100644 --- a/tex/context/base/mkiv/font-ots.lua +++ b/tex/context/base/mkiv/font-ots.lua @@ -6,73 +6,45 @@ if not modules then modules = { } end modules ['font-ots'] = { -- sequences license = "see context related readme files", } --- to be checked: discrun doesn't seem to do something useful now (except run the --- check again) so if we need it again we'll do a zwnjrun or so - --- components will go away and be replaced by a property table which simplifies --- code (also more efficient) - --- beware, on my development machine we test a slightly a more optimized version - --- assumptions: --- --- cursives don't cross discretionaries --- marks precede bases --- --- pitfalls: --- --- when we append to a dics field we need to set the field in order to update tail --- --- This is a version of font-otn.lua adapted to the new font loader code. It --- is a context version which can contain experimental code, but when we --- have serious patches we will backport to the font-otn files. The plain --- loader that ships with context also uses this now. --- --- todo: looks like we have a leak somewhere (probably in ligatures) --- todo: copy attributes to disc --- todo: get rid of components, better use the tounicode entry if needed (at all) --- --- we do some disc juggling where we need to keep in mind that the --- pre, post and replace fields can have prev pointers to a nesting --- node ... i wonder if that is still needed --- --- not possible: --- --- \discretionary {alpha-} {betagammadelta} --- {\discretionary {alphabeta-} {gammadelta} --- {\discretionary {alphabetagamma-} {delta} --- {alphabetagammadelta}}} - --[[ldx-- <p>This module is a bit more split up that I'd like but since we also want to test with plain <l n='tex'/> it has to be so. This module is part of <l n='context'/> and discussion about improvements and functionality mostly happens on the <l n='context'/> mailing list.</p> -<p>The specification of OpenType is kind of vague. Apart from a lack of a proper -free specifications there's also the problem that Microsoft and Adobe -may have their own interpretation of how and in what order to apply features. -In general the Microsoft website has more detailed specifications and is a -better reference. There is also some information in the FontForge help files.</p> +<p>The specification of OpenType is (or at least a decade ago was) kind of vague. +Apart from a lack of a proper free specifications there's also the problem that +Microsoft and Adobe may have their own interpretation of how and in what order to +apply features. In general the Microsoft website has more detailed specifications +and is a better reference. There is also some information in the FontForge help +files. In the end we rely most on the Microsoft specification.</p> <p>Because there is so much possible, fonts might contain bugs and/or be made to work with certain rederers. These may evolve over time which may have the side -effect that suddenly fonts behave differently.</p> +effect that suddenly fonts behave differently. We don't want to catch all font +issues.</p> -<p>After a lot of experiments (mostly by Taco, me and Idris) we're now at yet another -implementation. Of course all errors are mine and of course the code can be -improved. There are quite some optimizations going on here and processing speed -is currently acceptable. Not all functions are implemented yet, often because I -lack the fonts for testing. Many scripts are not yet supported either, but I will -look into them as soon as <l n='context'/> users ask for it.</p> +<p>After a lot of experiments (mostly by Taco, me and Idris) the first implementation +becaus quite useful. When it did most of what we wanted, a more optimized version +evolved. Of course all errors are mine and of course the code can be improved. There +are quite some optimizations going on here and processing speed is currently quite +acceptable and has been improved over time. Many complex scripts are not yet supported +yet, but I will look into them as soon as <l n='context'/> users ask for it.</p> -<p>The specification leaves room for interpretation. In case of doubt the microsoft +<p>The specification leaves room for interpretation. In case of doubt the Microsoft implementation is the reference as it is the most complete one. As they deal with lots of scripts and fonts, Kai and Ivo did a lot of testing of the generic code and their suggestions help improve the code. I'm aware that not all border cases can be taken care of, unless we accept excessive runtime, and even then the interference with other mechanisms (like hyphenation) are not trivial.</p> +<p>Especially discretionary handling has been improved much by Kai Eigner who uses complex +(latin) fonts. The current implementation is a compromis between his patches and my code +and in the meantime performance is quite ok. We cannot check all border cases without +compromising speed but so far we're okay. Given good test cases we can probably improve +it here and there. Especially chain lookups are non trivial with discretionaries but +things got much better over time thanks to Kai.</p> + <p>Glyphs are indexed not by unicode but in their own way. This is because there is no relationship with unicode at all, apart from the fact that a font might cover certain ranges of characters. One character can have multiple shapes. However, at the @@ -84,33 +56,74 @@ then in the output eventually.</p> that different from the one produced by <l n='fontforge'/> but we uses hashes instead. In <l n='context'/> that table is packed (similar tables are shared) and cached on disk so that successive runs can use the optimized table (after loading the table is -unpacked). The flattening code used later is a prelude to an even more compact table -format (and as such it keeps evolving).</p> - -<p>This module is sparsely documented because it is a moving target. The table format -of the reader changes and we experiment a lot with different methods for supporting -features.</p> +unpacked).</p> -<p>As with the <l n='afm'/> code, we may decide to store more information in the -<l n='otf'/> table.</p> +<p>This module is sparsely documented because it is has been a moving target. The +table format of the reader changed a bit over time and we experiment a lot with +different methods for supporting features. By now the structures are quite stable</p> <p>Incrementing the version number will force a re-cache. We jump the number by one -when there's a fix in the <l n='fontforge'/> library or <l n='lua'/> code that -results in different tables.</p> +when there's a fix in the reader or processing code that can result in different +results.</p> + +<p>This code is also used outside context but in context it has to work with other +mechanisms. Both put some constraints on the code here.</p> + --ldx]]-- +-- Remark: We assume that cursives don't cross discretionaries which is okay because it +-- is only used in semitic scripts. +-- +-- Remark: We assume that marks precede base characters. +-- +-- Remark: When complex ligatures extend into discs nodes we can get side effects. Normally +-- this doesn't happen; ff\d{l}{l}{l} in lm works but ff\d{f}{f}{f}. +-- +-- Todo: check if we copy attributes to disc nodes if needed. +-- +-- Todo: it would be nice if we could get rid of components. In other places we can use +-- the unicode properties. +-- +-- Remark: We do some disc juggling where we need to keep in mind that the pre, post and +-- replace fields can have prev pointers to a nesting node ... I wonder if that is still +-- needed. +-- +-- Remark: This is not possible: +-- +-- \discretionary {alpha-} {betagammadelta} +-- {\discretionary {alphabeta-} {gammadelta} +-- {\discretionary {alphabetagamma-} {delta} +-- {alphabetagammadelta}}} +-- +-- Remark: Something is messed up: we have two mark / ligature indices, one at the +-- injection end and one here ... this is based on KE's patches but there is something +-- fishy there as I'm pretty sure that for husayni we need some connection (as it's much +-- more complex than an average font) but I need proper examples of all cases, not of +-- only some. +-- +-- Remark: I wonder if indexed would be faster than unicoded. It would be a major +-- rewrite to have char being unicode + an index field in glyph nodes. Also more +-- assignments have to be made in order to keep things in sync. So, it's a no-go. +-- +-- Remark: We can provide a fast loop when there are no disc nodes (tests show a 1% +-- gain). Smaller functions might perform better cache-wise. But ... memory becomes +-- faster anyway, so ... + local type, next, tonumber = type, next, tonumber local random = math.random local formatters = string.formatters local insert = table.insert -local logs, trackers, nodes, attributes = logs, trackers, nodes, attributes +local registertracker = trackers.register -local registertracker = trackers.register -local registerdirective = directives.register +local logs = logs +local trackers = trackers +local nodes = nodes +local attributes = attributes +local fonts = fonts -local fonts = fonts -local otf = fonts.handlers.otf +local otf = fonts.handlers.otf +local tracers = nodes.tracers local trace_lookups = false registertracker("otf.lookups", function(v) trace_lookups = v end) local trace_singles = false registertracker("otf.singles", function(v) trace_singles = v end) @@ -124,7 +137,6 @@ local trace_cursive = false registertracker("otf.cursive", function(v local trace_preparing = false registertracker("otf.preparing", function(v) trace_preparing = v end) local trace_bugs = false registertracker("otf.bugs", function(v) trace_bugs = v end) local trace_details = false registertracker("otf.details", function(v) trace_details = v end) ------ trace_applied = false registertracker("otf.applied", function(v) trace_applied = v end) local trace_steps = false registertracker("otf.steps", function(v) trace_steps = v end) local trace_skips = false registertracker("otf.skips", function(v) trace_skips = v end) local trace_directions = false registertracker("otf.directions", function(v) trace_directions = v end) @@ -135,23 +147,20 @@ local trace_discruns = false registertracker("otf.discruns", function(v local trace_compruns = false registertracker("otf.compruns", function(v) trace_compruns = v end) local trace_testruns = false registertracker("otf.testruns", function(v) trace_testruns = v end) ------ zwnjruns = true registerdirective("otf.zwnjruns", function(v) zwnjruns = v end) local optimizekerns = true -local alwaysdisc = true registerdirective("otf.alwaysdisc", function(v) alwaysdisc = v end) -local report_direct = logs.reporter("fonts","otf direct") -local report_subchain = logs.reporter("fonts","otf subchain") -local report_chain = logs.reporter("fonts","otf chain") -local report_process = logs.reporter("fonts","otf process") -local report_warning = logs.reporter("fonts","otf warning") -local report_run = logs.reporter("fonts","otf run") +local report_direct = logs.reporter("fonts","otf direct") +local report_subchain = logs.reporter("fonts","otf subchain") +local report_chain = logs.reporter("fonts","otf chain") +local report_process = logs.reporter("fonts","otf process") +local report_warning = logs.reporter("fonts","otf warning") +local report_run = logs.reporter("fonts","otf run") registertracker("otf.replacements", "otf.singles,otf.multiples,otf.alternatives,otf.ligatures") registertracker("otf.positions","otf.marks,otf.kerns,otf.cursive") registertracker("otf.actions","otf.replacements,otf.positions") registertracker("otf.injections","nodes.injections") - -registertracker("*otf.sample","otf.steps,otf.actions,otf.analyzing") +registertracker("otf.sample","otf.steps,otf.actions,otf.analyzing") local nuts = nodes.nuts local tonode = nuts.tonode @@ -178,6 +187,10 @@ local setchar = nuts.setchar local getdisc = nuts.getdisc local setdisc = nuts.setdisc local setlink = nuts.setlink +local getcomponents = nuts.getcomponents -- the original one, not yet node-aux +local setcomponents = nuts.setcomponents -- the original one, not yet node-aux +local getdir = nuts.getdir +local getwidth = nuts.getwidth local ischar = nuts.is_char @@ -190,14 +203,16 @@ local flush_node = nuts.flush_node local end_of_math = nuts.end_of_math local traverse_nodes = nuts.traverse local traverse_id = nuts.traverse_id -local remove_node = nuts.remove +local set_components = nuts.set_components +local take_components = nuts.take_components +local count_components = nuts.count_components +local copy_no_components = nuts.copy_no_components +local copy_only_glyphs = nuts.copy_only_glyphs local setmetatableindex = table.setmetatableindex -local zwnj = 0x200C -local zwj = 0x200D -local wildcard = "*" -local default = "dflt" +----- zwnj = 0x200C +----- zwj = 0x200D local nodecodes = nodes.nodecodes local glyphcodes = nodes.glyphcodes @@ -215,13 +230,8 @@ local ligature_code = glyphcodes.ligature local privateattribute = attributes.private --- Something is messed up: we have two mark / ligature indices, one at the injection --- end and one here ... this is based on KE's patches but there is something fishy --- there as I'm pretty sure that for husayni we need some connection (as it's much --- more complex than an average font) but I need proper examples of all cases, not --- of only some. - local a_state = privateattribute('state') +local a_noligature = privateattribute("noligature") local injections = nodes.injections local setmark = injections.setmark @@ -233,11 +243,8 @@ local copyinjection = injections.copy local setligaindex = injections.setligaindex local getligaindex = injections.getligaindex -local cursonce = true - -local fonthashes = fonts.hashes -local fontdata = fonthashes.identifiers -local fontfeatures = fonthashes.features +local fontdata = fonts.hashes.identifiers +local fontfeatures = fonts.hashes.features local otffeatures = fonts.constructors.features.otf local registerotffeature = otffeatures.register @@ -248,37 +255,36 @@ local getrandom = utilities and utilities.randomizer and utilities.rand otf.defaultnodealternate = "none" -- first last --- We use a few global variables. The handler can be called nested but this assumes that the --- same font is used. Nested calls are normally not needed (only for devanagari). - -local tfmdata = false -local characters = false -local descriptions = false -local marks = false -local currentfont = false -local factor = 0 -local threshold = 0 -local checkmarks = false +-- We use a few semi-global variables. The handler can be called nested but this assumes +-- that the same font is used. -local sweepnode = nil -local sweepprev = nil -local sweepnext = nil -local sweephead = { } +local tfmdata = false +local characters = false +local descriptions = false +local marks = false +local classes = false +local currentfont = false +local factor = 0 +local threshold = 0 +local checkmarks = false -local notmatchpre = { } -local notmatchpost = { } -local notmatchreplace = { } +local sweepnode = nil +local sweepprev = nil +local sweepnext = nil +local sweephead = { } -local handlers = { } +local notmatchpre = { } +local notmatchpost = { } +local notmatchreplace = { } -local isspace = injections.isspace -local getthreshold = injections.getthreshold +local handlers = { } --- we use this for special testing and documentation +local isspace = injections.isspace +local getthreshold = injections.getthreshold -local checkstep = (nodes and nodes.tracers and nodes.tracers.steppers.check) or function() end -local registerstep = (nodes and nodes.tracers and nodes.tracers.steppers.register) or function() end -local registermessage = (nodes and nodes.tracers and nodes.tracers.steppers.message) or function() end +local checkstep = (tracers and tracers.steppers.check) or function() end +local registerstep = (tracers and tracers.steppers.register) or function() end +local registermessage = (tracers and tracers.steppers.message) or function() end local function checkdisccontent(d) local pre, post, replace = getdisc(d) @@ -351,6 +357,13 @@ local function mref(rlmode) end end +-- The next code is somewhat complicated by the fact that some fonts can have ligatures made +-- from ligatures that themselves have marks. This was identified by Kai in for instance +-- arabtype: KAF LAM SHADDA ALEF FATHA (0x0643 0x0644 0x0651 0x0627 0x064E). This becomes +-- KAF LAM-ALEF with a SHADDA on the first and a FATHA op de second component. In a next +-- iteration this becomes a KAF-LAM-ALEF with a SHADDA on the second and a FATHA on the +-- third component. + -- We can assume that languages that use marks are not hyphenated. We can also assume -- that at most one discretionary is present. @@ -360,21 +373,6 @@ end -- However, for arabic we need to keep them around for the sake of mark placement -- and indices. -local function copy_glyph(g) -- next and prev are untouched ! - local components = getfield(g,"components") - if components then - setfield(g,"components") - local n = copy_node(g) - copyinjection(n,g) -- we need to preserve the lig indices - setfield(g,"components",components) - return n - else - local n = copy_node(g) - copyinjection(n,g) -- we need to preserve the lig indices - return n - end -end - local function flattendisk(head,disc) local pre, post, replace, pretail, posttail, replacetail = getdisc(disc,true) local prev, next = getboth(disc) @@ -419,18 +417,40 @@ local function appenddisc(disc,list) if post then setlink(posttail,posthead) else - post = phead + post = posthead end if replace then setlink(replacetail,replacehead) else - replace = rhead + replace = replacehead end setdisc(disc,pre,post,replace) end -- start is a mark and we need to keep that one +local take_components = getcomponents -- we overload here (for now) +local set_components = setcomponents -- we overload here (for now) +----- get_components = getcomponents -- we overload here (for now) + +local function count_components(start,marks) + if getid(start) ~= glyph_code then + return 0 + elseif getsubtype(start) == ligature_code then + local i = 0 + local components = getcomponents(start) + while components do + i = i + count_components(components,marks) + components = getnext(components) + end + return i + elseif not marks[getchar(start)] then + return 1 + else + return 0 + end +end + local function markstoligature(head,start,stop,char) if start == stop and getchar(start) == char then return head, start @@ -439,46 +459,135 @@ local function markstoligature(head,start,stop,char) local next = getnext(stop) setprev(start) setnext(stop) - local base = copy_glyph(start) + local base = copy_no_components(start,copyinjection) if head == start then head = base end resetinjection(base) setchar(base,char) setsubtype(base,ligature_code) - setfield(base,"components",start) - setlink(prev,base) - setlink(base,next) + set_components(base,start) + setlink(prev,base,next) return head, base end end --- The next code is somewhat complicated by the fact that some fonts can have ligatures made --- from ligatures that themselves have marks. This was identified by Kai in for instance --- arabtype: KAF LAM SHADDA ALEF FATHA (0x0643 0x0644 0x0651 0x0627 0x064E). This becomes --- KAF LAM-ALEF with a SHADDA on the first and a FATHA op de second component. In a next --- iteration this becomes a KAF-LAM-ALEF with a SHADDA on the second and a FATHA on the --- third component. - -local function getcomponentindex(start) -- we could store this offset in the glyph (nofcomponents) - if getid(start) ~= glyph_code then -- and then get rid of all components - return 0 - elseif getsubtype(start) == ligature_code then - local i = 0 - local components = getfield(start,"components") - while components do - i = i + getcomponentindex(components) - components = getnext(components) - end - return i - elseif not marks[getchar(start)] then - return 1 - else - return 0 - end -end - -local a_noligature = attributes.private("noligature") +-- local function toligature(head,start,stop,char,dataset,sequence,markflag,discfound) -- brr head +-- if getattr(start,a_noligature) == 1 then +-- -- so we can do: e\noligature{ff}e e\noligature{f}fie (we only look at the first) +-- return head, start +-- end +-- if start == stop and getchar(start) == char then +-- resetinjection(start) +-- setchar(start,char) +-- return head, start +-- end +-- local prev = getprev(start) +-- local next = getnext(stop) +-- local comp = start +-- setprev(start) +-- setnext(stop) +-- local base = copy_no_components(start,copyinjection) +-- if start == head then +-- head = base +-- end +-- resetinjection(base) +-- setchar(base,char) +-- setsubtype(base,ligature_code) +-- set_components(base,comp) +-- setlink(prev,base,next) +-- if not discfound then +-- local deletemarks = markflag ~= "mark" +-- local components = start +-- local baseindex = 0 +-- local componentindex = 0 +-- local head = base +-- local current = base +-- -- first we loop over the glyphs in start .. stop +-- while start do +-- local char = getchar(start) +-- if not marks[char] then +-- baseindex = baseindex + componentindex +-- componentindex = getcomponentindex(start,marks) +-- elseif not deletemarks then -- quite fishy +-- setligaindex(start,baseindex + getligaindex(start,componentindex)) +-- if trace_marks then +-- logwarning("%s: keep mark %s, gets index %s",pref(dataset,sequence),gref(char),getligaindex(start)) +-- end +-- local n = copy_node(start) +-- copyinjection(n,start) +-- head, current = insert_node_after(head,current,n) -- unlikely that mark has components +-- elseif trace_marks then +-- logwarning("%s: delete mark %s",pref(dataset,sequence),gref(char)) +-- end +-- start = getnext(start) +-- end +-- -- we can have one accent as part of a lookup and another following +-- -- local start = components -- was wrong (component scanning was introduced when more complex ligs in devanagari was added) +-- local start = getnext(current) +-- while start do +-- local char = ischar(start) +-- if char then +-- if marks[char] then +-- setligaindex(start,baseindex + getligaindex(start,componentindex)) +-- if trace_marks then +-- logwarning("%s: set mark %s, gets index %s",pref(dataset,sequence),gref(char),getligaindex(start)) +-- end +-- start = getnext(start) +-- else +-- break +-- end +-- else +-- break +-- end +-- end +-- else +-- -- discfound ... forget about marks .. probably no scripts that hyphenate and have marks +-- local discprev, discnext = getboth(discfound) +-- if discprev and discnext then +-- -- we assume normalization in context, and don't care about generic ... especially +-- -- \- can give problems as there we can have a negative char but that won't match +-- -- anyway +-- local pre, post, replace, pretail, posttail, replacetail = getdisc(discfound,true) +-- if not replace then -- todo: signal simple hyphen +-- local prev = getprev(base) +-- local current = comp +-- local previous = nil +-- local copied = nil +-- while current do +-- if getid(current) == glyph_code then +-- local n = copy_node(current) +-- if copied then +-- setlink(previous,n) +-- else +-- copied = n +-- end +-- previous = n +-- end +-- current = getnext(current) +-- end +-- setprev(discnext) -- also blocks funny assignments +-- setnext(discprev) -- also blocks funny assignments +-- if pre then +-- setlink(discprev,pre) +-- end +-- pre = comp +-- if post then +-- setlink(posttail,discnext) +-- setprev(post) +-- else +-- post = discnext +-- end +-- setlink(prev,discfound,next) +-- setboth(base) +-- set_components(base,copied) +-- setdisc(discfound,pre,post,base) -- was discretionary_code +-- base = prev -- restart +-- end +-- end +-- end +-- return head, base +-- end local function toligature(head,start,stop,char,dataset,sequence,markflag,discfound) -- brr head if getattr(start,a_noligature) == 1 then @@ -490,33 +599,20 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou setchar(start,char) return head, start end - -- needs testing (side effects): - local components = getfield(start,"components") - if components then - -- we get a double free .. needs checking - -- flush_node_list(components) - end - -- local prev = getprev(start) local next = getnext(stop) local comp = start setprev(start) setnext(stop) - local base = copy_glyph(start) + local base = copy_no_components(start,copyinjection) if start == head then head = base end resetinjection(base) setchar(base,char) setsubtype(base,ligature_code) - setfield(base,"components",comp) -- start can have components ... do we need to flush? - if prev then - setnext(prev,base) - end - if next then - setprev(next,base) - end - setboth(base,prev,next) + set_components(base,comp) + setlink(prev,base,next) if not discfound then local deletemarks = markflag ~= "mark" local components = start @@ -529,7 +625,7 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou local char = getchar(start) if not marks[char] then baseindex = baseindex + componentindex - componentindex = getcomponentindex(start) + componentindex = count_components(start,marks) elseif not deletemarks then -- quite fishy setligaindex(start,baseindex + getligaindex(start,componentindex)) if trace_marks then @@ -544,7 +640,6 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou start = getnext(start) end -- we can have one accent as part of a lookup and another following - -- local start = components -- was wrong (component scanning was introduced when more complex ligs in devanagari was added) local start = getnext(current) while start do local char = ischar(start) @@ -570,27 +665,14 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou -- \- can give problems as there we can have a negative char but that won't match -- anyway local pre, post, replace, pretail, posttail, replacetail = getdisc(discfound,true) - if not replace then -- todo: signal simple hyphen - local prev = getprev(base) - local current = comp - local previous = nil - local copied = nil - while current do - if getid(current) == glyph_code then - local n = copy_node(current) - if copied then - setlink(previous,n) - else - copied = n - end - previous = n - end - current = getnext(current) - end - setprev(discnext) -- also blocks funny assignments - setnext(discprev) -- also blocks funny assignments + if not replace then + local prev = getprev(base) + local comp = take_components(base) + local copied = copy_only_glyphs(comp) if pre then setlink(discprev,pre) + else + setnext(discprev) -- also blocks funny assignments end pre = comp if post then @@ -598,13 +680,15 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou setprev(post) else post = discnext + setprev(discnext) -- also blocks funny assignments end - setlink(prev,discfound) - setlink(discfound,next) + setlink(prev,discfound,next) setboth(base) - setfield(base,"components",copied) - setdisc(discfound,pre,post,base) -- was discretionary_code - base = prev -- restart + -- here components have a pointer so we can't free it! + set_components(base,copied) + replace = base + setdisc(discfound,pre,post,replace) -- was discretionary_code + base = prev end end end @@ -868,7 +952,6 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,step,i,inje return head, start, false else local prev = start - local done = false while snext do local nextchar = ischar(snext,currentfont) if nextchar then @@ -888,8 +971,7 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,step,i,inje if trace_kerns then logprocess("%s: shifting single %s by %p",pref(dataset,sequence),gref(nextchar),k) end - done = true - break + return head, start, true end end if a and #a > 0 then @@ -906,15 +988,13 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,step,i,inje logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections") end end - done = true - break + return head, start, true elseif krn ~= 0 then local k = setkern(snext,factor,rlmode,krn,injection) if trace_kerns then logprocess("%s: inserting kern %p between %s and %s as %s",pref(dataset,sequence),k,gref(getchar(prev)),gref(nextchar),injection or "injections") end - done = true - break + return head, start, true else -- can't happen break end @@ -922,7 +1002,7 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,step,i,inje break end end - return head, start, done + return head, start, false end end @@ -1085,7 +1165,6 @@ function handlers.gpos_mark2mark(head,start,dataset,sequence,markanchors,rlmode) end function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,step,i) -- to be checked - local done = false local startchar = getchar(start) if marks[startchar] then if trace_cursive then @@ -1093,7 +1172,7 @@ function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,st end else local nxt = getnext(start) - while not done and nxt do + while nxt do local nextchar = ischar(nxt,currentfont) if not nextchar then break @@ -1111,7 +1190,7 @@ function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,st if trace_cursive then logprocess("%s: moving %s to %s cursive (%p,%p) using anchor %s and bound %s in %s mode",pref(dataset,sequence),gref(startchar),gref(nextchar),dx,dy,anchor,bound,mref(rlmode)) end - done = true + return head, start, true end end end @@ -1119,7 +1198,7 @@ function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,st end end end - return head, start, done + return head, start, false end --[[ldx-- @@ -1207,10 +1286,11 @@ function chainprocs.gsub_single(head,start,stop,dataset,sequence,currentlookup,c reportmoresteps(dataset,sequence) end local current = start + local mapping = steps[1].coverage while current do local currentchar = ischar(current) if currentchar then - local replacement = steps[1].coverage[currentchar] + local replacement = mapping[currentchar] if not replacement or replacement == "" then if trace_bugs then logwarning("%s: no single for %s",cref(dataset,sequence,chainindex),gref(currentchar)) @@ -1282,10 +1362,11 @@ function chainprocs.gsub_alternate(head,start,stop,dataset,sequence,currentlooku local what = dataset[1] local value = what == true and tfmdata.shared.features[kind] or what -- todo: optimize in ctx local current = start + local mapping = steps[1].coverage while current do local currentchar = ischar(current) if currentchar then - local alternatives = steps[1].coverage[currentchar] + local alternatives = mapping[currentchar] if alternatives then local choice, comment = get_alternative_glyph(current,alternatives,value) if choice then @@ -1437,7 +1518,6 @@ function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlm local kerns = step.coverage[startchar] -- always 1 step if kerns then local prev = start - local done = false while snext do local nextchar = ischar(snext,currentfont) if not nextchar then @@ -1459,8 +1539,7 @@ function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlm if trace_kerns then logprocess("%s: shifting single %s by %p",cref(dataset,sequence),gref(startchar),k) end - done = true - break + return head, start, true end end if a and #a > 0 then @@ -1477,20 +1556,17 @@ function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlm logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) end end - done = true - break + return head, start, true elseif krn ~= 0 then local k = setkern(snext,factor,rlmode,krn) if trace_kerns then logprocess("%s: inserting kern %s between %s and %s",cref(dataset,sequence),k,gref(getchar(prev)),gref(nextchar)) end - done = true - break + return head, start, true else break end end - return head, start, done end end return head, start, false @@ -1689,14 +1765,13 @@ function chainprocs.gpos_cursive(head,start,stop,dataset,sequence,currentlookup, local startchar = getchar(start) local exitanchors = steps[1].coverage[startchar] -- always 1 step if exitanchors then - local done = false if marks[startchar] then if trace_cursive then logprocess("%s: ignoring cursive for mark %s",pref(dataset,sequence),gref(startchar)) end else local nxt = getnext(start) - while not done and nxt do + while nxt do local nextchar = ischar(nxt,currentfont) if not nextchar then break @@ -1714,8 +1789,7 @@ function chainprocs.gpos_cursive(head,start,stop,dataset,sequence,currentlookup, if trace_cursive then logprocess("%s: moving %s to %s cursive (%p,%p) using anchor %s and bound %s in %s mode",pref(dataset,sequence),gref(startchar),gref(nextchar),dx,dy,anchor,bound,mref(rlmode)) end - done = true - break + return head, start, true end end elseif trace_bugs then @@ -1725,13 +1799,10 @@ function chainprocs.gpos_cursive(head,start,stop,dataset,sequence,currentlookup, end end end - return head, start, done - else - if trace_cursive and trace_details then - logprocess("%s, cursive %s is already done",pref(dataset,sequence),gref(getchar(start)),alreadydone) - end - return head, start, false + elseif trace_cursive and trace_details then + logprocess("%s, cursive %s is already done",pref(dataset,sequence),gref(getchar(start)),alreadydone) end + return head, start, false end -- what pointer to return, spec says stop @@ -1774,7 +1845,7 @@ local function checked(head) local current = head while current do if getid(current) == glue_code then - local kern = new_kern(getfield(current,"width")) + local kern = new_kern(getwidth(current)) if head == current then local next = getnext(current) if next then @@ -1785,8 +1856,7 @@ local function checked(head) current = next else local prev, next = getboth(current) - setlink(prev,kern) - setlink(kern,next) + setlink(prev,kern,next) flush_node(current) current = next end @@ -1804,7 +1874,107 @@ local function setdiscchecked(d,pre,post,replace) setdisc(d,pre,post,replace) end -local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,ck,chainproc) +local noflags = { false, false, false, false } + +local function chainrun(head,start,last,dataset,sequence,rlmode,ck,skipped) + + local size = ck[5] - ck[4] + 1 + local flags = sequence.flags or noflags + local done = false + local skipmark = flags[1] + local chainlookups = ck[6] + + -- current match + if chainlookups then + local nofchainlookups = #chainlookups + -- Lookups can be like { 1, false, 3 } or { false, 2 } or basically anything and + -- #lookups can be less than #current + if size == 1 then + -- if nofchainlookups > size then + -- -- bad rules + -- end + local chainlookup = chainlookups[1] + local chainkind = chainlookup.type + local chainproc = chainprocs[chainkind] + if chainproc then + local ok + head, start, ok = chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,1) + if ok then + done = true + end + else + logprocess("%s: %s is not yet supported (1)",cref(dataset,sequence),chainkind) + end + else + -- See LookupType 5: Contextual Substitution Subtable. Now it becomes messy. The + -- easiest case is where #current maps on #lookups i.e. one-to-one. But what if + -- we have a ligature. Cf the spec we then need to advance one character but we + -- really need to test it as there are fonts out there that are fuzzy and have + -- too many lookups: + -- + -- U+1105 U+119E U+1105 U+119E : sourcehansansklight: script=hang ccmp=yes + -- + local i = 1 + while start do + if skipped then + while start do + local char = getchar(start) + local class = classes[char] + if class then + if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then + start = getnext(start) + else + break + end + else + break + end + end + end + local chainlookup = chainlookups[i] + if chainlookup then + local chainkind = chainlookup.type + local chainproc = chainprocs[chainkind] + if chainproc then + local ok, n + head, start, ok, n = chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,i) + -- messy since last can be changed ! + if ok then + done = true + if n and n > 1 and i + n > nofchainlookups then + -- this is a safeguard, we just ignore the rest of the lookups + break + end + end + else + -- actually an error + logprocess("%s: %s is not yet supported (2)",cref(dataset,sequence),chainkind) + end + end + i = i + 1 + if i > size or not start then + break + elseif start then + start = getnext(start) + end + end + end + else + -- todo: needs checking for holes in the replacements + local replacements = ck[7] + if replacements then + head, start, done = reversesub(head,start,last,dataset,sequence,replacements,rlmode) + else + done = true + if trace_contexts then + logprocess("%s: skipping match",cref(dataset,sequence)) + end + end + end + return head, start, done +end + +local function chaindisk(head,start,dataset,sequence,rlmode,ck,skipped) if not start then return head, start, false @@ -1819,7 +1989,6 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c local sweepnode = sweepnode local sweeptype = sweeptype local sweepoverflow = false - local checkdisc = getprev(head) -- hm bad name head local keepdisc = not sweepnode local lookaheaddisc = nil local backtrackdisc = nil @@ -1845,19 +2014,23 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c hasglue = true elseif id == disc_code then if keepdisc then - keepdisc = false - if notmatchpre[current] ~= notmatchreplace[current] then - lookaheaddisc = current - end + keepdisc = false + lookaheaddisc = current local replace = getfield(current,"replace") - while replace and i <= l do - if getid(replace) == glyph_code then - i = i + 1 + if not replace then + sweepoverflow = true + sweepnode = current + current = getnext(current) + else + while replace and i <= l do + if getid(replace) == glyph_code then + i = i + 1 + end + replace = getnext(replace) end - replace = getnext(replace) + current = getnext(replace) end - last = current - current = getnext(c) + last = current else head, current = flattendisk(head,current) end @@ -1919,7 +2092,8 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c if notmatchpre[current] ~= notmatchreplace[current] then lookaheaddisc = current end - local replace = getfield(c,"replace") + -- we assume a simple text only replace (we could use nuts.count) + local replace = getfield(current,"replace") while replace and i < s do if getid(replace) == glyph_code then i = i + 1 @@ -1964,6 +2138,7 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c if notmatchpost[current] ~= notmatchreplace[current] then backtrackdisc = current end + -- we assume a simple text only replace (we could use nuts.count) local replace = getfield(current,"replace") while replace and i > 1 do if getid(replace) == glyph_code then @@ -1982,7 +2157,8 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c end end - local ok = false + local done = false + if lookaheaddisc then local cf = start @@ -2001,11 +2177,7 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c break end end - - setprev(lookaheaddisc,cprev) - if cprev then - setnext(cprev,lookaheaddisc) - end + setlink(cprev,lookaheaddisc) setprev(cf) setnext(cl) if startishead then @@ -2014,25 +2186,35 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c local pre, post, replace = getdisc(lookaheaddisc) local new = copy_node_list(cf) local cnew = new + if pre then + setlink(find_node_tail(cf),pre) + end + if replace then + local tail = find_node_tail(new) + setlink(tail,replace) + end for i=1,insertedmarks do cnew = getnext(cnew) end + cl = start local clast = cnew for i=f,l do + cl = getnext(cl) clast = getnext(clast) end if not notmatchpre[lookaheaddisc] then - cf, start, ok = chainproc(cf,start,last,dataset,sequence,chainlookup,rlmode,k) + local ok = false + cf, start, ok = chainrun(cf,start,cl,dataset,sequence,rlmode,ck,skipped) + if ok then + done = true + end end if not notmatchreplace[lookaheaddisc] then - new, cnew, ok = chainproc(new,cnew,clast,dataset,sequence,chainlookup,rlmode,k) - end - if pre then - setlink(cl,pre) - end - if replace then - local tail = find_node_tail(new) - setlink(tail,replace) + local ok = false + new, cnew, ok = chainrun(new,cnew,clast,dataset,sequence,rlmode,ck,skipped) + if ok then + done = true + end end if hasglue then setdiscchecked(lookaheaddisc,cf,post,new) @@ -2041,7 +2223,7 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c end start = getprev(lookaheaddisc) sweephead[cf] = getnext(clast) - sweephead[new] = getnext(last) + sweephead[new] = getnext(cl) elseif backtrackdisc then @@ -2077,10 +2259,18 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c clast = getnext(clast) end if not notmatchpost[backtrackdisc] then - cf, start, ok = chainproc(cf,start,last,dataset,sequence,chainlookup,rlmode,k) + local ok = false + cf, start, ok = chainrun(cf,start,last,dataset,sequence,rlmode,ck,skipped) + if ok then + done = true + end end if not notmatchreplace[backtrackdisc] then - new, cnew, ok = chainproc(new,cnew,clast,dataset,sequence,chainlookup,rlmode,k) + local ok = false + new, cnew, ok = chainrun(new,cnew,clast,dataset,sequence,rlmode,ck,skipped) + if ok then + done = true + end end if post then setlink(posttail,cf) @@ -2103,21 +2293,34 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c else - head, start, ok = chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,k) + local ok = false + head, start, ok = chainrun(head,start,last,dataset,sequence,rlmode,ck,skipped) + if ok then + done = true + end end - return head, start, ok + return head, start, done end -local noflags = { false, false, false, false } +local function chaintrac(head,start,dataset,sequence,rlmode,ck,skipped) + local rule = ck[1] + local lookuptype = ck[8] or ck[2] + local nofseq = #ck[3] + local first = ck[4] + local last = ck[5] + local char = getchar(start) + logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %a", + cref(dataset,sequence),rule,gref(char),first-1,last-first+1,nofseq-last,lookuptype) +end local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) local sweepnode = sweepnode local sweeptype = sweeptype local currentfont = currentfont local diskseen = false - local checkdisc = getprev(head) + local checkdisc = sweeptype and getprev(head) local flags = sequence.flags or noflags local done = false local skipmark = flags[1] @@ -2125,6 +2328,8 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) local skipbase = flags[3] local markclass = sequence.markclass local skipped = false + local startprev, + startnext = getboth(start) for k=1,#contexts do -- i've only seen ccmp having > 1 (e.g. dejavu) local match = true local current = start @@ -2138,7 +2343,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) -- this seldom happens as it makes no sense (bril, ebgaramond, husayni, minion) local char = ischar(current,currentfont) if char then - match = seq[1][char] + if not seq[1][char] then + match = false + end end else -- maybe we need a better space check (maybe check for glue or category or combination) @@ -2151,7 +2358,8 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) -- before/current/after | before/current | current/after local discfound = nil local n = f + 1 - last = getnext(last) -- the second in current (first already matched) + -- last = getnext(last) -- the second in current (first already matched) + last = startnext -- the second in current (first already matched) while n <= l do if not last and (sweeptype == "post" or sweeptype == "replace") then last = getnext(sweepnode) @@ -2160,9 +2368,8 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) if last then local char, id = ischar(last,currentfont) if char then - local ccd = descriptions[char] - if ccd then - local class = ccd.class or "base" + local class = classes[char] + if class then if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then skipped = true if trace_skips then @@ -2177,7 +2384,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) else if discfound then notmatchreplace[discfound] = true - match = not notmatchpre[discfound] + if notmatchpre[discfound] then + match = false + end else match = false end @@ -2186,7 +2395,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) else if discfound then notmatchreplace[discfound] = true - match = not notmatchpre[discfound] + if notmatchpre[discfound] then + match = false + end else match = false end @@ -2195,7 +2406,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) elseif char == false then if discfound then notmatchreplace[discfound] = true - match = not notmatchpre[discfound] + if notmatchpre[discfound] then + match = false + end else match = false end @@ -2238,11 +2451,16 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) end else notmatchreplace[last] = true - match = not notmatchpre[last] + if notmatchpre[last] then + match = false + end break end end - match = not notmatchpre[last] + -- why here again + if notmatchpre[last] then + match = false + end end -- maybe only if match last = getnext(last) @@ -2258,8 +2476,10 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) end -- before if match and f > 1 then - local prev = getprev(start) - if prev then + -- local prev = getprev(start) + -- if prev then + if startprev then + local prev = startprev if prev == checkdisc and (sweeptype == "pre" or sweeptype == "replace") then prev = getprev(sweepnode) -- sweeptype = nil @@ -2271,24 +2491,25 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) if prev then local char, id = ischar(prev,currentfont) if char then - local ccd = descriptions[char] - if ccd then - local class = ccd.class + local class = classes[char] + if class then if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then skipped = true if trace_skips then show_skip(dataset,sequence,char,ck,class) end - prev = getprev(prev) -- moved here + prev = getprev(prev) elseif seq[n][char] then - if n > 1 then -- new test - prev = getprev(prev) -- moved here + if n > 1 then + prev = getprev(prev) end n = n - 1 else if discfound then notmatchreplace[discfound] = true - match = not notmatchpost[discfound] + if notmatchpost[discfound] then + match = false + end else match = false end @@ -2297,17 +2518,20 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) else if discfound then notmatchreplace[discfound] = true - match = not notmatchpost[discfound] + if notmatchpost[discfound] then + match = false + end else match = false end break end - -- prev = getprev(prev) -- moved up elseif char == false then if discfound then notmatchreplace[discfound] = true - match = not notmatchpost[discfound] + if notmatchpost[discfound] then + match = false + end else match = false end @@ -2360,7 +2584,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) end else notmatchreplace[prev] = true - match = not notmatchpost[prev] + if notmatchpost[prev] then + match = false + end break end end @@ -2371,7 +2597,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) end -- maybe only if match prev = getprev(prev) - elseif seq[n][32] and isspace(prev,threshold) then + elseif seq[n][32] and id == glue_code and isspace(prev,threshold,id) then n = n - 1 prev = getprev(prev) else @@ -2407,9 +2633,8 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) if current then local char, id = ischar(current,currentfont) if char then - local ccd = descriptions[char] - if ccd then - local class = ccd.class + local class = classes[char] + if class then if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then skipped = true if trace_skips then @@ -2424,7 +2649,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) else if discfound then notmatchreplace[discfound] = true - match = not notmatchpre[discfound] + if notmatchpre[discfound] then + match = false + end else match = false end @@ -2433,7 +2660,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) else if discfound then notmatchreplace[discfound] = true - match = not notmatchpre[discfound] + if notmatchpre[discfound] then + match = false + end else match = false end @@ -2442,7 +2671,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) elseif char == false then if discfound then notmatchreplace[discfound] = true - match = not notmatchpre[discfound] + if notmatchpre[discfound] then + match = false + end else match = false end @@ -2485,7 +2716,10 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) end else notmatchreplace[current] = true - match = notmatchpre[current] + -- different than others, needs checking if "not" is okay + if not notmatchpre[current] then + match = false + end break end end @@ -2497,7 +2731,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) end -- maybe only if match current = getnext(current) - elseif seq[n][32] and isspace(current,threshold) then + elseif seq[n][32] and id == glue_code and isspace(current,threshold,id) then n = n + 1 current = getnext(current) else @@ -2515,112 +2749,13 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) end end if match then - -- Can lookups be of a different type? - local diskchain = diskseen or sweepnode if trace_contexts then - local rule = ck[1] - local lookuptype = ck[8] or ck[2] - local first = ck[4] - local last = ck[5] - local char = getchar(start) - logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %a", - cref(dataset,sequence),rule,gref(char),first-1,last-first+1,s-last,lookuptype) - end - local chainlookups = ck[6] - if chainlookups then - local nofchainlookups = #chainlookups - -- Lookups can be like { 1, false, 3 } or { false, 2 } or basically anything and - -- #lookups can be less than #current - if size == 1 then - -- if nofchainlookups > size then - -- -- bad rules - -- end - local chainlookup = chainlookups[1] - local chainkind = chainlookup.type - local chainproc = chainprocs[chainkind] - if chainproc then - local ok - if diskchain then - head, start, ok = chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,1,ck,chainproc) - else - head, start, ok = chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,1) - end - if ok then - done = true - end - else - logprocess("%s: %s is not yet supported (1)",cref(dataset,sequence),chainkind) - end - else - -- See LookupType 5: Contextual Substitution Subtable. Now it becomes messy. The - -- easiest case is where #current maps on #lookups i.e. one-to-one. But what if - -- we have a ligature. Cf the spec we then need to advance one character but we - -- really need to test it as there are fonts out there that are fuzzy and have - -- too many lookups: - -- - -- U+1105 U+119E U+1105 U+119E : sourcehansansklight: script=hang ccmp=yes - -- - local i = 1 - while start do - if skipped then - while start do -- todo: use properties - local char = getchar(start) - local ccd = descriptions[char] - if ccd then - local class = ccd.class or "base" - if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then - start = getnext(start) - else - break - end - else - break - end - end - end - local chainlookup = chainlookups[i] - if chainlookup then - local chainkind = chainlookup.type - local chainproc = chainprocs[chainkind] - if chainproc then - local ok, n - if diskchain then - head, start, ok = chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,i,ck,chainproc) - else - head, start, ok, n = chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,i) - end - -- messy since last can be changed ! - if ok then - done = true - if n and n > 1 and i + n > nofchainlookups then - -- this is a safeguard, we just ignore the rest of the lookups - break - end - end - else - -- actually an error - logprocess("%s: %s is not yet supported (2)",cref(dataset,sequence),chainkind) - end - end - i = i + 1 - if i > size or not start then - break - elseif start then - start = getnext(start) - end - end - end + chaintrac(head,start,dataset,sequence,rlmode,ck,skipped) + end + if diskseen or sweepnode then + head, start, done = chaindisk(head,start,dataset,sequence,rlmode,ck,skipped) else - -- todo: needs checking for holes in the replacements - local replacements = ck[7] - if replacements then - head, start, done = reversesub(head,start,last,dataset,sequence,replacements,rlmode) - else - done = true - if trace_contexts then - logprocess("%s: skipping match",cref(dataset,sequence)) - end - end + head, start, done = chainrun(head,start,last,dataset,sequence,rlmode,ck,skipped) end if done then break -- out of contexts (new, needs checking) @@ -2693,79 +2828,86 @@ end) -- fonts.hashes.sequences = sequencelists -local autofeatures = fonts.analyzers.features -local featuretypes = otf.tables.featuretypes -local defaultscript = otf.features.checkeddefaultscript -local defaultlanguage = otf.features.checkeddefaultlanguage - -local function initialize(sequence,script,language,enabled,autoscript,autolanguage) - local features = sequence.features - if features then - local order = sequence.order - if order then - local featuretype = featuretypes[sequence.type or "unknown"] - for i=1,#order do - local kind = order[i] - local valid = enabled[kind] - if valid then - local scripts = features[kind] - local languages = scripts and ( - scripts[script] or - scripts[wildcard] or - (autoscript and defaultscript(featuretype,autoscript,scripts)) - ) - local enabled = languages and ( - languages[language] or - languages[wildcard] or - (autolanguage and defaultlanguage(featuretype,autolanguage,languages)) - ) - if enabled then - return { valid, autofeatures[kind] or false, sequence, kind } +do -- overcome local limit + + local autofeatures = fonts.analyzers.features + local featuretypes = otf.tables.featuretypes + local defaultscript = otf.features.checkeddefaultscript + local defaultlanguage = otf.features.checkeddefaultlanguage + + local wildcard = "*" + local default = "dflt" + + local function initialize(sequence,script,language,enabled,autoscript,autolanguage) + local features = sequence.features + if features then + local order = sequence.order + if order then + local featuretype = featuretypes[sequence.type or "unknown"] + for i=1,#order do + local kind = order[i] + local valid = enabled[kind] + if valid then + local scripts = features[kind] + local languages = scripts and ( + scripts[script] or + scripts[wildcard] or + (autoscript and defaultscript(featuretype,autoscript,scripts)) + ) + local enabled = languages and ( + languages[language] or + languages[wildcard] or + (autolanguage and defaultlanguage(featuretype,autolanguage,languages)) + ) + if enabled then + return { valid, autofeatures[kind] or false, sequence, kind } + end end end - end - else - -- can't happen - end - end - return false -end - -function otf.dataset(tfmdata,font) -- generic variant, overloaded in context - local shared = tfmdata.shared - local properties = tfmdata.properties - local language = properties.language or "dflt" - local script = properties.script or "dflt" - local enabled = shared.features - local autoscript = enabled and enabled.autoscript - local autolanguage = enabled and enabled.autolanguage - local res = resolved[font] - if not res then - res = { } - resolved[font] = res - end - local rs = res[script] - if not rs then - rs = { } - res[script] = rs - end - local rl = rs[language] - if not rl then - rl = { - -- indexed but we can also add specific data by key - } - rs[language] = rl - local sequences = tfmdata.resources.sequences - if sequences then - for s=1,#sequences do - local v = enabled and initialize(sequences[s],script,language,enabled,autoscript,autolanguage) - if v then - rl[#rl+1] = v + else + -- can't happen + end + end + return false + end + + function otf.dataset(tfmdata,font) -- generic variant, overloaded in context + local shared = tfmdata.shared + local properties = tfmdata.properties + local language = properties.language or "dflt" + local script = properties.script or "dflt" + local enabled = shared.features + local autoscript = enabled and enabled.autoscript + local autolanguage = enabled and enabled.autolanguage + local res = resolved[font] + if not res then + res = { } + resolved[font] = res + end + local rs = res[script] + if not rs then + rs = { } + res[script] = rs + end + local rl = rs[language] + if not rl then + rl = { + -- indexed but we can also add specific data by key + } + rs[language] = rl + local sequences = tfmdata.resources.sequences + if sequences then + for s=1,#sequences do + local v = enabled and initialize(sequences[s],script,language,enabled,autoscript,autolanguage) + if v then + rl[#rl+1] = v + end end end end + return rl end - return rl + end local function report_disc(what,n) @@ -2851,7 +2993,7 @@ local function kernrun(disc,k_run,font,attr,...) done = true end setprev(replace,nest) --- setprev(replace) + -- setprev(replace) setnext(prev,disc) end if next then @@ -2867,13 +3009,15 @@ local function kernrun(disc,k_run,font,attr,...) if k_run(prevmarks,"emptyinjections",next,font,attr,...) then done = true end - setlink(prev,disc) - setlink(disc,next) + setlink(prev,disc,next) end return nextstart, done end -local function comprun(disc,c_run,...) +-- fonts like ebgaramond do ligatuires this way (less efficient than e.g. dejavu which +-- will do the testrun variant) + +local function comprun(disc,c_run,...) -- vararg faster than the whole list if trace_compruns then report_disc("comp",disc) end @@ -2883,7 +3027,7 @@ local function comprun(disc,c_run,...) -- if pre then sweepnode = disc - sweeptype = "pre" -- in alternative code preinjections is uc_c_sed (also used then for proeprties, saves a variable) + sweeptype = "pre" -- in alternative code preinjections is uc_c_sed (also used then for properties, saves a variable) local new, done = c_run(pre,...) if done then pre = new @@ -2997,41 +3141,6 @@ local function testrun(disc,t_run,c_run,...) end end --- A discrun happens when we have a zwnj. We're gpossing so it is unlikely that --- there has been a match changing the character. Now, as we check again here --- the question is: why do we do this ... needs checking as drun seems useless --- ... maybe that code can go away - --- local function discrun(disc,drun,krun) --- local prev, next = getboth(disc) --- if trace_discruns then --- report_disc("disc",disc) --- end --- if next and prev then --- setnext(prev,next) --- -- setprev(next,prev) --- drun(prev) --- setnext(prev,disc) --- -- setprev(next,disc) --- end --- -- --- if krun then -- currently always false --- local pre = getfield(disc,"pre") --- if not pre then --- -- go on --- elseif prev then --- local nest = getprev(pre) --- setlink(prev,pre) --- krun(prev,"preinjections") --- setprev(pre,nest) --- setnext(prev,disc) --- else --- krun(pre,"preinjections") --- end --- end --- return next --- end - -- We can make some assumptions with respect to discretionaries. First of all it is very -- unlikely that some of the analysis related attributes applies. Then we can also assume -- that the ConTeXt specific dynamic attribute is different, although we do use explicit @@ -3057,6 +3166,7 @@ end -- 1{2{\oldstyle\discretionary{3}{4}{5}}6}7\par -- 1{2\discretionary{3{\oldstyle3}}{{\oldstyle4}4}{5{\oldstyle5}5}6}7\par + local nesting = 0 local function c_run_single(head,font,attr,lookupcache,step,dataset,sequence,rlmode,handler) @@ -3071,7 +3181,10 @@ local function c_run_single(head,font,attr,lookupcache,step,dataset,sequence,rlm while start do local char = ischar(start,font) if char then - local a = attr and getattr(start,0) + local a -- happens often so no assignment is faster + if attr then + a = getattr(start,0) + end if not a or (a == attr) then local lookupmatch = lookupcache[char] if lookupmatch then @@ -3105,12 +3218,16 @@ local function t_run_single(start,stop,font,attr,lookupcache) while start ~= stop do local char = ischar(start,font) if char then - local a = attr and getattr(start,0) + local a -- happens often so no assignment is faster + if attr then + a = getattr(start,0) + end + local startnext = getnext(start) if not a or (a == attr) then local lookupmatch = lookupcache[char] if lookupmatch then -- hm, hyphens can match (tlig) so we need to really check -- if we need more than ligatures we can outline the code and use functions - local s = getnext(start) + local s = startnext local l = nil local d = 0 while s do @@ -3134,32 +3251,18 @@ local function t_run_single(start,stop,font,attr,lookupcache) else -- go on can be a mixed one end - start = getnext(start) + start = starttnext else break end end end --- local function d_run_single(prev,font,attr,lookupcache,step,dataset,sequence,rlmode,handler) --- local a = attr and getattr(prev,0) --- if not a or (a == attr) then --- local char = ischar(prev) -- can be disc --- if char then --- local lookupmatch = lookupcache[char] --- if lookupmatch then --- local h, d, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,1) --- if ok then --- done = true --- success = true --- end --- end --- end --- end --- end - local function k_run_single(sub,injection,last,font,attr,lookupcache,step,dataset,sequence,rlmode,handler) - local a = attr and getattr(sub,0) + local a -- happens often so no assignment is faster + if attr then + a = getattr(sub,0) + end if not a or (a == attr) then for n in traverse_nodes(sub) do -- only gpos if n == last then @@ -3191,7 +3294,10 @@ local function c_run_multiple(head,font,attr,steps,nofsteps,dataset,sequence,rlm while start do local char = ischar(start,font) if char then - local a = attr and getattr(start,0) + local a -- happens often so no assignment is faster + if attr then + a = getattr(start,0) + end if not a or (a == attr) then for i=1,nofsteps do local step = steps[i] @@ -3239,7 +3345,11 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps) while start ~= stop do local char = ischar(start,font) if char then - local a = attr and getattr(start,0) + local a -- happens often so no assignment is faster + if attr then + a = getattr(start,0) + end + local startnext = getnext(start) if not a or (a == attr) then for i=1,nofsteps do local step = steps[i] @@ -3248,7 +3358,7 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps) local lookupmatch = lookupcache[char] if lookupmatch then -- if we need more than ligatures we can outline the code and use functions - local s = getnext(start) + local s = startnext local l = nil local d = 0 while s do @@ -3276,41 +3386,18 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps) else -- go on can be a mixed one end - start = getnext(start) + start = startnext else break end end end --- local function d_run_multiple(prev,attr,steps,nofsteps,dataset,sequence,rlmode,handler) --- local a = attr and getattr(prev,0) --- if not a or (a == attr) then --- local char = ischar(prev) -- can be disc --- if char then --- for i=1,nofsteps do --- local step = steps[i] --- local lookupcache = step.coverage --- if lookupcache then --- local lookupmatch = lookupcache[char] --- if lookupmatch then --- -- we could move all code inline but that makes things even more unreadable --- local h, d, ok = handler(head,prev,dataset,sequence,lookupmatch,rlmode,step,i) --- if ok then --- done = true --- break --- end --- end --- else --- report_missing_coverage(dataset,sequence) --- end --- end --- end --- end --- end - local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler) - local a = attr and getattr(sub,0) + local a -- happens often so no assignment is faster + if attr then + a = getattr(sub,0) + end if not a or (a == attr) then for n in traverse_nodes(sub) do -- only gpos if n == last then @@ -3342,7 +3429,7 @@ end -- so maybe we no longer need a stack local function txtdirstate(start,stack,top,rlparmode) - local dir = getfield(start,"dir") + local dir = getdir(start) local new = 1 if dir == "+TRT" then top = top + 1 @@ -3366,7 +3453,7 @@ local function txtdirstate(start,stack,top,rlparmode) end local function pardirstate(start) - local dir = getfield(start,"dir") + local dir = getdir(start) local new = 0 if dir == "TLT" then new = 1 @@ -3394,15 +3481,16 @@ local function featuresprocessor(head,font,attr) nesting = nesting + 1 if nesting == 1 then - - currentfont = font - tfmdata = fontdata[font] - descriptions = tfmdata.descriptions - characters = tfmdata.characters - marks = tfmdata.resources.marks + currentfont = font + tfmdata = fontdata[font] + descriptions = tfmdata.descriptions -- only needed in gref so we could pass node there instead + characters = tfmdata.characters -- but this branch is not entered that often anyway + local resources = tfmdata.resources + marks = resources.marks + classes = resources.classes threshold, - factor = getthreshold(font) - checkmarks = tfmdata.properties.checkmarks + factor = getthreshold(font) + checkmarks = tfmdata.properties.checkmarks elseif currentfont ~= font then @@ -3427,14 +3515,9 @@ local function featuresprocessor(head,font,attr) end local rlmode = 0 - local done = false local datasets = otf.dataset(tfmdata,font,attr) - - local forcedisc = alwaysdisc or not attr - local dirstack = { } -- could move outside function but we can have local runs - sweephead = { } -- We could work on sub start-stop ranges instead but I wonder if there is that @@ -3442,8 +3525,8 @@ local function featuresprocessor(head,font,attr) -- to keep track of directions anyway. Also at some point I want to play with -- font interactions and then we do need the full sweeps. - -- Keeping track of the headnode is needed for devanagari (I generalized it a bit - -- so that multiple cases are also covered.) + -- Keeping track of the headnode is needed for devanagari. (I generalized it a bit + -- so that multiple cases are also covered.) We could prepend a temp node. -- We don't goto the next node when a disc node is created so that we can then treat -- the pre, post and replace. It's a bit of a hack but works out ok for most cases. @@ -3455,7 +3538,6 @@ local function featuresprocessor(head,font,attr) local sequence = dataset[3] -- sequences[s] -- also dataset[5] local rlparmode = 0 local topstack = 0 - local success = false local typ = sequence.type local gpossing = typ == "gpos_single" or typ == "gpos_pair" -- store in dataset local handler = handlers[typ] @@ -3465,7 +3547,7 @@ local function featuresprocessor(head,font,attr) -- this permits injection, watch the different arguments local h, d, ok = handler(head,head,dataset,sequence,nil,nil,nil,0,font,attr) if ok then - success = true + done = true if h then head = h end @@ -3476,7 +3558,10 @@ local function featuresprocessor(head,font,attr) while start do local char = ischar(start,font) if char then - local a = attr and getattr(start,0) + local a -- happens often so no assignment is faster + if attr then + a = getattr(start,0) + end if not a or (a == attr) then for i=1,nofsteps do local step = steps[i] @@ -3488,7 +3573,7 @@ local function featuresprocessor(head,font,attr) local ok head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i) if ok then - success = true + done = true break end end @@ -3518,11 +3603,19 @@ local function featuresprocessor(head,font,attr) while start do local char, id = ischar(start,font) if char then - local a = attr and getattr(start,0) - if a then - a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) - else - a = not attribute or getprop(start,a_state) == attribute + -- local a = attr and getattr(start,0) + -- if a then + -- a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) + -- else + -- a = not attribute or getprop(start,a_state) == attribute + -- end + local a -- happens often so no assignment is faster + if attr then + if getattr(start,0) == attr and (not attribute or getprop(start,a_state) == attribute) then + a = true + end + elseif not attribute or getprop(start,a_state) == attribute then + a = true end if a then local lookupmatch = lookupcache[char] @@ -3530,12 +3623,8 @@ local function featuresprocessor(head,font,attr) local ok head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,1) if ok then - success = true - -- elseif gpossing and zwnjruns and char == zwnj then - -- discrun(start,d_run,font,attr,lookupcache) + done = true end - -- elseif gpossing and zwnjruns and char == zwnj then - -- discrun(start,d_run,font,attr,lookupcache) end if start then start = getnext(start) @@ -3547,26 +3636,16 @@ local function featuresprocessor(head,font,attr) -- whatever glyph start = getnext(start) elseif id == disc_code then - -- ctx: we could assume the same attr as the surrounding glyphs but then we loose - -- the option to have interesting disc nodes (we gain upto 10% on extreme tests); - -- if a disc would have a font field we could even be more strict (see oldstyle test - -- case) - local a = forcedisc or getsubtype(start) == discretionary_code or getattr(start,0) == attr - if a then - -- local attr = false - local ok - if gpossing then - start, ok = kernrun(start,k_run_single, font,attr,lookupcache,step,dataset,sequence,rlmode,handler) - elseif typ == "gsub_ligature" then - start, ok = testrun(start,t_run_single,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,handler) - else - start, ok = comprun(start,c_run_single, font,attr,lookupcache,step,dataset,sequence,rlmode,handler) - end - if ok then - success = true - end + local ok + if gpossing then + start, ok = kernrun(start,k_run_single, font,attr,lookupcache,step,dataset,sequence,rlmode,handler) + elseif typ == "gsub_ligature" then + start, ok = testrun(start,t_run_single,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,handler) else - start = getnext(start) + start, ok = comprun(start,c_run_single, font,attr,lookupcache,step,dataset,sequence,rlmode,handler) + end + if ok then + done = true end elseif id == math_code then start = getnext(end_of_math(start)) @@ -3581,15 +3660,22 @@ local function featuresprocessor(head,font,attr) end else - while start do local char, id = ischar(start,font) if char then - local a = attr and getattr(start,0) - if a then - a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) - else - a = not attribute or getprop(start,a_state) == attribute + -- local a = attr and getattr(start,0) + -- if a then + -- a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) + -- else + -- a = not attribute or getprop(start,a_state) == attribute + -- end + local a -- happens often so no assignment is faster + if attr then + if getattr(start,0) == attr and (not attribute or getprop(start,a_state) == attribute) then + a = true + end + elseif not attribute or getprop(start,a_state) == attribute then + a = true end if a then for i=1,nofsteps do @@ -3602,16 +3688,12 @@ local function featuresprocessor(head,font,attr) local ok head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i) if ok then - success = true + done = true break elseif not start then -- don't ask why ... shouldn't happen break - -- elseif gpossing and zwnjruns and char == zwnj then - -- discrun(start,d_run,font,attr,steps,nofsteps) end - -- elseif gpossing and zwnjruns and char == zwnj then - -- discrun(start,d_run,font,attr,steps,nofsteps) end else report_missing_coverage(dataset,sequence) @@ -3626,22 +3708,16 @@ local function featuresprocessor(head,font,attr) elseif char == false then start = getnext(start) elseif id == disc_code then - -- see comment above - local a = forcedisc or getsubtype(start) == discretionary_code or getattr(start,0) == attr - if a then - local ok - if gpossing then - start, ok = kernrun(start,k_run_multiple, font,attr,steps,nofsteps,dataset,sequence,rlmode,handler) - elseif typ == "gsub_ligature" then - start, ok = testrun(start,t_run_multiple,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler) - else - start, ok = comprun(start,c_run_multiple, font,attr,steps,nofsteps,dataset,sequence,rlmode,handler) - end - if ok then - success = true - end + local ok + if gpossing then + start, ok = kernrun(start,k_run_multiple, font,attr,steps,nofsteps,dataset,sequence,rlmode,handler) + elseif typ == "gsub_ligature" then + start, ok = testrun(start,t_run_multiple,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler) else - start = getnext(start) + start, ok = comprun(start,c_run_multiple, font,attr,steps,nofsteps,dataset,sequence,rlmode,handler) + end + if ok then + done = true end elseif id == math_code then start = getnext(end_of_math(start)) @@ -3656,9 +3732,6 @@ local function featuresprocessor(head,font,attr) end end - if success then - done = true - end if trace_steps then -- ? registerstep(head) end diff --git a/tex/context/base/mkiv/font-pre.mkiv b/tex/context/base/mkiv/font-pre.mkiv index 881a577fb..24bb8de54 100644 --- a/tex/context/base/mkiv/font-pre.mkiv +++ b/tex/context/base/mkiv/font-pre.mkiv @@ -676,16 +676,27 @@ \definefontfeature[f:oldstyle] [onum=yes] \definefontfeature[f:tabular] [tnum=yes] \definefontfeature[f:superiors][sups=yes] +\definefontfeature[f:fractions][frac=yes] \definefontfeature[f:kern] [kern=yes] \definefontfeature[f:kerns] [kern=yes] \definealternativestyle [\v!smallcaps] [\setsmallcaps] [\setsmallcaps] \definealternativestyle [\v!oldstyle] [\setoldstyle ] [\setoldstyle ] +\definealternativestyle [\v!fractions] [\setfractions\resetbreakpoints] [\setfractions\resetbreakpoints] \unexpanded\def\setsmallcaps{\doaddfeature{f:smallcaps}} \unexpanded\def\setoldstyle {\doaddfeature{f:oldstyle}} \unexpanded\def\settabular {\doaddfeature{f:tabular}} \unexpanded\def\setsuperiors{\doaddfeature{f:superiors}} +\unexpanded\def\setfractions{\doaddfeature{f:fractions}} + +% \unexpanded\def\frc#1#2% +% {\dontleavehmode +% \begingroup +% \addff{frac}% +% \resetbreakpoints +% #1/#2% +% \endgroup} %D \macros %D {tinyfont} diff --git a/tex/context/base/mkiv/font-sel.lua b/tex/context/base/mkiv/font-sel.lua index 1bfd41c70..455310e14 100644 --- a/tex/context/base/mkiv/font-sel.lua +++ b/tex/context/base/mkiv/font-sel.lua @@ -18,9 +18,9 @@ local formatters = string.formatters local settings_to_array = utilities.parsers.settings_to_array local settings_to_hash = utilities.parsers.settings_to_hash local allocate = utilities.storage.allocate - + local v_default = interfaces.variables.default - + local implement = interfaces.implement local fonts = fonts @@ -49,7 +49,7 @@ local extras = selectfont.extras local alternatives = selectfont.alternatives local presets = selectfont.presets local defaults = selectfont.defaults - + local ctx_definefontsynonym = context.definefontsynonym local ctx_resetfontfallback = context.resetfontfallback local ctx_startfontclass = context.startfontclass @@ -70,7 +70,6 @@ local report_selectfont = logs.reporter("selectfont") local report_files = logs.reporter("selectfont","files") local report_features = logs.reporter("selectfont","features") local report_goodies = logs.reporter("selectfont","goodies") -local report_alternatives = logs.reporter("selectfont","alternatives") local report_typescript = logs.reporter("selectfont","typescripts") defaults["rm"] = { features = { ["sc"] = "*,f:smallcaps" } } @@ -943,4 +942,4 @@ implement { name = "definefontfamilypreset", actions = selectfont.definefontfamilypreset, arguments = { "string", "string" } -}
\ No newline at end of file +} diff --git a/tex/context/base/mkiv/font-set.mkvi b/tex/context/base/mkiv/font-set.mkvi index b29545ace..2c6d065d8 100644 --- a/tex/context/base/mkiv/font-set.mkvi +++ b/tex/context/base/mkiv/font-set.mkvi @@ -137,7 +137,7 @@ \unexpanded\def\font_preloads_fourth_stage {\begingroup %ifzeropt\fontcharwd\font\number`!\relax - \setbox\scratchbox\hbox{c o n t e x t}% + \setbox\scratchbox\hpack{\tf c o n t e x t}% \ifzeropt\wd\scratchbox \writeline \writestatus\m!fonts{!! No bodyfont has been defined and no defaults have been}% diff --git a/tex/context/base/mkiv/font-sol.lua b/tex/context/base/mkiv/font-sol.lua index 44c337dd5..82fc3dc40 100644 --- a/tex/context/base/mkiv/font-sol.lua +++ b/tex/context/base/mkiv/font-sol.lua @@ -65,8 +65,9 @@ local getattr = nuts.getattr local getfont = nuts.getfont local getsubtype = nuts.getsubtype local getlist = nuts.getlist +local getdir = nuts.getdir +local getwidth = nuts.getwidth -local setfield = nuts.setfield local setattr = nuts.setattr local setlink = nuts.setlink local setnext = nuts.setnext @@ -425,7 +426,7 @@ function splitters.split(head) if start then flush() end - rlmode = getfield(current,"dir") + rlmode = getdir(current) else if start then flush() @@ -757,8 +758,8 @@ function splitters.optimize(head) for current in traverse_ids(hlist_code,tonut(head)) do line = line + 1 local sign = getfield(current,"glue_sign") - local dir = getfield(current,"dir") - local width = getfield(current,"width") + local dir = getdir(current) + local width = getwidth(current) local list = getlist(current) if not encapsulate and getid(list) == glyph_code then -- nasty .. we always assume a prev being there .. future luatex will always have a leftskip set diff --git a/tex/context/base/mkiv/font-web.lua b/tex/context/base/mkiv/font-web.lua index 8ea57f301..452a8f59b 100644 --- a/tex/context/base/mkiv/font-web.lua +++ b/tex/context/base/mkiv/font-web.lua @@ -12,6 +12,9 @@ if not modules then modules = { } end modules ['font-otr'] = { -- and in a tex environment one can as well store the ttf/otf files in the tex tree. So, -- eventually we might even remove this code when version 1 is obsolete. +local ioopen = io.open +local replacesuffix = file.replacesuffix + local readers = fonts and fonts.handlers.otf.readers local streamreader = readers and readers.streamreader or utilities.files @@ -44,10 +47,22 @@ local infotags = { local report = logs.reporter("fonts","woff") +local runner = sandbox.registerrunner { + name = "woff2otf", + method = "execute", + program = "woff2_decompress", + template = "%inputfile% %outputfile%", + reporter = report, + checkers = { + inputfile = "readable", + outputfile = "writable", + } +} + local function woff2otf(inpname,outname,infoonly) - local outname = outname or file.replacesuffix(inpname,"otf") - local inp = io.open(inpname,"rb") + local outname = outname or replacesuffix(inpname,"otf") + local inp = ioopen(inpname,"rb") if not inp then report("invalid input file %a",inpname) @@ -73,7 +88,12 @@ local function woff2otf(inpname,outname,infoonly) if signature == "wOF2" then inp:close() if false then - os.execute("woff2_decompress " .. inpname .. " " .. outname) + if runner then + runner { + inputfile = inpname, + outputfile = outname, + } + end return outname, flavor else report("skipping version 2 file %a",inpname) @@ -81,7 +101,7 @@ local function woff2otf(inpname,outname,infoonly) end end - local out = io.open(outname,"wb") + local out = ioopen(outname,"wb") if not out then inp:close() diff --git a/tex/context/base/mkiv/grph-con.lua b/tex/context/base/mkiv/grph-con.lua index 380f56b14..65bb91631 100644 --- a/tex/context/base/mkiv/grph-con.lua +++ b/tex/context/base/mkiv/grph-con.lua @@ -16,7 +16,6 @@ local settings_to_array = utilities.parsers.settings_to_array local settings_to_hash = utilities.parsers.settings_to_hash local allocate = utilities.storage.allocate local setmetatableindex = table.setmetatableindex -local replacetemplate = utilities.templates.replace local codeinjections = backends.codeinjections local nodeinjections = backends.nodeinjections @@ -34,7 +33,6 @@ local converters = figures.converters local programs = figures.programs local runprogram = programs.run -local makeuptions = programs.makeoptions do -- eps | ps @@ -47,15 +45,16 @@ do -- eps | ps local epsconverter = converters.eps converters.ps = epsconverter - local epstopdf = { - resolutions = { - [v_low] = "screen", - [v_medium] = "ebook", - [v_high] = "prepress", - }, - command = os.type == "windows" and { "gswin64c", "gswin32c" } or "gs", - -- -dProcessDSCComments=false - argument = longtostring [[ + local resolutions = { + [v_low] = "screen", + [v_medium] = "ebook", + [v_high] = "prepress", + } + + local runner = sandbox.registerrunner { + name = "eps to pdf", + program = { windows = "gswin64c", unix = "gs" }, + template = longtostring [[ -q -sDEVICE=pdfwrite -dNOPAUSE @@ -70,10 +69,17 @@ do -- eps | ps "%oldname%" -c quit ]], + checkers = { + oldname = "readable", + newname = "writable", + presets = "string", + level = "string", + colorspace = "string", + }, } - programs.epstopdf = epstopdf - programs.gs = epstopdf + programs.epstopdf = { resolutions = epstopdf, runner = runner } + programs.gs = programs.epstopdf local cleanups = { } local cleaners = { } @@ -85,9 +91,9 @@ do -- eps | ps * P("%AI3_Cropmarks:") * quadruple * P("%%CropBox:") * quadruple / function(b,h,m,c) - return formatters["%%%%BoundingBox: %i %i %i %i\n%%%%HiResBoundingBox: %F %F %F %F\n%%%%CropBox: %F %F %F %F\n"]( - m[1],m[2],m[3],m[4], - m[1],m[2],m[3],m[4], + return formatters["%%%%BoundingBox: %r %r %r %r\n%%%%HiResBoundingBox: %F %F %F %F\n%%%%CropBox: %F %F %F %F\n"]( + m[1],m[2],m[3],m[4], -- rounded integer + m[1],m[2],m[3],m[4], -- real number m[1],m[2],m[3],m[4] ) end @@ -108,8 +114,7 @@ do -- eps | ps end function epsconverter.pdf(oldname,newname,resolution,colorspace) -- the resolution interface might change - local epstopdf = programs.epstopdf -- can be changed - local presets = epstopdf.resolutions[resolution or "high"] or epstopdf.resolutions.high + local presets = resolutions[resolution or "high"] or resolutions.high local level = codeinjections.getformatoption("pdf_level") or "1.3" local tmpname = oldname if not tmpname or tmpname == "" or not lfs.isfile(tmpname) then @@ -124,13 +129,13 @@ do -- eps | ps else colorspace = nil end - runprogram(epstopdf.command, epstopdf.argument, { + runner { newname = newname, oldname = tmpname, presets = presets, level = tostring(level), colorspace = colorspace, - } ) + } if tmpname ~= oldname then os.remove(tmpname) end @@ -144,29 +149,36 @@ do -- eps | ps end -do -- pdf - - local pdfconverter = converters.pdf - - -- programs.pdftoeps = { - -- command = "pdftops", - -- argument = [[-eps "%oldname%" "%newname%"]], - -- } - -- - -- pdfconverter.stripped = function(oldname,newname) - -- local pdftoeps = programs.pdftoeps -- can be changed - -- local epstopdf = programs.epstopdf -- can be changed - -- local presets = epstopdf.resolutions[resolution or ""] or epstopdf.resolutions.high - -- local level = codeinjections.getformatoption("pdf_level") or "1.3" - -- local tmpname = newname .. ".tmp" - -- runprogram(pdftoeps.command, pdftoeps.argument, { oldname = oldname, newname = tmpname, presets = presets, level = level }) - -- runprogram(epstopdf.command, epstopdf.argument, { oldname = tmpname, newname = newname, presets = presets, level = level }) - -- os.remove(tmpname) - -- end - -- - -- figures.registersuffix("stripped","pdf") - -end +-- do -- pdf +-- +-- local pdfconverter = converters.pdf +-- +-- programs.pdftoeps = { +-- runner = sandbox.registerrunner { +-- name = "pdf to ps", +-- command = "pdftops", +-- template = [[-eps "%oldname%" "%newname%"]], +-- checkers = { +-- oldname = "readable", +-- newname = "writable", +-- } +-- } +-- } +-- +-- pdfconverter.stripped = function(oldname,newname) +-- local pdftoeps = programs.pdftoeps -- can be changed +-- local epstopdf = programs.epstopdf -- can be changed +-- local presets = epstopdf.resolutions[resolution or ""] or epstopdf.resolutions.high +-- local level = codeinjections.getformatoption("pdf_level") or "1.3" +-- local tmpname = newname .. ".tmp" +-- pdftoeps.runner { oldname = oldname, newname = tmpname, presets = presets, level = level } +-- epstopdf.runner { oldname = tmpname, newname = newname, presets = presets, level = level } +-- os.remove(tmpname) +-- end +-- +-- figures.registersuffix("stripped","pdf") +-- +-- end do -- svg @@ -177,34 +189,46 @@ do -- svg -- arguments change again? Ok, it's weirder, with -A then it's a name only when -- not . (current) - programs.inkscape = { - command = "inkscape", - pdfargument = longtostring [[ + local runner = sandbox.registerrunner { + name = "svg to something", + program = "inkscape", + template = longtostring [[ "%oldname%" - --export-dpi=600 - --export-pdf="%newname%" - ]], - pngargument = longtostring [[ - "%oldname%" - --export-dpi=600 - --export-png="%newname%" + --export-dpi=%resolution% + --export-%format%="%newname%" ]], + checkers = { + oldname = "readable", + newname = "writable", + format = "string", + resolution = "string", + }, + defaults = { + format = "pdf", + resolution = "600", + } + } + + programs.inkscape = { + runner = runner, } function svgconverter.pdf(oldname,newname) - local inkscape = programs.inkscape -- can be changed - runprogram(inkscape.command, inkscape.pdfargument, { - newname = expandfilename(newname), - oldname = expandfilename(oldname), - } ) + runner { + format = "pdf", + resolution = "600", + newname = expandfilename(newname), + oldname = expandfilename(oldname), + } end function svgconverter.png(oldname,newname) - local inkscape = programs.inkscape - runprogram(inkscape.command, inkscape.pngargument, { - newname = expandfilename(newname), - oldname = expandfilename(oldname), - } ) + runner { + format = "png", + resolution = "600", + newname = expandfilename(newname), + oldname = expandfilename(oldname), + } end svgconverter.default = svgconverter.pdf @@ -280,81 +304,115 @@ do -- png | jpg | profiles return rgbprofile, cmykprofile end - programs.pngtocmykpdf = { - command = "gm", - argument = [[convert -compress Zip -strip +profile "*" -profile "%rgbprofile%" -profile "%cmykprofile%" -sampling-factor 1x1 "%oldname%" "%newname%"]], + local checkers = { + oldname = "readable", + newname = "writable", + rgbprofile = "string", + cmykprofile = "string", + resolution = "string", + color = "string", } - programs.jpgtocmykpdf = { - command = "gm", - argument = [[convert -compress JPEG -strip +profile "*" -profile "%rgbprofile%" -profile "%cmykprofile%" -sampling-factor 1x1 "%oldname%" "%newname%"]], + local defaults = { + resolution = "600", } - programs.pngtograypdf = { - command = "gm", - argument = [[convert -colorspace gray -compress Zip -sampling-factor 1x1 "%oldname%" "%newname%"]], + local pngtocmykpdf = sandbox.registerrunner { + name = "png to cmyk pdf", + program = "gm", + template = [[convert -compress Zip -strip +profile "*" -profile "%rgbprofile%" -profile "%cmykprofile%" -sampling-factor 1x1 "%oldname%" "%newname%"]], + checkers = checkers, + defaults = defaults, } - programs.jpgtograypdf = { - command = "gm", - argument = [[convert -colorspace gray -compress Zip -sampling-factor 1x1 "%oldname%" "%newname%"]], + local jpgtocmykpdf = sandbox.registerrunner { + name = "jpg to cmyk pdf", + program = "gm", + template = [[convert -compress JPEG -strip +profile "*" -profile "%rgbprofile%" -profile "%cmykprofile%" -sampling-factor 1x1 "%oldname%" "%newname%"]], + checkers = checkers, + defaults = defaults, } + local pngtograypdf = sandbox.registerrunner { + name = "png to gray pdf", + program = "gm", + template = [[convert -colorspace gray -compress Zip -sampling-factor 1x1 "%oldname%" "%newname%"]], + checkers = checkers, + defaults = defaults, + } + + local jpgtograypdf = sandbox.registerrunner { + name = "jpg to gray pdf", + program = "gm", + template = [[convert -colorspace gray -compress Zip -sampling-factor 1x1 "%oldname%" "%newname%"]], + checkers = checkers, + defaults = defaults, + } + + programs.pngtocmykpdf = { runner = pngtocmykpdf } + programs.jpgtocmykpdf = { runner = jpgtocmykpdf } + programs.pngtograypdf = { runner = pngtograypdf } + programs.jpgtograypdf = { runner = jpgtograypdf } + pngconverters["cmyk.pdf"] = function(oldname,newname,resolution) local rgbprofile, cmykprofile = profiles() - runprogram(programs.pngtocmykpdf.command, programs.pngtocmykpdf.argument, { - -- runprogram(programs.pngtocmykpdf, { - rgbprofile = rgbprofile, - cmykprofile = cmykprofile, + pngtocmykpdf { oldname = oldname, newname = newname, - } ) + rgbprofile = rgbprofile, + cmykprofile = cmykprofile, + resolution = resolution, + } end pngconverters["gray.pdf"] = function(oldname,newname,resolution) - runprogram(programs.pngtograypdf.command, programs.pngtograypdf.argument, { - -- runprogram(programs.pngtograypdf, { - oldname = oldname, - newname = newname, - } ) + pngtograypdf { + oldname = oldname, + newname = newname, + resolution = resolution, + } end jpgconverters["cmyk.pdf"] = function(oldname,newname,resolution) local rgbprofile, cmykprofile = profiles() - runprogram(programs.jpgtocmykpdf.command, programs.jpgtocmykpdf.argument, { - -- runprogram(programs.jpgtocmykpdf, { - rgbprofile = rgbprofile, - cmykprofile = cmykprofile, + jpgtocmykpdf { oldname = oldname, newname = newname, - } ) + rgbprofile = rgbprofile, + cmykprofile = cmykprofile, + resolution = resolution, + } end jpgconverters["gray.pdf"] = function(oldname,newname,resolution) - runprogram(programs.jpgtograypdf.command, programs.jpgtograypdf.argument, { - -- runprogram(programs.jpgtograypdf, { - oldname = oldname, - newname = newname, - } ) + jpgtograypdf { + oldname = oldname, + newname = newname, + resolution = resolution, + } end -- recolor - programs.recolor = { - command = "gm", - argument = [[convert -recolor "%color%" "%oldname%" "%newname%"]], + local recolorpng = sandbox.registerrunner { + name = "recolor png", + program = "gm", + template = [[convert -recolor "%color%" "%oldname%" "%newname%"]], + checkers = checkers, + defaults = defaults, } + -- this is now built in so not really needed any more + + programs.recolor = { runner = recolorpng } + pngconverters["recolor.png"] = function(oldname,newname,resolution,arguments) - runprogram ( - programs.recolor.command, - programs.recolor.argument, - { - oldname = oldname, - newname = newname, - color = arguments or ".5 0 0 .7 0 0 .9 0 0", - } - ) + recolorpng { + oldname = oldname, + newname = newname, + resolution = resolution, + color = arguments or ".5 0 0 .7 0 0 .9 0 0", + } end end diff --git a/tex/context/base/mkiv/grph-fil.lua b/tex/context/base/mkiv/grph-fil.lua index e774d097e..3c069da37 100644 --- a/tex/context/base/mkiv/grph-fil.lua +++ b/tex/context/base/mkiv/grph-fil.lua @@ -42,6 +42,16 @@ end job.register('job.files.collected', tobesaved, initializer) +local runner = sandbox.registerrunner { + name = "hashed context run", + program = "context", + template = [[%options% "%filename%"]], + checkers = { + options = "string", + filename = "readable", + } +} + function jobfiles.run(name,action) local usedname = addsuffix(name,inputsuffix) -- we assume tex if not set local oldchecksum = collected[usedname] @@ -55,7 +65,10 @@ function jobfiles.run(name,action) if ta == "function" then action(name) elseif ta == "string" and action ~= "" then + -- can be anything but we assume it gets checked by the sandbox os.execute(action) + elseif ta == "table" then + runner(action) else report_run("processing file, no action given for processing %a",name) end @@ -79,7 +92,7 @@ function jobfiles.context(name,options) else local result = replacesuffix(name,resultsuffix) if not done[result] then - jobfiles.run(name,"context ".. (options or "") .. " " .. name) + jobfiles.run(name, { options = options, filename = name }) done[result] = true end return result diff --git a/tex/context/base/mkiv/grph-inc.lua b/tex/context/base/mkiv/grph-inc.lua index 901d31827..b5e74b4c1 100644 --- a/tex/context/base/mkiv/grph-inc.lua +++ b/tex/context/base/mkiv/grph-inc.lua @@ -47,7 +47,6 @@ local concat, insert, remove = table.concat, table.insert, table.remove local todimen = string.todimen local collapsepath = file.collapsepath local formatters = string.formatters -local expandfilename = dir.expandname local formatcolumns = utilities.formatters.formatcolumns local P, R, S, Cc, C, Cs, Ct, lpegmatch = lpeg.P, lpeg.R, lpeg.S, lpeg.Cc, lpeg.C, lpeg.Cs, lpeg.Ct, lpeg.match @@ -97,16 +96,12 @@ end local report_inclusion = logs.reporter("graphics","inclusion") local report_figures = logs.reporter("system","graphics") local report_figure = logs.reporter("used graphic") -local report_status = logs.reporter("graphics","status") local report_newline = logs.newline local f_hash_part = formatters["%s->%s->%s->%s"] local f_hash_full = formatters["%s->%s->%s->%s->%s->%s->%s->%s"] local v_yes = variables.yes -local v_low = variables.low -local v_medium = variables.medium -local v_high = variables.high local v_global = variables["global"] local v_local = variables["local"] local v_default = variables.default @@ -1636,13 +1631,15 @@ includers.cld = includers.nongeneric setmetatableindex(converters,"table") +-- We keep this helper because it has been around for a while and therefore it can +-- be a depedency in an existing workflow. + function programs.makeoptions(options) local to = type(options) return (to == "table" and concat(options," ")) or (to == "string" and options) or "" end function programs.run(binary,argument,variables) - -- move this check to the runner code local found = nil if type(binary) == "table" then for i=1,#binary do diff --git a/tex/context/base/mkiv/grph-inc.mkiv b/tex/context/base/mkiv/grph-inc.mkiv index 90453b8ed..881bf9713 100644 --- a/tex/context/base/mkiv/grph-inc.mkiv +++ b/tex/context/base/mkiv/grph-inc.mkiv @@ -316,7 +316,7 @@ \edef\p_reference{\externalfigureparameter\c!reference}% % \dostarttagged\t!image\empty - \clf_figure_push + \clf_figure_push { name {\p_grph_include_name}% label {\ifx\p_label\empty\p_grph_include_label\else\p_label\fi}% page {\externalfigureparameter\c!page}% @@ -343,7 +343,7 @@ \ifx\p_height\empty \else height \dimexpr\p_height\relax \fi - \relax + }%\relax \clf_figure_identify \relax \ifconditional\c_grph_include_test_only diff --git a/tex/context/base/mkiv/grph-rul.lua b/tex/context/base/mkiv/grph-rul.lua index 4ac73b6ae..e3d1d8963 100644 --- a/tex/context/base/mkiv/grph-rul.lua +++ b/tex/context/base/mkiv/grph-rul.lua @@ -175,6 +175,7 @@ interfaces.implement { { "name", "string" }, } } , actions = function(t) + -- no nuts ! local rule = userrule(t) local ma = getattribute(a_colormodel) or 1 local ca = getattribute(a_color) diff --git a/tex/context/base/mkiv/l-lpeg.lua b/tex/context/base/mkiv/l-lpeg.lua index 959ca553e..877dae644 100644 --- a/tex/context/base/mkiv/l-lpeg.lua +++ b/tex/context/base/mkiv/l-lpeg.lua @@ -839,28 +839,48 @@ end local p_false = P(false) local p_true = P(true) -local function make(t) - local function making(t) - local p = p_false - local keys = sortedkeys(t) - for i=1,#keys do - local k = keys[i] - if k ~= "" then - local v = t[k] - if v == true then - p = p + P(k) * p_true - elseif v == false then - -- can't happen - else - p = p + P(k) * making(v) - end - end - end - if t[""] then - p = p + p_true - end - return p - end +-- local function making(t) +-- local p = p_false +-- local keys = sortedkeys(t) +-- for i=1,#keys do +-- local k = keys[i] +-- if k ~= "" then +-- local v = t[k] +-- if v == true then +-- p = p + P(k) * p_true +-- elseif v == false then +-- -- can't happen +-- else +-- p = p + P(k) * making(v) +-- end +-- end +-- end +-- if t[""] then +-- p = p + p_true +-- end +-- return p +-- end + +-- local function make(t) +-- local p = p_false +-- local keys = sortedkeys(t) +-- for i=1,#keys do +-- local k = keys[i] +-- if k ~= "" then +-- local v = t[k] +-- if v == true then +-- p = p + P(k) * p_true +-- elseif v == false then +-- -- can't happen +-- else +-- p = p + P(k) * making(v) +-- end +-- end +-- end +-- return p +-- end + +local function make(t,rest) local p = p_false local keys = sortedkeys(t) for i=1,#keys do @@ -872,10 +892,13 @@ local function make(t) elseif v == false then -- can't happen else - p = p + P(k) * making(v) + p = p + P(k) * make(v,v[""]) end end end + if rest then + p = p + p_true + end return p end @@ -990,21 +1013,21 @@ end -- local t = { "a", "abc", "ac", "abe", "abxyz", "xy", "bef","aa" } -- local p = lpeg.Cs((lpeg.utfchartabletopattern(t)/string.upper + 1)^1) --- inspect(lpegmatch(p,"a")) --- inspect(lpegmatch(p,"aa")) --- inspect(lpegmatch(p,"aaaa")) --- inspect(lpegmatch(p,"ac")) --- inspect(lpegmatch(p,"bc")) --- inspect(lpegmatch(p,"zzbczz")) --- inspect(lpegmatch(p,"zzabezz")) --- inspect(lpegmatch(p,"ab")) --- inspect(lpegmatch(p,"abc")) --- inspect(lpegmatch(p,"abe")) --- inspect(lpegmatch(p,"xa")) --- inspect(lpegmatch(p,"bx")) --- inspect(lpegmatch(p,"bax")) --- inspect(lpegmatch(p,"abxyz")) --- inspect(lpegmatch(p,"foobarbefcrap")) +-- inspect(lpegmatch(p,"a")=="A") +-- inspect(lpegmatch(p,"aa")=="AA") +-- inspect(lpegmatch(p,"aaaa")=="AAAA") +-- inspect(lpegmatch(p,"ac")=="AC") +-- inspect(lpegmatch(p,"bc")=="bc") +-- inspect(lpegmatch(p,"zzbczz")=="zzbczz") +-- inspect(lpegmatch(p,"zzabezz")=="zzABEzz") +-- inspect(lpegmatch(p,"ab")=="Ab") +-- inspect(lpegmatch(p,"abc")=="ABC") +-- inspect(lpegmatch(p,"abe")=="ABE") +-- inspect(lpegmatch(p,"xa")=="xA") +-- inspect(lpegmatch(p,"bx")=="bx") +-- inspect(lpegmatch(p,"bax")=="bAx") +-- inspect(lpegmatch(p,"abxyz")=="ABXYZ") +-- inspect(lpegmatch(p,"foobarbefcrap")=="foobArBEFcrAp") -- local t = { ["^"] = 1, ["^^"] = 2, ["^^^"] = 3, ["^^^^"] = 4 } -- local p = lpeg.Cs((lpeg.utfchartabletopattern(t)/t + 1)^1) diff --git a/tex/context/base/mkiv/l-lua.lua b/tex/context/base/mkiv/l-lua.lua index 357153836..adc2c97a8 100644 --- a/tex/context/base/mkiv/l-lua.lua +++ b/tex/context/base/mkiv/l-lua.lua @@ -188,7 +188,7 @@ if lua then lua.mask = load([[τεχ = 1]]) and "utf" or "ascii" end -local flush = io.flush +local flush = io.flush if flush then @@ -199,3 +199,85 @@ if flush then end +-- new + +if ffi and ffi.number then + -- already loaded +else + local okay + + okay, ffi = pcall(require,"ffi") + + if not ffi then + -- an old version + elseif ffi.os == "" or ffi.arch == "" then + -- no ffi support + ffi = nil + elseif ffi.number then + -- luatex + else + -- luajittex + ffi.number = tonumber + end +end + +-- done differently in context +-- +-- if ffi then +-- local load = ffi.load +-- local select = select +-- local type = type +-- local next = next +-- local sort = table.sort +-- local gmatch = string.gmatch +-- local okay = true +-- local control = { } +-- function ffi.load(name,...) +-- if okay == true or okay[name] then +-- return load(name,...) +-- else +-- return nil +-- end +-- end +-- function control.permit(...) +-- if okay == true then +-- okay = { } +-- end +-- for i=1,select("#",...) do +-- local n = select(i,...) +-- local t = type(n) +-- if t == "table" then +-- for i=1,#n do +-- control.permit(n[i]) +-- end +-- elseif t == "string" then +-- for s in gmatch(n,"[^,%s]+") do +-- okay[n] = true +-- end +-- end +-- end +-- end +-- function control.freeze(none) +-- control.permit = function() end +-- control.freeze = function() end +-- if none then +-- okay = { } +-- end +-- end +-- function control.permitted(name) +-- if okay == true then +-- return true +-- elseif type(name) == "string" then +-- return okay[name] or false +-- else +-- -- no helpers yet +-- local t = { } +-- for k, v in next, okay do +-- t[#t+1] = k +-- end +-- sort(t) +-- return t +-- end +-- end +-- ffi.control = control +-- end diff --git a/tex/context/base/mkiv/l-os.lua b/tex/context/base/mkiv/l-os.lua index 0a86ea6d6..5108faeef 100644 --- a/tex/context/base/mkiv/l-os.lua +++ b/tex/context/base/mkiv/l-os.lua @@ -119,7 +119,7 @@ end local execute = os.execute local iopopen = io.popen -function os.resultof(command) +local function resultof(command) local handle = iopopen(command,"r") -- already has flush if handle then local result = handle:read("*all") or "" @@ -130,9 +130,15 @@ function os.resultof(command) end end +os.resultof = resultof + +function os.pipeto(command) + return iopopen(command,"w") -- already has flush +end + if not io.fileseparator then if find(os.getenv("PATH"),";",1,true) then - io.fileseparator, io.pathseparator, os.type = "\\", ";", os.type or "mswin" + io.fileseparator, io.pathseparator, os.type = "\\", ";", os.type or "windows" else io.fileseparator, io.pathseparator, os.type = "/" , ":", os.type or "unix" end @@ -203,17 +209,17 @@ end }) local name, platform = os.name or "linux", os.getenv("MTX_PLATFORM") or "" -local function guess() - local architecture = os.resultof("uname -m") or "" - if architecture ~= "" then - return architecture - end - architecture = os.getenv("HOSTTYPE") or "" - if architecture ~= "" then - return architecture - end - return os.resultof("echo $HOSTTYPE") or "" -end +-- local function guess() +-- local architecture = resultof("uname -m") or "" +-- if architecture ~= "" then +-- return architecture +-- end +-- architecture = os.getenv("HOSTTYPE") or "" +-- if architecture ~= "" then +-- return architecture +-- end +-- return resultof("echo $HOSTTYPE") or "" +-- end -- os.bits = 32 | 64 @@ -245,7 +251,7 @@ 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 os.resultof("uname -m") or "" + local platform, architecture = "", os.getenv("HOSTTYPE") or resultof("uname -m") or "" if find(architecture,"x86_64",1,true) then platform = "linux-64" elseif find(architecture,"ppc",1,true) then @@ -273,9 +279,9 @@ elseif name == "macosx" then function resolvers.platform(t,k) -- local platform, architecture = "", os.getenv("HOSTTYPE") or "" -- if architecture == "" then - -- architecture = os.resultof("echo $HOSTTYPE") or "" + -- architecture = resultof("echo $HOSTTYPE") or "" -- end - local platform, architecture = "", os.resultof("echo $HOSTTYPE") or "" + local platform, architecture = "", resultof("echo $HOSTTYPE") or "" 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" @@ -294,7 +300,7 @@ elseif name == "macosx" then elseif name == "sunos" then function resolvers.platform(t,k) - local platform, architecture = "", os.resultof("uname -m") or "" + local platform, architecture = "", resultof("uname -m") or "" if find(architecture,"sparc",1,true) then platform = "solaris-sparc" else -- if architecture == 'i86pc' @@ -308,7 +314,7 @@ elseif name == "sunos" then elseif name == "freebsd" then function resolvers.platform(t,k) - local platform, architecture = "", os.resultof("uname -m") or "" + local platform, architecture = "", resultof("uname -m") or "" if find(architecture,"amd64",1,true) then platform = "freebsd-amd64" else @@ -323,7 +329,7 @@ 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 os.resultof("uname -m") or "" + local platform, architecture = "", os.getenv("HOSTTYPE") or resultof("uname -m") or "" if find(architecture,"x86_64",1,true) then platform = "kfreebsd-amd64" else diff --git a/tex/context/base/mkiv/l-sandbox.lua b/tex/context/base/mkiv/l-sandbox.lua index f7901379c..a95e70395 100644 --- a/tex/context/base/mkiv/l-sandbox.lua +++ b/tex/context/base/mkiv/l-sandbox.lua @@ -8,8 +8,8 @@ if not modules then modules = { } end modules ['l-sandbox'] = { -- We use string instead of function variables, so 'io.open' instead of io.open. That -- way we can still intercept repetetive overloads. One complication is that when we use --- sandboxed function sin helpers in the sanbox checkers, we can get a recursion loop --- so for that vreason we need to keep originals around till we enable the sandbox. +-- sandboxed functions in helpers in the sanbox checkers, we can get a recursion loop +-- so for that reason we need to keep originals around till we enable the sandbox. -- if sandbox then return end @@ -23,6 +23,8 @@ local format = string.format -- no formatters yet local concat = table.concat local sort = table.sort local gmatch = string.gmatch +local gsub = string.gsub +local requiem = require sandbox = { } local sandboxed = false @@ -34,6 +36,7 @@ local originals = { } local comments = { } local trace = false local logger = false +local blocked = { } -- this comes real early, so that we can still alias @@ -139,29 +142,62 @@ function sandbox.overload(func,overload,comment) return func end -function sandbox.initializer(f) - if not sandboxed then - initializers[#initializers+1] = f +local function whatever(specification,what,target) + if type(specification) ~= "table" then + report("%s needs a specification",what) + elseif type(specification.category) ~= "string" or type(specification.action) ~= "function" then + report("%s needs a category and action",what) + elseif not sandboxed then + target[#target+1] = specification elseif trace then - report("already enabled, discarding initializer") + report("already enabled, discarding %s",what) end end -function sandbox.finalizer(f) - if not sandboxed then - finalizers[#finalizers+1] = f - elseif trace then - report("already enabled, discarding finalizer") +function sandbox.initializer(specification) + whatever(specification,"initializer",initializers) +end + +function sandbox.finalizer(specification) + whatever(specification,"finalizer",finalizers) +end + +function require(name) + local n = gsub(name,"^.*[\\/]","") + local n = gsub(n,"[%.].*$","") + local b = blocked[n] + if b then + if trace then + report("using blocked: %s",n) + end + return b + else + if trace then + report("requiring: %s",name) + end + return requiem(name) + end +end + +function blockrequire(name,lib) + if trace then + report("preventing reload of: %s",name) end + blocked[name] = lib or _G[name] +end + +if TEXENGINE == "luajittex" or not ffi then + local ok + ok, ffi = pcall(require,"ffi") end function sandbox.enable() if not sandboxed then for i=1,#initializers do - initializers[i]() + initializers[i].action() end for i=1,#finalizers do - finalizers[i]() + finalizers[i].action() end local nnot = 0 local nyes = 0 @@ -189,22 +225,48 @@ function sandbox.enable() end if #cyes > 0 then sort(cyes) - report(" overloaded known : %s",concat(cyes," | ")) + report("overloaded known: %s",concat(cyes," | ")) end if nyes > 0 then - report(" overloaded unknown : %s",nyes) + report("overloaded unknown: %s",nyes) end if #cnot > 0 then sort(cnot) - report("not overloaded known : %s",concat(cnot," | ")) + report("not overloaded known: %s",concat(cnot," | ")) end if nnot > 0 then - report("not overloaded unknown : %s",nnot) + report("not overloaded unknown: %s",nnot) end if #skip > 0 then sort(skip) - report("not overloaded redefined : %s",concat(skip," | ")) + report("not overloaded redefined: %s",concat(skip," | ")) end + -- + -- if ffi then + -- report("disabling ffi") + -- -- for k, v in next, ffi do + -- -- if k ~= "gc" then + -- -- local t = type(v) + -- -- if t == "function" then + -- -- ffi[k] = function() report("accessing ffi.%s",k) end + -- -- elseif t == "number" then + -- -- ffi[k] = 0 + -- -- elseif t == "string" then + -- -- ffi[k] = "" + -- -- elseif t == "table" then + -- -- ffi[k] = { } + -- -- else + -- -- ffi[k] = false + -- -- end + -- -- end + -- -- end + -- for k, v in next, ffi do + -- if k ~= "gc" then + -- ffi[k] = nil + -- end + -- end + -- end + -- initializers = nil finalizers = nil originals = nil @@ -212,6 +274,13 @@ function sandbox.enable() end end +blockrequire("lfs",lfs) +blockrequire("io",io) +blockrequire("os",os) +blockrequire("ffi",ffi) + +-- require = register(require,"require") + -- we sandbox some of the built-in functions now: -- todo: require diff --git a/tex/context/base/mkiv/l-unicode.lua b/tex/context/base/mkiv/l-unicode.lua index 3dec80013..b913d0cfc 100644 --- a/tex/context/base/mkiv/l-unicode.lua +++ b/tex/context/base/mkiv/l-unicode.lua @@ -1270,3 +1270,35 @@ function utf.chrlen(u) -- u is number (u < 0xFC and 5) or (u < 0xFE and 6) or 0 end + +-- hashing saves a little but not that much in practice +-- +-- local utf32 = table.setmetatableindex(function(t,k) local v = toutf32(k) t[k] = v return v end) + +local extract = bit32.extract +local char = string.char + +function unicode.toutf32string(n) + if n <= 0xFF then + return + char(n) .. + "\000\000\000" + elseif n <= 0xFFFF then + return + char(extract(n, 0,8)) .. + char(extract(n, 8,8)) .. + "\000\000" + elseif n <= 0xFFFFFF then + return + char(extract(n, 0,8)) .. + char(extract(n, 8,8)) .. + char(extract(n,16,8)) .. + "\000" + else + return + char(extract(n, 0,8)) .. + char(extract(n, 8,8)) .. + char(extract(n,16,8)) .. + char(extract(n,24,8)) + end +end diff --git a/tex/context/base/mkiv/lang-dis.lua b/tex/context/base/mkiv/lang-dis.lua index e6ea180b0..34d7ec000 100644 --- a/tex/context/base/mkiv/lang-dis.lua +++ b/tex/context/base/mkiv/lang-dis.lua @@ -13,6 +13,9 @@ local nodes = nodes local tasks = nodes.tasks local nuts = nodes.nuts +local enableaction = tasks.enableaction +local setaction = tasks.setaction + local tonode = nuts.tonode local tonut = nuts.tonut @@ -29,12 +32,17 @@ local getchar = nuts.getchar local setchar = nuts.setchar local getdisc = nuts.getdisc local setdisc = nuts.setdisc +local getlang = nuts.setlang +local getboth = nuts.getboth +local setlist = nuts.setlist +local setlink = nuts.setlink local isglyph = nuts.isglyph local copy_node = nuts.copy local remove_node = nuts.remove local traverse_id = nuts.traverse_id local flush_list = nuts.flush_list +local flush_node = nuts.flush_node local nodecodes = nodes.nodecodes local disccodes = nodes.disccodes @@ -83,7 +91,7 @@ local expanders = { -- todo: take existing penalty setdisc(d,pre,post,replace,explicit_code,tex.exhyphenpenalty) else - setfield(d,"subtype",explicit_code) + setsubtype(d,explicit_code) end return template end, @@ -141,7 +149,7 @@ local expanders = { end end if template then - local language = template and getfield(template,"lang") + local language = template and getlang(template) local data = getlanguagedata(language) local prechar = data.prehyphenchar local postchar = data.posthyphenchar @@ -214,7 +222,7 @@ function languages.showdiscretionaries(v) setattribute(a_visualize,unsetvalue) else -- also nil if not enabled then - nodes.tasks.enableaction("processors","languages.visualizediscretionaries") + enableaction("processors","languages.visualizediscretionaries") enabled = true end setattribute(a_visualize,1) @@ -237,3 +245,71 @@ function languages.serializediscretionary(d) -- will move to tracer ) end +-- -- + +local wiped = 0 + +local function wipe(head,delayed) + local p, n = getboth(delayed) + local _, _, h, _, _, t = getdisc(delayed,true) + if p or n then + if h then + setlink(p,h) + setlink(t,n) + setfield(delayed,"replace") + else + setlink(p,n) + end + end + if head == delayed then + head = h + end + wiped = wiped + 1 + flush_node(delayed) + return head +end + +function languages.flatten(head) + local nuthead = tonut(head) + local delayed = nil + for d in traverse_id(disc_code,nuthead) do + if delayed then + nuthead = wipe(nuthead,delayed) + end + delayed = d + end + if delayed then + return tonode(wipe(nuthead,delayed)), true + else + return head, false + end +end + +function languages.nofflattened() + return wiped -- handy for testing +end + +-- experiment + +local flatten = languages.flatten +local getlist = nodes.getlist + +function nodes.handlers.flattenline(head) + local list = getlist(head) + if list then + flatten(list) + end + return head +end + +function nodes.handlers.flatten(head,where) + if head and (where == "box" or where == "adjusted_hbox") then + return flatten(head) + end + return true +end + +directives.register("hyphenator.flatten",function(v) + setaction("processors","nodes.handlers.flatten",v) + setaction("contributers","nodes.handlers.flattenline",v) +end) diff --git a/tex/context/base/mkiv/lang-hyp.lua b/tex/context/base/mkiv/lang-hyp.lua index b80bb003b..50132bfe1 100644 --- a/tex/context/base/mkiv/lang-hyp.lua +++ b/tex/context/base/mkiv/lang-hyp.lua @@ -78,6 +78,8 @@ if not modules then modules = { } end modules ['lang-hyp'] = { -- ins : when hyphenationbounds 2 or 3 -- adjust : when hyphenationbounds 2 or 3 +-- todo: maybe subtypes (because they have subtle meanings in the line breaking) + local type, rawset, tonumber, next = type, rawset, tonumber, next local P, R, S, Cg, Cf, Ct, Cc, C, Carg, Cs = lpeg.P, lpeg.R, lpeg.S, lpeg.Cg, lpeg.Cf, lpeg.Ct, lpeg.Cc, lpeg.C, lpeg.Carg, lpeg.Cs @@ -652,9 +654,11 @@ if context then local getprev = nuts.getprev local getsubtype = nuts.getsubtype local getlist = nuts.getlist + local getlang = nuts.getlang + local getattrlist = nuts.getattrlist + local setattrlist = nuts.setattrlist local isglyph = nuts.isglyph - local setfield = nuts.setfield local setchar = nuts.setchar local setdisc = nuts.setdisc @@ -993,6 +997,8 @@ if context then [nodecodes.math] = true, } + -- local gf = getfield local gt = setmetatableindex("number") getfield = function(n,f) gt[f] = gt[f] + 1 return gf(n,f) end languages.GETFIELD = gt + function traditional.hyphenate(head) local first = tonut(head) @@ -1045,7 +1051,7 @@ if context then local function insertpenalty() local p = new_penalty(interwordpenalty) - setfield(p,"attr",getfield(last,"attr")) + setattrlist(p,last) if trace_visualize then nuts.setvisual(p,"penalty") end @@ -1233,7 +1239,7 @@ if context then local current = start - local attributes = getfield(start,"attr") -- todo: just copy the last disc .. faster + local attrnode = start -- will be different, just the first char for i=1,rsize do local r = result[i] @@ -1248,8 +1254,8 @@ if context then post = serialize(true,leftchar) end setdisc(disc,pre,post,nil,discretionary_code,hyphenpenalty) - if attributes then - setfield(disc,"attr",attributes) + if attrnode then + setattrlist(disc,attrnode) end -- could be a replace as well insert_before(first,current,disc) @@ -1282,8 +1288,8 @@ if context then end end setdisc(disc,pre,post,replace,discretionary_code,hyphenpenalty) - if attributes then - setfield(disc,"attr",attributes) + if attrnode then + setattrlist(disc,attrnode) end insert_before(first,current,disc) else @@ -1303,7 +1309,7 @@ if context then end - local function inject(leftchar,rightchar,code,attributes) + local function inject(leftchar,rightchar,code,attrnode) if first ~= current then local disc = new_disc() first, current, glyph = remove_node(first,current) @@ -1322,8 +1328,8 @@ if context then pre = copy_node(glyph) setchar(pre,rightchar and rightchar > 0 and rightchar or code) setdisc(disc,pre,post,replace,discretionary_code,hyphenpenalty) - if attributes then - setfield(disc,"attr",attributes) + if attrnode then + setattrlist(disc,attrnode) end end return current @@ -1343,9 +1349,10 @@ if context then while current and current ~= last do -- and current local code, id = isglyph(current) if code then - local lang = getfield(current,"lang") + local lang = getlang(current) if lang ~= language then if dictionary and size > charmin and leftmin + rightmin <= size then + -- only german has many words starting with an uppercase character if categories[word[1]] == "lu" and getfield(start,"uchyph") < 0 then -- skip else @@ -1411,9 +1418,9 @@ if context then -- maybe also a strict mode here: no hyphenation before hyphenchars and skip -- the next set (but then, strict is an option) if code == exhyphenchar then - current = inject(leftexchar,rightexchar,code,getfield(current,"attr")) + current = inject(leftexchar,rightexchar,code,current) elseif hyphenchars and hyphenchars[code] then - current = inject(leftchar,rightchar,code,getfield(current,"attr")) + current = inject(leftchar,rightchar,code,current) end end else @@ -1557,11 +1564,13 @@ if context then local getcount = tex.getcount hyphenators.methods = methods - hyphenators.optimize = false + local optimize = false + + directives.register("hyphenator.optimize", function(v) optimize = v end) function hyphenators.handler(head,groupcode) if usedmethod then - if groupcode == "hbox" and hyphenators.optimize then + if optimize and (groupcode == "hbox" or groupcode == "adjusted_hbox") then if getcount("hyphenstate") > 0 then forced = false return usedmethod(head) diff --git a/tex/context/base/mkiv/lang-rep.lua b/tex/context/base/mkiv/lang-rep.lua index 2e998b7fb..6fde353f7 100644 --- a/tex/context/base/mkiv/lang-rep.lua +++ b/tex/context/base/mkiv/lang-rep.lua @@ -52,11 +52,13 @@ local getchar = nuts.getchar local isglyph = nuts.isglyph local setfield = nuts.setfield +local getfield = nuts.getfield local setattr = nuts.setattr local setlink = nuts.setlink local setnext = nuts.setnext local setprev = nuts.setprev local setchar = nuts.setchar +local setattrlist = nuts.setattrlist local insert_node_before = nuts.insert_before local remove_node = nuts.remove @@ -70,6 +72,8 @@ local new_disc = nodepool.disc local texsetattribute = tex.setattribute local unsetvalue = attributes.unsetvalue +local enableaction = nodes.tasks.enableaction + local v_reset = interfaces.variables.reset local implement = interfaces.implement @@ -222,34 +226,35 @@ function replacements.handler(head) local i = 1 while i <= newlength do local codes = newcodes[i] - local new = nil if type(codes) == "table" then local method = codes[1] if method == "discretionary" then local pre, post, replace = codes[2], codes[3], codes[4] - new = new_disc() if pre then - setfield(new,"pre",tonodes(pre,last)) + pre = tonodes(pre,last) end if post then - setfield(new,"post",tonodes(post,last)) + post = tonodes(post,last) end if replace then - setfield(new,"replace",tonodes(replace,last)) + replace = tonodes(replace,last) end + -- todo: also set attr + local new = new_disc(pre,post,replace) + setattrlist(new,last) head, current = insert_after(head,current,new) elseif method == "noligature" then -- not that efficient to copy but ok for testing local list = codes[2] if list then for i=1,#list do - new = copy_node(last) + local new = copy_node(last) setchar(new,list[i]) setattr(new,a_noligature,1) head, current = insert_after(head,current,new) end else - new = copy_node(last) + local new = copy_node(last) setchar(new,zwnj) head, current = insert_after(head,current,new) end @@ -257,7 +262,7 @@ function replacements.handler(head) -- todo end else - new = copy_node(last) + local new = copy_node(last) setchar(new,codes) head, current = insert_after(head,current,new) end @@ -310,7 +315,7 @@ function replacements.set(n) else n = lists[n].attribute if not enabled then - nodes.tasks.enableaction("processors","languages.replacements.handler") + enableaction("processors","languages.replacements.handler") if trace_replacements then report_replacement("enabling replacement handler") end diff --git a/tex/context/base/mkiv/lang-wrd.lua b/tex/context/base/mkiv/lang-wrd.lua index 38e6187af..8b6e48401 100644 --- a/tex/context/base/mkiv/lang-wrd.lua +++ b/tex/context/base/mkiv/lang-wrd.lua @@ -38,6 +38,7 @@ local getid = nuts.getid local getsubtype = nuts.getsubtype local getchar = nuts.getchar local setattr = nuts.setattr +local getlang = nuts.getlang local isglyph = nuts.isglyph local traverse_nodes = nuts.traverse @@ -45,7 +46,7 @@ local traverse_ids = nuts.traverse_id local wordsdata = words.data local chardata = characters.data -local tasks = nodes.tasks +local enableaction = nodes.tasks.enableaction local unsetvalue = attributes.unsetvalue @@ -161,7 +162,7 @@ local function mark_words(head,whenfound) -- can be optimized and shared while current do local code, id = isglyph(current) if code then - local a = getfield(current,"lang") + local a = getlang(current) if a then if a ~= language then if s > 0 then @@ -234,7 +235,7 @@ function words.enable(settings) if e then e(settings) end - tasks.enableaction("processors","languages.words.check") + enableaction("processors","languages.words.check") enabled = true end diff --git a/tex/context/base/mkiv/lpdf-ano.lua b/tex/context/base/mkiv/lpdf-ano.lua index 138388c7c..e89bda12b 100644 --- a/tex/context/base/mkiv/lpdf-ano.lua +++ b/tex/context/base/mkiv/lpdf-ano.lua @@ -229,7 +229,6 @@ luatex.registerstopactions(function() end end) - local function pdfnametree(destinations) local slices = { } local sorted = table.sortedkeys(destinations) diff --git a/tex/context/base/mkiv/lpdf-mis.lua b/tex/context/base/mkiv/lpdf-mis.lua index 8d2e85ad2..dc3f8560a 100644 --- a/tex/context/base/mkiv/lpdf-mis.lua +++ b/tex/context/base/mkiv/lpdf-mis.lua @@ -442,10 +442,10 @@ local function documentspecification() addtocatalog("Version", pdfconstant(format("1.%s",pdf.getminorversion()))) end --- temp hack: the mediabox is not under our control and has a precision of 4 digits +-- temp hack: the mediabox is not under our control and has a precision of 5 digits local factor = number.dimenfactors.bp -local f_value = formatters["%0.4F"] +local f_value = formatters["%0.5F"] local function boxvalue(n) -- we could share them return pdfverbose(f_value(factor * n)) diff --git a/tex/context/base/mkiv/lpdf-res.lua b/tex/context/base/mkiv/lpdf-res.lua index ca092c772..ac9478488 100644 --- a/tex/context/base/mkiv/lpdf-res.lua +++ b/tex/context/base/mkiv/lpdf-res.lua @@ -12,7 +12,7 @@ local implement = interfaces.implement local nuts = nodes.nuts local tonut = nodes.tonut -local setfield = nuts.setfield +local setwhd = nuts.setwhd local setlist = nuts.setlist local new_hlist = nuts.pool.hlist @@ -29,9 +29,7 @@ function codeinjections.restoreboxresource(index) local hbox = new_hlist() local list, wd, ht, dp = useboxresource(index) setlist(hbox,tonut(list)) - setfield(hbox,"width", wd) - setfield(hbox,"height", ht) - setfield(hbox,"depth", dp) + setwhd(hbox,wd,ht,dp) return hbox -- so we return a nut ! end diff --git a/tex/context/base/mkiv/lpdf-tag.lua b/tex/context/base/mkiv/lpdf-tag.lua index 3167aeb5c..e33c8a811 100644 --- a/tex/context/base/mkiv/lpdf-tag.lua +++ b/tex/context/base/mkiv/lpdf-tag.lua @@ -24,7 +24,7 @@ local nodes = nodes local nodeinjections = backends.pdf.nodeinjections local codeinjections = backends.pdf.codeinjections -local tasks = nodes.tasks +local enableaction = nodes.tasks.enableaction local pdfdictionary = lpdf.dictionary local pdfarray = lpdf.array @@ -602,9 +602,9 @@ end function codeinjections.enabletags(tg,lb) structures.tags.handler = nodeinjections.addtags - tasks.enableaction("shipouts","structures.tags.handler") - tasks.enableaction("shipouts","nodes.handlers.accessibility") - tasks.enableaction("math","noads.handlers.tags") + enableaction("shipouts","structures.tags.handler") + enableaction("shipouts","nodes.handlers.accessibility") + enableaction("math","noads.handlers.tags") -- maybe also textblock if trace_tags then report_tags("enabling structure tags") diff --git a/tex/context/base/mkiv/luat-cbk.lua b/tex/context/base/mkiv/luat-cbk.lua index 2c3bede72..7b28b3be4 100644 --- a/tex/context/base/mkiv/luat-cbk.lua +++ b/tex/context/base/mkiv/luat-cbk.lua @@ -70,9 +70,12 @@ directives.register("system.callbacks.permitoverloads", function(v) end end) -sandbox.initializer(function() - block_overloads = true -end) +sandbox.initializer { + category = "functions", + action = function() + block_overloads = true + end +} if not list then -- otherwise counters get reset diff --git a/tex/context/base/mkiv/luat-cod.lua b/tex/context/base/mkiv/luat-cod.lua index f62396a8e..31860db78 100644 --- a/tex/context/base/mkiv/luat-cod.lua +++ b/tex/context/base/mkiv/luat-cod.lua @@ -6,7 +6,7 @@ if not modules then modules = { } end modules ['luat-cod'] = { license = "see context related readme files" } -local type, loadfile = type, loadfile +local type, loadfile, tonumber = type, loadfile, tonumber local match, gsub, find, format = string.match, string.gsub, string.find, string.format local texconfig, lua = texconfig, lua @@ -96,7 +96,29 @@ local targetpath = "." -- environment.jobname = tex.jobname -- environment.version = tostring(tex.toks.contextversiontoks) -environment.initex = tex.formatname == "" +if LUATEXVERION == nil then + LUATEXVERSION = status.luatex_version/100 + + tonumber(status.luatex_revision)/1000 +end + +if LUATEXENGINE == nil then + LUATEXENGINE = status.luatex_engine and string.lower(status.luatex_engine) + or (find(status.banner,"LuajitTeX") and "luajittex" or "luatex") +end + +if JITSUPPORTED == nil then + JITSUPPORTED = LUATEXENGINE == "luajittex" or jit +end + +if INITEXMODE == nil then + INITEXMODE = status.ini_version +end + +environment.initex = INITEXMODE +environment.initexmode = INITEXMODE +environment.luatexversion = LUATEXVERSION +environment.luatexengine = LUATEXENGINE +environment.jitsupported = JITSUPPORTED if not environment.luafilechunk then diff --git a/tex/context/base/mkiv/luat-exe.lua b/tex/context/base/mkiv/luat-exe.lua index d8d954a30..1e9811218 100644 --- a/tex/context/base/mkiv/luat-exe.lua +++ b/tex/context/base/mkiv/luat-exe.lua @@ -8,66 +8,118 @@ if not modules then modules = { } end modules ['luat-exe'] = { if not sandbox then require("l-sandbox") require("util-sbx") end -- for testing +-- Ok, as usual, after finishing some code, I rewarded myself with searching youtube for +-- new music ... this time I ran into the swedisch group 'wintergatan' (search for: marble +-- machine) ... mechanical computers are so much more fun than the ones needed for running +-- the code below. Nice videos (and shows) too ... + local type = type -local executers = resolvers.executers or { } -resolvers.executers = executers +local executers = resolvers.executers or { } +resolvers.executers = executers -local disablerunners = sandbox.disablerunners -local registerbinary = sandbox.registerbinary -local registerroot = sandbox.registerroot +local disablerunners = sandbox.disablerunners +local disablelibraries = sandbox.disablelibraries +local registerbinary = sandbox.registerbinary +local registerlibrary = sandbox.registerlibrary +local registerroot = sandbox.registerroot -local lpegmatch = lpeg.match +local lpegmatch = lpeg.match -local sc_splitter = lpeg.tsplitat(";") -local cm_splitter = lpeg.tsplitat(",") +local sc_splitter = lpeg.tsplitat(";") +local cm_splitter = lpeg.tsplitat(",") local execution_mode directives.register("system.executionmode", function(v) execution_mode = v end) local execution_list directives.register("system.executionlist", function(v) execution_list = v end) local root_list directives.register("system.rootlist", function(v) root_list = v end) +local library_mode directives.register("system.librarymode", function(v) library_mode = v end) +local library_list directives.register("system.librarylist", function(v) library_list = v end) -sandbox.initializer(function() - if execution_mode == "none" then - -- will be done later - elseif execution_mode == "list" then - if type(execution_list) == "string" then - execution_list = lpegmatch(cm_splitter,execution_list) - end - if type(execution_list) == "table" then - for i=1,#execution_list do - registerbinary(execution_list[i]) +sandbox.initializer { + category = "binaries", + action = function() + if execution_mode == "none" then + -- will be done later + elseif execution_mode == "list" then + if type(execution_list) == "string" then + execution_list = lpegmatch(cm_splitter,execution_list) + end + if type(execution_list) == "table" then + for i=1,#execution_list do + registerbinary(execution_list[i]) + end end + else + registerbinary(true) -- all end - else - -- whatever else we have configured end -end) +} -sandbox.initializer(function() - if type(root_list) == "string" then - root_list = lpegmatch(sc_splitter,root_list) +sandbox.finalizer { + category = "binaries", + action = function() + if execution_mode == "none" then + disablerunners() + end end - if type(root_list) == "table" then - for i=1,#root_list do - local entry = root_list[i] - if entry ~= "" then - registerroot(entry) +} + +sandbox.initializer { + category = "libraries", + action = function() + if library_mode == "none" then + -- will be done later + elseif library_mode == "list" then + if type(library_list) == "string" then + library_list = lpegmatch(cm_splitter,library_list) + end + if type(library_list) == "table" then + for i=1,#library_list do + registerlibrary(library_list[i]) + end end + else + registerlibrary(true) -- all + end + end +} + +sandbox.finalizer { + category = "libraries", + action = function() + if library_mode == "none" then + disablelibraries() end end -end) +} -sandbox.finalizer(function() - if execution_mode == "none" then - disablerunners() +-- A bit of file system protection. + +sandbox.initializer{ + category = "files", + action = function () + if type(root_list) == "string" then + root_list = lpegmatch(sc_splitter,root_list) + end + if type(root_list) == "table" then + for i=1,#root_list do + local entry = root_list[i] + if entry ~= "" then + registerroot(entry) + end + end + end end -end) +} -- Let's prevent abuse of these libraries (built-in support still works). -sandbox.finalizer(function() - mplib = nil - epdf = nil - zip = nil - fontloader = nil -end) +sandbox.finalizer { + category = "functions", + action = function() + mplib = nil + epdf = nil + zip = nil + fontloader = nil + end +} diff --git a/tex/context/base/mkiv/luat-fmt.lua b/tex/context/base/mkiv/luat-fmt.lua index b5ea5685a..fe3c1042c 100644 --- a/tex/context/base/mkiv/luat-fmt.lua +++ b/tex/context/base/mkiv/luat-fmt.lua @@ -51,6 +51,33 @@ end -- The silent option is Taco. It's a bit of a hack because we cannot yet mess -- with directives. In fact, I could probably clean up the maker a bit by now. +local template = [[--ini %primaryflags% --lua="%luafile%" "%texfile%" %secondaryflags% %dump% %redirect%]] +local checkers = { + primaryflags = "string", + secondaryflags = "string", + luafile = "readable", -- "cache" + texfile = "readable", -- "cache" + redirect = "string", + dump = "string", +} + +local runners = { + luatex = sandbox.registerrunner { + name = "make luatex format", + program = "luatex", + template = template, + checkers = checkers, + reporter = report_format, + }, + luajittex = sandbox.registerrunner { + name = "make luajittex format", + program = "luajittex", + template = template, + checkers = checkers, + reporter = report_format, + }, +} + function environment.make_format(name,arguments) local engine = environment.ownmain or "luatex" local silent = environment.arguments.silent @@ -116,13 +143,20 @@ function environment.make_format(name,arguments) return end -- generate format - local dump = os.platform=="unix" and "\\\\dump" or "\\dump" - local command = format("%s --ini %s --lua=%s %s %s %s", - engine,primaryflags(),quoted(usedluastub),quoted(fulltexsourcename),secondaryflags(),dump) - if silent then + local specification = { + primaryflags = primaryflags(), + secondaryflags = secondaryflags(), + luafile = usedluastub, + texfile = fulltexsourcename, + dump = os.platform == "unix" and "\\\\dump" or "\\dump", + } + local runner = runners[engine] + if not runner then + report_format("format %a cannot be generated, no runner available for engine %a",name,engine) + elseif silent then statistics.starttiming() - local command = format("%s > temp.log",command) - local result = os.execute(command) + specification.redirect = "> temp.log" + local result = makeformat(specification) local runtime = statistics.stoptiming() if result ~= 0 then print(format("%s silent make > fatal error when making format %q",engine,name)) -- we use a basic print @@ -131,8 +165,7 @@ function environment.make_format(name,arguments) end os.remove("temp.log") else - report_format("running command: %s\n",command) - os.execute(command) + makeformat(specification) end -- remove related mem files local pattern = file.removesuffix(file.basename(usedluastub)).."-*.mem" diff --git a/tex/context/base/mkiv/luat-ini.lua b/tex/context/base/mkiv/luat-ini.lua index cd1f45692..3ea8551c8 100644 --- a/tex/context/base/mkiv/luat-ini.lua +++ b/tex/context/base/mkiv/luat-ini.lua @@ -25,4 +25,12 @@ if not global then global = _G end -LUATEXVERSION = status.luatex_version/100 + tonumber(status.luatex_revision)/1000 +LUATEXVERSION = status.luatex_version/100 + + tonumber(status.luatex_revision)/1000 + +LUATEXENGINE = status.luatex_engine and string.lower(status.luatex_engine) + or (string.find(status.banner,"LuajitTeX") and "luajittex" or "luatex") + +JITSUPPORTED = LUATEXENGINE == "luajittex" or jit + +INITEXMODE = status.ini_version diff --git a/tex/context/base/mkiv/luat-iop.lua b/tex/context/base/mkiv/luat-iop.lua index e1772af4e..34cc74e3e 100644 --- a/tex/context/base/mkiv/luat-iop.lua +++ b/tex/context/base/mkiv/luat-iop.lua @@ -9,16 +9,19 @@ if not modules then modules = { } end modules ['luat-iop'] = { local cleanedpathlist = resolvers.cleanedpathlist local registerroot = sandbox.registerroot -sandbox.initializer(function() - local function register(str,mode) - local trees = cleanedpathlist(str) - for i=1,#trees do - registerroot(trees[i],mode) +sandbox.initializer { + category = "files", + action = function() + local function register(str,mode) + local trees = cleanedpathlist(str) + for i=1,#trees do + registerroot(trees[i],mode) + end end + register("TEXMF","read") + register("TEXINPUTS","read") + register("MPINPUTS","read") + -- register("TEXMFCACHE","write") + registerroot(".","write") end - register("TEXMF","read") - register("TEXINPUTS","read") - register("MPINPUTS","read") - -- register("TEXMFCACHE","write") - registerroot(".","write") -end) +} diff --git a/tex/context/base/mkiv/lxml-ini.lua b/tex/context/base/mkiv/lxml-ini.lua index 6026b1090..11f634739 100644 --- a/tex/context/base/mkiv/lxml-ini.lua +++ b/tex/context/base/mkiv/lxml-ini.lua @@ -41,6 +41,8 @@ implement { name = "xmldoifelseselfempty", actions = lxml.doifelseempty, arg --------- { name = "xmlflushstripped", actions = lxml.strip, arguments = { "string", true } } implement { name = "xmlall", actions = lxml.all, arguments = { "string", "string" } } implement { name = "xmllastmatch", actions = lxml.lastmatch } +implement { name = "xmlpushmatch", actions = lxml.pushmatch } +implement { name = "xmlpopmatch", actions = lxml.popmatch } implement { name = "xmlatt", actions = lxml.att, arguments = { "string", "string" } } implement { name = "xmllastatt", actions = lxml.lastatt } implement { name = "xmlattdef", actions = lxml.att, arguments = { "string", "string", "string" } } diff --git a/tex/context/base/mkiv/lxml-ini.mkiv b/tex/context/base/mkiv/lxml-ini.mkiv index bf641f10b..6ba6bc8d4 100644 --- a/tex/context/base/mkiv/lxml-ini.mkiv +++ b/tex/context/base/mkiv/lxml-ini.mkiv @@ -82,6 +82,8 @@ \let\xmllast \clf_xmllast \let\xmllastatt \clf_xmllastatt \let\xmllastmatch \clf_xmllastmatch +\let\xmlpushmatch \clf_xmlpushmatch +\let\xmlpopmatch \clf_xmlpopmatch \let\xmlloaddirectives \clf_xmlloaddirectives \let\xmlmain \clf_xmlmain \let\xmlmatch \clf_xmlmatch diff --git a/tex/context/base/mkiv/lxml-lpt.lua b/tex/context/base/mkiv/lxml-lpt.lua index 19d69076a..939a737ab 100644 --- a/tex/context/base/mkiv/lxml-lpt.lua +++ b/tex/context/base/mkiv/lxml-lpt.lua @@ -820,36 +820,38 @@ local pathparser = Ct { "patterns", -- can be made a bit faster by moving some p + V("s_parent") + V("s_self") + V("s_root") - + V("s_ancestor"), + + V("s_ancestor") + + V("s_lastmatch"), shortcuts = V("shortcuts_a") * (spaces * "/" * spaces * V("shortcuts_a"))^0, s_descendant_or_self = (P("***/") + P("/")) * Cc(register_descendant_or_self), --- *** is a bonus s_descendant = P("**") * Cc(register_descendant), - s_child = P("*") * no_nextcolon * Cc(register_child ), - s_parent = P("..") * Cc(register_parent ), - s_self = P("." ) * Cc(register_self ), - s_root = P("^^") * Cc(register_root ), - s_ancestor = P("^") * Cc(register_ancestor ), + s_child = P("*") * no_nextcolon * Cc(register_child), + s_parent = P("..") * Cc(register_parent), + s_self = P("." ) * Cc(register_self), + s_root = P("^^") * Cc(register_root), + s_ancestor = P("^") * Cc(register_ancestor), + s_lastmatch = P("=") * Cc(register_last_match), -- we can speed this up when needed but we cache anyway so ... - descendant = P("descendant::") * Cc(register_descendant ), - child = P("child::") * Cc(register_child ), - parent = P("parent::") * Cc(register_parent ), - self = P("self::") * Cc(register_self ), - root = P('root::') * Cc(register_root ), - ancestor = P('ancestor::') * Cc(register_ancestor ), - descendant_or_self = P('descendant-or-self::') * Cc(register_descendant_or_self ), - ancestor_or_self = P('ancestor-or-self::') * Cc(register_ancestor_or_self ), - -- attribute = P('attribute::') * Cc(register_attribute ), - -- namespace = P('namespace::') * Cc(register_namespace ), - following = P('following::') * Cc(register_following ), - following_sibling = P('following-sibling::') * Cc(register_following_sibling ), - preceding = P('preceding::') * Cc(register_preceding ), - preceding_sibling = P('preceding-sibling::') * Cc(register_preceding_sibling ), - reverse_sibling = P('reverse-sibling::') * Cc(register_reverse_sibling ), - last_match = P('last-match::') * Cc(register_last_match ), + descendant = P("descendant::") * Cc(register_descendant), + child = P("child::") * Cc(register_child), + parent = P("parent::") * Cc(register_parent), + self = P("self::") * Cc(register_self), + root = P('root::') * Cc(register_root), + ancestor = P('ancestor::') * Cc(register_ancestor), + descendant_or_self = P('descendant-or-self::') * Cc(register_descendant_or_self), + ancestor_or_self = P('ancestor-or-self::') * Cc(register_ancestor_or_self), + -- attribute = P('attribute::') * Cc(register_attribute), + -- namespace = P('namespace::') * Cc(register_namespace), + following = P('following::') * Cc(register_following), + following_sibling = P('following-sibling::') * Cc(register_following_sibling), + preceding = P('preceding::') * Cc(register_preceding), + preceding_sibling = P('preceding-sibling::') * Cc(register_preceding_sibling), + reverse_sibling = P('reverse-sibling::') * Cc(register_reverse_sibling), + last_match = P('last-match::') * Cc(register_last_match), selector = P("{") * C((1-P("}"))^1) * P("}") / register_selector, @@ -1197,6 +1199,16 @@ do return lastmatch end + local stack = { } + + function xml.pushmatch() + insert(stack,lastmatch) + end + + function xml.popmatch() + lastmatch = remove(stack) + end + end local applylpath = xml.applylpath diff --git a/tex/context/base/mkiv/lxml-tex.lua b/tex/context/base/mkiv/lxml-tex.lua index fc86b9460..582185ba8 100644 --- a/tex/context/base/mkiv/lxml-tex.lua +++ b/tex/context/base/mkiv/lxml-tex.lua @@ -53,7 +53,8 @@ local xmlinclusions = xml.inclusions local xmlbadinclusions = xml.badinclusions local xmlcontent = xml.content local xmllastmatch = xml.lastmatch - +local xmlpushmatch = xml.pushmatch +local xmlpopmatch = xml.popmatch directives.enable("xml.path.keeplastmatch") @@ -1943,6 +1944,9 @@ function lxml.lastmatch() end end +lxml.pushmatch = xmlpushmatch +lxml.popmatch = xmlpopmatch + function lxml.snippet(id,i) local e = getid(id) if e then diff --git a/tex/context/base/mkiv/math-dir.lua b/tex/context/base/mkiv/math-dir.lua index 6978ba3b5..cba991b84 100644 --- a/tex/context/base/mkiv/math-dir.lua +++ b/tex/context/base/mkiv/math-dir.lua @@ -41,7 +41,7 @@ local insert_node_before = nuts.insert_before local insert_node_after = nuts.insert_after local nodecodes = nodes.nodecodes -local tasks = nodes.tasks +local enableaction = nodes.tasks.enableaction local glyph_code = nodecodes.glyph local hlist_code = nodecodes.hlist @@ -160,7 +160,7 @@ function directions.setmath(n) if trace_directions then report_directions("enabling directions handler") end - tasks.enableaction("math","typesetters.directions.processmath") + enableaction("math","typesetters.directions.processmath") enabled = true end end diff --git a/tex/context/base/mkiv/math-ini.lua b/tex/context/base/mkiv/math-ini.lua index de7592c87..321014d94 100644 --- a/tex/context/base/mkiv/math-ini.lua +++ b/tex/context/base/mkiv/math-ini.lua @@ -189,32 +189,16 @@ local escapes = characters.filters.utf.private.escapes -- not that many so no need to reuse tables -local setmathcharacter - -if LUATEXVERSION > 0.98 then - setmathcharacter = function(class,family,slot,unicode,mset,dset) - if mset and codes[class] then -- regular codes < 7 - setmathcode("global",slot,class,family,unicode) - mset = false - end - if dset and class == open_class or class == close_class or class == middle_class then - setdelcode("global",slot,family,unicode,0,0) - dset = false - end - return mset, dset +local setmathcharacter = function(class,family,slot,unicode,mset,dset) + if mset and codes[class] then -- regular codes < 7 + setmathcode("global",slot,class,family,unicode) + mset = false end -else - setmathcharacter = function(class,family,slot,unicode,mset,dset) - if mset and codes[class] then -- regular codes < 7 - setmathcode("global",slot,{class,family,unicode}) - mset = false - end - if dset and class == open_class or class == close_class or class == middle_class then - setdelcode("global",slot,{family,unicode,0,0}) - dset = false - end - return mset, dset + if dset and class == open_class or class == close_class or class == middle_class then + setdelcode("global",slot,family,unicode,0,0) + dset = false end + return mset, dset end local f_accent = formatters[ [[\ugdef\%s{\Umathaccent 0 "%X "%X }]] ] diff --git a/tex/context/base/mkiv/math-ini.mkiv b/tex/context/base/mkiv/math-ini.mkiv index 90478771e..3b57c56da 100644 --- a/tex/context/base/mkiv/math-ini.mkiv +++ b/tex/context/base/mkiv/math-ini.mkiv @@ -118,6 +118,7 @@ \definesystemattribute[mathcategory] [public] \definesystemattribute[mathmode] [public] \definesystemattribute[mathitalics] [public] +\definesystemattribute[mathkernpairs] [public] \definesystemattribute[mathbidi] [public] \definesystemattribute[mathdomain] [public] @@ -237,7 +238,9 @@ \def\math_m_yes_text[#1]% {\begingroup - \edef\currentmathematics{#1}% check for valid + \doifassignmentelse{#1}% + {\setupcurrentmathematics[#1]}% + {\edef\currentmathematics{#1}}% check for valid \edef\p_openup{\mathematicsparameter\c!openup}% \ifx\p_openup\v!yes \expandafter\math_m_yes_text_openedup @@ -1357,6 +1360,31 @@ % \csname\??mathitalics\mathematicsparameter\s!italics\endcsname % \to \everyswitchmathematics % only in mathematics +%D Math kerns (experiment) + +\installcorenamespace{mathkernpairs} + +\setnewconstant\c_math_kernpairs_attribute\attributeunsetvalue % no real need for an extra constant + +\def\math_kernpairs_initialize + {\ifnum\c_math_kernpairs_attribute=\attributeunsetvalue \else + \clf_initializemathkernpairs % one time + \global\let\math_kernpairs_initialize\relax + \fi} + +\appendtoks + \edef\p_kernpairs{\mathematicsparameter\s!kernpairs}% + \c_math_kernpairs_attribute\ifx\p_kernpairs\v!yes\plusone\else\attributeunsetvalue\fi\relax +\to \everyswitchmathematics % only in mathematics + +\appendtoks + \math_kernpairs_initialize + \attribute\mathkernpairsattribute\c_math_kernpairs_attribute +\to \everymathematics + +\setupmathematics + [\s!kernpairs=\v!no] + %D \macros %D {enablemathpunctuation,disablemathpunctuation} %D diff --git a/tex/context/base/mkiv/math-noa.lua b/tex/context/base/mkiv/math-noa.lua index 2b0d7b73f..fb08c4ef4 100644 --- a/tex/context/base/mkiv/math-noa.lua +++ b/tex/context/base/mkiv/math-noa.lua @@ -56,6 +56,7 @@ local trace_goodies = false registertracker("math.goodies", function local trace_variants = false registertracker("math.variants", function(v) trace_variants = v end) local trace_alternates = false registertracker("math.alternates", function(v) trace_alternates = v end) local trace_italics = false registertracker("math.italics", function(v) trace_italics = v end) +local trace_kernpairs = false registertracker("math.kernpairs", function(v) trace_kernpairs = v end) local trace_domains = false registertracker("math.domains", function(v) trace_domains = v end) local trace_families = false registertracker("math.families", function(v) trace_families = v end) local trace_fences = false registertracker("math.fences", function(v) trace_fences = v end) @@ -71,6 +72,7 @@ local report_goodies = logreporter("mathematics","goodies") local report_variants = logreporter("mathematics","variants") local report_alternates = logreporter("mathematics","alternates") local report_italics = logreporter("mathematics","italics") +local report_kernpairs = logreporter("mathematics","kernpairs") local report_domains = logreporter("mathematics","domains") local report_families = logreporter("mathematics","families") local report_fences = logreporter("mathematics","fences") @@ -86,6 +88,7 @@ local nutstring = nuts.tostring local setfield = nuts.setfield local setlink = nuts.setlink +local setlist = nuts.setlist local setnext = nuts.setnext local setprev = nuts.setprev local setchar = nuts.setchar @@ -101,6 +104,15 @@ local getsubtype = nuts.getsubtype local getchar = nuts.getchar local getfont = nuts.getfont local getattr = nuts.getattr +local getlist = nuts.getlist + +local getnucleus = nuts.getnucleus +local getsub = nuts.getsub +local getsup = nuts.getsup + +local setnucleus = nuts.setnucleus +local setsub = nuts.setsub +local setsup = nuts.setsup local flush_node = nuts.flush local new_node = nuts.new -- todo: pool: math_noad math_sub @@ -139,6 +151,8 @@ noads.handlers = noads.handlers or { } local handlers = noads.handlers local tasks = nodes.tasks +local enableaction = tasks.enableaction +local setaction = tasks.setaction local nodecodes = nodes.nodecodes local noadcodes = nodes.noadcodes @@ -175,6 +189,9 @@ local right_fence_code = fencecodes.right -- this initial stuff is tricky as we can have removed and new nodes with the same address -- the only way out is a free-per-page list of nodes (not bad anyway) +-- local gf = getfield local gt = setmetatableindex("number") getfield = function(n,f) gt[f] = gt[f] + 1 return gf(n,f) end mathematics.GETFIELD = gt +-- 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 @@ -223,13 +240,13 @@ local function process(start,what,n,parent) end elseif id == math_noad then -- single characters are like this - local noad = getfield(start,"nucleus") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"sup") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"sub") if noad then process(noad,what,n,start) end -- list + local noad = getnucleus(start) if noad then process(noad,what,n,start) end -- list + noad = getsup (start) if noad then process(noad,what,n,start) end -- list + noad = getsub (start) if noad then process(noad,what,n,start) end -- list elseif id == math_char or id == math_textchar or id == math_delim then break elseif id == math_box or id == math_sub then - local noad = getfield(start,"list") if noad then process(noad,what,n,start) end -- list (not getlist !) + local noad = getlist(start) if noad then process(noad,what,n,start) end -- list (not getlist !) elseif id == math_fraction then local noad = getfield(start,"num") if noad then process(noad,what,n,start) end -- list noad = getfield(start,"denom") if noad then process(noad,what,n,start) end -- list @@ -243,15 +260,15 @@ local function process(start,what,n,parent) elseif id == math_fence then local noad = getfield(start,"delim") if noad then process(noad,what,n,start) end -- delimiter elseif id == math_radical then - local noad = getfield(start,"nucleus") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"sup") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"sub") if noad then process(noad,what,n,start) end -- list + local noad = getnucleus(start) if noad then process(noad,what,n,start) end -- list + noad = getsup (start) if noad then process(noad,what,n,start) end -- list + noad = getsub (start) if noad then process(noad,what,n,start) end -- list noad = getfield(start,"left") if noad then process(noad,what,n,start) end -- delimiter noad = getfield(start,"degree") if noad then process(noad,what,n,start) end -- list elseif id == math_accent then - local noad = getfield(start,"nucleus") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"sup") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"sub") if noad then process(noad,what,n,start) end -- list + local noad = getnucleus(start) if noad then process(noad,what,n,start) end -- list + noad = getsup (start) if noad then process(noad,what,n,start) end -- list + noad = getsub (start) if noad then process(noad,what,n,start) end -- list noad = getfield(start,"accent") if noad then process(noad,what,n,start) end -- list noad = getfield(start,"bot_accent") if noad then process(noad,what,n,start) end -- list -- elseif id == math_style then @@ -270,11 +287,11 @@ local function processnested(current,what,n) local noad = nil local id = getid(current) if id == math_noad then - noad = getfield(current,"nucleus") if noad then process(noad,what,n,current) end -- list - noad = getfield(current,"sup") if noad then process(noad,what,n,current) end -- list - noad = getfield(current,"sub") if noad then process(noad,what,n,current) end -- list + noad = getnucleus(current) if noad then process(noad,what,n,current) end -- list + noad = getsup (current) if noad then process(noad,what,n,current) end -- list + noad = getsub (current) if noad then process(noad,what,n,current) end -- list elseif id == math_box or id == math_sub then - noad = getfield(current,"list") if noad then process(noad,what,n,current) end -- list (not getlist !) + noad = getlist(current) if noad then process(noad,what,n,current) end -- list (not getlist !) elseif id == math_fraction then noad = getfield(current,"num") if noad then process(noad,what,n,current) end -- list noad = getfield(current,"denom") if noad then process(noad,what,n,current) end -- list @@ -288,15 +305,15 @@ local function processnested(current,what,n) elseif id == math_fence then noad = getfield(current,"delim") if noad then process(noad,what,n,current) end -- delimiter elseif id == math_radical then - noad = getfield(current,"nucleus") if noad then process(noad,what,n,current) end -- list - noad = getfield(current,"sup") if noad then process(noad,what,n,current) end -- list - noad = getfield(current,"sub") if noad then process(noad,what,n,current) end -- list + noad = getnucleus(current) if noad then process(noad,what,n,current) end -- list + noad = getsup (current) if noad then process(noad,what,n,current) end -- list + noad = getsub (current) if noad then process(noad,what,n,current) end -- list noad = getfield(current,"left") if noad then process(noad,what,n,current) end -- delimiter noad = getfield(current,"degree") if noad then process(noad,what,n,current) end -- list elseif id == math_accent then - noad = getfield(current,"nucleus") if noad then process(noad,what,n,current) end -- list - noad = getfield(current,"sup") if noad then process(noad,what,n,current) end -- list - noad = getfield(current,"sub") if noad then process(noad,what,n,current) end -- list + noad = getnucleus(current) if noad then process(noad,what,n,current) end -- list + noad = getsup (current) if noad then process(noad,what,n,current) end -- list + noad = getsub (current) if noad then process(noad,what,n,current) end -- list noad = getfield(current,"accent") if noad then process(noad,what,n,current) end -- list noad = getfield(current,"bot_accent") if noad then process(noad,what,n,current) end -- list end @@ -306,11 +323,11 @@ local function processstep(current,process,n,id) local noad = nil local id = id or getid(current) if id == math_noad then - noad = getfield(current,"nucleus") if noad then process(noad,n,current) end -- list - noad = getfield(current,"sup") if noad then process(noad,n,current) end -- list - noad = getfield(current,"sub") if noad then process(noad,n,current) end -- list + noad = getnucleus(current) if noad then process(noad,n,current) end -- list + noad = getsup (current) if noad then process(noad,n,current) end -- list + noad = getsub (current) if noad then process(noad,n,current) end -- list elseif id == math_box or id == math_sub then - noad = getfield(current,"list") if noad then process(noad,n,current) end -- list (not getlist !) + noad = getlist(current) if noad then process(noad,n,current) end -- list (not getlist !) elseif id == math_fraction then noad = getfield(current,"num") if noad then process(noad,n,current) end -- list noad = getfield(current,"denom") if noad then process(noad,n,current) end -- list @@ -324,15 +341,15 @@ local function processstep(current,process,n,id) elseif id == math_fence then noad = getfield(current,"delim") if noad then process(noad,n,current) end -- delimiter elseif id == math_radical then - noad = getfield(current,"nucleus") if noad then process(noad,n,current) end -- list - noad = getfield(current,"sup") if noad then process(noad,n,current) end -- list - noad = getfield(current,"sub") if noad then process(noad,n,current) end -- list + noad = getnucleus(current) if noad then process(noad,n,current) end -- list + noad = getsup (current) if noad then process(noad,n,current) end -- list + noad = getsub (current) if noad then process(noad,n,current) end -- list noad = getfield(current,"left") if noad then process(noad,n,current) end -- delimiter noad = getfield(current,"degree") if noad then process(noad,n,current) end -- list elseif id == math_accent then - noad = getfield(current,"nucleus") if noad then process(noad,n,current) end -- list - noad = getfield(current,"sup") if noad then process(noad,n,current) end -- list - noad = getfield(current,"sub") if noad then process(noad,n,current) end -- list + noad = getnucleus(current) if noad then process(noad,n,current) end -- list + noad = getsup (current) if noad then process(noad,n,current) end -- list + noad = getsub (current) if noad then process(noad,n,current) end -- list noad = getfield(current,"accent") if noad then process(noad,n,current) end -- list noad = getfield(current,"bot_accent") if noad then process(noad,n,current) end -- list end @@ -703,8 +720,8 @@ local function makefence(what,char) local d = new_node(math_delim) local f = new_node(math_fence) if char then - local sym = getfield(char,"nucleus") - local chr = getfield(sym,"char") + local sym = getnucleus(char) + local chr = getchar(sym) local fam = getfield(sym,"fam") if chr == dummyfencechar then chr = 0 @@ -720,9 +737,9 @@ end local function makelist(noad,f_o,o_next,c_prev,f_c,middle) local list = new_node(math_sub) - setfield(list,"head",f_o) + setlist(list,f_o) setsubtype(noad,noad_inner) - setfield(noad,"nucleus",list) + setnucleus(noad,list) setlink(f_o,o_next) setlink(c_prev,f_c) if middle and next(middle) then @@ -733,12 +750,11 @@ local function makelist(noad,f_o,o_next,c_prev,f_c,middle) if m then local next = getnext(current) local fence = makefence(middle_fence_code,current) - setfield(current,"nucleus",nil) + setnucleus(current) flush_node(current) middle[current] = nil -- replace_node - setlink(prev,fence) - setlink(fence,next) + setlink(prev,fence,next) prev = fence current = next else @@ -758,7 +774,7 @@ local function convert_both(open,close,middle) local f_o = makefence(left_fence_code,open) local f_c = makefence(right_fence_code,close) makelist(open,f_o,o_next,c_prev,f_c,middle) - setfield(close,"nucleus",nil) + setnucleus(close) flush_node(close) if c_next then setprev(c_next,open) @@ -877,7 +893,7 @@ implement { name = "enableautofences", onlyonce = true, actions = function() - tasks.enableaction("math","noads.handlers.autofences") + enableaction("math","noads.handlers.autofences") enabled = true end } @@ -904,8 +920,8 @@ local function replace(pointer,what,n,parent) local start_super, stop_super, start_sub, stop_sub local mode = "unset" while next and getid(next) == math_noad do - local nextnucleus = getfield(next,"nucleus") - if nextnucleus and getid(nextnucleus) == math_char and not getfield(next,"sub") and not getfield(next,"sup") then + local nextnucleus = getnucleus(next) + if nextnucleus and getid(nextnucleus) == math_char and not getsub(next) and not getsup(next) then local char = getchar(nextnucleus) local s = superscripts[char] if s then @@ -948,11 +964,11 @@ local function replace(pointer,what,n,parent) end if start_super then if start_super == stop_super then - setfield(pointer,"sup",getfield(start_super,"nucleus")) + setsup(pointer,getnucleus(start_super)) else local list = new_node(math_sub) -- todo attr - setfield(list,"list",start_super) - setfield(pointer,"sup",list) + setlist(list,start_super) + setsup(pointer,list) end if mode == "super" then setnext(pointer,getnext(stop_super)) @@ -961,11 +977,11 @@ local function replace(pointer,what,n,parent) end if start_sub then if start_sub == stop_sub then - setfield(pointer,"sub",getfield(start_sub,"nucleus")) + setsub(pointer,getnucleus(start_sub)) else local list = new_node(math_sub) -- todo attr - setfield(list,"list",start_sub) - setfield(pointer,"sub",list) + setlist(list,start_sub) + setsub(pointer,list) end if mode == "sub" then setnext(pointer,getnext(stop_sub)) @@ -1237,9 +1253,9 @@ local c_negative_d = "trace:dr" local function insert_kern(current,kern) local sub = new_node(math_sub) -- todo: pool local noad = new_node(math_noad) -- todo: pool - setfield(sub,"list",kern) + setlist(sub,kern) setnext(kern,noad) - setfield(noad,"nucleus",current) + setnucleus(noad,current) return sub end @@ -1341,7 +1357,7 @@ end local enable enable = function() - tasks.enableaction("math", "noads.handlers.italics") + enableaction("math", "noads.handlers.italics") if trace_italics then report_italics("enabling math italics") end @@ -1393,6 +1409,80 @@ implement { actions = mathematics.resetitalics } +do + + -- math kerns (experiment) in goodies: + -- + -- mathematics = { + -- kernpairs = { + -- [0x1D44E] = { + -- [0x1D44F] = 400, -- 𝑎𝑏 + -- } + -- }, + -- } + + local a_kernpairs = privateattribute("mathkernpairs") + local kernpairs = { } + + local function enable() + enableaction("math", "noads.handlers.kernpairs") + if trace_kernpairs then + report_kernpairs("enabling math kern pairs") + end + enable = false + end + + implement { + name = "initializemathkernpairs", + actions = enable, + onlyonce = true, + } + + local hash = setmetatableindex(function(t,font) + local g = fontdata[font].goodies + local m = g and g[1].mathematics + local k = m and m.kernpairs + t[font] = k + return k + end) + + kernpairs[math_char] = function(pointer,what,n,parent) + if getattr(pointer,a_kernpairs) == 1 then + local font = getfont(pointer) + local list = hash[font] + if list then + local first = getchar(pointer) + local found = list[first] + if found then + local next = getnext(parent) + if next and getid(next) == math_noad then + pointer = getnucleus(next) + if pointer then + if getfont(pointer) == font then + local second = getchar(pointer) + local kern = found[second] + if kern then + kern = kern * fonts.hashes.parameters[font].hfactor + if trace_kernpairs then + report_kernpairs("adding %p kerning between %C and %C",kern,first,second) + end + setlink(parent,new_kern(kern),getnext(parent)) + end + end + end + end + end + end + end + end + + function handlers.kernpairs(head,style,penalties) + processnoads(head,kernpairs,"kernpairs") + return true + end + +end + -- primes and such local collapse = { } processors.collapse = collapse @@ -1437,30 +1527,30 @@ local validpair = { local function movesubscript(parent,current_nucleus,current_char) local prev = getprev(parent) if prev and getid(prev) == math_noad then - if not getfield(prev,"sup") and not getfield(prev,"sub") then + if not getsup(prev) and not getsub(prev) then -- {f} {'}_n => f_n^' setchar(current_nucleus,movesub[current_char or getchar(current_nucleus)]) - local nucleus = getfield(parent,"nucleus") - local sub = getfield(parent,"sub") - local sup = getfield(parent,"sup") - setfield(prev,"sup",nucleus) - setfield(prev,"sub",sub) + local nucleus = getnucleus(parent) + local sub = getsub(parent) + local sup = getsup(parent) + setsup(prev,nucleus) + setsub(prev,sub) local dummy = copy_node(nucleus) setchar(dummy,0) - setfield(parent,"nucleus",dummy) - setfield(parent,"sub",nil) + setnucleus(parent,dummy) + setsub(parent) if trace_collapsing then report_collapsing("fixing subscript") end - elseif not getfield(prev,"sup") then + elseif not getsup(prev) then -- {f} {'}_n => f_n^' setchar(current_nucleus,movesub[current_char or getchar(current_nucleus)]) - local nucleus = getfield(parent,"nucleus") - local sup = getfield(parent,"sup") - setfield(prev,"sup",nucleus) + local nucleus = getnucleus(parent) + local sup = getsup(parent) + setsup(prev,nucleus) local dummy = copy_node(nucleus) setchar(dummy,0) - setfield(parent,"nucleus",dummy) + setnucleus(parent,dummy) if trace_collapsing then report_collapsing("fixing subscript") end @@ -1471,16 +1561,16 @@ end local function collapsepair(pointer,what,n,parent,nested) -- todo: switch to turn in on and off if parent then if validpair[getsubtype(parent)] then - local current_nucleus = getfield(parent,"nucleus") + local current_nucleus = getnucleus(parent) if getid(current_nucleus) == math_char then local current_char = getchar(current_nucleus) - if not getfield(parent,"sub") and not getfield(parent,"sup") then + if not getsub(parent) and not getsup(parent) then local mathpair = mathpairs[current_char] if mathpair then local next_noad = getnext(parent) if next_noad and getid(next_noad) == math_noad then if validpair[getsubtype(next_noad)] then - local next_nucleus = getfield(next_noad,"nucleus") + local next_nucleus = getnucleus(next_noad) local next_char = getchar(next_nucleus) if getid(next_nucleus) == math_char then local newchar = mathpair[next_char] @@ -1498,10 +1588,10 @@ local function collapsepair(pointer,what,n,parent,nested) -- todo: switch to tur else setnext(parent) end - setfield(parent,"sup",getfield(next_noad,"sup")) - setfield(parent,"sub",getfield(next_noad,"sub")) - setfield(next_noad,"sup",nil) - setfield(next_noad,"sub",nil) + setsup(parent,getsup(next_noad)) + setsub(parent,getsub(next_noad)) + setsup(next_noad) + setsub(next_noad) flush_node(next_noad) collapsepair(pointer,what,n,parent,true) -- if not nested and movesub[current_char] then @@ -1560,7 +1650,7 @@ variants[math_char] = function(pointer,what,n,parent) -- also set export value if selector then local next = getnext(parent) if next and getid(next) == math_noad then - local nucleus = getfield(next,"nucleus") + local nucleus = getnucleus(next) if nucleus and getid(nucleus) == math_char and getchar(nucleus) == selector then local variant local tfmdata = fontdata[getfont(pointer)] @@ -1630,7 +1720,7 @@ function handlers.classes(head,style,penalties) end registertracker("math.classes",function(v) - tasks.setaction("math","noads.handlers.classes",v) + setaction("math","noads.handlers.classes",v) end) -- experimental @@ -1676,7 +1766,7 @@ do local enable enable = function() - tasks.enableaction("math", "noads.handlers.domains") + enableaction("math", "noads.handlers.domains") if trace_domains then report_domains("enabling math domains") end @@ -1799,7 +1889,7 @@ function handlers.showtree(head,style,penalties) end registertracker("math.showtree",function(v) - tasks.setaction("math","noads.handlers.showtree",v) + setaction("math","noads.handlers.showtree",v) end) -- also for me @@ -1813,7 +1903,7 @@ end registertracker("math.makeup",function(v) visual = v - tasks.setaction("math","noads.handlers.makeup",v) + setaction("math","noads.handlers.makeup",v) end) -- the normal builder diff --git a/tex/context/base/mkiv/math-tag.lua b/tex/context/base/mkiv/math-tag.lua index 975b894ec..13c8fffc7 100644 --- a/tex/context/base/mkiv/math-tag.lua +++ b/tex/context/base/mkiv/math-tag.lua @@ -30,6 +30,8 @@ local getdisc = nuts.getdisc local getsubtype = nuts.getsubtype local getattr = nuts.getattr local setattr = nuts.setattr +local getcomponents = nuts.getcomponents +local getwidth = nuts.getwidth local set_attributes = nuts.setattributes local traverse_nodes = nuts.traverse @@ -250,7 +252,7 @@ process = function(start) -- we cannot use the processor as we have no finalizer if tag == "formulacaption" then -- skip elseif tag == "mstacker" then - local list = getfield(start,"list") + local list = getlist(start) if list then process(list) end @@ -260,7 +262,7 @@ process = function(start) -- we cannot use the processor as we have no finalizer end local text = start_tagged(tag) setattr(start,a_tagged,text) - local list = getfield(start,"list") + local list = getlist(start) if not list then -- empty list elseif not attr then @@ -315,7 +317,7 @@ process = function(start) -- we cannot use the processor as we have no finalizer if id == hlist_code or id == vlist_code then runner(getlist(n),depth+1) elseif id == glyph_code then - runner(getfield(n,"components"),depth+1) -- this should not be needed + runner(getcomponents(n),depth+1) -- this should not be needed elseif id == disc_code then local pre, post, replace = getdisc(n) runner(pre,depth+1) -- idem @@ -335,7 +337,7 @@ process = function(start) -- we cannot use the processor as we have no finalizer stop_tagged() end elseif id == math_sub_code then -- normally a hbox - local list = getfield(start,"list") + local list = getlist(start) if list then local attr = getattr(start,a_tagged) local last = attr and taglist[attr] @@ -526,7 +528,7 @@ process = function(start) -- we cannot use the processor as we have no finalizer processsubsup(start) end elseif id == glue_code then - -- setattr(start,a_tagged,start_tagged("mspace",{ width = getfield(start,"width") })) + -- setattr(start,a_tagged,start_tagged("mspace",{ width = getwidth(start) })) setattr(start,a_tagged,start_tagged("mspace")) stop_tagged() else diff --git a/tex/context/base/mkiv/meta-imp-txt.mkiv b/tex/context/base/mkiv/meta-imp-txt.mkiv index c6ecc6f03..b2a6d6d1d 100644 --- a/tex/context/base/mkiv/meta-imp-txt.mkiv +++ b/tex/context/base/mkiv/meta-imp-txt.mkiv @@ -289,6 +289,9 @@ fi ; fi ; endfor ; + if TraceRot : + draw boundingbox currentpicture withpen pencircle scaled .25pt withcolor blue ; + fi ; enddef ; \stopMPdefinitions diff --git a/tex/context/base/mkiv/meta-tex.lua b/tex/context/base/mkiv/meta-tex.lua index 205024fae..71207975d 100644 --- a/tex/context/base/mkiv/meta-tex.lua +++ b/tex/context/base/mkiv/meta-tex.lua @@ -241,7 +241,7 @@ local f_exptext = formatters[ [[textext("\mathematics{%s\times10^{%s}}")]] ] local mpprint = mp.print -function mp.format(fmt,str) +function mp.format(fmt,str) -- bah, this overloads mp.format in mlib-lua.lua fmt = lpegmatch(cleaner,fmt) mpprint(f_textext(formatters[fmt](metapost.untagvariable(str,false)))) end diff --git a/tex/context/base/mkiv/mlib-lua.lua b/tex/context/base/mkiv/mlib-lua.lua index 8f24124b9..4198a7339 100644 --- a/tex/context/base/mkiv/mlib-lua.lua +++ b/tex/context/base/mkiv/mlib-lua.lua @@ -202,7 +202,7 @@ end local replacer = lpeg.replacer("@","%%") -function mp.format(fmt,...) +function mp.fprint(fmt,...) n = n + 1 if not find(fmt,"%%") then fmt = lpegmatch(replacer,fmt) @@ -539,3 +539,95 @@ mp._get_toks_ = mp.gettoks mp._set_dimen_ = mp.setdimen mp._set_count_ = mp.setcount mp._set_toks_ = mp.settoks + +-- position fun + +do + + local mprint = mp.print + local fprint = mp.fprint + local qprint = mp.quoted + local getwhd = job.positions.whd + local getxy = job.positions.xy + local getposition = job.positions.position + local getpage = job.positions.page + local getregion = job.positions.region + local getmacro = tokens.getters.macro + + function mp.positionpath(name) + local w, h, d = getwhd(name) + if w then + fprint("((%p,%p)--(%p,%p)--(%p,%p)--(%p,%p)--cycle)",0,-d,w,-d,w,h,0,h) + else + mprint("(origin--cycle)") + end + end + + function mp.positioncurve(name) + local w, h, d = getwhd(name) + if w then + fprint("((%p,%p)..(%p,%p)..(%p,%p)..(%p,%p)..cycle)",0,-d,w,-d,w,h,0,h) + else + mprint("(origin--cycle)") + end + end + + function mp.positionbox(name) + local p, x, y, w, h, d = getposition(name) + if p then + fprint("((%p,%p)--(%p,%p)--(%p,%p)--(%p,%p)--cycle)",x,y-d,x+w,y-d,x+w,y+h,x,y+h) + else + mprint("(%p,%p)",x,y) + end + end + + function mp.positionxy(name) + local x, y = getxy(name) + if x then + fprint("(%p,%p)",x,y) + else + mprint("origin") + end + end + + function mp.positionpage(name) + local p = getpage(name) + if p then + fprint("%p",p) + else + mprint("0") + end + end + + function mp.positionregion(name) + local r = getregion(name) + if r then + qprint(r) + else + qprint("unknown") + end + end + + function mp.positionwhd(name) + local w, h, d = getwhd(name) + if w then + fprint("(%p,%p,%p)",w,h,d) + else + mprint("(0,0,0)") + end + end + + function mp.positionpxy(name) + local p, x, y = getposition(name) + if p then + fprint("(%p,%p,%p)",p,x,y) + else + mprint("(0,0,0)") + end + end + + function mp.positionanchor() + qprint(getmacro("MPanchorid")) + end + +end diff --git a/tex/context/base/mkiv/mlib-pps.lua b/tex/context/base/mkiv/mlib-pps.lua index d08d5ddb7..8c7910d16 100644 --- a/tex/context/base/mkiv/mlib-pps.lua +++ b/tex/context/base/mkiv/mlib-pps.lua @@ -13,9 +13,11 @@ local insert, remove, concat = table.insert, table.remove, table.concat local Cs, Cf, C, Cg, Ct, P, S, V, Carg = lpeg.Cs, lpeg.Cf, lpeg.C, lpeg.Cg, lpeg.Ct, lpeg.P, lpeg.S, lpeg.V, lpeg.Carg local lpegmatch, tsplitat, tsplitter = lpeg.match, lpeg.tsplitat, lpeg.tsplitter local formatters = string.formatters +local exists, savedata = io.exists, io.savedata -local mplib, metapost, lpdf, context = mplib, metapost, lpdf, context - +local mplib = mplib +local metapost = metapost +local lpdf = lpdf local context = context local implement = interfaces.implement @@ -761,11 +763,33 @@ implement { arguments = "string" } +local pdftompy = sandbox.registerrunner { + name = "mpy:pstoedit", + program = "pstoedit", + template = "-ssp -dt -f mpost %pdffile% %mpyfile%", + checkers = { + pdffile = "writable", + mpyfile = "readable", + }, + reporter = report_metapost, +} + +local textopdf = sandbox.registerrunner { + name = "mpy:context", + program = "context", + template = "--once %runmode% %texfile%", + checkers = { + runmode = "string", + texfile = "readable", + }, + reporter = report_metapost, +} + function makempy.processgraphics(graphics) if #graphics == 0 then return end - if mpyfilename and io.exists(mpyfilename) then + if mpyfilename and exists(mpyfilename) then report_metapost("using file: %s",mpyfilename) return end @@ -775,16 +799,17 @@ function makempy.processgraphics(graphics) local mpyfile = file.replacesuffix(mpofile,"mpy") local pdffile = file.replacesuffix(mpofile,"pdf") local texfile = file.replacesuffix(mpofile,"tex") - io.savedata(texfile, { start, preamble, metapost.tex.get(), concat(graphics,"\n"), stop }, "\n") - local command = format("context --once %s %s", (tex.interactionmode == 0 and "--batchmode") or "", texfile) - os.execute(command) - if io.exists(pdffile) then - command = format("pstoedit -ssp -dt -f mpost %s %s", pdffile, mpyfile) - logs.newline() - report_metapost("running: %s",command) - logs.newline() - os.execute(command) - if io.exists(mpyfile) then + savedata(texfile, { start, preamble, metapost.tex.get(), concat(graphics,"\n"), stop }, "\n") + textopdf { + runmode = tex.interactionmode == 0 and "--batchmode" or "", + texfile = texfile, + } + if exists(pdffile) then + pdftompy { + pdffile = pdffile, + mpyfile = mpyfile, + } + if exists(mpyfile) then local result, r = { }, 0 local data = io.loaddata(mpyfile) if data and #data > 0 then @@ -792,7 +817,7 @@ function makempy.processgraphics(graphics) r = r + 1 result[r] = formatters["begingraphictextfig%sendgraphictextfig ;\n"](figure) end - io.savedata(mpyfile,concat(result,"")) + savedata(mpyfile,concat(result,"")) end end end diff --git a/tex/context/base/mkiv/mult-def.lua b/tex/context/base/mkiv/mult-def.lua index 69484a90f..7cee595cd 100644 --- a/tex/context/base/mkiv/mult-def.lua +++ b/tex/context/base/mkiv/mult-def.lua @@ -15238,6 +15238,9 @@ return { ["oldstyle"]={ ["en"]="oldstyle", }, + ["fractions"]={ + ["en"]="fractions", + }, ["on"]={ ["cs"]="zap", ["de"]="an", diff --git a/tex/context/base/mkiv/mult-low.lua b/tex/context/base/mkiv/mult-low.lua index ea1c169ea..23ee8688f 100644 --- a/tex/context/base/mkiv/mult-low.lua +++ b/tex/context/base/mkiv/mult-low.lua @@ -401,6 +401,7 @@ return { "cldprocessfile", "cldloadfile", "cldcontext", "cldcommand", -- "carryoverpar", + "lastlinewidth", -- "assumelongusagecs", -- diff --git a/tex/context/base/mkiv/mult-prm.lua b/tex/context/base/mkiv/mult-prm.lua index 4f01b66b6..ef6a5a0ad 100644 --- a/tex/context/base/mkiv/mult-prm.lua +++ b/tex/context/base/mkiv/mult-prm.lua @@ -315,6 +315,7 @@ return { "pdfvariable", "postexhyphenchar", "posthyphenchar", + "predisplaygapfactor", "preexhyphenchar", "prehyphenchar", "primitive", @@ -1139,6 +1140,7 @@ return { "postexhyphenchar", "posthyphenchar", "predisplaydirection", + "predisplaygapfactor", "predisplaypenalty", "predisplaysize", "preexhyphenchar", diff --git a/tex/context/base/mkiv/mult-sys.mkiv b/tex/context/base/mkiv/mult-sys.mkiv index 914929ab1..bd3ff9b3d 100644 --- a/tex/context/base/mkiv/mult-sys.mkiv +++ b/tex/context/base/mkiv/mult-sys.mkiv @@ -149,6 +149,7 @@ \definesystemconstant {sans} \definesystemconstant {mono} \definesystemconstant {math} +\definesystemconstant {nomath} \definesystemconstant {handwriting} \definesystemconstant {calligraphy} \definesystemconstant {casual} @@ -358,7 +359,7 @@ \definesystemconstant {integral} \definesystemconstant {insert} % maybe insertclass \definesystemconstant {marker} - +\definesystemconstant {kernpairs} \definesystemconstant {mixedcolumn} %definesystemconstant {property} diff --git a/tex/context/base/mkiv/node-acc.lua b/tex/context/base/mkiv/node-acc.lua index a63aef646..dccd7b7c0 100644 --- a/tex/context/base/mkiv/node-acc.lua +++ b/tex/context/base/mkiv/node-acc.lua @@ -8,92 +8,72 @@ if not modules then modules = { } end modules ['node-acc'] = { local nodes, node = nodes, node -local nodecodes = nodes.nodecodes -local tasks = nodes.tasks - -local nuts = nodes.nuts -local tonut = nodes.tonut -local tonode = nodes.tonode - -local getid = nuts.getid -local getfield = nuts.getfield -local getattr = nuts.getattr -local getlist = nuts.getlist -local getchar = nuts.getchar -local getnext = nuts.getnext - -local setfield = nuts.setfield -local setattr = nuts.setattr -local setlink = nuts.setlink -local setchar = nuts.setchar -local setsubtype = nuts.setsubtype - ------ traverse_nodes = nuts.traverse -local traverse_id = nuts.traverse_id -local copy_node = nuts.copy -local flush_node_list = nuts.flush_list -local insert_after = nuts.insert_after - -local glue_code = nodecodes.glue ------ kern_code = nodecodes.kern -local glyph_code = nodecodes.glyph -local hlist_code = nodecodes.hlist -local vlist_code = nodecodes.vlist - -local a_characters = attributes.private("characters") - -local threshold = 65536 -- not used -local nofreplaced = 0 +local nodecodes = nodes.nodecodes +local tasks = nodes.tasks + +local nuts = nodes.nuts +local tonut = nodes.tonut +local tonode = nodes.tonode + +local getid = nuts.getid +local getfield = nuts.getfield +local getattr = nuts.getattr +local getlist = nuts.getlist +local getchar = nuts.getchar +local getnext = nuts.getnext + +local setfield = nuts.setfield +local setattr = nuts.setattr +local setlink = nuts.setlink +local setchar = nuts.setchar +local setsubtype = nuts.setsubtype +local getwidth = nuts.getwidth +local setwidth = nuts.setwidth + +----- traverse_nodes = nuts.traverse +local traverse_id = nuts.traverse_id +----- copy_node = nuts.copy +local insert_after = nuts.insert_after +local copy_no_components = nuts.copy_no_components + +local glue_code = nodecodes.glue +----- kern_code = nodecodes.kern +local glyph_code = nodecodes.glyph +local hlist_code = nodecodes.hlist +local vlist_code = nodecodes.vlist + +local a_characters = attributes.private("characters") + +local threshold = 65536 -- not used +local nofreplaced = 0 -- todo: nbsp etc --- todo: collapse kerns - --- p_id +-- todo: collapse kerns (not needed, backend does this) +-- todo: maybe cache as we now create many nodes +-- todo: check for subtype related to spacing (13/14 but most seems to be user anyway) local function injectspaces(head) local p, p_id local n = head while n do local id = getid(n) - if id == glue_code then -- todo: check for subtype related to spacing (13/14 but most seems to be 0) - -- if getfield(n,."width") > 0 then -- threshold - -- if p and p_id == glyph_code then + if id == glue_code then if p and getid(p) == glyph_code then - local g = copy_node(p) - local c = getfield(g,"components") - if c then -- it happens that we copied a ligature - flush_node_list(c) - setfield(g,"components",nil) - setsubtype(g,256) - end + -- unless we don't care about the little bit of overhead + -- we can just: local g = copy_node(g) + local g = copy_no_components(p) local a = getattr(n,a_characters) setchar(g,32) - setlink(p,g) - setlink(g,n) --- we could cache as we now create many nodes - setfield(n,"width",getfield(n,"width") - getfield(g,"width")) + setlink(p,g,n) + setwidth(n,getwidth(n) - getwidth(g)) if a then setattr(g,a_characters,a) end setattr(n,a_characters,0) nofreplaced = nofreplaced + 1 end - -- end elseif id == hlist_code or id == vlist_code then injectspaces(getlist(n),attribute) - -- elseif id == kern_code then -- the backend already collapses - -- local first = n - -- while true do - -- local nn = getnext(n) - -- if nn and getid(nn) == kern_code then - -- -- maybe we should delete kerns but who cares at this stage - -- setfield(first,"kern",getfield(first,"kern") + getfield(nn,"kern") - -- setfield(nn,"kern",0) - -- n = nn - -- else - -- break - -- end - -- end end p_id = id p = n diff --git a/tex/context/base/mkiv/node-aux.lua b/tex/context/base/mkiv/node-aux.lua index 7f2360276..c6b276337 100644 --- a/tex/context/base/mkiv/node-aux.lua +++ b/tex/context/base/mkiv/node-aux.lua @@ -35,6 +35,10 @@ local getfont = nuts.getfont local getchar = nuts.getchar local getattr = nuts.getattr local getfield = nuts.getfield +local getboth = nuts.getboth +local getcomponents = nuts.getcomponents +local getwidth = nuts.getwidth +local setwidth = nuts.setwidth local setfield = nuts.setfield local setattr = nuts.setattr @@ -42,18 +46,21 @@ local setlink = nuts.setlink local setlist = nuts.setlist local setnext = nuts.setnext local setprev = nuts.setprev +local setcomponents = nuts.setcomponents +local setattrlist = nuts.setattrlist local traverse_nodes = nuts.traverse local traverse_id = nuts.traverse_id local flush_node = nuts.flush +local flush_list = nuts.flush_list local hpack_nodes = nuts.hpack local unset_attribute = nuts.unset_attribute local first_glyph = nuts.first_glyph local copy_node = nuts.copy ----- copy_node_list = nuts.copy_list local find_tail = nuts.tail -local insert_node_after = nuts.insert_after local getbox = nuts.getbox +local count = nuts.count local nodepool = nuts.pool local new_glue = nodepool.glue @@ -341,11 +348,10 @@ local function tonodes(str,fnt,attr) -- (str,template_glyph) -- moved from blob- n = new_glyph(fnt,s) end if attr then -- normally false when template - -- setfield(n,"attr",copy_node_list(attr)) - setfield(n,"attr",attr) + setattrlist(n,attr) end if head then - insert_node_after(head,tail,n) + setlink(tail,n) else head = n end @@ -447,9 +453,9 @@ end local function rehpack(n,width) local head = getlist(n) - local size = width or getfield(n,"width") + local size = width or getwidth(n) local temp = hpack_nodes(head,size,"exactly") - setfield(n,"width", size) + setwidth(n,size) setfield(n,"glue_set", getfield(temp,"glue_set")) setfield(n,"glue_sign", getfield(temp,"glue_sign")) setfield(n,"glue_order",getfield(temp,"glue_order")) @@ -482,3 +488,177 @@ end -- return 0 -- end -- end + +-- these component helpers might move to another module + +-- nodemode helper: here we also flatten components, no check for disc here + +function nuts.set_components(target,start,stop) + local head = getcomponents(target) + if head then + flush_list(head) + head = nil + end + if start then + setprev(start) + else + return nil + end + if stop then + setnext(stop) + end + local tail = nil + while start do + local c = getcomponents(start) + local n = getnext(start) + if c then + if head then + setlink(tail,c) + else + head = c + end + tail = find_tail(c) + setcomponents(start) + flush_node(start) + else + if head then + setlink(tail,start) + else + head = start + end + tail = start + end + start = n + end + setcomponents(target,head) + -- maybe also upgrade the subtype but we don't use it anyway + return head +end + +function nuts.get_components(target) + return getcomponents(target) +end + +nuts.get_components = getcomponents + +function nuts.take_components(target) + local c = getcomponents(target) + setcomponents(target) + -- maybe also upgrade the subtype but we don't use it anyway + return c +end + +-- nodemode helper: we assume a glyph and a flat components list (basemode can +-- have nested components) + +function nuts.count_components(n,marks) + local components = getcomponents(n) + if components then + if marks then + local i = 0 + for g in traverse_id(glyph_code,components) do + if not marks[getchar(g)] then + i = i + 1 + end + end + return i + else + return count(glyph_code,components) + end + else + return 0 + end +end + +-- nodemode helper: the next and prev pointers are untouched + +function nuts.copy_no_components(g,copyinjection) + local components = getcomponents(g) + if components then + setcomponents(g) + local n = copy_node(g) + if copyinjection then + copyinjection(n,g) + end + setcomponents(g,components) + -- maybe also upgrade the subtype but we don't use it anyway + return n + else + local n = copy_node(g) + if copyinjection then + copyinjection(n,g) + end + return n + end +end + +function nuts.copy_only_glyphs(current) + local head = nil + local previous = nil + for n in traverse_id(glyph_code,current) do + n = copy_node(n) + if head then + setlink(previous,n) + else + head = n + end + previous = n + end + return head +end + +-- node- and basemode helper + +function nuts.use_components(head,current) + local components = getcomponents(current) + if not components then + return head, current, current + end + local prev, next = getboth(current) + local first = current + local last = next + while components do + local gone = current + local tail = find_tail(components) + if prev then + setlink(prev,components) + end + if next then + setlink(tail,next) + end + if first == current then + first = components + end + if head == current then + head = components + end + current = components + setcomponents(gone) + flush_node(gone) + while true do + components = getcomponents(current) + if components then + next = getnext(current) + break -- current is composed + end + if next == last then + last = current + break -- components is false + end + prev = current + current = next + next = getnext(current) + end + end + return head, first, last +end + +-- function nuts.current_tail() +-- local whatever = texnest[texnest.ptr] +-- if whatever then +-- local tail = whatever.tail +-- if tail then +-- return tonut(tail) +-- end +-- end +-- end diff --git a/tex/context/base/mkiv/node-bck.lua b/tex/context/base/mkiv/node-bck.lua index 9ecc62170..abb025b74 100644 --- a/tex/context/base/mkiv/node-bck.lua +++ b/tex/context/base/mkiv/node-bck.lua @@ -11,7 +11,7 @@ if not modules then modules = { } end modules ['node-bck'] = { local attributes, nodes, node = attributes, nodes, node -local tasks = nodes.tasks +local enableaction = nodes.tasks.enableaction local nodecodes = nodes.nodecodes local listcodes = nodes.listcodes @@ -35,7 +35,6 @@ local getattr = nuts.getattr local getsubtype = nuts.getsubtype local getwhd = nuts.getwhd -local setfield = nuts.setfield local setattr = nuts.setattr local setlink = nuts.setlink local setlist = nuts.setlist @@ -85,11 +84,12 @@ local function add_backgrounds(head) -- rather old code .. to be redone if transparency then setattr(rule,a_transparency,transparency) end - setlink(rule,glue) - if list then - setlink(glue,list) - end - setlist(current,rule) +-- setlink(rule,glue) +-- if list then +-- setlink(glue,list) +-- end +-- setlist(current,rule) + setlist(current,rule,glue,list) end end end @@ -172,21 +172,16 @@ end nodes.handlers.backgrounds = function(head) local head, done = add_backgrounds (tonut(head)) return tonode(head), done end nodes.handlers.alignbackgrounds = function(head) local head, done = add_alignbackgrounds(tonut(head)) return tonode(head), done end --- elsewhere: needs checking - --- tasks.appendaction("shipouts","normalizers","nodes.handlers.backgrounds") --- tasks.appendaction("shipouts","normalizers","nodes.handlers.alignbackgrounds") - interfaces.implement { name = "enablebackgroundboxes", onlyonce = true, - actions = nodes.tasks.enableaction, + actions = enableaction, arguments = { "'shipouts'", "'nodes.handlers.backgrounds'" } } interfaces.implement { name = "enablebackgroundalign", onlyonce = true, - actions = nodes.tasks.enableaction, + actions = enableaction, arguments = { "'shipouts'", "'nodes.handlers.alignbackgrounds'" } } diff --git a/tex/context/base/mkiv/node-fin.lua b/tex/context/base/mkiv/node-fin.lua index 25a2d2f44..03c8a7607 100644 --- a/tex/context/base/mkiv/node-fin.lua +++ b/tex/context/base/mkiv/node-fin.lua @@ -26,6 +26,7 @@ local getid = nuts.getid local getlist = nuts.getlist local getleader = nuts.getleader local getattr = nuts.getattr +local getwidth = nuts.getwidth local setlist = nuts.setlist local setleader = nuts.setleader @@ -204,25 +205,31 @@ local function process(namespace,attribute,head,inheritance,default) -- one attr if content ~= list then setlist(stack,list) end - done = done or ok + if ok then + done = true + end else local list, ok = process(namespace,attribute,content,inheritance,default) if content ~= list then setlist(stack,list) end - done = done or ok + if ok then + done = true + end end else local list, ok = process(namespace,attribute,content,inheritance,default) if content ~= list then setlist(stack,list) end - done = done or ok + if ok then + done = true + end end -- end nested -- end elseif id == rule_code then - check = getfield(stack,"width") ~= 0 + check = getwidth(stack) ~= 0 end -- much faster this way than using a check() and nested() function if check then @@ -230,14 +237,14 @@ local function process(namespace,attribute,head,inheritance,default) -- one attr if c then if default and c == inheritance then if current ~= default then - head = insert_node_before(head,stack,copied(nsdata[default])) + head = insert_node_before(head,stack,copied(nsdata[default])) current = default - done = true + done = true end elseif current ~= c then - head = insert_node_before(head,stack,copied(nsdata[c])) + head = insert_node_before(head,stack,copied(nsdata[c])) current = c - done = true + done = true end if leader then local savedcurrent = current @@ -256,20 +263,26 @@ local function process(namespace,attribute,head,inheritance,default) -- one attr if leader ~= list then setleader(stack,list) end - done = done or ok + if ok then + done = true + end else local list, ok = process(namespace,attribute,leader,inheritance,default) if leader ~= list then setleader(stack,list) end - done = done or ok + if ok then + done = true + end end else local list, ok = process(namespace,attribute,leader,inheritance,default) if leader ~= list then setleader(stack,list) end - done = done or ok + if ok then + done = true + end end -- end nested -- current = savedcurrent @@ -277,14 +290,14 @@ local function process(namespace,attribute,head,inheritance,default) -- one attr end elseif default and inheritance then if current ~= default then - head = insert_node_before(head,stack,copied(nsdata[default])) + head = insert_node_before(head,stack,copied(nsdata[default])) current = default - done = true + done = true end elseif current > 0 then - head = insert_node_before(head,stack,copied(nsnone)) + head = insert_node_before(head,stack,copied(nsnone)) current = 0 - done = true + done = true end check = false end @@ -331,25 +344,31 @@ local function selective(namespace,attribute,head,inheritance,default) -- two at if content ~= list then setlist(stack,list) end - done = done or ok + if ok then + done = true + end else local list, ok = selective(namespace,attribute,content,inheritance,default) if content ~= list then setlist(stack,list) end - done = done or ok + if ok then + done = true + end end else local list, ok = selective(namespace,attribute,content,inheritance,default) if content ~= list then setlist(stack,list) end - done = done or ok + if ok then + done = true + end end -- end nested end elseif id == rule_code then - check = getfield(stack,"width") ~= 0 + check = getwidth(stack) ~= 0 end if check then @@ -360,7 +379,9 @@ local function selective(namespace,attribute,head,inheritance,default) -- two at local data = nsdata[default] head = insert_node_before(head,stack,copied(data[nsforced or getattr(stack,nsselector) or nsselector])) current = default - done = true + if ok then + done = true + end end else local s = getattr(stack,nsselector) @@ -369,7 +390,9 @@ local function selective(namespace,attribute,head,inheritance,default) -- two at head = insert_node_before(head,stack,copied(data[nsforced or getattr(stack,nsselector) or nsselector])) current = c current_selector = s - done = true + if ok then + done = true + end end end if leader then @@ -381,20 +404,26 @@ local function selective(namespace,attribute,head,inheritance,default) -- two at if leader ~= list then setleader(stack,list) end - done = done or ok + if ok then + done = true + end else local list, ok = selective(namespace,attribute,leader,inheritance,default) if leader ~= list then setleader(stack,list) end - done = done or ok + if ok then + done = true + end end else local list, ok = selective(namespace,attribute,leader,inheritance,default) if leader ~= list then setleader(stack,list) end - done = done or ok + if ok then + done = true + end end -- end nested leader = false @@ -402,9 +431,9 @@ local function selective(namespace,attribute,head,inheritance,default) -- two at elseif default and inheritance then if current ~= default then local data = nsdata[default] - head = insert_node_before(head,stack,copied(data[nsforced or getattr(stack,nsselector) or nsselector])) + head = insert_node_before(head,stack,copied(data[nsforced or getattr(stack,nsselector) or nsselector])) current = default - done = true + done = true end elseif current > 0 then head = insert_node_before(head,stack,copied(nsnone)) @@ -456,55 +485,63 @@ local function stacked(namespace,attribute,head,default) -- no triggering, no in if a and current ~= a and nslistwise[a] then -- viewerlayer / needs checking, see below local p = current current = a - head = insert_node_before(head,stack,copied(nsdata[a])) + head = insert_node_before(head,stack,copied(nsdata[a])) local list = stacked(namespace,attribute,content,current) -- two return values if content ~= list then setlist(stack,list) end - done = true head, stack = insert_node_after(head,stack,copied(nsnone)) current = p + done = true else local list, ok = stacked(namespace,attribute,content,current) if content ~= list then setlist(stack,list) -- only if ok end - done = done or ok + if ok then + done = true + end end else local list, ok = stacked(namespace,attribute,content,current) if content ~= list then setlist(stack,list) -- only if ok end - done = done or ok + if ok then + done = true + end end end elseif id == rule_code then - check = getfield(stack,"width") ~= 0 + check = getwidth(stack) ~= 0 end if check then local a = getattr(stack,attribute) if a then if current ~= a then - head = insert_node_before(head,stack,copied(nsdata[a])) - depth = depth + 1 - current, done = a, true + head = insert_node_before(head,stack,copied(nsdata[a])) + depth = depth + 1 + current = a + done = true end if leader then local list, ok = stacked(namespace,attribute,content,current) if leader ~= list then setleader(stack,list) -- only if ok end - done = done or ok + if ok then + done = true + end leader = false end elseif default > 0 then -- elseif current > 0 then - head = insert_node_before(head,stack,copied(nsnone)) - depth = depth - 1 - current, done = 0, true + head = insert_node_before(head,stack,copied(nsnone)) + depth = depth - 1 + current = 0 + done = true end check = false end @@ -564,17 +601,21 @@ local function stacker(namespace,attribute,head,default) -- no triggering, no in if content ~= list then setlist(current,list) end - done = done or ok + if ok then + done = true + end end else local list, ok = stacker(namespace,attribute,content,default) if list ~= content then setlist(current,list) end - done = done or ok + if ok then + done = true + end end elseif id == rule_code then - check = getfield(current,"width") ~= 0 + check = getwidth(current) ~= 0 end if check then @@ -588,11 +629,14 @@ local function stacker(namespace,attribute,head,default) -- no triggering, no in if n then head = insert_node_before(head,current,tonut(n)) -- a end - attrib, done = a, true + attrib = a + done = true if leader then -- tricky as a leader has to be a list so we cannot inject before local list, ok = stacker(namespace,attribute,leader,attrib) - done = done or ok + if ok then + done = true + end leader = false end end diff --git a/tex/context/base/mkiv/node-fnt.lua b/tex/context/base/mkiv/node-fnt.lua index 60b1f8332..85525cac2 100644 --- a/tex/context/base/mkiv/node-fnt.lua +++ b/tex/context/base/mkiv/node-fnt.lua @@ -157,56 +157,75 @@ end fonts.setdiscexpansion(true) +local function start_trace(head) + run = run + 1 + report_fonts() + report_fonts("checking node list, run %s",run) + report_fonts() + local n = tonut(head) + while n do + local char, id = isglyph(n) + if char then + local font = getfont(n) + local attr = getattr(n,0) or 0 + report_fonts("font %03i, dynamic %03i, glyph %C",font,attr,char) + elseif id == disc_code then + report_fonts("[disc] %s",nodes.listtoutf(n,true,false,n)) + elseif id == boundary_code then + report_fonts("[boundary] %i:%i",getsubtype(n),getfield(n,"value")) + else + report_fonts("[%s]",nodecodes[id]) + end + n = getnext(n) + end +end + +local function stop_trace(u,usedfonts,a,attrfonts,b,basefonts,r,redundant,e,expanders) + report_fonts() + report_fonts("statics : %s",u > 0 and concat(keys(usedfonts)," ") or "none") + report_fonts("dynamics: %s",a > 0 and concat(keys(attrfonts)," ") or "none") + report_fonts("built-in: %s",b > 0 and b or "none") + report_fonts("removed : %s",r > 0 and r or "none") +if expanders then + report_fonts("expanded: %s",e > 0 and e or "none") +end + report_fonts() +end + function handlers.characters(head) -- either next or not, but definitely no already processed list starttiming(nodes) - local usedfonts = { } - local attrfonts = { } - local basefonts = { } - local a, u, b, r = 0, 0, 0, 0 - local basefont = nil - local prevfont = nil - local prevattr = 0 - local mode = nil - local done = false - local variants = nil - local redundant = nil + local usedfonts = { } + local attrfonts = { } + local basefonts = { } + local basefont = nil + local prevfont = nil + local prevattr = 0 + local done = false + local variants = nil + local redundant = nil + local none = false + local nuthead = tonut(head) + + local a, u, b, r, e = 0, 0, 0, 0, 0 if trace_fontrun then - run = run + 1 - report_fonts() - report_fonts("checking node list, run %s",run) - report_fonts() - local n = tonut(head) - while n do - local char, id = isglyph(n) - if char then - local font = getfont(n) - local attr = getattr(n,0) or 0 - report_fonts("font %03i, dynamic %03i, glyph %C",font,attr,char) - elseif id == disc_code then - report_fonts("[disc] %s",nodes.listtoutf(n,true,false,n)) - elseif id == boundary_code then - report_fonts("[boundary] %i:%i",getsubtype(n),getfield(n,"value")) - else - report_fonts("[%s]",nodecodes[id]) - end - n = getnext(n) - end + start_trace(head) end - local nuthead = tonut(head) + -- There is no gain in checking for a single glyph and then having a fast path. On the + -- metafun manual (with some 2500 single char lists) the difference is just noise. for n in traverse_char(nuthead) do local font = getfont(n) - local attr = getattr(n,0) or 0 -- zero attribute is reserved for fonts in context + local attr = (none and prevattr) or getattr(n,0) or 0 -- zero attribute is reserved for fonts in context if font ~= prevfont or attr ~= prevattr then prevfont = font prevattr = attr - mode = fontmodes[font] -- we can also avoid the attr check variants = fontvariants[font] - if mode == "none" then + none = fontmodes[font] == "none" + if none then -- skip -- variants = false protect_glyph(n) @@ -316,11 +335,17 @@ function handlers.characters(head) if b > 0 then for i=1,b do local bi = basefonts[i] - if r == bi[1] then + local b1 = bi[1] + local b2 = bi[2] + if b1 == b2 then + if b1 == r then + bi[1] = false + bi[2] = false + end + elseif b1 == r then bi[1] = n - end - if r == bi[2] then - bi[2] = n + elseif b2 == r then + bi[2] = p end end end @@ -328,26 +353,31 @@ function handlers.characters(head) end end - local e = 0 - if force_discrun then -- basefont is not supported in disc only runs ... it would mean a lot of -- ranges .. we could try to run basemode as a separate processor run but -- not for now (we can consider it when the new node code is tested - -- local prevfont = nil - -- local prevattr = 0 - for d in traverse_id(disc_code,nuthead) do -- we could use first_glyph, only doing replace is good enough local _, _, r = getdisc(d) if r then + local prevfont = nil + local prevattr = nil + local none = false for n in traverse_char(r) do local font = getfont(n) - local attr = getattr(n,0) or 0 -- zero attribute is reserved for fonts in context + local attr = (none and prevattr) or getattr(n,0) or 0 -- zero attribute is reserved for fonts in context if font ~= prevfont or attr ~= prevattr then - if attr > 0 then + prevfont = font + prevattr = attr + none = fontmodes[font] == "none" -- very unlikely that we run into disc nodes in none mode + if none then + -- skip + -- variants = false + protect_glyph(n) + elseif attr > 0 then local used = attrfonts[font] if not used then used = { } @@ -370,11 +400,11 @@ function handlers.characters(head) end end end - prevfont = font - prevattr = attr end + -- we assume one font for now (and if there are more and we get into issues then + -- we can always remove the break) + break end - break elseif expanders then local subtype = getsubtype(d) if subtype == discretionary_code then @@ -389,36 +419,35 @@ function handlers.characters(head) end if trace_fontrun then - report_fonts() - report_fonts("statics : %s",u > 0 and concat(keys(usedfonts)," ") or "none") - report_fonts("dynamics: %s",a > 0 and concat(keys(attrfonts)," ") or "none") - report_fonts("built-in: %s",b > 0 and b or "none") - report_fonts("removed : %s",redundant and #redundant > 0 and #redundant or "none") - if expanders then - report_fonts("expanded: %s",e > 0 and e or "none") - end - report_fonts() + stop_trace(u,usedfonts,a,attrfonts,b,basefonts,r,redundant,e,expanders) end + -- in context we always have at least 2 processors if u == 0 then -- skip elseif u == 1 then local font, processors = next(usedfonts) - local attr = a == 0 and false or 0 -- 0 is the savest way + -- local attr = a == 0 and false or 0 -- 0 is the savest way + local attr = a > 0 and 0 or false -- 0 is the savest way for i=1,#processors do local h, d = processors[i](head,font,attr) if d then - head = h or head + if h then + head = h + end done = true end end else - local attr = a == 0 and false or 0 -- 0 is the savest way - for font, processors in next, usedfonts do + -- local attr = a == 0 and false or 0 -- 0 is the savest way + local attr = a > 0 and 0 or false -- 0 is the savest way + for font, processors in next, usedfonts do -- unordered for i=1,#processors do local h, d = processors[i](head,font,attr) if d then - head = h or head + if h then + head = h + end done = true end end @@ -428,22 +457,26 @@ function handlers.characters(head) -- skip elseif a == 1 then local font, dynamics = next(attrfonts) - for attribute, processors in next, dynamics do -- attr can switch in between + for attribute, processors in next, dynamics do -- unordered, attr can switch in between for i=1,#processors do local h, d = processors[i](head,font,attribute) if d then - head = h or head + if h then + head = h + end done = true end end end else for font, dynamics in next, attrfonts do - for attribute, processors in next, dynamics do -- attr can switch in between + for attribute, processors in next, dynamics do -- unordered, attr can switch in between for i=1,#processors do local h, d = processors[i](head,font,attribute) if d then - head = h or head + if h then + head = h + end done = true end end @@ -460,14 +493,15 @@ function handlers.characters(head) if (start or stop) and (start ~= stop) then local front = nuthead == start if stop then - start, stop = ligaturing(start,stop) - start, stop = kerning(start,stop) + start = ligaturing(start,stop) + start = kerning(start,stop) elseif start then -- safeguard start = ligaturing(start) start = kerning(start) end - if front then - head = tonode(start) + if front and nuthead ~= start then + -- nuthead = start + head = tonode(start) end end else @@ -476,26 +510,28 @@ function handlers.characters(head) local range = basefonts[i] local start = range[1] local stop = range[2] - if start then + if start then -- and start ~= stop but that seldom happens local front = nuthead == start - local prev, next + local prev = getprev(start) + local next = getnext(stop) if stop then - next = getnext(stop) start, stop = ligaturing(start,stop) start, stop = kerning(start,stop) else - prev = getprev(start) start = ligaturing(start) start = kerning(start) end + -- is done automatically if prev then setlink(prev,start) end if next then setlink(stop,next) end + -- till here if front and nuthead ~= start then - head = tonode(nuthead) + nuthead = start + head = tonode(start) end end end diff --git a/tex/context/base/mkiv/node-ltp.lua b/tex/context/base/mkiv/node-ltp.lua index 32b11267b..22a4799ad 100644 --- a/tex/context/base/mkiv/node-ltp.lua +++ b/tex/context/base/mkiv/node-ltp.lua @@ -21,6 +21,7 @@ if not modules then modules = { } end modules ['node-par'] = { -- todo: check and improve protrusion -- todo: arabic etc (we could use pretty large scales there) .. marks and cursive -- todo: see: we need to check this with the latest patches to the tex kernel +-- todo: adapt math glue spacing to new model (left/right) -- todo: optimize a bit more (less par.*) @@ -139,14 +140,13 @@ local sub, formatters = string.sub, string.formatters local round, floor = math.round, math.floor local insert, remove = table.insert, table.remove -local fonts, nodes, node = fonts, nodes, node +-- local fonts, nodes, node = fonts, nodes, node -- too many locals local trace_basic = false trackers.register("builders.paragraphs.basic", function(v) trace_basic = v end) local trace_lastlinefit = false trackers.register("builders.paragraphs.lastlinefit", function(v) trace_lastlinefit = v end) local trace_adjusting = false trackers.register("builders.paragraphs.adjusting", function(v) trace_adjusting = v end) local trace_protruding = false trackers.register("builders.paragraphs.protruding", function(v) trace_protruding = v end) local trace_expansion = false trackers.register("builders.paragraphs.expansion", function(v) trace_expansion = v end) -local trace_quality = false trackers.register("builders.paragraphs.quality", function(v) trace_quality = v end) local report_parbuilders = logs.reporter("nodes","parbuilders") ----- report_hpackers = logs.reporter("nodes","hpackers") @@ -207,7 +207,14 @@ local getattr = nuts.getattr local getdisc = nuts.getdisc local getglue = nuts.getglue local getwhd = nuts.getwhd -local setwhd = nuts.setwhd +local getcomponents = nuts.getcomponents +local getkern = nuts.getkern +local getpenalty = nuts.getpenalty +local getdir = nuts.getdir +local getshift = nuts.getshift +local getwidth = nuts.getwidth +local getheight = nuts.getheight +local getdepth = nuts.getdepth local isglyph = nuts.isglyph @@ -220,6 +227,13 @@ local setprev = nuts.setprev local setdisc = nuts.setdisc local setsubtype = nuts.setsubtype local setglue = nuts.setglue +local setwhd = nuts.setwhd +local setkern = nuts.setkern +local setdir = nuts.setdir +local setshift = nuts.setshift +local setwidth = nuts.setwidth +----- getheight = nuts.getheight +----- getdepth = nuts.getdepth local slide_node_list = nuts.slide -- get rid of this, probably ok > 78.2 local find_tail = nuts.tail @@ -233,8 +247,6 @@ local insert_node_after = nuts.insert_after local insert_node_before = nuts.insert_before local is_zero_glue = nuts.is_zero_glue -local setnodecolor = nodes.tracers.colors.set - local nodepool = nuts.pool local nodecodes = nodes.nodecodes @@ -352,12 +364,12 @@ local function checked_line_dir(stack,current) local n = stack.n + 1 stack.n = n stack[n] = current - return getfield(current,"dir") + return getdir(current) elseif n > 0 then local n = stack.n local dirnode = stack[n] dirstack.n = n - 1 - return getfield(dirnode,"dir") + return getdir(dirnode) else report_parbuilders("warning: missing pop node (%a)",1) -- in line ... end @@ -374,7 +386,7 @@ local function inject_dirs_at_end_of_line(stack,current,start,stop) while start and start ~= stop do local id = getid(start) if id == dir_code then - if not dir_pops[getfield(start,"dir")] then -- weird, what is this # + if not dir_pops[getdir(start)] then -- weird, what is this # n = n + 1 stack[n] = start elseif n > 0 then @@ -386,7 +398,7 @@ local function inject_dirs_at_end_of_line(stack,current,start,stop) start = getnext(start) end for i=n,1,-1 do - h, current = insert_node_after(current,current,new_dir(dir_negations[getfield(stack[i],"dir")])) + h, current = insert_node_after(current,current,new_dir(dir_negations[getdir(stack[i])])) end stack.n = n return current @@ -754,13 +766,13 @@ local function add_to_width(line_break_dir,checked_expansion,s) -- split into tw end elseif id == hlist_code or id == vlist_code then local wd, ht, dp = getwhd(s) - if is_parallel[getfield(s,"dir")][line_break_dir] then + if is_parallel[getdir(s)][line_break_dir] then size = size + wd else size = size + ht + dp end elseif id == kern_code then - local kern = getfield(s,"kern") + local kern = getkern(s) if kern ~= 0 then if checked_expansion and expand_kerns and (getsubtype(s) == kerning_code or getattr(a_fontkern)) then local stretch, shrink = kern_stretch_shrink(s,kern) @@ -776,7 +788,7 @@ local function add_to_width(line_break_dir,checked_expansion,s) -- split into tw size = size + kern end elseif id == rule_code then - size = size + getfield(s,"width") + size = size + getwidth(s) elseif trace_unsupported then report_parbuilders("unsupported node at location %a",6) end @@ -831,12 +843,12 @@ local function compute_break_width(par,break_type,p) -- split in two elseif id == kern_code then local s = getsubtype(p) if s == userkern_code or s == italickern_code then - break_width.size = break_width.size - getfield(p,"kern") + break_width.size = break_width.size - getkern(p) else return end elseif id == math_code then - break_width.size = break_width.size - getfield(p,"surround") + break_width.size = break_width.size - getkern(p) -- surround -- new in luatex local wd, stretch, shrink, stretch_order = getglue(p) local order = stretch_orders[stretch_order] @@ -859,7 +871,7 @@ local function append_to_vlist(par, b) if prev_depth > ignore_depth then if is_hlist then local width, stretch, shrink, stretch_order, shrink_order = getglue(par.baseline_skip) - local delta = width - prev_depth - getfield(b,"height") -- deficiency of space between baselines + local delta = width - prev_depth - getheight(b) -- deficiency of space between baselines local skip = nil if delta < par.line_skip_limit then width, stretch, shrink, stretch_order, shrink_order = getglue(par.lineskip) @@ -882,7 +894,7 @@ local function append_to_vlist(par, b) par.head_field = b end if is_hlist then - local pd = getfield(b,"depth") + local pd = getdepth(b) par.prev_depth = pd texnest[texnest.ptr].prevdepth = pd end @@ -1303,9 +1315,9 @@ local function post_line_break(par) setdisc(lastnode) -- nil, nil, nil disc_break = true elseif id == kern_code then - setfield(lastnode,"kern",0) + setkern(lastnode,0) elseif getid(lastnode) == math_code then - setfield(lastnode,"surround",0) + setkern(lastnode,0) -- surround -- new in luatex setglue(lastnode) -- zeros end @@ -1398,21 +1410,21 @@ local function post_line_break(par) local adjust_head = texlists.adjust_head local pre_adjust_head = texlists.pre_adjust_head -- - setfield(finished_line,"shift",cur_indent) + setshift(finished_line,cur_indent) -- -- -- this is gone: -- -- if par.each_line_height ~= ignored_dimen then - -- setfield(finished_line,"height",par.each_line_height) + -- setheight(finished_line,par.each_line_height) -- end -- if par.each_line_depth ~= ignored_dimen then - -- setfield(finished_line,"depth",par.each_line_depth) + -- setdepth(finished_line,par.each_line_depth) -- end -- if par.first_line_height ~= ignored_dimen and (current_line == par.first_line + 1) then - -- setfield(finished_line,"height",par.first_line_height) + -- setheight(finished_line,par.first_line_height) -- end -- if par.last_line_depth ~= ignored_dimen and current_line + 1 == par.best_line then - -- setfield(finished_line,"depth",par.last_line_depth) + -- setdepth(finished_line,par.last_line_depth) -- end -- if texlists.pre_adjust_head ~= pre_adjust_head then @@ -1473,7 +1485,7 @@ local function post_line_break(par) break elseif id == math_code then -- keep the math node - setfield(next,"surround",0) + setkern(next,0) -- surround -- new in luatex setglue(lastnode) -- zeros break @@ -1519,7 +1531,7 @@ local function wrap_up(par) par.do_last_line_fit = false else local glue = par.final_par_glue - setfield(glue,"width",getfield(glue,"width") + active_short - active_glue) + setwidth(glue,getwidth(glue) + active_short - active_glue) setfield(glue,"stretch",0) if trace_lastlinefit then report_parbuilders("applying last line fit, short %a, glue %p",active_short,active_glue) @@ -2263,7 +2275,7 @@ function constructors.methods.basic(head,d) end elseif id == hlist_code or id == vlist_code then local wd, ht, dp = getwhd(current) - if is_parallel[getfield(current,"dir")][par.line_break_dir] then + if is_parallel[getdir(current)][par.line_break_dir] then active_width.size = active_width.size + wd else active_width.size = active_width.size + ht + dp @@ -2298,7 +2310,7 @@ function constructors.methods.basic(head,d) if second_pass or subtype <= automatic_disc_code then local actual_pen = subtype == automatic_disc_code and par.ex_hyphen_penalty or par.hyphen_penalty -- 0.81 : - -- local actual_pen = getfield(current,"penalty") + -- local actual_pen = getpenalty(current) -- local pre, post, replace = getdisc(current) if not pre then -- trivial pre-break @@ -2377,9 +2389,9 @@ function constructors.methods.basic(head,d) p_active, n_active = try_break(0, unhyphenated_code, par, first_p, current, checked_expansion) end local active_width = par.active_width - active_width.size = active_width.size + getfield(current,"kern") + active_width.size = active_width.size + getkern(current) else - local kern = getfield(current,"kern") + local kern = getkern(current) if kern ~= 0 then active_width.size = active_width.size + kern if checked_expansion and expand_kerns and (getsubtype(current) == kerning_code or getattr(current,a_fontkern)) then @@ -2404,13 +2416,13 @@ function constructors.methods.basic(head,d) p_active, n_active = try_break(0, unhyphenated_code, par, first_p, current, checked_expansion) end local active_width = par.active_width - active_width.size = active_width.size + getfield(current,"surround") + active_width.size = active_width.size + getkern(current) -- surround -- new in luatex - + getfield(current,"width") + + getwidth(current) elseif id == rule_code then - active_width.size = active_width.size + getfield(current,"width") + active_width.size = active_width.size + getwidth(current) elseif id == penalty_code then - p_active, n_active = try_break(getfield(current,"penalty"), unhyphenated_code, par, first_p, current, checked_expansion) + p_active, n_active = try_break(getpenalty(current), unhyphenated_code, par, first_p, current, checked_expansion) elseif id == dir_code then par.line_break_dir = checked_line_dir(dirstack) or par.line_break_dir elseif id == localpar_code then @@ -2492,144 +2504,190 @@ end -- standard tex logging .. will be adapted .. -local function write_esc(cs) - local esc = tex.escapechar - if esc then - write("log",utfchar(esc),cs) - else - write("log",cs) +do + + local function write_esc(cs) + local esc = tex.escapechar + if esc then + write("log",utfchar(esc),cs) + else + write("log",cs) + end end -end -function diagnostics.start() -end + function diagnostics.start() + end -function diagnostics.stop() - write_nl("log",'') -end + function diagnostics.stop() + write_nl("log",'') + end -function diagnostics.current_pass(par,what) - write_nl("log",formatters["@%s"](what)) -end + function diagnostics.current_pass(par,what) + write_nl("log",formatters["@%s"](what)) + end -local verbose = false -- true + local verbose = false -- true -local function short_display(target,a,font_in_short_display) - while a do - local char, id = isglyph(a) - if char then - local font = getfont(a) - if font ~= font_in_short_display then - write(target,tex.fontidentifier(font) .. ' ') - font_in_short_display = font - end - if getsubtype(a) == ligature_code then - font_in_short_display = short_display(target,getfield(a,"components"),font_in_short_display) - else - write(target,utfchar(char)) - end - elseif id == disc_code then - local pre, post, replace = getdisc(a) - font_in_short_display = short_display(target,pre,font_in_short_display) - font_in_short_display = short_display(target,post,font_in_short_display) - elseif verbose then - write(target,formatters["[%s]"](nodecodes[id])) - elseif id == rule_code then - write(target,"|") - elseif id == glue_code then - write(target," ") - elseif id == kern_code then - local s = getsubtype(a) - if s == userkern_code or s == italickern_code or getattr(a,a_fontkern) then - if verbose then - write(target,"[|]") - -- else - -- write(target,"") + local function short_display(target,a,font_in_short_display) + while a do + local char, id = isglyph(a) + if char then + local font = getfont(a) + if font ~= font_in_short_display then + write(target,tex.fontidentifier(font) .. ' ') + font_in_short_display = font + end + -- todo: instead of components the split tounicode string + if getsubtype(a) == ligature_code then + font_in_short_display = short_display(target,getcomponents(a),font_in_short_display) + else + write(target,utfchar(char)) + end + elseif id == disc_code then + local pre, post, replace = getdisc(a) + font_in_short_display = short_display(target,pre,font_in_short_display) + font_in_short_display = short_display(target,post,font_in_short_display) + elseif verbose then + write(target,formatters["[%s]"](nodecodes[id])) + elseif id == rule_code then + write(target,"|") + elseif id == glue_code then + write(target," ") + elseif id == kern_code then + local s = getsubtype(a) + if s == userkern_code or s == italickern_code or getattr(a,a_fontkern) then + if verbose then + write(target,"[|]") + -- else + -- write(target,"") + end + else + write(target,"[]") end + elseif id == math_code then + write(target,"$") else write(target,"[]") end - elseif id == math_code then - write(target,"$") - else - write(target,"[]") + a = getnext(a) end - a = getnext(a) + return font_in_short_display end - return font_in_short_display -end -diagnostics.short_display = short_display + diagnostics.short_display = short_display -function diagnostics.break_node(par, q, fit_class, break_type, current) -- %d ? - local passive = par.passive - local typ_ind = break_type == hyphenated_code and '-' or "" - if par.do_last_line_fit then - local s = number.toscaled(q.active_short) - local g = number.toscaled(q.active_glue) - if current then - write_nl("log",formatters["@@%d: line %d.%d%s t=%s s=%s g=%s"]( - passive.serial or 0,q.line_number-1,fit_class,typ_ind,q.total_demerits,s,g)) + function diagnostics.break_node(par, q, fit_class, break_type, current) -- %d ? + local passive = par.passive + local typ_ind = break_type == hyphenated_code and '-' or "" + if par.do_last_line_fit then + local s = number.toscaled(q.active_short) + local g = number.toscaled(q.active_glue) + if current then + write_nl("log",formatters["@@%d: line %d.%d%s t=%s s=%s g=%s"]( + passive.serial or 0,q.line_number-1,fit_class,typ_ind,q.total_demerits,s,g)) + else + write_nl("log",formatters["@@%d: line %d.%d%s t=%s s=%s a=%s"]( + passive.serial or 0,q.line_number-1,fit_class,typ_ind,q.total_demerits,s,g)) + end else - write_nl("log",formatters["@@%d: line %d.%d%s t=%s s=%s a=%s"]( - passive.serial or 0,q.line_number-1,fit_class,typ_ind,q.total_demerits,s,g)) + write_nl("log",formatters["@@%d: line %d.%d%s t=%s"]( + passive.serial or 0,q.line_number-1,fit_class,typ_ind,q.total_demerits)) + end + if not passive.prev_break then + write("log"," -> @0") + else + write("log",formatters[" -> @%d"](passive.prev_break.serial or 0)) end - else - write_nl("log",formatters["@@%d: line %d.%d%s t=%s"]( - passive.serial or 0,q.line_number-1,fit_class,typ_ind,q.total_demerits)) - end - if not passive.prev_break then - write("log"," -> @0") - else - write("log",formatters[" -> @%d"](passive.prev_break.serial or 0)) end -end -function diagnostics.feasible_break(par, current, r, b, pi, d, artificial_demerits) - local printed_node = par.printed_node - if printed_node ~= current then - write_nl("log","") + function diagnostics.feasible_break(par, current, r, b, pi, d, artificial_demerits) + local printed_node = par.printed_node + if printed_node ~= current then + write_nl("log","") + if not current then + par.font_in_short_display = short_display("log",getnext(printed_node),par.font_in_short_display) + else + local save_link = getnext(current) + setnext(current) + write_nl("log","") + par.font_in_short_display = short_display("log",getnext(printed_node),par.font_in_short_display) + setnext(current,save_link) + end + par.printed_node = current + end + write_nl("log","@") if not current then - par.font_in_short_display = short_display("log",getnext(printed_node),par.font_in_short_display) + write_esc("par") else - local save_link = getnext(current) - setnext(current) - write_nl("log","") - par.font_in_short_display = short_display("log",getnext(printed_node),par.font_in_short_display) - setnext(current,save_link) + local id = getid(current) + if id == glue_code then + -- print nothing + elseif id == penalty_code then + write_esc("penalty") + elseif id == disc_code then + write_esc("discretionary") + elseif id == kern_code then + write_esc("kern") + elseif id == math_code then + write_esc("math") + else + write_esc("unknown") + end + end + local via, badness, demerits = 0, '*', '*' + if r.break_node then + via = r.break_node.serial or 0 + end + if b <= infinite_badness then + badness = tonumber(d) + end + if not artificial_demerits then + demerits = tonumber(d) end - par.printed_node = current + write("log",formatters[" via @%d b=%s p=%s d=%s"](via,badness,pi,demerits)) end - write_nl("log","@") - if not current then - write_esc("par") - else - local id = getid(current) - if id == glue_code then - -- print nothing - elseif id == penalty_code then - write_esc("penalty") - elseif id == disc_code then - write_esc("discretionary") - elseif id == kern_code then - write_esc("kern") - elseif id == math_code then - write_esc("math") + + -- + + local function common_message(hlist,line,str) + write_nl("") + if status.output_active then -- unset + write(str," has occurred while \\output is active") + else + write(str) + end + local fileline = status.linenumber + if line > 0 then + write(formatters[" in paragraph at lines %s--%s"](fileline,"--",fileline+line-1)) + elseif line < 0 then + write(formatters[" in alignment at lines "](fileline,"--",fileline-line-1)) else - write_esc("unknown") + write(formatters[" detected at line %s"](fileline)) end + write_nl("") + diagnostics.short_display(getlist(hlist),false) + write_nl("") + -- diagnostics.start() + -- show_box(getlist(hlist)) + -- diagnostics.stop() + end + + function diagnostics.overfull_hbox(hlist,line,d) + common_message(hlist,line,formatters["Overfull \\hbox (%spt too wide)"](number.toscaled(d))) end - local via, badness, demerits = 0, '*', '*' - if r.break_node then - via = r.break_node.serial or 0 + + function diagnostics.bad_hbox(hlist,line,b) + common_message(hlist,line,formatters["Tight \\hbox (badness %i)"](b)) end - if b <= infinite_badness then - badness = tonumber(d) + + function diagnostics.underfull_hbox(hlist,line,b) + common_message(hlist,line,formatters["Underfull \\hbox (badness %i)"](b)) end - if not artificial_demerits then - demerits = tonumber(d) + + function diagnostics.loose_hbox(hlist,line,b) + common_message(hlist,line,formatters["Loose \\hbox (badness %i)"](b)) end - write("log",formatters[" via @%d b=%s p=%s d=%s"](via,badness,pi,demerits)) + end -- reporting -- @@ -2640,574 +2698,536 @@ statistics.register("alternative parbuilders", function() end end) --- actually scaling kerns is not such a good idea and it will become --- configureable - --- This is no way a replacement for the built in (fast) packer --- it's just an alternative for special (testing) purposes. --- --- We could use two hpacks: one to be used in the par builder --- and one to be used for other purposes. The one in the par --- builder is much more simple as it does not need the expansion --- code but only need to register the effective expansion factor --- with the glyph. - -local function glyph_width_height_depth(curdir,pdir,p) - local wd, ht, dp = getwhd(p) - if is_rotated[curdir] then - if is_parallel[curdir][pdir] then - local half = (ht + dp) / 2 - return wd, half, half - else - local half = wd / 2 - return ht + dp, half, half - end - elseif is_rotated[pdir] then - if is_parallel[curdir][pdir] then - local half = (ht + dp) / 2 - return wd, half, half +do + + -- actually scaling kerns is not such a good idea and it will become + -- configureable + + -- This is no way a replacement for the built in (fast) packer + -- it's just an alternative for special (testing) purposes. + -- + -- We could use two hpacks: one to be used in the par builder + -- and one to be used for other purposes. The one in the par + -- builder is much more simple as it does not need the expansion + -- code but only need to register the effective expansion factor + -- with the glyph. + + local setnodecolor = nodes.tracers.colors.set + + local function glyph_width_height_depth(curdir,pdir,p) + local wd, ht, dp = getwhd(p) + if is_rotated[curdir] then + if is_parallel[curdir][pdir] then + local half = (ht + dp) / 2 + return wd, half, half + else + local half = wd / 2 + return ht + dp, half, half + end + elseif is_rotated[pdir] then + if is_parallel[curdir][pdir] then + local half = (ht + dp) / 2 + return wd, half, half + else + return ht + dp, wd, 0 -- weird + end else - return ht + dp, wd, 0 -- weird - end - else - if glyphdir_is_equal[curdir][pdir] then - return wd, ht, dp - elseif is_opposite[curdir][pdir] then - return wd, dp, ht - else -- can this happen? - return ht + dp, wd, 0 + if glyphdir_is_equal[curdir][pdir] then + return wd, ht, dp + elseif is_opposite[curdir][pdir] then + return wd, dp, ht + else -- can this happen? + return ht + dp, wd, 0 + end end end -end -local function pack_width_height_depth(curdir,pdir,p) - local wd, ht, dp = getwhd(p) - if is_rotated[curdir] then - if is_parallel[curdir][pdir] then - local half = (ht + dp) / 2 - return wd, half, half - else -- can this happen? - local half = wd / 2 - return ht + dp, half, half - end - else - if pardir_is_equal[curdir][pdir] then - return wd, ht, dp - elseif is_opposite[curdir][pdir] then - return wd, dp, ht - else -- weird dimensions, can this happen? - return ht + dp, wd, 0 + local function pack_width_height_depth(curdir,pdir,p) + local wd, ht, dp = getwhd(p) + if is_rotated[curdir] then + if is_parallel[curdir][pdir] then + local half = (ht + dp) / 2 + return wd, half, half + else -- can this happen? + local half = wd / 2 + return ht + dp, half, half + end + else + if pardir_is_equal[curdir][pdir] then + return wd, ht, dp + elseif is_opposite[curdir][pdir] then + return wd, dp, ht + else -- weird dimensions, can this happen? + return ht + dp, wd, 0 + end end end -end --- local function xpack(head,width,method,direction,analysis) --- --- -- inspect(analysis) --- --- local expansion = method == "cal_expand_ratio" --- local natural = analysis.size --- local font_stretch = analysis.adjust_stretch --- local font_shrink = analysis.adjust_shrink --- local font_expand_ratio = 0 --- local delta = width - natural --- --- local hlist = new_hlist() --- --- setlist(hlist,head) --- setfield(hlist,"dir",direction or tex.textdir) --- setfield(hlist,"width",width) --- setfield(hlist,"height",height) --- setfield(hlist,"depth",depth) --- --- if delta == 0 then --- --- setfield(hlist,"glue_sign",0) --- setfield(hlist,"glue_order",0) --- setfield(hlist,"glue_set",0) --- --- else --- --- local order = analysis.filll ~= 0 and fillcodes.filll or --- analysis.fill ~= 0 and fillcodes.fill or --- analysis.fil ~= 0 and fillcodes.fil or --- analysis.fi ~= 0 and fillcodes.fi or 0 --- --- if delta > 0 then --- --- if expansion and order == 0 and font_stretch > 0 then --- font_expand_ratio = (delta/font_stretch) * 1000 --- else --- local stretch = analysis.stretch --- if stretch ~= 0 then --- setfield(hlist,"glue_sign",1) -- stretch --- setfield(hlist,"glue_order",order) --- setfield(hlist,"glue_set",delta/stretch) --- else --- setfield(hlist,"glue_sign",0) -- nothing --- setfield(hlist,"glue_order",order) --- setfield(hlist,"glue_set",0) --- end --- end --- --- else --- --- if expansion and order == 0 and font_shrink > 0 then --- font_expand_ratio = (delta/font_shrink) * 1000 --- else --- local shrink = analysis.shrink --- if shrink ~= 0 then --- setfield(hlist,"glue_sign",2) -- shrink --- setfield(hlist,"glue_order",order) --- setfield(hlist,"glue_set",-delta/stretch) --- else --- setfield(hlist,"glue_sign",0) -- nothing --- setfield(hlist,"glue_order",order) --- setfield(hlist,"glue_set",0) --- end --- end --- --- end --- --- end --- --- if not expansion or font_expand_ratio == 0 then --- -- nothing --- elseif font_expand_ratio > 0 then --- if font_expand_ratio > 1000 then --- font_expand_ratio = 1000 --- end --- local current = head --- while current do --- local id = getid(current) --- if id == glyph_code then --- local stretch, shrink = char_stretch_shrink(current) -- get only one --- if stretch then --- if trace_expansion then --- setnodecolor(g,"hz:positive") --- end --- current.expansion_factor = font_expand_ratio * stretch --- end --- elseif id == kern_code then --- local kern = getfield(current,"kern") --- if kern ~= 0 and getsubtype(current) == kerning_code then --- setfield(current,"kern",font_expand_ratio * kern) --- end --- end --- current = getnext(current) --- end --- elseif font_expand_ratio < 0 then --- if font_expand_ratio < -1000 then --- font_expand_ratio = -1000 --- end --- local current = head --- while current do --- local id = getid(current) --- if id == glyph_code then --- local stretch, shrink = char_stretch_shrink(current) -- get only one --- if shrink then --- if trace_expansion then --- setnodecolor(g,"hz:negative") --- end --- current.expansion_factor = font_expand_ratio * shrink --- end --- elseif id == kern_code then --- local kern = getfield(current,"kern") --- if kern ~= 0 and getsubtype(current) == kerning_code then --- setfield(current,"kern",font_expand_ratio * kern) --- end --- end --- current = getnext(current) --- end --- end --- return hlist, 0 --- end - -local function hpack(head,width,method,direction,firstline,line) -- fast version when head = nil - - -- we can pass the adjust_width and adjust_height so that we don't need to recalculate them but - -- with the glue mess it's less trivial as we lack detail .. challenge - - local hlist = new_hlist() - - setfield(hlist,"dir",direction) - - if head == nil then - setfield(hlist,"width",width) - return hlist, 0 - else - setlist(hlist,head) - end + -- local function xpack(head,width,method,direction,analysis) + -- + -- -- inspect(analysis) + -- + -- local expansion = method == "cal_expand_ratio" + -- local natural = analysis.size + -- local font_stretch = analysis.adjust_stretch + -- local font_shrink = analysis.adjust_shrink + -- local font_expand_ratio = 0 + -- local delta = width - natural + -- + -- local hlist = new_hlist() + -- + -- setlist(hlist,head) + -- setdir(hlist,direction or tex.textdir) + -- setwhd(hlist,width,height,depth) + -- + -- if delta == 0 then + -- + -- setfield(hlist,"glue_sign",0) + -- setfield(hlist,"glue_order",0) + -- setfield(hlist,"glue_set",0) + -- + -- else + -- + -- local order = analysis.filll ~= 0 and fillcodes.filll or + -- analysis.fill ~= 0 and fillcodes.fill or + -- analysis.fil ~= 0 and fillcodes.fil or + -- analysis.fi ~= 0 and fillcodes.fi or 0 + -- + -- if delta > 0 then + -- + -- if expansion and order == 0 and font_stretch > 0 then + -- font_expand_ratio = (delta/font_stretch) * 1000 + -- else + -- local stretch = analysis.stretch + -- if stretch ~= 0 then + -- setfield(hlist,"glue_sign",1) -- stretch + -- setfield(hlist,"glue_order",order) + -- setfield(hlist,"glue_set",delta/stretch) + -- else + -- setfield(hlist,"glue_sign",0) -- nothing + -- setfield(hlist,"glue_order",order) + -- setfield(hlist,"glue_set",0) + -- end + -- end + -- + -- else + -- + -- if expansion and order == 0 and font_shrink > 0 then + -- font_expand_ratio = (delta/font_shrink) * 1000 + -- else + -- local shrink = analysis.shrink + -- if shrink ~= 0 then + -- setfield(hlist,"glue_sign",2) -- shrink + -- setfield(hlist,"glue_order",order) + -- setfield(hlist,"glue_set",-delta/stretch) + -- else + -- setfield(hlist,"glue_sign",0) -- nothing + -- setfield(hlist,"glue_order",order) + -- setfield(hlist,"glue_set",0) + -- end + -- end + -- + -- end + -- + -- end + -- + -- if not expansion or font_expand_ratio == 0 then + -- -- nothing + -- elseif font_expand_ratio > 0 then + -- if font_expand_ratio > 1000 then + -- font_expand_ratio = 1000 + -- end + -- local current = head + -- while current do + -- local id = getid(current) + -- if id == glyph_code then + -- local stretch, shrink = char_stretch_shrink(current) -- get only one + -- if stretch then + -- if trace_expansion then + -- setnodecolor(g,"hz:positive") + -- end + -- current.expansion_factor = font_expand_ratio * stretch + -- end + -- elseif id == kern_code then + -- local kern = getkern(current) + -- if kern ~= 0 and getsubtype(current) == kerning_code then + -- setkern(current,font_expand_ratio * kern) + -- end + -- end + -- current = getnext(current) + -- end + -- elseif font_expand_ratio < 0 then + -- if font_expand_ratio < -1000 then + -- font_expand_ratio = -1000 + -- end + -- local current = head + -- while current do + -- local id = getid(current) + -- if id == glyph_code then + -- local stretch, shrink = char_stretch_shrink(current) -- get only one + -- if shrink then + -- if trace_expansion then + -- setnodecolor(g,"hz:negative") + -- end + -- current.expansion_factor = font_expand_ratio * shrink + -- end + -- elseif id == kern_code then + -- local kern = getkern(current) + -- if kern ~= 0 and getsubtype(current) == kerning_code then + -- setkern(current,font_expand_ratio * kern) + -- end + -- end + -- current = getnext(current) + -- end + -- end + -- return hlist, 0 + -- end + + local function hpack(head,width,method,direction,firstline,line) -- fast version when head = nil + + -- we can pass the adjust_width and adjust_height so that we don't need to recalculate them but + -- with the glue mess it's less trivial as we lack detail .. challenge + + local hlist = new_hlist() + + setdir(hlist,direction) + + if head == nil then + setwidth(hlist,width) + return hlist, 0 + else + setlist(hlist,head) + end - local cal_expand_ratio = method == "cal_expand_ratio" or method == "subst_ex_font" + local cal_expand_ratio = method == "cal_expand_ratio" or method == "subst_ex_font" - direction = direction or tex.textdir + direction = direction or tex.textdir - local line = 0 + local line = 0 - local height = 0 - local depth = 0 - local natural = 0 - local font_stretch = 0 - local font_shrink = 0 - local font_expand_ratio = 0 - local last_badness = 0 - local expansion_stack = cal_expand_ratio and { } -- todo: optionally pass this - local expansion_index = 0 - local total_stretch = { [0] = 0, 0, 0, 0, 0 } - local total_shrink = { [0] = 0, 0, 0, 0, 0 } + local height = 0 + local depth = 0 + local natural = 0 + local font_stretch = 0 + local font_shrink = 0 + local font_expand_ratio = 0 + local last_badness = 0 + local expansion_stack = cal_expand_ratio and { } -- todo: optionally pass this + local expansion_index = 0 + local total_stretch = { [0] = 0, 0, 0, 0, 0 } + local total_shrink = { [0] = 0, 0, 0, 0, 0 } - local hpack_dir = direction + local hpack_dir = direction - local adjust_head = texlists.adjust_head - local pre_adjust_head = texlists.pre_adjust_head - local adjust_tail = adjust_head and slide_node_list(adjust_head) -- todo: find_tail - local pre_adjust_tail = pre_adjust_head and slide_node_list(pre_adjust_head) -- todo: find_tail + local adjust_head = texlists.adjust_head + local pre_adjust_head = texlists.pre_adjust_head + local adjust_tail = adjust_head and slide_node_list(adjust_head) -- todo: find_tail + local pre_adjust_tail = pre_adjust_head and slide_node_list(pre_adjust_head) -- todo: find_tail - new_dir_stack(hpack_dir) + new_dir_stack(hpack_dir) - local checked_expansion = false + local checked_expansion = false - if cal_expand_ratio then - checked_expansion = { } - setmetatableindex(checked_expansion,check_expand_lines) - end + if cal_expand_ratio then + checked_expansion = { } + setmetatableindex(checked_expansion,check_expand_lines) + end - -- this one also needs to check the font, so in the end indeed we might end up with two variants + -- this one also needs to check the font, so in the end indeed we might end up with two variants - local fontexps, lastfont + local fontexps, lastfont - local function process(current) -- called nested in disc replace + local function process(current) -- called nested in disc replace - while current do - local char, id = isglyph(current) - if char then - if cal_expand_ratio then - local currentfont = getfont(current) - if currentfont ~= lastfont then - fontexps = checked_expansion[currentfont] -- a bit redundant for the par line packer - lastfont = currentfont + while current do + local char, id = isglyph(current) + if char then + if cal_expand_ratio then + local currentfont = getfont(current) + if currentfont ~= lastfont then + fontexps = checked_expansion[currentfont] -- a bit redundant for the par line packer + lastfont = currentfont + end + if fontexps then + local expansion = fontexps[char] + if expansion then + font_stretch = font_stretch + expansion.glyphstretch + font_shrink = font_shrink + expansion.glyphshrink + expansion_index = expansion_index + 1 + expansion_stack[expansion_index] = current + end + end + end + -- use inline + local wd, ht, dp = glyph_width_height_depth(hpack_dir,"TLT",current) -- was TRT ? + natural = natural + wd + if ht > height then + height = ht + end + if dp > depth then + depth = dp end - if fontexps then - local expansion = fontexps[char] - if expansion then - font_stretch = font_stretch + expansion.glyphstretch - font_shrink = font_shrink + expansion.glyphshrink + elseif id == kern_code then + local kern = getkern(current) + if kern == 0 then + -- no kern + elseif getsubtype(current) == kerning_code then -- check getkern(p) + if cal_expand_ratio then + local stretch, shrink = kern_stretch_shrink(current,kern) + font_stretch = font_stretch + stretch + font_shrink = font_shrink + shrink expansion_index = expansion_index + 1 expansion_stack[expansion_index] = current end + natural = natural + kern + else + natural = natural + kern end - end - -- use inline - local wd, ht, dp = glyph_width_height_depth(hpack_dir,"TLT",current) -- was TRT ? - natural = natural + wd - if ht > height then - height = ht - end - if dp > depth then - depth = dp - end - elseif id == kern_code then - local kern = getfield(current,"kern") - if kern == 0 then - -- no kern - elseif getsubtype(current) == kerning_code then -- check getfield(p,"kern") - if cal_expand_ratio then - local stretch, shrink = kern_stretch_shrink(current,kern) - font_stretch = font_stretch + stretch - font_shrink = font_shrink + shrink - expansion_index = expansion_index + 1 - expansion_stack[expansion_index] = current + elseif id == disc_code then + local subtype = getsubtype(current) + if subtype ~= second_disc_code then + -- todo : local stretch, shrink = char_stretch_shrink(s) + local replace = getfield(current,"replace") + if replace then + process(replace) + end end - natural = natural + kern - else - natural = natural + kern - end - elseif id == disc_code then - local subtype = getsubtype(current) - if subtype ~= second_disc_code then - -- todo : local stretch, shrink = char_stretch_shrink(s) - local replace = getfield(current,"replace") - if replace then - process(replace) + elseif id == glue_code then + local wd, stretch, shrink, stretch_order, shrink_order = getglue(current) + natural = natural + wd + total_stretch[stretch_order] = total_stretch[stretch_order] + stretch + total_shrink [shrink_order] = total_shrink[shrink_order] + shrink + if getsubtype(current) >= leaders_code then + local leader = getleader(current) + local wd, ht, dp = getwhd(leader) -- can become getwhd(current) after 1.003 + if ht > height then + height = ht + end + if dp > depth then + depth = dp + end end - end - elseif id == glue_code then - local wd, stretch, shrink, stretch_order, shrink_order = getglue(current) - natural = natural + wd - total_stretch[stretch_order] = total_stretch[stretch_order] + stretch - total_shrink [shrink_order] = total_shrink[shrink_order] + shrink - if getsubtype(current) >= leaders_code then - local leader = getleader(current) - local ht = getfield(leader,"height") - local dp = getfield(leader,"depth") + elseif id == hlist_code or id == vlist_code then + local sh = getshift(current) + local wd, ht, dp = pack_width_height_depth(hpack_dir,getdir(current) or hpack_dir,current) -- added: or pack_dir + local hs, ds = ht - sh, dp + sh + natural = natural + wd + if hs > height then + height = hs + end + if ds > depth then + depth = ds + end + elseif id == rule_code then + local wd, ht, dp = getwhd(current) + natural = natural + wd if ht > height then height = ht end if dp > depth then depth = dp end + elseif id == math_code then + natural = natural + getkern(current) -- surround + -- new in luatex + + getwidth(current) + elseif id == unset_code then + local wd, ht, dp = getwhd(current) + local sh = getshift(current) + local hs = ht - sh + local ds = dp + sh + natural = natural + wd + if hs > height then + height = hs + end + if ds > depth then + depth = ds + end + elseif id == ins_code or id == mark_code then + local prev, next = getboth(current) + if adjust_tail then -- todo + setlink(prev,next) + setlink(adjust_tail,current) + setnext(current) + adjust_tail = current + else + adjust_head = current + adjust_tail = current + setboth(current) + end + elseif id == adjust_code then + local list = getlist(current) + if adjust_tail then + setnext(adjust_tail,list) + else + adjust_head = list + end + adjust_tail = slide_node_list(list) -- find_tail(list) + elseif id == dir_code then + hpack_dir = checked_line_dir(stack,current) or hpack_dir + elseif id == marginkern_code then + local width = getwidth(current) + if cal_expand_ratio then + -- is this ok? + local glyph = getfield(current,"glyph") + local char_pw = getsubtype(current) == leftmargin_code and left_pw or right_pw + font_stretch = font_stretch - width - char_pw(glyph) + font_shrink = font_shrink - width - char_pw(glyph) + expansion_index = expansion_index + 1 + expansion_stack[expansion_index] = glyph + end + natural = natural + width end - elseif id == hlist_code or id == vlist_code then - local sh = getfield(current,"shift") - local wd, ht, dp = pack_width_height_depth(hpack_dir,getfield(current,"dir") or hpack_dir,current) -- added: or pack_dir - local hs, ds = ht - sh, dp + sh - natural = natural + wd - if hs > height then - height = hs - end - if ds > depth then - depth = ds - end - elseif id == rule_code then - local wd, ht, dp = getwhd(current) - natural = natural + wd - if ht > height then - height = ht - end - if dp > depth then - depth = dp - end - elseif id == math_code then - natural = natural + getfield(current,"surround") - -- new in luatex - + getfield(current,"width") - elseif id == unset_code then - local wd = getfield(current,"width") - local ht = getfield(current,"height") - local dp = getfield(current,"depth") - local sh = getfield(current,"shift") - local hs = ht - sh - local ds = dp + sh - natural = natural + wd - if hs > height then - height = hs - end - if ds > depth then - depth = ds - end - elseif id == ins_code or id == mark_code then - local prev, next = getboth(current) - if adjust_tail then -- todo - setlink(prev,next) - setlink(adjust_tail,current) - setnext(current) - adjust_tail = current - else - adjust_head = current - adjust_tail = current - setboth(current) - end - elseif id == adjust_code then - local list = getlist(current) - if adjust_tail then - setnext(adjust_tail,list) - else - adjust_head = list - end - adjust_tail = slide_node_list(list) -- find_tail(list) - elseif id == dir_code then - hpack_dir = checked_line_dir(stack,current) or hpack_dir - elseif id == marginkern_code then - local width = getfield(current,"width") - if cal_expand_ratio then - -- is this ok? - local glyph = getfield(current,"glyph") - local char_pw = getsubtype(current) == leftmargin_code and left_pw or right_pw - font_stretch = font_stretch - width - char_pw(glyph) - font_shrink = font_shrink - width - char_pw(glyph) - expansion_index = expansion_index + 1 - expansion_stack[expansion_index] = glyph - end - natural = natural + width + current = getnext(current) end - current = getnext(current) - end - end - - process(head) - - if adjust_tail then - adjust_tail.next = nil -- todo - end - if pre_adjust_tail then - pre_adjust_tail.next = nil -- todo - end - if method == "additional" then - width = width + natural - end + end - setwhd(hlist,width,height,depth) + process(head) - local delta = width - natural - if delta == 0 then - setfield(hlist,"glue_sign",0) - setfield(hlist,"glue_order",0) - setfield(hlist,"glue_set",0) - elseif delta > 0 then - -- natural width smaller than requested width - local order = (total_stretch[4] ~= 0 and 4 or total_stretch[3] ~= 0 and 3) or - (total_stretch[2] ~= 0 and 2 or total_stretch[1] ~= 0 and 1) or 0 - if cal_expand_ratio and order == 0 and font_stretch > 0 then -- check sign of font_stretch - font_expand_ratio = delta/font_stretch + if adjust_tail then + adjust_tail.next = nil -- todo + end + if pre_adjust_tail then + pre_adjust_tail.next = nil -- todo + end + if method == "additional" then + width = width + natural + end - if font_expand_ratio > 1 then - font_expand_ratio = 1 - end + setwhd(hlist,width,height,depth) - local fontexps, lastfont - for i=1,expansion_index do - local g = expansion_stack[i] - local e = 0 - local char = isglyph(g) - if char then - local currentfont = getfont(g) - if currentfont ~= lastfont then - fontexps = expansions[currentfont] - lastfont = currentfont - end - local data = fontexps[char] - if trace_expansion then - setnodecolor(g,"hz:positive") - end - e = font_expand_ratio * data.glyphstretch / 1000 - else - local kern = getfield(g,"kern") - local stretch, shrink = kern_stretch_shrink(g,kern) - e = font_expand_ratio * stretch / 1000 - end - setfield(g,"expansion_factor",e) - end - end - local tso = total_stretch[order] - if tso ~= 0 then - setfield(hlist,"glue_sign",1) - setfield(hlist,"glue_order",order) - setfield(hlist,"glue_set",delta/tso) - else + local delta = width - natural + if delta == 0 then setfield(hlist,"glue_sign",0) - setfield(hlist,"glue_order",order) + setfield(hlist,"glue_order",0) setfield(hlist,"glue_set",0) - end - if font_expand_ratio ~= 0 then - -- todo - elseif order == 0 then -- and getlist(hlist) then - last_badness = calculate_badness(delta,total_stretch[0]) - if last_badness > tex.hbadness then - if last_badness > 100 then - diagnostics.underfull_hbox(hlist,line,last_badness) - else - diagnostics.loose_hbox(hlist,line,last_badness) + elseif delta > 0 then + -- natural width smaller than requested width + local order = (total_stretch[4] ~= 0 and 4 or total_stretch[3] ~= 0 and 3) or + (total_stretch[2] ~= 0 and 2 or total_stretch[1] ~= 0 and 1) or 0 + if cal_expand_ratio and order == 0 and font_stretch > 0 then -- check sign of font_stretch + font_expand_ratio = delta/font_stretch + + if font_expand_ratio > 1 then + font_expand_ratio = 1 + end + + local fontexps, lastfont + for i=1,expansion_index do + local g = expansion_stack[i] + local e = 0 + local char = isglyph(g) + if char then + local currentfont = getfont(g) + if currentfont ~= lastfont then + fontexps = expansions[currentfont] + lastfont = currentfont + end + local data = fontexps[char] + if trace_expansion then + setnodecolor(g,"hz:positive") + end + e = font_expand_ratio * data.glyphstretch / 1000 + else + local kern = getkern(g) + local stretch, shrink = kern_stretch_shrink(g,kern) + e = font_expand_ratio * stretch / 1000 + end + setfield(g,"expansion_factor",e) end end - end - else - -- natural width larger than requested width - local order = total_shrink[4] ~= 0 and 4 or total_shrink[3] ~= 0 and 3 - or total_shrink[2] ~= 0 and 2 or total_shrink[1] ~= 0 and 1 or 0 - if cal_expand_ratio and order == 0 and font_shrink > 0 then -- check sign of font_shrink - font_expand_ratio = delta/font_shrink - - if font_expand_ratio < 1 then - font_expand_ratio = -1 + local tso = total_stretch[order] + if tso ~= 0 then + setfield(hlist,"glue_sign",1) + setfield(hlist,"glue_order",order) + setfield(hlist,"glue_set",delta/tso) + else + setfield(hlist,"glue_sign",0) + setfield(hlist,"glue_order",order) + setfield(hlist,"glue_set",0) end - - local fontexps, lastfont - for i=1,expansion_index do - local g = expansion_stack[i] - local e = 0 - local char = isglyph(g) - if char then - local currentfont = getfont(g) - if currentfont ~= lastfont then - fontexps = expansions[currentfont] - lastfont = currentfont - end - local data = fontexps[char] - if trace_expansion then - setnodecolor(g,"hz:negative") + if font_expand_ratio ~= 0 then + -- todo + elseif order == 0 then -- and getlist(hlist) then + last_badness = calculate_badness(delta,total_stretch[0]) + if last_badness > tex.hbadness then + if last_badness > 100 then + diagnostics.underfull_hbox(hlist,line,last_badness) + else + diagnostics.loose_hbox(hlist,line,last_badness) end - e = font_expand_ratio * data.glyphshrink / 1000 - else - local kern = getfield(g,"kern") - local stretch, shrink = kern_stretch_shrink(g,kern) - e = font_expand_ratio * shrink / 1000 end - setfield(g,"expansion_factor",e) end - end - local tso = total_shrink[order] - if tso ~= 0 then - setfield(hlist,"glue_sign",2) - setfield(hlist,"glue_order",order) - setfield(hlist,"glue_set",-delta/tso) else - setfield(hlist,"glue_sign",0) - setfield(hlist,"glue_order",order) - setfield(hlist,"glue_set",0) - end - if font_expand_ratio ~= 0 then - -- todo - elseif tso < -delta and order == 0 then -- and getlist(hlist) then - last_badness = 1000000 - setfield(hlist,"glue_set",1) - local fuzz = - delta - total_shrink[0] - local hfuzz = tex.hfuzz - if fuzz > hfuzz or tex.hbadness < 100 then - local overfullrule = tex.overfullrule - if fuzz > hfuzz and overfullrule > 0 then - -- weird, is always called and no rules shows up - setfield(slide_node_list(list),"next",new_rule(overfullrule,nil,nil,getfield(hlist,"dir"))) -- todo: find_tail + -- natural width larger than requested width + local order = total_shrink[4] ~= 0 and 4 or total_shrink[3] ~= 0 and 3 + or total_shrink[2] ~= 0 and 2 or total_shrink[1] ~= 0 and 1 or 0 + if cal_expand_ratio and order == 0 and font_shrink > 0 then -- check sign of font_shrink + font_expand_ratio = delta/font_shrink + + if font_expand_ratio < 1 then + font_expand_ratio = -1 + end + + local fontexps, lastfont + for i=1,expansion_index do + local g = expansion_stack[i] + local e = 0 + local char = isglyph(g) + if char then + local currentfont = getfont(g) + if currentfont ~= lastfont then + fontexps = expansions[currentfont] + lastfont = currentfont + end + local data = fontexps[char] + if trace_expansion then + setnodecolor(g,"hz:negative") + end + e = font_expand_ratio * data.glyphshrink / 1000 + else + local kern = getkern(g) + local stretch, shrink = kern_stretch_shrink(g,kern) + e = font_expand_ratio * shrink / 1000 + end + setfield(g,"expansion_factor",e) end - diagnostics.overfull_hbox(hlist,line,-delta) end - elseif order == 0 and getlist(hlist) and last_badness > tex.hbadness then - diagnostics.bad_hbox(hlist,line,last_badness) + local tso = total_shrink[order] + if tso ~= 0 then + setfield(hlist,"glue_sign",2) + setfield(hlist,"glue_order",order) + setfield(hlist,"glue_set",-delta/tso) + else + setfield(hlist,"glue_sign",0) + setfield(hlist,"glue_order",order) + setfield(hlist,"glue_set",0) + end + if font_expand_ratio ~= 0 then + -- todo + elseif tso < -delta and order == 0 then -- and getlist(hlist) then + last_badness = 1000000 + setfield(hlist,"glue_set",1) + local fuzz = - delta - total_shrink[0] + local hfuzz = tex.hfuzz + if fuzz > hfuzz or tex.hbadness < 100 then + local overfullrule = tex.overfullrule + if fuzz > hfuzz and overfullrule > 0 then + -- weird, is always called and no rules shows up + setnext(slide_node_list(list),new_rule(overfullrule,nil,nil,getdir(hlist))) -- todo: find_tail + end + diagnostics.overfull_hbox(hlist,line,-delta) + end + elseif order == 0 and getlist(hlist) and last_badness > tex.hbadness then + diagnostics.bad_hbox(hlist,line,last_badness) + end end + return hlist, last_badness end - return hlist, last_badness -end -xpack_nodes = hpack -- comment this for old fashioned expansion (we need to fix float mess) + xpack_nodes = hpack -- comment this for old fashioned expansion (we need to fix float mess) -constructors.methods.hpack = hpack - -local function common_message(hlist,line,str) - write_nl("") - if status.output_active then -- unset - write(str," has occurred while \\output is active") - else - write(str) - end - local fileline = status.linenumber - if line > 0 then - write(formatters[" in paragraph at lines %s--%s"](fileline,"--",fileline+line-1)) - elseif line < 0 then - write(formatters[" in alignment at lines "](fileline,"--",fileline-line-1)) - else - write(formatters[" detected at line %s"](fileline)) - end - write_nl("") - diagnostics.short_display(getlist(hlist),false) - write_nl("") - -- diagnostics.start() - -- show_box(getlist(hlist)) - -- diagnostics.stop() -end - -function diagnostics.overfull_hbox(hlist,line,d) - common_message(hlist,line,formatters["Overfull \\hbox (%spt too wide)"](number.toscaled(d))) -end - -function diagnostics.bad_hbox(hlist,line,b) - common_message(hlist,line,formatters["Tight \\hbox (badness %i)"](b)) -end - -function diagnostics.underfull_hbox(hlist,line,b) - common_message(hlist,line,formatters["Underfull \\hbox (badness %i)"](b)) -end + constructors.methods.hpack = hpack -function diagnostics.loose_hbox(hlist,line,b) - common_message(hlist,line,formatters["Loose \\hbox (badness %i)"](b)) end diff --git a/tex/context/base/mkiv/node-met.lua b/tex/context/base/mkiv/node-met.lua index ea6ce6aca..acdb1286e 100644 --- a/tex/context/base/mkiv/node-met.lua +++ b/tex/context/base/mkiv/node-met.lua @@ -63,12 +63,7 @@ end nodes = nodes or { } local nodes = nodes ------ gonuts = type(node.direct) == "table" ------.gonuts = gonuts - local nodecodes = nodes.nodecodes -local hlist_code = nodecodes.hlist -local vlist_code = nodecodes.vlist nodes.tostring = node.tostring or tostring nodes.copy = node.copy @@ -107,8 +102,12 @@ nodes.protrusion_skippable = node.protrusion_skippable nodes.check_discretionaries = node.check_discretionaries nodes.write = node.write +nodes.count = node.count +nodes.length = node.length + nodes.has_attribute = node.has_attribute nodes.set_attribute = node.set_attribute +nodes.find_attribute = node.find_attribute nodes.unset_attribute = node.unset_attribute nodes.protect_glyphs = node.protect_glyphs @@ -118,34 +117,6 @@ nodes.kerning = node.kerning nodes.ligaturing = node.ligaturing nodes.mlist_to_hlist = node.mlist_to_hlist -if LUATEXVERSION < 0.97 then - - local getglue = node.getglue - - function node.is_zero_glue(n) - local width, stretch, shrink = getglue(n) - return width == 0 and stretch == 0 and shrink == 0 - end - -end - -if not node.rangedimensions then -- LUATEXVERSION < 0.99 - - local dimensions = node.dimensions - local getfield = node.getfield - local find_tail = node.tail - - function node.rangedimensions(parent,first,last) - return dimensions( - getfield(parent,"glue_set"), getfield(parent,"glue_sign"), getfield(parent,"glue_order"), - first, last or find_tail(first), getfield(parent,"dir") - ) - end - - nodes.rangedimensions = node.rangedimensions - -end - if not node.getwhd then local getfield = node.getfield function node.getwhd(n) @@ -196,69 +167,82 @@ local n_getfield = node.getfield local n_setattr = node.setattr local n_getattr = node.getattr local n_getdisc = node.getdisc -local n_getwhd = node.getwhd local n_getleader = node.getleader -local n_setnext = node.setnext or +local n_setnext = node.setnext or -- always function(c,next) setfield(c,"next",n) end -local n_setprev = node.setprev or +local n_setprev = node.setprev or -- always function(c,prev) setfield(c,"prev",p) end -local n_setlink = node.setlink or - function(c1,c2) - if c1 then setfield(c1,"next",c2) end - if c2 then setfield(c2,"prev",c1) end +local n_setlink = node.setlink or -- always +-- function(c1,c2) +-- if c1 then setfield(c1,"next",c2) end +-- if c2 then setfield(c2,"prev",c1) end +-- end + function(...) + -- not that fast but not used often anyway + local h = nil + for i=1,select("#",...) do + local n = (select(i,...)) + if not n then + -- go on + elseif h then + setfield(h,"next",n) + setfield(n,"prev",h) + else + h = n + end + end + return h end -local n_setboth = node.setboth or +local n_setboth = node.setboth or -- always function(c,p,n) setfield(c,"prev",p) setfield(c,"next",n) end -node.setnext = n_setnext -node.setprev = n_setprev -node.setlink = n_setlink -node.setboth = n_setboth - -nodes.getfield = n_getfield -nodes.setfield = n_setfield -nodes.getattr = n_getattr -nodes.setattr = n_setattr - -nodes.getnext = n_getnext -nodes.getprev = n_getprev -nodes.getid = n_getid -nodes.getchar = n_getchar -nodes.getfont = n_getfont -nodes.getsubtype = n_getsubtype -nodes.getlist = n_getlist -nodes.getleader = n_getleader -nodes.getdisc = n_getdisc ------.getpre = node.getpre or function(n) local h, _, _, t = n_getdisc(n,true) return h, t end ------.getpost = node.getpost or function(n) local _, h, _, _, t = n_getdisc(n,true) return h, t end ------.getreplace = node.getreplace or function(n) local _, _, h, _, _, t = n_getdisc(n,true) return h, t end - -nodes.is_char = node.is_char -nodes.ischar = node.is_char - -nodes.is_glyph = node.is_glyph -nodes.isglyph = node.is_glyph - -nodes.getbox = node.getbox or tex.getbox -nodes.setbox = node.setbox or tex.setbox - -local n_flush_node = nodes.flush -local n_copy_node = nodes.copy -local n_copy_list = nodes.copy_list -local n_find_tail = nodes.tail -local n_insert_after = nodes.insert_after -local n_insert_before = nodes.insert_before -local n_slide = nodes.slide - -local n_remove_node = node.remove -- not yet nodes.remove +node.setnext = n_setnext +node.setprev = n_setprev +node.setlink = n_setlink +node.setboth = n_setboth + +nodes.getfield = n_getfield +nodes.setfield = n_setfield +nodes.getattr = n_getattr +nodes.setattr = n_setattr +nodes.takeattr = nodes.unset_attribute + +nodes.getnext = n_getnext +nodes.getprev = n_getprev +nodes.getid = n_getid +nodes.getchar = n_getchar +nodes.getfont = n_getfont +nodes.getsubtype = n_getsubtype +nodes.getlist = n_getlist +nodes.getleader = n_getleader +nodes.getdisc = n_getdisc + +nodes.is_char = node.is_char +nodes.ischar = node.is_char + +nodes.is_glyph = node.is_glyph +nodes.isglyph = node.is_glyph + +nodes.getbox = node.getbox or tex.getbox +nodes.setbox = node.setbox or tex.setbox + +local n_flush_node = nodes.flush +local n_copy_node = nodes.copy +local n_copy_list = nodes.copy_list +local n_find_tail = nodes.tail +local n_insert_after = nodes.insert_after +local n_insert_before = nodes.insert_before +local n_slide = nodes.slide + +local n_remove_node = node.remove -- not yet nodes.remove local function remove(head,current,free_too) local t = current @@ -311,26 +295,7 @@ function nodes.replace(head,current,new) -- no head returned if false end end -local function count(stack,flat) - local n = 0 - while stack do - local id = n_getid(stack) - if not flat and id == hlist_code or id == vlist_code then - local list = n_getlist(stack) - if list then - n = n + 1 + count(list) -- self counts too - else - n = n + 1 - end - else - n = n + 1 - end - stack = n_getnext(stack) - end - return n -end - -nodes.count = count +-- nodes.countall : see node-nut.lua function nodes.append(head,current,...) for i=1,select("#",...) do @@ -662,7 +627,7 @@ local messyhack = table.tohash { -- temporary solution } table.setmetatableindex(keys,function(t,k) - v = (k == "attributelist" or k == nodecodes.attributelist) and { } or getfields(k) + local v = (k == "attributelist" or k == nodecodes.attributelist) and { } or getfields(k) if messyhack[k] then for i=1,#v do if v[i] == "subtype" then diff --git a/tex/context/base/mkiv/node-mig.lua b/tex/context/base/mkiv/node-mig.lua index 24bebb0cc..b3820a7d8 100644 --- a/tex/context/base/mkiv/node-mig.lua +++ b/tex/context/base/mkiv/node-mig.lua @@ -16,7 +16,7 @@ local report_nodes = logs.reporter("nodes","migrations") local attributes = attributes local nodes = nodes -local tasks = nodes.tasks +local enableaction = nodes.tasks.enableaction local nuts = nodes.nuts local tonut = nuts.tonut @@ -26,7 +26,6 @@ local getid = nuts.getid local getlist = nuts.getlist local getattr = nuts.getattr -local setfield = nuts.setfield local setattr = nuts.setattr local setlink = nuts.setlink local setlist = nuts.setlist @@ -139,21 +138,21 @@ end experiments.register("marks.migrate", function(v) if v then - tasks.enableaction("mvlbuilders", "nodes.handlers.migrate") + enableaction("mvlbuilders", "nodes.handlers.migrate") end migrate_marks = v end) experiments.register("inserts.migrate", function(v) if v then - tasks.enableaction("mvlbuilders", "nodes.handlers.migrate") + enableaction("mvlbuilders", "nodes.handlers.migrate") end migrate_inserts = v end) experiments.register("inserts.migrate.nested", function(v) if v then - tasks.enableaction("mvlbuilders", "nodes.handlers.migrate") + enableaction("mvlbuilders", "nodes.handlers.migrate") end inserts_too = v end) diff --git a/tex/context/base/mkiv/node-nut.lua b/tex/context/base/mkiv/node-nut.lua index cec272bcf..0c6714667 100644 --- a/tex/context/base/mkiv/node-nut.lua +++ b/tex/context/base/mkiv/node-nut.lua @@ -133,19 +133,90 @@ if not direct.setwhd then end end -nuts.getwhd = direct.getwhd -nuts.setwhd = direct.setwhd - -nuts.getfield = direct.getfield -nuts.getnext = direct.getnext -nuts.getprev = direct.getprev -nuts.getid = direct.getid -nuts.getattr = direct.get_attribute or direct.has_attribute or direct.getfield -nuts.getchar = direct.getchar -nuts.getfont = direct.getfont -nuts.getsubtype = direct.getsubtype -nuts.getlist = direct.getlist -- only hlist and vlist ! -nuts.getleader = direct.getleader +if not direct.getcomponents then + + local getfield = direct.getfield + local setfield = direct.setfield + local setsubtype = direct.setsubtype + + local attributelist_code = nodecodes.attributelist + + function direct.getcomponents(n) return getfield(n,"components") end + function direct.setcomponents(n,c) setfield(n,"components",c) end + function direct.getkern(n) return getfield(n,"kern") end + function direct.getwidth(n) return getfield(n,"width") end + function direct.setwidth(n,w) return setfield(n,"width",w) end + function direct.getheight(n) return getfield(n,"height") end + function direct.setheight(n,h) return setfield(n,"height",h) end + function direct.getdepth(n) return getfield(n,"depth") end + function direct.setdepth(n,d) return setfield(n,"depth",d) end + function direct.getshift(n) return getfield(n,"shift") end + function direct.setshift(n,s) return setfield(n,"shift",s) end + function direct.getpenalty(n) return getfield(n,"penalty") end + function direct.setpenalty(n,p) setfield(n,"penalty",p) end + function direct.getdir(n) return getfield(n,"dir") end + function direct.setdir(n,p) setfield(n,"dir",p) end + function direct.getlanguage(n) return getfield(n,"lang") end + function direct.setlanguage(n,l) return setfield(n,"lang",l) end + function direct.getattributelist(n) getfield(n,"attr") end + + function direct.getnucleus(n) return getfield(n,"nucleus") end + function direct.setnucleus(n,p) return setfield(n,"nucleus",p) end + function direct.getsup(n) return getfield(n,"sup") end + function direct.setsup(n,p) return setfield(n,"sup",p) end + function direct.getsub(n) return getfield(n,"sub") end + function direct.setsub(n,p) return setfield(n,"sub",p) end + + function direct.setattributelist(n,a) + if a and type(a) ~= attributelist_code then + a = getfield(a,"attr") + end + setfield(n,"attr",a) + end + + function direct.setkern(n,k,s) + setfield(n,"kern",k) + if s then + setsubtype(n,s) + end + end + + function direct.setfont(n,f,c) + setfield(n,"font",f) + if c then + setfield(n,"char",f) + end + end + + function direct.getoffsets(n) + return getfield(n,"xoffset"), getfield(n,"yoffset") + end + + function direct.setoffsets(n,x,y) + if x then + setfield(n,"xoffset",x) + end + if y then + setfield(n,"yoffset",y) + end + end + +end + +-- if LUATEXVERSION < 1.004 then +-- local gc = direct.getcomponents +-- getcomponents = function(n) local c = gc(n) return c ~= 0 and c or nil end +-- end + +-- local hash = table.setmetatableindex("number") +-- local ga = direct.get_attribute +-- function direct.get_attribute(n,a) +-- hash[a] = hash[a] + 1 +-- return ga(n,a) +-- end +-- function nuts.reportattr() +-- inspect(hash) +-- end -- local function track(name) -- local n = 0 @@ -163,12 +234,6 @@ nuts.getleader = direct.getleader -- setters -nuts.setfield = direct.setfield -nuts.setattr = direct.set_attribute or setfield - -nuts.getbox = direct.getbox -nuts.setbox = direct.setbox - -- helpers nuts.tostring = direct.tostring @@ -199,6 +264,10 @@ nuts.is_direct = direct.is_direct nuts.is_nut = direct.is_direct nuts.first_glyph = direct.first_glyph nuts.has_glyph = direct.has_glyph or direct.first_glyph +nuts.count = direct.count +nuts.length = direct.length +nuts.find_attribute = direct.find_attribute +nuts.unset_attribute = direct.unset_attribute nuts.current_attr = direct.current_attr nuts.has_field = direct.has_field @@ -228,56 +297,95 @@ if not direct.mlist_to_hlist then -- needed end -if LUATEXVERSION < 0.97 then - - local getglue = direct.getglue - - function direct.is_zero_glue(n) - local width, stretch, shrink = getglue(n) - return width == 0 and stretch == 0 and shrink == 0 - end - -end - -if not direct.rangedimensions then -- LUATEXVERSION < 0.99 - - local dimensions = direct.dimensions - local getfield = direct.getfield - local find_tail = direct.tail +nuts.getfield = direct.getfield +nuts.setfield = direct.setfield - function direct.rangedimensions(parent,first,last) - return dimensions( - getfield(parent,"glue_set"), getfield(parent,"glue_sign"), getfield(parent,"glue_order"), - first, last or find_tail(first), getfield(parent,"dir") - ) - end +nuts.getnext = direct.getnext +nuts.setnext = direct.setnext - nuts.rangedimensions = direct.rangedimensions +nuts.getid = direct.getid -end +nuts.getprev = direct.getprev +nuts.setprev = direct.setprev -local getglue = direct.getglue -local setglue = direct.setglue -local is_zero_glue = direct.is_zero_glue +nuts.getattr = direct.get_attribute +nuts.setattr = direct.set_attribute +nuts.takeattr = direct.unset_attribute -- ? +nuts.is_zero_glue = direct.is_zero_glue nuts.effective_glue = direct.effective_glue -nuts.getglue = getglue -nuts.setglue = setglue -nuts.is_zero_glue = is_zero_glue + +nuts.getglue = direct.getglue +nuts.setglue = direct.setglue nuts.getdisc = direct.getdisc -nuts.getwhd = direct.getwhd nuts.setdisc = direct.setdisc +nuts.getdiscretionary = direct.getdisc +nuts.setdiscretionary = direct.setdisc + +nuts.getwhd = direct.getwhd +nuts.setwhd = direct.setwhd +nuts.getwidth = direct.getwidth +nuts.setwidth = direct.setwidth +nuts.getheight = direct.getheight +nuts.setheight = direct.setheight +nuts.getdepth = direct.getdepth +nuts.setdepth = direct.setdepth +nuts.getshift = direct.getshift +nuts.setshift = direct.setshift + +nuts.getnucleus = direct.getnucleus +nuts.setnucleus = direct.setnucleus +nuts.getsup = direct.getsup +nuts.setsup = direct.setsup +nuts.getsub = direct.getsub +nuts.setsub = direct.setsub + +nuts.getchar = direct.getchar nuts.setchar = direct.setchar -nuts.setnext = direct.setnext -nuts.setprev = direct.setprev -nuts.setboth = direct.setboth +nuts.getfont = direct.getfont +nuts.setfont = direct.setfont + nuts.getboth = direct.getboth +nuts.setboth = direct.setboth nuts.setlink = direct.setlink +nuts.setsplit = direct.setsplit + +nuts.getlist = direct.getlist -- only hlist and vlist ! nuts.setlist = direct.setlist +nuts.getleader = direct.getleader nuts.setleader = direct.setleader +nuts.getcomponents = direct.getcomponents +nuts.setcomponents = direct.setcomponents + +nuts.getsubtype = direct.getsubtype nuts.setsubtype = direct.setsubtype +nuts.getlang = direct.getlang +nuts.setlang = direct.setlang +nuts.getlanguage = direct.getlang +nuts.setlanguage = direct.setlang + +nuts.getattrlist = direct.getattributelist +nuts.setattrlist = direct.setattributelist +nuts.getattributelist = direct.getattributelist +nuts.setattributelist = direct.setattributelist + +nuts.getoffsets = direct.getoffsets +nuts.setoffsets = direct.setoffsets + +nuts.getkern = direct.getkern +nuts.setkern = direct.setkern + +nuts.getdir = direct.getdir +nuts.setdir = direct.setdir + +nuts.getpenalty = direct.getpenalty +nuts.setpenalty = direct.setpenalty + +nuts.getbox = direct.getbox +nuts.setbox = direct.setbox + nuts.is_char = direct.is_char nuts.ischar = direct.is_char nuts.is_glyph = direct.is_glyph @@ -313,6 +421,11 @@ local function remove(head,current,free_too) return head, current, t end +-- alias + +nuts.getsurround = nuts.getkern +nuts.setsurround = nuts.setkern + -- bad: we can have prev's being glue_spec nuts.remove = remove @@ -326,11 +439,14 @@ function nuts.replace(head,current,new) -- no head returned if false head, current, new = false, head, current end local prev, next = d_getboth(current) - if next then - d_setlink(new,next) - end - if prev then - d_setlink(prev,new) +-- if next then +-- d_setlink(new,next) +-- end +-- if prev then +-- d_setlink(prev,new) +-- end + if prev or next then + d_setlink(prev,new,next) end if head then if head == current then @@ -344,14 +460,14 @@ function nuts.replace(head,current,new) -- no head returned if false end end -local function count(stack,flat) +local function countall(stack,flat) local n = 0 while stack do local id = d_getid(stack) if not flat and id == hlist_code or id == vlist_code then local list = d_getlist(stack) if list then - n = n + 1 + count(list) -- self counts too + n = n + 1 + countall(list) -- self counts too else n = n + 1 end @@ -363,7 +479,11 @@ local function count(stack,flat) return n end -nuts.count = count +nuts.countall = countall + +function nodes.countall(stack,flat) + return countall(tonut(stack),flat) +end function nuts.append(head,current,...) for i=1,select("#",...) do @@ -379,7 +499,7 @@ function nuts.prepend(head,current,...) return head, current end -function nuts.linked(...) +function nuts.linked(...) -- slides ! local head, last for i=1,select("#",...) do local next = select(i,...) diff --git a/tex/context/base/mkiv/node-ppt.lua b/tex/context/base/mkiv/node-ppt.lua index 82acf2ff4..5ebfca87d 100644 --- a/tex/context/base/mkiv/node-ppt.lua +++ b/tex/context/base/mkiv/node-ppt.lua @@ -27,7 +27,6 @@ local getnext = nuts.getnext local getprev = nuts.getprev local getsubtype = nuts.getsubtype local getfield = nuts.getfield -local setfield = nuts.setfield local getlist = nuts.getlist local setlist = nuts.setlist local removenode = nuts.remove @@ -102,8 +101,7 @@ local actions = { } properties.actions = actions table.setmetatableindex(actions,function(t,k) report("unknown property action %a",k) - local v = function() end - return v + return function() end end) local f_delayed = formatters["return function(target,head,where,propdata,parent) %s end"] @@ -314,7 +312,7 @@ local anchored = { } table.setmetatableindex(anchored,function(t,k) - v = anchored[v_after] + local v = anchored[v_after] t[k] = v return v end) diff --git a/tex/context/base/mkiv/node-pro.lua b/tex/context/base/mkiv/node-pro.lua index 713d78f07..8a501a590 100644 --- a/tex/context/base/mkiv/node-pro.lua +++ b/tex/context/base/mkiv/node-pro.lua @@ -6,23 +6,17 @@ if not modules then modules = { } end modules ['node-pro'] = { license = "see context related readme files" } -local utfchar = utf.char -local format, concat = string.format, table.concat - local trace_callbacks = false trackers .register("nodes.callbacks", function(v) trace_callbacks = v end) local force_processors = false directives.register("nodes.processors.force", function(v) force_processors = v end) local report_nodes = logs.reporter("nodes","processors") -local nodes = nodes -local tasks = nodes.tasks -local nuts = nodes.nuts - -local first_glyph = nodes.first_glyph -local has_glyph = nodes.has_glyph +local nodes = nodes +local tasks = nodes.tasks +local nuts = nodes.nuts -nodes.processors = nodes.processors or { } -local processors = nodes.processors +nodes.processors = nodes.processors or { } +local processors = nodes.processors -- vbox: grouptype: vbox vtop output split_off split_keep | box_type: exactly|aditional -- hbox: grouptype: hbox adjusted_hbox(=hbox_in_vmode) | box_type: exactly|aditional @@ -35,6 +29,9 @@ do local isglyph = nuts.isglyph local getnext = nuts.getnext + local utfchar = utf.char + local concat = table.concat + local n = 0 local function reconstruct(head) -- we probably have a better one @@ -72,125 +69,164 @@ local tracer = processors.tracer processors.enabled = true -- this will become a proper state (like trackers) -function processors.pre_linebreak_filter(head,groupcode) -- ,size,packtype,direction - -- local first, found = first_glyph(head) -- they really need to be glyphs - local found = force_processors or has_glyph(head) - if found then - if trace_callbacks then - local before = nodes.count(head,true) - local head, done = actions(head,groupcode) -- ,size,packtype,direction - local after = nodes.count(head,true) - if done then - tracer("pre_linebreak","changed",head,groupcode,before,after,true) +do + + local has_glyph = nodes.has_glyph + + function processors.pre_linebreak_filter(head,groupcode) -- ,size,packtype,direction + local found = force_processors or has_glyph(head) + if found then + if trace_callbacks then + local before = nodes.count(head,true) + local head, done = actions(head,groupcode) -- ,size,packtype,direction + local after = nodes.count(head,true) + if done then + tracer("pre_linebreak","changed",head,groupcode,before,after,true) + else + tracer("pre_linebreak","unchanged",head,groupcode,before,after,true) + end + return done and head or true else - tracer("pre_linebreak","unchanged",head,groupcode,before,after,true) + local head, done = actions(head,groupcode) -- ,size,packtype,direction + return done and head or true end - return done and head or true - else - local head, done = actions(head,groupcode) -- ,size,packtype,direction - return done and head or true + elseif trace_callbacks then + local n = nodes.count(head,false) + tracer("pre_linebreak","no chars",head,groupcode,n,n) end - elseif trace_callbacks then - local n = nodes.count(head,false) - tracer("pre_linebreak","no chars",head,groupcode,n,n) + return true end - return true -end -local function hpack_filter(head,groupcode,size,packtype,direction,attributes) - -- local first, found = first_glyph(head) -- they really need to be glyphs - local found = force_processors or has_glyph(head) - if found then - if trace_callbacks then - local before = nodes.count(head,true) - local head, done = actions(head,groupcode,size,packtype,direction,attributes) - local after = nodes.count(head,true) - if done then - tracer("hpack","changed",head,groupcode,before,after,true) + local function hpack_filter(head,groupcode,size,packtype,direction,attributes) + local found = force_processors or has_glyph(head) + if found then + if trace_callbacks then + local before = nodes.count(head,true) + local head, done = actions(head,groupcode,size,packtype,direction,attributes) + local after = nodes.count(head,true) + if done then + tracer("hpack","changed",head,groupcode,before,after,true) + else + tracer("hpack","unchanged",head,groupcode,before,after,true) + end + return done and head or true else - tracer("hpack","unchanged",head,groupcode,before,after,true) + local head, done = actions(head,groupcode,size,packtype,direction,attributes) + return done and head or true end - return done and head or true - else - local head, done = actions(head,groupcode,size,packtype,direction,attributes) - return done and head or true + elseif trace_callbacks then + local n = nodes.count(head,false) + tracer("hpack","no chars",head,groupcode,n,n) end - elseif trace_callbacks then - local n = nodes.count(head,false) - tracer("hpack","no chars",head,groupcode,n,n) + return true end - return true -end -processors.hpack_filter = hpack_filter + processors.hpack_filter = hpack_filter -do + do + + local setfield = nodes.setfield + local hpack = nodes.hpack + + function nodes.fullhpack(head,...) + local ok = hpack_filter(head) + if not done or done == true then + ok = head + end + local hp, b = hpack(ok,...) + setfield(hp,"prev",nil) + setfield(hp,"next",nil) + return hp, b + end + + end + + do - local setfield = nodes.setfield - local hpack = nodes.hpack + local setboth = nuts.setboth + local hpack = nuts.hpack - function nodes.fullhpack(head,...) - local ok = hpack_filter(head) - if not done or done == true then - ok = head + function nuts.fullhpack(head,...) + local ok = hpack_filter(tonode(head)) + if not done or done == true then + ok = head + else + ok = tonut(ok) + end + local hp, b = hpack(...) + setboth(hp) + return hp, b end - local hp, b = hpack(ok,...) - setfield(hp,"prev",nil) - setfield(hp,"next",nil) - return hp, b + end + callbacks.register('pre_linebreak_filter', processors.pre_linebreak_filter, "all kind of horizontal manipulations (before par break)") + callbacks.register('hpack_filter' , processors.hpack_filter, "all kind of horizontal manipulations (before hbox creation)") + end do - local setboth = nuts.setboth - local hpack = nuts.hpack + local actions = tasks.actions("finalizers") -- head, where + + -- beware, these are packaged boxes so no first_glyph test + -- maybe some day a hash with valid groupcodes + -- + -- beware, much can pass twice, for instance vadjust passes two times + -- + -- something weird here .. group mvl when making a vbox - function nuts.fullhpack(head,...) - local ok = hpack_filter(tonode(head)) - if not done or done == true then - ok = head + function processors.post_linebreak_filter(head,groupcode) + if trace_callbacks then + local before = nodes.count(head,true) + local head, done = actions(head,groupcode) + local after = nodes.count(head,true) + if done then + tracer("post_linebreak","changed",head,groupcode,before,after,true) + else + tracer("post_linebreak","unchanged",head,groupcode,before,after,true) + end + return done and head or true else - ok = tonut(ok) + local head, done = actions(head,groupcode) + return done and head or true end - local hp, b = hpack(...) - setboth(hp) - return hp, b end + callbacks.register('post_linebreak_filter', processors.post_linebreak_filter,"all kind of horizontal manipulations (after par break)") + end -callbacks.register('pre_linebreak_filter', processors.pre_linebreak_filter, "all kind of horizontal manipulations (before par break)") -callbacks.register('hpack_filter' , processors.hpack_filter, "all kind of horizontal manipulations (before hbox creation)") - -local actions = tasks.actions("finalizers") -- head, where - --- beware, these are packaged boxes so no first_glyph test --- maybe some day a hash with valid groupcodes --- --- beware, much can pass twice, for instance vadjust passes two times --- --- something weird here .. group mvl when making a vbox - -function processors.post_linebreak_filter(head,groupcode) - if trace_callbacks then - local before = nodes.count(head,true) - local head, done = actions(head,groupcode) - local after = nodes.count(head,true) - if done then - tracer("post_linebreak","changed",head,groupcode,before,after,true) - else - tracer("post_linebreak","unchanged",head,groupcode,before,after,true) +do + + local texnest = tex.nest + + local getlist = nodes.getlist + local getsubtype = nodes.getsubtype + local setlist = nodes.setlist + + local line_code = nodes.listcodes.line + + local actions = tasks.actions("contributers") + + function processors.contribute_filter(groupcode) + if groupcode == "box" then -- "pre_box" + local whatever = texnest[texnest.ptr] + if whatever then + local tail = whatever.tail + if tail and getsubtype(tail) == line_code then + local okay, done = actions(tail,groupcode) + if okay and okay ~= tail then + setlist(tail,okay) + end + end + end end - return done and head or true - else - local head, done = actions(head,groupcode) - return done and head or true end -end -callbacks.register('post_linebreak_filter', processors.post_linebreak_filter,"all kind of horizontal manipulations (after par break)") + callbacks.register('contribute_filter', processors.contribute_filter,"things done with lines") + +end statistics.register("h-node processing time", function() return statistics.elapsedseconds(nodes,"including kernel") -- hm, ok here? diff --git a/tex/context/base/mkiv/node-ref.lua b/tex/context/base/mkiv/node-ref.lua index c082ac817..b313a00b6 100644 --- a/tex/context/base/mkiv/node-ref.lua +++ b/tex/context/base/mkiv/node-ref.lua @@ -32,7 +32,7 @@ local cleanupdestinations = true local transparencies = attributes.transparencies local colors = attributes.colors local references = structures.references -local tasks = nodes.tasks +local enableaction = nodes.tasks.enableaction local trace_references = false trackers.register("nodes.references", function(v) trace_references = v end) local trace_destinations = false trackers.register("nodes.destinations", function(v) trace_destinations = v end) @@ -60,10 +60,15 @@ local getprev = nuts.getprev local getid = nuts.getid local getlist = nuts.getlist local setlist = nuts.setlist +local getwidth = nuts.getwidth +local setwidth = nuts.setwidth +local getheight = nuts.getheight local getattr = nuts.getattr local setattr = nuts.setattr local getsubtype = nuts.getsubtype local getwhd = nuts.getwhd +local getdir = nuts.getdir +local setshift = nuts.setshift local hpack_list = nuts.hpack local vpack_list = nuts.vpack @@ -212,7 +217,7 @@ local function dimensions(parent,start,stop) -- in principle we could move some report_area("dimensions taken of vlist") end local w, h, d = vlist_dimensions(first,last,parent) - local ht = getfield(first,"height") + local ht = getheight(first) return w, ht, d + h - ht, first else -- return hlist_dimensions(start,stop,parent) @@ -286,8 +291,9 @@ if first == last and getid(parent) == vlist_code and getid(first) == hlist_code setlink(result,getlist(first)) setlist(first,result) else - setlink(getprev(first),result) - setlink(result,first) + -- setlink(getprev(first),result) + -- setlink(result,first) + setlink(getprev(first),result,first) end return head, last end @@ -345,8 +351,9 @@ local function inject_list(id,current,reference,make,stack,pardir,txtdir) setlist(current,result) elseif moveright then -- brr no prevs done -- result after first - setlink(result,getnext(first)) - setlink(first,result) + -- setlink(result,getnext(first)) + -- setlink(first,result) + setlink(first,result,getnext(first)) else -- first after result setlink(result,first) @@ -405,9 +412,9 @@ local function inject_areas(head,attribute,make,stack,done,skip,parent,pardir,tx done[r] = done[r] - 1 end elseif id == dir_code then - txtdir = getfield(current,"dir") + txtdir = getdir(current) elseif id == localpar_code then - pardir = getfield(current,"dir") + pardir = getdir(current) elseif id == glue_code and getsubtype(current) == leftskip_code then -- any glue at the left? -- else @@ -457,9 +464,9 @@ local function inject_area(head,attribute,make,stack,done,parent,pardir,txtdir) end end elseif id == dir_code then - txtdir = getfield(current,"dir") + txtdir = getdir(current) elseif id == localpar_code then - pardir = getfield(current,"dir") + pardir = getdir(current) else local r = getattr(current,attribute) if r and not done[r] then @@ -501,8 +508,8 @@ local function addstring(what,str,shift) --todo make a pluggable helper (in font end local text = typesetters.tohpack(str,infofont) local rule = new_rule(emwidth/5,4*exheight,3*exheight) - setfield(text,"shift",shift) - return hpack_list(nuts.linked(text,rule)) + setshift(text,shift) + return hpack_list(setlink(text,rule)) end end end @@ -540,30 +547,30 @@ local function colorize(width,height,depth,n,reference,what,sr,offset) setattr(rule,a_transparency,u_transparency) if width < 0 then local kern = new_kern(width) - setfield(rule,"width",-width) + setwidth(rule,-width) setnext(kern,rule) setprev(rule,kern) return kern elseif sr and sr ~= "" then local text = addstring(what,sr,shift) if text then - local kern = new_kern(-getfield(text,"width")) - setlink(kern,text) - setlink(text,rule) + local kern = new_kern(-getwidth(text)) + -- setlink(kern,text) + -- setlink(text,rule) + setlink(kern,text,rule) return kern end end return rule end -local function justadd(what,sr,shift) +local function justadd(what,sr,shift,current) -- needs testing if sr and sr ~= "" then local text = addstring(what,sr,shift) if text then - local kern = new_kern(-getfield(text,"width")) - setlink(kern,text) - setlink(text,rule) - return kern + local kern = new_kern(-getwidth(text)) + setlink(kern,text,current) + return new_hlist(kern) end end end @@ -637,17 +644,12 @@ local function makereference(width,height,depth,reference) -- height and depth a end if trace_references then local step = 65536 --- result = hpack_list(colorize(width,height-step,depth-step,2,reference,"reference",texts,show_references)) -- step subtracted so that we can see seperate links --- setfield(result,"width",0) -result = new_hlist(colorize(width,height-step,depth-step,2,reference,"reference",texts,show_references)) -- step subtracted so that we can see seperate links + result = new_hlist(colorize(width,height-step,depth-step,2,reference,"reference",texts,show_references)) -- step subtracted so that we can see seperate links current = result elseif texts then - texts = justadd("reference",texts,show_references) + texts = justadd("reference",texts,show_references,current) if texts then --- result = hpack_list(texts) --- setfield(result,"width",0) -result = new_hlist(texts) - current = result + current = texts end end if current then @@ -656,11 +658,7 @@ result = new_hlist(texts) result = annot end references.registerpage(n) --- result = hpack_list(result,0) --- setfield(result,"width",0) --- setfield(result,"height",0) --- setfield(result,"depth",0) -result = new_hlist(result) + result = new_hlist(result) if cleanupreferences then stack[reference] = nil end return result, resolved elseif trace_references then @@ -757,9 +755,7 @@ local function makedestination(width,height,depth,reference) step = 4*65536 width, height, depth = 5*step, 5*step, 0 end --- local rule = hpack_list(colorize(width,height,depth,3,reference,"destination",texts,show_destinations)) --- setfield(rule,"width",0) -local rule = new_list(colorize(width,height,depth,3,reference,"destination",texts,show_destinations)) + local rule = new_hlist(colorize(width,height,depth,3,reference,"destination",texts,show_destinations)) if not result then result, current = rule, rule else @@ -768,15 +764,9 @@ local rule = new_list(colorize(width,height,depth,3,reference,"destination",text end width, height = width - step, height - step elseif texts then - texts = justadd("destination",texts,show_destinations) + texts = justadd("destination",texts,show_destinations,current) if texts then --- result = hpack_list(texts) --- if result then --- setfield(result,"width",0) --- current = result --- end -result = new_list(texts) -current = result + current = texts end end nofdestinations = nofdestinations + 1 @@ -791,12 +781,7 @@ current = result current = find_node_tail(annot) end if result then - -- some internal error --- result = hpack_list(result,0) --- setfield(result,"width",0) --- setfield(result,"height",0) --- setfield(result,"depth",0) -result = new_hlist(result) + result = new_hlist(result) end if cleanupdestinations then stack[reference] = nil end return result, resolved @@ -932,8 +917,8 @@ statistics.register("interactive elements", function() end) function references.enableinteraction() - tasks.enableaction("shipouts","nodes.references.handler") - tasks.enableaction("shipouts","nodes.destinations.handler") + enableaction("shipouts","nodes.references.handler") + enableaction("shipouts","nodes.destinations.handler") function references.enableinteraction() end end diff --git a/tex/context/base/mkiv/node-res.lua b/tex/context/base/mkiv/node-res.lua index cb06ae488..8b7ec1a62 100644 --- a/tex/context/base/mkiv/node-res.lua +++ b/tex/context/base/mkiv/node-res.lua @@ -79,14 +79,18 @@ local setchar = nuts.setchar local setlist = nuts.setlist local setwhd = nuts.setwhd local setglue = nuts.setglue +local setdisc = nuts.setdisc +local setfont = nuts.setfont +local setkern = nuts.setkern +local setpenalty = nuts.setpenalty +local setdir = nuts.setdir +local setshift = nuts.setshift +local setwidth = nuts.setwidth local copy_nut = nuts.copy local new_nut = nuts.new local flush_nut = nuts.flush -local copy_node = nodes.copy -local new_node = nodes.new - -- at some point we could have a dual set (the overhead of tonut is not much larger than -- metatable associations at the lua/c end esp if we also take assignments into account @@ -181,23 +185,26 @@ local wordboundary = register_nut(new_nut("boundary",boundarycodes.word)) -- the dir field needs to be set otherwise crash: -local rule = register_nut(new_nut("rule")) setfield(rule, "dir","TLT") -local emptyrule = register_nut(new_nut("rule",rulecodes.empty)) setfield(rule, "dir","TLT") -local userrule = register_nut(new_nut("rule",rulecodes.user)) setfield(rule, "dir","TLT") -local hlist = register_nut(new_nut("hlist")) setfield(hlist,"dir","TLT") -local vlist = register_nut(new_nut("vlist")) setfield(vlist,"dir","TLT") +local rule = register_nut(new_nut("rule")) setdir(rule, "TLT") +local emptyrule = register_nut(new_nut("rule",rulecodes.empty)) setdir(rule, "TLT") +local userrule = register_nut(new_nut("rule",rulecodes.user)) setdir(rule, "TLT") +local hlist = register_nut(new_nut("hlist")) setdir(hlist,"TLT") +local vlist = register_nut(new_nut("vlist")) setdir(vlist,"TLT") function nutpool.glyph(fnt,chr) local n = copy_nut(glyph) - if fnt then setfield(n,"font",fnt) end - if chr then setchar(n,chr) end + if fnt then + setfont(n,fnt,chr) + elseif chr then + setchar(n,chr) + end return n end function nutpool.penalty(p) local n = copy_nut(penalty) if p and p ~= 0 then - setfield(n,"penalty",p) + setpenalty(n,p) end return n end @@ -205,7 +212,7 @@ end function nutpool.kern(k) local n = copy_nut(kern) if k and k ~= 0 then - setfield(n,"kern",k) + setkern(n,k) end return n end @@ -228,39 +235,20 @@ end function nutpool.fontkern(k) local n = copy_nut(fontkern) - setfield(n,"kern",k) + if k and k ~= 0 then + setkern(n,k) + end return n end function nutpool.italickern(k) local n = copy_nut(italickern) if k and k ~= 0 then - setfield(n,"kern",k) + setkern(n,k) end return n end --- function nutpool.gluespec(width,stretch,shrink,stretch_order,shrink_order) --- -- maybe setglue --- local s = copy_nut(glue_spec) --- if width and width ~= 0 then --- setfield(s,"width",width) --- end --- if stretch and stretch ~= 0 then --- setfield(s,"stretch",stretch) --- end --- if shrink and shrink ~= 0 then --- setfield(s,"shrink",shrink) --- end --- if stretch_order and stretch_order ~= 0 then --- setfield(s,"stretch_order",stretch_order) --- end --- if shrink_order and shrink_order ~= 0 then --- setfield(s,"shrink_order",shrink_order) --- end --- return s --- end - function nutpool.gluespec(width,stretch,shrink,stretch_order,shrink_order) -- maybe setglue local s = copy_nut(glue_spec) @@ -270,27 +258,6 @@ function nutpool.gluespec(width,stretch,shrink,stretch_order,shrink_order) return s end --- local function someskip(skip,width,stretch,shrink,stretch_order,shrink_order) --- -- maybe setglue --- local n = copy_nut(skip) --- if width and width ~= 0 then --- setfield(n,"width",width) --- end --- if stretch and stretch ~= 0 then --- setfield(n,"stretch",stretch) --- end --- if shrink and shrink ~= 0 then --- setfield(n,"shrink",shrink) --- end --- if stretch_order and stretch_order ~= 0 then --- setfield(n,"stretch_order",stretch_order) --- end --- if shrink_order and shrink_order ~= 0 then --- setfield(n,"shrink_order",shrink_order) --- end --- return n --- end - local function someskip(skip,width,stretch,shrink,stretch_order,shrink_order) -- maybe setglue local n = copy_nut(skip) @@ -300,18 +267,6 @@ local function someskip(skip,width,stretch,shrink,stretch_order,shrink_order) return n end --- function nutpool.stretch(a,b) --- local n = copy_nut(glue) --- if b then --- setfield(n,"stretch",a) --- setfield(n,"stretch_order",b) --- else --- setfield(n,"stretch",1) --- setfield(n,"stretch_order",a or 1) --- end --- return n --- end - function nutpool.stretch(a,b) -- width stretch shrink stretch_order shrink_order local n = copy_nut(glue) @@ -322,18 +277,6 @@ function nutpool.stretch(a,b) return n end --- function nutpool.shrink(a,b) --- local n = copy_nut(glue) --- if b then --- setfield(n,"shrink",a) --- setfield(n,"shrink_order",b) --- else --- setfield(n,"shrink",1) --- setfield(n,"shrink_order",a or 1) --- end --- return n --- end - function nutpool.shrink(a,b) local n = copy_nut(glue) if not b then @@ -347,23 +290,6 @@ function nutpool.glue(width,stretch,shrink,stretch_order,shrink_order) return someskip(glue,width,stretch,shrink,stretch_order,shrink_order) end --- function nutpool.negatedglue(glue) --- local n = copy_nut(glue) --- local width = getfield(n,"width") --- local stretch = getfield(n,"stretch") --- local shrink = getfield(n,"shrink") --- if width and width ~= 0 then --- setfield(n,"width", -width) --- end --- if stretch and stretch ~= 0 then --- setfield(n,"stretch",-stretch) --- end --- if shrink and shrink ~= 0 then --- setfield(n,"shrink", -shrink) --- end --- return n --- end - function nutpool.negatedglue(glue) local n = copy_nut(glue) local width, stretch, shrink = getglue(n) @@ -387,13 +313,19 @@ function nutpool.baselineskip(width,stretch,shrink) return someskip(baselineskip,width,stretch,shrink) end -function nutpool.disc() - return copy_nut(disc) +function nutpool.disc(pre,post,replace) + local d = copy_nut(disc) + if pre or post or replace then + setdisc(d,pre,post,replace) + end + return d end function nutpool.textdir(dir) local t = copy_nut(textdir) - setfield(t,"dir",dir) + if dir then + setdir(t,dir) + end return t end @@ -403,7 +335,7 @@ function nutpool.rule(width,height,depth,dir) -- w/h/d == nil will let them adap setwhd(n,width,height,depth) end if dir then - setfield(n,"dir",dir) + setdir(n,dir) end return n end @@ -414,7 +346,7 @@ function nutpool.emptyrule(width,height,depth,dir) -- w/h/d == nil will let them setwhd(n,width,height,depth) end if dir then - setfield(n,"dir",dir) + setdir(n,dir) end return n end @@ -425,7 +357,7 @@ function nutpool.userrule(width,height,depth,dir) -- w/h/d == nil will let them setwhd(n,width,height,depth) end if dir then - setfield(n,"dir",dir) + setdir(n,dir) end return n end @@ -448,7 +380,7 @@ function nutpool.leftmarginkern(glyph,width) setfield(n,"glyph",glyph) end if width and width ~= 0 then - setfield(n,"width",width) + setwidth(n,width) end return n end @@ -463,7 +395,7 @@ function nutpool.rightmarginkern(glyph,width) setfield(n,"glyph",glyph) end if width and width ~= 0 then - setfield(n,"width",width) + setwidth(n,width) end return n end @@ -485,7 +417,7 @@ local function new_hlist(list,width,height,depth,shift) setwhd(n,width,height,depth) end if shift and shift ~= 0 then - setfield(n,"shift",shift) + setshift(n,shift) end return n end @@ -499,7 +431,7 @@ local function new_vlist(list,width,height,depth,shift) setwhd(n,width,height,depth) end if shift and shift ~= 0 then - setfield(n,"shift",shift) + setshift(n,shift) end return n end diff --git a/tex/context/base/mkiv/node-rul.lua b/tex/context/base/mkiv/node-rul.lua index 97100c896..8646fe447 100644 --- a/tex/context/base/mkiv/node-rul.lua +++ b/tex/context/base/mkiv/node-rul.lua @@ -19,9 +19,10 @@ if not modules then modules = { } end modules ['node-rul'] = { local attributes = attributes local nodes = nodes -local tasks = nodes.tasks local properties = nodes.properties +local enableaction = nodes.tasks.enableaction + local nuts = nodes.nuts local tonode = nuts.tonode local tonut = nuts.tonut @@ -39,6 +40,12 @@ local setattr = nuts.setattr local getfont = nuts.getfont local getsubtype = nuts.getsubtype local getlist = nuts.getlist +local setwhd = nuts.setwhd +local setdir = nuts.setdir +local setattrlist = nuts.setattrlist +local setshift = nuts.setshift +local getwidth = nuts.getwidth +local setwidth = nuts.setwidth local flushlist = nuts.flush_list local effective_glue = nuts.effective_glue @@ -58,15 +65,9 @@ local listcodes = nodes.listcodes local kerncodes = nodes.kerncodes local glyph_code = nodecodes.glyph -local disc_code = nodecodes.disc -local rule_code = nodecodes.rule -local boundary_code = nodecodes.boundary local localpar_code = nodecodes.localpar local dir_code = nodecodes.dir -local math_code = nodecodes.math local glue_code = nodecodes.glue -local penalty_code = nodecodes.penalty -local kern_code = nodecodes.kern local hlist_code = nodecodes.hlist local indent_code = listcodes.indent @@ -103,13 +104,10 @@ local v_left = variables.left local v_right = variables.right local v_local = variables["local"] local v_yes = variables.yes -local v_all = variables.all local v_foreground = variables.foreground local fonthashes = fonts.hashes local fontdata = fonthashes.identifiers -local fontunicodes = fonthashes.unicodes -local fontcharacters = fonthashes.characters local fontresources = fonthashes.resources local dimenfactor = fonts.helpers.dimenfactor @@ -139,7 +137,7 @@ local function userrule(t,noattributes) if noattributes == false or noattributes == nil then -- avoid fuzzy ones else - setfield(r,"attr",current_attr()) + setattrlist(r,current_attr()) end properties[r] = t return tonode(r) @@ -349,14 +347,9 @@ rules.handler = function(head) end function rules.enable() - tasks.enableaction("shipouts","nodes.rules.handler") + enableaction("shipouts","nodes.rules.handler") end --- elsewhere: --- --- tasks.appendaction ("shipouts", "normalizers", "nodes.rules.handler") --- tasks.disableaction("shipouts", "nodes.rules.handler") -- only kick in when used - local trace_shifted = false trackers.register("nodes.shifting", function(v) trace_shifted = v end) local report_shifted = logs.reporter("nodes","shifting") @@ -384,7 +377,7 @@ local function flush_shifted(head,first,last,data,level,parent,strip) -- not tha setprev(first) setnext(last) local width, height, depth = list_dimensions(parent,first,next) - local list = hpack_nodes(first,width,"exactly") + local list = hpack_nodes(first,width,"exactly") -- we can use a simple pack if first == head then head = list end @@ -395,9 +388,8 @@ local function flush_shifted(head,first,last,data,level,parent,strip) -- not tha setlink(list,next) end local raise = data.dy * dimenfactor(data.unit,fontdata[getfont(first)]) - setfield(list,"shift",raise) - setfield(list,"height",height) - setfield(list,"depth",depth) + setshift(list,raise) + setwhd(list,width,height,depth) if trace_shifted then report_shifted("width %p, nodes %a, text %a",width,n_tostring(first,last),n_tosequence(first,last,true)) end @@ -409,7 +401,7 @@ local process = nodes.processwords nodes.shifts.handler = function(head) return process(a_shifted,data,flush_shifted,head) end function nodes.shifts.enable() - tasks.enableaction("shipouts","nodes.shifts.handler") + enableaction("shipouts","nodes.shifts.handler") end -- linefillers @@ -445,7 +437,7 @@ local function linefiller(current,data,width,location) ca = ca, ta = ta, option = location, - direction = getfield(current,"dir"), + direction = getdir(current), }) else local linefiller = new_rule(width,height,depth) @@ -471,6 +463,7 @@ local function find_attr(head,attr) end function nodes.linefillers.handler(head) +-- local current = tonut(head) -- when we hook into the contributers for current in traverse_id(hlist_code,tonut(head)) do if getsubtype(current) == line_code then local list = getlist(current) @@ -523,16 +516,16 @@ function nodes.linefillers.handler(head) head = getnext(head) end if head then - local indentation = iskip and getfield(iskip,"width") or 0 - local leftfixed = lskip and getfield(lskip,"width") or 0 + local indentation = iskip and getwidth(iskip) or 0 + local leftfixed = lskip and getwidth(lskip) or 0 local lefttotal = lskip and effective_glue(lskip,current) or 0 local width = lefttotal - (leftlocal and leftfixed or 0) + indentation - distance if width > threshold then if iskip then - setfield(iskip,"width",0) + setwidth(iskip,0) end if lskip then - setglue(lskip,leftlocal and getfield(lskip,"width") or nil) + setglue(lskip,leftlocal and getwidth(lskip) or nil) if distance > 0 then insert_node_after(list,lskip,new_kern(distance)) end @@ -563,9 +556,9 @@ function nodes.linefillers.handler(head) tail = getprev(tail) end if tail then - local rightfixed = rskip and getfield(rskip,"width") or 0 + local rightfixed = rskip and getwidth(rskip) or 0 local righttotal = rskip and effective_glue(rskip,current) or 0 - local parfixed = pskip and getfield(pskip,"width") or 0 + local parfixed = pskip and getwidth(pskip) or 0 local partotal = pskip and effective_glue(pskip,current) or 0 local width = righttotal - (rightlocal and rightfixed or 0) + partotal - distance if width > threshold then @@ -573,7 +566,7 @@ function nodes.linefillers.handler(head) setglue(pskip) end if rskip then - setglue(rskip,rightlocal and getfield(rskip,"width") or nil) + setglue(rskip,rightlocal and getwidth(rskip) or nil) if distance > 0 then insert_node_before(list,rskip,new_kern(distance)) end @@ -600,7 +593,7 @@ local enable = false function nodes.linefillers.enable() if not enable then -- we could now nil it - tasks.enableaction("finalizers","nodes.linefillers.handler") + enableaction("finalizers","nodes.linefillers.handler") enable = true end end diff --git a/tex/context/base/mkiv/node-ser.lua b/tex/context/base/mkiv/node-ser.lua index 847db7a15..f1be21f84 100644 --- a/tex/context/base/mkiv/node-ser.lua +++ b/tex/context/base/mkiv/node-ser.lua @@ -26,7 +26,6 @@ local nodecodes = nodes.nodecodes local subtcodes = nodes.codes local noadcodes = nodes.noadcodes local getfields = nodes.fields -local nodekeys = nodes.keys local tonode = nodes.tonode diff --git a/tex/context/base/mkiv/node-tra.lua b/tex/context/base/mkiv/node-tra.lua index b3b4311e7..0d3192559 100644 --- a/tex/context/base/mkiv/node-tra.lua +++ b/tex/context/base/mkiv/node-tra.lua @@ -47,10 +47,14 @@ local getsubtype = nuts.getsubtype local getlist = nuts.getlist local getdisc = nuts.getdisc local setattr = nuts.setattr +local getglue = nuts.getglue local isglyph = nuts.isglyph +local getcomponents = nuts.getcomponents +local getdir = nuts.getdir +local getwidth = nuts.getwidth local flush_list = nuts.flush_list -local count_nodes = nuts.count +local count_nodes = nuts.countall local used_nodes = nuts.usedlist local traverse_by_id = nuts.traverse_id @@ -121,6 +125,7 @@ function nodes.handlers.checkforleaks(sparse) end local f_sequence = formatters["U+%04X:%s"] +local f_subrange = formatters["[[ %s ][ %s ][ %s ]]"] local function tosequence(start,stop,compact) if start then @@ -131,7 +136,7 @@ local function tosequence(start,stop,compact) local c, id = isglyph(start) if c then if compact then - local components = getfield(start,"components") + local components = getcomponents(start) if components then t[#t+1] = tosequence(components,nil,compact) else @@ -140,6 +145,9 @@ local function tosequence(start,stop,compact) else t[#t+1] = f_sequence(c,utfchar(c)) end + elseif id == disc_code then + local pre, post, replace = getdisc(start) + t[#t+1] = f_subrange(pre and tosequence(pre),post and tosequence(post),replace and tosequence(replace)) elseif id == rule_code then if compact then t[#t+1] = "|" @@ -147,7 +155,7 @@ local function tosequence(start,stop,compact) t[#t+1] = nodecodes[id] end elseif id == dir_code or id == localpar_code then - t[#t+1] = "[" .. getfield(start,"dir") .. "]" + t[#t+1] = "[" .. getdir(start) .. "]" elseif compact then t[#t+1] = "[]" else @@ -310,7 +318,7 @@ local function listtoutf(h,joiner,textonly,last,nodisc) end elseif textonly then if id == glue_code then - if getfield(h,"width") > 0 then + if getwidth(h) > 0 then w[#w+1] = " " end elseif id == hlist_code or id == vlist_code then @@ -375,7 +383,7 @@ local function nodetodimen(n) n = tonut(n) local id = getid(n) if id == kern_code then - local width = getfield(n,"width") + local width = getwidth(n) if width == 0 then return "0pt" else @@ -384,11 +392,10 @@ local function nodetodimen(n) elseif id ~= glue_code then return "0pt" end - local stretch_order = getfield(n,"stretch_order") - local shrink_order = getfield(n,"shrink_order") - local stretch = getfield(n,"stretch") / 65536 - local shrink = getfield(n,"shrink") / 65536 - local width = getfield(n,"width") / 65536 + local width, stretch, shrink, stretch_order, shrink_order = getglue(n) + stretch = stretch / 65536 + shrink = shrink / 65536 + width = width / 65536 if stretch_order ~= 0 then if shrink_order ~= 0 then return f_f_f(width,stretch,fillorders[stretch_order],shrink,fillorders[shrink_order]) diff --git a/tex/context/base/mkiv/node-tsk.lua b/tex/context/base/mkiv/node-tsk.lua index 56a4b18ef..4dcbb27bd 100644 --- a/tex/context/base/mkiv/node-tsk.lua +++ b/tex/context/base/mkiv/node-tsk.lua @@ -30,6 +30,20 @@ local sequencers = utilities.sequencers local compile = sequencers.compile local nodeprocessor = sequencers.nodeprocessor +local newsequencer = sequencers.new + +local appendgroup = sequencers.appendgroup +----- prependgroup = sequencers.prependgroup +----- replacegroup = sequencers.replacegroup +local enablegroup = sequencers.enablegroup +local disablegroup = sequencers.disablegroup + +local appendaction = sequencers.appendaction +local prependaction = sequencers.prependaction +local replaceaction = sequencers.replaceaction +local enableaction = sequencers.enableaction +local disableaction = sequencers.disableaction + local frozengroups = "no" function tasks.freeze(kind) @@ -41,7 +55,7 @@ function tasks.new(specification) -- was: name,arguments,list local arguments = specification.arguments or 0 local sequence = specification.sequence if name and sequence then - local tasklist = sequencers.new { + local tasklist = newsequencer { -- we can move more to the sequencer now .. todo } tasksdata[name] = { @@ -53,7 +67,7 @@ function tasks.new(specification) -- was: name,arguments,list processor = specification.processor or nodeprocessor } for l=1,#sequence do - sequencers.appendgroup(tasklist,sequence[l]) + appendgroup(tasklist,sequence[l]) end end end @@ -104,7 +118,7 @@ end function tasks.enableaction(name,action) local data = valid(name) if data then - sequencers.enableaction(data.list,action) + enableaction(data.list,action) data.runner = false end end @@ -112,7 +126,7 @@ end function tasks.disableaction(name,action) local data = valid(name) if data then - sequencers.disableaction(data.list,action) + disableaction(data.list,action) data.runner = false end end @@ -120,23 +134,30 @@ end function tasks.replaceaction(name,group,oldaction,newaction) local data = valid(name) if data then - sequencers.replaceaction(data.list,group,oldaction,newaction) + replaceaction(data.list,group,oldaction,newaction) data.runner = false end end -function tasks.setaction(name,action,value) - if value then - tasks.enableaction(name,action) - else - tasks.disableaction(name,action) +do + + local enableaction = tasks.enableaction + local disableaction = tasks.disableaction + + function tasks.setaction(name,action,value) + if value then + enableaction(name,action) + else + disableaction(name,action) + end end + end function tasks.enablegroup(name,group) local data = validgroup(name,"enable group") if data then - sequencers.enablegroup(data.list,group) + enablegroup(data.list,group) data.runner = false end end @@ -144,7 +165,7 @@ end function tasks.disablegroup(name,group) local data = validgroup(name,"disable group") if data then - sequencers.disablegroup(data.list,group) + disablegroup(data.list,group) data.runner = false end end @@ -152,7 +173,7 @@ end function tasks.appendaction(name,group,action,where,kind) local data = validgroup(name,"append action") if data then - sequencers.appendaction(data.list,group,action,where,kind) + appendaction(data.list,group,action,where,kind) data.runner = false end end @@ -160,7 +181,7 @@ end function tasks.prependaction(name,group,action,where,kind) local data = validgroup(name,"prepend action") if data then - sequencers.prependaction(data.list,group,action,where,kind) + prependaction(data.list,group,action,where,kind) data.runner = false end end @@ -168,7 +189,7 @@ end function tasks.removeaction(name,group,action) local data = validgroup(name,"remove action") if data then - sequencers.removeaction(data.list,group,action) + removeaction(data.list,group,action) data.runner = false end end @@ -366,6 +387,7 @@ tasks.new { tasks.new { name = "shipouts", arguments = 0, + -- nostate = true, -- maybe but only for main ones so little gain processor = nodeprocessor, sequence = { "before", -- for users @@ -418,3 +440,15 @@ tasks.new { -- "after", -- for users -- } -- } + +tasks.new { + name = "contributers", + arguments = 1, + processor = nodeprocessor, + sequence = { + "before", -- for users + "normalizers", + "after", -- for users + } +} + diff --git a/tex/context/base/mkiv/node-tst.lua b/tex/context/base/mkiv/node-tst.lua index 4832c048c..1109f28a3 100644 --- a/tex/context/base/mkiv/node-tst.lua +++ b/tex/context/base/mkiv/node-tst.lua @@ -32,6 +32,9 @@ local getprev = nuts.getprev local getid = nuts.getid local getchar = nuts.getchar local getsubtype = nuts.getsubtype +local getkern = nuts.getkern +local getpenalty = nuts.getpenalty +local getwidth = nuts.getwidth local find_node_tail = nuts.tail @@ -39,11 +42,11 @@ function nuts.leftmarginwidth(n) -- todo: three values while n do local id = getid(n) if id == glue_code then - return getsubtype(n) == leftskip_code and getfield(n,"width") or 0 + return getsubtype(n) == leftskip_code and getwidth(n) or 0 elseif id == whatsit_code then n = getnext(n) elseif id == hlist_code then - return getfield(n,"width") + return getwidth(n) else break end @@ -57,7 +60,7 @@ function nuts.rightmarginwidth(n) while n do local id = getid(n) if id == glue_code then - return getsubtype(n) == rightskip_code and getfield(n,"width") or 0 + return getsubtype(n) == rightskip_code and getwidth(n) or 0 elseif id == whatsit_code then n = getprev(n) else @@ -72,10 +75,9 @@ function nuts.somespace(n,all) if n then local id = getid(n) if id == glue_code then - return (all or ((getfield(n,"width") or 0) ~= 0)) and glue_code -- temp: or 0 - -- return (all or (getfield(n,"width") ~= 0)) and glue_code + return (all or (getwidth(n) ~= 0)) and glue_code -- temp: or 0 elseif id == kern_code then - return (all or (getfield(n,"kern") ~= 0)) and kern + return (all or (getkern(n) ~= 0)) and kern elseif id == glyph_code then local category = chardata[getchar(n)].category -- maybe more category checks are needed @@ -90,7 +92,7 @@ function nuts.somepenalty(n,value) local id = getid(n) if id == penalty_code then if value then - return getfield(n,"penalty") == value + return getpenalty(n) == value else return true end diff --git a/tex/context/base/mkiv/node-typ.lua b/tex/context/base/mkiv/node-typ.lua index efabe657b..06d0f13c2 100644 --- a/tex/context/base/mkiv/node-typ.lua +++ b/tex/context/base/mkiv/node-typ.lua @@ -18,6 +18,7 @@ local tonut = nuts.tonut local setfield = nuts.setfield local setlink = nuts.setlink local setchar = nuts.setchar +----- setattrlist = nuts.setattrlist local getfield = nuts.getfield local getfont = nuts.getfont @@ -42,7 +43,7 @@ local function tonodes(str,fontid,spacing,templateglyph) -- quick and dirty if not fontid then if templateglyph then fontid = getfont(templateglyph) - -- attrid = getfield(templateglyph,"attr") + -- attrid = setattrlist(templateglyph) else fontid = currentfont() -- attrid = current_attr() @@ -74,10 +75,10 @@ local function tonodes(str,fontid,spacing,templateglyph) -- quick and dirty if not next then -- nothing elseif not head then --- setfield(next,"attr",attrid) + -- setattrlist(next,attrid) head = next else --- setfield(next,"attr",attrid) + -- setattrlist(next,attrid) setlink(prev,next) end prev = next diff --git a/tex/context/base/mkiv/pack-rul.lua b/tex/context/base/mkiv/pack-rul.lua index 3279dca51..30eda7dd2 100644 --- a/tex/context/base/mkiv/pack-rul.lua +++ b/tex/context/base/mkiv/pack-rul.lua @@ -11,8 +11,6 @@ if not modules then modules = { } end modules ['pack-rul'] = { --ldx]]-- -- we need to be careful with display math as it uses shifts --- challenge: adapt glue_set --- setfield(h,"glue_set", getfield(h,"glue_set") * getfield(h,"width")/maxwidth -- interesting ... doesn't matter much -- \framed[align={lohi,middle}]{$x$} -- \framed[align={lohi,middle}]{$ $} @@ -45,6 +43,10 @@ local getwhd = nuts.getwhd local getid = nuts.getid local getsubtype = nuts.getsubtype local getbox = nuts.getbox +local getdir = nuts.getdir +local setshift = nuts.setshift +local setwidth = nuts.setwidth +local getwidth = nuts.getwidth local hpack = nuts.hpack local traverse_id = nuts.traverse_id @@ -68,7 +70,7 @@ local function doreshapeframedbox(n) local maxwidth = 0 local totalwidth = 0 local averagewidth = 0 - local boxwidth = getfield(box,"width") + local boxwidth = getwidth(box) if boxwidth ~= 0 then -- and h.subtype == vlist_code local list = getlist(box) if list then @@ -84,7 +86,7 @@ local function doreshapeframedbox(n) if repack then local subtype = getsubtype(n) if subtype == box_code or subtype == line_code then - lastlinelength = list_dimensions(l,getfield(n,"dir")) + lastlinelength = list_dimensions(l,getdir(n)) else lastlinelength = width end @@ -122,7 +124,7 @@ local function doreshapeframedbox(n) if l then local subtype = getsubtype(h) if subtype == box_code or subtype == line_code then - local p = hpack(l,maxwidth,'exactly',getfield(h,"dir")) -- multiple return value + local p = hpack(l,maxwidth,'exactly',getdir(h)) -- multiple return value setfield(h,"glue_set",getfield(p,"glue_set")) setfield(h,"glue_order",getfield(p,"glue_order")) setfield(h,"glue_sign",getfield(p,"glue_sign")) @@ -131,25 +133,25 @@ local function doreshapeframedbox(n) elseif checkformath and subtype == equation_code then -- display formulas use a shift if nofnonzero == 1 then - setfield(h,"shift",0) + setshift(h,0) end end - setfield(h,"width",maxwidth) + setwidth(h,maxwidth) end end end -- if vdone then -- for v in traverse_id(vlist_code,list) do - -- local width = getfield(n,"width") + -- local width = getwidth(n) -- if width > maxwidth then - -- setfield(v,"width",maxwidth) + -- setwidth(v,maxwidth) -- end -- end -- end - setfield(box,"width",maxwidth) + setwidth(box,maxwidth) averagewidth = noflines > 0 and totalwidth/noflines or 0 else -- e.g. empty math {$ $} or \hbox{} or ... - setfield(box,"width",0) + setwidth(box,0) end end end @@ -166,7 +168,7 @@ local function doanalyzeframedbox(n) local noflines = 0 local firstheight = nil local lastdepth = nil - if getfield(box,"width") ~= 0 then + if getwidth(box) ~= 0 then local list = getlist(box) if list then local function check(n) @@ -194,7 +196,7 @@ implement { name = "doreshapeframedbox", actions = doreshapeframedbox, arguments implement { name = "doanalyzeframedbox", actions = doanalyzeframedbox, arguments = "integer" } local function maxboxwidth(box) - local boxwidth = getfield(box,"width") + local boxwidth = getwidth(box) if boxwidth == 0 then return 0 end @@ -213,12 +215,12 @@ local function maxboxwidth(box) if repack then local subtype = getsubtype(n) if subtype == box_code or subtype == line_code then - lastlinelength = list_dimensions(l,getfield(n,"dir")) + lastlinelength = list_dimensions(l,getdir(n)) else - lastlinelength = getfield(n,"width") + lastlinelength = getwidth(n) end else - lastlinelength = getfield(n,"width") + lastlinelength = getwidth(n) end if lastlinelength > maxwidth then maxwidth = lastlinelength @@ -238,6 +240,6 @@ nodes.maxboxwidth = maxboxwidth implement { name = "themaxboxwidth", - actions = function(n) context("%isp",maxboxwidth(getbox(n))) end, + actions = function(n) context("%rsp",maxboxwidth(getbox(n))) end, -- r = rounded arguments = "integer" } diff --git a/tex/context/base/mkiv/page-cst.lua b/tex/context/base/mkiv/page-cst.lua index cd3b63c5d..03707a312 100644 --- a/tex/context/base/mkiv/page-cst.lua +++ b/tex/context/base/mkiv/page-cst.lua @@ -52,6 +52,10 @@ local setsubtype = nuts.setsubtype local setbox = nuts.setbox local getwhd = nuts.getwhd local setwhd = nuts.setwhd +local getkern = nuts.getkern +local getpenalty = nuts.getpenalty +local getwidth = nuts.getwidth +local getheight = nuts.getheight local getnext = nuts.getnext local getprev = nuts.getprev @@ -337,11 +341,7 @@ function columnsets.prepareflush(name) for r=1,nofrows-1 do setlink(column[r],column[r+1]) end - local v = new_vlist(column[1]) - setfield(v,"height",height) - -- setfield(v,"depth",linedepth) - setfield(v,"width",widths[c]) - columns[c] = v + columns[c] = new_vlist(column[1],widths[c],height,0) -- linedepth end -- texsetcount("c_page_grid_first_column",firstcolumn) @@ -774,9 +774,9 @@ end -- if line then -- break -- end --- used = used + getfield(head,"width") +-- used = used + getwidth(head) -- elseif id == kern_code then --- used = used + getfield(head,"kern") +-- used = used + getkern(head) -- elseif id == penalty_code then -- end -- if used > available then @@ -813,18 +813,18 @@ local function checkroom(head,available,row) if line then break end - used = used + getfield(head,"width") + used = used + getwidth(head) if used > available then break end elseif id == kern_code then - used = used + getfield(head,"kern") + used = used + getkern(head) if used > available then break end elseif id == penalty_code then -- not good enough ... we need to look bakck too - if getfield(head,"penalty") >= 10000 then + if getpenalty(head) >= 10000 then line = false else break @@ -862,9 +862,9 @@ end -- if id == hlist_code or id == vlist_code or id == rule_code then -- <= rule_code -- hd = getfield(head,"height") + getfield(head,"depth") -- elseif id == glue_code then --- hd = getfield(head,"width") +-- hd = getwidth(head) -- elseif id == kern_code then --- hd = getfield(head,"kern") +-- hd = getkern(head) -- elseif id == penalty_code then -- end -- if used + hd > available then @@ -919,7 +919,7 @@ local function findslice(dataset,head,available,column,row) attempts = attempts + 1 texsetbox("scratchbox",tonode(new_vlist(copy))) local done = splitbox("scratchbox",usedsize,"additional") - local used = getfield(done,"height") + local used = getheight(done) local rest = takebox("scratchbox") if used > (usedsize+slack) then if trace_detail then @@ -943,7 +943,7 @@ local function findslice(dataset,head,available,column,row) texsetbox("scratchbox",tonode(new_vlist(head))) done = splitbox("scratchbox",usedsize,"additional") rest = takebox("scratchbox") - used = getfield(done,"height") + used = getheight(done) if attempts > 1 then used = available end @@ -1237,9 +1237,7 @@ function columnsets.setarea(t) local column = t.c local row = t.r if column and row then - setfield(box,"height",dataset.lineheight) - setfield(box,"depth",dataset.linedepth) - setfield(box,"width",dataset.widths[column]) + setwhd(box,dataset.widths[column],dataset.lineheight,dataset.linedepth) cells[column][row] = box end end diff --git a/tex/context/base/mkiv/page-ins.mkiv b/tex/context/base/mkiv/page-ins.mkiv index c91073a14..51f2a3c1c 100644 --- a/tex/context/base/mkiv/page-ins.mkiv +++ b/tex/context/base/mkiv/page-ins.mkiv @@ -55,7 +55,7 @@ \unexpanded\def\page_inserts_synchronize_registers {\currentinsertionnumber\csname\??insertionnumber\currentinsertion\endcsname} -% for practical reasone we still set these elsewhere but that might chaneg in the future +% for practical reasons we still set these elsewhere but that might change in the future % % \global\count\currentinsertionnumber\numexpr\insertionparameter\c!factor/\insertionparameter\c!n\relax % \global\skip \currentinsertionnumber\insertionparameter\c!distance \relax @@ -65,7 +65,7 @@ \page_inserts_synchronize_registers \to \everysetupinsertion -\unexpanded\def\page_inserts_process#1% beware, this addapts currentinsertion ! +\unexpanded\def\page_inserts_process#1% beware, this adapts currentinsertion ! {\edef\currentinsertion{#1}% \currentinsertionnumber\csname\??insertionnumber\currentinsertion\endcsname \doprocessinsert\currentinsertionnumber} % old method diff --git a/tex/context/base/mkiv/page-lin.lua b/tex/context/base/mkiv/page-lin.lua index 011418063..8ec4ba5df 100644 --- a/tex/context/base/mkiv/page-lin.lua +++ b/tex/context/base/mkiv/page-lin.lua @@ -56,7 +56,7 @@ local line_code = listcodes.line local a_displaymath = attributes.private('displaymath') local a_linenumber = attributes.private('linenumber') local a_linereference = attributes.private('linereference') -local a_verbatimline = attributes.private('verbatimline') +----- a_verbatimline = attributes.private('verbatimline') local current_list = { } local cross_references = { } @@ -72,6 +72,10 @@ local setattr = nuts.setattr local getlist = nuts.getlist local getbox = nuts.getbox local getfield = nuts.getfield +----- getdir = nuts.getdir +----- getwidth = nuts.getwidth +local getheight = nuts.getheight +local getdepth = nuts.getdepth local setprop = nuts.setprop local getprop = nuts.getprop @@ -386,7 +390,7 @@ function boxed.stage_one(n,nested) local subtype = getsubtype(n) if subtype ~= line_code then -- go on - elseif getfield(n,"height") == 0 and getfield(n,"depth") == 0 then + elseif getheight(n) == 0 and getdepth(n) == 0 then -- skip funny hlists -- todo: check line subtype else local a = lineisnumbered(n) @@ -410,14 +414,14 @@ function boxed.stage_one(n,nested) check_number(n,a,skip) end else --- -- we now prevent nesting anyway .. maybe later we need to check again --- local v = getattr(list,a_verbatimline) --- if not v or v ~= last_v then --- last_v = v + -- -- we now prevent nesting anyway .. maybe later we need to check again + -- local v = getattr(list,a_verbatimline) + -- if not v or v ~= last_v then + -- last_v = v check_number(n,a,skip) --- else --- check_number(n,a,skip,true) --- end + -- else + -- check_number(n,a,skip,true) + -- end end skip = false end @@ -480,10 +484,10 @@ function boxed.stage_two(n,m) local li = current_list[i] local n, m, ti = li[1], li[2], t[i] if ti then - -- local d = getfield(n,"dir") + -- local d = getdir(n) -- local l = getlist(n) -- if d == "TRT" then - -- local w = getfield(n,"width") + -- local w = getwidth(n) -- ti = hpack_nodes(linked_nodes(new_kern(-w),ti,new_kern(w))) -- end -- setnext(ti,l) diff --git a/tex/context/base/mkiv/page-mix.lua b/tex/context/base/mkiv/page-mix.lua index 6bbc434dd..524181c8e 100644 --- a/tex/context/base/mkiv/page-mix.lua +++ b/tex/context/base/mkiv/page-mix.lua @@ -47,14 +47,17 @@ local flushnode = nuts.flush local concatnodes = nuts.concat local slidenodes = nuts.slide -- ok here as we mess with prev links intermediately -local getfield = nuts.getfield local setfield = nuts.setfield local setlink = nuts.setlink local setlist = nuts.setlist local setnext = nuts.setnext local setprev = nuts.setprev local setbox = nuts.setbox +local setwhd = nuts.setwhd +local setheight = nuts.setheight +local setdepth = nuts.setdepth +local getfield = nuts.getfield local getnext = nuts.getnext local getprev = nuts.getprev local getid = nuts.getid @@ -63,10 +66,11 @@ local getsubtype = nuts.getsubtype local getbox = nuts.getbox local getattribute = nuts.getattribute local getwhd = nuts.getwhd -local setwhd = nuts.setwhd - -local texgetcount = tex.getcount -local texgetglue = tex.getglue +local getkern = nuts.getkern +local getpenalty = nuts.getpenalty +local getwidth = nuts.getwidth +local getheight = nuts.getheight +local getdepth = nuts.getdepth local theprop = nuts.theprop @@ -119,7 +123,7 @@ local function collectinserts(result,nxt,nxtid) if nxtid == insert_code then i = i + 1 result.i = i - inserttotal = inserttotal + getfield(nxt,"height") -- height includes depth + inserttotal = inserttotal + getheight(nxt) -- height includes depth local s = getsubtype(nxt) local c = inserts[s] if trace_detail then @@ -172,15 +176,15 @@ local function discardtopglue(current,discarded) while current do local id = getid(current) if id == glue_code then - size = size + getfield(current,"width") + size = size + getwidth(current) discarded[#discarded+1] = current current = getnext(current) elseif id == penalty_code then - if getfield(current,"penalty") == forcedbreak then + if getpenalty(current) == forcedbreak then discarded[#discarded+1] = current current = getnext(current) while current and getid(current) == glue_code do - size = size + getfield(current,"width") + size = size + getwidth(current) discarded[#discarded+1] = current current = getnext(current) end @@ -210,7 +214,7 @@ local function stripbottomglue(results,discarded) end local id = getid(t) if id == penalty_code then - if getfield(t,"penalty") == forcedbreak then + if getpenalty(t) == forcedbreak then break else discarded[#discarded+1] = t @@ -219,7 +223,7 @@ local function stripbottomglue(results,discarded) end elseif id == glue_code then discarded[#discarded+1] = t - local width = getfield(t,"width") + local width = getwidth(t) if trace_state then report_state("columns %s, discarded bottom glue %p",i,width) end @@ -256,8 +260,8 @@ local function preparesplit(specification) -- a rather large function slidenodes(head) -- we can have set prev's to nil to prevent backtracking local discarded = { } local originalhead = head - local originalwidth = specification.originalwidth or getfield(list,"width") - local originalheight = specification.originalheight or getfield(list,"height") + local originalwidth = specification.originalwidth or getwidth(list) + local originalheight = specification.originalheight or getheight(list) local current = head local skipped = 0 local height = 0 @@ -480,7 +484,7 @@ local function preparesplit(specification) -- a rather large function head = current local function process_skip(current,nxt) - local advance = getfield(current,"width") + local advance = getwidth(current) if advance ~= 0 then local state, skipped = checked(advance,"glue") if trace_state then @@ -515,7 +519,7 @@ local function preparesplit(specification) -- a rather large function end local function process_kern(current,nxt) - local advance = getfield(current,"kern") + local advance = getkern(current) if advance ~= 0 then local state, skipped = checked(advance,"kern") if trace_state then @@ -538,7 +542,7 @@ local function preparesplit(specification) -- a rather large function local function process_rule(current,nxt) -- simple variant of h|vlist - local advance = getfield(current,"height") -- + getfield(current,"depth") + local advance = getheight(current) -- + getdepth(current) if advance ~= 0 then local state, skipped = checked(advance,"rule") if trace_state then @@ -556,7 +560,7 @@ local function preparesplit(specification) -- a rather large function -- else -- height = height + currentskips -- end - depth = getfield(current,"depth") + depth = getdepth(current) skip = 0 end lastcontent = current @@ -569,7 +573,7 @@ local function preparesplit(specification) -- a rather large function -- [chapter] [penalty] [section] [penalty] [first line] local function process_penalty(current,nxt) - local penalty = getfield(current,"penalty") + local penalty = getpenalty(current) if penalty == 0 then unlock(penalty) elseif penalty == forcedbreak then @@ -783,11 +787,11 @@ local function finalize(result) local l = list[i] local h = new_hlist() t[i] = h - setlist(h,getfield(l,"head")) + setlist(h,getlist(l)) local wd, ht, dp = getwhd(l) -- here ht is still ht + dp ! - setwhd(h,getfield(h,"width"),ht,dp) - setfield(l,"head",nil) + setwhd(h,getwidth(h),ht,dp) + setlist(l) end setprev(t[1]) -- needs checking setnext(t[#t]) -- needs checking @@ -946,9 +950,7 @@ local function getsplit(result,n) dp = result.depth end - setfield(v,"width",wd) - setfield(v,"height",ht) - setfield(v,"depth",dp) + setwhd(v,wd,ht,dp) if trace_state then local id = getid(h) @@ -962,9 +964,9 @@ local function getsplit(result,n) for c, list in next, r.inserts do local l = concatnodes(list) -for i=1,#list-1 do - setfield(list[i],"depth",0) -end + for i=1,#list-1 do + setdepth(list[i],0) + end local b = vpack(l) -- multiple arguments, todo: fastvpack -- setbox("global",c,b) diff --git a/tex/context/base/mkiv/page-str.lua b/tex/context/base/mkiv/page-str.lua index a254e9d7d..4aeffffd8 100644 --- a/tex/context/base/mkiv/page-str.lua +++ b/tex/context/base/mkiv/page-str.lua @@ -28,6 +28,8 @@ local vpack_node_list = nodes.vpack local settings_to_array = utilities.parsers.settings_to_array +local enableaction = nodes.tasks.enableaction + local texgetdimen = tex.getdimen local texgetbox = tex.getbox @@ -233,7 +235,7 @@ tasks.appendaction("mvlbuilders", "normalizers", "streams.collect") tasks.disableaction("mvlbuilders", "streams.collect") function streams.initialize() - tasks.enableaction ("mvlbuilders", "streams.collect") + enableaction("mvlbuilders","streams.collect") function streams.initialize() end end @@ -241,8 +243,8 @@ end -- todo: better names, enable etc implement { - name = "initializestream", - actions = streams.initialize, + name = "initializestream", + actions = streams.initialize, onlyonce = true, } diff --git a/tex/context/base/mkiv/publ-sor.lua b/tex/context/base/mkiv/publ-sor.lua index 218d11093..30a0d9bdd 100644 --- a/tex/context/base/mkiv/publ-sor.lua +++ b/tex/context/base/mkiv/publ-sor.lua @@ -217,6 +217,7 @@ local function sortsequence(dataset,list,sorttype) if type(action) == "function" then local valid = action(dataset,list,method) if valid and #valid > 0 then +-- sorters.setlanguage(options.language,options.method) sorters.sort(valid,compare) return valid else diff --git a/tex/context/base/mkiv/scrn-fld.mkvi b/tex/context/base/mkiv/scrn-fld.mkvi index a92abebc5..d69e7beb9 100644 --- a/tex/context/base/mkiv/scrn-fld.mkvi +++ b/tex/context/base/mkiv/scrn-fld.mkvi @@ -246,7 +246,6 @@ \fi layer {\fieldbodyparameter\c!fieldlayer}% option {\fieldbodyparameter\c!option}% - align {\fieldbodyparameter\c!align}% clickin {\fieldbodyparameter\c!clickin}% clickout {\fieldbodyparameter\c!clickout}% regionin {\fieldbodyparameter\c!regionin}% diff --git a/tex/context/base/mkiv/scrp-cjk.lua b/tex/context/base/mkiv/scrp-cjk.lua index b919098f1..d2ec201ca 100644 --- a/tex/context/base/mkiv/scrp-cjk.lua +++ b/tex/context/base/mkiv/scrp-cjk.lua @@ -31,6 +31,7 @@ local getchar = nuts.getchar local getid = nuts.getid local getattr = nuts.getattr local getsubtype = nuts.getsubtype +local getwidth = nuts.getwidth local getfield = nuts.getfield local setchar = nuts.setchar @@ -958,7 +959,7 @@ local function process(head,first,last) local subtype = getsubtype(first) if subtype == userskip_code or subtype == spaceskip_code or subtype == xspaceskip_code then -- for the moment no distinction possible between space and userskip - local w = getfield(first,"width") + local w = getwidth(first) local s = spacedata[getfont(p)] if w == s then -- could be option if trace_details then diff --git a/tex/context/base/mkiv/spac-adj.lua b/tex/context/base/mkiv/spac-adj.lua index bebc15b88..3db59881b 100644 --- a/tex/context/base/mkiv/spac-adj.lua +++ b/tex/context/base/mkiv/spac-adj.lua @@ -8,15 +8,17 @@ if not modules then modules = { } end modules ['spac-adj'] = { -- sort of obsolete code -local a_vadjust = attributes.private('graphicvadjust') +local a_vadjust = attributes.private('graphicvadjust') -local nodecodes = nodes.nodecodes +local nodecodes = nodes.nodecodes -local hlist_code = nodecodes.hlist -local vlist_code = nodecodes.vlist +local hlist_code = nodecodes.hlist +local vlist_code = nodecodes.vlist -local remove_node = nodes.remove -local hpack_node = node.hpack +local remove_node = nodes.remove +local hpack_node = node.hpack + +local enableaction = nodes.tasks.enableaction function nodes.handlers.graphicvadjust(head,groupcode) -- we can make an actionchain for mvl only if groupcode == "" then -- mvl only @@ -60,6 +62,6 @@ interfaces.implement { name = "enablegraphicvadjust", onlyonce = true, actions = function() - nodes.tasks.enableaction("finalizers","nodes.handlers.graphicvadjust") + enableaction("finalizers","nodes.handlers.graphicvadjust") end } diff --git a/tex/context/base/mkiv/spac-ali.lua b/tex/context/base/mkiv/spac-ali.lua index dc206a2a2..bc77090cf 100644 --- a/tex/context/base/mkiv/spac-ali.lua +++ b/tex/context/base/mkiv/spac-ali.lua @@ -19,18 +19,18 @@ local tonode = nuts.tonode local tonut = nuts.tonut local getfield = nuts.getfield -local setfield = nuts.setfield local getnext = nuts.getnext local getprev = nuts.getprev local getid = nuts.getid local getlist = nuts.getlist local setlist = nuts.setlist -local getattr = nuts.getattr -local setattr = nuts.setattr +local setlink = nuts.setlink +local takeattr = nuts.takeattr local getsubtype = nuts.getsubtype +local getwidth = nuts.getwidth +local findtail = nuts.tail local hpack_nodes = nuts.hpack -local linked_nodes = nuts.linked local unsetvalue = attributes.unsetvalue @@ -71,7 +71,7 @@ local function handler(head,leftpage,realpageno) local id = getid(current) if id == hlist_code then if getsubtype(current) == line_code then - local a = getattr(current,a_realign) + local a = takeattr(current,a_realign) if not a or a == 0 then -- skip else @@ -87,12 +87,16 @@ local function handler(head,leftpage,realpageno) action = leftpage and 2 or 1 end if action == 1 then - setlist(current,hpack_nodes(linked_nodes(getlist(current),new_stretch(3)),getfield(current,"width"),"exactly")) + local head = getlist(current) + setlink(findtail(head),new_stretch(3)) -- append + setlist(current,hpack_nodes(head,getwidth(current),"exactly")) if trace_realign then report_realign("flushing left, align %a, page %a, realpage %a",align,pageno,realpageno) end elseif action == 2 then - setlist(current,hpack_nodes(linked_nodes(new_stretch(3),getlist(current)),getfield(current,"width"),"exactly")) + local list = getlist(current) + local head = setlink(new_stretch(3),list) -- prepend + setlist(current,hpack_nodes(head,getwidth(current),"exactly")) if trace_realign then report_realign("flushing right. align %a, page %a, realpage %a",align,pageno,realpageno) end @@ -102,7 +106,6 @@ local function handler(head,leftpage,realpageno) done = true nofrealigned = nofrealigned + 1 end - setattr(current,a_realign,unsetvalue) end end handler(getlist(current),leftpage,realpageno) diff --git a/tex/context/base/mkiv/spac-chr.lua b/tex/context/base/mkiv/spac-chr.lua index 2ea53b89e..fe402ed87 100644 --- a/tex/context/base/mkiv/spac-chr.lua +++ b/tex/context/base/mkiv/spac-chr.lua @@ -36,6 +36,7 @@ local getnext = nuts.getnext local getprev = nuts.getprev local getattr = nuts.getattr local setattr = nuts.setattr +local setattrlist = nuts.setattrlist local getfont = nuts.getfont local getchar = nuts.getchar local setsubtype = nuts.setsubtype @@ -86,36 +87,33 @@ local c_zero = byte('0') local c_period = byte('.') local function inject_quad_space(unicode,head,current,fraction) - local attr = getfield(current,"attr") if fraction ~= 0 then fraction = fraction * fontquads[getfont(current)] end local glue = new_glue(fraction) - setfield(glue,"attr",attr) - setfield(current,"attr",nil) + setattrlist(glue,current) + setattrlist(current) -- why reset all setattr(glue,a_character,unicode) head, current = insert_node_after(head,current,glue) return head, current end local function inject_char_space(unicode,head,current,parent) - local attr = getfield(current,"attr") local font = getfont(current) local char = fontcharacters[font][parent] local glue = new_glue(char and char.width or fontparameters[font].space) - setfield(glue,"attr",attr) - setfield(current,"attr",nil) + setattrlist(glue,current) + setattrlist(current) -- why reset all setattr(glue,a_character,unicode) head, current = insert_node_after(head,current,glue) return head, current end local function inject_nobreak_space(unicode,head,current,space,spacestretch,spaceshrink) - local attr = getfield(current,"attr") local glue = new_glue(space,spacestretch,spaceshrink) local penalty = new_penalty(10000) - setfield(glue,"attr",attr) - setfield(current,"attr",nil) + setattrlist(glue,current) + setattrlist(current) -- why reset all setattr(glue,a_character,unicode) -- bombs head, current = insert_node_after(head,current,penalty) if trace_nbsp then diff --git a/tex/context/base/mkiv/spac-prf.lua b/tex/context/base/mkiv/spac-prf.lua index f89d836d8..841e5d271 100644 --- a/tex/context/base/mkiv/spac-prf.lua +++ b/tex/context/base/mkiv/spac-prf.lua @@ -51,12 +51,22 @@ local getsubtype = nuts.getsubtype local getlist = nuts.getlist local gettexbox = nuts.getbox local getwhd = nuts.getwhd +local getglue = nuts.getglue +local getkern = nuts.getkern +local getshift = nuts.getshift +local getwidth = nuts.getwidth +local getheight = nuts.getheight +local getdepth = nuts.getdepth local setfield = nuts.setfield local setlink = nuts.setlink local setlist = nuts.setlist local setattr = nuts.setattr local setwhd = nuts.setwhd +local setshift = nuts.setshift +local setwidth = nuts.setwidth +local setheight = nuts.setheight +local setdepth = nuts.setdepth local properties = nodes.properties.data local setprop = nuts.setprop @@ -86,6 +96,8 @@ local v_strict = variables.strict local setcolor = nodes.tracers.colors.set local settransparency = nodes.tracers.transparencies.set +local enableaction = nodes.tasks.enableaction + local profiling = { } builders.profiling = profiling @@ -117,7 +129,7 @@ local function getprofile(line,step) local step = step or 65536 -- * 2 -- 2pt local margin = step / 4 local min = 0 - local max = ceiling(getfield(line,"width")/step) + 1 + local max = ceiling(getwidth(line)/step) + 1 for i=min,max do heights[i] = 0 @@ -166,7 +178,7 @@ local function getprofile(line,step) wd, ht, dp = getwhd(current) progress() elseif id == kern_code then - wd = getfield(current,"kern") + wd = getkern(current) ht = 0 dp = 0 progress() @@ -176,20 +188,26 @@ local function getprofile(line,step) process(replace) end elseif id == glue_code then - wd = getfield(current,"width") + local width, stretch, shrink, stretch_order, shrink_order = getglue(current) if glue_sign == 1 then - if getfield(current,"stretch_order") == glue_order then - wd = wd + getfield(current,"stretch") * glue_set + if stretch_order == glue_order then + wd = width + stretch * glue_set + else + wd = width end elseif glue_sign == 2 then - if getfield(current,"shrink_order") == glue_order then - wd = wd - getfield(current,"shrink") * glue_set + if shrink_order == glue_order then + wd = width - shrink * glue_set + else + wd = width end + else + wd = width end if getsubtype(current) >= leaders_code then local leader = getleader(current) - ht = getfield(leader,"height") - dp = getfield(leader,"depth") + local w + w, ht, dp = getwhd(leader) -- can become getwhd(current) after 1.003 else ht = 0 dp = 0 @@ -197,7 +215,7 @@ local function getprofile(line,step) progress() elseif id == hlist_code then -- we could do a nested check .. but then we need to push / pop glue - local shift = getfield(current,"shift") + local shift = getshift(current) local w, h, d = getwhd(current) -- if getattr(current,a_specialcontent) then if getprop(current,"specialcontent") then @@ -212,19 +230,19 @@ local function getprofile(line,step) end progress() elseif id == vlist_code or id == unset_code then - local shift = getfield(current,"shift") -- todo + local shift = getshift(current) -- todo wd, ht, dp = getwhd(current) progress() elseif id == rule_code then wd, ht, dp = getwhd(current) progress() elseif id == math_code then - wd = getfield(current,"surround") + getfield(current,"width") + wd = getkern(current) + getwidth(current) -- surround ht = 0 dp = 0 progress() elseif id == marginkern_code then - wd = getfield(current,"width") + wd = getwidth(current) ht = 0 dp = 0 progress() @@ -293,16 +311,14 @@ local function addstring(height,depth) local dptext = depth local httext = typesetters.tohpack(height,infofont) local dptext = typesetters.tohpack(depth,infofont) - setfield(httext,"shift",- 1.2 * exheight) - setfield(dptext,"shift", 0.6 * exheight) - local text = nuts.hpack( - nuts.linked( - new_kern(-getfield(httext,"width")-emwidth), - httext, - new_kern(-getfield(dptext,"width")), - dptext - ) - ) + setshift(httext,- 1.2 * exheight) + setshift(dptext, 0.6 * exheight) + local text = hpack_nodes(setlink( + new_kern(-getwidth(httext)-emwidth), + httext, + new_kern(-getwidth(dptext)), + dptext + )) setwhd(text,0,0,0) return text end @@ -385,8 +401,8 @@ local function addprofile(node,profile,step) -- if texttoo then -- -- local text = addstring( - -- formatters["%0.4f"](getfield(rule,"height")/65536), - -- formatters["%0.4f"](getfield(rule,"depth") /65536) + -- formatters["%0.4f"](getheight(rule)/65536), + -- formatters["%0.4f"](getdepth(rule) /65536) -- ) -- -- setlink(text,rule) @@ -475,8 +491,8 @@ methods[v_strict] = function(top,bot,t_profile,b_profile,specification) local strutdp = specification.depth or texdimen.strutdp local lineheight = strutht + strutdp - local depth = getfield(top,"depth") - local height = getfield(bot,"height") + local depth = getdepth(top) + local height = getheight(bot) local total = depth + height local distance = specification.distance or 0 local delta = lineheight - total @@ -511,8 +527,8 @@ methods[v_fixed] = function(top,bot,t_profile,b_profile,specification) local strutdp = specification.depth or texdimen.strutdp local lineheight = strutht + strutdp - local depth = getfield(top,"depth") - local height = getfield(bot,"height") + local depth = getdepth(top) + local height = getheight(bot) local total = depth + height local distance = specification.distance or 0 local delta = lineheight - total @@ -524,8 +540,8 @@ methods[v_fixed] = function(top,bot,t_profile,b_profile,specification) -- no distance (yet) if delta < lineheight then - setfield(top,"depth",strutdp) - setfield(bot,"height",strutht) + setdepth(top,strutdp) + setheight(bot,strutht) return true end @@ -536,13 +552,13 @@ methods[v_fixed] = function(top,bot,t_profile,b_profile,specification) depth = depth - lineheight dp = dp + lineheight end - setfield(top,"depth",dp) + setdepth(top,dp) local ht = strutht while height > lineheight - strutht do height = height - lineheight ht = ht + lineheight end - setfield(bot,"height",ht) + setheight(bot,ht) local lines = floor(delta/lineheight) if lines > 0 then inject(top,bot,-lines * lineheight) @@ -553,17 +569,17 @@ methods[v_fixed] = function(top,bot,t_profile,b_profile,specification) end if total < lineheight then - setfield(top,"depth",strutdp) - setfield(bot,"height",strutht) + setdepth(top,strutdp) + setheight(bot,strutht) return true end if depth < strutdp then - setfield(top,"depth",strutdp) + setdepth(top,strutdp) total = total - depth + strutdp end if height < strutht then - setfield(bot,"height",strutht) + setheight(bot,strutht) total = total - height + strutht end @@ -663,7 +679,7 @@ local function profilelist(line,mvl) end break elseif id == glue_code then - local wd = getfield(current,"width") + local wd = getwidth(current) if not wd or wd == 0 then -- go on else @@ -737,7 +753,7 @@ local function profilelist(line,mvl) if top then local subtype = getsubtype(current) -- if subtype == lineskip_code or subtype == baselineskip_code then - local wd = getfield(current,"width") + local wd = getwidth(current) if wd > 0 then distance = wd lastglue = current @@ -781,9 +797,9 @@ local enabled = false function profiling.set(specification) if not enabled then - nodes.tasks.enableaction("mvlbuilders", "builders.profiling.pagehandler") + enableaction("mvlbuilders", "builders.profiling.pagehandler") -- too expensive so we expect that this happens explicitly, we keep for reference: - -- nodes.tasks.enableaction("vboxbuilders","builders.profiling.vboxhandler") + -- enableaction("vboxbuilders","builders.profiling.vboxhandler") enabled = true end local n = #specifications + 1 @@ -842,7 +858,7 @@ function profiling.profilebox(specification) local subtype = getsubtype(current) if subtype == lineskip_code or subtype == baselineskip_code then if top then - local wd = getfield(current,"width") + local wd = getwidth(current) if wd > 0 then distance = wd lastglue = current diff --git a/tex/context/base/mkiv/spac-ver.lua b/tex/context/base/mkiv/spac-ver.lua index 37f99e760..c7eec18ee 100644 --- a/tex/context/base/mkiv/spac-ver.lua +++ b/tex/context/base/mkiv/spac-ver.lua @@ -30,6 +30,8 @@ if not modules then modules = { } end modules ['spac-ver'] = { -- todo: strip baselineskip around display math +-- todo: getglue(n,false) instead of getfield + local next, type, tonumber = next, type, tonumber local gmatch, concat = string.gmatch, table.concat local ceil, floor = math.ceil, math.floor @@ -39,8 +41,6 @@ local allocate = utilities.storage.allocate local todimen = string.todimen local formatters = string.formatters -local P, C, R, S, Cc, Carg = lpeg.P, lpeg.C, lpeg.R, lpeg.S, lpeg.Cc, lpeg.Carg - local nodes = nodes local node = node local trackers = trackers @@ -62,7 +62,7 @@ local implement = interfaces.implement local v_local = variables["local"] local v_global = variables["global"] local v_box = variables.box -local v_page = variables.page -- reserved for future use +----- v_page = variables.page -- reserved for future use local v_split = variables.split local v_min = variables.min local v_max = variables.max @@ -136,15 +136,23 @@ local getprop = nuts.getprop local setprop = nuts.setprop local getglue = nuts.getglue local setglue = nuts.setglue +local getkern = nuts.getkern +local getpenalty = nuts.getpenalty +local setshift = nuts.setshift +local setwidth = nuts.setwidth +local getwidth = nuts.getwidth +local setheight = nuts.setheight +local getheight = nuts.getheight +local setdepth = nuts.setdepth +local getdepth = nuts.getdepth local find_node_tail = nuts.tail local flush_node = nuts.flush_node local traverse_nodes = nuts.traverse local traverse_nodes_id = nuts.traverse_id local insert_node_before = nuts.insert_before -local insert_node_after = nuts.insert_after local remove_node = nuts.remove -local count_nodes = nuts.count +local count_nodes = nuts.countall local hpack_node = nuts.hpack local vpack_node = nuts.vpack ----- writable_spec = nuts.writable_spec @@ -266,17 +274,6 @@ function vspacing.definesnapmethod(name,method) context(n) end --- local rule_id = nodecodes.rule --- local vlist_id = nodecodes.vlist --- function nodes.makevtop(n) --- if getid(n) == vlist_id then --- local list = getlist(n) --- local height = (list and getid(list) <= rule_id and getfield(list,"height")) or 0 --- setfield(n,"depth",getfield(n,"depth") - height + getfield(n,"height") --- setfield(n,"height",height --- end --- end - local function validvbox(parentid,list) if parentid == hlist_code then local id = getid(list) @@ -326,16 +323,16 @@ local function already_done(parentid,list,a_snapmethod) -- todo: done when only for n in traverse_nodes(list) do local id = getid(n) if id == hlist_code or id == vlist_code then --- local a = getattr(n,a_snapmethod) --- if not a then --- -- return true -- not snapped at all --- elseif a == 0 then --- return true -- already snapped --- end -local p = getprop(n,"snapper") -if p then - return p -end + -- local a = getattr(n,a_snapmethod) + -- if not a then + -- -- return true -- not snapped at all + -- elseif a == 0 then + -- return true -- already snapped + -- end + local p = getprop(n,"snapper") + if p then + return p + end elseif id == glue_code or id == penalty_code then -- or id == kern_code then -- go on else @@ -517,7 +514,7 @@ local function snap_hlist(where,current,method,height,depth) -- method[v_strut] ch, cd = lh, delta + d h, d = ch, cd local shifted = hpack_node(getlist(current)) - setfield(shifted,"shift",delta) + setshift(shifted,delta) setlist(current,shifted) done = true if t then @@ -552,7 +549,7 @@ local function snap_hlist(where,current,method,height,depth) -- method[v_strut] cd, ch = ld, delta + h h, d = ch, cd local shifted = hpack_node(getlist(current)) - setfield(shifted,"shift",delta) + setshift(shifted,delta) setlist(current,shifted) done = true if t then @@ -618,7 +615,7 @@ local function snap_hlist(where,current,method,height,depth) -- method[v_strut] t[#t+1] = formatters["before offset: %p (width %p height %p depth %p)"](offset,wd,ht,dp) end local shifted = hpack_node(getlist(current)) - setfield(shifted,"shift",offset) + setshift(shifted,offset) setlist(current,shifted) if t then local wd, ht, dp = getwhd(current) @@ -628,13 +625,13 @@ local function snap_hlist(where,current,method,height,depth) -- method[v_strut] setattr(current,a_snapmethod,0) end if not height then - setfield(current,"height",ch) + setheight(current,ch) if t then t[#t+1] = formatters["forced height: %p"](ch) end end if not depth then - setfield(current,"depth",cd) + setdepth(current,cd) if t then t[#t+1] = formatters["forced depth: %p"](cd) end @@ -664,8 +661,8 @@ local function snap_hlist(where,current,method,height,depth) -- method[v_strut] end local function snap_topskip(current,method) - local w = getfield(current,"width") or 0 - setfield(current,"width",0) + local w = getwidth(current) + setwidth(current,0) return w, 0 end @@ -714,6 +711,8 @@ storage.register("builders/vspacing/data/skip", vspacingdata.skip, "builders.vsp do -- todo: interface.variables and properties + local P, C, R, S, Cc = lpeg.P, lpeg.C, lpeg.R, lpeg.S, lpeg.Cc + vspacing.fixed = false local map = vspacingdata.map @@ -834,11 +833,11 @@ local function nodes_to_string(head) local id = getid(current) local ty = nodecodes[id] if id == penalty_code then - t[#t+1] = formatters["%s:%s"](ty,getfield(current,"penalty")) + t[#t+1] = formatters["%s:%s"](ty,getpenalty(current)) elseif id == glue_code then - t[#t+1] = formatters["%s:%s:%p"](ty,skipcodes[getsubtype(current)],getfield(current,"width")) + t[#t+1] = formatters["%s:%s:%p"](ty,skipcodes[getsubtype(current)],getwidth(current)) elseif id == kern_code then - t[#t+1] = formatters["%s:%p"](ty,getfield(current,"kern")) + t[#t+1] = formatters["%s:%p"](ty,getkern(current)) else t[#t+1] = ty end @@ -852,12 +851,12 @@ local function reset_tracing(head) end local function trace_skip(str,sc,so,sp,data) - trace_list[#trace_list+1] = { "skip", formatters["%s | %p | category %s | order %s | penalty %s"](str, getfield(data,"width"), sc or "-", so or "-", sp or "-") } + trace_list[#trace_list+1] = { "skip", formatters["%s | %p | category %s | order %s | penalty %s"](str, getwidth(data), sc or "-", so or "-", sp or "-") } tracing_info = true end local function trace_natural(str,data) - trace_list[#trace_list+1] = { "skip", formatters["%s | %p"](str, getfield(data,"width")) } + trace_list[#trace_list+1] = { "skip", formatters["%s | %p"](str, getwidth(data)) } tracing_info = true end @@ -877,9 +876,9 @@ end local function trace_done(str,data) if getid(data) == penalty_code then - trace_list[#trace_list+1] = { "penalty", formatters["%s | %s"](str,getfield(data,"penalty")) } + trace_list[#trace_list+1] = { "penalty", formatters["%s | %s"](str,getpenalty(data)) } else - trace_list[#trace_list+1] = { "glue", formatters["%s | %p"](str,getfield(data,"width")) } + trace_list[#trace_list+1] = { "glue", formatters["%s | %p"](str,getwidth(data)) } end tracing_info = true end @@ -958,10 +957,10 @@ end local w, h, d = 0, 0, 0 ----- w, h, d = 100*65536, 65536, 65536 -local function forced_skip(head,current,width,where,trace) +local function forced_skip(head,current,width,where,trace) -- looks old ... we have other tricks now if head == current then if getsubtype(head) == baselineskip_code then - width = width - (getfield(head,"width") or 0) + width = width - getwidth(head) end end if width == 0 then @@ -1057,7 +1056,7 @@ specialmethods[1] = function(pagehead,pagetail,start,penalty) report_specials(" context penalty %a, higher level, continue",p) end else - local p = getfield(current,"penalty") + local p = getpenalty(current) if p < 10000 then -- assume some other mechanism kicks in so we seem to have content if trace_specials then @@ -1101,15 +1100,15 @@ local function check_experimental_overlay(head,current) local skips = 0 -- -- We deal with this at the tex end .. we don't see spacing .. enabling this code - -- is probably harmless btu then we need to test it. + -- is probably harmless but then we need to test it. -- local c = getnext(p) while c and c ~= n do local id = getid(c) if id == glue_code then - skips = skips + (getfield(c,"width") or 0) + skips = skips + getwidth(c) elseif id == kern_code then - skips = skips + getfield(c,"kern") + skips = skips + getkern(c) end c = getnext(c) end @@ -1119,7 +1118,7 @@ local function check_experimental_overlay(head,current) local k = new_kern(-delta) if n_ht > p_ht then -- we should adapt pagetotal ! (need a hook for that) .. now we have the wrong pagebreak - setfield(p,"height",n_ht) + setheight(p,n_ht) end insert_node_before(head,n,k) if p == head then @@ -1230,18 +1229,18 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also local function compensate(n) local g = 0 while n and getid(n) == glue_code do - g = g + getfield(n,"width") + g = g + getwidth(n) n = getnext(n) end if n then local p = getprop(n,"snapper") if p then local extra = p.extra - if extra < 0 then - local h = p.ch -- getfield(n,"height") + if extra and extra < 0 then -- hm, extra can be unset ... needs checking + local h = p.ch -- getheight(n) -- maybe an extra check -- if h - extra < g then - setfield(n,"height",h-2*extra) + setheight(n,h-2*extra) p.extra = 0 if trace_vsnapping then report_snapper("removed extra space at top: %p",extra) @@ -1326,16 +1325,16 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also if trace then trace_done("flushed due to forced " .. why,glue_data) end - head = forced_skip(head,current,getfield(glue_data,"width") or 0,"before",trace) + head = forced_skip(head,current,getwidth(glue_data,width),"before",trace) flush_node(glue_data) else - local w = getfield(glue_data,"width") - if w ~= 0 then + local width, stretch, shrink = getglue(glue_data) + if width ~= 0 then if trace then trace_done("flushed due to non zero " .. why,glue_data) end head = insert_node_before(head,current,glue_data) - elseif getfield(glue_data,"stretch") ~= 0 or getfield(glue_data,"shrink") ~= 0 then + elseif stretch ~= 0 or shrink ~= 0 then if trace then trace_done("flushed due to stretch/shrink in" .. why,glue_data) end @@ -1398,16 +1397,15 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also end else local h, d, ch, cd, lines, extra = snap_hlist("mvl",current,sv,false,false) -lastsnap = { - ht = h, - dp = d, - ch = ch, - cd = cd, - extra = extra, - current = current, -} -setprop(current,"snapper",lastsnap) - + lastsnap = { + ht = h, + dp = d, + ch = ch, + cd = cd, + extra = extra, + current = current, + } + setprop(current,"snapper",lastsnap) if trace_vsnapping then report_snapper("mvl %a snapped from (%p,%p) to (%p,%p) using method %a (%s) for %a (%s lines): %s", nodecodes[id],h,d,ch,cd,sv.name,sv.specification,where,lines,listtoutf(list)) @@ -1425,15 +1423,15 @@ setprop(current,"snapper",lastsnap) flush("list") current = getnext(current) elseif id == penalty_code then - -- natural_penalty = getfield(current,"penalty") + -- natural_penalty = getpenalty(current) -- if trace then -- trace_done("removed penalty",current) -- end -- head, current = remove_node(head, current, true) current = getnext(current) elseif id == kern_code then - if snap and trace_vsnapping and getfield(current,"kern") ~= 0 then - report_snapper("kern of %p kept",getfield(current,"kern")) + if snap and trace_vsnapping and getkern(current) ~= 0 then + report_snapper("kern of %p kept",getkern(current)) end flush("kern") current = getnext(current) @@ -1572,8 +1570,8 @@ setprop(current,"snapper",lastsnap) elseif glue_order == so then -- is now exclusive, maybe support goback as combi, else why a set if sc == largest then - local cw = getfield(current,"width") or 0 - local gw = getfield(glue_data,"width") or 0 + local cw = getwidth(current) + local gw = getwidth(glue_data) if cw > gw then if trace then trace_skip("largest",sc,so,sp,current) @@ -1636,7 +1634,7 @@ setprop(current,"snapper",lastsnap) local s = getattr(current,a_snapmethod) if s and s ~= 0 then setattr(current,a_snapmethod,0) - setfield(current,"width",0) + setwidth(current,0) if trace_vsnapping then report_snapper("lineskip set to zero") end @@ -1658,7 +1656,7 @@ setprop(current,"snapper",lastsnap) local s = getattr(current,a_snapmethod) if s and s ~= 0 then setattr(current,a_snapmethod,0) - setfield(current,"width",0) + setwidth(current,0) if trace_vsnapping then report_snapper("baselineskip set to zero") end @@ -1683,8 +1681,8 @@ setprop(current,"snapper",lastsnap) end head, current = remove_node(head, current, true) elseif glue_data then - local w = getfield(current,"width") or 0 - if ((w ~= 0) and (w > (getfield(glue_data,"width") or 0))) then + local w = getwidth(current) + if (w ~= 0) and (w > getwidth(glue_data)) then glue_data = current if trace then trace_natural("taking parskip",current) @@ -1763,7 +1761,7 @@ setprop(current,"snapper",lastsnap) -- else -- other glue if snap and trace_vsnapping then - local w = getfield(current,"width") or 0 + local w = getwidth(current) if w ~= 0 then report_snapper("glue %p of type %a kept",w,skipcodes[subtype]) end @@ -1795,7 +1793,7 @@ setprop(current,"snapper",lastsnap) if trace then trace_done("result",p) end - head, tail = insert_node_after(head,tail,p) + setlink(tail,p) -- if penalty_data > special_penalty_min and penalty_data < special_penalty_max then local props = properties[p] if props then @@ -1813,11 +1811,13 @@ setprop(current,"snapper",lastsnap) trace_done("result",glue_data) end if force_glue then - head, tail = forced_skip(head,tail,getfield(glue_data,"width") or 0,"after",trace) + head, tail = forced_skip(head,tail,getwidth(glue_data),"after",trace) flush_node(glue_data) glue_data = nil + elseif tail then + setlink(tail,glue_data) else - head, tail = insert_node_after(head,tail,glue_data) + head = glue_data end texnest[texnest.ptr].prevdepth = 0 -- appending to the list bypasses tex's prevdepth handler end @@ -1911,36 +1911,40 @@ function vspacing.pagehandler(newhead,where) return nil end -local ignore = table.tohash { - "split_keep", - "split_off", - -- "vbox", -} +do -function vspacing.vboxhandler(head,where) - if head and not ignore[where] then - local h = tonut(head) - if getnext(h) then -- what if a one liner and snapping? - h = collapser(h,"vbox",where,trace_vbox_vspacing,true,a_snapvbox) -- todo: local snapper - return tonode(h) + local ignore = table.tohash { + "split_keep", + "split_off", + -- "vbox", + } + + function vspacing.vboxhandler(head,where) + if head and not ignore[where] then + local h = tonut(head) + if getnext(h) then -- what if a one liner and snapping? + h = collapser(h,"vbox",where,trace_vbox_vspacing,true,a_snapvbox) -- todo: local snapper + return tonode(h) + end end + return head end - return head -end -function vspacing.collapsevbox(n,aslist) -- for boxes but using global a_snapmethod - local box = getbox(n) - if box then - local list = getlist(box) - if list then - list = collapser(list,"snapper","vbox",trace_vbox_vspacing,true,a_snapmethod) - if aslist then - setlist(box,list) -- beware, dimensions of box are wrong now - else - setlist(box,vpack_node(list)) + function vspacing.collapsevbox(n,aslist) -- for boxes but using global a_snapmethod + local box = getbox(n) + if box then + local list = getlist(box) + if list then + list = collapser(list,"snapper","vbox",trace_vbox_vspacing,true,a_snapmethod) + if aslist then + setlist(box,list) -- beware, dimensions of box are wrong now + else + setlist(box,vpack_node(list)) + end end end end + end -- This one is needed to prevent bleeding of prevdepth to the next page @@ -1979,71 +1983,75 @@ end -- interface -implement { - name = "vspacing", - actions = vspacing.analyze, - scope = "private", - arguments = "string" -} - -implement { - name = "resetprevdepth", - actions = vspacing.resetprevdepth, - scope = "private" -} - -implement { - name = "vspacingsetamount", - actions = vspacing.setskip, - scope = "private", - arguments = "string", -} - -implement { - name = "vspacingdefine", - actions = vspacing.setmap, - scope = "private", - arguments = { "string", "string" } -} - -implement { - name = "vspacingcollapse", - actions = vspacing.collapsevbox, - scope = "private", - arguments = "integer" -} - -implement { - name = "vspacingcollapseonly", - actions = vspacing.collapsevbox, - scope = "private", - arguments = { "integer", true } -} - -implement { - name = "vspacingsnap", - actions = vspacing.snapbox, - scope = "private", - arguments = { "integer", "integer" } -} - -implement { - name = "definesnapmethod", - actions = vspacing.definesnapmethod, - scope = "private", - arguments = { "string", "string" } -} - -local remove_node = nodes.remove -local find_node_tail = nodes.tail +do -interfaces.implement { - name = "fakenextstrutline", - actions = function() - local head = texlists.page_head - if head then - local head = remove_node(head,find_node_tail(head),true) - texlists.page_head = head + implement { + name = "vspacing", + actions = vspacing.analyze, + scope = "private", + arguments = "string" + } + + implement { + name = "resetprevdepth", + actions = vspacing.resetprevdepth, + scope = "private" + } + + implement { + name = "vspacingsetamount", + actions = vspacing.setskip, + scope = "private", + arguments = "string", + } + + implement { + name = "vspacingdefine", + actions = vspacing.setmap, + scope = "private", + arguments = { "string", "string" } + } + + implement { + name = "vspacingcollapse", + actions = vspacing.collapsevbox, + scope = "private", + arguments = "integer" + } + + implement { + name = "vspacingcollapseonly", + actions = vspacing.collapsevbox, + scope = "private", + arguments = { "integer", true } + } + + implement { + name = "vspacingsnap", + actions = vspacing.snapbox, + scope = "private", + arguments = { "integer", "integer" } + } + + implement { + name = "definesnapmethod", + actions = vspacing.definesnapmethod, + scope = "private", + arguments = { "string", "string" } + } + + local remove_node = nodes.remove + local find_node_tail = nodes.tail + + interfaces.implement { + name = "fakenextstrutline", + actions = function() + local head = texlists.page_head + if head then + local head = remove_node(head,find_node_tail(head),true) + texlists.page_head = head + end end - end -} + } + +end diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf Binary files differindex ed9a82192..c01ed7449 100644 --- a/tex/context/base/mkiv/status-files.pdf +++ b/tex/context/base/mkiv/status-files.pdf diff --git a/tex/context/base/mkiv/status-lua.pdf b/tex/context/base/mkiv/status-lua.pdf Binary files differindex c6c5939bb..d9528aa62 100644 --- a/tex/context/base/mkiv/status-lua.pdf +++ b/tex/context/base/mkiv/status-lua.pdf diff --git a/tex/context/base/mkiv/strc-con.mkvi b/tex/context/base/mkiv/strc-con.mkvi index 396869608..18ce17355 100644 --- a/tex/context/base/mkiv/strc-con.mkvi +++ b/tex/context/base/mkiv/strc-con.mkvi @@ -971,8 +971,8 @@ catcodes \catcodetable } references { - internal \nextinternalreference - order \nextinternalorderreference + internal \locationcount + order \locationorder reference {\currentconstructionreference} prefix {\currentconstructionreferenceprefix} % block {\currentsectionblock} @@ -1016,7 +1016,7 @@ \clf_setinternalreference prefix {\referenceprefix}% reference {\currentconstructionreference}% - internal \nextinternalreference + internal \locationcount view {\interactionparameter\c!focus}% \relax \normalexpanded{% diff --git a/tex/context/base/mkiv/strc-doc.lua b/tex/context/base/mkiv/strc-doc.lua index 105e5ad8d..57fff5a21 100644 --- a/tex/context/base/mkiv/strc-doc.lua +++ b/tex/context/base/mkiv/strc-doc.lua @@ -16,7 +16,7 @@ if not modules then modules = { } end modules ['strc-doc'] = { -- in lists however zero's are ignored, so there numbersegments=2:4 gives result local next, type, tonumber, select = next, type, tonumber, select -local format, gsub, find, gmatch, match = string.format, string.gsub, string.find, string.gmatch, string.match +local find, match = string.find, string.match local concat, fastcopy, insert, remove = table.concat, table.fastcopy, table.insert, table.remove local max, min = math.max, math.min local allocate, mark, accesstable = utilities.storage.allocate, utilities.storage.mark, utilities.tables.accesstable @@ -411,16 +411,17 @@ function sections.setentry(given) v[2](k) end end - local n = { } - for i=1,newdepth do - n[i] = numbers[i] - end - numberdata.numbers = n +-- local n = { } +-- for i=1,newdepth do +-- n[i] = numbers[i] +-- end +-- numberdata.numbers = n + numberdata.numbers = { unpack(numbers,1,newdepth) } if not numberdata.block then numberdata.block = getcurrentblock() -- also in references end if #ownnumbers > 0 then - numberdata.ownnumbers = fastcopy(ownnumbers) + numberdata.ownnumbers = fastcopy(ownnumbers) -- { unpack(ownnumbers) } end if trace_detail then report_structure("name %a, numbers % a, own numbers % a",givenname,numberdata.numbers,numberdata.ownnumbers) diff --git a/tex/context/base/mkiv/strc-doc.mkiv b/tex/context/base/mkiv/strc-doc.mkiv index c453f199e..5f40521fa 100644 --- a/tex/context/base/mkiv/strc-doc.mkiv +++ b/tex/context/base/mkiv/strc-doc.mkiv @@ -23,10 +23,10 @@ {\clf_setinternalreference prefix {\currentstructurereferenceprefix}% reference {\currentstructurereference} - internal \nextinternalreference + internal \locationcount view {\interactionparameter\c!focus}% \relax \xdef\currentstructureattribute {\the\lastdestinationattribute}% - \xdef\currentstructuresynchronize{\strc_lists_inject_enhance{#1}{\nextinternalreference}}} + \xdef\currentstructuresynchronize{\strc_lists_inject_enhance{#1}{\the\locationcount}}} \protect \endinput diff --git a/tex/context/base/mkiv/strc-enu.mkvi b/tex/context/base/mkiv/strc-enu.mkvi index aaf735918..8eff706bb 100644 --- a/tex/context/base/mkiv/strc-enu.mkvi +++ b/tex/context/base/mkiv/strc-enu.mkvi @@ -366,7 +366,7 @@ \strc_enumerations_full_number_yes \edef\p_coupling{\constructionparameter\c!coupling}% \ifx\p_coupling\empty \else - \symbolreference[order(construction:\p_coupling:\nextinternalorderreference)]% + \symbolreference[order(construction:\p_coupling:\the\locationorder)]% \fi \fi} diff --git a/tex/context/base/mkiv/strc-itm.mkvi b/tex/context/base/mkiv/strc-itm.mkvi index e622318c3..a28193415 100644 --- a/tex/context/base/mkiv/strc-itm.mkvi +++ b/tex/context/base/mkiv/strc-itm.mkvi @@ -274,7 +274,7 @@ catcodes \catcodetable }% references {% - internal \nextinternalreference % no: this spoils references + internal \locationcount % no: this spoils references % block {\currentsectionblock}% view {\interactionparameter\c!focus}% prefix {\referenceprefix}% diff --git a/tex/context/base/mkiv/strc-lst.mkvi b/tex/context/base/mkiv/strc-lst.mkvi index 4309ae93a..a3718af18 100644 --- a/tex/context/base/mkiv/strc-lst.mkvi +++ b/tex/context/base/mkiv/strc-lst.mkvi @@ -145,7 +145,7 @@ {\endgroup} \unexpanded\def\strc_lists_inject_enhance#listindex#internal% - {\normalexpanded{\ctxlatecommand{enhancelist(#listindex)}}} + {\normalexpanded{\ctxlatecommand{enhancelist(\number#listindex)}}} \unexpanded\def\strc_lists_inject_yes[#settings][#userdata]% can be used directly {\setupcurrentlist[\c!type=userdata,\c!location=\v!none,#settings]% grouped (use \let... @@ -153,7 +153,7 @@ \setnextinternalreference \scratchcounter\clf_addtolist references { - internal \nextinternalreference + internal \locationcount % block {\currentsectionblock} % section structures.sections.currentid() % location {\p_location} @@ -167,12 +167,12 @@ userdata {\detokenize\expandafter{\normalexpanded{#userdata}}} \relax \edef\currentlistnumber{\the\scratchcounter}% -\setxvalue{\??listlocations\currentlist}{\nextinternalreference}% +\setxvalue{\??listlocations\currentlist}{\the\locationcount}% \ifx\p_location\v!here % this branch injects nodes ! - \strc_lists_inject_enhance{\currentlistnumber}{\nextinternalreference}% + \strc_lists_inject_enhance{\currentlistnumber}{\the\locationcount}% \clf_setinternalreference - internal \nextinternalreference + internal \locationcount view {\interactionparameter\c!focus}% \relax % this will change \xdef\currentstructurelistattribute{\the\lastdestinationattribute}% diff --git a/tex/context/base/mkiv/strc-mar.lua b/tex/context/base/mkiv/strc-mar.lua index 8b30e8514..624972af4 100644 --- a/tex/context/base/mkiv/strc-mar.lua +++ b/tex/context/base/mkiv/strc-mar.lua @@ -31,7 +31,8 @@ local getlist = nuts.getlist local getattr = nuts.getattr local getbox = nuts.getbox -local traverse_nodes = nuts.traverse +local traverse = nuts.traverse +local traverse_id = nuts.traverse_id local nodecodes = nodes.nodecodes local glyph_code = nodecodes.glyph @@ -117,7 +118,7 @@ end -- identify range local function sweep(head,first,last) - for n in traverse_nodes(head) do + for n in traverse(head) do local id = getid(n) if id == glyph_code then local a = getattr(n,a_marks) diff --git a/tex/context/base/mkiv/strc-mat.mkiv b/tex/context/base/mkiv/strc-mat.mkiv index 4c6b88c8a..4308666f3 100644 --- a/tex/context/base/mkiv/strc-mat.mkiv +++ b/tex/context/base/mkiv/strc-mat.mkiv @@ -518,8 +518,6 @@ %D Tricky stuff: -\newdimen\lastlinewidth - \abovedisplayskip \zeropoint \abovedisplayshortskip \zeropoint % evt. 0pt minus 3pt \belowdisplayskip \zeropoint @@ -529,6 +527,8 @@ \postdisplaypenalty \zerocount % -5000 goes wrong, see penalty at \section \mathdisplayskipmode \plusthree % because align also adds +% \predisplaygapfactor \zerocount % default is 2000 + \unexpanded\def\strc_formulas_forget_display_skips {\mathdisplayskipmode \plusthree \abovedisplayskip \zeropoint diff --git a/tex/context/base/mkiv/strc-not.lua b/tex/context/base/mkiv/strc-not.lua index c54cd442e..1464c7f73 100644 --- a/tex/context/base/mkiv/strc-not.lua +++ b/tex/context/base/mkiv/strc-not.lua @@ -26,8 +26,11 @@ local counterspecials = counters.specials local texgetcount = tex.getcount local texgetbox = tex.getbox +-- todo: allocate + notes.states = notes.states or { } lists.enhancers = lists.enhancers or { } +notes.numbers = notes.numbers or { } storage.register("structures/notes/states", notes.states, "structures.notes.states") @@ -143,6 +146,8 @@ end notes.setstate = setstate notes.getstate = getstate + + implement { name = "setnotestate", actions = setstate, @@ -157,6 +162,7 @@ implement { function notes.define(tag,kind,number) local state = setstate(tag,kind) + notes.numbers[number] = state state.number = number end @@ -451,23 +457,39 @@ end -- for the moment here but better in some builder modules +-- gets register "n" and location "i" (where 1 is before) + +-- this is an experiment, we will make a more general handler instead +-- of the current note one + local report_insert = logs.reporter("pagebuilder","insert") local trace_insert = false trackers.register("pagebuilder.insert",function(v) trace_insert = v end) local texgetglue = tex.getglue ------ texsetglue = tex.setglue +local texsetglue = tex.setglue -function notes.check_spacing(n,i) +local function check_spacing(n,i) local gn, pn, mn = texgetglue(n) local gi, pi, mi = texgetglue(i > 1 and "s_strc_notes_inbetween" or "s_strc_notes_before") - local gt, pt, mt = gn+gi, pn+pi, mn+mi + local gi, pi, mi = gn+gi, pn+pi, mn+mi if trace_insert then report_insert("%s %i: %p plus %p minus %p","always ",n,gn,pn,mn) report_insert("%s %i: %p plus %p minus %p",i > 1 and "inbetween" or "before ",n,gi,pi,mi) report_insert("%s %i: %p plus %p minus %p","effective",n,gt,pt,mt) end - -- texsetglue(0,gt,pt,mt) -- for the moment we use skip register 0 return gt, pt, mt end -callback.register("build_page_insert", notes.check_spacing) +notes.check_spacing = check_spacing + +callback.register("build_page_insert", function(n,i) + local state = notes.numbers[n] + if state then + -- only notes, kind of hardcoded .. bah + local gt, pt, mt = check_spacing(n,i) + texsetglue(0,gt,pt,mt) -- for the moment we use skip register 0 + return 0 + else + return n + end +end) diff --git a/tex/context/base/mkiv/strc-not.mkvi b/tex/context/base/mkiv/strc-not.mkvi index d2626d2ab..f1a51c5ad 100644 --- a/tex/context/base/mkiv/strc-not.mkvi +++ b/tex/context/base/mkiv/strc-not.mkvi @@ -404,7 +404,11 @@ \setexpandednoteparameter\s!insert{\namednoteparameter\currentnoteparent\s!insert}% \definenotation[\currentnote][\currentnoteparent][\c!type=\v!note]% \fi - \clf_definenote{\currentnote}{insert}\currentnoteinsertionnumber\relax + \clf_definenote + {\currentnote}% + {insert}% + \currentnoteinsertionnumber + \relax \to \everydefinenote % maybe we will share this at some point: diff --git a/tex/context/base/mkiv/strc-num.mkiv b/tex/context/base/mkiv/strc-num.mkiv index 2418130f9..4b222801a 100644 --- a/tex/context/base/mkiv/strc-num.mkiv +++ b/tex/context/base/mkiv/strc-num.mkiv @@ -545,7 +545,7 @@ \clf_setdestinationattribute {% references {% - internal \nextinternalreference + internal \locationcount % block {\currentsectionblock}% move to lua view {\interactionparameter\c!focus}% prefix {\currentstructurecomponentreferenceprefix}% @@ -621,7 +621,7 @@ \fi } references { - internal \nextinternalreference + internal \locationcount % block {\currentsectionblock} reference {\currentstructurecomponentreference} prefix {\currentstructurecomponentreferenceprefix} @@ -670,10 +670,10 @@ \relax \xdef\m_strc_counters_last_registered_index{\the\scratchcounter}% \clf_setinternalreference - internal \nextinternalreference + 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}{\nextinternalreference}}} + \xdef\m_strc_counters_last_registered_synchronize{\strc_lists_inject_enhance{\m_strc_counters_last_registered_index}{\the\locationcount}}} \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.mkvi b/tex/context/base/mkiv/strc-ref.mkvi index 96cb61b4a..9f2a7b91c 100644 --- a/tex/context/base/mkiv/strc-ref.mkvi +++ b/tex/context/base/mkiv/strc-ref.mkvi @@ -219,7 +219,7 @@ \clf_setdestinationattribute {% references {% - internal \nextinternalreference + internal \locationcount % block {\currentsectionblock}% view {\interactionparameter\c!focus}% \ifx\referenceprefix\empty\else @@ -281,7 +281,7 @@ \clf_setdestinationattribute {% references {% - internal \nextinternalreference + internal \locationcount % block {\currentsectionblock}% view {\interactionparameter\c!focus}% \ifx\referenceprefix\empty\else @@ -310,7 +310,7 @@ \clf_setdestinationattribute {% references {% - internal \nextinternalreference + internal \locationcount % block {\currentsectionblock}% view {\interactionparameter\c!focus}% \ifx\referenceprefix\empty\else @@ -401,7 +401,7 @@ prefix {\referenceprefix}% \fi reference {#label}% - internal \nextinternalreference + internal \locationcount }% metadata {% kind {\s!page}% @@ -424,7 +424,7 @@ references {% view {\interactionparameter\c!focus}% reference {#label}% - internal \nextinternalreference + internal \locationcount }% metadata {% kind {\s!page}% @@ -847,7 +847,7 @@ \letvalue{\??savedinternalreference\s!default}\!!zerocount \unexpanded\def\storeinternalreference#1#2% - {\setxvalue{\??savedinternalreference\currentstructurename}{#2}} + {\setxvalue{\??savedinternalreference\currentstructurename}{\number#2}} \newconditional\preferpagereferences diff --git a/tex/context/base/mkiv/strc-reg.mkiv b/tex/context/base/mkiv/strc-reg.mkiv index 5b32c6fc8..380cc9f22 100644 --- a/tex/context/base/mkiv/strc-reg.mkiv +++ b/tex/context/base/mkiv/strc-reg.mkiv @@ -298,7 +298,7 @@ userdata {\detokenize\expandafter{\normalexpanded{#3}}} }% \clf_setinternalreference - internal \nextinternalreference + internal \locationcount view {\interactionparameter\c!focus}% \relax % this will change \ifx\currentregisterownnumber\v!yes @@ -337,7 +337,7 @@ }% % overlap with the above % \clf_setinternalreference - % internal \nextinternalreference + % internal \locationcount % view {\interactionparameter\c!focus}% \relax % this will change \xdef\currentregistersynchronize{\ctxlatecommand{enhanceregister("\currentregister",\currentregisternumber)}}% @@ -524,7 +524,7 @@ }% }}% \clf_setinternalreference - internal \nextinternalreference + internal \locationcount view {\interactionparameter\c!focus}% \relax % this will change \dostarttagged\t!registerlocation\currentregister diff --git a/tex/context/base/mkiv/strc-ren.mkiv b/tex/context/base/mkiv/strc-ren.mkiv index b5fc9e11d..b3b9f04d9 100644 --- a/tex/context/base/mkiv/strc-ren.mkiv +++ b/tex/context/base/mkiv/strc-ren.mkiv @@ -82,24 +82,24 @@ \def\headreferenceattributes {\iflocation - % \ctxlua{structures.lists.taglocation(\nextinternalreference)}% maybe ... tags entry as used + % \ctxlua{structures.lists.taglocation(\the\locationcount)}% maybe ... tags entry as used attr \destinationattribute \currentstructureattribute attr \referenceattribute \currentstructurereferenceattribute - % attr \internalattribute \nextinternalreference + % attr \internalattribute \locationcount \fi} \def\setinlineheadreferenceattributes {\ifconditional\headisdisplay \else \iflocation \attribute\destinationattribute\currentstructureattribute \attribute\referenceattribute \currentstructurereferenceattribute - % \attribute\internalattribute \nextinternalreference + % \attribute\internalattribute \locationcount \fi \fi} \def\docheckheadreference {\edef\currentheadinteraction{\headparameter\c!interaction}% \ifx\currentheadinteraction\v!list % setuphead[<section>][interaction=list,...] - \strc_references_get_simple_reference{*\nextinternalreference}% + \strc_references_get_simple_reference{*\the\locationcount}% \let\currentstructurereferenceattribute\currentreferenceattribute \else\ifx\currentheadinteraction\v!reference % setuphead[<section>][interaction=reference,...] start<section>[backreference=abc,...] diff --git a/tex/context/base/mkiv/strc-sec.mkiv b/tex/context/base/mkiv/strc-sec.mkiv index 51b464eb9..b0771b475 100644 --- a/tex/context/base/mkiv/strc-sec.mkiv +++ b/tex/context/base/mkiv/strc-sec.mkiv @@ -176,11 +176,11 @@ \globallet\currentstructurecoding\s!tex \fi \setnextinternalreference - \storeinternalreference\currentstructurename\nextinternalreference % + \storeinternalreference\currentstructurename{\the\locationcount}% \strc_sectioning_set_reference_prefix \clf_setsectionentry references { - internal \nextinternalreference\space + internal \locationcount % block {\currentsectionblock} prefix {\currentstructurereferenceprefix} reference {\currentstructurereference} @@ -225,7 +225,7 @@ numberdata { % block {\currentsectionblock} \ifx\currentstructureshownumber\v!no - hidenumber \space true\space + hidenumber \space true\space % space needed for parser \fi separatorset {\structureparameter\c!sectionseparatorset} conversionset {\structureparameter\c!sectionconversionset} @@ -445,7 +445,7 @@ \clf_registersection {\currenthead} { coupling {\currentsectionheadcoupling} section {\currentsectionheadsection} - level \currentsectionlevel + level \space \currentsectionlevel \space % space needed for parser parent {\currentheadparent} }% \endgroup diff --git a/tex/context/base/mkiv/supp-box.lua b/tex/context/base/mkiv/supp-box.lua index 4e28f2805..b9bf0ccf0 100644 --- a/tex/context/base/mkiv/supp-box.lua +++ b/tex/context/base/mkiv/supp-box.lua @@ -38,6 +38,8 @@ local getid = nuts.getid local getlist = nuts.getlist local getattribute = nuts.getattribute local getbox = nuts.getbox +local getdir = nuts.getdir +local getwidth = nuts.getwidth local takebox = nuts.takebox local setfield = nuts.setfield @@ -46,6 +48,10 @@ local setboth = nuts.setboth local setnext = nuts.setnext local setbox = nuts.setbox local setlist = nuts.setlist +local setdisc = nuts.setdisc +local setwidth = nuts.setwidth +local setheight = nuts.setheight +local setdepth = nuts.setdepth local flush_node = nuts.flush_node local flush_list = nuts.flush_list @@ -53,7 +59,6 @@ local copy_node = nuts.copy local copy_list = nuts.copy_list local find_tail = nuts.tail local traverse_id = nuts.traverse_id -local link_nodes = nuts.linked local list_dimensions = nuts.dimensions local hpack = nuts.hpack @@ -78,12 +83,6 @@ local function hyphenatedlist(head,usecolor) local prev = getprev(current) if id == disc_code then local pre, post, replace = getdisc(current) - if pre then - setfield(current,"pre",nil) - end - if post then - setfield(current,"post",nil) - end if not usecolor then -- nothing fancy done elseif pre and post then @@ -96,23 +95,32 @@ local function hyphenatedlist(head,usecolor) end if replace then flush_list(replace) - setfield(current,"replace",nil) end + setdisc(current) setboth(current) - local list = link_nodes ( +-- local list = setlink ( +-- pre and new_penalty(10000), +-- pre, +-- current, +-- post, +-- post and new_penalty(10000) +-- ) +-- local tail = find_tail(list) +-- if prev then +-- setlink(prev,list) +-- end +-- if next then +-- setlink(tail,next) +-- end + setlink ( + prev, -- there had better be one pre and new_penalty(10000), pre, current, post, - post and new_penalty(10000) + post and new_penalty(10000), + next ) - local tail = find_tail(list) - if prev then - setlink(prev,list) - end - if next then - setlink(tail,next) - end -- flush_node(current) elseif id == vlist_code or id == hlist_code then hyphenatedlist(getlist(current)) @@ -351,8 +359,8 @@ implement { actions = function(n) local b = getbox(n) local factor = texget("baselineskip",false) / texget("hsize") - setfield(b,"depth",0) - setfield(b,"height",getfield(b,"width") * factor) + setdepth(b,0) + setheight(b,getwidth(b) * factor) end } @@ -426,7 +434,7 @@ local function firstdirinbox(n) local l = getlist(b) if l then for h in traverse_id(hlist_code,l) do - return getfield(h,"dir") + return getdir(h) end end end @@ -552,48 +560,57 @@ do end end - interfaces.implement { + implement { name = "putboxincache", arguments = { "string", "string", "integer" }, actions = boxes.save, } - interfaces.implement { + implement { name = "getboxfromcache", arguments = { "string", "string", "integer" }, actions = boxes.restore, } - interfaces.implement { + implement { name = "directboxfromcache", arguments = { "string", "string" }, actions = { boxes.direct, context }, -- actions = function(category,name) local b = boxes.direct(category,name) if b then context(b) end end, } - interfaces.implement { + implement { name = "directcopyboxfromcache", arguments = { "string", "string", true }, actions = { boxes.direct, context }, -- actions = function(category,name) local b = boxes.direct(category,name,true) if b then context(b) end end, } - interfaces.implement { + implement { name = "copyboxfromcache", arguments = { "string", "string", "integer", true }, actions = boxes.restore, } - interfaces.implement { + implement { name = "doifelseboxincache", arguments = { "string", "string" }, actions = { boxes.found, doifelse }, } - interfaces.implement { + implement { name = "resetboxesincache", arguments = { "string" }, actions = boxes.reset, } + implement { + name = "lastlinewidth", + actions = function() + local head = tex.lists.page_head + -- list dimensions returns 3 value but we take the first + context(head and list_dimensions(getlist(find_tail(tonut(tex.lists.page_head)))) or 0) + end + } + end diff --git a/tex/context/base/mkiv/supp-box.mkiv b/tex/context/base/mkiv/supp-box.mkiv index 8e38c4afa..9d2817cee 100644 --- a/tex/context/base/mkiv/supp-box.mkiv +++ b/tex/context/base/mkiv/supp-box.mkiv @@ -2971,6 +2971,10 @@ {\expandafter\newbox\csname\??localbox\string#1\endcsname \newlocalbox#1} +%D Who knows when this comes in handy: + +\unexpanded\def\lastlinewidth{\dimexpr\clf_lastlinelength\scaledpoint\relax} + \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 bff1b8428..eb5b3b90a 100644 --- a/tex/context/base/mkiv/syst-aux.mkiv +++ b/tex/context/base/mkiv/syst-aux.mkiv @@ -7021,7 +7021,7 @@ \unexpanded\def\retestfeature % timer support is new per 10/5/2005 {\bgroup \ifcase\interactionmode\let\wait\relax\fi - \writestatus\m!system{starting feature test}\wait + \writestatus\m!system{starting feature test (n=\number\c_syst_helpers_test_feature_m)}\wait \resettimer \c_syst_helpers_test_feature_n\zerocount \syst_helpers_test_feature_step diff --git a/tex/context/base/mkiv/tabl-xtb.lua b/tex/context/base/mkiv/tabl-xtb.lua index 62c95cbe6..dade345fc 100644 --- a/tex/context/base/mkiv/tabl-xtb.lua +++ b/tex/context/base/mkiv/tabl-xtb.lua @@ -71,6 +71,8 @@ local getwhd = nuts.getwhd local setfield = nuts.setfield local setlink = nuts.setlink +local setdir = nuts.setdir +local setshift = nuts.setshift local copy_node_list = nuts.copy_list local hpack_node_list = nuts.hpack @@ -819,11 +821,9 @@ function xtables.construct() local list = drc.list if list then local w, h, d = getwhd(list) - setfield(list,"shift",h+d) + setshift(list,h+d) -- list = hpack_node_list(list) -- is somehow needed - -- setfield(list,"width",0) - -- setfield(list,"height",0) - -- setfield(list,"depth",0) + -- setwhd(list,0,0,0) -- faster: local h = new_hlist(list) list = h @@ -872,7 +872,7 @@ function xtables.construct() -- we have a direction issue here but hpack_node_list(list,0,"exactly","TLT") cannot be used -- due to the fact that we need the width local hbox = hpack_node_list(list) - setfield(hbox,"dir","TLT") + setdir(hbox,"TLT") result[nofr] = { hbox, size, diff --git a/tex/context/base/mkiv/task-ini.lua b/tex/context/base/mkiv/task-ini.lua index 59500c9b6..14d0b6e74 100644 --- a/tex/context/base/mkiv/task-ini.lua +++ b/tex/context/base/mkiv/task-ini.lua @@ -56,6 +56,7 @@ appendaction("processors", "fonts", "builders.kernel.ligaturing") appendaction("processors", "fonts", "builders.kernel.kerning") -- always on (could be selective: if only node mode) appendaction("processors", "fonts", "nodes.handlers.stripping") -- disabled (might move) ------------("processors", "fonts", "typesetters.italics.handler") -- disabled (after otf/kern handling) +appendaction("processors", "fonts", "nodes.handlers.flatten") appendaction("processors", "lists", "typesetters.rubies.check") -- disabled (maybe someplace else) appendaction("processors", "lists", "typesetters.characteralign.handler") -- disabled (we need to to this after otf appliance) @@ -65,8 +66,9 @@ appendaction("processors", "lists", "typesetters.digits.handler") appendaction("processors", "lists", "typesetters.italics.handler") -- disabled (after otf/kern handling) appendaction("processors", "lists", "languages.visualizediscretionaries") -- disabled --- appendaction("processors", "lists", "typesetters.initials.handler") -- disabled +appendaction ("processors", "after", "typesetters.marksuspects") +appendaction("shipouts", "normalizers", "typesetters.showsuspects") appendaction("shipouts", "normalizers", "typesetters.margins.finalhandler") -- disabled ------------("shipouts", "normalizers", "nodes.handlers.cleanuppage") -- disabled appendaction("shipouts", "normalizers", "builders.paragraphs.expansion.trace") -- disabled @@ -108,6 +110,7 @@ appendaction("math", "normalizers", "noads.handlers.resize", nil, "no appendaction("math", "normalizers", "noads.handlers.alternates",nil, "nohead") -- always on appendaction("math", "normalizers", "noads.handlers.tags", nil, "nohead") -- disabled appendaction("math", "normalizers", "noads.handlers.italics", nil, "nohead") -- disabled +appendaction("math", "normalizers", "noads.handlers.kernpairs", nil, "nohead") -- disabled appendaction("math", "normalizers", "noads.handlers.classes", nil, "nohead") -- disabled appendaction("math", "builders", "builders.kernel.mlist_to_hlist") -- always on @@ -121,8 +124,13 @@ appendaction("finalizers", "lists", "builders.paragraphs.keeptogether") ------------("finalizers", "lists", "nodes.handlers.graphicvadjust") -- todo appendaction("finalizers", "fonts", "builders.paragraphs.solutions.splitters.optimize") -- experimental appendaction("finalizers", "lists", "builders.paragraphs.tag") + +-- the next can also be in contributers normalizers (when we remove the loop in the handler) + appendaction("finalizers", "lists", "nodes.linefillers.handler") +appendaction("contributers", "normalizers", "nodes.handlers.flattenline") + -- still experimental appendaction("mvlbuilders", "normalizers", "typesetters.margins.globalhandler") -- disabled @@ -170,9 +178,12 @@ disableaction("processors", "typesetters.italics.handler") disableaction("processors", "languages.visualizediscretionaries") disableaction("processors", "nodes.handlers.stripping") disableaction("processors", "builders.paragraphs.solutions.splitters.split") -disableaction("processors", "nodes.rubies.check") +disableaction("processors", "typesetters.rubies.check") disableaction("processors", "typesetters.fontkerns.handler") +disableaction("processors", "nodes.handlers.flatten") +disableaction("processors", "typesetters.marksuspects") +disableaction("shipouts", "typesetters.showsuspects") disableaction("shipouts", "typesetters.margins.finalhandler") disableaction("shipouts", "builders.paragraphs.expansion.trace") disableaction("shipouts", "typesetters.alignments.handler") @@ -192,8 +203,7 @@ disableaction("shipouts", "nodes.handlers.alignbackgrounds") disableaction("shipouts", "nodes.references.handler") disableaction("shipouts", "nodes.destinations.handler") -------------("shipouts", "nodes.handlers.export") -disableaction("shipouts","nodes.rubies.attach") - +disableaction("shipouts", "typesetters.rubies.attach") disableaction("finalizers", "typesetters.margins.localhandler") disableaction("finalizers", "builders.paragraphs.keeptogether") @@ -202,9 +212,12 @@ disableaction("finalizers", "builders.paragraphs.solutions.splitters.optimize") disableaction("finalizers", "builders.paragraphs.tag") disableaction("finalizers", "nodes.linefillers.handler") +disableaction("contributers","nodes.handlers.flattenline") + disableaction("math", "noads.handlers.showtree") disableaction("math", "noads.handlers.tags") disableaction("math", "noads.handlers.italics") +disableaction("math", "noads.handlers.kernpairs") disableaction("math", "noads.handlers.domains") disableaction("math", "noads.handlers.classes") disableaction("math", "noads.handlers.autofences") diff --git a/tex/context/base/mkiv/toks-ini.lua b/tex/context/base/mkiv/toks-ini.lua index 132605d38..0ce7b4836 100644 --- a/tex/context/base/mkiv/toks-ini.lua +++ b/tex/context/base/mkiv/toks-ini.lua @@ -68,7 +68,23 @@ local scan_csname = token.scan_csname local get_next = token.get_next +if not token.get_macro then + local scantoks = tex.scantoks + local gettoks = tex.gettoks + function token.get_meaning(name) + scantoks("t_get_macro",tex.ctxcatcodes,"\\"..name) + return gettoks("t_get_macro") + end + function token.get_macro(name) + scantoks("t_get_macro",tex.ctxcatcodes,"\\"..name) + local s = gettoks("t_get_macro") + return match(s,"^.-%->(.*)$") or s + end +end + local set_macro = token.set_macro +local get_macro = token.get_macro +local get_meaning = token.get_meaning local get_cmdname = token.get_cmdname local create_token = token.create @@ -238,14 +254,16 @@ tokens.scanners = { -- these expand } tokens.getters = { -- these don't expand - token = get_next, - count = tex.getcount, - dimen = tex.getdimen, - skip = tex.getglue, - glue = tex.getglue, - skip = tex.getmuglue, - glue = tex.getmuglue, - box = tex.getbox, + meaning = get_meaning, + macro = get_macro, + token = get_next, + count = tex.getcount, + dimen = tex.getdimen, + skip = tex.getglue, + glue = tex.getglue, + skip = tex.getmuglue, + glue = tex.getmuglue, + box = tex.getbox, } tokens.setters = { diff --git a/tex/context/base/mkiv/toks-ini.mkiv b/tex/context/base/mkiv/toks-ini.mkiv index 03ec99742..aaa735207 100644 --- a/tex/context/base/mkiv/toks-ini.mkiv +++ b/tex/context/base/mkiv/toks-ini.mkiv @@ -13,13 +13,13 @@ \writestatus{loading}{ConTeXt Token Support / Initialization} +\unprotect + +\newtoks\t_get_macro % will go away + \registerctxluafile{toks-ini}{1.001} \registerctxluafile{toks-scn}{1.001} \registerctxluafile{cldf-scn}{1.001} \registerctxluafile{cldf-stp}{1.001} -\unprotect - -% nothing yet - \protect \endinput diff --git a/tex/context/base/mkiv/toks-scn.lua b/tex/context/base/mkiv/toks-scn.lua index 696478144..3c41eedd8 100644 --- a/tex/context/base/mkiv/toks-scn.lua +++ b/tex/context/base/mkiv/toks-scn.lua @@ -153,8 +153,25 @@ tokens.converters = { toglue = "todimen", } +-- We could just pickup a keyword but then we really need to make sure +-- that no number follows it when that is the assignment and adding +-- an optional = defeats the gain in speed. Currently we have sources +-- with no spaces (\startcontextdefinitioncode ...) so it fails there. +-- +-- Another drawback is that we then need to use { } instead of ending +-- with \relax (as we can do now) but that is no big deal. It's just +-- that I then need to check the TeX end. More pain than gain and a bit +-- risky too. + local f_if = formatters[ " if scankeyword('%s') then data['%s'] = scan%s()"] local f_elseif = formatters[" elseif scankeyword('%s') then data['%s'] = scan%s()"] + +----- f_if = formatters[" local key = scanword() if key == '' then break elseif key == '%s' then data['%s'] = scan%s()"] +----- f_elseif = formatters[" elseif key == '%s' then data['%s'] = scan%s()"] + +----- f_if_x = formatters[ " if not data['%s'] and scankeyword('%s') then data['%s'] = scan%s()"] +----- f_elseif_x = formatters[" elseif not data['%s'] and scankeyword('%s') then data['%s'] = scan%s()"] + local f_local = formatters["local scan%s = scanners.%s"] local f_scan = formatters["scan%s()"] local f_shortcut = formatters["local %s = scanners.converters.%s"] @@ -163,6 +180,11 @@ local f_if_c = formatters[ " if scankeyword('%s') then data['%s'] = %s(s local f_elseif_c = formatters[" elseif scankeyword('%s') then data['%s'] = %s(scan%s())"] local f_scan_c = formatters["%s(scan%s())"] +-- see above +-- +----- f_if_c = formatters[" local key = scanword() if key == '' then break elseif key == '%s' then data['%s'] = %s(scan%s())"] +----- f_elseif_c = formatters[" elseif k == '%s' then data['%s'] = %s(scan%s())"] + local f_any = formatters[" else local key = scanword() if key then data[key] = scan%s() else break end end"] local f_any_c = formatters[" else local key = scanword() if key then data[key] = %s(scan%s()) else break end end"] local s_done = " else break end" @@ -269,6 +291,7 @@ function tokens.compile(specification) else m = m + 1 r[m] = (m > 1 and f_elseif or f_if )(t1,t1,t2) + -- r[m] = (m > 1 and f_elseif_x or f_if_x)(t1,t1,t1,t2) end end end @@ -291,9 +314,9 @@ function tokens.compile(specification) end tokens._action = a for i=1,#a do - code = f_action_f(i,code) --- f[#f+1] = f_action_s(i,i) -n = n + 1 f[n] = f_action_s(i,i) + code = f_action_f(i,code) + n = n + 1 + f[n] = f_action_s(i,i) end code = f_simple(f,code) else @@ -309,9 +332,9 @@ n = n + 1 f[n] = f_action_s(i,i) if a then tokens._action = a for i=1,#a do - code = f_action_f(i,code) --- f[#f+1] = f_action_s(i,i) -n = n + 1 f[n] = f_action_s(i,i) + code = f_action_f(i,code) + n = n + 1 + f[n] = f_action_s(i,i) end end code = f_table(f,ti,code) @@ -319,9 +342,9 @@ n = n + 1 f[n] = f_action_s(i,i) code = f_scan(ti) tokens._action = a for i=1,#a do - code = f_action_f(i,code) --- f[#f+1] = f_action_s(i,i) -n = n + 1 f[n] = f_action_s(i,i) + code = f_action_f(i,code) + n = n + 1 + f[n] = f_action_s(i,i) end code = f_simple(f,code) else @@ -367,9 +390,9 @@ n = n + 1 f[n] = f_action_s(i,i) if a then tokens._action = a for i=1,#a do - code = f_action_f(i,code) --- f[#f+1] = f_action_s(i,i) -n = n + 1 f[n] = f_action_s(i,i) + code = f_action_f(i,code) + n = n + 1 + f[n] = f_action_s(i,i) end end code = f_sequence(c,f,p,code) diff --git a/tex/context/base/mkiv/trac-deb.lua b/tex/context/base/mkiv/trac-deb.lua index 3770f4189..782be154f 100644 --- a/tex/context/base/mkiv/trac-deb.lua +++ b/tex/context/base/mkiv/trac-deb.lua @@ -337,26 +337,22 @@ local function trace_calls(n) trace_calls = function() end end -if LUATEXVERSION > 0.98 then +local editor = [[scite "-open:%filename%" -goto:%linenumber%]] - local editor = [[scite "-open:%filename%" -goto:%linenumber%]] - - directives.register("system.editor",function(v) - editor = v - end) - - callback.register("call_edit",function(filename,linenumber) - if editor then - editor = gsub(editor,"%%s",filename) - editor = gsub(editor,"%%d",linenumber) - editor = gsub(editor,"%%filename%%",filename) - editor = gsub(editor,"%%linenumber%%",linenumber) - logs.report("system","starting editor: %s",editor) - os.execute(editor) - end - end) +directives.register("system.editor",function(v) + editor = v +end) -end +callback.register("call_edit",function(filename,linenumber) + if editor then + editor = gsub(editor,"%%s",filename) + editor = gsub(editor,"%%d",linenumber) + editor = gsub(editor,"%%filename%%",filename) + editor = gsub(editor,"%%linenumber%%",linenumber) + logs.report("system","starting editor: %s",editor) + os.execute(editor) + end +end) directives.register("system.tracecalls", function(n) trace_calls(n) end) -- indirect is needed for nilling diff --git a/tex/context/base/mkiv/trac-inf.lua b/tex/context/base/mkiv/trac-inf.lua index 12a4f646f..2aecb6703 100644 --- a/tex/context/base/mkiv/trac-inf.lua +++ b/tex/context/base/mkiv/trac-inf.lua @@ -42,11 +42,53 @@ local function resettiming(instance) timers[instance or "notimer"] = { timing = 0, loadtime = 0 } end +local ticks = clock +local seconds = function(n) return n or 0 end + +-- local okay, ffi = pcall(require,"ffi") +-- +-- if ffi and os.type == "windows" then +-- +-- local okay, kernel = pcall(ffi.load,"kernel32") +-- +-- if kernel then +-- +-- local tonumber = ffi.number or tonumber +-- +-- ffi.cdef[[ +-- int QueryPerformanceFrequency(int64_t *lpFrequency); +-- int QueryPerformanceCounter(int64_t *lpPerformanceCount); +-- ]] +-- +-- local target = ffi.new("__int64[1]") +-- +-- ticks = function() +-- if kernel.QueryPerformanceCounter(target) == 1 then +-- return tonumber(target[0]) +-- else +-- return 0 +-- end +-- end +-- +-- local target = ffi.new("__int64[1]") +-- +-- seconds = function(ticks) +-- if kernel.QueryPerformanceFrequency(target) == 1 then +-- return ticks / tonumber(target[0]) +-- else +-- return 0 +-- end +-- end +-- +-- end +-- +-- end + local function starttiming(instance) local timer = timers[instance or "notimer"] local it = timer.timing or 0 if it == 0 then - timer.starttime = clock() + timer.starttime = ticks() if not timer.loadtime then timer.loadtime = 0 end @@ -62,7 +104,7 @@ local function stoptiming(instance) else local starttime = timer.starttime if starttime and starttime > 0 then - local stoptime = clock() + local stoptime = ticks() local loadtime = stoptime - starttime timer.stoptime = stoptime timer.loadtime = timer.loadtime + loadtime @@ -79,7 +121,7 @@ local function elapsed(instance) return instance or 0 else local timer = timers[instance or "notimer"] - return timer and timer.loadtime or 0 + return timer and seconds(timer.loadtime) or 0 end end @@ -137,10 +179,13 @@ function statistics.show() local total, indirect = status.callbacks or 0, status.indirect_callbacks or 0 return format("%s direct, %s indirect, %s total", total-indirect, indirect, total) end) - if jit then - local jitstatus = { jit.status() } - if jitstatus[1] then - register("luajit options", concat(jitstatus," ",2)) + if TEXENGINE == "luajittex" and JITSUPPORTED then + local jitstatus = jit.status + if jitstatus then + local jitstatus = { jitstatus() } + if jitstatus[1] then + register("luajit options", concat(jitstatus," ",2)) + end end end -- so far diff --git a/tex/context/base/mkiv/trac-jus.lua b/tex/context/base/mkiv/trac-jus.lua index 76d6438a1..6d00bf19e 100644 --- a/tex/context/base/mkiv/trac-jus.lua +++ b/tex/context/base/mkiv/trac-jus.lua @@ -23,11 +23,13 @@ local getlist = nuts.getlist local getattr = nuts.getattr local setattr = nuts.setattr local setlist = nuts.setlist +local setlink = nuts.setlink +local getwidth = nuts.getwidth +local findtail = nuts.tail local traverse_id = nuts.traverse_id local list_dimensions = nuts.dimensions -local linked_nodes = nuts.linked -local copy_node = nuts.copy +local copy_list = nuts.copy_list local tracedrule = nodes.tracers.pool.nuts.rule @@ -41,12 +43,14 @@ local hlist_code = nodes.nodecodes.hlist local texsetattribute = tex.setattribute local unsetvalue = attributes.unsetvalue +local enableaction = nodes.tasks.enableaction + local min_threshold = 0 local max_threshold = 0 local function set(n) - nodes.tasks.enableaction("mvlbuilders", "typesetters.checkers.handler") - nodes.tasks.enableaction("vboxbuilders","typesetters.checkers.handler") + enableaction("mvlbuilders", "typesetters.checkers.handler") + enableaction("vboxbuilders","typesetters.checkers.handler") texsetattribute(a_justification,n or 1) function typesetters.checkers.set(n) texsetattribute(a_justification,n or 1) @@ -77,7 +81,7 @@ function checkers.handler(head) for current in traverse_id(hlist_code,tonut(head)) do if getattr(current,a_justification) == 1 then setattr(current,a_justification,0) -- kind of reset - local width = getfield(current,"width") + local width = getwidth(current) if width > 0 then local list = getlist(current) if list then @@ -86,23 +90,29 @@ function checkers.handler(head) if naturalwidth == 0 or delta == 0 then -- special box elseif delta >= max_threshold then - local rule = tracedrule(delta,naturalheight,naturaldepth,getfield(list,"glue_set") == 1 and "trace:dr" or "trace:db") - setlist(current,linked_nodes(list,new_hlist(rule))) + local rule = new_hlist(tracedrule(delta,naturalheight,naturaldepth,getfield(list,"glue_set") == 1 and "trace:dr" or "trace:db")) + setlink(findtail(list),rule) + setlist(current,list) elseif delta <= min_threshold then local alignstate = getattr(list,a_alignstate) if alignstate == 1 then - local rule = tracedrule(-delta,naturalheight,naturaldepth,"trace:dc") - setlist(current,linked_nodes(new_hlist(rule),list)) + local rule = new_hlist(tracedrule(-delta,naturalheight,naturaldepth,"trace:dc")) + setlink(rule,list) + setlist(current,rule) elseif alignstate == 2 then - local lrule = tracedrule(-delta/2,naturalheight,naturaldepth,"trace:dy") - local rrule = copy_node(lrule) - setlist(current,linked_nodes(new_hlist(lrule),list,new_kern(delta/2),new_hlist(rrule))) + local lrule = new_hlist(tracedrule(-delta/2,naturalheight,naturaldepth,"trace:dy")) + local rrule = copy_list(lrule) + setlink(lrule,list) + setlink(findtail(list),new_kern(delta/2),rrule) + setlist(current,lrule) elseif alignstate == 3 then - local rule = tracedrule(-delta,naturalheight,naturaldepth,"trace:dm") - setlist(current,linked_nodes(list,new_kern(delta),new_hlist(rule))) + local rule = new_hlist(tracedrule(-delta,naturalheight,naturaldepth,"trace:dm")) + setlink(findtail(list),new_kern(delta),rule) + setlist(current,list) else - local rule = tracedrule(-delta,naturalheight,naturaldepth,"trace:dg") - setlist(current,linked_nodes(list,new_kern(delta),new_hlist(rule))) + local rule = new_hlist(tracedrule(-delta,naturalheight,naturaldepth,"trace:dg")) + setlink(findtail(list),new_kern(delta),rule) + setlist(current,list) end end end diff --git a/tex/context/base/mkiv/trac-par.lua b/tex/context/base/mkiv/trac-par.lua index 3d8909eb4..56291f8c8 100644 --- a/tex/context/base/mkiv/trac-par.lua +++ b/tex/context/base/mkiv/trac-par.lua @@ -21,6 +21,7 @@ local getnext = nuts.getnext local getlist = nuts.getlist local getfont = nuts.getfont local getchar = nuts.getchar +local getwidth = nuts.getwidth local nodecodes = nodes.nodecodes local hlist_code = nodecodes.hlist @@ -30,6 +31,8 @@ local setnodecolor = nodes.tracers.colors.set local parameters = fonts.hashes.parameters local basepoints = number.basepoints +local setaction = nodes.tasks.setaction + -- definecolor[hz:positive] [r=0.6] -- definecolor[hz:negative] [g=0.6] -- definecolor[hz:zero] [b=0.6] @@ -98,7 +101,7 @@ local function colorize(n) if trace_verbose then length = length + 1 list[length] = utfchar(getchar(n)) - width = width + getfield(n,"width") -- no kerning yet + width = width + getwidth(n) -- no kerning yet end end end @@ -126,17 +129,8 @@ function builders.paragraphs.expansion.trace(head) return head end -local tasks = nodes.tasks - --- tasks.prependaction("shipouts","normalizers","builders.paragraphs.expansion.trace") --- tasks.disableaction("shipouts","builders.paragraphs.expansion.trace") - local function set(v) - if v then - tasks.enableaction("shipouts","builders.paragraphs.expansion.trace") - else - tasks.disableaction("shipouts","builders.paragraphs.expansion.trace") - end + setaction("shipouts","builders.paragraphs.expansion.trace",v) end trackers.register("builders.paragraphs.expansion.verbose",set) diff --git a/tex/context/base/mkiv/trac-vis.lua b/tex/context/base/mkiv/trac-vis.lua index 52ab3e935..8cca4752b 100644 --- a/tex/context/base/mkiv/trac-vis.lua +++ b/tex/context/base/mkiv/trac-vis.lua @@ -76,6 +76,8 @@ local setlist = nuts.setlist local setleader = nuts.setleader local setsubtype = nuts.setsubtype local setattr = nuts.setattr +local setwidth = nuts.setwidth +local setshift = nuts.setshift local getfield = nuts.getfield local getid = nuts.getid @@ -91,6 +93,11 @@ local getprev = nuts.getprev local getboth = nuts.getboth local getdisc = nuts.getdisc local getwhd = nuts.getwhd +local getkern = nuts.getkern +local getpenalty = nuts.getpenalty +local getdir = nuts.getdir +local getwidth = nuts.getwidth +local getshift = nuts.getshift local hpack_nodes = nuts.hpack local vpack_nodes = nuts.vpack @@ -99,9 +106,8 @@ local flush_node_list = nuts.flush_list local insert_node_before = nuts.insert_before local insert_node_after = nuts.insert_after local traverse_nodes = nuts.traverse -local linked_nodes = nuts.linked local apply_to_nodes = nuts.apply - +local find_tail = nuts.tail local effectiveglue = nuts.effective_glue local hpack_string = nuts.typesetters.tohpack @@ -146,6 +152,8 @@ local bit = number.bit local setbit = number.setbit local clearbit = number.clearbit +local enableaction = nodes.tasks.enableaction + local trace_hbox local trace_vbox local trace_vtop @@ -158,33 +166,35 @@ local trace_whatsit local trace_user local trace_math local trace_italic +local trace_discretionary local report_visualize = logs.reporter("visualize") local modes = { - hbox = 1, - vbox = 2, - vtop = 4, - kern = 8, - glue = 16, - -- skip = 16, - penalty = 32, - fontkern = 64, - strut = 128, - whatsit = 256, - glyph = 512, - simple = 1024, - simplehbox = 1024 + 1, - simplevbox = 1024 + 2, - simplevtop = 1024 + 4, - user = 2048, - math = 4096, - italic = 8192, - origin = 16384, + hbox = 1, + vbox = 2, + vtop = 4, + kern = 8, + glue = 16, + -- skip = 16, + penalty = 32, + fontkern = 64, + strut = 128, + whatsit = 256, + glyph = 512, + simple = 1024, + simplehbox = 1024 + 1, + simplevbox = 1024 + 2, + simplevtop = 1024 + 4, + user = 2048, + math = 4096, + italic = 8192, + origin = 16384, + discretionary = 32768, } local usedfont, exheight, emwidth -local l_penalty, l_glue, l_kern, l_fontkern, l_hbox, l_vbox, l_vtop, l_strut, l_whatsit, l_glyph, l_user, l_math, l_italic, l_origin +local l_penalty, l_glue, l_kern, l_fontkern, l_hbox, l_vbox, l_vtop, l_strut, l_whatsit, l_glyph, l_user, l_math, l_italic, l_origin, l_discretionary local enabled = false local layers = { } @@ -219,21 +229,22 @@ local function enable() } layers[mode] = attributes.viewerlayers.register(tag,true) end - l_hbox = layers.hbox - l_vbox = layers.vbox - l_vtop = layers.vtop - l_glue = layers.glue - l_kern = layers.kern - l_penalty = layers.penalty - l_fontkern = layers.fontkern - l_strut = layers.strut - l_whatsit = layers.whatsit - l_glyph = layers.glyph - l_user = layers.user - l_math = layers.math - l_italic = layers.italic - l_origin = layers.origin - nodes.tasks.enableaction("shipouts","nodes.visualizers.handler") + l_hbox = layers.hbox + l_vbox = layers.vbox + l_vtop = layers.vtop + l_glue = layers.glue + l_kern = layers.kern + l_penalty = layers.penalty + l_fontkern = layers.fontkern + l_strut = layers.strut + l_whatsit = layers.whatsit + l_glyph = layers.glyph + l_user = layers.user + l_math = layers.math + l_italic = layers.italic + l_origin = layers.origin + l_discretionary = layers.discretionary + enableaction("shipouts","nodes.visualizers.handler") report_visualize("enabled") enabled = true tex.setcount("global","c_syst_visualizers_state",1) -- so that we can optimize at the tex end @@ -332,35 +343,37 @@ trackers .register("visualizers.makeup", function(v) set("makeup",v) end) trackers .register("visualizers.boxes", function(v) set("boxes", v) end) directives.register("visualizers.fraction", function(v) fraction = (v and tonumber(v)) or (v == "more" and 5) or 10 end) -local c_positive = "trace:b" -local c_negative = "trace:r" -local c_zero = "trace:g" -local c_text = "trace:s" -local c_space = "trace:y" -local c_skip_a = "trace:c" -local c_skip_b = "trace:m" -local c_glyph = "trace:o" -local c_ligature = "trace:s" -local c_white = "trace:w" -local c_math = "trace:r" -local c_origin = "trace:o" - -local c_positive_d = "trace:db" -local c_negative_d = "trace:dr" -local c_zero_d = "trace:dg" -local c_text_d = "trace:ds" -local c_space_d = "trace:dy" -local c_skip_a_d = "trace:dc" -local c_skip_b_d = "trace:dm" -local c_glyph_d = "trace:do" -local c_ligature_d = "trace:ds" -local c_white_d = "trace:dw" -local c_math_d = "trace:dr" -local c_origin_d = "trace:do" +local c_positive = "trace:b" +local c_negative = "trace:r" +local c_zero = "trace:g" +local c_text = "trace:s" +local c_space = "trace:y" +local c_skip_a = "trace:c" +local c_skip_b = "trace:m" +local c_glyph = "trace:o" +local c_ligature = "trace:s" +local c_white = "trace:w" +local c_math = "trace:r" +local c_origin = "trace:o" +local c_discretionary = "trace:o" + +local c_positive_d = "trace:db" +local c_negative_d = "trace:dr" +local c_zero_d = "trace:dg" +local c_text_d = "trace:ds" +local c_space_d = "trace:dy" +local c_skip_a_d = "trace:dc" +local c_skip_b_d = "trace:dm" +local c_glyph_d = "trace:do" +local c_ligature_d = "trace:ds" +local c_white_d = "trace:dw" +local c_math_d = "trace:dr" +local c_origin_d = "trace:do" +local c_discretionary_d = "trace:do" local function sometext(str,layer,color,textcolor,lap) -- we can just paste verbatim together .. no typesteting needed local text = hpack_string(str,usedfont) - local size = getfield(text,"width") + local size = getwidth(text) local rule = new_rule(size,2*exheight,exheight/2) local kern = new_kern(-size) if color then @@ -369,12 +382,14 @@ local function sometext(str,layer,color,textcolor,lap) -- we can just paste verb if textcolor then setlistcolor(getlist(text),textcolor) end - local info = linked_nodes(rule,kern,text) + local info = setlink(rule,kern,text) setlisttransparency(info,c_zero) info = hpack_nodes(info) - local width = getfield(info,"width") + local width = getwidth(info) if lap then - info = new_hlist(linked_nodes(new_kern(-width),info)) + info = new_hlist(setlink(new_kern(-width),info)) + else + info = new_hlist(info) end if layer then setattr(info,a_layer,layer) @@ -382,476 +397,535 @@ local function sometext(str,layer,color,textcolor,lap) -- we can just paste verb return info, width end -local f_cache = { } +local caches = table.setmetatableindex("table") -local function fontkern(head,current) - local width = getfield(current,"kern") - local extra = getfield(current,"expansion_factor") - local kern = width + extra - local info = f_cache[kern] - -- report_visualize("fontkern: %p ex %p",width,extra) - if info then - -- print("hit fontkern") - else - local text = hpack_string(formatters[" %0.3f"](kern*pt_factor),usedfont) - local rule = new_rule(emwidth/fraction,6*exheight,2*exheight) - local list = getlist(text) - if kern > 0 then - setlistcolor(list,c_positive_d) - elseif kern < 0 then - setlistcolor(list,c_negative_d) +local fontkern do + + local f_cache = caches["fontkern"] + + fontkern = function(head,current) + local width = getkern(current) + local extra = getfield(current,"expansion_factor") + local kern = width + extra + local info = f_cache[kern] + -- report_visualize("fontkern: %p ex %p",width,extra) + if info then + -- print("hit fontkern") else - setlistcolor(list,c_zero_d) + local text = hpack_string(formatters[" %0.3f"](kern*pt_factor),usedfont) + local rule = new_rule(emwidth/fraction,6*exheight,2*exheight) + local list = getlist(text) + if kern > 0 then + setlistcolor(list,c_positive_d) + elseif kern < 0 then + setlistcolor(list,c_negative_d) + else + setlistcolor(list,c_zero_d) + end + setlisttransparency(list,c_text_d) + settransparency(rule,c_text_d) + setshift(text,-5 * exheight) + info = new_hlist(setlink(rule,text)) + setattr(info,a_layer,l_fontkern) + f_cache[kern] = info end - setlisttransparency(list,c_text_d) - settransparency(rule,c_text_d) - setfield(text,"shift",-5 * exheight) - info = new_hlist(linked_nodes(rule,text)) - setattr(info,a_layer,l_fontkern) - f_cache[kern] = info + head = insert_node_before(head,current,copy_list(info)) + return head, current end - head = insert_node_before(head,current,copy_list(info)) - return head, current + end -local w_cache = { } -local tags = { - open = "FIC", - write = "FIW", - close = "FIC", - special = "SPE", - latelua = "LUA", - savepos = "POS", - userdefined = "USR", - -- backend stuff - pdfliteral = "PDF", - pdfrefobj = "PDF", - pdfannot = "PDF", - pdfstartlink = "PDF", - pdfendlink = "PDF", - pdfdest = "PDF", - pdfthread = "PDF", - pdfstartthread = "PDF", - pdfendthread = "PDF", - pdfthreaddata = "PDF", - pdflinkdata = "PDF", - pdfcolorstack = "PDF", - pdfsetmatrix = "PDF", - pdfsave = "PDF", - pdfrestore = "PDF", -} +local whatsit do + + local w_cache = caches["whatsit"] + + local tags = { + open = "FIC", + write = "FIW", + close = "FIC", + special = "SPE", + latelua = "LUA", + savepos = "POS", + userdefined = "USR", + -- backend stuff + pdfliteral = "PDF", + pdfrefobj = "PDF", + pdfannot = "PDF", + pdfstartlink = "PDF", + pdfendlink = "PDF", + pdfdest = "PDF", + pdfthread = "PDF", + pdfstartthread = "PDF", + pdfendthread = "PDF", + pdfthreaddata = "PDF", + pdflinkdata = "PDF", + pdfcolorstack = "PDF", + pdfsetmatrix = "PDF", + pdfsave = "PDF", + pdfrestore = "PDF", + } -local function whatsit(head,current) - local what = getsubtype(current) - local info = w_cache[what] - if info then - -- print("hit whatsit") - else - local tag = whatsitcodes[what] - -- maybe different text colors per tag - info = sometext(formatters["W:%s"](tag and tags[tag] or what),usedfont,nil,c_white) - setattr(info,a_layer,l_whatsit) - w_cache[what] = info + whatsit = function(head,current) + local what = getsubtype(current) + local info = w_cache[what] + if info then + -- print("hit whatsit") + else + local tag = whatsitcodes[what] + -- maybe different text colors per tag + info = sometext(formatters["W:%s"](tag and tags[tag] or what),usedfont,nil,c_white) + setattr(info,a_layer,l_whatsit) + w_cache[what] = info + end + head, current = insert_node_after(head,current,copy_list(info)) + return head, current end - head, current = insert_node_after(head,current,copy_list(info)) - return head, current + end -local u_cache = { } +local user do -local function user(head,current) - local what = getsubtype(current) - local info = u_cache[what] - if info then - -- print("hit user") - else - info = sometext(formatters["U:%s"](what),usedfont) - setattr(info,a_layer,l_user) - u_cache[what] = info + local u_cache = caches["user"] + + user = function(head,current) + local what = getsubtype(current) + local info = u_cache[what] + if info then + -- print("hit user") + else + info = sometext(formatters["U:%s"](what),usedfont) + setattr(info,a_layer,l_user) + u_cache[what] = info + end + head, current = insert_node_after(head,current,copy_list(info)) + return head, current end - head, current = insert_node_after(head,current,copy_list(info)) - return head, current + end -local m_cache = { - beginmath = { }, - endmath = { }, -} -local tags = { - beginmath = "B", - endmath = "E", -} +local math do -local function math(head,current) - local what = getsubtype(current) - local tag = mathcodes[what] - local skip = getfield(current,"surround") + getfield(current,"width") - local info = m_cache[tag][skip] - if info then - -- print("hit math") - else - local text, width = sometext(formatters["M:%s"](tag and tags[tag] or what),usedfont,nil,c_math_d) - local rule = new_rule(skip,-655360/fraction,2*655360/fraction) - setcolor(rule,c_math_d) - settransparency(rule,c_math_d) - setattr(rule,a_layer,l_math) - if tag == "beginmath" then - info = new_hlist(linked_nodes(new_glue(-skip),rule,new_glue(-width),text)) + local m_cache = { + b_cache = caches["bmath"], + e_cache = caches["emath"], + } + + local tags = { + beginmath = "B", + endmath = "E", + } + + math = function(head,current) + local what = getsubtype(current) + local tag = mathcodes[what] + local skip = getkern(current) + getwidth(current) -- surround + local info = m_cache[tag][skip] + if info then + -- print("hit math") else - info = new_hlist(linked_nodes(new_glue(-skip),rule,new_glue(-skip),text)) + local text, width = sometext(formatters["M:%s"](tag and tags[tag] or what),usedfont,nil,c_math_d) + local rule = new_rule(skip,-655360/fraction,2*655360/fraction) + setcolor(rule,c_math_d) + settransparency(rule,c_math_d) + setattr(rule,a_layer,l_math) + if tag == "beginmath" then + info = new_hlist(setlink(new_glue(-skip),rule,new_glue(-width),text)) + else + info = new_hlist(setlink(new_glue(-skip),rule,new_glue(-skip),text)) + end + setattr(info,a_layer,l_math) + m_cache[tag][skip] = info end - setattr(info,a_layer,l_math) - m_cache[tag][skip] = info + head, current = insert_node_after(head,current,copy_list(info)) + return head, current end - head, current = insert_node_after(head,current,copy_list(info)) - return head, current + end -local b_cache = { } +local ruledbox do -local o_cache = table.setmetatableindex(function(t,size) - local rule = new_rule(2*size,size,size) - origin = hpack_nodes(rule) - setcolor(rule,c_origin_d) - settransparency(rule,c_origin_d) - setattr(rule,a_layer,l_origin) - t[size] = origin - return origin -end) + local b_cache = caches["box"] + local o_cache = caches["origin"] -local function ruledbox(head,current,vertical,layer,what,simple,previous,trace_origin,parent) - local wd, ht, dp = getwhd(current) - if wd ~= 0 then - local shift = getfield(current,"shift") - local dir = getfield(current,"dir") --- if dir == "LTL" or dir == "RRT" then --- wd, ht, dp = ht + dp, wd, 0 --- end - local next = getnext(current) - local prev = previous - -- local prev = getprev(current) -- prev can be wrong in math mode < 0.78.3 - setboth(current) - local linewidth = emwidth/fraction - local size = 2*linewidth - local baseline, baseskip - if dp ~= 0 and ht ~= 0 then - if wd > 20*linewidth then - baseline = b_cache.baseline - if not baseline then - -- due to an optimized leader color/transparency we need to set the glue node in order - -- to trigger this mechanism - local leader = linked_nodes(new_glue(size),new_rule(3*size,linewidth,0),new_glue(size)) - leader = hpack_nodes(leader) - baseline = new_glue(0) - setleader(baseline,leader) - setsubtype(baseline,cleaders_code) - setfield(baseline,"stretch",65536) - setfield(baseline,"stretch_order",2) - setlisttransparency(baseline,c_text) - b_cache.baseline = baseline + table.setmetatableindex(o_cache,function(t,size) + local rule = new_rule(2*size,size,size) + local origin = hpack_nodes(rule) + setcolor(rule,c_origin_d) + settransparency(rule,c_origin_d) + setattr(rule,a_layer,l_origin) + t[size] = origin + return origin + end) + + ruledbox = function(head,current,vertical,layer,what,simple,previous,trace_origin,parent) + local wd, ht, dp = getwhd(current) + if wd ~= 0 then + local shift = getshift(current) + local dir = getdir(current) + -- if dir == "LTL" or dir == "RRT" then + -- wd, ht, dp = ht + dp, wd, 0 + -- end + local next = getnext(current) + local prev = previous + -- local prev = getprev(current) -- prev can be wrong in math mode < 0.78.3 + setboth(current) + local linewidth = emwidth/fraction + local size = 2*linewidth + local baseline, baseskip + if dp ~= 0 and ht ~= 0 then + if wd > 20*linewidth then + baseline = b_cache[size] + if not baseline then + -- due to an optimized leader color/transparency we need to set the glue node in order + -- to trigger this mechanism + local leader = setlink(new_glue(size),new_rule(3*size,linewidth,0),new_glue(size)) + leader = hpack_nodes(leader) + baseline = new_glue(0,65536,0,2,0) + setleader(baseline,leader) + setsubtype(baseline,cleaders_code) + setlisttransparency(baseline,c_text) + baseline = hpack_nodes(baseline,wd-size) + b_cache[size] = baseline + end + baseline = copy_list(baseline) + baseskip = new_kern(-wd+linewidth) + else + baseline = new_rule(wd-size,linewidth,0) + baseskip = new_kern(-wd+size) end - baseline = copy_list(baseline) - baseline = hpack_nodes(baseline,wd-size) - -- or new_hlist, set head and also: - -- baseline.width = wd - -- baseline.glue_set = wd/65536 - -- baseline.glue_order = 2 - -- baseline.glue_sign = 1 - baseskip = new_kern(-wd+linewidth) - else - baseline = new_rule(wd-size,linewidth,0) - baseskip = new_kern(-wd+size) end - end - local this - if not simple then - this = b_cache[what] - if not this then - local text = hpack_string(what,usedfont) - this = linked_nodes(new_kern(-getfield(text,"width")),text) - setlisttransparency(this,c_text) - this = new_hlist(this) - b_cache[what] = this + local this + if not simple then + this = b_cache[what] + if not this then + local text = hpack_string(what,usedfont) + this = setlink(new_kern(-getwidth(text)),text) + setlisttransparency(this,c_text) + this = new_hlist(this) + b_cache[what] = this + end end - end - -- we need to trigger the right mode (else sometimes no whatits) - local info = linked_nodes( - this and copy_list(this) or nil, - new_rule(linewidth,ht,dp), - new_rule(wd-size,-dp+linewidth,dp), - new_rule(linewidth,ht,dp), - new_kern(-wd+linewidth), - new_rule(wd-size,ht,-ht+linewidth) - ) - if baseskip then - info = linked_nodes(info,baseskip,baseline) -- could be in previous linked - end - setlisttransparency(info,c_text) - info = new_hlist(info) - -- - setattr(info,a_layer,layer) - if vertical then - if shift == 0 then - info = linked_nodes(current,dp ~= 0 and new_kern(-dp) or nil,info) - elseif trace_origin then - local size = 2*size - local origin = o_cache[size] - origin = copy_list(origin) - if getid(parent) == vlist_code then - setfield(origin,"shift",-shift) - info = linked_nodes(current,new_kern(-size),origin,new_kern(-size-dp),info) + -- we need to trigger the right mode (else sometimes no whatits) + local info = setlink( + this and copy_list(this) or nil, + new_rule(linewidth,ht,dp), + new_rule(wd-size,-dp+linewidth,dp), + new_rule(linewidth,ht,dp), + new_kern(-wd+linewidth), + new_rule(wd-size,ht,-ht+linewidth), + baseskip, + baseskip and baseline or nil + ) + setlisttransparency(info,c_text) + info = new_hlist(info) + -- + setattr(info,a_layer,layer) + if vertical then + if shift == 0 then + info = setlink(current,dp ~= 0 and new_kern(-dp) or nil,info) + elseif trace_origin then + local size = 2*size + local origin = o_cache[size] + origin = copy_list(origin) + if getid(parent) == vlist_code then + setshift(origin,-shift) + info = setlink(current,new_kern(-size),origin,new_kern(-size-dp),info) + else + -- todo .. i need an example + info = setlink(current,dp ~= 0 and new_kern(-dp) or nil,info) + end + setshift(current,0) else - -- todo .. i need an example - info = linked_nodes(current,dp ~= 0 and new_kern(-dp) or nil,info) + info = setlink(current,new_dp ~= 0 and new_kern(-dp) or nil,info) + setshift(current,0) end - setfield(current,"shift",0) + info = new_vlist(info,wd,ht,dp,shift) else - info = linked_nodes(current,new_dp ~= 0 and new_kern(-dp) or nil,info) - setfield(current,"shift",0) + if shift == 0 then + info = setlink(current,new_kern(-wd),info) + elseif trace_origin then + local size = 2*size + local origin = o_cache[size] + origin = copy_list(origin) + if getid(parent) == vlist_code then + info = setlink(current,new_kern(-wd-size-shift),origin,new_kern(-size+shift),info) + else + setshift(origin,-shift) + info = setlink(current,new_kern(-wd-size),origin,new_kern(-size),info) + end + setshift(current,0) + else + info = setlink(current,new_kern(-wd),info) + setshift(current,0) + end + info = new_hlist(info,wd,ht,dp,shift) end - info = new_vlist(info,wd,ht,dp,shift) - else - if shift == 0 then - info = linked_nodes(current,new_kern(-wd),info) - elseif trace_origin then - local size = 2*size - local origin = o_cache[size] - origin = copy_list(origin) - if getid(parent) == vlist_code then - info = linked_nodes(current,new_kern(-wd-size-shift),origin,new_kern(-size+shift),info) + if next then + setlink(info,next) + end + if prev then + if getid(prev) == gluespec_code then + report_visualize("ignoring invalid prev") + -- weird, how can this happen, an inline glue-spec, probably math else - setfield(origin,"shift",-shift) - info = linked_nodes(current,new_kern(-wd-size),origin,new_kern(-size),info) + setlink(prev,info) end - setfield(current,"shift",0) + end + if head == current then + return info, info else - info = linked_nodes(current,new_kern(-wd),info) - setfield(current,"shift",0) + return head, info end - info = new_hlist(info,wd,ht,dp,shift) - end - if next then - setlink(info,next) + else + return head, current end - if prev then - if getid(prev) == gluespec_code then - report_visualize("ignoring invalid prev") - -- weird, how can this happen, an inline glue-spec, probably math + end + +end + +local ruledglyph do + + ruledglyph = function(head,current,previous) -- wrong for vertical glyphs + local wd = getwidth(current) + -- local wd = chardata[getfont(current)][getchar(current)].width + if wd ~= 0 then + local wd, ht, dp = getwhd(current) + -- local dir = getdir(current) + -- if dir == "LTL" or dir = "RTT" then + -- wd, ht, dp = ht + dp, wd, 0 + -- end + local next = getnext(current) + local prev = previous + setboth(current) + local linewidth = emwidth/(2*fraction) + local baseline + -- if dp ~= 0 and ht ~= 0 then + if (dp >= 0 and ht >= 0) or (dp <= 0 and ht <= 0) then + baseline = new_rule(wd-2*linewidth,linewidth,0) + end + local doublelinewidth = 2*linewidth + -- could be a pdf rule (or a user rule now) + local info = setlink( + new_rule(linewidth,ht,dp), + new_rule(wd-doublelinewidth,-dp+linewidth,dp), + new_rule(linewidth,ht,dp), + new_kern(-wd+linewidth), + new_rule(wd-doublelinewidth,ht,-ht+linewidth), + new_kern(-wd+doublelinewidth), + baseline + ) + local char = chardata[getfont(current)][getchar(current)] + if char and type(char.unicode) == "table" then -- hackery test + setlistcolor(info,c_ligature) + setlisttransparency(info,c_ligature_d) else + setlistcolor(info,c_glyph) + setlisttransparency(info,c_glyph_d) + end + info = new_hlist(info) + setattr(info,a_layer,l_glyph) + local info = setlink(current,new_kern(-wd),info) + info = hpack_nodes(info) + setwidth(info,wd) + if next then + setlink(info,next) + end + if prev then setlink(prev,info) end - end - if head == current then - return info, info + if head == current then + return info, info + else + return head, info + end else - return head, info + return head, current end - else - return head, current end + end -local function ruledglyph(head,current,previous) -- wrong for vertical glyphs - local wd = getfield(current,"width") - -- local wd = chardata[getfont(current)][getchar(current)].width - if wd ~= 0 then - local wd, ht, dp = getwhd(current) --- local dir = getfield(current,"dir") --- if dir == "LTL" or dir = "RTT" then --- wd, ht, dp = ht + dp, wd, 0 --- end - local next = getnext(current) - local prev = previous - setboth(current) - local linewidth = emwidth/(2*fraction) - local baseline - -- if dp ~= 0 and ht ~= 0 then - if (dp >= 0 and ht >= 0) or (dp <= 0 and ht <= 0) then - baseline = new_rule(wd-2*linewidth,linewidth,0) - end - local doublelinewidth = 2*linewidth - -- could be a pdf rule (or a user rule now) - local info = linked_nodes( - new_rule(linewidth,ht,dp), - new_rule(wd-doublelinewidth,-dp+linewidth,dp), - new_rule(linewidth,ht,dp), - new_kern(-wd+linewidth), - new_rule(wd-doublelinewidth,ht,-ht+linewidth), - new_kern(-wd+doublelinewidth), - baseline - ) - local char = chardata[getfont(current)][getchar(current)] - if char and type(char.unicode) == "table" then -- hackery test - setlistcolor(info,c_ligature) - setlisttransparency(info,c_ligature_d) +local ruledglue do + + local g_cache_v = caches["vglue"] + local g_cache_h = caches["hglue"] + + local tags = { + -- userskip = "US", + lineskip = "LS", + baselineskip = "BS", + parskip = "PS", + abovedisplayskip = "DA", + belowdisplayskip = "DB", + abovedisplayshortskip = "SA", + belowdisplayshortskip = "SB", + leftskip = "LS", + rightskip = "RS", + topskip = "TS", + splittopskip = "ST", + tabskip = "AS", + spaceskip = "SS", + xspaceskip = "XS", + parfillskip = "PF", + thinmuskip = "MS", + medmuskip = "MM", + thickmuskip = "ML", + leaders = "NL", + cleaders = "CL", + xleaders = "XL", + gleaders = "GL", + -- true = "VS", + -- false = "HS", + } + + -- we sometimes pass previous as we can have issues in math (not watertight for all) + + ruledglue = function(head,current,vertical,parent) + local subtype = getsubtype(current) + local width = effectiveglue(current,parent) + local amount = formatters["%s:%0.3f"](tags[subtype] or (vertical and "VS") or "HS",width*pt_factor) + local info = (vertical and g_cache_v or g_cache_h)[amount] + if info then + -- print("glue hit") else - setlistcolor(info,c_glyph) - setlisttransparency(info,c_glyph_d) - end - info = new_hlist(info) - setattr(info,a_layer,l_glyph) - local info = linked_nodes(current,new_kern(-wd),info) - info = hpack_nodes(info) - setfield(info,"width",wd) - if next then - setlink(info,next) - end - if prev then - setlink(prev,info) + if subtype == space_code or subtype == xspace_code then -- not yet all space + info = sometext(amount,l_glue,c_space) + elseif subtype == leftskip_code or subtype == rightskip_code then + info = sometext(amount,l_glue,c_skip_a) + elseif subtype == userskip_code then + if width > 0 then + info = sometext(amount,l_glue,c_positive) + elseif width < 0 then + info = sometext(amount,l_glue,c_negative) + else + info = sometext(amount,l_glue,c_zero) + end + else + info = sometext(amount,l_glue,c_skip_b) + end + (vertical and g_cache_v or g_cache_h)[amount] = info end - if head == current then - return info, info - else - return head, info + info = copy_list(info) + if vertical then + info = vpack_nodes(info) end - else - return head, current + head, current = insert_node_before(head,current,info) + return head, getnext(current) end + end -local g_cache_v = { } -local g_cache_h = { } - -local tags = { - -- userskip = "US", - lineskip = "LS", - baselineskip = "BS", - parskip = "PS", - abovedisplayskip = "DA", - belowdisplayskip = "DB", - abovedisplayshortskip = "SA", - belowdisplayshortskip = "SB", - leftskip = "LS", - rightskip = "RS", - topskip = "TS", - splittopskip = "ST", - tabskip = "AS", - spaceskip = "SS", - xspaceskip = "XS", - parfillskip = "PF", - thinmuskip = "MS", - medmuskip = "MM", - thickmuskip = "ML", - leaders = "NL", - cleaders = "CL", - xleaders = "XL", - gleaders = "GL", - -- true = "VS", - -- false = "HS", -} +local ruledkern do --- we sometimes pass previous as we can have issues in math (not watertight for all) + local k_cache_v = caches["vkern"] + local k_cache_h = caches["hkern"] -local function ruledglue(head,current,vertical,parent) - local subtype = getsubtype(current) - local width = effectiveglue(current,parent) - local amount = formatters["%s:%0.3f"](tags[subtype] or (vertical and "VS") or "HS",width*pt_factor) - local info = (vertical and g_cache_v or g_cache_h)[amount] - if info then - -- print("glue hit") - else - if subtype == space_code or subtype == xspace_code then -- not yet all space - info = sometext(amount,l_glue,c_space) - elseif subtype == leftskip_code or subtype == rightskip_code then - info = sometext(amount,l_glue,c_skip_a) - elseif subtype == userskip_code then - if width > 0 then - info = sometext(amount,l_glue,c_positive) - elseif width < 0 then - info = sometext(amount,l_glue,c_negative) + ruledkern = function(head,current,vertical) + local kern = getkern(current) + local info = (vertical and k_cache_v or k_cache_h)[kern] + if info then + -- print("kern hit") + else + local amount = formatters["%s:%0.3f"](vertical and "VK" or "HK",kern*pt_factor) + if kern > 0 then + info = sometext(amount,l_kern,c_positive) + elseif kern < 0 then + info = sometext(amount,l_kern,c_negative) else - info = sometext(amount,l_glue,c_zero) + info = sometext(amount,l_kern,c_zero) end - else - info = sometext(amount,l_glue,c_skip_b) + (vertical and k_cache_v or k_cache_h)[kern] = info end - (vertical and g_cache_v or g_cache_h)[amount] = info - end - info = copy_list(info) - if vertical then - info = vpack_nodes(info) + info = copy_list(info) + if vertical then + info = vpack_nodes(info) + end + head, current = insert_node_before(head,current,info) + return head, getnext(current) end - head, current = insert_node_before(head,current,info) - return head, getnext(current) + end -local k_cache_v = { } -local k_cache_h = { } +local ruleditalic do -local function ruledkern(head,current,vertical) - local kern = getfield(current,"kern") - local info = (vertical and k_cache_v or k_cache_h)[kern] - if info then - -- print("kern hit") - else - local amount = formatters["%s:%0.3f"](vertical and "VK" or "HK",kern*pt_factor) - if kern > 0 then - info = sometext(amount,l_kern,c_positive) - elseif kern < 0 then - info = sometext(amount,l_kern,c_negative) + local i_cache = caches["itatalic"] + + ruleditalic = function(head,current) + local kern = getkern(current) + local info = i_cache[kern] + if info then + -- print("kern hit") else - info = sometext(amount,l_kern,c_zero) + local amount = formatters["%s:%0.3f"]("IC",kern*pt_factor) + if kern > 0 then + info = sometext(amount,l_kern,c_positive) + elseif kern < 0 then + info = sometext(amount,l_kern,c_negative) + else + info = sometext(amount,l_kern,c_zero) + end + i_cache[kern] = info end - (vertical and k_cache_v or k_cache_h)[kern] = info - end - info = copy_list(info) - if vertical then - info = vpack_nodes(info) + info = copy_list(info) + head, current = insert_node_before(head,current,info) + return head, getnext(current) end - head, current = insert_node_before(head,current,info) - return head, getnext(current) -end -local i_cache = { } +end -local function ruleditalic(head,current) - local kern = getfield(current,"kern") - local info = i_cache[kern] - if info then - -- print("kern hit") - else - local amount = formatters["%s:%0.3f"]("IC",kern*pt_factor) - if kern > 0 then - info = sometext(amount,l_kern,c_positive) - elseif kern < 0 then - info = sometext(amount,l_kern,c_negative) - else - info = sometext(amount,l_kern,c_zero) +local ruleddiscretionary do + + local d_cache = caches["discretionary"] + + ruleddiscretionary = function(head,current) + local d = d_cache[true] + if not the_discretionary then + local rule = new_rule(4*emwidth/fraction,4*exheight,exheight) + local kern = new_kern(-2*emwidth/fraction) + setlink(kern,rule) + setcolor(rule,c_discretionary_d) + settransparency(rule,c_discretionary_d) + setattr(rule,a_layer,l_discretionary) + d = new_hlist(kern) + d_cache[true] = d end - i_cache[kern] = info + insert_node_after(head,current,copy_list(d)) + return head, current end - info = copy_list(info) - head, current = insert_node_before(head,current,info) - return head, getnext(current) + end -local p_cache_v = { } -local p_cache_h = { } +local ruledpenalty do -local function ruledpenalty(head,current,vertical) - local penalty = getfield(current,"penalty") - local info = (vertical and p_cache_v or p_cache_h)[penalty] - if info then - -- print("penalty hit") - else - local amount = formatters["%s:%s"](vertical and "VP" or "HP",penalty) - if penalty > 0 then - info = sometext(amount,l_penalty,c_positive) - elseif penalty < 0 then - info = sometext(amount,l_penalty,c_negative) + local p_cache_v = caches["vpenalty"] + local p_cache_h = caches["hpenalty"] + + ruledpenalty = function(head,current,vertical) + local penalty = getpenalty(current) + local info = (vertical and p_cache_v or p_cache_h)[penalty] + if info then + -- print("penalty hit") else - info = sometext(amount,l_penalty,c_zero) + local amount = formatters["%s:%s"](vertical and "VP" or "HP",penalty) + if penalty > 0 then + info = sometext(amount,l_penalty,c_positive) + elseif penalty < 0 then + info = sometext(amount,l_penalty,c_negative) + else + info = sometext(amount,l_penalty,c_zero) + end + (vertical and p_cache_v or p_cache_h)[penalty] = info end - (vertical and p_cache_v or p_cache_h)[penalty] = info - end - info = copy_list(info) - if vertical then - info = vpack_nodes(info) - elseif raisepenalties then - setfield(info,"shift",-65536*4) + info = copy_list(info) + if vertical then + info = vpack_nodes(info) + elseif raisepenalties then + setshift(info,-65536*4) + end + head, current = insert_node_before(head,current,info) + return head, getnext(current) end - head, current = insert_node_before(head,current,info) - return head, getnext(current) + end local function visualize(head,vertical,forced,parent) @@ -880,37 +954,39 @@ local function visualize(head,vertical,forced,parent) if a ~= attr then prev_trace_fontkern = trace_fontkern if a == unsetvalue then - trace_hbox = false - trace_vbox = false - trace_vtop = false - trace_kern = false - trace_glue = false - trace_penalty = false - trace_fontkern = false - trace_strut = false - trace_whatsit = false - trace_glyph = false - trace_simple = false - trace_user = false - trace_math = false - trace_italic = false - trace_origin = false + trace_hbox = false + trace_vbox = false + trace_vtop = false + trace_kern = false + trace_glue = false + trace_penalty = false + trace_fontkern = false + trace_strut = false + trace_whatsit = false + trace_glyph = false + trace_simple = false + trace_user = false + trace_math = false + trace_italic = false + trace_origin = false + trace_discretionary = false else -- dead slow: - trace_hbox = hasbit(a, 1) - trace_vbox = hasbit(a, 2) - trace_vtop = hasbit(a, 4) - trace_kern = hasbit(a, 8) - trace_glue = hasbit(a, 16) - trace_penalty = hasbit(a, 32) - trace_fontkern = hasbit(a, 64) - trace_strut = hasbit(a, 128) - trace_whatsit = hasbit(a, 256) - trace_glyph = hasbit(a, 512) - trace_simple = hasbit(a, 1024) - trace_user = hasbit(a, 2048) - trace_math = hasbit(a, 4096) - trace_italic = hasbit(a, 8192) - trace_origin = hasbit(a,16384) + trace_hbox = hasbit(a, 1) + trace_vbox = hasbit(a, 2) + trace_vtop = hasbit(a, 4) + trace_kern = hasbit(a, 8) + trace_glue = hasbit(a, 16) + trace_penalty = hasbit(a, 32) + trace_fontkern = hasbit(a, 64) + trace_strut = hasbit(a, 128) + trace_whatsit = hasbit(a, 256) + trace_glyph = hasbit(a, 512) + trace_simple = hasbit(a, 1024) + trace_user = hasbit(a, 2048) + trace_math = hasbit(a, 4096) + trace_italic = hasbit(a, 8192) + trace_origin = hasbit(a,16384) + trace_discretionary = hasbit(a,32768) end attr = a end @@ -921,6 +997,9 @@ local function visualize(head,vertical,forced,parent) head, current = ruledglyph(head,current,previous) end elseif id == disc_code then + if trace_discretionary then + head, current = ruleddiscretionary(head,current) + end local pre, post, replace = getdisc(current) if pre then pre = visualize(pre,false,a,parent) @@ -996,46 +1075,21 @@ end do - local function freed(cache) - local n = 0 - for k, v in next, cache do - flush_node_list(v) - n = n + 1 + local function cleanup() + for tag, cache in next, caches do + for k, v in next, cache do + flush_node_list(v) + end end - if n == 0 then - return 0, cache - else - return n, { } + cleanup = function() + report_visualize("error, duplicate cleanup") end end - local function cleanup() - local hf, nw, nb, ng_v, ng_h, np_v, np_h, nk_v, nk_h - nf, f_cache = freed(f_cache) - nw, w_cache = freed(w_cache) - nb, b_cache = freed(b_cache) - no, o_cache = freed(o_cache) - ng_v, g_cache_v = freed(g_cache_v) - ng_h, g_cache_h = freed(g_cache_h) - np_v, p_cache_v = freed(p_cache_v) - np_h, p_cache_h = freed(p_cache_h) - nk_v, k_cache_v = freed(k_cache_v) - nk_h, k_cache_h = freed(k_cache_h) - -- report_visualize("cache cleanup: %s fontkerns, %s skips, %s penalties, %s kerns, %s whatsits, %s boxes, %s origins", - -- nf,ng_v+ng_h,np_v+np_h,nk_v+nk_h,nw,nb,no) - end - local function handler(head) if usedfont then starttiming(visualizers) - -- local l = texgetattribute(a_layer) - -- local v = texgetattribute(a_visual) - -- texsetattribute(a_layer,unsetvalue) - -- texsetattribute(a_visual,unsetvalue) head = visualize(tonut(head),true) - -- texsetattribute(a_layer,l) - -- texsetattribute(a_visual,v) - -- -- cleanup() stoptiming(visualizers) return tonode(head), true else diff --git a/tex/context/base/mkiv/trac-vis.mkiv b/tex/context/base/mkiv/trac-vis.mkiv index a503981f5..894408222 100644 --- a/tex/context/base/mkiv/trac-vis.mkiv +++ b/tex/context/base/mkiv/trac-vis.mkiv @@ -39,7 +39,7 @@ \newconstant\c_syst_visualizers_state \newtoks \t_syst_visualizers_optimize -\definesystemattribute[visual][public,global] % global ? +% \definesystemattribute[visual][public,global] % already defined % no, but can become an option: % diff --git a/tex/context/base/mkiv/typo-brk.lua b/tex/context/base/mkiv/typo-brk.lua index 749c25a33..84eff0654 100644 --- a/tex/context/base/mkiv/typo-brk.lua +++ b/tex/context/base/mkiv/typo-brk.lua @@ -32,11 +32,15 @@ local getsubtype = nuts.getsubtype local getfont = nuts.getfont local getid = nuts.getid local getfield = nuts.getfield -local getattr = nuts.getattr +----- getattr = nuts.getattr +local getattrlist = nuts.getattrlist +local takeattr = nuts.takeattr +local getlang = nuts.getlang local isglyph = nuts.isglyph local setfield = nuts.setfield local setattr = nuts.setattr +local setattrlist = nuts.setattrlist local setlink = nuts.setlink local setchar = nuts.setchar local setdisc = nuts.setdisc @@ -59,7 +63,7 @@ local texsetattribute = tex.setattribute local unsetvalue = attributes.unsetvalue local nodepool = nuts.pool -local tasks = nodes.tasks +local enableaction = nodes.tasks.enableaction local v_reset = interfaces.variables.reset local v_yes = interfaces.variables.yes @@ -109,19 +113,21 @@ end -- todo: use boundaries -local function withattribute(n,a) - setfield(n,"attr",a) - return n -end - local function insert_break(head,start,stop,before,after,kern) - local a = getfield(start,"attr") if not kern then - insert_node_before(head,start,withattribute(new_penalty(before),a)) - insert_node_before(head,start,withattribute(new_glue(0),a)) + local p = new_penalty(before) + local g = new_glue() + setattrlist(p,start) + setattrlist(g,start) + insert_node_before(head,start,p) + insert_node_before(head,start,g) end - insert_node_after(head,stop,withattribute(new_glue(0),a)) - insert_node_after(head,stop,withattribute(new_penalty(after),a)) + local p = new_penalty(after) + local g = new_glue() + setattrlist(p,start) + setattrlist(g,start) + insert_node_after(head,stop,g) + insert_node_after(head,stop,p) end methods[1] = function(head,start,stop,settings,kern) @@ -142,14 +148,8 @@ methods[6] = function(head,start,stop,settings,kern) local l = new_wordboundary() local d = new_disc() local r = new_wordboundary() - local a = getfield(start,"attr") - -- setfield(l,"attr",a) - setfield(d,"attr",a) -- otherwise basemode is forces and we crash - -- setfield(r,"attr",a) - setlink(p,l) - setlink(l,d) - setlink(d,r) - setlink(r,n) + setattrlist(d,start) -- otherwise basemode is forced and we crash + setlink(p,l,d,r,n) if start == stop then setboth(start) setdisc(d,start,nil,copy_node(start)) @@ -167,16 +167,14 @@ end methods[2] = function(head,start) -- ( => (- local p, n = getboth(start) if p and n then - local tmp - head, start, tmp = remove_node(head,start) - head, start = insert_node_before(head,start,new_disc()) - setfield(start,"attr",getfield(tmp,"attr")) - setfield(start,"replace",tmp) - local tmp = copy_node(tmp) - local hyphen = copy_node(tmp) - setchar(hyphen,languages.prehyphenchar(getfield(tmp,"lang"))) - setlink(tmp,hyphen) - setfield(start,"post",tmp) + local replace + head, start, replace = remove_node(head,start) + local post = copy_node(replace) + local hyphen = copy_node(post) + setchar(hyphen,languages.prehyphenchar(getlang(post))) + setlink(post,hyphen) + head, start = insert_node_before(head,start,new_disc(nil,post,replace)) + setattrlist(start,replace) insert_break(head,start,start,10000,10000) end return head, start @@ -185,16 +183,14 @@ end methods[3] = function(head,start) -- ) => -) local p, n = getboth(start) if p and n then - local tmp - head, start, tmp = remove_node(head,start) - head, start = insert_node_before(head,start,new_disc()) - setfield(start,"attr",getfield(tmp,"attr")) - setfield(start,"replace",tmp) - local tmp = copy_node(tmp) - local hyphen = copy_node(tmp) - setchar(hyphen,languages.prehyphenchar(getfield(tmp,"lang"))) - setlink(hyphen,tmp) - setfield(start,"pre",hyphen) + local replace + head, start, replace = remove_node(head,start) + local pre = copy_node(replace) + local hyphen = copy_node(pre) + setchar(hyphen,languages.prehyphenchar(getlang(pre))) + setlink(hyphen,pre) + head, start = insert_node_before(head,start,new_disc(hyphen,nil,replace)) -- so not pre ! + setattrlist(start,tmp) insert_break(head,start,start,10000,10000) end return head, start @@ -206,7 +202,7 @@ methods[4] = function(head,start) -- - => - - - local tmp head, start, tmp = remove_node(head,start) head, start = insert_node_before(head,start,new_disc()) - setfield(start,"attr",getfield(tmp,"attr")) + setattrlist(start,tmp) setdisc(start,copy_node(tmp),copy_node(tmp),tmp) insert_break(head,start,start,10000,10000) end @@ -218,11 +214,11 @@ methods[5] = function(head,start,stop,settings) -- x => p q r if p and n then local tmp head, start, tmp = remove_node(head,start) - head, start = insert_node_before(head,start,new_disc()) - local attr = getfield(tmp,"attr") - local font = getfont(tmp) - local left = settings.left - local right = settings.right + head, start = insert_node_before(head,start,new_disc()) + local attr = getattrlist(tmp) + local font = getfont(tmp) + local left = settings.left + local right = settings.right local middle = settings.middle if left then left = tonodes(tostring(left),font,attr) @@ -234,7 +230,7 @@ methods[5] = function(head,start,stop,settings) -- x => p q r middle = tonodes(tostring(middle),font,attr) end setdisc(start,left,right,middle) - setfield(start,"attr",attr) -- todo: critical only -- just a copy will do + setattrlist(start,attr) flush_node(tmp) insert_break(head,start,start,10000,10000) end @@ -254,7 +250,8 @@ function breakpoints.handler(head) while current do local char, id = isglyph(current) if char then - local a = getattr(current,a_breakpoints) + -- local a = getattr(current,a_breakpoints) + local a = takeattr(current,a_breakpoints) if a and a > 0 then if a ~= attr then local data = mapping[a] @@ -268,10 +265,10 @@ function breakpoints.handler(head) if map then local cmap = map[char] if cmap then - setattr(current,a_breakpoints,unsetvalue) -- should not be needed + -- setattr(current,a_breakpoints,unsetvalue) -- should not be needed -- for now we collect but when found ok we can move the handler here -- although it saves nothing in terms of performance - local lang = getfield(current,"lang") + local lang = getlang(current) local smap = lang and lang >= 0 and lang < 0x7FFF and (cmap[numbers[lang]] or cmap[""]) if smap then local skip = smap.skip @@ -328,7 +325,7 @@ function breakpoints.handler(head) local stop = data[2] local cmap = data[3] local smap = data[4] --- local lang = getfield(start,"lang") +-- local lang = getlang(start) -- -- we do a sanity check for language -- local smap = lang and lang >= 0 and lang < 0x7FFF and (cmap[numbers[lang]] or cmap[""]) -- if smap then @@ -450,7 +447,7 @@ function breakpoints.set(n) if trace_breakpoints then report_breakpoints("enabling breakpoints handler") end - tasks.enableaction("processors","typesetters.breakpoints.handler") + enableaction("processors","typesetters.breakpoints.handler") end n = n.number end @@ -458,10 +455,6 @@ function breakpoints.set(n) texsetattribute(a_breakpoints,n) end --- function breakpoints.enable() --- tasks.enableaction("processors","typesetters.breakpoints.handler") --- end - -- interface implement { diff --git a/tex/context/base/mkiv/typo-cap.lua b/tex/context/base/mkiv/typo-cap.lua index 972c5ea20..6bf4669df 100644 --- a/tex/context/base/mkiv/typo-cap.lua +++ b/tex/context/base/mkiv/typo-cap.lua @@ -25,7 +25,8 @@ local getfield = nuts.getfield local getnext = nuts.getnext local getprev = nuts.getprev local getid = nuts.getid -local getattr = nuts.getattr +----- getattr = nuts.getattr +local takeattr = nuts.takeattr local getfont = nuts.getfont local getsubtype = nuts.getsubtype local getchar = nuts.getchar @@ -34,11 +35,13 @@ local getdisc = nuts.getdisc local setfield = nuts.setfield local setattr = nuts.setattr local setchar = nuts.setchar +local setfont = nuts.setfont local copy_node = nuts.copy local end_of_math = nuts.end_of_math local traverse_id = nuts.traverse_id local insert_after = nuts.insert_after +local find_attribute = nuts.find_attribute local nodecodes = nodes.nodecodes local skipcodes = nodes.skipcodes @@ -51,7 +54,7 @@ local math_code = nodecodes.math local kerning_code = kerncodes.kerning -local tasks = nodes.tasks +local enableaction = nodes.tasks.enableaction local newkern = nuts.pool.kern @@ -214,7 +217,7 @@ end -- elseif dc == char then -- local lfa = lastfont[n] -- if lfa then --- setfield(first,"font",lfa) +-- setfont(first,lfa) -- return start, true, true -- else -- return start, false, true @@ -237,7 +240,7 @@ local function mixed(start,attr,lastfont,n,count,where,first) elseif dc == char then local lfa = lastfont[n] if lfa then - setfield(used,"font",lfa) + setfont(used,lfa) return start, true, true else return start, false, true @@ -274,7 +277,7 @@ local function Capital(start,attr,lastfont,n,count,where,first,once) -- 3 if lfa then local dc = uccodes[getchar(used)] if dc then - setfield(used,"font",lfa) + setfont(used,lfa) end end end @@ -335,17 +338,18 @@ register(variables.cap, variables.capital) -- clone register(variables.Cap, variables.Capital) -- clone function cases.handler(head) -- not real fast but also not used on much data + local start = tonut(head) local lastfont = { } local lastattr = nil local done = false - local start = tonut(head) local count = 0 local previd = nil local prev = nil while start do -- while because start can jump ahead local id = getid(start) if id == glyph_code then - local attr = getattr(start,a_cases) + -- local attr = getattr(start,a_cases) + local attr = takeattr(start,a_cases) if attr and attr > 0 and not blocked[attr] then if attr ~= lastattr then lastattr = attr @@ -353,7 +357,7 @@ function cases.handler(head) -- not real fast but also not used on much data else count = count + 1 end - setattr(start,a_cases,unsetvalue) + -- setattr(start,a_cases,unsetvalue) -- not needed local n, id, m = get(attr) if lastfont[n] == nil then lastfont[n] = id @@ -372,13 +376,14 @@ function cases.handler(head) -- not real fast but also not used on much data end end elseif id == disc_code then - local attr = getattr(start,a_cases) + -- local attr = getattr(start,a_cases) + local attr = takeattr(start,a_cases) if attr and attr > 0 and not blocked[attr] then if attr ~= lastattr then lastattr = attr count = 0 end - setattr(start,a_cases,unsetvalue) + -- setattr(start,a_cases,unsetvalue) -- not needed local n, id, m = get(attr) if lastfont[n] == nil then lastfont[n] = id @@ -390,6 +395,7 @@ function cases.handler(head) -- not real fast but also not used on much data local cnt = count for g in traverse_id(glyph_code,replace) do cnt = cnt + 1 + takeattr(g,a_cases) -- setattr(g,a_cases,unsetvalue) local _, _, quit = action(start,attr,lastfont,n,cnt,"replace",g) if quit then break end @@ -399,6 +405,7 @@ function cases.handler(head) -- not real fast but also not used on much data local cnt = count for g in traverse_id(glyph_code,pre) do cnt = cnt + 1 + takeattr(g,a_cases) -- setattr(g,a_cases,unsetvalue) local _, _, quit = action(start,attr,lastfont,n,cnt,"pre",g) if quit then break end @@ -408,6 +415,7 @@ function cases.handler(head) -- not real fast but also not used on much data local cnt = count for g in traverse_id(glyph_code,post) do cnt = cnt + 1 + takeattr(g,a_cases) -- setattr(g,a_cases,unsetvalue) local _, _, quit = action(start,attr,lastfont,n,cnt,"post",g) if quit then break end @@ -420,7 +428,7 @@ function cases.handler(head) -- not real fast but also not used on much data start = end_of_math(start) count = 0 elseif prev_id == kern_code and getsubtype(prev) == kerning_code then - -- still inside a word ...nomally kerns are added later + -- still inside a word ...normally kerns are added later else count = 0 end @@ -433,6 +441,120 @@ function cases.handler(head) -- not real fast but also not used on much data return head, done end +-- function cases.handler(head) -- not real fast but also not used on much data +-- local attr, start = find_attribute(tonut(head),a_cases) +-- if not start then +-- return head, false +-- end +-- local lastfont = { } +-- local lastattr = nil +-- local done = false +-- local count = 0 +-- local previd = nil +-- local prev = nil +-- while start do +-- while start do -- while because start can jump ahead +-- local id = getid(start) +-- if id == glyph_code then +-- -- local attr = getattr(start,a_cases) +-- local attr = takeattr(start,a_cases) +-- if attr and attr > 0 and not blocked[attr] then +-- if attr ~= lastattr then +-- lastattr = attr +-- count = 1 +-- else +-- count = count + 1 +-- end +-- -- setattr(start,a_cases,unsetvalue) -- not needed +-- local n, id, m = get(attr) +-- if lastfont[n] == nil then +-- lastfont[n] = id +-- end +-- local action = actions[n] -- map back to low number +-- if action then +-- start, ok = action(start,attr,lastfont,n,count) +-- if ok then +-- done = true +-- end +-- if trace_casing then +-- report_casing("case trigger %a, instance %a, fontid %a, result %a",n,m,id,ok) +-- end +-- elseif trace_casing then +-- report_casing("unknown case trigger %a",n) +-- end +-- end +-- elseif id == disc_code then +-- -- local attr = getattr(start,a_cases) +-- local attr = takeattr(start,a_cases) +-- if attr and attr > 0 and not blocked[attr] then +-- if attr ~= lastattr then +-- lastattr = attr +-- count = 0 +-- end +-- -- setattr(start,a_cases,unsetvalue) -- not needed +-- local n, id, m = get(attr) +-- if lastfont[n] == nil then +-- lastfont[n] = id +-- end +-- local action = actions[n] -- map back to low number +-- if action then +-- local pre, post, replace = getdisc(start) +-- if replace then +-- local cnt = count +-- for g in traverse_id(glyph_code,replace) do +-- cnt = cnt + 1 +-- takeattr(g,a_cases) +-- -- setattr(g,a_cases,unsetvalue) +-- local _, _, quit = action(start,attr,lastfont,n,cnt,"replace",g) +-- if quit then break end +-- end +-- end +-- if pre then +-- local cnt = count +-- for g in traverse_id(glyph_code,pre) do +-- cnt = cnt + 1 +-- takeattr(g,a_cases) +-- -- setattr(g,a_cases,unsetvalue) +-- local _, _, quit = action(start,attr,lastfont,n,cnt,"pre",g) +-- if quit then break end +-- end +-- end +-- if post then +-- local cnt = count +-- for g in traverse_id(glyph_code,post) do +-- cnt = cnt + 1 +-- takeattr(g,a_cases) +-- -- setattr(g,a_cases,unsetvalue) +-- local _, _, quit = action(start,attr,lastfont,n,cnt,"post",g) +-- if quit then break end +-- end +-- end +-- end +-- count = count + 1 +-- end +-- elseif id == math_code then +-- start = end_of_math(start) +-- count = 0 +-- elseif prev_id == kern_code and getsubtype(prev) == kerning_code then +-- -- still inside a word ...normally kerns are added later +-- else +-- count = 0 +-- start = getnext(start) +-- break +-- end +-- if start then +-- prev = start +-- previd = id +-- start = getnext(start) +-- end +-- end +-- if start then +-- attr, start = find_attribute(start,a_cases) +-- end +-- end +-- return head, done +-- end + -- function cases.handler(head) -- let's assume head doesn't change ... no reason -- local done = false -- local lastfont = { } @@ -461,7 +583,7 @@ function cases.set(n,id) n = registered[n] or tonumber(n) if n then if not enabled then - tasks.enableaction("processors","typesetters.cases.handler") + enableaction("processors","typesetters.cases.handler") if trace_casing then report_casing("enabling case handler") end diff --git a/tex/context/base/mkiv/typo-cap.mkiv b/tex/context/base/mkiv/typo-cap.mkiv index 114532e4e..96f3e28d6 100644 --- a/tex/context/base/mkiv/typo-cap.mkiv +++ b/tex/context/base/mkiv/typo-cap.mkiv @@ -20,7 +20,7 @@ \registerctxluafile{typo-cap}{1.001} -\definesystemattribute[case][public] +% \definesystemattribute[case][public] % already predefined %D \macros %D {setupcapitals} diff --git a/tex/context/base/mkiv/typo-cln.lua b/tex/context/base/mkiv/typo-cln.lua index bc11f944c..53452f838 100644 --- a/tex/context/base/mkiv/typo-cln.lua +++ b/tex/context/base/mkiv/typo-cln.lua @@ -24,7 +24,8 @@ local cleaners = typesetters.cleaners local variables = interfaces.variables local nodecodes = nodes.nodecodes -local tasks = nodes.tasks + +local enableaction = nodes.tasks.enableaction local texsetattribute = tex.setattribute @@ -91,7 +92,7 @@ function cleaners.set(n) texsetattribute(a_cleaner,unsetvalue) else if not enabled then - tasks.enableaction("processors","typesetters.cleaners.handler") + enableaction("processors","typesetters.cleaners.handler") if trace_cleaners then report_cleaners("enabling cleaners") end diff --git a/tex/context/base/mkiv/typo-dha.lua b/tex/context/base/mkiv/typo-dha.lua index bdba20878..a32f72e46 100644 --- a/tex/context/base/mkiv/typo-dha.lua +++ b/tex/context/base/mkiv/typo-dha.lua @@ -58,6 +58,7 @@ local getlist = nuts.getlist local getfield = nuts.getfield local getattr = nuts.getattr local getprop = nuts.getprop +local getdir = nuts.getdir local isglyph = nuts.isglyph -- or ischar local setfield = nuts.setfield @@ -312,7 +313,7 @@ local function process(start) elseif id == kern_code then setprop(current,"direction",'k') elseif id == dir_code then - local dir = getfield(current,"dir") + local dir = getdir(current) if dir == "+TRT" then autodir = -1 elseif dir == "+TLT" then @@ -329,7 +330,7 @@ local function process(start) textdir = autodir setprop(current,"direction",true) elseif id == localpar_code then - local dir = getfield(current,"dir") + local dir = getdir(current) if dir == 'TRT' then autodir = -1 elseif dir == 'TLT' then diff --git a/tex/context/base/mkiv/typo-dig.lua b/tex/context/base/mkiv/typo-dig.lua index 076761ad9..3d60131c7 100644 --- a/tex/context/base/mkiv/typo-dig.lua +++ b/tex/context/base/mkiv/typo-dig.lua @@ -28,13 +28,13 @@ local getprev = nuts.getprev local getfont = nuts.getfont local getchar = nuts.getchar local getid = nuts.getid +local getwidth = nuts.getwidth local getfield = nuts.getfield -local getattr = nuts.getattr +local takeattr = nuts.takeattr local setlink = nuts.setlink local setnext = nuts.setnext local setprev = nuts.setprev -local setattr = nuts.setattr local hpack_node = nuts.hpack local traverse_id = nuts.traverse_id @@ -48,7 +48,7 @@ local nodecodes = nodes.nodecodes local glyph_code = nodecodes.glyph local nodepool = nuts.pool -local tasks = nodes.tasks +local enableaction = nodes.tasks.enableaction local new_glue = nodepool.glue @@ -104,7 +104,7 @@ actions[1] = function(head,start,attr) local char = getchar(start) local unic = chardata[font][char].unicode or char if charbase[unic].category == "nd" then -- ignore unic tables - local oldwidth = getfield(start,"width") + local oldwidth = getwidth(start) local newwidth = getdigitwidth(font) if newwidth ~= oldwidth then if trace_digits then @@ -123,9 +123,8 @@ function digits.handler(head) local done, current, ok = false, head, false while current do if getid(current) == glyph_code then - local attr = getattr(current,a_digits) + local attr = takeattr(current,a_digits) if attr and attr > 0 then - setattr(current,a_digits,unsetvalue) local action = actions[attr%100] -- map back to low number if action then head, current, ok = action(head,current,attr) @@ -151,7 +150,7 @@ function digits.set(n) -- number or 'reset' n = tonumber(n) if n then if not enabled then - tasks.enableaction("processors","typesetters.digits.handler") + enableaction("processors","typesetters.digits.handler") if trace_digits then report_digits("enabling digit handler") end diff --git a/tex/context/base/mkiv/typo-dir.lua b/tex/context/base/mkiv/typo-dir.lua index 4422a15de..5ecf77a1f 100644 --- a/tex/context/base/mkiv/typo-dir.lua +++ b/tex/context/base/mkiv/typo-dir.lua @@ -44,7 +44,7 @@ local hasbit = number.hasbit local texsetattribute = tex.setattribute local unsetvalue = attributes.unsetvalue -local tasks = nodes.tasks +local enableaction = nodes.tasks.enableaction local tracers = nodes.tracers local setcolor = tracers.colors.set local resetcolor = tracers.colors.reset @@ -180,16 +180,12 @@ statistics.register("text directions", function() end end) --- function directions.enable() --- tasks.enableaction("processors","directions.handler") --- end - function directions.set(n) -- todo: names and numbers if not enabled then if trace_textdirections then report_textdirections("enabling directions handler") end - tasks.enableaction("processors","typesetters.directions.handler") + enableaction("processors","typesetters.directions.handler") enabled = true end if not n or n == 0 then diff --git a/tex/context/base/mkiv/typo-drp.lua b/tex/context/base/mkiv/typo-drp.lua index 0683a3472..e27ad75f3 100644 --- a/tex/context/base/mkiv/typo-drp.lua +++ b/tex/context/base/mkiv/typo-drp.lua @@ -22,7 +22,10 @@ local initials = typesetters.paragraphs or { } typesetters.initials = initials or { } local nodes = nodes + local tasks = nodes.tasks +local enableaction = tasks.enableaction +local disableaction = tasks.disableaction local nuts = nodes.nuts local tonut = nuts.tonut @@ -42,8 +45,11 @@ local setattr = nuts.setattr local setlink = nuts.setlink local setprev = nuts.setprev local setnext = nuts.setnext +local setfont = nuts.setfont local setchar = nuts.setchar local setwhd = nuts.setwhd +local setkern = nuts.setkern +local setoffsets = nuts.setoffsets local hpack_nodes = nuts.hpack @@ -91,7 +97,7 @@ local settings = nil function initials.set(specification) settings = specification or { } settings.enabled = true - tasks.enableaction("processors","typesetters.initials.handler") + enableaction("processors","typesetters.initials.handler") if trace_initials then report_initials("enabling initials") end @@ -250,11 +256,11 @@ actions[v_default] = function(head,setting) while true do local id = getid(current) if id == kern_code then - setfield(current,"kern",0) + setkern(current,0) elseif id == glyph_code then local next = getnext(current) if font then - setfield(current,"font",font) + setfont(current,font) end if dynamic > 0 then setattr(current,0,dynamic) @@ -316,8 +322,7 @@ actions[v_default] = function(head,setting) -- local hoffset = width + hoffset + distance + (indent and parindent or 0) for current in traverse_id(glyph_code,first) do - setfield(current,"xoffset",- hoffset ) - setfield(current,"yoffset",- voffset) -- no longer - height here + setoffsets(current,-hoffset,-voffset) -- no longer - height here if current == last then break end @@ -366,7 +371,7 @@ function initials.handler(head) end if attr then -- here as we can process nested boxes first so we need to keep state - tasks.disableaction("processors","typesetters.initials.handler") + disableaction("processors","typesetters.initials.handler") -- texsetattribute(attribute,unsetvalue) local alternative = settings.alternative or v_default local action = actions[alternative] or actions[v_default] diff --git a/tex/context/base/mkiv/typo-dua.lua b/tex/context/base/mkiv/typo-dua.lua index 596503dbc..c2f3c2763 100644 --- a/tex/context/base/mkiv/typo-dua.lua +++ b/tex/context/base/mkiv/typo-dua.lua @@ -77,10 +77,13 @@ local getlist = nuts.getlist local getchar = nuts.getchar local getfield = nuts.getfield local getprop = nuts.getprop +local getdir = nuts.getdir local setfield = nuts.setfield local setprop = nuts.setprop local setchar = nuts.setchar +local setdir = nuts.setdir +----- setattrlist = nuts.setattrlist local remove_node = nuts.remove local insert_node_after = nuts.insert_after @@ -232,7 +235,7 @@ local function build_list(head) -- todo: store node pointer ... saves loop list[size] = { char = 0x0020, direction = "ws", original = "ws", level = 0 } current = getnext(current) elseif id == dir_code then - local dir = getfield(current,"dir") + local dir = getdir(current) if dir == "+TLT" then list[size] = { char = 0x202A, direction = "lre", original = "lre", level = 0 } elseif dir == "+TRT" then @@ -324,7 +327,7 @@ end local function get_baselevel(head,list,size) -- todo: skip if first is object (or pass head and test for localpar) local id = getid(head) if id == localpar_code then - if getfield(head,"dir") == "TRT" then + if getdir(head) == "TRT" then return 1, "TRT", true else return 0, "TLT", true @@ -747,13 +750,13 @@ local function apply_to_list(list,size,head,pardir) setcolor(current,direction,false,mirror) end elseif id == hlist_code or id == vlist_code then - setfield(current,"dir",pardir) -- is this really needed? + setdir(current,pardir) -- is this really needed? elseif id == glue_code then if enddir and getsubtype(current) == parfillskip_code then -- insert the last enddir before \parfillskip glue local d = new_textdir(enddir) setprop(d,"directions",true) - -- setfield(d,"attr",getfield(current,"attr")) + -- setattrlist(d,current) head = insert_node_before(head,current,d) enddir = false done = true @@ -763,7 +766,7 @@ local function apply_to_list(list,size,head,pardir) -- localpar should always be the 1st node local d = new_textdir(begindir) setprop(d,"directions",true) - -- setfield(d,"attr",getfield(current,"attr")) + -- setattrlist(d,current) head, current = insert_node_after(head,current,d) begindir = nil done = true @@ -772,7 +775,7 @@ local function apply_to_list(list,size,head,pardir) if begindir then local d = new_textdir(begindir) setprop(d,"directions",true) - -- setfield(d,"attr",getfield(current,"attr")) + -- setattrlist(d,current) head = insert_node_before(head,current,d) done = true end @@ -786,7 +789,7 @@ local function apply_to_list(list,size,head,pardir) if enddir then local d = new_textdir(enddir) setprop(d,"directions",true) - -- setfield(d,"attr",getfield(current,"attr")) + -- setattrlist(d,current) head, current = insert_node_after(head,current,d) done = true end diff --git a/tex/context/base/mkiv/typo-dub.lua b/tex/context/base/mkiv/typo-dub.lua index 5a60a11e6..eea743c6d 100644 --- a/tex/context/base/mkiv/typo-dub.lua +++ b/tex/context/base/mkiv/typo-dub.lua @@ -66,10 +66,13 @@ local getchar = nuts.getchar local getattr = nuts.getattr local getfield = nuts.getfield local getprop = nuts.getprop +local getdir = nuts.getdir local setfield = nuts.setfield local setprop = nuts.setprop local setchar = nuts.setchar +local setdir = nuts.setdir +local setattrlist = nuts.setattrlist local remove_node = nuts.remove local insert_node_after = nuts.insert_after @@ -281,7 +284,7 @@ local function build_list(head) -- todo: store node pointer ... saves loop list[size] = { char = 0x0020, direction = "ws", original = "ws", level = 0 } current = getnext(current) elseif id == dir_code then - local dir = getfield(current,"dir") + local dir = getdir(current) if dir == "+TLT" then list[size] = { char = 0x202A, direction = "lre", original = "lre", level = 0 } elseif dir == "+TRT" then @@ -396,7 +399,7 @@ end local function get_baselevel(head,list,size) -- todo: skip if first is object (or pass head and test for localpar) local id = getid(head) if id == localpar_code then - if getfield(head,"dir") == "TRT" then + if getdir(head) == "TRT" then return 1, "TRT", true else return 0, "TLT", true @@ -894,13 +897,13 @@ local function apply_to_list(list,size,head,pardir) setcolor(current,direction,false,mirror) end elseif id == hlist_code or id == vlist_code then - setfield(current,"dir",pardir) -- is this really needed? + setdir(current,pardir) -- is this really needed? elseif id == glue_code then if enddir and getsubtype(current) == parfillskip_code then -- insert the last enddir before \parfillskip glue local d = new_textdir(enddir) setprop(d,"directions",true) - -- setfield(d,"attr",getfield(current,"attr")) + -- setattrlist(d,current) head = insert_node_before(head,current,d) enddir = false done = true @@ -910,7 +913,7 @@ local function apply_to_list(list,size,head,pardir) -- localpar should always be the 1st node local d = new_textdir(begindir) setprop(d,"directions",true) - -- setfield(d,"attr",getfield(current,"attr")) + -- setattrlist(d,current) head, current = insert_node_after(head,current,d) begindir = nil done = true @@ -919,7 +922,7 @@ local function apply_to_list(list,size,head,pardir) if begindir then local d = new_textdir(begindir) setprop(d,"directions",true) - -- setfield(d,"attr",getfield(current,"attr")) + -- setattrlist(d,current) head = insert_node_before(head,current,d) done = true end @@ -933,7 +936,7 @@ local function apply_to_list(list,size,head,pardir) if enddir then local d = new_textdir(enddir) setprop(d,"directions",true) - -- setfield(d,"attr",getfield(current,"attr")) + -- setattrlist(d,current) head, current = insert_node_after(head,current,d) done = true end diff --git a/tex/context/base/mkiv/typo-duc.lua b/tex/context/base/mkiv/typo-duc.lua index dfb69bcba..7fd49e54e 100644 --- a/tex/context/base/mkiv/typo-duc.lua +++ b/tex/context/base/mkiv/typo-duc.lua @@ -67,10 +67,13 @@ local getlist = nuts.getlist local getattr = nuts.getattr local getfield = nuts.getfield local getprop = nuts.getprop +local getdir = nuts.getdir local setfield = nuts.setfield local setprop = nuts.setprop local setchar = nuts.setchar +local setdir = nuts.setdir +local setattrlist = nuts.setattrlist local properties = nodes.properties @@ -288,7 +291,7 @@ local function build_list(head) -- todo: store node pointer ... saves loop setmetatable(t,mt_space) current = getnext(current) elseif id == dir_code then - local dir = getfield(current,"dir") + local dir = getdir(current) if dir == "+TLT" then t = { } setmetatable(t,mt_lre) @@ -412,7 +415,7 @@ end local function get_baselevel(head,list,size) -- todo: skip if first is object (or pass head and test for localpar) local id = getid(head) if id == localpar_code then - if getfield(head,"dir") == "TRT" then + if getdir(head) == "TRT" then return 1, "TRT", true else return 0, "TLT", true @@ -930,13 +933,13 @@ local function apply_to_list(list,size,head,pardir) setcolor(current,direction,false,mirror) end elseif id == hlist_code or id == vlist_code then - setfield(current,"dir",pardir) -- is this really needed? + setdir(current,pardir) -- is this really needed? elseif id == glue_code then if enddir and getsubtype(current) == parfillskip_code then -- insert the last enddir before \parfillskip glue local d = new_textdir(enddir) local p = properties[d] if p then p.directions = true else properties[d] = { directions = true } end - -- setfield(d,"attr",getfield(current,"attr")) + -- setattrlist(d,current) head = insert_node_before(head,current,d) enddir = false done = true @@ -946,7 +949,7 @@ local function apply_to_list(list,size,head,pardir) -- localpar should always be the 1st node local d = new_textdir(begindir) local p = properties[d] if p then p.directions = true else properties[d] = { directions = true } end - -- setfield(d,"attr",getfield(current,"attr")) + -- setattrlist(d,current) head, current = insert_node_after(head,current,d) begindir = nil done = true @@ -955,7 +958,7 @@ local function apply_to_list(list,size,head,pardir) if begindir then local d = new_textdir(begindir) local p = properties[d] if p then p.directions = true else properties[d] = { directions = true } end - -- setfield(d,"attr",getfield(current,"attr")) + -- setattrlist(d,current) head = insert_node_before(head,current,d) done = true end @@ -969,7 +972,7 @@ local function apply_to_list(list,size,head,pardir) if enddir then local d = new_textdir(enddir) local p = properties[d] if p then p.directions = true else properties[d] = { directions = true } end - -- setfield(d,"attr",getfield(current,"attr")) + -- setattrlist(d,current) head, current = insert_node_after(head,current,d) done = true end diff --git a/tex/context/base/mkiv/typo-fkr.lua b/tex/context/base/mkiv/typo-fkr.lua index b235ff284..a1135d0f3 100644 --- a/tex/context/base/mkiv/typo-fkr.lua +++ b/tex/context/base/mkiv/typo-fkr.lua @@ -23,6 +23,8 @@ local getkernpair = fonts.handlers.otf.getkern local insert_before = nuts.insert_before local new_kern = nuts.pool.fontkern +local enableaction = nodes.tasks.enableaction + local a_extrakern = attributes.private("extrafontkern") -- 0=none 1=min 2=max 3=mixed @@ -112,7 +114,7 @@ if context then local function setextrafontkerns(str) if not enabled then - nodes.tasks.enableaction("processors","typesetters.fontkerns.handler") + enableaction("processors","typesetters.fontkerns.handler") enabled = true end setattribute(a_extrakern,values[str] or unsetvalue) diff --git a/tex/context/base/mkiv/typo-fln.lua b/tex/context/base/mkiv/typo-fln.lua index fcd9b2c1f..cef77cea1 100644 --- a/tex/context/base/mkiv/typo-fln.lua +++ b/tex/context/base/mkiv/typo-fln.lua @@ -21,7 +21,10 @@ typesetters.firstlines = typesetters.firstlines or { } local firstlines = typesetters.firstlines local nodes = nodes + local tasks = nodes.tasks +local enableaction = tasks.enableaction +local disableaction = tasks.disableaction local context = context local implement = interfaces.implement @@ -45,6 +48,7 @@ local getbox = nuts.getbox local getdisc = nuts.getdisc local setdisc = nuts.setdisc local setlink = nuts.setlink +local setfont = nuts.setfont local nodecodes = nodes.nodecodes local glyph_code = nodecodes.glyph @@ -87,7 +91,7 @@ local settings = nil function firstlines.set(specification) settings = specification or { } - tasks.enableaction("processors","typesetters.firstlines.handler") + enableaction("processors","typesetters.firstlines.handler") if trace_firstlines then report_firstlines("enabling firstlines") end @@ -131,7 +135,7 @@ actions[v_line] = function(head,setting) if dynamic > 0 then setattr(g,0,dynamic) end - setfield(g,"font",font) + setfont(g,font) end end @@ -207,7 +211,7 @@ actions[v_line] = function(head,setting) if dynamic > 0 then setattr(start,0,dynamic) end - setfield(start,"font",font) + setfont(start,font) if ca and ca > 0 then setattr(start,a_colormodel,ma == 0 and 1 or ma) setattr(start,a_color,ca) @@ -311,7 +315,7 @@ actions[v_word] = function(head,setting) if dynamic > 0 then setattr(start,0,dynamic) end - setfield(start,"font",font) + setfont(start,font) elseif id == disc_code then -- continue elseif id == kern_code then -- todo: fontkern @@ -345,7 +349,7 @@ function firstlines.handler(head) end if attr then -- here as we can process nested boxes first so we need to keep state - tasks.disableaction("processors","typesetters.firstlines.handler") + disableaction("processors","typesetters.firstlines.handler") -- texsetattribute(attribute,unsetvalue) local alternative = settings.alternative or v_default local action = actions[alternative] or actions[v_default] diff --git a/tex/context/base/mkiv/typo-itc.lua b/tex/context/base/mkiv/typo-itc.lua index 61a1bfe6c..312832d5b 100644 --- a/tex/context/base/mkiv/typo-itc.lua +++ b/tex/context/base/mkiv/typo-itc.lua @@ -23,7 +23,7 @@ local glue_code = nodecodes.glue local disc_code = nodecodes.disc local math_code = nodecodes.math -local tasks = nodes.tasks +local enableaction = nodes.tasks.enableaction local nuts = nodes.nuts local nodepool = nuts.pool @@ -40,9 +40,14 @@ local getchar = nuts.getchar local getdisc = nuts.getdisc local getattr = nuts.getattr local setattr = nuts.setattr +local getattrlist = nuts.getattrlist +local setattrlist = nuts.setattrlist local setfield = nuts.setfield local setdisc = nuts.setdisc local isglyph = nuts.isglyph +local setkern = nuts.setkern +local getkern = nuts.getkern +local getheight = nuts.getheight local insert_node_after = nuts.insert_after local delete_node = nuts.delete @@ -124,7 +129,7 @@ local function okay(data,current,font,prevchar,previtalic,char,what) return false end if threshold then - local ht = getfield(current,"height") + local ht = getheight(current) local ex = exheights[font] local th = threshold * ex if ht <= th then @@ -149,9 +154,9 @@ end local function correction_kern(kern,n) local k = new_correction_kern(kern) if n then - local a = getfield(n,"attr") + local a = getattrlist(n) if a then -- maybe not - setfield(k,"attr",a) -- can be a marked content (border case) + setattrlist(k,a) -- can be a marked content (border case) end end return k @@ -160,9 +165,9 @@ end local function correction_glue(glue,n) local g = new_correction_glue(glue) if n then - local a = getfield(n,"attr") + local a = getattrlist(n) if a then -- maybe not - setfield(g,"attr",a) -- can be a marked content (border case) + setattrlist(g,a) -- can be a marked content (border case) end end return g @@ -195,10 +200,10 @@ local function domath(head,current, done) else a = a + 100 end - local i = getfield(kern,"kern") + local i = getkern(kern) local f = getfont(glyph) local c = getchar(glyph) - if getfield(next,"height") < 1.25*exheights[f] then + if getheight(next) < 1.25*exheights[f] then if i == 0 then if trace_italics then report_italics("%s italic %p between math %C and punctuation %C","ignoring",i,c,char) @@ -207,7 +212,7 @@ local function domath(head,current, done) if trace_italics then report_italics("%s italic between math %C and punctuation %C","removing",i,c,char) end - setfield(kern,"kern",0) -- or maybe a small value or half the ic + setkern(kern,0) -- or maybe a small value or half the ic done = true end elseif i == 0 then @@ -218,7 +223,7 @@ local function domath(head,current, done) report_italics("%s italic %p between math %C and punctuation %C","ignoring",i,c,char) end else - setfield(kern,"kern",i) + setkern(kern,i) if trace_italics then report_italics("%s italic %p between math %C and punctuation %C","setting",i,c,char) end @@ -593,7 +598,7 @@ function italics.handler(head) end enabletext = function() - tasks.enableaction("processors","typesetters.italics.handler") + enableaction("processors","typesetters.italics.handler") if trace_italics then report_italics("enabling text/text italics") end @@ -602,7 +607,7 @@ enabletext = function() end enablemath = function() - tasks.enableaction("processors","typesetters.italics.handler") + enableaction("processors","typesetters.italics.handler") if trace_italics then report_italics("enabling math/text italics") end diff --git a/tex/context/base/mkiv/typo-krn.lua b/tex/context/base/mkiv/typo-krn.lua index 6a2aed9a2..24a91d6b6 100644 --- a/tex/context/base/mkiv/typo-krn.lua +++ b/tex/context/base/mkiv/typo-krn.lua @@ -14,7 +14,8 @@ local next, type, tonumber = next, type, tonumber local nodes = nodes local fonts = fonts -local tasks = nodes.tasks +local enableaction = nodes.tasks.enableaction + local nuts = nodes.nuts local nodepool = nuts.pool @@ -28,23 +29,27 @@ local flush_node = nuts.flush_node local insert_node_before = nuts.insert_before local insert_node_after = nuts.insert_after local end_of_math = nuts.end_of_math +local use_components = nuts.use_components local getfield = nuts.getfield local getnext = nuts.getnext local getprev = nuts.getprev -local getboth = nuts.getboth local getid = nuts.getid local getfont = nuts.getfont local getsubtype = nuts.getsubtype local getchar = nuts.getchar local getdisc = nuts.getdisc +local getglue = nuts.getglue +local getkern = nuts.getkern local isglyph = nuts.isglyph local setfield = nuts.setfield local getattr = nuts.getattr -local setattr = nuts.setattr +local takeattr = nuts.takeattr local setlink = nuts.setlink -local setsubtype = nuts.setsubtype +local setdisc = nuts.setdisc +local setglue = nuts.setglue +local setkern = nuts.setkern local texsetattribute = tex.setattribute local unsetvalue = attributes.unsetvalue @@ -105,10 +110,6 @@ local report = logs.reporter("kerns") local trace_ligatures = false trackers.register("typesetters.kerns.ligatures", function(v) trace_ligatures = v end) local trace_ligatures_d = false trackers.register("typesetters.kerns.ligatures.detail",function(v) trace_ligatures_d = v end) --- use_advance is just an experiment: it makes copying glyphs (instead of new_glyph) dangerous - -local use_advance = false directives.register("typesetters.kerns.advance", function(v) use_advance = v end) - kerns.mapping = kerns.mapping or { } kerns.factors = kerns.factors or { } local a_kerns = attributes.private("kern") @@ -232,8 +233,7 @@ local function inject_begin(boundary,prev,keeptogether,krn,ok) -- prev is a glyp end if inject then -- not yet ok, as injected kerns can be overlays (from node-inj.lua) - setsubtype(boundary,userkern_code) - setfield(boundary,"kern",getfield(boundary,"kern") + quaddata[getfont(prev)]*krn) + setkern(boundary,getkern(boundary) + quaddata[getfont(prev)]*krn,userkern_code) return boundary, true end end @@ -269,8 +269,7 @@ local function inject_end(boundary,next,keeptogether,krn,ok) end if inject then -- not yet ok, as injected kerns can be overlays (from node-inj.lua) - setsubtype(tail,userkern_code) - setfield(tail,"kern",getfield(tail,"kern") + quaddata[getfont(next)]*krn) + setkern(tail,getkern(tail) + quaddata[getfont(next)]*krn,userkern_code) return boundary, true end end @@ -284,7 +283,7 @@ local function inject_end(boundary,next,keeptogether,krn,ok) local data = chardata[font][nextchar] local kerns = data and data.kerns local kern = (kerns and kerns[char] or 0) + quaddata[font]*krn - insert_node_after(boundary,tail,new_kern(kern)) + setlink(tail,new_kern(kern)) return boundary, true end end @@ -320,8 +319,7 @@ local function process_list(head,keeptogether,krn,font,okay) end if inject then -- not yet ok, as injected kerns can be overlays (from node-inj.lua) - setsubtype(prev,userkern_code) - setfield(prev,"kern",getfield(prev,"kern") + kern) + setkern(prev,getkern(prev) + kern,userkern_code) okay = true end end @@ -383,9 +381,8 @@ function kerns.handler(head) -- fontkerns don't get the attribute but they always sit between glyphs so -- are always valid bound .. disc nodes also somtimes don't get them local id = getid(start) - local attr = getattr(start,a_kerns) + local attr = takeattr(start,a_kerns) if attr and attr > 0 then - setattr(start,a_kerns,0) -- unsetvalue) local krn = mapping[attr] if krn == v_max then krn = .25 @@ -395,31 +392,13 @@ function kerns.handler(head) end if not krn or krn == 0 then bound = false - elseif id == glyph_code then -- we could use the subtype ligature - local c = getfield(start,"components") - if not c then - -- fine - elseif keepligature and keepligature(start) then + elseif id == glyph_code then + if keepligature and keepligature(start) then -- keep 'm - c = nil else - while c do - local s = start - local t = find_node_tail(c) - local p, n = getboth(s) - if p then - setlink(p,c) - else - head = c - end - if n then - setlink(t,n) - end - start = c - setfield(s,"components",nil) - flush_node(s) - c = getfield(start,"components") - end + -- we could use the subtype ligature but that's also a call + -- todo: check tounicode and use that information to split + head, start = use_components(head,start) end local char = getchar(start) local font = getfont(start) @@ -438,8 +417,7 @@ function kerns.handler(head) end if inject then -- not yet ok, as injected kerns can be overlays (from node-inj.lua) - setsubtype(prev,userkern_code) - setfield(prev,"kern",getfield(prev,"kern") + quaddata[font]*krn) + setkern(prev,getkern(prev) + quaddata[font]*krn,userkern_code) done = true end end @@ -451,11 +429,7 @@ function kerns.handler(head) local data = chardata[font][prevchar] local kerns = data and data.kerns local kern = (kerns and kerns[char] or 0) + quaddata[font]*krn - if not fillup and use_advance then - setfield(prev,"xadvance",getfield(prev,"xadvance") + kern) - else - insert_node_before(head,start,kern_injector(fillup,kern)) - end + insert_node_before(head,start,kern_injector(fillup,kern)) done = true end else @@ -485,12 +459,7 @@ function kerns.handler(head) languages.expand(start,pglyph and prev) end local pre, post, replace = getdisc(start) - -- we really need to reasign the fields as luatex keeps track of - -- the tail in a temp preceding head .. kind of messy so we might - -- want to come up with a better solution some day like a real - -- pretail etc fields in a disc node - -- - -- maybe i'll merge the now split functions + local indeed = false if pre then local okay = false if not prev then @@ -502,8 +471,7 @@ function kerns.handler(head) end pre, okay = process_list(pre,keeptogether,krn,false,okay) if okay then - setfield(start,"pre",pre) - done = true + indeed = true end end if post then @@ -517,8 +485,7 @@ function kerns.handler(head) end post, okay = process_list(post,keeptogether,krn,false,okay) if okay then - setfield(start,"post",post) - done = true + indeed = true end end if replace then @@ -539,11 +506,14 @@ function kerns.handler(head) end replace, okay = process_list(replace,keeptogether,krn,false,okay) if okay then - setfield(start,"replace",replace) - done = true + indeed = true end elseif prevfont then - setfield(start,"replace",new_kern(quaddata[prevfont]*krn)) + replace = new_kern(quaddata[prevfont]*krn) + indeed = true + end + if indeed then + setdisc(start,pre,post,replace) done = true end bound = false @@ -554,21 +524,18 @@ function kerns.handler(head) elseif id == glue_code then local subtype = getsubtype(start) if subtype == userskip_code or subtype == xspaceskip_code or subtype == spaceskip_code then - local w = getfield(start,"width") - if w > 0 then - local width = w + gluefactor * w * krn - local stretch = getfield(start,"stretch") * width / w - local shrink = getfield(start,"shrink") * width / w + local width, stretch, shrink, stretch_order, shrink_order = getglue(start) + if width > 0 then + local w = width + gluefactor * width * krn + stretch = stretch * w / width + shrink = shrink * w / width if fillup then stretch = 2 * stretch shrink = 2 * shrink - setfield(start,"stretch_order",1) - -- shrink_order ? + stretch_order = 1 + -- shrink_order = 1 ? end - setfield(start,"width",width) - setfield(start,"stretch",stretch) - setfield(start,"shrink", shrink) - -- + setglue(start,w,stretch,shrink,stretch_order,shrink_order) done = true end end @@ -617,7 +584,7 @@ function kerns.set(factor) end if factor == v_max or factor ~= 0 then if not enabled then - tasks.enableaction("processors","typesetters.kerns.handler") + enableaction("processors","typesetters.kerns.handler") enabled = true end local a = factors[factor] diff --git a/tex/context/base/mkiv/typo-lin.lua b/tex/context/base/mkiv/typo-lin.lua index 119b94cdc..d702bcb8c 100644 --- a/tex/context/base/mkiv/typo-lin.lua +++ b/tex/context/base/mkiv/typo-lin.lua @@ -89,6 +89,14 @@ local getprev = nuts.getprev local getboth = nuts.getboth local getfield = nuts.getfield local setfield = nuts.setfield +local setlink = nuts.setlink +local setkern = nuts.setkern +local getkern = nuts.getkern +local getdir = nuts.getdir +local getshift = nuts.getshift +local setshift = nuts.setshift +local getwidth = nuts.getwidth +local setwidth = nuts.setwidth local setprop = nuts.setprop local getprop = nuts.rawprop -- getprop @@ -135,8 +143,8 @@ local function finalize(prop,key) -- delayed calculations local line = prop.line local hsize = prop.hsize local width = prop.width - local shift = getfield(line,"shift") -- dangerous as it can be vertical as well - local reverse = getfield(line,"dir") == "TRT" or false + local shift = getshift(line) -- dangerous as it can be vertical as well + local reverse = getdir(line) == "TRT" or false local pack = new_hlist() local head = getlist(line) local delta = 0 @@ -168,7 +176,7 @@ local function normalize(line,islocal) -- assumes prestine lines, nothing pre/ap local head = oldhead local leftskip = nil local rightskip = nil - local width = getfield(line,"width") + local width = getwidth(line) local hsize = islocal and width or tex.hsize local lskip = 0 local rskip = 0 @@ -179,7 +187,7 @@ local function normalize(line,islocal) -- assumes prestine lines, nothing pre/ap local subtype = getsubtype(head) if subtype == leftskip_code then leftskip = head - lskip = getfield(head,"width") or 0 + lskip = getwidth(head) or 0 end current = getnext(head) id = getid(current) @@ -194,7 +202,7 @@ local function normalize(line,islocal) -- assumes prestine lines, nothing pre/ap if id == glue_code then if getsubtype(current) == rightskip_code then rightskip = tail - rskip = getfield(current,"width") or 0 + rskip = getwidth(current) or 0 current = getprev(tail) id = getid(current) end @@ -355,12 +363,14 @@ local function addanchortoline(n,anchor) local anchor = tonut(anchor) local where = line.where if trace_anchors then - local rule1 = new_rule(65536/2,4*65536,4*65536) - local rule2 = new_rule(8*65536,65536/4,65536/4) - local kern1 = new_kern(-65536/4) - local kern2 = new_kern(-65536/4-4*65536) - anchor = new_hlist(nuts.link { anchor, kern1, rule1, kern2, rule2 }) - setfield(anchor,"width",0) + anchor = new_hlist(setlink( + anchor, + new_kern(-65536/4), + new_rule(65536/2,4*65536,4*65536), + new_kern(-65536/4-4*65536), + new_rule(8*65536,65536/4,65536/4) + )) + setwidth(anchor,0) end if where.tail then local head = where.head @@ -393,15 +403,15 @@ function paragraphs.moveinline(n,blob,dx,dy) if dx ~= 0 then local prev, next = getboth(blob) if prev and getid(prev) == kern_code then - setfield(prev,"kern",getfield(prev,"kern") + dx) + setkern(prev,getkern(prev) + dx) end if next and getid(next) == kern_code then - setfield(next,"kern",getfield(next,"kern") - dx) + setkern(next,getkern(next) - dx) end end if dy ~= 0 then if getid(blob) == hlist_code then - setfield(blob,"shift",getfield(blob,"shift") + dy) + setshift(blob,getshift(blob) + dy) end end else diff --git a/tex/context/base/mkiv/typo-mar.lua b/tex/context/base/mkiv/typo-mar.lua index 680fb20cc..a5d607cd7 100644 --- a/tex/context/base/mkiv/typo-mar.lua +++ b/tex/context/base/mkiv/typo-mar.lua @@ -64,7 +64,6 @@ local tonut = nuts.tonut local hpack_nodes = nuts.hpack local traverse_id = nuts.traverse_id local flush_node_list = nuts.flush_list -local linked_nodes = nuts.linked local getfield = nuts.getfield local setfield = nuts.setfield @@ -78,6 +77,11 @@ local getlist = nuts.getlist local getwhd = nuts.getwhd local setlist = nuts.setlist local setlink = nuts.setlink +local getshift = nuts.getshift +local setshift = nuts.setshift +local getwidth = nuts.getwidth +local setwidth = nuts.setwidth +local getheight = nuts.getheight local getbox = nuts.getbox local takebox = nuts.takebox @@ -95,8 +99,6 @@ local vlist_code = nodecodes.vlist local whatsit_code = nodecodes.whatsit local userdefined_code = whatsitcodes.userdefined -local n_flush_node = nodes.flush - local nodepool = nuts.pool local new_usernumber = nodepool.usernumber @@ -486,10 +488,9 @@ local function markovershoot(current) -- todo: alleen als offset > line v_anchors = v_anchors + 1 cache[v_anchors] = fastcopy(stacked) local anchor = setanchor(v_anchors) - -- local list = hpack_nodes(linked_nodes(anchor,getlist(current))) -- not ok, we need to retain width - local list = hpack_nodes(linked_nodes(anchor,getlist(current)),getfield(current,"width"),"exactly")-- - -- why not: - -- local list = linked_nodes(anchor,getlist(current)) + -- local list = hpack_nodes(setlink(anchor,getlist(current))) -- not ok, we need to retain width + -- local list = setlink(anchor,getlist(current)) -- why not this ... better play safe + local list = hpack_nodes(setlink(anchor,getlist(current)),getwidth(current),"exactly")-- if trace_marginstack then report_margindata("marking anchor %a",v_anchors) end @@ -503,7 +504,7 @@ local function inject(parent,head,candidate) end local width, height, depth = getwhd(box) - local shift = getfield(box,"shift") + local shift = getshift(box) local stack = candidate.stack local stackname = candidate.stackname local location = candidate.location @@ -544,7 +545,7 @@ local function inject(parent,head,candidate) end end candidate.width = width - candidate.hsize = getfield(parent,"width") -- we can also pass textwidth + candidate.hsize = getwidth(parent) -- we can also pass textwidth candidate.psubtype = psubtype candidate.stackname = stackname if trace_margindata then @@ -617,7 +618,7 @@ local function inject(parent,head,candidate) -- following which we don't know yet ... so, consider stacking partially -- experimental. if method == v_top then - local delta = height - getfield(parent,"height") + local delta = height - getheight(parent) if trace_margindata then report_margindata("top aligned by %p",delta) end @@ -671,8 +672,8 @@ local function inject(parent,head,candidate) shift = shift + delta offset = offset + delta end - setfield(box,"shift",shift) - setfield(box,"width",0) -- not needed when wrapped + setshift(box,shift) + setwidth(box,0) -- not needed when wrapped -- if isstacked then setlink(box,addtoanchor(v_anchor,nofinjected)) @@ -785,7 +786,7 @@ local function flushed(scope,parent) -- current is hlist if done then local a = getattr(head,a_linenumber) -- hack .. we need a more decent critical attribute inheritance mechanism if false then - local l = hpack_nodes(head,getfield(parent,"width"),"exactly") + local l = hpack_nodes(head,getwidth(parent),"exactly") setlist(parent,l) if a then setattr(l,a_linenumber,a) @@ -947,14 +948,6 @@ end -- Somehow the vbox builder (in combinations) gets pretty confused and decides to -- go horizontal. So this needs more testing. -prependaction("finalizers", "lists", "typesetters.margins.localhandler") -prependaction("mvlbuilders", "normalizers", "typesetters.margins.globalhandler") -prependaction("shipouts", "normalizers", "typesetters.margins.finalhandler") - -disableaction("finalizers", "typesetters.margins.localhandler") -disableaction("mvlbuilders", "typesetters.margins.globalhandler") -disableaction("shipouts", "typesetters.margins.finalhandler") - enablelocal = function() enableaction("finalizers", "typesetters.margins.localhandler") enableaction("shipouts", "typesetters.margins.finalhandler") diff --git a/tex/context/base/mkiv/typo-pag.lua b/tex/context/base/mkiv/typo-pag.lua index 063b5214a..d6f71c8cc 100644 --- a/tex/context/base/mkiv/typo-pag.lua +++ b/tex/context/base/mkiv/typo-pag.lua @@ -34,8 +34,13 @@ local getnext = nuts.getnext local getprev = nuts.getprev local getid = nuts.getid local getattr = nuts.getattr +local takeattr = nuts.takeattr local setattr = nuts.setattr local getwhd = nuts.getwhd +local getkern = nuts.getkern +local setpenalty = nuts.setpenalty +local getwidth = nuts.getwidth +local getdepth = nuts.getdepth local insert_node_after = nuts.insert_after local new_penalty = nuts.pool.penalty @@ -43,6 +48,8 @@ local new_penalty = nuts.pool.penalty local trace_keeptogether = false local report_keeptogether = logs.reporter("parbuilders","keeptogether") +local enableaction = nodes.tasks.enableaction + local cache = { } local last = 0 local enabled = false @@ -57,7 +64,7 @@ function parbuilders.registertogether(line,specification) -- might change return end if not enabled then - nodes.tasks.enableaction("finalizers","builders.paragraphs.keeptogether") + enableaction("finalizers","builders.paragraphs.keeptogether") end local a = getattr(line,a_keeptogether) local c = a and cache[a] @@ -110,7 +117,7 @@ local function keeptogether(start,a) if a then local current = getnext(start) local previous = start - local total = getfield(previous,"depth") + local total = getdepth(previous) local slack = specification.slack local threshold = specification.depth - slack if trace_keeptogether then @@ -126,7 +133,7 @@ local function keeptogether(start,a) end if total <= threshold then if getid(previous) == penalty_code then - setfield(previous,"penalty",10000) + setpenalty(previous,10000) else insert_node_after(head,previous,new_penalty(10000)) end @@ -135,13 +142,13 @@ local function keeptogether(start,a) end elseif id == glue_code then -- hm, breakpoint, maybe turn this into kern - total = total + getfield(current,"width") + total = total + getwidth(current) if trace_keeptogether then report_keeptogether("%s, index %s, total %p, threshold %p","glue",a,total,threshold) end if total <= threshold then if getid(previous) == penalty_code then - setfield(previous,"penalty",10000) + setpenalty(previous,10000) else insert_node_after(head,previous,new_penalty(10000)) end @@ -149,13 +156,13 @@ local function keeptogether(start,a) break end elseif id == kern_code then - total = total + getfield(current,"kern") + total = total + getkern(current) if trace_keeptogether then report_keeptogether("%s, index %s, total %s, threshold %s","kern",a,total,threshold) end if total <= threshold then if getid(previous) == penalty_code then - setfield(previous,"penalty",10000) + setpenalty(previous,10000) else insert_node_after(head,previous,new_penalty(10000)) end @@ -165,9 +172,9 @@ local function keeptogether(start,a) elseif id == penalty_code then if total <= threshold then if getid(previous) == penalty_code then - setfield(previous,"penalty",10000) + setpenalty(previous,10000) end - setfield(current,"penalty",10000) + setpenalty(current,10000) else break end @@ -186,10 +193,9 @@ function parbuilders.keeptogether(head) local current = tonut(head) while current do if getid(current) == hlist_code then - local a = getattr(current,a_keeptogether) + local a = takeattr(current,a_keeptogether) if a and a > 0 then keeptogether(current,a) - setattr(current,a_keeptogether,unsetvalue) cache[a] = nil done = true end diff --git a/tex/context/base/mkiv/typo-rep.lua b/tex/context/base/mkiv/typo-rep.lua index 489877792..5266aa103 100644 --- a/tex/context/base/mkiv/typo-rep.lua +++ b/tex/context/base/mkiv/typo-rep.lua @@ -18,7 +18,7 @@ local trace_stripping = false trackers.register("nodes.stripping", function(v) local report_stripping = logs.reporter("fonts","stripping") local nodes = nodes -local tasks = nodes.tasks +local enableaction = nodes.tasks.enableaction local nuts = nodes.nuts local tonut = nuts.tonut @@ -119,7 +119,7 @@ function stripping.set(n) -- number or 'reset' if n then if not enabled then if initialize then initialize() end - tasks.enableaction("processors","nodes.handlers.stripping") + enableaction("processors","nodes.handlers.stripping") enabled = true end else @@ -129,11 +129,6 @@ function stripping.set(n) -- number or 'reset' texsetattribute(a_stripping,n) end --- why not in task-ini? - -tasks.appendaction("processors","fonts","nodes.handlers.stripping",nil,"nodes.handlers.characters") -tasks.disableaction("processors","nodes.handlers.stripping") - -- interface interfaces.implement { diff --git a/tex/context/base/mkiv/typo-rub.lua b/tex/context/base/mkiv/typo-rub.lua index f101668b6..9621a6218 100644 --- a/tex/context/base/mkiv/typo-rub.lua +++ b/tex/context/base/mkiv/typo-rub.lua @@ -48,9 +48,14 @@ local setprev = nuts.setprev local setlink = nuts.setlink local getlist = nuts.getlist local setlist = nuts.setlist +local setshift = nuts.setshift +local getwidth = nuts.getwidth +local setwidth = nuts.setwidth + local hpack = nuts.hpack local insert_after = nuts.insert_after local takebox = nuts.takebox +local traverse_id = nuts.traverse_id local nodecodes = nodes.nodecodes local glyph_code = nodecodes.glyph @@ -70,12 +75,13 @@ local kerncodes = nodes.kerncodes local font_code = kerncodes.font local nodepool = nuts.pool -local new_hlist = nodepool.hlist local new_kern = nodepool.kern local setprop = nuts.setprop local getprop = nuts.getprop +local enableaction = nodes.tasks.enableaction + local nofrubies = 0 local rubylist = { } @@ -93,8 +99,8 @@ do local splitter = lpeg.tsplitat("|") local function enable() - nodes.tasks.enableaction("processors","typesetters.rubies.check") - nodes.tasks.enableaction("shipouts", "typesetters.rubies.attach") + enableaction("processors","typesetters.rubies.check") + enableaction("shipouts", "typesetters.rubies.attach") enable = false end @@ -173,7 +179,7 @@ do local r = takebox(n) rubylist[nofrubies] = setmetatableindex({ text = r, - width = getfield(r,"width"), + width = getwidth(r), basewidth = 0, start = false, stop = false, @@ -210,7 +216,7 @@ function rubies.check(head) setlink(prev,h) end setlink(h,next) - local bwidth = getfield(h,"width") + local bwidth = getwidth(h) local rwidth = r.width r.basewidth = bwidth r.start = start @@ -218,7 +224,7 @@ function rubies.check(head) setprop(h,"ruby",found) if rwidth > bwidth then -- ruby is wider - setfield(h,"width",rwidth) + setwidth(h,rwidth) end end end @@ -259,121 +265,129 @@ function rubies.check(head) return tonode(head), true end -local function attach(head,parent) - local current = head - while current do - local id = getid(current) - if id == hlist_code then - local a = getprop(current,"ruby") - if a then - local ruby = rubylist[a] - local align = ruby.align or v_middle - local stretch = ruby.stretch or v_no - local hoffset = ruby.hoffset or 0 - local voffset = ruby.voffset or 0 - local start = ruby.start - local stop = ruby.stop - local text = ruby.text - local rwidth = ruby.width - local bwidth = ruby.basewidth - local delta = rwidth - bwidth - setfield(text,"width",0) - if voffset ~= 0 then - setfield(text,"shift",voffset) +local attach + +local function whatever(current) + local a = getprop(current,"ruby") + if a then + local ruby = rubylist[a] + local align = ruby.align or v_middle + local stretch = ruby.stretch or v_no + local hoffset = ruby.hoffset or 0 + local voffset = ruby.voffset or 0 + local start = ruby.start + local stop = ruby.stop + local text = ruby.text + local rwidth = ruby.width + local bwidth = ruby.basewidth + local delta = rwidth - bwidth + setwidth(text,0) + if voffset ~= 0 then + setshift(text,voffset) + end + -- center them + if delta > 0 then + -- ruby is wider + if stretch == v_yes then + setlink(text,start) + while start and start ~= stop do + local s = nodepool.stretch() + local n = getnext(start) + setlink(start,s,n) + start = n end - -- center them - if delta > 0 then - -- ruby is wider - if stretch == v_yes then - setlink(text,start) - while start and start ~= stop do - local s = nodepool.stretch() - local n = getnext(start) - setlink(start,s) - setlink(s,n) - start = n - end - text = hpack(text,rwidth,"exactly") + text = hpack(text,rwidth,"exactly") + else + local left = new_kern(delta/2) + local right = new_kern(delta/2) +-- setlink(left,start) +-- setlink(stop,right) +-- setlink(text,left) + setlink(text,left,start) + setlink(stop,right) + end + setlist(current,text) + elseif delta < 0 then + -- ruby is narrower + if align == v_auto then + local l = true + local c = getprev(current) + while c do + local id = getid(c) + if id == glue_code or id == penalty_code or id == kern_code or (id == whatsit_code and getsubtype(current,localpar_code)) then + -- go on + elseif id == hlist_code and getwidth(c) == 0 then + -- go on + elseif id == whatsit_code or id == localpar_code then + -- go on else - local left = new_kern(delta/2) - local right = new_kern(delta/2) - setlink(left,start) - setlink(stop,right) - setlink(text,left) - end - setlist(current,text) - elseif delta < 0 then - -- ruby is narrower - if align == v_auto then - local l = true - local c = getprev(current) - while c do - local id = getid(c) - if id == glue_code or id == penalty_code or id == kern_code or (id == whatsit_code and getsubtype(current,localpar_code)) then - -- go on - elseif id == hlist_code and getfield(c,"width") == 0 then - -- go on - elseif id == whatsit_code or id == localpar_code then - -- go on - else - l = false - break - end - c = getprev(c) - end - local r = true - local c = getnext(current) - while c do - local id = getid(c) - if id == glue_code or id == penalty_code or id == kern_code then - -- go on - elseif id == hlist_code and getfield(c,"width") == 0 then - -- go on - else - r = false - break - end - c = getnext(c) - end - if l and not r then - align = v_flushleft - elseif r and not l then - align = v_flushright - else - align = v_middle - end + l = false + break end - if align == v_flushleft then - setlink(text,start) - setlist(current,text) - elseif align == v_flushright then - local left = new_kern(-delta) - local right = new_kern(delta) - setlink(left,text) - setlink(text,right) - setlink(right,start) - setlist(current,left) + c = getprev(c) + end + local r = true + local c = getnext(current) + while c do + local id = getid(c) + if id == glue_code or id == penalty_code or id == kern_code then + -- go on + elseif id == hlist_code and getwidth(c) == 0 then + -- go on else - local left = new_kern(-delta/2) - local right = new_kern(delta/2) - setlink(left,text) - setlink(text,right) - setlink(right,start) - setlist(current,left) + r = false + break end + c = getnext(c) + end + if l and not r then + align = v_flushleft + elseif r and not l then + align = v_flushright else - setlink(text,start) - setlist(current,text) + align = v_middle end - setprop(current,"ruby",false) - rubylist[a] = nil + end + if align == v_flushleft then + setlink(text,start) + setlist(current,text) + elseif align == v_flushright then + local left = new_kern(-delta) + local right = new_kern(delta) +-- setlink(left,text) +-- setlink(text,right) +-- setlink(right,start) + setlink(left,text,right,start) + setlist(current,left) else - attach(getlist(current),current) + local left = new_kern(-delta/2) + local right = new_kern(delta/2) +-- setlink(left,text) +-- setlink(text,right) +-- setlink(right,start) + setlink(left,text,right,start) + setlist(current,left) end - elseif id == vlist_code then - attach(getlist(current),current) + else + setlink(text,start) + setlist(current,text) + end + setprop(current,"ruby",false) + rubylist[a] = nil + else + local list = getlist(current) + if list then + attach(list) end - current = getnext(current) + end +end + +attach = function(head) + for current in traverse_id(hlist_code,head) do + whatever(current) + end + for current in traverse_id(vlist_code,head) do + whatever(current) end return head, true end diff --git a/tex/context/base/mkiv/typo-rub.mkiv b/tex/context/base/mkiv/typo-rub.mkiv index 0ebc1d4a4..7b996089b 100644 --- a/tex/context/base/mkiv/typo-rub.mkiv +++ b/tex/context/base/mkiv/typo-rub.mkiv @@ -21,7 +21,7 @@ \registerctxluafile{typo-rub}{1.001} -\definesystemattribute[ruby] +\definesystemattribute[ruby][public] \installcorenamespace {ruby} \installcorenamespace {rubyanalyze} diff --git a/tex/context/base/mkiv/typo-spa.lua b/tex/context/base/mkiv/typo-spa.lua index d1aa2e277..bda139719 100644 --- a/tex/context/base/mkiv/typo-spa.lua +++ b/tex/context/base/mkiv/typo-spa.lua @@ -14,8 +14,6 @@ local report_spacing = logs.reporter("typesetting","spacing") local nodes, fonts, node = nodes, fonts, node -local tasks = nodes.tasks - local fonthashes = fonts.hashes local quaddata = fonthashes.quads @@ -31,8 +29,7 @@ local tonode = nuts.tonode local getnext = nuts.getnext local getprev = nuts.getprev local getfont = nuts.getfont -local getattr = nuts.getattr -local setattr = nuts.setattr +local takeattr = nuts.takeattr local isglyph = nuts.isglyph local insert_node_before = nuts.insert_before @@ -50,6 +47,8 @@ local math_code = nodecodes.math local somespace = nodes.somespace local somepenalty = nodes.somepenalty +local enableaction = nodes.tasks.enableaction + typesetters = typesetters or { } local typesetters = typesetters @@ -82,12 +81,11 @@ function spacings.handler(head) while start do local char, id = isglyph(start) if char then - local attr = getattr(start,a_spacings) + local attr = takeattr(start,a_spacings) if attr and attr > 0 then local data = mapping[attr] if data then local map = data.characters[char] - setattr(start,a_spacings,unsetvalue) -- needed? if map then local left = map.left local right = map.right @@ -210,7 +208,7 @@ function spacings.set(name) local data = numbers[name] if data then if not enabled then - tasks.enableaction("processors","typesetters.spacings.handler") + enableaction("processors","typesetters.spacings.handler") enabled = true end n = data.number or unsetvalue diff --git a/tex/context/base/mkiv/typo-sus.lua b/tex/context/base/mkiv/typo-sus.lua index d3526bb5d..e81b36b65 100644 --- a/tex/context/base/mkiv/typo-sus.lua +++ b/tex/context/base/mkiv/typo-sus.lua @@ -48,9 +48,11 @@ local getfield = nuts.getfield local getattr = nuts.getattr local getfont = nuts.getfont local getlist = nuts.getlist +local getkern = nuts.getkern +local getpenalty = nuts.getpenalty +local getwidth = nuts.getwidth local isglyph = nuts.isglyph -local setfield = nuts.setfield local setattr = nuts.setattr local setlist = nuts.setlist @@ -72,22 +74,21 @@ local a_suspect = attributes.private('suspect') local texsetattribute = tex.setattribute local enabled = false +local enableaction = nodes.tasks.enableaction + local threshold = 65536 / 4 local function special(n) if n then local id = getid(n) if id == kern_code then - local kern = getfield(n,"kern") - return kern < threshold + return getkern(n) < threshold elseif id == penalty_code then return true elseif id == glue_code then - local width = getfield(n,"width") - return width < threshold + return getwidth(n) < threshold elseif id == hlist_code then - local width = getfield(n,"width") - return width < threshold + return getwidth(n) < threshold end else return false @@ -118,21 +119,21 @@ local function mark(head,current,id,color) if id == glue_code then -- the glue can have stretch and/or shrink so the rule can overlap with the -- following glyph .. no big deal as that one then sits on top of the rule - local width = getfield(current,"width") + local width = getwidth(current) local rule = new_rule(width) local kern = new_kern(-width) head = insert_before(head,current,rule) head = insert_before(head,current,kern) setcolor(rule,color) -- elseif id == kern_code then - -- local width = getfield(current,"kern") + -- local width = getkern(current) -- local rule = new_rule(width) -- local kern = new_kern(-width) -- head = insert_before(head,current,rule) -- head = insert_before(head,current,kern) -- setcolor(rule,color) else - local width, height, depth = getWhd(current) + local width, height, depth = getwhd(current) local extra = fonts.hashes.xheights[getfont(current)] / 2 local rule = new_rule(width,height+extra,depth+extra) local hlist = new_hlist(rule) @@ -232,7 +233,7 @@ function typesetters.marksuspects(head) local prev = getprev(current) local prid = prev and getid(prev) local done = false - if prid == penalty_code and getfield(prev,"penalty") == 10000 then + if prid == penalty_code and getpenalty(prev) == 10000 then done = 8 -- orange else done = 5 -- darkmagenta @@ -292,19 +293,13 @@ function typesetters.showsuspects(head) end end -nodes.tasks.appendaction ("processors","after", "typesetters.marksuspects") -nodes.tasks.prependaction("shipouts", "normalizers","typesetters.showsuspects") - -nodes.tasks.disableaction("processors","typesetters.marksuspects") -nodes.tasks.disableaction("shipouts", "typesetters.showsuspects") - -- or maybe a directive trackers.register("typesetters.suspects",function(v) texsetattribute(a_suspecting,v and 1 or unsetvalue) if v and not enabled then - nodes.tasks.enableaction("processors","typesetters.marksuspects") - nodes.tasks.enableaction("shipouts", "typesetters.showsuspects") + enableaction("processors","typesetters.marksuspects") + enableaction("shipouts", "typesetters.showsuspects") enabled = true end end) diff --git a/tex/context/base/mkiv/typo-tal.lua b/tex/context/base/mkiv/typo-tal.lua index b3a1601d9..67380f24b 100644 --- a/tex/context/base/mkiv/typo-tal.lua +++ b/tex/context/base/mkiv/typo-tal.lua @@ -41,11 +41,9 @@ local getprev = nuts.getprev local getid = nuts.getid local getfont = nuts.getfont local getchar = nuts.getchar -local getfield = nuts.getfield local getattr = nuts.getattr local isglyph = nuts.isglyph -local setfield = nuts.setfield local setattr = nuts.setattr local setchar = nuts.setchar @@ -64,6 +62,8 @@ local tracers = nodes.tracers local setcolor = tracers.colors.set local tracedrule = tracers.pool.nuts.rule +local enableaction = nodes.tasks.enableaction + local characteralign = { } typesetters.characteralign = characteralign @@ -102,7 +102,7 @@ local validsigns = { local function setcharacteralign(column,separator) if not enabled then - nodes.tasks.enableaction("processors","typesetters.characteralign.handler") + enableaction("processors","typesetters.characteralign.handler") enabled = true end if not datasets then diff --git a/tex/context/base/mkiv/typo-wrp.lua b/tex/context/base/mkiv/typo-wrp.lua index 394e15090..07e34cd6c 100644 --- a/tex/context/base/mkiv/typo-wrp.lua +++ b/tex/context/base/mkiv/typo-wrp.lua @@ -23,9 +23,11 @@ local find_node_tail = nuts.tail local getprev = nuts.getprev local getid = nuts.getid local getsubtype = nuts.getsubtype -local getfield = nuts.getfield +local getpenalty = nuts.getpenalty local remove = nuts.remove +local enableaction = nodes.tasks.enableaction + local wrappers = { } typesetters.wrappers = wrappers @@ -39,9 +41,9 @@ local report = logs.reporter("paragraphs","wrappers") local function remove_dangling_crlf(head,tail) if tail and getid(tail) == glue_code and getsubtype(tail) == parfill_skip_code then tail = getprev(tail) - if tail and getid(tail) == penalty_code and getsubtype(tail) == user_penalty_code and getfield(tail,"penalty") == 10000 then + if tail and getid(tail) == penalty_code and getsubtype(tail) == user_penalty_code and getpenalty(tail) == 10000 then tail = getprev(tail) - if tail and getid(tail) == penalty_code and getsubtype(tail) == user_penalty_code and getfield(tail,"penalty") == -10000 then + if tail and getid(tail) == penalty_code and getsubtype(tail) == user_penalty_code and getpenalty(tail) == -10000 then if tail == head then -- can't happen else @@ -71,6 +73,6 @@ interfaces.implement { name = "enablecrlf", onlyonce = true, actions = function() - nodes.tasks.enableaction("processors","typesetters.wrappers.handler") + enableaction("processors","typesetters.wrappers.handler") end } diff --git a/tex/context/base/mkiv/util-fil.lua b/tex/context/base/mkiv/util-fil.lua index 0f9731a26..cf97d9541 100644 --- a/tex/context/base/mkiv/util-fil.lua +++ b/tex/context/base/mkiv/util-fil.lua @@ -93,7 +93,7 @@ end function files.readinteger1(f) -- one byte local n = byte(f:read(1)) - if n >= 0x80 then + if n >= 0x80 then -- return n - 0xFF - 1 return n - 0x100 else @@ -124,6 +124,14 @@ function files.readinteger2(f) return n end end + function files.readinteger2(f) + local a, b = byte(f:read(2),1,2) + if a >= 0x80 then + return 0x100 * a + b - 0x10000 + else + return 0x100 * a + b + end + end function files.readinteger2le(f) local b, a = byte(f:read(2),1,2) local n = 0x100 * a + b @@ -184,6 +192,14 @@ function files.readinteger4(f) return n end end + function files.readinteger4(f) + local a, b, c, d = byte(f:read(4),1,4) + if a >= 0x80 then + return 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000 + else + return 0x1000000 * a + 0x10000 * b + 0x100 * c + d + end + end function files.readinteger4le(f) local d, c, b, a = byte(f:read(4),1,4) local n = 0x1000000 * a + 0x10000 * b + 0x100 * c + d diff --git a/tex/context/base/mkiv/util-sbx.lua b/tex/context/base/mkiv/util-sbx.lua index 260e8b3b5..03593cb9b 100644 --- a/tex/context/base/mkiv/util-sbx.lua +++ b/tex/context/base/mkiv/util-sbx.lua @@ -23,19 +23,23 @@ local platform = os.type local P, S, C = lpeg.P, lpeg.S, lpeg.C local gsub = string.gsub local lower = string.lower +local find = string.find +local concat = string.concat local unquoted = string.unquoted local optionalquoted = string.optionalquoted +local basename = file.basename local sandbox = sandbox local validroots = { } local validrunners = { } -local validbinaries = { } +local validbinaries = true -- all permitted +local validlibraries = true -- all permitted local validators = { } -local p_validroot = nil local finalized = nil -local norunners = false local trace = false -local p_split = lpeg.tsplitat(" ") -- more spaces? + +local p_validroot = nil +local p_split = lpeg.firstofsplit(" ") local report = logs.reporter("sandbox") @@ -43,9 +47,12 @@ trackers.register("sandbox",function(v) trace = v end) -- often too late anyway sandbox.setreporter(report) -sandbox.finalizer(function() - finalized = true -end) +sandbox.finalizer { + category = "files", + action = function() + finalized = true + end +} local function registerroot(root,what) -- what == read|write if finalized then @@ -60,52 +67,57 @@ local function registerroot(root,what) -- what == read|write end end -sandbox.finalizer(function() -- initializers can set the path - if p_validroot then - report("roots are already initialized") - else - sandbox.registerroot(".","write") -- always ok - -- also register texmf as read - for name in sortedhash(validroots) do - if p_validroot then - p_validroot = P(name) + p_validroot - else - p_validroot = P(name) +sandbox.finalizer { + category = "files", + action = function() -- initializers can set the path + if p_validroot then + report("roots are already initialized") + else + sandbox.registerroot(".","write") -- always ok + -- also register texmf as read + for name in sortedhash(validroots) do + if p_validroot then + p_validroot = P(name) + p_validroot + else + p_validroot = P(name) + end end + p_validroot = p_validroot / validroots end - p_validroot = p_validroot / validroots end -end) +} -local function registerrunner(specification) +local function registerbinary(name) if finalized then - report("runners are already finalized") - else - local name = specification.name - if not name then - report("no runner name specified") + report("binaries are already finalized") + elseif type(name) == "string" and name ~= "" then + if not validbinaries then return end - local program = specification.program - if type(program) == "string" then - -- common for all platforms - elseif type(program) == "table" then - program = program[platform] - end - if type(program) ~= "string" or program == "" then - report("invalid runner %a specified for platform %a",name,platform) - return + if validbinaries == true then + validbinaries = { [name] = true } + else + validbinaries[name] = true end - specification.program = program - validrunners[name] = specification + elseif name == true then + validbinaries = { } end end -local function registerbinary(name) +local function registerlibrary(name) if finalized then - report("binaries are already finalized") + report("libraries are already finalized") elseif type(name) == "string" and name ~= "" then - validbinaries[name] = true + if not validlibraries then + return + end + if validlibraries == true then + validlibraries = { [name] = true } + else + validlibraries[name] = true + end + elseif name == true then + validlibraries = { } end end @@ -173,7 +185,7 @@ local function validfilename(name,what) end end -local function readable(name) +local function readable(name,finalized) if platform == "windows" then name = lower(name) -- we assume ascii names end @@ -183,7 +195,7 @@ local function readable(name) end end -local function writeable(name) +local function writeable(name,finalized) if platform == "windows" then name = lower(name) -- we assume ascii names end @@ -193,8 +205,8 @@ local function writeable(name) end end -validators.readable = readable validators.writeable = writeable +validators.readable = readable validators.filename = readable table.setmetatableindex(validators,function(t,k) @@ -204,23 +216,39 @@ table.setmetatableindex(validators,function(t,k) return readable end) -function validators.string(s) - return s -- can be used to prevent filename checking +function validators.string(s,finalized) + -- can be used to prevent filename checking (todo: only when registered) + if finalized and suspicious(s) then + return "" + else + return s + end end --- end of validators +function validators.cache(s) + if finalized then + return basename(s) + else + return s + end +end + +function validators.url(s) + if finalized and find("^file:") then + return "" + else + return s + end +end -sandbox.registerroot = registerroot -sandbox.registerrunner = registerrunner -sandbox.registerbinary = registerbinary -sandbox.validfilename = validfilename +-- end of validators local function filehandlerone(action,one,...) local checkedone = validfilename(one) if checkedone then return action(one,...) else --- report("file %a is unreachable",one) + -- report("file %a is unreachable",one) end end @@ -231,10 +259,10 @@ local function filehandlertwo(action,one,two,...) if checkedtwo then return action(one,two,...) else --- report("file %a is unreachable",two) + -- report("file %a is unreachable",two) end else --- report("file %a is unreachable",one) + -- report("file %a is unreachable",one) end end @@ -254,101 +282,276 @@ end -- runners can be strings or tables -- -- os.execute : string --- os.exec : table with program in [0|1] --- os.spawn : table with program in [0|1] +-- os.exec : string or table with program in [0|1] +-- os.spawn : string or table with program in [0|1] -- -- our execute: registered program with specification -local function runhandler(action,name,specification) - local kind = type(name) - if kind ~= "string" then +local osexecute = sandbox.original(os.execute) +local iopopen = sandbox.original(io.popen) +local reported = { } + +local function validcommand(name,program,template,checkers,defaults,variables,reporter,strict) + if validbinaries ~= false and (validbinaries == true or validbinaries[program]) then + if variables then + for variable, value in next, variables do + local checker = validators[checkers[variable]] + if checker then + value = checker(unquoted(value),strict) + if value then + variables[variable] = optionalquoted(value) + else + report("variable %a with value %a fails the check",variable,value) + return + end + else + report("variable %a has no checker",variable) + return + end + end + for variable, default in next, defaults do + local value = variables[variable] + if not value or value == "" then + local checker = validators[checkers[variable]] + if checker then + default = checker(unquoted(default),strict) + if default then + variables[variable] = optionalquoted(default) + else + report("variable %a with default %a fails the check",variable,default) + return + end + end + end + end + end + local command = program .. " " .. replace(template,variables) + if reporter then + reporter("executing runner %a: %s",name,command) + elseif trace then + report("executing runner %a: %s",name,command) + end + return command + elseif not reported[name] then + report("executing program %a of runner %a is not permitted",program,name) + reported[name] = true + end +end + +local runners = { + -- + -- name,program,template,checkers,variables,reporter + -- + resultof = function(...) + local command = validcommand(...) + if command then + local handle = iopopen(command,"r") -- already has flush + if handle then + local result = handle:read("*all") or "" + handle:close() + return result + end + end + end, + execute = function(...) + local command = validcommand(...) + if command then + return osexecute(command) + end + end, + pipeto = function(...) + local command = validcommand(...) + if command then + return iopopen(command,"w") -- already has flush + end + end, +} + +function sandbox.registerrunner(specification) + if type(specification) == "string" then + local wrapped = validrunners[specification] + inspect(table.sortedkeys(validrunners)) + if wrapped then + return wrapped + else + report("unknown predefined runner %a",specification) + return + end + end + if type(specification) ~= "table" then + report("specification should be a table (or string)") return end - if norunners then - report("no runners permitted, ignoring command: %s",name) + local name = specification.name + if type(name) ~= "string" then + report("invalid name, string expected") return end - local spec = validrunners[name] - if not spec then - report("unknown runner: %s",name) + if validrunners[name] then + report("invalid name, runner %a already defined") return end - -- specs are already checked - local program = spec.program - local variables = { } - local checkers = spec.checkers or { } - if specification then - -- we only handle runners that are defined before the sandbox is - -- closed so in principle we cannot have user runs with no files - -- while for context runners we assume a robust specification - for k, v in next, specification do - local checker = validators[checkers[k]] - local value = checker(unquoted(v)) -- todo: write checkers - if value then - variables[k] = optionalquoted(value) - else - report("suspicious argument found, run blocked: %s",v) - return - end - end + local program = specification.program + if type(program) == "string" then + -- common for all platforms + elseif type(program) == "table" then + program = program[platform] or program.default or program.unix + end + if type(program) ~= "string" or program == "" then + report("invalid runner %a specified for platform %a",name,platform) + return + end + local template = specification.template + if not template then + report("missing template for runner %a",name) + return end - local command = replace(program,variables) - if trace then - report("executing runner: %s",command) + local method = specification.method or "execute" + local checkers = specification.checkers or { } + local defaults = specification.defaults or { } + local runner = runners[method] + if runner then + local finalized = finalized -- so, the current situation is frozen + local wrapped = function(variables) + return runner(name,program,template,checkers,defaults,variables,specification.reporter,finalized) + end + validrunners[name] = wrapped + return wrapped + else + validrunners[name] = nil + report("invalid method for runner %a",name) end - return action(command) end --- only registered (from list) -- no checking on writable so let's assume harmless --- runs +local function suspicious(str) + return (find(str,"[/\\]") or find(command,"%.%.")) and true or false +end -local function binaryhandler(action,name) - local kind = type(name) - local list = name - if kind == "string" then - list = lpegmatch(p_split,name) +local function binaryrunner(action,command,...) + if validbinaries == false then + -- nothing permitted + report("no binaries permitted, ignoring command: %s",command) + return end - local program = name[0] or name[1] - if type(program) ~= "string" or program == "" then - return --silently ignore + if type(command) ~= "string" then + -- we only handle strings, maybe some day tables + report("command should be a string") + return end - if norunners then - report("no binaries permitted, ignoring command: %s",program) + local program = lpegmatch(p_split,command) + if not program or program == "" then + report("unable to filter binary from command: %s",command) return end - if not validbinaries[program] then - report("binary is not permitted: %s",program) + if validbinaries == true then + -- everything permitted + elseif not validbinaries[program] then + report("binary not permitted, ignoring command: %s",command) + return + elseif suspicious(command) then + report("/ \\ or .. found, ignoring command (use sandbox.registerrunner): %s",command) return end - for i=0,#list do - local n = list[i] - if n then - local v = readable(unquoted(n)) - if v then - list[i] = optionalquoted(v) - else - report("suspicious argument found, run blocked: %s",n) - return - end - end + return action(command,...) +end + +-- local function binaryrunner(action,command,...) +-- local original = command +-- if validbinaries == false then +-- -- nothing permitted +-- report("no binaries permitted, ignoring command: %s",command) +-- return +-- end +-- local program +-- if type(command) == "table" then +-- program = command[0] +-- if program then +-- command = concat(command," ",0) +-- else +-- program = command[1] +-- if program then +-- command = concat(command," ") +-- end +-- end +-- elseif type(command) = "string" then +-- program = lpegmatch(p_split,command) +-- else +-- report("command should be a string or table") +-- return +-- end +-- if not program or program == "" then +-- report("unable to filter binary from command: %s",command) +-- return +-- end +-- if validbinaries == true then +-- -- everything permitted +-- elseif not validbinaries[program] then +-- report("binary not permitted, ignoring command: %s",command) +-- return +-- elseif find(command,"[/\\]") or find(command,"%.%.") then +-- report("/ \\ or .. found, ignoring command (use sandbox.registerrunner): %s",command) +-- return +-- end +-- return action(original,...) +-- end + +local function dummyrunner(action,command,...) + if type(command) == "table" then + command = concat(command," ",command[0] and 0 or 1) end - return action(name) + report("ignoring command: %s",command) end sandbox.filehandlerone = filehandlerone sandbox.filehandlertwo = filehandlertwo sandbox.iohandler = iohandler -sandbox.runhandler = runhandler -sandbox.binaryhandler = binaryhandler function sandbox.disablerunners() - norunners = true + validbinaries = false end -local execute = sandbox.original(os.execute) +function sandbox.disablelibraries() + validlibraries = false +end + +if ffi then + + function sandbox.disablelibraries() + validlibraries = false + for k, v in next, ffi do + if k ~= "gc" then + ffi[k] = nil + end + end + end + + local load = ffi.load + + if load then + + local reported = { } + + function ffi.load(name,...) + if validlibraries == false then + -- all blocked + elseif validlibraries == true then + -- all permitted + return load(name,...) + elseif validlibraries[name] then + -- 'name' permitted + return load(name,...) + else + -- 'name' not permitted + end + if not reported[name] then + report("using library %a is not permitted",name) + reported[name] = true + end + return nil + end + + end -function sandbox.run(name,specification) - return runhandler(execute,name,specification) end ------------------- @@ -360,16 +563,18 @@ local register = sandbox.register if io then overload(io.open, filehandlerone,"io.open") - overload(io.popen, filehandlerone,"io.popen") + overload(io.popen, binaryrunner, "io.popen") overload(io.input, iohandler, "io.input") overload(io.output, iohandler, "io.output") overload(io.lines, filehandlerone,"io.lines") end if os then - overload(os.execute, binaryhandler, "os.execute") - overload(os.spawn, binaryhandler, "os.spawn") - overload(os.exec, binaryhandler, "os.exec") + overload(os.execute, binaryrunner, "os.execute") + overload(os.spawn, dummyrunner, "os.spawn") + overload(os.exec, dummyrunner, "os.exec") + overload(os.resultof, binaryrunner, "os.resultof") + overload(os.pipeto, binaryrunner, "os.pipeto") overload(os.rename, filehandlertwo,"os.rename") overload(os.remove, filehandlerone,"os.remove") end @@ -406,6 +611,11 @@ if epdf then epdf.open = register(epdf.open, filehandlerone,"epdf.open") end +sandbox.registerroot = registerroot +sandbox.registerbinary = registerbinary +sandbox.registerlibrary = registerlibrary +sandbox.validfilename = validfilename + -- not used in a normal mkiv run : os.spawn = os.execute -- not used in a normal mkiv run : os.exec = os.exec diff --git a/tex/context/base/mkiv/util-seq.lua b/tex/context/base/mkiv/util-seq.lua index 32fe59096..5836f5eca 100644 --- a/tex/context/base/mkiv/util-seq.lua +++ b/tex/context/base/mkiv/util-seq.lua @@ -293,7 +293,7 @@ sequencers.compile = compile -- todo: use sequencer (can have arguments and returnvalues etc now) -local template_yes = [[ +local template_yes_state = [[ %s return function(head%s) local ok, done = false, false @@ -301,6 +301,13 @@ return function(head%s) return head, done end]] +local template_yes_nostate = [[ +%s +return function(head%s) +%s + return head, true +end]] + local template_nop = [[ return function() return false, false @@ -308,6 +315,7 @@ end]] function sequencers.nodeprocessor(t,nofarguments) -- todo: handle 'kind' in plug into tostring local list, order, kind, gskip, askip = t.list, t.order, t.kind, t.gskip, t.askip + local nostate = t.nostate local vars, calls, args, n = { }, { }, nil, 0 if nofarguments == 0 then args = "" @@ -335,18 +343,24 @@ function sequencers.nodeprocessor(t,nofarguments) -- todo: handle 'kind' in plug n = n + 1 vars[n] = formatters["local %s = %s"](localized,action) -- only difference with tostring is kind and rets (why no return) - if kind[action] == "nohead" then - calls[n] = formatters[" ok = %s(head%s) done = done or ok"](localized,args) + if nostate then + if kind[action] == "nohead" then + calls[n] = formatters[" %s(head%s)"](localized,args) + else + calls[n] = formatters[" head = %s(head%s)"](localized,args) + end else - calls[n] = formatters[" head, ok = %s(head%s) done = done or ok"](localized,args) + if kind[action] == "nohead" then + calls[n] = formatters[" ok = %s(head%s) if ok then done = true end"](localized,args) + else + calls[n] = formatters[" head, ok = %s(head%s) if ok then done = true end"](localized,args) + end end --- local s = " print('" .. tostring(group) .. " " .. tostring(action) .. " : ' .. tostring(head)) " --- calls[n] = s .. calls[n] .. s end end end end - local processor = #calls > 0 and formatters[template_yes](concat(vars,"\n"),args,concat(calls,"\n")) or template_nop + local processor = #calls > 0 and formatters[nostate and template_yes_nostate or template_yes_state](concat(vars,"\n"),args,concat(calls,"\n")) or template_nop -- print(processor) return processor end diff --git a/tex/context/base/mkiv/util-sql-imp-client.lua b/tex/context/base/mkiv/util-sql-imp-client.lua index 6a019bd3a..a2763feac 100644 --- a/tex/context/base/mkiv/util-sql-imp-client.lua +++ b/tex/context/base/mkiv/util-sql-imp-client.lua @@ -178,6 +178,8 @@ local function datafetched(specification) if trace_sql then local t = osclock() report_state("command: %s",command) + -- for now we don't use sandbox.registerrunners as this module is + -- also used outside context local okay = os.execute(command) report_state("fetchtime: %.3f sec, return code: %i",osclock()-t,okay) -- not okay under linux return okay == 0 diff --git a/tex/context/base/mkiv/util-sql-imp-sqlite.lua b/tex/context/base/mkiv/util-sql-imp-sqlite.lua index bb789f648..1a960c1c3 100644 --- a/tex/context/base/mkiv/util-sql-imp-sqlite.lua +++ b/tex/context/base/mkiv/util-sql-imp-sqlite.lua @@ -26,7 +26,6 @@ local methods = sql.methods local validspecification = helpers.validspecification local preparetemplate = helpers.preparetemplate local splitdata = helpers.splitdata -local replacetemplate = utilities.templates.replace local serialize = sql.serialize local deserialize = sql.deserialize local getserver = sql.getserver diff --git a/tex/context/fonts/mkiv/cambria-math.lfg b/tex/context/fonts/mkiv/cambria-math.lfg index 6415069e6..ae875e64d 100644 --- a/tex/context/fonts/mkiv/cambria-math.lfg +++ b/tex/context/fonts/mkiv/cambria-math.lfg @@ -44,6 +44,11 @@ return { mathematics = { parameters = { DisplayOperatorMinHeight = FixDisplayOperatorMinHeight, - } - } + }, + -- kernpairs = { -- \setupmathematics[kernpairs=yes] + -- [0x1D44E] = { + -- [0x1D44F] = 1000, -- 𝑎𝑏 demo + -- } + -- }, + }, } diff --git a/tex/context/fonts/mkiv/type-imp-ebgaramond.mkiv b/tex/context/fonts/mkiv/type-imp-ebgaramond.mkiv index 838654d49..cd474242f 100644 --- a/tex/context/fonts/mkiv/type-imp-ebgaramond.mkiv +++ b/tex/context/fonts/mkiv/type-imp-ebgaramond.mkiv @@ -11,6 +11,8 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. +% Why so many features ... dead slow too + \definefontfeature [eb-garamond-normal] [default] @@ -32,7 +34,7 @@ \setups[font:fallback:serif] \definefontsynonym [Serif] [file:ebgaramond-regular] [features=eb-garamond-normal] \definefontsynonym [SerifItalic] [file:ebgaramond-italic] [features=eb-garamond-normal] - \definefontsynonym [SerifBold] [file:ebgaramond-bold] [features=eb-garamond-normal] + \definefontsynonym [SerifBold] [file:ebgaramond-regular] [features=eb-garamond-normal] % there is no bold \definefontsynonym [SerifCaps] [Serif] [features=eb-garamond-smallcaps] \stoptypescript diff --git a/tex/context/interface/mkii/keys-cs.xml b/tex/context/interface/mkii/keys-cs.xml index 65def6288..9ce2a779a 100644 --- a/tex/context/interface/mkii/keys-cs.xml +++ b/tex/context/interface/mkii/keys-cs.xml @@ -215,6 +215,7 @@ <cd:variable name='formulas' value='rovnice'/> <cd:variable name='forward' value='vpred'/> <cd:variable name='four' value='ctyri'/> + <cd:variable name='fractions' value='fractions'/> <cd:variable name='frame' value='ramecek'/> <cd:variable name='framedtext' value='oramovanytext'/> <cd:variable name='friday' value='patek'/> diff --git a/tex/context/interface/mkii/keys-de.xml b/tex/context/interface/mkii/keys-de.xml index a607b6358..404f8da89 100644 --- a/tex/context/interface/mkii/keys-de.xml +++ b/tex/context/interface/mkii/keys-de.xml @@ -215,6 +215,7 @@ <cd:variable name='formulas' value='formeln'/> <cd:variable name='forward' value='vorwaerts'/> <cd:variable name='four' value='vier'/> + <cd:variable name='fractions' value='fractions'/> <cd:variable name='frame' value='rahmen'/> <cd:variable name='framedtext' value='umrahmtertext'/> <cd:variable name='friday' value='freitag'/> diff --git a/tex/context/interface/mkii/keys-en.xml b/tex/context/interface/mkii/keys-en.xml index c84454f54..a1c935db8 100644 --- a/tex/context/interface/mkii/keys-en.xml +++ b/tex/context/interface/mkii/keys-en.xml @@ -215,6 +215,7 @@ <cd:variable name='formulas' value='formulas'/> <cd:variable name='forward' value='forward'/> <cd:variable name='four' value='four'/> + <cd:variable name='fractions' value='fractions'/> <cd:variable name='frame' value='frame'/> <cd:variable name='framedtext' value='framedtext'/> <cd:variable name='friday' value='friday'/> diff --git a/tex/context/interface/mkii/keys-fr.xml b/tex/context/interface/mkii/keys-fr.xml index 725272f3c..db6e35ac6 100644 --- a/tex/context/interface/mkii/keys-fr.xml +++ b/tex/context/interface/mkii/keys-fr.xml @@ -215,6 +215,7 @@ <cd:variable name='formulas' value='formules'/> <cd:variable name='forward' value='avance'/> <cd:variable name='four' value='quatre'/> + <cd:variable name='fractions' value='fractions'/> <cd:variable name='frame' value='cadre'/> <cd:variable name='framedtext' value='texteencadre'/> <cd:variable name='friday' value='vendredi'/> diff --git a/tex/context/interface/mkii/keys-it.xml b/tex/context/interface/mkii/keys-it.xml index d9642bf3a..86d6868b4 100644 --- a/tex/context/interface/mkii/keys-it.xml +++ b/tex/context/interface/mkii/keys-it.xml @@ -215,6 +215,7 @@ <cd:variable name='formulas' value='formule'/> <cd:variable name='forward' value='avanti'/> <cd:variable name='four' value='quattro'/> + <cd:variable name='fractions' value='fractions'/> <cd:variable name='frame' value='cornice'/> <cd:variable name='framedtext' value='testoincorniciato'/> <cd:variable name='friday' value='venerdi'/> diff --git a/tex/context/interface/mkii/keys-nl.xml b/tex/context/interface/mkii/keys-nl.xml index add0efe38..1c6077d1e 100644 --- a/tex/context/interface/mkii/keys-nl.xml +++ b/tex/context/interface/mkii/keys-nl.xml @@ -215,6 +215,7 @@ <cd:variable name='formulas' value='formules'/> <cd:variable name='forward' value='vooruit'/> <cd:variable name='four' value='vier'/> + <cd:variable name='fractions' value='fractions'/> <cd:variable name='frame' value='kader'/> <cd:variable name='framedtext' value='kadertekst'/> <cd:variable name='friday' value='vrijdag'/> diff --git a/tex/context/interface/mkii/keys-pe.xml b/tex/context/interface/mkii/keys-pe.xml index 6cb1bf833..91f778c5e 100644 --- a/tex/context/interface/mkii/keys-pe.xml +++ b/tex/context/interface/mkii/keys-pe.xml @@ -215,6 +215,7 @@ <cd:variable name='formulas' value='فرمولها'/> <cd:variable name='forward' value='بهجلو'/> <cd:variable name='four' value='چهار'/> + <cd:variable name='fractions' value='fractions'/> <cd:variable name='frame' value='قالب'/> <cd:variable name='framedtext' value='متنقالبی'/> <cd:variable name='friday' value='جمعه'/> diff --git a/tex/context/interface/mkii/keys-ro.xml b/tex/context/interface/mkii/keys-ro.xml index f1d644a29..a4566c4b4 100644 --- a/tex/context/interface/mkii/keys-ro.xml +++ b/tex/context/interface/mkii/keys-ro.xml @@ -215,6 +215,7 @@ <cd:variable name='formulas' value='formule'/> <cd:variable name='forward' value='avans'/> <cd:variable name='four' value='patru'/> + <cd:variable name='fractions' value='fractions'/> <cd:variable name='frame' value='incadrat'/> <cd:variable name='framedtext' value='textinconjurat'/> <cd:variable name='friday' value='vineri'/> diff --git a/tex/context/interface/mkiv/i-boxes.xml b/tex/context/interface/mkiv/i-boxes.xml index fda2600e5..648106b89 100644 --- a/tex/context/interface/mkiv/i-boxes.xml +++ b/tex/context/interface/mkiv/i-boxes.xml @@ -444,7 +444,7 @@ <cd:content/> </cd:arguments> </cd:command> - + <cd:command name="limitatelines" file="supp-box.mkiv"> <cd:arguments> <cd:resolve name="argument-number"/> @@ -1036,4 +1036,7 @@ </cd:arguments> </cd:command> + <cd:command name="lastlinewidth" file="supp-box.mkiv"> + </cd:command> + </cd:interface> diff --git a/tex/context/interface/mkiv/i-context.pdf b/tex/context/interface/mkiv/i-context.pdf Binary files differindex bf623a1eb..a3be00bdf 100644 --- a/tex/context/interface/mkiv/i-context.pdf +++ b/tex/context/interface/mkiv/i-context.pdf diff --git a/tex/context/interface/mkiv/i-fonts.xml b/tex/context/interface/mkiv/i-fonts.xml index 37542e1c9..46e8a0930 100644 --- a/tex/context/interface/mkiv/i-fonts.xml +++ b/tex/context/interface/mkiv/i-fonts.xml @@ -1063,6 +1063,8 @@ <cd:command name="settabular" file="font-pre.mkiv"/> + <cd:command name="setfractions" file="font-pre.mkiv"/> + <cd:command name="setsuperiors" file="font-pre.mkiv"/> <cd:command name="tinyfont" file="font-pre.mkiv"/> diff --git a/tex/context/interface/mkiv/i-readme.pdf b/tex/context/interface/mkiv/i-readme.pdf Binary files differindex 850c10386..bcb7a4fb6 100644 --- a/tex/context/interface/mkiv/i-readme.pdf +++ b/tex/context/interface/mkiv/i-readme.pdf diff --git a/tex/context/modules/mkiv/m-matrix.mkiv b/tex/context/modules/mkiv/m-matrix.mkiv index ccb376e39..b72453bdd 100644 --- a/tex/context/modules/mkiv/m-matrix.mkiv +++ b/tex/context/modules/mkiv/m-matrix.mkiv @@ -29,6 +29,8 @@ local copy = table.copy local insert = table.insert local remove = table.remove +local context = context + local matrix = { } moduledata.matrix = matrix @@ -67,27 +69,58 @@ end -- todo: define a matrix at the tex end so that we have more control -local fences_p = { - left = "\\left(\\,", - right = "\\,\\right)", +local fences = { + parentheses = { left = "\\left(\\,", right = "\\,\\right)" }, + brackets = { left = "\\left[\\,", right = "\\,\\right]" }, + bars = { left = "\\left|\\,", right = "\\,\\right|" }, } -local fences_b = { - left = "\\left[\\,", - right = "\\,\\right]", -} +-- one can add more fences + +fences.bar = fences.bars +fences.parenthesis = fences.parentheses +fences.bracket = fences.brackets + +-- one can set the template + +matrix.template = "%0.3F" function matrix.typeset(m,options) - local options = settings_to_hash(options or "") - context.startmatrix(options.determinant and fences_b or fences_p) - for i=1, #m do - local mi = m[i] - for j=1,#mi do - context.NC(mi[j]) - end - context.NR() + if type(m) == "table" then + local options = settings_to_hash(options or "") + local whatever = options.determinant == "yes" and fences.bars or fences.parentheses + if options.fences then + whatever = fences[options.fences] or whatever + elseif options.determinant then + whatever = fences.brackets + -- whatever = fences.bars + end + local template = options.template or matrix.template + if template == "yes" then + template = matrix.template + elseif template == "no" then + template = false + elseif tonumber(template) then + template = "%0." .. template .. "F" end - context.stopmatrix() + context.startmatrix(whatever) + for i=1, #m do + local mi = m[i] + for j=1,#mi do + context.NC() + local n = mi[j] + if template and tonumber(n) then + context(template,n) + else + context(mi[j]) + end + end + context.NR() + end + context.stopmatrix() + elseif m then + context(m) + end end -- interchange two rows (i-th, j-th) @@ -151,7 +184,7 @@ function matrix.inner(u,v) end local nv = #v if nv ~= nu then - return 0 + return "error: size mismatch" end local result = 0 for i=1,nu do @@ -163,8 +196,8 @@ end -- product of two matrices function matrix.product(m1,m2) - local product = { } if #m1[1] == #m2 then + local product = { } for i=1,#m1 do local m1i = m1[i] local mrow = { } @@ -177,8 +210,10 @@ function matrix.product(m1,m2) end product[i] = mrow end + return product + else + return "error: size mismatch" end - return product end local function uppertri(m,sign) @@ -225,7 +260,7 @@ function matrix.determinant(m) end return s*d else - return 0 + return "error: not a square matrix" end end @@ -295,7 +330,7 @@ matrix.rowEchelon = rowechelon -- solve the linear equation m X = c -local function solve(m,c) +local function solve(m,c) local n = #m if n ~= #c then return copy(m) @@ -393,14 +428,14 @@ moduledata.matrix.typeset(moduledata.matrix.multiply(document.DemoMatrixA, 2, 3) \stopsubject -\startsubject[title={Row 2 + $3 \times r_4$}] +\startsubject[title={Row 2 + $4 \times r_3$}] \startluacode moduledata.matrix.typeset(document.DemoMatrixA) context.blank() moduledata.matrix.sumrow(document.DemoMatrixA, 2, 3, 4) context.blank() -moduledata.matrix.typeset(document.DemoMatrixA) +moduledata.matrix.typeset(document.DemoMatrixA,{ fences = "bars" } ) \stopluacode \stopsubject @@ -445,7 +480,7 @@ local m = { { 0, 0, 2 }, { 2, 2, -6 }, } -context(moduledata.matrix.determinant(m)) +context(moduledata.matrix.determinant(m, "determinant=yes" )) \stopluacode \stopsubject @@ -461,7 +496,8 @@ local m = { } moduledata.matrix.typeset(m) -moduledata.matrix.typeset(moduledata.matrix.rowechelon(m,1)) +context.blank() +moduledata.matrix.typeset(moduledata.matrix.rowechelon(m,1), { determinant = "yes" }) \stopluacode \stopsubject @@ -479,6 +515,14 @@ local m = { local c = { 5, 2, 6, 8 } moduledata.matrix.typeset(moduledata.matrix.solve(m,c)) +context.blank() +moduledata.matrix.typeset(moduledata.matrix.solve(m,c), { template = 6 }) +context.blank() +moduledata.matrix.typeset(moduledata.matrix.solve(m,c), { template = "no" }) +context.blank() +moduledata.matrix.typeset(moduledata.matrix.solve(m,c), { template = "%0.3f" }) +context.blank() +moduledata.matrix.typeset(moduledata.matrix.solve(m,c), { template = "%0.4F" }) \stopluacode \stopsubject diff --git a/tex/context/modules/mkiv/m-steps.lua b/tex/context/modules/mkiv/m-steps.lua index 7fbb58370..ce84866a4 100644 --- a/tex/context/modules/mkiv/m-steps.lua +++ b/tex/context/modules/mkiv/m-steps.lua @@ -177,7 +177,6 @@ local function step_make_chart(settings) start() flush("step_begin_chart ;") -- - print(chartsettings.alternative) local alternative = chartsettings.alternative if not alternative or alternative == "" then alternative = chart.alternative diff --git a/tex/context/modules/mkiv/m-steps.mkvi b/tex/context/modules/mkiv/m-steps.mkvi index ce018a0d1..873015fd6 100644 --- a/tex/context/modules/mkiv/m-steps.mkvi +++ b/tex/context/modules/mkiv/m-steps.mkvi @@ -85,7 +85,8 @@ \setupSTEPlines [\c!alternative=1, \c!rulethickness=.15\bodyfontsize, - \c!height=3\bodyfontsize, + \c!height=\STEPlineparameter\c!width, + \c!width=3\bodyfontsize, \c!distance=.5\bodyfontsize, \c!offset=.25\bodyfontsize, \c!color=STEPlinecolor] diff --git a/tex/context/modules/mkiv/s-inf-03.mkiv b/tex/context/modules/mkiv/s-inf-03.mkiv index a253bed77..31333b8e5 100644 --- a/tex/context/modules/mkiv/s-inf-03.mkiv +++ b/tex/context/modules/mkiv/s-inf-03.mkiv @@ -16,7 +16,7 @@ \definefont [TitlePageFont] - [MonoBold at 15pt] + [MonoBold at 14pt] \setupbodyfont [tt,8pt] @@ -25,7 +25,7 @@ \definefont [TitlePageFont] - [MonoBold at 18pt] + [MonoBold at 17pt] \setupbodyfont [tt] @@ -159,7 +159,7 @@ local skipglobal = table.tohash { "_G", "_M", "_ENV", "", "context", "modules", "global", "arg", "utf", 1, "_ptbs_", "_pcol_", "_plib_", "_clib_", "_tlib_", - "kpse", "commands", + "kpse", "commands", "ffi", } local skipkeys = table.tohash { diff --git a/tex/context/modules/mkiv/s-languages-hyphenation.lua b/tex/context/modules/mkiv/s-languages-hyphenation.lua index 971ca3d8f..6d3cf3d3e 100644 --- a/tex/context/modules/mkiv/s-languages-hyphenation.lua +++ b/tex/context/modules/mkiv/s-languages-hyphenation.lua @@ -39,6 +39,8 @@ local getdisc = nuts.getdisc local getattr = nuts.getattr local getfont = nuts.getfont local getfield = nuts.getfield +local getlang = nuts.getlang +local setlang = nuts.setlang local setlink = nuts.setlink local setdisc = nuts.setdisc local setfield = nuts.setfield @@ -129,7 +131,7 @@ local function getlanguage(head,l,left,right) local t = { } for n in traverse_by_id(glyph_code,tonut(head)) do t[n] = { - getfield(n,"lang"), + getlang(n), getfield(n,"left"), getfield(n,"right"), } @@ -148,7 +150,7 @@ function moduledata.languages.hyphenation.showhyphens(head) -- somehow assigning -1 fails for n in traverse_by_id(glyph_code,tonut(head)) do cached[n] = { - getfield(n,"lang"), + getlang(n), getfield(n,"left"), getfield(n,"right") } @@ -161,7 +163,7 @@ function moduledata.languages.hyphenation.showhyphens(head) local lmin = s.lefthyphenmin local rmin = s.righthyphenmin for n in next, cached do - setfield(n,"lang",l) + setlang(n,l) setfield(n,"left",lmin) setfield(n,"right",rmin) end @@ -173,7 +175,7 @@ function moduledata.languages.hyphenation.showhyphens(head) mark(head,marked[i],1/16,l/2,l/4,"hyphenation:"..(colorbytag and tags[i] or i)) end for n, d in next, cached do - setfield(n,"lang",d[1]) + setlang(n,d[1]) setfield(n,"left",d[2]) setfield(n,"right",d[3]) end diff --git a/tex/context/sample/common/douglas.tex b/tex/context/sample/common/douglas.tex index 838c6d24d..0aa9486e6 100644 --- a/tex/context/sample/common/douglas.tex +++ b/tex/context/sample/common/douglas.tex @@ -4,7 +4,7 @@ of his forthcoming books|=|from the typesetting and layout down to the very shapes of the letters! Seldom has an author had anything remotely like this power to control the final appearance of his or her work. Knuth's \TEX\ -typesetting system has become well|-|known and as available in +typesetting system has become well|-|known and is available in many countries around the world. By contrast, his \METAFONT\ system for designing families of typefaces has not become as well known or as available. diff --git a/tex/context/sample/common/knuth.tex b/tex/context/sample/common/knuth.tex index 30b6310cc..2f6a2f8e7 100644 --- a/tex/context/sample/common/knuth.tex +++ b/tex/context/sample/common/knuth.tex @@ -13,4 +13,4 @@ But a system cannot be successful if it is too strongly influenced by a single person. Once the initial design is complete and fairly robust, the real test begins as people with many different viewpoints undertake their own -experiments. +experiments. diff --git a/tex/generic/context/luatex/luatex-basics-nod.lua b/tex/generic/context/luatex/luatex-basics-nod.lua index 42a7a2e29..5571a82ba 100644 --- a/tex/generic/context/luatex/luatex-basics-nod.lua +++ b/tex/generic/context/luatex/luatex-basics-nod.lua @@ -171,6 +171,8 @@ nodes.mlist_to_hlist = node.mlist_to_hlist -- we can go nuts (e.g. experimental); this split permits us us keep code -- used elsewhere stable but at the same time play around in context +-- much of this will go away + local direct = node.direct local nuts = { } nodes.nuts = nuts @@ -201,16 +203,39 @@ nuts.setattr = setfield nuts.getfont = direct.getfont nuts.setfont = direct.setfont nuts.getsubtype = direct.getsubtype -nuts.setsubtype = direct.setsubtype or function(n,s) setfield(n,"subtype",s) end +nuts.setsubtype = direct.setsubtype nuts.getchar = direct.getchar nuts.setchar = direct.setchar nuts.getdisc = direct.getdisc nuts.setdisc = direct.setdisc nuts.setlink = direct.setlink nuts.getlist = direct.getlist -nuts.setlist = direct.setlist or function(n,l) setfield(n,"list",l) end -nuts.getleader = direct.getleader -nuts.setleader = direct.setleader or function(n,l) setfield(n,"leader",l) end +nuts.setlist = direct.setlist + +nuts.getoffsets = direct.getoffsets or + function(n) + return getfield(n,"xoffset"), getfield(n,"yoffset") + end +nuts.setoffsets = direct.setoffsets or + function(n,x,y) + if x then setfield(n,"xoffset",x) end + if y then setfield(n,"xoffset",y) end + end + +nuts.getleader = direct.getleader or function(n) return getfield(n,"leader") end +nuts.setleader = direct.setleader or function(n,l) setfield(n,"leader",l) end +nuts.getcomponents = direct.getcomponents or function(n) return getfield(n,"components") end +nuts.setcomponents = direct.setcomponents or function(n,c) setfield(n,"components",c) end +nuts.getkern = direct.getkern or function(n) return getfield(n,"kern") end +nuts.setkern = direct.setkern or function(n,k) setfield(n,"kern",k) end +nuts.getdir = direct.getkern or function(n) return getfield(n,"dir") end +nuts.setdir = direct.setkern or function(n,d) setfield(n,"dir",d) end +nuts.getwidth = direct.getwidth or function(n) return getfield(n,"width") end +nuts.setwidth = direct.setwidth or function(n,w) return setfield(n,"width",w) end +nuts.getheight = direct.getheight or function(n) return getfield(n,"height") end +nuts.setheight = direct.setheight or function(n,h) return setfield(n,"height",h) end +nuts.getdepth = direct.getdepth or function(n) return getfield(n,"depth") end +nuts.setdepth = direct.setdepth or function(n,d) return setfield(n,"depth",d) end if not direct.is_glyph then local getchar = direct.getchar @@ -312,3 +337,128 @@ end nodes.setprop = nodes.setproperty nodes.getprop = nodes.getproperty + +-- a few helpers (we need to keep 'm in sync with context) .. some day components +-- might go so here we isolate them + +local setprev = nuts.setprev +local setnext = nuts.setnext +local getnext = nuts.getnext +local setlink = nuts.setlink +local getfield = nuts.getfield +local setfield = nuts.setfield +local getcomponents = nuts.getcomponents +local setcomponents = nuts.setcomponents + +local find_tail = nuts.tail +local flush_list = nuts.flush_list +local flush_node = nuts.flush_node +local traverse_id = nuts.traverse_id +local copy_node = nuts.copy_node + +local glyph_code = nodes.nodecodes.glyph + +function nuts.set_components(target,start,stop) + local head = getcomponents(target) + if head then + flush_list(head) + head = nil + end + if start then + setprev(start) + else + return nil + end + if stop then + setnext(stop) + end + local tail = nil + while start do + local c = getcomponents(start) + local n = getnext(start) + if c then + if head then + setlink(tail,c) + else + head = c + end + tail = find_tail(c) + setcomponents(start) + flush_node(start) + else + if head then + setlink(tail,start) + else + head = start + end + tail = start + end + start = n + end + setcomponents(target,head) + -- maybe also upgrade the subtype but we don't use it anyway + return head +end + +nuts.get_components = nuts.getcomponents + +function nuts.take_components(target) + local c = getcomponents(target) + setcomponents(target) + -- maybe also upgrade the subtype but we don't use it anyway + return c +end + +function nuts.count_components(n,marks) + local components = getcomponents(n) + if components then + if marks then + local i = 0 + for g in traverse_id(glyph_code,components) do + if not marks[getchar(g)] then + i = i + 1 + end + end + return i + else + return count(glyph_code,components) + end + else + return 0 + end +end + +function nuts.copy_no_components(g,copyinjection) + local components = getcomponents(g) + if components then + setcomponents(g) + local n = copy_node(g) + if copyinjection then + copyinjection(n,g) + end + setcomponents(g,components) + -- maybe also upgrade the subtype but we don't use it anyway + return n + else + local n = copy_node(g) + if copyinjection then + copyinjection(n,g) + end + return n + end +end + +function nuts.copy_only_glyphs(current) + local head = nil + local previous = nil + for n in traverse_id(glyph_code,current) do + n = copy_node(n) + if head then + setlink(previous,n) + else + head = n + end + previous = n + end + return head +end diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index 3a4a70c62..8ececb5a9 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 : 01/27/17 14:39:39 +-- merge date : 02/17/17 10:17:41 do -- begin closure to overcome local limits and interference @@ -108,6 +108,18 @@ if flush then local spawn=os.spawn if spawn then function os.spawn (...) flush() return spawn (...) end end local popen=io.popen if popen then function io.popen (...) flush() return popen (...) end end end +if ffi and ffi.number then +else + local okay + okay,ffi=pcall(require,"ffi") + if not ffi then + elseif ffi.os=="" or ffi.arch=="" then + ffi=nil + elseif ffi.number then + else + ffi.number=tonumber + end +end end -- closure @@ -678,27 +690,7 @@ function lpeg.append(list,pp,delayed,checked) end local p_false=P(false) local p_true=P(true) -local function make(t) - local function making(t) - local p=p_false - local keys=sortedkeys(t) - for i=1,#keys do - local k=keys[i] - if k~="" then - local v=t[k] - if v==true then - p=p+P(k)*p_true - elseif v==false then - else - p=p+P(k)*making(v) - end - end - end - if t[""] then - p=p+p_true - end - return p - end +local function make(t,rest) local p=p_false local keys=sortedkeys(t) for i=1,#keys do @@ -709,10 +701,13 @@ local function make(t) p=p+P(k)*p_true elseif v==false then else - p=p+P(k)*making(v) + p=p+P(k)*make(v,v[""]) end end end + if rest then + p=p+p_true + end return p end local function collapse(t,x) @@ -3491,6 +3486,23 @@ function utf.chrlen(u) (u<0xFC and 5) or (u<0xFE and 6) or 0 end +local extract=bit32.extract +local char=string.char +function unicode.toutf32string(n) + if n<=0xFF then + return + char(n).."\000\000\000" + elseif n<=0xFFFF then + return + char(extract(n,0,8))..char(extract(n,8,8)).."\000\000" + elseif n<=0xFFFFFF then + return + char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8)).."\000" + else + return + char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8))..char(extract(n,24,8)) + end +end end -- closure @@ -4296,6 +4308,14 @@ function files.readinteger2(f) return n end end + function files.readinteger2(f) + local a,b=byte(f:read(2),1,2) + if a>=0x80 then + return 0x100*a+b-0x10000 + else + return 0x100*a+b + end + end function files.readinteger2le(f) local b,a=byte(f:read(2),1,2) local n=0x100*a+b @@ -4348,6 +4368,14 @@ function files.readinteger4(f) return n end end + function files.readinteger4(f) + local a,b,c,d=byte(f:read(4),1,4) + if a>=0x80 then + return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 + else + return 0x1000000*a+0x10000*b+0x100*c+d + end + end function files.readinteger4le(f) local d,c,b,a=byte(f:read(4),1,4) local n=0x1000000*a+0x10000*b+0x100*c+d @@ -4969,16 +4997,37 @@ nuts.setattr=setfield nuts.getfont=direct.getfont nuts.setfont=direct.setfont nuts.getsubtype=direct.getsubtype -nuts.setsubtype=direct.setsubtype or function(n,s) setfield(n,"subtype",s) end +nuts.setsubtype=direct.setsubtype nuts.getchar=direct.getchar nuts.setchar=direct.setchar nuts.getdisc=direct.getdisc nuts.setdisc=direct.setdisc nuts.setlink=direct.setlink nuts.getlist=direct.getlist -nuts.setlist=direct.setlist or function(n,l) setfield(n,"list",l) end -nuts.getleader=direct.getleader -nuts.setleader=direct.setleader or function(n,l) setfield(n,"leader",l) end +nuts.setlist=direct.setlist +nuts.getoffsets=direct.getoffsets or + function(n) + return getfield(n,"xoffset"),getfield(n,"yoffset") + end +nuts.setoffsets=direct.setoffsets or + function(n,x,y) + if x then setfield(n,"xoffset",x) end + if y then setfield(n,"xoffset",y) end + end +nuts.getleader=direct.getleader or function(n) return getfield(n,"leader") end +nuts.setleader=direct.setleader or function(n,l) setfield(n,"leader",l) end +nuts.getcomponents=direct.getcomponents or function(n) return getfield(n,"components") end +nuts.setcomponents=direct.setcomponents or function(n,c) setfield(n,"components",c) end +nuts.getkern=direct.getkern or function(n) return getfield(n,"kern") end +nuts.setkern=direct.setkern or function(n,k) setfield(n,"kern",k) end +nuts.getdir=direct.getkern or function(n) return getfield(n,"dir") end +nuts.setdir=direct.setkern or function(n,d) setfield(n,"dir",d) end +nuts.getwidth=direct.getwidth or function(n) return getfield(n,"width") end +nuts.setwidth=direct.setwidth or function(n,w) return setfield(n,"width",w) end +nuts.getheight=direct.getheight or function(n) return getfield(n,"height") end +nuts.setheight=direct.setheight or function(n,h) return setfield(n,"height",h) end +nuts.getdepth=direct.getdepth or function(n) return getfield(n,"depth") end +nuts.setdepth=direct.setdepth or function(n,d) return setfield(n,"depth",d) end if not direct.is_glyph then local getchar=direct.getchar local getid=direct.getid @@ -5066,6 +5115,116 @@ nuts.setprop=function(n,k,v) end nodes.setprop=nodes.setproperty nodes.getprop=nodes.getproperty +local setprev=nuts.setprev +local setnext=nuts.setnext +local getnext=nuts.getnext +local setlink=nuts.setlink +local getfield=nuts.getfield +local setfield=nuts.setfield +local getcomponents=nuts.getcomponents +local setcomponents=nuts.setcomponents +local find_tail=nuts.tail +local flush_list=nuts.flush_list +local flush_node=nuts.flush_node +local traverse_id=nuts.traverse_id +local copy_node=nuts.copy_node +local glyph_code=nodes.nodecodes.glyph +function nuts.set_components(target,start,stop) + local head=getcomponents(target) + if head then + flush_list(head) + head=nil + end + if start then + setprev(start) + else + return nil + end + if stop then + setnext(stop) + end + local tail=nil + while start do + local c=getcomponents(start) + local n=getnext(start) + if c then + if head then + setlink(tail,c) + else + head=c + end + tail=find_tail(c) + setcomponents(start) + flush_node(start) + else + if head then + setlink(tail,start) + else + head=start + end + tail=start + end + start=n + end + setcomponents(target,head) + return head +end +nuts.get_components=nuts.getcomponents +function nuts.take_components(target) + local c=getcomponents(target) + setcomponents(target) + return c +end +function nuts.count_components(n,marks) + local components=getcomponents(n) + if components then + if marks then + local i=0 + for g in traverse_id(glyph_code,components) do + if not marks[getchar(g)] then + i=i+1 + end + end + return i + else + return count(glyph_code,components) + end + else + return 0 + end +end +function nuts.copy_no_components(g,copyinjection) + local components=getcomponents(g) + if components then + setcomponents(g) + local n=copy_node(g) + if copyinjection then + copyinjection(n,g) + end + setcomponents(g,components) + return n + else + local n=copy_node(g) + if copyinjection then + copyinjection(n,g) + end + return n + end +end +function nuts.copy_only_glyphs(current) + local head=nil + local previous=nil + for n in traverse_id(glyph_code,current) do + n=copy_node(n) + if head then + setlink(previous,n) + else + head=n + end + previous=n + end + return head +end end -- closure @@ -12885,6 +13044,7 @@ do sublookuplist[nofsublookups]=copy(h) sublookuphash[lookupid]=nofsublookups sublookupcheck[lookupid]=1 + h=nofsublookups else report_issue(i,what,sequence,"missing") rule.lookups=nil @@ -15600,7 +15760,7 @@ if not modules then modules={} end modules ['font-otl']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files", } -local gmatch,find,match,lower,strip=string.gmatch,string.find,string.match,string.lower,string.strip +local lower=string.lower local type,next,tonumber,tostring,unpack=type,next,tonumber,tostring,unpack local abs=math.abs local derivetable=table.derive @@ -15667,26 +15827,6 @@ function otf.load(filename,sub,featurefile) hash=hash.."-"..sub end hash=containers.cleanname(hash) - local featurefiles - if featurefile then - featurefiles={} - for s in gmatch(featurefile,"[^,]+") do - local name=resolvers.findfile(file.addsuffix(s,'fea'),'fea') or "" - if name=="" then - report_otf("loading error, no featurefile %a",s) - else - local attr=lfs.attributes(name) - featurefiles[#featurefiles+1]={ - name=name, - size=attr and attr.size or 0, - time=attr and attr.modification or 0, - } - end - end - if #featurefiles==0 then - featurefiles=nil - end - end local data=containers.read(otf.cache,hash) local reload=not data or data.size~=size or data.time~=time or data.tableversion~=otfreaders.tableversion if forceload then @@ -15753,6 +15893,17 @@ function otf.load(filename,sub,featurefile) applyruntimefixes(filename,data) end data.metadata.math=data.resources.mathconstants + local classes=data.resources.classes + if not classes then + local descriptions=data.descriptions + classes=setmetatableindex(function(t,k) + local d=descriptions[k] + local v=(d and d.class or "base") or false + t[k]=v + return v + end) + data.resources.classes=classes + end end return data end @@ -16631,7 +16782,6 @@ local trace_injections=false registertracker("fonts.injections",function(v) trac local trace_marks=false registertracker("fonts.injections.marks",function(v) trace_marks=v end) local trace_cursive=false registertracker("fonts.injections.cursive",function(v) trace_cursive=v end) local trace_spaces=false registertracker("fonts.injections.spaces",function(v) trace_spaces=v end) -local use_advance=false directives.register("fonts.injections.advance",function(v) use_advance=v end) local report_injections=logs.reporter("fonts","injections") local report_spaces=logs.reporter("fonts","spaces") local attributes,nodes,node=attributes,nodes,node @@ -16659,12 +16809,18 @@ local getnext=nuts.getnext local getprev=nuts.getprev local getid=nuts.getid local getfont=nuts.getfont -local getsubtype=nuts.getsubtype local getchar=nuts.getchar +local getoffsets=nuts.getoffsets local getboth=nuts.getboth -local ischar=nuts.is_char local getdisc=nuts.getdisc local setdisc=nuts.setdisc +local setoffsets=nuts.setoffsets +local ischar=nuts.is_char +local getkern=nuts.getkern +local setkern=nuts.setkern +local setlink=nuts.setlink +local setwidth=nuts.setwidth +local getwidth=nuts.getwidth local traverse_id=nuts.traverse_id local traverse_char=nuts.traverse_char local insert_node_before=nuts.insert_before @@ -16706,7 +16862,7 @@ function injections.copy(target,source) if tp then tp.injections=si else - propertydata[target]={ + properties[target]={ injections=si, } end @@ -17035,11 +17191,12 @@ local function show_result(head) while current do local id=getid(current) if id==glyph_code then - report_injections("char: %C, width %p, xoffset %p, yoffset %p", - getchar(current),getfield(current,"width"),getfield(current,"xoffset"),getfield(current,"yoffset")) + local w=getwidth(current) + local x,y=getoffsets(current) + report_injections("char: %C, width %p, xoffset %p, yoffset %p",getchar(current),w,x,y) skipping=false elseif id==kern_code then - report_injections("kern: %p",getfield(current,"kern")) + report_injections("kern: %p",getkern(current)) skipping=false elseif not skipping then report_injections() @@ -17065,70 +17222,58 @@ local function inject_kerns_only(head,where) local posttail=nil local replacetail=nil while current do - local id=getid(current) local next=getnext(current) - if id==glyph_code then - if getsubtype(current)<256 then - local p=rawget(properties,current) - if p then - local i=p.injections - if i then - local leftkern=i.leftkern - if leftkern and leftkern~=0 then - if use_advance then - setfield(current,"xoffset",leftkern) - setfield(current,"xadvance",leftkern) - else - insert_node_before(head,current,newkern(leftkern)) + local char,id=ischar(current) + if char then + local p=rawget(properties,current) + if p then + local i=p.injections + if i then + local leftkern=i.leftkern + if leftkern and leftkern~=0 then + insert_node_before(head,current,newkern(leftkern)) + end + end + if prevdisc then + local done=false + if post then + local i=p.postinjections + if i then + local leftkern=i.leftkern + if leftkern and leftkern~=0 then + setlink(posttail,newkern(leftkern)) + done=true end end end - if prevdisc then - local done=false - if post then - local i=p.postinjections - if i then - local leftkern=i.leftkern - if leftkern and leftkern~=0 then - if use_advance then - setfield(post,"xadvance",leftkern) - else - insert_node_after(post,posttail,newkern(leftkern)) - done=true - end - end + if replace then + local i=p.replaceinjections + if i then + local leftkern=i.leftkern + if leftkern and leftkern~=0 then + setlink(replacetail,newkern(leftkern)) + done=true end end - if replace then - local i=p.replaceinjections - if i then - local leftkern=i.leftkern - if leftkern and leftkern~=0 then - if use_advance then - setfield(replace,"xadvance",leftkern) - else - insert_node_after(replace,replacetail,newkern(leftkern)) - done=true - end - end - end - else - local i=p.emptyinjections - if i then - local leftkern=i.leftkern - if leftkern and leftkern~=0 then - setfield(prev,"replace",newkern(leftkern)) - end + else + local i=p.emptyinjections + if i then + local leftkern=i.leftkern + if leftkern and leftkern~=0 then + setfield(prev,"replace",newkern(leftkern)) end end - if done then - setdisc(prevdisc,pre,post,replace) - end + end + if done then + setdisc(prevdisc,pre,post,replace) end end end prevdisc=nil prevglyph=current + elseif char==false then + prevdisc=nil + prevglyph=current elseif id==disc_code then pre,post,replace,pretail,posttail,replacetail=getdisc(current,true) local done=false @@ -17140,13 +17285,8 @@ local function inject_kerns_only(head,where) if i then local leftkern=i.leftkern if leftkern and leftkern~=0 then - if use_advance then - setfield(pre,"xoffset",leftkern) - setfield(pre,"xadvance",leftkern) - else - pre=insert_node_before(pre,n,newkern(leftkern)) - done=true - end + pre=insert_node_before(pre,n,newkern(leftkern)) + done=true end end end @@ -17160,13 +17300,8 @@ local function inject_kerns_only(head,where) if i then local leftkern=i.leftkern if leftkern and leftkern~=0 then - if use_advance then - setfield(post,"xoffset",leftkern) - setfield(post,"xadvance",leftkern) - else - post=insert_node_before(post,n,newkern(leftkern)) - done=true - end + post=insert_node_before(post,n,newkern(leftkern)) + done=true end end end @@ -17180,13 +17315,8 @@ local function inject_kerns_only(head,where) if i then local leftkern=i.leftkern if leftkern and leftkern~=0 then - if use_advance then - setfield(replace,"xoffset",leftkern) - setfield(replace,"xadvance",leftkern) - else - replace=insert_node_before(replace,n,newkern(leftkern)) - done=true - end + replace=insert_node_before(replace,n,newkern(leftkern)) + done=true end end end @@ -17228,78 +17358,79 @@ local function inject_pairs_only(head,where) local posttail=nil local replacetail=nil while current do - local id=getid(current) local next=getnext(current) - if id==glyph_code then - if getsubtype(current)<256 then - local p=rawget(properties,current) - if p then - local i=p.injections + local char,id=ischar(current) + if char then + local p=rawget(properties,current) + if p then + local i=p.injections + if i then + local yoffset=i.yoffset + if yoffset and yoffset~=0 then + setoffsets(current,false,yoffset) + end + local leftkern=i.leftkern + if leftkern and leftkern~=0 then + head=insert_node_before(head,current,newkern(leftkern)) + end + local rightkern=i.rightkern + if rightkern and rightkern~=0 then + insert_node_after(head,current,newkern(rightkern)) + end + else + local i=p.emptyinjections if i then - local yoffset=i.yoffset - if yoffset and yoffset~=0 then - setfield(current,"yoffset",yoffset) - end - local leftkern=i.leftkern - if leftkern and leftkern~=0 then - head=insert_node_before(head,current,newkern(leftkern)) - end local rightkern=i.rightkern if rightkern and rightkern~=0 then - insert_node_after(head,current,newkern(rightkern)) - end - else - local i=p.emptyinjections - if i then - local rightkern=i.rightkern - if rightkern and rightkern~=0 then - if next and getid(next)==disc_code then - if replace then - else - setfield(next,"replace",newkern(rightkern)) - end + if next and getid(next)==disc_code then + if replace then + else + setfield(next,"replace",newkern(rightkern)) end end end end - if prevdisc then - local done=false - if post then - local i=p.postinjections - if i then - local leftkern=i.leftkern - if leftkern and leftkern~=0 then - insert_node_after(post,posttail,newkern(leftkern)) - done=true - end + end + if prevdisc then + local done=false + if post then + local i=p.postinjections + if i then + local leftkern=i.leftkern + if leftkern and leftkern~=0 then + setlink(posttail,newkern(leftkern)) + done=true end end - if replace then - local i=p.replaceinjections - if i then - local leftkern=i.leftkern - if leftkern and leftkern~=0 then - insert_node_after(replace,replacetail,newkern(leftkern)) - done=true - end - end - else - local i=p.emptyinjections - if i then - local leftkern=i.leftkern - if leftkern and leftkern~=0 then - setfield(prev,"replace",newkern(leftkern)) - end + end + if replace then + local i=p.replaceinjections + if i then + local leftkern=i.leftkern + if leftkern and leftkern~=0 then + setlink(replacetail,newkern(leftkern)) + done=true end end - if done then - setdisc(prevdisc,pre,post,replace) + else + local i=p.emptyinjections + if i then + local leftkern=i.leftkern + if leftkern and leftkern~=0 then + setfield(prev,"replace",newkern(leftkern)) + end end end + if done then + setdisc(prevdisc,pre,post,replace) + end end end prevdisc=nil prevglyph=current + elseif char==false then + prevdisc=nil + prevglyph=current elseif id==disc_code then pre,post,replace,pretail,posttail,replacetail=getdisc(current,true) local done=false @@ -17311,7 +17442,7 @@ local function inject_pairs_only(head,where) if i then local yoffset=i.yoffset if yoffset and yoffset~=0 then - setfield(n,"yoffset",yoffset) + setoffsets(n,false,yoffset) end local leftkern=i.leftkern if leftkern and leftkern~=0 then @@ -17335,7 +17466,7 @@ local function inject_pairs_only(head,where) if i then local yoffset=i.yoffset if yoffset and yoffset~=0 then - setfield(n,"yoffset",yoffset) + setoffsets(n,false,yoffset) end local leftkern=i.leftkern if leftkern and leftkern~=0 then @@ -17359,7 +17490,7 @@ local function inject_pairs_only(head,where) if i then local yoffset=i.yoffset if yoffset and yoffset~=0 then - setfield(n,"yoffset",yoffset) + setoffsets(n,false,yoffset) end local leftkern=i.leftkern if leftkern and leftkern~=0 then @@ -17423,11 +17554,8 @@ local function inject_pairs_only(head,where) return tonode(head),true end local function showoffset(n,flag) - local o=getfield(n,"xoffset") - if o==0 then - o=getfield(n,"yoffset") - end - if o~=0 then + local x,y=getoffsets(n) + if x~=0 or y~=0 then setcolor(n,flag and "darkred" or "darkgreen") else resetcolor(n) @@ -17461,7 +17589,8 @@ local function inject_everything(head,where) local marks={} local nofmarks=0 local function processmark(p,n,pn) - local px=getfield(p,"xoffset") + local px,py=getoffsets(p) + local nx,ny=getoffsets(n) local ox=0 local rightkern=nil local pp=rawget(properties,p) @@ -17489,7 +17618,7 @@ local function inject_everything(head,where) else ox=px-pn.markx if pn.checkmark then - local wn=getfield(n,"width") + local wn=getwidth(n) if wn~=0 then wn=wn/2 if trace_injections then @@ -17500,156 +17629,157 @@ local function inject_everything(head,where) end end end - local oy=getfield(n,"yoffset")+getfield(p,"yoffset")+pn.marky - setfield(n,"xoffset",ox) - setfield(n,"yoffset",oy) + local oy=ny+py+pn.marky + setoffsets(n,ox,oy) if trace_marks then showoffset(n,true) end end while current do - local id=getid(current) local next=getnext(current) - if id==glyph_code then - if getsubtype(current)<256 then - local p=rawget(properties,current) - if p then - local i=p.injections - if i then - local pm=i.markbasenode - if pm then - nofmarks=nofmarks+1 - marks[nofmarks]=current - else - local yoffset=i.yoffset - if yoffset and yoffset~=0 then - setfield(current,"yoffset",yoffset) - end - if hascursives then - local cursivex=i.cursivex - if cursivex then - if cursiveanchor then - if cursivex~=0 then - i.leftkern=(i.leftkern or 0)+cursivex - end - if maxc==0 then - minc=1 - maxc=1 - glyphs[1]=cursiveanchor - else - maxc=maxc+1 - glyphs[maxc]=cursiveanchor - end - properties[cursiveanchor].cursivedy=i.cursivey - last=current + local char,id=ischar(current) + if char then + local p=rawget(properties,current) + if p then + local i=p.injections + if i then + local pm=i.markbasenode + if pm then + nofmarks=nofmarks+1 + marks[nofmarks]=current + else + local yoffset=i.yoffset + if yoffset and yoffset~=0 then + setoffsets(current,false,yoffset) + end + if hascursives then + local cursivex=i.cursivex + if cursivex then + if cursiveanchor then + if cursivex~=0 then + i.leftkern=(i.leftkern or 0)+cursivex + end + if maxc==0 then + minc=1 + maxc=1 + glyphs[1]=cursiveanchor else - maxc=0 + maxc=maxc+1 + glyphs[maxc]=cursiveanchor + end + properties[cursiveanchor].cursivedy=i.cursivey + last=current + else + maxc=0 + end + elseif maxc>0 then + local nx,ny=getoffsets(current) + for i=maxc,minc,-1 do + local ti=glyphs[i] + ny=ny+properties[ti].cursivedy + setoffsets(ti,false,ny) + if trace_cursive then + showoffset(ti) end - elseif maxc>0 then - local ny=getfield(current,"yoffset") + end + maxc=0 + cursiveanchor=nil + end + if i.cursiveanchor then + cursiveanchor=current + else + if maxc>0 then + local nx,ny=getoffsets(current) for i=maxc,minc,-1 do local ti=glyphs[i] ny=ny+properties[ti].cursivedy - setfield(ti,"yoffset",ny) + setoffsets(ti,false,ny) if trace_cursive then showoffset(ti) end end maxc=0 - cursiveanchor=nil end - if i.cursiveanchor then - cursiveanchor=current - else - if maxc>0 then - local ny=getfield(current,"yoffset") - for i=maxc,minc,-1 do - local ti=glyphs[i] - ny=ny+properties[ti].cursivedy - setfield(ti,"yoffset",ny) - if trace_cursive then - showoffset(ti) - end - end - maxc=0 - end - cursiveanchor=nil - end - end - local leftkern=i.leftkern - if leftkern and leftkern~=0 then - insert_node_before(head,current,newkern(leftkern)) - end - local rightkern=i.rightkern - if rightkern and rightkern~=0 then - insert_node_after(head,current,newkern(rightkern)) + cursiveanchor=nil end end - else - local i=p.emptyinjections - if i then - local rightkern=i.rightkern - if rightkern and rightkern~=0 then - if next and getid(next)==disc_code then - if replace then - else - setfield(next,"replace",newkern(rightkern)) - end + local leftkern=i.leftkern + if leftkern and leftkern~=0 then + insert_node_before(head,current,newkern(leftkern)) + end + local rightkern=i.rightkern + if rightkern and rightkern~=0 then + insert_node_after(head,current,newkern(rightkern)) + end + end + else + local i=p.emptyinjections + if i then + local rightkern=i.rightkern + if rightkern and rightkern~=0 then + if next and getid(next)==disc_code then + if replace then + else + setfield(next,"replace",newkern(rightkern)) end end end end - if prevdisc then - if p then - local done=false - if post then - local i=p.postinjections - if i then - local leftkern=i.leftkern - if leftkern and leftkern~=0 then - insert_node_after(post,posttail,newkern(leftkern)) - done=true - end + end + if prevdisc then + if p then + local done=false + if post then + local i=p.postinjections + if i then + local leftkern=i.leftkern + if leftkern and leftkern~=0 then + setlink(posttail,newkern(leftkern)) + done=true end end - if replace then - local i=p.replaceinjections - if i then - local leftkern=i.leftkern - if leftkern and leftkern~=0 then - insert_node_after(replace,replacetail,newkern(leftkern)) - done=true - end - end - else - local i=p.emptyinjections - if i then - local leftkern=i.leftkern - if leftkern and leftkern~=0 then - setfield(prev,"replace",newkern(leftkern)) - end + end + if replace then + local i=p.replaceinjections + if i then + local leftkern=i.leftkern + if leftkern and leftkern~=0 then + setlink(replacetail,newkern(leftkern)) + done=true end end - if done then - setdisc(prevdisc,pre,post,replace) + else + local i=p.emptyinjections + if i then + local leftkern=i.leftkern + if leftkern and leftkern~=0 then + setfield(prev,"replace",newkern(leftkern)) + end end end - end - else - if hascursives and maxc>0 then - local ny=getfield(current,"yoffset") - for i=maxc,minc,-1 do - local ti=glyphs[i] - ny=ny+properties[ti].cursivedy - setfield(ti,"yoffset",getfield(ti,"yoffset")+ny) + if done then + setdisc(prevdisc,pre,post,replace) end - maxc=0 - cursiveanchor=nil end end + else + if hascursives and maxc>0 then + local nx,ny=getoffsets(current) + for i=maxc,minc,-1 do + local ti=glyphs[i] + ny=ny+properties[ti].cursivedy + local xi,yi=getoffsets(ti) + setoffsets(ti,xi,yi+ny) + end + maxc=0 + cursiveanchor=nil + end end prevdisc=nil prevglyph=current + elseif char==false then + prevdisc=nil + prevglyph=current elseif id==disc_code then pre,post,replace,pretail,posttail,replacetail=getdisc(current,true) local done=false @@ -17661,7 +17791,7 @@ local function inject_everything(head,where) if i then local yoffset=i.yoffset if yoffset and yoffset~=0 then - setfield(n,"yoffset",yoffset) + setoffsets(n,false,yoffset) end local leftkern=i.leftkern if leftkern and leftkern~=0 then @@ -17691,7 +17821,7 @@ local function inject_everything(head,where) if i then local yoffset=i.yoffset if yoffset and yoffset~=0 then - setfield(n,"yoffset",yoffset) + setoffsets(n,false,yoffset) end local leftkern=i.leftkern if leftkern and leftkern~=0 then @@ -17721,7 +17851,7 @@ local function inject_everything(head,where) if i then local yoffset=i.yoffset if yoffset and yoffset~=0 then - setfield(n,"yoffset",yoffset) + setoffsets(n,false,yoffset) end local leftkern=i.leftkern if leftkern and leftkern~=0 then @@ -17784,11 +17914,11 @@ local function inject_everything(head,where) current=next end if hascursives and maxc>0 then - local ny=getfield(last,"yoffset") + local nx,ny=getoffsets(last) for i=maxc,minc,-1 do local ti=glyphs[i] ny=ny+properties[ti].cursivedy - setfield(ti,"yoffset",ny) + setoffsets(ti,false,ny) if trace_cursive then showoffset(ti) end @@ -17845,9 +17975,9 @@ else end end injections.getthreshold=getthreshold -function injections.isspace(n,threshold) - if getid(n)==glue_code then - local w=getfield(n,"width") +function injections.isspace(n,threshold,id) + if (id or getid(n))==glue_code then + local w=getwidth(n) if threshold and w>threshold then return 32 end @@ -17901,32 +18031,32 @@ local function injectspaces(head) end end if leftkern then - local old=getfield(n,"width") + local old=getwidth(n) if old>threshold then if rightkern then local new=old+(leftkern+rightkern)*factor if trace_spaces then report_spaces("%C [%p -> %p] %C",prevchar,old,new,nextchar) end - setfield(n,"width",new) + setwidth(n,new) leftkern=false else local new=old+leftkern*factor if trace_spaces then report_spaces("%C [%p -> %p]",prevchar,old,new) end - setfield(n,"width",new) + setwidth(n,new) end end leftkern=false elseif rightkern then - local old=getfield(n,"width") + local old=getwidth(n) if old>threshold then local new=old+rightkern*factor if trace_spaces then report_spaces("[%p -> %p] %C",nextchar,old,new) end - setfield(n,"width",new) + setwidth(n,new) end rightkern=false end @@ -17982,7 +18112,6 @@ analyzers.methods=methods local a_state=attributes.private('state') local nuts=nodes.nuts local tonut=nuts.tonut -local getfield=nuts.getfield local getnext=nuts.getnext local getprev=nuts.getprev local getprev=nuts.getprev @@ -18355,11 +18484,14 @@ local type,next,tonumber=type,next,tonumber local random=math.random local formatters=string.formatters local insert=table.insert -local logs,trackers,nodes,attributes=logs,trackers,nodes,attributes local registertracker=trackers.register -local registerdirective=directives.register +local logs=logs +local trackers=trackers +local nodes=nodes +local attributes=attributes local fonts=fonts local otf=fonts.handlers.otf +local tracers=nodes.tracers local trace_lookups=false registertracker("otf.lookups",function(v) trace_lookups=v end) local trace_singles=false registertracker("otf.singles",function(v) trace_singles=v end) local trace_multiples=false registertracker("otf.multiples",function(v) trace_multiples=v end) @@ -18381,7 +18513,6 @@ local trace_discruns=false registertracker("otf.discruns",function(v) trace_disc local trace_compruns=false registertracker("otf.compruns",function(v) trace_compruns=v end) local trace_testruns=false registertracker("otf.testruns",function(v) trace_testruns=v end) local optimizekerns=true -local alwaysdisc=true registerdirective("otf.alwaysdisc",function(v) alwaysdisc=v end) local report_direct=logs.reporter("fonts","otf direct") local report_subchain=logs.reporter("fonts","otf subchain") local report_chain=logs.reporter("fonts","otf chain") @@ -18392,7 +18523,7 @@ registertracker("otf.replacements","otf.singles,otf.multiples,otf.alternatives,o registertracker("otf.positions","otf.marks,otf.kerns,otf.cursive") registertracker("otf.actions","otf.replacements,otf.positions") registertracker("otf.injections","nodes.injections") -registertracker("*otf.sample","otf.steps,otf.actions,otf.analyzing") +registertracker("otf.sample","otf.steps,otf.actions,otf.analyzing") local nuts=nodes.nuts local tonode=nuts.tonode local tonut=nuts.tonut @@ -18417,6 +18548,10 @@ local setchar=nuts.setchar local getdisc=nuts.getdisc local setdisc=nuts.setdisc local setlink=nuts.setlink +local getcomponents=nuts.getcomponents +local setcomponents=nuts.setcomponents +local getdir=nuts.getdir +local getwidth=nuts.getwidth local ischar=nuts.is_char local insert_node_after=nuts.insert_after local copy_node=nuts.copy @@ -18427,12 +18562,12 @@ local flush_node=nuts.flush_node local end_of_math=nuts.end_of_math local traverse_nodes=nuts.traverse local traverse_id=nuts.traverse_id -local remove_node=nuts.remove +local set_components=nuts.set_components +local take_components=nuts.take_components +local count_components=nuts.count_components +local copy_no_components=nuts.copy_no_components +local copy_only_glyphs=nuts.copy_only_glyphs local setmetatableindex=table.setmetatableindex -local zwnj=0x200C -local zwj=0x200D -local wildcard="*" -local default="dflt" local nodecodes=nodes.nodecodes local glyphcodes=nodes.glyphcodes local disccodes=nodes.disccodes @@ -18446,6 +18581,7 @@ local discretionary_code=disccodes.discretionary local ligature_code=glyphcodes.ligature local privateattribute=attributes.private local a_state=privateattribute('state') +local a_noligature=privateattribute("noligature") local injections=nodes.injections local setmark=injections.setmark local setcursive=injections.setcursive @@ -18455,10 +18591,8 @@ local resetinjection=injections.reset local copyinjection=injections.copy local setligaindex=injections.setligaindex local getligaindex=injections.getligaindex -local cursonce=true -local fonthashes=fonts.hashes -local fontdata=fonthashes.identifiers -local fontfeatures=fonthashes.features +local fontdata=fonts.hashes.identifiers +local fontfeatures=fonts.hashes.features local otffeatures=fonts.constructors.features.otf local registerotffeature=otffeatures.register local onetimemessage=fonts.loggers.onetimemessage or function() end @@ -18468,6 +18602,7 @@ local tfmdata=false local characters=false local descriptions=false local marks=false +local classes=false local currentfont=false local factor=0 local threshold=0 @@ -18482,9 +18617,9 @@ local notmatchreplace={} local handlers={} local isspace=injections.isspace local getthreshold=injections.getthreshold -local checkstep=(nodes and nodes.tracers and nodes.tracers.steppers.check) or function() end -local registerstep=(nodes and nodes.tracers and nodes.tracers.steppers.register) or function() end -local registermessage=(nodes and nodes.tracers and nodes.tracers.steppers.message) or function() end +local checkstep=(tracers and tracers.steppers.check) or function() end +local registerstep=(tracers and tracers.steppers.register) or function() end +local registermessage=(tracers and tracers.steppers.message) or function() end local function checkdisccontent(d) local pre,post,replace=getdisc(d) if pre then for n in traverse_id(glue_code,pre) do print("pre",nodes.idstostring(pre)) break end end @@ -18548,20 +18683,6 @@ local function mref(rlmode) return "l2r" end end -local function copy_glyph(g) - local components=getfield(g,"components") - if components then - setfield(g,"components") - local n=copy_node(g) - copyinjection(n,g) - setfield(g,"components",components) - return n - else - local n=copy_node(g) - copyinjection(n,g) - return n - end -end local function flattendisk(head,disc) local pre,post,replace,pretail,posttail,replacetail=getdisc(disc,true) local prev,next=getboth(disc) @@ -18605,15 +18726,34 @@ local function appenddisc(disc,list) if post then setlink(posttail,posthead) else - post=phead + post=posthead end if replace then setlink(replacetail,replacehead) else - replace=rhead + replace=replacehead end setdisc(disc,pre,post,replace) end +local take_components=getcomponents +local set_components=setcomponents +local function count_components(start,marks) + if getid(start)~=glyph_code then + return 0 + elseif getsubtype(start)==ligature_code then + local i=0 + local components=getcomponents(start) + while components do + i=i+count_components(components,marks) + components=getnext(components) + end + return i + elseif not marks[getchar(start)] then + return 1 + else + return 0 + end +end local function markstoligature(head,start,stop,char) if start==stop and getchar(start)==char then return head,start @@ -18622,37 +18762,18 @@ local function markstoligature(head,start,stop,char) local next=getnext(stop) setprev(start) setnext(stop) - local base=copy_glyph(start) + local base=copy_no_components(start,copyinjection) if head==start then head=base end resetinjection(base) setchar(base,char) setsubtype(base,ligature_code) - setfield(base,"components",start) - setlink(prev,base) - setlink(base,next) + set_components(base,start) + setlink(prev,base,next) return head,base end end -local function getcomponentindex(start) - if getid(start)~=glyph_code then - return 0 - elseif getsubtype(start)==ligature_code then - local i=0 - local components=getfield(start,"components") - while components do - i=i+getcomponentindex(components) - components=getnext(components) - end - return i - elseif not marks[getchar(start)] then - return 1 - else - return 0 - end -end -local a_noligature=attributes.private("noligature") local function toligature(head,start,stop,char,dataset,sequence,markflag,discfound) if getattr(start,a_noligature)==1 then return head,start @@ -18662,29 +18783,20 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou setchar(start,char) return head,start end - local components=getfield(start,"components") - if components then - end local prev=getprev(start) local next=getnext(stop) local comp=start setprev(start) setnext(stop) - local base=copy_glyph(start) + local base=copy_no_components(start,copyinjection) if start==head then head=base end resetinjection(base) setchar(base,char) setsubtype(base,ligature_code) - setfield(base,"components",comp) - if prev then - setnext(prev,base) - end - if next then - setprev(next,base) - end - setboth(base,prev,next) + set_components(base,comp) + setlink(prev,base,next) if not discfound then local deletemarks=markflag~="mark" local components=start @@ -18696,7 +18808,7 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou local char=getchar(start) if not marks[char] then baseindex=baseindex+componentindex - componentindex=getcomponentindex(start) + componentindex=count_components(start,marks) elseif not deletemarks then setligaindex(start,baseindex+getligaindex(start,componentindex)) if trace_marks then @@ -18731,27 +18843,14 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou local discprev,discnext=getboth(discfound) if discprev and discnext then local pre,post,replace,pretail,posttail,replacetail=getdisc(discfound,true) - if not replace then + if not replace then local prev=getprev(base) - local current=comp - local previous=nil - local copied=nil - while current do - if getid(current)==glyph_code then - local n=copy_node(current) - if copied then - setlink(previous,n) - else - copied=n - end - previous=n - end - current=getnext(current) - end - setprev(discnext) - setnext(discprev) + local comp=take_components(base) + local copied=copy_only_glyphs(comp) if pre then setlink(discprev,pre) + else + setnext(discprev) end pre=comp if post then @@ -18759,13 +18858,14 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou setprev(post) else post=discnext + setprev(discnext) end - setlink(prev,discfound) - setlink(discfound,next) + setlink(prev,discfound,next) setboth(base) - setfield(base,"components",copied) - setdisc(discfound,pre,post,base) - base=prev + set_components(base,copied) + replace=base + setdisc(discfound,pre,post,replace) + base=prev end end end @@ -18999,7 +19099,6 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,step,i,inje return head,start,false else local prev=start - local done=false while snext do local nextchar=ischar(snext,currentfont) if nextchar then @@ -19017,8 +19116,7 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,step,i,inje if trace_kerns then logprocess("%s: shifting single %s by %p",pref(dataset,sequence),gref(nextchar),k) end - done=true - break + return head,start,true end end if a and #a>0 then @@ -19035,15 +19133,13 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,step,i,inje logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections") end end - done=true - break + return head,start,true elseif krn~=0 then local k=setkern(snext,factor,rlmode,krn,injection) if trace_kerns then logprocess("%s: inserting kern %p between %s and %s as %s",pref(dataset,sequence),k,gref(getchar(prev)),gref(nextchar),injection or "injections") end - done=true - break + return head,start,true else break end @@ -19051,7 +19147,7 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,step,i,inje break end end - return head,start,done + return head,start,false end end function handlers.gpos_mark2base(head,start,dataset,sequence,markanchors,rlmode) @@ -19204,7 +19300,6 @@ function handlers.gpos_mark2mark(head,start,dataset,sequence,markanchors,rlmode) return head,start,false end function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,step,i) - local done=false local startchar=getchar(start) if marks[startchar] then if trace_cursive then @@ -19212,7 +19307,7 @@ function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,st end else local nxt=getnext(start) - while not done and nxt do + while nxt do local nextchar=ischar(nxt,currentfont) if not nextchar then break @@ -19229,7 +19324,7 @@ function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,st if trace_cursive then logprocess("%s: moving %s to %s cursive (%p,%p) using anchor %s and bound %s in %s mode",pref(dataset,sequence),gref(startchar),gref(nextchar),dx,dy,anchor,bound,mref(rlmode)) end - done=true + return head,start,true end end end @@ -19237,7 +19332,7 @@ function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,st end end end - return head,start,done + return head,start,false end local chainprocs={} local function logprocess(...) @@ -19279,10 +19374,11 @@ function chainprocs.gsub_single(head,start,stop,dataset,sequence,currentlookup,c reportmoresteps(dataset,sequence) end local current=start + local mapping=steps[1].coverage while current do local currentchar=ischar(current) if currentchar then - local replacement=steps[1].coverage[currentchar] + local replacement=mapping[currentchar] if not replacement or replacement=="" then if trace_bugs then logwarning("%s: no single for %s",cref(dataset,sequence,chainindex),gref(currentchar)) @@ -19335,10 +19431,11 @@ function chainprocs.gsub_alternate(head,start,stop,dataset,sequence,currentlooku local what=dataset[1] local value=what==true and tfmdata.shared.features[kind] or what local current=start + local mapping=steps[1].coverage while current do local currentchar=ischar(current) if currentchar then - local alternatives=steps[1].coverage[currentchar] + local alternatives=mapping[currentchar] if alternatives then local choice,comment=get_alternative_glyph(current,alternatives,value) if choice then @@ -19474,7 +19571,6 @@ function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlm local kerns=step.coverage[startchar] if kerns then local prev=start - local done=false while snext do local nextchar=ischar(snext,currentfont) if not nextchar then @@ -19494,8 +19590,7 @@ function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlm if trace_kerns then logprocess("%s: shifting single %s by %p",cref(dataset,sequence),gref(startchar),k) end - done=true - break + return head,start,true end end if a and #a>0 then @@ -19512,20 +19607,17 @@ function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlm logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) end end - done=true - break + return head,start,true elseif krn~=0 then local k=setkern(snext,factor,rlmode,krn) if trace_kerns then logprocess("%s: inserting kern %s between %s and %s",cref(dataset,sequence),k,gref(getchar(prev)),gref(nextchar)) end - done=true - break + return head,start,true else break end end - return head,start,done end end return head,start,false @@ -19720,14 +19812,13 @@ function chainprocs.gpos_cursive(head,start,stop,dataset,sequence,currentlookup, local startchar=getchar(start) local exitanchors=steps[1].coverage[startchar] if exitanchors then - local done=false if marks[startchar] then if trace_cursive then logprocess("%s: ignoring cursive for mark %s",pref(dataset,sequence),gref(startchar)) end else local nxt=getnext(start) - while not done and nxt do + while nxt do local nextchar=ischar(nxt,currentfont) if not nextchar then break @@ -19744,8 +19835,7 @@ function chainprocs.gpos_cursive(head,start,stop,dataset,sequence,currentlookup, if trace_cursive then logprocess("%s: moving %s to %s cursive (%p,%p) using anchor %s and bound %s in %s mode",pref(dataset,sequence),gref(startchar),gref(nextchar),dx,dy,anchor,bound,mref(rlmode)) end - done=true - break + return head,start,true end end elseif trace_bugs then @@ -19755,13 +19845,10 @@ function chainprocs.gpos_cursive(head,start,stop,dataset,sequence,currentlookup, end end end - return head,start,done - else - if trace_cursive and trace_details then - logprocess("%s, cursive %s is already done",pref(dataset,sequence),gref(getchar(start)),alreadydone) - end - return head,start,false + elseif trace_cursive and trace_details then + logprocess("%s, cursive %s is already done",pref(dataset,sequence),gref(getchar(start)),alreadydone) end + return head,start,false end local function show_skip(dataset,sequence,char,ck,class) logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a",cref(dataset,sequence),gref(char),class,ck[1],ck[8] or ck[2]) @@ -19771,7 +19858,7 @@ local function checked(head) local current=head while current do if getid(current)==glue_code then - local kern=new_kern(getfield(current,"width")) + local kern=new_kern(getwidth(current)) if head==current then local next=getnext(current) if next then @@ -19782,8 +19869,7 @@ local function checked(head) current=next else local prev,next=getboth(current) - setlink(prev,kern) - setlink(kern,next) + setlink(prev,kern,next) flush_node(current) current=next end @@ -19799,7 +19885,85 @@ local function setdiscchecked(d,pre,post,replace) if replace then replace=checked(replace) end setdisc(d,pre,post,replace) end -local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,ck,chainproc) +local noflags={ false,false,false,false } +local function chainrun(head,start,last,dataset,sequence,rlmode,ck,skipped) + local size=ck[5]-ck[4]+1 + local flags=sequence.flags or noflags + local done=false + local skipmark=flags[1] + local chainlookups=ck[6] + if chainlookups then + local nofchainlookups=#chainlookups + if size==1 then + local chainlookup=chainlookups[1] + local chainkind=chainlookup.type + local chainproc=chainprocs[chainkind] + if chainproc then + local ok + head,start,ok=chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,1) + if ok then + done=true + end + else + logprocess("%s: %s is not yet supported (1)",cref(dataset,sequence),chainkind) + end + else + local i=1 + while start do + if skipped then + while start do + local char=getchar(start) + local class=classes[char] + if class then + if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then + start=getnext(start) + else + break + end + else + break + end + end + end + local chainlookup=chainlookups[i] + if chainlookup then + local chainkind=chainlookup.type + local chainproc=chainprocs[chainkind] + if chainproc then + local ok,n + head,start,ok,n=chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,i) + if ok then + done=true + if n and n>1 and i+n>nofchainlookups then + break + end + end + else + logprocess("%s: %s is not yet supported (2)",cref(dataset,sequence),chainkind) + end + end + i=i+1 + if i>size or not start then + break + elseif start then + start=getnext(start) + end + end + end + else + local replacements=ck[7] + if replacements then + head,start,done=reversesub(head,start,last,dataset,sequence,replacements,rlmode) + else + done=true + if trace_contexts then + logprocess("%s: skipping match",cref(dataset,sequence)) + end + end + end + return head,start,done +end +local function chaindisk(head,start,dataset,sequence,rlmode,ck,skipped) if not start then return head,start,false end @@ -19812,7 +19976,6 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c local sweepnode=sweepnode local sweeptype=sweeptype local sweepoverflow=false - local checkdisc=getprev(head) local keepdisc=not sweepnode local lookaheaddisc=nil local backtrackdisc=nil @@ -19835,18 +19998,22 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c elseif id==disc_code then if keepdisc then keepdisc=false - if notmatchpre[current]~=notmatchreplace[current] then - lookaheaddisc=current - end + lookaheaddisc=current local replace=getfield(current,"replace") - while replace and i<=l do - if getid(replace)==glyph_code then - i=i+1 + if not replace then + sweepoverflow=true + sweepnode=current + current=getnext(current) + else + while replace and i<=l do + if getid(replace)==glyph_code then + i=i+1 + end + replace=getnext(replace) end - replace=getnext(replace) + current=getnext(replace) end last=current - current=getnext(c) else head,current=flattendisk(head,current) end @@ -19904,7 +20071,7 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c if notmatchpre[current]~=notmatchreplace[current] then lookaheaddisc=current end - local replace=getfield(c,"replace") + local replace=getfield(current,"replace") while replace and i<s do if getid(replace)==glyph_code then i=i+1 @@ -19965,7 +20132,7 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c end end end - local ok=false + local done=false if lookaheaddisc then local cf=start local cl=getprev(lookaheaddisc) @@ -19982,10 +20149,7 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c break end end - setprev(lookaheaddisc,cprev) - if cprev then - setnext(cprev,lookaheaddisc) - end + setlink(cprev,lookaheaddisc) setprev(cf) setnext(cl) if startishead then @@ -19994,25 +20158,35 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c local pre,post,replace=getdisc(lookaheaddisc) local new=copy_node_list(cf) local cnew=new + if pre then + setlink(find_node_tail(cf),pre) + end + if replace then + local tail=find_node_tail(new) + setlink(tail,replace) + end for i=1,insertedmarks do cnew=getnext(cnew) end + cl=start local clast=cnew for i=f,l do + cl=getnext(cl) clast=getnext(clast) end if not notmatchpre[lookaheaddisc] then - cf,start,ok=chainproc(cf,start,last,dataset,sequence,chainlookup,rlmode,k) + local ok=false + cf,start,ok=chainrun(cf,start,cl,dataset,sequence,rlmode,ck,skipped) + if ok then + done=true + end end if not notmatchreplace[lookaheaddisc] then - new,cnew,ok=chainproc(new,cnew,clast,dataset,sequence,chainlookup,rlmode,k) - end - if pre then - setlink(cl,pre) - end - if replace then - local tail=find_node_tail(new) - setlink(tail,replace) + local ok=false + new,cnew,ok=chainrun(new,cnew,clast,dataset,sequence,rlmode,ck,skipped) + if ok then + done=true + end end if hasglue then setdiscchecked(lookaheaddisc,cf,post,new) @@ -20021,7 +20195,7 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c end start=getprev(lookaheaddisc) sweephead[cf]=getnext(clast) - sweephead[new]=getnext(last) + sweephead[new]=getnext(cl) elseif backtrackdisc then local cf=getnext(backtrackdisc) local cl=start @@ -20054,10 +20228,18 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c clast=getnext(clast) end if not notmatchpost[backtrackdisc] then - cf,start,ok=chainproc(cf,start,last,dataset,sequence,chainlookup,rlmode,k) + local ok=false + cf,start,ok=chainrun(cf,start,last,dataset,sequence,rlmode,ck,skipped) + if ok then + done=true + end end if not notmatchreplace[backtrackdisc] then - new,cnew,ok=chainproc(new,cnew,clast,dataset,sequence,chainlookup,rlmode,k) + local ok=false + new,cnew,ok=chainrun(new,cnew,clast,dataset,sequence,rlmode,ck,skipped) + if ok then + done=true + end end if post then setlink(posttail,cf) @@ -20078,17 +20260,30 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c sweephead[post]=getnext(clast) sweephead[replace]=getnext(last) else - head,start,ok=chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,k) + local ok=false + head,start,ok=chainrun(head,start,last,dataset,sequence,rlmode,ck,skipped) + if ok then + done=true + end end - return head,start,ok + return head,start,done +end +local function chaintrac(head,start,dataset,sequence,rlmode,ck,skipped) + local rule=ck[1] + local lookuptype=ck[8] or ck[2] + local nofseq=#ck[3] + local first=ck[4] + local last=ck[5] + local char=getchar(start) + logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %a", + cref(dataset,sequence),rule,gref(char),first-1,last-first+1,nofseq-last,lookuptype) end -local noflags={ false,false,false,false } local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) local sweepnode=sweepnode local sweeptype=sweeptype local currentfont=currentfont local diskseen=false - local checkdisc=getprev(head) + local checkdisc=sweeptype and getprev(head) local flags=sequence.flags or noflags local done=false local skipmark=flags[1] @@ -20096,6 +20291,8 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) local skipbase=flags[3] local markclass=sequence.markclass local skipped=false + local startprev, + startnext=getboth(start) for k=1,#contexts do local match=true local current=start @@ -20107,7 +20304,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) if s==1 then local char=ischar(current,currentfont) if char then - match=seq[1][char] + if not seq[1][char] then + match=false + end end else local f=ck[4] @@ -20116,7 +20315,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) if size>1 then local discfound=nil local n=f+1 - last=getnext(last) + last=startnext while n<=l do if not last and (sweeptype=="post" or sweeptype=="replace") then last=getnext(sweepnode) @@ -20125,9 +20324,8 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) if last then local char,id=ischar(last,currentfont) if char then - local ccd=descriptions[char] - if ccd then - local class=ccd.class or "base" + local class=classes[char] + if class then if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then skipped=true if trace_skips then @@ -20142,7 +20340,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) else if discfound then notmatchreplace[discfound]=true - match=not notmatchpre[discfound] + if notmatchpre[discfound] then + match=false + end else match=false end @@ -20151,7 +20351,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) else if discfound then notmatchreplace[discfound]=true - match=not notmatchpre[discfound] + if notmatchpre[discfound] then + match=false + end else match=false end @@ -20160,7 +20362,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) elseif char==false then if discfound then notmatchreplace[discfound]=true - match=not notmatchpre[discfound] + if notmatchpre[discfound] then + match=false + end else match=false end @@ -20202,11 +20406,15 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) end else notmatchreplace[last]=true - match=not notmatchpre[last] + if notmatchpre[last] then + match=false + end break end end - match=not notmatchpre[last] + if notmatchpre[last] then + match=false + end end last=getnext(last) else @@ -20220,8 +20428,8 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) end end if match and f>1 then - local prev=getprev(start) - if prev then + if startprev then + local prev=startprev if prev==checkdisc and (sweeptype=="pre" or sweeptype=="replace") then prev=getprev(sweepnode) end @@ -20232,24 +20440,25 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) if prev then local char,id=ischar(prev,currentfont) if char then - local ccd=descriptions[char] - if ccd then - local class=ccd.class + local class=classes[char] + if class then if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then skipped=true if trace_skips then show_skip(dataset,sequence,char,ck,class) end - prev=getprev(prev) + prev=getprev(prev) elseif seq[n][char] then - if n>1 then - prev=getprev(prev) + if n>1 then + prev=getprev(prev) end n=n-1 else if discfound then notmatchreplace[discfound]=true - match=not notmatchpost[discfound] + if notmatchpost[discfound] then + match=false + end else match=false end @@ -20258,7 +20467,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) else if discfound then notmatchreplace[discfound]=true - match=not notmatchpost[discfound] + if notmatchpost[discfound] then + match=false + end else match=false end @@ -20267,7 +20478,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) elseif char==false then if discfound then notmatchreplace[discfound]=true - match=not notmatchpost[discfound] + if notmatchpost[discfound] then + match=false + end else match=false end @@ -20318,7 +20531,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) end else notmatchreplace[prev]=true - match=not notmatchpost[prev] + if notmatchpost[prev] then + match=false + end break end end @@ -20328,7 +20543,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) end end prev=getprev(prev) - elseif seq[n][32] and isspace(prev,threshold) then + elseif seq[n][32] and id==glue_code and isspace(prev,threshold,id) then n=n-1 prev=getprev(prev) else @@ -20361,9 +20576,8 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) if current then local char,id=ischar(current,currentfont) if char then - local ccd=descriptions[char] - if ccd then - local class=ccd.class + local class=classes[char] + if class then if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then skipped=true if trace_skips then @@ -20378,7 +20592,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) else if discfound then notmatchreplace[discfound]=true - match=not notmatchpre[discfound] + if notmatchpre[discfound] then + match=false + end else match=false end @@ -20387,7 +20603,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) else if discfound then notmatchreplace[discfound]=true - match=not notmatchpre[discfound] + if notmatchpre[discfound] then + match=false + end else match=false end @@ -20396,7 +20614,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) elseif char==false then if discfound then notmatchreplace[discfound]=true - match=not notmatchpre[discfound] + if notmatchpre[discfound] then + match=false + end else match=false end @@ -20438,7 +20658,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) end else notmatchreplace[current]=true - match=notmatchpre[current] + if not notmatchpre[current] then + match=false + end break end end @@ -20448,7 +20670,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) else end current=getnext(current) - elseif seq[n][32] and isspace(current,threshold) then + elseif seq[n][32] and id==glue_code and isspace(current,threshold,id) then n=n+1 current=getnext(current) else @@ -20466,94 +20688,13 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) end end if match then - local diskchain=diskseen or sweepnode if trace_contexts then - local rule=ck[1] - local lookuptype=ck[8] or ck[2] - local first=ck[4] - local last=ck[5] - local char=getchar(start) - logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %a", - cref(dataset,sequence),rule,gref(char),first-1,last-first+1,s-last,lookuptype) - end - local chainlookups=ck[6] - if chainlookups then - local nofchainlookups=#chainlookups - if size==1 then - local chainlookup=chainlookups[1] - local chainkind=chainlookup.type - local chainproc=chainprocs[chainkind] - if chainproc then - local ok - if diskchain then - head,start,ok=chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,1,ck,chainproc) - else - head,start,ok=chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,1) - end - if ok then - done=true - end - else - logprocess("%s: %s is not yet supported (1)",cref(dataset,sequence),chainkind) - end - else - local i=1 - while start do - if skipped then - while start do - local char=getchar(start) - local ccd=descriptions[char] - if ccd then - local class=ccd.class or "base" - if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then - start=getnext(start) - else - break - end - else - break - end - end - end - local chainlookup=chainlookups[i] - if chainlookup then - local chainkind=chainlookup.type - local chainproc=chainprocs[chainkind] - if chainproc then - local ok,n - if diskchain then - head,start,ok=chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,i,ck,chainproc) - else - head,start,ok,n=chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,i) - end - if ok then - done=true - if n and n>1 and i+n>nofchainlookups then - break - end - end - else - logprocess("%s: %s is not yet supported (2)",cref(dataset,sequence),chainkind) - end - end - i=i+1 - if i>size or not start then - break - elseif start then - start=getnext(start) - end - end - end + chaintrac(head,start,dataset,sequence,rlmode,ck,skipped) + end + if diskseen or sweepnode then + head,start,done=chaindisk(head,start,dataset,sequence,rlmode,ck,skipped) else - local replacements=ck[7] - if replacements then - head,start,done=reversesub(head,start,last,dataset,sequence,replacements,rlmode) - else - done=true - if trace_contexts then - logprocess("%s: skipping match",cref(dataset,sequence)) - end - end + head,start,done=chainrun(head,start,last,dataset,sequence,rlmode,ck,skipped) end if done then break @@ -20610,75 +20751,79 @@ local sequencelists=setmetatableindex(function(t,font) t[font]=sequences return sequences end) -local autofeatures=fonts.analyzers.features -local featuretypes=otf.tables.featuretypes -local defaultscript=otf.features.checkeddefaultscript -local defaultlanguage=otf.features.checkeddefaultlanguage -local function initialize(sequence,script,language,enabled,autoscript,autolanguage) - local features=sequence.features - if features then - local order=sequence.order - if order then - local featuretype=featuretypes[sequence.type or "unknown"] - for i=1,#order do - local kind=order[i] - local valid=enabled[kind] - if valid then - local scripts=features[kind] - local languages=scripts and ( - scripts[script] or - scripts[wildcard] or - (autoscript and defaultscript(featuretype,autoscript,scripts)) - ) - local enabled=languages and ( - languages[language] or - languages[wildcard] or - (autolanguage and defaultlanguage(featuretype,autolanguage,languages)) - ) - if enabled then - return { valid,autofeatures[kind] or false,sequence,kind } +do + local autofeatures=fonts.analyzers.features + local featuretypes=otf.tables.featuretypes + local defaultscript=otf.features.checkeddefaultscript + local defaultlanguage=otf.features.checkeddefaultlanguage + local wildcard="*" + local default="dflt" + local function initialize(sequence,script,language,enabled,autoscript,autolanguage) + local features=sequence.features + if features then + local order=sequence.order + if order then + local featuretype=featuretypes[sequence.type or "unknown"] + for i=1,#order do + local kind=order[i] + local valid=enabled[kind] + if valid then + local scripts=features[kind] + local languages=scripts and ( + scripts[script] or + scripts[wildcard] or + (autoscript and defaultscript(featuretype,autoscript,scripts)) + ) + local enabled=languages and ( + languages[language] or + languages[wildcard] or + (autolanguage and defaultlanguage(featuretype,autolanguage,languages)) + ) + if enabled then + return { valid,autofeatures[kind] or false,sequence,kind } + end end end + else end - else end + return false end - return false -end -function otf.dataset(tfmdata,font) - local shared=tfmdata.shared - local properties=tfmdata.properties - local language=properties.language or "dflt" - local script=properties.script or "dflt" - local enabled=shared.features - local autoscript=enabled and enabled.autoscript - local autolanguage=enabled and enabled.autolanguage - local res=resolved[font] - if not res then - res={} - resolved[font]=res - end - local rs=res[script] - if not rs then - rs={} - res[script]=rs - end - local rl=rs[language] - if not rl then - rl={ - } - rs[language]=rl - local sequences=tfmdata.resources.sequences - if sequences then - for s=1,#sequences do - local v=enabled and initialize(sequences[s],script,language,enabled,autoscript,autolanguage) - if v then - rl[#rl+1]=v + function otf.dataset(tfmdata,font) + local shared=tfmdata.shared + local properties=tfmdata.properties + local language=properties.language or "dflt" + local script=properties.script or "dflt" + local enabled=shared.features + local autoscript=enabled and enabled.autoscript + local autolanguage=enabled and enabled.autolanguage + local res=resolved[font] + if not res then + res={} + resolved[font]=res + end + local rs=res[script] + if not rs then + rs={} + res[script]=rs + end + local rl=rs[language] + if not rl then + rl={ + } + rs[language]=rl + local sequences=tfmdata.resources.sequences + if sequences then + for s=1,#sequences do + local v=enabled and initialize(sequences[s],script,language,enabled,autoscript,autolanguage) + if v then + rl[#rl+1]=v + end end end end + return rl end - return rl end local function report_disc(what,n) report_run("%s: %s > %s",what,n,languages.serializediscretionary(n)) @@ -20759,12 +20904,11 @@ local function kernrun(disc,k_run,font,attr,...) if k_run(prevmarks,"emptyinjections",next,font,attr,...) then done=true end - setlink(prev,disc) - setlink(disc,next) + setlink(prev,disc,next) end return nextstart,done end -local function comprun(disc,c_run,...) +local function comprun(disc,c_run,...) if trace_compruns then report_disc("comp",disc) end @@ -20878,7 +21022,10 @@ local function c_run_single(head,font,attr,lookupcache,step,dataset,sequence,rlm while start do local char=ischar(start,font) if char then - local a=attr and getattr(start,0) + local a + if attr then + a=getattr(start,0) + end if not a or (a==attr) then local lookupmatch=lookupcache[char] if lookupmatch then @@ -20908,11 +21055,15 @@ local function t_run_single(start,stop,font,attr,lookupcache) while start~=stop do local char=ischar(start,font) if char then - local a=attr and getattr(start,0) + local a + if attr then + a=getattr(start,0) + end + local startnext=getnext(start) if not a or (a==attr) then local lookupmatch=lookupcache[char] if lookupmatch then - local s=getnext(start) + local s=startnext local l=nil local d=0 while s do @@ -20935,14 +21086,17 @@ local function t_run_single(start,stop,font,attr,lookupcache) end else end - start=getnext(start) + start=starttnext else break end end end local function k_run_single(sub,injection,last,font,attr,lookupcache,step,dataset,sequence,rlmode,handler) - local a=attr and getattr(sub,0) + local a + if attr then + a=getattr(sub,0) + end if not a or (a==attr) then for n in traverse_nodes(sub) do if n==last then @@ -20973,7 +21127,10 @@ local function c_run_multiple(head,font,attr,steps,nofsteps,dataset,sequence,rlm while start do local char=ischar(start,font) if char then - local a=attr and getattr(start,0) + local a + if attr then + a=getattr(start,0) + end if not a or (a==attr) then for i=1,nofsteps do local step=steps[i] @@ -21014,7 +21171,11 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps) while start~=stop do local char=ischar(start,font) if char then - local a=attr and getattr(start,0) + local a + if attr then + a=getattr(start,0) + end + local startnext=getnext(start) if not a or (a==attr) then for i=1,nofsteps do local step=steps[i] @@ -21022,7 +21183,7 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps) if lookupcache then local lookupmatch=lookupcache[char] if lookupmatch then - local s=getnext(start) + local s=startnext local l=nil local d=0 while s do @@ -21049,14 +21210,17 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps) end else end - start=getnext(start) + start=startnext else break end end end local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler) - local a=attr and getattr(sub,0) + local a + if attr then + a=getattr(sub,0) + end if not a or (a==attr) then for n in traverse_nodes(sub) do if n==last then @@ -21084,7 +21248,7 @@ local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,datase end end local function txtdirstate(start,stack,top,rlparmode) - local dir=getfield(start,"dir") + local dir=getdir(start) local new=1 if dir=="+TRT" then top=top+1 @@ -21107,7 +21271,7 @@ local function txtdirstate(start,stack,top,rlparmode) return getnext(start),top,new end local function pardirstate(start) - local dir=getfield(start,"dir") + local dir=getdir(start) local new=0 if dir=="TLT" then new=1 @@ -21131,9 +21295,11 @@ local function featuresprocessor(head,font,attr) if nesting==1 then currentfont=font tfmdata=fontdata[font] - descriptions=tfmdata.descriptions - characters=tfmdata.characters - marks=tfmdata.resources.marks + descriptions=tfmdata.descriptions + characters=tfmdata.characters + local resources=tfmdata.resources + marks=resources.marks + classes=resources.classes threshold, factor=getthreshold(font) checkmarks=tfmdata.properties.checkmarks @@ -21149,7 +21315,6 @@ local function featuresprocessor(head,font,attr) local rlmode=0 local done=false local datasets=otf.dataset(tfmdata,font,attr) - local forcedisc=alwaysdisc or not attr local dirstack={} sweephead={} for s=1,#datasets do @@ -21158,7 +21323,6 @@ local function featuresprocessor(head,font,attr) local sequence=dataset[3] local rlparmode=0 local topstack=0 - local success=false local typ=sequence.type local gpossing=typ=="gpos_single" or typ=="gpos_pair" local handler=handlers[typ] @@ -21167,7 +21331,7 @@ local function featuresprocessor(head,font,attr) if not steps then local h,d,ok=handler(head,head,dataset,sequence,nil,nil,nil,0,font,attr) if ok then - success=true + done=true if h then head=h end @@ -21177,7 +21341,10 @@ local function featuresprocessor(head,font,attr) while start do local char=ischar(start,font) if char then - local a=attr and getattr(start,0) + local a + if attr then + a=getattr(start,0) + end if not a or (a==attr) then for i=1,nofsteps do local step=steps[i] @@ -21188,7 +21355,7 @@ local function featuresprocessor(head,font,attr) local ok head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i) if ok then - success=true + done=true break end end @@ -21218,11 +21385,13 @@ local function featuresprocessor(head,font,attr) while start do local char,id=ischar(start,font) if char then - local a=attr and getattr(start,0) - if a then - a=(a==attr) and (not attribute or getprop(start,a_state)==attribute) - else - a=not attribute or getprop(start,a_state)==attribute + local a + if attr then + if getattr(start,0)==attr and (not attribute or getprop(start,a_state)==attribute) then + a=true + end + elseif not attribute or getprop(start,a_state)==attribute then + a=true end if a then local lookupmatch=lookupcache[char] @@ -21230,7 +21399,7 @@ local function featuresprocessor(head,font,attr) local ok head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,step,1) if ok then - success=true + done=true end end if start then @@ -21242,21 +21411,16 @@ local function featuresprocessor(head,font,attr) elseif char==false then start=getnext(start) elseif id==disc_code then - local a=forcedisc or getsubtype(start)==discretionary_code or getattr(start,0)==attr - if a then - local ok - if gpossing then - start,ok=kernrun(start,k_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,handler) - elseif typ=="gsub_ligature" then - start,ok=testrun(start,t_run_single,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,handler) - else - start,ok=comprun(start,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,handler) - end - if ok then - success=true - end + local ok + if gpossing then + start,ok=kernrun(start,k_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,handler) + elseif typ=="gsub_ligature" then + start,ok=testrun(start,t_run_single,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,handler) else - start=getnext(start) + start,ok=comprun(start,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,handler) + end + if ok then + done=true end elseif id==math_code then start=getnext(end_of_math(start)) @@ -21273,11 +21437,13 @@ local function featuresprocessor(head,font,attr) while start do local char,id=ischar(start,font) if char then - local a=attr and getattr(start,0) - if a then - a=(a==attr) and (not attribute or getprop(start,a_state)==attribute) - else - a=not attribute or getprop(start,a_state)==attribute + local a + if attr then + if getattr(start,0)==attr and (not attribute or getprop(start,a_state)==attribute) then + a=true + end + elseif not attribute or getprop(start,a_state)==attribute then + a=true end if a then for i=1,nofsteps do @@ -21289,7 +21455,7 @@ local function featuresprocessor(head,font,attr) local ok head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i) if ok then - success=true + done=true break elseif not start then break @@ -21308,21 +21474,16 @@ local function featuresprocessor(head,font,attr) elseif char==false then start=getnext(start) elseif id==disc_code then - local a=forcedisc or getsubtype(start)==discretionary_code or getattr(start,0)==attr - if a then - local ok - if gpossing then - start,ok=kernrun(start,k_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler) - elseif typ=="gsub_ligature" then - start,ok=testrun(start,t_run_multiple,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler) - else - start,ok=comprun(start,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler) - end - if ok then - success=true - end + local ok + if gpossing then + start,ok=kernrun(start,k_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler) + elseif typ=="gsub_ligature" then + start,ok=testrun(start,t_run_multiple,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler) else - start=getnext(start) + start,ok=comprun(start,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler) + end + if ok then + done=true end elseif id==math_code then start=getnext(end_of_math(start)) @@ -21336,9 +21497,6 @@ local function featuresprocessor(head,font,attr) end end end - if success then - done=true - end if trace_steps then registerstep(head) end @@ -22472,8 +22630,7 @@ function handlers.devanagari_reorder_reph(head,start) if getprop(current,a_state)==s_pstf then startnext=getnext(start) head=remove_node(head,start) - local prev=getprev(current) - setlink(prev,start) + setlink(getprev(current),start) setlink(start,current) start=startnext startattr=getprop(start,a_syllabe) @@ -22502,8 +22659,7 @@ function handlers.devanagari_reorder_reph(head,start) if c then startnext=getnext(start) head=remove_node(head,start) - local prev=getprev(c) - setlink(prev,start) + setlink(getprev(c),start) setlink(start,c) start=startnext startattr=getprop(start,a_syllabe) @@ -22524,8 +22680,7 @@ function handlers.devanagari_reorder_reph(head,start) if start~=current then startnext=getnext(start) head=remove_node(head,start) - local next=getnext(current) - setlink(start,next) + setlink(start,getnext(current)) setlink(current,start) start=startnext end @@ -22573,8 +22728,7 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start) if not consonant[char] and getprop(current,a_state) then startnext=getnext(start) removenode(start,start) - local prev=getprev(current) - setlink(prev,start) + setlink(getprev(current),start) setlink(start,current) start=startnext break @@ -22867,8 +23021,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) end start=current end - local prev=getprev(halfpos) - setlink(prev,current) + setlink(getprev(halfpos),current) setlink(current,halfpos) halfpos=current elseif above_mark[char] then @@ -22898,8 +23051,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) if current==stop then stop=prev end - local next=getnext(target) - setlink(current,next) + setlink(current,getnext(target)) setlink(target,current) end end @@ -22924,8 +23076,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) if stop==next then stop=current end - local prev=getprev(c) - setlink(prev,next) + setlink(getprev(c),next) local nextnext=getnext(next) setnext(current,nextnext) local nextnextnext=getnext(nextnext) @@ -23730,42 +23881,61 @@ do return entry.data end end + local runner=sandbox and sandbox.registerrunner { + name="otfsvg", + program="inkscape", + method="pipeto", + template="--shell > temp-otf-svg-shape.log", + reporter=report_svg, + } + if notrunner then + runner=function() + return io.open("inkscape --shell > temp-otf-svg-shape.log","w") + end + end function otfsvg.topdf(svgshapes) - local inkscape=io.popen("inkscape --shell > temp-otf-svg-shape.log","w") local pdfshapes={} - local nofshapes=#svgshapes - local f_svgfile=formatters["temp-otf-svg-shape-%i.svg"] - local f_pdffile=formatters["temp-otf-svg-shape-%i.pdf"] - local f_convert=formatters["%s --export-pdf=%s\n"] - local filterglyph=otfsvg.filterglyph - report_svg("processing %i svg containers",nofshapes) - statistics.starttiming() - for i=1,nofshapes do - local entry=svgshapes[i] - for index=entry.first,entry.last do - local data=filterglyph(entry,index) - if data and data~="" then - local svgfile=f_svgfile(index) - local pdffile=f_pdffile(index) - savedata(svgfile,data) - inkscape:write(f_convert(svgfile,pdffile)) - pdfshapes[index]=true - end - end - end - inkscape:write("quit\n") - inkscape:close() - report_svg("processing %i pdf results",nofshapes) - for index in next,pdfshapes do - local svgfile=f_svgfile(index) - local pdffile=f_pdffile(index) - pdfshapes[index]=loaddata(pdffile) - remove(svgfile) - remove(pdffile) - end - statistics.stoptiming() - if statistics.elapsedseconds then - report_svg("svg conversion time %s",statistics.elapsedseconds()) + local inkscape=runner() + if inkscape then + local nofshapes=#svgshapes + local f_svgfile=formatters["temp-otf-svg-shape-%i.svg"] + local f_pdffile=formatters["temp-otf-svg-shape-%i.pdf"] + local f_convert=formatters["%s --export-pdf=%s\n"] + local filterglyph=otfsvg.filterglyph + local nofdone=0 + report_svg("processing %i svg containers",nofshapes) + statistics.starttiming() + for i=1,nofshapes do + local entry=svgshapes[i] + for index=entry.first,entry.last do + local data=filterglyph(entry,index) + if data and data~="" then + local svgfile=f_svgfile(index) + local pdffile=f_pdffile(index) + savedata(svgfile,data) + inkscape:write(f_convert(svgfile,pdffile)) + pdfshapes[index]=true + nofdone=nofdone+1 + if nofdone%100==0 then + report_svg("%i shapes processed",nofdone) + end + end + end + end + inkscape:write("quit\n") + inkscape:close() + report_svg("processing %i pdf results",nofshapes) + for index in next,pdfshapes do + local svgfile=f_svgfile(index) + local pdffile=f_pdffile(index) + pdfshapes[index]=loaddata(pdffile) + remove(svgfile) + remove(pdffile) + end + statistics.stoptiming() + if statistics.elapsedseconds then + report_svg("svg conversion time %s",statistics.elapsedseconds()) + end end return pdfshapes end |