summaryrefslogtreecommitdiff
path: root/src/fontloader/misc
diff options
context:
space:
mode:
Diffstat (limited to 'src/fontloader/misc')
-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
12 files changed, 580 insertions, 459 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