diff options
Diffstat (limited to 'tex/context/base/mkiv/anch-pos.lua')
-rw-r--r-- | tex/context/base/mkiv/anch-pos.lua | 216 |
1 files changed, 133 insertions, 83 deletions
diff --git a/tex/context/base/mkiv/anch-pos.lua b/tex/context/base/mkiv/anch-pos.lua index 4360c9386..b415fac3a 100644 --- a/tex/context/base/mkiv/anch-pos.lua +++ b/tex/context/base/mkiv/anch-pos.lua @@ -17,7 +17,10 @@ more efficient.</p> -- 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 tostring, next, rawget, setmetatable = tostring, next, rawget, setmetatable +-- this is one of the first modules using scanners and we need to replace +-- it by implement and friends + +local tostring, next, rawget, setmetatable, tonumber = tostring, next, rawget, setmetatable, tonumber local sort, sortedhash, sortedkeys = table.sort, table.sortedhash, table.sortedkeys local format, gmatch, match, find = string.format, string.gmatch, string.match, string.find local rawget = rawget @@ -25,6 +28,8 @@ local lpegmatch = lpeg.match local insert, remove = table.insert, table.remove local allocate, mark = utilities.storage.allocate, utilities.storage.mark +local report = logs.reporter("positions") + local scanners = tokens.scanners local scanstring = scanners.string local scaninteger = scanners.integer @@ -57,6 +62,10 @@ local getlist = nuts.getlist local setlist = nuts.setlist local getbox = nuts.getbox local getskip = nuts.getskip +local getid = nuts.getid +local getdimensions = nuts.dimensions + +local hlist_code = nodes.listcodes.hlist local find_tail = nuts.tail @@ -124,6 +133,7 @@ local nofregular = 0 jobpositions.used = false -- todo: register subsets and count them indepently +-- todo: categories, like par, page, ... saves find and also ordered tags then -- local function initializer() -- tobesaved = jobpositions.tobesaved @@ -138,92 +148,74 @@ jobpositions.used = false -- if data then -- last = data -- last.p = nil -- no need for a page --- elseif last then +-- elseif last and not collected[region] then -- collected[region] = last -- end -- end -- end --- -- enhance regions with paragraphs --- -- local sorted = sortedkeys(collected) --- -- +-- -- enhance regions with paragraphs -- could be a list of tags instead -- there can be too many +-- local regions = { } +-- -- for tag, data in sortedhash(collected) do --saves a sort later on but can be huge -- for tag, data in next, collected do --- -- for i=1,#sorted do --- -- local tag = sorted[i] --- -- local data = collected[tag] --- 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 +-- if find(tag,"^p:") then +-- local region = data.r +-- if region then +-- local paragraphs = regions[region] +-- if paragraphs then +-- local par = match(tag,"%d+") +-- data.par = tonumber(par) -- paragraphs[#paragraphs+1] = data +-- nofusedregions = nofusedregions + 1 +-- elseif r == false then +-- nofmissingregions = nofmissingregions + 1 +-- else +-- local r = collected[region] +-- if r then +-- local par = match(tag,"%d+") +-- data.par = tonumber(par) +-- paragraphs = { data } +-- regions[region] = paragraphs +-- nofusedregions = nofusedregions + 1 +-- r.paragraphs = paragraphs +-- else +-- nofmissingregions = nofmissingregions + 1 +-- regions[region] = false +-- end -- end --- nofusedregions = nofusedregions + 1 -- else --- nofmissingregions = nofmissingregions + 1 +-- nofregular = nofregular + 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 --- -- for i=1,#sorted do --- -- local tag = sorted[i] --- -- local data = collected[tag] --- 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 +-- for tag, paragraphs in next, regions do +-- if paragraphs then +-- sort(paragraphs,function(a,b) return a.par < b.par end) -- end --- -- so, we can be sparse and don't need 'or 0' code -- end -- jobpositions.used = next(collected) -- end --- todo: categories, like par, page, ... saves find and also ordered tags then +local splitter = lpeg.splitat(":") local function initializer() tobesaved = jobpositions.tobesaved collected = jobpositions.collected -- add sparse regions - local pages = structures.pages.collected - if pages then - local last = nil - for p=1,#pages do - local region = "page:" .. p - local data = collected[region] - if data then - last = data - last.p = nil -- no need for a page - elseif last then - collected[region] = last - end - end - end -- enhance regions with paragraphs -- could be a list of tags instead -- there can be too many - local regions = { } + local regiondata = { } + local pagedata = { } + local freedata = setmetatableindex("table") -- for tag, data in sortedhash(collected) do --saves a sort later on but can be huge for tag, data in next, collected do - if find(tag,"^p:") then + local prefix, rest = lpegmatch(splitter,tag) + if prefix == "p" then local region = data.r if region then - local paragraphs = regions[region] + local paragraphs = regiondata[region] if paragraphs then - local par = match(tag,"%d+") - data.par = tonumber(par) + data.par = tonumber(rest) or 0 paragraphs[#paragraphs+1] = data nofusedregions = nofusedregions + 1 elseif r == false then @@ -231,33 +223,63 @@ local function initializer() else local r = collected[region] if r then - local par = match(tag,"%d+") - data.par = tonumber(par) + data.par = tonumber(rest) or 0 paragraphs = { data } - regions[region] = paragraphs + regiondata[region] = paragraphs nofusedregions = nofusedregions + 1 r.paragraphs = paragraphs else nofmissingregions = nofmissingregions + 1 - regions[region] = false + regiondata[region] = false end end else nofregular = nofregular + 1 end + elseif prefix == "page" then + pagedata[tonumber(rest) or 0] = data + elseif prefix == "free" then + local t = freedata[data.p or 0] + t[#t+1] = data end setmetatable(data,default) end -- sort this data - for tag, paragraphs in next, regions do + for tag, paragraphs in next, regiondata do if paragraphs then sort(paragraphs,function(a,b) return a.par < b.par end) end 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.page = pagedata + jobpositions.free = freedata jobpositions.used = next(collected) end - job.register('job.positions.collected', tobesaved, initializer) local regions = { } @@ -335,9 +357,6 @@ end local function set(name,index,val) -- ,key local data = enhance(val or index) if val then --- if data[key] and not next(next(data)) then --- data = data[key] --- end container = tobesaved[name] if not container then tobesaved[name] = { @@ -469,16 +488,14 @@ end jobpositions.b_region = b_region jobpositions.e_region = e_region -local function setregionbox(n,tag) +local function setregionbox(n,tag,k,lo,ro,to,bo) -- kind if not tag or tag == "" then nofregions = nofregions + 1 tag = f_region(nofregions) end local box = getbox(n) - local w = getfield(box,"width") - local h = getfield(box,"height") - local d = getfield(box,"depth") - local x, y = getpos() -- was only y + local w, h, d = getdimensions(box) + local x, y = getpos() -- hm, makes no sense here tobesaved[tag] = { -- p = texgetcount("realpageno"), -- we copy them x = x ~= 0 and x or nil, -- was true @@ -486,17 +503,27 @@ local function setregionbox(n,tag) 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, } return tag, box end -local function markregionbox(n,tag,correct) -- correct needs checking - local tag, box = setregionbox(n,tag) +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(function() b_region(tag) end) local pop = new_latelua(function() e_region(correct) end) -- maybe we should construct a hbox first (needs experimenting) so that we can avoid some at the tex end local head = getlist(box) + -- no : + -- if getid(box) ~= hlist_code then + -- -- report("mark region box assumes a hlist, fix this for %a",tag) + -- head = nuts.hpack(head) + -- end if head then local tail = find_tail(head) setlink(push,head) @@ -528,15 +555,16 @@ local nofparagraphs = 0 scanners.parpos = function() -- todo: relate to localpar (so this is an intermediate variant) nofparagraphs = nofparagraphs + 1 texsetcount("global","c_anch_positions_paragraph",nofparagraphs) - local strutbox = getbox("strutbox") + local box = getbox("strutbox") + local w, h, d = getdimensions(box) local t = { p = true, c = true, r = true, x = true, y = true, - h = getfield(strutbox,"height"), -- never 0 - d = getfield(strutbox,"depth"), -- never 0 + h = h, + d = d, hs = texget("hsize"), -- never 0 } local leftskip = getfield(getskip("leftskip"),"width") @@ -605,9 +633,7 @@ end scanners.dosetpositionbox = function() -- name box local name = scanstring() local box = getbox(scaninteger()) - local w = getfield(box,"width") - local h = getfield(box,"height") - local d = getfield(box,"depth") + local w, h, d = getdimensions(box) tobesaved[name] = { p = true, c = column, @@ -646,10 +672,29 @@ end scanners.dosetpositionstrut = function() -- name local name = scanstring() - local strutbox = getbox("strutbox") - local h = getfield(strutbox,"height") - local d = getfield(strutbox,"depth") + local box = getbox("strutbox") + local w, h, d = getdimensions(box) + tobesaved[name] = { + 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 = texgetcount("inlinelefttoright") == 1 or nil, + } + ctxnode(new_latelua_node(function() enhance(tobesaved[name]) end)) +end + +scanners.dosetpositionstrutkind = function() -- name + local name = scanstring() + local kind = scaninteger() + local box = getbox("strutbox") + local w, h, d = getdimensions(box) tobesaved[name] = { + k = kind, p = true, c = column, r = true, @@ -1279,6 +1324,11 @@ scanners.markregionboxcorrected = function() -- box tag markregionbox(scaninteger(),scanstring(),true) end +scanners.markregionboxtaggedkind = function() -- box tag kind + markregionbox(scaninteger(),scanstring(),nil, + scaninteger(),scandimen(),scandimen(),scandimen(),scandimen()) +end + -- statistics (at least for the moment, when testing) statistics.register("positions", function() |