summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/fontloader/misc/fontloader-data-con.lua2
-rw-r--r--src/fontloader/misc/fontloader-font-cff.lua231
-rw-r--r--src/fontloader/misc/fontloader-font-dsp.lua3
-rw-r--r--src/fontloader/misc/fontloader-font-onr.lua197
-rw-r--r--src/fontloader/misc/fontloader-font-osd.lua156
-rw-r--r--src/fontloader/misc/fontloader-font-ota.lua54
-rw-r--r--src/fontloader/misc/fontloader-font-otj.lua42
-rw-r--r--src/fontloader/misc/fontloader-font-otl.lua2
-rw-r--r--src/fontloader/misc/fontloader-font-otr.lua181
-rw-r--r--src/fontloader/misc/fontloader-font-ots.lua68
-rw-r--r--src/fontloader/misc/fontloader-l-table.lua15
-rw-r--r--src/fontloader/misc/fontloader-util-str.lua88
-rw-r--r--src/fontloader/runtime/fontloader-basics-gen.lua100
-rw-r--r--src/fontloader/runtime/fontloader-reference.lua915
14 files changed, 1145 insertions, 909 deletions
diff --git a/src/fontloader/misc/fontloader-data-con.lua b/src/fontloader/misc/fontloader-data-con.lua
index 240538d..c79fca7 100644
--- a/src/fontloader/misc/fontloader-data-con.lua
+++ b/src/fontloader/misc/fontloader-data-con.lua
@@ -91,7 +91,7 @@ function containers.read(container,name)
local storage = container.storage
local stored = storage[name]
if not stored and container.enabled and caches and containers.usecache then
- stored = caches.loaddata(container.readables,name)
+ stored = caches.loaddata(container.readables,name,container.writable)
if stored and stored.cache_version == container.version then
if trace_cache or trace_containers then
report_containers("action %a, category %a, name %a","load",container.subcategory,name)
diff --git a/src/fontloader/misc/fontloader-font-cff.lua b/src/fontloader/misc/fontloader-font-cff.lua
index 8c57b47..1c6bd56 100644
--- a/src/fontloader/misc/fontloader-font-cff.lua
+++ b/src/fontloader/misc/fontloader-font-cff.lua
@@ -26,6 +26,7 @@ local concat, remove = table.concat, table.remove
local floor, abs, round, ceil = math.floor, math.abs, math.round, math.ceil
local P, C, R, S, C, Cs, Ct = lpeg.P, lpeg.C, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpeg.Ct
local lpegmatch = lpeg.match
+local formatters = string.formatters
local readers = fonts.handlers.otf.readers
local streamreader = readers.streamreader
@@ -594,6 +595,7 @@ do
local ymax = 0
local checked = false
local keepcurve = false
+ local version = 2
local function showstate(where)
report("%w%-10s : [%s] n=%i",depth*2,where,concat(stack," ",1,top),top)
@@ -1052,13 +1054,114 @@ do
end
end
- local function unsupported()
+ local function unsupported(t)
if trace_charstrings then
- showstate("unsupported")
+ showstate("unsupported " .. t)
end
top = 0
end
+ local function unsupportedsub(t)
+ if trace_charstrings then
+ showstate("unsupported sub " .. t)
+ end
+ top = 0
+ end
+
+ -- type 1 (not used in type 2)
+
+ local function getstem3()
+ if trace_charstrings then
+ showstate("stem3")
+ end
+ top = 0
+ end
+
+ local function divide()
+ if version == 1 then
+ local d = stack[top]
+ top = top - 1
+ stack[top] = stack[top] / d
+ end
+ end
+
+ local function closepath()
+ if version == 1 then
+ if trace_charstrings then
+ showstate("closepath")
+ end
+ end
+ top = 0
+ end
+
+ local function hsbw()
+ if version == 1 then
+ if trace_charstrings then
+ showstate("dotsection")
+ end
+ width = stack[top]
+ end
+ top = 0
+ end
+
+ local function seac()
+ if version == 1 then
+ if trace_charstrings then
+ showstate("seac")
+ end
+ end
+ top = 0
+ end
+
+ local function sbw()
+ if version == 1 then
+ if trace_charstrings then
+ showstate("sbw")
+ end
+ width = stack[top-1]
+ end
+ top = 0
+ end
+
+ -- these are probably used for special cases i.e. call out to postscript
+
+ local function callothersubr()
+ if version == 1 then
+ -- we don't support this (ok, we could mimick these othersubs)
+ if trace_charstrings then
+ showstate("callothersubr (unsupported)")
+ end
+ end
+ top = 0
+ end
+
+ local function pop()
+ if version == 1 then
+ -- we don't support this
+ if trace_charstrings then
+ showstate("pop (unsupported)")
+ end
+ top = top + 1
+ stack[top] = 0 -- a dummy
+ else
+ top = 0
+ end
+ end
+
+ local function setcurrentpoint()
+ if version == 1 then
+ -- we don't support this
+ if trace_charstrings then
+ showstate("pop (unsupported)")
+ end
+ x = x + stack[top-1]
+ y = y + stack[top]
+ end
+ top = 0
+ end
+
+ -- so far for unsupported postscript
+
-- Bah, we cannot use a fast lpeg because a hint has an unknown size and a
-- runtime capture cannot handle that well.
@@ -1076,7 +1179,7 @@ do
unsupported, -- 10 -- calllocal,
unsupported, -- 11 -- callreturn,
unsupported, -- 12 -- elsewhere
- unsupported, -- 13 -- hsbw
+ hsbw, -- 13 -- hsbw (type 1 cff)
unsupported, -- 14 -- endchar,
unsupported, -- 15
unsupported, -- 16
@@ -1098,6 +1201,17 @@ do
}
local subactions = {
+ -- cff 1
+ [000] = dotsection,
+ [001] = getstem3,
+ [002] = getstem3,
+ [006] = seac,
+ [007] = sbw,
+ [012] = divide,
+ [016] = callothersubr,
+ [017] = pop,
+ [033] = setcurrentpoint,
+ -- cff 2
[034] = hflex,
[035] = flex,
[036] = hflex1,
@@ -1107,23 +1221,29 @@ do
local p_bytes = Ct((P(1)/byte)^0)
local function call(scope,list,bias,process)
- local index = stack[top] + bias
- top = top - 1
- if trace_charstrings then
- showvalue(scope,index,true)
- end
- local str = list[index]
- if str then
- if type(str) == "string" then
- str = lpegmatch(p_bytes,str)
- list[index] = str
- end
- depth = depth + 1
- process(str)
- depth = depth - 1
+ depth = depth + 1
+ if top == 0 then
+ showstate(formatters["unknown %s call"](scope))
+ top = 0
else
- report("unknown %s %i",scope,index)
+ local index = stack[top] + bias
+ top = top - 1
+ if trace_charstrings then
+ showvalue(scope,index,true)
+ end
+ local tab = list[index]
+ if tab then
+ if type(tab) == "string" then
+ tab = lpegmatch(p_bytes,tab)
+ list[index] = tab
+ end
+ process(tab)
+ else
+ showstate(formatters["unknown %s call %i"](scope,index))
+ top = 0
+ end
end
+ depth = depth - 1
end
local function process(tab)
@@ -1131,7 +1251,7 @@ do
local n = #tab
while i <= n do
local t = tab[i]
- if t >= 32 and t<=246 then
+ if t >= 32 and t <= 246 then
-- -107 .. +107
top = top + 1
stack[top] = t - 139
@@ -1196,7 +1316,7 @@ do
local t = tab[i]
local a = subactions[t]
if a then
- a()
+ a(t)
else
if trace_charstrings then
showvalue("<subaction>",t)
@@ -1207,7 +1327,7 @@ do
else
local a = actions[t]
if a then
- local s = a()
+ local s = a(t)
if s then
i = i + s
end
@@ -1260,27 +1380,44 @@ do
-- end
-- end
- parsecharstrings = function(data,glyphs,doshapes)
+ local function setbias(globals,locals)
+ if version == 1 then
+ return
+ false,
+ false
+ else
+ local g, l = #globals, #locals
+ return
+ ((g < 1240 and 107) or (g < 33900 and 1131) or 32768) + 1,
+ ((l < 1240 and 107) or (l < 33900 and 1131) or 32768) + 1
+ end
+ end
+
+ parsecharstrings = function(data,glyphs,doshapes,tversion)
-- for all charstrings
local dictionary = data.dictionaries[1]
local charstrings = dictionary.charstrings
local charset = dictionary.charset
+ local private = dictionary.private or { data = { } }
+
keepcurve = doshapes
+ version = tversion
stack = { }
glyphs = glyphs or { }
strings = data.strings
- locals = dictionary.subroutines
- globals = data.routines
- globalbias = #globals
- localbias = #locals
- globalbias = ((globalbias < 1240 and 107) or (globalbias < 33900 and 1131) or 32768) + 1
- localbias = ((localbias < 1240 and 107) or (localbias < 33900 and 1131) or 32768) + 1
- local nominalwidth = dictionary.private.data.nominalwidthx or 0
- local defaultwidth = dictionary.private.data.defaultwidthx or 0
+ globals = data.routines or { }
+ locals = dictionary.subroutines or { }
+
+ globalbias, localbias = setbias(globals,locals)
+
+ local nominalwidth = private.data.nominalwidthx or 0
+ local defaultwidth = private.data.defaultwidthx or 0
for i=1,#charstrings do
- local str = charstrings[i]
- local tab = lpegmatch(p_bytes,str)
+ local tab = charstrings[i]
+ if type(tab) == "string" then
+ tab = lpegmatch(p_bytes,tab)
+ end
local index = i - 1
x = 0
y = 0
@@ -1341,20 +1478,23 @@ do
return glyphs
end
- parsecharstring = function(data,dictionary,charstring,glyphs,index,doshapes)
+ parsecharstring = function(data,dictionary,tab,glyphs,index,doshapes,tversion)
local private = dictionary.private
keepcurve = doshapes
+ version = tversion
strings = data.strings -- or in dict?
locals = dictionary.subroutines or { }
globals = data.routines or { }
- globalbias = #globals
- localbias = #locals
- globalbias = ((globalbias < 1240 and 107) or (globalbias < 33900 and 1131) or 32768) + 1
- localbias = ((localbias < 1240 and 107) or (localbias < 33900 and 1131) or 32768) + 1
+
+ globalbias, localbias = setbias(globals,locals)
+
local nominalwidth = private and private.data.nominalwidthx or 0
local defaultwidth = private and private.data.defaultwidthx or 0
--
- local tab = lpegmatch(p_bytes,charstring)
+ if type(tab) == "string" then
+ tab = lpegmatch(p_bytes,tab)
+ end
+ --
x = 0
y = 0
width = false
@@ -1384,7 +1524,8 @@ do
width = nominalwidth + width
end
--
-index = index - 1
+ index = index - 1
+ --
local glyph = glyphs[index] -- can be autodefined in otr
if not glyph then
glyphs[index] = {
@@ -1410,8 +1551,6 @@ index = index - 1
report("width: %s",tostring(width))
report("boundingbox: % t",boundingbox)
end
- --
- return charstring
end
resetcharstrings = function()
@@ -1542,7 +1681,7 @@ local function readcidprivates(f,data)
parseprivates(data,dictionaries)
end
-local function readnoselect(f,data,glyphs,doshapes)
+local function readnoselect(f,data,glyphs,doshapes,version)
local dictionaries = data.dictionaries
local dictionary = dictionaries[1]
readglobals(f,data)
@@ -1552,11 +1691,13 @@ local function readnoselect(f,data,glyphs,doshapes)
readprivates(f,data)
parseprivates(data,data.dictionaries)
readlocals(f,data,dictionary)
- parsecharstrings(data,glyphs,doshapes)
+ parsecharstrings(data,glyphs,doshapes,version)
resetcharstrings()
end
-local function readfdselect(f,data,glyphs,doshapes)
+readers.parsecharstrings = parsecharstrings
+
+local function readfdselect(f,data,glyphs,doshapes,version)
local header = data.header
local dictionaries = data.dictionaries
local dictionary = dictionaries[1]
@@ -1615,7 +1756,7 @@ local function readfdselect(f,data,glyphs,doshapes)
readlocals(f,data,dictionaries[i])
end
for i=1,#charstrings do
- parsecharstring(data,dictionaries[fdindex[i]+1],charstrings[i],glyphs,i,doshapes)
+ parsecharstring(data,dictionaries[fdindex[i]+1],charstrings[i],glyphs,i,doshapes,version)
end
resetcharstrings()
end
diff --git a/src/fontloader/misc/fontloader-font-dsp.lua b/src/fontloader/misc/fontloader-font-dsp.lua
index 49d5929..1c81e5e 100644
--- a/src/fontloader/misc/fontloader-font-dsp.lua
+++ b/src/fontloader/misc/fontloader-font-dsp.lua
@@ -53,6 +53,7 @@ local bittest = bit32.btest
local rshift = bit32.rshift
local concat = table.concat
local lower = string.lower
+local copy = table.copy
local sub = string.sub
local strip = string.strip
local tohash = table.tohash
@@ -1698,7 +1699,7 @@ do
flags = d.flags,
-- chain = d.chain,
}
- sublookuplist[nofsublookups] = h
+ sublookuplist[nofsublookups] = copy(h) -- we repack later
sublookuphash[lookupid] = nofsublookups
sublookupcheck[lookupid] = 1
else
diff --git a/src/fontloader/misc/fontloader-font-onr.lua b/src/fontloader/misc/fontloader-font-onr.lua
index dcf7445..6c33b24 100644
--- a/src/fontloader/misc/fontloader-font-onr.lua
+++ b/src/fontloader/misc/fontloader-font-onr.lua
@@ -50,31 +50,41 @@ and <l n='otf'/> reader.</p>
and new vectors (we actually had one bad vector with the old loader).</p>
--ldx]]--
-local get_indexes
+local get_indexes, get_shapes
do
- local n, m
+ local decrypt
- local progress = function(str,position,name,size)
- local forward = position + tonumber(size) + 3 + 2
- n = n + 1
- if n >= m then
- return #str, name
- elseif forward < #str then
- return forward, name
- else
- return #str, name
+ do
+
+ local r, c1, c2, n = 0, 0, 0, 0
+
+ local function step(c)
+ local cipher = byte(c)
+ local plain = bxor(cipher,rshift(r,8))
+ r = ((cipher + r) * c1 + c2) % 65536
+ return char(plain)
end
- end
- local initialize = function(str,position,size)
- n = 0
- m = size -- % tonumber(size)
- return position + 1
+ decrypt = function(binary,initial,seed)
+ r, c1, c2, n = initial, 52845, 22719, seed
+ binary = gsub(binary,".",step)
+ return sub(binary,n+1)
+ end
+
+ -- local pattern = Cs((P(1) / step)^1)
+ --
+ -- decrypt = function(binary,initial,seed)
+ -- r, c1, c2, n = initial, 52845, 22719, seed
+ -- binary = lpegmatch(pattern,binary)
+ -- return sub(binary,n+1)
+ -- end
+
end
local charstrings = P("/CharStrings")
+ local subroutines = P("/Subrs")
local encoding = P("/Encoding")
local dup = P("dup")
local put = P("put")
@@ -85,9 +95,64 @@ do
local spaces = P(" ")^1
local spacing = patterns.whitespace^0
+ local routines, vector, chars, n, m
+
+ local initialize = function(str,position,size)
+ n = 0
+ m = size -- % tonumber(size)
+ return position + 1
+ end
+
+ local setroutine = function(str,position,index,size)
+ local forward = position + tonumber(size)
+ local stream = sub(str,position+1,forward)
+ routines[index] = decrypt(stream,4330,4)
+ return forward
+ end
+
+ local setvector = function(str,position,name,size)
+ local forward = position + tonumber(size)
+ if n >= m then
+ return #str
+ elseif forward < #str then
+ vector[n] = name
+ n = n + 1 -- we compensate for notdef at the cff loader end
+ return forward
+ else
+ return #str
+ end
+ end
+
+ local setshapes = function(str,position,name,size)
+ local forward = position + tonumber(size)
+ local stream = sub(str,position+1,forward)
+ if n > m then
+ return #str
+ elseif forward < #str then
+ vector[n] = name
+ n = n + 1
+ chars [n] = decrypt(stream,4330,4)
+ return forward
+ else
+ return #str
+ end
+ end
+
+ local p_rd = spacing * (P("RD") + P("-|"))
+ local p_np = spacing * (P("NP") + P( "|"))
+ local p_nd = spacing * (P("ND") + P( "|"))
+
+ local p_filterroutines = -- dup <i> <n> RD or -| <n encrypted bytes> NP or |
+ (1-subroutines)^0 * subroutines * spaces * Cmt(cardinal,initialize)
+ * (Cmt(cardinal * spaces * cardinal * p_rd, setroutine) * p_np + P(1))^1
+
+ local p_filtershapes = -- /foo <n> RD <n encrypted bytes> ND
+ (1-charstrings)^0 * charstrings * spaces * Cmt(cardinal,initialize)
+ * (Cmt(name * spaces * cardinal * p_rd, setshapes) * p_nd + P(1))^1
+
local p_filternames = Ct (
(1-charstrings)^0 * charstrings * spaces * Cmt(cardinal,initialize)
- * (Cmt(name * spaces * cardinal, progress) + P(1))^1
+ * (Cmt(name * spaces * cardinal, setvector) + P(1))^1
)
-- /Encoding 256 array
@@ -102,36 +167,7 @@ do
-- if one of first 4 not 0-9A-F then binary else hex
- local decrypt
-
- do
-
- local r, c1, c2, n = 0, 0, 0, 0
-
- local function step(c)
- local cipher = byte(c)
- local plain = bxor(cipher,rshift(r,8))
- r = ((cipher + r) * c1 + c2) % 65536
- return char(plain)
- end
-
- decrypt = function(binary)
- r, c1, c2, n = 55665, 52845, 22719, 4
- binary = gsub(binary,".",step)
- return sub(binary,n+1)
- end
-
- -- local pattern = Cs((P(1) / step)^1)
- --
- -- decrypt = function(binary)
- -- r, c1, c2, n = 55665, 52845, 22719, 4
- -- binary = lpegmatch(pattern,binary)
- -- return sub(binary,n+1)
- -- end
-
- end
-
- local function loadpfbvector(filename)
+ local function loadpfbvector(filename,shapestoo)
-- for the moment limited to encoding only
local data = io.loaddata(resolvers.findfile(filename))
@@ -153,28 +189,36 @@ do
return
end
- binary = decrypt(binary,4)
+ binary = decrypt(binary,55665,4)
- local vector = lpegmatch(p_filternames,binary)
-
--- if vector[1] == ".notdef" then
--- -- tricky
--- vector[0] = table.remove(vector,1)
--- end
-
- for i=1,#vector do
- vector[i-1] = vector[i]
+ local names = { }
+ local encoding = lpegmatch(p_filterencoding,ascii)
+ local glyphs = { }
+
+ routines, vector, chars = { }, { }, { }
+
+ if shapestoo then
+ lpegmatch(p_filterroutines,binary)
+ lpegmatch(p_filtershapes,binary)
+ local data = {
+ dictionaries = {
+ {
+ charstrings = chars,
+ charset = vector,
+ subroutines = routines,
+ }
+ },
+ }
+ fonts.handlers.otf.readers.parsecharstrings(data,glyphs,true,true)
+ else
+ lpegmatch(p_filternames,binary)
end
- vector[#vector] = nil
- if not vector then
- report_pfb("no vector in %a",filename)
- return
- end
+ names = vector
- local encoding = lpegmatch(p_filterencoding,ascii)
+ routines, vector, chars = nil, nil, nil
- return vector, encoding
+ return names, encoding, glyphs
end
@@ -202,6 +246,11 @@ do
end
end
+ get_shapes = function(pfbname)
+ local vector, encoding, glyphs = loadpfbvector(pfbname,true)
+ return glyphs
+ end
+
end
--[[ldx--
@@ -428,6 +477,26 @@ function readers.loadfont(afmname,pfbname)
end
end
+-- for now, todo: n and check with otf (no afm needed here)
+
+function readers.loadshapes(filename)
+ local fullname = resolvers.findfile(filename) or ""
+ if fullname == "" then
+ return {
+ filename = "not found: " .. filename,
+ glyphs = { }
+ }
+ else
+ return {
+ filename = fullname,
+ format = "opentype",
+ glyphs = get_shapes(fullname) or { },
+ units = 1000,
+ }
+ end
+end
+
+
function readers.getinfo(filename)
local data = read(resolvers.findfile(filename),infoparser)
if data then
diff --git a/src/fontloader/misc/fontloader-font-osd.lua b/src/fontloader/misc/fontloader-font-osd.lua
index 26af691..b67cc92 100644
--- a/src/fontloader/misc/fontloader-font-osd.lua
+++ b/src/fontloader/misc/fontloader-font-osd.lua
@@ -613,13 +613,12 @@ local function initializedevanagi(tfmdata)
local steps = sequence.steps
local nofsteps = sequence.nofsteps
local features = sequence.features
- if features["rphf"] then
- -- deva
+ local has_rphf = features.rphf
+ local has_blwf = features.blwf
+ if has_rphf and has_rphf.deva then
devanagari.reph = true
- elseif features["blwf"] then
- -- deva
+ elseif has_blwf and has_blwf.deva then
devanagari.vattu = true
- -- dev2
for i=1,nofsteps do
local step = steps[i]
local coverage = step.coverage
@@ -632,59 +631,71 @@ local function initializedevanagi(tfmdata)
end
end
end
- if valid[kind] then
- for i=1,nofsteps do
- local step = steps[i]
- local coverage = step.coverage
- if coverage then
- local reph = false
- if step.osdstep then
- -- rphf acts on consonant + halant
- for k, v in next, ra do
- local r = coverage[k]
- if r then
- local h = false
- for k, v in next, halant do
- local h = r[k]
- if h then
- reph = h.ligature or false
- break
+ for kind, spec in next, features do -- beware, this is
+ if spec.dev2 and valid[kind] then
+ for i=1,nofsteps do
+ local step = steps[i]
+ local coverage = step.coverage
+ if coverage then
+ local reph = false
+ if kind == "rphf" then
+ --
+ -- KE: I don't understand the rationale behind osdstep. The original if
+ -- statement checked whether coverage is contextual chaining.
+ --
+ -- HH: The osdstep signals that we deal with our own feature here, not
+ -- one in the font itself so it was just a safeguard against us overloading
+ -- something driven by the font.
+ --
+ -- if step.osdstep then -- selective
+ if true then -- always
+ -- rphf acts on consonant + halant
+ for k, v in next, ra do
+ local r = coverage[k]
+ if r then
+ local h = false
+ for k, v in next, halant do
+ local h = r[k]
+ if h then
+ reph = h.ligature or false
+ break
+ end
+ end
+ if reph then
+ break
+ end
end
end
- if reph then
- break
- end
+ else
+ -- rphf might be result of other handler/chainproc
end
end
- else
- -- rphf might be result of other handler/chainproc
+ seqsubset[#seqsubset+1] = { kind, coverage, reph }
end
- seqsubset[#seqsubset+1] = { kind, coverage, reph }
end
end
- end
- if kind == "pref" then
- local sequence = dataset[3] -- was [5]
- local steps = sequence.steps
- local nofsteps = sequence.nofsteps
- for i=1,nofsteps do
- local step = steps[i]
- local coverage = step.coverage
- if coverage then
- for k, v in next, halant do
- local h = coverage[k]
- if h then
- local found = false
- for k, v in next, h do
- found = v and v.ligature
+ if kind == "pref" then
+ local steps = sequence.steps
+ local nofsteps = sequence.nofsteps
+ for i=1,nofsteps do
+ local step = steps[i]
+ local coverage = step.coverage
+ if coverage then
+ for k, v in next, halant do
+ local h = coverage[k]
+ if h then
+ local found = false
+ for k, v in next, h do
+ found = v and v.ligature
+ if found then
+ pre_base_reordering_consonants[k] = found
+ break
+ end
+ end
if found then
- pre_base_reordering_consonants[k] = found
break
end
end
- if found then
- break
- end
end
end
end
@@ -1132,6 +1143,8 @@ function handlers.devanagari_reorder_matras(head,start) -- no leak
start = startnext
break
end
+ else
+ break
end
current = next
end
@@ -1171,12 +1184,12 @@ function handlers.devanagari_reorder_reph(head,start)
local startfont = getfont(start)
local startattr = getprop(start,a_syllabe)
while current do
- local char = ischar(current,font)
+ local char = ischar(current,startfont)
if char and getprop(current,a_syllabe) == startattr then -- step 2
if halant[char] and not getprop(current,a_state) then
local next = getnext(current)
if next then
- local nextchar = ischar(next,font)
+ local nextchar = ischar(next,startfont)
if nextchar and zw_char[nextchar] and getprop(next,a_syllabe) == startattr then
current = next
next = getnext(current)
@@ -1198,7 +1211,7 @@ function handlers.devanagari_reorder_reph(head,start)
if not startnext then
current = getnext(start)
while current do
- local char = ischar(current,font)
+ local char = ischar(current,startfont)
if char and getprop(current,a_syllabe) == startattr then -- step 4
if getprop(current,a_state) == s_pstf then -- post-base
startnext = getnext(start)
@@ -1223,7 +1236,7 @@ function handlers.devanagari_reorder_reph(head,start)
current = getnext(start)
local c = nil
while current do
- local char = ischar(current,font)
+ local char = ischar(current,startfont)
if char and getprop(current,a_syllabe) == startattr then -- step 5
if not c and mark_above_below_post[char] and reorder_class[char] ~= "after subscript" then
c = current
@@ -1250,7 +1263,7 @@ function handlers.devanagari_reorder_reph(head,start)
current = start
local next = getnext(current)
while next do
- local nextchar = ischar(next,font)
+ local nextchar = ischar(next,startfont)
if nextchar and getprop(next,a_syllabe) == startattr then --step 6
current = next
next = getnext(current)
@@ -1263,7 +1276,7 @@ function handlers.devanagari_reorder_reph(head,start)
head = remove_node(head,start)
local next = getnext(current)
setlink(start,next)
- setlink(current,"next",start)
+ setlink(current,start)
start = startnext
end
end
@@ -1290,12 +1303,12 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
local startattr = getprop(start,a_syllabe)
-- can be fast for loop + caching state
while current do
- local char = ischar(current,font)
+ local char = ischar(current,startfont)
if char and getprop(current,a_syllabe) == startattr then
local next = getnext(current)
if halant[char] and not getprop(current,a_state) then
if next then
- local nextchar = ischar(next,font)
+ local nextchar = ischar(next,startfont)
if nextchar and getprop(next,a_syllabe) == startattr then
if nextchar == c_zwnj or nextchar == c_zwj then
current = next
@@ -1319,13 +1332,13 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
current = getnext(start)
startattr = getprop(start,a_syllabe)
while current do
- local char = ischar(current,font)
+ local char = ischar(current,startfont)
if char and getprop(current,a_syllabe) == startattr then
if not consonant[char] and getprop(current,a_state) then -- main
startnext = getnext(start)
removenode(start,start)
local prev = getprev(current)
- setlink(start,prev)
+ setlink(prev,start)
setlink(start,current)
start = startnext
break
@@ -1426,21 +1439,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) -- maybe do a pa
local kind = subset[1]
local lookupcache = subset[2]
if kind == "rphf" then
- for k, v in next, ra do
- local r = lookupcache[k]
- if r then
- for k, v in next, halant do
- local h = r[k]
- if h then
- reph = h.ligature or false
- break
- end
- end
- if reph then
- break
- end
- end
- end
+ reph = subset[3]
local current = start
local last = getnext(stop)
while current ~= last do
@@ -1473,7 +1472,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) -- maybe do a pa
if current ~= stop then
local c = locl[current] or getchar(current)
local found = lookupcache[c]
- if found then
+ if found then -- pre-base: pref Halant + Consonant
local next = getnext(current)
local n = locl[next] or getchar(next)
if found[n] then
@@ -1718,7 +1717,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) -- maybe do a pa
local prev = getprev(current)
if prev ~= target then
local next = getnext(current)
- setlink(next,prev)
+ setlink(prev,next)
if current == stop then
stop = prev
end
@@ -1752,7 +1751,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) -- maybe do a pa
stop = current
end
local prev = getprev(c)
- setlink(next,prev)
+ setlink(prev,next)
local nextnext = getnext(next)
setnext(current,nextnext)
local nextnextnext = getnext(nextnext)
@@ -1766,6 +1765,9 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) -- maybe do a pa
end
if getchar(base) == c_nbsp then
+ if base == stop then
+ stop = getprev(stop)
+ end
nbspaces = nbspaces - 1
head = remove_node(head, base)
flush_node(base)
@@ -1815,7 +1817,7 @@ local function analyze_next_chars_one(c,font,variant) -- skip one dependent vowe
elseif (vv == c_zwnj or vv == c_zwj) and halant[vvv] then
local nnnn = getnext(nnn)
if nnnn then
- local vvvv = ischar(nnnn)
+ local vvvv = ischar(nnnn,font)
if vvvv and consonant[vvvv] then
c = nnnn
end
@@ -1838,7 +1840,7 @@ local function analyze_next_chars_one(c,font,variant) -- skip one dependent vowe
local nn = getnext(n)
if nn then
local vv = ischar(nn,font)
- if vv and zw_char[vv] then
+ if vv and zw_char[v] then
n = nn
v = vv
nn = getnext(nn)
diff --git a/src/fontloader/misc/fontloader-font-ota.lua b/src/fontloader/misc/fontloader-font-ota.lua
index 4ddb831..b8944e0 100644
--- a/src/fontloader/misc/fontloader-font-ota.lua
+++ b/src/fontloader/misc/fontloader-font-ota.lua
@@ -262,36 +262,44 @@ local classifiers = characters.classifiers
if not classifiers then
- local first_arabic, last_arabic = characters.blockrange("arabic")
- local first_syriac, last_syriac = characters.blockrange("syriac")
- local first_mandiac, last_mandiac = characters.blockrange("mandiac")
- local first_nko, last_nko = characters.blockrange("nko")
+ local f_arabic, l_arabic = characters.blockrange("arabic")
+ local f_syriac, l_syriac = characters.blockrange("syriac")
+ local f_mandiac, l_mandiac = characters.blockrange("mandiac")
+ local f_nko, l_nko = characters.blockrange("nko")
+ local f_ext_a, l_ext_a = characters.blockrange("arabicextendeda")
classifiers = table.setmetatableindex(function(t,k)
- local c = chardata[k]
- local v = false
- if c then
- local arabic = c.arabic
- if arabic then
- v = mappers[arabic]
- if not v then
- log.report("analyze","error in mapping arabic %C",k)
- -- error
- v = false
- end
- elseif k >= first_arabic and k <= last_arabic or k >= first_syriac and k <= last_syriac or
- k >= first_mandiac and k <= last_mandiac or k >= first_nko and k <= last_nko then
- if categories[k] == "mn" then
- v = s_mark
- else
- v = s_rest
+ if type(k) == "number" then
+ local c = chardata[k]
+ local v = false
+ if c then
+ local arabic = c.arabic
+ if arabic then
+ v = mappers[arabic]
+ if not v then
+ log.report("analyze","error in mapping arabic %C",k)
+ -- error
+ v = false
+ end
+ elseif (k >= f_arabic and k <= l_arabic) or
+ (k >= f_syriac and k <= l_syriac) or
+ (k >= f_mandiac and k <= l_mandiac) or
+ (k >= f_nko and k <= l_nko) or
+ (k >= f_ext_a and k <= l_ext_a) then
+ if categories[k] == "mn" then
+ v = s_mark
+ else
+ v = s_rest
+ end
end
end
+ t[k] = v
+ return v
end
- t[k] = v
- return v
end)
+ characters.classifiers = classifiers
+
end
function methods.arab(head,font,attr)
diff --git a/src/fontloader/misc/fontloader-font-otj.lua b/src/fontloader/misc/fontloader-font-otj.lua
index 46b2ca8..68cf608 100644
--- a/src/fontloader/misc/fontloader-font-otj.lua
+++ b/src/fontloader/misc/fontloader-font-otj.lua
@@ -377,7 +377,8 @@ function injections.setkern(current,factor,rlmode,x,injection)
end
end
-function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk) -- ba=baseanchor, ma=markanchor
+function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk,checkmark) -- ba=baseanchor, ma=markanchor
+
local dx, dy = factor*(ba[1]-ma[1]), factor*(ba[2]-ma[2])
nofregisteredmarks = nofregisteredmarks + 1
if rlmode >= 0 then
@@ -398,6 +399,7 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk) -- ba=b
i.markbase = nofregisteredmarks
i.markbasenode = base
i.markmark = mkmk
+ i.checkmark = checkmark
end
else
p.injections = {
@@ -407,6 +409,7 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk) -- ba=b
markbase = nofregisteredmarks,
markbasenode = base,
markmark = mkmk,
+ checkmark = checkmark,
}
end
else
@@ -418,6 +421,7 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk) -- ba=b
markbase = nofregisteredmarks,
markbasenode = base,
markmark = mkmk,
+ checkmark = checkmark,
},
}
end
@@ -1062,11 +1066,22 @@ local function inject_everything(head,where)
ox = px - pn.markx
-- report_injections("l2r case 3: %p",ox)
-- end
- local wn = getfield(n,"width") -- in arial marks have widths
- if wn ~= 0 then
- -- bad: we should center
- pn.leftkern = -wn/2
- pn.rightkern = -wn/2
+ if pn.checkmark then
+ local wn = getfield(n,"width") -- in arial marks have widths
+ if wn ~= 0 then
+ wn = wn/2
+ if trace_injections then
+ report_injections("correcting non zero width mark %C",getchar(n))
+ end
+ -- -- bad: we should center
+ -- pn.leftkern = -wn
+ -- pn.rightkern = -wn
+ -- -- we're too late anyway as kerns are already injected so
+ -- -- we do it the ugly way (no checking if the previous is
+ -- -- already a kern) .. maybe we should fix the font instead
+ insert_node_before(n,n,newkern(-wn))
+ insert_node_after(n,n,newkern(-wn))
+ end
end
end
local oy = getfield(n,"yoffset") + getfield(p,"yoffset") + pn.marky
@@ -1092,10 +1107,10 @@ local function inject_everything(head,where)
nofmarks = nofmarks + 1
marks[nofmarks] = current
else
-local yoffset = i.yoffset
-if yoffset and yoffset ~= 0 then
- setfield(current,"yoffset",yoffset)
-end
+ local yoffset = i.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(current,"yoffset",yoffset)
+ end
if hascursives then
local cursivex = i.cursivex
if cursivex then
@@ -1148,10 +1163,6 @@ end
end
end
-- left|glyph|right
--- local yoffset = i.yoffset
--- if yoffset and yoffset ~= 0 then
--- setfield(current,"yoffset",yoffset)
--- end
local leftkern = i.leftkern
if leftkern and leftkern ~= 0 then
insert_node_before(head,current,newkern(leftkern))
@@ -1166,7 +1177,7 @@ end
local i = p.emptyinjections
if i then
-- glyph|disc|glyph (special case)
--- okay?
+ -- okay?
local rightkern = i.rightkern
if rightkern and rightkern ~= 0 then
if next and getid(next) == disc_code then
@@ -1561,6 +1572,7 @@ function injections.handler(head,where)
if triggers then
head = injectspaces(head)
end
+ -- todo: marks only run too
if nofregisteredmarks > 0 or nofregisteredcursives > 0 then
if trace_injections then
report_injections("injection variant %a","everything")
diff --git a/src/fontloader/misc/fontloader-font-otl.lua b/src/fontloader/misc/fontloader-font-otl.lua
index 94f6a45..0662290 100644
--- a/src/fontloader/misc/fontloader-font-otl.lua
+++ b/src/fontloader/misc/fontloader-font-otl.lua
@@ -52,7 +52,7 @@ local report_otf = logs.reporter("fonts","otf loading")
local fonts = fonts
local otf = fonts.handlers.otf
-otf.version = 3.025 -- beware: also sync font-mis.lua and in mtx-fonts
+otf.version = 3.026 -- beware: also sync font-mis.lua and in mtx-fonts
otf.cache = containers.define("fonts", "otl", otf.version, true)
otf.svgcache = containers.define("fonts", "svg", otf.version, true)
otf.pdfcache = containers.define("fonts", "pdf", otf.version, true)
diff --git a/src/fontloader/misc/fontloader-font-otr.lua b/src/fontloader/misc/fontloader-font-otr.lua
index 7c81285..9cdbc3d 100644
--- a/src/fontloader/misc/fontloader-font-otr.lua
+++ b/src/fontloader/misc/fontloader-font-otr.lua
@@ -1747,118 +1747,6 @@ function readers.math(f,fontdata,specification)
end
end
--- Goodie. A sequence instead of segments costs a bit more memory, some 300K on a
--- dejavu serif and about the same on a pagella regular.
-
-local function packoutlines(data,makesequence)
- local subfonts = data.subfonts
- if subfonts then
- for i=1,#subfonts do
- packoutlines(subfonts[i],makesequence)
- end
- return
- end
- local common = data.segments
- if common then
- return
- end
- local glyphs = data.glyphs
- if not glyphs then
- return
- end
- if makesequence then
- for index=1,#glyphs do
- local glyph = glyphs[index]
- local segments = glyph.segments
- if segments then
- local sequence = { }
- local nofsequence = 0
- for i=1,#segments do
- local segment = segments[i]
- local nofsegment = #segment
- nofsequence = nofsequence + 1
- sequence[nofsequence] = segment[nofsegment]
- for i=1,nofsegment-1 do
- nofsequence = nofsequence + 1
- sequence[nofsequence] = segment[i]
- end
- end
- glyph.sequence = sequence
- glyph.segments = nil
- end
- end
- else
- local hash = { }
- local common = { }
- local reverse = { }
- local last = 0
- for index=1,#glyphs do
- local segments = glyphs[index].segments
- if segments then
- for i=1,#segments do
- local h = concat(segments[i]," ")
- hash[h] = (hash[h] or 0) + 1
- end
- end
- end
- for index=1,#glyphs do
- local segments = glyphs[index].segments
- if segments then
- for i=1,#segments do
- local segment = segments[i]
- local h = concat(segment," ")
- if hash[h] > 1 then -- minimal one shared in order to hash
- local idx = reverse[h]
- if not idx then
- last = last + 1
- reverse[h] = last
- common[last] = segment
- idx = last
- end
- segments[i] = idx
- end
- end
- end
- end
- if last > 0 then
- data.segments = common
- end
- end
-end
-
-local function unpackoutlines(data)
- local subfonts = data.subfonts
- if subfonts then
- for i=1,#subfonts do
- unpackoutlines(subfonts[i])
- end
- return
- end
- local common = data.segments
- if not common then
- return
- end
- local glyphs = data.glyphs
- if not glyphs then
- return
- end
- for index=1,#glyphs do
- local segments = glyphs[index].segments
- if segments then
- for i=1,#segments do
- local c = common[segments[i]]
- if c then
- segments[i] = c
- end
- end
- end
- end
- data.segments = nil
-end
-
-otf.packoutlines = packoutlines
-otf.unpackoutlines = unpackoutlines
-
-- Now comes the loader. The order of reading these matters as we need to know
-- some properties in order to read following tables. When details is true we also
-- initialize the glyphs data.
@@ -2152,6 +2040,15 @@ function readers.loadshapes(filename,n)
shapes = true,
subfont = n,
}
+ if fontdata then
+ -- easier on luajit but still we can hit the 64 K stack constants issue
+ for k, v in next, fontdata.glyphs do
+ v.class = nil
+ v.index = nil
+ v.math = nil
+ -- v.name = nil
+ end
+ end
return fontdata and {
-- version = 0.123 -- todo
filename = filename,
@@ -2302,63 +2199,3 @@ function readers.extend(fontdata)
end
end
end
-
--- for now .. this will move to a context specific file
-
-if fonts.hashes then
-
- local identifiers = fonts.hashes.identifiers
- local loadshapes = readers.loadshapes
-
- readers.version = 0.006
- readers.cache = containers.define("fonts", "shapes", readers.version, true)
-
- -- todo: loaders per format
-
- local function load(filename,sub)
- local base = file.basename(filename)
- local name = file.removesuffix(base)
- local kind = file.suffix(filename)
- local attr = lfs.attributes(filename)
- local size = attr and attr.size or 0
- local time = attr and attr.modification or 0
- local sub = tonumber(sub)
- if size > 0 and (kind == "otf" or kind == "ttf" or kind == "tcc") then
- local hash = containers.cleanname(base) -- including suffix
- if sub then
- hash = hash .. "-" .. sub
- end
- data = containers.read(readers.cache,hash)
- if not data or data.time ~= time or data.size ~= size then
- data = loadshapes(filename,sub)
- if data then
- data.size = size
- data.format = data.format or (kind == "otf" and "opentype") or "truetype"
- data.time = time
- packoutlines(data)
- containers.write(readers.cache,hash,data)
- data = containers.read(readers.cache,hash) -- frees old mem
- end
- end
- unpackoutlines(data)
- else
- data = {
- filename = filename,
- size = 0,
- time = time,
- format = "unknown",
- units = 1000,
- glyphs = { }
- }
- end
- return data
- end
-
- fonts.hashes.shapes = table.setmetatableindex(function(t,k)
- local d = identifiers[k]
- local v = load(d.properties.filename,d.subindex)
- t[k] = v
- return v
- end)
-
-end
diff --git a/src/fontloader/misc/fontloader-font-ots.lua b/src/fontloader/misc/fontloader-font-ots.lua
index d371156..da5d50a 100644
--- a/src/fontloader/misc/fontloader-font-ots.lua
+++ b/src/fontloader/misc/fontloader-font-ots.lua
@@ -254,6 +254,7 @@ local marks = false
local currentfont = false
local factor = 0
local threshold = 0
+local checkmarks = false
local sweepnode = nil
local sweepprev = nil
@@ -959,7 +960,7 @@ function handlers.gpos_mark2base(head,start,dataset,sequence,markanchors,rlmode)
local ba = markanchors[1][basechar]
if ba then
local ma = markanchors[2]
- local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar])
+ local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
if trace_marks then
logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)",
pref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy)
@@ -1015,7 +1016,7 @@ function handlers.gpos_mark2ligature(head,start,dataset,sequence,markanchors,rlm
local index = getligaindex(start)
ba = ba[index]
if ba then
- local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar]) -- index
+ local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
if trace_marks then
logprocess("%s, anchor %s, index %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)",
pref(dataset,sequence),anchor,index,bound,gref(markchar),gref(basechar),index,dx,dy)
@@ -1064,7 +1065,7 @@ function handlers.gpos_mark2mark(head,start,dataset,sequence,markanchors,rlmode)
local ba = markanchors[1][basechar] -- slot 1 has been made copy of the class hash
if ba then
local ma = markanchors[2]
- local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true)
+ local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true,checkmarks)
if trace_marks then
logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)",
pref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy)
@@ -1532,7 +1533,7 @@ function chainprocs.gpos_mark2base(head,start,stop,dataset,sequence,currentlooku
if ba then
local ma = markanchors[2]
if ma then
- local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar])
+ local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
if trace_marks then
logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)",
cref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy)
@@ -1599,7 +1600,7 @@ function chainprocs.gpos_mark2ligature(head,start,stop,dataset,sequence,currentl
local index = getligaindex(start)
ba = ba[index]
if ba then
- local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar])
+ local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
if trace_marks then
logprocess("%s, anchor %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)",
cref(dataset,sequence),anchor,a or bound,gref(markchar),gref(basechar),index,dx,dy)
@@ -1652,7 +1653,7 @@ function chainprocs.gpos_mark2mark(head,start,stop,dataset,sequence,currentlooku
if ba then
local ma = markanchors[2]
if ma then
- local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true)
+ local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true,checkmarks)
if trace_marks then
logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)",
cref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy)
@@ -3381,6 +3382,7 @@ local function featuresprocessor(head,font,attr)
marks = tfmdata.resources.marks
threshold,
factor = getthreshold(font)
+ checkmarks = tfmdata.properties.checkmarks
elseif currentfont ~= font then
@@ -3665,7 +3667,7 @@ if fontfeatures then
function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr)
local features = fontfeatures[font]
- local enabled = features.spacekern == true and features.kern == true
+ local enabled = features and features.spacekern and features.kern
if enabled then
setspacekerns(font,sequence)
end
@@ -3677,7 +3679,7 @@ else -- generic (no hashes)
function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr)
local shared = fontdata[font].shared
local features = shared and shared.features
- local enabled = features and features.spacekern == true and features.kern == true
+ local enabled = features and features.spacekern and features.kern
if enabled then
setspacekerns(font,sequence)
end
@@ -3739,7 +3741,7 @@ local function spaceinitializer(tfmdata,value) -- attr
if kern then
if feat then
for script, languages in next, kern do
- local f = feat[k]
+ local f = feat[script]
if f then
for l in next, languages do
f[l] = true
@@ -3752,26 +3754,42 @@ local function spaceinitializer(tfmdata,value) -- attr
feat = kern
end
for i=1,#steps do
- local step = steps[i]
+ local step = steps[i]
local coverage = step.coverage
- if coverage then
- local kerns = coverage[32]
+ local rules = step.rules
+ local format = step.format
+ if rules then
+ -- not now: analyze (simple) rules
+ elseif coverage then
+ -- what to do if we have no [1] but only [2]
+ local single = format == gpos_single
+ local kerns = coverage[32]
if kerns then
for k, v in next, kerns do
- if type(v) == "table" then
- right[k] = v[3] -- needs checking
- else
+ if type(v) ~= "table" then
right[k] = v
+ elseif single then
+ right[k] = v[3]
+ else
+ local one = v[1]
+ if one then
+ right[k] = one[3]
+ end
end
end
end
for k, v in next, coverage do
local kern = v[32]
if kern then
- if type(kern) == "table" then
- left[k] = kern[3] -- needs checking
- else
+ if type(kern) ~= "table" then
left[k] = kern
+ elseif single then
+ left[k] = v[3]
+ else
+ local one = v[1]
+ if one then
+ left[k] = one[3]
+ end
end
end
end
@@ -3822,3 +3840,17 @@ registerotffeature {
node = spaceinitializer,
},
}
+
+local function markinitializer(tfmdata,value)
+ local properties = tfmdata.properties
+ properties.checkmarks = value
+end
+
+registerotffeature {
+ name = "checkmarks",
+ description = "check mark widths",
+ default = true,
+ initializers = {
+ node = markinitializer,
+ },
+}
diff --git a/src/fontloader/misc/fontloader-l-table.lua b/src/fontloader/misc/fontloader-l-table.lua
index d1e0592..498f518 100644
--- a/src/fontloader/misc/fontloader-l-table.lua
+++ b/src/fontloader/misc/fontloader-l-table.lua
@@ -478,7 +478,7 @@ function table.fromhash(t)
return hsh
end
-local noquotes, hexify, handle, compact, inline, functions
+local noquotes, hexify, handle, compact, inline, functions, metacheck
local reserved = table.tohash { -- intercept a language inconvenience: no reserved words as key
'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for', 'function', 'if',
@@ -608,7 +608,8 @@ local function do_serialize(root,name,depth,level,indexed)
if compact then
last = #root
for k=1,last do
- if root[k] == nil then
+ -- if root[k] == nil then
+ if rawget(root,k) == nil then
last = k - 1
break
end
@@ -817,6 +818,7 @@ local function serialize(_handle,root,name,specification) -- handle wins
functions = specification.functions
compact = specification.compact
inline = specification.inline and compact
+ metacheck = specification.metacheck
if functions == nil then
functions = true
end
@@ -826,6 +828,9 @@ local function serialize(_handle,root,name,specification) -- handle wins
if inline == nil then
inline = compact
end
+ if metacheck == nil then
+ metacheck = true
+ end
else
noquotes = false
hexify = false
@@ -833,6 +838,7 @@ local function serialize(_handle,root,name,specification) -- handle wins
compact = true
inline = true
functions = true
+ metacheck = true
end
if tname == "string" then
if name == "return" then
@@ -857,8 +863,9 @@ local function serialize(_handle,root,name,specification) -- handle wins
end
if root then
-- The dummy access will initialize a table that has a delayed initialization
- -- using a metatable. (maybe explicitly test for metatable)
- if getmetatable(root) then -- todo: make this an option, maybe even per subtable
+ -- using a metatable. (maybe explicitly test for metatable). This can crash on
+ -- metatables that check the index against a number.
+ if metacheck and getmetatable(root) then
local dummy = root._w_h_a_t_e_v_e_r_
root._w_h_a_t_e_v_e_r_ = nil
end
diff --git a/src/fontloader/misc/fontloader-util-str.lua b/src/fontloader/misc/fontloader-util-str.lua
index a54a4aa..42dbf16 100644
--- a/src/fontloader/misc/fontloader-util-str.lua
+++ b/src/fontloader/misc/fontloader-util-str.lua
@@ -10,7 +10,7 @@ utilities = utilities or { }
utilities.strings = utilities.strings or { }
local strings = utilities.strings
-local format, gsub, rep, sub = string.format, string.gsub, string.rep, string.sub
+local format, gsub, rep, sub, find = string.format, string.gsub, string.rep, string.sub, string.find
local load, dump = load, string.dump
local tonumber, type, tostring = tonumber, type, tostring
local unpack, concat = table.unpack, table.concat
@@ -385,6 +385,43 @@ function number.signed(i)
end
end
+-- maybe to util-num
+
+local digit = patterns.digit
+local period = patterns.period
+local three = digit * digit * digit
+
+local splitter = Cs (
+ (((1 - (three^1 * period))^1 + C(three)) * (Carg(1) * three)^1 + C((1-period)^1))
+ * (P(1)/"" * Carg(2)) * C(2)
+)
+
+patterns.formattednumber = splitter
+
+function number.formatted(n,sep1,sep2)
+ local s = type(s) == "string" and n or format("%0.2f",n)
+ if sep1 == true then
+ return lpegmatch(splitter,s,1,".",",")
+ elseif sep1 == "." then
+ return lpegmatch(splitter,s,1,sep1,sep2 or ",")
+ elseif sep1 == "," then
+ return lpegmatch(splitter,s,1,sep1,sep2 or ".")
+ else
+ return lpegmatch(splitter,s,1,sep1 or ",",sep2 or ".")
+ end
+end
+
+-- print(number.formatted(1))
+-- print(number.formatted(12))
+-- print(number.formatted(123))
+-- print(number.formatted(1234))
+-- print(number.formatted(12345))
+-- print(number.formatted(123456))
+-- print(number.formatted(1234567))
+-- print(number.formatted(12345678))
+-- print(number.formatted(12345678,true))
+-- print(number.formatted(1234.56,"!","?"))
+
local zero = P("0")^1 / ""
local plus = P("+") / ""
local minus = P("-")
@@ -732,43 +769,6 @@ local format_W = function(f) -- handy when doing depth related indent
return format("nspaces[%s]",tonumber(f) or 0)
end
--- maybe to util-num
-
-local digit = patterns.digit
-local period = patterns.period
-local three = digit * digit * digit
-
-local splitter = Cs (
- (((1 - (three^1 * period))^1 + C(three)) * (Carg(1) * three)^1 + C((1-period)^1))
- * (P(1)/"" * Carg(2)) * C(2)
-)
-
-patterns.formattednumber = splitter
-
-function number.formatted(n,sep1,sep2)
- local s = type(s) == "string" and n or format("%0.2f",n)
- if sep1 == true then
- return lpegmatch(splitter,s,1,".",",")
- elseif sep1 == "." then
- return lpegmatch(splitter,s,1,sep1,sep2 or ",")
- elseif sep1 == "," then
- return lpegmatch(splitter,s,1,sep1,sep2 or ".")
- else
- return lpegmatch(splitter,s,1,sep1 or ",",sep2 or ".")
- end
-end
-
--- print(number.formatted(1))
--- print(number.formatted(12))
--- print(number.formatted(123))
--- print(number.formatted(1234))
--- print(number.formatted(12345))
--- print(number.formatted(123456))
--- print(number.formatted(1234567))
--- print(number.formatted(12345678))
--- print(number.formatted(12345678,true))
--- print(number.formatted(1234.56,"!","?"))
-
local format_m = function(f)
n = n + 1
if not f or f == "" then
@@ -801,9 +801,16 @@ end
local format_extension = function(extensions,f,name)
local extension = extensions[name] or "tostring(%s)"
local f = tonumber(f) or 1
+ local w = find(extension,"%.%.%.")
if f == 0 then
+ if w then
+ extension = gsub(extension,"%.%.%.","")
+ end
return extension
elseif f == 1 then
+ if w then
+ extension = gsub(extension,"%.%.%.","%%s")
+ end
n = n + 1
local a = "a" .. n
return format(extension,a,a) -- maybe more times?
@@ -811,6 +818,11 @@ local format_extension = function(extensions,f,name)
local a = "a" .. (n + f + 1)
return format(extension,a,a)
else
+ if w then
+ extension = gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s")
+ end
+ -- we could fill an array and then n = n + 1 unpack(t,n,n+f) but as we
+ -- cache we don't save much and there are hardly any extensions anyway
local t = { }
for i=1,f do
n = n + 1
diff --git a/src/fontloader/runtime/fontloader-basics-gen.lua b/src/fontloader/runtime/fontloader-basics-gen.lua
index 871e548..8ea93cc 100644
--- a/src/fontloader/runtime/fontloader-basics-gen.lua
+++ b/src/fontloader/runtime/fontloader-basics-gen.lua
@@ -258,45 +258,83 @@ function caches.is_writable(path,name)
return fullname and file.is_writable(fullname)
end
-function caches.loaddata(paths,name)
- for i=1,#paths do
- local data = false
- local luaname, lucname = makefullname(paths[i],name)
- if lucname and not lfs.isfile(lucname) and type(caches.compile) == "function" then
- -- in case we used luatex and luajittex mixed ... lub or luc file
- texio.write(string.format("(compiling luc: %s)",lucname))
- data = loadfile(luaname)
- if data then
- data = data()
- end
- if data then
- caches.compile(data,luaname,lucname)
- return data
- end
+-- function caches.loaddata(paths,name)
+-- for i=1,#paths do
+-- local data = false
+-- local luaname, lucname = makefullname(paths[i],name)
+-- if lucname and not lfs.isfile(lucname) and type(caches.compile) == "function" then
+-- -- in case we used luatex and luajittex mixed ... lub or luc file
+-- texio.write(string.format("(compiling luc: %s)",lucname))
+-- data = loadfile(luaname)
+-- if data then
+-- data = data()
+-- end
+-- if data then
+-- caches.compile(data,luaname,lucname)
+-- return data
+-- end
+-- end
+-- if lucname and lfs.isfile(lucname) then -- maybe also check for size
+-- texio.write(string.format("(load luc: %s)",lucname))
+-- data = loadfile(lucname)
+-- if data then
+-- data = data()
+-- end
+-- if data then
+-- return data
+-- else
+-- texio.write(string.format("(loading failed: %s)",lucname))
+-- end
+-- end
+-- if luaname and lfs.isfile(luaname) then
+-- texio.write(string.format("(load lua: %s)",luaname))
+-- data = loadfile(luaname)
+-- if data then
+-- data = data()
+-- end
+-- if data then
+-- return data
+-- end
+-- end
+-- end
+-- end
+
+function caches.loaddata(readables,name,writable)
+ for i=1,#readables do
+ local path = readables[i]
+ local loader = false
+ local luaname, lucname = makefullname(path,name)
+ if lfs.isfile(lucname) then
+ loader = loadfile(lucname)
end
- if lucname and lfs.isfile(lucname) then -- maybe also check for size
- texio.write(string.format("(load luc: %s)",lucname))
- data = loadfile(lucname)
- if data then
- data = data()
+ if not loader and lfs.isfile(luaname) then
+ -- can be different paths when we read a file database from disk
+ local luacrap, lucname = makefullname(writable,name)
+ texio.write(string.format("(compiling luc: %s)",lucname))
+ if lfs.isfile(lucname) then
+ loader = loadfile(lucname)
end
- if data then
- return data
+ caches.compile(data,luaname,lucname)
+ if lfs.isfile(lucname) then
+ texio.write(string.format("(load luc: %s)",lucname))
+ loader = loadfile(lucname)
else
texio.write(string.format("(loading failed: %s)",lucname))
end
- end
- if luaname and lfs.isfile(luaname) then
- texio.write(string.format("(load lua: %s)",luaname))
- data = loadfile(luaname)
- if data then
- data = data()
- end
- if data then
- return data
+ if not loader then
+ texio.write(string.format("(load lua: %s)",luaname))
+ loader = loadfile(luaname)
+ else
+ texio.write(string.format("(loading failed: %s)",luaname))
end
end
+ if loader then
+ loader = loader()
+ collectgarbage("step")
+ return loader
+ end
end
+ return false
end
function caches.savedata(path,name,data)
diff --git a/src/fontloader/runtime/fontloader-reference.lua b/src/fontloader/runtime/fontloader-reference.lua
index 6ef9430..6b899a1 100644
--- a/src/fontloader/runtime/fontloader-reference.lua
+++ b/src/fontloader/runtime/fontloader-reference.lua
@@ -1,6 +1,6 @@
-- merged file : c:/data/develop/context/sources/luatex-fonts-merged.lua
-- parent file : c:/data/develop/context/sources/luatex-fonts.lua
--- merge date : 08/11/16 13:56:03
+-- merge date : 08/27/16 13:35:36
do -- begin closure to overcome local limits and interference
@@ -1352,7 +1352,7 @@ function table.fromhash(t)
end
return hsh
end
-local noquotes,hexify,handle,compact,inline,functions
+local noquotes,hexify,handle,compact,inline,functions,metacheck
local reserved=table.tohash {
'and','break','do','else','elseif','end','false','for','function','if',
'in','local','nil','not','or','repeat','return','then','true','until','while',
@@ -1422,7 +1422,7 @@ local function do_serialize(root,name,depth,level,indexed)
if compact then
last=#root
for k=1,last do
- if root[k]==nil then
+ if rawget(root,k)==nil then
last=k-1
break
end
@@ -1619,6 +1619,7 @@ local function serialize(_handle,root,name,specification)
functions=specification.functions
compact=specification.compact
inline=specification.inline and compact
+ metacheck=specification.metacheck
if functions==nil then
functions=true
end
@@ -1628,6 +1629,9 @@ local function serialize(_handle,root,name,specification)
if inline==nil then
inline=compact
end
+ if metacheck==nil then
+ metacheck=true
+ end
else
noquotes=false
hexify=false
@@ -1635,6 +1639,7 @@ local function serialize(_handle,root,name,specification)
compact=true
inline=true
functions=true
+ metacheck=true
end
if tname=="string" then
if name=="return" then
@@ -1658,7 +1663,7 @@ local function serialize(_handle,root,name,specification)
handle("t={")
end
if root then
- if getmetatable(root) then
+ if metacheck and getmetatable(root) then
local dummy=root._w_h_a_t_e_v_e_r_
root._w_h_a_t_e_v_e_r_=nil
end
@@ -3416,7 +3421,7 @@ if not modules then modules={} end modules ['util-str']={
utilities=utilities or {}
utilities.strings=utilities.strings or {}
local strings=utilities.strings
-local format,gsub,rep,sub=string.format,string.gsub,string.rep,string.sub
+local format,gsub,rep,sub,find=string.format,string.gsub,string.rep,string.sub,string.find
local load,dump=load,string.dump
local tonumber,type,tostring=tonumber,type,tostring
local unpack,concat=table.unpack,table.concat
@@ -3599,6 +3604,25 @@ function number.signed(i)
return "-",-i
end
end
+local digit=patterns.digit
+local period=patterns.period
+local three=digit*digit*digit
+local splitter=Cs (
+ (((1-(three^1*period))^1+C(three))*(Carg(1)*three)^1+C((1-period)^1))*(P(1)/""*Carg(2))*C(2)
+)
+patterns.formattednumber=splitter
+function number.formatted(n,sep1,sep2)
+ local s=type(s)=="string" and n or format("%0.2f",n)
+ if sep1==true then
+ return lpegmatch(splitter,s,1,".",",")
+ elseif sep1=="." then
+ return lpegmatch(splitter,s,1,sep1,sep2 or ",")
+ elseif sep1=="," then
+ return lpegmatch(splitter,s,1,sep1,sep2 or ".")
+ else
+ return lpegmatch(splitter,s,1,sep1 or ",",sep2 or ".")
+ end
+end
local zero=P("0")^1/""
local plus=P("+")/""
local minus=P("-")
@@ -3882,25 +3906,6 @@ end
local format_W=function(f)
return format("nspaces[%s]",tonumber(f) or 0)
end
-local digit=patterns.digit
-local period=patterns.period
-local three=digit*digit*digit
-local splitter=Cs (
- (((1-(three^1*period))^1+C(three))*(Carg(1)*three)^1+C((1-period)^1))*(P(1)/""*Carg(2))*C(2)
-)
-patterns.formattednumber=splitter
-function number.formatted(n,sep1,sep2)
- local s=type(s)=="string" and n or format("%0.2f",n)
- if sep1==true then
- return lpegmatch(splitter,s,1,".",",")
- elseif sep1=="." then
- return lpegmatch(splitter,s,1,sep1,sep2 or ",")
- elseif sep1=="," then
- return lpegmatch(splitter,s,1,sep1,sep2 or ".")
- else
- return lpegmatch(splitter,s,1,sep1 or ",",sep2 or ".")
- end
-end
local format_m=function(f)
n=n+1
if not f or f=="" then
@@ -3925,9 +3930,16 @@ end
local format_extension=function(extensions,f,name)
local extension=extensions[name] or "tostring(%s)"
local f=tonumber(f) or 1
+ local w=find(extension,"%.%.%.")
if f==0 then
+ if w then
+ extension=gsub(extension,"%.%.%.","")
+ end
return extension
elseif f==1 then
+ if w then
+ extension=gsub(extension,"%.%.%.","%%s")
+ end
n=n+1
local a="a"..n
return format(extension,a,a)
@@ -3935,6 +3947,9 @@ local format_extension=function(extensions,f,name)
local a="a"..(n+f+1)
return format(extension,a,a)
else
+ if w then
+ extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s")
+ end
local t={}
for i=1,f do
n=n+1
@@ -4466,44 +4481,41 @@ function caches.is_writable(path,name)
local fullname=makefullname(path,name)
return fullname and file.is_writable(fullname)
end
-function caches.loaddata(paths,name)
- for i=1,#paths do
- local data=false
- local luaname,lucname=makefullname(paths[i],name)
- if lucname and not lfs.isfile(lucname) and type(caches.compile)=="function" then
+function caches.loaddata(readables,name,writable)
+ for i=1,#readables do
+ local path=readables[i]
+ local loader=false
+ local luaname,lucname=makefullname(path,name)
+ if lfs.isfile(lucname) then
+ loader=loadfile(lucname)
+ end
+ if not loader and lfs.isfile(luaname) then
+ local luacrap,lucname=makefullname(writable,name)
texio.write(string.format("(compiling luc: %s)",lucname))
- data=loadfile(luaname)
- if data then
- data=data()
- end
- if data then
- caches.compile(data,luaname,lucname)
- return data
- end
- end
- if lucname and lfs.isfile(lucname) then
- texio.write(string.format("(load luc: %s)",lucname))
- data=loadfile(lucname)
- if data then
- data=data()
+ if lfs.isfile(lucname) then
+ loader=loadfile(lucname)
end
- if data then
- return data
+ caches.compile(data,luaname,lucname)
+ if lfs.isfile(lucname) then
+ texio.write(string.format("(load luc: %s)",lucname))
+ loader=loadfile(lucname)
else
texio.write(string.format("(loading failed: %s)",lucname))
end
- end
- if luaname and lfs.isfile(luaname) then
- texio.write(string.format("(load lua: %s)",luaname))
- data=loadfile(luaname)
- if data then
- data=data()
- end
- if data then
- return data
+ if not loader then
+ texio.write(string.format("(load lua: %s)",luaname))
+ loader=loadfile(luaname)
+ else
+ texio.write(string.format("(loading failed: %s)",luaname))
end
end
+ if loader then
+ loader=loader()
+ collectgarbage("step")
+ return loader
+ end
end
+ return false
end
function caches.savedata(path,name,data)
local luaname,lucname=makefullname(path,name)
@@ -4630,7 +4642,7 @@ function containers.read(container,name)
local storage=container.storage
local stored=storage[name]
if not stored and container.enabled and caches and containers.usecache then
- stored=caches.loaddata(container.readables,name)
+ stored=caches.loaddata(container.readables,name,container.writable)
if stored and stored.cache_version==container.version then
if trace_cache or trace_containers then
report_containers("action %a, category %a, name %a","load",container.subcategory,name)
@@ -8845,112 +8857,6 @@ function readers.math(f,fontdata,specification)
reportskippedtable("math")
end
end
-local function packoutlines(data,makesequence)
- local subfonts=data.subfonts
- if subfonts then
- for i=1,#subfonts do
- packoutlines(subfonts[i],makesequence)
- end
- return
- end
- local common=data.segments
- if common then
- return
- end
- local glyphs=data.glyphs
- if not glyphs then
- return
- end
- if makesequence then
- for index=1,#glyphs do
- local glyph=glyphs[index]
- local segments=glyph.segments
- if segments then
- local sequence={}
- local nofsequence=0
- for i=1,#segments do
- local segment=segments[i]
- local nofsegment=#segment
- nofsequence=nofsequence+1
- sequence[nofsequence]=segment[nofsegment]
- for i=1,nofsegment-1 do
- nofsequence=nofsequence+1
- sequence[nofsequence]=segment[i]
- end
- end
- glyph.sequence=sequence
- glyph.segments=nil
- end
- end
- else
- local hash={}
- local common={}
- local reverse={}
- local last=0
- for index=1,#glyphs do
- local segments=glyphs[index].segments
- if segments then
- for i=1,#segments do
- local h=concat(segments[i]," ")
- hash[h]=(hash[h] or 0)+1
- end
- end
- end
- for index=1,#glyphs do
- local segments=glyphs[index].segments
- if segments then
- for i=1,#segments do
- local segment=segments[i]
- local h=concat(segment," ")
- if hash[h]>1 then
- local idx=reverse[h]
- if not idx then
- last=last+1
- reverse[h]=last
- common[last]=segment
- idx=last
- end
- segments[i]=idx
- end
- end
- end
- end
- if last>0 then
- data.segments=common
- end
- end
-end
-local function unpackoutlines(data)
- local subfonts=data.subfonts
- if subfonts then
- for i=1,#subfonts do
- unpackoutlines(subfonts[i])
- end
- return
- end
- local common=data.segments
- if not common then
- return
- end
- local glyphs=data.glyphs
- if not glyphs then
- return
- end
- for index=1,#glyphs do
- local segments=glyphs[index].segments
- if segments then
- for i=1,#segments do
- local c=common[segments[i]]
- if c then
- segments[i]=c
- end
- end
- end
- end
- data.segments=nil
-end
-otf.packoutlines=packoutlines
-otf.unpackoutlines=unpackoutlines
local function getinfo(maindata,sub,platformnames,rawfamilynames)
local fontdata=sub and maindata.subfonts and maindata.subfonts[sub] or maindata
local names=fontdata.names
@@ -9218,6 +9124,13 @@ function readers.loadshapes(filename,n)
shapes=true,
subfont=n,
}
+ if fontdata then
+ for k,v in next,fontdata.glyphs do
+ v.class=nil
+ v.index=nil
+ v.math=nil
+ end
+ end
return fontdata and {
filename=filename,
format=fontdata.format,
@@ -9347,56 +9260,6 @@ function readers.extend(fontdata)
end
end
end
-if fonts.hashes then
- local identifiers=fonts.hashes.identifiers
- local loadshapes=readers.loadshapes
- readers.version=0.006
- readers.cache=containers.define("fonts","shapes",readers.version,true)
- local function load(filename,sub)
- local base=file.basename(filename)
- local name=file.removesuffix(base)
- local kind=file.suffix(filename)
- local attr=lfs.attributes(filename)
- local size=attr and attr.size or 0
- local time=attr and attr.modification or 0
- local sub=tonumber(sub)
- if size>0 and (kind=="otf" or kind=="ttf" or kind=="tcc") then
- local hash=containers.cleanname(base)
- if sub then
- hash=hash.."-"..sub
- end
- data=containers.read(readers.cache,hash)
- if not data or data.time~=time or data.size~=size then
- data=loadshapes(filename,sub)
- if data then
- data.size=size
- data.format=data.format or (kind=="otf" and "opentype") or "truetype"
- data.time=time
- packoutlines(data)
- containers.write(readers.cache,hash,data)
- data=containers.read(readers.cache,hash)
- end
- end
- unpackoutlines(data)
- else
- data={
- filename=filename,
- size=0,
- time=time,
- format="unknown",
- units=1000,
- glyphs={}
- }
- end
- return data
- end
- fonts.hashes.shapes=table.setmetatableindex(function(t,k)
- local d=identifiers[k]
- local v=load(d.properties.filename,d.subindex)
- t[k]=v
- return v
- end)
-end
end -- closure
@@ -9415,6 +9278,7 @@ local concat,remove=table.concat,table.remove
local floor,abs,round,ceil=math.floor,math.abs,math.round,math.ceil
local P,C,R,S,C,Cs,Ct=lpeg.P,lpeg.C,lpeg.R,lpeg.S,lpeg.C,lpeg.Cs,lpeg.Ct
local lpegmatch=lpeg.match
+local formatters=string.formatters
local readers=fonts.handlers.otf.readers
local streamreader=readers.streamreader
local readbytes=streamreader.readbytes
@@ -9815,6 +9679,7 @@ do
local ymax=0
local checked=false
local keepcurve=false
+ local version=2
local function showstate(where)
report("%w%-10s : [%s] n=%i",depth*2,where,concat(stack," ",1,top),top)
end
@@ -10237,9 +10102,91 @@ do
return floor((stems+7)/8)
end
end
- local function unsupported()
+ local function unsupported(t)
if trace_charstrings then
- showstate("unsupported")
+ showstate("unsupported "..t)
+ end
+ top=0
+ end
+ local function unsupportedsub(t)
+ if trace_charstrings then
+ showstate("unsupported sub "..t)
+ end
+ top=0
+ end
+ local function getstem3()
+ if trace_charstrings then
+ showstate("stem3")
+ end
+ top=0
+ end
+ local function divide()
+ if version==1 then
+ local d=stack[top]
+ top=top-1
+ stack[top]=stack[top]/d
+ end
+ end
+ local function closepath()
+ if version==1 then
+ if trace_charstrings then
+ showstate("closepath")
+ end
+ end
+ top=0
+ end
+ local function hsbw()
+ if version==1 then
+ if trace_charstrings then
+ showstate("dotsection")
+ end
+ width=stack[top]
+ end
+ top=0
+ end
+ local function seac()
+ if version==1 then
+ if trace_charstrings then
+ showstate("seac")
+ end
+ end
+ top=0
+ end
+ local function sbw()
+ if version==1 then
+ if trace_charstrings then
+ showstate("sbw")
+ end
+ width=stack[top-1]
+ end
+ top=0
+ end
+ local function callothersubr()
+ if version==1 then
+ if trace_charstrings then
+ showstate("callothersubr (unsupported)")
+ end
+ end
+ top=0
+ end
+ local function pop()
+ if version==1 then
+ if trace_charstrings then
+ showstate("pop (unsupported)")
+ end
+ top=top+1
+ stack[top]=0
+ else
+ top=0
+ end
+ end
+ local function setcurrentpoint()
+ if version==1 then
+ if trace_charstrings then
+ showstate("pop (unsupported)")
+ end
+ x=x+stack[top-1]
+ y=y+stack[top]
end
top=0
end
@@ -10256,7 +10203,7 @@ do
unsupported,
unsupported,
unsupported,
- unsupported,
+ hsbw,
unsupported,
unsupported,
unsupported,
@@ -10277,6 +10224,15 @@ do
hvcurveto,
}
local subactions={
+ [000]=dotsection,
+ [001]=getstem3,
+ [002]=getstem3,
+ [006]=seac,
+ [007]=sbw,
+ [012]=divide,
+ [016]=callothersubr,
+ [017]=pop,
+ [033]=setcurrentpoint,
[034]=hflex,
[035]=flex,
[036]=hflex1,
@@ -10284,23 +10240,29 @@ do
}
local p_bytes=Ct((P(1)/byte)^0)
local function call(scope,list,bias,process)
- local index=stack[top]+bias
- top=top-1
- if trace_charstrings then
- showvalue(scope,index,true)
- end
- local str=list[index]
- if str then
- if type(str)=="string" then
- str=lpegmatch(p_bytes,str)
- list[index]=str
- end
- depth=depth+1
- process(str)
- depth=depth-1
+ depth=depth+1
+ if top==0 then
+ showstate(formatters["unknown %s call"](scope))
+ top=0
else
- report("unknown %s %i",scope,index)
+ local index=stack[top]+bias
+ top=top-1
+ if trace_charstrings then
+ showvalue(scope,index,true)
+ end
+ local tab=list[index]
+ if tab then
+ if type(tab)=="string" then
+ tab=lpegmatch(p_bytes,tab)
+ list[index]=tab
+ end
+ process(tab)
+ else
+ showstate(formatters["unknown %s call %i"](scope,index))
+ top=0
+ end
end
+ depth=depth-1
end
local function process(tab)
local i=1
@@ -10367,7 +10329,7 @@ do
local t=tab[i]
local a=subactions[t]
if a then
- a()
+ a(t)
else
if trace_charstrings then
showvalue("<subaction>",t)
@@ -10378,7 +10340,7 @@ do
else
local a=actions[t]
if a then
- local s=a()
+ local s=a(t)
if s then
i=i+s
end
@@ -10392,25 +10354,38 @@ do
end
end
end
- parsecharstrings=function(data,glyphs,doshapes)
+ local function setbias(globals,locals)
+ if version==1 then
+ return
+ false,
+ false
+ else
+ local g,l=#globals,#locals
+ return
+ ((g<1240 and 107) or (g<33900 and 1131) or 32768)+1,
+ ((l<1240 and 107) or (l<33900 and 1131) or 32768)+1
+ end
+ end
+ parsecharstrings=function(data,glyphs,doshapes,tversion)
local dictionary=data.dictionaries[1]
local charstrings=dictionary.charstrings
local charset=dictionary.charset
+ local private=dictionary.private or { data={} }
keepcurve=doshapes
+ version=tversion
stack={}
glyphs=glyphs or {}
strings=data.strings
- locals=dictionary.subroutines
- globals=data.routines
- globalbias=#globals
- localbias=#locals
- globalbias=((globalbias<1240 and 107) or (globalbias<33900 and 1131) or 32768)+1
- localbias=((localbias<1240 and 107) or (localbias<33900 and 1131) or 32768)+1
- local nominalwidth=dictionary.private.data.nominalwidthx or 0
- local defaultwidth=dictionary.private.data.defaultwidthx or 0
+ globals=data.routines or {}
+ locals=dictionary.subroutines or {}
+ globalbias,localbias=setbias(globals,locals)
+ local nominalwidth=private.data.nominalwidthx or 0
+ local defaultwidth=private.data.defaultwidthx or 0
for i=1,#charstrings do
- local str=charstrings[i]
- local tab=lpegmatch(p_bytes,str)
+ local tab=charstrings[i]
+ if type(tab)=="string" then
+ tab=lpegmatch(p_bytes,tab)
+ end
local index=i-1
x=0
y=0
@@ -10461,19 +10436,19 @@ do
end
return glyphs
end
- parsecharstring=function(data,dictionary,charstring,glyphs,index,doshapes)
+ parsecharstring=function(data,dictionary,tab,glyphs,index,doshapes,tversion)
local private=dictionary.private
keepcurve=doshapes
+ version=tversion
strings=data.strings
locals=dictionary.subroutines or {}
globals=data.routines or {}
- globalbias=#globals
- localbias=#locals
- globalbias=((globalbias<1240 and 107) or (globalbias<33900 and 1131) or 32768)+1
- localbias=((localbias<1240 and 107) or (localbias<33900 and 1131) or 32768)+1
+ globalbias,localbias=setbias(globals,locals)
local nominalwidth=private and private.data.nominalwidthx or 0
local defaultwidth=private and private.data.defaultwidthx or 0
- local tab=lpegmatch(p_bytes,charstring)
+ if type(tab)=="string" then
+ tab=lpegmatch(p_bytes,tab)
+ end
x=0
y=0
width=false
@@ -10497,7 +10472,7 @@ do
else
width=nominalwidth+width
end
-index=index-1
+ index=index-1
local glyph=glyphs[index]
if not glyph then
glyphs[index]={
@@ -10520,7 +10495,6 @@ index=index-1
report("width: %s",tostring(width))
report("boundingbox: % t",boundingbox)
end
- return charstring
end
resetcharstrings=function()
result={}
@@ -10634,7 +10608,7 @@ local function readcidprivates(f,data)
end
parseprivates(data,dictionaries)
end
-local function readnoselect(f,data,glyphs,doshapes)
+local function readnoselect(f,data,glyphs,doshapes,version)
local dictionaries=data.dictionaries
local dictionary=dictionaries[1]
readglobals(f,data)
@@ -10644,10 +10618,11 @@ local function readnoselect(f,data,glyphs,doshapes)
readprivates(f,data)
parseprivates(data,data.dictionaries)
readlocals(f,data,dictionary)
- parsecharstrings(data,glyphs,doshapes)
+ parsecharstrings(data,glyphs,doshapes,version)
resetcharstrings()
end
-local function readfdselect(f,data,glyphs,doshapes)
+readers.parsecharstrings=parsecharstrings
+local function readfdselect(f,data,glyphs,doshapes,version)
local header=data.header
local dictionaries=data.dictionaries
local dictionary=dictionaries[1]
@@ -10705,7 +10680,7 @@ local function readfdselect(f,data,glyphs,doshapes)
readlocals(f,data,dictionaries[i])
end
for i=1,#charstrings do
- parsecharstring(data,dictionaries[fdindex[i]+1],charstrings[i],glyphs,i,doshapes)
+ parsecharstring(data,dictionaries[fdindex[i]+1],charstrings[i],glyphs,i,doshapes,version)
end
resetcharstrings()
end
@@ -11199,6 +11174,7 @@ local bittest=bit32.btest
local rshift=bit32.rshift
local concat=table.concat
local lower=string.lower
+local copy=table.copy
local sub=string.sub
local strip=string.strip
local tohash=table.tohash
@@ -12632,7 +12608,7 @@ do
markclass=d.markclass or nil,
flags=d.flags,
}
- sublookuplist[nofsublookups]=h
+ sublookuplist[nofsublookups]=copy(h)
sublookuphash[lookupid]=nofsublookups
sublookupcheck[lookupid]=1
else
@@ -15344,7 +15320,7 @@ local trace_defining=false registertracker("fonts.defining",function(v) trace_de
local report_otf=logs.reporter("fonts","otf loading")
local fonts=fonts
local otf=fonts.handlers.otf
-otf.version=3.025
+otf.version=3.026
otf.cache=containers.define("fonts","otl",otf.version,true)
otf.svgcache=containers.define("fonts","svg",otf.version,true)
otf.pdfcache=containers.define("fonts","pdf",otf.version,true)
@@ -16624,7 +16600,7 @@ function injections.setkern(current,factor,rlmode,x,injection)
return 0,0
end
end
-function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk)
+function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk,checkmark)
local dx,dy=factor*(ba[1]-ma[1]),factor*(ba[2]-ma[2])
nofregisteredmarks=nofregisteredmarks+1
if rlmode>=0 then
@@ -16642,6 +16618,7 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk)
i.markbase=nofregisteredmarks
i.markbasenode=base
i.markmark=mkmk
+ i.checkmark=checkmark
end
else
p.injections={
@@ -16651,6 +16628,7 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk)
markbase=nofregisteredmarks,
markbasenode=base,
markmark=mkmk,
+ checkmark=checkmark,
}
end
else
@@ -16662,6 +16640,7 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk)
markbase=nofregisteredmarks,
markbasenode=base,
markmark=mkmk,
+ checkmark=checkmark,
},
}
end
@@ -17213,10 +17192,16 @@ local function inject_everything(head,where)
end
else
ox=px-pn.markx
- local wn=getfield(n,"width")
- if wn~=0 then
- pn.leftkern=-wn/2
- pn.rightkern=-wn/2
+ if pn.checkmark then
+ local wn=getfield(n,"width")
+ if wn~=0 then
+ wn=wn/2
+ if trace_injections then
+ report_injections("correcting non zero width mark %C",getchar(n))
+ end
+ insert_node_before(n,n,newkern(-wn))
+ insert_node_after(n,n,newkern(-wn))
+ end
end
end
local oy=getfield(n,"yoffset")+getfield(p,"yoffset")+pn.marky
@@ -17240,10 +17225,10 @@ local function inject_everything(head,where)
nofmarks=nofmarks+1
marks[nofmarks]=current
else
-local yoffset=i.yoffset
-if yoffset and yoffset~=0 then
- setfield(current,"yoffset",yoffset)
-end
+ local yoffset=i.yoffset
+ if yoffset and yoffset~=0 then
+ setfield(current,"yoffset",yoffset)
+ end
if hascursives then
local cursivex=i.cursivex
if cursivex then
@@ -17884,33 +17869,40 @@ local mappers={
}
local classifiers=characters.classifiers
if not classifiers then
- local first_arabic,last_arabic=characters.blockrange("arabic")
- local first_syriac,last_syriac=characters.blockrange("syriac")
- local first_mandiac,last_mandiac=characters.blockrange("mandiac")
- local first_nko,last_nko=characters.blockrange("nko")
+ local f_arabic,l_arabic=characters.blockrange("arabic")
+ local f_syriac,l_syriac=characters.blockrange("syriac")
+ local f_mandiac,l_mandiac=characters.blockrange("mandiac")
+ local f_nko,l_nko=characters.blockrange("nko")
+ local f_ext_a,l_ext_a=characters.blockrange("arabicextendeda")
classifiers=table.setmetatableindex(function(t,k)
- local c=chardata[k]
- local v=false
- if c then
- local arabic=c.arabic
- if arabic then
- v=mappers[arabic]
- if not v then
- log.report("analyze","error in mapping arabic %C",k)
- v=false
- end
- elseif k>=first_arabic and k<=last_arabic or k>=first_syriac and k<=last_syriac or
- k>=first_mandiac and k<=last_mandiac or k>=first_nko and k<=last_nko then
- if categories[k]=="mn" then
- v=s_mark
- else
- v=s_rest
+ if type(k)=="number" then
+ local c=chardata[k]
+ local v=false
+ if c then
+ local arabic=c.arabic
+ if arabic then
+ v=mappers[arabic]
+ if not v then
+ log.report("analyze","error in mapping arabic %C",k)
+ v=false
+ end
+ elseif (k>=f_arabic and k<=l_arabic) or
+ (k>=f_syriac and k<=l_syriac) or
+ (k>=f_mandiac and k<=l_mandiac) or
+ (k>=f_nko and k<=l_nko) or
+ (k>=f_ext_a and k<=l_ext_a) then
+ if categories[k]=="mn" then
+ v=s_mark
+ else
+ v=s_rest
+ end
end
end
+ t[k]=v
+ return v
end
- t[k]=v
- return v
end)
+ characters.classifiers=classifiers
end
function methods.arab(head,font,attr)
local first,last=nil,nil
@@ -18180,6 +18172,7 @@ local marks=false
local currentfont=false
local factor=0
local threshold=0
+local checkmarks=false
local sweepnode=nil
local sweepprev=nil
local sweepnext=nil
@@ -18795,7 +18788,7 @@ function handlers.gpos_mark2base(head,start,dataset,sequence,markanchors,rlmode)
local ba=markanchors[1][basechar]
if ba then
local ma=markanchors[2]
- local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar])
+ local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
if trace_marks then
logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)",
pref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy)
@@ -18850,7 +18843,7 @@ function handlers.gpos_mark2ligature(head,start,dataset,sequence,markanchors,rlm
local index=getligaindex(start)
ba=ba[index]
if ba then
- local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar])
+ local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
if trace_marks then
logprocess("%s, anchor %s, index %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)",
pref(dataset,sequence),anchor,index,bound,gref(markchar),gref(basechar),index,dx,dy)
@@ -18897,7 +18890,7 @@ function handlers.gpos_mark2mark(head,start,dataset,sequence,markanchors,rlmode)
local ba=markanchors[1][basechar]
if ba then
local ma=markanchors[2]
- local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true)
+ local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true,checkmarks)
if trace_marks then
logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)",
pref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy)
@@ -19279,7 +19272,7 @@ function chainprocs.gpos_mark2base(head,start,stop,dataset,sequence,currentlooku
if ba then
local ma=markanchors[2]
if ma then
- local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar])
+ local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
if trace_marks then
logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)",
cref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy)
@@ -19345,7 +19338,7 @@ function chainprocs.gpos_mark2ligature(head,start,stop,dataset,sequence,currentl
local index=getligaindex(start)
ba=ba[index]
if ba then
- local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar])
+ local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
if trace_marks then
logprocess("%s, anchor %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)",
cref(dataset,sequence),anchor,a or bound,gref(markchar),gref(basechar),index,dx,dy)
@@ -19397,7 +19390,7 @@ function chainprocs.gpos_mark2mark(head,start,stop,dataset,sequence,currentlooku
if ba then
local ma=markanchors[2]
if ma then
- local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true)
+ local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true,checkmarks)
if trace_marks then
logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)",
cref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy)
@@ -20837,6 +20830,7 @@ local function featuresprocessor(head,font,attr)
marks=tfmdata.resources.marks
threshold,
factor=getthreshold(font)
+ checkmarks=tfmdata.properties.checkmarks
elseif currentfont~=font then
report_warning("nested call with a different font, level %s, quitting",nesting)
nesting=nesting-1
@@ -21057,7 +21051,7 @@ local setspacekerns=nodes.injections.setspacekerns if not setspacekerns then os.
if fontfeatures then
function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr)
local features=fontfeatures[font]
- local enabled=features.spacekern==true and features.kern==true
+ local enabled=features and features.spacekern and features.kern
if enabled then
setspacekerns(font,sequence)
end
@@ -21067,7 +21061,7 @@ else
function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr)
local shared=fontdata[font].shared
local features=shared and shared.features
- local enabled=features and features.spacekern==true and features.kern==true
+ local enabled=features and features.spacekern and features.kern
if enabled then
setspacekerns(font,sequence)
end
@@ -21122,7 +21116,7 @@ local function spaceinitializer(tfmdata,value)
if kern then
if feat then
for script,languages in next,kern do
- local f=feat[k]
+ local f=feat[script]
if f then
for l in next,languages do
f[l]=true
@@ -21137,24 +21131,38 @@ local function spaceinitializer(tfmdata,value)
for i=1,#steps do
local step=steps[i]
local coverage=step.coverage
- if coverage then
+ local rules=step.rules
+ local format=step.format
+ if rules then
+ elseif coverage then
+ local single=format==gpos_single
local kerns=coverage[32]
if kerns then
for k,v in next,kerns do
- if type(v)=="table" then
- right[k]=v[3]
- else
+ if type(v)~="table" then
right[k]=v
+ elseif single then
+ right[k]=v[3]
+ else
+ local one=v[1]
+ if one then
+ right[k]=one[3]
+ end
end
end
end
for k,v in next,coverage do
local kern=v[32]
if kern then
- if type(kern)=="table" then
- left[k]=kern[3]
- else
+ if type(kern)~="table" then
left[k]=kern
+ elseif single then
+ left[k]=v[3]
+ else
+ local one=v[1]
+ if one then
+ left[k]=one[3]
+ end
end
end
end
@@ -21202,6 +21210,18 @@ registerotffeature {
node=spaceinitializer,
},
}
+local function markinitializer(tfmdata,value)
+ local properties=tfmdata.properties
+ properties.checkmarks=value
+end
+registerotffeature {
+ name="checkmarks",
+ description="check mark widths",
+ default=true,
+ initializers={
+ node=markinitializer,
+ },
+}
end -- closure
@@ -21605,9 +21625,11 @@ local function initializedevanagi(tfmdata)
local steps=sequence.steps
local nofsteps=sequence.nofsteps
local features=sequence.features
- if features["rphf"] then
+ local has_rphf=features.rphf
+ local has_blwf=features.blwf
+ if has_rphf and has_rphf.deva then
devanagari.reph=true
- elseif features["blwf"] then
+ elseif has_blwf and has_blwf.deva then
devanagari.vattu=true
for i=1,nofsteps do
local step=steps[i]
@@ -21621,57 +21643,60 @@ local function initializedevanagi(tfmdata)
end
end
end
- if valid[kind] then
- for i=1,nofsteps do
- local step=steps[i]
- local coverage=step.coverage
- if coverage then
- local reph=false
- if step.osdstep then
- for k,v in next,ra do
- local r=coverage[k]
- if r then
- local h=false
- for k,v in next,halant do
- local h=r[k]
- if h then
- reph=h.ligature or false
- break
+ for kind,spec in next,features do
+ if spec.dev2 and valid[kind] then
+ for i=1,nofsteps do
+ local step=steps[i]
+ local coverage=step.coverage
+ if coverage then
+ local reph=false
+ if kind=="rphf" then
+ if true then
+ for k,v in next,ra do
+ local r=coverage[k]
+ if r then
+ local h=false
+ for k,v in next,halant do
+ local h=r[k]
+ if h then
+ reph=h.ligature or false
+ break
+ end
+ end
+ if reph then
+ break
+ end
end
end
- if reph then
- break
- end
+ else
end
end
- else
+ seqsubset[#seqsubset+1]={ kind,coverage,reph }
end
- seqsubset[#seqsubset+1]={ kind,coverage,reph }
end
end
- end
- if kind=="pref" then
- local sequence=dataset[3]
- local steps=sequence.steps
- local nofsteps=sequence.nofsteps
- for i=1,nofsteps do
- local step=steps[i]
- local coverage=step.coverage
- if coverage then
- for k,v in next,halant do
- local h=coverage[k]
- if h then
- local found=false
- for k,v in next,h do
- found=v and v.ligature
+ if kind=="pref" then
+ local steps=sequence.steps
+ local nofsteps=sequence.nofsteps
+ for i=1,nofsteps do
+ local step=steps[i]
+ local coverage=step.coverage
+ if coverage then
+ for k,v in next,halant do
+ local h=coverage[k]
+ if h then
+ local found=false
+ for k,v in next,h do
+ found=v and v.ligature
+ if found then
+ pre_base_reordering_consonants[k]=found
+ break
+ end
+ end
if found then
- pre_base_reordering_consonants[k]=found
break
end
end
- if found then
- break
- end
end
end
end
@@ -22058,6 +22083,8 @@ function handlers.devanagari_reorder_matras(head,start)
start=startnext
break
end
+ else
+ break
end
current=next
end
@@ -22070,12 +22097,12 @@ function handlers.devanagari_reorder_reph(head,start)
local startfont=getfont(start)
local startattr=getprop(start,a_syllabe)
while current do
- local char=ischar(current,font)
+ local char=ischar(current,startfont)
if char and getprop(current,a_syllabe)==startattr then
if halant[char] and not getprop(current,a_state) then
local next=getnext(current)
if next then
- local nextchar=ischar(next,font)
+ local nextchar=ischar(next,startfont)
if nextchar and zw_char[nextchar] and getprop(next,a_syllabe)==startattr then
current=next
next=getnext(current)
@@ -22097,7 +22124,7 @@ function handlers.devanagari_reorder_reph(head,start)
if not startnext then
current=getnext(start)
while current do
- local char=ischar(current,font)
+ local char=ischar(current,startfont)
if char and getprop(current,a_syllabe)==startattr then
if getprop(current,a_state)==s_pstf then
startnext=getnext(start)
@@ -22119,7 +22146,7 @@ function handlers.devanagari_reorder_reph(head,start)
current=getnext(start)
local c=nil
while current do
- local char=ischar(current,font)
+ local char=ischar(current,startfont)
if char and getprop(current,a_syllabe)==startattr then
if not c and mark_above_below_post[char] and reorder_class[char]~="after subscript" then
c=current
@@ -22143,7 +22170,7 @@ function handlers.devanagari_reorder_reph(head,start)
current=start
local next=getnext(current)
while next do
- local nextchar=ischar(next,font)
+ local nextchar=ischar(next,startfont)
if nextchar and getprop(next,a_syllabe)==startattr then
current=next
next=getnext(current)
@@ -22156,7 +22183,7 @@ function handlers.devanagari_reorder_reph(head,start)
head=remove_node(head,start)
local next=getnext(current)
setlink(start,next)
- setlink(current,"next",start)
+ setlink(current,start)
start=startnext
end
end
@@ -22169,12 +22196,12 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
local startfont=getfont(start)
local startattr=getprop(start,a_syllabe)
while current do
- local char=ischar(current,font)
+ local char=ischar(current,startfont)
if char and getprop(current,a_syllabe)==startattr then
local next=getnext(current)
if halant[char] and not getprop(current,a_state) then
if next then
- local nextchar=ischar(next,font)
+ local nextchar=ischar(next,startfont)
if nextchar and getprop(next,a_syllabe)==startattr then
if nextchar==c_zwnj or nextchar==c_zwj then
current=next
@@ -22198,13 +22225,13 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
current=getnext(start)
startattr=getprop(start,a_syllabe)
while current do
- local char=ischar(current,font)
+ local char=ischar(current,startfont)
if char and getprop(current,a_syllabe)==startattr then
if not consonant[char] and getprop(current,a_state) then
startnext=getnext(start)
removenode(start,start)
local prev=getprev(current)
- setlink(start,prev)
+ setlink(prev,start)
setlink(start,current)
start=startnext
break
@@ -22264,21 +22291,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces)
local kind=subset[1]
local lookupcache=subset[2]
if kind=="rphf" then
- for k,v in next,ra do
- local r=lookupcache[k]
- if r then
- for k,v in next,halant do
- local h=r[k]
- if h then
- reph=h.ligature or false
- break
- end
- end
- if reph then
- break
- end
- end
- end
+ reph=subset[3]
local current=start
local last=getnext(stop)
while current~=last do
@@ -22311,7 +22324,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces)
if current~=stop then
local c=locl[current] or getchar(current)
local found=lookupcache[c]
- if found then
+ if found then
local next=getnext(current)
local n=locl[next] or getchar(next)
if found[n] then
@@ -22538,7 +22551,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces)
local prev=getprev(current)
if prev~=target then
local next=getnext(current)
- setlink(next,prev)
+ setlink(prev,next)
if current==stop then
stop=prev
end
@@ -22569,7 +22582,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces)
stop=current
end
local prev=getprev(c)
- setlink(next,prev)
+ setlink(prev,next)
local nextnext=getnext(next)
setnext(current,nextnext)
local nextnextnext=getnext(nextnext)
@@ -22582,6 +22595,9 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces)
current=getnext(current)
end
if getchar(base)==c_nbsp then
+ if base==stop then
+ stop=getprev(stop)
+ end
nbspaces=nbspaces-1
head=remove_node(head,base)
flush_node(base)
@@ -22623,7 +22639,7 @@ local function analyze_next_chars_one(c,font,variant)
elseif (vv==c_zwnj or vv==c_zwj) and halant[vvv] then
local nnnn=getnext(nnn)
if nnnn then
- local vvvv=ischar(nnnn)
+ local vvvv=ischar(nnnn,font)
if vvvv and consonant[vvvv] then
c=nnnn
end
@@ -22646,7 +22662,7 @@ local function analyze_next_chars_one(c,font,variant)
local nn=getnext(n)
if nn then
local vv=ischar(nn,font)
- if vv and zw_char[vv] then
+ if vv and zw_char[v] then
n=nn
v=vv
nn=getnext(nn)
@@ -24226,26 +24242,25 @@ handlers.afm=afm
local readers=afm.readers or {}
afm.readers=readers
afm.version=1.512
-local get_indexes
+local get_indexes,get_shapes
do
- local n,m
- local progress=function(str,position,name,size)
- local forward=position+tonumber(size)+3+2
- n=n+1
- if n>=m then
- return #str,name
- elseif forward<#str then
- return forward,name
- else
- return #str,name
+ local decrypt
+ do
+ local r,c1,c2,n=0,0,0,0
+ local function step(c)
+ local cipher=byte(c)
+ local plain=bxor(cipher,rshift(r,8))
+ r=((cipher+r)*c1+c2)%65536
+ return char(plain)
+ end
+ decrypt=function(binary,initial,seed)
+ r,c1,c2,n=initial,52845,22719,seed
+ binary=gsub(binary,".",step)
+ return sub(binary,n+1)
end
- end
- local initialize=function(str,position,size)
- n=0
- m=size
- return position+1
end
local charstrings=P("/CharStrings")
+ local subroutines=P("/Subrs")
local encoding=P("/Encoding")
local dup=P("dup")
local put=P("put")
@@ -24255,28 +24270,58 @@ do
local cardinal=digits/tonumber
local spaces=P(" ")^1
local spacing=patterns.whitespace^0
+ local routines,vector,chars,n,m
+ local initialize=function(str,position,size)
+ n=0
+ m=size
+ return position+1
+ end
+ local setroutine=function(str,position,index,size)
+ local forward=position+tonumber(size)
+ local stream=sub(str,position+1,forward)
+ routines[index]=decrypt(stream,4330,4)
+ return forward
+ end
+ local setvector=function(str,position,name,size)
+ local forward=position+tonumber(size)
+ if n>=m then
+ return #str
+ elseif forward<#str then
+ vector[n]=name
+ n=n+1
+ return forward
+ else
+ return #str
+ end
+ end
+ local setshapes=function(str,position,name,size)
+ local forward=position+tonumber(size)
+ local stream=sub(str,position+1,forward)
+ if n>m then
+ return #str
+ elseif forward<#str then
+ vector[n]=name
+ n=n+1
+ chars [n]=decrypt(stream,4330,4)
+ return forward
+ else
+ return #str
+ end
+ end
+ local p_rd=spacing*(P("RD")+P("-|"))
+ local p_np=spacing*(P("NP")+P("|"))
+ local p_nd=spacing*(P("ND")+P("|"))
+ local p_filterroutines=
+ (1-subroutines)^0*subroutines*spaces*Cmt(cardinal,initialize)*(Cmt(cardinal*spaces*cardinal*p_rd,setroutine)*p_np+P(1))^1
+ local p_filtershapes=
+ (1-charstrings)^0*charstrings*spaces*Cmt(cardinal,initialize)*(Cmt(name*spaces*cardinal*p_rd,setshapes)*p_nd+P(1))^1
local p_filternames=Ct (
- (1-charstrings)^0*charstrings*spaces*Cmt(cardinal,initialize)*(Cmt(name*spaces*cardinal,progress)+P(1))^1
+ (1-charstrings)^0*charstrings*spaces*Cmt(cardinal,initialize)*(Cmt(name*spaces*cardinal,setvector)+P(1))^1
)
local p_filterencoding=(1-encoding)^0*encoding*spaces*digits*spaces*array*(1-dup)^0*Cf(
Ct("")*Cg(spacing*dup*spaces*cardinal*spaces*name*spaces*put)^1
,rawset)
- local decrypt
- do
- local r,c1,c2,n=0,0,0,0
- local function step(c)
- local cipher=byte(c)
- local plain=bxor(cipher,rshift(r,8))
- r=((cipher+r)*c1+c2)%65536
- return char(plain)
- end
- decrypt=function(binary)
- r,c1,c2,n=55665,52845,22719,4
- binary=gsub(binary,".",step)
- return sub(binary,n+1)
- end
- end
- local function loadpfbvector(filename)
+ local function loadpfbvector(filename,shapestoo)
local data=io.loaddata(resolvers.findfile(filename))
if not data then
report_pfb("no data in %a",filename)
@@ -24291,18 +24336,30 @@ do
report_pfb("no binary data in %a",filename)
return
end
- binary=decrypt(binary,4)
- local vector=lpegmatch(p_filternames,binary)
- for i=1,#vector do
- vector[i-1]=vector[i]
- end
- vector[#vector]=nil
- if not vector then
- report_pfb("no vector in %a",filename)
- return
- end
+ binary=decrypt(binary,55665,4)
+ local names={}
local encoding=lpegmatch(p_filterencoding,ascii)
- return vector,encoding
+ local glyphs={}
+ routines,vector,chars={},{},{}
+ if shapestoo then
+ lpegmatch(p_filterroutines,binary)
+ lpegmatch(p_filtershapes,binary)
+ local data={
+ dictionaries={
+ {
+ charstrings=chars,
+ charset=vector,
+ subroutines=routines,
+ }
+ },
+ }
+ fonts.handlers.otf.readers.parsecharstrings(data,glyphs,true,true)
+ else
+ lpegmatch(p_filternames,binary)
+ end
+ names=vector
+ routines,vector,chars=nil,nil,nil
+ return names,encoding,glyphs
end
local pfb=handlers.pfb or {}
handlers.pfb=pfb
@@ -24326,6 +24383,10 @@ do
end
end
end
+ get_shapes=function(pfbname)
+ local vector,encoding,glyphs=loadpfbvector(pfbname,true)
+ return glyphs
+ end
end
local spacer=patterns.spacer
local whitespace=patterns.whitespace
@@ -24474,6 +24535,22 @@ function readers.loadfont(afmname,pfbname)
return data
end
end
+function readers.loadshapes(filename)
+ local fullname=resolvers.findfile(filename) or ""
+ if fullname=="" then
+ return {
+ filename="not found: "..filename,
+ glyphs={}
+ }
+ else
+ return {
+ filename=fullname,
+ format="opentype",
+ glyphs=get_shapes(fullname) or {},
+ units=1000,
+ }
+ end
+end
function readers.getinfo(filename)
local data=read(resolvers.findfile(filename),infoparser)
if data then