summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/font-syn.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/font-syn.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/font-syn.lua597
1 files changed, 384 insertions, 213 deletions
diff --git a/Master/texmf-dist/tex/context/base/font-syn.lua b/Master/texmf-dist/tex/context/base/font-syn.lua
index 5ad92e0022d..1d444cdc705 100644
--- a/Master/texmf-dist/tex/context/base/font-syn.lua
+++ b/Master/texmf-dist/tex/context/base/font-syn.lua
@@ -17,8 +17,14 @@ local lpegmatch = lpeg.match
local utfgsub, utflower = utf.gsub, utf.lower
local unpack = unpack or table.unpack
-local trace_names = false trackers.register("fonts.names", function(v) trace_names = v end)
-local trace_warnings = false trackers.register("fonts.warnings", function(v) trace_warnings = v end)
+local allocate = utilities.storage.allocate
+local sparse = utilities.storage.sparse
+
+local trace_names = false trackers.register("fonts.names", function(v) trace_names = v end)
+local trace_warnings = false trackers.register("fonts.warnings", function(v) trace_warnings = v end)
+local trace_specifications = false trackers.register("fonts.specifications", function(v) trace_specifications = v end)
+
+local report_names = logs.reporter("fonts","names")
--[[ldx--
<p>This module implements a name to filename resolver. Names are resolved
@@ -27,31 +33,33 @@ using a table that has keys filtered from the font related files.</p>
local texsprint = (tex and tex.sprint) or print
-fonts = fonts or { }
-input = input or { }
-texmf = texmf or { }
+fonts = fonts or { } -- also used elsewhere
+
+local names = { }
+fonts.names = names
-fonts.names = fonts.names or { }
-fonts.names.filters = fonts.names.filters or { }
-fonts.names.data = fonts.names.data or { }
+names.filters = names.filters or { }
+local filters = names.filters
-local names = fonts.names
-local filters = fonts.names.filters
+names.data = names.data or { }
-names.version = 1.103
+names.version = 1.110
names.basename = "names"
names.saved = false
names.loaded = false
names.be_clever = true
names.enabled = true
-names.autoreload = toboolean(os.env['MTX.FONTS.AUTOLOAD'] or os.env['MTX_FONTS_AUTOLOAD'] or "no")
names.cache = containers.define("fonts","data",names.version,true)
+local autoreload = true
+
+directives.register("fonts.autoreload", function(v) autoreload = toboolean(v) end)
+
--[[ldx--
<p>A few helpers.</p>
--ldx]]--
-local P, C, Cc, Cs, Carg = lpeg.P, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Carg
+local P, C, Cc, Cs = lpeg.P, lpeg.C, lpeg.Cc, lpeg.Cs
-- what to do with 'thin'
@@ -74,6 +82,10 @@ local weights = Cs ( -- not extra
+ P("regular") / "normal"
)
+local normalized_weights = sparse {
+ regular = "normal",
+}
+
local styles = Cs (
P("reverseoblique") / "reverseitalic"
+ P("regular") / "normal"
@@ -85,6 +97,12 @@ local styles = Cs (
+ P("ita") / "italic"
)
+local normalized_styles = sparse {
+ reverseoblique = "reverseitalic",
+ regular = "normal",
+ oblique = "italic",
+}
+
local widths = Cs(
P("condensed")
+ P("thin")
@@ -94,22 +112,26 @@ local widths = Cs(
+ P("book") / "normal"
)
+local normalized_widths = sparse()
+
local variants = Cs( -- fax casual
P("smallcaps")
+ P("oldstyle")
+ P("caps") / "smallcaps"
)
+local normalized_variants = sparse()
+
local any = P(1)
-local analysed_table
+local analyzed_table
-local analyser = Cs (
+local analyzer = Cs (
(
- weights / function(s) analysed_table[1] = s return "" end
- + styles / function(s) analysed_table[2] = s return "" end
- + widths / function(s) analysed_table[3] = s return "" end
- + variants / function(s) analysed_table[4] = s return "" end
+ weights / function(s) analyzed_table[1] = s return "" end
+ + styles / function(s) analyzed_table[2] = s return "" end
+ + widths / function(s) analyzed_table[3] = s return "" end
+ + variants / function(s) analyzed_table[4] = s return "" end
+ any
)^0
)
@@ -123,24 +145,24 @@ function names.splitspec(askedname)
width = width and lpegmatch(widths, width) or width
variant = variant and lpegmatch(variants,variant) or variant
if trace_names then
- logs.report("fonts","requested name '%s' split in name '%s', weight '%s', style '%s', width '%s' and variant '%s'",
+ report_names("requested name '%s' split in name '%s', weight '%s', style '%s', width '%s' and variant '%s'",
askedname,name or '',weight or '',style or '',width or '',variant or '')
end
if not weight or not weight or not width or not variant then
weight, style, width, variant = weight or "normal", style or "normal", width or "normal", variant or "normal"
if trace_names then
- logs.report("fonts","request '%s' normalized to '%s-%s-%s-%s-%s'",
+ report_names("request '%s' normalized to '%s-%s-%s-%s-%s'",
askedname,name,weight,style,width,variant)
end
end
return name or askedname, weight, style, width, variant
end
-local function analysespec(somename)
+local function analyzespec(somename)
if somename then
- analysed_table = { }
- local name = lpegmatch(analyser,somename)
- return name, analysed_table[1], analysed_table[2], analysed_table[3], analysed_table[4]
+ analyzed_table = { }
+ local name = lpegmatch(analyzer,somename)
+ return name, analyzed_table[1], analyzed_table[2], analyzed_table[3], analyzed_table[4]
end
end
@@ -171,9 +193,9 @@ filters.otf = fontloader.fullinfo
function filters.afm(name)
-- we could parse the afm file as well, and then report an error but
-- it's not worth the trouble
- local pfbname = resolvers.find_file(file.removesuffix(name)..".pfb","pfb") or ""
+ local pfbname = resolvers.findfile(file.removesuffix(name)..".pfb","pfb") or ""
if pfbname == "" then
- pfbname = resolvers.find_file(file.removesuffix(file.basename(name))..".pfb","pfb") or ""
+ pfbname = resolvers.findfile(file.removesuffix(file.basename(name))..".pfb","pfb") or ""
end
if pfbname ~= "" then
local f = io.open(name)
@@ -210,33 +232,39 @@ filters.list = {
--~ "ttc", "otf", "ttf", "dfont", "afm",
}
-names.xml_configuration_file = "fonts.conf" -- a bit weird format, bonus feature
-names.environment_path_variable = "OSFONTDIR" -- the official way, in minimals etc
+names.fontconfigfile = "fonts.conf" -- a bit weird format, bonus feature
+names.osfontdirvariable = "OSFONTDIR" -- the official way, in minimals etc
filters.paths = { }
filters.names = { }
function names.getpaths(trace)
- local hash, result = { }, { }
- local function collect(t)
+ local hash, result, r = { }, { }, 0
+ local function collect(t,where)
for i=1, #t do
- local v = resolvers.clean_path(t[i])
- v = gsub(v,"/+$","")
+ local v = resolvers.cleanpath(t[i])
+ v = gsub(v,"/+$","") -- not needed any more
local key = lower(v)
+ report_names("adding path from %s: %s",where,v)
if not hash[key] then
- hash[key], result[#result+1] = true, v
+ r = r + 1
+ result[r] = v
+ hash[key] = true
end
end
end
- local path = names.environment_path_variable or ""
+ local path = names.osfontdirvariable or ""
if path ~= "" then
- collect(resolvers.expanded_path_list(path))
+ collect(resolvers.expandedpathlist(path),path)
end
if xml then
- local confname = names.xml_configuration_file or ""
+ local confname = resolvers.expansion("FONTCONFIG_FILE") or ""
+ if confname == "" then
+ confname = names.fontconfigfile or ""
+ end
if confname ~= "" then
-- first look in the tex tree
- local name = resolvers.find_file(confname,"other")
+ local name = resolvers.findfile(confname,"fontconfig files") or ""
if name == "" then
-- after all, fontconfig is a unix thing
name = file.join("/etc",confname)
@@ -246,7 +274,7 @@ function names.getpaths(trace)
end
if name ~= "" and lfs.isfile(name) then
if trace_names then
- logs.report("fontnames","loading fontconfig file: %s",name)
+ report_names("loading fontconfig file: %s",name)
end
local xmldata = xml.load(name)
-- begin of untested mess
@@ -259,19 +287,19 @@ function names.getpaths(trace)
end
if lfs.isfile(incname) then
if trace_names then
- logs.report("fontnames","merging included fontconfig file: %s",incname)
+ report_names("merging included fontconfig file: %s",incname)
end
return io.loaddata(incname)
elseif trace_names then
- logs.report("fontnames","ignoring included fontconfig file: %s",incname)
+ report_names("ignoring included fontconfig file: %s",incname)
end
end)
-- end of untested mess
local fontdirs = xml.collect_texts(xmldata,"dir",true)
if trace_names then
- logs.report("fontnames","%s dirs found in fontconfig",#fontdirs)
+ report_names("%s dirs found in fontconfig",#fontdirs)
end
- collect(fontdirs)
+ collect(fontdirs,"fontconfig file")
end
end
end
@@ -287,7 +315,20 @@ local function cleanname(name)
-- return (utfgsub(utfgsub(lower(str),"[^%a%A%d]",""),"%s",""))
end
-names.cleanname = cleanname
+local function cleanfilename(fullname,defaultsuffix)
+ local _, _, name, suffix = file.splitname(fullname)
+ name = gsub(lower(name),"[^%a%d]","")
+ if suffix and suffix ~= "" then
+ return name .. ".".. suffix
+ elseif defaultsuffix and defaultsuffix ~= "" then
+ return name .. ".".. defaultsuffix
+ else
+ return name
+ end
+end
+
+names.cleanname = cleanname
+names.cleanfilename = cleanfilename
local function check_names(result)
local names = result.names
@@ -305,10 +346,10 @@ local function walk_tree(pathlist,suffix,identify)
if pathlist then
for i=1,#pathlist do
local path = pathlist[i]
- path = resolvers.clean_path(path .. "/")
+ path = resolvers.cleanpath(path .. "/")
path = gsub(path,"/+","/")
local pattern = path .. "**." .. suffix -- ** forces recurse
- logs.report("fontnames", "globbing path %s",pattern)
+ report_names( "globbing path %s",pattern)
local t = dir.glob(pattern)
sort(t,sorter)
for j=1,#t do
@@ -343,8 +384,8 @@ local function check_name(data,result,filename,suffix,subfont)
modifiers = modifiers and cleanname(modifiers)
weight = weight and cleanname(weight)
italicangle = (italicangle == 0) and nil
- -- analyse
- local a_name, a_weight, a_style, a_width, a_variant = analysespec(fullname or fontname or familyname)
+ -- analyze
+ local a_name, a_weight, a_style, a_width, a_variant = analyzespec(fullname or fontname or familyname)
-- check
local width = a_width
local variant = a_variant
@@ -368,7 +409,7 @@ local function check_name(data,result,filename,suffix,subfont)
fullname = fullname or fontname
familyname = familyname or fontname
specifications[#specifications + 1] = {
- filename = filename,
+ filename = filename, -- unresolved
format = lower(suffix),
subfont = subfont,
rawname = rawname,
@@ -395,11 +436,11 @@ local function cleanupkeywords()
for i=1,#specifications do
local s = specifications[i]
-- fix (sofar styles are taken from the name, and widths from the specification)
- local _, b_weight, b_style, b_width, b_variant = analysespec(s.weight)
- local _, c_weight, c_style, c_width, c_variant = analysespec(s.style)
- local _, d_weight, d_style, d_width, d_variant = analysespec(s.width)
- local _, e_weight, e_style, e_width, e_variant = analysespec(s.variant)
- local _, f_weight, f_style, f_width, f_variant = analysespec(s.fullname or "")
+ local _, b_weight, b_style, b_width, b_variant = analyzespec(s.weight)
+ local _, c_weight, c_style, c_width, c_variant = analyzespec(s.style)
+ local _, d_weight, d_style, d_width, d_variant = analyzespec(s.width)
+ local _, e_weight, e_style, e_width, e_variant = analyzespec(s.variant)
+ local _, f_weight, f_style, f_width, f_variant = analyzespec(s.fullname or "")
local weight = b_weight or c_weight or d_weight or e_weight or f_weight or "normal"
local style = b_style or c_style or d_style or e_style or f_style or "normal"
local width = b_width or c_width or d_width or e_width or f_width or "normal"
@@ -529,12 +570,12 @@ local function checkduplicate(where) -- fails on "Romantik" but that's a border
local nv = #v
if nv > 1 then
if trace_warnings then
- logs.report("fontnames", "double lookup: %s => %s",k,concat(v," | "))
+ report_names( "double lookup: %s => %s",k,concat(v," | "))
end
n = n + nv
end
end
- logs.report("fontnames", "%s double lookups in %s",n,where)
+ report_names( "%s double lookups in %s",n,where)
end
local function checkduplicates()
@@ -588,28 +629,42 @@ local function unpackreferences()
end
end
-local function analysefiles()
+local function analyzefiles()
local data = names.data
- local done, totalnofread, totalnofskipped = { }, 0, 0
+ local done, totalnofread, totalnofskipped, totalnofduplicates, nofread, nofskipped, nofduplicates = { }, 0, 0, 0, 0, 0, 0
local skip_paths, skip_names = filters.paths, filters.names
+--~ local trace_warnings = true
local function identify(completename,name,suffix,storedname)
local basename = file.basename(completename)
local basepath = file.dirname(completename)
+ nofread = nofread + 1
if done[name] then
-- already done (avoid otf afm clash)
+ if trace_names then
+ report_names("%s font %s already done",suffix,completename)
+ end
+ nofduplicates = nofduplicates + 1
+ nofskipped = nofskipped + 1
elseif not io.exists(completename) then
-- weird error
- elseif not file.is_qualified_path(completename) and resolvers.find_file(completename,suffix) == "" then
+ if trace_names then
+ report_names("%s font %s does not really exist",suffix,completename)
+ end
+ nofskipped = nofskipped + 1
+ elseif not file.is_qualified_path(completename) and resolvers.findfile(completename,suffix) == "" then
-- not locateble by backend anyway
+ if trace_names then
+ report_names("%s font %s cannot be found by backend",suffix,completename)
+ end
+ nofskipped = nofskipped + 1
else
- nofread = nofread + 1
if #skip_paths > 0 then
for i=1,#skip_paths do
if find(basepath,skip_paths[i]) then
if trace_names then
- logs.report("fontnames","rejecting path of %s font %s",suffix,completename)
- logs.push()
+ report_names("rejecting path of %s font %s",suffix,completename)
end
+ nofskipped = nofskipped + 1
return
end
end
@@ -619,77 +674,84 @@ local function analysefiles()
if find(basename,skip_names[i]) then
done[name] = true
if trace_names then
- logs.report("fontnames","rejecting name of %s font %s",suffix,completename)
- logs.push()
+ report_names("rejecting name of %s font %s",suffix,completename)
end
+ nofskipped = nofskipped + 1
return
end
end
end
if trace_names then
- logs.report("fontnames","identifying %s font %s",suffix,completename)
- logs.push()
+ report_names("identifying %s font %s",suffix,completename)
end
local result, message = filters[lower(suffix)](completename)
- if trace_names then
- logs.pop()
- end
if result then
- if not result[1] then
- local ok = check_name(data,result,storedname,suffix)
- if not ok then
- nofskipped = nofskipped + 1
- end
- else
+ if result[1] then
for r=1,#result do
local ok = check_name(data,result[r],storedname,suffix,r-1) -- subfonts start at zero
- if not ok then
- nofskipped = nofskipped + 1
- end
+ -- if not ok then
+ -- nofskipped = nofskipped + 1
+ -- end
end
+ else
+ local ok = check_name(data,result,storedname,suffix)
+ -- if not ok then
+ -- nofskipped = nofskipped + 1
+ -- end
end
if trace_warnings and message and message ~= "" then
- logs.report("fontnames","warning when identifying %s font %s: %s",suffix,completename,message)
+ report_names("warning when identifying %s font %s: %s",suffix,completename,message)
end
elseif trace_warnings then
- logs.report("fontnames","error when identifying %s font %s: %s",suffix,completename,message or "unknown")
+ nofskipped = nofskipped + 1
+ report_names("error when identifying %s font %s: %s",suffix,completename,message or "unknown")
end
done[name] = true
end
+ logs.flush() -- a bit overkill for each font, maybe not needed here
end
local function traverse(what, method)
local list = filters.list
for n=1,#list do
local suffix = list[n]
local t = os.gettimeofday() -- use elapser
- nofread, nofskipped = 0, 0
+ nofread, nofskipped, nofduplicates = 0, 0, 0
suffix = lower(suffix)
- logs.report("fontnames", "identifying %s font files with suffix %s",what,suffix)
+ report_names( "identifying %s font files with suffix %s",what,suffix)
method(suffix)
suffix = upper(suffix)
- logs.report("fontnames", "identifying %s font files with suffix %s",what,suffix)
+ report_names( "identifying %s font files with suffix %s",what,suffix)
method(suffix)
- totalnofread, totalnofskipped = totalnofread + nofread, totalnofskipped + nofskipped
+ totalnofread, totalnofskipped, totalnofduplicates = totalnofread + nofread, totalnofskipped + nofskipped, totalnofduplicates + nofduplicates
local elapsed = os.gettimeofday() - t
- logs.report("fontnames", "%s %s files identified, %s hash entries added, runtime %0.3f seconds",nofread,what,nofread-nofskipped,elapsed)
+ report_names( "%s %s files identified, %s skipped, %s duplicates, %s hash entries added, runtime %0.3f seconds",nofread,what,nofskipped,nofduplicates,nofread-nofskipped,elapsed)
end
+ logs.flush()
end
if not trace_warnings then
- logs.report("fontnames", "warnings are disabled (tracker 'fonts.warnings')")
+ report_names( "warnings are disabled (tracker 'fonts.warnings')")
end
traverse("tree", function(suffix) -- TEXTREE only
- resolvers.with_files(".*%." .. suffix .. "$", function(method,root,path,name)
- if method == "file" then
+ resolvers.dowithfilesintree(".*%." .. suffix .. "$", function(method,root,path,name)
+ if method == "file" or method == "tree" then
local completename = root .."/" .. path .. "/" .. name
- identify(completename,name,suffix,name,name)
+ completename = resolvers.resolve(completename) -- no shortcut
+ identify(completename,name,suffix,name)
+ return true
end
+ end, function(blobtype,blobpath,pattern)
+ blobpath = resolvers.resolve(blobpath) -- no shortcut
+ report_names( "scanning %s for %s files",blobpath,suffix)
+ end, function(blobtype,blobpath,pattern,total,checked,done)
+ blobpath = resolvers.resolve(blobpath) -- no shortcut
+ report_names( "%s entries found, %s %s files checked, %s okay",total,checked,suffix,done)
end)
end)
if texconfig.kpse_init then
-- we do this only for a stupid names run, not used for context itself,
-- using the vars is to clumsy so we just stick to a full scan instead
traverse("lsr", function(suffix) -- all trees
- local pathlist = resolvers.split_path(resolvers.show_path("ls-R") or "")
+ local pathlist = resolvers.splitpath(resolvers.showpath("ls-R") or "")
walk_tree(pathlist,suffix,identify)
end)
else
@@ -697,11 +759,22 @@ local function analysefiles()
walk_tree(names.getpaths(trace),suffix,identify)
end)
end
- data.statistics.readfiles, data.statistics.skippedfiles = totalnofread, totalnofskipped
+ data.statistics.readfiles, data.statistics.skippedfiles, data.statistics.duplicatefiles = totalnofread, totalnofskipped, totalnofduplicates
+end
+
+local function addfilenames()
+ local data = names.data
+ local specifications = data.specifications
+ local files = { }
+ for i=1,#specifications do
+ local fullname = specifications[i].filename
+ files[cleanfilename(fullname)] = fullname
+ end
+ data.files = files
end
local function rejectclashes() -- just to be sure, so no explicit afm will be found then
- local specifications, used, okay = names.data.specifications, { }, { }
+ local specifications, used, okay, o = names.data.specifications, { }, { }, 0
for i=1,#specifications do
local s = specifications[i]
local f = s.fontname
@@ -709,18 +782,21 @@ local function rejectclashes() -- just to be sure, so no explicit afm will be fo
local fnd, fnm = used[f], s.filename
if fnd then
if trace_warnings then
- logs.report("fontnames", "fontname '%s' clashes, rejecting '%s' in favor of '%s'",f,fnm,fnd)
+ report_names( "fontname '%s' clashes, rejecting '%s' in favor of '%s'",f,fnm,fnd)
end
else
- used[f], okay[#okay+1] = fnm, s
+ used[f] = fnm
+ o = o + 1
+ okay[o] = s
end
else
- okay[#okay+1] = s
+ o = o + 1
+ okay[o] = s
end
end
local d = #specifications - #okay
if d > 0 then
- logs.report("fontnames", "%s files rejected due to clashes",d)
+ report_names( "%s files rejected due to clashes",d)
end
names.data.specifications = okay
end
@@ -737,30 +813,31 @@ local function resetdata()
specifications = { },
families = { },
statistics = { },
- data_state = resolvers.data_state(),
+ datastate = resolvers.datastate(),
}
end
function names.identify()
resetdata()
- analysefiles()
+ analyzefiles()
rejectclashes()
collectfamilies()
collectstatistics()
cleanupkeywords()
collecthashes()
checkduplicates()
+ addfilenames()
-- sorthashes() -- will be resorted when saved
end
function names.is_permitted(name)
- return containers.is_usable(names.cache(), name)
+ return containers.is_usable(names.cache, name)
end
-function names.write_data(name,data)
- containers.write(names.cache(),name,data)
+function names.writedata(name,data)
+ containers.write(names.cache,name,data)
end
-function names.read_data(name)
- return containers.read(names.cache(),name)
+function names.readdata(name)
+ return containers.read(names.cache,name)
end
function names.load(reload,verbose)
@@ -768,13 +845,13 @@ function names.load(reload,verbose)
if reload then
if names.is_permitted(names.basename) then
names.identify(verbose)
- names.write_data(names.basename,names.data)
+ names.writedata(names.basename,names.data)
else
- logs.report("font table", "unable to access database cache")
+ report_names("unable to access database cache")
end
names.saved = true
end
- local data = names.read_data(names.basename)
+ local data = names.readdata(names.basename)
names.data = data
if not names.saved then
if not data or not next(data) or not data.specifications or not next(data.specifications) then
@@ -783,7 +860,7 @@ function names.load(reload,verbose)
names.saved = true
end
if not data then
- logs.report("font table", "accessing the data table failed")
+ report_names("accessing the data table failed")
else
unpackreferences()
sorthashes()
@@ -809,7 +886,7 @@ local function list_them(mapping,sorted,pattern,t,all)
end
function names.list(pattern,reload,all) -- here?
- names.load(reload)
+ names.load() -- todo reload
if names.loaded then
local t = { }
local data = names.data
@@ -838,19 +915,21 @@ local reloaded = false
local function is_reloaded()
if not reloaded then
local data = names.data
- if names.autoreload then
- local c_status = table.serialize(resolvers.data_state())
- local f_status = table.serialize(data.data_state)
+ if autoreload then
+ local c_status = table.serialize(resolvers.datastate())
+ local f_status = table.serialize(data.datastate)
if c_status == f_status then
- -- logs.report("fonts","font database matches configuration and file hashes")
+ report_names("font database has matching configuration and file hashes")
return
else
- logs.report("fonts","font database does not match configuration and file hashes")
+ report_names("font database has mismatching configuration and file hashes")
end
+ else
+ report_names("font database is regenerated (controlled by directive 'fonts.autoreload')")
end
names.loaded = false
reloaded = true
- io.flush()
+ logs.flush()
names.load(true)
end
end
@@ -886,7 +965,7 @@ local function foundname(name,sub) -- sub is not used currently
local found = mappings[l][name]
if found then
if trace_names then
- logs.report("fonts","resolved via direct name match: '%s'",name)
+ report_names("resolved via direct name match: '%s'",name)
end
return found
end
@@ -896,7 +975,7 @@ local function foundname(name,sub) -- sub is not used currently
local found, fname = fuzzy(mappings[l],sorted_mappings[l],name,sub)
if found then
if trace_names then
- logs.report("fonts","resolved via fuzzy name match: '%s' => '%s'",name,fname)
+ report_names("resolved via fuzzy name match: '%s' => '%s'",name,fname)
end
return found
end
@@ -906,7 +985,7 @@ local function foundname(name,sub) -- sub is not used currently
local found = fallbacks[l][name]
if found then
if trace_names then
- logs.report("fonts","resolved via direct fallback match: '%s'",name)
+ report_names("resolved via direct fallback match: '%s'",name)
end
return found
end
@@ -916,11 +995,14 @@ local function foundname(name,sub) -- sub is not used currently
local found, fname = fuzzy(sorted_mappings[l],sorted_fallbacks[l],name,sub)
if found then
if trace_names then
- logs.report("fonts","resolved via fuzzy fallback match: '%s' => '%s'",name,fname)
+ report_names("resolved via fuzzy fallback match: '%s' => '%s'",name,fname)
end
return found
end
end
+ if trace_names then
+ report_names("font with name '%s' cannot be found",name)
+ end
end
function names.resolvedspecification(askedname,sub)
@@ -942,6 +1024,17 @@ function names.resolve(askedname,sub)
end
end
+function names.getfilename(askedname,suffix) -- last resort, strip funny chars
+ names.load()
+ local files = names.data.files
+ askedname = files and files[cleanfilename(askedname,suffix)] or ""
+ if askedname == "" then
+ return ""
+ else
+ return resolvers.findbinfile(askedname,suffix) or ""
+ end
+end
+
-- specified search
local function s_collect_weight_style_width_variant(found,done,all,weight,style,width,variant,family)
@@ -1144,7 +1237,7 @@ local function collect(stage,found,done,name,weight,style,width,variant,all)
strictname = "^".. name -- to be checked
local family = families[name]
if trace_names then
- logs.report("fonts","resolving name '%s', weight '%s', style '%s', width '%s', variant '%s'",
+ report_names("resolving name '%s', weight '%s', style '%s', width '%s', variant '%s'",
name or "?",tostring(weight),tostring(style),tostring(width),tostring(variant))
end
--~ print(name,table.serialize(family))
@@ -1153,27 +1246,27 @@ local function collect(stage,found,done,name,weight,style,width,variant,all)
if width and width ~= "" then
if variant and variant ~= "" then
if trace_names then
- logs.report("fonts","resolving stage %s, name '%s', weight '%s', style '%s', width '%s', variant '%s'",stage,name,weight,style,width,variant)
+ report_names("resolving stage %s, name '%s', weight '%s', style '%s', width '%s', variant '%s'",stage,name,weight,style,width,variant)
end
s_collect_weight_style_width_variant(found,done,all,weight,style,width,variant,family)
m_collect_weight_style_width_variant(found,done,all,weight,style,width,variant,families,sorted,strictname)
else
if trace_names then
- logs.report("fonts","resolving stage %s, name '%s', weight '%s', style '%s', width '%s'",stage,name,weight,style,width)
+ report_names("resolving stage %s, name '%s', weight '%s', style '%s', width '%s'",stage,name,weight,style,width)
end
s_collect_weight_style_width(found,done,all,weight,style,width,family)
m_collect_weight_style_width(found,done,all,weight,style,width,families,sorted,strictname)
end
else
if trace_names then
- logs.report("fonts","resolving stage %s, name '%s', weight '%s', style '%s'",stage,name,weight,style)
+ report_names("resolving stage %s, name '%s', weight '%s', style '%s'",stage,name,weight,style)
end
s_collect_weight_style(found,done,all,weight,style,family)
m_collect_weight_style(found,done,all,weight,style,families,sorted,strictname)
end
else
if trace_names then
- logs.report("fonts","resolving stage %s, name '%s', weight '%s'",stage,name,weight)
+ report_names("resolving stage %s, name '%s', weight '%s'",stage,name,weight)
end
s_collect_weight(found,done,all,weight,family)
m_collect_weight(found,done,all,weight,families,sorted,strictname)
@@ -1181,33 +1274,33 @@ local function collect(stage,found,done,name,weight,style,width,variant,all)
elseif style and style ~= "" then
if width and width ~= "" then
if trace_names then
- logs.report("fonts","resolving stage %s, name '%s', style '%s', width '%s'",stage,name,style,width)
+ report_names("resolving stage %s, name '%s', style '%s', width '%s'",stage,name,style,width)
end
s_collect_style_width(found,done,all,style,width,family)
m_collect_style_width(found,done,all,style,width,families,sorted,strictname)
else
if trace_names then
- logs.report("fonts","resolving stage %s, name '%s', style '%s'",stage,name,style)
+ report_names("resolving stage %s, name '%s', style '%s'",stage,name,style)
end
s_collect_style(found,done,all,style,family)
m_collect_style(found,done,all,style,families,sorted,strictname)
end
elseif width and width ~= "" then
if trace_names then
- logs.report("fonts","resolving stage %s, name '%s', width '%s'",stage,name,width)
+ report_names("resolving stage %s, name '%s', width '%s'",stage,name,width)
end
s_collect_width(found,done,all,width,family)
m_collect_width(found,done,all,width,families,sorted,strictname)
else
if trace_names then
- logs.report("fonts","resolving stage %s, name '%s'",stage,name)
+ report_names("resolving stage %s, name '%s'",stage,name)
end
s_collect(found,done,all,family)
m_collect(found,done,all,families,sorted,strictname)
end
end
-function heuristic(name,weight,style,width,variant,all) -- todo: fallbacks
+local function heuristic(name,weight,style,width,variant,all) -- todo: fallbacks
local found, done = { }, { }
--~ print(name,weight,style,width,variant)
weight, style, width, variant = weight or "normal", style or "normal", width or "normal", variant or "normal"
@@ -1236,11 +1329,11 @@ function heuristic(name,weight,style,width,variant,all) -- todo: fallbacks
if nf then
local t = { }
for i=1,nf do
- t[#t+1] = format("'%s'",found[i].fontname)
+ t[i] = format("'%s'",found[i].fontname)
end
- logs.report("fonts","name '%s' resolved to %s instances: %s",name,nf,concat(t," "))
+ report_names("name '%s' resolved to %s instances: %s",name,nf,concat(t," "))
else
- logs.report("fonts","name '%s' unresolved",name)
+ report_names("name '%s' unresolved",name)
end
end
if all then
@@ -1252,7 +1345,7 @@ end
function names.specification(askedname,weight,style,width,variant,reload,all)
if askedname and askedname ~= "" and names.enabled then
- askedname = lower(askedname) -- or cleanname
+ askedname = cleanname(askedname) -- or cleanname
names.load(reload)
local found = heuristic(askedname,weight,style,width,variant,all)
if not found and is_reloaded() then
@@ -1267,7 +1360,7 @@ end
function names.collect(askedname,weight,style,width,variant,reload,all)
if askedname and askedname ~= "" and names.enabled then
- askedname = lower(askedname) -- or cleanname
+ askedname = cleanname(askedname) -- or cleanname
names.load(reload)
local list = heuristic(askedname,weight,style,width,variant,true)
if not list or #list == 0 and is_reloaded() then
@@ -1282,7 +1375,7 @@ function names.collectspec(askedname,reload,all)
return names.collect(name,weight,style,width,variant,reload,all)
end
-function names.resolvespec(askedname,sub)
+function names.resolvespec(askedname,sub) -- redefined later
local found = names.specification(names.splitspec(askedname))
if found then
return found.filename, found.subfont and found.rawname
@@ -1291,14 +1384,14 @@ end
function names.collectfiles(askedname,reload) -- no all
if askedname and askedname ~= "" and names.enabled then
- askedname = lower(askedname) -- or cleanname
+ askedname = cleanname(askedname) -- or cleanname
names.load(reload)
local list = { }
local basename = file.basename
local specifications = names.data.specifications
for i=1,#specifications do
local s = specifications[i]
- if find(lower(basename(s.filename)),askedname) then
+ if find(cleanname(basename(s.filename)),askedname) then
list[#list+1] = s
end
end
@@ -1306,65 +1399,71 @@ function names.collectfiles(askedname,reload) -- no all
end
end
---[[ldx--
-<p>Fallbacks, not permanent but a transition thing.</p>
---ldx]]--
-
-names.new_to_old = {
- ["lmroman10-capsregular"] = "lmromancaps10-oblique",
- ["lmroman10-capsoblique"] = "lmromancaps10-regular",
- ["lmroman10-demi"] = "lmromandemi10-oblique",
- ["lmroman10-demioblique"] = "lmromandemi10-regular",
- ["lmroman8-oblique"] = "lmromanslant8-regular",
- ["lmroman9-oblique"] = "lmromanslant9-regular",
- ["lmroman10-oblique"] = "lmromanslant10-regular",
- ["lmroman12-oblique"] = "lmromanslant12-regular",
- ["lmroman17-oblique"] = "lmromanslant17-regular",
- ["lmroman10-boldoblique"] = "lmromanslant10-bold",
- ["lmroman10-dunhill"] = "lmromandunh10-oblique",
- ["lmroman10-dunhilloblique"] = "lmromandunh10-regular",
- ["lmroman10-unslanted"] = "lmromanunsl10-regular",
- ["lmsans10-demicondensed"] = "lmsansdemicond10-regular",
- ["lmsans10-demicondensedoblique"] = "lmsansdemicond10-oblique",
- ["lmsansquotation8-bold"] = "lmsansquot8-bold",
- ["lmsansquotation8-boldoblique"] = "lmsansquot8-boldoblique",
- ["lmsansquotation8-oblique"] = "lmsansquot8-oblique",
- ["lmsansquotation8-regular"] = "lmsansquot8-regular",
- ["lmtypewriter8-regular"] = "lmmono8-regular",
- ["lmtypewriter9-regular"] = "lmmono9-regular",
- ["lmtypewriter10-regular"] = "lmmono10-regular",
- ["lmtypewriter12-regular"] = "lmmono12-regular",
- ["lmtypewriter10-italic"] = "lmmono10-italic",
- ["lmtypewriter10-oblique"] = "lmmonoslant10-regular",
- ["lmtypewriter10-capsoblique"] = "lmmonocaps10-oblique",
- ["lmtypewriter10-capsregular"] = "lmmonocaps10-regular",
- ["lmtypewriter10-light"] = "lmmonolt10-regular",
- ["lmtypewriter10-lightoblique"] = "lmmonolt10-oblique",
- ["lmtypewriter10-lightcondensed"] = "lmmonoltcond10-regular",
- ["lmtypewriter10-lightcondensedoblique"] = "lmmonoltcond10-oblique",
- ["lmtypewriter10-dark"] = "lmmonolt10-bold",
- ["lmtypewriter10-darkoblique"] = "lmmonolt10-boldoblique",
- ["lmtypewritervarwd10-regular"] = "lmmonoproplt10-regular",
- ["lmtypewritervarwd10-oblique"] = "lmmonoproplt10-oblique",
- ["lmtypewritervarwd10-light"] = "lmmonoprop10-regular",
- ["lmtypewritervarwd10-lightoblique"] = "lmmonoprop10-oblique",
- ["lmtypewritervarwd10-dark"] = "lmmonoproplt10-bold",
- ["lmtypewritervarwd10-darkoblique"] = "lmmonoproplt10-boldoblique",
-}
-
-names.old_to_new = table.swapped(names.new_to_old)
+--~ --[[ldx--
+--~ <p>Fallbacks, not permanent but a transition thing.</p>
+--~ --ldx]]--
+--~
+--~ names.new_to_old = allocate {
+--~ ["lmroman10-capsregular"] = "lmromancaps10-oblique",
+--~ ["lmroman10-capsoblique"] = "lmromancaps10-regular",
+--~ ["lmroman10-demi"] = "lmromandemi10-oblique",
+--~ ["lmroman10-demioblique"] = "lmromandemi10-regular",
+--~ ["lmroman8-oblique"] = "lmromanslant8-regular",
+--~ ["lmroman9-oblique"] = "lmromanslant9-regular",
+--~ ["lmroman10-oblique"] = "lmromanslant10-regular",
+--~ ["lmroman12-oblique"] = "lmromanslant12-regular",
+--~ ["lmroman17-oblique"] = "lmromanslant17-regular",
+--~ ["lmroman10-boldoblique"] = "lmromanslant10-bold",
+--~ ["lmroman10-dunhill"] = "lmromandunh10-oblique",
+--~ ["lmroman10-dunhilloblique"] = "lmromandunh10-regular",
+--~ ["lmroman10-unslanted"] = "lmromanunsl10-regular",
+--~ ["lmsans10-demicondensed"] = "lmsansdemicond10-regular",
+--~ ["lmsans10-demicondensedoblique"] = "lmsansdemicond10-oblique",
+--~ ["lmsansquotation8-bold"] = "lmsansquot8-bold",
+--~ ["lmsansquotation8-boldoblique"] = "lmsansquot8-boldoblique",
+--~ ["lmsansquotation8-oblique"] = "lmsansquot8-oblique",
+--~ ["lmsansquotation8-regular"] = "lmsansquot8-regular",
+--~ ["lmtypewriter8-regular"] = "lmmono8-regular",
+--~ ["lmtypewriter9-regular"] = "lmmono9-regular",
+--~ ["lmtypewriter10-regular"] = "lmmono10-regular",
+--~ ["lmtypewriter12-regular"] = "lmmono12-regular",
+--~ ["lmtypewriter10-italic"] = "lmmono10-italic",
+--~ ["lmtypewriter10-oblique"] = "lmmonoslant10-regular",
+--~ ["lmtypewriter10-capsoblique"] = "lmmonocaps10-oblique",
+--~ ["lmtypewriter10-capsregular"] = "lmmonocaps10-regular",
+--~ ["lmtypewriter10-light"] = "lmmonolt10-regular",
+--~ ["lmtypewriter10-lightoblique"] = "lmmonolt10-oblique",
+--~ ["lmtypewriter10-lightcondensed"] = "lmmonoltcond10-regular",
+--~ ["lmtypewriter10-lightcondensedoblique"] = "lmmonoltcond10-oblique",
+--~ ["lmtypewriter10-dark"] = "lmmonolt10-bold",
+--~ ["lmtypewriter10-darkoblique"] = "lmmonolt10-boldoblique",
+--~ ["lmtypewritervarwd10-regular"] = "lmmonoproplt10-regular",
+--~ ["lmtypewritervarwd10-oblique"] = "lmmonoproplt10-oblique",
+--~ ["lmtypewritervarwd10-light"] = "lmmonoprop10-regular",
+--~ ["lmtypewritervarwd10-lightoblique"] = "lmmonoprop10-oblique",
+--~ ["lmtypewritervarwd10-dark"] = "lmmonoproplt10-bold",
+--~ ["lmtypewritervarwd10-darkoblique"] = "lmmonoproplt10-boldoblique",
+--~ }
+--~
+--~ names.old_to_new = allocate(table.swapped(names.new_to_old))
+
+--~ todo:
+--~
+--~ blacklisted = {
+--~ ["cmr10.ttf"] = "completely messed up",
+--~ }
function names.exists(name)
local found = false
local list = filters.list
for k=1,#list do
local v = list[k]
- found = (resolvers.find_file(name,v) or "") ~= ""
+ found = (resolvers.findfile(name,v) or "") ~= ""
if found then
return found
end
end
- return ((resolvers.find_file(name,"tfm") or "") ~= "") or ((names.resolve(name) or "") ~= "")
+ return ((resolvers.findfile(name,"tfm") or "") ~= "") or ((names.resolve(name) or "") ~= "")
end
-- for i=1,fonts.names.lookup(pattern) do
@@ -1385,19 +1484,31 @@ function names.lookup(pattern,name,reload) -- todo: find
lookups = families[pattern]
end
if trace_names then
- logs.report("fonts","starting with %s lookups for '%s'",#lookups,pattern)
+ report_names("starting with %s lookups for '%s'",#lookups,pattern)
end
if lookups then
for key, value in gmatch(pattern,"([^=,]+)=([^=,]+)") do
- local t = { }
- for i=1,#lookups do
- local s = lookups[i]
- if s[key] == value then
- t[#t+1] = lookups[i]
+ local t, n = { }, 0
+ if find(value,"*") then
+ value = string.topattern(value)
+ for i=1,#lookups do
+ local s = lookups[i]
+ if find(s[key],value) then
+ n = n + 1
+ t[n] = lookups[i]
+ end
+ end
+ else
+ for i=1,#lookups do
+ local s = lookups[i]
+ if s[key] == value then
+ n = n + 1
+ t[n] = lookups[i]
+ end
end
end
if trace_names then
- logs.report("fonts","%s matches for key '%s' with value '%s'",#t,key,value)
+ report_names("%s matches for key '%s' with value '%s'",#t,key,value)
end
lookups = t
end
@@ -1424,31 +1535,91 @@ function names.getlookups(pattern,name,reload)
return lastlookups
end
-function table.formatcolumns(result)
- if result and #result > 0 then
- local widths = { }
- local first = result[1]
- local n = #first
- for i=1,n do
- widths[i] = 0
- end
- for i=1,#result do
- local r = result[i]
- for j=1,n do
- local w = #r[j]
- if w > widths[j] then
- widths[j] = w
+-- The following is new ... watch the overload!
+
+local specifications = allocate()
+names.specifications = specifications
+
+-- files = {
+-- name = "antykwapoltawskiego",
+-- list = {
+-- ["AntPoltLtCond-Regular.otf"] = {
+-- -- name = "antykwapoltawskiego",
+-- style = "regular",
+-- weight = "light",
+-- width = "condensed",
+-- },
+-- },
+-- }
+
+function names.register(files)
+ if files then
+ local list, commonname = files.list, files.name
+ if list then
+ local n, m = 0, 0
+ for filename, filespec in next, list do
+ local name = lower(filespec.name or commonname)
+ if name and name ~= "" then
+ local style = normalized_styles [lower(filespec.style or "normal")]
+ local width = normalized_widths [lower(filespec.width or "normal")]
+ local weight = normalized_weights [lower(filespec.weight or "normal")]
+ local variant = normalized_variants[lower(filespec.variant or "normal")]
+ local weights = specifications[name ] if not weights then weights = { } specifications[name ] = weights end
+ local styles = weights [weight] if not styles then styles = { } weights [weight] = styles end
+ local widths = styles [style ] if not widths then widths = { } styles [style ] = widths end
+ local variants = widths [width ] if not variants then variants = { } widths [width ] = variants end
+ variants[variant] = filename
+ n = n + 1
+ else
+ m = m + 1
end
end
+ if trace_specifications then
+ report_names("%s filenames registered, %s filenames rejected",n,m)
+ end
end
- for i=1,n do
- widths[i] = "%-" .. widths[i] .. "s"
+ end
+end
+
+function names.registered(name,weight,style,width,variant)
+ local ok = specifications[name]
+ ok = ok and (ok[(weight and weight ~= "" and weight ) or "normal"] or ok.normal)
+ ok = ok and (ok[(style and style ~= "" and style ) or "normal"] or ok.normal)
+ ok = ok and (ok[(width and width ~= "" and width ) or "normal"] or ok.normal)
+ ok = ok and (ok[(variant and variant ~= "" and variant) or "normal"] or ok.normal)
+ --
+ -- todo: same fallbacks as with database
+ --
+ if ok then
+ return {
+ filename = ok,
+ subname = "",
+ -- rawname = nil,
+ }
+ end
+end
+
+function names.resolvespec(askedname,sub) -- overloads previous definition
+ local name, weight, style, width, variant = names.splitspec(askedname)
+ if trace_specifications then
+ report_names("resolving specification: %s -> name=%s, weight=%s, style=%s, width=%s, variant=%s",askedname,name,weight,style,width,variant)
+ end
+ local found = names.registered(name,weight,style,width,variant)
+ if found and found.filename then
+ if trace_specifications then
+ report_names("resolved by registered names: %s -> %s",askedname,found.filename)
end
- local template = concat(widths," ")
- for i=1,#result do
- local str = format(template,unpack(result[i]))
- result[i] = string.strip(str)
+ return found.filename, found.subname, found.rawname
+ else
+ found = names.specification(name,weight,style,width,variant)
+ if found and found.filename then
+ if trace_specifications then
+ report_names("resolved by font database: %s -> %s",askedname,found.filename)
+ end
+ return found.filename, found.subfont and found.rawname
end
end
- return result
+ if trace_specifications then
+ report_names("unresolved: %s",askedname)
+ end
end