diff options
Diffstat (limited to 'tex/context/base/mkxl/anch-snc.lmt')
-rw-r--r-- | tex/context/base/mkxl/anch-snc.lmt | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/tex/context/base/mkxl/anch-snc.lmt b/tex/context/base/mkxl/anch-snc.lmt new file mode 100644 index 000000000..57789a5a0 --- /dev/null +++ b/tex/context/base/mkxl/anch-snc.lmt @@ -0,0 +1,243 @@ +if not modules then modules = { } end modules ['anch-snc'] = { + version = 1.001, + comment = "companion to anch-snc.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local tonumber, next, setmetatable = tonumber, next, setmetatable +local concat, sort, remove, copy = table.concat, table.sort, table.remove, table.copy +local match, find = string.match, string.find +local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns +local setmetatableindex = table.setmetatableindex +local P, Cc = lpeg.P, lpeg.Cc + +graphics = graphics or { } +local synchronizers = { } +graphics.synchronizers = synchronizers + +local p_number = lpegpatterns.cardinal/tonumber +local p_space = lpegpatterns.whitespace^0 +local p_tag = P("syncpos:") * p_number * P(":") * p_number +local p_option = p_number * ((P(",") * p_space * P("reset") * Cc(true)) + Cc(false)) -- for now + +local list = { } +local kinds = { + above = 1, + continue = 2, + nothing = 3, + normal = 4, + below = 5, +} + +local allentries = setmetatableindex(function(t,category) + setmetatable(t,nil) + for tag, pos in next, job.positions.collected do + local c, n = lpegmatch(p_tag,tag) + if c then + local tc = t[c] + if tc then + tc[n] = pos + else + t[c] = { [n] = pos } + end + end + end + for k, list in next, t do + sort(list,function(a,b) + local ap = a.p + local bp = b.p + if ap == bp then + return b.y < a.y + else + return ap < bp + end + end) + list.start = 1 + end + setmetatableindex(t,"table") + return t[category] +end) + +local lastdone = { } + +function synchronizers.collect(category,realpage,region) + local all = allentries[category] + local m = 0 + local n = #all + list = { } + if region and region ~= "" then + -- successive can be optimized when we sort by region + local start = 1 + local done = false + local last, rtop, rbot + for i=start,n do + local pos = all[i] + local p = pos.p + local r = pos.r + if r == region then + if not done then + local region = job.positions.collected[r] + list.region = region + list.page = region + rtop = (region.y or 0) + (region.h or 0) + rbot = (region.y or 0) - (region.d or 0) + last = { kind = "nothing", top = rtop, bottom = 0, task = 0 } + m = m + 1 ; list[m] = last + done = true + end + local top = pos.y + pos.h + last.bottom = top + local task, reset = lpegmatch(p_option,pos.e) + last = { kind = "normal", top = top, bottom = 0, task = task } + m = m + 1 ; list[m] = last + end + end + if done then + last.bottom = rbot + end + else + local start = all.start or 1 + local done = false + local last, rtop, rbot, ptop, pbot + for i=start,n do + local pos = all[i] + local p = pos.p + if p == realpage then + if not done then + local region = job.positions.collected[pos.r] + local page = job.positions.collected["page:"..realpage] or region + list.region = region + list.page = page + rtop = (region.y or 0) + (region.h or 0) + rbot = (region.y or 0) - (region.d or 0) + ptop = (page .y or 0) + (page .h or 0) + pbot = (page .y or 0) - (page .d or 0) + last = { kind = "above", top = ptop, bottom = rtop, task = 0 } + m = m + 1 ; list[m] = last + if i > 1 then + local task, reset = lpegmatch(p_option,all[i-1].e) + last = { kind = "continue", top = rtop, bottom = 0, task = task } + m = m + 1 ; list[m] = last + else + last = { kind = "nothing", top = rtop, bottom = 0, task = 0 } + m = m + 1 ; list[m] = last + end + done = true + end + local top = pos.y + pos.h + last.bottom = top + local task, reset = lpegmatch(p_option,pos.e) + if reset then + local l = list[2] + l.kind = "nothing" + l.task = 0 + end + last = { kind = "normal", top = top, bottom = 0, task = task } + m = m + 1 ; list[m] = last + elseif p > realpage then + all.start = i -- tricky, only for page + break + end + end + if done then + last.bottom = rbot + last = { kind = "below", top = rbot, bottom = pbot, task = 0 } + m = m + 1 ; list[m] = last + lastdone[category] = { + { kind = "above", top = ptop, bottom = rtop, task = 0 }, + { kind = "continue", top = rtop, bottom = rbot, task = list[#list-1].task }, -- lasttask + { kind = "below", top = rbot, bottom = pbot, task = 0 }, + region = list.region, + page = list.page, + } + else + local l = lastdone[category] + if l then + list = copy(l) -- inefficient, maybe metatable for region/page + m = 3 + end + end + end + return m +end + +function synchronizers.extend() + local n = #list + if n > 0 then + for i=1,n do + local l = list[i] + local k = l.kind + if k == "nothing" then + local ll = list[i+1] + if ll and ll.kind == "normal" then + ll.top = l.top + remove(list,i) + n = #list + break + end + end + end + end + return n +end + +function synchronizers.prune() + local n = #list + if n > 0 then + if list[1].kind == "above" then + remove(list,1) + end + if list[1].kind == "nothing" then + remove(list,1) + end + if list[#list].kind == "below" then + remove(list,#list) + end + n = #list + end + return n +end + +function synchronizers.collapse() + local n = #list + if n > 0 then + local m = 0 + local p = nil + for i=1,n do + local l = list[i] + local t = l.task + if p == t then + list[m].bottom = l.bottom + else + m = m + 1 + list[m] = l + end + p = t + end + for i=n,m+1,-1 do + list[i] = nil + end + n = m + end + return n +end + +function synchronizers.getsize () return #list end +function synchronizers.gettop (n) return list[n].top end +function synchronizers.getbottom(n) return list[n].bottom end +function synchronizers.getkind (n) return kinds[list[n].kind] end +function synchronizers.gettask (n) return list[n].task end + +function synchronizers.getx() return list.page.x or 0 end +function synchronizers.gety() return list.page.y or 0 end +function synchronizers.getw() return list.page.w or 0 end +function synchronizers.geth() return list.page.h or 0 end +function synchronizers.getd() return list.page.d or 0 end + +-- function mp.xxOverlayRegion() +-- local r = tokens.getters.macro("m_overlay_region") +-- mp.quoted('"'.. r .. '"') +-- end + |