node-met.lua /size: 24 Kb    last modification: 2020-07-01 14:35
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
node-nut
'
]
=
{
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 9
-- This is an experimental module. Don't use nuts for generic code, at least not till
10
-- the regular code is proven stable. No support otherwise.
11 12
-- luatex: todo: copylist should return h, t
13
-- todo: see if using insert_before and insert_after makes sense here
14 15
-- This file is a side effect of the \LUATEX\ speed optimization project of Luigi
16
-- Scarso and me. As \CONTEXT\ spends over half its time in \LUA, we though that
17
-- using \LUAJIT\ could improve performance. We've published some of our experiences
18
-- elsewhere, but to summarize: \LUAJITTEX\ benefits a lot from the faster virtual
19
-- machine, but when jit is turned of we loose some again. We experimented with
20
-- ffi (without messing up the \CONTEXT\ code too much) but there we also lost more
21
-- than we gained (mostly due to lack of compatible userdata support: it's all or
22
-- nothing). This made us decide to look into the \LUA||\TEX\ interfacing and by
23
-- profiling and careful looking at the (of course then still beta source code) we
24
-- could come up with some improvements. The first showed up in 0.75 and we've more
25
-- on the agenda for 0.80. Although some interfaces could be sped up significantly
26
-- in practice we're only talking of 5||10\% on a \CONTEXT\ run and maybe more when
27
-- complex and extensive node list manipulations happens (we're talking of hundreds
28
-- of millions cross boundary calls then for documents of hundreds pages). One of the
29
-- changes in the \CONTEXT\ code base is that we went from indexed access to nodes to
30
-- function calls (in principle faster weren't it that the accessors need to do more
31
-- checking which makes them slower) and from there to optimizing these calls as well
32
-- as providing fast variants for well defined situations. At first optimizations were
33
-- put in a separate \type {node.fast} table although some improvements could be
34
-- ported to the main node functions. Because we got the feeling that more gain was
35
-- possible (especially when using more complex fonts and \MKIV\ functionality) we
36
-- eventually abandoned this approach and dropped the \type {fast} table in favour of
37
-- another hack. In the process we had done lots of profiling and testing so we knew
38
-- where time was wasted,
39
--
40
-- As lots of testing and experimenting was part of this project, I could not have
41
-- done without stacks of new \CD s and \DVD s. This time Porcupine Tree, No-Man
42
-- and Archive were came to rescue.
43
--
44
-- It all started with testing performance of:
45
--
46
-- node.getfield = metatable.__index
47
-- node.setfield = metatable.__newindex
48 49
local
type
,
select
=
type
,
select
50
local
setmetatableindex
=
table
.
setmetatableindex
51 52
-- First we get the metatable of a node:
53 54
local
metatable
=
nil
55 56
do
57
local
glyph
=
node
.
new
(
"
glyph
"
,
0
)
58
metatable
=
getmetatable
(
glyph
)
59
node
.
free
(
glyph
)
60
end
61 62
-- statistics.tracefunction(node, "node", "getfield","setfield")
63
-- statistics.tracefunction(node.direct,"node.direct","getfield","setfield")
64 65
-- We start with some helpers and provide all relevant basic functions in the
66
-- node namespace as well.
67 68
nodes
=
nodes
or
{
}
69
local
nodes
=
nodes
70 71
local
nodecodes
=
nodes
.
nodecodes
72 73
nodes
.
tostring
=
node
.
tostring
or
tostring
74
nodes
.
copy
=
node
.
copy
75
nodes
.
copy_node
=
node
.
copy
76
nodes
.
copy_list
=
node
.
copy_list
77
nodes
.
delete
=
node
.
delete
78
nodes
.
dimensions
=
node
.
dimensions
79
nodes
.
rangedimensions
=
node
.
rangedimensions
80
nodes
.
end_of_math
=
node
.
end_of_math
81
nodes
.
flush
=
node
.
flush_node
82
nodes
.
flush_node
=
node
.
flush_node
83
nodes
.
flush_list
=
node
.
flush_list
84
nodes
.
free
=
node
.
free
85
nodes
.
insert_after
=
node
.
insert_after
86
nodes
.
insert_before
=
node
.
insert_before
87
nodes
.
hpack
=
node
.
hpack
88
nodes
.
new
=
node
.
new
89
nodes
.
tail
=
node
.
tail
90
nodes
.
traverse
=
node
.
traverse
91
nodes
.
traverse_id
=
node
.
traverse_id
92
nodes
.
traverse_char
=
node
.
traverse_char
93
nodes
.
traverse_glyph
=
node
.
traverse_glyph
94
nodes
.
traverse_list
=
node
.
traverse_list
95
nodes
.
slide
=
node
.
slide
96
nodes
.
vpack
=
node
.
vpack
97
nodes
.
fields
=
node
.
fields
98
nodes
.
is_node
=
node
.
is_node
99
nodes
.
setglue
=
node
.
setglue
100
nodes
.
uses_font
=
node
.
uses_font
101 102
nodes
.
first_glyph
=
node
.
first_glyph
103
nodes
.
has_glyph
=
node
.
has_glyph
or
node
.
first_glyph
104 105
nodes
.
current_attr
=
node
.
current_attr
106
nodes
.
has_field
=
node
.
has_field
107
nodes
.
last_node
=
node
.
last_node
108
nodes
.
usedlist
=
node
.
usedlist
109
nodes
.
protrusion_skippable
=
node
.
protrusion_skippable
110
nodes
.
check_discretionaries
=
node
.
check_discretionaries
111
nodes
.
write
=
node
.
write
112
nodes
.
flatten_discretionaries
=
node
.
flatten_discretionaries
113 114
nodes
.
count
=
node
.
count
115
nodes
.
length
=
node
.
length
116 117
nodes
.
has_attribute
=
node
.
has_attribute
118
nodes
.
set_attribute
=
node
.
set_attribute
119
nodes
.
find_attribute
=
node
.
find_attribute
120
nodes
.
unset_attribute
=
node
.
unset_attribute
121 122
nodes
.
protect_glyph
=
node
.
protect_glyph
123
nodes
.
protect_glyphs
=
node
.
protect_glyphs
124
nodes
.
unprotect_glyph
=
node
.
unprotect_glyph
125
nodes
.
unprotect_glyphs
=
node
.
unprotect_glyphs
126
nodes
.
kerning
=
node
.
kerning
127
nodes
.
ligaturing
=
node
.
ligaturing
128
nodes
.
hyphenating
=
node
.
hyphenating
129
nodes
.
mlist_to_hlist
=
node
.
mlist_to_hlist
130 131
nodes
.
effective_glue
=
node
.
effective_glue
132
nodes
.
getglue
=
node
.
getglue
133
nodes
.
setglue
=
node
.
setglue
134
nodes
.
is_zero_glue
=
node
.
is_zero_glue
135 136
nodes
.
tonode
=
function
(
n
)
return
n
end
137
nodes
.
tonut
=
function
(
n
)
return
n
end
138 139
-- These are never used in \CONTEXT, only as a gimmick in node operators
140
-- so we keep them around.
141 142
local
n_getfield
=
node
.
getfield
143
local
n_getattr
=
node
.
get_attribute
144 145
local
n_setfield
=
node
.
setfield
146
local
n_setattr
=
n_setfield
147 148
nodes
.
getfield
=
n_getfield
149
nodes
.
setfield
=
n_setfield
150
nodes
.
getattr
=
n_getattr
151
nodes
.
setattr
=
n_setattr
152
nodes
.
takeattr
=
nodes
.
unset_attribute
153 154
local
function
n_getid
(
n
)
return
n_getfield
(
n
,
"
id
"
)
end
155
local
function
n_getsubtype
(
n
)
return
n_getfield
(
n
,
"
subtype
"
)
end
156 157
nodes
.
getid
=
n_getid
158
nodes
.
getsubtype
=
n_getsubtype
159 160
local
function
n_getchar
(
n
)
return
n_getfield
(
n
,
"
char
"
)
end
161
local
function
n_setchar
(
n
,
c
)
return
n_setfield
(
n
,
"
char
"
,
c
)
end
162
local
function
n_getfont
(
n
)
return
n_getfield
(
n
,
"
font
"
)
end
163
local
function
n_setfont
(
n
,
f
)
return
n_setfield
(
n
,
"
font
"
,
f
)
end
164 165
nodes
.
getchar
=
n_getchar
166
nodes
.
setchar
=
n_setchar
167
nodes
.
getfont
=
n_getfont
168
nodes
.
setfont
=
n_setfont
169 170
local
function
n_getlist
(
n
)
return
n_getfield
(
n
,
"
list
"
)
end
171
local
function
n_setlist
(
n
,
l
)
return
n_setfield
(
n
,
"
list
"
,
l
)
end
172
local
function
n_getleader
(
n
)
return
n_getfield
(
n
,
"
leader
"
)
end
173
local
function
n_setleader
(
n
,
l
)
return
n_setfield
(
n
,
"
leader
"
,
l
)
end
174 175
nodes
.
getlist
=
n_getlist
176
nodes
.
setlist
=
n_setlist
177
nodes
.
getleader
=
n_getleader
178
nodes
.
setleader
=
n_setleader
179 180
local
function
n_getnext
(
n
)
return
n_getfield
(
n
,
"
next
"
)
end
181
local
function
n_setnext
(
n
,
nn
)
return
n_setfield
(
n
,
"
next
"
,
nn
)
end
182
local
function
n_getprev
(
n
)
return
n_getfield
(
n
,
"
prev
"
)
end
183
local
function
n_setprev
(
n
,
pp
)
return
n_setfield
(
n
,
"
prev
"
,
pp
)
end
184
local
function
n_getboth
(
n
)
return
n_getfield
(
n
,
"
prev
"
)
,
n_getfield
(
n
,
"
next
"
)
end
185
local
function
n_setboth
(
n
,
pp
,
nn
)
return
n_setfield
(
n
,
"
prev
"
,
pp
)
,
n_setfield
(
n
,
"
next
"
,
nn
)
end
186 187
nodes
.
getnext
=
n_getnext
188
nodes
.
setnext
=
n_setnext
189
nodes
.
getprev
=
n_getprev
190
nodes
.
setprev
=
n_setprev
191
nodes
.
getboth
=
n_getboth
192
nodes
.
setboth
=
n_setboth
193 194
local
function
n_setlink
(
...
)
195
-- not that fast but not used often anyway
196
local
h
=
nil
197
for
i
=
1
,
select
(
"
#
"
,
...
)
do
198
local
n
=
select
(
i
,
...
)
199
if
not
n
then
200
-- go on
201
elseif
h
then
202
n_setfield
(
h
,
"
next
"
,
n
)
203
n_setfield
(
n
,
"
prev
"
,
h
)
204
else
205
h
=
n
206
end
207
end
208
return
h
209
end
210 211
nodes
.
setlink
=
n_setlink
212 213
nodes
.
getbox
=
node
.
getbox
or
tex
.
getbox
214
nodes
.
setbox
=
node
.
setbox
or
tex
.
setbox
215 216
local
n_flush_node
=
nodes
.
flush
217
local
n_copy_node
=
nodes
.
copy
218
local
n_copy_list
=
nodes
.
copy_list
219
local
n_find_tail
=
nodes
.
tail
220
local
n_insert_after
=
nodes
.
insert_after
221
local
n_insert_before
=
nodes
.
insert_before
222
local
n_slide
=
nodes
.
slide
223 224
local
n_remove_node
=
node
.
remove
-- not yet nodes.remove
225 226
local
function
remove
(
head
,
current
,
free_too
)
227
local
t
=
current
228
head
,
current
=
n_remove_node
(
head
,
current
)
229
if
not
t
then
230
-- forget about it
231
elseif
free_too
then
232
n_flush_node
(
t
)
233
t
=
nil
234
else
235
n_setboth
(
t
)
236
end
237
return
head
,
current
,
t
238
end
239 240
nodes
.
remove
=
remove
241 242
function
nodes
.
delete
(
head
,
current
)
243
return
remove
(
head
,
current
,
true
)
244
end
245 246
-- local h, c = nodes.replace(head,current,new)
247
-- local c = nodes.replace(false,current,new)
248
-- local c = nodes.replace(current,new)
249
--
250
-- todo: check for new.next and find tail
251 252
function
nodes
.
replace
(
head
,
current
,
new
)
-- no head returned if false
253
if
not
new
then
254
head
,
current
,
new
=
false
,
head
,
current
255
-- current, new = head, current
256
end
257
local
prev
=
n_getprev
(
current
)
258
local
next
=
n_getnext
(
current
)
259
if
next
then
260
n_setlink
(
new
,
next
)
261
end
262
if
prev
then
263
n_setlink
(
prev
,
new
)
264
end
265
if
head
then
266
if
head
=
=
current
then
267
head
=
new
268
end
269
n_flush_node
(
current
)
270
return
head
,
new
271
else
272
n_flush_node
(
current
)
273
return
new
274
end
275
end
276 277
-- nodes.countall : see node-nut.lua
278 279
function
nodes
.
append
(
head
,
current
,
...
)
280
for
i
=
1
,
select
(
"
#
"
,
...
)
do
281
head
,
current
=
n_insert_after
(
head
,
current
,
(
select
(
i
,
...
)
)
)
282
end
283
return
head
,
current
284
end
285 286
function
nodes
.
prepend
(
head
,
current
,
...
)
287
for
i
=
1
,
select
(
"
#
"
,
...
)
do
288
head
,
current
=
n_insert_before
(
head
,
current
,
(
select
(
i
,
...
)
)
)
289
end
290
return
head
,
current
291
end
292 293
function
nodes
.
linked
(
...
)
294
local
head
,
last
295
for
i
=
1
,
select
(
"
#
"
,
...
)
do
296
local
next
=
select
(
i
,
...
)
297
if
next
then
298
if
head
then
299
n_setlink
(
last
,
next
)
300
else
301
head
=
next
302
end
303
last
=
n_find_tail
(
next
)
-- we could skip the last one
304
end
305
end
306
return
head
307
end
308 309
function
nodes
.
concat
(
list
)
-- consider tail instead of slide
310
local
head
,
tail
311
for
i
=
1
,
#
list
do
312
local
li
=
list
[
i
]
313
if
li
then
314
if
head
then
315
n_setlink
(
tail
,
li
)
316
else
317
head
=
li
318
end
319
tail
=
n_slide
(
li
)
320
end
321
end
322
return
head
,
tail
323
end
324 325
function
nodes
.
reference
(
n
)
326
return
n
and
tonut
(
n
)
or
"
<none>
"
327
end
328 329
-- Here starts an experiment with metatables. Of course this only works with nodes
330
-- wrapped in userdata with a metatable.
331
--
332
-- Nodes are kind of special in the sense that you need to keep an eye on creation
333
-- and destruction. This is quite natural if you consider that changing the content
334
-- of a node would also change any copy (or alias). As there are too many pitfalls
335
-- we don't have this kind of support built in \LUATEX, which means that macro
336
-- packages are free to provide their own. One can even use local variants.
337
--
338
-- n1 .. n2 : append nodes, no copies
339
-- n1 * 5 : append 4 copies of nodes
340
-- 5 + n1 : strip first 5 nodes
341
-- n1 - 5 : strip last 5 nodes
342
-- n1 + n2 : inject n2 after first of n1
343
-- n1 - n2 : inject n2 before last of n1
344
-- n1^2 : two copies of nodes (keep orginal)
345
-- - n1 : reverse nodes
346
-- n1/f : apply function to nodes
347 348
-- local s = nodes.typesetters.tonodes
349
--
350
-- local function w(lst)
351
-- context.dontleavehmode()
352
-- context(lst)
353
-- context.par()
354
-- end
355
--
356
-- local n1 = s("a")
357
-- local n2 = s("b")
358
-- local n3 = s("c")
359
-- local n4 = s("d")
360
-- local n5 = s("e")
361
-- local n6 = s("f")
362
-- local n7 = s("g")
363
--
364
-- local n0 = n1 .. (n2 * 10).. n3 .. (5 * n4) .. n5 .. ( 5 * n6 ) .. n7 / function(n) n.char = string.byte("!") return n end
365
--
366
-- w(#n0)
367
--
368
-- w(n0)
369
--
370
-- local n1 = s("a") * 10
371
-- local n2 = s("b") * 10
372
--
373
-- local n0 = ((5 + n1) .. (n2 - 5) )
374
-- local n0 = - n0
375
--
376
-- local n0 = nil .. n0^3 .. nil
377
--
378
-- w(n0)
379
--
380
-- w ( s("a") + s("b") ) w ( s("a") + 4*s("b") ) w ( 4*s("a") + s("b") ) w ( 4*s("a") + 4*s("b") )
381
-- w ( s("a") - s("b") ) w ( s("a") - 4*s("b") ) w ( 4*s("a") - s("b") ) w ( 4*s("a") - 4*s("b") )
382 383
local
n_remove_node
=
nodes
.
remove
384 385
metatable
.
__concat
=
function
(
n1
,
n2
)
-- todo: accept nut on one end
386
if
not
n1
then
387
return
n2
388
elseif
not
n2
then
389
return
n1
390
elseif
n1
=
=
n2
then
391
-- or abort
392
return
n2
-- or n2 * 2
393
else
394
local
tail
=
n_find_tail
(
n1
)
395
n_setlink
(
tail
,
n2
)
396
return
n1
397
end
398
end
399 400
metatable
.
__mul
=
function
(
n
,
multiplier
)
401
if
type
(
multiplier
)
~
=
"
number
"
then
402
n
,
multiplier
=
multiplier
,
n
403
end
404
if
multiplier
<
=
1
then
405
return
n
406
elseif
n_getnext
(
n
)
then
407
local
head
408
for
i
=
2
,
multiplier
do
409
local
h
=
n_copy_list
(
n
)
410
if
head
then
411
local
t
=
n_find_tail
(
h
)
412
n_setlink
(
t
,
head
)
413
end
414
head
=
h
415
end
416
local
t
=
n_find_tail
(
n
)
417
n_setlink
(
t
,
head
)
418
else
419
local
head
420
for
i
=
2
,
multiplier
do
421
local
c
=
n_copy_node
(
n
)
422
if
head
then
423
n_setlink
(
c
,
head
)
424
end
425
head
=
c
426
end
427
n_setlink
(
n
,
head
)
428
end
429
return
n
430
end
431 432
metatable
.
__sub
=
function
(
first
,
second
)
433
if
type
(
second
)
=
=
"
number
"
then
434
local
tail
=
n_find_tail
(
first
)
435
for
i
=
1
,
second
do
436
local
prev
=
n_getprev
(
tail
)
437
n_flush_node
(
tail
)
-- can become flushlist/flushnode
438
if
prev
then
439
tail
=
prev
440
else
441
return
nil
442
end
443
end
444
if
tail
then
445
n_setnext
(
tail
)
446
return
first
447
else
448
return
nil
449
end
450
else
451
-- aaaaa - bbb => aaaabbba
452
local
firsttail
=
n_find_tail
(
first
)
453
local
prev
=
n_getprev
(
firsttail
)
454
if
prev
then
455
local
secondtail
=
n_find_tail
(
second
)
456
n_setlink
(
secondtail
,
firsttail
)
457
n_setlink
(
prev
,
second
)
458
return
first
459
else
460
local
secondtail
=
n_find_tail
(
second
)
461
n_setlink
(
secondtail
,
first
)
462
return
second
463
end
464
end
465
end
466 467
metatable
.
__add
=
function
(
first
,
second
)
468
if
type
(
first
)
=
=
"
number
"
then
469
local
head
=
second
470
for
i
=
1
,
first
do
471
local
second
=
n_getnext
(
head
)
472
n_flush_node
(
head
)
-- can become flushlist/flushnode
473
if
second
then
474
head
=
second
475
else
476
return
nil
477
end
478
end
479
if
head
then
480
n_setprev
(
head
)
481
return
head
482
else
483
return
nil
484
end
485
else
486
-- aaaaa + bbb => abbbaaaa
487
local
next
=
n_getnext
(
first
)
488
if
next
then
489
local
secondtail
=
n_find_tail
(
second
)
490
n_setlink
(
first
,
second
)
491
n_setlink
(
secondtail
,
next
)
492
else
493
n_setlink
(
first
,
second
)
494
end
495
return
first
496
end
497
end
498 499
metatable
.
__len
=
function
(
current
)
500
local
length
=
0
501
while
current
do
502
current
=
n_getnext
(
current
)
503
length
=
length
+
1
504
end
505
return
length
506
end
507 508
metatable
.
__div
=
function
(
list
,
action
)
509
return
action
(
list
)
or
list
-- always a value
510
end
511 512
metatable
.
__pow
=
function
(
n
,
multiplier
)
513
local
tail
=
n
514
local
head
=
nil
515
if
n_getnext
(
n
)
then
516
if
multiplier
=
=
1
then
517
head
=
n_copy_list
(
n
)
518
else
519
for
i
=
1
,
multiplier
do
520
local
h
=
n_copy_list
(
n
)
521
if
head
then
522
local
t
=
n_find_tail
(
h
)
523
n_setlink
(
t
,
head
)
524
end
525
head
=
h
526
end
527
end
528
else
529
if
multiplier
=
=
1
then
530
head
=
n_copy_node
(
n
)
531
else
532
for
i
=
2
,
multiplier
do
533
local
c
=
n_copy_node
(
n
)
534
if
head
then
535
n_setlink
(
head
,
c
)
536
end
537
head
=
c
538
end
539
end
540
end
541
-- todo: tracing
542
return
head
543
end
544 545
metatable
.
__unm
=
function
(
head
)
546
local
last
=
head
547
local
first
=
head
548
local
current
=
n_getnext
(
head
)
549
while
current
do
550
local
next
=
n_getnext
(
current
)
551
n_setlink
(
current
,
first
)
552
first
=
current
553
current
=
next
554
end
555
n_setprev
(
first
)
556
n_setnext
(
last
)
557
return
first
558
end
559 560
-- see node-nut.lua for more info on going nuts
561 562
-- if not gonuts then
563
--
564
-- local nuts = { }
565
-- nodes.nuts = nuts
566
--
567
-- local function dummy(f) return f end
568
--
569
-- nodes.vianuts = dummy
570
-- nodes.vianodes = dummy
571
--
572
-- for k, v in next, nodes do
573
-- if type(v) == "function" then
574
-- nuts[k] = v
575
-- end
576
-- end
577
--
578
-- end
579 580
-- also handy
581 582
local
tonode
=
nodes
.
tonode
583
local
whatsit_code
=
nodecodes
.
whatsit
584
local
getfields
=
node
.
fields
585
local
sort
=
table
.
sort
586
local
whatsitkeys
=
{
}
587
local
keys
=
{
whatsit
=
whatsitkeys
}
588
local
messyhack
=
table
.
tohash
{
-- temporary solution
589
nodecodes
.
attributelist
,
590
nodecodes
.
attribute
,
591
nodecodes
.
action
,
-- hm
592
}
593 594
setmetatableindex
(
keys
,
function
(
t
,
k
)
595
local
v
=
(
k
=
=
"
attributelist
"
or
k
=
=
nodecodes
.
attributelist
)
and
{
}
or
getfields
(
k
)
596
if
messyhack
[
k
]
then
597
for
i
=
1
,
#
v
do
598
if
v
[
i
]
=
=
"
subtype
"
then
599
remove
(
v
,
i
)
600
break
601
end
602
end
603
end
604
if
v
[
0
]
then
v
[
#
v
+
1
]
=
"
next
"
v
[
0
]
=
nil
end
605
if
v
[
-1
]
then
v
[
#
v
+
1
]
=
"
prev
"
v
[
-1
]
=
nil
end
606
sort
(
v
)
607
t
[
k
]
=
v
608
return
v
609
end
)
610 611
setmetatableindex
(
whatsitkeys
,
function
(
t
,
k
)
612
local
v
=
getfields
(
whatsit_code
,
k
)
613
if
v
[
0
]
then
v
[
#
v
+
1
]
=
"
next
"
v
[
0
]
=
nil
end
614
if
v
[
-1
]
then
v
[
#
v
+
1
]
=
"
prev
"
v
[
-1
]
=
nil
end
615
sort
(
v
)
616
t
[
k
]
=
v
617
return
v
618
end
)
619 620
local
function
nodefields
(
n
)
621
n
=
tonode
(
n
)
622
local
id
=
n
.
id
623
if
id
=
=
whatsit_code
then
624
return
whatsitkeys
[
n
.
subtype
]
625
else
626
return
keys
[
id
]
627
end
628
end
629 630
nodes
.
keys
=
keys
-- [id][subtype]
631
nodes
.
fields
=
nodefields
-- (n)
632 633
if
not
nodes
.
count
then
634 635
local
type
=
type
636 637
local
direct
=
node
.
direct
638
local
todirect
=
direct
.
tovaliddirect
639
local
tonode
=
direct
.
tonode
640 641
local
count
=
direct
.
count
642
local
length
=
direct
.
length
643
local
slide
=
direct
.
slide
644 645
function
node
.
count
(
id
,
first
,
last
)
646
return
count
(
id
,
first
and
todirect
(
first
)
,
last
and
todirect
(
last
)
or
nil
)
647
end
648 649
function
node
.
length
(
first
,
last
)
650
return
length
(
first
and
todirect
(
first
)
,
last
and
todirect
(
last
)
or
nil
)
651
end
652 653
function
node
.
slide
(
n
)
654
if
n
then
655
n
=
slide
(
todirect
(
n
)
)
656
if
n
then
657
return
tonode
(
n
)
658
end
659
end
660
return
nil
661
end
662 663
local
hyphenating
=
direct
.
hyphenating
664
local
ligaturing
=
direct
.
ligaturing
665
local
kerning
=
direct
.
kerning
666 667
-- kind of inconsistent
668 669
function
node
.
hyphenating
(
first
,
last
)
670
if
first
then
671
local
h
,
t
=
hyphenating
(
todirect
(
first
)
,
last
and
todirect
(
last
)
or
nil
)
672
return
h
and
tonode
(
h
)
or
nil
,
t
and
tonode
(
t
)
or
nil
,
true
673
else
674
return
nil
,
false
675
end
676
end
677 678
function
node
.
ligaturing
(
first
,
last
)
679
if
first
then
680
local
h
,
t
=
ligaturing
(
todirect
(
first
)
,
last
and
todirect
(
last
)
or
nil
)
681
return
h
and
tonode
(
h
)
or
nil
,
t
and
tonode
(
t
)
or
nil
,
true
682
else
683
return
nil
,
false
684
end
685
end
686 687
function
node
.
kerning
(
first
,
last
)
688
if
first
then
689
local
h
,
t
=
kerning
(
todirect
(
first
)
,
last
and
todirect
(
last
)
or
nil
)
690
return
h
and
tonode
(
h
)
or
nil
,
t
and
tonode
(
t
)
or
nil
,
true
691
else
692
return
nil
,
false
693
end
694
end
695 696
local
protect_glyph
=
direct
.
protect_glyph
697
local
unprotect_glyph
=
direct
.
unprotect_glyph
698
local
protect_glyphs
=
direct
.
protect_glyphs
699
local
unprotect_glyphs
=
direct
.
unprotect_glyphs
700 701
function
node
.
protect_glyphs
(
first
,
last
)
702
protect_glyphs
(
todirect
(
first
)
,
last
and
todirect
(
last
)
or
nil
)
703
end
704 705
function
node
.
unprotect_glyphs
(
first
,
last
)
706
unprotect_glyphs
(
todirect
(
first
)
,
last
and
todirect
(
last
)
or
nil
)
707
end
708 709
function
node
.
protect_glyph
(
first
)
710
protect_glyph
(
todirect
(
first
)
)
711
end
712 713
function
node
.
unprotect_glyph
(
first
)
714
unprotect_glyph
(
todirect
(
first
)
)
715
end
716 717
local
flatten_discretionaries
=
direct
.
flatten_discretionaries
718
local
check_discretionaries
=
direct
.
check_discretionaries
719
local
check_discretionary
=
direct
.
check_discretionary
720 721
function
node
.
flatten_discretionaries
(
first
)
722
local
h
,
count
=
flatten_discretionaries
(
todirect
(
first
)
)
723
return
tonode
(
h
)
,
count
724
end
725 726
function
node
.
check_discretionaries
(
n
)
727
check_discretionaries
(
todirect
(
n
)
)
728
end
729 730
function
node
.
check_discretionary
(
n
)
731
check_discretionary
(
todirect
(
n
)
)
732
end
733 734
local
hpack
=
direct
.
hpack
735
local
vpack
=
direct
.
vpack
736
local
list_to_hlist
=
direct
.
mlist_to_hlist
737 738
function
node
.
hpack
(
head
,
...
)
739
local
h
,
badness
=
hpack
(
head
and
todirect
(
head
)
or
nil
,
...
)
740
return
tonode
(
h
)
,
badness
741
end
742 743
function
node
.
vpack
(
head
,
...
)
744
local
h
,
badness
=
vpack
(
head
and
todirect
(
head
)
or
nil
,
...
)
745
return
tonode
(
h
)
,
badness
746
end
747 748
function
node
.
mlist_to_hlist
(
head
,
...
)
749
return
tonode
(
mlist_to_hlist
(
head
and
todirect
(
head
)
or
nil
,
...
)
)
750
end
751 752
local
end_of_math
=
direct
.
end_of_math
753
local
find_attribute
=
direct
.
find_attribute
754
local
first_glyph
=
direct
.
first_glyph
755 756
function
node
.
end_of_math
(
n
)
757
if
n
then
758
n
=
end_of_math
(
todirect
(
n
)
)
759
if
n
then
760
return
tonode
(
n
)
761
end
762
end
763
return
nil
764
end
765 766
function
node
.
find_attribute
(
n
,
a
)
767
if
n
then
768
local
v
,
n
=
find_attribute
(
todirect
(
n
)
,
a
)
769
if
n
then
770
return
v
,
tonode
(
n
)
771
end
772
end
773
return
nil
774
end
775 776
function
node
.
first_glyph
(
first
,
last
)
777
local
n
=
first_glyph
(
todirect
(
first
)
,
last
and
todirect
(
last
)
or
nil
)
778
return
n
and
tonode
(
n
)
or
nil
779
end
780 781
local
dimensions
=
direct
.
dimensions
782
local
rangedimensions
=
direct
.
rangedimensions
783
local
effective_glue
=
direct
.
effective_glue
784 785
function
node
.
dimensions
(
a
,
b
,
c
,
d
,
e
)
786
if
type
(
a
)
=
=
"
userdata
"
then
787
a
=
todirect
(
a
)
788
if
type
(
b
)
=
=
"
userdata
"
then
789
b
=
todirect
(
b
)
790
end
791
return
dimensions
(
a
,
b
)
792
else
793
d
=
todirect
(
d
)
794
if
type
(
e
)
=
=
"
userdata
"
then
795
e
=
todirect
(
e
)
796
end
797
return
dimensions
(
a
,
b
,
c
,
d
,
e
)
798
end
799
return
0
,
0
,
0
800
end
801 802
function
node
.
rangedimensions
(
parent
,
first
,
last
)
803
return
rangedimenensions
(
todirect
(
parent
)
,
todirect
(
first
)
,
last
and
todirect
(
last
)
)
804
end
805 806
function
node
.
effective_glue
(
list
,
parent
)
807
return
effective_glue
(
list
and
todirect
(
list
)
or
nil
,
parent
and
todirect
(
parent
)
or
nil
)
808
end
809 810
local
uses_font
=
direct
.
uses_font
811
local
has_glyph
=
direct
.
has_glyph
812
local
protrusion_skippable
=
direct
.
protrusion_skippable
813
local
prepend_prevdepth
=
direct
.
prepend_prevdepth
814
local
make_extensible
=
direct
.
make_extensible
815 816
function
node
.
uses_font
(
n
,
f
)
817
return
uses_font
(
todirect
(
n
)
,
f
)
818
end
819 820
function
node
.
has_glyph
(
n
)
821
return
has_glyph
(
todirect
(
n
)
)
822
end
823 824
function
node
.
protrusion_skippable
(
n
)
825
return
protrusion_skippable
(
todirect
(
n
)
)
826
end
827 828
function
node
.
prepend_prevdepth
(
n
)
829
local
n
,
d
=
prepend_prevdepth
(
todirect
(
n
)
)
830
return
tonode
(
n
)
,
d
831
end
832 833
function
node
.
make_extensible
(
...
)
834
local
n
=
make_extensible
(
...
)
835
return
n
and
tonode
(
n
)
or
nil
836
end
837 838
local
last_node
=
direct
.
last_node
839 840
function
node
.
last_node
(
)
841
local
n
=
last_node
(
)
842
return
n
and
tonode
(
n
)
or
nil
843
end
844 845
local
is_zero_glue
=
direct
.
is_zero_glue
846
local
getglue
=
direct
.
getglue
847
local
setglue
=
direct
.
setglue
848 849
function
node
.
is_zero_glue
(
n
)
850
return
is_zero_glue
(
todirect
(
n
)
)
851
end
852 853
function
node
.
get_glue
(
n
)
854
return
get_glue
(
todirect
(
n
)
)
855
end
856 857
function
node
.
set_glue
(
n
)
858
return
set_glue
(
todirect
(
n
)
)
859
end
860 861
end
862