View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update | 
|---|---|---|---|---|---|
| 0001010 | context | bug report | public | 2019-07-22 15:10 | 2019-07-22 15:10 | 
| Reporter | itoijala | Assigned To | |||
| Priority | normal | Severity | minor | Reproducibility | always | 
| Status | new | Resolution | open | ||
| Summary | 0001010: xtables stretch width | ||||
| Description | Using the options stretch and width can result in a table that does not take up the full \textwidth. This means that the content is shrunk further than necessary. I think this is due to a bug in xtables.reflow_width. I think the "width" in line 674 of tabl-xtb.lua should be widetotal instead, giving: local factor = (widetotal + delta) / widetotal This makes sense as the equation we want to solve is widetotal + delta = factor * widetotal  | ||||
| Steps To Reproduce | See the attached file. This includes a copy of the patched function that can be activated by removing some comment markers. It should be run as context xtables-demo.tex --trackers=xtable.construct --debug  | ||||
| Tags | No tags attached. | ||||
| 
		 | 
	
	  xtables-demo.tex (6,818 bytes)   
 
\startluacode
xtables = typesetters.xtables
local orig = xtables.reflow_width
local data = nil
local trace_xtable = nil
local showwidths = nil
local v_max = nil
local report_xtable = nil
local v_stretch = nil
local v_width = nil
function 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 heights = data.heights
    local depths = data.depths
    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
    -- here we can also check spans
    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
                local wc = widths[c]
                width = width + wc
             -- if width > maxwidth then
                if wc > maxwidth then -- per 2015-08-09
                    autowidths[c] = true
                    nofwide = nofwide + 1
                    widetotal = widetotal + wc
                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 %p",delta)
            end
        elseif options[v_width] then
            local factor = delta / width
            if trace_xtable then
                report_xtable("proportional stretch, delta %p, width %p, factor %a",delta,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 %p, extra %p",delta,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 %p, delta %p, columns %s, fixed %p",widetotal,delta,nofwide,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) / widetotal -- PATCHED!
            if trace_xtable then
                report_xtable("proportional shrink used, total %p, delta %p, columns %s, factor %s",widetotal,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 %p, delta %p, columns %s, fixed %p",widetotal,delta,nofwide,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
for i = 1, debug.getinfo(orig).nups do
    debug.upvaluejoin(reflow_width, i, orig, i)
end
-- Run with or without these lines to compare
-- xtables.reflow_width = reflow_width
-- interfaces.implement { name = "x_table_reflow_width", actions = xtables.reflow_width }
\stopluacode
\starttext
\showframe
\startxtable[option={stretch}]
  \startxrow
    \startxcell
      a
    \stopxcell
    \startxcell
      abcdefghijklmnopqrstuvwxyz
    \stopxcell
    \startxcell
      abcdefghijklmnopqrstuvwxyz
    \stopxcell
    \startxcell
      abcdefghijklmnopqrstuvwxyz
    \stopxcell
  \stopxrow
\stopxtable
\startxtable[option={stretch,width}]
  \startxrow
    \startxcell
      a
    \stopxcell
    \startxcell
      abcdefghijklmnopqrstuvwxyz
    \stopxcell
    \startxcell
      abcdefghijklmnopqrstuvwxyz
    \stopxcell
    \startxcell
      abcdefghijklmnopqrstuvwxyz
    \stopxcell
  \stopxrow
\stopxtable
\stoptext
 |