summaryrefslogtreecommitdiff
path: root/tex/context
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context')
-rw-r--r--tex/context/base/mkii/cont-new.mkii2
-rw-r--r--tex/context/base/mkii/context.mkii2
-rw-r--r--tex/context/base/mkiv/anch-pos.lua2
-rw-r--r--tex/context/base/mkiv/attr-col.lua2
-rw-r--r--tex/context/base/mkiv/back-exp.lua8
-rw-r--r--tex/context/base/mkiv/cont-new.mkiv2
-rw-r--r--tex/context/base/mkiv/context-lmtx-error.pdfbin0 -> 4171 bytes
-rw-r--r--tex/context/base/mkiv/context-lmtx-error.tex8
-rw-r--r--tex/context/base/mkiv/context.mkiv2
-rw-r--r--tex/context/base/mkiv/context.mkxl2
-rw-r--r--tex/context/base/mkiv/data-vir.lua17
-rw-r--r--tex/context/base/mkiv/font-age.lua13
-rw-r--r--tex/context/base/mkiv/font-agl.lua15
-rw-r--r--tex/context/base/mkiv/font-mis.lua2
-rw-r--r--tex/context/base/mkiv/font-otl.lua2
-rw-r--r--tex/context/base/mkiv/font-oup.lua20
-rw-r--r--tex/context/base/mkiv/grph-con.lua22
-rw-r--r--tex/context/base/mkiv/grph-img.lua181
-rw-r--r--tex/context/base/mkiv/grph-inc.lua34
-rw-r--r--tex/context/base/mkiv/grph-inc.mkiv19
-rw-r--r--tex/context/base/mkiv/grph-trf.mkiv10
-rw-r--r--tex/context/base/mkiv/l-unicode.lua84
-rw-r--r--tex/context/base/mkiv/lang-txt.lua129
-rw-r--r--tex/context/base/mkiv/lpdf-ano.lua188
-rw-r--r--tex/context/base/mkiv/lpdf-img.lua25
-rw-r--r--tex/context/base/mkiv/lpdf-ini.lua14
-rw-r--r--tex/context/base/mkiv/lpdf-lmt.lua195
-rw-r--r--tex/context/base/mkiv/lpdf-pde.lua2
-rw-r--r--tex/context/base/mkiv/lpdf-tag.lua158
-rw-r--r--tex/context/base/mkiv/lxml-css.lua152
-rw-r--r--tex/context/base/mkiv/math-ini.lua2
-rw-r--r--tex/context/base/mkiv/math-ini.mkiv5
-rw-r--r--tex/context/base/mkiv/math-stc.mkvi107
-rw-r--r--tex/context/base/mkiv/meta-tex.mkiv83
-rw-r--r--tex/context/base/mkiv/mlib-cnt.lua12
-rw-r--r--tex/context/base/mkiv/mlib-lmp.lua71
-rw-r--r--tex/context/base/mkiv/mlib-pdf.lua71
-rw-r--r--tex/context/base/mkiv/mlib-pps.lua93
-rw-r--r--tex/context/base/mkiv/mlib-run.lua2
-rw-r--r--tex/context/base/mkiv/mlib-scn.lua7
-rw-r--r--tex/context/base/mkiv/mlib-svg.lua3617
-rw-r--r--tex/context/base/mkiv/mult-mps.lua2
-rw-r--r--tex/context/base/mkiv/mult-prm.lua3
-rw-r--r--tex/context/base/mkiv/node-ini.lua5
-rw-r--r--tex/context/base/mkiv/page-cst.lua1
-rw-r--r--tex/context/base/mkiv/page-ffl.mkiv6
-rw-r--r--tex/context/base/mkiv/page-lin.mkvi21
-rw-r--r--tex/context/base/mkiv/page-mix.lua12
-rw-r--r--tex/context/base/mkiv/page-mix.mkiv3
-rw-r--r--tex/context/base/mkiv/page-not.mkiv26
-rw-r--r--tex/context/base/mkiv/page-run.mkiv6
-rw-r--r--tex/context/base/mkiv/regi-ini.lua35
-rw-r--r--tex/context/base/mkiv/regi-ini.mkiv4
-rw-r--r--tex/context/base/mkiv/status-files.pdfbin26676 -> 26686 bytes
-rw-r--r--tex/context/base/mkiv/status-lua.pdfbin268444 -> 268844 bytes
-rw-r--r--tex/context/base/mkiv/strc-itm.mklx32
-rw-r--r--tex/context/base/mkiv/strc-not.mkvi20
-rw-r--r--tex/context/base/mkiv/strc-tag.lua8
-rw-r--r--tex/context/base/mkiv/strc-tag.mkiv10
-rw-r--r--tex/context/base/mkiv/syst-ini.mkxl1
-rw-r--r--tex/context/base/mkiv/tabl-ntb.mkiv74
-rw-r--r--tex/context/base/mkiv/tabl-ntb.mkxl74
-rw-r--r--tex/context/base/mkiv/typo-chr.mkiv1
-rw-r--r--tex/context/base/mkiv/typo-del.mkiv15
-rw-r--r--tex/context/interface/mkiv/i-context.pdfbin893281 -> 893544 bytes
-rw-r--r--tex/context/interface/mkiv/i-readme.pdfbin61165 -> 61165 bytes
-rw-r--r--tex/context/modules/common/s-abbreviations-logos.tex2
67 files changed, 3947 insertions, 1796 deletions
diff --git a/tex/context/base/mkii/cont-new.mkii b/tex/context/base/mkii/cont-new.mkii
index adfd46772..42dac33ab 100644
--- a/tex/context/base/mkii/cont-new.mkii
+++ b/tex/context/base/mkii/cont-new.mkii
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\newcontextversion{2019.10.11 15:47}
+\newcontextversion{2019.10.28 18:12}
%D This file is loaded at runtime, thereby providing an
%D excellent place for hacks, patches, extensions and new
diff --git a/tex/context/base/mkii/context.mkii b/tex/context/base/mkii/context.mkii
index 71b70dd56..d3691a6e7 100644
--- a/tex/context/base/mkii/context.mkii
+++ b/tex/context/base/mkii/context.mkii
@@ -20,7 +20,7 @@
%D your styles an modules.
\edef\contextformat {\jobname}
-\edef\contextversion{2019.10.11 15:47}
+\edef\contextversion{2019.10.28 18:12}
%D For those who want to use this:
diff --git a/tex/context/base/mkiv/anch-pos.lua b/tex/context/base/mkiv/anch-pos.lua
index ba830e3de..629e4f73f 100644
--- a/tex/context/base/mkiv/anch-pos.lua
+++ b/tex/context/base/mkiv/anch-pos.lua
@@ -69,7 +69,7 @@ local getwhd = nuts.getwhd
local hlist_code = nodes.nodecodes.hlist
local find_tail = nuts.tail
-local hpack = nuts.hpack
+----- hpack = nuts.hpack
local new_latelua = nuts.pool.latelua
diff --git a/tex/context/base/mkiv/attr-col.lua b/tex/context/base/mkiv/attr-col.lua
index 5ea72c7e3..15590dccc 100644
--- a/tex/context/base/mkiv/attr-col.lua
+++ b/tex/context/base/mkiv/attr-col.lua
@@ -549,7 +549,7 @@ local function extender(transparencies,key)
end
local function reviver(data,n)
- if transparencies.supported then
+ if n and transparencies.supported then
local v = values[n]
local d
if not v then
diff --git a/tex/context/base/mkiv/back-exp.lua b/tex/context/base/mkiv/back-exp.lua
index 617bf7cc3..deb11b4d2 100644
--- a/tex/context/base/mkiv/back-exp.lua
+++ b/tex/context/base/mkiv/back-exp.lua
@@ -1992,6 +1992,10 @@ do
end
end
+ function structurestags.gettablecell(fulltag)
+ return tabledata[fulltag]
+ end
+
function extras.tablecell(di,element,n,fulltag)
local hash = tabledata[fulltag]
if hash then
@@ -2027,6 +2031,10 @@ do
end
end
+ function structurestags.gettabulatecell(fulltag)
+ return tabulatedata[fulltag]
+ end
+
function extras.tabulate(di,element,n,fulltag)
local data = di.data
for i=1,#data do
diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv
index 4b584e787..f06aeab01 100644
--- a/tex/context/base/mkiv/cont-new.mkiv
+++ b/tex/context/base/mkiv/cont-new.mkiv
@@ -13,7 +13,7 @@
% \normalend % uncomment this to get the real base runtime
-\newcontextversion{2019.10.11 15:47}
+\newcontextversion{2019.10.28 18:12}
%D This file is loaded at runtime, thereby providing an excellent place for
%D hacks, patches, extensions and new features.
diff --git a/tex/context/base/mkiv/context-lmtx-error.pdf b/tex/context/base/mkiv/context-lmtx-error.pdf
new file mode 100644
index 000000000..0455781a3
--- /dev/null
+++ b/tex/context/base/mkiv/context-lmtx-error.pdf
Binary files differ
diff --git a/tex/context/base/mkiv/context-lmtx-error.tex b/tex/context/base/mkiv/context-lmtx-error.tex
new file mode 100644
index 000000000..25020cb59
--- /dev/null
+++ b/tex/context/base/mkiv/context-lmtx-error.tex
@@ -0,0 +1,8 @@
+\startTEXpage[offset=overlay,toffset=.5pt,boffset=.5pt,background=color,backgroundcolor=gray]
+ \definedfont[LMTypewriterVarWd-Regular]%
+ \darkred e%
+ \darkgreen r%
+ \darkblue r%
+ \darkyellow o%
+ \darkgray r%
+\stopTEXpage
diff --git a/tex/context/base/mkiv/context.mkiv b/tex/context/base/mkiv/context.mkiv
index 58334d47a..b367c0c44 100644
--- a/tex/context/base/mkiv/context.mkiv
+++ b/tex/context/base/mkiv/context.mkiv
@@ -45,7 +45,7 @@
%D {YYYY.MM.DD HH:MM} format.
\edef\contextformat {\jobname}
-\edef\contextversion{2019.10.11 15:47}
+\edef\contextversion{2019.10.28 18:12}
\edef\contextkind {beta}
%D Kind of special:
diff --git a/tex/context/base/mkiv/context.mkxl b/tex/context/base/mkiv/context.mkxl
index 1e235689a..77678596c 100644
--- a/tex/context/base/mkiv/context.mkxl
+++ b/tex/context/base/mkiv/context.mkxl
@@ -29,7 +29,7 @@
%D {YYYY.MM.DD HH:MM} format.
\edef\contextformat {\jobname}
-\edef\contextversion{2019.10.11 15:47}
+\edef\contextversion{2019.10.28 18:12}
\edef\contextkind {beta}
%D Kind of special:
diff --git a/tex/context/base/mkiv/data-vir.lua b/tex/context/base/mkiv/data-vir.lua
index 7e25c822d..c5e63039c 100644
--- a/tex/context/base/mkiv/data-vir.lua
+++ b/tex/context/base/mkiv/data-vir.lua
@@ -6,6 +6,7 @@ if not modules then modules = { } end modules ['data-vir'] = {
license = "see context related readme files"
}
+local type = type
local formatters, validstrings = string.formatters, string.valid
local trace_virtual = false
@@ -18,14 +19,18 @@ local resolvers = resolvers
local finders, openers, loaders, savers = resolvers.finders, resolvers.openers, resolvers.loaders, resolvers.savers
-local data = { }
-local n = 0 -- hm, number can be query
-local f_virtual = formatters["virtual://%s.%s"]
+local data = { }
+local n = 0 -- hm, number can be query
+local f_virtual_n = formatters["virtual://%s.%s"]
+local f_virtual_y = formatters["virtual://%s-%s.%s"]
-function savers.virtual(specification,content)
+function savers.virtual(specification,content,suffix)
n = n + 1 -- one number for all namespaces
- local path = specification.path
- local filename = f_virtual(path ~= "" and path or "virtualfile",n)
+ local path = type(specification) == "table" and specification.path or specification
+ if type(path) ~= "string" or path == "" then
+ path = "virtualfile"
+ end
+ local filename = suffix and f_virtual_y(path,n,suffix) or f_virtual_n(path,suffix)
if trace_virtual then
report_virtual("saver: file %a saved",filename)
end
diff --git a/tex/context/base/mkiv/font-age.lua b/tex/context/base/mkiv/font-age.lua
index b20a57538..1545c1c8d 100644
--- a/tex/context/base/mkiv/font-age.lua
+++ b/tex/context/base/mkiv/font-age.lua
@@ -12,6 +12,9 @@ if context then
os.exit()
end
+-- There is no need for a special script to generate this list as it's seldom
+-- changes: inspect(fonts.encodings.agl.unicodes) will do.
+
return {
["A"]=65,
["AE"]=198,
@@ -1603,6 +1606,7 @@ return {
["eightideographicparen"]=12839,
["eightinferior"]=8328,
["eightmonospace"]=65304,
+ ["eightoldstyle"]=56,
["eightparen"]=9339,
["eightperiod"]=9359,
["eightpersian"]=1784,
@@ -1760,6 +1764,7 @@ return {
["fiveideographicparen"]=12836,
["fiveinferior"]=8325,
["fivemonospace"]=65301,
+ ["fiveoldstyle"]=53,
["fiveparen"]=9336,
["fiveperiod"]=9356,
["fivepersian"]=1781,
@@ -1788,6 +1793,7 @@ return {
["fourinferior"]=8324,
["fourmonospace"]=65300,
["fournumeratorbengali"]=2551,
+ ["fouroldstyle"]=52,
["fourparen"]=9335,
["fourperiod"]=9355,
["fourpersian"]=1780,
@@ -2616,6 +2622,7 @@ return {
["nineideographicparen"]=12840,
["nineinferior"]=8329,
["ninemonospace"]=65305,
+ ["nineoldstyle"]=57,
["nineparen"]=9340,
["nineperiod"]=9360,
["ninepersian"]=1785,
@@ -2782,6 +2789,7 @@ return {
["oneinferior"]=8321,
["onemonospace"]=65297,
["onenumeratorbengali"]=2548,
+ ["oneoldstyle"]=49,
["oneparen"]=9332,
["oneperiod"]=9352,
["onepersian"]=1777,
@@ -3298,6 +3306,7 @@ return {
["sevenideographicparen"]=12838,
["seveninferior"]=8327,
["sevenmonospace"]=65303,
+ ["sevenoldstyle"]=55,
["sevenparen"]=9338,
["sevenperiod"]=9358,
["sevenpersian"]=1783,
@@ -3394,6 +3403,7 @@ return {
["sixideographicparen"]=12837,
["sixinferior"]=8326,
["sixmonospace"]=65302,
+ ["sixoldstyle"]=54,
["sixparen"]=9337,
["sixperiod"]=9357,
["sixpersian"]=1782,
@@ -3602,6 +3612,7 @@ return {
["threeinferior"]=8323,
["threemonospace"]=65299,
["threenumeratorbengali"]=2550,
+ ["threeoldstyle"]=51,
["threeparen"]=9334,
["threeperiod"]=9354,
["threepersian"]=1779,
@@ -3722,6 +3733,7 @@ return {
["twoinferior"]=8322,
["twomonospace"]=65298,
["twonumeratorbengali"]=2549,
+ ["twooldstyle"]=50,
["twoparen"]=9333,
["twoperiod"]=9353,
["twopersian"]=1778,
@@ -4088,6 +4100,7 @@ return {
["zerohackarabic"]=1632,
["zeroinferior"]=8320,
["zeromonospace"]=65296,
+ ["zerooldstyle"]=48,
["zeropersian"]=1776,
["zerosuperior"]=8304,
["zerothai"]=3664,
diff --git a/tex/context/base/mkiv/font-agl.lua b/tex/context/base/mkiv/font-agl.lua
index 49b85421f..19912b944 100644
--- a/tex/context/base/mkiv/font-agl.lua
+++ b/tex/context/base/mkiv/font-agl.lua
@@ -395,7 +395,7 @@ local synonyms = allocate {
zeroarabic = 0x0660,
}
-local extras = allocate { -- private extensions
+local extras = allocate { -- private extensions
Dcroat = 0x0110,
Delta = 0x2206,
Euro = 0x20AC,
@@ -635,6 +635,17 @@ local extras = allocate { -- private extensions
theta1 = 0x03D1,
twodotenleader = 0x2025,
+ zerooldstyle = 0x0030,
+ oneoldstyle = 0x0031,
+ twooldstyle = 0x0032,
+ threeoldstyle = 0x0033,
+ fouroldstyle = 0x0034,
+ fiveoldstyle = 0x0035,
+ sixoldstyle = 0x0036,
+ sevenoldstyle = 0x0037,
+ eightoldstyle = 0x0038,
+ nineoldstyle = 0x0039,
+
dotlessj = 0x0237,
}
@@ -653,7 +664,7 @@ if names then
mark(unicodes)
mark(ctxcodes)
-else
+elseif characters then
names = allocate { } -- filled from char-def.lua
unicodes = allocate { }
diff --git a/tex/context/base/mkiv/font-mis.lua b/tex/context/base/mkiv/font-mis.lua
index c3fb58580..da02ab608 100644
--- a/tex/context/base/mkiv/font-mis.lua
+++ b/tex/context/base/mkiv/font-mis.lua
@@ -21,7 +21,7 @@ local readers = otf.readers
if readers then
- otf.version = otf.version or 3.109
+ otf.version = otf.version or 3.110
otf.cache = otf.cache or containers.define("fonts", "otl", otf.version, true)
function fonts.helpers.getfeatures(name,save)
diff --git a/tex/context/base/mkiv/font-otl.lua b/tex/context/base/mkiv/font-otl.lua
index 8bf44d79e..5d3bd4230 100644
--- a/tex/context/base/mkiv/font-otl.lua
+++ b/tex/context/base/mkiv/font-otl.lua
@@ -52,7 +52,7 @@ local report_otf = logs.reporter("fonts","otf loading")
local fonts = fonts
local otf = fonts.handlers.otf
-otf.version = 3.109 -- beware: also sync font-mis.lua and in mtx-fonts
+otf.version = 3.110 -- beware: also sync font-mis.lua and in mtx-fonts
otf.cache = containers.define("fonts", "otl", otf.version, true)
otf.svgcache = containers.define("fonts", "svg", otf.version, true)
otf.pngcache = containers.define("fonts", "png", otf.version, true)
diff --git a/tex/context/base/mkiv/font-oup.lua b/tex/context/base/mkiv/font-oup.lua
index 51b1c248f..0e7e25808 100644
--- a/tex/context/base/mkiv/font-oup.lua
+++ b/tex/context/base/mkiv/font-oup.lua
@@ -720,6 +720,10 @@ local function checklookups(fontdata,missing,nofmissing)
end
end
+local firstprivate = fonts.privateoffsets and fonts.privateoffsets.textbase or 0xF0000
+local puafirst = 0xE000
+local pualast = 0xF8FF
+
local function unifymissing(fontdata)
if not fonts.mappings then
require("font-map")
@@ -730,20 +734,22 @@ local function unifymissing(fontdata)
resources.unicodes = unicodes
for unicode, d in next, fontdata.descriptions do
if unicode < privateoffset then
- local name = d.name
- if name then
- unicodes[name] = unicode
+ if unicode >= puafirst and unicode <= pualast then
+ -- report_unicodes("resolving private unicode %U",unicode)
+ else
+ local name = d.name
+ if name then
+ unicodes[name] = unicode
+ end
end
+ else
+ -- report_unicodes("resolving private unicode %U",unicode)
end
end
fonts.mappings.addtounicode(fontdata,fontdata.filename,checklookups)
resources.unicodes = nil
end
-local firstprivate = fonts.privateoffsets and fonts.privateoffsets.textbase or 0xF0000
-local puafirst = 0xE000
-local pualast = 0xF8FF
-
local function unifyglyphs(fontdata,usenames)
local private = fontdata.private or privateoffset
local glyphs = fontdata.glyphs
diff --git a/tex/context/base/mkiv/grph-con.lua b/tex/context/base/mkiv/grph-con.lua
index ab6651f97..788136f6d 100644
--- a/tex/context/base/mkiv/grph-con.lua
+++ b/tex/context/base/mkiv/grph-con.lua
@@ -420,3 +420,25 @@ do -- png | jpg | profiles
end
end
+
+if CONTEXTLMTXMODE > 0 then
+
+ -- This might also work ok in mkiv but is yet untested. Anyway, it's experimental as we
+ -- go through TeX which is is inefficient. I'll improve the buffer trick.
+
+ local function remap(specification)
+ local fullname = specification.fullname
+ if fullname then
+ local only = file.nameonly(fullname)
+ local name = formatters["svg-%s-inclusion"](only)
+ local code = formatters["\\includesvgfile[%s]\\resetbuffer[%s]"](fullname,name)
+ buffers.assign(name,code)
+ specification.format = "buffer"
+ specification.fullname = name
+ end
+ return specification
+ end
+
+ figures.remappers.svg = { mp = remap }
+
+end
diff --git a/tex/context/base/mkiv/grph-img.lua b/tex/context/base/mkiv/grph-img.lua
index 795ea4827..4b4bee1fc 100644
--- a/tex/context/base/mkiv/grph-img.lua
+++ b/tex/context/base/mkiv/grph-img.lua
@@ -16,27 +16,9 @@ local round = math.round
local concat = table.concat
local suffixonly = file.suffix
-local files = utilities.files
-local getsize = files.getsize
-local readbyte = files.readbyte
-local readstring = files.readstring
-local readcardinal = files.readcardinal
-local readcardinal2 = files.readcardinal2
-local readcardinal4 = files.readcardinal4
-local readcardinal2le = files.readcardinal2le
-local readcardinal4le = files.readcardinal4le
-local skipbytes = files.skip
-local setposition = files.setposition
-local getposition = files.getposition
-
-local newreader = io.newreader
-
-local setmetatableindex = table.setmetatableindex
-local setmetatablecall = table.setmetatablecall
-
------ lpdf = lpdf or { }
------ pdfmajorversion = lpdf.majorversion
------ pdfminorversion = lpdf.minorversion
+local newreader = io.newreader
+local setmetatableindex = table.setmetatableindex
+local setmetatablecall = table.setmetatablecall
local graphics = graphics or { }
local identifiers = { }
@@ -119,22 +101,20 @@ do
-- good old tiff tags here.
local function read_APP1_Exif(f, xres, yres, orientation) -- untested
- local position = false
- local readcardinal2 = readcardinal2
- local readcardinal4 = readcardinal4
+ local position = false
+ local littleendian = false
-- endian II|MM
while true do
- position = getposition(f)
- local b = readbyte(f)
+ position = f:getposition()
+ local b = f:readbyte()
if b == 0 then
-- next one
- elseif b == 0x4D and readbyte(f) == 0x4D then -- M
+ elseif b == 0x4D and f:readbyte() == 0x4D then -- M
-- big endian
break
- elseif b == 0x49 and readbyte(f) == 0x49 then -- I
+ elseif b == 0x49 and f:readbyte() == 0x49 then -- I
-- little endian
- readcardinal2 = readcardinal2le
- readcardinal4 = readcardinal4le
+ littleendian = true
break
else
-- warning "bad exif data"
@@ -142,46 +122,46 @@ do
end
end
-- version
- local version = readcardinal2(f)
+ local version = littleendian and f:readcardinal2le() or f:readcardinal2()
if version ~= 42 then
return xres, yres, orientation
end
-- offset to records
- local offset = readcardinal4(f)
+ local offset = littleendian and f:readcardinal4le() or f:readcardinal4()
if not offset then
return xres, yres, orientation
end
- setposition(f,position + offset)
- local entries = readcardinal2(f)
+ f:setposition(position + offset)
+ local entries = littleendian and f:readcardinal2le() or f:readcardinal2()
if not entries or entries == 0 then
return xres, yres, orientation
end
local x_res, y_res, x_res_ms, y_res_ms, x_temp, y_temp
local res_unit, res_unit_ms
for i=1,entries do
- local tag = readcardinal2(f)
- local kind = readcardinal2(f)
- local size = readcardinal4(f)
+ local tag = littleendian and f:readcardinal2le() or f:readcardinal2()
+ local kind = littleendian and f:readcardinal2le() or f:readcardinal2()
+ local size = littleendian and f:readcardinal4le() or f:readcardinal4()
local value = 0
local num = 0
local den = 0
if kind == 1 or kind == 7 then -- byte | undefined
- value = readbyte(f)
- skipbytes(f,3)
+ value = f:readbyte()
+ f:skip(3)
elseif kind == 3 or kind == 8 then -- (un)signed short
- value = readcardinal2(f)
- skipbytes(f,2)
+ value = littleendian and f:readcardinal2le() or f:readcardinal2()
+ f:skip(2)
elseif kind == 4 or kind == 9 then -- (un)signed long
- value = readcardinal4(f)
+ value = littleendian and f:readcardinal4le() or f:readcardinal4()
elseif kind == 5 or kind == 10 then -- (s)rational
- local offset = readcardinal4(f)
- local saved = getposition(f)
- setposition(f,position+offset)
- num = readcardinal4(f)
- den = readcardinal4(f)
- setposition(f,saved)
+ local offset = littleendian and f:readcardinal4le() or f:readcardinal4()
+ local saved = f:getposition()
+ f:setposition(position+offset)
+ num = littleendian and f:readcardinal4le() or f:readcardinal4()
+ den = littleendian and f:readcardinal4le() or f:readcardinal4()
+ f:setposition(saved)
else -- 2 -- ascii
- skipbytes(f,4)
+ f:skip(4)
end
if tag == 274 then -- orientation
orientation = value
@@ -226,7 +206,7 @@ do
return round(xres), round(yres), orientation
end
- function identifiers.jpg(filename)
+ function identifiers.jpg(filename,method)
local specification = {
filename = filename,
filetype = "jpg",
@@ -235,7 +215,7 @@ do
specification.error = "invalid filename"
return specification -- error
end
- local f = io.open(filename,"rb")
+ local f = newreader(filename,method)
if not f then
specification.error = "unable to open file"
return specification -- error
@@ -246,7 +226,7 @@ do
specification.totalpages = 1
specification.pagenum = 1
specification.length = 0
- local banner = readcardinal2(f)
+ local banner = f:readcardinal2()
if banner ~= 0xFFD8 then
specification.error = "no jpeg file"
return specification -- error
@@ -255,11 +235,11 @@ do
local yres = 0
local orientation = 1
local okay = false
- local filesize = getsize(f) -- seek end
+ local filesize = f:getsize() -- seek end
-- local majorversion = pdfmajorversion and pdfmajorversion() or 1
-- local minorversion = pdfminorversion and pdfminorversion() or 7
- while getposition(f) < filesize do
- local b = readbyte(f)
+ while f:getposition() < filesize do
+ local b = f:readbyte()
if not b then
break
elseif b ~= 0xFF then
@@ -269,8 +249,8 @@ do
end
break
end
- local category = readbyte(f)
- local position = getposition(f)
+ local category = f:readbyte()
+ local position = f:getposition()
local length = 0
local tagdata = tags[category]
if not tagdata then
@@ -290,25 +270,25 @@ do
-- specification.error = "no progressive DCT in PDF <= 1.2"
-- break
-- end
- length = readcardinal2(f)
- specification.colordepth = readcardinal(f)
- specification.ysize = readcardinal2(f)
- specification.xsize = readcardinal2(f)
- specification.colorspace = colorspaces[readcardinal(f)]
+ length = f:readcardinal2()
+ specification.colordepth = f:readcardinal()
+ specification.ysize = f:readcardinal2()
+ specification.xsize = f:readcardinal2()
+ specification.colorspace = colorspaces[f:readcardinal()]
if not specification.colorspace then
specification.error = "unsupported color space"
break
end
okay = true
elseif name == "APP0" then
- length = readcardinal2(f)
+ length = f:readcardinal2()
if length > 6 then
- local format = readstring(f,5)
+ local format = f:readstring(5)
if format == "JFIF\000" then
- skipbytes(f,2)
- units = readcardinal(f)
- xres = readcardinal2(f)
- yres = readcardinal2(f)
+ f:skip(2)
+ units = f:readcardinal()
+ xres = f:readcardinal2()
+ yres = f:readcardinal2()
if units == 1 then
-- pixels per inch
if xres == 1 or yres == 1 then
@@ -325,18 +305,18 @@ do
end
end
elseif name == "APP1" then
- length = readcardinal2(f)
+ length = f:readcardinal2()
if length > 7 then
- local format = readstring(f,5)
+ local format = f:readstring(5)
if format == "Exif\000" then
xres, yres, orientation = read_APP1_Exif(f,xres,yres,orientation)
end
end
elseif not tagdata.zerolength then
- length = readcardinal2(f)
+ length = f:readcardinal2()
end
if length > 0 then
- setposition(f,position+length)
+ f:setposition(position+length)
end
end
f:close()
@@ -362,15 +342,15 @@ end
do
local function read_boxhdr(specification,f)
- local size = readcardinal4(f)
- local kind = readstring(f,4)
+ local size = f:readcardinal4()
+ local kind = f:readstring(4)
if kind then
kind = strip(lower(kind))
else
kind = ""
end
if size == 1 then
- size = readcardinal4(f) * 0xFFFF0000 + readcardinal4(f)
+ size = f:readcardinal4() * 0xFFFF0000 + f:readcardinal4()
end
if size == 0 and kind ~= "jp2c" then -- move this
specification.error = "invalid size"
@@ -379,40 +359,40 @@ do
end
local function scan_ihdr(specification,f)
- specification.ysize = readcardinal4(f)
- specification.xsize = readcardinal4(f)
- skipbytes(f,2) -- nc
- specification.colordepth = readcardinal(f) + 1
- skipbytes(f,3) -- c unkc ipr
+ specification.ysize = f:readcardinal4()
+ specification.xsize = f:readcardinal4()
+ f:skip(2) -- nc
+ specification.colordepth = f:readcardinal() + 1
+ f:skip(3) -- c unkc ipr
end
local function scan_resc_resd(specification,f)
- local vr_n = readcardinal2(f)
- local vr_d = readcardinal2(f)
- local hr_n = readcardinal2(f)
- local hr_d = readcardinal2(f)
- local vr_e = readcardinal(f)
- local hr_e = readcardinal(f)
+ local vr_n = f:readcardinal2()
+ local vr_d = f:readcardinal2()
+ local hr_n = f:readcardinal2()
+ local hr_d = f:readcardinal2()
+ local vr_e = f:readcardinal()
+ local hr_e = f:readcardinal()
specification.xres = math.round((hr_n / hr_d) * math.exp(hr_e * math.log(10.0)) * 0.0254)
specification.yres = math.round((vr_n / vr_d) * math.exp(vr_e * math.log(10.0)) * 0.0254)
end
local function scan_res(specification,f,last)
- local pos = getposition(f)
+ local pos = f:getposition()
while true do
local kind, size = read_boxhdr(specification,f)
pos = pos + size
if kind == "resc" then
if specification.xres == 0 and specification.yres == 0 then
scan_resc_resd(specification,f)
- if getposition(f) ~= pos then
+ if f:getposition() ~= pos then
specification.error = "invalid resc"
return
end
end
elseif tpos == "resd" then
scan_resc_resd(specification,f)
- if getposition(f) ~= pos then
+ if f:getposition() ~= pos then
specification.error = "invalid resd"
return
end
@@ -425,19 +405,19 @@ do
if specification.error then
break
end
- setposition(f,pos)
+ f:setposition(pos)
end
end
local function scan_jp2h(specification,f,last)
local okay = false
- local pos = getposition(f)
+ local pos = f:getposition()
while true do
local kind, size = read_boxhdr(specification,f)
pos = pos + size
if kind == "ihdr" then
scan_ihdr(specification,f)
- if getposition(f) ~= pos then
+ if f:getposition() ~= pos then
specification.error = "invalid ihdr"
return false
end
@@ -453,12 +433,12 @@ do
if specification.error then
break
end
- setposition(f,pos)
+ f:setposition(pos)
end
return okay
end
- function identifiers.jp2(filename)
+ function identifiers.jp2(filename,method)
local specification = {
filename = filename,
filetype = "jp2",
@@ -467,7 +447,7 @@ do
specification.error = "invalid filename"
return specification -- error
end
- local f = io.open(filename,"rb")
+ local f = newreader(filename,method)
if not f then
specification.error = "unable to open file"
return specification -- error
@@ -482,13 +462,13 @@ do
local yres = 0
local orientation = 1
local okay = false
- local filesize = getsize(f) -- seek end
+ local filesize = f:getsize() -- seek end
--
local pos = 0
-- signature
local kind, size = read_boxhdr(specification,f)
pos = pos + size
- setposition(f,pos)
+ f:setposition(pos)
-- filetype
local kind, size = read_boxhdr(specification,f)
if kind ~= "ftyp" then
@@ -496,7 +476,7 @@ do
return specification
end
pos = pos + size
- setposition(f,pos)
+ f:setposition(pos)
while not okay do
local kind, size = read_boxhdr(specification,f)
pos = pos + size
@@ -506,7 +486,7 @@ do
specification.error = "no ihdr box found"
return specification
end
- setposition(f,pos)
+ f:setposition(pos)
end
--
f:close()
@@ -538,7 +518,7 @@ do
-- 6 = rgb + alpha "image c"
-- for i=1,length/3 do
- -- palette[i] = readstring(f,3)
+ -- palette[i] = f:readstring3)
-- end
local function grab(t,f,once)
@@ -635,7 +615,6 @@ do
tables[kind] = t
end
t[#t+1] = {
--- offset = getposition(f),
offset = f:getposition(),
length = length,
}
diff --git a/tex/context/base/mkiv/grph-inc.lua b/tex/context/base/mkiv/grph-inc.lua
index bfe67094e..1d59972ab 100644
--- a/tex/context/base/mkiv/grph-inc.lua
+++ b/tex/context/base/mkiv/grph-inc.lua
@@ -298,6 +298,7 @@ local figures_resources = allocate() figures.resources = figures_resources
local existers = allocate() figures.existers = existers
local checkers = allocate() figures.checkers = checkers
local includers = allocate() figures.includers = includers
+local remappers = allocate() figures.remappers = remappers
local converters = allocate() figures.converters = converters
local identifiers = allocate() figures.identifiers = identifiers
local programs = allocate() figures.programs = programs
@@ -324,7 +325,7 @@ local figures_order = allocate {
local figures_formats = allocate { -- magic and order will move here
["pdf"] = { list = { "pdf" } },
- ["mps"] = { patterns = { "mps", "%d+" } },
+ ["mps"] = { patterns = { "^mps$", "^%d+$" } }, -- we need to anchor
["jpg"] = { list = { "jpg", "jpeg" } },
["png"] = { list = { "png" } },
["jp2"] = { list = { "jp2" } },
@@ -779,24 +780,32 @@ local function register(askedname,specification)
arguments or ""
)
end
- -- quick hack
- local converter = (newformat ~= format or resolution or arguments) and converters[format]
+ -- begin of quick hack
+ local remapper = remappers[format]
+ if remapper then
+ remapper = remapper[conversion]
+ if remapper then
+ specification = remapper(specification) or specification
+ format = specification.format
+ newformat = format
+ conversion = nil
+ end
+ end
+ -- end of quick hack
+ local converter = (not remapper) and (newformat ~= format or resolution or arguments) and converters[format]
if converter then
- if converter[newformat] then
- converter = converter[newformat]
+ local okay = converter[newformat]
+ if okay then
+ converter = okay
else
newformat = defaultformat
- if converter[newformat] then
- converter = converter[newformat]
- else
- converter = nil
- newformat = defaultformat
- end
+ converter = converter[newformat]
end
elseif trace_conversion then
report_inclusion("no converter for %a to %a",format,newformat)
end
if converter then
+ -- todo: make this a function
--
-- todo: outline as helper function
--
@@ -891,7 +900,7 @@ local function register(askedname,specification)
format = suffix
end
end
-specification.format = format
+ specification.format = format
elseif io.exists(oldname) then
report_inclusion("file %a is bugged",oldname)
if format and imagetypes[format] then
@@ -1425,6 +1434,7 @@ local transforms = setmetatableindex (
local function checktransform(figure,forced)
if auto_transform then
+
local orientation = (forced ~= "" and forced ~= v_auto and forced) or figure.orientation or 0
local transform = transforms["orientation-"..orientation]
figure.transform = transform
diff --git a/tex/context/base/mkiv/grph-inc.mkiv b/tex/context/base/mkiv/grph-inc.mkiv
index 31c9cbce9..578bad1d0 100644
--- a/tex/context/base/mkiv/grph-inc.mkiv
+++ b/tex/context/base/mkiv/grph-inc.mkiv
@@ -904,6 +904,25 @@
\unexpanded\def\overlayfigure#1%
{\externalfigure[#1][\c!width=\d_overlay_width,\c!height=\d_overlay_height]}
+% Experimental (will become cleaner):
+
+\ifcase\contextlmtxmode \else
+
+ \unexpanded\def\includesvgfile {\dontleavehmode\begingroup\dodoubleempty\grph_include_svg_file}
+ \unexpanded\def\includesvgbuffer{\dontleavehmode\begingroup\dodoubleempty\grph_include_svg_buffer}
+
+ \def\grph_include_svg_file[#1][#2]%
+ {\getdummyparameters[\c!offset=\zeropoint,#2]%
+ \clf_includesvgfile{#1}\dimexpr\dummyparameter\c!offset\relax
+ \endgroup}
+
+ \def\grph_include_svg_buffer[#1][#2]%
+ {\getdummyparameters[\c!offset=\zeropoint,#2]%
+ \clf_includesvgbuffer{#1}\dimexpr\dummyparameter\c!offset\relax
+ \endgroup}
+
+\fi
+
% Bonus:
\useexternalfigure
diff --git a/tex/context/base/mkiv/grph-trf.mkiv b/tex/context/base/mkiv/grph-trf.mkiv
index 0c7ba22f8..274b2f8ef 100644
--- a/tex/context/base/mkiv/grph-trf.mkiv
+++ b/tex/context/base/mkiv/grph-trf.mkiv
@@ -603,8 +603,18 @@
\edef\p_sy{#2}%
\dowithnextboxcs\grph_scale_fast_sx_xy_finish\hbox}
+% \def\grph_scale_fast_sx_xy_finish
+% {\grph_scale_check_sx_sy
+% \grph_scale_calculations_nop
+% \grph_scale_apply
+% \box\nextbox
+% \egroup}
+
\def\grph_scale_fast_sx_xy_finish
{\grph_scale_check_sx_sy
+ \d_grph_scale_wd\wd\nextbox
+ \d_grph_scale_ht\ht\nextbox
+ \d_grph_scale_dp\dp\nextbox
\grph_scale_calculations_nop
\grph_scale_apply
\box\nextbox
diff --git a/tex/context/base/mkiv/l-unicode.lua b/tex/context/base/mkiv/l-unicode.lua
index 13e0a3fa1..c57aaf33e 100644
--- a/tex/context/base/mkiv/l-unicode.lua
+++ b/tex/context/base/mkiv/l-unicode.lua
@@ -1081,56 +1081,62 @@ function utf.utf32_to_utf8_t(t,endian)
return endian and utf32_to_utf8_be_t(t) or utf32_to_utf8_le_t(t) or t
end
-local function little(b)
- if b < 0x10000 then
- return char(b%256,rshift(b,8))
- else
- b = b - 0x10000
- local b1 = rshift(b,10) + 0xD800
- local b2 = b%1024 + 0xDC00
- return char(b1%256,rshift(b1,8),b2%256,rshift(b2,8))
+if bit32 then
+
+ local rshift = bit32.rshift
+
+ local function little(b)
+ if b < 0x10000 then
+ return char(b%256,rshift(b,8))
+ else
+ b = b - 0x10000
+ local b1 = rshift(b,10) + 0xD800
+ local b2 = b%1024 + 0xDC00
+ return char(b1%256,rshift(b1,8),b2%256,rshift(b2,8))
+ end
end
-end
-local function big(b)
- if b < 0x10000 then
- return char(rshift(b,8),b%256)
- else
- b = b - 0x10000
- local b1 = rshift(b,10) + 0xD800
- local b2 = b%1024 + 0xDC00
- return char(rshift(b1,8),b1%256,rshift(b2,8),b2%256)
+ local function big(b)
+ if b < 0x10000 then
+ return char(rshift(b,8),b%256)
+ else
+ b = b - 0x10000
+ local b1 = rshift(b,10) + 0xD800
+ local b2 = b%1024 + 0xDC00
+ return char(rshift(b1,8),b1%256,rshift(b2,8),b2%256)
+ end
end
-end
-local l_remap = Cs((p_utf8byte/little+P(1)/"")^0)
-local b_remap = Cs((p_utf8byte/big +P(1)/"")^0)
+ local l_remap = Cs((p_utf8byte/little+P(1)/"")^0)
+ local b_remap = Cs((p_utf8byte/big +P(1)/"")^0)
-local function utf8_to_utf16_be(str,nobom)
- if nobom then
- return lpegmatch(b_remap,str)
- else
- return char(254,255) .. lpegmatch(b_remap,str)
+ local function utf8_to_utf16_be(str,nobom)
+ if nobom then
+ return lpegmatch(b_remap,str)
+ else
+ return char(254,255) .. lpegmatch(b_remap,str)
+ end
end
-end
-local function utf8_to_utf16_le(str,nobom)
- if nobom then
- return lpegmatch(l_remap,str)
- else
- return char(255,254) .. lpegmatch(l_remap,str)
+ local function utf8_to_utf16_le(str,nobom)
+ if nobom then
+ return lpegmatch(l_remap,str)
+ else
+ return char(255,254) .. lpegmatch(l_remap,str)
+ end
end
-end
-utf.utf8_to_utf16_be = utf8_to_utf16_be
-utf.utf8_to_utf16_le = utf8_to_utf16_le
+ utf.utf8_to_utf16_be = utf8_to_utf16_be
+ utf.utf8_to_utf16_le = utf8_to_utf16_le
-function utf.utf8_to_utf16(str,littleendian,nobom)
- if littleendian then
- return utf8_to_utf16_le(str,nobom)
- else
- return utf8_to_utf16_be(str,nobom)
+ function utf.utf8_to_utf16(str,littleendian,nobom)
+ if littleendian then
+ return utf8_to_utf16_le(str,nobom)
+ else
+ return utf8_to_utf16_be(str,nobom)
+ end
end
+
end
local pattern = Cs (
diff --git a/tex/context/base/mkiv/lang-txt.lua b/tex/context/base/mkiv/lang-txt.lua
index daf8f787e..f89795e39 100644
--- a/tex/context/base/mkiv/lang-txt.lua
+++ b/tex/context/base/mkiv/lang-txt.lua
@@ -36,6 +36,7 @@ if not modules then modules = { } end modules ['lang-txt'] = {
-- kr Korean Jeong Dalyoung
-- la Latin ...
-- lt Lithuanian Marius Aleknevičius
+-- mk Macedonian Jakub Loula, Tomáš Hála (2019), Stojan Trajanovski
-- nb Norwegian Hans Fredrik Nordhaug, ...
-- nn Norwegian Hans Fredrik Nordhaug, ...
-- nl Dutch Hans Hagen
@@ -44,7 +45,7 @@ if not modules then modules = { } end modules ['lang-txt'] = {
-- pt Portuguese Pedro F. M. Mendonça
-- ro Romanian Dan Seracu, ...
-- ru Russian Olga Briginets, Alexander Bokovoy, Victor Figurnov, ...
--- sk Slovak ...
+-- sk Slovak Tomáš Hála (2012)
-- sl Slovenian Mojca Miklavec
-- sv Swedish ...
-- tk Turkish Tobias Burnus
@@ -73,6 +74,7 @@ data.labels={
["en"]="In",
["es"]="En",
["fr"]="Dans",
+ ["mk"]="во",
["pe"]="در",
},
},
@@ -81,6 +83,7 @@ data.labels={
["de"]="Numer",
["en"]="Number",
["fr"]="Numéro",
+ ["mk"]="Број",
["nl"]="Nummer",
["pe"]="شماره",
},
@@ -90,6 +93,7 @@ data.labels={
["de"]="Band",
["en"]="Volume",
["et"]="Köide",
+ ["mk"]="Том",
["nl"]="Deel",
["pe"]="جلد",
},
@@ -102,6 +106,7 @@ data.labels={
["et"]="ja",
["fr"]="et",
["it"]="e",
+ ["mk"]="и",
["nl"]="en",
["pe"]="و",
},
@@ -114,6 +119,7 @@ data.labels={
["et"]="väljaanne",
["fr"]="édition",
["it"]="edizione",
+ ["mk"]="издание",
["nl"]="editie",
["pe"]="ویرایش",
},
@@ -125,6 +131,7 @@ data.labels={
["et"]="toimetaja",
["fr"]="éditeur",
["it"]="a cura di",
+ ["mk"]="уредник",
["pe"]="ویراستار",
},
},
@@ -136,6 +143,8 @@ data.labels={
["et"]="toimetajad",
["fr"]="éditeurs",
["it"]="a cura di",
+ ["mk"]="уредници",
+
},
},
["in"]={
@@ -143,6 +152,7 @@ data.labels={
["en"]="in",
["es"]="en",
["fr"]="dans",
+ ["mk"]="во",
["pe"]="در",
},
},
@@ -154,6 +164,7 @@ data.labels={
["et"]="magistritöö",
["fr"]="Thèse de master (DEA, DESS, master)",
["it"]="Tesi di laurea",
+ ["mk"]="Магистерска дисертација",
["nl"]="Masterproef",
["pe"]="پایان‌نامه کارشناسی ارشد",
},
@@ -163,6 +174,7 @@ data.labels={
["de"]="Numer",
["en"]="number",
["fr"]="numéro",
+ ["mk"]="број",
["nl"]="nummer",
["pe"]="شماره",
},
@@ -172,6 +184,7 @@ data.labels={
["de"]="von",
["en"]="of",
["fr"]="de",
+ ["mk"]="од",
["nl"]="van",
},
},
@@ -179,12 +192,14 @@ data.labels={
["labels"]={
["en"]="et al.",
["et"]="jt",
+ ["mk"]="и др.",
},
},
["p"]={
["labels"]={
["de"]="S.",
["en"]="p.",
+ ["mk"]="стр.",
["et"]="lk",
["pe"]="ص",
},
@@ -194,6 +209,7 @@ data.labels={
["de"]="Seiten",
["en"]="pages",
["et"]="leheküljed",
+ ["mk"]="страници",
["nl"]="paginas",
["pe"]="صفحات",
},
@@ -206,6 +222,7 @@ data.labels={
["et"]="Patent",
["fr"]="Brevet",
["it"]="Brevetto",
+ ["mk"]="Патент",
["nl"]="Octrooi",
},
},
@@ -217,6 +234,7 @@ data.labels={
["et"]="doktoritöö",
["fr"]="Thèse de doctorat",
["it"]="Tesi di dottorato",
+ ["mk"]="Докторска дисертација",
["nl"]="Proefschrift",
["pe"]="رساله دکتری",
},
@@ -226,6 +244,7 @@ data.labels={
["de"]="S.",
["en"]="pp.",
["et"]="lk-d",
+ ["mk"]="стр.",
["pe"]="صص",
},
},
@@ -237,6 +256,7 @@ data.labels={
["et"]="tehniline raport",
["fr"]="Rapport technique",
["it"]="Relazione tecnica",
+ ["mk"]="Технички извештај",
["nl"]="Technisch rapport",
["pe"]="گزارش فنی",
},
@@ -246,6 +266,7 @@ data.labels={
["de"]="Band",
["en"]="volume",
["et"]="köide",
+ ["mk"]="том",
["nl"]="deel",
["pe"]="جلد",
},
@@ -258,6 +279,7 @@ data.labels={
["et"]="koos",
["fr"]="avec",
["it"]="con",
+ ["mk"]="со",
["nl"]="met",
},
},
@@ -267,6 +289,7 @@ data.labels={
["labels"]={
["cz"]="P",
["en"]="Pr",
+ ["mk"]="P",
["sk"]="P",
},
},
@@ -276,6 +299,7 @@ data.labels={
["en"]="arccos",
["es"]="arc\\sixperemspace cos",
["hr"]="arc\\sixperemspace cos",
+ ["mk"]="arccos",
["pl"]="arc\\sixperemspace cos",
["sk"]="arccos",
},
@@ -286,6 +310,7 @@ data.labels={
["en"]="arccosh",
["es"]="arc\\sixperemspace cosh",
["hr"]="arc\\sixperemspace cosh",
+ ["mk"]="arccosh",
["pl"]="arc\\sixperemspace cosh",
["sk"]="arccosh",
},
@@ -296,6 +321,7 @@ data.labels={
["en"]="arccot",
["es"]="arc\\sixperemspace cot",
["hr"]="arc\\sixperemspace ctg",
+ ["mk"]="arccotg",
["pl"]="arc\\sixperemspace ctg",
["sk"]="arccotg",
},
@@ -306,6 +332,7 @@ data.labels={
["en"]="arcsin",
["es"]="arc\\sixperemspace sen",
["hr"]="arc\\sixperemspace sin",
+ ["mk"]="arcsin",
["pl"]="arc\\sixperemspace sin",
["sk"]="arcsin",
},
@@ -316,6 +343,7 @@ data.labels={
["en"]="arcsinh",
["es"]="arc\\sixperemspace senh",
["hr"]="arc\\sixperemspace sinh",
+ ["mk"]="arcsinh",
["pl"]="arc\\sixperemspace sinh",
["sk"]="arcsinh",
},
@@ -326,6 +354,7 @@ data.labels={
["en"]="arctan",
["es"]="arc\\sixperemspace tan",
["hr"]="arc\\sixperemspace tg",
+ ["mk"]="arctg",
["pl"]="arc\\sixperemspace tg",
["sk"]="arctg",
},
@@ -336,8 +365,9 @@ data.labels={
["en"]="arctanh",
["es"]="arc\\sixperemspace tanh",
["hr"]="arc\\sixperemspace tgh",
+ ["mk"]="arctgh",
["pl"]="arc\\sixperemspace tgh",
- ["sk"]="arctg",
+ ["sk"]="arctgh",
},
},
["arg"]={
@@ -345,6 +375,7 @@ data.labels={
["cz"]="arg",
["en"]="arg",
["es"]="arg",
+ ["mk"]="arg",
["sk"]="arg",
},
},
@@ -353,6 +384,7 @@ data.labels={
["cz"]="cos",
["en"]="cos",
["es"]="cos",
+ ["mk"]="cos",
["sk"]="cos",
},
},
@@ -361,6 +393,7 @@ data.labels={
["cz"]="cosh",
["en"]="cosh",
["es"]="cosh",
+ ["mk"]="cosh",
["sk"]="cosh",
},
},
@@ -370,6 +403,7 @@ data.labels={
["en"]="cot",
["es"]="cot",
["hr"]="ctg",
+ ["mk"]="ctg",
["pl"]="ctg",
["sk"]="cotg",
},
@@ -379,6 +413,7 @@ data.labels={
["cz"]="cotgh",
["en"]="coth",
["es"]="coth",
+ ["mk"]="ctgh",
["sk"]="cotgh",
},
},
@@ -387,6 +422,7 @@ data.labels={
["cz"]="cosec",
["en"]="csc",
["es"]="csc",
+ ["mk"]="cosec",
["sk"]="cosec",
},
},
@@ -396,6 +432,7 @@ data.labels={
["en"]="cot",
["es"]="cot",
["hr"]="ctg",
+ ["mk"]="ctg",
["pl"]="ctg",
["sk"]="cotg",
},
@@ -405,6 +442,7 @@ data.labels={
["cz"]="deg",
["en"]="deg",
["es"]="gr",
+ ["mk"]="deg",
["sk"]="deg",
},
},
@@ -426,6 +464,7 @@ data.labels={
["cz"]="dim",
["en"]="dim",
["es"]="dim",
+ ["mk"]="dim",
["sk"]="dim",
},
},
@@ -443,6 +482,7 @@ data.labels={
["en"]="gcd",
["es"]="mcd",
["hr"]="nzd",
+ ["mk"]="НЗД",
["nl"]="ggd",
["sk"]="NSD",
},
@@ -460,6 +500,7 @@ data.labels={
["cz"]="inf",
["en"]="inf",
["es"]="inf",
+ ["mk"]="inf",
["sk"]="inf",
},
},
@@ -485,6 +526,7 @@ data.labels={
["en"]="lcm",
["es"]="MCM",
["hr"]="nzv",
+ ["mk"]="НЗС",
["nl"]="kgv",
["sk"]="NSN",
},
@@ -494,6 +536,7 @@ data.labels={
["cz"]="log",
["en"]="lg",
["es"]="log",
+ ["mk"]="lg",
["sk"]="log",
},
},
@@ -502,6 +545,7 @@ data.labels={
["cz"]="lim",
["en"]="lim",
["es"]="lím",
+ ["mk"]="lim",
["sk"]="lim",
},
},
@@ -510,6 +554,7 @@ data.labels={
["cz"]="lim\\sixperemspace inf",
["en"]="lim\\sixperemspace inf",
["es"]="lím\\sixperemspace inf",
+ ["mk"]="lim\\sixperemspace inf",
["sk"]="lim\\sixperemspace inf",
},
},
@@ -518,6 +563,7 @@ data.labels={
["cz"]="lim\\sixperemspace sup",
["en"]="lim\\sixperemspace sup",
["es"]="lím\\sixperemspace sup",
+ ["mk"]="lim\\sixperemspace sup",
["sk"]="lim\\sixperemspace sup",
},
},
@@ -526,6 +572,7 @@ data.labels={
["cz"]="ln",
["en"]="ln",
["es"]="ln",
+ ["mk"]="ln",
["sk"]="ln",
},
},
@@ -534,6 +581,7 @@ data.labels={
["cz"]="log",
["en"]="log",
["es"]="log",
+ ["mk"]="log",
["sk"]="log",
},
},
@@ -542,6 +590,7 @@ data.labels={
["cz"]="max",
["en"]="max",
["es"]="máx",
+ ["mk"]="max",
["sk"]="max",
},
},
@@ -558,6 +607,7 @@ data.labels={
["cz"]="min",
["en"]="min",
["es"]="mín",
+ ["mk"]="min",
["sk"]="min",
},
},
@@ -566,6 +616,7 @@ data.labels={
["cz"]="mod",
["en"]="mod",
["es"]="mod",
+ ["mk"]="mod",
["sk"]="mod",
},
},
@@ -582,6 +633,7 @@ data.labels={
["cz"]="sec",
["en"]="sec",
["es"]="sec",
+ ["mk"]="sec",
["sk"]="sec",
},
},
@@ -590,6 +642,7 @@ data.labels={
["cz"]="sin",
["en"]="sin",
["es"]="sen",
+ ["mk"]="sin",
["sk"]="sin",
},
},
@@ -598,6 +651,7 @@ data.labels={
["cz"]="sinh",
["en"]="sinh",
["es"]="senh",
+ ["mk"]="sinh",
["sk"]="sinh",
},
},
@@ -606,6 +660,7 @@ data.labels={
["cz"]="sup",
["en"]="sup",
["es"]="sup",
+ ["mk"]="sup",
["sk"]="sup",
},
},
@@ -615,6 +670,7 @@ data.labels={
["en"]="tan",
["es"]="tan",
["hr"]="tg",
+ ["mk"]="tg",
["pl"]="tg",
["sk"]="tg",
},
@@ -624,6 +680,7 @@ data.labels={
["cz"]="tgh",
["en"]="tanh",
["es"]="tanh",
+ ["mk"]="tgh",
["sk"]="tgh",
},
},
@@ -659,6 +716,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="",
+ ["mk"]=" и ",
["nb"]="",
["nl"]=" en ",
["nn"]="",
@@ -699,6 +757,7 @@ data.labels={
["kr"]="부록",
["la"]="",
["lt"]="",
+ ["mk"]="Додаток ",
["nb"]="Tillegg ",
["nl"]="",
["nn"]="Tillegg ",
@@ -741,6 +800,7 @@ data.labels={
["la"]="Aprilis",
["lt"]="balandžio",
["nb"]="april",
+ ["mk"]="април",
["nl"]="april",
["nn"]="april",
["pe"]="آوریل",
@@ -781,6 +841,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="apr",
+ ["mk"]="апр.",
["nb"]="april",
["nl"]="",
["nn"]="april",
@@ -816,6 +877,7 @@ data.labels={
["it"]="a pagina ",
["la"]="",
["lt"]="puslapyje ",
+ ["mk"]="на страница ",
["nb"]="på side ",
["nl"]="op pagina ",
["nn"]="på side ",
@@ -858,6 +920,7 @@ data.labels={
["kr"]="8",
["la"]="Augustus",
["lt"]="rugpjūčio",
+ ["mk"]="август",
["nb"]="august",
["nl"]="augustus",
["nn"]="august",
@@ -899,6 +962,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="aug",
+ ["mk"]="авг.",
["nb"]="aug.",
["nl"]="",
["nn"]="aug.",
@@ -938,6 +1002,7 @@ data.labels={
["kr"]={ "제", "장" },
["la"]="",
["lt"]="",
+ ["mk"]="Глава ",
["nb"]="",
["nl"]="",
["nn"]="",
@@ -973,6 +1038,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="",
+ ["mk"]=" (продолжение)",
["nb"]="",
["nl"]=" (vervolgd)",
["nn"]="",
@@ -995,6 +1061,7 @@ data.labels={
["en"]="day",
["et"]="päev",
["kr"]="일",
+ ["mk"]="ден",
["nl"]="dag",
["pe"]="روز",
},
@@ -1024,6 +1091,7 @@ data.labels={
["la"]="December",
["lt"]="gruodžio",
["nb"]="desember",
+ ["mk"]="декември",
["nl"]="december",
["nn"]="desember",
["pe"]="دسامبر",
@@ -1064,6 +1132,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="dec",
+ ["mk"]="дек.",
["nb"]="des.",
["nl"]="",
["nn"]="des.",
@@ -1104,6 +1173,7 @@ data.labels={
["kr"]="2",
["la"]="Februarius",
["lt"]="vasario",
+ ["mk"]="февруари",
["nb"]="februar",
["nl"]="februari",
["nn"]="februar",
@@ -1145,6 +1215,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="feb",
+ ["mk"]="фев.",
["nb"]="feb.",
["nl"]="",
["nn"]="feb.",
@@ -1183,6 +1254,7 @@ data.labels={
["kr"]="그림 ",
["la"]="Imago ",
["lt"]={ "", " pav." },
+ ["mk"]="Слика ",
["nb"]="Figur ",
["nl"]="Figuur ",
["nn"]="Figur ",
@@ -1204,6 +1276,7 @@ data.labels={
["labels"]={
["en"]="on a following page",
["et"]="järgmisel leheküljel",
+ ["mk"]="на следната страница",
["nl"]="op een volgende bladzijde",
["pe"]="در صفحات آینده",
},
@@ -1230,6 +1303,7 @@ data.labels={
["kr"]="금요일",
["la"]="Dies Veneris",
["lt"]="penktadienis",
+ ["mk"]="петок",
["nb"]="fredag",
["nl"]="vrijdag",
["nn"]="fredag",
@@ -1268,6 +1342,7 @@ data.labels={
["ja"]="イラスト",
["la"]="Typus ",
["lt"]="Graphic ",
+ ["mk"]="График ",
["nb"]="Bilde ",
["nl"]="Grafiek ",
["nn"]="Bilete ",
@@ -1305,6 +1380,7 @@ data.labels={
["kr"]="그러므로",
["la"]="",
["lt"]="kaip parodyta aukščiau",
+ ["mk"]="како што е прикажано погоре",
["nb"]="som vist over",
["nl"]="hierboven",
["nn"]="som vist over",
@@ -1342,6 +1418,7 @@ data.labels={
["kr"]="이후로",
["la"]="",
["lt"]="kaip parodyta žemiau",
+ ["mk"]="како што е прикажано подолу",
["nb"]="som vist under",
["nl"]="hieronder",
["nn"]="som vist under",
@@ -1381,6 +1458,7 @@ data.labels={
["kr"]="간주곡",
["la"]="Intermissum ",
["lt"]="Intermezzo ",
+ ["mk"]="Дигресија ",
["nb"]="Intermesso ",
["nl"]="Intermezzo ",
["nn"]="Intermesso ",
@@ -1421,6 +1499,7 @@ data.labels={
["kr"]="1",
["la"]="Ianuarius",
["lt"]="sausio",
+ ["mk"]="јануари",
["nb"]="januar",
["nl"]="januari",
["nn"]="januar",
@@ -1462,6 +1541,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="jan",
+ ["mk"]="jан.",
["nb"]="jan.",
["nl"]="",
["nn"]="jan.",
@@ -1503,6 +1583,7 @@ data.labels={
["kr"]="7",
["la"]="Iulius",
["lt"]="liepos",
+ ["mk"]="јули",
["nb"]="juli",
["nl"]="juli",
["nn"]="juli",
@@ -1544,6 +1625,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="jul",
+ ["mk"]="јул.",
["nb"]="juli",
["nl"]="",
["nn"]="juli",
@@ -1584,6 +1666,7 @@ data.labels={
["kr"]="6",
["la"]="Iunius",
["lt"]="birželio",
+ ["mk"]="јуни",
["nb"]="juni",
["nl"]="juni",
["nn"]="juni",
@@ -1625,6 +1708,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="jun",
+ ["mk"]="јун.",
["nb"]="juni",
["nl"]="",
["nn"]="juni",
@@ -1663,6 +1747,7 @@ data.labels={
["kr"]="행",
["la"]="versus ",
["lt"]="line ",
+ ["mk"]="линија ",
["nb"]="linje ",
["nl"]="regel ",
["nn"]="linje ",
@@ -1702,6 +1787,7 @@ data.labels={
["kr"]="행",
["la"]="versus ",
["lt"]="lines ",
+ ["mk"]="линии ",
["nb"]="linjer ",
["nl"]="regels ",
["nn"]="linjer ",
@@ -1742,6 +1828,7 @@ data.labels={
["kr"]="3",
["la"]="Martius",
["lt"]="kovo",
+ ["mk"]="март",
["nb"]="mars",
["nl"]="maart",
["nn"]="mars",
@@ -1783,6 +1870,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="mar",
+ ["mk"]="мар.",
["nb"]="mars",
["nl"]="",
["nn"]="mars",
@@ -1824,6 +1912,7 @@ data.labels={
["kr"]="5",
["la"]="Maius",
["lt"]="gegužės",
+ ["mk"]="мај",
["nb"]="mai",
["nl"]="mei",
["nn"]="mai",
@@ -1865,6 +1954,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="may",
+ ["mk"]="мај",
["nb"]="mai",
["nl"]="",
["nn"]="mai",
@@ -1903,6 +1993,7 @@ data.labels={
["kr"]="월요일",
["la"]="Dies Lunae",
["lt"]="pirmadienis",
+ ["mk"]="понеделник",
["nb"]="mandag",
["nl"]="maandag",
["nn"]="måndag",
@@ -1925,6 +2016,7 @@ data.labels={
["en"]="month",
["et"]="kuu",
["kr"]="월",
+ ["mk"]="месец",
["nl"]="maand",
["pe"]="ماه",
},
@@ -1953,6 +2045,7 @@ data.labels={
["kr"]="11",
["la"]="November",
["lt"]="lapkričio",
+ ["mk"]="ноември",
["nb"]="november",
["nl"]="november",
["nn"]="november",
@@ -1994,6 +2087,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="nov",
+ ["mk"]="ноем.",
["nb"]="nov.",
["nl"]="",
["nn"]="nov.",
@@ -2033,6 +2127,7 @@ data.labels={
["kr"]="10",
["la"]="October",
["lt"]="spalio",
+ ["mk"]="октомври",
["nb"]="oktober",
["nl"]="oktober",
["nn"]="oktober",
@@ -2074,6 +2169,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="oct",
+ ["mk"]="окт.",
["nb"]="okt.",
["nl"]="",
["nn"]="okt.",
@@ -2110,6 +2206,7 @@ data.labels={
["kr"]="쪽",
["la"]="",
["lt"]="puslapis ",
+ ["mk"]="страница ",
["nb"]="side ",
["nl"]="pagina ",
["nn"]="side ",
@@ -2149,7 +2246,8 @@ data.labels={
["kr"]={ "제", "부" },
["la"]="Pars ",
["lt"]={ "", " dalis" },
- ["nb"]="Del",
+ ["mk"]="Дел ",
+ ["nb"]="Del ",
["nl"]="Deel ",
["nn"]="Del",
["pe"]="قسمت ",
@@ -2170,6 +2268,7 @@ data.labels={
["labels"]={
["en"]="on a preceding page",
["et"]="eelmisel lehel",
+ ["mk"]="на претходната страница",
["nl"]="op een voorgaande bladzijde",
["pe"]="در صفحات گذشته",
},
@@ -2196,6 +2295,7 @@ data.labels={
["kr"]="토요일",
["la"]="Dies Saturni",
["lt"]="šeštadienis",
+ ["mk"]="сабота",
["nb"]="lørdag",
["nl"]="zaterdag",
["nn"]="laurdag",
@@ -2237,6 +2337,7 @@ data.labels={
["la"]="",
["lt"]="",
["nb"]="",
+ ["mk"]="Поглавје ",
["nl"]="",
["nn"]="",
["pe"]="بخش ",
@@ -2273,6 +2374,7 @@ data.labels={
["kr"]="",
["la"]="",
["lt"]="žiūrėti ",
+ ["mk"]="види ",
["nb"]="se ",
["nl"]="zie ",
["nn"]="sjå ",
@@ -2314,6 +2416,7 @@ data.labels={
["kr"]="9",
["la"]="September",
["lt"]="rugsėjo",
+ ["mk"]="септември",
["nb"]="september",
["nl"]="september",
["nn"]="september",
@@ -2355,6 +2458,7 @@ data.labels={
["it"]="",
["la"]="",
["lt"]="sep",
+ ["mk"]="септ.",
["nb"]="sep.",
["nl"]="",
["nn"]="sep.",
@@ -2393,6 +2497,7 @@ data.labels={
["ja"]="",
["la"]="",
["lt"]="",
+ ["mk"]="Подпоглавје ",
["nb"]="",
["nl"]="",
["nn"]="",
@@ -2432,6 +2537,7 @@ data.labels={
["ja"]="",
["la"]="",
["lt"]="",
+ ["mk"]="Подподпоглавје ",
["nb"]="",
["nl"]="",
["nn"]="",
@@ -2471,6 +2577,7 @@ data.labels={
["ja"]="",
["la"]="",
["lt"]="",
+ ["mk"]="Подподподпоглавје ",
["nb"]="",
["nl"]="",
["nn"]="",
@@ -2510,6 +2617,7 @@ data.labels={
["kr"]="일요일",
["la"]="Dies Solis",
["lt"]="sekmadienis",
+ ["mk"]="недела",
["nb"]="søndag",
["nl"]="zondag",
["nn"]="sundag",
@@ -2549,6 +2657,7 @@ data.labels={
["kr"]="표 ",
["la"]="Tabula ",
["lt"]={ "", " lentelė." },
+ ["mk"]="Табела ",
["nb"]="Tabell ",
["nl"]="Tabel ",
["nn"]="Tabell ",
@@ -2588,6 +2697,7 @@ data.labels={
["kr"]="목요일",
["la"]="Dies Iovis",
["lt"]="ketvirtadienis",
+ ["mk"]="четврток",
["nb"]="torsdag",
["nl"]="donderdag",
["nn"]="torsdag",
@@ -2627,6 +2737,7 @@ data.labels={
["kr"]="화요일",
["la"]="Dies Martis",
["lt"]="antradienis",
+ ["mk"]="вторник",
["nb"]="tirsdag",
["nl"]="dinsdag",
["nn"]="tysdag",
@@ -2666,6 +2777,7 @@ data.labels={
["kr"]="수요일",
["la"]="Dies Mercuri",
["lt"]="trečiadienis",
+ ["mk"]="среда",
["nb"]="onsdag",
["nl"]="woensdag",
["nn"]="onsdag",
@@ -2688,6 +2800,7 @@ data.labels={
["en"]="year",
["et"]="aasta",
["kr"]="년",
+ ["mk"]="година",
["nl"]="jaar",
["pe"]="سال",
},
@@ -2716,6 +2829,7 @@ data.labels={
["kr"]="약어",
["la"]="Notae",
["lt"]="Santrumpos",
+ ["mk"]="Скратеници",
["nb"]="Forkortelser",
["nl"]="Afkortingen",
["nn"]="Forkortingar",
@@ -2755,6 +2869,7 @@ data.labels={
["kr"]="목차",
["la"]="Quod in libro continetur",
["lt"]="Turinys",
+ ["mk"]="Содржина",
["nb"]="Innhold",
["nl"]="Inhoud",
["nn"]="Innhald",
@@ -2794,6 +2909,7 @@ data.labels={
["kr"]="그림 ",
["la"]="Imagines",
["lt"]="Iliustracijos",
+ ["mk"]="Листа на слики",
["nb"]="Figurer",
["nl"]="Figuren",
["nn"]="Figurar",
@@ -2833,6 +2949,7 @@ data.labels={
["kr"]="그래픽 ",
["la"]="Typi",
["lt"]="Graphics",
+ ["mk"]="Листа на графици",
["nb"]="Bilde",
["nl"]="Grafieken",
["nn"]="Bilete",
@@ -2872,6 +2989,7 @@ data.labels={
["kr"]="찾아보기",
["la"]="Indices",
["lt"]="Rodyklė",
+ ["mk"]="Индекс",
["nb"]="Register",
["nl"]="Index",
["nn"]="Register",
@@ -2911,6 +3029,7 @@ data.labels={
["kr"]="간주곡",
["la"]="Intermissa",
["lt"]="Intermezzos",
+ ["mk"]="Листа на дигресии",
["nb"]="Intermesso",
["nl"]="Intermezzo's",
["nn"]="Intermesso",
@@ -2949,6 +3068,7 @@ data.labels={
["kr"]="이성",
["la"]="Typi negotiales",
["lt"]="Logos",
+ ["mk"]="Логоа",
["nb"]="Logoer",
["nl"]="Logo's",
["nn"]="Logoar",
@@ -2985,6 +3105,7 @@ data.labels={
["kr"]="참고문헌",
["la"]="",
["lt"]="Literatūra",
+ ["mk"]="Литература",
["nb"]="",
["nl"]="Literatuur",
["nn"]="",
@@ -3024,6 +3145,7 @@ data.labels={
["kr"]="표 ",
["la"]="Tabulae",
["lt"]="Lentelės",
+ ["mk"]="Листа на табели",
["nb"]="Tabeller",
["nl"]="Tabellen",
["nn"]="Tabellar",
@@ -3063,6 +3185,7 @@ data.labels={
["kr"]="측정단위",
["la"]="Modi",
["lt"]="Units",
+ ["mk"]="Единици",
["nb"]="Enheter",
["nl"]="Eenheden",
["nn"]="Einingar",
diff --git a/tex/context/base/mkiv/lpdf-ano.lua b/tex/context/base/mkiv/lpdf-ano.lua
index 05f18f512..1c4a3ba27 100644
--- a/tex/context/base/mkiv/lpdf-ano.lua
+++ b/tex/context/base/mkiv/lpdf-ano.lua
@@ -133,6 +133,99 @@ local function checkautoprefixes(destinations)
end
end
+local maxslice = 32 -- could be made configureable ... 64 is also ok
+
+local function pdfmakenametree(list,apply)
+ if not next(list) then
+ return
+ end
+ local slices = { }
+ local sorted = sortedkeys(list)
+ local size = #sorted
+ local maxslice = maxslice
+ if size <= 1.5*maxslice then
+ maxslice = size
+ end
+ for i=1,size,maxslice do
+ local amount = min(i+maxslice-1,size)
+ local names = pdfarray { }
+ local n = 0
+ for j=i,amount do
+ local name = sorted[j]
+ local target = list[name]
+ n = n + 1 ; names[n] = tostring(name)
+ n = n + 1 ; names[n] = apply and apply(target) or target
+ end
+ local first = sorted[i]
+ local last = sorted[amount]
+ local limits = pdfarray {
+ first,
+ last,
+ }
+ local d = pdfdictionary {
+ Names = names,
+ Limits = limits,
+ }
+ slices[#slices+1] = {
+ reference = pdfreference(pdfflushobject(d)),
+ limits = limits,
+ }
+ end
+ local function collectkids(slices,first,last)
+ local f = slices[first]
+ local l = slices[last]
+ if f and l then
+ local k = pdfarray()
+ local n = 0
+ local d = pdfdictionary {
+ Kids = k,
+ Limits = pdfarray {
+ f.limits[1],
+ l.limits[2],
+ },
+ }
+ for i=first,last do
+ n = n + 1 ; k[n] = slices[i].reference
+ end
+ return d
+ end
+ end
+ if #slices == 1 then
+ return slices[1].reference
+ else
+ while true do
+ local size = #slices
+ if size > maxslice then
+ local temp = { }
+ local n = 0
+ for i=1,size,maxslice do
+ local kids = collectkids(slices,i,min(i+maxslice-1,size))
+ if kids then
+ n = n + 1
+ temp[n] = {
+ reference = pdfreference(pdfflushobject(kids)),
+ limits = kids.Limits,
+ }
+ else
+ -- error
+ end
+ end
+ slices = temp
+ else
+ local kids = collectkids(slices,1,size)
+ if kids then
+ return pdfreference(pdfflushobject(kids))
+ else
+ -- error
+ return
+ end
+ end
+ end
+ end
+end
+
+lpdf.makenametree = pdfmakenametree
+
-- Bah, I hate this kind of features .. anyway, as we have delayed resolving we
-- only support a document-wide setup and it has to be set before the first one
-- is used. Also, we default to a non-intrusive gray and the outline is kept
@@ -237,8 +330,6 @@ end
lpdf.registerdestination = pdfregisterdestination
-local maxslice = 32 -- could be made configureable ... 64 is also ok
-
logs.registerfinalactions(function()
if log_destinations and next(destinations) then
local report = logs.startfilelogging("references","used destinations")
@@ -252,98 +343,10 @@ logs.registerfinalactions(function()
end
end)
-local function pdfnametree(destinations)
- local slices = { }
- checkautoprefixes(destinations)
- if not next(destinations) then
- return
- end
- local sorted = sortedkeys(destinations)
- local size = #sorted
-
- if size <= 1.5*maxslice then
- maxslice = size
- end
-
- for i=1,size,maxslice do
- local amount = min(i+maxslice-1,size)
- local names = pdfarray { }
- local n = 0
- for j=i,amount do
- local destination = sorted[j]
- local pagenumber = destinations[destination]
- n = n + 1 ; names[n] = tostring(destination) -- tostring is a safeguard
- n = n + 1 ; names[n] = pdfreference(pagenumber)
- end
- local first = sorted[i]
- local last = sorted[amount]
- local limits = pdfarray {
- first,
- last,
- }
- local d = pdfdictionary {
- Names = names,
- Limits = limits,
- }
- slices[#slices+1] = {
- reference = pdfreference(pdfflushobject(d)),
- limits = limits,
- }
- end
- local function collectkids(slices,first,last)
- local f = slices[first]
- local l = slices[last]
- if f and l then
- local k = pdfarray()
- local n = 0
- local d = pdfdictionary {
- Kids = k,
- Limits = pdfarray {
- f.limits[1],
- l.limits[2],
- },
- }
- for i=first,last do
- n = n + 1 ; k[n] = slices[i].reference
- end
- return d
- end
- end
- if #slices == 1 then
- return slices[1].reference
- else
- while true do
- if #slices > maxslice then
- local temp = { }
- local size = #slices
- for i=1,size,maxslice do
- local kids = collectkids(slices,i,min(i+maxslice-1,size))
- if kids then
- temp[#temp+1] = {
- reference = pdfreference(pdfflushobject(kids)),
- limits = kids.Limits,
- }
- else
- -- error
- end
- end
- slices = temp
- else
- local kids = collectkids(slices,1,#slices)
- if kids then
- return pdfreference(pdfflushobject(kids))
- else
- -- error
- return
- end
- end
- end
- end
-end
-
local function pdfdestinationspecification()
if next(destinations) then -- safeguard
- local r = pdfnametree(destinations)
+ checkautoprefixes(destinations)
+ local r = pdfmakenametree(destinations,pdfreference)
if r then
pdfaddtonames("Dests",r)
end
@@ -353,7 +356,6 @@ local function pdfdestinationspecification()
end
end
-lpdf.nametree = pdfnametree
lpdf.destinationspecification = pdfdestinationspecification
lpdf.registerdocumentfinalizer(pdfdestinationspecification,"collect destinations")
diff --git a/tex/context/base/mkiv/lpdf-img.lua b/tex/context/base/mkiv/lpdf-img.lua
index 4e54989cd..97b596937 100644
--- a/tex/context/base/mkiv/lpdf-img.lua
+++ b/tex/context/base/mkiv/lpdf-img.lua
@@ -65,6 +65,18 @@ trackers.register("graphics.backend", function(v) trace = v end)
local injectors = { }
lpdf.injectors = injectors
+-- todo: load from a virtual file
+
+local function loadcontent(filename,method)
+ return method == "string" and filename or loaddata(filename)
+end
+
+local function newcontent(filename,method)
+ return newreader(filename,method)
+end
+
+--
+
local chars = setmetatableindex(function(t,k) -- share this one
local v = (k <= 0 and "\000") or (k >= 255 and "\255") or char(k)
t[k] = v
@@ -73,7 +85,7 @@ end)
do
- function injectors.jpg(specification)
+ function injectors.jpg(specification,method)
if specification.error then
return
end
@@ -96,7 +108,7 @@ do
local xsize = specification.xsize
local ysize = specification.ysize
local colordepth = specification.colordepth
- local content = loaddata(filename)
+ local content = loadcontent(filename,method)
local xobject = pdfdictionary {
Type = pdfconstant("XObject"),
Subtype = pdfconstant("Image"),
@@ -127,7 +139,7 @@ end
do
- function injectors.jp2(specification)
+ function injectors.jp2(specification,method)
if specification.error then
return
end
@@ -138,7 +150,7 @@ do
-- todo: set filename
local xsize = specification.xsize
local ysize = specification.ysize
- local content = loaddata(filename)
+ local content = loadcontent(filename,method)
local xobject = pdfdictionary {
Type = pdfconstant("XObject"),
Subtype = pdfconstant("Image"),
@@ -936,7 +948,7 @@ do
if not idat then
return
end
- local pngfile = newreader(filename,method)
+ local pngfile = newcontent(filename,method)
if not pngfile then
return
end
@@ -1074,7 +1086,7 @@ do
else
pallette = false
end
- elseif decode then
+ elseif decode or (enforcecmyk and not palette) then
-- this one needs checking
local bytes = analyze(colordepth,colorspace)
if bytes then
@@ -1091,6 +1103,7 @@ do
else
return
end
+ decode = true -- due to enforcecmyk
else
-- print("PASS ON")
end
diff --git a/tex/context/base/mkiv/lpdf-ini.lua b/tex/context/base/mkiv/lpdf-ini.lua
index fd1e52aad..b039daa58 100644
--- a/tex/context/base/mkiv/lpdf-ini.lua
+++ b/tex/context/base/mkiv/lpdf-ini.lua
@@ -1502,12 +1502,12 @@ end
do
- local f_actual_text_p = formatters["BT /Span << /ActualText <feff%s> >> BDC %s EMC ET"]
- local f_actual_text_b = formatters["BT /Span << /ActualText <feff%s> >> BDC"]
- local s_actual_text_e = "EMC ET"
- local f_actual_text_b_not = formatters["/Span << /ActualText <feff%s> >> BDC"]
- local s_actual_text_e_not = "EMC"
- local f_actual_text = formatters["/Span <</ActualText %s >> BDC"]
+ local f_actual_text_p = formatters["BT /Span << /ActualText <feff%s> >> BDC %s EMC ET"]
+ local f_actual_text_b = formatters["BT /Span << /ActualText <feff%s> >> BDC"]
+ local s_actual_text_e = "EMC ET"
+ local f_actual_text_b_not = formatters["/Span << /ActualText <feff%s> >> BDC"]
+ local s_actual_text_e_not = "EMC"
+ local f_actual_text = formatters["/Span <</ActualText %s >> BDC"]
local context = context
local pdfdirect = nodes.pool.directliteral -- we can use nuts.write deep down
@@ -1689,5 +1689,3 @@ end
if environment.arguments.nocompression then
lpdf.setcompression(0,0,true)
end
-
-
diff --git a/tex/context/base/mkiv/lpdf-lmt.lua b/tex/context/base/mkiv/lpdf-lmt.lua
index b46274b34..4cce7fc74 100644
--- a/tex/context/base/mkiv/lpdf-lmt.lua
+++ b/tex/context/base/mkiv/lpdf-lmt.lua
@@ -79,8 +79,6 @@ local properties = fonthashes.properties
local report = logs.reporter("backend")
-local trace_threshold = false trackers.register("backends.pdf.threshold", function(v) trace_threshold = v end)
-
-- used variables
local pdf_h, pdf_v
@@ -89,7 +87,7 @@ local need_width, need_mode, done_width, done_mode
local mode
local f_pdf_cur, f_pdf, fs_cur, fs, f_cur
local tj_delta, cw
-local usedfonts, usedxforms, usedximages
+local usedfonts, usedxforms, usedximages, usedxgroups
local getxformname, getximagename
local boundingbox, shippingmode, objectnumber
local tmrx, tmry, tmsx, tmsy, tmtx, tmty
@@ -132,6 +130,7 @@ local function reset_variables(specification)
usedfonts = setmetatableindex(usefont)
usedxforms = { }
usedximages = { }
+ -- usedxgroups = { }
boundingbox = specification.boundingbox
end
@@ -521,6 +520,8 @@ local flushcharacter do
return v
end)
+ local trace_threshold = false trackers.register("backends.pdf.threshold", function(v) trace_threshold = v end)
+
flushcharacter = function(current,pos_h,pos_v,pos_r,font,char,data,naturalwidth,factor,width,f,e)
if need_tf or font ~= f_cur or f_pdf ~= f_pdf_cur or fs ~= fs_cur or mode == "page" then
pdf_goto_textmode()
@@ -842,6 +843,11 @@ end
-- rules
+local f_font = formatters["F%d"]
+local f_form = formatters["Fm%d"]
+local f_group = formatters["Gp%d"]
+local f_image = formatters["Im%d"]
+
local flushedxforms = { } -- actually box resources but can also be direct
local localconverter = nil -- will be set
@@ -1040,6 +1046,37 @@ local flushrule, flushsimplerule, flushimage do
pdf.getximagename = getximagename
end)
+ -- Groups are flushed immediately but we can decide to make them into a
+ -- specific whatsit ... but not now. We could hash them if needed when
+ -- we use lot sof them in mp ... but not now.
+
+ usedxgroups = { }
+ local groups = 0
+ local group = nil
+
+ function lpdf.flushgroup(content,bbox)
+ if not group then
+ group = pdfdictionary {
+ Type = pdfconstant("Group"),
+ S = pdfconstant("Transparency"),
+ }
+ end
+ local wrapper = pdfdictionary {
+ Type = pdf_xobject,
+ Subtype = pdf_form,
+ FormType = 1,
+ Group = group,
+ BBox = pdfarray(bbox),
+ Resources = lpdf.collectedresources { serialize = false },
+ }
+ local objnum = pdfflushstreamobject(content,wrapper,false)
+ groups = groups + 1
+ usedxgroups[groups] = objnum
+ return f_group(groups)
+ end
+
+ -- end of experiment
+
local function flushpdfximage(current,pos_h,pos_v,pos_r,size_h,size_v)
local width,
@@ -1053,7 +1090,7 @@ local flushrule, flushsimplerule, flushimage do
yorigin,
xsize,
ysize,
- rotation,
+ rotation, -- transform / orientation / rotation : it's a mess (i need to redo this)
objnum,
groupref = pdfincludeimage(index) -- needs to be sorted out, bad name (no longer mixed anyway)
@@ -1064,6 +1101,8 @@ local flushrule, flushsimplerule, flushimage do
local rx, sx, sy, ry, tx, ty = 1, 0, 0, 1, 0, 0
+ -- tricky: xsize and ysize swapped
+
if kind == img_pdf or kind == img_stream or kind == img_memstream then
rx, ry, tx, ty = 1/xsize, 1/ysize, xorigin/xsize, yorigin/ysize
else
@@ -1364,15 +1403,70 @@ local function initialize(driver,details)
reset_buffer()
end
-local f_font = formatters["F%d"]
-local f_form = formatters["Fm%d"]
-local f_image = formatters["Im%d"]
-
-- This will all move and be merged and become less messy.
-- todo: more clever resource management: a bit tricky as we can inject
-- stuff in the page stream
+local compact = false
+
+do
+
+ -- This is more a convenience feature and it might even be not entirely robust.
+ -- It removes redundant color directives which makes the page stream look a bit
+ -- nicer (also when figuring out issues). I might add more here but there is
+ -- some additional overhead involved so runtime can be impacted.
+
+ local P, R, S, Cs, lpegmatch = lpeg.P, lpeg.R, lpeg.S, lpeg.Cs, lpeg.match
+
+ local p_ds = (R("09") + S(" ."))^1
+ ----- p_nl = S("\n\r")^1
+ local p_nl = S("\n")^1
+ local p_eg = P("Q")
+
+ local p_cl = p_ds * (P("rg") + P("g") + P("k")) * p_ds * (P("RG") + P("G") + P("K"))
+ ----- p_cl = (p_ds * (P("rg") + P("g") + P("k") + P("RG") + P("G") + P("K")))^1
+ local p_tr = P("/Tr") * p_ds * P("gs")
+
+ local p_no_cl = (p_cl * p_nl) / ""
+ local p_no_tr = (p_tr * p_nl) / ""
+ local p_no_nl = 1 - p_nl
+
+ local p_do_cl = p_cl * p_nl
+ local p_do_tr = p_tr * p_nl
+
+ local p_do_eg = p_eg * p_nl
+
+ local pattern = Cs( (
+ (p_no_cl + p_no_tr)^0 * p_do_eg -- transparencies and colors before Q
+ + p_no_tr * p_no_cl * p_do_tr * p_do_cl -- transparencies and colors before others
+ + p_no_cl * p_do_cl -- successive colors
+ + p_no_tr * p_do_tr -- successive transparencies
+ + p_no_nl^1
+ + 1
+ )^1 )
+
+ local oldsize = 0
+ local newsize = 0
+
+ directives.register("pdf.compact", function(v)
+ compact = v and function(s)
+ oldsize = oldsize + #s
+ s = lpegmatch(pattern,s) or s
+ newsize = newsize + #s
+ return s
+ end
+ end)
+
+ statistics.register("pdf pagestream",function()
+ if oldsize ~= newsize then
+ return string.format("old size: %i, new size %i",oldsize,newsize)
+ end
+ end)
+
+
+end
+
local pushmode, popmode
local function finalize(driver,details)
@@ -1386,6 +1480,10 @@ local function finalize(driver,details)
local content = concat(buffer,"\n",1,b)
+ if compact then
+ content = compact(content)
+ end
+
local fonts = nil
local xforms = nil
@@ -1399,7 +1497,7 @@ local function finalize(driver,details)
-- messy: use real indexes for both ... so we need to change some in the
-- full luatex part
- if next(usedxforms) or next(usedximages) then
+ if next(usedxforms) or next(usedximages) or next(usedxgroups) then
xforms = pdfdictionary { }
for k in sortedhash(usedxforms) do
-- xforms[f_form(k)] = pdfreference(k)
@@ -1408,6 +1506,9 @@ local function finalize(driver,details)
for k, v in sortedhash(usedximages) do
xforms[f_image(k)] = pdfreference(v)
end
+ for k, v in sortedhash(usedxgroups) do
+ xforms[f_group(k)] = pdfreference(v)
+ end
end
reset_buffer()
@@ -1951,9 +2052,15 @@ end)
local openfile, closefile do
- local f_used = formatters["%010i 00000 n \010"]
- local f_link = formatters["%010i 00000 f \010"]
- local f_first = formatters["%010i 65535 f \010"]
+ -- I used to do <space><lf> but then figured out that when I open and save a file in a mode
+ -- that removes trailing spaces, the xref becomes invalid. The problem was then that a
+ -- reconstruction of the file by a viewer gives weird effects probably because percent symbols
+ -- gets interpreted then. Thanks to Ross Moore for noticing this side effect!
+
+ local f_used = formatters["%010i 00000 n\013\010"]
+ local f_link = formatters["%010i 00000 f\013\010"]
+ local f_first = formatters["%010i 65535 f\013\010"]
+
local f_pdf = formatters["%%PDF-%i.%i\010"]
local f_xref = formatters["xref\0100 %i\010"]
local f_trailer_id = formatters["trailer\010<< %s /ID [ <%s> <%s> ] >>\010startxref\010%i\010%%%%EOF"]
@@ -2006,7 +2113,23 @@ local openfile, closefile do
end
closefile = function(abort)
- if not abort then
+ if abort then
+ f:close()
+ f = io.open(abort,"wb")
+ if f then
+ local name = resolvers.findfile("context-lmtx-error.pdf")
+ if name then
+ local data = io.loaddata(name)
+ if data then
+ f:write(data)
+ f:close()
+ return
+ end
+ end
+ f:close()
+ removefile(abort)
+ end
+ else
local xrefoffset = offset
local lastfree = 0
local noffree = 0
@@ -2188,9 +2311,10 @@ local openfile, closefile do
flush(f,f_trailer_no(trailer(),xrefoffset))
end
end
+ f:close()
end
- f:close()
io.flush()
+ closefile = function() end
end
end
@@ -2239,8 +2363,8 @@ updaters.register("backend.update.pdf",function()
specification.index = index
local xobject = pdfdictionary { }
if not specification.notype then
- xobject.Type = pdfconstant("XObject")
- xobject.Subtype = pdfconstant("Form")
+ xobject.Type = pdf_xobject
+ xobject.Subtype = pdf_form
xobject.FormType = 1
end
local bbox = specification.bbox
@@ -2322,8 +2446,8 @@ updaters.register("backend.update.pdf",function()
local bbox = specification.bbox
local xorigin = bbox[1]
local yorigin = bbox[2]
- local xsize = specification.width -- should equal to: bbox[3] - xorigin
- local ysize = specification.height -- should equal to: bbox[4] - yorigin
+ local xsize = bbox[3] - xorigin -- we need the original ones, not the 'rotated' ones
+ local ysize = bbox[4] - yorigin -- we need the original ones, not the 'rotated' ones
local transform = specification.transform or 0
local objnum = specification.objnum or pdfreserveobj()
local groupref = nil
@@ -2448,7 +2572,6 @@ do
local texgetbox = tex.getbox
local pdfname = nil
- local tmpname = nil
local converter = nil
local useddriver = nil -- a bit of a hack
@@ -2474,13 +2597,7 @@ do
-- end
--
pdfname = file.addsuffix(tex.jobname,"pdf")
- tmpname = "l_m_t_x_" .. pdfname
- removefile(tmpname)
- if isfile(tmpname) then
- report("file %a can't be opened, aborting",tmpname)
- os.exit()
- end
- openfile(tmpname)
+ openfile(pdfname)
--
luatex.registerstopactions(1,function()
if pdfname then
@@ -2507,35 +2624,15 @@ do
local function wrapup(driver)
if pdfname then
- local ok = true
- if isfile(pdfname) then
- removefile(pdfname)
- end
- if isfile(pdfname) then
- ok = false
- file.copy(tmpname,pdfname)
- else
- renamefile(tmpname,pdfname)
- if isfile(tmpname) then
- ok = false
- end
- end
- if not ok then
- print(formatters["\nerror in renaming %a to %a\n"](tmpname,pdfname))
- end
+ closefile()
pdfname = nil
- tmpname = nil
end
end
local function cleanup(driver)
- if tmpname then
- closefile(true)
- if isfile(tmpname) then
- removefile(tmpname)
- end
+ if pdfname then
+ closefile(pdfname)
pdfname = nil
- tmpname = nil
end
end
diff --git a/tex/context/base/mkiv/lpdf-pde.lua b/tex/context/base/mkiv/lpdf-pde.lua
index b159df24f..2a8cfeede 100644
--- a/tex/context/base/mkiv/lpdf-pde.lua
+++ b/tex/context/base/mkiv/lpdf-pde.lua
@@ -1035,7 +1035,7 @@ if images then do
local root = pdfdoc.Catalog
local page = pdfdoc.pages[pagenumber]
if page then
- local sizetag = sizes[size or "crop"] or sizes.cro
+ local sizetag = sizes[size or "crop"] or sizes.crop
local mediabox = page.MediaBox or { 0, 0, 0, 0 }
local cropbox = page[sizetag] or mediabox
return {
diff --git a/tex/context/base/mkiv/lpdf-tag.lua b/tex/context/base/mkiv/lpdf-tag.lua
index 0a2fe679e..d99e09243 100644
--- a/tex/context/base/mkiv/lpdf-tag.lua
+++ b/tex/context/base/mkiv/lpdf-tag.lua
@@ -6,11 +6,11 @@ if not modules then modules = { } end modules ['lpdf-tag'] = {
license = "see context related readme files"
}
-local next = next
-local format, match, concat = string.format, string.match, table.concat
+local next, type = next, type
+local format, match, gmatch = string.format, string.match, string.gmatch
+local concat, sortedhash = table.concat, table.sortedhash
local lpegmatch, P, S, C = lpeg.match, lpeg.P, lpeg.S, lpeg.C
local settings_to_hash = utilities.parsers.settings_to_hash
-local sortedhash = table.sortedhash
local formatters = string.formatters
local trace_tags = false trackers.register("structures.tags", function(v) trace_tags = v end)
@@ -36,6 +36,7 @@ local pdfunicode = lpdf.unicode
local pdfflushobject = lpdf.flushobject
local pdfreserveobject = lpdf.reserveobject
local pdfpagereference = lpdf.pagereference
+local pdfmakenametree = lpdf.makenametree
local addtocatalog = lpdf.addtocatalog
local addtopageattributes = lpdf.addtopageattributes
@@ -62,6 +63,7 @@ local getattr = nuts.getattr
local getprev = nuts.getprev
local getnext = nuts.getnext
local getlist = nuts.getlist
+local getchar = nuts.getchar
local setlink = nuts.setlink
local setlist = nuts.setlist
@@ -75,7 +77,7 @@ local structure_kids -- delayed
local structure_ref -- delayed
local parent_ref -- delayed
local root -- delayed
-local names -- delayed
+local names = { }
local tree = { }
local elements = { }
@@ -90,29 +92,49 @@ local usedmapping = { }
----- tagsplitter = structurestags.patterns.splitter
--- local embeddedtags = false -- true will id all, for tracing
--- local f_tagid = formatters["%s-%04i"]
--- local embeddedfilelist = pdfarray() -- /AF crap
---
--- directives.register("structures.tags.embedmath",function(v)
--- if not v then
--- -- only enable
--- elseif embeddedtags == true then
--- -- already all tagged
--- elseif embeddedtags then
--- embeddedtags.math = true
--- else
--- embeddedtags = { math = true }
--- end
--- end)
+local embeddedtags = false -- true will id all, for tracing, otherwise table
+local f_tagid = formatters["%s-%04i"]
+local embeddedfilelist = pdfarray() -- /AF crap
--- function codeinjections.maptag(original,target,kind)
--- mapping[original] = { target, kind or "inline" }
--- end
+-- for testing, not that it was ever used:
+
+directives.register("structures.tags.embed",function(v)
+ if type(v) == "string" then
+ if type(embeddedtags) ~= "table" then
+ embeddedtags = { }
+ end
+ for s in gmatch(v,"([^, ]+)") do
+ embeddedtags[s] = true
+ end
+ elseif v and not embeddedtags then
+ embeddedtags = true
+ end
+end)
+
+-- for old times sake, not that it was ever used:
+
+directives.register("structures.tags.embedmath",function(v)
+ if not v then
+ -- only enable
+ elseif embeddedtags == true then
+ -- already all tagged
+ elseif embeddedtags then
+ embeddedtags.math = true
+ else
+ embeddedtags = { math = true }
+ end
+end)
+
+function codeinjections.maptag(original,target,kind)
+ mapping[original] = { target, kind or "inline" }
+end
+
+-- mostly the same as the annotations tree
local function finishstructure()
if root and #structure_kids > 0 then
- local nums, n = pdfarray(), 0
+ local nums = pdfarray()
+ local n = 0
for i=1,#tree do
n = n + 1 ; nums[n] = i - 1
n = n + 1 ; nums[n] = pdfreference(pdfflushobject(tree[i]))
@@ -120,17 +142,7 @@ local function finishstructure()
local parenttree = pdfdictionary {
Nums = nums
}
- -- we need to split names into smaller parts (e.g. alphabetic or so)
- -- we already have code for that somewhere
- if #names > 0 then
- local kids = pdfdictionary {
- Limits = pdfarray { names[1], names[#names-1] },
- Names = names,
- }
- local idtree = pdfdictionary {
- Kids = pdfarray { pdfreference(pdfflushobject(kids)) },
- }
- end
+ local idtree = pdfmakenametree(names)
--
local rolemap = pdfdictionary()
for k, v in next, usedmapping do
@@ -142,7 +154,7 @@ local function finishstructure()
Type = pdfconstant("StructTreeRoot"),
K = pdfreference(pdfflushobject(structure_kids)),
ParentTree = pdfreference(pdfflushobject(parent_ref,parenttree)),
- IDTree = #names > 0 and pdfreference(pdfflushobject(idtree)) or nil,
+ IDTree = idtree,
RoleMap = rolemap, -- sorted ?
}
pdfflushobject(structure_ref,structuretree)
@@ -191,6 +203,9 @@ end
local pdf_userproperties = pdfconstant("UserProperties")
+-- /O /Table
+-- /Headers [ ]
+
local function makeattribute(t)
if t and next(t) then
local properties = pdfarray()
@@ -209,40 +224,65 @@ end
local function makeelement(fulltag,parent)
local specification = specifications[fulltag]
- local tag = specification.tagname
- if tag == "ignore" then
+ local tagname = specification.tagname
+ local tagnameused = tagname
+ local attributes = nil
+ if tagname == "ignore" then
return false
- elseif tag == "mstackertop" or tag == "mstackerbot" or tag == "mstackermid"then
+ elseif tagname == "mstackertop" or tagname == "mstackerbot" or tagname == "mstackermid"then
-- TODO
return true
+ elseif tagname == "tabulatecell" then
+ local d = structurestags.gettabulatecell(fulltag)
+ if d and d.kind == 1 then
+ tagnameused = "tabulateheadcell"
+ end
+ elseif tagname == "tablecell" then
+ -- will become a plugin model
+ local d = structurestags.gettablecell(fulltag)
+ if d then
+ if d.kind == 1 then
+ tagnameused = "tableheadcell"
+ end
+ local rows = d.rows or 1
+ local cols = d.columns or 1
+ if rows > 1 or cols > 1 then
+ attributes = pdfdictionary {
+ O = pdfconstant("Table"),
+ RowSpan = rows > 1 and rows or nil,
+ ColSpan = cols > 1 and cols or nil,
+ }
+ end
+
+ end
end
--
local detail = specification.detail
local userdata = specification.userdata
--
- usedmapping[tag] = true
+ usedmapping[tagname] = true
--
-- specification.attribute is unique
--
local id = nil
- -- local af = nil
- -- if embeddedtags then
- -- local tagname = specification.tagname
- -- local tagindex = specification.tagindex
- -- if embeddedtags == true or embeddedtags[tagname] then
- -- id = f_tagid(tagname,tagindex)
- -- af = job.fileobjreferences.collected[id]
- -- if af then
- -- local r = pdfreference(af)
- -- af = pdfarray { r }
- -- -- embeddedfilelist[#embeddedfilelist+1] = r
- -- end
- -- end
- -- end
+ local af = nil
+ if embeddedtags then
+ local tagindex = specification.tagindex
+ if embeddedtags == true or embeddedtags[tagname] then
+ id = f_tagid(tagname,tagindex)
+ af = job.fileobjreferences.collected[id]
+ if af then
+ local r = pdfreference(af)
+ af = pdfarray { r }
+ -- embeddedfilelist[#embeddedfilelist+1] = r
+ end
+ end
+ end
--
local k = pdfarray()
local r = pdfreserveobject()
- local t = usedlabels[tag] or tag
+ local t = usedlabels[tagnameused] or tagnameused
+ -- local a = nil
local d = pdfdictionary {
Type = pdf_struct_element,
S = pdfconstant(t),
@@ -251,16 +291,15 @@ local function makeelement(fulltag,parent)
P = parent.pref,
Pg = pageref,
K = pdfreference(r),
- A = a and makeattribute(a) or nil,
+ -- A = a and makeattribute(a) or nil,
+ A = attributes,
-- Alt = " Who cares ",
-- ActualText = " Hi Hans ",
AF = af,
}
local s = pdfreference(pdfflushobject(d))
if id and names then
- local size = #names
- names[size+1] = id
- names[size+2] = s
+ names[id] = s
end
local kids = parent.kids
kids[#kids+1] = s
@@ -336,11 +375,11 @@ function nodeinjections.addtags(head)
root = { pref = pdfreference(structure_ref), kids = structure_kids }
names = pdfarray()
end
-
local function collectranges(head,list)
for n, id in nextnode, head do
if id == glyph_code then
-- maybe also disc
+if getchar(n) ~= 0 then
local at = getattr(n,a_tagged) or false -- false: pagebody or so, so artifact
-- if not at then
-- range = nil
@@ -352,6 +391,7 @@ function nodeinjections.addtags(head)
elseif range then
range[4] = n -- stop
end
+end
elseif id == hlist_code or id == vlist_code then
local at = getattr(n,a_image)
if at then
diff --git a/tex/context/base/mkiv/lxml-css.lua b/tex/context/base/mkiv/lxml-css.lua
index 8f7f19e84..96dc626f7 100644
--- a/tex/context/base/mkiv/lxml-css.lua
+++ b/tex/context/base/mkiv/lxml-css.lua
@@ -146,52 +146,116 @@ if context then
end
-local p_digit = lpeg.patterns.digit
-
-local pattern = Cf( Ct("") * (
- Cg(
- Cc("style") * (
- C("italic")
- + C("oblique")
- + C("slanted") / "oblique"
- )
- + Cc("variant") * (
- (C("smallcaps") + C("caps")) / "small-caps"
- )
- + Cc("weight") * (
- C("bold")
- )
- + Cc("family") * (
- (C("mono") + C("type")) / "monospace" -- just ignore the "space(d)"
- + (C("sansserif") + C("sans")) / "sans-serif" -- match before serif
- + C("serif")
- )
- + Cc("size") * Ct (
- (S("+-")^0 * (p_digit^0 * P(".") * p_digit^1 + p_digit^1 * P(".") + p_digit^1)) / tonumber
- * C(P("p") * S("txc") + P("e") * S("xm") + S("mc") * P("m") + P("in") + P("%"))
+
+do
+
+ local p_digit = lpegpatterns.digit
+ local p_unquoted = Cs(lpegpatterns.unquoted)
+ local p_size = (S("+-")^0 * (p_digit^0 * P(".") * p_digit^1 + p_digit^1 * P(".") + p_digit^1)) / tonumber
+ * C(P("p") * S("txc") + P("e") * S("xm") + S("mc") * P("m") + P("in") + P("%"))
+
+ local pattern = Cf( Ct("") * (
+ Cg(
+ Cc("style") * (
+ C("italic")
+ + C("oblique")
+ + C("slanted") / "oblique"
+ )
+ + Cc("variant") * (
+ (C("smallcaps") + C("caps")) / "small-caps"
+ )
+ + Cc("weight") * (
+ C("bold")
+ )
+ + Cc("family") * (
+ (C("mono") + C("type")) / "monospace" -- just ignore the "space(d)"
+ + (C("sansserif") + C("sans")) / "sans-serif" -- match before serif
+ + C("serif")
+ )
+ + Cc("size") * Ct(p_size)
)
- )
---+ P("\\") * (
--- P("bf") * ( Cg ( Cc("weight") * Cc("bold") ) )
--- + P("bi") * ( Cg ( Cc("weight") * Cc("bold") )
--- * Cg ( Cc("style") * Cc("italic") ) )
--- + P("bs") * ( Cg ( Cc("weight") * Cc("bold") )
--- * Cg ( Cc("style") * Cc("oblique") ) )
--- + P("it") * ( Cg ( Cc("style") * Cc("italic") ) )
--- + P("sl") * ( Cg ( Cc("style") * Cc("oblique") ) )
--- + P("sc") * ( Cg ( Cc("variant") * Cc("small-caps") ) )
--- + P("tt") * ( Cg ( Cc("family") * Cc("monospace") ) )
---)
- + P(1)
-)^0 , rawset)
-
-function css.fontspecification(str)
- return str and lpegmatch(pattern,lower(str))
-end
+ + P(1)
+ )^0 , rawset)
+
+ function css.fontspecification(str)
+ return str and lpegmatch(pattern,lower(str))
+ end
+
+ -- These map onto context!
+
+ function css.style(str)
+ if str and str ~= "" then
+ str = lower(str)
+ if str == "italic" then
+ return "italic"
+ elseif str == "slanted" or str == "oblique" then
+ return "slanted"
+ end
+ end
+ return "normal"
+ end
+
+ function css.variant(str) -- will change to a feature
+ if str and str ~= "" then
+ str = lower(str)
+ if str == "small-caps" or str == "caps" or str == "smallcaps" then
+ return "caps"
+ end
+ end
+ return "normal"
+ end
+
+ function css.weight(str)
+ if str and str ~= "" then
+ str = lower(str)
+ if str == "bold" then
+ return "bold"
+ end
+ end
+ return "normal"
+ end
+
+ function css.family(str)
+ if str and str ~= "" then
+ str = lower(str)
+ if str == "mono" or str == "type" or str == "monospace" then
+ return "mono"
+ elseif str == "sansserif" or str == "sans" then
+ return "sans"
+ elseif str == "serif" then
+ return "serif"
+ else
+ -- what if multiple ...
+ return lpegmatch(p_unquoted,str) or str
+ end
+ end
+ end
+
+ function css.size(str,factors)
+ local size, unit
+ if type(str) == "table" then
+ size, unit = str[1], str[2]
+ elseif str and str ~= "" then
+ size, unit = lpegmatch(p_size,lower(str))
+ end
+ if size and unit then
+ if factors then
+ return (factors[unit] or 1) * size
+ else
+ return size, unit
+ end
+ end
+ end
+
+ function css.colorspecification(str)
+ if str and str ~= "" then
+ local c = attributes.colors.values[tonumber(str)]
+ if c then
+ return format("rgb(%s%%,%s%%,%s%%)",c[3]*100,c[4]*100,c[5]*100)
+ end
+ end
+ end
-function css.colorspecification(str)
- local c = str and attributes.colors.values[tonumber(str)]
- return c and format("rgb(%s%%,%s%%,%s%%)",c[3]*100,c[4]*100,c[5]*100)
end
-- The following might be handy. It hooks into the normal parser as <selector>
diff --git a/tex/context/base/mkiv/math-ini.lua b/tex/context/base/mkiv/math-ini.lua
index 7a8419702..0af9a2121 100644
--- a/tex/context/base/mkiv/math-ini.lua
+++ b/tex/context/base/mkiv/math-ini.lua
@@ -319,7 +319,7 @@ function mathematics.define(family)
if mathclass then
local name = character.mathname
if name then
- report_math("fatal error, conlicting mathclass and mathspec for %C",unicode)
+ report_math("fatal error, conflicting mathclass and mathspec for %C",unicode)
os.exit()
else
local class = classes[mathclass] or mathclass -- no real checks needed
diff --git a/tex/context/base/mkiv/math-ini.mkiv b/tex/context/base/mkiv/math-ini.mkiv
index 7259fca3f..c9018ba50 100644
--- a/tex/context/base/mkiv/math-ini.mkiv
+++ b/tex/context/base/mkiv/math-ini.mkiv
@@ -129,6 +129,11 @@
\mathflattenmode 31
+\ifdefined\mathlimitsmode
+ % ignore \limits and \nolimts when no scripts (better spacing)
+ \mathlimitsmode\plusone
+\fi
+
\appendtoks
\attribute\mathmodeattribute\plusone
\to \everydisplay
diff --git a/tex/context/base/mkiv/math-stc.mkvi b/tex/context/base/mkiv/math-stc.mkvi
index 92325d0af..cc3625eb4 100644
--- a/tex/context/base/mkiv/math-stc.mkvi
+++ b/tex/context/base/mkiv/math-stc.mkvi
@@ -86,11 +86,19 @@
\def\math_stackers_regular
{\mathstylehbox{\usemathstackerscolorparameter\c!color
- \Umathaccent\fam\zerocount\scratchunicode{\hskip\scratchwidth}}}
+ \hskip\d_math_stackers_offset_l
+ \Umathaccent\fam\zerocount\scratchunicode
+ {\hskip\dimexpr\scratchwidth-\d_math_stackers_offset_l-\d_math_stackers_offset_r}%
+ \hskip\d_math_stackers_offset_r
+ }}
\def\math_stackers_stretch % we don't have that one yet
{\mathstylehbox{\usemathstackerscolorparameter\c!color
- \Umathaccent\fam\zerocount\scratchunicode{\hskip\hsize}}}
+ \hskip\d_math_stackers_offset_l
+ \Umathaccent\fam\zerocount\scratchunicode
+ {\hskip\dimexpr\hsize-\d_math_stackers_offset_l-\d_math_stackers_offset_r}%
+ \hskip\d_math_stackers_offset_r
+ }}
% these delimiters are a unuseable as they don't center for small arguments:
%
@@ -499,7 +507,7 @@
\dostoptagged
\mathstackersparameter\c!right\relax
\endgroup}
- %\math_stackers_start_group}
+ %\math_stackers_stop_group}
\unexpanded\def\definemathextensible
{\dotripleempty\math_stackers_define_normal}
@@ -572,8 +580,27 @@
\let\math_stackers_stop_group\endgroup
\fi}
-\unexpanded\def\math_stackers_make_double#top#bottom#category#codepoint#codeextra#text%
+\newconstant\c_math_stackers_top
+\newconstant\c_math_stackers_bottom
+\newconstant\c_math_stackers_codepoint
+\newconstant\c_math_stackers_extracode
+\newdimen \d_math_stackers_offset_l
+\newdimen \d_math_stackers_offset_r
+
+\setupmathstackers[lt=\zeropoint,rt=\zeropoint,lb=\zeropoint,rb=\zeropoint]
+
+\unexpanded\def\math_stackers_make_double#top#bottom#category#codepoint#codeextra%
{\math_stackers_start_group{#category}%
+ \c_math_stackers_top #top\relax
+ \c_math_stackers_bottom #bottom\relax
+ \c_math_stackers_codepoint#codepoint\relax
+ \c_math_stackers_extracode#codeextra\relax
+ \dosingleempty\math_stackers_make_double_indeed}
+
+\unexpanded\def\math_stackers_make_double_indeed[#settings]#text%
+ {\iffirstargument
+ \setupcurrentmathstackers[#settings]%
+ \fi
\mathstackersparameter\c!left\relax
\dostarttagged\t!mathstacker\currentmathstackers
\ifmmode\math_class_by_parameter\mathstackersparameter\else\dontleavehmode\fi
@@ -587,7 +614,7 @@
\scratchleftoffset \zeropoint
\scratchrightoffset\zeropoint
%
- \math_stackers_check_unicode{#codepoint}%
+ \math_stackers_check_unicode\c_math_stackers_codepoint
%
\ifx\math_stackers_middle\empty
\setbox\scratchboxthree\emptyhbox
@@ -602,24 +629,37 @@
\fi
\advance\scratchwidth2\scratchhoffset
%
+ %\scratchunicode\c_math_stackers_codepoint
+ \ifcase\c_math_stackers_bottom
+ \d_math_stackers_offset_l\mathstackersparameter{lt}%
+ \d_math_stackers_offset_r\mathstackersparameter{rt}%
+ \else\ifcase\c_math_stackers_top
+ \d_math_stackers_offset_l\mathstackersparameter{lb}%
+ \d_math_stackers_offset_r\mathstackersparameter{rb}%
+ \else
+ \d_math_stackers_offset_l\mathstackersparameter{lt}%
+ \d_math_stackers_offset_r\mathstackersparameter{rt}%
+ \fi\fi
\setbox\scratchboxtwo\csname\??mathstackersalternative\p_alternative\endcsname
\setbox\scratchboxthree\hpack to \scratchwidth{\hss\box\scratchboxthree\hss}%
%
- \scratchunicode#codeextra\relax
- \ifcase\scratchunicode\else
+ \ifcase\c_math_stackers_extracode\else
+ \scratchunicode\c_math_stackers_extracode
+ \d_math_stackers_offset_l\mathstackersparameter{lb}%
+ \d_math_stackers_offset_r\mathstackersparameter{rb}%
\setbox\scratchboxone\csname\??mathstackersalternative\p_alternative\endcsname
\fi
%
\math_stackers_normalize_three
% analysis
- \ifcase#bottom\relax
- \ifcase#top\relax
+ \ifcase\c_math_stackers_bottom
+ \ifcase\c_math_stackers_top
\dosettagproperty\s!subtype\t!munderover
\else
\dosettagproperty\s!subtype\t!mover
\fi
\else
- \ifcase#top\relax
+ \ifcase\c_math_stackers_top
\dosettagproperty\s!subtype\t!munder
\else
% brrr
@@ -633,7 +673,7 @@
\math_stackers_stop_tagged
%
\ifdim\htdp\scratchboxtwo>\zeropoint
- \ifcase#bottom\else
+ \ifcase\c_math_stackers_bottom\else
\kern-\scratchwidth
% under
\math_stackers_start_tagged_bot
@@ -643,7 +683,7 @@
+\ht\scratchboxtwo
+\mathstackersparameter\c!distance % was \c!voffset
\relax
- \ifcase#top\relax
+ \ifcase\c_math_stackers_top
\box\scratchboxtwo
\else
\box\scratchboxone
@@ -651,7 +691,7 @@
\egroup
\math_stackers_stop_tagged
\fi
- \ifcase#top\else
+ \ifcase\c_math_stackers_top\else
\kern-\scratchwidth
% over
\math_stackers_start_tagged_top
@@ -665,7 +705,6 @@
\egroup
\math_stackers_stop_tagged
\fi
- %
\fi}%
\dostoptagged
\mathstackersparameter\c!right\relax
@@ -696,10 +735,6 @@
\setuevalue{#1}{\math_stackers_make_double\plusone \plusone\noexpand\currentmathstackers{\number#2}{\number#3}}%
\fi}
-\unexpanded\def\mathover {\begingroup\dosingleempty\math_stackers_handle_over }
-\unexpanded\def\mathunder {\begingroup\dosingleempty\math_stackers_handle_under }
-\unexpanded\def\mathdouble{\begingroup\dodoubleempty\math_stackers_handle_double}
-
\unexpanded\def\definemathover {\dotripleargument \math_stackers_define_over }
\unexpanded\def\definemathunder {\dotripleargument \math_stackers_define_under }
\unexpanded\def\definemathdouble{\doquadrupleargument\math_stackers_define_double}
@@ -713,29 +748,41 @@
\def\math_stackers_define_double[#category][#command][#topcode][#bottomcode]%
{\setuvalue{#command}{\math_stackers_handle_direct\plusone\plusone{#category}{#topcode}{#bottomcode}}}
-\unexpanded\def\mathover {\begingroup\dosingleempty\math_stackers_handle_over }
-\unexpanded\def\mathunder {\begingroup\dosingleempty\math_stackers_handle_under }
-\unexpanded\def\mathdouble{\begingroup\dosingleempty\math_stackers_handle_double}
+\unexpanded\def\mathover {\begingroup\dodoubleempty\math_stackers_handle_over }
+\unexpanded\def\mathunder {\begingroup\dodoubleempty\math_stackers_handle_under }
+\unexpanded\def\mathdouble{\begingroup\dodoubleempty\math_stackers_handle_double}
-\def\math_stackers_handle_over[#category]#topcode#text%
- {\math_stackers_make_double\plusone\zerocount
- {\iffirstargument#category\else\v!top\fi}%
+\def\math_stackers_handle_over[#category][#settings]#topcode#text%
+ {\edef\currentmathstackers{\iffirstargument#category\else\v!top\fi}%
+ \ifsecondargument
+ \setupcurrentmathstackers[#settings]%
+ \fi
+ \math_stackers_make_double\plusone\zerocount
+ {\currentmathstackers}%
{#topcode}%
{0}%
{#text}%
\endgroup}
-\def\math_stackers_handle_under[#category]#bottomcode#text%
- {\math_stackers_make_double\zerocount\plusone
- {\iffirstargument#category\else\v!bottom\fi}%
+\def\math_stackers_handle_under[#category][#settings]#bottomcode#text%
+ {\edef\currentmathstackers{\iffirstargument#category\else\v!bottom\fi}%
+ \ifsecondargument
+ \setupcurrentmathstackers[#settings]%
+ \fi
+ \math_stackers_make_double\zerocount\plusone
+ {\currentmathstackers}%
{#bottomcode}%
{0}%
{#text}%
\endgroup}
-\def\math_stackers_handle_double[#category]#topcode#bottomcode#text%
- {\math_stackers_make_double\plusone\plusone
- {\iffirstargument#category\else\v!both\fi}%
+\def\math_stackers_handle_double[#category][#settings]#topcode#bottomcode#text%
+ {\edef\currentmathstackers{\iffirstargument#category\else\v!both\fi}%
+ \ifsecondargument
+ \setupcurrentmathstackers[#settings]%
+ \fi
+ \math_stackers_make_double\plusone\plusone
+ {\currentmathstackers}%
{#topcode}%
{#bottomcode}%
{#text}%
diff --git a/tex/context/base/mkiv/meta-tex.mkiv b/tex/context/base/mkiv/meta-tex.mkiv
index 03ad5ee39..418ddc196 100644
--- a/tex/context/base/mkiv/meta-tex.mkiv
+++ b/tex/context/base/mkiv/meta-tex.mkiv
@@ -153,4 +153,87 @@
\clf_MPLIBconvertoutlinetext\numexpr#1\relax{#2}\scratchbox
\endgroup}
+%D For now here. We don't do the whole thing, because then one can as
+%D well just export to pdf. We assume consistent integration.
+
+\definefontsynonym[serif-normal-normal] [\s!Serif]
+\definefontsynonym[serif-normal-italic] [\s!SerifItalic]
+\definefontsynonym[serif-normal-oblique][\s!SerifSlanted]
+\definefontsynonym[serif-bold-normal] [\s!SerifBold]
+\definefontsynonym[serif-bold-italic] [\s!SerifBoldItalic]
+\definefontsynonym[serif-bold-oblique] [\s!SerifBoldSlanted]
+
+\definefontsynonym[sans-normal-normal] [\s!Sans]
+\definefontsynonym[sans-normal-italic] [\s!SansItalic]
+\definefontsynonym[sans-normal-oblique] [\s!SansSlanted]
+\definefontsynonym[sans-bold-normal] [\s!SansBold]
+\definefontsynonym[sans-bold-italic] [\s!SansBoldItalic]
+\definefontsynonym[sans-bold-oblique] [\s!SansBoldSlanted]
+
+\definefontsynonym[mono-normal-normal] [\s!Mono]
+\definefontsynonym[mono-normal-italic] [\s!MonoItalic]
+\definefontsynonym[mono-normal-oblique] [\s!MonoSlanted]
+\definefontsynonym[mono-bold-normal] [\s!MonoBold]
+\definefontsynonym[mono-bold-italic] [\s!MonoBoldItalic]
+\definefontsynonym[mono-bold-oblique] [\s!MonoBoldSlanted]
+
+\installcorenamespace {svgfamily}
+
+\setvalue{\??svgfamily }{serif}
+\setvalue{\??svgfamily serif}{serif}
+\setvalue{\??svgfamily sans}{sans}
+\setvalue{\??svgfamily mono}{mono}
+
+%D This can't change because otherwise \type {\scale[width=4cm]{graphic}} fails.
+
+\unexpanded\def\svgscaled#1%
+ {\fastsxsy{#1}{#1}\svgnormal}
+
+\unexpanded\def\svgnormal#1#2#3#4% family weight style text
+ {\bgroup
+ \edef\p_family{#1}%
+ \ifx\p_family\empty\else
+ \edef\p_font{\ifcsname\??svgfamily#1\endcsname\lastnamedcs\else#1\fi-#2-#3}%
+ \predefinedfont[\s!spec:\p_font*\s!default\space @ 10bp]%
+ \fi
+ #4%
+ \egroup}
+
+\unexpanded\def\svgcolored#1#2#3#4% r g b text
+ {\colored[r=#1,g=#2,b=#3]{#4}}
+
+\unexpanded\def\svgplaced#1#2#3#4% dx dy width text
+ {\doifelsenothing{#3}%
+ {\hpack}%
+ {\hpack to #3}%
+ {\raise#2\onebasepoint\hbox{\kern#1\onebasepoint\relax#4}}}
+
+\newdimen\grph_svg_scratchwidth % maybe \startsvgpos etc
+
+\unexpanded\def\svgposchar#1#2#3% dx dy char
+ {\setbox\scratchbox\hpack\bgroup
+ \raise#2\onebasepoint\hbox\bgroup
+ \kern\dimexpr#1\onebasepoint-\grph_svg_scratchwidth\relax
+ \char#3\relax
+ \egroup
+ \egroup
+ \advance\grph_svg_scratchwidth\wd\scratchbox
+ \box\scratchbox}
+
+\unexpanded\def\svgchar#1% char
+ {\char#1\relax}
+
+\definelayer[svgmps][\c!method=\v!fit]
+
+\unexpanded\def\svgstartlayer
+ {\resetlayer[svgmps]%
+ \setlayer[svgmps]\bgroup}
+
+\unexpanded\def\svgstoplayer
+ {\egroup
+ \flushlayer[svgmps]}
+
+\unexpanded\def\svgsetlayer#1#2%
+ {\setlayer[svgmps][\c!x=#1\onebasepoint,\c!y=#2\onebasepoint]} % {#3}
+
\protect \endinput
diff --git a/tex/context/base/mkiv/mlib-cnt.lua b/tex/context/base/mkiv/mlib-cnt.lua
index 16625befb..adcaf9f94 100644
--- a/tex/context/base/mkiv/mlib-cnt.lua
+++ b/tex/context/base/mkiv/mlib-cnt.lua
@@ -313,12 +313,12 @@ function mp.lmt_contours_start()
for i=1,nofvalues do
colors[i] = { fcolor(i) }
end
-if attributes.colors.model == "cmyk" then
- for i=1,#colors do
- local c = colors[i]
- colors[i] = { 1 - c[1], 1 - c[2], 1 - c[3], 0 }
- end
-end
+ if attributes.colors.model == "cmyk" then
+ for i=1,#colors do
+ local c = colors[i]
+ colors[i] = { 1 - c[1], 1 - c[2], 1 - c[3], 0 }
+ end
+ end
return colors, fcolor
end
end
diff --git a/tex/context/base/mkiv/mlib-lmp.lua b/tex/context/base/mkiv/mlib-lmp.lua
index e72ddd03c..402c194fe 100644
--- a/tex/context/base/mkiv/mlib-lmp.lua
+++ b/tex/context/base/mkiv/mlib-lmp.lua
@@ -6,6 +6,8 @@ if not modules then modules = { } end modules ['mlib-lmp'] = {
license = "see context related readme files",
}
+local type = type
+
local aux = mp.aux
local mpnumeric = aux.numeric
local mppair = aux.pair
@@ -136,23 +138,64 @@ do
end
-function mp.lmt_svg_include()
- local filename = metapost.getparameter { "filename" }
- local fontname = metapost.getparameter { "fontname" }
- local metacode = nil
- if fontname and fontname ~= "" then
- local unicode = metapost.getparameter { "unicode" }
- if unicode then
- metacode = metapost.svgglyphtomp(fontname,math.round(unicode))
+if CONTEXTLMTXMODE > 0 then
+
+ function mp.lmt_svg_include()
+ local labelfile = metapost.getparameter { "labelfile" }
+ if labelfile then
+ local labels = table.load(labelfile) -- todo: same path as svg file
+ if type(labels) == "table" then
+ for i=1,#labels do
+ metapost.remaptext(labels[i])
+ end
+ end
+ end
+ local fontname = metapost.getparameter { "fontname" }
+ if fontname and fontname ~= "" then
+ local unicode = metapost.getparameter { "unicode" }
+ if unicode then
+ mpdirect (
+ metapost.svgglyphtomp(fontname,math.round(unicode))
+ )
+ end
+ return
+ end
+ local filename = metapost.getparameter { "filename" }
+ if filename and filename ~= "" then
+ mpdirect ( metapost.svgtomp {
+ data = io.loaddata(filename),
+ remap = true,
+ } )
+ return
+ end
+ local buffer = metapost.getparameter { "buffer" }
+ if buffer then
+ mpdirect ( metapost.svgtomp {
+ data = buffers.getcontent(buffer),
+ -- remap = true,
+ } )
+ return
+ end
+ local code = metapost.getparameter { "code" }
+ if code then
+ mpdirect ( metapost.svgtomp {
+ data = code,
+ } )
+ return
end
- elseif filename and filename ~= "" then
- metacode = metapost.svgtomp {
- data = io.loaddata(filename)
- }
end
- if metacode then
- mpdirect(metacode)
+
+end
+
+if CONTEXTLMTXMODE > 0 then
+
+ function mp.lmt_do_remaptext()
+ local parameters = metapost.scanparameters()
+ if parameters and parameters.label then
+ metapost.remaptext(parameters)
+ end
end
+
end
if CONTEXTLMTXMODE > 0 then
diff --git a/tex/context/base/mkiv/mlib-pdf.lua b/tex/context/base/mkiv/mlib-pdf.lua
index ece332d84..4f183eed3 100644
--- a/tex/context/base/mkiv/mlib-pdf.lua
+++ b/tex/context/base/mkiv/mlib-pdf.lua
@@ -274,6 +274,34 @@ local function flushconcatpath(path, t, open)
return t
end
+local function toboundingbox(path)
+ local size = #path
+ if size == 4 then
+ local pth = path[1]
+ local x = pth.x_coord
+ local y = pth.y_coord
+ local llx, lly, urx, ury = x, y, x, y
+ for i=2,size do
+ pth = path[i]
+ x = pth.x_coord
+ y = pth.y_coord
+ if x < llx then
+ llx = x
+ elseif x > urx then
+ urx = x
+ end
+ if y < lly then
+ lly = y
+ elseif y > ury then
+ ury = y
+ end
+ end
+ return { llx, lly, urx, ury }
+ else
+ return { 0, 0, 0, 0 }
+ end
+end
+
metapost.flushnormalpath = flushnormalpath
-- The flusher is pdf based, if another backend is used, we need to overload the
@@ -283,8 +311,10 @@ metapost.flushnormalpath = flushnormalpath
-- 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.
+--
+-- This variable stuff will change in lmtx.
-local ignore = function () end
+local ignore = function() end
local space = P(" ")
local equal = P("=")
@@ -380,10 +410,10 @@ function metapost.flush(specification,result)
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 pluginactions = metapost.pluginactions or ignore -- before / after
local startfigure = flusher.startfigure
local stopfigure = flusher.stopfigure
local flushfigure = flusher.flushfigure
@@ -413,6 +443,8 @@ function metapost.flush(specification,result)
-- we need to be indirect if we want the one-pass solution
+ local groupstack = { }
+
local function processfigure()
result[#result+1] = "q"
if objects then
@@ -444,6 +476,35 @@ function metapost.flush(specification,result)
miterlimit, linecap, linejoin, dashed = -1, -1, -1, "" -- was false
elseif objecttype == "start_bounds" or objecttype == "stop_bounds" then
-- skip
+ elseif objecttype == "start_group" then
+ if lpdf.flushgroup then
+ local before, after = processplugins(object)
+ if before then
+ result[#result+1] = "q"
+ result = pluginactions(before,result,flushfigure)
+ insert(groupstack, {
+ after = after,
+ result = result,
+ bbox = toboundingbox(object.path),
+ })
+ result = { }
+miterlimit, linecap, linejoin, dashed, linewidth = -1, -1, -1, "", false
+ else
+ insert(groupstack,false)
+ end
+ else
+ insert(groupstack,false)
+ end
+ elseif objecttype == "stop_group" then
+ local data = remove(groupstack)
+ if data then
+ local id = lpdf.flushgroup(concat(result,"\r"),data.bbox)
+ result = data.result
+ result[#result+1] = formatters["/%s Do"](id)
+ result = pluginactions(data.after,result,flushfigure)
+ result[#result+1] = "Q"
+miterlimit, linecap, linejoin, dashed, linewidth = -1, -1, -1, "", false
+ end
else
-- we use an indirect table as we want to overload
-- entries but this is not possible in userdata
@@ -451,7 +512,7 @@ function metapost.flush(specification,result)
-- can be optimized if no path
--
local original = object
- local object = { }
+ local object = { }
setmetatable(object, {
__index = original
})
diff --git a/tex/context/base/mkiv/mlib-pps.lua b/tex/context/base/mkiv/mlib-pps.lua
index 46d436466..5098eb76d 100644
--- a/tex/context/base/mkiv/mlib-pps.lua
+++ b/tex/context/base/mkiv/mlib-pps.lua
@@ -30,6 +30,8 @@ local flush_list = node.flush_list
local setmetatableindex = table.setmetatableindex
local sortedhash = table.sortedhash
+local new_hlist = nodes.pool.hlist
+
local starttiming = statistics.starttiming
local stoptiming = statistics.stoptiming
@@ -258,6 +260,9 @@ local function startjob(plugmode,kind,mpx)
top = {
textexts = { }, -- all boxes, optionally with a different color
texstrings = { },
+ mapstrings = { },
+ mapindices = { },
+ mapmoves = { },
texlast = 0,
texdata = setmetatableindex({},preset), -- references to textexts in order or usage
plugmode = plugmode, -- some day we can then skip all pre/postscripts
@@ -720,7 +725,7 @@ function metapost.processplugins(object) -- each object (second pass)
if prescript and #prescript > 0 then
local before = { }
local after = { }
- processoractions.runner(object,splitprescript(prescript) or {},before,after)
+ processoractions.runner(object,splitprescript(prescript) or { },before,after)
return #before > 0 and before, #after > 0 and after
else
local c = object.color
@@ -870,6 +875,92 @@ local tx_reset, tx_process do
mp.mf_some_text(index,madetext)
end
+ -- a label can be anything, also something mp doesn't like in strings
+ -- so we return an index instead
+
+ function metapost.processing()
+ return top and true or false
+ end
+
+ function metapost.remaptext(replacement)
+ if top then
+ local mapstrings = top.mapstrings
+ local mapindices = top.mapindices
+ local label = replacement.label
+ local index = 0
+ if label then
+ local found = mapstrings[label]
+ if found then
+ setmetatableindex(found,replacement)
+ index = found.index
+ else
+ index = #mapindices + 1
+ replacement.index = index
+ mapindices[index] = replacement
+ mapstrings[label] = replacement
+ end
+ end
+ return index
+ else
+ return 0
+ end
+ end
+
+ function metapost.remappedtext(what)
+ return top and (top.mapstrings[what] or top.mapindices[tonumber(what)])
+ end
+
+ function mp.mf_map_move(index)
+ mp.triplet(top.mapmoves[index])
+ end
+
+ function mp.mf_map_text(index,str)
+ local map = top.mapindices[tonumber(str)]
+ if type(map) == "table" then
+ local text = map.text
+ local overload = map.overload
+ local offset = 0
+ local width = 0
+ local where = nil
+ --
+ mp_index = index
+ -- the image text
+ if overload then
+ top.texstrings[mp_index] = map.template or map.label or "error"
+ tex.runtoks("mptexttoks")
+ local box = textakebox("mptextbox") or new_hlist()
+ width = bp * box.width
+ where = overload.where
+ end
+ -- the real text
+ top.texstrings[mp_index] = overload and overload.text or text or "error"
+ tex.runtoks("mptexttoks")
+ local box = textakebox("mptextbox") or new_hlist()
+ local twd = bp * box.width
+ local tht = bp * box.height
+ local tdp = bp * box.depth
+ -- the check
+ if where then
+ local scale = 1 -- / (map.scale or 1)
+ if where == "l" or where == "left" then
+ offset = scale * (twd - width)
+ elseif where == "m" or where == "middle" then
+ offset = scale * (twd - width) / 2
+ end
+ end
+ -- the result
+ top.textexts[mp_index] = box
+ top.mapmoves[mp_index] = { offset, map.dx or 0, map.dy or 0 }
+ --
+ mp.triplet(twd,tht,tdp)
+ madetext = nil
+ return
+ else
+ map = type(map) == "string" and map or str
+ return mp.mf_some_text(index,context.escape(map) or map)
+ end
+ end
+
-- This is a bit messy. In regular metapost it's a kind of immediate replacement
-- so embedded btex ... etex is not really working as one would expect. We now have
-- a mix: it's immediate when we are at the outer level (rawmadetext) and indirect
diff --git a/tex/context/base/mkiv/mlib-run.lua b/tex/context/base/mkiv/mlib-run.lua
index cc4a77660..07fa6a191 100644
--- a/tex/context/base/mkiv/mlib-run.lua
+++ b/tex/context/base/mkiv/mlib-run.lua
@@ -852,6 +852,8 @@ do
end,
}
+ -- make table variant:
+
function metapost.simple(instance,code,useextensions,dontwrap)
-- can we pickup the instance ?
local mpx = metapost.pushformat {
diff --git a/tex/context/base/mkiv/mlib-scn.lua b/tex/context/base/mkiv/mlib-scn.lua
index 1ebe68bdc..709961543 100644
--- a/tex/context/base/mkiv/mlib-scn.lua
+++ b/tex/context/base/mkiv/mlib-scn.lua
@@ -250,7 +250,7 @@ local function get_parameters(nested)
end
local function getparameters()
- local namespace = scanstring()
+ local namespace = scanstring()
-- same as below
local parameters = get_parameters()
local presets = presets[namespace]
@@ -668,6 +668,11 @@ end
-- return false
-- end
+function metapost.scanparameters()
+-- scantoken() -- we scan the semicolon
+ return get_parameters()
+end
+
metapost.registerscript("getparameters", getparameters)
metapost.registerscript("applyparameters", applyparameters)
metapost.registerscript("presetparameters", presetparameters)
diff --git a/tex/context/base/mkiv/mlib-svg.lua b/tex/context/base/mkiv/mlib-svg.lua
index d201ec20e..afbf36ecf 100644
--- a/tex/context/base/mkiv/mlib-svg.lua
+++ b/tex/context/base/mkiv/mlib-svg.lua
@@ -6,36 +6,21 @@ if not modules then modules = { } end modules ['mlib-svg'] = {
license = "see context related readme files",
}
--- As usual with these standards, things like a path can be very compact while the rest is
--- very verbose which defeats the point. This is a first attempt. There will be a converter
--- to MP as well as directly to PDF. This module was made for one of the dangerous curves
--- talks at the 2019 CTX meeting. I will do the font when I need it (not that hard).
+-- Just a few notes:
--
--- There is no real need to boost performance here .. we can always make a fast variant
--- when really needed. I will also do some of the todo's when I run into proper fonts.
-
--- Written with Anne Clark on speakers as distraction.
-
--- Todo when I run into an example:
---
--- var(color,color)
--- --color<decimal>
--- currentColor : when i run into an example
--- some more fonts
---
--- Todo: some day
---
--- optimize
--- instances
--- withpen -> pickup
+-- There is no real need to boost performance here .. we can always make a fast
+-- variant when really needed. I will also do some of the todo's when I run into
+-- proper fonts. I need to optimize this a bit but will do that once I'm satisfied
+-- with the outcome and don't need more hooks and plugs. At some point I will
+-- optimize the MetaPost part because now we probably have more image wrapping
+-- than needed.
--
--- Todo: when i am motivated
+-- As usual with these standards, things like a path can be very compact while the
+-- rest is very verbose which defeats the point. This is a first attempt. There will
+-- be a converter to MP as well as directly to PDF. This module was made for one of
+-- the dangerous curves talks at the 2019 CTX meeting. I will do the font when I
+-- need it (not that hard).
--
--- shading
--- "none" -> false
--- clip = [ auto | rect(llx,lly,urx,ury) ] (in svg)
--- xlink url ... whatever
-
-- The fact that in the more recent versions of SVG the older text related elements
-- are depricated and not even supposed to be supported, combined with the fact that
-- the text element assumes css styling, demonstrates that there is not so much as a
@@ -43,468 +28,236 @@ if not modules then modules = { } end modules ['mlib-svg'] = {
-- (probably combined with some libraries that at that point exist) determine what
-- is standard. Anyway, it probably also means that these formats are not that
-- suitable for long term archival purposes. So don't take the next implementation
--- too serious.
-
+-- too serious. So in the end we now have (1) attributes for properties (which is
+-- nice and clean and what attributes are for, (2) a style attribute that needs to
+-- be parsed, (3) classes that map to styles and (4) element related styles, plus a
+-- kind of inheritance (given the limited number of elements sticking to only <g> as
+-- wrapper would have made much sense. Anyway, we need to deal with it. With all
+-- these style things going on, one can wonder where it will end. Basically svg
+-- became just a html element that way and less clean too. The same is true for
+-- tspan, which means that text itself is nested xml.
+--
-- We can do a direct conversion to PDF but then we also loose the abstraction which
--- in the future will be used.
+-- in the future will be used, and for fonts we need to spawn out to TeX anyway, so
+-- the little overhead of calling MetaPost is okay I guess. Also, we want to
+-- overload labels, share fonts with the main document, etc. and are not aiming at a
+-- general purpose SVG converter. For going to PDF one can just use InkScape.
+--
+-- Written with Anne Clark on speakers as distraction.
+--
+-- Todo when I run into an example (but ony when needed and reasonable):
+--
+-- var(color,color)
+-- --color<decimal>
+-- currentColor : when i run into an example
+-- a bit more shading
+-- clip = [ auto | rect(llx,lly,urx,ury) ] (in svg)
+-- xlink url ... whatever
+-- masks
+-- opacity per group (i need to add that to metafun first, inefficient pdf but
+-- maybe filldraw can help here)
+--
+-- Maybe in metafun:
+--
+-- penciled n -> withpen pencircle scaled n
+-- applied (...) -> transformed bymatrix (...)
+-- withopacity n -> withtransparency (1,n)
+
+-- When testing mbo files:
+--
+-- empty paths
+-- missing control points
+-- funny fontnames like abcdefverdana etc
+-- paths representing glyphs but also with style specs
+-- all kind of attributes
+-- very weird and inefficient shading
+
+-- 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 type, tonumber = type, tonumber
+local rawget, type, tonumber, tostring, next, setmetatable = rawget, 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 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 concat, setmetatableindex = table.concat, table.setmetatableindex
+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 = string.formatters
+local formatters, fullstrip = string.formatters, string.fullstrip
local extract = bit32.extract
+local utfsplit, utfbyte = utf.split, utf.byte
-local xmlconvert, xmlcollected, xmlcount, xmlfirst, xmlroot, xmltext = xml.convert, xml.collected, xml.count, xml.first, xml.root, xml.text
+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
-metapost = metapost or { }
-local metapost = metapost
-local context = context
+local bpfactor = number.dimenfactors.bp
-local report = logs.reporter("metapost","svg")
-
-local trace = false
--- local trace = true
-
--- todo: also a high res mode
--- todo: optimize (no hurry)
-
-local f_rectangle = formatters['unitsquare xyscaled (%.3N,%.3N) shifted (%.3N,%.3N)']
-local f_rounded = formatters['roundedsquarexy(%.3N,%.3N,%.3N,%.3N) shifted (%.3N,%.3N)']
-local f_ellipse = formatters['(fullcircle xyscaled (%.3N,%.3N) shifted (%.3N,%.3N))']
-local f_circle = formatters['(fullcircle scaled %.3N shifted (%.3N,%.3N))']
-local f_line = formatters['((%.3N,%.3N)--(%.3N,%.3N))']
-local f_fill = formatters['fill %s(%s--cycle)%s%s%s ;'] -- play safe
-local f_fill_cycle_c = formatters['fill %s(%s..cycle)%s%s%s ;']
-local f_fill_cycle_l = formatters['fill %s(%s--cycle)%s%s%s ;']
-local f_eofill = formatters['eofill %s(%s--cycle)%s%s%s ;'] -- play safe
-local f_eofill_cycle_c = formatters['eofill %s(%s..cycle)%s%s%s ;']
-local f_eofill_cycle_l = formatters['eofill %s(%s--cycle)%s%s%s ;']
-local f_nofill = formatters['nofill %s(%s--cycle)%s ;'] -- play safe
-local f_nofill_cycle_c = formatters['nofill %s(%s..cycle)%s ;']
-local f_nofill_cycle_l = formatters['nofill %s(%s--cycle)%s ;']
-local f_draw = formatters['draw %s(%s)%s%s%s%s%s ;']
-local f_nodraw = formatters['nodraw %s(%s)%s ;']
-
--- local f_fill = formatters['F %s(%s--C)%s%s%s ;'] -- play safe
--- local f_fill_cycle_c = formatters['F %s(%s..C)%s%s%s ;']
--- local f_fill_cycle_l = formatters['F %s(%s--C)%s%s%s ;']
--- local f_eofill = formatters['E %s(%s--C)%s%s%s ;'] -- play safe
--- local f_eofill_cycle_c = formatters['E %s(%s..C)%s%s%s ;']
--- local f_eofill_cycle_l = formatters['E %s(%s--C)%s%s%s ;']
--- local f_nofill = formatters['f %s(%s--C)%s ;'] -- play safe
--- local f_nofill_cycle_c = formatters['f %s(%s..C)%s ;']
--- local f_nofill_cycle_l = formatters['f %s(%s--C)%s ;']
--- local f_draw = formatters['D %s(%s)%s%s%s%s%s ;']
--- local f_nodraw = formatters['d %s(%s)%s ;']
-
-local f_color = formatters[' withcolor "%s"']
------ f_color_rgb = formatters[' withcolor "0x%02X%02X%02X"']
------ f_color_rgba = formatters[' withcolor "0x%02X%02X%02X" withtransparency (1,%3N)']
------ f_color_triplet = formatters['"0x%02X%02X%02X"']
-
-local f_rgb = formatters[' withcolor svgcolor(%.3N,%.3N,%.3N)']
-local f_rgba = formatters[' withcolor svgcolor(%.3N,%.3N,%.3N) withtransparency (1,%3N)']
-local f_triplet = formatters['svgvolor(%.3N,%.3N,%.3N)']
-local f_gray = formatters[' withcolor %.3N']
-
-local f_opacity = formatters[' withtransparency (1,%.3N)']
-local f_pen = formatters[' withpen pencircle scaled %.3N']
-
-local f_dashed_n = formatters[" dashed dashpattern (%s ) "]
-local f_dashed_y = formatters[" dashed dashpattern (%s ) shifted (%.3N,0) "]
-
-local f_moveto = formatters['(%N,%n)']
-local f_curveto_z = formatters[' controls (%.3N,%.3N) and (%.3N,%.3N) .. (%.3N,%.3N)']
-local f_curveto_n = formatters['.. controls (%.3N,%.3N) and (%.3N,%.3N) .. (%.3N,%.3N)']
-local f_lineto_z = formatters['(%.3N,%.3N)']
-local f_lineto_n = formatters['-- (%.3N,%.3N)']
-
-local f_rotatedaround = formatters[" ) rotatedaround((%.3N,%.3N),%.3N)"]
-local f_rotated = formatters[" ) rotated(%.3N)"]
-local f_shifted = formatters[" ) shifted(%.3N,%.3N)"]
-local f_slanted_x = formatters[" ) xslanted(%.3N)"]
-local f_slanted_y = formatters[" ) yslanted(%.3N)"]
-local f_scaled = formatters[" ) scaled(%.3N)"]
-local f_xyscaled = formatters[" ) xyscaled(%.3N,%.3N)"]
-local f_matrix = formatters[" ) transformed bymatrix(%.3N,%.3N,%.3N,%.3N,%.3N,%.3N)"]
-
--- penciled n -> withpen pencircle scaled n
--- applied (...) -> transformed bymatrix (...)
--- withopacity n -> withtransparency (1,n)
-
-local s_clip_start = 'draw image ('
-local f_clip_stop = formatters[') ; clip currentpicture to (%s) ;']
-local f_eoclip_stop = formatters[') ; eoclip currentpicture to (%s) ;']
-
-local f_transform_start = formatters["draw %s image ( "]
-local f_transform_stop = formatters[") %s ;"]
-
-local s_offset_start = "draw image ( "
-local f_offset_stop = formatters[") shifted (%.3N,%.3N) ;"]
-
-local s_scaled_start = "draw image ( "
-local f_scaled_stop = formatters[") scaled %.3N ;"]
-
-local s_hacked_start = "draw image ("
-local f_hacked_stop = formatters[") shifted (0,%.3N) scaled %.3N ;"]
--- local f_hacked_stop = formatters[") scaled %.3N ;"]
-
-local f_viewport_start = "draw image ("
-local f_viewport_stop = ") ;"
-local f_viewport_shift = formatters["currentpicture := currentpicture shifted (%03N,%03N);"]
-local f_viewport_clip = formatters["clip currentpicture to (unitsquare xyscaled (%03N,%03N));"]
-
-local f_linecap = formatters["interim linecap := %s ;"]
-local f_linejoin = formatters["interim linejoin := %s ;"]
-local f_miterlimit = formatters["interim miterlimit := %s ;"]
-
-local s_begingroup = "begingroup;"
-local s_endgroup = "endgroup;"
-
--- make dedicated macro
-
-local s_shade_linear = ' withshademethod "linear" '
-local s_shade_circular = ' withshademethod "circular" '
-local f_shade_step = formatters['withshadestep ( withshadefraction %.3N withshadecolors(%s,%s) )']
-local f_shade_one = formatters['withprescript "sh_center_a=%.3N %.3N"']
-local f_shade_two = formatters['withprescript "sh_center_b=%.3N %.3N"']
-
-local f_text_scaled = formatters['(textext.drt("%s") scaled %.3N shifted (%.3N,%.3N))']
-local f_text_normal = formatters['(textext.drt("%s") shifted (%.3N,%.3N))']
-
--- We can actually use the svg color definitions from the tex end but maybe a user doesn't
--- want those replace the normal definitions.
-
-local svgcolors = {
- black = 0x000000,
- navy = 0x000080,
- darkblue = 0x00008B,
- mediumblue = 0x0000CD,
- blue = 0x0000FF,
- darkgreen = 0x006400,
- green = 0x008000,
- teal = 0x008080,
- darkcyan = 0x008B8B,
- deepskyblue = 0x00BFFF,
- darkturquoise = 0x00CED1,
- mediumspringgreen = 0x00FA9A,
- lime = 0x00FF00,
- springgreen = 0x00FF7F,
- cyan = 0x00FFFF,
- aqua = 0x00FFFF,
- midnightblue = 0x191970,
- dodgerblue = 0x1E90FF,
- lightseagreen = 0x20B2AA,
- forestgreen = 0x228B22,
- seagreen = 0x2E8B57,
- darkslategray = 0x2F4F4F,
- darkslategrey = 0x2F4F4F,
- limegreen = 0x32CD32,
- mediumseagreen = 0x3CB371,
- turquoise = 0x40E0D0,
- royalblue = 0x4169E1,
- steelblue = 0x4682B4,
- darkslateblue = 0x483D8B,
- mediumturquoise = 0x48D1CC,
- indigo = 0x4B0082,
- darkolivegreen = 0x556B2F,
- cadetblue = 0x5F9EA0,
- cornflowerblue = 0x6495ED,
- mediumaquamarine = 0x66CDAA,
- dimgrey = 0x696969,
- dimgray = 0x696969,
- slateblue = 0x6A5ACD,
- olivedrab = 0x6B8E23,
- slategrey = 0x708090,
- slategray = 0x708090,
- lightslategray = 0x778899,
- lightslategrey = 0x778899,
- mediumslateblue = 0x7B68EE,
- lawngreen = 0x7CFC00,
- chartreuse = 0x7FFF00,
- aquamarine = 0x7FFFD4,
- maroon = 0x800000,
- purple = 0x800080,
- olive = 0x808000,
- gray = 0x808080,
- grey = 0x808080,
- skyblue = 0x87CEEB,
- lightskyblue = 0x87CEFA,
- blueviolet = 0x8A2BE2,
- darkred = 0x8B0000,
- darkmagenta = 0x8B008B,
- saddlebrown = 0x8B4513,
- darkseagreen = 0x8FBC8F,
- lightgreen = 0x90EE90,
- mediumpurple = 0x9370DB,
- darkviolet = 0x9400D3,
- palegreen = 0x98FB98,
- darkorchid = 0x9932CC,
- yellowgreen = 0x9ACD32,
- sienna = 0xA0522D,
- brown = 0xA52A2A,
- darkgray = 0xA9A9A9,
- darkgrey = 0xA9A9A9,
- lightblue = 0xADD8E6,
- greenyellow = 0xADFF2F,
- paleturquoise = 0xAFEEEE,
- lightsteelblue = 0xB0C4DE,
- powderblue = 0xB0E0E6,
- firebrick = 0xB22222,
- darkgoldenrod = 0xB8860B,
- mediumorchid = 0xBA55D3,
- rosybrown = 0xBC8F8F,
- darkkhaki = 0xBDB76B,
- silver = 0xC0C0C0,
- mediumvioletred = 0xC71585,
- indianred = 0xCD5C5C,
- peru = 0xCD853F,
- chocolate = 0xD2691E,
- tan = 0xD2B48C,
- lightgray = 0xD3D3D3,
- lightgrey = 0xD3D3D3,
- thistle = 0xD8BFD8,
- orchid = 0xDA70D6,
- goldenrod = 0xDAA520,
- palevioletred = 0xDB7093,
- crimson = 0xDC143C,
- gainsboro = 0xDCDCDC,
- plum = 0xDDA0DD,
- burlywood = 0xDEB887,
- lightcyan = 0xE0FFFF,
- lavender = 0xE6E6FA,
- darksalmon = 0xE9967A,
- violet = 0xEE82EE,
- palegoldenrod = 0xEEE8AA,
- lightcoral = 0xF08080,
- khaki = 0xF0E68C,
- aliceblue = 0xF0F8FF,
- honeydew = 0xF0FFF0,
- azure = 0xF0FFFF,
- sandybrown = 0xF4A460,
- wheat = 0xF5DEB3,
- beige = 0xF5F5DC,
- whitesmoke = 0xF5F5F5,
- mintcream = 0xF5FFFA,
- ghostwhite = 0xF8F8FF,
- salmon = 0xFA8072,
- antiquewhite = 0xFAEBD7,
- linen = 0xFAF0E6,
- lightgoldenrodyellow = 0xFAFAD2,
- oldlace = 0xFDF5E6,
- red = 0xFF0000,
- fuchsia = 0xFF00FF,
- magenta = 0xFF00FF,
- deeppink = 0xFF1493,
- orangered = 0xFF4500,
- tomato = 0xFF6347,
- hotpink = 0xFF69B4,
- coral = 0xFF7F50,
- darkorange = 0xFF8C00,
- lightsalmon = 0xFFA07A,
- orange = 0xFFA500,
- lightpink = 0xFFB6C1,
- pink = 0xFFC0CB,
- gold = 0xFFD700,
- peachpuff = 0xFFDAB9,
- navajowhite = 0xFFDEAD,
- moccasin = 0xFFE4B5,
- bisque = 0xFFE4C4,
- mistyrose = 0xFFE4E1,
- blanchedalmond = 0xFFEBCD,
- papayawhip = 0xFFEFD5,
- lavenderblush = 0xFFF0F5,
- seashell = 0xFFF5EE,
- cornsilk = 0xFFF8DC,
- lemonchiffon = 0xFFFACD,
- floralwhite = 0xFFFAF0,
- snow = 0xFFFAFA,
- yellow = 0xFFFF00,
- lightyellow = 0xFFFFE0,
- ivory = 0xFFFFF0,
- white = 0xFFFFFF,
-}
-
-local svgcolor = setmetatableindex(function(t,k)
- -- we delay building all these strings
- local v = svgcolors[k]
- if v then
- v = f_rgb(extract(v,16,8),extract(v,8,8),extract(v,0,8))
+local function xmlinheritattributes(c,pa)
+ local at = c.at
+ local dt = c.dt
+ if at and dt then
+ if pa then
+ setmetatableindex(at,pa)
+ end
+ for i=1,#dt do
+ local dti = dt[i]
+ if type(dti) == "table" then
+ xmlinheritattributes(dti,at)
+ end
+ end
else
- v = false
+ -- comment of so
end
- t[k] = v
- return v
-end)
+end
-local p_digit = lpegpatterns.digit
-local p_hexdigit = lpegpatterns.hexdigit
-local p_space = lpegpatterns.whitespace
+xml.inheritattributes = xmlinheritattributes
-local p_hexcolor = P("#") * C(p_hexdigit*p_hexdigit)^1 / function(r,g,b)
- r = tonumber(r,16)/255
- if g then
- g = tonumber(g,16)/255
- end
- if b then
- b = tonumber(b,16)/255
- end
- if b then
- return f_rgb(r,g,b)
- else
- return f_gray(r)
- end
-end
+-- Maybe some day helpers will move to the metapost.svg namespace!
-local p_hexcolor3 = P("#") * C(p_hexdigit*p_hexdigit)^1 / function(r,g,b)
- r = tonumber(r,16)/255
- g = g and tonumber(g,16)/255 or r
- b = b and tonumber(b,16)/255 or g
- return f_triplet(r,g,b)
-end
+metapost = metapost or { }
+local metapost = metapost
+local context = context
-local function hexcolor(c)
- return lpegmatch(p_hexcolor,c)
-end
+local report = logs.reporter("metapost","svg")
-local function hexcolor3(c)
- return lpegmatch(p_hexcolor3,c)
-end
+local trace = false trackers.register("metapost.svg", function(v) trace = v end)
+local trace_text = false trackers.register("metapost.svg.text", function(v) trace_text = v end)
+local trace_path = false trackers.register("metapost.svg.path", function(v) trace_path = v end)
+local trace_result = false trackers.register("metapost.svg.result", function(v) trace_result = v end)
--- gains a little:
+local pathtracer = {
+ ["stroke"] = "darkred",
+ ["stroke-opacity"] = ".5",
+ ["stroke-width"] = ".5",
+ ["fill"] = "darkgray",
+ ["fill-opacity"] = ".75",
+}
--- local hexhash = setmetatableindex(function(t,k) local v = lpegmatch(p_hexcolor, k) t[k] = v return v end) -- per file
--- local hexhash3 = setmetatableindex(function(t,k) local v = lpegmatch(p_hexcolor3,k) t[k] = v return v end) -- per file
+-- 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).
--
--- local function hexcolor (c) return hexhash [c] end -- directly do hexhash [c]
--- local function hexcolor3(c) return hexhash3[c] end -- directly do hexhash3[c]
-
--- Most of the conversion is rather trivial code till I ran into a file with arcs. A bit
--- of searching lead to the a2c javascript function but it has some puzzling thingies
--- (like sin and cos definitions that look like leftovers). Anyway, we can if needed
--- optimize it a bit more. Here does it come from:
+-- Most of the conversion is rather trivial code till I ran into a file with arcs. A
+-- bit of searching lead to the a2c javascript function but it has some puzzling
+-- thingies (like sin and cos definitions that look like leftovers and possible
+-- division by zero). Anyway, we can if needed optimize it a bit more. Here does it
+-- come from:
-- http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
-- https://github.com/adobe-webplatform/Snap.svg/blob/b242f49e6798ac297a3dad0dfb03c0893e394464/src/path.js
-local d120 = (pi * 120) / 180
-local pi2 = 2 * pi
+local a2c do
-local function a2c(x1, y1, rx, ry, angle, large, sweep, x2, y2, f1, f2, cx, cy)
+ local d120 = (pi * 120) / 180
+ local pi2 = 2 * pi
- local recursive = f1
+ a2c = function(x1, y1, rx, ry, angle, large, sweep, x2, y2, f1, f2, cx, cy)
- if rx == 0 or ry == 0 then
- return { x1, y1, x2, y2, x2, y2 }
- end
+ if (rx == 0 or ry == 0 ) or (x1 == x2 and y1 == y2) then
+ return { x1, y1, x2, y2, x2, y2 }
+ end
- if x1 == x2 and y1 == y2 then
- return { x1, y1, x2, y2, x2, y2 }
- end
+ local recursive = f1
+ local rad = pi / 180 * angle
+ local res = nil
+ local cosrad = cos(-rad) -- local cosrad = cosd(angle)
+ local sinrad = sin(-rad) -- local sinrad = sind(angle)
- local rad = pi / 180 * angle
- local res = nil
+ if not recursive then
- local cosrad = cos(-rad) -- local cosrad = cosd(angle)
- local sinrad = sin(-rad) -- local sinrad = sind(angle)
+ x1, y1 = x1 * cosrad - y1 * sinrad, x1 * sinrad + y1 * cosrad
+ x2, y2 = x2 * cosrad - y2 * sinrad, x2 * sinrad + y2 * cosrad
- if not recursive then
+ local x = (x1 - x2) / 2
+ local y = (y1 - y2) / 2
+ local xx = x * x
+ local yy = y * y
+ local h = xx / (rx * rx) + yy / (ry * ry)
- x1, y1 = x1 * cosrad - y1 * sinrad, x1 * sinrad + y1 * cosrad
- x2, y2 = x2 * cosrad - y2 * sinrad, x2 * sinrad + y2 * cosrad
+ if h > 1 then
+ h = sqrt(h)
+ rx = h * rx
+ ry = h * ry
+ end
- local x = (x1 - x2) / 2
- local y = (y1 - y2) / 2
- local xx = x * x
- local yy = y * y
- local h = xx / (rx * rx) + yy / (ry * ry)
+ local rx2 = rx * rx
+ local ry2 = ry * ry
+ local ry2xx = ry2 * xx
+ local rx2yy = rx2 * yy
+ local total = rx2yy + ry2xx -- otherwise overflow
- if h > 1 then
- h = sqrt(h)
- rx = h * rx
- ry = h * ry
- end
+ local k = total == 0 and 0 or sqrt(abs((rx2 * ry2 - rx2yy - ry2xx) / total))
- local rx2 = rx * rx
- local ry2 = ry * ry
- local ry2xx = ry2 * xx
- local rx2yy = rx2 * yy
- local total = rx2yy + ry2xx -- otherwise overflow
-
- local k = total == 0 and 0 or sqrt(abs((rx2 * ry2 - rx2yy - ry2xx) / total))
+ if large == sweep then
+ k = -k
+ end
- if large == sweep then
- k = -k
- end
+ cx = k * rx * y / ry + (x1 + x2) / 2
+ cy = k * -ry * x / rx + (y1 + y2) / 2
- cx = k * rx * y / ry + (x1 + x2) / 2
- cy = k * -ry * x / rx + (y1 + y2) / 2
+ f1 = (y1 - cy) / ry -- otherwise crash on a tiny eps
+ f2 = (y2 - cy) / ry -- otherwise crash on a tiny eps
- f1 = (y1 - cy) / ry -- otherwise crash on a tiny eps
- f2 = (y2 - cy) / ry -- otherwise crash on a tiny eps
+ f1 = asin((f1 < -1.0 and -1.0) or (f1 > 1.0 and 1.0) or f1)
+ f2 = asin((f2 < -1.0 and -1.0) or (f2 > 1.0 and 1.0) or f2)
- f1 = asin((f1 < -1.0 and -1.0) or (f1 > 1.0 and 1.0) or f1)
- f2 = asin((f2 < -1.0 and -1.0) or (f2 > 1.0 and 1.0) or f2)
+ if x1 < cx then f1 = pi - f1 end
+ if x2 < cx then f2 = pi - f2 end
- if x1 < cx then f1 = pi - f1 end
- if x2 < cx then f2 = pi - f2 end
+ if f1 < 0 then f1 = pi2 + f1 end
+ if f2 < 0 then f2 = pi2 + f2 end
- if f1 < 0 then f1 = pi2 + f1 end
- if f2 < 0 then f2 = pi2 + f2 end
+ if sweep ~= 0 and f1 > f2 then f1 = f1 - pi2 end
+ if sweep == 0 and f2 > f1 then f2 = f2 - pi2 end
- if sweep ~= 0 and f1 > f2 then
- f1 = f1 - pi2
end
- if sweep == 0 and f2 > f1 then
- f2 = f2 - pi2
+
+ if abs(f2 - f1) > d120 then
+ local f2old = f2
+ local x2old = x2
+ local y2old = y2
+ f2 = f1 + d120 * ((sweep ~= 0 and f2 > f1) and 1 or -1)
+ x2 = cx + rx * cos(f2)
+ y2 = cy + ry * sin(f2)
+ res = a2c(x2, y2, rx, ry, angle, 0, sweep, x2old, y2old, f2, f2old, cx, cy)
end
- end
+ local c1 = cos(f1)
+ local s1 = sin(f1)
+ local c2 = cos(f2)
+ local s2 = sin(f2)
- if abs(f2 - f1) > d120 then
- local f2old = f2
- local x2old = x2
- local y2old = y2
- f2 = f1 + d120 * ((sweep ~= 0 and f2 > f1) and 1 or -1)
- x2 = cx + rx * cos(f2)
- y2 = cy + ry * sin(f2)
- res = a2c(x2, y2, rx, ry, angle, 0, sweep, x2old, y2old, f2, f2old, cx, cy)
- end
+ local t = tan((f2 - f1) / 4)
+ local hx = 4 * rx * t / 3
+ local hy = 4 * ry * t / 3
+
+ local r = { x1 - hx * s1, y1 + hy * c1, x2 + hx * s2, y2 - hy * c2, x2, y2, unpack(res or { }) }
- local c1 = cos(f1)
- local s1 = sin(f1)
- local c2 = cos(f2)
- local s2 = sin(f2)
-
- local t = tan((f2 - f1) / 4)
- local hx = 4 * rx * t / 3
- local hy = 4 * ry * t / 3
-
- local r = { x1 - hx * s1, y1 + hy * c1, x2 + hx * s2, y2 - hy * c2, x2, y2, unpack(res or { }) }
-
- if not recursive then -- we can also check for sin/cos being 0/1
- cosrad = cos(rad)
- sinrad = sin(rad)
- -- cosrad = cosd(angle)
- -- sinrad = sind(angle)
- for i0=1,#r,2 do
- local i1 = i0 + 1
- local x = r[i0]
- local y = r[i1]
- r[i0] = x * cosrad - y * sinrad
- r[i1] = x * sinrad + y * cosrad
+ if not recursive then -- we can also check for sin/cos being 0/1
+ cosrad = cos(rad)
+ sinrad = sin(rad)
+ -- cosrad = cosd(angle)
+ -- sinrad = sind(angle)
+ for i0=1,#r,2 do
+ local i1 = i0 + 1
+ local x = r[i0]
+ local y = r[i1]
+ r[i0] = x * cosrad - y * sinrad
+ r[i1] = x * sinrad + y * cosrad
+ end
end
+
+ return r
end
- return r
end
--- incredible: we can find .123.456 => 0.123 0.456 ...
+-- We share some patterns.
+
+local p_digit = lpegpatterns.digit
+local p_hexdigit = lpegpatterns.hexdigit
+local p_space = lpegpatterns.whitespace
local factors = {
["pt"] = 1.25,
@@ -521,14 +274,18 @@ local percentage_r = 1/100
local percentage_x = percentage_r
local percentage_y = percentage_r
+-- incredible: we can find .123.456 => 0.123 0.456 ...
+
local p_command_x = C(S("Hh"))
local p_command_y = C(S("Vv"))
local p_command_xy = C(S("CcLlMmQqSsTt"))
local p_command_a = C(S("Aa"))
local p_command = C(S("Zz"))
-local p_separator = S("\t\n\r ,")^1
-local p_number = (S("+-")^0 * (p_digit^0 * P(".") * p_digit^1 + p_digit^1 * P(".") + p_digit^1) )
+local p_optseparator = S("\t\n\r ,")^0
+local p_separator = S("\t\n\r ,")^1
+local p_number = (S("+-")^0 * (p_digit^0 * P(".") * p_digit^1 + p_digit^1 * P(".") + p_digit^1))
+ * (P("e") * S("+-")^0 * p_digit^1)^-1
local function convert (n) n = tonumber(n) return n end
local function convert_r (n,u) n = tonumber(n) if u == true then return percentage_r * n elseif u then return u * n else return n end end
@@ -537,11 +294,11 @@ local function convert_y (n,u) n = tonumber(n) if u == true then return percen
local function convert_vx(n,u) n = tonumber(n) if u == true then return percentage_x * n elseif u then return u * n else return n end end
local function convert_vy(n,u) n = - tonumber(n) if u == true then return percentage_y * n elseif u then return u * n else return n end end
-local p_unit = ( P("p") * S("txc") + P("e") * S("xm") + S("mc") * P("m") + P("in")) / factors
+local p_unit = (P("p") * S("txc") + P("e") * S("xm") + S("mc") * P("m") + P("in")) / factors
local p_percent = P("%") * Cc(true)
-local c_number_n = C(p_number)
-local c_number_u = C(p_number) * (p_unit + p_percent)^-1
+local c_number_n = C(p_number)
+local c_number_u = C(p_number) * (p_unit + p_percent)^-1
local p_number_n = c_number_n / convert
local p_number_x = c_number_u / convert_x
@@ -550,300 +307,688 @@ local p_number_y = c_number_u / convert_y
local p_number_vy = c_number_u / convert_vy
local p_number_r = c_number_u / convert_r
--- local p_number = p_number_r -- maybe no percent here
-
-local function asnumber (s) return lpegmatch(p_number, s) end
-local function asnumber_r (s) return lpegmatch(p_number_r, s) end
-local function asnumber_x (s) return lpegmatch(p_number_x, s) end
-local function asnumber_y (s) return lpegmatch(p_number_y, s) end
-local function asnumber_vx(s) return lpegmatch(p_number_vx,s) end
-local function asnumber_vy(s) return lpegmatch(p_number_vy,s) end
-
-local p_numbersep = p_number_n + p_separator
-local p_numbers = p_separator^0 * P("(") * p_numbersep^0 * p_separator^0 * P(")")
-local p_four = p_numbersep^4
-
--- local p_path = Ct((p_command + (p_number_x * p_separator^0 * p_number_y * p_separator^0) + p_separator)^1)
-
-local p_path = Ct ( (
- p_command_xy * (p_separator^0 * p_number_vx *
- p_separator^0 * p_number_vy )^1
- + p_command_x * (p_separator^0 * p_number_vx )^1
- + p_command_y * (p_separator^0 * p_number_vy )^1
- + p_command_a * (p_separator^0 * p_number_vx *
- p_separator^0 * p_number_vy *
- p_separator^0 * p_number_r *
- p_separator^0 * p_number_n * -- flags
- p_separator^0 * p_number_n * -- flags
- p_separator^0 * p_number_vx *
- p_separator^0 * p_number_vy )^1
+local function asnumber (s) return s and lpegmatch(p_number, s) or 0 end
+local function asnumber_r (s) return s and lpegmatch(p_number_r, s) or 0 end
+local function asnumber_x (s) return s and lpegmatch(p_number_x, s) or 0 end
+local function asnumber_y (s) return s and lpegmatch(p_number_y, s) or 0 end
+local function asnumber_vx(s) return s and lpegmatch(p_number_vx,s) or 0 end
+local function asnumber_vy(s) return s and lpegmatch(p_number_vy,s) or 0 end
+
+local p_number_vx_t = Ct { (p_number_vx + p_separator)^1 }
+local p_number_vy_t = Ct { (p_number_vy + p_separator)^1 }
+
+local zerotable = { 0 }
+
+local function asnumber_vx_t(s) return s and lpegmatch(p_number_vx_t,s) or zerotable end
+local function asnumber_vy_t(s) return s and lpegmatch(p_number_vy_t,s) or zerotable end
+
+local p_numbersep = p_number_n + p_separator
+local p_numbers = p_optseparator * P("(") * p_numbersep^0 * p_optseparator * P(")")
+local p_fournumbers = p_numbersep^4
+local p_path = Ct ( (
+ p_command_xy * (p_optseparator * p_number_vx *
+ p_optseparator * p_number_vy )^1
+ + p_command_x * (p_optseparator * p_number_vx )^1
+ + p_command_y * (p_optseparator * p_number_vy )^1
+ + p_command_a * (p_optseparator * p_number_vx *
+ p_optseparator * p_number_vy *
+ p_optseparator * p_number_r *
+ p_optseparator * p_number_n * -- flags
+ p_optseparator * p_number_n * -- flags
+ p_optseparator * p_number_vx *
+ p_optseparator * p_number_vy )^1
+ p_command
+ p_separator
)^1 )
-local p_rgbacolor = P("rgba(") * (C(p_number) + p_separator)^1 * P(")")
+-- We can actually use the svg color definitions from the tex end but maybe a user
+-- doesn't want those replace the normal definitions.
+--
+-- local hexhash = setmetatableindex(function(t,k) local v = lpegmatch(p_hexcolor, k) t[k] = v return v end) -- per file
+-- local hexhash3 = setmetatableindex(function(t,k) local v = lpegmatch(p_hexcolor3,k) t[k] = v return v end) -- per file
+--
+-- local function hexcolor (c) return hexhash [c] end -- directly do hexhash [c]
+-- local function hexcolor3(c) return hexhash3[c] end -- directly do hexhash3[c]
+
+local rgbcomponents, withcolor, thecolor do
+
+ local svgcolors = {
+ aliceblue = 0xF0F8FF, antiquewhite = 0xFAEBD7, aqua = 0x00FFFF, aquamarine = 0x7FFFD4,
+ azure = 0xF0FFFF, beige = 0xF5F5DC, bisque = 0xFFE4C4, black = 0x000000,
+ blanchedalmond = 0xFFEBCD, blue = 0x0000FF, blueviolet = 0x8A2BE2, brown = 0xA52A2A,
+ burlywood = 0xDEB887, cadetblue = 0x5F9EA0, hartreuse = 0x7FFF00, chocolate = 0xD2691E,
+ coral = 0xFF7F50, cornflowerblue = 0x6495ED, cornsilk = 0xFFF8DC, crimson = 0xDC143C,
+ cyan = 0x00FFFF, darkblue = 0x00008B, darkcyan = 0x008B8B, darkgoldenrod = 0xB8860B,
+ darkgray = 0xA9A9A9, darkgreen = 0x006400, darkgrey = 0xA9A9A9, darkkhaki = 0xBDB76B,
+ darkmagenta = 0x8B008B, darkolivegreen = 0x556B2F, darkorange = 0xFF8C00, darkorchid = 0x9932CC,
+ darkred = 0x8B0000, darksalmon = 0xE9967A, darkseagreen = 0x8FBC8F, darkslateblue = 0x483D8B,
+ darkslategray = 0x2F4F4F, darkslategrey = 0x2F4F4F, darkturquoise = 0x00CED1, darkviolet = 0x9400D3,
+ deeppink = 0xFF1493, deepskyblue = 0x00BFFF, dimgray = 0x696969, dimgrey = 0x696969,
+ dodgerblue = 0x1E90FF, firebrick = 0xB22222, floralwhite = 0xFFFAF0, forestgreen = 0x228B22,
+ fuchsia = 0xFF00FF, gainsboro = 0xDCDCDC, ghostwhite = 0xF8F8FF, gold = 0xFFD700,
+ goldenrod = 0xDAA520, gray = 0x808080, green = 0x008000, greenyellow = 0xADFF2F,
+ grey = 0x808080, honeydew = 0xF0FFF0, hotpink = 0xFF69B4, indianred = 0xCD5C5C,
+ indigo = 0x4B0082, ivory = 0xFFFFF0, khaki = 0xF0E68C, lavender = 0xE6E6FA,
+ lavenderblush = 0xFFF0F5, lawngreen = 0x7CFC00, lemonchiffon = 0xFFFACD, lightblue = 0xADD8E6,
+ lightcoral = 0xF08080, lightcyan = 0xE0FFFF, lightgoldenrodyellow = 0xFAFAD2, lightgray = 0xD3D3D3,
+ lightgreen = 0x90EE90, lightgrey = 0xD3D3D3, lightpink = 0xFFB6C1, lightsalmon = 0xFFA07A,
+ lightseagreen = 0x20B2AA, lightskyblue = 0x87CEFA, lightslategray = 0x778899, lightslategrey = 0x778899,
+ lightsteelblue = 0xB0C4DE, lightyellow = 0xFFFFE0, lime = 0x00FF00, limegreen = 0x32CD32,
+ linen = 0xFAF0E6, magenta = 0xFF00FF, maroon = 0x800000, mediumaquamarine = 0x66CDAA,
+ mediumblue = 0x0000CD, mediumorchid = 0xBA55D3, mediumpurple = 0x9370DB, mediumseagreen = 0x3CB371,
+ mediumslateblue = 0x7B68EE, mediumspringgreen = 0x00FA9A, mediumturquoise = 0x48D1CC, mediumvioletred = 0xC71585,
+ midnightblue = 0x191970, mintcream = 0xF5FFFA, mistyrose = 0xFFE4E1, moccasin = 0xFFE4B5,
+ navajowhite = 0xFFDEAD, navy = 0x000080, oldlace = 0xFDF5E6, olive = 0x808000,
+ olivedrab = 0x6B8E23, orange = 0xFFA500, orangered = 0xFF4500, orchid = 0xDA70D6,
+ palegoldenrod = 0xEEE8AA, palegreen = 0x98FB98, paleturquoise = 0xAFEEEE, palevioletred = 0xDB7093,
+ papayawhip = 0xFFEFD5, peachpuff = 0xFFDAB9, peru = 0xCD853F, pink = 0xFFC0CB,
+ plum = 0xDDA0DD, powderblue = 0xB0E0E6, purple = 0x800080, red = 0xFF0000,
+ rosybrown = 0xBC8F8F, royalblue = 0x4169E1, saddlebrown = 0x8B4513, salmon = 0xFA8072,
+ sandybrown = 0xF4A460, seagreen = 0x2E8B57, seashell = 0xFFF5EE, sienna = 0xA0522D,
+ silver = 0xC0C0C0, skyblue = 0x87CEEB, slateblue = 0x6A5ACD, slategray = 0x708090,
+ slategrey = 0x708090, snow = 0xFFFAFA, springgreen = 0x00FF7F, steelblue = 0x4682B4,
+ tan = 0xD2B48C, teal = 0x008080, thistle = 0xD8BFD8, tomato = 0xFF6347,
+ turquoise = 0x40E0D0, violet = 0xEE82EE, wheat = 0xF5DEB3, white = 0xFFFFFF,
+ whitesmoke = 0xF5F5F5, yellow = 0xFFFF00, yellowgreen = 0x9ACD32,
+ }
-local function rgbacolor(s)
- local r, g, b, a = lpegmatch(p_rgbacolor,s)
- if a then
- return f_rgba(r/255,g/255,b/255,a)
- end
-end
+ local f_rgb = formatters['withcolor svgcolor(%N,%N,%N)']
+ local f_gray = formatters['withcolor svggray(%N)']
+ local f_rgba = formatters['withcolor svgcolor(%N,%N,%N) withtransparency (1,%N)']
+ local f_graya = formatters['withcolor svggray(%N) withtransparency (1,%N)']
+ local f_name = formatters['withcolor "%s"']
+ local f_svgcolor = formatters['svgcolor(%N,%N,%N)']
+ local f_svggray = formatters['svggray(%N)']
+ local f_svgname = formatters['"%s"']
+
+ local triplets = setmetatableindex(function(t,k)
+ -- we delay building all these strings
+ local v = svgcolors[k]
+ if v then
+ v = { extract(v,16,8)/255, extract(v,8,8)/255, extract(v,0,8)/255 }
+ else
+ v = false
+ end
+ t[k] = v
+ return v
+ end)
-local function viewbox(v)
- local x, y, w, h = lpegmatch(p_four,v)
- if h then
- return x, y, w, h
+ local p_fraction = C(p_number) * C("%")^-1 / function(a,b)
+ a = tonumber(a) return a / (b and 100 or 255)
end
-end
+ local p_hexcolor = P("#") * C(p_hexdigit*p_hexdigit)^1 / function(r,g,b)
+ return r and tonumber(r,16)/255 or nil, g and tonumber(g,16)/255 or nil, b and tonumber(b,16)/255 or nil
+ end
+ local p_rgbacolor = P("rgb") * (P("a")^-1) * P("(") * (p_fraction + p_separator)^1 * P(")")
--- actually we can loop faster because we can go to the last one
+ rgbcomponents = function(color)
+ local h = lpegmatch(p_hexcolor,color)
+ if h then
+ return h
+ end
+ local r, g, b, a = lpegmatch(p_rgbacolor,color)
+ if r then
+ return r, g or r, b or r
+ end
+ local t = triplets[color]
+ return t[1], t[2], t[3]
-local function grabpath(str)
- local p = lpegmatch(p_path,str)
- local np = #p
- local t = { } -- no real saving here if we share
- local n = 0
- local all = { entries = np, closed = false, curve = false }
- local a = 0
- local i = 0
- local last = "M"
- local prev = last
- local kind = "L"
- local x = 0
- local y = 0
- local x1 = 0
- local y1 = 0
- local x2 = 0
- local y2 = 0
- local rx = 0
- local ry = 0
- local ar = 0
- local al = 0
- local as = 0
- local ac = nil
- while i < np do
- i = i + 1
- local pi = p[i]
- if type(pi) ~= "number" then
- last = pi
- i = i + 1
- pi = p[i]
- end
- -- most often
- ::restart::
- if last == "c" then
- x1 = x + pi
- i = i + 1 ; y1 = y + p[i]
- i = i + 1 ; x2 = x + p[i]
- i = i + 1 ; y2 = y + p[i]
- i = i + 1 ; x = x + p[i]
- i = i + 1 ; y = y + p[i]
- goto curveto
- elseif last == "l" then
- x = x + pi
- i = i + 1 ; y = y + p[i]
- goto lineto
- elseif last == "h" then
- x = x + pi
- goto lineto
- elseif last == "v" then
- y = y + pi
- goto lineto
- elseif last == "a" then
- x1 = x
- y1 = y
- rx = pi
- i = i + 1 ; ry = p[i]
- i = i + 1 ; ar = p[i]
- i = i + 1 ; al = p[i]
- i = i + 1 ; as = p[i]
- i = i + 1 ; x = x + p[i]
- i = i + 1 ; y = y + p[i]
- goto arc
- elseif last == "s" then
- if prev == "C" then
- x1 = 2 * x - x2
- y1 = 2 * y - y2
+ end
+
+ withcolor = function(color)
+ local r, g, b = lpegmatch(p_hexcolor,color)
+ if b and not (r == g and g == b) then
+ return f_rgb(r,g,b)
+ elseif r then
+ return f_gray(r)
+ end
+ local r, g, b, a = lpegmatch(p_rgbacolor,color)
+ if a then
+ if a == 1 then
+ if r == g and g == b then
+ return f_gray(r)
+ else
+ return f_rgb(r,g,b)
+ end
else
- x1 = x
- y1 = y
- end
- x2 = x + pi
- i = i + 1 ; y2 = y + p[i]
- i = i + 1 ; x = x + p[i]
- i = i + 1 ; y = y + p[i]
- goto curveto
- elseif last == "m" then
- if n > 0 then
- a = a + 1
- all[a] = concat(t,"",1,n)
- n = 0
- end
- x = x + pi
- i = i + 1 ; y = y + p[i]
- goto moveto
- elseif last == "z" then
- goto close
- -- less frequent
- elseif last == "C" then
- x1 = pi
- i = i + 1 ; y1 = p[i]
- i = i + 1 ; x2 = p[i]
- i = i + 1 ; y2 = p[i]
- i = i + 1 ; x = p[i]
- i = i + 1 ; y = p[i]
- goto curveto
- elseif last == "L" then
- x = pi
- i = i + 1 ; y = p[i]
- goto lineto
- elseif last == "H" then
- x = pi
- goto lineto
- elseif last == "V" then
- y = pi
- goto lineto
- elseif last == "A" then
- x1 = x
- y1 = y
- rx = pi
- i = i + 1 ; ry = p[i]
- i = i + 1 ; ar = p[i]
- i = i + 1 ; al = p[i]
- i = i + 1 ; as = p[i]
- i = i + 1 ; x = p[i]
- i = i + 1 ; y = p[i]
- goto arc
- elseif last == "S" then
- if prev == "C" then
- x1 = 2 * x - x2
- y1 = 2 * y - y2
+ if r == g and g == b then
+ return f_graya(r,a)
+ else
+ return f_rgba(r,g,b,a)
+ end
+ end
+ end
+ if not r then
+ local t = triplets[color]
+ if t then
+ r, g, b = t[1], t[2], t[3]
+ end
+ end
+ if r then
+ if r == g and g == b then
+ return f_gray(r)
+ elseif g and b then
+ return f_rgb(r,g,b)
else
- x1 = x
- y1 = y
- end
- x2 = pi
- i = i + 1 ; y2 = p[i]
- i = i + 1 ; x = p[i]
- i = i + 1 ; y = p[i]
- goto curveto
- elseif last == "M" then
- if n > 0 then
- a = a + 1 ; all[a] = concat(t,"",1,n) ; n = 0
- end
- x = pi ;
- i = i + 1 ; y = p[i]
- goto moveto
- elseif last == "Z" then
- goto close
- -- very seldom
- elseif last == "q" then
- x1 = x + pi
- i = i + 1 ; y1 = y + p[i]
- i = i + 1 ; x2 = x + p[i]
- i = i + 1 ; y2 = y + p[i]
- goto quadratic
- elseif last == "t" then
- if prev == "C" then
- x1 = 2 * x - x1
- y1 = 2 * y - y1
+ return f_gray(r)
+ end
+ end
+ return f_name(color)
+ end
+
+ thecolor = function(color)
+ local h = lpegmatch(p_hexcolor,color)
+ if h then
+ return h
+ end
+ local r, g, b, a = lpegmatch(p_rgbacolor,color)
+ if not r then
+ local t = triplets[color]
+ if t then
+ r, g, b = t[1], t[2], t[3]
+ end
+ end
+ if r then
+ if r == g and g == b then
+ return f_svggray(r)
+ elseif g and b then
+ return f_svgcolor(r,g,b)
else
- x1 = x
- y1 = y
- end
- x2 = x + pi
- i = i + 1 ; y2 = y + p[i]
- goto quadratic
- elseif last == "Q" then
- x1 = pi
- i = i + 1 ; y1 = p[i]
- i = i + 1 ; x2 = p[i]
- i = i + 1 ; y2 = p[i]
- goto quadratic
- elseif last == "T" then
- if prev == "C" then
- x1 = 2 * x - x1
- y1 = 2 * y - y1
+ return f_svggray(r)
+ end
+ end
+ return f_svgname(color)
+ end
+
+end
+
+-- actually we can loop faster because we can go to the last one
+
+local grabpath, grablist do
+
+ local f_moveto = formatters['(%N,%n)']
+ local f_curveto_z = formatters['controls(%N,%N)and(%N,%N)..(%N,%N)']
+ local f_curveto_n = formatters['..controls(%N,%N)and(%N,%N)..(%N,%N)']
+ local f_lineto_z = formatters['(%N,%N)']
+ local f_lineto_n = formatters['--(%N,%N)']
+
+ local m = { __index = function() return 0 end }
+
+ grabpath = function(str)
+ local p = lpegmatch(p_path,str) or { }
+ local np = #p
+ local all = { entries = np, closed = false, curve = false }
+ if np == 0 then
+ return all
+ end
+ setmetatable(p,m)
+ local t = { } -- no real saving here if we share
+ local n = 0
+ local a = 0
+ local i = 0
+ local last = "M"
+ local prev = last
+ local kind = "L"
+ local x, y = 0, 0
+ local x1, y1 = 0, 0
+ local x2, y2 = 0, 0
+ local rx, ry = 0, 0
+ local ar, al = 0, 0
+ local as, ac = 0, nil
+ local mx, my = 0, 0
+ while i < np do
+ i = i + 1
+ local pi = p[i]
+ if type(pi) ~= "number" then
+ last = pi
+ i = i + 1
+ pi = p[i]
+ end
+ -- most often
+ if last == "c" then
+ x1 = x + pi
+ i = i + 1 ; y1 = y + p[i]
+ i = i + 1 ; x2 = x + p[i]
+ i = i + 1 ; y2 = y + p[i]
+ i = i + 1 ; x = x + p[i]
+ i = i + 1 ; y = y + p[i]
+ goto curveto
+ elseif last == "l" then
+ x = x + pi
+ i = i + 1 ; y = y + p[i]
+ goto lineto
+ elseif last == "h" then
+ x = x + pi
+ goto lineto
+ elseif last == "v" then
+ y = y + pi
+ goto lineto
+ elseif last == "a" then
+ x1 = x
+ y1 = y
+ rx = pi
+ i = i + 1 ; ry = p[i]
+ i = i + 1 ; ar = p[i]
+ i = i + 1 ; al = p[i]
+ i = i + 1 ; as = p[i]
+ i = i + 1 ; x = x + p[i]
+ i = i + 1 ; y = y + p[i]
+ goto arc
+ elseif last == "s" then
+ if prev == "C" then
+ x1 = 2 * x - x2
+ y1 = 2 * y - y2
+ else
+ x1 = x
+ y1 = y
+ end
+ x2 = x + pi
+ i = i + 1 ; y2 = y + p[i]
+ i = i + 1 ; x = x + p[i]
+ i = i + 1 ; y = y + p[i]
+ goto curveto
+ elseif last == "m" then
+ if n > 0 then
+ a = a + 1 ; all[a] = concat(t,"",1,n) ; n = 0
+ end
+ x = x + pi
+ i = i + 1 ; y = y + p[i]
+ goto moveto
+ elseif last == "z" then
+ goto close
+ -- less frequent
+ elseif last == "C" then
+ x1 = pi
+ i = i + 1 ; y1 = p[i]
+ i = i + 1 ; x2 = p[i]
+ i = i + 1 ; y2 = p[i]
+ i = i + 1 ; x = p[i]
+ i = i + 1 ; y = p[i]
+ goto curveto
+ elseif last == "L" then
+ x = pi
+ i = i + 1 ; y = p[i]
+ goto lineto
+ elseif last == "H" then
+ x = pi
+ goto lineto
+ elseif last == "V" then
+ y = pi
+ goto lineto
+ elseif last == "A" then
+ x1 = x
+ y1 = y
+ rx = pi
+ i = i + 1 ; ry = p[i]
+ i = i + 1 ; ar = p[i]
+ i = i + 1 ; al = p[i]
+ i = i + 1 ; as = p[i]
+ i = i + 1 ; x = p[i]
+ i = i + 1 ; y = p[i]
+ goto arc
+ elseif last == "S" then
+ if prev == "C" then
+ x1 = 2 * x - x2
+ y1 = 2 * y - y2
+ else
+ x1 = x
+ y1 = y
+ end
+ x2 = pi
+ i = i + 1 ; y2 = p[i]
+ i = i + 1 ; x = p[i]
+ i = i + 1 ; y = p[i]
+ goto curveto
+ elseif last == "M" then
+ if n > 0 then
+ a = a + 1 ; all[a] = concat(t,"",1,n) ; n = 0
+ end
+ x = pi ;
+ i = i + 1 ; y = p[i]
+ goto moveto
+ elseif last == "Z" then
+ goto close
+ -- very seldom
+ elseif last == "q" then
+ x1 = x + pi
+ i = i + 1 ; y1 = y + p[i]
+ i = i + 1 ; x2 = x + p[i]
+ i = i + 1 ; y2 = y + p[i]
+ goto quadratic
+ elseif last == "t" then
+ if prev == "C" then
+ x1 = 2 * x - x1
+ y1 = 2 * y - y1
+ else
+ x1 = x
+ y1 = y
+ end
+ x2 = x + pi
+ i = i + 1 ; y2 = y + p[i]
+ goto quadratic
+ elseif last == "Q" then
+ x1 = pi
+ i = i + 1 ; y1 = p[i]
+ i = i + 1 ; x2 = p[i]
+ i = i + 1 ; y2 = p[i]
+ goto quadratic
+ elseif last == "T" then
+ if prev == "C" then
+ x1 = 2 * x - x1
+ y1 = 2 * y - y1
+ else
+ x1 = x
+ y1 = y
+ end
+ x2 = pi
+ i = i + 1 ; y2 = p[i]
+ goto quadratic
else
- x1 = x
- y1 = y
+ goto continue
end
- x2 = pi
- i = i + 1 ; y2 = p[i]
- goto quadratic
- else
- goto continue
- end
- ::moveto::
- n = n + 1 ; t[n] = f_moveto(x,y)
- last = last == "M" and "L" or "l"
- prev = "M"
- goto continue
- ::lineto::
- n = n + 1 ; t[n] = (n > 0 and f_lineto_n or f_lineto_z)(x,y)
- prev = "L"
- goto continue
- ::curveto::
- n = n + 1 ; t[n] = (n > 0 and f_curveto_n or f_curveto_z)(x1,y1,x2,y2,x,y)
- prev = "C"
- goto continue
- ::arc::
- ac = a2c(x1,y1,rx,ry,ar,al,as,x,y)
- for i=1,#ac,6 do
+ ::moveto::
+ n = n + 1 ; t[n] = f_moveto(x,y)
+ last = last == "M" and "L" or "l"
+ prev = "M"
+ mx = x
+ my = y
+ goto continue
+ ::lineto::
+ n = n + 1 ; t[n] = (n > 0 and f_lineto_n or f_lineto_z)(x,y)
+ prev = "L"
+ goto continue
+ ::curveto::
+ n = n + 1 ; t[n] = (n > 0 and f_curveto_n or f_curveto_z)(x1,y1,x2,y2,x,y)
+ prev = "C"
+ goto continue
+ ::arc::
+ ac = a2c(x1,y1,rx,ry,ar,al,as,x,y)
+ for i=1,#ac,6 do
+ n = n + 1 ; t[n] = (n > 0 and f_curveto_n or f_curveto_z)(
+ ac[i],ac[i+1],ac[i+2],ac[i+3],ac[i+4],ac[i+5]
+ )
+ end
+ prev = "A"
+ goto continue
+ ::quadratic::
n = n + 1 ; t[n] = (n > 0 and f_curveto_n or f_curveto_z)(
- ac[i],ac[i+1],ac[i+2],ac[i+3],ac[i+4],ac[i+5]
+ x + 2/3 * (x1-x ), y + 2/3 * (y1-y ),
+ x2 + 2/3 * (x1-x2), y2 + 2/3 * (y1-y2),
+ x2, y2
)
+ x = x2
+ y = y2
+ prev = "C"
+ goto continue
+ ::close::
+ -- n = n + 1 ; t[n] = prev == "C" and "..cycle" or "--cycle"
+ n = n + 1 ; t[n] = "--cycle"
+ if n > 0 then
+ a = a + 1 ; all[a] = concat(t,"",1,n) ; n = 0
+ end
+ if i == np then
+ break
+ else
+ i = i - 1
+ end
+ kind = prev
+ prev = "Z"
+ -- this is kind of undocumented: a close also moves back
+ x = mx
+ y = my
+ ::continue::
+ end
+ if n > 0 then
+ a = a + 1 ; all[a] = concat(t,"",1,n) ; n = 0
+ end
+ if prev == "Z" then
+ all.closed = true
+ end
+ all.curve = (kind == "C" or kind == "A")
+ return all, p
+ end
+
+ -- this is a bit tricky as what are points for a mark ... the next can be simplified
+ -- a lot
+
+ grablist = function(p)
+ local np = #p
+ if np == 0 then
+ return nil
+ end
+ local t = { }
+ local n = 0
+ local a = 0
+ local i = 0
+ local last = "M"
+ local prev = last
+ local kind = "L"
+ local x, y = 0, 0
+ local x1, y1 = 0, 0
+ local x2, y2 = 0, 0
+ local rx, ry = 0, 0
+ local ar, al = 0, 0
+ local as, ac = 0, nil
+ local mx, my = 0, 0
+ while i < np do
+ i = i + 1
+ local pi = p[i]
+ if type(pi) ~= "number" then
+ last = pi
+ i = i + 1
+ pi = p[i]
end
- prev = "A"
- goto continue
- ::quadratic::
- n = n + 1 ; t[n] = (n > 0 and f_curveto_n or f_curveto_z)(
- x + 2/3 * (x1-x ), y + 2/3 * (y1-y ),
- x2 + 2/3 * (x1-x2), y2 + 2/3 * (y1-y2),
- x2, y2
- )
- x = x2
- y = y2
- prev = "C"
- goto continue
- ::close::
- -- n = n + 1 ; t[n] = prev == "C" and "..cycle" or "--cycle"
- n = n + 1 ; t[n] = "--cycle"
- if n > 0 then
- a = a + 1 ; all[a] = concat(t,"",1,n) ; n = 0
- end
- if i == n then
- break
+ -- most often
+ if last == "c" then
+ x1 = x + pi
+ i = i + 1 ; y1 = y + p[i]
+ i = i + 1 ; x2 = x + p[i]
+ i = i + 1 ; y2 = y + p[i]
+ i = i + 1 ; x = x + p[i]
+ i = i + 1 ; y = y + p[i]
+ goto curveto
+ elseif last == "l" then
+ x = x + pi
+ i = i + 1 ; y = y + p[i]
+ goto lineto
+ elseif last == "h" then
+ x = x + pi
+ goto lineto
+ elseif last == "v" then
+ y = y + pi
+ goto lineto
+ elseif last == "a" then
+ x1 = x
+ y1 = y
+ rx = pi
+ i = i + 1 ; ry = p[i]
+ i = i + 1 ; ar = p[i]
+ i = i + 1 ; al = p[i]
+ i = i + 1 ; as = p[i]
+ i = i + 1 ; x = x + p[i]
+ i = i + 1 ; y = y + p[i]
+ goto arc
+ elseif last == "s" then
+ if prev == "C" then
+ x1 = 2 * x - x2
+ y1 = 2 * y - y2
+ else
+ x1 = x
+ y1 = y
+ end
+ x2 = x + pi
+ i = i + 1 ; y2 = y + p[i]
+ i = i + 1 ; x = x + p[i]
+ i = i + 1 ; y = y + p[i]
+ goto curveto
+ elseif last == "m" then
+ x = x + pi
+ i = i + 1 ; y = y + p[i]
+ goto moveto
+ elseif last == "z" then
+ goto close
+ -- less frequent
+ elseif last == "C" then
+ x1 = pi
+ i = i + 1 ; y1 = p[i]
+ i = i + 1 ; x2 = p[i]
+ i = i + 1 ; y2 = p[i]
+ i = i + 1 ; x = p[i]
+ i = i + 1 ; y = p[i]
+ goto curveto
+ elseif last == "L" then
+ x = pi
+ i = i + 1 ; y = p[i]
+ goto lineto
+ elseif last == "H" then
+ x = pi
+ goto lineto
+ elseif last == "V" then
+ y = pi
+ goto lineto
+ elseif last == "A" then
+ x1 = x
+ y1 = y
+ rx = pi
+ i = i + 1 ; ry = p[i]
+ i = i + 1 ; ar = p[i]
+ i = i + 1 ; al = p[i]
+ i = i + 1 ; as = p[i]
+ i = i + 1 ; x = p[i]
+ i = i + 1 ; y = p[i]
+ goto arc
+ elseif last == "S" then
+ if prev == "C" then
+ x1 = 2 * x - x2
+ y1 = 2 * y - y2
+ else
+ x1 = x
+ y1 = y
+ end
+ x2 = pi
+ i = i + 1 ; y2 = p[i]
+ i = i + 1 ; x = p[i]
+ i = i + 1 ; y = p[i]
+ goto curveto
+ elseif last == "M" then
+ x = pi ;
+ i = i + 1 ; y = p[i]
+ goto moveto
+ elseif last == "Z" then
+ goto close
+ -- very seldom
+ elseif last == "q" then
+ x1 = x + pi
+ i = i + 1 ; y1 = y + p[i]
+ i = i + 1 ; x2 = x + p[i]
+ i = i + 1 ; y2 = y + p[i]
+ goto quadratic
+ elseif last == "t" then
+ if prev == "C" then
+ x1 = 2 * x - x1
+ y1 = 2 * y - y1
+ else
+ x1 = x
+ y1 = y
+ end
+ x2 = x + pi
+ i = i + 1 ; y2 = y + p[i]
+ goto quadratic
+ elseif last == "Q" then
+ x1 = pi
+ i = i + 1 ; y1 = p[i]
+ i = i + 1 ; x2 = p[i]
+ i = i + 1 ; y2 = p[i]
+ goto quadratic
+ elseif last == "T" then
+ if prev == "C" then
+ x1 = 2 * x - x1
+ y1 = 2 * y - y1
+ else
+ x1 = x
+ y1 = y
+ end
+ x2 = pi
+ i = i + 1 ; y2 = p[i]
+ goto quadratic
else
- i = i - 1
+ goto continue
end
- kind = prev
- prev = "Z"
- ::continue::
- end
- if n > 0 then
- a = a + 1 ; all[a] = concat(t,"",1,n) ; n = 0
- end
- if prev == "Z" then
- all.closed = true
+ ::moveto::
+ n = n + 1 ; t[n] = x
+ n = n + 1 ; t[n] = y
+ last = last == "M" and "L" or "l"
+ prev = "M"
+ mx = x
+ my = y
+ goto continue
+ ::lineto::
+ n = n + 1 ; t[n] = x
+ n = n + 1 ; t[n] = y
+ prev = "L"
+ goto continue
+ ::curveto::
+ n = n + 1 ; t[n] = x
+ n = n + 1 ; t[n] = y
+ prev = "C"
+ goto continue
+ ::arc::
+ ac = a2c(x1,y1,rx,ry,ar,al,as,x,y)
+ for i=1,#ac,6 do
+ n = n + 1 ; t[n] = ac[i+4]
+ n = n + 1 ; t[n] = ac[i+5]
+ end
+ prev = "A"
+ goto continue
+ ::quadratic::
+ n = n + 1 ; t[n] = x2
+ n = n + 1 ; t[n] = y2
+ x = x2
+ y = y2
+ prev = "C"
+ goto continue
+ ::close::
+ n = n + 1 ; t[n] = mx
+ n = n + 1 ; t[n] = my
+ if i == np then
+ break
+ end
+ kind = prev
+ prev = "Z"
+ x = mx
+ y = my
+ ::continue::
+ end
+ return t
end
- all.curve = (kind == "C" or kind == "A")
- return all
+
end
-local transform do
+-- todo: viewbox helper
+
+local s_wrapped_start = "draw image ("
+local f_wrapped_stop = formatters[") shifted (0,%N) scaled %N ;"]
+
+local handletransform, handleviewbox do
--todo: better lpeg
- local n = 0
+ local f_rotatedaround = formatters[" rotatedaround((%N,%N),%N)"]
+ local f_rotated = formatters[" rotated(%N)"]
+ local f_shifted = formatters[" shifted(%N,%N)"]
+ local f_slanted_x = formatters[" xslanted(%N)"]
+ local f_slanted_y = formatters[" yslanted(%N)"]
+ local f_scaled = formatters[" scaled(%N)"]
+ local f_xyscaled = formatters[" xyscaled(%N,%N)"]
+ local f_matrix = formatters[" transformed bymatrix(%N,%N,%N,%N,%N,%N)"]
+
+ local s_transform_start = "draw image ( "
+ local f_transform_stop = formatters[")%s ;"]
local function rotate(r,x,y)
if x then
- n = n + 1
return r and f_rotatedaround(x,-(y or x),-r)
elseif r then
- n = n + 1
return f_rotated(-r)
else
return ""
@@ -852,10 +997,8 @@ local transform do
local function translate(x,y)
if y then
- n = n + 1
return f_shifted(x,-y)
elseif x then
- n = n + 1
return f_shifted(x,0)
else
return ""
@@ -864,10 +1007,8 @@ local transform do
local function scale(x,y)
if y then
- n = n + 1
return f_xyscaled(x,y)
elseif x then
- n = n + 1
return f_scaled(x)
else
return ""
@@ -876,7 +1017,6 @@ local transform do
local function skewx(x)
if x then
- n = n + 1
return f_slanted_x(math.sind(-x))
else
return ""
@@ -885,7 +1025,6 @@ local transform do
local function skewy(y)
if y then
- n = n + 1
return f_slanted_y(math.sind(-y))
else
return ""
@@ -893,7 +1032,6 @@ local transform do
end
local function matrix(rx,sx,sy,ry,tx,ty)
- n = n + 1
return f_matrix(rx or 1, sx or 0, sy or 0, ry or 1, tx or 0, - (ty or 0))
end
@@ -910,14 +1048,20 @@ local transform do
+ P(1)/""
)^1)
- transform = function(t,image)
- n = 0
- local e = lpegmatch(p_transform,t)
- local b = rep("( ",n)
- if image then
- return f_transform_start(b), f_transform_stop(e)
- else
- return b, e
+ 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
+ end
+ end
+
+ handleviewbox = function(v)
+ if v then
+ local x, y, w, h = lpegmatch(p_fournumbers,v)
+ if h then
+ return x, y, w, h
+ end
end
end
@@ -927,10 +1071,13 @@ local dashed do
-- actually commas are mandate but we're tolerant
- local p_number = p_separator^0/"" * p_number_r
- local p_on = Cc(" on ") * p_number
- local p_off = Cc(" off ") * p_number
- local p_dashed = Cs((p_on * p_off^-1)^1)
+ local f_dashed_n = formatters[" dashed dashpattern (%s ) "]
+ local f_dashed_y = formatters[" dashed dashpattern (%s ) shifted (%N,0) "]
+
+ local p_number = p_optseparator/"" * p_number_r
+ local p_on = Cc(" on ") * p_number
+ local p_off = Cc(" off ") * p_number
+ local p_dashed = Cs((p_on * p_off^-1)^1)
dashed = function(s,o)
if not find(s,",") then
@@ -944,108 +1091,274 @@ end
do
- local defaults = {
- x = 0, x1 = 0, x2 = 0, cx = 0, rx = 0,
- y = 0, y1 = 0, y2 = 0, cy = 0, ry = 0,
- r = 0,
-
- width = 0,
- height = 0,
-
- stroke = "none",
- fill = "black",
- opacity = "none",
-
- ["stroke-width"] = 1,
- ["stroke-linecap"] = "none",
- ["stroke-linejoin"] = "none",
- ["stroke-dasharray"] = "none",
- ["stroke-dashoffset"] = "none",
- ["stroke-miterlimit"] = "none",
- ["stroke-opacity"] = "none",
-
- ["fill-opacity"] = "none",
- -- ["fill-rule"] = "nonzero",
- -- ["clip-rule"] = "nonzero",
- }
-
local handlers = { }
local process = false
local root = false
local result = false
local r = false
local definitions = false
- local styles = false
- local bodyfont = false
+ local classstyles = false
+ local tagstyles = false
+
+ local tags = {
+ ["a"] = true,
+ -- ["altgGlyph"] = true,
+ -- ["altgGlyphDef"] = true,
+ -- ["altgGlyphItem"] = true,
+ -- ["animate"] = true,
+ -- ["animateColor"] = true,
+ -- ["animateMotion"] = true,
+ -- ["animateTransform"] = true,
+ ["circle"] = true,
+ ["clipPath"] = true,
+ -- ["color-profile"] = true,
+ -- ["cursor"] = true,
+ ["defs"] = true,
+ -- ["desc"] = true,
+ ["ellipse"] = true,
+ -- ["filter"] = true,
+ -- ["font"] = true,
+ -- ["font-face"] = true,
+ -- ["font-face-format"] = true,
+ -- ["font-face-name"] = true,
+ -- ["font-face-src"] = true,
+ -- ["font-face-uri"] = true,
+ -- ["foreignObject"] = true,
+ ["g"] = true,
+ -- ["glyph"] = true,
+ -- ["glyphRef"] = true,
+ -- ["hkern"] = true,
+ ["image"] = true,
+ ["line"] = true,
+ ["linearGradient"] = true,
+ ["marker"] = true,
+ -- ["mask"] = true,
+ -- ["metadata"] = true,
+ -- ["missing-glyph"] = true,
+ -- ["mpath"] = true,
+ ["path"] = true,
+ -- ["pattern"] = true,
+ ["polygon"] = true,
+ ["polyline"] = true,
+ ["radialGradient"] = true,
+ ["rect"] = true,
+ -- ["script"] = true,
+ -- ["set"] = true,
+ ["stop"] = true,
+ ["style"] = true,
+ ["svg"] = true,
+ -- ["switch"] = true,
+ ["symbol"] = true,
+ ["text"] = true,
+ -- ["textPath"] = true,
+ -- ["title"] = true,
+ ["tspan"] = true,
+ ["use"] = true,
+ -- ["view"] = true,
+ -- ["vkern"] = true,
+ }
- -- todo: check use ... and make definitions[id] self resolving
+ local function handlechains(c)
+ if tags[c.tg] then
+ local at = c.at
+ local dt = c.dt
+ if at and dt then
+ -- at["inkscape:connector-curvature"] = nil -- cleare entry and might prevent table growth
+ local estyle = rawget(at,"style")
+ if estyle and estyle ~= "" then
+ for k, v in gmatch(estyle,"%s*([^:]+):%s*([^;]+);?") do
+ at[k] = v
+ end
+ end
+ local eclass = rawget(at,"class")
+ if eclass and eclass ~= "" then
+ for c in gmatch(eclass,"[^ ]+") do
+ local s = classstyles[c]
+ if s then
+ for k, v in next, s do
+ at[k] = v
+ end
+ end
+ end
+ end
+ local tstyle = tagstyles[tag]
+ if tstyle then
+ for k, v in next, tstyle do
+ at[k] = v
+ end
+ end
+ if trace_path and pathtracer then
+ for k, v in next, pathtracer do
+ at[k] = v
+ end
+ end
+ for i=1,#dt do
+ local dti = dt[i]
+ if type(dti) == "table" then
+ handlechains(dti)
+ end
+ end
+ end
+ end
+ end
+
+ local handlestyle do
+
+ -- It can also be CDATA but that is probably dealt with because we only
+ -- check for style entries and ignore the rest. But maybe we also need
+ -- to check a style at the outer level?
+
+ local p_key = C((R("az","AZ","09","__","--")^1))
+ local p_spec = P("{") * C((1-P("}"))^1) * P("}")
+ local p_valid = Carg(1) * P(".") * p_key + Carg(2) * p_key
+ local p_grab = ((p_valid * p_space^0 * p_spec / rawset) + p_space^1 + P(1))^1
+
+ local fontspecification = css.fontspecification
+
+ handlestyle = function(c)
+ local s = xmltext(c)
+ lpegmatch(p_grab,s,1,classstyles,tagstyles)
+ for k, v in next, classstyles do
+ local t = { }
+ for k, v in gmatch(v,"%s*([^:]+):%s*([^;]+);?") do
+ if k == "font" then
+ local s = fontspecification(v)
+ for k, v in next, s do
+ t["font-"..k] = v
+ end
+ else
+ t[k] = v
+ end
+ end
+ classstyles[k] = t
+ end
+ for k, v in next, tagstyles do
+ local t = { }
+ for k, v in gmatch(v,"%s*([^:]+):%s*([^;]+);?") do
+ if k == "font" then
+ local s = fontspecification(v)
+ for k, v in next, s do
+ t["font-"..k] = v
+ end
+ else
+ t[k] = v
+ end
+ end
+ tagstyles[k] = t
+ end
+ end
+
+ function handlers.style()
+ -- ignore
+ end
+
+ end
+
+ -- We can have root in definitions and then do a metatable lookup but use
+ -- is not used that often I guess.
local function locate(id)
+ local res = definitions[id]
+ if res then
+ return res
+ end
local ref = gsub(id,"^url%(#(.-)%)$","%1")
local ref = gsub(ref,"^#","")
+ -- we can make a fast id lookup
local res = xmlfirst(root,"**[@id='"..ref.."']")
if res then
definitions[id] = res
- return res
- else
- -- warning
end
+ return res
end
- local function clippath(id,a)
- local spec = definitions[id] or locate(id)
- if spec then
- local kind = spec.tg
- if kind == "clipPath" then
- ::again::
- for c in xmlcollected(spec,"/(path|use|g)") do
- local tg = c.tg
- if tg == "use" then
- local ca = c.at
- local id = ca["xlink:href"]
- if id then
- spec = locate(id)
- if spec then
- local sa = spec.at
- setmetatableindex(sa,ca)
- if spec.tg == "path" then
- local d = sa.d
- if d then
- local p = grabpath(d)
- p.evenodd = sa["clip-rule"] == "evenodd" or a["clip-rule"] == "evenodd"
- return p
- else
- goto done
- end
- else
- goto again
- end
+ -- also locate
+
+ local function handleclippath(at)
+ local clippath = at["clip-path"]
+
+ if not clippath then
+ return
+ end
+
+ local spec = definitions[clippath] or locate(clippath)
+
+ -- do we really need thsi crap
+ if not spec then
+ local index = match(clippath,"(%d+)")
+ if index then
+ spec = xmlfirst(root,"clipPath["..tostring(tonumber(index) or 0).."]")
+ end
+ end
+ -- so far for the crap
+
+ if not spec then
+ report("unknown clip %a",clippath)
+ return
+ elseif spec.tg ~= "clipPath" then
+ report("bad clip %a",clippath)
+ return
+ end
+
+ ::again::
+ for c in xmlcollected(spec,"/(path|use|g)") do
+ local tg = c.tg
+ if tg == "use" then
+ local ca = c.at
+ local id = ca["xlink:href"]
+ if id then
+ spec = locate(id)
+ if spec then
+ local sa = spec.at
+ setmetatableindex(sa,ca)
+ if spec.tg == "path" then
+ local d = sa.d
+ if d then
+ local p = grabpath(d)
+ p.evenodd = sa["clip-rule"] == "evenodd"
+ p.close = true
+ return p, clippath
+ else
+ return
end
- end
- -- break
- elseif tg == "path" then
- local ca = c.at
- local d = ca.d
- if d then
- local p = grabpath(d)
- p.evenodd = ca["clip-rule"] == "evenodd" or a["clip-rule"] == "evenodd"
- return p
else
- goto done
+ goto again
end
- else
- -- inherit?
end
end
- ::done::
+ -- break
+ elseif tg == "path" then
+ local ca = c.at
+ local d = ca.d
+ if d then
+ local p = grabpath(d)
+ p.evenodd = ca["clip-rule"] == "evenodd"
+ p.close = true
+ return p, clippath
+ else
+ return
+ end
else
- report("unknown clip %a",id)
+ -- inherit?
end
end
end
+ local s_shade_linear = ' withshademethod "linear" '
+ local s_shade_circular = ' withshademethod "circular" '
+ local f_shade_step = formatters['withshadestep ( withshadefraction %N withshadecolors(%s,%s) )']
+ local f_shade_one = formatters['withprescript "sh_center_a=%N %N"']
+ local f_shade_two = formatters['withprescript "sh_center_b=%N %N"']
+
+ local f_color = formatters['withcolor "%s"']
+ local f_opacity = formatters['withtransparency (1,%N)']
+ local f_pen = formatters['withpen pencircle scaled %N']
+
+ -- todo: gradient unfinished
+ -- todo: opacity but first we need groups in mp
+
local function gradient(id)
- local spec = definitions[id]
+ local spec = definitions[id] -- no locate !
if spec then
local kind = spec.tg
local shade = nil
@@ -1054,25 +1367,25 @@ do
if kind == "linearGradient" then
shade = { s_shade_linear }
--
- local x1 = a.x1
- local y1 = a.y1
- local x2 = a.x2
- local y2 = a.y2
+ local x1 = rawget(a,"x1")
+ local y1 = rawget(a,"y1")
+ local x2 = rawget(a,"x2")
+ local y2 = rawget(a,"y2")
if x1 and y1 then
- n = n + 1 shade[n] = f_shade_one(asnumber_vx(x1),asnumber_vy(y1))
+ n = n + 1 ; shade[n] = f_shade_one(asnumber_vx(x1),asnumber_vy(y1))
end
if x2 and y2 then
- n = n + 1 shade[n] = f_shade_one(asnumber_vx(x2),asnumber_vy(y2))
+ n = n + 1 ; shade[n] = f_shade_one(asnumber_vx(x2),asnumber_vy(y2))
end
--
elseif kind == "radialGradient" then
shade = { s_shade_circular }
--
- local cx = a.cx -- x center
- local cy = a.cy -- y center
- local r = a.r -- radius
- local fx = a.fx -- focal points
- local fy = a.fy -- focal points
+ local cx = rawget(a,"cx") -- x center
+ local cy = rawget(a,"cy") -- y center
+ local r = rawget(a,"r" ) -- radius
+ local fx = rawget(a,"fx") -- focal points
+ local fy = rawget(a,"fy") -- focal points
--
if cx and cy then
-- todo
@@ -1091,566 +1404,1328 @@ do
-- local gt = a.gradientTransform
-- local sm = a.spreadMethod
local colora, colorb
+ -- startcolor ?
for c in xmlcollected(spec,"/stop") do
local a = c.at
- local offset = a.offset
- local colorb = a["stop-color"]
- local opacity = a["stop-opacity"]
-
- colorb = colorb and (hexcolor3(colorb) or svgcolor[colorb] or colorb)
- colora = colora or colorb
-
+ local offset = rawget(a,"offset")
+ local colorb = rawget(a,"stop-color")
+ local opacity = rawget(a,"stop-opacity")
+ if colorb then
+ colorb = thecolor(colorb)
+ end
+ if not colora then
+ colora = colorb
+ end
-- what if no percentage
local fraction = offset and asnumber_r(offset)
-
if not fraction then
-- offset = tonumber(offset)
-- for now
fraction = xmlcount(spec,"/stop")/100
end
- n = n + 1 shade[n] = f_shade_step(fraction,colora,colorb)
+ if colora and colorb and color_a ~= "" and color_b ~= "" then
+ n = n + 1 ; shade[n] = f_shade_step(fraction,colora,colorb)
+ end
- prevcolor = color
+ colora = colorb
end
- return concat(shade)
+ return concat(shade," ")
end
end
- local function drawproperties(stroke,a)
- local w = a["stroke-width"]
- if w then
- w = f_pen(asnumber_r(w))
- else
- w = ""
- end
- local d = a["stroke-dasharray"]
- if d ~= "none" then
- local o = a["stroke-dashoffset"]
- if o ~= "none" then
+ local function drawproperties(stroke,at,opacity)
+ local p = at["stroke-width"]
+ if p then
+ p = f_pen(asnumber_r(p))
+ end
+ local d = at["stroke-dasharray"]
+ if d == "none" then
+ d = nil
+ elseif d then
+ local o = at["stroke-dashoffset"]
+ if o and o ~= "none" then
o = asnumber_r(o)
else
o = false
end
d = dashed(d,o)
- else
- d = ""
- end
- local c = hexcolor(stroke)
- if not c then
- c = rgbacolor(stroke)
- if not c then
- c = f_color(svgcolor[stroke] or stroke)
- end
end
- local o = a["stroke-opacity"] or a.opacity
- if o ~= "none" then
+ local c = withcolor(stroke)
+ local o = at["stroke-opacity"] or (opacity and at["opacity"])
+ if o == "none" then
+ o = nil
+ elseif o then
o = asnumber_r(o)
if o and o ~= 1 then
o = f_opacity(o)
else
- o = ""
+ o = nil
end
- else
- o = ""
end
- return w, d, c, o
+ return p, d, c, o
end
- local function fillproperties(fill,a)
- local c = gradient(fill)
- if not c then
- c = hexcolor(fill)
- if not c then
- c = f_color(svgcolor[fill] or fill)
+ local s_opacity_start = "draw image ("
+ local f_opacity_stop = formatters["setgroup currentpicture to boundingbox currentpicture withtransparency (1,%N)) ;"]
+
+ local function sharedopacity(at)
+ local o = at["opacity"]
+ if o and o ~= "none" then
+ o = asnumber_r(o)
+ if o and o ~= 1 then
+ return s_opacity_start, f_opacity_stop(o)
end
end
- local o = a["fill-opacity"] or a.opacity
- if o == "none" then
+ end
+
+ local function fillproperties(fill,at,opacity)
+ local c = c ~= "none" and (gradient(fill) or withcolor(fill)) or nil
+ local o = at["fill-opacity"] or (opacity and at["opacity"])
+ if o and o ~= "none" then
o = asnumber_r(o)
- if o and o ~= 1 then
- o = f_opacity(asnumber_r(o))
- else
- o = ""
+ if o == 1 then
+ return c
+ elseif o then
+ return c, f_opacity(o), o == 0
end
- else
- o = ""
end
- return c, o
+ return c
end
-- todo: clip = [ auto | rect(llx,lly,urx,ury) ]
- local function offset(a)
- local x = a.x
- local y = a.y
- if x then x = asnumber_vx(x) end
- if y then y = asnumber_vy(y) end
- if not x then x = 0 end
- if not y then y = 0 end
+ local s_offset_start = "draw image ( "
+ local f_offset_stop = formatters[") shifted (%N,%N) ;"]
+ local s_rotation_start = "draw image ( "
+ local f_rotation_stop = formatters[") rotatedaround((0,0),-angle((%N,%N))) ;"]
+ local f_rotation_angle = formatters[") rotatedaround((0,0),-%N) ;"]
+
+ local function offset(at)
+ local x = asnumber_vx(rawget(at,"x"))
+ local y = asnumber_vy(rawget(at,"y"))
if x ~= 0 or y ~= 0 then
- r = r + 1 ; result[r] = s_offset_start
- return function()
- r = r + 1 ; result[r] = f_offset_stop(x,-y)
- end
+ return s_offset_start, f_offset_stop(x,y)
end
end
- local function viewport(x,y,w,h,noclip)
- r = r + 1 ; result[r] = f_viewport_start
+ local s_viewport_start = "draw image ("
+ local s_viewport_stop = ") ;"
+ local f_viewport_shift = formatters["currentpicture := currentpicture shifted (%03N,%03N);"]
+ local f_viewport_scale = formatters["currentpicture := currentpicture xysized (%03N,%03N);"]
+ local f_viewport_clip = formatters["clip currentpicture to (unitsquare xyscaled (%03N,%03N));"]
+
+ local function viewport(x,y,w,h,noclip,scale)
+ r = r + 1 ; result[r] = s_viewport_start
return function()
+ local okay = w ~= 0 and h ~= 0
+ if okay and scale then
+ r = r + 1 ; result[r] = f_viewport_scale(w,h)
+ end
if x ~= 0 or y ~= 0 then
r = r + 1 ; result[r] = f_viewport_shift(-x,y)
end
- if not noclip then
+ if okay and not noclip then
r = r + 1 ; result[r] = f_viewport_clip(w,-h)
end
- r = r + 1 ; result[r] = f_viewport_stop
+
+ r = r + 1 ; result[r] = s_viewport_stop
end
end
- function handlers.defs(c,top)
+ -- maybe forget about defs and just always locate (and then backtrack
+ -- over <g> if needed)
+
+ function handlers.defs(c)
for c in xmlcollected(c,"/*") do
- local a = c.at
- local id = a.id
- -- setmetatableindex(a,top)
- if id then
- definitions["#" .. id ] = c
- definitions["url(#" .. id .. ")"] = c
+ local a = c.at
+ if a then
+ local id = rawget(a,"id")
+ if id then
+ definitions["#" .. id ] = c
+ definitions["url(#" .. id .. ")"] = c
+ end
end
end
end
- function handlers.use(c,top)
- local a = setmetatableindex(c.at,top)
- local id = a["xlink:href"] -- better a rawget
- if id then
- local d = definitions[id]
- if d then
- local h = handlers[d.tg]
- if h then
- h(d,a)
- end
- else
- local res = locate(id)
- if res then
- local wrapup = offset(a)
- process(res,"/*",top)
- if wrapup then
- wrapup()
- end
- else
- report("unknown definition %a",id)
- end
+ function handlers.symbol(c)
+ if uselevel == 0 then
+ local id = rawget(c.at,"id")
+ if id then
+ definitions["#" .. id ] = c
+ definitions["url(#" .. id .. ")"] = c
end
+ else
+ handlers.g(c)
end
end
- local linecaps = { butt = "butt", square = "squared", round = "rounded" }
- local linejoins = { miter = "mitered", bevel = "beveled", round = "rounded" }
+ local uselevel = 0
- local function stoplineproperties()
- r = r + 1 result[r] = s_endgroup
- end
+ function handlers.use(c)
+ local at = c.at
+ local id = rawget(at,"href") or rawget(at,"xlink:href") -- better a rawget
+ local res = locate(id)
+ if res then
+ -- width height ?
+ uselevel = uselevel + 1
+ local boffset, eoffset = offset(at)
+ local btransform, etransform, transform = handletransform(at)
- local function startlineproperties(a)
- local cap = a["stroke-linecap"]
- local join = a["stroke-linejoin"]
- local limit = a["stroke-miterlimit"]
- cap = cap ~= "none" and linecaps [cap] or false
- join = join ~= "none" and linejoins[join] or false
- limit = limit ~= "none" and asnumber_r(limit) or false
- if cap or join or limit then
- r = r + 1 result[r] = s_begingroup
- if cap then
- r = r + 1 result[r] = f_linecap(cap)
+ if boffset then
+ r = r + 1 result[r] = boffset
end
- if join then
- r = r + 1 result[r] = f_linejoin(join)
+
+ -- local clippath = at.clippath
+
+ if btransform then
+ r = r + 1 result[r] = btransform
+ end
+
+ local _transform = transform
+ local _clippath = clippath
+ at["transform"] = false
+ -- at["clip-path"] = false
+
+ process(res,"/*")
+
+ at["transform"] = _transform
+ -- at["clip-path"] = _clippath
+
+ if etransform then
+ r = r + 1 ; result[r] = etransform
end
- if limit then
- r = r + 1 result[r] = f_miterlimit(limit)
+
+ if eoffset then
+ r = r + 1 result[r] = eoffset
end
- return stoplineproperties
+
+ uselevel = uselevel - 1
+ else
+ report("use: unknown definition %a",id)
end
end
- local function flush(a,shape,nofill)
- local fill = not nofill and a.fill
- local stroke = a.stroke
- local cpath = a["clip-path"]
- local trans = a.transform
- local b, e = "", ""
+ local f_no_draw = formatters['nodraw (%s)']
+ local f_do_draw = formatters['draw (%s)']
+ local f_no_fill_c = formatters['nofill (%s..cycle)']
+ local f_do_fill_c = formatters['fill (%s..cycle)']
+ local f_eo_fill_c = formatters['eofill (%s..cycle)']
+ local f_no_fill_l = formatters['nofill (%s--cycle)']
+ local f_do_fill_l = formatters['fill (%s--cycle)']
+ local f_eo_fill_l = formatters['eofill (%s--cycle)']
+ local f_do_fill = f_do_fill_c
+ local f_eo_fill = f_eo_fill_c
+ local f_no_fill = f_no_fill_c
+ local s_clip_start = 'draw image ('
+ local f_clip_stop_c = formatters[') ; clip currentpicture to (%s..cycle) ;']
+ local f_clip_stop_l = formatters[') ; clip currentpicture to (%s--cycle) ;']
+ local f_clip_stop = f_clip_stop_c
+ local f_eoclip_stop_c = formatters[') ; eoclip currentpicture to (%s..cycle) ;']
+ local f_eoclip_stop_l = formatters[') ; eoclip currentpicture to (%s--cycle) ;']
+ local f_eoclip_stop = f_eoclip_stop_c
+
+ -- could be shared and then beginobject | endobject
+
+ local function flushobject(object,at,c,o)
+ local btransform, etransform = handletransform(at)
+ local cpath = handleclippath(at)
+
if cpath then
- cpath = clippath(cpath,a)
+ r = r + 1 ; result[r] = s_clip_start
end
- if cpath then
- r = r + 1 result[r] = s_clip_start
+
+ if btransform then
+ r = r + 1 ; result[r] = btransform
end
- if trans then
- b, e = transform(trans)
+
+ r = r + 1 ; result[r] = f_do_draw(object)
+
+ if c then
+ r = r + 1 ; result[r] = c
end
- if fill and fill ~= "none" then
- r = r + 1 result[r] = (a["fill-rule"] == "evenodd" and f_eofill or f_fill)(b,shape,e,fillproperties(fill,a))
+
+ if o then
+ r = r + 1 ; result[r] = o
end
- if stroke and stroke ~= "none" and stroke ~= 0 then
- local wrapup = startlineproperties(a)
- r = r + 1 result[r] = f_draw(b,shape,e,drawproperties(stroke,a))
- if wrapup then
- wrapup()
- end
+
+ if etransform then
+ r = r + 1 ; result[r] = etransform
end
+
+ r = r + 1 ; result[r] = ";"
+
if cpath then
- r = r + 1 result[r] = (cpath.evenodd and f_eoclip_stop or f_clip_stop)(cpath[1])
+ local f_done = cpath.evenodd
+ if cpath.curve then
+ f_done = f_done and f_eoclip_stop_c or f_clip_stop_c
+ else
+ f_done = f_done and f_eoclip_stop_l or f_clip_stop_l
+ end
+ r = r + 1 ; result[r] = f_done(cpath[1])
end
end
- -- todo: strokes in:
+ do
- local function flushpath(a,shape)
- local fill = a.fill
- local stroke = a.stroke
- local cpath = a["clip-path"]
- local trans = a.transform
- local b, e = "", ""
- if cpath then
- cpath = definitions[cpath]
- end
- if cpath then
- r = r + 1 result[r] = s_clip_start
- end
- -- todo: image (nicer for transform too)
- if trans then
- b, e = transform(trans)
- end
- if fill and fill ~= "none" then
- local n = #shape
- for i=1,n do
- r = r + 1
- if i == n then
- local f = a["fill-rule"] == "evenodd"
- if shape.closed then
- f = f and f_eofill or f_fill
- elseif shape.curve then
- f = f and f_eofill_cycle_c or f_fill_cycle_c
- else
- f = f and f_eofill_cycle_l or f_fill_cycle_l
- end
- result[r] = f(b,shape[i],e,fillproperties(fill,a))
- else
- result[r] = f_nofill(b,shape[i],e)
+ local flush
+
+ local f_linecap = formatters["interim linecap := %s ;"]
+ local f_linejoin = formatters["interim linejoin := %s ;"]
+ local f_miterlimit = formatters["interim miterlimit := %s ;"]
+
+ local s_begingroup = "begingroup;"
+ local s_endgroup = "endgroup;"
+
+ local linecaps = { butt = "butt", square = "squared", round = "rounded" }
+ local linejoins = { miter = "mitered", bevel = "beveled", round = "rounded" }
+
+ local function startlineproperties(at)
+ local cap = at["stroke-linecap"]
+ local join = at["stroke-linejoin"]
+ local limit = at["stroke-miterlimit"]
+ cap = cap and linecaps [cap]
+ join = join and linejoins[join]
+ limit = limit and asnumber_r(limit)
+ if cap or join or limit then
+ r = r + 1 ; result[r] = s_begingroup
+ if cap then
+ r = r + 1 ; result[r] = f_linecap(cap)
+ end
+ if join then
+ r = r + 1 ; result[r] = f_linejoin(join)
+ end
+ if limit then
+ r = r + 1 ; result[r] = f_miterlimit(limit)
+ end
+ return function()
+ at["stroke-linecap"] = false
+ at["stroke-linejoin"] = false
+ at["stroke-miterlimit"] = false
+ r = r + 1 ; result[r] = s_endgroup
+ at["stroke-linecap"] = cap
+ at["stroke-linejoin"] = join
+ at["stroke-miterlimit"] = limit
end
end
end
- if stroke and stroke ~= "none" and stroke ~= 0 then
- local wrapup = startlineproperties(a)
- local n = #shape
- for i=1,n do
- r = r + 1
- if i == n then
- result[r] = f_draw(b,shape[i],e,drawproperties(stroke,a))
+
+ -- markers are a quite rediculous thing .. let's assume simple usage for now
+
+ function handlers.marker()
+ -- todo: is just a def too
+ end
+
+ -- kind of local svg ... so make a generic one
+ --
+ -- todo: combine more (offset+scale+rotation)
+
+ local function makemarker(where,c,x1,y1,x2,y2,x3,y3)
+ local at = c.at
+ local refx = rawget(at,"refX")
+ local refy = rawget(at,"refY")
+ local width = rawget(at,"markerWidth")
+ local height = rawget(at,"markerHeight")
+ local view = rawget(at,"viewBox")
+ local orient = rawget(at,"orient")
+ -- local ratio = rawget(at,"preserveAspectRatio")
+ local units = at["markerUnits"]
+ local height = at["markerHeight"]
+ local angx = 0
+ local angy = 0
+ local angle = 0
+
+ if where == "beg" then
+ if orient == "auto" then -- unchecked
+ -- no angle
+ angx = x2 - x3
+ angy = y2 - y3
+ elseif orient == "auto-start-reverse" then -- checked
+ -- points to start
+ angx = x3 - x2
+ angy = y3 - y2
+ elseif orient then -- unchecked
+ angle = asnumber_r(orient)
+ end
+ elseif where == "end" then
+ if orient == "auto" then -- unchecked
+ -- no angle ?
+ angx = x1 - x2
+ angy = y1 - y2
+ elseif orient == "auto-start-reverse" then -- unchecked
+ -- points to end
+ angx = x2 - x1
+ angy = y2 - y1
+ elseif orient then -- unchecked
+ angle = asnumber_r(orient)
+ end
+ elseif orient then -- unchecked
+ angle = asnumber_r(orient)
+ end
+
+ -- what wins: viewbox or w/h
+
+ refx = asnumber_x(refx)
+ refy = asnumber_y(refy)
+
+ width = width and asnumber_x(width) or 3 -- defaults
+ height = height and asnumber_y(height) or 3 -- defaults
+
+ local x = 0
+ local y = 0
+ local w = width
+ local h = height
+
+ -- kind of like the main svg
+
+ r = r + 1 ; result[r] = s_offset_start
+
+ local wrapupviewport
+-- todo : better viewbox code
+ local xpct, ypct, rpct
+ if view then
+ x, y, w, h = handleviewbox(view)
+ end
+
+ if width ~= 0 then
+ w = width
+ end
+ if height ~= 0 then
+ h = height
+ end
+
+ if h then
+ xpct = percentage_x
+ ypct = percentage_y
+ rpct = percentage_r
+ percentage_x = w / 100
+ percentage_y = h / 100
+ percentage_r = (sqrt(w^2 + h^2) / sqrt(2)) / 100
+ wrapupviewport = viewport(x,y,w,h,true,true) -- no clip
+ end
+
+ -- we can combine a lot here:
+
+ local hasref = refx ~= 0 or refy ~= 0
+ local hasrot = angx ~= 0 or angy ~= 0 or angle ~= 0
+
+ local btransform, etransform, transform = handletransform(at)
+
+ if btransform then
+ r = r + 1 ; result[r] = btransform
+ end
+
+ if hasrot then
+ r = r + 1 ; result[r] = s_rotation_start
+ end
+
+ if hasref then
+ r = r + 1 ; result[r] = s_offset_start
+ end
+
+ local _transform = transform
+ at["transform"] = false
+
+ handlers.g(c)
+
+ at["transform"] = _transform
+
+ if hasref then
+ r = r + 1 ; result[r] = f_offset_stop(-refx,refy)
+ end
+
+ if hasrot then
+ if angle ~= 0 then
+ r = r + 1 ; result[r] = f_rotation_angle(angle)
else
- result[r] = f_nodraw(b,shape[i],e)
+ r = r + 1 ; result[r] = f_rotation_stop(angx,angy)
end
end
- if wrapup then
- wrapup()
+
+ if etransform then
+ r = r + 1 ; result[r] = etransform
end
+
+ if h then
+ percentage_x = xpct
+ percentage_y = ypct
+ percentage_r = rpct
+ if wrapupviewport then
+ wrapupviewport()
+ end
+ end
+ r = r + 1 ; result[r] = f_offset_stop(x2,y2)
+
end
- if cpath then
- r = r + 1 result[r] = f_clip_stop(cpath[1])
- end
- end
- function handlers.line(c,top)
- local a = setmetatableindex(c.at,top)
- local x1 = asnumber_vx(a.x1)
- local y1 = asnumber_vy(a.y1)
- local x2 = asnumber_vx(a.x2)
- local y2 = asnumber_vy(a.y2)
- if trace then
- report("line: x1 %.3N, y1 %.3N, x2 %.3N, x3 %.3N",x1,y1,x2,y2)
+ local function addmarkers(list,begmarker,midmarker,endmarker)
+ local n = #list
+ if n > 3 then
+ if begmarker then
+ local m = locate(begmarker)
+ if m then
+ makemarker("beg",m,false,false,list[1],list[2],list[3],list[4])
+ end
+ end
+ if midmarker then
+ local m = locate(midmarker)
+ if m then
+ for i=3,n-2,2 do
+ makemarker("mid",m,list[i-2],list[i-1],list[i],list[i+1],list[i+2],list[i+3])
+ end
+ end
+ end
+ if endmarker then
+ local m = locate(endmarker)
+ if m then
+ makemarker("end",m,list[n-3],list[n-2],list[n-1],list[n],false,false)
+ end
+ end
+ else
+ -- no line
+ end
end
- flush(a,f_line(x1,y1,x2,y2),true)
- end
- function handlers.rect(c,top)
- local a = setmetatableindex(c.at,top)
- local w = asnumber_x(a.width)
- local h = asnumber_y(a.height)
- local x = asnumber_vx(a.x)
- local y = asnumber_vy(a.y) - h
- local rx = a.rx
- local ry = a.ry
- if rx == 0 then rx = false end -- maybe no default 0
- if ry == 0 then ry = false end -- maybe no default 0
- if rx or ry then
- rx = asnumber_x(rx or ry)
- ry = asnumber_y(ry or rx)
- if trace then
- report("rect: x %.3N, y %.3N, w %.3N, h %.3N, rx %.3N, ry %.3N",x,y,w,h,rx,ry)
+ local function flush(shape,dofill,at,list,begmarker,midmarker,endmarker)
+
+ local fill = dofill and (at["fill"] or "black")
+ local stroke = at["stroke"] or "none"
+
+ local btransform, etransform = handletransform(at)
+ local cpath = handleclippath(at)
+
+ if cpath then
+ r = r + 1 ; result[r] = s_clip_start
end
- flush(a,f_rounded(w,h,rx,ry,x,y))
- else
- if trace then
- report("rect: x %.3N, y %.3N, w %.3N, h %.3N",x,y,w,h)
+
+ local has_stroke = stroke and stroke ~= "none"
+ local has_fill = fill and fill ~= "none"
+
+ local bopacity, eopacity
+ if has_stroke and has_fill then
+ bopacity, eopacity = sharedopacity(at)
+ end
+
+ if bopacity then
+ r = r + 1 ; result[r] = bopacity
+ end
+
+ if has_fill then
+ local color, opacity = fillproperties(fill,at,not has_stroke)
+ local f_xx_fill = at["fill-rule"] == "evenodd" and f_eo_fill or f_do_fill
+ if btransform then
+ r = r + 1 ; result[r] = btransform
+ end
+ r = r + 1 result[r] = f_xx_fill(shape)
+ if color then
+ r = r + 1 ; result[r] = color
+ end
+ if opacity then
+ r = r + 1 ; result[r] = opacity
+ end
+ r = r + 1 ; result[r] = etransform or ";"
+ end
+
+ if has_stroke then
+ local wrapup = startlineproperties(at)
+ local pen, dashing, color, opacity = drawproperties(stroke,at,not has_fill)
+ if btransform then
+ r = r + 1 ; result[r] = btransform
+ end
+ r = r + 1 ; result[r] = f_do_draw(shape)
+ if pen then
+ r = r + 1 ; result[r] = pen
+ end
+ if dashing then
+ r = r + 1 ; result[r] = dashing
+ end
+ if color then
+ r = r + 1 ; result[r] = color
+ end
+ if opacity then
+ r = r + 1 ; result[r] = opacity
+ end
+ r = r + 1 ; result[r] = etransform or ";"
+ --
+ if list then
+ addmarkers(list,begmarker,midmarker,endmarker)
+ end
+ --
+ if wrapup then
+ wrapup()
+ end
+ end
+
+ if eopacity then
+ r = r + 1 ; result[r] = eopacity
+ end
+
+ if cpath then
+ r = r + 1 ; result[r] = (cpath.evenodd and f_eoclip_stop or f_clip_stop)(cpath[1])
end
- flush(a,f_rectangle(w,h,x,y))
- end
- end
- function handlers.ellipse(c,top)
- local a = setmetatableindex(c.at,top)
- local x = asnumber_vx(a.cx)
- local y = asnumber_vy(a.cy)
- local rx = asnumber_x (a.rx)
- local ry = asnumber_y (a.ry)
- if trace then
- report("ellipse: x %.3N, y %.3N, rx %.3N, ry %.3N",x,y,rx,ry)
end
- flush(a,f_ellipse(2*rx,2*ry,x,y))
- end
- function handlers.circle(c,top)
- local a = setmetatableindex(c.at,top)
- local x = asnumber_vx(a.cx)
- local y = asnumber_vy(a.cy)
- local r = asnumber_r (a.r)
- if trace then
- report("circle: x %.3N, y %.3N, r %.3N",x,y,r)
+ local f_rectangle = formatters['unitsquare xyscaled (%N,%N) shifted (%N,%N)']
+ local f_rounded = formatters['roundedsquarexy(%N,%N,%N,%N) shifted (%N,%N)']
+ local f_line = formatters['((%N,%N)--(%N,%N))']
+ local f_ellipse = formatters['(fullcircle xyscaled (%N,%N) shifted (%N,%N))']
+ local f_circle = formatters['(fullcircle scaled %N shifted (%N,%N))']
+
+ function handlers.line(c)
+ local at = c.at
+ local x1 = rawget(at,"x1")
+ local y1 = rawget(at,"y1")
+ local x2 = rawget(at,"x2")
+ local y2 = rawget(at,"y2")
+
+ x1 = x1 and asnumber_vx(x1) or 0
+ y1 = y1 and asnumber_vy(y1) or 0
+ x2 = x2 and asnumber_vx(x2) or 0
+ y2 = y2 and asnumber_vy(y2) or 0
+
+ flush(f_line(x1,y1,x2,y2),false,at)
end
- flush(a,f_circle(2*r,x,y))
- end
- function handlers.path(c,top)
- local a = setmetatableindex(c.at,top)
- local d = a.d
- if d then
- local p = grabpath(d)
- if trace then
- report("path: %i entries, %sclosed",p.entries,p.closed and "" or "not ")
+ function handlers.rect(c)
+ local at = c.at
+ local width = rawget(at,"width")
+ local height = rawget(at,"height")
+ local x = rawget(at,"x")
+ local y = rawget(at,"y")
+ local rx = rawget(at,"rx")
+ local ry = rawget(at,"ry")
+
+ width = width and asnumber_x(width) or 0
+ height = height and asnumber_y(height) or 0
+ x = x and asnumber_vx(x) or 0
+ y = y and asnumber_vy(y) or 0
+
+ y = y - height
+
+ if rx then rx = asnumber(rx) end
+ if ry then ry = asnumber(ry) end
+
+ if rx or ry then
+ if not rx then rx = ry end
+ if not ry then ry = rx end
+ flush(f_rounded(width,height,rx,ry,x,y),true,at)
+ else
+ flush(f_rectangle(width,height,x,y),true,at)
end
- flushpath(a,p)
end
- end
- do
+ function handlers.ellipse(c)
+ local at = c.at
+ local cx = rawget(at,"cx")
+ local cy = rawget(at,"cy")
+ local rx = rawget(at,"rx")
+ local ry = rawget(at,"ry")
+
+ cx = cx and asnumber_vx(cx) or 0
+ cy = cy and asnumber_vy(cy) or 0
+ rx = rx and asnumber_r (rx) or 0
+ ry = ry and asnumber_r (ry) or 0
- local p_pair = p_separator^0 * p_number_vx * p_separator^0 * p_number_vy
- local p_pair_z = p_pair / f_lineto_z
- local p_pair_n = p_pair / f_lineto_n
+ flush(f_ellipse(2*rx,2*ry,cx,cy),true,at)
+ end
+
+ function handlers.circle(c)
+ local at = c.at
+ local cx = rawget(at,"cx")
+ local cy = rawget(at,"cy")
+ local r = rawget(at,"r")
+
+ cx = cx and asnumber_vx(cx) or 0
+ cy = cy and asnumber_vy(cy) or 0
+ r = r and asnumber_r (r) or 0
+
+ flush(f_circle(2*r,cx,cy),true,at)
+ end
+
+ local f_lineto_z = formatters['(%N,%N)']
+ local f_lineto_n = formatters['--(%N,%N)']
+
+ local p_pair = p_optseparator * p_number_vx * p_optseparator * p_number_vy
local p_open = Cc("(")
local p_close = Carg(1) * P(true) / function(s) return s end
- local p_polyline = Cs(p_open * p_pair_z * p_pair_n^0 * p_close)
-
- function handlers.polyline(c,top)
- local a = setmetatableindex(c.at,top)
- local p = a.points
- if p then
- flush(a,lpegmatch(p_polyline,p,1,")"),true)
+ local p_polyline = Cs(p_open * (p_pair / f_lineto_z) * (p_pair / f_lineto_n)^0 * p_close)
+ local p_polypair = Ct(p_pair^0)
+
+ local function poly(c,final)
+ local at = c.at
+ local points = rawget(at,"points")
+ if points then
+ local path = lpegmatch(p_polyline,points,1,final)
+ local list = nil
+ local begmarker = rawget(at,"marker-start")
+ local midmarker = rawget(at,"marker-mid")
+ local endmarker = rawget(at,"marker-end")
+ if begmarker or midmarker or endmarker then
+ list = lpegmatch(p_polypair,points)
+ end
+ flush(path,true,at,list,begmarker,midmarker,endmarker)
end
end
- function handlers.polygon(c,top)
- local a = setmetatableindex(c.at,top)
- local p = a.points
- if p then
- flush(a,lpegmatch(p_polyline,p,1,"--cycle)"))
+ function handlers.polyline(c) poly(c, ")") end
+ function handlers.polygon (c) poly(c,"--cycle)") end
+
+ local s_image_start = "draw image ("
+ local s_image_stop = ") ;"
+
+ function handlers.path(c)
+ local at = c.at
+ local d = rawget(at,"d")
+ if d then
+ local shape, l = grabpath(d)
+ local fill = at["fill"] or "black"
+ local stroke = at["stroke"] or "none"
+ local n = #shape
+
+ local btransform, etransform = handletransform(at)
+ local cpath = handleclippath(at)
+
+ if cpath then
+ r = r + 1 ; result[r] = s_clip_start
+ end
+
+ -- todo: image (nicer for transform too)
+
+ if fill and fill ~= "none" then
+ local color, opacity = fillproperties(fill,at)
+ local f_xx_fill = at["fill-rule"] == "evenodd"
+ if shape.closed then
+ f_xx_fill = f_xx_fill and f_eo_fill or f_do_fill
+ elseif shape.curve then
+ f_xx_fill = f_xx_fill and f_eo_fill_c or f_do_fill_c
+ else
+ f_xx_fill = f_xx_fill and f_eo_fill_l or f_do_fill_l
+ end
+ if n == 1 then
+ if btransform then
+ r = r + 1 ; result[r] = btransform
+ end
+ r = r + 1 result[r] = f_xx_fill(shape[1])
+ if color then
+ r = r + 1 ; result[r] = color
+ end
+ if opacity then
+ r = r + 1 ; result[r] = opacity
+ end
+ r = r + 1 ; result[r] = etransform or ";"
+ else
+ r = r + 1 ; result[r] = btransform or s_image_start
+ for i=1,n do
+ if i == n then
+ r = r + 1 ; result[r] = f_xx_fill(shape[i])
+ if color then
+ r = r + 1 ; result[r] = color
+ end
+ if opacity then
+ r = r + 1 ; result[r] = opacity
+ end
+ else
+ r = r + 1 ; result[r] = f_no_fill(shape[i])
+ end
+ r = r + 1 ; result[r] = ";"
+ end
+ r = r + 1 ; result[r] = etransform or s_image_stop
+ end
+ end
+
+ if stroke and stroke ~= "none" then
+ local begmarker = rawget(at,"marker-start")
+ local midmarker = rawget(at,"marker-mid")
+ local endmarker = rawget(at,"marker-end")
+ if begmarker or midmarker or endmarker then
+ list = grablist(l)
+ end
+ local wrapup = startlineproperties(at)
+ local pen, dashing, color, opacity = drawproperties(stroke,at)
+ if n == 1 and not list then
+ if btransform then
+ r = r + 1 ; result[r] = btransform
+ end
+ r = r + 1 result[r] = f_do_draw(shape[1])
+ if pen then
+ r = r + 1 ; result[r] = pen
+ end
+ if dashing then
+ r = r + 1 ; result[r] = dashing
+ end
+ if color then
+ r = r + 1 ; result[r] = color
+ end
+ if opacity then
+ r = r + 1 ; result[r] = opacity
+ end
+ r = r + 1 result[r] = etransform or ";"
+ else
+ r = r + 1 result[r] = btransform or "draw image ("
+ for i=1,n do
+ r = r + 1 result[r] = f_do_draw(shape[i])
+ if pen then
+ r = r + 1 ; result[r] = pen
+ end
+ if dashing then
+ r = r + 1 ; result[r] = dashing
+ end
+ if color then
+ r = r + 1 ; result[r] = color
+ end
+ if opacity then
+ r = r + 1 ; result[r] = opacity
+ end
+ r = r + 1 ; result[r] = ";"
+ end
+ if list then
+ addmarkers(list,begmarker,midmarker,endmarker)
+ end
+ r = r + 1 ; result[r] = etransform or ") ;"
+ end
+ if wrapup then
+ wrapup()
+ end
+ end
+
+ if cpath then
+ r = r + 1 ; result[r] = f_clip_stop(cpath[1])
+ end
+
end
end
end
- function handlers.g(c,top)
- local a = c.at
- setmetatableindex(a,top)
- process(c,"/*",a)
- end
+ -- kind of special
+
+ do
+
+ -- some day:
+ --
+ -- specification = identifiers.jpg(data."string")
+ -- specification.data = data
+ -- inclusion takes from data
+ -- specification.data = false
+
+ local f_image = formatters[ [[figure("%s") xysized (%N,%N) shifted (%N,%N)]] ]
+
+ local nofimages = 0
+
+ function handlers.image(c)
+ local at = c.at
+ local im = rawget(at,"xlink:href")
+ if im then
+ local kind, data = match(im,"^data:image/([a-z]+);base64,(.*)$")
+ if kind == "png" then
+ -- ok
+ elseif kind == "jpeg" then
+ kind = "jpg"
+ else
+ kind = false
+ end
+ if kind and data then
+ local w = rawget(at,"width")
+ local h = rawget(at,"height")
+ local x = rawget(at,"x")
+ local y = rawget(at,"y")
+ w = w and asnumber_x(w)
+ h = h and asnumber_y(h)
+ x = x and asnumber_vx(x) or 0
+ y = y and asnumber_vy(y) or 0
+ nofimages = nofimages + 1
+ local name = "temp-svg-image-" .. nofimages .. "." .. kind
+ local data = mime.decode("base64")(data)
+ io.savedata(name,data)
+ if not w or not h then
+ local info = graphics.identifiers[kind](data,"string")
+ if info then
+ -- todo: keep aspect ratio attribute
+ local xsize = info.xsize
+ local ysize = info.ysize
+ if not w then
+ if not h then
+ w = xsize
+ h = ysize
+ else
+ w = (h / ysize) * xsize
+ end
+ else
+ h = (w / xsize) * ysize
+ end
+ end
+ end
+ -- safeguard:
+ if not w then w = h or 1 end
+ if not h then h = w or 1 end
+ luatex.registertempfile(name)
+ -- done:
+ flushobject(f_image(name,w,h,x,y - h),at)
+ else
+ -- nothing done
+ end
+ end
+ end
- function handlers.symbol(c,top)
- report("todo: %s","symbol")
end
- -- We only need to filter classes .. I will complete this when I really need
- -- it. Not hard to do but kind of boring.
+ -- these transform: g a text svg symbol
+
+ do
+
+ function handlers.a(c)
+ process(c,"/*")
+ end
+
+ function handlers.g(c) -- much like flushobject so better split and share
+ local at = c.at
+
+ local btransform, etransform, transform = handletransform(at)
+ local cpath, clippath = handleclippath(at)
+
+ if cpath then
+ r = r + 1 ; result[r] = s_clip_start
+ end
+
+ if btransform then
+ r= r + 1 result[r] = btransform
+ end
+
+ local _transform = transform
+ local _clippath = clippath
+ at["transform"] = false
+ at["clip-path"] = false
+
+ process(c,"/*")
- local p_class = P(".") * C((R("az","AZ","09","__","--")^1))
- local p_spec = P("{") * C((1-P("}"))^1) * P("}")
+ at["transform"] = _transform
+ at["clip-path"] = _clippath
- local p_grab = ((Carg(1) * p_class * p_space^0 * p_spec / function(t,k,v) t[k] = v end) + p_space^1 + P(1))^1
+ if etransform then
+ r = r + 1 ; result[r] = etransform
+ end
- function handlers.style(c,top)
- local s = xmltext(c)
- lpegmatch(p_grab,s,1,styles)
- for k, v in next, styles do
- -- todo: lpeg
- local t = { }
- for k, v in gmatch(v,"%s*([^:]+):%s*([^;]+);") do
- if k == "font" then
- v = xml.css.fontspecification(v)
+ if cpath then
+ local f_done = cpath.evenodd
+ if cpath.curve then
+ f_done = f_done and f_eoclip_stop_c or f_clip_stop_c
+ else
+ f_done = f_done and f_eoclip_stop_l or f_clip_stop_l
end
- t[k] = v
+ r = r + 1 ; result[r] = f_done(cpath[1])
end
- styles[k] = t
end
- bodyfont = tex.getdimen("bodyfontsize") / 65536
- end
- -- this will never really work out
-
- function handlers.text(c,top)
- local a = c.at
- local x = asnumber_vx(a.x)
- local y = asnumber_vy(a.y)
- local text = xmltext(c)
- local size = false
- local fill = a.fill
- -- escape text or keep it at the tex end
- local class = a.class
- if class then
- local style = styles[class]
- if style and next(style) then
- local font = style.font
- local s_family = font and font.family
- local s_style = font and font.style
- local s_weight = font and font.weight
- local s_size = font and font.size
- if s_size then
- local f = factors[s_size[2]]
- if f then
- size = f * s_size[1]
+ -- this will never really work out
+ --
+ -- todo: register text in lua in mapping with id, then draw mapping unless overloaded
+ -- using lmt_svglabel with family,style,weight,size,id passed
+
+ -- nested tspans are messy: they can have displacements but in inkscape we also
+ -- see x and y (inner and outer element)
+
+ -- The size is a bit of an issue. I assume that the specified size relates to the
+ -- designsize but we want to be able to use other fonts.
+
+ do
+
+ local f_styled = formatters["\\svgstyled{%s}{%s}{%s}{%s}"]
+ local f_colored = formatters["\\svgcolored{%N}{%N}{%N}{"]
+ local f_placed = formatters["\\svgplaced{%N}{%N}{}{"]
+ local f_poschar = formatters["\\svgposchar{%N}{%N}{%s}"]
+ local f_char = formatters["\\svgchar{%s}"]
+
+ local f_scaled = formatters["\\svgscaled{%N}{%s}{%s}{%s}"]
+ local f_normal = formatters["\\svgnormal{%s}{%s}{%s}"]
+
+ -- We move to the outer (x,y) and when we have an inner offset we
+ -- (need to) compensate for that outer offset.
+
+ -- local f_text_scaled_svg = formatters['(svgtext("%s") scaled %N shifted (%N,%N))']
+ -- 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")']
+
+ -- or just maptext
+
+ local f_mapped_normal_svg = formatters['(svgtext("%s") shifted (%N,%N))']
+ local f_mapped_simple_svg = formatters['svgtext("%s")']
+
+ local cssfamily = css.family
+ local cssstyle = css.style
+ local cssweight = css.weight
+ local csssize = css.size
+
+ local usedfonts = setmetatableindex(function(t,k)
+ local v = setmetatableindex("table")
+ t[k] = v
+ return v
+ end)
+
+ local p_texescape = lpegpatterns.texescape
+
+ -- For now as I need it for my (some 1500) test files.
+
+ local function checkedfamily(name)
+ if find(name,"^.-verdana.-$") then
+ name = "verdana"
+ end
+ return name
+ end
+
+ -- todo: only escape some chars and handle space
+
+ local defaultsize = 10
+
+ local function collect(t,c,x,y,size,scale,family,tx,ty)
+ local at = c.at
+ local ax = rawget(at,"x")
+ local ay = rawget(at,"y")
+ local dx = rawget(at,"dx")
+ local dy = rawget(at,"dy")
+ local v_fill = at["fill"]
+ local v_family = at["font-family"]
+ local v_style = at["font-style"]
+ local v_weight = at["font-weight"]
+ local v_size = at["font-size"]
+ --
+ ax = ax and asnumber_vx(ax) or x
+ ay = ay and asnumber_vy(ay) or y
+ dx = dx and asnumber_vx(dx) or 0
+ dy = dy and asnumber_vy(dy) or 0
+ --
+ if v_family then v_family = cssfamily(v_family) end
+ if v_style then v_style = cssstyle (v_style) end
+ if v_weight then v_weight = cssweight(v_weight) end
+ if v_size then v_size = csssize (v_size,factors) end
+ --
+ ax = ax - x
+ ay = ay - y
+ --
+ local elayered = ax ~= 0 or ay ~= 0 or false
+ local eplaced = dx ~= 0 or dy ~= 0 or false
+
+ local usedsize, usedscaled
+
+ if elayered then
+ -- we're now at the outer level again so we need to scale
+ -- back to the outer level values
+ t[#t+1] = formatters["\\svgsetlayer{%0N}{%0N}{"](ax,-ay)
+ usedsize = v_size or defaultsize
+ usedscale = usedsize / defaultsize
+ else
+ -- we're nested so we can be scaled
+ usedsize = v_size or size
+ usedscale = (usedsize / defaultsize) / scale
+ end
+ --
+ -- print("element ",c.tg)
+ -- print(" layered ",elayered)
+ -- print(" font size ",v_size)
+ -- print(" parent size ",size)
+ -- print(" parent scale",scale)
+ -- print(" used size ",usedsize)
+ -- print(" used scale ",usedscale)
+ --
+ if eplaced then
+ t[#t+1] = f_placed(dx,dy)
+ end
+ --
+ if not v_family then v_family = family end
+ if not v_weight then v_weight = "normal" end
+ if not v_style then v_style = "normal" end
+ --
+ if v_family then
+ v_family = fonts.names.cleanname(v_family)
+ v_family = checkedfamily(v_family)
+ end
+ --
+ usedfonts[v_family][v_weight][v_style] = true
+ --
+-- if usedscale == 1 then
+-- t[#t+1] = f_normal( v_family,v_weight,v_style)
+-- else
+ t[#t+1] = f_scaled(usedscale,v_family,v_weight,v_style)
+-- end
+ t[#t+1] = "{"
+ --
+ local ecolored = v_fill and v_fill ~= "" or false
+ if ecolored then
+ -- todo
+ local r, g, b = rgbcomponents(v_fill)
+ if r and g and b then
+ t[#t+1] = f_colored(r,g,b)
+ else
+ ecolored = false
end
end
- -- todo: family: serif | sans-serif | monospace : use mapping
- if s_family then
- if s_family == "serif" then
- text = "\\rm " .. text
- elseif s_family == "sans-serif" then
- text = "\\ss " .. text
+ --
+ local dt = c.dt
+ local nt = #dt
+ for i=1,nt do
+ local di = dt[i]
+ if type(di) == "table" then
+ -- can be a tspan (should we pass dx too)
+ collect(t,di,x,y,usedsize,usedscale,v_family)
else
- text = "\\tt " .. text
+ if i == 1 then
+ di = gsub(di,"^%s+","")
+ end
+ if i == nt then
+ di = gsub(di,"%s+$","")
+ end
+ local chars = utfsplit(di)
+ if tx then
+ for i=1,#chars do
+ chars[i] = f_poschar(
+ (tx[i] or 0) - x,
+ (ty[i] or 0) - y,
+ utfbyte(chars[i])
+ )
+ end
+ di = "{" .. concat(chars) .. "}"
+ else
+ -- this needs to be texescaped ! and even quotes and newlines
+ -- or we could register it but that's a bit tricky as we nest
+ -- and don't know what we can expect here
+ -- di = lpegmatch(p_texescape,di) or di
+ for i=1,#chars do
+ chars[i] = f_char(utfbyte(chars[i]))
+ end
+ di = concat(chars)
+ end
+ t[#t+1] = di
end
end
- if s_style or s_weight then
- text = formatters['\\style[%s%s]{%s}'](s_weight or "",s_style or "",text)
+ --
+ if ecolored then
+ t[#t+1] = "}"
end
- fill = style.fill or fill
+ --
+ t[#t+1] = "}"
+ --
+ if eplaced then
+ t[#t+1] = "}"
+ end
+ if elayered then
+ t[#t+1] = "}"
+ end
+ --
+ return t
end
- end
- if size then
- -- bodyfontsize
- size = size/bodyfont
- text = f_text_scaled(text,size,x,y)
- else
- text = f_text_normal(text,x,y)
- end
- if fill and fill ~= "none" then
- text = f_draw("",text,"",fillproperties(fill,a))
- else
- text = f_draw("",text,"","","","","")
- end
- if trace then
- report("text: x %.3N, y %.3N, text %s",x,y,text)
- end
- r = r + 1 ; result[r] = text
- end
- function handlers.svg(c,top,x,y,w,h,noclip,notransform,normalize)
- local a = setmetatableindex(c.at,top)
- local v = a.viewBox
- local t = a.transform
- local wrapupoffset
- local wrapupviewport
- local btransform
- local etransform
- local bhacked
- local ehacked
- local wd = w
- -- local ex, em
- local xpct, ypct, rpct
- if notransform then
--- t = nil
- end
- if trace then
- report("view: %s, xpct %.3N, ypct %.3N","before",percentage_x,percentage_y)
- end
- if v then
- x, y, w, h = viewbox(v)
- if trace then
- report("viewbox: x %.3N, y %.3N, width %.3N, height %.3N",x,y,w,h)
+ local s_startlayer = "\\svgstartlayer "
+ local s_stoplayer = "\\svgstoplayer "
+
+ function handlers.text(c)
+ local only = fullstrip(xmltextonly(c))
+ -- if metapost.processing() then
+ local at = c.at
+ local x = rawget(at,"x")
+ local y = rawget(at,"y")
+
+ local tx = asnumber_vx_t(x)
+ local ty = asnumber_vy_t(y)
+
+ x = tx[1] or 0 -- catch bad x/y spec
+ y = ty[1] or 0 -- catch bad x/y spec
+
+ local v_fill = at["fill"]
+ if not v_fill or v_fill == "none" then
+ v_fill = "black"
+ end
+ local color, opacity, invisible = fillproperties(v_fill,at)
+ local r = metapost.remappedtext(only)
+ if r then
+ if x == 0 and y == 0 then
+ only = f_mapped_simple_svg(r.index)
+ else
+ only = f_mapped_normal_svg(r.index,x,y)
+ end
+ flushobject(only,at,color,opacity)
+ if trace_text then
+ report("text: %s",only)
+ end
+ elseif not invisible then -- can be an option
+ local scale = 1
+ local textid = 0
+ local result = { }
+ local nx = #tx
+ local ny = #ty
+ --
+ result[#result+1] = s_startlayer
+ if nx > 1 or ny > 1 then
+ concat(collect(result,c,x,y,defaultsize,1,"serif",tx,ty))
+ else
+ concat(collect(result,c,x,y,defaultsize,1,"serif"))
+ end
+ result[#result+1] = s_stoplayer
+ result = concat(result)
+ if x == 0 and y == 0 then
+ result = f_text_simple_svg(result)
+ else
+ result = f_text_normal_svg(result,x,y)
+ end
+ flushobject(result,at,color,opacity)
+ if trace_text then
+ report("text: %s",result)
+ end
+ elseif trace_text then
+ report("invisible text: %s",only)
+ end
+ -- elseif trace_text then
+ -- report("ignored text: %s",only)
+ -- end
end
+
+ function metapost.reportsvgfonts()
+ for family, weights in sortedhash(usedfonts) do
+ for weight, styles in sortedhash(weights) do
+ for style in sortedhash(styles) do
+ report("used font: %s-%s-%s",family,weight,style)
+ end
+ end
+ end
+ end
+
+ statistics.register("used svg fonts",function()
+ if next(usedfonts) then
+ -- also in log file
+ logs.startfilelogging(report,"used svg fonts")
+ local t = { }
+ for family, weights in sortedhash(usedfonts) do
+ for weight, styles in sortedhash(weights) do
+ for style in sortedhash(styles) do
+ report("%s-%s-%s",family,weight,style)
+ t[#t+1] = formatters["%s-%s-%s"](family,weight,style)
+ end
+ end
+ end
+ logs.stopfilelogging()
+ return concat(t," ")
+ end
+ end)
+
end
- if h then
- --
- -- em = factors["em"]
- -- ex = factors["ex"]
- -- factors["em"] = em
- -- factors["ex"] = ex
- --
- xpct = percentage_x
- ypct = percentage_y
- rpct = percentage_r
- percentage_x = w / 100
- percentage_y = h / 100
- percentage_r = (sqrt(w^2 + h^2) / sqrt(2)) / 100
+
+ function handlers.svg(c,x,y,w,h,noclip,notransform,normalize,usetextindex)
+ local at = c.at
+
+ local wrapupviewport
+ local bhacked
+ local ehacked
+ local wd = w
+ -- local ex, em
+ local xpct, ypct, rpct
+
+ local btransform, etransform, transform = handletransform(at)
+
if trace then
- report("view: %s, xpct %.3N, ypct %.3N","inside",percentage_x,percentage_y)
+ report("view: %s, xpct %N, ypct %N","before",percentage_x,percentage_y)
end
- wrapupviewport = viewport(x,y,w,h,noclip)
- end
- -- todo: combine transform and offset here
- if t then
- btransform, etransform = transform(t,true)
- end
- -- some fonts need this (bad transforms + viewbox)
- if v and normalize and w and wd and w ~= wd and w > 0 and wd > 0 then
- bhacked = s_hacked_start
- ehacked = f_hacked_stop(y or 0,wd/w)
- end
- if btransform then
- r = r + 1 ; result[r] = btransform
- end
- if bhacked then
- r = r + 1 ; result[r] = bhacked
- end
- wrapupoffset = offset(a)
- process(c,"/*",top or defaults)
- if wrapupoffset then
- wrapupoffset()
- end
- if ehacked then
- r = r + 1 ; result[r] = ehacked
- end
- if etransform then
- r = r + 1 ; result[r] = etransform
- end
- if h then
- --
- -- factors["em"] = em
- -- factors["ex"] = ex
- --
- percentage_x = xpct
- percentage_y = ypct
- percentage_r = rpct
- if wrapupviewport then
- wrapupviewport()
+
+ local viewbox = at.viewBox
+
+ if viewbox then
+ x, y, w, h = handleviewbox(viewbox)
+ if trace then
+ report("viewbox: x %N, y %N, width %N, height %N",x,y,w,h)
+ end
+ end
+ if not w or not h or w == 0 or h == 0 then
+ noclip = true
+ end
+ if h then
+ --
+ -- em = factors["em"]
+ -- ex = factors["ex"]
+ -- factors["em"] = em
+ -- factors["ex"] = ex
+ --
+ xpct = percentage_x
+ ypct = percentage_y
+ rpct = percentage_r
+ percentage_x = w / 100
+ percentage_y = h / 100
+ percentage_r = (sqrt(w^2 + h^2) / sqrt(2)) / 100
+ if trace then
+ report("view: %s, xpct %N, ypct %N","inside",percentage_x,percentage_y)
+ end
+ wrapupviewport = viewport(x,y,w,h,noclip)
+ end
+ -- todo: combine transform and offset here
+
+ -- some fonts need this (bad transforms + viewbox)
+ if v and normalize and w and wd and w ~= wd and w > 0 and wd > 0 then
+ bhacked = s_wrapped_start
+ ehacked = f_wrapped_stop(y or 0,wd/w)
+ end
+ if btransform then
+ r = r + 1 ; result[r] = btransform
+ end
+ if bhacked then
+ r = r + 1 ; result[r] = bhacked
+ end
+ local boffset, eoffset = offset(at)
+ if boffset then
+ r = r + 1 result[r] = boffset
+ end
+ textindex = usetextindex and 0 or false
+
+ at["transform"] = false
+ at["viewBox"] = false
+
+ process(c,"/*")
+
+ at["transform"] = transform
+ at["viewBox"] = viewbox
+
+ if eoffset then
+ r = r + 1 result[r] = eoffset
+ end
+ if ehacked then
+ r = r + 1 ; result[r] = ehacked
+ end
+ if etransform then
+ r = r + 1 ; result[r] = etransform
+ end
+ if h then
+ --
+ -- factors["em"] = em
+ -- factors["ex"] = ex
+ --
+ percentage_x = xpct
+ percentage_y = ypct
+ percentage_r = rpct
+ if wrapupviewport then
+ wrapupviewport()
+ end
+ end
+ if trace then
+ report("view: %s, xpct %N, ypct %N","after",percentage_x,percentage_y)
end
end
- if trace then
- report("view: %s, xpct %.3N, ypct %.3N","after",percentage_x,percentage_y)
- end
+
end
- process = function(x,p,top)
+ process = function(x,p)
for c in xmlcollected(x,p) do
- local h = handlers[c.tg]
+ local tg = c.tg
+ local h = handlers[c.tg]
if h then
- h(c,top)
+ h(c)
end
end
end
+ -- For huge inefficient files there can be lots of garbage to collect so
+ -- maybe we should run the collector when a file is larger than say 50K.
+
function metapost.svgtomp(specification,pattern,notransform,normalize)
local mps = ""
local svg = specification.data
@@ -1660,21 +2735,33 @@ do
if svg then
local c = xmlfirst(svg,pattern or "/svg")
if c then
- root, result, r, definitions, styles, bodyfont = svg, { }, 0, { }, { }, 12
- -- print("default",x,y,w,h)
+ root = svg
+ result = { }
+ r = 0
+ definitions = { }
+ tagstyles = { }
+ classstyles = { }
+ for s in xmlcollected(c,"/style") do
+ handlestyle(c)
+ end
+ handlechains(c)
+ xmlinheritattributes(c) -- put this in handlechains
handlers.svg (
c,
- nil,
specification.x,
specification.y,
specification.width,
specification.height,
specification.noclip,
notransform,
- normalize
+ normalize,
+ specification.remap
)
+ if trace_result then
+ report("result graphic:\n %\n t",result)
+ end
mps = concat(result," ")
- root, result, r, definitions, styles, bodyfont = false, false, false, false, false, false
+ root, result, r, definitions, styles = false, false, false, false, false
else
report("missing svg root element")
end
@@ -1686,14 +2773,49 @@ do
end
--- These helpers might move to their own module .. some day ...
+-- These helpers might move to their own module .. some day ... also they will become
+-- 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
+ 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 [ 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 = "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 = dd.comment
- local offset = dd.pageoffset
- for i=1,#dd do
+ 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,
@@ -1701,6 +2823,10 @@ function metapost.showsvgpage(data)
}, 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))
@@ -1713,10 +2839,31 @@ function metapost.showsvgpage(data)
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]
+ 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
+
function metapost.svgtopdf(data,...)
local mps = metapost.svgtomp(data,...)
if mps then
- local pdf = metapost.simple("metafun",mps,true) -- todo: special instance, only basics needed
+ -- todo: special instance, only basics needed
+ local pdf = metapost.simple("metafun",mps,true,false,"svg")
if pdf then
return pdf
else
@@ -1867,7 +3014,7 @@ do
local svgshapes = svgfile and svgfile.svgshapes
if svgshapes then
if type(unicode) == "string" then
- unicode = utf.byte(unicode)
+ unicode = utfbyte(unicode)
end
local chardata = tfmdata.characters[unicode]
local index = chardata and chardata.index
diff --git a/tex/context/base/mkiv/mult-mps.lua b/tex/context/base/mkiv/mult-mps.lua
index 625e8ca65..6385d3fe5 100644
--- a/tex/context/base/mkiv/mult-mps.lua
+++ b/tex/context/base/mkiv/mult-mps.lua
@@ -23,7 +23,7 @@ return {
"transform", "transformed", "ulcorner", "uniformdeviate", "unknown",
"urcorner", "xpart", "xscaled", "xxpart", "xypart", "ypart", "yscaled", "yxpart",
"yypart", "zscaled",
- "addto", "clip", "input", "interim", "let", "newinternal", "save", "setbounds",
+ "addto", "clip", "input", "interim", "let", "newinternal", "save", "setbounds", "setgroup",
"shipout", "show", "showdependencies", "showtoken", "showvariable",
"special",
"begingroup", "endgroup", "of", "curl", "tension", "and", "controls",
diff --git a/tex/context/base/mkiv/mult-prm.lua b/tex/context/base/mkiv/mult-prm.lua
index 04044e2a9..7b30b232e 100644
--- a/tex/context/base/mkiv/mult-prm.lua
+++ b/tex/context/base/mkiv/mult-prm.lua
@@ -228,6 +228,7 @@ return {
"automatichyphenmode",
"automatichyphenpenalty",
"begincsname",
+ "beginlocalcontrol",
"boundary",
"boxattr",
"boxdirection",
@@ -319,6 +320,7 @@ return {
"matheqnogapstep",
"mathflattenmode",
"mathitalicsmode",
+ "mathlimitsmode",
"mathnolimitsmode",
"matholdmode",
"mathpenaltiesmode",
@@ -744,6 +746,7 @@ return {
"showboxbreadth",
"showboxdepth",
"showlists",
+ "shownodedetails",
"showthe",
"skewchar",
"skip",
diff --git a/tex/context/base/mkiv/node-ini.lua b/tex/context/base/mkiv/node-ini.lua
index 02c2c6f6e..ce0a473ba 100644
--- a/tex/context/base/mkiv/node-ini.lua
+++ b/tex/context/base/mkiv/node-ini.lua
@@ -512,11 +512,6 @@ end
trackers.register("system.showcodes", nodes.showcodes)
-if not nodecodes.dir then
- report_codes("use a newer version of luatex")
- os.exit()
-end
-
-- We don't need this sanitize-after-callback in ConTeXt and by disabling it we
-- also have a way to check if LuaTeX itself does the right thing.
diff --git a/tex/context/base/mkiv/page-cst.lua b/tex/context/base/mkiv/page-cst.lua
index 583e6af0c..119e7fc2b 100644
--- a/tex/context/base/mkiv/page-cst.lua
+++ b/tex/context/base/mkiv/page-cst.lua
@@ -36,7 +36,6 @@ local nuts = nodes.nuts
local tonode = nuts.tonode
local tonut = nuts.tonut
-local hpack = nuts.hpack
local vpack = nuts.vpack
local flushlist = nuts.flush_list
----- removenode = nuts.remove
diff --git a/tex/context/base/mkiv/page-ffl.mkiv b/tex/context/base/mkiv/page-ffl.mkiv
index 414cae4ac..306c19790 100644
--- a/tex/context/base/mkiv/page-ffl.mkiv
+++ b/tex/context/base/mkiv/page-ffl.mkiv
@@ -180,6 +180,12 @@
\setbox\scratchbox\vbox{\directvspacing\p_spaceinbetween}%
\scratchdimen\htdp\scratchbox
\fi
+ \ifvoid\b_strc_floats_facing_l\else
+ \page_postprocessors_linenumbers_box\b_strc_floats_facing_l
+ \fi
+ \ifvoid\b_strc_floats_facing_r\else
+ \page_postprocessors_linenumbers_box\b_strc_floats_facing_r
+ \fi
\doloop{%
\strc_floats_facing_flush_wrap\b_strc_floats_facing_l\v!left
\strc_floats_facing_flush_wrap\b_strc_floats_facing_r\v!right
diff --git a/tex/context/base/mkiv/page-lin.mkvi b/tex/context/base/mkiv/page-lin.mkvi
index 51f808df8..6a03d12e4 100644
--- a/tex/context/base/mkiv/page-lin.mkvi
+++ b/tex/context/base/mkiv/page-lin.mkvi
@@ -72,10 +72,22 @@
\newconditional\page_postprocessors_needed_box
-\unexpanded\def\page_postprocessors_linenumbers_page #tag{\page_lines_add_numbers_to_box{#tag}\plusone \plusone \zerocount}
-\unexpanded\def\page_postprocessors_linenumbers_box #tag{\page_lines_add_numbers_to_box{#tag}\plusone \plusone \zerocount}
-\unexpanded\def\page_postprocessors_linenumbers_deepbox#tag{\page_lines_add_numbers_to_box{#tag}\plusone \plusone \plusone }
-\unexpanded\def\page_postprocessors_linenumbers_column #tag{\page_lines_add_numbers_to_box{#tag}\currentcolumn\nofcolumns\zerocount}
+\unexpanded\def\page_postprocessors_linenumbers_page_indeed #tag{\page_lines_add_numbers_to_box{#tag}\plusone \plusone \zerocount}
+\unexpanded\def\page_postprocessors_linenumbers_box_indeed #tag{\page_lines_add_numbers_to_box{#tag}\plusone \plusone \zerocount}
+\unexpanded\def\page_postprocessors_linenumbers_deepbox_indeed#tag{\page_lines_add_numbers_to_box{#tag}\plusone \plusone \plusone }
+\unexpanded\def\page_postprocessors_linenumbers_column_indeed #tag{\page_lines_add_numbers_to_box{#tag}\currentcolumn\nofcolumns\zerocount}
+
+\let\page_postprocessors_linenumbers_page \gobbleoneargument
+\let\page_postprocessors_linenumbers_box \gobbleoneargument
+\let\page_postprocessors_linenumbers_deepbox\gobbleoneargument
+\let\page_postprocessors_linenumbers_column \gobbleoneargument
+
+\unexpanded\def\page_postprocessors_linenumbers_check
+ {\glet\page_postprocessors_linenumbers_check \relax
+ \glet\page_postprocessors_linenumbers_page \page_postprocessors_linenumbers_page_indeed
+ \glet\page_postprocessors_linenumbers_box \page_postprocessors_linenumbers_box_indeed
+ \glet\page_postprocessors_linenumbers_deepbox\page_postprocessors_linenumbers_deepbox_indeed
+ \glet\page_postprocessors_linenumbers_column \page_postprocessors_linenumbers_column_indeed}
\def\page_lines_start_define
{\setxvalue{\??linenumberinginstance\currentlinenumbering}%
@@ -179,6 +191,7 @@
\unexpanded\def\startlinenumbering
{\begingroup
+ \page_postprocessors_linenumbers_check
\dodoubleempty\page_lines_start}
\newcount\c_pages_lines_nesting
diff --git a/tex/context/base/mkiv/page-mix.lua b/tex/context/base/mkiv/page-mix.lua
index 51a12429e..d64646d8a 100644
--- a/tex/context/base/mkiv/page-mix.lua
+++ b/tex/context/base/mkiv/page-mix.lua
@@ -41,7 +41,6 @@ local nuts = nodes.nuts
local tonode = nuts.tonode
local listtoutf = nodes.listtoutf
-local hpack = nuts.hpack
local vpack = nuts.vpack
local flushnode = nuts.flush
local concatnodes = nuts.concat
@@ -800,7 +799,7 @@ local function finalize(result)
local t = { }
for i=1,#list do
local l = list[i]
- local h = new_hlist()
+ local h = new_vlist() -- was hlist but that's wrong
local g = getlist(l)
t[i] = h
setlist(h,g)
@@ -881,12 +880,12 @@ end
local function getsplit(result,n)
if not result then
- report_state("flush, column %s, no result",n)
+ report_state("flush, column %s, %s",n,"no result")
return
end
local r = result.results[n]
if not r then
- report_state("flush, column %s, empty",n)
+ report_state("flush, column %s, %s",n,"empty")
end
local h = r.head
if not h then
@@ -982,9 +981,8 @@ local function getsplit(result,n)
for i=1,#list-1 do
setdepth(list[i],0)
end
- local b = vpack(l) -- multiple arguments, todo: fastvpack
-setbox("global",c,b) -- when we wrap in a box
- -- setbox(c,b)
+ local b = vpack(l) -- multiple arguments, todo: fastvpack
+ setbox("global",c,b) -- when we wrap in a box
r.inserts[c] = nil
end
diff --git a/tex/context/base/mkiv/page-mix.mkiv b/tex/context/base/mkiv/page-mix.mkiv
index f41d739be..e3ed47835 100644
--- a/tex/context/base/mkiv/page-mix.mkiv
+++ b/tex/context/base/mkiv/page-mix.mkiv
@@ -242,7 +242,8 @@
\page_one_command_routine
\fi
\global\setbox\b_page_mix_preceding\vbox % pack ?
- {\page_otr_command_flush_top_insertions
+ {\forgetall
+ \page_otr_command_flush_top_insertions
\ifdim\htdp\b_page_mix_preceding=\zeropoint \else
\writestatus\m!columns{preceding error}%
\unvbox\b_page_mix_preceding
diff --git a/tex/context/base/mkiv/page-not.mkiv b/tex/context/base/mkiv/page-not.mkiv
index d7602bd26..d6f63846f 100644
--- a/tex/context/base/mkiv/page-not.mkiv
+++ b/tex/context/base/mkiv/page-not.mkiv
@@ -22,20 +22,20 @@
\unprotect
-\def\checkbegincolumnfootnotes % should happen inside otr
- {\ifcase\c_strc_notes_page_location
- \erasenotebackup
- \else
- \flushnotes
- \savenotecontent
- \fi
- \savenotedata}
+% \def\checkbegincolumnfootnotes % should happen inside otr
+% {\ifcase\c_strc_notes_page_location
+% \erasenotebackup
+% \else
+% \flushnotes
+% \savenotecontent
+% \fi
+% \savenotedata}
-\def\checkendcolumnfootnotes
- {\restorenotedata
- \ifcase\c_strc_notes_page_location\else
- \restorenotecontent
- \fi}
+% \def\checkendcolumnfootnotes
+% {\restorenotedata
+% \ifcase\c_strc_notes_page_location\else
+% \restorenotecontent
+% \fi}
\let\checksinglecolumnfootnotes\relax
diff --git a/tex/context/base/mkiv/page-run.mkiv b/tex/context/base/mkiv/page-run.mkiv
index eedcfa416..d3efe1698 100644
--- a/tex/context/base/mkiv/page-run.mkiv
+++ b/tex/context/base/mkiv/page-run.mkiv
@@ -206,16 +206,16 @@
\gdef\page_grids_add_to_one_indeed#1%
{\begingroup
\resetvisualizers
- \global\setbox#1\vpack{\backgroundline[layout:one]{\box#1}}%
+ \global\setbox#1\vpack{\noindent\backgroundline[layout:one]{\box#1}}%
\endgroup}
\gdef\page_grids_add_to_mix_indeed#1%
{\begingroup
\resetvisualizers
- \global\setbox#1\vpack{\backgroundline[layout:mix]{\box#1}}%
+ \global\setbox#1\vpack{\noindent\backgroundline[layout:mix]{\box#1}}%
\endgroup}
-%D Ths next command shows some statistics (we might add more in due time):
+%D The next command shows some statistics (we might add more in due time):
\unexpanded\gdef\showusage
{\gtoksapp\everyaftershipout{\ctxcommand{showusage()}}%
diff --git a/tex/context/base/mkiv/regi-ini.lua b/tex/context/base/mkiv/regi-ini.lua
index 7691e8765..4b2412ee8 100644
--- a/tex/context/base/mkiv/regi-ini.lua
+++ b/tex/context/base/mkiv/regi-ini.lua
@@ -16,9 +16,11 @@ runtime.</p>
local commands, context = commands, context
+
+local tostring = tostring
local utfchar = utf.char
local P, Cs, Cc, lpegmatch = lpeg.P, lpeg.Cs, lpeg.Cc, lpeg.match
-local char, gsub, format, gmatch, byte, match = string.char, string.gsub, string.format, string.gmatch, string.byte, string.match
+local char, gsub, format, gmatch, byte, match, lower = string.char, string.gsub, string.format, string.gmatch, string.byte, string.match, string.lower
local next = next
local insert, remove, fastcopy = table.insert, table.remove, table.fastcopy
local concat = table.concat
@@ -103,11 +105,14 @@ local synonyms = { -- backward compatibility list
["pdf"] = "pdfdoc",
+ ["437"] = "ibm",
}
local currentregime = "utf"
local function loadregime(mapping,regime)
+ regime = lower(tostring(regime))
+ regime = synonyms[regime] or synonyms["windows-"..regime] or regime
local name = resolvers.findfile(format("regi-%s.lua",regime)) or ""
local data = name ~= "" and dofile(name)
if data then
@@ -126,8 +131,11 @@ end
local function loadreverse(t,k)
local t = { }
- for k, v in next, mapping[k] do
- t[v] = k
+ local m = mapping[k]
+ if m then
+ for k, v in next, m do
+ t[v] = k
+ end
end
backmapping[k] = t
return t
@@ -141,7 +149,8 @@ regimes.backmapping = backmapping
local function fromregime(regime,line)
if line and #line > 0 then
- local map = mapping[regime and synonyms[regime] or regime or currentregime]
+-- local map = mapping[regime and synonyms[regime] or regime or currentregime]
+ local map = mapping[regime or currentregime]
if map then
line = gsub(line,".",map)
end
@@ -459,3 +468,21 @@ if interfaces then
}
end
+
+-- Actually we can have a function returned from the lookup but we don't
+-- really use this code so I'm in no hurry.
+
+if lua.getcodepage then
+ local cod, acp, map
+ function os.tocodepage(name)
+ if map == nil then
+ cod, acp = lua.getcodepage()
+ map = cod and cod ~= 65001 and regimes.toregime
+ end
+ return map and map(cod,name) or name
+ end
+else
+ function os.tocodepage(name)
+ return name
+ end
+end
diff --git a/tex/context/base/mkiv/regi-ini.mkiv b/tex/context/base/mkiv/regi-ini.mkiv
index 532a4db0b..fcdc2536f 100644
--- a/tex/context/base/mkiv/regi-ini.mkiv
+++ b/tex/context/base/mkiv/regi-ini.mkiv
@@ -30,4 +30,8 @@
\unexpanded\def\startregime [#1]{\clf_startregime{#1}}
\unexpanded\def\stopregime {\clf_stopregime}
+% only for diagnostics:
+
+\def\codepagename#1{\cldcontext{os.tocodepage("#1")}}
+
\protect \endinput
diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf
index b209ac2ab..f337a1e15 100644
--- a/tex/context/base/mkiv/status-files.pdf
+++ b/tex/context/base/mkiv/status-files.pdf
Binary files differ
diff --git a/tex/context/base/mkiv/status-lua.pdf b/tex/context/base/mkiv/status-lua.pdf
index 2b57a46fb..4825b13c7 100644
--- a/tex/context/base/mkiv/status-lua.pdf
+++ b/tex/context/base/mkiv/status-lua.pdf
Binary files differ
diff --git a/tex/context/base/mkiv/strc-itm.mklx b/tex/context/base/mkiv/strc-itm.mklx
index e5458b5dd..c456bf470 100644
--- a/tex/context/base/mkiv/strc-itm.mklx
+++ b/tex/context/base/mkiv/strc-itm.mklx
@@ -961,23 +961,23 @@
% symbols + states
\def\strc_itemgroups_store_global_symbol#symbol%
- {\letgvalue{\??itemgroupglobal\currentitemlevel}#symbol}
+ {\letgvalue{\??itemgroupglobal\currentitemgroup:\currentitemlevel}#symbol}
\def\strc_itemgroups_store_local_symbol#symbol%
- {\letgvalue{\??itemgrouplocal\currentitemlevel}#symbol}
+ {\letgvalue{\??itemgrouplocal\currentitemgroup:\currentitemlevel}#symbol}
\def\strc_itemgroups_fetch_global_symbol
- {\csname\??itemgroupglobal\currentitemlevel\endcsname}
+ {\csname\??itemgroupglobal\currentitemgroup:\currentitemlevel\endcsname}
\def\strc_itemgroups_fetch_local_symbol
- {\csname\??itemgrouplocal\currentitemlevel\endcsname}
+ {\csname\??itemgrouplocal\currentitemgroup:\currentitemlevel\endcsname}
\def\strc_itemgroups_setup_symbol_default
{\edef\strc_itemgroups_asked_symbol{\itemgroupparameter\c!symbol}%
\strc_itemgroups_store_global_symbol\empty}
\def\strc_itemgroups_setup_symbol_continue
- {\ifcsname\??itemgroupglobal\currentitemlevel\endcsname
+ {\ifcsname\??itemgroupglobal\currentitemgroup:\currentitemlevel\endcsname
\let\strc_itemgroups_asked_symbol\strc_itemgroups_fetch_global_symbol
\else
\let\strc_itemgroups_asked_symbol\currentitemlevel
@@ -1859,4 +1859,26 @@
\defineitemgroup
[\v!itemize]
+%D This is really ugly I should get rid of the global mess, whuch is a side
+%D effect of the simple \type {\item} interface that we're stuck with for
+%D compatibility reasons. See footnotes for usage. It's probablynot robust
+%D for mixed itemgroups so in the end I need to get rid of the globals. One
+%D problem is that counters are set.
+
+\defineitemgroup
+ [\v!itemize:\v!note]
+
+\def\strc_itemgroups_push
+ {\edef\strc_itemgroups_pop
+ {\xdef\noexpand\currentitemlevel{\currentitemlevel}%
+ \global\c_strc_itemgroups_nesting \the\c_strc_itemgroups_nesting \relax
+ \global\c_strc_itemgroups_column_depth\the\c_strc_itemgroups_column_depth\relax}%
+ \global\c_strc_itemgroups_column_depth\zerocount
+ \global\c_strc_itemgroups_nesting \zerocount
+ \glet\currentitemlevel\!!zerocount
+ \unexpanded\def\startitemize{\startitemgroup[\v!itemize:\v!note]}%
+ \unexpanded\def\stopitemize {\stopitemgroup}}
+
+\let\strc_itemgroups_pop\relax
+
\protect \endinput
diff --git a/tex/context/base/mkiv/strc-not.mkvi b/tex/context/base/mkiv/strc-not.mkvi
index f11c831dd..48151c76e 100644
--- a/tex/context/base/mkiv/strc-not.mkvi
+++ b/tex/context/base/mkiv/strc-not.mkvi
@@ -943,11 +943,22 @@
\letvalue{\??notepenalty\v!verystrict}\notepenaltyverystrict
\letvalue{\??notepenalty }\notepenaltytolerant
+% \def\strc_notes_set_width
+% {\edef\p_width{\noteparameter\c!width}%
+% \ifx\p_width\empty
+% \setnoteparameter\c!width{\hsize}%
+% \fi}
+
+\setupnotes
+ [\c!width=\v!auto]
+
\def\strc_notes_set_width
{\edef\p_width{\noteparameter\c!width}%
- \ifx\p_width\empty
+ \ifx\p_width\v!auto
+ \setnoteparameter\c!width{\ifdim\hsize<\makeupwidth\hsize\else\makeupwidth\fi}%
+ \else\ifx\p_width\empty
\setnoteparameter\c!width{\hsize}%
- \fi}
+ \fi\fi}
\appendtoks
\strc_notes_set_width
@@ -1390,9 +1401,8 @@
%D Nasty, the might be more:
-\appendtoks
- \c_strc_itemgroups_nesting\zerocount
-\to \everyinsidenoteinsert
+\appendtoks \strc_itemgroups_push \to \everybeforenoteinsert
+\appendtoks \strc_itemgroups_pop \to \everyafternoteinsert
% maybe but better use [scope=local] here
%
diff --git a/tex/context/base/mkiv/strc-tag.lua b/tex/context/base/mkiv/strc-tag.lua
index 0453640ca..88e0f108d 100644
--- a/tex/context/base/mkiv/strc-tag.lua
+++ b/tex/context/base/mkiv/strc-tag.lua
@@ -124,10 +124,18 @@ local properties = allocate { -- todo: more "record = true" to improve forma
table = { pdf = "Table", nature = "display" },
tablerow = { pdf = "TR", nature = "display" },
tablecell = { pdf = "TD", nature = "mixed" },
+ tableheadcell = { pdf = "TH", nature = "mixed" },
+ tablehead = { pdf = "THEAD", nature = "display" },
+ tablebody = { pdf = "TBODY", nature = "display" },
+ tablefoot = { pdf = "TFOOT", nature = "display" },
tabulate = { pdf = "Table", nature = "display" },
tabulaterow = { pdf = "TR", nature = "display" },
tabulatecell = { pdf = "TD", nature = "mixed" },
+ tabulateheadcell = { pdf = "TH", nature = "mixed" },
+ tabulatehead = { pdf = "THEAD", nature = "display" },
+ tabulatebody = { pdf = "TBODY", nature = "display" },
+ tabulatefoot = { pdf = "TFOOT", nature = "display" },
list = { pdf = "TOC", nature = "display" },
listitem = { pdf = "TOCI", nature = "display" },
diff --git a/tex/context/base/mkiv/strc-tag.mkiv b/tex/context/base/mkiv/strc-tag.mkiv
index 621a54040..021245f29 100644
--- a/tex/context/base/mkiv/strc-tag.mkiv
+++ b/tex/context/base/mkiv/strc-tag.mkiv
@@ -83,9 +83,19 @@
\def\t!table {table} % Table
\def\t!tablerow {tablerow} % TR
\def\t!tablecell {tablecell} % TD
+\def\t!tableheadcell {tableheadcell} % TH
+\def\t!tablehead {tablehead} % THEAD
+\def\t!tablebody {tablebody} % TBODY
+\def\t!tablefoot {tablefoot} % TFOOT
+
+
\def\t!tabulate {tabulate} % Table
\def\t!tabulaterow {tabulaterow} % TR
\def\t!tabulatecell {tabulatecell} % TD
+\def\t!tabulateheadcell {tabulateheadcell} % TH
+\def\t!tabulatehead {tabulatehead} % THEAD
+\def\t!tabulatebody {tabulatebody} % TBODY
+\def\t!tabulatefoot {tabulatefoot} % TFOOT
\def\t!math {math} % math
\def\t!mathtable {mtable} % Table
diff --git a/tex/context/base/mkiv/syst-ini.mkxl b/tex/context/base/mkiv/syst-ini.mkxl
index 22b3ba039..0befec48c 100644
--- a/tex/context/base/mkiv/syst-ini.mkxl
+++ b/tex/context/base/mkiv/syst-ini.mkxl
@@ -370,6 +370,7 @@
\newdimen\scratchwidth
\newdimen\scratchheight
\newdimen\scratchdepth
+\newdimen\scratchtotal
\newdimen\scratchoffset
\newdimen\scratchleftoffset
diff --git a/tex/context/base/mkiv/tabl-ntb.mkiv b/tex/context/base/mkiv/tabl-ntb.mkiv
index 113b7a364..8162f3964 100644
--- a/tex/context/base/mkiv/tabl-ntb.mkiv
+++ b/tex/context/base/mkiv/tabl-ntb.mkiv
@@ -200,6 +200,13 @@
\newbox\b_tabl_ntb_final
+%D For tagging and export:
+
+\newconstant \c_tabl_ntb_head
+\newconstant \c_tabl_ntb_body
+\newconstant \c_tabl_ntb_foot
+\newconditional \c_tabl_ntb_okay
+
%D We have already prepared the previous macros for nesting, so we only have to pop
%D in the right ones:
@@ -1007,19 +1014,30 @@
\unexpanded\def\eTABLE % beware, we need to get rid of spurious spaces when in hmode
{% tricky and dirty order -)
+ \setfalse\c_tabl_ntb_okay
+ % head
\doifelsesometoks\t_tabl_ntb_head % slow, better a flag
- {\the\t_tabl_ntb_head
+ {\c_tabl_ntb_head\numexpr\c_tabl_ntb_maximum_row+\plusone\relax
+ \the\t_tabl_ntb_head
\c_tabl_ntb_n_of_head_lines\c_tabl_ntb_maximum_row\relax
\doifelsesometoks\t_tabl_ntb_next
{\the\t_tabl_ntb_next
\c_tabl_ntb_n_of_next_lines\numexpr\c_tabl_ntb_maximum_row-\c_tabl_ntb_n_of_head_lines\relax}%
{\c_tabl_ntb_n_of_next_lines\zerocount}% was 1
\c_tabl_ntb_n_of_hdnx_lines\c_tabl_ntb_maximum_row}
- {\c_tabl_ntb_n_of_head_lines\zerocount % was 1
+ {\c_tabl_ntb_head\zerocount
+ \c_tabl_ntb_n_of_head_lines\zerocount % was 1
\c_tabl_ntb_n_of_next_lines\zerocount
\c_tabl_ntb_n_of_hdnx_lines\zerocount}%
+ % body
+ \c_tabl_ntb_body\numexpr\c_tabl_ntb_maximum_row+\plusone\relax
\the\t_tabl_ntb_body
- \the\t_tabl_ntb_foot
+ % foot
+ \doifelsesometoks\t_tabl_ntb_foot
+ {\c_tabl_ntb_foot\numexpr\c_tabl_ntb_maximum_row+\plusone\relax
+ \the\t_tabl_ntb_foot}%
+ {\c_tabl_ntb_foot\zerocount}%
+ % done
\removeunwantedspaces % only if hmode
% finish cells
\tabl_ntb_loop_one
@@ -1235,19 +1253,65 @@
\let\m_tabl_ntb_saved_row\!!zerocount
\let\m_tabl_ntb_saved_col\!!zerocount
+\def\tabl_ntb_start_tagged
+ {\scratchcounter\numexpr\c_tabl_ntb_row+\plusone\relax
+ \ifnum\scratchcounter=\c_tabl_ntb_head
+ \ifconditional\c_tabl_ntb_okay
+ \dostoptagged
+ \else
+ \settrue\c_tabl_ntb_okay
+ \fi
+ \dostarttagged\t!tablehead\empty
+ \else\ifnum\scratchcounter=\c_tabl_ntb_body
+ \ifconditional\c_tabl_ntb_okay
+ \dostoptagged
+ \else
+ \settrue\c_tabl_ntb_okay
+ \fi
+ \dostarttagged\t!tablebody\empty
+ \else\ifnum\scratchcounter=\c_tabl_ntb_foot
+ \ifconditional\c_tabl_ntb_okay
+ \dostoptagged
+ \else
+ \settrue\c_tabl_ntb_okay
+ \fi
+ \dostarttagged\t!tablefoot\empty
+ \fi\fi\fi
+ \dostarttagged\t!tablerow\empty}
+
+\def\tabl_ntb_stop_tagged
+ {\dostoptagged
+ \ifconditional\c_tabl_ntb_okay
+ \scratchcounter\numexpr\c_tabl_ntb_row+\plustwo\relax
+ \ifnum\scratchcounter=\c_tabl_ntb_body
+ \dostoptagged
+ \setfalse\c_tabl_ntb_okay
+ \else\ifnum\scratchcounter=\c_tabl_ntb_foot
+ \dostoptagged
+ \setfalse\c_tabl_ntb_okay
+ \else\ifnum\scratchcounter>\c_tabl_ntb_maximum_row
+ \dostoptagged
+ \setfalse\c_tabl_ntb_okay
+ \fi\fi\fi
+ \fi}
+
\unexpanded\def\tabl_ntb_row_align_start
{\global\advance\c_tabl_ntb_row\plusone
\global\c_tabl_ntb_col\plusone
\global\c_tabl_ntb_spn\zerocount
\tabl_ntb_row_align_start_inject
- \dostarttagged\t!tablerow\empty
+ \ifconditional\c_strc_tags_enabled
+ \tabl_ntb_start_tagged
+ \fi
\hbox\bgroup
\kern\dimexpr\d_tabl_ntb_leftmargindistance\relax}
\unexpanded\def\tabl_ntb_row_align_stop
{\kern\dimexpr\d_tabl_ntb_rightmargindistance-\d_tabl_ntb_columndistance\relax
\egroup
- \dostoptagged
+ \ifconditional\c_strc_tags_enabled
+ \tabl_ntb_stop_tagged
+ \fi
\tabl_ntb_row_align_stop_inject}
\unexpanded\def\tabl_ntb_before_page
diff --git a/tex/context/base/mkiv/tabl-ntb.mkxl b/tex/context/base/mkiv/tabl-ntb.mkxl
index d7ba548d2..6b84411b2 100644
--- a/tex/context/base/mkiv/tabl-ntb.mkxl
+++ b/tex/context/base/mkiv/tabl-ntb.mkxl
@@ -198,6 +198,13 @@
\newbox\b_tabl_ntb_final
+%D For tagging and export:
+
+\newconstant \c_tabl_ntb_head
+\newconstant \c_tabl_ntb_body
+\newconstant \c_tabl_ntb_foot
+\newconditional \c_tabl_ntb_okay
+
%D We have already prepared the previous macros for nesting, so we only have to pop
%D in the right ones:
@@ -1005,19 +1012,30 @@
\unexpanded\def\eTABLE % beware, we need to get rid of spurious spaces when in hmode
{% tricky and dirty order -)
+ \setfalse\c_tabl_ntb_okay
+ % head
\doifelsesometoks\t_tabl_ntb_head % slow, better a flag
- {\the\t_tabl_ntb_head
+ {\c_tabl_ntb_head\numexpr\c_tabl_ntb_maximum_row+\plusone\relax
+ \the\t_tabl_ntb_head
\c_tabl_ntb_n_of_head_lines\c_tabl_ntb_maximum_row\relax
\doifelsesometoks\t_tabl_ntb_next
{\the\t_tabl_ntb_next
\c_tabl_ntb_n_of_next_lines\numexpr\c_tabl_ntb_maximum_row-\c_tabl_ntb_n_of_head_lines\relax}%
{\c_tabl_ntb_n_of_next_lines\zerocount}% was 1
\c_tabl_ntb_n_of_hdnx_lines\c_tabl_ntb_maximum_row}
- {\c_tabl_ntb_n_of_head_lines\zerocount % was 1
+ {\c_tabl_ntb_head\zerocount
+ \c_tabl_ntb_n_of_head_lines\zerocount % was 1
\c_tabl_ntb_n_of_next_lines\zerocount
\c_tabl_ntb_n_of_hdnx_lines\zerocount}%
+ % body
+ \c_tabl_ntb_body\numexpr\c_tabl_ntb_maximum_row+\plusone\relax
\the\t_tabl_ntb_body
- \the\t_tabl_ntb_foot
+ % foot
+ \doifelsesometoks\t_tabl_ntb_foot
+ {\c_tabl_ntb_foot\numexpr\c_tabl_ntb_maximum_row+\plusone\relax
+ \the\t_tabl_ntb_foot}%
+ {\c_tabl_ntb_foot\zerocount}%
+ % done
\removeunwantedspaces % only if hmode
% finish cells
\tabl_ntb_loop_one
@@ -1233,19 +1251,65 @@
\let\m_tabl_ntb_saved_row\!!zerocount
\let\m_tabl_ntb_saved_col\!!zerocount
+\def\tabl_ntb_start_tagged
+ {\scratchcounter\numexpr\c_tabl_ntb_row+\plusone\relax
+ \ifnum\scratchcounter=\c_tabl_ntb_head
+ \ifconditional\c_tabl_ntb_okay
+ \dostoptagged
+ \else
+ \settrue\c_tabl_ntb_okay
+ \fi
+ \dostarttagged\t!tablehead\empty
+ \orelse\ifnum\scratchcounter=\c_tabl_ntb_body
+ \ifconditional\c_tabl_ntb_okay
+ \dostoptagged
+ \else
+ \settrue\c_tabl_ntb_okay
+ \fi
+ \dostarttagged\t!tablebody\empty
+ \orelse\ifnum\scratchcounter=\c_tabl_ntb_foot
+ \ifconditional\c_tabl_ntb_okay
+ \dostoptagged
+ \else
+ \settrue\c_tabl_ntb_okay
+ \fi
+ \dostarttagged\t!tablefoot\empty
+ \fi
+ \dostarttagged\t!tablerow\empty}
+
+\def\tabl_ntb_stop_tagged
+ {\dostoptagged
+ \ifconditional\c_tabl_ntb_okay
+ \scratchcounter\numexpr\c_tabl_ntb_row+\plustwo\relax
+ \ifnum\scratchcounter=\c_tabl_ntb_body
+ \dostoptagged
+ \setfalse\c_tabl_ntb_okay
+ \orelse\ifnum\scratchcounter=\c_tabl_ntb_foot
+ \dostoptagged
+ \setfalse\c_tabl_ntb_okay
+ \orelse\ifnum\scratchcounter>\c_tabl_ntb_maximum_row
+ \dostoptagged
+ \setfalse\c_tabl_ntb_okay
+ \fi
+ \fi}
+
\unexpanded\def\tabl_ntb_row_align_start
{\global\advance\c_tabl_ntb_row\plusone
\global\c_tabl_ntb_col\plusone
\global\c_tabl_ntb_spn\zerocount
\tabl_ntb_row_align_start_inject
- \dostarttagged\t!tablerow\empty
+ \ifconditional\c_strc_tags_enabled
+ \tabl_ntb_start_tagged
+ \fi
\hbox\bgroup
\kern\dimexpr\d_tabl_ntb_leftmargindistance\relax}
\unexpanded\def\tabl_ntb_row_align_stop
{\kern\dimexpr\d_tabl_ntb_rightmargindistance-\d_tabl_ntb_columndistance\relax
\egroup
- \dostoptagged
+ \ifconditional\c_strc_tags_enabled
+ \tabl_ntb_stop_tagged
+ \fi
\tabl_ntb_row_align_stop_inject}
\unexpanded\def\tabl_ntb_before_page
diff --git a/tex/context/base/mkiv/typo-chr.mkiv b/tex/context/base/mkiv/typo-chr.mkiv
index 365c79e51..7da783ceb 100644
--- a/tex/context/base/mkiv/typo-chr.mkiv
+++ b/tex/context/base/mkiv/typo-chr.mkiv
@@ -1,4 +1,3 @@
-
%D \module
%D [ file=typo-chr,
%D version=2015.01.01, % or about that time
diff --git a/tex/context/base/mkiv/typo-del.mkiv b/tex/context/base/mkiv/typo-del.mkiv
index 2ce98841e..9320c37ee 100644
--- a/tex/context/base/mkiv/typo-del.mkiv
+++ b/tex/context/base/mkiv/typo-del.mkiv
@@ -674,22 +674,29 @@
\dostoptagged}
\def\typo_delimited_nextleft_symbol#1%
- {\localleftbox\bgroup
+ {\let\typo_delimited_reset_next_symbol\typo_delimited_reset_next_symbol_indeed
+ \localleftbox\bgroup
\swapmacros\leftboundarycharacter\rightboundarycharacter
\boundarycharactermode\plusone
\typo_delimited_left_symbol#1%
\egroup}
\def\typo_delimited_nextright_symbol#1%
- {\localrightbox\bgroup
+ {\let\typo_delimited_reset_next_symbol\typo_delimited_reset_next_symbol_indeed
+ \localrightbox\bgroup
\swapmacros\leftboundarycharacter\rightboundarycharacter
\boundarycharactermode\plusone
\typo_delimited_right_symbol#1%
\egroup}
+\unexpanded\def\typo_delimited_reset_next_symbol_indeed
+ {\localleftbox {}%
+ \localrightbox{}}%
+
+\let\typo_delimited_reset_next_symbol\relax
+
\appendtoks
- \localleftbox {}%
- \localrightbox{}%
+ \typo_delimited_reset_next_symbol
\to \everyforgetall
% \starttext
diff --git a/tex/context/interface/mkiv/i-context.pdf b/tex/context/interface/mkiv/i-context.pdf
index df76d474e..966b2ae73 100644
--- a/tex/context/interface/mkiv/i-context.pdf
+++ b/tex/context/interface/mkiv/i-context.pdf
Binary files differ
diff --git a/tex/context/interface/mkiv/i-readme.pdf b/tex/context/interface/mkiv/i-readme.pdf
index 99f21c336..f65eb65f8 100644
--- a/tex/context/interface/mkiv/i-readme.pdf
+++ b/tex/context/interface/mkiv/i-readme.pdf
Binary files differ
diff --git a/tex/context/modules/common/s-abbreviations-logos.tex b/tex/context/modules/common/s-abbreviations-logos.tex
index 9cf7085f5..81fb060d8 100644
--- a/tex/context/modules/common/s-abbreviations-logos.tex
+++ b/tex/context/modules/common/s-abbreviations-logos.tex
@@ -146,6 +146,7 @@
\logo [INITEX] {ini\TeXsuffix}
\logo [INRSTEX] {inrs\TeXsuffix}
\logo [IO] {io}
+\logo [INKSCAPE] {Inkscape}
\logo [IRCNET] {IRCnet}
\logo [ISO] {iso}
\logo [JAVA] {Java}
@@ -335,6 +336,7 @@
%logo [WINNX] {Win9x}
\logo [WTHREEC] {W3C}
\logo [WWW] {www}
+\logo [WIKIPEDIA] {Wikipedia} % WikipediA (looks too weird)
\logo [WYSIWYG] {wysiwyg}
%logo [XDVI] {Xdvi}
\logo [XETEX] {\XeTeX}