trac-vis.lua /size: 53 Kb    last modification: 2020-07-01 14:35
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
trac-vis
'
]
=
{
2
version
=
1
.
001
,
3
comment
=
"
companion to trac-vis.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
local
node
,
nodes
,
attributes
,
tex
=
node
,
nodes
,
attributes
,
tex
10
local
type
,
tonumber
,
next
,
rawget
=
type
,
tonumber
,
next
,
rawget
11
local
gmatch
=
string
.
gmatch
12
local
formatters
=
string
.
formatters
13
local
round
=
math
.
round
14 15
-- This module started out in the early days of mkiv and luatex with visualizing
16
-- kerns related to fonts. In the process of cleaning up the visual debugger code it
17
-- made sense to integrate some other code that I had laying around and replace the
18
-- old supp-vis debugging code. As only a subset of the old visual debugger makes
19
-- sense it has become a different implementation. Soms of the m-visual
20
-- functionality will also be ported. The code is rather trivial. The caching is not
21
-- really needed but saves upto 50% of the time needed to add visualization. Of
22
-- course the overall runtime is larger because of color and layer processing in the
23
-- backend (can be times as much) so the runtime is somewhat larger with full
24
-- visualization enabled. In practice this will never happen unless one is demoing.
25 26
-- todo: global switch (so no attributes)
27
-- todo: maybe also xoffset, yoffset of glyph
28
-- todo: inline concat (more efficient)
29
-- todo: tags can also be numbers (just add to hash)
30 31
local
nodecodes
=
nodes
.
nodecodes
32 33
local
nuts
=
nodes
.
nuts
34
local
tonut
=
nuts
.
tonut
35
local
tonode
=
nuts
.
tonode
36 37
local
setboth
=
nuts
.
setboth
38
local
setlink
=
nuts
.
setlink
39
local
setdisc
=
nuts
.
setdisc
40
local
setlist
=
nuts
.
setlist
41
local
setleader
=
nuts
.
setleader
42
local
setsubtype
=
nuts
.
setsubtype
43
local
setattr
=
nuts
.
setattr
44
local
setwidth
=
nuts
.
setwidth
45
local
setshift
=
nuts
.
setshift
46 47
local
getid
=
nuts
.
getid
48
local
getfont
=
nuts
.
getfont
49
local
getattr
=
nuts
.
getattr
50
local
getsubtype
=
nuts
.
getsubtype
51
local
getbox
=
nuts
.
getbox
52
local
getlist
=
nuts
.
getlist
53
local
getleader
=
nuts
.
getleader
54
local
getnext
=
nuts
.
getnext
55
local
getprev
=
nuts
.
getprev
56
local
getboth
=
nuts
.
getboth
57
local
getdisc
=
nuts
.
getdisc
58
local
getwhd
=
nuts
.
getwhd
59
local
getkern
=
nuts
.
getkern
60
local
getpenalty
=
nuts
.
getpenalty
61
local
getwidth
=
nuts
.
getwidth
62
local
getdepth
=
nuts
.
getdepth
63
local
getshift
=
nuts
.
getshift
64
local
getexpansion
=
nuts
.
getexpansion
65 66
local
isglyph
=
nuts
.
isglyph
67 68
local
hpack_nodes
=
nuts
.
hpack
69
local
vpack_nodes
=
nuts
.
vpack
70
local
copy_list
=
nuts
.
copy_list
71
local
copy_node
=
nuts
.
copy_node
72
local
flush_node_list
=
nuts
.
flush_list
73
local
insert_node_before
=
nuts
.
insert_before
74
local
insert_node_after
=
nuts
.
insert_after
75
local
apply_to_nodes
=
nuts
.
apply
76
local
find_tail
=
nuts
.
tail
77
local
effectiveglue
=
nuts
.
effective_glue
78 79
local
nextnode
=
nuts
.
traversers
.
node
80 81
local
hpack_string
=
nuts
.
typesetters
.
tohpack
82 83
local
texgetattribute
=
tex
.
getattribute
84
local
texsetattribute
=
tex
.
setattribute
85 86
local
setmetatableindex
=
table
.
setmetatableindex
87 88
local
unsetvalue
=
attributes
.
unsetvalue
89 90
local
current_font
=
font
.
current
91 92
local
fonthashes
=
fonts
.
hashes
93
local
chardata
=
fonthashes
.
characters
94
local
exheights
=
fonthashes
.
exheights
95
local
emwidths
=
fonthashes
.
emwidths
96
local
pt_factor
=
number
.
dimenfactors
.
pt
97 98
local
nodepool
=
nuts
.
pool
99
local
new_rule
=
nodepool
.
rule
100
local
new_kern
=
nodepool
.
kern
101
local
new_glue
=
nodepool
.
glue
102
local
new_hlist
=
nodepool
.
hlist
103
local
new_vlist
=
nodepool
.
vlist
104 105
local
tracers
=
nodes
.
tracers
106
local
visualizers
=
nodes
.
visualizers
107 108
local
setcolor
=
tracers
.
colors
.
set
109
local
setlistcolor
=
tracers
.
colors
.
setlist
110
local
settransparency
=
tracers
.
transparencies
.
set
111
local
setlisttransparency
=
tracers
.
transparencies
.
setlist
112 113
local
starttiming
=
statistics
.
starttiming
114
local
stoptiming
=
statistics
.
stoptiming
115 116
local
a_visual
=
attributes
.
private
(
"
visual
"
)
117
local
a_layer
=
attributes
.
private
(
"
viewerlayer
"
)
118 119
local
band
=
bit32
.
band
120
local
bor
=
bit32
.
bor
121 122
local
enableaction
=
nodes
.
tasks
.
enableaction
123 124
-- local trace_hbox
125
-- local trace_vbox
126
-- local trace_vtop
127
-- local trace_kern
128
-- local trace_glue
129
-- local trace_penalty
130
-- local trace_fontkern
131
-- local trace_strut
132
-- local trace_whatsit
133
-- local trace_user
134
-- local trace_math
135
-- local trace_italic
136
-- local trace_discretionary
137
-- local trace_expansion
138
-- local trace_line
139
-- local trace_space
140 141
local
report_visualize
=
logs
.
reporter
(
"
visualize
"
)
142 143
local
modes
=
{
144
hbox
=
0x000001
,
145
vbox
=
0x000002
,
146
vtop
=
0x000004
,
147
kern
=
0x000008
,
148
glue
=
0x000010
,
149
penalty
=
0x000020
,
150
fontkern
=
0x000040
,
151
strut
=
0x000080
,
152
whatsit
=
0x000100
,
153
glyph
=
0x000200
,
154
simple
=
0x000400
,
155
simplehbox
=
0x000401
,
156
simplevbox
=
0x000402
,
157
simplevtop
=
0x000404
,
158
user
=
0x000800
,
159
math
=
0x001000
,
160
italic
=
0x002000
,
161
origin
=
0x004000
,
162
discretionary
=
0x008000
,
163
expansion
=
0x010000
,
164
line
=
0x020000
,
165
space
=
0x040000
,
166
depth
=
0x080000
,
167
marginkern
=
0x100000
,
168
mathlistkern
=
0x200000
,
169
}
170 171
local
usedfont
,
exheight
,
emwidth
172
local
l_penalty
,
l_glue
,
l_kern
,
l_fontkern
,
l_hbox
,
l_vbox
,
l_vtop
,
l_strut
,
l_whatsit
,
l_glyph
,
l_user
,
l_math
,
l_marginkern
,
l_mathlistkern
,
l_italic
,
l_origin
,
l_discretionary
,
l_expansion
,
l_line
,
l_space
,
l_depth
173 174
local
enabled
=
false
175
local
layers
=
{
}
176 177
local
preset_boxes
=
modes
.
hbox
+
modes
.
vbox
+
modes
.
origin
178
local
preset_makeup
=
preset_boxes
179
+
modes
.
kern
+
modes
.
glue
+
modes
.
penalty
180
local
preset_all
=
preset_makeup
181
+
modes
.
fontkern
+
modes
.
marginkern
+
modes
.
mathlistkern
182
+
modes
.
whatsit
+
modes
.
glyph
+
modes
.
user
+
modes
.
math
183 184
function
visualizers
.
setfont
(
id
)
185
usedfont
=
id
or
current_font
(
)
186
exheight
=
exheights
[
usedfont
]
187
emwidth
=
emwidths
[
usedfont
]
188
end
189 190
-- we can preset a bunch of bits
191 192
local
userrule
-- bah, not yet defined: todo, delayed(nuts.rules,"userrule")
193
local
outlinerule
-- bah, not yet defined: todo, delayed(nuts.rules,"userrule")
194 195
local
function
initialize
(
)
196
--
197
if
not
usedfont
then
198
-- we use a narrow monospaced font -- infofont ?
199
visualizers
.
setfont
(
fonts
.
definers
.
define
{
name
=
"
lmmonoltcond10regular
"
,
size
=
tex
.
sp
(
"
4pt
"
)
}
)
200
end
201
--
202
for
mode
,
value
in
next
,
modes
do
203
local
tag
=
formatters
[
"
v_%s
"
]
(
mode
)
204
attributes
.
viewerlayers
.
define
{
205
tag
=
tag
,
206
title
=
formatters
[
"
visualizer %s
"
]
(
mode
)
,
207
visible
=
"
start
"
,
208
editable
=
"
yes
"
,
209
printable
=
"
yes
"
210
}
211
layers
[
mode
]
=
attributes
.
viewerlayers
.
register
(
tag
,
true
)
212
end
213
l_hbox
=
layers
.
hbox
214
l_vbox
=
layers
.
vbox
215
l_vtop
=
layers
.
vtop
216
l_glue
=
layers
.
glue
217
l_kern
=
layers
.
kern
218
l_penalty
=
layers
.
penalty
219
l_fontkern
=
layers
.
fontkern
220
l_strut
=
layers
.
strut
221
l_whatsit
=
layers
.
whatsit
222
l_glyph
=
layers
.
glyph
223
l_user
=
layers
.
user
224
l_math
=
layers
.
math
225
l_italic
=
layers
.
italic
226
l_marginkern
=
layers
.
marginkern
227
l_mathlistkern
=
layers
.
mathlistkern
228
l_origin
=
layers
.
origin
229
l_discretionary
=
layers
.
discretionary
230
l_expansion
=
layers
.
expansion
231
l_line
=
layers
.
line
232
l_space
=
layers
.
space
233
l_depth
=
layers
.
depth
234
--
235
if
not
userrule
then
236
userrule
=
nuts
.
rules
.
userrule
237
end
238
--
239
if
not
outlinerule
then
240
outlinerule
=
nuts
.
pool
.
outlinerule
241
end
242
initialize
=
false
243
end
244 245
local
function
enable
(
)
246
if
initialize
then
247
initialize
(
)
248
end
249
enableaction
(
"
shipouts
"
,
"
nodes.visualizers.handler
"
)
250
report_visualize
(
"
enabled
"
)
251
enabled
=
true
252
tex
.
setcount
(
"
global
"
,
"
c_syst_visualizers_state
"
,
1
)
-- so that we can optimize at the tex end
253
end
254 255
local
function
setvisual
(
n
,
a
,
what
,
list
)
-- this will become more efficient when we have the bit lib linked in
256
if
not
n
or
n
=
=
"
reset
"
then
257
return
unsetvalue
258
elseif
n
=
=
true
or
n
=
=
"
makeup
"
then
259
if
not
a
or
a
=
=
0
or
a
=
=
unsetvalue
then
260
a
=
preset_makeup
261
else
262
a
=
bor
(
a
,
preset_makeup
)
263
end
264
elseif
n
=
=
"
boxes
"
then
265
if
not
a
or
a
=
=
0
or
a
=
=
unsetvalue
then
266
a
=
preset_boxes
267
else
268
a
=
bor
(
a
,
preset_boxes
)
269
end
270
elseif
n
=
=
"
all
"
then
271
if
what
=
=
false
then
272
return
unsetvalue
273
elseif
not
a
or
a
=
=
0
or
a
=
=
unsetvalue
then
274
a
=
preset_all
275
else
276
a
=
bor
(
a
,
preset_all
)
277
end
278
else
279
for
s
in
gmatch
(
n
,
"
[a-z]+
"
)
do
280
local
m
=
modes
[
s
]
281
if
not
m
then
282
-- go on
283
elseif
not
a
or
a
=
=
0
or
a
=
=
unsetvalue
then
284
a
=
m
285
else
286
a
=
bor
(
a
,
m
)
287
end
288
end
289
end
290
if
not
a
or
a
=
=
0
or
a
=
=
unsetvalue
then
291
return
unsetvalue
292
elseif
not
enabled
then
-- must happen at runtime (as we don't store layers yet)
293
enable
(
)
294
end
295
return
a
296
end
297 298
function
nuts
.
setvisual
(
n
,
mode
)
299
setattr
(
n
,
a_visual
,
setvisual
(
mode
,
getattr
(
n
,
a_visual
)
,
true
)
)
300
end
301 302
function
nuts
.
setvisuals
(
n
,
mode
)
-- currently the same
303
setattr
(
n
,
a_visual
,
setvisual
(
mode
,
getattr
(
n
,
a_visual
)
,
true
,
true
)
)
304
end
305 306
-- fast setters
307 308
do
309 310
local
cached
=
setmetatableindex
(
function
(
t
,
k
)
311
if
k
=
=
true
then
312
return
texgetattribute
(
a_visual
)
313
elseif
not
k
then
314
t
[
k
]
=
unsetvalue
315
return
unsetvalue
316
else
317
local
v
=
setvisual
(
k
)
318
t
[
k
]
=
v
319
return
v
320
end
321
end
)
322 323
-- local function applyvisuals(n,mode)
324
-- local a = cached[mode]
325
-- apply_to_nodes(n,function(n) setattr(n,a_visual,a) end)
326
-- end
327 328
local
a
=
unsetvalue
329 330
local
f
=
function
(
n
)
setattr
(
n
,
a_visual
,
a
)
end
331 332
local
function
applyvisuals
(
n
,
mode
)
333
a
=
cached
[
mode
]
334
apply_to_nodes
(
n
,
f
)
335
end
336 337
nuts
.
applyvisuals
=
applyvisuals
338 339
function
nodes
.
applyvisuals
(
n
,
mode
)
340
applyvisuals
(
tonut
(
n
)
,
mode
)
341
end
342 343
function
visualizers
.
attribute
(
mode
)
344
return
cached
[
mode
]
345
end
346 347
visualizers
.
attributes
=
cached
348 349
end
350 351
function
nuts
.
copyvisual
(
n
,
m
)
352
setattr
(
n
,
a_visual
,
getattr
(
m
,
a_visual
)
)
353
end
354 355
function
visualizers
.
setvisual
(
n
)
356
texsetattribute
(
a_visual
,
setvisual
(
n
,
texgetattribute
(
a_visual
)
)
)
357
end
358 359
function
visualizers
.
setlayer
(
n
)
360
texsetattribute
(
a_layer
,
layers
[
n
]
or
unsetvalue
)
361
end
362 363
local
function
set
(
mode
,
v
)
364
texsetattribute
(
a_visual
,
setvisual
(
mode
,
texgetattribute
(
a_visual
)
,
v
)
)
365
end
366 367
for
mode
,
value
in
next
,
modes
do
368
trackers
.
register
(
formatters
[
"
visualizers.%s
"
]
(
mode
)
,
function
(
v
)
set
(
mode
,
v
)
end
)
369
end
370 371
local
fraction
=
10
372 373
trackers
.
register
(
"
visualizers.reset
"
,
function
(
v
)
set
(
"
reset
"
,
v
)
end
)
374
trackers
.
register
(
"
visualizers.all
"
,
function
(
v
)
set
(
"
all
"
,
v
)
end
)
375
trackers
.
register
(
"
visualizers.makeup
"
,
function
(
v
)
set
(
"
makeup
"
,
v
)
end
)
376
trackers
.
register
(
"
visualizers.boxes
"
,
function
(
v
)
set
(
"
boxes
"
,
v
)
end
)
377
directives
.
register
(
"
visualizers.fraction
"
,
function
(
v
)
fraction
=
(
v
and
tonumber
(
v
)
)
or
(
v
=
=
"
more
"
and
5
)
or
10
end
)
378 379
local
c_positive
=
"
trace:b
"
380
local
c_negative
=
"
trace:r
"
381
local
c_zero
=
"
trace:g
"
382
local
c_text
=
"
trace:s
"
383
local
c_space
=
"
trace:y
"
384
local
c_space_x
=
"
trace:m
"
385
local
c_skip_a
=
"
trace:c
"
386
local
c_skip_b
=
"
trace:m
"
387
local
c_glyph
=
"
trace:o
"
388
local
c_ligature
=
"
trace:s
"
389
local
c_white
=
"
trace:w
"
390
local
c_math
=
"
trace:s
"
391
local
c_origin
=
"
trace:o
"
392
local
c_discretionary
=
"
trace:d
"
393
local
c_expansion
=
"
trace:o
"
394
local
c_depth
=
"
trace:o
"
395
local
c_indent
=
"
trace:s
"
396 397
local
c_positive_d
=
"
trace:db
"
398
local
c_negative_d
=
"
trace:dr
"
399
local
c_zero_d
=
"
trace:dg
"
400
local
c_text_d
=
"
trace:ds
"
401
local
c_space_d
=
"
trace:dy
"
402
local
c_space_x_d
=
"
trace:dm
"
403
local
c_skip_a_d
=
"
trace:dc
"
404
local
c_skip_b_d
=
"
trace:dm
"
405
local
c_glyph_d
=
"
trace:do
"
406
local
c_ligature_d
=
"
trace:ds
"
407
local
c_white_d
=
"
trace:dw
"
408
local
c_math_d
=
"
trace:dr
"
409
local
c_origin_d
=
"
trace:do
"
410
local
c_discretionary_d
=
"
trace:dd
"
411
local
c_expansion_d
=
"
trace:do
"
412
local
c_depth_d
=
"
trace:do
"
413 414
local
function
sometext
(
str
,
layer
,
color
,
textcolor
,
lap
)
-- we can just paste verbatim together .. no typesteting needed
415
local
text
=
hpack_string
(
str
,
usedfont
)
416
local
size
=
getwidth
(
text
)
417
local
rule
=
new_rule
(
size
,
2
*
exheight
,
exheight
/
2
)
418
local
kern
=
new_kern
(
-
size
)
419
if
color
then
420
setcolor
(
rule
,
color
)
421
end
422
if
textcolor
then
423
setlistcolor
(
getlist
(
text
)
,
textcolor
)
424
end
425
local
info
=
setlink
(
rule
,
kern
,
text
)
426
setlisttransparency
(
info
,
c_zero
)
427
info
=
hpack_nodes
(
info
)
428
local
width
=
getwidth
(
info
)
429
if
lap
then
430
info
=
new_hlist
(
setlink
(
new_kern
(
-
width
)
,
info
)
)
431
else
432
info
=
new_hlist
(
info
)
-- a bit overkill: double wrapped
433
end
434
if
layer
then
435
setattr
(
info
,
a_layer
,
layer
)
436
end
437
return
info
,
width
438
end
439 440
local
function
someblob
(
str
,
layer
,
color
,
textcolor
,
width
)
441
local
text
=
hpack_string
(
str
,
usedfont
)
442
local
size
=
getwidth
(
text
)
443
local
rule
=
new_rule
(
width
,
2
*
exheight
,
exheight
/
2
)
444
local
kern
=
new_kern
(
-
width
+
(
width
-
size
)
/
2
)
445
if
color
then
446
setcolor
(
rule
,
color
)
447
end
448
if
textcolor
then
449
setlistcolor
(
getlist
(
text
)
,
textcolor
)
450
end
451
local
info
=
setlink
(
rule
,
kern
,
text
)
452
setlisttransparency
(
info
,
c_zero
)
453
info
=
hpack_nodes
(
info
)
454
local
width
=
getwidth
(
info
)
455
info
=
new_hlist
(
info
)
456
if
layer
then
457
setattr
(
info
,
a_layer
,
layer
)
458
end
459
return
info
,
width
460
end
461 462
local
caches
=
setmetatableindex
(
"
table
"
)
463 464
local
fontkern
,
italickern
,
marginkern
,
mathlistkern
do
465 466
local
f_cache
=
caches
[
"
fontkern
"
]
467
local
i_cache
=
caches
[
"
italickern
"
]
468
local
m_cache
=
caches
[
"
marginkern
"
]
469
local
l_cache
=
caches
[
"
mathlistkern
"
]
470 471
local
function
somekern
(
head
,
current
,
cache
,
color
,
layer
)
472
local
width
=
getkern
(
current
)
473
local
extra
=
getexpansion
(
current
)
474
local
kern
=
width
+
extra
475
local
info
=
cache
[
kern
]
476
if
not
info
then
477
local
text
=
hpack_string
(
formatters
[
"
%0.3f
"
]
(
kern
*
pt_factor
)
,
usedfont
)
478
local
rule
=
new_rule
(
emwidth
/
fraction
,
6
*
exheight
,
2
*
exheight
)
479
local
list
=
getlist
(
text
)
480
if
kern
>
0
then
481
setlistcolor
(
list
,
c_positive_d
)
482
elseif
kern
<
0
then
483
setlistcolor
(
list
,
c_negative_d
)
484
else
485
setlistcolor
(
list
,
c_zero_d
)
486
end
487
setlisttransparency
(
list
,
color
)
488
setcolor
(
rule
,
color
)
489
settransparency
(
rule
,
color
)
490
setshift
(
text
,
-5
*
exheight
)
491
info
=
new_hlist
(
setlink
(
rule
,
text
)
)
492
setattr
(
info
,
a_layer
,
layer
)
493
f_cache
[
kern
]
=
info
494
end
495
head
=
insert_node_before
(
head
,
current
,
copy_list
(
info
)
)
496
return
head
,
current
497
end
498 499
fontkern
=
function
(
head
,
current
)
500
return
somekern
(
head
,
current
,
f_cache
,
c_text_d
,
l_fontkern
)
501
end
502 503
italickern
=
function
(
head
,
current
)
504
return
somekern
(
head
,
current
,
i_cache
,
c_glyph_d
,
l_italic
)
505
end
506 507
marginkern
=
function
(
head
,
current
)
508
return
somekern
(
head
,
current
,
m_cache
,
c_glyph_d
,
l_marginkern
)
509
end
510 511
mathlistkern
=
function
(
head
,
current
)
512
return
somekern
(
head
,
current
,
l_cache
,
c_glyph_d
,
l_mathlistkern
)
513
end
514 515
end
516 517
local
glyphexpansion
do
518 519
local
f_cache
=
caches
[
"
glyphexpansion
"
]
520 521
glyphexpansion
=
function
(
head
,
current
)
522
local
extra
=
getexpansion
(
current
)
523
if
extra
and
extra
~
=
0
then
524
extra
=
extra
/
1000
525
local
info
=
f_cache
[
extra
]
526
if
not
info
then
527
local
text
=
hpack_string
(
round
(
extra
)
,
usedfont
)
528
local
rule
=
new_rule
(
emwidth
/
fraction
,
exheight
,
2
*
exheight
)
529
local
list
=
getlist
(
text
)
530
if
extra
>
0
then
531
setlistcolor
(
list
,
c_positive_d
)
532
elseif
extra
<
0
then
533
setlistcolor
(
list
,
c_negative_d
)
534
end
535
setlisttransparency
(
list
,
c_text_d
)
536
setcolor
(
rule
,
c_text_d
)
537
settransparency
(
rule
,
c_text_d
)
538
setshift
(
text
,
1
.
5
*
exheight
)
539
info
=
new_hlist
(
setlink
(
rule
,
text
)
)
540
setattr
(
info
,
a_layer
,
l_expansion
)
541
f_cache
[
extra
]
=
info
542
end
543
head
=
insert_node_before
(
head
,
current
,
copy_list
(
info
)
)
544
return
head
,
current
545
end
546
return
head
,
current
547
end
548 549
end
550 551
local
kernexpansion
do
552 553
local
f_cache
=
caches
[
"
kernexpansion
"
]
554 555
kernexpansion
=
function
(
head
,
current
)
556
local
extra
=
getexpansion
(
current
)
557
if
extra
~
=
0
then
558
extra
=
extra
/
1000
559
local
info
=
f_cache
[
extra
]
560
if
not
info
then
561
local
text
=
hpack_string
(
round
(
extra
)
,
usedfont
)
562
local
rule
=
new_rule
(
emwidth
/
fraction
,
exheight
,
4
*
exheight
)
563
local
list
=
getlist
(
text
)
564
if
extra
>
0
then
565
setlistcolor
(
list
,
c_positive_d
)
566
elseif
extra
<
0
then
567
setlistcolor
(
list
,
c_negative_d
)
568
end
569
setlisttransparency
(
list
,
c_text_d
)
570
setcolor
(
rule
,
c_text_d
)
571
settransparency
(
rule
,
c_text_d
)
572
setshift
(
text
,
3
.
5
*
exheight
)
573
info
=
new_hlist
(
setlink
(
rule
,
text
)
)
574
setattr
(
info
,
a_layer
,
l_expansion
)
575
f_cache
[
extra
]
=
info
576
end
577
head
=
insert_node_before
(
head
,
current
,
copy_list
(
info
)
)
578
return
head
,
current
579
end
580
return
head
,
current
581
end
582 583
end
584 585
local
whatsit
do
586 587
local
whatsitcodes
=
nodes
.
whatsitcodes
588
local
w_cache
=
caches
[
"
whatsit
"
]
589 590
local
tags
=
{
591
open
=
"
OPN
"
,
592
write
=
"
WRI
"
,
593
close
=
"
CLS
"
,
594
special
=
"
SPE
"
,
595
latelua
=
"
LUA
"
,
596
savepos
=
"
POS
"
,
597
userdefined
=
"
USR
"
,
598
literal
=
"
LIT
"
,
599
setmatrix
=
"
MAT
"
,
600
save
=
"
SAV
"
,
601
restore
=
"
RES
"
,
602
}
603 604
whatsit
=
function
(
head
,
current
)
605
local
what
=
getsubtype
(
current
)
606
local
info
=
w_cache
[
what
]
607
if
info
then
608
-- print("hit whatsit")
609
else
610
local
tag
=
whatsitcodes
[
what
]
611
-- maybe different text colors per tag
612
info
=
sometext
(
formatters
[
"
W:%s
"
]
(
tag
and
tags
[
tag
]
or
what
)
,
usedfont
,
nil
,
c_white
)
613
setattr
(
info
,
a_layer
,
l_whatsit
)
614
w_cache
[
what
]
=
info
615
end
616
head
,
current
=
insert_node_after
(
head
,
current
,
copy_list
(
info
)
)
617
return
head
,
current
618
end
619 620
end
621 622
local
user
do
623 624
local
u_cache
=
caches
[
"
user
"
]
625 626
user
=
function
(
head
,
current
)
627
local
what
=
getsubtype
(
current
)
628
local
info
=
u_cache
[
what
]
629
if
info
then
630
-- print("hit user")
631
else
632
info
=
sometext
(
formatters
[
"
U:%s
"
]
(
what
)
,
usedfont
)
633
setattr
(
info
,
a_layer
,
l_user
)
634
u_cache
[
what
]
=
info
635
end
636
head
,
current
=
insert_node_after
(
head
,
current
,
copy_list
(
info
)
)
637
return
head
,
current
638
end
639 640
end
641 642
local
math
do
643 644
local
mathcodes
=
nodes
.
mathcodes
645
local
m_cache
=
{
646
beginmath
=
caches
[
"
bmath
"
]
,
647
endmath
=
caches
[
"
emath
"
]
,
648
}
649
local
tags
=
{
650
beginmath
=
"
B
"
,
651
endmath
=
"
E
"
,
652
}
653 654
math
=
function
(
head
,
current
)
655
local
what
=
getsubtype
(
current
)
656
local
tag
=
mathcodes
[
what
]
657
local
skip
=
getkern
(
current
)
+
getwidth
(
current
)
-- surround
658
local
info
=
m_cache
[
tag
]
[
skip
]
659
if
info
then
660
-- print("hit math")
661
else
662
local
text
,
width
=
sometext
(
formatters
[
"
M:%s
"
]
(
tag
and
tags
[
tag
]
or
what
)
,
usedfont
,
nil
,
c_math_d
)
663
local
rule
=
new_rule
(
skip
,
-655360
/
fraction
,
2
*
655360
/
fraction
)
664
setcolor
(
rule
,
c_math_d
)
665
settransparency
(
rule
,
c_math_d
)
666
setattr
(
rule
,
a_layer
,
l_math
)
667
if
tag
=
=
"
beginmath
"
then
668
info
=
new_hlist
(
setlink
(
new_glue
(
-
skip
)
,
rule
,
new_glue
(
-
width
)
,
text
)
)
669
else
670
info
=
new_hlist
(
setlink
(
new_glue
(
-
skip
)
,
rule
,
new_glue
(
-
skip
)
,
text
)
)
671
end
672
setattr
(
info
,
a_layer
,
l_math
)
673
m_cache
[
tag
]
[
skip
]
=
info
674
end
675
head
,
current
=
insert_node_after
(
head
,
current
,
copy_list
(
info
)
)
676
return
head
,
current
677
end
678 679
end
680 681
local
ruleddepth
do
682 683
ruleddepth
=
function
(
current
,
wd
,
ht
,
dp
)
684
local
wd
,
ht
,
dp
=
getwhd
(
current
)
685
if
dp
~
=
0
then
686
local
rule
=
new_rule
(
wd
,
0
,
dp
)
687
setcolor
(
rule
,
c_depth
)
688
settransparency
(
rule
,
c_zero
)
689
setattr
(
rule
,
a_layer
,
l_depth
)
690
setlist
(
current
,
setlink
(
rule
,
new_kern
(
-
wd
)
,
getlist
(
current
)
)
)
691
end
692
end
693 694
end
695 696
local
ruledbox
do
697 698
local
b_cache
=
caches
[
"
box
"
]
699
local
o_cache
=
caches
[
"
origin
"
]
700 701
setmetatableindex
(
o_cache
,
function
(
t
,
size
)
702
local
rule
=
new_rule
(
2
*
size
,
size
,
size
)
703
local
origin
=
hpack_nodes
(
rule
)
704
setcolor
(
rule
,
c_origin_d
)
705
settransparency
(
rule
,
c_origin_d
)
706
setattr
(
rule
,
a_layer
,
l_origin
)
707
t
[
size
]
=
origin
708
return
origin
709
end
)
710 711
ruledbox
=
function
(
head
,
current
,
vertical
,
layer
,
what
,
simple
,
previous
,
trace_origin
,
parent
)
712
local
wd
,
ht
,
dp
=
getwhd
(
current
)
713
if
wd
~
=
0
then
714
local
shift
=
getshift
(
current
)
715
local
next
=
getnext
(
current
)
716
local
prev
=
previous
717
setboth
(
current
)
718
local
linewidth
=
emwidth
/
fraction
719
local
size
=
2
*
linewidth
720
local
this
721
if
not
simple
then
722
this
=
b_cache
[
what
]
723
if
not
this
then
724
local
text
=
hpack_string
(
what
,
usedfont
)
725
this
=
setlink
(
new_kern
(
-
getwidth
(
text
)
)
,
text
)
726
setlisttransparency
(
this
,
c_text
)
727
this
=
new_hlist
(
this
)
728
b_cache
[
what
]
=
this
729
end
730
end
731
-- we need to trigger the right mode (else sometimes no whatits)
732
local
info
=
setlink
(
733
this
and
copy_list
(
this
)
or
nil
,
734
(
dp
=
=
0
and
outlinerule
and
outlinerule
(
wd
,
ht
,
dp
,
linewidth
)
)
or
userrule
{
735
width
=
wd
,
736
height
=
ht
,
737
depth
=
dp
,
738
line
=
linewidth
,
739
type
=
"
box
"
,
740
dashed
=
3
*
size
,
741
}
742
)
743
--
744
setlisttransparency
(
info
,
c_text
)
745
info
=
new_hlist
(
info
)
-- important
746
--
747
setattr
(
info
,
a_layer
,
layer
)
748
if
vertical
then
749
if
shift
=
=
0
then
750
info
=
setlink
(
current
,
dp
~
=
0
and
new_kern
(
-
dp
)
or
nil
,
info
)
751
elseif
trace_origin
then
752
local
size
=
2
*
size
753
local
origin
=
o_cache
[
size
]
754
origin
=
copy_list
(
origin
)
755
if
getid
(
parent
)
=
=
vlist_code
then
756
setshift
(
origin
,
-
shift
)
757
info
=
setlink
(
current
,
new_kern
(
-
size
)
,
origin
,
new_kern
(
-
size
-
dp
)
,
info
)
758
else
759
-- todo .. i need an example
760
info
=
setlink
(
current
,
dp
~
=
0
and
new_kern
(
-
dp
)
or
nil
,
info
)
761
end
762
setshift
(
current
,
0
)
763
else
764
info
=
setlink
(
current
,
new_dp
~
=
0
and
new_kern
(
-
dp
)
or
nil
,
info
)
765
setshift
(
current
,
0
)
766
end
767
info
=
new_vlist
(
info
,
wd
,
ht
,
dp
,
shift
)
768
else
769
if
shift
=
=
0
then
770
info
=
setlink
(
current
,
new_kern
(
-
wd
)
,
info
)
771
elseif
trace_origin
then
772
local
size
=
2
*
size
773
local
origin
=
o_cache
[
size
]
774
origin
=
copy_list
(
origin
)
775
if
getid
(
parent
)
=
=
vlist_code
then
776
info
=
setlink
(
current
,
new_kern
(
-
wd
-
size
-
shift
)
,
origin
,
new_kern
(
-
size
+
shift
)
,
info
)
777
else
778
setshift
(
origin
,
-
shift
)
779
info
=
setlink
(
current
,
new_kern
(
-
wd
-
size
)
,
origin
,
new_kern
(
-
size
)
,
info
)
780
end
781
setshift
(
current
,
0
)
782
else
783
info
=
setlink
(
current
,
new_kern
(
-
wd
)
,
info
)
784
setshift
(
current
,
0
)
785
end
786
info
=
new_hlist
(
info
,
wd
,
ht
,
dp
,
shift
)
787
end
788
if
next
then
789
setlink
(
info
,
next
)
790
end
791
if
prev
and
prev
>
0
then
792
setlink
(
prev
,
info
)
793
end
794
if
head
=
=
current
then
795
return
info
,
info
796
else
797
return
head
,
info
798
end
799
else
800
return
head
,
current
801
end
802
end
803 804
end
805 806
local
ruledglyph
do
807 808
-- see boundingbox feature .. maybe a pdf stream is more efficient, after all we
809
-- have a frozen color anyway or i need a more detailed cache .. below is a more
810
-- texie approach
811 812
ruledglyph
=
function
(
head
,
current
,
previous
)
-- wrong for vertical glyphs
813
local
wd
=
getwidth
(
current
)
814
if
wd
~
=
0
then
815
local
wd
,
ht
,
dp
=
getwhd
(
current
)
816
local
next
=
getnext
(
current
)
817
local
prev
=
previous
818
setboth
(
current
)
819
local
linewidth
=
emwidth
/
(
2
*
fraction
)
820
local
info
821
--
822
info
=
setlink
(
823
(
dp
=
=
0
and
outlinerule
and
outlinerule
(
wd
,
ht
,
dp
,
linewidth
)
)
or
userrule
{
824
width
=
wd
,
825
height
=
ht
,
826
depth
=
dp
,
827
line
=
linewidth
,
828
type
=
"
box
"
,
829
}
,
830
new_kern
(
-
wd
)
831
)
832
--
833
local
c
,
f
=
isglyph
(
current
)
834
local
char
=
chardata
[
f
]
[
c
]
835
if
char
and
type
(
char
.
unicode
)
=
=
"
table
"
then
-- hackery test
836
setlistcolor
(
info
,
c_ligature
)
837
setlisttransparency
(
info
,
c_ligature_d
)
838
else
839
setlistcolor
(
info
,
c_glyph
)
840
setlisttransparency
(
info
,
c_glyph_d
)
841
end
842
info
=
new_hlist
(
info
)
843
setattr
(
info
,
a_layer
,
l_glyph
)
844
local
info
=
setlink
(
current
,
new_kern
(
-
wd
)
,
info
)
845
info
=
hpack_nodes
(
info
)
846
setwidth
(
info
,
wd
)
847
if
next
then
848
setlink
(
info
,
next
)
849
end
850
if
prev
then
851
setlink
(
prev
,
info
)
852
end
853
if
head
=
=
current
then
854
return
info
,
info
855
else
856
return
head
,
info
857
end
858
else
859
return
head
,
current
860
end
861
end
862 863
function
visualizers
.
setruledglyph
(
f
)
864
ruledglyph
=
f
or
ruledglyph
865
end
866 867
end
868 869
local
ruledglue
do
870 871
local
gluecodes
=
nodes
.
gluecodes
872
local
leadercodes
=
nodes
.
gluecodes
873 874
local
userskip_code
=
gluecodes
.
userskip
875
local
spaceskip_code
=
gluecodes
.
spaceskip
876
local
xspaceskip_code
=
gluecodes
.
xspaceskip
877
local
zerospaceskip_code
=
gluecodes
.
zerospaceskip
or
gluecodes
.
userskip
878
local
leftskip_code
=
gluecodes
.
leftskip
879
local
rightskip_code
=
gluecodes
.
rightskip
880
local
parfillskip_code
=
gluecodes
.
parfillskip
881
local
indentskip_code
=
gluecodes
.
indentskip
882
local
correctionskip_code
=
gluecodes
.
correctionskip
883 884
local
cleaders_code
=
leadercodes
.
cleaders
885 886
local
g_cache_v
=
caches
[
"
vglue
"
]
887
local
g_cache_h
=
caches
[
"
hglue
"
]
888 889
local
tags
=
{
890
-- [userskip_code] = "US",
891
[
gluecodes
.
lineskip
]
=
"
LS
"
,
892
[
gluecodes
.
baselineskip
]
=
"
BS
"
,
893
[
gluecodes
.
parskip
]
=
"
PS
"
,
894
[
gluecodes
.
abovedisplayskip
]
=
"
DA
"
,
895
[
gluecodes
.
belowdisplayskip
]
=
"
DB
"
,
896
[
gluecodes
.
abovedisplayshortskip
]
=
"
SA
"
,
897
[
gluecodes
.
belowdisplayshortskip
]
=
"
SB
"
,
898
[
gluecodes
.
topskip
]
=
"
TS
"
,
899
[
gluecodes
.
splittopskip
]
=
"
ST
"
,
900
[
gluecodes
.
tabskip
]
=
"
AS
"
,
901
[
gluecodes
.
lefthangskip
]
=
"
LH
"
,
902
[
gluecodes
.
righthangskip
]
=
"
RH
"
,
903
[
gluecodes
.
thinmuskip
]
=
"
MS
"
,
904
[
gluecodes
.
medmuskip
]
=
"
MM
"
,
905
[
gluecodes
.
thickmuskip
]
=
"
ML
"
,
906
[
gluecodes
.
intermathskip
]
=
"
IM
"
,
907
[
gluecodes
.
mathskip
]
=
"
MT
"
,
908
[
leadercodes
.
leaders
]
=
"
NL
"
,
909
[
leadercodes
.
cleaders
]
=
"
CL
"
,
910
[
leadercodes
.
xleaders
]
=
"
XL
"
,
911
[
leadercodes
.
gleaders
]
=
"
GL
"
,
912
-- true = "VS",
913
-- false = "HS",
914
[
leftskip_code
]
=
"
LS
"
,
915
[
rightskip_code
]
=
"
RS
"
,
916
[
spaceskip_code
]
=
"
SP
"
,
917
[
xspaceskip_code
]
=
"
XS
"
,
918
[
zerospaceskip_code
]
=
"
ZS
"
,
919
[
parfillskip_code
]
=
"
PF
"
,
920
[
indentskip_code
]
=
"
IN
"
,
921
[
correctionskip_code
]
=
"
CS
"
,
922
}
923 924
-- we sometimes pass previous as we can have issues in math (not watertight for all)
925 926
ruledglue
=
function
(
head
,
current
,
vertical
,
parent
)
927
local
subtype
=
getsubtype
(
current
)
928
local
width
=
effectiveglue
(
current
,
parent
)
929
local
amount
=
formatters
[
"
%s:%0.3f
"
]
(
tags
[
subtype
]
or
(
vertical
and
"
VS
"
)
or
"
HS
"
,
width
*
pt_factor
)
930
local
info
=
(
vertical
and
g_cache_v
or
g_cache_h
)
[
amount
]
931
if
info
then
932
-- print("glue hit")
933
else
934
if
subtype
=
=
spaceskip_code
or
subtype
=
=
xspaceskip_code
or
subtype
=
=
zerospaceskip_code
then
935
info
=
sometext
(
amount
,
l_glue
,
c_space
)
936
elseif
subtype
=
=
leftskip_code
or
subtype
=
=
rightskip_code
then
937
info
=
sometext
(
amount
,
l_glue
,
c_skip_a
)
938
elseif
subtype
=
=
parfillskip_code
or
subtype
=
=
indentskip_code
or
subtype
=
=
correctionskip_code
then
939
info
=
sometext
(
amount
,
l_glue
,
c_indent
)
940
elseif
subtype
=
=
userskip_code
then
941
if
width
>
0
then
942
info
=
sometext
(
amount
,
l_glue
,
c_positive
)
943
elseif
width
<
0
then
944
info
=
sometext
(
amount
,
l_glue
,
c_negative
)
945
else
946
info
=
sometext
(
amount
,
l_glue
,
c_zero
)
947
end
948
else
949
info
=
sometext
(
amount
,
l_glue
,
c_skip_b
)
950
end
951
(
vertical
and
g_cache_v
or
g_cache_h
)
[
amount
]
=
info
952
end
953
info
=
copy_list
(
info
)
954
if
vertical
then
955
info
=
vpack_nodes
(
info
)
956
end
957
head
,
current
=
insert_node_before
(
head
,
current
,
info
)
958
return
head
,
getnext
(
current
)
959
end
960 961
-- ruledspace = function(head,current,parent)
962
-- local subtype = getsubtype(current)
963
-- if subtype == spaceskip_code or subtype == xspaceskip_code or subtype == zerospaceskip_code then
964
-- local width = effectiveglue(current,parent)
965
-- local amount = formatters["%s:%0.3f"](tags[subtype] or "HS",width*pt_factor)
966
-- local info = g_cache_h[amount]
967
-- if info then
968
-- -- print("space hit")
969
-- else
970
-- info = sometext(amount,l_glue,c_space)
971
-- g_cache_h[amount] = info
972
-- end
973
-- info = copy_list(info)
974
-- head, current = insert_node_before(head,current,info)
975
-- return head, getnext(current)
976
-- else
977
-- return head, current
978
-- end
979
-- end
980 981
local
g_cache_s
=
caches
[
"
space
"
]
982
local
g_cache_x
=
caches
[
"
xspace
"
]
983 984
ruledspace
=
function
(
head
,
current
,
parent
)
985
local
subtype
=
getsubtype
(
current
)
986
if
subtype
=
=
spaceskip_code
or
subtype
=
=
xspaceskip_code
or
subtype
=
=
zerospaceskip_code
then
-- not yet all space
987
local
width
=
effectiveglue
(
current
,
parent
)
988
local
info
989
if
subtype
=
=
spaceskip_code
then
990
info
=
g_cache_s
[
width
]
991
if
not
info
then
992
info
=
someblob
(
"
SP
"
,
l_glue
,
c_space
,
nil
,
width
)
993
g_cache_s
[
width
]
=
info
994
end
995
else
996
info
=
g_cache_x
[
width
]
997
if
not
info
then
998
info
=
someblob
(
"
XS
"
,
l_glue
,
c_space_x
,
nil
,
width
)
999
g_cache_x
[
width
]
=
info
1000
end
1001
end
1002
info
=
copy_list
(
info
)
1003
head
,
current
=
insert_node_before
(
head
,
current
,
info
)
1004
return
head
,
getnext
(
current
)
1005
else
1006
return
head
,
current
1007
end
1008
end
1009 1010
end
1011 1012
local
ruledkern
do
1013 1014
local
k_cache_v
=
caches
[
"
vkern
"
]
1015
local
k_cache_h
=
caches
[
"
hkern
"
]
1016 1017
ruledkern
=
function
(
head
,
current
,
vertical
,
mk
)
1018
local
kern
=
getkern
(
current
)
1019
local
cache
=
vertical
and
k_cache_v
or
k_cache_h
1020
local
info
=
cache
[
kern
]
1021
if
not
info
then
1022
local
amount
=
formatters
[
"
%s:%0.3f
"
]
(
vertical
and
"
VK
"
or
(
mk
and
"
MK
"
)
or
"
HK
"
,
kern
*
pt_factor
)
1023
if
kern
>
0
then
1024
info
=
sometext
(
amount
,
l_kern
,
c_positive
)
1025
elseif
kern
<
0
then
1026
info
=
sometext
(
amount
,
l_kern
,
c_negative
)
1027
else
1028
info
=
sometext
(
amount
,
l_kern
,
c_zero
)
1029
end
1030
cache
[
kern
]
=
info
1031
end
1032
info
=
copy_list
(
info
)
1033
if
vertical
then
1034
info
=
vpack_nodes
(
info
)
1035
end
1036
head
,
current
=
insert_node_before
(
head
,
current
,
info
)
1037
return
head
,
getnext
(
current
)
1038
end
1039 1040
end
1041 1042
local
ruleditalic
do
1043 1044
local
i_cache
=
caches
[
"
italic
"
]
1045 1046
ruleditalic
=
function
(
head
,
current
)
1047
local
kern
=
getkern
(
current
)
1048
local
info
=
i_cache
[
kern
]
1049
if
not
info
then
1050
local
amount
=
formatters
[
"
%s:%0.3f
"
]
(
"
IC
"
,
kern
*
pt_factor
)
1051
if
kern
>
0
then
1052
info
=
sometext
(
amount
,
l_kern
,
c_positive
)
1053
elseif
kern
<
0
then
1054
info
=
sometext
(
amount
,
l_kern
,
c_negative
)
1055
else
1056
info
=
sometext
(
amount
,
l_kern
,
c_zero
)
1057
end
1058
i_cache
[
kern
]
=
info
1059
end
1060
info
=
copy_list
(
info
)
1061
head
,
current
=
insert_node_before
(
head
,
current
,
info
)
1062
return
head
,
getnext
(
current
)
1063
end
1064 1065
end
1066 1067
local
ruledmarginkern
do
1068 1069
local
m_cache
=
caches
[
"
marginkern
"
]
1070 1071
ruledmarginkern
=
function
(
head
,
current
)
1072
local
kern
=
getkern
(
current
)
1073
local
info
=
m_cache
[
kern
]
1074
if
not
info
then
1075
local
amount
=
formatters
[
"
%s:%0.3f
"
]
(
"
MK
"
,
kern
*
pt_factor
)
1076
if
kern
>
0
then
1077
info
=
sometext
(
amount
,
l_marginkern
,
c_positive
)
1078
elseif
kern
<
0
then
1079
info
=
sometext
(
amount
,
l_marginkern
,
c_negative
)
1080
else
1081
info
=
sometext
(
amount
,
l_marginkern
,
c_zero
)
1082
end
1083
m_cache
[
kern
]
=
info
1084
end
1085
info
=
copy_list
(
info
)
1086
head
,
current
=
insert_node_before
(
head
,
current
,
info
)
1087
return
head
,
getnext
(
current
)
1088
end
1089 1090
end
1091 1092
local
ruledmathlistkern
do
1093 1094
local
l_cache
=
caches
[
"
mathlistkern
"
]
1095 1096
ruledmathlistkern
=
function
(
head
,
current
)
1097
local
kern
=
getkern
(
current
)
1098
local
info
=
l_cache
[
kern
]
1099
if
not
info
then
1100
local
amount
=
formatters
[
"
%s:%0.3f
"
]
(
"
LK
"
,
kern
*
pt_factor
)
1101
if
kern
>
0
then
1102
info
=
sometext
(
amount
,
l_mathlistkern
,
c_positive
)
1103
elseif
kern
<
0
then
1104
info
=
sometext
(
amount
,
l_mathlistkern
,
c_negative
)
1105
else
1106
info
=
sometext
(
amount
,
l_mathlistkern
,
c_zero
)
1107
end
1108
l_cache
[
kern
]
=
info
1109
end
1110
info
=
copy_list
(
info
)
1111
head
,
current
=
insert_node_before
(
head
,
current
,
info
)
1112
return
head
,
getnext
(
current
)
1113
end
1114 1115
end
1116 1117
local
ruleddiscretionary
do
1118 1119
local
d_cache
=
caches
[
"
discretionary
"
]
1120 1121
ruleddiscretionary
=
function
(
head
,
current
)
1122
local
d
=
d_cache
[
true
]
1123
if
not
the_discretionary
then
1124
local
rule
=
new_rule
(
4
*
emwidth
/
fraction
,
4
*
exheight
,
exheight
)
1125
local
kern
=
new_kern
(
-2
*
emwidth
/
fraction
)
1126
setlink
(
kern
,
rule
)
1127
setcolor
(
rule
,
c_discretionary_d
)
1128
settransparency
(
rule
,
c_discretionary_d
)
1129
setattr
(
rule
,
a_layer
,
l_discretionary
)
1130
d
=
new_hlist
(
kern
)
1131
d_cache
[
true
]
=
d
1132
end
1133
insert_node_after
(
head
,
current
,
copy_list
(
d
)
)
1134
return
head
,
current
1135
end
1136 1137
end
1138 1139
local
ruledpenalty
do
1140 1141
local
p_cache_v
=
caches
[
"
vpenalty
"
]
1142
local
p_cache_h
=
caches
[
"
hpenalty
"
]
1143 1144
local
raisepenalties
=
false
1145 1146
directives
.
register
(
"
visualizers.raisepenalties
"
,
function
(
v
)
raisepenalties
=
v
end
)
1147 1148
ruledpenalty
=
function
(
head
,
current
,
vertical
)
1149
local
penalty
=
getpenalty
(
current
)
1150
local
info
=
(
vertical
and
p_cache_v
or
p_cache_h
)
[
penalty
]
1151
if
info
then
1152
-- print("penalty hit")
1153
else
1154
local
amount
=
formatters
[
"
%s:%s
"
]
(
vertical
and
"
VP
"
or
"
HP
"
,
penalty
)
1155
if
penalty
>
0
then
1156
info
=
sometext
(
amount
,
l_penalty
,
c_positive
)
1157
elseif
penalty
<
0
then
1158
info
=
sometext
(
amount
,
l_penalty
,
c_negative
)
1159
else
1160
info
=
sometext
(
amount
,
l_penalty
,
c_zero
)
1161
end
1162
(
vertical
and
p_cache_v
or
p_cache_h
)
[
penalty
]
=
info
1163
end
1164
info
=
copy_list
(
info
)
1165
if
vertical
then
1166
info
=
vpack_nodes
(
info
)
1167
elseif
raisepenalties
then
1168
setshift
(
info
,
-65536
*
4
)
1169
end
1170
head
,
current
=
insert_node_before
(
head
,
current
,
info
)
1171
return
head
,
getnext
(
current
)
1172
end
1173 1174
end
1175 1176
do
1177 1178
local
disc_code
=
nodecodes
.
disc
1179
local
kern_code
=
nodecodes
.
kern
1180
local
glyph_code
=
nodecodes
.
glyph
1181
local
glue_code
=
nodecodes
.
glue
1182
local
penalty_code
=
nodecodes
.
penalty
1183
local
whatsit_code
=
nodecodes
.
whatsit
1184
local
user_code
=
nodecodes
.
user
1185
local
math_code
=
nodecodes
.
math
1186
local
hlist_code
=
nodecodes
.
hlist
1187
local
vlist_code
=
nodecodes
.
vlist
1188
local
marginkern_code
=
nodecodes
.
marginkern
1189
local
mathlistkern_code
=
nodecodes
.
mathlistkern
1190 1191
local
kerncodes
=
nodes
.
kerncodes
1192
local
fontkern_code
=
kerncodes
.
fontkern
1193
local
italickern_code
=
kerncodes
.
italiccorrection
1194
local
leftmarginkern_code
=
kerncodes
.
leftmarginkern
1195
local
rightmarginkern_code
=
kerncodes
.
rightmarginkern
1196
local
mathlistkern_code
=
kerncodes
.
mathlistkern
1197
----- userkern_code = kerncodes.userkern
1198 1199
local
listcodes
=
nodes
.
listcodes
1200
local
linelist_code
=
listcodes
.
line
1201 1202
local
cache
1203 1204
local
function
visualize
(
head
,
vertical
,
forced
,
parent
)
1205
local
trace_hbox
=
false
1206
local
trace_vbox
=
false
1207
local
trace_vtop
=
false
1208
local
trace_kern
=
false
1209
local
trace_glue
=
false
1210
local
trace_penalty
=
false
1211
local
trace_fontkern
=
false
1212
local
trace_strut
=
false
1213
local
trace_whatsit
=
false
1214
local
trace_glyph
=
false
1215
local
trace_simple
=
false
1216
local
trace_user
=
false
1217
local
trace_math
=
false
1218
local
trace_italic
=
false
1219
local
trace_origin
=
false
1220
local
trace_discretionary
=
false
1221
local
trace_expansion
=
false
1222
local
trace_line
=
false
1223
local
trace_space
=
false
1224
local
trace_depth
=
false
1225
local
current
=
head
1226
local
previous
=
nil
1227
local
attr
=
unsetvalue
1228
local
prev_trace_fontkern
=
nil
1229
local
prev_trace_italic
=
nil
1230
local
prev_trace_marginkern
=
nil
1231
-- local prev_trace_mathlist = nil
1232
local
prev_trace_expansion
=
nil
1233 1234
while
current
do
1235
local
id
=
getid
(
current
)
1236
local
a
=
forced
or
getattr
(
current
,
a_visual
)
or
unsetvalue
1237
local
subtype
1238
if
a
~
=
attr
then
1239
prev_trace_fontkern
=
trace_fontkern
1240
prev_trace_italic
=
trace_italic
1241
prev_trace_marginkern
=
trace_marginkern
1242
-- prev_trace_mathlistkern = trace_mathlistkern
1243
prev_trace_expansion
=
trace_expansion
1244
attr
=
a
1245
if
a
=
=
unsetvalue
then
1246
trace_hbox
=
false
1247
trace_vbox
=
false
1248
trace_vtop
=
false
1249
trace_kern
=
false
1250
trace_glue
=
false
1251
trace_penalty
=
false
1252
trace_fontkern
=
false
1253
trace_strut
=
false
1254
trace_whatsit
=
false
1255
trace_glyph
=
false
1256
trace_simple
=
false
1257
trace_user
=
false
1258
trace_math
=
false
1259
trace_italic
=
false
1260
trace_origin
=
false
1261
trace_discretionary
=
false
1262
trace_expansion
=
false
1263
trace_line
=
false
1264
trace_space
=
false
1265
trace_depth
=
false
1266
trace_marginkern
=
false
1267
trace_mathlistkern
=
false
1268
if
id
=
=
kern_code
then
1269
goto
kern
1270
else
1271
goto
list
1272
end
1273
else
-- dead slow:
1274
-- cache[a]()
1275
trace_hbox
=
band
(
a
,
0x000001
)
~
=
0
1276
trace_vbox
=
band
(
a
,
0x000002
)
~
=
0
1277
trace_vtop
=
band
(
a
,
0x000004
)
~
=
0
1278
trace_kern
=
band
(
a
,
0x000008
)
~
=
0
1279
trace_glue
=
band
(
a
,
0x000010
)
~
=
0
1280
trace_penalty
=
band
(
a
,
0x000020
)
~
=
0
1281
trace_fontkern
=
band
(
a
,
0x000040
)
~
=
0
1282
trace_strut
=
band
(
a
,
0x000080
)
~
=
0
1283
trace_whatsit
=
band
(
a
,
0x000100
)
~
=
0
1284
trace_glyph
=
band
(
a
,
0x000200
)
~
=
0
1285
trace_simple
=
band
(
a
,
0x000400
)
~
=
0
1286
trace_user
=
band
(
a
,
0x000800
)
~
=
0
1287
trace_math
=
band
(
a
,
0x001000
)
~
=
0
1288
trace_italic
=
band
(
a
,
0x002000
)
~
=
0
1289
trace_origin
=
band
(
a
,
0x004000
)
~
=
0
1290
trace_discretionary
=
band
(
a
,
0x008000
)
~
=
0
1291
trace_expansion
=
band
(
a
,
0x010000
)
~
=
0
1292
trace_line
=
band
(
a
,
0x020000
)
~
=
0
1293
trace_space
=
band
(
a
,
0x040000
)
~
=
0
1294
trace_depth
=
band
(
a
,
0x080000
)
~
=
0
1295
trace_marginkern
=
band
(
a
,
0x100000
)
~
=
0
1296
trace_mathlistkern
=
band
(
a
,
0x200000
)
~
=
0
1297
end
1298
elseif
a
=
=
unsetvalue
then
1299
goto
list
1300
end
1301
if
trace_strut
then
1302
setattr
(
current
,
a_layer
,
l_strut
)
1303
elseif
id
=
=
glyph_code
then
1304
if
trace_glyph
then
1305
head
,
current
=
ruledglyph
(
head
,
current
,
previous
)
1306
end
1307
if
trace_expansion
then
1308
head
,
current
=
glyphexpansion
(
head
,
current
)
1309
end
1310
elseif
id
=
=
disc_code
then
1311
if
trace_discretionary
then
1312
head
,
current
=
ruleddiscretionary
(
head
,
current
)
1313
end
1314
local
pre
,
post
,
replace
=
getdisc
(
current
)
1315
if
pre
then
1316
pre
=
visualize
(
pre
,
false
,
a
,
parent
)
1317
end
1318
if
post
then
1319
post
=
visualize
(
post
,
false
,
a
,
parent
)
1320
end
1321
if
replace
then
1322
replace
=
visualize
(
replace
,
false
,
a
,
parent
)
1323
end
1324
setdisc
(
current
,
pre
,
post
,
replace
)
1325
elseif
id
=
=
kern_code
then
1326
goto
kern
1327
elseif
id
=
=
glue_code
then
1328
local
content
=
getleader
(
current
)
1329
if
content
then
1330
setleader
(
current
,
visualize
(
content
,
false
,
nil
,
parent
)
)
1331
elseif
trace_glue
then
1332
head
,
current
=
ruledglue
(
head
,
current
,
vertical
,
parent
)
1333
elseif
trace_space
then
1334
head
,
current
=
ruledspace
(
head
,
current
,
parent
)
1335
end
1336
elseif
id
=
=
penalty_code
then
1337
if
trace_penalty
then
1338
head
,
current
=
ruledpenalty
(
head
,
current
,
vertical
)
1339
end
1340
elseif
id
=
=
hlist_code
or
id
=
=
vlist_code
then
1341
goto
list
1342
elseif
id
=
=
whatsit_code
then
1343
if
trace_whatsit
then
1344
head
,
current
=
whatsit
(
head
,
current
)
1345
end
1346
elseif
id
=
=
user_code
then
1347
if
trace_user
then
1348
head
,
current
=
user
(
head
,
current
)
1349
end
1350
elseif
id
=
=
math_code
then
1351
if
trace_math
then
1352
head
,
current
=
math
(
head
,
current
)
1353
end
1354
elseif
id
=
=
marginkern_code
then
1355
if
trace_kern
then
1356
head
,
current
=
ruledkern
(
head
,
current
,
vertical
,
true
)
1357
end
1358
end
1359
goto
next
1360
::
kern
::
1361
subtype
=
getsubtype
(
current
)
1362
if
subtype
=
=
fontkern_code
then
1363
if
trace_fontkern
or
prev_trace_fontkern
then
1364
head
,
current
=
fontkern
(
head
,
current
)
1365
end
1366
if
trace_expansion
or
prev_trace_expansion
then
1367
head
,
current
=
kernexpansion
(
head
,
current
)
1368
end
1369
elseif
subtype
=
=
italickern_code
then
1370
if
trace_italic
or
prev_trace_italic
then
1371
head
,
current
=
italickern
(
head
,
current
)
1372
elseif
trace_kern
then
1373
head
,
current
=
ruleditalic
(
head
,
current
)
1374
end
1375
elseif
subtype
=
=
leftmarginkern_code
or
subtype
=
=
rightmarginkern_code
then
1376
if
trace_marginkern
or
prev_trace_marginkern
then
1377
head
,
current
=
marginkern
(
head
,
current
)
1378
elseif
trace_kern
then
1379
head
,
current
=
ruledmarginkern
(
head
,
current
)
1380
end
1381
elseif
subtype
=
=
mathlistkern_code
then
1382
if
trace_mathlist
then
-- or prev_trace_mathlist then
1383
head
,
current
=
mathlistkern
(
head
,
current
)
1384
elseif
trace_kern
then
1385
head
,
current
=
ruledmathlistkern
(
head
,
current
)
1386
end
1387
else
1388
if
trace_kern
then
1389
head
,
current
=
ruledkern
(
head
,
current
,
vertical
)
1390
end
1391
end
1392
goto
next
;
1393
::
list
::
1394
if
id
=
=
hlist_code
then
1395
local
content
=
getlist
(
current
)
1396
if
content
then
1397
setlist
(
current
,
visualize
(
content
,
false
,
nil
,
current
)
)
1398
end
1399
if
trace_depth
then
1400
ruleddepth
(
current
)
1401
end
1402
if
trace_line
and
getsubtype
(
current
)
=
=
linelist_code
then
1403
head
,
current
=
ruledbox
(
head
,
current
,
false
,
l_line
,
"
L__
"
,
trace_simple
,
previous
,
trace_origin
,
parent
)
1404
elseif
trace_hbox
then
1405
head
,
current
=
ruledbox
(
head
,
current
,
false
,
l_hbox
,
"
H__
"
,
trace_simple
,
previous
,
trace_origin
,
parent
)
1406
end
1407
elseif
id
=
=
vlist_code
then
1408
local
content
=
getlist
(
current
)
1409
if
content
then
1410
setlist
(
current
,
visualize
(
content
,
true
,
nil
,
current
)
)
1411
end
1412
if
trace_vtop
then
1413
head
,
current
=
ruledbox
(
head
,
current
,
true
,
l_vtop
,
"
_T_
"
,
trace_simple
,
previous
,
trace_origin
,
parent
)
1414
elseif
trace_vbox
then
1415
head
,
current
=
ruledbox
(
head
,
current
,
true
,
l_vbox
,
"
__V
"
,
trace_simple
,
previous
,
trace_origin
,
parent
)
1416
end
1417
end
1418
::
next
::
1419
previous
=
current
1420
current
=
getnext
(
current
)
1421
end
1422
return
head
1423
end
1424 1425
local
function
cleanup
(
)
1426
for
tag
,
cache
in
next
,
caches
do
1427
for
k
,
v
in
next
,
cache
do
1428
flush_node_list
(
v
)
1429
end
1430
end
1431
cleanup
=
function
(
)
1432
report_visualize
(
"
error, duplicate cleanup
"
)
1433
end
1434
end
1435 1436
luatex
.
registerstopactions
(
cleanup
)
1437 1438
function
visualizers
.
handler
(
head
)
1439
if
usedfont
then
1440
starttiming
(
visualizers
)
1441
head
=
visualize
(
head
,
true
)
1442
stoptiming
(
visualizers
)
1443
return
head
,
true
1444
else
1445
return
head
,
false
1446
end
1447
end
1448 1449
function
visualizers
.
box
(
n
)
1450
if
usedfont
then
1451
starttiming
(
visualizers
)
1452
local
box
=
getbox
(
n
)
1453
if
box
then
1454
setlist
(
box
,
visualize
(
getlist
(
box
)
,
getid
(
box
)
=
=
vlist_code
)
)
1455
end
1456
stoptiming
(
visualizers
)
1457
return
head
,
true
1458
else
1459
return
head
,
false
1460
end
1461
end
1462 1463
end
1464 1465
do
1466 1467
local
hlist_code
=
nodecodes
.
hlist
1468
local
vlist_code
=
nodecodes
.
vlist
1469 1470
local
last
=
nil
1471
local
used
=
nil
1472 1473
local
mark
=
{
1474
"
trace:1
"
,
"
trace:2
"
,
"
trace:3
"
,
1475
"
trace:4
"
,
"
trace:5
"
,
"
trace:6
"
,
1476
"
trace:7
"
,
1477
}
1478 1479
local
function
markfonts
(
list
)
1480
for
n
,
id
in
nextnode
,
list
do
1481
if
id
=
=
glyph_code
then
1482
local
font
=
getfont
(
n
)
1483
local
okay
=
used
[
font
]
1484
if
not
okay
then
1485
last
=
last
+
1
1486
okay
=
mark
[
last
]
1487
used
[
font
]
=
okay
1488
end
1489
setcolor
(
n
,
okay
)
1490
elseif
id
=
=
hlist_code
or
id
=
=
vlist_code
then
1491
markfonts
(
getlist
(
n
)
)
1492
end
1493
end
1494
end
1495 1496
function
visualizers
.
markfonts
(
list
)
1497
last
,
used
=
0
,
{
}
1498
markfonts
(
type
(
n
)
=
=
"
number
"
and
getlist
(
getbox
(
n
)
)
or
n
)
1499
end
1500 1501
end
1502 1503
statistics
.
register
(
"
visualization time
"
,
function
(
)
1504
if
enabled
then
1505
-- cleanup() -- in case we don't don't do it each time
1506
return
formatters
[
"
%s seconds
"
]
(
statistics
.
elapsedtime
(
visualizers
)
)
1507
end
1508
end
)
1509 1510
-- interface
1511 1512
do
1513 1514
local
implement
=
interfaces
.
implement
1515 1516
implement
{
1517
name
=
"
setvisual
"
,
1518
arguments
=
"
string
"
,
1519
actions
=
visualizers
.
setvisual
1520
}
1521 1522
implement
{
1523
name
=
"
setvisuals
"
,
1524
arguments
=
"
string
"
,
1525
actions
=
visualizers
.
setvisual
1526
}
1527 1528
implement
{
1529
name
=
"
getvisual
"
,
1530
arguments
=
"
string
"
,
1531
actions
=
{
setvisual
,
context
}
1532
}
1533 1534
implement
{
1535
name
=
"
setvisuallayer
"
,
1536
arguments
=
"
string
"
,
1537
actions
=
visualizers
.
setlayer
1538
}
1539 1540
implement
{
1541
name
=
"
markvisualfonts
"
,
1542
arguments
=
"
integer
"
,
1543
actions
=
visualizers
.
markfonts
1544
}
1545 1546
implement
{
1547
name
=
"
setvisualfont
"
,
1548
arguments
=
"
integer
"
,
1549
actions
=
visualizers
.
setfont
1550
}
1551 1552
end
1553 1554
-- Here for now:
1555 1556
do
1557 1558
local
function
make
(
str
,
forecolor
,
rulecolor
,
layer
)
1559
if
initialize
then
1560
initialize
(
)
1561
end
1562
local
rule
=
new_rule
(
emwidth
/
fraction
,
exheight
,
4
*
exheight
)
1563
setcolor
(
rule
,
rulecolor
)
1564
settransparency
(
rule
,
rulecolor
)
1565
local
info
1566
if
str
=
=
"
"
then
1567
info
=
new_hlist
(
rule
)
1568
else
1569
local
text
=
hpack_string
(
str
,
usedfont
)
1570
local
list
=
getlist
(
text
)
1571
setlistcolor
(
list
,
textcolor
)
1572
setlisttransparency
(
list
,
textcolor
)
1573
setshift
(
text
,
3
.
5
*
exheight
)
1574
info
=
new_hlist
(
setlink
(
rule
,
text
)
)
1575
end
1576
setattr
(
info
,
a_layer
,
layer
)
1577
return
info
1578
end
1579 1580
function
visualizers
.
register
(
name
,
textcolor
,
rulecolor
)
1581
if
rawget
(
layers
,
name
)
then
1582
-- message
1583
return
1584
end
1585
local
cache
=
caches
[
name
]
1586
local
layer
=
layers
[
name
]
1587
if
not
textcolor
then
1588
textcolor
=
c_text_d
1589
end
1590
if
not
rulecolor
then
1591
rulecolor
=
c_origin_d
1592
end
1593
return
function
(
str
)
1594
if
not
str
then
1595
str
=
"
"
1596
end
1597
local
info
=
cache
[
str
]
1598
if
not
info
then
1599
info
=
make
(
str
,
textcolor
,
rulecolor
,
layer
)
1600
cache
[
str
]
=
info
1601
end
1602
return
copy_node
(
info
)
1603
end
1604
end
1605 1606
end
1607