diff options
author | Context Git Mirror Bot <phg42.2a@gmail.com> | 2015-09-09 22:15:06 +0200 |
---|---|---|
committer | Context Git Mirror Bot <phg42.2a@gmail.com> | 2015-09-09 22:15:06 +0200 |
commit | f28043b96635a0845521fe0094a3863d7ff13b6d (patch) | |
tree | b57730bb08599d5875bee8cf118d832e0c5977a3 /tex/context/base/typo-lin.lua | |
parent | cf4c4c56e5748e91ecc28f8126f5fc6eadfd73fa (diff) | |
download | context-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.lua | 568 |
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 |