summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/tabl-xtb.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/tabl-xtb.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/tabl-xtb.lua986
1 files changed, 986 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/context/base/tabl-xtb.lua b/Master/texmf-dist/tex/context/base/tabl-xtb.lua
new file mode 100644
index 00000000000..395d65a032c
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/tabl-xtb.lua
@@ -0,0 +1,986 @@
+if not modules then modules = { } end modules ['tabl-xtb'] = {
+ version = 1.001,
+ comment = "companion to tabl-xtb.mkvi",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[
+
+This table mechanism is a combination between TeX and Lua. We do process
+cells at the TeX end and inspect them at the Lua end. After some analysis
+we have a second pass using the calculated widths, and if needed cells
+will go through a third pass to get the heights right. This last pass is
+avoided when possible which is why some code below looks a bit more
+complex than needed. The reason for such optimizations is that each cells
+is actually a framed instance and because tables like this can be hundreds
+of pages we want to keep processing time reasonable.
+
+To a large extend the behaviour is comparable with the way bTABLE/eTABLE
+works and there is a module that maps that one onto this one. Eventually
+this mechamism will be improved so that it can replace its older cousin.
+
+]]--
+
+-- todo: use linked list instead of r/c array
+
+local texdimen = tex.dimen
+local texcount = tex.count
+local texbox = tex.box
+local texsetcount = tex.setcount
+local texsetdimen = tex.setdimen
+
+local format = string.format
+local concat = table.concat
+local points = number.points
+
+local context = context
+local context_beginvbox = context.beginvbox
+local context_endvbox = context.endvbox
+local context_blank = context.blank
+local context_nointerlineskip = context.nointerlineskip
+
+local variables = interfaces.variables
+
+local setmetatableindex = table.setmetatableindex
+local settings_to_hash = utilities.parsers.settings_to_hash
+
+local copy_node_list = node.copy_list
+local hpack_node_list = node.hpack
+local vpack_node_list = node.vpack
+local slide_node_list = node.slide
+local flush_node_list = node.flush_list
+
+local nodepool = nodes.pool
+
+local new_glue = nodepool.glue
+local new_kern = nodepool.kern
+local new_penalty = nodepool.penalty
+
+local v_stretch = variables.stretch
+local v_normal = variables.normal
+local v_width = variables.width
+local v_height = variables.height
+local v_repeat = variables["repeat"]
+local v_max = variables.max
+local v_fixed = variables.fixed
+
+local xtables = { }
+typesetters.xtables = xtables
+
+local trace_xtable = false
+local report_xtable = logs.reporter("xtable")
+
+trackers.register("xtable.construct", function(v) trace_xtable = v end)
+
+local null_mode = 0
+local head_mode = 1
+local foot_mode = 2
+local more_mode = 3
+local body_mode = 4
+
+local namedmodes = { [0] =
+ "null",
+ "head",
+ "foot",
+ "next",
+ "body",
+}
+
+local stack, data = { }, nil
+
+function xtables.create(settings)
+ table.insert(stack,data)
+ local rows = { }
+ local widths = { }
+ local heights = { }
+ local depths = { }
+ local spans = { }
+ local distances = { }
+ local autowidths = { }
+ local modes = { }
+ local fixedrows = { }
+ local fixedcolumns = { }
+ local frozencolumns = { }
+ local options = { }
+ data = {
+ rows = rows,
+ widths = widths,
+ heights = heights,
+ depths = depths,
+ spans = spans,
+ distances = distances,
+ modes = modes,
+ autowidths = autowidths,
+ fixedrows = fixedrows,
+ fixedcolumns = fixedcolumns,
+ frozencolumns = frozencolumns,
+ options = options,
+ nofrows = 0,
+ nofcolumns = 0,
+ currentrow = 0,
+ currentcolumn = 0,
+ settings = settings or { },
+ }
+ local function add_zero(t,k)
+ t[k] = 0
+ return 0
+ end
+ local function add_table(t,k)
+ local v = { }
+ t[k] = v
+ return v
+ end
+ local function add_cell(row,c)
+ local cell = {
+ nx = 0,
+ ny = 0,
+ list = false,
+ }
+ row[c] = cell
+ if c > data.nofcolumns then
+ data.nofcolumns = c
+ end
+ return cell
+ end
+ local function add_row(rows,r)
+ local row = { }
+ setmetatableindex(row,add_cell)
+ rows[r] = row
+ if r > data.nofrows then
+ data.nofrows = r
+ end
+ return row
+ end
+ setmetatableindex(rows,add_row)
+ setmetatableindex(widths,add_zero)
+ setmetatableindex(heights,add_zero)
+ setmetatableindex(depths,add_zero)
+ setmetatableindex(distances,add_zero)
+ setmetatableindex(modes,add_zero)
+ setmetatableindex(fixedrows,add_zero)
+ setmetatableindex(fixedcolumns,add_zero)
+ setmetatableindex(options,add_table)
+ --
+ settings.columndistance = tonumber(settings.columndistance) or 0
+ settings.rowdistance = tonumber(settings.rowdistance) or 0
+ settings.leftmargindistance = tonumber(settings.leftmargindistance) or 0
+ settings.rightmargindistance = tonumber(settings.rightmargindistance) or 0
+ settings.options = settings_to_hash(settings.option)
+ settings.textwidth = tonumber(settings.textwidth) or tex.hsize
+ settings.lineheight = tonumber(settings.lineheight) or texdimen.lineheight
+ settings.maxwidth = tonumber(settings.maxwidth) or settings.textwidth/8
+ -- if #stack > 0 then
+ -- settings.textwidth = tex.hsize
+ -- end
+ data.criterium_v = 2 * data.settings.lineheight
+ data.criterium_h = .75 * data.settings.textwidth
+
+end
+
+function xtables.initialize_reflow_width(option)
+ local r = data.currentrow
+ local c = data.currentcolumn + 1
+ local drc = data.rows[r][c]
+ drc.nx = texcount.c_tabl_x_nx
+ drc.ny = texcount.c_tabl_x_ny
+ local distances = data.distances
+ local distance = texdimen.d_tabl_x_distance
+ if distance > distances[c] then
+ distances[c] = distance
+ end
+ if option and option ~= "" then
+ local options = settings_to_hash(option)
+ data.options[r][c] = options
+ if options[v_fixed] then
+ data.frozencolumns[c] = true
+ end
+ end
+ data.currentcolumn = c
+end
+
+-- local function rather_fixed(n)
+-- for n in node.
+
+function xtables.set_reflow_width()
+ local r = data.currentrow
+ local c = data.currentcolumn
+ local rows = data.rows
+ local row = rows[r]
+ while row[c].span do -- can also be previous row ones
+ c = c + 1
+ end
+ local tb = texbox.b_tabl_x
+ local drc = row[c]
+ --
+ drc.list = true -- we don't need to keep the content around as we're in trial mode (no: copy_node_list(tb))
+ --
+ local widths, width = data.widths, tb.width
+ if width > widths[c] then
+ widths[c] = width
+ end
+ local heights, height = data.heights, tb.height
+ if height > heights[r] then
+ heights[r] = height
+ end
+ local depths, depth = data.depths, tb.depth
+ if depth > depths[r] then
+ depths[r] = depth
+ end
+ --
+ local dimensionstate = texcount.frameddimensionstate
+ local fixedcolumns = data.fixedcolumns
+ local fixedrows = data.fixedrows
+ if dimensionstate == 1 then
+ if width > fixedcolumns[c] then -- how about a span here?
+ fixedcolumns[c] = width
+ end
+ elseif dimensionstate == 2 then
+ fixedrows[r] = height
+ elseif dimensionstate == 3 then
+ fixedrows[r] = height -- width
+ fixedcolumns[c] = width -- height
+ else -- probably something frozen, like an image -- we could parse the list
+ if width <= data.criterium_h and height >= data.criterium_v then
+ if width > fixedcolumns[c] then -- how about a span here?
+ fixedcolumns[c] = width
+ end
+ end
+ end
+ drc.dimensionstate = dimensionstate
+ --
+ local nx, ny = drc.nx, drc.ny
+ if nx > 1 or ny > 1 then
+ local spans = data.spans
+ local self = true
+ for y=1,ny do
+ for x=1,nx do
+ if self then
+ self = false
+ else
+ local ry = r + y - 1
+ local cx = c + x - 1
+ if y > 1 then
+ spans[ry] = true
+ end
+ rows[ry][cx].span = true
+ end
+ end
+ end
+ c = c + nx - 1
+ end
+ if c > data.nofcolumns then
+ data.nofcolumns = c
+ end
+ data.currentcolumn = c
+end
+
+function xtables.initialize_reflow_height()
+ local r = data.currentrow
+ local c = data.currentcolumn + 1
+ local rows = data.rows
+ local row = rows[r]
+ while row[c].span do -- can also be previous row ones
+ c = c + 1
+ end
+ data.currentcolumn = c
+ local widths = data.widths
+ local w = widths[c]
+ local drc = row[c]
+ for x=1,drc.nx-1 do
+ w = w + widths[c+x]
+ end
+ texdimen.d_tabl_x_width = w
+ local dimensionstate = drc.dimensionstate or 0
+ if dimensionstate == 1 or dimensionstate == 3 then
+ -- width was fixed so height is known
+ texcount.c_tabl_x_skip_mode = 1
+ elseif dimensionstate == 2 then
+ -- height is enforced
+ texcount.c_tabl_x_skip_mode = 1
+ elseif data.autowidths[c] then
+ -- width has changed so we need to recalculate the height
+ texcount.c_tabl_x_skip_mode = 0
+ else
+ texcount.c_tabl_x_skip_mode = 1
+ end
+end
+
+function xtables.set_reflow_height()
+ local r = data.currentrow
+ local c = data.currentcolumn
+ local rows = data.rows
+ local row = rows[r]
+-- while row[c].span do -- we could adapt drc.nx instead
+-- c = c + 1
+-- end
+ local tb = texbox.b_tabl_x
+ local drc = row[c]
+ if data.fixedrows[r] == 0 then -- and drc.dimensionstate < 2
+ local heights, height = data.heights, tb.height
+ if height > heights[r] then
+ heights[r] = height
+ end
+ local depths, depth = data.depths, tb.depth
+ if depth > depths[r] then
+ depths[r] = depth
+ end
+ end
+-- c = c + drc.nx - 1
+-- data.currentcolumn = c
+end
+
+function xtables.initialize_construct()
+ local r = data.currentrow
+ local c = data.currentcolumn + 1
+ local rows = data.rows
+ local row = rows[r]
+ while row[c].span do -- can also be previous row ones
+ c = c + 1
+ end
+ data.currentcolumn = c
+ local widths = data.widths
+ local heights = data.heights
+ local depths = data.depths
+ local w = widths[c]
+ local h = heights[r]
+ local d = depths[r]
+ local drc = row[c]
+ for x=1,drc.nx-1 do
+ w = w + widths[c+x]
+ end
+ for y=1,drc.ny-1 do
+ h = h + heights[r+y]
+ d = d + depths[r+y]
+ end
+ texdimen.d_tabl_x_width = w
+ texdimen.d_tabl_x_height = h + d
+ texdimen.d_tabl_x_depth = 0
+end
+
+function xtables.set_construct()
+ local r = data.currentrow
+ local c = data.currentcolumn
+ local rows = data.rows
+ local row = rows[r]
+-- while row[c].span do -- can also be previous row ones
+-- c = c + 1
+-- end
+ local drc = row[c]
+ -- this will change as soon as in luatex we can reset a box list without freeing
+ drc.list = copy_node_list(texbox.b_tabl_x)
+-- c = c + drc.nx - 1
+-- data.currentcolumn = c
+end
+
+local function showwidths(where,widths,autowidths)
+ local result = { }
+ for i=1,#widths do
+ result[#result+1] = format("%12s%s",points(widths[i]),autowidths[i] and "*" or " ")
+ end
+ return report_xtable("%s : %s",where,concat(result," "))
+end
+
+function xtables.reflow_width()
+ local nofrows = data.nofrows
+ local nofcolumns = data.nofcolumns
+ local rows = data.rows
+ for r=1,nofrows do
+ local row = rows[r]
+ for c=1,nofcolumns do
+ local drc = row[c]
+ if drc.list then
+ --- flush_node_list(drc.list)
+ drc.list = false
+ end
+ end
+ end
+ -- spread
+ local settings = data.settings
+ local options = settings.options
+ local maxwidth = settings.maxwidth
+ -- calculate width
+ local widths = data.widths
+ local distances = data.distances
+ local autowidths = data.autowidths
+ local fixedcolumns = data.fixedcolumns
+ local frozencolumns = data.frozencolumns
+ local width = 0
+ local distance = 0
+ local nofwide = 0
+ local widetotal = 0
+ local available = settings.textwidth - settings.leftmargindistance - settings.rightmargindistance
+ if trace_xtable then
+ showwidths("stage 1",widths,autowidths)
+ end
+ local noffrozen = 0
+ if options[v_max] then
+ for c=1,nofcolumns do
+ width = width + widths[c]
+ if width > maxwidth then
+ autowidths[c] = true
+ nofwide = nofwide + 1
+ widetotal = widetotal + widths[c]
+ end
+ if c < nofcolumns then
+ distance = distance + distances[c]
+ end
+ if frozencolumns[c] then
+ noffrozen = noffrozen + 1 -- brr, should be nx or so
+ end
+ end
+ else
+ for c=1,nofcolumns do -- also keep track of forced
+ local fixedwidth = fixedcolumns[c]
+ if fixedwidth > 0 then
+ widths[c] = fixedwidth
+ width = width + fixedwidth
+ else
+ width = width + widths[c]
+ if width > maxwidth then
+ autowidths[c] = true
+ nofwide = nofwide + 1
+ widetotal = widetotal + widths[c]
+ end
+ end
+ if c < nofcolumns then
+ distance = distance + distances[c]
+ end
+ if frozencolumns[c] then
+ noffrozen = noffrozen + 1 -- brr, should be nx or so
+ end
+ end
+ end
+ if trace_xtable then
+ showwidths("stage 2",widths,autowidths)
+ end
+ local delta = available - width - distance - (nofcolumns-1) * settings.columndistance
+ if delta == 0 then
+ -- nothing to be done
+ if trace_xtable then
+ report_xtable("perfect fit")
+ end
+ elseif delta > 0 then
+ -- we can distribute some
+ if not options[v_stretch] then
+ -- not needed
+ if trace_xtable then
+ report_xtable("too wide but no stretch, delta: %s",points(delta))
+ end
+ elseif options[v_width] then
+ local factor = delta / width
+ if trace_xtable then
+ report_xtable("proportional stretch, delta: %s, width: %s, factor: %s",
+ points(delta),points(width),factor)
+ end
+ for c=1,nofcolumns do
+ widths[c] = widths[c] + factor * widths[c]
+ end
+ else
+ -- frozen -> a column with option=fixed will not stretch
+ local extra = delta / (nofcolumns - noffrozen)
+ if trace_xtable then
+ report_xtable("normal stretch, delta: %s, extra: %s",
+ points(delta),points(extra))
+ end
+ for c=1,nofcolumns do
+ if not frozencolumns[c] then
+ widths[c] = widths[c] + extra
+ end
+ end
+ end
+ elseif nofwide > 0 then
+ while true do
+ done = false
+ local available = (widetotal + delta) / nofwide
+ if trace_xtable then
+ report_xtable("shrink check, total: %s, delta: %s, columns: %s, fixed: %s",
+ points(widetotal),points(delta),nofwide,points(available))
+ end
+ for c=1,nofcolumns do
+ if autowidths[c] and available >= widths[c] then
+ autowidths[c] = nil
+ nofwide = nofwide - 1
+ widetotal = widetotal - widths[c]
+ done = true
+ end
+ end
+ if not done then
+ break
+ end
+ end
+ -- maybe also options[v_width] here but tricky as width does not say
+ -- much about amount
+
+ if options[v_width] then -- not that much (we could have a clever vpack loop balancing .. no fun)
+ local factor = (widetotal + delta) / width
+ if trace_xtable then
+ report_xtable("proportional shrink used, total: %s, delta: %s, columns: %s, factor: %s",
+ points(widetotal),points(delta),nofwide,factor)
+ end
+ for c=1,nofcolumns do
+ if autowidths[c] then
+ widths[c] = factor * widths[c]
+ end
+ end
+ else
+ local available = (widetotal + delta) / nofwide
+ if trace_xtable then
+ report_xtable("normal shrink used, total: %s, delta: %s, columns: %s, fixed: %s",
+ points(widetotal),points(delta),nofwide,points(available))
+ end
+ for c=1,nofcolumns do
+ if autowidths[c] then
+ widths[c] = available
+ end
+ end
+ end
+ end
+ if trace_xtable then
+ showwidths("stage 3",widths,autowidths)
+ end
+ --
+ data.currentrow = 0
+ data.currentcolumn = 0
+end
+
+function xtables.reflow_height()
+ data.currentrow = 0
+ data.currentcolumn = 0
+ local settings = data.settings
+ if settings.options[v_height] then
+ local heights = data.heights
+ local depths = data.depths
+ local nofrows = data.nofrows
+ local totalheight = 0
+ local totaldepth = 0
+ for i=1,nofrows do
+ totalheight = totalheight + heights[i]
+ totalheight = totalheight + depths [i]
+ end
+ local total = totalheight + totaldepth
+ local leftover = settings.textheight - total
+ if leftover > 0 then
+ local leftheight = (totalheight / total ) * leftover / #heights
+ local leftdepth = (totaldepth / total ) * leftover / #depths
+ for i=1,nofrows do
+ heights[i] = heights[i] + leftheight
+ depths [i] = depths [i] + leftdepth
+ end
+ end
+ end
+end
+
+local function showspans(data)
+ local rows = data.rows
+ local modes = data.modes
+ local nofcolumns = data.nofcolumns
+ local nofrows = data.nofrows
+ for r=1,nofrows do
+ local line = { }
+ local row = rows[r]
+ for c=1,nofcolumns do
+ local cell =row[c]
+ if cell.list then
+ line[#line+1] = "list"
+ elseif cell.span then
+ line[#line+1] = "span"
+ else
+ line[#line+1] = "none"
+ end
+ end
+ report_xtable("%3d : %s : %s",r,namedmodes[modes[r]] or "----",concat(line," "))
+ end
+end
+
+function xtables.construct()
+ local rows = data.rows
+ local heights = data.heights
+ local depths = data.depths
+ local widths = data.widths
+ local spans = data.spans
+ local distances = data.distances
+ local modes = data.modes
+ local settings = data.settings
+ local nofcolumns = data.nofcolumns
+ local nofrows = data.nofrows
+ local columndistance = settings.columndistance
+ local rowdistance = settings.rowdistance
+ local leftmargindistance = settings.leftmargindistance
+ local rightmargindistance = settings.rightmargindistance
+ -- ranges can be mixes so we collect
+
+ if trace_xtable then
+ showspans(data)
+ end
+
+ local ranges = {
+ [head_mode] = { },
+ [foot_mode] = { },
+ [more_mode] = { },
+ [body_mode] = { },
+ }
+ for r=1,nofrows do
+ local m = modes[r]
+ if m == 0 then
+ m = body_mode
+ end
+ local range = ranges[m]
+ range[#range+1] = r
+ end
+ -- todo: hook in the splitter ... the splitter can ask for a chunk of
+ -- a certain size ... no longer a split memory issue then and header
+ -- footer then has to happen here too .. target height
+ local function packaged_column(r)
+ local row = rows[r]
+ local start = nil
+ local stop = nil
+ if leftmargindistance > 0 then
+ start = new_kern(leftmargindistance)
+ stop = start
+ end
+ local hasspan = false
+ for c=1,nofcolumns do
+ local drc = row[c]
+ if not hasspan then
+ hasspan = drc.span
+ end
+ local list = drc.list
+ if list then
+ list.shift = list.height + list.depth
+ list = hpack_node_list(list) -- is somehow needed
+ list.width = 0
+ list.height = 0
+ list.depth = 0
+ if start then
+ stop.next = list
+ list.prev = stop
+ else
+ start = list
+ end
+ stop = list -- one node anyway, so not needed: slide_node_list(list)
+ end
+ local step = widths[c]
+ if c < nofcolumns then
+ step = step + columndistance + distances[c]
+ end
+ local kern = new_kern(step)
+ if stop then
+ stop.prev = kern
+ stop.next = kern
+ else -- can be first spanning next row (ny=...)
+ start = kern
+ end
+ stop = kern
+ end
+ if start then
+ if rightmargindistance > 0 then
+ local kern = new_kern(rightmargindistance)
+ stop.next = kern
+ kern.prev = stop
+ -- stop = kern
+ end
+ return start, heights[r] + depths[r], hasspan
+ end
+ end
+ local function collect_range(range)
+ local result, nofr = { }, 0
+ local nofrange = #range
+ for i=1,#range do
+ local r = range[i]
+ -- local row = rows[r]
+ local list, size, hasspan = packaged_column(r)
+ if list then
+ if hasspan and nofr > 0 then
+ result[nofr][4] = true
+ end
+ nofr = nofr + 1
+ result[nofr] = {
+ hpack_node_list(list),
+ size,
+ i < nofrange and rowdistance > 0 and rowdistance or false, -- might move
+ false
+ }
+ end
+ end
+ return result
+ end
+ local body = collect_range(ranges[body_mode])
+ data.results = {
+ [head_mode] = collect_range(ranges[head_mode]),
+ [foot_mode] = collect_range(ranges[foot_mode]),
+ [more_mode] = collect_range(ranges[more_mode]),
+ [body_mode] = body,
+ }
+ if #body == 0 then
+ texsetcount("global","c_tabl_x_state",0)
+ texsetdimen("global","d_tabl_x_final_width",0)
+ else
+ texsetcount("global","c_tabl_x_state",1)
+ texsetdimen("global","d_tabl_x_final_width",body[1][1].width)
+ end
+end
+
+local function inject(row,copy,package)
+ local list = row[1]
+ if copy then
+ row[1] = copy_node_list(list)
+ end
+ if package then
+ context_beginvbox()
+ context(list)
+ context(new_kern(row[2]))
+ context_endvbox()
+ context_nointerlineskip() -- figure out a better way
+ if row[4] then
+ -- nothing as we have a span
+ elseif row[3] then
+ context_blank(row[3] .. "sp") -- why blank ?
+ else
+ context(new_glue(0))
+ end
+ else
+ context(list)
+ context(new_kern(row[2]))
+ if row[3] then
+ context(new_glue(row[3]))
+ end
+ end
+end
+
+local function total(row,distance)
+ local n = #row > 0 and rowdistance or 0
+ for i=1,#row do
+ local ri = row[i]
+ n = n + ri[2] + (ri[3] or 0)
+ end
+ return n
+end
+
+-- local function append(list,what)
+-- for i=1,#what do
+-- local l = what[i]
+-- list[#list+1] = l[1]
+-- local k = l[2] + (l[3] or 0)
+-- if k ~= 0 then
+-- list[#list+1] = new_kern(k)
+-- end
+-- end
+-- end
+
+local function spanheight(body,i)
+ local height, n = 0, 1
+ while true do
+ local bi = body[i]
+ if bi then
+ height = height + bi[2] + (bi[3] or 0)
+ if bi[4] then
+ n = n + 1
+ i = i + 1
+ else
+ break
+ end
+ else
+ break
+ end
+ end
+ return height, n
+end
+
+function xtables.flush(directives) -- todo split by size / no inbetween then .. glue list kern blank
+ local vsize = directives.vsize
+ local method = directives.method or v_normal
+ local settings = data.settings
+ local results = data.results
+ local rowdistance = settings.rowdistance
+ local head = results[head_mode]
+ local foot = results[foot_mode]
+ local more = results[more_mode]
+ local body = results[body_mode]
+ local repeatheader = settings.header == v_repeat
+ local repeatfooter = settings.footer == v_repeat
+ if vsize and vsize > 0 then
+ context_beginvbox()
+ local bodystart = data.bodystart or 1
+ local bodystop = data.bodystop or #body
+ if bodystart > 0 and bodystart <= bodystop then
+ local bodysize = vsize
+ local footsize = total(foot,rowdistance)
+ local headsize = total(head,rowdistance)
+ local moresize = total(more,rowdistance)
+ local firstsize, firstspans = spanheight(body,bodystart)
+ if bodystart == 1 then -- first chunk gets head
+ bodysize = bodysize - headsize - footsize
+ if headsize > 0 and bodysize >= firstsize then
+ for i=1,#head do
+ inject(head[i],repeatheader)
+ end
+ if rowdistance > 0 then
+ context(new_glue(rowdistance))
+ end
+ if not repeatheader then
+ results[head_mode] = { }
+ end
+ end
+ elseif moresize > 0 then -- following chunk gets next
+ bodysize = bodysize - footsize - moresize
+ if bodysize >= firstsize then
+ for i=1,#more do
+ inject(more[i],true)
+ end
+ if rowdistance > 0 then
+ context(new_glue(rowdistance))
+ end
+ end
+ elseif headsize > 0 and repeatheader then -- following chunk gets head
+ bodysize = bodysize - footsize - headsize
+ if bodysize >= firstsize then
+ for i=1,#head do
+ inject(head[i],true)
+ end
+ if rowdistance > 0 then
+ context(new_glue(rowdistance))
+ end
+ end
+ else -- following chunk gets nothing
+ bodysize = bodysize - footsize
+ end
+ if bodysize >= firstsize then
+ local i = bodystart
+ while i <= bodystop do -- room for improvement
+ local total, spans = spanheight(body,i)
+ local bs = bodysize - total
+ if bs > 0 then
+ bodysize = bs
+ for s=1,spans do
+ inject(body[i])
+ body[i] = nil
+ i = i + 1
+ end
+ bodystart = i
+ else
+ break
+ end
+ end
+ if bodystart > bodystop then
+ -- all is flushed and footer fits
+ if footsize > 0 then
+ if rowdistance > 0 then
+ context(new_glue(rowdistance))
+ end
+ for i=1,#foot do
+ inject(foot[i])
+ end
+ results[foot_mode] = { }
+ end
+ results[body_mode] = { }
+ texsetcount("global","c_tabl_x_state",0)
+ else
+ -- some is left so footer is delayed
+ -- todo: try to flush a few more lines
+ if repeatfooter and footsize > 0 then
+ if rowdistance > 0 then
+ context(new_glue(rowdistance))
+ end
+ for i=1,#foot do
+ inject(foot[i],true)
+ end
+ else
+ -- todo: try to fit more of body
+ end
+ texsetcount("global","c_tabl_x_state",2)
+ end
+ else
+ if firstsize > vsize then
+ -- get rid of the too large cell
+ for s=1,firstspans do
+ inject(body[bodystart])
+ body[bodystart] = nil
+ bodystart = bodystart + 1
+ end
+ end
+ texsetcount("global","c_tabl_x_state",2) -- 1
+ end
+ else
+ texsetcount("global","c_tabl_x_state",0)
+ end
+ data.bodystart = bodystart
+ data.bodystop = bodystop
+ context_endvbox()
+ else
+ if method == variables.split then
+ -- maybe also a non float mode with header/footer repeat although
+ -- we can also use a float without caption
+ for i=1,#head do
+ inject(head[i],false,true)
+ end
+ if #head > 0 and rowdistance > 0 then
+ context_blank(rowdistance .. "sp")
+ end
+ for i=1,#body do
+ inject(body[i],false,true)
+ end
+ if #foot > 0 and rowdistance > 0 then
+ context_blank(rowdistance .. "sp")
+ end
+ for i=1,#foot do
+ inject(foot[i],false,true)
+ end
+ else -- normal
+ context_beginvbox()
+ for i=1,#head do
+ inject(head[i])
+ end
+ if #head > 0 and rowdistance > 0 then
+ context(new_glue(rowdistance))
+ end
+ for i=1,#body do
+ inject(body[i])
+ end
+ if #foot > 0 and rowdistance > 0 then
+ context(new_glue(rowdistance))
+ end
+ for i=1,#foot do
+ inject(foot[i])
+ end
+ context_endvbox()
+ end
+ results[head_mode] = { }
+ results[body_mode] = { }
+ results[foot_mode] = { }
+ texsetcount("global","c_tabl_x_state",0)
+ end
+end
+
+function xtables.cleanup()
+ for mode, result in next, data.results do
+ for _, r in next, result do
+ flush_node_list(r[1])
+ end
+ end
+ data = table.remove(stack)
+end
+
+function xtables.next_row()
+ local r = data.currentrow + 1
+ data.modes[r] = texcount.c_tabl_x_mode
+ data.currentrow = r
+ data.currentcolumn = 0
+end
+
+-- eventually we might only have commands
+
+commands.x_table_create = xtables.create
+commands.x_table_reflow_width = xtables.reflow_width
+commands.x_table_reflow_height = xtables.reflow_height
+commands.x_table_construct = xtables.construct
+commands.x_table_flush = xtables.flush
+commands.x_table_cleanup = xtables.cleanup
+commands.x_table_next_row = xtables.next_row
+commands.x_table_init_reflow_width = xtables.initialize_reflow_width
+commands.x_table_init_reflow_height = xtables.initialize_reflow_height
+commands.x_table_init_construct = xtables.initialize_construct
+commands.x_table_set_reflow_width = xtables.set_reflow_width
+commands.x_table_set_reflow_height = xtables.set_reflow_height
+commands.x_table_set_construct = xtables.set_construct