summaryrefslogtreecommitdiff
path: root/tex/context/base/anch-pgr.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/anch-pgr.lua')
-rw-r--r--tex/context/base/anch-pgr.lua1388
1 files changed, 694 insertions, 694 deletions
diff --git a/tex/context/base/anch-pgr.lua b/tex/context/base/anch-pgr.lua
index 992b4deff..278448e3a 100644
--- a/tex/context/base/anch-pgr.lua
+++ b/tex/context/base/anch-pgr.lua
@@ -1,694 +1,694 @@
-if not modules then modules = { } end modules ['anch-pgr'] = {
- version = 1.001,
- comment = "companion to anch-pgr.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
--- todo: we need to clean up lists (of previous pages)
-
-local commands, context = commands, context
-
-local format = string.format
-local abs = math.abs
-local concat, sort = table.concat, table.sort
-local splitter = lpeg.splitat(":")
-local lpegmatch = lpeg.match
-
-local jobpositions = job.positions
-local formatters = string.formatters
-
-local report_graphics = logs.reporter("graphics")
-
-local f_b_tag = formatters["b:%s"]
-local f_e_tag = formatters["e:%s"]
-local f_p_tag = formatters["p:%s"]
-
-local f_tag_two = formatters["%s:%s"]
-
-local f_point = formatters["%p"]
-local f_pair = formatters["(%p,%p)"]
-local f_path = formatters["%--t--cycle"]
-
-local function regionarea(r)
- local rx, ry = r.x, r.y
- local rw = rx + r.w
- local rh = ry + r.h
- local rd = ry - r.d
- return {
- f_pair(rx, rh - ry),
- f_pair(rw, rh - ry),
- f_pair(rw, rd - ry),
- f_pair(rx, rd - ry),
- }
-end
-
--- we can use a 'local t, n' and reuse the table
-
-local eps = 2
-
-local function add(t,x,y,last,direction)
- local n = #t
- if n == 0 then
- t[n+1] = { x, y }
- else
- local tn = t[n]
- local lx = tn[1]
- local ly = tn[2]
- if x == lx and y == ly then
- -- quick skip
- elseif n == 1 then
--- if abs(lx-x) <= eps or abs(ly-y) <= eps then
- if abs(lx-x) > eps or abs(ly-y) > eps then
- t[n+1] = { x, y }
- end
- else
- local tm = t[n-1]
- local px = tm[1]
- local py = tm[2]
-if (direction == "down" and y > ly) or (direction == "up" and y < ly) then
- -- move back from too much hang
-else
- if abs(lx-px) <= eps and abs(lx-x) <= eps then
- if abs(ly-y) > eps then
- tn[2] = y
- end
- elseif abs(ly-py) <= eps and abs(ly-y) <= eps then
- if abs(lx-x) > eps then
- tn[1] = x
- end
- elseif not last then
- t[n+1] = { x, y }
- end
-end
- end
- end
-end
-
--- local function add(t,x,y,last)
--- t[#t+1] = { x, y }
--- end
-
-local function finish(t)
- local n = #t
- if n > 1 then
- local first = t[1]
- local last = t[n]
- if abs(first[1]-last[1]) <= eps and abs(first[2]-last[2]) <= eps then
- t[n] = nil
- end
- end
-end
-
-local function clip(t,ytop,ybot)
- local first, last = 1, #t
- for i=first,last do
- local y = t[i][2]
- if ytop < y then
- first = i
- end
- if ybot > y then
- last = i
- break
- end
- end
- local lp = { }
- lp[#lp+1] = { t[first][1], ytop }
- for i=first+1,last-1 do
- lp[#lp+1] = { t[i][1], t[i][2] }
- end
- lp[#lp+1] = { t[last][1], ybot }
- return lp
-end
-
--- todo: mark regions and free paragraphs in collected
-
-local function shapes(r,rx,ry,rw,rh,rd,lytop,lybot,rytop,rybot,obeyhang)
- -- we assume that we only hang per page and not cross pages
- -- which makes sense as hanging is only uses in special cases
- --
- -- we can remove data as soon as a page is done so we could
- -- remember per page and discard areas after each shipout
- local leftshape, rightshape
- leftshape = { { rx, rh } } -- spikes get removed so we can start at the edge
- rightshape = { { rw, rh } } -- even if we hang next
- local paragraphs = r.paragraphs
- local extending = false
- if paragraphs then
- for i=1,#paragraphs do
- local p = paragraphs[i]
- local ha = p.ha
- if obeyhang and ha and ha ~= 0 then
- local py = p.y
- local ph = p.h
- local pd = p.d
- local hi = p.hi
- local hang = ha * (ph + pd)
- local py_ph = py + ph
- -- ha < 0 hi < 0 : right top
- -- ha < 0 hi > 0 : left top
- if ha < 0 then
- if hi < 0 then -- right
- add(rightshape,rw, py_ph,"up")
- add(rightshape,rw + hi,py_ph,"up")
- add(rightshape,rw + hi,py_ph + hang,"up")
- add(rightshape,rw, py_ph + hang,"up")
- else
- -- left
- add(leftshape,rx,py_ph,"down")
- add(leftshape,rx + hi,py_ph,"down")
- add(leftshape,rx + hi,py_ph + hang,"down")
- add(leftshape,rx,py_ph + hang,"down")
- end
- else
- -- maybe some day
- end
- extending = true -- false
- else -- we need to clip to the next par
- local ps = p.ps
- if ps then
- local py = p.y
- local ph = p.h
- local pd = p.d
- local step = ph + pd
- local size = #ps * step
- local py_ph = py + ph
- add(leftshape,rx,py_ph,"up")
- add(rightshape,rw,py_ph,"down")
- for i=1,#ps do
- local p = ps[i]
- local l = p[1]
- local w = p[2]
- add(leftshape,rx + l, py_ph,"up")
- add(rightshape,rx + l + w, py_ph,"down")
- py_ph = py_ph - step
- add(leftshape,rx + l, py_ph,"up")
- add(rightshape,rx + l + w, py_ph,"down")
- end
- extending = true
- elseif extending then
- local py = p.y
- local ph = p.h
- local pd = p.d
- local py_ph = py + ph
- local py_pd = py - pd
- add(leftshape,leftshape[#leftshape][1],py_ph,"up")
- add(rightshape,rightshape[#rightshape][1],py_ph,"down")
- add(leftshape,rx,py_ph,"up") -- shouldn't this be py_pd
- add(rightshape,rw,py_ph,"down") -- shouldn't this be py_pd
- extending = false
- end
- end
- end
- end
- -- we can have a simple variant when no paragraphs
- if extending then
- -- not ok
- leftshape[#leftshape][2] = rd
- rightshape[#rightshape][2] = rw
- else
- add(leftshape,rx,rd,"up")
- add(rightshape,rw,rd,"down")
- end
- return clip(leftshape,lytop,lybot), clip(rightshape,rytop,rybot)
-end
-
--- local function shapes(r,rx,ry,rw,rh,rd,lytop,lybot,rytop,rybot,obeyhang)
--- local leftshape = { { rx, rh }, { rx, rd } }
--- local rightshape = { { rw, rh }, { rw, rd } }
--- return clip(leftshape,lytop,lybot), clip(rightshape,rytop,rybot)
--- end
-
-local function singlepart(b,e,r,left,right,obeyhang)
- local bx, by = b.x, b.y
- local ex, ey = e.x, e.y
- local rx, ry = r.x, r.y
- local rw = rx + r.w
- local rh = ry + r.h
- local rd = ry - r.d
- if left then
- rx = rx + left
- rw = rw - right
- end
- local bh = by + b.h
- local bd = by - b.d
- local eh = ey + e.h
- local ed = ey - e.d
- if ex == rx then
- -- We probably have a strut at the next line so we force a width
- -- although of course it is better to move up. But as we have whitespace
- -- (at least visually) injected then it's best to stress the issue.
- ex = rw
- end
- local area
- if by == ey then
- area = {
- f_pair(bx,bh-ry),
- f_pair(ex,eh-ry),
- f_pair(ex,ed-ry),
- f_pair(bx,bd-ry),
- }
- else
- area = { }
- local leftshapes, rightshapes = shapes(r,rx,ry,rw,rh,rd,bd,ed,bh,eh,obeyhang)
- add(area,bx,bh-ry)
- for i=1,#rightshapes do
- local ri = rightshapes[i]
- add(area,ri[1],ri[2]-ry)
- end
- add(area,ex,eh-ry)
- add(area,ex,ed-ry)
- for i=#leftshapes,1,-1 do
- local li = leftshapes[i]
- add(area,li[1],li[2]-ry)
- end
- add(area,bx,bd-ry)
- add(area,bx,bh-ry,true) -- finish last straight line (but no add as we cycle)
- finish(area)
- for i=1,#area do
- local a = area[i]
- area[i] = f_pair(a[1],a[2])
- end
- end
- return {
- location = "single",
- region = r,
- area = area,
- }
-end
-
-local function firstpart(b,r,left,right,obeyhang)
- local bx, by = b.x, b.y
- local rx, ry = r.x, r.y
- local rw = rx + r.w
- local rh = ry + r.h
- local rd = ry - r.d
- if left then
- rx = rx + left
- rw = rw - right
- end
- local bh = by + b.h
- local bd = by - b.d
- local area = { }
- local leftshapes, rightshapes = shapes(r,rx,ry,rw,rh,rd,bd,rd,bh,rd,obeyhang)
- add(area,bx,bh-ry)
- for i=1,#rightshapes do
- local ri = rightshapes[i]
- add(area,ri[1],ri[2]-ry)
- end
- for i=#leftshapes,1,-1 do
- local li = leftshapes[i]
- add(area,li[1],li[2]-ry)
- end
- add(area,bx,bd-ry)
- add(area,bx,bh-ry,true) -- finish last straight line (but no add as we cycle)
- finish(area)
- for i=1,#area do
- local a = area[i]
- area[i] = f_pair(a[1],a[2])
- end
- return {
- location = "first",
- region = r,
- area = area,
- }
-end
-
-local function middlepart(r,left,right,obeyhang)
- local rx, ry = r.x, r.y
- local rw = rx + r.w
- local rh = ry + r.h
- local rd = ry - r.d
- if left then
- rx = rx + left
- rw = rw - right
- end
- local area = { }
- local leftshapes, rightshapes = shapes(r,rx,ry,rw,rh,rd,rh,rd,rh,rd,obeyhang)
- for i=#leftshapes,1,-1 do
- local li = leftshapes[i]
- add(area,li[1],li[2]-ry)
- end
- for i=1,#rightshapes do
- local ri = rightshapes[i]
- add(area,ri[1],ri[2]-ry)
- end
- finish(area)
- for i=1,#area do
- local a = area[i]
- area[i] = f_pair(a[1],a[2])
- end
- return {
- location = "middle",
- region = r,
- area = area,
- }
-end
-
-local function lastpart(e,r,left,right,obeyhang)
- local ex, ey = e.x, e.y
- local rx, ry = r.x, r.y
- local rw = rx + r.w
- local rh = ry + r.h
- local rd = ry - r.d
- if left then
- rx = rx + left
- rw = rw - right
- end
- local eh = ey + e.h
- local ed = ey - e.d
- local area = { }
- -- two cases: till end and halfway e line
- local leftshapes, rightshapes = shapes(r,rx,ry,rw,rh,rd,rh,ed,rh,eh,obeyhang)
- for i=1,#rightshapes do
- local ri = rightshapes[i]
- add(area,ri[1],ri[2]-ry)
- end
- add(area,ex,eh-ry)
- add(area,ex,ed-ry)
- for i=#leftshapes,1,-1 do
- local li = leftshapes[i]
- add(area,li[1],li[2]-ry)
- end
- finish(area)
- for i=1,#area do
- local a = area[i]
- area[i] = f_pair(a[1],a[2])
- end
- return {
- location = "last",
- region = r,
- area = area,
- }
-end
-
-graphics = graphics or { }
-local backgrounds = { }
-
-graphics.backgrounds = backgrounds
-
-local function calculatemultipar(tag,obeyhang)
- local collected = jobpositions.collected
- local b = collected[f_b_tag(tag)]
- local e = collected[f_e_tag(tag)]
- if not b or not e then
- report_graphics("invalid tag %a",tag)
- return { }
- end
- local br = b.r
- local er = e.r
- if not br or not er then
- report_graphics("invalid region for %a",tag)
- return { }
- end
- local btag, bindex = lpegmatch(splitter,br)
- local etag, eindex = lpegmatch(splitter,er)
- if not bindex or not eindex or btag ~= etag then
- report_graphics("invalid indices for %a",tag)
- return { }
- end
- local bindex = tonumber(bindex)
- local eindex = tonumber(eindex)
- -- Here we compensate for columns (in tables): a table can have a set of column
- -- entries and these are shared. We compensate left/right based on the columns
- -- x and w but need to take the region into acount where the specification was
- -- flushed and not the begin pos's region, because otherwise we get the wrong
- -- compensation for assymetrical doublesided layouts.
- local left = 0
- local right = 0
- local rc = b.c
- if rc then
- rc = collected[rc]
- if rc then
- local tb = collected[rc.r]
- if tb then
- left = -(tb.x - rc.x)
- right = (tb.w - rc.w - left) -- tb.x - rc.x
- end
- end
- end
- -- Obeying intermediate changes of left/rightskip makes no sense as it will
- -- look bad, so we only look at the begin situation.
- --
- local bn = b.n
- if bn then
- local bp = collected[f_p_tag(bn)]
- if bp then
- left = left + bp.ls
- right = right + bp.rs
- end
- end
- --
- if bindex == eindex then
- return {
- list = { [b.p] = { singlepart(b,e,collected[br],left,right,obeyhang) } },
- bpos = b,
- epos = e,
- }
- else
- local list = {
- [b.p] = { firstpart(b,collected[br],left,right,obeyhang) },
- }
- for i=bindex+1,eindex-1 do
- br = f_tag_two(btag,i)
- local r = collected[br]
- if not r then
- report_graphics("invalid middle for %a",br)
- else
- local p = r.p
- local pp = list[p]
- if pp then
- pp[#pp+1] = middlepart(r,left,right,obeyhang)
- else
- list[p] = { middlepart(r,left,right,obeyhang) }
- end
- end
- end
- local p = e.p
- local pp = list[p]
- if pp then
- pp[#pp+1] = lastpart(e,collected[er],left,right,obeyhang)
- else
- list[p] = { lastpart(e,collected[er],left,right,obeyhang) }
- end
- return {
- list = list,
- bpos = b,
- epos = e,
- }
- end
-end
-
--- local pending = { } -- needs gc
---
--- local function register(data,n,anchor)
--- local pa = pending[anchor]
--- if not pa then
--- pa = { }
--- pending[anchor] = pa
--- end
--- for page, pagedata in next, data do
--- local pap = pa[page]
--- if pap then
--- pap[#pap+1] = n
--- else
--- pa[page] = { n }
--- end
--- end
--- end
---
--- function backgrounds.registered(anchor,page)
--- local pa = pending[anchor]
--- if pa then
--- concat(pa,",")
--- else
--- return ""
--- end
--- end
-
-local pbg = { } -- will move to pending
-
-function backgrounds.calculatemultipar(n)
- if not pbg[n] then
- pbg[n] = calculatemultipar("pbg",n) or { }
- end
-end
-
-local multilocs = {
- single = 1, -- maybe 0
- first = 1,
- middle = 2,
- last = 3,
-}
-
--- if unknown context_abck : input mp-abck.mpiv ; fi ;
-
-local f_template_a = [[
-path multiregs[], multipars[], multibox ;
-string multikind[] ;
-numeric multilocs[], nofmultipars ;
-nofmultipars := %s ;
-multibox := unitsquare xyscaled (%p,%p) ;
-numeric par_strut_height, par_strut_depth, par_line_height ;
-par_strut_height := %p ;
-par_strut_depth := %p ;
-par_line_height := %p ;
-]]
-
-local f_template_b = [[
-multilocs[%s] := %s ;
-multikind[%s] := "%s" ;
-multipars[%s] := (%--t--cycle) shifted - (%p,%p) ;
-]]
-
-local f_template_c = [[
-multiregs[%s] := (%--t--cycle) shifted - %s ;
-]]
-
-local f_template_d = [[
-setbounds currentpicture to multibox ;
-]]
-
-f_template_a = formatters[f_template_a]
-f_template_b = formatters[f_template_b]
-f_template_c = formatters[f_template_c]
-f_template_d = formatters[f_template_d]
-
-function backgrounds.fetchmultipar(n,anchor,page,obeyhang)
- local data = pbg[n]
- if not data then
- data = calculatemultipar(n,obeyhang)
- pbg[n] = data -- can be replaced by register
- -- register(data.list,n,anchor)
- end
- if data then
- local list = data.list
- if list then
- local pagedata = list[page]
- if pagedata then
- local nofmultipars = #pagedata
- -- report_graphics("fetching %a at page %s using anchor %a containing %s multipars",n,page,anchor,nofmultipars)
- local a = jobpositions.collected[anchor]
- if not a then
- report_graphics("missing anchor %a",anchor)
- else
- local trace = false
- local x, y, w, h, d = a.x, a.y, a.w, a.h, a.d
- local bpos = data.bpos
- local bh, bd = bpos.h, bpos.d
- local result = { f_template_a(nofmultipars,w,h+d,bh,bd,bh+bd) }
- for i=1,nofmultipars do
- local region = pagedata[i]
- result[#result+1] = f_template_b(
- i, multilocs[region.location],
- i, region.location,
- i, region.area, x, y-region.region.y)
- if trace then
- result[#result+1] = f_template_c(i, regionarea(region.region), offset)
- end
- end
- data[page] = nil
- result[#result+1] = f_template_d()
- result = concat(result,"\n")
- return result
- end
- end
- end
- end
- return f_template_a(0,"origin",0,0,0)
-end
-
-backgrounds.point = f_point
-backgrounds.pair = f_pair
-backgrounds.path = f_path
-
-function commands.fetchmultipar(n,anchor,page)
- context(backgrounds.fetchmultipar(n,anchor,page))
-end
-
-function commands.fetchmultishape(n,anchor,page)
- context(backgrounds.fetchmultipar(n,anchor,page,true))
-end
-
-local f_template_a = [[
-path posboxes[], posregions[] ;
-numeric pospages[] ;
-numeric nofposboxes ;
-nofposboxes := %s ;
-%t ;
-]]
-
-local f_template_b = [[
-pospages[%s] := %s ;
-posboxes[%s] := (%p,%p)--(%p,%p)--(%p,%p)--(%p,%p)--cycle ;
-posregions[%s] := (%p,%p)--(%p,%p)--(%p,%p)--(%p,%p)--cycle ;
-]]
-
-f_template_a = formatters[f_template_a]
-f_template_b = formatters[f_template_b]
-
-function commands.fetchposboxes(tags,anchor,page) -- no caching (yet) / todo: anchor, page
- local collected = jobpositions.collected
- if type(tags) == "string" then
- tags = utilities.parsers.settings_to_array(tags)
- end
- local list, nofboxes = { }, 0
- for i=1,#tags do
- local tag= tags[i]
- local c = collected[tag]
- if c then
- local r = c.r
- if r then
- r = collected[r]
- if r then
- local rx, ry, rw, rh, rd = r.x, r.y, r.w, r.h, r.d
- local cx = c.x - rx
- local cy = c.y - ry
- local cw = cx + c.w
- local ch = cy + c.h
- local cd = cy - c.d
- nofboxes = nofboxes + 1
- list[nofboxes] = f_template_b(
- nofboxes,c.p,
- nofboxes,cx,ch,cw,ch,cw,cd,cx,cd,
- nofboxes,0,rh,rw,rh,rw,rd,0,rd
- )
- end
- end
- else
- print("\n missing",tag)
- end
- end
- context(f_template_a(nofboxes,list))
-end
-
-local doifelse = commands.doifelse
-
-function commands.doifelsemultipar(n,page,obeyhang)
- local data = pbg[n]
- if not data then
- data = calculatemultipar(n,obeyhang)
- pbg[n] = data
- end
- if page then
- doifelse(data and data[page] and true)
- else
- doifelse(data and next(data) and true)
- end
-end
-
-function commands.doifelserangeonpage(first,last,page)
- local collected = jobpositions.collected
- local f = collected[first]
- if not f then
- doifelse(false)
- return
- end
- local l = collected[last]
- if not l then
- doifelse(false)
- return
- end
- doifelse(page >= f.p and page <= l.p)
-end
+if not modules then modules = { } end modules ['anch-pgr'] = {
+ version = 1.001,
+ comment = "companion to anch-pgr.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- todo: we need to clean up lists (of previous pages)
+
+local commands, context = commands, context
+
+local format = string.format
+local abs = math.abs
+local concat, sort = table.concat, table.sort
+local splitter = lpeg.splitat(":")
+local lpegmatch = lpeg.match
+
+local jobpositions = job.positions
+local formatters = string.formatters
+
+local report_graphics = logs.reporter("graphics")
+
+local f_b_tag = formatters["b:%s"]
+local f_e_tag = formatters["e:%s"]
+local f_p_tag = formatters["p:%s"]
+
+local f_tag_two = formatters["%s:%s"]
+
+local f_point = formatters["%p"]
+local f_pair = formatters["(%p,%p)"]
+local f_path = formatters["%--t--cycle"]
+
+local function regionarea(r)
+ local rx, ry = r.x, r.y
+ local rw = rx + r.w
+ local rh = ry + r.h
+ local rd = ry - r.d
+ return {
+ f_pair(rx, rh - ry),
+ f_pair(rw, rh - ry),
+ f_pair(rw, rd - ry),
+ f_pair(rx, rd - ry),
+ }
+end
+
+-- we can use a 'local t, n' and reuse the table
+
+local eps = 2
+
+local function add(t,x,y,last,direction)
+ local n = #t
+ if n == 0 then
+ t[n+1] = { x, y }
+ else
+ local tn = t[n]
+ local lx = tn[1]
+ local ly = tn[2]
+ if x == lx and y == ly then
+ -- quick skip
+ elseif n == 1 then
+-- if abs(lx-x) <= eps or abs(ly-y) <= eps then
+ if abs(lx-x) > eps or abs(ly-y) > eps then
+ t[n+1] = { x, y }
+ end
+ else
+ local tm = t[n-1]
+ local px = tm[1]
+ local py = tm[2]
+if (direction == "down" and y > ly) or (direction == "up" and y < ly) then
+ -- move back from too much hang
+else
+ if abs(lx-px) <= eps and abs(lx-x) <= eps then
+ if abs(ly-y) > eps then
+ tn[2] = y
+ end
+ elseif abs(ly-py) <= eps and abs(ly-y) <= eps then
+ if abs(lx-x) > eps then
+ tn[1] = x
+ end
+ elseif not last then
+ t[n+1] = { x, y }
+ end
+end
+ end
+ end
+end
+
+-- local function add(t,x,y,last)
+-- t[#t+1] = { x, y }
+-- end
+
+local function finish(t)
+ local n = #t
+ if n > 1 then
+ local first = t[1]
+ local last = t[n]
+ if abs(first[1]-last[1]) <= eps and abs(first[2]-last[2]) <= eps then
+ t[n] = nil
+ end
+ end
+end
+
+local function clip(t,ytop,ybot)
+ local first, last = 1, #t
+ for i=first,last do
+ local y = t[i][2]
+ if ytop < y then
+ first = i
+ end
+ if ybot > y then
+ last = i
+ break
+ end
+ end
+ local lp = { }
+ lp[#lp+1] = { t[first][1], ytop }
+ for i=first+1,last-1 do
+ lp[#lp+1] = { t[i][1], t[i][2] }
+ end
+ lp[#lp+1] = { t[last][1], ybot }
+ return lp
+end
+
+-- todo: mark regions and free paragraphs in collected
+
+local function shapes(r,rx,ry,rw,rh,rd,lytop,lybot,rytop,rybot,obeyhang)
+ -- we assume that we only hang per page and not cross pages
+ -- which makes sense as hanging is only uses in special cases
+ --
+ -- we can remove data as soon as a page is done so we could
+ -- remember per page and discard areas after each shipout
+ local leftshape, rightshape
+ leftshape = { { rx, rh } } -- spikes get removed so we can start at the edge
+ rightshape = { { rw, rh } } -- even if we hang next
+ local paragraphs = r.paragraphs
+ local extending = false
+ if paragraphs then
+ for i=1,#paragraphs do
+ local p = paragraphs[i]
+ local ha = p.ha
+ if obeyhang and ha and ha ~= 0 then
+ local py = p.y
+ local ph = p.h
+ local pd = p.d
+ local hi = p.hi
+ local hang = ha * (ph + pd)
+ local py_ph = py + ph
+ -- ha < 0 hi < 0 : right top
+ -- ha < 0 hi > 0 : left top
+ if ha < 0 then
+ if hi < 0 then -- right
+ add(rightshape,rw, py_ph,"up")
+ add(rightshape,rw + hi,py_ph,"up")
+ add(rightshape,rw + hi,py_ph + hang,"up")
+ add(rightshape,rw, py_ph + hang,"up")
+ else
+ -- left
+ add(leftshape,rx,py_ph,"down")
+ add(leftshape,rx + hi,py_ph,"down")
+ add(leftshape,rx + hi,py_ph + hang,"down")
+ add(leftshape,rx,py_ph + hang,"down")
+ end
+ else
+ -- maybe some day
+ end
+ extending = true -- false
+ else -- we need to clip to the next par
+ local ps = p.ps
+ if ps then
+ local py = p.y
+ local ph = p.h
+ local pd = p.d
+ local step = ph + pd
+ local size = #ps * step
+ local py_ph = py + ph
+ add(leftshape,rx,py_ph,"up")
+ add(rightshape,rw,py_ph,"down")
+ for i=1,#ps do
+ local p = ps[i]
+ local l = p[1]
+ local w = p[2]
+ add(leftshape,rx + l, py_ph,"up")
+ add(rightshape,rx + l + w, py_ph,"down")
+ py_ph = py_ph - step
+ add(leftshape,rx + l, py_ph,"up")
+ add(rightshape,rx + l + w, py_ph,"down")
+ end
+ extending = true
+ elseif extending then
+ local py = p.y
+ local ph = p.h
+ local pd = p.d
+ local py_ph = py + ph
+ local py_pd = py - pd
+ add(leftshape,leftshape[#leftshape][1],py_ph,"up")
+ add(rightshape,rightshape[#rightshape][1],py_ph,"down")
+ add(leftshape,rx,py_ph,"up") -- shouldn't this be py_pd
+ add(rightshape,rw,py_ph,"down") -- shouldn't this be py_pd
+ extending = false
+ end
+ end
+ end
+ end
+ -- we can have a simple variant when no paragraphs
+ if extending then
+ -- not ok
+ leftshape[#leftshape][2] = rd
+ rightshape[#rightshape][2] = rw
+ else
+ add(leftshape,rx,rd,"up")
+ add(rightshape,rw,rd,"down")
+ end
+ return clip(leftshape,lytop,lybot), clip(rightshape,rytop,rybot)
+end
+
+-- local function shapes(r,rx,ry,rw,rh,rd,lytop,lybot,rytop,rybot,obeyhang)
+-- local leftshape = { { rx, rh }, { rx, rd } }
+-- local rightshape = { { rw, rh }, { rw, rd } }
+-- return clip(leftshape,lytop,lybot), clip(rightshape,rytop,rybot)
+-- end
+
+local function singlepart(b,e,r,left,right,obeyhang)
+ local bx, by = b.x, b.y
+ local ex, ey = e.x, e.y
+ local rx, ry = r.x, r.y
+ local rw = rx + r.w
+ local rh = ry + r.h
+ local rd = ry - r.d
+ if left then
+ rx = rx + left
+ rw = rw - right
+ end
+ local bh = by + b.h
+ local bd = by - b.d
+ local eh = ey + e.h
+ local ed = ey - e.d
+ if ex == rx then
+ -- We probably have a strut at the next line so we force a width
+ -- although of course it is better to move up. But as we have whitespace
+ -- (at least visually) injected then it's best to stress the issue.
+ ex = rw
+ end
+ local area
+ if by == ey then
+ area = {
+ f_pair(bx,bh-ry),
+ f_pair(ex,eh-ry),
+ f_pair(ex,ed-ry),
+ f_pair(bx,bd-ry),
+ }
+ else
+ area = { }
+ local leftshapes, rightshapes = shapes(r,rx,ry,rw,rh,rd,bd,ed,bh,eh,obeyhang)
+ add(area,bx,bh-ry)
+ for i=1,#rightshapes do
+ local ri = rightshapes[i]
+ add(area,ri[1],ri[2]-ry)
+ end
+ add(area,ex,eh-ry)
+ add(area,ex,ed-ry)
+ for i=#leftshapes,1,-1 do
+ local li = leftshapes[i]
+ add(area,li[1],li[2]-ry)
+ end
+ add(area,bx,bd-ry)
+ add(area,bx,bh-ry,true) -- finish last straight line (but no add as we cycle)
+ finish(area)
+ for i=1,#area do
+ local a = area[i]
+ area[i] = f_pair(a[1],a[2])
+ end
+ end
+ return {
+ location = "single",
+ region = r,
+ area = area,
+ }
+end
+
+local function firstpart(b,r,left,right,obeyhang)
+ local bx, by = b.x, b.y
+ local rx, ry = r.x, r.y
+ local rw = rx + r.w
+ local rh = ry + r.h
+ local rd = ry - r.d
+ if left then
+ rx = rx + left
+ rw = rw - right
+ end
+ local bh = by + b.h
+ local bd = by - b.d
+ local area = { }
+ local leftshapes, rightshapes = shapes(r,rx,ry,rw,rh,rd,bd,rd,bh,rd,obeyhang)
+ add(area,bx,bh-ry)
+ for i=1,#rightshapes do
+ local ri = rightshapes[i]
+ add(area,ri[1],ri[2]-ry)
+ end
+ for i=#leftshapes,1,-1 do
+ local li = leftshapes[i]
+ add(area,li[1],li[2]-ry)
+ end
+ add(area,bx,bd-ry)
+ add(area,bx,bh-ry,true) -- finish last straight line (but no add as we cycle)
+ finish(area)
+ for i=1,#area do
+ local a = area[i]
+ area[i] = f_pair(a[1],a[2])
+ end
+ return {
+ location = "first",
+ region = r,
+ area = area,
+ }
+end
+
+local function middlepart(r,left,right,obeyhang)
+ local rx, ry = r.x, r.y
+ local rw = rx + r.w
+ local rh = ry + r.h
+ local rd = ry - r.d
+ if left then
+ rx = rx + left
+ rw = rw - right
+ end
+ local area = { }
+ local leftshapes, rightshapes = shapes(r,rx,ry,rw,rh,rd,rh,rd,rh,rd,obeyhang)
+ for i=#leftshapes,1,-1 do
+ local li = leftshapes[i]
+ add(area,li[1],li[2]-ry)
+ end
+ for i=1,#rightshapes do
+ local ri = rightshapes[i]
+ add(area,ri[1],ri[2]-ry)
+ end
+ finish(area)
+ for i=1,#area do
+ local a = area[i]
+ area[i] = f_pair(a[1],a[2])
+ end
+ return {
+ location = "middle",
+ region = r,
+ area = area,
+ }
+end
+
+local function lastpart(e,r,left,right,obeyhang)
+ local ex, ey = e.x, e.y
+ local rx, ry = r.x, r.y
+ local rw = rx + r.w
+ local rh = ry + r.h
+ local rd = ry - r.d
+ if left then
+ rx = rx + left
+ rw = rw - right
+ end
+ local eh = ey + e.h
+ local ed = ey - e.d
+ local area = { }
+ -- two cases: till end and halfway e line
+ local leftshapes, rightshapes = shapes(r,rx,ry,rw,rh,rd,rh,ed,rh,eh,obeyhang)
+ for i=1,#rightshapes do
+ local ri = rightshapes[i]
+ add(area,ri[1],ri[2]-ry)
+ end
+ add(area,ex,eh-ry)
+ add(area,ex,ed-ry)
+ for i=#leftshapes,1,-1 do
+ local li = leftshapes[i]
+ add(area,li[1],li[2]-ry)
+ end
+ finish(area)
+ for i=1,#area do
+ local a = area[i]
+ area[i] = f_pair(a[1],a[2])
+ end
+ return {
+ location = "last",
+ region = r,
+ area = area,
+ }
+end
+
+graphics = graphics or { }
+local backgrounds = { }
+
+graphics.backgrounds = backgrounds
+
+local function calculatemultipar(tag,obeyhang)
+ local collected = jobpositions.collected
+ local b = collected[f_b_tag(tag)]
+ local e = collected[f_e_tag(tag)]
+ if not b or not e then
+ report_graphics("invalid tag %a",tag)
+ return { }
+ end
+ local br = b.r
+ local er = e.r
+ if not br or not er then
+ report_graphics("invalid region for %a",tag)
+ return { }
+ end
+ local btag, bindex = lpegmatch(splitter,br)
+ local etag, eindex = lpegmatch(splitter,er)
+ if not bindex or not eindex or btag ~= etag then
+ report_graphics("invalid indices for %a",tag)
+ return { }
+ end
+ local bindex = tonumber(bindex)
+ local eindex = tonumber(eindex)
+ -- Here we compensate for columns (in tables): a table can have a set of column
+ -- entries and these are shared. We compensate left/right based on the columns
+ -- x and w but need to take the region into acount where the specification was
+ -- flushed and not the begin pos's region, because otherwise we get the wrong
+ -- compensation for assymetrical doublesided layouts.
+ local left = 0
+ local right = 0
+ local rc = b.c
+ if rc then
+ rc = collected[rc]
+ if rc then
+ local tb = collected[rc.r]
+ if tb then
+ left = -(tb.x - rc.x)
+ right = (tb.w - rc.w - left) -- tb.x - rc.x
+ end
+ end
+ end
+ -- Obeying intermediate changes of left/rightskip makes no sense as it will
+ -- look bad, so we only look at the begin situation.
+ --
+ local bn = b.n
+ if bn then
+ local bp = collected[f_p_tag(bn)]
+ if bp then
+ left = left + bp.ls
+ right = right + bp.rs
+ end
+ end
+ --
+ if bindex == eindex then
+ return {
+ list = { [b.p] = { singlepart(b,e,collected[br],left,right,obeyhang) } },
+ bpos = b,
+ epos = e,
+ }
+ else
+ local list = {
+ [b.p] = { firstpart(b,collected[br],left,right,obeyhang) },
+ }
+ for i=bindex+1,eindex-1 do
+ br = f_tag_two(btag,i)
+ local r = collected[br]
+ if not r then
+ report_graphics("invalid middle for %a",br)
+ else
+ local p = r.p
+ local pp = list[p]
+ if pp then
+ pp[#pp+1] = middlepart(r,left,right,obeyhang)
+ else
+ list[p] = { middlepart(r,left,right,obeyhang) }
+ end
+ end
+ end
+ local p = e.p
+ local pp = list[p]
+ if pp then
+ pp[#pp+1] = lastpart(e,collected[er],left,right,obeyhang)
+ else
+ list[p] = { lastpart(e,collected[er],left,right,obeyhang) }
+ end
+ return {
+ list = list,
+ bpos = b,
+ epos = e,
+ }
+ end
+end
+
+-- local pending = { } -- needs gc
+--
+-- local function register(data,n,anchor)
+-- local pa = pending[anchor]
+-- if not pa then
+-- pa = { }
+-- pending[anchor] = pa
+-- end
+-- for page, pagedata in next, data do
+-- local pap = pa[page]
+-- if pap then
+-- pap[#pap+1] = n
+-- else
+-- pa[page] = { n }
+-- end
+-- end
+-- end
+--
+-- function backgrounds.registered(anchor,page)
+-- local pa = pending[anchor]
+-- if pa then
+-- concat(pa,",")
+-- else
+-- return ""
+-- end
+-- end
+
+local pbg = { } -- will move to pending
+
+function backgrounds.calculatemultipar(n)
+ if not pbg[n] then
+ pbg[n] = calculatemultipar("pbg",n) or { }
+ end
+end
+
+local multilocs = {
+ single = 1, -- maybe 0
+ first = 1,
+ middle = 2,
+ last = 3,
+}
+
+-- if unknown context_abck : input mp-abck.mpiv ; fi ;
+
+local f_template_a = [[
+path multiregs[], multipars[], multibox ;
+string multikind[] ;
+numeric multilocs[], nofmultipars ;
+nofmultipars := %s ;
+multibox := unitsquare xyscaled (%p,%p) ;
+numeric par_strut_height, par_strut_depth, par_line_height ;
+par_strut_height := %p ;
+par_strut_depth := %p ;
+par_line_height := %p ;
+]]
+
+local f_template_b = [[
+multilocs[%s] := %s ;
+multikind[%s] := "%s" ;
+multipars[%s] := (%--t--cycle) shifted - (%p,%p) ;
+]]
+
+local f_template_c = [[
+multiregs[%s] := (%--t--cycle) shifted - %s ;
+]]
+
+local f_template_d = [[
+setbounds currentpicture to multibox ;
+]]
+
+f_template_a = formatters[f_template_a]
+f_template_b = formatters[f_template_b]
+f_template_c = formatters[f_template_c]
+f_template_d = formatters[f_template_d]
+
+function backgrounds.fetchmultipar(n,anchor,page,obeyhang)
+ local data = pbg[n]
+ if not data then
+ data = calculatemultipar(n,obeyhang)
+ pbg[n] = data -- can be replaced by register
+ -- register(data.list,n,anchor)
+ end
+ if data then
+ local list = data.list
+ if list then
+ local pagedata = list[page]
+ if pagedata then
+ local nofmultipars = #pagedata
+ -- report_graphics("fetching %a at page %s using anchor %a containing %s multipars",n,page,anchor,nofmultipars)
+ local a = jobpositions.collected[anchor]
+ if not a then
+ report_graphics("missing anchor %a",anchor)
+ else
+ local trace = false
+ local x, y, w, h, d = a.x, a.y, a.w, a.h, a.d
+ local bpos = data.bpos
+ local bh, bd = bpos.h, bpos.d
+ local result = { f_template_a(nofmultipars,w,h+d,bh,bd,bh+bd) }
+ for i=1,nofmultipars do
+ local region = pagedata[i]
+ result[#result+1] = f_template_b(
+ i, multilocs[region.location],
+ i, region.location,
+ i, region.area, x, y-region.region.y)
+ if trace then
+ result[#result+1] = f_template_c(i, regionarea(region.region), offset)
+ end
+ end
+ data[page] = nil
+ result[#result+1] = f_template_d()
+ result = concat(result,"\n")
+ return result
+ end
+ end
+ end
+ end
+ return f_template_a(0,"origin",0,0,0)
+end
+
+backgrounds.point = f_point
+backgrounds.pair = f_pair
+backgrounds.path = f_path
+
+function commands.fetchmultipar(n,anchor,page)
+ context(backgrounds.fetchmultipar(n,anchor,page))
+end
+
+function commands.fetchmultishape(n,anchor,page)
+ context(backgrounds.fetchmultipar(n,anchor,page,true))
+end
+
+local f_template_a = [[
+path posboxes[], posregions[] ;
+numeric pospages[] ;
+numeric nofposboxes ;
+nofposboxes := %s ;
+%t ;
+]]
+
+local f_template_b = [[
+pospages[%s] := %s ;
+posboxes[%s] := (%p,%p)--(%p,%p)--(%p,%p)--(%p,%p)--cycle ;
+posregions[%s] := (%p,%p)--(%p,%p)--(%p,%p)--(%p,%p)--cycle ;
+]]
+
+f_template_a = formatters[f_template_a]
+f_template_b = formatters[f_template_b]
+
+function commands.fetchposboxes(tags,anchor,page) -- no caching (yet) / todo: anchor, page
+ local collected = jobpositions.collected
+ if type(tags) == "string" then
+ tags = utilities.parsers.settings_to_array(tags)
+ end
+ local list, nofboxes = { }, 0
+ for i=1,#tags do
+ local tag= tags[i]
+ local c = collected[tag]
+ if c then
+ local r = c.r
+ if r then
+ r = collected[r]
+ if r then
+ local rx, ry, rw, rh, rd = r.x, r.y, r.w, r.h, r.d
+ local cx = c.x - rx
+ local cy = c.y - ry
+ local cw = cx + c.w
+ local ch = cy + c.h
+ local cd = cy - c.d
+ nofboxes = nofboxes + 1
+ list[nofboxes] = f_template_b(
+ nofboxes,c.p,
+ nofboxes,cx,ch,cw,ch,cw,cd,cx,cd,
+ nofboxes,0,rh,rw,rh,rw,rd,0,rd
+ )
+ end
+ end
+ else
+ print("\n missing",tag)
+ end
+ end
+ context(f_template_a(nofboxes,list))
+end
+
+local doifelse = commands.doifelse
+
+function commands.doifelsemultipar(n,page,obeyhang)
+ local data = pbg[n]
+ if not data then
+ data = calculatemultipar(n,obeyhang)
+ pbg[n] = data
+ end
+ if page then
+ doifelse(data and data[page] and true)
+ else
+ doifelse(data and next(data) and true)
+ end
+end
+
+function commands.doifelserangeonpage(first,last,page)
+ local collected = jobpositions.collected
+ local f = collected[first]
+ if not f then
+ doifelse(false)
+ return
+ end
+ local l = collected[last]
+ if not l then
+ doifelse(false)
+ return
+ end
+ doifelse(page >= f.p and page <= l.p)
+end