diff options
Diffstat (limited to 'tex/context/base/attr-ini.lua')
-rw-r--r-- | tex/context/base/attr-ini.lua | 697 |
1 files changed, 345 insertions, 352 deletions
diff --git a/tex/context/base/attr-ini.lua b/tex/context/base/attr-ini.lua index 4469608c4..81ca873d9 100644 --- a/tex/context/base/attr-ini.lua +++ b/tex/context/base/attr-ini.lua @@ -29,11 +29,17 @@ function totokens(str) return t end -function pdfliteral(str) - local t = node.new('whatsit',8) - t.mode = 1 -- direct - t.data = str -- totokens(str) - return t +-- temp hack, will be proper driver stuff + +backends = backends or { } +backends.pdf = backends.pdf or { } +backend = backend or backends.pdf + +function backends.pdf.literal(str) + local t = node.new('whatsit',8) + t.mode = 1 -- direct + t.data = str -- totokens(str) + return t end -- shipouts @@ -45,44 +51,44 @@ do local hlist, vlist = node.id('hlist'), node.id('vlist') - local function do_process_page(attribute,processor,head) -- maybe work with ranges - local previous, stack = nil, head - while stack do - local id = stack.id - if id == hlist or id == vlist then - local content = stack.list - if content then - stack.list = do_process_page(attribute,processor,content) - end - else - stack, previous, head = processor(attribute,stack,previous,head) - end - previous = stack - stack = stack.next - end - return head - end + local contains = node.has_attribute + + nodes.trigger = false + nodes.triggering = false + + -- we used to do the main processor loop here and call processor for each node + -- but eventually this was too much a slow down (1 sec on 23 for 120 pages mk) + -- so that we moved looping to teh processor itself; this may lead to a bit of + -- duplicate code once that we have more state handlers function nodes.process_page(head) + local trigger = nodes.trigger if head then - input.start_timing(nodes) + input.start_timing(attributes) local done, used = false, { } for name, plugin in pairs(shipouts.plugins) do local attribute = attributes.numbers[name] if attribute then - local initializer = plugin.initializer - local processor = plugin.processor - local finalizer = plugin.finalizer - if initializer then - initializer(attribute,head) - end - if processor then - head = do_process_page(attribute,processor,head) - end - if finalizer then - local ok - ok, head, used[attribute] = finalizer(attribute,head) - done = done or ok + local namespace = plugin.namespace + if namespace.enabled then + local initializer = plugin.initializer + local processor = plugin.processor + local finalizer = plugin.finalizer + local resolver = plugin.resolver + if initializer then + initializer(namespace,attribute,head) + end + if processor then + local inheritance = (resolver and resolver()) or -1 + local ok + ok, head = processor(namespace,attribute,head,inheritance) + done = done or ok + end + if finalizer then -- no need when not ok + local ok + ok, head, used[attribute] = finalizer(namespace,attribute,head) + done = done or ok + end end else texio.write_nl(string.format("undefined attribute %s",name)) @@ -92,14 +98,17 @@ do for name, plugin in pairs(shipouts.plugins) do local attribute = attributes.numbers[name] if used[attribute] then - local flusher = plugin.flusher - if flusher then - head = flusher(attribute,head,used[attribute]) + local namespace = plugin.namespace + if namespace.enabled then + local flusher = plugin.flusher + if flusher then + head = flusher(namespace,attribute,head,used[attribute]) + end end end end end - input.stop_timing(nodes) + input.stop_timing(attributes) end return head end @@ -132,7 +141,7 @@ states = { } do - local glyph, rule, whatsit = node.id('glyph'), node.id('rule'), node.id('whatsit') + local glyph, rule, whatsit, hlist, vlist = node.id('glyph'), node.id('rule'), node.id('whatsit'), node.id('hlist'), node.id('vlist') local current, used, done = 0, { }, false @@ -140,11 +149,11 @@ do current, used, done = 0, { }, false end - local contains = node.has_attribute + local contains, copy = node.has_attribute, node.copy - function insert(n,stack,previous,head) + local function insert(n,stack,previous,head) if n then - n = node.copy(n) + n = copy(n) n.next = stack if previous then previous.next = n @@ -156,94 +165,128 @@ do return stack, previous, head end - function states.finalize(what,attribute,head) - if what.enabled and what.none and current > 0 and head.list then - local head = head.list - stack, previous, head = insert(what.none,list,nil,list) + function states.finalize(namespace,attribute,head) + if current > 0 and namespace.none then + if head.id == hlist or head.id == vlist then + local stack, previous, head = insert(namespace.none,head.list,nil,head.list) + else + local stack, previous, head = insert(namespace.none,head,nil,head) + end + return true, head, true + else + return false, head, false end - return done, head, used end ---~ function states.process(what,attribute,stack,previous,head) -- one attribute ---~ if what.enabled then ---~ local c = contains(stack,attribute) ---~ if c then ---~ if current ~= c then ---~ local id = stack.id ---~ if id == glyph or id == rule or id == whatsit then ---~ stack, previous, head = insert(what.data[c],stack,previous,head) ---~ current, done, used[c] = c, true, true ---~ end ---~ end ---~ elseif current > 0 then ---~ stack, previous, head = insert(what.none,stack,previous,head) ---~ current, done, used[0] = 0, true, true ---~ end ---~ end ---~ return stack, previous, head ---~ end - - function states.process(what,attribute,stack,previous,head) -- one attribute - if what.enabled then + function states.process(namespace,attribute,head,inheritance,default) -- one attribute + local trigger = nodes.triggering and nodes.trigger + local stack, previous, done, process = head, nil, false, states.process + while stack do local id = stack.id - if id == glyph or id == rule then -- or id == whatsit then + if id == hlist or id == vlist then + local content = stack.list + if content then + local ok = false + if trigger and contains(stack,trigger) then + local outer = contains(stack,attribute) + if outer ~= inheritance then + ok, stack.list = process(namespace,attribute,content,inheritance,outer) + else + ok, stack.list = process(namespace,attribute,content,inheritance,default) + end + else + ok, stack.list = process(namespace,attribute,content,inheritance,default) + end + done = done or ok + end + elseif id == glyph or id == rule or id == whatsit then -- special local c = contains(stack,attribute) if c then - if current ~= c then - stack, previous, head = insert(what.data[c],stack,previous,head) + if default and c == inheritance then + if current ~= default then + local data = namespace.data[default] or namespace.reviver(default) + stack, previous, head = insert(data,stack,previous,head) + current, done, used[default] = default, true, true + end + elseif current ~= c then + local data = namespace.data[c] or namespace.reviver(c) + stack, previous, head = insert(data,stack,previous,head) current, done, used[c] = c, true, true end + elseif default and inheritance then + if current ~= default then + local data = namespace.data[default] or namespace.reviver(default) + stack, previous, head = insert(data,stack,previous,head) + current, done, used[default] = default, true, true + end elseif current > 0 then - stack, previous, head = insert(what.none,stack,previous,head) + stack, previous, head = insert(namespace.none,stack,previous,head) current, done, used[0] = 0, true, true end end + previous = stack + stack = stack.next end - return stack, previous, head + return done, head end ---~ function states.selective(what,attribute,stack,previous,head) -- two attributes ---~ if what.enabled then ---~ local c = contains(stack,attribute) ---~ if c then ---~ if current ~= c then ---~ local id = stack.id ---~ if id == glyph or id == rule then -- or id == whatsit then ---~ stack, previous, head = insert(what.data[c][contains(stack,what.selector) or what.default],stack,previous,head) ---~ current, done, used[c] = c, true, true ---~ end ---~ end ---~ elseif current > 0 then ---~ local id = stack.id ---~ if id == glyph or id == rule then -- or id == whatsit then ---~ stack, previous, head = insert(what.none,stack,previous,head) ---~ current, done, used[0] = 0, true, true ---~ end ---~ end ---~ end ---~ return stack, previous, head ---~ end + -- we can force a selector, e.g. document wide color spaces, saves a little - function states.selective(what,attribute,stack,previous,head) -- two attributes - if what.enabled then + function states.selective(namespace,attribute,head,inheritance,default) -- two attributes + local trigger = nodes.triggering and nodes.trigger + local stack, previous, done, selective = head, nil, false, states.selective + local defaultselector, forcedselector, selector, reviver = namespace.default, namespace.forced, namespace.selector, namespace.reviver + local none = namespace.none + while stack do local id = stack.id - if id == glyph or id == rule then -- or id == whatsit then + if id == hlist or id == vlist then + local content = stack.list + if content then + local ok = false + if trigger and contains(stack,trigger) then + local outer = contains(stack,attribute) + if outer ~= inheritance then + ok, stack.list = selective(namespace,attribute,content,inheritance,outer) + else + ok, stack.list = selective(namespace,attribute,content,inheritance,default) + end + else + ok, stack.list = selective(namespace,attribute,content,inheritance,default) + end + done = done or ok + end + elseif id == glyph or id == rule or id == whatsit then -- special local c = contains(stack,attribute) if c then - if current ~= c then - stack, previous, head = insert(what.data[c][contains(stack,what.selector) or what.default],stack,previous,head) + if default and c == inheritance then + if current ~= default then + local data = namespace.data[default] or reviver(default) + stack, previous, head = insert(data[forcedselector or contains(stack,selector) or defaultselector],stack,previous,head) + current, done, used[default] = default, true, true + end + elseif current ~= c then + local data = namespace.data[c] or reviver(c) + stack, previous, head = insert(data[forcedselector or contains(stack,selector) or defaultselector],stack,previous,head) current, done, used[c] = c, true, true end + elseif default and inheritance then + if current ~= default then + local data = namespace.data[default] or reviver(default) + stack, previous, head = insert(data[forcedselector or contains(stack,selector) or defaultselector],stack,previous,head) + current, done, used[default] = default, true, true + end elseif current > 0 then - stack, previous, head = insert(what.none,stack,previous,head) + stack, previous, head = insert(none,stack,previous,head) current, done, used[0] = 0, true, true end end + previous = stack + stack = stack.next end - return stack, previous, head + return done, head end - collected = { } + local collected = { } function states.collect(str) collected[#collected+1] = str @@ -269,24 +312,40 @@ end -- we also need to store the colorvalues because we need then in mp -colors = colors or { } -colors.enabled = true -colors.data = colors.data or { } -colors.strings = colors.strings or { } +colors = colors or { } +colors.data = colors.data or { } +colors.values = colors.values or { } colors.registered = colors.registered or { } +colors.enabled = true colors.weightgray = true colors.attribute = 0 colors.selector = 0 colors.default = 1 +colors.main = nil -input.storage.register(true,"colors/data", colors.strings, "colors.data") +-- This is a compromis between speed and simplicity. We used to store the +-- values and data in one array, which made in neccessary to store the +-- converters that need node constructor into strings and evaluate them +-- at runtime (after reading from storage). Think of: +-- +-- colors.strings = colors.strings or { } +-- +-- if environment.initex then +-- colors.strings[color] = "return colors." .. colorspace .. "(" .. table.concat({...},",") .. ")" +-- end +-- +-- input.storage.register(true,"colors/data", colors.strings, "colors.data") -- evaluated +-- +-- We assume that only processcolors are defined in the format. + +input.storage.register(false,"colors/values", colors.values, "colors.values") input.storage.register(false,"colors/registered", colors.registered, "colors.registered") colors.stamps = { rgb = "r:%s:%s:%s", cmyk = "c:%s:%s:%s:%s", gray = "s:%s", - spot = "p:%s:%s" + spot = "p:%s:%s:%s:%s" } colors.models = { @@ -303,23 +362,23 @@ do local format = string.format local concat = table.concat - local function rgbdata(r,g,b) - return pdfliteral(format("%s %s %s rg %s %s %s RG",r,g,b,r,g,b)) + local function rgbdata(r,g,b) -- dodo: backends.pdf.rgbdata + return backends.pdf.literal(format("%s %s %s rg %s %s %s RG",r,g,b,r,g,b)) end local function cmykdata(c,m,y,k) - return pdfliteral(format("%s %s %s %s k %s %s %s %s K",c,m,y,k,c,m,y,k)) + return backends.pdf.literal(format("%s %s %s %s k %s %s %s %s K",c,m,y,k,c,m,y,k)) end local function graydata(s) - return pdfliteral(format("%s g %s G",s,s)) + return backends.pdf.literal(format("%s g %s G",s,s)) end - local function spotdata(n,p) -- name, parent, ratio + local function spotdata(n,f,d,p) if type(p) == "string" then p = p:gsub(","," ") -- brr misuse of spot end - return pdfliteral(format("/%s cs /%s CS %s SCN %s scn",n,n,p,p)) + return backends.pdf.literal(format("/%s cs /%s CS %s SCN %s scn",n,n,p,p)) end local function rgbtocmyk(r,g,b) @@ -349,33 +408,54 @@ do -- default color space function colors.gray(s) - local gray = graydata(s) - return { gray, gray, gray, gray, 2, s, 0, 0, 0, 0, 0, 0, 1 } + return { 2, s, 0, 0, 0, 0, 0, 0, 1 } end function colors.rgb(r,g,b) local s = rgbtogray(r,g,b) local c, m, y, k = rgbtocmyk(r,g,b) - local gray, rgb, cmyk = graydata(s), rgbdata(r,g,b), cmykdata(c,m,y,k) - return { rgb, gray, rgb, cmyk, 3, s, r, g, b, c, m, y, k } + return { 3, s, r, g, b, c, m, y, k } end function colors.cmyk(c,m,y,k) local s = cmyktogray(c,m,y,k) local r, g, b = cmyktorgb(c,m,y,k) - local gray, rgb, cmyk = graydata(s), rgbdata(r,g,b), cmykdata(c,m,y,k) - return { cmyk, gray, rgb, cmyk, 4, s, r, g, b, c, m, y, k } + return { 4, s, r, g, b, c, m, y, k } end - function colors.spot(parent,p) -- parent, ratio - local spot = spotdata(parent,p) - if type(p) == "string" and p:find(",") then - -- use converted replacement (combination color) - else - -- todo: map gray, rgb, cmyk onto fraction*parent + function colors.spot(parent,f,d,p) +--~ if type(p) == "string" and p:find(",") then +--~ -- use converted replacement (combination color) +--~ else +--~ -- todo: map gray, rgb, cmyk onto fraction*parent +--~ end + return { 5, .5, .5, .5, .5, 0, 0, 0, .5, parent, f, d, p } + end + + function colors.reviver(n) + local d = colors.data[n] + if not d then + local v = colors.values[n] + if not v then + local gray = graydata(0) + d = { gray, gray, gray, gray } + logs.report("attributes",string.format("unable to revive color %s",n or "?")) + else + local kind, gray, rgb, cmyk = v[1], graydata(v[2]), rgbdata(v[3],v[4],v[5]), cmykdata(v[6],v[7],v[8],v[9]) + if kind == 2 then + d = { gray, gray, gray, gray } + elseif kind == 3 then + d = { rgb, gray, rgb, cmyk } + elseif kind == 4 then + d = { cmyk, gray, rgb, cmyk } + elseif kind == 5 then + local spot = spotdata(v[10],v[11],v[12],v[13]) + d = { spot, gray, rgb, cmyk } + end + end + colors.data[n] = d end - local gray, rgb, cmyk = graydata(.5), rgbdata(.5,.5,.5), cmykdata(0,0,0,.5) - return { spot, gray, rgb, cmyk, 5 } + return d end function colors.filter(n) @@ -386,284 +466,197 @@ do end --- conversion models - function colors.setmodel(attribute,name) colors.selector = attributes.numbers[attribute] colors.default = colors.models[name] or 1 return colors.default end -function colors.register(attribute, name, colorspace, ...) +function colors.register(attribute, name, colorspace, ...) -- passing 9 vars is faster local stamp = string.format(colors.stamps[colorspace], ...) local color = colors.registered[stamp] if not color then - local cd = colors.data - color = #cd+1 - cd[color] = colors[colorspace](...) - if environment.initex then - colors.strings[color] = "return colors." .. colorspace .. "(" .. table.concat({...},",") .. ")" - end + color = #colors.values+1 + colors.values[color] = colors[colorspace](...) colors.registered[stamp] = color + colors.reviver(color) + end + if name then + attributes.list[attributes.numbers[attribute]][name] = color -- not grouped, so only global colors end - attributes.list[attributes.numbers[attribute]][name] = color return colors.registered[stamp] end +function colors.value(id) + return colors.values[id] +end + shipouts.plugins.color = { - initializer = function(...) return states.initialize(colors,...) end, - finalizer = function(...) return states.finalize (colors,...) end, - processor = function(...) return states.selective (colors,...) end, + namespace = colors, + initializer = states.initialize, + finalizer = states.finalize , + processor = states.selective , + resolver = function(...) return colors.main end, +} + +-- transparencies + +-- for the moment we manage transparencies in the pdf driver because +-- first we need a nice interface to some pdf things + +transparencies = transparencies or { } +transparencies.registered = transparencies.registered or { } +transparencies.data = transparencies.data or { } +transparencies.values = transparencies.values or { } +transparencies.enabled = true +transparencies.template = "%s:%s" + +input.storage.register(false, "transparencies/registered", transparencies.registered, "transparencies.registered") +input.storage.register(false, "transparencies/data", transparencies.data, "transparencies.data") +input.storage.register(false, "transparencies/values", transparencies.values, "transparencies.values") + +function transparencies.reference(n) + return backends.pdf.literal(string.format("/Tr%s gs",n)) +end + +transparencies.none = transparencies.reference(0) + +function transparencies.register(name,...) + local stamp = string.format(transparencies.template, ...) + local n = transparencies.registered[stamp] + if not n then + n = #transparencies.data+1 + transparencies.data[n] = transparencies.reference(n) + transparencies.values[n] = { ... } + transparencies.registered[stamp] = n + states.collect(string.format("\\presetPDFtransparency{%s}{%s}",...)) -- too many, but experimental anyway + end + return transparencies.registered[stamp] +end + +function transparencies.value(id) + return transparencies.values[id] +end + +shipouts.plugins.transparency = { + namespace = transparencies, + initializer = states.initialize, + finalizer = states.finalize , + processor = states.process , } --- overprint / knockout -overprints = { enabled = true , data = { } } +overprints = overprints or { } +overprints.data = overprints.data or { } +overprints.enabled = true + +overprints.data[1] = backends.pdf.literal(string.format("/GSoverprint gs")) +overprints.data[2] = backends.pdf.literal(string.format("/GSknockout gs")) -overprints.none = pdfliteral(string.format("/GSoverprint gs")) -overprints.data[1] = pdfliteral(string.format("/GSknockout gs")) +overprints.none = overprints.data[1] overprints.registered = { - overprint = 0, - knockout = 1, + overprint = 1, + knockout = 2, } function overprints.register(stamp) +-- states.collect(tex.sprint(tex.ctxcatcodes,"\\initializePDFoverprint")) -- to be testd return overprints.registered[stamp] or overprints.registered.overprint end shipouts.plugins.overprint = { - initializer = function(...) return states.initialize(overprints,...) end, - finalizer = function(...) return states.finalize (overprints,...) end, - processor = function(...) return states.process (overprints,...) end, + namespace = overprints, + initializer = states.initialize, + finalizer = states.finalize , + processor = states.process , } --- negative / positive -negatives = { enabled = true, data = { } } +negatives = netatives or { } +negatives.data = negatives.data or { } +negatives.enabled = true -negatives.none = pdfliteral(string.format("/GSpositive gs")) -negatives.data[1] = pdfliteral(string.format("/GSnegative gs")) +negatives.data[1] = backends.pdf.literal(string.format("/GSpositive gs")) +negatives.data[2] = backends.pdf.literal(string.format("/GSnegative gs")) + +negatives.none = negatives.data[1] negatives.registered = { - positive = 0, - negative = 1, + positive = 1, + negative = 2, } function negatives.register(stamp) +-- states.collect(tex.sprint(tex.ctxcatcodes,"\\initializePDFnegative")) -- to be testd return negatives.registered[stamp] or negatives.registered.positive end shipouts.plugins.negative = { - initializer = function(...) return states.initialize(negatives,...) end, - finalizer = function(...) return states.finalize (negatives,...) end, - processor = function(...) return states.process (negatives,...) end, + namespace = negatives, + initializer = states.initialize, + finalizer = states.finalize, + processor = states.process, } -- effects -effects = { enabled = true, data = { } } - -effects.none = pdfliteral(string.format("0 Tr")) -effects.data[1] = pdfliteral(string.format("1 Tr")) -effects.data[2] = pdfliteral(string.format("2 Tr")) -effects.data[3] = pdfliteral(string.format("3 Tr")) +effects = effects or { } +effects.data = effects.data or { } +effects.registered = effects.registered or { } +effects.enabled = true +effects.stamp = "%s:%s:%s" + +input.storage.register(false, "effects/registered", effects.registered, "effects.registered") +input.storage.register(false, "effects/data", effects.data, "effects.data") + +function effects.register(effect,stretch,rulethickness) + local stamp = string.format(effects.stamp,effect,stretch,rulethickness) + local n = effects.registered[stamp] + if not n then + n = #effects.data+1 + effects.data[n] = effects.reference(effect,stretch,rulethickness) + effects.registered[stamp] = n + -- states.collect("") -- nothing + end + return effects.registered[stamp] +end -effects.registered = { - normal = 0, - inner = 0, - outer = 1, - both = 2, - hidden = 3, +backends.pdf.effects = { + normal = 1, + inner = 1, + outer = 2, + both = 3, + hidden = 4, } -function effects.register(stamp) - return effects.registered[stamp] or effects.registered.normal +function effects.reference(effect,stretch,rulethickness) -- will move, test code, we will develop a proper model for that + effect = backends.pdf.effects[effects] or backends.pdf.effects['normal'] + if stretch > 0 then + stretch = stretch .. " w " + else + stretch = "" + end + if rulethickness > 0 then + rulethickness = number.dimenfactors["bp"]*rulethickness.. " Tc " + else + rulethickness = "" + end + return backends.pdf.literal(string.format("%s%s%s Tr",stretch,rulethickness,effect)) -- watch order end +effects.none = effects.reference(effect,0,0) + shipouts.plugins.effect = { - initializer = function(...) return states.initialize(effects,...) end, - finalizer = function(...) return states.finalize (effects,...) end, - processor = function(...) return states.process (effects,...) end, + namespace = effects, + initializer = states.initialize, + finalizer = states.finalize , + processor = states.process , } -- layers --~ /OC /somename BDC --~ EMC - --- transparencies - --- for the moment we manage transparencies in the pdf driver because --- first we need a nice interface to some pdf things - -transparencies = { - enabled = true, - data = { }, - registered = { }, - hack = { } -} - -input.storage.register(false, "transparencies/registed", transparencies.registered, "transparencies.registered") -input.storage.register(false, "transparencies/data", transparencies.data, "transparencies.data") -input.storage.register(false, "transparencies/hack", transparencies.hack, "transparencies.hack") - -function transparencies.reference(n) - return pdfliteral(string.format("/Tr%s gs",n)) -end - -transparencies.none = transparencies.reference(0) - -transparencies.stamp = "%s:%s" - -function transparencies.register(...) - local stamp = string.format(transparencies.stamp, ...) - if not transparencies.registered[stamp] then - local n = #transparencies.data+1 - transparencies.data[n] = transparencies.reference(n) - transparencies.registered[stamp] = n - states.collect(string.format("\\presetPDFtransparency{%s}{%s}",...)) -- too many, but experimental anyway - end - return transparencies.registered[stamp] -end - -shipouts.plugins.transparency = { - initializer = function(...) return states.initialize(transparencies,...) end, - finalizer = function(...) return states.finalize (transparencies,...) end, - processor = function(...) return states.process (transparencies,...) end, -} - ---~ shipouts.plugins.transparency.flusher = function(attribute,head,used) ---~ local max = 0 ---~ for k,v in pairs(used) do ---~ end ---~ return head ---~ end - ---~ from the time that node lists were tables and not userdata ... ---~ ---~ local function do_collapse_page(stack,existing_t) ---~ if stack then ---~ local t = existing_t or { } ---~ for _, node in ipairs(stack) do ---~ if node then ---~ local kind = node[1] ---~ node[3] = nil ---~ if kind == 'hlist' or kind == 'vlist' then ---~ node[8] = do_collapse_page(node[8]) -- maybe here check for nil ---~ t[#t+1] = node ---~ elseif kind == 'inline' then -- appending literals cost too much time ---~ local nodes = node[4] ---~ if #nodes == 1 then ---~ t[#t+1] = nodes[1] ---~ else ---~ do_collapse_page(nodes,t) ---~ end ---~ else ---~ t[#t+1] = node ---~ end ---~ end ---~ end ---~ return t ---~ else ---~ return nil ---~ end ---~ end ---~ ---~ local function do_process_page(attribute,processor,stack) ---~ if stack then ---~ for i, node in ipairs(stack) do ---~ if node then ---~ local kind = node[1] ---~ if kind == 'hlist' or kind == "vlist" then ---~ local content = node[8] ---~ if not content then ---~ -- nil node ---~ elseif type(content) == "table" then ---~ node[8] = do_process_page(attribute,processor,content) ---~ else ---~ node[8] = do_process_page(attribute,processor,tex.get_node_list(content)) ---~ end ---~ elseif kind == 'inline' then ---~ node[4] = do_process_page(attribute,processor,node[4]) ---~ else ---~ processor(attribute,stack,i,node,kind) ---~ end ---~ end ---~ end ---~ end ---~ return stack ---~ end ---~ ---~ function nodes.process_page(stack,...) ---~ if stack then ---~ input.start_timing(nodes) ---~ local done, used = false, { } ---~ for name, plugin in pairs(shipouts.plugins) do ---~ local attribute = attributes.numbers[name] ---~ if attribute then ---~ local initializer = plugin.initializer ---~ local processor = plugin.processor ---~ local finalizer = plugin.finalizer ---~ if initializer then ---~ initializer(attribute,stack) ---~ end ---~ if processor then ---~ do_process_page(attribute,processor,stack) ---~ end ---~ if finalizer then ---~ local ok ---~ ok, used[attribute] = finalizer(attribute,stack) ---~ done = done or ok ---~ end ---~ else ---~ texio.write_nl(string.format("undefined attribute %s",name)) ---~ end ---~ end ---~ if done then ---~ stack = do_collapse_page(stack) ---~ for name, plugin in pairs(shipouts.plugins) do ---~ local attribute = attributes.numbers[name] ---~ if used[attribute] then ---~ local flusher = plugin.flusher ---~ if flusher then ---~ flusher(attribute,stack,used[attribute]) ---~ end ---~ end ---~ end ---~ else ---~ stack = true ---~ end ---~ input.stop_timing(nodes) ---~ end ---~ return stack ---~ end ---~ ---~ function states.finalize(what,attribute,stack) ---~ if what.enabled then ---~ if current > 0 then ---~ local list = stack ---~ if #stack == 1 then ---~ list = stack[#stack][8] ---~ end ---~ list[#list+1], current, done, used[0] = what.none, 0, true, true ---~ end ---~ end ---~ return done, used ---~ end ---~ ---~ function states.process(what,attribute,stack,i,node,kind) ---~ if what.enabled then ---~ local a = node[3] ---~ if a then ---~ local c = a[attribute] ---~ if c then ---~ if current ~= c and (kind == 'glyph' or kind == 'rule') then ---~ stack[i], current, done, used[c] = nodes.inline(what.data[c], node), c, true, true ---~ end ---~ elseif current > 0 then ---~ stack[i], current, done, used[0] = nodes.inline(what.none, node), 0, true, true ---~ end ---~ end ---~ end ---~ end |