if not modules then modules = { } end modules ['typo-stc'] = { version = 1.001, comment = "companion to typo-stc.mkxl", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } local tonumber, next = tonumber, next local gmatch = string.gmatch local stepper = utilities.parsers.stepper -- local trace_stacking = false trackers.register("typesetters.stacking", function(v) trace_stacking = v end) -- -- local report_stacking = logs.reporter("typesetting","stacking") local nodes, node = nodes, node local nuts = nodes.nuts local tonut = nuts.tonut local nodecodes = nodes.nodecodes local glyph_code = nodecodes.glyph local disc_code = nodecodes.disc -- unlikely local hlist_code = nodecodes.hlist local vlist_code = nodecodes.vlist local whatsit_code = nodecodes.whatsit local rule_code = nodecodes.rule local glue_code = nodecodes.glue local emptyrule_code = nodes.rulecodes.empty local a_stacking = attributes.private("stacking") local getattr = nuts.getattr local getwhd = nuts.getwhd local getlist = nuts.getlist local setlist = nuts.setlist local setleader = nuts.setleader local getsubtype = nuts.getsubtype local setsubtype = nuts.setsubtype local isnextglyph = nuts.isnextglyph local replace_node = nuts.replace local remove_node = nuts.remove local nextcontent = nuts.traversers.content local new_emptyrule = nuts.pool.emptyrule local unblocked = { savepos = true, save = true, restore = true, setmatrix = true, startmatrix = true, stopmatrix = true, startscaling = true, stopscaling = true, startrotation = true, stoprotation = true, startmirroring = true, stopmirroring = true, startclipping = true, stopclipping = true, } local stacking = typesetters.stacking or { } typesetters.stacking = stacking local nofstacking = 0xFFFF -- we don't mix with numbers local registered = { } local currentset = { } local enabled = false local function getselection(str) local t = { } stepper(str,function(s) local r = registered[s] or tonumber(s) if r then t[r] = true end end) return t end local function getindex(str) return registered[str] or tonumber(str) or 0 end typesetters.stacking.getselection = getselection typesetters.stacking.getindex = getindex local report = logs.reporter("stacking") local trace = false interfaces.implement { name = "newstacking", arguments = "2 strings", usage = "value", actions = function(s,n) n = n and tonumber(n) if not n then nofstacking = nofstacking + 1 n = nofstacking end registered[s] = n if trace then report("define %a as index %i",s,n) end return tokens.values.integer, n end, } interfaces.implement { name = "enablestacking", actions = function() if not enabled then nodes.tasks.enableaction("shipouts", "typesetters.stacking.handler") enabled = true end end, } interfaces.implement { name = "setstacking", arguments = "string", actions = function(str) currentset = getselection(str) if not enabled and next(currentset) then if trace then report("selecting %a",str) end nodes.tasks.enableaction("shipouts", "typesetters.stacking.handler") enabled = true end end, } local function process(head) local current = head while current do local nxt, chr, id = isnextglyph(current) if chr then local a = getattr(current,a_stacking) if a and (a == 0 or not currentset[a]) then local w, h, d = getwhd(current) local r = new_emptyrule(w,h,d) head, current = replace_node(head,current,r) end elseif id == glue_code then local a = getattr(current,a_stacking) if a and (a == 0 or not currentset[a]) then setleader(current) end elseif id == hlist_code or id == vlist_code then local a = getattr(current,a_stacking) if a and (a == 0 or not currentset[a]) then setlist(current) else local list = getlist(current) if list then local l = process(list) if l ~= list then setlist(current,l) end end end elseif id == rule_code then local a = getattr(current,a_stacking) if a and not currentset[a] then setsubtype(current,emptyrule_code) end elseif id == whatsit_code then local a = getattr(current,a_stacking) if a and (a == 0 or not currentset[a]) and not unblocked[getsubtype(current)] then head, current = remove_node(head,current,true) end elseif id == disc_code then -- doesn't happen local a = getattr(current,a_stacking) if a and (a == 0 or not currentset[a]) then local w, h, d = getwhd(current) local r = new_emptyrule(w,h,d) head, current = replace_node(head,current,r) end end current = nxt end return head end stacking.handler = process