summaryrefslogtreecommitdiff
path: root/tex/context/base/typo-lin.lua
diff options
context:
space:
mode:
authorContext Git Mirror Bot <phg42.2a@gmail.com>2015-09-09 22:15:06 +0200
committerContext Git Mirror Bot <phg42.2a@gmail.com>2015-09-09 22:15:06 +0200
commitf28043b96635a0845521fe0094a3863d7ff13b6d (patch)
treeb57730bb08599d5875bee8cf118d832e0c5977a3 /tex/context/base/typo-lin.lua
parentcf4c4c56e5748e91ecc28f8126f5fc6eadfd73fa (diff)
downloadcontext-f28043b96635a0845521fe0094a3863d7ff13b6d.tar.gz
2015-09-09 21:26:00
Diffstat (limited to 'tex/context/base/typo-lin.lua')
-rw-r--r--tex/context/base/typo-lin.lua568
1 files changed, 426 insertions, 142 deletions
diff --git a/tex/context/base/typo-lin.lua b/tex/context/base/typo-lin.lua
index 536252960..6327f8f23 100644
--- a/tex/context/base/typo-lin.lua
+++ b/tex/context/base/typo-lin.lua
@@ -6,106 +6,233 @@ if not modules then modules = { } end modules ['typo-lin'] = {
license = "see context related readme files"
}
--- can become typo-par or so
-
-local trace_anchors = false trackers.register("paragraphs.anchors", function(v) trace_anchors = v end)
-
-local nuts = nodes.nuts
-local nodecodes = nodes.nodecodes
-local gluecodes = nodes.gluecodes
-local listcodes = nodes.listcodes
-local whatcodes = nodes.whatsitcodes
-
-local hlist_code = nodecodes.hlist
-local glue_code = nodecodes.glue
-local whatsit_code = nodecodes.whatsit
-local line_code = listcodes.line
-local leftskip_code = gluecodes.leftskip
-local rightskip_code = gluecodes.rightskip
-local textdir_code = whatcodes.textdir
-local localpar_code = whatcodes.localpar
-
-local tonut = nodes.tonut
-local tonode = nodes.tonode
-
-local traverse_id = nuts.traverse_id
-local insert_before = nuts.insert_before
-local insert_after = nuts.insert_after
-local findtail = nuts.tail
-local remove_node = nuts.remove
-local hpack_nodes = nuts.hpack
-
-local getsubtype = nuts.getsubtype
-local getlist = nuts.getlist
-local getid = nuts.getid
-local getnext = nuts.getnext
-local getfield = nuts.getfield
-local setfield = nuts.setfield
-
-local setprop = nuts.setprop
-local getprop = nuts.getprop
-
-local nodepool = nuts.pool
-local new_glue = nodepool.glue
-local new_kern = nodepool.kern
-local new_leftskip = nodepool.leftskip
-local new_rightskip = nodepool.rightskip
-local new_hlist = nodepool.hlist
-local new_vlist = nodepool.vlist
-local new_rule = nodepool.rule
-
-local texgetcount = tex.getcount
-
-local paragraphs = { }
-typesetters.paragraphs = paragraphs
-
--- also strip disc
-
+-- This is experimental code. The idea is to create an anchor point in a line but there are
+-- some considerations:
+--
+-- * if we normalize in order to have more easy access later on, we need to normalize all
+-- lines and we cannot catch all without losing efficiency
+--
+-- * if we normalize too soon, we might have issues with changed properties later on
+--
+-- * if we normalize too late, we have no knowledge of the current hsize
+--
+-- * if we always create an anchor we also create unwanted overhead if it is not used later
+-- on (more nodes)
+--
+-- The question is: do we mind of at the first access an anchor is created? As we cannot know
+-- that now, I choose some middle ground but this might change. if we don't assume direct
+-- access but only helpers, we can decide later.
+--
+-- Because of right2left mess it makes sense to use helpers so that we only need to deal with
+-- this mess once, in helpers. The more abstraction there the better. And so, after a week of
+-- experimenting, yet another abstraction was introduced.
+--
+-- The danger of adding the anchor later is that we adapt the head and so the caller needs to
+-- check that ... real messy. On the other hand, we soldom traverse the line. And other
+-- mechanisms can push stuff in front too. Actually that alone can mess up analysis when we
+-- delay too much. So in the end we need to accept the slow down.
+--
-- We only need to normalize the left side because when we mess around
-- we keep the page stream order (and adding content to the right of the
-- line is a no-go for tagged etc. For the same reason we don't use two
-- left anchors (each side fo leftskip) because there can be stretch. But,
-- maybe there are good reasons for having just that anchor (mostly for
-- educational purposes I guess.)
-
+--
-- At this stage the localpar node is no longer of any use so we remove
-- it (each line has the direction attached). We might at some point also
-- strip the disc nodes as they no longer serve a purpose but that can
-- better be a helper. Anchoring left has advantage of keeping page stream.
+--
+-- This looks a bit messy but we want to keep the box as it is so \showboxes still
+-- visualizes as expected. Normally left and rightskips end up in the line while
+-- hangindents become shifts and hsize corrections. We could normalize this to
+-- a line with
-- indent : hlist type 3
-- hangindent : shift and width
--- new_glue(0,65536,65536,2,2) -- hss (or skip -width etc)
+local type = type
--- -- rightskip checking
---
--- local tail = findtail(head)
--- local rightskip = nil
--- local right = new_hlist()
--- local id = getid(tail)
--- if id == glue_code then
--- local subtype = getsubtype(tail)
--- if subtype == rightskip_code then
--- rightskip = tail
--- end
--- end
--- if not rightskip then
--- print("inserting rightskip")
--- rightskip = new_rightskip()
--- insert_after(head,tail,rightskip)
--- tail = rightskip
--- end
--- insert_after(head,tail,right)
---
--- tail = tail,
--- right = {
--- pack = right,
--- head = nil,
--- tail = nil,
--- }
+local trace_anchors = false trackers.register("paragraphs.anchors", function(v) trace_anchors = v end)
+
+local report = logs.reporter("anchors")
+
+local nuts = nodes.nuts
+local nodecodes = nodes.nodecodes
+local gluecodes = nodes.gluecodes
+local listcodes = nodes.listcodes
+local whatcodes = nodes.whatsitcodes
+
+local hlist_code = nodecodes.hlist
+local glue_code = nodecodes.glue
+local kern_code = nodecodes.kern
+local whatsit_code = nodecodes.whatsit
+local line_code = listcodes.line
+local userskip_code = gluecodes.userskip
+local leftskip_code = gluecodes.leftskip
+local rightskip_code = gluecodes.rightskip
+local parfillskip_code = gluecodes.parfillskip
+local textdir_code = whatcodes.textdir
+local localpar_code = whatcodes.localpar
+
+local tonut = nodes.tonut
+local tonode = nodes.tonode
+
+local traverse_id = nuts.traverse_id
+local insert_before = nuts.insert_before
+local insert_after = nuts.insert_after
+local findtail = nuts.tail
+local remove_node = nuts.remove
+local hpack_nodes = nuts.hpack
+local copy_list = nuts.copy_list
+
+local getsubtype = nuts.getsubtype
+local getlist = nuts.getlist
+local getid = nuts.getid
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getfield = nuts.getfield
+local setfield = nuts.setfield
--- todo: see if we can hook into box in buildpagefilter .. saves traverse
+local setprop = nuts.setprop
+local getprop = nuts.getprop
+
+local nodepool = nuts.pool
+local new_glue = nodepool.glue
+local new_kern = nodepool.kern
+local new_leftskip = nodepool.leftskip
+local new_rightskip = nodepool.rightskip
+local new_hlist = nodepool.hlist
+local new_vlist = nodepool.vlist
+local new_rule = nodepool.rule
+local new_latelua = nodepool.latelua
+
+local texgetcount = tex.getcount
+local setmetatableindex = table.setmetatableindex
+local formatters = string.formatters
+
+local jobpositions = job.positions
+local getposition = jobpositions.get
+local getreserved = jobpositions.getreserved
+
+local paragraphs = { }
+typesetters.paragraphs = paragraphs
+
+local addskips = false
+local noflines = 0
+
+-- This is the third version, a mix between immediate (prestice lines) and delayed
+-- as we don't want anchors that are not used.
+
+local function finalize(prop,key) -- delayed calculations
+ local line = prop.line
+ local hsize = prop.hsize
+ local width = prop.width
+ local shift = getfield(line,"shift") -- dangerous as it can be vertical as well
+ local reverse = getfield(line,"dir") == "TRT" or false
+ local pack = new_hlist()
+ local head = getlist(line)
+ local delta = 0
+ if reverse then
+ delta = - shift + (hsize - width)
+ else
+ delta = shift
+ end
+ -- if reverse then delta = - delta end
+ -- head = insert_before(head,head,nodepool.textdir("-TLT"))
+ head = insert_before(head,head,new_kern(delta))
+ head = insert_before(head,head,pack)
+ head = insert_before(head,head,new_kern(-delta))
+ -- head = insert_before(head,head,nodepool.textdir("TLT"))
+ setfield(line,"list",head)
+ local where = {
+ pack = pack,
+ head = nil,
+ tail = nil,
+ }
+ prop.anchor = where
+ prop.reverse = reverse
+ prop.shift = shift
+ setmetatableindex(prop,nil)
+ return prop[key]
+end
+
+local function normalize(line,islocal) -- assumes prestine lines, nothing pre/appended
+ local oldhead = getlist(line)
+ local head = oldhead
+ local leftskip = nil
+ local rightskip = nil
+ local width = getfield(line,"width")
+ local hsize = islocal and width or tex.hsize
+ local lskip = 0
+ local rskip = 0
+ local pskip = 0
+ local current = head
+ local id = getid(current)
+ if id == glue_code then
+ local subtype = getsubtype(head)
+ if subtype == leftskip_code then
+ local spec = getfield(head,"spec")
+ leftskip = head
+ lskip = getfield(spec,"width")
+ end
+ current = getnext(head)
+ id = getid(current)
+ end
+ if id == whatsit_code then
+ if getsubtype(head) == localpar_code then
+ head = remove_node(head,head,true)
+ end
+ end
+ local tail = findtail(head)
+ local current = tail
+ local id = getid(current)
+ if id == glue_code then
+ if getsubtype(current) == rightskip_code then
+ local spec = getfield(current,"spec")
+ rightskip = tail
+ rskip = getfield(spec,"width")
+ current = getprev(tail)
+ id = getid(current)
+ end
+ if id == glue_code then
+ if getsubtype(current) == parfillskip_code then
+ pskip = nuts.effectiveglue(current,line)
+ end
+ end
+ end
+ if addskips then
+ if rightskip and not leftskip then
+ leftskip = new_leftskip(lskip)
+ head = insert_before(head,head,leftskip)
+ end
+ if leftskip and not rightskip then
+ rightskip = new_rightskip(0)
+ head, tail = insert_after(head,tail,rightskip)
+ end
+ end
+ if head ~= oldhead then
+ setfield(line,"list",head)
+ end
+ noflines = noflines + 1
+ local prop = {
+ width = width,
+ hsize = hsize,
+ leftskip = lskip,
+ rightskip = rskip,
+ parfillskip = pskip,
+ line = line,
+ number = noflines,
+ }
+ setmetatableindex(prop,finalize)
+ setprop(line,"line",prop)
+ return prop
+end
+
+function paragraphs.checkline(n)
+ return getprop(n,"line") or normalize(n,true)
+end
function paragraphs.normalize(head,islocal)
if texgetcount("pagebodymode") > 0 then
@@ -114,79 +241,236 @@ function paragraphs.normalize(head,islocal)
end
for line in traverse_id(hlist_code,tonut(head)) do
if getsubtype(line) == line_code and not getprop(line,"line") then
- local head = getlist(line)
- local leftskip = nil
- local anchor = new_hlist()
- local id = getid(head)
- local shift = getfield(line,"shift")
- local width = getfield(line,"width")
- local hsize = islocal and width or tex.hsize
- local reverse = getfield(line,"dir") == "TRT" or false
- if id == glue_code then
- local subtype = getsubtype(head)
- if subtype == leftskip_code then
- leftskip = head
- end
- local next = getnext(head)
- if next and getsubtype(next) == localpar_code then
- head = remove_node(head,next,true)
- end
- elseif id == whatsit_code then
- if getsubtype(head) == localpar_code then
- head = remove_node(head,head,true)
- end
- end
- head = insert_before(head,head,anchor)
- shift = shift + width - hsize
- if reverse then
- head = insert_before(head,head,new_kern(shift))
- insert_after(head,anchor,new_kern(-shift))
- else
- head = insert_before(head,head,new_kern(-shift))
- end
- if not leftskip then
- head = insert_before(head,head,new_leftskip(0))
- end
-setfield(anchor,"attr",getfield(line,"attr"))
--- print(nodes.idstostring(head))
--- print("NORMALIZE",line)
- setfield(line,"list",head)
- setprop(line,"line",{
- reverse = reverse,
- width = width,
- hsize = hsize,
- shift = shift,
- head = head,
- anchor = {
- pack = anchor,
- head = nil,
- tail = nil,
- },
- })
+ normalize(line,islocal)
end
end
return head, true
end
-function paragraphs.addtoline(n,list)
+-- print(nodes.idstostring(head))
+
+-- We do only basic positioning and leave compensation for directions and distances
+-- to the caller as that one knows the circumstances better.
+
+-- todo: only in mvl or explicitly, e.g. framed or so, not in all lines
+
+function paragraphs.addtoline(n,list,option)
local line = getprop(n,"line")
+ if not line then
+ line = normalize(n,true)
+ end
if line then
if trace_anchors and not line.traced then
line.traced = true
local rule = new_rule(2*65536,2*65536,1*65536)
local list = insert_before(rule,rule,new_kern(-1*65536))
paragraphs.addtoline(n,list)
+ local rule = new_rule(2*65536,6*65536,-3*65536)
+ local list = insert_before(rule,rule,new_kern(-1*65536))
+ paragraphs.addtoline(n,list,"internal")
+ else
+ line.traced = true
+ end
+ local list = tonut(list)
+ local where = line.anchor
+ local tail = where.tail
+ local head = where.head
+ local blob = new_hlist(list)
+ local delta = 0
+ if option == "internal" then
+ if line.reverse then
+ delta = line.shift - line.leftskip - (line.hsize - line.width)
+ else
+ delta = line.shift + line.leftskip
+ end
end
- local list = tonut(list)
- local what = line.anchor
- local tail = what.tail
- local blob = new_hlist(list)
+ -- always kerns, also when 0 so that we can adapt but we can optimize if needed
+ -- by keeping a hash as long as we use the shiftinline helper .. no need to
+ -- optimize now .. we can also decide to put each blob in a hlist
+ local kern = new_kern(delta)
if tail then
- insert_after(what.head,what.tail,blob)
+ head, tail = insert_after(head,tail,kern)
else
- setfield(what.pack,"list",blob)
- what.head = blob
+ head, tail = kern, kern
+ setfield(where.pack,"list",head)
+ end
+ head, tail = insert_after(head,tail,blob)
+ local kern = new_kern(-delta)
+ head, tail = insert_after(head,tail,kern)
+ --
+ where.head = head
+ where.tail = tail
+ return line, blob
+ else
+ -- report("unknown anchor")
+ end
+end
+
+local function addanchortoline(n,anchor)
+ local line = type(n) ~= "table" and getprop(n,"line") or n
+ if not line then
+ line = normalize(n,true)
+ end
+ if line then
+ local anchor = tonut(anchor)
+ local where = line.anchor
+ local head = where.head
+ if trace_anchors then
+ local rule1 = new_rule(65536/2,4*65536,4*65536)
+ local rule2 = new_rule(8*65536,65536/4,65536/4)
+ local kern1 = new_kern(-65536/4)
+ local kern2 = new_kern(-65536/4-4*65536)
+ local list = new_hlist(nuts.link { anchor, kern1, rule1, kern2, rule2 })
+ setfield(list,"width",0)
+ insert_before(head,head,list)
+ if not where.tail then
+ where.tail = list
+
+ end
+ setfield(where.pack,"list",list)
+ where.head = list
+ else
+ insert_before(head,head,anchor)
+ if not where.tail then
+ where.tail = anchor
+ end
+ setfield(where.pack,"list",anchor)
+ where.head = anchor
+ end
+ return line, anchor
+ end
+end
+
+paragraphs.addanchortoline = addanchortoline
+
+function paragraphs.moveinline(n,blob,dx,dy)
+ if not blob then
+ return
+ end
+ if not dx then
+ dx = 0
+ end
+ if not dy then
+ dy = 0
+ end
+ if dx ~= 0 or dy ~= 0 then
+ local line = type(n) ~= "table" and getprop(n,"line") or n
+ if line then
+ if dx ~= 0 then
+ local prev = getprev(blob)
+ local next = getnext(blob)
+ if prev and getid(prev) == kern_code then
+ setfield(prev,"kern",getfield(prev,"kern") + dx)
+ end
+ if next and getid(next) == kern_code then
+ setfield(next,"kern",getfield(next,"kern") - dx)
+ end
+ end
+ if dy ~= 0 then
+ if getid(blob) == hlist_code then
+ setfield(blob,"shift",getfield(blob,"shift") + dy)
+ end
+ end
+ else
+-- report("no line")
+ end
+ end
+end
+
+local f_anchor = formatters["_plib_.set('md:h',%i,{x=true,c=true})"]
+local s_anchor = 'md:h'
+
+local function setanchor(h_anchor)
+ return new_latelua(f_anchor(h_anchor))
+end
+
+-- local t_anchor = { x = true, c = true }
+--
+-- local function setanchor(h_anchor)
+-- return lateluafunction(function() setposition("md:h",h_anchor,t_anchor) end)
+-- end
+
+function paragraphs.calculatedelta(n,width,delta,atleft,islocal,followshape,area)
+ local line = type(n) ~= "table" and getprop(n,"line") or n
+ if not line then
+ line = normalize(n,true)
+ end
+ local hmove = 0
+ if line then
+ local reverse = line.reverse
+ -- basic hsize based anchoring
+ if atleft then
+ if reverse then
+ -- delta = delta
+ else
+ delta = - delta - width
+ end
+ else
+ if reverse then
+ delta = - delta - width - line.hsize
+ else
+ delta = delta + line.hsize
+ end
+ end
+ if islocal then
+ -- relative to hsize with leftskip / rightskip compensation
+ if atleft then
+ if reverse then
+ delta = delta - line.leftskip
+ else
+ delta = delta + line.leftskip
+ end
+ else
+ if reverse then
+ delta = delta + line.rightskip
+ else
+ delta = delta - line.rightskip
+ end
+ end
+ if followshape then
+ -- shape compensation
+ if atleft then
+ if reverse then
+ delta = delta + line.shift - line.hsize + line.width
+ else
+ delta = delta + line.shift
+ end
+ else
+ if reverse then
+ delta = delta + line.shift + line.parfillskip
+ else
+ delta = delta + line.shift - line.hsize + line.width - line.parfillskip
+ end
+ end
+ end
+ end
+ if area then
+ local number = line.number
+ if not line.hanchor then
+ addanchortoline(line,setanchor(number))
+ line.hanchor = true
+ end
+ local blob = getposition(s_anchor,number)
+ if blob then
+ local reference = getreserved(area,blob.c)
+ if reference then
+ hmove = (reference.x or 0) - (blob.x or 0)
+ if atleft then
+ if reverse then
+ hmove = hmove + (reference.w or 0)
+ else
+ -- hmove = hmove
+ end
+ else
+ if reverse then
+ hmove = hmove + line.hsize
+ else
+ hmove = hmove + (reference.w or 0) - line.hsize
+ end
+ end
+ end
+ end
end
- what.tail = blob
end
+ return delta, hmove
end