summaryrefslogtreecommitdiff
path: root/tex/generic
diff options
context:
space:
mode:
authorMarius <mariausol@gmail.com>2012-10-19 01:20:13 +0300
committerMarius <mariausol@gmail.com>2012-10-19 01:20:13 +0300
commit69d2352af4b60929b37fc49f3bdb263977016244 (patch)
treedb5eb11398e345dfa23b4c4500fb93575d2afb7c /tex/generic
parentc18f7cbe51449a611ea1819fedd9a4ff18529b7d (diff)
downloadcontext-69d2352af4b60929b37fc49f3bdb263977016244.tar.gz
stable 2012.05.30 11:26
Diffstat (limited to 'tex/generic')
-rw-r--r--tex/generic/context/luatex/luatex-basics-gen.lua4
-rw-r--r--tex/generic/context/luatex/luatex-fonts-ext.lua16
-rw-r--r--tex/generic/context/luatex/luatex-fonts-merged.lua1892
-rw-r--r--tex/generic/context/luatex/luatex-fonts.lua2
-rw-r--r--tex/generic/context/luatex/luatex-mplib.tex11
5 files changed, 772 insertions, 1153 deletions
diff --git a/tex/generic/context/luatex/luatex-basics-gen.lua b/tex/generic/context/luatex/luatex-basics-gen.lua
index 2f03efba8..bdbc3cf51 100644
--- a/tex/generic/context/luatex/luatex-basics-gen.lua
+++ b/tex/generic/context/luatex/luatex-basics-gen.lua
@@ -87,7 +87,7 @@ local remapper = {
function resolvers.findfile(name,fileformat)
name = string.gsub(name,"\\","\/")
fileformat = fileformat and string.lower(fileformat)
- local found = kpse.find_file(name,(fileformat and fileformat ~= "" and (remapper[fileformat] or fileformat)) or file.suffix(name,"tex"))
+ local found = kpse.find_file(name,(fileformat and fileformat ~= "" and (remapper[fileformat] or fileformat)) or file.extname(name,"tex"))
if not found or found == "" then
found = kpse.find_file(name,"other text files")
end
@@ -96,7 +96,7 @@ end
function resolvers.findbinfile(name,fileformat)
if not fileformat or fileformat == "" then
- fileformat = file.suffix(name) -- string.match(name,"%.([^%.]-)$")
+ fileformat = file.extname(name) -- string.match(name,"%.([^%.]-)$")
end
return resolvers.findfile(name,(fileformat and remapper[fileformat]) or fileformat)
end
diff --git a/tex/generic/context/luatex/luatex-fonts-ext.lua b/tex/generic/context/luatex/luatex-fonts-ext.lua
index b60d04512..d8884ccc7 100644
--- a/tex/generic/context/luatex/luatex-fonts-ext.lua
+++ b/tex/generic/context/luatex/luatex-fonts-ext.lua
@@ -18,14 +18,18 @@ local otffeatures = fonts.constructors.newfeatures("otf")
local function initializeitlc(tfmdata,value)
if value then
- -- the magic 40 and it formula come from Dohyun Kim but we might need another guess
- local parameters = tfmdata.parameters
+ -- the magic 40 and it formula come from Dohyun Kim
+ local parameters = tfmdata.parameters
local italicangle = parameters.italicangle
if italicangle and italicangle ~= 0 then
- local properties = tfmdata.properties
- local factor = tonumber(value) or 1
- properties.hasitalics = true
- properties.autoitalicamount = factor * (parameters.uwidth or 40)/2
+ local uwidth = (parameters.uwidth or 40)/2
+ for unicode, d in next, tfmdata.descriptions do
+ local it = d.boundingbox[3] - d.width + uwidth
+ if it ~= 0 then
+ d.italic = it
+ end
+ end
+ tfmdata.properties.hasitalics = true
end
end
end
diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua
index 1d14a9990..ea509c338 100644
--- a/tex/generic/context/luatex/luatex-fonts-merged.lua
+++ b/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 : 10/17/12 22:49:16
+-- merge date : 05/30/12 11:26:34
do -- begin closure to overcome local limits and interference
@@ -118,28 +118,11 @@ function string.topattern(str,lowercase,strict)
end
end
-
-function string.valid(str,default)
- return (type(str) == "string" and str ~= "" and str) or default or nil
-end
-
-- obsolete names:
string.quote = string.quoted
string.unquote = string.unquoted
--- handy fallback
-
-string.itself = function(s) return s end
-
--- also handy (see utf variant)
-
-local pattern = Ct(C(1)^0)
-
-function string.totable(str)
- return lpegmatch(pattern,str)
-end
-
end -- closure
do -- begin closure to overcome local limits and interference
@@ -152,8 +135,7 @@ if not modules then modules = { } end modules ['l-table'] = {
license = "see context related readme files"
}
-local type, next, tostring, tonumber, ipairs = type, next, tostring, tonumber, ipairs
-local table, string = table, string
+local type, next, tostring, tonumber, ipairs, table, string = type, next, tostring, tonumber, ipairs, table, string
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
@@ -164,8 +146,6 @@ local getinfo = debug.getinfo
-- impact on ConTeXt was not that large; the remaining ipairs already
-- have been replaced. In a similar fashion we also hardly used pairs.
--
--- Hm, actually ipairs was retained, but we no longer use it anyway.
---
-- Just in case, we provide the fallbacks as discussed in Programming
-- in Lua (http://www.lua.org/pil/7.3.html):
@@ -225,16 +205,12 @@ function table.strip(tab)
end
function table.keys(t)
- if t then
- local keys, k = { }, 0
- for key, _ in next, t do
- k = k + 1
- keys[k] = key
- end
- return keys
- else
- return { }
+ local keys, k = { }, 0
+ for key, _ in next, t do
+ k = k + 1
+ keys[k] = key
end
+ return keys
end
local function compare(a,b)
@@ -247,49 +223,41 @@ local function compare(a,b)
end
local function sortedkeys(tab)
- if tab then
- local srt, category, s = { }, 0, 0 -- 0=unknown 1=string, 2=number 3=mixed
- for key,_ in next, tab do
- s = s + 1
- srt[s] = key
- if category == 3 then
- -- no further check
+ local srt, category, s = { }, 0, 0 -- 0=unknown 1=string, 2=number 3=mixed
+ for key,_ in next, tab do
+ s = s + 1
+ srt[s] = key
+ if category == 3 then
+ -- no further check
+ else
+ local tkey = type(key)
+ if tkey == "string" then
+ category = (category == 2 and 3) or 1
+ elseif tkey == "number" then
+ category = (category == 1 and 3) or 2
else
- local tkey = type(key)
- if tkey == "string" then
- category = (category == 2 and 3) or 1
- elseif tkey == "number" then
- category = (category == 1 and 3) or 2
- else
- category = 3
- end
+ category = 3
end
end
- if category == 0 or category == 3 then
- sort(srt,compare)
- else
- sort(srt)
- end
- return srt
+ end
+ if category == 0 or category == 3 then
+ sort(srt,compare)
else
- return { }
+ sort(srt)
end
+ return srt
end
local function sortedhashkeys(tab) -- fast one
- if tab then
- local srt, s = { }, 0
- for key,_ in next, tab do
- if key then
- s= s + 1
- srt[s] = key
- end
+ local srt, s = { }, 0
+ for key,_ in next, tab do
+ if key then
+ s= s + 1
+ srt[s] = key
end
- sort(srt)
- return srt
- else
- return { }
end
+ sort(srt)
+ return srt
end
table.sortedkeys = sortedkeys
@@ -314,7 +282,7 @@ end
table.sortedhash = sortedhash
table.sortedpairs = sortedhash
-function table.append(t,list)
+function table.append(t, list)
local n = #t
for i=1,#list do
n = n + 1
@@ -549,26 +517,12 @@ local function do_serialize(root,name,depth,level,indexed)
end
-- we could check for k (index) being number (cardinal)
if root and next(root) then
- -- local first, last = nil, 0 -- #root cannot be trusted here (will be ok in 5.2 when ipairs is gone)
- -- if compact then
- -- -- NOT: for k=1,#root do (we need to quit at nil)
- -- for k,v in ipairs(root) do -- can we use next?
- -- if not first then first = k end
- -- last = last + 1
- -- end
- -- end
- local first, last = nil, 0
+ local first, last = nil, 0 -- #root cannot be trusted here (will be ok in 5.2 when ipairs is gone)
if compact then
- last = #root
- for k=1,last do
--- if not root[k] then
- if root[k] == nil then
- last = k - 1
- break
- end
- end
- if last > 0 then
- first = 1
+ -- NOT: for k=1,#root do (we need to quit at nil)
+ for k,v in ipairs(root) do -- can we use next?
+ if not first then first = k end
+ last = last + 1
end
end
local sk = sortedkeys(root)
@@ -1060,27 +1014,23 @@ function table.reversed(t)
end
end
-function table.sequenced(t,sep) -- hash only
- if t then
- local s, n = { }, 0
- for k, v in sortedhash(t) do
- if simple then
- if v == true then
- n = n + 1
- s[n] = k
- elseif v and v~= "" then
- n = n + 1
- s[n] = k .. "=" .. tostring(v)
- end
- else
+function table.sequenced(t,sep,simple) -- hash only
+ local s, n = { }, 0
+ for k, v in sortedhash(t) do
+ if simple then
+ if v == true then
+ n = n + 1
+ s[n] = k
+ elseif v and v~= "" then
n = n + 1
s[n] = k .. "=" .. tostring(v)
end
+ else
+ n = n + 1
+ s[n] = k .. "=" .. tostring(v)
end
- return concat(s, sep or " | ")
- else
- return ""
end
+ return concat(s, sep or " | ")
end
function table.print(t,...)
@@ -1160,8 +1110,6 @@ local lpeg = require("lpeg")
-- tracing (only used when we encounter a problem in integration of lpeg in luatex)
--- some code will move to unicode and string
-
local report = texio and texio.write_nl or print
-- local lpmatch = lpeg.match
@@ -1198,8 +1146,8 @@ local report = texio and texio.write_nl or print
-- 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, next = type, next
-local byte, char, gmatch, format = string.byte, string.char, string.gmatch, string.format
+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.
@@ -1207,8 +1155,9 @@ local byte, char, gmatch, format = string.byte, string.char, string.gmatch, stri
lpeg.patterns = lpeg.patterns or { } -- so that we can share
local patterns = lpeg.patterns
-local P, R, S, V, Ct, C, Cs, Cc, Cp = lpeg.P, lpeg.R, lpeg.S, lpeg.V, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc, lpeg.Cp
-local lpegtype, lpegmatch = lpeg.type, lpeg.match
+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
@@ -1259,10 +1208,6 @@ patterns.utf8char = utf8char
patterns.validutf8 = validutf8char
patterns.validutf8char = validutf8char
-local eol = S("\n\r")
-local spacer = S(" \t\f\v") -- + char(0xc2, 0xa0) if we want utf (cf mail roberto)
-local whitespace = eol + spacer
-
patterns.digit = digit
patterns.sign = sign
patterns.cardinal = sign^0 * digit^1
@@ -1282,16 +1227,16 @@ patterns.letter = patterns.lowercase + patterns.uppercase
patterns.space = space
patterns.tab = P("\t")
patterns.spaceortab = patterns.space + patterns.tab
-patterns.eol = eol
-patterns.spacer = spacer
-patterns.whitespace = whitespace
+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 - spacer
-patterns.nonwhitespace = 1 - whitespace
+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(",") * spacer^0
+patterns.commaspacer = P(",") * patterns.spacer^0
patterns.period = P(".")
patterns.colon = P(":")
patterns.semicolon = P(";")
@@ -1306,10 +1251,6 @@ patterns.undouble = (dquote/"") * patterns.nodquote * (dquote/"")
patterns.unquoted = patterns.undouble + patterns.unsingle -- more often undouble
patterns.unspacer = ((patterns.spacer^1)/"")^0
-patterns.singlequoted = squote * patterns.nosquote * squote
-patterns.doublequoted = dquote * patterns.nodquote * dquote
-patterns.quoted = patterns.doublequoted + patterns.singlequoted
-
patterns.somecontent = (anything - newline - space)^1 -- (utf8char - newline - space)^1
patterns.beginline = #(1-newline)
@@ -1320,17 +1261,8 @@ patterns.beginline = #(1-newline)
-- print(string.unquoted('"test"'))
-- print(string.unquoted('"test"'))
-local function anywhere(pattern) --slightly adapted from website
- return P { P(pattern) + 1 * V(1) }
-end
-
-lpeg.anywhere = anywhere
-
-function lpeg.instringchecker(p)
- p = anywhere(p)
- return function(str)
- return lpegmatch(p,str) and true or false
- end
+function lpeg.anywhere(pattern) --slightly adapted from website
+ return P { P(pattern) + 1 * V(1) } -- why so complex?
end
function lpeg.splitter(pattern, action)
@@ -1379,13 +1311,13 @@ function string.splitup(str,separator)
if not separator then
separator = ","
end
- return lpegmatch(splitters_m[separator] or splitat(separator),str)
+ return match(splitters_m[separator] or splitat(separator),str)
end
---~ local p = splitat("->",false) print(lpegmatch(p,"oeps->what->more")) -- oeps what more
---~ local p = splitat("->",true) print(lpegmatch(p,"oeps->what->more")) -- oeps what->more
---~ local p = splitat("->",false) print(lpegmatch(p,"oeps")) -- oeps
---~ local p = splitat("->",true) print(lpegmatch(p,"oeps")) -- oeps
+--~ 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 = { }
@@ -1395,20 +1327,16 @@ function lpeg.split(separator,str)
c = tsplitat(separator)
cache[separator] = c
end
- return lpegmatch(c,str)
+ return match(c,str)
end
function string.split(str,separator)
- if separator then
- local c = cache[separator]
- if not c then
- c = tsplitat(separator)
- cache[separator] = c
- end
- return lpegmatch(c,str)
- else
- return { str }
+ 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
@@ -1421,7 +1349,7 @@ patterns.textline = content
--~ local linesplitter = Ct(content^0)
--~
--~ function string.splitlines(str)
---~ return lpegmatch(linesplitter,str)
+--~ return match(linesplitter,str)
--~ end
local linesplitter = tsplitat(newline)
@@ -1429,7 +1357,7 @@ local linesplitter = tsplitat(newline)
patterns.linesplitter = linesplitter
function string.splitlines(str)
- return lpegmatch(linesplitter,str)
+ return match(linesplitter,str)
end
local utflinesplitter = utfbom^-1 * tsplitat(newline)
@@ -1437,58 +1365,7 @@ local utflinesplitter = utfbom^-1 * tsplitat(newline)
patterns.utflinesplitter = utflinesplitter
function string.utfsplitlines(str)
- return lpegmatch(utflinesplitter,str or "")
-end
-
-local utfcharsplitter_ows = utfbom^-1 * Ct(C(utf8char)^0)
-local utfcharsplitter_iws = utfbom^-1 * Ct((whitespace^1 + C(utf8char))^0)
-
-function string.utfsplit(str,ignorewhitespace) -- new
- if ignorewhitespace then
- return lpegmatch(utfcharsplitter_iws,str or "")
- else
- return lpegmatch(utfcharsplitter_ows,str or "")
- end
-end
-
--- inspect(string.utfsplit("a b c d"))
--- inspect(string.utfsplit("a b c d",true))
-
--- -- alternative 1: 0.77
---
--- local utfcharcounter = utfbom^-1 * Cs((utf8char/'!')^0)
---
--- function string.utflength(str)
--- return #lpegmatch(utfcharcounter,str or "")
--- end
---
--- -- alternative 2: 1.70
---
--- local n = 0
---
--- local utfcharcounter = utfbom^-1 * (utf8char/function() n = n + 1 end)^0 -- slow
---
--- function string.utflength(str)
--- n = 0
--- lpegmatch(utfcharcounter,str or "")
--- return n
--- end
---
--- -- alternative 3: 0.24 (native unicode.utf8.len: 0.047)
-
-local n = 0
-
-local utfcharcounter = utfbom^-1 * Cs ( (
- Cp() * (lpeg.patterns.utf8one )^1 * Cp() / function(f,t) n = n + t - f end
- + Cp() * (lpeg.patterns.utf8two )^1 * Cp() / function(f,t) n = n + (t - f)/2 end
- + Cp() * (lpeg.patterns.utf8three)^1 * Cp() / function(f,t) n = n + (t - f)/3 end
- + Cp() * (lpeg.patterns.utf8four )^1 * Cp() / function(f,t) n = n + (t - f)/4 end
-)^0 )
-
-function string.utflength(str)
- n = 0
- lpegmatch(utfcharcounter,str or "")
- return n
+ return match(utflinesplitter,str or "")
end
--~ lpeg.splitters = cache -- no longer public
@@ -1503,7 +1380,7 @@ function lpeg.checkedsplit(separator,str)
c = Ct(separator^0 * other * (separator^1 * other)^0)
cache[separator] = c
end
- return lpegmatch(c,str)
+ return match(c,str)
end
function string.checkedsplit(str,separator)
@@ -1514,7 +1391,7 @@ function string.checkedsplit(str,separator)
c = Ct(separator^0 * other * (separator^1 * other)^0)
cache[separator] = c
end
- return lpegmatch(c,str)
+ return match(c,str)
end
--~ from roberto's site:
@@ -1529,10 +1406,10 @@ patterns.utf8byte = utf8byte
--~ local str = " a b c d "
---~ local s = lpeg.stripper(lpeg.R("az")) print("["..lpegmatch(s,str).."]")
---~ local s = lpeg.keeper(lpeg.R("az")) print("["..lpegmatch(s,str).."]")
---~ local s = lpeg.stripper("ab") print("["..lpegmatch(s,str).."]")
---~ local s = lpeg.keeper("ab") print("["..lpegmatch(s,str).."]")
+--~ 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 = { }
@@ -1565,11 +1442,11 @@ function lpeg.keeper(str)
end
function lpeg.frontstripper(str) -- or pattern (yet undocumented)
- return (P(str) + P(true)) * Cs(anything^0)
+ return (P(str) + P(true)) * Cs(P(1)^0)
end
function lpeg.endstripper(str) -- or pattern (yet undocumented)
- return Cs((1 - P(str) * endofstring)^0)
+ return Cs((1 - P(str) * P(-1))^0)
end
-- Just for fun I looked at the used bytecode and
@@ -1578,22 +1455,8 @@ end
function lpeg.replacer(one,two)
if type(one) == "table" then
local no = #one
- local p
- if no == 0 then
- for k, v in next, one do
- local pp = P(k) / v
- if p then
- p = p + pp
- else
- p = pp
- end
- end
- return Cs((p + 1)^0)
- elseif no == 1 then
- local o = one[1]
- one, two = P(o[1]), o[2]
- return Cs(((1-one)^1 + one/two)^0)
- else
+ if no > 0 then
+ local p
for i=1,no do
local o = one[i]
local pp = P(o[1]) / o[2]
@@ -1606,16 +1469,11 @@ function lpeg.replacer(one,two)
return Cs((p + 1)^0)
end
else
- one = P(one)
two = two or ""
- return Cs(((1-one)^1 + one/two)^0)
+ return Cs((P(one)/two + 1)^0)
end
end
--- print(lpeg.match(lpeg.replacer("e","a"),"test test"))
--- print(lpeg.match(lpeg.replacer{{"e","a"}},"test test"))
--- print(lpeg.match(lpeg.replacer({ e = "a", t = "x" }),"test test"))
-
local splitters_f, splitters_s = { }, { }
function lpeg.firstofsplit(separator) -- always return value
@@ -1643,14 +1501,14 @@ function lpeg.balancer(left,right)
return P { left * ((1 - left - right) + V(1))^0 * right }
end
---~ print(1,lpegmatch(lpeg.firstofsplit(":"),"bc:de"))
---~ print(2,lpegmatch(lpeg.firstofsplit(":"),":de")) -- empty
---~ print(3,lpegmatch(lpeg.firstofsplit(":"),"bc"))
---~ print(4,lpegmatch(lpeg.secondofsplit(":"),"bc:de"))
---~ print(5,lpegmatch(lpeg.secondofsplit(":"),"bc:")) -- empty
---~ print(6,lpegmatch(lpeg.secondofsplit(":",""),"bc"))
---~ print(7,lpegmatch(lpeg.secondofsplit(":"),"bc"))
---~ print(9,lpegmatch(lpeg.secondofsplit(":","123"),"bc"))
+--~ 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:
--~
@@ -1664,7 +1522,7 @@ local nany = utf8char/""
function lpeg.counter(pattern)
pattern = Cs((P(pattern)/" " + nany)^0)
return function(str)
- return #lpegmatch(pattern,str)
+ return #match(pattern,str)
end
end
@@ -1678,7 +1536,7 @@ if utfgmatch then
end
return n
else -- 4 times slower but still faster than / function
- return #lpegmatch(Cs((P(what)/" " + nany)^0),str)
+ return #match(Cs((P(what)/" " + nany)^0),str)
end
end
@@ -1693,9 +1551,9 @@ else
p = Cs((P(what)/" " + nany)^0)
cache[p] = p
end
- return #lpegmatch(p,str)
+ return #match(p,str)
else -- 4 times slower but still faster than / function
- return #lpegmatch(Cs((P(what)/" " + nany)^0),str)
+ return #match(Cs((P(what)/" " + nany)^0),str)
end
end
@@ -1722,7 +1580,7 @@ local p = Cs((S("-.+*%()[]") / patterns_escapes + anything)^0)
local s = Cs((S("-.+*%()[]") / simple_escapes + anything)^0)
function string.escapedpattern(str,simple)
- return lpegmatch(simple and s or p,str)
+ return match(simple and s or p,str)
end
-- utf extensies
@@ -1769,7 +1627,7 @@ else
p = P(uc)
end
end
- lpegmatch((utf8char/f)^0,str)
+ match((utf8char/f)^0,str)
return p
end
@@ -1785,7 +1643,7 @@ function lpeg.UR(str,more)
first = str
last = more or first
else
- first, last = lpegmatch(range,str)
+ first, last = match(range,str)
if not last then
return P(str)
end
@@ -1821,15 +1679,11 @@ end
--~ print(lpeg.count("äáàa",lpeg.UR("àá")))
--~ print(lpeg.count("äáàa",lpeg.UR(0x0000,0xFFFF)))
-function lpeg.is_lpeg(p)
- return p and lpegtype(p) == "pattern"
-end
-
-function lpeg.oneof(list,...) -- lpeg.oneof("elseif","else","if","then") -- assume proper order
+function lpeg.oneof(list,...) -- lpeg.oneof("elseif","else","if","then")
if type(list) ~= "table" then
list = { list, ... }
end
- -- table.sort(list) -- longest match first
+ -- sort(list) -- longest match first
local p = P(list[1])
for l=2,#list do
p = p + P(list[l])
@@ -1837,6 +1691,10 @@ function lpeg.oneof(list,...) -- lpeg.oneof("elseif","else","if","then") -- assu
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.
@@ -1994,24 +1852,6 @@ end
-- utfchar(0x205F), -- math thinspace
-- } )
--- handy from within tex:
-
-local lpegmatch = lpeg.match
-
-local replacer = lpeg.replacer("@","%%") -- Watch the escaped % in lpeg!
-
-function string.tformat(fmt,...)
- return format(lpegmatch(replacer,fmt),...)
-end
-
--- strips leading and trailing spaces and collapsed all other spaces
-
-local pattern = Cs(whitespace^0/"" * ((whitespace^1 * P(-1) / "") + (whitespace^1/" ") + P(1))^0)
-
-function string.collapsespaces(str)
- return lpegmatch(pattern,str)
-end
-
end -- closure
do -- begin closure to overcome local limits and interference
@@ -2034,49 +1874,28 @@ function boolean.tonumber(b)
end
function toboolean(str,tolerant)
- if str == nil then
- return false
- elseif str == false then
- return false
- elseif str == true then
- return true
+ 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
- elseif not tolerant then
- return false
- elseif str == 0 then
- return false
- elseif (tonumber(str) or 0) > 0 then
- return true
else
- return str == "yes" or str == "on" or str == "t"
+ return str
end
end
string.toboolean = toboolean
-function string.booleanstring(str)
- if str == nil then
- return false
- elseif str == false then
- return false
- elseif str == true then
- return true
- elseif str == "true" then
- return true
- elseif str == "false" then
- return false
- elseif str == 0 then
- return false
- elseif (tonumber(str) or 0) > 0 then
- return true
- else
- return str == "yes" or str == "on" or str == "t"
- end
-end
-
function string.is_boolean(str,default)
if type(str) == "string" then
if str == "true" or str == "yes" or str == "on" or str == "t" then
@@ -2167,7 +1986,7 @@ local function nameonly(name)
return (gsub(match(name,"^.+[/\\](.-)$") or name,"%.[%a%d]+$",""))
end
-local function suffixonly(name,default)
+local function extname(name,default)
return match(name,"^.+%.([^/\\]-)$") or default or ""
end
@@ -2176,16 +1995,11 @@ local function splitname(name)
return n or name, s or ""
end
-file.basename = basename
-
-file.pathpart = dirname
-file.dirname = dirname
-
-file.nameonly = nameonly
-
-file.suffixonly = suffixonly
-file.extname = suffixonly -- obsolete
-file.suffix = suffixonly
+file.basename = basename
+file.dirname = dirname
+file.nameonly = nameonly
+file.extname = extname
+file.suffix = extname
function file.removesuffix(filename)
return (gsub(filename,"%.[%a%d]+$",""))
@@ -2331,11 +2145,6 @@ end
file.isreadable = file.is_readable -- depricated
file.iswritable = file.is_writable -- depricated
-function file.size(name)
- local a = attributes(name)
- return a and a.size or 0
-end
-
-- todo: lpeg \\ / .. does not save much
local checkedsplit = string.checkedsplit
@@ -2466,7 +2275,7 @@ end
--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * C(noperiod^1) * -1
---~ function file.suffixonly(name)
+--~ function file.extname(name)
--~ return lpegmatch(pattern,name) or ""
--~ end
@@ -2528,7 +2337,7 @@ end
--~ end
--~ end
---~ local test = file.suffixonly
+--~ local test = file.extname
--~ local test = file.basename
--~ local test = file.dirname
--~ local test = file.addsuffix
@@ -2574,7 +2383,6 @@ local drive = C(R("az","AZ")) * P(":")
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 rest = C(P(1)^0)
drive = drive + Cc("")
path = path + Cc("")
@@ -2583,8 +2391,7 @@ 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) -- trick: two extra captures
-local pattern_d = path * rest
+local pattern_c = C(drive * path) * C(base * suffix)
function file.splitname(str,splitdrive)
if splitdrive then
@@ -2594,10 +2401,6 @@ function file.splitname(str,splitdrive)
end
end
-function file.splitbase(str)
- return lpegmatch(pattern_d,str) -- returns path, base+suffix
-end
-
function file.nametotable(str,splitdrive) -- returns table
local path, drive, subpath, name, base, suffix = lpegmatch(pattern_c,str)
if splitdrive then
@@ -2619,8 +2422,6 @@ function file.nametotable(str,splitdrive) -- returns table
end
end
--- print(file.splitbase("a/b/c.txt"))
-
-- function test(t) for k, v in next, t do print(v, "=>", file.splitname(v)) end end
--
-- test { "c:", "c:/aa", "c:/aa/bb", "c:/aa/bb/cc", "c:/aa/bb/cc.dd", "c:/aa/bb/cc.dd.ee" }
@@ -2667,14 +2468,14 @@ else
io.fileseparator, io.pathseparator = "/" , ":"
end
-function io.loaddata(filename,textmode) -- return nil if empty
+function io.loaddata(filename,textmode)
local f = io.open(filename,(textmode and 'r') or 'rb')
if f then
local data = f:read('*all')
f:close()
- if #data > 0 then
- return data
- end
+ return data
+ else
+ return nil
end
end
@@ -2696,45 +2497,6 @@ function io.savedata(filename,data,joiner)
end
end
-function io.loadlines(filename,n) -- return nil if empty
- local f = io.open(filename,'r')
- if f then
- if n then
- local lines = { }
- for i=1,n do
- local line = f:read("*lines")
- if line then
- lines[#lines+1] = line
- else
- break
- end
- end
- f:close()
- lines = concat(lines,"\n")
- if #lines > 0 then
- return lines
- end
- else
- local line = f:read("*line") or ""
- assert(f:close())
- if #line > 0 then
- return line
- end
- end
- end
-end
-
-function io.loadchunk(filename,n)
- local f = io.open(filename,'rb')
- if f then
- local data = f:read(n or 1024)
- f:close()
- if #data > 0 then
- return data
- end
- end
-end
-
function io.exists(filename)
local f = io.open(filename)
if f == nil then
@@ -3040,7 +2802,7 @@ local remapper = {
function resolvers.findfile(name,fileformat)
name = string.gsub(name,"\\","\/")
fileformat = fileformat and string.lower(fileformat)
- local found = kpse.find_file(name,(fileformat and fileformat ~= "" and (remapper[fileformat] or fileformat)) or file.suffix(name,"tex"))
+ local found = kpse.find_file(name,(fileformat and fileformat ~= "" and (remapper[fileformat] or fileformat)) or file.extname(name,"tex"))
if not found or found == "" then
found = kpse.find_file(name,"other text files")
end
@@ -3049,7 +2811,7 @@ end
function resolvers.findbinfile(name,fileformat)
if not fileformat or fileformat == "" then
- fileformat = file.suffix(name) -- string.match(name,"%.([^%.]-)$")
+ fileformat = file.extname(name) -- string.match(name,"%.([^%.]-)$")
end
return resolvers.findfile(name,(fileformat and remapper[fileformat]) or fileformat)
end
@@ -3473,30 +3235,36 @@ if not modules then modules = { } end modules ['font-ini'] = {
license = "see context related readme files"
}
+-- basemethods -> can also be in list
+-- presetcontext -> defaults
+-- hashfeatures -> ctx version
+
--[[ldx--
<p>Not much is happening here.</p>
--ldx]]--
-local allocate = utilities.storage.allocate
+local lower = string.lower
+local allocate, mark = utilities.storage.allocate, utilities.storage.mark
local report_defining = logs.reporter("fonts","defining")
-fonts = fonts or { }
-local fonts = fonts
+fontloader.totable = fontloader.to_table
-fonts.hashes = { identifiers = allocate() }
+fonts = fonts or { } -- already defined in context
+local fonts = fonts
-fonts.tables = fonts.tables or { }
-fonts.helpers = fonts.helpers or { }
-fonts.tracers = fonts.tracers or { } -- for the moment till we have move to moduledata
-fonts.specifiers = fonts.specifiers or { } -- in format !
+-- some of these might move to where they are used first:
+fonts.hashes = { identifiers = allocate() }
fonts.analyzers = { } -- not needed here
fonts.readers = { }
+fonts.tables = { }
fonts.definers = { methods = { } }
+fonts.specifiers = fonts.specifiers or { } -- in format !
fonts.loggers = { register = function() end }
+fonts.helpers = { }
-fontloader.totable = fontloader.to_table
+fonts.tracers = { } -- for the moment till we have move to moduledata
end -- closure
@@ -3533,9 +3301,9 @@ local report_defining = logs.reporter("fonts","defining")
--ldx]]--
local fonts = fonts
-local constructors = fonts.constructors or { }
+local constructors = { }
fonts.constructors = constructors
-local handlers = fonts.handlers or { } -- can have preloaded tables
+local handlers = { }
fonts.handlers = handlers
local specifiers = fonts.specifiers
@@ -3862,10 +3630,6 @@ function constructors.scale(tfmdata,specification)
elseif forcedsize > 1000 then -- safeguard
scaledpoints = forcedsize
end
- targetparameters.mathsize = mathsize -- context specific
- targetparameters.textsize = textsize -- context specific
- targetparameters.forcedsize = forcedsize -- context specific
- targetparameters.extrafactor = extrafactor -- context specific
--
local tounicode = resources.tounicode
local defaultwidth = resources.defaultwidth or 0
@@ -4577,7 +4341,7 @@ setmetatableindex(formats, function(t,k)
t[k] = l
return l
end
- return rawget(t,file.suffix(l))
+ return rawget(t,file.extname(l))
end)
local locations = { }
@@ -4674,31 +4438,19 @@ function constructors.getfeatureaction(what,where,mode,name)
end
end
-function constructors.newhandler(what) -- could be a metatable newindex
- local handler = handlers[what]
- if not handler then
- handler = { }
- handlers[what] = handler
- end
- return handler
-end
-
-function constructors.newfeatures(what) -- could be a metatable newindex
- local handler = handlers[what]
- local features = handler.features
+function constructors.newfeatures(what)
+ local features = handlers[what].features
if not features then
- local tables = handler.tables -- can be preloaded
- local statistics = handler.statistics -- can be preloaded
+ local tables = handlers[what].tables -- can be preloaded
features = allocate {
defaults = { },
descriptions = tables and tables.features or { },
- used = statistics and statistics.usedfeatures or { },
initializers = { base = { }, node = { } },
processors = { base = { }, node = { } },
manipulators = { base = { }, node = { } },
}
features.register = function(specification) return register(features,specification) end
- handler.features = features -- will also become hidden
+ handlers[what].features = features -- will also become hidden
end
return features
end
@@ -4900,17 +4652,17 @@ local format, match, lower = string.format, string.match, string.lower
local tonumber = tonumber
local P, S, R, C, V, lpegmatch = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.match
-local fonts, logs, trackers = fonts, logs, trackers
-
local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
-local report_otf = logs.reporter("fonts","otf loading")
+local report_otf = logs.reporter("fonts","otf loading")
-local cid = { }
-fonts.cid = cid
+local fonts = fonts
-local cidmap = { }
-local cidmax = 10
+local cid = { }
+fonts.cid = cid
+
+local cidmap = { }
+local cidmax = 10
-- original string parser: 0.109, lpeg parser: 0.036 seconds for Adobe-CNS1-4.cidmap
--
@@ -4969,7 +4721,8 @@ local function loadcidfile(filename)
end
end
-cid.loadfile = loadcidfile -- we use the frozen variant
+cid.loadfile = loadcidfile -- we use the frozen variant
+
local template = "%s-%s-%s.cidmap"
local function locate(registry,ordering,supplement)
@@ -5065,20 +4818,18 @@ if not modules then modules = { } end modules ['font-map'] = {
license = "see context related readme files"
}
-local tonumber = tonumber
-
local match, format, find, concat, gsub, lower = string.match, string.format, string.find, table.concat, string.gsub, string.lower
local P, R, S, C, Ct, Cc, lpegmatch = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Ct, lpeg.Cc, lpeg.match
local utfbyte = utf.byte
-local trace_loading = false trackers.register("fonts.loading", function(v) trace_loading = v end)
+local trace_loading = false trackers.register("fonts.loading", function(v) trace_loading = v end)
local trace_mapping = false trackers.register("fonts.mapping", function(v) trace_unimapping = v end)
local report_fonts = logs.reporter("fonts","loading") -- not otf only
-local fonts = fonts
-local mappings = fonts.mappings or { }
-fonts.mappings = mappings
+local fonts = fonts
+local mappings = { }
+fonts.mappings = mappings
--[[ldx--
<p>Eventually this code will disappear because map files are kind
@@ -5101,7 +4852,7 @@ end
local hex = R("AF","09")
local hexfour = (hex*hex*hex*hex) / function(s) return tonumber(s,16) end
local hexsix = (hex^1) / function(s) return tonumber(s,16) end
-local dec = (R("09")^1) / tonumber
+local dec = (R("09")^1) / tonumber
local period = P(".")
local unicode = P("uni") * (hexfour * (period + P(-1)) * Cc(false) + Ct(hexfour^1) * Cc(true))
local ucode = P("u") * (hexsix * (period + P(-1)) * Cc(false) + Ct(hexsix ^1) * Cc(true))
@@ -5512,16 +5263,15 @@ if not modules then modules = { } end modules ['font-oti'] = {
local lower = string.lower
+local allocate = utilities.storage.allocate
+
local fonts = fonts
-local constructors = fonts.constructors
+local otf = { }
+fonts.handlers.otf = otf
-local otf = constructors.newhandler("otf")
-local otffeatures = constructors.newfeatures("otf")
-local otftables = otf.tables
+local otffeatures = fonts.constructors.newfeatures("otf")
local registerotffeature = otffeatures.register
-local allocate = utilities.storage.allocate
-
registerotffeature {
name = "features",
description = "initialization of feature handler",
@@ -5530,6 +5280,8 @@ registerotffeature {
-- these are later hooked into node and base initializaters
+local otftables = otf.tables -- not always defined
+
local function setmode(tfmdata,value)
if value then
tfmdata.properties.mode = lower(value)
@@ -6714,7 +6466,7 @@ actions["prepare lookups"] = function(data,filename,raw)
end
-- The reverse handler does a bit redundant splitting but it's seldom
--- seen so we don't bother too much. We could store the replacement
+-- seen so we don' tbother too much. We could store the replacement
-- in the current list (value instead of true) but it makes other code
-- uglier. Maybe some day.
@@ -6732,22 +6484,6 @@ local function t_uncover(splitter,cache,covers)
return result
end
-local function s_uncover(splitter,cache,cover)
- if cover == "" then
- return nil
- else
- local uncovered = cache[cover]
- if not uncovered then
- uncovered = lpegmatch(splitter,cover)
--- for i=1,#uncovered do
--- uncovered[i] = { [uncovered[i]] = true }
--- end
- cache[cover] = uncovered
- end
- return { uncovered }
- end
-end
-
local function t_hashed(t,cache)
if t then
local ht = { }
@@ -6769,6 +6505,22 @@ local function t_hashed(t,cache)
end
end
+local function s_uncover(splitter,cache,cover)
+ if cover == "" then
+ return nil
+ else
+ local uncovered = cache[cover]
+ if not uncovered then
+ uncovered = lpegmatch(splitter,cover)
+ for i=1,#uncovered do
+ uncovered[i] = { [uncovered[i]] = true }
+ end
+ cache[cover] = uncovered
+ end
+ return uncovered
+ end
+end
+
local s_hashed = t_hashed
local function r_uncover(splitter,cache,cover,replacements)
@@ -6793,15 +6545,11 @@ local function r_uncover(splitter,cache,cover,replacements)
end
end
-actions["reorganize lookups"] = function(data,filename,raw) -- we could check for "" and n == 0
+actions["reorganize lookups"] = function(data,filename,raw)
-- we prefer the before lookups in a normal order
if data.lookups then
local splitter = data.helpers.tounicodetable
- local t_u_cache = { }
- local s_u_cache = t_u_cache -- string keys
- local t_h_cache = { }
- local s_h_cache = t_h_cache -- table keys (so we could use one cache)
- local r_u_cache = { } -- maybe shared
+ local cache, h_cache = { }, { }
for _, lookup in next, data.lookups do
local rules = lookup.rules
if rules then
@@ -6809,15 +6557,15 @@ actions["reorganize lookups"] = function(data,filename,raw) -- we could check fo
if format == "class" then
local before_class = lookup.before_class
if before_class then
- before_class = t_uncover(splitter,t_u_cache,reversed(before_class))
+ before_class = t_uncover(splitter,cache,reversed(before_class))
end
local current_class = lookup.current_class
if current_class then
- current_class = t_uncover(splitter,t_u_cache,current_class)
+ current_class = t_uncover(splitter,cache,current_class)
end
local after_class = lookup.after_class
if after_class then
- after_class = t_uncover(splitter,t_u_cache,after_class)
+ after_class = t_uncover(splitter,cache,after_class)
end
for i=1,#rules do
local rule = rules[i]
@@ -6827,7 +6575,7 @@ actions["reorganize lookups"] = function(data,filename,raw) -- we could check fo
for i=1,#before do
before[i] = before_class[before[i]] or { }
end
- rule.before = t_hashed(before,t_h_cache)
+ rule.before = t_hashed(before,h_cache)
end
local current = class.current
local lookups = rule.lookups
@@ -6838,14 +6586,14 @@ actions["reorganize lookups"] = function(data,filename,raw) -- we could check fo
lookups[i] = false -- e.g. we can have two lookups and one replacement
end
end
- rule.current = t_hashed(current,t_h_cache)
+ rule.current = t_hashed(current,h_cache)
end
local after = class.after
if after then
for i=1,#after do
after[i] = after_class[after[i]] or { }
end
- rule.after = t_hashed(after,t_h_cache)
+ rule.after = t_hashed(after,h_cache)
end
rule.class = nil
end
@@ -6860,18 +6608,18 @@ actions["reorganize lookups"] = function(data,filename,raw) -- we could check fo
if coverage then
local before = coverage.before
if before then
- before = t_uncover(splitter,t_u_cache,reversed(before))
- rule.before = t_hashed(before,t_h_cache)
+ before = t_uncover(splitter,cache,reversed(before))
+ rule.before = t_hashed(before,h_cache)
end
local current = coverage.current
if current then
- current = t_uncover(splitter,t_u_cache,current)
- rule.current = t_hashed(current,t_h_cache)
+ current = t_uncover(splitter,cache,current)
+ rule.current = t_hashed(current,h_cache)
end
local after = coverage.after
if after then
- after = t_uncover(splitter,t_u_cache,after)
- rule.after = t_hashed(after,t_h_cache)
+ after = t_uncover(splitter,cache,after)
+ rule.after = t_hashed(after,h_cache)
end
rule.coverage = nil
end
@@ -6883,22 +6631,22 @@ actions["reorganize lookups"] = function(data,filename,raw) -- we could check fo
if reversecoverage then
local before = reversecoverage.before
if before then
- before = t_uncover(splitter,t_u_cache,reversed(before))
- rule.before = t_hashed(before,t_h_cache)
+ before = t_uncover(splitter,cache,reversed(before))
+ rule.before = t_hashed(before,h_cache)
end
local current = reversecoverage.current
if current then
- current = t_uncover(splitter,t_u_cache,current)
- rule.current = t_hashed(current,t_h_cache)
+ current = t_uncover(splitter,cache,current)
+ rule.current = t_hashed(current,h_cache)
end
local after = reversecoverage.after
if after then
- after = t_uncover(splitter,t_u_cache,after)
- rule.after = t_hashed(after,t_h_cache)
+ after = t_uncover(splitter,cache,after)
+ rule.after = t_hashed(after,h_cache)
end
local replacements = reversecoverage.replacements
if replacements then
- rule.replacements = r_uncover(splitter,r_u_cache,current,replacements)
+ rule.replacements = r_uncover(splitter,cache,current,replacements)
end
rule.reversecoverage = nil
end
@@ -6909,19 +6657,19 @@ actions["reorganize lookups"] = function(data,filename,raw) -- we could check fo
local glyphs = rule.glyphs
if glyphs then
local fore = glyphs.fore
- if fore and fore ~= "" then
- fore = s_uncover(splitter,s_u_cache,fore)
- rule.before = s_hashed(fore,s_h_cache)
+ if fore then
+ fore = s_uncover(splitter,cache,fore)
+ rule.before = s_hashed(fore,h_cache)
end
local back = glyphs.back
if back then
- back = s_uncover(splitter,s_u_cache,back)
- rule.after = s_hashed(back,s_h_cache)
+ back = s_uncover(splitter,cache,back)
+ rule.after = s_hashed(back,h_cache)
end
local names = glyphs.names
if names then
- names = s_uncover(splitter,s_u_cache,names)
- rule.current = s_hashed(names,s_h_cache)
+ names = s_uncover(splitter,cache,names)
+ rule.current = s_hashed(names,h_cache)
end
rule.glyphs = nil
end
@@ -7576,7 +7324,7 @@ local function read_from_otf(specification)
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.suffix(specification.filename),specification)
+ fonts.loggers.register(tfmdata,file.extname(specification.filename),specification)
end
return tfmdata
end
@@ -7700,27 +7448,26 @@ local type, next, tonumber, tostring = type, next, tonumber, tostring
local lpegmatch = lpeg.match
local utfchar = utf.char
-local trace_baseinit = false trackers.register("otf.baseinit", function(v) trace_baseinit = 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_ligatures_detail = false trackers.register("otf.ligatures.detail", function(v) trace_ligatures_detail = v end)
-local trace_kerns = false trackers.register("otf.kerns", function(v) trace_kerns = v end)
-local trace_preparing = false trackers.register("otf.preparing", function(v) trace_preparing = v end)
+local trace_baseinit = false trackers.register("otf.baseinit", function(v) trace_baseinit = 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_kerns = false trackers.register("otf.kerns", function(v) trace_kerns = v end)
+local trace_preparing = false trackers.register("otf.preparing", function(v) trace_preparing = v end)
-local report_prepare = logs.reporter("fonts","otf prepare")
+local report_prepare = logs.reporter("fonts","otf prepare")
-local fonts = fonts
-local otf = fonts.handlers.otf
+local fonts = fonts
+local otf = fonts.handlers.otf
-local otffeatures = otf.features
-local registerotffeature = otffeatures.register
+local otffeatures = fonts.constructors.newfeatures("otf")
+local registerotffeature = otffeatures.register
-otf.defaultbasealternate = "none" -- first last
+otf.defaultbasealternate = "none" -- first last
-local wildcard = "*"
-local default = "dflt"
+local wildcard = "*"
+local default = "dflt"
local function gref(descriptions,n)
if type(n) == "number" then
@@ -7855,7 +7602,7 @@ local function finalize_ligatures(tfmdata,ligatures)
if ligature then
local unicode, lookupdata = ligature[1], ligature[2]
if trace then
- trace_ligatures_detail("building %q into %q",concat(lookupdata," "),unicode)
+ print("BUILDING",concat(lookupdata," "),unicode)
end
local size = #lookupdata
local firstcode = lookupdata[1] -- [2]
@@ -7868,7 +7615,7 @@ local function finalize_ligatures(tfmdata,ligatures)
if not firstdata then
firstcode = private
if trace then
- trace_ligatures_detail("defining %q as %q",firstname,firstcode)
+ print(" DEFINING",firstname,firstcode)
end
unicodes[firstname] = firstcode
firstdata = { intermediate = true, ligatures = { } }
@@ -7892,7 +7639,7 @@ local function finalize_ligatures(tfmdata,ligatures)
end
end
if trace then
- trace_ligatures_detail("codes (%s,%s) + (%s,%s) -> %s",firstname,firstcode,secondname,secondcode,target)
+ print("CODES",firstname,firstcode,secondname,secondcode,target)
end
local firstligs = firstdata.ligatures
if firstligs then
@@ -8365,6 +8112,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
@@ -8376,16 +8124,27 @@ 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.
-function injections.installnewkern(nk)
- newkern = nk or newkern
-end
-
local cursives = { }
local marks = { }
local kerns = { }
@@ -8671,13 +8430,16 @@ function injections.handler(head,where,keep)
-- new per 2010-10-06, width adapted per 2010-02-03
-- we used to negate the width of marks because in tfm
-- that makes sense but we no longer do that so as a
- -- consequence the sign of p.width was changed
+ -- 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
+ -- one is right
local k = wx[p]
if k then
- -- brill roman: A\char"0300 (but ugly anyway)
- n.xoffset = p.xoffset - p.width + d[1] - k[2] -- was + p.width
+ n.xoffset = p.xoffset + p.width + d[1] - k[2]
else
- -- lucida: U\char"032F (default+mark)
+ -- n.xoffset = p.xoffset + p.width + d[1]
+ -- lucida U\char"032F (default+mark)
n.xoffset = p.xoffset - p.width + d[1] -- 01-05-2011
end
else
@@ -8817,371 +8579,6 @@ end -- closure
do -- begin closure to overcome local limits and interference
-if not modules then modules = { } end modules ['font-ota'] = {
- version = 1.001,
- comment = "companion to font-otf.lua (analysing)",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
--- this might become scrp-*.lua
-
-local type, tostring, match, format, concat = type, tostring, string.match, string.format, table.concat
-
-if not trackers then trackers = { register = function() end } end
-
-local trace_analyzing = false trackers.register("otf.analyzing", function(v) trace_analyzing = v end)
-
-local fonts, nodes, node = fonts, nodes, node
-
-local allocate = utilities.storage.allocate
-
-local otf = fonts.handlers.otf
-
-local analyzers = fonts.analyzers
-local initializers = allocate()
-local methods = allocate()
-
-analyzers.initializers = initializers
-analyzers.methods = methods
-analyzers.useunicodemarks = false
-
-local nodecodes = nodes.nodecodes
-local glyph_code = nodecodes.glyph
-
-local set_attribute = node.set_attribute
-local has_attribute = node.has_attribute
-local traverse_id = node.traverse_id
-local traverse_node_list = node.traverse
-
-local fontdata = fonts.hashes.identifiers
-local state = attributes.private('state')
-local categories = characters and characters.categories or { } -- sorry, only in context
-
-local otffeatures = fonts.constructors.newfeatures("otf")
-local registerotffeature = otffeatures.register
-
---[[ldx--
-<p>Analyzers run per script and/or language and are needed in order to
-process features right.</p>
---ldx]]--
-
-analyzers.constants = {
- init = 1,
- medi = 2,
- fina = 3,
- isol = 4,
- -- devanagari
- rphf = 5,
- half = 6,
- pref = 7,
- blwf = 8,
- pstf = 9,
-}
-
--- todo: analyzers per script/lang, cross font, so we need an font id hash -> script
--- e.g. latin -> hyphenate, arab -> 1/2/3 analyze -- its own namespace
-
-function analyzers.setstate(head,font)
- local useunicodemarks = analyzers.useunicodemarks
- local tfmdata = fontdata[font]
- local characters = tfmdata.characters
- local descriptions = tfmdata.descriptions
- local first, last, current, n, done = nil, nil, head, 0, false -- maybe make n boolean
- while current do
- local id = current.id
- if id == glyph_code and current.font == font then
- local char = current.char
- local d = descriptions[char]
- if d then
- if d.class == "mark" or (useunicodemarks and categories[char] == "mn") then
- done = true
- set_attribute(current,state,5) -- mark
- elseif n == 0 then
- first, last, n = current, current, 1
- set_attribute(current,state,1) -- init
- else
- last, n = current, n+1
- set_attribute(current,state,2) -- medi
- end
- else -- finish
- if first and first == last then
- set_attribute(last,state,4) -- isol
- elseif last then
- set_attribute(last,state,3) -- fina
- end
- first, last, n = nil, nil, 0
- end
- elseif id == disc_code then
- -- always in the middle
- set_attribute(current,state,2) -- midi
- last = current
- else -- finish
- if first and first == last then
- set_attribute(last,state,4) -- isol
- elseif last then
- set_attribute(last,state,3) -- fina
- end
- first, last, n = nil, nil, 0
- end
- current = current.next
- end
- if first and first == last then
- set_attribute(last,state,4) -- isol
- elseif last then
- set_attribute(last,state,3) -- fina
- end
- return head, done
-end
-
--- in the future we will use language/script attributes instead of the
--- font related value, but then we also need dynamic features which is
--- somewhat slower; and .. we need a chain of them
-
-local function analyzeinitializer(tfmdata,value) -- attr
- local script, language = otf.scriptandlanguage(tfmdata) -- attr
- local action = initializers[script]
- if not action then
- -- skip
- elseif type(action) == "function" then
- return action(tfmdata,value)
- else
- local action = action[language]
- if action then
- return action(tfmdata,value)
- end
- end
-end
-
-local function analyzeprocessor(head,font,attr)
- local tfmdata = fontdata[font]
- local script, language = otf.scriptandlanguage(tfmdata,attr)
- local action = methods[script]
- if not action then
- -- skip
- elseif type(action) == "function" then
- return action(head,font,attr)
- else
- action = action[language]
- if action then
- return action(head,font,attr)
- end
- end
- return head, false
-end
-
-registerotffeature {
- name = "analyze",
- description = "analysis of (for instance) character classes",
- default = true,
- initializers = {
- node = analyzeinitializer,
- },
- processors = {
- position = 1,
- node = analyzeprocessor,
- }
-}
-
--- latin
-
-methods.latn = analyzers.setstate
-
--- this info eventually will go into char-def and we will have a state
--- table for generic then
-
-local zwnj = 0x200C
-local zwj = 0x200D
-
-local isol = {
- [0x0600] = true, [0x0601] = true, [0x0602] = true, [0x0603] = true,
- [0x0608] = true, [0x060B] = true, [0x0621] = true, [0x0674] = true,
- [0x06DD] = true, [zwnj] = true,
-}
-
-local isol_fina = {
- [0x0622] = true, [0x0623] = true, [0x0624] = true, [0x0625] = true,
- [0x0627] = true, [0x0629] = true, [0x062F] = true, [0x0630] = true,
- [0x0631] = true, [0x0632] = true, [0x0648] = true, [0x0671] = true,
- [0x0672] = true, [0x0673] = true, [0x0675] = true, [0x0676] = true,
- [0x0677] = true, [0x0688] = true, [0x0689] = true, [0x068A] = true,
- [0x068B] = true, [0x068C] = true, [0x068D] = true, [0x068E] = true,
- [0x068F] = true, [0x0690] = true, [0x0691] = true, [0x0692] = true,
- [0x0693] = true, [0x0694] = true, [0x0695] = true, [0x0696] = true,
- [0x0697] = true, [0x0698] = true, [0x0699] = true, [0x06C0] = true,
- [0x06C3] = true, [0x06C4] = true, [0x06C5] = true, [0x06C6] = true,
- [0x06C7] = true, [0x06C8] = true, [0x06C9] = true, [0x06CA] = true,
- [0x06CB] = true, [0x06CD] = true, [0x06CF] = true, [0x06D2] = true,
- [0x06D3] = true, [0x06D5] = true, [0x06EE] = true, [0x06EF] = true,
- [0x0759] = true, [0x075A] = true, [0x075B] = true, [0x076B] = true,
- [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 = {
- [0x0626] = true, [0x0628] = true, [0x062A] = true, [0x062B] = true,
- [0x062C] = true, [0x062D] = true, [0x062E] = true, [0x0633] = true,
- [0x0634] = true, [0x0635] = true, [0x0636] = true, [0x0637] = true,
- [0x0638] = true, [0x0639] = true, [0x063A] = true, [0x063B] = true,
- [0x063C] = true, [0x063D] = true, [0x063E] = true, [0x063F] = true,
- [0x0640] = true, [0x0641] = true, [0x0642] = true, [0x0643] = true,
- [0x0644] = true, [0x0645] = true, [0x0646] = true, [0x0647] = true,
- [0x0649] = true, [0x064A] = true, [0x066E] = true, [0x066F] = true,
- [0x0678] = true, [0x0679] = true, [0x067A] = true, [0x067B] = true,
- [0x067C] = true, [0x067D] = true, [0x067E] = true, [0x067F] = true,
- [0x0680] = true, [0x0681] = true, [0x0682] = true, [0x0683] = true,
- [0x0684] = true, [0x0685] = true, [0x0686] = true, [0x0687] = true,
- [0x069A] = true, [0x069B] = true, [0x069C] = true, [0x069D] = true,
- [0x069E] = true, [0x069F] = true, [0x06A0] = true, [0x06A1] = true,
- [0x06A2] = true, [0x06A3] = true, [0x06A4] = true, [0x06A5] = true,
- [0x06A6] = true, [0x06A7] = true, [0x06A8] = true, [0x06A9] = true,
- [0x06AA] = true, [0x06AB] = true, [0x06AC] = true, [0x06AD] = true,
- [0x06AE] = true, [0x06AF] = true, [0x06B0] = true, [0x06B1] = true,
- [0x06B2] = true, [0x06B3] = true, [0x06B4] = true, [0x06B5] = true,
- [0x06B6] = true, [0x06B7] = true, [0x06B8] = true, [0x06B9] = true,
- [0x06BA] = true, [0x06BB] = true, [0x06BC] = true, [0x06BD] = true,
- [0x06BE] = true, [0x06BF] = true, [0x06C1] = true, [0x06C2] = true,
- [0x06CC] = true, [0x06CE] = true, [0x06D0] = true, [0x06D1] = true,
- [0x06FA] = true, [0x06FB] = true, [0x06FC] = true, [0x06FF] = true,
- [0x0750] = true, [0x0751] = true, [0x0752] = true, [0x0753] = true,
- [0x0754] = true, [0x0755] = true, [0x0756] = true, [0x0757] = true,
- [0x0758] = true, [0x075C] = true, [0x075D] = true, [0x075E] = true,
- [0x075F] = true, [0x0760] = true, [0x0761] = true, [0x0762] = true,
- [0x0763] = true, [0x0764] = true, [0x0765] = true, [0x0766] = true,
- [0x0767] = true, [0x0768] = true, [0x0769] = true, [0x076A] = true,
- [0x076D] = true, [0x076E] = true, [0x076F] = true, [0x0770] = true,
- [0x0772] = true, [0x0775] = true, [0x0776] = true, [0x0777] = true,
- [0x077A] = true, [0x077B] = true, [0x077C] = true, [0x077D] = true,
- [0x077E] = true, [0x077F] = 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,
- [0x0724] = true, [0x0725] = true, [0x0726] = true, [0x0727] = true,
- [0x0729] = true, [0x072B] = true,
-
- -- also
-
- [zwj] = true,
-}
-
-local arab_warned = { }
-
--- todo: gref
-
-local function warning(current,what)
- local char = current.char
- if not arab_warned[char] then
- log.report("analyze","arab: character %s (U+%05X) has no %s class", char, char, what)
- arab_warned[char] = true
- end
-end
-
-local function finish(first,last)
- if last then
- if first == last then
- local fc = first.char
- if isol_fina_medi_init[fc] or isol_fina[fc] then
- set_attribute(first,state,4) -- isol
- else
- warning(first,"isol")
- set_attribute(first,state,0) -- error
- end
- else
- local lc = last.char
- if isol_fina_medi_init[lc] or isol_fina[lc] then -- why isol here ?
- -- if laststate == 1 or laststate == 2 or laststate == 4 then
- set_attribute(last,state,3) -- fina
- else
- warning(last,"fina")
- set_attribute(last,state,0) -- error
- end
- end
- first, last = nil, nil
- elseif first then
- -- first and last are either both set so we never com here
- local fc = first.char
- if isol_fina_medi_init[fc] or isol_fina[fc] then
- set_attribute(first,state,4) -- isol
- else
- warning(first,"isol")
- set_attribute(first,state,0) -- error
- end
- first = nil
- end
- return first, last
-end
-
-function methods.arab(head,font,attr) -- maybe make a special version with no trace
- local useunicodemarks = analyzers.useunicodemarks
- local tfmdata = fontdata[font]
- local marks = tfmdata.resources.marks
- local first, last, current, done = nil, nil, head, false
- while current do
- if current.id == glyph_code and current.subtype<256 and current.font == font and not has_attribute(current,state) then
- done = true
- local char = current.char
- if marks[char] or (useunicodemarks and categories[char] == "mn") then
- set_attribute(current,state,5) -- mark
- elseif isol[char] then -- can be zwj or zwnj too
- first, last = finish(first,last)
- set_attribute(current,state,4) -- isol
- first, last = nil, nil
- elseif not first then
- if isol_fina_medi_init[char] then
- set_attribute(current,state,1) -- init
- first, last = first or current, current
- elseif isol_fina[char] then
- set_attribute(current,state,4) -- isol
- first, last = nil, nil
- else -- no arab
- first, last = finish(first,last)
- end
- elseif isol_fina_medi_init[char] then
- first, last = first or current, current
- set_attribute(current,state,2) -- medi
- elseif isol_fina[char] then
- if not has_attribute(last,state,1) then
- -- tricky, we need to check what last may be !
- set_attribute(last,state,2) -- medi
- end
- set_attribute(current,state,3) -- fina
- first, last = nil, nil
- elseif char >= 0x0600 and char <= 0x06FF then
- set_attribute(current,state,6) -- rest
- first, last = finish(first,last)
- else --no
- first, last = finish(first,last)
- end
- else
- first, last = finish(first,last)
- end
- current = current.next
- end
- first, last = finish(first,last)
- return head, done
-end
-
-methods.syrc = methods.arab
-
-directives.register("otf.analyze.useunicodemarks",function(v)
- analyzers.useunicodemarks = v
-end)
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
if not modules then modules = { } end modules ['font-otn'] = {
version = 1.001,
comment = "companion to font-ini.mkiv",
@@ -9300,8 +8697,6 @@ results in different tables.</p>
-- we now use only one hash. If needed we can have multiple again but in that
-- case I will probably prefix (i.e. rename) the lookups in the cached font file.
--- Todo: make plugin feature that operates on char/glyphnode arrays
-
local concat, insert, remove = table.concat, table.insert, table.remove
local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip
local type, next, tonumber, tostring = type, next, tonumber, tostring
@@ -9337,7 +8732,6 @@ local report_subchain = logs.reporter("fonts","otf subchain")
local report_chain = logs.reporter("fonts","otf chain")
local report_process = logs.reporter("fonts","otf process")
local report_prepare = logs.reporter("fonts","otf prepare")
-local report_warning = logs.reporter("fonts","otf warning")
registertracker("otf.verbose_chain", function(v) otf.setcontextchain(v and "verbose") end)
registertracker("otf.normal_chain", function(v) otf.setcontextchain(v and "normal") end)
@@ -9497,229 +8891,105 @@ local function pref(kind,lookupname)
return format("feature %s, lookup %s",kind,lookupname)
end
--- We can assume that languages that use marks are not hyphenated. We can also assume
--- that at most one discretionary is present.
+-- we can assume that languages that use marks are not hyphenated
+-- we can also assume that at most one discretionary is present
--- 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. Also, later on copying and freeing becomes easier.
--- However, for arabic we need to keep them around for the sake of mark placement
--- and indices.
-
-local function copy_glyph(g) -- next and prev are untouched !
- local components = g.components
- if components then
- g.components = nil
- local n = copy_node(g)
- g.components = components
- return n
- else
- return copy_node(g)
+local function markstoligature(kind,lookupname,start,stop,char)
+ local n = copy_node(start)
+ local keep = start
+ local current
+ current, start = insert_node_after(start,start,n)
+ local snext = stop.next
+ current.next = snext
+ if snext then
+ snext.prev = current
end
+ start.prev, stop.next = nil, nil
+ current.char, current.subtype, current.components = char, ligature_code, start
+ return keep
end
--- start is a mark and we need to keep that one
-
--- local function markstoligature(kind,lookupname,start,stop,char)
--- -- [start]..[stop]
--- local keep = start
--- local prev = start.prev
--- local next = stop.next
--- local base = copy_glyph(start)
--- local current, start = insert_node_after(start,start,base)
--- -- [current][start]..[stop]
--- current.next = next
--- if next then
--- next.prev = current
--- end
--- start.prev = nil
--- stop.next = nil
--- current.char = char
--- current.subtype = ligature_code
--- current.components = start
--- return keep
--- end
-
-local function markstoligature(kind,lookupname,start,stop,char)
- if start == stop and start.char == char then
+local function toligature(kind,lookupname,start,stop,char,markflag,discfound) -- brr head
+ if start == stop then
+ start.char = char
return start
- else
- local prev = start.prev
+ 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 = start.font
+ lignode.char = char
+ lignode.subtype = ligature_code
local next = stop.next
- start.prev = nil
+ local prev = start.prev
stop.next = nil
- local base = copy_glyph(start)
- base.char = char
- base.subtype = ligature_code
- base.components = start
- if prev then
- prev.next = base
- end
+ 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 = base
+ next.prev = lignode
end
- base.next = next
- base.prev = prev
- return base
- end
-end
-
--- The next code is somewhat complicated by the fact that some fonts can have ligatures made
--- from ligatures that themselves have marks. This was identified by Kai in for instance
--- arabtype: KAF LAM SHADDA ALEF FATHA (0x0643 0x0644 0x0651 0x0627 0x064E). This becomes
--- KAF LAM-ALEF with a SHADDA on the first and a FATHA op de second component. In a next
--- iteration this becomes a KAF-LAM-ALEF with a SHADDA on the second and a FATHA on the
--- third component.
-
-local function getcomponentindex(start)
- if start.id ~= glyph_code then
- return 0
- elseif start.subtype == ligature_code then
- local i = 0
- local components = start.components
- while components do
- i = i + getcomponentindex(components)
- components = components.next
- end
- return i
- elseif not marks[start.char] then
- return 1
+ lignode.next = next
+ lignode.prev = prev
+ -- print("start->end",nodes.tosequence(start))
+ return lignode
else
- return 0
- end
-end
-
--- local function toligature(kind,lookupname,start,stop,char,markflag,discfound) -- brr head
--- if start == stop and start.char == char then
--- start.char = char
--- return start
--- elseif discfound then
--- local prev = start.prev
--- local next = stop.next
--- start.prev = nil
--- stop.next = nil
--- local base = copy_glyph(start)
--- base.char = char
--- base.subtype = ligature_code
--- base.components = start -- start can have components
--- if prev then
--- prev.next = base
--- end
--- if next then
--- next.prev = base
--- end
--- base.next = next
--- base.prev = prev
--- return base
--- else
--- -- start is the ligature
--- local deletemarks = markflag ~= "mark"
--- local prev = start.prev
--- local next = stop.next
--- local base = copy_glyph(start)
--- local current, start = insert_node_after(start,start,base)
--- -- [start->current][copyofstart->start]...[stop]
--- current.next = next
--- if next then
--- next.prev = current
--- end
--- start.prev = nil
--- stop.next = nil
--- current.char = char
--- current.subtype = ligature_code
--- current.components = start
--- local head = current
--- -- this is messy ... we should get rid of the components eventually
--- local baseindex = 0
--- local componentindex = 0
--- while start do
--- local char = start.char
--- if not marks[char] then
--- baseindex = baseindex + componentindex
--- componentindex = getcomponentindex(start)
--- elseif not deletemarks then -- quite fishy
--- set_attribute(start,ligacomp,baseindex + (has_attribute(start,ligacomp) or componentindex))
--- if trace_marks then
--- logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),has_attribute(start,ligacomp))
--- end
--- head, current = insert_node_after(head,current,copy_glyph(start)) -- unlikely that mark has components
--- end
--- start = start.next
--- end
--- start = current.next
--- while start and start.id == glyph_code do -- hm, is id test needed ?
--- local char = start.char
--- if marks[char] then
--- set_attribute(start,ligacomp,baseindex + (has_attribute(start,ligacomp) or componentindex))
--- if trace_marks then
--- logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),has_attribute(start,ligacomp))
--- end
--- else
--- break
--- end
--- start = start.next
--- end
--- return head
--- end
--- end
-
-local function toligature(kind,lookupname,start,stop,char,markflag,discfound) -- brr head
- if start == stop and start.char == char then
- start.char = char
- return start
- end
- local prev = start.prev
- local next = stop.next
- start.prev = nil
- stop.next = nil
- local base = copy_glyph(start)
- base.char = char
- base.subtype = ligature_code
- base.components = start -- start can have components
- if prev then
- prev.next = base
- end
- if next then
- next.prev = base
- end
- base.next = next
- base.prev = prev
- if not discfound then
+ -- start is the ligature
local deletemarks = markflag ~= "mark"
- local components = start
- local baseindex = 0
- local componentindex = 0
- local head = base
- local current = base
+ local n = copy_node(start)
+ local current
+ current, start = insert_node_after(start,start,n)
+ local snext = stop.next
+ current.next = snext
+ if snext then
+ snext.prev = current
+ end
+ start.prev = nil
+ stop.next = nil
+ current.char = char
+ current.subtype = ligature_code
+ current.components = start
+ local head = current
+ -- this is messy ... we should get rid of the components eventually
+ local i = 0 -- is index of base
while start do
- local char = start.char
- if not marks[char] then
- baseindex = baseindex + componentindex
- componentindex = getcomponentindex(start)
+ if not marks[start.char] then
+ i = i + 1
elseif not deletemarks then -- quite fishy
- set_attribute(start,ligacomp,baseindex + (has_attribute(start,ligacomp) or componentindex))
+ set_attribute(start,ligacomp,i)
if trace_marks then
- logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),has_attribute(start,ligacomp))
+ 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)) -- unlikely that mark has components
+ head, current = insert_node_after(head,current,copy_node(start))
end
start = start.next
end
- local start = components
- while start and start.id == glyph_code do -- hm, is id test needed ?
- local char = start.char
- if marks[char] then
- set_attribute(start,ligacomp,baseindex + (has_attribute(start,ligacomp) or componentindex))
+ 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(char),has_attribute(start,ligacomp))
+ logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i)
end
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 base
end
function handlers.gsub_single(start,kind,lookupname,replacement)
@@ -9774,7 +9044,7 @@ local function multiple_glyphs(start,multiple) -- marks ?
if nofmultiples > 1 then
local sn = start.next
for k=2,nofmultiples do -- todo: use insert_node
- local n = copy_node(start) -- ignore components
+ local n = copy_node(start)
n.char = multiple[k]
n.next = sn
n.prev = start
@@ -9799,12 +9069,12 @@ function handlers.gsub_alternate(start,kind,lookupname,alternative,sequence)
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(start.char),gref(choice),choice)
+ 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(start.char))
+ logwarning("%s: no variant %s for %s",pref(kind,lookupname),tostring(value),gref(char))
end
end
return start, true
@@ -10298,10 +9568,6 @@ local function delete_till_stop(start,stop,ignoremarks) -- keeps start
repeat -- start x x m x x stop => start m
local next = start.next
if not marks[next.char] then
-local components = next.components
-if components then -- probably not needed
- flush_node_list(components)
-end
delete_node(start,next)
end
n = n + 1
@@ -10309,10 +9575,6 @@ end
else -- start x x x stop => start
repeat
local next = start.next
-local components = next.components
-if components then -- probably not needed
- flush_node_list(components)
-end
delete_node(start,next)
n = n + 1
until next == stop
@@ -11041,7 +10303,7 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
break
end
prev = prev.prev
- elseif seq[n][32] then -- somewhat special, as zapfino can have many preceding spaces
+ elseif seq[n][32] then -- somehat special, as zapfino can have many preceding spaces
n = n -1
else
match = false
@@ -11281,7 +10543,12 @@ end)
-- fonts.hashes.lookups = lookuphashes
-local constants = fonts.analyzers.constants
+local special_attributes = {
+ init = 1,
+ medi = 2,
+ fina = 3,
+ isol = 4
+}
local function initialize(sequence,script,language,enabled)
local features = sequence.features
@@ -11291,7 +10558,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, constants[kind] or false, sequence.chain or 0, kind, sequence }
+ return { valid, special_attributes[kind] or false, sequence.chain or 0, kind, sequence }
end
end
end
@@ -11299,7 +10566,7 @@ local function initialize(sequence,script,language,enabled)
return false
end
-function otf.dataset(tfmdata,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"
@@ -11317,17 +10584,12 @@ function otf.dataset(tfmdata,font) -- generic variant, overloaded in context
end
local rl = rs[language]
if not rl then
- rl = {
- -- indexed but we can also add specific data by key
- }
+ rl = { }
rs[language] = rl
- local sequences = tfmdata.resources.sequences
setmetatableindex(rl, function(t,k)
- if type(k) == "number" then
- local v = enabled and initialize(sequences[k],script,language,enabled)
- t[k] = v
- return v
- end
+ local v = enabled and initialize(sequences[k],script,language,enabled)
+ t[k] = v
+ return v
end)
end
return rl
@@ -11349,8 +10611,6 @@ end
-- start = start.next
-- end
--- there will be a new direction parser (pre-parsed etc)
-
local function featuresprocessor(head,font,attr)
local lookuphash = lookuphashes[font] -- we can also check sequences here
@@ -11378,7 +10638,7 @@ local function featuresprocessor(head,font,attr)
local sequences = resources.sequences
local done = false
- local datasets = otf.dataset(tfmdata,font,attr)
+ local datasets = otf.dataset(tfmdata,sequences,font,attr)
local dirstack = { } -- could move outside function
@@ -11387,9 +10647,6 @@ local function featuresprocessor(head,font,attr)
-- 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.
- -- Keeping track of the headnode is needed for devanagari (I generalized it a bit
- -- so that multiple cases are also covered.
-
for s=1,#sequences do
local dataset = datasets[s]
if dataset then
@@ -11425,12 +10682,8 @@ local function featuresprocessor(head,font,attr)
if lookupcache then
local lookupmatch = lookupcache[start.char]
if lookupmatch then
- local headnode = start == head
start, success = handler(start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
if success then
- if headnode then
- head = start
- end
break
end
end
@@ -11474,14 +10727,10 @@ local function featuresprocessor(head,font,attr)
local lookupmatch = lookupcache[start.char]
if lookupmatch then
-- sequence kan weg
- local headnode = start == head
local ok
start, ok = handler(start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
if ok then
success = true
- if headnode then
- head = start
- end
end
end
if start then start = start.next end
@@ -11551,14 +10800,10 @@ local function featuresprocessor(head,font,attr)
local lookupmatch = lookupcache[start.char]
if lookupmatch then
-- we could move all code inline but that makes things even more unreadable
- local headnode = start == head
local ok
start, ok = handler(start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
if ok then
success = true
- if headnode then
- head = start
- end
break
end
end
@@ -11885,10 +11130,6 @@ registerotffeature {
}
}
--- this will change but is needed for an experiment:
-
-otf.handlers = handlers
-
end -- closure
do -- begin closure to overcome local limits and interference
@@ -12516,6 +11757,388 @@ end -- closure
do -- begin closure to overcome local limits and interference
+if not modules then modules = { } end modules ['font-ota'] = {
+ version = 1.001,
+ comment = "companion to font-otf.lua (analysing)",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this might become scrp-*.lua
+
+local type, tostring, match, format, concat = type, tostring, string.match, string.format, table.concat
+
+if not trackers then trackers = { register = function() end } end
+
+local trace_analyzing = false trackers.register("otf.analyzing", function(v) trace_analyzing = v end)
+
+local fonts, nodes, node = fonts, nodes, node
+
+local allocate = utilities.storage.allocate
+
+local otf = fonts.handlers.otf
+
+local analyzers = fonts.analyzers
+local initializers = allocate()
+local methods = allocate()
+
+analyzers.initializers = initializers
+analyzers.methods = methods
+analyzers.useunicodemarks = false
+
+local nodecodes = nodes.nodecodes
+local glyph_code = nodecodes.glyph
+
+local set_attribute = node.set_attribute
+local has_attribute = node.has_attribute
+local traverse_id = node.traverse_id
+local traverse_node_list = node.traverse
+
+local fontdata = fonts.hashes.identifiers
+local state = attributes.private('state')
+local categories = characters and characters.categories or { } -- sorry, only in context
+
+local tracers = nodes.tracers
+local colortracers = tracers and tracers.colors
+local setnodecolor = colortracers and colortracers.set or function() end
+local resetnodecolor = colortracers and colortracers.reset or function() end
+
+local otffeatures = fonts.constructors.newfeatures("otf")
+local registerotffeature = otffeatures.register
+
+--[[ldx--
+<p>Analyzers run per script and/or language and are needed in order to
+process features right.</p>
+--ldx]]--
+
+-- todo: analyzers per script/lang, cross font, so we need an font id hash -> script
+-- e.g. latin -> hyphenate, arab -> 1/2/3 analyze -- its own namespace
+
+local state = attributes.private('state')
+
+function analyzers.setstate(head,font)
+ local useunicodemarks = analyzers.useunicodemarks
+ local tfmdata = fontdata[font]
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local first, last, current, n, done = nil, nil, head, 0, false -- maybe make n boolean
+ while current do
+ local id = current.id
+ if id == glyph_code and current.font == font then
+ local char = current.char
+ local d = descriptions[char]
+ if d then
+ if d.class == "mark" or (useunicodemarks and categories[char] == "mn") then
+ done = true
+ set_attribute(current,state,5) -- mark
+ elseif n == 0 then
+ first, last, n = current, current, 1
+ set_attribute(current,state,1) -- init
+ else
+ last, n = current, n+1
+ set_attribute(current,state,2) -- medi
+ end
+ else -- finish
+ if first and first == last then
+ set_attribute(last,state,4) -- isol
+ elseif last then
+ set_attribute(last,state,3) -- fina
+ end
+ first, last, n = nil, nil, 0
+ end
+ elseif id == disc_code then
+ -- always in the middle
+ set_attribute(current,state,2) -- midi
+ last = current
+ else -- finish
+ if first and first == last then
+ set_attribute(last,state,4) -- isol
+ elseif last then
+ set_attribute(last,state,3) -- fina
+ end
+ first, last, n = nil, nil, 0
+ end
+ current = current.next
+ end
+ if first and first == last then
+ set_attribute(last,state,4) -- isol
+ elseif last then
+ set_attribute(last,state,3) -- fina
+ end
+ return head, done
+end
+
+-- in the future we will use language/script attributes instead of the
+-- font related value, but then we also need dynamic features which is
+-- somewhat slower; and .. we need a chain of them
+
+local function analyzeinitializer(tfmdata,value) -- attr
+ local script, language = otf.scriptandlanguage(tfmdata) -- attr
+ local action = initializers[script]
+ if action then
+ if type(action) == "function" then
+ return action(tfmdata,value)
+ else
+ local action = action[language]
+ if action then
+ return action(tfmdata,value)
+ end
+ end
+ end
+end
+
+local function analyzeprocessor(head,font,attr)
+ local tfmdata = fontdata[font]
+ local script, language = otf.scriptandlanguage(tfmdata,attr)
+ local action = methods[script]
+ if action then
+ if type(action) == "function" then
+ return action(head,font,attr)
+ else
+ action = action[language]
+ if action then
+ return action(head,font,attr)
+ end
+ end
+ end
+ return head, false
+end
+
+registerotffeature {
+ name = "analyze",
+ description = "analysis of (for instance) character classes",
+ default = true,
+ initializers = {
+ node = analyzeinitializer,
+ },
+ processors = {
+ position = 1,
+ node = analyzeprocessor,
+ }
+}
+
+-- latin
+
+methods.latn = analyzers.setstate
+
+-- this info eventually will go into char-def and we will have a state
+-- table for generic then
+
+local zwnj = 0x200C
+local zwj = 0x200D
+
+local isol = {
+ [0x0600] = true, [0x0601] = true, [0x0602] = true, [0x0603] = true,
+ [0x0608] = true, [0x060B] = true, [0x0621] = true, [0x0674] = true,
+ [0x06DD] = true, [zwnj] = true,
+}
+
+local isol_fina = {
+ [0x0622] = true, [0x0623] = true, [0x0624] = true, [0x0625] = true,
+ [0x0627] = true, [0x0629] = true, [0x062F] = true, [0x0630] = true,
+ [0x0631] = true, [0x0632] = true, [0x0648] = true, [0x0671] = true,
+ [0x0672] = true, [0x0673] = true, [0x0675] = true, [0x0676] = true,
+ [0x0677] = true, [0x0688] = true, [0x0689] = true, [0x068A] = true,
+ [0x068B] = true, [0x068C] = true, [0x068D] = true, [0x068E] = true,
+ [0x068F] = true, [0x0690] = true, [0x0691] = true, [0x0692] = true,
+ [0x0693] = true, [0x0694] = true, [0x0695] = true, [0x0696] = true,
+ [0x0697] = true, [0x0698] = true, [0x0699] = true, [0x06C0] = true,
+ [0x06C3] = true, [0x06C4] = true, [0x06C5] = true, [0x06C6] = true,
+ [0x06C7] = true, [0x06C8] = true, [0x06C9] = true, [0x06CA] = true,
+ [0x06CB] = true, [0x06CD] = true, [0x06CF] = true, [0x06D2] = true,
+ [0x06D3] = true, [0x06D5] = true, [0x06EE] = true, [0x06EF] = true,
+ [0x0759] = true, [0x075A] = true, [0x075B] = true, [0x076B] = true,
+ [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 = {
+ [0x0626] = true, [0x0628] = true, [0x062A] = true, [0x062B] = true,
+ [0x062C] = true, [0x062D] = true, [0x062E] = true, [0x0633] = true,
+ [0x0634] = true, [0x0635] = true, [0x0636] = true, [0x0637] = true,
+ [0x0638] = true, [0x0639] = true, [0x063A] = true, [0x063B] = true,
+ [0x063C] = true, [0x063D] = true, [0x063E] = true, [0x063F] = true,
+ [0x0640] = true, [0x0641] = true, [0x0642] = true, [0x0643] = true,
+ [0x0644] = true, [0x0645] = true, [0x0646] = true, [0x0647] = true,
+ [0x0649] = true, [0x064A] = true, [0x066E] = true, [0x066F] = true,
+ [0x0678] = true, [0x0679] = true, [0x067A] = true, [0x067B] = true,
+ [0x067C] = true, [0x067D] = true, [0x067E] = true, [0x067F] = true,
+ [0x0680] = true, [0x0681] = true, [0x0682] = true, [0x0683] = true,
+ [0x0684] = true, [0x0685] = true, [0x0686] = true, [0x0687] = true,
+ [0x069A] = true, [0x069B] = true, [0x069C] = true, [0x069D] = true,
+ [0x069E] = true, [0x069F] = true, [0x06A0] = true, [0x06A1] = true,
+ [0x06A2] = true, [0x06A3] = true, [0x06A4] = true, [0x06A5] = true,
+ [0x06A6] = true, [0x06A7] = true, [0x06A8] = true, [0x06A9] = true,
+ [0x06AA] = true, [0x06AB] = true, [0x06AC] = true, [0x06AD] = true,
+ [0x06AE] = true, [0x06AF] = true, [0x06B0] = true, [0x06B1] = true,
+ [0x06B2] = true, [0x06B3] = true, [0x06B4] = true, [0x06B5] = true,
+ [0x06B6] = true, [0x06B7] = true, [0x06B8] = true, [0x06B9] = true,
+ [0x06BA] = true, [0x06BB] = true, [0x06BC] = true, [0x06BD] = true,
+ [0x06BE] = true, [0x06BF] = true, [0x06C1] = true, [0x06C2] = true,
+ [0x06CC] = true, [0x06CE] = true, [0x06D0] = true, [0x06D1] = true,
+ [0x06FA] = true, [0x06FB] = true, [0x06FC] = true, [0x06FF] = true,
+ [0x0750] = true, [0x0751] = true, [0x0752] = true, [0x0753] = true,
+ [0x0754] = true, [0x0755] = true, [0x0756] = true, [0x0757] = true,
+ [0x0758] = true, [0x075C] = true, [0x075D] = true, [0x075E] = true,
+ [0x075F] = true, [0x0760] = true, [0x0761] = true, [0x0762] = true,
+ [0x0763] = true, [0x0764] = true, [0x0765] = true, [0x0766] = true,
+ [0x0767] = true, [0x0768] = true, [0x0769] = true, [0x076A] = true,
+ [0x076D] = true, [0x076E] = true, [0x076F] = true, [0x0770] = true,
+ [0x0772] = true, [0x0775] = true, [0x0776] = true, [0x0777] = true,
+ [0x077A] = true, [0x077B] = true, [0x077C] = true, [0x077D] = true,
+ [0x077E] = true, [0x077F] = 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,
+ [0x0724] = true, [0x0725] = true, [0x0726] = true, [0x0727] = true,
+ [0x0729] = true, [0x072B] = true,
+
+ -- also
+
+ [zwj] = true,
+}
+
+local arab_warned = { }
+
+
+-- todo: gref
+
+local function warning(current,what)
+ local char = current.char
+ if not arab_warned[char] then
+ log.report("analyze","arab: character %s (U+%05X) has no %s class", char, char, what)
+ arab_warned[char] = true
+ end
+end
+
+function methods.nocolor(head,font,attr)
+ for n in traverse_id(glyph_code,head) do
+ if not font or n.font == font then
+ resetnodecolor(n)
+ end
+ end
+ return head, true
+end
+
+local function finish(first,last)
+ if last then
+ if first == last then
+ local fc = first.char
+ if isol_fina_medi_init[fc] or isol_fina[fc] then
+ set_attribute(first,state,4) -- isol
+ if trace_analyzing then setnodecolor(first,"font:isol") end
+ else
+ warning(first,"isol")
+ set_attribute(first,state,0) -- error
+ if trace_analyzing then resetnodecolor(first) end
+ end
+ else
+ local lc = last.char
+ if isol_fina_medi_init[lc] or isol_fina[lc] then -- why isol here ?
+ -- if laststate == 1 or laststate == 2 or laststate == 4 then
+ set_attribute(last,state,3) -- fina
+ if trace_analyzing then setnodecolor(last,"font:fina") end
+ else
+ warning(last,"fina")
+ set_attribute(last,state,0) -- error
+ if trace_analyzing then resetnodecolor(last) end
+ end
+ end
+ first, last = nil, nil
+ elseif first then
+ -- first and last are either both set so we never com here
+ local fc = first.char
+ if isol_fina_medi_init[fc] or isol_fina[fc] then
+ set_attribute(first,state,4) -- isol
+ if trace_analyzing then setnodecolor(first,"font:isol") end
+ else
+ warning(first,"isol")
+ set_attribute(first,state,0) -- error
+ if trace_analyzing then resetnodecolor(first) end
+ end
+ first = nil
+ end
+ return first, last
+end
+
+function methods.arab(head,font,attr) -- maybe make a special version with no trace
+ local useunicodemarks = analyzers.useunicodemarks
+ local tfmdata = fontdata[font]
+ local marks = tfmdata.resources.marks
+ local first, last, current, done = nil, nil, head, false
+ while current do
+ if current.id == glyph_code and current.subtype<256 and current.font == font and not has_attribute(current,state) then
+ done = true
+ local char = current.char
+ if marks[char] or (useunicodemarks and categories[char] == "mn") then
+ set_attribute(current,state,5) -- mark
+ if trace_analyzing then setnodecolor(current,"font:mark") end
+ elseif isol[char] then -- can be zwj or zwnj too
+ first, last = finish(first,last)
+ set_attribute(current,state,4) -- isol
+ if trace_analyzing then setnodecolor(current,"font:isol") end
+ first, last = nil, nil
+ elseif not first then
+ if isol_fina_medi_init[char] then
+ set_attribute(current,state,1) -- init
+ if trace_analyzing then setnodecolor(current,"font:init") end
+ first, last = first or current, current
+ elseif isol_fina[char] then
+ set_attribute(current,state,4) -- isol
+ if trace_analyzing then setnodecolor(current,"font:isol") end
+ first, last = nil, nil
+ else -- no arab
+ first, last = finish(first,last)
+ end
+ elseif isol_fina_medi_init[char] then
+ first, last = first or current, current
+ set_attribute(current,state,2) -- medi
+ if trace_analyzing then setnodecolor(current,"font:medi") end
+ elseif isol_fina[char] then
+ if not has_attribute(last,state,1) then
+ -- tricky, we need to check what last may be !
+ set_attribute(last,state,2) -- medi
+ if trace_analyzing then setnodecolor(last,"font:medi") end
+ end
+ set_attribute(current,state,3) -- fina
+ if trace_analyzing then setnodecolor(current,"font:fina") end
+ first, last = nil, nil
+ elseif char >= 0x0600 and char <= 0x06FF then
+ if trace_analyzing then setnodecolor(current,"font:rest") end
+ first, last = finish(first,last)
+ else --no
+ first, last = finish(first,last)
+ end
+ else
+ first, last = finish(first,last)
+ end
+ current = current.next
+ end
+ first, last = finish(first,last)
+ return head, done
+end
+
+methods.syrc = methods.arab
+
+directives.register("otf.analyze.useunicodemarks",function(v)
+ analyzers.useunicodemarks = v
+end)
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
if not modules then modules = { } end modules ['luatex-fonts-lua'] = {
version = 1.001,
comment = "companion to luatex-*.tex",
@@ -12562,8 +12185,6 @@ if not modules then modules = { } end modules ['font-def'] = {
license = "see context related readme files"
}
--- We can overload some of the definers.functions so we don't local them.
-
local concat = table.concat
local format, gmatch, match, find, lower, gsub = string.format, string.gmatch, string.match, string.find, string.lower, string.gsub
local tostring, next = tostring, next
@@ -12600,6 +12221,7 @@ definers.methods = definers.methods or { }
local internalized = allocate() -- internal tex numbers (private)
+
local loadedfonts = constructors.loadedfonts
local designsizes = constructors.designsizes
@@ -12629,7 +12251,7 @@ and prepares a table that will move along as we proceed.</p>
-- name name(sub) name(sub)*spec name*spec
-- name@spec*oeps
-local splitter, splitspecifiers = nil, "" -- not so nice
+local splitter, splitspecifiers = nil, ""
local P, C, S, Cc = lpeg.P, lpeg.C, lpeg.S, lpeg.Cc
@@ -12640,7 +12262,7 @@ local space = P(" ")
definers.defaultlookup = "file"
-local prefixpattern = P(false)
+local prefixpattern = P(false)
local function addspecifier(symbol)
splitspecifiers = splitspecifiers .. symbol
@@ -12676,12 +12298,12 @@ function definers.registersplit(symbol,action,verbosename)
end
end
-local function 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",
- specification, lookup ~= "" and lookup or "[file]", name ~= "" and name or "-",
- sub ~= "" and sub or "-", method ~= "" and method or "-", detail ~= "" and detail or "-")
+ specification, (lookup ~= "" and lookup) or "[file]", (name ~= "" and name) or "-",
+ (sub ~= "" and sub) or "-", (method ~= "" and method) or "-", (detail ~= "" and detail) or "-")
end
if not lookup or lookup == "" then
lookup = definers.defaultlookup
@@ -12701,13 +12323,10 @@ local function makespecification(specification,lookup,name,sub,method,detail,siz
return t
end
-
-definers.makespecification = makespecification
-
function definers.analyze(specification, size)
-- can be optimized with locals
local lookup, name, sub, method, detail = getspecification(specification or "")
- return makespecification(specification, lookup, name, sub, method, detail, size)
+ return definers.makespecification(specification, lookup, name, sub, method, detail, size)
end
--[[ldx--
@@ -12754,7 +12373,7 @@ function resolvers.spec(specification)
if resolved then
specification.resolved = resolved
specification.sub = sub
- specification.forced = file.suffix(resolved)
+ specification.forced = file.extname(resolved)
specification.name = file.removesuffix(resolved)
end
else
@@ -12802,13 +12421,12 @@ specification yet.</p>
function definers.applypostprocessors(tfmdata)
local postprocessors = tfmdata.postprocessors
if postprocessors then
- local properties = tfmdata.properties
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]","-")
- properties.fullname = format("%s-%s",properties.fullname,extrahash)
+ tfmdata.properties.fullname = format("%s-%s",tfmdata.properties.fullname,extrahash)
end
end
end
@@ -13126,14 +12744,18 @@ local otffeatures = fonts.constructors.newfeatures("otf")
local function initializeitlc(tfmdata,value)
if value then
- -- the magic 40 and it formula come from Dohyun Kim but we might need another guess
- local parameters = tfmdata.parameters
+ -- the magic 40 and it formula come from Dohyun Kim
+ local parameters = tfmdata.parameters
local italicangle = parameters.italicangle
if italicangle and italicangle ~= 0 then
- local properties = tfmdata.properties
- local factor = tonumber(value) or 1
- properties.hasitalics = true
- properties.autoitalicamount = factor * (parameters.uwidth or 40)/2
+ local uwidth = (parameters.uwidth or 40)/2
+ for unicode, d in next, tfmdata.descriptions do
+ local it = d.boundingbox[3] - d.width + uwidth
+ if it ~= 0 then
+ d.italic = it
+ end
+ end
+ tfmdata.properties.hasitalics = true
end
end
end
diff --git a/tex/generic/context/luatex/luatex-fonts.lua b/tex/generic/context/luatex/luatex-fonts.lua
index 535519db7..f5045a4e3 100644
--- a/tex/generic/context/luatex/luatex-fonts.lua
+++ b/tex/generic/context/luatex/luatex-fonts.lua
@@ -176,9 +176,9 @@ else
loadmodule('font-otf.lua')
loadmodule('font-otb.lua')
loadmodule('node-inj.lua') -- will be replaced (luatex >= .70)
- loadmodule('font-ota.lua')
loadmodule('font-otn.lua')
-- loadmodule('luatex-fonts-chr.lua')
+ loadmodule('font-ota.lua')
loadmodule('luatex-fonts-lua.lua')
loadmodule('font-def.lua')
loadmodule('luatex-fonts-def.lua')
diff --git a/tex/generic/context/luatex/luatex-mplib.tex b/tex/generic/context/luatex/luatex-mplib.tex
index 8af9f2d8a..ef6dfff95 100644
--- a/tex/generic/context/luatex/luatex-mplib.tex
+++ b/tex/generic/context/luatex/luatex-mplib.tex
@@ -31,15 +31,8 @@
\def\setmplibformat#1{\def\mplibformat{#1}}
\def\setupmplibcatcodes
- {\catcode`\{=12 % could be optional .. not really needed
- \catcode`\}=12 % could be optional .. not really needed
- \catcode`\#=12
- \catcode`\^=12
- \catcode`\~=12
- \catcode`\_=12
- \catcode`\%=12
- \catcode`\&=12
- \catcode`\$=12 }
+ {\catcode`\{=12 \catcode`\}=12 \catcode`\#=12 \catcode`\^=12 \catcode`\~=12
+ \catcode`\_=12 \catcode`\%=12 \catcode`\&=12 \catcode`\$=12 }
\def\mplibcode
{\bgroup