diff options
Diffstat (limited to 'tex/context/base/trac-vis.lua')
-rw-r--r-- | tex/context/base/trac-vis.lua | 1014 |
1 files changed, 0 insertions, 1014 deletions
diff --git a/tex/context/base/trac-vis.lua b/tex/context/base/trac-vis.lua deleted file mode 100644 index b54182798..000000000 --- a/tex/context/base/trac-vis.lua +++ /dev/null @@ -1,1014 +0,0 @@ -if not modules then modules = { } end modules ['trac-vis'] = { - version = 1.001, - comment = "companion to trac-vis.mkiv", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - -local string, number, table = string, number, table -local node, nodes, attributes, fonts, tex = node, nodes, attributes, fonts, tex -local type = type -local format = string.format -local formatters = string.formatters - --- This module started out in the early days of mkiv and luatex with --- visualizing kerns related to fonts. In the process of cleaning up the --- visual debugger code it made sense to integrate some other code that --- I had laying around and replace the old supp-vis debugging code. As --- only a subset of the old visual debugger makes sense it has become a --- different implementation. Soms of the m-visual functionality will also --- be ported. The code is rather trivial. The caching is not really needed --- but saves upto 50% of the time needed to add visualization. Of course --- the overall runtime is larger because of color and layer processing in --- the backend (can be times as much) so the runtime is somewhat larger --- with full visualization enabled. In practice this will never happen --- unless one is demoing. - --- We could use pdf literals and re stream codes but it's not worth the --- trouble because we would end up in color etc mess. Maybe one day I'll --- make a nodeinjection variant. - --- todo: global switch (so no attributes) --- todo: maybe also xoffset, yoffset of glyph --- todo: inline concat (more efficient) --- todo: tags can also be numbers (just add to hash) - -local nodecodes = nodes.nodecodes -local disc_code = nodecodes.disc -local kern_code = nodecodes.kern -local glyph_code = nodecodes.glyph -local hlist_code = nodecodes.hlist -local vlist_code = nodecodes.vlist -local glue_code = nodecodes.glue -local penalty_code = nodecodes.penalty -local whatsit_code = nodecodes.whatsit -local user_code = nodecodes.user -local math_code = nodecodes.math -local gluespec_code = nodecodes.gluespec - -local kerncodes = nodes.kerncodes -local font_kern_code = kerncodes.fontkern -local user_kern_code = kerncodes.userkern - -local gluecodes = nodes.gluecodes -local cleaders_code = gluecodes.cleaders -local userskip_code = gluecodes.userskip -local space_code = gluecodes.space -local xspace_code = gluecodes.xspace -local leftskip_code = gluecodes.leftskip -local rightskip_code = gluecodes.rightskip - -local whatsitcodes = nodes.whatsitcodes -local mathcodes = nodes.mathcodes - -local nuts = nodes.nuts -local tonut = nuts.tonut -local tonode = nuts.tonode - -local getfield = nuts.getfield -local getnext = nuts.getnext -local getprev = nuts.getprev -local getid = nuts.getid -local setfield = nuts.setfield -local getattr = nuts.getattr -local setattr = nuts.setattr -local getfont = nuts.getfont -local getsubtype = nuts.getsubtype -local getchar = nuts.getchar -local getbox = nuts.getbox -local getlist = nuts.getlist -local getleader = nuts.getleader - -local hpack_nodes = nuts.hpack -local vpack_nodes = nuts.vpack -local copy_node = nuts.copy -local copy_list = nuts.copy_list -local free_node = nuts.free -local free_node_list = nuts.flush_list -local insert_node_before = nuts.insert_before -local insert_node_after = nuts.insert_after -local traverse_nodes = nuts.traverse -local linked_nodes = nuts.linked - -local fast_hpack = nuts.fasthpack -local fast_hpack_string = nuts.typesetters.fast_hpack - -local texgetattribute = tex.getattribute -local texsetattribute = tex.setattribute - -local unsetvalue = attributes.unsetvalue - -local current_font = font.current - -local fonthashes = fonts.hashes -local chardata = fonthashes.characters -local exheights = fonthashes.exheights -local emwidths = fonthashes.emwidths -local pt_factor = number.dimenfactors.pt - -local nodepool = nuts.pool -local new_rule = nodepool.rule -local new_kern = nodepool.kern -local new_glue = nodepool.glue -local new_penalty = nodepool.penalty - -local tracers = nodes.tracers -local visualizers = nodes.visualizers - -local setcolor = tracers.colors.set -local setlistcolor = tracers.colors.setlist -local settransparency = tracers.transparencies.set -local setlisttransparency = tracers.transparencies.setlist - -local starttiming = statistics.starttiming -local stoptiming = statistics.stoptiming - -local a_visual = attributes.private("visual") -local a_fontkern = attributes.private("fontkern") -local a_layer = attributes.private("viewerlayer") - -local hasbit = number.hasbit -local bit = number.bit -local setbit = number.setbit -local clearbit = number.clearbit - -local trace_hbox -local trace_vbox -local trace_vtop -local trace_kern -local trace_glue -local trace_penalty -local trace_fontkern -local trace_strut -local trace_whatsit -local trace_user -local trace_math - -local report_visualize = logs.reporter("visualize") - -local modes = { - hbox = 1, - vbox = 2, - vtop = 4, - kern = 8, - glue = 16, - penalty = 32, - fontkern = 64, - strut = 128, - whatsit = 256, - glyph = 512, - simple = 1024, - simplehbox = 1024 + 1, - simplevbox = 1024 + 2, - simplevtop = 1024 + 4, - user = 2048, - math = 4096, -} - -local modes_makeup = { "hbox", "vbox", "kern", "glue", "penalty" } -local modes_boxes = { "hbox", "vbox" } -local modes_all = { "hbox", "vbox", "kern", "glue", "penalty", "fontkern", "whatsit", "glyph", "user", "math" } - -local usedfont, exheight, emwidth -local l_penalty, l_glue, l_kern, l_fontkern, l_hbox, l_vbox, l_vtop, l_strut, l_whatsit, l_glyph, l_user, l_math - -local enabled = false -local layers = { } - -local preset_boxes = modes.hbox + modes.vbox -local preset_makeup = preset_boxes + modes.kern + modes.glue + modes.penalty -local preset_all = preset_makeup + modes.fontkern + modes.whatsit + modes.glyph + modes.user + modes.math - -function visualizers.setfont(id) - usedfont = id or current_font() - exheight = exheights[usedfont] - emwidth = emwidths[usedfont] -end - --- we can preset a bunch of bits - -local function enable() - if not usedfont then - -- we use a narrow monospaced font -- infofont ? - visualizers.setfont(fonts.definers.define { name = "lmmonoltcond10regular", size = tex.sp("4pt") }) - end - for mode, value in next, modes do - local tag = formatters["v_%s"](mode) - attributes.viewerlayers.define { - tag = tag, - title = formatters["visualizer %s"](mode), - visible = "start", - editable = "yes", - printable = "yes" - } - layers[mode] = attributes.viewerlayers.register(tag,true) - end - l_hbox = layers.hbox - l_vbox = layers.vbox - l_vtop = layers.vtop - l_glue = layers.glue - l_kern = layers.kern - l_penalty = layers.penalty - l_fontkern = layers.fontkern - l_strut = layers.strut - l_whatsit = layers.whatsit - l_glyph = layers.glyph - l_user = layers.user - l_math = layers.math - nodes.tasks.enableaction("shipouts","nodes.visualizers.handler") - report_visualize("enabled") - enabled = true - tex.setcount("global","c_syst_visualizers_state",1) -- so that we can optimize at the tex end -end - -local function setvisual(n,a,what) -- this will become more efficient when we have the bit lib linked in - if not n or n == "reset" then - return unsetvalue - elseif n == "makeup" then - if not a or a == 0 or a == unsetvalue then - a = preset_makeup - else - a = setbit(a,preset_makeup) - end - elseif n == "boxes" then - if not a or a == 0 or a == unsetvalue then - a = preset_boxes - else - a = setbit(a,preset_boxes) - end - elseif n == "all" then - if what == false then - return unsetvalue - elseif not a or a == 0 or a == unsetvalue then - a = preset_all - else - a = setbit(a,preset_all) - end - else - local m = modes[n] - if not m then - -- go on - elseif a == unsetvalue then - if what == false then - return unsetvalue - else - -- a = setbit(0,m) - a = m - end - elseif what == false then - a = clearbit(a,m) - elseif not a or a == 0 then - a = m - else - a = setbit(a,m) - end - end - if not a or a == 0 or a == unsetvalue then - return unsetvalue - elseif not enabled then -- must happen at runtime (as we don't store layers yet) - enable() - end - return a -end - -function visualizers.setvisual(n) - texsetattribute(a_visual,setvisual(n,texgetattribute(a_visual))) -end - -function visualizers.setlayer(n) - texsetattribute(a_layer,layers[n] or unsetvalue) -end - -local function set(mode,v) - texsetattribute(a_visual,setvisual(mode,texgetattribute(a_visual),v)) -end - -for mode, value in next, modes do - trackers.register(formatters["visualizers.%s"](mode), function(v) set(mode,v) end) -end - -local fraction = 10 - -trackers .register("visualizers.reset", function(v) set("reset", v) end) -trackers .register("visualizers.all", function(v) set("all", v) end) -trackers .register("visualizers.makeup", function(v) set("makeup",v) end) -trackers .register("visualizers.boxes", function(v) set("boxes", v) end) -directives.register("visualizers.fraction", function(v) fraction = tonumber(v) or fraction end) - -local c_positive = "trace:b" -local c_negative = "trace:r" -local c_zero = "trace:g" -local c_text = "trace:s" -local c_space = "trace:y" -local c_skip_a = "trace:c" -local c_skip_b = "trace:m" -local c_glyph = "trace:o" -local c_ligature = "trace:s" -local c_white = "trace:w" -local c_math = "trace:r" - -local c_positive_d = "trace:db" -local c_negative_d = "trace:dr" -local c_zero_d = "trace:dg" -local c_text_d = "trace:ds" -local c_space_d = "trace:dy" -local c_skip_a_d = "trace:dc" -local c_skip_b_d = "trace:dm" -local c_glyph_d = "trace:do" -local c_ligature_d = "trace:ds" -local c_white_d = "trace:dw" -local c_math_d = "trace:dr" - -local function sometext(str,layer,color,textcolor,lap) -- we can just paste verbatim together .. no typesteting needed - local text = fast_hpack_string(str,usedfont) - local size = getfield(text,"width") - local rule = new_rule(size,2*exheight,exheight/2) - local kern = new_kern(-size) - if color then - setcolor(rule,color) - end - if textcolor then - setlistcolor(getlist(text),textcolor) - end - local info = linked_nodes(rule,kern,text) - setlisttransparency(info,c_zero) - info = fast_hpack(info) - local width = getfield(info,"width") - if lap then - info = fast_hpack(linked_nodes(new_kern(-width),info)) - end - if layer then - setattr(info,a_layer,layer) - end - setfield(info,"width",0) - setfield(info,"height",0) - setfield(info,"depth",0) - return info, width -end - -local f_cache = { } - -local function fontkern(head,current) - local kern = getfield(current,"kern") - local info = f_cache[kern] - if info then - -- print("hit fontkern") - else - local text = fast_hpack_string(formatters[" %0.3f"](kern*pt_factor),usedfont) - local rule = new_rule(emwidth/fraction,6*exheight,2*exheight) - local list = getlist(text) - if kern > 0 then - setlistcolor(list,c_positive_d) - elseif kern < 0 then - setlistcolor(list,c_negative_d) - else - setlistcolor(list,c_zero_d) - end - setlisttransparency(list,c_text_d) - settransparency(rule,c_text_d) - setfield(text,"shift",-5 * exheight) - info = fast_hpack(linked_nodes(rule,text)) - setattr(info,a_layer,l_fontkern) - setfield(info,"width",0) - setfield(info,"height",0) - setfield(info,"depth",0) - f_cache[kern] = info - end - head = insert_node_before(head,current,copy_list(info)) - return head, current -end - -local w_cache = { } -local tags = { - open = "FIC", - write = "FIW", - close = "FIC", - special = "SPE", - localpar = "PAR", - dir = "DIR", - pdfliteral = "PDF", - pdfrefobj = "PDF", - pdfrefxform = "PDF", - pdfrefximage = "PDF", - pdfannot = "PDF", - pdfstartlink = "PDF", - pdfendlink = "PDF", - pdfdest = "PDF", - pdfthread = "PDF", - pdfstartthread = "PDF", - pdfendthread = "PDF", - pdfsavepos = "PDF", - pdfthreaddata = "PDF", - pdflinkdata = "PDF", - pdfcolorstack = "PDF", - pdfsetmatrix = "PDF", - pdfsave = "PDF", - pdfrestore = "PDF", - latelua = "LUA", - closelua = "LUA", - cancelboundary = "CBD", - userdefined = "USR", -} - -local function whatsit(head,current) - local what = getsubtype(current) - local info = w_cache[what] - if info then - -- print("hit whatsit") - else - local tag = whatsitcodes[what] - -- maybe different text colors per tag - info = sometext(formatters["W:%s"](tag and tags[tag] or what),usedfont,nil,c_white) - setattr(info,a_layer,l_whatsit) - w_cache[what] = info - end - head, current = insert_node_after(head,current,copy_list(info)) - return head, current -end - -local u_cache = { } - -local function user(head,current) - local what = getsubtype(current) - local info = u_cache[what] - if info then - -- print("hit user") - else - info = sometext(formatters["U:%s"](what),usedfont) - setattr(info,a_layer,l_user) - u_cache[what] = info - end - head, current = insert_node_after(head,current,copy_list(info)) - return head, current -end - -local m_cache = { } -local tags = { - beginmath = "B", - endmath = "E", -} - -local function math(head,current) - local what = getsubtype(current) - local info = m_cache[what] - if info then - -- print("hit math") - else - local tag = mathcodes[what] - info = sometext(formatters["M:%s"](tag and tags[tag] or what),usedfont,nil,c_math_d) - setattr(info,a_layer,l_math) - m_cache[what] = info - end - head, current = insert_node_after(head,current,copy_list(info)) - return head, current -end - -local b_cache = { } - -local function ruledbox(head,current,vertical,layer,what,simple,previous) - local wd = getfield(current,"width") - if wd ~= 0 then - local ht = getfield(current,"height") - local dp = getfield(current,"depth") - local shift = getfield(current,"shift") - local next = getnext(current) - local prev = previous - -- local prev = getprev(current) -- prev can be wrong in math mode < 0.78.3 - setfield(current,"next",nil) - setfield(current,"prev",nil) - local linewidth = emwidth/fraction - local baseline, baseskip - if dp ~= 0 and ht ~= 0 then - if wd > 20*linewidth then - baseline = b_cache.baseline - if not baseline then - -- due to an optimized leader color/transparency we need to set the glue node in order - -- to trigger this mechanism - local leader = linked_nodes(new_glue(2*linewidth),new_rule(6*linewidth,linewidth,0),new_glue(2*linewidth)) - -- setlisttransparency(leader,c_text) - leader = fast_hpack(leader) - -- setlisttransparency(leader,c_text) - baseline = new_glue(0) - setfield(baseline,"leader",leader) - setfield(baseline,"subtype",cleaders_code) - local spec = getfield(baseline,"spec") - setfield(spec,"stretch",65536) - setfield(spec,"stretch_order",2) - setlisttransparency(baseline,c_text) - b_cache.baseline = baseline - end - baseline = copy_list(baseline) - baseline = fast_hpack(baseline,wd-2*linewidth) - -- or new hpack node, set head and also: - -- baseline.width = wd - -- baseline.glue_set = wd/65536 - -- baseline.glue_order = 2 - -- baseline.glue_sign = 1 - baseskip = new_kern(-wd+linewidth) - else - baseline = new_rule(wd-2*linewidth,linewidth,0) - baseskip = new_kern(-wd+2*linewidth) - end - end - local this - if not simple then - this = b_cache[what] - if not this then - local text = fast_hpack_string(what,usedfont) - this = linked_nodes(new_kern(-getfield(text,"width")),text) - setlisttransparency(this,c_text) - this = fast_hpack(this) - setfield(this,"width",0) - setfield(this,"height",0) - setfield(this,"depth",0) - b_cache[what] = this - end - end - -- we need to trigger the right mode (else sometimes no whatits) - local info = linked_nodes( - this and copy_list(this) or nil, - new_rule(linewidth,ht,dp), - new_rule(wd-2*linewidth,-dp+linewidth,dp), - new_rule(linewidth,ht,dp), - new_kern(-wd+linewidth), - new_rule(wd-2*linewidth,ht,-ht+linewidth) - ) - if baseskip then - info = linked_nodes(info,baseskip,baseline) -- could be in previous linked - end - local shft - if shift == 0 then - shift = nil - else - local sh = shift > 0 and shift or 0 - local sd = shift < 0 and - shift or 0 - shft = fast_hpack(new_rule(2*emwidth/fraction,sh,sd)) - setfield(shft,"width",0) - if sh > 0 then - setfield(shft,"height",0) - end - if sd > 0 then - setfield(shft,"depth",0) - end - end - setlisttransparency(info,c_text) - info = fast_hpack(info) - setfield(info,"width",0) - setfield(info,"height",0) - setfield(info,"depth",0) - setattr(info,a_layer,layer) - local info = linked_nodes(shft,current,new_kern(-wd),info) - info = fast_hpack(info,wd) - if vertical then - info = vpack_nodes(info) - end - if shift then - setfield(current,"shift",0) - setfield(info,"width",wd) - setfield(info,"height",ht) - setfield(info,"depth",dp) - setfield(info,"shift",shift) - end - if next then - setfield(info,"next",next) - setfield(next,"prev",info) - end - if prev then - if getid(prev) == gluespec_code then - report_visualize("ignoring invalid prev") - -- weird, how can this happen, an inline glue-spec, probably math - else - setfield(info,"prev",prev) - setfield(prev,"next",info) - end - end - if head == current then - return info, info - else - return head, info - end - else - return head, current - end -end - -local function ruledglyph(head,current,previous) - local wd = getfield(current,"width") - -- local wd = chardata[getfield(current,"font")][getfield(current,"char")].width - if wd ~= 0 then - local ht = getfield(current,"height") - local dp = getfield(current,"depth") - local next = getnext(current) - local prev = previous - setfield(current,"next",nil) - setfield(current,"prev",nil) - local linewidth = emwidth/(2*fraction) - local baseline - -- if dp ~= 0 and ht ~= 0 then - if (dp >= 0 and ht >= 0) or (dp <= 0 and ht <= 0) then - baseline = new_rule(wd-2*linewidth,linewidth,0) - end - local doublelinewidth = 2*linewidth - -- could be a pdf rule - local info = linked_nodes( - new_rule(linewidth,ht,dp), - new_rule(wd-doublelinewidth,-dp+linewidth,dp), - new_rule(linewidth,ht,dp), - new_kern(-wd+linewidth), - new_rule(wd-doublelinewidth,ht,-ht+linewidth), - new_kern(-wd+doublelinewidth), - baseline - ) -local char = chardata[getfield(current,"font")][getfield(current,"char")] -if char and char.tounicode and #char.tounicode > 4 then -- hack test - setlistcolor(info,c_ligature) - setlisttransparency(info,c_ligature_d) -else - setlistcolor(info,c_glyph) - setlisttransparency(info,c_glyph_d) -end - info = fast_hpack(info) - setfield(info,"width",0) - setfield(info,"height",0) - setfield(info,"depth",0) - setattr(info,a_layer,l_glyph) - local info = linked_nodes(current,new_kern(-wd),info) - info = fast_hpack(info) - setfield(info,"width",wd) - if next then - setfield(info,"next",next) - setfield(next,"prev",info) - end - if prev then - setfield(info,"prev",prev) - setfield(prev,"next",info) - end - if head == current then - return info, info - else - return head, info - end - else - return head, current - end -end - -local g_cache = { } - -local tags = { - -- userskip = "US", - lineskip = "LS", - baselineskip = "BS", - parskip = "PS", - abovedisplayskip = "DA", - belowdisplayskip = "DB", - abovedisplayshortskip = "SA", - belowdisplayshortskip = "SB", - leftskip = "LS", - rightskip = "RS", - topskip = "TS", - splittopskip = "ST", - tabskip = "AS", - spaceskip = "SS", - xspaceskip = "XS", - parfillskip = "PF", - thinmuskip = "MS", - medmuskip = "MM", - thickmuskip = "ML", - leaders = "NL", - cleaders = "CL", - xleaders = "XL", - gleaders = "GL", - -- true = "VS", - -- false = "HS", -} - --- we sometimes pass previous as we can have issues in math (not watertight for all) - -local function ruledglue(head,current,vertical) - local spec = getfield(current,"spec") - local width = getfield(spec,"width") - local subtype = getsubtype(current) - local amount = formatters["%s:%0.3f"](tags[subtype] or (vertical and "VS") or "HS",width*pt_factor) - local info = g_cache[amount] - if info then - -- print("glue hit") - else - if subtype == space_code or subtype == xspace_code then -- not yet all space - info = sometext(amount,l_glue,c_space) - elseif subtype == leftskip_code or subtype == rightskip_code then - info = sometext(amount,l_glue,c_skip_a) - elseif subtype == userskip_code then - if width > 0 then - info = sometext(amount,l_glue,c_positive) - elseif width < 0 then - info = sometext(amount,l_glue,c_negative) - else - info = sometext(amount,l_glue,c_zero) - end - else - info = sometext(amount,l_glue,c_skip_b) - end - g_cache[amount] = info - end - info = copy_list(info) - if vertical then - info = vpack_nodes(info) - end - head, current = insert_node_before(head,current,info) - return head, getnext(current) -end - -local k_cache = { } - -local function ruledkern(head,current,vertical) - local kern = getfield(current,"kern") - local info = k_cache[kern] - if info then - -- print("kern hit") - else - local amount = formatters["%s:%0.3f"](vertical and "VK" or "HK",kern*pt_factor) - if kern > 0 then - info = sometext(amount,l_kern,c_positive) - elseif kern < 0 then - info = sometext(amount,l_kern,c_negative) - else - info = sometext(amount,l_kern,c_zero) - end - k_cache[kern] = info - end - info = copy_list(info) - if vertical then - info = vpack_nodes(info) - end - head, current = insert_node_before(head,current,info) - return head, getnext(current) -end - -local p_cache = { } - -local function ruledpenalty(head,current,vertical) - local penalty = getfield(current,"penalty") - local info = p_cache[penalty] - if info then - -- print("penalty hit") - else - local amount = formatters["%s:%s"](vertical and "VP" or "HP",penalty) - if penalty > 0 then - info = sometext(amount,l_penalty,c_positive) - elseif penalty < 0 then - info = sometext(amount,l_penalty,c_negative) - else - info = sometext(amount,l_penalty,c_zero) - end - p_cache[penalty] = info - end - info = copy_list(info) - if vertical then - info = vpack_nodes(info) - end - head, current = insert_node_before(head,current,info) - return head, getnext(current) -end - -local function visualize(head,vertical,forced) - local trace_hbox = false - local trace_vbox = false - local trace_vtop = false - local trace_kern = false - local trace_glue = false - local trace_penalty = false - local trace_fontkern = false - local trace_strut = false - local trace_whatsit = false - local trace_glyph = false - local trace_simple = false - local trace_user = false - local trace_math = false - local current = head - local previous = nil - local attr = unsetvalue - local prev_trace_fontkern = nil - while current do - local id = getid(current) - local a = forced or getattr(current,a_visual) or unsetvalue - if a ~= attr then - prev_trace_fontkern = trace_fontkern - if a == unsetvalue then - trace_hbox = false - trace_vbox = false - trace_vtop = false - trace_kern = false - trace_glue = false - trace_penalty = false - trace_fontkern = false - trace_strut = false - trace_whatsit = false - trace_glyph = false - trace_simple = false - trace_user = false - trace_math = false - else -- dead slow: - trace_hbox = hasbit(a, 1) - trace_vbox = hasbit(a, 2) - trace_vtop = hasbit(a, 4) - trace_kern = hasbit(a, 8) - trace_glue = hasbit(a, 16) - trace_penalty = hasbit(a, 32) - trace_fontkern = hasbit(a, 64) - trace_strut = hasbit(a, 128) - trace_whatsit = hasbit(a, 256) - trace_glyph = hasbit(a, 512) - trace_simple = hasbit(a,1024) - trace_user = hasbit(a,2048) - trace_math = hasbit(a,4096) - end - attr = a - end - if trace_strut then - setattr(current,a_layer,l_strut) - elseif id == glyph_code then - if trace_glyph then - head, current = ruledglyph(head,current,previous) - end - elseif id == disc_code then - local pre = getfield(current,"pre") - if pre then - setfield(current,"pre",visualize(pre,false,a)) - end - local post = getfield(current,"post") - if post then - setfield(current,"post",visualize(post,false,a)) - end - local replace = getfield(current,"replace") - if replace then - setfield(current,"replace",visualize(replace,false,a)) - end - elseif id == kern_code then - local subtype = getsubtype(current) - -- tricky ... we don't copy the trace attribute in node-inj (yet) - if subtype == font_kern_code or getattr(current,a_fontkern) then - if trace_fontkern or prev_trace_fontkern then - head, current = fontkern(head,current) - end - else -- if subtype == user_kern_code then - if trace_kern then - head, current = ruledkern(head,current,vertical) - end - end - elseif id == glue_code then - local content = getleader(current) - if content then - setfield(current,"leader",visualize(content,false)) - elseif trace_glue then - head, current = ruledglue(head,current,vertical) - end - elseif id == penalty_code then - if trace_penalty then - head, current = ruledpenalty(head,current,vertical) - end - elseif id == hlist_code then - local content = getlist(current) - if content then - setfield(current,"list",visualize(content,false)) - end - if trace_hbox then - head, current = ruledbox(head,current,false,l_hbox,"H__",trace_simple,previous) - end - elseif id == vlist_code then - local content = getlist(current) - if content then - setfield(current,"list",visualize(content,true)) - end - if trace_vtop then - head, current = ruledbox(head,current,true,l_vtop,"_T_",trace_simple,previous) - elseif trace_vbox then - head, current = ruledbox(head,current,true,l_vbox,"__V",trace_simple,previous) - end - elseif id == whatsit_code then - if trace_whatsit then - head, current = whatsit(head,current) - end - elseif id == user_code then - if trace_user then - head, current = user(head,current) - end - elseif id == math_code then - if trace_math then - head, current = math(head,current) - end - end - previous = current - current = getnext(current) - end - return head -end - -local function freed(cache) - local n = 0 - for k, v in next, cache do - free_node_list(v) - n = n + 1 - end - if n == 0 then - return 0, cache - else - return n, { } - end -end - -local function cleanup() - local hf, ng, np, nk, nw - nf, f_cache = freed(f_cache) - ng, g_cache = freed(g_cache) - np, p_cache = freed(p_cache) - nk, k_cache = freed(k_cache) - nw, w_cache = freed(w_cache) - nb, b_cache = freed(b_cache) - -- report_visualize("cache cleanup: %s fontkerns, %s skips, %s penalties, %s kerns, %s whatsits, %s boxes",nf,ng,np,nk,nw,nb) -end - -local function handler(head) - if usedfont then - starttiming(visualizers) - -- local l = texgetattribute(a_layer) - -- local v = texgetattribute(a_visual) - -- texsetattribute(a_layer,unsetvalue) - -- texsetattribute(a_visual,unsetvalue) - head = visualize(tonut(head)) - -- texsetattribute(a_layer,l) - -- texsetattribute(a_visual,v) - -- -- cleanup() - stoptiming(visualizers) - return tonode(head), true - else - return head, false - end -end - -visualizers.handler = handler - -function visualizers.box(n) - if usedfont then - starttiming(visualizers) - local box = getbox(n) - setfield(box,"list",visualize(getlist(box))) - stoptiming(visualizers) - return head, true - else - return head, false - end -end - -local last = nil -local used = nil - -local mark = { - "trace:1", "trace:2", "trace:3", - "trace:4", "trace:5", "trace:6", - "trace:7", -} - -local function markfonts(list) - for n in traverse_nodes(list) do - local id = getid(n) - if id == glyph_code then - local font = getfont(n) - local okay = used[font] - if not okay then - last = last + 1 - okay = mark[last] - used[font] = okay - end - setcolor(n,okay) - elseif id == hlist_code or id == vlist_code then - markfonts(getlist(n)) - end - end -end - -function visualizers.markfonts(list) - last, used = 0, { } - markfonts(type(n) == "number" and getlist(getbox(n)) or n) -end - -luatex.registerstopactions(cleanup) - -statistics.register("visualization time",function() - if enabled then - -- cleanup() -- in case we don't don't do it each time - return format("%s seconds",statistics.elapsedtime(visualizers)) - end -end) - --- interface - -local implement = interfaces.implement - -implement { name = "setvisual", arguments = "string", actions = visualizers.setvisual } -implement { name = "getvisual", arguments = "string", actions = { setvisual, context } } -implement { name = "setvisuallayer", arguments = "string", actions = visualizers.setlayer } -implement { name = "markvisualfonts", arguments = "integer", actions = visualizers.markfonts } -implement { name = "setvisualfont", arguments = "integer", actions = visualizers.setfont } - |