diff options
Diffstat (limited to 'tex/context/base/font-syn.lua')
-rw-r--r-- | tex/context/base/font-syn.lua | 187 |
1 files changed, 115 insertions, 72 deletions
diff --git a/tex/context/base/font-syn.lua b/tex/context/base/font-syn.lua index 5ad92e002..b698fe27f 100644 --- a/tex/context/base/font-syn.lua +++ b/tex/context/base/font-syn.lua @@ -20,6 +20,8 @@ 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 report_names = logs.new("fontnames") + --[[ldx-- <p>This module implements a name to filename resolver. Names are resolved using a table that has keys filtered from the font related files.</p> @@ -44,7 +46,7 @@ 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.autoreload = toboolean(os.getenv('MTX.FONTS.AUTOLOAD') or os.getenv('MTX_FONTS_AUTOLOAD') or "no") names.cache = containers.define("fonts","data",names.version,true) --[[ldx-- @@ -123,13 +125,13 @@ 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 @@ -218,11 +220,12 @@ filters.names = { } function names.getpaths(trace) local hash, result = { }, { } - local function collect(t) + local function collect(t,where) for i=1, #t do local v = resolvers.clean_path(t[i]) - v = gsub(v,"/+$","") + 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 end @@ -230,13 +233,16 @@ function names.getpaths(trace) end local path = names.environment_path_variable or "" if path ~= "" then - collect(resolvers.expanded_path_list(path)) + collect(resolvers.expanded_path_list(path),path) end if xml then - local confname = names.xml_configuration_file or "" + local confname = resolvers.getenv("FONTCONFIG_FILE") or "" + if confname == "" then + confname = names.xml_configuration_file or "" + end if confname ~= "" then -- first look in the tex tree - local name = resolvers.find_file(confname,"other") + local name = resolvers.find_file(confname,"fontconfig files") or "" if name == "" then -- after all, fontconfig is a unix thing name = file.join("/etc",confname) @@ -246,7 +252,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 +265,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 @@ -308,7 +314,7 @@ local function walk_tree(pathlist,suffix,identify) path = resolvers.clean_path(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 @@ -529,12 +535,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() @@ -590,26 +596,43 @@ end local function analysefiles() 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 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) + logs.push() + end + nofduplicates = nofduplicates + 1 + nofskipped = nofskipped + 1 elseif not io.exists(completename) then -- weird error + if trace_names then + report_names("%s font %s does not really exist",suffix,completename) + logs.push() + end + nofskipped = nofskipped + 1 elseif not file.is_qualified_path(completename) and resolvers.find_file(completename,suffix) == "" then -- not locateble by backend anyway + if trace_names then + report_names("%s font %s cannot be found by backend",suffix,completename) + logs.push() + 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) + report_names("rejecting path of %s font %s",suffix,completename) logs.push() end + nofskipped = nofskipped + 1 return end end @@ -619,15 +642,16 @@ 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) + report_names("rejecting name of %s font %s",suffix,completename) logs.push() end + nofskipped = nofskipped + 1 return end end end if trace_names then - logs.report("fontnames","identifying %s font %s",suffix,completename) + report_names("identifying %s font %s",suffix,completename) logs.push() end local result, message = filters[lower(suffix)](completename) @@ -635,24 +659,25 @@ local function analysefiles() 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 @@ -662,27 +687,32 @@ local function analysefiles() 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 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 + if method == "file" or method == "tree" then local completename = root .."/" .. path .. "/" .. name - identify(completename,name,suffix,name,name) + identify(completename,name,suffix,name) + return true end + end, function(blobtype,blobpath,pattern) + report_names( "scanning %s for %s files",blobpath,suffix) + end, function(blobtype,blobpath,pattern,total,checked,done) + report_names( "%s entries found, %s %s files checked, %s okay",total,checked,suffix,done) end) end) if texconfig.kpse_init then @@ -697,7 +727,7 @@ 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 rejectclashes() -- just to be sure, so no explicit afm will be found then @@ -709,7 +739,7 @@ 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 @@ -720,7 +750,7 @@ local function rejectclashes() -- just to be sure, so no explicit afm will be fo 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 @@ -754,13 +784,13 @@ function names.identify() 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) + containers.write(names.cache,name,data) end function names.read_data(name) - return containers.read(names.cache(),name) + return containers.read(names.cache,name) end function names.load(reload,verbose) @@ -770,7 +800,7 @@ function names.load(reload,verbose) names.identify(verbose) names.write_data(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 @@ -783,7 +813,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() @@ -842,10 +872,10 @@ local function is_reloaded() local c_status = table.serialize(resolvers.data_state()) local f_status = table.serialize(data.data_state) if c_status == f_status then - -- logs.report("fonts","font database matches configuration and file hashes") + -- report_names("font database matches configuration and file hashes") return else - logs.report("fonts","font database does not match configuration and file hashes") + report_names("font database does not match configuration and file hashes") end end names.loaded = false @@ -886,7 +916,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 +926,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 +936,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 +946,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) @@ -1144,7 +1177,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 +1186,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 +1214,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" @@ -1238,9 +1271,9 @@ function heuristic(name,weight,style,width,variant,all) -- todo: fallbacks for i=1,nf do t[#t+1] = 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 @@ -1385,19 +1418,29 @@ 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] + if find(value,"*") then + value = string.topattern(value) + for i=1,#lookups do + local s = lookups[i] + if find(s[key],value) then + t[#t+1] = lookups[i] + end + end + else + for i=1,#lookups do + local s = lookups[i] + if s[key] == value then + t[#t+1] = 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 |