if not modules then modules = { } end modules ['pack-obj'] = { version = 1.001, comment = "companion to pack-obj.mkiv", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } -- We save object references in the main utility table; job objects are reusable -- components. local context = context local codeinjections = backends.codeinjections local ctx_doifelse = commands.doifelse local report = logs.reporter("objects") local trace = false trackers.register("objects",function(v) trace = v end) local nuts = nodes.nuts local setlink = nuts.setlink local getlist = nuts.getlist local setbox = nuts.setbox local new_latelua = nuts.pool.latelua local settexdimen = tokens.setters.dimen local getcount = tex.getcount local implement = interfaces.implement local setmacro = interfaces.setmacro local allocate = utilities.storage.allocate local collected = allocate() local tobesaved = allocate() local jobobjects = { collected = collected, tobesaved = tobesaved, } job.objects = jobobjects local function initializer() collected = jobobjects.collected tobesaved = jobobjects.tobesaved end job.register('job.objects.collected', tobesaved, initializer, nil) local function saveobject(tag,number,page) local data = { number, page } tobesaved[tag] = data collected[tag] = data end local function saveobjectspec(specification) local tag = specification.tag local data = { specification.number, specification.page } tobesaved[tag] = data collected[tag] = data end local function setobject(tag,number,page) collected[tag] = { number, page } end local function getobject(tag) return collected[tag] or tobesaved[tag] end local function getobjectnumber(tag,default) local o = collected[tag] or tobesaved[tag] return o and o[1] or default end local function getobjectpage(tag,default) local o = collected[tag] or tobesaved[tag] return o and o[2] or default end jobobjects.save = saveobject jobobjects.set = setobject jobobjects.get = getobject jobobjects.number = getobjectnumber jobobjects.page = getobjectpage local data = table.setmetatableindex("table") objects = { data = data, n = 0, } local objects = objects function objects.register(ns,id,b,referenced,offset,mode,delay) -- The delay feature is just an experiment: a value of 1 delays the -- flushing and 2 overloads the content. It might disappear again. local found = data[ns][id] nodes.handlers.finalizebox(b) if found and delay == 2 then data[ns][id] = { codeinjections.registerboxresource(b,nil,nil,found[1]), -- hardcoded [1] offset, referenced or false, mode, } return elseif mode == 0 then -- tex data[ns][id] = { codeinjections.registerboxresource(b,nil,delay), -- a box number offset, referenced or false, mode, } else -- box (backend) data[ns][id] = { codeinjections.registerboxresource(b,offset,delay), -- a box number false, referenced, mode, } end if trace then report("registering object %a (n=%i)",id,n) end end function objects.restore(ns,id) -- why not just pass a box number here too (ok, we also set offset) local d = data[ns][id] if d then local index = d[1] local offset = d[2] local status = d[3] local mode = d[4] local hbox = codeinjections.restoreboxresource(index) -- a nut ! if status then local list = getlist(hbox) local page = new_latelua { action = saveobjectspec, tag = ns .. "::" .. id, number = index, page = getcount("realpageno"), } -- list is a rule setlink(list,page) end setbox("b_pack_objects",hbox) settexdimen("d_pack_objects_offset",offset or 0) else setbox("b_pack_objects",nil) settexdimen("d_pack_objects_offset",0) -- for good old times end if trace then report("restoring object %a",id) end end function objects.dimensions(index) local d = data[ns][id] if d then return codeinjections.boxresourcedimensions(d[1]) else return 0, 0, 0, 0 end end function objects.reference(ns,id) local d = data[ns][id] if d then return d[1] else return getobjectnumber(ns .."::" .. id,0) end end function objects.page(ns,id) return getobjectpage(ns .."::" .. id,getcount("realpageno")) end function objects.found(ns,id) return data[ns][id] end implement { name = "registerreferencedobject", arguments = { "string", "string", "integer", true, "dimension", "integer", "integer" }, actions = objects.register, } implement { name = "registerobject", arguments = { "string", "string", "integer", false, "dimension", "integer", "integer" }, actions = objects.register, } implement { name = "restoreobject", arguments = "2 strings", actions = objects.restore, } implement { name = "doifelseobjectfound", arguments = "2 arguments", public = true, protected = true, actions = function(ns,id) ctx_doifelse(data[ns][id]) -- ctx_doifelse(objects.reference(ns,id)) end, } implement { name = "doifelseobjectreferencefound", arguments = "2 arguments", public = true, protected = true, actions = function(ns,id) -- ctx_doifelse(data[ns][id]) ctx_doifelse(objects.reference(ns,id)) end, } implement { name = "getobjectreference", arguments = { "argument", "argument", "csname" }, public = true, protected = true, actions = function(ns,id,target) setmacro(target,objects.reference(ns,id),"global") end } implement { name = "getobjectreferencepage", arguments = { "argument", "argument", "csname" }, public = true, protected = true, actions = function(ns,id,target) setmacro(target,objects.page(ns,id),"global") end } implement { name = "getobjectdimensions", arguments = "2 arguments", public = true, protected = true, actions = function(ns,id) local object = data[ns][id] local w, h, d, o = 0, 0, 0, 0 if object then w, h, d, o = codeinjections.boxresourcedimensions(object[1]) end settexdimen("d_pack_objects_width", w or 0) settexdimen("d_pack_objects_height",h or 0) settexdimen("d_pack_objects_depth", d or 0) settexdimen("d_pack_objects_offset",o or #objects > 2 and object[2] or 0) end } -- for the moment here: implement { name = "registerbackendsymbol", arguments = { "string", "integer" }, actions = function(...) codeinjections.registersymbol(...) end }