summaryrefslogtreecommitdiff
path: root/tex/context/base/spac-ver.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/spac-ver.lua')
-rw-r--r--tex/context/base/spac-ver.lua951
1 files changed, 693 insertions, 258 deletions
diff --git a/tex/context/base/spac-ver.lua b/tex/context/base/spac-ver.lua
index 0035c4119..d1cf09e17 100644
--- a/tex/context/base/spac-ver.lua
+++ b/tex/context/base/spac-ver.lua
@@ -8,10 +8,16 @@ if not modules then modules = { } end modules ['spac-ver'] = {
-- we also need to call the spacer for inserts!
--- todo: directly set skips
+-- somehow lists still don't always have proper prev nodes so i need to
+-- check all of the luatex code some day .. maybe i should replece the
+-- whole mvl handler by lua code .. why not
+
+-- todo: use lua nodes with lua data (>0.79)
+-- see ** can go when 0.79
-- this code dates from the beginning and is kind of experimental; it
--- will be optimized and improved soon
+-- will be optimized and improved soon .. it's way too complex now but
+-- dates from less possibilities
--
-- the collapser will be redone with user nodes; also, we might get make
-- parskip into an attribute and appy it explicitly thereby getting rid
@@ -32,14 +38,20 @@ local formatters = string.formatters
local P, C, R, S, Cc = lpeg.P, lpeg.C, lpeg.R, lpeg.S, lpeg.Cc
-local nodes, node, trackers, attributes, context, commands, tex = nodes, node, trackers, attributes, context, commands, tex
+local nodes = nodes
+local node = node
+local trackers = trackers
+local attributes = attributes
+local context = context
+local tex = tex
local texlists = tex.lists
local texgetdimen = tex.getdimen
+local texsetdimen = tex.setdimen
local texnest = tex.nest
-local texgetbox = tex.getbox
local variables = interfaces.variables
+local implement = interfaces.implement
-- vertical space handler
@@ -49,11 +61,12 @@ local trace_page_builder = false trackers.register("builders.page", fun
local trace_collect_vspacing = false trackers.register("vspacing.collect", function(v) trace_collect_vspacing = v end)
local trace_vspacing = false trackers.register("vspacing.spacing", function(v) trace_vspacing = v end)
local trace_vsnapping = false trackers.register("vspacing.snapping", function(v) trace_vsnapping = v end)
-local trace_vpacking = false trackers.register("vspacing.packing", function(v) trace_vpacking = v end)
+local trace_specials = false trackers.register("vspacing.specials", function(v) trace_specials = v end)
local report_vspacing = logs.reporter("vspacing","spacing")
local report_collapser = logs.reporter("vspacing","collapsing")
local report_snapper = logs.reporter("vspacing","snapping")
+local report_specials = logs.reporter("vspacing","specials")
local report_page_builder = logs.reporter("builders","page")
local a_skipcategory = attributes.private('skipcategory')
@@ -63,27 +76,46 @@ local a_skiporder = attributes.private('skiporder')
local a_snapmethod = attributes.private('snapmethod')
local a_snapvbox = attributes.private('snapvbox')
-local find_node_tail = node.tail
-local free_node = node.free
-local free_node_list = node.flush_list
-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 count_nodes = nodes.count
-local nodeidstostring = nodes.idstostring
-local hpack_node = node.hpack
-local vpack_node = node.vpack
-local writable_spec = nodes.writable_spec
+local nuts = nodes.nuts
+local tonode = nuts.tonode
+local tonut = nuts.tonut
+local ntostring = nuts.tostring
+
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getlist = nuts.getlist
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+local getsubtype = nuts.getsubtype
+local getbox = nuts.getbox
+
+local find_node_tail = nuts.tail
+local free_node = nuts.free
+local free_node_list = nuts.flush_list
+local copy_node = nuts.copy
+local traverse_nodes = nuts.traverse
+local traverse_nodes_id = nuts.traverse_id
+local insert_node_before = nuts.insert_before
+local insert_node_after = nuts.insert_after
+local remove_node = nuts.remove
+local count_nodes = nuts.count
+local hpack_node = nuts.hpack
+local vpack_node = nuts.vpack
+local writable_spec = nuts.writable_spec
+local nodereference = nuts.reference
+
local listtoutf = nodes.listtoutf
+local nodeidstostring = nodes.idstostring
-local nodepool = nodes.pool
+local nodepool = nuts.pool
local new_penalty = nodepool.penalty
local new_kern = nodepool.kern
local new_rule = nodepool.rule
+local new_glue = nodepool.glue
local new_gluespec = nodepool.gluespec
local nodecodes = nodes.nodecodes
@@ -103,8 +135,8 @@ builders.vspacing = vspacing
local vspacingdata = vspacing.data or { }
vspacing.data = vspacingdata
-vspacingdata.snapmethods = vspacingdata.snapmethods or { }
-local snapmethods = vspacingdata.snapmethods --maybe some older code can go
+local snapmethods = vspacingdata.snapmethods or { }
+vspacingdata.snapmethods = snapmethods
storage.register("builders/vspacing/data/snapmethods", snapmethods, "builders.vspacing.data.snapmethods")
@@ -114,11 +146,13 @@ local default = {
strut = true,
hfraction = 1,
dfraction = 1,
+ bfraction = 0.25,
}
local fractions = {
minheight = "hfraction", maxheight = "hfraction",
mindepth = "dfraction", maxdepth = "dfraction",
+ box = "bfraction",
top = "tlines", bottom = "blines",
}
@@ -179,28 +213,26 @@ end
-- local rule_id = nodecodes.rule
-- local vlist_id = nodecodes.vlist
-- function nodes.makevtop(n)
--- if n.id == vlist_id then
--- local list = n.list
--- local height = (list and list.id <= rule_id and list.height) or 0
--- n.depth = n.depth - height + n.height
--- n.height = height
+-- if getid(n) == vlist_id then
+-- local list = getlist(n)
+-- local height = (list and getid(list) <= rule_id and getfield(list,"height")) or 0
+-- setfield(n,"depth",getfield(n,"depth") - height + getfield(n,"height")
+-- setfield(n,"height",height
-- end
-- end
-local reference = nodes.reference
-
local function validvbox(parentid,list)
if parentid == hlist_code then
- local id = list.id
+ local id = getid(list)
if id == whatsit_code then -- check for initial par subtype
- list = list.next
+ list = getnext(list)
if not next then
return nil
end
end
local done = nil
for n in traverse_nodes(list) do
- local id = n.id
+ local id = getid(n)
if id == vlist_code or id == hlist_code then
if done then
return nil
@@ -214,9 +246,9 @@ local function validvbox(parentid,list)
end
end
if done then
- local id = done.id
+ local id = getid(done)
if id == hlist_code then
- return validvbox(id,done.list)
+ return validvbox(id,getlist(done))
end
end
return done -- only one vbox
@@ -226,19 +258,19 @@ end
local function already_done(parentid,list,a_snapmethod) -- todo: done when only boxes and all snapped
-- problem: any snapped vbox ends up in a line
if list and parentid == hlist_code then
- local id = list.id
+ local id = getid(list)
if id == whatsit_code then -- check for initial par subtype
- list = list.next
+ list = getnext(list)
if not next then
return false
end
end
--~ local i = 0
for n in traverse_nodes(list) do
- local id = n.id
---~ i = i + 1 print(i,nodecodes[id],n[a_snapmethod])
+ local id = getid(n)
+--~ i = i + 1 print(i,nodecodes[id],getattr(n,a_snapmethod))
if id == hlist_code or id == vlist_code then
- local a = n[a_snapmethod]
+ local a = getattr(n,a_snapmethod)
if not a then
-- return true -- not snapped at all
elseif a == 0 then
@@ -276,11 +308,11 @@ end
-- check variables.none etc
local function snap_hlist(where,current,method,height,depth) -- method.strut is default
- local list = current.list
+ local list = getlist(current)
local t = trace_vsnapping and { }
if t then
t[#t+1] = formatters["list content: %s"](listtoutf(list))
- t[#t+1] = formatters["parent id: %s"](reference(current))
+ t[#t+1] = formatters["parent id: %s"](nodereference(current))
t[#t+1] = formatters["snap method: %s"](method.name)
t[#t+1] = formatters["specification: %s"](method.specification)
end
@@ -312,26 +344,58 @@ local function snap_hlist(where,current,method,height,depth) -- method.strut is
t[#t+1] = formatters["auto: snapht %p snapdp %p"](snapht,snapdp)
end
end
- local h, d = height or current.height, depth or current.depth
- local hr, dr, ch, cd = method.hfraction or 1, method.dfraction or 1, h, d
- local tlines, blines = method.tlines or 1, method.blines or 1
- local done, plusht, plusdp = false, snapht, snapdp
+
+ local h = (method.noheight and 0) or height or getfield(current,"height")
+ local d = (method.nodepth and 0) or depth or getfield(current,"depth")
+ local hr = method.hfraction or 1
+ local dr = method.dfraction or 1
+ local br = method.bfraction or 0
+ local ch = h
+ local cd = d
+ local tlines = method.tlines or 1
+ local blines = method.blines or 1
+ local done = false
+ local plusht = snapht
+ local plusdp = snapdp
local snaphtdp = snapht + snapdp
- if method.none then
+ if method.box then
+ local br = 1 - br
+ if br < 0 then
+ br = 0
+ elseif br > 1 then
+ br = 1
+ end
+ local n = ceiled((h+d-br*snapht-br*snapdp)/snaphtdp)
+ local x = n * snaphtdp - h - d
+ plusht = h + x / 2
+ plusdp = d + x / 2
+ elseif method.max then
+ local n = ceiled((h+d)/snaphtdp)
+ local x = n * snaphtdp - h - d
+ plusht = h + x / 2
+ plusdp = d + x / 2
+ elseif method.min then
+ local n = floored((h+d)/snaphtdp)
+ local x = n * snaphtdp - h - d
+ plusht = h + x / 2
+ plusdp = d + x / 2
+ elseif method.none then
plusht, plusdp = 0, 0
if t then
t[#t+1] = "none: plusht 0pt plusdp 0pt"
end
end
if method.halfline then -- extra halfline
- plusht, plusdp = plusht + snaphtdp/2, plusdp + snaphtdp/2
+ plusht = plusht + snaphtdp/2
+ plusdp = plusdp + snaphtdp/2
if t then
t[#t+1] = formatters["halfline: plusht %p plusdp %p"](plusht,plusdp)
end
end
if method.line then -- extra line
- plusht, plusdp = plusht + snaphtdp, plusdp + snaphtdp
+ plusht = plusht + snaphtdp
+ plusdp = plusdp + snaphtdp
if t then
t[#t+1] = formatters["line: plusht %p plusdp %p"](plusht,plusdp)
end
@@ -339,22 +403,22 @@ local function snap_hlist(where,current,method,height,depth) -- method.strut is
if method.first then
local thebox = current
- local id = thebox.id
+ local id = getid(thebox)
if id == hlist_code then
- thebox = validvbox(id,thebox.list)
- id = thebox and thebox.id
+ thebox = validvbox(id,getlist(thebox))
+ id = thebox and getid(thebox)
end
if thebox and id == vlist_code then
- local list = thebox.list
+ local list = getlist(thebox)
local lh, ld
for n in traverse_nodes_id(hlist_code,list) do
- lh = n.height
- ld = n.depth
+ lh = getfield(n,"height")
+ ld = getfield(n,"depth")
break
end
if lh then
- local ht = thebox.height
- local dp = thebox.depth
+ local ht = getfield(thebox,"height")
+ local dp = getfield(thebox,"depth")
if t then
t[#t+1] = formatters["first line: height %p depth %p"](lh,ld)
t[#t+1] = formatters["dimensions: height %p depth %p"](ht,dp)
@@ -362,9 +426,9 @@ local function snap_hlist(where,current,method,height,depth) -- method.strut is
local delta = h - lh
ch, cd = lh, delta + d
h, d = ch, cd
- local shifted = hpack_node(current.list)
- shifted.shift = delta
- current.list = shifted
+ local shifted = hpack_node(getlist(current))
+ setfield(shifted,"shift",delta)
+ setfield(current,"list",shifted)
done = true
if t then
t[#t+1] = formatters["first: height %p depth %p shift %p"](ch,cd,delta)
@@ -377,20 +441,21 @@ local function snap_hlist(where,current,method,height,depth) -- method.strut is
end
elseif method.last then
local thebox = current
- local id = thebox.id
+ local id = getid(thebox)
if id == hlist_code then
- thebox = validvbox(id,thebox.list)
- id = thebox and thebox.id
+ thebox = validvbox(id,getlist(thebox))
+ id = thebox and getid(thebox)
end
if thebox and id == vlist_code then
- local list, lh, ld = thebox.list
+ local list = getlist(thebox)
+ local lh, ld
for n in traverse_nodes_id(hlist_code,list) do
- lh = n.height
- ld = n.depth
+ lh = getfield(n,"height")
+ ld = getfield(n,"depth")
end
if lh then
- local ht = thebox.height
- local dp = thebox.depth
+ local ht = getfield(thebox,"height")
+ local dp = getfield(thebox,"depth")
if t then
t[#t+1] = formatters["last line: height %p depth %p" ](lh,ld)
t[#t+1] = formatters["dimensions: height %p depth %p"](ht,dp)
@@ -398,9 +463,9 @@ local function snap_hlist(where,current,method,height,depth) -- method.strut is
local delta = d - ld
cd, ch = ld, delta + h
h, d = ch, cd
- local shifted = hpack_node(current.list)
- shifted.shift = delta
- current.list = shifted
+ local shifted = hpack_node(getlist(current))
+ setfield(shifted,"shift",delta)
+ setfield(current,"list",shifted)
done = true
if t then
t[#t+1] = formatters["last: height %p depth %p shift %p"](ch,cd,delta)
@@ -461,25 +526,25 @@ local function snap_hlist(where,current,method,height,depth) -- method.strut is
if offset then
-- we need to set the attr
if t then
- t[#t+1] = formatters["before offset: %p (width %p height %p depth %p)"](offset,current.width,current.height,current.depth)
+ t[#t+1] = formatters["before offset: %p (width %p height %p depth %p)"](offset,getfield(current,"width"),getfield(current,"height"),getfield(current,"depth"))
end
- local shifted = hpack_node(current.list)
- shifted.shift = offset
- current.list = shifted
+ local shifted = hpack_node(getlist(current))
+ setfield(shifted,"shift",offset)
+ setfield(current,"list",shifted)
if t then
- t[#t+1] = formatters["after offset: %p (width %p height %p depth %p)"](offset,current.width,current.height,current.depth)
+ t[#t+1] = formatters["after offset: %p (width %p height %p depth %p)"](offset,getfield(current,"width"),getfield(current,"height"),getfield(current,"depth"))
end
- shifted[a_snapmethod] = 0
- current[a_snapmethod] = 0
+ setattr(shifted,a_snapmethod,0)
+ setattr(current,a_snapmethod,0)
end
if not height then
- current.height = ch
+ setfield(current,"height",ch)
if t then
t[#t+1] = formatters["forced height: %p"](ch)
end
end
if not depth then
- current.depth = cd
+ setfield(current,"depth",cd)
if t then
t[#t+1] = formatters["forced depth: %p"](cd)
end
@@ -492,18 +557,24 @@ local function snap_hlist(where,current,method,height,depth) -- method.strut is
t[#t+1] = formatters["final height: %p -> %p"](h,ch)
t[#t+1] = formatters["final depth: %p -> %p"](d,cd)
end
+-- todo:
+--
+-- if h < 0 or d < 0 then
+-- h = 0
+-- d = 0
+-- end
if t then
- report_snapper("trace: %s type %s\n\t%\n\tt",where,nodecodes[current.id],t)
+ report_snapper("trace: %s type %s\n\t%\n\tt",where,nodecodes[getid(current)],t)
end
return h, d, ch, cd, lines
end
local function snap_topskip(current,method)
- local spec = current.spec
- local w = spec.width
+ local spec = getfield(current,"spec")
+ local w = getfield(spec,"width")
local wd = w
- if spec.writable then
- spec.width = 0
+ if getfield(spec,"writable") then
+ setfield(spec,"width",0)
wd = 0
end
return w, wd
@@ -518,14 +589,15 @@ local categories = allocate {
[5] = 'disable',
[6] = 'nowhite',
[7] = 'goback',
- [8] = 'together'
+ [8] = 'together', -- not used (?)
+ [9] = 'overlay',
}
vspacing.categories = categories
function vspacing.tocategories(str)
local t = { }
- for s in gmatch(str,"[^, ]") do
+ for s in gmatch(str,"[^, ]") do -- use lpeg instead
local n = tonumber(s)
if n then
t[categories[n]] = true
@@ -536,7 +608,7 @@ function vspacing.tocategories(str)
return t
end
-function vspacing.tocategory(str)
+function vspacing.tocategory(str) -- can be optimized
if type(str) == "string" then
return set.tonumber(vspacing.tocategories(str))
else
@@ -567,15 +639,15 @@ do -- todo: interface.variables
-- This will change: just node.write and we can store the values in skips which
-- then obeys grouping
- local fixedblankskip = context.fixedblankskip
- local flexibleblankskip = context.flexibleblankskip
- local setblankcategory = context.setblankcategory
- local setblankorder = context.setblankorder
- local setblankpenalty = context.setblankpenalty
- local setblankhandling = context.setblankhandling
- local flushblankhandling = context.flushblankhandling
- local addpredefinedblankskip = context.addpredefinedblankskip
- local addaskedblankskip = context.addaskedblankskip
+ local ctx_fixedblankskip = context.fixedblankskip
+ local ctx_flexibleblankskip = context.flexibleblankskip
+ local ctx_setblankcategory = context.setblankcategory
+ local ctx_setblankorder = context.setblankorder
+ local ctx_setblankpenalty = context.setblankpenalty
+ ----- ctx_setblankhandling = context.setblankhandling
+ local ctx_flushblankhandling = context.flushblankhandling
+ local ctx_addpredefinedblankskip = context.addpredefinedblankskip
+ local ctx_addaskedblankskip = context.addaskedblankskip
local function analyze(str,oldcategory) -- we could use shorter names
for s in gmatch(str,"([^ ,]+)") do
@@ -587,35 +659,35 @@ do -- todo: interface.variables
if mk then
category = analyze(mk,category)
elseif keyword == k_fixed then
- fixedblankskip()
+ ctx_fixedblankskip()
elseif keyword == k_flexible then
- flexibleblankskip()
+ ctx_flexibleblankskip()
elseif keyword == k_category then
local category = tonumber(detail)
if category then
- setblankcategory(category)
+ ctx_setblankcategory(category)
if category ~= oldcategory then
- flushblankhandling()
+ ctx_flushblankhandling()
oldcategory = category
end
end
elseif keyword == k_order and detail then
local order = tonumber(detail)
if order then
- setblankorder(order)
+ ctx_setblankorder(order)
end
elseif keyword == k_penalty and detail then
local penalty = tonumber(detail)
if penalty then
- setblankpenalty(penalty)
+ ctx_setblankpenalty(penalty)
end
else
amount = tonumber(amount) or 1
local sk = skip[keyword]
if sk then
- addpredefinedblankskip(amount,keyword)
+ ctx_addpredefinedblankskip(amount,keyword)
else -- no check
- addaskedblankskip(amount,keyword)
+ ctx_addaskedblankskip(amount,keyword)
end
end
end
@@ -623,22 +695,22 @@ do -- todo: interface.variables
return category
end
- local pushlogger = context.pushlogger
- local startblankhandling = context.startblankhandling
- local stopblankhandling = context.stopblankhandling
- local poplogger = context.poplogger
+ local ctx_pushlogger = context.pushlogger
+ local ctx_startblankhandling = context.startblankhandling
+ local ctx_stopblankhandling = context.stopblankhandling
+ local ctx_poplogger = context.poplogger
function vspacing.analyze(str)
if trace_vspacing then
- pushlogger(report_vspacing)
- startblankhandling()
+ ctx_pushlogger(report_vspacing)
+ ctx_startblankhandling()
analyze(str,1)
- stopblankhandling()
- poplogger()
+ ctx_stopblankhandling()
+ ctx_poplogger()
else
- startblankhandling()
+ ctx_startblankhandling()
analyze(str,1)
- stopblankhandling()
+ ctx_stopblankhandling()
end
end
@@ -664,18 +736,18 @@ local trace_list, tracing_info, before, after = { }, false, "", ""
local function nodes_to_string(head)
local current, t = head, { }
while current do
- local id = current.id
+ local id = getid(current)
local ty = nodecodes[id]
if id == penalty_code then
- t[#t+1] = formatters["%s:%s"](ty,current.penalty)
+ t[#t+1] = formatters["%s:%s"](ty,getfield(current,"penalty"))
elseif id == glue_code then -- or id == kern_code then -- to be tested
t[#t+1] = formatters["%s:%p"](ty,current)
elseif id == kern_code then
- t[#t+1] = formatters["%s:%p"](ty,current.kern)
+ t[#t+1] = formatters["%s:%p"](ty,getfield(current,"kern"))
else
t[#t+1] = ty
end
- current = current.next
+ current = getnext(current)
end
return concat(t," + ")
end
@@ -699,7 +771,7 @@ local function trace_info(message, where, what)
end
local function trace_node(what)
- local nt = nodecodes[what.id]
+ local nt = nodecodes[getid(what)]
local tl = trace_list[#trace_list]
if tl and tl[1] == "node" then
trace_list[#trace_list] = { "node", formatters["%s + %s"](tl[2],nt) }
@@ -709,8 +781,8 @@ local function trace_node(what)
end
local function trace_done(str,data)
- if data.id == penalty_code then
- trace_list[#trace_list+1] = { "penalty", formatters["%s | %s"](str,data.penalty) }
+ if getid(data) == penalty_code then
+ trace_list[#trace_list+1] = { "penalty", formatters["%s | %s"](str,getfield(data,"penalty")) }
else
trace_list[#trace_list+1] = { "glue", formatters["%s | %p"](str,data) }
end
@@ -748,22 +820,32 @@ local belowdisplayshortskip_code = skipcodes.belowdisplayshortskip
local topskip_code = skipcodes.topskip
local splittopskip_code = skipcodes.splittopskip
+-- local function free_glue_node(n)
+-- free_node(n)
+-- local s = getfield(n,"spec")
+-- if s then
+-- free_node(s)
+-- end
+-- end
+
local free_glue_node = free_node
+local free_glue_spec = function() end
+----- free_glue_spec = free_node -- can be enabled in in 0.73 (so for the moment we leak due to old luatex engine issues)
function vspacing.snapbox(n,how)
local sv = snapmethods[how]
if sv then
- local box = texgetbox(n)
- local list = box.list
+ local box = getbox(n)
+ local list = getlist(box)
if list then
- local s = list[a_snapmethod]
+ local s = getattr(list,a_snapmethod)
if s == 0 then
if trace_vsnapping then
-- report_snapper("box list not snapped, already done")
end
else
- local ht = box.height
- local dp = box.depth
+ local ht = getfield(box,"height")
+ local dp = getfield(box,"depth")
if false then -- todo: already_done
-- assume that the box is already snapped
if trace_vsnapping then
@@ -772,14 +854,14 @@ function vspacing.snapbox(n,how)
end
else
local h, d, ch, cd, lines = snap_hlist("box",box,sv,ht,dp)
- box.height= ch
- box.depth = cd
+ setfield(box,"height",ch)
+ setfield(box,"depth",cd)
if trace_vsnapping then
report_snapper("box list snapped from (%p,%p) to (%p,%p) using method %a (%s) for %a (%s lines): %s",
h,d,ch,cd,sv.name,sv.specification,"direct",lines,listtoutf(list))
end
- box[a_snapmethod] = 0 --
- list[a_snapmethod] = 0 -- yes or no
+ setattr(box,a_snapmethod,0) --
+ setattr(list,a_snapmethod,0) -- yes or no
end
end
end
@@ -801,8 +883,10 @@ local w, h, d = 0, 0, 0
----- w, h, d = 100*65536, 65536, 65536
local function forced_skip(head,current,width,where,trace)
- if head == current and head.subtype == baselineskip_code then
- width = width - head.spec.width
+ if head == current then
+ if getsubtype(head) == baselineskip_code then
+ width = width - getfield(getfield(head,"spec"),"width")
+ end
end
if width == 0 then
-- do nothing
@@ -825,62 +909,270 @@ end
-- penalty only works well when before skip
-local discard, largest, force, penalty, add, disable, nowhite, goback, together = 0, 1, 2, 3, 4, 5, 6, 7, 8 -- move into function when upvalue 60 issue
+local discard = 0
+local largest = 1
+local force = 2
+local penalty = 3
+local add = 4
+local disable = 5
+local nowhite = 6
+local goback = 7
+local together = 8 -- not used (?)
+local overlay = 9
-- [whatsits][hlist][glue][glue][penalty]
local special_penalty_min = 32250
local special_penalty_max = 35000
+local special_penalty_xxx = 0
+
+-- this is rather messy and complex: we want to make sure that successive
+-- header don't break but also make sure that we have at least a decent
+-- break when we have succesive ones (often when testing)
+
+-- todo: mark headers as such so that we can recognize them
+
+local specialmethods = { }
+local specialmethod = 1
-local function specialpenalty(start,penalty)
- -- nodes.showsimplelist(texlists.page_head,1)
- local current = find_node_tail(texlists.page_head)
+local properties = nodes.properties.data
+
+specialmethods[1] = function(pagehead,pagetail,start,penalty)
+ --
+ if not pagehead or penalty < special_penalty_min or penalty > special_penalty_max then
+ return
+ end
+ local current = pagetail
+ --
+ -- nodes.showsimplelist(pagehead,0)
+ --
+ if trace_specials then
+ report_specials("checking penalty %a",penalty)
+ end
while current do
- local id = current.id
- if id == glue_code then
- current = current.prev
- elseif id == penalty_code then
- local p = current.penalty
- if p == penalty then
- if trace_vspacing then
- report_vspacing("overloading penalty %a",p)
+ local id = getid(current)
+ if id == penalty_code then
+ local p = properties[current]
+ if p then
+ local p = p.special_penalty
+ if not p then
+ if trace_specials then
+ report_specials(" regular penalty, continue")
+ end
+ elseif p == penalty then
+ if trace_specials then
+ report_specials(" context penalty %a, same level, overloading",p)
+ end
+ return special_penalty_xxx
+ elseif p > special_penalty_min and p < special_penalty_max then
+ if penalty < p then
+ if trace_specials then
+ report_specials(" context penalty %a, lower level, overloading",p)
+ end
+ return special_penalty_xxx
+ else
+ if trace_specials then
+ report_specials(" context penalty %a, higher level, quitting",p)
+ end
+ return
+ end
+ elseif trace_specials then
+ report_specials(" context penalty %a, higher level, continue",p)
end
- return current
- elseif p >= 10000 then
- current = current.prev
else
- break
+ local p = getfield(current,"penalty")
+ if p < 10000 then
+ -- assume some other mechanism kicks in so we seem to have content
+ if trace_specials then
+ report_specials(" regular penalty %a, quitting",p)
+ end
+ break
+ else
+ if trace_specials then
+ report_specials(" regular penalty %a, continue",p)
+ end
+ end
+ end
+ end
+ current = getprev(current)
+ end
+ -- none found, so no reson to be special
+ if trace_specials then
+ if pagetail then
+ report_specials(" context penalty, discarding, nothing special")
+ else
+ report_specials(" context penalty, discarding, nothing preceding")
+ end
+ end
+ return special_penalty_xxx
+end
+
+-- specialmethods[2] : always put something before and use that as to-be-changed
+--
+-- we could inject a vadjust to force a recalculation .. a mess
+--
+-- So, the next is far from robust and okay but for the moment this overlaying
+-- has to do. Always test this with the examples in spec-ver.mkvi!
+
+local function check_experimental_overlay(head,current)
+ local p = nil
+ local c = current
+ local n = nil
+
+ -- setfield(head,"prev",nil) -- till we have 0.79 **
+
+ local function overlay(p,n,mvl)
+ local p_ht = getfield(p,"height")
+ local p_dp = getfield(p,"depth")
+ local n_ht = getfield(n,"height")
+ local skips = 0
+ --
+ -- We deal with this at the tex end .. we don't see spacing .. enabling this code
+ -- is probably harmless btu then we need to test it.
+ --
+ local c = getnext(p)
+ while c and c ~= n do
+ local id = getid(c)
+ if id == glue_code then
+ skips = skips + getfield(getfield(c,"glue_spec"),"width")
+ elseif id == kern_code then
+ skips = skips + getfield(c,"kern")
end
+ c = getnext(c)
+ end
+ --
+ local delta = n_ht + skips + p_dp
+ texsetdimen("global","d_spac_overlay",-delta) -- for tracing
+ local k = new_kern(-delta)
+ if n_ht > p_ht then
+ -- we should adapt pagetotal ! (need a hook for that) .. now we have the wrong pagebreak
+ setfield(p,"height",n_ht)
+ end
+ insert_node_before(head,n,k)
+ if p == head then
+ head = k
+ end
+ if trace_vspacing then
+ report_vspacing("overlaying, prev height: %p, prev depth: %p, next height: %p, skips: %p, move up: %p",p_ht,p_dp,n_ht,skips,delta)
+ end
+ return remove_node(head,current,true)
+ end
+
+ -- goto next line
+ while c do
+ local id = getid(c)
+ if id == glue_code or id == penalty_code or id == kern_code then
+ -- skip (actually, remove)
+ c = getnext(c)
+ elseif id == hlist_code then
+ n = c
+ break
else
- current = current.prev
+ break
+ end
+ end
+ if n then
+ -- we have a next line, goto prev line
+ c = current
+ while c do
+ local id = getid(c)
+ if id == glue_code or id == penalty_code then
+ c = getprev(c)
+ elseif id == hlist_code then
+ p = c
+ break
+ else
+ break
+ end
+ end
+ if not p then
+ if a_snapmethod == a_snapvbox then
+ -- quit, we're not on the mvl
+ else
+ local c = tonut(texlists.page_head)
+ while c and c ~= n do
+ local id = getid(c)
+ if id == hlist_code then
+ p = c
+ end
+ c = getnext(c)
+ end
+ if p and p ~= n then
+ return overlay(p,n,true)
+ end
+ end
+ elseif p ~= n then
+ return overlay(p,n,false)
end
end
+ -- in fact, we could try again later ... so then no remove (a few tries)
+ return remove_node(head, current, true)
end
+-- This will be replaced after 0.80+ when we have a more robust look-back and
+-- can look at the bigger picture.
+
+-- todo: look back and when a special is there before a list is seen penalty keep ut
+
+-- we now look back a lot, way too often
+
local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also pass tail
if trace then
reset_tracing(head)
end
local current, oldhead = head, head
local glue_order, glue_data, force_glue = 0, nil, false
- local penalty_order, penalty_data, natural_penalty = 0, nil, nil
+ local penalty_order, penalty_data, natural_penalty, special_penalty = 0, nil, nil, nil
local parskip, ignore_parskip, ignore_following, ignore_whitespace, keep_together = nil, false, false, false, false
--
-- todo: keep_together: between headers
--
+ local pagehead = nil
+ local pagetail = nil
+
+ local function getpagelist()
+ if not pagehead then
+ pagehead = texlists.page_head
+ if pagehead then
+ pagehead = tonut(texlists.page_head)
+ pagetail = find_node_tail(pagehead) -- no texlists.page_tail yet-- no texlists.page_tail yet
+ end
+ end
+ end
+ --
local function flush(why)
if penalty_data then
local p = new_penalty(penalty_data)
if trace then trace_done("flushed due to " .. why,p) end
- head = insert_node_before(head,current,p)
+ if penalty_data >= 10000 then -- or whatever threshold?
+ local prev = getprev(current)
+ if getid(prev) == glue_code then -- maybe go back more, or maybe even push back before any glue
+ -- tricky case: spacing/grid-007.tex: glue penalty glue
+ head = insert_node_before(head,prev,p)
+ else
+ head = insert_node_before(head,current,p)
+ end
+ else
+ head = insert_node_before(head,current,p)
+ end
+-- if penalty_data > special_penalty_min and penalty_data < special_penalty_max then
+ local props = properties[p]
+ if props then
+ props.special_penalty = special_penalty or penalty_data
+ else
+ properties[p] = {
+ special_penalty = special_penalty or penalty_data
+ }
+ end
+-- end
end
if glue_data then
- local spec = glue_data.spec
+ local spec = getfield(glue_data,"spec")
if force_glue then
if trace then trace_done("flushed due to " .. why,glue_data) end
- head = forced_skip(head,current,spec.width,"before",trace)
+ head = forced_skip(head,current,getfield(spec,"width"),"before",trace)
free_glue_node(glue_data)
- elseif spec.writable then
+ elseif getfield(spec,"writable") then
if trace then trace_done("flushed due to " .. why,glue_data) end
head = insert_node_before(head,current,glue_data)
else
@@ -892,6 +1184,26 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also
penalty_order, penalty_data, natural_penalty = 0, nil, nil
parskip, ignore_parskip, ignore_following, ignore_whitespace = nil, false, false, false
end
+ --
+
+-- quick hack, can be done nicer
+-- local nobreakfound = nil
+-- local function checknobreak()
+-- local pagehead, pagetail = getpagelist()
+-- local current = pagetail
+-- while current do
+-- local id = getid(current)
+-- if id == hlist_code or id == vlist_code then
+-- return false
+-- elseif id == penalty_code then
+-- return getfield(current,"penalty") >= 10000
+-- end
+-- current = getprev(current)
+-- end
+-- return false
+-- end
+
+ --
if trace_vsnapping then
report_snapper("global ht/dp = %p/%p, local ht/dp = %p/%p",
texgetdimen("globalbodyfontstrutheight"), texgetdimen("globalbodyfontstrutdepth"),
@@ -899,13 +1211,19 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also
)
end
if trace then trace_info("start analyzing",where,what) end
+
+-- local headprev = getprev(head)
+
while current do
- local id = current.id
+ local id = getid(current)
if id == hlist_code or id == vlist_code then
+-- if nobreakfound == nil then
+-- nobreakfound = false
+-- end
-- needs checking, why so many calls
if snap then
- local list = current.list
- local s = current[a_snapmethod]
+ local list = getlist(current)
+ local s = getattr(current,a_snapmethod)
if not s then
-- if trace_vsnapping then
-- report_snapper("mvl list not snapped")
@@ -919,8 +1237,8 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also
if sv then
-- check if already snapped
if list and already_done(id,list,a_snapmethod) then
- local ht = current.height
- local dp = current.depth
+ local ht = getfield(current,"height")
+ local dp = getfield(current,"depth")
-- assume that the box is already snapped
if trace_vsnapping then
report_snapper("mvl list already snapped at (%p,%p): %s",ht,dp,listtoutf(list))
@@ -935,40 +1253,60 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also
elseif trace_vsnapping then
report_snapper("mvl %a not snapped due to unknown snap specification: %s",nodecodes[id],listtoutf(list))
end
- current[a_snapmethod] = 0
+ setattr(current,a_snapmethod,0)
end
else
--
end
-- tex.prevdepth = 0
flush("list")
- current = current.next
+ current = getnext(current)
elseif id == penalty_code then
- -- natural_penalty = current.penalty
+ -- natural_penalty = getfield(current,"penalty")
-- if trace then trace_done("removed penalty",current) end
-- head, current = remove_node(head, current, true)
- current = current.next
+
+-- if nobreakfound == nil then
+-- nobreakfound = checknobreak()
+-- end
+-- if nobreakfound and getfield(current,"penalty") <= 10000 then
+-- -- if trace then
+-- trace_done("removed penalty",current)
+-- -- end
+-- head, current = remove_node(head, current, true)
+-- end
+
+ current = getnext(current)
elseif id == kern_code then
- if snap and trace_vsnapping and current.kern ~= 0 then
- report_snapper("kern of %p kept",current.kern)
+ if snap and trace_vsnapping and getfield(current,"kern") ~= 0 then
+ report_snapper("kern of %p kept",getfield(current,"kern"))
end
flush("kern")
- current = current.next
+ current = getnext(current)
elseif id == glue_code then
- local subtype = current.subtype
+ local subtype = getsubtype(current)
if subtype == userskip_code then
- local sc = current[a_skipcategory] -- has no default, no unset (yet)
- local so = current[a_skiporder] or 1 -- has 1 default, no unset (yet)
- local sp = current[a_skippenalty] -- has no default, no unset (yet)
+ local sc = getattr(current,a_skipcategory) -- has no default, no unset (yet)
+ local so = getattr(current,a_skiporder) or 1 -- has 1 default, no unset (yet)
+ local sp = getattr(current,a_skippenalty) -- has no default, no unset (yet)
if sp and sc == penalty then
+ if where == "page" then
+ getpagelist()
+ local p = specialmethods[specialmethod](pagehead,pagetail,current,sp)
+ if p then
+ if trace then
+ trace_skip("previous special penalty %a is changed to %a using method %a",sp,p,specialmethod)
+ end
+ special_penalty = sp
+ sp = p
+ end
-if where == "page" and sp >= special_penalty_min and sp <= special_penalty_max then
- local previousspecial = specialpenalty(current,sp)
- if previousspecial then
- previousspecial.penalty = 0
- sp = 0
- end
-end
+-- else
+-- if nobreakfound == nil then
+-- nobreakfound = checknobreak()
+-- end
+
+ end
if not penalty_data then
penalty_data = sp
elseif penalty_order < so then
@@ -977,43 +1315,52 @@ end
penalty_data = sp
end
if trace then trace_skip("penalty in skip",sc,so,sp,current) end
+
+-- if nobreakfound then
+-- penalty_data = 10000
+-- if trace then
+-- trace_skip("nobreak found before penalty in skip",sc,so,sp,current)
+-- end
+-- 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 = insert_node_before(head,current,glue_data)
if trace then trace_natural("natural",current) end
- current = current.next
+ current = getnext(current)
else
-- not look back across head
--- todo: prev can be whatsit (latelua)
- local previous = current.prev
- if previous and previous.id == glue_code and previous.subtype == userskip_code then
- local ps = previous.spec
- if ps.writable then
- local cs = current.spec
- if cs.writable and ps.stretch_order == 0 and ps.shrink_order == 0 and cs.stretch_order == 0 and cs.shrink_order == 0 then
- local pw, pp, pm = ps.width, ps.stretch, ps.shrink
- local cw, cp, cm = cs.width, cs.stretch, cs.shrink
+ -- todo: prev can be whatsit (latelua)
+ local previous = getprev(current)
+ if previous and getid(previous) == glue_code and getsubtype(previous) == userskip_code then
+ local ps = getfield(previous,"spec")
+ if getfield(ps,"writable") then
+ local cs = getfield(current,"spec")
+ if getfield(cs,"writable") and getfield(ps,"stretch_order") == 0 and getfield(ps,"shrink_order") == 0 and getfield(cs,"stretch_order") == 0 and getfield(cs,"shrink_order") == 0 then
+ local pw, pp, pm = getfield(ps,"width"), getfield(ps,"stretch"), getfield(ps,"shrink")
+ local cw, cp, cm = getfield(cs,"width"), getfield(cs,"stretch"), getfield(cs,"shrink")
-- ps = writable_spec(previous) -- no writable needed here
-- ps.width, ps.stretch, ps.shrink = pw + cw, pp + cp, pm + cm
- previous.spec = new_gluespec(pw + cw, pp + cp, pm + cm) -- else topskip can disappear
+ free_glue_spec(ps)
+ setfield(previous,"spec",new_gluespec(pw + cw, pp + cp, pm + cm)) -- else topskip can disappear
if trace then trace_natural("removed",current) end
head, current = remove_node(head, current, true)
-- current = previous
if trace then trace_natural("collapsed",previous) end
- -- current = current.next
+ -- current = getnext(current)
else
if trace then trace_natural("filler",current) end
- current = current.next
+ current = getnext(current)
end
else
if trace then trace_natural("natural (no prev spec)",current) end
- current = current.next
+ current = getnext(current)
end
else
if trace then trace_natural("natural (no prev)",current) end
- current = current.next
+ current = getnext(current)
end
end
glue_order, glue_data = 0, nil
@@ -1031,6 +1378,12 @@ end
elseif sc == discard then
if trace then trace_skip("discard",sc,so,sp,current) end
head, current = remove_node(head, current, true)
+ elseif sc == overlay then
+ -- todo (overlay following line over previous
+ if trace then trace_skip("overlay",sc,so,sp,current) end
+ -- beware: head can actually be after the affected nodes as
+ -- we look back ... some day head will the real head
+ head, current = check_experimental_overlay(head,current,a_snapmethod)
elseif ignore_following then
if trace then trace_skip("disabled",sc,so,sp,current) end
head, current = remove_node(head, current, true)
@@ -1046,12 +1399,12 @@ end
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, gw = cs.width, gs.width
+ local cs, gs = getfield(current,"spec"), getfield(glue_data,"spec")
+ local cw, gw = getfield(cs,"width"), getfield(gs,"width")
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)
+ 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)
@@ -1059,7 +1412,7 @@ 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)
+ head, current, glue_data = remove_node(head,current)
elseif sc == force then
-- last one counts, some day we can provide an accumulator and largest etc
-- but not now
@@ -1073,11 +1426,11 @@ end
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
- local old, new = writable_spec(glue_data), current.spec
- old.width = old.width + new.width
- old.stretch = old.stretch + new.stretch
- old.shrink = old.shrink + new.shrink
+ -- local old, new = glue_data.spec, getfield(current,"spec")
+ local old, new = writable_spec(glue_data), getfield(current,"spec")
+ setfield(old,"width",getfield(old,"width") + getfield(new,"width"))
+ setfield(old,"stretch",getfield(old,"stretch") + getfield(new,"stretch"))
+ setfield(old,"shrink",getfield(old,"shrink") + getfield(new,"shrink"))
-- toto: order
head, current = remove_node(head, current, true)
else
@@ -1093,12 +1446,13 @@ end
end
elseif subtype == lineskip_code then
if snap then
- local s = current[a_snapmethod]
+ local s = getattr(current,a_snapmethod)
if s and s ~= 0 then
- current[a_snapmethod] = 0
- if current.spec.writable then
+ setattr(current,a_snapmethod,0)
+ local spec = getfield(current,"spec")
+ if getfield(spec,"writable") then
local spec = writable_spec(current)
- spec.width = 0
+ setfield(spec,"width",0)
if trace_vsnapping then
report_snapper("lineskip set to zero")
end
@@ -1111,15 +1465,16 @@ end
if trace then trace_skip("lineskip",sc,so,sp,current) end
flush("lineskip")
end
- current = current.next
+ current = getnext(current)
elseif subtype == baselineskip_code then
if snap then
- local s = current[a_snapmethod]
+ local s = getattr(current,a_snapmethod)
if s and s ~= 0 then
- current[a_snapmethod] = 0
- if current.spec.writable then
+ setattr(current,a_snapmethod,0)
+ local spec = getfield(current,"spec")
+ if getfield(spec,"writable") then
local spec = writable_spec(current)
- spec.width = 0
+ setfield(spec,"width",0)
if trace_vsnapping then
report_snapper("baselineskip set to zero")
end
@@ -1132,17 +1487,17 @@ end
if trace then trace_skip("baselineskip",sc,so,sp,current) end
flush("baselineskip")
end
- current = current.next
+ current = getnext(current)
elseif subtype == parskip_code 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)
elseif glue_data then
- local ps = current.spec
- local gs = glue_data.spec
- if ps.writable and gs.writable and ps.width > gs.width then
- glue_data.spec = copy_node(ps)
+ local ps = getfield(current,"spec")
+ local gs = getfield(glue_data,"spec")
+ if getfield(ps,"writable") and getfield(gs,"writable") and getfield(ps,"width") > getfield(gs,"width") then
+ setfield(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
@@ -1154,9 +1509,9 @@ end
end
elseif subtype == topskip_code or subtype == splittopskip_code then
if snap then
- local s = current[a_snapmethod]
+ local s = getattr(current,a_snapmethod)
if s and s ~= 0 then
- current[a_snapmethod] = 0
+ setattr(current,a_snapmethod,0)
local sv = snapmethods[s]
local w, cw = snap_topskip(current,sv)
if trace_vsnapping then
@@ -1170,46 +1525,46 @@ end
if trace then trace_skip("topskip",sc,so,sp,current) end
flush("topskip")
end
- current = current.next
+ current = getnext(current)
elseif subtype == abovedisplayskip_code then
--
if trace then trace_skip("above display skip (normal)",sc,so,sp,current) end
flush("above display skip (normal)")
- current = current.next
+ current = getnext(current)
--
elseif subtype == belowdisplayskip_code then
--
if trace then trace_skip("below display skip (normal)",sc,so,sp,current) end
flush("below display skip (normal)")
- current = current.next
- --
+ current = getnext(current)
+ --
elseif subtype == abovedisplayshortskip_code then
--
if trace then trace_skip("above display skip (short)",sc,so,sp,current) end
flush("above display skip (short)")
- current = current.next
+ current = getnext(current)
--
elseif subtype == belowdisplayshortskip_code then
--
if trace then trace_skip("below display skip (short)",sc,so,sp,current) end
flush("below display skip (short)")
- current = current.next
+ current = getnext(current)
--
else -- other glue
if snap and trace_vsnapping then
- local spec = current.spec
- if spec.writable and spec.width ~= 0 then
- report_snapper("glue %p of type %a kept",current.spec.width,skipcodes[subtype])
- -- spec.width = 0
+ local spec = getfield(current,"spec")
+ if getfield(spec,"writable") and getfield(spec,"width") ~= 0 then
+ report_snapper("glue %p of type %a kept",getfield(spec,"width"),skipcodes[subtype])
+ -- setfield(spec,"width",0)
end
end
- if trace then trace_skip(formatter["glue of type %a"](subtype),sc,so,sp,current) end
+ if trace then trace_skip(formatters["glue of type %a"](subtype),sc,so,sp,current) end
flush("some glue")
- current = current.next
+ current = getnext(current)
end
else
- flush("something else")
- current = current.next
+ flush(formatters["node with id %a"](id))
+ current = getnext(current)
end
end
if trace then trace_info("stop analyzing",where,what) end
@@ -1225,17 +1580,28 @@ end
local p = new_penalty(penalty_data)
if trace then trace_done("result",p) end
head, tail = insert_node_after(head,tail,p)
+ -- if penalty_data > special_penalty_min and penalty_data < special_penalty_max then
+ local props = properties[p]
+ if props then
+ props.special_penalty = special_penalty or penalty_data
+ else
+ properties[p] = {
+ special_penalty = special_penalty or penalty_data
+ }
+ end
+ -- end
end
if glue_data then
if not tail then tail = find_node_tail(head) end
if trace then trace_done("result",glue_data) end
if force_glue then
- head, tail = forced_skip(head,tail,glue_data.spec.width,"after",trace)
+ local spec = getfield(glue_data,"spec")
+ head, tail = forced_skip(head,tail,getfield(spec,"width"),"after",trace)
free_glue_node(glue_data)
else
head, tail = insert_node_after(head,tail,glue_data)
end
-texnest[texnest.ptr].prevdepth = 0 -- appending to the list bypasses tex's prevdepth handler
+ texnest[texnest.ptr].prevdepth = 0 -- appending to the list bypasses tex's prevdepth handler
end
if trace then
if glue_data or penalty_data then
@@ -1243,9 +1609,16 @@ texnest[texnest.ptr].prevdepth = 0 -- appending to the list bypasses tex's prevd
end
show_tracing(head)
if oldhead ~= head then
- trace_info("head has been changed from %a to %a",nodecodes[oldhead.id],nodecodes[head.id])
+ trace_info("head has been changed from %a to %a",nodecodes[getid(oldhead)],nodecodes[getid(head)])
end
end
+
+-- if headprev then
+-- setprev(head,headprev)
+-- setnext(headprev,head)
+-- end
+-- print("C HEAD",tonode(head))
+
return head, true
end
@@ -1271,16 +1644,17 @@ end
function vspacing.pagehandler(newhead,where)
-- local newhead = texlists.contrib_head
if newhead then
+ newhead = tonut(newhead)
local newtail = find_node_tail(newhead) -- best pass that tail, known anyway
local flush = false
stackhack = true -- todo: only when grid snapping once enabled
-- todo: fast check if head = tail
for n in traverse_nodes(newhead) do -- we could just look for glue nodes
- local id = n.id
+ local id = getid(n)
if id ~= glue_code then
flush = true
- elseif n.subtype == userskip_code then
- if n[a_skipcategory] then
+ elseif getsubtype(n) == userskip_code then
+ if getattr(n,a_skipcategory) then
stackhack = true
else
flush = true
@@ -1292,35 +1666,36 @@ function vspacing.pagehandler(newhead,where)
if flush then
if stackhead then
if trace_collect_vspacing then report("appending %s nodes to stack (final): %s",newhead) end
- stacktail.next = newhead
- newhead.prev = stacktail
+ setfield(stacktail,"next",newhead)
+ setfield(newhead,"prev",stacktail)
newhead = stackhead
stackhead, stacktail = nil, nil
end
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,true,a_snapmethod)
- newhead = collapser(newhead,"page",where,trace_page_vspacing,true,a_snapmethod)
+ -- texlists.contrib_head = collapser(newhead,"page",where,trace_page_vspacing,true,a_snapmethod)
+ newhead = collapser(newhead,"page",where,trace_page_vspacing,true,a_snapmethod)
else
if trace_collect_vspacing then report("flushing %s nodes: %s",newhead) end
-- texlists.contrib_head = newhead
end
+ return tonode(newhead)
else
if stackhead then
if trace_collect_vspacing then report("appending %s nodes to stack (intermediate): %s",newhead) end
- stacktail.next = newhead
- newhead.prev = stacktail
+ setfield(stacktail,"next",newhead)
+ setfield(newhead,"prev",stacktail)
else
if trace_collect_vspacing then report("storing %s nodes in stack (initial): %s",newhead) end
stackhead = newhead
end
stacktail = newtail
-- texlists.contrib_head = nil
- newhead = nil
+ -- newhead = nil
end
end
- return newhead
+ return nil
end
local ignore = table.tohash {
@@ -1330,18 +1705,27 @@ local ignore = table.tohash {
}
function vspacing.vboxhandler(head,where)
- if head and not ignore[where] and head.next then
- head = collapser(head,"vbox",where,trace_vbox_vspacing,true,a_snapvbox) -- todo: local snapper
+ if head and not ignore[where] then
+ local h = tonut(head)
+ if getnext(h) then -- what if a one liner and snapping?
+ h = collapser(h,"vbox",where,trace_vbox_vspacing,true,a_snapvbox) -- todo: local snapper
+ return tonode(h)
+ end
end
return head
end
-function vspacing.collapsevbox(n) -- for boxes but using global a_snapmethod
- local box = texgetbox(n)
+function vspacing.collapsevbox(n,aslist) -- for boxes but using global a_snapmethod
+ local box = getbox(n)
if box then
- local list = box.list
+ local list = getlist(box)
if list then
- box.list = vpack_node(collapser(list,"snapper","vbox",trace_vbox_vspacing,true,a_snapmethod))
+ list = collapser(list,"snapper","vbox",trace_vbox_vspacing,true,a_snapmethod)
+ if aslist then
+ setfield(box,"list",list) -- beware, dimensions of box are wrong now
+ else
+ setfield(box,"list",vpack_node(list))
+ end
end
end
end
@@ -1352,14 +1736,65 @@ end
local outer = texnest[0]
function vspacing.resetprevdepth()
- outer.prevdepth = 0
+ if texlists.hold_head then
+ outer.prevdepth = 0
+ end
end
-- interface
-commands.vspacing = vspacing.analyze
-commands.vspacingsetamount = vspacing.setskip
-commands.vspacingdefine = vspacing.setmap
-commands.vspacingcollapse = vspacing.collapsevbox
-commands.vspacingsnap = vspacing.snapbox
-commands.resetprevdepth = vspacing.resetprevdepth
+implement {
+ name = "vspacing",
+ actions = vspacing.analyze,
+ scope = "private",
+ arguments = "string"
+}
+
+implement {
+ name = "resetprevdepth",
+ actions = vspacing.resetprevdepth,
+ scope = "private"
+}
+
+implement {
+ name = "vspacingsetamount",
+ actions = vspacing.setskip,
+ scope = "private",
+ arguments = "string",
+}
+
+implement {
+ name = "vspacingdefine",
+ actions = vspacing.setmap,
+ scope = "private",
+ arguments = { "string", "string" }
+}
+
+implement {
+ name = "vspacingcollapse",
+ actions = vspacing.collapsevbox,
+ scope = "private",
+ arguments = "integer"
+}
+
+implement {
+ name = "vspacingcollapseonly",
+ actions = vspacing.collapsevbox,
+ scope = "private",
+ arguments = { "integer", true }
+}
+
+implement {
+ name = "vspacingsnap",
+ actions = vspacing.snapbox,
+ scope = "private",
+ arguments = { "integer", "integer" }
+}
+
+implement {
+ name = "definesnapmethod",
+ actions = vspacing.definesnapmethod,
+ scope = "private",
+ arguments = { "string", "string" }
+}
+