summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/generic/context
diff options
context:
space:
mode:
authorMojca Miklavec <mojca.miklavec@gmail.com>2012-05-14 17:38:55 +0000
committerMojca Miklavec <mojca.miklavec@gmail.com>2012-05-14 17:38:55 +0000
commit15995e10bfc68edf79970c4ea4fbb6678566c46e (patch)
tree2de7ca2a83f2d37ef043ad7429a5cb945bb79ddb /Master/texmf-dist/tex/generic/context
parentc9a39f716f1e5ec820ed3aab2c9aef25c5a9d730 (diff)
ConTeXt 2012.05.14 16:00
git-svn-id: svn://tug.org/texlive/trunk@26371 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/generic/context')
-rw-r--r--Master/texmf-dist/tex/generic/context/luatex/luatex-basics-gen.lua (renamed from Master/texmf-dist/tex/generic/context/luatex-basics-gen.lua)65
-rw-r--r--Master/texmf-dist/tex/generic/context/luatex/luatex-basics-nod.lua (renamed from Master/texmf-dist/tex/generic/context/luatex-basics-nod.lua)0
-rw-r--r--Master/texmf-dist/tex/generic/context/luatex/luatex-basics.tex (renamed from Master/texmf-dist/tex/generic/context/luatex-basics.tex)2
-rw-r--r--Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-cbk.lua (renamed from Master/texmf-dist/tex/generic/context/luatex-fonts-cbk.lua)0
-rw-r--r--Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-def.lua (renamed from Master/texmf-dist/tex/generic/context/luatex-fonts-def.lua)0
-rw-r--r--Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-demo-vf-1.lua (renamed from Master/texmf-dist/tex/generic/context/luatex-fonts-demo-vf-1.lua)0
-rw-r--r--Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-enc.lua (renamed from Master/texmf-dist/tex/generic/context/luatex-fonts-enc.lua)2
-rw-r--r--Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-ext.lua (renamed from Master/texmf-dist/tex/generic/context/luatex-fonts-ext.lua)6
-rw-r--r--Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-lua.lua (renamed from Master/texmf-dist/tex/generic/context/luatex-fonts-lua.lua)0
-rw-r--r--Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-merged.lua (renamed from Master/texmf-dist/tex/generic/context/luatex-fonts-merged.lua)3750
-rw-r--r--Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-syn.lua (renamed from Master/texmf-dist/tex/generic/context/luatex-fonts-syn.lua)0
-rw-r--r--Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-tfm.lua (renamed from Master/texmf-dist/tex/generic/context/luatex-fonts-tfm.lua)0
-rw-r--r--Master/texmf-dist/tex/generic/context/luatex/luatex-fonts.lua (renamed from Master/texmf-dist/tex/generic/context/luatex-fonts.lua)19
-rw-r--r--Master/texmf-dist/tex/generic/context/luatex/luatex-fonts.tex (renamed from Master/texmf-dist/tex/generic/context/luatex-fonts.tex)2
-rw-r--r--Master/texmf-dist/tex/generic/context/luatex/luatex-mplib.lua (renamed from Master/texmf-dist/tex/generic/context/luatex-mplib.lua)0
-rw-r--r--Master/texmf-dist/tex/generic/context/luatex/luatex-mplib.tex (renamed from Master/texmf-dist/tex/generic/context/luatex-mplib.tex)2
-rw-r--r--Master/texmf-dist/tex/generic/context/luatex/luatex-plain.tex25
-rw-r--r--Master/texmf-dist/tex/generic/context/luatex/luatex-preprocessor-test.tex (renamed from Master/texmf-dist/tex/generic/context/luatex-preprocessor-test.tex)0
-rw-r--r--Master/texmf-dist/tex/generic/context/luatex/luatex-preprocessor.lua (renamed from Master/texmf-dist/tex/generic/context/luatex-preprocessor.lua)0
-rw-r--r--Master/texmf-dist/tex/generic/context/luatex/luatex-preprocessor.tex (renamed from Master/texmf-dist/tex/generic/context/luatex-preprocessor.tex)2
-rw-r--r--Master/texmf-dist/tex/generic/context/luatex/luatex-test.tex (renamed from Master/texmf-dist/tex/generic/context/luatex-test.tex)4
-rw-r--r--Master/texmf-dist/tex/generic/context/m-metapo.tex89
-rw-r--r--Master/texmf-dist/tex/generic/context/mptopdf/mptopdf.tex (renamed from Master/texmf-dist/tex/generic/context/mptopdf.tex)2
-rw-r--r--Master/texmf-dist/tex/generic/context/ppchtex/m-ch-de.tex (renamed from Master/texmf-dist/tex/generic/context/m-ch-de.tex)0
-rw-r--r--Master/texmf-dist/tex/generic/context/ppchtex/m-ch-en.tex (renamed from Master/texmf-dist/tex/generic/context/m-ch-en.tex)0
-rw-r--r--Master/texmf-dist/tex/generic/context/ppchtex/m-ch-nl.tex (renamed from Master/texmf-dist/tex/generic/context/m-ch-nl.tex)0
-rw-r--r--Master/texmf-dist/tex/generic/context/ppchtex/ppchtex.noc (renamed from Master/texmf-dist/tex/generic/context/ppchtex.noc)0
27 files changed, 2407 insertions, 1563 deletions
diff --git a/Master/texmf-dist/tex/generic/context/luatex-basics-gen.lua b/Master/texmf-dist/tex/generic/context/luatex/luatex-basics-gen.lua
index 602601d5cc7..bdbc3cf5188 100644
--- a/Master/texmf-dist/tex/generic/context/luatex-basics-gen.lua
+++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-basics-gen.lua
@@ -80,6 +80,8 @@ local remapper = {
dfont = "truetype fonts", -- "truetype dictionary",
cid = "cid maps",
fea = "font feature files",
+ pfa = "type1 fonts", -- this is for Khaled, in ConTeXt we don't use this!
+ pfb = "type1 fonts", -- this is for Khaled, in ConTeXt we don't use this!
}
function resolvers.findfile(name,fileformat)
@@ -191,7 +193,7 @@ end
local function makefullname(path,name)
if path and path ~= "" then
name = "temp-" .. name -- clash prevention
- return file.addsuffix(file.join(path,name),"lua")
+ return file.addsuffix(file.join(path,name),"lua"), file.addsuffix(file.join(path,name),"luc")
end
end
@@ -202,25 +204,66 @@ end
function caches.loaddata(paths,name)
for i=1,#paths do
- local fullname = makefullname(paths[i],name)
- if fullname then
- texio.write(string.format("(load: %s)",fullname))
- local data = loadfile(fullname)
- return data and data()
+ local data = false
+ local luaname, lucname = makefullname(paths[i],name)
+ if lucname and lfs.isfile(lucname) then
+ texio.write(string.format("(load: %s)",lucname))
+ data = loadfile(lucname)
end
+ if not data and luaname and lfs.isfile(luaname) then
+ texio.write(string.format("(load: %s)",luaname))
+ data = loadfile(luaname)
+ end
+ return data and data()
end
end
function caches.savedata(path,name,data)
- local fullname = makefullname(path,name)
- if fullname then
- texio.write(string.format("(save: %s)",fullname))
- table.tofile(fullname,data,true,{ reduce = true })
+ local luaname, lucname = makefullname(path,name)
+ if luaname then
+ texio.write(string.format("(save: %s)",luaname))
+ table.tofile(luaname,data,true,{ reduce = true })
+ if lucname and type(caches.compile) == "function" then
+ os.remove(lucname) -- better be safe
+ texio.write(string.format("(save: %s)",lucname))
+ caches.compile(data,luaname,lucname)
+ end
+ end
+end
+
+-- According to KH os.execute is not permitted in plain/latex so there is
+-- no reason to use the normal context way. So the method here is slightly
+-- different from the one we have in context. We also use different suffixes
+-- as we don't want any clashes (sharing cache files is not that handy as
+-- context moves on faster.)
+--
+-- Beware: serialization might fail on large files (so maybe we should pcall
+-- this) in which case one should limit the method to luac and enable support
+-- for execution.
+
+caches.compilemethod = "luac" -- luac dump both
+
+function caches.compile(data,luaname,lucname)
+ local done = false
+ if caches.compilemethod == "luac" or caches.compilemethod == "both" then
+ local command = "-o " .. string.quoted(lucname) .. " -s " .. string.quoted(luaname)
+ done = os.spawn("texluac " .. command) == 0
+ end
+ if not done and (caches.compilemethod == "dump" or caches.compilemethod == "both") then
+ local d = table.serialize(data,true)
+ if d and d ~= "" then
+ local f = io.open(lucname,'w')
+ if f then
+ local s = loadstring(d)
+ f:write(string.dump(s))
+ f:close()
+ end
+ end
end
end
--
-local table.setmetatableindex(t,f)
+function table.setmetatableindex(t,f)
setmetatable(t,{ __index = f })
end
diff --git a/Master/texmf-dist/tex/generic/context/luatex-basics-nod.lua b/Master/texmf-dist/tex/generic/context/luatex/luatex-basics-nod.lua
index 151d98a8f31..151d98a8f31 100644
--- a/Master/texmf-dist/tex/generic/context/luatex-basics-nod.lua
+++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-basics-nod.lua
diff --git a/Master/texmf-dist/tex/generic/context/luatex-basics.tex b/Master/texmf-dist/tex/generic/context/luatex/luatex-basics.tex
index 8308204d572..bb34587ff6c 100644
--- a/Master/texmf-dist/tex/generic/context/luatex-basics.tex
+++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-basics.tex
@@ -5,7 +5,7 @@
%D subtitle=Attribute Allocation,
%D author=Hans Hagen,
%D date=\currentdate,
-%D copyright=public domain]
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
%D As soon as we feel the need this file will file will contain an extension
%D to the standard plain register allocation. For the moment we stick to a
diff --git a/Master/texmf-dist/tex/generic/context/luatex-fonts-cbk.lua b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-cbk.lua
index 9db94f65e48..9db94f65e48 100644
--- a/Master/texmf-dist/tex/generic/context/luatex-fonts-cbk.lua
+++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-cbk.lua
diff --git a/Master/texmf-dist/tex/generic/context/luatex-fonts-def.lua b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-def.lua
index 0c2f0dbd583..0c2f0dbd583 100644
--- a/Master/texmf-dist/tex/generic/context/luatex-fonts-def.lua
+++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-def.lua
diff --git a/Master/texmf-dist/tex/generic/context/luatex-fonts-demo-vf-1.lua b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-demo-vf-1.lua
index 3878ae64805..3878ae64805 100644
--- a/Master/texmf-dist/tex/generic/context/luatex-fonts-demo-vf-1.lua
+++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-demo-vf-1.lua
diff --git a/Master/texmf-dist/tex/generic/context/luatex-fonts-enc.lua b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-enc.lua
index ac736f2a6e8..e20c3a03b54 100644
--- a/Master/texmf-dist/tex/generic/context/luatex-fonts-enc.lua
+++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-enc.lua
@@ -18,7 +18,7 @@ fonts.encodings.agl = { }
setmetatable(fonts.encodings.agl, { __index = function(t,k)
if k == "unicodes" then
texio.write(" <loading (extended) adobe glyph list>")
- local unicodes = dofile(resolvers.findfile("font-agl.lua"))
+ local unicodes = dofile(resolvers.findfile("font-age.lua"))
fonts.encodings.agl = { unicodes = unicodes }
return unicodes
else
diff --git a/Master/texmf-dist/tex/generic/context/luatex-fonts-ext.lua b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-ext.lua
index 951afcc7e0b..d8884ccc74c 100644
--- a/Master/texmf-dist/tex/generic/context/luatex-fonts-ext.lua
+++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-ext.lua
@@ -29,7 +29,7 @@ local function initializeitlc(tfmdata,value)
d.italic = it
end
end
- tfmdata.properties.italic_correction = true
+ tfmdata.properties.hasitalics = true
end
end
end
@@ -54,7 +54,7 @@ local function initializeslant(tfmdata,value)
elseif value < -1 then
value = -1
end
- tfmdata.parameters.slant_factor = value
+ tfmdata.parameters.slantfactor = value
end
otffeatures.register {
@@ -75,7 +75,7 @@ local function initializeextend(tfmdata,value)
elseif value < -10 then
value = -10
end
- tfmdata.parameters.extend_factor = value
+ tfmdata.parameters.extendfactor = value
end
otffeatures.register {
diff --git a/Master/texmf-dist/tex/generic/context/luatex-fonts-lua.lua b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-lua.lua
index ec3fe38be3e..ec3fe38be3e 100644
--- a/Master/texmf-dist/tex/generic/context/luatex-fonts-lua.lua
+++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-lua.lua
diff --git a/Master/texmf-dist/tex/generic/context/luatex-fonts-merged.lua b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-merged.lua
index 7e954182ad7..cdef91b38fd 100644
--- a/Master/texmf-dist/tex/generic/context/luatex-fonts-merged.lua
+++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-merged.lua
@@ -1,6 +1,6 @@
-- merged file : luatex-fonts-merged.lua
-- parent file : luatex-fonts.lua
--- merge date : 05/18/11 18:04:18
+-- merge date : 05/14/12 16:00:55
do -- begin closure to overcome local limits and interference
@@ -127,650 +127,6 @@ end -- closure
do -- begin closure to overcome local limits and interference
-if not modules then modules = { } end modules ['l-lpeg'] = {
- version = 1.001,
- comment = "companion to luat-lib.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-local lpeg = require("lpeg")
-
-local type = type
-
--- Beware, we predefine a bunch of patterns here and one reason for doing so
--- is that we get consistent behaviour in some of the visualizers.
-
-lpeg.patterns = lpeg.patterns or { } -- so that we can share
-local patterns = lpeg.patterns
-
-local P, R, S, V, match = lpeg.P, lpeg.R, lpeg.S, lpeg.V, lpeg.match
-local Ct, C, Cs, Cc = lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc
-local lpegtype = lpeg.type
-
-local utfcharacters = string.utfcharacters
-local utfgmatch = unicode and unicode.utf8.gmatch
-
-local anything = P(1)
-local endofstring = P(-1)
-local alwaysmatched = P(true)
-
-patterns.anything = anything
-patterns.endofstring = endofstring
-patterns.beginofstring = alwaysmatched
-patterns.alwaysmatched = alwaysmatched
-
-local digit, sign = R('09'), S('+-')
-local cr, lf, crlf = P("\r"), P("\n"), P("\r\n")
-local newline = crlf + cr + lf
-local escaped = P("\\") * anything
-local squote = P("'")
-local dquote = P('"')
-local space = P(" ")
-
-local utfbom_32_be = P('\000\000\254\255')
-local utfbom_32_le = P('\255\254\000\000')
-local utfbom_16_be = P('\255\254')
-local utfbom_16_le = P('\254\255')
-local utfbom_8 = P('\239\187\191')
-local utfbom = utfbom_32_be + utfbom_32_le
- + utfbom_16_be + utfbom_16_le
- + utfbom_8
-local utftype = utfbom_32_be / "utf-32-be" + utfbom_32_le / "utf-32-le"
- + utfbom_16_be / "utf-16-be" + utfbom_16_le / "utf-16-le"
- + utfbom_8 / "utf-8" + alwaysmatched / "unknown"
-
-local utf8next = R("\128\191")
-
-patterns.utf8one = R("\000\127")
-patterns.utf8two = R("\194\223") * utf8next
-patterns.utf8three = R("\224\239") * utf8next * utf8next
-patterns.utf8four = R("\240\244") * utf8next * utf8next * utf8next
-patterns.utfbom = utfbom
-patterns.utftype = utftype
-
-local utf8char = patterns.utf8one + patterns.utf8two + patterns.utf8three + patterns.utf8four
-local validutf8char = utf8char^0 * endofstring * Cc(true) + Cc(false)
-
-patterns.utf8 = utf8char
-patterns.utf8char = utf8char
-patterns.validutf8 = validutf8char
-patterns.validutf8char = validutf8char
-
-patterns.digit = digit
-patterns.sign = sign
-patterns.cardinal = sign^0 * digit^1
-patterns.integer = sign^0 * digit^1
-patterns.float = sign^0 * digit^0 * P('.') * digit^1
-patterns.cfloat = sign^0 * digit^0 * P(',') * digit^1
-patterns.number = patterns.float + patterns.integer
-patterns.cnumber = patterns.cfloat + patterns.integer
-patterns.oct = P("0") * R("07")^1
-patterns.octal = patterns.oct
-patterns.HEX = P("0x") * R("09","AF")^1
-patterns.hex = P("0x") * R("09","af")^1
-patterns.hexadecimal = P("0x") * R("09","AF","af")^1
-patterns.lowercase = R("az")
-patterns.uppercase = R("AZ")
-patterns.letter = patterns.lowercase + patterns.uppercase
-patterns.space = space
-patterns.tab = P("\t")
-patterns.spaceortab = patterns.space + patterns.tab
-patterns.eol = S("\n\r")
-patterns.spacer = S(" \t\f\v") -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
-patterns.newline = newline
-patterns.emptyline = newline^1
-patterns.nonspacer = 1 - patterns.spacer
-patterns.whitespace = patterns.eol + patterns.spacer
-patterns.nonwhitespace = 1 - patterns.whitespace
-patterns.equal = P("=")
-patterns.comma = P(",")
-patterns.commaspacer = P(",") * patterns.spacer^0
-patterns.period = P(".")
-patterns.colon = P(":")
-patterns.semicolon = P(";")
-patterns.underscore = P("_")
-patterns.escaped = escaped
-patterns.squote = squote
-patterns.dquote = dquote
-patterns.nosquote = (escaped + (1-squote))^0
-patterns.nodquote = (escaped + (1-dquote))^0
-patterns.unsingle = (squote/"") * patterns.nosquote * (squote/"")
-patterns.undouble = (dquote/"") * patterns.nodquote * (dquote/"")
-patterns.unquoted = patterns.undouble + patterns.unsingle -- more often undouble
-patterns.unspacer = ((patterns.spacer^1)/"")^0
-
-patterns.somecontent = (anything - newline - space)^1 -- (utf8char - newline - space)^1
-patterns.beginline = #(1-newline)
-
-local unquoted = Cs(patterns.unquoted * endofstring) -- not C
-
-function string.unquoted(str)
- return match(unquoted,str) or str
-end
-
---~ print(string.unquoted("test"))
---~ print(string.unquoted([["t\"est"]]))
---~ print(string.unquoted([["t\"est"x]]))
---~ print(string.unquoted("\'test\'"))
-
-function lpeg.anywhere(pattern) --slightly adapted from website
- return P { P(pattern) + 1 * V(1) } -- why so complex?
-end
-
-function lpeg.splitter(pattern, action)
- return (((1-P(pattern))^1)/action+1)^0
-end
-
-local splitters_s, splitters_m = { }, { }
-
-local function splitat(separator,single)
- local splitter = (single and splitters_s[separator]) or splitters_m[separator]
- if not splitter then
- separator = P(separator)
- local other = C((1 - separator)^0)
- if single then
- local any = anything
- splitter = other * (separator * C(any^0) + "") -- ?
- splitters_s[separator] = splitter
- else
- splitter = other * (separator * other)^0
- splitters_m[separator] = splitter
- end
- end
- return splitter
-end
-
-lpeg.splitat = splitat
-
---~ local p = splitat("->",false) print(match(p,"oeps->what->more")) -- oeps what more
---~ local p = splitat("->",true) print(match(p,"oeps->what->more")) -- oeps what->more
---~ local p = splitat("->",false) print(match(p,"oeps")) -- oeps
---~ local p = splitat("->",true) print(match(p,"oeps")) -- oeps
-
-local cache = { }
-
-function lpeg.split(separator,str)
- local c = cache[separator]
- if not c then
- c = Ct(splitat(separator))
- cache[separator] = c
- end
- return match(c,str)
-end
-
-function string.split(str,separator)
- local c = cache[separator]
- if not c then
- c = Ct(splitat(separator))
- cache[separator] = c
- end
- return match(c,str)
-end
-
-local spacing = patterns.spacer^0 * newline -- sort of strip
-local empty = spacing * Cc("")
-local nonempty = Cs((1-spacing)^1) * spacing^-1
-local content = (empty + nonempty)^1
-
-patterns.textline = content
-
---~ local linesplitter = Ct(content^0)
---~
---~ function string.splitlines(str)
---~ return match(linesplitter,str)
---~ end
-
-local linesplitter = Ct(splitat(newline))
-
-patterns.linesplitter = linesplitter
-
-function string.splitlines(str)
- return match(linesplitter,str)
-end
-
-local utflinesplitter = utfbom^-1 * Ct(splitat(newline))
-
-patterns.utflinesplitter = utflinesplitter
-
-function string.utfsplitlines(str)
- return match(utflinesplitter,str)
-end
-
---~ lpeg.splitters = cache -- no longer public
-
-local cache = { }
-
-function lpeg.checkedsplit(separator,str)
- local c = cache[separator]
- if not c then
- separator = P(separator)
- local other = C((1 - separator)^1)
- c = Ct(separator^0 * other * (separator^1 * other)^0)
- cache[separator] = c
- end
- return match(c,str)
-end
-
-function string.checkedsplit(str,separator)
- local c = cache[separator]
- if not c then
- separator = P(separator)
- local other = C((1 - separator)^1)
- c = Ct(separator^0 * other * (separator^1 * other)^0)
- cache[separator] = c
- end
- return match(c,str)
-end
-
---~ from roberto's site:
-
-local f1 = string.byte
-
-local function f2(s) local c1, c2 = f1(s,1,2) return c1 * 64 + c2 - 12416 end
-local function f3(s) local c1, c2, c3 = f1(s,1,3) return (c1 * 64 + c2) * 64 + c3 - 925824 end
-local function f4(s) local c1, c2, c3, c4 = f1(s,1,4) return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168 end
-
-local utf8byte = patterns.utf8one/f1 + patterns.utf8two/f2 + patterns.utf8three/f3 + patterns.utf8four/f4
-
-patterns.utf8byte = utf8byte
-
---~ local str = " a b c d "
-
---~ local s = lpeg.stripper(lpeg.R("az")) print("["..lpeg.match(s,str).."]")
---~ local s = lpeg.keeper(lpeg.R("az")) print("["..lpeg.match(s,str).."]")
---~ local s = lpeg.stripper("ab") print("["..lpeg.match(s,str).."]")
---~ local s = lpeg.keeper("ab") print("["..lpeg.match(s,str).."]")
-
-local cache = { }
-
-function lpeg.stripper(str)
- if type(str) == "string" then
- local s = cache[str]
- if not s then
- s = Cs(((S(str)^1)/"" + 1)^0)
- cache[str] = s
- end
- return s
- else
- return Cs(((str^1)/"" + 1)^0)
- end
-end
-
-local cache = { }
-
-function lpeg.keeper(str)
- if type(str) == "string" then
- local s = cache[str]
- if not s then
- s = Cs((((1-S(str))^1)/"" + 1)^0)
- cache[str] = s
- end
- return s
- else
- return Cs((((1-str)^1)/"" + 1)^0)
- end
-end
-
-function lpeg.frontstripper(str) -- or pattern (yet undocumented)
- return (P(str) + P(true)) * Cs(P(1)^0)
-end
-
-function lpeg.endstripper(str) -- or pattern (yet undocumented)
- return Cs((1 - P(str) * P(-1))^0)
-end
-
--- Just for fun I looked at the used bytecode and
--- p = (p and p + pp) or pp gets one more (testset).
-
-function lpeg.replacer(one,two)
- if type(one) == "table" then
- local no = #one
- if no > 0 then
- local p
- for i=1,no do
- local o = one[i]
- local pp = P(o[1]) / o[2]
- if p then
- p = p + pp
- else
- p = pp
- end
- end
- return Cs((p + 1)^0)
- end
- else
- two = two or ""
- return Cs((P(one)/two + 1)^0)
- end
-end
-
-local splitters_f, splitters_s = { }, { }
-
-function lpeg.firstofsplit(separator) -- always return value
- local splitter = splitters_f[separator]
- if not splitter then
- separator = P(separator)
- splitter = C((1 - separator)^0)
- splitters_f[separator] = splitter
- end
- return splitter
-end
-
-function lpeg.secondofsplit(separator) -- nil if not split
- local splitter = splitters_s[separator]
- if not splitter then
- separator = P(separator)
- splitter = (1 - separator)^0 * separator * C(anything^0)
- splitters_s[separator] = splitter
- end
- return splitter
-end
-
-function lpeg.balancer(left,right)
- left, right = P(left), P(right)
- return P { left * ((1 - left - right) + V(1))^0 * right }
-end
-
---~ print(1,match(lpeg.firstofsplit(":"),"bc:de"))
---~ print(2,match(lpeg.firstofsplit(":"),":de")) -- empty
---~ print(3,match(lpeg.firstofsplit(":"),"bc"))
---~ print(4,match(lpeg.secondofsplit(":"),"bc:de"))
---~ print(5,match(lpeg.secondofsplit(":"),"bc:")) -- empty
---~ print(6,match(lpeg.secondofsplit(":",""),"bc"))
---~ print(7,match(lpeg.secondofsplit(":"),"bc"))
---~ print(9,match(lpeg.secondofsplit(":","123"),"bc"))
-
---~ -- slower:
---~
---~ function lpeg.counter(pattern)
---~ local n, pattern = 0, (lpeg.P(pattern)/function() n = n + 1 end + lpeg.anything)^0
---~ return function(str) n = 0 ; lpegmatch(pattern,str) ; return n end
---~ end
-
-local nany = utf8char/""
-
-function lpeg.counter(pattern)
- pattern = Cs((P(pattern)/" " + nany)^0)
- return function(str)
- return #match(pattern,str)
- end
-end
-
-if utfgmatch then
-
- function lpeg.count(str,what) -- replaces string.count
- if type(what) == "string" then
- local n = 0
- for _ in utfgmatch(str,what) do
- n = n + 1
- end
- return n
- else -- 4 times slower but still faster than / function
- return #match(Cs((P(what)/" " + nany)^0),str)
- end
- end
-
-else
-
- local cache = { }
-
- function lpeg.count(str,what) -- replaces string.count
- if type(what) == "string" then
- local p = cache[what]
- if not p then
- p = Cs((P(what)/" " + nany)^0)
- cache[p] = p
- end
- return #match(p,str)
- else -- 4 times slower but still faster than / function
- return #match(Cs((P(what)/" " + nany)^0),str)
- end
- end
-
-end
-
-local patterns_escapes = { -- also defines in l-string
- ["%"] = "%%",
- ["."] = "%.",
- ["+"] = "%+", ["-"] = "%-", ["*"] = "%*",
- ["["] = "%[", ["]"] = "%]",
- ["("] = "%)", [")"] = "%)",
- -- ["{"] = "%{", ["}"] = "%}"
- -- ["^"] = "%^", ["$"] = "%$",
-}
-
-local simple_escapes = { -- also defines in l-string
- ["-"] = "%-",
- ["."] = "%.",
- ["?"] = ".",
- ["*"] = ".*",
-}
-
-local p = Cs((S("-.+*%()[]") / patterns_escapes + anything)^0)
-local s = Cs((S("-.+*%()[]") / simple_escapes + anything)^0)
-
-function string.escapedpattern(str,simple)
- return match(simple and s or p,str)
-end
-
--- utf extensies
-
-lpeg.UP = lpeg.P
-
-if utfcharacters then
-
- function lpeg.US(str)
- local p
- for uc in utfcharacters(str) do
- if p then
- p = p + P(uc)
- else
- p = P(uc)
- end
- end
- return p
- end
-
-
-elseif utfgmatch then
-
- function lpeg.US(str)
- local p
- for uc in utfgmatch(str,".") do
- if p then
- p = p + P(uc)
- else
- p = P(uc)
- end
- end
- return p
- end
-
-else
-
- function lpeg.US(str)
- local p
- local f = function(uc)
- if p then
- p = p + P(uc)
- else
- p = P(uc)
- end
- end
- match((utf8char/f)^0,str)
- return p
- end
-
-end
-
-local range = Cs(utf8byte) * (Cs(utf8byte) + Cc(false))
-
-local utfchar = unicode and unicode.utf8 and unicode.utf8.char
-
-function lpeg.UR(str,more)
- local first, last
- if type(str) == "number" then
- first = str
- last = more or first
- else
- first, last = match(range,str)
- if not last then
- return P(str)
- end
- end
- if first == last then
- return P(str)
- elseif utfchar and last - first < 8 then -- a somewhat arbitrary criterium
- local p
- for i=first,last do
- if p then
- p = p + P(utfchar(i))
- else
- p = P(utfchar(i))
- end
- end
- return p -- nil when invalid range
- else
- local f = function(b)
- return b >= first and b <= last
- end
- return utf8byte / f -- nil when invalid range
- end
-end
-
---~ lpeg.print(lpeg.R("ab","cd","gh"))
---~ lpeg.print(lpeg.P("a","b","c"))
---~ lpeg.print(lpeg.S("a","b","c"))
-
---~ print(lpeg.count("äáàa",lpeg.P("á") + lpeg.P("à")))
---~ print(lpeg.count("äáàa",lpeg.UP("áà")))
---~ print(lpeg.count("äáàa",lpeg.US("àá")))
---~ print(lpeg.count("äáàa",lpeg.UR("aá")))
---~ print(lpeg.count("äáàa",lpeg.UR("àá")))
---~ print(lpeg.count("äáàa",lpeg.UR(0x0000,0xFFFF)))
-
-function lpeg.oneof(list,...) -- lpeg.oneof("elseif","else","if","then")
- if type(list) ~= "table" then
- list = { list, ... }
- end
- -- sort(list) -- longest match first
- local p = P(list[1])
- for l=2,#list do
- p = p + P(list[l])
- end
- return p
-end
-
-function lpeg.is_lpeg(p)
- return p and lpegtype(p) == "pattern"
-end
-
---~ Cf(Ct("") * (Cg(C(...) * "=" * Cs(...)))^0, rawset)
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules = { } end modules ['l-boolean'] = {
- version = 1.001,
- comment = "companion to luat-lib.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-local type, tonumber = type, tonumber
-
-boolean = boolean or { }
-local boolean = boolean
-
--- function boolean.tonumber(b)
--- return b and 1 or 0 -- test and test and return or return
--- end
-
-function boolean.tonumber(b)
- if b then return 1 else return 0 end -- test and return or return
-end
-
-function toboolean(str,tolerant)
- if tolerant then
- local tstr = type(str)
- if tstr == "string" then
- return str == "true" or str == "yes" or str == "on" or str == "1" or str == "t"
- elseif tstr == "number" then
- return tonumber(str) ~= 0
- elseif tstr == "nil" then
- return false
- else
- return str
- end
- elseif str == "true" then
- return true
- elseif str == "false" then
- return false
- else
- return str
- end
-end
-
-string.toboolean = toboolean
-
-function string.is_boolean(str,default)
- if type(str) == "string" then
- if str == "true" or str == "yes" or str == "on" or str == "t" then
- return true
- elseif str == "false" or str == "no" or str == "off" or str == "f" then
- return false
- end
- end
- return default
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules = { } end modules ['l-math'] = {
- version = 1.001,
- comment = "companion to luat-lib.mkiv",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-local floor, sin, cos, tan = math.floor, math.sin, math.cos, math.tan
-
-if not math.round then
- function math.round(x) return floor(x + 0.5) end
-end
-
-if not math.div then
- function math.div(n,m) return floor(n/m) end
-end
-
-if not math.mod then
- function math.mod(n,m) return n % m end
-end
-
-local pipi = 2*math.pi/360
-
-if not math.sind then
- function math.sind(d) return sin(d*pipi) end
- function math.cosd(d) return cos(d*pipi) end
- function math.tand(d) return tan(d*pipi) end
-end
-
-if not math.odd then
- function math.odd (n) return n % 2 == 0 end
- function math.even(n) return n % 2 ~= 0 end
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
if not modules then modules = { } end modules ['l-table'] = {
version = 1.001,
comment = "companion to luat-lib.mkiv",
@@ -783,11 +139,12 @@ local type, next, tostring, tonumber, ipairs, table, string = type, next, tostri
local concat, sort, insert, remove = table.concat, table.sort, table.insert, table.remove
local format, find, gsub, lower, dump, match = string.format, string.find, string.gsub, string.lower, string.dump, string.match
local getmetatable, setmetatable = getmetatable, setmetatable
+local getinfo = debug.getinfo
-- Starting with version 5.2 Lua no longer provide ipairs, which makes
-- sense. As we already used the for loop and # in most places the
-- impact on ConTeXt was not that large; the remaining ipairs already
--- have been replaced. In a similar fashio we also hardly used pairs.
+-- have been replaced. In a similar fashion we also hardly used pairs.
--
-- Just in case, we provide the fallbacks as discussed in Programming
-- in Lua (http://www.lua.org/pil/7.3.html):
@@ -1130,6 +487,8 @@ end
-- problem: there no good number_to_string converter with the best resolution
+local function dummy() end
+
local function do_serialize(root,name,depth,level,indexed)
if level > 0 then
depth = depth .. " "
@@ -1324,18 +683,20 @@ local function do_serialize(root,name,depth,level,indexed)
end
elseif t == "function" then
if functions then
+ local f = getinfo(v).what == "C" and dump(dummy) or dump(v)
+ -- local f = getinfo(v).what == "C" and dump(function(...) return v(...) end) or dump(v)
if tk == "number" then -- or find(k,"^%d+$") then
if hexify then
- handle(format("%s [0x%04X]=loadstring(%q),",depth,k,dump(v)))
+ handle(format("%s [0x%04X]=loadstring(%q),",depth,k,f))
else
- handle(format("%s [%s]=loadstring(%q),",depth,k,dump(v)))
+ handle(format("%s [%s]=loadstring(%q),",depth,k,f))
end
elseif tk == "boolean" then
- handle(format("%s [%s]=loadstring(%q),",depth,tostring(k),dump(v)))
+ handle(format("%s [%s]=loadstring(%q),",depth,tostring(k),f))
elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
- handle(format("%s %s=loadstring(%q),",depth,k,dump(v)))
+ handle(format("%s %s=loadstring(%q),",depth,k,f))
else
- handle(format("%s [%q]=loadstring(%q),",depth,k,dump(v)))
+ handle(format("%s [%q]=loadstring(%q),",depth,k,f))
end
end
else
@@ -1698,6 +1059,893 @@ function table.has_one_entry(t)
return t and not next(t,next(t))
end
+-- new
+
+function table.loweredkeys(t) -- maybe utf
+ local l = { }
+ for k, v in next, t do
+ l[lower(k)] = v
+ end
+ return l
+end
+
+-- new, might move (maybe duplicate)
+
+function table.unique(old)
+ local hash = { }
+ local new = { }
+ local n = 0
+ for i=1,#old do
+ local oi = old[i]
+ if not hash[oi] then
+ n = n + 1
+ new[n] = oi
+ hash[oi] = true
+ end
+ end
+ return new
+end
+
+-- function table.sorted(t,...)
+-- table.sort(t,...)
+-- return t -- still sorts in-place
+-- end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['l-lpeg'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+
+-- a new lpeg fails on a #(1-P(":")) test and really needs a + P(-1)
+
+local lpeg = require("lpeg")
+
+-- tracing (only used when we encounter a problem in integration of lpeg in luatex)
+
+local report = texio and texio.write_nl or print
+
+--~ local lpmatch = lpeg.match
+--~ local lpprint = lpeg.print
+--~ local lpp = lpeg.P
+--~ local lpr = lpeg.R
+--~ local lps = lpeg.S
+--~ local lpc = lpeg.C
+--~ local lpb = lpeg.B
+--~ local lpv = lpeg.V
+--~ local lpcf = lpeg.Cf
+--~ local lpcb = lpeg.Cb
+--~ local lpcg = lpeg.Cg
+--~ local lpct = lpeg.Ct
+--~ local lpcs = lpeg.Cs
+--~ local lpcc = lpeg.Cc
+--~ local lpcmt = lpeg.Cmt
+--~ local lpcarg = lpeg.Carg
+
+--~ function lpeg.match(l,...) report("LPEG MATCH") lpprint(l) return lpmatch(l,...) end
+
+--~ function lpeg.P (l) local p = lpp (l) report("LPEG P =") lpprint(l) return p end
+--~ function lpeg.R (l) local p = lpr (l) report("LPEG R =") lpprint(l) return p end
+--~ function lpeg.S (l) local p = lps (l) report("LPEG S =") lpprint(l) return p end
+--~ function lpeg.C (l) local p = lpc (l) report("LPEG C =") lpprint(l) return p end
+--~ function lpeg.B (l) local p = lpb (l) report("LPEG B =") lpprint(l) return p end
+--~ function lpeg.V (l) local p = lpv (l) report("LPEG V =") lpprint(l) return p end
+--~ function lpeg.Cf (l) local p = lpcf (l) report("LPEG Cf =") lpprint(l) return p end
+--~ function lpeg.Cb (l) local p = lpcb (l) report("LPEG Cb =") lpprint(l) return p end
+--~ function lpeg.Cg (l) local p = lpcg (l) report("LPEG Cg =") lpprint(l) return p end
+--~ function lpeg.Ct (l) local p = lpct (l) report("LPEG Ct =") lpprint(l) return p end
+--~ function lpeg.Cs (l) local p = lpcs (l) report("LPEG Cs =") lpprint(l) return p end
+--~ function lpeg.Cc (l) local p = lpcc (l) report("LPEG Cc =") lpprint(l) return p end
+--~ function lpeg.Cmt (l) local p = lpcmt (l) report("LPEG Cmt =") lpprint(l) return p end
+--~ function lpeg.Carg (l) local p = lpcarg(l) report("LPEG Carg =") lpprint(l) return p end
+
+local type = type
+local byte, char, gmatch = string.byte, string.char, string.gmatch
+
+-- Beware, we predefine a bunch of patterns here and one reason for doing so
+-- is that we get consistent behaviour in some of the visualizers.
+
+lpeg.patterns = lpeg.patterns or { } -- so that we can share
+local patterns = lpeg.patterns
+
+local P, R, S, V, match = lpeg.P, lpeg.R, lpeg.S, lpeg.V, lpeg.match
+local Ct, C, Cs, Cc = lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc
+local lpegtype = lpeg.type
+
+local utfcharacters = string.utfcharacters
+local utfgmatch = unicode and unicode.utf8.gmatch
+
+local anything = P(1)
+local endofstring = P(-1)
+local alwaysmatched = P(true)
+
+patterns.anything = anything
+patterns.endofstring = endofstring
+patterns.beginofstring = alwaysmatched
+patterns.alwaysmatched = alwaysmatched
+
+local digit, sign = R('09'), S('+-')
+local cr, lf, crlf = P("\r"), P("\n"), P("\r\n")
+local newline = crlf + S("\r\n") -- cr + lf
+local escaped = P("\\") * anything
+local squote = P("'")
+local dquote = P('"')
+local space = P(" ")
+
+local utfbom_32_be = P('\000\000\254\255')
+local utfbom_32_le = P('\255\254\000\000')
+local utfbom_16_be = P('\255\254')
+local utfbom_16_le = P('\254\255')
+local utfbom_8 = P('\239\187\191')
+local utfbom = utfbom_32_be + utfbom_32_le
+ + utfbom_16_be + utfbom_16_le
+ + utfbom_8
+local utftype = utfbom_32_be / "utf-32-be" + utfbom_32_le / "utf-32-le"
+ + utfbom_16_be / "utf-16-be" + utfbom_16_le / "utf-16-le"
+ + utfbom_8 / "utf-8" + alwaysmatched / "unknown"
+
+local utf8next = R("\128\191")
+
+patterns.utf8one = R("\000\127")
+patterns.utf8two = R("\194\223") * utf8next
+patterns.utf8three = R("\224\239") * utf8next * utf8next
+patterns.utf8four = R("\240\244") * utf8next * utf8next * utf8next
+patterns.utfbom = utfbom
+patterns.utftype = utftype
+
+local utf8char = patterns.utf8one + patterns.utf8two + patterns.utf8three + patterns.utf8four
+local validutf8char = utf8char^0 * endofstring * Cc(true) + Cc(false)
+
+patterns.utf8 = utf8char
+patterns.utf8char = utf8char
+patterns.validutf8 = validutf8char
+patterns.validutf8char = validutf8char
+
+patterns.digit = digit
+patterns.sign = sign
+patterns.cardinal = sign^0 * digit^1
+patterns.integer = sign^0 * digit^1
+patterns.float = sign^0 * digit^0 * P('.') * digit^1
+patterns.cfloat = sign^0 * digit^0 * P(',') * digit^1
+patterns.number = patterns.float + patterns.integer
+patterns.cnumber = patterns.cfloat + patterns.integer
+patterns.oct = P("0") * R("07")^1
+patterns.octal = patterns.oct
+patterns.HEX = P("0x") * R("09","AF")^1
+patterns.hex = P("0x") * R("09","af")^1
+patterns.hexadecimal = P("0x") * R("09","AF","af")^1
+patterns.lowercase = R("az")
+patterns.uppercase = R("AZ")
+patterns.letter = patterns.lowercase + patterns.uppercase
+patterns.space = space
+patterns.tab = P("\t")
+patterns.spaceortab = patterns.space + patterns.tab
+patterns.eol = S("\n\r")
+patterns.spacer = S(" \t\f\v") -- + char(0xc2, 0xa0) if we want utf (cf mail roberto)
+patterns.newline = newline
+patterns.emptyline = newline^1
+patterns.nonspacer = 1 - patterns.spacer
+patterns.whitespace = patterns.eol + patterns.spacer
+patterns.nonwhitespace = 1 - patterns.whitespace
+patterns.equal = P("=")
+patterns.comma = P(",")
+patterns.commaspacer = P(",") * patterns.spacer^0
+patterns.period = P(".")
+patterns.colon = P(":")
+patterns.semicolon = P(";")
+patterns.underscore = P("_")
+patterns.escaped = escaped
+patterns.squote = squote
+patterns.dquote = dquote
+patterns.nosquote = (escaped + (1-squote))^0
+patterns.nodquote = (escaped + (1-dquote))^0
+patterns.unsingle = (squote/"") * patterns.nosquote * (squote/"")
+patterns.undouble = (dquote/"") * patterns.nodquote * (dquote/"")
+patterns.unquoted = patterns.undouble + patterns.unsingle -- more often undouble
+patterns.unspacer = ((patterns.spacer^1)/"")^0
+
+patterns.somecontent = (anything - newline - space)^1 -- (utf8char - newline - space)^1
+patterns.beginline = #(1-newline)
+
+-- print(string.unquoted("test"))
+-- print(string.unquoted([["t\"est"]]))
+-- print(string.unquoted([["t\"est"x]]))
+-- print(string.unquoted("\'test\'"))
+-- print(string.unquoted('"test"'))
+-- print(string.unquoted('"test"'))
+
+function lpeg.anywhere(pattern) --slightly adapted from website
+ return P { P(pattern) + 1 * V(1) } -- why so complex?
+end
+
+function lpeg.splitter(pattern, action)
+ return (((1-P(pattern))^1)/action+1)^0
+end
+
+function lpeg.tsplitter(pattern, action)
+ return Ct((((1-P(pattern))^1)/action+1)^0)
+end
+
+-- probleem: separator can be lpeg and that does not hash too well, but
+-- it's quite okay as the key is then not garbage collected
+
+local splitters_s, splitters_m, splitters_t = { }, { }, { }
+
+local function splitat(separator,single)
+ local splitter = (single and splitters_s[separator]) or splitters_m[separator]
+ if not splitter then
+ separator = P(separator)
+ local other = C((1 - separator)^0)
+ if single then
+ local any = anything
+ splitter = other * (separator * C(any^0) + "") -- ?
+ splitters_s[separator] = splitter
+ else
+ splitter = other * (separator * other)^0
+ splitters_m[separator] = splitter
+ end
+ end
+ return splitter
+end
+
+local function tsplitat(separator)
+ local splitter = splitters_t[separator]
+ if not splitter then
+ splitter = Ct(splitat(separator))
+ splitters_t[separator] = splitter
+ end
+ return splitter
+end
+
+lpeg.splitat = splitat
+lpeg.tsplitat = tsplitat
+
+function string.splitup(str,separator)
+ if not separator then
+ separator = ","
+ end
+ return match(splitters_m[separator] or splitat(separator),str)
+end
+
+--~ local p = splitat("->",false) print(match(p,"oeps->what->more")) -- oeps what more
+--~ local p = splitat("->",true) print(match(p,"oeps->what->more")) -- oeps what->more
+--~ local p = splitat("->",false) print(match(p,"oeps")) -- oeps
+--~ local p = splitat("->",true) print(match(p,"oeps")) -- oeps
+
+local cache = { }
+
+function lpeg.split(separator,str)
+ local c = cache[separator]
+ if not c then
+ c = tsplitat(separator)
+ cache[separator] = c
+ end
+ return match(c,str)
+end
+
+function string.split(str,separator)
+ local c = cache[separator]
+ if not c then
+ c = tsplitat(separator)
+ cache[separator] = c
+ end
+ return match(c,str)
+end
+
+local spacing = patterns.spacer^0 * newline -- sort of strip
+local empty = spacing * Cc("")
+local nonempty = Cs((1-spacing)^1) * spacing^-1
+local content = (empty + nonempty)^1
+
+patterns.textline = content
+
+--~ local linesplitter = Ct(content^0)
+--~
+--~ function string.splitlines(str)
+--~ return match(linesplitter,str)
+--~ end
+
+local linesplitter = tsplitat(newline)
+
+patterns.linesplitter = linesplitter
+
+function string.splitlines(str)
+ return match(linesplitter,str)
+end
+
+local utflinesplitter = utfbom^-1 * tsplitat(newline)
+
+patterns.utflinesplitter = utflinesplitter
+
+function string.utfsplitlines(str)
+ return match(utflinesplitter,str or "")
+end
+
+--~ lpeg.splitters = cache -- no longer public
+
+local cache = { }
+
+function lpeg.checkedsplit(separator,str)
+ local c = cache[separator]
+ if not c then
+ separator = P(separator)
+ local other = C((1 - separator)^1)
+ c = Ct(separator^0 * other * (separator^1 * other)^0)
+ cache[separator] = c
+ end
+ return match(c,str)
+end
+
+function string.checkedsplit(str,separator)
+ local c = cache[separator]
+ if not c then
+ separator = P(separator)
+ local other = C((1 - separator)^1)
+ c = Ct(separator^0 * other * (separator^1 * other)^0)
+ cache[separator] = c
+ end
+ return match(c,str)
+end
+
+--~ from roberto's site:
+
+local function f2(s) local c1, c2 = byte(s,1,2) return c1 * 64 + c2 - 12416 end
+local function f3(s) local c1, c2, c3 = byte(s,1,3) return (c1 * 64 + c2) * 64 + c3 - 925824 end
+local function f4(s) local c1, c2, c3, c4 = byte(s,1,4) return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168 end
+
+local utf8byte = patterns.utf8one/byte + patterns.utf8two/f2 + patterns.utf8three/f3 + patterns.utf8four/f4
+
+patterns.utf8byte = utf8byte
+
+--~ local str = " a b c d "
+
+--~ local s = lpeg.stripper(lpeg.R("az")) print("["..lpeg.match(s,str).."]")
+--~ local s = lpeg.keeper(lpeg.R("az")) print("["..lpeg.match(s,str).."]")
+--~ local s = lpeg.stripper("ab") print("["..lpeg.match(s,str).."]")
+--~ local s = lpeg.keeper("ab") print("["..lpeg.match(s,str).."]")
+
+local cache = { }
+
+function lpeg.stripper(str)
+ if type(str) == "string" then
+ local s = cache[str]
+ if not s then
+ s = Cs(((S(str)^1)/"" + 1)^0)
+ cache[str] = s
+ end
+ return s
+ else
+ return Cs(((str^1)/"" + 1)^0)
+ end
+end
+
+local cache = { }
+
+function lpeg.keeper(str)
+ if type(str) == "string" then
+ local s = cache[str]
+ if not s then
+ s = Cs((((1-S(str))^1)/"" + 1)^0)
+ cache[str] = s
+ end
+ return s
+ else
+ return Cs((((1-str)^1)/"" + 1)^0)
+ end
+end
+
+function lpeg.frontstripper(str) -- or pattern (yet undocumented)
+ return (P(str) + P(true)) * Cs(P(1)^0)
+end
+
+function lpeg.endstripper(str) -- or pattern (yet undocumented)
+ return Cs((1 - P(str) * P(-1))^0)
+end
+
+-- Just for fun I looked at the used bytecode and
+-- p = (p and p + pp) or pp gets one more (testset).
+
+function lpeg.replacer(one,two)
+ if type(one) == "table" then
+ local no = #one
+ if no > 0 then
+ local p
+ for i=1,no do
+ local o = one[i]
+ local pp = P(o[1]) / o[2]
+ if p then
+ p = p + pp
+ else
+ p = pp
+ end
+ end
+ return Cs((p + 1)^0)
+ end
+ else
+ two = two or ""
+ return Cs((P(one)/two + 1)^0)
+ end
+end
+
+local splitters_f, splitters_s = { }, { }
+
+function lpeg.firstofsplit(separator) -- always return value
+ local splitter = splitters_f[separator]
+ if not splitter then
+ separator = P(separator)
+ splitter = C((1 - separator)^0)
+ splitters_f[separator] = splitter
+ end
+ return splitter
+end
+
+function lpeg.secondofsplit(separator) -- nil if not split
+ local splitter = splitters_s[separator]
+ if not splitter then
+ separator = P(separator)
+ splitter = (1 - separator)^0 * separator * C(anything^0)
+ splitters_s[separator] = splitter
+ end
+ return splitter
+end
+
+function lpeg.balancer(left,right)
+ left, right = P(left), P(right)
+ return P { left * ((1 - left - right) + V(1))^0 * right }
+end
+
+--~ print(1,match(lpeg.firstofsplit(":"),"bc:de"))
+--~ print(2,match(lpeg.firstofsplit(":"),":de")) -- empty
+--~ print(3,match(lpeg.firstofsplit(":"),"bc"))
+--~ print(4,match(lpeg.secondofsplit(":"),"bc:de"))
+--~ print(5,match(lpeg.secondofsplit(":"),"bc:")) -- empty
+--~ print(6,match(lpeg.secondofsplit(":",""),"bc"))
+--~ print(7,match(lpeg.secondofsplit(":"),"bc"))
+--~ print(9,match(lpeg.secondofsplit(":","123"),"bc"))
+
+--~ -- slower:
+--~
+--~ function lpeg.counter(pattern)
+--~ local n, pattern = 0, (lpeg.P(pattern)/function() n = n + 1 end + lpeg.anything)^0
+--~ return function(str) n = 0 ; lpegmatch(pattern,str) ; return n end
+--~ end
+
+local nany = utf8char/""
+
+function lpeg.counter(pattern)
+ pattern = Cs((P(pattern)/" " + nany)^0)
+ return function(str)
+ return #match(pattern,str)
+ end
+end
+
+if utfgmatch then
+
+ function lpeg.count(str,what) -- replaces string.count
+ if type(what) == "string" then
+ local n = 0
+ for _ in utfgmatch(str,what) do
+ n = n + 1
+ end
+ return n
+ else -- 4 times slower but still faster than / function
+ return #match(Cs((P(what)/" " + nany)^0),str)
+ end
+ end
+
+else
+
+ local cache = { }
+
+ function lpeg.count(str,what) -- replaces string.count
+ if type(what) == "string" then
+ local p = cache[what]
+ if not p then
+ p = Cs((P(what)/" " + nany)^0)
+ cache[p] = p
+ end
+ return #match(p,str)
+ else -- 4 times slower but still faster than / function
+ return #match(Cs((P(what)/" " + nany)^0),str)
+ end
+ end
+
+end
+
+local patterns_escapes = { -- also defines in l-string
+ ["%"] = "%%",
+ ["."] = "%.",
+ ["+"] = "%+", ["-"] = "%-", ["*"] = "%*",
+ ["["] = "%[", ["]"] = "%]",
+ ["("] = "%)", [")"] = "%)",
+ -- ["{"] = "%{", ["}"] = "%}"
+ -- ["^"] = "%^", ["$"] = "%$",
+}
+
+local simple_escapes = { -- also defines in l-string
+ ["-"] = "%-",
+ ["."] = "%.",
+ ["?"] = ".",
+ ["*"] = ".*",
+}
+
+local p = Cs((S("-.+*%()[]") / patterns_escapes + anything)^0)
+local s = Cs((S("-.+*%()[]") / simple_escapes + anything)^0)
+
+function string.escapedpattern(str,simple)
+ return match(simple and s or p,str)
+end
+
+-- utf extensies
+
+lpeg.UP = lpeg.P
+
+if utfcharacters then
+
+ function lpeg.US(str)
+ local p
+ for uc in utfcharacters(str) do
+ if p then
+ p = p + P(uc)
+ else
+ p = P(uc)
+ end
+ end
+ return p
+ end
+
+
+elseif utfgmatch then
+
+ function lpeg.US(str)
+ local p
+ for uc in utfgmatch(str,".") do
+ if p then
+ p = p + P(uc)
+ else
+ p = P(uc)
+ end
+ end
+ return p
+ end
+
+else
+
+ function lpeg.US(str)
+ local p
+ local f = function(uc)
+ if p then
+ p = p + P(uc)
+ else
+ p = P(uc)
+ end
+ end
+ match((utf8char/f)^0,str)
+ return p
+ end
+
+end
+
+local range = Cs(utf8byte) * (Cs(utf8byte) + Cc(false))
+
+local utfchar = unicode and unicode.utf8 and unicode.utf8.char
+
+function lpeg.UR(str,more)
+ local first, last
+ if type(str) == "number" then
+ first = str
+ last = more or first
+ else
+ first, last = match(range,str)
+ if not last then
+ return P(str)
+ end
+ end
+ if first == last then
+ return P(str)
+ elseif utfchar and last - first < 8 then -- a somewhat arbitrary criterium
+ local p
+ for i=first,last do
+ if p then
+ p = p + P(utfchar(i))
+ else
+ p = P(utfchar(i))
+ end
+ end
+ return p -- nil when invalid range
+ else
+ local f = function(b)
+ return b >= first and b <= last
+ end
+ return utf8byte / f -- nil when invalid range
+ end
+end
+
+--~ lpeg.print(lpeg.R("ab","cd","gh"))
+--~ lpeg.print(lpeg.P("a","b","c"))
+--~ lpeg.print(lpeg.S("a","b","c"))
+
+--~ print(lpeg.count("äáàa",lpeg.P("á") + lpeg.P("à")))
+--~ print(lpeg.count("äáàa",lpeg.UP("áà")))
+--~ print(lpeg.count("äáàa",lpeg.US("àá")))
+--~ print(lpeg.count("äáàa",lpeg.UR("aá")))
+--~ print(lpeg.count("äáàa",lpeg.UR("àá")))
+--~ print(lpeg.count("äáàa",lpeg.UR(0x0000,0xFFFF)))
+
+function lpeg.oneof(list,...) -- lpeg.oneof("elseif","else","if","then")
+ if type(list) ~= "table" then
+ list = { list, ... }
+ end
+ -- sort(list) -- longest match first
+ local p = P(list[1])
+ for l=2,#list do
+ p = p + P(list[l])
+ end
+ return p
+end
+
+function lpeg.is_lpeg(p)
+ return p and lpegtype(p) == "pattern"
+end
+
+-- For the moment here, but it might move to utilities. Beware, we need to
+-- have the longest keyword first, so 'aaa' comes beforte 'aa' which is why we
+-- loop back from the end cq. prepend.
+
+local sort, fastcopy, sortedkeys = table.sort, table.fastcopy, table.sortedkeys -- dependency!
+
+function lpeg.append(list,pp,delayed,checked)
+ local p = pp
+ if #list > 0 then
+ local keys = fastcopy(list)
+ sort(keys)
+ for i=#keys,1,-1 do
+ local k = keys[i]
+ if p then
+ p = P(k) + p
+ else
+ p = P(k)
+ end
+ end
+ elseif delayed then -- hm, it looks like the lpeg parser resolves anyway
+ local keys = sortedkeys(list)
+ if p then
+ for i=1,#keys,1 do
+ local k = keys[i]
+ local v = list[k]
+ p = P(k)/list + p
+ end
+ else
+ for i=1,#keys do
+ local k = keys[i]
+ local v = list[k]
+ if p then
+ p = P(k) + p
+ else
+ p = P(k)
+ end
+ end
+ if p then
+ p = p / list
+ end
+ end
+ elseif checked then
+ -- problem: substitution gives a capture
+ local keys = sortedkeys(list)
+ for i=1,#keys do
+ local k = keys[i]
+ local v = list[k]
+ if p then
+ if k == v then
+ p = P(k) + p
+ else
+ p = P(k)/v + p
+ end
+ else
+ if k == v then
+ p = P(k)
+ else
+ p = P(k)/v
+ end
+ end
+ end
+ else
+ local keys = sortedkeys(list)
+ for i=1,#keys do
+ local k = keys[i]
+ local v = list[k]
+ if p then
+ p = P(k)/v + p
+ else
+ p = P(k)/v
+ end
+ end
+ end
+ return p
+end
+
+-- inspect(lpeg.append({ a = "1", aa = "1", aaa = "1" } ,nil,true))
+-- inspect(lpeg.append({ ["degree celsius"] = "1", celsius = "1", degree = "1" } ,nil,true))
+
+-- function lpeg.exact_match(words,case_insensitive)
+-- local pattern = concat(words)
+-- if case_insensitive then
+-- local pattern = S(upper(characters)) + S(lower(characters))
+-- local list = { }
+-- for i=1,#words do
+-- list[lower(words[i])] = true
+-- end
+-- return Cmt(pattern^1, function(_,i,s)
+-- return list[lower(s)] and i
+-- end)
+-- else
+-- local pattern = S(concat(words))
+-- local list = { }
+-- for i=1,#words do
+-- list[words[i]] = true
+-- end
+-- return Cmt(pattern^1, function(_,i,s)
+-- return list[s] and i
+-- end)
+-- end
+-- end
+
+-- experiment:
+
+local function make(t)
+ local p
+-- for k, v in next, t do
+ for k, v in table.sortedhash(t) do
+ if not p then
+ if next(v) then
+ p = P(k) * make(v)
+ else
+ p = P(k)
+ end
+ else
+ if next(v) then
+ p = p + P(k) * make(v)
+ else
+ p = p + P(k)
+ end
+ end
+ end
+ return p
+end
+
+function lpeg.utfchartabletopattern(list)
+ local tree = { }
+ for i=1,#list do
+ local t = tree
+ for c in gmatch(list[i],".") do
+ if not t[c] then
+ t[c] = { }
+ end
+ t = t[c]
+ end
+ end
+ return make(tree)
+end
+
+-- inspect ( lpeg.utfchartabletopattern {
+-- utfchar(0x00A0), -- nbsp
+-- utfchar(0x2000), -- enquad
+-- utfchar(0x2001), -- emquad
+-- utfchar(0x2002), -- enspace
+-- utfchar(0x2003), -- emspace
+-- utfchar(0x2004), -- threeperemspace
+-- utfchar(0x2005), -- fourperemspace
+-- utfchar(0x2006), -- sixperemspace
+-- utfchar(0x2007), -- figurespace
+-- utfchar(0x2008), -- punctuationspace
+-- utfchar(0x2009), -- breakablethinspace
+-- utfchar(0x200A), -- hairspace
+-- utfchar(0x200B), -- zerowidthspace
+-- utfchar(0x202F), -- narrownobreakspace
+-- utfchar(0x205F), -- math thinspace
+-- } )
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['l-boolean'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local type, tonumber = type, tonumber
+
+boolean = boolean or { }
+local boolean = boolean
+
+function boolean.tonumber(b)
+ if b then return 1 else return 0 end -- test and return or return
+end
+
+function toboolean(str,tolerant)
+ if tolerant then
+ local tstr = type(str)
+ if tstr == "string" then
+ return str == "true" or str == "yes" or str == "on" or str == "1" or str == "t"
+ elseif tstr == "number" then
+ return tonumber(str) ~= 0
+ elseif tstr == "nil" then
+ return false
+ else
+ return str
+ end
+ elseif str == "true" then
+ return true
+ elseif str == "false" then
+ return false
+ else
+ return str
+ end
+end
+
+string.toboolean = toboolean
+
+function string.is_boolean(str,default)
+ if type(str) == "string" then
+ if str == "true" or str == "yes" or str == "on" or str == "t" then
+ return true
+ elseif str == "false" or str == "no" or str == "off" or str == "f" then
+ return false
+ end
+ end
+ return default
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['l-math'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local floor, sin, cos, tan = math.floor, math.sin, math.cos, math.tan
+
+if not math.round then
+ function math.round(x) return floor(x + 0.5) end
+end
+
+if not math.div then
+ function math.div(n,m) return floor(n/m) end
+end
+
+if not math.mod then
+ function math.mod(n,m) return n % m end
+end
+
+local pipi = 2*math.pi/360
+
+if not math.sind then
+ function math.sind(d) return sin(d*pipi) end
+ function math.cosd(d) return cos(d*pipi) end
+ function math.tand(d) return tan(d*pipi) end
+end
+
+if not math.odd then
+ function math.odd (n) return n % 2 ~= 0 end
+ function math.even(n) return n % 2 == 0 end
+end
+
end -- closure
do -- begin closure to overcome local limits and interference
@@ -1817,10 +2065,10 @@ end
local trick_1 = char(1)
local trick_2 = "^" .. trick_1 .. "/+"
-function file.join(...)
+function file.join(...) -- rather dirty
local lst = { ... }
local a, b = lst[1], lst[2]
- if a == "" then
+ if not a or a == "" then -- not a added
lst[1] = trick_1
elseif b and find(a,"^/+$") and find(b,"^/") then
lst[1] = ""
@@ -1850,9 +2098,39 @@ end
--~ print(file.join("http:///a","/y"))
--~ print(file.join("//nas-1","/y"))
+-- We should be able to use:
+--
+-- function file.is_writable(name)
+-- local a = attributes(name) or attributes(dirname(name,"."))
+-- return a and sub(a.permissions,2,2) == "w"
+-- end
+--
+-- But after some testing Taco and I came up with:
+
function file.is_writable(name)
- local a = attributes(name) or attributes(dirname(name,"."))
- return a and sub(a.permissions,2,2) == "w"
+ if lfs.isdir(name) then
+ name = name .. "/m_t_x_t_e_s_t.tmp"
+ local f = io.open(name,"wb")
+ if f then
+ f:close()
+ os.remove(name)
+ return true
+ end
+ elseif lfs.isfile(name) then
+ local f = io.open(name,"ab")
+ if f then
+ f:close()
+ return true
+ end
+ else
+ local f = io.open(name,"ab")
+ if f then
+ f:close()
+ os.remove(name)
+ return true
+ end
+ end
+ return false
end
function file.is_readable(name)
@@ -1900,7 +2178,7 @@ end
--~ variant. After some skyping we got it sort of compatible with the old
--~ one. After that the anchoring to currentdir was added in a better way.
--~ Of course there are some optimizations too. Finally we had to deal with
---~ windows drive prefixes and thinsg like sys://.
+--~ windows drive prefixes and things like sys://.
function file.collapsepath(str,anchor)
if anchor and not find(str,"^/") and not find(str,"^%a:") then
@@ -1928,7 +2206,7 @@ function file.collapsepath(str,anchor)
if element == '.' then
-- do nothing
elseif element == '..' then
- local n = i -1
+ local n = i - 1
while n > 0 do
local element = oldelements[n]
if element ~= '..' and element ~= '.' then
@@ -2102,10 +2380,42 @@ local path = C(((1-slash)^0 * slash)^0)
local suffix = period * C(P(1-period)^0 * P(-1))
local base = C((1-suffix)^0)
-local pattern = (drive + Cc("")) * (path + Cc("")) * (base + Cc("")) * (suffix + Cc(""))
+drive = drive + Cc("")
+path = path + Cc("")
+base = base + Cc("")
+suffix = suffix + Cc("")
+
+local pattern_a = drive * path * base * suffix
+local pattern_b = path * base * suffix
+local pattern_c = C(drive * path) * C(base * suffix)
+
+function file.splitname(str,splitdrive)
+ if splitdrive then
+ return lpegmatch(pattern_a,str) -- returns drive, path, base, suffix
+ else
+ return lpegmatch(pattern_b,str) -- returns path, base, suffix
+ end
+end
-function file.splitname(str) -- returns drive, path, base, suffix
- return lpegmatch(pattern,str)
+function file.nametotable(str,splitdrive) -- returns table
+ local path, drive, subpath, name, base, suffix = lpegmatch(pattern_c,str)
+ if splitdrive then
+ return {
+ path = path,
+ drive = drive,
+ subpath = subpath,
+ name = name,
+ base = base,
+ suffix = suffix,
+ }
+ else
+ return {
+ path = path,
+ name = name,
+ base = base,
+ suffix = suffix,
+ }
+ end
end
-- function test(t) for k, v in next, t do print(v, "=>", file.splitname(v)) end end
@@ -2390,6 +2700,11 @@ function io.readstring(f,n,m)
return str
end
+--
+
+if not io.i_limiter then function io.i_limiter() end end -- dummy so we can test safely
+if not io.o_limiter then function io.o_limiter() end end -- dummy so we can test safely
+
end -- closure
do -- begin closure to overcome local limits and interference
@@ -2476,6 +2791,8 @@ local remapper = {
dfont = "truetype fonts", -- "truetype dictionary",
cid = "cid maps",
fea = "font feature files",
+ pfa = "type1 fonts", -- this is for Khaled, in ConTeXt we don't use this!
+ pfb = "type1 fonts", -- this is for Khaled, in ConTeXt we don't use this!
}
function resolvers.findfile(name,fileformat)
@@ -2587,7 +2904,7 @@ end
local function makefullname(path,name)
if path and path ~= "" then
name = "temp-" .. name -- clash prevention
- return file.addsuffix(file.join(path,name),"lua")
+ return file.addsuffix(file.join(path,name),"lua"), file.addsuffix(file.join(path,name),"luc")
end
end
@@ -2598,26 +2915,67 @@ end
function caches.loaddata(paths,name)
for i=1,#paths do
- local fullname = makefullname(paths[i],name)
- if fullname then
- texio.write(string.format("(load: %s)",fullname))
- local data = loadfile(fullname)
- return data and data()
+ local data = false
+ local luaname, lucname = makefullname(paths[i],name)
+ if lucname and lfs.isfile(lucname) then
+ texio.write(string.format("(load: %s)",lucname))
+ data = loadfile(lucname)
end
+ if not data and luaname and lfs.isfile(luaname) then
+ texio.write(string.format("(load: %s)",luaname))
+ data = loadfile(luaname)
+ end
+ return data and data()
end
end
function caches.savedata(path,name,data)
- local fullname = makefullname(path,name)
- if fullname then
- texio.write(string.format("(save: %s)",fullname))
- table.tofile(fullname,data,true,{ reduce = true })
+ local luaname, lucname = makefullname(path,name)
+ if luaname then
+ texio.write(string.format("(save: %s)",luaname))
+ table.tofile(luaname,data,true,{ reduce = true })
+ if lucname and type(caches.compile) == "function" then
+ os.remove(lucname) -- better be safe
+ texio.write(string.format("(save: %s)",lucname))
+ caches.compile(data,luaname,lucname)
+ end
end
end
+-- According to KH os.execute is not permitted in plain/latex so there is
+-- no reason to use the normal context way. So the method here is slightly
+-- different from the one we have in context. We also use different suffixes
+-- as we don't want any clashes (sharing cache files is not that handy as
+-- context moves on faster.)
--
+-- Beware: serialization might fail on large files (so maybe we should pcall
+-- this) in which case one should limit the method to luac and enable support
+-- for execution.
+
+caches.compilemethod = "luac" -- luac dump both
-local table.setmetatableindex(t,f)
+function caches.compile(data,luaname,lucname)
+ local done = false
+ if caches.compilemethod == "luac" or caches.compilemethod == "both" then
+ local command = "-o " .. string.quoted(lucname) .. " -s " .. string.quoted(luaname)
+ done = os.spawn("texluac " .. command) == 0
+ end
+ if not done and (caches.compilemethod == "dump" or caches.compilemethod == "both") then
+ local d = table.serialize(data,true)
+ if d and d ~= "" then
+ local f = io.open(lucname,'w')
+ if f then
+ local s = loadstring(d)
+ f:write(string.dump(s))
+ f:close()
+ end
+ end
+ end
+end
+
+--
+
+function table.setmetatableindex(t,f)
setmetatable(t,{ __index = f })
end
@@ -2917,12 +3275,15 @@ if not modules then modules = { } end modules ['font-con'] = {
}
+-- some names of table entries will be changed (no _)
+
local utf = unicode.utf8
local next, tostring, rawget = next, tostring, rawget
local format, match, lower, gsub = string.format, string.match, string.lower, string.gsub
local utfbyte = utf.byte
local sort, insert, concat, sortedkeys, serialize, fastcopy = table.sort, table.insert, table.concat, table.sortedkeys, table.serialize, table.fastcopy
+local derivetable = table.derive
local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
local trace_scaling = false trackers.register("fonts.scaling" , function(v) trace_scaling = v end)
@@ -2935,32 +3296,128 @@ local report_defining = logs.reporter("fonts","defining")
<p>Here we only implement a few helper functions.</p>
--ldx]]--
-local fonts = fonts
-local constructors = { }
-fonts.constructors = constructors
-local handlers = { }
-fonts.handlers = handlers
+local fonts = fonts
+local constructors = { }
+fonts.constructors = constructors
+local handlers = { }
+fonts.handlers = handlers
-local specifiers = fonts.specifiers
-local contextsetups = specifiers.contextsetups
-local contextnumbers = specifiers.contextnumbers
+local specifiers = fonts.specifiers
+local contextsetups = specifiers.contextsetups
+local contextnumbers = specifiers.contextnumbers
-local allocate = utilities.storage.allocate
-local setmetatableindex = table.setmetatableindex
+local allocate = utilities.storage.allocate
+local setmetatableindex = table.setmetatableindex
-- will be directives
-constructors.dontembed = allocate()
-constructors.mathactions = { }
-constructors.autocleanup = true
-constructors.namemode = "fullpath" -- will be a function
+constructors.dontembed = allocate()
+constructors.autocleanup = true
+constructors.namemode = "fullpath" -- will be a function
-constructors.version = 1.01
-constructors.cache = containers.define("fonts", "constructors", constructors.version, false)
+constructors.version = 1.01
+constructors.cache = containers.define("fonts", "constructors", constructors.version, false)
-constructors.privateoffset = 0xF0000 -- 0x10FFFF
+constructors.privateoffset = 0xF0000 -- 0x10FFFF
+
+-- Some experimental helpers (handy for tracing):
+--
+-- todo: extra:
+--
+-- extra_space => space.extra
+-- space => space.width
+-- space_stretch => space.stretch
+-- space_shrink => space.shrink
+
+-- We do keep the x-height, extra_space, space_shrink and space_stretch
+-- around as these are low level official names.
+
+constructors.keys = {
+ properties = {
+ encodingbytes = "number",
+ embedding = "number",
+ cidinfo = {
+ },
+ format = "string",
+ fontname = "string",
+ fullname = "string",
+ filename = "filename",
+ psname = "string",
+ name = "string",
+ virtualized = "boolean",
+ hasitalics = "boolean",
+ autoitalicamount = "basepoints",
+ nostackmath = "boolean",
+ noglyphnames = "boolean",
+ mode = "string",
+ hasmath = "boolean",
+ mathitalics = "boolean",
+ textitalics = "boolean",
+ finalized = "boolean",
+ },
+ parameters = {
+ mathsize = "number",
+ scriptpercentage = "float",
+ scriptscriptpercentage = "float",
+ units = "cardinal",
+ designsize = "scaledpoints",
+ expansion = {
+ stretch = "integerscale", -- might become float
+ shrink = "integerscale", -- might become float
+ step = "integerscale", -- might become float
+ auto = "boolean",
+ },
+ protrusion = {
+ auto = "boolean",
+ },
+ slantfactor = "float",
+ extendfactor = "float",
+ factor = "float",
+ hfactor = "float",
+ vfactor = "float",
+ size = "scaledpoints",
+ units = "scaledpoints",
+ scaledpoints = "scaledpoints",
+ slantperpoint = "scaledpoints",
+ spacing = {
+ width = "scaledpoints",
+ stretch = "scaledpoints",
+ shrink = "scaledpoints",
+ extra = "scaledpoints",
+ },
+ xheight = "scaledpoints",
+ quad = "scaledpoints",
+ ascender = "scaledpoints",
+ descender = "scaledpoints",
+ synonyms = {
+ space = "spacing.width",
+ spacestretch = "spacing.stretch",
+ spaceshrink = "spacing.shrink",
+ extraspace = "spacing.extra",
+ x_height = "xheight",
+ space_stretch = "spacing.stretch",
+ space_shrink = "spacing.shrink",
+ extra_space = "spacing.extra",
+ em = "quad",
+ ex = "xheight",
+ slant = "slantperpoint",
+ },
+ },
+ description = {
+ width = "basepoints",
+ height = "basepoints",
+ depth = "basepoints",
+ boundingbox = { },
+ },
+ character = {
+ width = "scaledpoints",
+ height = "scaledpoints",
+ depth = "scaledpoints",
+ italic = "scaledpoints",
+ },
+}
--- This might become an interface;
+-- This might become an interface:
local designsizes = allocate()
constructors.designsizes = designsizes
@@ -3009,7 +3466,7 @@ excessive memory usage in CJK fonts, we no longer pass the boundingbox.)</p>
-- The scaler is only used for otf and afm and virtual fonts. If
-- a virtual font has italic correction make sure to set the
--- italic_correction flag. Some more flags will be added in
+-- hasitalics flag. Some more flags will be added in
-- the future.
--[[ldx--
@@ -3055,39 +3512,75 @@ function constructors.calculatescale(tfmdata,scaledpoints)
return scaledpoints, scaledpoints / (parameters.units or 1000) -- delta
end
-function constructors.assignmathparameters(target,tfmdata)
+local unscaled = {
+ ScriptPercentScaleDown = true,
+ ScriptScriptPercentScaleDown = true,
+ RadicalDegreeBottomRaisePercent = true
+}
+
+function constructors.assignmathparameters(target,original) -- simple variant, not used in context
-- when a tfm file is loaded, it has already been scaled
- -- and it never enters the scaled so this is otf only
+ -- and it never enters the scaled so this is otf only and
+ -- even then we do some extra in the context math plugins
local mathparameters = original.mathparameters
if mathparameters and next(mathparameters) then
local targetparameters = target.parameters
+ local targetproperties = target.properties
local targetmathparameters = { }
- local factor = targetparameters.factor
+ local factor = targetproperties.math_is_scaled and 1 or targetparameters.factor
for name, value in next, mathparameters do
- if name == "RadicalDegreeBottomRaisePercent" then
+ if unscaled[name] then
targetmathparameters[name] = value
else
targetmathparameters[name] = value * factor
end
end
- if not targetmathparameters.AccentBaseHeight then
- targetmathparameters.AccentBaseHeight = nil -- safeguard, still needed?
- end
if not targetmathparameters.FractionDelimiterSize then
- targetmathparameters.FractionDelimiterSize = 0
+ targetmathparameters.FractionDelimiterSize = 1.01 * targetparameters.size
end
if not mathparameters.FractionDelimiterDisplayStyleSize then
- targetmathparameters.FractionDelimiterDisplayStyleSize = 0
+ targetmathparameters.FractionDelimiterDisplayStyleSize = 2.40 * targetparameters.size
end
target.mathparameters = targetmathparameters
end
end
+function constructors.beforecopyingcharacters(target,original)
+ -- can be used for additional tweaking
+end
+
+function constructors.aftercopyingcharacters(target,original)
+ -- can be used for additional tweaking
+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
+ 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
+
function constructors.scale(tfmdata,specification)
local target = { } -- the new table
--
if tonumber(specification) then
- specification = { size = specification }
+ specification = { size = specification }
end
--
local scaledpoints = specification.size
@@ -3104,10 +3597,9 @@ function constructors.scale(tfmdata,specification)
local mathparameters = tfmdata.mathparameters or { }
--
local targetcharacters = { }
- local targetdescriptions = table.derive(descriptions)
- local targetparameters = table.derive(parameters)
- -- local targetmathparameters = table.fastcopy(mathparameters) -- happens elsewhere
- local targetproperties = table.derive(properties)
+ local targetdescriptions = derivetable(descriptions)
+ local targetparameters = derivetable(parameters)
+ local targetproperties = derivetable(properties)
local targetgoodies = goodies -- we need to loop so no metatable
target.characters = targetcharacters
target.descriptions = targetdescriptions
@@ -3123,9 +3615,10 @@ function constructors.scale(tfmdata,specification)
-- specification.textsize : natural (text)size
-- parameters.mathsize : 1=text 2=script 3=scriptscript >1000 enforced size (feature value other than yes)
--
- local mathsize = tonumber(specification.mathsize) or 0
- local textsize = tonumber(specification.textsize) or scaledpoints
- local forcedsize = tonumber(parameters.mathsize ) or 0
+ local mathsize = tonumber(specification.mathsize) or 0
+ local textsize = tonumber(specification.textsize) or scaledpoints
+ local forcedsize = tonumber(parameters.mathsize ) or 0
+ local extrafactor = tonumber(specification.factor ) or 1
if (mathsize == 2 or forcedsize == 2) and parameters.scriptpercentage then
scaledpoints = parameters.scriptpercentage * textsize / 100
elseif (mathsize == 3 or forcedsize == 3) and parameters.scriptscriptpercentage then
@@ -3212,17 +3705,17 @@ function constructors.scale(tfmdata,specification)
target.auto_protrude = protrusion.auto
end
-- widening
- local extend_factor = parameters.extend_factor or 0
- if extend_factor ~= 0 and extend_factor ~= 1 then
- hdelta = hdelta * extend_factor
- target.extend = extend_factor * 1000 -- extent ?
+ local extendfactor = parameters.extendfactor or 0
+ if extendfactor ~= 0 and extendfactor ~= 1 then
+ hdelta = hdelta * extendfactor
+ target.extend = extendfactor * 1000 -- extent ?
else
target.extend = 1000 -- extent ?
end
-- slanting
- local slant_factor = parameters.slant_factor or 0
- if slant_factor ~= 0 then
- target.slant = slant_factor * 1000
+ local slantfactor = parameters.slantfactor or 0
+ if slantfactor ~= 0 then
+ target.slant = slantfactor * 1000
else
target.slant = 0
end
@@ -3234,19 +3727,20 @@ function constructors.scale(tfmdata,specification)
targetparameters.units = units
targetparameters.scaledpoints = askedscaledpoints
--
- local isvirtual = properties.virtualized or tfmdata.type == "virtual"
- local hasquality = target.auto_expand or target.auto_protrude
- local hasitalic = properties.italic_correction
- local stackmath = not properties.no_stackmath
- local nonames = properties.noglyphnames
- local nodemode = properties.mode == "node"
+ local isvirtual = properties.virtualized or tfmdata.type == "virtual"
+ local hasquality = target.auto_expand or target.auto_protrude
+ local hasitalics = properties.hasitalics
+ local autoitalicamount = properties.autoitalicamount
+ local stackmath = not properties.nostackmath
+ local nonames = properties.noglyphnames
+ local nodemode = properties.mode == "node"
--
if changed and not next(changed) then
changed = false
end
--
target.type = isvirtual and "virtual" or "real"
- -- this will move to some subtable so that it is copied at once
+ --
target.postprocessors = tfmdata.postprocessors
--
local targetslant = (parameters.slant or parameters[1] or 0)
@@ -3257,7 +3751,7 @@ function constructors.scale(tfmdata,specification)
local targetquad = (parameters.quad or parameters[6] or 0)*hdelta
local targetextra_space = (parameters.extra_space or parameters[7] or 0)*hdelta
--
- targetparameters.slant = targetslant
+ targetparameters.slant = targetslant -- slantperpoint
targetparameters.space = targetspace
targetparameters.space_stretch = targetspace_stretch
targetparameters.space_shrink = targetspace_shrink
@@ -3273,25 +3767,27 @@ function constructors.scale(tfmdata,specification)
if descender then
targetparameters.descender = delta * descender
end
- -- copies, might disappear
- targetparameters.xheight = targetparameters.xheight or parameters.x_height
- targetparameters.extraspace = targetparameters.extraspace or parameters.extra_space
- targetparameters.spacestretch = targetparameters.spacestretch or parameters.space_stretch
- targetparameters.spaceshrink = targetparameters.spaceshrink or parameters.space_shrink
+ --
+ constructors.enhanceparameters(targetparameters) -- official copies for us
--
local protrusionfactor = (targetquad ~= 0 and 1000/targetquad) or 0
local scaledwidth = defaultwidth * hdelta
local scaledheight = defaultheight * vdelta
local scaleddepth = defaultdepth * vdelta
--
- local hasmath = (properties.has_math or next(mathparameters)) and true
+ if trace_defining then
+ report_defining("scaling by (%s,%s): name '%s', fullname: '%s', filename: '%s'",
+ hdelta,vdelta,name or "noname",fullname or "nofullname",filename or "nofilename")
+ end
+ --
+ local hasmath = (properties.hasmath or next(mathparameters)) and true
if hasmath then
if trace_defining then
report_defining("math enabled for: name '%s', fullname: '%s', filename: '%s'",
name or "noname",fullname or "nofullname",filename or "nofilename")
end
constructors.assignmathparameters(target,tfmdata) -- does scaling and whatever is needed
- properties.has_math = true
+ properties.hasmath = true
target.nomath = false
target.MathConstants = target.mathparameters
else
@@ -3299,29 +3795,75 @@ function constructors.scale(tfmdata,specification)
report_defining("math disabled for: name '%s', fullname: '%s', filename: '%s'",
name or "noname",fullname or "nofullname",filename or "nofilename")
end
- properties.has_math = false
+ properties.hasmath = false
target.nomath = true
target.mathparameters = nil -- nop
end
--
- local sharedkerns = { }
+ local italickey = "italic"
+ --
+ -- some context specific trickery (this will move to a plugin)
+ --
+ if hasmath then
+ if properties.mathitalics then
+ italickey = "italic_correction"
+ if trace_defining then
+ report_defining("math italics disabled for: name '%s', fullname: '%s', filename: '%s'",
+ name or "noname",fullname or "nofullname",filename or "nofilename")
+ end
+ end
+ autoitalicamount = false -- new
+ else
+ if properties.textitalics then
+ italickey = "italic_correction"
+ if trace_defining then
+ report_defining("text italics disabled for: name '%s', fullname: '%s', filename: '%s'",
+ name or "noname",fullname or "nofullname",filename or "nofilename")
+ end
+ if properties.delaytextitalics then
+ autoitalicamount = false
+ end
+ end
+ end
+ --
+ -- end of context specific trickery
+ --
+ constructors.beforecopyingcharacters(target,tfmdata)
+ --
+ local sharedkerns = { }
+ --
+ -- we can have a dumb mode (basemode without math etc) that skips most
--
for unicode, character in next, characters do
- local chr, description, index
+ local chr, description, index, touni
if changed then
- -- basemode hack
+ -- basemode hack (we try to catch missing tounicodes, e.g. needed for ssty in math cambria)
local c = changed[unicode]
if c then
- description = descriptions[c] or character
+ description = descriptions[c] or descriptions[unicode] or character
character = characters[c] or character
index = description.index or c
+ if tounicode then
+ touni = tounicode[index] -- nb: index!
+ if not touni then -- goodie
+ local d = descriptions[unicode] or characters[unicode]
+ local i = d.index or unicode
+ touni = tounicode[i] -- nb: index!
+ end
+ end
else
description = descriptions[unicode] or character
index = description.index or unicode
+ if tounicode then
+ touni = tounicode[index] -- nb: index!
+ end
end
else
description = descriptions[unicode] or character
index = description.index or unicode
+ if tounicode then
+ touni = tounicode[index] -- nb: index!
+ end
end
local width = description.width
local height = description.height
@@ -3364,15 +3906,12 @@ function constructors.scale(tfmdata,specification)
}
end
end
+ if touni then
+ chr.tounicode = touni
+ end
-- if trace_scaling then
-- report_defining("t=%s, u=%s, i=%s, n=%s c=%s",k,chr.tounicode or "",index or 0,description.name or '-',description.class or '-')
-- end
- if tounicode then
- local tu = tounicode[index] -- nb: index!
- if tu then
- chr.tounicode = tu
- end
- end
if hasquality then
-- we could move these calculations elsewhere (saves calculations)
local ve = character.expansion_factor
@@ -3388,11 +3927,21 @@ function constructors.scale(tfmdata,specification)
chr.right_protruding = protrusionfactor*width*vr
end
end
- -- todo: hasitalic
- if hasitalic then
- local vi = description.italic or character.italic
+ --
+ if autoitalicamount then
+ local vi = description.italic
+ if not vi then
+ local vi = description.boundingbox[3] - description.width + autoitalicamount
+ if vi > 0 then -- < 0 indicates no overshoot or a very small auto italic
+ chr[italickey] = vi*hdelta
+ end
+ elseif vi ~= 0 then
+ chr[italickey] = vi*hdelta
+ end
+ elseif hasitalics then
+ local vi = description.italic
if vi and vi ~= 0 then
- chr.italic = vi*hdelta
+ chr[italickey] = vi*hdelta
end
end
-- to be tested
@@ -3523,6 +4072,9 @@ function constructors.scale(tfmdata,specification)
end
targetcharacters[unicode] = chr
end
+ --
+ constructors.aftercopyingcharacters(target,tfmdata)
+ --
return target
end
@@ -3563,12 +4115,12 @@ function constructors.finalize(tfmdata)
parameters.size = tfmdata.size
end
--
- if not parameters.extend_factor then
- parameters.extend_factor = tfmdata.extend or 0
+ if not parameters.extendfactor then
+ parameters.extendfactor = tfmdata.extend or 0
end
--
- if not parameters.slant_factor then
- parameters.slant_factor = tfmdata.slant or 0
+ if not parameters.slantfactor then
+ parameters.slantfactor = tfmdata.slant or 0
end
--
if not parameters.designsize then
@@ -3621,8 +4173,8 @@ function constructors.finalize(tfmdata)
-- tfmdata.fonts
-- tfmdata.unscaled
--
- if not properties.has_math then
- properties.has_math = not tfmdata.nomath
+ if not properties.hasmath then
+ properties.hasmath = not tfmdata.nomath
end
--
tfmdata.MathConstants = nil
@@ -3907,7 +4459,7 @@ a helper function.</p>
function constructors.checkedfeatures(what,features)
local defaults = handlers[what].features.defaults
if features and next(features) then
- features = fastcopy(features) -- can be inherited
+ features = fastcopy(features) -- can be inherited (mt) but then no loops possible
for key, value in next, defaults do
if features[key] == nil then
features[key] = value
@@ -3941,7 +4493,7 @@ function constructors.initializefeatures(what,tfmdata,features,trace,report)
for i=1,#initializers do
local step = initializers[i]
local feature = step.name
--- we could intercept mode here .. needs a rewrite of this whole loop then btu it's cleaner that way
+-- we could intercept mode here .. needs a rewrite of this whole loop then but it's cleaner that way
local value = features[feature]
if not value then
-- disabled
@@ -4010,6 +4562,9 @@ function constructors.collectprocessors(what,tfmdata,features,trace,report)
end
end
end
+ elseif trace then
+ report("no feature processors for mode %s for font %s",
+ mode or 'unknown', tfmdata.properties.fullname or 'unknown')
end
end
return processes
@@ -4068,7 +4623,7 @@ fonts.encodings.agl = { }
setmetatable(fonts.encodings.agl, { __index = function(t,k)
if k == "unicodes" then
texio.write(" <loading (extended) adobe glyph list>")
- local unicodes = dofile(resolvers.findfile("font-agl.lua"))
+ local unicodes = dofile(resolvers.findfile("font-age.lua"))
fonts.encodings.agl = { unicodes = unicodes }
return unicodes
else
@@ -4351,6 +4906,15 @@ local function tounicode16sequence(unicodes)
return concat(t)
end
+local function fromunicode16(str)
+ if #str == 4 then
+ return tonumber(str,16)
+ else
+ local l, r = match(str,"(....)(....)")
+ return (tonumber(l,16)- 0xD800)*0x400 + tonumber(r,16) - 0xDC00
+ end
+end
+
--~ This is quite a bit faster but at the cost of some memory but if we
--~ do this we will also use it elsewhere so let's not follow this route
--~ now. I might use this method in the plain variant (no caching there)
@@ -4375,6 +4939,7 @@ mappings.loadlumtable = loadlumtable
mappings.makenameparser = makenameparser
mappings.tounicode16 = tounicode16
mappings.tounicode16sequence = tounicode16sequence
+mappings.fromunicode16 = fromunicode16
local separator = S("_.")
local other = C((1 - separator)^1)
@@ -4430,7 +4995,9 @@ function mappings.addtounicode(data,filename)
if unic == -1 or unic >= private or (unic >= 0xE000 and unic <= 0xF8FF) or unic == 0xFFFE or unic == 0xFFFF then
local unicode = lumunic and lumunic[name] or unicodevector[name]
if unicode then
- originals[index], tounicode[index], ns = unicode, tounicode16(unicode), ns + 1
+ originals[index] = unicode
+ tounicode[index] = tounicode16(unicode)
+ ns = ns + 1
end
-- cidmap heuristics, beware, there is no guarantee for a match unless
-- the chain resolves
@@ -4439,7 +5006,9 @@ function mappings.addtounicode(data,filename)
if foundindex then
unicode = cidcodes[foundindex] -- name to number
if unicode then
- originals[index], tounicode[index], ns = unicode, tounicode16(unicode), ns + 1
+ originals[index] = unicode
+ tounicode[index] = tounicode16(unicode)
+ ns = ns + 1
else
local reference = cidnames[foundindex] -- number to name
if reference then
@@ -4447,16 +5016,23 @@ function mappings.addtounicode(data,filename)
if foundindex then
unicode = cidcodes[foundindex]
if unicode then
- originals[index], tounicode[index], ns = unicode, tounicode16(unicode), ns + 1
+ originals[index] = unicode
+ tounicode[index] = tounicode16(unicode)
+ ns = ns + 1
end
end
if not unicode then
local foundcodes, multiple = lpegmatch(uparser,reference)
if foundcodes then
+ originals[index] = foundcodes
if multiple then
- originals[index], tounicode[index], nl, unicode = foundcodes, tounicode16sequence(foundcodes), nl + 1, true
+ tounicode[index] = tounicode16sequence(foundcodes)
+ nl = nl + 1
+ unicode = true
else
- originals[index], tounicode[index], ns, unicode = foundcodes, tounicode16(foundcodes), ns + 1, foundcodes
+ tounicode[index] = tounicode16(foundcodes)
+ ns = ns + 1
+ unicode = foundcodes
end
end
end
@@ -4467,19 +5043,8 @@ function mappings.addtounicode(data,filename)
-- a.whatever or a_b_c.whatever or a_b_c (no numbers)
if not unicode then
local split = lpegmatch(ligsplitter,name)
- local nplit = (split and #split) or 0
- if nplit == 0 then
- -- skip
- elseif nplit == 1 then
- local base = split[1]
- unicode = unicodes[base] or unicodevector[base]
- if unicode then
- if type(unicode) == "table" then
- unicode = unicode[1]
- end
- originals[index], tounicode[index], ns = unicode, tounicode16(unicode), ns + 1
- end
- else
+ local nplit = split and #split or 0
+ if nplit >= 2 then
local t, n = { }, 0
for l=1,nplit do
local base = split[l]
@@ -4497,26 +5062,39 @@ function mappings.addtounicode(data,filename)
if n == 0 then -- done then
-- nothing
elseif n == 1 then
- originals[index], tounicode[index], nl, unicode = t[1], tounicode16(t[1]), nl + 1, true
+ originals[index] = t[1]
+ tounicode[index] = tounicode16(t[1])
else
- originals[index], tounicode[index], nl, unicode = t, tounicode16sequence(t), nl + 1, true
+ originals[index] = t
+ tounicode[index] = tounicode16sequence(t)
end
+ nl = nl + 1
+ unicode = true
+ else
+ -- skip: already checked and we don't want privates here
end
end
- -- last resort
+ -- last resort (we might need to catch private here as well)
if not unicode then
local foundcodes, multiple = lpegmatch(uparser,name)
if foundcodes then
if multiple then
- originals[index], tounicode[index], nl, unicode = foundcodes, tounicode16sequence(foundcodes), nl + 1, true
+ originals[index] = foundcodes
+ tounicode[index] = tounicode16sequence(foundcodes)
+ nl = nl + 1
+ unicode = true
else
- originals[index], tounicode[index], ns, unicode = foundcodes, tounicode16(foundcodes), ns + 1, foundcodes
+ originals[index] = foundcodes
+ tounicode[index] = tounicode16(foundcodes)
+ ns = ns + 1
+ unicode = foundcodes
end
end
end
- if not unicode then
- originals[index], tounicode[index] = 0xFFFD, "FFFD"
- end
+ -- if not unicode then
+ -- originals[index] = 0xFFFD
+ -- tounicode[index] = "FFFD"
+ -- end
end
end
if trace_mapping then
@@ -4782,6 +5360,8 @@ if not modules then modules = { } end modules ['font-otf'] = {
-- to_table -> totable
-- ascent descent
+-- more checking against low level calls of functions
+
local utf = unicode.utf8
local utfbyte = utf.byte
@@ -4792,7 +5372,7 @@ local getn = table.getn
local lpegmatch = lpeg.match
local reversed, concat, remove = table.reversed, table.concat, table.remove
local ioflush = io.flush
-local fastcopy, tohash = table.fastcopy, table.tohash
+local fastcopy, tohash, derivetable = table.fastcopy, table.tohash, table.derive
local allocate = utilities.storage.allocate
local registertracker = trackers.register
@@ -4817,7 +5397,7 @@ local otf = fonts.handlers.otf
otf.glists = { "gsub", "gpos" }
-otf.version = 2.730 -- beware: also sync font-mis.lua
+otf.version = 2.736 -- beware: also sync font-mis.lua
otf.cache = containers.define("fonts", "otf", otf.version, true)
local fontdata = fonts.hashes.identifiers
@@ -4884,15 +5464,21 @@ local function showfeatureorder(rawdata,filename)
if features then
for feature, scripts in next, features do
local tt = { }
- for script, languages in next, scripts do
- local ttt = { }
- for language, _ in next, languages do
- ttt[#ttt+1] = language
+ if type(scripts) == "table" then
+ for script, languages in next, scripts do
+ local ttt = { }
+ for language, _ in next, languages do
+ ttt[#ttt+1] = language
+ end
+ tt[#tt+1] = format("[%s: %s]",script,concat(ttt," "))
+ end
+ if trace_loading then
+ report_otf(" %s: %s",feature,concat(tt," "))
+ end
+ else
+ if trace_loading then
+ report_otf(" %s: %s",feature,tostring(scripts))
end
- tt[#tt+1] = format("[%s: %s]",script,concat(ttt," "))
- end
- if trace_loading then
- report_otf(" %s: %s",feature,concat(tt," "))
end
end
end
@@ -5061,11 +5647,14 @@ end
-- patches.register("before","migrate metadata","cambria",function() end)
function patches.register(what,where,pattern,action)
- local ww = what[where]
- if ww then
- ww[pattern] = action
- else
- ww = { [pattern] = action}
+ local pw = patches[what]
+ if pw then
+ local ww = pw[where]
+ if ww then
+ ww[pattern] = action
+ else
+ pw[where] = { [pattern] = action}
+ end
end
end
@@ -5106,8 +5695,8 @@ function otf.load(filename,format,sub,featurefile)
local attr = lfs.attributes(name)
featurefiles[#featurefiles+1] = {
name = name,
- size = size,
- time = time,
+ size = attr and attr.size or 0,
+ time = attr and attr.modification or 0,
}
end
end
@@ -5190,6 +5779,9 @@ function otf.load(filename,format,sub,featurefile)
duplicates = {
-- alternative unicodes
},
+ variants = {
+ -- alternative unicodes (variants)
+ },
lookuptypes = {
},
},
@@ -5214,6 +5806,7 @@ function otf.load(filename,format,sub,featurefile)
if packdata then
if cleanup > 0 then
collectgarbage("collect")
+--~ lua.collectgarbage()
end
enhance("pack",data,filename,nil)
end
@@ -5221,6 +5814,7 @@ function otf.load(filename,format,sub,featurefile)
data = containers.write(otf.cache, hash, data)
if cleanup > 1 then
collectgarbage("collect")
+--~ lua.collectgarbage()
end
stoptiming(data)
if elapsedtime then -- not in generic
@@ -5229,10 +5823,12 @@ function otf.load(filename,format,sub,featurefile)
fontloader.close(fontdata) -- free memory
if cleanup > 3 then
collectgarbage("collect")
+--~ lua.collectgarbage()
end
data = containers.read(otf.cache, hash) -- this frees the old table and load the sparse one
if cleanup > 2 then
collectgarbage("collect")
+--~ lua.collectgarbage()
end
else
data = nil
@@ -5269,7 +5865,7 @@ local mt = {
}
actions["prepare tables"] = function(data,filename,raw)
- data.properties.italic_correction = false
+ data.properties.hasitalics = false
end
actions["add dimensions"] = function(data,filename)
@@ -5354,7 +5950,7 @@ local function somecopy(old) -- fast one
end
end
--- not setting italic_correction and class (when nil) during
+-- not setting hasitalics and class (when nil) during
-- table cronstruction can save some mem
actions["prepare glyphs"] = function(data,filename,raw)
@@ -5370,6 +5966,7 @@ actions["prepare glyphs"] = function(data,filename,raw)
local unicodes = resources.unicodes -- name to unicode
local indices = resources.indices -- index to unicode
local duplicates = resources.duplicates
+ local variants = resources.variants
if rawsubfonts then
@@ -5469,11 +6066,28 @@ actions["prepare glyphs"] = function(data,filename,raw)
}
local altuni = glyph.altuni
if altuni then
- local d = { }
+ local d
for i=1,#altuni do
- d[#d+1] = altuni[i].unicode
+ local a = altuni[i]
+ local u = a.unicode
+ local v = a.variant
+ if v then
+ local vv = variants[v]
+ if vv then
+ vv[u] = unicode
+ else -- xits-math has some:
+ vv = { [u] = unicode }
+ variants[v] = vv
+ end
+ elseif d then
+ d[#d+1] = u
+ else
+ d = { u }
+ end
+ end
+ if d then
+ duplicates[unicode] = d
end
- duplicates[unicode] = d
end
else
report_otf("potential problem: glyph 0x%04X is used but empty",index)
@@ -5495,9 +6109,8 @@ actions["check encoding"] = function(data,filename,raw)
local properties = data.properties
local unicodes = resources.unicodes -- name to unicode
local indices = resources.indices -- index to unicodes
- local duplicates = resources.duplicates
- -- begin of messy (not needed whwn cidmap)
+ -- begin of messy (not needed when cidmap)
local mapdata = raw.map or { }
local unicodetoindex = mapdata and mapdata.map or { }
@@ -5571,7 +6184,6 @@ actions["add duplicates"] = function(data,filename,raw)
end
end
end
-
end
-- class : nil base mark ligature component (maybe we don't need it in description)
@@ -5582,9 +6194,9 @@ actions["analyze glyphs"] = function(data,filename,raw) -- maybe integrate this
local resources = data.resources
local metadata = data.metadata
local properties = data.properties
- local italic_correction = false
+ local hasitalics = false
local widths = { }
- local marks = { }
+ local marks = { } -- always present (saves checking)
for unicode, description in next, descriptions do
local glyph = description.glyph
local italic = glyph.italic_correction
@@ -5594,7 +6206,7 @@ actions["analyze glyphs"] = function(data,filename,raw) -- maybe integrate this
-- skip
else
description.italic = italic
- italic_correction = true
+ hasitalics = true
end
local width = glyph.width
widths[width] = (widths[width] or 0) + 1
@@ -5607,7 +6219,7 @@ actions["analyze glyphs"] = function(data,filename,raw) -- maybe integrate this
end
end
-- flag italic
- properties.italic_correction = italic_correction
+ properties.hasitalics = hasitalics
-- flag marks
resources.marks = marks
-- share most common width for cjk fonts
@@ -5729,6 +6341,29 @@ actions["prepare tounicode"] = function(data,filename,raw)
fonts.mappings.addtounicode(data,filename)
end
+local g_directions = {
+ gsub_contextchain = 1,
+ gpos_contextchain = 1,
+ -- gsub_context = 1,
+ -- gpos_context = 1,
+ gsub_reversecontextchain = -1,
+ gpos_reversecontextchain = -1,
+}
+
+-- Research by Khaled Hosny has demonstrated that the font loader merges
+-- regular and AAT features and that these can interfere (especially because
+-- we dropped checking for valid features elsewhere. So, we just check for
+-- the special flag and drop the feature if such a tag is found.
+
+local function supported(features)
+ for i=1,#features do
+ if features[i].ismac then
+ return false
+ end
+ end
+ return true
+end
+
actions["reorganize subtables"] = function(data,filename,raw)
local resources = data.resources
local sequences = { }
@@ -5741,72 +6376,72 @@ actions["reorganize subtables"] = function(data,filename,raw)
if dw then
for k=1,#dw do
local gk = dw[k]
- local typ = gk.type
- local chain =
- (typ == "gsub_contextchain" or typ == "gpos_contextchain") and 1 or
- (typ == "gsub_reversecontextchain" or typ == "gpos_reversecontextchain") and -1 or 0
- --
- local subtables = gk.subtables
- if subtables then
- local t = { }
- for s=1,#subtables do
- t[s] = subtables[s].name
- end
- subtables = t
- end
- local flags, markclass = gk.flags, nil
- if flags then
- local t = { -- forcing false packs nicer
- (flags.ignorecombiningmarks and "mark") or false,
- (flags.ignoreligatures and "ligature") or false,
- (flags.ignorebaseglyphs and "base") or false,
- flags.r2l or false,
- }
- markclass = flags.mark_class
- if markclass then
- markclass = resources.markclasses[markclass]
- end
- flags = t
- end
- --
- local name = gk.name
- --
local features = gk.features
- if features then
- -- scripts, tag, ismac
- local f = { }
- for i=1,#features do
- local df = features[i]
- local tag = strip(lower(df.tag))
- local ft = f[tag] if not ft then ft = {} f[tag] = ft end
- local dscripts = df.scripts
- for i=1,#dscripts do
- local d = dscripts[i]
- local languages = d.langs
- local script = strip(lower(d.script))
- local fts = ft[script] if not fts then fts = {} ft[script] = fts end
- for i=1,#languages do
- fts[strip(lower(languages[i]))] = true
+-- if features and supported(features) then
+ if not features or supported(features) then -- not always features !
+ local typ = gk.type
+ local chain = g_directions[typ] or 0
+ local subtables = gk.subtables
+ if subtables then
+ local t = { }
+ for s=1,#subtables do
+ t[s] = subtables[s].name
+ end
+ subtables = t
+ end
+ local flags, markclass = gk.flags, nil
+ if flags then
+ local t = { -- forcing false packs nicer
+ (flags.ignorecombiningmarks and "mark") or false,
+ (flags.ignoreligatures and "ligature") or false,
+ (flags.ignorebaseglyphs and "base") or false,
+ flags.r2l or false,
+ }
+ markclass = flags.mark_class
+ if markclass then
+ markclass = resources.markclasses[markclass]
+ end
+ flags = t
+ end
+ --
+ local name = gk.name
+ --
+ if features then
+ -- scripts, tag, ismac
+ local f = { }
+ for i=1,#features do
+ local df = features[i]
+ local tag = strip(lower(df.tag))
+ local ft = f[tag] if not ft then ft = {} f[tag] = ft end
+ local dscripts = df.scripts
+ for i=1,#dscripts do
+ local d = dscripts[i]
+ local languages = d.langs
+ local script = strip(lower(d.script))
+ local fts = ft[script] if not fts then fts = {} ft[script] = fts end
+ for i=1,#languages do
+ fts[strip(lower(languages[i]))] = true
+ end
end
end
+ sequences[#sequences+1] = {
+ type = typ,
+ chain = chain,
+ flags = flags,
+ name = name,
+ subtables = subtables,
+ markclass = markclass,
+ features = f,
+ }
+ else
+ lookups[name] = {
+ type = typ,
+ chain = chain,
+ flags = flags,
+ subtables = subtables,
+ markclass = markclass,
+ }
end
- sequences[#sequences+1] = {
- type = typ,
- chain = chain,
- flags = flags,
- name = name,
- subtables = subtables,
- markclass = markclass,
- features = f,
- }
- else
- lookups[name] = {
- type = typ,
- chain = chain,
- flags = flags,
- subtables = subtables,
- markclass = markclass,
- }
end
end
end
@@ -5847,19 +6482,20 @@ end
local function t_hashed(t,cache)
if t then
- local h = { }
+ local ht = { }
for i=1,#t do
local ti = t[i]
- local h = cache[ti]
- if not h then
- h = { }
+ local tih = cache[ti]
+ if not tih then
+ tih = { }
for i=1,#ti do
- h[ti] = true
+ tih[ti[i]] = true
end
+ cache[ti] = tih
end
- cache[ti] = h
+ ht[i] = tih
end
- return h
+ return ht
else
return nil
end
@@ -5943,7 +6579,7 @@ actions["reorganize lookups"] = function(data,filename,raw)
for i=1,#current do
current[i] = current_class[current[i]] or { }
if lookups and not lookups[i] then
- lookups[i] = false
+ lookups[i] = false -- e.g. we can have two lookups and one replacement
end
end
rule.current = t_hashed(current,h_cache)
@@ -6040,8 +6676,6 @@ actions["reorganize lookups"] = function(data,filename,raw)
end
end
--- to be checked italic_correction
-
local function check_variants(unicode,the_variants,splitter,unicodes)
local variants = the_variants.variants
if variants then -- use splitter
@@ -6441,9 +7075,9 @@ local function copytotfm(data,cache_id)
if data then
local metadata = data.metadata
local resources = data.resources
- local properties = table.derive(data.properties)
- local descriptions = table.derive(data.descriptions)
- local goodies = table.derive(data.goodies)
+ local properties = derivetable(data.properties)
+ local descriptions = derivetable(data.descriptions)
+ local goodies = derivetable(data.goodies)
local characters = { }
local parameters = { }
local mathparameters = { }
@@ -6569,6 +7203,11 @@ local function copytotfm(data,cache_id)
local fullname = metadata.fullname or fontname
local units = metadata.units_per_em or 1000
--
+ if units == 0 then -- catch bugs in fonts
+ units = 1000
+ metadata.units_per_em = 1000
+ end
+ --
parameters.slant = 0
parameters.space = spaceunits -- 3.333 (cmr10)
parameters.space_stretch = units/2 -- 500 -- 1.666 (cmr10)
@@ -6654,9 +7293,9 @@ local function otftotfm(specification)
tfmdata.shared = shared
end
shared.rawdata = rawdata
- shared.features = features -- default
+ -- shared.features = features -- default
shared.dynamics = { }
- shared.processes = { }
+ -- shared.processes = { }
tfmdata.changed = { }
shared.features = features
shared.processes = otf.setfeatures(tfmdata,features)
@@ -6675,7 +7314,8 @@ local function read_from_otf(specification)
tfmdata.properties.sub = specification.sub
--
tfmdata = constructors.scale(tfmdata,specification)
- constructors.applymanipulators("otf",tfmdata,specification.features.normal,trace_features,report_otf)
+ local allfeatures = tfmdata.shared.features or specification.features.normal
+ constructors.applymanipulators("otf",tfmdata,allfeatures,trace_features,report_otf)
constructors.setname(tfmdata,specification) -- only otf?
fonts.loggers.register(tfmdata,file.extname(specification.filename),specification)
end
@@ -6741,15 +7381,15 @@ local function check_otf(forced,specification,suffix,what)
if forced then
name = file.addsuffix(name,suffix,true)
end
- local fullname, tfmdata = findbinfile(name,suffix) or "", nil -- one shot
+ local fullname = findbinfile(name,suffix) or ""
if fullname == "" then
- fullname = fonts.names.getfilename(name,suffix)
+ fullname = fonts.names.getfilename(name,suffix) or ""
end
if fullname ~= "" then
- specification.filename, specification.format = fullname, what -- hm, so we do set the filename, then
- tfmdata = read_from_otf(specification) -- we need to do it for all matches / todo
+ specification.filename = fullname
+ specification.format = what
+ return read_from_otf(specification)
end
- return tfmdata
end
local function opentypereader(specification,suffix,what)
@@ -6817,6 +7457,8 @@ local otf = fonts.handlers.otf
local otffeatures = fonts.constructors.newfeatures("otf")
local registerotffeature = otffeatures.register
+otf.defaultbasealternate = "none" -- first last
+
local wildcard = "*"
local default = "dflt"
@@ -6849,6 +7491,22 @@ local function cref(feature,lookupname)
end
end
+local function report_alternate(feature,lookupname,descriptions,unicode,replacement,value,comment)
+ report_prepare("%s: base alternate %s => %s (%s => %s)",cref(feature,lookupname),
+ gref(descriptions,unicode),replacement and gref(descriptions,replacement) or "-",
+ tostring(value),comment)
+end
+
+local function report_substitution(feature,lookupname,descriptions,unicode,substitution)
+ report_prepare("%s: base substitution %s => %s",cref(feature,lookupname),
+ gref(descriptions,unicode),gref(descriptions,substitution))
+end
+
+local function report_ligature(feature,lookupname,descriptions,unicode,ligature)
+ report_prepare("%s: base ligature %s => %s",cref(feature,lookupname),
+ gref(descriptions,ligature),gref(descriptions,unicode))
+end
+
local basemethods = { }
local basemethod = "<unset>"
@@ -7013,27 +7671,47 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis
local lookuptypes = resources.lookuptypes
local ligatures = { }
+ local alternate = tonumber(value)
+ local defaultalt = otf.defaultbasealternate
+
+ local trace_singles = trace_baseinit and trace_singles
+ local trace_alternatives = trace_baseinit and trace_alternatives
+ local trace_ligatures = trace_baseinit and trace_ligatures
local actions = {
substitution = function(lookupdata,lookupname,description,unicode)
- if trace_baseinit and trace_singles then
- report_prepare("%s: base substitution %s => %s",cref(feature,lookupname),
- gref(descriptions,unicode),gref(descriptions,replacement))
+ if trace_singles then
+ report_substitution(feature,lookupname,descriptions,unicode,lookupdata)
end
changed[unicode] = lookupdata
end,
alternate = function(lookupdata,lookupname,description,unicode)
- local replacement = lookupdata[value] or lookupdata[#lookupdata]
- if trace_baseinit and trace_alternatives then
- report_prepare("%s: base alternate %s %s => %s",cref(feature,lookupname),
- tostring(value),gref(descriptions,unicode),gref(descriptions,replacement))
+ local replacement = lookupdata[alternate]
+ if replacement then
+ changed[unicode] = replacement
+ if trace_alternatives then
+ report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"normal")
+ end
+ elseif defaultalt == "first" then
+ replacement = lookupdata[1]
+ changed[unicode] = replacement
+ if trace_alternatives then
+ report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt)
+ end
+ elseif defaultalt == "last" then
+ replacement = lookupdata[#data]
+ if trace_alternatives then
+ report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt)
+ end
+ else
+ if trace_alternatives then
+ report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"unknown")
+ end
end
- changed[unicode] = replacement
end,
ligature = function(lookupdata,lookupname,description,unicode)
- if trace_baseinit and trace_alternatives then
- report_prepare("%s: base ligature %s %s => %s",cref(feature,lookupname),
- tostring(value),gref(descriptions,lookupdata),gref(descriptions,unicode))
+ if trace_ligatures then
+ report_ligature(feature,lookupname,descriptions,unicode,lookupdata)
end
ligatures[#ligatures+1] = { unicode, lookupdata }
end,
@@ -7199,6 +7877,12 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis
local lookuptypes = resources.lookuptypes
local ligatures = { }
+ local alternate = tonumber(value)
+ local defaultalt = otf.defaultbasealternate
+
+ local trace_singles = trace_baseinit and trace_singles
+ local trace_alternatives = trace_baseinit and trace_alternatives
+ local trace_ligatures = trace_baseinit and trace_ligatures
for l=1,#lookuplist do
local lookupname = lookuplist[l]
@@ -7206,20 +7890,38 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis
local lookuptype = lookuptypes[lookupname]
for unicode, data in next, lookupdata do
if lookuptype == "substitution" then
- if trace_baseinit and trace_singles then
- report_prepare("%s: base substitution %s => %s",cref(feature,lookupname),
- gref(descriptions,unicode),gref(descriptions,data))
+ if trace_singles then
+ report_substitution(feature,lookupname,descriptions,unicode,data)
end
changed[unicode] = data
elseif lookuptype == "alternate" then
- local replacement = data[value] or data[#data]
- if trace_baseinit and trace_alternatives then
- report_prepare("%s: base alternate %s %s => %s",cref(feature,lookupname),
- tostring(value),gref(descriptions,unicode),gref(descriptions,replacement))
+ local replacement = data[alternate]
+ if replacement then
+ changed[unicode] = replacement
+ if trace_alternatives then
+ report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"normal")
+ end
+ elseif defaultalt == "first" then
+ replacement = data[1]
+ changed[unicode] = replacement
+ if trace_alternatives then
+ report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt)
+ end
+ elseif defaultalt == "last" then
+ replacement = data[#data]
+ if trace_alternatives then
+ report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt)
+ end
+ else
+ if trace_alternatives then
+ report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"unknown")
+ end
end
- changed[unicode] = replacement
elseif lookuptype == "ligature" then
ligatures[#ligatures+1] = { unicode, data, lookupname }
+ if trace_ligatures then
+ report_ligature(feature,lookupname,descriptions,unicode,data)
+ end
end
end
end
@@ -7244,13 +7946,6 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis
make_2(present,tfmdata,characters,tree,"ctx_"..unicode,unicode,unicode,done,lookupname)
end
- if done then
- for lookupname, list in next, done do
- report_prepare("%s: base ligatures %s => %s",cref(feature,lookupname),
- tostring(value),gref(descriptions,done))
- end
- end
-
end
end
@@ -7356,13 +8051,13 @@ registerotffeature {
description = "features",
default = true,
initializers = {
---~ position = 1, -- after setscript (temp hack ... we need to force script / language to 1
+ -- position = 1, -- after setscript (temp hack ... we need to force script / language to 1
base = featuresinitializer,
}
}
-- independent : collect lookups independently (takes more runtime ... neglectable)
--- shared : shares lookups with node mode (takes more memory ... noticeable)
+-- shared : shares lookups with node mode (takes more memory unless also a node mode variant is used ... noticeable)
directives.register("fonts.otf.loader.basemethod", function(v)
if basemethods[v] then
@@ -7410,6 +8105,7 @@ local traverse_id = node.traverse_id
local unset_attribute = node.unset_attribute
local has_attribute = node.has_attribute
local set_attribute = node.set_attribute
+local copy_node = node.copy
local insert_node_before = node.insert_before
local insert_node_after = node.insert_after
@@ -7420,17 +8116,38 @@ local cursbase = attributes.private('cursbase')
local curscurs = attributes.private('curscurs')
local cursdone = attributes.private('cursdone')
local kernpair = attributes.private('kernpair')
+local ligacomp = attributes.private('ligacomp')
+local fontkern = attributes.private('fontkern')
+
+if context then
+
+ local kern = nodes.pool.register(newkern())
+
+ set_attribute(kern,fontkern,1) -- we can have several, attributes are shared
+
+ newkern = function(k)
+ local c = copy_node(kern)
+ c.kern = k
+ return c
+ end
+
+end
+
+-- This injector has been tested by Idris Samawi Hamid (several arabic fonts as well as
+-- the rather demanding Husayni font), Khaled Hosny (latin and arabic) and Kaj Eigner
+-- (arabic, hebrew and thai) and myself (whatever font I come across). I'm pretty sure
+-- that this code is not 100% okay but examples are needed to figure things out.
local cursives = { }
local marks = { }
local kerns = { }
--- currently we do gpos/kern in a bit inofficial way but when we
--- have the extra fields in glyphnodes to manipulate ht/dp/wd
--- explicitly i will provide an alternative; also, we can share
--- tables
+-- Currently we do gpos/kern in a bit inofficial way but when we have the extra fields in
+-- glyphnodes to manipulate ht/dp/wd explicitly I will provide an alternative; also, we
+-- can share tables.
--- for the moment we pass the r2l key ... volt/arabtype tests
+-- For the moment we pass the r2l key ... volt/arabtype tests .. idris: this needs
+-- checking with husayni (volt and fontforge).
function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext)
local dx, dy = factor*(exit[1]-entry[1]), factor*(exit[2]-entry[2])
@@ -7473,14 +8190,16 @@ function injections.setkern(current,factor,rlmode,x,tfmchr)
end
end
-function injections.setmark(start,base,factor,rlmode,ba,ma,index) --ba=baseanchor, ma=markanchor
- local dx, dy = factor*(ba[1]-ma[1]), factor*(ba[2]-ma[2])
- local bound = has_attribute(base,markbase)
+function injections.setmark(start,base,factor,rlmode,ba,ma,index) -- ba=baseanchor, ma=markanchor
+ local dx, dy = factor*(ba[1]-ma[1]), factor*(ba[2]-ma[2]) -- the index argument is no longer used but when this
+ local bound = has_attribute(base,markbase) -- fails again we should pass it
+local index = 1
if bound then
local mb = marks[bound]
if mb then
- if not index then index = #mb + 1 end
- mb[index] = { dx, dy }
+ -- if not index then index = #mb + 1 end
+index = #mb + 1
+ mb[index] = { dx, dy, rlmode }
set_attribute(start,markmark,bound)
set_attribute(start,markdone,index)
return dx, dy, bound
@@ -7488,6 +8207,7 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,index) --ba=baseancho
report_injections("possible problem, U+%05X is base mark without data (id: %s)",base.char,bound)
end
end
+-- index = index or 1
index = index or 1
bound = #marks + 1
set_attribute(base,markbase,bound)
@@ -7534,7 +8254,7 @@ local function trace(head)
end
else
m = m[1]
- report_injections(" markmark: bound=%s, dx=%s, dy=%s",mm,m[1] or "?",m[2] or "?")
+ report_injections(" markmark: bound=%s, dx=%s, dy=%s",mm,m and m[1] or "?",m and m[2] or "?")
end
end
if cb then
@@ -7552,7 +8272,8 @@ end
-- todo: reuse tables (i.e. no collection), but will be extra fields anyway
-- todo: check for attribute
--- we can have a fast test on a font being processed, so we can check faster for marks etc
+-- We can have a fast test on a font being processed, so we can check faster for marks etc
+-- but I'll make a context variant anyway.
function injections.handler(head,where,keep)
local has_marks, has_cursives, has_kerns = next(marks), next(cursives), next(kerns)
@@ -7690,6 +8411,7 @@ function injections.handler(head,where,keep)
local p_markbase = has_attribute(p,markbase)
if p_markbase then
local mrks = marks[p_markbase]
+ local nofmarks = #mrks
for n in traverse_id(glyph_code,p.next) do
local n_markmark = has_attribute(n,markmark)
if p_markbase == n_markmark then
@@ -7703,7 +8425,7 @@ function injections.handler(head,where,keep)
-- that makes sense but we no longer do that so as a
-- consequence the sign of p.width was changed (we need
-- to keep an eye on it as we don't have that many fonts
- -- that enter this branch .. i'm still not sure if this
+ -- that enter this branch .. I'm still not sure if this
-- one is right
local k = wx[p]
if k then
@@ -7726,9 +8448,14 @@ function injections.handler(head,where,keep)
else
n.yoffset = n.yoffset + p.yoffset + d[2]
end
+ if nofmarks == 1 then
+ break
+ else
+ nofmarks = nofmarks - 1
+ end
end
else
- break
+ -- KE: there can be <mark> <mkmk> <mark> sequences in ligatures
end
end
end
@@ -7740,23 +8467,32 @@ function injections.handler(head,where,keep)
-- todo : combine
if next(wx) then
for n, k in next, wx do
- -- only w can be nil, can be sped up when w == nil
- local rl, x, w, r2l = k[1], k[2] or 0, k[4] or 0, k[6]
- local wx = w - x
- if r2l then
- if wx ~= 0 then
- insert_node_before(head,n,newkern(wx))
- end
- if x ~= 0 then
- insert_node_after (head,n,newkern(x))
- end
- else
- if x ~= 0 then
- insert_node_before(head,n,newkern(x))
- end
- if wx ~= 0 then
- insert_node_after(head,n,newkern(wx))
+ -- only w can be nil (kernclasses), can be sped up when w == nil
+ local x, w = k[2] or 0, k[4]
+ if w then
+ local rl = k[1] -- r2l = k[6]
+ local wx = w - x
+ if rl < 0 then -- KE: don't use r2l here
+ if wx ~= 0 then
+ insert_node_before(head,n,newkern(wx))
+ end
+ if x ~= 0 then
+ insert_node_after (head,n,newkern(x))
+ end
+ else
+ if x ~= 0 then
+ insert_node_before(head,n,newkern(x))
+ end
+ if wx ~= 0 then
+ insert_node_after(head,n,newkern(wx))
+ end
end
+ elseif x ~= 0 then
+ -- this needs checking for rl < 0 but it is unlikely that a r2l script
+ -- uses kernclasses between glyphs so we're probably safe (KE has a
+ -- problematic font where marks interfere with rl < 0 in the previous
+ -- case)
+ insert_node_before(head,n,newkern(x))
end
end
end
@@ -7795,9 +8531,9 @@ function injections.handler(head,where,keep)
end
if w then
-- copied from above
- local r2l = kk[6]
+ -- local r2l = kk[6]
local wx = w - x
- if r2l then
+ if rl < 0 then -- KE: don't use r2l here
if wx ~= 0 then
insert_node_before(head,n,newkern(wx))
end
@@ -7865,6 +8601,7 @@ if not modules then modules = { } end modules ['font-otn'] = {
-- default features (per language, script)
-- handle positions (we need example fonts)
-- handle gpos_single (we might want an extra width field in glyph nodes because adding kerns might interfere)
+-- mark (to mark) code is still not what it should be (too messy but we need some more extreem husayni tests)
--[[ldx--
<p>This module is a bit more split up that I'd like but since we also want to test
@@ -7961,25 +8698,27 @@ local random = math.random
local logs, trackers, nodes, attributes = logs, trackers, nodes, attributes
+local registertracker = trackers.register
+
local fonts = fonts
local otf = fonts.handlers.otf
-local trace_lookups = false trackers.register("otf.lookups", function(v) trace_lookups = v end)
-local trace_singles = false trackers.register("otf.singles", function(v) trace_singles = v end)
-local trace_multiples = false trackers.register("otf.multiples", function(v) trace_multiples = v end)
-local trace_alternatives = false trackers.register("otf.alternatives", function(v) trace_alternatives = v end)
-local trace_ligatures = false trackers.register("otf.ligatures", function(v) trace_ligatures = v end)
-local trace_contexts = false trackers.register("otf.contexts", function(v) trace_contexts = v end)
-local trace_marks = false trackers.register("otf.marks", function(v) trace_marks = v end)
-local trace_kerns = false trackers.register("otf.kerns", function(v) trace_kerns = v end)
-local trace_cursive = false trackers.register("otf.cursive", function(v) trace_cursive = v end)
-local trace_preparing = false trackers.register("otf.preparing", function(v) trace_preparing = v end)
-local trace_bugs = false trackers.register("otf.bugs", function(v) trace_bugs = v end)
-local trace_details = false trackers.register("otf.details", function(v) trace_details = v end)
-local trace_applied = false trackers.register("otf.applied", function(v) trace_applied = v end)
-local trace_steps = false trackers.register("otf.steps", function(v) trace_steps = v end)
-local trace_skips = false trackers.register("otf.skips", function(v) trace_skips = v end)
-local trace_directions = false trackers.register("otf.directions", function(v) trace_directions = v end)
+local trace_lookups = false registertracker("otf.lookups", function(v) trace_lookups = v end)
+local trace_singles = false registertracker("otf.singles", function(v) trace_singles = v end)
+local trace_multiples = false registertracker("otf.multiples", function(v) trace_multiples = v end)
+local trace_alternatives = false registertracker("otf.alternatives", function(v) trace_alternatives = v end)
+local trace_ligatures = false registertracker("otf.ligatures", function(v) trace_ligatures = v end)
+local trace_contexts = false registertracker("otf.contexts", function(v) trace_contexts = v end)
+local trace_marks = false registertracker("otf.marks", function(v) trace_marks = v end)
+local trace_kerns = false registertracker("otf.kerns", function(v) trace_kerns = v end)
+local trace_cursive = false registertracker("otf.cursive", function(v) trace_cursive = v end)
+local trace_preparing = false registertracker("otf.preparing", function(v) trace_preparing = v end)
+local trace_bugs = false registertracker("otf.bugs", function(v) trace_bugs = v end)
+local trace_details = false registertracker("otf.details", function(v) trace_details = v end)
+local trace_applied = false registertracker("otf.applied", function(v) trace_applied = v end)
+local trace_steps = false registertracker("otf.steps", function(v) trace_steps = v end)
+local trace_skips = false registertracker("otf.skips", function(v) trace_skips = v end)
+local trace_directions = false registertracker("otf.directions", function(v) trace_directions = v end)
local report_direct = logs.reporter("fonts","otf direct")
local report_subchain = logs.reporter("fonts","otf subchain")
@@ -7987,15 +8726,15 @@ local report_chain = logs.reporter("fonts","otf chain")
local report_process = logs.reporter("fonts","otf process")
local report_prepare = logs.reporter("fonts","otf prepare")
-trackers.register("otf.verbose_chain", function(v) otf.setcontextchain(v and "verbose") end)
-trackers.register("otf.normal_chain", function(v) otf.setcontextchain(v and "normal") end)
+registertracker("otf.verbose_chain", function(v) otf.setcontextchain(v and "verbose") end)
+registertracker("otf.normal_chain", function(v) otf.setcontextchain(v and "normal") end)
-trackers.register("otf.replacements", "otf.singles,otf.multiples,otf.alternatives,otf.ligatures")
-trackers.register("otf.positions","otf.marks,otf.kerns,otf.cursive")
-trackers.register("otf.actions","otf.replacements,otf.positions")
-trackers.register("otf.injections","nodes.injections")
+registertracker("otf.replacements", "otf.singles,otf.multiples,otf.alternatives,otf.ligatures")
+registertracker("otf.positions","otf.marks,otf.kerns,otf.cursive")
+registertracker("otf.actions","otf.replacements,otf.positions")
+registertracker("otf.injections","nodes.injections")
-trackers.register("*otf.sample","otf.steps,otf.actions,otf.analyzing")
+registertracker("*otf.sample","otf.steps,otf.actions,otf.analyzing")
local insert_node_after = node.insert_after
local delete_node = nodes.delete
@@ -8003,6 +8742,7 @@ local copy_node = node.copy
local find_node_tail = node.tail or node.slide
local set_attribute = node.set_attribute
local has_attribute = node.has_attribute
+local flush_node_list = node.flush_list
local setmetatableindex = table.setmetatableindex
@@ -8027,14 +8767,21 @@ local ligature_code = glyphcodes.ligature
local privateattribute = attributes.private
+-- Something is messed up: we have two mark / ligature indices, one at the injection
+-- end and one here ... this is bases in KE's patches but there is something fishy
+-- there as I'm pretty sure that for husayni we need some connection (as it's much
+-- more complex than an average font) but I need proper examples of all cases, not
+-- of only some.
+
local state = privateattribute('state')
local markbase = privateattribute('markbase')
local markmark = privateattribute('markmark')
-local markdone = privateattribute('markdone')
+local markdone = privateattribute('markdone') -- assigned at the injection end
local cursbase = privateattribute('cursbase')
local curscurs = privateattribute('curscurs')
local cursdone = privateattribute('cursdone')
local kernpair = privateattribute('kernpair')
+local ligacomp = privateattribute('ligacomp') -- assigned here (ideally it should be combined)
local injections = nodes.injections
local setmark = injections.setmark
@@ -8054,6 +8801,8 @@ local registerotffeature = otffeatures.register
local onetimemessage = fonts.loggers.onetimemessage
+otf.defaultnodealternate = "none" -- first last
+
-- we share some vars here, after all, we have no nested lookups and
-- less code
@@ -8156,21 +8905,35 @@ end
local function toligature(kind,lookupname,start,stop,char,markflag,discfound) -- brr head
if start == stop then
start.char = char
+ return start
elseif discfound then
-- print("start->stop",nodes.tosequence(start,stop))
+ local components = start.components
+ if components then
+ flush_node_list(components)
+ start.components = nil
+ end
local lignode = copy_node(start)
- lignode.font, lignode.char, lignode.subtype = start.font, char, ligature_code
- local next, prev = stop.next, start.prev
+ lignode.font = start.font
+ lignode.char = char
+ lignode.subtype = ligature_code
+ local next = stop.next
+ local prev = start.prev
stop.next = nil
- lignode = node.do_ligature_n(start, stop, lignode)
+ start.prev = nil
+ lignode.components = start
+ -- print("lignode",nodes.tosequence(lignode))
+ -- print("components",nodes.tosequence(lignode.components))
prev.next = lignode
if next then
next.prev = lignode
end
- lignode.next, lignode.prev = next, prev
- start = lignode
+ lignode.next = next
+ lignode.prev = prev
-- print("start->end",nodes.tosequence(start))
- else -- start is the ligature
+ return lignode
+ else
+ -- start is the ligature
local deletemarks = markflag ~= "mark"
local n = copy_node(start)
local current
@@ -8180,48 +8943,46 @@ local function toligature(kind,lookupname,start,stop,char,markflag,discfound) --
if snext then
snext.prev = current
end
- start.prev, stop.next = nil, nil
- current.char, current.subtype, current.components = char, ligature_code, start
+ start.prev = nil
+ stop.next = nil
+ current.char = char
+ current.subtype = ligature_code
+ current.components = start
local head = current
- if deletemarks then
- if trace_marks then
- while start do
- if marks[start.char] then
- logwarning("%s: remove mark %s",pref(kind,lookupname),gref(start.char))
- end
- start = start.next
- end
- end
- else
- local i = 0
- while start do
- if marks[start.char] then
- set_attribute(start,markdone,i)
- if trace_marks then
- logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i)
- end
- head, current = insert_node_after(head,current,copy_node(start))
- else
- i = i + 1
+ -- this is messy ... we should get rid of the components eventually
+ local i = 0 -- is index of base
+ while start do
+ if not marks[start.char] then
+ i = i + 1
+ elseif not deletemarks then -- quite fishy
+ set_attribute(start,ligacomp,i)
+ if trace_marks then
+ logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i)
+ end
+ head, current = insert_node_after(head,current,copy_node(start))
+ end
+ start = start.next
+ end
+ start = current.next
+ while start and start.id == glyph_code do
+ if marks[start.char] then
+ set_attribute(start,ligacomp,i)
+ if trace_marks then
+ logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i)
end
- start = start.next
- end
- start = current.next
- while start and start.id == glyph_code do
- if marks[start.char] then
- set_attribute(start,markdone,i)
- if trace_marks then
- logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i)
- end
- else
- break
- end
- start = start.next
+ else
+ break
end
+ start = start.next
end
+ --
+ -- we do need components in funny kerning mode but maybe I can better reconstruct then
+ -- as we do have the font components info available; removing components makes the
+ -- previous code much simpler
+ --
+ -- flush_node_list(head.components)
return head
end
- return start
end
function handlers.gsub_single(start,kind,lookupname,replacement)
@@ -8232,8 +8993,12 @@ function handlers.gsub_single(start,kind,lookupname,replacement)
return start, true
end
-local function alternative_glyph(start,alternatives,kind,chainname,chainlookupname,lookupname) -- chainname and chainlookupname optional
- local value, choice, n = featurevalue or tfmdata.shared.features[kind], nil, #alternatives -- global value, brrr
+local function get_alternative_glyph(start,alternatives,value)
+ -- needs checking: (global value, brrr)
+ local choice = nil
+ local n = #alternatives
+ local char = start.char
+ --
if value == "random" then
local r = random(1,n)
value, choice = format("random, choice %s",r), alternatives[r]
@@ -8246,23 +9011,26 @@ local function alternative_glyph(start,alternatives,kind,chainname,chainlookupna
if type(value) ~= "number" then
value, choice = "default, choice 1", alternatives[1]
elseif value > n then
- value, choice = format("no %s variants, taking %s",value,n), alternatives[n]
+ local defaultalt = otf.defaultnodealternate
+ if defaultalt == "first" then
+ value, choice = format("no %s variants, taking %s",value,n), alternatives[n]
+ elseif defaultalt == "last" then
+ value, choice = format("no %s variants, taking %s",value,1), alternatives[1]
+ else
+ value, choice = format("no %s variants, ignoring",value), false
+ end
elseif value == 0 then
- value, choice = format("choice %s (no change)",value), start.char
+ value, choice = format("choice %s (no change)",value), char
elseif value < 1 then
value, choice = format("no %s variants, taking %s",value,1), alternatives[1]
else
value, choice = format("choice %s",value), alternatives[value]
end
end
- if not choice then
- logwarning("%s: no variant %s for %s",cref(kind,chainname,chainlookupname,lookupname),value,gref(start.char))
- choice, value = start.char, format("no replacement instead of %s",value)
- end
- return choice, value
+ return choice
end
-local function multiple_glyphs(start,multiple)
+local function multiple_glyphs(start,multiple) -- marks ?
local nofmultiples = #multiple
if nofmultiples > 0 then
start.char = multiple[1]
@@ -8290,11 +9058,18 @@ local function multiple_glyphs(start,multiple)
end
function handlers.gsub_alternate(start,kind,lookupname,alternative,sequence)
- local choice, index = alternative_glyph(start,alternative,kind,lookupname)
- if trace_alternatives then
- logprocess("%s: replacing %s by alternative %s (%s)",pref(kind,lookupname),gref(start.char),gref(choice),index)
+ local value = featurevalue == true and tfmdata.shared.features[kind] or featurevalue
+ local choice = get_alternative_glyph(start,alternative,value)
+ if choice then
+ if trace_alternatives then
+ logprocess("%s: replacing %s by alternative %s (%s)",pref(kind,lookupname),gref(char),gref(choice),choice)
+ end
+ start.char = choice
+ else
+ if trace_alternatives then
+ logwarning("%s: no variant %s for %s",pref(kind,lookupname),tostring(value),gref(char))
+ end
end
- start.char = choice
return start, true
end
@@ -8457,18 +9232,14 @@ function handlers.gpos_mark2ligature(start,kind,lookupname,markanchors,sequence)
local markchar = start.char
if marks[markchar] then
local base = start.prev -- [glyph] [optional marks] [start=mark]
- local index = 1
if base and base.id == glyph_code and base.subtype<256 and base.font == currentfont then
local basechar = base.char
if marks[basechar] then
- index = index + 1
while true do
base = base.prev
if base and base.id == glyph_code and base.subtype<256 and base.font == currentfont then
basechar = base.char
- if marks[basechar] then
- index = index + 1
- else
+ if not marks[basechar] then
break
end
else
@@ -8479,8 +9250,7 @@ function handlers.gpos_mark2ligature(start,kind,lookupname,markanchors,sequence)
end
end
end
- local i = has_attribute(start,markdone)
- if i then index = i end
+ local index = has_attribute(start,ligacomp)
local baseanchors = descriptions[basechar]
if baseanchors then
baseanchors = baseanchors.anchors
@@ -8494,7 +9264,7 @@ function handlers.gpos_mark2ligature(start,kind,lookupname,markanchors,sequence)
if ma then
ba = ba[index]
if ba then
- local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,index)
+ local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma) -- index
if trace_marks then
logprocess("%s, anchor %s, index %s, bound %s: anchoring mark %s to baselig %s at index %s => (%s,%s)",
pref(kind,lookupname),anchor,index,bound,gref(markchar),gref(basechar),index,dx,dy)
@@ -8525,46 +9295,55 @@ end
function handlers.gpos_mark2mark(start,kind,lookupname,markanchors,sequence)
local markchar = start.char
if marks[markchar] then
---~ local alreadydone = markonce and has_attribute(start,markmark)
---~ if not alreadydone then
- local base = start.prev -- [glyph] [basemark] [start=mark]
- if base and base.id == glyph_code and base.subtype<256 and base.font == currentfont then -- subtype test can go
- local basechar = base.char
- local baseanchors = descriptions[basechar]
+ local base = start.prev -- [glyph] [basemark] [start=mark]
+ -- while base and has_attribute(base,ligacomp) and has_attribute(base,ligacomp) ~= has_attribute(start,ligacomp) do
+ -- base = base.prev -- KE: prevents mkmk for marks on different components of a ligature
+ -- end
+ local slc = has_attribute(start,ligacomp)
+ if slc then -- a rather messy loop ... needs checking with husayni
+ while base do
+ local blc = has_attribute(base,ligacomp)
+ if blc and blc ~= slc then
+ base = base.prev
+ else
+ break
+ end
+ end
+ end
+ if base and base.id == glyph_code and base.subtype<256 and base.font == currentfont then -- subtype test can go
+ local basechar = base.char
+ local baseanchors = descriptions[basechar]
+ if baseanchors then
+ baseanchors = baseanchors.anchors
if baseanchors then
- baseanchors = baseanchors.anchors
+ baseanchors = baseanchors['basemark']
if baseanchors then
- baseanchors = baseanchors['basemark']
- if baseanchors then
- local al = anchorlookups[lookupname]
- for anchor,ba in next, baseanchors do
- if al[anchor] then
- local ma = markanchors[anchor]
- if ma then
- local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma)
- if trace_marks then
- logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%s,%s)",
- pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
- end
- return start,true
+ local al = anchorlookups[lookupname]
+ for anchor,ba in next, baseanchors do
+ if al[anchor] then
+ local ma = markanchors[anchor]
+ if ma then
+ local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma)
+ if trace_marks then
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%s,%s)",
+ pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
end
+ return start,true
end
end
- if trace_bugs then
- logwarning("%s: no matching anchors for mark %s and basemark %s",pref(kind,lookupname),gref(markchar),gref(basechar))
- end
+ end
+ if trace_bugs then
+ logwarning("%s: no matching anchors for mark %s and basemark %s",pref(kind,lookupname),gref(markchar),gref(basechar))
end
end
- else -- if trace_bugs then
- -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar))
- onetimemessage(currentfont,basechar,"no base anchors",report_fonts)
end
- elseif trace_bugs then
- logwarning("%s: prev node is no mark",pref(kind,lookupname))
+ else -- if trace_bugs then
+ -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar))
+ onetimemessage(currentfont,basechar,"no base anchors",report_fonts)
end
---~ elseif trace_marks and trace_details then
---~ logprocess("%s, mark %s is already bound (n=%s), ignoring mark2mark",pref(kind,lookupname),gref(markchar),alreadydone)
---~ end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no mark",pref(kind,lookupname))
+ end
elseif trace_bugs then
logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar))
end
@@ -8718,33 +9497,6 @@ end
local logwarning = report_subchain
-function chainmores.chainsub(start,stop,kind,chainname,currentcontext,lookuphash,lookuplist,chainlookupname,n)
- logprocess("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname))
- return start, false
-end
-
--- handled later:
---
--- function chainmores.gsub_single(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,n)
--- return chainprocs.gsub_single(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,n)
--- end
-
-function chainmores.gsub_multiple(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,n)
- logprocess("%s: gsub_multiple not yet supported",cref(kind,chainname,chainlookupname))
- return start, false
-end
-
-function chainmores.gsub_alternate(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,n)
- logprocess("%s: gsub_alternate not yet supported",cref(kind,chainname,chainlookupname))
- return start, false
-end
-
--- handled later:
---
--- function chainmores.gsub_ligature(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,n)
--- return chainprocs.gsub_ligature(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,n)
--- end
-
local function logprocess(...)
if trace_steps then
registermessage(...)
@@ -8762,6 +9514,11 @@ function chainprocs.chainsub(start,stop,kind,chainname,currentcontext,lookuphash
return start, false
end
+function chainmores.chainsub(start,stop,kind,chainname,currentcontext,lookuphash,lookuplist,chainlookupname,n)
+ logprocess("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname))
+ return start, false
+end
+
-- The reversesub is a special case, which is why we need to store the replacements
-- in a bit weird way. There is no lookup and the replacement comes from the lookup
-- itself. It is meant mostly for dealing with Urdu.
@@ -8793,17 +9550,29 @@ example, the following is valid:</p>
<p>Therefore we we don't really do the replacement here already unless we have the
single lookup case. The efficiency of the replacements can be improved by deleting
-as less as needed but that would also mke the code even more messy.</p>
+as less as needed but that would also make the code even more messy.</p>
--ldx]]--
-local function delete_till_stop(start,stop,ignoremarks)
- if start ~= stop then
- -- todo keep marks
+local function delete_till_stop(start,stop,ignoremarks) -- keeps start
+ local n = 1
+ if start == stop then
+ -- done
+ elseif ignoremarks then
+ repeat -- start x x m x x stop => start m
+ local next = start.next
+ if not marks[next.char] then
+ delete_node(start,next)
+ end
+ n = n + 1
+ until next == stop
+ else -- start x x x stop => start
repeat
local next = start.next
delete_node(start,next)
+ n = n + 1
until next == stop
end
+ return n
end
--[[ldx--
@@ -8813,10 +9582,6 @@ match.</p>
function chainprocs.gsub_single(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex)
-- todo: marks ?
---~ if not chainindex then
---~ delete_till_stop(start,stop) -- ,currentlookup.flags[1]
---~ stop = start
---~ end
local current = start
local subtables = currentlookup.subtables
if #subtables > 1 then
@@ -8862,7 +9627,7 @@ the match.</p>
--ldx]]--
function chainprocs.gsub_multiple(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
- delete_till_stop(start,stop)
+ delete_till_stop(start,stop) -- we could pass ignoremarks as #3 ..
local startchar = start.char
local subtables = currentlookup.subtables
local lookupname = subtables[1]
@@ -8887,36 +9652,54 @@ function chainprocs.gsub_multiple(start,stop,kind,chainname,currentcontext,looku
return start, false
end
+-- function chainmores.gsub_multiple(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,n)
+-- logprocess("%s: gsub_multiple not yet supported",cref(kind,chainname,chainlookupname))
+-- return start, false
+-- end
+
+chainmores.gsub_multiple = chainprocs.gsub_multiple
+
--[[ldx--
<p>Here we replace start by new glyph. First we delete the rest of the match.</p>
--ldx]]--
+-- char_1 mark_1 -> char_x mark_1 (ignore marks)
+-- char_1 mark_1 -> char_x
+
+-- to be checked: do we always have just one glyph?
+-- we can also have alternates for marks
+-- marks come last anyway
+-- are there cases where we need to delete the mark
+
function chainprocs.gsub_alternate(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
- -- todo: marks ?
- delete_till_stop(start,stop)
local current = start
local subtables = currentlookup.subtables
+ local value = featurevalue == true and tfmdata.shared.features[kind] or featurevalue
while current do
- if current.id == glyph_code then
+ if current.id == glyph_code then -- is this check needed?
local currentchar = current.char
local lookupname = subtables[1]
local alternatives = lookuphash[lookupname]
if not alternatives then
if trace_bugs then
- logwarning("%s: no alternative hits",cref(kind,chainname,chainlookupname,lookupname))
+ logwarning("%s: no alternative hit",cref(kind,chainname,chainlookupname,lookupname))
end
else
alternatives = alternatives[currentchar]
- if not alternatives then
- if trace_bugs then
- logwarning("%s: no alternative for %s",cref(kind,chainname,chainlookupname,lookupname),gref(currentchar))
- end
- else
- local choice, index = alternative_glyph(current,alternatives,kind,chainname,chainlookupname,lookupname)
- current.char = choice
- if trace_alternatives then
- logprocess("%s: replacing single %s by alternative %s (%s)",cref(kind,chainname,chainlookupname,lookupname),index,gref(currentchar),gref(choice),index)
+ if alternatives then
+ local choice = get_alternative_glyph(current,alternatives,value)
+ if choice then
+ if trace_alternatives then
+ logprocess("%s: replacing %s by alternative %s (%s)",cref(kind,chainname,chainlookupname,lookupname),gref(char),gref(choice),choice)
+ end
+ start.char = choice
+ else
+ if trace_alternatives then
+ logwarning("%s: no variant %s for %s",cref(kind,chainname,chainlookupname,lookupname),tostring(value),gref(char))
+ end
end
+ elseif trace_bugs then
+ logwarning("%s: no alternative for %s",cref(kind,chainname,chainlookupname,lookupname),gref(currentchar))
end
end
return start, true
@@ -8929,6 +9712,13 @@ function chainprocs.gsub_alternate(start,stop,kind,chainname,currentcontext,look
return start, false
end
+-- function chainmores.gsub_alternate(start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,n)
+-- logprocess("%s: gsub_alternate not yet supported",cref(kind,chainname,chainlookupname))
+-- return start, false
+-- end
+
+chainmores.gsub_alternate = chainprocs.gsub_alternate
+
--[[ldx--
<p>When we replace ligatures we use a helper that handles the marks. I might change
this function (move code inline and handle the marks by a separate function). We
@@ -9079,18 +9869,14 @@ function chainprocs.gpos_mark2ligature(start,stop,kind,chainname,currentcontext,
end
if markanchors then
local base = start.prev -- [glyph] [optional marks] [start=mark]
- local index = 1
if base and base.id == glyph_code and base.subtype<256 and base.font == currentfont then
local basechar = base.char
if marks[basechar] then
- index = index + 1
while true do
base = base.prev
if base and base.id == glyph_code and base.subtype<256 and base.font == currentfont then
basechar = base.char
- if marks[basechar] then
- index = index + 1
- else
+ if not marks[basechar] then
break
end
else
@@ -9102,8 +9888,7 @@ function chainprocs.gpos_mark2ligature(start,stop,kind,chainname,currentcontext,
end
end
-- todo: like marks a ligatures hash
- local i = has_attribute(start,markdone)
- if i then index = i end
+ local index = has_attribute(start,ligacomp)
local baseanchors = descriptions[basechar].anchors
if baseanchors then
local baseanchors = baseanchors['baselig']
@@ -9115,7 +9900,7 @@ function chainprocs.gpos_mark2ligature(start,stop,kind,chainname,currentcontext,
if ma then
ba = ba[index]
if ba then
- local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,index)
+ local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma) -- index
if trace_marks then
logprocess("%s, anchor %s, bound %s: anchoring mark %s to baselig %s at index %s => (%s,%s)",
cref(kind,chainname,chainlookupname,lookupname),anchor,a or bound,gref(markchar),gref(basechar),index,dx,dy)
@@ -9156,6 +9941,20 @@ function chainprocs.gpos_mark2mark(start,stop,kind,chainname,currentcontext,look
end
if markanchors then
local base = start.prev -- [glyph] [basemark] [start=mark]
+ -- while (base and has_attribute(base,ligacomp) and has_attribute(base,ligacomp) ~= has_attribute(start,ligacomp)) do
+ -- base = base.prev -- KE: prevents mkmk for marks on different components of a ligature
+ -- end
+ local slc = has_attribute(start,ligacomp)
+ if slc then -- a rather messy loop ... needs checking with husayni
+ while base do
+ local blc = has_attribute(base,ligacomp)
+ if blc and blc ~= slc then
+ base = base.prev
+ else
+ break
+ end
+ end
+ end
if base and base.id == glyph_code and base.subtype<256 and base.font == currentfont then -- subtype test can go
local basechar = base.char
local baseanchors = descriptions[basechar].anchors
@@ -9372,36 +10171,40 @@ end
local function normal_handle_contextchain(start,kind,chainname,contexts,sequence,lookuphash)
-- local rule, lookuptype, sequence, f, l, lookups = ck[1], ck[2] ,ck[3], ck[4], ck[5], ck[6]
- local flags, done = sequence.flags, false
- local skipmark, skipligature, skipbase = flags[1], flags[2], flags[3]
- local someskip = skipmark or skipligature or skipbase -- could be stored in flags for a fast test (hm, flags could be false !)
- local markclass = sequence.markclass -- todo, first we need a proper test
- local skipped = false
+ local flags = sequence.flags
+ local done = false
+ local skipmark = flags[1]
+ local skipligature = flags[2]
+ local skipbase = flags[3]
+ local someskip = skipmark or skipligature or skipbase -- could be stored in flags for a fast test (hm, flags could be false !)
+ local markclass = sequence.markclass -- todo, first we need a proper test
+ local skipped = false
for k=1,#contexts do
- local match, current, last = true, start, start
- local ck = contexts[k]
- local seq = ck[3]
- local s = #seq
+ local match = true
+ local current = start
+ local last = start
+ local ck = contexts[k]
+ local seq = ck[3]
+ local s = #seq
-- f..l = mid string
if s == 1 then
-- never happens
match = current.id == glyph_code and current.subtype<256 and current.font == currentfont and seq[1][current.char]
else
- -- todo: better space check (maybe check for glue)
+ -- maybe we need a better space check (maybe check for glue or category or combination)
+ -- we cannot optimize for n=2 because there can be disc nodes
local f, l = ck[4], ck[5]
-- current match
- if f == 1 and f == l then
+ if f == 1 and f == l then -- current only
-- already a hit
- match = true
- else
+ -- match = true
+ else -- before/current/after | before/current | current/after
-- no need to test first hit (to be optimized)
- local n = f + 1
- last = last.next
- -- we cannot optimize for n=2 because there can be disc nodes
- -- if not someskip and n == l then
- -- -- n=2 and no skips then faster loop
- -- match = last and last.id == glyph_code and last.subtype<256 and last.font == currentfont and seq[n][last.char]
- -- else
+ if f == l then -- new, else last out of sync (f is > 1)
+ -- match = true
+ else
+ local n = f + 1
+ last = last.next
while n <= l do
if last then
local id = last.id
@@ -9423,24 +10226,29 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
end
n = n + 1
else
- match = false break
+ match = false
+ break
end
else
- match = false break
+ match = false
+ break
end
else
- match = false break
+ match = false
+ break
end
- elseif id == disc_code then -- what to do with kerns?
+ elseif id == disc_code then
last = last.next
else
- match = false break
+ match = false
+ break
end
else
- match = false break
+ match = false
+ break
end
end
- -- end
+ end
end
-- before
if match and f > 1 then
@@ -9464,26 +10272,31 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
elseif seq[n][char] then
n = n -1
else
- match = false break
+ match = false
+ break
end
else
- match = false break
+ match = false
+ break
end
else
- match = false break
+ match = false
+ break
end
elseif id == disc_code then
-- skip 'm
elseif seq[n][32] then
n = n -1
else
- match = false break
+ match = false
+ break
end
prev = prev.prev
elseif seq[n][32] then -- somehat special, as zapfino can have many preceding spaces
n = n -1
else
- match = false break
+ match = false
+ break
end
end
elseif f == 2 then
@@ -9491,7 +10304,8 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
else
for n=f-1,1 do
if not seq[n][32] then
- match = false break
+ match = false
+ break
end
end
end
@@ -9519,26 +10333,31 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
elseif seq[n][char] then
n = n + 1
else
- match = false break
+ match = false
+ break
end
else
- match = false break
+ match = false
+ break
end
else
- match = false break
+ match = false
+ break
end
elseif id == disc_code then
-- skip 'm
elseif seq[n][32] then -- brrr
n = n + 1
else
- match = false break
+ match = false
+ break
end
current = current.next
elseif seq[n][32] then
n = n + 1
else
- match = false break
+ match = false
+ break
end
end
elseif s-l == 1 then
@@ -9546,7 +10365,8 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
else
for n=l+1,s do
if not seq[n][32] then
- match = false break
+ match = false
+ break
end
end
end
@@ -9572,11 +10392,15 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
if nofchainlookups == 1 then
local chainlookupname = chainlookups[1]
local chainlookup = lookuptable[chainlookupname]
- local cp = chainprocs[chainlookup.type]
- if cp then
- start, done = cp(start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence)
- else
- logprocess("%s: %s is not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)
+ if chainlookup then
+ local cp = chainprocs[chainlookup.type]
+ if cp then
+ start, done = cp(start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence)
+ else
+ logprocess("%s: %s is not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)
+ end
+ else -- shouldn't happen
+ logprocess("%s is not yet supported",cref(kind,chainname,chainlookupname))
end
else
local i = 1
@@ -9598,8 +10422,8 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
end
end
local chainlookupname = chainlookups[i]
- local chainlookup = lookuptable[chainlookupname]
- local cp = chainmores[chainlookup.type]
+ local chainlookup = lookuptable[chainlookupname] -- can be false (n matches, <n replacement)
+ local cp = chainlookup and chainmores[chainlookup.type]
if cp then
local ok, n
start, ok, n = cp(start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,i,sequence)
@@ -9612,7 +10436,8 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
i = i + 1
end
else
- logprocess("%s: multiple subchains for %s are not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)
+ -- is valid
+ -- logprocess("%s: multiple subchains for %s are not yet supported",cref(kind,chainname,chainlookupname),chainlookup and chainlookup.type or "?")
i = i + 1
end
start = start.next
@@ -9722,7 +10547,7 @@ local function initialize(sequence,script,language,enabled)
if valid then
local languages = scripts[script] or scripts[wildcard]
if languages and (languages[language] or languages[wildcard]) then
- return { valid, special_attributes[kind] or false, sequence.chain or 0, kind }
+ return { valid, special_attributes[kind] or false, sequence.chain or 0, kind, sequence }
end
end
end
@@ -9730,7 +10555,7 @@ local function initialize(sequence,script,language,enabled)
return false
end
-function otf.dataset(ftfmdata,sequences,font) -- generic variant, overloaded in context
+function otf.dataset(tfmdata,sequences,font) -- generic variant, overloaded in context
local shared = tfmdata.shared
local properties = tfmdata.properties
local language = properties.language or "dflt"
@@ -9759,6 +10584,22 @@ function otf.dataset(ftfmdata,sequences,font) -- generic variant, overloaded in
return rl
end
+-- elseif id == glue_code then
+-- if p[5] then -- chain
+-- local pc = pp[32]
+-- if pc then
+-- start, ok = start, false -- p[1](start,kind,p[2],pc,p[3],p[4])
+-- if ok then
+-- done = true
+-- end
+-- if start then start = start.next end
+-- else
+-- start = start.next
+-- end
+-- else
+-- start = start.next
+-- end
+
local function featuresprocessor(head,font,attr)
local lookuphash = lookuphashes[font] -- we can also check sequences here
@@ -9788,67 +10629,147 @@ local function featuresprocessor(head,font,attr)
local done = false
local datasets = otf.dataset(tfmdata,sequences,font,attr)
+ local dirstack = { } -- could move outside function
+
+ -- We could work on sub start-stop ranges instead but I wonder if there is that
+ -- much speed gain (experiments showed that it made not much sense) and we need
+ -- to keep track of directions anyway. Also at some point I want to play with
+ -- font interactions and then we do need the full sweeps.
+
for s=1,#sequences do
- local pardir, txtdir, success = 0, { }, false -- we could reuse txtdir and use a top pointer
- local sequence = sequences[s]
- local dataset = datasets[s] -- cache
- featurevalue = dataset and dataset[1] -- todo: pass to function instead of using a global
- if featurevalue then
- local attribute, chain, typ, subtables = dataset[2], dataset[3], sequence.type, sequence.subtables
---~ print(typ)
---~ table.print(table.keys(sequence))
- if chain < 0 then
- -- this is a limited case, no special treatments like 'init' etc
- local handler = handlers[typ]
- -- we need to get rid of this slide !
- local start = find_node_tail(head) -- slow (we can store tail because there's always a skip at the end): todo
- while start do
- local id = start.id
- if id == glyph_code then
- if start.subtype<256 and start.font == font then
- local a = has_attribute(start,0)
- if a then
- a = a == attr
- else
- a = true
- end
- if a then
- for i=1,#subtables do
- local lookupname = subtables[i]
- local lookupcache = lookuphash[lookupname]
- if lookupcache then
- local lookupmatch = lookupcache[start.char]
- if lookupmatch then
- start, success = handler(start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
- if success then
- break
+ local dataset = datasets[s]
+ if dataset then
+ featurevalue = dataset[1] -- todo: pass to function instead of using a global
+ if featurevalue then
+ local sequence = sequences[s] -- also dataset[5]
+ local rlparmode = 0
+ local topstack = 0
+ local success = false
+ local attribute = dataset[2]
+ local chain = dataset[3] -- sequence.chain or 0
+ local typ = sequence.type
+ local subtables = sequence.subtables
+ if chain < 0 then
+ -- this is a limited case, no special treatments like 'init' etc
+ local handler = handlers[typ]
+ -- we need to get rid of this slide! probably no longer needed in latest luatex
+ local start = find_node_tail(head) -- slow (we can store tail because there's always a skip at the end): todo
+ while start do
+ local id = start.id
+ if id == glyph_code then
+ if start.subtype<256 and start.font == font then
+ local a = has_attribute(start,0)
+ if a then
+ a = a == attr
+ else
+ a = true
+ end
+ if a then
+ for i=1,#subtables do
+ local lookupname = subtables[i]
+ local lookupcache = lookuphash[lookupname]
+ if lookupcache then
+ local lookupmatch = lookupcache[start.char]
+ if lookupmatch then
+ start, success = handler(start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
+ if success then
+ break
+ end
end
+ else
+ report_missing_cache(typ,lookupname)
end
- else
- report_missing_cache(typ,lookupname)
end
+ if start then start = start.prev end
+ else
+ start = start.prev
end
- if start then start = start.prev end
else
start = start.prev
end
else
start = start.prev
end
- else
- start = start.prev
end
- end
- else
- local handler = handlers[typ]
- local ns = #subtables
- local start = head -- local ?
- rlmode = 0 -- to be checked ?
- if ns == 1 then
- local lookupname = subtables[1]
- local lookupcache = lookuphash[lookupname]
- if not lookupcache then
- report_missing_cache(typ,lookupname)
+ else
+ local handler = handlers[typ]
+ local ns = #subtables
+ local start = head -- local ?
+ rlmode = 0 -- to be checked ?
+ if ns == 1 then -- happens often
+ local lookupname = subtables[1]
+ local lookupcache = lookuphash[lookupname]
+ if not lookupcache then -- also check for empty cache
+ report_missing_cache(typ,lookupname)
+ else
+ while start do
+ local id = start.id
+ if id == glyph_code then
+ if start.subtype<256 and start.font == font then
+ local a = has_attribute(start,0)
+ if a then
+ a = (a == attr) and (not attribute or has_attribute(start,state,attribute))
+ else
+ a = not attribute or has_attribute(start,state,attribute)
+ end
+ if a then
+ local lookupmatch = lookupcache[start.char]
+ if lookupmatch then
+ -- sequence kan weg
+ local ok
+ start, ok = handler(start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
+ if ok then
+ success = true
+ end
+ end
+ if start then start = start.next end
+ else
+ start = start.next
+ end
+ else
+ start = start.next
+ end
+ elseif id == whatsit_code then -- will be function
+ local subtype = start.subtype
+ if subtype == dir_code then
+ local dir = start.dir
+ if dir == "+TRT" or dir == "+TLT" then
+ topstack = topstack + 1
+ dirstack[topstack] = dir
+ elseif dir == "-TRT" or dir == "-TLT" then
+ topstack = topstack - 1
+ end
+ local newdir = dirstack[topstack]
+ if newdir == "+TRT" then
+ rlmode = -1
+ elseif newdir == "+TLT" then
+ rlmode = 1
+ else
+ rlmode = rlparmode
+ end
+ if trace_directions then
+ report_process("directions after txtdir %s: txtdir=%s:%s, parmode=%s, txtmode=%s",dir,topstack,newdir or "unset",rlparmode,rlmode)
+ end
+ elseif subtype == localpar_code then
+ local dir = start.dir
+ if dir == "TRT" then
+ rlparmode = -1
+ elseif dir == "TLT" then
+ rlparmode = 1
+ else
+ rlparmode = 0
+ end
+ rlmode = rlparmode
+ if trace_directions then
+ report_process("directions after pardir %s: parmode=%s, txtmode=%s",dir,rlparmode,rlmode)
+ end
+ end
+ start = start.next
+ else
+ start = start.next
+ end
+ end
+ end
else
while start do
local id = start.id
@@ -9861,13 +10782,22 @@ local function featuresprocessor(head,font,attr)
a = not attribute or has_attribute(start,state,attribute)
end
if a then
- local lookupmatch = lookupcache[start.char]
- if lookupmatch then
- -- sequence kan weg
- local ok
- start, ok = handler(start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
- if ok then
- success = true
+ for i=1,ns do
+ local lookupname = subtables[i]
+ local lookupcache = lookuphash[lookupname]
+ if lookupcache then
+ local lookupmatch = lookupcache[start.char]
+ if lookupmatch then
+ -- we could move all code inline but that makes things even more unreadable
+ local ok
+ start, ok = handler(start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
+ if ok then
+ success = true
+ break
+ end
+ end
+ else
+ report_missing_cache(typ,lookupname)
end
end
if start then start = start.next end
@@ -9877,54 +10807,39 @@ local function featuresprocessor(head,font,attr)
else
start = start.next
end
- -- elseif id == glue_code then
- -- if p[5] then -- chain
- -- local pc = pp[32]
- -- if pc then
- -- start, ok = start, false -- p[1](start,kind,p[2],pc,p[3],p[4])
- -- if ok then
- -- done = true
- -- end
- -- if start then start = start.next end
- -- else
- -- start = start.next
- -- end
- -- else
- -- start = start.next
- -- end
elseif id == whatsit_code then
local subtype = start.subtype
if subtype == dir_code then
local dir = start.dir
if dir == "+TRT" or dir == "+TLT" then
- insert(txtdir,dir)
+ topstack = topstack + 1
+ dirstack[topstack] = dir
elseif dir == "-TRT" or dir == "-TLT" then
- remove(txtdir)
+ topstack = topstack - 1
end
- local d = txtdir[#txtdir]
- if d == "+TRT" then
+ local newdir = dirstack[topstack]
+ if newdir == "+TRT" then
rlmode = -1
- elseif d == "+TLT" then
+ elseif newdir == "+TLT" then
rlmode = 1
else
- rlmode = pardir
+ rlmode = rlparmode
end
if trace_directions then
- report_process("directions after textdir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode)
+ report_process("directions after txtdir %s: txtdir=%s:%s, parmode=%s, txtmode=%s",dir,topstack,newdir or "unset",rlparmode,rlmode)
end
elseif subtype == localpar_code then
local dir = start.dir
if dir == "TRT" then
- pardir = -1
+ rlparmode = -1
elseif dir == "TLT" then
- pardir = 1
+ rlparmode = 1
else
- pardir = 0
+ rlparmode = 0
end
- rlmode = pardir
- --~ txtdir = { }
+ rlmode = rlparmode
if trace_directions then
- report_process("directions after pardir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode)
+ report_process("directions after pardir %s: parmode=%s, txtmode=%s",dir,rlparmode,rlmode)
end
end
start = start.next
@@ -9933,105 +10848,13 @@ local function featuresprocessor(head,font,attr)
end
end
end
- else
- while start do
- local id = start.id
- if id == glyph_code then
- if start.subtype<256 and start.font == font then
- local a = has_attribute(start,0)
- if a then
- a = (a == attr) and (not attribute or has_attribute(start,state,attribute))
- else
- a = not attribute or has_attribute(start,state,attribute)
- end
- if a then
- for i=1,ns do
- local lookupname = subtables[i]
- local lookupcache = lookuphash[lookupname]
- if lookupcache then
- local lookupmatch = lookupcache[start.char]
- if lookupmatch then
- -- we could move all code inline but that makes things even more unreadable
- local ok
- start, ok = handler(start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
- if ok then
- success = true
- break
- end
- end
- else
- report_missing_cache(typ,lookupname)
- end
- end
- if start then start = start.next end
- else
- start = start.next
- end
- else
- start = start.next
- end
- -- elseif id == glue_code then
- -- if p[5] then -- chain
- -- local pc = pp[32]
- -- if pc then
- -- start, ok = start, false -- p[1](start,kind,p[2],pc,p[3],p[4])
- -- if ok then
- -- done = true
- -- end
- -- if start then start = start.next end
- -- else
- -- start = start.next
- -- end
- -- else
- -- start = start.next
- -- end
- elseif id == whatsit_code then
- local subtype = start.subtype
- if subtype == dir_code then
- local dir = start.dir
- if dir == "+TRT" or dir == "+TLT" then
- insert(txtdir,dir)
- elseif dir == "-TRT" or dir == "-TLT" then
- remove(txtdir)
- end
- local d = txtdir[#txtdir]
- if d == "+TRT" then
- rlmode = -1
- elseif d == "+TLT" then
- rlmode = 1
- else
- rlmode = pardir
- end
- if trace_directions then
- report_process("directions after textdir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode)
- end
- elseif subtype == localpar_code then
- local dir = start.dir
- if dir == "TRT" then
- pardir = -1
- elseif dir == "TLT" then
- pardir = 1
- else
- pardir = 0
- end
- rlmode = pardir
- --~ txtdir = { }
- if trace_directions then
- report_process("directions after pardir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode)
- end
- end
- start = start.next
- else
- start = start.next
- end
- end
end
- end
- if success then
- done = true
- end
- if trace_steps then -- ?
- registerstep(head)
+ if success then
+ done = true
+ end
+ if trace_steps then -- ?
+ registerstep(head)
+ end
end
end
end
@@ -10110,55 +10933,59 @@ local function prepare_lookups(tfmdata)
local description = descriptions[unicode]
- local lookups = description.slookups
- if lookups then
- for lookupname, lookupdata in next, lookups do
- action[lookuptypes[lookupname]](lookupdata,lookupname,unicode,lookuphash)
+ if description then
+
+ local lookups = description.slookups
+ if lookups then
+ for lookupname, lookupdata in next, lookups do
+ action[lookuptypes[lookupname]](lookupdata,lookupname,unicode,lookuphash)
+ end
end
- end
- local lookups = description.mlookups
- if lookups then
- for lookupname, lookuplist in next, lookups do
- local lookuptype = lookuptypes[lookupname]
- for l=1,#lookuplist do
- local lookupdata = lookuplist[l]
- action[lookuptype](lookupdata,lookupname,unicode,lookuphash)
+ local lookups = description.mlookups
+ if lookups then
+ for lookupname, lookuplist in next, lookups do
+ local lookuptype = lookuptypes[lookupname]
+ for l=1,#lookuplist do
+ local lookupdata = lookuplist[l]
+ action[lookuptype](lookupdata,lookupname,unicode,lookuphash)
+ end
end
end
- end
- local list = description.kerns
- if list then
- for lookup, krn in next, list do -- ref to glyph, saves lookup
- local target = lookuphash[lookup]
- if target then
- target[unicode] = krn
- else
- lookuphash[lookup] = { [unicode] = krn }
+ local list = description.kerns
+ if list then
+ for lookup, krn in next, list do -- ref to glyph, saves lookup
+ local target = lookuphash[lookup]
+ if target then
+ target[unicode] = krn
+ else
+ lookuphash[lookup] = { [unicode] = krn }
+ end
end
end
- end
- local list = description.anchors
- if list then
- for typ, anchors in next, list do -- types
- if typ == "mark" or typ == "cexit" then -- or entry?
- for name, anchor in next, anchors do
- local lookups = anchor_to_lookup[name]
- if lookups then
- for lookup, _ in next, lookups do
- local target = lookuphash[lookup]
- if target then
- target[unicode] = anchors
- else
- lookuphash[lookup] = { [unicode] = anchors }
+ local list = description.anchors
+ if list then
+ for typ, anchors in next, list do -- types
+ if typ == "mark" or typ == "cexit" then -- or entry?
+ for name, anchor in next, anchors do
+ local lookups = anchor_to_lookup[name]
+ if lookups then
+ for lookup, _ in next, lookups do
+ local target = lookuphash[lookup]
+ if target then
+ target[unicode] = anchors
+ else
+ lookuphash[lookup] = { [unicode] = anchors }
+ end
end
end
end
end
end
end
+
end
end
@@ -10340,7 +11167,7 @@ end
--~ end
local valid = {
- coverage = { chainsub = true, chainpos = true },
+ coverage = { chainsub = true, chainpos = true, contextsub = true },
reversecoverage = { reversesub = true },
glyphs = { chainsub = true, chainpos = true },
}
@@ -11250,7 +12077,7 @@ registerotffeature {
methods.latn = analyzers.setstate
--- this info eventually will go into char-def adn we will have a state
+-- this info eventually will go into char-def and we will have a state
-- table for generic then
local zwnj = 0x200C
@@ -11280,6 +12107,12 @@ local isol_fina = {
[0x076C] = true, [0x0771] = true, [0x0773] = true, [0x0774] = true,
[0x0778] = true, [0x0779] = true, [0xFEF5] = true, [0xFEF7] = true,
[0xFEF9] = true, [0xFEFB] = true,
+
+ -- syriac
+
+ [0x0710] = true, [0x0715] = true, [0x0716] = true, [0x0717] = true,
+ [0x0718] = true, [0x0719] = true, [0x0728] = true, [0x072A] = true,
+ [0x072C] = true, [0x071E] = true,
}
local isol_fina_medi_init = {
@@ -11317,10 +12150,19 @@ local isol_fina_medi_init = {
[0x0772] = true, [0x0775] = true, [0x0776] = true, [0x0777] = true,
[0x077A] = true, [0x077B] = true, [0x077C] = true, [0x077D] = true,
[0x077E] = true, [0x077F] = true, [zwj] = true,
+
+ -- syriac
+
+ [0x0712] = true, [0x0713] = true, [0x0714] = true, [0x071A] = true,
+ [0x071B] = true, [0x071C] = true, [0x071D] = true, [0x071F] = true,
+ [0x0720] = true, [0x0721] = true, [0x0722] = true, [0x0723] = true,
+ [0x0725] = true, [0x0726] = true, [0x0727] = true, [0x0729] = true,
+ [0x072B] = true, [0x0724] = true, [0x0706] = true, [0x0707] = true,
}
local arab_warned = { }
+
-- todo: gref
local function warning(current,what)
@@ -11438,6 +12280,8 @@ function methods.arab(head,font,attr) -- maybe make a special version with no tr
return head, done
end
+methods.syrc = methods.arab
+
directives.register("otf.analyze.useunicodemarks",function(v)
analyzers.useunicodemarks = v
end)
@@ -11605,7 +12449,7 @@ function definers.registersplit(symbol,action,verbosename)
end
end
-function definers.makespecification(specification, lookup, name, sub, method, detail, size)
+function definers.makespecification(specification,lookup,name,sub,method,detail,size)
size = size or 655360
if trace_defining then
report_defining("%s -> lookup: %s, name: %s, sub: %s, method: %s, detail: %s",
@@ -11656,13 +12500,14 @@ end
function resolvers.name(specification)
local resolve = fonts.names.resolve
if resolve then
- local resolved, sub = fonts.names.resolve(specification.name,specification.sub)
- specification.resolved, specification.sub = resolved, sub
+ local resolved, sub = resolve(specification.name,specification.sub,specification) -- we pass specification for overloaded versions
if resolved then
+ specification.resolved = resolved
+ specification.sub = sub
local suffix = file.suffix(resolved)
if fonts.formats[suffix] then
specification.forced = suffix
- specification.name = file.removesuffix(resolved)
+ specification.name = file.removesuffix(resolved)
else
specification.name = resolved
end
@@ -11675,10 +12520,12 @@ end
function resolvers.spec(specification)
local resolvespec = fonts.names.resolvespec
if resolvespec then
- specification.resolved, specification.sub = fonts.names.resolvespec(specification.name,specification.sub)
- if specification.resolved then
- specification.forced = file.extname(specification.resolved)
- specification.name = file.removesuffix(specification.resolved)
+ local resolved, sub = resolvespec(specification.name,specification.sub,specification) -- we pass specification for overloaded versions
+ if resolved then
+ specification.resolved = resolved
+ specification.sub = sub
+ specification.forced = file.extname(resolved)
+ specification.name = file.removesuffix(resolved)
end
else
resolvers.name(specification)
@@ -11697,17 +12544,6 @@ function definers.resolve(specification)
else
specification.forced = specification.forced
end
- -- for the moment here (goodies set outside features)
- local goodies = specification.goodies
- if goodies and goodies ~= "" then
- local normal = specification.features.normal
- if not normal then
- specification.features.normal = { goodies = goodies }
- elseif not normal.goodies then
- normal.goodies = goodies
- end
- end
- --
specification.hash = lower(specification.name .. ' @ ' .. constructors.hashfeatures(specification))
if specification.sub and specification.sub ~= "" then
specification.hash = specification.sub .. ' @ ' .. specification.hash
@@ -11731,25 +12567,43 @@ features (esp in virtual fonts) so let's not do that now.</p>
specification yet.</p>
--ldx]]--
--- not in context, at least not now:
---
+-- very experimental:
+
+function definers.applypostprocessors(tfmdata)
+ local postprocessors = tfmdata.postprocessors
+ if postprocessors then
+ for i=1,#postprocessors do
+ local extrahash = postprocessors[i](tfmdata) -- after scaling etc
+ if type(extrahash) == "string" and extrahash ~= "" then
+ -- e.g. a reencoding needs this
+ extrahash = gsub(lower(extrahash),"[^a-z]","-")
+ tfmdata.properties.fullname = format("%s-%s",tfmdata.properties.fullname,extrahash)
+ end
+ end
+ end
+ return tfmdata
+end
+
-- function definers.applypostprocessors(tfmdata)
--- local postprocessors = tfmdata.postprocessors
--- if postprocessors then
--- for i=1,#postprocessors do
--- local extrahash = postprocessors[i](tfmdata) -- after scaling etc
--- if type(extrahash) == "string" and extrahash ~= "" then
--- -- e.g. a reencoding needs this
--- extrahash = gsub(lower(extrahash),"[^a-z]","-")
--- tfmdata.properties.fullname = format("%s-%s",tfmdata.properties.fullname,extrahash)
--- end
--- end
--- end
-- return tfmdata
-- end
-function definers.applypostprocessors(tfmdata)
- return tfmdata
+local function checkembedding(tfmdata)
+ local properties = tfmdata.properties
+ local embedding
+ if directive_embedall then
+ embedding = "full"
+ elseif properties and properties.filename and constructors.dontembed[properties.filename] then
+ embedding = "no"
+ else
+ embedding = "subset"
+ end
+ if properties then
+ properties.embedding = embedding
+ else
+ tfmdata.properties = { embedding = embedding }
+ end
+ tfmdata.embedding = embedding
end
function definers.loadfont(specification)
@@ -11781,21 +12635,8 @@ function definers.loadfont(specification)
end
end
if tfmdata then
- local properties = tfmdata.properties
- local embedding
- if directive_embedall then
- embedding = "full"
- elseif properties.filename and constructors.dontembed[properties.filename] then
- embedding = "no"
- else
- embedding = "subset"
- end
- if properties then
- properties.embedding = embedding
- else
- tfmdata.properties = { embedding = embedding }
- end
tfmdata = definers.applypostprocessors(tfmdata)
+ checkembedding(tfmdata) -- todo: general postprocessor
loadedfonts[hash] = tfmdata
designsizes[specification.hash] = tfmdata.parameters.designsize
end
@@ -11881,14 +12722,25 @@ function definers.read(specification,size,id) -- id can be optional, name can al
specification = definers.resolve(specification)
local hash = constructors.hashinstance(specification)
local tfmdata = definers.registered(hash) -- id
- if not tfmdata then
+ if tfmdata then
+ if trace_defining then
+ report_defining("already hashed: %s",hash)
+ end
+ else
tfmdata = definers.loadfont(specification) -- can be overloaded
if tfmdata then
---~ constructors.checkvirtualid(tfmdata) -- interferes
+ if trace_defining then
+ report_defining("loaded and hashed: %s",hash)
+ end
+ --~ constructors.checkvirtualid(tfmdata) -- interferes
tfmdata.properties.hash = hash
if id then
definers.register(tfmdata,id)
end
+ else
+ if trace_defining then
+ report_defining("not loaded and hashed: %s",hash)
+ end
end
end
lastdefined = tfmdata or id -- todo ! ! ! ! !
@@ -11898,7 +12750,7 @@ function definers.read(specification,size,id) -- id can be optional, name can al
local properties = tfmdata.properties or { }
local parameters = tfmdata.parameters or { }
report_defining("using %s font with id %s, name:%s size:%s bytes:%s encoding:%s fullname:%s filename:%s",
- properties.type or "unknown",
+ properties.format or "unknown",
id or "?",
properties.name or "?",
parameters.size or "default",
@@ -12054,7 +12906,7 @@ local function initializeitlc(tfmdata,value)
d.italic = it
end
end
- tfmdata.properties.italic_correction = true
+ tfmdata.properties.hasitalics = true
end
end
end
@@ -12079,7 +12931,7 @@ local function initializeslant(tfmdata,value)
elseif value < -1 then
value = -1
end
- tfmdata.parameters.slant_factor = value
+ tfmdata.parameters.slantfactor = value
end
otffeatures.register {
@@ -12100,7 +12952,7 @@ local function initializeextend(tfmdata,value)
elseif value < -10 then
value = -10
end
- tfmdata.parameters.extend_factor = value
+ tfmdata.parameters.extendfactor = value
end
otffeatures.register {
diff --git a/Master/texmf-dist/tex/generic/context/luatex-fonts-syn.lua b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-syn.lua
index 36a74d0f497..36a74d0f497 100644
--- a/Master/texmf-dist/tex/generic/context/luatex-fonts-syn.lua
+++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-syn.lua
diff --git a/Master/texmf-dist/tex/generic/context/luatex-fonts-tfm.lua b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-tfm.lua
index b9bb1bd0f28..b9bb1bd0f28 100644
--- a/Master/texmf-dist/tex/generic/context/luatex-fonts-tfm.lua
+++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-tfm.lua
diff --git a/Master/texmf-dist/tex/generic/context/luatex-fonts.lua b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts.lua
index 23d33f26b8f..f5045a4e32a 100644
--- a/Master/texmf-dist/tex/generic/context/luatex-fonts.lua
+++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts.lua
@@ -7,9 +7,20 @@ if not modules then modules = { } end modules ['luatex-fonts'] = {
}
-- The following code isolates the generic ConTeXt code from already
--- defined or to be defined namespaces.
-
--- todo: all global namespaces in called modules will get local shortcuts
+-- defined or to be defined namespaces. This is the reference loader
+-- for plain, but the generic code is also used in luaotfload (which
+-- is is a file meant for latex) and that is maintained by Khaled
+-- Hosny. We do our best to keep the interface as clean as possible.
+--
+-- The code base is rather stable now, especially if you stay away from
+-- the non generic code. All relevant data is organized in tables within
+-- the main table of a font instance. There are a few places where in
+-- context other code is plugged in, but this does not affect the core
+-- code. Users can (given that their macro package provides this option)
+-- access the font data (characters, descriptions, properties, parameters,
+-- etc) of this main table.
+--
+-- Todo: all global namespaces in called modules will get local shortcuts.
utf = unicode.utf8
@@ -122,10 +133,10 @@ else
-- version 1.0 there will be an official api defined.
loadmodule('l-string.lua')
+ loadmodule('l-table.lua')
loadmodule('l-lpeg.lua')
loadmodule('l-boolean.lua')
loadmodule('l-math.lua')
- loadmodule('l-table.lua')
loadmodule('l-file.lua')
loadmodule('l-io.lua')
diff --git a/Master/texmf-dist/tex/generic/context/luatex-fonts.tex b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts.tex
index 8ccc9f3d566..a7c8bc2b8fd 100644
--- a/Master/texmf-dist/tex/generic/context/luatex-fonts.tex
+++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts.tex
@@ -4,7 +4,7 @@
%D title=\LUATEX\ Support Macros,
%D subtitle=Generic \OPENTYPE\ Font Handler,
%D author=Hans Hagen,
-%D copyright=see context related readme files]
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
%D \subject{Welcome}
%D
diff --git a/Master/texmf-dist/tex/generic/context/luatex-mplib.lua b/Master/texmf-dist/tex/generic/context/luatex/luatex-mplib.lua
index c6628acb3b8..c6628acb3b8 100644
--- a/Master/texmf-dist/tex/generic/context/luatex-mplib.lua
+++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-mplib.lua
diff --git a/Master/texmf-dist/tex/generic/context/luatex-mplib.tex b/Master/texmf-dist/tex/generic/context/luatex/luatex-mplib.tex
index 69195864670..ef6dfff958b 100644
--- a/Master/texmf-dist/tex/generic/context/luatex-mplib.tex
+++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-mplib.tex
@@ -4,7 +4,7 @@
%D title=\LUATEX\ Support Macros,
%D subtitle=\METAPOST\ to \PDF\ conversion,
%D author=Taco Hoekwater \& Hans Hagen,
-%D copyright=see context related readme files]
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
%D This is the companion to the \LUA\ module \type {supp-mpl.lua}. Further
%D embedding is up to others. A simple example of usage in plain \TEX\ is:
diff --git a/Master/texmf-dist/tex/generic/context/luatex/luatex-plain.tex b/Master/texmf-dist/tex/generic/context/luatex/luatex-plain.tex
new file mode 100644
index 00000000000..e47ad58ad9a
--- /dev/null
+++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-plain.tex
@@ -0,0 +1,25 @@
+%D \module
+%D [ file=luatex-plain,
+%D version=2009.12.01,
+%D title=\LUATEX\ Macros,
+%D subtitle=Plain Format,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+
+\input plain
+
+\directlua {tex.enableprimitives('', tex.extraprimitives())}
+
+\pdfoutput=1
+
+\everyjob \expandafter {%
+ \the\everyjob
+ \input luatex-basics\relax
+ \input luatex-fonts\relax
+ \input luatex-mplib\relax
+}
+
+\edef\fmtversion{\fmtversion+luatex}
+
+\dump
diff --git a/Master/texmf-dist/tex/generic/context/luatex-preprocessor-test.tex b/Master/texmf-dist/tex/generic/context/luatex/luatex-preprocessor-test.tex
index 857b28f831b..857b28f831b 100644
--- a/Master/texmf-dist/tex/generic/context/luatex-preprocessor-test.tex
+++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-preprocessor-test.tex
diff --git a/Master/texmf-dist/tex/generic/context/luatex-preprocessor.lua b/Master/texmf-dist/tex/generic/context/luatex/luatex-preprocessor.lua
index 8faa0b47e69..8faa0b47e69 100644
--- a/Master/texmf-dist/tex/generic/context/luatex-preprocessor.lua
+++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-preprocessor.lua
diff --git a/Master/texmf-dist/tex/generic/context/luatex-preprocessor.tex b/Master/texmf-dist/tex/generic/context/luatex/luatex-preprocessor.tex
index fe4872d6101..03b483f4185 100644
--- a/Master/texmf-dist/tex/generic/context/luatex-preprocessor.tex
+++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-preprocessor.tex
@@ -4,7 +4,7 @@
%D title=\LUATEX\ Support Macros,
%D subtitle=Generic Preprocessor,
%D author=Hans Hagen,
-%D copyright=public domain]
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
\directlua{dofile(kpse.find_file('luatex-preprocessor.lua'))}
diff --git a/Master/texmf-dist/tex/generic/context/luatex-test.tex b/Master/texmf-dist/tex/generic/context/luatex/luatex-test.tex
index 1c3aeb1b689..3020b5594cc 100644
--- a/Master/texmf-dist/tex/generic/context/luatex-test.tex
+++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-test.tex
@@ -5,13 +5,15 @@
%D subtitle=Simple Test File,
%D author=Hans Hagen,
%D date=\currentdate,
-%D copyright=public domain]
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
%D See \type {luatex-plain.tex} (or on my machine \type {luatex.tex}
%D for how to make a format.
\pdfoutput=1
+% \directlua{generic_context.caches.compilemethod = "both" } % none luac dump both
+
\font\testa=file:lmroman10-regular at 12pt \testa \input tufte \par
\font\testb=file:lmroman12-regular:+liga; at 24pt \testb effe flink fietsen \par
\font\testc=file:lmroman12-regular:mode=node;+liga; at 24pt \testc effe flink fietsen \par
diff --git a/Master/texmf-dist/tex/generic/context/m-metapo.tex b/Master/texmf-dist/tex/generic/context/m-metapo.tex
deleted file mode 100644
index 8680f69c6b2..00000000000
--- a/Master/texmf-dist/tex/generic/context/m-metapo.tex
+++ /dev/null
@@ -1,89 +0,0 @@
-%D \module
-%D [ file=m-metapo,
-%D version=1999.03.26,
-%D title=\LATEX\ Modules,
-%D subtitle=\METAPOST\ Inclusion,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ distribution and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-%D We quit when \CONTEXT\ is found and use some deep down
-%D macro to trigger this:
-
-\ifx\undefined\dodoplaceexternalfigure \else \expandafter \endinput \fi
-
-%D \macros
-%D {includeMPgraphics}
-%D
-%D This rather small \LATEX\ module is dedicated to David
-%D Arnold. It takes care of including the fonts used in
-%D \METAPOST\ graphics in the file. This hack is needed when
-%D one uses another \DVI\ driver than \DVIPS. This module
-%D falls back on the generic \CONTEXT\ support module:
-
-\ifx\undefined\includeMPfonts \input supp-mps.tex \relax \fi
-
-%D Instead of using \type {\includegraphics}, one should use its
-%D little brother \type {\includeMPgraphics}. This macro takes
-%D the same arguments.
-
-\def\includeMPgraphics#1#%
- {\leavevmode\vbox\bgroup\hbox\bgroup
- \def\includeMPgraphics##1%
- {\includeMPfonts{##1}%
- \includegraphics#1{##1}%
- \egroup\egroup}%
- \includeMPgraphics}
-
-%D An example of using this module is given below:
-%D
-%D \starttyping
-%D \documentclass[10pt]{article}
-%D
-%D \usepackage{graphicx}
-%D \usepackage{m-metapo}
-%D
-%D \begin{document}
-%D \includeMPgraphics{somefile.1}
-%D \includeMPgraphics[angle=90]{somefile.2}
-%D \end{document}
-%D \stoptyping
-%D
-%D This module needs \type {supp-mps} and \type {supp-mis},
-%D that both are present in the \CONTEXT\ path.
-%D
-%D Please do not forget to say \type {prologues:=1} at the
-%D top of the metapost file!
-%D
-%D For non \LATEX\ (and \CONTEXT) users we provide an
-%D alternative inclusion macro. This one has no optional
-%D arguments.
-
-\ifx\includegraphics\undefined
-
- \ifx\undefined\dogetEPSboundingbox \input supp-eps.tex \relax \fi
-
- \def\includeMPgraphics#1%
- {\hbox\bgroup
- \includeMPfonts{#1}%
- \dogetEPSboundingbox{#1}{\dimen2}{\dimen4}{\dimen6}{\dimen8}%
- \vbox to \dimen8
- {\forgetall
- \hsize\dimen6
- \vfill
- \hbox to \hsize
- {\special
- {PSfile="#1"\space
- llx=\EPSllx\space
- lly=\EPSlly\space
- urx=\EPSurx\space
- ury=\EPSury\space}}}%
- \egroup}
-
-\fi
-
-\endinput
diff --git a/Master/texmf-dist/tex/generic/context/mptopdf.tex b/Master/texmf-dist/tex/generic/context/mptopdf/mptopdf.tex
index a0ac34a42b3..3efe573924a 100644
--- a/Master/texmf-dist/tex/generic/context/mptopdf.tex
+++ b/Master/texmf-dist/tex/generic/context/mptopdf/mptopdf.tex
@@ -5,7 +5,7 @@
%D subtitle=conversion to \PDF,
%D author=Hans Hagen,
%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
diff --git a/Master/texmf-dist/tex/generic/context/m-ch-de.tex b/Master/texmf-dist/tex/generic/context/ppchtex/m-ch-de.tex
index 467cdc67044..467cdc67044 100644
--- a/Master/texmf-dist/tex/generic/context/m-ch-de.tex
+++ b/Master/texmf-dist/tex/generic/context/ppchtex/m-ch-de.tex
diff --git a/Master/texmf-dist/tex/generic/context/m-ch-en.tex b/Master/texmf-dist/tex/generic/context/ppchtex/m-ch-en.tex
index 6bd4353199b..6bd4353199b 100644
--- a/Master/texmf-dist/tex/generic/context/m-ch-en.tex
+++ b/Master/texmf-dist/tex/generic/context/ppchtex/m-ch-en.tex
diff --git a/Master/texmf-dist/tex/generic/context/m-ch-nl.tex b/Master/texmf-dist/tex/generic/context/ppchtex/m-ch-nl.tex
index c9d77733ac5..c9d77733ac5 100644
--- a/Master/texmf-dist/tex/generic/context/m-ch-nl.tex
+++ b/Master/texmf-dist/tex/generic/context/ppchtex/m-ch-nl.tex
diff --git a/Master/texmf-dist/tex/generic/context/ppchtex.noc b/Master/texmf-dist/tex/generic/context/ppchtex/ppchtex.noc
index 99d073255cb..99d073255cb 100644
--- a/Master/texmf-dist/tex/generic/context/ppchtex.noc
+++ b/Master/texmf-dist/tex/generic/context/ppchtex/ppchtex.noc