1if modules then modules = { } end modules ['typo-bld'] = {
2 version = 1.001,
3 comment = "companion to typo-bld.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
11local insert, remove = table.insert, table.remove
12
13builders = builders or { }
14local builders = builders
15
16builders.paragraphs = builders.paragraphs or { }
17local parbuilders = builders.paragraphs
18
19parbuilders.constructors = parbuilders.constructors or { }
20local constructors = parbuilders.constructors
21
22constructors.names = constructors.names or { }
23local names = constructors.names
24
25constructors.numbers = constructors.numbers or { }
26local numbers = constructors.numbers
27
28constructors.methods = constructors.methods or { }
29local methods = constructors.methods
30
31local a_parbuilder = attributes.numbers['parbuilder'] or 999
32constructors.attribute = a_parbuilder
33
34local unsetvalue = attributes.unsetvalue
35local texsetattribute = tex.setattribute
36local texnest = tex.nest
37local texlists = tex.lists
38
39local texget = tex.get
40local texset = tex.set
41
42local texgetdimen = tex.getdimen
43
44local nodes = nodes
45local nodeidstostring = nodes.idstostring
46local nodepool = nodes.pool
47local new_baselineskip = nodepool.baselineskip
48local new_lineskip = nodepool.lineskip
49local insertnodebefore = nodes.insertbefore
50local hpack_node = nodes.hpack
51
52local nuts = nodes.nuts
53local tonode = nodes.tonode
54local tonut = nodes.tonut
55local count_nodes = nuts.countall
56local getattr = nuts.getattr
57
58local starttiming = statistics.starttiming
59local stoptiming = statistics.stoptiming
60
61local registercallback = callbacks.register
62
63storage.register("builders/paragraphs/constructors/names", names, "builders.paragraphs.constructors.names")
64storage.register("builders/paragraphs/constructors/numbers", numbers, "builders.paragraphs.constructors.numbers")
65
66local trace_page_builder = false trackers.register("builders.page", function(v) trace_page_builder = v end)
67local trace_vbox_builder = false trackers.register("builders.vbox", function(v) trace_vbox_builder = v end)
68local trace_post_builder = false trackers.register("builders.post", function(v) trace_post_builder = v end)
69
70local report_page_builder = logs.reporter("builders","page")
71local report_vbox_builder = logs.reporter("builders","vbox")
72local report_par_builder = logs.reporter("builders","par")
73
74local mainconstructor = nil
75local nofconstructors = 0
76local stack = { }
77
78function constructors.define(name)
79 nofconstructors = nofconstructors + 1
80 names[nofconstructors] = name
81 numbers[name] = nofconstructors
82end
83
84function constructors.set(name)
85 if name then
86 mainconstructor = numbers[name] or unsetvalue
87 else
88 mainconstructor = stack[#stack] or unsetvalue
89 end
90 texsetattribute(a_parbuilder,mainconstructor)
91 if mainconstructor ~= unsetvalue then
92 constructors.enable()
93 end
94end
95
96function constructors.start(name)
97 local number = numbers[name]
98 insert(stack,number)
99 mainconstructor = number or unsetvalue
100 texsetattribute(a_parbuilder,mainconstructor)
101 if mainconstructor ~= unsetvalue then
102 constructors.enable()
103 end
104
105end
106
107function constructors.stop()
108 remove(stack)
109 mainconstructor = stack[#stack] or unsetvalue
110 texsetattribute(a_parbuilder,mainconstructor)
111 if mainconstructor == unsetvalue then
112 constructors.disable()
113 end
114
115end
116
117
118
119
120
121
122
123function constructors.handler(head,followed_by_display)
124 if type(head) == "boolean" then
125 return head
126 else
127 local attribute = getattr(head,a_parbuilder)
128 if attribute then
129 local method = names[attribute]
130 if method then
131 local handler = methods[method]
132 if handler then
133 return handler(head,followed_by_display)
134 else
135 report_par_builder("contructor method %a is not defined",tostring(method))
136 return true
137 end
138 end
139 end
140 return true
141 end
142end
143
144
145
146function constructors.methods.default(head,followed_by_display)
147 return true
148end
149
150
151
152function parbuilders.constructors.methods.oneline(head,followed_by_display)
153
154 local t = texnest[texnest.ptr]
155 local h = hpack_node(head)
156 local d = texget("baselineskip",false) - t.prevdepth - h.height
157 t.prevdepth = h.depth
158 t.prevgraf = 1
159 if d < texget("lineskiplimit") then
160 return insertnodebefore(h,h,new_lineskip(texget("lineskip",false)))
161 else
162 return insertnodebefore(h,h,new_baselineskip(d))
163 end
164end
165
166
167
168
169
170
171
172
173local actions = constructors.handler
174local enabled = false
175
176local function processor(head,followed_by_display)
177
178 if enabled then
179 starttiming(parbuilders)
180 head = tonut(head)
181 head = actions(head,followed_by_display)
182 head = tonode(head)
183 stoptiming(parbuilders)
184 return head
185 else
186 return true
187 end
188end
189
190function constructors.enable () enabled = true end
191function constructors.disable() enabled = false end
192
193registercallback('linebreak_filter', processor, "breaking paragraps into lines")
194
195statistics.register("linebreak processing time", function()
196 return statistics.elapsedseconds(parbuilders)
197end)
198
199
200
201nodes.builders = nodes.builder or { }
202local builders = nodes.builders
203
204local vboxactions = nodes.tasks.actions("vboxbuilders")
205
206function builders.vpack_filter(head,groupcode,size,packtype,maxdepth,direction)
207 local done = false
208 if head then
209 starttiming(builders)
210 head = tonut(head)
211 if trace_vbox_builder then
212 local before = count_nodes(head)
213 head, done = vboxactions(head,groupcode,size,packtype,maxdepth,direction)
214 local after = count_nodes(head)
215 nodes.processors.tracer("vpack",head,groupcode,before,after,done)
216 else
217 head, done = vboxactions(head,groupcode)
218 end
219 head = tonode(head)
220 stoptiming(builders)
221 end
222 return head, done
223end
224
225
226
227
228local pageactions = nodes.tasks.actions("mvlbuilders")
229
230
231local function report(groupcode,head)
232 report_page_builder("trigger: %s",groupcode)
233 report_page_builder(" vsize : %p",texget("vsize"))
234 report_page_builder(" pagegoal : %p",texget("pagegoal"))
235 report_page_builder(" pagetotal: %p",texget("pagetotal"))
236 report_page_builder(" list : %s",head and nodeidstostring(head) or "<empty>")
237end
238
239
240
241
242
243
244
245function builders.buildpage_filter(groupcode)
246 local head = texlists.contrib_head
247 if head then
248 local done = false
249
250 starttiming(builders)
251 if trace_page_builder then
252 report(groupcode,head)
253 end
254 head, done = pageactions(head,groupcode)
255 stoptiming(builders)
256
257
258 texlists.contrib_head = head or nil
259
260 return done and head or true
261 else
262
263 if trace_page_builder then
264 report(groupcode)
265 end
266
267 return nil
268 end
269end
270
271registercallback('vpack_filter', builders.vpack_filter, "vertical spacing etc")
272registercallback('buildpage_filter', builders.buildpage_filter, "vertical spacing etc (mvl)")
273
274statistics.register("v-node processing time", function()
275 return statistics.elapsedseconds(builders)
276end)
277
278local implement = interfaces.implement
279
280implement { name = "defineparbuilder", actions = constructors.define, arguments = "string" }
281implement { name = "setparbuilder", actions = constructors.set, arguments = "string" }
282implement { name = "startparbuilder", actions = constructors.start, arguments = "string" }
283implement { name = "stopparbuilder", actions = constructors.stop }
284implement { name = "enableparbuilder", actions = constructors.enable }
285implement { name = "disableparbuilder", actions = constructors.disable }
286
287
288
289local nuts = nodes.nuts
290local tonut = nodes.tonut
291local setcolor = nodes.tracers.colors.set
292local listtoutf = nodes.listtoutf
293local new_kern = nuts.pool.kern
294local new_rule = nuts.pool.rule
295local hpack = nuts.hpack
296local getheight = nuts.getheight
297local getdepth = nuts.getdepth
298local getdirection = nuts.getdirection
299local getlist = nuts.getlist
300local setwidth = nuts.setwidth
301local setdirection = nuts.setdirection
302local setlink = nuts.setlink
303local tonode = nuts.tonode
304
305local report_hpack = logs.reporter("hpack routine")
306local report_vpack = logs.reporter("vpack routine")
307
308
309
310local function vpack_quality(how,n,detail,first,last)
311 if last <= 0 then
312 report_vpack("%s vbox",how)
313 elseif first > 0 and first < last then
314 report_vpack("%s vbox at line %i - %i",how,first,last)
315 else
316 report_vpack("%s vbox at line %i",how,last)
317 end
318end
319
320trackers.register("builders.vpack.quality",function(v)
321 registercallback("vpack_quality",v and report_vpack_quality or nil,"check vpack quality")
322end)
323
324local report, show = false, false
325
326local function hpack_quality(how,detail,n,first,last)
327 n = tonut(n)
328 if report then
329 local str = listtoutf(getlist(n),"",true,nil,true)
330 if last <= 0 then
331 report_hpack("%s hbox: %s",how,str)
332 elseif first > 0 and first < last then
333 report_hpack("%s hbox at line %i - %i: %s",how,first,last,str)
334 else
335 report_hpack("%s hbox at line %i: %s",how,last,str)
336 end
337 end
338 if show then
339 local width = 2*65536
340 local height = getheight(n)
341 local depth = getdepth(n)
342 local direction = getdirection(n)
343 if height < 4*65526 then
344 height = 4*65526
345 end
346 if depth < 2*65526 then
347 depth = 2*65526
348 end
349 local rule = new_rule(width,height,depth)
350 setdirection(rule,direction)
351 if how == "overfull" then
352 setcolor(rule,"red")
353 local kern = new_kern(-detail)
354 setlink(kern,rule)
355 rule = kern
356 elseif how == "underfull" then
357 setcolor(rule,"blue")
358 elseif how == "loose" then
359 setcolor(rule,"magenta")
360 elseif how == "tight" then
361 setcolor(rule,"cyan")
362 end
363 rule = hpack(rule)
364 setwidth(rule,0)
365 setdirection(rule,direction)
366 return tonode(rule)
367 end
368end
369
370trackers.register("builders.hpack.quality",function(v)
371 report = v
372 registercallback("hpack_quality",(report or show) and hpack_quality or nil,"check hpack quality")
373end)
374
375trackers.register("builders.hpack.overflow",function(v)
376 show = v
377 registercallback("hpack_quality",(report or show) and hpack_quality or nil,"check hpack quality")
378end)
379 |