diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkxl/anch-pgr.lmt')
-rw-r--r-- | Master/texmf-dist/tex/context/base/mkxl/anch-pgr.lmt | 1325 |
1 files changed, 1325 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkxl/anch-pgr.lmt b/Master/texmf-dist/tex/context/base/mkxl/anch-pgr.lmt new file mode 100644 index 00000000000..5b750d80e7a --- /dev/null +++ b/Master/texmf-dist/tex/context/base/mkxl/anch-pgr.lmt @@ -0,0 +1,1325 @@ +if not modules then modules = { } end modules ['anch-pgr'] = { + version = 1.001, + comment = "companion to anch-pgr.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- This is a bit messy module but backgrounds are messy anyway. Especially when we want to +-- follow shapes. This will always be work in progress as it also depends on new features +-- in context. +-- +-- Alas, shapes and inline didn't work as expected end of 2016 so I had to pick up this +-- thread again. But with regular excursions to listening to Brad Mehldau's Mehliana I +-- could keep myself motivated. Some old stuff has been removed, some suboptimal code has +-- been replaced. Background code is still not perfect, but some day ... the details manual +-- will discuss this issue. + +local tonumber = tonumber +local sort, concat = table.sort, table.concat +local splitter = lpeg.splitat(":") +local lpegmatch = lpeg.match + +local jobpositions = job.positions +local formatters = string.formatters +local setmetatableindex = table.setmetatableindex +local settings_to_array = utilities.parsers.settings_to_array + +local enableaction = nodes.tasks.enableaction + +local commands = commands +local context = context + +local implement = interfaces.implement + +local getmacro = tokens.getters.macro +local scanmpstring = mp.scan.string +local mpgnamespace = getmacro("??graphicvariable") + +local report_graphics = logs.reporter("backgrounds") +local report_shapes = logs.reporter("backgrounds","shapes") +local report_free = logs.reporter("backgrounds","free") + +local trace_shapes = false trackers.register("backgrounds.shapes", function(v) trace_shapes = v end) +local trace_ranges = false trackers.register("backgrounds.shapes.ranges",function(v) trace_ranges = v end) +local trace_free = false trackers.register("backgrounds.shapes.free", function(v) trace_free = v end) + +local f_b_tag = formatters["b:%s"] +local f_e_tag = formatters["e:%s"] +local f_p_tag = formatters["p:%s"] + +local f_tag_two = formatters["%s:%s"] + +local f_point = formatters["%p"] +local f_pair = formatters["(%p,%p)"] +local f_path = formatters["%--t--cycle"] +local f_pair_i = formatters["(%r,%r)"] -- rounded + +graphics = graphics or { } +local backgrounds = { } +graphics.backgrounds = backgrounds + +-- -- -- these can go -- -- -- + +backgrounds.point = f_point +backgrounds.pair = f_pair +backgrounds.path = f_path + +-- -- -- + +local texsetattribute = tex.setattribute + +local a_textbackground = attributes.private("textbackground") + +local nuts = nodes.nuts + +local new_latelua = nuts.pool.latelua +local new_rule = nuts.pool.rule +local new_kern = nuts.pool.kern +local new_hlist = nuts.pool.hlist + +local getbox = nuts.getbox +local getid = nuts.getid +----- getlist = nuts.getlist +local setlink = nuts.setlink +local getheight = nuts.getheight +local getdepth = nuts.getdepth + +local nodecodes = nodes.nodecodes +local par_code = nodecodes.par + +local start_of_par = nuts.start_of_par +local insert_before = nuts.insert_before +local insert_after = nuts.insert_after + +local processranges = nuts.processranges + +local unsetvalue = attributes.unsetvalue + +local jobpositions = job.positions +local getpos = jobpositions.getpos +local getfree = jobpositions.getfree + +local data = { } +local realpage = 1 +local recycle = 1000 -- only tables can overflow this +local enabled = false + +-- Freeing the data is somewhat tricky as we can have backgrounds spanning +-- many pages but for an arbitrary background shape that is not so common. + +local function check(specification) + local a = specification.attribute + local index = specification.index + local depth = specification.depth + local d = specification.data + local where = specification.where + local ht = specification.ht + local dp = specification.dp + -- this is not yet r2l ready + local w = d.shapes[realpage] + local x, y = getpos() + if trace_ranges then + report_shapes("attribute %i, index %i, depth %i, location %s, position (%p,%p)", + a,index,depth,where,x,y) + end + local n = #w + if d.index ~= index then + n = n + 1 + d.index = index + d.depth = depth + -- w[n] = { x, x, y, ht, dp } + w[n] = { y, ht, dp, x, x } + else + local wn = w[n] + local wh = wn[2] + local wd = wn[3] + if depth < d.depth then + local wy = wn[1] + wn[1] = y + d.depth = depth + local dy = wy - y + wh = wh - dy + wd = wd - dy + end + if where == "r" then + if x > wn[5] then + wn[5] = x + end + else + if x < wn[4] then + wn[4] = x + end + end + if ht > wh then + wn[2] = ht + end + if dp > wd then + wn[3] = dp + end + end + -- inspect(w) +end + +local index = 0 + +local function flush(head,f,l,a,parent,depth) + local d = data[a] + if d then + local ix = index + local ht = getheight(parent) + local dp = getdepth(parent) + local ln = new_latelua { action = check, attribute = a, index = ix, depth = depth, data = d, where = "l", ht = ht, dp = dp } + local rn = new_latelua { action = check, attribute = a, index = ix, depth = depth, data = d, where = "r", ht = ht, dp = dp } + if trace_ranges then + ln = new_hlist(setlink(new_rule(65536,65536*4,0),new_kern(-65536),ln)) + rn = new_hlist(setlink(new_rule(65536,0,65536*4),new_kern(-65536),rn)) + end + if getid(f) == par_code and start_of_par(f) then -- we need to clean this mess + insert_after(head,f,ln) + else + head, f = insert_before(head,f,ln) + end + insert_after(head,l,rn) + end + return head, true +end + +local function registerbackground(name) + local n = #data + 1 + if n > recycle then + -- we could also free all e: that are beyond a page but we don't always + -- know the page so a recycle is nicer and the s lists are kept anyway + -- so the amount of kept data is not that large + n = 1 + end + local b = jobpositions.tobesaved["b:"..name] + if b then + local s = setmetatableindex("table") + b.s = s + data[n] = { + bpos = b, + name = name, + n = n, + shapes = s, + count = 0, + sindex = 0, + } + texsetattribute(a_textbackground,n) + if not enabled then + enableaction("contributers", "nodes.handlers.textbackgrounds") + enabled = true + end + else + texsetattribute(a_textbackground,unsetvalue) + end +end + +-- local function collectbackgrounds(r,n) +-- if enabled then +-- local parent = getbox(n) +-- local head = getlist(parent) +-- realpage = r +-- processranges(a_textbackground,flush,head) -- ,parent) +-- end +-- end +-- +-- interfaces.implement { +-- name = "collectbackgrounds", +-- actions = collectbackgrounds, +-- arguments = { "integer", "integer" } +-- } + +nodes.handlers.textbackgrounds = function(head,where,parent) -- we have hlistdir and local dir + -- todo enable action in register + index = index + 1 + return processranges(a_textbackground,flush,head,parent) +end + +interfaces.implement { + name = "registerbackground", + actions = registerbackground, + arguments = "string", +} + +-- optimized already but we can assume a cycle i.e. prune the last point and then +-- even less code .. we could merge some loops but his is more robust + +-- use idiv here + +local function topairs(t,n) + local r = { } + for i=1,n do + local ti = t[i] + r[i] = f_pair_i(ti[1]/65556,ti[2]/65536) + end + return concat(r," ") +end + +local eps = 65536 / 4 +local pps = eps +local nps = - pps + +local function unitvector(x,y) + if x < pps and x > nps then + x = 0 + elseif x < 0 then + x = -1 + else + x = 1 + end + if y < pps and y > nps then + y = 0 + elseif y < 0 then + y = -1 + else + y = 1 + end + return x, y +end + +local function finish(t) + local tm = #t + if tm < 2 then + return + end + if trace_ranges then + report_shapes("initial list: %s",topairs(t,tm)) + end + -- remove similar points + local n = 1 + local tn = tm + local tf = t[1] + local tx = tf[1] + local ty = tf[2] + for i=2,#t do + local ti = t[i] + local ix = ti[1] + local iy = ti[2] + local dx = ix - tx + local dy = iy - ty + if dx > eps or dx < - eps or dy > eps or dy < - eps then + n = n + 1 + t[n] = ti + tx = ix + ty = iy + end + end + if trace_shapes then + report_shapes("removing similar points: %s",topairs(t,n)) + end + if n > 2 then + -- remove redundant points + repeat + tn = n + n = 0 + local tm = t[tn] + local tmx = tm[1] + local tmy = tm[2] + local tp = t[1] + local tpx = tp[1] + local tpy = tp[2] + for i=1,tn do -- while and only step when done + local ti = tp + local tix = tpx + local tiy = tpy + if i == tn then + tp = t[1] + else + tp = t[i+1] + end + tpx = tp[1] + tpy = tp[2] + + local vx1, vx2 = unitvector(tix - tmx,tpx - tix) + if vx1 ~= vx2 then + n = n + 1 + t[n] = ti + else + local vy1, vy2 = unitvector(tiy - tmy,tpy - tiy) + if vy1 ~= vy2 then + n = n + 1 + t[n] = ti + end + end + + tmx = tix + tmy = tiy + end + until n == tn or n <= 2 + if trace_shapes then + report_shapes("removing redundant points: %s",topairs(t,n)) + end + -- remove spikes + if n > 2 then + repeat + tn = n + n = 0 + local tm = t[tn] + local tmx = tm[1] + local tmy = tm[2] + local tp = t[1] + local tpx = tp[1] + local tpy = tp[2] + for i=1,tn do -- while and only step when done + local ti = tp + local tix = tpx + local tiy = tpy + if i == tn then + tp = t[1] + else + tp = t[i+1] + end + tpx = tp[1] + tpy = tp[2] + + local vx1, vx2 = unitvector(tix - tmx,tpx - tix) + if vx1 ~= - vx2 then + n = n + 1 + t[n] = ti + else + local vy1, vy2 = unitvector(tiy - tmy,tpy - tiy) + if vy1 ~= - vy2 then + n = n + 1 + t[n] = ti + end + end + + tmx = tix + tmy = tiy + end + until n == tn or n <= 2 + if trace_shapes then + report_shapes("removing spikes: %s",topairs(t,n)) + end + end + end + -- prune trailing points + if tm > n then + for i=tm,n+1,-1 do + t[i] = nil + end + end + if n > 1 then + local tf = t[1] + local tl = t[n] + local dx = tf[1] - tl[1] + local dy = tf[2] - tl[2] + if dx > eps or dx < - eps or dy > eps or dy < - eps then + -- different points + else + -- saves a point (as we -- cycle anyway) + t[n] = nil + n = n -1 + end + if trace_shapes then + report_shapes("removing cyclic endpoints: %s",topairs(t,n)) + end + end + return t +end + +local eps = 65536 + +-- The next function can introduce redundant points but these are removed later on +-- in the unspiker. It makes checking easier. + +local function shape(kind,b,p,realpage,xmin,xmax,ymin,ymax,fh,ld) + local s = b.s + if not s then + if trace_shapes then + report_shapes("calculating %s area, no shape",kind) + end + return + end + s = s[realpage] + if not s then + if trace_shapes then + report_shapes("calculating %s area, no shape for page %s",kind,realpage) + end + return + end + local ns = #s + if ns == 0 then + if trace_shapes then + report_shapes("calculating %s area, empty shape for page %s",kind,realpage) + end + return + end + -- + if trace_shapes then + report_shapes("calculating %s area, using shape for page %s",kind,realpage) + end + -- it's a bit inefficient to use the par values and later compensate for b and + -- e but this keeps the code (loop) cleaner + local ph = p and p.h or 0 + local pd = p and p.d or 0 + -- + xmax = xmax + eps + xmin = xmin - eps + ymax = ymax + eps + ymin = ymin - eps + local ls = { } -- left shape + local rs = { } -- right shape + local pl = nil -- previous left x + local pr = nil -- previous right x + local n = 0 + local xl = nil + local xr = nil + local mh = ph -- min + local md = pd -- min + for i=1,ns do + local si = s[i] + local y = si[1] + local ll = si[4] -- can be sparse + if ll then + xl = ll + local rr = si[5] -- can be sparse + if rr then + xr = rr + end + end + if trace_ranges then + report_shapes("original : [%02i] xl=%p xr=%p y=%p",i,xl,xr,y) + end + if xl ~= xr then -- could be catched in the finalizer + local xm = xl + (xr - xl)/2 -- midpoint should be in region + if xm >= xmin and xm <= xmax and y >= ymin and y <= ymax then + local ht = si[2] -- can be sparse + if ht then + ph = ht + local dp = si[3] -- can be sparse + if dp then + pd = dp + end + end + local h = y + (ph < mh and mh or ph) + local d = y - (pd < md and md or pd) + if pl then + n = n + 1 + ls[n] = { pl, h } + rs[n] = { pr, h } + if trace_ranges then + report_shapes("paragraph : [%02i] xl=%p xr=%p y=%p",i,pl,pr,h) + end + end + n = n + 1 + ls[n] = { xl, h } + rs[n] = { xr, h } + if trace_ranges then + report_shapes("height : [%02i] xl=%p xr=%p y=%p",i,xl,xr,h) + end + n = n + 1 + ls[n] = { xl, d } + rs[n] = { xr, d } + if trace_ranges then + report_shapes("depth : [%02i] xl=%p xr=%p y=%p",i,xl,xr,d) + end + end + pl, pr = xl, xr + else + if trace_ranges then + report_shapes("ignored : [%02i] xl=%p xr=%p y=%p",i,xl,xr,y) + end + end + end + -- + if true and n > 0 then + -- use height of b and depth of e, maybe check for weird border + -- cases here + if fh then + local lsf = ls[1] + local rsf = rs[1] + if lsf[2] < fh then + lsf[2] = fh + end + if rsf[2] < fh then + rsf[2] = fh + end + end + if fd then + local lsl = ls[n] + local rsl = rs[n] + if lsl[2] > fd then + lsl[2] = fd + end + if rsl[2] > fd then + rsl[2] = fd + end + end + end + -- + for i=n,1,-1 do + n = n + 1 rs[n] = ls[i] + end + return rs +end + +local function singlepart(b,e,p,realpage,r,left,right) + local bx = b.x + local by = b.y + local ex = e.x + local ey = e.y + local rx = r.x + local ry = r.y + local bh = by + b.h + local bd = by - b.d + local eh = ey + e.h + local ed = ey - e.d + local rh = ry + r.h + local rd = ry - r.d + local rw = rx + r.w + if left then + rx = rx + left + rw = rw - right + end + if ex == rx then + -- We probably have a strut at the next line so we force a width + -- although of course it is better to move up. But as we have whitespace + -- (at least visually) injected then it's best to stress the issue. + ex = rw + end + local area + if by == ey then + if trace_shapes then + report_shapes("calculating single area, partial line") + end + area = { + { bx, bh }, + { ex, eh }, + { ex, ed }, + { bx, bd }, + } + elseif b.k == 2 then + area = { + { rx, bh }, + { rw, bh }, + { rw, ed }, + { rx, ed }, + } + else + area = shape("single",b,p,realpage,rx,rw,rd,rh,bh,ed) + end + if not area then + area = { + { bx, bh }, + { rw, bh }, + { rw, eh }, + { ex, eh }, + { ex, ed }, + { rx, ed }, + { rx, bd }, + { bx, bd }, + } + end + return { + location = "single", + region = r, + area = finish(area), + } +end + +local function firstpart(b,e,p,realpage,r,left,right) + local bx = b.x + local by = b.y + local rx = r.x + local ry = r.y + local bh = by + b.h + local bd = by - b.d + local rh = ry + r.h + local rd = ry - r.d + local rw = rx + r.w + if left then + rx = rx + left + rw = rw - right + end + local area = shape("first",b,p,realpage,rx,rw,rd,rh,bh,false) + if not area then + if b.k == 2 then + area = { + { rx, bh }, + { rw, bh }, + { rw, rd }, + { rx, rd }, + } + else + area = { + { bx, bh }, + { rw, bh }, + { rw, rd }, -- { rw, eh }, + { rx, rd }, -- { rx, ed }, + { rx, bd }, + { bx, bd }, + } + end + end + return { + location = "first", + region = r, + area = finish(area), + } +end + +local function middlepart(b,e,p,realpage,r,left,right) + local rx = r.x + local ry = r.y + local rh = ry + r.h + local rd = ry - r.d + local rw = rx + r.w + if left then + rx = rx + left + rw = rw - right + end + local area = shape("middle",b,p,realpage,rx,rw,rd,rh,false,false) + if not area then + area = { + { rw, rh }, + { rw, rd }, + { rx, rd }, + { rx, rh }, + } + end + return { + location = "middle", + region = r, + area = finish(area), + } +end + +local function lastpart(b,e,p,realpage,r,left,right) + local ex = e.x + local ey = e.y + local rx = r.x + local ry = r.y + local eh = ey + e.h + local ed = ey - e.d + local rh = ry + r.h + local rd = ry - r.d + local rw = rx + r.w + if left then + rx = rx + left + rw = rw - right + end + local area = shape("last",b,p,realpage,rx,rw,rd,rh,false,ed) + if not area then + if b.k == 2 then + area = { + { rw, rh }, + { rw, ed }, + { rx, ed }, + { rx, rh }, + } + else + area = { + { rw, rh }, -- { rw, bh }, + { rw, eh }, + { ex, eh }, + { ex, ed }, + { rx, ed }, + { rx, rh }, -- { rx, bd }, + } + end + end + return { + location = "last", + region = r, + area = finish(area), + } +end + +local function calculatemultipar(tag) + local collected = jobpositions.collected + local b = collected[f_b_tag(tag)] + local e = collected[f_e_tag(tag)] + if not b or not e then + report_shapes("invalid tag %a",tag) + return { } + end + local br = b.r + local er = e.r + if not br or not er then + report_shapes("invalid region for %a",tag) + return { } + end + local btag, bindex = lpegmatch(splitter,br) + local etag, eindex = lpegmatch(splitter,er) + if not bindex or not eindex or btag ~= etag then + report_shapes("invalid indices for %a",tag) + return { } + end + local bindex = tonumber(bindex) + local eindex = tonumber(eindex) + -- Here we compensate for columns (in tables): a table can have a set of column + -- entries and these are shared. We compensate left/right based on the columns + -- x and w but need to take the region into acount where the specification was + -- flushed and not the begin pos's region, because otherwise we get the wrong + -- compensation for asymetrical doublesided layouts. + local left = 0 + local right = 0 + local bc = b.c + local rc = bc and collected[bc] + if rc then + local tb = collected[rc.r] + if tb then + left = -(tb.x - rc.x) + right = (tb.w - rc.w - left) + end + end + -- Obeying intermediate changes of left/rightskip makes no sense as it will + -- look bad, so we only look at the begin situation. + local bn = b.n + local p = bn and collected[f_p_tag(bn)] -- par + if p then + left = left + (p.ls or 0) + right = right + (p.rs or 0) + end + -- + local bp = b.p -- page + if trace_shapes then + report_shapes("tag %a, left %p, right %p, par %s, page %s, column %s", + tag,left,right,bn or "-",bp or "-",bc or "-") + end + -- + if bindex == eindex then + return { + list = { [bp] = { singlepart(b,e,p,bp,collected[br],left,right) } }, + bpos = b, + epos = e, + } + else + local list = { + [bp] = { firstpart(b,e,p,bp,collected[br],left,right) }, + } + for i=bindex+1,eindex-1 do + br = f_tag_two(btag,i) + local r = collected[br] + if not r then + report_graphics("invalid middle for %a",br) + else + local rp = r.p -- page + local pp = list[rp] + local mp = middlepart(b,e,p,rp,r,left,right) + if pp then + pp[#pp+1] = mp + else + list[rp] = { mp } + end + end + end + local ep = e.p -- page + local pp = list[ep] + local lp = lastpart(b,e,p,ep,collected[er],left,right) + if pp then + pp[#pp+1] = lp + else + list[ep] = { lp } + end + return { + list = list, + bpos = b, + epos = e, + } + end +end + +local pbg = { } -- will move to pending + +local multilocs = { + single = 1, -- maybe 0 + first = 1, + middle = 2, + last = 3, +} + +-- if unknown context_abck : input mp-abck.mpiv ; fi ; + +local f_template_a = formatters[ [[ +path multiregs[], multipars[], multibox ; +string multikind[] ; +numeric multilocs[], nofmultipars ; +nofmultipars := %s ; +multibox := unitsquare xyscaled (%p,%p) ; +numeric par_strut_height, par_strut_depth, par_line_height ; +par_strut_height := %p ; +par_strut_depth := %p ; +par_line_height := %p ; +]] ] + +local f_template_b = formatters[ [[ +multilocs[%s] := %s ; +multikind[%s] := "%s" ; +multipars[%s] := (%--t--cycle) shifted - (%p,%p) ; +]] ] + +-- unspiked(simplified(%--t--cycle)) shifted - (%p,%p) ; + +local f_template_c = formatters[ [[ +setbounds currentpicture to multibox ; +]] ] + +local function freemultipar(pagedata,frees) -- ,k + -- if k == 3 then + -- -- tables have local regions + -- return + -- end + if not frees then + return + end + local nfree = #frees + if nfree == 0 then + return + end + for i=1,#pagedata do + local data = pagedata[i] + local area = data.area + + if area then + + local region = data.region + local y = 0 -- region.y + -- local x = region.x + local areas = { } + data.areas = areas + + local f_1 = { } + local n_1 = 0 + local f_2 = { } + local n_2 = 0 + for i=1,#frees do + local f = frees[i] + local k = f.k + if k == 1 then -- pag + n_1 = n_1 + 1 + f_1[n_1] = f + elseif k == 2 or k == 3 then -- par + n_2 = n_2 + 1 + f_2[n_2] = f + end + end + + local lineheight = tex.dimen.lineheight + + -- page floats + + local function check_one(free1,free2) + local temp = { } + local some = false + local top = (free2 and (y + free2.y + free2.h + (free2.to or 0))) or false + local bot = (free1 and (y + free1.y - free1.d - (free1.bo or 0))) or false + for i=1,#area do + local a = area[i] + local x = a[1] + local y = a[2] + if free2 and y <= top then + y = top + end + if free1 and y >= bot then + y = bot + end + if not some then + some = y + elseif some == true then + -- done + elseif y ~= some then + some = true + end + temp[i] = { x, y } + end + if some == true then + areas[#areas+1] = temp + end + end + + if n_1 > 0 then + check_one(false,f_1[1]) + for i=2,n_1 do + check_one(f_1[i-1],f_1[i]) + end + check_one(f_1[n_1],false) + end + + -- par floats + + if #areas == 0 then + areas[1] = area + end + + -- we can collect the coordinates first + + local function check_two(area,frees) + local ul = area[1] + local ur = area[2] + local lr = area[3] + local ll = area[4] + local ulx = ul[1] + local uly = ul[2] + local urx = ur[1] + local ury = ur[2] + local lrx = lr[1] + local lry = lr[2] + local llx = ll[1] + local lly = ll[2] + + local temp = { } + local n = 0 + local done = false + + for i=1,#frees do + local free = frees[i] + local fx = free.x + local fy = free.y + local ymax = y + fy + free.h + (free.to or 0) + local ymin = y + fy - free.d - (free.bo or 0) + local xmin = fx - (free.lo or 0) + local xmax = fx + free.w + (free.ro or 0) + if free.k == 3 then + if uly <= ymax and uly >= ymin and lly <= ymin then + if trace_free then + report_free("case 1, top, right") -- ok + end + n = n + 1 temp[n] = { xmin, ury } + n = n + 1 temp[n] = { xmin, ymin } + n = n + 1 temp[n] = { lrx, ymin } + n = n + 1 temp[n] = { lrx, lry } + done = true + elseif uly >= ymax and lly <= ymin then + if trace_free then + report_free("case 2, outside, right") -- ok + end + if uly - ymax < lineheight then + n = n + 1 temp[n] = { xmin, ury } + else + n = n + 1 temp[n] = { urx, ury } + n = n + 1 temp[n] = { urx, ymax } + end + n = n + 1 temp[n] = { xmin, ymax } + n = n + 1 temp[n] = { xmin, ymin } + n = n + 1 temp[n] = { lrx, ymin } + n = n + 1 temp[n] = { lrx, lry } + done = true + elseif lly <= ymax and lly >= ymin and uly >= ymax then + if trace_free then + report_free("case 3, bottom, right") + end + if uly - ymax < lineheight then + n = n + 1 temp[n] = { xmin, ury } + else + n = n + 1 temp[n] = { urx, ury } + n = n + 1 temp[n] = { urx, ymax } + end + n = n + 1 temp[n] = { xmin, ymax } + n = n + 1 temp[n] = { xmin, lry } + done = true + elseif uly <= ymax and lly >= ymin then + if trace_free then + report_free("case 4, inside, right") + end + n = n + 1 temp[n] = { xmin, uly } + n = n + 1 temp[n] = { xmin, lly } + done = true + else + -- case 0 + if trace_free then + report_free("case 0, nothing") + end + end + end + end + + if not done then + if trace_free then + report_free("no right shape") + end + n = n + 1 temp[n] = { urx, ury } + n = n + 1 temp[n] = { lrx, lry } + n = n + 1 temp[n] = { llx, lly } + else + done = false + end + + for i=#frees,1,-1 do + local free = frees[i] + local fx = free.x + local fy = free.y + local ymax = y + fy + free.h + (free.to or 0) + local ymin = y + fy - free.d - (free.bo or 0) + local xmin = fx - (free.lo or 0) + local xmax = fx + free.w + (free.ro or 0) + if free.k == 2 then + if uly <= ymax and uly >= ymin and lly <= ymin then + if trace_free then + report_free("case 1, top, left") -- ok + end + n = n + 1 temp[n] = { ulx, ymin } + n = n + 1 temp[n] = { xmax, ymin } + n = n + 1 temp[n] = { xmax, uly } + done = true + elseif uly >= ymax and lly <= ymin then + if trace_free then + report_free("case 2, outside, left") -- ok + end + n = n + 1 temp[n] = { llx, lly } + n = n + 1 temp[n] = { llx, ymin } + n = n + 1 temp[n] = { xmax, ymin } + n = n + 1 temp[n] = { xmax, ymax } + if uly - ymax < lineheight then + n = n + 1 temp[n] = { xmax, uly } + else + n = n + 1 temp[n] = { llx, ymax } + n = n + 1 temp[n] = { llx, uly } + end + done = true + elseif lly <= ymax and lly >= ymin and uly >= ymax then + if trace_free then + report_free("case 3, bottom, left") + end + n = n + 1 temp[n] = { xmax, lly } + n = n + 1 temp[n] = { xmax, ymax } + if uly - ymax < lineheight then + n = n + 1 temp[n] = { xmax, uly } + else + n = n + 1 temp[n] = { llx, ymax } + n = n + 1 temp[n] = { llx, uly } + end + done = true + elseif uly <= ymax and lly >= ymin then + if trace_free then + report_free("case 4, inside, left") + end + n = n + 1 temp[n] = { xmax, lly } + n = n + 1 temp[n] = { xmax, uly } + done = true + else + -- case 0 + end + end + end + + if not done then + if trace_free then + report_free("no left shape") + end + n = n + 1 temp[n] = { llx, lly } + end + n = n + 1 temp[n] = { ulx, uly } + + return temp + end + + if n_2 > 0 then + for i=1,#areas do + local area = areas[i] + if #area == 4 then -- and also check type, must be pargaraph + areas[i] = check_two(area,f_2) + else + -- message that not yet supported + end + end + end + + for i=1,#areas do + finish(areas[i]) -- again + end + + end + + end +end + +local function fetchmultipar(n,anchor,page) + local a = jobpositions.collected[anchor] + if not a then + report_graphics("missing anchor %a",anchor) + else + local data = pbg[n] + if not data then + data = calculatemultipar(n) + pbg[n] = data -- can be replaced by register + -- register(data.list,n,anchor) + end + local list = data and data.list + if list then + local pagedata = list[page] + if pagedata then + local k = data.bpos.k + if k ~= 3 then + -- to be checked: no need in txt mode + freemultipar(pagedata,getfree(page)) + end + local nofmultipars = #pagedata + if trace_shapes then + report_graphics("fetching %a at page %s using anchor %a containing %s multipars", + n,page,anchor,nofmultipars) + end + local x = a.x + local y = a.y + local w = a.w + local h = a.h + local d = a.d + local bpos = data.bpos + local bh = bpos.h + local bd = bpos.d + local result = { false } -- slot 1 will be set later + local n = 0 + for i=1,nofmultipars do + local data = pagedata[i] + local location = data.location + local region = data.region + local areas = data.areas + if not areas then + areas = { data.area } + end + for i=1,#areas do + local area = areas[i] + for i=1,#area do + local a = area[i] + area[i] = f_pair(a[1],a[2]) + end + n = n + 1 + result[n+1] = f_template_b(n,multilocs[location],n,location,n,area,x,y) + end + end + data[page] = nil + result[1] = f_template_a(n,w,h+d,bh,bd,bh+bd) -- was delayed + result[n+2] = f_template_c() + return concat(result,"\n") + end + end + end + return f_template_a(0,0,0,0,0,0); +end + +backgrounds.fetchmultipar = fetchmultipar + +local function getwhatever(action) + local tags = scanmpstring() + local anchor = scanmpstring() + local page = nil + if tags == "self" then + tags = getmacro(mpgnamespace .. getmacro("currentmpvariableclass") .. ":self",true) -- Isn't it already edef'd? + elseif type(tags) == "string" then + tags = settings_to_array(tags) + for i=1,#tags do + tags[i] = getmacro(mpgnamespace .. getmacro("currentmpvariableclass") .. ":" .. tags[i],true) -- Isn't it already edef'd? + end + end + if anchor == "anchor" then + anchor = getmacro("MPanchorid") -- brrr + end + if tags and anchor then + return action(tags,anchor,page) + end +end + +metapost.registerscript("getmultipars", function() + return getwhatever(fetchmultipar) +end) + +-- n anchor page + +implement { + name = "fetchmultipar", + actions = { fetchmultipar, context }, + arguments = { "string", "string", "integer" } +} + +-- todo: use inject + +do + + local f_template_a = formatters[ [[ + path posboxes[], posregions[] ; + numeric pospages[] ; + numeric nofposboxes ; + nofposboxes := %s ; + %t + ]] ] + + local f_template_b = formatters[ [[ + pospages[%s] := %s ; + posboxes[%s] := (%p,%p)--(%p,%p)--(%p,%p)--(%p,%p)--cycle ; + posregions[%s] := (%p,%p)--(%p,%p)--(%p,%p)--(%p,%p)--cycle ; + ]] ] + + local function getposboxes(tags,anchor,page) -- no caching (yet) / page + local collected = jobpositions.collected + if type(tags) == "string" then + tags = settings_to_array(tags) + end + local list = { } + local nofboxes = 0 + for i=1,#tags do + local tag= tags[i] + local c = collected[tag] + if c then + local r = c.r + if anchor ~= r then + r = anchor + end + if r then + r = collected[r] + if r then + local rx = r.x + local ry = r.y + local rw = r.w + local rh = r.h + local rd = r.d + local cx = c.x - rx + local cy = c.y - ry + local cw = cx + c.w + local ch = cy + c.h + local cd = cy - c.d + nofboxes = nofboxes + 1 + list[nofboxes] = f_template_b( + nofboxes,c.p, + nofboxes,cx,ch,cw,ch,cw,cd,cx,cd, + nofboxes,0,rh,rw,rh,rw,rd,0,rd + ) + end + end + else + -- print("\n missing",tag) + end + end + return f_template_a(nofboxes,list) + end + + metapost.registerscript("getposboxes", function() + return getwhatever(getposboxes) + end) + + implement { + name = "fetchposboxes", + arguments = { "string", "string", "integer" }, + actions = { getposboxes, context }, + } + +end + +do + + local doifelse = commands.doifelse + + implement { + name = "doifelserangeonpage", + arguments = { "string", "string", "integer" }, + actions = function(first,last,page) + local c = jobpositions.collected + local f = c[first] + if f then + f = f.p + if f and f ~= true and page >= f then + local l = c[last] + if l then + l = l.p + doifelse(l and l ~= true and page <= l) + return + end + end + end + doifelse(false) + end + } + +end |