summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/anch-pgr.lua
diff options
context:
space:
mode:
authorHans Hagen <pragma@wxs.nl>2017-01-17 18:05:46 +0100
committerContext Git Mirror Bot <phg42.2a@gmail.com>2017-01-17 18:05:46 +0100
commit0cfeab235554eeee0dddd6c3f44d3939ab490ff1 (patch)
treefed70e9a3332741e5294a01197c716dff8556506 /tex/context/base/mkiv/anch-pgr.lua
parent72d161c0a522fd92f32edd3588fa126c453f4a3d (diff)
downloadcontext-0cfeab235554eeee0dddd6c3f44d3939ab490ff1.tar.gz
2017-01-17 17:43:00
Diffstat (limited to 'tex/context/base/mkiv/anch-pgr.lua')
-rw-r--r--tex/context/base/mkiv/anch-pgr.lua1241
1 files changed, 834 insertions, 407 deletions
diff --git a/tex/context/base/mkiv/anch-pgr.lua b/tex/context/base/mkiv/anch-pgr.lua
index fa5d50de8..5c79f70a1 100644
--- a/tex/context/base/mkiv/anch-pgr.lua
+++ b/tex/context/base/mkiv/anch-pgr.lua
@@ -7,249 +7,444 @@ if not modules then modules = { } end modules ['anch-pgr'] = {
}
-- This is a bit messy module but backgrounds are messy anyway. Especially when we want to
--- follow shapes. This is work in progress (and always will be).
+-- follow shapes. This will always be work in progress as it also depends on new features
+-- in context.
+--
+-- Alas, shapes and inline didn't work as expected end of 2016 so I had to pick up this
+-- thread again. But with regular excursions to listening to Brad Mehldau's Mehliana I
+-- could keep myself motivated. Some old stuff has been removed, some suboptimal code has
+-- been replaced. Background code is still not perfect, but some day ... the details manual
+-- will discuss this issue.
-local format = string.format
-local abs = math.abs
+local abs, div, floor, round = math.abs, math.div, math.floor, math.round
local concat, sort, copy = table.concat, table.sort, table.copy
local splitter = lpeg.splitat(":")
local lpegmatch = lpeg.match
-local jobpositions = job.positions
-local formatters = string.formatters
+local jobpositions = job.positions
+local formatters = string.formatters
+local setmetatableindex = table.setmetatableindex
-local commands = commands
-local context = context
+local commands = commands
+local context = context
-local implement = interfaces.implement
+local implement = interfaces.implement
-local report_graphics = logs.reporter("graphics")
+local report_graphics = logs.reporter("backgrounds")
+local report_shapes = logs.reporter("backgrounds","shapes")
+local report_free = logs.reporter("backgrounds","free")
-local f_b_tag = formatters["b:%s"]
-local f_e_tag = formatters["e:%s"]
-local f_p_tag = formatters["p:%s"]
+local trace_shapes = false trackers.register("backgrounds.shapes", function(v) trace_shapes = v end)
+local trace_free = false trackers.register("backgrounds.shapes.free",function(v) trace_free = v end)
-local f_tag_two = formatters["%s:%s"]
+local f_b_tag = formatters["b:%s"]
+local f_e_tag = formatters["e:%s"]
+local f_p_tag = formatters["p:%s"]
-local f_point = formatters["%p"]
-local f_pair = formatters["(%p,%p)"]
-local f_path = formatters["%--t--cycle"]
+local f_tag_two = formatters["%s:%s"]
-graphics = graphics or { }
-local backgrounds = { }
-graphics.backgrounds = backgrounds
+local f_point = formatters["%p"]
+local f_pair = formatters["(%p,%p)"]
+local f_path = formatters["%--t--cycle"]
+local f_pair_i = formatters["(%i,%i)"]
-local function regionarea(r)
- local rx = r.x
- local ry = 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
+graphics = graphics or { }
+local backgrounds = { }
+graphics.backgrounds = backgrounds
--- we can use a 'local t, n' and reuse the table
+-- -- --
-local eps = 2
+local texsetattribute = tex.setattribute
+local texgetcount = tex.getcount
+local pdfgetpos = pdf.getpos -- why not a generic name !
-local function add(t,x,y,direction,last)
- local n = #t
- if n == 0 then
- t[n+1] = { x, y }
+local a_textbackground = attributes.private("textbackground")
+
+local nuts = nodes.nuts
+
+local new_latelua = nuts.pool.latelua
+
+local getbox = nuts.getbox
+local getlist = nuts.getlist
+
+local insert_before = nuts.insert_before
+local insert_after = nuts.insert_after
+
+local processranges = nodes.processranges
+
+local v_yes = interfaces.variables.yes
+local v_always = interfaces.variables.always
+
+local jobpositions = job.positions
+
+local data = { }
+local realpage = 1
+local recycle = 1000 -- only tables can overflow this
+local enabled = false
+
+-- Freeing the data is somewhat tricky as we can have backgrounds spanning
+-- many pages but for an arbitrary background shape that is not so common.
+
+local function registerbackground(name)
+ local n = #data + 1
+ if n > recycle then
+ n = 1
+ end
+ local b = jobpositions.tobesaved["b:"..name]
+ if b then
+ local s = setmetatableindex("table")
+ b.s = s
+ data[n] = {
+ bpos = b,
+ name = name,
+ n = n,
+ shapes = s,
+ count = 0,
+ }
+ texsetattribute(a_textbackground,n)
+ enabled = true
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
- 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
- tn[1] = x -- hm
- elseif abs(lx-px) <= eps and abs(lx-x) <= eps then
- if abs(ly-y) > eps then
- tn[2] = y
- end
- t[n+1] = { x, y }
- elseif abs(ly-py) <= eps and abs(ly-y) <= eps then
- if abs(lx-x) > eps then
- tn[1] = x
+ texsetattribute(a_textbackground,attributes.unsetvalue)
+ end
+end
+
+local function check(d,where)
+ -- this is not yet r2l ready
+ local w = d.shapes[realpage]
+ local x, y = pdfgetpos()
+ local n = #w
+ if n == 0 then
+ w[n+1] = { x, x, y }
+ elseif where == "r" then
+ local w0 = w[n]
+ if n > 2 then
+ local w2 = w[n-2]
+ if w2[2] == x then
+ local w1 = w[n-1]
+ if w1[2] == x then
+ local xx = w1[1]
+ if w2[1] == xx and xx == w0[1] then
+ w1[3] = w0[3]
+ w[n] = nil
+ return
+ end
end
- t[n+1] = { x, y }
- elseif not last then
- t[n+1] = { x, y }
end
end
+ w0[2] = x
+ elseif w[n][3] == y then
+ -- we have another one in the same line
+ -- w[n][2] = x
+ else
+ w[n+1] = { x, x, y }
end
end
--- local function add(t,x,y,last)
--- t[#t+1] = { x, y }
--- end
+local function flush(head,f,l,a,parent)
+ local d = data[a]
+ if d then
+ head, f = insert_before(head,f,new_latelua(function() check(d,"l") end))
+ head, l = insert_after (head,l,new_latelua(function() check(d,"r") end))
+ end
+ return head, true
+end
-local function finish(t) -- circulair list
- 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
+local function collectbackgrounds(r,n)
+ if enabled then
+ local parent = getbox(n)
+ local head = getlist(parent)
+ realpage = r
+ processranges(a_textbackground,flush,head) -- ,parent)
end
end
-local function clip(t,ytop,ybot)
- local first = 1
- local last = #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
+interfaces.implement {
+ name = "collectbackgrounds",
+ actions = collectbackgrounds,
+ arguments = { "integer", "integer" }
+}
+
+interfaces.implement {
+ name = "registerbackground",
+ actions = registerbackground,
+ arguments = { "string" }
+}
+
+-- optimized already but we can assume a cycle i.e. prune the last point and then
+-- even less code .. we could merge some loops but his is more robust
+
+local function topairs(t,n)
+ local r = { }
+ for i=1,n do
+ local ti = t[i]
+ r[i] = f_pair_i(ti[1]/65556,ti[2]/65536)
+ end
+ return concat(r," ")
+end
+
+local eps = 65536 / 4 -- 2
+local pps = eps
+local nps = - pps
+
+local function unitvector(x,y)
+ if x < pps and x > nps then
+ x = 0
+ elseif x < 0 then
+ x = -1
+ else
+ x = 1
end
- -- or just reuse t
- local lp = { { t[first][1], ytop } }
- local ln = 2
- for i=first+1,last-1 do
- -- lp[ln] = { t[i][1], t[i][2] }
- lp[ln] = t[i]
- ln = ln + 1
+ if y < pps and y > nps then
+ y = 0
+ elseif y < 0 then
+ y = -1
+ else
+ y = 1
end
- lp[ln] = { t[last][1], ybot }
- return lp
+ return x, y
end
--- todo: mark regions and free paragraphs in collected
-
--- 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 function shapes(r,rx,ry,rw,rh,rd,lytop,lybot,rytop,rybot,obeyhang)
- local delta = r2l and (rw - rx) or 0
- local xleft = rx + delta
- local xright = rw - delta
- local paragraphs = r.paragraphs
- local leftshape = { { xleft, rh } } -- spikes get removed so we can start at the edge
- local rightshape = { { xright, rh } } -- even if we hang next
- local extending = false
-
- if obeyhang and paragraphs and #paragraphs > 0 then
-
- for i=1,#paragraphs do
- local p = paragraphs[i]
- local ha = p.ha
- if 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
- if ha < 0 then
- if hi < 0 then
- -- right top
- add(rightshape,xright, py_ph, "down") -- "up"
- add(rightshape,xright + hi,py_ph, "down") -- "up"
- add(rightshape,xright + hi,py_ph + hang,"down") -- "up"
- add(rightshape,xright, py_ph + hang,"down") -- "up"
- else
- -- left top
- add(leftshape,xleft, py_ph, "down")
- add(leftshape,xleft + hi,py_ph, "down")
- add(leftshape,xleft + hi,py_ph + hang,"down")
- add(leftshape,xleft, py_ph + hang,"down")
- end
+local function finish(t)
+ local tm = #t
+ if tm < 2 then
+ return
+ end
+ if trace_shapes then
+ report_shapes("initial list: %s",topairs(t,tm))
+ end
+ -- remove similar points
+ local n = 1
+ local tn = tm
+ local tf = t[1]
+ local tx = tf[1]
+ local ty = tf[2]
+ for i=2,#t do
+ local ti = t[i]
+ local ix = ti[1]
+ local iy = ti[2]
+ local dx = ix - tx
+ local dy = iy - ty
+ if dx > eps or dx < - eps or dy > eps or dy < - eps then
+ n = n + 1
+ t[n] = ti
+ tx = ix
+ ty = iy
+ end
+ end
+ if trace_shapes then
+ report_shapes("removing similar points: %s",topairs(t,n))
+ end
+ if n > 2 then
+ -- remove redundant points
+ repeat
+ tn = n
+ n = 0
+ local tm = t[tn]
+ local tmx = tm[1]
+ local tmy = tm[2]
+ local tp = t[1]
+ local tpx = tp[1]
+ local tpy = tp[2]
+ for i=1,tn do -- while and only step when done
+ local ti = tp
+ local tix = tpx
+ local tiy = tpy
+ if i == tn then
+ tp = t[1]
+ else
+ tp = t[i+1]
+ end
+ tpx = tp[1]
+ tpy = tp[2]
+
+ local vx1, vx2 = unitvector(tix - tmx,tpx - tix)
+ if vx1 ~= vx2 then
+ n = n + 1
+ t[n] = ti
else
- -- maybe some day
+ local vy1, vy2 = unitvector(tiy - tmy,tpy - tiy)
+ if vy1 ~= vy2 then
+ n = n + 1
+ t[n] = ti
+ end
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, xleft + l, py_ph,"up")
- add(rightshape,xright + l + w, py_ph,"down")
- py_ph = py_ph - step
- add(leftshape, xleft + l, py_ph,"up")
- add(rightshape,xright + l + w, py_ph,"down")
+
+ tmx = tix
+ tmy = tiy
+ end
+ until n == tn or n <= 2
+ if trace_shapes then
+ report_shapes("removing redundant points: %s",topairs(t,n))
+ end
+ -- remove spikes
+ if n > 2 then
+ repeat
+ tn = n
+ n = 0
+ local tm = t[tn]
+ local tmx = tm[1]
+ local tmy = tm[2]
+ local tp = t[1]
+ local tpx = tp[1]
+ local tpy = tp[2]
+ for i=1,tn do -- while and only step when done
+ local ti = tp
+ local tix = tpx
+ local tiy = tpy
+ if i == tn then
+ tp = t[1]
+ else
+ tp = t[i+1]
+ end
+ tpx = tp[1]
+ tpy = tp[2]
+
+ local vx1, vx2 = unitvector(tix - tmx,tpx - tix)
+ if vx1 ~= - vx2 then
+ n = n + 1
+ t[n] = ti
+ else
+ local vy1, vy2 = unitvector(tiy - tmy,tpy - tiy)
+ if vy1 ~= - vy2 then
+ n = n + 1
+ t[n] = ti
+ end
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, xleft ,py_ph,"up") -- shouldn't this be py_pd
- add(rightshape,xright,py_ph,"down") -- shouldn't this be py_pd
- extending = false
+
+ tmx = tix
+ tmy = tiy
end
+ until n == tn or n <= 2
+ if trace_shapes then
+ report_shapes("removing spikes: %s",topairs(t,n))
end
end
- -- we can have a simple variant when no paragraphs
- if extending then
- -- not ok
- leftshape [#leftshape] [2] = rd
- rightshape[#rightshape][2] = rd
+ end
+ -- prune trailing points
+ if tm > n then
+ for i=tm,n+1,-1 do
+ t[i] = nil
+ end
+ end
+ if n > 1 then
+ local tf = t[1]
+ local tl = t[n]
+ local dx = tf[1] - tl[1]
+ local dy = tf[2] - tl[2]
+ if dx > eps or dx < - eps or dy > eps or dy < - eps then
+ -- different points
else
- add(leftshape, xleft ,rd,"up")
- add(rightshape,xright,rd,"down")
+ -- saves a point (as we -- cycle anyway)
+ t[n] = nil
+ n = n -1
+ end
+ if trace_shapes then
+ report_shapes("removing cyclic endpoints: %s",topairs(t,n))
end
+ end
+ return t
+end
- else
- leftshape [2] = { xleft, rd }
- rightshape[2] = { xright, rd }
+local eps = 65536
+
+-- The next function can introduce redundant points but these are removed later on
+-- in the unspiker. It makes checking easier.
+
+local function shape(kind,b,p,realpage,xmin,xmax,ymin,ymax,fh,ld)
+ local s = b.s
+ if not s then
+ if trace_shapes then
+ report_shapes("calculating %s area, no shape",kind)
+ end
+ return
+ end
+ s = s[realpage]
+ if not s then
+ if trace_shapes then
+ report_shapes("calculating %s area, no shape for page %s",kind,realpage)
+ end
+ return
+ end
+ local ns = #s
+ if ns == 0 then
+ if trace_shapes then
+ report_shapes("calculating %s area, empty shape for page %s",kind,realpage)
+ end
+ return
+ end
+ --
+ if trace_shapes then
+ report_shapes("calculating %s area, using shape for page %s",kind,realpage)
+ end
+ -- it's a bit inefficient to use the par values and later compensate for b and
+ -- e but this keeps the code (loop) cleaner
+ local ph = p and p.h or 0
+ local pd = p and p.d or 0
+ --
+ xmax = xmax + eps
+ xmin = xmin - eps
+ ymax = ymax + eps
+ ymin = ymin - eps
+ local ls = { } -- left shape
+ local rs = { } -- right shape
+ local pl = nil -- previous left x
+ local pr = nil -- previous right x
+ local n = 0
+ for i=1,ns do
+ local si = s[i]
+ local xl = si[1]
+ local xr = si[2]
+ local y = si[3]
+ local xm = xl + (xr - xl)/2 -- midpoint should be in region
+ if xm >= xmin and xm <= xmax and y >= ymin and y <= ymax then
+ local h = y + ph
+ local d = y - pd
+ if pl then
+ n = n + 1
+ ls[n] = { pl, h }
+ rs[n] = { pr, h }
+ end
+ n = n + 1
+ ls[n] = { xl, h }
+ rs[n] = { xr, h }
+ n = n + 1
+ ls[n] = { xl, d }
+ rs[n] = { xr, d }
+ end
+ pl, pr = xl, xr
+ end
+ --
+ if true and n > 0 then
+ -- use height of b and depth of e, maybe check for weird border
+ -- cases here
+ if fh then
+ ls[1][2] = fh
+ rs[1][2] = fh
+ end
+ if fd then
+ ls[n][2] = fd
+ rs[n][2] = fd
+ end
+ end
+ --
+ for i=n,1,-1 do
+ n = n + 1 rs[n] = ls[i]
end
- leftshape = clip(leftshape,lytop,lybot)
- rightshape = clip(rightshape,rytop,rybot)
- return leftshape, rightshape
+ return rs
end
-local function singlepart(b,e,r,left,right,obeyhang)
+local function singlepart(b,e,p,realpage,r,left,right)
local bx, by = b.x, b.y
local ex, ey = e.x, e.y
local rx, ry = r.x, r.y
+ local bh, bd = by + b.h, by - b.d
+ local eh, ed = ey + e.h, ey - e.d
+ local rh, rd = ry + r.h, ry - r.d
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
@@ -258,175 +453,160 @@ local function singlepart(b,e,r,left,right,obeyhang)
end
local area
if by == ey then
+ if trace_shapes then
+ report_shapes("calculating single area, partial line")
+ end
+ area = {
+ { bx, bh },
+ { ex, eh },
+ { ex, ed },
+ { bx, bd },
+ }
+ elseif b.k == 2 then
area = {
- f_pair(bx,bh-ry),
- f_pair(ex,eh-ry),
- f_pair(ex,ed-ry),
- f_pair(bx,bd-ry),
+ { rx, bh },
+ { rw, bh },
+ { rw, ed },
+ { rx, ed },
}
else
- area = { }
- local leftshapes, rightshapes = shapes(r,rx,ry,rw,rh,rd,bd,ed,bh,eh,obeyhang,b.r2l)
-
- -- needed for shapes
-
- bx = leftshapes[1][1]
- ex = rightshapes[#rightshapes][1]
-
- --
-
- 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,nil,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
+ area = shape("single",b,p,realpage,rx,rw,rd,rh,bh,ed)
+ end
+ if not area then
+ area = {
+ { bx, bh },
+ { rw, bh },
+ { rw, eh },
+ { ex, eh },
+ { ex, ed },
+ { rx, ed },
+ { rx, bd },
+ { bx, bd },
+ }
end
return {
location = "single",
region = r,
- area = area,
+ area = finish(area),
}
end
-local function firstpart(b,r,left,right,obeyhang)
+local function firstpart(b,e,p,realpage,r,left,right)
local bx, by = b.x, b.y
local rx, ry = r.x, r.y
+ local bh, bd = by + b.h, by - b.d
+ local rh, rd = ry + r.h, ry - r.d
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,b.r2l)
- 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,nil,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])
+ local area = shape("first",b,p,realpage,rx,rw,rd,rh,bh,false)
+ if not area then
+ if b.k == 2 then
+ area = {
+ { rx, bh },
+ { rw, bh },
+ { rw, rd },
+ { rx, rd },
+ }
+ else
+ area = {
+ { bx, bh },
+ { rw, bh },
+ { rw, rd }, -- { rw, eh },
+ { rx, rd }, -- { rx, ed },
+ { rx, bd },
+ { bx, bd },
+ }
+ end
end
return {
location = "first",
region = r,
- area = area,
+ area = finish(area),
}
end
-local function middlepart(r,left,right,obeyhang)
- local rx = r.x
- local ry = r.y
+local function middlepart(b,e,p,realpage,r,left,right)
+ local rx, ry = r.x, r.y
+ local rh, rd = ry + r.h, ry - r.d
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])
+ local area = shape("middle",b,p,realpage,rx,rw,rd,rh,false,false)
+ if not area then
+ area = {
+ { rw, rh },
+ { rw, rd },
+ { rx, rd },
+ { rx, rh },
+ }
end
return {
location = "middle",
region = r,
- area = area,
+ area = finish(area),
}
end
-local function lastpart(e,r,left,right,obeyhang)
+local function lastpart(b,e,p,realpage,r,left,right)
local ex, ey = e.x, e.y
local rx, ry = r.x, r.y
+ local eh, ed = ey + e.h, ey - e.d
+ local rh, rd = ry + r.h, ry - r.d
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,e.r2l)
- 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])
+ local area = shape("last",b,p,realpage,rx,rw,rd,rh,false,ed)
+ if not area then
+ if b.k == 2 then
+ area = {
+ { rw, rh },
+ { rw, ed },
+ { rx, ed },
+ { rx, rh },
+ }
+ else
+ area = {
+ { rw, rh }, -- { rw, bh },
+ { rw, eh },
+ { ex, eh },
+ { ex, ed },
+ { rx, ed },
+ { rx, rh }, -- { rx, bd },
+ }
+ end
end
return {
location = "last",
region = r,
- area = area,
+ area = finish(area),
}
end
-local function calculatemultipar(tag,obeyhang)
+local function calculatemultipar(tag)
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)
+ report_shapes("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)
+ report_shapes("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)
+ report_shapes("invalid indices for %a",tag)
return { }
end
local bindex = tonumber(bindex)
@@ -435,41 +615,42 @@ local function calculatemultipar(tag,obeyhang)
-- 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
+ -- compensation for asymetrical doublesided layouts.
+ local left = 0
local right = 0
- local rc = b.c
+ local bc = b.c
+ local rc = bc and collected[bc]
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
+ local tb = collected[rc.r]
+ if tb then
+ left = -(tb.x - rc.x)
+ right = (tb.w - rc.w - left)
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
+ local p = bn and collected[f_p_tag(bn)] -- par
+ if p then
+ left = left + p.ls
+ right = right + p.rs
+ end
+ --
+ local bp = b.p -- page
+ if trace_shapes then
+ report_shapes("tag %a, left %p, right %p, par %s, page %s, column %s",
+ left,right,bn or "-",bp or "-",bc or "-")
end
--
- local result
if bindex == eindex then
- result = {
- list = { [b.p] = { singlepart(b,e,collected[br],left,right,obeyhang) } },
+ return {
+ list = { [bp] = { singlepart(b,e,p,bp,collected[br],left,right) } },
bpos = b,
epos = e,
}
else
local list = {
- [b.p] = { firstpart(b,collected[br],left,right,obeyhang) },
+ [bp] = { firstpart(b,e,p,bp,collected[br],left,right) },
}
for i=bindex+1,eindex-1 do
br = f_tag_two(btag,i)
@@ -477,68 +658,34 @@ local function calculatemultipar(tag,obeyhang)
if not r then
report_graphics("invalid middle for %a",br)
else
- local p = r.p
- local pp = list[p]
- local mp = middlepart(r,left,right,obeyhang)
+ local rp = r.p -- page
+ local pp = list[rp]
+ local mp = middlepart(b,e,p,rp,r,left,right)
if pp then
pp[#pp+1] = mp
else
- list[p] = { mp }
+ list[rp] = { mp }
end
end
end
- local p = e.p
- local pp = list[p]
- local lp = lastpart(e,collected[er],left,right,obeyhang)
+ local ep = e.p -- page
+ local pp = list[ep]
+ local lp = lastpart(b,e,p,ep,collected[er],left,right)
if pp then
pp[#pp+1] = lp
else
- list[p] = { lp }
+ list[ep] = { lp }
end
- result = {
+ return {
list = list,
bpos = b,
epos = e,
}
end
- return result
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,
@@ -563,51 +710,335 @@ par_line_height := %p ;
local f_template_b = formatters[ [[
multilocs[%s] := %s ;
multikind[%s] := "%s" ;
-multipars[%s] := simplified(%--t--cycle) shifted - (%p,%p) ;
+multipars[%s] := (%--t--cycle) shifted - (%p,%p) ;
]] ]
+-- unspiked(simplified(%--t--cycle)) shifted - (%p,%p) ;
+
local f_template_c = formatters[ [[
setbounds currentpicture to multibox ;
]] ]
-local function 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)
+local function freemultipar(pagedata,frees) -- ,k
+ -- if k == 3 then
+ -- -- tables have local regions
+ -- return
+ -- end
+ if not frees then
+ return
+ end
+ local nfree = #frees
+ if nfree == 0 then
+ return
+ end
+ for i=1,#pagedata do
+ local data = pagedata[i]
+ local area = data.area
+
+ if area then
+
+ local region = data.region
+ local y = 0 -- region.y
+ -- local x = region.x
+ local areas = { }
+ data.areas = areas
+
+ local f_1, n_1 = { }, 0
+ local f_2, n_2 = { }, 0
+ for i=1,#frees do
+ local f = frees[i]
+ local k = f.k
+ if k == 1 then -- pag
+ n_1 = n_1 + 1
+ f_1[n_1] = f
+ elseif k == 2 or k == 3 then -- par
+ n_2 = n_2 + 1
+ f_2[n_2] = f
+ end
+ end
+
+ local lineheight = tex.dimen.lineheight
+
+ -- page floats
+
+ local function check_one(free1,free2)
+ local temp = { }
+ local some = false
+ local top = (free2 and (y + free2.y + free2.h + (free2.to or 0))) or false
+ local bot = (free1 and (y + free1.y - free1.d - (free1.bo or 0))) or false
+ for i=1,#area do
+ local a = area[i]
+ local x = a[1]
+ local y = a[2]
+ if free2 and y <= top then
+ y = top
+ end
+ if free1 and y >= bot then
+ y = bot
+ end
+ if not some then
+ some = y
+ elseif some == true then
+ -- done
+ elseif y ~= some then
+ some = true
+ end
+ temp[i] = { x, y }
+ end
+ if some == true then
+ areas[#areas+1] = temp
+ end
+ end
+
+ if n_1 > 0 then
+ check_one(false,f_1[1])
+ for i=2,n_1 do
+ check_one(f_1[i-1],f_1[i])
+ end
+ check_one(f_1[n_1],false)
+ end
+
+ -- par floats
+
+ if #areas == 0 then
+ areas[1] = area
+ end
+
+ -- we can collect the coordinates first
+
+ local function check_two(area,frees)
+ local ul = area[1]
+ local ur = area[2]
+ local lr = area[3]
+ local ll = area[4]
+ local ulx, uly = ul[1], ul[2]
+ local urx, ury = ur[1], ur[2]
+ local lrx, lry = lr[1], lr[2]
+ local llx, lly = ll[1], ll[2]
+
+ local temp = { }
+ local n = 0
+ local done = false
+
+ for i=1,#frees do
+ local free = frees[i]
+ local fx = free.x
+ local fy = free.y
+ local ymax = y + fy + free.h + (free.to or 0)
+ local ymin = y + fy - free.d - (free.bo or 0)
+ local xmin = fx - (free.lo or 0)
+ local xmax = fx + free.w + (free.ro or 0)
+ if free.k == 3 then
+ if uly <= ymax and uly >= ymin and lly <= ymin then
+ if trace_free then
+ report_free("case 1, top, right") -- ok
+ end
+ n = n + 1 temp[n] = { xmin, ury }
+ n = n + 1 temp[n] = { xmin, ymin }
+ n = n + 1 temp[n] = { lrx, ymin }
+ n = n + 1 temp[n] = { lrx, lry }
+ done = true
+ elseif uly >= ymax and lly <= ymin then
+ if trace_free then
+ report_free("case 2, outside, right") -- ok
+ end
+ if uly - ymax < lineheight then
+ n = n + 1 temp[n] = { xmin, ury }
+ else
+ n = n + 1 temp[n] = { urx, ury }
+ n = n + 1 temp[n] = { urx, ymax }
+ end
+ n = n + 1 temp[n] = { xmin, ymax }
+ n = n + 1 temp[n] = { xmin, ymin }
+ n = n + 1 temp[n] = { lrx, ymin }
+ n = n + 1 temp[n] = { lrx, lry }
+ done = true
+ elseif lly <= ymax and lly >= ymin and uly >= ymax then
+ if trace_free then
+ report_free("case 3, bottom, right")
+ end
+ if uly - ymax < lineheight then
+ n = n + 1 temp[n] = { xmin, ury }
+ else
+ n = n + 1 temp[n] = { urx, ury }
+ n = n + 1 temp[n] = { urx, ymax }
+ end
+ n = n + 1 temp[n] = { xmin, ymax }
+ n = n + 1 temp[n] = { xmin, lry }
+ done = true
+ elseif uly <= ymax and lly >= ymin then
+ if trace_free then
+ report_free("case 4, inside, right")
+ end
+ n = n + 1 temp[n] = { xmin, lly }
+ n = n + 1 temp[n] = { xmin, uly }
+ done = true
+ else
+ -- case 0
+ if trace_free then
+ report_free("case 0, nothing")
+ end
+ end
+ end
+ end
+
+ if not done then
+ if trace_free then
+ report_free("no right shape")
+ end
+ n = n + 1 temp[n] = { urx, ury }
+ n = n + 1 temp[n] = { lrx, lry }
+ n = n + 1 temp[n] = { llx, lly }
+ else
+ done = false
+ end
+
+ for i=#frees,1,-1 do
+ local free = frees[i]
+ local fx = free.x
+ local fy = free.y
+ local ymax = y + fy + free.h + (free.to or 0)
+ local ymin = y + fy - free.d - (free.bo or 0)
+ local xmin = fx - (free.lo or 0)
+ local xmax = fx + free.w + (free.ro or 0)
+ if free.k == 2 then
+ if uly <= ymax and uly >= ymin and lly <= ymin then
+ if trace_free then
+ report_free("case 1, top, left") -- ok
+ end
+ n = n + 1 temp[n] = { ulx, ymin }
+ n = n + 1 temp[n] = { xmax, ymin }
+ n = n + 1 temp[n] = { xmax, uly }
+ done = true
+ elseif uly >= ymax and lly <= ymin then
+ if trace_free then
+ report_free("case 2, outside, left") -- ok
+ end
+ n = n + 1 temp[n] = { llx, lly }
+ n = n + 1 temp[n] = { llx, ymin }
+ n = n + 1 temp[n] = { xmax, ymin }
+ n = n + 1 temp[n] = { xmax, ymax }
+ if uly - ymax < lineheight then
+ n = n + 1 temp[n] = { xmax, uly }
+ else
+ n = n + 1 temp[n] = { llx, ymax }
+ n = n + 1 temp[n] = { llx, uly }
+ end
+ done = true
+ elseif lly <= ymax and lly >= ymin and uly >= ymax then
+ if trace_free then
+ report_free("case 3, bottom, left")
+ end
+ n = n + 1 temp[n] = { xmax, lly }
+ n = n + 1 temp[n] = { xmax, ymax }
+ if uly - ymax < lineheight then
+ n = n + 1 temp[n] = { xmax, uly }
+ else
+ n = n + 1 temp[n] = { llx, ymax }
+ n = n + 1 temp[n] = { llx, uly }
+ end
+ done = true
+ elseif uly <= ymax and lly >= ymin then
+ if trace_free then
+ report_free("case 4, inside, left")
+ end
+ n = n + 1 temp[n] = { xmax, lly }
+ n = n + 1 temp[n] = { xmax, uly }
+ done = true
+ else
+ -- case 0
+ end
+ end
+ end
+
+ if not done then
+ if trace_free then
+ report_free("no left shape")
+ end
+ n = n + 1 temp[n] = { llx, lly }
+ end
+ n = n + 1 temp[n] = { ulx, uly }
+
+ return temp
+ end
+
+ if n_2 > 0 then
+ for i=1,#areas do
+ local area = areas[i]
+ if #area == 4 then -- and also check type, must be pargaraph
+ areas[i] = check_two(area,f_2)
+ else
+ -- message that not yet supported
+ end
+ end
+ end
+
+ for i=1,#areas do
+ finish(areas[i]) -- again
+ end
+
+ end
+
end
- if data then
- local list = data.list
+end
+
+local function fetchmultipar(n,anchor,page)
+ local a = jobpositions.collected[anchor]
+ if not a then
+ report_graphics("missing anchor %a",anchor)
+ else
+ local data = pbg[n]
+ if not data then
+ data = calculatemultipar(n)
+ pbg[n] = data -- can be replaced by register
+ -- register(data.list,n,anchor)
+ end
+ local list = data and data.list
if list then
local pagedata = list[page]
if pagedata then
+ local k = data.bpos.k
+ if k ~= 3 then
+ -- to be checked: no need in txt mode
+ freemultipar(pagedata,jobpositions.free[page])
+ end
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 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_shapes then
+ report_graphics("fetching %a at page %s using anchor %a containing %s multipars",
+ n,page,anchor,nofmultipars)
+ end
+ local x, y = a.x, a.y
+ local w, h, d = a.w, a.h, a.d
+ local bpos = data.bpos
+ local bh, bd = bpos.h, bpos.d
+ local result = { false } -- slot 1 will be set later
+ local n = 0
+ for i=1,nofmultipars do
+ local data = pagedata[i]
+ local location = data.location
+ local region = data.region
+ local areas = data.areas
+ if not areas then
+ areas = { data.area }
+ end
+ for i=1,#areas do
+ local area = areas[i]
+ for i=1,#area do
+ local a = area[i]
+ area[i] = f_pair(a[1],a[2])
+ end
+ n = n + 1
+ result[n+1] = f_template_b(n,multilocs[location],n,location,n,area,x,y)
end
- data[page] = nil
- result[#result+1] = f_template_c()
- result = concat(result,"\n")
- return result
end
+ data[page] = nil
+ result[1] = f_template_a(n,w,h+d,bh,bd,bh+bd) -- was delayed
+ result[n+2] = f_template_c()
+ return concat(result,"\n")
end
end
end
- return f_template_a(0,"origin",0,0,0)
+ return f_template_a(0,0,0,0,0,0);
end
backgrounds.fetchmultipar = fetchmultipar
@@ -624,12 +1055,6 @@ implement {
arguments = { "string", "string", "integer" }
}
-implement {
- name = "fetchmultishape",
- actions = { fetchmultipar, context },
- arguments = { "string", "string", "integer", true }
-}
-
local f_template_a = formatters[ [[
path posboxes[], posregions[] ;
numeric pospages[] ;
@@ -663,7 +1088,7 @@ implement {
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 cy = c.y
local cw = cx + c.w
local ch = cy + c.h
local cd = cy - c.d
@@ -689,17 +1114,19 @@ implement {
name = "doifelserangeonpage",
arguments = { "string", "string", "integer" },
actions = function(first,last,page)
- local collected = jobpositions.collected
- local f = collected[first]
- if not f or f.p == true then
- doifelse(false)
- return
- end
- local l = collected[last]
- if not l or l.p == true then
- doifelse(false)
- return
+ local c = jobpositions.collected
+ local f = c[first]
+ if f then
+ f = f.p
+ if f and f ~= true and page >= f then
+ local l = c[last]
+ if l then
+ l = l.p
+ doifelse(l and l ~= true and page <= l)
+ return
+ end
+ end
end
- doifelse(page >= f.p and page <= l.p)
+ doifelse(false)
end
}