summaryrefslogtreecommitdiff
path: root/tex/context/base/trac-vis.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/trac-vis.lua')
-rw-r--r--tex/context/base/trac-vis.lua234
1 files changed, 188 insertions, 46 deletions
diff --git a/tex/context/base/trac-vis.lua b/tex/context/base/trac-vis.lua
index aff044921..556dc1347 100644
--- a/tex/context/base/trac-vis.lua
+++ b/tex/context/base/trac-vis.lua
@@ -24,6 +24,9 @@ local format = string.format
-- 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.
+
-- todo: global switch (so no attributes)
-- todo: maybe also xoffset, yoffset of glyph
-- todo: inline concat (more efficient)
@@ -32,10 +35,12 @@ local nodecodes = nodes.nodecodes
local disc_code = nodecodes.disc
local kern_code = nodecodes.kern
local glyph_code = nodecodes.glyph
+local disc_code = nodecodes.disc
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 kerncodes = nodes.kerncodes
local font_kern_code = kerncodes.fontkern
@@ -60,7 +65,9 @@ local free_node = node.free
local free_node_list = node.flush_list
local has_attribute = node.has_attribute
local set_attribute = node.set_attribute
+local unset_attribute = node.unset_attribute
local insert_before = node.insert_before
+local insert_after = node.insert_after
local fast_hpack = nodes.fasthpack
local tex_attribute = tex.attribute
@@ -105,28 +112,39 @@ local bit = number.bit
local setbit = number.setbit
local clearbit = number.clearbit
-local trace_hbox -- 1
-local trace_vbox -- 2
-local trace_kern -- 4
-local trace_glue -- 8
-local trace_penalty -- 16
-local trace_fontkern -- 32
+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 report_visualize = logs.reporter("visualize")
local modes = {
- hbox = 1,
- vbox = 2,
- kern = 4,
- glue = 8,
- penalty = 16,
- fontkern = 32,
+ hbox = 1,
+ vbox = 2,
+ vtop = 4,
+ kern = 8,
+ glue = 16,
+ penalty = 32,
+ fontkern = 64,
+ strut = 128,
+ whatsit = 256,
+ glyph = 512,
}
+local makeup_modes = { "hbox", "vbox", "vtop", "kern", "glue", "penalty" }
+local all_modes = { "hbox", "vbox", "vtop", "kern", "glue", "penalty", "fontkern", "whatsit", "glyph" }
+
local usedfont, exheight, emwidth
-local l_penalty, l_glue, l_kern, l_fontkern, l_hbox, l_vbox
+local l_penalty, l_glue, l_kern, l_fontkern, l_hbox, l_vbox, l_vtop, l_strut, l_whatsit, l_glyph
local enabled = false
+local layers = { }
function visualizers.setfont(id)
usedfont = id or current_font()
@@ -138,17 +156,15 @@ local function setvisual(n,a,what) -- this will become more efficient when we ha
if not n or n == "reset" then
return unsetvalue
elseif n == "makeup" then
- a = setvisual("hbox",a)
- a = setvisual("vbox",a)
- a = setvisual("kern",a)
- a = setvisual("glue",a)
- a = setvisual("penalty",a)
+ for i=1,#makeup_modes do
+ a = setvisual(makeup_modes[i],a)
+ end
elseif n == "all" then
if what == false then
return unsetvalue
else
- for k, v in next, modes do
- a = setvisual(k,a)
+ for i=1,#all_modes do
+ a = setvisual(all_modes[i],a)
end
end
else
@@ -176,7 +192,6 @@ local function setvisual(n,a,what) -- this will become more efficient when we ha
-- we use a narrow monospaced font
visualizers.setfont(fonts.definers.define { name = "lmmonoltcond10regular", size = tex.sp("4pt") })
end
- local layers = { }
for mode, value in next, modes do
local tag = format("v_%s",mode)
attributes.viewerlayers.define {
@@ -188,12 +203,16 @@ local function setvisual(n,a,what) -- this will become more efficient when we ha
}
layers[mode] = attributes.viewerlayers.register(tag,true)
end
- l_penalty = layers.penalty
+ 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_hbox = layers.hbox
- l_vbox = layers.vbox
+ l_strut = layers.strut
+ l_whatsit = layers.whatsit
+ l_glyph = layers.glyph
nodes.tasks.enableaction("shipouts","nodes.visualizers.handler")
report_visualize("enabled")
enabled = true
@@ -205,7 +224,12 @@ function visualizers.setvisual(n)
tex_attribute[a_visual] = setvisual(n,tex_attribute[a_visual])
end
+function visualizers.setlayer(n)
+ tex_attribute[a_layer] = layers[n] or unsetvalue
+end
+
commands.setvisual = visualizers.setvisual
+commands.setlayer = visualizers.setlayer
function commands.visual(n)
context(setvisual(n,0))
@@ -230,6 +254,7 @@ 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_positive_d = "trace:db"
local c_negative_d = "trace:dr"
@@ -238,6 +263,7 @@ 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 function sometext(str,layer,color)
local text = fast_hpack_string(str,usedfont)
@@ -291,15 +317,29 @@ local function fontkern(head,current)
info.depth = 0
f_cache[kern] = info
end
- head, current = insert_before(head,current,copy_list(info))
- return head, current.next
+ head = insert_before(head,current,copy_list(info))
+ return head, current
end
--- cache baseline
+local w_cache = { }
+
+local function whatsit(head,current)
+ local what = current.subtype
+ local info = w_cache[what]
+ if info then
+ -- print("hit whatsit")
+ else
+ local info = sometext(format("W:%s",what),usedfont)
+ set_attribute(info,a_layer,l_whatsit)
+ w_cache[what] = info
+ end
+ head, current = insert_after(head,current,copy_list(info))
+ return head, current
+end
local b_cache
-local function ruledbox(head, current, vertical)
+local function ruledbox(head,current,vertical,layer)
local wd = current.width
if wd ~= 0 then
local ht, dp = current.height, current.depth
@@ -348,10 +388,13 @@ local function ruledbox(head, current, vertical)
info.width = 0
info.height = 0
info.depth = 0
- set_attribute(info,a_layer,vertical and l_vbox or l_hbox)
+ set_attribute(info,a_layer,layer)
local info = concat_nodes {
- info,
+-- info,
+-- current,
current,
+ new_kern(-wd),
+ info,
}
info = fast_hpack(info)
if vertical then
@@ -375,6 +418,59 @@ local function ruledbox(head, current, vertical)
end
end
+local function ruledglyph(head,current)
+ local wd = current.width
+ if wd ~= 0 then
+ local ht, dp = current.height, current.depth
+ local next, prev = current.next, current.prev
+ current.next, current.prev = nil, nil
+ local linewidth = .05 * emwidth
+ local baseline
+ if dp ~= 0 and ht ~= 0 then
+ baseline = new_rule(wd-2*linewidth,linewidth,0)
+ end
+ local doublelinewidth = 2*linewidth
+ local info = concat_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,
+ }
+ setlistcolor(info,c_glyph)
+ setlisttransparency(info,c_glyph_d)
+ info = fast_hpack(info)
+ info.width = 0
+ info.height = 0
+ info.depth = 0
+ set_attribute(info,a_layer,l_glyph)
+ local info = concat_nodes {
+ current,
+ new_kern(-wd),
+ info,
+ }
+ info = fast_hpack(info)
+ info.width = wd
+ if next then
+ info.next = next
+ next.prev = info
+ end
+ if prev then
+ info.prev = prev
+ 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 = {
@@ -494,10 +590,14 @@ end
local function visualize(head,vertical)
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 current = head
local prev_trace_fontkern = nil
local attr = unsetvalue
@@ -509,21 +609,50 @@ local function visualize(head,vertical)
if not a 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
else
- trace_hbox = hasbit(a,1)
- trace_vbox = hasbit(a,2)
- trace_kern = hasbit(a,4)
- trace_glue = hasbit(a,8)
- trace_penalty = hasbit(a,16)
- trace_fontkern = hasbit(a,32)
+ 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)
end
attr = a
end
- if id == kern_code then
+ if trace_strut then
+ set_attribute(current,a_layer,l_strut)
+ elseif id == glyph_code then
+ if trace_glyph then
+ head, current = ruledglyph(head,current)
+ end
+ elseif id == disc_code then
+ if trace_glyph then
+ local pre = current.pre
+ if pre then
+ current.pre = ruledglyph(pre,pre)
+ end
+ local post = current.post
+ if post then
+ current.post = ruledglyph(post,post)
+ end
+ local replace = current.replace
+ if replace then
+ current.replace = ruledglyph(replace,replace)
+ end
+ end
+ elseif id == kern_code then
local subtype = current.subtype
-- tricky ... we don't copy the trace attribute in node-inj (yet)
if subtype == font_kern_code or has_attribute(current,a_fontkern) then
@@ -538,7 +667,7 @@ local function visualize(head,vertical)
elseif id == glue_code then
local content = current.leader
if content then
- current.leaders = visualize(content,false)
+ current.leader = visualize(content,false)
elseif trace_glue then
head, current = ruledglue(head,current,vertical)
end
@@ -556,15 +685,21 @@ local function visualize(head,vertical)
current.list = visualize(content,false)
end
if trace_hbox then
- head, current = ruledbox(head,current,false)
+ head, current = ruledbox(head,current,false,l_hbox)
end
elseif id == vlist_code then
local content = current.list
if content then
current.list = visualize(content,true)
end
- if trace_vbox then
- head, current = ruledbox(head,current,true)
+ if trace_vtop then
+ head, current = ruledbox(head,current,true,l_vtop)
+ elseif trace_vbox then
+ head, current = ruledbox(head,current,true,l_vbox)
+ end
+ elseif id == whatsit_code then
+ if trace_whatsit then
+ head, current = whatsit(head,current)
end
end
current = current.next
@@ -586,30 +721,37 @@ local function freed(cache)
end
local function cleanup()
- local hf, ng, np, nk
+ 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)
if b_cache then
free_node_list(b_cache)
b_cache = nil
end
- -- report_visualize("cache: %s fontkerns, %s skips, %s penalties, %s kerns",nf,ng,np,nk)
+ -- report_visualize("cache: %s fontkerns, %s skips, %s penalties, %s kerns, %s whatsits",nf,ng,np,nk,nw)
end
function visualizers.handler(head)
if usedfont then
starttiming(visualizers)
+ -- local l = tex_attribute[a_layer]
+ -- local v = tex_attribute[a_visual]
+ -- tex_attribute[a_layer] = unsetvalue
+ -- tex_attribute[a_visual] = unsetvalue
head = visualize(head)
--- cleanup()
+ -- tex_attribute[a_layer] = l
+ -- tex_attribute[a_visual] = v
+ -- -- cleanup()
stoptiming(visualizers)
end
return head, false
end
-function nodes.visualizers.box(n)
- tex.box[n].list = nodes.visualizers.handler(tex.box[n].list)
+function visualizers.box(n)
+ tex.box[n].list = visualizers.handler(tex.box[n].list)
end
statistics.register("visualization time",function()