summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/mlib-svg.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkiv/mlib-svg.lua')
-rw-r--r--tex/context/base/mkiv/mlib-svg.lua280
1 files changed, 175 insertions, 105 deletions
diff --git a/tex/context/base/mkiv/mlib-svg.lua b/tex/context/base/mkiv/mlib-svg.lua
index b56c1fd54..f4b3117a6 100644
--- a/tex/context/base/mkiv/mlib-svg.lua
+++ b/tex/context/base/mkiv/mlib-svg.lua
@@ -75,24 +75,21 @@ if not modules then modules = { } end modules ['mlib-svg'] = {
-- One can run into pretty crazy images, like lines that are fills being clipped
-- to some width. That's the danger of hiding yourself behind an interface I guess.
-local rawget, type, tonumber, tostring, next, setmetatable = rawget, type, tonumber, tostring, next, setmetatable
+local rawget, rawset, type, tonumber, tostring, next, setmetatable = rawget, rawset, type, tonumber, tostring, next, setmetatable
-local P, S, R, C, Ct, Cs, Cc, Cp, Carg = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Ct, lpeg.Cs, lpeg.Cc, lpeg.Cp, lpeg.Carg
+local P, S, R, C, Ct, Cs, Cc, Cp, Cg, Cf, Carg = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Ct, lpeg.Cs, lpeg.Cc, lpeg.Cp, lpeg.Cg, lpeg.Cf, lpeg.Carg
local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns
-local pi, sin, cos, asin, sind, cosd, tan, abs, sqrt = math.pi, math.sin, math.cos, math.asin, math.sind, math.cosd, math.tan, math.abs, math.sqrt
+local sqrt = math.sqrt
local concat, setmetatableindex, sortedhash = table.concat, table.setmetatableindex, table.sortedhash
local gmatch, gsub, find, match, rep = string.gmatch, string.gsub, string.find, string.match, string.rep
local formatters, fullstrip = string.formatters, string.fullstrip
-local extract = bit32.extract
local utfsplit, utfbyte = utf.split, utf.byte
local xmlconvert, xmlcollected, xmlcount, xmlfirst, xmlroot = xml.convert, xml.collected, xml.count, xml.first, xml.root
local xmltext, xmltextonly = xml.text, xml.textonly
local css = xml.css or { } -- testing
-local bpfactor = number.dimenfactors.bp
-
local function xmlinheritattributes(c,pa)
local at = c.at
local dt = c.dt
@@ -134,6 +131,47 @@ local pathtracer = {
["fill-opacity"] = ".75",
}
+-- This is just an experiment. Todo: reset hash etc. Also implement
+-- an option handler.
+
+local svghash = false do
+
+ local svglast = 0
+ local svglist = false
+
+ local function checkhash(t,k)
+ local n = svglast + 1
+ svglast = n
+ svglist[n] = k
+ t[k] = n
+ return n
+ end
+
+ function metapost.startsvghashing()
+ svglast = 0
+ svglist = { }
+ svghash = setmetatableindex(checkhash)
+ end
+
+ function metapost.stopsvghashing()
+ svglast = 0
+ svglist = false
+ svghash = false
+ end
+
+ interfaces.implement {
+ name = "svghashed",
+ arguments = "integer",
+ actions = function(n)
+ local t = svglist and svglist[n]
+ if t then
+ context(t)
+ end
+ end
+ }
+
+end
+
-- We have quite some closures because otherwise we run into the local variable
-- limitations. It doesn't always look pretty now, sorry. I'll clean up this mess
-- some day (the usual nth iteration of code).
@@ -149,6 +187,8 @@ local pathtracer = {
local a2c do
+ local pi, sin, cos, tan, asin, abs = math.pi, math.sin, math.cos, math.tan, math.asin, math.abs
+
local d120 = (pi * 120) / 180
local pi2 = 2 * pi
@@ -401,6 +441,8 @@ local rgbcomponents, withcolor, thecolor do
local f_svggray = formatters['svggray(%.3N)']
local f_svgname = formatters['"%s"']
+ local extract = bit32.extract
+
local triplets = setmetatableindex(function(t,k)
-- we delay building all these strings
local v = svgcolors[k]
@@ -971,6 +1013,8 @@ local f_wrapped_stop = formatters[") shifted (0,%N) scaled %N ;"]
local handletransform, handleviewbox do
+ local sind = math.sind
+
--todo: better lpeg
local f_rotatedaround = formatters[" rotatedaround((%N,%N),%N)"]
@@ -1017,7 +1061,7 @@ local handletransform, handleviewbox do
local function skewx(x)
if x then
- return f_slanted_x(math.sind(-x))
+ return f_slanted_x(sind(-x))
else
return ""
end
@@ -1025,7 +1069,7 @@ local handletransform, handleviewbox do
local function skewy(y)
if y then
- return f_slanted_y(math.sind(-y))
+ return f_slanted_y(sind(-y))
else
return ""
end
@@ -1035,24 +1079,34 @@ local handletransform, handleviewbox do
return f_matrix(rx or 1, sx or 0, sy or 0, ry or 1, tx or 0, - (ty or 0))
end
- -- how to deal with units here?
+ -- How to deal with units here? Anyway, order seems to matter.
- local p_transform = Cs ( (
- P("translate") * p_numbers / translate -- maybe xy
- + P("scale") * p_numbers / scale
- + P("rotate") * p_numbers / rotate
- + P("matrix") * p_numbers / matrix
- + P("skewX") * p_numbers / skewx
- + P("skewY") * p_numbers / skewy
- -- + p_separator
- + P(1)/""
- )^1)
+ local p_transform = Cf ( Ct("") * (
+ lpegpatterns.whitespace^0 * Cg(
+ C("translate") * (p_numbers / translate) -- maybe xy
+ + C("scale") * (p_numbers / scale)
+ + C("rotate") * (p_numbers / rotate)
+ + C("matrix") * (p_numbers / matrix)
+ + C("skewX") * (p_numbers / skewx)
+ + C("skewY") * (p_numbers / skewy)
+ )
+ )^1, rawset)
handletransform = function(at)
local t = at.transform
if t then
local e = lpegmatch(p_transform,t)
- return s_transform_start, f_transform_stop(e), t
+ if e then
+ e = concat({
+ e.rotate or "",
+ e.skewX or "",
+ e.skewY or "",
+ e.scale or "",
+ e.translate or "",
+ e.matrix or "",
+ }, " ")
+ return s_transform_start, f_transform_stop(e), t
+ end
end
end
@@ -2340,6 +2394,7 @@ do
local f_scaled = formatters["\\svgscaled{%N}{%s}{%s}{%s}"]
local f_normal = formatters["\\svgnormal{%s}{%s}{%s}"]
+ local f_hashed = formatters["\\svghashed{%s}"]
-- We move to the outer (x,y) and when we have an inner offset we
-- (need to) compensate for that outer offset.
@@ -2348,8 +2403,14 @@ do
-- local f_text_normal_svg = formatters['(svgtext("%s") shifted (%N,%N))']
-- local f_text_simple_svg = formatters['svgtext("%s")']
- local f_text_normal_svg = formatters['(textext.drt("%s") shifted (%N,%N))']
- local f_text_simple_svg = formatters['textext.drt("%s")']
+ local anchors = {
+ ["start"] = "drt",
+ ["end"] = "dflt",
+ ["middle"] = "d",
+ }
+
+ local f_text_normal_svg = formatters['(textext.%s("%s") shifted (%N,%N))']
+ local f_text_simple_svg = formatters['textext.%s("%s")']
-- or just maptext
@@ -2480,7 +2541,9 @@ do
di = gsub(di,"%s+$","")
end
local chars = utfsplit(di)
- if tx then
+ if svghash then
+ di = f_hashed(svghash[di])
+ elseif tx then
for i=1,#chars do
chars[i] = f_poschar(
(tx[i] or 0) - x,
@@ -2540,6 +2603,7 @@ do
v_fill = "black"
end
local color, opacity, invisible = fillproperties(v_fill,at)
+ local anchor = anchors[at["text-anchor"] or "start"] or "drt"
local r = metapost.remappedtext(only)
if r then
if x == 0 and y == 0 then
@@ -2567,9 +2631,9 @@ do
result[#result+1] = s_stoplayer
result = concat(result)
if x == 0 and y == 0 then
- result = f_text_simple_svg(result)
+ result = f_text_simple_svg(anchor,result)
else
- result = f_text_normal_svg(result,x,y)
+ result = f_text_normal_svg(anchor,result,x,y)
end
flushobject(result,at,color,opacity)
if trace_text then
@@ -2741,7 +2805,7 @@ do
definitions = { }
tagstyles = { }
classstyles = { }
- for s in xmlcollected(c,"/style") do
+ for s in xmlcollected(c,"style") do -- can also be in a def, so let's play safe
handlestyle(c)
end
handlechains(c)
@@ -2777,101 +2841,107 @@ end
-- a bit more efficient, because we now go to mp and back which is kind of redundant,
-- but for now it will do.
-function metapost.includesvgfile(filename,offset) -- offset in sp
- if lfs.isfile(filename) then
+do
+
+ local bpfactor = number.dimenfactors.bp
+
+ function metapost.includesvgfile(filename,offset) -- offset in sp
+ if lfs.isfile(filename) then
+ context.startMPcode("doublefun")
+ context('draw lmt_svg [ filename = "%s", offset = %N ] ;',filename,(offset or 0)*bpfactor)
+ context.stopMPcode()
+ end
+ end
+
+ function metapost.includesvgbuffer(name,offset) -- offset in sp
context.startMPcode("doublefun")
- context('draw lmt_svg [ filename = "%s", offset = %N ] ;',filename,(offset or 0)*bpfactor)
+ context('draw lmt_svg [ buffer = "%s", offset = %N ] ;',name or "",(offset or 0)*bpfactor)
context.stopMPcode()
end
-end
-
-function metapost.includesvgbuffer(name,offset) -- offset in sp
- context.startMPcode("doublefun")
- context('draw lmt_svg [ buffer = "%s", offset = %N ] ;',name or "",(offset or 0)*bpfactor)
- context.stopMPcode()
-end
-interfaces.implement {
- name = "includesvgfile",
- actions = metapost.includesvgfile,
- arguments = { "string", "dimension" },
-}
+ interfaces.implement {
+ name = "includesvgfile",
+ actions = metapost.includesvgfile,
+ arguments = { "string", "dimension" },
+ }
-interfaces.implement {
- name = "includesvgbuffer",
- actions = metapost.includesvgbuffer,
- arguments = { "string", "dimension" },
-}
+ interfaces.implement {
+ name = "includesvgbuffer",
+ actions = metapost.includesvgbuffer,
+ arguments = { "string", "dimension" },
+ }
-function metapost.showsvgpage(data)
- local dd = data.data
- if not dd then
- local fn = data.filename
- dd = fn and table.load(fn)
- end
- if type(dd) == "table" then
- local comment = data.comment
- local offset = data.pageoffset
- local index = data.index
- local first = math.max(index or 1,1)
- local last = math.min(index or #dd,#dd)
- for i=first,last do
- local d = setmetatableindex( {
- data = dd[i],
- comment = comment and i or false,
- pageoffset = offset or nil,
- }, data)
- metapost.showsvgpage(d)
- end
- elseif data.method == "code" then
- context.startMPcode(doublefun)
- context(metapost.svgtomp(data))
- context.stopMPcode()
- else
- context.startMPpage { instance = "doublefun", offset = data.pageoffset or nil }
- context(metapost.svgtomp(data))
+ function metapost.showsvgpage(data)
+ local dd = data.data
+ if not dd then
+ local fn = data.filename
+ dd = fn and table.load(fn)
+ end
+ if type(dd) == "table" then
local comment = data.comment
- if comment then
- context("draw boundingbox currentpicture withcolor .6red ;")
- context('draw textext.bot("\\strut\\tttf %s") ysized (10pt) shifted center bottomboundary currentpicture ;',comment)
- end
- context.stopMPpage()
- end
-end
-
-function metapost.typesvgpage(data)
- local dd = data.data
- if not dd then
- local fn = data.filename
- dd = fn and table.load(fn)
- end
- if type(dd) == "table" then
- local index = data.index
- if index and index > 0 and index <= #dd then
- data = dd[index]
+ local offset = data.pageoffset
+ local index = data.index
+ local first = math.max(index or 1,1)
+ local last = math.min(index or #dd,#dd)
+ for i=first,last do
+ local d = setmetatableindex( {
+ data = dd[i],
+ comment = comment and i or false,
+ pageoffset = offset or nil,
+ }, data)
+ metapost.showsvgpage(d)
+ end
+ elseif data.method == "code" then
+ context.startMPcode(doublefun)
+ context(metapost.svgtomp(data))
+ context.stopMPcode()
else
- data = nil
+ context.startMPpage { instance = "doublefun", offset = data.pageoffset or nil }
+ context(metapost.svgtomp(data))
+ local comment = data.comment
+ if comment then
+ context("draw boundingbox currentpicture withcolor .6red ;")
+ context('draw textext.bot("\\strut\\tttf %s") ysized (10pt) shifted center bottomboundary currentpicture ;',comment)
+ end
+ context.stopMPpage()
end
end
- if type(data) == "string" and data ~= "" then
- buffers.assign("svgpage",data)
- context.typebuffer ({ "svgpage" }, { option = "XML", strip = "yes" })
+
+ function metapost.typesvgpage(data)
+ local dd = data.data
+ if not dd then
+ local fn = data.filename
+ dd = fn and table.load(fn)
+ end
+ if type(dd) == "table" then
+ local index = data.index
+ if index and index > 0 and index <= #dd then
+ data = dd[index]
+ else
+ data = nil
+ end
+ end
+ if type(data) == "string" and data ~= "" then
+ buffers.assign("svgpage",data)
+ context.typebuffer ({ "svgpage" }, { option = "XML", strip = "yes" })
+ end
end
-end
-function metapost.svgtopdf(data,...)
- local mps = metapost.svgtomp(data,...)
- if mps then
- -- todo: special instance, only basics needed
- local pdf = metapost.simple("metafun",mps,true,false,"svg")
- if pdf then
- return pdf
+ function metapost.svgtopdf(data,...)
+ local mps = metapost.svgtomp(data,...)
+ if mps then
+ -- todo: special instance, only basics needed
+ local pdf = metapost.simple("metafun",mps,true,false,"svg")
+ if pdf then
+ return pdf
+ else
+ -- message
+ end
else
-- message
end
- else
- -- message
end
+
end
do