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