diff options
Diffstat (limited to 'tex/context/base/mkxl/anch-pos.lmt')
-rw-r--r-- | tex/context/base/mkxl/anch-pos.lmt | 1633 |
1 files changed, 1633 insertions, 0 deletions
diff --git a/tex/context/base/mkxl/anch-pos.lmt b/tex/context/base/mkxl/anch-pos.lmt new file mode 100644 index 000000000..e1d9bd752 --- /dev/null +++ b/tex/context/base/mkxl/anch-pos.lmt @@ -0,0 +1,1633 @@ +if not modules then modules = { } end modules ['anch-pos'] = { + version = 1.001, + comment = "companion to anch-pos.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +--[[ldx-- +<p>We save positional information in the main utility table. Not only +can we store much more information in <l n='lua'/> but it's also +more efficient.</p> +--ldx]]-- + +-- plus (extra) is obsolete but we will keep it for a while +-- +-- maybe replace texsp by our own converter (stay at the lua end) +-- eventually mp will have large numbers so we can use sp there too +-- +-- this is one of the first modules using scanners and we need to replace it by +-- implement and friends +-- +-- we could have namespaces, like p, page, region, columnarea, textarea but then +-- we need virtual table accessors as well as have tag/id accessors ... we don't +-- save much here (at least not now) +-- +-- This was the last module that got rid of directly setting scanners, with a little +-- performance degradation but not that noticeable. + +local tostring, next, setmetatable, tonumber = tostring, next, setmetatable, tonumber +local sort = table.sort +local format, gmatch = string.format, string.gmatch +local lpegmatch = lpeg.match +local insert, remove = table.insert, table.remove +local allocate = utilities.storage.allocate + +local report = logs.reporter("positions") + +local scanners = tokens.scanners +local scanstring = scanners.string +local scaninteger = scanners.integer +local scandimen = scanners.dimen + +local implement = interfaces.implement + +local commands = commands +local context = context + +local ctx_latelua = context.latelua + +local tex = tex +local texgetcount = tex.getcount +local texgetinteger = tex.getintegervalue or tex.getcount +local texsetcount = tex.setcount +local texget = tex.get +local texsp = tex.sp +----- texsp = string.todimen -- because we cache this is much faster but no rounding + +local setmetatableindex = table.setmetatableindex +local setmetatablenewindex = table.setmetatablenewindex + +local nuts = nodes.nuts + +local setlink = nuts.setlink +local getlist = nuts.getlist +local setlist = nuts.setlist +local getbox = nuts.getbox +local getid = nuts.getid +local getwhd = nuts.getwhd + +local hlist_code = nodes.nodecodes.hlist + +local find_tail = nuts.tail +----- hpack = nuts.hpack + +local new_latelua = nuts.pool.latelua + +local variables = interfaces.variables +local v_text = variables.text +local v_column = variables.column + +local pt = number.dimenfactors.pt +local pts = number.pts +local formatters = string.formatters + +local collected = allocate() +local tobesaved = allocate() + +local jobpositions = { + collected = collected, + tobesaved = tobesaved, +} + +job.positions = jobpositions + +local default = { -- not r and paragraphs etc + __index = { + x = 0, -- x position baseline + y = 0, -- y position baseline + w = 0, -- width + h = 0, -- height + d = 0, -- depth + p = 0, -- page + n = 0, -- paragraph + ls = 0, -- leftskip + rs = 0, -- rightskip + hi = 0, -- hangindent + ha = 0, -- hangafter + hs = 0, -- hsize + pi = 0, -- parindent + ps = false, -- parshape + dir = 0, + } +} + +local f_b_tag = formatters["b:%s"] +local f_e_tag = formatters["e:%s"] +local f_p_tag = formatters["p:%s"] +local f_w_tag = formatters["w:%s"] + +local f_region = formatters["region:%s"] + +local f_tag_three = formatters["%s:%s:%s"] +local f_tag_two = formatters["%s:%s"] + +local nofregular = 0 +local nofspecial = 0 +local splitter = lpeg.splitat(":",true) + +local pagedata = { } +local columndata = setmetatableindex("table") -- per page +local freedata = setmetatableindex("table") -- per page + +local function initializer() + tobesaved = jobpositions.tobesaved + collected = jobpositions.collected + for tag, data in next, collected do + local prefix, rest = lpegmatch(splitter,tag) + if prefix == "p" then + nofregular = nofregular + 1 + elseif prefix == "page" then + nofregular = nofregular + 1 + pagedata[tonumber(rest) or 0] = data + elseif prefix == "free" then + nofspecial = nofspecial + 1 + local t = freedata[data.p or 0] + t[#t+1] = data + elseif prefix == "columnarea" then + columndata[data.p or 0][data.c or 0] = data + end + setmetatable(data,default) + end + -- + local pages = structures.pages.collected + if pages then + local last = nil + for p=1,#pages do + local region = "page:" .. p + local data = pagedata[p] + local free = freedata[p] + if free then + sort(free,function(a,b) return b.y < a.y end) -- order matters ! + end + if data then + last = data + last.free = free + elseif last then + local t = setmetatableindex({ free = free, p = p },last) + if not collected[region] then + collected[region] = t + else + -- something is wrong + end + pagedata[p] = t + end + end + end + jobpositions.pagedata = pagedata +end + +function jobpositions.used() + return next(collected) -- we can safe it +end + +function jobpositions.getfree(page) + return freedata[page] +end + +-- we can gain a little when we group positions but then we still have to +-- deal with regions and cells so we either end up with lots of extra small +-- tables pointing to them and/or assembling/disassembling so in the end +-- it makes no sense to do it (now) and still have such a mix +-- +-- proof of concept code removed ... see archive + +local function finalizer() + -- We make the (possible extensive) shape lists sparse working + -- from the end. We could also drop entries here that have l and + -- r the same which saves testing later on. + for k, v in next, tobesaved do + local s = v.s + if s then + for p, data in next, s do + local n = #data + if n > 1 then + local ph = data[1][2] + local pd = data[1][3] + local xl = data[1][4] + local xr = data[1][5] + for i=2,n do + local di = data[i] + local h = di[2] + local d = di[3] + local l = di[4] + local r = di[5] + if r == xr then + di[5] = nil + if l == xl then + di[4] = nil + if d == pd then + di[3] = nil + if h == ph then + di[2] = nil + else + ph = h + end + else + pd, ph = d, h + end + else + ph, pd, xl = h, d, l + end + else + ph, pd, xl, xr = h, d, l, r + end + end + end + end + end + end +end + +job.register('job.positions.collected', tobesaved, initializer, finalizer) + +local regions = { } +local nofregions = 0 +local region = nil + +local columns = { } +local nofcolumns = 0 +local column = nil + +local nofpages = nil + +-- beware ... we're not sparse here as lua will reserve slots for the nilled + +local getpos, gethpos, getvpos + +function jobpositions.registerhandlers(t) + getpos = t and t.getpos or function() return 0, 0 end + getrpos = t and t.getrpos or function() return 0, 0, 0 end + gethpos = t and t.gethpos or function() return 0 end + getvpos = t and t.getvpos or function() return 0 end +end + +function jobpositions.getpos () return getpos () end +function jobpositions.getrpos() return getrpos() end +function jobpositions.gethpos() return gethpos() end +function jobpositions.getvpos() return getvpos() end + +-------- jobpositions.getcolumn() return column end + +jobpositions.registerhandlers() + +local function setall(name,p,x,y,w,h,d,extra) + tobesaved[name] = { + p = p, + x = x ~= 0 and x or nil, + y = y ~= 0 and y or nil, + w = w ~= 0 and w or nil, + h = h ~= 0 and h or nil, + d = d ~= 0 and d or nil, + e = extra ~= "" and extra or nil, + r = region, + c = column, + r2l = texgetinteger("inlinelefttoright") == 1 and true or nil, + } +end + +local function enhance(data) + if not data then + return nil + end + if data.r == true then -- or "" + data.r = region + end + if data.x == true then + if data.y == true then + local x, y = getpos() + data.x = x ~= 0 and x or nil + data.y = y ~= 0 and y or nil + else + local x = gethpos() + data.x = x ~= 0 and x or nil + end + elseif data.y == true then + local y = getvpos() + data.y = y ~= 0 and y or nil + end + if data.p == true then + data.p = texgetcount("realpageno") -- we should use a variable set in otr + end + if data.c == true then + data.c = column + end + if data.w == 0 then + data.w = nil + end + if data.h == 0 then + data.h = nil + end + if data.d == 0 then + data.d = nil + end + return data +end + +-- analyze some files (with lots if margindata) and then when one key optionally +-- use that one instead of a table (so, a 3rd / 4th argument: key, e.g. "x") + +local function set(name,index,value) -- ,key + -- officially there should have been a settobesaved + local data = enhance(value or {}) + if value then + container = tobesaved[name] + if not container then + tobesaved[name] = { + [index] = data + } + else + container[index] = data + end + else + tobesaved[name] = data + end +end + +local function setspec(specification) + local name = specification.name + local index = specification.index + local value = specification.value + local data = enhance(value or {}) + if value then + container = tobesaved[name] + if not container then + tobesaved[name] = { + [index] = data + } + else + container[index] = data + end + else + tobesaved[name] = data + end +end + +local function get(id,index) + if index then + local container = collected[id] + return container and container[index] + else + return collected[id] + end +end + +------------.setdim = setdim +jobpositions.setall = setall +jobpositions.set = set +jobpositions.setspec = setspec +jobpositions.get = get + +implement { + name = "dosaveposition", + public = true, + protected = true, + arguments = { "argument", "integerargument", "dimenargument", "dimenargument" }, + actions = setall, -- name p x y +} + +implement { + name = "dosavepositionwhd", + public = true, + protected = true, + arguments = { "argument", "integerargument", "dimenargument", "dimenargument", "dimenargument", "dimenargument", "dimenargument" }, + actions = setall, -- name p x y w h d +} + +implement { + name = "dosavepositionplus", + public = true, + protected = true, + arguments = { "argument", "integerargument", "dimenargument", "dimenargument", "dimenargument", "dimenargument", "dimenargument", "argument" }, + actions = setall, -- name p x y w h d extra +} + +-- will become private table (could also become attribute driven but too nasty +-- as attributes can bleed e.g. in margin stuff) + +-- not much gain in keeping stack (inc/dec instead of insert/remove) + +local function b_column(specification) + local tag = specification.tag + local x = gethpos() + tobesaved[tag] = { + r = true, + x = x ~= 0 and x or nil, + -- w = 0, + } + insert(columns,tag) + column = tag +end + +local function e_column() + local t = tobesaved[column] + if not t then + -- something's wrong + else + local x = gethpos() - t.x + t.w = x ~= 0 and x or nil + t.r = region + end + remove(columns) + column = columns[#columns] +end + +jobpositions.b_column = b_column +jobpositions.e_column = e_column + +implement { + name = "bposcolumn", + arguments = "string", + actions = function(tag) + insert(columns,tag) + column = tag + end +} + +implement { + name = "bposcolumnregistered", + arguments = "string", + actions = function(tag) + insert(columns,tag) + column = tag + ctx_latelua { action = b_column, tag = tag } + end +} + +implement { + name = "eposcolumn", + actions = function() + remove(columns) + column = columns[#columns] + end +} + +implement { + name = "eposcolumnregistered", + actions = function() + ctx_latelua { action = e_column } + remove(columns) + column = columns[#columns] + end +} + +-- regions + +local function b_region(specification) + local tag = specification.tag or specification + local last = tobesaved[tag] + local x, y = getpos() + last.x = x ~= 0 and x or nil + last.y = y ~= 0 and y or nil + last.p = texgetcount("realpageno") + insert(regions,tag) -- todo: fast stack + region = tag +end + +local function e_region(specification) + local last = tobesaved[region] + local y = getvpos() + local x, y = getpos() + if specification.correct then + local h = (last.y or 0) - y + last.h = h ~= 0 and h or nil + end + last.y = y ~= 0 and y or nil + remove(regions) -- todo: fast stack + region = regions[#regions] +end + +jobpositions.b_region = b_region +jobpositions.e_region = e_region + +local lastregion + +local function setregionbox(n,tag,k,lo,ro,to,bo,column) -- kind + if not tag or tag == "" then + nofregions = nofregions + 1 + tag = f_region(nofregions) + end + local box = getbox(n) + local w, h, d = getwhd(box) + tobesaved[tag] = { + -- p = texgetcount("realpageno"), -- we copy them + x = 0, + y = 0, + w = w ~= 0 and w or nil, + h = h ~= 0 and h or nil, + d = d ~= 0 and d or nil, + k = k ~= 0 and k or nil, + lo = lo ~= 0 and lo or nil, + ro = ro ~= 0 and ro or nil, + to = to ~= 0 and to or nil, + bo = bo ~= 0 and bo or nil, + c = column or nil, + } + lastregion = tag + return tag, box +end + +local function markregionbox(n,tag,correct,...) -- correct needs checking + local tag, box = setregionbox(n,tag,...) + -- todo: check if tostring is needed with formatter + local push = new_latelua { action = b_region, tag = tag } + local pop = new_latelua { action = e_region, correct = correct } + -- maybe we should construct a hbox first (needs experimenting) so that we can avoid some at the tex end + local head = getlist(box) + -- no, this fails with \framed[region=...] .. needs thinking + -- if getid(box) ~= hlist_code then + -- -- report("mark region box assumes a hlist, fix this for %a",tag) + -- head = hpack(head) + -- end + if head then + local tail = find_tail(head) + setlink(push,head) + setlink(tail,pop) + else -- we can have a simple push/pop + setlink(push,pop) + end + setlist(box,push) +end + +jobpositions.markregionbox = markregionbox +jobpositions.setregionbox = setregionbox + +function jobpositions.enhance(name) + enhance(tobesaved[name]) +end + +function jobpositions.gettobesaved(name,tag) + local t = tobesaved[name] + if t and tag then + return t[tag] + else + return t + end +end + +function jobpositions.settobesaved(name,tag,data) + local t = tobesaved[name] + if t and tag and data then + t[tag] = data + end +end + +local nofparagraphs = 0 + +implement { + name = "parpos", + actions = function() + nofparagraphs = nofparagraphs + 1 + texsetcount("global","c_anch_positions_paragraph",nofparagraphs) + local box = getbox("strutbox") + local w, h, d = getwhd(box) + local t = { + p = true, + c = true, + r = true, + x = true, + y = true, + h = h, + d = d, + hs = texget("hsize"), -- never 0 + } + local leftskip = texget("leftskip",false) + local rightskip = texget("rightskip",false) + local hangindent = texget("hangindent") + local hangafter = texget("hangafter") + local parindent = texget("parindent") + local parshape = texget("parshape") + if leftskip ~= 0 then + t.ls = leftskip + end + if rightskip ~= 0 then + t.rs = rightskip + end + if hangindent ~= 0 then + t.hi = hangindent + end + if hangafter ~= 1 and hangafter ~= 0 then -- can not be zero .. so it needs to be 1 if zero + t.ha = hangafter + end + if parindent ~= 0 then + t.pi = parindent + end + if parshape and #parshape > 0 then + t.ps = parshape + end + local name = f_p_tag(nofparagraphs) + tobesaved[name] = t + ctx_latelua { action = enhance, specification = t } + end +} + +implement { + name = "dosetposition", + arguments = "argument", + public = true, + protected = true, + actions = function(name) + local spec = { + p = true, + c = column, + r = true, + x = true, + y = true, + n = nofparagraphs > 0 and nofparagraphs or nil, + r2l = texgetinteger("inlinelefttoright") == 1 or nil, + } + tobesaved[name] = spec + ctx_latelua { action = enhance, specification = spec } + end +} + +implement { + name = "dosetpositionwhd", + arguments = { "argument", "dimenargument", "dimenargument", "dimenargument" }, + public = true, + protected = true, + actions = function(name,w,h,d) + local spec = { + p = true, + c = column, + r = true, + x = true, + y = true, + w = w ~= 0 and w or nil, + h = h ~= 0 and h or nil, + d = d ~= 0 and d or nil, + n = nofparagraphs > 0 and nofparagraphs or nil, + r2l = texgetinteger("inlinelefttoright") == 1 or nil, + } + tobesaved[name] = spec + ctx_latelua { action = enhance, specification = spec } + end +} + +implement { + name = "dosetpositionbox", + arguments = { "argument", "integerargument" }, + public = true, + protected = true, + actions = function(name,n) + local box = getbox(n) + local w, h, d = getwhd(box) + local spec = { + p = true, + c = column, + r = true, + x = true, + y = true, + w = w ~= 0 and w or nil, + h = h ~= 0 and h or nil, + d = d ~= 0 and d or nil, + n = nofparagraphs > 0 and nofparagraphs or nil, + r2l = texgetinteger("inlinelefttoright") == 1 or nil, + } + tobesaved[name] = spec + ctx_latelua { action = enhance, specification = spec } + end +} + +implement { + name = "dosetpositionplus", + arguments = { "argument", "dimenargument", "dimenargument", "dimenargument" }, + public = true, + protected = true, + actions = function(name,w,h,d) + local spec = { + p = true, + c = column, + r = true, + x = true, + y = true, + w = w ~= 0 and w or nil, + h = h ~= 0 and h or nil, + d = d ~= 0 and d or nil, + n = nofparagraphs > 0 and nofparagraphs or nil, + e = scanstring(), + r2l = texgetinteger("inlinelefttoright") == 1 or nil, + } + tobesaved[name] = spec + ctx_latelua { action = enhance, specification = spec } + end +} + +implement { + name = "dosetpositionstrut", + arguments = "argument", + public = true, + protected = true, + actions = function(name) + local box = getbox("strutbox") + local w, h, d = getwhd(box) + local spec = { + p = true, + c = column, + r = true, + x = true, + y = true, + h = h ~= 0 and h or nil, + d = d ~= 0 and d or nil, + n = nofparagraphs > 0 and nofparagraphs or nil, + r2l = texgetinteger("inlinelefttoright") == 1 or nil, + } + tobesaved[name] = spec + ctx_latelua { action = enhance, specification = spec } + end +} + +implement { + name = "dosetpositionstrutkind", + arguments = { "argument", "integerargument" }, + public = true, + protected = true, + actions = function(name,kind) + local box = getbox("strutbox") + local w, h, d = getwhd(box) + local spec = { + k = kind, + p = true, + c = column, + r = true, + x = true, + y = true, + h = h ~= 0 and h or nil, + d = d ~= 0 and d or nil, + n = nofparagraphs > 0 and nofparagraphs or nil, + r2l = texgetinteger("inlinelefttoright") == 1 or nil, + } + tobesaved[name] = spec + ctx_latelua { action = enhance, specification = spec } + end +} + +function jobpositions.getreserved(tag,n) + if tag == v_column then + local fulltag = f_tag_three(tag,texgetcount("realpageno"),n or 1) + local data = collected[fulltag] + if data then + return data, fulltag + end + tag = v_text + end + if tag == v_text then + local fulltag = f_tag_two(tag,texgetcount("realpageno")) + return collected[fulltag] or false, fulltag + end + return collected[tag] or false, tag +end + +function jobpositions.copy(target,source) + collected[target] = collected[source] +end + +function jobpositions.replace(id,p,x,y,w,h,d) + collected[id] = { p = p, x = x, y = y, w = w, h = h, d = d } -- c g +end + +local function getpage(id) + local jpi = collected[id] + return jpi and jpi.p +end + +local function getcolumn(id) + local jpi = collected[id] + return jpi and jpi.c or false +end + +local function getparagraph(id) + local jpi = collected[id] + return jpi and jpi.n +end + +local function getregion(id) + local jpi = collected[id] + if jpi then + local r = jpi.r + if r then + return r + end + local p = jpi.p + if p then + return "page:" .. p + end + end + return false +end + +jobpositions.page = getpage +jobpositions.column = getcolumn +jobpositions.paragraph = getparagraph +jobpositions.region = getregion + +jobpositions.p = getpage -- not used, kind of obsolete +jobpositions.c = getcolumn -- idem +jobpositions.n = getparagraph -- idem +jobpositions.r = getregion -- idem + +function jobpositions.x(id) + local jpi = collected[id] + return jpi and jpi.x +end + +function jobpositions.y(id) + local jpi = collected[id] + return jpi and jpi.y +end + +function jobpositions.width(id) + local jpi = collected[id] + return jpi and jpi.w +end + +function jobpositions.height(id) + local jpi = collected[id] + return jpi and jpi.h +end + +function jobpositions.depth(id) + local jpi = collected[id] + return jpi and jpi.d +end + +function jobpositions.whd(id) + local jpi = collected[id] + if jpi then + return jpi.h, jpi.h, jpi.d + end +end + +function jobpositions.leftskip(id) + local jpi = collected[id] + return jpi and jpi.ls +end + +function jobpositions.rightskip(id) + local jpi = collected[id] + return jpi and jpi.rs +end + +function jobpositions.hsize(id) + local jpi = collected[id] + return jpi and jpi.hs +end + +function jobpositions.parindent(id) + local jpi = collected[id] + return jpi and jpi.pi +end + +function jobpositions.hangindent(id) + local jpi = collected[id] + return jpi and jpi.hi +end + +function jobpositions.hangafter(id) + local jpi = collected[id] + return jpi and jpi.ha or 1 +end + +function jobpositions.xy(id) + local jpi = collected[id] + if jpi then + return jpi.x, jpi.y + else + return 0, 0 + end +end + +function jobpositions.lowerleft(id) + local jpi = collected[id] + if jpi then + return jpi.x, jpi.y - jpi.d + else + return 0, 0 + end +end + +function jobpositions.lowerright(id) + local jpi = collected[id] + if jpi then + return jpi.x + jpi.w, jpi.y - jpi.d + else + return 0, 0 + end +end + +function jobpositions.upperright(id) + local jpi = collected[id] + if jpi then + return jpi.x + jpi.w, jpi.y + jpi.h + else + return 0, 0 + end +end + +function jobpositions.upperleft(id) + local jpi = collected[id] + if jpi then + return jpi.x, jpi.y + jpi.h + else + return 0, 0 + end +end + +function jobpositions.position(id) + local jpi = collected[id] + if jpi then + return jpi.p, jpi.x, jpi.y, jpi.w, jpi.h, jpi.d + else + return 0, 0, 0, 0, 0, 0 + end +end + +local splitter = lpeg.splitat(",") + +function jobpositions.extra(id,n,default) -- assume numbers + local jpi = collected[id] + if jpi then + local e = jpi.e + if e then + local split = jpi.split + if not split then + split = lpegmatch(splitter,jpi.e) + jpi.split = split + end + return texsp(split[n]) or default -- watch the texsp here + end + end + return default +end + +local function overlapping(one,two,overlappingmargin) -- hm, strings so this is wrong .. texsp + one = collected[one] + two = collected[two] + if one and two and one.p == two.p then + if not overlappingmargin then + overlappingmargin = 2 + end + local x_one = one.x + local x_two = two.x + local w_two = two.w + local llx_one = x_one - overlappingmargin + local urx_two = x_two + w_two + overlappingmargin + if llx_one > urx_two then + return false + end + local w_one = one.w + local urx_one = x_one + w_one + overlappingmargin + local llx_two = x_two - overlappingmargin + if urx_one < llx_two then + return false + end + local y_one = one.y + local y_two = two.y + local d_one = one.d + local h_two = two.h + local lly_one = y_one - d_one - overlappingmargin + local ury_two = y_two + h_two + overlappingmargin + if lly_one > ury_two then + return false + end + local h_one = one.h + local d_two = two.d + local ury_one = y_one + h_one + overlappingmargin + local lly_two = y_two - d_two - overlappingmargin + if ury_one < lly_two then + return false + end + return true + end +end + +local function onsamepage(list,page) + for id in gmatch(list,"(, )") do + local jpi = collected[id] + if jpi then + local p = jpi.p + if not p then + return false + elseif not page then + page = p + elseif page ~= p then + return false + end + end + end + return page +end + +local function columnofpos(realpage,xposition) + local p = columndata[realpage] + if p then + for i=1,#p do + local c = p[i] + local x = c.x or 0 + local w = c.w or 0 + if xposition >= x and xposition <= (x + w) then + return i + end + end + end + return 1 +end + +jobpositions.overlapping = overlapping +jobpositions.onsamepage = onsamepage +jobpositions.columnofpos = columnofpos + +-- interface + +implement { + name = "replacepospxywhd", + arguments = { "argument", "integerargument", "dimenargument", "dimenargument", "dimenargument", "dimenargument", "dimenargument" }, + public = true, + protected = true, + actions = function(name,page,x,y,w,h,d) + collected[name] = { + p = page, + x = x, + y = y, + w = w, + h = h, + d = d, + } + end +} + +implement { + name = "copyposition", + arguments = "2 arguments", + public = true, + protected = true, + actions = function(target,source) + collected[target] = collected[source] + end +} + +implement { + name = "MPp", + arguments = "argument", + public = true, + actions = function(name) + local jpi = collected[name] + if jpi then + local p = jpi.p + if p and p ~= true then + context(p) + return + end + end + context('0') + end +} + +implement { + name = "MPx", + arguments = "argument", + public = true, + actions = function(name) + local jpi = collected[name] + if jpi then + local x = jpi.x + if x and x ~= true and x ~= 0 then + context("%.5Fpt",x*pt) + return + end + end + context('0pt') + end +} + +implement { + name = "MPy", + arguments = "argument", + public = true, + actions = function(name) + local jpi = collected[name] + if jpi then + local y = jpi.y + if y and y ~= true and y ~= 0 then + context("%.5Fpt",y*pt) + return + end + end + context('0pt') + end +} + +implement { + name = "MPw", + arguments = "argument", + public = true, + actions = function(name) + local jpi = collected[name] + if jpi then + local w = jpi.w + if w and w ~= 0 then + context("%.5Fpt",w*pt) + return + end + end + context('0pt') + end +} + +implement { + name = "MPh", + arguments = "argument", + public = true, + actions = function(name) + local jpi = collected[name] + if jpi then + local h = jpi.h + if h and h ~= 0 then + context("%.5Fpt",h*pt) + return + end + end + context('0pt') + end +} + +implement { + name = "MPd", + arguments = "argument", + public = true, + actions = function(name) + local jpi = collected[name] + if jpi then + local d = jpi.d + if d and d ~= 0 then + context("%.5Fpt",d*pt) + return + end + end + context('0pt') + end +} + +implement { + name = "MPxy", + arguments = "argument", + public = true, + actions = function(name) + local jpi = collected[name] + if jpi then + context('(%.5Fpt,%.5Fpt)', + jpi.x*pt, + jpi.y*pt + ) + else + context('(0,0)') + end + end +} + +implement { + name = "MPwhd", + arguments = "argument", + public = true, + actions = function(name) + local jpi = collected[name] + if jpi then + local w = jpi.w or 0 + local h = jpi.h or 0 + local d = jpi.d or 0 + if w ~= 0 or h ~= 0 or d ~= 0 then + context("%.5Fpt,%.5Fpt,%.5Fpt",w*pt,h*pt,d*pt) + return + end + end + context('0pt,0pt,0pt') + end +} + +implement { + name = "MPll", + arguments = "argument", + public = true, + actions = function(name) + local jpi = collected[name] + if jpi then + context('(%.5Fpt,%.5Fpt)', + jpi.x *pt, + (jpi.y-jpi.d)*pt + ) + else + context('(0,0)') -- for mp only + end + end +} + +implement { + name = "MPlr", + arguments = "argument", + public = true, + actions = function(name) + local jpi = collected[name] + if jpi then + context('(%.5Fpt,%.5Fpt)', + (jpi.x + jpi.w)*pt, + (jpi.y - jpi.d)*pt + ) + else + context('(0,0)') -- for mp only + end + end +} + +implement { + name = "MPur", + arguments = "argument", + public = true, + actions = function(name) + local jpi = collected[name] + if jpi then + context('(%.5Fpt,%.5Fpt)', + (jpi.x + jpi.w)*pt, + (jpi.y + jpi.h)*pt + ) + else + context('(0,0)') -- for mp only + end + end +} + +implement { + name = "MPul", + arguments = "argument", + public = true, + actions = function(name) + local jpi = collected[name] + if jpi then + context('(%.5Fpt,%.5Fpt)', + jpi.x *pt, + (jpi.y + jpi.h)*pt + ) + else + context('(0,0)') -- for mp only + end + end +} + +local function MPpos(id) + local jpi = collected[id] + if jpi then + local p = jpi.p + if p then + context("%s,%.5Fpt,%.5Fpt,%.5Fpt,%.5Fpt,%.5Fpt", + p, + jpi.x*pt, + jpi.y*pt, + jpi.w*pt, + jpi.h*pt, + jpi.d*pt + ) + return + end + end + context('0,0,0,0,0,0') -- for mp only +end + +implement { + name = "MPpos", + arguments = "argument", + public = true, + actions = MPpos +} + +implement { + name = "MPn", + arguments = "argument", + public = true, + actions = function(name) + local jpi = collected[name] + if jpi then + local n = jpi.n + if n then + context(n) + return + end + end + context(0) + end +} + +implement { + name = "MPc", + arguments = "argument", + public = true, + actions = function(name) + local jpi = collected[name] + if jpi then + local c = jpi.c + if c and c ~= true then + context(c) + return + end + end + context('0') -- okay ? + end +} + +implement { + name = "MPr", + arguments = "argument", + public = true, + actions = function(name) + local jpi = collected[name] + if jpi then + local r = jpi.r + if r and r ~= true then + context(r) + return + end + local p = jpi.p + if p and p ~= true then + context("page:" .. p) + end + end + end +} + +local function MPpardata(id) + local t = collected[id] + if not t then + local tag = f_p_tag(id) + t = collected[tag] + end + if t then + context("%.5Fpt,%.5Fpt,%.5Fpt,%.5Fpt,%s,%.5Fpt", + t.hs*pt, + t.ls*pt, + t.rs*pt, + t.hi*pt, + t.ha, + t.pi*pt + ) + else + context("0,0,0,0,0,0") -- for mp only + end +end + +implement { + name = "MPpardata", + arguments = "argument", + public = true, + actions = MPpardata +} + +implement { + name = "MPposset", + arguments = "argument", + public = true, + actions = function(name) + local b = f_b_tag(name) + local e = f_e_tag(name) + local w = f_w_tag(name) + local p = f_p_tag(getparagraph(b)) + MPpos(b) context(",") MPpos(e) context(",") MPpos(w) context(",") MPpos(p) context(",") MPpardata(p) + end +} + +implement { + name = "MPls", + arguments = "argument", + public = true, + actions = function(name) + local jpi = collected[name] + if jpi then + context("%.5Fpt",jpi.ls*pt) + else + context("0pt") + end + end +} + +implement { + name = "MPrs", + arguments = "argument", + public = true, + actions = function(name) + local jpi = collected[name] + if jpi then + context("%.5Fpt",jpi.rs*pt) + else + context("0pt") + end + end +} + +local splitter = lpeg.tsplitat(",") + +implement { + name = "MPplus", + arguments = { "argument", "integerargument", "argument" }, + public = true, + actions = function(name,n,default) + local jpi = collected[name] + if jpi then + local e = jpi.e + if e then + local split = jpi.split + if not split then + split = lpegmatch(splitter,jpi.e) + jpi.split = split + end + context(split[n] or default) + return + end + end + context(default) + end +} + +implement { + name = "MPrest", + arguments = { "argument", "argument" }, + public = true, + actions = function(name,default) + local jpi = collected[name] + context(jpi and jpi.e or default) + end +} + +implement { + name = "MPxywhd", + arguments = "argument", + public = true, + actions = function(name) + local jpi = collected[name] + if jpi then + context("%.5Fpt,%.5Fpt,%.5Fpt,%.5Fpt,%.5Fpt", + jpi.x*pt, + jpi.y*pt, + jpi.w*pt, + jpi.h*pt, + jpi.d*pt + ) + else + context("0,0,0,0,0") -- for mp only + end + end +} + +local doif = commands.doif +local doifelse = commands.doifelse + +implement { + name = "doifelseposition", + arguments = "argument", + public = true, + protected = true, + actions = function(name) + doifelse(collected[name]) + end +} + +implement { + name = "doifposition", + arguments = "argument", + public = true, + protected = true, + actions = function(name) + doif(collected[name]) + end +} + +implement { + name = "doifelsepositiononpage", + arguments = { "string", "integerargument" }, + public = true, + protected = true, + actions = function(name,p) + local c = collected[name] + doifelse(c and c.p == p) + end +} + +implement { + name = "doifelseoverlapping", + arguments = { "argument", "argument" }, + public = true, + protected = true, + actions = function(one,two) + doifelse(overlapping(one,two)) + end +} + +implement { + name = "doifelsepositionsonsamepage", + arguments = "argument", -- string + public = true, + protected = true, + actions = function(list) + doifelse(onsamepage(list)) + end +} + +implement { + name = "doifelsepositionsonthispage", + arguments = "argument", -- string + public = true, + protected = true, + actions = function(list) + doifelse(onsamepage(list,tostring(texgetcount("realpageno")))) + end +} + +implement { + name = "doifelsepositionsused", + public = true, + protected = true, + actions = function() + doifelse(next(collected)) + end +} + +implement { + name = "markregionbox", + arguments = "integer", + actions = markregionbox +} + +implement { + name = "setregionbox", + arguments = "integer", + actions = setregionbox +} + +implement { + name = "markregionboxtagged", + arguments = { "integer", "string" }, + actions = markregionbox +} + +implement { + name = "markregionboxtaggedn", + arguments = { "integer", "string", "integer" }, + actions = function(box,tag,n) + markregionbox(box,tag,nil,nil,nil,nil,nil,nil,n) + end +} + +implement { + name = "setregionboxtagged", + arguments = { "integer", "string" }, + actions = setregionbox +} + +implement { + name = "markregionboxcorrected", + arguments = { "integer", "string", true }, + actions = markregionbox +} + +implement { + name = "markregionboxtaggedkind", + arguments = { "integer", "string", "integer", "dimen", "dimen", "dimen", "dimen" }, + actions = function(box,tag,n,d1,d2,d3,d4) + markregionbox(box,tag,nil,n,d1,d2,d3,d4) + end +} + +implement { + name = "reservedautoregiontag", + public = true, + actions = function() + nofregions = nofregions + 1 + context(f_region(nofregions)) + end +} + +-- statistics (at least for the moment, when testing) + +-- statistics.register("positions", function() +-- local total = nofregular + nofusedregions + nofmissingregions +-- if total > 0 then +-- return format("%s collected, %s regulars, %s regions, %s unresolved regions", +-- total, nofregular, nofusedregions, nofmissingregions) +-- else +-- return nil +-- end +-- end) + +statistics.register("positions", function() + local total = nofregular + nofspecial + if total > 0 then + return format("%s collected, %s regular, %s special",total,nofregular,nofspecial) + else + return nil + end +end) + +-- We support the low level positional commands too: + +local newsavepos = nodes.pool.savepos + +implement { name = "savepos", actions = function() context(newsavepos()) end } +implement { name = "lastxpos", actions = function() context(gethpos()) end } +implement { name = "lastypos", actions = function() context(getvpos()) end } |