summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/mlib-pdf.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mlib-pdf.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/mlib-pdf.lua275
1 files changed, 129 insertions, 146 deletions
diff --git a/Master/texmf-dist/tex/context/base/mlib-pdf.lua b/Master/texmf-dist/tex/context/base/mlib-pdf.lua
index 352070408c1..8000d5a282e 100644
--- a/Master/texmf-dist/tex/context/base/mlib-pdf.lua
+++ b/Master/texmf-dist/tex/context/base/mlib-pdf.lua
@@ -7,14 +7,22 @@ if not modules then modules = { } end modules ['mlib-pdf'] = {
}
local format, concat, gsub = string.format, table.concat, string.gsub
-local texsprint = tex.sprint
local abs, sqrt, round = math.abs, math.sqrt, math.round
+local setmetatable = setmetatable
+local Cf, C, Cg, Ct, P, S, lpegmatch = lpeg.Cf, lpeg.C, lpeg.Cg, lpeg.Ct, lpeg.P, lpeg.S, lpeg.match
-local copy_node, write_node = node.copy, node.write
+local allocate = utilities.storage.allocate
-local ctxcatcodes = tex.ctxcatcodes
+local report_metapost = logs.reporter("metapost")
+
+local mplib, context = mplib, context
+
+local copy_node = node.copy
+local write_node = node.write
metapost = metapost or { }
+local metapost = metapost
+
metapost.multipass = false
metapost.n = 0
metapost.optimize = true -- false
@@ -61,19 +69,19 @@ metapost.flushers.pdf = { }
local savedliterals = nil
-local mpsliteral = nodes.register(node.new("whatsit",8))
+local mpsliteral = nodes.pool.register(node.new("whatsit",8)) -- pdfliteral
-function metapost.flush_literal(d) -- \def\MPLIBtoPDF#1{\ctxlua{metapost.flush_literal(#1)}}
+function metapost.flushliteral(d) -- \def\MPLIBtoPDF#1{\ctxlua{metapost.flush_literal(#1)}}
if savedliterals then
local literal = copy_node(mpsliteral)
literal.data = savedliterals[d]
write_node(literal)
else
- logs.report("metapost","problem flushing literal %s",d)
+ report_metapost("problem flushing literal %s",d)
end
end
-function metapost.flush_reset()
+function metapost.flushreset() -- will become obsolete and internal
savedliterals = nil
end
@@ -83,10 +91,10 @@ function metapost.flushers.pdf.comment(message)
if savedliterals then
local last = #savedliterals + 1
savedliterals[last] = message
- texsprint(ctxcatcodes,"\\MPLIBtoPDF{",last,"}")
+ context.MPLIBtoPDF(last)
else
savedliterals = { message }
- texsprint(ctxcatcodes,"\\MPLIBtoPDF{1}")
+ context.MPLIBtoPDF(1)
end
end
end
@@ -94,14 +102,14 @@ end
function metapost.flushers.pdf.startfigure(n,llx,lly,urx,ury,message)
savedliterals = nil
metapost.n = metapost.n + 1
- texsprint(ctxcatcodes,format("\\startMPLIBtoPDF{%s}{%s}{%s}{%s}",llx,lly,urx,ury))
+ context.startMPLIBtoPDF(llx,lly,urx,ury)
if message then metapost.flushers.pdf.comment(message) end
end
function metapost.flushers.pdf.stopfigure(message)
if message then metapost.flushers.pdf.comment(message) end
- texsprint(ctxcatcodes,"\\stopMPLIBtoPDF")
- texsprint(ctxcatcodes,"\\ctxlua{metapost.flush_reset()}") -- maybe just at the beginning
+ context.stopMPLIBtoPDF()
+ context.MPLIBflushreset() -- maybe just at the beginning
end
function metapost.flushers.pdf.flushfigure(pdfliterals) -- table
@@ -110,33 +118,30 @@ function metapost.flushers.pdf.flushfigure(pdfliterals) -- table
if savedliterals then
local last = #savedliterals + 1
savedliterals[last] = pdfliterals
- texsprint(ctxcatcodes,"\\MPLIBtoPDF{",last,"}")
+ context.MPLIBtoPDF(last)
else
savedliterals = { pdfliterals }
- texsprint(ctxcatcodes,"\\MPLIBtoPDF{1}")
+ context.MPLIBtoPDF(1)
end
end
end
function metapost.flushers.pdf.textfigure(font,size,text,width,height,depth) -- we could save the factor
text = gsub(text,".","\\hbox{%1}") -- kerning happens in metapost (i have to check if this is true for mplib)
- texsprint(ctxcatcodes,format("\\MPLIBtextext{%s}{%s}{%s}{%s}{%s}",font,size,text,0,-number.dimenfactors.bp*depth))
+ context.MPLIBtextext(font,size,text,0,-number.dimenfactors.bp*depth)
end
local bend_tolerance = 131/65536
local rx, sx, sy, ry, tx, ty, divider = 1, 0, 0, 1, 0, 0, 1
+local pen_info = mplib.pen_info
+
local function pen_characteristics(object)
- if mplib.pen_info then
- local t = mplib.pen_info(object)
- rx, ry, sx, sy, tx, ty = t.rx, t.ry, t.sx, t.sy, t.tx, t.ty
- divider = sx*sy - rx*ry
- return not (sx==1 and rx==0 and ry==0 and sy==1 and tx==0 and ty==0), t.width
- else
- rx, sx, sy, ry, tx, ty, divider = 1, 0, 0, 1, 0, 0, 1
- return false, 1
- end
+ local t = pen_info(object)
+ rx, ry, sx, sy, tx, ty = t.rx, t.ry, t.sx, t.sy, t.tx, t.ty
+ divider = sx*sy - rx*ry
+ return not (sx==1 and rx==0 and ry==0 and sy==1 and tx==0 and ty==0), t.width
end
local function mpconcat(px, py) -- no tx, ty here / we can move this one inline if needed
@@ -155,84 +160,109 @@ local function curved(ith,pth)
end
local function flushnormalpath(path, t, open)
- t = t or { }
- local pth, ith
+ local pth, ith, nt
+ if t then
+ nt = #t
+ else
+ t = { }
+ nt = 0
+ end
for i=1,#path do
+ nt = nt + 1
pth = path[i]
if not ith then
- t[#t+1] = format("%f %f m",pth.x_coord,pth.y_coord)
+ t[nt] = format("%f %f m",pth.x_coord,pth.y_coord)
elseif curved(ith,pth) then
- t[#t+1] = format("%f %f %f %f %f %f c",ith.right_x,ith.right_y,pth.left_x,pth.left_y,pth.x_coord,pth.y_coord)
+ t[nt] = format("%f %f %f %f %f %f c",ith.right_x,ith.right_y,pth.left_x,pth.left_y,pth.x_coord,pth.y_coord)
else
- t[#t+1] = format("%f %f l",pth.x_coord,pth.y_coord)
+ t[nt] = format("%f %f l",pth.x_coord,pth.y_coord)
end
ith = pth
end
if not open then
+ nt = nt + 1
local one = path[1]
if curved(pth,one) then
- t[#t+1] = format("%f %f %f %f %f %f c",pth.right_x,pth.right_y,one.left_x,one.left_y,one.x_coord,one.y_coord )
+ t[nt] = format("%f %f %f %f %f %f c",pth.right_x,pth.right_y,one.left_x,one.left_y,one.x_coord,one.y_coord )
else
- t[#t+1] = format("%f %f l",one.x_coord,one.y_coord)
+ t[nt] = format("%f %f l",one.x_coord,one.y_coord)
end
elseif #path == 1 then
-- special case .. draw point
local one = path[1]
- t[#t+1] = format("%f %f l",one.x_coord,one.y_coord)
+ nt = nt + 1
+ t[nt] = format("%f %f l",one.x_coord,one.y_coord)
end
return t
end
local function flushconcatpath(path, t, open)
- t = t or { }
- t[#t+1] = format("%f %f %f %f %f %f cm", sx, rx, ry, sy, tx ,ty)
- local pth, ith
+ local pth, ith, nt
+ if t then
+ nt = #t
+ else
+ t = { }
+ nt = 0
+ end
+ nt = nt + 1
+ t[nt] = format("%f %f %f %f %f %f cm", sx, rx, ry, sy, tx ,ty)
for i=1,#path do
+ nt = nt + 1
pth = path[i]
if not ith then
- t[#t+1] = format("%f %f m",mpconcat(pth.x_coord,pth.y_coord))
+ t[nt] = format("%f %f m",mpconcat(pth.x_coord,pth.y_coord))
elseif curved(ith,pth) then
local a, b = mpconcat(ith.right_x,ith.right_y)
local c, d = mpconcat(pth.left_x,pth.left_y)
- t[#t+1] = format("%f %f %f %f %f %f c",a,b,c,d,mpconcat(pth.x_coord,pth.y_coord))
+ t[nt] = format("%f %f %f %f %f %f c",a,b,c,d,mpconcat(pth.x_coord,pth.y_coord))
else
- t[#t+1] = format("%f %f l",mpconcat(pth.x_coord, pth.y_coord))
+ t[nt] = format("%f %f l",mpconcat(pth.x_coord, pth.y_coord))
end
ith = pth
end
if not open then
+ nt = nt + 1
local one = path[1]
if curved(pth,one) then
local a, b = mpconcat(pth.right_x,pth.right_y)
local c, d = mpconcat(one.left_x,one.left_y)
- t[#t+1] = format("%f %f %f %f %f %f c",a,b,c,d,mpconcat(one.x_coord, one.y_coord))
+ t[nt] = format("%f %f %f %f %f %f c",a,b,c,d,mpconcat(one.x_coord, one.y_coord))
else
- t[#t+1] = format("%f %f l",mpconcat(one.x_coord,one.y_coord))
+ t[nt] = format("%f %f l",mpconcat(one.x_coord,one.y_coord))
end
elseif #path == 1 then
-- special case .. draw point
+ nt = nt + 1
local one = path[1]
- t[#t+1] = format("%f %f l",mpconcat(one.x_coord,one.y_coord))
+ t[nt] = format("%f %f l",mpconcat(one.x_coord,one.y_coord))
end
return t
end
metapost.flushnormalpath = flushnormalpath
-metapost.specials = metapost.specials or { }
+-- The flusher is pdf based, if another backend is used, we need to overload the
+-- flusher; this is beta code, the organization will change (already upgraded in
+-- sync with mplib)
+--
+-- We can avoid the before table but I like symmetry. There is of course a small
+-- performance penalty, but so is passing extra arguments (result, flusher, after)
+-- and returning stuff.
--- we have two extension handlers, one for pre and postscripts, and one for colors
+local function ignore() end
--- the flusher is pdf based, if another backend is used, we need to overload the
--- flusher; this is beta code, the organization will change
-
-function metapost.flush(result,flusher,askedfig) -- pdf flusher, table en dan concat is sneller, 1 literal
+function metapost.flush(result,flusher,askedfig)
if result then
local figures = result.fig
if figures then
flusher = flusher or metapost.flushers.pdf
- local colorconverter = metapost.colorconverter() -- function !
- local colorhandler = metapost.colorhandler
+ local resetplugins = metapost.resetplugins or ignore
+ local processplugins = metapost.processplugins or ignore
+ local pluginactions = metapost.pluginactions or ignore
+ local startfigure = flusher.startfigure
+ local stopfigure = flusher.stopfigure
+ local flushfigure = flusher.flushfigure
+ local textfigure = flusher.textfigure
for f=1, #figures do
local figure = figures[f]
local objects = getobjects(result,figure,f)
@@ -248,19 +278,18 @@ function metapost.flush(result,flusher,askedfig) -- pdf flusher, table en dan co
metapost.ury = ury
if urx < llx then
-- invalid
- flusher.startfigure(fignum,0,0,0,0,"invalid",figure)
- flusher.stopfigure()
+ startfigure(fignum,0,0,0,0,"invalid",figure)
+ stopfigure()
else
- flusher.startfigure(fignum,llx,lly,urx,ury,"begin",figure)
+ startfigure(fignum,llx,lly,urx,ury,"begin",figure)
t[#t+1] = "q"
if objects then
+ resetplugins() -- we should move the colorinitializer here
t[#t+1] = metapost.colorinitializer()
- -- once we have multiple prescripts we can do more tricky things like
- -- text and special colors at the same time
for o=1,#objects do
local object = objects[o]
local objecttype = object.type
- if objecttype == "start_bounds" or objecttype == "stop_bounds" then
+ if objecttype == "start_bounds" or objecttype == "stop_bounds" or objecttype == "special" then
-- skip
elseif objecttype == "start_clip" then
t[#t+1] = "q"
@@ -269,74 +298,44 @@ function metapost.flush(result,flusher,askedfig) -- pdf flusher, table en dan co
elseif objecttype == "stop_clip" then
t[#t+1] = "Q"
miterlimit, linecap, linejoin, dashed = -1, -1, -1, false
- elseif objecttype == "special" then
- metapost.specials.register(object.prescript)
elseif objecttype == "text" then
t[#t+1] = "q"
local ot = object.transform -- 3,4,5,6,1,2
t[#t+1] = format("%f %f %f %f %f %f cm",ot[3],ot[4],ot[5],ot[6],ot[1],ot[2]) -- TH: format("%f %f m %f %f %f %f 0 0 cm",unpack(ot))
- flusher.flushfigure(t) -- flush accumulated literals
+ flushfigure(t) -- flush accumulated literals
t = { }
- flusher.textfigure(object.font,object.dsize,object.text,object.width,object.height,object.depth)
+ textfigure(object.font,object.dsize,object.text,object.width,object.height,object.depth)
t[#t+1] = "Q"
else
- -- alternatively we can pass on the stack, could be a helper
- -- can be optimized with locals
- local currentobject = { -- not needed when no extensions
- type = object.type,
- miterlimit = object.miterlimit,
- linejoin = object.linejoin,
- linecap = object.linecap,
- color = object.color,
- dash = object.dash,
- path = object.path,
- htap = object.htap,
- pen = object.pen,
- prescript = object.prescript,
- postscript = object.postscript,
- }
- --
- local before, inbetween, after = nil, nil, nil
- --
- local cs, cr = currentobject.color, nil
- -- todo document why ...
- if cs and colorhandler and #cs > 0 and round(cs[1]*10000) == 123 then -- test in function
- currentobject, cr = colorhandler(cs,currentobject,t,colorconverter)
- objecttype = currentobject.type
- end
- --
- local prescript = currentobject.prescript
- if prescript and prescript ~= "" then
- -- move test to function
- local special = metapost.specials[prescript]
- if special then
- currentobject, before, inbetween, after = special(currentobject.postscript,currentobject,t,flusher)
- objecttype = currentobject.type
- end
+ -- we use an indirect table as we want to overload
+ -- entries but this is not possible in userdata
+ local original = object
+ local object = { }
+ setmetatable(object, {
+ __index = original
+ })
+ -- first we analyze
+ local before, after = processplugins(object)
+ local objecttype = object.type -- can have changed
+ if before then
+ t = pluginactions(before,t,flushfigure)
end
- --
- cs = currentobject.color
- if cs and #cs > 0 then
- t[#t+1], cr = colorconverter(cs)
- end
- --
- if before then currentobject, t = before() end
- local ml = currentobject.miterlimit
+ local ml = object.miterlimit
if ml and ml ~= miterlimit then
miterlimit = ml
t[#t+1] = format("%f M",ml)
end
- local lj = currentobject.linejoin
+ local lj = object.linejoin
if lj and lj ~= linejoin then
linejoin = lj
t[#t+1] = format("%i j",lj)
end
- local lc = currentobject.linecap
+ local lc = object.linecap
if lc and lc ~= linecap then
linecap = lc
t[#t+1] = format("%i J",lc)
end
- local dl = currentobject.dash
+ local dl = object.dash
if dl then
local d = format("[%s] %i d",concat(dl.dashes or {}," "),dl.offset)
if d ~= dashed then
@@ -347,14 +346,13 @@ function metapost.flush(result,flusher,askedfig) -- pdf flusher, table en dan co
t[#t+1] = "[] 0 d"
dashed = false
end
- if inbetween then currentobject, t = inbetween() end
- local path = currentobject.path
+ local path = object.path -- newpath
local transformed, penwidth = false, 1
local open = path and path[1].left_type and path[#path].right_type -- at this moment only "end_point"
- local pen = currentobject.pen
+ local pen = object.pen
if pen then
if pen.type == 'elliptical' then
- transformed, penwidth = pen_characteristics(object) -- boolean, value
+ transformed, penwidth = pen_characteristics(original) -- boolean, value
t[#t+1] = format("%f w",penwidth) -- todo: only if changed
if objecttype == 'fill' then
objecttype = 'both'
@@ -383,7 +381,7 @@ function metapost.flush(result,flusher,askedfig) -- pdf flusher, table en dan co
if transformed then
t[#t+1] = "Q"
end
- local path = currentobject.htap
+ local path = object.htap
if path then
if transformed then
t[#t+1] = "q"
@@ -404,16 +402,19 @@ function metapost.flush(result,flusher,askedfig) -- pdf flusher, table en dan co
t[#t+1] = "Q"
end
end
- if cr then
- t[#t+1] = cr
+ if after then
+ t = pluginactions(after,t,flushfigure)
+ end
+ if object.grouped then
+ -- can be qQ'd so changes can end up in groups
+ miterlimit, linecap, linejoin, dashed = -1, -1, -1, false
end
- if after then currentobject, t = after() end
end
- end
+ end
end
t[#t+1] = "Q"
- flusher.flushfigure(t)
- flusher.stopfigure("end")
+ flushfigure(t)
+ stopfigure("end")
end
if askedfig then
break
@@ -428,6 +429,7 @@ function metapost.parse(result,askedfig)
if result then
local figures = result.fig
if figures then
+ local analyzeplugins = metapost.analyzeplugins
for f=1, #figures do
local figure = figures[f]
local fignum = figure:charcode() or 0
@@ -440,17 +442,14 @@ function metapost.parse(result,askedfig)
metapost.ury = ury
local objects = getobjects(result,figure,f)
if objects then
+ -- for o=1,#objects do
+ -- local object = objects[o]
+ -- local prescript = object.prescript
+ -- if prescript then
+ -- analyzeplugins(object)
+ -- end
for o=1,#objects do
- local object = objects[o]
- if object.type == "outline" then
- local prescript = object.prescript
- if prescript then
- local special = metapost.specials[prescript]
- if special then
- special(object.postscript,object)
- end
- end
- end
+ analyzeplugins(objects[o])
end
end
break
@@ -467,15 +466,17 @@ local t = { }
local flusher = {
startfigure = function()
t = { }
- texsprint(ctxcatcodes,"\\startnointerference")
+ context.startnointerference()
end,
flushfigure = function(literals)
+ local n = #t
for i=1, #literals do
- t[#t+1] = literals[i]
+ n = n + 1
+ t[n] = literals[i]
end
end,
stopfigure = function()
- texsprint(ctxcatcodes,"\\stopnointerference")
+ context.stopnointerference()
end
}
@@ -499,7 +500,7 @@ function metapost.totable(result)
local field = fields[f]
tt[field] = object[field]
end
- t[#t+1] = tt
+ t[o] = tt
end
local b = figure:boundingbox()
return {
@@ -510,21 +511,3 @@ function metapost.totable(result)
return nil
end
end
-
--- will be overloaded later
-
-function metapost.colorconverter()
- return function(cr)
- local n = #cr
- if n == 4 then
- local c, m, y, k = cr[1], cr[2], cr[3], cr[4]
- return format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k), "0 g 0 G"
- elseif n == 3 then
- local r, g, b = cr[1], cr[2], cr[3]
- return format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b), "0 g 0 G"
- else
- local s = cr[1]
- return format("%.3f g %.3f G",s,s), "0 g 0 G"
- end
- end
-end