pack-obj.lmt /size: 7271 b    last modification: 2023-12-21 09:44
1if not modules then modules = { } end modules ['pack-obj'] = {
2    version   = 1.001,
3    comment   = "companion to pack-obj.mkiv",
4    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5    copyright = "PRAGMA ADE / ConTeXt Development Team",
6    license   = "see context related readme files"
7}
8
9-- We save object references in the main utility table; job objects are reusable
10-- components.
11
12local context         = context
13local codeinjections  = backends.codeinjections
14local ctx_doifelse    = commands.doifelse
15
16local report          = logs.reporter("objects")
17local trace           = false  trackers.register("objects",function(v) trace = v end)
18
19local nuts            = nodes.nuts
20
21local setlink         = nuts.setlink
22local getlist         = nuts.getlist
23local setbox          = nuts.setbox
24
25local new_latelua     = nuts.pool.latelua
26
27local settexdimen     = tokens.setters.dimen
28
29local getcount        = tex.getcount
30
31local implement       = interfaces.implement
32local setmacro        = interfaces.setmacro
33
34local allocate        = utilities.storage.allocate
35
36local collected       = allocate()
37local tobesaved       = allocate()
38
39local jobobjects      = {
40    collected = collected,
41    tobesaved = tobesaved,
42}
43
44job.objects           = jobobjects
45
46local function initializer()
47    collected = jobobjects.collected
48    tobesaved = jobobjects.tobesaved
49end
50
51job.register('job.objects.collected', tobesaved, initializer, nil)
52
53local function saveobject(tag,number,page)
54    local data = { number, page }
55    tobesaved[tag] = data
56    collected[tag] = data
57end
58
59local function saveobjectspec(specification)
60    local tag  = specification.tag
61    local data = { specification.number, specification.page }
62    tobesaved[tag] = data
63    collected[tag] = data
64end
65
66local function setobject(tag,number,page)
67    collected[tag] = { number, page }
68end
69
70local function getobject(tag)
71    return collected[tag] or tobesaved[tag]
72end
73
74local function getobjectnumber(tag,default)
75    local o = collected[tag] or tobesaved[tag]
76    return o and o[1] or default
77end
78
79local function getobjectpage(tag,default)
80    local o = collected[tag] or tobesaved[tag]
81    return o and o[2] or default
82end
83
84jobobjects.save   = saveobject
85jobobjects.set    = setobject
86jobobjects.get    = getobject
87jobobjects.number = getobjectnumber
88jobobjects.page   = getobjectpage
89
90
91local data = table.setmetatableindex("table")
92
93objects = {
94    data = data,
95    n    = 0,
96}
97
98local objects = objects
99
100function objects.register(ns,id,b,referenced,offset,mode,delay)
101    -- The delay feature is just an experiment: a value of 1 delays the
102    -- flushing and 2 overloads the content. It might disappear again.
103    local found = data[ns][id]
104    nodes.handlers.finalizebox(b)
105    if found and delay == 2 then
106        data[ns][id] = {
107            codeinjections.registerboxresource(b,nil,nil,found[1]), -- hardcoded [1]
108            offset,
109            referenced or false,
110            mode,
111        }
112        return
113    elseif mode == 0 then
114        -- tex
115        data[ns][id] = {
116            codeinjections.registerboxresource(b,nil,delay), -- a box number
117            offset,
118            referenced or false,
119            mode,
120        }
121    else
122        -- box (backend)
123        data[ns][id] = {
124            codeinjections.registerboxresource(b,offset,delay), -- a box number
125            false,
126            referenced,
127            mode,
128        }
129    end
130    if trace then
131        report("registering object %a (n=%i)",id,n)
132    end
133end
134
135function objects.restore(ns,id) -- why not just pass a box number here too (ok, we also set offset)
136    local d = data[ns][id]
137    if d then
138        local index  = d[1]
139        local offset = d[2]
140        local status = d[3]
141        local mode   = d[4]
142        local hbox   = codeinjections.restoreboxresource(index) -- a nut !
143        if status then
144            local list = getlist(hbox)
145            local page = new_latelua {
146                action = saveobjectspec,
147                tag    = ns .. "::" .. id,
148                number = index,
149                page   = getcount("realpageno"),
150            }
151            -- list is a rule
152            setlink(list,page)
153        end
154        setbox("b_pack_objects",hbox)
155        settexdimen("d_pack_objects_offset",offset or 0)
156    else
157        setbox("b_pack_objects",nil)
158        settexdimen("d_pack_objects_offset",0) -- for good old times
159    end
160    if trace then
161        report("restoring object %a",id)
162    end
163end
164
165function objects.dimensions(index)
166    local d = data[ns][id]
167    if d then
168        return codeinjections.boxresourcedimensions(d[1])
169    else
170        return 0, 0, 0, 0
171    end
172end
173
174function objects.reference(ns,id)
175    local d = data[ns][id]
176    if d then
177        return d[1]
178    else
179        return getobjectnumber(ns .."::" .. id,0)
180    end
181end
182
183function objects.page(ns,id)
184    return getobjectpage(ns .."::" .. id,getcount("realpageno"))
185end
186
187function objects.found(ns,id)
188    return data[ns][id]
189end
190
191implement {
192    name      = "registerreferencedobject",
193    arguments = { "string", "string", "integer", true, "dimension", "integer", "integer" },
194    actions   = objects.register,
195}
196
197implement {
198    name      = "registerobject",
199    arguments = { "string", "string", "integer", false, "dimension", "integer", "integer" },
200    actions   = objects.register,
201}
202
203implement {
204    name      = "restoreobject",
205    arguments = "2 strings",
206    actions   = objects.restore,
207}
208
209implement {
210    name      = "doifelseobjectfound",
211    arguments = "2 arguments",
212    public    = true,
213    protected = true,
214    actions   = function(ns,id)
215        ctx_doifelse(data[ns][id])
216     -- ctx_doifelse(objects.reference(ns,id))
217    end,
218}
219
220implement {
221    name      = "doifelseobjectreferencefound",
222    arguments = "2 arguments",
223    public    = true,
224    protected = true,
225    actions   = function(ns,id)
226     -- ctx_doifelse(data[ns][id])
227        ctx_doifelse(objects.reference(ns,id))
228    end,
229}
230
231implement {
232    name      = "getobjectreference",
233    arguments = { "argument", "argument", "csname" },
234    public    = true,
235    protected = true,
236    actions   = function(ns,id,target)
237        setmacro(target,objects.reference(ns,id),"global")
238    end
239}
240
241implement {
242    name      = "getobjectreferencepage",
243    arguments = { "argument", "argument", "csname" },
244    public    = true,
245    protected = true,
246    actions   = function(ns,id,target)
247        setmacro(target,objects.page(ns,id),"global")
248    end
249}
250
251implement {
252    name      = "getobjectdimensions",
253    arguments = "2 arguments",
254    public    = true,
255    protected = true,
256    actions   = function(ns,id)
257        local object = data[ns][id]
258        local w, h, d, o = 0, 0, 0, 0
259        if object then
260            w, h, d, o = codeinjections.boxresourcedimensions(object[1])
261        end
262        settexdimen("d_pack_objects_width", w or 0)
263        settexdimen("d_pack_objects_height",h or 0)
264        settexdimen("d_pack_objects_depth", d or 0)
265        settexdimen("d_pack_objects_offset",o or #objects > 2 and object[2] or 0)
266    end
267}
268
269-- for the moment here:
270
271implement {
272    name      = "registerbackendsymbol",
273    arguments = { "string", "integer" },
274    actions   = function(...)
275        codeinjections.registersymbol(...)
276    end
277}
278