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