summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkiv')
-rw-r--r--tex/context/base/mkiv/back-pdf.mkiv6
-rw-r--r--tex/context/base/mkiv/back-pdf.mkxl8
-rw-r--r--tex/context/base/mkiv/back-pdp.lua15
-rw-r--r--tex/context/base/mkiv/cldf-ini.lua4
-rw-r--r--tex/context/base/mkiv/cldf-scn.lua3
-rw-r--r--tex/context/base/mkiv/colo-ini.mkiv6
-rw-r--r--tex/context/base/mkiv/colo-ini.mkxl6
-rw-r--r--tex/context/base/mkiv/cont-new.mkiv2
-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-ini.lua2
-rw-r--r--tex/context/base/mkiv/font-cff.lua5
-rw-r--r--tex/context/base/mkiv/font-con.lua77
-rw-r--r--tex/context/base/mkiv/font-ctx.lua4
-rw-r--r--tex/context/base/mkiv/font-def.lua3
-rw-r--r--tex/context/base/mkiv/font-dsp.lua2
-rw-r--r--tex/context/base/mkiv/font-imp-italics.lua46
-rw-r--r--tex/context/base/mkiv/font-lib.mkvi10
-rw-r--r--tex/context/base/mkiv/font-ocl.lua117
-rw-r--r--tex/context/base/mkiv/font-ocm.lua874
-rw-r--r--tex/context/base/mkiv/font-otr.lua115
-rw-r--r--tex/context/base/mkiv/font-ott.lua38
-rw-r--r--tex/context/base/mkiv/font-shp.lua127
-rw-r--r--tex/context/base/mkiv/grph-con.lua23
-rw-r--r--tex/context/base/mkiv/grph-trf.lua125
-rw-r--r--tex/context/base/mkiv/grph-trf.mkiv163
-rw-r--r--tex/context/base/mkiv/lpdf-lmt.lua24
-rw-r--r--tex/context/base/mkiv/math-ini.mkiv71
-rw-r--r--tex/context/base/mkiv/math-rad.mkvi32
-rw-r--r--tex/context/base/mkiv/mlib-ctx.mkxl1
-rw-r--r--tex/context/base/mkiv/mlib-ran.lua237
-rw-r--r--tex/context/base/mkiv/mult-prm.lua2
-rw-r--r--tex/context/base/mkiv/node-res.lua10
-rw-r--r--tex/context/base/mkiv/spac-par.mkiv36
-rw-r--r--tex/context/base/mkiv/status-files.pdfbin27765 -> 27723 bytes
-rw-r--r--tex/context/base/mkiv/status-lua.pdfbin251365 -> 251531 bytes
-rw-r--r--tex/context/base/mkiv/supp-ran.lua2
-rw-r--r--tex/context/base/mkiv/syst-aux.lua55
-rw-r--r--tex/context/base/mkiv/toks-ini.lua3
-rw-r--r--tex/context/base/mkiv/toks-scn.lua19
-rw-r--r--tex/context/base/mkiv/typo-del.mkiv6
-rw-r--r--tex/context/base/mkiv/util-tab.lua9
42 files changed, 1735 insertions, 557 deletions
diff --git a/tex/context/base/mkiv/back-pdf.mkiv b/tex/context/base/mkiv/back-pdf.mkiv
index ec1c641e6..697aa311f 100644
--- a/tex/context/base/mkiv/back-pdf.mkiv
+++ b/tex/context/base/mkiv/back-pdf.mkiv
@@ -65,9 +65,9 @@
\unexpanded\def\pdflastobj {\numexpr\clf_pdflastobj\relax}
\unexpanded\def\pdfrefobj {\clf_pdfrefobj }
-\unexpanded\def\pdfrestore {\clf_restore}
-\unexpanded\def\pdfsave {\clf_save}
-\unexpanded\def\pdfsetmatrix{\clf_setmatrix}
+\unexpanded\def\pdfrestore {\pdfextension restore}
+\unexpanded\def\pdfsave {\pdfextension save}
+\unexpanded\def\pdfsetmatrix{\pdfextension setmatrix}
\let\pdfxform \saveboxresource
\let\pdflastxform \lastsavedboxresourceindex
diff --git a/tex/context/base/mkiv/back-pdf.mkxl b/tex/context/base/mkiv/back-pdf.mkxl
index ab65458c5..6538a8309 100644
--- a/tex/context/base/mkiv/back-pdf.mkxl
+++ b/tex/context/base/mkiv/back-pdf.mkxl
@@ -65,11 +65,11 @@
\unexpanded\def\pdfliteral {\clf_pdfliteral}
\unexpanded\def\pdfobj {\clf_pdfobj}%
\unexpanded\def\pdflastobj {\numexpr\clf_pdflastobj\relax}
-\unexpanded\def\pdfrefobj {\clf_pdfrefobj }
+\unexpanded\def\pdfrefobj {\clf_pdfrefobj}
-\unexpanded\def\pdfrestore {\clf_restore}
-\unexpanded\def\pdfsave {\clf_save}
-\unexpanded\def\pdfsetmatrix{\clf_setmatrix}
+\unexpanded\def\pdfrestore {\pdfextension restore}
+\unexpanded\def\pdfsave {\pdfextension save}
+\unexpanded\def\pdfsetmatrix{\pdfextension setmatrix}
\let\pdfxform \saveboxresource
\let\pdflastxform \lastsavedboxresourceindex
diff --git a/tex/context/base/mkiv/back-pdp.lua b/tex/context/base/mkiv/back-pdp.lua
index 6111cf469..6e663f1dd 100644
--- a/tex/context/base/mkiv/back-pdp.lua
+++ b/tex/context/base/mkiv/back-pdp.lua
@@ -273,9 +273,12 @@ implement { name = "pdffeedback", actions = pdffeedback }
-- for the moment (tikz)
-implement { name = "pdfliteral", actions = pdfliteral }
-implement { name = "pdfobj", actions = pdfobj }
-implement { name = "pdflastobj", actions = pdflastobj }
-implement { name = "pdfrefobj", actions = pdfrefobj }
---------- { name = "pdfannot", actions = pdfannot }
---------- { name = "pdfdest", actions = pdfdest }
+implement { name = "pdfliteral", actions = pdfliteral }
+implement { name = "pdfobj", actions = pdfobj }
+implement { name = "pdflastobj", actions = pdflastobj }
+implement { name = "pdfrefobj", actions = pdfrefobj }
+--------- { name = "pdfannot", actions = pdfannot }
+--------- { name = "pdfdest", actions = pdfdest }
+--------- { name = "pdfsave", actions = pdfsave }
+--------- { name = "pdfrestore", actions = pdfrestore }
+--------- { name = "pdfsetmatrix", actions = pdfsetmatrix }
diff --git a/tex/context/base/mkiv/cldf-ini.lua b/tex/context/base/mkiv/cldf-ini.lua
index 56cbfe3fa..5f33f9c2a 100644
--- a/tex/context/base/mkiv/cldf-ini.lua
+++ b/tex/context/base/mkiv/cldf-ini.lua
@@ -392,7 +392,7 @@ local interfacescanners = setmetatablenewindex(function(t,k,v)
-- rawset(t,k,v)
end)
-function interfaces.registerscanner(name,action,protected,public,call)
+function interfaces.registerscanner(name,action,protected,public,valuetype)
rawset(interfacescanners,name,action)
if storedscanners[name] then
-- report_cld("warning: scanner %a is already set (mode 2a)",name)
@@ -405,7 +405,7 @@ function interfaces.registerscanner(name,action,protected,public,call)
local n = registerfunction("interfaces.scanners."..name,true)
storedscanners[name] = n
local name = public and name or ("clf_" .. name)
- setluatoken(name,n,"global",protected and "protected" or "")
+ setluatoken(name,n,"global",protected and "protected" or "",valuetype or "")
else
storedscanners[name] = true
-- report_cld("installing interface scanner: %s (mode 2c)",name)
diff --git a/tex/context/base/mkiv/cldf-scn.lua b/tex/context/base/mkiv/cldf-scn.lua
index d0b16e034..d79383866 100644
--- a/tex/context/base/mkiv/cldf-scn.lua
+++ b/tex/context/base/mkiv/cldf-scn.lua
@@ -77,8 +77,7 @@ function interfaces.implement(specification)
if scanners[name] and not specification.overload then
report("warning: 'scanners.%s' is redefined",name)
end
- -- scanners[name] = scanner -- we now use:
- register(name,scanner,specification.protected,specification.public,specification.call)
+ register(name,scanner,specification.protected,specification.public,specification.valuetype)
if private then
return
end
diff --git a/tex/context/base/mkiv/colo-ini.mkiv b/tex/context/base/mkiv/colo-ini.mkiv
index c489635de..71c823f8a 100644
--- a/tex/context/base/mkiv/colo-ini.mkiv
+++ b/tex/context/base/mkiv/colo-ini.mkiv
@@ -1380,7 +1380,11 @@
% \normal added else fails in metafun manual (leaders do a hard scan)
-\unexpanded\def\forcecolorhack{\leaders\hrule\hskip\zeropoint\relax} % relax is needed !
+% \unexpanded\def\forcecolorhack{\leaders\hrule\hskip\zeropoint\relax} % relax is needed !
+%
+% I really need to sort this out!
+
+\unexpanded\def\forcecolorhack{\leaders\hrule height\zeropoint depth\zeropoint\hskip\zeropoint\relax} % relax is needed !
%D We default to the colors defined in \type {colo-imp-rgb} and
%D support both \RGB\ and \CMYK\ output. Transparencies are defined
diff --git a/tex/context/base/mkiv/colo-ini.mkxl b/tex/context/base/mkiv/colo-ini.mkxl
index e821fb7e2..47d6cc8a1 100644
--- a/tex/context/base/mkiv/colo-ini.mkxl
+++ b/tex/context/base/mkiv/colo-ini.mkxl
@@ -1322,7 +1322,11 @@
% \normal added else fails in metafun manual (leaders do a hard scan)
-\unexpanded\def\forcecolorhack{\leaders\hrule\hskip\zeropoint\relax} % relax is needed !
+% \unexpanded\def\forcecolorhack{\leaders\hrule\hskip\zeropoint\relax} % relax is needed !
+%
+% I really need to sort this out!
+
+\unexpanded\def\forcecolorhack{\leaders\hrule height\zeropoint depth\zeropoint\hskip\zeropoint\relax} % relax is needed !
%D We default to the colors defined in \type {colo-imp-rgb} and
%D support both \RGB\ and \CMYK\ output. Transparencies are defined
diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv
index 9ce4dacf5..f8c96cab7 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{2020.04.30 11:10}
+\newcontextversion{2020.05.07 10:57}
%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.mkiv b/tex/context/base/mkiv/context.mkiv
index 6f17f2868..d7310826b 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{2020.04.30 11:10}
+\edef\contextversion{2020.05.07 10:57}
\edef\contextkind {beta}
%D Kind of special:
diff --git a/tex/context/base/mkiv/context.mkxl b/tex/context/base/mkiv/context.mkxl
index 4bdb96da8..7ad162369 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{2020.04.30 11:10}
+\edef\contextversion{2020.05.07 10:57}
\edef\contextkind {beta}
%D Kind of special:
diff --git a/tex/context/base/mkiv/data-ini.lua b/tex/context/base/mkiv/data-ini.lua
index 2e9010085..3c1531019 100644
--- a/tex/context/base/mkiv/data-ini.lua
+++ b/tex/context/base/mkiv/data-ini.lua
@@ -75,6 +75,7 @@ end
do
+ local oldhome = osgetenv('HOME')
local homedir = osgetenv(ostype == "windows" and 'USERPROFILE' or 'HOME') or ''
if not homedir or homedir == "" then
@@ -86,6 +87,7 @@ do
ossetenv("HOME", homedir) -- can be used in unix cnf files
ossetenv("USERPROFILE",homedir) -- can be used in windows cnf files
+ environment.oldhome = oldhome
environment.homedir = homedir
end
diff --git a/tex/context/base/mkiv/font-cff.lua b/tex/context/base/mkiv/font-cff.lua
index 72b0a038f..627847efa 100644
--- a/tex/context/base/mkiv/font-cff.lua
+++ b/tex/context/base/mkiv/font-cff.lua
@@ -612,6 +612,9 @@ do
parsedictionaries = function(data,dictionaries,what)
stack = { }
strings = data.strings
+ if trace_charstrings then
+ report("charstring format %a",what)
+ end
for i=1,#dictionaries do
top = 0
result = what == "cff" and {
@@ -1517,7 +1520,7 @@ do
end
end
else
- -- error
+ top = top - nofregions * n
end
end
diff --git a/tex/context/base/mkiv/font-con.lua b/tex/context/base/mkiv/font-con.lua
index 1bb63aa51..04c42061e 100644
--- a/tex/context/base/mkiv/font-con.lua
+++ b/tex/context/base/mkiv/font-con.lua
@@ -210,60 +210,45 @@ end
-- we default to false, so a macro package has to enable it explicitly. In
-- LuaTeX the fullname is used to identify a font as being unique.
-constructors.sharefonts = false
-constructors.nofsharedfonts = 0
-local sharednames = { }
+local nofinstances = 0
+local instances = setmetatableindex(function(t,k)
+ nofinstances = nofinstances + 1
+ t[k] = nofinstances
+ return nofinstances
+end)
function constructors.trytosharefont(target,tfmdata)
- if constructors.sharefonts then -- not robust !
- local characters = target.characters
- local n = 1
- local t = { target.psname }
- local u = sortedkeys(characters)
- for i=1,#u do
- local k = u[i]
- n = n + 1 ; t[n] = k
- n = n + 1 ; t[n] = characters[k].index or k
+ local properties = target.properties
+ local instance = properties.instance
+ if instance then
+ local fullname = target.fullname
+ local fontname = target.fontname
+ local psname = target.psname
+ local format = tfmdata.properties.format
+ if format == "opentype" then
+ target.streamprovider = 1
+ elseif format == "truetype" then
+ target.streamprovider = 2
+ else
+ target.streamprovider = 0
end
- local h = md5.HEX(concat(t," "))
- local s = sharednames[h]
- if s then
- if trace_defining then
- report_defining("font %a uses backend resources of font %a",target.fullname,s)
+ if target.streamprovider > 0 then
+ if fullname then
+ fullname = fullname .. ":" .. instances[instance]
+ target.fullname = fullname
+ end
+ if fontname then
+ fontname = fontname .. ":" .. instances[instance]
+ target.fontname = fontname
+ end
+ if psname then
+ psname = psname .. ":" .. instances[instance]
+ target.psname = psname
end
- target.fullname = s
- constructors.nofsharedfonts = constructors.nofsharedfonts + 1
- target.properties.sharedwith = s
- else
- sharednames[h] = target.fullname
end
end
end
--- function constructors.enhanceparameters(parameters)
--- local xheight = parameters.x_height
--- local quad = parameters.quad
--- local space = parameters.space
--- local stretch = parameters.space_stretch
--- local shrink = parameters.space_shrink
--- local extra = parameters.extra_space
--- local slant = parameters.slant
--- -- synonyms
--- parameters.xheight = xheight
--- parameters.spacestretch = stretch
--- parameters.spaceshrink = shrink
--- parameters.extraspace = extra
--- parameters.em = quad
--- parameters.ex = xheight
--- parameters.slantperpoint = slant
--- parameters.spacing = {
--- width = space,
--- stretch = stretch,
--- shrink = shrink,
--- extra = extra,
--- }
--- end
-
local synonyms = {
exheight = "x_height",
xheight = "x_height",
diff --git a/tex/context/base/mkiv/font-ctx.lua b/tex/context/base/mkiv/font-ctx.lua
index 6f8354de8..9e59c66bc 100644
--- a/tex/context/base/mkiv/font-ctx.lua
+++ b/tex/context/base/mkiv/font-ctx.lua
@@ -173,6 +173,7 @@ if CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 then
end
constructors.sharefonts = true -- experimental
+constructors.nofsharedfonts = 0
constructors.nofsharedhashes = 0
constructors.nofsharedvectors = 0
constructors.noffontsloaded = 0
@@ -202,6 +203,7 @@ do
local shares = { }
local hashes = { }
+
local nofinstances = 0
local instances = setmetatableindex(function(t,k)
nofinstances = nofinstances + 1
@@ -240,7 +242,7 @@ do
end
if psname then
-- this one is used for the funny prefix in font names in pdf
- -- so it has ot be kind of unique in order to avoid subset prefix
+ -- so it has to be kind of unique in order to avoid subset prefix
-- clashes being reported
psname = psname .. ":" .. instances[instance]
target.psname = psname
diff --git a/tex/context/base/mkiv/font-def.lua b/tex/context/base/mkiv/font-def.lua
index e287bf79c..09f2e2c32 100644
--- a/tex/context/base/mkiv/font-def.lua
+++ b/tex/context/base/mkiv/font-def.lua
@@ -207,9 +207,6 @@ function resolvers.name(specification)
features.normal = normal
end
normal.instance = instance
- -- if not callbacks.supported.glyph_stream_provider then
- -- normal.variableshapes = true -- for the moment
- -- end
end
--
local suffix = lower(suffixonly(resolved))
diff --git a/tex/context/base/mkiv/font-dsp.lua b/tex/context/base/mkiv/font-dsp.lua
index 3058be37b..f8794bcde 100644
--- a/tex/context/base/mkiv/font-dsp.lua
+++ b/tex/context/base/mkiv/font-dsp.lua
@@ -302,7 +302,7 @@ end)
-- values can be anything the min/max permits so we can either think of
-- real values of a fraction along the axis (probably easier)
--- wght:400,wdth:100,ital:1
+-- wght=400,wdth=100,ital=1
local function axistofactors(str)
local t = settings_to_hash(str)
diff --git a/tex/context/base/mkiv/font-imp-italics.lua b/tex/context/base/mkiv/font-imp-italics.lua
index 83c785d38..3e172bede 100644
--- a/tex/context/base/mkiv/font-imp-italics.lua
+++ b/tex/context/base/mkiv/font-imp-italics.lua
@@ -79,33 +79,25 @@ if context then
registerotffeature(specification)
registerafmfeature(specification)
-end
-
--- no longer used
-
--- if context then
---
--- -- local function initializemathitalics(tfmdata,value) -- yes no delay
--- -- tfmdata.properties.mathitalics = toboolean(value)
--- -- end
--- --
--- -- local specification = {
--- -- name = "mathitalics",
--- -- description = "use alternative math italic correction",
--- -- initializers = {
--- -- base = initializemathitalics,
--- -- node = initializemathitalics,
--- -- }
--- -- }
--- --
--- -- registerotffeature(specification)
--- -- registerafmfeature(specification)
---
--- end
-
--- -- also not used, only when testing
-
-if context then
+ -- no longer used
+
+ -- local function initializemathitalics(tfmdata,value) -- yes no delay
+ -- tfmdata.properties.mathitalics = toboolean(value)
+ -- end
+ --
+ -- local specification = {
+ -- name = "mathitalics",
+ -- description = "use alternative math italic correction",
+ -- initializers = {
+ -- base = initializemathitalics,
+ -- node = initializemathitalics,
+ -- }
+ -- }
+ --
+ -- registerotffeature(specification)
+ -- registerafmfeature(specification)
+
+ -- only used when testing
local letter = characters.is_letter
local always = true
diff --git a/tex/context/base/mkiv/font-lib.mkvi b/tex/context/base/mkiv/font-lib.mkvi
index b2f42f0c2..133143224 100644
--- a/tex/context/base/mkiv/font-lib.mkvi
+++ b/tex/context/base/mkiv/font-lib.mkvi
@@ -50,12 +50,12 @@
%registerctxluafile{font-osm}{}
\ifcase\contextlmtxmode
- \ifnum\luatexversion>111
- \doifelsefileexists{font-ocm.lua}
- {\registerctxluafile{font-ocm}{}} % mkiv new
- {\registerctxluafile{font-ocl}{}}
+ \ifcase\directlua{tex.print(callback.list()["provide_charproc_data"] == false and 1 or 0)}\relax
+ % this is the generic variant that will become luatex-fonts-ocl once we have
+ % more recent versions of luatex 1.13/1.14 on the garden
+ \registerctxluafile{font-ocl}{}
\else
- \registerctxluafile{font-ocl}{} % generic (will become luatex-fonts-ocl)
+ \registerctxluafile{font-ocm}{}
\fi
\else
\registerctxluafile{font-ogr}{} % lmtx
diff --git a/tex/context/base/mkiv/font-ocl.lua b/tex/context/base/mkiv/font-ocl.lua
index 1890e5ec5..e6a38af5c 100644
--- a/tex/context/base/mkiv/font-ocl.lua
+++ b/tex/context/base/mkiv/font-ocl.lua
@@ -8,10 +8,6 @@ if not modules then modules = { } end modules ['font-ocl'] = {
-- todo : user list of colors
-if CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 then
- return
-end
-
local tostring, tonumber, next = tostring, tonumber, next
local round, max = math.round, math.round
local gsub, find = string.gsub, string.find
@@ -151,85 +147,17 @@ local function convert(t,k)
return v
end
-local start = { "pdf", "mode", "font" } -- force text mode (so get q Q right)
------ stop = { "pdf", "mode", "page" } -- force page mode (else overlap)
-local push = { "pdf", "page", "q" }
-local pop = { "pdf", "page", "Q" }
-
--- -- This one results in color directives inside BT ET but has less q Q pairs. It
--- -- only shows the first glyph in acrobat and nothing more. No problem with other
--- -- renderers.
---
--- local function initializeoverlay(tfmdata,kind,value) -- hm, always value
--- if value then
--- local resources = tfmdata.resources
--- local palettes = resources.colorpalettes
--- if palettes then
--- --
--- local converted = resources.converted
--- if not converted then
--- converted = setmetatableindex(convert)
--- resources.converted = converted
--- end
--- local colorvalues = sharedpalettes[value] or converted[palettes[tonumber(value) or 1] or palettes[1]] or { }
--- local classes = #colorvalues
--- if classes == 0 then
--- return
--- end
--- --
--- local characters = tfmdata.characters
--- local descriptions = tfmdata.descriptions
--- local properties = tfmdata.properties
--- --
--- properties.virtualized = true
--- tfmdata.fonts = {
--- { id = 0 }
--- }
--- --
--- local getactualtext = otf.getactualtext
--- local default = colorvalues[#colorvalues]
--- local b, e = getactualtext(tounicode(0xFFFD))
--- local actualb = { "pdf", "page", b } -- saves tables
--- local actuale = { "pdf", "page", e } -- saves tables
--- --
--- for unicode, character in next, characters do
--- local description = descriptions[unicode]
--- if description then
--- local colorlist = description.colors
--- if colorlist then
--- local u = description.unicode or characters[unicode].unicode
--- local w = character.width or 0
--- local s = #colorlist
--- local goback = w ~= 0 and leftcommand[w] or nil -- needs checking: are widths the same
--- local t = {
--- start,
--- not u and actualb or { "pdf", "page", (getactualtext(tounicode(u))) },
--- push,
--- }
--- local n = 3
--- local l = nil
--- for i=1,s do
--- local entry = colorlist[i]
--- local v = colorvalues[entry.class] or default
--- if v and l ~= v then
--- n = n + 1 t[n] = v
--- l = v
--- end
--- n = n + 1 t[n] = charcommand[entry.slot]
--- if s > 1 and i < s and goback then
--- n = n + 1 t[n] = goback
--- end
--- end
--- n = n + 1 t[n] = pop
--- n = n + 1 t[n] = actuale
--- n = n + 1 t[n] = stop
--- character.commands = t
--- end
--- end
--- end
--- end
--- end
--- end
+-- At some point 'font' mode was added to the engine and we can assume that most distributions
+-- ship a luatex that has it; ancient versions are no longer supported anyway. Begin 2020 there
+-- was an actualtext related mail exchange with RM etc. that might result in similar mode keys
+-- in other tex->pdf programs because there is a bit of inconsistency in the way this is dealt
+-- with. Best is not to touch this code too much.
+
+local mode = { "pdf", "mode", "font" }
+local push = { "pdf", "page", "q" }
+local pop = { "pdf", "page", "Q" }
+
+-- see context git repository for older variant (pre 20200501 cleanup)
local function initializeoverlay(tfmdata,kind,value)
if value then
@@ -278,10 +206,11 @@ local function initializeoverlay(tfmdata,kind,value)
local s = #colorlist
local goback = w ~= 0 and leftcommand[w] or nil -- needs checking: are widths the same
local t = {
+ mode,
not u and actualb or { "pdf", "page", (getactualtext(tounicode(u))) },
push,
}
- local n = 2
+ local n = 3
local l = nil
for i=1,s do
local entry = colorlist[i]
@@ -436,7 +365,7 @@ do
local savedata = io.savedata
local remove = os.remove
- if context and xml.convert then
+if context then
local xmlconvert = xml.convert
local xmlfirst = xml.first
@@ -451,13 +380,13 @@ do
return data
end
- else
+else
function otfsvg.filterglyph(entry,index) -- can be overloaded
return entry.data
end
- end
+end
local runner = sandbox and sandbox.registerrunner {
name = "otfsvg",
@@ -484,6 +413,16 @@ do
-- Because a generic setup can be flawed we need to catch bad inkscape runs which add a bit of
-- ugly overhead. Bah.
+ local new = nil
+
+ local function inkscapeformat(suffix)
+ if new == nil then
+ new = os.resultof("inkscape --version") or ""
+ new = new == "" or not find(new,"Inkscape%s*0")
+ end
+ return new and "filename" or suffix
+ end
+
function otfsvg.topdf(svgshapes,tfmdata)
local pdfshapes = { }
local inkscape = runner()
@@ -493,7 +432,7 @@ do
local nofshapes = #svgshapes
local f_svgfile = formatters["temp-otf-svg-shape-%i.svg"]
local f_pdffile = formatters["temp-otf-svg-shape-%i.pdf"]
- local f_convert = formatters["%s --export-pdf=%s\n"]
+ local f_convert = formatters["%s --export-%s=%s\n"]
local filterglyph = otfsvg.filterglyph
local nofdone = 0
local processed = { }
@@ -507,7 +446,7 @@ do
local svgfile = f_svgfile(index)
local pdffile = f_pdffile(index)
savedata(svgfile,data)
- inkscape:write(f_convert(svgfile,pdffile))
+ inkscape:write(f_convert(svgfile,inkscapeformat("pdf"),pdffile))
processed[index] = true
nofdone = nofdone + 1
if nofdone % 25 == 0 then
diff --git a/tex/context/base/mkiv/font-ocm.lua b/tex/context/base/mkiv/font-ocm.lua
new file mode 100644
index 000000000..131b0ed13
--- /dev/null
+++ b/tex/context/base/mkiv/font-ocm.lua
@@ -0,0 +1,874 @@
+if not modules then modules = { } end modules ['font-ocm'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+if not context then
+ return
+elseif CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 then
+ return
+else
+ -- Maybe I'll also make a generic variant but for now I just test this in
+ -- MkIV. After all, color fonts are not that much used (and generic is for
+ -- serious looking articles and books and not for fancy documents using
+ -- emoji.) Below is a quick and dirty implementation. Also, it looks like
+ -- these features were never used outside context anyway (in spite of being
+ -- in generic).
+end
+
+local tostring, tonumber, next = tostring, tonumber, next
+local round, max = math.round, math.round
+local sortedkeys, sortedhash, concat = table.sortedkeys, table.sortedhash, table.concat
+local setmetatableindex = table.setmetatableindex
+local formatters = string.formatters
+
+local otf = fonts.handlers.otf
+local otfregister = otf.features.register
+local bpfactor = number.dimenfactors.bp
+local typethree = { }
+
+callback.register("provide_charproc_data",function(action,f,...)
+ local registered = typethree[f]
+ if registered then
+ return registered(action,f,...)
+ else
+ return 0, 0 -- this will also disable further calls
+ end
+end)
+
+local defaults = {
+ [1] = function() return 0, 0 end,
+ [2] = function() return 0, 0 end,
+ [3] = function() return 0.001, "" end,
+}
+
+local function registeractions(t)
+ return {
+ [1] = t.preroll or defaults[1],
+ [2] = t.collect or defaults[2],
+ [3] = t.wrapup or defaults[3],
+ }
+end
+
+local function registertypethreeresource(specification,n,o)
+ specification.usedobjects["X"..n] = lpdf.reference(o)
+end
+
+local function registertypethreefont(specification,n,o)
+ specification.usedfonts["F"..n] = lpdf.reference(o)
+end
+
+local function typethreeresources(specification)
+ local usedobjects = specification.usedobjects
+ local usedfonts = specification.usedfonts
+ local resources = { }
+ if next(usedobjects) then
+ resources[#resources+1] = "/XObject << " .. usedobjects() .. " >>"
+ end
+ if next(usedfonts) then
+ resources[#resources+1] = "/Font << " .. usedfonts() .. " >>"
+ end
+ -- resources[#resources+1] = lpdf.collectedresources()
+ specification.usedfonts = nil
+ specification.usedobjects = nil
+ return concat(resources, " ")
+end
+
+local function registerfont(specification,actions)
+ specification.usedfonts = lpdf.dictionary()
+ specification.usedobjects = lpdf.dictionary()
+ typethree[specification.id] = function(action,f,c)
+ return actions[action](specification,f,c)
+ end
+end
+
+fonts.handlers.typethree = {
+ register = function(id,handler)
+ -- needed for manual
+ if not typethree[id] then
+ logs.report("fonts","low level Type3 handler registered for font with id %i",id)
+ typethree[id] = handler
+ end
+ end
+}
+
+local initializeoverlay do
+
+ local f_color = formatters["%.3f %.3f %.3f rg"]
+ local f_gray = formatters["%.3f g"]
+ local sharedpalettes = { }
+ local colors = attributes.list[attributes.private('color')] or { }
+ local transparencies = attributes.list[attributes.private('transparency')] or { }
+
+ function otf.registerpalette(name,values)
+ sharedpalettes[name] = values
+ local color = lpdf.color
+ local transparency = lpdf.transparency
+ local register = colors.register
+ for i=1,#values do
+ local v = values[i]
+ if v == "textcolor" then
+ values[i] = false
+ else
+ local c = nil
+ local t = nil
+ if type(v) == "table" then
+ c = register(name,"rgb",
+ max(round((v.r or 0)*255),255)/255,
+ max(round((v.g or 0)*255),255)/255,
+ max(round((v.b or 0)*255),255)/255
+ )
+ else
+ c = colors[v]
+ t = transparencies[v]
+ end
+ if c and t then
+ values[i] = color(1,c) .. " " .. transparency(t)
+ elseif c then
+ values[i] = color(1,c)
+ elseif t then
+ values[i] = color(1,t)
+ end
+ end
+ end
+ end
+
+ local function convert(t,k)
+ local v = { }
+ for i=1,#k do
+ local p = k[i]
+ local r, g, b = p[1], p[2], p[3]
+ if r == g and g == b then
+ v[i] = f_gray(r/255)
+ else
+ v[i] = f_color(r/255,g/255,b/255)
+ end
+ end
+ t[k] = v
+ return v
+ end
+
+ -- This is by no means watertight (the id mess) especially because we
+ -- don't know it yet. Instead we can just assemble here and avoid the
+ -- box approach. I might do that (so then we need to pass fonts and
+ -- extra resource entries.
+
+ local f_stream = formatters["%s 0 d0 %s 0 0 %s 0 %s cm /X%i Do"]
+ local fontorder = 0
+ local actions = registeractions {
+
+ preroll = function(specification,f,c)
+ local data = specification.delegated[c]
+ local colorlist = data.colorlist
+ local colorvalues = specification.colorvalues
+ local default = specification.default
+ local mainid = specification.mainid
+ local t = { "\\typethreefont{", mainid, "}" }
+ local n = 3
+ local l = nil
+ local m = #colorlist
+ for i=1,m do
+ local entry = colorlist[i]
+ local v = colorvalues[entry.class] or default
+ if v and l ~= v then
+ n = n + 1 ; t[n] = "\\typethreecode{"
+ n = n + 1 ; t[n] = v
+ n = n + 1 ; t[n] = "}"
+ l = v
+ end
+ if i < m then
+ n = n + 1 ; t[n] = "\\typethreechar{"
+ else
+ n = n + 1 ; t[n] = "\\typethreelast{"
+ end
+ n = n + 1 ; t[n] = entry.slot
+ n = n + 1 ; t[n] = "}"
+ end
+ token.set_macro("typethreemacro",concat(t))
+ tex.runtoks("typethreetoks")
+ registertypethreeresource(specification,c,tex.saveboxresource(0,nil,lpdf.collectedresources(),true))
+ -- registertypethreefont(specification,mainid,lpdf.reference(lpdf.getfontobjnumber(mainid)))
+ return 0, 0
+ end,
+
+ collect = function(specification,f,c)
+ local parameters = specification.parameters
+ local data = specification.delegated[c]
+ local factor = parameters.hfactor
+ local units = parameters.units
+ local width = (data.width or 0) / factor
+ local scale = 100
+ local factor = units * bpfactor -- / scale
+ local depth = (data.depth or 0)*factor
+ local shift = - depth / (10*units/1000)
+ local object = pdf.immediateobj("stream",f_stream(width,scale,scale,shift,c))
+ return object, width
+ end,
+
+ wrapup = function(specification,f)
+ return 0.001, typethreeresources(specification)
+ end,
+
+ }
+
+ local function register(specification)
+ registerfont(specification,actions)
+ end
+
+ initializeoverlay = function(tfmdata,kind,value)
+ if value then
+ local resources = tfmdata.resources
+ local palettes = resources.colorpalettes
+ if palettes then
+ local converted = resources.converted
+ if not converted then
+ converted = setmetatableindex(convert)
+ resources.converted = converted
+ end
+ local colorvalues = sharedpalettes[value]
+ local default = false -- so the text color (bad for icon overloads)
+ if colorvalues then
+ default = colorvalues[#colorvalues]
+ else
+ colorvalues = converted[palettes[tonumber(value) or 1] or palettes[1]] or { }
+ end
+ local classes = #colorvalues
+ if classes == 0 then
+ return
+ end
+ --
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local properties = tfmdata.properties
+ local parameters = tfmdata.parameters
+ --
+ properties.virtualized = true
+ --
+ local delegated = { }
+ local index = 0
+ local fonts = tfmdata.fonts or { }
+ local fontindex = #fonts + 1
+ tfmdata.fonts = fonts
+
+ local function flush()
+ if index > 0 then
+ fontorder = fontorder + 1
+ local f = {
+ characters = delegated,
+ parameters = parameters,
+ tounicode = true,
+ format = "type3",
+ name = "InternalTypeThreeFont" , -- .. fontorder,
+ psname = "none",
+ }
+ fonts[fontindex] = {
+ id = font.define(f),
+ delegated = delegated,
+ parameters = parameters,
+ colorvalues = colorvalues,
+ default = default,
+ }
+ end
+ fontindex = fontindex + 1
+ index = 0
+ delegated = { }
+ end
+
+ for unicode, character in sortedhash(characters) do
+ local description = descriptions[unicode]
+ if description then
+ local colorlist = description.colors
+ if colorlist then
+ if index == 255 then
+ flush()
+ end
+ index = index + 1
+ delegated[index] = {
+ width = character.width,
+ height = character.height,
+ depth = character.depth,
+ tounicode = character.tounicode,
+ colorlist = colorlist,
+ }
+ character.commands = {
+ { "slot", fontindex, index },
+ }
+ end
+ end
+ end
+
+ flush()
+ local mainid = font.nextid()
+ for i=1,#fonts do
+ local f = fonts[i]
+ if f.delegated then
+ f.mainid = mainid
+ register(f)
+ end
+ end
+
+ return true
+ end
+ end
+ end
+
+ otfregister {
+ name = "colr",
+ description = "color glyphs",
+ manipulators = {
+ base = initializeoverlay,
+ node = initializeoverlay,
+ }
+ }
+
+end
+
+do
+
+ local nofstreams = 0
+ local f_name = formatters[ [[pdf-glyph-%05i]] ]
+ local f_used = context and formatters[ [[original:///%s]] ] or formatters[ [[%s]] ]
+ local hashed = { }
+ local cache = { }
+
+ local openpdf = pdfe.new
+
+ function otf.storepdfdata(pdf)
+ if pdf then
+ local done = hashed[pdf]
+ if not done then
+ nofstreams = nofstreams + 1
+ local f = f_name(nofstreams)
+ local n = openpdf(pdf,#pdf,f)
+ done = f_used(n)
+ hashed[pdf] = done
+ end
+ return done
+ end
+ end
+
+end
+
+local pdftovirtual do
+
+ local f_stream = formatters["%s 0 d0 %s 0 0 %s %s %s cm /X%i Do"]
+ local fontorder = 0
+ local shared = { }
+ local actions = registeractions {
+
+ preroll = function(specification,f,c)
+ return 0, 0
+ end,
+
+ collect = function(specification,f,c)
+ local parameters = specification.parameters
+ local data = specification.delegated[c]
+ local desdata = data.desdata
+ local pdfdata = data.pdfdata
+ local width = desdata.width or 0
+ local height = desdata.height or 0
+ local depth = desdata.depth or 0
+ local factor = parameters.hfactor
+ local units = parameters.units
+ local typ = type(pdfdata)
+
+ local dx = 0
+ local dy = 0
+ local scale = 1
+
+ if typ == "table" then
+ data = pdfdata.data
+ dx = pdfdata.x or pdfdata.dx or 0
+ dy = pdfdata.y or pdfdata.dy or 0
+ scale = pdfdata.scale or 1
+ elseif typ == "string" then
+ data = pdfdata
+ dx = 0
+ dy = 0
+ else
+ return 0, 0
+ end
+
+ if not data then
+ return 0, 0
+ end
+
+ local name = otf.storepdfdata(data)
+ local xform = shared[name]
+
+ if not xform then
+ xform = images.embed(images.create { filename = name })
+ shared[name] = xform
+ end
+
+ registertypethreeresource(specification,c,xform.objnum)
+
+ scale = scale * (width / (xform.width * bpfactor))
+ dy = - depth + dy
+-- dx = 0
+-- dy = 0
+ local object = pdf.immediateobj("stream",f_stream(width,scale,scale,dx,dy,c)), width
+
+ return object, width
+ end,
+
+ wrapup = function(specification,f)
+ return 1/specification.parameters.units, typethreeresources(specification)
+ end,
+
+ }
+
+ local function register(specification)
+ registerfont(specification,actions)
+ end
+
+ pdftovirtual = function(tfmdata,pdfshapes,kind) -- kind = png|svg
+ if not tfmdata or not pdfshapes or not kind then
+ return
+ end
+ --
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local properties = tfmdata.properties
+ local parameters = tfmdata.parameters
+ local hfactor = parameters.hfactor
+ --
+ properties.virtualized = true
+ --
+ local storepdfdata = otf.storepdfdata
+ --
+ local delegated = { }
+ local index = 0
+ local fonts = tfmdata.fonts or { }
+ local fontindex = #fonts + 1
+ tfmdata.fonts = fonts
+
+ local function flush()
+ if index > 0 then
+ fontorder = fontorder + 1
+ local f = {
+ characters = delegated,
+ parameters = parameters,
+ tounicode = true,
+ format = "type3",
+ name = "InternalTypeThreeFont" .. fontorder,
+ psname = "none",
+ size = parameters.size,
+ }
+ fonts[fontindex] = {
+ id = font.define(f),
+ delegated = delegated,
+ parameters = parameters,
+ }
+ end
+ fontindex = fontindex + 1
+ index = 0
+ delegated = { }
+ end
+
+ for unicode, character in sortedhash(characters) do
+ local idx = character.index
+ if idx then
+ local pdfdata = pdfshapes[idx]
+ local description = descriptions[unicode]
+ if pdfdata and description then
+ if index == 255 then
+ flush()
+ end
+ index = index + 1
+ delegated[index] = {
+ desdata = description,
+ width = character.width,
+ height = character.width,
+ depth = character.width,
+ tounicode = character.tounicode,
+ pdfdata = pdfdata,
+ }
+ character.commands = {
+ { "slot", fontindex, index },
+ }
+ end
+ end
+ end
+ --
+ flush()
+ local mainid = font.nextid()
+ for i=1,#fonts do
+ local f = fonts[i]
+ if f.delegated then
+ f.mainid = mainid
+ register(f)
+ end
+ end
+ --
+ end
+
+end
+
+local initializesvg do
+
+ local otfsvg = otf.svg or { }
+ otf.svg = otfsvg
+ otf.svgenabled = true
+
+ local report_svg = logs.reporter("fonts","svg conversion")
+
+ local loaddata = io.loaddata
+ local savedata = io.savedata
+ local remove = os.remove
+
+ local xmlconvert = xml.convert
+ local xmlfirst = xml.first
+
+ function otfsvg.filterglyph(entry,index)
+ local d = entry.data
+ if gzip.compressed(d) then
+ d = gzip.decompress(d) or d
+ end
+ local svg = xmlconvert(d)
+ local root = svg and xmlfirst(svg,"/svg[@id='glyph"..index.."']")
+ local data = root and tostring(root)
+ return data
+ end
+
+ local runner = sandbox and sandbox.registerrunner {
+ name = "otfsvg",
+ program = "inkscape",
+ method = "pipeto",
+ template = "--export-area-drawing --shell > temp-otf-svg-shape.log",
+ reporter = report_svg,
+ }
+
+ if not runner then
+ --
+ -- poor mans variant for generic:
+ --
+ runner = function()
+ return io.popen("inkscape --export-area-drawing --shell > temp-otf-svg-shape.log","w")
+ end
+ end
+
+ -- There are svg out there with bad viewBox specifications where shapes lay outside that area,
+ -- but trying to correct that didn't work out well enough so I discarded that code. BTW, we
+ -- decouple the inskape run and the loading run because inkscape is working in the background
+ -- in the files so we need to have unique files.
+ --
+ -- Because a generic setup can be flawed we need to catch bad inkscape runs which add a bit of
+ -- ugly overhead. Bah.
+
+ local new = nil
+
+ local function inkscapeformat(suffix)
+ if new == nil then
+ new = os.resultof("inkscape --version") or ""
+ new = new == "" or not find(new,"Inkscape%s*0")
+ end
+ return new and "filename" or suffix
+ end
+
+ function otfsvg.topdf(svgshapes,tfmdata)
+ local pdfshapes = { }
+ local inkscape = runner()
+ if inkscape then
+ -- local indices = fonts.getindices(tfmdata)
+ local descriptions = tfmdata.descriptions
+ local nofshapes = #svgshapes
+ local f_svgfile = formatters["temp-otf-svg-shape-%i.svg"]
+ local f_pdffile = formatters["temp-otf-svg-shape-%i.pdf"]
+ local f_convert = formatters["%s --export-%s=%s\n"]
+ local filterglyph = otfsvg.filterglyph
+ local nofdone = 0
+ local processed = { }
+ report_svg("processing %i svg containers",nofshapes)
+ statistics.starttiming()
+ for i=1,nofshapes do
+ local entry = svgshapes[i]
+ for index=entry.first,entry.last do
+ local data = filterglyph(entry,index)
+ if data and data ~= "" then
+ local svgfile = f_svgfile(index)
+ local pdffile = f_pdffile(index)
+ savedata(svgfile,data)
+ inkscape:write(f_convert(svgfile,inkscapeformat("pdf"),pdffile))
+ processed[index] = true
+ nofdone = nofdone + 1
+ if nofdone % 25 == 0 then
+ report_svg("%i shapes submitted",nofdone)
+ end
+ end
+ end
+ end
+ if nofdone % 25 ~= 0 then
+ report_svg("%i shapes submitted",nofdone)
+ end
+ report_svg("processing can be going on for a while")
+ inkscape:write("quit\n")
+ inkscape:close()
+ report_svg("processing %i pdf results",nofshapes)
+ for index in next, processed do
+ local svgfile = f_svgfile(index)
+ local pdffile = f_pdffile(index)
+ -- local fntdata = descriptions[indices[index]]
+ -- local bounds = fntdata and fntdata.boundingbox
+ local pdfdata = loaddata(pdffile)
+ if pdfdata and pdfdata ~= "" then
+ pdfshapes[index] = {
+ data = pdfdata,
+ -- x = bounds and bounds[1] or 0,
+ -- y = bounds and bounds[2] or 0,
+ }
+ end
+ remove(svgfile)
+ remove(pdffile)
+ end
+ local characters = tfmdata.characters
+ for k, v in next, characters do
+ local d = descriptions[k]
+ local i = d.index
+ if i then
+ local p = pdfshapes[i]
+ if p then
+ local w = d.width
+ local l = d.boundingbox[1]
+ local r = d.boundingbox[3]
+ p.scale = (r - l) / w
+ p.x = l
+ end
+ end
+ end
+ if not next(pdfshapes) then
+ report_svg("there are no converted shapes, fix your setup")
+ end
+ statistics.stoptiming()
+ if statistics.elapsedseconds then
+ report_svg("svg conversion time %s",statistics.elapsedseconds() or "-")
+ end
+ end
+ return pdfshapes
+ end
+
+ initializesvg = function(tfmdata,kind,value) -- hm, always value
+ if value and otf.svgenabled then
+ local svg = tfmdata.properties.svg
+ local hash = svg and svg.hash
+ local timestamp = svg and svg.timestamp
+ if not hash then
+ return
+ end
+ local pdffile = containers.read(otf.pdfcache,hash)
+ local pdfshapes = pdffile and pdffile.pdfshapes
+ if not pdfshapes or pdffile.timestamp ~= timestamp or not next(pdfshapes) then
+ -- the next test tries to catch errors in generic usage but of course can result
+ -- in running again and again
+ local svgfile = containers.read(otf.svgcache,hash)
+ local svgshapes = svgfile and svgfile.svgshapes
+ pdfshapes = svgshapes and otfsvg.topdf(svgshapes,tfmdata,otf.pdfcache.writable,hash) or { }
+ containers.write(otf.pdfcache, hash, {
+ pdfshapes = pdfshapes,
+ timestamp = timestamp,
+ })
+ end
+ pdftovirtual(tfmdata,pdfshapes,"svg")
+ return true
+ end
+ end
+
+ otfregister {
+ name = "svg",
+ description = "svg glyphs",
+ manipulators = {
+ base = initializesvg,
+ node = initializesvg,
+ }
+ }
+
+end
+
+-- This can be done differently e.g. with ffi and gm and we can share code anway. Using
+-- batchmode in gm is not faster and as it accumulates we would need to flush all
+-- individual shapes. But ... in context lmtx (and maybe the backport) we will use
+-- a different and more efficient method anyway. I'm still wondering if I should
+-- keep color code in generic. Maybe it should be optional.
+
+local initializepng do
+
+ local otfpng = otf.png or { }
+ otf.png = otfpng
+ otf.pngenabled = true
+
+ local report_png = logs.reporter("fonts","png conversion")
+
+ local loaddata = io.loaddata
+ local savedata = io.savedata
+ local remove = os.remove
+
+ local runner = sandbox and sandbox.registerrunner {
+ name = "otfpng",
+ program = "gm",
+ template = "convert -quality 100 temp-otf-png-shape.png temp-otf-png-shape.pdf > temp-otf-svg-shape.log",
+ -- reporter = report_png,
+ }
+
+ if not runner then
+ --
+ -- poor mans variant for generic:
+ --
+ runner = function()
+ return os.execute("gm convert -quality 100 temp-otf-png-shape.png temp-otf-png-shape.pdf > temp-otf-svg-shape.log")
+ end
+ end
+
+ -- Alternatively we can create a single pdf file with -adjoin and then pick up pages from
+ -- that file but creating thousands of small files is no fun either.
+
+ local files = utilities.files
+ local openfile = files.open
+ local closefile = files.close
+ local setposition = files.setposition
+ local readstring = files.readstring
+
+ function otfpng.topdf(pngshapes,filename)
+ if pngshapes and filename then
+ local pdfshapes = { }
+ local pngfile = "temp-otf-png-shape.png"
+ local pdffile = "temp-otf-png-shape.pdf"
+ local nofdone = 0
+ local indices = sortedkeys(pngshapes) -- can be sparse
+ local nofindices = #indices
+ report_png("processing %i png containers",nofindices)
+ statistics.starttiming()
+ local filehandle = openfile(filename)
+ for i=1,nofindices do
+ local index = indices[i]
+ local entry = pngshapes[index]
+ -- local data = entry.data -- or placeholder
+ local offset = entry.o
+ local size = entry.s
+ local x = entry.x
+ local y = entry.y
+ local data = nil
+ if offset and size then
+ setposition(filehandle,offset)
+ data = readstring(filehandle,size)
+ savedata(pngfile,data)
+ runner()
+ data = loaddata(pdffile)
+ end
+ pdfshapes[index] = {
+-- x = x ~= 0 and x or nil,
+-- y = y ~= 0 and y or nil,
+ data = data,
+ }
+ nofdone = nofdone + 1
+ if nofdone % 100 == 0 then
+ report_png("%i shapes processed",nofdone)
+ end
+ end
+ closefile(filehandle)
+ report_png("processing %i pdf results",nofindices)
+ remove(pngfile)
+ remove(pdffile)
+ statistics.stoptiming()
+ if statistics.elapsedseconds then
+ report_png("png conversion time %s",statistics.elapsedseconds() or "-")
+ end
+ return pdfshapes
+ end
+ end
+
+ initializepng = function(tfmdata,kind,value) -- hm, always value
+ if value and otf.pngenabled then
+ local png = tfmdata.properties.png
+ local hash = png and png.hash
+ local timestamp = png and png.timestamp
+ if not hash then
+ return
+ end
+ local pdffile = containers.read(otf.pdfcache,hash)
+ local pdfshapes = pdffile and pdffile.pdfshapes
+ if not pdfshapes or pdffile.timestamp ~= timestamp then
+ local pngfile = containers.read(otf.pngcache,hash)
+ local filename = tfmdata.resources.filename
+ local pngshapes = pngfile and pngfile.pngshapes
+ pdfshapes = pngshapes and otfpng.topdf(pngshapes,filename) or { }
+ containers.write(otf.pdfcache, hash, {
+ pdfshapes = pdfshapes,
+ timestamp = timestamp,
+ })
+ end
+ --
+ pdftovirtual(tfmdata,pdfshapes,"png")
+ return true
+ end
+ end
+
+ otfregister {
+ name = "sbix",
+ description = "sbix glyphs",
+ manipulators = {
+ base = initializepng,
+ node = initializepng,
+ }
+ }
+
+ otfregister {
+ name = "cblc",
+ description = "cblc glyphs",
+ manipulators = {
+ base = initializepng,
+ node = initializepng,
+ }
+ }
+
+end
+
+do
+
+ local function initializecolor(tfmdata,kind,value)
+ if value == "auto" then
+ return
+ initializeoverlay(tfmdata,kind,value) or
+ initializesvg (tfmdata,kind,value) or
+ initializepng (tfmdata,kind,value)
+ elseif value == "overlay" then
+ return initializeoverlay(tfmdata,kind,value)
+ elseif value == "svg" then
+ return initializesvg(tfmdata,kind,value)
+ elseif value == "png" or value == "bitmap" then
+ return initializepng(tfmdata,kind,value)
+ else
+ -- forget about it
+ end
+ end
+
+ otfregister {
+ name = "color",
+ description = "color glyphs",
+ manipulators = {
+ base = initializecolor,
+ node = initializecolor,
+ }
+ }
+
+end
+
+-- Old stuff:
+
+do
+
+ local startactualtext = nil
+ local stopactualtext = nil
+
+ function otf.getactualtext(s)
+ if not startactualtext then
+ startactualtext = backends.codeinjections.startunicodetoactualtextdirect
+ stopactualtext = backends.codeinjections.stopunicodetoactualtextdirect
+ end
+ return startactualtext(s), stopactualtext()
+ end
+
+end
+
diff --git a/tex/context/base/mkiv/font-otr.lua b/tex/context/base/mkiv/font-otr.lua
index e72605320..bad42054f 100644
--- a/tex/context/base/mkiv/font-otr.lua
+++ b/tex/context/base/mkiv/font-otr.lua
@@ -2084,8 +2084,6 @@ local function readtable(tag,f,fontdata,specification,...)
end
end
-local variablefonts_supported = (context and true) or (logs and logs.application and true) or false
-
local function readdata(f,offset,specification)
local fontdata, tables = loadtables(f,specification,offset)
@@ -2094,12 +2092,6 @@ local function readdata(f,offset,specification)
prepareglyps(fontdata)
end
- if not variablefonts_supported then
- specification.instance = nil
- specification.variable = nil
- specification.factors = nil
- end
-
fontdata.temporary = { }
readtable("name",f,fontdata,specification)
@@ -2118,71 +2110,66 @@ local function readdata(f,offset,specification)
readtable("avar",f,fontdata,specification)
readtable("fvar",f,fontdata,specification)
- if variablefonts_supported then
-
- local variabledata = fontdata.variabledata
-
- if variabledata then
- local instances = variabledata.instances
- local axis = variabledata.axis
- if axis and (not instances or #instances == 0) then
- instances = { }
- variabledata.instances = instances
- local function add(n,subfamily,value)
- local values = { }
- for i=1,#axis do
- local a = axis[i]
- values[i] = {
- axis = a.tag,
- value = i == n and value or a.default,
- }
- end
- instances[#instances+1] = {
- subfamily = subfamily,
- values = values,
- }
- end
+ local variabledata = fontdata.variabledata
+
+ if variabledata then
+ local instances = variabledata.instances
+ local axis = variabledata.axis
+ if axis and (not instances or #instances == 0) then
+ instances = { }
+ variabledata.instances = instances
+ local function add(n,subfamily,value)
+ local values = { }
for i=1,#axis do
- local a = axis[i]
- local tag = a.tag
- add(i,"default"..tag,a.default)
- add(i,"minimum"..tag,a.minimum)
- add(i,"maximum"..tag,a.maximum)
+ local a = axis[i]
+ values[i] = {
+ axis = a.tag,
+ value = i == n and value or a.default,
+ }
end
- -- report("%i fake instances added",#instances)
+ instances[#instances+1] = {
+ subfamily = subfamily,
+ values = values,
+ }
end
- end
-
- if not specification.factors then
- local instance = specification.instance
- if type(instance) == "string" then
- local factors = helpers.getfactors(fontdata,instance)
- if factors then
- specification.factors = factors
- fontdata.factors = factors
- fontdata.instance = instance
- report("user instance: %s, factors: % t",instance,factors)
- else
- report("user instance: %s, bad factors",instance)
- end
+ for i=1,#axis do
+ local a = axis[i]
+ local tag = a.tag
+ add(i,"default"..tag,a.default)
+ add(i,"minimum"..tag,a.minimum)
+ add(i,"maximum"..tag,a.maximum)
end
+ -- report("%i fake instances added",#instances)
end
-
- if not fontdata.factors then
- if fontdata.variabledata then
- local factors = helpers.getfactors(fontdata,true)
- if factors then
- specification.factors = factors
- fontdata.factors = factors
- -- report("factors: % t",factors)
- -- else
- -- report("bad factors")
- end
+ end
+ if not specification.factors then
+ local instance = specification.instance
+ if type(instance) == "string" then
+ local factors = helpers.getfactors(fontdata,instance)
+ if factors then
+ specification.factors = factors
+ fontdata.factors = factors
+ fontdata.instance = instance
+ report("user instance: %s, factors: % t",instance,factors)
else
- -- report("unknown instance")
+ report("user instance: %s, bad factors",instance)
end
end
+ end
+ if not fontdata.factors then
+ if fontdata.variabledata then
+ local factors = helpers.getfactors(fontdata,true)
+ if factors then
+ specification.factors = factors
+ fontdata.factors = factors
+ -- report("factors: % t",factors)
+ -- else
+ -- report("bad factors")
+ end
+ else
+ -- report("unknown instance")
+ end
end
readtable("os/2",f,fontdata,specification)
diff --git a/tex/context/base/mkiv/font-ott.lua b/tex/context/base/mkiv/font-ott.lua
index c9e467f22..f4d7e05a1 100644
--- a/tex/context/base/mkiv/font-ott.lua
+++ b/tex/context/base/mkiv/font-ott.lua
@@ -1117,41 +1117,6 @@ local checkers = {
end
}
--- Keep this:
---
--- function otf.features.normalize(features)
--- if features then
--- local h = { }
--- for k, v in next, features do
--- k = lower(k)
--- if k == "language" then
--- v = gsub(lower(v),"[^a-z0-9]","")
--- h.language = rawget(verboselanguages,v) or (languages[v] and v) or "dflt" -- auto adds
--- elseif k == "script" then
--- v = gsub(lower(v),"[^a-z0-9]","")
--- h.script = rawget(verbosescripts,v) or (scripts[v] and v) or "dflt" -- auto adds
--- else
--- if type(v) == "string" then
--- local b = is_boolean(v)
--- if type(b) == "nil" then
--- v = tonumber(v) or lower(v)
--- else
--- v = b
--- end
--- end
--- if not rawget(features,k) then
--- k = rawget(verbosefeatures,k) or k
--- end
--- local c = checkers[k]
--- h[k] = c and c(v) or v
--- end
--- end
--- return h
--- end
--- end
-
--- inspect(fonts.handlers.otf.statistics.usedfeatures)
-
if not storage then
return
end
@@ -1178,9 +1143,6 @@ function otffeatures.normalize(features,wrap) -- wrap is for context
h.script = rawget(verbosescripts,v) or (scripts[v] and v) or "dflt" -- auto adds
elseif k == "axis" then
h[k] = normalizedaxis(value)
- if not callbacks.supported.glyph_stream_provider then
- h.variableshapes = true -- for the moment
- end
else
local uk = usedfeatures[key]
local uv = uk[value]
diff --git a/tex/context/base/mkiv/font-shp.lua b/tex/context/base/mkiv/font-shp.lua
index 4d5254760..c3fea6d46 100644
--- a/tex/context/base/mkiv/font-shp.lua
+++ b/tex/context/base/mkiv/font-shp.lua
@@ -379,124 +379,17 @@ otf.loadstreamdata = loadstreamdata -- not public
otf.loadshapes = loadshapes
otf.getstreamhash = getstreamhash -- not public, might move to other namespace
-local f_c = formatters["%.6N %.6N %.6N %.6N %.6N %.6N c"]
-local f_l = formatters["%.6N %.6N l"]
-local f_m = formatters["%.6N %.6N m"]
-
-local function segmentstopdf(segments,factor,bt,et)
- local t = { }
- local m = 0
- local n = #segments
- local d = false
- for i=1,n do
- local s = segments[i]
- local w = s[#s]
- if w == "c" then
- m = m + 1
- t[m] = f_c(s[1]*factor,s[2]*factor,s[3]*factor,s[4]*factor,s[5]*factor,s[6]*factor)
- elseif w == "l" then
- m = m + 1
- t[m] = f_l(s[1]*factor,s[2]*factor)
- elseif w == "m" then
- m = m + 1
- t[m] = f_m(s[1]*factor,s[2]*factor)
- elseif w == "q" then
- local p = segments[i-1]
- local n = #p
- local l_x = factor*p[n-2]
- local l_y = factor*p[n-1]
- local m_x = factor*s[1]
- local m_y = factor*s[2]
- local r_x = factor*s[3]
- local r_y = factor*s[4]
- m = m + 1
- t[m] = f_c (
- l_x + 2/3 * (m_x-l_x), l_y + 2/3 * (m_y-l_y),
- r_x + 2/3 * (m_x-r_x), r_y + 2/3 * (m_y-r_y),
- r_x, r_y
- )
- end
- end
- m = m + 1
- t[m] = "h f" -- B*
- if bt and et then
- t[0] = bt
- t[m+1] = et
- return concat(t,"\n",0,m+1)
- else
- return concat(t,"\n")
- end
-end
-
-local function initialize(tfmdata,key,value)
- if value then
- local shapes = otf.loadoutlinedata(tfmdata)
- if not shapes then
- return
- end
- local glyphs = shapes.glyphs
- if not glyphs then
- return
- end
- local characters = tfmdata.characters
- local parameters = tfmdata.parameters
- local hfactor = parameters.hfactor * (7200/7227)
- local factor = hfactor / 65536
- local getactualtext = otf.getactualtext
- for unicode, char in next, characters do
- if char.commands then
- -- can't happen as we're doing this before other messing around
- else
- local shape = glyphs[char.index]
- if shape then
- local segments = shape.segments
- if segments then
- -- we need inline in order to support color
- local bt, et = getactualtext(char.tounicode or char.unicode or unicode)
- char.commands = {
- { "pdf", "origin", segmentstopdf(segments,factor,bt,et) }
- }
- end
- end
- end
- end
- end
-end
-
-otf.features.register {
- name = "variableshapes", -- enforced for now
- description = "variable shapes",
- manipulators = {
- base = initialize,
- node = initialize,
- }
-}
-
--- In the end it is easier to just provide the new charstring (cff) and points (ttf). First
--- of all we already have the right information so there is no need to patch the already complex
--- backend code (we only need to make sure the cff is valid). Also, I prototyped support for
--- these fonts using (converted to) normal postscript shapes, a functionality that was already
--- present for a while for metafun. This solution even permits us to come up with usage of such
--- fonts in unexpected ways. It also opens the road to shapes generated with metafun includes
--- as real cff (or ttf) shapes instead of virtual in-line shapes.
---
--- This is probably a prelude to writing a complete backend font inclusion plugin in lua. After
--- all I already have most info. For this we just need to pass a list of used glyphs (or analyze
--- them ourselves).
-
local streams = fonts.hashes.streams
-if callbacks.supported.glyph_stream_provider then
+-- we can now assume that luatex has this one
- callback.register("glyph_stream_provider",function(id,index,mode)
- if id > 0 then
- local streams = streams[id].streams
- -- print(id,index,streams[index])
- if streams then
- return streams[index] or ""
- end
+callback.register("glyph_stream_provider",function(id,index,mode)
+ if id > 0 then
+ local streams = streams[id].streams
+ -- print(id,index,streams[index])
+ if streams then
+ return streams[index] or ""
end
- return ""
- end)
-
-end
+ end
+ return ""
+end)
diff --git a/tex/context/base/mkiv/grph-con.lua b/tex/context/base/mkiv/grph-con.lua
index c3c711b0c..b3d39f0bd 100644
--- a/tex/context/base/mkiv/grph-con.lua
+++ b/tex/context/base/mkiv/grph-con.lua
@@ -9,6 +9,7 @@ if not modules then modules = { } end modules ['grph-con'] = {
local P, R, S, Cc, C, Cs, Ct, lpegmatch = lpeg.P, lpeg.R, lpeg.S, lpeg.Cc, lpeg.C, lpeg.Cs, lpeg.Ct, lpeg.match
local tonumber = tonumber
+local find = string.find
local longtostring = string.longtostring
local formatters = string.formatters
local expandfilename = dir.expandname
@@ -194,6 +195,22 @@ do -- svg
-- arguments change again? Ok, it's weirder, with -A then it's a name only when
-- not . (current)
+ -- Beware: the order of printed output lines is a bit random depending on the
+ -- method of calling (bin or pipe) because part of the message prints to stdout
+ -- and part to stderr. Also, on Windows, a second call to the old binaries
+ -- doesn't return anything at all, so that is also a signal of it being old.
+ -- This test will be dropped in 2021 anyway.
+
+ local new = nil
+
+ local function inkscapeformat(suffix)
+ if new == nil then
+ new = os.resultof("inkscape --version") or ""
+ new = new == "" or not find(new,"Inkscape%s*0")
+ end
+ return new and "filename" or suffix
+ end
+
local runner = sandbox.registerrunner {
name = "svg to something",
program = "inkscape",
@@ -209,7 +226,7 @@ do -- svg
resolution = "string",
},
defaults = {
- format = "pdf",
+ format = format,
resolution = "600",
}
}
@@ -220,7 +237,7 @@ do -- svg
function svgconverter.pdf(oldname,newname)
runner {
- format = "pdf",
+ format = inkscapeformat("pdf"),
resolution = "600",
newname = expandfilename(newname),
oldname = expandfilename(oldname),
@@ -229,7 +246,7 @@ do -- svg
function svgconverter.png(oldname,newname)
runner {
- format = "png",
+ format = inkscapeformat("png"),
resolution = "600",
newname = expandfilename(newname),
oldname = expandfilename(oldname),
diff --git a/tex/context/base/mkiv/grph-trf.lua b/tex/context/base/mkiv/grph-trf.lua
new file mode 100644
index 000000000..f476ec692
--- /dev/null
+++ b/tex/context/base/mkiv/grph-trf.lua
@@ -0,0 +1,125 @@
+if not modules then modules = { } end modules ['grph-trf'] = {
+ version = 1.001,
+ comment = "companion to grph-trf.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- see grph-trf-todo.lua for older preliminary code for the rest
+
+local sind, cosd, tand, abs = math.sind, math.cosd, math.tand, math.abs
+
+local texsetdimen = tex.setdimen
+
+local function analyzerotate(rotation,width,height,depth,total,notfit,obeydepth)
+ --
+ -- print(rotation,width,height,depth,notfit,obeydepth)
+ --
+ local sin = sind(rotation)
+ local cos = cosd(rotation)
+ local abssin = abs(sin)
+ local abscos = abs(cos)
+ local xsize = 0
+ local ysize = 0
+ local xposition = 0
+ local yposition = 0
+ local xoffset = 0
+ local yoffset = 0
+ local newwidth = width
+ local newheight = height
+ local newdepth = depth
+ -- print(sin,cos)
+ if sin > 0 then
+ if cos > 0 then
+ xsize = cos * width + sin * total
+ ysize = sin * width + cos * total
+ yposition = cos * total
+ if notfit then
+ xoffset = - sin * height
+ newwidth = sin * depth + cos * width
+ else
+ newwidth = xsize + xposition - xoffset
+ end
+ if obeydepth then
+ yoffset = cos * depth
+ end
+ newheight = ysize - yoffset
+ newdepth = yoffset
+ -- print("case 1, done")
+ else
+ xsize = abscos * width + sin * total
+ ysize = sin * width + abscos * total
+ xposition = abscos * width
+ if notfit then
+ xoffset = - xsize + sin * depth
+ end
+ if obeydepth then
+ yoffset = abscos * height
+ newwidth = abssin * total + abscos * width + xoffset
+ else
+ newwidth = xsize
+ end
+ newheight = ysize - yoffset
+ newdepth = yoffset
+ -- print("case 2, done")
+ end
+ else
+ if cos < 0 then
+ xsize = abscos * width + abssin * total
+ ysize = abssin * width + abscos * total
+ xposition = xsize
+ yposition = abssin * width
+ if notfit then
+ xoffset = - xsize + abssin * height
+ end
+ if obeydepth then
+ yoffset = ysize + cos * depth
+ end
+ newwidth = notfit and (abssin * height) or xsize
+ newheight = ysize - yoffset
+ newdepth = yoffset
+ -- print("case 3, done")
+ else
+ xsize = cos * width + abssin * total
+ ysize = abssin * width + cos * total
+ xposition = abssin * total
+ yposition = cos * total
+ if notfit then
+ xoffset = - abssin * depth
+ newwidth = xsize + xoffset
+ else
+ newwidth = xsize
+ end
+ if obeydepth then
+ yoffset = cos * depth
+ end
+ newheight = ysize - yoffset + sin * width
+ newdepth = yoffset - sin * width
+ -- print("case 4, done")
+ end
+ end
+ texsetdimen("d_grph_rotate_x_size", xsize)
+ texsetdimen("d_grph_rotate_y_size", ysize)
+ texsetdimen("d_grph_rotate_x_position", xposition)
+ texsetdimen("d_grph_rotate_y_position", yposition)
+ texsetdimen("d_grph_rotate_x_offset", xoffset)
+ texsetdimen("d_grph_rotate_y_offset", yoffset)
+ texsetdimen("d_grph_rotate_new_width", newwidth)
+ texsetdimen("d_grph_rotate_new_height", newheight)
+ texsetdimen("d_grph_rotate_new_depth", newdepth)
+end
+
+interfaces.implement {
+ name = "analyzerotate",
+ actions = analyzerotate,
+ arguments = {
+ "integer",
+ "dimension",
+ "dimension",
+ "dimension",
+ "dimension",
+ "conditional",
+ "conditional",
+ },
+}
diff --git a/tex/context/base/mkiv/grph-trf.mkiv b/tex/context/base/mkiv/grph-trf.mkiv
index f9218036c..522dd08d6 100644
--- a/tex/context/base/mkiv/grph-trf.mkiv
+++ b/tex/context/base/mkiv/grph-trf.mkiv
@@ -24,6 +24,8 @@
%D We could move the calculations to \LUA\ and clean up this lot anyway. On the
%D other hand, there is some danger of messing up so it has a real low priority.
+\registerctxluafile{grph-trf}{}
+
% local:
\newdimen\d_grph_scale_x_size
@@ -794,6 +796,8 @@
\installcorenamespace {rotatelocation}
\installcorenamespace {rotatepreset}
+% todo: scratchcounters
+
\newdimen\d_grph_rotate_x_size
\newdimen\d_grph_rotate_y_size
\newdimen\d_grph_rotate_x_offset
@@ -811,6 +815,10 @@
\let\d_grph_rotate_saved_height\!!heightb
\let\d_grph_rotate_saved_depth \!!depthb
+\let\d_grph_rotate_new_width \!!widthc
+\let\d_grph_rotate_new_height\!!heightc
+\let\d_grph_rotate_new_depth \!!depthc
+
\newconditional\c_grph_rotate_obey_depth
\newconditional\c_grph_rotate_not_fit
\newconditional\c_grph_rotate_center
@@ -948,111 +956,30 @@
\d_grph_rotate_saved_width \wd\nextbox
\d_grph_rotate_saved_height\ht\nextbox
\d_grph_rotate_saved_depth \dp\nextbox
- \setbox\nextbox\naturalvpack{\vskip.5\ht\nextbox\hskip-.5\wd\nextbox\box\nextbox}%
+ \setbox\nextbox\naturalhpack{\hskip-.5\wd\nextbox\lower.5\ht\nextbox\box\nextbox}%
\smashbox\nextbox
\fi
+ %
\d_grph_rotate_width \wd\nextbox
\d_grph_rotate_height\ht\nextbox
\d_grph_rotate_depth \dp\nextbox
- \setbox\nextbox\naturalvpack{\naturalhpack{\raise\dp\nextbox\box\nextbox}}%
- \d_grph_rotate_used_height \ht\nextbox
- % much of the next happens in lua (all the sin and cos) so we can do that in
- % one go if needed
- \setcalculatedcos\cos\p_rotation_rotation
- \setcalculatedsin\sin\p_rotation_rotation
- \ifdim\sin\points>\zeropoint
- \ifdim\cos\points>\zeropoint
- \grph_rotate_calculate_a
- \grph_rotate_apply
- \else
- \grph_rotate_calculate_b
- \grph_rotate_apply
- \wd\nextbox\ifconditional\c_grph_rotate_not_fit\sin\d_grph_rotate_depth\else\d_grph_rotate_x_size\fi
- \fi
- \else
- \ifdim\cos\points<\zeropoint
- \grph_rotate_calculate_c
- \grph_rotate_apply
- \wd\nextbox\ifconditional\c_grph_rotate_not_fit\negated\sin\d_grph_rotate_height\else\d_grph_rotate_x_size\fi
- \else\ifdim\sin\points=\zeropoint
- \grph_rotate_calculate_d
- \grph_rotate_apply
- % no wd ?
- \else
- \grph_rotate_calculate_e
- \grph_rotate_apply
- \wd\nextbox\ifconditional\c_grph_rotate_not_fit\negated\sin\d_grph_rotate_height\else\d_grph_rotate_x_size\fi
- \fi\fi
- \fi
- \ifconditional\c_grph_rotate_center
- \setbox\nextbox\naturalvpack{\vskip-.5\d_grph_rotate_saved_height\hskip.5\d_grph_rotate_saved_height\box\nextbox}%
- \wd\nextbox\d_grph_rotate_saved_width
- \ht\nextbox\d_grph_rotate_saved_height
- \dp\nextbox\d_grph_rotate_saved_depth
- \fi
- \boxcursor\box\nextbox}
-
-\def\grph_rotate_calculate_a
- {\d_grph_rotate_x_size\dimexpr\cos\d_grph_rotate_width+\sin\d_grph_rotate_used_height\relax
- \d_grph_rotate_y_size\dimexpr\sin\d_grph_rotate_width+\cos\d_grph_rotate_used_height\relax
- \d_grph_rotate_x_position\zeropoint
- \d_grph_rotate_y_position\cos\d_grph_rotate_used_height
- \ifconditional\c_grph_rotate_not_fit
- \d_grph_rotate_x_offset\dimexpr\negated\sin\d_grph_rotate_used_height+\sin\d_grph_rotate_depth\relax
- \fi
- \ifconditional\c_grph_rotate_obey_depth
- \d_grph_rotate_y_offset\cos\d_grph_rotate_depth
- \fi}
-
-\def\grph_rotate_calculate_b
- {\d_grph_rotate_x_size\dimexpr\negated\cos\d_grph_rotate_width+\sin\d_grph_rotate_used_height\relax
- \d_grph_rotate_y_size\dimexpr\sin\d_grph_rotate_width+\negated\cos\d_grph_rotate_used_height\relax
- \d_grph_rotate_x_position\negated\cos\d_grph_rotate_width
- \d_grph_rotate_y_position\zeropoint
- \ifconditional\c_grph_rotate_not_fit
- \d_grph_rotate_x_offset\dimexpr-\d_grph_rotate_x_size+\sin\d_grph_rotate_depth\relax
- \fi
- \ifconditional\c_grph_rotate_obey_depth
- \d_grph_rotate_y_offset\negated\cos\d_grph_rotate_height
- \fi}
-
-\def\grph_rotate_calculate_c
- {\d_grph_rotate_x_size\dimexpr\negated\cos\d_grph_rotate_width+\negated\sin\d_grph_rotate_used_height\relax
- \d_grph_rotate_y_size\dimexpr\negated\sin\d_grph_rotate_width+\negated\cos\d_grph_rotate_used_height\relax
- \d_grph_rotate_x_position\d_grph_rotate_x_size
- \d_grph_rotate_y_position\negated\sin\d_grph_rotate_width
- \ifconditional\c_grph_rotate_not_fit
- \d_grph_rotate_x_offset\dimexpr-\d_grph_rotate_x_size+\negated\sin\d_grph_rotate_height\relax
- \fi
- \ifconditional\c_grph_rotate_obey_depth
- \d_grph_rotate_y_offset\dimexpr\d_grph_rotate_y_size+\cos\d_grph_rotate_depth\relax
- \fi}
-
-\def\grph_rotate_calculate_d
- {\d_grph_rotate_x_size\dimexpr\cos\d_grph_rotate_width+\negated\sin\d_grph_rotate_used_height\relax
- \d_grph_rotate_y_size\dimexpr\negated\sin\d_grph_rotate_width+\cos\d_grph_rotate_used_height\relax
- \d_grph_rotate_x_position\zeropoint
- \d_grph_rotate_y_position\d_grph_rotate_y_size
- \d_grph_rotate_x_offset\zeropoint
- \ifconditional\c_grph_rotate_obey_depth
- \d_grph_rotate_y_offset\d_grph_rotate_depth
- \fi}
-
-\def\grph_rotate_calculate_e
- {\d_grph_rotate_x_size\dimexpr\cos\d_grph_rotate_width+\negated\sin\d_grph_rotate_used_height\relax
- \d_grph_rotate_y_size\dimexpr\negated\sin\d_grph_rotate_width+\cos\d_grph_rotate_used_height\relax
- \d_grph_rotate_x_position\negated\sin\d_grph_rotate_used_height
- \d_grph_rotate_y_position\d_grph_rotate_y_size
- \ifconditional\c_grph_rotate_not_fit
- \d_grph_rotate_x_offset\dimexpr-\d_grph_rotate_x_size+\negated\sin\d_grph_rotate_height\relax
- \fi
- \ifconditional\c_grph_rotate_obey_depth
- \d_grph_rotate_y_offset\negated\sin\d_grph_rotate_depth
- \fi}
-
-\def\grph_rotate_apply
- {\setbox\nextbox\naturalvpack to \d_grph_rotate_y_size
- {\vfill
+ %
+ \setbox\nextbox\naturalvpack{\naturalhpack{\raise\dp\nextbox\box\nextbox}}% can we do without
+ %
+ \d_grph_rotate_used_height\ht\nextbox
+ %
+ \clf_analyzerotate % rather accurate
+ \numexpr\p_rotation_rotation\relax
+ \d_grph_rotate_width
+ \d_grph_rotate_height
+ \d_grph_rotate_depth
+ \d_grph_rotate_used_height
+ \c_grph_rotate_not_fit
+ \c_grph_rotate_obey_depth
+ \relax
+ %
+ \setbox\nextbox\naturalvpack to \d_grph_rotate_y_size
+ {\vfilll
\naturalhpack to \d_grph_rotate_x_size
{\dostartrotation\p_rotation_rotation
\wd\nextbox\zeropoint
@@ -1061,9 +988,24 @@
\dostoprotation
\hfill}%
\kern\d_grph_rotate_y_position}%
+ %
\setbox\nextbox\naturalhpack
{\kern\dimexpr\d_grph_rotate_x_position+\d_grph_rotate_x_offset\relax
- \lower\d_grph_rotate_y_offset\box\nextbox}}
+ \lower\d_grph_rotate_y_offset
+ \box\nextbox}%
+ %
+ \ifconditional\c_grph_rotate_center
+ \setbox\nextbox\naturalhpack{\hskip.5\d_grph_rotate_saved_width\lower-.5\d_grph_rotate_saved_height\box\nextbox}%
+ \wd\nextbox\d_grph_rotate_saved_width
+ \ht\nextbox\d_grph_rotate_saved_height
+ \dp\nextbox\d_grph_rotate_saved_depth
+ \else
+ \wd\nextbox\d_grph_rotate_new_width
+ \ht\nextbox\d_grph_rotate_new_height
+ \dp\nextbox\d_grph_rotate_new_depth
+ \fi
+ %
+ \boxcursor\box\nextbox}
% \dostepwiserecurse{0}{360}{10}
% {\startlinecorrection[blank]
@@ -1077,4 +1019,23 @@
% \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=high] {\ruledhbox{\bfb (high)}}}}}
% \stoplinecorrection}
+% \def\Test{\ruledhbox{%
+% \def\DemoX{\vl\kern.5\emwidth\vl}%
+% \kern\emwidth\ruledhpack{\green\rotate[rotation=20] {\ruledhpack{\DemoX}}}%
+% \kern\emwidth\ruledhpack{\blue \rotate[rotation=0] {\ruledhpack{\DemoX}}}%
+% \kern\emwidth\ruledhpack{\red \rotate[rotation=-20] {\ruledhpack{\DemoX}}}%
+% \kern\emwidth\ruledhpack{\green\rotate[rotation=200] {\ruledhpack{\DemoX}}}%
+% \kern\emwidth\ruledhpack{\blue \rotate[rotation=180] {\ruledhpack{\DemoX}}}%
+% \kern\emwidth\ruledhpack{\red \rotate[rotation=-200]{\ruledhpack{\DemoX}}}%
+% \kern\emwidth}}
+
+% \startTEXpage[offset=10pt,align=middle]
+% \setuprotate[location=fit] \Test \par {\infofont\setstrut\strut fit} \par
+% \setuprotate[location=depth] \Test \par {\infofont\setstrut\strut depth} \par
+% \setuprotate[location=broad] \Test \par {\infofont\setstrut\strut broad} \par
+% \setuprotate[location=high] \Test \par {\infofont\setstrut\strut high} \par
+% \setuprotate[location=middle] \Test \par {\infofont\setstrut\strut middle} \par
+% \setuprotate[location=default] \Test \par {\infofont\setstrut\strut default} \par
+% \stopTEXpage
+
\protect \endinput
diff --git a/tex/context/base/mkiv/lpdf-lmt.lua b/tex/context/base/mkiv/lpdf-lmt.lua
index 8148bec01..ab07e984d 100644
--- a/tex/context/base/mkiv/lpdf-lmt.lua
+++ b/tex/context/base/mkiv/lpdf-lmt.lua
@@ -2228,20 +2228,22 @@ local openfile, closefile do
closefile = function(abort)
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
+ if not environment.arguments.nodummy then
+ 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()
end
- f:close()
- removefile(abort)
end
+ removefile(abort)
else
local xrefoffset = offset
local lastfree = 0
diff --git a/tex/context/base/mkiv/math-ini.mkiv b/tex/context/base/mkiv/math-ini.mkiv
index ca92476ed..c419e39ee 100644
--- a/tex/context/base/mkiv/math-ini.mkiv
+++ b/tex/context/base/mkiv/math-ini.mkiv
@@ -103,9 +103,9 @@
\def\Umathaccents {\Umathaccent \s!both }
\ifdefined\Umathcharclass \else
- \def\Umathcharclass{\cldcontext{tex.getmathcode(token.scan_int())[1]}}
- \def\Umathcharfam {\cldcontext{tex.getmathcode(token.scan_int())[2]}}
- \def\Umathcharslot {\cldcontext{tex.getmathcode(token.scan_int())[3]}}
+ \def\Umathcharclass{\numexpr\cldcontext{tex.getmathcode(token.scan_int())[1]}\relax}
+ \def\Umathcharfam {\numexpr\cldcontext{tex.getmathcode(token.scan_int())[2]}\relax}
+ \def\Umathcharslot {\numexpr\cldcontext{tex.getmathcode(token.scan_int())[3]}\relax}
\fi
%D The attributes that we will use (todo: pack some into one but uglier code):
@@ -2924,6 +2924,71 @@
\let\unstackscripts\math_scripts_unstack
\to \everymathematics
+%D Expensive (tracing and inject) but a primitive (using factors) is tricky as we
+%D want this frozen support.
+
+\ifcase\contextlmtxmode
+
+ \def\math_openup_parameter#1#2%
+ {\ifzeropt#1\displaystyle \else\ifdim#1\displaystyle =\maxdimen\else\frozen#1\displaystyle #2#1\displaystyle \fi\fi
+ \ifzeropt#1\crampeddisplaystyle \else\ifdim#1\crampeddisplaystyle =\maxdimen\else\frozen#1\crampeddisplaystyle #2#1\crampeddisplaystyle \fi\fi
+ \ifzeropt#1\textstyle \else\ifdim#1\textstyle =\maxdimen\else\frozen#1\textstyle #2#1\textstyle \fi\fi
+ \ifzeropt#1\crampedtextstyle \else\ifdim#1\crampedtextstyle =\maxdimen\else\frozen#1\crampedtextstyle #2#1\crampedtextstyle \fi\fi
+ \ifzeropt#1\scriptstyle \else\ifdim#1\scriptstyle =\maxdimen\else\frozen#1\scriptstyle #2#1\scriptstyle \fi\fi
+ \ifzeropt#1\crampedscriptstyle \else\ifdim#1\crampedscriptstyle =\maxdimen\else\frozen#1\crampedscriptstyle #2#1\crampedscriptstyle \fi\fi
+ \ifzeropt#1\scriptscriptstyle \else\ifdim#1\scriptscriptstyle =\maxdimen\else\frozen#1\scriptscriptstyle #2#1\scriptscriptstyle \fi\fi
+ \ifzeropt#1\crampedscriptscriptstyle\else\ifdim#1\crampedscriptscriptstyle=\maxdimen\else\frozen#1\crampedscriptscriptstyle#2#1\crampedscriptscriptstyle\fi\fi}
+
+\else
+
+ % \def\math_openup_parameter#1#2%
+ % {\ifzeropt#1\displaystyle \orelse\ifdim#1\displaystyle =\maxdimen\else\frozen#1\displaystyle #2#1\displaystyle \fi
+ % \ifzeropt#1\crampeddisplaystyle \orelse\ifdim#1\crampeddisplaystyle =\maxdimen\else\frozen#1\crampeddisplaystyle #2#1\crampeddisplaystyle \fi
+ % \ifzeropt#1\textstyle \orelse\ifdim#1\textstyle =\maxdimen\else\frozen#1\textstyle #2#1\textstyle \fi
+ % \ifzeropt#1\crampedtextstyle \orelse\ifdim#1\crampedtextstyle =\maxdimen\else\frozen#1\crampedtextstyle #2#1\crampedtextstyle \fi
+ % \ifzeropt#1\scriptstyle \orelse\ifdim#1\scriptstyle =\maxdimen\else\frozen#1\scriptstyle #2#1\scriptstyle \fi
+ % \ifzeropt#1\crampedscriptstyle \orelse\ifdim#1\crampedscriptstyle =\maxdimen\else\frozen#1\crampedscriptstyle #2#1\crampedscriptstyle \fi
+ % \ifzeropt#1\scriptscriptstyle \orelse\ifdim#1\scriptscriptstyle =\maxdimen\else\frozen#1\scriptscriptstyle #2#1\scriptscriptstyle \fi
+ % \ifzeropt#1\crampedscriptscriptstyle\orelse\ifdim#1\crampedscriptscriptstyle=\maxdimen\else\frozen#1\crampedscriptscriptstyle#2#1\crampedscriptscriptstyle\fi}
+
+ % \def\mdim#1#2%
+ % {\ifcase\ifzeropt#1#2\plusone\orelse\ifdim#1#2=\maxdimen\plusone\else\zerocount\fi}
+ %
+ % \def\mdim
+ % {\afterassignment\mmdim\scratchdimen}
+ %
+ % \def\mmdim
+ % {\ifcase\ifzeropt\scratchdimen\plusone\orelse\ifdim\scratchdimen=\maxdimen\plusone\else\zerocount\fi}
+ %
+ % \def\math_openup_parameter#1#2%
+ % {\ifcondition\mdim#1\displaystyle \frozen#1\displaystyle #2\dimexpr#1\displaystyle \relax\fi
+ % \ifcondition\mdim#1\crampeddisplaystyle \frozen#1\crampeddisplaystyle #2\dimexpr#1\crampeddisplaystyle \relax\fi
+ % \ifcondition\mdim#1\textstyle \frozen#1\textstyle #2\dimexpr#1\textstyle \relax\fi
+ % \ifcondition\mdim#1\crampedtextstyle \frozen#1\crampedtextstyle #2\dimexpr#1\crampedtextstyle \relax\fi
+ % \ifcondition\mdim#1\scriptstyle \frozen#1\scriptstyle #2\dimexpr#1\scriptstyle \relax\fi
+ % \ifcondition\mdim#1\crampedscriptstyle \frozen#1\crampedscriptstyle #2\dimexpr#1\crampedscriptstyle \relax\fi
+ % \ifcondition\mdim#1\scriptscriptstyle \frozen#1\scriptscriptstyle #2\dimexpr#1\scriptscriptstyle \relax\fi
+ % \ifcondition\mdim#1\crampedscriptscriptstyle\frozen#1\crampedscriptscriptstyle#2\dimexpr#1\crampedscriptscriptstyle\relax\fi}
+
+ % \Umathparameter : 0=zero, 1=set, 2=unset (les stracing clutter this way)
+
+ \def\math_openup_parameter#1#2%
+ {\ifcase\Umathparameter#1\displaystyle \or\frozen#1\displaystyle #2#1\displaystyle \fi
+ \ifcase\Umathparameter#1\crampeddisplaystyle \or\frozen#1\crampeddisplaystyle #2#1\crampeddisplaystyle \fi
+ \ifcase\Umathparameter#1\textstyle \or\frozen#1\textstyle #2#1\textstyle \fi
+ \ifcase\Umathparameter#1\crampedtextstyle \or\frozen#1\crampedtextstyle #2#1\crampedtextstyle \fi
+ \ifcase\Umathparameter#1\scriptstyle \or\frozen#1\scriptstyle #2#1\scriptstyle \fi
+ \ifcase\Umathparameter#1\crampedscriptstyle \or\frozen#1\crampedscriptstyle #2#1\crampedscriptstyle \fi
+ \ifcase\Umathparameter#1\scriptscriptstyle \or\frozen#1\scriptscriptstyle #2#1\scriptscriptstyle \fi
+ \ifcase\Umathparameter#1\crampedscriptscriptstyle\or\frozen#1\crampedscriptscriptstyle#2#1\crampedscriptscriptstyle\fi}
+
+\fi
+
+\unexpanded\def\mathopenupparameter#1#2%
+ {\ifdim#2\points=\zeropoint\else
+ \math_openup_parameter#1{#2}%
+ \fi}
+
\protect \endinput
% % not used (yet)
diff --git a/tex/context/base/mkiv/math-rad.mkvi b/tex/context/base/mkiv/math-rad.mkvi
index c0b128a61..c640e768e 100644
--- a/tex/context/base/mkiv/math-rad.mkvi
+++ b/tex/context/base/mkiv/math-rad.mkvi
@@ -43,8 +43,36 @@
% \let\normalsurd\surd % \Uradical "0 "221A
% \unexpanded\def\surd{\normalsurd{}}
-
-%D The real thing:
+%D The real thing. If needed one can control matters with one of the many
+%D \type {\Umath...} parameters.
+%D
+%D \starttyping
+%D \def\R {\Umathradicaldegreeafter\textstyle0pt}
+%D \def\RR{\Umathradicaldegreeafter\textstyle\dimexpr
+%D \Umathradicaldegreeafter\textstyle+.1em\relax}
+%D \def\RRR{\frozen\Umathradicaldegreeafter\textstyle\dimexpr
+%D \Umathradicaldegreeafter\textstyle+.2em\relax}
+%D
+%D $ \sqrt[3]{5} \RR\sqrt[3]{5} \sqrt[3]{5} $\par
+%D $ \sqrt[3]{5} {\RRR\sqrt[3]{5}} \sqrt[3]{5} $\par
+%D $ \RR\sqrt[3]{5} {\RRR\sqrt[3]{5}} \sqrt[3]{5} $\par
+%D
+%D \def\R {\Umathradicaldegreeafter\textstyle
+%D 0pt}
+%D \def\RR {\Umathradicaldegreeafter\textstyle
+%D 0.95\Umathradicaldegreeafter\textstyle}
+%D \def\RRR{\frozen\Umathradicaldegreeafter\textstyle
+%D 0.9\Umathradicaldegreeafter\textstyle}
+%D
+%D $ \sqrt[3]{5} \RR\sqrt[3]{5} \sqrt[3]{5} $\par
+%D $ \sqrt[3]{5} {\RRR\sqrt[3]{5}} \sqrt[3]{5} $\par
+%D $ \RR\sqrt[3]{5} {\RRR\sqrt[3]{5}} \sqrt[3]{5} $\par
+%D
+%D \def\RR {\mathopenupparameter\Umathradicaldegreeafter{.1}}
+%D
+%D $ \sqrt[3]{5} \RR\sqrt[3]{5} \sqrt[3]{5} $\par
+%D $ \sqrt[3]{5} {\RR\sqrt[3]{5}} \sqrt[3]{5} $\par
+%D \stoptyping
\installcorenamespace{mathradical}
\installcorenamespace{mathradicalalternative}
diff --git a/tex/context/base/mkiv/mlib-ctx.mkxl b/tex/context/base/mkiv/mlib-ctx.mkxl
index bb2460627..dd2d0ae24 100644
--- a/tex/context/base/mkiv/mlib-ctx.mkxl
+++ b/tex/context/base/mkiv/mlib-ctx.mkxl
@@ -18,6 +18,7 @@
\registerctxluafile{mlib-lua}{}
\registerctxluafile{mlib-scn}{}
\registerctxluafile{mlib-mat}{}
+\registerctxluafile{mlib-ran}{}
\registerctxluafile{mlib-lmp}{}
\registerctxluafile{mlib-int}{}
\registerctxluafile{mlib-lmt}{}
diff --git a/tex/context/base/mkiv/mlib-ran.lua b/tex/context/base/mkiv/mlib-ran.lua
new file mode 100644
index 000000000..cb8645e8d
--- /dev/null
+++ b/tex/context/base/mkiv/mlib-ran.lua
@@ -0,0 +1,237 @@
+if not modules then modules = { } end modules ['mlib-ran'] = {
+ version = 1.001,
+ comment = "companion to mlib-ctx.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+}
+
+local next = next
+local ceil, floor, random, sqrt, cos, sin, pi, max, min = math.ceil, math.floor, math.random, math.sqrt, math.cos, math.sin, math.pi, math.min, math.max
+local remove = table.remove
+
+-- Below is a bit of rainy saturday afternoon hobyism, while listening to Judith
+-- Owens redisCOVERed (came there via Leland Sklar who I have on a few live blurays;
+-- and who is also on YT). (Also nice: https://www.youtube.com/watch?v=GXqasIRaxlA)
+
+-- When Aditya pointed me to an article on mazes I ended up at poison distributions
+-- which to me looks nicer than what I normally do, fill a grid and then randomize
+-- the resulting positions. With some hooks this can be used for interesting patterns
+-- too. A few links:
+--
+-- https://bost.ocks.org/mike/algorithms/#maze-generation
+-- https://extremelearning.com.au/
+-- https://www.jasondavies.com/maps/random-points/
+-- http://devmag.org.za/2009/05/03/poisson-disk-sampling
+
+-- The next function is quite close to what us discribed in the poisson-disk-sampling
+-- link mentioned before. One can either use a one dimensional grid array or a two
+-- dimensional one. The example code uses some classes dealing with points. In the
+-- process I added some more control.
+
+-- we could do without the samplepoints list
+
+local function poisson(width, height, mindist, newpointscount, initialx, initialy)
+ local starttime = os.clock()
+ local cellsize = mindist / sqrt(2)
+ local nofwidth = ceil(width // cellsize)
+ local nofheight = ceil(height // cellsize)
+ local grid = lua.newtable(nofwidth,0) -- table.setmetatableindex("table")
+ local firstx = initialx or random() * width
+ local firsty = initialy or random() * height
+ local firstpoint = { firstx, firsty, 1 }
+ -- local samplepoints = { firstpoint }
+ local processlist = { firstpoint }
+ local nofprocesslist = 1
+ local nofsamplepoints = 1
+ local twopi = 2 * pi
+
+ for i=1,nofwidth do
+ local g = lua.newindex(nofheight,false)
+ grid[i] = g
+ end
+
+ local x = floor(firstx // cellsize) + 1 -- lua indices
+ local y = floor(firsty // cellsize) + 1 -- lua indices
+
+ x = max(1, min(x, width - 1))
+ y = max(1, min(y, height - 1))
+
+ grid[x][y] = firstpoint
+
+ -- The website shows graphic for this 5*5 grid snippet, if we use a one dimentional
+ -- array then we could have one loop; a first version used a metatable trick so we
+ -- had grid[i+gx][j+gy] but we no we also return the grid, so ... we now just check.
+
+ -- There is no need for the samplepoints list as we can get that from the grid but
+ -- instead we can store the index with the grid.
+
+ while nofprocesslist > 0 do
+ local point = remove(processlist,random(1,nofprocesslist))
+ nofprocesslist = nofprocesslist - 1
+ for i=1,newpointscount do -- we start at 1
+ local radius = mindist * (random() + 1)
+ local angle = twopi * random()
+ local nx = point[1] + radius * cos(angle)
+ local ny = point[2] + radius * sin(angle)
+ if nx > 1 and ny > 1 and nx <= width and ny <= height then -- lua indices
+ local gx = floor(nx // cellsize)
+ local gy = floor(ny // cellsize)
+ -- the 5x5 cells around the point
+ for i=-2,2 do
+ for j=-2,2 do
+ local cell = grid[i + gx]
+ if cell then
+ cell = cell[j + gy]
+ if cell and sqrt((cell[1] - nx)^2 + (cell[2] - ny)^2) < mindist then
+ goto next
+ end
+ end
+ end
+ end
+ -- local newpoint = { nx, ny }
+ nofprocesslist = nofprocesslist + 1
+ nofsamplepoints = nofsamplepoints + 1
+ local newpoint = { nx, ny, nofsamplepoints }
+ processlist [nofprocesslist] = newpoint
+ -- samplepoints[nofsamplepoints] = newpoint
+ grid[gx][gy] = newpoint
+ end
+ ::next::
+ end
+ end
+
+ return {
+ count = nofsamplepoints,
+ -- points = samplepoints,
+ grid = grid,
+ time = os.clock() - starttime,
+ }
+end
+
+-- For now:
+
+local randomizers = utilities.randomizers or { }
+utilities.randomizers = randomizers
+randomizers.poisson = poisson
+
+-- The MetaFun interface:
+
+local formatters = string.formatters
+local concat = table.concat
+
+local f_macro = formatters["%s(%N,%N);"]
+
+local f_macros = {
+ [2] = formatters["%s(%N,%N);"],
+ [3] = formatters["%s(%N,%N,%i);"],
+ [4] = formatters["%s(%N,%N,%i,%i);"],
+}
+
+function grid_to_mp(t,f,n)
+ local grid = t.grid
+ local count = t.count
+ local result = { }
+ local r = 0
+ local macro = f or "draw"
+ local runner = f_macros[n or 2] or f_macros[2]
+ for i=1,#grid do
+ local g = grid[i]
+ if g then
+ for j=1,#g do
+ local v = g[j]
+ if v then
+ r = r + 1
+ result[r] = runner(macro,v[1],v[2],v[3],count)
+ end
+ end
+ end
+ end
+ return concat(result, " ")
+end
+
+local getparameter = metapost.getparameter
+
+local function lmt_poisson()
+ local initialx = getparameter { "initialx" }
+ local initialy = getparameter { "initialy" }
+ local width = getparameter { "width" }
+ local height = getparameter { "height" }
+ local distance = getparameter { "distance" }
+ local count = getparameter { "count" }
+
+ local result = poisson (
+ width, height, distance, count,
+ initialx > 0 and initialx or false,
+ initialy > 0 and initialy or false
+ )
+
+ if result then
+ logs.report("poisson","w=%N, h=%N, d=%N, c=%N, n=%i, runtime %.3f",
+ width, height, distance, count, result.count, result.time
+ )
+ end
+
+ return result
+end
+
+function mp.lmt_poisson_generate()
+ local result = lmt_poisson()
+ if result then
+ return grid_to_mp (
+ result,
+ getparameter { "macro" },
+ getparameter { "arguments" }
+ )
+ end
+end
+
+-- -- some playing around showed no benefit
+--
+-- function points_to_mp(t,f)
+-- local points = t.points
+-- local count = t.count
+-- local result = { }
+-- local r = 0
+-- local macro = f or "draw"
+-- local runner = f_macros[n or 2] or f_macros[2]
+-- for i=1,count do
+-- local v = points[i]
+-- r = r + 1
+-- result[r] = runner(macro,v[1],v[2],v[3],count)
+-- end
+-- return concat(result, " ")
+-- end
+--
+-- local result = false
+-- local i, j, n = 0, 0, 0
+--
+-- function mp.lmt_poison_start()
+-- result = lmt_poisson()
+-- end
+--
+-- function mp.lmt_poisson_stop()
+-- result = false
+-- end
+--
+-- function mp.lmt_poisson_count()
+-- return result and result.count or 0
+-- end
+--
+-- function mp.lmt_poisson_get(i)
+-- if result then
+-- return mp.pair(result.points[i])
+-- end
+-- end
+--
+-- function mp.lmt_poisson_generate()
+-- mp.lmt_poisson_start()
+-- if result then
+-- return grid_to_mp (
+-- result,
+-- getparameter { "macro" },
+-- getparameter { "arguments" }
+-- )
+-- end
+-- mp.lmt_poisson_stop()
+-- end
diff --git a/tex/context/base/mkiv/mult-prm.lua b/tex/context/base/mkiv/mult-prm.lua
index 5ff7f6bfc..36a8cd8e5 100644
--- a/tex/context/base/mkiv/mult-prm.lua
+++ b/tex/context/base/mkiv/mult-prm.lua
@@ -159,6 +159,7 @@ return {
"Umathoverbarvgap",
"Umathoverdelimiterbgap",
"Umathoverdelimitervgap",
+ "Umathparameter",
"Umathpunctbinspacing",
"Umathpunctclosespacing",
"Umathpunctinnerspacing",
@@ -219,6 +220,7 @@ return {
"Ustartmath",
"Ustopdisplaymath",
"Ustopmath",
+ "Ustyle",
"Usubscript",
"Usuperscript",
"Uunderdelimiter",
diff --git a/tex/context/base/mkiv/node-res.lua b/tex/context/base/mkiv/node-res.lua
index 1832a0d1e..9b76fed54 100644
--- a/tex/context/base/mkiv/node-res.lua
+++ b/tex/context/base/mkiv/node-res.lua
@@ -36,6 +36,7 @@ local glyph_code = nodecodes.glyph
local rule_code = nodecodes.rule
local kern_code = nodecodes.kern
local glue_code = nodecodes.glue
+local gluespec_code = nodecodes.gluespec
local whatsit_code = nodecodes.whatsit
local currentfont = font.current
@@ -163,6 +164,7 @@ local fontkern = register_nut(new_nut(kern_code,kerncodes.fontkern))
local italickern = register_nut(new_nut(kern_code,kerncodes.italiccorrection))
local penalty = register_nut(new_nut(nodecodes.penalty))
local glue = register_nut(new_nut(glue_code))
+local gluespec = register_nut(new_nut(gluespec_code))
local glyph = register_nut(new_nut(glyph_code,0))
local textdir = register_nut(new_nut(nodecodes.dir))
@@ -283,6 +285,14 @@ function nutpool.italickern(k)
return n
end
+function nutpool.gluespec(width,stretch,shrink,stretch_order,shrink_order)
+ local n = copy_nut(gluespec)
+ if width or stretch or shrink or stretch_order or shrink_order then
+ setglue(n,width,stretch,shrink,stretch_order,shrink_order)
+ end
+ return n
+end
+
local function someskip(skip,width,stretch,shrink,stretch_order,shrink_order)
-- maybe setglue
local n = copy_nut(skip)
diff --git a/tex/context/base/mkiv/spac-par.mkiv b/tex/context/base/mkiv/spac-par.mkiv
index 7678cc34b..1fd1cbd8a 100644
--- a/tex/context/base/mkiv/spac-par.mkiv
+++ b/tex/context/base/mkiv/spac-par.mkiv
@@ -15,13 +15,19 @@
\unprotect
-%D The dreadful sequence \type {\bgroup} \unknown\
-%D \type {\carryoverpar} \unknown\ \type {\egroup} is needed
-%D when for instance sidefloats are used in combination with
-%D something that starts with a group. This is because
-%D otherwise the indentation as set (by the output routine)
-%D inside the group are forgotten afterwards. (I must
-%D not forget its existence).
+%D The dreadful sequence \type {\bgroup} \unknown\ \type {\carryoverpar} \unknown\
+%D \type {\egroup} is needed when for instance sidefloats are used in combination
+%D with something that starts with a group. This is because otherwise the
+%D indentation as set (by the output routine) inside the group are forgotten
+%D afterwards. (I must not forget its existence).
+
+% Todo (maybe):
+%
+% \parshape \getparshape\relax
+% \interlinepenalties \getinterlinepenalties\relax
+% \clubpenalties \getclubpenalties\relax
+% \widowpenalties \getwidowpenalties\relax
+% \displaywidowpenalties\getdisplaywidowpenalties\relax
\def\carryoverpar#1% #1 can be \endgroup or \egroup or ... expandable !
{\normalexpanded
@@ -43,8 +49,8 @@
\unexpanded\def\flushparagraphproperties
{\popmacro\currentparagraphproperties}
-% Beware, changing this will break some code (like pos/backgrounds) but
-% it has been changed anyway so let's see where things go wrong.
+%D Beware, changing this will break some code (like pos/backgrounds) but it has been
+%D changed anyway so let's see where things go wrong.
\installcorenamespace{paragraphintro}
@@ -133,11 +139,11 @@
\gtoksapp\t_spac_paragraphs_intro_first{#1}%
\glet\insertparagraphintro\spac_paragraphs_flush_intro}
-%D Here comes the flusher (we misuse the one level expansion of token
-%D registers to feed a nice stream into the paragraph.)
+%D Here comes the flusher (we misuse the one level expansion of token registers to
+%D feed a nice stream into the paragraph.)
-\unexpanded\def\spac_paragraphs_flush_intro % we make sure that the token lists expand directly after another
- {\normalexpanded{% % so the first code is there twice
+\unexpanded\def\spac_paragraphs_flush_intro % we make sure that the token lists expand directly
+ {\normalexpanded{% % after another so the first code is there twice
\ifconditional\c_spac_paragraphs_intro_each
\ifconditional\c_spac_paragraphs_intro_next
\glet\insertparagraphintro\spac_paragraphs_flush_intro_next
@@ -180,8 +186,8 @@
%D \macros
%D {flushatnextpar}
%D
-%D This macro collects data that will be flushed at the next paragraph.
-%D By using this macro you can avoid interfering nodes (writes, etc).
+%D This macro collects data that will be flushed at the next paragraph. By using
+%D this macro you can avoid interfering nodes (writes, etc).
\let\flushpostponednodedata\relax % hook into everypar
diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf
index 97606d8ba..2fc104db6 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 858c331bb..20fc6a9b8 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/supp-ran.lua b/tex/context/base/mkiv/supp-ran.lua
index 1a2d10bea..ef2654406 100644
--- a/tex/context/base/mkiv/supp-ran.lua
+++ b/tex/context/base/mkiv/supp-ran.lua
@@ -132,6 +132,8 @@ utilities.randomizer = {
reuseseed = reuserandomseed,
popseed = poprandomseed,
get = getrandom,
+ -- the original, only for testing
+ -- mathrandom = random,
}
-- todo: also open up in utilities.randomizer.*
diff --git a/tex/context/base/mkiv/syst-aux.lua b/tex/context/base/mkiv/syst-aux.lua
index 28fcb65fa..e28e23be0 100644
--- a/tex/context/base/mkiv/syst-aux.lua
+++ b/tex/context/base/mkiv/syst-aux.lua
@@ -11,20 +11,20 @@ if not modules then modules = { } end modules ['syst-aux'] = {
-- utfmatch(str,"(.?)(.*)$")
-- utf.sub(str,1,1)
-local tonumber, next = tonumber, next
+local tonumber, next, type = tonumber, next, type
local utfsub = utf.sub
local P, S, R, C, Cc, Cs, Carg, lpegmatch = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Carg, lpeg.match
local next = next
-local find = string.find
+local find, formatters = string.find, string.formatters
local context = context
local implement = interfaces.implement
-local formatters = string.formatters
+local setmacro = interfaces.setmacro
local setcatcode = tex.setcatcode
+local texget = tex.get
local utf8character = lpeg.patterns.utf8character
local settings_to_array = utilities.parsers.settings_to_array
local settings_to_set = utilities.parsers.settings_to_set
-local setmacro = interfaces.setmacro
local pattern = C(utf8character^-1) * C(P(1)^0)
@@ -780,15 +780,58 @@ implement {
local bp = number.dimenfactors.bp
-interfaces.implement {
+implement {
name = "tobigpoints",
actions = function(d) context("%.5F",bp * d) end,
arguments = "dimension",
}
-interfaces.implement {
+implement {
name = "towholebigpoints",
actions = function(d) context("%r",bp * d) end,
arguments = "dimension",
}
+-- for now here:
+
+local function getshape(s)
+ local t = texget(s)
+ local n = t and #t or 0
+ context(n)
+ if n > 0 then
+ for i=1,n do
+ local ti = t[i]
+ if type(ti) == "table" then
+ context(" %isp %isp",ti[1],ti[2])
+ else
+ context(" %i",ti)
+ end
+ end
+ end
+end
+
+implement {
+ name = "getparshape",
+ public = true,
+ actions = function() getshape("parshape") end,
+}
+implement {
+ name = "getclubpenalties",
+ public = true,
+ actions = function() getshape("clubpenalties") end,
+}
+implement {
+ name = "getinterlinepenalties",
+ public = true,
+ actions = function() getshape("interlinepenalties") end,
+ }
+implement {
+ name = "getdisplaywidowpenalties",
+ public = true,
+ actions = function() getshape("displaywidowpenalties") end,
+}
+implement {
+ name = "getwidowpenalties",
+ public = true,
+ actions = function() getshape("widowpenalties") end,
+}
diff --git a/tex/context/base/mkiv/toks-ini.lua b/tex/context/base/mkiv/toks-ini.lua
index eef26574e..594fb4743 100644
--- a/tex/context/base/mkiv/toks-ini.lua
+++ b/tex/context/base/mkiv/toks-ini.lua
@@ -39,6 +39,7 @@ local scan_code = token.scan_code
local scan_token_code = token.scan_token_code
local scan_dimen = token.scan_dimen
local scan_glue = token.scan_glue
+local scan_gluespec = token.scan_skip
local scan_keyword = token.scan_keyword
local scan_keyword_cs = token.scan_keyword_cs or scan_keyword
local scan_token = token.scan_token
@@ -164,7 +165,7 @@ tokens.scanners = { -- these expand
dimen = scan_dimen,
dimension = scan_dimen,
glue = scan_glue,
- skip = scan_glue,
+ gluespec = scan_gluespec,
integer = scan_int,
real = scan_real,
float = scan_float,
diff --git a/tex/context/base/mkiv/toks-scn.lua b/tex/context/base/mkiv/toks-scn.lua
index 2d20d5a8b..fcbdec5a0 100644
--- a/tex/context/base/mkiv/toks-scn.lua
+++ b/tex/context/base/mkiv/toks-scn.lua
@@ -262,6 +262,7 @@ local f_any_all_c= formatters[" local key = scanword() if key then data[key] =
local f_table = formatters["%\nt\nreturn function()\n local data = { }\n%s\n return %s\nend\n"]
local f_sequence = formatters["%\nt\n%\nt\n%\nt\nreturn function()\n return %s\nend\n"]
+local f_singular = formatters["%\nt\n%\nt\n\nreturn function(%s)\n return %s\nend\n"]
local f_simple = formatters["%\nt\nreturn function()\n return %s\nend\n"]
local f_string = formatters["%q"]
local f_action_f = formatters["action%s(%s)"]
@@ -331,6 +332,7 @@ function tokens.compile(specification)
a = { a }
end
local code
+ local args
local function compile(t,nested)
local done = s_done
local r = { }
@@ -437,6 +439,23 @@ function tokens.compile(specification)
else
return scanners[ti]
end
+ elseif #t == 0 then
+ if specification.valuetype then
+ code = "b"
+ args = "_,b"
+ else
+ code = ""
+ args = ""
+ end
+ if a then
+ tokens._action = a
+ for i=1,#a do
+ code = f_action_f(i,code)
+ n = n + 1
+ f[n] = f_action_s(i,i)
+ end
+ end
+ code = f_singular(c,f,args,code)
else
local r = { }
local p = { }
diff --git a/tex/context/base/mkiv/typo-del.mkiv b/tex/context/base/mkiv/typo-del.mkiv
index 9320c37ee..afa7e0ffe 100644
--- a/tex/context/base/mkiv/typo-del.mkiv
+++ b/tex/context/base/mkiv/typo-del.mkiv
@@ -524,6 +524,7 @@
\begingroup
\usedelimitedtextstyleandcolor\c!style\c!color
%
+ \begingroup
\edef\p_delimited_left {\delimitedtextparameter{\c!left}}%
\edef\p_delimited_right {\delimitedtextparameter{\c!right}}%
\edef\p_delimited_nextleft {\delimitedtextparameter{\c!nextleft}}%
@@ -539,7 +540,10 @@
\def\typo_delimited_stop_par
{\typo_delimited_stop_content
\rightdelimitedtextmark
- \carryoverpar\endgroup % new per 2013-01-21 ... please left floats
+ \rightdelimitedtextmark
+ \carryoverpar\endgroup
+ \endgraf
+ \endgroup
\pop_macro_checkindentation
\typo_delimited_stop_par_indeed
\delimitedtextparameter\c!after
diff --git a/tex/context/base/mkiv/util-tab.lua b/tex/context/base/mkiv/util-tab.lua
index 4dafb2acd..9f7112eb9 100644
--- a/tex/context/base/mkiv/util-tab.lua
+++ b/tex/context/base/mkiv/util-tab.lua
@@ -961,3 +961,12 @@ function table.ordered(t)
return function() end
end
end
+
+-- function table.randomremove(t,n)
+-- if not n then
+-- n = #t
+-- end
+-- if n > 0 then
+-- return remove(t,random(1,n))
+-- end
+-- end