diff options
author | Marius <mariausol@gmail.com> | 2013-05-19 20:40:34 +0300 |
---|---|---|
committer | Marius <mariausol@gmail.com> | 2013-05-19 20:40:34 +0300 |
commit | 13ec4b540e0d46c97fd7b089e0b7413da81e0a9f (patch) | |
tree | bebfa563a17c06b3bd3bf8f6f4ba6d025e00d107 /tex/context/base/anch-pos.lua | |
parent | 69ad13650cda027526271179e95b5294694143a1 (diff) | |
download | context-13ec4b540e0d46c97fd7b089e0b7413da81e0a9f.tar.gz |
beta 2013.05.19 19:27
Diffstat (limited to 'tex/context/base/anch-pos.lua')
-rw-r--r-- | tex/context/base/anch-pos.lua | 2072 |
1 files changed, 1036 insertions, 1036 deletions
diff --git a/tex/context/base/anch-pos.lua b/tex/context/base/anch-pos.lua index 2697cecf4..c94fd60a0 100644 --- a/tex/context/base/anch-pos.lua +++ b/tex/context/base/anch-pos.lua @@ -1,1036 +1,1036 @@ -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 - -local commands, context = commands, context - -local tostring, next, rawget, setmetatable = tostring, next, rawget, setmetatable -local sort = table.sort -local format, gmatch, match = string.format, string.gmatch, string.match -local rawget = rawget -local lpegmatch = lpeg.match -local insert, remove = table.insert, table.remove -local allocate, mark = utilities.storage.allocate, utilities.storage.mark -local texsp, texcount, texbox, texdimen, texsetcount = tex.sp, tex.count, tex.box, tex.dimen, tex.setcount ------ texsp = string.todimen -- because we cache this is much faster but no rounding - -local pdf = pdf -- h and v are variables - -local setmetatableindex = table.setmetatableindex -local new_latelua = nodes.pool.latelua -local find_tail = node.slide - -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 - -_plib_ = jobpositions -- might go - -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 - } -} - -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_b_column = formatters["_plib_.b_col(%q)"] -local f_e_column = formatters["_plib_.e_col()"] - -local f_enhance = formatters["_plib_.enhance(%q)"] -local f_region = formatters["region:%s"] - -local f_b_region = formatters["_plib_.b_region(%q)"] -local f_e_region = formatters["_plib_.e_region(%s)"] - -local f_tag_three = formatters["%s:%s:%s"] -local f_tag_two = formatters["%s:%s"] - -local function sorter(a,b) - return a.y > b.y -end - -local nofusedregions = 0 -local nofmissingregions = 0 -local nofregular = 0 - --- todo: register subsets and count them indepently - -local function initializer() - tobesaved = jobpositions.tobesaved - collected = jobpositions.collected - -- enhance regions with paragraphs - for tag, data in next, collected do - local region = data.r - if region then - local r = collected[region] - if r then - local paragraphs = r.paragraphs - if not paragraphs then - r.paragraphs = { data } - else - paragraphs[#paragraphs+1] = data - end - nofusedregions = nofusedregions + 1 - else - nofmissingregions = nofmissingregions + 1 - end - else - nofregular = nofregular + 1 - end - setmetatable(data,default) - end - -- add metatable - -- for tag, data in next, collected do - -- setmetatable(data,default) - -- end - -- sort this data - for tag, data in next, collected do - local region = data.r - if region then - local r = collected[region] - if r then - local paragraphs = r.paragraphs - if paragraphs and #paragraphs > 1 then - sort(paragraphs,sorter) - end - end - end - -- so, we can be sparse and don't need 'or 0' code - end -end - -job.register('job.positions.collected', tobesaved, initializer) - -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 function setdim(name,w,h,d,extra) -- will be used when we move to sp allover - local x = pdf.h - local y = pdf.v - if x == 0 then x = nil end - if y == 0 then y = nil end - if w == 0 then w = nil end - if h == 0 then h = nil end - if d == 0 then d = nil end - if extra == "" then extra = nil end - -- todo: sparse - tobesaved[name] = { - p = texcount.realpageno, - x = x, - y = y, - w = w, - h = h, - d = d, - e = extra, - r = region, - c = column, - } -end - -local function setall(name,p,x,y,w,h,d,extra) - if x == 0 then x = nil end - if y == 0 then y = nil end - if w == 0 then w = nil end - if h == 0 then h = nil end - if d == 0 then d = nil end - if extra == "" then extra = nil end - -- todo: sparse - tobesaved[name] = { - p = p, - x = x, - y = y, - w = w, - h = h, - d = d, - e = extra, - r = region, - c = column, - } -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 - data.x = pdf.h - end - if data.y == true then - data.y = pdf.v - end - if data.p == true then - data.p = texcount.realpageno - 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 - -local function set(name,index,val) - local data = enhance(val or index) - if val 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 - -jobpositions.setdim = setdim -jobpositions.setall = setall -jobpositions.set = set -jobpositions.get = get - -commands.setpos = setall - --- will become private table (could also become attribute driven but too nasty --- as attributes can bleed e.g. in margin stuff) - -function jobpositions.b_col(tag) - tobesaved[tag] = { - r = true, - x = pdf.h, - w = 0, - } - insert(columns,tag) - column = tag -end - -function jobpositions.e_col(tag) - local t = tobesaved[column] - if not t then - -- something's wrong - else - t.w = pdf.h - t.x - t.r = region - end - remove(columns) - column = columns[#columns] -end - -function commands.bcolumn(tag,register) - insert(columns,tag) - column = tag - if register then - context(new_latelua(f_b_column(tag))) - end -end - -function commands.ecolumn(register) - if register then - context(new_latelua(f_e_column())) - end - remove(columns) - column = columns[#columns] -end - --- regions - -function jobpositions.b_region(tag) - local last = tobesaved[tag] - last.x = pdf.h -last.y = pdf.v - last.p = texcount.realpageno - insert(regions,tag) - region = tag -end - -function jobpositions.e_region(correct) - local last = tobesaved[region] -if correct then - last.h = last.y - pdf.v -end - last.y = pdf.v - remove(regions) - region = regions[#regions] -end - -function jobpositions.markregionbox(n,tag,correct) - if not tag or tag == "" then - nofregions = nofregions + 1 - tag = f_region(nofregions) - end - local box = texbox[n] - local w = box.width - local h = box.height - local d = box.depth - tobesaved[tag] = { - p = true, - x = true, - y = pdf.v, -- true, - w = w ~= 0 and w or nil, - h = h ~= 0 and h or nil, - d = d ~= 0 and d or nil, - } - local push = new_latelua(f_b_region(tag)) - local pop = new_latelua(f_e_region(tostring(correct))) -- todo: check if tostring is needed with formatter - -- maybe we should construct a hbox first (needs experimenting) so that we can avoid some at the tex end - local head = box.list - if head then - local tail = find_tail(head) - head.prev = push - push.next = head - pop .prev = tail - tail.next = pop - else -- we can have a simple push/pop - push.next = pop - pop.prev = push - end - box.list = push -end - -function jobpositions.enhance(name) - enhance(tobesaved[name]) -end - -function commands.pos(name,t) - tobesaved[name] = t - context(new_latelua(f_enhance(name))) -end - -local nofparagraphs = 0 - -function commands.parpos() -- todo: relate to localpar (so this is an intermediate variant) - nofparagraphs = nofparagraphs + 1 - texsetcount("global","c_anch_positions_paragraph",nofparagraphs) - local strutbox = texbox.strutbox - local t = { - p = true, - c = true, - r = true, - x = true, - y = true, - h = strutbox.height, - d = strutbox.depth, - hs = tex.hsize, - } - local leftskip = tex.leftskip.width - local rightskip = tex.rightskip.width - local hangindent = tex.hangindent - local hangafter = tex.hangafter - local parindent = tex.parindent - local parshape = tex.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 tag = f_p_tag(nofparagraphs) - tobesaved[tag] = t - context(new_latelua(f_enhance(tag))) -end - -function commands.posxy(name) -- can node.write be used here? - tobesaved[name] = { - p = true, - c = column, - r = true, - x = true, - y = true, - n = nofparagraphs > 0 and nofparagraphs or nil, - } - context(new_latelua(f_enhance(name))) -end - -function commands.poswhd(name,w,h,d) - tobesaved[name] = { - p = true, - c = column, - r = true, - x = true, - y = true, - w = w, - h = h, - d = d, - n = nofparagraphs > 0 and nofparagraphs or nil, - } - context(new_latelua(f_enhance(name))) -end - -function commands.posplus(name,w,h,d,extra) - tobesaved[name] = { - p = true, - c = column, - r = true, - x = true, - y = true, - w = w, - h = h, - d = d, - n = nofparagraphs > 0 and nofparagraphs or nil, - e = extra, - } - context(new_latelua(f_enhance(name))) -end - -function commands.posstrut(name,w,h,d) - local strutbox = texbox.strutbox - tobesaved[name] = { - p = true, - c = column, - r = true, - x = true, - y = true, - h = strutbox.height, - d = strutbox.depth, - n = nofparagraphs > 0 and nofparagraphs or nil, - } - context(new_latelua(f_enhance(name))) -end - -function jobpositions.getreserved(tag,n) - if tag == v_column then - local fulltag = f_tag_three(tag,texcount.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,texcount.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 - -function jobpositions.page(id) - local jpi = collected[id] - return jpi and jpi.p -end - -function jobpositions.region(id) - local jpi = collected[id] - return jpi and jpi.r or false -end - -function jobpositions.column(id) - local jpi = collected[id] - return jpi and jpi.c or false -end - -function jobpositions.paragraph(id) - local jpi = collected[id] - return jpi and jpi.n -end - -jobpositions.p = jobpositions.page -jobpositions.r = jobpositions.region -jobpositions.c = jobpositions.column -jobpositions.n = jobpositions.paragraph - -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.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 - -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 - -jobpositions.overlapping = overlapping -jobpositions.onsamepage = onsamepage - --- interface - -commands.replacepospxywhd = jobpositions.replace -commands.copyposition = jobpositions.copy - -function commands.MPp(id) - local jpi = collected[id] - if jpi then - local p = jpi.p - if p and p ~= true then - context(p) - return - end - end - context('0') -end - -function commands.MPx(id) - local jpi = collected[id] - 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 - -function commands.MPy(id) - local jpi = collected[id] - 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 - -function commands.MPw(id) - local jpi = collected[id] - if jpi then - local w = jpi.w - if w and w ~= 0 then - context("%.5fpt",w*pt) - return - end - end - context('0pt') -end - -function commands.MPh(id) - local jpi = collected[id] - if jpi then - local h = jpi.h - if h and h ~= 0 then - context("%.5fpt",h*pt) - return - end - end - context('0pt') -end - -function commands.MPd(id) - local jpi = collected[id] - if jpi then - local d = jpi.d - if d and d ~= 0 then - context("%.5fpt",d*pt) - return - end - end - context('0pt') -end - -function commands.MPxy(id) - local jpi = collected[id] - if jpi then - context('(%.5fpt,%.5fpt)', - jpi.x*pt, - jpi.y*pt - ) - else - context('(0,0)') - end -end - -function commands.MPll(id) - local jpi = collected[id] - if jpi then - context('(%.5fpt,%.5fpt)', - jpi.x *pt, - (jpi.y-jpi.d)*pt - ) - else - context('(0,0)') -- for mp only - end -end - -function commands.MPlr(id) - local jpi = collected[id] - 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 - -function commands.MPur(id) - local jpi = collected[id] - 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 - -function commands.MPul(id) - local jpi = collected[id] - 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 - -commands.MPpos = MPpos - -function commands.MPn(id) - local jpi = collected[id] - if jpi then - local n = jpi.n - if n then - context(n) - return - end - end - context(0) -end - -function commands.MPc(id) - local jpi = collected[id] - if jpi then - local c = jpi.c - if c and p ~= true then - context(c) - return - end - end - context(c) -- number -end - -function commands.MPr(id) - local jpi = collected[id] - if jpi then - local r = jpi.r - if r and p ~= true then - context(r) - return - end - end -end - -local function MPpardata(n) - local t = collected[n] - if not t then - local tag = f_p_tag(n) - 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 - -commands.MPpardata = MPpardata - -function commands.MPposset(id) -- special helper, used in backgrounds - local b = f_b_tag(id) - local e = f_e_tag(id) - local w = f_w_tag(id) - local p = f_p_tag(jobpositions.n(b)) - MPpos(b) context(",") MPpos(e) context(",") MPpos(w) context(",") MPpos(p) context(",") MPpardata(p) -end - -function commands.MPls(id) - local t = collected[id] - if t then - context("%.5fpt",t.ls*pt) - else - context("0pt") - end -end - -function commands.MPrs(id) - local t = collected[id] - if t then - context("%.5fpt",t.rs*pt) - else - context("0pt") - end -end - -local splitter = lpeg.tsplitat(",") - -function commands.MPplus(id,n,default) - 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 - context(split[n] or default) - return - end - end - context(default) -end - -function commands.MPrest(id,default) - local jpi = collected[id] - context(jpi and jpi.e or default) -end - -function commands.MPxywhd(id) - local t = collected[id] - if t then - context("%.5fpt,%.5fpt,%.5fpt,%.5fpt,%.5fpt", - t.x*pt, - t.y*pt, - t.w*pt, - t.h*pt, - t.d*pt - ) - else - context("0,0,0,0,0") -- for mp only - end -end - -local doif, doifelse = commands.doif, commands.doifelse - -function commands.doifpositionelse(name) - doifelse(collected[name]) -end - -function commands.doifposition(name) - doif(collected[name]) -end - -function commands.doifpositiononpage(name,page) -- probably always realpageno - local c = collected[name] - doifelse(c and c.p == page) -end - -function commands.doifoverlappingelse(one,two,overlappingmargin) - doifelse(overlapping(one,two,overlappingmargin)) -end - -function commands.doifpositionsonsamepageelse(list,page) - doifelse(onsamepage(list)) -end - -function commands.doifpositionsonthispageelse(list) - doifelse(onsamepage(list,tostring(tex.count.realpageno))) -end - -function commands.doifelsepositionsused() - doifelse(next(collected)) -end - -commands.markcolumnbox = jobpositions.markcolumnbox -commands.markregionbox = jobpositions.markregionbox - --- 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) +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
+
+local commands, context = commands, context
+
+local tostring, next, rawget, setmetatable = tostring, next, rawget, setmetatable
+local sort = table.sort
+local format, gmatch, match = string.format, string.gmatch, string.match
+local rawget = rawget
+local lpegmatch = lpeg.match
+local insert, remove = table.insert, table.remove
+local allocate, mark = utilities.storage.allocate, utilities.storage.mark
+local texsp, texcount, texbox, texdimen, texsetcount = tex.sp, tex.count, tex.box, tex.dimen, tex.setcount
+----- texsp = string.todimen -- because we cache this is much faster but no rounding
+
+local pdf = pdf -- h and v are variables
+
+local setmetatableindex = table.setmetatableindex
+local new_latelua = nodes.pool.latelua
+local find_tail = node.slide
+
+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
+
+_plib_ = jobpositions -- might go
+
+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
+ }
+}
+
+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_b_column = formatters["_plib_.b_col(%q)"]
+local f_e_column = formatters["_plib_.e_col()"]
+
+local f_enhance = formatters["_plib_.enhance(%q)"]
+local f_region = formatters["region:%s"]
+
+local f_b_region = formatters["_plib_.b_region(%q)"]
+local f_e_region = formatters["_plib_.e_region(%s)"]
+
+local f_tag_three = formatters["%s:%s:%s"]
+local f_tag_two = formatters["%s:%s"]
+
+local function sorter(a,b)
+ return a.y > b.y
+end
+
+local nofusedregions = 0
+local nofmissingregions = 0
+local nofregular = 0
+
+-- todo: register subsets and count them indepently
+
+local function initializer()
+ tobesaved = jobpositions.tobesaved
+ collected = jobpositions.collected
+ -- enhance regions with paragraphs
+ for tag, data in next, collected do
+ local region = data.r
+ if region then
+ local r = collected[region]
+ if r then
+ local paragraphs = r.paragraphs
+ if not paragraphs then
+ r.paragraphs = { data }
+ else
+ paragraphs[#paragraphs+1] = data
+ end
+ nofusedregions = nofusedregions + 1
+ else
+ nofmissingregions = nofmissingregions + 1
+ end
+ else
+ nofregular = nofregular + 1
+ end
+ setmetatable(data,default)
+ end
+ -- add metatable
+ -- for tag, data in next, collected do
+ -- setmetatable(data,default)
+ -- end
+ -- sort this data
+ for tag, data in next, collected do
+ local region = data.r
+ if region then
+ local r = collected[region]
+ if r then
+ local paragraphs = r.paragraphs
+ if paragraphs and #paragraphs > 1 then
+ sort(paragraphs,sorter)
+ end
+ end
+ end
+ -- so, we can be sparse and don't need 'or 0' code
+ end
+end
+
+job.register('job.positions.collected', tobesaved, initializer)
+
+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 function setdim(name,w,h,d,extra) -- will be used when we move to sp allover
+ local x = pdf.h
+ local y = pdf.v
+ if x == 0 then x = nil end
+ if y == 0 then y = nil end
+ if w == 0 then w = nil end
+ if h == 0 then h = nil end
+ if d == 0 then d = nil end
+ if extra == "" then extra = nil end
+ -- todo: sparse
+ tobesaved[name] = {
+ p = texcount.realpageno,
+ x = x,
+ y = y,
+ w = w,
+ h = h,
+ d = d,
+ e = extra,
+ r = region,
+ c = column,
+ }
+end
+
+local function setall(name,p,x,y,w,h,d,extra)
+ if x == 0 then x = nil end
+ if y == 0 then y = nil end
+ if w == 0 then w = nil end
+ if h == 0 then h = nil end
+ if d == 0 then d = nil end
+ if extra == "" then extra = nil end
+ -- todo: sparse
+ tobesaved[name] = {
+ p = p,
+ x = x,
+ y = y,
+ w = w,
+ h = h,
+ d = d,
+ e = extra,
+ r = region,
+ c = column,
+ }
+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
+ data.x = pdf.h
+ end
+ if data.y == true then
+ data.y = pdf.v
+ end
+ if data.p == true then
+ data.p = texcount.realpageno
+ 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
+
+local function set(name,index,val)
+ local data = enhance(val or index)
+ if val 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
+
+jobpositions.setdim = setdim
+jobpositions.setall = setall
+jobpositions.set = set
+jobpositions.get = get
+
+commands.setpos = setall
+
+-- will become private table (could also become attribute driven but too nasty
+-- as attributes can bleed e.g. in margin stuff)
+
+function jobpositions.b_col(tag)
+ tobesaved[tag] = {
+ r = true,
+ x = pdf.h,
+ w = 0,
+ }
+ insert(columns,tag)
+ column = tag
+end
+
+function jobpositions.e_col(tag)
+ local t = tobesaved[column]
+ if not t then
+ -- something's wrong
+ else
+ t.w = pdf.h - t.x
+ t.r = region
+ end
+ remove(columns)
+ column = columns[#columns]
+end
+
+function commands.bcolumn(tag,register)
+ insert(columns,tag)
+ column = tag
+ if register then
+ context(new_latelua(f_b_column(tag)))
+ end
+end
+
+function commands.ecolumn(register)
+ if register then
+ context(new_latelua(f_e_column()))
+ end
+ remove(columns)
+ column = columns[#columns]
+end
+
+-- regions
+
+function jobpositions.b_region(tag)
+ local last = tobesaved[tag]
+ last.x = pdf.h
+last.y = pdf.v
+ last.p = texcount.realpageno
+ insert(regions,tag)
+ region = tag
+end
+
+function jobpositions.e_region(correct)
+ local last = tobesaved[region]
+if correct then
+ last.h = last.y - pdf.v
+end
+ last.y = pdf.v
+ remove(regions)
+ region = regions[#regions]
+end
+
+function jobpositions.markregionbox(n,tag,correct)
+ if not tag or tag == "" then
+ nofregions = nofregions + 1
+ tag = f_region(nofregions)
+ end
+ local box = texbox[n]
+ local w = box.width
+ local h = box.height
+ local d = box.depth
+ tobesaved[tag] = {
+ p = true,
+ x = true,
+ y = pdf.v, -- true,
+ w = w ~= 0 and w or nil,
+ h = h ~= 0 and h or nil,
+ d = d ~= 0 and d or nil,
+ }
+ local push = new_latelua(f_b_region(tag))
+ local pop = new_latelua(f_e_region(tostring(correct))) -- todo: check if tostring is needed with formatter
+ -- maybe we should construct a hbox first (needs experimenting) so that we can avoid some at the tex end
+ local head = box.list
+ if head then
+ local tail = find_tail(head)
+ head.prev = push
+ push.next = head
+ pop .prev = tail
+ tail.next = pop
+ else -- we can have a simple push/pop
+ push.next = pop
+ pop.prev = push
+ end
+ box.list = push
+end
+
+function jobpositions.enhance(name)
+ enhance(tobesaved[name])
+end
+
+function commands.pos(name,t)
+ tobesaved[name] = t
+ context(new_latelua(f_enhance(name)))
+end
+
+local nofparagraphs = 0
+
+function commands.parpos() -- todo: relate to localpar (so this is an intermediate variant)
+ nofparagraphs = nofparagraphs + 1
+ texsetcount("global","c_anch_positions_paragraph",nofparagraphs)
+ local strutbox = texbox.strutbox
+ local t = {
+ p = true,
+ c = true,
+ r = true,
+ x = true,
+ y = true,
+ h = strutbox.height,
+ d = strutbox.depth,
+ hs = tex.hsize,
+ }
+ local leftskip = tex.leftskip.width
+ local rightskip = tex.rightskip.width
+ local hangindent = tex.hangindent
+ local hangafter = tex.hangafter
+ local parindent = tex.parindent
+ local parshape = tex.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 tag = f_p_tag(nofparagraphs)
+ tobesaved[tag] = t
+ context(new_latelua(f_enhance(tag)))
+end
+
+function commands.posxy(name) -- can node.write be used here?
+ tobesaved[name] = {
+ p = true,
+ c = column,
+ r = true,
+ x = true,
+ y = true,
+ n = nofparagraphs > 0 and nofparagraphs or nil,
+ }
+ context(new_latelua(f_enhance(name)))
+end
+
+function commands.poswhd(name,w,h,d)
+ tobesaved[name] = {
+ p = true,
+ c = column,
+ r = true,
+ x = true,
+ y = true,
+ w = w,
+ h = h,
+ d = d,
+ n = nofparagraphs > 0 and nofparagraphs or nil,
+ }
+ context(new_latelua(f_enhance(name)))
+end
+
+function commands.posplus(name,w,h,d,extra)
+ tobesaved[name] = {
+ p = true,
+ c = column,
+ r = true,
+ x = true,
+ y = true,
+ w = w,
+ h = h,
+ d = d,
+ n = nofparagraphs > 0 and nofparagraphs or nil,
+ e = extra,
+ }
+ context(new_latelua(f_enhance(name)))
+end
+
+function commands.posstrut(name,w,h,d)
+ local strutbox = texbox.strutbox
+ tobesaved[name] = {
+ p = true,
+ c = column,
+ r = true,
+ x = true,
+ y = true,
+ h = strutbox.height,
+ d = strutbox.depth,
+ n = nofparagraphs > 0 and nofparagraphs or nil,
+ }
+ context(new_latelua(f_enhance(name)))
+end
+
+function jobpositions.getreserved(tag,n)
+ if tag == v_column then
+ local fulltag = f_tag_three(tag,texcount.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,texcount.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
+
+function jobpositions.page(id)
+ local jpi = collected[id]
+ return jpi and jpi.p
+end
+
+function jobpositions.region(id)
+ local jpi = collected[id]
+ return jpi and jpi.r or false
+end
+
+function jobpositions.column(id)
+ local jpi = collected[id]
+ return jpi and jpi.c or false
+end
+
+function jobpositions.paragraph(id)
+ local jpi = collected[id]
+ return jpi and jpi.n
+end
+
+jobpositions.p = jobpositions.page
+jobpositions.r = jobpositions.region
+jobpositions.c = jobpositions.column
+jobpositions.n = jobpositions.paragraph
+
+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.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
+
+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
+
+jobpositions.overlapping = overlapping
+jobpositions.onsamepage = onsamepage
+
+-- interface
+
+commands.replacepospxywhd = jobpositions.replace
+commands.copyposition = jobpositions.copy
+
+function commands.MPp(id)
+ local jpi = collected[id]
+ if jpi then
+ local p = jpi.p
+ if p and p ~= true then
+ context(p)
+ return
+ end
+ end
+ context('0')
+end
+
+function commands.MPx(id)
+ local jpi = collected[id]
+ 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
+
+function commands.MPy(id)
+ local jpi = collected[id]
+ 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
+
+function commands.MPw(id)
+ local jpi = collected[id]
+ if jpi then
+ local w = jpi.w
+ if w and w ~= 0 then
+ context("%.5fpt",w*pt)
+ return
+ end
+ end
+ context('0pt')
+end
+
+function commands.MPh(id)
+ local jpi = collected[id]
+ if jpi then
+ local h = jpi.h
+ if h and h ~= 0 then
+ context("%.5fpt",h*pt)
+ return
+ end
+ end
+ context('0pt')
+end
+
+function commands.MPd(id)
+ local jpi = collected[id]
+ if jpi then
+ local d = jpi.d
+ if d and d ~= 0 then
+ context("%.5fpt",d*pt)
+ return
+ end
+ end
+ context('0pt')
+end
+
+function commands.MPxy(id)
+ local jpi = collected[id]
+ if jpi then
+ context('(%.5fpt,%.5fpt)',
+ jpi.x*pt,
+ jpi.y*pt
+ )
+ else
+ context('(0,0)')
+ end
+end
+
+function commands.MPll(id)
+ local jpi = collected[id]
+ if jpi then
+ context('(%.5fpt,%.5fpt)',
+ jpi.x *pt,
+ (jpi.y-jpi.d)*pt
+ )
+ else
+ context('(0,0)') -- for mp only
+ end
+end
+
+function commands.MPlr(id)
+ local jpi = collected[id]
+ 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
+
+function commands.MPur(id)
+ local jpi = collected[id]
+ 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
+
+function commands.MPul(id)
+ local jpi = collected[id]
+ 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
+
+commands.MPpos = MPpos
+
+function commands.MPn(id)
+ local jpi = collected[id]
+ if jpi then
+ local n = jpi.n
+ if n then
+ context(n)
+ return
+ end
+ end
+ context(0)
+end
+
+function commands.MPc(id)
+ local jpi = collected[id]
+ if jpi then
+ local c = jpi.c
+ if c and p ~= true then
+ context(c)
+ return
+ end
+ end
+ context(c) -- number
+end
+
+function commands.MPr(id)
+ local jpi = collected[id]
+ if jpi then
+ local r = jpi.r
+ if r and p ~= true then
+ context(r)
+ return
+ end
+ end
+end
+
+local function MPpardata(n)
+ local t = collected[n]
+ if not t then
+ local tag = f_p_tag(n)
+ 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
+
+commands.MPpardata = MPpardata
+
+function commands.MPposset(id) -- special helper, used in backgrounds
+ local b = f_b_tag(id)
+ local e = f_e_tag(id)
+ local w = f_w_tag(id)
+ local p = f_p_tag(jobpositions.n(b))
+ MPpos(b) context(",") MPpos(e) context(",") MPpos(w) context(",") MPpos(p) context(",") MPpardata(p)
+end
+
+function commands.MPls(id)
+ local t = collected[id]
+ if t then
+ context("%.5fpt",t.ls*pt)
+ else
+ context("0pt")
+ end
+end
+
+function commands.MPrs(id)
+ local t = collected[id]
+ if t then
+ context("%.5fpt",t.rs*pt)
+ else
+ context("0pt")
+ end
+end
+
+local splitter = lpeg.tsplitat(",")
+
+function commands.MPplus(id,n,default)
+ 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
+ context(split[n] or default)
+ return
+ end
+ end
+ context(default)
+end
+
+function commands.MPrest(id,default)
+ local jpi = collected[id]
+ context(jpi and jpi.e or default)
+end
+
+function commands.MPxywhd(id)
+ local t = collected[id]
+ if t then
+ context("%.5fpt,%.5fpt,%.5fpt,%.5fpt,%.5fpt",
+ t.x*pt,
+ t.y*pt,
+ t.w*pt,
+ t.h*pt,
+ t.d*pt
+ )
+ else
+ context("0,0,0,0,0") -- for mp only
+ end
+end
+
+local doif, doifelse = commands.doif, commands.doifelse
+
+function commands.doifpositionelse(name)
+ doifelse(collected[name])
+end
+
+function commands.doifposition(name)
+ doif(collected[name])
+end
+
+function commands.doifpositiononpage(name,page) -- probably always realpageno
+ local c = collected[name]
+ doifelse(c and c.p == page)
+end
+
+function commands.doifoverlappingelse(one,two,overlappingmargin)
+ doifelse(overlapping(one,two,overlappingmargin))
+end
+
+function commands.doifpositionsonsamepageelse(list,page)
+ doifelse(onsamepage(list))
+end
+
+function commands.doifpositionsonthispageelse(list)
+ doifelse(onsamepage(list,tostring(tex.count.realpageno)))
+end
+
+function commands.doifelsepositionsused()
+ doifelse(next(collected))
+end
+
+commands.markcolumnbox = jobpositions.markcolumnbox
+commands.markregionbox = jobpositions.markregionbox
+
+-- 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)
|