1if not modules then modules = { } end modules ['page-str'] = {
2 version = 1.001,
3 comment = "companion to page-str.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
10
11
12
13local concat, insert, remove = table.concat, table.insert, table.remove
14
15local nodes, node = nodes, node
16
17local tasks = nodes.tasks
18
19local implement = interfaces.implement
20
21local nodecodes = nodes.nodecodes
22
23local nuts = nodes.nuts
24local tonut = nodes.tonut
25local slide_node_list = nuts.slide
26local write_node = nuts.write
27local flushnode = nuts.flush
28local copy_node_list = nuts.copylist
29local vpack_node_list = nuts.vpack
30local new_strut = nuts.pool.strutrule
31
32
33local setlink = nuts.setlink
34local getlist = nuts.getlist
35local setlist = nuts.setlist
36local getwhd = nuts.getwhd
37local setwhd = nuts.setwhd
38local setattrlist = nuts.setattrlist
39
40local settings_to_array = utilities.parsers.settings_to_array
41
42local enableaction = nodes.tasks.enableaction
43
44local texgetdimen = tex.getdimen
45
46local trace_collecting = false trackers.register("streams.collecting", function(v) trace_collecting = v end)
47local trace_flushing = false trackers.register("streams.flushing", function(v) trace_flushing = v end)
48
49local report_streams = logs.reporter("streams")
50
51streams = streams or { }
52local streams = streams
53
54
55
56local data = { }
57local name = nil
58local stack = { }
59
60function streams.enable(newname)
61 if newname == "default" then
62 name = nil
63 else
64 name = newname
65 end
66end
67
68function streams.disable()
69 name = stack[#stack]
70end
71
72function streams.start(newname)
73 insert(stack,name)
74 name = newname
75end
76
77function streams.stop(newname)
78 name = remove(stack)
79end
80
81function streams.collect(head,where)
82 if name and head and name ~= "default" then
83 local head = tonut(head)
84 local dana = data[name]
85 if not dana then
86 dana = { }
87 data[name] = dana
88 end
89 local last = dana[#dana]
90 if last then
91 local tail = slide_node_list(last)
92 setlink(tail,head)
93 elseif last == false then
94 dana[#dana] = head
95 else
96 dana[1] = head
97 end
98 if trace_collecting then
99 report_streams("appending snippet %a to slot %s",name,#dana)
100 end
101 return nil
102 else
103 return head
104 end
105end
106
107function streams.push(thename)
108 if not thename or thename == "" then
109 thename = name
110 end
111 if thename and thename ~= "" then
112 local dana = data[thename]
113 if dana then
114 dana[#dana+1] = false
115 if trace_collecting then
116 report_streams("pushing snippet %a",thename)
117 end
118 end
119 end
120end
121
122function streams.flush(name,copy)
123 local dana = data[name]
124 if dana then
125 local dn = #dana
126 if dn == 0 then
127
128 elseif copy then
129 if trace_flushing then
130 report_streams("flushing copies of %s slots of %a",dn,name)
131 end
132 for i=1,dn do
133 local di = dana[i]
134 if di then
135 write_node(copy_node_list(getlist(di)))
136 end
137 end
138 if copy then
139 data[name] = nil
140 end
141 else
142 if trace_flushing then
143 report_streams("flushing %s slots of %a",dn,name)
144 end
145 for i=1,dn do
146 local di = dana[i]
147 if di then
148 write_node(getlist(di))
149 setlist(di)
150 flushnode(di)
151 end
152 end
153 end
154 end
155end
156
157function streams.synchronize(list)
158
159 list = settings_to_array(list)
160 local max = 0
161 if trace_flushing then
162 report_streams("synchronizing list: % t",list)
163 end
164 for i=1,#list do
165 local dana = data[list[i]]
166 if dana then
167 local n = #dana
168 if n > max then
169 max = n
170 end
171 end
172 end
173 if trace_flushing then
174 report_streams("maximum number of slots: %s",max)
175 end
176 for m=1,max do
177 local height, depth = 0, 0
178 for i=1,#list do
179 local name = list[i]
180 local dana = data[name]
181 if dana then
182 local slot = dana[m]
183 if slot then
184 local vbox = vpack_node_list(slot)
185 local wd, ht, dp = getwhd(vbox)
186 if ht > height then
187 height = ht
188 end
189 if dp > depth then
190 depth = dp
191 end
192 dana[m] = vbox
193 if trace_flushing then
194 report_streams("slot %s of %a is packed to height %p and depth %p",m,name,ht,dp)
195 end
196 end
197 end
198 end
199 if trace_flushing then
200 report_streams("slot %s has max height %p and max depth %p",m,height,depth)
201 end
202 local strutht = texgetdimen("globalbodyfontstrutheight")
203 local strutdp = texgetdimen("globalbodyfontstrutdepth")
204 local struthtdp = strutht + strutdp
205 for i=1,#list do
206 local name = list[i]
207 local dana = data[name]
208 if dana then
209 local vbox = dana[m]
210 if vbox then
211 local wd, ht, dp = getwhd(vbox)
212 local delta_height = height - ht
213 local delta_depth = depth - dp
214 if delta_height > 0 or delta_depth > 0 then
215 if false then
216
217 setwhd(vbox,false,height,depth)
218 if trace_flushing then
219 report_streams("slot %s of %a with delta (%p,%p) is compensated",m,i,delta_height,delta_depth)
220 end
221 else
222
223
224 local list = getlist(vbox)
225 local tail = list and slide_node_list(list)
226 local n = 0
227 local delta = delta_height
228 while delta > 0 do
229
230 local strut = new_strut(0,strutht,strutdp)
231 setattrlist(strut,vbox)
232 if tail then
233
234 setlink(tail,strut)
235 end
236 tail = strut
237 n = n + 1
238 delta = delta - struthtdp
239 end
240 dana[m] = vpack_node_list(getlist(vbox))
241 setlist(vbox)
242 flushnode(vbox)
243 if trace_flushing then
244 report_streams("slot %s:%s with delta (%p,%p) is compensated by %s lines",m,i,delta_height,delta_depth,n)
245 end
246 end
247 end
248 end
249 else
250
251 end
252 end
253 end
254end
255
256
257
258tasks.appendaction("mvlbuilders", "normalizers", "streams.collect")
259
260tasks.disableaction("mvlbuilders", "streams.collect")
261
262function streams.initialize()
263 enableaction("mvlbuilders","streams.collect")
264 function streams.initialize() end
265end
266
267
268
269
270implement {
271 name = "initializestream",
272 actions = streams.initialize,
273 onlyonce = true,
274}
275
276implement {
277 name = "enablestream",
278 actions = streams.enable,
279 arguments = "string"
280}
281
282implement {
283 name = "disablestream",
284 actions = streams.disable
285}
286
287implement {
288 name = "startstream",
289 actions = streams.start,
290 arguments = "string"
291}
292
293implement {
294 name = "stopstream",
295 actions = streams.stop
296}
297
298implement {
299 name = "flushstream",
300 actions = streams.flush,
301 arguments = "string"
302}
303
304implement {
305 name = "flushstreamcopy",
306 actions = streams.flush,
307 arguments = { "string", true }
308}
309
310implement {
311 name = "synchronizestream",
312 actions = streams.synchronize,
313 arguments = "string"
314}
315
316implement {
317 name = "pushstream",
318 actions = streams.push,
319 arguments = "string"
320}
321 |