diff options
Diffstat (limited to 'tex/context/base/typo-mar.lua')
-rw-r--r-- | tex/context/base/typo-mar.lua | 297 |
1 files changed, 200 insertions, 97 deletions
diff --git a/tex/context/base/typo-mar.lua b/tex/context/base/typo-mar.lua index 85d5c85a8..fed9e0745 100644 --- a/tex/context/base/typo-mar.lua +++ b/tex/context/base/typo-mar.lua @@ -76,6 +76,8 @@ if not modules then modules = { } end modules ['typo-mar'] = { local format, validstring = string.format, string.valid local insert, remove = table.insert, table.remove local setmetatable, next = setmetatable, next +local formatters = string.formatters +local toboolean = toboolean local attributes, nodes, node, variables = attributes, nodes, node, variables @@ -114,14 +116,32 @@ local v_continue = variables.continue local v_first = variables.first local v_text = variables.text local v_column = variables.column - -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 v_line = variables.line + +local nuts = nodes.nuts +local nodepool = nuts.pool + +local tonode = nuts.tonode +local tonut = nuts.tonut + +local copy_node_list = nuts.copy_list +local hpack_nodes = nuts.hpack -- nodes.fasthpack not really faster here +local traverse_id = nuts.traverse_id +local free_node_list = nuts.flush_list +local insert_node_after = nuts.insert_after +local insert_node_before = nuts.insert_before +local linked_nodes = nuts.linked + +local getfield = nuts.getfield +local setfield = nuts.setfield +local getnext = nuts.getnext +local getprev = nuts.getprev +local getid = nuts.getid +local getattr = nuts.getattr +local setattr = nuts.setattr +local getsubtype = nuts.getsubtype +local getbox = nuts.getbox +local getlist = nuts.getlist local nodecodes = nodes.nodecodes local listcodes = nodes.listcodes @@ -144,33 +164,31 @@ local userdefined_code = whatsitcodes.userdefined local dir_code = whatsitcodes.dir local localpar_code = whatsitcodes.localpar -local nodepool = nodes.pool +local nodepool = nuts.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 lateluafunction = nodepool.lateluafunction + local texgetcount = tex.getcount local texgetdimen = tex.getdimen -local texgetbox = tex.getbox local texget = tex.get -local points = number.points - local isleftpage = layouts.status.isleftpage -local registertogether = builders.paragraphs.registertogether - -local jobpositions = job.positions -local getposition = jobpositions.position +local registertogether = builders.paragraphs.registertogether -- tonode local a_margindata = attributes.private("margindata") local inline_mark = nodepool.userids["margins.inline"] -local margins = { } +local jobpositions = job.positions +local getposition = jobpositions.get +local setposition = jobpositions.set +local getreserved = jobpositions.getreserved + +local margins = { } typesetters.margins = margins local locations = { v_left, v_right, v_inner, v_outer } -- order might change @@ -233,7 +251,7 @@ local function showstore(store,banner,location) if next(store) then for i, si in table.sortedpairs(store) do local si =store[i] - report_margindata("%s: stored in %a at %s: %a => %s",banner,location,i,validstring(si.name,"no name"),nodes.toutf(si.box.list)) + report_margindata("%s: stored in %a at %s: %a => %s",banner,location,i,validstring(si.name,"no name"),nodes.toutf(getlist(si.box))) end else report_margindata("%s: nothing stored in location %a",banner,location) @@ -242,7 +260,7 @@ end function margins.save(t) setmetatable(t,defaults) - local content = texgetbox(t.number) + local content = getbox(t.number) local location = t.location local category = t.category local inline = t.inline @@ -310,11 +328,11 @@ function margins.save(t) -- nice is to make a special status table mechanism local leftmargindistance = texgetdimen("naturalleftmargindistance") local rightmargindistance = texgetdimen("naturalrightmargindistance") - local strutbox = texgetbox("strutbox") - t.strutdepth = strutbox.depth - t.strutheight = strutbox.height - t.leftskip = texget("leftskip").width -- we're not in forgetall - t.rightskip = texget("rightskip").width -- we're not in forgetall + local strutbox = getbox("strutbox") + t.strutdepth = getfield(strutbox,"depth") + t.strutheight = getfield(strutbox,"height") + t.leftskip = getfield(texget("leftskip"),"width") -- we're not in forgetall + t.rightskip = getfield(texget("rightskip"),"width") -- we're not in forgetall t.leftmargindistance = leftmargindistance -- todo:layoutstatus table t.rightmargindistance = rightmargindistance t.leftedgedistance = texgetdimen("naturalleftedgedistance") @@ -327,7 +345,7 @@ function margins.save(t) -- -- t.realpageno = texgetcount("realpageno") if inline then - context(new_usernumber(inline_mark,nofsaved)) + context(tonode(new_usernumber(inline_mark,nofsaved))) -- or use a normal node store[nofsaved] = t -- no insert nofinlined = nofinlined + 1 else @@ -352,6 +370,18 @@ end local status, nofstatus = { }, 0 +local f_anchor = formatters["_plib_.set('md:h',%i,{x=true,c=true})"] + +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 + local function realign(current,candidate) local location = candidate.location local margin = candidate.margin @@ -404,7 +434,7 @@ local function realign(current,candidate) -- we assume that list is a hbox, otherwise we had to take the whole current -- in order to get it right - current.width = 0 + setfield(current,"width",0) local anchornode, move_x -- this mess is needed for alignments (combinations) so we use that @@ -418,12 +448,12 @@ local function realign(current,candidate) anchor = v_text end if inline or anchor ~= v_text or candidate.psubtype == alignment_code then - -- the alignment_code check catches margintexts ste before a tabulate + -- the alignment_code check catches margintexts before a tabulate h_anchors = h_anchors + 1 - anchornode = new_latelua(format("_plib_.set('md:h',%i,{x=true,c=true})",h_anchors)) - local blob = jobpositions.get('md:h', h_anchors) + anchornode = setanchor(h_anchors) + local blob = getposition('md:h',h_anchors) if blob then - local reference = jobpositions.getreserved(anchor,blob.c) + local reference = getreserved(anchor,blob.c) if reference then if location == v_left then move_x = (reference.x or 0) - (blob.x or 0) @@ -446,9 +476,9 @@ local function realign(current,candidate) report_margindata("realigned %a, location %a, margin %a",candidate.n,location,margin) end end - - current.list = hpack_nodes(anchornode .. new_kern(-delta) .. current.list .. new_kern(delta)) - current.width = 0 + local list = hpack_nodes(linked_nodes(anchornode,new_kern(-delta),getlist(current),new_kern(delta))) + setfield(current,"list",list) + setfield(current,"width",0) end local function realigned(current,a) @@ -478,24 +508,36 @@ end -- resetstacked() -function margins.ha(tag) -- maybe l/r keys ipv left/right keys +local function ha(tag) -- maybe l/r keys ipv left/right keys local p = cache[tag] p.p = true p.y = true - jobpositions.set('md:v',tag,p) + setposition('md:v',tag,p) cache[tag] = nil end -local function markovershoot(current) +margins.ha = ha + +local f_anchor = formatters["typesetters.margins.ha(%s)"] +local function setanchor(v_anchor) + return new_latelua(f_anchor(v_anchor)) +end + +-- local function setanchor(v_anchor) -- freezes the global here +-- return lateluafunction(function() ha(v_anchor) end) +-- end + +local function markovershoot(current) -- todo: alleen als offset > line v_anchors = v_anchors + 1 cache[v_anchors] = stacked - local anchor = new_latelua(format("typesetters.margins.ha(%s)",v_anchors)) -- todo: alleen als offset > line - current.list = hpack_nodes(anchor .. current.list) + local anchor = setanchor(v_anchors) + local list = hpack_nodes(linked_nodes(anchor,getlist(current))) + setfield(current,"list",list) end local function getovershoot(location) - local p = jobpositions.get("md:v",v_anchors) - local c = jobpositions.get("md:v",v_anchors+1) + local p = getposition("md:v",v_anchors) + local c = getposition("md:v",v_anchors+1) if p and c and p.p and p.p == c.p then local distance = p.y - c.y local offset = p[location] or 0 @@ -512,10 +554,13 @@ end local function inject(parent,head,candidate) local box = candidate.box - local width = box.width - local height = box.height - local depth = box.depth - local shift = box.shift + if not box then + return head, nil, false -- we can have empty texts + end + local width = getfield(box,"width") + local height = getfield(box,"height") + local depth = getfield(box,"depth") + local shift = getfield(box,"shift") local stack = candidate.stack local location = candidate.location local method = candidate.method @@ -524,13 +569,18 @@ local function inject(parent,head,candidate) local baseline = candidate.baseline local strutheight = candidate.strutheight local strutdepth = candidate.strutdepth - local psubtype = parent.subtype + local psubtype = getsubtype(parent) local offset = stacked[location] local firstonstack = offset == false or offset == nil nofstatus = nofstatus + 1 nofdelayed = nofdelayed + 1 status[nofstatus] = candidate -- yet untested + baseline = tonumber(baseline) + if not baseline then + baseline = toboolean(baseline) + end + -- if baseline == true then baseline = false -- hbox vtop @@ -546,7 +596,7 @@ local function inject(parent,head,candidate) end end candidate.width = width - candidate.hsize = parent.width -- we can also pass textwidth + candidate.hsize = getfield(parent,"width") -- we can also pass textwidth candidate.psubtype = psubtype if trace_margindata then report_margindata("processing, index %s, height %p, depth %p, parent %s",candidate.n,height,depth,listcodes[psubtype]) @@ -557,10 +607,10 @@ local function inject(parent,head,candidate) -- offset = offset + height end if stack == v_yes then - offset = offset + candidate.dy + offset = offset + candidate.dy -- always shift = shift + offset elseif stack == v_continue then - offset = offset + candidate.dy + offset = offset + candidate.dy -- always if firstonstack then offset = offset + getovershoot(location) end @@ -573,13 +623,23 @@ local function inject(parent,head,candidate) -- experimental. -- -- -- if method == v_top then - local delta = height - parent.height + local delta = height - getfield(parent,"height") if trace_margindata then report_margindata("top aligned by %p",delta) end - if delta < candidate.threshold then + if delta < candidate.threshold then -- often we need a negative threshold here shift = shift + voffset + delta end + elseif method == v_line then + if getfield(parent,"depth") == 0 then + local delta = height - getfield(parent,"height") + if trace_margindata then + report_margindata("top aligned by %p (no depth)",delta) + end + if delta < candidate.threshold then -- often we need a negative threshold here + shift = shift + voffset + delta + end + end elseif method == v_first then if baseline then shift = shift + voffset + height - baseline -- option @@ -616,22 +676,23 @@ local function inject(parent,head,candidate) shift = shift + delta offset = offset + delta end - box.shift = shift - box.width = 0 + setfield(box,"shift",shift) + setfield(box,"width",0) if not head then head = box - elseif head.id == whatsit_code and head.subtype == localpar_code then + elseif getid(head) == whatsit_code and getsubtype(head) == localpar_code then -- experimental - if head.dir == "TRT" then - box.list = hpack_nodes(new_kern(candidate.hsize) .. box.list .. new_kern(-candidate.hsize)) + if getfield(head,"dir") == "TRT" then + local list = hpack_nodes(linked_nodes(new_kern(candidate.hsize),getlist(box),new_kern(-candidate.hsize))) + setfield(box,"list",list) end insert_node_after(head,head,box) else - head.prev = box - box.next = head + setfield(head,"prev",box) + setfield(box,"next",head) head = box end - box[a_margindata] = nofstatus + setattr(box,a_margindata,nofstatus) if trace_margindata then report_margindata("injected, location %a, shift %p",location,shift) end @@ -656,12 +717,12 @@ local function flushinline(parent,head) local current = head local done = false local continue = false - local room, don, con + local room, don, con, list while current and nofinlined > 0 do - local id = current.id + local id = getid(current) if id == whatsit_code then - if current.subtype == userdefined_code and current.user_id == inline_mark then - local n = current.value + if getsubtype(current) == userdefined_code and getfield(current,"user_id") == inline_mark then + local n = getfield(current,"value") local candidate = inlinestore[n] if candidate then -- no vpack, as we want to realign inlinestore[n] = nil @@ -674,11 +735,12 @@ local function flushinline(parent,head) end elseif id == hlist_code or id == vlist_code then -- optional (but sometimes needed) - current.list, don, con = flushinline(current,current.list) + list, don, con = flushinline(current,getlist(current)) + setfield(current,"list",list) continue = continue or con done = done or don end - current = current.next + current = getnext(current) end return head, done, continue end @@ -686,7 +748,7 @@ end local a_linenumber = attributes.private('linenumber') local function flushed(scope,parent) -- current is hlist - local head = parent.list + local head = getlist(parent) local done = false local continue = false local room, con, don @@ -695,33 +757,40 @@ local function flushed(scope,parent) -- current is hlist for l=1,#locations do local location = locations[l] local store = displaystore[category][location][scope] - 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, con = inject(parent,head,candidate) - done = true - continue = continue or con - nofstored = nofstored - 1 - registertogether(parent,room) - else - break + if store then + 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, con = inject(parent,head,candidate) + done = true + continue = continue or con + nofstored = nofstored - 1 + if room then + registertogether(tonode(parent),room) -- !! tonode + end + else + break + end end + else + -- report_margindata("fatal error: invalid category %a",category or "?") end end end if nofinlined > 0 then if done then - parent.list = head + setfield(parent,"list",head) end head, don, con = flushinline(parent,head) continue = continue or con done = done or don end if done then - local a = head[a_linenumber] -- hack .. we need a more decent critical attribute inheritance mechanism - parent.list = hpack_nodes(head,parent.width,"exactly") + local a = getattr(head,a_linenumber) -- hack .. we need a more decent critical attribute inheritance mechanism + local l = hpack_nodes(head,getfield(parent,"width"),"exactly") + setfield(parent,"list",l) if a then - parent.list[a_linenumber] = a + setattr(l,a_linenumber,a) end -- resetstacked() end @@ -736,14 +805,15 @@ local function handler(scope,head,group) if trace_margindata then report_margindata("flushing stage one, stored %s, scope %s, delayed %s, group %a",nofstored,scope,nofdelayed,group) end + head = tonut(head) local current = head local done = false while current do - local id = current.id - if (id == vlist_code or id == hlist_code) and not current[a_margindata] then + local id = getid(current) + if (id == vlist_code or id == hlist_code) and not getattr(current,a_margindata) then local don, continue = flushed(scope,current) if don then - current[a_margindata] = 0 -- signal to prevent duplicate processing + setattr(current,a_margindata,0) -- signal to prevent duplicate processing if continue then markovershoot(current) end @@ -753,12 +823,12 @@ local function handler(scope,head,group) done = true end end - current = current.next + current = getnext(current) end -- if done then resetstacked() -- why doesn't done work ok here? -- end - return head, done + return tonode(head), done else return head, false end @@ -789,15 +859,15 @@ function margins.globalhandler(head,group) -- check group end return head, false elseif group == "hmode_par" then - return handler("global",head,group) + return handler(v_global,head,group) elseif group == "vmode_par" then -- experiment (for alignments) - return handler("global",head,group) + return handler(v_global,head,group) -- this needs checking as we then get quite some one liners to process and -- we cannot look ahead then: elseif group == "box" then -- experiment (for alignments) - return handler("global",head,group) + return handler(v_global,head,group) elseif group == "alignment" then -- experiment (for alignments) - return handler("global",head,group) + return handler(v_global,head,group) else if trace_margingroup then report_margindata("ignored 2, group %a, stored %s, inhibit %a",group,nofstored,inhibit) @@ -811,11 +881,11 @@ local function finalhandler(head) local current = head local done = false while current do - local id = current.id + local id = getid(current) if id == hlist_code then - local a = current[a_margindata] + local a = getattr(current,a_margindata) if not a or a == 0 then - finalhandler(current.list) + finalhandler(getlist(current)) elseif realigned(current,a) then done = true if nofdelayed == 0 then @@ -823,9 +893,9 @@ local function finalhandler(head) end end elseif id == vlist_code then - finalhandler(current.list) + finalhandler(getlist(current)) end - current = current.next + current = getnext(current) end return head, done else @@ -838,7 +908,10 @@ function margins.finalhandler(head) -- if trace_margindata then -- report_margindata("flushing stage two, instore: %s, delayed: %s",nofstored,nofdelayed) -- end - return finalhandler(head) + head = tonut(head) + local head, done = finalhandler(head) + head = tonode(head) + return head, done else return head, false end @@ -877,3 +950,33 @@ statistics.register("margin data", function() return nil end end) + +interfaces.implement { + name = "savemargindata", + actions = margins.save, + arguments = { + { + { "location" }, + { "method" }, + { "category" }, + { "name" }, + { "scope" }, + { "number", "integer" }, + { "margin" }, + { "distance", "dimen" }, + { "hoffset", "dimen" }, + { "voffset", "dimen" }, + { "dy", "dimen" }, + { "bottomspace", "dimen" }, + { "baseline"}, -- dimen or string or + { "threshold", "dimen" }, + { "inline", "boolean" }, + { "anchor" }, + -- { "leftskip", "dimen" }, + -- { "rightskip", "dimen" }, + { "align" }, + { "line", "integer" }, + { "stack" }, + } + } +} |