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