diff options
author | Taco Hoekwater <taco@elvenkind.com> | 2009-08-23 11:11:32 +0000 |
---|---|---|
committer | Taco Hoekwater <taco@elvenkind.com> | 2009-08-23 11:11:32 +0000 |
commit | 8fc3039c82d48605b5ca8b2eda3f4fdd755681e1 (patch) | |
tree | 3cd9bbdd599bc4d1ac0409e167fee2136e4c0ec9 /Master/texmf-dist/tex/context/base/meta-pdh.lua | |
parent | 850fc99b7cd3ae7a20065531fe866ff7bae642ec (diff) |
this is context 2009.08.19 17:10
git-svn-id: svn://tug.org/texlive/trunk@14827 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/context/base/meta-pdh.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/meta-pdh.lua | 602 |
1 files changed, 602 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/context/base/meta-pdh.lua b/Master/texmf-dist/tex/context/base/meta-pdh.lua new file mode 100644 index 00000000000..ef15c6a1145 --- /dev/null +++ b/Master/texmf-dist/tex/context/base/meta-pdh.lua @@ -0,0 +1,602 @@ +if not modules then modules = { } end modules ['meta-pdf'] = { + version = 1.001, + comment = "companion to meta-pdf.tex", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- This file contains the history of the converter. We keep it around as it +-- relates to the development of luatex. + +-- This is the third version. Version 1 converted to Lua code, +-- version 2 gsubbed the file into TeX code, and version 3 uses +-- the new lpeg functionality and streams the result into TeX. + +-- We will move old stuff to edu. + +--~ old lpeg 0.4 lpeg 0.5 +--~ 100 times test graphic 2.45 (T:1.07) 0.72 (T:0.24) 0.580 (0.560 no table) -- 0.54 optimized for one space (T:0.19) +--~ 100 times big graphic 10.44 4.30/3.35 nogb 2.914 (2.050 no table) -- 1.99 optimized for one space (T:0.85) +--~ 500 times test graphic T:1.29 T:1.16 (T:1.10 no table) -- T:1.10 + +-- only needed for mp output on disk + +local concat, format = table.concat, string.format + +local texsprint = tex.sprint +local ctxcatcodes = tex.ctxcatcodes + +mptopdf = { } +mptopdf.parsers = { } +mptopdf.parser = 'none' +mptopdf.n = 0 + +function mptopdf.reset() + mptopdf.data = "" + mptopdf.path = { } + mptopdf.stack = { } + mptopdf.texts = { } + mptopdf.version = 0 + mptopdf.shortcuts = false + mptopdf.resetpath() +end + +function mptopdf.resetpath() + mptopdf.stack.close = false + mptopdf.stack.path = { } + mptopdf.stack.concat = nil + mptopdf.stack.special = false +end + +mptopdf.reset() + +function mptopdf.parsers.none() + -- no parser set +end + +function mptopdf.parse() + mptopdf.parsers[mptopdf.parser]() +end + +-- old code + +mptopdf.steps = { } + +mptopdf.descapes = { + ['('] = "\\\\char40 ", + [')'] = "\\\\char41 ", + ['"'] = "\\\\char92 " +} + +function mptopdf.descape(str) + str = str:gsub("\\(%d%d%d)",function(n) + return "\\char" .. tonumber(n,8) .. " " + end) + return str:gsub("\\([%(%)\\])",mptopdf.descapes) +end + +function mptopdf.steps.descape(str) + str = str:gsub("\\(%d%d%d)",function(n) + return "\\\\char" .. tonumber(n,8) .. " " + end) + return str:gsub("\\([%(%)\\])",mptopdf.descapes) +end + +function mptopdf.steps.strip() -- .3 per expr + mptopdf.data = mptopdf.data:gsub("^(.-)%%+Page:.-%c+(.*)%s+%a+%s+%%+EOF.*$", function(preamble, graphic) + local bbox = "0 0 0 0" + for b in preamble:gmatch("%%%%%a+oundingBox: +(.-)%c+") do + bbox = b + end + local name, version = preamble:gmatch("%%%%Creator: +(.-) +(.-) ") + mptopdf.version = tostring(version or "0") + if preamble:find("/hlw{0 dtransform") then + mptopdf.shortcuts = true + end + -- the boundingbox specification needs to come before data, well, not really + return bbox .. " boundingbox\n" .. "\nbegindata\n" .. graphic .. "\nenddata\n" + end, 1) + mptopdf.data = mptopdf.data:gsub("%%%%MetaPostSpecials: +(.-)%c+", "%1 specials\n", 1) + mptopdf.data = mptopdf.data:gsub("%%%%MetaPostSpecial: +(.-)%c+", "%1 special\n") + mptopdf.data = mptopdf.data:gsub("%%.-%c+", "") +end + +function mptopdf.steps.cleanup() + if not mptopdf.shortcuts then + mptopdf.data = mptopdf.data:gsub("gsave%s+fill%s+grestore%s+stroke", "both") + mptopdf.data = mptopdf.data:gsub("([%d%.]+)%s+([%d%.]+)%s+dtransform%s+exch%s+truncate%s+exch%s+idtransform%s+pop%s+setlinewidth", function(wx,wy) + if tonumber(wx) > 0 then return wx .. " setlinewidth" else return wy .. " setlinewidth" end + end) + mptopdf.data = mptopdf.data:gsub("([%d%.]+)%s+([%d%.]+)%s+dtransform%s+truncate%s+idtransform%s+setlinewidth%s+pop", function(wx,wy) + if tonumber(wx) > 0 then return wx .. " setlinewidth" else return wy .. " setlinewidth" end + end) + end +end + +function mptopdf.steps.convert() + mptopdf.data = mptopdf.data:gsub("%c%((.-)%) (.-) (.-) fshow", function(str,font,scale) + mptopdf.texts[mptopdf.texts+1] = {mptopdf.steps.descape(str), font, scale} + return "\n" .. #mptopdf.texts .. " textext" + end) + mptopdf.data = mptopdf.data:gsub("%[%s*(.-)%s*%]", function(str) + return str:gsub("%s+"," ") + end) + local t + mptopdf.data = mptopdf.data:gsub("%s*([^%a]-)%s*(%a+)", function(args,cmd) + if cmd == "textext" then + t = mptopdf.texts[tonumber(args)] + return "mps.textext(" .. "\"" .. t[2] .. "\"," .. t[3] .. ",\"" .. t[1] .. "\")\n" + else + return "mps." .. cmd .. "(" .. args:gsub(" +",",") .. ")\n" + end + end) +end + +function mptopdf.steps.process() + assert(loadstring(mptopdf.data))() -- () runs the loaded chunk +end + +function mptopdf.parsers.gsub() + mptopdf.steps.strip() + mptopdf.steps.cleanup() + mptopdf.steps.convert() + mptopdf.steps.process() +end + +-- end of old code + +-- from lua to tex + +function mptopdf.pdfcode(str) + texsprint(ctxcatcodes,"\\pdfliteral{" .. str .. "}") -- \\MPScode +end + +function mptopdf.texcode(str) + texsprint(ctxcatcodes,str) +end + +-- auxiliary functions + +function mptopdf.flushconcat() + if mptopdf.stack.concat then + mptopdf.pdfcode(concat(mptopdf.stack.concat," ") .. " cm") + mptopdf.stack.concat = nil + end +end + +function mptopdf.flushpath(cmd) + -- faster: no local function and ipairs + if #mptopdf.stack.path > 0 then + local path = { } + if mptopdf.stack.concat then + local sx, sy = mptopdf.stack.concat[1], mptopdf.stack.concat[4] + local rx, ry = mptopdf.stack.concat[2], mptopdf.stack.concat[3] + local tx, ty = mptopdf.stack.concat[5], mptopdf.stack.concat[6] + local d = (sx*sy) - (rx*ry) + local function mpconcat(px, py) + return (sy*(px-tx)-ry*(py-ty))/d, (sx*(py-ty)-rx*(px-tx))/d + end + local stackpath = mptopdf.stack.path + for k=1,#stackpath do + local v = stackpath[k] + v[1],v[2] = mpconcat(v[1],v[2]) + if #v == 7 then + v[3],v[4] = mpconcat(v[3],v[4]) + v[5],v[6] = mpconcat(v[5],v[6]) + end + path[#path+1] = concat(v," ") + end + else + local stackpath = mptopdf.stack.path + for k=1,#stackpath do + path[#path+1] = concat(stackpath[k]," ") + end + end + mptopdf.flushconcat() + mptopdf.texcode("\\MPSpath{" .. concat(path," ") .. "}") + if mptopdf.stack.close then + mptopdf.texcode("\\MPScode{h " .. cmd .. "}") + else + mptopdf.texcode("\\MPScode{" .. cmd .."}") + end + end + mptopdf.resetpath() +end + +function mptopdf.loaded(name) + local ok, n + mptopdf.reset() + ok, mptopdf.data, n = resolvers.loadbinfile(name, 'tex') -- we need a binary load ! + return ok +end + +if not mptopdf.parse then + function mptopdf.parse() end -- forward declaration +end + +function mptopdf.convertmpstopdf(name) + if mptopdf.loaded(name) then + mptopdf.n = mptopdf.n + 1 + statistics.starttiming(mptopdf) + mptopdf.parse() + mptopdf.reset() + statistics.stoptiming(mptopdf) + else + tex.print("file " .. name .. " not found") + end +end + +-- mp interface + +mps = mps or { } + +function mps.creator(a, b, c) + mptopdf.version = tonumber(b) +end + +function mps.creationdate(a) + mptopdf.date= a +end + +function mps.newpath() + mptopdf.stack.path = { } +end + +function mps.boundingbox(llx, lly, urx, ury) + mptopdf.texcode("\\MPSboundingbox{" .. llx .. "}{" .. lly .. "}{" .. urx .. "}{" .. ury .. "}") +end + +function mps.moveto(x,y) + mptopdf.stack.path[#mptopdf.stack.path+1] = {x,y,"m"} +end + +function mps.curveto(ax, ay, bx, by, cx, cy) + mptopdf.stack.path[#mptopdf.stack.path+1] = {ax,ay,bx,by,cx,cy,"c"} +end + +function mps.lineto(x,y) + mptopdf.stack.path[#mptopdf.stack.path+1] = {x,y,"l"} +end + +function mps.rlineto(x,y) + local dx, dy = 0, 0 + if #mptopdf.stack.path > 0 then + dx, dy = mptopdf.stack.path[#mptopdf.stack.path][1], mptopdf.stack.path[#mptopdf.stack.path][2] + end + mptopdf.stack.path[#mptopdf.stack.path+1] = {dx,dy,"l"} +end + +function mps.translate(tx,ty) + mptopdf.pdfcode("1 0 0 0 1 " .. tx .. " " .. ty .. " cm") +end + +function mps.scale(sx,sy) + mptopdf.stack.concat = {sx,0,0,sy,0,0} +end + +function mps.concat(sx, rx, ry, sy, tx, ty) + mptopdf.stack.concat = {sx,rx,ry,sy,tx,ty} +end + +function mps.setlinejoin(d) + mptopdf.pdfcode(d .. " j") +end + +function mps.setlinecap(d) + mptopdf.pdfcode(d .. " J") +end + +function mps.setmiterlimit(d) + mptopdf.pdfcode(d .. " M") +end + +function mps.gsave() + mptopdf.pdfcode("q") +end + +function mps.grestore() + mptopdf.pdfcode("Q") +end + +function mps.setdash(...) + local n = select("#",...) + mptopdf.pdfcode("[" .. concat({...}," ",1,n-1) .. "] " .. select(n,...) .. " d") +end + +function mps.resetdash() + mptopdf.pdfcode("[ ] 0 d") +end + +function mps.setlinewidth(d) + mptopdf.pdfcode(d .. " w") +end + +function mps.closepath() + mptopdf.stack.close = true +end + +function mps.fill() + mptopdf.flushpath('f') +end + +function mps.stroke() + mptopdf.flushpath('S') +end + +function mps.both() + mptopdf.flushpath('B') +end + +function mps.clip() + mptopdf.flushpath('W n') +end + +function mps.textext(font, scale, str) -- old parser + local dx, dy = 0, 0 + if #mptopdf.stack.path > 0 then + dx, dy = mptopdf.stack.path[1][1], mptopdf.stack.path[1][2] + end + mptopdf.flushconcat() + mptopdf.texcode("\\MPStextext{"..font.."}{"..scale.."}{"..str.."}{"..dx.."}{"..dy.."}") + mptopdf.resetpath() +end + +--~ function mps.handletext(font,scale.str,dx,dy) +--~ local one, two = string.match(str, "^(%d+)::::(%d+)") +--~ if one and two then +--~ mptopdf.texcode("\\MPTOPDFtextext{"..font.."}{"..scale.."}{"..one.."}{"..two.."}{"..dx.."}{"..dy.."}") +--~ else +--~ mptopdf.texcode("\\MPTOPDFtexcode{"..font.."}{"..scale.."}{"..str.."}{"..dx.."}{"..dy.."}") +--~ end +--~ end + +function mps.setrgbcolor(r,g,b) -- extra check + r, g = tonumber(r), tonumber(g) -- needed when we use lpeg + if r == 0.0123 and g < 0.1 then + mptopdf.texcode("\\MPSspecial{" .. g*10000 .. "}{" .. b*10000 .. "}") + elseif r == 0.123 and g < 0.1 then + mptopdf.texcode("\\MPSspecial{" .. g* 1000 .. "}{" .. b* 1000 .. "}") + else + mptopdf.texcode("\\MPSrgb{" .. r .. "}{" .. g .. "}{" .. b .. "}") + end +end + +function mps.setcmykcolor(c,m,y,k) + mptopdf.texcode("\\MPScmyk{" .. c .. "}{" .. m .. "}{" .. y .. "}{" .. k .. "}") +end + +function mps.setgray(s) + mptopdf.texcode("\\MPSgray{" .. s .. "}") +end + +function mps.specials(version,signal,factor) -- 2.0 123 1000 +end + +function mps.special(...) -- 7 1 0.5 1 0 0 1 3 + local n = select("#",...) + mptopdf.texcode("\\MPSbegin\\MPSset{" .. concat({...},"}\\MPSset{",2,n) .. "}\\MPSend") +end + +function mps.begindata() +end + +function mps.enddata() +end + +function mps.showpage() +end + +mps.n = mps.newpath -- n +mps.p = mps.closepath -- h +mps.l = mps.lineto -- l +mps.r = mps.rlineto -- r +mps.m = mps.moveto -- m +mps.c = mps.curveto -- c +mps.hlw = mps.setlinewidth +mps.vlw = mps.setlinewidth + +mps.C = mps.setcmykcolor -- k +mps.G = mps.setgray -- g +mps.R = mps.setrgbcolor -- rg + +mps.lj = mps.setlinejoin -- j +mps.ml = mps.setmiterlimit -- M +mps.lc = mps.setlinecap -- J +mps.sd = mps.setdash -- d +mps.rd = mps.resetdash + +mps.S = mps.stroke -- S +mps.F = mps.fill -- f +mps.B = mps.both -- B +mps.W = mps.clip -- W + +mps.q = mps.gsave -- q +mps.Q = mps.grestore -- Q + +mps.s = mps.scale -- (not in pdf) +mps.t = mps.concat -- (not the same as pdf anyway) + +mps.P = mps.showpage + +-- experimental + +function mps.attribute(id,value) + mptopdf.texcode("\\attribute " .. id .. "=" .. value .. " ") +-- mptopdf.texcode("\\dompattribute{" .. id .. "}{" .. value .. "}") +end + +-- lpeg parser + +-- The lpeg based parser is rather optimized for the kind of output +-- that MetaPost produces. It's my first real lpeg code, which may +-- show. Because the parser binds to functions, we define it last. + +do -- assumes \let\c\char + + local byte = string.byte + local digit = lpeg.R("09") + local spec = digit^2 * lpeg.P("::::") * digit^2 + local text = lpeg.Cc("{") * ( + lpeg.P("\\") * ( (digit * digit * digit) / function(n) return "c" .. tonumber(n,8) end) + + lpeg.P(" ") / function(n) return "\\c32" end + -- never in new mp + lpeg.P(1) / function(n) return "\\c" .. byte(n) end + ) * lpeg.Cc("}") + local package = lpeg.Cs(spec + text^0) + + function mps.fshow(str,font,scale) -- lpeg parser + mps.textext(font,scale,package:match(str)) + end + +end + +do + + local eol = lpeg.S('\r\n')^1 + local sp = lpeg.P(' ')^1 + local space = lpeg.S(' \r\n')^1 + local number = lpeg.S('0123456789.-+')^1 + local nonspace = lpeg.P(1-lpeg.S(' \r\n'))^1 + + local cnumber = lpeg.C(number) + local cstring = lpeg.C(nonspace) + + local specials = (lpeg.P("%%MetaPostSpecials:") * sp * (cstring * sp^0)^0 * eol) / mps.specials + local special = (lpeg.P("%%MetaPostSpecial:") * sp * (cstring * sp^0)^0 * eol) / mps.special + local boundingbox = (lpeg.P("%%BoundingBox:") * sp * (cnumber * sp^0)^4 * eol) / mps.boundingbox + local highresboundingbox = (lpeg.P("%%HiResBoundingBox:") * sp * (cnumber * sp^0)^4 * eol) / mps.boundingbox + + local setup = lpeg.P("%%BeginSetup") * (1 - lpeg.P("%%EndSetup") )^1 + local prolog = lpeg.P("%%BeginProlog") * (1 - lpeg.P("%%EndProlog"))^1 + local comment = lpeg.P('%')^1 * (1 - eol)^1 + + local curveto = ((cnumber * sp)^6 * lpeg.P("curveto") ) / mps.curveto + local lineto = ((cnumber * sp)^2 * lpeg.P("lineto") ) / mps.lineto + local rlineto = ((cnumber * sp)^2 * lpeg.P("rlineto") ) / mps.rlineto + local moveto = ((cnumber * sp)^2 * lpeg.P("moveto") ) / mps.moveto + local setrgbcolor = ((cnumber * sp)^3 * lpeg.P("setrgbcolor") ) / mps.setrgbcolor + local setcmykcolor = ((cnumber * sp)^4 * lpeg.P("setcmykcolor") ) / mps.setcmykcolor + local setgray = ((cnumber * sp)^1 * lpeg.P("setgray") ) / mps.setgray + local newpath = ( lpeg.P("newpath") ) / mps.newpath + local closepath = ( lpeg.P("closepath") ) / mps.closepath + local fill = ( lpeg.P("fill") ) / mps.fill + local stroke = ( lpeg.P("stroke") ) / mps.stroke + local clip = ( lpeg.P("clip") ) / mps.clip + local both = ( lpeg.P("gsave fill grestore")) / mps.both + local showpage = ( lpeg.P("showpage") ) + local setlinejoin = ((cnumber * sp)^1 * lpeg.P("setlinejoin") ) / mps.setlinejoin + local setlinecap = ((cnumber * sp)^1 * lpeg.P("setlinecap") ) / mps.setlinecap + local setmiterlimit = ((cnumber * sp)^1 * lpeg.P("setmiterlimit") ) / mps.setmiterlimit + local gsave = ( lpeg.P("gsave") ) / mps.gsave + local grestore = ( lpeg.P("grestore") ) / mps.grestore + + local setdash = (lpeg.P("[") * (cnumber * sp^0)^0 * lpeg.P("]") * sp * cnumber * sp * lpeg.P("setdash")) / mps.setdash + local concat = (lpeg.P("[") * (cnumber * sp^0)^6 * lpeg.P("]") * sp * lpeg.P("concat") ) / mps.concat + local scale = ( (cnumber * sp^0)^6 * sp * lpeg.P("concat") ) / mps.concat + + local fshow = (lpeg.P("(") * lpeg.C((1-lpeg.P(")"))^1) * lpeg.P(")") * space * cstring * space * cnumber * space * lpeg.P("fshow")) / mps.fshow + local fshow = (lpeg.P("(") * + lpeg.Cs( ( lpeg.P("\\(")/"\\050" + lpeg.P("\\)")/"\\051" + (1-lpeg.P(")")) )^1 ) + * lpeg.P(")") * space * cstring * space * cnumber * space * lpeg.P("fshow")) / mps.fshow + + local setlinewidth_x = (lpeg.P("0") * sp * cnumber * sp * lpeg.P("dtransform truncate idtransform setlinewidth pop")) / mps.setlinewidth + local setlinewidth_y = (cnumber * sp * lpeg.P("0 dtransform exch truncate exch idtransform pop setlinewidth") ) / mps.setlinewidth + + local c = ((cnumber * sp)^6 * lpeg.P("c") ) / mps.curveto -- ^6 very inefficient, ^1 ok too + local l = ((cnumber * sp)^2 * lpeg.P("l") ) / mps.lineto + local r = ((cnumber * sp)^2 * lpeg.P("r") ) / mps.rlineto + local m = ((cnumber * sp)^2 * lpeg.P("m") ) / mps.moveto + local vlw = ((cnumber * sp)^1 * lpeg.P("vlw")) / mps.setlinewidth + local hlw = ((cnumber * sp)^1 * lpeg.P("hlw")) / mps.setlinewidth + + local R = ((cnumber * sp)^3 * lpeg.P("R") ) / mps.setrgbcolor + local C = ((cnumber * sp)^4 * lpeg.P("C") ) / mps.setcmykcolor + local G = ((cnumber * sp)^1 * lpeg.P("G") ) / mps.setgray + + local lj = ((cnumber * sp)^1 * lpeg.P("lj") ) / mps.setlinejoin + local ml = ((cnumber * sp)^1 * lpeg.P("ml") ) / mps.setmiterlimit + local lc = ((cnumber * sp)^1 * lpeg.P("lc") ) / mps.setlinecap + + local n = lpeg.P("n") / mps.newpath + local p = lpeg.P("p") / mps.closepath + local S = lpeg.P("S") / mps.stroke + local F = lpeg.P("F") / mps.fill + local B = lpeg.P("B") / mps.both + local W = lpeg.P("W") / mps.clip + local P = lpeg.P("P") / mps.showpage + + local q = lpeg.P("q") / mps.gsave + local Q = lpeg.P("Q") / mps.grestore + + local sd = (lpeg.P("[") * (cnumber * sp^0)^0 * lpeg.P("]") * sp * cnumber * sp * lpeg.P("sd")) / mps.setdash + local rd = ( lpeg.P("rd")) / mps.resetdash + + local s = ( (cnumber * sp^0)^2 * lpeg.P("s") ) / mps.scale + local t = (lpeg.P("[") * (cnumber * sp^0)^6 * lpeg.P("]") * sp * lpeg.P("t") ) / mps.concat + + -- experimental + + local attribute = ((cnumber * sp)^2 * lpeg.P("attribute")) / mps.attribute + local A = ((cnumber * sp)^2 * lpeg.P("A")) / mps.attribute + + local preamble = ( + prolog + setup + + boundingbox + highresboundingbox + specials + special + + comment + ) + + local procset = ( + lj + ml + lc + + c + l + m + n + p + r + + A + + R + C + G + + S + F + B + W + + vlw + hlw + + Q + q + + sd + rd + + t + s + + fshow + + P + ) + + local verbose = ( + curveto + lineto + moveto + newpath + closepath + rlineto + + setrgbcolor + setcmykcolor + setgray + + attribute + + setlinejoin + setmiterlimit + setlinecap + + stroke + fill + clip + both + + setlinewidth_x + setlinewidth_y + + gsave + grestore + + concat + scale + + fshow + + setdash + -- no resetdash + showpage + ) + + -- order matters in terms of speed / we could check for procset first + + local captures_old = ( space + verbose + preamble )^0 + local captures_new = ( space + procset + preamble + verbose )^0 + + function mptopdf.parsers.lpeg() + if mptopdf.data:find("%%%%BeginResource: procset mpost") then + captures_new:match(mptopdf.data) + else + captures_old:match(mptopdf.data) + end + end + +end + +mptopdf.parser = 'lpeg' + +-- status info + +statistics.register("mps conversion time",function() + local n = mptopdf.n + if n > 0 then + return format("%s seconds, %s conversions", statistics.elapsedtime(mptopdf),n) + else + return nil + end +end) |