diff options
Diffstat (limited to 'tex')
80 files changed, 4552 insertions, 1670 deletions
diff --git a/tex/context/base/mkii/cont-new.mkii b/tex/context/base/mkii/cont-new.mkii index d06fbe463..6c1dca8a2 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{2021.01.11 16:28} +\newcontextversion{2021.01.17 21:39} %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 c36274955..dbe4e4249 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{2021.01.11 16:28} +\edef\contextversion{2021.01.17 21:39} %D For those who want to use this: diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv index 49c850c9b..d8dfa0fa2 100644 --- a/tex/context/base/mkiv/cont-new.mkiv +++ b/tex/context/base/mkiv/cont-new.mkiv @@ -13,7 +13,7 @@ % \normalend % uncomment this to get the real base runtime -\newcontextversion{2021.01.11 16:28} +\newcontextversion{2021.01.17 21:39} %D This file is loaded at runtime, thereby providing an excellent place for hacks, %D patches, extensions and new features. There can be local overloads in cont-loc diff --git a/tex/context/base/mkiv/context.mkiv b/tex/context/base/mkiv/context.mkiv index 93744dfda..8e697e850 100644 --- a/tex/context/base/mkiv/context.mkiv +++ b/tex/context/base/mkiv/context.mkiv @@ -45,7 +45,7 @@ %D {YYYY.MM.DD HH:MM} format. \edef\contextformat {\jobname} -\edef\contextversion{2021.01.11 16:28} +\edef\contextversion{2021.01.17 21:39} %D Kind of special: diff --git a/tex/context/base/mkiv/font-imp-math.lua b/tex/context/base/mkiv/font-imp-math.lua index ed82fcc48..d2294e93c 100644 --- a/tex/context/base/mkiv/font-imp-math.lua +++ b/tex/context/base/mkiv/font-imp-math.lua @@ -80,6 +80,34 @@ registerotffeature { } } +function fonts.helpers.mathscriptslots(tfmdata,textcode) + local rawdata = tfmdata.shared.rawdata + local rawresources = rawdata and rawdata.resources + local rawfeatures = rawresources and rawresources.features + local basesubstitutions = rawfeatures and rawfeatures.gsub + local sequences = basesubstitutions and tfmdata.resources.sequences + if sequences then + local characters = tfmdata.characters + if characters[textcode] then + for s=1,#sequences do + local sequence = sequences[s] + local sfeatures = sequence.features + if sfeatures and sfeatures.ssty then + local steps = sequence.steps + for i=1,#steps do + local coverage = steps[i].coverage + if coverage then + local okay = coverage[textcode] + if okay then + return okay + end + end + end + end + end + end + end +end local function initialize(tfmdata,key,value) if value then local rawdata = tfmdata.shared.rawdata diff --git a/tex/context/base/mkiv/font-imp-tracing.lua b/tex/context/base/mkiv/font-imp-tracing.lua index 1acf14558..255b4cdf0 100644 --- a/tex/context/base/mkiv/font-imp-tracing.lua +++ b/tex/context/base/mkiv/font-imp-tracing.lua @@ -139,107 +139,3 @@ local specification = { registerotffeature(specification) registerafmfeature(specification) - -local f_m = formatters["%F %F m"] -local f_l = formatters["%F %F l"] -local f_b = formatters["[] 0 d 0 J %.6F w"] -local f_e = formatters["s"] - -local function ladder(list,docolor,nocolor,lst,offset,sign,default) - local l = lst[1] - local x1 = bp * (offset + l.kern) * sign - local y1 = bp * l.height - local t = { f_b(r,r/2), f_m(x1,y1) } - local n = 2 - local m = #lst - if default > 0 then - default = default * bp + r - else - default = default * bp - r - end - if m == 1 then - n = n + 1 t[n] = f_l(x1,default) - else - for i=1,m do - local l = lst[i] - local x2 = bp * (offset + l.kern) * sign - local y2 = bp * l.height - if i > 1 and y2 == 0 then - y2 = default - end - n = n + 1 t[n] = f_l(x2,y1) - n = n + 1 t[n] = f_l(x2,y2) - x1, y1 = x2, y2 - end - end - n = n + 1 t[n] = f_e() - list[#list+1] = docolor - list[#list+1] = { "pdf", "origin", concat(t," ") } - list[#list+1] = nocolor -end - -local function initialize(tfmdata,key,value) - if value then - if not backcolors then - local vfspecials = backends.pdf.tables.vfspecials - startcolor = vfspecials.startcolor - stopcolor = vfspecials.stopcolor - end - local characters = tfmdata.characters - local brcolor = startcolor("darkred") - local trcolor = startcolor("darkgreen") - local blcolor = startcolor("darkblue") - local tlcolor = startcolor("darkyellow") - local black = stopcolor - for unicode, character in next, characters do - local mathkern = character.mathkern - if mathkern then - -- more efficient would be co collect more in one pdf - -- directive but this is hardly used so not worth the - -- effort - local width = character.width or 0 - local height = character.height or 0 - local depth = character.depth or 0 - local list = { } - local br = mathkern.bottom_right - local tr = mathkern.top_right - local bl = mathkern.bottom_left - local tl = mathkern.top_left - if br then - ladder(list,brcolor,black,br,width,1,height) - end - if tr then - ladder(list,trcolor,black,tr,width,1,-depth) - end - if bl then - ladder(list,blcolor,black,bl,0,-1,height) - end - if tl then - ladder(list,tlcolor,black,tl,0,-1,-depth) - end - if #list > 0 then - local commands = character.commands - if commands then - character.commands = appendcommandtable(commands,list) - else - list[#list+1] = charcommand[unicode] - character.commands = list - end - end - end - end - end -end - -local specification = { - name = "staircase", - description = "show staircase kerns", - position=1, - manipulators = { - base = initialize, - node = initialize, - } -} - -registerotffeature(specification) -registerafmfeature(specification) diff --git a/tex/context/base/mkiv/font-pre.mkiv b/tex/context/base/mkiv/font-pre.mkiv index c32690375..445dedd25 100644 --- a/tex/context/base/mkiv/font-pre.mkiv +++ b/tex/context/base/mkiv/font-pre.mkiv @@ -405,6 +405,7 @@ mathalternates=yes, mathitalics=yes, % we pass them mathdimensions=all, + % mathkerns=yes, % mathgaps=yes, language=dflt, script=math] diff --git a/tex/context/base/mkiv/good-mth.lua b/tex/context/base/mkiv/good-mth.lua index b85e680cc..3473cc205 100644 --- a/tex/context/base/mkiv/good-mth.lua +++ b/tex/context/base/mkiv/good-mth.lua @@ -6,8 +6,9 @@ if not modules then modules = { } end modules ['good-mth'] = { license = "see context related readme files" } -local type, next = type, next +local type, next, tonumber, unpack = type, next, tonumber, unpack local ceil = math.ceil +local match = string.match local fonts = fonts @@ -20,6 +21,10 @@ local fontgoodies = fonts.goodies or { } local fontcharacters = fonts.hashes.characters +local trace_defining = false trackers.register("math.defining", function(v) trace_defining = v end) + +local report_math = logs.reporter("mathematics","initializing") + local nuts = nodes.nuts local setlink = nuts.setlink @@ -33,11 +38,149 @@ local new_vlist = nodepool.vlist local insert_node_after = nuts.insert_after +local helpers = fonts.helpers +local upcommand = helpers.commands.up +local rightcommand = helpers.commands.right +local charcommand = helpers.commands.char +local prependcommands = helpers.prependcommands + -- experiment, we have to load the definitions immediately as they precede -- the definition so they need to be initialized in the typescript +local function withscriptcode(tfmdata,unicode,data,action) + if type(unicode) == "string" then + local p, u = match(unicode,"^(.-):(.-)$") + if u then + u = tonumber(u) + if u then + local slots = fonts.helpers.mathscriptslots(tfmdata,u) + if slots then + if p == "*" then + action(u,data) + for i=1,#slots do + action(slots[i],data) + end + else + p = tonumber(p) + if p then + action(slots[p],data) + end + end + end + end + end + else + action(unicode,data) + end +end + local function finalize(tfmdata,feature,value) - mathematics.overloaddimensions(tfmdata,tfmdata,value) +-- if tfmdata.mathparameters then -- funny, cambria text has this + local goodies = tfmdata.goodies + if goodies then + local virtualized = mathematics.virtualized + for i=1,#goodies do + local goodie = goodies[i] + local mathematics = goodie.mathematics + local dimensions = mathematics and mathematics.dimensions + if dimensions then + if trace_defining then + report_math("overloading dimensions in %a @ %p",tfmdata.properties.fullname,tfmdata.parameters.size) + end + local characters = tfmdata.characters + local descriptions = tfmdata.descriptions + local parameters = tfmdata.parameters + local factor = parameters.factor + local hfactor = parameters.hfactor + local vfactor = parameters.vfactor + local function overloadone(unicode,data) + local character = characters[unicode] + if not character then + local c = virtualized[unicode] + if c then + character = characters[c] + end + end + if character then + local width = data.width + local height = data.height + local depth = data.depth + if trace_defining and (width or height or depth) then + report_math("overloading dimensions of %C, width %p, height %p, depth %p", + unicode,width or 0,height or 0,depth or 0) + end + if width then character.width = width * hfactor end + if height then character.height = height * vfactor end + if depth then character.depth = depth * vfactor end + -- + local xoffset = data.xoffset + local yoffset = data.yoffset + if xoffset == "llx" then + local d = descriptions[unicode] + if d then + xoffset = - d.boundingbox[1] * hfactor + character.width = character.width + xoffset + xoffset = rightcommand[xoffset] + else + xoffset = nil + end + elseif xoffset and xoffset ~= 0 then + xoffset = rightcommand[xoffset * hfactor] + else + xoffset = nil + end + if yoffset and yoffset ~= 0 then + yoffset = upcommand[yoffset * vfactor] + else + yoffset = nil + end + if xoffset or yoffset then + local commands = characters.commands + if commands then + prependcommands(commands,yoffset,xoffset) + else + local slot = charcommand[unicode] + if xoffset and yoffset then + character.commands = { xoffset, yoffset, slot } + elseif xoffset then + character.commands = { xoffset, slot } + else + character.commands = { yoffset, slot } + end + end + end + elseif trace_defining then + report_math("no overloading dimensions of %C, not in font",unicode) + end + end + local function overload(dimensions) + for unicode, data in next, dimensions do + withscriptcode(tfmdata,unicode,data,overloadone) + end + end + if value == nil then + value = { "default" } + end + if value == "all" or value == true then + for name, value in next, dimensions do + overload(value) + end + else + if type(value) == "string" then + value = utilities.parsers.settings_to_array(value) + end + if type(value) == "table" then + for i=1,#value do + local d = dimensions[value[i]] + if d then + overload(d) + end + end + end + end + end + end + end end registerotffeature { @@ -77,10 +220,11 @@ end fontgoodies.register("mathematics", initialize) -local enabled = false directives.register("fontgoodies.mathkerning",function(v) enabled = v end) +-- local enabled = false directives.register("fontgoodies.mathkerning",function(v) enabled = v end) local function initialize(tfmdata) - if enabled and tfmdata.mathparameters then -- funny, cambria text has this +-- if enabled and tfmdata.mathparameters then -- funny, cambria text has this + if tfmdata.mathparameters then -- funny, cambria text has this local goodies = tfmdata.goodies if goodies then local characters = tfmdata.characters @@ -91,12 +235,15 @@ local function initialize(tfmdata) if mathgoodies then local kerns = mathgoodies.kerns if kerns then - for unicode, specification in next, kerns do + local function kernone(unicode,data) local chardata = characters[unicode] - if chardata and (not chardata.mathkerns or specification.force) then - chardata.mathkerns = specification + if chardata and (not chardata.mathkerns or data.force) then + chardata.mathkerns = data end end + for unicode, data in next, kerns do + withscriptcode(tfmdata,unicode,data,kernone) + end return end end @@ -109,9 +256,9 @@ local function initialize(tfmdata) end registerotffeature { - name = "mathkerns", - description = "math kerns", - default = true, + name = "mathkerns", + description = "math kerns", + -- default = true, initializers = { base = initialize, node = initialize, diff --git a/tex/context/base/mkiv/math-act.lua b/tex/context/base/mkiv/math-act.lua index 4f38b4195..a5cfa82de 100644 --- a/tex/context/base/mkiv/math-act.lua +++ b/tex/context/base/mkiv/math-act.lua @@ -230,115 +230,6 @@ sequencers.appendaction("aftercopyingcharacters", "system","mathematics.tweakaft local virtualized = mathematics.virtualized -function mathematics.overloaddimensions(target,original,set) - local goodies = target.goodies - if goodies then - for i=1,#goodies do - local goodie = goodies[i] - local mathematics = goodie.mathematics - local dimensions = mathematics and mathematics.dimensions - if dimensions then - if trace_defining then - report_math("overloading dimensions in %a @ %p",target.properties.fullname,target.parameters.size) - end - local characters = target.characters - local descriptions = target.descriptions - local parameters = target.parameters - local factor = parameters.factor - local hfactor = parameters.hfactor - local vfactor = parameters.vfactor -if not CONTEXTLMTXMODE or CONTEXTLMTXMODE == 0 then - target.type = "virtual" - target.properties.virtualized = true -end - local function overload(dimensions) - for unicode, data in next, dimensions do - local character = characters[unicode] - if not character then - local c = virtualized[unicode] - if c then - character = characters[c] - end - end - if character then - -- - local width = data.width - local height = data.height - local depth = data.depth - if trace_defining and (width or height or depth) then - report_math("overloading dimensions of %C, width %p, height %p, depth %p", - unicode,width or 0,height or 0,depth or 0) - end - if width then character.width = width * hfactor end - if height then character.height = height * vfactor end - if depth then character.depth = depth * vfactor end - -- - local xoffset = data.xoffset - local yoffset = data.yoffset - if xoffset == "llx" then - local d = descriptions[unicode] - if d then - xoffset = - d.boundingbox[1] * hfactor - character.width = character.width + xoffset - xoffset = rightcommand[xoffset] - else - xoffset = nil - end - elseif xoffset and xoffset ~= 0 then - xoffset = rightcommand[xoffset * hfactor] - else - xoffset = nil - end - if yoffset and yoffset ~= 0 then - yoffset = upcommand[yoffset * vfactor] - else - yoffset = nil - end - if xoffset or yoffset then - local commands = characters.commands - if commands then - prependcommands(commands,yoffset,xoffset) - else - local slot = charcommand[unicode] - if xoffset and yoffset then - character.commands = { xoffset, yoffset, slot } - elseif xoffset then - character.commands = { xoffset, slot } - else - character.commands = { yoffset, slot } - end - end - end - elseif trace_defining then - report_math("no overloading dimensions of %C, not in font",unicode) - end - end - end - if set == nil then - set = { "default" } - end - if set == "all" or set == true then - for name, set in next, dimensions do - overload(set) - end - else - if type(set) == "string" then - set = utilities.parsers.settings_to_array(set) - end - if type(set) == "table" then - for i=1,#set do - local d = dimensions[set[i]] - if d then - overload(d) - end - end - end - end - end - end - end -end - -- no, it's a feature now (see good-mth): -- -- sequencers.appendaction("aftercopyingcharacters", "system","mathematics.overloaddimensions") @@ -711,10 +602,10 @@ function mathematics.finishfallbacks(target,specification,fallbacks) fonts = { } target.fonts = fonts end -if not CONTEXTLMTXMODE or CONTEXTLMTXMODE == 0 then + -- target.type = "virtual" target.properties.virtualized = true -end + -- if #fonts == 0 then fonts[1] = { id = 0, size = size } -- self, will be resolved later end diff --git a/tex/context/base/mkiv/mult-fun.lua b/tex/context/base/mkiv/mult-fun.lua index 4d99e8320..4e4a901c0 100644 --- a/tex/context/base/mkiv/mult-fun.lua +++ b/tex/context/base/mkiv/mult-fun.lua @@ -187,7 +187,7 @@ return { -- "inpath", "pointof", "leftof", "rightof", -- - "utflen", "utfsub", + "utfnum", "utflen", "utfsub", -- "newhash", "disposehash", "inhash", "tohash", -- diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf Binary files differindex d55bfa411..605d8e1f1 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 78ade839c..3c5c26cb3 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-mar.lua b/tex/context/base/mkiv/strc-mar.lua index b5fd2667b..f7953c416 100644 --- a/tex/context/base/mkiv/strc-mar.lua +++ b/tex/context/base/mkiv/strc-mar.lua @@ -122,7 +122,7 @@ end local function sweep(head,first,last) for n, id, subtype in nextnode, head do -- we need to handle empty heads so we test for latelua - if id == glyph_code or (id == whatsit_code and subtype == lateluawhatsit_code) then + if id == glyph_code or (id == whatsit_code and subtype == lateluawhatsit_code) then -- brrr local a = getattr(n,a_marks) if not a then -- next diff --git a/tex/context/base/mkiv/task-ini.lua b/tex/context/base/mkiv/task-ini.lua index c06e32df3..3e78fb2f9 100644 --- a/tex/context/base/mkiv/task-ini.lua +++ b/tex/context/base/mkiv/task-ini.lua @@ -95,6 +95,7 @@ appendaction("shipouts", "finishers", "attributes.transparencies.handler", appendaction("shipouts", "finishers", "attributes.colorintents.handler", nil, "nut", "disabled" ) appendaction("shipouts", "finishers", "attributes.negatives.handler", nil, "nut", "disabled" ) appendaction("shipouts", "finishers", "attributes.effects.handler", nil, "nut", "disabled" ) +appendaction("shipouts", "finishers", "attributes.alternates.handler", nil, "nut", "disabled" ) appendaction("shipouts", "finishers", "attributes.viewerlayers.handler", nil, "nut", "disabled" ) appendaction("shipouts", "wrapup", "nodes.handlers.export", nil, "nut", "disabled" ) -- always last diff --git a/tex/context/base/mkxl/anch-pos.lmt b/tex/context/base/mkxl/anch-pos.lmt index e804dbdf6..67d1657f2 100644 --- a/tex/context/base/mkxl/anch-pos.lmt +++ b/tex/context/base/mkxl/anch-pos.lmt @@ -1628,6 +1628,9 @@ end) local newsavepos = nodes.pool.savepos +jobpositions.lastx = 0 +jobpositions.lasty = 0 + implement { name = "savepos", actions = function() context(newsavepos()) end } -implement { name = "lastxpos", actions = function() context(gethpos()) end } -implement { name = "lastypos", actions = function() context(getvpos()) end } +implement { name = "lastxpos", actions = function() context(jobpositions.lastx) end } +implement { name = "lastypos", actions = function() context(jobpositions.lasty) end } diff --git a/tex/context/base/mkxl/attr-alt.lmt b/tex/context/base/mkxl/attr-alt.lmt new file mode 100644 index 000000000..9d8592074 --- /dev/null +++ b/tex/context/base/mkxl/attr-alt.lmt @@ -0,0 +1,111 @@ +if not modules then modules = { } end modules ['attr-eff'] = { + version = 1.001, + comment = "companion to attr-eff.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local attributes, nodes, backends, utilities = attributes, nodes, backends, utilities +local tex = tex + +local states = attributes.states +local enableaction = nodes.tasks.enableaction +local nodeinjections = backends.nodeinjections +local texsetattribute = tex.setattribute +local allocate = utilities.storage.allocate +local setmetatableindex = table.setmetatableindex + +local interfaces = interfaces +local implement = interfaces.implement + +attributes.alternates = attributes.alternates or { } +local alternates = attributes.alternates + +local a_alternate = attributes.private('alternate') + +alternates.data = allocate() +alternates.values = alternates.values or { } +alternates.registered = alternates.registered or { } +alternates.attribute = a_alternate + +local data = alternates.data +local registered = alternates.registered +local values = alternates.values + +storage.register("attributes/alternates/registered", registered, "attributes.alternates.registered") +storage.register("attributes/alternates/values", values, "attributes.alternates.values") + +local function extender(alternates,key) + if key == "none" then + local d = nodeinjections.stopalternate() + alternates.none = d + return d + end +end + +local function reviver(data,n) + local d = values[n] and nodeinjections.startalternate(values[n]) or nodeinjections.stopalternate() + data[n] = d + return d +end + +setmetatableindex(alternates, extender) +setmetatableindex(alternates.data, reviver) + +alternates.handler = nodes.installattributehandler { + name = "alternate", + namespace = alternates, + initializer = states.initialize, + finalizer = states.finalize, + processor = states.simple, +} + +local function register(specification) + local text = specification.text or "unknown" + local n = registered[text] + if not n then + n = #values + 1 + values[n] = text + registered[text] = n + end + return n +end + +local enabled = false + +local function enable() + if not enabled then + enableaction("shipouts","attributes.alternates.handler") + enabled = true + end +end + +alternates.register = register +alternates.enable = enable + +-- interface + +implement { + name = "setalternate", + actions = function(specification) + if not enabled then + enable() + end + texsetattribute(a_alternate,register(specification)) + end, + arguments = { + { + { "text", "string" }, + } + } +} + +implement { + name = "resetalternate", + actions = function() + if enabled then + texsetattribute(a_alternate) + end + end +} diff --git a/tex/context/base/mkxl/attr-alt.mkxl b/tex/context/base/mkxl/attr-alt.mkxl new file mode 100644 index 000000000..3881d929e --- /dev/null +++ b/tex/context/base/mkxl/attr-alt.mkxl @@ -0,0 +1,55 @@ +%D \module +%D [ file=attr-alt, +%D version=2007.06.06, +%D title=\CONTEXT\ Attribute Macros, +%D subtitle=Alternates, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\writestatus{loading}{ConTeXt Attribute Macros / Alternates} + +\registerctxluafile{attr-alt}{autosuffix} + +%D The main reason for providing this is that we need to make sure we have no +%D dangling end markers when we cross a page. Public viewers don't seem to support +%D actual text at all and acrobat has some funny selection issues. +%D +%D \starttyping +%D test +%D \startalternate[text={A}] +%D \dorecurse{10}{A } +%D \startalternate[text={B}] +%D \dorecurse{10}{B } +%D \stopalternate +%D \dorecurse{10}{A } +%D \stopalternate +%D test \par +%D \stoptyping +%D +%D \starttyping +%D test \startalternate[text={e=mc^2}]!$e=mc^2$\stopalternate\par +%D test \alternate{e=mc^2}{copy:}\nbsp$e=mc^2$\par +%D \stoptyping + +\unprotect + +\permanent\protected\def\startalternate[#1]% maybe better/also: [text={...}] + {\begingroup + \getdummyparameters[\c!text=,#1]% + \clf_setalternate text {\dummyparameter\c!text}\relax} + +\permanent\protected\def\stopalternate + {\endgroup} + +\permanent\protected\def\alternate#1% + {\groupedcommand{\clf_setalternate text {#1}\relax}{}} + +\permanent\protected\def\setalternate #1{\clf_setalternate text {#1}\relax} +\permanent\protected\def\resetalternate {\clf_resetalternate} + +\protect \endinput diff --git a/tex/context/base/mkxl/attr-eff.mkxl b/tex/context/base/mkxl/attr-eff.mkxl index 04a0c55ce..42aadf9a2 100644 --- a/tex/context/base/mkxl/attr-eff.mkxl +++ b/tex/context/base/mkxl/attr-eff.mkxl @@ -30,8 +30,8 @@ \appendtoks \edef\p_method{\effectparameter\c!method}% \ifx\p_method\v!command - \setuxvalue{\e!start\currenteffect}{\starteffect[#1]}% - \setuxvalue{\e!stop \currenteffect}{\stopeffect}% + \frozen\protected\xdefcsname\e!start\currenteffect\endcsname{\starteffect[#1]}% + \frozen\protected\xdefcsname\e!stop \currenteffect\endcsname{\stopeffect}% \fi \to \everydefineeffect diff --git a/tex/context/base/mkxl/attr-ini.mkxl b/tex/context/base/mkxl/attr-ini.mkxl index de22cd6e2..8cef1ec56 100644 --- a/tex/context/base/mkxl/attr-ini.mkxl +++ b/tex/context/base/mkxl/attr-ini.mkxl @@ -130,6 +130,7 @@ \definesystemattribute [ruled] [public] \definesystemattribute [shifted] [public] \definesystemattribute [checkedbreak] [public] +\definesystemattribute [alternate] [public] \definesystemattribute [vboxtohboxseparator] [public] \permanent\protected\let\showattributes\clf_showattributes % maybe at lua end diff --git a/tex/context/base/mkxl/back-trf.mkxl b/tex/context/base/mkxl/back-ext.mkxl index fcf69ade4..bba33335d 100644 --- a/tex/context/base/mkxl/back-trf.mkxl +++ b/tex/context/base/mkxl/back-ext.mkxl @@ -1,8 +1,8 @@ %D \module -%D [ file=back-trf, -%D version=2019.02.08, % 2009.04.15, +%D [ file=back-ext, +%D version=2019.02.08, % and later, merged file %D title=\CONTEXT\ Backend Macros, -%D subtitle=Transformations, +%D subtitle=Output, %D author=Hans Hagen, %D date=\currentdate, %D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] @@ -11,9 +11,15 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. +% \registerctxluafile{back-ext}{autosuffix} + \unprotect -\registerctxluafile{back-trf}{autosuffix} +% \let\normalopenout \openout +% \let\normalwrite \write +% \let\normalcloseout\closeout +% \let\normallatelua \latelua +% \let\normalspecial \special % rotation diff --git a/tex/context/base/mkxl/back-ini.lmt b/tex/context/base/mkxl/back-ini.lmt index ee40c384d..922705742 100644 --- a/tex/context/base/mkxl/back-ini.lmt +++ b/tex/context/base/mkxl/back-ini.lmt @@ -95,17 +95,6 @@ statistics.register("used backend", function() end end) -local comment = { "comment", "" } - -tables.vfspecials = allocate { - red = comment, - green = comment, - blue = comment, - black = comment, - startslant = comment, - stopslant = comment, -} - -- can best be here interfaces.implement { @@ -131,25 +120,6 @@ end) backends.included = included --- Also here: - -local paper_width = 0 -local paper_height = 0 - -function codeinjections.setpagedimensions(paperwidth,paperheight) - if paperwidth then - paper_width = paperwidth - end - if paperheight then - paper_height = paperheight - end - return paper_width, paper_height -end - -function codeinjections.getpagedimensions() - return paper_width, paper_height -end - -- could also be codeinjections function backends.getcallbackstate() diff --git a/tex/context/base/mkxl/back-out.lmt b/tex/context/base/mkxl/back-out.lmt deleted file mode 100644 index fbcb220dc..000000000 --- a/tex/context/base/mkxl/back-out.lmt +++ /dev/null @@ -1,255 +0,0 @@ -if not modules then modules = { } end modules ['back-out'] = { - version = 1.001, - comment = "companion to back-ini.mkiv", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - -local type = type -local loadstring = loadstring - -local context = context - --- tokens.scanners..... - -local get = token.get_index -local scanners = tokens.scanners -local scaninteger = scanners.integer -local scanstring = scanners.string -local scankeyword = scanners.keyword -local scantokenlist = scanners.tokenlist - -local serialize = token.serialize - -local logwriter = logs.writer -local openfile = io.open -local flushio = io.flush - -local nuts = nodes.nuts -local tonode = nuts.tonode -local copynode = nuts.copy -local nodepool = nuts.pool - -local getdata = nuts.getdata - -local whatsit_code = nodes.nodecodes.whatsit - -local whatsitcodes = nodes.whatsitcodes - -local literalvalues = nodes.literalvalues -local originliteral_code = literalvalues.origin -local pageliteral_code = literalvalues.page -local directliteral_code = literalvalues.direct -local rawliteral_code = literalvalues.raw - -local immediate_code = tex.flagcodes.immediate - -local nodeproperties = nodes.properties.data - -local channels = { } - -local register = nodepool.register -local newnut = nuts.new - -local opennode = register(newnut(whatsit_code,whatsitcodes.open)) -local writenode = register(newnut(whatsit_code,whatsitcodes.write)) -local closenode = register(newnut(whatsit_code,whatsitcodes.close)) -local lateluanode = register(newnut(whatsit_code,whatsitcodes.latelua)) -local literalnode = register(newnut(whatsit_code,whatsitcodes.literal)) -local savenode = register(newnut(whatsit_code,whatsitcodes.save)) -local restorenode = register(newnut(whatsit_code,whatsitcodes.restore)) -local setmatrixnode = register(newnut(whatsit_code,whatsitcodes.setmatrix)) - -local open_command, write_command, close_command - -backends = backends or { } - -local function immediately(prefix) - return prefix and (prefix & immediate_code) ~= 0 -end - -local function openout(prefix) - local channel = scaninteger() - scankeyword("=") -- hack - local filename = scanstring() - if not immediately(prefix) then - local n = copynode(opennode) - nodeproperties[n] = { channel = channel, filename = filename } -- action = "open" - return context(tonode(n)) - elseif not channels[channel] then - local handle = openfile(filename,"wb") or false - if handle then - channels[channel] = handle - else - -- error - end - end -end - -function backends.openout(n) - local p = nodeproperties[n] - if p then - local handle = openfile(p.filename,"wb") or false - if handle then - channels[p.channel] = handle - else - -- error - end - end -end - -local function write(prefix) - local channel = scaninteger() - if not immediately(prefix) then - local t = scantokenlist() - local n = copynode(writenode) - nodeproperties[n] = { channel = channel, data = t } -- action = "write" - return context(tonode(n)) - else - local content = scanstring() - local handle = channels[channel] - if handle then - handle:write(content,"\n") - else - logwriter(content,"\n") - end - end -end - -function backends.writeout(n) - local p = nodeproperties[n] - if p then - local handle = channels[p.channel] - local content = serialize(p.data) - if handle then - handle:write(content,"\n") - else - logwriter(content,"\n") - end - end -end - -local function closeout(prefix) - local channel = scaninteger() - if not immediately(prefix) then - local n = copynode(closenode) - nodeproperties[n] = { channel = channel } -- action = "close" - return context(tonode(n)) - else - local handle = channels[channel] - if handle then - handle:close() - channels[channel] = false - flushio() - else - -- error - end - end -end - -function backends.closeout(n) - local p = nodeproperties[n] - if p then - local channel = p.channel - local handle = channels[channel] - if handle then - handle:close() - channels[channel] = false - flushio() - else - -- error - end - end -end - -local noflatelua = 0 - -local function latelua() - local node = copynode(lateluanode) - local name = "latelua" - if scankeyword("name") then - name = scanstring() - end - local data = scantokenlist() - nodeproperties[node] = { name = name, data = data } - return context(tonode(node)) -end - -function backends.latelua(current,pos_h,pos_v) -- todo: pass pos_h and pos_v (more efficient in lmtx) - local p = nodeproperties[current] - if p then - data = p.data - else - data = getdata(current) - end - noflatelua = noflatelua + 1 - local kind = type(data) - if kind == "table" then - data.action(data.specification or data) - elseif kind == "function" then - data() - else - if kind ~= "string" then - data = serialize(data) - end - if #data ~= "" then - local code = loadstring(data) - if code then - code() - end - end - end -end - -function backends.getcallbackstate() - return { count = noflatelua } -end - -function nodepool.originliteral(str) local t = copynode(literalnode) nodeproperties[t] = { data = str, mode = originliteral_code } return t end -function nodepool.pageliteral (str) local t = copynode(literalnode) nodeproperties[t] = { data = str, mode = pageliteral_code } return t end -function nodepool.directliteral(str) local t = copynode(literalnode) nodeproperties[t] = { data = str, mode = directliteral_code } return t end -function nodepool.rawliteral (str) local t = copynode(literalnode) nodeproperties[t] = { data = str, mode = rawliteral_code } return t end - -local pdfliterals = { - [originliteral_code] = originliteral_code, [literalvalues[originliteral_code]] = originliteral_code, - [pageliteral_code] = pageliteral_code, [literalvalues[pageliteral_code]] = pageliteral_code, - [directliteral_code] = directliteral_code, [literalvalues[directliteral_code]] = directliteral_code, - [rawliteral_code] = rawliteral_code, [literalvalues[rawliteral_code]] = rawliteral_code, -} - -function nodepool.literal(mode,str) - local t = copynode(literalnode) - if str then - nodeproperties[t] = { data = str, mode = pdfliterals[mode] or pageliteral_code } - else - nodeproperties[t] = { data = mode, mode = pageliteral_code } - end - return t -end - ---- these 3 will move to node-res as they are generic - -function nodepool.save() - return copynode(savenode) -end - -function nodepool.restore() - return copynode(restorenode) -end - -function nodepool.setmatrix(rx,sx,sy,ry,tx,ty) - local t = copynode(setmatrixnode) - nodeproperties[t] = { matrix = { rx, sx, sy, ry, tx, ty } } - return t -end - -interfaces.implement { name = "openout", actions = openout, public = true, usage = "value" } -interfaces.implement { name = "write", actions = write, public = true, usage = "value" } -interfaces.implement { name = "closeout", actions = closeout, public = true, usage = "value" } -interfaces.implement { name = "latelua", actions = latelua, public = true, protected = true } -interfaces.implement { name = "special", actions = scanstring, public = true, protected = true } - -open_command = get(token.create("openout")) -write_command = get(token.create("write")) -close_command = get(token.create("closeout")) diff --git a/tex/context/base/mkxl/back-out.mkxl b/tex/context/base/mkxl/back-out.mkxl deleted file mode 100644 index 5cf79b2ea..000000000 --- a/tex/context/base/mkxl/back-out.mkxl +++ /dev/null @@ -1,22 +0,0 @@ -%D \module -%D [ file=back-out, -%D version=2019.02.08, -%D title=\CONTEXT\ Backend Macros, -%D subtitle=Output, -%D author=Hans Hagen, -%D date=\currentdate, -%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] -%C -%C This module is part of the \CONTEXT\ macro||package and is -%C therefore copyrighted by \PRAGMA. See mreadme.pdf for -%C details. - -\registerctxluafile{back-out}{autosuffix} - -% \let\normalopenout \openout -% \let\normalwrite \write -% \let\normalcloseout\closeout -% \let\normallatelua \latelua -% \let\normalspecial \special - -\endinput diff --git a/tex/context/base/mkxl/back-pdf.mkxl b/tex/context/base/mkxl/back-pdf.mkxl index 66db06ef1..d59c29bc0 100644 --- a/tex/context/base/mkxl/back-pdf.mkxl +++ b/tex/context/base/mkxl/back-pdf.mkxl @@ -20,7 +20,6 @@ \registerctxluafile{lpdf-ini}{autosuffix,optimize} \registerctxluafile{lpdf-lmt}{autosuffix,optimize} \registerctxluafile{lpdf-col}{autosuffix} -\registerctxluafile{lpdf-vfc}{autosuffix} \registerctxluafile{lpdf-xmp}{autosuffix} \registerctxluafile{lpdf-ano}{autosuffix} \registerctxluafile{lpdf-res}{autosuffix} diff --git a/tex/context/base/mkxl/back-trf.lmt b/tex/context/base/mkxl/back-trf.lmt deleted file mode 100644 index e3ec0bda3..000000000 --- a/tex/context/base/mkxl/back-trf.lmt +++ /dev/null @@ -1,164 +0,0 @@ -if not modules then modules = { } end modules ['back-trf'] = { - version = 1.001, - comment = "companion to back-ini.mkiv", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - -local sind, cosd, abs = math.sind, math.cosd, math.abs -local insert, remove = table.insert, table.remove -local unpack = unpack - -local context = context - -local formatters = string.formatters - -local scanners = tokens.scanners -local scankeyword = scanners.keyword -local scaninteger = scanners.integer -local scannumber = scanners.number -local scanstring = scanners.string - -local implement = interfaces.implement - -local nodepool = nodes.pool -local savenode = nodepool.save -local restorenode = nodepool.restore -local setmatrixnode = nodepool.setmatrix -local literalnode = nodepool.literal -- has to become some nodeinjection - -local stack = { } -local restore = true -- false - -updaters.register("backend.update",function() - savenode = nodepool.save -- not needed - restorenode = nodepool.restore -- not needed - setmatrixnode = nodepool.setmatrix -- not needed - literalnode = nodepool.literal -- has to become some nodeinjection -end) - -local function stopsomething() - local top = remove(stack) - if top == false then - -- not wrapped - elseif top == true then - context(restorenode()) - elseif top then - context(setmatrixnode(unpack(top))) -- not really needed anymore - context(restorenode()) - else - -- nesting error - end -end - -local function startrotation() - local a = scannumber() - if a == 0 then - insert(stack,false) - else - local s, c = sind(a), cosd(a) - if abs(s) < 0.000001 then - s = 0 -- otherwise funny -0.00000 - end - if abs(c) < 0.000001 then - c = 0 -- otherwise funny -0.00000 - end - context(savenode()) - context(setmatrixnode(c,s,-s,c)) - insert(stack,restore and { c, -s, s, c } or true) - end -end - -implement { name = "startrotation", actions = startrotation } -implement { name = "stoprotation", actions = stopsomething } - -local function startscaling() -- at the tex end we use sx and sy instead of rx and ry - local rx, ry = 1, 1 - while true do - if scankeyword("rx") then - rx = scannumber() - elseif scankeyword("ry") then - ry = scannumber() - -- elseif scankeyword("revert") then - -- local top = stack[#stack] - -- if top then - -- rx = top[1] - -- ry = top[4] - -- else - -- rx = 1 - -- ry = 1 - -- end - else - break - end - end - if rx == 1 and ry == 1 then - insert(stack,false) - else - if rx == 0 then - rx = 0.0001 - end - if ry == 0 then - ry = 0.0001 - end - context(savenode()) - context(setmatrixnode(rx,0,0,ry)) - insert(stack,restore and { 1/rx, 0, 0, 1/ry } or true) - end -end - -implement { name = "startscaling", actions = startscaling } -implement { name = "stopscaling", actions = stopsomething } - -local function startmatrix() -- rx sx sy ry -- tx, ty - local rx, sx, sy, ry = 1, 0, 0, 1 - while true do - if scankeyword("rx") then rx = scannumber() - elseif scankeyword("ry") then ry = scannumber() - elseif scankeyword("sx") then sx = scannumber() - elseif scankeyword("sy") then sy = scannumber() - else break end - end - if rx == 1 and sx == 0 and sy == 0 and ry == 1 then - insert(stack,false) - else - context(savenode()) - context(setmatrixnode(rx,sx,sy,ry)) - insert(stack,store and { -rx, -sx, -sy, -ry } or true) - end -end - -implement { name = "startmatrix", actions = startmatrix } -implement { name = "stopmatrix", actions = stopsomething } - -local function startmirroring() - context(setmatrixnode(-1,0,0,1)) -end - -implement { name = "startmirroring", actions = startmirroring } -implement { name = "stopmirroring", actions = startmirroring } -- not: stopsomething - --- this could also run on top of pack-rul ... todo - --- local function startclipping() --- -- context(savenode()) --- context(literalnode("origin",formatters["q 0 w %s W n"](scanstring()))) --- end --- --- local function stopclipping() --- -- context(restorenode()) --- context(literalnode("Q")) --- end - -local function startclipping() - context(savenode()) - context(literalnode("origin",formatters["0 w %s W n"](scanstring()))) -end - -local function stopclipping() - context(restorenode()) -end - -implement { name = "startclipping", actions = startclipping } -implement { name = "stopclipping", actions = stopclipping } diff --git a/tex/context/base/mkxl/colo-nod.lmt b/tex/context/base/mkxl/colo-nod.lmt index d65f5978c..67487fee5 100644 --- a/tex/context/base/mkxl/colo-nod.lmt +++ b/tex/context/base/mkxl/colo-nod.lmt @@ -12,9 +12,9 @@ local setattrs = nuts.setattrs local privateattributes = attributes.private +local a_colormodel = privateattributes('colormodel') local a_color = privateattributes('color') local a_transparency = privateattributes('transparency') -local a_colormodel = privateattributes('colormodel') local colors = { } nuts.colors = colors @@ -26,9 +26,9 @@ function colors.set(n,ma,ca,ta) -- we could also do layers here ma = 1 end if ta then - setattrs(n,a_colorspace,ma,a_color,ca,a_transparency,ta) + setattrs(n,a_colormodel,ma,a_color,ca,a_transparency,ta) else - setattrs(n,a_colorspace,ma,a_color,ca) + setattrs(n,a_colormodel,ma,a_color,ca) end end elseif ta then diff --git a/tex/context/base/mkxl/cont-new.mkxl b/tex/context/base/mkxl/cont-new.mkxl index 31dbd327a..8f1882ce5 100644 --- a/tex/context/base/mkxl/cont-new.mkxl +++ b/tex/context/base/mkxl/cont-new.mkxl @@ -13,7 +13,7 @@ % \normalend % uncomment this to get the real base runtime -\newcontextversion{2021.01.11 16:28} +\newcontextversion{2021.01.17 21:39} %D This file is loaded at runtime, thereby providing an excellent place for hacks, %D patches, extensions and new features. There can be local overloads in cont-loc diff --git a/tex/context/base/mkxl/context.mkxl b/tex/context/base/mkxl/context.mkxl index 751712225..54b1bb730 100644 --- a/tex/context/base/mkxl/context.mkxl +++ b/tex/context/base/mkxl/context.mkxl @@ -29,7 +29,7 @@ %D {YYYY.MM.DD HH:MM} format. \immutable\edef\contextformat {\jobname} -\immutable\edef\contextversion{2021.01.11 16:28} +\immutable\edef\contextversion{2021.01.17 21:39} %overloadmode 1 % check frozen / warning %overloadmode 2 % check frozen / error @@ -159,7 +159,7 @@ \loadmkxlfile{node-ini} -\loadmkxlfile{cldf-bas} % basics / depends on nodes +% \loadmkxlfile{cldf-bas} % basics / depends on nodes \loadmkxlfile{node-fin} \loadmkxlfile{node-mig} @@ -169,13 +169,15 @@ \loadmkxlfile{back-ini} \loadmkxlfile{back-res} -\loadmkxlfile{back-trf} -\loadmkxlfile{back-out} +\loadmkxlfile{back-ext} + +\loadmkxlfile{cldf-bas} % basics / depends on nodes \loadmkxlfile{attr-col} \loadmkxlfile{attr-lay} \loadmkxlfile{attr-neg} \loadmkxlfile{attr-eff} +\loadmkxlfile{attr-alt} \loadmkxlfile{attr-mkr} \loadmkxlfile{trac-tex} diff --git a/tex/context/base/mkxl/driv-shp.lmt b/tex/context/base/mkxl/driv-shp.lmt index 9747ba82d..cfa61e30e 100644 --- a/tex/context/base/mkxl/driv-shp.lmt +++ b/tex/context/base/mkxl/driv-shp.lmt @@ -99,21 +99,7 @@ local gleaders_code = gluecodes.gleaders local spaceskip_code = gluecodes.spaceskip -local saveposwhatsit_code = whatsitcodes.savepos -local userdefinedwhatsit_code = whatsitcodes.userdefined -local openwhatsit_code = whatsitcodes.open -local writewhatsit_code = whatsitcodes.write -local closewhatsit_code = whatsitcodes.close -local lateluawhatsit_code = whatsitcodes.latelua -local literalwhatsit_code = whatsitcodes.literal -local setmatrixwhatsit_code = whatsitcodes.setmatrix -local savewhatsit_code = whatsitcodes.save -local restorewhatsit_code = whatsitcodes.restore - -local getpagedimensions getpagedimensions = function() - getpagedimensions = backends.codeinjections.getpagedimensions - return getpagedimensions() -end +local getpagedimensions = layouts.getpagedimensions local drivers = drivers local instances = drivers.instances @@ -154,11 +140,6 @@ local flushcharacter local flushfontchar local flushrule local flushliteral -local flushsetmatrix -local flushsave -local flushrestore -local flushspecial ------ flushimage -- make local @@ -169,307 +150,323 @@ function drivers.getvpos() return round(pos_v) end -- characters -local flush_character - -local stack = setmetatableindex("table") -local level = 0 -local nesting = 0 -local main = 0 - --- experiment (smaller page stream but might be fragile) +local flush_character do -local tospace = false directives.register("backends.spaces", function(v) tospace = v end) + local stack = setmetatableindex("table") + local level = 0 + local nesting = 0 + local main = 0 --- todo: cache streams + -- experiment (smaller page stream but might be fragile) -local default = 16384 * number.dimenfactors.bp -- 65536 // 4 + local tospace = false directives.register("backends.spaces", function(v) tospace = v end) -local startcolor = function() end -local stopcolor = function() end + -- todo: cache streams -updaters.register("backend.update",function() - startcolor = fonts.vfcommands.startcolor - stopcolor = fonts.vfcommands.stopcolor -end) + local default = 16384 * number.dimenfactors.bp -- 65536 // 4 -local function flush_vf_packet(current,pos_h,pos_v,pos_r,font,char,data,factor,vfcommands,sx,sy) + local vfinjectors = fonts.helpers.vfinjectors - if nesting > 100 then - return - elseif nesting == 0 then - main = font - end + local function flush_vf_packet(current,pos_h,pos_v,pos_r,font,char,data,factor,vfcommands,sx,sy) - nesting = nesting + 1 + if nesting > 100 then + return + elseif nesting == 0 then + main = font + end - local saved_h = pos_h - local saved_v = pos_v - local saved_r = pos_r - pos_r = lefttoright_code + nesting = nesting + 1 - local data = fontdata[font] - local fnt = font - local fonts = data.fonts - local siz = (data.parameters.factor or 1)/65536 + local saved_h = pos_h + local saved_v = pos_v + local saved_r = pos_r + pos_r = lefttoright_code --- siz = siz * data.parameters.size / 1000 + local data = fontdata[font] + local fnt = font + local fonts = data.fonts + local siz = (data.parameters.factor or 1)/65536 - local function flushchar(font,char,fnt,chr,f,e) - if fnt then - local nest = char ~= chr or font ~= fnt - if fnt == 0 then - fnt = main + local function flushchar(font,char,fnt,chr,f,e) + if fnt then + local nest = char ~= chr or font ~= fnt + if fnt == 0 then + fnt = main + end + return flush_character(current,fnt,chr,factor,nest,pos_h,pos_v,pos_r,f,e) + else + return 0 end --- return flush_character(false,fnt,chr,factor,nest,pos_h,pos_v,pos_r,f,e) - return flush_character(current,fnt,chr,factor,nest,pos_h,pos_v,pos_r,f,e) - else - return 0 end - end - -- we assume resolved fonts: id mandate but maybe also size - - for i=1,#vfcommands do - local packet = vfcommands[i] - local command = packet[1] - if command == "char" then - local chr = packet[2] - local f = packet[3] - local e = packet[4] - pos_h = pos_h + flushchar(font,char,fnt,chr,f,e) - elseif command == "slot" then - local index = packet[2] - local chr = packet[3] - local f = packet[4] - local e = packet[5] - if index == 0 then - pos_h = pos_h + flushchar(font,char,font,chr,f,e) - else - local okay = fonts and fonts[index] - if okay then - local fnt = okay.id - if fnt then - pos_h = pos_h + flushchar(font,char,fnt,chr,f,e) - end - else - -- safeguard, we assume the font itself (often index 1) - pos_h = pos_h + flushchar(font,char,font,chr,f,e) - end - end - elseif command == "use" then - local index = packet[2] - if index then - local fnt + -- we assume resolved fonts: id mandate but maybe also size + + -- we could map left, right, up, down -> offset + -- we could map char, font, slot to -> slot + + for i=1,#vfcommands do + local packet = vfcommands[i] + local command = packet[1] + if command == "char" then + local chr = packet[2] + local f = packet[3] + local e = packet[4] + pos_h = pos_h + flushchar(font,char,fnt,chr,f,e) + elseif command == "slot" then + local index = packet[2] + local chr = packet[3] + local f = packet[4] + local e = packet[5] if index == 0 then - fnt = font + pos_h = pos_h + flushchar(font,char,font,chr,f,e) else local okay = fonts and fonts[index] if okay then - fnt = okay.id + local fnt = okay.id + if fnt then + pos_h = pos_h + flushchar(font,char,fnt,chr,f,e) + end + else + -- safeguard, we assume the font itself (often index 1) + pos_h = pos_h + flushchar(font,char,font,chr,f,e) end end - if fnt then - -- not efficient but ok for now as experiment - local d = characters[fnt] - if d then - for i=3,#packet do - local chr = packet[i] - local dat = d[chr] - if dat then - flushfontchar(fnt,chr,dat) + elseif command == "use" then + local index = packet[2] + if index then + local fnt + if index == 0 then + fnt = font + else + local okay = fonts and fonts[index] + if okay then + fnt = okay.id + end + end + if fnt then + -- not efficient but ok for now as experiment + local d = characters[fnt] + if d then + for i=3,#packet do + local chr = packet[i] + local dat = d[chr] + if dat then + flushfontchar(fnt,chr,dat) + end end end end end - end - elseif command == "right" then - local h = packet[2] -- already scaled - if factor ~= 0 and h ~= 0 then - h = h + h * factor / 1000 -- expansion - end - h = h * sx - pos_h = pos_h + h - elseif command == "down" then - local v = packet[2] -- already scaled - v = v * sy - pos_v = pos_v - v - elseif command == "push" then - level = level + 1 - local s = stack[level] - s[1] = pos_h - s[2] = pos_v - elseif command == "pop" then - if level > 0 then - local s = stack[level] - pos_h = s[1] - pos_v = s[2] - level = level - 1 - end - elseif command == "rule" then - local size_v = packet[2] - local size_h = packet[3] - if size_h > 0 and size_v > 0 then - if factor ~= 0 then - size_h = size_h + size_h * factor / 1000 + elseif command == "right" then + local h = packet[2] -- already scaled + if h ~= 0 then + if factor ~= 0 then + h = h + h * factor / 1000 -- expansion + end + pos_h = pos_h + h * sx end - if size_h > 0 then - size_h = size_h * sx - size_v = size_v * sy - flushsimplerule(pos_h,pos_v,pos_r,size_h,size_v) - pos_h = pos_h + size_h + elseif command == "left" then + local h = packet[2] -- already scaled + if h ~= 0 then + if factor ~= 0 then + h = h + h * factor / 1000 -- expansion + end + pos_h = pos_h - h * sx end - end - elseif command == "frame" then - -- d:width d:height d:depth d:rulethickness b:outline b:advance b:baseline s:color - local width = packet[2] - if width > 0 then - local height = packet[3] or 0 - local depth = packet[4] or 0 - local total = height + depth - if total > 0 then + elseif command == "down" then + local v = packet[2] -- already scaled + if v and v ~= 0 then + pos_v = pos_v - v * sy + end + elseif command == "up" then + local v = packet[2] -- already scaled + if v and v ~= 0 then + pos_v = pos_v + v * sy + end + elseif command == "offset" then + local h = packet[2] or 0 + local v = packet[3] or 0 + if h ~= 0 then if factor ~= 0 then - width = width + width * factor / 1000 + h = h + h * factor / 1000 -- expansion end - if width > 0 then - local line = packet[5] or default - local outline = not packet[6] - local advance = not packet[7] - local baseline = outline and packet[8] - local color = packet[9] - if color then - startcolor(color) - end - width = width * sx - height = height * sy - depth = depth * sy - flushspecialrule(pos_h,pos_v,pos_r,width,height,depth,line,outline,baseline) - if color then - stopcolor() + pos_h = pos_h + h * sx + end + if v and v ~= 0 then + pos_v = pos_v + v * sy + end + elseif command == "push" then + level = level + 1 + local s = stack[level] + s[1] = pos_h + s[2] = pos_v + elseif command == "pop" then + if level > 0 then + local s = stack[level] + pos_h = s[1] + pos_v = s[2] + level = level - 1 + end + elseif command == "rule" then + local size_v = packet[2] + local size_h = packet[3] + if size_h > 0 and size_v > 0 then + if factor ~= 0 then + size_h = size_h + size_h * factor / 1000 + end + if size_h > 0 then + size_h = size_h * sx + size_v = size_v * sy + flushsimplerule(pos_h,pos_v,pos_r,size_h,size_v) + pos_h = pos_h + size_h + end + end + elseif command == "frame" then + -- d:width d:height d:depth d:rulethickness b:outline b:advance b:baseline s:color + local width = packet[2] + if width > 0 then + local height = packet[3] or 0 + local depth = packet[4] or 0 + local total = height + depth + if total > 0 then + if factor ~= 0 then + width = width + width * factor / 1000 end - if advance then - pos_h = pos_h + width + if width > 0 then + local line = packet[5] or default + local outline = not packet[6] + local advance = not packet[7] + local baseline = outline and packet[8] + local color = packet[9] -- no longer needed probably + if color then + vfinjectors.startcolor(pos_h,pos_v,color) -- takes packet or string + end + width = width * sx + height = height * sy + depth = depth * sy + flushspecialrule(pos_h,pos_v,pos_r,width,height,depth,line,outline,baseline) + if color then + vfinjectors.stopcolor() + end + if advance then + pos_h = pos_h + width + end end end end + elseif command == "font" then + local index = packet[2] + local okay = fonts and fonts[index] + if okay then + fnt = okay.id or fnt -- or maybe just return + end + elseif command == "lua" then + local code = packet[2] + local kind = type(code) + if kind ~= "function" then + code = loadstring(code) + kind = type(code) + end + if kind == "function" then + code(font,char,pos_h,pos_v,sx,sy) + end + elseif command == "node" then -- obsolete + local h = packet[2] + hlist_out(h,getlist(h)) + else + local injector = vfinjectors[command] + if injector then + injector(pos_h,pos_v,packet) + end end - elseif command == "font" then - local index = packet[2] - local okay = fonts and fonts[index] - if okay then - fnt = okay.id or fnt -- or maybe just return - end - elseif command == "lua" then - local code = packet[2] - local kind = type(code) - if kind ~= "function" then - code = loadstring(code) - kind = type(code) - end - if kind == "function" then - code(font,char,pos_h,pos_v,sx,sy) - end - elseif command == "node" then - -- us this really useful? - local h = packet[2] - hlist_out(h,getlist(h)) - elseif command == "pdf" then - -- this will disappear and become a plug - flushliteral(false,pos_h,pos_v,packet[2],packet[3]) - -- elseif command == "image" then - -- -- doesn't work because intercepted by engine so we use a different - -- -- mechanism (for now) - -- local image = packet[2] - -- -- to do - -- elseif command == "pdfmode" then - -- -- doesn't happen - -- elseif command == "special" then - -- -- not supported - -- elseif command == "nop" then - -- -- nothing to do| - -- elseif command == "scale" then - -- -- not supported + -- image : not needed, maybe some day + -- pdfmode : not used + -- special : makes no sense + -- nop : the official ignore + -- scale : not supported end - end - pos_h = saved_h - pos_v = saved_v - pos_r = saved_r + pos_h = saved_h + pos_v = saved_v + pos_r = saved_r - nesting = nesting - 1 -end + nesting = nesting - 1 + end -local onetimemessage -- could be defined later (todo: make plug for this) + local onetimemessage -- could be defined later (todo: make plug for this) -local getxyscales = nuts.getxyscales + local getxyscales = nuts.getxyscales -flush_character = function(current,font,char,factor,vfcommands,pos_h,pos_v,pos_r,f,e) + flush_character = function(current,font,char,factor,vfcommands,pos_h,pos_v,pos_r,f,e) - if font ~= lastfont then - lastfont = font - fontcharacters = characters[font] - updatefontstate(font) - end + if font ~= lastfont then + lastfont = font + fontcharacters = characters[font] + updatefontstate(font) + end - local data = fontcharacters[char] - if not data then - if char > 0 then - if not onetimemessage then - onetimemessage = fonts.loggers.onetimemessage + local data = fontcharacters[char] + if not data then + if char > 0 then + if not onetimemessage then + onetimemessage = fonts.loggers.onetimemessage + end + onetimemessage(font,char,"missing") end - onetimemessage(font,char,"missing") - end - return 0, 0, 0 - end - if vfcommands then - vfcommands = data.commands - end - local width, height, depth, naturalwidth, sx, sy - if current then - naturalwidth, height, depth, factor = getwhd(current,true) -- also get corrected width - sx, sy = getxyscales(current) -- maybe: getwhdfs - if factor == 0 then - width = naturalwidth - else - -- width = (1.0 + factor/1000000.0) * naturalwidth - width = naturalwidth + naturalwidth * factor/1000000.0 - -- width = naturalwidth + naturalwidth * 0.000001 * factor + return 0, 0, 0 end - else - width = data.width or 0 - height = data.height or 0 - depth = data.depth or 0 - naturalwidth = width - if not factor then - factor = 0 + if vfcommands then + vfcommands = data.commands end - sx = 1 - sy = 1 - end - if pos_r == righttoleft_code then - pos_h = pos_h - width -- here ? - end - if vfcommands then - flush_vf_packet(current,pos_h,pos_v,pos_r,font,char,data,factor,vfcommands,sx,sy) -- also f ? - else - -- kind of messy that we do orientation here and offsets elsewhere - local orientation = data.orientation - if orientation and (orientation == 1 or orientation == 3) then - local x = data.xoffset - local y = data.yoffset - if x then - pos_h = pos_h + x + local width, height, depth, naturalwidth, sx, sy + if current then + naturalwidth, height, depth, factor = getwhd(current,true) -- also get corrected width + sx, sy = getxyscales(current) -- maybe: getwhdfs + if factor == 0 then + width = naturalwidth + else + -- width = (1.0 + factor/1000000.0) * naturalwidth + width = naturalwidth + naturalwidth * factor/1000000.0 + -- width = naturalwidth + naturalwidth * 0.000001 * factor end - if y then - pos_v = pos_v + y + else + width = data.width or 0 + height = data.height or 0 + depth = data.depth or 0 + naturalwidth = width + if not factor then + factor = 0 end - pushorientation(orientation,pos_h,pos_v) - flushcharacter(current,pos_h,pos_v,pos_r,font,char,data,f,e,factor,sx,sy) -- ,naturalwidth,width) - poporientation(orientation,pos_h,pos_v) + sx = 1 + sy = 1 + end + if pos_r == righttoleft_code then + pos_h = pos_h - width -- here ? + end + if vfcommands then + flush_vf_packet(current,pos_h,pos_v,pos_r,font,char,data,factor,vfcommands,sx,sy) -- also f ? else - flushcharacter(current,pos_h,pos_v,pos_r,font,char,data,f,e,factor,sx,sy) -- ,naturalwidth,width) + -- kind of messy that we do orientation here and offsets elsewhere .. this might change + local orientation = data.orientation + if orientation and (orientation == 1 or orientation == 3) then + local x = data.xoffset + local y = data.yoffset + if x then + pos_h = pos_h + x + end + if y then + pos_v = pos_v + y + end + pushorientation(orientation,pos_h,pos_v) + flushcharacter(current,pos_h,pos_v,pos_r,font,char,data,f,e,factor,sx,sy) -- ,naturalwidth,width) + poporientation(orientation,pos_h,pos_v) + else + flushcharacter(current,pos_h,pos_v,pos_r,font,char,data,f,e,factor,sx,sy) -- ,naturalwidth,width) + end end + return width, height, depth end - return width, height, depth + end -- end of characters @@ -536,6 +533,13 @@ local function flushcloseout(current) end end +local function flushsavepos(current,pos_h,pos_v) + jobpositions.lastx = pos_h + jobpositions.lasty = pos_v +end + +local flushwhatsit + local hlist_out, vlist_out do local function applyanchor(orientation,x,y,width,height,depth,woffset,hoffset,doffset,xoffset,yoffset) @@ -905,26 +909,7 @@ local hlist_out, vlist_out do goto synced end elseif id == whatsit_code then - if subtype == literalwhatsit_code then - flushliteral(current,pos_h,pos_v) - elseif subtype == lateluawhatsit_code then - flushlatelua(current,pos_h,pos_v) - elseif subtype == setmatrixwhatsit_code then - flushsetmatrix(current,pos_h,pos_v) - elseif subtype == savewhatsit_code then - flushsave(current,pos_h,pos_v) - elseif subtype == restorewhatsit_code then - flushrestore(current,pos_h,pos_v) - elseif subtype == saveposwhatsit_code then - last_position_x = pos_h - last_position_y = pos_v - elseif subtype == writewhatsit_code then - flushwriteout(current) - elseif subtype == closewhatsit_code then - flushcloseout(current) - elseif subtype == openwhatsit_code then - flushopenout(current) - end + flushwhatsit[subtype](current,pos_h,pos_v) elseif id == disc_code then local replace, tail = getreplace(current) -- actually, we no longer have these select discs in the packaged list ... it's about @@ -1164,26 +1149,7 @@ local hlist_out, vlist_out do end cur_v = cur_v + total elseif id == whatsit_code then - if subtype == literalwhatsit_code then - flushliteral(current,pos_h,pos_v) - elseif subtype == lateluawhatsit_code then - flushlatelua(current,pos_h,pos_v) - elseif subtype == setmatrixwhatsit_code then - flushsetmatrix(current,pos_h,pos_v) - elseif subtype == savewhatsit_code then - flushsave(current,pos_h,pos_v) - elseif subtype == restorewhatsit_code then - flushrestore(current,pos_h,pos_v) - elseif subtype == saveposwhatsit_code then - last_position_x = pos_h - last_position_y = pos_v - elseif subtype == writewhatsit_code then - flushwriteout(current) - elseif subtype == closewhatsit_code then - flushcloseout(current) - elseif subtype == openwhatsit_code then - flushopenout(current) - end + flushwhatsit[subtype](current,pos_h,pos_v) else -- penalty goto synced @@ -1223,22 +1189,47 @@ function drivers.converters.lmtx(driver,box,smode,objnum,specification) initialize = actions.initialize finalize = actions.finalize - updatefontstate = flushers.updatefontstate - - pushorientation = flushers.pushorientation - poporientation = flushers.poporientation + -- we need to do this once ... + + if not updatefontstate then + + updatefontstate = flushers.updatefontstate + + pushorientation = flushers.pushorientation + poporientation = flushers.poporientation + + flushcharacter = flushers.character + flushfontchar = flushers.fontchar + flushrule = flushers.rule + flushsimplerule = flushers.simplerule + flushspecialrule = flushers.specialrule + flushliteral = flushers.literal + + flushwhatsit = setmetatableindex ( { + [whatsitcodes.literal] = flushliteral, + [whatsitcodes.latelua] = flushlatelua, + [whatsitcodes.userdefined] = function() end, -- special purpose, handled in callbacks + [whatsitcodes.savepos] = flushsavepos, -- only used by generic packages + [whatsitcodes.save] = flushers.save, + [whatsitcodes.restore] = flushers.restore, + [whatsitcodes.setmatrix] = flushers.setmatrix, + [whatsitcodes.open] = flushopenout, -- generic + [whatsitcodes.close] = flushcloseout, -- generic + [whatsitcodes.write] = flushwriteout, -- generic + [whatsitcodes.startmatrix] = flushers.startmatrix, + [whatsitcodes.stopmatrix] = flushers.stopmatrix, + [whatsitcodes.startscaling] = flushers.startscaling, + [whatsitcodes.stopscaling] = flushers.stopscaling, + [whatsitcodes.startrotation] = flushers.startrotation, + [whatsitcodes.stoprotation] = flushers.stoprotation, + [whatsitcodes.startmirroring] = flushers.startmirroring, + [whatsitcodes.stopmirroring] = flushers.stopmirroring, + [whatsitcodes.startclipping] = flushers.startclipping, + [whatsitcodes.stopclipping] = flushers.stopclipping, + [whatsitcodes.setstate] = flushers.setstate, + }, function(t, k) report("weird whatsit %a",k) return function() end end) - flushcharacter = flushers.character - flushfontchar = flushers.fontchar - flushrule = flushers.rule - flushsimplerule = flushers.simplerule - flushspecialrule = flushers.specialrule - flushspecial = flushers.special - flushliteral = flushers.literal - flushsetmatrix = flushers.setmatrix - flushsave = flushers.save - flushrestore = flushers.restore - -- flushimage = flushers.image + end reset_dir_stack() reset_state() @@ -1279,12 +1270,6 @@ function drivers.converters.lmtx(driver,box,smode,objnum,specification) local pagewidth, pageheight = getpagedimensions() - -- local h_offset_par = texget("hoffset") - -- local v_offset_par = texget("voffset") - - -- page_h_origin = trueinch - -- page_v_origin = trueinch - pos_r = lefttoright_code if pagewidth > 0 then @@ -1307,17 +1292,14 @@ function drivers.converters.lmtx(driver,box,smode,objnum,specification) page_size_v = total end - local refpoint_h = 0 -- + page_h_origin + h_offset_par - local refpoint_v = page_size_v -- - page_v_origin - v_offset_par + local refpoint_h = 0 + local refpoint_v = page_size_v pos_h = refpoint_h pos_v = refpoint_v - height - -- synced else - -- page_h_origin = 0 - -- page_v_origin = 0 page_size_h = width page_size_v = total pos_r = getdirection(box) diff --git a/tex/context/base/mkxl/font-chk.lmt b/tex/context/base/mkxl/font-chk.lmt index 7141be2c7..8e73d1b3c 100644 --- a/tex/context/base/mkxl/font-chk.lmt +++ b/tex/context/base/mkxl/font-chk.lmt @@ -64,7 +64,6 @@ local implement = interfaces.implement local glyph_code = nodes.nodecodes.glyph -local new_special = nodes.pool.special -- todo: literal local hpack_node = node.hpack local nuts = nodes.nuts diff --git a/tex/context/base/mkxl/font-con.lmt b/tex/context/base/mkxl/font-con.lmt index 88e17290a..60e3f0233 100644 --- a/tex/context/base/mkxl/font-con.lmt +++ b/tex/context/base/mkxl/font-con.lmt @@ -51,6 +51,8 @@ constructors.designsizes = designsizes local loadedfonts = allocate() constructors.loadedfonts = loadedfonts +----- scalecommands = fonts.helpers.scalecommands + --[[ldx-- <p>We need to normalize the scale factor (in scaled points). This has to do with the fact that <l n='tex'/> uses a negative multiple of 1000 as @@ -260,6 +262,8 @@ function constructors.scale(tfmdata,specification) end target.specification = specification -- + local scalecommands = fonts.helpers.scalecommands -- defined later + -- local scaledpoints = specification.size local relativeid = specification.relativeid -- @@ -774,37 +778,7 @@ function constructors.scale(tfmdata,specification) end local vc = character.commands if vc then - -- we assume non scaled commands here - -- tricky .. we need to scale pseudo math glyphs too - -- which is why we deal with rules too - local ok = false - for i=1,#vc do - local key = vc[i][1] - if key == "right" or key == "down" or key == "rule" then - ok = true - break - end - end - if ok then - local tt = { } - for i=1,#vc do - local ivc = vc[i] - local key = ivc[1] - if key == "right" then - tt[i] = { key, ivc[2]*hdelta } - elseif key == "down" then - tt[i] = { key, ivc[2]*vdelta } - elseif key == "rule" then - tt[i] = { key, ivc[2]*vdelta, ivc[3]*hdelta } - else -- not comment - tt[i] = ivc -- shared since in cache and untouched - end - end - chr.commands = tt - else - chr.commands = vc - end - -- chr.index = nil + chr.commands = scalecommands(vc,hdelta,vdelta) end targetcharacters[unicode] = chr end diff --git a/tex/context/base/mkxl/font-fbk.lmt b/tex/context/base/mkxl/font-fbk.lmt index 651bca331..47d284c84 100644 --- a/tex/context/base/mkxl/font-fbk.lmt +++ b/tex/context/base/mkxl/font-fbk.lmt @@ -63,13 +63,12 @@ local function composecharacters(tfmdata) local deltaxheight = scale * (Xdesc.boundingbox[4] - xdesc.boundingbox[4]) local extraxheight = fraction * deltaxheight -- maybe use compose value local italicfactor = parameters.italicfactor or 0 - local vfspecials = backends.tables.vfspecials --brr local red, green, blue, black if trace_visualize then - red = vfspecials.startcolor("red") - green = vfspecials.startcolor("green") - blue = vfspecials.startcolor("blue") - black = vfspecials.stopcolor + red = { "startcolor", "red" } + green = { "startcolor", "green" } + blue = { "startcolor", "blue" } + black = { "stopcolor" } end local compose = fonts.goodies.getcompositions(tfmdata) if compose and trace_visualize then diff --git a/tex/context/base/mkxl/font-imp-math.lmt b/tex/context/base/mkxl/font-imp-math.lmt index 079c867e2..277190f24 100644 --- a/tex/context/base/mkxl/font-imp-math.lmt +++ b/tex/context/base/mkxl/font-imp-math.lmt @@ -70,6 +70,35 @@ registerotffeature { -- A quick and dirty and low level implementation but okay for testing: +function fonts.helpers.mathscriptslots(tfmdata,textcode) + local rawdata = tfmdata.shared.rawdata + local rawresources = rawdata and rawdata.resources + local rawfeatures = rawresources and rawresources.features + local basesubstitutions = rawfeatures and rawfeatures.gsub + local sequences = basesubstitutions and tfmdata.resources.sequences + if sequences then + local characters = tfmdata.characters + if characters[textcode] then + for s=1,#sequences do + local sequence = sequences[s] + local sfeatures = sequence.features + if sfeatures and sfeatures.ssty then + local steps = sequence.steps + for i=1,#steps do + local coverage = steps[i].coverage + if coverage then + local okay = coverage[textcode] + if okay then + return okay + end + end + end + end + end + end + end +end + local function manipulate(tfmdata,key,value) if texconditionals["c_font_compact"] then local rawdata = tfmdata.shared.rawdata @@ -81,7 +110,7 @@ local function manipulate(tfmdata,key,value) if sequences then local characters = tfmdata.characters for s=1,#sequences do - local sequence = sequences[s] + local sequence = sequences[s] local sfeatures = sequence.features if sfeatures and sfeatures.ssty then local steps = sequence.steps diff --git a/tex/context/base/mkxl/font-imp-tracing.lmt b/tex/context/base/mkxl/font-imp-tracing.lmt new file mode 100644 index 000000000..59603c9dd --- /dev/null +++ b/tex/context/base/mkxl/font-imp-tracing.lmt @@ -0,0 +1,286 @@ +if not modules then modules = { } end modules ['font-imp-tracing'] = { + version = 1.001, + comment = "companion to font-ini.mkiv and hand-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local abs = math.abs + +local next, type = next, type +local concat = table.concat +local formatters = string.formatters + +local fonts = fonts + +local handlers = fonts.handlers +local registerotffeature = handlers.otf.features.register +local registerafmfeature = handlers.afm.features.register + +local settings_to_array = utilities.parsers.settings_to_array +local setmetatableindex = table.setmetatableindex + +local helpers = fonts.helpers +local appendcommandtable = helpers.appendcommandtable +local prependcommands = helpers.prependcommands +local charcommand = helpers.commands.char + +local variables = interfaces.variables + +local v_background = variables.background +local v_frame = variables.frame +local v_empty = variables.empty +local v_none = variables.none + +local function initialize(tfmdata,key,value) + if value then + local vfspecials = fonts.helpers.vfspecials + local vfcommands = fonts.helpers.commands + local backgrounds = vfspecials.backgrounds + local outlines = vfspecials.outlines + local characters = tfmdata.characters + local rulecache = backgrounds + local showchar = true + local color = "palegray" + if type(value) == "string" then + value = settings_to_array(value) + for i=1,#value do + local v = value[i] + if v == v_frame then + rulecache = outlines + elseif v == v_background then + rulecache = backgrounds + elseif v == v_empty then + showchar = false + elseif v == v_none then + color = nil + else + color = v + end + end + end + local gray = color and { "startcolor", color } or nil + local black = gray and { "stopcolor" } or nil + for unicode, character in next, characters do + local width = character.width or 0 + local height = character.height or 0 + local depth = character.depth or 0 + local rule = rulecache[height][depth][width] + if showchar then + local commands = character.commands + if commands then + if gray then + character.commands = prependcommands ( + commands, gray, rule, black + ) + else + character.commands = prependcommands ( + commands, rule + ) + end + else + local char = charcommand[unicode] + if gray then + character.commands = { + gray, rule, black, char + } + else + character.commands = { + rule, char + } + end + end + else + if gray then + character.commands = { + gray, rule, black + } + else + character.commands = { + rule + } + end + end + end + end +end + +local specification = { + name = "boundingbox", + description = "show boundingbox", + manipulators = { + base = initialize, + node = initialize, + } +} + +registerotffeature(specification) +registerafmfeature(specification) + +local function initialize(tfmdata,key,value) + if value then + local rawdata = tfmdata.shared.rawdata + local rawresources = rawdata and rawdata.resources + local mathconstants = rawresources.mathconstants + if mathconstants then + local vfspecials = fonts.helpers.vfspecials + local vfcommands = fonts.helpers.commands + local backgrounds = vfspecials.backgrounds + local outlines = vfspecials.outlines + local characters = tfmdata.characters + local rulecache = backgrounds + local push = vfcommands.push + local pop = vfcommands.pop + local black = { "stopcolor" } + local itcolor = { "startcolor", "trace:0" } -- s / dd (transparent) + local brcolor = { "startcolor", "trace:1" } -- r / dr + local trcolor = { "startcolor", "trace:2" } -- g / dg + local blcolor = { "startcolor", "trace:3" } -- b / db + local tlcolor = { "startcolor", "trace:4" } -- y / dy + for unicode, character in next, characters do + local mathkern = character.mathkern + local italic = character.vert_italic or character.italic + if mathkern or (italic and italic ~= 0) then + local width = character.width or 0 + local height = character.height or 0 + local depth = character.depth or 0 + local list = { } + local count = 0 + if italic and italic ~= 0 then + count = count + 1 list[count] = itcolor + count = count + 1 list[count] = push + count = count + 1 list[count] = { "offset", width + (italic < 0 and -italic or 0), 0 } + count = count + 1 list[count] = rulecache[height][depth][abs(-italic)] + count = count + 1 list[count] = pop + count = count + 1 list[count] = black + end + if mathkern then + local br = mathkern.bottom_right + local tr = mathkern.top_right + local bl = mathkern.bottom_left + local tl = mathkern.top_left + if br then + local done = false + for i=1,#br do + local l = br[i] + local h = l.height or 0 + local k = l.kern or 0 + if k ~= 0 then + if h == 0 then + h = height + depth -- todo max + end + if not done then + count = count + 1 list[count] = brcolor + done = true + end + count = count + 1 list[count] = push + count = count + 1 list[count] = { "offset", width + (k < 0 and k or 0), - depth } + count = count + 1 list[count] = rulecache[h][0][abs(k)] + count = count + 1 list[count] = pop + end + end + if done then + count = count + 1 list[count] = black + end + end + if tr then + local done = false + for i=1,#tr do + local l = tr[i] + local h = l.height or 0 + local k = l.kern or 0 + if k ~= 0 then + if h == 0 then + h = height + depth -- todo max + end + if not done then + count = count + 1 list[count] = trcolor + done = true + end + count = count + 1 list[count] = push + count = count + 1 list[count] = { "offset", width + (k < 0 and k or 0), height - h } + count = count + 1 list[count] = rulecache[h][0][abs(k)] + count = count + 1 list[count] = pop + end + end + if done then + count = count + 1 list[count] = black + end + end + if bl then + local done = false + for i=1,#bl do + local l = bl[i] + local h = l.height or 0 + local k = l.kern or 0 + if k ~= 0 then + if h == 0 then + h = height + depth -- todo max + end + if not done then + count = count + 1 list[count] = blcolor + done = true + end + count = count + 1 list[count] = push + count = count + 1 list[count] = { "offset", (k < 0 and k or 0), -depth } + count = count + 1 list[count] = rulecache[h][0][abs(k)] + count = count + 1 list[count] = pop + end + end + if done then + count = count + 1 list[count] = black + end + end + if tl then + local done = false + for i=1,#tl do + local l = tl[i] + local h = l.height or 0 + local k = l.kern or 0 + if k ~= 0 then + if h == 0 then + h = height + depth -- todo max + end + if not done then + count = count + 1 list[count] = tlcolor + done = true + end + count = count + 1 list[count] = push + count = count + 1 list[count] = { "offset", (k < 0 and k or 0), height - h } + count = count + 1 list[count] = rulecache[h][0][abs(k)] + count = count + 1 list[count] = pop + end + end + if done then + count = count + 1 list[count] = black + end + end + end + if count > 0 then + local commands = character.commands + if commands then + character.commands = appendcommandtable(commands,list) + else + list[#list+1] = charcommand[unicode] + character.commands = list + end + end + end + end + end + end +end + +local specification = { + name = "staircase", + description = "show staircase kerns", +-- position = 1, + manipulators = { + base = initialize, + node = initialize, + } +} + +registerotffeature(specification) +registerafmfeature(specification) diff --git a/tex/context/base/mkxl/font-lib.mklx b/tex/context/base/mkxl/font-lib.mklx index 00bddc2c3..e90973d75 100644 --- a/tex/context/base/mkxl/font-lib.mklx +++ b/tex/context/base/mkxl/font-lib.mklx @@ -17,7 +17,7 @@ \registerctxluafile{font-ini}{autosuffix} \registerctxluafile{font-log}{} -\registerctxluafile{font-con}{autosuffix} +\registerctxluafile{font-con}{autosuffix} % kind of early %registerctxluafile{font-cft}{} \registerctxluafile{font-enc}{} \registerctxluafile{font-fmp}{autosuffix} @@ -88,7 +88,7 @@ \registerctxluafile{good-ini}{} \registerctxluafile{good-gen}{} \registerctxluafile{good-ctx}{} -\registerctxluafile{good-mth}{} +\registerctxluafile{good-mth}{autosuffix} \registerctxluafile{font-def}{autosuffix} \registerctxluafile{font-ctx}{autosuffix} % after def as it overloads @@ -116,7 +116,7 @@ % not yet, lmtx feature } -\registerctxluafile{font-imp-tracing}{} % comes last! +\registerctxluafile{font-imp-tracing}{autosuffix} % comes last! \registerctxluafile{font-fbk}{autosuffix} diff --git a/tex/context/base/mkxl/font-ogr.lmt b/tex/context/base/mkxl/font-ogr.lmt index df6449ded..a3f8acb3c 100644 --- a/tex/context/base/mkxl/font-ogr.lmt +++ b/tex/context/base/mkxl/font-ogr.lmt @@ -242,6 +242,8 @@ do -- this will move to its own module return false end + -- list of tonumber keywords + local function initializemps(tfmdata,kind,value) if value then local specification = settings_to_hash_strict(value) @@ -256,9 +258,20 @@ do -- this will move to its own module local categories = settings_to_array(category) local usedshapes = nil local index = 0 - local spread = tonumber(specification.spread or 0) + local spread = tonumber(specification.spread or 0) -- hm local hascolor = hascolorspec(specification) - specification.spread = spread -- now a number + + specification.spread = spread -- now a number, maybe also for slant, weight etc + + local preroll = specification.preroll + if preroll then + metapost.simple(instance,"begingroup;",true,true) + metapost.setparameterset("mpsfont",specification) + metapost.simple("simplefun",preroll) + metapost.setparameterset("mpsfont") + metapost.simple(instance,"endgroup;",true,true) + end + for i=1,#categories do local category = categories[i] local mpsshapes = shapes[category] @@ -291,25 +304,39 @@ do -- this will move to its own module } -- todo: deal with extensibles and more properties for unicode, shape in sortedhash(mpsshapes.glyphs) do - -- local oldc = characters[unicode] - -- if oldc then - index = index + 1 -- todo: somehow we end up with 2 as first entry after 0 - local wd = shape.width or defaultwidth - local ht = shape.height or defaultheight - local dp = shape.depth or defaultdepth - local newc = { - index = index, -- into usedshapes - width = scale * (wd + spread), - height = scale * ht, - depth = scale * dp, - unicode = unicode, - } - -- - characters [unicode] = newc - descriptions[unicode] = newc - -- - usedshapes[unicode] = shape.code or defaultcode - -- end + index = index + 1 -- todo: somehow we end up with 2 as first entry after 0 + local wd = shape.width or defaultwidth + local ht = shape.height or defaultheight + local dp = shape.depth or defaultdepth + local uc = shape.tounicode + if uc then + uc = round(uc) -- brrr can be 123.0 + end + local newc = { + index = index, -- into usedshapes + width = scale * (wd + spread), + height = scale * ht, + depth = scale * dp, + unicode = uc or unicode, + } + -- + characters [unicode] = newc + descriptions[unicode] = newc + usedshapes [unicode] = shape.code or defaultcode + -- + -- This is a way to get/use randomized shapes (see punk example). + -- + if uc and uc ~= unicode then + local c = characters[uc] + if c then + local v = c.variants + if v then + v[#v + 1] = unicode + else + c.variants = { unicode } + end + end + end end end end diff --git a/tex/context/base/mkxl/font-pre.mkxl b/tex/context/base/mkxl/font-pre.mkxl index fafe20a60..884a6c913 100644 --- a/tex/context/base/mkxl/font-pre.mkxl +++ b/tex/context/base/mkxl/font-pre.mkxl @@ -405,7 +405,9 @@ mathalternates=yes, mathitalics=yes, % we pass them mathdimensions=all, -compactmath=yes, + % mathkerns=yes, + % staircase=yes, + compactmath=yes, % mathgaps=yes, language=dflt, script=math] diff --git a/tex/context/base/mkxl/font-vfc.lmt b/tex/context/base/mkxl/font-vfc.lmt index e39eca683..9330bdea0 100644 --- a/tex/context/base/mkxl/font-vfc.lmt +++ b/tex/context/base/mkxl/font-vfc.lmt @@ -71,13 +71,111 @@ function helpers.appendcommandtable(commands,t) end helpers.commands = utilities.storage.allocate { - char = setmetatableindex(function(t,k) local v = { "slot", 0, k } t[k] = v return v end), - right = setmetatableindex(function(t,k) local v = { "right", k } t[k] = v return v end), - left = setmetatableindex(function(t,k) local v = { "right", -k } t[k] = v return v end), -- todo: left - down = setmetatableindex(function(t,k) local v = { "down", k } t[k] = v return v end), - up = setmetatableindex(function(t,k) local v = { "down", -k } t[k] = v return v end), -- todo: up + char = setmetatableindex(function(t,k) local v = { "slot", 0, k } t[k] = v return v end), + right = setmetatableindex(function(t,k) local v = { "right", k } t[k] = v return v end), + left = setmetatableindex(function(t,k) local v = { "left", k } t[k] = v return v end), + down = setmetatableindex(function(t,k) local v = { "down", k } t[k] = v return v end), + up = setmetatableindex(function(t,k) local v = { "up", k } t[k] = v return v end), push = push, pop = pop, dummy = dummy, } +helpers.vfinjectors = { + -- backend specific: startcolor, stopcolor etc +} + +-- maybe round() + +local defaultline = 16384 + +helpers.vfspecials = { + + backgrounds = setmetatableindex(function(t,h) + local v = setmetatableindex(function(t,d) + local v = setmetatableindex(function(t,w) + local v = { "frame", w, h, d, defaultline, true, true } + t[w] = v + return v + end) + t[d] = v + return v + end) + t[h] = v + return v + end), + + outlines = setmetatableindex(function(t,h) + local v = setmetatableindex(function(t,d) + local v = setmetatableindex(function(t,w) + local v = { "frame", w, h, d, defaultline, false, true } + t[w] = v + return v + end) + t[d] = v + return v + end) + t[h] = v + return v + end), + +} + +-- In the past we only copied when we had something that got scaled but the problem +-- is that we then run into issues when we extend a commands in the parent. This +-- needs checking. When we go to glyph scaling, this can go away. +-- +-- The alternative is to work with unscaled values and always do scaling at the +-- TeX end. So, then we need accessors instead of tables and we also need to check +-- all the context code: where do we access values? +-- +-- On the other hand, in glyph scale mode we hardly do any scaling so we seldom +-- call the next one. +-- +-- What if we use named fields: then we can scale by field name. + +local scaled = { + right = true, + down = true, + left = true, + right = true, + offset = true, + rule = true, + char = false, + font = false, + slot = false, + use = false, + push = false, + pop = false, + lua = false, + -- obsolete + node = false, + -- additional ones are never scaled (color etc) +} + +function helpers.scalecommands(list,hdelta,vdelta) + local n = #list + for i=1,n do + local key = list[i][1] + if scaled[list[i][1]] then + local result = { } + for i=1,n do + local cmd = list[i] + local key = ivc[1] + if key == "right" or key == "left" then + result[i] = { key, cmd[2]*hdelta } + elseif key == "down" or key == "up" then + result[i] = { key, cmd[2]*vdelta } + elseif key == "offset" or key == "rule" then + result[i] = { key, cmd[2]*hdelta, cmd[3]*vdelta } + -- elseif key == "frame" then + -- result[i] = cmd -- already scaled, for now + else + result[i] = cmd -- shared since in cache and untouched + end + end + return result + end + end + return list +end diff --git a/tex/context/base/mkxl/good-mth.lmt b/tex/context/base/mkxl/good-mth.lmt new file mode 100644 index 000000000..87b6787df --- /dev/null +++ b/tex/context/base/mkxl/good-mth.lmt @@ -0,0 +1,464 @@ +if not modules then modules = { } end modules ['good-mth'] = { + version = 1.000, + comment = "companion to font-lib.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local type, next, tonumber, unpack = type, next, tonumber, unpack +local ceil = math.ceil +local match = string.match + +local fonts = fonts + +local trace_goodies = false trackers.register("fonts.goodies", function(v) trace_goodies = v end) +local report_goodies = logs.reporter("fonts","goodies") + +local registerotffeature = fonts.handlers.otf.features.register + +local fontgoodies = fonts.goodies or { } + +local fontcharacters = fonts.hashes.characters + +local trace_defining = false trackers.register("math.defining", function(v) trace_defining = v end) + +local report_math = logs.reporter("mathematics","initializing") + +local nuts = nodes.nuts + +local setlink = nuts.setlink + +local nodepool = nuts.pool + +local new_kern = nodepool.kern +local new_glyph = nodepool.glyph +local new_hlist = nodepool.hlist +local new_vlist = nodepool.vlist + +local insert_node_after = nuts.insert_after + +local helpers = fonts.helpers +local upcommand = helpers.commands.up +local rightcommand = helpers.commands.right +local charcommand = helpers.commands.char +local prependcommands = helpers.prependcommands + +-- experiment, we have to load the definitions immediately as they precede +-- the definition so they need to be initialized in the typescript + +local function withscriptcode(tfmdata,unicode,data,action) + if type(unicode) == "string" then + local p, u = match(unicode,"^(.-):(.-)$") + if u then + u = tonumber(u) + if u then + local slots = fonts.helpers.mathscriptslots(tfmdata,u) + if slots then + if p == "*" then + action(u,data) + for i=1,#slots do + action(slots[i],data) + end + else + p = tonumber(p) + if p then + action(slots[p],data) + end + end + end + end + end + else + action(unicode,data) + end +end + +local function finalize(tfmdata,feature,value) +-- if tfmdata.mathparameters then -- funny, cambria text has this + local goodies = tfmdata.goodies + if goodies then + local virtualized = mathematics.virtualized + for i=1,#goodies do + local goodie = goodies[i] + local mathematics = goodie.mathematics + local dimensions = mathematics and mathematics.dimensions + if dimensions then + if trace_defining then + report_math("overloading dimensions in %a @ %p",tfmdata.properties.fullname,tfmdata.parameters.size) + end + local characters = tfmdata.characters + local descriptions = tfmdata.descriptions + local parameters = tfmdata.parameters + local factor = parameters.factor + local hfactor = parameters.hfactor + local vfactor = parameters.vfactor + -- + tfmdata.type = "virtual" + tfmdata.properties.virtualized = true + -- + local function overloadone(unicode,data) + local character = characters[unicode] + if not character then + local c = virtualized[unicode] + if c then + character = characters[c] + end + end + if character then + local width = data.width + local height = data.height + local depth = data.depth + if trace_defining and (width or height or depth) then + report_math("overloading dimensions of %C, width %p, height %p, depth %p", + unicode,width or 0,height or 0,depth or 0) + end + if width then character.width = width * hfactor end + if height then character.height = height * vfactor end + if depth then character.depth = depth * vfactor end + -- + local xoffset = data.xoffset + local yoffset = data.yoffset + if xoffset == "llx" then + local d = descriptions[unicode] + if d then + xoffset = - d.boundingbox[1] * hfactor + character.width = character.width + xoffset + xoffset = rightcommand[xoffset] + else + xoffset = nil + end + elseif xoffset and xoffset ~= 0 then + xoffset = rightcommand[xoffset * hfactor] + else + xoffset = nil + end + if yoffset and yoffset ~= 0 then + yoffset = upcommand[yoffset * vfactor] + else + yoffset = nil + end + if xoffset or yoffset then + local commands = characters.commands + if commands then + prependcommands(commands,yoffset,xoffset) + else + local slot = charcommand[unicode] + if xoffset and yoffset then + character.commands = { xoffset, yoffset, slot } + elseif xoffset then + character.commands = { xoffset, slot } + else + character.commands = { yoffset, slot } + end + end + end + elseif trace_defining then + report_math("no overloading dimensions of %C, not in font",unicode) + end + end + local function overload(dimensions) + for unicode, data in next, dimensions do + withscriptcode(tfmdata,unicode,data,overloadone) + end + end + if value == nil then + value = { "default" } + end + if value == "all" or value == true then + for name, value in next, dimensions do + overload(value) + end + else + if type(value) == "string" then + value = utilities.parsers.settings_to_array(value) + end + if type(value) == "table" then + for i=1,#value do + local d = dimensions[value[i]] + if d then + overload(d) + end + end + end + end + end + end + end +end + +registerotffeature { + name = "mathdimensions", + description = "manipulate math dimensions", + -- default = true, + manipulators = { + base = finalize, + node = finalize, + } +} + +local function initialize(goodies) + local mathgoodies = goodies.mathematics + if mathgoodies then + local virtuals = mathgoodies.virtuals + local mapfiles = mathgoodies.mapfiles + local maplines = mathgoodies.maplines + if virtuals then + for name, specification in next, virtuals do + -- beware, they are all constructed ... we should be more selective + mathematics.makefont(name,specification,goodies) + end + end + if mapfiles then + for i=1,#mapfiles do + fonts.mappings.loadfile(mapfiles[i]) -- todo: backend function + end + end + if maplines then + for i=1,#maplines do + fonts.mappings.loadline(maplines[i]) -- todo: backend function + end + end + end +end + +fontgoodies.register("mathematics", initialize) + +-- local enabled = false directives.register("fontgoodies.mathkerning",function(v) enabled = v end) + +local function initialize(tfmdata) +-- if enabled and tfmdata.mathparameters then -- funny, cambria text has this + if tfmdata.mathparameters then -- funny, cambria text has this + local goodies = tfmdata.goodies + if goodies then + local characters = tfmdata.characters + if characters[0x1D44E] then -- 119886 + -- we have at least an italic a + for i=1,#goodies do + local mathgoodies = goodies[i].mathematics + if mathgoodies then + local kerns = mathgoodies.kerns + if kerns then + local function kernone(unicode,data) + local chardata = characters[unicode] + if chardata and (not chardata.mathkerns or data.force) then + chardata.mathkerns = data + end + end + for unicode, data in next, kerns do + withscriptcode(tfmdata,unicode,data,kernone) + end + return + end + end + end + else + return -- no proper math font anyway + end + end + end +end + +registerotffeature { + name = "mathkerns", + description = "math kerns", + -- default = true, + initializers = { + base = initialize, + node = initialize, + } +} + +-- math italics (not really needed) +-- +-- it would be nice to have a \noitalics\font option + +local function initialize(tfmdata) + local goodies = tfmdata.goodies + if goodies then + local shared = tfmdata.shared + for i=1,#goodies do + local mathgoodies = goodies[i].mathematics + if mathgoodies then + local mathitalics = mathgoodies.italics + if mathitalics then + local properties = tfmdata.properties + if properties.setitalics then + mathitalics = mathitalics[file.nameonly(properties.name)] or mathitalics + if mathitalics then + if trace_goodies then + report_goodies("loading mathitalics for font %a",properties.name) + end + local corrections = mathitalics.corrections + local defaultfactor = mathitalics.defaultfactor + -- properties.mathitalic_defaultfactor = defaultfactor -- we inherit outer one anyway (name will change) + if corrections then + fontgoodies.registerpostprocessor(tfmdata, function(tfmdata) -- this is another tfmdata (a copy) + -- better make a helper so that we have less code being defined + local properties = tfmdata.properties + local parameters = tfmdata.parameters + local characters = tfmdata.characters + properties.mathitalic_defaultfactor = defaultfactor + properties.mathitalic_defaultvalue = defaultfactor * parameters.quad + if trace_goodies then + report_goodies("assigning mathitalics for font %a",properties.name) + end + local quad = parameters.quad + local hfactor = parameters.hfactor + for k, v in next, corrections do + local c = characters[k] + if c then + if v > -1 and v < 1 then + c.italic = v * quad + else + c.italic = v * hfactor + end + else + report_goodies("invalid mathitalics entry %U for font %a",k,properties.name) + end + end + end) + end + return -- maybe not as these can accumulate + end + end + end + end + end + end +end + +registerotffeature { + name = "mathitalics", + description = "additional math italic corrections", + -- default = true, + initializers = { + base = initialize, + node = initialize, + } +} + +-- fontgoodies.register("mathitalics", initialize) + +local function mathradicalaction(n,h,v,font,mchar,echar) + local characters = fontcharacters[font] + local mchardata = characters[mchar] + local echardata = characters[echar] + local ewidth = echardata.width + local mwidth = mchardata.width + local delta = h - ewidth + local glyph = new_glyph(font,echar) + local head = glyph + if delta > 0 then + local count = ceil(delta/mwidth) + local kern = (delta - count * mwidth) / count + for i=1,count do + local k = new_kern(kern) + local g = new_glyph(font,mchar) + setlink(k,head) + setlink(g,k) + head = g + end + end + local height = mchardata.height + local list = new_hlist(head) + local kern = new_kern(height-v) + list = setlink(kern,list) + local list = new_vlist(kern) + insert_node_after(n,n,list) +end + +local function mathhruleaction(n,h,v,font,bchar,mchar,echar) + local characters = fontcharacters[font] + local bchardata = characters[bchar] + local mchardata = characters[mchar] + local echardata = characters[echar] + local bwidth = bchardata.width + local mwidth = mchardata.width + local ewidth = echardata.width + local delta = h - ewidth - bwidth + local glyph = new_glyph(font,echar) + local head = glyph + if delta > 0 then + local count = ceil(delta/mwidth) + local kern = (delta - count * mwidth) / (count+1) + for i=1,count do + local k = new_kern(kern) + local g = new_glyph(font,mchar) + setlink(k,head) + setlink(g,k) + head = g + end + local k = new_kern(kern) + setlink(k,head) + head = k + end + local g = new_glyph(font,bchar) + setlink(g,head) + head = g + local height = mchardata.height + local list = new_hlist(head) + local kern = new_kern(height-v) + list = setlink(kern,list) + local list = new_vlist(kern) + insert_node_after(n,n,list) +end + +local function initialize(tfmdata) + local goodies = tfmdata.goodies + if goodies then + local resources = tfmdata.resources + local ruledata = { } + for i=1,#goodies do + local mathematics = goodies[i].mathematics + if mathematics then + local rules = mathematics.rules + if rules then + for tag, name in next, rules do + ruledata[tag] = name + end + end + end + end + if next(ruledata) then + local characters = tfmdata.characters + local unicodes = resources.unicodes + if characters and unicodes then + local mathruleactions = resources.mathruleactions + if not mathruleactions then + mathruleactions = { } + resources.mathruleactions = mathruleactions + end + -- + local mchar = unicodes[ruledata["radical.extender"] or false] + local echar = unicodes[ruledata["radical.end"] or false] + if mchar and echar then + mathruleactions.radicalaction = function(n,h,v,font) + mathradicalaction(n,h,v,font,mchar,echar) + end + end + -- + local bchar = unicodes[ruledata["hrule.begin"] or false] + local mchar = unicodes[ruledata["hrule.extender"] or false] + local echar = unicodes[ruledata["hrule.end"] or false] + if bchar and mchar and echar then + mathruleactions.hruleaction = function(n,h,v,font) + mathhruleaction(n,h,v,font,bchar,mchar,echar) + end + end + -- not that nice but we need to register it at the tex end + -- context.enablemathrules("\\fontclass") + end + end + end +end + +registerotffeature { + name = "mathrules", + description = "check math rules", + default = true, + initializers = { + base = initialize, + node = initialize, + } +} diff --git a/tex/context/base/mkxl/layo-ini.lmt b/tex/context/base/mkxl/layo-ini.lmt new file mode 100644 index 000000000..1570075d9 --- /dev/null +++ b/tex/context/base/mkxl/layo-ini.lmt @@ -0,0 +1,115 @@ +if not modules then modules = { } end modules ['layo-ini'] = { + version = 1.001, + comment = "companion to layo-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- We need to share information between the TeX and Lua end about the typographical +-- model. This happens here. This code might move. + +local texgetcount = tex.getcount +local conditionals = tex.conditionals + +layouts = { + status = { }, +} + +local status = layouts.status + +function status.leftorrightpageaction(left,right) + if left == nil then + left, right = false, true + end + if not conditionals.layoutisdoublesided then + return left, right + elseif conditionals.layoutissinglesided then + return left, right + elseif texgetcount("pagenoshift") % 2 == 0 then + if texgetcount("realpageno") % 2 == 0 then + return right, left + else + return left, right + end + else + if texgetcount("realpageno") % 2 == 0 then + return left, right + else + return right, left + end + end +end + +function status.isleftpage(r) + if not conditionals.layoutisdoublesided then + return false + elseif conditionals.layoutissinglesided then + return false + elseif texgetcount("pagenoshift") % 2 == 0 then + return (r or texgetcount("realpageno")) % 2 == 0 + else + return not (r or texgetcount("realpageno")) % 2 == 0 + end +end + +-- Instead of making these these driver specific we make them generic. We can even consider +-- to make these registers at the tex end. + +local canvas = { + pagespec = "default", -- v_default + paperwidth = 0, + paperheight = 0, + topoffset = 0, + leftoffset = 0, + height = 0, + width = 0, + cropoffset = 0, + bleedoffset = 0, + trimoffset = 0, + artoffset = 0, + doublesided = false, + marked = false, + copies = false, +} + +function layouts.setupcanvas(specification) + local paperheight = specification.paperheight or canvas.paperheight + local paperwidth = specification.paperwidth or canvas.paperwidth + local cropoffset = specification.cropoffset or 0 + local trimoffset = cropoffset - (specification.trimoffset or 0) + local bleedoffset = trimoffset - (specification.bleedoffset or 0) + local artoffset = bleedoffset - (specification.artoffset or 0) + -- + canvas.paperheight = paperheight + canvas.paperwidth = paperwidth + canvas.cropoffset = cropoffset + canvas.trimoffset = trimoffset + canvas.bleedoffset = bleedoffset + canvas.artoffset = artoffset + -- + canvas.pagespec = specification.mode or pagespec + canvas.topoffset = specification.topoffset or 0 + canvas.leftoffset = specification.leftoffset or 0 + canvas.height = specification.height or paperheight + canvas.width = specification.width or paperwidth + canvas.marked = specification.print + -- + local copies = specification.copies + if type(copies) == "number" and copies < 2 then + canvas.copies = false + end + -- + local doublesided = specification.doublesided + if doublesided ~= nil then + canvas.doublesided = doublesided + end +end + +function layouts.getpagedimensions() + return canvas.paperwidth, canvas.paperheight +end + +function layouts.getcanvas() + return canvas +end diff --git a/tex/context/base/mkxl/layo-ini.mkxl b/tex/context/base/mkxl/layo-ini.mkxl index 4979989cd..73b7e978e 100644 --- a/tex/context/base/mkxl/layo-ini.mkxl +++ b/tex/context/base/mkxl/layo-ini.mkxl @@ -25,6 +25,6 @@ \ifdefined\pagenoshift \else \newcount \pagenoshift \fi \ifdefined\realpageno \else \newcount \realpageno \fi -\registerctxluafile{layo-ini}{} +\registerctxluafile{layo-ini}{autosuffix} \protect \endinput diff --git a/tex/context/base/mkxl/lpdf-col.lmt b/tex/context/base/mkxl/lpdf-col.lmt index 778d250c6..a999cb2c7 100644 --- a/tex/context/base/mkxl/lpdf-col.lmt +++ b/tex/context/base/mkxl/lpdf-col.lmt @@ -6,8 +6,6 @@ if not modules then modules = { } end modules ['lpdf-col'] = { license = "see context related readme files" } --- slants also page ? - local type, next, tostring, tonumber = type, next, tostring, tonumber local char, byte, format, gsub, rep, gmatch = string.char, string.byte, string.format, string.gsub, string.rep, string.gmatch local settings_to_array, settings_to_numbers = utilities.parsers.settings_to_array, utilities.parsers.settings_to_numbers @@ -25,7 +23,7 @@ local registrations = backends.pdf.registrations local nodepool = nodes.nuts.pool local register = nodepool.register -local pageliteral = nodepool.pageliteral +local setstate = nodepool.setstate local pdfconstant = lpdf.constant local pdfdictionary = lpdf.dictionary @@ -131,26 +129,26 @@ lpdf.registerpagefinalizer(addpagegroup,3,"pagegroup") -- color injection function nodeinjections.rgbcolor(r,g,b) - return register(pageliteral(f_rgb(r,g,b,r,g,b))) + return register(setstate(f_rgb(r,g,b,r,g,b))) end function nodeinjections.cmykcolor(c,m,y,k) - return register(pageliteral(f_cmyk(c,m,y,k,c,m,y,k))) + return register(setstate(f_cmyk(c,m,y,k,c,m,y,k))) end function nodeinjections.graycolor(s) -- caching 0/1 does not pay off - return register(pageliteral(f_gray(s,s))) + return register(setstate(f_gray(s,s))) end function nodeinjections.spotcolor(n,f,d,p) if type(p) == "string" then p = gsub(p,","," ") -- brr misuse of spot end - return register(pageliteral(f_spot(n,n,p,p))) + return register(setstate(f_spot(n,n,p,p))) end function nodeinjections.transparency(n) - return register(pageliteral(f_tr_gs(n))) + return register(setstate(f_tr_gs(n))) end -- a bit weird but let's keep it here for a while @@ -169,7 +167,7 @@ function nodeinjections.effect(effect,stretch,rulethickness) -- always, no zero test (removed) rulethickness = bp * rulethickness effect = effects[effect] or effects['normal'] - return register(pageliteral(f_effect(stretch,rulethickness,effect))) -- watch order + return register(setstate(f_effect(stretch,rulethickness,effect))) -- watch order end -- spot- and indexcolors @@ -727,29 +725,20 @@ function lpdf.finishtransparencycode() end end --- this will move to lpdf-spe.lua an dwe then can also add a metatable with --- normal context colors - do - local pdfcolor = lpdf.color - local pdftransparency = lpdf.transparency - - local f_slant = formatters["q 1 0 %N 1 0 0 cm"] + local pdfprint, pdfcolor, pdftransparency - local slants = setmetatableindex(function(t,k) - local v = { "pdf", "origin", f_slant(a) } - t[k] = v - return k + updaters.register("backend.update.lpdf",function() + pdfprint = lpdf.print + pdfcolor = lpdf.color + pdftransparency = lpdf.transparency end) - local function startslant(a) - return slants[a] - end - local c_cache = setmetatableindex(function(t,m) + -- We inherit the outer transparency. local v = setmetatableindex(function(t,c) - local p = { "pdf", "page", "q " .. pdfcolor(m,c) } + local p = "q " .. pdfcolor(m,c) t[c] = p return p end) @@ -757,13 +746,11 @@ do return v end) - -- we inherit the outer transparency - local t_cache = setmetatableindex(function(t,transparency) local p = pdftransparency(transparency) local v = setmetatableindex(function(t,colormodel) local v = setmetatableindex(function(t,color) - local v = { "pdf", "page", "q " .. pdfcolor(colormodel,color) .. " " .. p } + local v = "q " .. pdfcolor(colormodel,color) .. " " .. p t[color] = v return v end) @@ -774,120 +761,33 @@ do return v end) - local function startcolor(k) - local m, c = colortoattributes(k) - local t = transparencytoattribute(k) - if t and t ~= unsetvalue then - return t_cache[t][m][c] - else - return c_cache[m][c] - end - end - - -- A problem is that we need to transfer back and this is kind of - -- messy so we force text mode .. i'll do a better job on that but - -- will experiment first (both engines). Virtual fonts will change - -- anyway. - - local vfspecials = backends.pdf.tables.vfspecials or allocate { } - backends.pdf.tables.vfspecials = vfspecials - - vfspecials.startcolor = startcolor - -- vfspecials.stopcolor = { "pdf", "text", "Q" } -- fails - vfspecials.stopcolor = { "pdf", "page", "Q" } - - vfspecials.startslant = startslant - vfspecials.stopslant = { "pdf", "page", "Q" } -- fails - -end - --- new method: - -do - updaters.register("backend.update.lpdf",function() - pdfprint = lpdf.print - end) - - -- Is this still used? It's a font property now. - - local f_slant = formatters["q 1 0 %N 1 0 0 cm"] - - local slants = setmetatableindex(function(t,k) - local v = f_slant(a) - t[k] = v - return k - end) - local function startslant(a) - return pdfprint("origin", slants[a]) - end + local vfinjectors = fonts.helpers.vfinjectors - local function stopslant() - pdfprint("text", "Q") - end + vfinjectors.pdf = function(pos_h,pos_v,packet) + pdfprint(packet[2],packet[3]) + end - -- We inherit the outer transparency. - - local pdfcolor = lpdf.color - local pdftransparency = lpdf.transparency - - -- local c_cache = setmetatableindex(function(t,m) - -- local v = setmetatableindex(function(t,c) - -- local p = "q " .. pdfcolor(m,c) - -- t[c] = p - -- return p - -- end) - -- t[m] = v - -- return v - -- end) - -- - -- local t_cache = setmetatableindex(function(t,transparency) - -- local p = pdftransparency(transparency) - -- local v = setmetatableindex(function(t,colormodel) - -- local v = setmetatableindex(function(t,color) - -- local v = "q " .. pdfcolor(colormodel,color) .. " " .. p - -- t[color] = v - -- return v - -- end) - -- t[colormodel] = v - -- return v - -- end) - -- t[transparency] = v - -- return v - -- end) - - -- local function startcolor(color) - -- local m, c = colortoattributes(color) - -- local t = transparencytoattribute(color) - -- if t then - -- pdfprint("page", t_cache[t][m][c]) - -- else - -- pdfprint("page", c_cache[m][c]) - -- end - -- end - - local function startcolor(color) - local m, c = colortoattributes(color) - local t = transparencytoattribute(color) - if t and t ~= unsetvalue then - pdfprint("page", "q " .. pdfcolor(m,c) .. " " .. pdftransparency(t)) - else - pdfprint("page", "q " .. pdfcolor(m,c)) + vfinjectors.startcolor = function(pos_h,pos_v,packet) + local color = type(packet) == "table" and packet[2] or packet + if color then + local m, c = colortoattributes(color) + local t = transparencytoattribute(color) + if t and t ~= unsetvalue then + pdfprint("page", t_cache[t][m][c]) -- "q " .. pdfcolor(m,c) .. " " .. pdftransparency(t) + else + pdfprint("page", c_cache[m][c]) -- "q " .. pdfcolor(m,c)) + end + else + pdfprint("page", "q") + end end - end - local function stopcolor() - pdfprint("text", "Q") - end + vfinjectors.stopcolor = function() + pdfprint("text", "Q") + end - updaters.register("backend.update.lpdf",function() - fonts.vfcommands = { - startslant = startslant, - stopslant = stopslant, - startcolor = startcolor, - stopcolor = stopcolor, - } end) end diff --git a/tex/context/base/mkxl/lpdf-ini.lmt b/tex/context/base/mkxl/lpdf-ini.lmt index 59e728dfb..ea9466d39 100644 --- a/tex/context/base/mkxl/lpdf-ini.lmt +++ b/tex/context/base/mkxl/lpdf-ini.lmt @@ -82,12 +82,11 @@ do lpdf.getpos = drivers.getpos end) - local pdfgetmatrix, pdfhasmatrix, pdfprint, pdfgetpos + local pdfgetmatrix, pdfhasmatrix, pdfgetpos updaters.register("backend.update.lpdf",function() pdfgetmatrix = lpdf.getmatrix pdfhasmatrix = lpdf.hasmatrix - pdfprint = lpdf.print pdfgetpos = lpdf.getpos end) @@ -541,21 +540,6 @@ end local function add_x(t,k,v) rawset(t,k,tostring(v)) end --- local mt_x = { __index = { __lpdftype__ = "stream" }, __lpdftype = "stream", __tostring = tostring_x, __call = value_x, __newindex = add_x } --- local mt_d = { __index = { __lpdftype__ = "dictionary" }, __lpdftype = "dictionary", __tostring = tostring_d, __call = value_d, __add = add_to_d } --- local mt_a = { __index = { __lpdftype__ = "array" }, __lpdftype = "array", __tostring = tostring_a, __call = value_a, __add = add_to_a } --- local mt_u = { __index = { __lpdftype__ = "unicode" }, __lpdftype = "unicode", __tostring = tostring_u, __call = value_u } --- local mt_s = { __index = { __lpdftype__ = "string" }, __lpdftype = "string", __tostring = tostring_s, __call = value_s } --- local mt_p = { __index = { __lpdftype__ = "docstring" }, __lpdftype = "docstring", __tostring = tostring_p, __call = value_p } --- local mt_n = { __index = { __lpdftype__ = "number" }, __lpdftype = "number", __tostring = tostring_n, __call = value_n } --- local mt_c = { __index = { __lpdftype__ = "constant" }, __lpdftype = "constant", __tostring = tostring_c, __call = value_c } --- local mt_z = { __index = { __lpdftype__ = "null" }, __lpdftype = "null", __tostring = tostring_z, __call = value_z } --- local mt_t = { __index = { __lpdftype__ = "true" }, __lpdftype = "true", __tostring = tostring_t, __call = value_t } --- local mt_f = { __index = { __lpdftype__ = "false" }, __lpdftype = "false", __tostring = tostring_f, __call = value_f } --- local mt_r = { __index = { __lpdftype__ = "reference" }, __lpdftype = "reference", __tostring = tostring_r, __call = value_r } --- local mt_v = { __index = { __lpdftype__ = "verbose" }, __lpdftype = "verbose", __tostring = tostring_v, __call = value_v } --- local mt_l = { __index = { __lpdftype__ = "literal" }, __lpdftype = "literal", __tostring = tostring_l, __call = value_l } - local mt_x = { __index = { __lpdftype__ = "stream" }, __tostring = tostring_x, __call = value_x, __newindex = add_x } local mt_d = { __index = { __lpdftype__ = "dictionary" }, __tostring = tostring_d, __call = value_d, __add = add_to_d } local mt_a = { __index = { __lpdftype__ = "array" }, __tostring = tostring_a, __call = value_a, __add = add_to_a } @@ -1259,6 +1243,17 @@ do end } + local setstate = nodes.nuts.pool.setstate + + function nodeinjections.startalternate(str) + return setstate(f_actual_text(tosixteen(str))) + end + + function nodeinjections.stopalternate() + return setstate("EMC") + end + + end -- interface diff --git a/tex/context/base/mkxl/lpdf-lmt.lmt b/tex/context/base/mkxl/lpdf-lmt.lmt index 44352994a..b57557aee 100644 --- a/tex/context/base/mkxl/lpdf-lmt.lmt +++ b/tex/context/base/mkxl/lpdf-lmt.lmt @@ -100,6 +100,10 @@ local report_objects = logs.reporter("backend","objects") local trace_objects = false trackers.register("backend.objects", function(v) trace_objects = v end) local trace_details = false trackers.register("backend.details", function(v) trace_details = v end) +-- we collect them: + +local flushers = { } + -- used variables local pdf_h, pdf_v @@ -185,7 +189,7 @@ local tjfactor = 100 / 65536 lpdf.usedcharacters = usedcharacters -local function updatefontstate(font) +function flushers.updatefontstate(font) fontcharacters = characters[font] fontdescriptions = descriptions[font] fontparameters = parameters[font] @@ -400,8 +404,7 @@ local function pdf_goto_fontmode() end -- characters - -local flushcharacter do +do local round = math.round @@ -413,52 +416,23 @@ local flushcharacter do local hshift = false local vshift = false - -- local naturalwidths = setmetatableindex(function(t,font) - -- local d = descriptions[font] - -- local c = characters[font] - -- local f = parameters[font].hfactor - -- local v = setmetatableindex(function(t,char) - -- local w - -- local e = d and d[char] - -- if e then - -- w = e.width - -- if w then - -- w = w * f - -- end - -- end - -- if not w then - -- e = c[char] - -- if e then - -- w = e.width or 0 - -- end - -- end - -- if not w then - -- w = 0 - -- end - -- t[char] = w - -- return w - -- end) - -- t[font] = v - -- return v - -- end) - local naturalwidths = setmetatableindex(function(t,font) local d = descriptions[font] local c = characters[font] - local f = parameters[font].hfactor + local f = parameters[font].hfactor or parameters[font].factor local v = setmetatableindex(function(t,char) local w - local e = c[char] + local e = d and d[char] if e then - w = e.width or 0 + w = e.width + if w then + w = w * f + end end if not w then - e = d and d[char] + e = c[char] if e then - w = e.width - if w then - w = w * f - end + w = e.width or 0 end end if not w then @@ -592,7 +566,7 @@ local flushcharacter do -- luatex (a precursor to lmtx and also for comparison) but only in lmtx now so ... -- time to move on I guess. - flushcharacter = function(current,pos_h,pos_v,pos_r,font,char,data,f,e,factor,sx,sy) -- ,naturalwidth,width) + flushers.character = function(current,pos_h,pos_v,pos_r,font,char,data,f,e,factor,sx,sy) -- ,naturalwidth,width) if sx ~= f_x_scale or sy ~= f_y_scale or need_tf or font ~= f_cur or f_pdf ~= f_pdf_cur or fs ~= fs_cur or mode == "page" then pdf_goto_textmode() setup_fontparameters(font,factor,f,e,sx,sy) @@ -665,7 +639,7 @@ local flushcharacter do end - flushfontchar = function(font,char,data) + flushers.fontchar = function(font,char,data) local dummy = usedfonts[font] local index = data.index or char if not pdfcharacters[index] then @@ -690,14 +664,12 @@ local flushliteral do local textliteral_code = literalvalues.text local fontliteral_code = literalvalues.font - local getdata = nuts.getdata - - flushliteral = function(current,pos_h,pos_v,mode,str) - if mode then - if not str then - mode, str = originliteral_code, mode - elseif mode == "mode" then - mode = literalvalues[str] + flushliteral = function(current,pos_h,pos_v) + local p = nodeproperties[current] + if p then + local str = p.data + if str and str ~= "" then + local mode = p.mode if mode == originliteral_code then pdf_goto_pagemode() pdf_set_pos(pos_h,pos_v) @@ -707,49 +679,22 @@ local flushliteral do pdf_goto_textmode() elseif mode == fontliteral_code then pdf_goto_fontmode() - elseif mode == alwaysliteral_code then + elseif mode == alwaysliteral_code then -- aka direct pdf_end_string_nl() need_tm = true elseif mode == rawliteral_code then pdf_end_string_nl() + else + report("invalid literal mode %a when flushing %a",mode,str) + return end - return - else - mode = literalvalues[mode] - end - else - local p = nodeproperties[current] - if p then - str = p.data - mode = p.mode - else - str, mode = getdata(current) - end - end - if str and str ~= "" then - if mode == originliteral_code then - pdf_goto_pagemode() - pdf_set_pos(pos_h,pos_v) - elseif mode == pageliteral_code then - pdf_goto_pagemode() - elseif mode == textliteral_code then - pdf_goto_textmode() - elseif mode == fontliteral_code then - pdf_goto_fontmode() - elseif mode == alwaysliteral_code then - pdf_end_string_nl() - need_tm = true - elseif mode == rawliteral_code then - pdf_end_string_nl() - else - report("check literal") - pdf_goto_pagemode() - pdf_set_pos(pos_h,pos_v) + b = b + 1 ; buffer[b] = str end - b = b + 1 ; buffer[b] = str end end + flushers.literal = flushliteral + function lpdf.print(mode,str) -- This only works inside objects, don't change this to flush -- in between. It's different from luatex but okay. @@ -774,8 +719,8 @@ local flushliteral do elseif mode == rawliteral_code then pdf_end_string_nl() else - pdf_goto_pagemode() - -- pdf_set_pos(pdf_h,pdf_v) + report("invalid literal mode %a when flushing %a",mode,str) + return end b = b + 1 ; buffer[b] = str end @@ -785,14 +730,14 @@ end -- grouping & orientation -local flushsave, flushrestore, flushsetmatrix do +do local matrices = { } local positions = { } local nofpositions = 0 local nofmatrices = 0 - flushsave = function(current,pos_h,pos_v) + local flushsave = function(current,pos_h,pos_v) nofpositions = nofpositions + 1 positions[nofpositions] = { pos_h, pos_v, nofmatrices } pdf_goto_pagemode() @@ -800,7 +745,7 @@ local flushsave, flushrestore, flushsetmatrix do b = b + 1 ; buffer[b] = "q" end - flushrestore = function(current,pos_h,pos_v) + local flushrestore = function(current,pos_h,pos_v) if nofpositions < 1 then return end @@ -822,7 +767,7 @@ local flushsave, flushrestore, flushsetmatrix do local f_matrix_2 = formatters["%.6N 0 0 %.6N 0 0 cm"] local f_matrix_4 = formatters["%.6N %.6N %.6N %.6N 0 0 cm"] - flushsetmatrix = function(current,pos_h,pos_v) + local flushsetmatrix = function(current,pos_h,pos_v) local p = nodeproperties[current] if p then local m = p.matrix @@ -879,6 +824,10 @@ local flushsave, flushrestore, flushsetmatrix do end end + flushers.setmatrix = flushsetmatrix + flushers.save = flushsave + flushers.restore = flushrestore + function lpdf.hasmatrix() return nofmatrices > 0 end @@ -891,7 +840,7 @@ local flushsave, flushrestore, flushsetmatrix do end end - pushorientation = function(orientation,pos_h,pos_v,pos_r) + flushers.pushorientation = function(orientation,pos_h,pos_v,pos_r) pdf_goto_pagemode() pdf_set_pos(pos_h,pos_v) b = b + 1 ; buffer[b] = "q" @@ -904,12 +853,76 @@ local flushsave, flushrestore, flushsetmatrix do end end - poporientation = function(orientation,pos_h,pos_v,pos_r) + flushers.poporientation = function(orientation,pos_h,pos_v,pos_r) pdf_goto_pagemode() pdf_set_pos(pos_h,pos_v) b = b + 1 ; buffer[b] = "Q" end + -- + + flushers.startmatrix = function(current,pos_h,pos_v) + flushsave(current,pos_h,pos_v) + flushsetmatrix(current,pos_h,pos_v) + end + + flushers.stopmatrix = function(current,pos_h,pos_v) + flushrestore(current,pos_h,pos_v) + end + + flushers.startscaling = function(current,pos_h,pos_v) + flushsave(current,pos_h,pos_v) + flushsetmatrix(current,pos_h,pos_v) + end + + flushers.stopscaling = function(current,pos_h,pos_v) + flushrestore(current,pos_h,pos_v) + end + + flushers.startrotation = function(current,pos_h,pos_v) + flushsave(current,pos_h,pos_v) + flushsetmatrix(current,pos_h,pos_v) + end + + flushers.stoprotation = function(current,pos_h,pos_v) + flushrestore(current,pos_h,pos_v) + end + + flushers.startmirroring = function(current,pos_h,pos_v) + flushsave(current,pos_h,pos_v) + flushsetmatrix(current,pos_h,pos_v) + end + + flushers.stopmirroring = function(current,pos_h,pos_v) + flushrestore(current,pos_h,pos_v) + end + + flushers.startclipping = function(current,pos_h,pos_v) + flushsave(current,pos_h,pos_v) + flushliteral("origin",formatters["0 w %s W n"](properties[current].path)) + end + + flushers.stopclipping = function(current,pos_h,pos_v) + flushrestore(current,pos_h,pos_v) + end + +end + +do + + local nodeproperties = nodes.properties.data + + flushers.setstate = function(current,pos_h,pos_v) + local p = nodeproperties[current] + if p then + local d = p.data + if d and d ~= "" then + pdf_goto_pagemode() + b = b + 1 ; buffer[b] = d + end + end + end + end -- rules @@ -917,7 +930,7 @@ end local flushedxforms = { } -- actually box resources but can also be direct local localconverter = nil -- will be set -local flushrule, flushsimplerule, flushspecialrule, flushimage, flushgroup do +local flushimage do local rulecodes = nodes.rulecodes local newrule = nodes.pool.rule @@ -1041,7 +1054,7 @@ local flushrule, flushsimplerule, flushspecialrule, flushimage, flushgroup do end end --- updaters.register("backend.update.tex",function() + -- updaters.register("backend.update.tex",function() updaters.register("backend.update.lpdf",function() tex.saveboxresource = saveboxresource tex.useboxresource = useboxresource @@ -1115,7 +1128,7 @@ local flushrule, flushsimplerule, flushspecialrule, flushimage, flushgroup do local groups = 0 local group = nil - flushgroup = function(content,bbox) + local flushgroup = function(content,bbox) if not group then group = pdfdictionary { Type = pdfconstant("Group"), @@ -1136,6 +1149,7 @@ local flushrule, flushsimplerule, flushspecialrule, flushimage, flushgroup do return f_gr(groups) end + flushers.group = flushgroup lpdf.flushgroup = flushgroup -- todo: access via driver in mlib-pps -- end of experiment @@ -1287,6 +1301,8 @@ local flushrule, flushsimplerule, flushspecialrule, flushimage, flushgroup do b = b + 1 ; buffer[b] = s_e end + flushers.image = flushimage + -- For the moment we need this hack because the engine checks the 'image' -- command in virtual fonts (so we use lua instead). -- @@ -1294,7 +1310,7 @@ local flushrule, flushsimplerule, flushspecialrule, flushimage, flushgroup do -- never because the next are like the other engines and compensate for -- small sizes which is needed for inaccurate viewers. - flushrule = function(current,pos_h,pos_v,pos_r,size_h,size_v,subtype) + flushers.rule = function(current,pos_h,pos_v,pos_r,size_h,size_v,subtype) if subtype == emptyrule_code then return @@ -1350,7 +1366,7 @@ local flushrule, flushsimplerule, flushspecialrule, flushimage, flushgroup do end - flushsimplerule = function(pos_h,pos_v,pos_r,size_h,size_v) + flushers.simplerule = function(pos_h,pos_v,pos_r,size_h,size_v) pdf_goto_pagemode() b = b + 1 ; buffer[b] = s_b @@ -1374,7 +1390,7 @@ local flushrule, flushsimplerule, flushspecialrule, flushimage, flushgroup do b = b + 1 ; buffer[b] = s_e end - flushspecialrule = function(pos_h,pos_v,pos_r,width,height,depth,line,outline,baseline) + flushers.specialrule = function(pos_h,pos_v,pos_r,width,height,depth,line,outline,baseline) pdf_goto_pagemode() b = b + 1 ; buffer[b] = s_b @@ -2953,24 +2969,7 @@ do drivers.install { name = "pdf", - flushers = { - character = flushcharacter, - fontchar = flushfontchar, - rule = flushrule, - simplerule = flushsimplerule, - specialrule = flushspecialrule, - pushorientation = pushorientation, - poporientation = poporientation, - -- - literal = flushliteral, - setmatrix = flushsetmatrix, - save = flushsave, - restore = flushrestore, - image = flushimage, - group = flushgroup, - -- - updatefontstate = updatefontstate, - }, + flushers = flushers, actions = { prepare = prepare, wrapup = wrapup, diff --git a/tex/context/base/mkxl/lpdf-mis.lmt b/tex/context/base/mkxl/lpdf-mis.lmt index 46accf9a4..afb149d8a 100644 --- a/tex/context/base/mkxl/lpdf-mis.lmt +++ b/tex/context/base/mkxl/lpdf-mis.lmt @@ -26,11 +26,14 @@ local nodeinjections = backends.pdf.nodeinjections local codeinjections = backends.pdf.codeinjections local registrations = backends.pdf.registrations +local getpagedimensions = layouts.getpagedimensions +local getcanvas = layouts.getcanvas + local nuts = nodes.nuts local copy_node = nuts.copy local nodepool = nuts.pool -local pageliteral = nodepool.pageliteral +local setstate = nodepool.setstate local register = nodepool.register local pdfdictionary = lpdf.dictionary @@ -86,10 +89,10 @@ local v_righttoleft = variables.righttoleft local v_title = variables.title local v_nomenubar = variables.nomenubar -local positive = register(pageliteral("/GSpositive gs")) -local negative = register(pageliteral("/GSnegative gs")) -local overprint = register(pageliteral("/GSoverprint gs")) -local knockout = register(pageliteral("/GSknockout gs")) +local positive = register(setstate("/GSpositive gs")) +local negative = register(setstate("/GSnegative gs")) +local overprint = register(setstate("/GSoverprint gs")) +local knockout = register(setstate("/GSknockout gs")) local omitextraboxes = false @@ -410,46 +413,12 @@ local pagespecs = { }, } -local pagespec, topoffset, leftoffset, height, width, doublesided = "default", 0, 0, 0, 0, false -local cropoffset, bleedoffset, trimoffset, artoffset = 0, 0, 0, 0 -local marked = false -local copies = false +local function documentspecification() + local canvas = getcanvas() -local getpagedimensions getpagedimensions = function() - getpagedimensions = backends.codeinjections.getpagedimensions - return getpagedimensions() -end + -- move this to layo-ini ? -function codeinjections.setupcanvas(specification) - local paperheight = specification.paperheight - local paperwidth = specification.paperwidth - local paperdouble = specification.doublesided - -- - paperwidth, paperheight = codeinjections.setpagedimensions(paperwidth,paperheight) - -- - pagespec = specification.mode or pagespec - topoffset = specification.topoffset or 0 - leftoffset = specification.leftoffset or 0 - height = specification.height or paperheight - width = specification.width or paperwidth - marked = specification.print - -- - copies = specification.copies - if copies and copies < 2 then - copies = false - end - -- - cropoffset = specification.cropoffset or 0 - trimoffset = cropoffset - (specification.trimoffset or 0) - bleedoffset = trimoffset - (specification.bleedoffset or 0) - artoffset = bleedoffset - (specification.artoffset or 0) - -- - if paperdouble ~= nil then - doublesided = paperdouble - end -end - -local function documentspecification() + local pagespec = canvas.pagespec if not pagespec or pagespec == "" then pagespec = v_default end @@ -460,7 +429,7 @@ local function documentspecification() local spec = defaults or pagespecs[v_default] -- successive keys can modify this if spec.layout == "auto" then - if doublesided then + if canvas.doublesided then local s = pagespecs[v_doublesided] -- to be checked voor interfaces for k, v in next, s do spec[k] = v @@ -478,6 +447,7 @@ local function documentspecification() end end end + -- maybe interfaces.variables local layout = spec.layout local mode = spec.mode @@ -495,6 +465,8 @@ local function documentspecification() addtocatalog("PageMode",pdfconstant(mode)) end local prints = nil + local marked = canvas.marked + local copies = canvas.copies if marked then local pages = structures.pages local marked = pages.allmarked(marked) @@ -534,10 +506,15 @@ local function boxvalue(n) -- we could share them end local function pagespecification() - local paperwidth, paperheight = codeinjections.getpagedimensions() + local canvas = getcanvas() + local paperwidth = canvas.paperwidth + local paperheight = canvas.paperheight + local leftoffset = canvas.leftoffset + local topoffset = canvas.topoffset + -- local llx = leftoffset - local lly = paperheight + topoffset - height - local urx = width - leftoffset + local urx = canvas.width - leftoffset + local lly = paperheight + topoffset - canvas.height local ury = paperheight - topoffset -- boxes can be cached local function extrabox(WhatBox,offset,always) @@ -553,10 +530,10 @@ local function pagespecification() if omitextraboxes then -- only useful for testing / comparing else - extrabox("CropBox",cropoffset,true) -- mandate for rendering - extrabox("TrimBox",trimoffset,true) -- mandate for pdf/x - extrabox("BleedBox",bleedoffset) -- optional - -- extrabox("ArtBox",artoffset) -- optional .. unclear what this is meant to do + extrabox("CropBox",canvas.cropoffset,true) -- mandate for rendering + extrabox("TrimBox",canvas.trimoffset,true) -- mandate for pdf/x + extrabox("BleedBox",canvas.bleedoffset) -- optional + -- extrabox("ArtBox",canvas.artoffset) -- optional .. unclear what this is meant to do end end diff --git a/tex/context/base/mkxl/lpdf-ren.lmt b/tex/context/base/mkxl/lpdf-ren.lmt index 8aa61e1dc..3794250d9 100644 --- a/tex/context/base/mkxl/lpdf-ren.lmt +++ b/tex/context/base/mkxl/lpdf-ren.lmt @@ -60,7 +60,7 @@ local copy_node = nuts.copy local nodepool = nuts.pool local register = nodepool.register -local pageliteral = nodepool.pageliteral +local setstate = nodepool.setstate local pdf_ocg = pdfconstant("OCG") local pdf_ocmd = pdfconstant("OCMD") @@ -267,7 +267,7 @@ function nodeinjections.startlayer(name) local c = cache[name] if not c then useviewerlayer(name) - c = register(pageliteral(f_bdc(escapednames[name]))) + c = register(setstate(f_bdc(escapednames[name]))) cache[name] = c end return copy_node(c) @@ -275,7 +275,7 @@ end function nodeinjections.stoplayer() if not stop then - stop = register(pageliteral(s_emc)) + stop = register(setstate(s_emc)) end return copy_node(stop) end @@ -292,7 +292,7 @@ function nodeinjections.startstackedlayer(s,t,first,last) r[#r+1] = startlayer(values[t[i]]) end r = concat(r," ") - return pageliteral(r) + return setstate(r) end function nodeinjections.stopstackedlayer(s,t,first,last) @@ -301,7 +301,7 @@ function nodeinjections.stopstackedlayer(s,t,first,last) r[#r+1] = stoplayer() end r = concat(r," ") - return pageliteral(r) + return setstate(r) end function nodeinjections.changestackedlayer(s,t1,first1,last1,t2,first2,last2) @@ -313,7 +313,7 @@ function nodeinjections.changestackedlayer(s,t1,first1,last1,t2,first2,last2) r[#r+1] = startlayer(values[t2[i]]) end r = concat(r," ") - return pageliteral(r) + return setstate(r) end -- transitions diff --git a/tex/context/base/mkxl/lpdf-rul.lmt b/tex/context/base/mkxl/lpdf-rul.lmt index ae2142a8e..efcc62073 100644 --- a/tex/context/base/mkxl/lpdf-rul.lmt +++ b/tex/context/base/mkxl/lpdf-rul.lmt @@ -33,13 +33,9 @@ local formatters = string.formatters -- This is very pdf specific. Maybe move some to lpdf-rul.lua some day. -local pdfprint +local pdfprint ; pdfprint = function(...) pdfprint = lpdf.print return pdfprint(...) end -pdfprint = function(...) pdfprint = lpdf.print return pdfprint(...) end - --- updaters.register("backend.update",function() --- pdfprint = lpdf.print --- end) +-- updaters.register("backend.update",function() pdfprint = lpdf.print end) do diff --git a/tex/context/base/mkxl/lpdf-tag.lmt b/tex/context/base/mkxl/lpdf-tag.lmt index 4ea92d951..44a84ea59 100644 --- a/tex/context/base/mkxl/lpdf-tag.lmt +++ b/tex/context/base/mkxl/lpdf-tag.lmt @@ -63,7 +63,7 @@ local a_image = attributes.private('image') local nuts = nodes.nuts local nodepool = nuts.pool -local pageliteral = nodepool.pageliteral +local setstate = nodepool.setstate local register = nodepool.register local getid = nuts.getid @@ -369,7 +369,7 @@ local visualize = nil function nodeinjections.addtags(head) if not EMCliteral then - EMCliteral = register(pageliteral("EMC")) + EMCliteral = register(setstate("EMC")) end local last = nil @@ -516,9 +516,9 @@ end end end if prev then - literal = pageliteral(makecontent(prev,id,specification)) + literal = setstate(makecontent(prev,id,specification)) elseif ignore then - literal = pageliteral(makeignore(specification)) + literal = setstate(makeignore(specification)) else -- maybe also ignore or maybe better: comment or so end @@ -543,7 +543,7 @@ end else - local literal = pageliteral(makeignore(specification)) + local literal = setstate(makeignore(specification)) inject(start,stop,list,literal) @@ -667,9 +667,9 @@ end -- end -- -- if r > 0 then --- local literal = pageliteral(concat(result,"\n")) +-- local literal = setstate(concat(result,"\n")) -- -- use insert instead: --- local literal = pageliteral(result) +-- local literal = setstate(result) -- local prev = getprev(start) -- if prev then -- setlink(prev,literal) @@ -691,7 +691,7 @@ end -- for i=1,noftop do -- result[i] = "EMC" -- end --- local literal = pageliteral(concat(result,"\n")) +-- local literal = setstate(concat(result,"\n")) -- -- use insert instead: -- local next = getnext(last) -- if next then diff --git a/tex/context/base/mkxl/lpdf-vfc.lmt b/tex/context/base/mkxl/lpdf-vfc.lmt deleted file mode 100644 index 6030bb028..000000000 --- a/tex/context/base/mkxl/lpdf-vfc.lmt +++ /dev/null @@ -1,42 +0,0 @@ -if not modules then modules = { } end modules ['lpdf-vfc'] = { - version = 1.001, - comment = "companion to lpdf-ini.mkiv", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - -local setmetatableindex = table.setmetatableindex - -local defaultline = 16384 - -local vfspecials = backends.pdf.tables.vfspecials or utilities.storage.allocate { } -backends.pdf.tables.vfspecials = vfspecials - -vfspecials.backgrounds = setmetatableindex(function(t,h) - local v = setmetatableindex(function(t,d) - local v = setmetatableindex(function(t,w) - local v = { "frame", w, h, d, defaultline, true, true } - t[w] = v - return v - end) - t[d] = v - return v - end) - t[h] = v - return v -end) - -vfspecials.outlines = setmetatableindex(function(t,h) - local v = setmetatableindex(function(t,d) - local v = setmetatableindex(function(t,w) - local v = { "frame", w, h, d, defaultline, false, true } - t[w] = v - return v - end) - t[d] = v - return v - end) - t[h] = v - return v -end) diff --git a/tex/context/base/mkxl/math-act.lmt b/tex/context/base/mkxl/math-act.lmt new file mode 100644 index 000000000..3076f2ac9 --- /dev/null +++ b/tex/context/base/mkxl/math-act.lmt @@ -0,0 +1,480 @@ +if not modules then modules = { } end modules ['math-act'] = { + version = 1.001, + comment = "companion to math-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- Here we tweak some font properties (if needed). The commented sections +-- have been removed (no longer viable) but can be found in the .lua variant. + +local type, next = type, next +local fastcopy, insert, remove = table.fastcopy, table.insert, table.remove +local formatters = string.formatters + +local trace_defining = false trackers.register("math.defining", function(v) trace_defining = v end) +local trace_collecting = false trackers.register("math.collecting", function(v) trace_collecting = v end) + +local report_math = logs.reporter("mathematics","initializing") + +local context = context +local commands = commands +local mathematics = mathematics +local texsetdimen = tex.setdimen +local abs = math.abs + +local helpers = fonts.helpers +local upcommand = helpers.commands.up +local rightcommand = helpers.commands.right +local charcommand = helpers.commands.char +local prependcommands = helpers.prependcommands + +local sequencers = utilities.sequencers +local appendgroup = sequencers.appendgroup +local appendaction = sequencers.appendaction + +local fontchars = fonts.hashes.characters +local fontproperties = fonts.hashes.properties + +local mathfontparameteractions = sequencers.new { + name = "mathparameters", + arguments = "target,original", +} + +appendgroup("mathparameters","before") -- user +appendgroup("mathparameters","system") -- private +appendgroup("mathparameters","after" ) -- user + +function fonts.constructors.assignmathparameters(original,target) + local runner = mathfontparameteractions.runner + if runner then + runner(original,target) + end +end + +function mathematics.initializeparameters(target,original) + local mathparameters = original.mathparameters + if mathparameters and next(mathparameters) then + mathparameters = mathematics.dimensions(mathparameters) + if not mathparameters.SpaceBeforeScript then + mathparameters.SpaceBeforeScript = mathparameters.SpaceAfterScript + end + target.mathparameters = mathparameters + end +end + +sequencers.appendaction("mathparameters","system","mathematics.initializeparameters") + +local how = { + -- RadicalKernBeforeDegree = "horizontal", + -- RadicalKernAfterDegree = "horizontal", + ScriptPercentScaleDown = "unscaled", + ScriptScriptPercentScaleDown = "unscaled", + RadicalDegreeBottomRaisePercent = "unscaled", + NoLimitSupFactor = "unscaled", + NoLimitSubFactor = "unscaled", +} + +function mathematics.scaleparameters(target,original) + if not target.properties.math_is_scaled then + local mathparameters = target.mathparameters + if mathparameters and next(mathparameters) then + local parameters = target.parameters + local factor = parameters.factor + local hfactor = parameters.hfactor + local vfactor = parameters.vfactor + for name, value in next, mathparameters do + local h = how[name] + if h == "unscaled" then + -- kept + elseif h == "horizontal" then + value = value * hfactor + elseif h == "vertical"then + value = value * vfactor + else + value = value * factor + end + mathparameters[name] = value + end + end + target.properties.math_is_scaled = true + end +end + +-- AccentBaseHeight vs FlattenedAccentBaseHeight + +function mathematics.checkaccentbaseheight(target,original) + local mathparameters = target.mathparameters + if mathparameters and mathparameters.AccentBaseHeight == 0 then + mathparameters.AccentBaseHeight = target.parameters.x_height -- needs checking + end +end + +function mathematics.checkprivateparameters(target,original) + local mathparameters = target.mathparameters + if mathparameters then + local parameters = target.parameters + local properties = target.properties + if parameters then + local size = parameters.size + if size then + if not mathparameters.FractionDelimiterSize then + mathparameters.FractionDelimiterSize = 1.01 * size + end + if not mathparameters.FractionDelimiterDisplayStyleSize then + mathparameters.FractionDelimiterDisplayStyleSize = 2.40 * size + end + elseif properties then + report_math("invalid parameters in font %a",properties.fullname or "?") + else + report_math("invalid parameters in font") + end + elseif properties then + report_math("no parameters in font %a",properties.fullname or "?") + else + report_math("no parameters and properties in font") + end + end +end + +function mathematics.overloadparameters(target,original) + local mathparameters = target.mathparameters + if mathparameters and next(mathparameters) then + local goodies = target.goodies + if goodies then + for i=1,#goodies do + local goodie = goodies[i] + local mathematics = goodie.mathematics + local parameters = mathematics and mathematics.parameters + if parameters then + if trace_defining then + report_math("overloading math parameters in %a @ %p",target.properties.fullname,target.parameters.size) + end + for name, value in next, parameters do + local tvalue = type(value) + if tvalue == "string" then + report_math("comment for math parameter %a: %s",name,value) + else + local oldvalue = mathparameters[name] + local newvalue = oldvalue + if oldvalue then + if tvalue == "number" then + newvalue = value + elseif tvalue == "function" then + newvalue = value(oldvalue,target,original) + elseif not tvalue then + newvalue = nil + end + if trace_defining and oldvalue ~= newvalue then + report_math("overloading math parameter %a: %S => %S",name,oldvalue,newvalue) + end + else + report_math("invalid math parameter %a",name) + end + mathparameters[name] = newvalue + end + end + end + end + end + end +end + +local function applytweaks(when,target,original) + local goodies = original.goodies + if goodies then + for i=1,#goodies do + local goodie = goodies[i] + local mathematics = goodie.mathematics + local tweaks = mathematics and mathematics.tweaks + if type(tweaks) == "table" then + tweaks = tweaks[when] + if type(tweaks) == "table" then + if trace_defining then + report_math("tweaking math of %a @ %p (%s)",target.properties.fullname,target.parameters.size,when) + end + for i=1,#tweaks do + local tweak= tweaks[i] + local tvalue = type(tweak) + if tvalue == "function" then + tweak(target,original) + end + end + end + end + end + end +end + +function mathematics.tweakbeforecopyingfont(target,original) + local mathparameters = target.mathparameters -- why not hasmath + if mathparameters then + applytweaks("beforecopying",target,original) + end +end + +function mathematics.tweakaftercopyingfont(target,original) + local mathparameters = target.mathparameters -- why not hasmath + if mathparameters then + applytweaks("aftercopying",target,original) + end +end + +sequencers.appendaction("mathparameters","system","mathematics.scaleparameters") +sequencers.appendaction("mathparameters","system","mathematics.checkaccentbaseheight") -- should go in lfg instead +sequencers.appendaction("mathparameters","system","mathematics.checkprivateparameters") -- after scaling ! +sequencers.appendaction("mathparameters","system","mathematics.overloadparameters") + +sequencers.appendaction("beforecopyingcharacters","system","mathematics.tweakbeforecopyingfont") +sequencers.appendaction("aftercopyingcharacters", "system","mathematics.tweakaftercopyingfont") + +local virtualized = mathematics.virtualized + +-- no, it's a feature now (see good-mth): +-- +-- sequencers.appendaction("aftercopyingcharacters", "system","mathematics.overloaddimensions") + +-- a couple of predefined tweaks: + +local tweaks = { } +mathematics.tweaks = tweaks + +-- helpers + +local setmetatableindex = table.setmetatableindex + +local getfontoffamily = tex.getfontoffamily + +local fontcharacters = fonts.hashes.characters +local extensibles = utilities.storage.allocate() +fonts.hashes.extensibles = extensibles + +local chardata = characters.data +local extensibles = mathematics.extensibles + +-- we use numbers at the tex end (otherwise we could stick to chars) + +local e_left = extensibles.left +local e_right = extensibles.right +local e_horizontal = extensibles.horizontal +local e_mixed = extensibles.mixed +local e_unknown = extensibles.unknown + +local unknown = { e_unknown, false, false } + +local function extensiblecode(font,unicode) + local characters = fontcharacters[font] + local character = characters[unicode] + if not character then + return unknown + end + local first = character.next + local code = unicode + local next = first + while next do + code = next + character = characters[next] + next = character.next + end + local char = chardata[unicode] + if not char then + return unknown + end + if character.horiz_variants then + if character.vert_variants then + return { e_mixed, code, character } + else + local m = char.mathextensible + local e = m and extensibles[m] + return e and { e, code, character } or unknown + end + elseif character.vert_variants then + local m = char.mathextensible + local e = m and extensibles[m] + return e and { e, code, character } or unknown + elseif first then + -- assume accent (they seldom stretch .. sizes) + local m = char.mathextensible or char.mathstretch + local e = m and extensibles[m] + return e and { e, code, character } or unknown + else + return unknown + end +end + +setmetatableindex(extensibles,function(extensibles,font) + local codes = { } + setmetatableindex(codes, function(codes,unicode) + local status = extensiblecode(font,unicode) + codes[unicode] = status + return status + end) + extensibles[font] = codes + return codes +end) + +local function extensiblecode(family,unicode) + return extensibles[getfontoffamily(family or 0)][unicode][1] +end + +-- left : [head] ... +-- right : ... [head] +-- horizontal : [head] ... [head] +-- +-- abs(right["start"] - right["end"]) | right.advance | characters[right.glyph].width + +local function horizontalcode(family,unicode) + local font = getfontoffamily(family or 0) + local data = extensibles[font][unicode] + local kind = data[1] + local loffset = 0 + local roffset = 0 + if kind == e_left then + local charlist = data[3].horiz_variants + if charlist then + local left = charlist[1] + loffset = abs((left["start"] or 0) - (left["end"] or 0)) + end + elseif kind == e_right then + local charlist = data[3].horiz_variants + if charlist then + local right = charlist[#charlist] + roffset = abs((right["start"] or 0) - (right["end"] or 0)) + end + elseif kind == e_horizontal then + local charlist = data[3].horiz_variants + if charlist then + local left = charlist[1] + local right = charlist[#charlist] + loffset = abs((left ["start"] or 0) - (left ["end"] or 0)) + roffset = abs((right["start"] or 0) - (right["end"] or 0)) + end + end + return kind, loffset, roffset +end + +mathematics.extensiblecode = extensiblecode +mathematics.horizontalcode = horizontalcode + +interfaces.implement { + name = "extensiblecode", + arguments = { "integer", "integer" }, + actions = { extensiblecode, context } +} + +interfaces.implement { + name = "horizontalcode", + arguments = { "integer", "integer" }, + actions = function(family,unicode) + local kind, loffset, roffset = horizontalcode(family,unicode) + texsetdimen("scratchleftoffset", loffset) + texsetdimen("scratchrightoffset",roffset) + context(kind) + end +} + + +local stack = { } + +function mathematics.registerfallbackid(n,id,name) + if trace_collecting then + report_math("resolved fallback font %i, name %a, id %a, used %a", + n,name,id,fontproperties[id].fontname) + end + stack[#stack][n] = id +end + +interfaces.implement { -- will be shared with text + name = "registerfontfallbackid", + arguments = { "integer", "integer", "string" }, + actions = mathematics.registerfallbackid, +} + +function mathematics.resolvefallbacks(target,specification,fallbacks) + local definitions = fonts.collections.definitions[fallbacks] + if definitions then + local size = specification.size -- target.size + local list = { } + insert(stack,list) + context.pushcatcodes("prt") -- context.unprotect() + for i=1,#definitions do + local definition = definitions[i] + local name = definition.font + local features = definition.features or "" + local size = size * (definition.rscale or 1) + context.font_fallbacks_register_math(i,name,features,size) + if trace_collecting then + report_math("registering fallback font %i, name %a, size %a, features %a",i,name,size,features) + end + end + context.popcatcodes() + end +end + +function mathematics.finishfallbacks(target,specification,fallbacks) + local list = remove(stack) + if list and #list > 0 then + local definitions = fonts.collections.definitions[fallbacks] + if definitions and #definitions > 0 then + if trace_collecting then + report_math("adding fallback characters to font %a",specification.hash) + end + local definedfont = fonts.definers.internal + local copiedglyph = fonts.handlers.vf.math.copy_glyph + local fonts = target.fonts + local size = specification.size -- target.size + local characters = target.characters + if not fonts then + fonts = { } + target.fonts = fonts + end + if #fonts == 0 then + fonts[1] = { id = 0, size = size } -- self, will be resolved later + end + local done = { } + for i=1,#definitions do + local definition = definitions[i] + local name = definition.font + local start = definition.start + local stop = definition.stop + local gaps = definition.gaps + local check = definition.check + local force = definition.force + local rscale = definition.rscale or 1 + local offset = definition.offset or start + local id = list[i] + if id then + local index = #fonts + 1 + fonts[index] = { id = id, size = size } + local chars = fontchars[id] + local function remap(unic,unicode,gap) + if check and not chars[unicode] then + return + end + if force or (not done[unic] and not characters[unic]) then + if trace_collecting then + report_math("replacing math character %C by %C using vector %a and font id %a for %a%s%s", + unic,unicode,fallbacks,id,fontproperties[id].fontname,check and ", checked",gap and ", gap plugged") + end + characters[unic] = copiedglyph(target,characters,chars,unicode,index) + done[unic] = true + end + end + local step = offset - start + for unicode = start, stop do + remap(unicode + step,unicode,false) + end + if gaps then + for unic, unicode in next, gaps do + remap(unic,unicode,true) + remap(unicode,unicode,true) + end + end + end + end + elseif trace_collecting then + report_math("no fallback characters added to font %a",specification.hash) + end + end +end diff --git a/tex/context/base/mkxl/math-ali.mkxl b/tex/context/base/mkxl/math-ali.mkxl index d90f3ab0f..72f857720 100644 --- a/tex/context/base/mkxl/math-ali.mkxl +++ b/tex/context/base/mkxl/math-ali.mkxl @@ -285,7 +285,7 @@ \math_number_right_of_eqalign \global\settrue\c_math_eqalign_first \crcr - \dostoptagged} % finish row + \noalign{\dostoptagged}} % finish row \permanent\protected\def\math_alignment_NC {\relax diff --git a/tex/context/base/mkxl/math-ini.mkxl b/tex/context/base/mkxl/math-ini.mkxl index 95501be65..01ecd63a2 100644 --- a/tex/context/base/mkxl/math-ini.mkxl +++ b/tex/context/base/mkxl/math-ini.mkxl @@ -66,7 +66,7 @@ \registerctxluafile{math-ini}{} \registerctxluafile{math-dim}{} -\registerctxluafile{math-act}{} +\registerctxluafile{math-act}{autosuffix} \registerctxluafile{math-ext}{} \registerctxluafile{math-vfu}{autosuffix} \registerctxluafile{math-ttv}{} diff --git a/tex/context/base/mkxl/math-noa.lmt b/tex/context/base/mkxl/math-noa.lmt index c884e6927..92edbc441 100644 --- a/tex/context/base/mkxl/math-noa.lmt +++ b/tex/context/base/mkxl/math-noa.lmt @@ -693,7 +693,8 @@ do end -- We can optimize this if we really think that math is a bottleneck which it never - -- really is. + -- really is. Beware: the font is the text font in the family, so we only check the + -- text font here. relocate[mathchar_code] = function(pointer) local g = getattr(pointer,a_mathgreek) or 0 @@ -757,7 +758,13 @@ do end end if not characters[char] then + local fam = getfam(pointer) + local fnt = getfontoffamily(fam,1) setchar(pointer,errorchar(font,char)) + if font ~= fnt then + errorchar(fnt,char) + errorchar(getfontoffamily(fam,2),char) + end end if trace_analyzing then setnodecolor(pointer,"font:medi") diff --git a/tex/context/base/mkxl/meta-imp-punk.mkxl b/tex/context/base/mkxl/meta-imp-punk.mkxl new file mode 100644 index 000000000..050023642 --- /dev/null +++ b/tex/context/base/mkxl/meta-imp-punk.mkxl @@ -0,0 +1,272 @@ +%D \module +%D [ file=meta-imp-punk, +%D version=2020.01.16, +%D title=\METAPOST\ Graphics, +%D subtitle=Punk, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +% This file is a merge of the original punk files by Donald Knuth, who +% added this comment: +% +% Font inspired by Gerard and Marjan Unger's lectures, Feb 1985 +% +% The regular punk files are part of TeXLive and in metafont format. All +% errors introduced are ours. We also changed the encoding to unicode. In +% due time we might add a few more more characters. We still need to +% improve some of the metrics which involves a bit of trial and error. The +% font just covers basic latin shapes but in ConTeXt MkIV we add virtual +% composed shapes. There is a module m-punk.tex that implements this. This +% derivate is also used in mk.tex (mk.pdf) which is one of our tests for +% LuaTeX. We published an article on it in the MAPS (NTG magazine). +% +% 2008, mkiv variant: Taco Hoekwater & Hans Hagen +% 2020, lmtx variant: Hans Hagen (playground) + +\startMPcalculation{simplefun} + + picture PunkShapes[][]; + + numeric PunkId ; PunkId := 0 ; + numeric PunkBase ; PunkBase := 0 ; + string PunkName ; PunkName := "punk" ; + numeric PunkUsed ; PunkUsed := 0 ; + numeric PunkSlant ; PunkSlant := 0 ; + numeric PunkWeight ; PunkWeight := 1 ; + numeric PunkSqueeze ; PunkSqueeze := 1 ; + numeric PunkExtend ; PunkExtend := 1 ; + numeric PunkVariants ; PunkVariants := 0 ; + + numeric PunkRatio ; PunkRatio := 2/3 ; + numeric PunkScale ; PunkScale := 20 ; % when zero we use the knuth values + numeric PunkN ; PunkN := 0 ; + + def beginpunkchar(expr c, n, hor, ver) = + begingroup ; + save uc, w, h, d, hdev, vdev ; + hdev := hor * dev ; % modify horizontal amounts of deviation + vdev := ver * dev ; % modify vertical amounts of deviation + uc := if string c : utfnum(c) else : c fi ; + h := if PunkScale > 0 : PunkN else : n fi / PunkSqueeze ; + w := n * PunkExtend ; + d := 0 ; + clearxy ; + clearit ; + enddef ; + + def endpunkchar = + if PunkSlant <> 0 : + currentpicture := currentpicture slanted PunkSlant ; + fi ; + save llx, lly, uly ; + llx := xpart llcorner currentpicture ; + lly := ypart llcorner currentpicture ; + uly := ypart ulcorner currentpicture ; + + currentpicture := currentpicture shifted (- llx + 1, 0); + w := bbwidth(currentpicture) + 2 ; + h := uly ; + d := if lly < 0 : - lly else : 0 fi ; + + PunkUsed := if PunkBase > 0 : PunkBase else : uc fi; + PunkShapes[PunkId][PunkUsed] := currentpicture ; + lmt_registerglyph [ + category = PunkName, + unicode = PunkUsed, + tounicode = uc, + width = w, + height = h, + depth = d, + code = "draw PunkShapes[" & decimal PunkId & "][" & decimal PunkUsed & "]", + ] ; + if PunkBase > 0 : + PunkBase := PunkBase + 1 ; + fi ; + endgroup ; + enddef ; + + def initialize_punk_upper = + PunkN := PunkScale ; + dev := 1 ; + enddef ; + + def initialize_punk_lower = + PunkN := PunkScale * PunkRatio ; + dev := .5 ; + enddef ; + + def revert_punk_lower = + PunkN := PunkScale ; + dev := 1 ; + enddef ; + + def beginpunkfont = + + begingroup ; + + save dev; + + save u ; u := 1 ; + + PunkBase := 0 ; + + pen linepen ; linepen := pencircle scaled (PunkWeight * u) ; + pen dotpen ; dotpen := linepen scaled 2 slanted -PunkSlant ; + + pickup linepen ; + + save pp ; vardef pp expr z = + z + (hdev * normaldeviate, vdev * normaldeviate) + enddef ; + + save pd ; def pd expr z = + drawdot z withpen dotpen ; + enddef ; + + PunkId := PunkId + 1 ; + + lmt_registerglyphs [ + name = PunkName, % todo: when we do name = name we get ['"name"'] = name + units = 25, + width = 25, + height = 25, + depth = 0, + usecolor = true, + ] ; + + def endchar = endpunkchar enddef ; + + enddef ; + + def endpunkfont = + endgroup; + enddef ; + + % We started out with immediate: + + % def MakePunkFont (expr name, filename, slant, weight, squeeze, extend) = + % begingroup ; + % save PunkName, PunkFileName, PunkSlant, PunkWeight, PunkSqueeze, PunkExend, PunkVariants ; + % string PunkName, PunkFileName ; + % PunkFileName := filename ; + % PunkName := name ; + % PunkSlant := slant ; + % PunkWeight := weight ; + % PunkSqueeze := squeeze ; + % PunkExtend := extend ; + % PunkVariants := 0 ; + % beginpunkfont ; + % loadfile(PunkFileName) ; + % endpunkfont ; + % endgroup ; + % enddef ; + % + % MakePunkFont("punk", "punkfont-characters.mp", 1, 0 ) ; + % MakePunkFont("punkbold", "punkfont-characters.mp", 2, 0 ) ; + % MakePunkFont("punkslanted", "punkfont-characters.mp", 1, 0.15) ; + % MakePunkFont("punkboldslanted", "punkfont-characters.mp", 2, 0.15) ; + + % And ended up with delayed: + + def punkpreroll = + begingroup ; + save PunkName, PunkFileName, PunkSlant, PunkWeight, PunkSqueeze, PunkExtend, PunkVariants ; + string PunkName, PunkFileName ; + PunkName := getparameterdefault "mpsfont" "name" "punk" ; + PunkFileName := getparameterdefault "mpsfont" "filename" "punkfont-characters.mp" ; + PunkSlant := scantokens(getparameterdefault "mpsfont" "slant" "0") ; + PunkWeight := scantokens(getparameterdefault "mpsfont" "weight" "1") ; + PunkSqueeze := scantokens(getparameterdefault "mpsfont" "squeeze" "1") ; + PunkExtend := scantokens(getparameterdefault "mpsfont" "extend" "1") ; + PunkVariants := scantokens(getparameterdefault "mpsfont" "variants" "0"); + beginpunkfont ; + loadfile(PunkFileName) ; + if PunkVariants > 0 : + PunkBase := 57344 ; % 0xE000 ; 0xF0000 ; + for i=1 upto PunkVariants : + loadfile(PunkFileName) ; + endfor ; + fi ; + endpunkfont ; + endgroup ; + enddef ; + +\stopMPcalculation + +% Are these names okay? If so it can go into the core. + +\permanent\protected\def\enablerandomvariants{\setcharactercasing[randomvariant]} +\permanent\protected\def\randomvariants {\groupedcommand\enablerandomvariants\donothing} +\permanent\protected\def\startrandomvariants {\begingroup\enablerandomvariants} +\permanent\protected\def\stoprandomvariants {\endgroup} + +\definefontfeature [punk] [metapost={category=punk,preroll=punkpreroll}] +\definefontfeature [punkrandom] [metapost={category=punk,preroll=punkpreroll,variants=10}] +\definefontfeature [punkbold] [metapost={category=punk,preroll=punkpreroll,weight=2}] +\definefontfeature [punkslanted] [metapost={category=punk,preroll=punkpreroll,slant=.15}] +\definefontfeature [punkboldslanted] [metapost={category=punk,preroll=punkpreroll,slant=.15,weight=2}] +\definefontfeature [punkveryslanted] [metapost={category=punk,preroll=punkpreroll,slant=-.15}] +\definefontfeature [punksqueezed] [metapost={category=punk,preroll=punkpreroll,squeeze=.5}] +\definefontfeature [punkextended] [metapost={category=punk,preroll=punkpreroll,extend=1.3}] + +\continueifinputfile{meta-imp-punk.mkxl} + +% immediate: +% +% \definefontfeature [punk] [metapost=punk] +% \definefontfeature [punkbold] [metapost=punkbold] +% \definefontfeature [punkslanted] [metapost=punkslanted] +% \definefontfeature [punkboldslanted] [metapost=punkboldslanted] + +% delayed: + +% name=punk +% filename=punkfont-characters.mp + +\setupbodyfont[dejavu] + +\definefont[PunkA][Serif*punk] +\definefont[PunkB][Serif*punkbold] +\definefont[PunkC][Serif*punkslanted] +\definefont[PunkD][Serif*punkboldslanted] +\definefont[PunkE][Serif*punkveryslanted] +\definefont[PunkF][Serif*punkrandom] +\definefont[PunkG][Serif*punksqueezed] +\definefont[PunkH][Serif*punkextended] + +\starttext + +\startTEXpage[offset=10pt,width=30cm] + % \showglyphs + {\darkcyan \PunkA \samplefile{tufte} \par} + {\darkmagenta \PunkB \samplefile{tufte} \par} + {\darkred \PunkC \samplefile{tufte} \par} + {\darkgreen \PunkD \samplefile{tufte} \par} + {\darkblue \PunkE \samplefile{tufte} \par} + {\darkyellow \PunkF \enablerandomvariants \samplefile{tufte} \par} + {\darkgray \PunkG \samplefile{tufte} \par} + {\darkorange \PunkH \samplefile{tufte} \par} +\stopTEXpage + +\startTEXpage[offset=10pt,width=2cm] + \PunkF \enablerandomvariants + \dostepwiserecurse{1}{2000}{1}{\glyphscale#1\relax f } +\stopTEXpage + +% \setupbodyfont[dejavu] + +\setupbodyfont[punk] %one first needs to load a bodyfont ! + +\startTEXpage[offset=10pt,width=20cm] + {\darkcyan \tf \samplefile{zapf} \par} + {\darkmagenta \bf \samplefile{zapf} \par} + {\darkred \sl \samplefile{zapf} \par} + {\darkgreen \bs \samplefile{zapf} \par} +\stopTEXpage + +\stoptext diff --git a/tex/context/base/mkxl/mlib-mpf.lmt b/tex/context/base/mkxl/mlib-mpf.lmt index 6bd31376c..d66491a16 100644 --- a/tex/context/base/mkxl/mlib-mpf.lmt +++ b/tex/context/base/mkxl/mlib-mpf.lmt @@ -86,12 +86,10 @@ do else runscripts[nofscripts] = name end --- print("set",name,nofscripts,f) return nofscripts end function metapost.scriptindex(name) --- print("get",name,runnames[name] or 0) return runnames[name] or 0 end @@ -945,9 +943,14 @@ do registerscript("setcount", function() setcount(scanstring(),scannumeric()) end) registerscript("settoks", function() settoks (scanstring(),scanstring()) end) + local utfnum = utf.byte local utflen = utf.len local utfsub = utf.sub + registerscript("utfnum", function() + injectnumeric(utfnum(scanstring())) + end) + registerscript("utflen", function() injectnumeric(utflen(scanstring())) end) diff --git a/tex/context/base/mkxl/node-ext.lmt b/tex/context/base/mkxl/node-ext.lmt new file mode 100644 index 000000000..2f909cd3d --- /dev/null +++ b/tex/context/base/mkxl/node-ext.lmt @@ -0,0 +1,650 @@ +if not modules then modules = { } end modules ['back-out'] = { + version = 1.001, + comment = "companion to back-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local type, unpack, rawset = type, unpack, type +local loadstring = loadstring +local sind, cosd, abs = math.sind, math.cosd, math.abs +local insert, remove = table.insert, table.remove + +local context = context +local implement = interfaces.implement + +local allocate = utilities.storage.allocate + +local formatters = string.formatters + +local get = token.get_index -- getters +local scanners = tokens.scanners +local scaninteger = scanners.integer +local scanstring = scanners.string +local scankeyword = scanners.keyword +local scantokenlist = scanners.tokenlist +local scannumber = scanners.number + +local nuts = nodes.nuts +local tonode = nuts.tonode +local copynut = nuts.copy +local nutpool = nuts.pool +local nodepool = nodes.pool + +local nodeproperties = nodes.properties.data + +local register = nutpool.register +local newnut = nuts.new +local tonode = nodes.tonode + +-- Whatsits are a generic node type with very few fields. We use them to implement +-- whatever we like. Some are good old tex whatsits but many are specific to the +-- macro package. They are part of the backend. + +backends = backends or { } +local backends = backends + +local whatsit_code = nodes.nodecodes.whatsit +local whatsitcodes = allocate { } +nodes.whatsitcodes = whatsitcodes +local lastwhatsit = 0 + +nodes.subtypes.whatsit = whatsitcodes + +local function registerwhatsit(name) + lastwhatsit = lastwhatsit + 1 + whatsitcodes[lastwhatsit] = name + whatsitcodes[name] = lastwhatsit + return lastwhatsit +end + +local function registerwhatsitnode(name) + return register(newnut(whatsit_code,registerwhatsit(name))) +end + +-- We only have a subset of literals. In fact, we try to avoid literals. + +do + + local literalvalues = allocate { } + nodes.literalvalues = literalvalues + local lastliteral = 0 + local literalnode = registerwhatsitnode("literal") + + local function registerliteral(name,alias) + lastliteral = lastliteral + 1 + literalvalues[lastliteral] = name + literalvalues[name] = lastliteral + if alias then + literalvalues[alias] = lastliteral + end + return lastliteral + end + + local originliteral_code = registerliteral("origin") + local pageliteral_code = registerliteral("page") + local directliteral_code = registerliteral("always","direct") + local rawliteral_code = registerliteral("raw") + local textliteral_code = registerliteral("text") -- not to be used + local fontliteral_code = registerliteral("font") -- not to be used + + function nutpool.originliteral(str) local t = copynut(literalnode) nodeproperties[t] = { data = str, mode = originliteral_code } return t end + function nutpool.pageliteral (str) local t = copynut(literalnode) nodeproperties[t] = { data = str, mode = pageliteral_code } return t end + function nutpool.directliteral(str) local t = copynut(literalnode) nodeproperties[t] = { data = str, mode = directliteral_code } return t end + function nutpool.rawliteral (str) local t = copynut(literalnode) nodeproperties[t] = { data = str, mode = rawliteral_code } return t end + + local pdfliterals = { + [originliteral_code] = originliteral_code, [literalvalues[originliteral_code]] = originliteral_code, + [pageliteral_code] = pageliteral_code, [literalvalues[pageliteral_code]] = pageliteral_code, + [directliteral_code] = directliteral_code, [literalvalues[directliteral_code]] = directliteral_code, + [rawliteral_code] = rawliteral_code, [literalvalues[rawliteral_code]] = rawliteral_code, + } + + function nutpool.literal(mode,str) + local t = copynut(literalnode) + if str then + nodeproperties[t] = { data = str, mode = pdfliterals[mode] or pageliteral_code } + else + nodeproperties[t] = { data = mode, mode = pageliteral_code } + end + return t + end + +end + +-- The latelua node is just another whatsit and we handle the \LUA\ code with +-- other \LUA\ code, contrary to \LUATEX\ where it's a native node. + +do + + local getdata = nuts.getdata + local serialize = token.serialize + + local lateluanode = registerwhatsitnode("latelua") + local noflatelua = 0 + + function nutpool.latelua(code) + local n = copynut(lateluanode) + nodeproperties[n] = { data = code } + return n + end + + function backends.latelua(current,pos_h,pos_v) -- todo: pass pos_h and pos_v (more efficient in lmtx) + local p = nodeproperties[current] + if p then + data = p.data + else + data = getdata(current) + end + noflatelua = noflatelua + 1 + local kind = type(data) + if kind == "table" then + data.action(data.specification or data) + elseif kind == "function" then + data() + else + if kind ~= "string" then + data = serialize(data) + end + if #data ~= "" then + local code = loadstring(data) + if code then + code() + end + end + end + end + + function backends.getcallbackstate() + return { count = noflatelua } + end + + implement { + name = "latelua", + public = true, + protected = true, + actions = function() + local node = copynut(lateluanode) + local name = "latelua" + if scankeyword("name") then + name = scanstring() + end + local data = scantokenlist() + nodeproperties[node] = { name = name, data = data } + return context(tonode(node)) + end, + } + +end + +-- This can be anything. Dealing with these nodes is done via properties, as with +-- the other whatsits. + +do + + local usernode = registerwhatsitnode("userdefined") + + local userids = allocate() + local lastid = 0 + + setmetatable(userids, { + __index = function(t,k) + if type(k) == "string" then + lastid = lastid + 1 + rawset(userids,lastid,k) + rawset(userids,k,lastid) + return lastid + else + rawset(userids,k,k) + return k + end + end, + __call = function(t,k) + return t[k] + end + } ) + + function nutpool.userdefined(id,data) + local n = copynut(usernode) + nodeproperties[n] = { id = id, data = data } + return n + end + + nutpool .usernode = nutpool.userdefined + nutpool .userids = userids + nodepool.userids = userids + +end + +-- This one is only used by generic packages. + +do + + local saveposnode = registerwhatsitnode("savepos") + + function nutpool.savepos() + return copynut(saveposnode) + end + +end + +do + + local savenode = registerwhatsitnode("save") + local restorenode = registerwhatsitnode("restore") + local setmatrixnode = registerwhatsitnode("setmatrix") + + local stack = { } + local restore = true -- false + + -- these are old school nodes + + function nutpool.save() + return copynut(savenode) + end + + function nutpool.restore() + return copynut(restorenode) + end + + function nutpool.setmatrix(rx,sx,sy,ry,tx,ty) + local t = copynut(setmatrixnode) + nodeproperties[t] = { matrix = { rx, sx, sy, ry, tx, ty } } + return t + end + + -- common + + local function stopcommon(n) + local top = remove(stack) + if top == false then + return -- not wrapped + elseif top == true then + return copynut(n) + elseif top then + local t = copynut(n) + nodeproperties[t] = { matrix = { unpack(top) } } + return t + else + return -- nesting error + end + end + + -- matrix + + local startmatrixnode = registerwhatsitnode("startmatrix") + local stopmatrixnode = registerwhatsitnode("stopmatrix") + + local function startmatrix(rx, sx, sy, ry) + if rx == 1 and sx == 0 and sy == 0 and ry == 1 then + insert(stack,false) + else + local t = copynut(startmatrixnode) + nodeproperties[t] = { matrix = { rx, sx, sy, ry } } + insert(stack,store and { -rx, -sx, -sy, -ry } or true) + return t + end + end + + local function stopmatrix() + return stopcommon(stopmatrixnode) + end + + implement { + name = "startmatrix", + actions = function() + local rx, sx, sy, ry = 1, 0, 0, 1 + while true do + if scankeyword("rx") then rx = scannumber() + elseif scankeyword("ry") then ry = scannumber() + elseif scankeyword("sx") then sx = scannumber() + elseif scankeyword("sy") then sy = scannumber() + else break end + end + local t = startmatrix(rx,sx,sy,ry) + if t then + context(tonode(t)) + end + end, + } + + implement { + name = "stopmatrix", + actions = function() + local t = stopmatrix(n) + if t then + context(tonode(t)) + end + end, + } + + -- scale + + local startscalingnode = registerwhatsitnode("startscaling") + local stopscalingnode = registerwhatsitnode("stopscaling") + + local function startscaling(rx, ry) -- at the tex end we use sx and sy instead of rx and ry + if rx == 1 and ry == 1 then + insert(stack,false) + else + if rx == 0 then + rx = 0.0001 + end + if ry == 0 then + ry = 0.0001 + end + local t = copynut(startscalingnode) + nodeproperties[t] = { matrix = { rx, 0, 0, ry } } + insert(stack,restore and { 1/rx, 0, 0, 1/ry } or true) + return t + end + end + + local function stopscaling() -- at the tex end we use sx and sy instead of rx and ry + return stopcommon(stopscalingnode) + end + + implement { + name = "startscaling", + actions = function() + local rx, ry = 1, 1 + while true do + if scankeyword("rx") then + rx = scannumber() + elseif scankeyword("ry") then + ry = scannumber() + else + break + end + end + local t = startscaling(rx,ry) + if t then + context(tonode(t)) + end + end, + } + + implement { + name = "stopscaling", + actions = function() + local t = stopscaling(n) + if t then + context(tonode(t)) + end + end, + } + + -- rotate + + local startrotationnode = registerwhatsitnode("startrotation") + local stoprotationnode = registerwhatsitnode("stoprotation") + + local function startrotation(a) + if a == 0 then + insert(stack,false) + else + local s, c = sind(a), cosd(a) + if abs(s) < 0.000001 then + s = 0 -- otherwise funny -0.00000 + end + if abs(c) < 0.000001 then + c = 0 -- otherwise funny -0.00000 + end + local t = copynut(startrotationnode) + nodeproperties[t] = { matrix = { c, s, -s, c } } + insert(stack,restore and { c, -s, s, c } or true) + return t + end + end + + local function stoprotation() + return stopcommon(stoprotationnode) + end + + nutpool.startrotation = startrotation + + implement { + name = "startrotation", + actions = function() + local n = scannumber() + local t = startrotation(n) + if t then + context(tonode(t)) + end + end, + } + + implement { + name = "stoprotation", + actions = function() + local t = stoprotation() + if t then + context(tonode(t)) + end + end, + } + + -- mirror + + local startmirroringnode = registerwhatsitnode("startmirroring") + local stopmirroringnode = registerwhatsitnode("stopmirroring") + + local function startmirroring() + local t = copynut(startmirroringnode) + nodeproperties[t] = { matrix = { -1, 0, 0, 1 } } + return t + end + + local function stopmirroring() + local t = copynut(stopmirroringnode) + nodeproperties[t] = { matrix = { -1, 0, 0, 1 } } + return t + end + + implement { + name = "startmirroring", + actions = function() + context(tonode(startmirroring())) + end, + } + + implement { + name = "stopmirroring", + actions = function() + context(tonode(stopmirroring())) + end, + } + + -- clip + + local startclippingnode = registerwhatsitnode("startclipping") + local stopclippingnode = registerwhatsitnode("stopclipping") + + local function startclipping(path) + local t = copynut(startclippingnode) + nodeproperties[t] = { path = path } + return t + end + + local function stopclipping() + return copynut(stopclippingnode) + end + + implement { + name = "startclipping", + actions = function() + context(tonode(startclipping(scanstring()))) + end + } + + implement { + name = "stopclipping", + actions = function() + context(tonode(stopclipping())) + end, + } + +end + +-- The (delayed and immediate) write operations are emulated in \LUA\ and presented +-- as primitives at the \TEX\ end. + +do + + local logwriter = logs.writer + local openfile = io.open + local flushio = io.flush + local serialize = token.serialize + + local opennode = registerwhatsitnode("open") + local writenode = registerwhatsitnode("write") + local closenode = registerwhatsitnode("close") + local channels = { } + local immediate_code = tex.flagcodes.immediate + + function backends.openout(n) + local p = nodeproperties[n] + if p then + local handle = openfile(p.filename,"wb") or false + if handle then + channels[p.channel] = handle + else + -- error + end + end + end + + function backends.writeout(n) + local p = nodeproperties[n] + if p then + local handle = channels[p.channel] + local content = serialize(p.data) + if handle then + handle:write(content,"\n") + else + logwriter(content,"\n") + end + end + end + + function backends.closeout(n) + local p = nodeproperties[n] + if p then + local channel = p.channel + local handle = channels[channel] + if handle then + handle:close() + channels[channel] = false + flushio() + else + -- error + end + end + end + + local function immediately(prefix) + return prefix and (prefix & immediate_code) ~= 0 + end + + implement { + name = "openout", + public = true, + usage = "value", + actions = function(prefix) + local channel = scaninteger() + scankeyword("=") -- hack + local filename = scanstring() + if not immediately(prefix) then + local n = copynut(opennode) + nodeproperties[n] = { channel = channel, filename = filename } -- action = "open" + return context(tonode(n)) + elseif not channels[channel] then + local handle = openfile(filename,"wb") or false + if handle then + channels[channel] = handle + else + -- error + end + end + end, + } + + implement { + name = "write", + public = true, + usage = "value", + actions = function(prefix) + local channel = scaninteger() + if not immediately(prefix) then + local t = scantokenlist() + local n = copynut(writenode) + nodeproperties[n] = { channel = channel, data = t } -- action = "write" + return context(tonode(n)) + else + local content = scanstring() + local handle = channels[channel] + if handle then + handle:write(content,"\n") + else + logwriter(content,"\n") + end + end + end, + } + + implement { + name = "closeout", + public = true, + usage = "value", + actions = function(prefix) + local channel = scaninteger() + if not immediately(prefix) then + local n = copynut(closenode) + nodeproperties[n] = { channel = channel } -- action = "close" + return context(tonode(n)) + else + local handle = channels[channel] + if handle then + handle:close() + channels[channel] = false + flushio() + else + -- error + end + end + end, + } + + -- why ... + + local open_command = get(token.create("openout")) + local write_command = get(token.create("write")) + local close_command = get(token.create("closeout")) + +end + +-- states: these get injected independent of grouping + +do + + local setstatenode = registerwhatsitnode("setstate") + + function nutpool.setstate(data) + local n = copynut(setstatenode) + nodeproperties[n] = { data = data } + return n + end + +end + +-- We don't support specials so we make them dummies. + +do + implement { + name = "special", + actions = scanstring, + public = true, + protected = true, + } +end diff --git a/tex/context/base/mkxl/node-fin.lmt b/tex/context/base/mkxl/node-fin.lmt index dab90863a..a9180ddb2 100644 --- a/tex/context/base/mkxl/node-fin.lmt +++ b/tex/context/base/mkxl/node-fin.lmt @@ -36,6 +36,7 @@ local setlist = nuts.setlist local setleader = nuts.setleader local copy_node = nuts.copy +local find_tail = nuts.tail local insert_node_before = nuts.insert_before local insert_node_after = nuts.insert_after @@ -165,13 +166,15 @@ function states.finalize(namespace,attribute,head) -- is this one ok? if id == hlist_code or id == vlist_code then local content = getlist(head) if content then - local list = insert_node_before(content,content,copy_node(nsnone)) -- two return values +-- local list = insert_node_before(content,content,copy_node(nsnone)) -- two return values + local list = insert_node_after(content,find_tail(content),copy_node(nsnone)) -- two return values if list ~= content then setlist(head,list) end end else - head = insert_node_before(head,head,copy_node(nsnone)) +-- head = insert_node_before(head,head,copy_node(nsnone)) + head = insert_node_after(find_tail(head),head,copy_node(nsnone)) end return head, true end @@ -295,6 +298,75 @@ states.process = function(namespace,attribute,head,default) return process(attribute,head,default) end +local function simple(attribute,head) + local check = false + local leader = nil + for stack, id, subtype, content in nextcontent, head do + if id == glyph_code or id == disc_code then + check = true + elseif id == glue_code then + check = true + leader = content + elseif id == hlist_code or id == vlist_code then + if getorientation(stack) then + local outer = getattr(stack,attribute) + if outer then + if current ~= outer then + if current > 0 then + head = insert_node_before(head,stack,copy_node(nsnone)) + end + head = insert_node_before(head,stack,copy_node(nsdata[c])) + current = outer + end + elseif current > 0 then + head = insert_node_before(head,stack,copy_node(nsnone)) + current = 0 + end + end + local list = simple(attribute,content) + if content ~= list then + setlist(stack,list) + end + elseif id == rule_code then + check = has_dimensions(stack) + end + if check then + local c = getattr(stack,attribute) + if c then + if current ~= c then + if current > 0 then + head = insert_node_before(head,stack,copy_node(nsnone)) + end + head = insert_node_before(head,stack,copy_node(nsdata[c])) + current = c + end + if leader then + local savedcurrent = current + local ci = getid(leader) + if ci == hlist_code or ci == vlist_code then + current = 0 + end + local list = simple(attribute,leader) + if leader ~= list then + setleader(stack,list) + end + current = savedcurrent + leader = false + end + elseif current > 0 then + head = insert_node_before(head,stack,copy_node(nsnone)) + current = 0 + end + check = false + end + end + return head +end + +states.simple = function(namespace,attribute,head,default) + return simple(attribute,head,default) +end + -- we can force a selector, e.g. document wide color spaces, saves a little -- watch out, we need to check both the selector state (like colorspace) and -- the main state (like color), otherwise we get into troubles when a selector diff --git a/tex/context/base/mkxl/node-ini.lmt b/tex/context/base/mkxl/node-ini.lmt index 0fba0a4d9..4ba4b4000 100644 --- a/tex/context/base/mkxl/node-ini.lmt +++ b/tex/context/base/mkxl/node-ini.lmt @@ -65,31 +65,6 @@ local function simplified(t) return r end -local nodecodes = simplified(node.types()) - -local whatcodes = allocate { - literal = 0x1, [0x1] = "literal", - latelua = 0x2, [0x2] = "latelua", - userdefined = 0x3, [0x3] = "userdefined", - savepos = 0x4, [0x4] = "savepos", - save = 0x5, [0x5] = "save", - restore = 0x6, [0x6] = "restore", - setmatrix = 0x7, [0x7] = "setmatrix", - open = 0x8, [0x8] = "open", - close = 0x9, [0x9] = "close", - write = 0xA, [0xA] = "write", -} - -local usercodes = allocate { - [ 97] = "attribute", -- a - [100] = "number", -- d - [102] = "float", -- f - [108] = "lua", -- l - [110] = "node", -- n - [115] = "string", -- s - [116] = "token" -- t -} - local noadoptions = allocate { set = 0x08, unused_1 = 0x00 + 0x08, @@ -102,15 +77,7 @@ local noadoptions = allocate { right = 0x14 + 0x08, } -local literalvalues = allocate { - [0] = "origin", - [1] = "page", - [2] = "always", - [3] = "raw", - [4] = "text", - [5] = "font", - [6] = "special", -} +local nodecodes = simplified(node.types()) gluecodes = allocate(swapped(gluecodes,gluecodes)) dircodes = allocate(swapped(dircodes,dircodes)) @@ -118,7 +85,6 @@ boundarycodes = allocate(swapped(boundarycodes,boundarycodes)) noadcodes = allocate(swapped(noadcodes,noadcodes)) radicalcodes = allocate(swapped(radicalcodes,radicalcodes)) nodecodes = allocate(swapped(nodecodes,nodecodes)) -whatcodes = allocate(swapped(whatcodes,whatcodes)) listcodes = allocate(swapped(listcodes,listcodes)) glyphcodes = allocate(swapped(glyphcodes,glyphcodes)) kerncodes = allocate(swapped(kerncodes,kerncodes)) @@ -129,18 +95,15 @@ accentcodes = allocate(swapped(accentcodes,accentcodes)) fencecodes = allocate(swapped(fencecodes,fencecodes)) parcodes = allocate(swapped(parcodes,parcodes)) rulecodes = allocate(swapped(rulecodes,rulecodes)) -usercodes = allocate(swapped(usercodes,usercodes)) noadoptions = allocate(swapped(noadoptions,noadoptions)) dirvalues = allocate(swapped(dirvalues,dirvalues)) -literalvalues = allocate(swapped(literalvalues,literalvalues)) fillvalues = allocate(swapped(fillvalues,fillvalues)) nodes.gluecodes = gluecodes nodes.dircodes = dircodes nodes.boundarycodes = boundarycodes nodes.noadcodes = noadcodes -nodes.whatcodes = whatcodes nodes.listcodes = listcodes nodes.glyphcodes = glyphcodes nodes.kerncodes = kerncodes @@ -152,13 +115,11 @@ nodes.radicalcodes = radicalcodes nodes.fencecodes = fencecodes nodes.parcodes = parcodes nodes.rulecodes = rulecodes -nodes.usercodes = usercodes nodes.noadoptions = noadoptions nodes.fillvalues = fillvalues nodes.fillcodes = fillvalues -- for now nodes.dirvalues = dirvalues -nodes.literalvalues = literalvalues nodes.nodecodes = nodecodes @@ -167,7 +128,6 @@ local subtypes = allocate { dir = dircodes, boundary = boundarycodes, noad = noadcodes, - whatsit = whatcodes, glyph = glyphcodes, kern = kerncodes, penalty = penaltycodes, @@ -201,11 +161,9 @@ nodes.subtypes = subtypes nodes.skipcodes = gluecodes nodes.directioncodes = dircodes -nodes.whatsitcodes = whatcodes nodes.discretionarycodes = disccodes nodes.directionvalues = dirvalues -nodes.literalvalues = literalvalues glyphcodes.glyph = glyphcodes.character @@ -218,8 +176,6 @@ listcodes.column = listcodes.alignment kerncodes.kerning = kerncodes.fontkern kerncodes.italiccorrection = kerncodes.italiccorrection or 1 -- new -literalvalues.direct = literalvalues.always - nodes.noadoptions = { set = 0x08, unused_1 = 0x00 + 0x08, diff --git a/tex/context/base/mkxl/node-ini.mkxl b/tex/context/base/mkxl/node-ini.mkxl index 4de4e00b4..b3f17e041 100644 --- a/tex/context/base/mkxl/node-ini.mkxl +++ b/tex/context/base/mkxl/node-ini.mkxl @@ -22,6 +22,7 @@ \registerctxluafile{node-met}{autosuffix} \registerctxluafile{node-nut}{autosuffix} \registerctxluafile{node-res}{autosuffix} +\registerctxluafile{node-ext}{autosuffix} %registerctxluafile{node-ppt}{} % experimental, not used so probably useless \registerctxluafile{node-aux}{autosuffix} \registerctxluafile{node-gcm}{autosuffix} @@ -33,11 +34,10 @@ \registerctxluafile{node-dir}{} % experimental, not yet (and maybe never) used \registerctxluafile{node-pro}{autosuffix} \registerctxluafile{node-ser}{autosuffix} -%registerctxluafile{node-ext}{} \registerctxluafile{node-acc}{autosuffix} % experimental %registerctxluafile{node-prp}{} % makes no sense (yet) \registerctxluafile{node-scn}{autosuffix} -\registerctxluafile{node-syn}{} +\registerctxluafile{node-syn}{autosuffix} \registerctxluafile{node-par}{autosuffix} %D This might go away (needs checking anyway, very old code): diff --git a/tex/context/base/mkxl/node-res.lmt b/tex/context/base/mkxl/node-res.lmt index 7a37b1b9e..fbb1d1fe2 100644 --- a/tex/context/base/mkxl/node-res.lmt +++ b/tex/context/base/mkxl/node-res.lmt @@ -6,7 +6,7 @@ if not modules then modules = { } end modules ['node-res'] = { license = "see context related readme files" } -local type, next = type, next +local type, next, rawset = type, next, rawset local gmatch, format = string.gmatch, string.format --[[ldx-- @@ -21,7 +21,6 @@ local report_nodes = logs.reporter("nodes","housekeeping") nodes.pool = nodes.pool or { } local nodepool = nodes.pool -local whatsitcodes = nodes.whatsitcodes local gluecodes = nodes.gluecodes local kerncodes = nodes.kerncodes local rulecodes = nodes.rulecodes @@ -36,7 +35,6 @@ local rule_code = nodecodes.rule local kern_code = nodecodes.kern local glue_code = nodecodes.glue local gluespec_code = nodecodes.gluespec -local whatsit_code = nodecodes.whatsit local currentfont = font.current local texgetcount = tex.getcount @@ -45,25 +43,6 @@ local allocate = utilities.storage.allocate local reserved = { } local nofreserved = 0 -local userids = allocate() -local lastid = 0 - -setmetatable(userids, { - __index = function(t,k) - if type(k) == "string" then - lastid = lastid + 1 - rawset(userids,lastid,k) - rawset(userids,k,lastid) - return lastid - else - rawset(userids,k,k) - return k - end - end, - __call = function(t,k) - return t[k] - end -} ) -- nuts overload @@ -149,10 +128,7 @@ local function register_node(n) return n end -nodepool.userids = userids nodepool.register = register_node - -nutpool.userids = userids nutpool.register = register_node -- could be register_nut -- so far @@ -168,11 +144,6 @@ local glyph = register_nut(new_nut(glyph_code,0)) local textdir = register_nut(new_nut(nodecodes.dir)) -local latelua = register_nut(new_nut(whatsit_code,whatsitcodes.latelua)) -local savepos = register_nut(new_nut(whatsit_code,whatsitcodes.savepos)) - -local user_node = new_nut(whatsit_code,whatsitcodes.userdefined) - local left_margin_kern = register_nut(new_nut(kern_code,kerncodes.leftmargincode)) local right_margin_kern = register_nut(new_nut(kern_code,kerncodes.rightmargincode)) @@ -414,16 +385,6 @@ function nutpool.leader(width,list) return n end -function nutpool.savepos() - return copy_nut(savepos) -end - -function nutpool.latelua(code) - local n = copy_nut(latelua) - nodeproperties[n] = { data = code } - return n -end - function nutpool.leftmarginkern(glyph,width) local n = copy_nut(left_margin_kern) if not glyph then diff --git a/tex/context/base/mkxl/node-syn.lmt b/tex/context/base/mkxl/node-syn.lmt new file mode 100644 index 000000000..ce5f0d2dd --- /dev/null +++ b/tex/context/base/mkxl/node-syn.lmt @@ -0,0 +1,782 @@ +if not modules then modules = { } end modules ['node-syn'] = { + version = 1.001, + comment = "companion to node-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- Because we have these fields in some node that are used by synctex, and because +-- some users seem to like that feature, I decided to implement a variant that might +-- work out better for ConTeXt. This is experimental code. I don't use it myself so +-- it will take a while to mature. There will be some helpers that one can use in +-- more complex situations like included xml files. Currently (somewhere else) we +-- take care of valid files, that is: we prohibit access to files in the tree +-- because we don't want users to mess up styles. +-- +-- It is unclear how the output gets interpreted but by reverse engineering (and +-- stripping) the file generated by generic synctex, I got there eventually. For +-- instance, we only need to be able to go back to a place where text is entered, +-- but still we need all that redundant box wrapping. Anyway, I was able to get a +-- minimal output and cross my fingers that the parser used in editors is not +-- changed in fundamental ways. +-- +-- I only tested SumatraPDF with SciTE, for which one needs to configure in the +-- viewer: +-- +-- InverseSearchCmdLine = c:\data\system\scite\wscite\scite.exe "%f" "-goto:%l" $ +-- +-- In fact, a way more powerful implementation would have been not to add a library +-- to a viewer, but letthe viewer call an external program: +-- +-- InverseSearchCmdLine = mtxrun.exe --script synctex --edit --name="%f" --line="%l" $ +-- +-- which would (re)launch the editor in the right spot. That way we can really +-- tune well to the macro package used and also avoid the fuzzy heuristics of +-- the library. +-- +-- Unfortunately syntex always removes the files at the end and not at the start +-- (this happens in synctexterminate) so we need to work around that by using an +-- intermediate file. This is no big deal in context (which has a runner) but +-- definitely not nice. +-- +-- The visualizer code is only needed for testing so we don't use fancy colors or +-- provide more detail. After all we're only interested in rendered source text +-- anyway. We try to play safe which sometimes means that we'd better no go +-- somewhere than go someplace wrong. +-- +-- A previous version had a mode for exporting boxes and such but I removed that +-- as it made no sense. Also, collecting output in a table was not faster than +-- directly piping to the file, probably because the amount is not that large. We +-- keep some left-overs commented. +-- +-- A significate reduction in file size can be realized when reusing the same +-- values. Actually that triggered the current approach in ConTeXt. In the latest +-- synctex parser vertical positions can be repeated by an "=" sign but for some +-- reason only for that field. It's probably trivial to do that for all of "w h d v +-- h" but it currently not the case so I'll delay that till all are supported. (We +-- could benefit a lot from such a repetition scheme but not much from a "v" alone +-- which -alas- indicates that synctex is still mostly a latex targeted story.) +-- +-- It's kind of hard to fight the parser because it really wants to go to some file +-- but maybe some day I can figure it out. Some untagged text (in the pdf) somehow +-- gets seen as part of the last box. Anonymous content is simply not part of the +-- concept. Using a dummy name doesn't help either as the editor gets a signal to +-- open that dummy. Even an empty filename doesn't work. +-- +-- We output really simple and compact code, like: +-- +-- SyncTeX Version:1 +-- Input:1:e:/tmp/oeps.tex +-- Input:2:c:/data/develop/context/sources/klein.tex +-- Output:pdf +-- Magnification:1000 +-- Unit:1 +-- X Offset:0 +-- Y Offset:0 +-- Content: +-- !160 +-- {1 +-- h0,0:0,0,0,0,0 +-- v0,0:0,55380990:39158276,55380990,0 +-- h2,1:4661756,9176901:27969941,655360,327680 +-- h2,2:4661756,10125967:26048041,655360,327680 +-- h2,3:30962888,10125967:1668809,655360,327680 +-- h2,3:4661756,11075033:23142527,655360,327680 +-- h2,4:28046650,11075033:4585047,655360,327680 +-- h2,4:4661756,12024099:22913954,655360,327680 +-- h2,5:27908377,12024099:4723320,655360,327680 +-- h2,5:4661756,12973165:22918783,655360,327680 +-- h2,6:27884864,12973165:4746833,655360,327680 +-- h2,6:4661756,13922231:18320732,655360,327680 +-- ] +-- !533 +-- }1 +-- Input:3:c:/data/develop/context/sources/ward.tex +-- !57 +-- {2 +-- h0,0:0,0,0,0,0 +-- v0,0:0,55380990:39158276,55380990,0 +-- h3,1:4661756,9176901:18813145,655360,327680 +-- h3,2:23713999,9176901:8917698,655360,327680 +-- h3,2:4661756,10125967:10512978,655360,327680 +-- h3,3:15457206,10125967:17174491,655360,327680 +-- h3,3:4661756,11075033:3571223,655360,327680 +-- h3,4:8459505,11075033:19885281,655360,327680 +-- h3,5:28571312,11075033:4060385,655360,327680 +-- h3,5:4661756,12024099:15344870,655360,327680 +-- ] +-- !441 +-- }2 +-- !8 +-- Postamble: +-- Count:22 +-- !23 +-- Post scriptum: +-- +-- But for some reason, when the pdf file has some extra content (like page numbers) +-- the main document is consulted. Bah. It would be nice to have a mode for *only* +-- looking at marked areas. It somehow works not but maybe depends on the parser. +-- +-- Supporting reuseable objects makes not much sense as these are often graphics or +-- ornamental. They can not have hyperlinks etc (at least not without some hackery +-- which I'm not willing to do) so basically they are sort of useless for text. +-- +-- Some generic (more clever code) has been removed as I don't see things change +-- that much. + +local type, rawset = type, rawset +local concat = table.concat +local formatters = string.formatters +local replacesuffix, suffixonly, nameonly = file.replacesuffix, file.suffix, file.nameonly +local openfile, renamefile, removefile = io.open, os.rename, os.remove + +local report_system = logs.reporter("system") + +local tex = tex +local texget = tex.get + +local nuts = nodes.nuts + +local getid = nuts.getid +local getlist = nuts.getlist +local setlist = nuts.setlist +local getnext = nuts.getnext +local getwhd = nuts.getwhd +local getwidth = nuts.getwidth +local getsubtype = nuts.getsubtype + +local nodecodes = nodes.nodecodes +local kerncodes = nodes.kerncodes + +local glyph_code = nodecodes.glyph +local disc_code = nodecodes.disc +local glue_code = nodecodes.glue +local penalty_code = nodecodes.penalty +local kern_code = nodecodes.kern +----- rule_code = nodecodes.rule +local hlist_code = nodecodes.hlist +local vlist_code = nodecodes.vlist +local dir_code = nodecodes.dir +local fontkern_code = kerncodes.fontkern + +local cancel_code = nodes.dircodes.cancel + +local insert_before = nuts.insert_before +local insert_after = nuts.insert_after + +local nodepool = nuts.pool +local new_latelua = nodepool.latelua +local new_rule = nodepool.rule +local new_kern = nodepool.kern + +local getdimensions = nuts.dimensions +local getrangedimensions = nuts.rangedimensions + +local getsynctexfields = nuts.getsynctexfields or nuts.get_synctex_fields +local forcesynctextag = tex.forcesynctextag or tex.force_synctex_tag +local forcesynctexline = tex.forcesynctexline or tex.force_synctex_line +local getsynctexline = tex.getsynctexline or tex.get_synctex_line +local setsynctexmode = tex.setsynctexmode or tex.set_synctex_mode + +local foundintree = resolvers.foundintree + +local getpagedimensions = layouts.getpagedimensions + +local eol = "\010" + +----- f_glue = formatters["g%i,%i:%i,%i\010"] +----- f_glyph = formatters["x%i,%i:%i,%i\010"] +----- f_kern = formatters["k%i,%i:%i,%i:%i\010"] +----- f_rule = formatters["r%i,%i:%i,%i:%i,%i,%i\010"] +----- f_form = formatters["f%i,%i,%i\010"] +local z_hlist = "[0,0:0,0:0,0,0\010" +local z_vlist = "(0,0:0,0:0,0,0\010" +----- z_xform = "<0,0:0,0,0\010" -- or so +local s_hlist = "]\010" +local s_vlist = ")\010" +----- s_xform = ">\010" +local f_hlist_1 = formatters["h%i,%i:%i,%i:%i,%i,%i\010"] +local f_hlist_2 = formatters["h%i,%i:%i,%s:%i,%i,%i\010"] +local f_vlist_1 = formatters["v%i,%i:%i,%i:%i,%i,%i\010"] +local f_vlist_2 = formatters["v%i,%i:%i,%s:%i,%i,%i\010"] + +local synctex = luatex.synctex or { } +luatex.synctex = synctex + +local getpos ; getpos = function() getpos = job.positions.getpos return getpos() end + +-- status stuff + +local enabled = false +local paused = 0 +local used = false +local never = false + +-- the file name stuff + +local noftags = 0 +local stnums = { } +local nofblocked = 0 +local blockedfilenames = { } +local blockedsuffixes = { + mkii = true, + mkiv = true, + mkvi = true, + mkxl = true, + mklx = true, + mkix = true, + mkxi = true, + -- lfg = true, +} + +local sttags = table.setmetatableindex(function(t,name) + if blockedsuffixes[suffixonly(name)] then + -- Just so that I don't get the ones on my development tree. + nofblocked = nofblocked + 1 + return 0 + elseif blockedfilenames[nameonly(name)] then + -- So we can block specific files. + nofblocked = nofblocked + 1 + return 0 + elseif foundintree(name) then + -- One shouldn't edit styles etc this way. + nofblocked = nofblocked + 1 + return 0 + else + noftags = noftags + 1 + t[name] = noftags + stnums[noftags] = name + return noftags + end +end) + +function synctex.blockfilename(name) + blockedfilenames[nameonly(name)] = name +end + +function synctex.setfilename(name,line) + if paused == 0 and name then + forcesynctextag(sttags[name]) + if line then + forcesynctexline(line) + end + end +end + +function synctex.resetfilename() + if paused == 0 then + forcesynctextag(0) + forcesynctexline(0) + end +end + +do + + local nesting = 0 + local ignored = false + + function synctex.pushline() + nesting = nesting + 1 + if nesting == 1 then + local l = getsynctexline() + ignored = l and l > 0 + if not ignored then + forcesynctexline(texget("inputlineno")) + end + end + end + + function synctex.popline() + if nesting == 1 then + if not ignored then + forcesynctexline() + ignored = false + end + end + nesting = nesting - 1 + end + +end + +-- the node stuff + +local filehandle = nil +local nofsheets = 0 +local nofobjects = 0 +local last = 0 +local filesdone = 0 +local tmpfile = false +local logfile = false + +local function writeanchor() + local size = filehandle:seek("end") + filehandle:write("!",size-last,eol) + last = size +end + +local function writefiles() + local total = #stnums + if filesdone < total then + for i=filesdone+1,total do + filehandle:write("Input:",i,":",stnums[i],eol) + end + filesdone = total + end +end + +local function makenames() + logfile = replacesuffix(tex.jobname,"synctex") + tmpfile = replacesuffix(logfile,"syncctx") +end + +local function flushpreamble() + makenames() + filehandle = openfile(tmpfile,"wb") + if filehandle then + filehandle:write("SyncTeX Version:1",eol) + writefiles() + filehandle:write("Output:pdf",eol) + filehandle:write("Magnification:1000",eol) + filehandle:write("Unit:1",eol) + filehandle:write("X Offset:0",eol) + filehandle:write("Y Offset:0",eol) + filehandle:write("Content:",eol) + flushpreamble = function() + writefiles() + return filehandle + end + else + enabled = false + end + return filehandle +end + +function synctex.wrapup() + if tmpfile then + renamefile(tmpfile,logfile) + tmpfile = nil + end +end + +local function flushpostamble() + if not filehandle then + return + end + writeanchor() + filehandle:write("Postamble:",eol) + filehandle:write("Count:",nofobjects,eol) + writeanchor() + filehandle:write("Post scriptum:",eol) + filehandle:close() + enabled = false +end + +local x_hlist do + + local function doaction_1(t,l,w,h,d) + local pagewidth, pageheight = getpagedimensions() + local x, y = getpos() + filehandle:write(f_hlist_1(t,l,x,pageheight-y,w,h,d)) + nofobjects = nofobjects + 1 + end + + local lasty = false + + local function doaction_2(t,l,w,h,d) + local pagewidth, pageheight = getpagedimensions() + local x, y = getpos() + y = pageheight - y + filehandle:write(f_hlist_2(t,l,x,y == lasty and "=" or y,w,h,d)) + lasty = y + nofobjects = nofobjects + 1 + end + + local doaction = doaction_1 + + x_hlist = function(head,current,t,l,w,h,d) + if filehandle then + return insert_before(head,current,new_latelua(function() doaction(t,l,w,h,d) end)) + else + return head + end + end + + directives.register("system.synctex.compression", function(v) + doaction = tonumber(v) == 2 and doaction_2 or doaction_1 + end) + +end + +-- color is already handled so no colors + +local collect = nil +local fulltrace = false +local trace = false +local height = 10 * 65536 +local depth = 5 * 65536 +local traceheight = 32768 +local tracedepth = 32768 + +trackers.register("system.synctex.visualize", function(v) + trace = v + fulltrace = v == "real" +end) + +local function inject(head,first,last,tag,line) + local w, h, d = getdimensions(first,getnext(last)) + if h < height then + h = height + end + if d < depth then + d = depth + end + if trace then + head = insert_before(head,first,new_rule(w,fulltrace and h or traceheight,fulltrace and d or tracedepth)) + head = insert_before(head,first,new_kern(-w)) + end + head = x_hlist(head,first,tag,line,w,h,d) + return head +end + +local function collect_min(head) + local current = head + while current do + local id = getid(current) + if id == glyph_code then + local first = current + local last = current + local tag = 0 + local line = 0 + while true do + if id == glyph_code then + local tc, lc = getsynctexfields(current) + if tc and tc > 0 then + tag = tc + line = lc + end + last = current + elseif id == disc_code or (id == kern_code and getsubtype(current) == fontkern_code) then + last = current + else + if tag > 0 then + head = inject(head,first,last,tag,line) + end + break + end + current = getnext(current) + if current then + id = getid(current) + else + if tag > 0 then + head = inject(head,first,last,tag,line) + end + return head + end + end + end + -- pick up (as id can have changed) + if id == hlist_code or id == vlist_code then + local list = getlist(current) + if list then + local l = collect(list) + if l ~= list then + setlist(current,l) + end + end + end + current = getnext(current) + end + return head +end + +local function inject(parent,head,first,last,tag,line) + local w, h, d = getrangedimensions(parent,first,getnext(last)) + if h < height then + h = height + end + if d < depth then + d = depth + end + if trace then + head = insert_before(head,first,new_rule(w,fulltrace and h or traceheight,fulltrace and d or tracedepth)) + head = insert_before(head,first,new_kern(-w)) + end + head = x_hlist(head,first,tag,line,w,h,d) + return head +end + +local function collect_max(head,parent) + local current = head + while current do + local id = getid(current) + if id == glyph_code then + local first = current + local last = current + local tag = 0 + local line = 0 + while true do + if id == glyph_code then + local tc, lc = getsynctexfields(current) + if tc and tc > 0 then + if tag > 0 and (tag ~= tc or line ~= lc) then + head = inject(parent,head,first,last,tag,line) + first = current + end + tag = tc + line = lc + last = current + else + if tag > 0 then + head = inject(parent,head,first,last,tag,line) + tag = 0 + end + first = nil + last = nil + end + elseif id == disc_code then + if not first then + first = current + end + last = current + elseif id == kern_code and getsubtype(current) == fontkern_code then + if first then + last = current + end + elseif id == glue_code then + if tag > 0 then + local tc, lc = getsynctexfields(current) + if tc and tc > 0 then + if tag ~= tc or line ~= lc then + head = inject(parent,head,first,last,tag,line) + tag = 0 + break + end + else + head = inject(parent,head,first,last,tag,line) + tag = 0 + break + end + else + tag = 0 + break + end + id = nil -- so no test later on + elseif id == penalty_code then + -- go on (and be nice for math) + else + if tag > 0 then + head = inject(parent,head,first,last,tag,line) + tag = 0 + end + break + end + current = getnext(current) + if current then + id = getid(current) + else + if tag > 0 then + head = inject(parent,head,first,last,tag,line) + end + return head + end + end + end + -- pick up (as id can have changed) + if id == hlist_code or id == vlist_code then + local list = getlist(current) + if list then + local l = collect(list,current) + if l and l ~= list then + setlist(current,l) + end + end + end + current = getnext(current) + end + return head +end + +collect = collect_max + +function synctex.collect(head,where) + if enabled and where ~= "object" then + return collect(head,head) + else + return head + end +end + +-- also no solution for bad first file resolving in sumatra + +function synctex.start() + if enabled then + nofsheets = nofsheets + 1 -- could be realpageno + if flushpreamble() then + writeanchor() + filehandle:write("{",nofsheets,eol) + -- this seems to work: + local pagewidth, pageheight = getpagedimensions() + filehandle:write(z_hlist) + filehandle:write(f_vlist_1(0,0,0,pageheight,pagewidth,pageheight,0)) + end + end +end + +function synctex.stop() + if enabled then + -- filehandle:write(s_vlist,s_hlist) + filehandle:write(s_hlist) + writeanchor() + filehandle:write("}",nofsheets,eol) + nofobjects = nofobjects + 2 + end +end + +local enablers = { } +local disablers = { } + +function synctex.registerenabler(f) + enablers[#enablers+1] = f +end + +function synctex.registerdisabler(f) + disablers[#disablers+1] = f +end + +function synctex.enable() + if not never and not enabled then + enabled = true + setsynctexmode(3) -- we want details + if not used then + nodes.tasks.enableaction("shipouts","luatex.synctex.collect") + report_system("synctex functionality is enabled, expect 5-10 pct runtime overhead!") + used = true + end + for i=1,#enablers do + enablers[i](true) + end + end +end + +function synctex.disable() + if enabled then + setsynctexmode(0) + report_system("synctex functionality is disabled!") + enabled = false + for i=1,#disablers do + disablers[i](false) + end + end +end + +function synctex.finish() + if enabled then + flushpostamble() + else + makenames() + removefile(logfile) + removefile(tmpfile) + end +end + +local filename = nil + +function synctex.pause() + paused = paused + 1 + if enabled and paused == 1 then + setsynctexmode(0) + end +end + +function synctex.resume() + if enabled and paused == 1 then + setsynctexmode(3) + end + paused = paused - 1 +end + +-- not the best place + +luatex.registerstopactions(synctex.finish) + +statistics.register("synctex tracing",function() + if used then + return string.format("%i referenced files, %i files ignored, %i objects flushed, logfile: %s", + noftags,nofblocked,nofobjects,logfile) + end +end) + +local implement = interfaces.implement +local variables = interfaces.variables + +function synctex.setup(t) + if t.state == variables.never then + synctex.disable() -- just in case + never = true + return + end + if t.method == variables.max then + collect = collect_max + else + collect = collect_min + end + if t.state == variables.start then + synctex.enable() + else + synctex.disable() + end +end + +implement { + name = "synctexblockfilename", + arguments = "string", + actions = synctex.blockfilename, +} + +implement { + name = "synctexsetfilename", + arguments = "string", + actions = synctex.setfilename, +} + +implement { + name = "synctexresetfilename", + actions = synctex.resetfilename, +} + +implement { + name = "setupsynctex", + actions = synctex.setup, + arguments = { + { + { "state" }, + { "method" }, + }, + }, +} + +implement { + name = "synctexpause", + actions = synctex.pause, +} + +implement { + name = "synctexresume", + actions = synctex.resume, +} + +implement { + name = "synctexpushline", + actions = synctex.pushline, +} + +implement { + name = "synctexpopline", + actions = synctex.popline, +} + +implement { + name = "synctexdisable", + actions = synctex.disable, +} diff --git a/tex/context/base/mkxl/node-tra.lmt b/tex/context/base/mkxl/node-tra.lmt index da3cb1d33..6060522be 100644 --- a/tex/context/base/mkxl/node-tra.lmt +++ b/tex/context/base/mkxl/node-tra.lmt @@ -704,7 +704,7 @@ table.setmetatableindex(nodestracerpool,function(t,k,v) return v end) -function nutstracerpool.rule(w,h,d,c,s) -- so some day we can consider using literals (speedup) +function nutstracerpool.rule(w,h,d,c,s) return setproperties(new_rule(w,h,d),c,s) end diff --git a/tex/context/base/mkxl/page-lin.lmt b/tex/context/base/mkxl/page-lin.lmt index 9ea502899..f50031ab3 100644 --- a/tex/context/base/mkxl/page-lin.lmt +++ b/tex/context/base/mkxl/page-lin.lmt @@ -192,7 +192,7 @@ local function resolve(n,m) -- we can now check the 'line' flag (todo) if content then if id == hlist_code then for current, subtype in nextwhatsit, content do - if subtype == latelua_code then + if subtype == latelua_code then -- this has to change! local a = getattr(current,a_linereference) if a then cross_references[a] = m diff --git a/tex/context/base/mkxl/scrn-pag.lmt b/tex/context/base/mkxl/scrn-pag.lmt new file mode 100644 index 000000000..210a57707 --- /dev/null +++ b/tex/context/base/mkxl/scrn-pag.lmt @@ -0,0 +1,56 @@ +if not modules then modules = { } end modules ['scrn-pag'] = { + version = 1.001, + comment = "companion to scrn-pag.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +interactions = interactions or { } +interactions.pages = interactions.pages or { } +local pages = interactions.pages + +local implement = interfaces.implement + +pages.setupcanvas = layouts.setupcanvas + +local codeinjections = backends.codeinjections + +function pages.setpagetransition(specification) + codeinjections.setpagetransition(specification) +end + +implement { + name = "setupcanvas", + actions = pages.setupcanvas, + arguments = { + { + { "mode" }, + { "singlesided", "boolean" }, + { "doublesided", "boolean" }, + { "leftoffset", "dimen" }, + { "topoffset", "dimen" }, + { "width", "dimen" }, + { "height", "dimen" }, + { "paperwidth", "dimen" }, + { "paperheight", "dimen" }, + { "cropoffset", "dimen" }, + { "bleedoffset", "dimen" }, + { "artoffset", "dimen" }, + { "trimoffset", "dimen" }, + { "copies", "integer" }, + { "print", "string" }, -- , tohash + } + } +} + +implement { + name = "setpagetransition", + actions = pages.setpagetransition, + arguments = { + { + { "n" }, + { "delay", "integer" }, + } + } +} diff --git a/tex/context/base/mkxl/scrn-pag.mklx b/tex/context/base/mkxl/scrn-pag.mklx index 80e16f63d..67e24178e 100644 --- a/tex/context/base/mkxl/scrn-pag.mklx +++ b/tex/context/base/mkxl/scrn-pag.mklx @@ -15,7 +15,7 @@ \writestatus{loading}{ConTeXt Screen Macros / Pages} -\registerctxluafile{scrn-pag}{} +\registerctxluafile{scrn-pag}{autosuffix} \unprotect diff --git a/tex/context/base/mkxl/spac-hor.mkxl b/tex/context/base/mkxl/spac-hor.mkxl index 426580c7d..13d1f9021 100644 --- a/tex/context/base/mkxl/spac-hor.mkxl +++ b/tex/context/base/mkxl/spac-hor.mkxl @@ -677,6 +677,29 @@ \newskip \s_spac_narrower_right_last \newconditional\s_spac_narrower_last_swap +% \def\spac_narrower_start_apply#1% +% {\narrowerparameter\c!before +% \global\s_spac_narrower_left \zeropoint +% \global\s_spac_narrower_right \zeropoint +% \global\s_spac_narrower_middle\zeropoint +% \edef\askednarrower{#1}% +% \ifx\askednarrower\v!reverse +% \ifconditional\s_spac_narrower_last_swap +% \leftskip \s_spac_narrower_right_last +% \rightskip\s_spac_narrower_left_last +% \setfalse\s_spac_narrower_last_swap +% \else +% \leftskip \s_spac_narrower_left_last +% \rightskip\s_spac_narrower_right_last +% \settrue\s_spac_narrower_last_swap +% \fi +% \else +% \normalexpanded{\processcommalistwithparameters[\askednarrower]}\spac_narrower_initialize +% \advance\leftskip \dimexpr\s_spac_narrower_left +\s_spac_narrower_middle\relax +% \advance\rightskip\dimexpr\s_spac_narrower_right+\s_spac_narrower_middle\relax +% \fi +% \seteffectivehsize} + \def\spac_narrower_start_apply#1% {\narrowerparameter\c!before \global\s_spac_narrower_left \zeropoint @@ -685,18 +708,18 @@ \edef\askednarrower{#1}% \ifx\askednarrower\v!reverse \ifconditional\s_spac_narrower_last_swap - \leftskip \s_spac_narrower_right_last - \rightskip\s_spac_narrower_left_last + \frozen\leftskip \s_spac_narrower_right_last + \frozen\rightskip\s_spac_narrower_left_last \setfalse\s_spac_narrower_last_swap \else - \leftskip \s_spac_narrower_left_last - \rightskip\s_spac_narrower_right_last + \frozen\leftskip \s_spac_narrower_left_last + \frozen\rightskip\s_spac_narrower_right_last \settrue\s_spac_narrower_last_swap \fi \else \normalexpanded{\processcommalistwithparameters[\askednarrower]}\spac_narrower_initialize - \advance\leftskip \dimexpr\s_spac_narrower_left +\s_spac_narrower_middle\relax - \advance\rightskip\dimexpr\s_spac_narrower_right+\s_spac_narrower_middle\relax + \frozen\advance\leftskip \dimexpr\s_spac_narrower_left +\s_spac_narrower_middle\relax + \frozen\advance\rightskip\dimexpr\s_spac_narrower_right+\s_spac_narrower_middle\relax \fi \seteffectivehsize} diff --git a/tex/context/base/mkxl/strc-reg.mkxl b/tex/context/base/mkxl/strc-reg.mkxl index af98ca481..dcfdd0946 100644 --- a/tex/context/base/mkxl/strc-reg.mkxl +++ b/tex/context/base/mkxl/strc-reg.mkxl @@ -40,6 +40,20 @@ % \index[pageclass::] {textclass::entry} % \index[pageclass::key]{textclass::entry} +% nice example: +% +% \setupregister[index] +% [n=1, +% pageleft=\hfilll, +% pageright=\frozen\parfillleftskip 0pt plus 1fill\frozen\parfillrightskip 0pt\par] +% +% \starttext +% +% {\showmakeup \placeindex \page} +% +% % \dorecurse{10}{\dontleavehmode \index{AAA}\page} +% \dorecurse{100}{\dontleavehmode\index{AAA}\page} + % tzt variant with n entries, parameters and userdata (altnum) \installcorenamespace{register} diff --git a/tex/context/base/mkxl/trac-vis.lmt b/tex/context/base/mkxl/trac-vis.lmt index 8c04a0372..6e9bd8e8c 100644 --- a/tex/context/base/mkxl/trac-vis.lmt +++ b/tex/context/base/mkxl/trac-vis.lmt @@ -595,17 +595,28 @@ local whatsit do local w_cache = caches["whatsit"] local tags = { - open = "OPN", - write = "WRI", - close = "CLS", - special = "SPE", - latelua = "LUA", - savepos = "POS", - userdefined = "USR", - literal = "LIT", - setmatrix = "MAT", - save = "SAV", - restore = "RES", + [whatsitcodes.open] = "OPN", + [whatsitcodes.write] = "WRI", + [whatsitcodes.close] = "CLS", + -- [whatsitcodes.special] = "SPE", + [whatsitcodes.latelua] = "LUA", + [whatsitcodes.savepos] = "POS", + [whatsitcodes.userdefined] = "USR", + [whatsitcodes.literal] = "LIT", + [whatsitcodes.setmatrix] = "MAT", + [whatsitcodes.save] = "SAV", + [whatsitcodes.restore] = "RES", + [whatsitcodes.startscaling] = "+SCA", + [whatsitcodes.stopscaling] = "-SCA", + [whatsitcodes.startrotation] = "+ROT", + [whatsitcodes.stoprotation] = "-ROT", + [whatsitcodes.startmirroring] = "+MIR", + [whatsitcodes.stopmirroring] = "-MIR", + [whatsitcodes.startclipping] = "+CLP", + [whatsitcodes.stopclipping] = "-CLP", + [whatsitcodes.startmatrix] = "+MAT", + [whatsitcodes.stopmatrix] = "-MAT", + [whatsitcodes.setstate] = "SET", -- can't happen because these are added after visualizing } whatsit = function(head,current) @@ -614,7 +625,7 @@ local whatsit do if info then -- print("hit whatsit") else - info = sometext(formatters["W:%s"](what),usedfont,nil,c_white) + info = sometext(formatters["W:%s"](tags[what] or what),usedfont,nil,c_white) setattr(info,a_layer,l_whatsit) w_cache[what] = info end @@ -880,20 +891,13 @@ local ruledglyph do setboth(current) local linewidth = emwidth/(2*fraction) local x_offset, y_offset, l_margin, r_margin, raise = getoffsets(current) - wd = wd - l_margin - r_margin - local info = (dp == 0 and outlinerule and outlinerule(wd,ht,dp,linewidth)) or userrule { + local info = setlink((dp == 0 and outlinerule and outlinerule(wd,ht,dp,linewidth)) or userrule { width = wd, height = ht, depth = dp, line = linewidth, type = "box", - } - if l_margin == 0 then - info = setlink(info,new_kern(-wd)) - else - info = setlink(new_kern(-l_margin),info,new_kern(-wd+l_margin)) - end - -- + },new_kern(-wd)) local c, f = isglyph(current) local char = chardata[f][c] if char and type(char.unicode) == "table" then -- hackery test @@ -1409,7 +1413,7 @@ do trace_marginkern = band(a,0x100000) ~= 0 trace_mathlistkern = band(a,0x200000) ~= 0 trace_dir = band(a,0x400000) ~= 0 - trace_whatsit = band(a,0x800000) ~= 0 + trace_par = band(a,0x800000) ~= 0 end elseif a == unsetvalue then goto list diff --git a/tex/context/base/mkxl/typo-cap.lmt b/tex/context/base/mkxl/typo-cap.lmt index dbf6950c8..67acb2535 100644 --- a/tex/context/base/mkxl/typo-cap.lmt +++ b/tex/context/base/mkxl/typo-cap.lmt @@ -11,7 +11,7 @@ if not modules then modules = { } end modules ['typo-cap'] = { local next, type, tonumber = next, type, tonumber local format, insert = string.format, table.insert -local div, getrandom = math.div, utilities.randomizer.get +local div, getrandom, random = math.div, utilities.randomizer.get, math.random local trace_casing = false trackers.register("typesetters.casing", function(v) trace_casing = v end) @@ -435,3 +435,24 @@ interfaces.implement { actions = cases.set, arguments = { "argument" } } + +-- An example of a special plug, see type-imp-punk for usage. + +cases.register("randomvariant", function(start) + local char, fnt = isglyph(start) + local data = fontchar[fnt][char] + if data then + local variants = data.variants + if variants then + local n = #variants + local i = getrandom("variant",1,n+1) + if i > n then + -- we keep the original + else + setchar(start,variants[i]) + end + return start, true + end + end + return start, false +end) diff --git a/tex/context/fonts/mkiv/bonum-math.lfg b/tex/context/fonts/mkiv/bonum-math.lfg index 8dfa63405..51ca2d7f1 100644 --- a/tex/context/fonts/mkiv/bonum-math.lfg +++ b/tex/context/fonts/mkiv/bonum-math.lfg @@ -1,5 +1,8 @@ -local kern_200 = { bottomright = { { kern = -200 } } } -local kern_100 = { bottomright = { { kern = -100 } } } +local kern_V = { bottomright = { { kern = -200 } } } +local kern_W = { bottomright = { { kern = -100 } } } +local offset_f = { xoffset = "llx" } + +-- Beware of updates in ssty slots! return { name = "bonum-math", @@ -10,12 +13,21 @@ return { mathematics = { dimensions = { default = { - [0x1D453] = { xoffset = "llx" },-- 𝑓 + -- [0x1D453] = offset_f, -- 𝑓 + -- ["1:0x1D453"] = offset_f, -- needed for compact + -- ["2:0x1D453"] = offset_f, -- needed for compact + ["*:0x1D453"] = offset_f, -- 𝑓 }, }, kerns = { - [0x1D449] = kern_200, -- 𝑉 - [0x1D44A] = kern_100, -- 𝑊 + -- [0x1D449] = kern_V, -- 𝑉 + -- ["1:0x1D449"] = kern_V, -- needed for compact + -- ["2:0x1D449"] = kern_V, -- needed for compact + -- [0x1D44A] = kern_W, -- 𝑊 + -- ["1:0x1D44A"] = kern_W, -- needed for compact + -- ["2:0x1D44A"] = kern_W, -- needed for compact + ["*:0x1D449"] = kern_V, -- 𝑉 + ["*:0x1D44A"] = kern_W, -- 𝑊 }, alternates = { dotless = { feature = 'dtls', value = 1, comment = "Mathematical Dotless Forms" }, diff --git a/tex/context/fonts/mkiv/dejavu-math.lfg b/tex/context/fonts/mkiv/dejavu-math.lfg index d28c69060..608b396f8 100644 --- a/tex/context/fonts/mkiv/dejavu-math.lfg +++ b/tex/context/fonts/mkiv/dejavu-math.lfg @@ -1,4 +1,7 @@ -local kern_250 = { bottomright = { { kern = -250 } } } +local kern_V = { bottomright = { { kern = -250 } } } +local kern_W = kern_W + +-- Beware of updates in ssty slots! return { name = "dejavu-math", @@ -8,8 +11,14 @@ return { copyright = "ConTeXt development team", mathematics = { kerns = { - [0x1D449] = kern_250, -- - [0x1D44A] = kern_250, -- 𝑊 + -- [0x1D449] = kern_V, -- 𝑉 + -- ["1:0x1D449"] = kern_V, -- needed for compact + -- ["2:0x1D449"] = kern_V, -- needed for compact + -- [0x1D44A] = kern_W, -- 𝑊 + -- ["1:0x1D44A"] = kern_W, -- needed for compact + -- ["2:0x1D44A"] = kern_W, -- needed for compact + ["*:0x1D449"] = kern_V, -- 𝑉 + ["*:0x1D44A"] = kern_W, -- 𝑊 }, alternates = { dotless = { feature = 'dtls', value = 1, comment = "Mathematical Dotless Forms" }, diff --git a/tex/context/fonts/mkiv/minion-math.lfg b/tex/context/fonts/mkiv/minion-math.lfg index a4f539ec7..863836c1c 100644 --- a/tex/context/fonts/mkiv/minion-math.lfg +++ b/tex/context/fonts/mkiv/minion-math.lfg @@ -1,6 +1,5 @@ -local kern_100 = { bottomright = { { kern = -100 } } } -local kern_150 = { bottomright = { { kern = -150 } } } -local kern_200 = { bottomright = { { kern = -200 } } } +local kern_W = { bottomright = { { kern = -150 } } } +local kern_V = { bottomright = { { kern = -200 } } } return { name = "minion-math", @@ -23,8 +22,9 @@ return { }, mathematics = { kerns = { - [0x1D449] = kern_200, -- 𝑉 - [0x1D44A] = kern_150, -- 𝑊 + [0x1D449] = kern_V, -- 𝑉 + [0x1D44A] = kern_W, -- 𝑊 + -- todo: ssty 1/2 }, }, } diff --git a/tex/context/fonts/mkiv/pagella-math.lfg b/tex/context/fonts/mkiv/pagella-math.lfg index c85ff3f6b..d4ae14162 100644 --- a/tex/context/fonts/mkiv/pagella-math.lfg +++ b/tex/context/fonts/mkiv/pagella-math.lfg @@ -1,7 +1,8 @@ -local kern_200 = { bottomright = { { kern = -200 } } } -local kern_100 = { bottomright = { { kern = -100 } } } +local kern_V = { bottomright = { { kern = -200 } } } +local kern_W = { bottomright = { { kern = -100 } } } +local offset_f = { xoffset = "llx" } --- Beware of updates ! +-- Beware of updates in ssty slots! return { name = "pagella-math", @@ -12,13 +13,22 @@ return { mathematics = { dimensions = { default = { - -- [0x1D453] = { xoffset = 162, width = 278 + 162 },-- 𝑓 - [0x1D453] = { xoffset = "llx" },-- 𝑓 + -- [0x1D453] = { xoffset = 162, width = 278 + 162 },-- 𝑓 + -- [0x1D453] = offset_f, -- 𝑓 + -- ["1:0x1D453"] = offset_f, -- needed for compact + -- ["2:0x1D453"] = offset_f, -- needed for compact + ["*:0x1D453"] = offset_f, -- 𝑓 }, }, kerns = { - [0x1D449] = kern_200, -- 𝑉 - [0x1D44A] = kern_100, -- 𝑊 + -- [0x1D449] = kern_V, -- 𝑉 + -- ["1:0x1D449"] = kern_V, -- needed for compact + -- ["2:0x1D449"] = kern_V, -- needed for compact + -- [0x1D44A] = kern_W, -- 𝑊 + -- ["1:0x1D44A"] = kern_W, -- needed for compact + -- ["2:0x1D44A"] = kern_W, -- needed for compact + ["*:0x1D449"] = kern_V, -- 𝑉 + ["*:0x1D44A"] = kern_W, -- 𝑊 }, alternates = { dotless = { feature = 'dtls', value = 1, comment = "Mathematical Dotless Forms" }, diff --git a/tex/context/fonts/mkiv/schola-math.lfg b/tex/context/fonts/mkiv/schola-math.lfg index 9787c18a9..b60bc6d99 100644 --- a/tex/context/fonts/mkiv/schola-math.lfg +++ b/tex/context/fonts/mkiv/schola-math.lfg @@ -1,5 +1,7 @@ -local kern_200_050 = { bottomright = { { kern = -200 } }, topright = { { kern = 50 } } } -local kern_100_050 = { bottomright = { { kern = -100 } }, topright = { { kern = 50 } } } +local kern_V = { bottomright = { { kern = -200 } }, topright = { { kern = 50 } } } +local kern_W = { bottomright = { { kern = -100 } }, topright = { { kern = 50 } } } + +-- Beware of updates in ssty slots! return { name = "schola-math", @@ -9,8 +11,14 @@ return { copyright = "ConTeXt development team", mathematics = { kerns = { - [0x1D449] = kern_200_050, -- - [0x1D44A] = kern_100_050, -- 𝑊 + -- [0x1D449] = kern_V, -- 𝑉 + -- ["1:0x1D449"] = kern_V, -- needed for compact + -- ["2:0x1D449"] = kern_V, -- needed for compact + -- [0x1D44A] = kern_W, -- 𝑊 + -- ["1:0x1D44A"] = kern_W, -- needed for compact + -- ["2:0x1D44A"] = kern_W, -- needed for compact + ["*:0x1D449"] = kern_V, -- 𝑉 + ["*:0x1D44A"] = kern_W, -- 𝑊 }, alternates = { dotless = { feature = 'dtls', value = 1, comment = "Mathematical Dotless Forms" }, diff --git a/tex/context/fonts/mkiv/termes-math.lfg b/tex/context/fonts/mkiv/termes-math.lfg index 1501fd536..3cf8685eb 100644 --- a/tex/context/fonts/mkiv/termes-math.lfg +++ b/tex/context/fonts/mkiv/termes-math.lfg @@ -1,5 +1,8 @@ -local kern_200 = { bottomright = { { kern = -200 } } } -local kern_100 = { bottomright = { { kern = -100 } } } +local kern_V = { bottomright = { { kern = -200 } } } +local kern_W = { bottomright = { { kern = -100 } } } +local offset_f = { xoffset = "llx" } + +-- Beware of updates in ssty slots! return { name = "termes-math", @@ -10,12 +13,21 @@ return { mathematics = { dimensions = { default = { - [0x1D453] = { xoffset = "llx" },-- 𝑓 + -- [0x1D453] = offset_f, -- 𝑓 + -- ["1:0x1D453"] = offset_f, -- needed for compact + -- ["2:0x1D453"] = offset_f, -- needed for compact + ["*:0x1D453"] = offset_f, -- 𝑓 }, }, kerns = { - [0x1D449] = kern_200, -- 𝑉 - [0x1D44A] = kern_100, -- 𝑊 + -- [0x1D449] = kern_V, -- 𝑉 + -- ["1:0x1D449"] = kern_V, -- needed for compact + -- ["2:0x1D449"] = kern_V, -- needed for compact + -- [0x1D44A] = kern_W, -- 𝑊 + -- ["1:0x1D44A"] = kern_W, -- needed for compact + -- ["2:0x1D44A"] = kern_W, -- needed for compact + ["*:0x1D449"] = kern_V, -- 𝑉 + ["*:0x1D44A"] = kern_W, -- 𝑊 }, alternates = { dotless = { feature = 'dtls', value = 1, comment = "Mathematical Dotless Forms" }, diff --git a/tex/context/fonts/mkiv/type-imp-punk.mkxl b/tex/context/fonts/mkiv/type-imp-punk.mkxl new file mode 100644 index 000000000..aa01a1d4e --- /dev/null +++ b/tex/context/fonts/mkiv/type-imp-punk.mkxl @@ -0,0 +1,54 @@ +%D \module +%D [ file=type-imp-punk, +%D version=2020.01.17, +%D title=\CONTEXT\ Typescript Macros, +%D subtitle=Punk Again, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +%D Yet another look at punk. + +\ifdefined\enablerandomvariants\else + \useMPlibrary[punk] +\fi + +\doifelse {\truefontname{Serif}} {unknown} { + \writestatus{fonts}{you need to load a base bodyfont first} + \endinput +} { + % we're ok +} + +\starttypescriptcollection[punk] + + \definefontfeature [punk] [metapost={category=punk,preroll=punkpreroll}] + \definefontfeature [punkrandom] [metapost={category=punk,preroll=punkpreroll,variants=5}] + \definefontfeature [punkbold] [metapost={category=punk,preroll=punkpreroll,weight=2}] + \definefontfeature [punkslanted] [metapost={category=punk,preroll=punkpreroll,slant=.15}] + \definefontfeature [punkboldslanted] [metapost={category=punk,preroll=punkpreroll,slant=.15,weight=2}] + \definefontfeature [punkveryslanted] [metapost={category=punk,preroll=punkpreroll,slant=-.15}] + \definefontfeature [punksqueezed] [metapost={category=punk,preroll=punkpreroll,squeeze=.5}] + \definefontfeature [punkextended] [metapost={category=punk,preroll=punkpreroll,extend=1.3}] + + \definefontsynonym [punkbase] [\truefontname{Serif}] + + \starttypescript [\s!serif] [punk] + \definefontsynonym [\s!Serif] [punkbase] [\s!features=punk] + \definefontsynonym [\s!SerifSlanted] [punkbase] [\s!features=punkslanted] + \definefontsynonym [\s!SerifBold] [punkbase] [\s!features=punkbold] + \definefontsynonym [\s!SerifBoldSlanted][punkbase] [\s!features=punkboldslanted] + \definefontsynonym [\s!SerifItalic] [\s!SerifSlanted] + \definefontsynonym [\s!SerifBoldItalic] [\s!SerifBoldSlanted] + \stoptypescript + + \starttypescript [punk] + \definetypeface [punk] [\s!rm] [\s!serif] [punk] [\s!default] + \stoptypescript + +\stoptypescriptcollection + diff --git a/tex/context/fonts/mkiv/type-imp-texgyre.mkiv b/tex/context/fonts/mkiv/type-imp-texgyre.mkiv index d10fe505f..72d3b3588 100644 --- a/tex/context/fonts/mkiv/type-imp-texgyre.mkiv +++ b/tex/context/fonts/mkiv/type-imp-texgyre.mkiv @@ -247,8 +247,8 @@ \starttypescript [\s!math][times,termes][\s!all] % \loadfontgoodies[texgyre] % \definefontsynonym[\s!MathRoman][file:texgyre-termes-math-regular.otf][\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=texgyre] - \definefontsynonym[\s!MathRoman] [file:texgyretermes-math.otf][\s!features={\s!math\mathsizesuffix,oldmath,mathextra},\s!goodies=termes-math] - \definefontsynonym[\s!MathRomanBold][file:texgyretermes-math.otf][\s!features={\s!math\mathsizesuffix,oldmath,termes-math-bold,mathextra},\s!goodies=termes-math] + \definefontsynonym[\s!MathRoman] [file:texgyretermes-math.otf][\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=termes-math] + \definefontsynonym[\s!MathRomanBold][file:texgyretermes-math.otf][\s!features={\s!math\mathsizesuffix,termes-math-bold,mathextra},\s!goodies=termes-math] \stoptypescript \stoptypescriptcollection @@ -276,8 +276,8 @@ \starttypescript [\s!math][palatino,pagella][\s!all] % \loadfontgoodies[texgyre] % \definefontsynonym[\s!MathRoman][file:texgyre-pagella-math-regular.otf][\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=texgyre] - \definefontsynonym[\s!MathRoman] [file:texgyrepagella-math.otf][\s!features={\s!math\mathsizesuffix,oldmath,mathextra},\s!goodies=pagella-math] - \definefontsynonym[\s!MathRomanBold][file:texgyrepagella-math.otf][\s!features={\s!math\mathsizesuffix,oldmath,pagella-math-bold,mathextra},\s!goodies=pagella-math] + \definefontsynonym[\s!MathRoman] [file:texgyrepagella-math.otf][\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=pagella-math] + \definefontsynonym[\s!MathRomanBold][file:texgyrepagella-math.otf][\s!features={\s!math\mathsizesuffix,pagella-math-bold,mathextra},\s!goodies=pagella-math] \stoptypescript \stoptypescriptcollection @@ -289,8 +289,8 @@ \starttypescript [\s!math][bookman,bonum][\s!all] % \loadfontgoodies[texgyre] % \definefontsynonym[\s!MathRoman][file:texgyre-bonum-math-regular.otf][\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=texgyre] - \definefontsynonym[\s!MathRoman] [file:texgyrebonum-math.otf][\s!features={\s!math\mathsizesuffix,oldmath,mathextra},\s!goodies=bonum-math] - \definefontsynonym[\s!MathRomanBold][file:texgyrebonum-math.otf][\s!features={\s!math\mathsizesuffix,oldmath,bonum-math-bold,mathextra},\s!goodies=bonum-math] + \definefontsynonym[\s!MathRoman] [file:texgyrebonum-math.otf][\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=bonum-math] + \definefontsynonym[\s!MathRomanBold][file:texgyrebonum-math.otf][\s!features={\s!math\mathsizesuffix,bonum-math-bold,mathextra},\s!goodies=bonum-math] \stoptypescript \stoptypescriptcollection @@ -300,8 +300,8 @@ \starttypescript [\s!math][schoolbook,schola][\s!all] % \loadfontgoodies[texgyre] % \definefontsynonym[\s!MathRoman][file:texgyre-schola-math-regular.otf][\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=texgyre] - \definefontsynonym[\s!MathRoman] [file:texgyreschola-math.otf][\s!features={\s!math\mathsizesuffix,oldmath,mathextra},\s!goodies=schola-math] - \definefontsynonym[\s!MathRomanBold][file:texgyreschola-math.otf][\s!features={\s!math\mathsizesuffix,oldmath,schola-math-bold,mathextra},\s!goodies=schola-math] + \definefontsynonym[\s!MathRoman] [file:texgyreschola-math.otf][\s!features={\s!math\mathsizesuffix,mathextra},\s!goodies=schola-math] + \definefontsynonym[\s!MathRomanBold][file:texgyreschola-math.otf][\s!features={\s!math\mathsizesuffix,schola-math-bold,mathextra},\s!goodies=schola-math] \stoptypescript \stoptypescriptcollection diff --git a/tex/context/fonts/mkiv/xits-math.lfg b/tex/context/fonts/mkiv/xits-math.lfg index b37ab1277..88d3a8d45 100644 --- a/tex/context/fonts/mkiv/xits-math.lfg +++ b/tex/context/fonts/mkiv/xits-math.lfg @@ -14,6 +14,7 @@ local italics = { -- [0x1D44E] = 0.99, -- a (fraction of quad) -- [0x1D44F] = 100, -- b (font points) [0x1D453] = -0.0375, -- f + -- todo: ssty 1/2 } } diff --git a/tex/context/modules/mkiv/m-punk.mkiv b/tex/context/modules/mkiv/m-punk.mkiv index 47f1a0177..9eb7411ba 100644 --- a/tex/context/modules/mkiv/m-punk.mkiv +++ b/tex/context/modules/mkiv/m-punk.mkiv @@ -17,6 +17,11 @@ %D https://www.youtube.com/watch?v=g5c2Htj8Vtw %D \stoptyping +\ifcase\contextlmtxmode\else + \writestatus{punk}{use metapost library punk instead} + \endinput +\fi + \startluacode local concat = table.concat local round = math.round diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index c1300a71b..552559e96 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 : 2021-01-11 16:28 +-- merge date : 2021-01-17 21:39 do -- begin closure to overcome local limits and interference |