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