spac-ver.lmt /size: 98 Kb    last modification: 2021-10-28 13:51
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
spac-ver
'
]
=
{
2
version
=
1
.
001
,
3
optimize
=
true
,
4
comment
=
"
companion to spac-ver.mkiv
"
,
5
author
=
"
Hans Hagen, PRAGMA-ADE, Hasselt NL
"
,
6
copyright
=
"
PRAGMA ADE / ConTeXt Development Team
"
,
7
license
=
"
see context related readme files
"
8
}
9 10
-- we also need to call the spacer for inserts!
11 12
-- somehow lists still don't always have proper prev nodes so i need to
13
-- check all of the luatex code some day .. maybe i should replece the
14
-- whole mvl handler by lua code .. why not
15 16
-- todo: use lua nodes with lua data (>0.79)
17
-- see ** can go when 0.79
18 19
-- needs to be redone, too many calls and tests now ... still within some
20
-- luatex limitations
21 22
-- this code dates from the beginning and is kind of experimental; it
23
-- will be optimized and improved soon .. it's way too complex now but
24
-- dates from less possibilities
25
--
26
-- the collapser will be redone with user nodes; also, we might get make
27
-- parskip into an attribute and appy it explicitly thereby getting rid
28
-- of automated injections; eventually i want to get rid of the currently
29
-- still needed tex -> lua -> tex > lua chain (needed because we can have
30
-- expandable settings at the tex end
31 32
-- todo: strip baselineskip around display math
33 34
local
next
,
type
,
tonumber
=
next
,
type
,
tonumber
35
local
gmatch
,
concat
=
string
.
gmatch
,
table
.
concat
36
local
ceil
,
floor
,
abs
=
math
.
ceil
,
math
.
floor
,
math
.
abs
37
local
lpegmatch
=
lpeg
.
match
38
local
unpack
=
unpack
or
table
.
unpack
39
local
allocate
=
utilities
.
storage
.
allocate
40
local
todimen
=
string
.
todimen
41
local
formatters
=
string
.
formatters
42 43
local
nodes
=
nodes
44
local
trackers
=
trackers
45
local
attributes
=
attributes
46
local
context
=
context
47
local
tex
=
tex
48 49
local
texlists
=
tex
.
lists
50
local
texget
=
tex
.
get
51
local
texgetcount
=
tex
.
getcount
52
local
texgetdimen
=
tex
.
getdimen
53
local
texgetglue
=
tex
.
getglue
54
local
texset
=
tex
.
set
55
local
texsetdimen
=
tex
.
setdimen
56
local
texsetcount
=
tex
.
setcount
57
local
texnest
=
tex
.
nest
58
local
texgetbox
=
tex
.
getbox
59 60
local
buildpage
=
tex
.
triggerbuildpage
61 62
local
variables
=
interfaces
.
variables
63
local
implement
=
interfaces
.
implement
64 65
local
v_local
=
variables
[
"
local
"
]
66
local
v_global
=
variables
[
"
global
"
]
67
local
v_box
=
variables
.
box
68
----- v_page = variables.page -- reserved for future use
69
local
v_split
=
variables
.
split
70
local
v_min
=
variables
.
min
71
local
v_max
=
variables
.
max
72
local
v_none
=
variables
.
none
73
local
v_line
=
variables
.
line
74
local
v_noheight
=
variables
.
noheight
75
local
v_nodepth
=
variables
.
nodepth
76
local
v_line
=
variables
.
line
77
local
v_halfline
=
variables
.
halfline
78
local
v_line_m
=
"
-
"
.
.
v_line
79
local
v_halfline_m
=
"
-
"
.
.
v_halfline
80
local
v_first
=
variables
.
first
81
local
v_last
=
variables
.
last
82
local
v_top
=
variables
.
top
83
local
v_bottom
=
variables
.
bottom
84
local
v_maxheight
=
variables
.
maxheight
85
local
v_minheight
=
variables
.
minheight
86
local
v_mindepth
=
variables
.
mindepth
87
local
v_maxdepth
=
variables
.
maxdepth
88
local
v_offset
=
variables
.
offset
89
local
v_strut
=
variables
.
strut
90 91
local
v_hfraction
=
variables
.
hfraction
92
local
v_dfraction
=
variables
.
dfraction
93
local
v_bfraction
=
variables
.
bfraction
94
local
v_tlines
=
variables
.
tlines
95
local
v_blines
=
variables
.
blines
96 97
-- vertical space handler
98 99
local
trace_vbox_vspacing
=
false
trackers
.
register
(
"
vspacing.vbox
"
,
function
(
v
)
trace_vbox_vspacing
=
v
end
)
100
local
trace_page_vspacing
=
false
trackers
.
register
(
"
vspacing.page
"
,
function
(
v
)
trace_page_vspacing
=
v
end
)
101
local
trace_page_builder
=
false
trackers
.
register
(
"
builders.page
"
,
function
(
v
)
trace_page_builder
=
v
end
)
102
local
trace_collect_vspacing
=
false
trackers
.
register
(
"
vspacing.collect
"
,
function
(
v
)
trace_collect_vspacing
=
v
end
)
103
local
trace_vspacing
=
false
trackers
.
register
(
"
vspacing.spacing
"
,
function
(
v
)
trace_vspacing
=
v
end
)
104
local
trace_vsnapping
=
false
trackers
.
register
(
"
vspacing.snapping
"
,
function
(
v
)
trace_vsnapping
=
v
end
)
105
local
trace_specials
=
false
trackers
.
register
(
"
vspacing.specials
"
,
function
(
v
)
trace_specials
=
v
end
)
106 107
local
remove_math_skips
=
true
directives
.
register
(
"
vspacing.removemathskips
"
,
function
(
v
)
remnove_math_skips
=
v
end
)
108 109
local
report_vspacing
=
logs
.
reporter
(
"
vspacing
"
,
"
spacing
"
)
110
local
report_collapser
=
logs
.
reporter
(
"
vspacing
"
,
"
collapsing
"
)
111
local
report_snapper
=
logs
.
reporter
(
"
vspacing
"
,
"
snapping
"
)
112
local
report_specials
=
logs
.
reporter
(
"
vspacing
"
,
"
specials
"
)
113 114
local
a_skipcategory
=
attributes
.
private
(
'
skipcategory
'
)
115
local
a_skippenalty
=
attributes
.
private
(
'
skippenalty
'
)
116
local
a_skiporder
=
attributes
.
private
(
'
skiporder
'
)
117
local
a_snapmethod
=
attributes
.
private
(
'
snapmethod
'
)
118
local
a_snapvbox
=
attributes
.
private
(
'
snapvbox
'
)
119 120
local
nuts
=
nodes
.
nuts
121
local
tonut
=
nuts
.
tonut
122 123
local
getnext
=
nuts
.
getnext
124
local
setlink
=
nuts
.
setlink
125
local
getprev
=
nuts
.
getprev
126
local
getid
=
nuts
.
getid
127
local
getlist
=
nuts
.
getlist
128
local
setlist
=
nuts
.
setlist
129
local
getattr
=
nuts
.
getattr
130
local
setattr
=
nuts
.
setattr
131
local
getsubtype
=
nuts
.
getsubtype
132
local
getbox
=
nuts
.
getbox
133
local
getwhd
=
nuts
.
getwhd
134
local
setwhd
=
nuts
.
setwhd
135
local
getprop
=
nuts
.
getprop
136
local
setprop
=
nuts
.
setprop
137
local
getglue
=
nuts
.
getglue
138
local
setglue
=
nuts
.
setglue
139
local
getkern
=
nuts
.
getkern
140
local
getpenalty
=
nuts
.
getpenalty
141
local
setshift
=
nuts
.
setshift
142
local
setwidth
=
nuts
.
setwidth
143
local
getwidth
=
nuts
.
getwidth
144
local
setheight
=
nuts
.
setheight
145
local
getheight
=
nuts
.
getheight
146
local
setdepth
=
nuts
.
setdepth
147
local
getdepth
=
nuts
.
getdepth
148
local
setnext
=
nuts
.
setnext
149 150
local
find_node_tail
=
nuts
.
tail
151
local
flushnode
=
nuts
.
flushnode
152
local
remove_node
=
nuts
.
remove
153
local
count_nodes
=
nuts
.
countall
154
local
hpack_node
=
nuts
.
hpack
155
local
vpack_node
=
nuts
.
vpack
156 157
local
startofpar
=
nuts
.
startofpar
158 159
local
write_node
=
nuts
.
write
160 161
local
nextnode
=
nuts
.
traversers
.
node
162
local
nexthlist
=
nuts
.
traversers
.
hlist
163 164
local
nodereference
=
nuts
.
reference
165 166
local
listtoutf
=
nodes
.
listtoutf
167
local
nodeidstostring
=
nodes
.
idstostring
168 169
local
nodepool
=
nuts
.
pool
170 171
local
new_penalty
=
nodepool
.
penalty
172
local
new_kern
=
nodepool
.
kern
173
local
new_glue
=
nodepool
.
glue
174
local
new_rule
=
nodepool
.
rule
175 176
local
nodecodes
=
nodes
.
nodecodes
177
local
gluecodes
=
nodes
.
gluecodes
178
----- penaltycodes = nodes.penaltycodes
179
----- listcodes = nodes.listcodes
180 181
local
penalty_code
=
nodecodes
.
penalty
182
local
kern_code
=
nodecodes
.
kern
183
local
glue_code
=
nodecodes
.
glue
184
local
hlist_code
=
nodecodes
.
hlist
185
local
vlist_code
=
nodecodes
.
vlist
186
local
rule_code
=
nodecodes
.
rule
187
local
par_code
=
nodecodes
.
par
188 189
local
userskip_code
=
gluecodes
.
userskip
190
local
lineskip_code
=
gluecodes
.
lineskip
191
local
baselineskip_code
=
gluecodes
.
baselineskip
192
local
parskip_code
=
gluecodes
.
parskip
193
local
topskip_code
=
gluecodes
.
topskip
194
local
splittopskip_code
=
gluecodes
.
splittopskip
195 196
local
linelist_code
=
nodes
.
listcodes
.
line
197 198
local
properties
=
nodes
.
properties
.
data
199 200
local
vspacing
=
builders
.
vspacing
or
{
}
201
builders
.
vspacing
=
vspacing
202 203
local
vspacingdata
=
vspacing
.
data
or
{
}
204
vspacing
.
data
=
vspacingdata
205 206
local
snapmethods
=
vspacingdata
.
snapmethods
or
{
}
207
vspacingdata
.
snapmethods
=
snapmethods
208 209
storage
.
register
(
"
builders/vspacing/data/snapmethods
"
,
snapmethods
,
"
builders.vspacing.data.snapmethods
"
)
210 211
do
212 213
local
default
=
{
214
[
v_maxheight
]
=
true
,
215
[
v_maxdepth
]
=
true
,
216
[
v_strut
]
=
true
,
217
[
v_hfraction
]
=
1
,
218
[
v_dfraction
]
=
1
,
219
[
v_bfraction
]
=
0
.
25
,
220
}
221 222
local
fractions
=
{
223
[
v_minheight
]
=
v_hfraction
,
[
v_maxheight
]
=
v_hfraction
,
224
[
v_mindepth
]
=
v_dfraction
,
[
v_maxdepth
]
=
v_dfraction
,
225
[
v_box
]
=
v_bfraction
,
226
[
v_top
]
=
v_tlines
,
[
v_bottom
]
=
v_blines
,
227
}
228 229
local
values
=
{
230
offset
=
"
offset
"
231
}
232 233
local
colonsplitter
=
lpeg
.
splitat
(
"
:
"
)
234 235
local
function
listtohash
(
str
)
236
local
t
=
{
}
237
for
s
in
gmatch
(
str
,
"
[^, ]+
"
)
do
238
local
key
,
detail
=
lpegmatch
(
colonsplitter
,
s
)
239
local
v
=
variables
[
key
]
240
if
v
then
241
t
[
v
]
=
true
242
if
detail
then
243
local
k
=
fractions
[
key
]
244
if
k
then
245
detail
=
tonumber
(
"
0
"
.
.
detail
)
246
if
detail
then
247
t
[
k
]
=
detail
248
end
249
else
250
k
=
values
[
key
]
251
if
k
then
252
detail
=
todimen
(
detail
)
253
if
detail
then
254
t
[
k
]
=
detail
255
end
256
end
257
end
258
end
259
else
260
detail
=
tonumber
(
"
0
"
.
.
key
)
261
if
detail
then
262
t
[
v_hfraction
]
=
detail
263
t
[
v_dfraction
]
=
detail
264
end
265
end
266
end
267
if
next
(
t
)
then
268
t
[
v_hfraction
]
=
t
[
v_hfraction
]
or
1
269
t
[
v_dfraction
]
=
t
[
v_dfraction
]
or
1
270
return
t
271
else
272
return
default
273
end
274
end
275 276
function
vspacing
.
definesnapmethod
(
name
,
method
)
277
local
n
=
#
snapmethods
+
1
278
local
t
=
listtohash
(
method
)
279
snapmethods
[
n
]
=
t
280
t
.
name
=
name
-- not interfaced
281
t
.
specification
=
method
-- not interfaced
282
context
(
n
)
283
end
284 285
end
286 287
local
function
validvbox
(
parentid
,
list
)
288
if
parentid
=
=
hlist_code
then
289
local
id
=
getid
(
list
)
290
if
id
=
=
par_code
and
startofpar
(
list
)
then
291
list
=
getnext
(
list
)
292
if
not
next
then
293
return
nil
294
end
295
end
296
local
done
=
nil
297
for
n
,
id
in
nextnode
,
list
do
298
if
id
=
=
vlist_code
or
id
=
=
hlist_code
then
299
if
done
then
300
return
nil
301
else
302
done
=
n
303
end
304
elseif
id
=
=
glue_code
or
id
=
=
penalty_code
then
305
-- go on
306
else
307
return
nil
-- whatever
308
end
309
end
310
if
done
then
311
local
id
=
getid
(
done
)
312
if
id
=
=
hlist_code
then
313
return
validvbox
(
id
,
getlist
(
done
)
)
314
end
315
end
316
return
done
-- only one vbox
317
end
318
end
319 320
local
function
already_done
(
parentid
,
list
,
a_snapmethod
)
-- todo: done when only boxes and all snapped
321
-- problem: any snapped vbox ends up in a line
322
if
list
and
parentid
=
=
hlist_code
then
323
local
id
=
getid
(
list
)
324
if
id
=
=
par_code
and
startofpar
(
list
)
then
325
list
=
getnext
(
list
)
326
if
not
list
then
327
return
false
328
end
329
end
330
for
n
,
id
in
nextnode
,
list
do
331
if
id
=
=
hlist_code
or
id
=
=
vlist_code
then
332
-- local a = getattr(n,a_snapmethod)
333
-- if not a then
334
-- -- return true -- not snapped at all
335
-- elseif a == 0 then
336
-- return true -- already snapped
337
-- end
338
local
p
=
getprop
(
n
,
"
snapper
"
)
339
if
p
then
340
return
p
341
end
342
elseif
id
=
=
glue_code
or
id
=
=
penalty_code
then
-- or id == kern_code then
343
-- go on
344
else
345
return
false
-- whatever
346
end
347
end
348
end
349
return
false
350
end
351 352
-- check variables.none etc
353 354
local
snap_hlist
do
355 356
local
function
fixedprofile
(
current
)
357
local
profiling
=
builders
.
profiling
358
return
profiling
and
profiling
.
fixedprofile
(
current
)
359
end
360 361
-- quite tricky: ceil(-something) => -0
362 363
local
function
ceiled
(
n
)
364
if
n
<
0
or
n
<
0
.
01
then
365
return
0
366
else
367
return
ceil
(
n
)
368
end
369
end
370 371
local
function
floored
(
n
)
372
if
n
<
0
or
n
<
0
.
01
then
373
return
0
374
else
375
return
floor
(
n
)
376
end
377
end
378 379
snap_hlist
=
function
(
where
,
current
,
method
,
height
,
depth
)
-- method[v_strut] is default
380
if
fixedprofile
(
current
)
then
381
return
382
end
383
local
list
=
getlist
(
current
)
384
local
t
=
trace_vsnapping
and
{
}
385
if
t
then
386
t
[
#
t
+
1
]
=
formatters
[
"
list content: %s
"
]
(
listtoutf
(
list
)
)
387
t
[
#
t
+
1
]
=
formatters
[
"
snap method: %s
"
]
(
method
.
name
)
-- not interfaced
388
t
[
#
t
+
1
]
=
formatters
[
"
specification: %s
"
]
(
method
.
specification
)
-- not interfaced
389
end
390
local
snapht
,
snapdp
391
if
method
[
v_local
]
then
392
-- snapping is done immediately here
393
snapht
=
texgetdimen
(
"
bodyfontstrutheight
"
)
394
snapdp
=
texgetdimen
(
"
bodyfontstrutdepth
"
)
395
if
t
then
396
t
[
#
t
+
1
]
=
formatters
[
"
local: snapht %p snapdp %p
"
]
(
snapht
,
snapdp
)
397
end
398
elseif
method
[
v_global
]
then
399
snapht
=
texgetdimen
(
"
globalbodyfontstrutheight
"
)
400
snapdp
=
texgetdimen
(
"
globalbodyfontstrutdepth
"
)
401
if
t
then
402
t
[
#
t
+
1
]
=
formatters
[
"
global: snapht %p snapdp %p
"
]
(
snapht
,
snapdp
)
403
end
404
else
405
-- maybe autolocal
406
-- snapping might happen later in the otr
407
snapht
=
texgetdimen
(
"
globalbodyfontstrutheight
"
)
408
snapdp
=
texgetdimen
(
"
globalbodyfontstrutdepth
"
)
409
local
lsnapht
=
texgetdimen
(
"
bodyfontstrutheight
"
)
410
local
lsnapdp
=
texgetdimen
(
"
bodyfontstrutdepth
"
)
411
if
snapht
~
=
lsnapht
and
snapdp
~
=
lsnapdp
then
412
snapht
,
snapdp
=
lsnapht
,
lsnapdp
413
end
414
if
t
then
415
t
[
#
t
+
1
]
=
formatters
[
"
auto: snapht %p snapdp %p
"
]
(
snapht
,
snapdp
)
416
end
417
end
418 419
local
wd
,
ht
,
dp
=
getwhd
(
current
)
420 421
local
h
=
(
method
[
v_noheight
]
and
0
)
or
height
or
ht
422
local
d
=
(
method
[
v_nodepth
]
and
0
)
or
depth
or
dp
423
local
hr
=
method
[
v_hfraction
]
or
1
424
local
dr
=
method
[
v_dfraction
]
or
1
425
local
br
=
method
[
v_bfraction
]
or
0
426
local
ch
=
h
427
local
cd
=
d
428
local
tlines
=
method
[
v_tlines
]
or
1
429
local
blines
=
method
[
v_blines
]
or
1
430
local
done
=
false
431
local
plusht
=
snapht
432
local
plusdp
=
snapdp
433
local
snaphtdp
=
snapht
+
snapdp
434
local
extra
=
0
435 436
if
t
then
437
t
[
#
t
+
1
]
=
formatters
[
"
hlist: wd %p ht %p (used %p) dp %p (used %p)
"
]
(
wd
,
ht
,
h
,
dp
,
d
)
438
t
[
#
t
+
1
]
=
formatters
[
"
fractions: hfraction %s dfraction %s bfraction %s tlines %s blines %s
"
]
(
hr
,
dr
,
br
,
tlines
,
blines
)
439
end
440 441
if
method
[
v_box
]
then
442
local
br
=
1
-
br
443
if
br
<
0
then
444
br
=
0
445
elseif
br
>
1
then
446
br
=
1
447
end
448
local
n
=
ceiled
(
(
h
+
d
-
br
*
snapht
-
br
*
snapdp
)
/
snaphtdp
)
449
local
x
=
n
*
snaphtdp
-
h
-
d
450
plusht
=
h
+
x
/
2
451
plusdp
=
d
+
x
/
2
452
if
t
then
453
t
[
#
t
+
1
]
=
formatters
[
"
%s: plusht %p plusdp %p
"
]
(
v_box
,
plusht
,
plusdp
)
454
end
455
elseif
method
[
v_max
]
then
456
local
n
=
ceiled
(
(
h
+
d
)
/
snaphtdp
)
457
local
x
=
n
*
snaphtdp
-
h
-
d
458
plusht
=
h
+
x
/
2
459
plusdp
=
d
+
x
/
2
460
if
t
then
461
t
[
#
t
+
1
]
=
formatters
[
"
%s: plusht %p plusdp %p
"
]
(
v_max
,
plusht
,
plusdp
)
462
end
463
elseif
method
[
v_min
]
then
464
-- we catch a lone min
465
if
method
.
specification
~
=
v_min
then
466
local
n
=
floored
(
(
h
+
d
)
/
snaphtdp
)
467
local
x
=
n
*
snaphtdp
-
h
-
d
468
plusht
=
h
+
x
/
2
469
plusdp
=
d
+
x
/
2
470
if
plusht
<
0
then
471
plusht
=
0
472
end
473
if
plusdp
<
0
then
474
plusdp
=
0
475
end
476
end
477
if
t
then
478
t
[
#
t
+
1
]
=
formatters
[
"
%s: plusht %p plusdp %p
"
]
(
v_min
,
plusht
,
plusdp
)
479
end
480
elseif
method
[
v_none
]
then
481
plusht
,
plusdp
=
0
,
0
482
if
t
then
483
t
[
#
t
+
1
]
=
formatters
[
"
%s: plusht %p plusdp %p
"
]
(
v_none
,
0
,
0
)
484
end
485
end
486
-- for now, we actually need to tag a box and then check at several points if something ended up
487
-- at the top of a page
488
if
method
[
v_halfline
]
then
-- extra halfline
489
extra
=
snaphtdp
/
2
490
plusht
=
plusht
+
extra
491
plusdp
=
plusdp
+
extra
492
if
t
then
493
t
[
#
t
+
1
]
=
formatters
[
"
%s: plusht %p plusdp %p
"
]
(
v_halfline
,
plusht
,
plusdp
)
494
end
495
end
496
if
method
[
v_line
]
then
-- extra line
497
extra
=
snaphtdp
498
plusht
=
plusht
+
extra
499
plusdp
=
plusdp
+
extra
500
if
t
then
501
t
[
#
t
+
1
]
=
formatters
[
"
%s: plusht %p plusdp %p
"
]
(
v_line
,
plusht
,
plusdp
)
502
end
503
end
504
if
method
[
v_halfline_m
]
then
-- extra halfline
505
extra
=
-
snaphtdp
/
2
506
plusht
=
plusht
+
extra
507
plusdp
=
plusdp
+
extra
508
if
t
then
509
t
[
#
t
+
1
]
=
formatters
[
"
%s: plusht %p plusdp %p
"
]
(
v_halfline_m
,
plusht
,
plusdp
)
510
end
511
end
512
if
method
[
v_line_m
]
then
-- extra line
513
extra
=
-
snaphtdp
514
plusht
=
plusht
+
extra
515
plusdp
=
plusdp
+
extra
516
if
t
then
517
t
[
#
t
+
1
]
=
formatters
[
"
%s: plusht %p plusdp %p
"
]
(
v_line_m
,
plusht
,
plusdp
)
518
end
519
end
520
if
method
[
v_first
]
then
521
local
thebox
=
current
522
local
id
=
getid
(
thebox
)
523
if
id
=
=
hlist_code
then
524
thebox
=
validvbox
(
id
,
getlist
(
thebox
)
)
525
id
=
thebox
and
getid
(
thebox
)
526
end
527
if
thebox
and
id
=
=
vlist_code
then
528
local
list
=
getlist
(
thebox
)
529
local
lw
,
lh
,
ld
530
for
n
in
nexthlist
,
list
do
531
lw
,
lh
,
ld
=
getwhd
(
n
)
532
break
533
end
534
if
lh
then
535
local
wd
,
ht
,
dp
=
getwhd
(
thebox
)
536
if
t
then
537
t
[
#
t
+
1
]
=
formatters
[
"
first line: height %p depth %p
"
]
(
lh
,
ld
)
538
t
[
#
t
+
1
]
=
formatters
[
"
dimensions: height %p depth %p
"
]
(
ht
,
dp
)
539
end
540
local
delta
=
h
-
lh
541
ch
,
cd
=
lh
,
delta
+
d
542
h
,
d
=
ch
,
cd
543
local
shifted
=
hpack_node
(
getlist
(
current
)
)
544
setshift
(
shifted
,
delta
)
545
setlist
(
current
,
shifted
)
546
done
=
true
547
if
t
then
548
t
[
#
t
+
1
]
=
formatters
[
"
first: height %p depth %p shift %p
"
]
(
ch
,
cd
,
delta
)
549
end
550
elseif
t
then
551
t
[
#
t
+
1
]
=
"
first: not done, no content
"
552
end
553
elseif
t
then
554
t
[
#
t
+
1
]
=
"
first: not done, no vbox
"
555
end
556
elseif
method
[
v_last
]
then
557
local
thebox
=
current
558
local
id
=
getid
(
thebox
)
559
if
id
=
=
hlist_code
then
560
thebox
=
validvbox
(
id
,
getlist
(
thebox
)
)
561
id
=
thebox
and
getid
(
thebox
)
562
end
563
if
thebox
and
id
=
=
vlist_code
then
564
local
list
=
getlist
(
thebox
)
565
local
lw
,
lh
,
ld
566
for
n
in
nexthlist
,
list
do
567
lw
,
lh
,
ld
=
getwhd
(
n
)
568
end
569
if
lh
then
570
local
wd
,
ht
,
dp
=
getwhd
(
thebox
)
571
if
t
then
572
t
[
#
t
+
1
]
=
formatters
[
"
last line: height %p depth %p
"
]
(
lh
,
ld
)
573
t
[
#
t
+
1
]
=
formatters
[
"
dimensions: height %p depth %p
"
]
(
ht
,
dp
)
574
end
575
local
delta
=
d
-
ld
576
cd
,
ch
=
ld
,
delta
+
h
577
h
,
d
=
ch
,
cd
578
local
shifted
=
hpack_node
(
getlist
(
current
)
)
579
setshift
(
shifted
,
delta
)
580
setlist
(
current
,
shifted
)
581
done
=
true
582
if
t
then
583
t
[
#
t
+
1
]
=
formatters
[
"
last: height %p depth %p shift %p
"
]
(
ch
,
cd
,
delta
)
584
end
585
elseif
t
then
586
t
[
#
t
+
1
]
=
"
last: not done, no content
"
587
end
588
elseif
t
then
589
t
[
#
t
+
1
]
=
"
last: not done, no vbox
"
590
end
591
end
592
if
method
[
v_minheight
]
then
593
ch
=
floored
(
(
h
-
hr
*
snapht
)
/
snaphtdp
)
*
snaphtdp
+
plusht
594
if
t
then
595
t
[
#
t
+
1
]
=
formatters
[
"
minheight: %p
"
]
(
ch
)
596
end
597
elseif
method
[
v_maxheight
]
then
598
ch
=
ceiled
(
(
h
-
hr
*
snapht
)
/
snaphtdp
)
*
snaphtdp
+
plusht
599
if
t
then
600
t
[
#
t
+
1
]
=
formatters
[
"
maxheight: %p
"
]
(
ch
)
601
end
602
else
603
ch
=
plusht
604
if
t
then
605
t
[
#
t
+
1
]
=
formatters
[
"
set height: %p
"
]
(
ch
)
606
end
607
end
608
if
method
[
v_mindepth
]
then
609
cd
=
floored
(
(
d
-
dr
*
snapdp
)
/
snaphtdp
)
*
snaphtdp
+
plusdp
610
if
t
then
611
t
[
#
t
+
1
]
=
formatters
[
"
mindepth: %p
"
]
(
cd
)
612
end
613
elseif
method
[
v_maxdepth
]
then
614
cd
=
ceiled
(
(
d
-
dr
*
snapdp
)
/
snaphtdp
)
*
snaphtdp
+
plusdp
615
if
t
then
616
t
[
#
t
+
1
]
=
formatters
[
"
maxdepth: %p
"
]
(
cd
)
617
end
618
else
619
cd
=
plusdp
620
if
t
then
621
t
[
#
t
+
1
]
=
formatters
[
"
set depth: %p
"
]
(
cd
)
622
end
623
end
624
if
method
[
v_top
]
then
625
ch
=
ch
+
tlines
*
snaphtdp
626
if
t
then
627
t
[
#
t
+
1
]
=
formatters
[
"
top height: %p
"
]
(
ch
)
628
end
629
end
630
if
method
[
v_bottom
]
then
631
cd
=
cd
+
blines
*
snaphtdp
632
if
t
then
633
t
[
#
t
+
1
]
=
formatters
[
"
bottom depth: %p
"
]
(
cd
)
634
end
635
end
636
local
offset
=
method
[
v_offset
]
637
if
offset
then
638
-- we need to set the attr
639
if
t
then
640
local
wd
,
ht
,
dp
=
getwhd
(
current
)
641
t
[
#
t
+
1
]
=
formatters
[
"
before offset: %p (width %p height %p depth %p)
"
]
(
offset
,
wd
,
ht
,
dp
)
642
end
643
local
shifted
=
hpack_node
(
getlist
(
current
)
)
644
setshift
(
shifted
,
offset
)
645
setlist
(
current
,
shifted
)
646
if
t
then
647
local
wd
,
ht
,
dp
=
getwhd
(
current
)
648
t
[
#
t
+
1
]
=
formatters
[
"
after offset: %p (width %p height %p depth %p)
"
]
(
offset
,
wd
,
ht
,
dp
)
649
end
650
setattr
(
shifted
,
a_snapmethod
,
0
)
651
setattr
(
current
,
a_snapmethod
,
0
)
652
end
653
if
not
height
then
654
setheight
(
current
,
ch
)
655
if
t
then
656
t
[
#
t
+
1
]
=
formatters
[
"
forced height: %p
"
]
(
ch
)
657
end
658
end
659
if
not
depth
then
660
setdepth
(
current
,
cd
)
661
if
t
then
662
t
[
#
t
+
1
]
=
formatters
[
"
forced depth: %p
"
]
(
cd
)
663
end
664
end
665
local
lines
=
(
ch
+
cd
)
/
snaphtdp
666
if
t
then
667
local
original
=
(
h
+
d
)
/
snaphtdp
668
local
whatever
=
(
ch
+
cd
)
/
(
texgetdimen
(
"
globalbodyfontstrutheight
"
)
+
texgetdimen
(
"
globalbodyfontstrutdepth
"
)
)
669
t
[
#
t
+
1
]
=
formatters
[
"
final lines : %p -> %p (%p)
"
]
(
original
,
lines
,
whatever
)
670
t
[
#
t
+
1
]
=
formatters
[
"
final height: %p -> %p
"
]
(
h
,
ch
)
671
t
[
#
t
+
1
]
=
formatters
[
"
final depth : %p -> %p
"
]
(
d
,
cd
)
672
end
673
-- todo:
674
--
675
-- if h < 0 or d < 0 then
676
-- h = 0
677
-- d = 0
678
-- end
679
if
t
then
680
report_snapper
(
"
trace: %s type %s\n\t%\n\tt
"
,
where
,
nodecodes
[
getid
(
current
)
]
,
t
)
681
end
682
if
not
method
[
v_split
]
then
683
-- so extra will not be compensated at the top of a page
684
extra
=
0
685
end
686
return
h
,
d
,
ch
,
cd
,
lines
,
extra
687
end
688 689
end
690 691
local
categories
=
{
[
0
]
=
692
"
discard
"
,
693
"
largest
"
,
694
"
force
"
,
695
"
penalty
"
,
696
"
add
"
,
697
"
disable
"
,
698
"
nowhite
"
,
699
"
goback
"
,
700
"
packed
"
,
701
"
overlay
"
,
702
"
enable
"
,
703
"
notopskip
"
,
704
}
705 706
categories
=
allocate
(
table
.
swapped
(
categories
,
categories
)
)
707
vspacing
.
categories
=
categories
708 709
function
vspacing
.
tocategories
(
str
)
710
local
t
=
{
}
711
for
s
in
gmatch
(
str
,
"
[^, ]
"
)
do
-- use lpeg instead
712
local
n
=
tonumber
(
s
)
713
if
n
then
714
t
[
categories
[
n
]
]
=
true
715
else
716
t
[
b
]
=
true
717
end
718
end
719
return
t
720
end
721 722
function
vspacing
.
tocategory
(
str
)
-- can be optimized
723
if
type
(
str
)
=
=
"
string
"
then
724
return
set
.
tonumber
(
vspacing
.
tocategories
(
str
)
)
725
else
726
return
set
.
tonumber
(
{
[
categories
[
str
]
]
=
true
}
)
727
end
728
end
729 730
vspacingdata
.
map
=
vspacingdata
.
map
or
{
}
-- allocate ?
731
vspacingdata
.
skip
=
vspacingdata
.
skip
or
{
}
-- allocate ?
732 733
storage
.
register
(
"
builders/vspacing/data/map
"
,
vspacingdata
.
map
,
"
builders.vspacing.data.map
"
)
734
storage
.
register
(
"
builders/vspacing/data/skip
"
,
vspacingdata
.
skip
,
"
builders.vspacing.data.skip
"
)
735 736
local
setspecification
,
getspecification
737 738
-- attributes : more overhead : feels faster than properties
739
-- properties : more natural : feels slower than attributes
740
-- data : more native : is little faster than attributes
741 742
if
true
then
743
-- if false then
744 745
-- quite okay but more memory due to attributes (not many)
746 747
local
setattrs
=
nuts
.
setattrs
748
local
getattrs
=
nuts
.
getattrs
749 750
setspecification
=
function
(
n
,
category
,
penalty
,
order
)
751
setattrs
(
n
,
false
,
a_skipcategory
,
category
,
a_skippenalty
,
penalty
,
a_skiporder
,
order
or
1
)
752
end
753 754
getspecification
=
function
(
n
)
755
return
getattrs
(
n
,
a_skipcategory
,
a_skippenalty
,
a_skiporder
)
756
end
757 758
-- elseif true then
759
elseif
false
then
760 761
-- more natural as we stay in lua
762 763
setspecification
=
function
(
n
,
category
,
penalty
,
order
)
764
-- we know that there are no properties
765
properties
[
n
]
=
{
766
[
a_skipcategory
]
=
category
,
767
[
a_skippenalty
]
=
penalty
,
768
[
a_skiporder
]
=
order
or
1
,
769
}
770
end
771 772
getspecification
=
function
(
n
)
773
local
p
=
properties
[
n
]
774
if
p
then
775
return
p
[
a_skipcategory
]
,
p
[
a_skippenalty
]
,
p
[
a_skiporder
]
776
end
777
end
778 779
else
780 781
-- quite efficient but needs testing because we limit values
782 783
local
getdata
=
nuts
.
getdata
784
local
setdata
=
nuts
.
setdata
785 786
setspecification
=
function
(
n
,
category
,
penalty
,
order
)
787
if
not
category
or
category
>
0xF
then
788
category
=
0xF
789
end
790
if
not
order
or
order
>
0xFF
then
791
order
=
0xFF
792
end
793
if
not
penalty
or
penalty
>
0x7FFFF
then
794
penalty
=
0x7FFFF
795
elseif
penalty
<
-0x7FFFF
then
796
penalty
=
-0x7FFFF
797
end
798
-- we need overflow checks
799
setdata
(
n
,
(
penalty
<
<
12
)
+
(
order
<
<
4
)
+
category
)
800
end
801 802
getspecification
=
function
(
n
)
803
local
data
=
getdata
(
n
)
804
if
data
and
data
~
=
0
then
805
local
category
=
data
&
0x0F
806
local
order
=
(
data
>
>
4
)
&
0xFF
807
local
penalty
=
data
>
>
12
808
if
category
=
=
0xF
then
809
category
=
nil
810
end
811
if
order
=
=
0xFF
then
812
order
=
nil
813
end
814
if
penalty
=
=
0x7FFFF
then
815
penalty
=
nil
816
end
817
return
category
,
penalty
,
order
818
else
819
return
nil
,
nil
,
nil
820
end
821
end
822 823
end
824 825
do
826 827
local
P
,
C
,
R
,
S
,
Cc
,
Cs
=
lpeg
.
P
,
lpeg
.
C
,
lpeg
.
R
,
lpeg
.
S
,
lpeg
.
Cc
,
lpeg
.
Cs
828 829
vspacing
.
fixed
=
false
830 831
local
map
=
vspacingdata
.
map
832
local
skip
=
vspacingdata
.
skip
833 834
local
sign
=
S
(
"
+-
"
)
^
0
835
local
multiplier
=
C
(
sign
*
R
(
"
09
"
)
^
1
)
*
P
(
"
*
"
)
836
local
singlefier
=
Cs
(
sign
*
Cc
(
1
)
)
837
local
separator
=
S
(
"
,
"
)
838
local
category
=
P
(
"
:
"
)
*
C
(
(
1
-
separator
)
^
1
)
839
local
keyword
=
C
(
(
1
-
category
-
separator
)
^
1
)
840
local
splitter
=
(
multiplier
+
Cc
(
1
)
)
*
keyword
*
(
category
+
Cc
(
false
)
)
841 842
local
k_fixed
=
variables
.
fixed
843
local
k_flexible
=
variables
.
flexible
844 845
local
k_category
<const>
=
"
category
"
846
local
k_penalty
<const>
=
"
penalty
"
847
local
k_order
<const>
=
"
order
"
848 849
function
vspacing
.
setmap
(
from
,
to
)
850
map
[
from
]
=
to
851
end
852 853
function
vspacing
.
setskip
(
key
,
value
,
grid
)
854
if
value
~
=
"
"
then
855
if
grid
=
=
"
"
then
grid
=
value
end
856
skip
[
key
]
=
{
value
,
grid
}
857
end
858
end
859 860
local
expandmacro
=
token
.
expandmacro
-- todo
861
-- local runlocal = tex.runlocal
862
-- local setmacro = tokens.setters.macro
863
-- local settoks = tex.settoks
864
local
toscaled
=
tex
.
toscaled
865 866
local
b_done
=
false
867
local
b_packed
=
false
868 869
local
b_amount
=
0
870
local
b_stretch
=
0
871
local
b_shrink
=
0
872
local
b_category
=
false
873
local
b_penalty
=
false
874
local
b_order
=
false
875
local
b_fixed
=
false
876
local
b_grid
=
false
877 878
local
pattern
=
nil
879 880
local
packed
=
categories
.
packed
881 882
local
gluefactor
=
.
25
883 884
local
ctx_ignoreparskip
=
context
.
core
.
ignoreparskip
885 886
local
function
before
(
)
887
b_amount
=
0
888
b_stretch
=
0
889
b_shrink
=
0
890
b_category
=
1
891
b_penalty
=
false
892
b_order
=
false
893
b_fixed
=
b_grid
894
end
895 896
local
function
after
(
)
897
if
b_fixed
then
898
b_stretch
=
0
899
b_shrink
=
0
900
else
901
b_stretch
=
gluefactor
*
b_amount
902
b_shrink
=
gluefactor
*
b_amount
903
end
904
end
905 906
-- use a cache for predefined ones
907 908
local
function
inject
(
)
909
local
n
=
new_glue
(
b_amount
,
b_stretch
,
b_shrink
)
910
setspecification
(
n
,
b_category
,
b_penalty
,
b_order
or
1
)
911
write_node
(
n
)
912
end
913 914
local
function
flush
(
)
915
after
(
)
916
if
b_done
then
917
inject
(
)
918
b_done
=
false
919
end
920
before
(
)
921
end
922 923
-- local cmd = token.create("vspacingfromtempstring")
924
-- local cmd = token.create("vspacingpredefinedvalue") -- not yet known
925 926
local
function
handler
(
multiplier
,
keyword
,
detail
)
927
if
not
keyword
then
928
report_vspacing
(
"
unknown directive %a
"
,
s
)
929
else
930
local
mk
=
map
[
keyword
]
931
if
mk
then
932
lpegmatch
(
pattern
,
mk
)
933
elseif
keyword
=
=
k_fixed
then
934
b_fixed
=
true
935
elseif
keyword
=
=
k_flexible
then
936
b_flexible
=
false
937
elseif
keyword
=
=
k_category
then
938
local
category
=
tonumber
(
detail
)
939
if
category
=
=
packed
then
940
b_packed
=
true
941
elseif
category
then
942
b_category
=
category
943
b_done
=
true
944
flush
(
)
945
end
946
elseif
keyword
=
=
k_order
and
detail
then
947
local
order
=
tonumber
(
detail
)
948
if
order
then
949
b_order
=
order
950
end
951
elseif
keyword
=
=
k_penalty
and
detail
then
952
local
penalty
=
tonumber
(
detail
)
953
if
penalty
then
954
flush
(
)
955
b_done
=
true
956
b_category
=
3
957
b_penalty
=
penalty
958
flush
(
)
959
end
960
else
961
local
amount
,
stretch
,
shrink
962
multiplier
=
tonumber
(
multiplier
)
or
1
963
local
sk
=
skip
[
keyword
]
964
if
sk
then
965
-- multiplier, keyword
966
-- best, for now, todo: runlocal with arguments
967
expandmacro
(
"
vspacingpredefinedvalue
"
,
true
,
keyword
)
968
-- expandmacro(cmd,true,keyword)
969
-- setmacro("tempstring",keyword)
970
-- runlocal(cmd)
971
-- nicest
972
-- runlocal(cache[keyword])
973
-- fast
974
-- settoks("scratchtoks",keyword)
975
-- runlocal("vspacingfromscratchtoks")
976
-- middleground
977
-- setmacro("tempstring",keyword)
978
-- runlocal(ctx_vspacingfromtempstring)
979
--
980
amount
,
stretch
,
shrink
=
texgetglue
(
"
scratchskip
"
)
981
if
not
stretch
then
982
stretch
=
0
983
end
984
if
not
shrink
then
985
shrink
=
0
986
end
987
if
stretch
=
=
0
and
shrink
=
=
0
then
988
stretch
=
gluefactor
*
amount
-- always unless grid
989
shrink
=
stretch
-- always unless grid
990
end
991
else
-- no check, todo: parse plus and minus
992
amount
=
toscaled
(
keyword
)
993
stretch
=
gluefactor
*
amount
-- always unless grid
994
shrink
=
stretch
-- always unless grid
995
end
996
-- we look at fixed later
997
b_amount
=
b_amount
+
multiplier
*
amount
998
b_stretch
=
b_stretch
+
multiplier
*
stretch
999
b_shrink
=
b_shrink
+
multiplier
*
shrink
1000
b_done
=
true
1001
end
1002
end
1003
end
1004 1005
-- alternatively we can make a table and have a keyword -> split cache but this is probably
1006
-- not really a bottleneck
1007 1008
local
splitter
=
(
(
multiplier
+
singlefier
)
*
keyword
*
(
category
+
Cc
(
false
)
)
)
/
handler
1009
pattern
=
(
splitter
+
separator
^
1
)
^
0
1010 1011
function
vspacing
.
inject
(
grid
,
str
)
1012
if
trace_vspacing
then
1013
-- ctx_pushlogger(report_vspacing)
1014
end
1015
b_done
=
false
1016
b_packed
=
false
1017
b_grid
=
grid
=
=
true
or
grid
=
=
1
1018
before
(
)
1019
lpegmatch
(
pattern
,
str
)
1020
after
(
)
1021
if
b_done
then
1022
inject
(
)
1023
end
1024
if
b_packed
then
1025
ctx_ignoreparskip
(
)
1026
end
1027
if
trace_vspacing
then
1028
-- ctx_poplogger()
1029
end
1030
end
1031 1032
function
vspacing
.
injectpenalty
(
penalty
)
1033
local
n
=
new_glue
(
)
1034
-- setattrs(n,false,a_skipcategory,categories.penalty,a_skippenalty,penalty,a_skiporder,1)
1035
setspecification
(
n
,
categories
.
penalty
,
penalty
,
1
)
1036
write_node
(
n
)
1037
end
1038 1039
function
vspacing
.
injectskip
(
amount
)
1040
local
n
=
new_glue
(
amount
)
1041
-- setattrs(n,false,a_skipcategory,categories.largest,a_skippenalty,false,a_skiporder,1)
1042
setspecification
(
n
,
categories
.
largest
,
false
,
1
)
1043
write_node
(
n
)
1044
end
1045 1046
function
vspacing
.
injectdisable
(
amount
)
1047
local
n
=
new_glue
(
)
1048
-- setattrs(n,false,a_skipcategory,categories.disable,a_skippenalty,false,a_skiporder,1)
1049
setspecification
(
n
,
categories
.
disable
,
false
,
1
)
1050
write_node
(
n
)
1051
end
1052 1053
end
1054 1055
-- implementation
1056 1057
-- alignment box begin_of_par vmode_par hmode_par insert penalty before_display after_display
1058 1059
function
vspacing
.
snapbox
(
n
,
how
)
1060
local
sv
=
snapmethods
[
how
]
1061
if
sv
then
1062
local
box
=
getbox
(
n
)
1063
local
list
=
getlist
(
box
)
1064
if
list
then
1065
local
s
=
getattr
(
list
,
a_snapmethod
)
1066
if
s
=
=
0
then
1067
if
trace_vsnapping
then
1068
-- report_snapper("box list not snapped, already done")
1069
end
1070
else
1071
local
wd
,
ht
,
dp
=
getwhd
(
box
)
1072
if
false
then
-- todo: already_done
1073
-- assume that the box is already snapped
1074
if
trace_vsnapping
then
1075
report_snapper
(
"
box list already snapped at (%p,%p): %s
"
,
1076
ht
,
dp
,
listtoutf
(
list
)
)
1077
end
1078
else
1079
local
h
,
d
,
ch
,
cd
,
lines
,
extra
=
snap_hlist
(
"
box
"
,
box
,
sv
,
ht
,
dp
)
1080
setprop
(
box
,
"
snapper
"
,
{
1081
ht
=
h
,
1082
dp
=
d
,
1083
ch
=
ch
,
1084
cd
=
cd
,
1085
extra
=
extra
,
1086
current
=
current
,
1087
}
)
1088
setwhd
(
box
,
wd
,
ch
,
cd
)
1089
if
trace_vsnapping
then
1090
report_snapper
(
"
box list snapped from (%p,%p) to (%p,%p) using method %a (%s) for %a (%s lines): %s
"
,
1091
h
,
d
,
ch
,
cd
,
sv
.
name
,
sv
.
specification
,
"
direct
"
,
lines
,
listtoutf
(
list
)
)
1092
end
1093
setattr
(
box
,
a_snapmethod
,
0
)
--
1094
setattr
(
list
,
a_snapmethod
,
0
)
-- yes or no
1095
end
1096
end
1097
end
1098
end
1099
end
1100 1101
-- I need to figure out how to deal with the prevdepth that crosses pages. In fact,
1102
-- prevdepth is often quite interfering (even over a next paragraph) so I need to
1103
-- figure out a trick. Maybe use something other than a rule. If we visualize we'll
1104
-- see the baselineskip in action:
1105
--
1106
-- \blank[force,5*big] { \baselineskip1cm xxxxxxxxx \par } \page
1107
-- \blank[force,5*big] { \baselineskip1cm xxxxxxxxx \par } \page
1108
-- \blank[force,5*big] { \baselineskip5cm xxxxxxxxx \par } \page
1109 1110
-- We can register and copy the rule instead.
1111 1112
do
1113 1114
local
insertnodeafter
=
nuts
.
insertafter
1115
local
insertnodebefore
=
nuts
.
insertbefore
1116 1117
local
abovedisplayskip_code
=
gluecodes
.
abovedisplayskip
1118
local
belowdisplayskip_code
=
gluecodes
.
belowdisplayskip
1119
local
abovedisplayshortskip_code
=
gluecodes
.
abovedisplayshortskip
1120
local
belowdisplayshortskip_code
=
gluecodes
.
belowdisplayshortskip
1121 1122
local
w
,
h
,
d
=
0
,
0
,
0
1123
----- w, h, d = 100*65536, 65536, 65536
1124 1125
local
trace_list
=
{
}
1126
local
tracing_info
=
{
}
1127
local
before
=
"
"
1128
local
after
=
"
"
1129 1130
local
function
nodes_to_string
(
head
)
1131
local
current
=
head
1132
local
t
=
{
}
1133
while
current
do
1134
local
id
=
getid
(
current
)
1135
local
ty
=
nodecodes
[
id
]
1136
if
id
=
=
penalty_code
then
1137
t
[
#
t
+
1
]
=
formatters
[
"
%s:%s
"
]
(
ty
,
getpenalty
(
current
)
)
1138
elseif
id
=
=
glue_code
then
1139
t
[
#
t
+
1
]
=
formatters
[
"
%s:%s:%p
"
]
(
ty
,
gluecodes
[
getsubtype
(
current
)
]
,
getwidth
(
current
)
)
1140
elseif
id
=
=
kern_code
then
1141
t
[
#
t
+
1
]
=
formatters
[
"
%s:%p
"
]
(
ty
,
getkern
(
current
)
)
1142
else
1143
t
[
#
t
+
1
]
=
ty
1144
end
1145
current
=
getnext
(
current
)
1146
end
1147
return
concat
(
t
,
"
+
"
)
1148
end
1149 1150
local
function
reset_tracing
(
head
)
1151
trace_list
,
tracing_info
,
before
,
after
=
{
}
,
false
,
nodes_to_string
(
head
)
,
"
"
1152
end
1153 1154
local
function
trace_skip
(
str
,
sc
,
so
,
sp
,
data
)
1155
trace_list
[
#
trace_list
+
1
]
=
{
"
skip
"
,
formatters
[
"
%s | %p | category %s | order %s | penalty %s
"
]
(
str
,
getwidth
(
data
)
,
sc
or
"
-
"
,
so
or
"
-
"
,
sp
or
"
-
"
)
}
1156
tracing_info
=
true
1157
end
1158 1159
local
function
trace_natural
(
str
,
data
)
1160
trace_list
[
#
trace_list
+
1
]
=
{
"
skip
"
,
formatters
[
"
%s | %p
"
]
(
str
,
getwidth
(
data
)
)
}
1161
tracing_info
=
true
1162
end
1163 1164
local
function
trace_info
(
message
,
where
,
what
)
1165
trace_list
[
#
trace_list
+
1
]
=
{
"
info
"
,
formatters
[
"
%s: %s/%s
"
]
(
message
,
where
,
what
)
}
1166
end
1167 1168
local
function
trace_node
(
what
)
1169
local
nt
=
nodecodes
[
getid
(
what
)
]
1170
local
tl
=
trace_list
[
#
trace_list
]
1171
if
tl
and
tl
[
1
]
=
=
"
node
"
then
1172
trace_list
[
#
trace_list
]
=
{
"
node
"
,
formatters
[
"
%s + %s
"
]
(
tl
[
2
]
,
nt
)
}
1173
else
1174
trace_list
[
#
trace_list
+
1
]
=
{
"
node
"
,
nt
}
1175
end
1176
end
1177 1178
local
function
show_tracing
(
head
)
1179
if
tracing_info
then
1180
after
=
nodes_to_string
(
head
)
1181
for
i
=
1
,
#
trace_list
do
1182
local
tag
,
text
=
unpack
(
trace_list
[
i
]
)
1183
if
tag
=
=
"
info
"
then
1184
report_collapser
(
text
)
1185
else
1186
report_collapser
(
"
%s: %s
"
,
tag
,
text
)
1187
end
1188
end
1189
report_collapser
(
"
before: %s
"
,
before
)
1190
report_collapser
(
"
after : %s
"
,
after
)
1191
end
1192
end
1193 1194
local
function
trace_done
(
str
,
data
)
1195
if
getid
(
data
)
=
=
penalty_code
then
1196
trace_list
[
#
trace_list
+
1
]
=
{
"
penalty
"
,
formatters
[
"
%s | %s
"
]
(
str
,
getpenalty
(
data
)
)
}
1197
else
1198
trace_list
[
#
trace_list
+
1
]
=
{
"
glue
"
,
formatters
[
"
%s | %p
"
]
(
str
,
getwidth
(
data
)
)
}
1199
end
1200
tracing_info
=
true
1201
end
1202 1203
local
function
forced_skip
(
head
,
current
,
width
,
where
,
trace
)
-- looks old ... we have other tricks now
1204
if
head
=
=
current
then
1205
if
getsubtype
(
head
)
=
=
baselineskip_code
then
1206
width
=
width
-
getwidth
(
head
)
1207
end
1208
end
1209
if
width
=
=
0
then
1210
-- do nothing
1211
elseif
where
=
=
"
after
"
then
1212
head
,
current
=
insertnodeafter
(
head
,
current
,
new_rule
(
w
,
h
,
d
)
)
1213
head
,
current
=
insertnodeafter
(
head
,
current
,
new_kern
(
width
)
)
1214
head
,
current
=
insertnodeafter
(
head
,
current
,
new_rule
(
w
,
h
,
d
)
)
1215
else
1216
local
c
=
current
1217
head
,
current
=
insertnodebefore
(
head
,
current
,
new_rule
(
w
,
h
,
d
)
)
1218
head
,
current
=
insertnodebefore
(
head
,
current
,
new_kern
(
width
)
)
1219
head
,
current
=
insertnodebefore
(
head
,
current
,
new_rule
(
w
,
h
,
d
)
)
1220
current
=
c
1221
end
1222
if
trace
then
1223
report_vspacing
(
"
inserting forced skip of %p
"
,
width
)
1224
end
1225
return
head
,
current
1226
end
1227 1228
-- penalty only works well when before skip
1229 1230
local
discard
=
categories
.
discard
1231
local
largest
=
categories
.
largest
1232
local
force
=
categories
.
force
1233
local
penalty
=
categories
.
penalty
1234
local
add
=
categories
.
add
1235
local
disable
=
categories
.
disable
1236
local
nowhite
=
categories
.
nowhite
1237
local
goback
=
categories
.
goback
1238
local
packed
=
categories
.
packed
1239
local
overlay
=
categories
.
overlay
1240
local
enable
=
categories
.
enable
1241
local
notopskip
=
categories
.
notopskip
1242 1243
-- [whatsits][hlist][glue][glue][penalty]
1244 1245
local
special_penalty_min
=
32250
1246
local
special_penalty_max
=
35000
1247
local
special_penalty_xxx
=
0
1248 1249
-- this is rather messy and complex: we want to make sure that successive
1250
-- header don't break but also make sure that we have at least a decent
1251
-- break when we have succesive ones (often when testing)
1252 1253
-- todo: mark headers as such so that we can recognize them
1254 1255
local
specialmethods
=
{
}
1256
local
specialmethod
=
1
1257 1258
specialmethods
[
1
]
=
function
(
pagehead
,
pagetail
,
start
,
penalty
)
1259
--
1260
if
not
pagehead
or
penalty
<
special_penalty_min
or
penalty
>
special_penalty_max
then
1261
return
1262
end
1263
local
current
=
pagetail
1264
--
1265
-- nodes.showsimplelist(pagehead,0)
1266
--
1267
if
trace_specials
then
1268
report_specials
(
"
checking penalty %a
"
,
penalty
)
1269
end
1270
while
current
do
1271
local
id
=
getid
(
current
)
1272
if
id
=
=
penalty_code
then
1273
local
p
=
properties
[
current
]
1274
if
p
then
1275
local
p
=
p
.
special_penalty
1276
if
not
p
then
1277
if
trace_specials
then
1278
report_specials
(
"
regular penalty, continue
"
)
1279
end
1280
elseif
p
=
=
penalty
then
1281
if
trace_specials
then
1282
report_specials
(
"
context penalty %a, same level, overloading
"
,
p
)
1283
end
1284
return
special_penalty_xxx
1285
elseif
p
>
special_penalty_min
and
p
<
special_penalty_max
then
1286
if
penalty
<
p
then
1287
if
trace_specials
then
1288
report_specials
(
"
context penalty %a, lower level, overloading
"
,
p
)
1289
end
1290
return
special_penalty_xxx
1291
else
1292
if
trace_specials
then
1293
report_specials
(
"
context penalty %a, higher level, quitting
"
,
p
)
1294
end
1295
return
1296
end
1297
elseif
trace_specials
then
1298
report_specials
(
"
context penalty %a, higher level, continue
"
,
p
)
1299
end
1300
else
1301
local
p
=
getpenalty
(
current
)
1302
if
p
<
10000
then
1303
-- assume some other mechanism kicks in so we seem to have content
1304
if
trace_specials
then
1305
report_specials
(
"
regular penalty %a, quitting
"
,
p
)
1306
end
1307
break
1308
else
1309
if
trace_specials
then
1310
report_specials
(
"
regular penalty %a, continue
"
,
p
)
1311
end
1312
end
1313
end
1314
end
1315
current
=
getprev
(
current
)
1316
end
1317
-- none found, so no reson to be special
1318
if
trace_specials
then
1319
if
pagetail
then
1320
report_specials
(
"
context penalty, discarding, nothing special
"
)
1321
else
1322
report_specials
(
"
context penalty, discarding, nothing preceding
"
)
1323
end
1324
end
1325
return
special_penalty_xxx
1326
end
1327 1328
-- This will be replaced after 0.80+ when we have a more robust look-back and
1329
-- can look at the bigger picture.
1330 1331
-- todo: look back and when a special is there before a list is seen penalty keep ut
1332 1333
-- we now look back a lot, way too often
1334 1335
-- userskip
1336
-- lineskip
1337
-- baselineskip
1338
-- parskip
1339
-- abovedisplayskip
1340
-- belowdisplayskip
1341
-- abovedisplayshortskip
1342
-- belowdisplayshortskip
1343
-- topskip
1344
-- splittopskip
1345 1346
-- we could inject a vadjust to force a recalculation .. a mess
1347
--
1348
-- So, the next is far from robust and okay but for the moment this overlaying
1349
-- has to do. Always test this with the examples in spac-ver.mkvi!
1350 1351
local
function
snap_topskip
(
current
,
method
)
1352
local
w
=
getwidth
(
current
)
1353
setwidth
(
current
,
0
)
1354
return
w
,
0
1355
end
1356 1357
local
function
check_experimental_overlay
(
head
,
current
)
1358
local
p
=
nil
1359
local
c
=
current
1360
local
n
=
nil
1361
local
function
overlay
(
p
,
n
,
mvl
)
1362
local
p_wd
,
p_ht
,
p_dp
=
getwhd
(
p
)
1363
local
n_wd
,
n_ht
,
n_dp
=
getwhd
(
n
)
1364
local
skips
=
0
1365
--
1366
-- We deal with this at the tex end .. we don't see spacing .. enabling this code
1367
-- is probably harmless but then we need to test it.
1368
--
1369
-- we could calculate this before we call
1370
--
1371
-- problem: prev list and next list can be unconnected
1372
--
1373
local
c
=
getnext
(
p
)
1374
local
l
=
c
1375
while
c
and
c
~
=
n
do
1376
local
id
=
getid
(
c
)
1377
if
id
=
=
glue_code
then
1378
skips
=
skips
+
getwidth
(
c
)
1379
elseif
id
=
=
kern_code
then
1380
skips
=
skips
+
getkern
(
c
)
1381
end
1382
l
=
c
1383
c
=
getnext
(
c
)
1384
end
1385
local
c
=
getprev
(
n
)
1386
while
c
and
c
~
=
n
and
c
~
=
l
do
1387
local
id
=
getid
(
c
)
1388
if
id
=
=
glue_code
then
1389
skips
=
skips
+
getwidth
(
c
)
1390
elseif
id
=
=
kern_code
then
1391
skips
=
skips
+
getkern
(
c
)
1392
end
1393
c
=
getprev
(
c
)
1394
end
1395
--
1396
local
delta
=
n_ht
+
skips
+
p_dp
1397
texsetdimen
(
"
global
"
,
"
d_spac_overlay
"
,
-
delta
)
-- for tracing
1398
-- we should adapt pagetotal ! (need a hook for that) .. now we have the wrong pagebreak
1399
local
k
=
new_kern
(
-
delta
)
1400
head
=
insertnodebefore
(
head
,
n
,
k
)
1401
if
n_ht
>
p_ht
then
1402
local
k
=
new_kern
(
n_ht
-
p_ht
)
1403
head
=
insertnodebefore
(
head
,
p
,
k
)
1404
end
1405
if
trace_vspacing
then
1406
report_vspacing
(
"
overlaying, prev height: %p, prev depth: %p, next height: %p, skips: %p, move up: %p
"
,
p_ht
,
p_dp
,
n_ht
,
skips
,
delta
)
1407
end
1408
return
remove_node
(
head
,
current
,
true
)
1409
end
1410 1411
-- goto next line
1412
while
c
do
1413
local
id
=
getid
(
c
)
1414
if
id
=
=
glue_code
or
id
=
=
penalty_code
or
id
=
=
kern_code
then
1415
-- skip (actually, remove)
1416
c
=
getnext
(
c
)
1417
elseif
id
=
=
hlist_code
then
1418
n
=
c
1419
break
1420
else
1421
break
1422
end
1423
end
1424
if
n
then
1425
-- we have a next line, goto prev line
1426
c
=
current
1427
while
c
do
1428
local
id
=
getid
(
c
)
1429
if
id
=
=
glue_code
or
id
=
=
penalty_code
then
-- kern ?
1430
c
=
getprev
(
c
)
1431
elseif
id
=
=
hlist_code
then
1432
p
=
c
1433
break
1434
else
1435
break
1436
end
1437
end
1438
if
not
p
then
1439
if
a_snapmethod
=
=
a_snapvbox
then
1440
-- quit, we're not on the mvl
1441
else
1442
-- inefficient when we're at the end of a page
1443
local
c
=
tonut
(
texlists
.
page_head
)
1444
while
c
and
c
~
=
n
do
1445
local
id
=
getid
(
c
)
1446
if
id
=
=
hlist_code
then
1447
p
=
c
1448
end
1449
c
=
getnext
(
c
)
1450
end
1451
if
p
and
p
~
=
n
then
1452
return
overlay
(
p
,
n
,
true
)
1453
end
1454
end
1455
elseif
p
~
=
n
then
1456
return
overlay
(
p
,
n
,
false
)
1457
end
1458
end
1459
-- in fact, we could try again later ... so then no remove (a few tries)
1460
return
remove_node
(
head
,
current
,
true
)
1461
end
1462 1463
local
function
collapser
(
head
,
where
,
what
,
trace
,
snap
,
a_snapmethod
)
-- maybe also pass tail
1464
if
trace
then
1465
reset_tracing
(
head
)
1466
end
1467
local
current
=
head
1468
local
oldhead
=
head
1469
local
glue_order
=
0
1470
local
glue_data
1471
local
force_glue
=
false
1472
local
penalty_order
=
0
1473
local
penalty_data
1474
local
natural_penalty
1475
local
special_penalty
1476
local
parskip
1477
local
ignore_parskip
=
false
1478
local
ignore_following
=
false
1479
local
ignore_whitespace
=
false
1480
local
keep_together
=
false
1481
local
lastsnap
1482
local
pagehead
1483
local
pagetail
1484
--
1485
-- todo: keep_together: between headers
1486
--
1487
local
function
getpagelist
(
)
1488
if
not
pagehead
then
1489
pagehead
=
texlists
.
page_head
1490
if
pagehead
then
1491
pagehead
=
tonut
(
pagehead
)
1492
pagetail
=
find_node_tail
(
pagehead
)
-- no texlists.page_tail yet-- no texlists.page_tail yet
1493
end
1494
end
1495
end
1496
--
1497
local
function
compensate
(
n
)
1498
local
g
=
0
1499
while
n
and
getid
(
n
)
=
=
glue_code
do
1500
g
=
g
+
getwidth
(
n
)
1501
n
=
getnext
(
n
)
1502
end
1503
if
n
then
1504
local
p
=
getprop
(
n
,
"
snapper
"
)
1505
if
p
then
1506
local
extra
=
p
.
extra
1507
if
extra
and
extra
<
0
then
-- hm, extra can be unset ... needs checking
1508
local
h
=
p
.
ch
-- getheight(n)
1509
-- maybe an extra check
1510
-- if h - extra < g then
1511
setheight
(
n
,
h
-2
*
extra
)
1512
p
.
extra
=
0
1513
if
trace_vsnapping
then
1514
report_snapper
(
"
removed extra space at top: %p
"
,
extra
)
1515
end
1516
-- end
1517
end
1518
end
1519
return
n
1520
end
1521
end
1522
--
1523
local
function
removetopsnap
(
)
1524
getpagelist
(
)
1525
if
pagehead
then
1526
local
n
=
pagehead
and
compensate
(
pagehead
)
1527
if
n
and
n
~
=
pagetail
then
1528
local
p
=
getprop
(
pagetail
,
"
snapper
"
)
1529
if
p
then
1530
local
e
=
p
.
extra
1531
if
e
and
e
<
0
then
1532
local
t
=
texget
(
"
pagetotal
"
)
1533
if
t
>
0
then
1534
local
g
=
texget
(
"
pagegoal
"
)
-- 1073741823 is signal
1535
local
d
=
g
-
t
1536
if
d
<
-
e
then
1537
local
penalty
=
new_penalty
(
1000000
)
1538
setlink
(
penalty
,
head
)
1539
head
=
penalty
1540
report_snapper
(
"
force pagebreak due to extra space at bottom: %p
"
,
e
)
1541
end
1542
end
1543
end
1544
end
1545
end
1546
elseif
head
then
1547
compensate
(
head
)
1548
end
1549
end
1550
--
1551
local
function
getavailable
(
)
1552
getpagelist
(
)
1553
if
pagehead
then
1554
local
t
=
texget
(
"
pagetotal
"
)
1555
if
t
>
0
then
1556
local
g
=
texget
(
"
pagegoal
"
)
1557
return
g
-
t
1558
end
1559
end
1560
return
false
1561
end
1562
--
1563
local
function
flush
(
why
)
1564
if
penalty_data
then
1565
local
p
=
new_penalty
(
penalty_data
)
1566
if
trace
then
1567
trace_done
(
"
flushed due to
"
.
.
why
,
p
)
1568
end
1569
if
penalty_data
>
=
10000
then
-- or whatever threshold?
1570
local
prev
=
getprev
(
current
)
1571
if
getid
(
prev
)
=
=
glue_code
then
-- maybe go back more, or maybe even push back before any glue
1572
-- tricky case: spacing/grid-007.tex: glue penalty glue
1573
head
=
insertnodebefore
(
head
,
prev
,
p
)
1574
else
1575
head
=
insertnodebefore
(
head
,
current
,
p
)
1576
end
1577
else
1578
head
=
insertnodebefore
(
head
,
current
,
p
)
1579
end
1580
-- if penalty_data > special_penalty_min and penalty_data < special_penalty_max then
1581
local
props
=
properties
[
p
]
1582
if
props
then
1583
props
.
special_penalty
=
special_penalty
or
penalty_data
1584
else
1585
properties
[
p
]
=
{
1586
special_penalty
=
special_penalty
or
penalty_data
1587
}
1588
end
1589
-- end
1590
end
1591
if
glue_data
then
1592
if
force_glue
then
1593
if
trace
then
1594
trace_done
(
"
flushed due to forced
"
.
.
why
,
glue_data
)
1595
end
1596
head
=
forced_skip
(
head
,
current
,
getwidth
(
glue_data
,
width
)
,
"
before
"
,
trace
)
1597
flushnode
(
glue_data
)
1598
else
1599
local
width
,
stretch
,
shrink
=
getglue
(
glue_data
)
1600
if
width
~
=
0
then
1601
if
trace
then
1602
trace_done
(
"
flushed due to non zero
"
.
.
why
,
glue_data
)
1603
end
1604
head
=
insertnodebefore
(
head
,
current
,
glue_data
)
1605
elseif
stretch
~
=
0
or
shrink
~
=
0
then
1606
if
trace
then
1607
trace_done
(
"
flushed due to stretch/shrink in
"
.
.
why
,
glue_data
)
1608
end
1609
head
=
insertnodebefore
(
head
,
current
,
glue_data
)
1610
else
1611
-- report_vspacing("needs checking (%s): %p",gluecodes[getsubtype(glue_data)],w)
1612
flushnode
(
glue_data
)
1613
end
1614
end
1615
end
1616 1617
if
trace
then
1618
trace_node
(
current
)
1619
end
1620
glue_order
,
glue_data
,
force_glue
=
0
,
nil
,
false
1621
penalty_order
,
penalty_data
,
natural_penalty
=
0
,
nil
,
nil
1622
parskip
,
ignore_parskip
,
ignore_following
,
ignore_whitespace
=
nil
,
false
,
false
,
false
1623
end
1624
--
1625
if
trace_vsnapping
then
1626
report_snapper
(
"
global ht/dp = %p/%p, local ht/dp = %p/%p
"
,
1627
texgetdimen
(
"
globalbodyfontstrutheight
"
)
,
1628
texgetdimen
(
"
globalbodyfontstrutdepth
"
)
,
1629
texgetdimen
(
"
bodyfontstrutheight
"
)
,
1630
texgetdimen
(
"
bodyfontstrutdepth
"
)
1631
)
1632
end
1633
if
trace
then
1634
trace_info
(
"
start analyzing
"
,
where
,
what
)
1635
end
1636
if
snap
and
where
=
=
"
page
"
then
1637
removetopsnap
(
)
1638
end
1639
while
current
do
1640
local
id
=
getid
(
current
)
1641
if
id
=
=
hlist_code
or
id
=
=
vlist_code
then
1642
-- needs checking, why so many calls
1643
if
snap
then
1644
lastsnap
=
nil
1645
local
list
=
getlist
(
current
)
1646
local
s
=
getattr
(
current
,
a_snapmethod
)
1647
if
not
s
then
1648
-- if trace_vsnapping then
1649
-- report_snapper("mvl list not snapped")
1650
-- end
1651
elseif
s
=
=
0
then
1652
if
trace_vsnapping
then
1653
report_snapper
(
"
mvl %a not snapped, already done: %s
"
,
nodecodes
[
id
]
,
listtoutf
(
list
)
)
1654
end
1655
else
1656
local
sv
=
snapmethods
[
s
]
1657
if
sv
then
1658
-- check if already snapped
1659
local
done
=
list
and
already_done
(
id
,
list
,
a_snapmethod
)
1660
if
done
then
1661
-- assume that the box is already snapped
1662
if
trace_vsnapping
then
1663
local
w
,
h
,
d
=
getwhd
(
current
)
1664
report_snapper
(
"
mvl list already snapped at (%p,%p): %s
"
,
h
,
d
,
listtoutf
(
list
)
)
1665
end
1666
else
1667
local
h
,
d
,
ch
,
cd
,
lines
,
extra
=
snap_hlist
(
"
mvl
"
,
current
,
sv
,
false
,
false
)
1668
lastsnap
=
{
1669
ht
=
h
,
1670
dp
=
d
,
1671
ch
=
ch
,
1672
cd
=
cd
,
1673
extra
=
extra
,
1674
current
=
current
,
1675
}
1676
setprop
(
current
,
"
snapper
"
,
lastsnap
)
1677
if
trace_vsnapping
then
1678
report_snapper
(
"
mvl %a snapped from (%p,%p) to (%p,%p) using method %a (%s) for %a (%s lines): %s
"
,
1679
nodecodes
[
id
]
,
h
,
d
,
ch
,
cd
,
sv
.
name
,
sv
.
specification
,
where
,
lines
,
listtoutf
(
list
)
)
1680
end
1681
end
1682
elseif
trace_vsnapping
then
1683
report_snapper
(
"
mvl %a not snapped due to unknown snap specification: %s
"
,
nodecodes
[
id
]
,
listtoutf
(
list
)
)
1684
end
1685
setattr
(
current
,
a_snapmethod
,
0
)
1686
end
1687
else
1688
--
1689
end
1690
-- tex.prevdepth = 0
1691
flush
(
"
list
"
)
1692
current
=
getnext
(
current
)
1693
elseif
id
=
=
penalty_code
then
1694
-- natural_penalty = getpenalty(current)
1695
-- if trace then
1696
-- trace_done("removed penalty",current)
1697
-- end
1698
-- head, current = remove_node(head,current,true)
1699
current
=
getnext
(
current
)
1700
elseif
id
=
=
kern_code
then
1701
if
snap
and
trace_vsnapping
and
getkern
(
current
)
~
=
0
then
1702
report_snapper
(
"
kern of %p kept
"
,
getkern
(
current
)
)
1703
end
1704
flush
(
"
kern
"
)
1705
current
=
getnext
(
current
)
1706
elseif
id
=
=
glue_code
then
1707
local
subtype
=
getsubtype
(
current
)
1708
if
subtype
=
=
userskip_code
then
1709
-- local sc, so, sp = getattrs(current,a_skipcategory,a_skiporder,a_skippenalty)
1710
local
sc
,
sp
,
so
=
getspecification
(
current
)
1711
if
not
so
then
1712
so
=
1
-- the others have no default value
1713
end
1714
if
sp
and
sc
=
=
penalty
then
1715
if
where
=
=
"
page
"
then
1716
getpagelist
(
)
1717
local
p
=
specialmethods
[
specialmethod
]
(
pagehead
,
pagetail
,
current
,
sp
)
1718
if
p
then
1719
-- todo: other tracer
1720
--
1721
-- if trace then
1722
-- trace_skip("previous special penalty %a is changed to %a using method %a",sp,p,specialmethod)
1723
-- end
1724
special_penalty
=
sp
1725
sp
=
p
1726
end
1727
end
1728
if
not
penalty_data
then
1729
penalty_data
=
sp
1730
elseif
penalty_order
<
so
then
1731
penalty_order
,
penalty_data
=
so
,
sp
1732
elseif
penalty_order
=
=
so
and
sp
>
penalty_data
then
1733
penalty_data
=
sp
1734
end
1735
if
trace
then
1736
trace_skip
(
"
penalty in skip
"
,
sc
,
so
,
sp
,
current
)
1737
end
1738
head
,
current
=
remove_node
(
head
,
current
,
true
)
1739
elseif
not
sc
then
-- if not sc then
1740
if
glue_data
then
1741
if
trace
then
1742
trace_done
(
"
flush
"
,
glue_data
)
1743
end
1744
head
=
insertnodebefore
(
head
,
current
,
glue_data
)
1745
if
trace
then
1746
trace_natural
(
"
natural
"
,
current
)
1747
end
1748
current
=
getnext
(
current
)
1749
glue_data
=
nil
1750
else
1751
-- not look back across head
1752
-- todo: prev can be whatsit (latelua)
1753
local
previous
=
getprev
(
current
)
1754
if
previous
and
getid
(
previous
)
=
=
glue_code
and
getsubtype
(
previous
)
=
=
userskip_code
then
1755
local
pwidth
,
pstretch
,
pshrink
,
pstretch_order
,
pshrink_order
=
getglue
(
previous
)
1756
local
cwidth
,
cstretch
,
cshrink
,
cstretch_order
,
cshrink_order
=
getglue
(
current
)
1757
if
pstretch_order
=
=
0
and
pshrink_order
=
=
0
and
cstretch_order
=
=
0
and
cshrink_order
=
=
0
then
1758
setglue
(
previous
,
pwidth
+
cwidth
,
pstretch
+
cstretch
,
pshrink
+
cshrink
)
1759
if
trace
then
1760
trace_natural
(
"
removed
"
,
current
)
1761
end
1762
head
,
current
=
remove_node
(
head
,
current
,
true
)
1763
if
trace
then
1764
trace_natural
(
"
collapsed
"
,
previous
)
1765
end
1766
else
1767
if
trace
then
1768
trace_natural
(
"
filler
"
,
current
)
1769
end
1770
current
=
getnext
(
current
)
1771
end
1772
else
1773
if
trace
then
1774
trace_natural
(
"
natural (no prev)
"
,
current
)
1775
end
1776
current
=
getnext
(
current
)
1777
end
1778
end
1779
glue_order
=
0
1780
elseif
sc
=
=
disable
or
sc
=
=
enable
then
1781
local
next
=
getnext
(
current
)
1782
if
next
then
1783
ignore_following
=
sc
=
=
disable
1784
if
trace
then
1785
trace_skip
(
sc
=
=
disable
and
"
disable
"
or
"
enable
"
,
sc
,
so
,
sp
,
current
)
1786
end
1787
head
,
current
=
remove_node
(
head
,
current
,
true
)
1788
else
1789
current
=
next
1790
end
1791
elseif
sc
=
=
packed
then
1792
if
trace
then
1793
trace_skip
(
"
packed
"
,
sc
,
so
,
sp
,
current
)
1794
end
1795
-- can't happen !
1796
head
,
current
=
remove_node
(
head
,
current
,
true
)
1797
elseif
sc
=
=
nowhite
then
1798
local
next
=
getnext
(
current
)
1799
if
next
then
1800
ignore_whitespace
=
true
1801
head
,
current
=
remove_node
(
head
,
current
,
true
)
1802
else
1803
current
=
next
1804
end
1805
elseif
sc
=
=
discard
then
1806
if
trace
then
1807
trace_skip
(
"
discard
"
,
sc
,
so
,
sp
,
current
)
1808
end
1809
head
,
current
=
remove_node
(
head
,
current
,
true
)
1810
elseif
sc
=
=
overlay
then
1811
-- todo (overlay following line over previous
1812
if
trace
then
1813
trace_skip
(
"
overlay
"
,
sc
,
so
,
sp
,
current
)
1814
end
1815
-- beware: head can actually be after the affected nodes as
1816
-- we look back ... some day head will the real head
1817
head
,
current
=
check_experimental_overlay
(
head
,
current
,
a_snapmethod
)
1818
elseif
ignore_following
then
1819
if
trace
then
1820
trace_skip
(
"
disabled
"
,
sc
,
so
,
sp
,
current
)
1821
end
1822
head
,
current
=
remove_node
(
head
,
current
,
true
)
1823
elseif
not
glue_data
then
1824
if
trace
then
1825
trace_skip
(
"
assign
"
,
sc
,
so
,
sp
,
current
)
1826
end
1827
glue_order
=
so
1828
head
,
current
,
glue_data
=
remove_node
(
head
,
current
)
1829
elseif
glue_order
<
so
then
1830
if
trace
then
1831
trace_skip
(
"
force
"
,
sc
,
so
,
sp
,
current
)
1832
end
1833
glue_order
=
so
1834
flushnode
(
glue_data
)
1835
head
,
current
,
glue_data
=
remove_node
(
head
,
current
)
1836
elseif
glue_order
=
=
so
then
1837
-- is now exclusive, maybe support goback as combi, else why a set
1838
if
sc
=
=
largest
then
1839
local
cw
=
getwidth
(
current
)
1840
local
gw
=
getwidth
(
glue_data
)
1841
if
cw
>
gw
then
1842
if
trace
then
1843
trace_skip
(
"
largest
"
,
sc
,
so
,
sp
,
current
)
1844
end
1845
flushnode
(
glue_data
)
1846
head
,
current
,
glue_data
=
remove_node
(
head
,
current
)
1847
else
1848
if
trace
then
1849
trace_skip
(
"
remove smallest
"
,
sc
,
so
,
sp
,
current
)
1850
end
1851
head
,
current
=
remove_node
(
head
,
current
,
true
)
1852
end
1853
elseif
sc
=
=
goback
then
1854
if
trace
then
1855
trace_skip
(
"
goback
"
,
sc
,
so
,
sp
,
current
)
1856
end
1857
flushnode
(
glue_data
)
1858
head
,
current
,
glue_data
=
remove_node
(
head
,
current
)
1859
elseif
sc
=
=
force
then
1860
-- last one counts, some day we can provide an accumulator and largest etc
1861
-- but not now
1862
if
trace
then
1863
trace_skip
(
"
force
"
,
sc
,
so
,
sp
,
current
)
1864
end
1865
flushnode
(
glue_data
)
1866
head
,
current
,
glue_data
=
remove_node
(
head
,
current
)
1867
elseif
sc
=
=
penalty
then
1868
if
trace
then
1869
trace_skip
(
"
penalty
"
,
sc
,
so
,
sp
,
current
)
1870
end
1871
flushnode
(
glue_data
)
1872
glue_data
=
nil
1873
head
,
current
=
remove_node
(
head
,
current
,
true
)
1874
elseif
sc
=
=
add
then
1875
if
trace
then
1876
trace_skip
(
"
add
"
,
sc
,
so
,
sp
,
current
)
1877
end
1878
local
cwidth
,
cstretch
,
cshrink
=
getglue
(
current
)
1879
local
gwidth
,
gstretch
,
gshrink
=
getglue
(
glue_data
)
1880
setglue
(
glue_data
,
gwidth
+
cwidth
,
gstretch
+
cstretch
,
gshrink
+
cshrink
)
1881
-- toto: order
1882
head
,
current
=
remove_node
(
head
,
current
,
true
)
1883
else
1884
if
trace
then
1885
trace_skip
(
"
unknown
"
,
sc
,
so
,
sp
,
current
)
1886
end
1887
head
,
current
=
remove_node
(
head
,
current
,
true
)
1888
end
1889
else
1890
if
trace
then
1891
trace_skip
(
"
unknown
"
,
sc
,
so
,
sp
,
current
)
1892
end
1893
head
,
current
=
remove_node
(
head
,
current
,
true
)
1894
end
1895
if
sc
=
=
force
then
1896
force_glue
=
true
1897
end
1898
elseif
subtype
=
=
lineskip_code
then
1899
if
snap
then
1900
local
s
=
getattr
(
current
,
a_snapmethod
)
1901
if
s
and
s
~
=
0
then
1902
setattr
(
current
,
a_snapmethod
,
0
)
1903
setwidth
(
current
,
0
)
1904
if
trace_vsnapping
then
1905
report_snapper
(
"
lineskip set to zero
"
)
1906
end
1907
else
1908
if
trace
then
1909
trace_skip
(
"
lineskip
"
,
sc
,
so
,
sp
,
current
)
1910
end
1911
flush
(
"
lineskip
"
)
1912
end
1913
else
1914
if
trace
then
1915
trace_skip
(
"
lineskip
"
,
sc
,
so
,
sp
,
current
)
1916
end
1917
flush
(
"
lineskip
"
)
1918
end
1919
current
=
getnext
(
current
)
1920
elseif
subtype
=
=
baselineskip_code
then
1921
if
snap
then
1922
local
s
=
getattr
(
current
,
a_snapmethod
)
1923
if
s
and
s
~
=
0
then
1924
setattr
(
current
,
a_snapmethod
,
0
)
1925
setwidth
(
current
,
0
)
1926
if
trace_vsnapping
then
1927
report_snapper
(
"
baselineskip set to zero
"
)
1928
end
1929
else
1930
if
trace
then
1931
trace_skip
(
"
baselineskip
"
,
sc
,
so
,
sp
,
current
)
1932
end
1933
flush
(
"
baselineskip
"
)
1934
end
1935
else
1936
if
trace
then
1937
trace_skip
(
"
baselineskip
"
,
sc
,
so
,
sp
,
current
)
1938
end
1939
flush
(
"
baselineskip
"
)
1940
end
1941
current
=
getnext
(
current
)
1942
elseif
subtype
=
=
parskip_code
then
1943
-- parskip always comes later
1944
if
ignore_whitespace
then
1945
if
trace
then
1946
trace_natural
(
"
ignored parskip
"
,
current
)
1947
end
1948
head
,
current
=
remove_node
(
head
,
current
,
true
)
1949
elseif
glue_data
then
1950
local
w
=
getwidth
(
current
)
1951
if
w
~
=
0
and
w
>
getwidth
(
glue_data
)
then
1952
flushnode
(
glue_data
)
1953
glue_data
=
current
1954
if
trace
then
1955
trace_natural
(
"
taking parskip
"
,
current
)
1956
end
1957
head
,
current
=
remove_node
(
head
,
current
)
1958
else
1959
if
trace
then
1960
trace_natural
(
"
removed parskip
"
,
current
)
1961
end
1962
head
,
current
=
remove_node
(
head
,
current
,
true
)
1963
end
1964
else
1965
if
trace
then
1966
trace_natural
(
"
honored parskip
"
,
current
)
1967
end
1968
head
,
current
,
glue_data
=
remove_node
(
head
,
current
)
1969
end
1970
elseif
subtype
=
=
topskip_code
or
subtype
=
=
splittopskip_code
then
1971
local
next
=
getnext
(
current
)
1972
-- if next and getattr(next,a_skipcategory) == notopskip then
1973
if
next
and
getspecification
(
next
)
=
=
notopskip
then
1974
nuts
.
setglue
(
current
)
-- zero
1975
end
1976
if
snap
then
1977
local
s
=
getattr
(
current
,
a_snapmethod
)
1978
if
s
and
s
~
=
0
then
1979
setattr
(
current
,
a_snapmethod
,
0
)
1980
local
sv
=
snapmethods
[
s
]
1981
local
w
,
cw
=
snap_topskip
(
current
,
sv
)
1982
if
trace_vsnapping
then
1983
report_snapper
(
"
topskip snapped from %p to %p for %a
"
,
w
,
cw
,
where
)
1984
end
1985
else
1986
if
trace
then
1987
trace_skip
(
"
topskip
"
,
sc
,
so
,
sp
,
current
)
1988
end
1989
flush
(
"
topskip
"
)
1990
end
1991
else
1992
if
trace
then
1993
trace_skip
(
"
topskip
"
,
sc
,
so
,
sp
,
current
)
1994
end
1995
flush
(
"
topskip
"
)
1996
end
1997
current
=
getnext
(
current
)
1998
elseif
subtype
=
=
abovedisplayskip_code
and
remove_math_skips
then
1999
--
2000
if
trace
then
2001
trace_skip
(
"
above display skip (normal)
"
,
sc
,
so
,
sp
,
current
)
2002
end
2003
flush
(
"
above display skip (normal)
"
)
2004
current
=
getnext
(
current
)
2005
--
2006
elseif
subtype
=
=
belowdisplayskip_code
and
remove_math_skips
then
2007
--
2008
if
trace
then
2009
trace_skip
(
"
below display skip (normal)
"
,
sc
,
so
,
sp
,
current
)
2010
end
2011
flush
(
"
below display skip (normal)
"
)
2012
current
=
getnext
(
current
)
2013
--
2014
elseif
subtype
=
=
abovedisplayshortskip_code
and
remove_math_skips
then
2015
--
2016
if
trace
then
2017
trace_skip
(
"
above display skip (short)
"
,
sc
,
so
,
sp
,
current
)
2018
end
2019
flush
(
"
above display skip (short)
"
)
2020
current
=
getnext
(
current
)
2021
--
2022
elseif
subtype
=
=
belowdisplayshortskip_code
and
remove_math_skips
then
2023
--
2024
if
trace
then
2025
trace_skip
(
"
below display skip (short)
"
,
sc
,
so
,
sp
,
current
)
2026
end
2027
flush
(
"
below display skip (short)
"
)
2028
current
=
getnext
(
current
)
2029
--
2030
else
-- other glue
2031
if
snap
and
trace_vsnapping
then
2032
local
w
=
getwidth
(
current
)
2033
if
w
~
=
0
then
2034
report_snapper
(
"
glue %p of type %a kept
"
,
w
,
gluecodes
[
subtype
]
)
2035
end
2036
end
2037
if
trace
then
2038
trace_skip
(
formatters
[
"
glue of type %a
"
]
(
subtype
)
,
sc
,
so
,
sp
,
current
)
2039
end
2040
flush
(
"
some glue
"
)
2041
current
=
getnext
(
current
)
2042
end
2043
else
2044
flush
(
trace
and
formatters
[
"
node with id %a
"
]
(
id
)
or
"
other node
"
)
2045
current
=
getnext
(
current
)
2046
end
2047
end
2048
if
trace
then
2049
trace_info
(
"
stop analyzing
"
,
where
,
what
)
2050
end
2051
-- if natural_penalty and (not penalty_data or natural_penalty > penalty_data) then
2052
-- penalty_data = natural_penalty
2053
-- end
2054
if
trace
and
(
glue_data
or
penalty_data
)
then
2055
trace_info
(
"
start flushing
"
,
where
,
what
)
2056
end
2057
local
tail
2058
if
penalty_data
then
2059
tail
=
find_node_tail
(
head
)
2060
local
p
=
new_penalty
(
penalty_data
)
2061
if
trace
then
2062
trace_done
(
"
result
"
,
p
)
2063
end
2064
setlink
(
tail
,
p
)
2065
-- if penalty_data > special_penalty_min and penalty_data < special_penalty_max then
2066
local
props
=
properties
[
p
]
2067
if
props
then
2068
props
.
special_penalty
=
special_penalty
or
penalty_data
2069
else
2070
properties
[
p
]
=
{
2071
special_penalty
=
special_penalty
or
penalty_data
2072
}
2073
end
2074
-- end
2075
end
2076
if
glue_data
then
2077
if
not
tail
then
tail
=
find_node_tail
(
head
)
end
2078
if
trace
then
2079
trace_done
(
"
result
"
,
glue_data
)
2080
end
2081
if
force_glue
then
2082
head
,
tail
=
forced_skip
(
head
,
tail
,
getwidth
(
glue_data
)
,
"
after
"
,
trace
)
2083
flushnode
(
glue_data
)
2084
glue_data
=
nil
2085
elseif
tail
then
2086
setlink
(
tail
,
glue_data
)
2087
setnext
(
glue_data
)
2088
else
2089
head
=
glue_data
2090
end
2091
texnest
[
texnest
.
ptr
]
.
prevdepth
=
0
-- appending to the list bypasses tex's prevdepth handler
2092
end
2093
if
trace
then
2094
if
glue_data
or
penalty_data
then
2095
trace_info
(
"
stop flushing
"
,
where
,
what
)
2096
end
2097
show_tracing
(
head
)
2098
if
oldhead
~
=
head
then
2099
trace_info
(
"
head has been changed from %a to %a
"
,
nodecodes
[
getid
(
oldhead
)
]
,
nodecodes
[
getid
(
head
)
]
)
2100
end
2101
end
2102
return
head
2103
end
2104 2105
local
stackhead
,
stacktail
,
stackhack
=
nil
,
nil
,
false
2106 2107
local
function
report
(
message
,
where
,
lst
)
2108
if
lst
and
where
then
2109
report_vspacing
(
message
,
where
,
count_nodes
(
lst
,
true
)
,
nodeidstostring
(
lst
)
)
2110
else
2111
report_vspacing
(
message
,
count_nodes
(
lst
,
true
)
,
nodeidstostring
(
lst
)
)
2112
end
2113
end
2114 2115
-- ugly code: we get partial lists (check if this stack is still okay) ... and we run
2116
-- into temp nodes (sigh)
2117 2118
local
forceflush
=
false
2119 2120
function
vspacing
.
pagehandler
(
newhead
,
where
)
2121
if
newhead
then
2122
local
newtail
=
find_node_tail
(
newhead
)
-- best pass that tail, known anyway
2123
local
flush
=
false
2124
stackhack
=
true
-- todo: only when grid snapping once enabled
2125
-- todo: fast check if head = tail
2126
for
n
,
id
,
subtype
in
nextnode
,
newhead
do
-- we could just look for glue nodes
2127
if
id
~
=
glue_code
then
2128
flush
=
true
2129
elseif
subtype
=
=
userskip_code
then
2130
-- local sc = getattr(n,a_skipcategory)
2131
local
sc
=
getspecification
(
n
)
2132
if
sc
then
2133
stackhack
=
true
2134
else
2135
flush
=
true
2136
end
2137
elseif
subtype
=
=
parskip_code
then
2138
-- if where == new_graf then ... end
2139
if
texgetcount
(
"
c_spac_vspacing_ignore_parskip
"
)
>
0
then
2140
-- texsetcount("c_spac_vspacing_ignore_parskip",0)
2141
setglue
(
n
)
2142
-- maybe removenode
2143
end
2144
end
2145
end
2146
texsetcount
(
"
c_spac_vspacing_ignore_parskip
"
,
0
)
2147 2148
if
forceflush
then
2149
forceflush
=
false
2150
flush
=
true
2151
end
2152 2153
if
flush
then
2154
if
stackhead
then
2155
if
trace_collect_vspacing
then
report
(
"
%s > appending %s nodes to stack (final): %s
"
,
where
,
newhead
)
end
2156
setlink
(
stacktail
,
newhead
)
2157
newhead
=
stackhead
2158
stackhead
=
nil
2159
stacktail
=
nil
2160
end
2161
if
stackhack
then
2162
stackhack
=
false
2163
if
trace_collect_vspacing
then
report
(
"
%s > processing %s nodes: %s
"
,
where
,
newhead
)
end
2164
newhead
=
collapser
(
newhead
,
"
page
"
,
where
,
trace_page_vspacing
,
true
,
a_snapmethod
)
2165
else
2166
if
trace_collect_vspacing
then
report
(
"
%s > flushing %s nodes: %s
"
,
where
,
newhead
)
end
2167
end
2168
return
newhead
2169
else
2170
if
stackhead
then
2171
if
trace_collect_vspacing
then
report
(
"
%s > appending %s nodes to stack (intermediate): %s
"
,
where
,
newhead
)
end
2172
setlink
(
stacktail
,
newhead
)
2173
else
2174
if
trace_collect_vspacing
then
report
(
"
%s > storing %s nodes in stack (initial): %s
"
,
where
,
newhead
)
end
2175
stackhead
=
newhead
2176
end
2177
stacktail
=
newtail
2178
end
2179
end
2180
return
nil
2181
end
2182 2183
function
vspacing
.
pageoverflow
(
)
2184
local
h
=
0
2185
if
stackhead
then
2186
for
n
,
id
in
nextnode
,
stackhead
do
2187
if
id
=
=
glue_code
then
2188
h
=
h
+
getwidth
(
n
)
2189
elseif
id
=
=
kern_code
then
2190
h
=
h
+
getkern
(
n
)
2191
end
2192
end
2193
end
2194
return
h
2195
end
2196 2197
function
vspacing
.
forcepageflush
(
)
2198
forceflush
=
true
2199
end
2200 2201
local
ignore
=
table
.
tohash
{
2202
"
split_keep
"
,
2203
"
split_off
"
,
2204
-- "vbox",
2205
}
2206 2207
function
vspacing
.
vboxhandler
(
head
,
where
)
2208
if
head
and
not
ignore
[
where
]
and
getnext
(
head
)
then
2209
if
getnext
(
head
)
then
-- what if a one liner and snapping?
2210
head
=
collapser
(
head
,
"
vbox
"
,
where
,
trace_vbox_vspacing
,
true
,
a_snapvbox
)
-- todo: local snapper
2211
return
head
2212
end
2213
end
2214
return
head
2215
end
2216 2217
function
vspacing
.
collapsevbox
(
n
,
aslist
)
-- for boxes but using global a_snapmethod
2218
local
box
=
getbox
(
n
)
2219
if
box
then
2220
local
list
=
getlist
(
box
)
2221
if
list
then
2222
list
=
collapser
(
list
,
"
snapper
"
,
"
vbox
"
,
trace_vbox_vspacing
,
true
,
a_snapmethod
)
2223
if
aslist
then
2224
setlist
(
box
,
list
)
-- beware, dimensions of box are wrong now
2225
else
2226
setlist
(
box
,
vpack_node
(
list
)
)
2227
end
2228
end
2229
end
2230
end
2231 2232
end
2233 2234
-- This one is needed to prevent bleeding of prevdepth to the next page
2235
-- which doesn't work well with forced skips. I'm not that sure if the
2236
-- following is a good way out.
2237 2238
do
2239 2240
local
outer
=
texnest
[
0
]
2241 2242
local
enabled
=
true
2243
local
trace
=
false
2244
local
report
=
logs
.
reporter
(
"
vspacing
"
)
2245 2246
trackers
.
register
(
"
vspacing.synchronizepage
"
,
function
(
v
)
2247
trace
=
v
2248
end
)
2249 2250
directives
.
register
(
"
vspacing.synchronizepage
"
,
function
(
v
)
2251
enabled
=
v
2252
end
)
2253 2254
local
ignoredepth
=
-65536000
2255 2256
-- A previous version analyzed the number of lines moved to the next page in
2257
-- synchronizepage because prevgraf is unreliable in that case. However, we cannot
2258
-- tweak that parameter because it is also used in postlinebreak and hangafter, so
2259
-- there is a danger for interference. Therefore we now do it dynamically.
2260 2261
-- We can also support other lists but there prevgraf probably is ok.
2262 2263
function
vspacing
.
getnofpreviouslines
(
head
)
2264
if
enabled
then
2265
if
not
thead
then
2266
head
=
texlists
.
page_head
2267
end
2268
local
noflines
=
0
2269
if
head
then
2270
local
tail
=
find_node_tail
(
tonut
(
head
)
)
2271
while
tail
do
2272
local
id
=
getid
(
tail
)
2273
if
id
=
=
hlist_code
then
2274
if
getsubtype
(
tail
)
=
=
linelist_code
then
2275
noflines
=
noflines
+
1
2276
else
2277
break
2278
end
2279
elseif
id
=
=
vlist_code
then
2280
break
2281
elseif
id
=
=
glue_code
then
2282
local
subtype
=
getsubtype
(
tail
)
2283
if
subtype
=
=
baselineskip_code
or
subtype
=
=
lineskip_code
then
2284
-- we're ok
2285
elseif
subtype
=
=
parskip_code
then
2286
if
getwidth
(
tail
)
>
0
then
2287
break
2288
else
2289
-- we assume we're ok
2290
end
2291
end
2292
elseif
id
=
=
penalty_code
then
2293
-- we're probably ok
2294
elseif
id
=
=
rule_code
or
id
=
=
kern_code
then
2295
break
2296
else
2297
-- ins, mark, boundary, whatsit
2298
end
2299
tail
=
getprev
(
tail
)
2300
end
2301
end
2302
return
noflines
2303
end
2304
end
2305 2306
interfaces
.
implement
{
2307
name
=
"
getnofpreviouslines
"
,
2308
public
=
true
,
2309
actions
=
vspacing
.
getnofpreviouslines
,
2310
}
2311 2312
function
vspacing
.
synchronizepage
(
)
2313
if
enabled
then
2314
if
trace
then
2315
local
newdepth
=
outer
.
prevdepth
2316
local
olddepth
=
newdepth
2317
if
not
texlists
.
page_head
then
2318
newdepth
=
ignoredepth
2319
texset
(
"
prevdepth
"
,
ignoredepth
)
2320
outer
.
prevdepth
=
ignoredepth
2321
end
2322
report
(
"
page %i, prevdepth %p => %p
"
,
texgetcount
(
"
realpageno
"
)
,
olddepth
,
newdepth
)
2323
-- report("list %s",nodes.idsandsubtypes(head))
2324
else
2325
if
not
texlists
.
page_head
then
2326
texset
(
"
prevdepth
"
,
ignoredepth
)
2327
outer
.
prevdepth
=
ignoredepth
2328
end
2329
end
2330
end
2331
end
2332 2333
local
trace
=
false
2334
-- local last = nil
2335
local
vmode_code
=
tex
.
modelevels
.
vertical
2336
local
temp_code
=
nodecodes
.
temp
2337
local
texgetnest
=
tex
.
getnest
2338
local
texgetlist
=
tex
.
getlist
2339
local
getnodetail
=
nodes
.
tail
2340 2341
-- trackers.register("vspacing.forcestrutdepth",function(v) trace = v end)
2342 2343
-- abs : negative is inner
2344 2345
function
vspacing
.
checkstrutdepth
(
depth
)
2346
local
nest
=
texgetnest
(
)
2347
if
abs
(
nest
.
mode
)
=
=
vmode_code
and
nest
.
head
then
2348
local
tail
=
nest
.
tail
2349
local
id
=
tail
.
id
2350
if
id
=
=
hlist_code
then
2351
if
tail
.
depth
<
depth
then
2352
tail
.
depth
=
depth
2353
end
2354
nest
.
prevdepth
=
depth
2355
elseif
id
=
=
temp_code
and
texgetnest
(
"
ptr
"
)
=
=
0
then
2356
local
head
=
texgetlist
(
"
page_head
"
)
2357
if
head
then
2358
tail
=
getnodetail
(
head
)
2359
if
tail
and
tail
.
id
=
=
hlist_code
then
2360
if
tail
.
depth
<
depth
then
2361
tail
.
depth
=
depth
2362
end
2363
nest
.
prevdepth
=
depth
2364
-- only works in lmtx
2365
texset
(
"
pagedepth
"
,
depth
)
2366
end
2367
end
2368
end
2369
end
2370
end
2371 2372
interfaces
.
implement
{
2373
name
=
"
checkstrutdepth
"
,
2374
arguments
=
"
dimension
"
,
2375
actions
=
vspacing
.
checkstrutdepth
,
2376
}
2377 2378
-- function vspacing.forcestrutdepth(n,depth,trace_mode,plus)
2379
-- local box = texgetbox(n)
2380
-- if box then
2381
-- box = tonut(box)
2382
-- local head = getlist(box)
2383
-- if head then
2384
-- local tail = find_node_tail(head)
2385
-- if tail then
2386
-- if getid(tail) == hlist_code then
2387
-- local dp = getdepth(tail)
2388
-- if dp < depth then
2389
-- setdepth(tail,depth)
2390
-- outer.prevdepth = depth
2391
-- if trace or trace_mode > 0 then
2392
-- nuts.setvisual(tail,"depth")
2393
-- end
2394
-- end
2395
-- end
2396
-- -- last = nil
2397
-- -- if plus then
2398
-- -- -- penalty / skip ...
2399
-- -- local height = 0
2400
-- -- local sofar = 0
2401
-- -- local same = false
2402
-- -- local seen = false
2403
-- -- local list = { }
2404
-- -- last = nil
2405
-- -- while tail do
2406
-- -- local id = getid(tail)
2407
-- -- if id == hlist_code or id == vlist_code then
2408
-- -- local w, h, d = getwhd(tail)
2409
-- -- height = height + h + d + sofar
2410
-- -- sofar = 0
2411
-- -- last = tail
2412
-- -- elseif id == kern_code then
2413
-- -- sofar = sofar + getkern(tail)
2414
-- -- elseif id == glue_code then
2415
-- -- if seen then
2416
-- -- sofar = sofar + getwidth(tail)
2417
-- -- seen = false
2418
-- -- else
2419
-- -- break
2420
-- -- end
2421
-- -- elseif id == penalty_code then
2422
-- -- local p = getpenalty(tail)
2423
-- -- if p >= 10000 then
2424
-- -- same = true
2425
-- -- seen = true
2426
-- -- else
2427
-- -- break
2428
-- -- end
2429
-- -- else
2430
-- -- break
2431
-- -- end
2432
-- -- tail = getprev(tail)
2433
-- -- end
2434
-- -- texsetdimen("global","d_spac_prevcontent",same and height or 0)
2435
-- -- end
2436
-- end
2437
-- end
2438
-- end
2439
-- end
2440 2441
local
hlist_code
=
nodes
.
nodecodes
.
hlist
2442
local
insert_code
=
nodes
.
nodecodes
.
insert
2443
local
mark_code
=
nodes
.
nodecodes
.
mark
2444
local
line_code
=
nodes
.
listcodes
.
line
2445 2446
local
nuts
=
nodes
.
nuts
2447
local
getid
=
nuts
.
getid
2448
local
getsubtype
=
nuts
.
getsubtype
2449
local
getdepth
=
nuts
.
getdepth
2450
local
setdepth
=
nuts
.
setdepth
2451
local
gettotal
=
nuts
.
gettotal
2452
local
getspeciallist
=
nuts
.
getspeciallist
2453
local
setspeciallist
=
nuts
.
setspeciallist
2454 2455
local
triggerbuildpage
=
tex
.
triggerbuildpage
2456 2457
local
texgetdimen
=
tex
.
getdimen
2458
local
texsetdimen
=
tex
.
setdimen
2459
local
texgetnest
=
tex
.
getnest
2460
local
texget
=
tex
.
get
2461
local
texset
=
tex
.
set
2462 2463
local
trace
=
false
trackers
.
register
(
"
otr.forcestrutdepth
"
,
function
(
v
)
2464
trace
=
v
and
function
(
n
)
2465
nuts
.
setvisual
(
nuts
.
tonut
(
n
)
,
nodes
.
visualizers
.
modes
.
depth
)
2466
end
2467
end
)
2468 2469
local
treversenode
=
nuts
.
treversers
.
node
2470 2471
function
vspacing
.
forcestrutdepth
(
)
2472
-- check if in mvl
2473
if
texgetnest
(
"
ptr
"
)
=
=
0
then
2474
-- this flushes the contributions
2475
while
getspeciallist
(
"
contribute_head
"
)
do
2476
triggerbuildpage
(
)
2477
end
2478
-- now we consult the last line (if present)
2479
local
head
,
tail
=
getspeciallist
(
"
page_head
"
)
2480
if
tail
then
2481
for
n
,
id
,
subtype
in
treversenode
,
tail
do
2482
if
id
=
=
hlist_code
then
2483
if
subtype
=
=
line_code
then
2484
local
strutdp
=
texgetdimen
(
"
strutdp
"
)
2485
local
delta
=
strutdp
-
getdepth
(
n
)
2486
if
delta
>
0
then
2487
setdepth
(
n
,
strutdp
)
2488
texset
(
"
pagetotal
"
,
texget
(
"
pagetotal
"
)
+
delta
)
2489
texset
(
"
pagedepth
"
,
strutdp
)
2490
if
trace
then
2491
trace
(
n
)
2492
end
2493
end
2494
end
2495
break
2496
elseif
id
=
=
insert_code
or
id
=
=
mark_code
then
2497
-- prev
2498
else
2499
break
2500
end
2501
end
2502
end
2503
else
2504
local
nest
=
texgetnest
(
)
2505
-- if abs(nest.mode) == vmode_code and nest.head then
2506
local
tail
=
nest
.
tail
2507
if
tail
.
id
=
=
hlist_code
and
tail
.
subtype
=
=
line_code
then
2508
local
strutdp
=
texgetdimen
(
"
strutdp
"
)
2509
if
tail
.
depth
<
strutdp
then
2510
tail
.
depth
=
strutdp
2511
end
2512
nest
.
prevdepth
=
strutdp
2513
if
trace
then
2514
trace
(
tail
)
2515
end
2516
end
2517
-- end
2518
end
2519
end
2520 2521
-- interfaces.implement {
2522
-- name = "removelastline",
2523
-- actions = function()
2524
-- local h, t = getspeciallist("page_head")
2525
-- if t and getid(t) == hlist_code and getsubtype(t) == line_code then
2526
-- local total = gettotal(t)
2527
-- h = remove_node(h,t,true)
2528
-- setspeciallist(h)
2529
-- texset("pagetotal",texget("pagetotal") - total)
2530
-- -- set prevdepth
2531
-- end
2532
-- end
2533
-- }
2534 2535
function
vspacing
.
pushatsame
(
)
2536
-- needs better checking !
2537
if
last
then
-- setsplit
2538
nuts
.
setnext
(
getprev
(
last
)
)
2539
nuts
.
setprev
(
last
)
2540
end
2541
end
2542 2543
function
vspacing
.
popatsame
(
)
2544
-- needs better checking !
2545
nuts
.
write
(
last
)
2546
end
2547 2548
end
2549 2550
-- interface
2551 2552
do
2553 2554
interfaces
.
implement
{
2555
name
=
"
injectvspacing
"
,
2556
actions
=
vspacing
.
inject
,
2557
arguments
=
{
"
integer
"
,
"
string
"
}
,
2558
}
2559 2560
interfaces
.
implement
{
2561
name
=
"
injectvpenalty
"
,
2562
actions
=
vspacing
.
injectpenalty
,
2563
arguments
=
"
integer
"
,
2564
}
2565 2566
interfaces
.
implement
{
2567
name
=
"
injectvskip
"
,
2568
actions
=
vspacing
.
injectskip
,
2569
arguments
=
"
dimension
"
,
2570
}
2571 2572
interfaces
.
implement
{
2573
name
=
"
injectdisable
"
,
2574
actions
=
vspacing
.
injectdisable
,
2575
}
2576 2577
--
2578 2579
implement
{
2580
name
=
"
synchronizepage
"
,
2581
actions
=
vspacing
.
synchronizepage
,
2582
scope
=
"
private
"
2583
}
2584 2585
-- implement {
2586
-- name = "forcestrutdepth",
2587
-- arguments = { "integer", "dimension", "integer" },
2588
-- actions = vspacing.forcestrutdepth,
2589
-- scope = "private"
2590
-- }
2591 2592
-- implement {
2593
-- name = "forcestrutdepthplus",
2594
-- arguments = { "integer", "dimension", "integer", true },
2595
-- actions = vspacing.forcestrutdepth,
2596
-- scope = "private"
2597
-- }
2598 2599
implement
{
2600
name
=
"
forcestrutdepth
"
,
2601
public
=
true
,
2602
protected
=
true
,
2603
actions
=
vspacing
.
forcestrutdepth
,
2604
}
2605 2606
implement
{
2607
name
=
"
pushatsame
"
,
2608
actions
=
vspacing
.
pushatsame
,
2609
scope
=
"
private
"
2610
}
2611 2612
implement
{
2613
name
=
"
popatsame
"
,
2614
actions
=
vspacing
.
popatsame
,
2615
scope
=
"
private
"
2616
}
2617 2618
implement
{
2619
name
=
"
vspacingsetamount
"
,
2620
actions
=
vspacing
.
setskip
,
2621
scope
=
"
private
"
,
2622
arguments
=
"
string
"
,
2623
}
2624 2625
implement
{
2626
name
=
"
vspacingdefine
"
,
2627
actions
=
vspacing
.
setmap
,
2628
scope
=
"
private
"
,
2629
arguments
=
"
2 strings
"
,
2630
}
2631 2632
implement
{
2633
name
=
"
vspacingcollapse
"
,
2634
actions
=
vspacing
.
collapsevbox
,
2635
scope
=
"
private
"
,
2636
arguments
=
"
integer
"
2637
}
2638 2639
implement
{
2640
name
=
"
vspacingcollapseonly
"
,
2641
actions
=
vspacing
.
collapsevbox
,
2642
scope
=
"
private
"
,
2643
arguments
=
{
"
integer
"
,
true
}
2644
}
2645 2646
implement
{
2647
name
=
"
vspacingsnap
"
,
2648
actions
=
vspacing
.
snapbox
,
2649
scope
=
"
private
"
,
2650
arguments
=
{
"
integer
"
,
"
integer
"
}
2651
}
2652 2653
implement
{
2654
name
=
"
definesnapmethod
"
,
2655
actions
=
vspacing
.
definesnapmethod
,
2656
scope
=
"
private
"
,
2657
arguments
=
"
2 strings
"
,
2658
}
2659 2660
-- local remove_node = nodes.remove
2661
-- local find_node_tail = nodes.tail
2662
--
2663
-- interfaces.implement {
2664
-- name = "fakenextstrutline",
2665
-- actions = function()
2666
-- local head = texlists.page_head
2667
-- if head then
2668
-- local head = remove_node(head,find_node_tail(head),true)
2669
-- texlists.page_head = head
2670
-- buildpage()
2671
-- end
2672
-- end
2673
-- }
2674 2675
implement
{
2676
name
=
"
removelastline
"
,
2677
actions
=
function
(
)
2678
local
head
=
texlists
.
page_head
2679
if
head
then
2680
local
tail
=
find_node_tail
(
head
)
2681
if
tail
then
2682
-- maybe check for hlist subtype 1
2683
local
head
=
remove_node
(
head
,
tail
,
true
)
2684
texlists
.
page_head
=
head
2685
buildpage
(
)
2686
end
2687
end
2688
end
2689
}
2690 2691
implement
{
2692
name
=
"
showpagelist
"
,
-- will improve
2693
actions
=
function
(
)
2694
local
head
=
texlists
.
page_head
2695
if
head
then
2696
print
(
"
start
"
)
2697
while
head
do
2698
print
(
"
"
.
.
tostring
(
head
)
)
2699
head
=
head
.
next
2700
end
2701
end
2702
end
2703
}
2704 2705
implement
{
2706
name
=
"
pageoverflow
"
,
2707
actions
=
{
vspacing
.
pageoverflow
,
context
}
2708
}
2709 2710
implement
{
2711
name
=
"
forcepageflush
"
,
2712
actions
=
vspacing
.
forcepageflush
2713
}
2714 2715
end
2716