summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/mkiv/mlib-pdf.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkiv/mlib-pdf.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/mlib-pdf.lua598
1 files changed, 310 insertions, 288 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkiv/mlib-pdf.lua b/Master/texmf-dist/tex/context/base/mkiv/mlib-pdf.lua
index 92fde5e1369..75f810fb33b 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/mlib-pdf.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/mlib-pdf.lua
@@ -6,8 +6,9 @@ if not modules then modules = { } end modules ['mlib-pdf'] = {
license = "see context related readme files",
}
-local gsub = string.gsub
-local concat, insert, remove = table.concat, table.insert, table.remove
+-- maybe %s is better than %f
+
+local format, concat, gsub = string.format, table.concat, string.gsub
local abs, sqrt, round = math.abs, math.sqrt, math.round
local setmetatable, rawset, tostring, tonumber, type = setmetatable, rawset, tostring, tonumber, type
local P, S, C, Ct, Cc, Cg, Cf, Carg = lpeg.P, lpeg.S, lpeg.C, lpeg.Ct, lpeg.Cc, lpeg.Cg, lpeg.Cf, lpeg.Carg
@@ -40,34 +41,23 @@ local pdfflusher = { }
metapost.flushers.pdf = pdfflusher
metapost.n = 0
+metapost.optimize = true -- false
local experiment = true -- uses context(node) that already does delayed nodes
local savedliterals = nil -- needs checking
-local mpsliteral = nodes.pool.originliteral
-
-local f_f = formatters["%.6F"]
-local f_m = formatters["%.6F %.6F m"]
-local f_c = formatters["%.6F %.6F %.6F %.6F %.6F %.6F c"]
-local f_l = formatters["%.6F %.6F l"]
-local f_cm = formatters["%.6F %.6F %.6F %.6F %.6F %.6F cm"]
-local f_M = formatters["%.6F M"]
+local mpsliteral = nodes.pool.register(node.new("whatsit",nodes.whatsitcodes.pdfliteral)) -- pdfliteral.mode = 1
+
+local f_f = formatters["%F"]
+
+local f_m = formatters["%F %F m"]
+local f_c = formatters["%F %F %F %F %F %F c"]
+local f_l = formatters["%F %F l"]
+local f_cm = formatters["%F %F %F %F %F %F cm"]
+local f_M = formatters["%F M"]
local f_j = formatters["%i j"]
local f_J = formatters["%i J"]
-local f_d = formatters["[%s] %.6F d"]
-local f_w = formatters["%.3F w"]
-
-directives.register("metapost.stripzeros",function()
- f_f = formatters["%.6N"]
- f_m = formatters["%.6N %.6N m"]
- f_c = formatters["%.6N %.6N %.6N %.6N %.6N %.6N c"]
- f_l = formatters["%.6N %.6N l"]
- f_cm = formatters["%.6N %.6N %.6N %.6N %.6N %.6N cm"]
- f_M = formatters["%.6N M"]
- f_j = formatters["%i j"]
- f_J = formatters["%i J"]
- f_d = formatters["[%s] %.6N d"]
- f_w = formatters["%.3N w"]
-end)
+local f_d = formatters["[%s] %F d"]
+local f_w = formatters["%F w"]
directives.register("metapost.savetable",function(v)
if type(v) == "string" then
@@ -83,28 +73,60 @@ trackers.register("metapost.forcestroke",function(v)
force_stroke = v
end)
+local pdfliteral = function(pdfcode)
+ local literal = copy_node(mpsliteral)
+ literal.data = pdfcode
+ return literal
+end
+
-- Because in MKiV we always have two passes, we save the objects. When an extra
-- mp run is done (due to for instance texts identifier in the parse pass), we
-- get a new result table and the stored objects are forgotten. Otherwise they
-- are reused.
local function getobjects(result,figure,index)
- return figure:objects()
+ if metapost.optimize then
+ local robjects = result.objects
+ if not robjects then
+ robjects = { }
+ result.objects = robjects
+ end
+ local fobjects = robjects[index or 1]
+ if not fobjects then
+ fobjects = figure:objects()
+ robjects[index] = fobjects
+ end
+ return fobjects
+ else
+ return figure:objects()
+ end
end
-function metapost.convert(specification,result)
- local flusher = specification.flusher
- local askedfig = specification.askedfig
- if save_table then
- table.save(save_table,metapost.totable(result,1)) -- direct
+function metapost.convert(result, trialrun, flusher, multipass, askedfig)
+ if trialrun then
+ local multipassindeed = metapost.parse(result,askedfig)
+ if multipass and not multipassindeed and metapost.optimize then
+ if save_table then
+ table.save(save_table,metapost.totable(result,1)) -- direct
+ end
+ metapost.flush(result,flusher,askedfig) -- saves a run
+ else
+ return false
+ end
+ else
+ if save_table then
+ table.save(save_table,metapost.totable(result,1)) -- direct
+ end
+ metapost.flush(result,flusher,askedfig)
end
- metapost.flush(specification,result)
return true -- done
end
function metapost.flushliteral(d)
if savedliterals then
- write_node(mpsliteral(savedliterals[d]))
+ local literal = copy_node(mpsliteral)
+ literal.data = savedliterals[d]
+ write_node(literal)
else
report_metapost("problem flushing literal %a",d)
end
@@ -118,7 +140,7 @@ function pdfflusher.comment(message)
if message then
message = formatters["%% mps graphic %s: %s"](metapost.n,message)
if experiment then
- context(mpsliteral(message))
+ context(pdfliteral(message))
elseif savedliterals then
local last = #savedliterals + 1
savedliterals[last] = message
@@ -147,7 +169,7 @@ function pdfflusher.flushfigure(pdfliterals) -- table
if #pdfliterals > 0 then
pdfliterals = concat(pdfliterals,"\n")
if experiment then
- context(mpsliteral(pdfliterals))
+ context(pdfliteral(pdfliterals))
else
if savedliterals then
local last = #savedliterals + 1
@@ -298,6 +320,15 @@ local p_boolean = P("false") * Cc(false) + P("true") * Cc(true)
local p_set = Ct(number^1)
local p_path = Ct(Ct(number * number^-5)^1)
+-- local variable =
+-- P("1:") * key * p_number
+-- + P("2:") * key * p_string
+-- + P("3:") * key * p_boolean
+-- + S("4568") * P(":") * key * p_set
+-- + P("7:") * key * p_path
+--
+-- local pattern_key = Cf ( Carg(1) * (Cg(variable * newline^0)^0), rawset)
+
local variable =
P("1:") * p_number
+ P("2:") * p_string
@@ -343,9 +374,7 @@ function metapost.processspecial(str)
end
end
-local stack = { }
-
-local function pushproperties(figure)
+local function setproperties(figure)
local boundingbox = figure:boundingbox()
local properties = {
llx = boundingbox[1],
@@ -359,321 +388,313 @@ local function pushproperties(figure)
italic = figure:italcorr(),
number = figure:charcode() or 0,
}
- insert(stack,properties)
metapost.properties = properties
return properties
end
-local function popproperties()
- metapost.properties = remove(stack)
-end
-
local function nocomment() end
metapost.comment = nocomment
-function metapost.flush(specification,result)
+function metapost.flush(result,flusher,askedfig)
if result then
- local flusher = specification.flusher
- local askedfig = specification.askedfig
- local incontext = specification.incontext
- local figures = result.fig
+ local figures = result.fig
if figures then
flusher = flusher or pdfflusher
- local resetplugins = metapost.resetplugins or ignore -- before figure
- local processplugins = metapost.processplugins or ignore -- each object
+ local resetplugins = metapost.resetplugins or ignore -- before figure
+ local processplugins = metapost.processplugins or ignore -- each object
local synchronizeplugins = metapost.synchronizeplugins or ignore
- local pluginactions = metapost.pluginactions or ignore -- before / after
- local startfigure = flusher.startfigure
- local stopfigure = flusher.stopfigure
- local flushfigure = flusher.flushfigure
- local textfigure = flusher.textfigure
- local processspecial = flusher.processspecial or metapost.processspecial
- metapost.comment = flusher.comment or nocomment
+ local pluginactions = metapost.pluginactions or ignore -- before / after
+ local startfigure = flusher.startfigure
+ local stopfigure = flusher.stopfigure
+ local flushfigure = flusher.flushfigure
+ local textfigure = flusher.textfigure
+ local processspecial = flusher.processspecial or metapost.processspecial
+ metapost.comment = flusher.comment or nocomment
for index=1,#figures do
- local figure = figures[index]
- local properties = pushproperties(figure)
+ local figure = figures[index]
+ local properties = setproperties(figure)
if askedfig == "direct" or askedfig == "all" or askedfig == properties.number then
- local objects = getobjects(result,figure,index)
- local result = { }
- local miterlimit = -1
- local linecap = -1
- local linejoin = -1
- local dashed = false
- local llx = properties.llx
- local lly = properties.lly
- local urx = properties.urx
- local ury = properties.ury
+ local objects = getobjects(result,figure,index)
+ local result = { }
+ local miterlimit, linecap, linejoin, dashed = -1, -1, -1, false
+ local llx = properties.llx
+ local lly = properties.lly
+ local urx = properties.urx
+ local ury = properties.ury
if urx < llx then
-- invalid
startfigure(properties.number,0,0,0,0,"invalid",figure)
stopfigure()
else
-
- -- we need to be indirect if we want the one-pass solution
-
- local function processfigure()
- result[#result+1] = "q"
- if objects then
- -- resetplugins(result) -- we should move the colorinitializer here
- local savedpath = nil
- local savedhtap = nil
- for o=1,#objects do
- local object = objects[o]
- local objecttype = object.type
- if objecttype == "text" then
- result[#result+1] = "q"
- local ot = object.transform -- 3,4,5,6,1,2
- result[#result+1] = f_cm(ot[3],ot[4],ot[5],ot[6],ot[1],ot[2])
- flushfigure(result) -- flush accumulated literals
- result = { }
- textfigure(object.font,object.dsize,object.text,object.width,object.height,object.depth)
- result[#result+1] = "Q"
- elseif objecttype == "special" then
- if processspecial then
- processspecial(object.prescript)
+ startfigure(properties.number,llx,lly,urx,ury,"begin",figure)
+ result[#result+1] = "q"
+ if objects then
+ resetplugins(result) -- we should move the colorinitializer here
+ local savedpath = nil
+ local savedhtap = nil
+ for o=1,#objects do
+ local object = objects[o]
+ local objecttype = object.type
+ if objecttype == "text" then
+ result[#result+1] = "q"
+ local ot = object.transform -- 3,4,5,6,1,2
+ result[#result+1] = f_cm(ot[3],ot[4],ot[5],ot[6],ot[1],ot[2]) -- TH: formatters["%F %F m %F %F %F %F 0 0 cm"](unpack(ot))
+ flushfigure(result) -- flush accumulated literals
+ result = { }
+ textfigure(object.font,object.dsize,object.text,object.width,object.height,object.depth)
+ result[#result+1] = "Q"
+ elseif objecttype == "special" then
+ if processspecial then
+ processspecial(object.prescript)
+ end
+ elseif objecttype == "start_clip" then
+ local evenodd = not object.istext and object.postscript == "evenodd"
+ result[#result+1] = "q"
+ flushnormalpath(object.path,result,false)
+ result[#result+1] = evenodd and "W* n" or "W n"
+ elseif objecttype == "stop_clip" then
+ result[#result+1] = "Q"
+ miterlimit, linecap, linejoin, dashed = -1, -1, -1, "" -- was false
+ elseif objecttype == "start_bounds" or objecttype == "stop_bounds" then
+ -- skip
+ else
+ -- we use an indirect table as we want to overload
+ -- entries but this is not possible in userdata
+ --
+ -- can be optimized if no path
+ --
+ local original = object
+ local object = { }
+ setmetatable(object, {
+ __index = original
+ })
+ -- first we analyze
+ local before, after = processplugins(object)
+ local evenodd, collect, both = false, false, false
+ local postscript = object.postscript
+ if not object.istext then
+ if postscript == "evenodd" then
+ evenodd = true
+ elseif postscript == "collect" then
+ collect = true
+ elseif postscript == "both" then
+ both = true
+ elseif postscript == "eoboth" then
+ evenodd = true
+ both = true
+ end
+ end
+ --
+ if collect then
+ if not savedpath then
+ savedpath = { object.path or false }
+ savedhtap = { object.htap or false }
+ else
+ savedpath[#savedpath+1] = object.path or false
+ savedhtap[#savedhtap+1] = object.htap or false
end
- elseif objecttype == "start_clip" then
- local evenodd = not object.istext and object.postscript == "evenodd"
- result[#result+1] = "q"
- flushnormalpath(object.path,result,false)
- result[#result+1] = evenodd and "W* n" or "W n"
- elseif objecttype == "stop_clip" then
- result[#result+1] = "Q"
- miterlimit, linecap, linejoin, dashed = -1, -1, -1, "" -- was false
- elseif objecttype == "start_bounds" or objecttype == "stop_bounds" then
- -- skip
else
- -- we use an indirect table as we want to overload
- -- entries but this is not possible in userdata
- --
- -- can be optimized if no path
- --
- local original = object
- local object = { }
- setmetatable(object, {
- __index = original
- })
- local before,
- after = processplugins(object)
- local evenodd = false
- local collect = false
- local both = false
- local postscript = object.postscript
- if not object.istext then
- if postscript == "evenodd" then
- evenodd = true
- elseif postscript == "collect" then
- collect = true
- elseif postscript == "both" then
- both = true
- elseif postscript == "eoboth" then
- evenodd = true
- both = true
- end
+ local objecttype = object.type -- can have changed
+ if before then
+ result = pluginactions(before,result,flushfigure)
end
- --
- if collect then
- if not savedpath then
- savedpath = { object.path or false }
- savedhtap = { object.htap or false }
- else
- savedpath[#savedpath+1] = object.path or false
- savedhtap[#savedhtap+1] = object.htap or false
+ local ml = object.miterlimit
+ if ml and ml ~= miterlimit then
+ miterlimit = ml
+ result[#result+1] = f_M(ml)
+ end
+ local lj = object.linejoin
+ if lj and lj ~= linejoin then
+ linejoin = lj
+ result[#result+1] = f_j(lj)
+ end
+ local lc = object.linecap
+ if lc and lc ~= linecap then
+ linecap = lc
+ result[#result+1] = f_J(lc)
+ end
+ if both then
+ if dashed ~= false then -- was just dashed test
+ result[#result+1] = "[] 0 d"
+ dashed = false
end
else
- local objecttype = object.type -- can have changed
- if before then
- result = pluginactions(before,result,flushfigure)
- end
- local ml = object.miterlimit
- if ml and ml ~= miterlimit then
- miterlimit = ml
- result[#result+1] = f_M(ml)
- end
- local lj = object.linejoin
- if lj and lj ~= linejoin then
- linejoin = lj
- result[#result+1] = f_j(lj)
- end
- local lc = object.linecap
- if lc and lc ~= linecap then
- linecap = lc
- result[#result+1] = f_J(lc)
+ local dl = object.dash
+ if dl then
+ local d = f_d(concat(dl.dashes or {}," "),dl.offset)
+ if d ~= dashed then
+ dashed = d
+ result[#result+1] = d
+ end
+ elseif dashed ~= false then -- was just dashed test
+ result[#result+1] = "[] 0 d"
+ dashed = false
end
- if both then
- if dashed ~= false then -- was just dashed test
- result[#result+1] = "[] 0 d"
- dashed = false
+ end
+ 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 = object.pen
+ if pen then
+ if pen.type == 'elliptical' then
+ transformed, penwidth = pen_characteristics(original) -- boolean, value
+ result[#result+1] = f_w(penwidth) -- todo: only if changed
+ if objecttype == 'fill' then
+ objecttype = 'both'
end
- else
- local dl = object.dash
- if dl then
- local d = f_d(concat(dl.dashes or {}," "),dl.offset)
- if d ~= dashed then
- dashed = d
- result[#result+1] = d
+ else -- calculated by mplib itself
+ objecttype = 'fill'
+ end
+ end
+ if transformed then
+ result[#result+1] = "q"
+ end
+ if path then
+ if savedpath then
+ for i=1,#savedpath do
+ local path = savedpath[i]
+ if transformed then
+ flushconcatpath(path,result,open)
+ else
+ flushnormalpath(path,result,open)
end
- elseif dashed ~= false then -- was just dashed test
- result[#result+1] = "[] 0 d"
- dashed = false
end
- end
- local path = object.path -- newpath
- local transformed = false
- local penwidth = 1
- local open = path and path[1].left_type and path[#path].right_type -- at this moment only "end_point"
- local pen = object.pen
- if pen then
- if pen.type == "elliptical" then
- transformed, penwidth = pen_characteristics(original) -- boolean, value
- result[#result+1] = f_w(penwidth) -- todo: only if changed
- if objecttype == "fill" then
- objecttype = "both"
- end
- else -- calculated by mplib itself
- objecttype = "fill"
- end
+ savedpath = nil
end
if transformed then
- result[#result+1] = "q"
+ flushconcatpath(path,result,open)
+ else
+ flushnormalpath(path,result,open)
end
- if path then
- if savedpath then
- for i=1,#savedpath do
- local path = savedpath[i]
- if transformed then
- flushconcatpath(path,result,open)
- else
- flushnormalpath(path,result,open)
- end
- end
- savedpath = nil
- end
- if transformed then
- flushconcatpath(path,result,open)
+ if force_stroke then
+ result[#result+1] = open and "S" or "h S"
+ elseif objecttype == "fill" then
+ result[#result+1] = evenodd and "h f*" or "h f" -- f* = eo
+ elseif objecttype == "outline" then
+ if both then
+ result[#result+1] = evenodd and "h B*" or "h B" -- B* = eo
else
- flushnormalpath(path,result,open)
- end
- if force_stroke then
result[#result+1] = open and "S" or "h S"
- elseif objecttype == "fill" then
- result[#result+1] = evenodd and "h f*" or "h f" -- f* = eo
- elseif objecttype == "outline" then
- if both then
- result[#result+1] = evenodd and "h B*" or "h B" -- B* = eo
- else
- result[#result+1] = open and "S" or "h S"
- end
- elseif objecttype == "both" then
- result[#result+1] = evenodd and "h B*" or "h B" -- B* = eo -- b includes closepath
end
+ elseif objecttype == "both" then
+ result[#result+1] = evenodd and "h B*" or "h B" -- B* = eo -- b includes closepath
end
+ end
+ if transformed then
+ result[#result+1] = "Q"
+ end
+ local path = object.htap
+ if path then
if transformed then
- result[#result+1] = "Q"
+ result[#result+1] = "q"
end
- local path = object.htap
- if path then
- if transformed then
- result[#result+1] = "q"
- end
- if savedhtap then
- for i=1,#savedhtap do
- local path = savedhtap[i]
- if transformed then
- flushconcatpath(path,result,open)
- else
- flushnormalpath(path,result,open)
- end
+ if savedhtap then
+ for i=1,#savedhtap do
+ local path = savedhtap[i]
+ if transformed then
+ flushconcatpath(path,result,open)
+ else
+ flushnormalpath(path,result,open)
end
- savedhtap = nil
- evenodd = true
- end
- if transformed then
- flushconcatpath(path,result,open)
- else
- flushnormalpath(path,result,open)
- end
- if force_stroke then
- result[#result+1] = open and "S" or "h S"
- elseif objecttype == "fill" then
- result[#result+1] = evenodd and "h f*" or "h f" -- f* = eo
- elseif objecttype == "outline" then
- result[#result+1] = open and "S" or "h S"
- elseif objecttype == "both" then
- result[#result+1] = evenodd and "h B*" or "h B" -- B* = eo -- b includes closepath
- end
- if transformed then
- result[#result+1] = "Q"
end
+ savedhtap = nil
+ evenodd = true
+ end
+ if transformed then
+ flushconcatpath(path,result,open)
+ else
+ flushnormalpath(path,result,open)
end
- if after then
- result = pluginactions(after,result,flushfigure)
+ if force_stroke then
+ result[#result+1] = open and "S" or "h S"
+ elseif objecttype == "fill" then
+ result[#result+1] = evenodd and "h f*" or "h f" -- f* = eo
+ elseif objecttype == "outline" then
+ result[#result+1] = open and "S" or "h S"
+ elseif objecttype == "both" then
+ result[#result+1] = evenodd and "h B*" or "h B" -- B* = eo -- b includes closepath
+ end
+ if transformed then
+ result[#result+1] = "Q"
end
end
- if object.grouped then
- -- can be qQ'd so changes can end up in groups
- miterlimit, linecap, linejoin, dashed = -1, -1, -1, "" -- was false
+ if after then
+ result = pluginactions(after,result,flushfigure)
end
end
+ if object.grouped then
+ -- can be qQ'd so changes can end up in groups
+ miterlimit, linecap, linejoin, dashed = -1, -1, -1, "" -- was false
+ end
end
end
- result[#result+1] = "Q"
- flushfigure(result)
- end
- startfigure(properties.number,llx,lly,urx,ury,"begin",figure)
- if incontext then
- context(function() processfigure() end)
- else
- processfigure()
end
+ result[#result+1] = "Q"
+ flushfigure(result)
stopfigure("end")
-
end
if askedfig ~= "all" then
break
end
end
- popproperties()
end
metapost.comment = nocomment
- resetplugins(result) -- we should move the colorinitializer here
end
end
end
--- tracing:
-
-do
-
- local result = { }
-
- local flusher = {
- startfigure = function()
- result = { }
- context.startnointerference()
- end,
- flushfigure = function(literals)
- local n = #result
- for i=1,#literals do
- result[n+i] = literals[i]
+function metapost.parse(result,askedfig)
+ if result then
+ local figures = result.fig
+ if figures then
+ local multipass = false
+ local analyzeplugins = metapost.analyzeplugins -- each object
+ for index=1,#figures do
+ local figure = figures[index]
+ local properties = setproperties(figure)
+ if askedfig == "direct" or askedfig == "all" or askedfig == properties.number then
+ local objects = getobjects(result,figure,index)
+ if objects then
+ for o=1,#objects do
+ if analyzeplugins(objects[o]) then
+ multipass = true
+ end
+ end
+ end
+ if askedfig ~= "all" then
+ break
+ end
+ end
end
- end,
- stopfigure = function()
- context.stopnointerference()
+ return multipass
end
- }
+ end
+end
- local specification = {
- flusher = flusher,
- -- incontext = true,
- }
+-- tracing:
- function metapost.pdfliterals(result)
- metapost.flush(specification,result)
- return result
+local result = { }
+
+local flusher = {
+ startfigure = function()
+ result = { }
+ context.startnointerference()
+ end,
+ flushfigure = function(literals)
+ local n = #result
+ for i=1,#literals do
+ result[n+i] = literals[i]
+ end
+ end,
+ stopfigure = function()
+ context.stopnointerference()
end
+}
+function metapost.pdfliterals(result)
+ metapost.flush(result,flusher)
+ return result
end
function metapost.totable(result,askedfig)
@@ -681,6 +702,7 @@ function metapost.totable(result,askedfig)
local figure = result and result.fig and result.fig[1]
if figure then
local results = { }
+ -- local objects = figure:objects()
local objects = getobjects(result,figure,askedfig)
for o=1,#objects do
local object = objects[o]