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 = string . gmatch
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 nodecodes = nodes . nodecodes
34
35local nuts = nodes . nuts
36local tonut = nuts . tonut
37
38local setboth = nuts . setboth
39local setlink = nuts . setlink
40local setdisc = nuts . setdisc
41local setlist = nuts . setlist
42local setleader = nuts . setleader
43local setsubtype = nuts . setsubtype
44local setattr = nuts . setattr
45local setwidth = nuts . setwidth
46local setshift = nuts . setshift
47
48local getid = nuts . getid
49local getfont = nuts . getfont
50local getattr = nuts . getattr
51local getsubtype = nuts . getsubtype
52local getbox = nuts . getbox
53local getlist = nuts . getlist
54local getleader = nuts . getleader
55local getnext = nuts . getnext
56local getprev = nuts . getprev
57local getboth = nuts . getboth
58local getdisc = nuts . getdisc
59local getwhd = nuts . getwhd
60local getkern = nuts . getkern
61local getpenalty = nuts . getpenalty
62local getwidth = nuts . getwidth
63local getdepth = nuts . getdepth
64local getshift = nuts . getshift
65local getexpansion = nuts . getexpansion
66local getdirection = nuts . getdirection
67local getstate = nuts . getstate
68
69local isglyph = nuts . isglyph
70
71local hpack_nodes = nuts . hpack
72local vpack_nodes = nuts . vpack
73local copylist = nuts . copylist
74local copy_node = nuts . copy
75local insertnodebefore = nuts . insertbefore
76local insertnodeafter = nuts . insertafter
77local apply_to_nodes = nuts . apply
78local find_tail = nuts . tail
79local effectiveglue = nuts . effectiveglue
80local flushnodelist = nuts . flushlist
81
82local hpack_string = nuts . typesetters . tohpack
83
84local texgetattribute = tex . getattribute
85local texsetattribute = tex . setattribute
86
87local setmetatableindex = table . setmetatableindex
88
89local unsetvalue = attributes . unsetvalue
90
91local current_font = font . current
92
93local fonthashes = fonts . hashes
94local chardata = fonthashes . characters
95local exheights = fonthashes . exheights
96local emwidths = fonthashes . emwidths
97local pt_factor = number . dimenfactors . pt
98
99local nodepool = nuts . pool
100local new_rule = nodepool . rule
101local new_kern = nodepool . kern
102local new_glue = nodepool . glue
103local new_hlist = nodepool . hlist
104local new_vlist = nodepool . vlist
105
106local tracers = nodes . tracers
107local visualizers = nodes . visualizers
108
109local setcolor = tracers . colors . set
110local setlistcolor = tracers . colors . setlist
111local settransparency = tracers . transparencies . set
112local setlisttransparency = tracers . transparencies . setlist
113
114local starttiming = statistics . starttiming
115local stoptiming = statistics . stoptiming
116
117local a_visual = attributes . private ( " visual " )
118local a_layer = attributes . private ( " viewerlayer " )
119
120local band = bit32 . band
121local bor = bit32 . bor
122
123local enableaction = nodes . tasks . enableaction
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142local report_visualize = logs . reporter ( " visualize " )
143
144local 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
174local usedfont , exheight , emwidth
175local 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
178local enabled = false
179local layers = { }
180
181local preset_boxes = modes . hbox + modes . vbox + modes . origin
182local preset_makeup = preset_boxes
183 + modes . kern + modes . glue + modes . penalty
184local 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
189function visualizers . setfont ( id )
190 usedfont = id or current_font ( )
191 exheight = exheights [ usedfont ]
192 emwidth = emwidths [ usedfont ]
193end
194
195
196
197local userrule
198local outlinerule
199
200local function initialize ( )
201
202 if not usedfont then
203
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
250end
251
252local 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 )
260end
261
262local function setvisual ( n , a , what , list )
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
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
300 enable ( )
301 end
302 return a
303end
304
305function nuts . setvisual ( n , mode )
306 setattr ( n , a_visual , setvisual ( mode , getattr ( n , a_visual ) , true ) )
307end
308
309function nuts . setvisuals ( n , mode )
310 setattr ( n , a_visual , setvisual ( mode , getattr ( n , a_visual ) , true , true ) )
311end
312
313
314
315do
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
331
332
333
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
356end
357
358function nuts . copyvisual ( n , m )
359 setattr ( n , a_visual , getattr ( m , a_visual ) )
360end
361
362function visualizers . setvisual ( n )
363 texsetattribute ( a_visual , setvisual ( n , texgetattribute ( a_visual ) ) )
364end
365
366function visualizers . setlayer ( n )
367 texsetattribute ( a_layer , layers [ n ] or unsetvalue )
368end
369
370local function set ( mode , v )
371 texsetattribute ( a_visual , setvisual ( mode , texgetattribute ( a_visual ) , v ) )
372end
373
374for mode , value in next , modes do
375 trackers . register ( formatters [ " visualizers.%s " ] ( mode ) , function ( v ) set ( mode , v ) end )
376end
377
378local fraction = 10
379
380trackers . register ( " visualizers.reset " , function ( v ) set ( " reset " , v ) end )
381trackers . register ( " visualizers.all " , function ( v ) set ( " all " , v ) end )
382trackers . register ( " visualizers.makeup " , function ( v ) set ( " makeup " , v ) end )
383trackers . register ( " visualizers.boxes " , function ( v ) set ( " boxes " , v ) end )
384directives . register ( " visualizers.fraction " , function ( v ) fraction = ( v and tonumber ( v ) ) or ( v = = " more " and 5 ) or 10 end )
385
386local c_positive = " trace:b "
387local c_negative = " trace:r "
388local c_zero = " trace:g "
389local c_text = " trace:s "
390local c_space = " trace:y "
391local c_space_x = " trace:m "
392local c_skip_a = " trace:c "
393local c_skip_b = " trace:m "
394local c_glyph = " trace:o "
395local c_ligature = " trace:s "
396local c_white = " trace:w "
397
398
399
400
401local c_depth = " trace:o "
402local c_indent = " trace:s "
403
404local c_positive_d = " trace:db "
405local c_negative_d = " trace:dr "
406local c_zero_d = " trace:dg "
407local c_text_d = " trace:ds "
408local c_space_d = " trace:dy "
409local c_space_x_d = " trace:dm "
410local c_skip_a_d = " trace:dc "
411local c_skip_b_d = " trace:dm "
412local c_glyph_d = " trace:do "
413local c_ligature_d = " trace:ds "
414local c_white_d = " trace:dw "
415local c_math_d = " trace:dr "
416local c_origin_d = " trace:do "
417local c_discretionary_d = " trace:dd "
418
419
420
421
422local function sometext ( str , layer , color , textcolor , lap )
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 )
441 end
442 if layer then
443 setattr ( info , a_layer , layer )
444 end
445 return info , width
446end
447
448local 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
468end
469
470local caches = setmetatableindex ( " table " )
471
472local 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
523end
524
525local 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
557end
558
559local kernexpansion do
560
561 local f_cache = caches [ " kernexpansion " ]
562
563
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
593end
594
595local 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
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
628end
629
630local 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 "
650 local info = d_cache [ what ]
651 if info then
652
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
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
681end
682
683local 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
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
701end
702
703local 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 )
719 local info = m_cache [ tag ] [ skip ]
720 if info then
721
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
740end
741
742local 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
755end
756
757local 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
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 )
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
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
865end
866
867local ruledglyph do
868
869
870
871
872
873 ruledglyph = function ( head , current , previous )
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
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
928end
929
930local 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
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
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
974
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
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
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
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
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
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
1072end
1073
1074local 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
1102end
1103
1104local 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
1127end
1128
1129local 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
1152end
1153
1154local 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
1177end
1178
1179local 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
1199end
1200
1201local 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
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
1236end
1237
1238do
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
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
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
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
1342
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
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
1541end
1542
1543do
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
1580end
1581
1582statistics . register ( " visualization time " , function ( )
1583 if enabled then
1584
1585 return formatters [ " %s seconds " ] ( statistics . elapsedtime ( visualizers ) )
1586 end
1587end )
1588
1589
1590
1591do
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
1631end
1632
1633
1634
1635do
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
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
1685end
1686 |