summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/mkxl/typo-bld.lmt
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkxl/typo-bld.lmt')
-rw-r--r--Master/texmf-dist/tex/context/base/mkxl/typo-bld.lmt414
1 files changed, 414 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkxl/typo-bld.lmt b/Master/texmf-dist/tex/context/base/mkxl/typo-bld.lmt
new file mode 100644
index 00000000000..599106ccd61
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkxl/typo-bld.lmt
@@ -0,0 +1,414 @@
+if modules then modules = { } end modules ['typo-bld'] = { -- was node-par
+ version = 1.001,
+ comment = "companion to typo-bld.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- no need for nuts in the one-line demo (that might move anyway)
+
+local insert, remove = table.insert, table.remove
+
+builders = builders or { }
+local builders = builders
+
+builders.paragraphs = builders.paragraphs or { }
+local parbuilders = builders.paragraphs
+
+parbuilders.constructors = parbuilders.constructors or { }
+local constructors = parbuilders.constructors
+
+constructors.names = constructors.names or { }
+local names = constructors.names
+
+constructors.numbers = constructors.numbers or { }
+local numbers = constructors.numbers
+
+constructors.methods = constructors.methods or { }
+local methods = constructors.methods
+
+local a_parbuilder = attributes.numbers['parbuilder'] or 999 -- why 999
+constructors.attribute = a_parbuilder
+
+local unsetvalue = attributes.unsetvalue
+local texsetattribute = tex.setattribute
+local texnest = tex.nest
+local texlists = tex.lists
+
+local texget = tex.get
+local texset = tex.set
+
+local texgetdimen = tex.getdimen
+
+local nodes = nodes
+local nodeidstostring = nodes.idstostring
+local nodepool = nodes.pool
+local new_baselineskip = nodepool.baselineskip
+local new_lineskip = nodepool.lineskip
+local insert_node_before = nodes.insert_before
+local hpack_node = nodes.hpack
+
+local nuts = nodes.nuts
+local tonode = nodes.tonode
+local tonut = nodes.tonut
+local count_nodes = nuts.countall
+local getattr = nuts.getattr
+
+local starttiming = statistics.starttiming
+local stoptiming = statistics.stoptiming
+
+local registercallback = callbacks.register
+
+storage.register("builders/paragraphs/constructors/names", names, "builders.paragraphs.constructors.names")
+storage.register("builders/paragraphs/constructors/numbers", numbers, "builders.paragraphs.constructors.numbers")
+
+local trace_page_builder = false trackers.register("builders.page", function(v) trace_page_builder = v end)
+local trace_vbox_builder = false trackers.register("builders.vbox", function(v) trace_vbox_builder = v end)
+local trace_post_builder = false trackers.register("builders.post", function(v) trace_post_builder = v end)
+
+local report_page_builder = logs.reporter("builders","page")
+local report_vbox_builder = logs.reporter("builders","vbox")
+local report_par_builder = logs.reporter("builders","par")
+
+local mainconstructor = nil -- not stored in format
+local nofconstructors = 0
+local stack = { }
+
+function constructors.define(name)
+ nofconstructors = nofconstructors + 1
+ names[nofconstructors] = name
+ numbers[name] = nofconstructors
+end
+
+function constructors.set(name) --- will go
+ if name then
+ mainconstructor = numbers[name] or unsetvalue
+ else
+ mainconstructor = stack[#stack] or unsetvalue
+ end
+ texsetattribute(a_parbuilder,mainconstructor)
+ if mainconstructor ~= unsetvalue then
+ constructors.enable()
+ end
+end
+
+function constructors.start(name)
+ local number = numbers[name]
+ insert(stack,number)
+ mainconstructor = number or unsetvalue
+ texsetattribute(a_parbuilder,mainconstructor)
+ if mainconstructor ~= unsetvalue then
+ constructors.enable()
+ end
+ -- report_par_builder("start %a",name)
+end
+
+function constructors.stop()
+ remove(stack)
+ mainconstructor = stack[#stack] or unsetvalue
+ texsetattribute(a_parbuilder,mainconstructor)
+ if mainconstructor == unsetvalue then
+ constructors.disable()
+ end
+ -- report_par_builder("stop")
+end
+
+-- return values:
+--
+-- true : tex will break itself
+-- false : idem but dangerous
+-- head : list of valid vmode nodes with last being hlist
+
+function constructors.handler(head,followed_by_display)
+ if type(head) == "boolean" then
+ return head
+ else
+ local attribute = getattr(head,a_parbuilder) -- or mainconstructor
+ if attribute then
+ local method = names[attribute]
+ if method then
+ local handler = methods[method]
+ if handler then
+ return handler(head,followed_by_display)
+ else
+ report_par_builder("contructor method %a is not defined",tostring(method))
+ return true -- let tex break
+ end
+ end
+ end
+ return true -- let tex break
+ end
+end
+
+-- just for testing
+
+function constructors.methods.default(head,followed_by_display)
+ return true -- let tex break
+end
+
+-- also for testing (now also surrounding spacing done)
+
+function parbuilders.constructors.methods.oneline(head,followed_by_display)
+ -- when needed we will turn this into a helper
+ local t = texnest[texnest.ptr]
+ local h = hpack_node(head)
+ local d = texget("baselineskip",false) - t.prevdepth - h.height
+ t.prevdepth = h.depth
+ t.prevgraf = 1
+ if d < texget("lineskiplimit") then
+ return insert_node_before(h,h,new_lineskip(texget("lineskip",false))) -- no stretch etc
+ else
+ return insert_node_before(h,h,new_baselineskip(d))
+ end
+end
+
+-- It makes no sense to have a sequence here as we already have
+-- pre and post hooks and only one parbuilder makes sense, so no:
+--
+-- local actions = nodes.tasks.actions("parbuilders")
+--
+-- yet ... maybe some day.
+
+local actions = constructors.handler
+local enabled = false
+
+local function processor(head,followed_by_display)
+ -- todo: not again in otr so we need to flag
+ if enabled then
+ starttiming(parbuilders)
+ head = tonut(head)
+ head = actions(head,followed_by_display)
+ head = tonode(head)
+ stoptiming(parbuilders)
+ return head
+ else
+ return true -- let tex do the work
+ end
+end
+
+function constructors.enable () enabled = true end
+function constructors.disable() enabled = false end
+
+registercallback('linebreak_filter', processor, "breaking paragraps into lines")
+
+statistics.register("linebreak processing time", function()
+ return statistics.elapsedseconds(parbuilders)
+end)
+
+-- todo: move from nodes.builders to builders
+
+nodes.builders = nodes.builder or { }
+local builders = nodes.builders
+
+local vboxactions = nodes.tasks.actions("vboxbuilders")
+
+function builders.vpack_filter(head,groupcode,size,packtype,maxdepth,direction)
+ local done = false
+ if head then
+ starttiming(builders)
+ head = tonut(head)
+ if trace_vbox_builder then
+ local before = count_nodes(head)
+ head, done = vboxactions(head,groupcode,size,packtype,maxdepth,direction)
+ local after = count_nodes(head)
+ nodes.processors.tracer("vpack",head,groupcode,before,after,done)
+ else
+ head, done = vboxactions(head,groupcode)
+ end
+ head = tonode(head)
+ stoptiming(builders)
+ end
+ return head, done
+end
+
+-- This one is special in the sense that it has no head and we operate on the mlv. Also,
+-- we need to do the vspacing last as it removes items from the mvl.
+
+local pageactions = nodes.tasks.actions("mvlbuilders")
+----- lineactions = nodes.tasks.actions("linebuilders")
+
+local function report(groupcode,head)
+ report_page_builder("trigger: %s",groupcode)
+ report_page_builder(" vsize : %p",texget("vsize"))
+ report_page_builder(" pagegoal : %p",texget("pagegoal"))
+ report_page_builder(" pagetotal: %p",texget("pagetotal"))
+ report_page_builder(" list : %s",head and nodeidstostring(head) or "<empty>")
+end
+
+-- check why box is called before after_linebreak .. maybe make categories and
+-- call 'm less
+
+-- this will be split into contribute_filter for these 4 so at some point
+-- the check can go away
+
+-- Todo: contrib_head can be any head (kind of) not per se the page one so maybe I will
+-- intercept that in the engine with page_contribute_head or so.
+
+function builders.buildpage_filter(groupcode)
+ local head = texlists.contribute_head
+ if head then
+ local done = false
+ -- called quite often ... maybe time to remove timing
+ starttiming(builders)
+ if trace_page_builder then
+ report(groupcode,head)
+ end
+ head, done = pageactions(head,groupcode)
+ stoptiming(builders)
+ -- -- doesn't work here (not passed on?)
+ -- texset("pagegoal,texget("vsize") - texgetdimen("d_page_floats_inserted_top") - texgetdimen("d_page_floats_inserted_bottom")
+ texlists.contribute_head = head or nil -- needs checking
+ -- tex.setlist("contribute_head",head,head and nodes.tail(head))
+ return done and head or true -- no return value needed
+ else
+ -- happens quite often
+ if trace_page_builder then
+ report(groupcode)
+ end
+-- return nil, false -- no return value needed
+ return nil
+ end
+end
+
+registercallback('vpack_filter', builders.vpack_filter, "vertical spacing etc")
+registercallback('buildpage_filter', builders.buildpage_filter, "vertical spacing etc (mvl)")
+
+statistics.register("v-node processing time", function()
+ return statistics.elapsedseconds(builders)
+end)
+
+local implement = interfaces.implement
+
+implement { name = "defineparbuilder", actions = constructors.define, arguments = "string" }
+implement { name = "setparbuilder", actions = constructors.set, arguments = "string" }
+implement { name = "startparbuilder", actions = constructors.start, arguments = "string" }
+implement { name = "stopparbuilder", actions = constructors.stop }
+implement { name = "enableparbuilder", actions = constructors.enable }
+implement { name = "disableparbuilder", actions = constructors.disable }
+
+-- Here are some tracers:
+
+local nuts = nodes.nuts
+local tonut = nodes.tonut
+local setcolor = nodes.tracers.colors.set
+local listtoutf = nodes.listtoutf
+local new_kern = nuts.pool.kern
+local new_rule = nuts.pool.rule
+local hpack = nuts.hpack
+local getheight = nuts.getheight
+local getdepth = nuts.getdepth
+local getdirection = nuts.getdirection
+local getlist = nuts.getlist
+local setwidth = nuts.setwidth
+local setdirection = nuts.setdirection
+local setlink = nuts.setlink
+local tonode = nuts.tonode
+
+local list = { }
+
+local report_quality = logs.reporter("pack quality")
+
+-- overflow|badness w h d dir
+
+local function vpack_quality(how,n,detail,first,last,filename)
+ if last <= 0 then
+ report_quality("%s vbox",how)
+ elseif first > 0 and first < last then
+ report_quality("%s vbox at line %i - %i in file %a",how,first,last,filename or "?")
+ else
+ report_quality("%s vbox at line %i in file %a",how,filename or "?",last)
+ end
+ list[#list+1] = { "hbox", how, filename, first, last, how }
+end
+
+trackers.register("builders.vpack.quality",function(v)
+ registercallback("vpack_quality",v and vpack_quality or nil,"check vpack quality")
+end)
+
+local report = false
+local show = false
+
+local function hpack_quality(how,detail,n,first,last,filename)
+ n = tonut(n)
+ if report then
+ local str = listtoutf(getlist(n),"",true,nil,true)
+ if last <= 0 then
+ report_quality("%s hbox: %s",how,str)
+ elseif first > 0 and first < last then
+ report_quality("%s hbox at line %i - %i in file %a: %s",how,first,last,filename or "?",str)
+ else
+ report_quality("%s hbox at line %i in file %a: %s",how,last,filename or "?",str)
+ end
+ list[#list+1] = { "hbox", how, filename, first, last, str }
+ end
+ if show then
+ local width = 2*65536
+ local height = getheight(n)
+ local depth = getdepth(n)
+ local direction = getdirection(n)
+ if height < 4*65526 then
+ height = 4*65526
+ end
+ if depth < 2*65526 then
+ depth = 2*65526
+ end
+ local rule = new_rule(width,height,depth)
+ setdirection(rule,direction)
+ if how == "overfull" then
+ setcolor(rule,"red")
+ local kern = new_kern(-detail)
+ setlink(kern,rule)
+ rule = kern
+ elseif how == "underfull" then
+ setcolor(rule,"blue")
+ elseif how == "loose" then
+ setcolor(rule,"magenta")
+ elseif how == "tight" then
+ setcolor(rule,"cyan")
+ end
+ rule = hpack(rule)
+ setwidth(rule,0)
+ setdirection(rule,direction)
+ return tonode(rule) -- can be a nut
+ end
+end
+
+trackers.register("builders.hpack.quality",function(v)
+ report = v
+ registercallback("hpack_quality",(report or show) and hpack_quality or nil,"check hpack quality")
+end)
+
+trackers.register("builders.hpack.overflow",function(v)
+ show = v
+ registercallback("hpack_quality",(report or show) and hpack_quality or nil,"check hpack quality")
+end)
+
+statistics.register("quality reports", function()
+ local n = #list
+ if n > 0 then
+ local t = table.setmetatableindex("number")
+ local fw = 0
+ local hw = 0
+ for i=1,n do
+ local f = list[i][1]
+ local h = list[i][2]
+ if #f > fw then
+ fw = #f
+ end
+ if #h > hw then
+ hw = #h
+ end
+ t[h] = t[h] + 1
+ end
+ logs.startfilelogging(report_quality)
+ for i=1,n do
+ local l = list[i]
+ report_quality("%-" .. fw .. "s [%04i - %04i] : %-" .. hw .. "s %s : %s",file.basename(l[3]),l[4],l[5],l[2],l[1],l[6])
+ end
+ logs.stopfilelogging()
+ report_quality()
+ report_quality("%i entries added to the log file : %s",n,table.sequenced(t))
+ report_quality()
+ end
+end)