diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkxl/typo-lin.lmt')
-rw-r--r-- | Master/texmf-dist/tex/context/base/mkxl/typo-lin.lmt | 402 |
1 files changed, 402 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkxl/typo-lin.lmt b/Master/texmf-dist/tex/context/base/mkxl/typo-lin.lmt new file mode 100644 index 00000000000..86365c3ba03 --- /dev/null +++ b/Master/texmf-dist/tex/context/base/mkxl/typo-lin.lmt @@ -0,0 +1,402 @@ +if not modules then modules = { } end modules ['typo-lin'] = { + version = 1.001, + comment = "companion to typo-lin.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- 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 par 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 + +local type = type + +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 listcodes = nodes.listcodes + +local hlist_code = nodecodes.hlist +local kern_code = nodecodes.kern +local linelist_code = listcodes.line + +local tonut = nodes.tonut +local tonode = nodes.tonode + +local nexthlist = nuts.traversers.hlist +local insert_before = nuts.insert_before +local insert_after = nuts.insert_after + +local getlist = nuts.getlist +local setlist = nuts.setlist +local getid = nuts.getid +local getboth = nuts.getboth +local setlink = nuts.setlink +local setkern = nuts.setkern +local getkern = nuts.getkern +local getdirection = nuts.getdirection +local getshift = nuts.getshift +local setshift = nuts.setshift +local getwidth = nuts.getwidth +local setwidth = nuts.setwidth + +local getnormalizedline = nuts.getnormalizedline + +local setprop = nuts.setprop +local getprop = nuts.rawprop -- getprop + +local effectiveglue = nuts.effective_glue + +local nodepool = nuts.pool +local new_kern = nodepool.kern +local new_hlist = nodepool.hlist +local new_rule = nodepool.rule +local new_glue = nodepool.glue + +local righttoleft_code = nodes.dirvalues.righttoleft + +local texgetcount = tex.getcount +local setmetatableindex = table.setmetatableindex + +local jobpositions = job.positions +local getposition = jobpositions.get +local getreserved = jobpositions.getreserved + +local paragraphs = { } +typesetters.paragraphs = paragraphs + +local noflines = 0 + +local function finalize(prop,key) -- delayed calculations + local line = prop.line + local hsize = prop.hsize + local width = prop.width + local shift = getshift(line) -- dangerous as it can be vertical as well + local reverse = getdirection(line) == righttoleft_code or false + local pack = new_hlist() + local head = getlist(line) + local delta = 0 + if reverse then + delta = - shift + (hsize - width) + else + delta = shift + end + local kern1 = new_kern(delta) + local kern2 = new_kern(-delta) + head = insert_before(head,head,kern1) -- setlink + head = insert_before(head,head,pack) + head = insert_before(head,head,kern2) + setlist(line,head) + local where = { + pack = pack, + head = nil, + tail = nil, + } + prop.where = 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 prop = getnormalizedline(line) -- we also can have "lineproperties" set but for a different porpose + local width = getwidth(line) + local hsize = islocal and width or tex.hsize + noflines = noflines + 1 + if prop then + prop.width = width + prop.hsize = hsize + prop.line = line + prop.number = noflines + else + -- can be a vbox ... we could use a metatable with zeros + prop = { + width = width, + hsize = hsize, + leftskip = 0, + rightskip = 0, + lefthangskip = 0, + righthangskip = 0, + parfillleftskip = 0, + parfillrightskip = 0, + line = line, + number = noflines, + } + end + setprop(line,"line",prop) + setmetatableindex(prop,finalize) + return prop +end + +function paragraphs.checkline(n) + return getprop(n,"line") or normalize(n,true) +end + +-- 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 + +local function 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)) + addtoline(n,list) + local rule = new_rule(2*65536,6*65536,-3*65536) + local list = insert_before(rule,rule,new_kern(-1*65536)) + addtoline(n,list,"internal") + else + line.traced = true + end + local list = tonut(list) + local where = line.where + local head = where.head + local tail = where.tail + local blob = new_hlist(list) + local delta = 0 + if option == "internal" then + if line.reverse then + delta = line.lefthangskip - line.leftskip - (line.hsize - line.width) + else + delta = line.lefthangskip + line.leftskip + end + end + -- 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 + head, tail = insert_after(head,tail,kern) + else + head, tail = kern, kern + setlist(where.pack,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.where + if trace_anchors then + anchor = new_hlist(setlink( + anchor, + new_kern(-65536/4), + new_rule(65536/2,4*65536,4*65536), + new_kern(-65536/4-4*65536), + new_rule(8*65536,65536/4,65536/4) + )) + setwidth(anchor,0) + end + if where.tail then + local head = where.head + insert_before(head,head,anchor) + else + where.tail = anchor + end + setlist(where.pack,anchor) + where.head = anchor + return line + end +end + +paragraphs.addtoline = addtoline +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, next = getboth(blob) + if prev and getid(prev) == kern_code then + setkern(prev,getkern(prev) + dx) + end + if next and getid(next) == kern_code then + setkern(next,getkern(next) - dx) + end + end + if dy ~= 0 then + if getid(blob) == hlist_code then + setshift(blob,getshift(blob) + dy) + end + end + else + -- report("no line") + end + end +end + +local latelua = nodepool.latelua +local setposition = jobpositions.setspec + +local function setanchor(h_anchor) + return latelua { + action = setposition, + name = "md:h", + index = h_anchor, + value = { x = true, c = true }, + } +end + +-- needs to be adapted ! + +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 (compare to mkiv where we have shift!) + if atleft then + if reverse then + delta = delta + line.lefthangskip - line.hsize + line.width -- needs testing: + line.parfillleftskip + else + delta = delta + line.lefthangskip -- needs testing: - line.parfillleftskip + end + else + if reverse then + delta = delta + line.lefthangskip + line.parfillrightskip + else + delta = delta + line.lefthangskip - line.hsize + line.width - line.parfillrightskip + 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("md:h",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 + end + return delta, hmove +end |