1if not modules then modules = { } end modules ['node-res'] = {
2 version = 1.001,
3 comment = "companion to node-ini.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
9local type, next, rawset = type, next, rawset
10local gmatch, format = string.gmatch, string.format
11local round = math.round
12
13local nodes, node = nodes, node
14
15local report_nodes = logs.reporter("nodes","housekeeping")
16
17nodes.pool = nodes.pool or { }
18local nodepool = nodes.pool
19
20local gluecodes = nodes.gluecodes
21local kerncodes = nodes.kerncodes
22local rulecodes = nodes.rulecodes
23local nodecodes = nodes.nodecodes
24local boundarycodes = nodes.boundarycodes
25local usercodes = nodes.usercodes
26
27local nodeproperties = nodes.properties.data
28
29local glyph_code = nodecodes.glyph
30local rule_code = nodecodes.rule
31local kern_code = nodecodes.kern
32local glue_code = nodecodes.glue
33local gluespec_code = nodecodes.gluespec
34
35local currentfont = font.current
36local texgetcount = tex.getcount
37
38local allocate = utilities.storage.allocate
39
40local reserved = { }
41local nofreserved = 0
42
43
44
45local nuts = nodes.nuts
46local nutpool = { }
47nuts.pool = nutpool
48
49local tonut = nuts.tonut
50local tonode = nuts.tonode
51
52local getbox = nuts.getbox
53local getid = nuts.getid
54local getlist = nuts.getlist
55local getglue = nuts.getglue
56
57local setfield = nuts.setfield
58local setchar = nuts.setchar
59local setlist = nuts.setlist
60local setwhd = nuts.setwhd
61local setglue = nuts.setglue
62local setdisc = nuts.setdisc
63local setfont = nuts.setfont
64local setkern = nuts.setkern
65local setpenalty = nuts.setpenalty
66local setdir = nuts.setdir
67local setdirection = nuts.setdirection
68local setshift = nuts.setshift
69local setwidth = nuts.setwidth
70local setsubtype = nuts.setsubtype
71local setleader = nuts.setleader
72local setclass = nuts.setclass
73local setdata = nuts.setdata
74local setoffsets = nuts.setoffsets
75local setvalue = nuts.setvalue
76
77local setruledimensions = nuts.setruledimensions
78
79local copy_nut = nuts.copyonly
80local new_nut = nuts.new
81local flush_nut = nuts.flush
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99table.setmetatableindex(nodepool,function(t,k,v)
100
101 local v = function(...)
102 local f = nutpool[k]
103 local v = function(...)
104 return tonode(f(...))
105 end
106 t[k] = v
107 return v(...)
108 end
109 t[k] = v
110 return v
111end)
112
113local function register_nut(n)
114 nofreserved = nofreserved + 1
115 reserved[nofreserved] = n
116 return n
117end
118
119local function register_node(n)
120 nofreserved = nofreserved + 1
121 if type(n) == "number" then
122 reserved[nofreserved] = n
123 else
124 reserved[nofreserved] = tonut(n)
125 end
126 return n
127end
128
129nodepool.register = register_node
130nutpool.register = register_node
131
132
133
134local disc = register_nut(new_nut(nodecodes.disc))
135local kern = register_nut(new_nut(kern_code,kerncodes.userkern))
136local fontkern = register_nut(new_nut(kern_code,kerncodes.fontkern))
137local italickern = register_nut(new_nut(kern_code,kerncodes.italiccorrection))
138local spacefontkern = register_nut(new_nut(kern_code,kerncodes.spacefontkern))
139local penalty = register_nut(new_nut(nodecodes.penalty))
140local glue = register_nut(new_nut(glue_code))
141local gluespec = register_nut(new_nut(gluespec_code))
142local glyph = register_nut(new_nut(glyph_code,0))
143
144local textdir = register_nut(new_nut(nodecodes.dir))
145
146local left_margin_kern = register_nut(new_nut(kern_code,kerncodes.leftmargincode))
147local right_margin_kern = register_nut(new_nut(kern_code,kerncodes.rightmargincode))
148
149local lineskip = register_nut(new_nut(glue_code,gluecodes.lineskip))
150local baselineskip = register_nut(new_nut(glue_code,gluecodes.baselineskip))
151local leftskip = register_nut(new_nut(glue_code,gluecodes.leftskip))
152local rightskip = register_nut(new_nut(glue_code,gluecodes.rightskip))
153local lefthangskip = register_nut(new_nut(glue_code,gluecodes.lefthangskip))
154local righthangskip = register_nut(new_nut(glue_code,gluecodes.righthangskip))
155local indentskip = register_nut(new_nut(glue_code,gluecodes.indentskip))
156local correctionskip = register_nut(new_nut(glue_code,gluecodes.correctionskip))
157
158local temp = register_nut(new_nut(nodecodes.temp,0))
159
160local noad = register_nut(new_nut(nodecodes.noad))
161local delimiter = register_nut(new_nut(nodecodes.delimiter))
162local fence = register_nut(new_nut(nodecodes.fence))
163local submlist = register_nut(new_nut(nodecodes.submlist))
164local accent = register_nut(new_nut(nodecodes.accent))
165local radical = register_nut(new_nut(nodecodes.radical))
166local fraction = register_nut(new_nut(nodecodes.fraction))
167local subbox = register_nut(new_nut(nodecodes.subbox))
168local mathchar = register_nut(new_nut(nodecodes.mathchar))
169local mathtextchar = register_nut(new_nut(nodecodes.mathtextchar))
170local choice = register_nut(new_nut(nodecodes.choice))
171
172local boundary = register_nut(new_nut(nodecodes.boundary,boundarycodes.user))
173local wordboundary = register_nut(new_nut(nodecodes.boundary,boundarycodes.word))
174
175local cleader = register_nut(copy_nut(glue)) setsubtype(cleader,gluecodes.cleaders) setglue(cleader,0,65536,0,2,0)
176
177
178
179local lefttoright_code = tex.directioncodes.lefttoright
180
181local rule = register_nut(new_nut(rule_code))
182local emptyrule = register_nut(new_nut(rule_code,rulecodes.empty))
183local strutrule = register_nut(new_nut(rule_code,rulecodes.strut))
184local userrule = register_nut(new_nut(rule_code,rulecodes.user))
185local outlinerule = register_nut(new_nut(rule_code,rulecodes.outline))
186local imagerule = register_nut(new_nut(rule_code,rulecodes.image))
187local boxrule = register_nut(new_nut(rule_code,rulecodes.box))
188local virtualrule = register_nut(new_nut(rule_code,rulecodes.virtual))
189local hlist = register_nut(new_nut(nodecodes.hlist)) setdirection(hlist,lefttoright_code)
190local vlist = register_nut(new_nut(nodecodes.vlist)) setdirection(vlist,lefttoright_code)
191
192function nutpool.glyph(fnt,chr)
193 local n = copy_nut(glyph)
194 if fnt then
195 setfont(n,fnt == true and currentfont() or fnt,chr)
196 elseif chr then
197 setchar(n,chr)
198 end
199 return n
200end
201
202function nutpool.penalty(p)
203 local n = copy_nut(penalty)
204 if p and p ~= 0 then
205 setpenalty(n,p)
206 end
207 return n
208end
209
210function nutpool.kern(k)
211 local n = copy_nut(kern)
212 if k and k ~= 0 then
213 setkern(n,k)
214 end
215 return n
216end
217
218function nutpool.boundary(v)
219 local n = copy_nut(boundary)
220 if v and v ~= 0 then
221 setvalue(n,v)
222 end
223 return n
224end
225
226function nutpool.wordboundary(v)
227 local n = copy_nut(wordboundary)
228 if v and v ~= 0 then
229 setvalue(n,v)
230 end
231 return n
232end
233
234function nutpool.fontkern(k)
235 local n = copy_nut(fontkern)
236 if k and k ~= 0 then
237 setkern(n,k)
238 end
239 return n
240end
241
242function nutpool.italickern(k)
243 local n = copy_nut(italickern)
244 if k and k ~= 0 then
245 setkern(n,k)
246 end
247 return n
248end
249
250function nutpool.spacefontkern(k)
251 local n = copy_nut(spacefontkern)
252 if k and k ~= 0 then
253 setkern(n,k)
254 end
255 return n
256end
257
258function nutpool.gluespec(width,stretch,shrink,stretch_order,shrink_order)
259 local n = copy_nut(gluespec)
260 if width or stretch or shrink or stretch_order or shrink_order then
261 setglue(n,width,stretch,shrink,stretch_order,shrink_order)
262 end
263 return n
264end
265
266local function someskip(skip,width,stretch,shrink,stretch_order,shrink_order)
267
268 local n = copy_nut(skip)
269 if width or stretch or shrink or stretch_order or shrink_order then
270 setglue(n,width,stretch,shrink,stretch_order,shrink_order)
271 end
272 return n
273end
274
275function nutpool.stretch(a,b)
276
277 local n = copy_nut(glue)
278 if not b then
279 a, b = 1, a or 1
280 end
281 setglue(n,0,a,0,b,0)
282 return n
283end
284
285function nutpool.shrink(a,b)
286 local n = copy_nut(glue)
287 if not b then
288 a, b = 1, a or 1
289 end
290 setglue(n,0,0,a,0,0,b)
291 return n
292end
293
294function nutpool.glue(width,stretch,shrink,stretch_order,shrink_order)
295 return someskip(glue,width,stretch,shrink,stretch_order,shrink_order)
296end
297
298function nutpool.negatedglue(glue)
299 local n = copy_nut(glue)
300 local width, stretch, shrink = getglue(n)
301 setglue(n,-width,-stretch,-shrink)
302 return n
303end
304
305function nutpool.leftskip(width,stretch,shrink,stretch_order,shrink_order)
306 return someskip(leftskip,width,stretch,shrink,stretch_order,shrink_order)
307end
308
309function nutpool.rightskip(width,stretch,shrink,stretch_order,shrink_order)
310 return someskip(rightskip,width,stretch,shrink,stretch_order,shrink_order)
311end
312
313function nutpool.lefthangskip(width,stretch,shrink,stretch_order,shrink_order)
314 return someskip(lefthangskip,width,stretch,shrink,stretch_order,shrink_order)
315end
316
317function nutpool.righthangskip(width,stretch,shrink,stretch_order,shrink_order)
318 return someskip(righthangskip,width,stretch,shrink,stretch_order,shrink_order)
319end
320
321function nutpool.indentskip(width,stretch,shrink,stretch_order,shrink_order)
322 return someskip(indentskip,width,stretch,shrink,stretch_order,shrink_order)
323end
324
325function nutpool.lineskip(width,stretch,shrink,stretch_order,shrink_order)
326 return someskip(lineskip,width,stretch,shrink,stretch_order,shrink_order)
327end
328
329function nutpool.baselineskip(width,stretch,shrink)
330 return someskip(baselineskip,width,stretch,shrink)
331end
332
333function nutpool.disc(pre,post,replace)
334 local d = copy_nut(disc)
335 if pre or post or replace then
336 setdisc(d,pre,post,replace)
337 end
338 return d
339end
340
341function nutpool.direction(dir,swap)
342 local t = copy_nut(textdir)
343 if not dir then
344
345 elseif swap then
346 setdirection(t,dir,true)
347 else
348 setdirection(t,dir,false)
349 end
350 return t
351end
352
353function nutpool.rule(width,height,depth)
354 local n = copy_nut(rule)
355 if width or height or depth then
356 setwhd(n,width,height,depth)
357 end
358 return n
359end
360
361function nutpool.emptyrule(width,height,depth)
362 local n = copy_nut(emptyrule)
363 if width or height or depth then
364 setwhd(n,width,height,depth)
365 end
366 return n
367end
368
369
370
371function nutpool.strutrule(width,height,depth)
372 local n = copy_nut(strutrule)
373 if width or height or depth then
374 setwhd(n,width,height,depth)
375 end
376 return n
377end
378
379function nutpool.userrule(width,height,depth)
380 local n = copy_nut(userrule)
381 if width or height or depth then
382 setwhd(n,width,height,depth)
383 end
384 return n
385end
386
387function nutpool.outlinerule(width,height,depth,line)
388 local n = copy_nut(outlinerule)
389 if width or height or depth then
390 setwhd(n,width,height,depth)
391 end
392 if line then
393 setdata(n,round(line))
394 end
395 return n
396end
397
398function nutpool.imagerule(width,height,depth)
399 local n = copy_nut(imagerule)
400 if width or height or depth then
401 setwhd(n,width,height,depth)
402 end
403 return n
404end
405
406function nutpool.boxrule(width,height,depth)
407 local n = copy_nut(boxrule)
408 if width or height or depth then
409 setwhd(n,width,height,depth)
410 end
411 return n
412end
413
414function nutpool.virtualrule(width,height,depth,data)
415 local n = copy_nut(virtualrule)
416 if width or height or depth or data then
417 setruledimensions(n,width,height,depth,data)
418 end
419 return n
420end
421
422local function new_leader(width,list)
423 local n = copy_nut(cleader)
424 if width then
425 setwidth(n,width)
426 end
427 if list then
428 setleader(n,list)
429 end
430 return n
431end
432
433nutpool.leader = new_leader
434
435function nodepool.leader(width,list)
436 return tonode(new_leader(width,list and tonut(list)))
437end
438
439function nutpool.leftmarginkern(glyph,width)
440 local n = copy_nut(left_margin_kern)
441 if not glyph then
442 report_nodes("invalid pointer to left margin glyph node")
443 elseif getid(glyph) ~= glyph_code then
444 report_nodes("invalid node type %a for %s margin glyph node",nodecodes[glyph],"left")
445 else
446 setfield(n,"glyph",glyph)
447 end
448 if width and width ~= 0 then
449 setwidth(n,width)
450 end
451 return n
452end
453
454function nutpool.rightmarginkern(glyph,width)
455 local n = copy_nut(right_margin_kern)
456 if not glyph then
457 report_nodes("invalid pointer to right margin glyph node")
458 elseif getid(glyph) ~= glyph_code then
459 report_nodes("invalid node type %a for %s margin glyph node",nodecodes[p],"right")
460 else
461 setfield(n,"glyph",glyph)
462 end
463 if width and width ~= 0 then
464 setwidth(n,width)
465 end
466 return n
467end
468
469function nutpool.temp()
470 return copy_nut(temp)
471end
472
473function nutpool.noad(class)
474 local n = copy_nut(noad)
475 if class then
476 setsubtype(n,class)
477 setclass(n,class,class,class)
478 end
479 return n
480end
481
482
483
484function nutpool.delimiter() return copy_nut(delimiter) end nutpool.delim = nutpool.delimiter
485function nutpool.fence() return copy_nut(fence) end
486function nutpool.submlist() return copy_nut(submlist) end
487function nutpool.fence() return copy_nut(fence) end
488function nutpool.accent() return copy_nut(accent) end
489function nutpool.radical() return copy_nut(radical) end
490function nutpool.fraction() return copy_nut(fraction) end
491function nutpool.subbox() return copy_nut(subbox) end
492function nutpool.mathchar() return copy_nut(mathchar) end
493function nutpool.mathtextchar() return copy_nut(mathtextchar) end
494function nutpool.choice() return copy_nut(choice) end
495
496local function new_hlist(list,width,height,depth,shift)
497 local n = copy_nut(hlist)
498 if list then
499 setlist(n,list)
500 end
501 if width or height or depth then
502 setwhd(n,width,height,depth)
503 end
504 if shift and shift ~= 0 then
505 setshift(n,shift)
506 end
507 return n
508end
509
510local function new_vlist(list,width,height,depth,shift)
511 local n = copy_nut(vlist)
512 if list then
513 setlist(n,list)
514 end
515 if width or height or depth then
516 setwhd(n,width,height,depth)
517 end
518 if shift and shift ~= 0 then
519 setshift(n,shift)
520 end
521 return n
522end
523
524nutpool.hlist = new_hlist
525nutpool.vlist = new_vlist
526
527function nodepool.hlist(list,width,height,depth,shift)
528 return tonode(new_hlist(list and tonut(list),width,height,depth,shift))
529end
530
531function nodepool.vlist(list,width,height,depth,shift)
532 return tonode(new_vlist(list and tonut(list),width,height,depth,shift))
533end
534
535function nutpool.usernode(id,data)
536 local n = copy_nut(user_node)
537 nodeproperties[n] = {
538 id = id,
539 data = data,
540 }
541 return n
542end
543
544
545
546local function cleanup(nofboxes)
547
548 local tracers = nodes.tracers
549 if tracers and tracers.steppers then
550 tracers.steppers.reset()
551 end
552 local nl = 0
553 local nr = nofreserved
554 for i=1,nofreserved do
555 local ri = reserved[i]
556 flush_nut(reserved[i])
557 end
558 if nofboxes then
559 for i=0,nofboxes do
560 local l = getbox(i)
561 if l then
562 flush_nut(l)
563 nl = nl + 1
564 end
565 end
566 end
567 reserved = { }
568 nofreserved = 0
569 return nr, nl, nofboxes
570end
571
572local usage = node.inuse
573local stock = node.instock
574
575nutpool .cleanup = cleanup
576nodepool.cleanup = cleanup
577
578nutpool .usage = usage
579nodepool.usage = usage
580
581nutpool .stock = stock
582nodepool.stock = stock
583
584
585
586statistics.register("cleaned up reserved nodes", function()
587 return format("%s nodes, %s lists of %s", cleanup(texgetcount("c_syst_last_allocated_box")))
588end)
589
590statistics.register("node memory usage", function()
591 local used = usage()
592 if next(used) then
593 local t, n = { }, 0
594 for k, v in table.sortedhash(used) do
595 n = n + 1 ; t[n] = format("%s %s",v,k)
596 end
597 return table.concat(t,", ")
598 end
599end)
600
601lua.registerinitexfinalizer(cleanup, "cleanup reserved nodes")
602
603do
604
605 local glyph = glyph
606 local traverseid = nuts.traverseid
607
608 local traversers = table.setmetatableindex(function(t,k)
609 local v = traverseid(type(k) == "number" and k or nodecodes[k],glyph)
610 t[k] = v
611 return v
612 end)
613
614 local treversers = table.setmetatableindex(function(t,k)
615 local v = traverseid(type(k) == "number" and k or nodecodes[k],glyph,true)
616 t[k] = v
617 return v
618 end)
619
620
621
622 traversers.node = nuts.traverse (glyph)
623 traversers.char = nuts.traversechar (glyph)
624 traversers.glyph = nuts.traverseglyph (glyph)
625 traversers.list = nuts.traverselist (glyph)
626 traversers.content = nuts.traversecontent(glyph)
627 traversers.leader = nuts.traverseleader (glyph)
628
629 treversers.node = nuts.traverse (glyph,true)
630 treversers.char = nuts.traversechar (glyph,true)
631 treversers.glyph = nuts.traverseglyph (glyph,true)
632 treversers.list = nuts.traverselist (glyph,true)
633 treversers.content = nuts.traversecontent(glyph,true)
634 treversers.leader = nuts.traverseleader (glyph,true)
635
636 nuts.traversers = traversers
637 nuts.treversers = treversers
638
639end
640 |