diff options
Diffstat (limited to 'tex/context/base/spac-ver.lua')
-rw-r--r-- | tex/context/base/spac-ver.lua | 621 |
1 files changed, 471 insertions, 150 deletions
diff --git a/tex/context/base/spac-ver.lua b/tex/context/base/spac-ver.lua index 16291df27..408b310f4 100644 --- a/tex/context/base/spac-ver.lua +++ b/tex/context/base/spac-ver.lua @@ -8,10 +8,17 @@ if not modules then modules = { } end modules ['spac-ver'] = { -- this code dates from the beginning and is kind of experimental; it -- will be optimized and improved soon +-- +-- the collapser will be redone with user nodes; also, we might get make +-- parskip into an attribute and appy it explicitly thereby getting rid +-- of automated injections; eventually i want to get rid of the currently +-- still needed tex -> lua -> tex > lua chain (needed because we can have +-- expandable settings at the tex end -local next, type = next, type -local format, gmatch, concat = string.format, string.gmatch, table.concat -local texsprint, texlists = tex.sprint, tex.lists +local next, type, tonumber = next, type, tonumber +local format, gmatch, concat, match = string.format, string.gmatch, table.concat, string.match +local ceil, floor, max, min, round = math.ceil, math.floor, math.max, math.min, math.round +local texsprint, texlists, texdimen, texbox, texht, texdp = tex.sprint, tex.lists, tex.dimen, tex.box, tex.ht, tex.dp local ctxcatcodes = tex.ctxcatcodes local variables = interfaces.variables @@ -24,12 +31,15 @@ local trace_vbox_vspacing = false trackers.register("nodes.vbox_vspacing", local trace_page_vspacing = false trackers.register("nodes.page_vspacing", function(v) trace_page_vspacing = v end) local trace_collect_vspacing = false trackers.register("nodes.collect_vspacing", function(v) trace_collect_vspacing = v end) local trace_vspacing = false trackers.register("nodes.vspacing", function(v) trace_vspacing = v end) +local trace_vsnapping = false trackers.register("nodes.vsnapping", function(v) trace_vsnapping = v end) local skip_category = attributes.private('skip-category') local skip_penalty = attributes.private('skip-penalty') local skip_order = attributes.private('skip-order') local snap_category = attributes.private('snap-category') local display_math = attributes.private('display-math') +local snap_method = attributes.private('snap-method') +local snap_done = attributes.private('snap-done') local has_attribute = node.has_attribute local unset_attribute = node.unset_attribute @@ -38,13 +48,17 @@ local find_node_tail = node.tail local free_node = node.free local copy_node = node.copy local traverse_nodes = node.traverse +local traverse_nodes_id = node.traverse_id local insert_node_before = node.insert_before local insert_node_after = node.insert_after local remove_node = nodes.remove local make_penalty_node = nodes.penalty +local make_kern_node = nodes.kern +local make_rule_node = nodes.rule local count_nodes = nodes.count local node_ids_to_string = nodes.ids_to_string local hpack_node = node.hpack +local vpack_node = node.vpack local glyph = node.id("glyph") local penalty = node.id("penalty") @@ -54,7 +68,164 @@ local hlist = node.id('hlist') local vlist = node.id('vlist') local adjust = node.id('adjust') -vspacing = vspacing or { } +vspacing = vspacing or { } +vspacing.data = vspacing.data or { } + +vspacing.data.snapmethods = vspacing.data.snapmethods or { } + +storage.register("vspacing/data/snapmethods", vspacing.data.snapmethods, "vspacing.data.snapmethods") + +local snapmethods, snapht, snapdp, snaphtdp = vspacing.data.snapmethods, 0, 0, 0 + +local default = { + maxheight = true, + maxdepth = true, + strut = true, + hfraction = 1, + dfraction = 1, +} + +local fractions = { + minheight = "hfraction", maxheight = "hfraction", + mindepth = "dfraction", maxdepth = "dfraction", +} + +local colonsplitter = lpeg.splitat(":") + +function interfaces.listtohash(str) + local t = { } + for s in gmatch(str,"[^, ]+") do + local key, fraction = colonsplitter:match(s) + local v = variables[key] + if v then + t[v] = true + if fraction then + local k = fractions[key] + if k then + fraction = tonumber("0" .. fraction) + if fraction then + t[k] = fraction + end + end + end + else + fraction = tonumber("0" .. key) + if fraction then + t.hfraction, t.dfraction = fraction, fraction + end + end + end + if next(t) then + t.hfraction = t.hfraction or 1 + t.dfraction = t.dfraction or 1 + return t + else + return default + end +end + +function vspacing.define_snap_method(name,method) + local n = #snapmethods + 1 + local t = interfaces.listtohash(method) + snapmethods[n] = t + t.name, t.specification = name, method + tex.write(n) +end + +function vspacing.freeze_snap_method(ht,dp) + snapht, snapdp = ht or texdimen.strutht, dp or texdimen.strutdp + snaphtdp = snapht + snapdp +end + +local function snap_hlist(current,method) -- method.strut is default + local h, d = current.height, current.depth + local hr, dr, ch, cd = method.hfraction or 1, method.dfraction or 1, h, d + local done, plusht, plusdp = false, snapht, snapdp + if method.none then + plusht, plusdp = 0, 0 + end + if method.halfline then + plusht, plusdp = plusht + snaphtdp/2, plusdp + snaphtdp/2 + end + if method.line then + plusht, plusdp = plusht + snaphtdp, plusdp + snaphtdp + end + if method.first then + if current.id == vlist then + local list, lh, ld = current.list + for n in traverse_nodes_id(hlist,list) do + lh, ld = n.height, n.depth + break + end + if lh then + local x = max(ceil((lh-hr*snapht)/snaphtdp),0)*snaphtdp + plusht + local n = make_kern_node(x-lh) + n.next, list.prev, current.list = list, n, n + ch = x + snaphtdp + cd = max(ceil((d+h-lh-dr*snapdp-hr*snapht)/snaphtdp),0)*snaphtdp + plusdp + done = true + end + end + elseif method.last then + if current.id == vlist then + local list, lh, ld = current.list + for n in traverse_nodes_id(hlist,list) do + lh, ld = n.height, n.depth + end + if lh then + local baseline_till_top = h + d - ld + local x = max(ceil((baseline_till_top-hr*snapht)/snaphtdp),0)*snaphtdp + plusht + local n = make_kern_node(x-baseline_till_top) + n.next, list.prev, current.list = list, n, n + ch = x + cd = max(ceil((ld-dr*snapdp)/snaphtdp),0)*snaphtdp + plusdp + done = true + end + end + end + if done then + -- first or last + elseif method.minheight then + ch = max(floor((h-hr*snapht)/snaphtdp),0)*snaphtdp + plusht + elseif method.maxheight then + ch = max(ceil((h-hr*snapht)/snaphtdp),0)*snaphtdp + plusht + else + ch = plusht + end + if done then + -- first or last + elseif method.mindepth then + cd = max(floor((d-dr*snapdp)/snaphtdp),0)*snaphtdp + plusdp + elseif method.maxdepth then + cd = max(ceil((d-dr*snapdp)/snaphtdp),0)*snaphtdp + plusdp + else + cd = plusdp + end + current.height, current.depth = ch, cd + return h, d, ch, cd, (ch+cd)/snaphtdp +end + +local function snap_topskip(current,method) + local spec = current.spec + local w = spec.width + local wd = w + if spec then + wd = 0 -- snapht - w + spec.width = wd + end + return w, wd +end + +local function snapped_spec(current) + local spec = current.spec + if spec then + local w = ceil(spec.width/snaphtdp)*snaphtdp + spec.width = w + return w + else + return 0 + end +end vspacing.categories = { [0] = 'discard', @@ -90,7 +261,6 @@ function vspacing.tocategory(str) end end -vspacing.data = vspacing.data or { } vspacing.data.map = vspacing.data.map or { } vspacing.data.skip = vspacing.data.skip or { } @@ -117,8 +287,6 @@ do -- todo: interface.variables local k_fixed, k_flexible, k_category, k_penalty, k_order = variables.fixed, variables.flexible, "category", "penalty", "order" local function analyse(str,oldcategory,texsprint) ---~ print(table.serialize(map)) ---~ print(table.serialize(skip)) for s in gmatch(str,"([^ ,]+)") do local amount, keyword, detail = splitter:match(s) if not keyword then @@ -149,7 +317,6 @@ do -- todo: interface.variables local penalty = tonumber(detail) if penalty then texsprint(ctxcatcodes,format("\\setblankpenalty{%s}",penalty)) - texsprint(ctxcatcodes,"\\flushblankhandling") end else amount = tonumber(amount) or 1 @@ -189,11 +356,11 @@ end -- implementation -nodes.snapvalues = { } +--~ nodes.snapvalues = { } -function nodes.setsnapvalue(n,ht,dp) - nodes.snapvalues[n] = { ht, dp, ht+dp } -end +--~ function nodes.setsnapvalue(n,ht,dp) +--~ nodes.snapvalues[n] = { ht, dp, ht+dp } +--~ end local trace_list, tracing_info, before, after = { }, false, "", "" @@ -342,26 +509,134 @@ local free_glue_node = free_node local free_glue_spec = free_node local discard, largest, force, penalty, add, disable, nowhite, goback = 0, 1, 2, 3, 4, 5, 6, 7 -local function collapser(head,where,what,trace) -- maybe also pass tail +function vspacing.snap_box(n,how) + local sv = snapmethods[how] + if sv then + local list = texbox[n].list + if list and (list.id == hlist or list.id == vlist) then + local h, d, ch, cd, lines = snap_hlist(list,sv) + texht[n], texdp[n] = ch, cd + if trace_vsnapping then + logs.report("snapper", "hlist snapped from (%s,%s) to (%s,%s) using method '%s' (%s) for '%s' (%s lines)",h,d,ch,cd,sv.name,sv.specification,"direct",lines) + end + end + end +end + +local function forced_skip(head,current,width,where,trace) + if where == "after" then + head, current = insert_node_after(head,current,make_rule_node(0,0,0)) + head, current = insert_node_after(head,current,make_kern_node(width)) + head, current = insert_node_after(head,current,make_rule_node(0,0,0)) + else + local c = current + head, current = insert_node_before(head,current,make_rule_node(0,0,0)) + head, current = insert_node_before(head,current,make_kern_node(width)) + head, current = insert_node_before(head,current,make_rule_node(0,0,0)) + current = c + end + if trace then + logs.report("vspacing", "inserting forced skip of %s",width) + end + return head, current +end + +local function collapser(head,where,what,trace,snap) -- maybe also pass tail if trace then reset_tracing(head) trace_info("start analyzing",where,what) end local current = head - local glue_order, glue_data = 0, nil + local glue_order, glue_data, force_glue = 0, nil, false local penalty_order, penalty_data, natural_penalty = 0, nil, nil local parskip, ignore_parskip, ignore_following, ignore_whitespace = nil, false, false, false + local function flush(why) + if penalty_data then + local p = make_penalty_node(penalty_data) + if trace then trace_done("flushed due to " .. why,p) end + head, _ = insert_node_before(head,current,p) + end + if glue_data then + if force_glue then + if trace then trace_done("flushed due to " .. why,glue_data) end + head, _ = forced_skip(head,current,glue_data.spec.width,"before",trace) + free_glue_node(glue_data) + elseif glue_data.spec then + if trace then trace_done("flushed due to " .. why,glue_data) end + head, _ = insert_node_before(head,current,glue_data) + else + free_glue_node(glue_data) + end + end + if trace then trace_node(current) end + glue_order, glue_data, force_glue = 0, nil, false + penalty_order, penalty_data, natural_penalty = 0, nil, nil + parskip, ignore_parskip, ignore_following, ignore_whitespace = nil, false, false, false + end while current do - local id = current.id -- has each node a subtype ? - if id == glue and current.subtype == 0 then -- todo, other subtypes, like math + local id, subtype = current.id, current.subtype + if id == hlist or id == vlist then + if snap then + local s = has_attribute(current,snap_method) + if s then + unset_attribute(current,snap_method) + if not has_attribute(current,snap_done) then + local sv = snapmethods[s] + if sv then + local h, d, ch, cd, lines = snap_hlist(current,sv) + if trace_vsnapping then + logs.report("snapper", "hlist snapped from (%s,%s) to (%s,%s) using method '%s' (%s) for '%s' (%s lines)",h,d,ch,cd,sv.name,sv.specification,where,lines) + end + elseif trace_vsnapping then + logs.report("snapper", "hlist not snapped due to unknown snap specification") + end + set_attribute(current,snap_done,s) + elseif trace_vsnapping then + logs.report("snapper", "hlist not snapped, already done") + end + elseif trace_vsnapping then + -- logs.report("snapper", "hlist not snapped") + end + else + -- + end + -- tex.prevdepth = 0 + flush("list") + current = current.next + elseif id == penalty then + --~ natural_penalty = current.penalty + --~ if trace then trace_done("removed penalty",current) end + --~ head, current = remove_node(head, current, true) + current = current.next + elseif id == kern then + if snap and trace_vsnapping and current.kern ~= 0 then + --~ current.kern = 0 + logs.report("snapper", "kern of %s (kept)",current.kern) + end + flush("kern") + current = current.next + elseif id ~= glue then + flush("something else") + current = current.next + elseif subtype == user_skip then -- todo, other subtypes, like math local sc = has_attribute(current,skip_category) -- has no default, no unset (yet) local so = has_attribute(current,skip_order ) or 1 -- has 1 default, no unset (yet) - local sp = has_attribute(current,skip_penalty ) -- has no degault, no unset (yet) - if not sc then + local sp = has_attribute(current,skip_penalty ) -- has no default, no unset (yet) + if sp and sc == penalty then + if not penalty_data then + penalty_data = sp + elseif penalty_order < so then + penalty_order, penalty_data = so, sp + elseif penalty_order == so and sp > penalty_data then + penalty_data = sp + end + head, current = remove_node(head, current, true) + elseif not sc then -- if not sc then if glue_data then if trace then trace_done("flush",glue_data) end head, current = nodes.before(head,current,glue_data) if trace then trace_natural("natural",current) end + current = current.next else -- not look back across head local previous = current.prev @@ -375,174 +650,203 @@ local function collapser(head,where,what,trace) -- maybe also pass tail ps.width, ps.stretch, ps.shrink = pw + cw, pp + cp, pm + cm if trace then trace_natural("removed",current) end head, current = remove_node(head, current, true) - current = previous - if trace then trace_natural("collapsed",current) end + -- current = previous + if trace then trace_natural("collapsed",previous) end + -- current = current.next else if trace then trace_natural("filler",current) end + current = current.next end else if trace then trace_natural("natural (no prev spec)",current) end + current = current.next end else if trace then trace_natural("natural (no prev)",current) end + current = current.next end end glue_order, glue_data = 0, nil - if current then - current = current.next - end - else - if sc == disable then - ignore_following = true - if trace then trace_skip("disable",sc,so,sp,current) end - head, current = remove_node(head, current, true) - elseif sc == nowhite then - ignore_whitespace = true + elseif sc == disable then + ignore_following = true + if trace then trace_skip("disable",sc,so,sp,current) end + head, current = remove_node(head, current, true) + elseif sc == nowhite then + ignore_whitespace = true + head, current = remove_node(head, current, true) + elseif sc == discard then + if trace then trace_skip("discard",sc,so,sp,current) end + head, current = remove_node(head, current, true) + elseif ignore_following then + if trace then trace_skip("disabled",sc,so,sp,current) end + head, current = remove_node(head, current, true) + elseif not glue_data then + if trace then trace_skip("assign",sc,so,sp,current) end + glue_order = so + head, current, glue_data = remove_node(head, current) + elseif glue_order < so then + if trace then trace_skip("force",sc,so,sp,current) end + glue_order = so + free_glue_node(glue_data) + head, current, glue_data = remove_node(head, current) + elseif glue_order == so then + -- is now exclusive, maybe support goback as combi, else why a set + if sc == largest then + local cs, gs = current.spec, glue_data.spec + local cw = (cs and cs.width) or 0 + local gw = (gs and gs.width) or 0 + if cw > gw then + if trace then trace_skip('largest',sc,so,sp,current) end + free_glue_node(glue_data) -- also free spec + head, current, glue_data = remove_node(head, current) + else + if trace then trace_skip('remove smallest',sc,so,sp,current) end + head, current = remove_node(head, current, true) + end + elseif sc == goback then + if trace then trace_skip('goback',sc,so,sp,current) end + free_glue_node(glue_data) -- also free spec + head, current, glue_data = remove_node(head, current) + elseif sc == force then + -- todo: inject kern + if trace then trace_skip('force',sc,so,sp,current) end + free_glue_node(glue_data) -- also free spec + head, current, glue_data = remove_node(head, current) + elseif sc == penalty then + -- ? ? ? ? + if trace then trace_skip('penalty',sc,so,sp,current) end + free_glue_node(glue_data) -- also free spec + glue_data = nil head, current = remove_node(head, current, true) - elseif sc == discard then - if trace then trace_skip("discard",sc,so,sp,current) end + elseif sc == add then + if trace then trace_skip('add',sc,so,sp,current) end + local old, new = glue_data.spec, current.spec + old.width = old.width + new.width + old.stretch = old.stretch + new.stretch + old.shrink = old.shrink + new.shrink + -- toto: order head, current = remove_node(head, current, true) else - if sp then - if not penalty_data then - penalty_data = sp - elseif penalty_order < so then - penalty_order, penalty_data = so, sp - elseif penalty_order == so and sp > penalty_data then - penalty_data = sp - end - end - if ignore_following then - if trace then trace_skip("disabled",sc,so,sp,current) end - head, current = remove_node(head, current, true) - elseif not glue_data then - if trace then trace_skip("assign",sc,so,sp,current) end - glue_order = so - head, current, glue_data = remove_node(head, current) - elseif glue_order < so then - if trace then trace_skip("force",sc,so,sp,current) end - glue_order = so - free_glue_node(glue_data) - head, current, glue_data = remove_node(head, current) - elseif glue_order == so then - -- is now exclusive, maybe support goback as combi, else why a set - if sc == largest then - local cs, gs = current.spec, glue_data.spec - local cw = (cs and cs.width) or 0 - local gw = (gs and gs.width) or 0 - if cw > gw then - if trace then trace_skip('largest',sc,so,sp,current) end - free_glue_node(glue_data) -- also free spec - head, current, glue_data = remove_node(head, current) - else - if trace then trace_skip('remove smallest',sc,so,sp,current) end - head, current = remove_node(head, current, true) - end - elseif sc == goback then - if trace then trace_skip('goback',sc,so,sp,current) end - free_glue_node(glue_data) -- also free spec - head, current, glue_data = remove_node(head, current) - elseif sc == force then - -- todo: inject kern - if trace then trace_skip('force',sc,so,sp,current) end - free_glue_node(glue_data) -- also free spec - head, current, glue_data = remove_node(head, current) - elseif sc == penalty then - if trace then trace_skip('penalty',sc,so,sp,current) end - free_glue_node(glue_data) -- also free spec - glue_data = nil - head, current = remove_node(head, current, true) - elseif sc == add then - if trace then trace_skip('add',sc,so,sp,current) end - local old, new = glue_data.spec, current.spec - old.width = old.width + new.width - old.stretch = old.stretch + new.stretch - old.shrink = old.shrink + new.shrink - -- toto: order - head, current = remove_node(head, current, true) - else - if trace then trace_skip("unknown",sc,so,sp,current) end - head, current = remove_node(head, current, true) + if trace then trace_skip("unknown",sc,so,sp,current) end + head, current = remove_node(head, current, true) + end + else + if trace then trace_skip("unknown",sc,so,sp,current) end + head, current = remove_node(head, current, true) + end + if sc == force then + force_glue = true + end + elseif subtype == line_skip then + if snap then + local sn = has_attribute(current,snap_method) + if sn then + unset_attribute(current,snap_method) + local spec = current.spec + if spec then + spec.width = 0 + if trace_vsnapping then + logs.report("snapper", "lineskip set to zero") end - else - if trace then trace_skip("unknown",sc,so,sp,current) end - head, current = remove_node(head, current, true) end + else + if trace then trace_skip("lineskip",sc,so,sp,current) end + flush("lineskip") end + else + if trace then trace_skip("lineskip",sc,so,sp,current) end + flush("lineskip") end - elseif id == penalty then - --~ natural_penalty = current.penalty - --~ if trace then trace_done("removed penalty",current) end - --~ head, current = remove_node(head, current, true) current = current.next - elseif id == glue and current.subtype == 2 then - local sn = has_attribute(current,snap_category) - if sn then - -- local sv = nodes.snapvalues[sn] - -- if sv then - if trace then trace_natural("removed baselineskip",current) end - head, current = remove_node(head, current, true) - -- else - -- current = current.next - -- end + elseif subtype == baseline_skip then + if snap then + local sn = has_attribute(current,snap_method) + if sn then + unset_attribute(current,snap_method) + local spec = current.spec + if spec then + spec.width = 0 + if trace_vsnapping then + logs.report("snapper", "baselineskip set to zero") + end + end + else + if trace then trace_skip("baselineskip",sc,so,sp,current) end + flush("baselineskip") + end else - if trace then trace_natural("keep baselineskip",current) end - current = current.next + if trace then trace_skip("baselineskip",sc,so,sp,current) end + flush("baselineskip") end - elseif id == glue and current.subtype == 3 then + current = current.next + elseif subtype == par_skip then -- parskip always comes later if ignore_whitespace then if trace then trace_natural("ignored parskip",current) end - head, current = remove_node(head,current,true) + head, current = remove_node(head, current, true) elseif glue_data then local ps, gs = current.spec, glue_data.spec if ps and gs and ps.width > gs.width then - -- free_glue_spec(glue_data.spec) -- result in double free glue_data.spec = copy_node(ps) if trace then trace_natural("taking parskip",current) end else if trace then trace_natural("removed parskip",current) end end - head, current = remove_node(head, current,true) + head, current = remove_node(head, current, true) else if trace then trace_natural("honored parskip",current) end head, current, glue_data = remove_node(head, current) end - --~ if trace then trace_natural("removed parskip",current) end - --~ current.spec = nil - --~ current = current.next - else --- reversed - if penalty_data then - local p = make_penalty_node(penalty_data) - if trace then trace_done("flushed",p) end - head, current = insert_node_before(head,current,p) - -- penalty_data = nil - end - if glue_data then - if trace then trace_done("flushed",glue_data) end - head, current = insert_node_before(head,current,glue_data) - -- glue_order, glue_data = 0, nil - end - if trace then trace_node(current) end - if id == hlist and where == 'hmode_par' then - local list = current.list - if list then - local sn = has_attribute(list,snap_category) - if sn then - local sv = nodes.snapvalues[sn] - if sv then - local height, depth, lineheight = sv[1], sv[2], sv[3] - -- is math.ceil really needed? - current.height = math.ceil((current.height-height)/lineheight)*lineheight + height - current.depth = math.ceil((current.depth -depth )/lineheight)*lineheight + depth - end + elseif subtype == top_skip_code or subtype == split_top_skip_code then + if snap then + local s = has_attribute(current,snap_method) + if s then + unset_attribute(current,snap_method) + local sv = snapmethods[s] + local w, cw = snap_topskip(current,sv) + if trace_vsnapping then + logs.report("snapper", "topskip snapped from %s to %s for '%s'",w,cw,where) end + else + if trace then trace_skip("topskip",sc,so,sp,current) end + flush("topskip") end + else + if trace then trace_skip("topskip",sc,so,sp,current) end + flush("topskip") end - glue_order, glue_data = 0, nil - penalty_order, penalty_data, natural_penalty = 0, nil, nil - parskip, ignore_parskip, ignore_following, ignore_whitespace = nil, false, false, false + current = current.next + elseif subtype == above_display_skip then + -- +if trace then trace_skip("above display skip (normal)",sc,so,sp,current) end +flush("above display skip (normal)") +current = current.next + -- + elseif subtype == below_display_skip then + -- +if trace then trace_skip("below display skip (normal)",sc,so,sp,current) end +flush("below display skip (normal)") +current = current.next + -- + elseif subtype == above_display_short_skip then + -- +if trace then trace_skip("above display skip (short)",sc,so,sp,current) end +flush("above display skip (short)") +current = current.next + -- + elseif subtype == below_display_short_skip then + -- +if trace then trace_skip("below display skip (short)",sc,so,sp,current) end +flush("below display skip (short)") +current = current.next + -- + else -- other glue + if snap and trace_vsnapping and current.spec and current.spec.width ~= 0 then + logs.report("snapper", "%s of %s (kept)",skips[subtype],current.spec.width) + --~ current.spec.width = 0 + end + if trace then trace_skip(format("some glue (%s)",subtype),sc,so,sp,current) end + flush("some glue") current = current.next end end @@ -563,7 +867,13 @@ local function collapser(head,where,what,trace) -- maybe also pass tail if glue_data then if not tail then tail = find_node_tail(head) end if trace then trace_done("result",glue_data) end - head, tail = insert_node_after(head,tail,glue_data) +--~ snapped_spec(glue_data) + if force_glue then + head, tail = forced_skip(head,tail,glue_data.spec.width,"after",trace) + free_glue_node(glue_data) + else + head, tail = insert_node_after(head,tail,glue_data) + end end if trace then if glue_data or penalty_data then @@ -596,6 +906,7 @@ function nodes.handle_page_spacing(where) starttiming(vspacing) local newtail = find_node_tail(newhead) local flush = false +stackhack = true -- todo: only when grid snapping once enabled for n in traverse_nodes(newhead) do -- we could just look for glue nodes local id = n.id if id == glue then @@ -623,7 +934,7 @@ function nodes.handle_page_spacing(where) if stackhack then stackhack = false if trace_collect_vspacing then report("processing %s nodes: %s",newhead) end - texlists.contrib_head = collapser(newhead,"page",where,trace_page_vspacing) + texlists.contrib_head = collapser(newhead,"page",where,trace_page_vspacing,true) else if trace_collect_vspacing then report("flushing %s nodes: %s",newhead) end texlists.contrib_head = newhead @@ -653,12 +964,21 @@ local ignore = table.tohash { function nodes.handle_vbox_spacing(head,where) if head and not ignore[where] and head.next then starttiming(vspacing) - head = collapser(head,"vbox",where,trace_vbox_vspacing) + head = collapser(head,"vbox",where,trace_vbox_vspacing,false) stoptiming(vspacing) end return head end +function nodes.collapse_vbox(n) -- for boxes + local list = texbox[n].list + if list then + starttiming(vspacing) + texbox[n].list = vpack_node(collapser(list,"snapper","vbox",trace_vbox_vspacing,true)) + stoptiming(vspacing) + end +end + statistics.register("v-node processing time", function() if statistics.elapsedindeed(vspacing) then return format("%s seconds", statistics.elapsedtime(vspacing)) @@ -689,6 +1009,7 @@ local vlist = node.id('vlist') local remove_node = nodes.remove local hpack_node = node.hpack +local vpack_node = node.vpack local has_attribute = node.has_attribute function nodes.repackage_graphicvadjust(head,groupcode) -- we can make an actionchain for mvl only |