diff options
Diffstat (limited to 'tex/context/base/page-str.lua')
-rw-r--r-- | tex/context/base/page-str.lua | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/tex/context/base/page-str.lua b/tex/context/base/page-str.lua new file mode 100644 index 000000000..c4d1957c3 --- /dev/null +++ b/tex/context/base/page-str.lua @@ -0,0 +1,221 @@ +if not modules then modules = { } end modules ['page-str'] = { + version = 1.001, + comment = "companion to page-str.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- work in progresss .. unfinished + +local concat = table.concat + +local find_tail, write_node, free_node, copy_nodelist = node.slide, node.write, node.free, node.copy_list +local vpack_nodelist, hpack_nodelist = node.vpack, node.hpack +local texdimen, texbox = tex.dimen, tex.box + +local new_kern = nodes.kern +local new_glyph = nodes.glyph + +local trace_collecting = false trackers.register("streams.collecting", function(v) trace_collecting = v end) +local trace_flushing = false trackers.register("streams.flushing", function(v) trace_flushing = v end) + +streams = streams or { } + +local data, name, stack = { }, nil, { } + +function streams.enable(newname) + if newname == "default" then + name = nil + else + name = newname + end +end + +function streams.disable() + name = stack[#stack] +end + +function streams.start(newname) + table.insert(stack,name) + name = newname +end + +function streams.stop(newname) + name = table.remove(stack) +end + +function streams.collect(head,where) + if name and head and name ~= "default" then + local tail = node.slide(head) + local dana = data[name] + if not dana then + dana = { } + data[name] = dana + end + local last = dana[#dana] + if last then + local tail = find_tail(last) + tail.next, head.prev = head, tail + elseif last == false then + dana[#dana] = head + else + dana[1] = head + end + if trace_collecting then + logs.report("streams","appending snippet '%s' to slot %s",name,#dana) + end + return nil, true + else + return head, false + end +end + +function streams.push(thename) + if not thename or thename == "" then + thename = name + end + if thename and thename ~= "" then + local dana = data[thename] + if dana then + dana[#dana+1] = false + if trace_collecting then + logs.report("streams","pushing snippet '%s'",thename) + end + end + end +end + +function streams.flush(name,copy) -- problem: we need to migrate afterwards + local dana = data[name] + if dana then + local dn = #dana + if dn == 0 then + -- nothing to flush + elseif copy then + if trace_flushing then + logs.report("streams","flushing copies of %s slots of '%s'",dn,name) + end + for i=1,dn do + local di = dana[i] + if di then + write_node(copy_nodelist(di.list)) -- list, will be option + end + end + if copy then + data[name] = nil + end + else + if trace_flushing then + logs.report("streams","flushing %s slots of '%s'",dn,name) + end + for i=1,dn do + local di = dana[i] + if di then + write_node(di.list) -- list, will be option + di.list = nil + free_node(di) + end + end + end + end +end + +function streams.synchronize(list) -- this is an experiment ! + -- we don't optimize this as we want to trace in detail + list = aux.settings_to_array(list) + local max = 0 + if trace_flushing then + logs.report("streams","synchronizing list: %s",concat(list," ")) + end + for i=1,#list do + local dana = data[list[i]] + if dana then + local n = #dana + if n > max then + max = n + end + end + end + if trace_flushing then + logs.report("streams","maximum number of slots: %s",max) + end + for m=1,max do + local height, depth = 0, 0 + for i=1,#list do + local name = list[i] + local dana = data[name] + local slot = dana[m] + if slot then + local vbox = vpack_nodelist(slot) + local ht, dp = vbox.height, vbox.depth + if ht > height then + height = ht + end + if dp > depth then + depth = dp + end + dana[m] = vbox + if trace_flushing then + logs.report("streams","slot %s of '%s' is packed to height %s and depth %s",m,name,ht,dp) + end + end + end + if trace_flushing then + logs.report("streams","slot %s has max height %s and max depth %s",m,height,depth) + end + local strutht, strutdp = texdimen.globalbodyfontstrutheight, texdimen.globalbodyfontstrutdepth + local struthtdp = strutht + strutdp + for i=1,#list do + local name = list[i] + local dana = data[name] + local vbox = dana[m] + if vbox then + local delta_height = height - vbox.height + local delta_depth = depth - vbox.depth + if delta_height > 0 or delta_depth > 0 then + if false then + -- actually we need to add glue and repack + vbox.height, vbox.depth = height, depth + if trace_flushing then + logs.report("streams","slot %s of '%s' with delta (%s,%s) is compensated",m,i,delta_height,delta_depth) + end + else + -- this is not yet ok as we also need to keep an eye on vertical spacing + -- so we might need to do some splitting or whatever + local tail = vbox.list and find_tail(vbox.list) + local n, delta = 0, delta_height -- for tracing + while delta > 0 do + -- we need to add some interline penalties + local line = copy_nodelist(tex.box.strutbox) + line.height, line.depth = strutht, strutdp + if tail then + tail.next, line.prev = line, tail + end + tail = line + n, delta = n +1, delta - struthtdp + end + dana[m] = vpack_nodelist(vbox.list) + vbox.list = nil + free_node(vbox) + if trace_flushing then + logs.report("streams","slot %s:%s with delta (%s,%s) is compensated by %s lines",m,i,delta_height,delta_depth,n) + end + end + end + else + -- make dummy + end + end + end +end + +tasks.appendaction("mvlbuilders", "normalizers", "streams.collect") + +tasks.disableaction("mvlbuilders", "streams.collect") + +function streams.initialize() + tasks.enableaction ("mvlbuilders", "streams.collect") +end + +-- todo: remove empty last { }'s |