summaryrefslogtreecommitdiff
path: root/tex/context/base/typo-mar.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/typo-mar.lua')
-rw-r--r--tex/context/base/typo-mar.lua308
1 files changed, 191 insertions, 117 deletions
diff --git a/tex/context/base/typo-mar.lua b/tex/context/base/typo-mar.lua
index 6e941bac0..4d9043424 100644
--- a/tex/context/base/typo-mar.lua
+++ b/tex/context/base/typo-mar.lua
@@ -31,7 +31,7 @@ if not modules then modules = { } end modules ['typo-mar'] = {
-- whatever[tag] = nil
-- end
--
--- function anchors.startmove(tag,how)
+-- function anchors.startmove(tag,how) -- save/restore nodes but they don't support moves
-- local w = whatever[tag]
-- if not w then
-- -- error
@@ -84,93 +84,103 @@ local trace_marginstack = false trackers.register("typesetters.margindata.stack
local report_margindata = logs.reporter("typesetters","margindata")
-local tasks = nodes.tasks
-local prependaction = tasks.prependaction
-local disableaction = tasks.disableaction
-local enableaction = tasks.enableaction
-
-local variables = interfaces.variables
-
-local conditionals = tex.conditionals
-
-local v_top = variables.top
-local v_depth = variables.depth
-local v_local = variables["local"]
-local v_global = variables["global"]
-local v_left = variables.left
-local v_right = variables.right
-local v_flushleft = variables.flushleft
-local v_flushright = variables.flushright
-local v_inner = variables.inner
-local v_outer = variables.outer
-local v_margin = variables.margin
-local v_edge = variables.edge
-local v_default = variables.default
-local v_normal = variables.normal
-local v_yes = variables.yes
-local v_first = variables.first
-
-local has_attribute = node.has_attribute
-local set_attribute = node.set_attribute
-local unset_attribute = node.unset_attribute
-local copy_node_list = node.copy_list
-local slide_nodes = node.slide
-local hpack_nodes = node.hpack -- nodes.fasthpack not really faster here
-local traverse_id = node.traverse_id
-local free_node_list = node.flush_list
-local insert_node_after= node.insert_after
-
-local link_nodes = nodes.link
-
-local nodecodes = nodes.nodecodes
-local listcodes = nodes.listcodes
-local gluecodes = nodes.gluecodes
-local whatsitcodes = nodes.whatsitcodes
-
-local hlist_code = nodecodes.hlist
-local vlist_code = nodecodes.vlist
-local glue_code = nodecodes.glue
-local kern_code = nodecodes.kern
-local penalty_code = nodecodes.penalty
-local whatsit_code = nodecodes.whatsit
-local line_code = listcodes.line
-local leftskip_code = gluecodes.leftskip
-local rightskip_code = gluecodes.rightskip
-local userdefined_code = whatsitcodes.userdefined
-
-local dir_code = whatsitcodes.dir
-local localpar_code = whatsitcodes.localpar
-
-local nodepool = nodes.pool
-
-local new_kern = nodepool.kern
-local new_penalty = nodepool.penalty
-local new_stretch = nodepool.stretch
-local new_usernumber = nodepool.usernumber
-local new_latelua = nodepool.latelua
-
-local texcount = tex.count
-local texdimen = tex.dimen
-local texbox = tex.box
-
-local isleftpage = layouts.status.isleftpage
-local registertogether = builders.paragraphs.registertogether
-
-local a_margindata = attributes.private("margindata")
-
-local inline_mark = nodepool.userids["margins.inline"]
-
-local margins = { }
-typesetters.margins = margins
-
-local locations = { v_left, v_right, v_inner, v_outer } -- order might change
-local categories = { }
-local displaystore = { } -- [category][location][scope]
-local inlinestore = { } -- [number]
-local nofsaved = 0
-local nofstored = 0
-local nofinlined = 0
-local nofdelayed = 0
+local tasks = nodes.tasks
+local prependaction = tasks.prependaction
+local disableaction = tasks.disableaction
+local enableaction = tasks.enableaction
+
+local variables = interfaces.variables
+
+local conditionals = tex.conditionals
+
+local v_top = variables.top
+local v_depth = variables.depth
+local v_local = variables["local"]
+local v_global = variables["global"]
+local v_left = variables.left
+local v_right = variables.right
+local v_flushleft = variables.flushleft
+local v_flushright = variables.flushright
+local v_inner = variables.inner
+local v_outer = variables.outer
+local v_margin = variables.margin
+local v_edge = variables.edge
+local v_default = variables.default
+local v_normal = variables.normal
+local v_yes = variables.yes
+local v_continue = variables.continue
+local v_first = variables.first
+
+local has_attribute = node.has_attribute
+local set_attribute = node.set_attribute
+local unset_attribute = node.unset_attribute
+local copy_node_list = node.copy_list
+local slide_nodes = node.slide
+local hpack_nodes = node.hpack -- nodes.fasthpack not really faster here
+local traverse_id = node.traverse_id
+local free_node_list = node.flush_list
+local insert_node_after = node.insert_after
+local insert_node_before = node.insert_before
+
+local link_nodes = nodes.link
+
+local nodecodes = nodes.nodecodes
+local listcodes = nodes.listcodes
+local gluecodes = nodes.gluecodes
+local whatsitcodes = nodes.whatsitcodes
+
+local hlist_code = nodecodes.hlist
+local vlist_code = nodecodes.vlist
+local glue_code = nodecodes.glue
+local kern_code = nodecodes.kern
+local penalty_code = nodecodes.penalty
+local whatsit_code = nodecodes.whatsit
+local line_code = listcodes.line
+local leftskip_code = gluecodes.leftskip
+local rightskip_code = gluecodes.rightskip
+local userdefined_code = whatsitcodes.userdefined
+
+local dir_code = whatsitcodes.dir
+local localpar_code = whatsitcodes.localpar
+
+local nodepool = nodes.pool
+
+local new_kern = nodepool.kern
+local new_glue = nodepool.glue
+local new_penalty = nodepool.penalty
+local new_stretch = nodepool.stretch
+local new_usernumber = nodepool.usernumber
+local new_latelua = nodepool.latelua
+
+local texcount = tex.count
+local texdimen = tex.dimen
+local texbox = tex.box
+
+local points = number.points
+
+local isleftpage = layouts.status.isleftpage
+local registertogether = builders.paragraphs.registertogether
+
+local jobpositions = job.positions
+local getposition = jobpositions.position
+
+local a_margindata = attributes.private("margindata")
+
+local inline_mark = nodepool.userids["margins.inline"]
+
+local margins = { }
+typesetters.margins = margins
+
+local locations = { v_left, v_right, v_inner, v_outer } -- order might change
+local categories = { }
+local displaystore = { } -- [category][location][scope]
+local inlinestore = { } -- [number]
+local nofsaved = 0
+local nofstored = 0
+local nofinlined = 0
+local nofdelayed = 0
+local h_anchors = 0
+local v_anchors = 0
local mt1 = {
__index = function(t,location)
@@ -339,7 +349,7 @@ end
-- When the prototype inner/outer code that was part of this proved to be
-- okay it was moved elsewhere.
-local status, nofstatus, anchors = { }, 0, 0
+local status, nofstatus = { }, 0
local function realign(current,candidate)
local location = candidate.location
@@ -396,15 +406,15 @@ local function realign(current,candidate)
current.width = 0
if candidate.inline then -- this mess is needed for alignments (combinations)
- anchors = anchors + 1
- local anchor = new_latelua(format("_plib_.setraw('_md_:%s',pdf.h)",anchors))
- local blob_x = job.positions.v("_md_:"..anchors) or 0
- local text_x = job.positions.x("text:"..tex.count.realpageno) or 0
+ h_anchors = h_anchors + 1
+ local anchor = new_latelua(format("_plib_.setraw('_mh_:%s',pdf.h)",h_anchors))
+ local blob_x = jobpositions.v("_mh_:"..h_anchors) or 0
+ local text_x = jobpositions.x("text:"..texcount.realpageno) or 0
local move_x = text_x - blob_x
delta = delta - move_x
current.list = hpack_nodes(link_nodes(anchor,new_kern(-delta),current.list,new_kern(delta)))
if trace_margindata then
- report_margindata("realigned: %s, location: %s, margin: %s, move: %s",candidate.n,location,margin,number.points(move_x))
+ report_margindata("realigned: %s, location: %s, margin: %s, move: %s",candidate.n,location,margin,points(move_x))
end
else
current.list = hpack_nodes(link_nodes(new_kern(-delta),current.list,new_kern(delta)))
@@ -412,7 +422,6 @@ local function realign(current,candidate)
report_margindata("realigned: %s, location: %s, margin: %s",candidate.n,location,margin)
end
end
-
current.width = 0
end
@@ -424,15 +433,62 @@ local function realigned(current,a)
return true
end
+-- Stacking is done in two ways: the v_yes option stacks per paragraph (or line,
+-- depending on what gets by) and mostly concerns margin data dat got ste at more or
+-- less the same time. The v_continue option uses position tracking and works on
+-- larger range. However, crossing pages is not part of it. Anyway, when you have
+-- such messed up margin data you'd better think twice.
+--
+-- The stacked table keeps track (per location) of the offsets (the v_yes case). This
+-- table gets saved when the v_continue case is active. We use a special variant
+-- of position tracking, after all we only need the page number and vertical position.
+
local stacked = { }
+local cache = { }
local function resetstacked()
- for i=1,#locations do
- stacked[locations[i]] = false
- end
+-- for i=1,#locations do
+-- stacked[locations[i]] = false
+-- end
+ stacked = { }
+end
+
+-- resetstacked()
+
+function margins.ha(tag)
+ local p = cache[tag]
+ p.r = texcount.realpageno
+ p.y = pdf.v
+ _plib_.setraw('_mv_:'..tag,p)
+ cache[tag] = nil
+end
+
+local function markovershoot(current)
+ h_anchors = h_anchors + 1
+ cache[h_anchors] = stacked
+ local anchor = new_latelua(format("typesetters.margins.ha(%s)",h_anchors)) -- todo: alleen als offset > line
+ current.list = hpack_nodes(link_nodes(anchor,current.list))
end
-resetstacked()
+local function getovershoot(location)
+ local previous = '_mv_:' .. h_anchors
+ local current = '_mv_:' .. (h_anchors + 1)
+ local p = jobpositions.v(previous)
+ local c = jobpositions.v(current)
+ if p and c and p.r and p.r == c.r then
+ local distance = p.y - c.y
+ local offset = p[location] or 0
+ local overshoot = offset - distance
+ if trace_marginstack then
+ report_margindata("location: %s, distance: %s, offset: %s, overshoot: %s",
+ location,points(distance),points(offset),points(overshoot))
+ end
+ if overshoot > 0 then
+ return overshoot
+ end
+ end
+ return 0
+end
local function inject(parent,head,candidate)
local box = candidate.box
@@ -447,7 +503,7 @@ local function inject(parent,head,candidate)
local line = candidate.line
local baseline = candidate.baseline
local offset = stacked[location]
- local firstonstack = offset == false
+ local firstonstack = offset == false or offset == nil
nofstatus = nofstatus + 1
nofdelayed = nofdelayed + 1
status[nofstatus] = candidate
@@ -473,6 +529,9 @@ local function inject(parent,head,candidate)
if stack == v_yes then
offset = offset + candidate.dy
shift = shift + offset
+ elseif stack == v_continue then
+ offset = offset + candidate.dy + getovershoot(location)
+ shift = shift + offset
end
-- -- --
-- Maybe we also need to patch offset when we apply methods, but how ...
@@ -537,21 +596,25 @@ local function inject(parent,head,candidate)
-- we need to add line etc to offset as well
offset = offset + depth
local room = {
- height = height,
- depth = offset,
- slack = candidate.bottomspace, -- todo: 'depth' => strutdepth
+ height = height,
+ depth = offset,
+ slack = candidate.bottomspace, -- todo: 'depth' => strutdepth
+ lineheight = candidate.lineheight, -- only for tracing
}
-offset = offset + height
+ offset = offset + height
stacked[location] = offset
-- todo: if no real depth then zero
if trace_margindata then
report_margindata("status, offset: %s",offset)
end
- return head, room
+ return head, room, stack == v_continue
end
-local function flushinline(parent,head,done)
+local function flushinline(parent,head)
local current = head
+ local done = false
+ local continue = false
+ local room, don, con
while current and nofinlined > 0 do
local id = current.id
if id == whatsit_code then
@@ -561,24 +624,28 @@ local function flushinline(parent,head,done)
if candidate then -- no vpack, as we want to realign
inlinestore[n] = nil
nofinlined = nofinlined - 1
- head = inject(parent,head,candidate) -- maybe return applied offset
+ head, room, con = inject(parent,head,candidate) -- maybe return applied offset
+ continue = continue or con
done = true
nofstored = nofstored - 1
end
end
elseif id == hlist_code or id == vlist_code then
-- optional (but sometimes needed)
- current.list, done = flushinline(current,current.list,done)
+ current.list, don, con = flushinline(current,current.list)
+ continue = continue or con
+ done = done or don
end
current = current.next
end
- return head, done
+ return head, done, continue
end
local function flushed(scope,parent) -- current is hlist
- local done = false
local head = parent.list
- local room
+ local done = false
+ local continue = false
+ local room, con, don
for c=1,#categories do
local category = categories[c]
for l=1,#locations do
@@ -587,8 +654,9 @@ local function flushed(scope,parent) -- current is hlist
while true do
local candidate = remove(store,1) -- brr, local stores are sparse
if candidate then -- no vpack, as we want to realign
- head, room = inject(parent,head,candidate) -- maybe return applied offset
+ head, room, con = inject(parent,head,candidate)
done = true
+ continue = continue or con
nofstored = nofstored - 1
registertogether(parent,room)
else
@@ -601,13 +669,15 @@ local function flushed(scope,parent) -- current is hlist
if done then
parent.list = head
end
- head, done = flushinline(parent,head,false)
+ head, don, con = flushinline(parent,head)
+ continue = continue or con
+ done = done or don
end
if done then
parent.list = hpack_nodes(head,parent.width,"exactly")
- resetstacked()
+ -- resetstacked()
end
- return done
+ return done, continue
end
-- only when group : vbox|vmode_par
@@ -623,8 +693,12 @@ local function handler(scope,head,group)
while current do
local id = current.id
if (id == vlist_code or id == hlist_code) and not has_attribute(current,a_margindata) then
- if flushed(scope,current) then
+ local don, continue = flushed(scope,current)
+ if don then
set_attribute(current,a_margindata,0) -- signal to prevent duplicate processing
+ if continue then
+ markovershoot(current)
+ end
if nofstored <= 0 then
break
end
@@ -634,7 +708,7 @@ local function handler(scope,head,group)
current = current.next
end
-- if done then
- -- resetstacked()
+ resetstacked() -- why doesn't done work ok here?
-- end
return head, done
else