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_rule = nuts.pool.rule
31
32
33local setlink = nuts.setlink
34local getlist = nuts.getlist
35local setlist = nuts.setlist
36local getwhd = nuts.getwhd
37local setwhd = nuts.setwhd
38
39local settings_to_array = utilities.parsers.settings_to_array
40
41local enableaction = nodes.tasks.enableaction
42
43local texgetdimen = tex.getdimen
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
230
231 local line = new_rule(0,strutht,strutdp)
232 if tail then
233
234 setlink(tail,line)
235 end
236 tail = line
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 |